diff --git a/.travis.yml b/.travis.yml index 63f2051cb..784b7bdf7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -19,7 +19,7 @@ cache: directories: - ffmpeg-samples before_install: - - if [ "$TRAVIS_OS_NAME" == "osx" ]; then brew update --all; fi + - if [ "$TRAVIS_OS_NAME" == "osx" ]; then brew update; fi install: - if [ "$TRAVIS_OS_NAME" == "osx" ]; then brew install nasm; fi script: diff --git a/Changelog b/Changelog index e8c7aab10..196f37644 100644 --- a/Changelog +++ b/Changelog @@ -1,320 +1,154 @@ Entries are sorted chronologically from oldest to youngest within each release, releases are sorted from youngest to oldest. -version 4.0.4: -- avcodec/hevcdec: Avoid only partly skiping duplicate first slices -- lavc/bmp: Avoid a heap buffer overwrite for 1bpp input. -- avcodec/mpegpicture: Check size of edge_emu_buffer -- avformat/mov: Fix potential integer overflow in entry check in mov_read_trun() -- avcodec/truemotion2: Fix integer overflow in tm2_null_res_block() -- avcodec/dfa: Check the chunk header is not truncated -- avcodec/clearvideo: Check remaining data in P frames -- avcodec/dvbsubdec: Check object position -- avcodec/cdgraphics: Use ff_set_dimensions() -- avformat/gdv: Check fps -- configure: use vpx_codec_vp8_dx/cx for libvpx-vp8 checking -- configure: add missing pthreads extralibs dependency for libvpx-vp9 -- avcodec/mpeg4videodec: Check idx in mpeg4_decode_studio_block() -- avcodec/dxv: Correct integer overflow in get_opcodes() -- avcodec/scpr: Fix use of uninitialized variable -- avcodec/qpeg: Limit copy in qpeg_decode_intra() to the available bytes -- avcodec/aic: Check remaining bits in aic_decode_coeffs() -- avcodec/gdv: Check for truncated tags in decompress_5() -- avcodec/bethsoftvideo: Check block_type -- avcodec/jpeg2000dwt: Fix integer overflow in dwt_decode97_int() -- avcodec/error_resilience: Use a symmetric check for skipping MV estimation -- avcodec/mlpdec: Insuffient typo -- avcodec/zmbv: obtain frame later -- avcodec/jvdec: Check available input space before decode8x8() -- avcodec/h264_direct: Fix overflow in POC comparission -- avformat/webmdashenc: Check id in adaption_sets -- avformat/http: Fix Out-of-Bounds access in process_line() -- avformat/ftp: Fix Out-of-Bounds Access and Information Leak in ftp.c:393 -- avcodec/htmlsubtitles: Fixes denial of service due to use of sscanf in inner loop for handling braces -- avcodec/htmlsubtitles: Fixes denial of service due to use of sscanf in inner loop for tag scaning -- avformat/matroskadec: Do not leak queued packets on sync errors -- avcodec/mpeg4videodec: Clear interlaced_dct for studio profile -- avformat/mov: Do not use reference stream in mov_read_sidx() if there is no reference stream -- avcodec/sbrdsp_fixed.c: remove input value limit for sbr_sum_square_c() -- avformat/mov: validate chunk_count vs stsc_data -- avformat/mov.c: require tfhd to begin parsing trun -- avcodec/pgssubdec: Check for duplicate display segments -- avformat/rtsp: Check number of streams in sdp_parse_line() -- avformat/rtsp: Clear reply in every iteration in ff_rtsp_connect() -- avcodec/fic: Check that there is input left in fic_decode_block() -- avcodec/tiff: Check for 12bit gray fax -- avutil/imgutils: Optimize memset_bytes() by using av_memcpy_backptr() -- avutil/mem: Optimize fill32() by unrolling and using 64bit -- configure: bump year -- avcodec/diracdec: Check component quant -- avcodec/tests/rangecoder: initialize array to avoid valgrind warning -- avcodec/h264_slice: Fix integer overflow in implicit_weight_table() -- avcodec/exr: set layer_match in all branches -- avcodec/exr: Check for duplicate channel index -- avcodec/4xm: Fix returned error codes -- avformat/libopenmpt: Fix successfull typo -- avcodec/v4l2_m2m: fix cant typo -- avcodec/mjpegbdec: Fix some misplaced {} and spaces -- avformat/wvdec: detect and error out on WavPack DSD files -- avcodec/mips: Fix failed case: hevc-conformance-AMP_A_Samsung_* when enable msa -- avcodec/fic: Fail on invalid slice size/off -- postproc/postprocess_template: remove FF_REG_sp from clobber list -- postproc/postprocess_template: Avoid using %4 for the threshold compare -- avcodec/rpza: Check that there is enough data for all the blocks -- avcodec/rpza: Move frame allocation to a later point -- avcodec/avcodec: Document the data type for AV_PKT_DATA_MPEGTS_STREAM_ID -- avformat/mpegts: Fix side data type for stream id -- tests/fate/filter-video: increase fuzz for fate-filter-refcmp-psnr-rgb -- avcodec/mjpegdec: Fix indention of ljpeg_decode_yuv_scan() -- lavf/id3v2: fail read_apic on EOF reading mimetype -- avformat/nutenc: Document trailer index assert better -- lavf/mov: ensure only one tkhd per trak -- avcodec/clearvideo: Check remaining input bits in P macro block loop -- avcodec/dxv: Check that there is enough data to decompress -- avcodec/ppc/hevcdsp: Fix build failures with powerpc-linux-gnu-gcc-4.8 with --disable-optimizations -- avcodec/msvideo1: Check for too small dimensions -- avcodec/wmv2dec: Skip I frame if its smaller than 1/8 of the minimal size -- avcodec/msmpeg4dec: Skip frame if its smaller than 1/8 of the minimal size -- avcodec/truemotion2rt: Fix rounding in input size check -- avcodec/truemotion2: fix integer overflows in tm2_low_chroma() -- avcodec/pngdec: Check compression method -- fftools/ffmpeg: Repair reinit_filter feature -- avcodec/shorten: Fix integer overflow with offset -- h264_redundant_pps: Fix logging context -- avcodec/cavsdec: Propagate error codes inside decode_mb_i() -- avcodec/mpeg4videodec: Clear partitioned frame in decode_studio_vop_header() -- avcodec/mpegaudio_parser: Consume more than 0 bytes in case of the unsupported mp3adu case -- avcodec/hevcdec: decode at most one slice reporting being the first in the picture -- avformat/dsfdec: fix calculation of size of data chunk -- avformat/dsfdec: properly handle padded last packet -- avcodec/hevcdec: fix non-ref frame judgement -- avcodec/libaomenc: remove AVOption related to frame partitions +version 4.2.1: +- avformat/vividas: check for tiny blocks using alignment +- avcodec/vc1_pred: Fix refdist in scaleforopp() +- avcodec/vorbisdec: fix FASTDIV usage for vr_type == 2 +- avcodec/iff: Check for overlap in cmap_read_palette() +- avcodec/apedec: Fix 32bit int overflow in do_apply_filter() +- lavf/rawenc: Only accept the appropriate stream type for raw muxers. +- avformat/matroskadec: use av_fast_realloc to reallocate ebml list arrays +- avformat/matroskadec: use proper types for some EbmlSyntax fields +- avcodec/ralf: fix undefined shift in extend_code() +- avcodec/ralf: fix undefined shift +- avcodec/bgmc: Check input space in ff_bgmc_decode_init() +- avcodec/vp3: Check for end of input in 2 places of vp4_unpack_macroblocks() +- avcodec/truemotion2: Fix multiple integer overflows in tm2_null_res_block() +- avcodec/vc1_block: Check the return code from vc1_decode_p_block() +- avcodec/vc1dec: Require res_sprite for wmv3images +- avcodec/vc1_block: Check for double escapes +- avcodec/vorbisdec: Check get_vlc2() failure +- avcodec/tta: Fix integer overflow in prediction +- avcodec/vb: Check input packet size to be large enough to contain flags +- avcodec/cavsdec: Limit the number of access units per packet to 2 +- avcodec/atrac9dec: Check block_align +- avcodec/alac: Check for bps of 0 +- avcodec/alac: Fix multiple integer overflows in lpc_prediction() +- avcodec/rl2: set dimensions +- avcodec/aacdec: Add FF_CODEC_CAP_INIT_CLEANUP +- avcodec/idcinvideo: Add 320x240 default maximum resolution +- avformat/realtextdec: free queue on error +- avcodec/vp5/6/8: use vpX_rac_is_end() +- avformat/vividas: Check av_xiphlacing() return value before use +- avcodec/alsdec: Fix integer overflow in decode_var_block_data() +- avcodec/alsdec: Limit maximum channels to 512 +- avcodec/anm: Check input size for a frame with just a stop code +- avcodec/flicvideo: Optimize and Simplify FLI_COPY in flic_decode_frame_24BPP() by using bytestream2_get_buffer() +- avcodec/loco: Check left column value +- avcodec/ffwavesynth: Fixes invalid shift with pink noise seeking +- avcodec/ffwavesynth: Fix integer overflow for some corner case values +- avcodec/indeo2: Check remaining input more often +- avcodec/diracdec: Check that slices are fewer than pixels +- avcodec/vp56: Consider the alpha start as end of the prior header +- avcodec/4xm: Check for end of input in decode_p_block() +- avcodec/hevcdec: Check delta_luma_weight_l0/1 +- avcodec/hnm4video: Optimize postprocess_current_frame() +- avcodec/hevc_refs: Optimize 16bit generate_missing_ref() +- avcodec/scpr: Use av_memcpy_backptr() in type 17 and 33 +- avcodec/tiff: Enforce increasing offsets +- avcodec/dds: Use ff_set_dimensions() +- avformat/vividas: Fix another infinite loop +- avformat/vividas: Fix infinite loop in header parser +- avcodec/mpc8: Fix 32bit mask/enum +- avcodec/alsdec: Fix integer overflows of raw_samples in decode_var_block_data() +- avcodec/alsdec: Fix integer overflow of raw_samples in decode_blocks() +- avcodec/alsdec: fix mantisse shift +- avcodec/pngdec: consider chunk size in minimal size check +- avcodec/vc1_block: Fix invalid shifts in vc1_decode_i_blocks() +- avcodec/vc1_block: fix invalid shift in vc1_decode_p_mb() +- avcodec/aacdec_template: fix integer overflow in imdct_and_windowing() +- avformat/mpegts: Check if ready on SCTE reception +- avcodec/omx: fix xFramerate calculation +- avformat/avidec: add support for recognizing HEVC fourcc when demuxing +- avformat/mpegts: fix teletext PTS when selecting teletext streams only +- avcodec/h2645_parse: zero initialize the rbsp buffer +- avcodec/omx: Fix handling of fragmented buffers +- avcodec/omx: ensure zerocopy mode can be disabled on rpi builds +- avformat/mxfdec: do not ignore bad size errors +- avformat/matroskadec: Fix seeking +- ffplay: properly detect all window size changes -version 4.0.3: -- avutil/integer: Fix integer overflow in av_mul_i() -- avcodec/msrle: Check that the input is large enough to contain a end of picture code -- avformat/ftp: return AVERROR_EOF for EOF -- avcodec/libx264: remove FF_CODEC_CAP_INIT_THREADSAFE flag -- avcodec/jpeg2000dec: Fix off by 1 error in JPEG2000_PGOD_CPRL handling -- avcodec/mpeg4videodec: Fix typo in sprite delta check -- avcodec/h264_cavlc: Check mb_skip_run -- avcodec/ra144: Fix integer overflow in add_wav() -- avformat/utils: Never store negative values in last_IP_duration -- avformat/utils: Fix integer overflow in discontinuity check -- Revert "avcodec/cbs_h264: silence errors about end_of_seq nalus" -- avcodec/cbs: ensure user_data is padded for GBC parsing -- avcodec/cbs: fix crash in sei_pic_timestamp -- avcodec/cbs_h264: silence errors about end_of_seq nalus -- avcodec/cuviddec: properly take deinterlacing and display delay into account for buffer_full check -- avcodec/h2645_parse: skip NALUs with no content after stripping all the trailing zeros -- configure: _deps: validate, reduce sensitivity -- configure: speed up check_deps() -- configure: speed up print_enabled_components() -- configure: speed up flatten_extralibs_wrapper() -- avformat/utils: Fix potential integer overflow in extract_extradata() -- avcodec/unary: Improve get_unary() docs -- avcodec/gdv: Replace divisions by shifts in rescale() -- avcodec/ac3dec: Fix shift signedness in mask creation -- avcodec/eac3dec: Check that channel_map does not contain more than EAC3_MAX_CHANNELS -- doc/examples/vaapi_transcode: Fix the typo -- avcodec/dvdsubdec: Sanity check len in decode_rle() -- avcodec/mpeg4videodec: Fix undefined shift in get_amv() -- avcodec/zmbv: Check that the decompressed data size is correct -- avcodec/zmbv: Update decomp_len in raw frames -- avcodec/shorten: Fix bitstream end check in read_header() -- avcodec/dvdsubdec: Avoid branch in decode_run_8bit() -- avcodec/h264_refs: Document last if() in ff_h264_execute_ref_pic_marking() -- avcodec/ra144: Fix undefined integer overflow in add_wav() -- avcodec/indeo4: Check dimensions in decode_pic_hdr() -- avformat/mov: Error on too large stsd entry counts. -- examples: Fix use of AV_CODEC_FLAG_GLOBAL_HEADER -- avcodec/hq_hqa: Check remaining input bits in hqa_decode_mb() -- avcodec/vb: Check for end of bytestream before reading blocktype -- avcodec/snowdec: Fix integer overflow with motion vector residual -- avcodec/mpeg4videodec: Fix slice end detection in mpeg4_decode_studio_mb() -- avformat/nsvdec: Do not parse multiple NSVf -- avformat/dashdec: Fix strlen(rep_id_val) with it being NULL -- avformat/mlvdec: read_string() received unsigned size, make the argument unsigned -- avformat/rmdec: Fix EOF check in the stream loop in ivr_read_header() -- avcodec/scpr: Check for min > max in decompress_p() -- avcodec/shorten: Fix signed 32bit overflow in shift in shorten_decode_frame() -- avcodec/shorten: Fix integer overflow in residual/LPC combination -- avcodec/shorten: Check verbatim length -- avcodec/mpegaudio_parser: Initialize poutbuf* -- avcodec/aacpsdsp_template: Fix integer overflow in ps_stereo_interpolate_c() -- avformat/flvenc: Check audio packet size -- lavc/svq3: Fix regression decoding some files. -- avcodec/mlp_parser: Check if synccode is within buffer -- avcodec/qtrle: Check remaining bytestream in qtrle_decode_XYbpp() -- avcodec/diracdec: Check bytes count in else branch in decode_lowdelay() too -- avcodec/diracdec: Check slice numbers for overflows in relation to picture dimensions -- avcodec/diracdec: Change frame_number to 64bit as its a 32bit from the bitstream and we also have a -1 special case -- avcodec/dirac_dwt_template: Fix several integer overflows in horizontal_compose_daub97i() -- avcodec/diracdec: Prevent integer overflow in intermediate in global_mv() -- swresample/swresample: Fix input channel count in resample_first computation -- avutil/pixfmt: Document chroma plane size for odd resolutions -- lavf/libsmbclient: return AVERROR_EOF for EOF. -- lavc/videotoolboxenc: Fix compilation on osx 10.10.5 Yosemite -- avcodec/mediacodecdec: fix SEGV on modern nvidia decoders -- avcodec/bitstream_filters: check the input argument of av_bsf_get_by_name() for NULL -- avformat/librtmp: fix returning EOF from Read/Write -- avcodec/videotoolboxenc: fix undefined behavior with rc_max_rate=0 +version 4.2: +- tpad filter +- AV1 decoding support through libdav1d +- dedot filter +- chromashift and rgbashift filters +- freezedetect filter +- truehd_core bitstream filter +- dhav demuxer +- PCM-DVD encoder +- GIF parser +- vividas demuxer +- hymt decoder +- anlmdn filter +- maskfun filter +- hcom demuxer and decoder +- ARBC decoder +- libaribb24 based ARIB STD-B24 caption support (profiles A and C) +- Support decoding of HEVC 4:4:4 content in nvdec and cuviddec +- removed libndi-newtek +- agm decoder +- KUX demuxer +- AV1 frame split bitstream filter +- lscr decoder +- lagfun filter +- asoftclip filter +- Support decoding of HEVC 4:4:4 content in vdpau +- colorhold filter +- xmedian filter +- asr filter +- showspatial multimedia filter +- VP4 video decoder +- IFV demuxer +- derain filter +- deesser filter +- mov muxer writes tracks with unspecified language instead of English by default +- add support for using clang to compile CUDA kernels -version 4.0.2: -- avcodec/dvdsub_parser: Allocate input padding -- avcodec/dvdsub_parser: Init output buf/size -- avcodec/dirac_dwt_template: Fix signedness regression in interleave() -- avformat/mov: Simplify last element computation in mov_estimate_video_delay() -- avformat/mov: Break out of inner loop early in mov_estimate_video_delay() -- avformat/mov: Eliminate variable buf_size from mov_estimate_video_delay() -- avformat/mov: remove modulo operations from mov_estimate_video_delay() -- avformat/movenc: Write version 2 of audio atom if channels is not known -- swresample/arm: rename labels to fix xcode build error -- avformat/movenc: Check input sample count -- avcodec/mjpegdec: Check for odd progressive RGB -- avcodec/vp8_parser: Do not leave data/size uninitialized -- avformat/mms: Add missing chunksize check -- avformat/pva: Check for EOF before retrying in read_part_of_packet() -- avformat/rmdec: Do not pass mime type in rm_read_multi() to ff_rm_read_mdpr_codecdata() -- avformat/asfdec_o: Check size_bmp more fully -- avformat/mxfdec: Fix av_log context -- avcodec/mpeg4videodec: Check for bitstream end in read_quant_matrix_ext() -- avcodec/indeo4: Check for end of bitstream in decode_mb_info() -- avcodec/ac3dec: Check channel_map index -- avcodec/mpeg4videodec: Remove use of FF_PROFILE_MPEG4_SIMPLE_STUDIO as indicator of studio profile -- avcodec/shorten: Fix undefined addition in shorten_decode_frame() -- avcodec/shorten: Fix undefined integer overflow -- avcodec/jpeg2000dec: Fixes invalid shifts in jpeg2000_decode_packets_po_iteration() -- avcodec/jpeg2000dec: Check that there are enough bytes for all tiles -- avformat/movenc: Use mov->fc consistently for av_log() -- avcodec/mpeg4videodec: Check read profile before setting it -- avformat/movenc: Do not pass AVCodecParameters in avpriv_request_sample -- avcodec/ac3_parser: Check init_get_bits8() for failure -- avformat/movenc: Check that frame_types other than EAC3_FRAME_TYPE_INDEPENDENT have a supported substream id -- avcodec/dpx: Check elements in 12bps planar path -- avcodec/escape124: Fix spelling errors in comment -- avcodec/ra144: Fix integer overflow in ff_eval_refl() -- avcodec/cscd: Check output buffer size for lzo. -- avcodec/escape124: Check buf_size against num_superblocks -- avcodec/h264_parser: Reduce needed history for parsing mb index -- avcodec/magicyuv: Check bits left in flags&1 branch -- avcodec/mjpegdec: Check for end of bitstream in ljpeg_decode_rgb_scan() -- ffmpeg: fix -stream_loop with multiple inputs -- ffmpeg: factorize input thread creation and destruction -- avformat/mpegts: parse large PMTs with multiple tables -- Revert "avcodec/mediacodecdec: wait on first frame after input buffers are full" -- avcodec/videotoolboxenc: fix invalid session on iOS -- avcodec/videotoolboxenc: split initialization -- avcodec/videotoolboxenc: fix mutex/cond leak in error path - -version 4.0.1: -- avcodec/aacdec_fixed: Fix undefined integer overflow in apply_independent_coupling_fixed() -- avcodec/dirac_dwt_template: Fix undefined behavior in interleave() -- avutil/common: Fix undefined behavior in av_clip_uintp2_c() -- fftools/ffmpeg: Fallback to duration if sample rate is unavailable -- avformat/mov: Only set pkt->duration to non negative values -- avcodec/mpeg4videodec: Clear bits_per_raw_sample if it has originated from a previous instance -- avformat/movenc: fix recognization of cover image streams -- avformat/movenc: properly handle cover image codecs -- avcodec/h264_slice: Fix overflow in recovery_frame computation -- avcodec/h264_ps: Move MAX_LOG2_MAX_FRAME_NUM to header so it can be used in h264_sei -- avcodec/h264_mc_template: Only prefetch motion if the list is used. -- avcodec/xwddec: Use ff_set_dimensions() -- avcodec/wavpack: Fix overflow in adding tail -- avcodec/shorten: Fix multiple integer overflows -- avcodec/shorten: Fix undefined shift in fix_bitshift() -- avcodec/shorten: Fix a negative left shift in shorten_decode_frame() -- avcodec/shorten: Sanity check nmeans -- avcodec/shorten: Check non COMM chunk len before skip in decode_aiff_header() -- avcodec/mjpegdec: Fix integer overflow in ljpeg_decode_rgb_scan() -- avcodec/truemotion2: Fix overflow in tm2_apply_deltas() -- avcodec/opus_silk: Change silk_lsf2lpc() slightly toward silk/NLSF2A.c -- avcodec/amrwbdec: Fix division by 0 in find_hb_gain() -- avcodec/h263dec: Reinitialize idct context if it has not been setup for the active profile -- avcodec/idctdsp: Clear idct/idct_add for studio profile -- avformat/mov: replace a value error by clipping into valid range in mov_read_stsc() -- avformat/bintext: Reduce detection for random .bin files as it more likely is not a multimedia related file -- avformat/mov: Break out early if chunk_count is 0 in mov_build_index() -- avcodec/fic: Avoid some magic numbers related to cursors -- avcodec/mpeg4video: Detect reference studio streams as studio streams -- avcodec/mpeg4videodec: Do not corrupt bits_per_raw_sample -- avcodec/mpeg4videode: Eliminate out of loop VOP startcode reading for studio profile -- avcodec/g2meet: ask for sample with overflowing RGB -- avcodec/idctdsp: Transmit studio_profile to init instead of using AVCodecContext profile -- avcodec/ac3dec: Check that the number of channels with dependant streams is valid -- avcodec/ac3dec: Fix null pointer dereference in ac3_decode_frame() -- avcodec/aacdec_fixed: use 64bit to avoid overflow in rounding in apply_dependent_coupling_fixed() -- oavcodec/aacpsdsp_template: Use unsigned for hs0X to prevent undefined behavior -- avcodec/g723_1dec: Clip bits2 in both directions -- avcodec/mpeg4videoenc: Use 64 bit for times in mpeg4_encode_gop_header() -- avcodec/mlpdec: Only change noise_type if the related fields are valid -- indeo4: Decode all or nothing of a band header. -- avcodec/ac3dec: Use frame_size if superframe_size is 0 -- avformat/mov: Only fail for STCO/STSC contradictions if both exist -- avcodec/dirac_dwt: Fix integer overflow in COMPOSE_DD97iH0 / COMPOSE_DD137iL0 -- avcodec/fic: Check available input space for cursor -- avcodec/mpeg4videodec: Check bps (VOL header) before VOP for studio profile -- avcodec/g2meet: Check RGB upper limit -- avcodec/jpeg2000dec: Fix undefined shift in the jpeg2000_decode_packets_po_iteration() CPRL case -- avcodec/jpeg2000dec: Skip init for component in CPRL if nothing is to be done -- avcodec/g2meet: Change order of operations to avoid undefined behavior -- avcodec/flac_parser: Fix infinite loop -- avcodec/mpeg4videodec: Split decode_studio_vol_header() out of decode_studiovisualobject() -- avcodec/mpeg4videodec: Move decode_studiovisualobject() parsing in the branch for visual object parsing -- avcodec/mpeg4video_parser: Avoid litteral 0x1B6, use named constant instead -- avcodec/mpeg4video_parser: Fix incorrect spliting of MPEG-4 studio frames -- avformat/m4vdec: Use the same constant names as libavcodec -- avformat/m4vdec: Fix detection of raw MPEG-4 ES Studio -- avcodec/wavpack: Fix integer overflow in DEC_MED() / INC_MED() -- avcodec/wavpack: Fix integer overflow in wv_unpack_stereo() -- avcodec/error_resilience: Fix integer overflow in filter181() -- avcodec/h263dec: Check slice_ret in mspeg4 slice loop -- avcodec/elsdec: Fix memleaks -- avcodec/vc1_block: simplify ac_val computation -- avcodec/ffv1enc: Check that the crc + version combination is supported -- configure: The eac3_core bitstream filter needs the ac3 parser. -- configure: fix arm inline asm checks -- lavf/libssh: translate a read of 0 to EOF -- ffprobe: fix SEGV when new streams are added -- avformat/mpegts: fix incorrect indentation -- avformat/mpegts: initialize section_buf to fix valgrind test failure -- avformat/mpegts: reindent after last change -- avformat/mpegts: parse sections with multiple tables -- avformat/mpegts: clean up whitespace -- avformat/mpegts: use MAX_SECTION_SIZE instead of hardcoded value -- avformat/mpegts: skip non-PMT tids earlier -- avcodec/mediacodecdec: add workaround for buggy amlogic mpeg2 decoder -- avcodec/mediacodecdec: wait on first frame after input buffers are full -- avcodec/mediacodecdec: restructure mediacodec_receive_frame -- avcodec/mediacodec_wrapper: add helper to fetch SDK_INT -- avcodec/mediacodecdec: refactor pts handling -- avcodec/mediacodecdec: use AV_TIME_BASE_Q -- avcodec/mediacodecdec: clarify delay_flush specific code -- avcodec/videotoolbox: fix decoding of some HEVC videos -- avcodec/hevc: remove videotoolbox hack -- avcodec/videotoolbox: split h264/hevc callbacks -- avcodec/videotoolbox: cleanups -- avcodec/videotoolbox: fix kVTCouldNotFindVideoDecoderErr trying to decode HEVC on iOS -- avcodec/videotoolbox: improve logging of decoder errors -- avcodec/xwddec: fix palette alpha -- avformat/webm_chunk: always use a static buffer for get_chunk_filename -- configure: fix configure check for lilv-0 -- avcodec/nvdec_hevc: fix scaling lists -- avcodec/hevcdec: make ff_hevc_frame_nb_refs take a const pointer -- lavf/bluray: translate a read of 0 to EOF -- lavf/dashenc: don't call flush_init_segment before avformat_write_header -- avdevice/decklink_dec: unref packets on avpacket_queue_put error -- avcodec/hnm4video: fix palette alpha -- avcodec/anm: fix palette alpha -- avformat/qtpalette: parse color table according to the QuickTime file format specs -- ffplay: Fix realloc_texture when input texture is NULL. -- hwcontext_vaapi: Fix compilation with libva versions < 1.4.0 -- lavf/qsv: clone the frame which may be managed by framework -- lavf: make overlay_qsv work based on framesync -- avformat/segafilm - revert keyframe detection -- avformat/utils: refactor upstream_stream_timings -- avformat/utils: ignore outlier durations on subtitle/data streams as well +version 4.1: +- deblock filter +- tmix filter +- amplify filter +- fftdnoiz filter +- aderivative and aintegral audio filters +- pal75bars and pal100bars video filter sources +- support mbedTLS based TLS +- adeclick filter +- adeclip filter +- libtensorflow backend for DNN based filters like srcnn +- vc1 decoder is now bit-exact +- ATRAC9 decoder +- lensfun wrapper filter +- colorconstancy filter +- AVS2 video decoder via libdavs2 +- IMM4 video decoder +- Brooktree ProSumer video decoder +- MatchWare Screen Capture Codec decoder +- WinCam Motion Video decoder +- 1D LUT filter (lut1d) +- RemotelyAnywhere Screen Capture decoder +- cue and acue filters +- support for AV1 in MP4 +- transpose_npp filter +- AVS2 video encoder via libxavs2 +- amultiply filter +- Block-Matching 3d (bm3d) denoising filter +- acrossover filter +- ilbc decoder +- audio denoiser as afftdn filter +- AV1 parser +- SER demuxer +- sinc audio filter source +- chromahold filter +- setparams filter +- vibrance filter +- decoding S12M timecode in h264 +- xstack filter +- pcm vidc decoder and encoder +- (a)graphmonitor filter +- yadif_cuda filter version 4.0: @@ -370,6 +204,7 @@ version 4.0: - Haivision SRT protocol via libsrt - segafilm muxer - vfrdet filter +- SRCNN filter version 3.4: diff --git a/INSTALL.md b/INSTALL.md index 5db912231..3b220bc6f 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -1,4 +1,4 @@ -#Installing FFmpeg: +## Installing FFmpeg 1. Type `./configure` to create the configuration. A list of configure options is printed by running `configure --help`. diff --git a/LICENSE.md b/LICENSE.md index ba65b059c..c7d6bf712 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -103,18 +103,9 @@ license version needs to be upgraded by passing `--enable-version3` to configure There are certain libraries you can combine with FFmpeg whose licenses are not compatible with the GPL and/or the LGPL. If you wish to enable these libraries, even in circumstances that their license may be incompatible, pass -`--enable-nonfree` to configure. But note that if you enable any of these -libraries the resulting binary will be under a complex license mix that is -more restrictive than the LGPL and that may result in additional obligations. -It is possible that these restrictions cause the resulting binary to be +`--enable-nonfree` to configure. This will cause the resulting binary to be unredistributable. The Fraunhofer FDK AAC and OpenSSL libraries are under licenses which are incompatible with the GPLv2 and v3. To the best of our knowledge, they are compatible with the LGPL. - -The NVENC library, while its header file is licensed under the compatible MIT -license, requires a proprietary binary blob at run time, and is deemed to be -incompatible with the GPL. We are not certain if it is compatible with the -LGPL, but we require `--enable-nonfree` even with LGPL configurations in case -it is not. diff --git a/MAINTAINERS b/MAINTAINERS index b61856243..88b0109f2 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -39,7 +39,7 @@ QuickTime faststart: Miscellaneous Areas =================== -documentation Stefano Sabatini, Mike Melanson, Timothy Gu, Lou Logan, Gyan Doshi +documentation Stefano Sabatini, Mike Melanson, Timothy Gu, Gyan Doshi project server Árpád Gereöffy, Michael Niedermayer, Reimar Doeffinger, Alexander Strasser, Nikolay Aleksandrov presets Robert Swain metadata subsystem Aurelien Jacobs @@ -52,8 +52,8 @@ Communication website Deby Barbara Lepage fate.ffmpeg.org Timothy Gu -Trac bug tracker Alexander Strasser, Michael Niedermayer, Carl Eugen Hoyos, Lou Logan -mailing lists Baptiste Coudurier, Lou Logan +Trac bug tracker Alexander Strasser, Michael Niedermayer, Carl Eugen Hoyos +mailing lists Baptiste Coudurier Google+ Paul B Mahol, Michael Niedermayer, Alexander Strasser Twitter Lou Logan, Reynaldo H. Verdejo Pinochet Launchpad Timothy Gu @@ -121,7 +121,6 @@ Generic Parts: motion* Michael Niedermayer rate control: ratecontrol.c Michael Niedermayer - libxvid_rc.c Michael Niedermayer simple IDCT: simple_idct.c, simple_idct.h Michael Niedermayer postprocessing: @@ -144,6 +143,7 @@ Codecs: asv* Michael Niedermayer atrac3plus* Maxim Poliakovski audiotoolbox* Rodger Combs + avs2* Huiwen Ren bgmc.c, bgmc.h Thilo Borgmann binkaudio.c Peter Ross cavs* Stefan Gehrer @@ -168,7 +168,6 @@ Codecs: eacmv*, eaidct*, eat* Peter Ross evrc* Paul B Mahol exif.c, exif.h Thilo Borgmann - exr.c Martin Vignali ffv1* Michael Niedermayer ffwavesynth.c Nicolas George fifo.c Jan Sebechlebsky @@ -190,6 +189,7 @@ Codecs: libcelt_dec.c Nicolas George libcodec2.c Tomas Härdin libdirac* David Conrad + libdavs2.c Huiwen Ren libgsm.c Michel Bardiaux libkvazaar.c Arttu Ylä-Outinen libopenjpeg.c Jaikrishnan Menon @@ -220,7 +220,7 @@ Codecs: ptx.c Ivo van Poorten qcelp* Reynaldo H. Verdejo Pinochet qdm2.c, qdm2data.h Roberto Togni - qsv* Mark Thompson + qsv* Mark Thompson, Zhong Li qtrle.c Mike Melanson ra144.c, ra144.h, ra288.c, ra288.h Roberto Togni resample2.c Michael Niedermayer @@ -333,6 +333,7 @@ Filters: vf_bwdif Thomas Mundt (CC ) vf_chromakey.c Timo Rothenpieler vf_colorchannelmixer.c Paul B Mahol + vf_colorconstancy.c Mina Sami (CC ) vf_colorbalance.c Paul B Mahol vf_colorkey.c Timo Rothenpieler vf_colorlevels.c Paul B Mahol @@ -360,6 +361,7 @@ Filters: vf_ssim.c Paul B Mahol vf_stereo3d.c Paul B Mahol vf_telecine.c Paul B Mahol + vf_tonemap_opencl.c Ruiling Song vf_yadif.c Michael Niedermayer vf_zoompan.c Paul B Mahol @@ -413,7 +415,6 @@ Muxers/Demuxers: flvenc.c Michael Niedermayer, Steven Liu gxf.c Reimar Doeffinger gxfenc.c Baptiste Coudurier - hls.c Anssi Hannula hlsenc.c Christian Suloway, Steven Liu idcin.c Mike Melanson idroqdec.c Mike Melanson @@ -524,9 +525,10 @@ Operating systems / CPU architectures ===================================== Alpha Falk Hueffner -MIPS Manojkumar Bhosale +MIPS Manojkumar Bhosale, Shiyou Yin Mac OS X / PowerPC Romain Dolbeau, Guillaume Poirier Amiga / PowerPC Colin Ward +Linux / PowerPC Lauri Kasanen Windows MinGW Alex Beregszaszi, Ramiro Polla Windows Cygwin Victor Paesa Windows MSVC Matthew Oliver, Hendrik Leppkes @@ -575,8 +577,11 @@ Releases If you want to maintain an older release, please contact us -GnuPG Fingerprints of maintainers and contributors -================================================== +GnuPG Fingerprints and IRC nicknames of maintainers and contributors +==================================================================== + +IRC nicknames are in parentheses. These apply +to the IRC channels listed on the website. Alexander Strasser 1C96 78B7 83CB 8AA7 9AF5 D1EB A7D8 A57B A876 E58F Anssi Hannula 1A92 FF42 2DD9 8D2E 8AF7 65A9 4278 C520 513D F3CB @@ -594,7 +599,7 @@ Jaikrishnan Menon 61A1 F09F 01C9 2D45 78E1 C862 25DC 8831 AF70 D368 James Almer 7751 2E8C FD94 A169 57E6 9A7A 1463 01AD 7376 59E0 Jean Delvare 7CA6 9F44 60F1 BDC4 1FD2 C858 A552 6B9B B3CD 4E6A Loren Merritt ABD9 08F4 C920 3F65 D8BE 35D7 1540 DAA7 060F 56DE -Lou Logan 7D68 DC73 CBEF EABB 671A B6CF 621C 2E28 82F8 DC3A +Lou Logan (llogan) 7D68 DC73 CBEF EABB 671A B6CF 621C 2E28 82F8 DC3A Michael Niedermayer 9FF2 128B 147E F673 0BAD F133 611E C787 040B 0FAB Nicolas George 24CE 01CE 9ACC 5CEB 74D8 8D9D B063 D997 36E5 4C93 Nikolay Aleksandrov 8978 1D8C FB71 588E 4B27 EAA8 C4F0 B5FC E011 13B1 @@ -611,5 +616,5 @@ Steinar H. Gunderson C2E9 004F F028 C18E 4EAD DB83 7F61 7561 7797 8F76 Stephan Hilb 4F38 0B3A 5F39 B99B F505 E562 8D5C 5554 4E17 8863 Tiancheng "Timothy" Gu 9456 AFC0 814A 8139 E994 8351 7FE6 B095 B582 B0D4 Tim Nicholson 38CF DB09 3ED0 F607 8B67 6CED 0C0B FC44 8B0B FC83 -Tomas Härdin A79D 4E3D F38F 763F 91F5 8B33 A01E 8AE0 41BB 2551 +Tomas Härdin (thardin) A79D 4E3D F38F 763F 91F5 8B33 A01E 8AE0 41BB 2551 Wei Gao 4269 7741 857A 0E60 9EC5 08D2 4744 4EFA 62C1 87B9 diff --git a/Makefile b/Makefile index 0cd0a1d6f..532372c9c 100644 --- a/Makefile +++ b/Makefile @@ -50,6 +50,9 @@ $(TOOLS): %$(EXESUF): %.o target_dec_%_fuzzer$(EXESUF): target_dec_%_fuzzer.o $(FF_DEP_LIBS) $(LD) $(LDFLAGS) $(LDEXEFLAGS) $(LD_O) $^ $(ELIBS) $(FF_EXTRALIBS) $(LIBFUZZER_PATH) +tools/target_dem_fuzzer$(EXESUF): tools/target_dem_fuzzer.o $(FF_DEP_LIBS) + $(LD) $(LDFLAGS) $(LDEXEFLAGS) $(LD_O) $^ $(ELIBS) $(FF_EXTRALIBS) $(LIBFUZZER_PATH) + tools/sofa2wavs$(EXESUF): ELIBS = $(FF_EXTRALIBS) tools/uncoded_frame$(EXESUF): $(FF_DEP_LIBS) tools/uncoded_frame$(EXESUF): ELIBS = $(FF_EXTRALIBS) @@ -58,6 +61,7 @@ tools/target_dec_%_fuzzer$(EXESUF): $(FF_DEP_LIBS) CONFIGURABLE_COMPONENTS = \ $(wildcard $(FFLIBS:%=$(SRC_PATH)/lib%/all*.c)) \ $(SRC_PATH)/libavcodec/bitstream_filters.c \ + $(SRC_PATH)/libavcodec/parsers.c \ $(SRC_PATH)/libavformat/protocols.c \ config.h: ffbuild/.config @@ -134,7 +138,7 @@ uninstall-data: clean:: $(RM) $(CLEANSUFFIXES) - $(RM) $(addprefix compat/,$(CLEANSUFFIXES)) $(addprefix compat/*/,$(CLEANSUFFIXES)) + $(RM) $(addprefix compat/,$(CLEANSUFFIXES)) $(addprefix compat/*/,$(CLEANSUFFIXES)) $(addprefix compat/*/*/,$(CLEANSUFFIXES)) $(RM) -r coverage-html $(RM) -rf coverage.info coverage.info.in lcov @@ -158,7 +162,7 @@ check: all alltools examples testprogs fate include $(SRC_PATH)/tests/Makefile -$(sort $(OBJDIRS)): +$(sort $(OUTDIRS)): $(Q)mkdir -p $@ # Dummy rule to stop make trying to rebuild removed or renamed headers diff --git a/README.md b/README.md index 1a466d90b..447347c70 100644 --- a/README.md +++ b/README.md @@ -4,31 +4,6 @@ FFmpeg README FFmpeg is a collection of libraries and tools to process multimedia content such as audio, video, subtitles and related metadata. -## For Jellyfin - -This particular repository is designed to support building a static, portable, -FFMPEG release of 4.0.3 for the [Jellyfin project](https://github.com/jellyfin). - -To build packages, use `./build `, where `release` is one of: - * `stretch` (Debian 9.X "Stretch") - * `buster` (Debian 10.X "Buster") - * `xenial` (Ubuntu 16.04 "Xenial Xerus") - * `bionic` (Ubuntu 18.04 "Bionic Beaver") - * `cosmic` (Ubuntu 18.10 "Cosmic Cuttlefish") - -And `arch` is one of: - * `amd64` (Standard 64-bit x86) - * `armhf` (ARMv6, Raspberry Pi) - -The build setup requires `docker` support and may use a significant amount of -disk space. Binary releases are available in the [repository](https://repo.jellyfin.org/releases/server). - -For older Ubuntu releases in between these officially supported versions, the -oldest should generally be compatible. - -The build setup will attempt to generate both `amd64` and `armhf` binary packages -if the release supports it. - ## Libraries * `libavcodec` provides implementation of a wider range of codecs. diff --git a/RELEASE b/RELEASE index c5106e6d1..fae6e3d04 100644 --- a/RELEASE +++ b/RELEASE @@ -1 +1 @@ -4.0.4 +4.2.1 diff --git a/RELEASE_NOTES b/RELEASE_NOTES index 7129a9d66..324dcc379 100644 --- a/RELEASE_NOTES +++ b/RELEASE_NOTES @@ -1,10 +1,10 @@ - ┌───────────────────────────────────┐ - │ RELEASE NOTES for FFmpeg 4.0 "Wu" │ - └───────────────────────────────────┘ + ┌────────────────────────────────────┐ + │ RELEASE NOTES for FFmpeg 4.2 "Ada" │ + └────────────────────────────────────┘ - The FFmpeg Project proudly presents FFmpeg 4.0 "Wu", about 6 - months after the release of FFmpeg 3.4. + The FFmpeg Project proudly presents FFmpeg 4.2 "Ada", about 8 + months after the release of FFmpeg 4.1. A complete Changelog is available at the root of the project, and the complete Git history on https://git.ffmpeg.org/gitweb/ffmpeg.git diff --git a/VERSION b/VERSION index c5106e6d1..fae6e3d04 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -4.0.4 +4.2.1 diff --git a/compat/avisynth/avisynth_c.h b/compat/avisynth/avisynth_c.h index 605b92ae6..8d17125ad 100644 --- a/compat/avisynth/avisynth_c.h +++ b/compat/avisynth/avisynth_c.h @@ -34,6 +34,22 @@ // NOTE: this is a partial update of the Avisynth C interface to recognize // new color spaces added in Avisynth 2.60. By no means is this document // completely Avisynth 2.60 compliant. +// 170103: added new CPU constants (FMA4, AVX512xx) +// 171102: define SIZETMOD. do not use yet, experimental. Offsets are size_t instead of int. Affects x64. +// 171106: avs_get_row_size calls into avs_get_row_size_p, instead of direct field access +// 171106: avs_get_height calls into avs_get_row_size_p, instead of direct field access +// 180524: AVSC_EXPORT to dllexport in capi.h for avisynth_c_plugin_init +// 180524: avs_is_same_colorspace VideoInfo parameters to const +// 181230: Readability: functions regrouped to mix less AVSC_API and AVSC_INLINE, put together Avisynth+ specific stuff +// 181230: use #ifndef AVSC_NO_DECLSPEC for AVSC_INLINE functions which are calling API functions +// 181230: comments on avs_load_library (helper for loading API entries dynamically into a struct using AVSC_NO_DECLSPEC define) +// 181230: define alias AVS_FRAME_ALIGN as FRAME_ALIGN +// 181230: remove unused form of avs_get_rowsize and avs_get_height (kept earlier for reference) +// 190104: avs_load_library: smart fallback mechanism for Avisynth+ specific functions: +// if they are not loadable, they will work in a classic Avisynth compatible mode +// Example#1: e.g. avs_is_444 will call the existing avs_is_yv24 instead +// Example#2: avs_bits_per_component will return 8 for all colorspaces (Classic Avisynth supports only 8 bits/pixel) +// Thus the Avisynth+ specific API functions are safely callable even when connected to classic Avisynth DLL #ifndef __AVISYNTH_C__ #define __AVISYNTH_C__ @@ -42,7 +58,7 @@ #include "avs/capi.h" #include "avs/types.h" - +#define AVS_FRAME_ALIGN FRAME_ALIGN ///////////////////////////////////////////////////////////////////// // // Constants @@ -124,7 +140,7 @@ enum { AVS_CS_GENERIC_YUVA444 = AVS_CS_PLANAR | AVS_CS_YUVA | AVS_CS_VPLANEFIRST | AVS_CS_SUB_HEIGHT_1 | AVS_CS_SUB_WIDTH_1 }; // 4:4:4:A planar - // Specific colorformats + // Specific color formats enum { AVS_CS_UNKNOWN = 0, AVS_CS_BGR24 = AVS_CS_RGB_TYPE | AVS_CS_BGR | AVS_CS_INTERLEAVED, @@ -134,18 +150,18 @@ enum { // AVS_CS_I420 = 1<<4 Reserved AVS_CS_RAW32 = 1<<5 | AVS_CS_INTERLEAVED, - AVS_CS_YV24 = AVS_CS_GENERIC_YUV444 | AVS_CS_SAMPLE_BITS_8, // YVU 4:4:4 planar - AVS_CS_YV16 = AVS_CS_GENERIC_YUV422 | AVS_CS_SAMPLE_BITS_8, // YVU 4:2:2 planar - AVS_CS_YV12 = AVS_CS_GENERIC_YUV420 | AVS_CS_SAMPLE_BITS_8, // YVU 4:2:0 planar + AVS_CS_YV24 = AVS_CS_GENERIC_YUV444 | AVS_CS_SAMPLE_BITS_8, // YUV 4:4:4 planar + AVS_CS_YV16 = AVS_CS_GENERIC_YUV422 | AVS_CS_SAMPLE_BITS_8, // YUV 4:2:2 planar + AVS_CS_YV12 = AVS_CS_GENERIC_YUV420 | AVS_CS_SAMPLE_BITS_8, // YUV 4:2:0 planar AVS_CS_I420 = AVS_CS_PLANAR | AVS_CS_YUV | AVS_CS_SAMPLE_BITS_8 | AVS_CS_UPLANEFIRST | AVS_CS_SUB_HEIGHT_2 | AVS_CS_SUB_WIDTH_2, // YUV 4:2:0 planar AVS_CS_IYUV = AVS_CS_I420, - AVS_CS_YV411 = AVS_CS_PLANAR | AVS_CS_YUV | AVS_CS_SAMPLE_BITS_8 | AVS_CS_VPLANEFIRST | AVS_CS_SUB_HEIGHT_1 | AVS_CS_SUB_WIDTH_4, // YVU 4:1:1 planar - AVS_CS_YUV9 = AVS_CS_PLANAR | AVS_CS_YUV | AVS_CS_SAMPLE_BITS_8 | AVS_CS_VPLANEFIRST | AVS_CS_SUB_HEIGHT_4 | AVS_CS_SUB_WIDTH_4, // YVU 4:1:0 planar + AVS_CS_YV411 = AVS_CS_PLANAR | AVS_CS_YUV | AVS_CS_SAMPLE_BITS_8 | AVS_CS_VPLANEFIRST | AVS_CS_SUB_HEIGHT_1 | AVS_CS_SUB_WIDTH_4, // YUV 4:1:1 planar + AVS_CS_YUV9 = AVS_CS_PLANAR | AVS_CS_YUV | AVS_CS_SAMPLE_BITS_8 | AVS_CS_VPLANEFIRST | AVS_CS_SUB_HEIGHT_4 | AVS_CS_SUB_WIDTH_4, // YUV 4:1:0 planar AVS_CS_Y8 = AVS_CS_GENERIC_Y | AVS_CS_SAMPLE_BITS_8, // Y 4:0:0 planar //------------------------- // AVS16: new planar constants go live! Experimental PF 160613 - // 10-12-14 bit + planar RGB + BRG48/64 160725 + // 10-12-14-16 bit + planar RGB + BGR48/64 160725 AVS_CS_YUV444P10 = AVS_CS_GENERIC_YUV444 | AVS_CS_SAMPLE_BITS_10, // YUV 4:4:4 10bit samples AVS_CS_YUV422P10 = AVS_CS_GENERIC_YUV422 | AVS_CS_SAMPLE_BITS_10, // YUV 4:2:2 10bit samples AVS_CS_YUV420P10 = AVS_CS_GENERIC_YUV420 | AVS_CS_SAMPLE_BITS_10, // YUV 4:2:0 10bit samples @@ -246,9 +262,9 @@ enum { //SUBTYPES enum { // New 2.6 explicitly defined cache hints. AVS_CACHE_NOTHING=10, // Do not cache video. - AVS_CACHE_WINDOW=11, // Hard protect upto X frames within a range of X from the current frame N. - AVS_CACHE_GENERIC=12, // LRU cache upto X frames. - AVS_CACHE_FORCE_GENERIC=13, // LRU cache upto X frames, override any previous CACHE_WINDOW. + AVS_CACHE_WINDOW=11, // Hard protect up to X frames within a range of X from the current frame N. + AVS_CACHE_GENERIC=12, // LRU cache up to X frames. + AVS_CACHE_FORCE_GENERIC=13, // LRU cache up to X frames, override any previous CACHE_WINDOW. AVS_CACHE_GET_POLICY=30, // Get the current policy. AVS_CACHE_GET_WINDOW=31, // Get the current window h_span. @@ -256,8 +272,8 @@ enum { AVS_CACHE_AUDIO=50, // Explicitly do cache audio, X byte cache. AVS_CACHE_AUDIO_NOTHING=51, // Explicitly do not cache audio. - AVS_CACHE_AUDIO_NONE=52, // Audio cache off (auto mode), X byte intial cache. - AVS_CACHE_AUDIO_AUTO=53, // Audio cache on (auto mode), X byte intial cache. + AVS_CACHE_AUDIO_NONE=52, // Audio cache off (auto mode), X byte initial cache. + AVS_CACHE_AUDIO_AUTO=53, // Audio cache on (auto mode), X byte initial cache. AVS_CACHE_GET_AUDIO_POLICY=70, // Get the current audio policy. AVS_CACHE_GET_AUDIO_SIZE=71, // Get the current audio cache size. @@ -284,7 +300,7 @@ enum { AVS_CACHE_COST_MED=224, // Child response of medium cost. (Real time) AVS_CACHE_COST_HI=225, // Child response of heavy cost. (Slow) - AVS_CACHE_GETCHILD_THREAD_MODE=240, // Cache ask Child for thread safetyness. + AVS_CACHE_GETCHILD_THREAD_MODE=240, // Cache ask Child for thread safety. AVS_CACHE_THREAD_UNSAFE=241, // Only 1 thread allowed for all instances. 2.5 filters default! AVS_CACHE_THREAD_CLASS=242, // Only 1 thread allowed for each instance. 2.6 filters default! AVS_CACHE_THREAD_SAFE=243, // Allow all threads in any instance. @@ -297,6 +313,8 @@ enum { }; #ifdef BUILDING_AVSCORE +AVSValue create_c_video_filter(AVSValue args, void * user_data, IScriptEnvironment * e0); + struct AVS_ScriptEnvironment { IScriptEnvironment * env; const char * error; @@ -313,7 +331,7 @@ typedef struct AVS_ScriptEnvironment AVS_ScriptEnvironment; // AVS_VideoInfo // -// AVS_VideoInfo is layed out identicly to VideoInfo +// AVS_VideoInfo is laid out identically to VideoInfo typedef struct AVS_VideoInfo { int width, height; // width=0 means no video unsigned fps_numerator, fps_denominator; @@ -326,7 +344,7 @@ typedef struct AVS_VideoInfo { INT64 num_audio_samples; int nchannels; - // Imagetype properties + // Image type properties int image_type; } AVS_VideoInfo; @@ -353,77 +371,20 @@ AVSC_INLINE int avs_is_yuv(const AVS_VideoInfo * p) AVSC_INLINE int avs_is_yuy2(const AVS_VideoInfo * p) { return (p->pixel_type & AVS_CS_YUY2) == AVS_CS_YUY2; } -AVSC_API(int, avs_is_rgb48)(const AVS_VideoInfo * p); +AVSC_API(int, avs_is_yv24)(const AVS_VideoInfo * p); // avs+: for generic 444 check, use avs_is_yuv444 -AVSC_API(int, avs_is_rgb64)(const AVS_VideoInfo * p); +AVSC_API(int, avs_is_yv16)(const AVS_VideoInfo * p); // avs+: for generic 422 check, use avs_is_yuv422 -AVSC_API(int, avs_is_yv24)(const AVS_VideoInfo * p); - -AVSC_API(int, avs_is_yv16)(const AVS_VideoInfo * p); - -AVSC_API(int, avs_is_yv12)(const AVS_VideoInfo * p) ; +AVSC_API(int, avs_is_yv12)(const AVS_VideoInfo * p) ; // avs+: for generic 420 check, use avs_is_yuv420 AVSC_API(int, avs_is_yv411)(const AVS_VideoInfo * p); -AVSC_API(int, avs_is_y8)(const AVS_VideoInfo * p); - -AVSC_API(int, avs_is_yuv444p16)(const AVS_VideoInfo * p); - -AVSC_API(int, avs_is_yuv422p16)(const AVS_VideoInfo * p); - -AVSC_API(int, avs_is_yuv420p16)(const AVS_VideoInfo * p); - -AVSC_API(int, avs_is_y16)(const AVS_VideoInfo * p); - -AVSC_API(int, avs_is_yuv444ps)(const AVS_VideoInfo * p); - -AVSC_API(int, avs_is_yuv422ps)(const AVS_VideoInfo * p); - -AVSC_API(int, avs_is_yuv420ps)(const AVS_VideoInfo * p); - -AVSC_API(int, avs_is_y32)(const AVS_VideoInfo * p); - -AVSC_API(int, avs_is_444)(const AVS_VideoInfo * p); - -AVSC_API(int, avs_is_422)(const AVS_VideoInfo * p); - -AVSC_API(int, avs_is_420)(const AVS_VideoInfo * p); - -AVSC_API(int, avs_is_y)(const AVS_VideoInfo * p); - -AVSC_API(int, avs_is_yuva)(const AVS_VideoInfo * p); - -AVSC_API(int, avs_is_planar_rgb)(const AVS_VideoInfo * p); - -AVSC_API(int, avs_is_planar_rgba)(const AVS_VideoInfo * p); - - - -AVSC_INLINE int avs_is_property(const AVS_VideoInfo * p, int property) - { return ((p->image_type & property)==property ); } - -AVSC_INLINE int avs_is_planar(const AVS_VideoInfo * p) - { return !!(p->pixel_type & AVS_CS_PLANAR); } - -AVSC_API(int, avs_is_color_space)(const AVS_VideoInfo * p, int c_space); - -AVSC_INLINE int avs_is_field_based(const AVS_VideoInfo * p) - { return !!(p->image_type & AVS_IT_FIELDBASED); } - -AVSC_INLINE int avs_is_parity_known(const AVS_VideoInfo * p) - { return ((p->image_type & AVS_IT_FIELDBASED)&&(p->image_type & (AVS_IT_BFF | AVS_IT_TFF))); } - -AVSC_INLINE int avs_is_bff(const AVS_VideoInfo * p) - { return !!(p->image_type & AVS_IT_BFF); } - -AVSC_INLINE int avs_is_tff(const AVS_VideoInfo * p) - { return !!(p->image_type & AVS_IT_TFF); } +AVSC_API(int, avs_is_y8)(const AVS_VideoInfo * p); // avs+: for generic grayscale, use avs_is_y AVSC_API(int, avs_get_plane_width_subsampling)(const AVS_VideoInfo * p, int plane); AVSC_API(int, avs_get_plane_height_subsampling)(const AVS_VideoInfo * p, int plane); - AVSC_API(int, avs_bits_per_pixel)(const AVS_VideoInfo * p); AVSC_API(int, avs_bytes_from_pixels)(const AVS_VideoInfo * p, int pixels); @@ -432,10 +393,42 @@ AVSC_API(int, avs_row_size)(const AVS_VideoInfo * p, int plane); AVSC_API(int, avs_bmp_size)(const AVS_VideoInfo * vi); +AVSC_API(int, avs_is_color_space)(const AVS_VideoInfo * p, int c_space); + +// no API for these, inline helper functions +AVSC_INLINE int avs_is_property(const AVS_VideoInfo * p, int property) +{ + return ((p->image_type & property) == property); +} + +AVSC_INLINE int avs_is_planar(const AVS_VideoInfo * p) +{ + return !!(p->pixel_type & AVS_CS_PLANAR); +} + +AVSC_INLINE int avs_is_field_based(const AVS_VideoInfo * p) +{ + return !!(p->image_type & AVS_IT_FIELDBASED); +} + +AVSC_INLINE int avs_is_parity_known(const AVS_VideoInfo * p) +{ + return ((p->image_type & AVS_IT_FIELDBASED) && (p->image_type & (AVS_IT_BFF | AVS_IT_TFF))); +} + +AVSC_INLINE int avs_is_bff(const AVS_VideoInfo * p) +{ + return !!(p->image_type & AVS_IT_BFF); +} + +AVSC_INLINE int avs_is_tff(const AVS_VideoInfo * p) +{ + return !!(p->image_type & AVS_IT_TFF); +} + AVSC_INLINE int avs_samples_per_second(const AVS_VideoInfo * p) { return p->audio_samples_per_second; } - AVSC_INLINE int avs_bytes_per_channel_sample(const AVS_VideoInfo * p) { switch (p->sample_type) { @@ -447,6 +440,7 @@ AVSC_INLINE int avs_bytes_per_channel_sample(const AVS_VideoInfo * p) default: return 0; } } + AVSC_INLINE int avs_bytes_per_audio_sample(const AVS_VideoInfo * p) { return p->nchannels*avs_bytes_per_channel_sample(p);} @@ -488,19 +482,56 @@ AVSC_INLINE void avs_set_fps(AVS_VideoInfo * p, unsigned numerator, unsigned den p->fps_denominator = denominator/x; } -#ifdef AVS_IMPLICIT_FUNCTION_DECLARATION_ERROR -AVSC_INLINE int avs_is_same_colorspace(AVS_VideoInfo * x, AVS_VideoInfo * y) +#ifndef AVSC_NO_DECLSPEC +// this inline function is calling an API function +AVSC_INLINE int avs_is_same_colorspace(const AVS_VideoInfo * x, const AVS_VideoInfo * y) { return (x->pixel_type == y->pixel_type) || (avs_is_yv12(x) && avs_is_yv12(y)); } #endif +// Avisynth+ extensions +AVSC_API(int, avs_is_rgb48)(const AVS_VideoInfo * p); + +AVSC_API(int, avs_is_rgb64)(const AVS_VideoInfo * p); + +AVSC_API(int, avs_is_yuv444p16)(const AVS_VideoInfo * p); // obsolete, use avs_is_yuv444 + +AVSC_API(int, avs_is_yuv422p16)(const AVS_VideoInfo * p); // obsolete, use avs_is_yuv422 + +AVSC_API(int, avs_is_yuv420p16)(const AVS_VideoInfo * p); // obsolete, use avs_is_yuv420 + +AVSC_API(int, avs_is_y16)(const AVS_VideoInfo * p); // obsolete, use avs_is_y + +AVSC_API(int, avs_is_yuv444ps)(const AVS_VideoInfo * p); // obsolete, use avs_is_yuv444 + +AVSC_API(int, avs_is_yuv422ps)(const AVS_VideoInfo * p); // obsolete, use avs_is_yuv422 + +AVSC_API(int, avs_is_yuv420ps)(const AVS_VideoInfo * p); // obsolete, use avs_is_yuv420 + +AVSC_API(int, avs_is_y32)(const AVS_VideoInfo * p); // obsolete, use avs_is_y + +AVSC_API(int, avs_is_444)(const AVS_VideoInfo * p); + +AVSC_API(int, avs_is_422)(const AVS_VideoInfo * p); + +AVSC_API(int, avs_is_420)(const AVS_VideoInfo * p); + +AVSC_API(int, avs_is_y)(const AVS_VideoInfo * p); + +AVSC_API(int, avs_is_yuva)(const AVS_VideoInfo * p); + +AVSC_API(int, avs_is_planar_rgb)(const AVS_VideoInfo * p); + +AVSC_API(int, avs_is_planar_rgba)(const AVS_VideoInfo * p); + AVSC_API(int, avs_num_components)(const AVS_VideoInfo * p); AVSC_API(int, avs_component_size)(const AVS_VideoInfo * p); AVSC_API(int, avs_bits_per_component)(const AVS_VideoInfo * p); +// end of Avisynth+ specific ///////////////////////////////////////////////////////////////////// // @@ -513,11 +544,15 @@ AVSC_API(int, avs_bits_per_component)(const AVS_VideoInfo * p); // to be reused. The instances are deleted when the corresponding AVS // file is closed. -// AVS_VideoFrameBuffer is layed out identicly to VideoFrameBuffer +// AVS_VideoFrameBuffer is laid out identically to VideoFrameBuffer // DO NOT USE THIS STRUCTURE DIRECTLY typedef struct AVS_VideoFrameBuffer { BYTE * data; +#ifdef SIZETMOD + size_t data_size; +#else int data_size; +#endif // sequence_number is incremented every time the buffer is changed, so // that stale views can tell they're no longer valid. volatile long sequence_number; @@ -527,56 +562,94 @@ typedef struct AVS_VideoFrameBuffer { // VideoFrame holds a "window" into a VideoFrameBuffer. -// AVS_VideoFrame is layed out identicly to IVideoFrame +// AVS_VideoFrame is laid out identically to IVideoFrame // DO NOT USE THIS STRUCTURE DIRECTLY typedef struct AVS_VideoFrame { volatile long refcount; AVS_VideoFrameBuffer * vfb; - int offset, pitch, row_size, height, offsetU, offsetV, pitchUV; // U&V offsets are from top of picture. - int row_sizeUV, heightUV; +#ifdef SIZETMOD + size_t offset; +#else + int offset; +#endif + int pitch, row_size, height; +#ifdef SIZETMOD + size_t offsetU, offsetV; +#else + int offsetU, offsetV; +#endif + int pitchUV; // U&V offsets are from top of picture. + int row_sizeUV, heightUV; // for Planar RGB offsetU, offsetV is for the 2nd and 3rd Plane. + // for Planar RGB pitchUV and row_sizeUV = 0, because when no VideoInfo (MakeWriteable) + // the decision on existence of UV is checked by zero pitch + // AVS+ extension, avisynth.h: class does not break plugins if appended here +#ifdef SIZETMOD + size_t offsetA; +#else + int offsetA; +#endif + int pitchA, row_sizeA; // 4th alpha plane support, pitch and row_size is 0 is none } AVS_VideoFrame; // Access functions for AVS_VideoFrame AVSC_API(int, avs_get_pitch_p)(const AVS_VideoFrame * p, int plane); -#ifdef AVS_IMPLICIT_FUNCTION_DECLARATION_ERROR -AVSC_INLINE int avs_get_pitch(const AVS_VideoFrame * p) { - return avs_get_pitch_p(p, 0);} -#endif - AVSC_API(int, avs_get_row_size_p)(const AVS_VideoFrame * p, int plane); -AVSC_INLINE int avs_get_row_size(const AVS_VideoFrame * p) { - return p->row_size; } - AVSC_API(int, avs_get_height_p)(const AVS_VideoFrame * p, int plane); -AVSC_INLINE int avs_get_height(const AVS_VideoFrame * p) { - return p->height;} - AVSC_API(const BYTE *, avs_get_read_ptr_p)(const AVS_VideoFrame * p, int plane); -#ifdef AVS_IMPLICIT_FUNCTION_DECLARATION_ERROR -AVSC_INLINE const BYTE* avs_get_read_ptr(const AVS_VideoFrame * p) { - return avs_get_read_ptr_p(p, 0);} -#endif - AVSC_API(int, avs_is_writable)(const AVS_VideoFrame * p); AVSC_API(BYTE *, avs_get_write_ptr_p)(const AVS_VideoFrame * p, int plane); -#ifdef AVS_IMPLICIT_FUNCTION_DECLARATION_ERROR -AVSC_INLINE BYTE* avs_get_write_ptr(const AVS_VideoFrame * p) { - return avs_get_write_ptr_p(p, 0);} -#endif - AVSC_API(void, avs_release_video_frame)(AVS_VideoFrame *); // makes a shallow copy of a video frame AVSC_API(AVS_VideoFrame *, avs_copy_video_frame)(AVS_VideoFrame *); +// no API for these, inline helper functions #ifndef AVSC_NO_DECLSPEC +// this inline function is calling an API function +AVSC_INLINE int avs_get_pitch(const AVS_VideoFrame * p) { + return avs_get_pitch_p(p, 0); +} +#endif + +#ifndef AVSC_NO_DECLSPEC +// this inline function is calling an API function +AVSC_INLINE int avs_get_row_size(const AVS_VideoFrame * p) { + return avs_get_row_size_p(p, 0); } +#endif + + +#ifndef AVSC_NO_DECLSPEC +// this inline function is calling an API function +AVSC_INLINE int avs_get_height(const AVS_VideoFrame * p) { + return avs_get_height_p(p, 0); +} +#endif + +#ifndef AVSC_NO_DECLSPEC +// this inline function is calling an API function +AVSC_INLINE const BYTE* avs_get_read_ptr(const AVS_VideoFrame * p) { + return avs_get_read_ptr_p(p, 0);} +#endif + +#ifndef AVSC_NO_DECLSPEC +// this inline function is calling an API function +AVSC_INLINE BYTE* avs_get_write_ptr(const AVS_VideoFrame * p) { + return avs_get_write_ptr_p(p, 0);} +#endif + +#ifndef AVSC_NO_DECLSPEC +// this inline function is calling an API function AVSC_INLINE void avs_release_frame(AVS_VideoFrame * f) {avs_release_video_frame(f);} +#endif + +#ifndef AVSC_NO_DECLSPEC +// this inline function is calling an API function AVSC_INLINE AVS_VideoFrame * avs_copy_frame(AVS_VideoFrame * f) {return avs_copy_video_frame(f);} #endif @@ -587,14 +660,14 @@ AVSC_INLINE AVS_VideoFrame * avs_copy_frame(AVS_VideoFrame * f) // // Treat AVS_Value as a fat pointer. That is use avs_copy_value -// and avs_release_value appropiaty as you would if AVS_Value was +// and avs_release_value appropriately as you would if AVS_Value was // a pointer. // To maintain source code compatibility with future versions of the // avisynth_c API don't use the AVS_Value directly. Use the helper // functions below. -// AVS_Value is layed out identicly to AVSValue +// AVS_Value is laid out identically to AVSValue typedef struct AVS_Value AVS_Value; struct AVS_Value { short type; // 'a'rray, 'c'lip, 'b'ool, 'i'nt, 'f'loat, 's'tring, 'v'oid, or 'l'ong @@ -610,15 +683,19 @@ struct AVS_Value { } d; }; -// AVS_Value should be initilized with avs_void. +// AVS_Value should be initialized with avs_void. // Should also set to avs_void after the value is released -// with avs_copy_value. Consider it the equalvent of setting +// with avs_copy_value. Consider it the equivalent of setting // a pointer to NULL static const AVS_Value avs_void = {'v'}; AVSC_API(void, avs_copy_value)(AVS_Value * dest, AVS_Value src); AVSC_API(void, avs_release_value)(AVS_Value); +AVSC_API(AVS_Clip *, avs_take_clip)(AVS_Value, AVS_ScriptEnvironment *); +AVSC_API(void, avs_set_to_clip)(AVS_Value *, AVS_Clip *); + +// no API for these, inline helper functions AVSC_INLINE int avs_defined(AVS_Value v) { return v.type != 'v'; } AVSC_INLINE int avs_is_clip(AVS_Value v) { return v.type == 'c'; } AVSC_INLINE int avs_is_bool(AVS_Value v) { return v.type == 'b'; } @@ -628,9 +705,6 @@ AVSC_INLINE int avs_is_string(AVS_Value v) { return v.type == 's'; } AVSC_INLINE int avs_is_array(AVS_Value v) { return v.type == 'a'; } AVSC_INLINE int avs_is_error(AVS_Value v) { return v.type == 'e'; } -AVSC_API(AVS_Clip *, avs_take_clip)(AVS_Value, AVS_ScriptEnvironment *); -AVSC_API(void, avs_set_to_clip)(AVS_Value *, AVS_Clip *); - AVSC_INLINE int avs_as_bool(AVS_Value v) { return v.d.boolean; } AVSC_INLINE int avs_as_int(AVS_Value v) @@ -661,11 +735,13 @@ AVSC_INLINE AVS_Value avs_new_value_float(float v0) AVSC_INLINE AVS_Value avs_new_value_error(const char * v0) { AVS_Value v; v.type = 'e'; v.d.string = v0; return v; } #ifndef AVSC_NO_DECLSPEC +// this inline function is calling an API function AVSC_INLINE AVS_Value avs_new_value_clip(AVS_Clip * v0) { AVS_Value v; avs_set_to_clip(&v, v0); return v; } #endif AVSC_INLINE AVS_Value avs_new_value_array(AVS_Value * v0, int size) { AVS_Value v; v.type = 'a'; v.d.array = v0; v.array_size = (short)size; return v; } +// end of inline helper functions ///////////////////////////////////////////////////////////////////// // @@ -722,7 +798,7 @@ struct AVS_FilterInfo // Create a new filter // fi is set to point to the AVS_FilterInfo so that you can -// modify it once it is initilized. +// modify it once it is initialized. // store_child should generally be set to true. If it is not // set than ALL methods (the function pointers) must be defined // If it is set than you do not need to worry about freeing the child @@ -753,10 +829,26 @@ enum { AVS_CPUF_SSSE3 = 0x200, // Core 2 AVS_CPUF_SSE4 = 0x400, // Penryn, Wolfdale, Yorkfield AVS_CPUF_SSE4_1 = 0x400, -//AVS_CPUF_AVX = 0x800, // Sandy Bridge, Bulldozer + AVS_CPUF_AVX = 0x800, // Sandy Bridge, Bulldozer AVS_CPUF_SSE4_2 = 0x1000, // Nehalem -//AVS_CPUF_AVX2 = 0x2000, // Haswell -//AVS_CPUF_AVX512 = 0x4000, // Knights Landing + // AVS+ + AVS_CPUF_AVX2 = 0x2000, // Haswell + AVS_CPUF_FMA3 = 0x4000, + AVS_CPUF_F16C = 0x8000, + AVS_CPUF_MOVBE = 0x10000, // Big Endian Move + AVS_CPUF_POPCNT = 0x20000, + AVS_CPUF_AES = 0x40000, + AVS_CPUF_FMA4 = 0x80000, + + AVS_CPUF_AVX512F = 0x100000, // AVX-512 Foundation. + AVS_CPUF_AVX512DQ = 0x200000, // AVX-512 DQ (Double/Quad granular) Instructions + AVS_CPUF_AVX512PF = 0x400000, // AVX-512 Prefetch + AVS_CPUF_AVX512ER = 0x800000, // AVX-512 Exponential and Reciprocal + AVS_CPUF_AVX512CD = 0x1000000, // AVX-512 Conflict Detection + AVS_CPUF_AVX512BW = 0x2000000, // AVX-512 BW (Byte/Word granular) Instructions + AVS_CPUF_AVX512VL = 0x4000000, // AVX-512 VL (128/256 Vector Length) Extensions + AVS_CPUF_AVX512IFMA = 0x8000000, // AVX-512 IFMA integer 52 bit + AVS_CPUF_AVX512VBMI = 0x10000000 // AVX-512 VBMI }; @@ -793,20 +885,23 @@ AVSC_API(int, avs_set_global_var)(AVS_ScriptEnvironment *, const char* name, con AVSC_API(AVS_VideoFrame *, avs_new_video_frame_a)(AVS_ScriptEnvironment *, const AVS_VideoInfo * vi, int align); -// align should be at least 16 +// align should be at least 16 for classic Avisynth +// Avisynth+: any value, Avs+ ensures a minimum alignment if too small align is provided +// no API for these, inline helper functions #ifndef AVSC_NO_DECLSPEC -AVSC_INLINE -AVS_VideoFrame * avs_new_video_frame(AVS_ScriptEnvironment * env, +// this inline function is calling an API function +AVSC_INLINE AVS_VideoFrame * avs_new_video_frame(AVS_ScriptEnvironment * env, const AVS_VideoInfo * vi) - {return avs_new_video_frame_a(env,vi,FRAME_ALIGN);} + {return avs_new_video_frame_a(env,vi,AVS_FRAME_ALIGN);} -AVSC_INLINE -AVS_VideoFrame * avs_new_frame(AVS_ScriptEnvironment * env, +// an older compatibility alias +// this inline function is calling an API function +AVSC_INLINE AVS_VideoFrame * avs_new_frame(AVS_ScriptEnvironment * env, const AVS_VideoInfo * vi) - {return avs_new_video_frame_a(env,vi,FRAME_ALIGN);} + {return avs_new_video_frame_a(env,vi,AVS_FRAME_ALIGN);} #endif - +// end of inline helper functions AVSC_API(int, avs_make_writable)(AVS_ScriptEnvironment *, AVS_VideoFrame * * pvf); @@ -839,7 +934,10 @@ AVSC_API(AVS_VideoFrame *, avs_subframe_planar)(AVS_ScriptEnvironment *, AVS_Vid // The returned video frame must be be released #ifdef AVSC_NO_DECLSPEC -// use LoadLibrary and related functions to dynamically load Avisynth instead of declspec(dllimport) +// This part uses LoadLibrary and related functions to dynamically load Avisynth instead of declspec(dllimport) +// When AVSC_NO_DECLSPEC is defined, you can use avs_load_library to populate API functions into a struct +// AVSC_INLINE functions which call onto an API functions should be treated specially (todo) + /* The following functions needs to have been declared, probably from windows.h @@ -856,6 +954,14 @@ typedef struct AVS_Library AVS_Library; #define AVSC_DECLARE_FUNC(name) name##_func name +// AVSC_DECLARE_FUNC helps keeping naming convention: type is xxxxx_func, function name is xxxxx +// e.g. "AVSC_DECLARE_FUNC(avs_add_function);" +// is a shortcut for "avs_add_function_func avs_add_function;" + +// Note: AVSC_INLINE functions which call into API, +// are guarded by #ifndef AVSC_NO_DECLSPEC +// They should call the appropriate library-> API entry + struct AVS_Library { HMODULE handle; @@ -898,28 +1004,11 @@ struct AVS_Library { AVSC_DECLARE_FUNC(avs_vsprintf); AVSC_DECLARE_FUNC(avs_get_error); - AVSC_DECLARE_FUNC(avs_is_rgb48); - AVSC_DECLARE_FUNC(avs_is_rgb64); AVSC_DECLARE_FUNC(avs_is_yv24); AVSC_DECLARE_FUNC(avs_is_yv16); AVSC_DECLARE_FUNC(avs_is_yv12); AVSC_DECLARE_FUNC(avs_is_yv411); AVSC_DECLARE_FUNC(avs_is_y8); - AVSC_DECLARE_FUNC(avs_is_yuv444p16); - AVSC_DECLARE_FUNC(avs_is_yuv422p16); - AVSC_DECLARE_FUNC(avs_is_yuv420p16); - AVSC_DECLARE_FUNC(avs_is_y16); - AVSC_DECLARE_FUNC(avs_is_yuv444ps); - AVSC_DECLARE_FUNC(avs_is_yuv422ps); - AVSC_DECLARE_FUNC(avs_is_yuv420ps); - AVSC_DECLARE_FUNC(avs_is_y32); - AVSC_DECLARE_FUNC(avs_is_444); - AVSC_DECLARE_FUNC(avs_is_422); - AVSC_DECLARE_FUNC(avs_is_420); - AVSC_DECLARE_FUNC(avs_is_y); - AVSC_DECLARE_FUNC(avs_is_yuva); - AVSC_DECLARE_FUNC(avs_is_planar_rgb); - AVSC_DECLARE_FUNC(avs_is_planar_rgba); AVSC_DECLARE_FUNC(avs_is_color_space); AVSC_DECLARE_FUNC(avs_get_plane_width_subsampling); @@ -935,14 +1024,73 @@ struct AVS_Library { AVSC_DECLARE_FUNC(avs_is_writable); AVSC_DECLARE_FUNC(avs_get_write_ptr_p); + // Avisynth+ specific + // Note: these functions are simulated/use fallback to existing functions + AVSC_DECLARE_FUNC(avs_is_rgb48); + AVSC_DECLARE_FUNC(avs_is_rgb64); + AVSC_DECLARE_FUNC(avs_is_yuv444p16); + AVSC_DECLARE_FUNC(avs_is_yuv422p16); + AVSC_DECLARE_FUNC(avs_is_yuv420p16); + AVSC_DECLARE_FUNC(avs_is_y16); + AVSC_DECLARE_FUNC(avs_is_yuv444ps); + AVSC_DECLARE_FUNC(avs_is_yuv422ps); + AVSC_DECLARE_FUNC(avs_is_yuv420ps); + AVSC_DECLARE_FUNC(avs_is_y32); + AVSC_DECLARE_FUNC(avs_is_444); + AVSC_DECLARE_FUNC(avs_is_422); + AVSC_DECLARE_FUNC(avs_is_420); + AVSC_DECLARE_FUNC(avs_is_y); + AVSC_DECLARE_FUNC(avs_is_yuva); + AVSC_DECLARE_FUNC(avs_is_planar_rgb); + AVSC_DECLARE_FUNC(avs_is_planar_rgba); AVSC_DECLARE_FUNC(avs_num_components); AVSC_DECLARE_FUNC(avs_component_size); AVSC_DECLARE_FUNC(avs_bits_per_component); + // end of Avisynth+ specific }; #undef AVSC_DECLARE_FUNC +// Helper functions for fallback simulation +// Avisynth+ extensions do not exist in classic Avisynth so they are simulated +AVSC_INLINE int avs_is_xx_fallback_return_false(const AVS_VideoInfo * p) +{ + return 0; +} + +// Avisynth+ extensions do not exist in classic Avisynth so they are simulated +AVSC_INLINE int avs_num_components_fallback(const AVS_VideoInfo * p) +{ + switch (p->pixel_type) { + case AVS_CS_UNKNOWN: + return 0; + case AVS_CS_RAW32: + case AVS_CS_Y8: + return 1; + case AVS_CS_BGR32: + return 4; // not planar but return the count + default: + return 3; + } +} + +// Avisynth+ extensions do not exist in classic Avisynth so they are simulated +AVSC_INLINE int avs_component_size_fallback(const AVS_VideoInfo * p) +{ + return 1; +} + +// Avisynth+ extensions do not exist in classic Avisynth so they are simulated +AVSC_INLINE int avs_bits_per_component_fallback(const AVS_VideoInfo * p) +{ + return 8; +} +// End of helper functions for fallback simulation + +// avs_load_library() allocates an array for API procedure entries +// reads and fills the entries with live procedure addresses. +// AVSC_INLINE helpers which are calling into API procedures are not treated here (todo) AVSC_INLINE AVS_Library * avs_load_library() { AVS_Library *library = (AVS_Library *)malloc(sizeof(AVS_Library)); @@ -960,6 +1108,55 @@ AVSC_INLINE AVS_Library * avs_load_library() { goto fail;\ } +#if 0 +// FFmpeg-specific: we don't use the FALLBACK stuff, and it causes build errors, +// so ifdef it out on our side. + +// When an API function is not loadable, let's try a replacement +// Missing Avisynth+ functions will be substituted with classic Avisynth compatible methods +/* +Avisynth+ When method is missing (classic Avisynth) +avs_is_rgb48 constant false +avs_is_rgb64 constant false +avs_is_yuv444p16 constant false +avs_is_yuv422p16 constant false +avs_is_yuv420p16 constant false +avs_is_y16 constant false +avs_is_yuv444ps constant false +avs_is_yuv422ps constant false +avs_is_yuv420ps constant false +avs_is_y32 constant false +avs_is_444 avs_is_yv24 +avs_is_422 avs_is_yv16 +avs_is_420 avs_is_yv12 +avs_is_y avs_is_y8 +avs_is_yuva constant false +avs_is_planar_rgb constant false +avs_is_planar_rgba constant false +avs_num_components special: avs_num_components_fake Y8:1 RGB32:4 else 3 +avs_component_size constant 1 (1 bytes/component) +avs_bits_per_component constant 8 (8 bits/component) +*/ + + // try to load an alternative function +#define AVSC_LOAD_FUNC_FALLBACK(name,name2) {\ + library->name = (name##_func) GetProcAddress(library->handle, AVSC_STRINGIFY(name));\ + if (library->name == NULL)\ + library->name = (name##_func) GetProcAddress(library->handle, AVSC_STRINGIFY(name2));\ + if (library->name == NULL)\ + goto fail;\ +} + + // try to assign a replacement function +#define AVSC_LOAD_FUNC_FALLBACK_SIMULATED(name,name2) {\ + library->name = (name##_func) GetProcAddress(library->handle, AVSC_STRINGIFY(name));\ + if (library->name == NULL)\ + library->name = name2;\ + if (library->name == NULL)\ + goto fail;\ +} +#endif + AVSC_LOAD_FUNC(avs_add_function); AVSC_LOAD_FUNC(avs_at_exit); AVSC_LOAD_FUNC(avs_bit_blt); @@ -999,28 +1196,11 @@ AVSC_INLINE AVS_Library * avs_load_library() { AVSC_LOAD_FUNC(avs_vsprintf); AVSC_LOAD_FUNC(avs_get_error); - AVSC_LOAD_FUNC(avs_is_rgb48); - AVSC_LOAD_FUNC(avs_is_rgb64); AVSC_LOAD_FUNC(avs_is_yv24); AVSC_LOAD_FUNC(avs_is_yv16); AVSC_LOAD_FUNC(avs_is_yv12); AVSC_LOAD_FUNC(avs_is_yv411); AVSC_LOAD_FUNC(avs_is_y8); - AVSC_LOAD_FUNC(avs_is_yuv444p16); - AVSC_LOAD_FUNC(avs_is_yuv422p16); - AVSC_LOAD_FUNC(avs_is_yuv420p16); - AVSC_LOAD_FUNC(avs_is_y16); - AVSC_LOAD_FUNC(avs_is_yuv444ps); - AVSC_LOAD_FUNC(avs_is_yuv422ps); - AVSC_LOAD_FUNC(avs_is_yuv420ps); - AVSC_LOAD_FUNC(avs_is_y32); - AVSC_LOAD_FUNC(avs_is_444); - AVSC_LOAD_FUNC(avs_is_422); - AVSC_LOAD_FUNC(avs_is_420); - AVSC_LOAD_FUNC(avs_is_y); - AVSC_LOAD_FUNC(avs_is_yuva); - AVSC_LOAD_FUNC(avs_is_planar_rgb); - AVSC_LOAD_FUNC(avs_is_planar_rgba); AVSC_LOAD_FUNC(avs_is_color_space); AVSC_LOAD_FUNC(avs_get_plane_width_subsampling); @@ -1036,15 +1216,35 @@ AVSC_INLINE AVS_Library * avs_load_library() { AVSC_LOAD_FUNC(avs_is_writable); AVSC_LOAD_FUNC(avs_get_write_ptr_p); - AVSC_LOAD_FUNC(avs_num_components); - AVSC_LOAD_FUNC(avs_component_size); - AVSC_LOAD_FUNC(avs_bits_per_component); - - +#if 0 + // Avisynth+ specific but made them callable for classic Avisynth hosts + AVSC_LOAD_FUNC_FALLBACK_SIMULATED(avs_is_rgb48, avs_is_xx_fallback_return_false); + AVSC_LOAD_FUNC_FALLBACK_SIMULATED(avs_is_rgb64, avs_is_xx_fallback_return_false); + AVSC_LOAD_FUNC_FALLBACK_SIMULATED(avs_is_yuv444p16, avs_is_xx_fallback_return_false); + AVSC_LOAD_FUNC_FALLBACK_SIMULATED(avs_is_yuv422p16, avs_is_xx_fallback_return_false); + AVSC_LOAD_FUNC_FALLBACK_SIMULATED(avs_is_yuv420p16, avs_is_xx_fallback_return_false); + AVSC_LOAD_FUNC_FALLBACK_SIMULATED(avs_is_y16, avs_is_xx_fallback_return_false); + AVSC_LOAD_FUNC_FALLBACK_SIMULATED(avs_is_yuv444ps, avs_is_xx_fallback_return_false); + AVSC_LOAD_FUNC_FALLBACK_SIMULATED(avs_is_yuv422ps, avs_is_xx_fallback_return_false); + AVSC_LOAD_FUNC_FALLBACK_SIMULATED(avs_is_yuv420ps, avs_is_xx_fallback_return_false); + AVSC_LOAD_FUNC_FALLBACK_SIMULATED(avs_is_y32, avs_is_xx_fallback_return_false); + AVSC_LOAD_FUNC_FALLBACK(avs_is_444, avs_is_yv24); + AVSC_LOAD_FUNC_FALLBACK(avs_is_422, avs_is_yv16); + AVSC_LOAD_FUNC_FALLBACK(avs_is_420, avs_is_yv12); + AVSC_LOAD_FUNC_FALLBACK(avs_is_y, avs_is_y8); + AVSC_LOAD_FUNC_FALLBACK_SIMULATED(avs_is_yuva, avs_is_xx_fallback_return_false); + AVSC_LOAD_FUNC_FALLBACK_SIMULATED(avs_is_planar_rgb, avs_is_xx_fallback_return_false); + AVSC_LOAD_FUNC_FALLBACK_SIMULATED(avs_is_planar_rgba, avs_is_xx_fallback_return_false); + AVSC_LOAD_FUNC_FALLBACK_SIMULATED(avs_num_components, avs_num_components_fallback); + AVSC_LOAD_FUNC_FALLBACK_SIMULATED(avs_component_size, avs_component_size_fallback); + AVSC_LOAD_FUNC_FALLBACK_SIMULATED(avs_bits_per_component, avs_bits_per_component_fallback); +#endif #undef __AVSC_STRINGIFY #undef AVSC_STRINGIFY #undef AVSC_LOAD_FUNC +#undef AVSC_LOAD_FUNC_FALLBACK +#undef AVSC_LOAD_FUNC_FALLBACK_SIMULATED return library; diff --git a/compat/avisynth/avs/capi.h b/compat/avisynth/avs/capi.h index 6ed6770c6..8799bf1fb 100644 --- a/compat/avisynth/avs/capi.h +++ b/compat/avisynth/avs/capi.h @@ -39,17 +39,49 @@ # define EXTERN_C #endif -#ifndef AVSC_USE_STDCALL -# define AVSC_CC __cdecl -#else -# define AVSC_CC __stdcall +#ifdef BUILDING_AVSCORE +# if defined(GCC) && defined(X86_32) +# define AVSC_CC +# else // MSVC builds and 64-bit GCC +# ifndef AVSC_USE_STDCALL +# define AVSC_CC __cdecl +# else +# define AVSC_CC __stdcall +# endif +# endif +#else // needed for programs that talk to AviSynth+ +# ifndef AVSC_WIN32_GCC32 // see comment below +# ifndef AVSC_USE_STDCALL +# define AVSC_CC __cdecl +# else +# define AVSC_CC __stdcall +# endif +# else +# define AVSC_CC +# endif #endif +// On 64-bit Windows, there's only one calling convention, +// so there is no difference between MSVC and GCC. On 32-bit, +// this isn't true. The convention that GCC needs to use to +// even build AviSynth+ as 32-bit makes anything that uses +// it incompatible with 32-bit MSVC builds of AviSynth+. +// The AVSC_WIN32_GCC32 define is meant to provide a user +// switchable way to make builds of FFmpeg to test 32-bit +// GCC builds of AviSynth+ without having to screw around +// with alternate headers, while still default to the usual +// situation of using 32-bit MSVC builds of AviSynth+. + +// Hopefully, this situation will eventually be resolved +// and a broadly compatible solution will arise so the +// same 32-bit FFmpeg build can handle either MSVC or GCC +// builds of AviSynth+. + #define AVSC_INLINE static __inline #ifdef BUILDING_AVSCORE -# define AVSC_EXPORT EXTERN_C -# define AVSC_API(ret, name) EXTERN_C __declspec(dllexport) ret AVSC_CC name +# define AVSC_EXPORT __declspec(dllexport) +# define AVSC_API(ret, name) EXTERN_C AVSC_EXPORT ret AVSC_CC name #else # define AVSC_EXPORT EXTERN_C __declspec(dllexport) # ifndef AVSC_NO_DECLSPEC diff --git a/compat/avisynth/avs/config.h b/compat/avisynth/avs/config.h index 7acd95b57..a7d3e692e 100644 --- a/compat/avisynth/avs/config.h +++ b/compat/avisynth/avs/config.h @@ -42,7 +42,7 @@ // alignment. They should always request the exact alignment value they need. // This is to make sure that plugins work over the widest range of AviSynth // builds possible. -#define FRAME_ALIGN 32 +#define FRAME_ALIGN 64 #if defined(_M_AMD64) || defined(__x86_64) # define X86_64 @@ -52,4 +52,19 @@ # error Unsupported CPU architecture. #endif +#if defined(_MSC_VER) +# define MSVC +#elif defined(__GNUC__) +# define GCC +#elif defined(__clang__) +# define CLANG +#else +# error Unsupported compiler. +#endif + +#if defined(GCC) +# undef __forceinline +# define __forceinline inline +#endif + #endif //AVS_CONFIG_H diff --git a/compat/avisynth/avs/types.h b/compat/avisynth/avs/types.h index e5f084cd3..df15f1d8e 100644 --- a/compat/avisynth/avs/types.h +++ b/compat/avisynth/avs/types.h @@ -35,6 +35,12 @@ // Define all types necessary for interfacing with avisynth.dll +#ifdef __cplusplus + #include +#else + #include +#endif + // Raster types used by VirtualDub & Avisynth typedef unsigned int Pixel32; typedef unsigned char BYTE; diff --git a/compat/cuda/cuda_runtime.h b/compat/cuda/cuda_runtime.h new file mode 100644 index 000000000..92c55ad85 --- /dev/null +++ b/compat/cuda/cuda_runtime.h @@ -0,0 +1,131 @@ +/* + * Minimum CUDA compatibility definitions header + * + * Copyright (c) 2019 Rodger Combs + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef COMPAT_CUDA_CUDA_RUNTIME_H +#define COMPAT_CUDA_CUDA_RUNTIME_H + +// Common macros +#define __global__ __attribute__((global)) +#define __device__ __attribute__((device)) +#define __device_builtin__ __attribute__((device_builtin)) +#define __align__(N) __attribute__((aligned(N))) +#define __inline__ __inline__ __attribute__((always_inline)) + +#define max(a, b) ((a) > (b) ? (a) : (b)) +#define min(a, b) ((a) < (b) ? (a) : (b)) +#define abs(x) ((x) < 0 ? -(x) : (x)) + +#define atomicAdd(a, b) (__atomic_fetch_add(a, b, __ATOMIC_SEQ_CST)) + +// Basic typedefs +typedef __device_builtin__ unsigned long long cudaTextureObject_t; + +typedef struct __device_builtin__ __align__(2) uchar2 +{ + unsigned char x, y; +} uchar2; + +typedef struct __device_builtin__ __align__(4) ushort2 +{ + unsigned short x, y; +} ushort2; + +typedef struct __device_builtin__ uint3 +{ + unsigned int x, y, z; +} uint3; + +typedef struct uint3 dim3; + +typedef struct __device_builtin__ __align__(8) int2 +{ + int x, y; +} int2; + +typedef struct __device_builtin__ __align__(4) uchar4 +{ + unsigned char x, y, z, w; +} uchar4; + +typedef struct __device_builtin__ __align__(8) ushort4 +{ + unsigned char x, y, z, w; +} ushort4; + +typedef struct __device_builtin__ __align__(16) int4 +{ + int x, y, z, w; +} int4; + +// Accessors for special registers +#define GETCOMP(reg, comp) \ + asm("mov.u32 %0, %%" #reg "." #comp ";" : "=r"(tmp)); \ + ret.comp = tmp; + +#define GET(name, reg) static inline __device__ uint3 name() {\ + uint3 ret; \ + unsigned tmp; \ + GETCOMP(reg, x) \ + GETCOMP(reg, y) \ + GETCOMP(reg, z) \ + return ret; \ +} + +GET(getBlockIdx, ctaid) +GET(getBlockDim, ntid) +GET(getThreadIdx, tid) + +// Instead of externs for these registers, we turn access to them into calls into trivial ASM +#define blockIdx (getBlockIdx()) +#define blockDim (getBlockDim()) +#define threadIdx (getThreadIdx()) + +// Basic initializers (simple macros rather than inline functions) +#define make_uchar2(a, b) ((uchar2){.x = a, .y = b}) +#define make_ushort2(a, b) ((ushort2){.x = a, .y = b}) +#define make_uchar4(a, b, c, d) ((uchar4){.x = a, .y = b, .z = c, .w = d}) +#define make_ushort4(a, b, c, d) ((ushort4){.x = a, .y = b, .z = c, .w = d}) + +// Conversions from the tex instruction's 4-register output to various types +#define TEX2D(type, ret) static inline __device__ void conv(type* out, unsigned a, unsigned b, unsigned c, unsigned d) {*out = (ret);} + +TEX2D(unsigned char, a & 0xFF) +TEX2D(unsigned short, a & 0xFFFF) +TEX2D(uchar2, make_uchar2(a & 0xFF, b & 0xFF)) +TEX2D(ushort2, make_ushort2(a & 0xFFFF, b & 0xFFFF)) +TEX2D(uchar4, make_uchar4(a & 0xFF, b & 0xFF, c & 0xFF, d & 0xFF)) +TEX2D(ushort4, make_ushort4(a & 0xFFFF, b & 0xFFFF, c & 0xFFFF, d & 0xFFFF)) + +// Template calling tex instruction and converting the output to the selected type +template +static inline __device__ T tex2D(cudaTextureObject_t texObject, float x, float y) +{ + T ret; + unsigned ret1, ret2, ret3, ret4; + asm("tex.2d.v4.u32.f32 {%0, %1, %2, %3}, [%4, {%5, %6}];" : + "=r"(ret1), "=r"(ret2), "=r"(ret3), "=r"(ret4) : + "l"(texObject), "f"(x), "f"(y)); + conv(&ret, ret1, ret2, ret3, ret4); + return ret; +} + +#endif /* COMPAT_CUDA_CUDA_RUNTIME_H */ diff --git a/compat/cuda/dynlink_loader.h b/compat/cuda/dynlink_loader.h index 9f9346508..ca79e604c 100644 --- a/compat/cuda/dynlink_loader.h +++ b/compat/cuda/dynlink_loader.h @@ -16,8 +16,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef AV_COMPAT_CUDA_DYNLINK_LOADER_H -#define AV_COMPAT_CUDA_DYNLINK_LOADER_H +#ifndef COMPAT_CUDA_DYNLINK_LOADER_H +#define COMPAT_CUDA_DYNLINK_LOADER_H #include "libavutil/log.h" #include "compat/w32dlfcn.h" @@ -30,4 +30,4 @@ #include -#endif +#endif /* COMPAT_CUDA_DYNLINK_LOADER_H */ diff --git a/compat/cuda/ptx2c.sh b/compat/cuda/ptx2c.sh index 5ccabbf56..0750e7a3b 100755 --- a/compat/cuda/ptx2c.sh +++ b/compat/cuda/ptx2c.sh @@ -27,7 +27,7 @@ IN="$2" NAME="$(basename "$IN" | sed 's/\..*//')" printf "const char %s_ptx[] = \\" "$NAME" > "$OUT" -while read LINE +while IFS= read -r LINE do printf "\n\t\"%s\\\n\"" "$(printf "%s" "$LINE" | sed -e 's/\r//g' -e 's/["\\]/\\&/g')" >> "$OUT" done < "$IN" diff --git a/compat/djgpp/math.c b/compat/djgpp/math.c new file mode 100644 index 000000000..777b879e0 --- /dev/null +++ b/compat/djgpp/math.c @@ -0,0 +1,47 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#define FUN(name, type, op) \ +type name(type x, type y) \ +{ \ + if (fpclassify(x) == FP_NAN) return y; \ + if (fpclassify(y) == FP_NAN) return x; \ + return x op y ? x : y; \ +} + +FUN(fmin, double, <) +FUN(fmax, double, >) +FUN(fminf, float, <) +FUN(fmaxf, float, >) + +long double fmodl(long double x, long double y) +{ + return fmod(x, y); +} + +long double scalbnl(long double x, int exp) +{ + return scalbn(x, exp); +} + +long double copysignl(long double x, long double y) +{ + return copysign(x, y); +} diff --git a/compat/djgpp/math.h b/compat/djgpp/math.h new file mode 100644 index 000000000..4c02ea9c4 --- /dev/null +++ b/compat/djgpp/math.h @@ -0,0 +1,25 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +double fmin(double, double); +double fmax(double, double); +float fminf(float, float); +float fmaxf(float, float); +long double fmodl(long double, long double); +long double scalbnl(long double, int); +long double copysignl(long double, long double); diff --git a/compat/windows/makedef b/compat/windows/makedef index 7258b94a9..add8222d1 100755 --- a/compat/windows/makedef +++ b/compat/windows/makedef @@ -48,7 +48,7 @@ trap 'rm -f -- $libname' EXIT if [ -n "$AR" ]; then $AR rcs ${libname} $@ >/dev/null else - lib -out:${libname} $@ >/dev/null + lib.exe -out:${libname} $@ >/dev/null fi if [ $? != 0 ]; then echo "Could not create temporary library." >&2 @@ -108,7 +108,7 @@ if [ -n "$NM" ]; then cut -d' ' -f3 | sed -e "s/^${prefix}//") else - dump=$(dumpbin -linkermember:1 ${libname} | + dump=$(dumpbin.exe -linkermember:1 ${libname} | sed -e '/public symbols/,$!d' -e '/^ \{1,\}Summary/,$d' -e "s/ \{1,\}${prefix}/ /" -e 's/ \{1,\}/ /g' | tail -n +2 | cut -d' ' -f3) diff --git a/compat/windows/mslink b/compat/windows/mslink index 07b2b3e37..6cab09007 100755 --- a/compat/windows/mslink +++ b/compat/windows/mslink @@ -4,6 +4,6 @@ LINK_EXE_PATH=$(dirname "$(command -v cl)")/link if [ -x "$LINK_EXE_PATH" ]; then "$LINK_EXE_PATH" $@ else - link $@ + link.exe $@ fi exit $? diff --git a/configure b/configure index 15e6c321b..34c2adb4a 100755 --- a/configure +++ b/configure @@ -213,11 +213,12 @@ External library support: --enable-gmp enable gmp, needed for rtmp(t)e support if openssl or librtmp is not used [no] --enable-gnutls enable gnutls, needed for https support - if openssl or libtls is not used [no] + if openssl, libtls or mbedtls is not used [no] --disable-iconv disable iconv [autodetect] --enable-jni enable JNI support [no] --enable-ladspa enable LADSPA audio filtering [no] --enable-libaom enable AV1 video encoding/decoding via libaom [no] + --enable-libaribb24 enable ARIB text and caption decoding via libaribb24 [no] --enable-libass enable libass subtitles rendering, needed for subtitles and ass filter [no] --enable-libbluray enable BluRay reading using libbluray [no] @@ -226,6 +227,8 @@ External library support: --enable-libcelt enable CELT decoding via libcelt [no] --enable-libcdio enable audio CD grabbing with libcdio [no] --enable-libcodec2 enable codec2 en/decoding using libcodec2 [no] + --enable-libdav1d enable AV1 decoding via libdav1d [no] + --enable-libdavs2 enable AVS2 decoding via libdavs2 [no] --enable-libdc1394 enable IIDC-1394 grabbing using libdc1394 and libraw1394 [no] --enable-libfdk-aac enable AAC de/encoding via libfdk-aac [no] @@ -238,7 +241,9 @@ External library support: --enable-libiec61883 enable iec61883 via libiec61883 [no] --enable-libilbc enable iLBC de/encoding via libilbc [no] --enable-libjack enable JACK audio sound server [no] + --enable-libklvanc enable Kernel Labs VANC processing [no] --enable-libkvazaar enable HEVC encoding via libkvazaar [no] + --enable-liblensfun enable lensfun lens correction [no] --enable-libmodplug enable ModPlug via libmodplug [no] --enable-libmp3lame enable MP3 encoding via libmp3lame [no] --enable-libopencore-amrnb enable AMR-NB de/encoding via libopencore-amrnb [no] @@ -259,10 +264,12 @@ External library support: --enable-libspeex enable Speex de/encoding via libspeex [no] --enable-libsrt enable Haivision SRT protocol via libsrt [no] --enable-libssh enable SFTP protocol via libssh [no] + --enable-libtensorflow enable TensorFlow as a DNN module backend + for DNN based filters like sr [no] --enable-libtesseract enable Tesseract, needed for ocr filter [no] --enable-libtheora enable Theora encoding via libtheora [no] --enable-libtls enable LibreSSL (via libtls), needed for https support - if openssl or gnutls is not used [no] + if openssl, gnutls or mbedtls is not used [no] --enable-libtwolame enable MP2 encoding via libtwolame [no] --enable-libv4l2 enable libv4l2/v4l-utils [no] --enable-libvidstab enable video stabilization using vid.stab [no] @@ -276,40 +283,46 @@ External library support: --enable-libx264 enable H.264 encoding via x264 [no] --enable-libx265 enable HEVC encoding via x265 [no] --enable-libxavs enable AVS encoding via xavs [no] + --enable-libxavs2 enable AVS2 encoding via xavs2 [no] --enable-libxcb enable X11 grabbing using XCB [autodetect] --enable-libxcb-shm enable X11 grabbing shm communication [autodetect] --enable-libxcb-xfixes enable X11 grabbing mouse rendering [autodetect] --enable-libxcb-shape enable X11 grabbing shape rendering [autodetect] --enable-libxvid enable Xvid encoding via xvidcore, native MPEG-4/Xvid encoder exists [no] - --enable-libxml2 enable XML parsing using the C library libxml2 [no] + --enable-libxml2 enable XML parsing using the C library libxml2, needed + for dash demuxing support [no] --enable-libzimg enable z.lib, needed for zscale filter [no] --enable-libzmq enable message passing via libzmq [no] --enable-libzvbi enable teletext support via libzvbi [no] --enable-lv2 enable LV2 audio filtering [no] --disable-lzma disable lzma [autodetect] --enable-decklink enable Blackmagic DeckLink I/O support [no] - --enable-libndi_newtek enable Newteck NDI I/O support [no] + --enable-mbedtls enable mbedTLS, needed for https support + if openssl, gnutls or libtls is not used [no] --enable-mediacodec enable Android MediaCodec support [no] --enable-libmysofa enable libmysofa, needed for sofalizer filter [no] --enable-openal enable OpenAL 1.1 capture support [no] --enable-opencl enable OpenCL processing [no] --enable-opengl enable OpenGL rendering [no] --enable-openssl enable openssl, needed for https support - if gnutls or libtls is not used [no] + if gnutls, libtls or mbedtls is not used [no] + --enable-pocketsphinx enable PocketSphinx, needed for asr filter [no] --disable-sndio disable sndio support [autodetect] --disable-schannel disable SChannel SSP, needed for TLS support on Windows if openssl and gnutls are not used [autodetect] --disable-sdl2 disable sdl2 [autodetect] --disable-securetransport disable Secure Transport, needed for TLS support on OSX if openssl and gnutls are not used [autodetect] + --enable-vapoursynth enable VapourSynth demuxer [no] --disable-xlib disable xlib [autodetect] --disable-zlib disable zlib [autodetect] The following libraries provide various hardware acceleration features: --disable-amf disable AMF video encoding code [autodetect] --disable-audiotoolbox disable Apple AudioToolbox code [autodetect] - --enable-cuda-sdk enable CUDA features that require the CUDA SDK [no] + --enable-cuda-nvcc enable Nvidia CUDA compiler [no] + --disable-cuda-llvm disable CUDA compilation using clang [autodetect] --disable-cuvid disable Nvidia CUVID support [autodetect] --disable-d3d11va disable Microsoft Direct3D 11 video acceleration code [autodetect] --disable-dxva2 disable Microsoft DirectX 9 video acceleration code [autodetect] @@ -358,7 +371,7 @@ Toolchain options: --cxx=CXX use C compiler CXX [$cxx_default] --objcc=OCC use ObjC compiler OCC [$cc_default] --dep-cc=DEPCC use dependency generator DEPCC [$cc_default] - --nvcc=NVCC use Nvidia CUDA compiler NVCC [$nvcc_default] + --nvcc=NVCC use Nvidia CUDA compiler NVCC or clang [$nvcc_default] --ld=LD use linker LD [$ld_default] --pkg-config=PKGCONFIG use pkg-config tool PKGCONFIG [$pkg_config_default] --pkg-config-flags=FLAGS pass additional flags to pkgconf [] @@ -369,7 +382,7 @@ Toolchain options: --host-cppflags=HCPPFLAGS use HCPPFLAGS when compiling for host --host-ld=HOSTLD use host linker HOSTLD --host-ldflags=HLDFLAGS use HLDFLAGS when linking for host - --host-libs=HLIBS use libs HLIBS when linking for host + --host-extralibs=HLIBS use libs HLIBS when linking for host --host-os=OS compiler host OS [$target_os] --extra-cflags=ECFLAGS add ECFLAGS to CFLAGS [$CFLAGS] --extra-cxxflags=ECFLAGS add ECFLAGS to CXXFLAGS [$CXXFLAGS] @@ -429,6 +442,7 @@ Optimization options (experts only): --disable-mipsdsp disable MIPS DSP ASE R1 optimizations --disable-mipsdspr2 disable MIPS DSP ASE R2 optimizations --disable-msa disable MSA optimizations + --disable-msa2 disable MSA2 optimizations --disable-mipsfpu disable floating point MIPS optimizations --disable-mmi disable Loongson SIMD optimizations --disable-fast-unaligned consider unaligned accesses slow @@ -462,7 +476,7 @@ Developer options (useful when working on FFmpeg itself): --random-seed=VALUE seed value for --enable/disable-random --disable-valgrind-backtrace do not print a backtrace under Valgrind (only applies to --disable-optimizations builds) - --enable-osfuzz Enable building fuzzer tool + --enable-ossfuzz Enable building fuzzer tool --libfuzzer=PATH path to libfuzzer --ignore-tests=TESTS comma-separated list (without "fate-" prefix in the name) of tests whose result is ignored @@ -491,9 +505,13 @@ log(){ } log_file(){ - log BEGIN $1 - pr -n -t $1 >> $logfile - log END $1 + log BEGIN "$1" + log_file_i=1 + while IFS= read -r log_file_line; do + printf '%5d\t%s\n' "$log_file_i" "$log_file_line" + log_file_i=$(($log_file_i+1)) + done < "$1" >> "$logfile" + log END "$1" } warn(){ @@ -637,6 +655,12 @@ request(){ done } +warn_if_gets_disabled(){ + for var in $*; do + WARN_IF_GETS_DISABLED_LIST="$WARN_IF_GETS_DISABLED_LIST $var" + done +} + enable(){ set_all yes $* } @@ -645,6 +669,14 @@ disable(){ set_all no $* } +disable_with_reason(){ + disable $1 + eval "${1}_disable_reason=\"$2\"" + if requested $1; then + die "ERROR: $1 requested, but $2" + fi +} + enable_weak(){ set_weak yes $* } @@ -773,10 +805,10 @@ check_deps(){ [ -n "$dep_ifa" ] && { enabled_all $dep_ifa && enable_weak $cfg; } [ -n "$dep_ifn" ] && { enabled_any $dep_ifn && enable_weak $cfg; } - enabled_all $dep_all || { disable $cfg && requested $cfg && die "ERROR: $cfg requested, but not all dependencies are satisfied: $dep_all"; } - enabled_any $dep_any || { disable $cfg && requested $cfg && die "ERROR: $cfg requested, but not any dependency is satisfied: $dep_any"; } - disabled_all $dep_con || { disable $cfg && requested $cfg && die "ERROR: $cfg requested, but some conflicting dependencies are unsatisfied: $dep_con"; } - disabled_any $dep_sel && { disable $cfg && requested $cfg && die "ERROR: $cfg requested, but some selected dependency is unsatisfied: $dep_sel"; } + enabled_all $dep_all || { disable_with_reason $cfg "not all dependencies are satisfied: $dep_all"; } + enabled_any $dep_any || { disable_with_reason $cfg "not any dependency is satisfied: $dep_any"; } + disabled_all $dep_con || { disable_with_reason $cfg "some conflicting dependencies are unsatisfied: $dep_con"; } + disabled_any $dep_sel && { disable_with_reason $cfg "some selected dependency is unsatisfied: $dep_sel"; } enabled $cfg && enable_deep_weak $dep_sel $dep_sgs @@ -891,14 +923,14 @@ add_cxxflags(){ append CXXFLAGS $($cflags_filter "$@") } -add_asflags(){ - append ASFLAGS $($asflags_filter "$@") -} - add_objcflags(){ append OBJCFLAGS $($objcflags_filter "$@") } +add_asflags(){ + append ASFLAGS $($asflags_filter "$@") +} + add_ldflags(){ append LDFLAGS $($ldflags_filter "$@") } @@ -911,14 +943,14 @@ add_ldsoflags(){ append LDSOFLAGS $($ldflags_filter "$@") } -add_stripflags(){ - append ASMSTRIPFLAGS "$@" -} - add_extralibs(){ prepend extralibs $($ldflags_filter "$@") } +add_stripflags(){ + append ASMSTRIPFLAGS "$@" +} + add_host_cppflags(){ append host_cppflags "$@" } @@ -947,12 +979,36 @@ test_stat(){ stat "$1" >> $logfile 2>&1 } +cc_e(){ + eval printf '%s\\n' $CC_E +} + cc_o(){ eval printf '%s\\n' $CC_O } -cc_e(){ - eval printf '%s\\n' $CC_E +as_o(){ + eval printf '%s\\n' $AS_O +} + +x86asm_o(){ + eval printf '%s\\n' $X86ASM_O +} + +ld_o(){ + eval printf '%s\\n' $LD_O +} + +hostcc_e(){ + eval printf '%s\\n' $HOSTCC_E +} + +hostcc_o(){ + eval printf '%s\\n' $HOSTCC_O +} + +nvcc_o(){ + eval printf '%s\\n' $NVCC_O } test_cc(){ @@ -976,6 +1032,29 @@ test_objcc(){ test_cmd $objcc -Werror=missing-prototypes $CPPFLAGS $CFLAGS $OBJCFLAGS "$@" $OBJCC_C $(cc_o $TMPO) $TMPM } +test_nvcc(){ + log test_nvcc "$@" + cat > $TMPCU + log_file $TMPCU + tmpcu_=$TMPCU + tmpo_=$TMPO + [ -x "$(command -v cygpath)" ] && tmpcu_=$(cygpath -m $tmpcu_) && tmpo_=$(cygpath -m $tmpo_) + test_cmd $nvcc $nvccflags "$@" $NVCC_C $(nvcc_o $tmpo_) $tmpcu_ +} + +check_nvcc() { + log check_nvcc "$@" + name=$1 + shift 1 + disabled $name && return + disable $name + test_nvcc "$@" < $TMPC @@ -983,10 +1062,6 @@ test_cpp(){ test_cmd $cc $CPPFLAGS $CFLAGS "$@" $(cc_e $TMPO) $TMPC } -as_o(){ - eval printf '%s\\n' $AS_O -} - test_as(){ log test_as "$@" cat > $TMPS @@ -994,10 +1069,6 @@ test_as(){ test_cmd $as $CPPFLAGS $ASFLAGS "$@" $AS_C $(as_o $TMPO) $TMPS } -x86asm_o(){ - eval printf '%s\\n' $X86ASM_O -} - test_x86asm(){ log test_x86asm "$@" echo "$1" > $TMPASM @@ -1069,10 +1140,6 @@ check_x86asm(){ test_x86asm "$@" && enable $name } -ld_o(){ - eval printf '%s\\n' $LD_O -} - test_ld(){ log test_ld "$@" type=$1 @@ -1183,8 +1250,8 @@ check_stripflags(){ test_stripflags "$@" && add_stripflags "$@" } -check_header(){ - log check_header "$@" +check_headers(){ + log check_headers "$@" headers=$1 shift disable_sanitized $headers @@ -1476,8 +1543,7 @@ require(){ require_cc(){ log require_cc "$@" name="$1" - shift - test_code cc "$@" || die "ERROR: $name failed" + check_cc "$@" || die "ERROR: $name failed" } require_cpp(){ @@ -1488,16 +1554,16 @@ require_cpp(){ check_lib_cpp "$headers" "$classes" "$@" || die "ERROR: $name not found" } -require_header(){ - log require_header "$@" +require_headers(){ + log require_headers "$@" headers="$1" - check_header "$@" || die "ERROR: $headers not found" + check_headers "$@" || die "ERROR: $headers not found" } require_cpp_condition(){ log require_cpp_condition "$@" - condition="$2" - test_cpp_condition "$@" || die "ERROR: $condition not satisfied" + condition="$3" + check_cpp_condition "$@" || die "ERROR: $condition not satisfied" } require_pkg_config(){ @@ -1506,14 +1572,6 @@ require_pkg_config(){ check_pkg_config "$@" || die "ERROR: $pkg_version not found using pkg-config$pkg_config_fail_message" } -hostcc_e(){ - eval printf '%s\\n' $HOSTCC_E -} - -hostcc_o(){ - eval printf '%s\\n' $HOSTCC_O -} - test_host_cc(){ log test_host_cc "$@" cat > $TMPC @@ -1653,17 +1711,18 @@ EXTERNAL_LIBRARY_GPL_LIST=" avisynth frei0r libcdio + libdavs2 librubberband libvidstab libx264 libx265 libxavs + libxavs2 libxvid " EXTERNAL_LIBRARY_NONFREE_LIST=" decklink - libndi_newtek libfdk_aac openssl libtls @@ -1671,10 +1730,13 @@ EXTERNAL_LIBRARY_NONFREE_LIST=" EXTERNAL_LIBRARY_VERSION3_LIST=" gmp + libaribb24 + liblensfun libopencore_amrnb libopencore_amrwb libvmaf libvo_amrwbenc + mbedtls rkmpp " @@ -1699,6 +1761,7 @@ EXTERNAL_LIBRARY_LIST=" libcaca libcelt libcodec2 + libdav1d libdc1394 libdrm libflite @@ -1710,6 +1773,7 @@ EXTERNAL_LIBRARY_LIST=" libiec61883 libilbc libjack + libklvanc libkvazaar libmodplug libmp3lame @@ -1729,6 +1793,7 @@ EXTERNAL_LIBRARY_LIST=" libspeex libsrt libssh + libtensorflow libtesseract libtheora libtwolame @@ -1745,6 +1810,8 @@ EXTERNAL_LIBRARY_LIST=" mediacodec openal opengl + pocketsphinx + vapoursynth " HWACCEL_AUTODETECT_LIBRARY_LIST=" @@ -1752,6 +1819,7 @@ HWACCEL_AUTODETECT_LIBRARY_LIST=" audiotoolbox crystalhd cuda + cuda_llvm cuvid d3d11va dxva2 @@ -1772,6 +1840,7 @@ EXTRALIBS_LIST=" " HWACCEL_LIBRARY_NONFREE_LIST=" + cuda_nvcc cuda_sdk libnpp " @@ -1937,6 +2006,7 @@ ARCH_EXT_LIST_MIPS=" mipsdsp mipsdspr2 msa + msa2 " ARCH_EXT_LIST_LOONGSON=" @@ -2197,6 +2267,7 @@ TOOLCHAIN_FEATURES=" TYPES_LIST=" kCMVideoCodecType_HEVC + kCVPixelFormatType_420YpCbCr10BiPlanarVideoRange socklen_t struct_addrinfo struct_group_source_req @@ -2255,10 +2326,14 @@ CONFIG_EXTRA=" bswapdsp cabac cbs + cbs_av1 cbs_h264 cbs_h265 + cbs_jpeg cbs_mpeg2 + cbs_vp9 dirac_parse + dnn dvprofile exif faandct @@ -2315,6 +2390,7 @@ CONFIG_EXTRA=" rtpdec rtpenc_chain rv34dsp + scene_sad sinewin snappy srtp @@ -2413,6 +2489,7 @@ CMDLINE_SET=" tempprefix toolchain valgrind + windres x86asmexe " @@ -2458,6 +2535,7 @@ mipsdsp_deps="mips" mipsdspr2_deps="mips" mmi_deps="mips" msa_deps="mipsfpu" +msa2_deps="msa" cpunop_deps="i686" x86_64_select="i686" @@ -2516,11 +2594,15 @@ w32threads_deps="atomics_native" threads_if_any="$THREADS_LIST" # subsystems -cbs_h264_select="cbs golomb" -cbs_h265_select="cbs golomb" +cbs_av1_select="cbs" +cbs_h264_select="cbs" +cbs_h265_select="cbs" +cbs_jpeg_select="cbs" cbs_mpeg2_select="cbs" +cbs_vp9_select="cbs" dct_select="rdft" dirac_parse_select="golomb" +dnn_suggest="libtensorflow" error_resilience_select="me_cmp" faandct_deps="faan" faandct_select="fdctdsp" @@ -2537,7 +2619,7 @@ mpeg_er_select="error_resilience" mpegaudio_select="mpegaudiodsp mpegaudioheader" mpegaudiodsp_select="dct" mpegvideo_select="blockdsp h264chroma hpeldsp idctdsp me_cmp mpeg_er videodsp" -mpegvideoenc_select="me_cmp mpegvideo pixblockdsp qpeldsp" +mpegvideoenc_select="aandcttables me_cmp mpegvideo pixblockdsp qpeldsp" vc1dsp_select="h264chroma qpeldsp startcode" rdft_select="fft" @@ -2558,7 +2640,7 @@ als_decoder_select="bswapdsp" amrnb_decoder_select="lsp" amrwb_decoder_select="lsp" amv_decoder_select="sp5x_decoder exif" -amv_encoder_select="aandcttables jpegtables mpegvideoenc" +amv_encoder_select="jpegtables mpegvideoenc" ape_decoder_select="bswapdsp llauddsp" apng_decoder_deps="zlib" apng_encoder_deps="zlib" @@ -2568,12 +2650,13 @@ aptx_encoder_select="audio_frame_queue" aptx_hd_decoder_select="audio_frame_queue" aptx_hd_encoder_select="audio_frame_queue" asv1_decoder_select="blockdsp bswapdsp idctdsp" -asv1_encoder_select="bswapdsp fdctdsp pixblockdsp" +asv1_encoder_select="aandcttables bswapdsp fdctdsp pixblockdsp" asv2_decoder_select="blockdsp bswapdsp idctdsp" -asv2_encoder_select="bswapdsp fdctdsp pixblockdsp" +asv2_encoder_select="aandcttables bswapdsp fdctdsp pixblockdsp" atrac1_decoder_select="mdct sinewin" atrac3_decoder_select="mdct" atrac3p_decoder_select="mdct sinewin" +atrac9_decoder_select="mdct" avrn_decoder_select="exif jpegtables" bink_decoder_select="blockdsp hpeldsp" binkaudio_dct_decoder_select="mdct rdft dct sinewin wma_freqs" @@ -2589,7 +2672,7 @@ dca_decoder_select="mdct" dds_decoder_select="texturedsp" dirac_decoder_select="dirac_parse dwt golomb videodsp mpegvideoenc" dnxhd_decoder_select="blockdsp idctdsp" -dnxhd_encoder_select="aandcttables blockdsp fdctdsp idctdsp mpegvideoenc pixblockdsp" +dnxhd_encoder_select="blockdsp fdctdsp idctdsp mpegvideoenc pixblockdsp" dolby_e_decoder_select="mdct" dvvideo_decoder_select="dvprofile idctdsp" dvvideo_encoder_select="dvprofile fdctdsp me_cmp pixblockdsp" @@ -2620,9 +2703,9 @@ g2m_decoder_deps="zlib" g2m_decoder_select="blockdsp idctdsp jpegtables" g729_decoder_select="audiodsp" h261_decoder_select="mpegvideo" -h261_encoder_select="aandcttables mpegvideoenc" +h261_encoder_select="mpegvideoenc" h263_decoder_select="h263_parser h263dsp mpegvideo qpeldsp" -h263_encoder_select="aandcttables h263dsp mpegvideoenc" +h263_encoder_select="h263dsp mpegvideoenc" h263i_decoder_select="h263_decoder" h263p_decoder_select="h263_decoder" h263p_encoder_select="h263_encoder" @@ -2634,6 +2717,7 @@ hap_encoder_select="texturedspenc" hevc_decoder_select="bswapdsp cabac golomb hevcparse videodsp" huffyuv_decoder_select="bswapdsp huffyuvdsp llviddsp" huffyuv_encoder_select="bswapdsp huffman huffyuvencdsp llvidencdsp" +hymt_decoder_select="huffyuv_decoder" iac_decoder_select="imc_decoder" imc_decoder_select="bswapdsp fft mdct sinewin" indeo3_decoder_select="hpeldsp" @@ -2643,17 +2727,18 @@ interplay_video_decoder_select="hpeldsp" jpegls_decoder_select="mjpeg_decoder" jv_decoder_select="blockdsp" lagarith_decoder_select="llviddsp" -ljpeg_encoder_select="aandcttables idctdsp jpegtables mpegvideoenc" +ljpeg_encoder_select="idctdsp jpegtables mpegvideoenc" +lscr_decoder_deps="zlib" magicyuv_decoder_select="llviddsp" magicyuv_encoder_select="llvidencdsp" mdec_decoder_select="blockdsp idctdsp mpegvideo" metasound_decoder_select="lsp mdct sinewin" mimic_decoder_select="blockdsp bswapdsp hpeldsp idctdsp" mjpeg_decoder_select="blockdsp hpeldsp exif idctdsp jpegtables" -mjpeg_encoder_select="aandcttables jpegtables mpegvideoenc" +mjpeg_encoder_select="jpegtables mpegvideoenc" mjpegb_decoder_select="mjpeg_decoder" mlp_decoder_select="mlp_parser" -mlp_encoder_select="lpc" +mlp_encoder_select="lpc audio_frame_queue" motionpixels_decoder_select="bswapdsp" mp1_decoder_select="mpegaudio" mp1float_decoder_select="mpegaudio" @@ -2669,9 +2754,9 @@ mpc7_decoder_select="bswapdsp mpegaudiodsp" mpc8_decoder_select="mpegaudiodsp" mpegvideo_decoder_select="mpegvideo" mpeg1video_decoder_select="mpegvideo" -mpeg1video_encoder_select="aandcttables mpegvideoenc h263dsp" +mpeg1video_encoder_select="mpegvideoenc h263dsp" mpeg2video_decoder_select="mpegvideo" -mpeg2video_encoder_select="aandcttables mpegvideoenc h263dsp" +mpeg2video_encoder_select="mpegvideoenc h263dsp" mpeg4_decoder_select="h263_decoder mpeg4video_parser" mpeg4_encoder_select="h263_encoder" msa1_decoder_select="mss34dsp" @@ -2683,6 +2768,7 @@ msmpeg4v3_decoder_select="h263_decoder" msmpeg4v3_encoder_select="h263_encoder" mss2_decoder_select="mpegvideo qpeldsp vc1_decoder" mts2_decoder_select="mss34dsp" +mwsc_decoder_deps="zlib" mxpeg_decoder_select="mjpeg_decoder" nellymoser_decoder_select="mdct sinewin" nellymoser_encoder_select="audio_frame_queue mdct sinewin" @@ -2701,6 +2787,7 @@ qdm2_decoder_select="mdct rdft mpegaudiodsp" ra_144_decoder_select="audiodsp" ra_144_encoder_select="audio_frame_queue lpc audiodsp" ralf_decoder_select="golomb" +rasc_decoder_deps="zlib" rawvideo_decoder_select="bswapdsp" rscc_decoder_deps="zlib" rtjpeg_decoder_select="me_cmp" @@ -2714,14 +2801,15 @@ screenpresso_decoder_deps="zlib" shorten_decoder_select="bswapdsp" sipr_decoder_select="lsp" snow_decoder_select="dwt h264qpel hpeldsp me_cmp rangecoder videodsp" -snow_encoder_select="aandcttables dwt h264qpel hpeldsp me_cmp mpegvideoenc rangecoder" +snow_encoder_select="dwt h264qpel hpeldsp me_cmp mpegvideoenc rangecoder" sonic_decoder_select="golomb rangecoder" sonic_encoder_select="golomb rangecoder" sonic_ls_encoder_select="golomb rangecoder" sp5x_decoder_select="mjpeg_decoder" +speedhq_decoder_select="mpegvideo" srgc_decoder_deps="zlib" svq1_decoder_select="hpeldsp" -svq1_encoder_select="aandcttables hpeldsp me_cmp mpegvideoenc" +svq1_encoder_select="hpeldsp me_cmp mpegvideoenc" svq3_decoder_select="golomb h264dsp h264parse h264pred hpeldsp tpeldsp videodsp" svq3_decoder_suggest="zlib" tak_decoder_select="audiodsp" @@ -2732,7 +2820,7 @@ thp_decoder_select="mjpeg_decoder" tiff_decoder_suggest="zlib lzma" tiff_encoder_suggest="zlib" truehd_decoder_select="mlp_parser" -truehd_encoder_select="lpc" +truehd_encoder_select="lpc audio_frame_queue" truemotion2_decoder_select="bswapdsp" truespeech_decoder_select="bswapdsp" tscc_decoder_deps="zlib" @@ -2746,6 +2834,7 @@ vc1image_decoder_select="vc1_decoder" vorbis_decoder_select="mdct" vorbis_encoder_select="audio_frame_queue mdct" vp3_decoder_select="hpeldsp vp3dsp videodsp" +vp4_decoder_select="vp3_decoder" vp5_decoder_select="h264chroma hpeldsp videodsp vp3dsp vp56dsp" vp6_decoder_select="h264chroma hpeldsp huffman videodsp vp3dsp vp56dsp" vp6a_decoder_select="vp6_decoder" @@ -2753,6 +2842,7 @@ vp6f_decoder_select="vp6_decoder" vp7_decoder_select="h264pred videodsp vp8dsp" vp8_decoder_select="h264pred videodsp vp8dsp" vp9_decoder_select="videodsp vp9_parser vp9_superframe_split_bsf" +wcmv_decoder_deps="zlib" webp_decoder_select="vp8_decoder exif" wmalossless_decoder_select="llauddsp" wmapro_decoder_select="mdct sinewin wma_freqs" @@ -2783,6 +2873,7 @@ d3d11va_deps="dxva_h ID3D11VideoDecoder ID3D11VideoContext" dxva2_deps="dxva2api_h DXVA2_ConfigPictureDecode ole32 user32" ffnvcodec_deps_any="libdl LoadLibrary" nvdec_deps="ffnvcodec" +vaapi_x11_deps="xlib" videotoolbox_hwaccel_deps="videotoolbox pthreads" videotoolbox_hwaccel_extralibs="-framework QuartzCore" xvmc_deps="X11_extensions_XvMClib_h" @@ -2871,7 +2962,7 @@ vc1_vdpau_hwaccel_deps="vdpau" vc1_vdpau_hwaccel_select="vc1_decoder" vp8_nvdec_hwaccel_deps="nvdec" vp8_nvdec_hwaccel_select="vp8_decoder" -vp8_vaapi_hwaccel_deps="vaapi VAPictureParameterBufferVP8" +vp8_vaapi_hwaccel_deps="vaapi" vp8_vaapi_hwaccel_select="vp8_decoder" vp9_d3d11va_hwaccel_deps="d3d11va DXVA_PicParams_VP9" vp9_d3d11va_hwaccel_select="vp9_decoder" @@ -2898,12 +2989,15 @@ qsvdec_select="qsv" qsvenc_select="qsv" qsvvpp_select="qsv" vaapi_encode_deps="vaapi" -v4l2_m2m_deps_any="linux_videodev2_h" +v4l2_m2m_deps="linux_videodev2_h sem_timedwait" hwupload_cuda_filter_deps="ffnvcodec" scale_npp_filter_deps="ffnvcodec libnpp" -scale_cuda_filter_deps="cuda_sdk" -thumbnail_cuda_filter_deps="cuda_sdk" +scale_cuda_filter_deps="ffnvcodec" +scale_cuda_filter_deps_any="cuda_nvcc cuda_llvm" +thumbnail_cuda_filter_deps="ffnvcodec" +thumbnail_cuda_filter_deps_any="cuda_nvcc cuda_llvm" +transpose_npp_filter_deps="ffnvcodec libnpp" amf_deps_any="libdl LoadLibrary" nvenc_deps="ffnvcodec" @@ -2925,9 +3019,9 @@ h264_qsv_decoder_select="h264_mp4toannexb_bsf h264_parser qsvdec" h264_qsv_encoder_select="qsvenc" h264_rkmpp_decoder_deps="rkmpp" h264_rkmpp_decoder_select="h264_mp4toannexb_bsf" -h264_vaapi_encoder_deps="VAEncPictureParameterBufferH264" h264_vaapi_encoder_select="cbs_h264 vaapi_encode" h264_v4l2m2m_decoder_deps="v4l2_m2m h264_v4l2_m2m" +h264_v4l2m2m_decoder_select="h264_mp4toannexb_bsf" h264_v4l2m2m_encoder_deps="v4l2_m2m h264_v4l2_m2m" hevc_amf_encoder_deps="amf" hevc_cuvid_decoder_deps="cuvid" @@ -2942,12 +3036,13 @@ hevc_rkmpp_decoder_select="hevc_mp4toannexb_bsf" hevc_vaapi_encoder_deps="VAEncPictureParameterBufferHEVC" hevc_vaapi_encoder_select="cbs_h265 vaapi_encode" hevc_v4l2m2m_decoder_deps="v4l2_m2m hevc_v4l2_m2m" +hevc_v4l2m2m_decoder_select="hevc_mp4toannexb_bsf" hevc_v4l2m2m_encoder_deps="v4l2_m2m hevc_v4l2_m2m" mjpeg_cuvid_decoder_deps="cuvid" mjpeg_qsv_encoder_deps="libmfx" mjpeg_qsv_encoder_select="qsvenc" mjpeg_vaapi_encoder_deps="VAEncPictureParameterBufferJPEG" -mjpeg_vaapi_encoder_select="vaapi_encode jpegtables" +mjpeg_vaapi_encoder_select="cbs_jpeg jpegtables vaapi_encode" mpeg1_cuvid_decoder_deps="cuvid" mpeg1_v4l2m2m_decoder_deps="v4l2_m2m mpeg1_v4l2_m2m" mpeg2_crystalhd_decoder_select="crystalhd" @@ -2956,7 +3051,6 @@ mpeg2_mmal_decoder_deps="mmal" mpeg2_mediacodec_decoder_deps="mediacodec" mpeg2_qsv_decoder_select="qsvdec mpegvideo_parser" mpeg2_qsv_encoder_select="qsvenc" -mpeg2_vaapi_encoder_deps="VAEncPictureParameterBufferMPEG2" mpeg2_vaapi_encoder_select="cbs_mpeg2 vaapi_encode" mpeg2_v4l2m2m_decoder_deps="v4l2_m2m mpeg2_v4l2_m2m" mpeg4_crystalhd_decoder_select="crystalhd" @@ -2992,6 +3086,7 @@ wmv3_crystalhd_decoder_select="crystalhd" # parsers aac_parser_select="adts_header" +av1_parser_select="cbs_av1" h264_parser_select="golomb h264dsp h264parse" hevc_parser_select="hevcparse" mpegaudio_parser_select="mpegaudioheader" @@ -3001,6 +3096,8 @@ vc1_parser_select="vc1dsp" # bitstream_filters aac_adtstoasc_bsf_select="adts_header" +av1_frame_split_bsf_select="cbs_av1" +av1_metadata_bsf_select="cbs_av1" eac3_core_bsf_select="ac3_parser" filter_units_bsf_select="cbs" h264_metadata_bsf_deps="const_nan" @@ -3010,6 +3107,7 @@ hevc_metadata_bsf_select="cbs_h265" mjpeg2jpeg_bsf_select="jpegtables" mpeg2_metadata_bsf_select="cbs_mpeg2" trace_headers_bsf_select="cbs" +vp9_metadata_bsf_select="cbs_vp9" # external libraries aac_at_decoder_deps="audiotoolbox" @@ -3053,9 +3151,13 @@ hevc_videotoolbox_encoder_deps="pthreads" hevc_videotoolbox_encoder_select="videotoolbox_encoder" libaom_av1_decoder_deps="libaom" libaom_av1_encoder_deps="libaom" +libaom_av1_encoder_select="extract_extradata_bsf" +libaribb24_decoder_deps="libaribb24" libcelt_decoder_deps="libcelt" libcodec2_decoder_deps="libcodec2" libcodec2_encoder_deps="libcodec2" +libdav1d_decoder_deps="libdav1d" +libdavs2_decoder_deps="libdavs2" libfdk_aac_decoder_deps="libfdk_aac" libfdk_aac_encoder_deps="libfdk_aac" libfdk_aac_encoder_select="audio_frame_queue" @@ -3109,8 +3211,10 @@ libx264rgb_encoder_deps="libx264 x264_csp_bgr" libx264rgb_encoder_select="libx264_encoder" libx265_encoder_deps="libx265" libxavs_encoder_deps="libxavs" +libxavs2_encoder_deps="libxavs2" libxvid_encoder_deps="libxvid" libzvbi_teletext_decoder_deps="libzvbi" +vapoursynth_demuxer_deps="vapoursynth" videotoolbox_suggest="coreservices" videotoolbox_deps="corefoundation coremedia corevideo" videotoolbox_encoder_deps="videotoolbox VTCompressionSessionPrepareToEncodeFrames" @@ -3145,6 +3249,7 @@ image2_alias_pix_demuxer_select="image2_demuxer" image2_brender_pix_demuxer_select="image2_demuxer" ipod_muxer_select="mov_muxer" ismv_muxer_select="mov_muxer" +ivf_muxer_select="av1_metadata_bsf vp9_superframe_bsf" matroska_audio_muxer_select="matroska_muxer" matroska_demuxer_select="iso_media riffdec" matroska_demuxer_suggest="bzlib lzo zlib" @@ -3210,11 +3315,8 @@ decklink_deps_any="libdl LoadLibrary" decklink_indev_deps="decklink threads" decklink_indev_extralibs="-lstdc++" decklink_outdev_deps="decklink threads" +decklink_outdev_suggest="libklvanc" decklink_outdev_extralibs="-lstdc++" -libndi_newtek_indev_deps="libndi_newtek" -libndi_newtek_indev_extralibs="-lndi" -libndi_newtek_outdev_deps="libndi_newtek" -libndi_newtek_outdev_extralibs="-lndi" dshow_indev_deps="IBaseFilter" dshow_indev_extralibs="-lpsapi -lole32 -lstrmiids -luuid -loleaut32 -lshlwapi" fbdev_indev_deps="linux_fb_h" @@ -3231,6 +3333,7 @@ libcdio_indev_deps="libcdio" libdc1394_indev_deps="libdc1394" openal_indev_deps="openal" opengl_outdev_deps="opengl" +opengl_outdev_suggest="sdl2" oss_indev_deps_any="sys_soundcard_h" oss_outdev_deps_any="sys_soundcard_h" pulse_indev_deps="libpulse" @@ -3245,14 +3348,13 @@ v4l2_outdev_suggest="libv4l2" vfwcap_indev_deps="vfw32 vfwcap_defines" xcbgrab_indev_deps="libxcb" xcbgrab_indev_suggest="libxcb_shm libxcb_shape libxcb_xfixes" -xv_outdev_deps="X11_extensions_Xvlib_h XvGetPortAttribute" -xv_outdev_extralibs="-lXv -lX11 -lXext" +xv_outdev_deps="xlib" # protocols async_protocol_deps="threads" bluray_protocol_deps="libbluray" ffrtmpcrypt_protocol_conflict="librtmp_protocol" -ffrtmpcrypt_protocol_deps_any="gcrypt gmp openssl" +ffrtmpcrypt_protocol_deps_any="gcrypt gmp openssl mbedtls" ffrtmpcrypt_protocol_select="tcp_protocol" ffrtmphttp_protocol_conflict="librtmp_protocol" ffrtmphttp_protocol_select="http_protocol" @@ -3265,18 +3367,8 @@ httpproxy_protocol_suggest="zlib" https_protocol_select="tls_protocol" https_protocol_suggest="zlib" icecast_protocol_select="http_protocol" -librtmp_protocol_deps="librtmp" -librtmpe_protocol_deps="librtmp" -librtmps_protocol_deps="librtmp" -librtmpt_protocol_deps="librtmp" -librtmpte_protocol_deps="librtmp" -libsmbclient_protocol_deps="libsmbclient gplv3" -libssh_protocol_deps="libssh" -libtls_conflict="openssl gnutls" mmsh_protocol_select="http_protocol" mmst_protocol_select="network" -libsrt_protocol_deps="libsrt" -libsrt_protocol_select="network" rtmp_protocol_conflict="librtmp_protocol" rtmp_protocol_select="tcp_protocol" rtmp_protocol_suggest="zlib" @@ -3292,34 +3384,53 @@ rtmpte_protocol_suggest="zlib" rtmpts_protocol_select="ffrtmphttp_protocol https_protocol" rtmpts_protocol_suggest="zlib" rtp_protocol_select="udp_protocol" -schannel_conflict="openssl gnutls libtls" +schannel_conflict="openssl gnutls libtls mbedtls" sctp_protocol_deps="struct_sctp_event_subscribe struct_msghdr_msg_flags" sctp_protocol_select="network" -securetransport_conflict="openssl gnutls libtls" +securetransport_conflict="openssl gnutls libtls mbedtls" srtp_protocol_select="rtp_protocol srtp" tcp_protocol_select="network" -tls_protocol_deps_any="gnutls openssl schannel securetransport libtls" +tls_protocol_deps_any="gnutls openssl schannel securetransport libtls mbedtls" tls_protocol_select="tcp_protocol" udp_protocol_select="network" udplite_protocol_select="network" unix_protocol_deps="sys_un_h" unix_protocol_select="network" +# external library protocols +librtmp_protocol_deps="librtmp" +librtmpe_protocol_deps="librtmp" +librtmps_protocol_deps="librtmp" +librtmpt_protocol_deps="librtmp" +librtmpte_protocol_deps="librtmp" +libsmbclient_protocol_deps="libsmbclient gplv3" +libsrt_protocol_deps="libsrt" +libsrt_protocol_select="network" +libssh_protocol_deps="libssh" +libtls_conflict="openssl gnutls mbedtls" + # filters +afftdn_filter_deps="avcodec" +afftdn_filter_select="fft" afftfilt_filter_deps="avcodec" afftfilt_filter_select="fft" afir_filter_deps="avcodec" afir_filter_select="fft" amovie_filter_deps="avcodec avformat" aresample_filter_deps="swresample" +asr_filter_deps="pocketsphinx" ass_filter_deps="libass" atempo_filter_deps="avcodec" atempo_filter_select="rdft" avgblur_opencl_filter_deps="opencl" azmq_filter_deps="libzmq" blackframe_filter_deps="gpl" +bm3d_filter_deps="avcodec" +bm3d_filter_select="dct" boxblur_filter_deps="gpl" +boxblur_opencl_filter_deps="opencl gpl" bs2b_filter_deps="libbs2b" +colorkey_opencl_filter_deps="opencl" colormatrix_filter_deps="gpl" convolution_opencl_filter_deps="opencl" convolve_filter_deps="avcodec" @@ -3335,19 +3446,25 @@ deconvolve_filter_select="fft" deinterlace_qsv_filter_deps="libmfx" deinterlace_vaapi_filter_deps="vaapi" delogo_filter_deps="gpl" -denoise_vaapi_filter_deps="vaapi VAProcPipelineParameterBuffer" +denoise_vaapi_filter_deps="vaapi" +derain_filter_select="dnn" deshake_filter_select="pixelutils" +dilation_opencl_filter_deps="opencl" drawtext_filter_deps="libfreetype" drawtext_filter_suggest="libfontconfig libfribidi" elbg_filter_deps="avcodec" eq_filter_deps="gpl" +erosion_opencl_filter_deps="opencl" fftfilt_filter_deps="avcodec" fftfilt_filter_select="rdft" +fftdnoiz_filter_deps="avcodec" +fftdnoiz_filter_select="fft" find_rect_filter_deps="avcodec avformat gpl" firequalizer_filter_deps="avcodec" firequalizer_filter_select="rdft" flite_filter_deps="libflite" -framerate_filter_select="pixelutils" +framerate_filter_select="scene_sad" +freezedetect_filter_select="scene_sad" frei0r_filter_deps="frei0r libdl" frei0r_src_filter_deps="frei0r libdl" fspp_filter_deps="gpl" @@ -3357,13 +3474,16 @@ hqdn3d_filter_deps="gpl" interlace_filter_deps="gpl" kerndeint_filter_deps="gpl" ladspa_filter_deps="ladspa libdl" +lensfun_filter_deps="liblensfun version3" lv2_filter_deps="lv2" mcdeint_filter_deps="avcodec gpl" movie_filter_deps="avcodec avformat" mpdecimate_filter_deps="gpl" mpdecimate_filter_select="pixelutils" +minterpolate_filter_select="scene_sad" mptestsrc_filter_deps="gpl" negate_filter_deps="lut_filter" +nlmeans_opencl_filter_deps="opencl" nnedi_filter_deps="gpl" ocr_filter_deps="libtesseract" ocv_filter_deps="libopencv" @@ -3377,19 +3497,21 @@ perspective_filter_deps="gpl" phase_filter_deps="gpl" pp7_filter_deps="gpl" pp_filter_deps="gpl postproc" -procamp_vaapi_filter_deps="vaapi VAProcPipelineParameterBuffer" +prewitt_opencl_filter_deps="opencl" +procamp_vaapi_filter_deps="vaapi" program_opencl_filter_deps="opencl" pullup_filter_deps="gpl" removelogo_filter_deps="avcodec avformat swscale" repeatfields_filter_deps="gpl" resample_filter_deps="avresample" +roberts_opencl_filter_deps="opencl" rubberband_filter_deps="librubberband" sab_filter_deps="gpl swscale" scale2ref_filter_deps="swscale" scale_filter_deps="swscale" scale_qsv_filter_deps="libmfx" -select_filter_select="pixelutils" -sharpness_vaapi_filter_deps="vaapi VAProcPipelineParameterBuffer" +select_filter_select="scene_sad" +sharpness_vaapi_filter_deps="vaapi" showcqt_filter_deps="avcodec avformat swscale" showcqt_filter_suggest="libfontconfig libfreetype" showcqt_filter_select="fft" @@ -3401,12 +3523,15 @@ showspectrumpic_filter_deps="avcodec" showspectrumpic_filter_select="fft" signature_filter_deps="gpl avcodec avformat" smartblur_filter_deps="gpl swscale" +sobel_opencl_filter_deps="opencl" sofalizer_filter_deps="libmysofa avcodec" sofalizer_filter_select="fft" spectrumsynth_filter_deps="avcodec" spectrumsynth_filter_select="fft" spp_filter_deps="gpl avcodec" spp_filter_select="fft idctdsp fdctdsp me_cmp pixblockdsp" +sr_filter_deps="avformat swscale" +sr_filter_select="dnn" stereo3d_filter_deps="gpl" subtitles_filter_deps="avformat avcodec libass" super2xsai_filter_deps="gpl" @@ -3415,6 +3540,9 @@ tinterlace_filter_deps="gpl" tinterlace_merge_test_deps="tinterlace_filter" tinterlace_pad_test_deps="tinterlace_filter" tonemap_filter_deps="const_nan" +tonemap_opencl_filter_deps="opencl const_nan" +transpose_opencl_filter_deps="opencl" +transpose_vaapi_filter_deps="vaapi VAProcPipelineCaps_rotation_flags" unsharp_opencl_filter_deps="opencl" uspp_filter_deps="gpl avcodec" vaguedenoiser_filter_deps="gpl" @@ -3424,9 +3552,11 @@ libvmaf_filter_deps="libvmaf pthreads" zmq_filter_deps="libzmq" zoompan_filter_deps="swscale" zscale_filter_deps="libzimg const_nan" -scale_vaapi_filter_deps="vaapi VAProcPipelineParameterBuffer" +scale_vaapi_filter_deps="vaapi" vpp_qsv_filter_deps="libmfx" vpp_qsv_filter_select="qsvvpp" +yadif_cuda_filter_deps="ffnvcodec" +yadif_cuda_filter_deps_any="cuda_nvcc cuda_llvm" # examples avio_dir_cmd_deps="avformat avutil" @@ -3477,15 +3607,15 @@ swresample_suggest="libm libsoxr" swscale_deps="avutil" swscale_suggest="libm" -avcodec_extralibs="pthreads_extralibs iconv_extralibs" +avcodec_extralibs="pthreads_extralibs iconv_extralibs dxva2_extralibs" avfilter_extralibs="pthreads_extralibs" avutil_extralibs="d3d11va_extralibs nanosleep_extralibs pthreads_extralibs vaapi_drm_extralibs vaapi_x11_extralibs vdpau_x11_extralibs" # programs -ffmpeg_deps="avcodec avfilter avformat swresample" +ffmpeg_deps="avcodec avfilter avformat" ffmpeg_select="aformat_filter anull_filter atrim_filter format_filter - null_filter - trim_filter" + hflip_filter null_filter + transpose_filter trim_filter vflip_filter" ffmpeg_suggest="ole32 psapi shell32" ffplay_deps="avcodec avformat swscale swresample sdl2" ffplay_select="rdft crop_filter transpose_filter hflip_filter vflip_filter rotate_filter" @@ -3530,8 +3660,6 @@ version_script='--version-script' objformat="elf32" x86asmexe_default="nasm" windres_default="windres" -nvcc_default="nvcc" -nvccflags_default="-gencode arch=compute_30,code=sm_30 -O2" striptype="direct" # OS @@ -3542,6 +3670,7 @@ host_os=$target_os_default if test "$target_os_default" = aix; then arch_default=$(uname -p) strip_default="strip -X32_64" + nm_default="nm -g -X32_64" else arch_default=$(uname -m) fi @@ -3632,6 +3761,8 @@ mkdir -p ffbuild # find source path if test -f configure; then source_path=. +elif test -f src/configure; then + source_path=src else source_path=$(cd $(dirname "$0"); pwd) case "$source_path" in @@ -3658,8 +3789,7 @@ find_things_extern(){ find_filters_extern(){ file=$source_path/$1 - #sed -n "s/^extern AVFilter ff_\([avfsinkrc]\{2,5\}\)_\(\w\+\);/\2_filter/p" $file - sed -E -n "s/^extern AVFilter ff_([avfsinkrc]{2,5})_([a-zA-Z0-9_]+);/\2_filter/p" $file + sed -n 's/^extern AVFilter ff_[avfsinkrc]\{2,5\}_\([[:alnum:]_]\{1,\}\);/\1_filter/p' $file } FILTER_LIST=$(find_filters_extern libavfilter/allfilters.c) @@ -3673,7 +3803,7 @@ CODEC_LIST=" $ENCODER_LIST $DECODER_LIST " -PARSER_LIST=$(find_things_extern parser AVCodecParser libavcodec/parser.c) +PARSER_LIST=$(find_things_extern parser AVCodecParser libavcodec/parsers.c) BSF_LIST=$(find_things_extern bsf AVBitStreamFilter libavcodec/bitstream_filters.c) HWACCEL_LIST=$(find_things_extern hwaccel AVHWAccel libavcodec/hwaccels.h) PROTOCOL_LIST=$(find_things_extern protocol URLProtocol libavformat/protocols.c) @@ -3723,8 +3853,22 @@ die_unknown(){ } print_in_columns() { - cols=$(expr $ncols / 24) - cat | tr ' ' '\n' | sort | pr -r "-$cols" -w $ncols -t + tr ' ' '\n' | sort | tr '\r\n' ' ' | awk -v col_width=24 -v width="$ncols" ' + { + num_cols = width > col_width ? int(width / col_width) : 1; + num_rows = int((NF + num_cols-1) / num_cols); + y = x = 1; + for (y = 1; y <= num_rows; y++) { + i = y; + for (x = 1; x <= num_cols; x++) { + if (i <= NF) { + line = sprintf("%s%-" col_width "s", line, $i); + } + i = i + num_rows; + } + print line; line = ""; + } + }' | sed 's/ *$//' } show_list() { @@ -3810,6 +3954,7 @@ for opt do name=$(echo "${optval}" | sed "s/,/_${thing}|/g")_${thing} list=$(filter "$name" $list) [ "$list" = "" ] && warn "Option $opt did not match anything" + test $action = enable && warn_if_gets_disabled $list $action $list ;; --enable-yasm|--disable-yasm) @@ -3930,6 +4075,12 @@ fi enabled_all gnutls openssl && die "GnuTLS and OpenSSL must not be enabled at the same time." +enabled_all gnutls mbedtls && + die "GnuTLS and mbedTLS must not be enabled at the same time." + +enabled_all openssl mbedtls && + die "OpenSSL and mbedTLS must not be enabled at the same time." + # Disable all the library-specific components if the library itself # is disabled, see AVCODEC_LIST and following _LIST variables. @@ -3947,7 +4098,7 @@ set >> $logfile test -n "$valgrind" && toolchain="valgrind-memcheck" -enabled ossfuzz && { +enabled ossfuzz && ! echo $CFLAGS | grep -q -- "-fsanitize=" && ! echo $CFLAGS | grep -q -- "-fcoverage-mapping" &&{ add_cflags -fsanitize=address,undefined -fsanitize-coverage=trace-pc-guard,trace-cmp -fno-omit-frame-pointer add_ldflags -fsanitize=address,undefined -fsanitize-coverage=trace-pc-guard,trace-cmp } @@ -3965,8 +4116,8 @@ case "$toolchain" in ;; *-tsan) cc_default="${toolchain%-tsan}" - add_cflags -fsanitize=thread -fPIE - add_ldflags -fsanitize=thread -pie + add_cflags -fsanitize=thread + add_ldflags -fsanitize=thread case "$toolchain" in gcc-tsan) add_cflags -fPIC @@ -3997,23 +4148,22 @@ case "$toolchain" in # behaviour if the regexp was unable to match anything, since this # successfully parses the version number of existing supported # versions that require the converter (MSVC 2010 and 2012). - cl_major_ver=$(cl 2>&1 | sed -n 's/.*Version \([[:digit:]]\{1,\}\)\..*/\1/p') + cl_major_ver=$(cl.exe 2>&1 | sed -n 's/.*Version \([[:digit:]]\{1,\}\)\..*/\1/p') if [ -z "$cl_major_ver" ] || [ $cl_major_ver -ge 18 ]; then - cc_default="cl" - cxx_default="cl" + cc_default="cl.exe" + cxx_default="cl.exe" else - cc_default="c99wrap cl" - cxx_default="c99wrap cl" + die "Unsupported MSVC version (2013 or newer required)" fi ld_default="$source_path/compat/windows/mslink" - nm_default="dumpbin -symbols" - ar_default="lib" + nm_default="dumpbin.exe -symbols" + ar_default="lib.exe" case "$arch" in aarch64|arm64) - as_default="armasm64" + as_default="armasm64.exe" ;; arm*) - as_default="armasm" + as_default="armasm.exe" ;; esac target_os_default="win32" @@ -4057,6 +4207,11 @@ if test -n "$cross_prefix"; then enable cross_compile fi +set_default target_os +if test "$target_os" = android; then + cc_default="clang" +fi + ar_default="${cross_prefix}${ar_default}" cc_default="${cross_prefix}${cc_default}" cxx_default="${cross_prefix}${cxx_default}" @@ -4072,8 +4227,22 @@ windres_default="${cross_prefix}${windres_default}" sysinclude_default="${sysroot}/usr/include" +if enabled cuda_sdk; then + warn "Option --enable-cuda-sdk is deprecated. Use --enable-cuda-nvcc instead." + enable cuda_nvcc +fi + +if enabled cuda_nvcc; then + nvcc_default="nvcc" + nvccflags_default="-gencode arch=compute_30,code=sm_30 -O2" +else + nvcc_default="clang" + nvccflags_default="--cuda-gpu-arch=sm_30 -O2" + NVCC_C="" +fi + set_default arch cc cxx doxygen pkg_config ranlib strip sysinclude \ - target_exec target_os x86asmexe nvcc + target_exec x86asmexe nvcc enabled cross_compile || host_cc_default=$cc set_default host_cc @@ -4140,6 +4309,7 @@ tmpfile TMPCPP .cpp tmpfile TMPE $EXESUF tmpfile TMPH .h tmpfile TMPM .m +tmpfile TMPCU .cu tmpfile TMPO .o tmpfile TMPS .S tmpfile TMPSH .sh @@ -4777,18 +4947,26 @@ elif enabled mips; then enable fast_cmov enable fast_unaligned disable aligned_stack - disable mipsfpu disable mipsdsp disable mipsdspr2 + # When gcc version less than 5.3.0, add -fno-expensive-optimizations flag. + if [ $cc == gcc ]; then + gcc_version=$(gcc -dumpversion) + if [ "$(echo "$gcc_version 5.3.0" | tr " " "\n" | sort -rV | head -n 1)" == "$gcc_version" ]; then + expensive_optimization_flag="" + else + expensive_optimization_flag="-fno-expensive-optimizations" + fi + fi case $cpu in loongson3*) - cpuflags="-march=loongson3a -mhard-float -fno-expensive-optimizations" + cpuflags="-march=loongson3a -mhard-float $expensive_optimization_flag" ;; loongson2e) - cpuflags="-march=loongson2e -mhard-float -fno-expensive-optimizations" + cpuflags="-march=loongson2e -mhard-float $expensive_optimization_flag" ;; loongson2f) - cpuflags="-march=loongson2f -mhard-float -fno-expensive-optimizations" + cpuflags="-march=loongson2f -mhard-float $expensive_optimization_flag" ;; esac ;; @@ -5038,6 +5216,8 @@ case $target_os in android) disable symver enable section_data_rel_ro + add_cflags -fPIE + add_ldexeflags -fPIE -pie SLIB_INSTALL_NAME='$(SLIBNAME)' SLIB_INSTALL_LINKS= SHFLAGS='-shared -Wl,-soname,$(SLIBNAME)' @@ -5061,6 +5241,7 @@ case $target_os in echo "hwcap_1 = OVERRIDE;" > mapfile && add_ldflags -Wl,-M,mapfile nm_default='nm -P -g' + striptype="" version_script='-M' VERSION_SCRIPT_POSTPROCESS_CMD='perl $(SRC_PATH)/compat/solaris/make_sunver.pl - $(OBJS)' ;; @@ -5102,7 +5283,7 @@ case $target_os in enabled x86_64 && objformat="macho64" || objformat="macho32" enabled_any pic shared x86_64 || { check_cflags -mdynamic-no-pic && add_asflags -mdynamic-no-pic; } - check_header dispatch/dispatch.h && + check_headers dispatch/dispatch.h && add_cppflags '-I\$(SRC_PATH)/compat/dispatch_semaphore' if test -n "$sysroot"; then is_in -isysroot $cc $CPPFLAGS $CFLAGS || check_cppflags -isysroot $sysroot @@ -5214,7 +5395,6 @@ case $target_os in network_extralibs="-lsocket" objformat="coff" enable dos_paths - add_cppflags -U__STRICT_ANSI__ ;; linux) enable section_data_rel_ro @@ -5285,7 +5465,7 @@ link_name=$(mktemp -u $TMPDIR/name_XXXXXXXX) mkdir "$link_dest" $ln_s "$link_dest" "$link_name" touch "$link_dest/test_file" -if [ "$source_path" != "." ] && ([ ! -d src ] || [ -L src ]) && [ -e "$link_name/test_file" ]; then +if [ "$source_path" != "." ] && [ "$source_path" != "src" ] && ([ ! -d src ] || [ -L src ]) && [ -e "$link_name/test_file" ]; then # create link to source path [ -e src ] && rm src $ln_s "$source_path" src @@ -5327,6 +5507,7 @@ probe_libc(){ add_${pfx}cppflags -D__printf__=__gnu_printf__ test_${pfx}cpp_condition windows.h "!defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0600" && add_${pfx}cppflags -D_WIN32_WINNT=0x0600 + add_${pfx}cppflags -D_POSIX_C_SOURCE=200112 -D_XOPEN_SOURCE=600 elif test_${pfx}cpp_condition _mingw.h "defined __MINGW_VERSION" || test_${pfx}cpp_condition _mingw.h "defined __MINGW32_VERSION"; then eval ${pfx}libc_type=mingw32 @@ -5340,6 +5521,7 @@ probe_libc(){ add_${pfx}cppflags -D_WIN32_WINNT=0x0600 eval test \$${pfx_no_}cc_type = "gcc" && add_${pfx}cppflags -D__printf__=__gnu_printf__ + add_${pfx}cppflags -D_POSIX_C_SOURCE=200112 -D_XOPEN_SOURCE=600 elif test_${pfx}cpp_condition crtversion.h "defined _VC_CRT_MAJOR_VERSION"; then eval ${pfx}libc_type=msvcrt if test_${pfx}cpp_condition crtversion.h "_VC_CRT_MAJOR_VERSION < 14"; then @@ -5383,6 +5565,11 @@ EOF elif test_${pfx}cpp_condition sys/brand.h "defined LABELED_BRAND_NAME"; then eval ${pfx}libc_type=solaris add_${pfx}cppflags -D__EXTENSIONS__ -D_XOPEN_SOURCE=600 + elif test_${pfx}cpp_condition sys/version.h "defined __DJGPP__"; then + eval ${pfx}libc_type=djgpp + add_cppflags -U__STRICT_ANSI__ + add_cflags "-include $source_path/compat/djgpp/math.h" + add_compat djgpp/math.o fi test_${pfx}cc < @@ -5587,9 +5774,10 @@ elif enabled mips; then enabled mipsfpu && check_inline_asm_flags mipsfpu '"cvt.d.l $f0, $f2"' '-mhard-float' enabled mipsfpu && (enabled mips32r5 || enabled mips32r6 || enabled mips64r6) && check_inline_asm_flags mipsfpu '"cvt.d.l $f0, $f1"' '-mfp64' - enabled mipsfpu && enabled msa && check_inline_asm_flags msa '"addvi.b $w0, $w1, 1"' '-mmsa' && check_header msa.h || disable msa + enabled mipsfpu && enabled msa && check_inline_asm_flags msa '"addvi.b $w0, $w1, 1"' '-mmsa' && check_headers msa.h || disable msa enabled mipsdsp && check_inline_asm_flags mipsdsp '"addu.qb $t0, $t1, $t2"' '-mdsp' enabled mipsdspr2 && check_inline_asm_flags mipsdspr2 '"absq_s.qb $t0, $t1"' '-mdspr2' + enabled msa && enabled msa2 && check_inline_asm_flags msa2 '"nxbits.any.b $w0, $w0"' '-mmsa2' && check_headers msa2.h || disable msa2 if enabled bigendian && enabled msa; then disable msa @@ -5732,9 +5920,9 @@ if ! disabled network; then check_type "sys/types.h sys/socket.h" socklen_t # Prefer arpa/inet.h over winsock2 - if check_header arpa/inet.h ; then + if check_headers arpa/inet.h ; then check_func closesocket - elif check_header winsock2.h ; then + elif check_headers winsock2.h ; then check_func_headers winsock2.h closesocket -lws2 && network_extralibs="-lws2" || { check_func_headers winsock2.h closesocket -lws2_32 && @@ -5820,31 +6008,31 @@ check_func_headers windows.h Sleep check_func_headers windows.h VirtualAlloc check_func_headers glob.h glob enabled xlib && - check_func_headers "X11/Xlib.h X11/extensions/Xvlib.h" XvGetPortAttribute -lXv -lX11 -lXext + check_lib xlib "X11/Xlib.h X11/extensions/Xvlib.h" XvGetPortAttribute -lXv -lX11 -lXext -check_header direct.h -check_header dirent.h -check_header dxgidebug.h -check_header dxva.h -check_header dxva2api.h -D_WIN32_WINNT=0x0600 -check_header io.h -check_header linux/perf_event.h -check_header libcrystalhd/libcrystalhd_if.h -check_header malloc.h -check_header net/udplite.h -check_header poll.h -check_header sys/param.h -check_header sys/resource.h -check_header sys/select.h -check_header sys/time.h -check_header sys/un.h -check_header termios.h -check_header unistd.h -check_header valgrind/valgrind.h +check_headers direct.h +check_headers dirent.h +check_headers dxgidebug.h +check_headers dxva.h +check_headers dxva2api.h -D_WIN32_WINNT=0x0600 +check_headers io.h +check_headers linux/perf_event.h +check_headers libcrystalhd/libcrystalhd_if.h +check_headers malloc.h +check_headers net/udplite.h +check_headers poll.h +check_headers sys/param.h +check_headers sys/resource.h +check_headers sys/select.h +check_headers sys/time.h +check_headers sys/un.h +check_headers termios.h +check_headers unistd.h +check_headers valgrind/valgrind.h check_func_headers VideoToolbox/VTCompressionSession.h VTCompressionSessionPrepareToEncodeFrames -framework VideoToolbox -check_header windows.h -check_header X11/extensions/XvMClib.h -check_header asm/types.h +check_headers windows.h +check_headers X11/extensions/XvMClib.h +check_headers asm/types.h # it seems there are versions of clang in some distros that try to use the # gcc headers, which explodes for stdatomic @@ -5880,6 +6068,7 @@ enabled avfoundation && { enabled videotoolbox && { check_lib coreservices CoreServices/CoreServices.h UTGetOSTypeFromString "-framework CoreServices" check_func_headers CoreMedia/CMFormatDescription.h kCMVideoCodecType_HEVC "-framework CoreMedia" + check_func_headers CoreVideo/CVPixelBuffer.h kCVPixelFormatType_420YpCbCr10BiPlanarVideoRange "-framework CoreVideo" } check_struct "sys/time.h sys/resource.h" "struct rusage" ru_maxrss @@ -5890,22 +6079,31 @@ check_type "windows.h d3d11.h" "ID3D11VideoDecoder" check_type "windows.h d3d11.h" "ID3D11VideoContext" check_type "d3d9.h dxva2api.h" DXVA2_ConfigPictureDecode -D_WIN32_WINNT=0x0602 -check_type "va/va.h va/va_dec_hevc.h" "VAPictureParameterBufferHEVC" -check_type "va/va.h va/va_dec_vp8.h" "VAPictureParameterBufferVP8" -check_struct "va/va.h" "VADecPictureParameterBufferVP9" bit_depth -check_type "va/va.h va/va_vpp.h" "VAProcPipelineParameterBuffer" -check_type "va/va.h va/va_enc_h264.h" "VAEncPictureParameterBufferH264" -check_type "va/va.h va/va_enc_hevc.h" "VAEncPictureParameterBufferHEVC" -check_type "va/va.h va/va_enc_jpeg.h" "VAEncPictureParameterBufferJPEG" -check_type "va/va.h va/va_enc_mpeg2.h" "VAEncPictureParameterBufferMPEG2" -check_type "va/va.h va/va_enc_vp8.h" "VAEncPictureParameterBufferVP8" -check_type "va/va.h va/va_enc_vp9.h" "VAEncPictureParameterBufferVP9" - check_type "vdpau/vdpau.h" "VdpPictureInfoHEVC" +if [ -z "$nvccflags" ]; then + nvccflags=$nvccflags_default +fi + +if enabled x86_64 || enabled ppc64 || enabled aarch64; then + nvccflags="$nvccflags -m64" +else + nvccflags="$nvccflags -m32" +fi + +if enabled cuda_nvcc; then + nvccflags="$nvccflags -ptx" +else + nvccflags="$nvccflags -S -nocudalib -nocudainc --cuda-device-only -include ${source_link}/compat/cuda/cuda_runtime.h" + check_nvcc cuda_llvm +fi + if ! disabled ffnvcodec; then - check_pkg_config ffnvcodec "ffnvcodec >= 8.0.14.1" \ - "ffnvcodec/nvEncodeAPI.h ffnvcodec/dynlink_cuda.h ffnvcodec/dynlink_cuviddec.h ffnvcodec/dynlink_nvcuvid.h" "" + ffnv_hdr_list="ffnvcodec/nvEncodeAPI.h ffnvcodec/dynlink_cuda.h ffnvcodec/dynlink_cuviddec.h ffnvcodec/dynlink_nvcuvid.h" + check_pkg_config ffnvcodec "ffnvcodec >= 9.0.18.0" "$ffnv_hdr_list" "" || \ + check_pkg_config ffnvcodec "ffnvcodec >= 8.2.15.8 ffnvcodec < 8.3" "$ffnv_hdr_list" "" || \ + check_pkg_config ffnvcodec "ffnvcodec >= 8.1.24.9 ffnvcodec < 8.2" "$ffnv_hdr_list" "" || \ + check_pkg_config ffnvcodec "ffnvcodec >= 8.0.14.9 ffnvcodec < 8.1" "$ffnv_hdr_list" "" fi check_cpp_condition winrt windows.h "!WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)" @@ -5950,7 +6148,8 @@ if ! disabled pthreads && ! enabled w32threads && ! enabled os2threads; then fi fi -enabled zlib && check_lib zlib zlib.h zlibVersion -lz +enabled zlib && { check_pkg_config zlib zlib "zlib.h" zlibVersion || + check_lib zlib zlib.h zlibVersion -lz; } enabled bzlib && check_lib bzlib bzlib.h BZ2_bzlibVersion -lbz2 enabled lzma && check_lib lzma lzma.h lzma_version_number -llzma @@ -5974,17 +6173,19 @@ for func in $COMPLEX_FUNCS; do done # these are off by default, so fail if requested and not available -enabled cuda_sdk && require cuda_sdk cuda.h cuCtxCreate -lcuda +enabled cuda_nvcc && { check_nvcc cuda_nvcc || die "ERROR: failed checking for nvcc."; } enabled chromaprint && require chromaprint chromaprint.h chromaprint_get_version -lchromaprint -enabled decklink && { require_header DeckLinkAPI.h && - { test_cpp_condition DeckLinkAPIVersion.h "BLACKMAGIC_DECKLINK_API_VERSION >= 0x0a060100" || die "ERROR: Decklink API version must be >= 10.6.1."; } } -enabled libndi_newtek && require_header Processing.NDI.Lib.h -enabled frei0r && require_header frei0r.h +enabled decklink && { require_headers DeckLinkAPI.h && + { test_cpp_condition DeckLinkAPIVersion.h "BLACKMAGIC_DECKLINK_API_VERSION >= 0x0a090500" || die "ERROR: Decklink API version must be >= 10.9.5."; } } +enabled frei0r && require_headers "frei0r.h dlfcn.h" enabled gmp && require gmp gmp.h mpz_export -lgmp enabled gnutls && require_pkg_config gnutls gnutls gnutls/gnutls.h gnutls_global_init -enabled jni && { [ $target_os = "android" ] && check_header jni.h && enabled pthreads || die "ERROR: jni not found"; } -enabled ladspa && require_header ladspa.h -enabled libaom && require_pkg_config libaom "aom >= 0.1.0" aom/aom_codec.h aom_codec_version +enabled jni && { [ $target_os = "android" ] && check_headers jni.h && enabled pthreads || die "ERROR: jni not found"; } +enabled ladspa && require_headers "ladspa.h dlfcn.h" +enabled libaom && require_pkg_config libaom "aom >= 1.0.0" aom/aom_codec.h aom_codec_version +enabled libaribb24 && { check_pkg_config libaribb24 "aribb24 > 1.0.3" "aribb24/aribb24.h" arib_instance_new || + { enabled gpl && require_pkg_config libaribb24 aribb24 "aribb24/aribb24.h" arib_instance_new; } || + die "ERROR: libaribb24 requires version higher than 1.0.3 or --enable-gpl."; } enabled lv2 && require_pkg_config lv2 lilv-0 "lilv/lilv.h" lilv_world_new enabled libiec61883 && require libiec61883 libiec61883/iec61883.h iec61883_cmp_connect -lraw1394 -lavc1394 -lrom1394 -liec61883 enabled libass && require_pkg_config libass libass ass/ass.h ass_library_init @@ -5995,6 +6196,8 @@ enabled libcelt && require libcelt celt/celt.h celt_decode -lcelt0 && die "ERROR: libcelt must be installed and version must be >= 0.11.0."; } enabled libcaca && require_pkg_config libcaca caca caca.h caca_create_canvas enabled libcodec2 && require libcodec2 codec2/codec2.h codec2_create -lcodec2 +enabled libdav1d && require_pkg_config libdav1d "dav1d >= 0.2.1" "dav1d/dav1d.h" dav1d_version +enabled libdavs2 && require_pkg_config libdavs2 "davs2 >= 1.6.0" davs2.h davs2_decoder_open enabled libdc1394 && require_pkg_config libdc1394 libdc1394-2 dc1394/dc1394.h dc1394_new enabled libdrm && require_pkg_config libdrm libdrm xf86drm.h drmGetVersion enabled libfdk_aac && { check_pkg_config libfdk_aac fdk-aac "fdk-aac/aacenc_lib.h" aacEncOpen || @@ -6012,7 +6215,9 @@ enabled libgsm && { for gsm_hdr in "gsm.h" "gsm/gsm.h"; do check_lib libgsm "${gsm_hdr}" gsm_create -lgsm && break; done || die "ERROR: libgsm not found"; } enabled libilbc && require libilbc ilbc.h WebRtcIlbcfix_InitDecode -lilbc $pthreads_extralibs +enabled libklvanc && require libklvanc libklvanc/vanc.h klvanc_context_create -lklvanc enabled libkvazaar && require_pkg_config libkvazaar "kvazaar >= 0.8.1" kvazaar.h kvz_api_get +enabled liblensfun && require_pkg_config liblensfun lensfun lensfun.h lf_db_new # While it may appear that require is being used as a pkg-config # fallback for libmfx, it is actually being used to detect a different # installation route altogether. If libmfx is installed via the Intel @@ -6023,13 +6228,14 @@ enabled libmfx && { check_pkg_config libmfx libmfx "mfx/mfxvideo.h" M { require libmfx "mfx/mfxvideo.h" MFXInit "-llibmfx $advapi32_extralibs" && warn "using libmfx without pkg-config"; } } enabled libmodplug && require_pkg_config libmodplug libmodplug libmodplug/modplug.h ModPlug_Load enabled libmp3lame && require "libmp3lame >= 3.98.3" lame/lame.h lame_set_VBR_quality -lmp3lame $libm_extralibs -enabled libmysofa && require libmysofa "mysofa.h" mysofa_load -lmysofa $zlib_extralibs -enabled libnpp && { check_lib libnpp npp.h nppGetLibVersion -lnppig -lnppicc -lnppc || - check_lib libnpp npp.h nppGetLibVersion -lnppi -lnppc || +enabled libmysofa && { check_pkg_config libmysofa libmysofa mysofa.h mysofa_load || + require libmysofa mysofa.h mysofa_load -lmysofa $zlib_extralibs; } +enabled libnpp && { check_lib libnpp npp.h nppGetLibVersion -lnppig -lnppicc -lnppc -lnppidei || + check_lib libnpp npp.h nppGetLibVersion -lnppi -lnppc -lnppidei || die "ERROR: libnpp not found"; } enabled libopencore_amrnb && require libopencore_amrnb opencore-amrnb/interf_dec.h Decoder_Interface_init -lopencore-amrnb enabled libopencore_amrwb && require libopencore_amrwb opencore-amrwb/dec_if.h D_IF_init -lopencore-amrwb -enabled libopencv && { check_header opencv2/core/core_c.h && +enabled libopencv && { check_headers opencv2/core/core_c.h && { check_pkg_config libopencv opencv opencv2/core/core_c.h cvCreateImageHeader || require libopencv opencv2/core/core_c.h cvCreateImageHeader -lopencv_core -lopencv_imgproc; } || require_pkg_config libopencv opencv opencv/cxcore.h cvCreateImageHeader; } @@ -6056,7 +6262,8 @@ enabled libsnappy && require libsnappy snappy-c.h snappy_compress -lsnap enabled libsoxr && require libsoxr soxr.h soxr_create -lsoxr enabled libssh && require_pkg_config libssh libssh libssh/sftp.h sftp_init enabled libspeex && require_pkg_config libspeex speex speex/speex.h speex_decoder_init -enabled libsrt && require_pkg_config libsrt "srt >= 1.2.0" srt/srt.h srt_socket +enabled libsrt && require_pkg_config libsrt "srt >= 1.3.0" srt/srt.h srt_socket +enabled libtensorflow && require libtensorflow tensorflow/c/c_api.h TF_Version -ltensorflow enabled libtesseract && require_pkg_config libtesseract tesseract tesseract/capi.h TessBaseAPICreate enabled libtheora && require libtheora theora/theoraenc.h th_info_init -ltheoraenc -ltheoradec -logg enabled libtls && require_pkg_config libtls libtls tls.h tls_configure @@ -6065,7 +6272,7 @@ enabled libtwolame && require libtwolame twolame.h twolame_init -ltwolame die "ERROR: libtwolame must be installed and version must be >= 0.3.10"; } enabled libv4l2 && require_pkg_config libv4l2 libv4l2 libv4l2.h v4l2_ioctl enabled libvidstab && require_pkg_config libvidstab "vidstab >= 0.98" vid.stab/libvidstab.h vsMotionDetectInit -enabled libvmaf && require_pkg_config libvmaf "libvmaf >= 0.6.2" libvmaf.h compute_vmaf +enabled libvmaf && require_pkg_config libvmaf "libvmaf >= 1.3.9" libvmaf.h compute_vmaf enabled libvo_amrwbenc && require libvo_amrwbenc vo-amrwbenc/enc_if.h E_IF_init -lvo-amrwbenc enabled libvorbis && require_pkg_config libvorbis vorbis vorbis/codec.h vorbis_info_init && require_pkg_config libvorbisenc vorbisenc vorbis/vorbisenc.h vorbis_encode_init @@ -6073,13 +6280,11 @@ enabled libvorbis && require_pkg_config libvorbis vorbis vorbis/codec.h enabled libvpx && { enabled libvpx_vp8_decoder && { check_pkg_config libvpx_vp8_decoder "vpx >= 1.4.0" "vpx/vpx_decoder.h vpx/vp8dx.h" vpx_codec_vp8_dx || - check_lib libvpx_vp8_decoder "vpx/vpx_decoder.h vpx/vp8dx.h" "vpx_codec_vp8_dx VPX_IMG_FMT_HIGHBITDEPTH" "-lvpx $libm_extralibs $pthreads_extralibs" || - die "ERROR: libvpx decoder version must be >=1.4.0"; + check_lib libvpx_vp8_decoder "vpx/vpx_decoder.h vpx/vp8dx.h" "vpx_codec_vp8_dx VPX_IMG_FMT_HIGHBITDEPTH" "-lvpx $libm_extralibs $pthreads_extralibs" } enabled libvpx_vp8_encoder && { check_pkg_config libvpx_vp8_encoder "vpx >= 1.4.0" "vpx/vpx_encoder.h vpx/vp8cx.h" vpx_codec_vp8_cx || - check_lib libvpx_vp8_encoder "vpx/vpx_encoder.h vpx/vp8cx.h" "vpx_codec_vp8_cx VPX_IMG_FMT_HIGHBITDEPTH" "-lvpx $libm_extralibs $pthreads_extralibs" || - die "ERROR: libvpx encoder version must be >=1.4.0"; + check_lib libvpx_vp8_encoder "vpx/vpx_encoder.h vpx/vp8cx.h" "vpx_codec_vp8_cx VPX_IMG_FMT_HIGHBITDEPTH" "-lvpx $libm_extralibs $pthreads_extralibs" } enabled libvpx_vp9_decoder && { check_pkg_config libvpx_vp9_decoder "vpx >= 1.4.0" "vpx/vpx_decoder.h vpx/vp8dx.h" vpx_codec_vp9_dx || @@ -6101,11 +6306,12 @@ enabled libwebp && { enabled libx264 && { check_pkg_config libx264 x264 "stdint.h x264.h" x264_encoder_encode || { require libx264 "stdint.h x264.h" x264_encoder_encode "-lx264 $pthreads_extralibs $libm_extralibs" && warn "using libx264 without pkg-config"; } } && - require_cpp_condition x264.h "X264_BUILD >= 118" && + require_cpp_condition libx264 x264.h "X264_BUILD >= 118" && check_cpp_condition libx262 x264.h "X264_MPEG2" enabled libx265 && require_pkg_config libx265 x265 x265.h x265_api_get && - require_cpp_condition x265.h "X265_BUILD >= 68" + require_cpp_condition libx265 x265.h "X265_BUILD >= 68" enabled libxavs && require libxavs "stdint.h xavs.h" xavs_encoder_encode "-lxavs $pthreads_extralibs $libm_extralibs" +enabled libxavs2 && require_pkg_config libxavs2 "xavs2 >= 1.3.0" "stdint.h xavs2.h" xavs2_api_get enabled libxvid && require libxvid xvid.h xvid_global -lxvidcore enabled libzimg && require_pkg_config libzimg "zimg >= 2.7.0" zimg.h zimg_get_api_version enabled libzmq && require_pkg_config libzmq libzmq zmq.h zmq_ctx_new @@ -6113,6 +6319,10 @@ enabled libzvbi && require_pkg_config libzvbi zvbi-0.2 libzvbi.h vbi_d { test_cpp_condition libzvbi.h "VBI_VERSION_MAJOR > 0 || VBI_VERSION_MINOR > 2 || VBI_VERSION_MINOR == 2 && VBI_VERSION_MICRO >= 28" || enabled gpl || die "ERROR: libzvbi requires version 0.2.28 or --enable-gpl."; } enabled libxml2 && require_pkg_config libxml2 libxml-2.0 libxml2/libxml/xmlversion.h xmlCheckVersion +enabled mbedtls && { check_pkg_config mbedtls mbedtls mbedtls/x509_crt.h mbedtls_x509_crt_init || + check_pkg_config mbedtls mbedtls mbedtls/ssl.h mbedtls_ssl_init || + check_lib mbedtls mbedtls/ssl.h mbedtls_ssl_init -lmbedtls -lmbedx509 -lmbedcrypto || + die "ERROR: mbedTLS not found"; } enabled mediacodec && { enabled jni || die "ERROR: mediacodec requires --enable-jni"; } enabled mmal && { check_lib mmal interface/mmal/mmal.h mmal_port_connect -lmmal_core -lmmal_util -lmmal_vc_client -lbcm_host || { ! enabled cross_compile && @@ -6126,7 +6336,8 @@ enabled openal && { { for al_extralibs in "${OPENAL_LIBS}" "-lopenal" die "ERROR: openal not found"; } && { test_cpp_condition "AL/al.h" "defined(AL_VERSION_1_1)" || die "ERROR: openal must be installed and version must be 1.1 or compatible"; } -enabled opencl && { check_lib opencl OpenCL/cl.h clEnqueueNDRangeKernel -Wl,-framework,OpenCL || +enabled opencl && { check_pkg_config opencl OpenCL CL/cl.h clEnqueueNDRangeKernel || + check_lib opencl OpenCL/cl.h clEnqueueNDRangeKernel -Wl,-framework,OpenCL || check_lib opencl CL/cl.h clEnqueueNDRangeKernel -lOpenCL || die "ERROR: opencl not found"; } && { test_cpp_condition "OpenCL/cl.h" "defined(CL_VERSION_1_2)" || @@ -6138,9 +6349,9 @@ enabled opengl && { check_lib opengl GL/glx.h glXGetProcAddress "-lGL check_lib opengl ES2/gl.h glGetError "-isysroot=${sysroot} -Wl,-framework,OpenGLES" || die "ERROR: opengl not found." } -enabled omx && require_header OMX_Core.h -enabled omx_rpi && { check_header OMX_Core.h || - { ! enabled cross_compile && add_cflags -isystem/opt/vc/include/IL && check_header OMX_Core.h ; } || +enabled omx && require_headers OMX_Core.h +enabled omx_rpi && { check_headers OMX_Core.h || + { ! enabled cross_compile && add_cflags -isystem/opt/vc/include/IL && check_headers OMX_Core.h ; } || die "ERROR: OpenMAX IL headers not found"; } && enable omx enabled openssl && { check_pkg_config openssl openssl openssl/ssl.h OPENSSL_init_ssl || check_pkg_config openssl openssl openssl/ssl.h SSL_library_init || @@ -6148,11 +6359,14 @@ enabled openssl && { check_pkg_config openssl openssl openssl/ssl.h OP check_lib openssl openssl/ssl.h SSL_library_init -lssl32 -leay32 || check_lib openssl openssl/ssl.h SSL_library_init -lssl -lcrypto -lws2_32 -lgdi32 || die "ERROR: openssl not found"; } +enabled pocketsphinx && require_pkg_config pocketsphinx pocketsphinx pocketsphinx/pocketsphinx.h ps_init enabled rkmpp && { require_pkg_config rkmpp rockchip_mpp rockchip/rk_mpi.h mpp_create && require_pkg_config rockchip_mpp "rockchip_mpp >= 1.3.7" rockchip/rk_mpi.h mpp_create && { enabled libdrm || die "ERROR: rkmpp requires --enable-libdrm"; } } +enabled vapoursynth && require_pkg_config vapoursynth "vapoursynth-script >= 42" VSScript.h vsscript_init + if enabled gcrypt; then GCRYPT_CONFIG="${cross_prefix}libgcrypt-config" @@ -6216,8 +6430,8 @@ pod2man --help > /dev/null 2>&1 && enable pod2man || disable pod2man rsync --help 2> /dev/null | grep -q 'contimeout' && enable rsync_contimeout || disable rsync_contimeout # check V4L2 codecs available in the API -check_header linux/fb.h -check_header linux/videodev2.h +check_headers linux/fb.h +check_headers linux/videodev2.h test_code cc linux/videodev2.h "struct v4l2_frmsizeenum vfse; vfse.discrete.width = 0;" && enable_sanitized struct_v4l2_frmivalenum_discrete check_cc v4l2_m2m linux/videodev2.h "int i = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_VIDEO_M2M | V4L2_BUF_FLAG_LAST;" check_cc vc1_v4l2_m2m linux/videodev2.h "int i = V4L2_PIX_FMT_VC1_ANNEX_G;" @@ -6230,7 +6444,7 @@ check_cc h264_v4l2_m2m linux/videodev2.h "int i = V4L2_PIX_FMT_H264;" check_cc vp8_v4l2_m2m linux/videodev2.h "int i = V4L2_PIX_FMT_VP8;" check_cc vp9_v4l2_m2m linux/videodev2.h "int i = V4L2_PIX_FMT_VP9;" -check_header sys/videoio.h +check_headers sys/videoio.h test_code cc sys/videoio.h "struct v4l2_frmsizeenum vfse; vfse.discrete.width = 0;" && enable_sanitized struct_v4l2_frmivalenum_discrete check_lib user32 "windows.h winuser.h" GetShellWindow -luser32 @@ -6242,10 +6456,10 @@ check_cpp_condition vfwcap_defines vfw.h "WM_CAP_DRIVER_CONNECT > WM_USER" check_type "dshow.h" IBaseFilter # check for ioctl_meteor.h, ioctl_bt848.h and alternatives -check_header "dev/bktr/ioctl_meteor.h dev/bktr/ioctl_bt848.h" || - check_header "machine/ioctl_meteor.h machine/ioctl_bt848.h" || - check_header "dev/video/meteor/ioctl_meteor.h dev/video/bktr/ioctl_bt848.h" || - check_header "dev/ic/bt8xx.h" +check_headers "dev/bktr/ioctl_meteor.h dev/bktr/ioctl_bt848.h" || + check_headers "machine/ioctl_meteor.h machine/ioctl_bt848.h" || + check_headers "dev/video/meteor/ioctl_meteor.h dev/video/bktr/ioctl_bt848.h" || + check_headers "dev/ic/bt8xx.h" if check_struct sys/soundcard.h audio_buf_info bytes; then enable_sanitized sys/soundcard.h @@ -6299,19 +6513,26 @@ test_cpp <= 0.35.0" "va/va.h" vaInitialize if enabled vaapi; then - check_lib vaapi_drm "va/va.h va/va_drm.h" vaGetDisplayDRM -lva -lva-drm - check_lib vaapi_x11 "va/va.h va/va_x11.h" vaGetDisplay -lva -lva-x11 -lX11 -fi + check_pkg_config vaapi_drm "libva-drm" "va/va_drm.h" vaGetDisplayDRM + + if enabled xlib; then + check_pkg_config vaapi_x11 "libva-x11" "va/va_x11.h" vaGetDisplay + fi -enabled vaapi && check_cpp_condition vaapi_1 "va/va.h" "VA_CHECK_VERSION(1, 0, 0)" + check_type "va/va.h va/va_dec_hevc.h" "VAPictureParameterBufferHEVC" + check_struct "va/va.h" "VADecPictureParameterBufferVP9" bit_depth + check_struct "va/va.h va/va_vpp.h" "VAProcPipelineCaps" rotation_flags + check_type "va/va.h va/va_enc_hevc.h" "VAEncPictureParameterBufferHEVC" + check_type "va/va.h va/va_enc_jpeg.h" "VAEncPictureParameterBufferJPEG" + check_type "va/va.h va/va_enc_vp8.h" "VAEncPictureParameterBufferVP8" + check_type "va/va.h va/va_enc_vp9.h" "VAEncPictureParameterBufferVP9" +fi + if enabled_all opencl libdrm ; then check_type "CL/cl_intel.h" "clCreateImageFromFdINTEL_fn" && enable opencl_drm_beignet @@ -6320,9 +6541,10 @@ if enabled_all opencl libdrm ; then fi if enabled_all opencl vaapi ; then - enabled opencl_drm_beignet && enable opencl_vaapi_beignet - if enabled libmfx ; then - check_type "CL/cl.h CL/va_ext.h" "clCreateFromVA_APIMediaSurfaceINTEL_fn" && + if enabled opencl_drm_beignet ; then + enable opencl_vaapi_beignet + else + check_type "CL/cl.h CL/cl_va_api_media_sharing_intel.h" "clCreateFromVA_APIMediaSurfaceINTEL_fn" && enable opencl_vaapi_intel_media fi fi @@ -6353,6 +6575,14 @@ if enabled x86; then disable ffnvcodec cuvid nvdec nvenc ;; esac +elif enabled ppc64 && ! enabled bigendian; then + case $target_os in + linux) + ;; + *) + disable ffnvcodec cuvid nvdec nvenc + ;; + esac else disable ffnvcodec cuvid nvdec nvenc fi @@ -6416,6 +6646,7 @@ check_disable_warning -Wno-format-zero-length check_disable_warning -Wno-pointer-sign check_disable_warning -Wno-unused-const-variable check_disable_warning -Wno-bool-operation +check_disable_warning -Wno-char-subscripts check_disable_warning_headers(){ warning_flag=-W${1#-Wno-} @@ -6431,7 +6662,7 @@ EOF # add some linker flags check_ldflags -Wl,--warn-common -check_ldflags -Wl,-rpath-link=libpostproc:libswresample:libswscale:libavfilter:libavdevice:libavformat:libavcodec:libavutil:libavresample +check_ldflags -Wl,-rpath-link=:libpostproc:libswresample:libswscale:libavfilter:libavdevice:libavformat:libavcodec:libavutil:libavresample enabled rpath && add_ldexeflags -Wl,-rpath,$libdir && add_ldsoflags -Wl,-rpath,$libdir test_ldflags -Wl,-Bsymbolic && append SHFLAGS -Wl,-Bsymbolic @@ -6503,16 +6734,6 @@ if [ -z "$optflags" ]; then fi fi -if [ -z "$nvccflags" ]; then - nvccflags=$nvccflags_default -fi - -if enabled x86_64 || enabled ppc64 || enabled aarch64; then - nvccflags="$nvccflags -m64" -else - nvccflags="$nvccflags -m32" -fi - check_optflags(){ check_cflags "$@" enabled lto && check_ldflags "$@" @@ -6698,10 +6919,17 @@ check_deps $CONFIG_LIST \ enabled threads && ! enabled pthreads && ! enabled atomics_native && die "non pthread threading without atomics not supported, try adding --enable-pthreads or --cpu=i486 or higher if you are on x86" enabled avresample && warn "Building with deprecated library libavresample" -if test $target_os = "haiku"; then +case $target_os in +haiku) disable memalign disable posix_memalign -fi + ;; +*-dos|freedos|opendos) + if test_cpp_condition sys/version.h "defined(__DJGPP__) && __DJGPP__ == 2 && __DJGPP_MINOR__ == 5"; then + disable memalign + fi + ;; +esac flatten_extralibs(){ nested_entries= @@ -6785,11 +7013,13 @@ done enabled zlib && add_cppflags -DZLIB_CONST # conditional library dependencies, in any order +enabled afftdn_filter && prepend avfilter_deps "avcodec" enabled afftfilt_filter && prepend avfilter_deps "avcodec" enabled afir_filter && prepend avfilter_deps "avcodec" enabled amovie_filter && prepend avfilter_deps "avformat avcodec" enabled aresample_filter && prepend avfilter_deps "swresample" enabled atempo_filter && prepend avfilter_deps "avcodec" +enabled bm3d_filter && prepend avfilter_deps "avcodec" enabled cover_rect_filter && prepend avfilter_deps "avformat avcodec" enabled convolve_filter && prepend avfilter_deps "avcodec" enabled deconvolve_filter && prepend avfilter_deps "avcodec" @@ -6815,6 +7045,7 @@ enabled signature_filter && prepend avfilter_deps "avcodec avformat" enabled smartblur_filter && prepend avfilter_deps "swscale" enabled spectrumsynth_filter && prepend avfilter_deps "avcodec" enabled spp_filter && prepend avfilter_deps "avcodec" +enabled sr_filter && prepend avfilter_deps "avformat swscale" enabled subtitles_filter && prepend avfilter_deps "avformat avcodec" enabled uspp_filter && prepend avfilter_deps "avcodec" enabled zoompan_filter && prepend avfilter_deps "swscale" @@ -6822,7 +7053,8 @@ enabled zoompan_filter && prepend avfilter_deps "swscale" enabled lavfi_indev && prepend avdevice_deps "avfilter" #FIXME -enabled sdl2_outdev && add_cflags $(filter_out '-Dmain=SDL_main' $sdl2_cflags) +enabled_any sdl2_outdev opengl_outdev && enabled sdl2 && + add_cflags $(filter_out '-Dmain=SDL_main' $sdl2_cflags) enabled opus_decoder && prepend avcodec_deps "swresample" @@ -6923,6 +7155,7 @@ if enabled mips; then echo "MIPS DSP R1 enabled ${mipsdsp-no}" echo "MIPS DSP R2 enabled ${mipsdspr2-no}" echo "MIPS MSA enabled ${msa-no}" + echo "MIPS MSA2 enabled ${msa2-no}" echo "LOONGSON MMI enabled ${mmi-no}" fi if enabled ppc; then @@ -6985,6 +7218,15 @@ echo "License: $license" fi # test "$quiet" != "yes" +if test -n "$WARN_IF_GETS_DISABLED_LIST"; then + for cfg in $WARN_IF_GETS_DISABLED_LIST; do + if disabled $cfg; then + varname=${cfg}_disable_reason + eval "warn \"Disabled $cfg because \$$varname\"" + fi + done +fi + if test -n "$WARNINGS"; then printf "\n%s%s$WARNINGS%s" "$warn_color" "$bold_color" "$reset_color" enabled fatal_warnings && exit 1 diff --git a/debian/changelog b/debian/changelog index d36fa0060..c2e0dd8d7 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +jellyfin-ffmpeg (4.2.1-1) unstable; urgency=medium + + * New upstream version 4.2.1 + + -- Joshua Boniface Fri, 27 Sep 2019 20:13:25 -0400 + jellyfin-ffmpeg (4.0.4-3) unstable; urgency=medium * Use libfontconfig to allow baked-in subtitle support diff --git a/doc/APIchanges b/doc/APIchanges index 4f6ac2a03..07331b16e 100644 --- a/doc/APIchanges +++ b/doc/APIchanges @@ -15,6 +15,69 @@ libavutil: 2017-10-21 API changes, most recent first: +-------- 8< --------- FFmpeg 4.2 was cut here -------- 8< --------- + +2019-06-21 - a30e44098a - lavu 56.30.100 - frame.h + Add FF_DECODE_ERROR_DECODE_SLICES + +2019-06-14 - edfced8c04 - lavu 56.29.100 - frame.h + Add FF_DECODE_ERROR_CONCEALMENT_ACTIVE + +2019-05-15 - b79b29ddb1 - lavu 56.28.100 - tx.h + Add av_tx_init(), av_tx_uninit() and related definitions. + +2019-04-20 - 3153a6502a - lavc 58.52.100 - avcodec.h + Add AV_CODEC_FLAG_DROPCHANGED to allow avcodec_receive_frame to drop + frames whose parameters differ from first decoded frame in stream. + +2019-04-12 - abfeba9724 - lavf 58.27.102 + Rename hls,applehttp demuxer to hls + +2019-01-27 - 5bcefceec8 - lavc 58.46.100 - avcodec.h + Add discard_damaged_percentage + +2019-01-08 - 1ef4828276 - lavu 56.26.100 - frame.h + Add AV_FRAME_DATA_REGIONS_OF_INTEREST + +2018-12-21 - 2744d6b364 - lavu 56.25.100 - hdr_dynamic_metadata.h + Add AV_FRAME_DATA_DYNAMIC_HDR_PLUS enum value, av_dynamic_hdr_plus_alloc(), + av_dynamic_hdr_plus_create_side_data() functions, and related structs. + +-------- 8< --------- FFmpeg 4.1 was cut here -------- 8< --------- + +2018-10-27 - 718044dc19 - lavu 56.21.100 - pixdesc.h + Add av_read_image_line2(), av_write_image_line2() + +2018-10-24 - f9d4126f28 - lavu 56.20.100 - frame.h + Add AV_FRAME_DATA_S12M_TIMECODE + +2018-10-11 - f6d48b618a - lavc 58.33.100 - mediacodec.h + Add av_mediacodec_render_buffer_at_time(). + +2018-09-09 - 35498c124a - lavc 58.29.100 - avcodec.h + Add AV_PKT_DATA_AFD + +2018-08-16 - b33f5299a5 - lavc 58.23.100 - avcodec.h + Add av_bsf_flush(). + +2018-05-18 - 2b2f2f65f3 - lavf 58.15.100 - avformat.h + Add pmt_version field to AVProgram + +2018-05-17 - 5dfeb7f081 - lavf 58.14.100 - avformat.h + Add AV_DISPOSITION_STILL_IMAGE + +2018-05-10 - c855683427 - lavu 56.18.101 - hwcontext_cuda.h + Add AVCUDADeviceContext.stream. + +2018-04-30 - 56b081da57 - lavu 56.18.100 - pixdesc.h + Add AV_PIX_FMT_FLAG_ALPHA to AV_PIX_FMT_PAL8. + +2018-04-26 - 5be0410cb3 - lavu 56.17.100 - opt.h + Add AV_OPT_FLAG_DEPRECATED. + +2018-04-26 - 71fa82bed6 - lavu 56.16.100 - threadmessage.h + Add av_thread_message_queue_nb_elems(). + -------- 8< --------- FFmpeg 4.0 was cut here -------- 8< --------- 2018-04-03 - d6fc031caf - lavu 56.13.100 - pixdesc.h diff --git a/doc/Doxyfile b/doc/Doxyfile index 1c7de2ef4..eedfdf40d 100644 --- a/doc/Doxyfile +++ b/doc/Doxyfile @@ -38,7 +38,7 @@ PROJECT_NAME = FFmpeg # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 4.0.4 +PROJECT_NUMBER = 4.2.1 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a diff --git a/doc/bitstream_filters.texi b/doc/bitstream_filters.texi index 7322af655..14f35893d 100644 --- a/doc/bitstream_filters.texi +++ b/doc/bitstream_filters.texi @@ -37,6 +37,61 @@ raw ADTS AAC or an MPEG-TS container to MP4A-LATM, to an FLV file, or to MOV/MP4 files and related formats such as 3GP or M4A. Please note that it is auto-inserted for MP4A-LATM and MOV/MP4 and related formats. +@section av1_metadata + +Modify metadata embedded in an AV1 stream. + +@table @option +@item td +Insert or remove temporal delimiter OBUs in all temporal units of the +stream. + +@table @samp +@item insert +Insert a TD at the beginning of every TU which does not already have one. +@item remove +Remove the TD from the beginning of every TU which has one. +@end table + +@item color_primaries +@item transfer_characteristics +@item matrix_coefficients +Set the color description fields in the stream (see AV1 section 6.4.2). + +@item color_range +Set the color range in the stream (see AV1 section 6.4.2; note that +this cannot be set for streams using BT.709 primaries, sRGB transfer +characteristic and identity (RGB) matrix coefficients). +@table @samp +@item tv +Limited range. +@item pc +Full range. +@end table + +@item chroma_sample_position +Set the chroma sample location in the stream (see AV1 section 6.4.2). +This can only be set for 4:2:0 streams. + +@table @samp +@item vertical +Left position (matching the default in MPEG-2 and H.264). +@item colocated +Top-left position. +@end table + +@item tick_rate +Set the tick rate (@emph{num_units_in_display_tick / time_scale}) in +the timing info in the sequence header. +@item num_ticks_per_picture +Set the number of ticks in each picture, to indicate that the stream +has a fixed framerate. Ignored if @option{tick_rate} is not also set. + +@item delete_padding +Deletes Padding OBUs. + +@end table + @section chomp Remove zero padding at the end of a packet. @@ -48,7 +103,9 @@ DTS-HD. @section dump_extra -Add extradata to the beginning of the filtered packets. +Add extradata to the beginning of the filtered packets except when +said packets already exactly begin with the extradata that is intended +to be added. @table @option @item freq @@ -65,7 +122,7 @@ add extradata to all packets @end table @end table -If not specified it is assumed @samp{e}. +If not specified it is assumed @samp{k}. For example the following @command{ffmpeg} command forces a global header (thus disabling individual packet headers) in the H.264 packets @@ -215,6 +272,15 @@ insert the string ``hello'' associated with the given UUID. @item delete_filler Deletes both filler NAL units and filler SEI messages. +@item level +Set the level in the SPS. Refer to H.264 section A.3 and tables A-1 +to A-5. + +The argument must be the name of a level (for example, @samp{4.2}), a +level_idc value (for example, @samp{42}), or the special name @samp{auto} +indicating that the filter should attempt to guess the level from the +input stream properties. + @end table @section h264_mp4toannexb @@ -297,6 +363,15 @@ will replace the current ones if the stream is already cropped. These fields are set in pixels. Note that some sizes may not be representable if the chroma is subsampled (H.265 section 7.4.3.2.1). +@item level +Set the level in the VPS and SPS. See H.265 section A.4 and tables +A.6 and A.7. + +The argument must be the name of a level (for example, @samp{5.1}), a +@emph{general_level_idc} value (for example, @samp{153} for level 5.1), +or the special name @samp{auto} indicating that the filter should +attempt to guess the level from the input stream properties. + @end table @section hevc_mp4toannexb @@ -469,6 +544,72 @@ ffmpeg -i INPUT -c copy -bsf noise[=1] output.mkv @section null This bitstream filter passes the packets through unchanged. +@section prores_metadata + +Modify color property metadata embedded in prores stream. + +@table @option +@item color_primaries +Set the color primaries. +Available values are: + +@table @samp +@item auto +Keep the same color primaries property (default). + +@item unknown +@item bt709 +@item bt470bg +BT601 625 + +@item smpte170m +BT601 525 + +@item bt2020 +@item smpte431 +DCI P3 + +@item smpte432 +P3 D65 + +@end table + +@item transfer_characteristics +Set the color transfer. +Available values are: + +@table @samp +@item auto +Keep the same transfer characteristics property (default). + +@item unknown +@item bt709 +BT 601, BT 709, BT 2020 +@end table + + +@item matrix_coefficients +Set the matrix coefficient. +Available values are: + +@table @samp +@item auto +Keep the same transfer characteristics property (default). + +@item unknown +@item bt709 +@item smpte170m +BT 601 + +@item bt2020nc +@end table +@end table + +Set Rec709 colorspace for each frame of the file +@example +ffmpeg -i INPUT -c copy -bsf:v prores_metadata=color_primaries=bt709:color_trc=bt709:colorspace=bt709 output.mov +@end example + @section remove_extra Remove extradata from packets. @@ -505,7 +646,38 @@ Log trace output containing all syntax elements in the coded stream headers (everything above the level of individual coded blocks). This can be useful for debugging low-level stream issues. -Supports H.264, H.265 and MPEG-2. +Supports AV1, H.264, H.265, (M)JPEG, MPEG-2 and VP9, but depending +on the build only a subset of these may be available. + +@section truehd_core + +Extract the core from a TrueHD stream, dropping ATMOS data. + +@section vp9_metadata + +Modify metadata embedded in a VP9 stream. + +@table @option +@item color_space +Set the color space value in the frame header. +@table @samp +@item unknown +@item bt601 +@item bt709 +@item smpte170 +@item smpte240 +@item bt2020 +@item rgb +@end table + +@item color_range +Set the color range value in the frame header. Note that this cannot +be set in RGB streams. +@table @samp +@item tv +@item pc +@end table +@end table @section vp9_superframe diff --git a/doc/build_system.txt b/doc/build_system.txt index 325a9e83d..3d6a21a9f 100644 --- a/doc/build_system.txt +++ b/doc/build_system.txt @@ -36,11 +36,11 @@ install examples Build all examples located in doc/examples. -libavformat/output-example - Build the libavformat basic example. +checkheaders + Check headers dependencies. -libswscale/swscale-test - Build the swscale self-test (useful also as an example). +alltools + Build all tools in tools directory. config Reconfigure the project with the current configuration. diff --git a/doc/codecs.texi b/doc/codecs.texi index c9b9a1136..0d0de94c5 100644 --- a/doc/codecs.texi +++ b/doc/codecs.texi @@ -55,6 +55,9 @@ Do not draw edges. @item psnr Set error[?] variables during encoding. @item truncated +@item drop_changed +Don't output frames whose parameters differ from first decoded frame in stream. +Error AVERROR_INPUT_CHANGED is returned when a frame is dropped. @item ildct Use interlaced DCT. @@ -775,8 +778,6 @@ Place global headers at every keyframe instead of in extradata. Frame data might be split into multiple chunks. @item showall Show all frames before the first keyframe. -@item skiprd -Deprecated, use mpegvideo private options instead. @item export_mvs Export motion vectors into frame side-data (see @code{AV_FRAME_DATA_MOTION_VECTORS}) for codecs that support it. See also @file{doc/examples/export_mvs.c}. @@ -962,6 +963,9 @@ Discard all bidirectional frames. @item nokey Discard all frames excepts keyframes. +@item nointra +Discard all frames except I frames. + @item all Discard all frames. @end table @@ -986,10 +990,6 @@ Set chroma qp offset from luma. @item trellis @var{integer} (@emph{encoding,audio,video}) Set rate-distortion optimal quantization. -@item sc_factor @var{integer} (@emph{encoding,video}) -Set value multiplied by qscale for each frame and added to -scene_change_score. - @item mv0_threshold @var{integer} (@emph{encoding,video}) @item b_sensitivity @var{integer} (@emph{encoding,video}) Adjust sensitivity of b_frame_strategy 1. @@ -1236,7 +1236,7 @@ instead of alpha. Default is 0. @item dump_separator @var{string} (@emph{input}) Separator used to separate the fields printed on the command line about the Stream parameters. -For example to separate the fields with newlines and indention: +For example, to separate the fields with newlines and indentation: @example ffprobe -dump_separator " " -i ~/videos/matrixbench_mpeg2.mpg diff --git a/doc/decoders.texi b/doc/decoders.texi index a9510bdf0..0582b018b 100644 --- a/doc/decoders.texi +++ b/doc/decoders.texi @@ -47,6 +47,38 @@ top-field-first is assumed @end table +@section libdav1d + +dav1d AV1 decoder. + +libdav1d allows libavcodec to decode the AOMedia Video 1 (AV1) codec. +Requires the presence of the libdav1d headers and library during configuration. +You need to explicitly configure the build with @code{--enable-libdav1d}. + +@subsection Options + +The following option is supported by the libdav1d wrapper. + +@table @option + +@item framethreads +Set amount of frame threads to use during decoding. The default value is 0 (autodetect). + +@item tilethreads +Set amount of tile threads to use during decoding. The default value is 0 (autodetect). + +@item filmgrain +Apply film grain to the decoded video if present in the bitstream. The default value +is true. + +@end table + +@section libdavs2 + +AVS2-P2/IEEE1857.4 video decoder wrapper. + +This decoder allows libavcodec to decode AVS2 streams with davs2 library. + @c man end VIDEO DECODERS @chapter Audio Decoders @@ -188,6 +220,31 @@ without this library. @chapter Subtitles Decoders @c man begin SUBTILES DECODERS +@section libaribb24 + +ARIB STD-B24 caption decoder. + +Implements profiles A and C of the ARIB STD-B24 standard. + +@subsection libaribb24 Decoder Options + +@table @option + +@item -aribb24-base-path @var{path} +Sets the base path for the libaribb24 library. This is utilized for reading of +configuration files (for custom unicode conversions), and for dumping of +non-text symbols as images under that location. + +Unset by default. + +@item -aribb24-skip-ruby-text @var{boolean} +Tells the decoder wrapper to skip text blocks that contain half-height ruby +text. + +Enabled by default. + +@end table + @section dvbsub @subsection Options @@ -248,18 +305,25 @@ configuration. You need to explicitly configure the build with @table @option @item txt_page -List of teletext page numbers to decode. You may use the special * string to -match all pages. Pages that do not match the specified list are dropped. +List of teletext page numbers to decode. Pages that do not match the specified +list are dropped. You may use the special @code{*} string to match all pages, +or @code{subtitle} to match all subtitle pages. Default value is *. @item txt_chop_top Discards the top teletext line. Default value is 1. @item txt_format -Specifies the format of the decoded subtitles. The teletext decoder is capable -of decoding the teletext pages to bitmaps or to simple text, you should use -"bitmap" for teletext pages, because certain graphics and colors cannot be -expressed in simple text. You might use "text" for teletext based subtitles if -your application can handle simple text based subtitles. Default value is -bitmap. +Specifies the format of the decoded subtitles. +@table @option +@item bitmap +The default format, you should use this for teletext pages, because certain +graphics and colors cannot be expressed in simple text or even ASS. +@item text +Simple text based output without formatting. +@item ass +Formatted ASS output, subtitle pages and teletext pages are returned in +different styles, subtitle pages are stripped down to text, but an effort is +made to keep the text alignment and the formatting. +@end table @item txt_left X offset of generated bitmaps, default is 0. @item txt_top @@ -272,7 +336,8 @@ present between the subtitle lines because of double-sized teletext characters. Default value is 1. @item txt_duration Sets the display duration of the decoded teletext pages or subtitles in -milliseconds. Default value is 30000 which is 30 seconds. +milliseconds. Default value is -1 which means infinity or until the next +subtitle event comes. @item txt_transparent Force transparent background of the generated teletext bitmaps. Default value is 0 which means an opaque background. diff --git a/doc/demuxers.texi b/doc/demuxers.texi index e7c2abce5..57d153221 100644 --- a/doc/demuxers.texi +++ b/doc/demuxers.texi @@ -25,17 +25,6 @@ Audible Format 2, 3, and 4 demuxer. This demuxer is used to demux Audible Format 2, 3, and 4 (.aa) files. -@section applehttp - -Apple HTTP Live Streaming demuxer. - -This demuxer presents all AVStreams from all variant streams. -The id field is set to the bitrate variant index number. By setting -the discard flags on AVStreams (by pressing 'a' or 'v' in ffplay), -the caller can decide which variant streams to actually receive. -The total bitrate of the variant that the stream belongs to is -available in a metadata key named "variant_bitrate". - @section apng Animated Portable Network Graphics demuxer. @@ -269,6 +258,12 @@ ffmpeg -f live_flv -i rtmp:///anything/key .... @table @option @item -flv_metadata @var{bool} Allocate the streams according to the onMetaData array content. + +@item -flv_ignore_prevtag @var{bool} +Ignore the size of previous tag value. + +@item -flv_full_metadata @var{bool} +Output all context of the onMetadata. @end table @section gif @@ -314,6 +309,15 @@ infinitely. HLS demuxer +Apple HTTP Live Streaming demuxer. + +This demuxer presents all AVStreams from all variant streams. +The id field is set to the bitrate variant index number. By setting +the discard flags on AVStreams (by pressing 'a' or 'v' in ffplay), +the caller can decide which variant streams to actually receive. +The total bitrate of the variant that the stream belongs to is +available in a metadata key named "variant_bitrate". + It accepts the following options: @table @option @@ -475,14 +479,84 @@ ffmpeg -framerate 10 -pattern_type glob -i "*.png" out.mkv The Game Music Emu library is a collection of video game music file emulators. -See @url{http://code.google.com/p/game-music-emu/} for more information. +See @url{https://bitbucket.org/mpyne/game-music-emu/overview} for more information. -Some files have multiple tracks. The demuxer will pick the first track by -default. The @option{track_index} option can be used to select a different -track. Track indexes start at 0. The demuxer exports the number of tracks as -@var{tracks} meta data entry. +It accepts the following options: -For very large files, the @option{max_size} option may have to be adjusted. +@table @option + +@item track_index +Set the index of which track to demux. The demuxer can only export one track. +Track indexes start at 0. Default is to pick the first track. Number of tracks +is exported as @var{tracks} metadata entry. + +@item sample_rate +Set the sampling rate of the exported track. Range is 1000 to 999999. Default is 44100. + +@item max_size @emph{(bytes)} +The demuxer buffers the entire file into memory. Adjust this value to set the maximum buffer size, +which in turn, acts as a ceiling for the size of files that can be read. +Default is 50 MiB. + +@end table + +@section libmodplug + +ModPlug based module demuxer + +See @url{https://github.com/Konstanty/libmodplug} + +It will export one 2-channel 16-bit 44.1 kHz audio stream. +Optionally, a @code{pal8} 16-color video stream can be exported with or without printed metadata. + +It accepts the following options: + +@table @option +@item noise_reduction +Apply a simple low-pass filter. Can be 1 (on) or 0 (off). Default is 0. + +@item reverb_depth +Set amount of reverb. Range 0-100. Default is 0. + +@item reverb_delay +Set delay in ms, clamped to 40-250 ms. Default is 0. + +@item bass_amount +Apply bass expansion a.k.a. XBass or megabass. Range is 0 (quiet) to 100 (loud). Default is 0. + +@item bass_range +Set cutoff i.e. upper-bound for bass frequencies. Range is 10-100 Hz. Default is 0. + +@item surround_depth +Apply a Dolby Pro-Logic surround effect. Range is 0 (quiet) to 100 (heavy). Default is 0. + +@item surround_delay +Set surround delay in ms, clamped to 5-40 ms. Default is 0. + +@item max_size +The demuxer buffers the entire file into memory. Adjust this value to set the maximum buffer size, +which in turn, acts as a ceiling for the size of files that can be read. Range is 0 to 100 MiB. +0 removes buffer size limit (not recommended). Default is 5 MiB. + +@item video_stream_expr +String which is evaluated using the eval API to assign colors to the generated video stream. +Variables which can be used are @code{x}, @code{y}, @code{w}, @code{h}, @code{t}, @code{speed}, +@code{tempo}, @code{order}, @code{pattern} and @code{row}. + +@item video_stream +Generate video stream. Can be 1 (on) or 0 (off). Default is 0. + +@item video_stream_w +Set video frame width in 'chars' where one char indicates 8 pixels. Range is 20-512. Default is 30. + +@item video_stream_h +Set video frame height in 'chars' where one char indicates 8 pixels. Range is 20-512. Default is 30. + +@item video_stream_ptxt +Print metadata on video stream. Includes @code{speed}, @code{tempo}, @code{order}, @code{pattern}, +@code{row} and @code{ts} (time in ms). Can be 1 (on) or 0 (off). Default is 1. + +@end table @section libopenmpt @@ -538,6 +612,9 @@ This demuxer accepts the following options: Set size limit for looking up a new synchronization. Default value is 65536. +@item skip_unknown_pmt +Skip PMTs for programs not defined in the PAT. Default value is 0. + @item fix_teletext_pts Override teletext packet PTS and DTS values with the timestamps calculated from the PCR of the first program which the teletext stream is part of and is @@ -552,6 +629,10 @@ Show the detected raw packet size, cannot be set by the user. Scan and combine all PMTs. The value is an integer with value from -1 to 1 (-1 means automatic setting, 1 means enabled, 0 means disabled). Default value is -1. + +@item merge_pmt_versions +Re-use existing streams when a PMT's version is updated and elementary +streams move to different PIDs. Default value is 0. @end table @section mpjpeg @@ -649,4 +730,20 @@ Example: convert the captions to a format most players understand: ffmpeg -i http://www.ted.com/talks/subtitles/id/1/lang/en talk1-en.srt @end example +@section vapoursynth + +Vapoursynth wrapper. + +Due to security concerns, Vapoursynth scripts will not +be autodetected so the input format has to be forced. For ff* CLI tools, +add @code{-f vapoursynth} before the input @code{-i yourscript.vpy}. + +This demuxer accepts the following option: +@table @option +@item max_script_size +The demuxer buffers the entire script into memory. Adjust this value to set the maximum buffer size, +which in turn, acts as a ceiling for the size of scripts that can be read. +Default is 1 MiB. +@end table + @c man end DEMUXERS diff --git a/doc/developer.texi b/doc/developer.texi index a0eeefe24..5c342c910 100644 --- a/doc/developer.texi +++ b/doc/developer.texi @@ -128,6 +128,9 @@ designated struct initializers (@samp{struct s x = @{ .i = 17 @};}); @item compound literals (@samp{x = (struct s) @{ 17, 23 @};}). +@item +for loops with variable definition (@samp{for (int i = 0; i < 8; i++)}); + @item Implementation defined behavior for signed integers is assumed to match the expected behavior for two's complement. Non representable values in integer diff --git a/doc/encoders.texi b/doc/encoders.texi index 7b095754d..eefd12475 100644 --- a/doc/encoders.texi +++ b/doc/encoders.texi @@ -733,6 +733,14 @@ if set to 0. Default value is 0. +@item eld_v2 +Enable ELDv2 (LD-MPS extension for ELD stereo signals) for ELDv2 if set to 1, +disabled if set to 0. + +Note that option is available when fdk-aac version (AACENCODER_LIB_VL0.AACENCODER_LIB_VL1.AACENCODER_LIB_VL2) > (4.0.0). + +Default value is 0. + @item signaling Set SBR/PS signaling style. @@ -1370,6 +1378,181 @@ makes it possible to store non-rgb pix_fmts. @end table +@section libaom-av1 + +libaom AV1 encoder wrapper. + +Requires the presence of the libaom headers and library during +configuration. You need to explicitly configure the build with +@code{--enable-libaom}. + +@subsection Options + +The wrapper supports the following standard libavcodec options: + +@table @option + +@item b +Set bitrate target in bits/second. By default this will use +variable-bitrate mode. If @option{maxrate} and @option{minrate} are +also set to the same value then it will use constant-bitrate mode, +otherwise if @option{crf} is set as well then it will use +constrained-quality mode. + +@item g keyint_min +Set key frame placement. The GOP size sets the maximum distance between +key frames; if zero the output stream will be intra-only. The minimum +distance is ignored unless it is the same as the GOP size, in which case +key frames will always appear at a fixed interval. Not set by default, +so without this option the library has completely free choice about +where to place key frames. + +@item qmin qmax +Set minimum/maximum quantisation values. Valid range is from 0 to 63 +(warning: this does not match the quantiser values actually used by AV1 +- divide by four to map real quantiser values to this range). Defaults +to min/max (no constraint). + +@item minrate maxrate bufsize rc_init_occupancy +Set rate control buffering parameters. Not used if not set - defaults +to unconstrained variable bitrate. + +@item threads +Set the number of threads to use while encoding. This may require the +@option{tiles} or @option{row-mt} options to also be set to actually +use the specified number of threads fully. Defaults to the number of +hardware threads supported by the host machine. + +@item profile +Set the encoding profile. Defaults to using the profile which matches +the bit depth and chroma subsampling of the input. + +@end table + +The wrapper also has some specific options: + +@table @option + +@item cpu-used +Set the quality/encoding speed tradeoff. Valid range is from 0 to 8, +higher numbers indicating greater speed and lower quality. The default +value is 1, which will be slow and high quality. + +@item auto-alt-ref +Enable use of alternate reference frames. Defaults to the internal +default of the library. + +@item arnr-max-frames (@emph{frames}) +Set altref noise reduction max frame count. Default is -1. + +@item arnr-strength (@emph{strength}) +Set altref noise reduction filter strength. Range is -1 to 6. Default is -1. + +@item aq-mode (@emph{aq-mode}) +Set adaptive quantization mode. Possible values: + +@table @samp +@item none (@emph{0}) +Disabled. + +@item variance (@emph{1}) +Variance-based. + +@item complexity (@emph{2}) +Complexity-based. + +@item cyclic (@emph{3}) +Cyclic refresh. +@end table + +@item lag-in-frames +Set the maximum number of frames which the encoder may keep in flight +at any one time for lookahead purposes. Defaults to the internal +default of the library. + +@item error-resilience +Enable error resilience features: +@table @option +@item default +Improve resilience against losses of whole frames. +@end table +Not enabled by default. + +@item crf +Set the quality/size tradeoff for constant-quality (no bitrate target) +and constrained-quality (with maximum bitrate target) modes. Valid +range is 0 to 63, higher numbers indicating lower quality and smaller +output size. Only used if set; by default only the bitrate target is +used. + +@item static-thresh +Set a change threshold on blocks below which they will be skipped by +the encoder. Defined in arbitrary units as a nonnegative integer, +defaulting to zero (no blocks are skipped). + +@item drop-threshold +Set a threshold for dropping frames when close to rate control bounds. +Defined as a percentage of the target buffer - when the rate control +buffer falls below this percentage, frames will be dropped until it +has refilled above the threshold. Defaults to zero (no frames are +dropped). + +@item denoise-noise-level (@emph{level}) +Amount of noise to be removed for grain synthesis. Grain synthesis is disabled if +this option is not set or set to 0. + +@item denoise-block-size (@emph{pixels}) +Block size used for denoising for grain synthesis. If not set, AV1 codec +uses the default value of 32. + +@item undershoot-pct (@emph{pct}) +Set datarate undershoot (min) percentage of the target bitrate. Range is -1 to 100. +Default is -1. + +@item overshoot-pct (@emph{pct}) +Set datarate overshoot (max) percentage of the target bitrate. Range is -1 to 1000. +Default is -1. + +@item minsection-pct (@emph{pct}) +Minimum percentage variation of the GOP bitrate from the target bitrate. If minsection-pct +is not set, the libaomenc wrapper computes it as follows: @code{(minrate * 100 / bitrate)}. +Range is -1 to 100. Default is -1 (unset). + +@item maxsection-pct (@emph{pct}) +Maximum percentage variation of the GOP bitrate from the target bitrate. If maxsection-pct +is not set, the libaomenc wrapper computes it as follows: @code{(maxrate * 100 / bitrate)}. +Range is -1 to 5000. Default is -1 (unset). + +@item frame-parallel (@emph{boolean}) +Enable frame parallel decodability features. Default is true. + +@item tiles +Set the number of tiles to encode the input video with, as columns x +rows. Larger numbers allow greater parallelism in both encoding and +decoding, but may decrease coding efficiency. Defaults to the minimum +number of tiles required by the size of the input video (this is 1x1 +(that is, a single tile) for sizes up to and including 4K). + +@item tile-columns tile-rows +Set the number of tiles as log2 of the number of tile rows and columns. +Provided for compatibility with libvpx/VP9. + +@item row-mt (Requires libaom >= 1.0.0-759-g90a15f4f2) +Enable row based multi-threading. Disabled by default. + +@item enable-cdef (@emph{boolean}) +Enable Constrained Directional Enhancement Filter. The libaom-av1 +encoder enables CDEF by default. + +@item enable-global-motion (@emph{boolean}) +Enable the use of global motion for block prediction. Default is true. + +@item enable-intrabc (@emph{boolean}) +Enable block copy mode for intra block prediction. This mode is +useful for screen content. Default is true. + +@end table + @section libkvazaar Kvazaar H.265/HEVC encoder. @@ -1641,7 +1824,8 @@ means unlimited. @table @option @item auto-alt-ref Enable use of alternate reference frames (2-pass only). -@item arnr-max-frames +Values greater than 1 enable multi-layer alternate reference frames (VP9 only). +@item arnr-maxframes Set altref noise reduction max frame count. @item arnr-type Set altref noise reduction filter type: backward, forward, centered. @@ -1654,6 +1838,38 @@ Set number of frames to look ahead for frametype and ratecontrol. @item error-resilient Enable error resiliency features. +@item sharpness @var{integer} +Increase sharpness at the expense of lower PSNR. +The valid range is [0, 7]. + +@item VP8-specific options +@table @option +@item ts-parameters +Sets the temporal scalability configuration using a :-separated list of +key=value pairs. For example, to specify temporal scalability parameters +with @code{ffmpeg}: +@example +ffmpeg -i INPUT -c:v libvpx -ts-parameters ts_number_layers=3:\ +ts_target_bitrate=250000,500000,1000000:ts_rate_decimator=4,2,1:\ +ts_periodicity=4:ts_layer_id=0,2,1,2 OUTPUT +@end example +Below is a brief explanation of each of the parameters, please +refer to @code{struct vpx_codec_enc_cfg} in @code{vpx/vpx_encoder.h} for more +details. +@table @option +@item ts_number_layers +Number of temporal coding layers. +@item ts_target_bitrate +Target bitrate for each temporal layer. +@item ts_rate_decimator +Frame rate decimation factor for each temporal layer. +@item ts_periodicity +Length of the sequence defining frame temporal layer membership. +@item ts_layer_id +Template defining the membership of frames to temporal layers. +@end table +@end table + @item VP9-specific options @table @option @item lossless @@ -1692,6 +1908,8 @@ Corpus VBR mode is a variant of standard VBR where the complexity distribution midpoint is passed in rather than calculated for a specific clip or chunk. The valid range is [0, 10000]. 0 (default) uses standard VBR. +@item enable-tpl @var{boolean} +Enable temporal dependency model. @end table @end table @@ -2180,6 +2398,63 @@ ffmpeg -i input -c:v libx265 -x265-params crf=26:psy-rd=1 output.mp4 @end example @end table +@section libxavs2 + +xavs2 AVS2-P2/IEEE1857.4 encoder wrapper. + +This encoder requires the presence of the libxavs2 headers and library +during configuration. You need to explicitly configure the build with +@option{--enable-libxavs2}. + +The following standard libavcodec options are used: +@itemize +@item +@option{b} / @option{bit_rate} +@item +@option{g} / @option{gop_size} +@item +@option{bf} / @option{max_b_frames} +@end itemize + +The encoder also has its own specific options: +@subsection Options + +@table @option +@item lcu_row_threads +Set the number of parallel threads for rows from 1 to 8 (default 5). + +@item initial_qp +Set the xavs2 quantization parameter from 1 to 63 (default 34). This is +used to set the initial qp for the first frame. + +@item qp +Set the xavs2 quantization parameter from 1 to 63 (default 34). This is +used to set the qp value under constant-QP mode. + +@item max_qp +Set the max qp for rate control from 1 to 63 (default 55). + +@item min_qp +Set the min qp for rate control from 1 to 63 (default 20). + +@item speed_level +Set the Speed level from 0 to 9 (default 0). Higher is better but slower. + +@item log_level +Set the log level from -1 to 3 (default 0). -1: none, 0: error, +1: warning, 2: info, 3: debug. + +@item xavs2-params +Set xavs2 options using a list of @var{key}=@var{value} couples separated +by ":". + +For example to specify libxavs2 encoding options with @option{-xavs2-params}: + +@example +ffmpeg -i input -c:v libxavs2 -xavs2-params RdoqLevel=0 output.avs2 +@end example +@end table + @section libxvid Xvid MPEG-4 Part 2 encoder wrapper. @@ -2370,6 +2645,9 @@ Specifies the video_format written into the sequence display extension indicating the source of the video pictures. The default is @samp{unspecified}, can be @samp{component}, @samp{pal}, @samp{ntsc}, @samp{secam} or @samp{mac}. For maximum compatibility, use @samp{component}. +@item a53cc @var{boolean} +Import closed captions (which must be ATSC compatible format) into output. +Default is 1 (on). @end table @section png @@ -2565,6 +2843,9 @@ The following standard libavcodec options are used: @option{bf} / @option{max_b_frames} @item @option{profile} + +If not set, this will be determined automatically from the format of the input +frames and the profiles supported by the driver. @item @option{level} @item @@ -2585,7 +2866,8 @@ Speed / quality tradeoff: higher values are faster / worse quality. Size / quality tradeoff: higher values are smaller / worse quality. @item @option{qmin} -(only: @option{qmax} is not supported) +@item +@option{qmax} @item @option{i_qfactor} / @option{i_quant_factor} @item @@ -2594,8 +2876,55 @@ Size / quality tradeoff: higher values are smaller / worse quality. @option{b_qfactor} / @option{b_quant_factor} @item @option{b_qoffset} / @option{b_quant_offset} +@item +@option{slices} @end itemize +All encoders support the following options: +@table @option +@item low_power +Some drivers/platforms offer a second encoder for some codecs intended to use +less power than the default encoder; setting this option will attempt to use +that encoder. Note that it may support a reduced feature set, so some other +options may not be available in this mode. + +@item idr_interval +Set the number of normal intra frames between full-refresh (IDR) frames in +open-GOP mode. The intra frames are still IRAPs, but will not include global +headers and may have non-decodable leading pictures. + +@item b_depth +Set the B-frame reference depth. When set to one (the default), all B-frames +will refer only to P- or I-frames. When set to greater values multiple layers +of B-frames will be present, frames in each layer only referring to frames in +higher layers. + +@item rc_mode +Set the rate control mode to use. A given driver may only support a subset of +modes. + +Possible modes: +@table @option +@item auto +Choose the mode automatically based on driver support and the other options. +This is the default. +@item CQP +Constant-quality. +@item CBR +Constant-bitrate. +@item VBR +Variable-bitrate. +@item ICQ +Intelligent constant-quality. +@item QVBR +Quality-defined variable-bitrate. +@item AVBR +Average variable bitrate. +@end table + +@end table + +Each encoder also has its own specific options: @table @option @item h264_vaapi @@ -2603,8 +2932,6 @@ Size / quality tradeoff: higher values are smaller / worse quality. @option{level} sets the value of @emph{level_idc}. @table @option -@item low_power -Use low-power encoding mode. @item coder Set entropy encoder (default is @emph{cabac}). Possible values: @@ -2617,21 +2944,70 @@ Use CABAC. @item cavlc Use CAVLC. @end table + +@item aud +Include access unit delimiters in the stream (not included by default). + +@item sei +Set SEI message types to include. +Some combination of the following values: +@table @samp +@item identifier +Include a @emph{user_data_unregistered} message containing information about +the encoder. +@item timing +Include picture timing parameters (@emph{buffering_period} and +@emph{pic_timing} messages). +@item recovery_point +Include recovery points where appropriate (@emph{recovery_point} messages). +@end table + @end table @item hevc_vaapi @option{profile} and @option{level} set the values of @emph{general_profile_idc} and @emph{general_level_idc} respectively. +@table @option +@item aud +Include access unit delimiters in the stream (not included by default). + +@item tier +Set @emph{general_tier_flag}. This may affect the level chosen for the stream +if it is not explicitly specified. + +@item sei +Set SEI message types to include. +Some combination of the following values: +@table @samp +@item hdr +Include HDR metadata if the input frames have it +(@emph{mastering_display_colour_volume} and @emph{content_light_level} +messages). +@end table + +@end table + @item mjpeg_vaapi -Always encodes using the standard quantisation and huffman tables - -@option{global_quality} scales the standard quantisation table (range 1-100). +Only baseline DCT encoding is supported. The encoder always uses the standard +quantisation and huffman tables - @option{global_quality} scales the standard +quantisation table (range 1-100). + +For YUV, 4:2:0, 4:2:2 and 4:4:4 subsampling modes are supported. RGB is also +supported, and will create an RGB JPEG. + +@table @option +@item jfif +Include JFIF header in each frame (not included by default). +@item huffman +Include standard huffman tables (on by default). Turning this off will save +a few hundred bytes in each output frame, but may lose compatibility with some +JPEG decoders which don't fully handle MJPEG. +@end table @item mpeg2_vaapi @option{profile} and @option{level} set the value of @emph{profile_and_level_indication}. -No rate control is supported. - @item vp8_vaapi B-frames are not supported. diff --git a/doc/examples/Makefile b/doc/examples/Makefile index 928ff306b..2935424e5 100644 --- a/doc/examples/Makefile +++ b/doc/examples/Makefile @@ -37,7 +37,7 @@ $(EXAMPLES_G): %$(PROGSSUF)_g$(EXESUF): %.o examples: $(EXAMPLES) $(EXAMPLES:%$(PROGSSUF)$(EXESUF)=%.o): | doc/examples -OBJDIRS += doc/examples +OUTDIRS += doc/examples DOXY_INPUT += $(EXAMPLES:%$(PROGSSUF)$(EXESUF)=%.c) diff --git a/doc/examples/avio_reading.c b/doc/examples/avio_reading.c index cbfeb174b..36ee02afa 100644 --- a/doc/examples/avio_reading.c +++ b/doc/examples/avio_reading.c @@ -117,11 +117,12 @@ int main(int argc, char *argv[]) end: avformat_close_input(&fmt_ctx); + /* note: the internal buffer could have changed, and be != avio_ctx_buffer */ - if (avio_ctx) { + if (avio_ctx) av_freep(&avio_ctx->buffer); - av_freep(&avio_ctx); - } + avio_context_free(&avio_ctx); + av_file_unmap(buffer, buffer_size); if (ret < 0) { diff --git a/doc/examples/filtering_audio.c b/doc/examples/filtering_audio.c index b109dbcb9..834b137cd 100644 --- a/doc/examples/filtering_audio.c +++ b/doc/examples/filtering_audio.c @@ -74,7 +74,6 @@ static int open_input_file(const char *filename) if (!dec_ctx) return AVERROR(ENOMEM); avcodec_parameters_to_context(dec_ctx, fmt_ctx->streams[audio_stream_index]->codecpar); - av_opt_set_int(dec_ctx, "refcounted_frames", 1, 0); /* init the audio decoder */ if ((ret = avcodec_open2(dec_ctx, dec, NULL)) < 0) { diff --git a/doc/examples/filtering_video.c b/doc/examples/filtering_video.c index ed4e7bbd8..105a200d9 100644 --- a/doc/examples/filtering_video.c +++ b/doc/examples/filtering_video.c @@ -29,6 +29,8 @@ #define _XOPEN_SOURCE 600 /* for usleep */ #include +#include +#include #include #include @@ -77,7 +79,6 @@ static int open_input_file(const char *filename) if (!dec_ctx) return AVERROR(ENOMEM); avcodec_parameters_to_context(dec_ctx, fmt_ctx->streams[video_stream_index]->codecpar); - av_opt_set_int(dec_ctx, "refcounted_frames", 1, 0); /* init the video decoder */ if ((ret = avcodec_open2(dec_ctx, dec, NULL)) < 0) { @@ -210,18 +211,21 @@ int main(int argc, char **argv) { int ret; AVPacket packet; - AVFrame *frame = av_frame_alloc(); - AVFrame *filt_frame = av_frame_alloc(); + AVFrame *frame; + AVFrame *filt_frame; - if (!frame || !filt_frame) { - perror("Could not allocate frame"); - exit(1); - } if (argc != 2) { fprintf(stderr, "Usage: %s file\n", argv[0]); exit(1); } + frame = av_frame_alloc(); + filt_frame = av_frame_alloc(); + if (!frame || !filt_frame) { + perror("Could not allocate frame"); + exit(1); + } + if ((ret = open_input_file(argv[1])) < 0) goto end; if ((ret = init_filters(filter_descr)) < 0) @@ -248,27 +252,25 @@ int main(int argc, char **argv) goto end; } - if (ret >= 0) { - frame->pts = frame->best_effort_timestamp; + frame->pts = frame->best_effort_timestamp; - /* push the decoded frame into the filtergraph */ - if (av_buffersrc_add_frame_flags(buffersrc_ctx, frame, AV_BUFFERSRC_FLAG_KEEP_REF) < 0) { - av_log(NULL, AV_LOG_ERROR, "Error while feeding the filtergraph\n"); - break; - } - - /* pull filtered frames from the filtergraph */ - while (1) { - ret = av_buffersink_get_frame(buffersink_ctx, filt_frame); - if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) - break; - if (ret < 0) - goto end; - display_frame(filt_frame, buffersink_ctx->inputs[0]->time_base); - av_frame_unref(filt_frame); - } - av_frame_unref(frame); + /* push the decoded frame into the filtergraph */ + if (av_buffersrc_add_frame_flags(buffersrc_ctx, frame, AV_BUFFERSRC_FLAG_KEEP_REF) < 0) { + av_log(NULL, AV_LOG_ERROR, "Error while feeding the filtergraph\n"); + break; } + + /* pull filtered frames from the filtergraph */ + while (1) { + ret = av_buffersink_get_frame(buffersink_ctx, filt_frame); + if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) + break; + if (ret < 0) + goto end; + display_frame(filt_frame, buffersink_ctx->inputs[0]->time_base); + av_frame_unref(filt_frame); + } + av_frame_unref(frame); } } av_packet_unref(&packet); diff --git a/doc/examples/hw_decode.c b/doc/examples/hw_decode.c index 77ae8df35..f3286f472 100644 --- a/doc/examples/hw_decode.c +++ b/doc/examples/hw_decode.c @@ -4,21 +4,23 @@ * * HW Acceleration API (video decoding) decode sample * - * This file is part of FFmpeg. + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with FFmpeg; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. */ /** @@ -211,7 +213,6 @@ int main(int argc, char *argv[]) return -1; decoder_ctx->get_format = get_hw_format; - av_opt_set_int(decoder_ctx, "refcounted_frames", 1, 0); if (hw_decoder_init(decoder_ctx, type) < 0) return -1; diff --git a/doc/examples/metadata.c b/doc/examples/metadata.c index e330d077a..b6cfa6bd3 100644 --- a/doc/examples/metadata.c +++ b/doc/examples/metadata.c @@ -47,6 +47,11 @@ int main (int argc, char **argv) if ((ret = avformat_open_input(&fmt_ctx, argv[1], NULL, NULL))) return ret; + if ((ret = avformat_find_stream_info(fmt_ctx, NULL)) < 0) { + av_log(NULL, AV_LOG_ERROR, "Cannot find stream information\n"); + return ret; + } + while ((tag = av_dict_get(fmt_ctx->metadata, "", tag, AV_DICT_IGNORE_SUFFIX))) printf("%s=%s\n", tag->key, tag->value); diff --git a/doc/examples/vaapi_encode.c b/doc/examples/vaapi_encode.c index 3bdc62bef..98fd5d3b5 100644 --- a/doc/examples/vaapi_encode.c +++ b/doc/examples/vaapi_encode.c @@ -1,21 +1,23 @@ /* * Video Acceleration API (video encoding) encode sample * - * This file is part of FFmpeg. + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with FFmpeg; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. */ /** diff --git a/doc/examples/vaapi_transcode.c b/doc/examples/vaapi_transcode.c index ff455c093..279d20f63 100644 --- a/doc/examples/vaapi_transcode.c +++ b/doc/examples/vaapi_transcode.c @@ -1,21 +1,23 @@ /* * Video Acceleration API (video transcoding) transcode sample * - * This file is part of FFmpeg. + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with FFmpeg; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. */ /** diff --git a/doc/faq.texi b/doc/faq.texi index 73624c647..8b165eb43 100644 --- a/doc/faq.texi +++ b/doc/faq.texi @@ -76,7 +76,7 @@ the gcc developers. Note that we will not add workarounds for gcc bugs. Also note that (some of) the gcc developers believe this is not a bug or not a bug they should fix: -@url{http://gcc.gnu.org/bugzilla/show_bug.cgi?id=11203}. +@url{https://gcc.gnu.org/bugzilla/show_bug.cgi?id=11203}. Then again, some of them do not know the difference between an undecidable problem and an NP-hard problem... @@ -257,13 +257,13 @@ default. @section Which are good parameters for encoding high quality MPEG-4? '-mbd rd -flags +mv4+aic -trellis 2 -cmp 2 -subcmp 2 -g 300 -pass 1/2', -things to try: '-bf 2', '-flags qprd', '-flags mv0', '-flags skiprd'. +things to try: '-bf 2', '-mpv_flags qp_rd', '-mpv_flags mv0', '-mpv_flags skip_rd'. @section Which are good parameters for encoding high quality MPEG-1/MPEG-2? '-mbd rd -trellis 2 -cmp 2 -subcmp 2 -g 100 -pass 1/2' but beware the '-g 100' might cause problems with some decoders. -Things to try: '-bf 2', '-flags qprd', '-flags mv0', '-flags skiprd. +Things to try: '-bf 2', '-mpv_flags qp_rd', '-mpv_flags mv0', '-mpv_flags skip_rd'. @section Interlaced video looks very bad when encoded with ffmpeg, what is wrong? @@ -516,7 +516,7 @@ in the ffmpeg invocation. This is effective whether you run ffmpeg in a shell or invoke ffmpeg in its own process via an operating system API. As an alternative, when you are running ffmpeg in a shell, you can redirect -standard input to @code{/dev/null} (on Linux and Mac OS) +standard input to @code{/dev/null} (on Linux and macOS) or @code{NUL} (on Windows). You can do this redirect either on the ffmpeg invocation, or from a shell script which calls ffmpeg. @@ -526,7 +526,7 @@ For example: ffmpeg -nostdin -i INPUT OUTPUT @end example -or (on Linux, Mac OS, and other UNIX-like shells): +or (on Linux, macOS, and other UNIX-like shells): @example ffmpeg -i INPUT OUTPUT = 2.0.5, Windows SDL >= 2.0.6. @item -volume Set the startup volume. 0 means silence, 100 means no volume reduction or amplification. Negative values are treated as 0, values above 100 are treated @@ -72,6 +76,10 @@ as 100. Force format. @item -window_title @var{title} Set window title (default is the input filename). +@item -left @var{title} +Set the x position for the left of the window (default is a centered window). +@item -top @var{title} +Set the y position for the top of the window (default is a centered window). @item -loop @var{number} Loops movie playback times. 0 means forever. @item -showmode @var{mode} @@ -189,6 +197,12 @@ input as soon as possible. Enabled by default for realtime streams, where data may be dropped if not read in time. Use this option to enable infinite buffers for all inputs, use @option{-noinfbuf} to disable it. +@item -filter_threads @var{nb_threads} +Defines how many threads are used to process a filter pipeline. Each pipeline +will produce a thread pool with this many threads available for parallel +processing. The default is 0 which means that the thread count will be +determined by the number of available CPUs. + @end table @section While playing diff --git a/doc/ffprobe.texi b/doc/ffprobe.texi index 4e9f184a1..28371cee5 100644 --- a/doc/ffprobe.texi +++ b/doc/ffprobe.texi @@ -425,7 +425,7 @@ The @code{csv} writer is equivalent to @code{compact}, but supports different defaults. Each section is printed on a single line. -If no option is specifid, the output has the form: +If no option is specified, the output has the form: @example section|key1=val1| ... |keyN=valN @end example @@ -584,14 +584,14 @@ value is 0. This is required for generating an XML file which can be validated through an XSD file. -@item xsd_compliant, x +@item xsd_strict, x If set to 1 perform more checks for ensuring that the output is XSD compliant. Default value is 0. This option automatically sets @option{fully_qualified} to 1. @end table For more information about the XML format, see -@url{http://www.w3.org/XML/}. +@url{https://www.w3.org/XML/}. @c man end WRITERS @chapter Timecode diff --git a/doc/ffprobe.xsd b/doc/ffprobe.xsd index 3e58da0f4..97dc67def 100644 --- a/doc/ffprobe.xsd +++ b/doc/ffprobe.xsd @@ -147,11 +147,25 @@ + + + + + + + + + + + + + + diff --git a/doc/fftools-common-opts.texi b/doc/fftools-common-opts.texi index 84705c0b6..1234de850 100644 --- a/doc/fftools-common-opts.texi +++ b/doc/fftools-common-opts.texi @@ -34,27 +34,24 @@ Possible forms of stream specifiers are: @table @option @item @var{stream_index} Matches the stream with this index. E.g. @code{-threads:1 4} would set the -thread count for the second stream to 4. -@item @var{stream_type}[:@var{stream_index}] +thread count for the second stream to 4. If @var{stream_index} is used as an +additional stream specifier (see below), then it selects stream number +@var{stream_index} from the matching streams. Stream numbering is based on the +order of the streams as detected by libavformat except when a program ID is +also specified. In this case it is based on the ordering of the streams in the +program. +@item @var{stream_type}[:@var{additional_stream_specifier}] @var{stream_type} is one of following: 'v' or 'V' for video, 'a' for audio, 's' for subtitle, 'd' for data, and 't' for attachments. 'v' matches all video streams, 'V' only matches video streams which are not attached pictures, video -thumbnails or cover arts. If @var{stream_index} is given, then it matches -stream number @var{stream_index} of this type. Otherwise, it matches all -streams of this type. -@item p:@var{program_id}[:@var{stream_index}] or p:@var{program_id}[:@var{stream_type}[:@var{stream_index}]] or -p:@var{program_id}:m:@var{key}[:@var{value}] -In first version, if @var{stream_index} is given, then it matches the stream with number @var{stream_index} -in the program with the id @var{program_id}. Otherwise, it matches all streams in the -program. In the second version, @var{stream_type} is one of following: 'v' for video, 'a' for audio, 's' -for subtitle, 'd' for data. If @var{stream_index} is also given, then it matches -stream number @var{stream_index} of this type in the program with the id @var{program_id}. -Otherwise, if only @var{stream_type} is given, it matches all -streams of this type in the program with the id @var{program_id}. -In the third version matches streams in the program with the id @var{program_id} with the metadata -tag @var{key} having the specified value. If -@var{value} is not given, matches streams that contain the given tag with any -value. +thumbnails or cover arts. If @var{additional_stream_specifier} is used, then +it matches streams which both have this type and match the +@var{additional_stream_specifier}. Otherwise, it matches all streams of the +specified type. +@item p:@var{program_id}[:@var{additional_stream_specifier}] +Matches streams which are in the program with the id @var{program_id}. If +@var{additional_stream_specifier} is used, then it matches streams which both +are part of the program and match the @var{additional_stream_specifier}. @item #@var{stream_id} or i:@var{stream_id} Match the stream by stream id (e.g. PID in MPEG-TS container). @@ -112,6 +109,10 @@ Print detailed information about the muxer named @var{muxer_name}. Use the @item filter=@var{filter_name} Print detailed information about the filter name @var{filter_name}. Use the @option{-filters} option to get a list of all filters. + +@item bsf=@var{bitstream_filter_name} +Print detailed information about the bitstream filter name @var{bitstream_filter_name}. +Use the @option{-bsfs} option to get a list of all bitstream filters. @end table @item -version @@ -245,7 +246,7 @@ Dump full command line and console output to a file named @code{@var{program}-@var{YYYYMMDD}-@var{HHMMSS}.log} in the current directory. This file can be useful for bug reports. -It also implies @code{-loglevel verbose}. +It also implies @code{-loglevel debug}. Setting the environment variable @env{FFREPORT} to any value has the same effect. If the value is a ':'-separated key=value sequence, these @@ -371,7 +372,15 @@ ffmpeg -i input.flac -id3v2_version 3 out.mp3 @end example All codec AVOptions are per-stream, and thus a stream specifier -should be attached to them. +should be attached to them: +@example +ffmpeg -i multichannel.mxf -map 0:v:0 -map 0:a:0 -map 0:a:0 -c:a:0 ac3 -b:a:0 640k -ac:a:1 2 -c:a:1 aac -b:2 128k out.mp4 +@end example + +In the above example, a multichannel audio stream is mapped twice for output. +The first instance is encoded with codec ac3 and bitrate 640k. +The second instance is downmixed to 2 channels and encoded with codec aac. A bitrate of 128k is specified for it using +absolute index of the output stream. Note: the @option{-nooption} syntax cannot be used for boolean AVOptions, use @option{-option 0}/@option{-option 1}. diff --git a/doc/filters.texi b/doc/filters.texi index f267d26b9..604e44d56 100644 --- a/doc/filters.texi +++ b/doc/filters.texi @@ -390,6 +390,10 @@ The filter accepts the following options: @item level_in Set input gain. Default is 1. Range is between 0.015625 and 64. +@item mode +Set mode of compressor operation. Can be @code{upward} or @code{downward}. +Default is @code{downward}. + @item threshold If a signal of stream rises above this level it will affect the gain reduction. @@ -431,7 +435,7 @@ Range is between 0 and 1. @end table @section acontrast -Simple audio dynamic range commpression/expansion filter. +Simple audio dynamic range compression/expansion filter. The filter accepts the following options: @@ -493,6 +497,23 @@ ffmpeg -i first.flac -i second.flac -filter_complex acrossfade=d=10:o=0:c1=exp:c @end example @end itemize +@section acrossover +Split audio stream into several bands. + +This filter splits audio stream into two or more frequency ranges. +Summing all streams back will give flat output. + +The filter accepts the following options: + +@table @option +@item split +Set split frequencies. Those must be positive and increasing. + +@item order +Set filter order, can be @var{2nd}, @var{4th} or @var{8th}. +Default is @var{4th}. +@end table + @section acrusher Reduce audio bit resolution. @@ -551,6 +572,107 @@ Set LFO range. Set LFO rate. @end table +@section acue + +Delay audio filtering until a given wallclock timestamp. See the @ref{cue} +filter. + +@section adeclick +Remove impulsive noise from input audio. + +Samples detected as impulsive noise are replaced by interpolated samples using +autoregressive modelling. + +@table @option +@item w +Set window size, in milliseconds. Allowed range is from @code{10} to +@code{100}. Default value is @code{55} milliseconds. +This sets size of window which will be processed at once. + +@item o +Set window overlap, in percentage of window size. Allowed range is from +@code{50} to @code{95}. Default value is @code{75} percent. +Setting this to a very high value increases impulsive noise removal but makes +whole process much slower. + +@item a +Set autoregression order, in percentage of window size. Allowed range is from +@code{0} to @code{25}. Default value is @code{2} percent. This option also +controls quality of interpolated samples using neighbour good samples. + +@item t +Set threshold value. Allowed range is from @code{1} to @code{100}. +Default value is @code{2}. +This controls the strength of impulsive noise which is going to be removed. +The lower value, the more samples will be detected as impulsive noise. + +@item b +Set burst fusion, in percentage of window size. Allowed range is @code{0} to +@code{10}. Default value is @code{2}. +If any two samples detected as noise are spaced less than this value then any +sample between those two samples will be also detected as noise. + +@item m +Set overlap method. + +It accepts the following values: +@table @option +@item a +Select overlap-add method. Even not interpolated samples are slightly +changed with this method. + +@item s +Select overlap-save method. Not interpolated samples remain unchanged. +@end table + +Default value is @code{a}. +@end table + +@section adeclip +Remove clipped samples from input audio. + +Samples detected as clipped are replaced by interpolated samples using +autoregressive modelling. + +@table @option +@item w +Set window size, in milliseconds. Allowed range is from @code{10} to @code{100}. +Default value is @code{55} milliseconds. +This sets size of window which will be processed at once. + +@item o +Set window overlap, in percentage of window size. Allowed range is from @code{50} +to @code{95}. Default value is @code{75} percent. + +@item a +Set autoregression order, in percentage of window size. Allowed range is from +@code{0} to @code{25}. Default value is @code{8} percent. This option also controls +quality of interpolated samples using neighbour good samples. + +@item t +Set threshold value. Allowed range is from @code{1} to @code{100}. +Default value is @code{10}. Higher values make clip detection less aggressive. + +@item n +Set size of histogram used to detect clips. Allowed range is from @code{100} to @code{9999}. +Default value is @code{1000}. Higher values make clip detection less aggressive. + +@item m +Set overlap method. + +It accepts the following values: +@table @option +@item a +Select overlap-add method. Even not interpolated samples are slightly changed +with this method. + +@item s +Select overlap-save method. Not interpolated samples remain unchanged. +@end table + +Default value is @code{a}. +@end table + @section adelay Delay one or more audio channels. @@ -565,6 +687,7 @@ Set list of delays in milliseconds for each channel separated by '|'. Unused delays will be silently ignored. If number of given delays is smaller than number of channels all remaining channels will not be delayed. If you want to delay exact number of samples, append 'S' to number. +If you want instead to delay in seconds, append 's' to number. @end table @subsection Examples @@ -585,6 +708,12 @@ adelay=0|500S|700S @end example @end itemize +@section aderivative, aintegral + +Compute derivative/integral of audio stream. + +Applying both filters one after another produces original audio. + @section aecho Apply echoing to the input audio. @@ -831,6 +960,10 @@ select inverted half of sine wave select double-exponential seat @item desi select double-exponential sigmoid +@item losi +select logistic sigmoid +@item nofade +no fade applied @end table @end table @@ -850,23 +983,113 @@ afade=t=out:st=875:d=25 @end example @end itemize +@section afftdn +Denoise audio samples with FFT. + +A description of the accepted parameters follows. + +@table @option +@item nr +Set the noise reduction in dB, allowed range is 0.01 to 97. +Default value is 12 dB. + +@item nf +Set the noise floor in dB, allowed range is -80 to -20. +Default value is -50 dB. + +@item nt +Set the noise type. + +It accepts the following values: +@table @option +@item w +Select white noise. + +@item v +Select vinyl noise. + +@item s +Select shellac noise. + +@item c +Select custom noise, defined in @code{bn} option. + +Default value is white noise. +@end table + +@item bn +Set custom band noise for every one of 15 bands. +Bands are separated by ' ' or '|'. + +@item rf +Set the residual floor in dB, allowed range is -80 to -20. +Default value is -38 dB. + +@item tn +Enable noise tracking. By default is disabled. +With this enabled, noise floor is automatically adjusted. + +@item tr +Enable residual tracking. By default is disabled. + +@item om +Set the output mode. + +It accepts the following values: +@table @option +@item i +Pass input unchanged. + +@item o +Pass noise filtered out. + +@item n +Pass only noise. + +Default value is @var{o}. +@end table +@end table + +@subsection Commands + +This filter supports the following commands: +@table @option +@item sample_noise, sn +Start or stop measuring noise profile. +Syntax for the command is : "start" or "stop" string. +After measuring noise profile is stopped it will be +automatically applied in filtering. + +@item noise_reduction, nr +Change noise reduction. Argument is single float number. +Syntax for the command is : "@var{noise_reduction}" + +@item noise_floor, nf +Change noise floor. Argument is single float number. +Syntax for the command is : "@var{noise_floor}" + +@item output_mode, om +Change output mode operation. +Syntax for the command is : "i", "o" or "n" string. +@end table + @section afftfilt Apply arbitrary expressions to samples in frequency domain. @table @option @item real Set frequency domain real expression for each separate channel separated -by '|'. Default is "1". +by '|'. Default is "re". If the number of input channels is greater than the number of expressions, the last specified expression is used for the remaining output channels. @item imag Set frequency domain imaginary expression for each separate channel -separated by '|'. If not set, @var{real} option is used. +separated by '|'. Default is "im". Each expression in @var{real} and @var{imag} can contain the following -constants: +constants and functions: @table @option @item sr @@ -886,28 +1109,23 @@ number of channels @item pts current frame pts + +@item re +current real part of frequency bin of current channel + +@item im +current imaginary part of frequency bin of current channel + +@item real(b, ch) +Return the value of real part of frequency bin at location (@var{bin},@var{channel}) + +@item imag(b, ch) +Return the value of imaginary part of frequency bin at location (@var{bin},@var{channel}) @end table @item win_size -Set window size. - -It accepts the following values: -@table @samp -@item w16 -@item w32 -@item w64 -@item w128 -@item w256 -@item w512 -@item w1024 -@item w2048 -@item w4096 -@item w8192 -@item w16384 -@item w32768 -@item w65536 -@end table -Default is @code{w4096} +Set window size. Allowed range is from 16 to 131072. +Default is @code{4096} @item win_func Set window function. Default is @code{hann}. @@ -923,7 +1141,7 @@ window function will be picked. Default is @code{0.75}. @item Leave almost only low frequencies in audio: @example -afftfilt="1-clip((b/nb)*b,0,1)" +afftfilt="'real=re * (1-clip((b/nb)*b,0,1))':imag='im * (1-clip((b/nb)*b,0,1))'" @end example @end itemize @@ -933,11 +1151,11 @@ afftfilt="1-clip((b/nb)*b,0,1)" Apply an arbitrary Frequency Impulse Response filter. This filter is designed for applying long FIR filters, -up to 30 seconds long. +up to 60 seconds long. It can be used as component for digital crossover filters, room equalization, cross talk cancellation, wavefield synthesis, -auralization, ambiophonics and ambisonics. +auralization, ambiophonics, ambisonics and spatialization. This filter uses second stream as FIR coefficients. If second stream holds single channel, it will be used @@ -957,8 +1175,60 @@ Set wet gain. This sets final output gain. @item length Set Impulse Response filter length. Default is 1, which means whole IR is processed. -@item again +@item gtype Enable applying gain measured from power of IR. + +Set which approach to use for auto gain measurement. + +@table @option +@item none +Do not apply any gain. + +@item peak +select peak gain, very conservative approach. This is default value. + +@item dc +select DC gain, limited application. + +@item gn +select gain to noise approach, this is most popular one. +@end table + +@item irgain +Set gain to be applied to IR coefficients before filtering. +Allowed range is 0 to 1. This gain is applied after any gain applied with @var{gtype} option. + +@item irfmt +Set format of IR stream. Can be @code{mono} or @code{input}. +Default is @code{input}. + +@item maxir +Set max allowed Impulse Response filter duration in seconds. Default is 30 seconds. +Allowed range is 0.1 to 60 seconds. + +@item response +Show IR frequency response, magnitude(magenta), phase(green) and group delay(yellow) in additional video stream. +By default it is disabled. + +@item channel +Set for which IR channel to display frequency response. By default is first channel +displayed. This option is used only when @var{response} is enabled. + +@item size +Set video stream size. This option is used only when @var{response} is enabled. + +@item rate +Set video stream frame rate. This option is used only when @var{response} is enabled. + +@item minp +Set minimal partition size used for convolution. Default is @var{8192}. +Allowed range is from @var{8} to @var{32768}. +Lower values decreases latency at cost of higher CPU usage. + +@item maxp +Set maximal partition size used for convolution. Default is @var{8192}. +Allowed range is from @var{8} to @var{32768}. +Lower values may increase CPU usage. @end table @subsection Examples @@ -1021,9 +1291,16 @@ Shorter signals than the chosen attack time will be left untouched. Set input level before filtering. Default is 1. Allowed range is from 0.015625 to 64. +@item mode +Set the mode of operation. Can be @code{upward} or @code{downward}. +Default is @code{downward}. If set to @code{upward} mode, higher parts of signal +will be amplified, expanding dynamic range in upward direction. +Otherwise, in case of @code{downward} lower parts of signal will be reduced. + @item range Set the level of gain reduction when the signal is below the threshold. Default is 0.06125. Allowed range is from 0 to 1. +Setting this to 0 disables reduction and then filter behaves like expander. @item threshold If a signal rises above this level the gain reduction is released. @@ -1099,7 +1376,7 @@ Z-plane zeros/poles, polar degrees @item r Set kind of processing. -Can be @code{d} - direct or @code{s} - serial cascading. Defauls is @code{s}. +Can be @code{d} - direct or @code{s} - serial cascading. Default is @code{s}. @item e Set filtering precision. @@ -1115,6 +1392,20 @@ single-precision floating-point 16-bit integers @end table +@item mix +How much to use filtered signal in output. Default is 1. +Range is between 0 and 1. + +@item response +Show IR frequency response, magnitude(magenta), phase(green) and group delay(yellow) in additional video stream. +By default it is disabled. + +@item channel +Set for which IR channel to display frequency response. By default is first channel +displayed. This option is used only when @var{response} is enabled. + +@item size +Set video stream size. This option is used only when @var{response} is enabled. @end table Coefficients in @code{tf} format are separated by spaces and are in ascending @@ -1132,7 +1423,7 @@ used for all remaining channels. @itemize @item -Apply 2 pole elliptic notch at arround 5000Hz for 48000 Hz sample rate: +Apply 2 pole elliptic notch at around 5000Hz for 48000 Hz sample rate: @example aiir=k=1:z=7.957584807809675810E-1 -2.575128568908332300 3.674839853930788710 -2.57512875289799137 7.957586296317130880E-1:p=1 -2.86950072432325953 3.63022088054647218 -2.28075678147272232 6.361362326477423500E-1:f=tf:r=d @end example @@ -1219,6 +1510,10 @@ kHz @item width, w Specify the band-width of a filter in width_type units. +@item mix, m +How much to use filtered signal in output. Default is 1. +Range is between 0 and 1. + @item channels, c Specify which channels to filter, by default all available are filtered. @end table @@ -1238,6 +1533,10 @@ Syntax for the command is : "@var{width_type}" @item width, w Change allpass width. Syntax for the command is : "@var{width}" + +@item mix, m +Change allpass mix. +Syntax for the command is : "@var{mix}" @end table @section aloop @@ -1356,6 +1655,15 @@ Specify weight of each input audio stream as sequence. Each weight is separated by space. By default all inputs have same weight. @end table +@section amultiply + +Multiply first audio stream with second audio stream and store result +in output audio stream. Multiplication is done by multiplying each +sample from first stream with sample at same position from second stream. + +With this element-wise multiplication one can create amplitude fades and +amplitude modulations. + @section anequalizer High-order parametric multiband equalizer for each channel. @@ -1450,6 +1758,62 @@ Full filter invocation with asendcmd may look like this: asendcmd=c='4.0 anequalizer change 0|f=200|w=50|g=1',anequalizer=... @end table +@section anlmdn + +Reduce broadband noise in audio samples using Non-Local Means algorithm. + +Each sample is adjusted by looking for other samples with similar contexts. This +context similarity is defined by comparing their surrounding patches of size +@option{p}. Patches are searched in an area of @option{r} around the sample. + +The filter accepts the following options. + +@table @option +@item s +Set denoising strength. Allowed range is from 0.00001 to 10. Default value is 0.00001. + +@item p +Set patch radius duration. Allowed range is from 1 to 100 milliseconds. +Default value is 2 milliseconds. + +@item r +Set research radius duration. Allowed range is from 2 to 300 milliseconds. +Default value is 6 milliseconds. + +@item o +Set the output mode. + +It accepts the following values: +@table @option +@item i +Pass input unchanged. + +@item o +Pass noise filtered out. + +@item n +Pass only noise. + +Default value is @var{o}. +@end table + +@item m +Set smooth factor. Default value is @var{11}. Allowed range is from @var{1} to @var{15}. +@end table + +@subsection Commands + +This filter supports the following commands: +@table @option +@item s +Change denoise strength. Argument is single float number. +Syntax for the command is : "@var{s}" + +@item o +Change output mode. +Syntax for the command is : "i", "o" or "n" string. +@end table + @section anull Pass the audio source unchanged to the output. @@ -1477,11 +1841,23 @@ Set the minimum total number of samples in the output audio stream. If the value is longer than the input audio length, silence is added to the end, until the value is reached. This option is mutually exclusive with @option{pad_len}. + +@item pad_dur +Specify the duration of samples of silence to add. See +@ref{time duration syntax,,the Time duration section in the ffmpeg-utils(1) manual,ffmpeg-utils} +for the accepted syntax. Used only if set to non-zero value. + +@item whole_dur +Specify the minimum total duration in the output audio stream. See +@ref{time duration syntax,,the Time duration section in the ffmpeg-utils(1) manual,ffmpeg-utils} +for the accepted syntax. Used only if set to non-zero value. If the value is longer than +the input audio length, silence is added to the end, until the value is reached. +This option is mutually exclusive with @option{pad_dur} @end table -If neither the @option{pad_len} nor the @option{whole_len} option is -set, the filter will add silence to the end of the input stream -indefinitely. +If neither the @option{pad_len} nor the @option{whole_len} nor @option{pad_dur} +nor @option{whole_dur} option is set, the filter will add silence to the end of +the input stream indefinitely. @subsection Examples @@ -1739,6 +2115,68 @@ audio, the data is treated as if all the planes were concatenated. A list of Adler-32 checksums for each data plane. @end table +@section asoftclip +Apply audio soft clipping. + +Soft clipping is a type of distortion effect where the amplitude of a signal is saturated +along a smooth curve, rather than the abrupt shape of hard-clipping. + +This filter accepts the following options: + +@table @option +@item type +Set type of soft-clipping. + +It accepts the following values: +@table @option +@item tanh +@item atan +@item cubic +@item exp +@item alg +@item quintic +@item sin +@end table + +@item param +Set additional parameter which controls sigmoid function. +@end table + +@section asr +Automatic Speech Recognition + +This filter uses PocketSphinx for speech recognition. To enable +compilation of this filter, you need to configure FFmpeg with +@code{--enable-pocketsphinx}. + +It accepts the following options: + +@table @option +@item rate +Set sampling rate of input audio. Defaults is @code{16000}. +This need to match speech models, otherwise one will get poor results. + +@item hmm +Set dictionary containing acoustic model files. + +@item dict +Set pronunciation dictionary. + +@item lm +Set language model file. + +@item lmctl +Set language model set. + +@item lmname +Set which language model to use. + +@item logfn +Set output for log messages. +@end table + +The filter exports recognized speech as the frame metadata @code{lavfi.asr.text}. + @anchor{astats} @section astats @@ -1774,6 +2212,11 @@ Flat_factor Peak_count Bit_depth Dynamic_range +Zero_crossings +Zero_crossings_rate +Number_of_NaNs +Number_of_Infs +Number_of_denormals and for Overall: DC_offset @@ -1791,6 +2234,9 @@ Flat_factor Peak_count Bit_depth Number_of_samples +Number_of_NaNs +Number_of_Infs +Number_of_denormals For example full key look like this @code{lavfi.astats.1.DC_offset} or this @code{lavfi.astats.Overall.Peak_count}. @@ -1800,6 +2246,17 @@ For description what each key means read below. @item reset Set number of frame after which stats are going to be recalculated. Default is disabled. + +@item measure_perchannel +Select the entries which need to be measured per channel. The metadata keys can +be used as flags, default is @option{all} which measures everything. +@option{none} disables all per channel measurement. + +@item measure_overall +Select the entries which need to be measured overall. The metadata keys can +be used as flags, default is @option{all} which measures everything. +@option{none} disables all overall measurement. + @end table A description of each shown parameter follows: @@ -1851,6 +2308,12 @@ Overall bit depth of audio. Number of bits used for each sample. @item Dynamic range Measured dynamic range of audio in dB. + +@item Zero crossings +Number of points where the waveform crosses the zero level axis. + +@item Zero crossings rate +Rate of Zero crossings and number of audio samples. @end table @section atempo @@ -1859,7 +2322,12 @@ Adjust audio tempo. The filter accepts exactly one parameter, the audio tempo. If not specified then the filter will assume nominal 1.0 tempo. Tempo must -be in the [0.5, 2.0] range. +be in the [0.5, 100.0] range. + +Note that tempo greater than 2 will skip some samples rather than +blend them in. If for any reason this is a concern it is always +possible to daisy-chain several instances of atempo to achieve the +desired product tempo. @subsection Examples @@ -1871,9 +2339,15 @@ atempo=0.8 @end example @item -To speed up audio to 125% tempo: +To speed up audio to 300% tempo: @example -atempo=1.25 +atempo=3 +@end example + +@item +To speed up audio to 300% tempo by daisy-chaining two atempo instances: +@example +atempo=sqrt(3),atempo=sqrt(3) @end example @end itemize @@ -1981,6 +2455,10 @@ kHz @item width, w Specify the band-width of a filter in width_type units. +@item mix, m +How much to use filtered signal in output. Default is 1. +Range is between 0 and 1. + @item channels, c Specify which channels to filter, by default all available are filtered. @end table @@ -2000,6 +2478,10 @@ Syntax for the command is : "@var{width_type}" @item width, w Change bandpass width. Syntax for the command is : "@var{width}" + +@item mix, m +Change bandpass mix. +Syntax for the command is : "@var{mix}" @end table @section bandreject @@ -2032,6 +2514,10 @@ kHz @item width, w Specify the band-width of a filter in width_type units. +@item mix, m +How much to use filtered signal in output. Default is 1. +Range is between 0 and 1. + @item channels, c Specify which channels to filter, by default all available are filtered. @end table @@ -2051,9 +2537,13 @@ Syntax for the command is : "@var{width_type}" @item width, w Change bandreject width. Syntax for the command is : "@var{width}" + +@item mix, m +Change bandreject mix. +Syntax for the command is : "@var{mix}" @end table -@section bass +@section bass, lowshelf Boost or cut the bass (lower) frequencies of the audio using a two-pole shelving filter with a response similar to that of a standard @@ -2090,6 +2580,10 @@ kHz @item width, w Determine how steep is the filter's shelf transition. +@item mix, m +How much to use filtered signal in output. Default is 1. +Range is between 0 and 1. + @item channels, c Specify which channels to filter, by default all available are filtered. @end table @@ -2113,6 +2607,10 @@ Syntax for the command is : "@var{width}" @item gain, g Change bass gain. Syntax for the command is : "@var{gain}" + +@item mix, m +Change bass mix. +Syntax for the command is : "@var{mix}" @end table @section biquad @@ -2135,6 +2633,10 @@ This filter supports the following commands: @item b2 Change biquad parameter. Syntax for the command is : "@var{value}" + +@item mix, m +How much to use filtered signal in output. Default is 1. +Range is between 0 and 1. @end table @section bs2b @@ -2566,6 +3068,42 @@ Optional. It should have a value much less than 1 (e.g. 0.05 or 0.02) and is used to prevent clipping. @end table +@section deesser + +Apply de-essing to the audio samples. + +@table @option +@item i +Set intensity for triggering de-essing. Allowed range is from 0 to 1. +Default is 0. + +@item m +Set amount of ducking on treble part of sound. Allowed range is from 0 to 1. +Default is 0.5. + +@item f +How much of original frequency content to keep when de-essing. Allowed range is from 0 to 1. +Default is 0.5. + +@item s +Set the output mode. + +It accepts the following values: +@table @option +@item i +Pass input unchanged. + +@item o +Pass ess filtered out. + +@item e +Pass only ess. + +Default value is @var{o}. +@end table + +@end table + @section drmeter Measure audio dynamic range. @@ -2788,6 +3326,10 @@ Specify the band-width of a filter in width_type units. Set the required gain or attenuation in dB. Beware of clipping when using a positive gain. +@item mix, m +How much to use filtered signal in output. Default is 1. +Range is between 0 and 1. + @item channels, c Specify which channels to filter, by default all available are filtered. @end table @@ -2826,6 +3368,10 @@ Syntax for the command is : "@var{width}" @item gain, g Change equalizer gain. Syntax for the command is : "@var{gain}" + +@item mix, m +Change equalizer mix. +Syntax for the command is : "@var{mix}" @end table @section extrastereo @@ -3200,7 +3746,8 @@ Full example using wav files as coefficients with amovie filters for 7.1 downmix each amovie filter use stereo file with IR coefficients as input. The files give coefficients for each position of virtual loudspeaker: @example -ffmpeg -i input.wav -lavfi-complex "amovie=azi_270_ele_0_DFC.wav[sr],amovie=azi_90_ele_0_DFC.wav[sl],amovie=azi_225_ele_0_DFC.wav[br],amovie=azi_135_ele_0_DFC.wav[bl],amovie=azi_0_ele_0_DFC.wav,asplit[fc][lfe],amovie=azi_35_ele_0_DFC.wav[fl],amovie=azi_325_ele_0_DFC.wav[fr],[a:0][fl][fr][fc][lfe][bl][br][sl][sr]headphone=FL|FR|FC|LFE|BL|BR|SL|SR" +ffmpeg -i input.wav +-filter_complex "amovie=azi_270_ele_0_DFC.wav[sr];amovie=azi_90_ele_0_DFC.wav[sl];amovie=azi_225_ele_0_DFC.wav[br];amovie=azi_135_ele_0_DFC.wav[bl];amovie=azi_0_ele_0_DFC.wav,asplit[fc][lfe];amovie=azi_35_ele_0_DFC.wav[fl];amovie=azi_325_ele_0_DFC.wav[fr];[0:a][fl][fr][fc][lfe][bl][br][sl][sr]headphone=FL|FR|FC|LFE|BL|BR|SL|SR" output.wav @end example @@ -3208,7 +3755,7 @@ output.wav Full example using wav files as coefficients with amovie filters for 7.1 downmix, but now in @var{multich} @var{hrir} format. @example -ffmpeg -i input.wav -lavfi-complex "amovie=minp.wav[hrirs],[a:0][hrirs]headphone=map=FL|FR|FC|LFE|BL|BR|SL|SR:hrir=multich" +ffmpeg -i input.wav -filter_complex "amovie=minp.wav[hrirs];[0:a][hrirs]headphone=map=FL|FR|FC|LFE|BL|BR|SL|SR:hrir=multich" output.wav @end example @end itemize @@ -3248,6 +3795,10 @@ Specify the band-width of a filter in width_type units. Applies only to double-pole filter. The default is 0.707q and gives a Butterworth response. +@item mix, m +How much to use filtered signal in output. Default is 1. +Range is between 0 and 1. + @item channels, c Specify which channels to filter, by default all available are filtered. @end table @@ -3267,6 +3818,10 @@ Syntax for the command is : "@var{width_type}" @item width, w Change highpass width. Syntax for the command is : "@var{width}" + +@item mix, m +Change highpass mix. +Syntax for the command is : "@var{mix}" @end table @section join @@ -3556,6 +4111,10 @@ Specify the band-width of a filter in width_type units. Applies only to double-pole filter. The default is 0.707q and gives a Butterworth response. +@item mix, m +How much to use filtered signal in output. Default is 1. +Range is between 0 and 1. + @item channels, c Specify which channels to filter, by default all available are filtered. @end table @@ -3584,6 +4143,10 @@ Syntax for the command is : "@var{width_type}" @item width, w Change lowpass width. Syntax for the command is : "@var{width}" + +@item mix, m +Change lowpass mix. +Syntax for the command is : "@var{mix}" @end table @section lv2 @@ -3766,6 +4329,9 @@ not meant to be used directly. @section rubberband Apply time-stretching and pitch-shifting with librubberband. +To enable compilation of this filter, you need to configure FFmpeg with +@code{--enable-librubberband}. + The filter accepts the following options: @table @option @@ -3859,6 +4425,10 @@ The filter accepts the following options: @item level_in Set input gain. Default is 1. Range is between 0.015625 and 64. +@item mode +Set mode of compressor operation. Can be @code{upward} or @code{downward}. +Default is @code{downward}. + @item threshold If a signal of second stream raises above this level it will affect the gain reduction of first stream. @@ -3935,9 +4505,16 @@ The filter accepts the following options: Set input level before filtering. Default is 1. Allowed range is from 0.015625 to 64. +@item mode +Set the mode of operation. Can be @code{upward} or @code{downward}. +Default is @code{downward}. If set to @code{upward} mode, higher parts of signal +will be amplified, expanding dynamic range in upward direction. +Otherwise, in case of @code{downward} lower parts of signal will be reduced. + @item range Set the level of gain reduction when the signal is below the threshold. Default is 0.06125. Allowed range is from 0 to 1. +Setting this to 0 disables reduction and then filter behaves like expander. @item threshold If a signal rises above this level the gain reduction is released. @@ -3991,12 +4568,15 @@ The printed times and duration are expressed in seconds. The filter accepts the following options: @table @option -@item duration, d -Set silence duration until notification (default is 2 seconds). - @item noise, n Set noise tolerance. Can be specified in dB (in case "dB" is appended to the specified value) or amplitude ratio. Default is -60dB, or 0.001. + +@item duration, d +Set silence duration until notification (default is 2 seconds). + +@item mono, m +Process each channel separately, instead of combined. By default is disabled. @end table @subsection Examples @@ -4044,6 +4624,19 @@ you may wish to increase the value to account for background noise. Can be specified in dB (in case "dB" is appended to the specified value) or amplitude ratio. Default value is @code{0}. +@item start_silence +Specify max duration of silence at beginning that will be kept after +trimming. Default is 0, which is equal to trimming all samples detected +as silence. + +@item start_mode +Specify mode of detection of silence end in start of multi-channel audio. +Can be @var{any} or @var{all}. Default is @var{any}. +With @var{any}, any sample that is detected as non-silence will cause +stopped trimming of silence. +With @var{all}, only if all channels are detected as non-silence will cause +stopped trimming of silence. + @item stop_periods Set the count for trimming silence from the end of audio. To remove silence from the middle of a file, specify a @var{stop_periods} @@ -4065,11 +4658,18 @@ the end of audio. Can be specified in dB (in case "dB" is appended to the specified value) or amplitude ratio. Default value is @code{0}. -@item leave_silence -This indicates that @var{stop_duration} length of audio should be left intact -at the beginning of each period of silence. -For example, if you want to remove long pauses between words but do not want -to remove the pauses completely. Default value is @code{0}. +@item stop_silence +Specify max duration of silence at end that will be kept after +trimming. Default is 0, which is equal to trimming all samples detected +as silence. + +@item stop_mode +Specify mode of detection of silence start in end of multi-channel audio. +Can be @var{any} or @var{all}. Default is @var{any}. +With @var{any}, any sample that is detected as non-silence will cause +stopped trimming of silence. +With @var{all}, only if all channels are detected as non-silence will cause +stopped trimming of silence. @item detection Set how is silence detected. Can be @code{rms} or @code{peak}. Second is faster @@ -4077,7 +4677,8 @@ and works better with digital silence which is exactly 0. Default value is @code{rms}. @item window -Set ratio used to calculate size of window for detecting silence. +Set duration in number of seconds used to calculate size of window in number +of samples for detecting silence. Default value is @code{0.02}. Allowed range is from @code{0} to @code{10}. @end table @@ -4089,14 +4690,14 @@ The following example shows how this filter can be used to start a recording that does not contain the delay at the start which usually occurs between pressing the record button and the start of the performance: @example -silenceremove=1:5:0.02 +silenceremove=start_periods=1:start_duration=5:start_threshold=0.02 @end example @item Trim all silence encountered from beginning to end where there is more than 1 second of silence in audio: @example -silenceremove=0:0:0:-1:1:-90dB +silenceremove=stop_periods=-1:stop_duration=1:stop_threshold=-90dB @end example @end itemize @@ -4149,6 +4750,28 @@ Descriptions with unrecognised channel names are ignored. @item lfegain Set custom gain for LFE channels. Value is in dB. Default is 0. + +@item framesize +Set custom frame size in number of samples. Default is 1024. +Allowed range is from 1024 to 96000. Only used if option @samp{type} +is set to @var{freq}. + +@item normalize +Should all IRs be normalized upon importing SOFA file. +By default is enabled. + +@item interpolate +Should nearest IRs be interpolated with neighbor IRs if exact position +does not match. By default is disabled. + +@item minphase +Minphase all IRs upon loading of SOFA file. By default is disabled. + +@item anglestep +Set neighbor search angle step. Only used if option @var{interpolate} is enabled. + +@item radstep +Set neighbor search radius step. Only used if option @var{interpolate} is enabled. @end table @subsection Examples @@ -4415,20 +5038,119 @@ Set LFE low cut off frequency. By default, this is @var{128} Hz. @item lfe_high Set LFE high cut off frequency. By default, this is @var{256} Hz. +@item lfe_mode +Set LFE mode, can be @var{add} or @var{sub}. Default is @var{add}. +In @var{add} mode, LFE channel is created from input audio and added to output. +In @var{sub} mode, LFE channel is created from input audio and added to output but +also all non-LFE output channels are subtracted with output LFE channel. + +@item angle +Set angle of stereo surround transform, Allowed range is from @var{0} to @var{360}. +Default is @var{90}. + @item fc_in Set front center input volume. By default, this is @var{1}. @item fc_out Set front center output volume. By default, this is @var{1}. +@item fl_in +Set front left input volume. By default, this is @var{1}. + +@item fl_out +Set front left output volume. By default, this is @var{1}. + +@item fr_in +Set front right input volume. By default, this is @var{1}. + +@item fr_out +Set front right output volume. By default, this is @var{1}. + +@item sl_in +Set side left input volume. By default, this is @var{1}. + +@item sl_out +Set side left output volume. By default, this is @var{1}. + +@item sr_in +Set side right input volume. By default, this is @var{1}. + +@item sr_out +Set side right output volume. By default, this is @var{1}. + +@item bl_in +Set back left input volume. By default, this is @var{1}. + +@item bl_out +Set back left output volume. By default, this is @var{1}. + +@item br_in +Set back right input volume. By default, this is @var{1}. + +@item br_out +Set back right output volume. By default, this is @var{1}. + +@item bc_in +Set back center input volume. By default, this is @var{1}. + +@item bc_out +Set back center output volume. By default, this is @var{1}. + @item lfe_in Set LFE input volume. By default, this is @var{1}. @item lfe_out Set LFE output volume. By default, this is @var{1}. + +@item allx +Set spread usage of stereo image across X axis for all channels. + +@item ally +Set spread usage of stereo image across Y axis for all channels. + +@item fcx, flx, frx, blx, brx, slx, srx, bcx +Set spread usage of stereo image across X axis for each channel. + +@item fcy, fly, fry, bly, bry, sly, sry, bcy +Set spread usage of stereo image across Y axis for each channel. + +@item win_size +Set window size. Allowed range is from @var{1024} to @var{65536}. Default size is @var{4096}. + +@item win_func +Set window function. + +It accepts the following values: +@table @samp +@item rect +@item bartlett +@item hann, hanning +@item hamming +@item blackman +@item welch +@item flattop +@item bharris +@item bnuttall +@item bhann +@item sine +@item nuttall +@item lanczos +@item gauss +@item tukey +@item dolph +@item cauchy +@item parzen +@item poisson +@item bohman +@end table +Default is @code{hann}. + +@item overlap +Set window overlap. If set to 1, the recommended overlap for selected +window function will be picked. Default is @code{0.5}. @end table -@section treble +@section treble, highshelf Boost or cut treble (upper) frequencies of the audio using a two-pole shelving filter with a response similar to that of a standard @@ -4465,6 +5187,10 @@ kHz @item width, w Determine how steep is the filter's shelf transition. +@item mix, m +How much to use filtered signal in output. Default is 1. +Range is between 0 and 1. + @item channels, c Specify which channels to filter, by default all available are filtered. @end table @@ -4488,6 +5214,10 @@ Syntax for the command is : "@var{width}" @item gain, g Change treble gain. Syntax for the command is : "@var{gain}" + +@item mix, m +Change treble mix. +Syntax for the command is : "@var{mix}" @end table @section tremolo @@ -5050,6 +5780,49 @@ Set number of samples per each frame. Set window function to be used when generating FIR coefficients. @end table +@section sinc + +Generate a sinc kaiser-windowed low-pass, high-pass, band-pass, or band-reject FIR coefficients. + +The resulting stream can be used with @ref{afir} filter for filtering the audio signal. + +The filter accepts the following options: + +@table @option +@item sample_rate, r +Set sample rate, default is 44100. + +@item nb_samples, n +Set number of samples per each frame. Default is 1024. + +@item hp +Set high-pass frequency. Default is 0. + +@item lp +Set low-pass frequency. Default is 0. +If high-pass frequency is lower than low-pass frequency and low-pass frequency +is higher than 0 then filter will create band-pass filter coefficients, +otherwise band-reject filter coefficients. + +@item phase +Set filter phase response. Default is 50. Allowed range is from 0 to 100. + +@item beta +Set Kaiser window beta. + +@item att +Set stop-band attenuation. Default is 120dB, allowed range is from 40 to 180 dB. + +@item round +Enable rounding, by default is disabled. + +@item hptaps +Set number of taps for high-pass filter. + +@item lptaps +Set number of taps for low-pass filter. +@end table + @section sine Generate an audio signal made of a sine wave with amplitude 1/8. @@ -5183,6 +5956,43 @@ input reaches end of stream. This will cause problems if your encoding pipeline drops frames. If you're trying to apply an image as an overlay to a video stream, consider the @var{overlay} filter instead. +@section amplify + +Amplify differences between current pixel and pixels of adjacent frames in +same pixel location. + +This filter accepts the following options: + +@table @option +@item radius +Set frame radius. Default is 2. Allowed range is from 1 to 63. +For example radius of 3 will instruct filter to calculate average of 7 frames. + +@item factor +Set factor to amplify difference. Default is 2. Allowed range is from 0 to 65535. + +@item threshold +Set threshold for difference amplification. Any difference greater or equal to +this value will not alter source pixel. Default is 10. +Allowed range is from 0 to 65535. + +@item tolerance +Set tolerance for difference amplification. Any difference lower to +this value will not alter source pixel. Default is 0. +Allowed range is from 0 to 65535. + +@item low +Set lower limit for changing source pixel. Default is 65535. Allowed range is from 0 to 65535. +This option controls maximum possible value that will decrease source pixel value. + +@item high +Set high limit for changing source pixel. Default is 65535. Allowed range is from 0 to 65535. +This option controls maximum possible value that will increase source pixel value. + +@item planes +Set which planes to filter. Default is all. Allowed range is from 0 to 15. +@end table + @section ass Same as the @ref{subtitles} filter, except that it doesn't require libavcodec @@ -5243,7 +6053,7 @@ Threshold A is designed to react on abrupt changes in the input signal and threshold B is designed to react on continuous changes in the input signal. @item s -Set number of frames filter will use for averaging. Default is 33. Must be odd +Set number of frames filter will use for averaging. Default is 9. Must be odd number in range [5, 129]. @item p @@ -5258,13 +6068,13 @@ The filter accepts the following options: @table @option @item sizeX -Set horizontal kernel size. +Set horizontal radius size. @item planes Set which planes to filter. By default all planes are filtered. @item sizeY -Set vertical kernel size, if zero it will be same as @code{sizeX}. +Set vertical radius size, if zero it will be same as @code{sizeX}. Default is @code{0}. @end table @@ -5472,10 +6282,10 @@ the width and height of currently filtered plane @item SW @item SH -Width and height scale depending on the currently filtered plane. It is the -ratio between the corresponding luma plane number of pixels and the current -plane ones. E.g. for YUV4:2:0 the values are @code{1,1} for the luma plane, and -@code{0.5,0.5} for chroma planes. +Width and height scale for the plane being filtered. It is the +ratio between the dimensions of the current plane to the luma plane, +e.g. for a @code{yuv420p} frame, the values are @code{1,1} for +the luma plane and @code{0.5,0.5} for the chroma planes. @item T Time of the current frame, expressed in seconds. @@ -5542,6 +6352,91 @@ tblend=all_mode=grainextract @end example @end itemize +@section bm3d + +Denoise frames using Block-Matching 3D algorithm. + +The filter accepts the following options. + +@table @option +@item sigma +Set denoising strength. Default value is 1. +Allowed range is from 0 to 999.9. +The denoising algorithm is very sensitive to sigma, so adjust it +according to the source. + +@item block +Set local patch size. This sets dimensions in 2D. + +@item bstep +Set sliding step for processing blocks. Default value is 4. +Allowed range is from 1 to 64. +Smaller values allows processing more reference blocks and is slower. + +@item group +Set maximal number of similar blocks for 3rd dimension. Default value is 1. +When set to 1, no block matching is done. Larger values allows more blocks +in single group. +Allowed range is from 1 to 256. + +@item range +Set radius for search block matching. Default is 9. +Allowed range is from 1 to INT32_MAX. + +@item mstep +Set step between two search locations for block matching. Default is 1. +Allowed range is from 1 to 64. Smaller is slower. + +@item thmse +Set threshold of mean square error for block matching. Valid range is 0 to +INT32_MAX. + +@item hdthr +Set thresholding parameter for hard thresholding in 3D transformed domain. +Larger values results in stronger hard-thresholding filtering in frequency +domain. + +@item estim +Set filtering estimation mode. Can be @code{basic} or @code{final}. +Default is @code{basic}. + +@item ref +If enabled, filter will use 2nd stream for block matching. +Default is disabled for @code{basic} value of @var{estim} option, +and always enabled if value of @var{estim} is @code{final}. + +@item planes +Set planes to filter. Default is all available except alpha. +@end table + +@subsection Examples + +@itemize +@item +Basic filtering with bm3d: +@example +bm3d=sigma=3:block=4:bstep=2:group=1:estim=basic +@end example + +@item +Same as above, but filtering only luma: +@example +bm3d=sigma=3:block=4:bstep=2:group=1:estim=basic:planes=1 +@end example + +@item +Same as above, but with both estimation modes: +@example +split[a][b],[a]bm3d=sigma=3:block=4:bstep=2:group=1:estim=basic[a],[b][a]bm3d=sigma=3:block=4:bstep=2:group=16:estim=final:ref=1 +@end example + +@item +Same as above, but prefilter with @ref{nlmeans} filter instead: +@example +split[a][b],[a]nlmeans=s=3:r=7:p=3[a],[b][a]bm3d=sigma=3:block=4:bstep=2:group=16:estim=final:ref=1 +@end example +@end itemize + @section boxblur Apply a boxblur algorithm to the input video. @@ -5683,6 +6578,31 @@ Only deinterlace frames marked as interlaced. The default value is @code{all}. @end table +@section chromahold +Remove all color information for all colors except for certain one. + +The filter accepts the following options: + +@table @option +@item color +The color which will not be replaced with neutral chroma. + +@item similarity +Similarity percentage with the above color. +0.01 matches only the exact key color, while 1.0 matches everything. + +@item blend +Blend percentage. +0.0 makes pixels either fully gray, or not gray at all. +Higher values result in more preserved color. + +@item yuv +Signals that the color passed is already in YUV instead of RGB. + +Literal colors like "green" or "red" don't make sense with this enabled anymore. +This can be used to pass exact YUV values as hexadecimal numbers. +@end table + @section chromakey YUV colorspace color/chroma keying. @@ -5728,6 +6648,23 @@ ffmpeg -f lavfi -i color=c=black:s=1280x720 -i video.mp4 -shortest -filter_compl @end example @end itemize +@section chromashift +Shift chroma pixels horizontally and/or vertically. + +The filter accepts the following options: +@table @option +@item cbh +Set amount to shift chroma-blue horizontally. +@item cbv +Set amount to shift chroma-blue vertically. +@item crh +Set amount to shift chroma-red horizontally. +@item crv +Set amount to shift chroma-red vertically. +@item edge +Set edge mode, can be @var{smear}, default, or @var{warp}. +@end table + @section ciescope Display CIE color diagram with pixels overlaid onto it. @@ -5933,6 +6870,24 @@ ffmpeg -i background.png -i video.mp4 -filter_complex "[1:v]colorkey=0x3BBD1E:0. @end example @end itemize +@section colorhold +Remove all color information for all RGB colors except for certain one. + +The filter accepts the following options: + +@table @option +@item color +The color which will not be replaced with neutral gray. + +@item similarity +Similarity percentage with the above color. +0.01 matches only the exact key color, while 1.0 matches everything. + +@item blend +Blend percentage. 0.0 makes pixels fully gray. +Higher values result in more preserved color. +@end table + @section colorlevels Adjust video input frames using levels. @@ -6380,7 +7335,7 @@ colorspace=smpte240m @section convolution -Apply convolution 3x3, 5x5 or 7x7 filter. +Apply convolution of 3x3, 5x5, 7x7 or horizontal/vertical up to 49 elements. The filter accepts the following options: @@ -6390,13 +7345,15 @@ The filter accepts the following options: @item 2m @item 3m Set matrix for each plane. -Matrix is sequence of 9, 25 or 49 signed integers. +Matrix is sequence of 9, 25 or 49 signed integers in @var{square} mode, +and from 1 to 49 odd number of signed integers in @var{row} mode. @item 0rdiv @item 1rdiv @item 2rdiv @item 3rdiv Set multiplier for calculated value for each plane. +If unset or 0, it will be sum of all matrix elements. @item 0bias @item 1bias @@ -6404,6 +7361,13 @@ Set multiplier for calculated value for each plane. @item 3bias Set bias for each plane. This value is added to the result of the multiplication. Useful for making the overall image brighter or darker. Default is 0.0. + +@item 0mode +@item 1mode +@item 2mode +@item 3mode +Set matrix mode for each plane. Can be @var{square}, @var{row} or @var{column}. +Default is @var{square}. @end table @subsection Examples @@ -6805,6 +7769,37 @@ indicates 'never reset', and returns the largest area encountered during playback. @end table +@anchor{cue} +@section cue + +Delay video filtering until a given wallclock timestamp. The filter first +passes on @option{preroll} amount of frames, then it buffers at most +@option{buffer} amount of frames and waits for the cue. After reaching the cue +it forwards the buffered frames and also any subsequent frames coming in its +input. + +The filter can be used synchronize the output of multiple ffmpeg processes for +realtime output devices like decklink. By putting the delay in the filtering +chain and pre-buffering frames the process can pass on data to output almost +immediately after the target wallclock timestamp is reached. + +Perfect frame accuracy cannot be guaranteed, but the result is good enough for +some use cases. + +@table @option + +@item cue +The cue timestamp expressed in a UNIX timestamp in microseconds. Default is 0. + +@item preroll +The duration of content to pass on as preroll expressed in seconds. Default is 0. + +@item buffer +The maximum duration of content to buffer before waiting for the cue expressed +in seconds. Default is 0. + +@end table + @anchor{curves} @section curves @@ -7074,6 +8069,65 @@ e.g. banding detection threshold is triggered for all color components. The default is disabled. @end table +@section deblock + +Remove blocking artifacts from input video. + +The filter accepts the following options: + +@table @option +@item filter +Set filter type, can be @var{weak} or @var{strong}. Default is @var{strong}. +This controls what kind of deblocking is applied. + +@item block +Set size of block, allowed range is from 4 to 512. Default is @var{8}. + +@item alpha +@item beta +@item gamma +@item delta +Set blocking detection thresholds. Allowed range is 0 to 1. +Defaults are: @var{0.098} for @var{alpha} and @var{0.05} for the rest. +Using higher threshold gives more deblocking strength. +Setting @var{alpha} controls threshold detection at exact edge of block. +Remaining options controls threshold detection near the edge. Each one for +below/above or left/right. Setting any of those to @var{0} disables +deblocking. + +@item planes +Set planes to filter. Default is to filter all available planes. +@end table + +@subsection Examples + +@itemize +@item +Deblock using weak filter and block size of 4 pixels. +@example +deblock=filter=weak:block=4 +@end example + +@item +Deblock using strong filter, block size of 4 pixels and custom thresholds for +deblocking more edges. +@example +deblock=filter=strong:block=4:alpha=0.12:beta=0.07:gamma=0.06:delta=0.05 +@end example + +@item +Similar as above, but filter only first plane. +@example +deblock=filter=strong:block=4:alpha=0.12:beta=0.07:gamma=0.06:delta=0.05:planes=1 +@end example + +@item +Similar as above, but filter only second and third plane. +@example +deblock=filter=strong:block=4:alpha=0.12:beta=0.07:gamma=0.06:delta=0.05:planes=6 +@end example +@end itemize + @anchor{decimate} @section decimate @@ -7137,6 +8191,30 @@ had noise. The @code{deconvolve} filter also supports the @ref{framesync} options. +@section dedot + +Reduce cross-luminance (dot-crawl) and cross-color (rainbows) from video. + +It accepts the following options: + +@table @option +@item m +Set mode of operation. Can be combination of @var{dotcrawl} for cross-luminance reduction and/or +@var{rainbows} for cross-color reduction. + +@item lt +Set spatial luma threshold. Lower values increases reduction of cross-luminance. + +@item tl +Set tolerance for temporal luma. Higher values increases reduction of cross-luminance. + +@item tc +Set tolerance for chroma temporal variation. Higher values increases reduction of cross-color. + +@item ct +Set temporal chroma threshold. Lower values increases reduction of cross-color. +@end table + @section deflate Apply deflate effect to the video. @@ -7277,6 +8355,40 @@ delogo=x=0:y=0:w=100:h=77:band=10 @end itemize +@section derain + +Remove the rain in the input image/video by applying the derain methods based on +convolutional neural networks. Supported models: + +@itemize +@item +Recurrent Squeeze-and-Excitation Context Aggregation Net (RESCAN). +See @url{http://openaccess.thecvf.com/content_ECCV_2018/papers/Xia_Li_Recurrent_Squeeze-and-Excitation_Context_ECCV_2018_paper.pdf}. +@end itemize + +Training scripts as well as scripts for model generation are provided in +the repository at @url{https://github.com/XueweiMeng/derain_filter.git}. + +The filter accepts the following options: + +@table @option +@item dnn_backend +Specify which DNN backend to use for model loading and execution. This option accepts +the following values: + +@table @samp +@item native +Native implementation of DNN loading and execution. +@end table +Default value is @samp{native}. + +@item model +Set path to model file specifying network architecture and its parameters. +Note that different backends use different file formats. TensorFlow backend +can load files for both formats, while native backend can load files for only +its format. +@end table + @section deshake Attempt to fix small changes in horizontal and/or vertical shift. This @@ -7941,7 +9053,21 @@ the width of the rendered text the x and y offset coordinates where the text is drawn. These parameters allow the @var{x} and @var{y} expressions to refer -each other, so you can for example specify @code{y=x/dar}. +to each other, so you can for example specify @code{y=x/dar}. + +@item pict_type +A one character description of the current frame's picture type. + +@item pkt_pos +The current packet's position in the input file or stream +(in bytes, from the start of the input). A value of -1 indicates +this info is not available. + +@item pkt_duration +The current packet's duration, in seconds. + +@item pkt_size +The current packet's size (in bytes). @end table @anchor{drawtext_expansion} @@ -8011,11 +9137,18 @@ The first argument is mandatory and specifies the metadata key. The second argument is optional and specifies a default value, used when the metadata key is not found or empty. +Available metadata can be identified by inspecting entries +starting with TAG included within each frame section +printed by running @code{ffprobe -show_frames}. + +String metadata generated in filters leading to +the drawtext filter are also available. + @item n, frame_num The frame number, starting from 0. @item pict_type -A 1 character description of the current picture type. +A one character description of the current picture type. @item pts The timestamp of the current frame. @@ -8030,11 +9163,38 @@ local time zone time. The second argument is an offset added to the timestamp. +If the format is set to @code{hms}, a third argument @code{24HH} may be +supplied to present the hour part of the formatted timestamp in 24h format +(00-23). + If the format is set to @code{localtime} or @code{gmtime}, a third argument may be supplied: a strftime() format string. By default, @var{YYYY-MM-DD HH:MM:SS} format will be used. @end table +@subsection Commands + +This filter supports altering parameters via commands: +@table @option +@item reinit +Alter existing filter parameters. + +Syntax for the argument is the same as for filter invocation, e.g. + +@example +fontsize=56:fontcolor=green:text='Hello World' +@end example + +Full filter invocation with sendcmd would look like this: + +@example +sendcmd=c='56.0 drawtext reinit fontsize=56\:fontcolor=green\:text=Hello\\ World' +@end example +@end table + +If the entire argument can't be parsed or applied as valid values then the filter will +continue with its existing parameters. + @subsection Examples @itemize @@ -8172,9 +9332,14 @@ Draw white/gray wires on black background. @item colormix Mix the colors to create a paint/cartoon effect. -@end table +@item canny +Apply Canny edge detector on all selected planes. +@end table Default value is @var{wires}. + +@item planes +Select planes for filtering. By default all available planes are filtered. @end table @subsection Examples @@ -8587,6 +9752,40 @@ fftfilt=dc_Y=0:weight_Y='exp(-4 * ((Y+X)/(W+H)))' @end itemize +@section fftdnoiz +Denoise frames using 3D FFT (frequency domain filtering). + +The filter accepts the following options: + +@table @option +@item sigma +Set the noise sigma constant. This sets denoising strength. +Default value is 1. Allowed range is from 0 to 30. +Using very high sigma with low overlap may give blocking artifacts. + +@item amount +Set amount of denoising. By default all detected noise is reduced. +Default value is 1. Allowed range is from 0 to 1. + +@item block +Set size of block, Default is 4, can be 3, 4, 5 or 6. +Actual size of block in pixels is 2 to power of @var{block}, so by default +block size in pixels is 2^4 which is 16. + +@item overlap +Set block overlap. Default is 0.5. Allowed range is from 0.2 to 0.8. + +@item prev +Set number of previous frames to use for denoising. By default is set to 0. + +@item next +Set number of next frames to to use for denoising. By default is set to 0. + +@item planes +Set planes which will be filtered, by default are all available filtered +except alpha. +@end table + @section field Extract a single field from an interlaced image using stride @@ -9079,7 +10278,7 @@ Specifies the rectangle in which to search. @itemize @item -Generate a representative palette of a given video using @command{ffmpeg}: +Cover a rectangular object by the supplied image of a given video using @command{ffmpeg}: @example ffmpeg -i file.ts -vf find_rect=newref.pgm,cover_rect=cover.jpg:mode=cover new.mkv @end example @@ -9113,7 +10312,7 @@ Default value is @var{blur}. @itemize @item -Generate a representative palette of a given video using @command{ffmpeg}: +Cover a rectangular object by the supplied image of a given video using @command{ffmpeg}: @example ffmpeg -i file.ts -vf find_rect=newref.pgm,cover_rect=cover.jpg:mode=cover new.mkv @end example @@ -9361,6 +10560,35 @@ Select frame after every @code{step} frames. Allowed values are positive integers higher than 0. Default value is @code{1}. @end table +@section freezedetect + +Detect frozen video. + +This filter logs a message and sets frame metadata when it detects that the +input video has no significant change in content during a specified duration. +Video freeze detection calculates the mean average absolute difference of all +the components of video frames and compares it to a noise floor. + +The printed times and duration are expressed in seconds. The +@code{lavfi.freezedetect.freeze_start} metadata key is set on the first frame +whose timestamp equals or exceeds the detection duration and it contains the +timestamp of the first frame of the freeze. The +@code{lavfi.freezedetect.freeze_duration} and +@code{lavfi.freezedetect.freeze_end} metadata keys are set on the first frame +after the freeze. + +The filter accepts the following options: + +@table @option +@item noise, n +Set noise tolerance. Can be specified in dB (in case "dB" is appended to the +specified value) or as a difference ratio between 0 and 1. Default is -60dB, or +0.001. + +@item duration, d +Set freeze duration until notification (default is 2 seconds). +@end table + @anchor{frei0r} @section frei0r @@ -9467,7 +10695,7 @@ The filter accepts the following options: Set horizontal sigma, standard deviation of Gaussian blur. Default is @code{0.5}. @item steps -Set number of steps for Gaussian approximation. Defauls is @code{1}. +Set number of steps for Gaussian approximation. Default is @code{1}. @item planes Set which planes to filter. By default all planes are filtered. @@ -9479,6 +10707,8 @@ Default is @code{-1}. @section geq +Apply generic equation to each pixel. + The filter accepts the following options: @table @option @@ -9656,6 +10886,104 @@ gradfun=radius=8 @end itemize +@section graphmonitor, agraphmonitor +Show various filtergraph stats. + +With this filter one can debug complete filtergraph. +Especially issues with links filling with queued frames. + +The filter accepts the following options: + +@table @option +@item size, s +Set video output size. Default is @var{hd720}. + +@item opacity, o +Set video opacity. Default is @var{0.9}. Allowed range is from @var{0} to @var{1}. + +@item mode, m +Set output mode, can be @var{fulll} or @var{compact}. +In @var{compact} mode only filters with some queued frames have displayed stats. + +@item flags, f +Set flags which enable which stats are shown in video. + +Available values for flags are: +@table @samp +@item queue +Display number of queued frames in each link. + +@item frame_count_in +Display number of frames taken from filter. + +@item frame_count_out +Display number of frames given out from filter. + +@item pts +Display current filtered frame pts. + +@item time +Display current filtered frame time. + +@item timebase +Display time base for filter link. + +@item format +Display used format for filter link. + +@item size +Display video size or number of audio channels in case of audio used by filter link. + +@item rate +Display video frame rate or sample rate in case of audio used by filter link. +@end table + +@item rate, r +Set upper limit for video rate of output stream, Default value is @var{25}. +This guarantee that output video frame rate will not be higher than this value. +@end table + +@section greyedge +A color constancy variation filter which estimates scene illumination via grey edge algorithm +and corrects the scene colors accordingly. + +See: @url{https://staff.science.uva.nl/th.gevers/pub/GeversTIP07.pdf} + +The filter accepts the following options: + +@table @option +@item difford +The order of differentiation to be applied on the scene. Must be chosen in the range +[0,2] and default value is 1. + +@item minknorm +The Minkowski parameter to be used for calculating the Minkowski distance. Must +be chosen in the range [0,20] and default value is 1. Set to 0 for getting +max value instead of calculating Minkowski distance. + +@item sigma +The standard deviation of Gaussian blur to be applied on the scene. Must be +chosen in the range [0,1024.0] and default value = 1. floor( @var{sigma} * break_off_sigma(3) ) +can't be equal to 0 if @var{difford} is greater than 0. +@end table + +@subsection Examples +@itemize + +@item +Grey Edge: +@example +greyedge=difford=1:minknorm=5:sigma=2 +@end example + +@item +Max Edge: +@example +greyedge=difford=1:minknorm=0:sigma=2 +@end example + +@end itemize + @anchor{haldclut} @section haldclut @@ -9678,6 +11006,8 @@ Default is @code{1}. @code{haldclut} also has the same interpolation options as @ref{lut3d} (both filters share the same internals). +This filter also supports the @ref{framesync} options. + More information about the Hald CLUT can be found on Eskil Steenberg's website (Hald CLUT author) at @url{http://www.quelsolaar.com/technology/clut.html}. @@ -9865,6 +11195,7 @@ A floating point number which specifies chroma temporal strength. It defaults to @var{luma_tmp}*@var{chroma_spatial}/@var{luma_spatial}. @end table +@anchor{hwdownload} @section hwdownload Download hardware frames to system memory. @@ -9955,6 +11286,7 @@ ways if there are any additional constraints on that filter's output. Do not use it without fully understanding the implications of its use. @end table +@anchor{hwupload} @section hwupload Upload system memory frames to hardware surfaces. @@ -10369,6 +11701,21 @@ kerndeint=map=1 @end example @end itemize +@section lagfun + +Slowly update darker pixels. + +This filter makes short flashes of light appear longer. +This filter accepts the following options: + +@table @option +@item decay +Set factor for decaying. Default is .95. Allowed range is from 0 to 1. + +@item planes +Set which planes to filter. Default is all. Allowed range is from 0 to 15. +@end table + @section lenscorrection Correct radial lens distortion @@ -10416,6 +11763,133 @@ The formula that generates the correction is: where @var{r_0} is halve of the image diagonal and @var{r_src} and @var{r_tgt} are the distances from the focal point in the source and target images, respectively. +@section lensfun + +Apply lens correction via the lensfun library (@url{http://lensfun.sourceforge.net/}). + +The @code{lensfun} filter requires the camera make, camera model, and lens model +to apply the lens correction. The filter will load the lensfun database and +query it to find the corresponding camera and lens entries in the database. As +long as these entries can be found with the given options, the filter can +perform corrections on frames. Note that incomplete strings will result in the +filter choosing the best match with the given options, and the filter will +output the chosen camera and lens models (logged with level "info"). You must +provide the make, camera model, and lens model as they are required. + +The filter accepts the following options: + +@table @option +@item make +The make of the camera (for example, "Canon"). This option is required. + +@item model +The model of the camera (for example, "Canon EOS 100D"). This option is +required. + +@item lens_model +The model of the lens (for example, "Canon EF-S 18-55mm f/3.5-5.6 IS STM"). This +option is required. + +@item mode +The type of correction to apply. The following values are valid options: + +@table @samp +@item vignetting +Enables fixing lens vignetting. + +@item geometry +Enables fixing lens geometry. This is the default. + +@item subpixel +Enables fixing chromatic aberrations. + +@item vig_geo +Enables fixing lens vignetting and lens geometry. + +@item vig_subpixel +Enables fixing lens vignetting and chromatic aberrations. + +@item distortion +Enables fixing both lens geometry and chromatic aberrations. + +@item all +Enables all possible corrections. + +@end table +@item focal_length +The focal length of the image/video (zoom; expected constant for video). For +example, a 18--55mm lens has focal length range of [18--55], so a value in that +range should be chosen when using that lens. Default 18. + +@item aperture +The aperture of the image/video (expected constant for video). Note that +aperture is only used for vignetting correction. Default 3.5. + +@item focus_distance +The focus distance of the image/video (expected constant for video). Note that +focus distance is only used for vignetting and only slightly affects the +vignetting correction process. If unknown, leave it at the default value (which +is 1000). + +@item scale +The scale factor which is applied after transformation. After correction the +video is no longer necessarily rectangular. This parameter controls how much of +the resulting image is visible. The value 0 means that a value will be chosen +automatically such that there is little or no unmapped area in the output +image. 1.0 means that no additional scaling is done. Lower values may result +in more of the corrected image being visible, while higher values may avoid +unmapped areas in the output. + +@item target_geometry +The target geometry of the output image/video. The following values are valid +options: + +@table @samp +@item rectilinear (default) +@item fisheye +@item panoramic +@item equirectangular +@item fisheye_orthographic +@item fisheye_stereographic +@item fisheye_equisolid +@item fisheye_thoby +@end table +@item reverse +Apply the reverse of image correction (instead of correcting distortion, apply +it). + +@item interpolation +The type of interpolation used when correcting distortion. The following values +are valid options: + +@table @samp +@item nearest +@item linear (default) +@item lanczos +@end table +@end table + +@subsection Examples + +@itemize +@item +Apply lens correction with make "Canon", camera model "Canon EOS 100D", and lens +model "Canon EF-S 18-55mm f/3.5-5.6 IS STM" with focal length of "18" and +aperture of "8.0". + +@example +ffmpeg -i input.mov -vf lensfun=make=Canon:model="Canon EOS 100D":lens_model="Canon EF-S 18-55mm f/3.5-5.6 IS STM":focal_length=18:aperture=8 -c:v h264 -b:v 8000k output.mov +@end example + +@item +Apply the same as before, but only for the first 5 seconds of video. + +@example +ffmpeg -i input.mov -vf lensfun=make=Canon:model="Canon EOS 100D":lens_model="Canon EF-S 18-55mm f/3.5-5.6 IS STM":focal_length=18:aperture=8:enable='lte(t\,5)' -c:v h264 -b:v 8000k output.mov +@end example + +@end itemize + @section libvmaf Obtain the VMAF (Video Multi-Method Assessment Fusion) @@ -10425,7 +11899,7 @@ The obtained VMAF score is printed through the logging system. It requires Netflix's vmaf library (libvmaf) as a pre-requisite. After installing the library it can be enabled using: -@code{./configure --enable-libvmaf}. +@code{./configure --enable-libvmaf --enable-version3}. If no model path is specified it uses the default model: @code{vmaf_v0.6.1.pkl}. The filter has following options: @@ -10442,7 +11916,9 @@ Set the file path to be used to store logs. Set the format of the log file (xml or json). @item enable_transform -Enables transform for computing vmaf. +This option can enable/disable the @code{score_transform} applied to the final predicted VMAF score, +if you have specified score_transform option in the input parameter file passed to @code{run_vmaf_training.py} +Default value: @code{false} @item phone_model Invokes the phone model which will generate VMAF scores higher than in the @@ -10459,6 +11935,15 @@ Enables computing ms_ssim along with vmaf. @item pool Set the pool method (mean, min or harmonic mean) to be used for computing vmaf. + +@item n_threads +Set number of threads to be used when computing vmaf. + +@item n_subsample +Set interval for frame subsampling used when computing vmaf. + +@item enable_conf_interval +Enables confidence interval. @end table This filter also supports the @ref{framesync} options. @@ -10472,7 +11957,7 @@ ffmpeg -i main.mpg -i ref.mpg -lavfi libvmaf -f null - Example with options: @example -ffmpeg -i main.mpg -i ref.mpg -lavfi libvmaf="psnr=1:enable-transform=1" -f null - +ffmpeg -i main.mpg -i ref.mpg -lavfi libvmaf="psnr=1:log_fmt=json" -f null - @end example @section limiter @@ -10510,6 +11995,65 @@ Set maximal size in number of frames. Default is 0. Set first frame of loop. Default is 0. @end table +@subsection Examples + +@itemize +@item +Loop single first frame infinitely: +@example +loop=loop=-1:size=1:start=0 +@end example + +@item +Loop single first frame 10 times: +@example +loop=loop=10:size=1:start=0 +@end example + +@item +Loop 10 first frames 5 times: +@example +loop=loop=5:size=10:start=0 +@end example +@end itemize + +@section lut1d + +Apply a 1D LUT to an input video. + +The filter accepts the following options: + +@table @option +@item file +Set the 1D LUT file name. + +Currently supported formats: +@table @samp +@item cube +Iridas +@item csp +cineSpace +@end table + +@item interp +Select interpolation mode. + +Available values are: + +@table @samp +@item nearest +Use values from the nearest defined point. +@item linear +Interpolate values using the linear interpolation. +@item cosine +Interpolate values using the cosine interpolation. +@item cubic +Interpolate values using the cubic interpolation. +@item spline +Interpolate values using the spline interpolation. +@end table +@end table + @anchor{lut3d} @section lut3d @@ -10531,6 +12075,8 @@ Iridas DaVinci @item m3d Pandora +@item csp +cineSpace @end table @item interp Select interpolation mode. @@ -10547,8 +12093,6 @@ Interpolate values using a tetrahedron. @end table @end table -This filter also supports the @ref{framesync} options. - @section lumakey Turn certain luma values into transparency. @@ -10735,6 +12279,10 @@ set second pixel component expression set third pixel component expression @item c3 set fourth pixel component expression, corresponds to the alpha component + +@item d +set output bit depth, only available for @code{lut2} filter. By default is 0, +which means bit depth is automatically picked from first input format. @end table Each of them specifies the expression to use for computing the lookup table for @@ -10827,6 +12375,33 @@ copied from first stream. By default value 0xf, all planes will be processed. @end table +@section maskfun +Create mask from input video. + +For example it is useful to create motion masks after @code{tblend} filter. + +This filter accepts the following options: + +@table @option +@item low +Set low threshold. Any pixel component lower or exact than this value will be set to 0. + +@item high +Set high threshold. Any pixel component higher than this value will be set to max value +allowed for current pixel format. + +@item planes +Set planes to filter, by default all available planes are filtered. + +@item fill +Fill all frame pixels with this value. + +@item sum +Set max average pixel value for frame. If sum of all pixel components is higher that this +average, output frame will be completely filled with value set by @var{fill} option. +Typically useful for scene changes when used in combination with @code{tblend} filter. +@end table + @section mcdeint Apply motion-compensation deinterlacing. @@ -11089,7 +12664,14 @@ The number of inputs. If unspecified, it defaults to 2. @item weights Specify weight of each input video stream as sequence. -Each weight is separated by space. +Each weight is separated by space. If number of weights +is smaller than number of @var{frames} last specified +weight will be used for all remaining unset weights. + +@item scale +Specify scale, if it is set it will be multiplied with sum +of each weight multiplied with pixel values to give final destination +pixel value. By default @var{scale} is auto scaled to sum of weights. @item duration Specify how end of stream is determined. @@ -11146,11 +12728,17 @@ Default value for @option{hi} is 64*12, default value for @option{lo} is @section negate -Negate input video. +Negate (invert) the input video. -It accepts an integer in input; if non-zero it negates the -alpha component (if available). The default value in input is 0. +It accepts the following option: +@table @option + +@item negate_alpha +With value 1, it negates the alpha component, if present. Default value is 0. +@end table + +@anchor{nlmeans} @section nlmeans Denoise frames using Non-Local Means algorithm. @@ -11167,10 +12755,10 @@ The filter accepts the following options. @table @option @item s -Set denoising strength. +Set denoising strength. Default is 1.0. Must be in range [1.0, 30.0]. @item p -Set patch size. +Set patch size. Default is 7. Must be odd number in range [0, 99]. @item pc Same as @option{p} but for chroma planes. @@ -11178,7 +12766,7 @@ Same as @option{p} but for chroma planes. The default value is @var{0} and means automatic. @item r -Set research size. +Set research size. Default is 15. Must be odd number in range [0, 99]. @item rc Same as @option{r} but for chroma planes. @@ -11462,7 +13050,9 @@ Pass the video source unchanged to the output. @section ocr Optical Character Recognition -This filter uses Tesseract for optical character recognition. +This filter uses Tesseract for optical character recognition. To enable +compilation of this filter, you need to configure FFmpeg with +@code{--enable-libtesseract}. It accepts the following options: @@ -11482,6 +13072,7 @@ Set character blacklist. @end table The filter exports recognized text as the frame metadata @code{lavfi.ocr.text}. +The filter exports confidence of recognized words as the frame metadata @code{lavfi.ocr.confidence}. @section ocv @@ -13081,6 +14672,9 @@ Set the black color threshold. Default is @code{0.15}. Allowed range is @code{[0 @item chp Enable checking the parity bit. In the event of a parity error, the filter will output @code{0x00} for that character. Default is false. + +@item lp +Lowpass lines prior further proccessing. Default is disabled. @end table @subsection Examples @@ -13142,6 +14736,12 @@ Xmap and Ymap input video streams must be of same dimensions. Output video strea will have Xmap/Ymap video stream dimensions. Xmap and Ymap input video streams are 16bit depth, single channel. +@table @option +@item format +Specify pixel format of output from this filter. Can be @code{color} or @code{gray}. +Default is @code{color}. +@end table + @section removegrain The removegrain filter is a spatial denoiser for progressive video. @@ -13298,6 +14898,31 @@ trim=end=5,reverse @end example @end itemize +@section rgbashift +Shift R/G/B/A pixels horizontally and/or vertically. + +The filter accepts the following options: +@table @option +@item rh +Set amount to shift red horizontally. +@item rv +Set amount to shift red vertically. +@item gh +Set amount to shift green horizontally. +@item gv +Set amount to shift green vertically. +@item bh +Set amount to shift blue horizontally. +@item bv +Set amount to shift blue vertically. +@item ah +Set amount to shift alpha horizontally. +@item av +Set amount to shift alpha vertically. +@item edge +Set edge mode, can be @var{smear}, default, or @var{warp}. +@end table + @section roberts Apply roberts cross operator to input video stream. @@ -13601,6 +15226,8 @@ Set color space conforming to the United States Federal Communications Commission (FCC) Code of Federal Regulations (CFR) Title 47 (2003) 73.682 (a). @item bt601 +@item bt470 +@item smpte170m Set color space conforming to: @itemize @@ -13617,6 +15244,9 @@ Society of Motion Picture and Television Engineers (SMPTE) ST 170:2004 @item smpte240m Set color space conforming to SMPTE ST 240:1999. + +@item bt2020 +Set color space conforming to ITU-R BT.2020 non-constant luminance system. @end table @item in_range @@ -13898,6 +15528,12 @@ Scale a subtitle stream (b) to match the main video (a) in size before overlayin @example 'scale2ref[b][a];[a][b]overlay' @end example + +@item +Scale a logo to 1/10th the height of a video, while preserving its display aspect ratio. +@example +[logo-in][video-in]scale2ref=w=oh*mdar:h=ih/10[logo-out][video-out] +@end example @end itemize @anchor{selectivecolor} @@ -14111,11 +15747,137 @@ Mark the frame as progressive. @end table @end table +@anchor{setparams} +@section setparams + +Force frame parameter for the output video frame. + +The @code{setparams} filter marks interlace and color range for the +output frames. It does not change the input frame, but only sets the +corresponding property, which affects how the frame is treated by +filters/encoders. + +@table @option +@item field_mode +Available values are: + +@table @samp +@item auto +Keep the same field property (default). + +@item bff +Mark the frame as bottom-field-first. + +@item tff +Mark the frame as top-field-first. + +@item prog +Mark the frame as progressive. +@end table + +@item range +Available values are: + +@table @samp +@item auto +Keep the same color range property (default). + +@item unspecified, unknown +Mark the frame as unspecified color range. + +@item limited, tv, mpeg +Mark the frame as limited range. + +@item full, pc, jpeg +Mark the frame as full range. +@end table + +@item color_primaries +Set the color primaries. +Available values are: + +@table @samp +@item auto +Keep the same color primaries property (default). + +@item bt709 +@item unknown +@item bt470m +@item bt470bg +@item smpte170m +@item smpte240m +@item film +@item bt2020 +@item smpte428 +@item smpte431 +@item smpte432 +@item jedec-p22 +@end table + +@item color_trc +Set the color transfer. +Available values are: + +@table @samp +@item auto +Keep the same color trc property (default). + +@item bt709 +@item unknown +@item bt470m +@item bt470bg +@item smpte170m +@item smpte240m +@item linear +@item log100 +@item log316 +@item iec61966-2-4 +@item bt1361e +@item iec61966-2-1 +@item bt2020-10 +@item bt2020-12 +@item smpte2084 +@item smpte428 +@item arib-std-b67 +@end table + +@item colorspace +Set the colorspace. +Available values are: + +@table @samp +@item auto +Keep the same colorspace property (default). + +@item gbr +@item bt709 +@item unknown +@item fcc +@item bt470bg +@item smpte170m +@item smpte240m +@item ycgco +@item bt2020nc +@item bt2020c +@item smpte2085 +@item chroma-derived-nc +@item chroma-derived-c +@item ictcp +@end table +@end table + @section showinfo Show a line containing various information for each input video frame. The input video is not modified. +This filter supports the following options: + +@table @option +@item checksum +Calculate checksums of each plane. By default enabled. +@end table + The shown line contains a sequence of key/value pairs of the form @var{key}:@var{value}. @@ -14937,6 +16699,60 @@ option may cause flicker since the B-Frames have often larger QP. Default is @code{0} (not enabled). @end table +@section sr + +Scale the input by applying one of the super-resolution methods based on +convolutional neural networks. Supported models: + +@itemize +@item +Super-Resolution Convolutional Neural Network model (SRCNN). +See @url{https://arxiv.org/abs/1501.00092}. + +@item +Efficient Sub-Pixel Convolutional Neural Network model (ESPCN). +See @url{https://arxiv.org/abs/1609.05158}. +@end itemize + +Training scripts as well as scripts for model file (.pb) saving can be found at +@url{https://github.com/XueweiMeng/sr/tree/sr_dnn_native}. Original repository +is at @url{https://github.com/HighVoltageRocknRoll/sr.git}. + +Native model files (.model) can be generated from TensorFlow model +files (.pb) by using tools/python/convert.py + +The filter accepts the following options: + +@table @option +@item dnn_backend +Specify which DNN backend to use for model loading and execution. This option accepts +the following values: + +@table @samp +@item native +Native implementation of DNN loading and execution. + +@item tensorflow +TensorFlow backend. To enable this backend you +need to install the TensorFlow for C library (see +@url{https://www.tensorflow.org/install/install_c}) and configure FFmpeg with +@code{--enable-libtensorflow} +@end table + +Default value is @samp{native}. + +@item model +Set path to model file specifying network architecture and its parameters. +Note that different backends use different file formats. TensorFlow backend +can load files for both formats, while native backend can load files for only +its format. + +@item scale_factor +Set scale factor for SRCNN model. Allowed values are @code{2}, @code{3} and @code{4}. +Default value is @code{2}. Scale factor is necessary for SRCNN model, because it accepts +input upscaled using bicubic upscaling with proper scale factor. +@end table + @anchor{subtitles} @section subtitles @@ -15003,10 +16819,10 @@ To render the second subtitles stream from that file, use: subtitles=video.mkv:si=1 @end example -To make the subtitles stream from @file{sub.srt} appear in transparent green +To make the subtitles stream from @file{sub.srt} appear in 80% transparent blue @code{DejaVu Serif}, use: @example -subtitles=sub.srt:force_style='FontName=DejaVu Serif,PrimaryColour=&HAA00FF00' +subtitles=sub.srt:force_style='FontName=DejaVu Serif,PrimaryColour=&HCCFF0000' @end example @section super2xsai @@ -15479,14 +17295,14 @@ Specify flags influencing the filter process. Available value for @var{flags} is: @table @option -@item low_pass_filter, vlfp +@item low_pass_filter, vlpf Enable linear vertical low-pass filtering in the filter. Vertical low-pass filtering is required when creating an interlaced destination from a progressive source which contains high-frequency vertical detail. Filtering will reduce interlace 'twitter' and Moire patterning. -@item complex_filter, cvlfp +@item complex_filter, cvlpf Enable complex vertical low-pass filtering. This will slightly less reduce interlace 'twitter' and Moire patterning but better retain detail and subjective sharpness impression. @@ -15498,6 +17314,51 @@ Vertical low-pass filtering can only be enabled for @option{mode} @end table +@section tmix + +Mix successive video frames. + +A description of the accepted options follows. + +@table @option +@item frames +The number of successive frames to mix. If unspecified, it defaults to 3. + +@item weights +Specify weight of each input video frame. +Each weight is separated by space. If number of weights is smaller than +number of @var{frames} last specified weight will be used for all remaining +unset weights. + +@item scale +Specify scale, if it is set it will be multiplied with sum +of each weight multiplied with pixel values to give final destination +pixel value. By default @var{scale} is auto scaled to sum of weights. +@end table + +@subsection Examples + +@itemize +@item +Average 7 successive frames: +@example +tmix=frames=7:weights="1 1 1 1 1 1 1" +@end example + +@item +Apply simple temporal convolution: +@example +tmix=frames=3:weights="-1 3 -1" +@end example + +@item +Similar as above but only showing temporal differences: +@example +tmix=frames=3:weights="-1 2 -1":scale=1 +@end example +@end itemize + +@anchor{tonemap} @section tonemap Tone map colors from different dynamic ranges. @@ -15605,6 +17466,47 @@ embedded peak information in display metadata is not reliable or when tone mapping from a lower range to a higher range. @end table +@section tpad + +Temporarily pad video frames. + +The filter accepts the following options: + +@table @option +@item start +Specify number of delay frames before input video stream. + +@item stop +Specify number of padding frames after input video stream. +Set to -1 to pad indefinitely. + +@item start_mode +Set kind of frames added to beginning of stream. +Can be either @var{add} or @var{clone}. +With @var{add} frames of solid-color are added. +With @var{clone} frames are clones of first frame. + +@item stop_mode +Set kind of frames added to end of stream. +Can be either @var{add} or @var{clone}. +With @var{add} frames of solid-color are added. +With @var{clone} frames are clones of last frame. + +@item start_duration, stop_duration +Specify the duration of the start/stop delay. See +@ref{time duration syntax,,the Time duration section in the ffmpeg-utils(1) manual,ffmpeg-utils} +for the accepted syntax. +These options override @var{start} and @var{stop}. + +@item color +Specify the color of the padded area. For the syntax of this option, +check the @ref{color syntax,,"Color" section in the ffmpeg-utils +manual,ffmpeg-utils}. + +The default value of @var{color} is "black". +@end table + +@anchor{transpose} @section transpose Transpose rows with columns in the input video and optionally flip it. @@ -15684,6 +17586,47 @@ The command above can also be specified as: transpose=1:portrait @end example +@section transpose_npp + +Transpose rows with columns in the input video and optionally flip it. +For more in depth examples see the @ref{transpose} video filter, which shares mostly the same options. + +It accepts the following parameters: + +@table @option + +@item dir +Specify the transposition direction. + +Can assume the following values: +@table @samp +@item cclock_flip +Rotate by 90 degrees counterclockwise and vertically flip. (default) + +@item clock +Rotate by 90 degrees clockwise. + +@item cclock +Rotate by 90 degrees counterclockwise. + +@item clock_flip +Rotate by 90 degrees clockwise and vertically flip. +@end table + +@item passthrough +Do not apply the transposition if the input geometry matches the one +specified by the specified value. It accepts the following values: +@table @samp +@item none +Always apply transposition. (default) +@item portrait +Preserve portrait geometry (when @var{height} >= @var{width}). +@item landscape +Preserve landscape geometry (when @var{width} >= @var{height}). +@end table + +@end table + @section trim Trim the input so that the output contains one continuous subpart of the input. @@ -16282,6 +18225,39 @@ and ones with constant delta pts. If there was frames with variable delta, than it will also show min and max delta encountered. +@section vibrance + +Boost or alter saturation. + +The filter accepts the following options: +@table @option +@item intensity +Set strength of boost if positive value or strength of alter if negative value. +Default is 0. Allowed range is from -2 to 2. + +@item rbal +Set the red balance. Default is 1. Allowed range is from -10 to 10. + +@item gbal +Set the green balance. Default is 1. Allowed range is from -10 to 10. + +@item bbal +Set the blue balance. Default is 1. Allowed range is from -10 to 10. + +@item rlum +Set the red luma coefficient. + +@item glum +Set the green luma coefficient. + +@item blum +Set the blue luma coefficient. + +@item alternate +If @code{intensity} is negative and this is set to 1, colors will change, +otherwise colors will be less saturated, more towards gray. +@end table + @anchor{vignette} @section vignette @@ -16436,6 +18412,10 @@ implemented based on the de-interlace algorithm written by Jim Easterbrook for BBC R&D, the Weston 3 field deinterlacing filter uses filter coefficients calculated by BBC R&D. +This filter use field-dominance information in frame to decide which +of each pair of fields to place first in the output. +If it gets it wrong use @ref{setfield} filter before @code{w3fdif} filter. + There are two sets of filter coefficients, so called "simple": and "complex". Which set of filter coefficients is used can be set by passing an optional parameter: @@ -16647,7 +18627,7 @@ separatefields,select=eq(mod(n,4),0)+eq(mod(n,4),3),weave @section xbr Apply the xBR high-quality magnification filter which is designed for pixel art. It follows a set of edge-detection rules, see -@url{http://www.libretro.com/forums/viewtopic.php?f=6&t=134}. +@url{https://forums.libretro.com/t/xbr-algorithm-tutorial/123}. It accepts the following option: @@ -16658,6 +18638,79 @@ Set the scaling dimension: @code{2} for @code{2xBR}, @code{3} for Default is @code{3}. @end table +@section xmedian +Pick median pixels from several input videos. + +The filter accept the following options: + +@table @option +@item inputs +Set number of inputs. +Default is 3. Allowed range is from 3 to 255. +If number of inputs is even number, than result will be mean value between two median values. + +@item planes +Set which planes to filter. Default value is @code{15}, by which all planes are processed. +@end table + +@section xstack +Stack video inputs into custom layout. + +All streams must be of same pixel format. + +The filter accept the following option: + +@table @option +@item inputs +Set number of input streams. Default is 2. + +@item layout +Specify layout of inputs. +This option requires the desired layout configuration to be explicitly set by the user. +This sets position of each video input in output. Each input +is separated by '|'. +The first number represents the column, and the second number represents the row. +Numbers start at 0 and are separated by '_'. Optionally one can use wX and hX, +where X is video input from which to take width or height. +Multiple values can be used when separated by '+'. In such +case values are summed together. + +For 2 inputs, a default layout of @code{0_0|w0_0} is set. In all other cases, +a layout must be set by the user. + +@item shortest +If set to 1, force the output to terminate when the shortest input +terminates. Default value is 0. +@end table + +@subsection Examples + +@itemize +@item +Display 4 inputs into 2x2 grid, +note that if inputs are of different sizes unused gaps might appear, +as not all of output video is used. +@example +xstack=inputs=4:layout=0_0|0_h0|w0_0|w0_h0 +@end example + +@item +Display 4 inputs into 1x4 grid, +note that if inputs are of different sizes unused gaps might appear, +as not all of output video is used. +@example +xstack=inputs=4:layout=0_0|0_h0|0_h0+h1|0_h0+h1+h2 +@end example + +@item +Display 9 inputs into 3x3 grid, +note that if inputs are of different sizes unused gaps might appear, +as not all of output video is used. +@example +xstack=inputs=9:layout=w3_0|w3_h0+h2|w3_h0|0_h4|0_0|w3+w1_0|0_h1+h2|w3+w1_h0|w3+w1_h1+h2 +@end example +@end itemize + @anchor{yadif} @section yadif @@ -16667,6 +18720,64 @@ filter"). It accepts the following parameters: +@table @option + +@item mode +The interlacing mode to adopt. It accepts one of the following values: + +@table @option +@item 0, send_frame +Output one frame for each frame. +@item 1, send_field +Output one frame for each field. +@item 2, send_frame_nospatial +Like @code{send_frame}, but it skips the spatial interlacing check. +@item 3, send_field_nospatial +Like @code{send_field}, but it skips the spatial interlacing check. +@end table + +The default value is @code{send_frame}. + +@item parity +The picture field parity assumed for the input interlaced video. It accepts one +of the following values: + +@table @option +@item 0, tff +Assume the top field is first. +@item 1, bff +Assume the bottom field is first. +@item -1, auto +Enable automatic detection of field parity. +@end table + +The default value is @code{auto}. +If the interlacing is unknown or the decoder does not export this information, +top field first will be assumed. + +@item deint +Specify which frames to deinterlace. Accept one of the following +values: + +@table @option +@item 0, all +Deinterlace all frames. +@item 1, interlaced +Only deinterlace frames marked as interlaced. +@end table + +The default value is @code{all}. +@end table + +@section yadif_cuda + +Deinterlace the input video using the @ref{yadif} algorithm, but implemented +in CUDA so that it can work as part of a GPU accelerated pipeline with nvdec +and/or nvenc. + +It accepts the following parameters: + + @table @option @item mode @@ -16724,7 +18835,7 @@ This filter accepts the following options: @table @option @item zoom, z -Set the zoom expression. Default is 1. +Set the zoom expression. Range is 1-10. Default is 1. @item x @item y @@ -16822,7 +18933,8 @@ zoompan=z='min(max(zoom,pzoom)+0.0015,1.5)':d=1:x='iw/2-(iw/zoom/2)':y='ih/2-(ih @anchor{zscale} @section zscale Scale (resize) the input video, using the z.lib library: -https://github.com/sekrit-twc/zimg. +@url{https://github.com/sekrit-twc/zimg}. To enable compilation of this +filter, you need to configure FFmpeg with @code{--enable-libzimg}. The zscale filter forces the output display aspect ratio to be the same as the input, by changing the output sample aspect ratio. @@ -17084,6 +19196,622 @@ pixel format "yuv422p" @var{hsub} is 2 and @var{vsub} is 1. @c man end VIDEO FILTERS +@chapter OpenCL Video Filters +@c man begin OPENCL VIDEO FILTERS + +Below is a description of the currently available OpenCL video filters. + +To enable compilation of these filters you need to configure FFmpeg with +@code{--enable-opencl}. + +Running OpenCL filters requires you to initialize a hardware device and to pass that device to all filters in any filter graph. +@table @option + +@item -init_hw_device opencl[=@var{name}][:@var{device}[,@var{key=value}...]] +Initialise a new hardware device of type @var{opencl} called @var{name}, using the +given device parameters. + +@item -filter_hw_device @var{name} +Pass the hardware device called @var{name} to all filters in any filter graph. + +@end table + +For more detailed information see @url{https://www.ffmpeg.org/ffmpeg.html#Advanced-Video-options} + +@itemize +@item +Example of choosing the first device on the second platform and running avgblur_opencl filter with default parameters on it. +@example +-init_hw_device opencl=gpu:1.0 -filter_hw_device gpu -i INPUT -vf "hwupload, avgblur_opencl, hwdownload" OUTPUT +@end example +@end itemize + +Since OpenCL filters are not able to access frame data in normal memory, all frame data needs to be uploaded(@ref{hwupload}) to hardware surfaces connected to the appropriate device before being used and then downloaded(@ref{hwdownload}) back to normal memory. Note that @ref{hwupload} will upload to a surface with the same layout as the software frame, so it may be necessary to add a @ref{format} filter immediately before to get the input into the right format and @ref{hwdownload} does not support all formats on the output - it may be necessary to insert an additional @ref{format} filter immediately following in the graph to get the output in a supported format. + +@section avgblur_opencl + +Apply average blur filter. + +The filter accepts the following options: + +@table @option +@item sizeX +Set horizontal radius size. +Range is @code{[1, 1024]} and default value is @code{1}. + +@item planes +Set which planes to filter. Default value is @code{0xf}, by which all planes are processed. + +@item sizeY +Set vertical radius size. Range is @code{[1, 1024]} and default value is @code{0}. If zero, @code{sizeX} value will be used. +@end table + +@subsection Example + +@itemize +@item +Apply average blur filter with horizontal and vertical size of 3, setting each pixel of the output to the average value of the 7x7 region centered on it in the input. For pixels on the edges of the image, the region does not extend beyond the image boundaries, and so out-of-range coordinates are not used in the calculations. +@example +-i INPUT -vf "hwupload, avgblur_opencl=3, hwdownload" OUTPUT +@end example +@end itemize + +@section boxblur_opencl + +Apply a boxblur algorithm to the input video. + +It accepts the following parameters: + +@table @option + +@item luma_radius, lr +@item luma_power, lp +@item chroma_radius, cr +@item chroma_power, cp +@item alpha_radius, ar +@item alpha_power, ap + +@end table + +A description of the accepted options follows. + +@table @option +@item luma_radius, lr +@item chroma_radius, cr +@item alpha_radius, ar +Set an expression for the box radius in pixels used for blurring the +corresponding input plane. + +The radius value must be a non-negative number, and must not be +greater than the value of the expression @code{min(w,h)/2} for the +luma and alpha planes, and of @code{min(cw,ch)/2} for the chroma +planes. + +Default value for @option{luma_radius} is "2". If not specified, +@option{chroma_radius} and @option{alpha_radius} default to the +corresponding value set for @option{luma_radius}. + +The expressions can contain the following constants: +@table @option +@item w +@item h +The input width and height in pixels. + +@item cw +@item ch +The input chroma image width and height in pixels. + +@item hsub +@item vsub +The horizontal and vertical chroma subsample values. For example, for the +pixel format "yuv422p", @var{hsub} is 2 and @var{vsub} is 1. +@end table + +@item luma_power, lp +@item chroma_power, cp +@item alpha_power, ap +Specify how many times the boxblur filter is applied to the +corresponding plane. + +Default value for @option{luma_power} is 2. If not specified, +@option{chroma_power} and @option{alpha_power} default to the +corresponding value set for @option{luma_power}. + +A value of 0 will disable the effect. +@end table + +@subsection Examples + +Apply boxblur filter, setting each pixel of the output to the average value of box-radiuses @var{luma_radius}, @var{chroma_radius}, @var{alpha_radius} for each plane respectively. The filter will apply @var{luma_power}, @var{chroma_power}, @var{alpha_power} times onto the corresponding plane. For pixels on the edges of the image, the radius does not extend beyond the image boundaries, and so out-of-range coordinates are not used in the calculations. + +@itemize +@item +Apply a boxblur filter with the luma, chroma, and alpha radius +set to 2 and luma, chroma, and alpha power set to 3. The filter will run 3 times with box-radius set to 2 for every plane of the image. +@example +-i INPUT -vf "hwupload, boxblur_opencl=luma_radius=2:luma_power=3, hwdownload" OUTPUT +-i INPUT -vf "hwupload, boxblur_opencl=2:3, hwdownload" OUTPUT +@end example + +@item +Apply a boxblur filter with luma radius set to 2, luma_power to 1, chroma_radius to 4, chroma_power to 5, alpha_radius to 3 and alpha_power to 7. + +For the luma plane, a 2x2 box radius will be run once. + +For the chroma plane, a 4x4 box radius will be run 5 times. + +For the alpha plane, a 3x3 box radius will be run 7 times. +@example +-i INPUT -vf "hwupload, boxblur_opencl=2:1:4:5:3:7, hwdownload" OUTPUT +@end example +@end itemize + +@section convolution_opencl + +Apply convolution of 3x3, 5x5, 7x7 matrix. + +The filter accepts the following options: + +@table @option +@item 0m +@item 1m +@item 2m +@item 3m +Set matrix for each plane. +Matrix is sequence of 9, 25 or 49 signed numbers. +Default value for each plane is @code{0 0 0 0 1 0 0 0 0}. + +@item 0rdiv +@item 1rdiv +@item 2rdiv +@item 3rdiv +Set multiplier for calculated value for each plane. +If unset or 0, it will be sum of all matrix elements. +The option value must be a float number greater or equal to @code{0.0}. Default value is @code{1.0}. + +@item 0bias +@item 1bias +@item 2bias +@item 3bias +Set bias for each plane. This value is added to the result of the multiplication. +Useful for making the overall image brighter or darker. +The option value must be a float number greater or equal to @code{0.0}. Default value is @code{0.0}. + +@end table + +@subsection Examples + +@itemize +@item +Apply sharpen: +@example +-i INPUT -vf "hwupload, convolution_opencl=0 -1 0 -1 5 -1 0 -1 0:0 -1 0 -1 5 -1 0 -1 0:0 -1 0 -1 5 -1 0 -1 0:0 -1 0 -1 5 -1 0 -1 0, hwdownload" OUTPUT +@end example + +@item +Apply blur: +@example +-i INPUT -vf "hwupload, convolution_opencl=1 1 1 1 1 1 1 1 1:1 1 1 1 1 1 1 1 1:1 1 1 1 1 1 1 1 1:1 1 1 1 1 1 1 1 1:1/9:1/9:1/9:1/9, hwdownload" OUTPUT +@end example + +@item +Apply edge enhance: +@example +-i INPUT -vf "hwupload, convolution_opencl=0 0 0 -1 1 0 0 0 0:0 0 0 -1 1 0 0 0 0:0 0 0 -1 1 0 0 0 0:0 0 0 -1 1 0 0 0 0:5:1:1:1:0:128:128:128, hwdownload" OUTPUT +@end example + +@item +Apply edge detect: +@example +-i INPUT -vf "hwupload, convolution_opencl=0 1 0 1 -4 1 0 1 0:0 1 0 1 -4 1 0 1 0:0 1 0 1 -4 1 0 1 0:0 1 0 1 -4 1 0 1 0:5:5:5:1:0:128:128:128, hwdownload" OUTPUT +@end example + +@item +Apply laplacian edge detector which includes diagonals: +@example +-i INPUT -vf "hwupload, convolution_opencl=1 1 1 1 -8 1 1 1 1:1 1 1 1 -8 1 1 1 1:1 1 1 1 -8 1 1 1 1:1 1 1 1 -8 1 1 1 1:5:5:5:1:0:128:128:0, hwdownload" OUTPUT +@end example + +@item +Apply emboss: +@example +-i INPUT -vf "hwupload, convolution_opencl=-2 -1 0 -1 1 1 0 1 2:-2 -1 0 -1 1 1 0 1 2:-2 -1 0 -1 1 1 0 1 2:-2 -1 0 -1 1 1 0 1 2, hwdownload" OUTPUT +@end example +@end itemize + +@section dilation_opencl + +Apply dilation effect to the video. + +This filter replaces the pixel by the local(3x3) maximum. + +It accepts the following options: + +@table @option +@item threshold0 +@item threshold1 +@item threshold2 +@item threshold3 +Limit the maximum change for each plane. Range is @code{[0, 65535]} and default value is @code{65535}. +If @code{0}, plane will remain unchanged. + +@item coordinates +Flag which specifies the pixel to refer to. +Range is @code{[0, 255]} and default value is @code{255}, i.e. all eight pixels are used. + +Flags to local 3x3 coordinates region centered on @code{x}: + + 1 2 3 + + 4 x 5 + + 6 7 8 +@end table + +@subsection Example + +@itemize +@item +Apply dilation filter with threshold0 set to 30, threshold1 set 40, threshold2 set to 50 and coordinates set to 231, setting each pixel of the output to the local maximum between pixels: 1, 2, 3, 6, 7, 8 of the 3x3 region centered on it in the input. If the difference between input pixel and local maximum is more then threshold of the corresponding plane, output pixel will be set to input pixel + threshold of corresponding plane. +@example +-i INPUT -vf "hwupload, dilation_opencl=30:40:50:coordinates=231, hwdownload" OUTPUT +@end example +@end itemize + +@section erosion_opencl + +Apply erosion effect to the video. + +This filter replaces the pixel by the local(3x3) minimum. + +It accepts the following options: + +@table @option +@item threshold0 +@item threshold1 +@item threshold2 +@item threshold3 +Limit the maximum change for each plane. Range is @code{[0, 65535]} and default value is @code{65535}. +If @code{0}, plane will remain unchanged. + +@item coordinates +Flag which specifies the pixel to refer to. +Range is @code{[0, 255]} and default value is @code{255}, i.e. all eight pixels are used. + +Flags to local 3x3 coordinates region centered on @code{x}: + + 1 2 3 + + 4 x 5 + + 6 7 8 +@end table + +@subsection Example + +@itemize +@item +Apply erosion filter with threshold0 set to 30, threshold1 set 40, threshold2 set to 50 and coordinates set to 231, setting each pixel of the output to the local minimum between pixels: 1, 2, 3, 6, 7, 8 of the 3x3 region centered on it in the input. If the difference between input pixel and local minimum is more then threshold of the corresponding plane, output pixel will be set to input pixel - threshold of corresponding plane. +@example +-i INPUT -vf "hwupload, erosion_opencl=30:40:50:coordinates=231, hwdownload" OUTPUT +@end example +@end itemize + +@section colorkey_opencl +RGB colorspace color keying. + +The filter accepts the following options: + +@table @option +@item color +The color which will be replaced with transparency. + +@item similarity +Similarity percentage with the key color. + +0.01 matches only the exact key color, while 1.0 matches everything. + +@item blend +Blend percentage. + +0.0 makes pixels either fully transparent, or not transparent at all. + +Higher values result in semi-transparent pixels, with a higher transparency +the more similar the pixels color is to the key color. +@end table + +@subsection Examples + +@itemize +@item +Make every semi-green pixel in the input transparent with some slight blending: +@example +-i INPUT -vf "hwupload, colorkey_opencl=green:0.3:0.1, hwdownload" OUTPUT +@end example +@end itemize + +@section nlmeans_opencl + +Non-local Means denoise filter through OpenCL, this filter accepts same options as @ref{nlmeans}. + +@section overlay_opencl + +Overlay one video on top of another. + +It takes two inputs and has one output. The first input is the "main" video on which the second input is overlaid. +This filter requires same memory layout for all the inputs. So, format conversion may be needed. + +The filter accepts the following options: + +@table @option + +@item x +Set the x coordinate of the overlaid video on the main video. +Default value is @code{0}. + +@item y +Set the x coordinate of the overlaid video on the main video. +Default value is @code{0}. + +@end table + +@subsection Examples + +@itemize +@item +Overlay an image LOGO at the top-left corner of the INPUT video. Both inputs are yuv420p format. +@example +-i INPUT -i LOGO -filter_complex "[0:v]hwupload[a], [1:v]format=yuv420p, hwupload[b], [a][b]overlay_opencl, hwdownload" OUTPUT +@end example +@item +The inputs have same memory layout for color channels , the overlay has additional alpha plane, like INPUT is yuv420p, and the LOGO is yuva420p. +@example +-i INPUT -i LOGO -filter_complex "[0:v]hwupload[a], [1:v]format=yuva420p, hwupload[b], [a][b]overlay_opencl, hwdownload" OUTPUT +@end example + +@end itemize + +@section prewitt_opencl + +Apply the Prewitt operator (@url{https://en.wikipedia.org/wiki/Prewitt_operator}) to input video stream. + +The filter accepts the following option: + +@table @option +@item planes +Set which planes to filter. Default value is @code{0xf}, by which all planes are processed. + +@item scale +Set value which will be multiplied with filtered result. +Range is @code{[0.0, 65535]} and default value is @code{1.0}. + +@item delta +Set value which will be added to filtered result. +Range is @code{[-65535, 65535]} and default value is @code{0.0}. +@end table + +@subsection Example + +@itemize +@item +Apply the Prewitt operator with scale set to 2 and delta set to 10. +@example +-i INPUT -vf "hwupload, prewitt_opencl=scale=2:delta=10, hwdownload" OUTPUT +@end example +@end itemize + +@section roberts_opencl +Apply the Roberts cross operator (@url{https://en.wikipedia.org/wiki/Roberts_cross}) to input video stream. + +The filter accepts the following option: + +@table @option +@item planes +Set which planes to filter. Default value is @code{0xf}, by which all planes are processed. + +@item scale +Set value which will be multiplied with filtered result. +Range is @code{[0.0, 65535]} and default value is @code{1.0}. + +@item delta +Set value which will be added to filtered result. +Range is @code{[-65535, 65535]} and default value is @code{0.0}. +@end table + +@subsection Example + +@itemize +@item +Apply the Roberts cross operator with scale set to 2 and delta set to 10 +@example +-i INPUT -vf "hwupload, roberts_opencl=scale=2:delta=10, hwdownload" OUTPUT +@end example +@end itemize + +@section sobel_opencl + +Apply the Sobel operator (@url{https://en.wikipedia.org/wiki/Sobel_operator}) to input video stream. + +The filter accepts the following option: + +@table @option +@item planes +Set which planes to filter. Default value is @code{0xf}, by which all planes are processed. + +@item scale +Set value which will be multiplied with filtered result. +Range is @code{[0.0, 65535]} and default value is @code{1.0}. + +@item delta +Set value which will be added to filtered result. +Range is @code{[-65535, 65535]} and default value is @code{0.0}. +@end table + +@subsection Example + +@itemize +@item +Apply sobel operator with scale set to 2 and delta set to 10 +@example +-i INPUT -vf "hwupload, sobel_opencl=scale=2:delta=10, hwdownload" OUTPUT +@end example +@end itemize + +@section tonemap_opencl + +Perform HDR(PQ/HLG) to SDR conversion with tone-mapping. + +It accepts the following parameters: + +@table @option +@item tonemap +Specify the tone-mapping operator to be used. Same as tonemap option in @ref{tonemap}. + +@item param +Tune the tone mapping algorithm. same as param option in @ref{tonemap}. + +@item desat +Apply desaturation for highlights that exceed this level of brightness. The +higher the parameter, the more color information will be preserved. This +setting helps prevent unnaturally blown-out colors for super-highlights, by +(smoothly) turning into white instead. This makes images feel more natural, +at the cost of reducing information about out-of-range colors. + +The default value is 0.5, and the algorithm here is a little different from +the cpu version tonemap currently. A setting of 0.0 disables this option. + +@item threshold +The tonemapping algorithm parameters is fine-tuned per each scene. And a threshold +is used to detect whether the scene has changed or not. If the distance between +the current frame average brightness and the current running average exceeds +a threshold value, we would re-calculate scene average and peak brightness. +The default value is 0.2. + +@item format +Specify the output pixel format. + +Currently supported formats are: +@table @var +@item p010 +@item nv12 +@end table + +@item range, r +Set the output color range. + +Possible values are: +@table @var +@item tv/mpeg +@item pc/jpeg +@end table + +Default is same as input. + +@item primaries, p +Set the output color primaries. + +Possible values are: +@table @var +@item bt709 +@item bt2020 +@end table + +Default is same as input. + +@item transfer, t +Set the output transfer characteristics. + +Possible values are: +@table @var +@item bt709 +@item bt2020 +@end table + +Default is bt709. + +@item matrix, m +Set the output colorspace matrix. + +Possible value are: +@table @var +@item bt709 +@item bt2020 +@end table + +Default is same as input. + +@end table + +@subsection Example + +@itemize +@item +Convert HDR(PQ/HLG) video to bt2020-transfer-characteristic p010 format using linear operator. +@example +-i INPUT -vf "format=p010,hwupload,tonemap_opencl=t=bt2020:tonemap=linear:format=p010,hwdownload,format=p010" OUTPUT +@end example +@end itemize + +@section unsharp_opencl + +Sharpen or blur the input video. + +It accepts the following parameters: + +@table @option +@item luma_msize_x, lx +Set the luma matrix horizontal size. +Range is @code{[1, 23]} and default value is @code{5}. + +@item luma_msize_y, ly +Set the luma matrix vertical size. +Range is @code{[1, 23]} and default value is @code{5}. + +@item luma_amount, la +Set the luma effect strength. +Range is @code{[-10, 10]} and default value is @code{1.0}. + +Negative values will blur the input video, while positive values will +sharpen it, a value of zero will disable the effect. + +@item chroma_msize_x, cx +Set the chroma matrix horizontal size. +Range is @code{[1, 23]} and default value is @code{5}. + +@item chroma_msize_y, cy +Set the chroma matrix vertical size. +Range is @code{[1, 23]} and default value is @code{5}. + +@item chroma_amount, ca +Set the chroma effect strength. +Range is @code{[-10, 10]} and default value is @code{0.0}. + +Negative values will blur the input video, while positive values will +sharpen it, a value of zero will disable the effect. + +@end table + +All parameters are optional and default to the equivalent of the +string '5:5:1.0:5:5:0.0'. + +@subsection Examples + +@itemize +@item +Apply strong luma sharpen effect: +@example +-i INPUT -vf "hwupload, unsharp_opencl=luma_msize_x=7:luma_msize_y=7:luma_amount=2.5, hwdownload" OUTPUT +@end example + +@item +Apply a strong blur of both luma and chroma parameters: +@example +-i INPUT -vf "hwupload, unsharp_opencl=7:7:-2:7:7:-2, hwdownload" OUTPUT +@end example +@end itemize + +@c man end OPENCL VIDEO FILTERS + @chapter Video Sources @c man begin VIDEO SOURCES @@ -17376,7 +20104,7 @@ Set outer coloring mode. It shall assume one of following values: @table @option @item iteration_count -Set iteration cound mode. +Set iteration count mode. @item normalized_iteration_count set normalized iteration count mode. @end table @@ -17625,13 +20353,15 @@ ffplay -f lavfi life=s=300x200:mold=10:r=60:ratio=0.1:death_color=#C83232:life_c @anchor{color} @anchor{haldclutsrc} @anchor{nullsrc} +@anchor{pal75bars} +@anchor{pal100bars} @anchor{rgbtestsrc} @anchor{smptebars} @anchor{smptehdbars} @anchor{testsrc} @anchor{testsrc2} @anchor{yuvtestsrc} -@section allrgb, allyuv, color, haldclutsrc, nullsrc, rgbtestsrc, smptebars, smptehdbars, testsrc, testsrc2, yuvtestsrc +@section allrgb, allyuv, color, haldclutsrc, nullsrc, pal75bars, pal100bars, rgbtestsrc, smptebars, smptehdbars, testsrc, testsrc2, yuvtestsrc The @code{allrgb} source returns frames of size 4096x4096 of all rgb colors. @@ -17646,6 +20376,12 @@ The @code{nullsrc} source returns unprocessed video frames. It is mainly useful to be employed in analysis / debugging tools, or as the source for filters which ignore the input data. +The @code{pal75bars} source generates a color bars pattern, based on +EBU PAL recommendations with 75% color levels. + +The @code{pal100bars} source generates a color bars pattern, based on +EBU PAL recommendations with 100% color levels. + The @code{rgbtestsrc} source generates an RGB test pattern useful for detecting RGB vs BGR issues. You should see a red, green and blue stripe from top to bottom. @@ -17946,7 +20682,7 @@ Default is @code{log}. @item acount Set how much frames to accumulate in histogram. -Defauls is 1. Setting this to -1 accumulates all frames. +Default is 1. Setting this to -1 accumulates all frames. @item rheight Set histogram ratio of window height. @@ -17966,9 +20702,15 @@ Default is @code{replace}. @section aphasemeter -Convert input audio to a video output, displaying the audio phase. +Measures phase of input audio, which is exported as metadata @code{lavfi.aphasemeter.phase}, +representing mean phase of current audio frame. A video output can also be produced and is +enabled by default. The audio is passed through as first output. -The filter accepts the following options: +Audio will be rematrixed to stereo if it has a different channel layout. Phase value is in +range @code{[-1, 1]} where @code{-1} means left and right channels are completely out of phase +and @code{1} means channels are in phase. + +The filter accepts the following options, all related to its video output: @table @option @item rate, r @@ -17994,11 +20736,6 @@ Set color which will be used for drawing median phase. If color is Enable video output. Default is enabled. @end table -The filter also exports the frame metadata @code{lavfi.aphasemeter.phase} which -represents mean phase of current audio frame. Value is in range @code{[-1, 1]}. -The @code{-1} means left and right channels are completely out of phase and -@code{1} means channels are in phase. - @section avectorscope Convert input audio to a video output, representing the audio vector @@ -18354,17 +21091,26 @@ ebur128=metadata=1,adrawgraph=lavfi.r128.M:min=-120:max=5 @anchor{ebur128} @section ebur128 -EBU R128 scanner filter. This filter takes an audio stream as input and outputs -it unchanged. By default, it logs a message at a frequency of 10Hz with the +EBU R128 scanner filter. This filter takes an audio stream and analyzes its loudness +level. By default, it logs a message at a frequency of 10Hz with the Momentary loudness (identified by @code{M}), Short-term loudness (@code{S}), Integrated loudness (@code{I}) and Loudness Range (@code{LRA}). +The filter can only analyze streams which have a sampling rate of 48000 Hz and whose +sample format is double-precision floating point. The input stream will be converted to +this specification, if needed. Users may need to insert aformat and/or aresample filters +after this filter to obtain the original parameters. + The filter also has a video output (see the @var{video} option) with a real time graph to observe the loudness evolution. The graphic contains the logged message mentioned above, so it is not printed anymore when this option is set, unless the verbose logging is set. The main graphing area contains the short-term loudness (3 seconds of analysis), and the gauge on the right is for -the momentary loudness (400 milliseconds). +the momentary loudness (400 milliseconds), but can optionally be configured +to instead display short-term loudness (see @var{gauge}). + +The green area marks a +/- 1LU target range around the target loudness +(-23LUFS by default, unless modified through @var{target}). More information about the Loudness Recommendation EBU R128 on @url{http://tech.ebu.ch/loudness}. @@ -18441,6 +21187,23 @@ Multi-channel input files are not affected by this option. @item panlaw Set a specific pan law to be used for the measurement of dual mono files. This parameter is optional, and has a default value of -3.01dB. + +@item target +Set a specific target level (in LUFS) used as relative zero in the visualization. +This parameter is optional and has a default value of -23LUFS as specified +by EBU R128. However, material published online may prefer a level of -16LUFS +(e.g. for use with podcasts or video platforms). + +@item gauge +Set the value displayed by the gauge. Valid values are @code{momentary} and s +@code{shortterm}. By default the momentary value will be used, but in certain +scenarios it may be more useful to observe the short term value instead (e.g. +live mixing). + +@item scale +Sets the display scale for the loudness. Valid parameters are @code{absolute} +(in LUFS) or @code{relative} (LU) relative to the target. This only affects the +video output, not the summary or continuous log output. @end table @subsection Examples @@ -18671,6 +21434,14 @@ They accept the following options: @item limit Time limit for the pauses. Any pause longer than that will be considered a timestamp discontinuity and reset the timer. Default is 2 seconds. +@item speed +Speed factor for processing. The value must be a float larger than zero. +Values larger than 1.0 will result in faster than realtime processing, +smaller will slow processing down. The @var{limit} is automatically adapted +accordingly. Default is 1.0. + +A processing speed faster than what is possible without these filters cannot +be achieved. @end table @anchor{select} @@ -19041,7 +21812,7 @@ The expression is evaluated through the eval API and can contain the following constants: @table @option -@item FRAME_RATE +@item FRAME_RATE, FR frame rate, only defined for constant frame-rate video @item PTS @@ -19581,25 +22352,9 @@ Reverse logarithmic scale. Default is @code{lin}. @item win_size -Set window size. +Set window size. Allowed range is from 16 to 65536. -It accepts the following values: -@table @samp -@item w16 -@item w32 -@item w64 -@item w128 -@item w256 -@item w512 -@item w1024 -@item w2048 -@item w4096 -@item w8192 -@item w16384 -@item w32768 -@item w65536 -@end table -Default is @code{w2048} +Default is @code{2048} @item win_func Set windowing function. @@ -19625,6 +22380,7 @@ It accepts the following values: @item cauchy @item parzen @item poisson +@item bohman @end table Default is @code{hanning}. @@ -19656,6 +22412,58 @@ Set minimum amplitude used in @code{log} amplitude scaler. @end table +@section showspatial + +Convert stereo input audio to a video output, representing the spatial relationship +between two channels. + +The filter accepts the following options: + +@table @option +@item size, s +Specify the video size for the output. For the syntax of this option, check the +@ref{video size syntax,,"Video size" section in the ffmpeg-utils manual,ffmpeg-utils}. +Default value is @code{512x512}. + +@item win_size +Set window size. Allowed range is from @var{1024} to @var{65536}. Default size is @var{4096}. + +@item win_func +Set window function. + +It accepts the following values: +@table @samp +@item rect +@item bartlett +@item hann +@item hanning +@item hamming +@item blackman +@item welch +@item flattop +@item bharris +@item bnuttall +@item bhann +@item sine +@item nuttall +@item lanczos +@item gauss +@item tukey +@item dolph +@item cauchy +@item parzen +@item poisson +@item bohman +@end table + +Default value is @code{hann}. + +@item overlap +Set ratio of overlap window. Default value is @code{0.5}. +When value is @code{1} overlap is set to recommended size for specific +window function currently used. +@end table + @anchor{showspectrum} @section showspectrum @@ -19723,6 +22531,18 @@ each channel is displayed using the fiery color scheme each channel is displayed using the fruit color scheme @item cool each channel is displayed using the cool color scheme +@item magma +each channel is displayed using the magma color scheme +@item green +each channel is displayed using the green color scheme +@item viridis +each channel is displayed using the viridis color scheme +@item plasma +each channel is displayed using the plasma color scheme +@item cividis +each channel is displayed using the cividis color scheme +@item terrain +each channel is displayed using the terrain color scheme @end table Default value is @samp{channel}. @@ -19748,6 +22568,19 @@ logarithmic Default value is @samp{sqrt}. +@item fscale +Specify frequency scale. + +It accepts the following values: +@table @samp +@item lin +linear +@item log +logarithmic +@end table + +Default value is @samp{lin}. + @item saturation Set saturation modifier for displayed colors. Negative values provide alternative color scheme. @code{0} is no saturation at all. @@ -19779,6 +22612,7 @@ It accepts the following values: @item cauchy @item parzen @item poisson +@item bohman @end table Default value is @code{hann}. @@ -19802,6 +22636,18 @@ Set which data to display. Can be @code{magnitude}, default or @code{phase}. @item rotation Set color rotation, must be in [-1.0, 1.0] range. Default value is @code{0}. + +@item start +Set start frequency from which to display spectrogram. Default is @code{0}. + +@item stop +Set stop frequency to which to display spectrogram. Default is @code{0}. + +@item fps +Set upper frame rate limit. Default is @code{auto}, unlimited. + +@item legend +Draw time and frequency axes and legends. Default is disabled. @end table The usage is very similar to the showwaves filter; see the examples in that @@ -19872,6 +22718,18 @@ each channel is displayed using the fiery color scheme each channel is displayed using the fruit color scheme @item cool each channel is displayed using the cool color scheme +@item magma +each channel is displayed using the magma color scheme +@item green +each channel is displayed using the green color scheme +@item viridis +each channel is displayed using the viridis color scheme +@item plasma +each channel is displayed using the plasma color scheme +@item cividis +each channel is displayed using the cividis color scheme +@item terrain +each channel is displayed using the terrain color scheme @end table Default value is @samp{intensity}. @@ -19895,6 +22753,19 @@ logarithmic @end table Default value is @samp{log}. +@item fscale +Specify frequency scale. + +It accepts the following values: +@table @samp +@item lin +linear +@item log +logarithmic +@end table + +Default value is @samp{lin}. + @item saturation Set saturation modifier for displayed colors. Negative values provide alternative color scheme. @code{0} is no saturation at all. @@ -19926,6 +22797,7 @@ It accepts the following values: @item cauchy @item parzen @item poisson +@item bohman @end table Default value is @code{hann}. @@ -19943,6 +22815,12 @@ Draw time and frequency axes and legends. Default is enabled. @item rotation Set color rotation, must be in [-1.0, 1.0] range. Default value is @code{0}. + +@item start +Set start frequency from which to display spectrogram. Default is @code{0}. + +@item stop +Set stop frequency to which to display spectrogram. Default is @code{0}. @end table @subsection Examples @@ -20168,6 +23046,20 @@ Cubic root. @end table Default is linear. + +@item draw +Set the draw mode. + +Available values are: +@table @samp +@item scale +Scale pixel values for each drawn sample. + +@item full +Draw every sample directly. +@end table + +Default value is @code{scale}. @end table @subsection Examples @@ -20222,7 +23114,7 @@ This filter is primarily created for reversing processed @ref{showspectrum} filter outputs, but can synthesize sound from other spectrograms too. But in such case results are going to be poor if the phase data is not available, because in such cases phase data need to be recreated, usually -its just recreated from random noise. +it's just recreated from random noise. For best results use gray only output (@code{channel} color mode in @ref{showspectrum} filter) and @code{log} scale for magnitude video and @code{lin} scale for phase video. To produce phase, for 2nd video, use diff --git a/doc/formats.texi b/doc/formats.texi index ddd774354..729c77b01 100644 --- a/doc/formats.texi +++ b/doc/formats.texi @@ -30,37 +30,43 @@ latency. Must be an integer not lesser than 32. It is 5000000 by default. @item packetsize @var{integer} (@emph{output}) Set packet size. -@item fflags @var{flags} (@emph{input/output}) -Set format flags. +@item fflags @var{flags} +Set format flags. Some are implemented for a limited number of formats. -Possible values: +Possible values for input files: @table @samp -@item ignidx -Ignore index. +@item discardcorrupt +Discard corrupted packets. @item fastseek Enable fast, but inaccurate seeks for some formats. @item genpts -Generate PTS. +Generate missing PTS if DTS is present. +@item igndts +Ignore DTS if PTS is set. Inert when nofillin is set. +@item ignidx +Ignore index. +@item keepside (@emph{deprecated},@emph{inert}) +@item nobuffer +Reduce the latency introduced by buffering during initial input streams analysis. @item nofillin -Do not fill in missing values that can be exactly calculated. +Do not fill in missing values in packet fields that can be exactly calculated. @item noparse Disable AVParsers, this needs @code{+nofillin} too. -@item igndts -Ignore DTS. -@item discardcorrupt -Discard corrupted frames. @item sortdts -Try to interleave output packets by DTS. -@item keepside -Do not merge side data. -@item latm -Enable RTP MP4A-LATM payload. -@item nobuffer -Reduce the latency introduced by optional buffering +Try to interleave output packets by DTS. At present, available only for AVIs with an index. +@end table + +Possible values for output files: +@table @samp +@item autobsf +Automatically apply bitstream filters as required by the output format. Enabled by default. @item bitexact Only write platform-, build- and time-independent data. This ensures that file and data checksums are reproducible and match between platforms. Its primary use is for regression testing. +@item flush_packets +Write out packets immediately. +@item latm (@emph{deprecated},@emph{inert}) @item shortest Stop muxing at the end of the shortest stream. It may be needed to increase max_interleave_delta to avoid flushing the longer @@ -205,7 +211,7 @@ is @code{0} (meaning that no offset is applied). @item dump_separator @var{string} (@emph{input}) Separator used to separate the fields printed on the command line about the Stream parameters. -For example to separate the fields with newlines and indention: +For example, to separate the fields with newlines and indentation: @example ffprobe -dump_separator " " -i ~/videos/matrixbench_mpeg2.mpg @@ -214,6 +220,32 @@ ffprobe -dump_separator " @item max_streams @var{integer} (@emph{input}) Specifies the maximum number of streams. This can be used to reject files that would require too many resources due to a large number of streams. + +@item skip_estimate_duration_from_pts @var{bool} (@emph{input}) +Skip estimation of input duration when calculated using PTS. +At present, applicable for MPEG-PS and MPEG-TS. + +@item strict, f_strict @var{integer} (@emph{input/output}) +Specify how strictly to follow the standards. @code{f_strict} is deprecated and +should be used only via the @command{ffmpeg} tool. + +Possible values: +@table @samp +@item very +strictly conform to an older more strict version of the spec or reference software +@item strict +strictly conform to all the things in the spec no matter what consequences +@item normal + +@item unofficial +allow unofficial extensions +@item experimental +allow non standardized experimental things, experimental +(unfinished/work in progress/not well tested) decoders and encoders. +Note: experimental decoders can pose a security risk, do not use this for +decoding untrusted input. +@end table + @end table @c man end FORMAT OPTIONS @@ -224,30 +256,10 @@ would require too many resources due to a large number of streams. Format stream specifiers allow selection of one or more streams that match specific properties. -Possible forms of stream specifiers are: -@table @option -@item @var{stream_index} -Matches the stream with this index. - -@item @var{stream_type}[:@var{stream_index}] -@var{stream_type} is one of following: 'v' for video, 'a' for audio, -'s' for subtitle, 'd' for data, and 't' for attachments. If -@var{stream_index} is given, then it matches the stream number -@var{stream_index} of this type. Otherwise, it matches all streams of -this type. - -@item p:@var{program_id}[:@var{stream_index}] -If @var{stream_index} is given, then it matches the stream with number -@var{stream_index} in the program with the id -@var{program_id}. Otherwise, it matches all streams in the program. - -@item #@var{stream_id} -Matches the stream by a format-specific ID. -@end table - The exact semantics of stream specifiers is defined by the @code{avformat_match_stream_specifier()} function declared in the -@file{libavformat/avformat.h} header. +@file{libavformat/avformat.h} header and documented in the +@ref{Stream specifiers,,Stream specifiers section in the ffmpeg(1) manual,ffmpeg}. @ifclear config-writeonly @include demuxers.texi diff --git a/doc/general.texi b/doc/general.texi index 2583006b1..3c0c80344 100644 --- a/doc/general.texi +++ b/doc/general.texi @@ -17,21 +17,164 @@ for more formats. None of them are used by default, their use has to be explicitly requested by passing the appropriate flags to @command{./configure}. -@section Alliance for Open Media libaom +@section Alliance for Open Media (AOM) -FFmpeg can make use of the libaom library for AV1 decoding. +FFmpeg can make use of the AOM library for AV1 decoding and encoding. Go to @url{http://aomedia.org/} and follow the instructions for installing the library. Then pass @code{--enable-libaom} to configure to enable it. -@section OpenJPEG +@section AMD AMF/VCE -FFmpeg can use the OpenJPEG libraries for encoding/decoding J2K videos. Go to -@url{http://www.openjpeg.org/} to get the libraries and follow the installation -instructions. To enable using OpenJPEG in FFmpeg, pass @code{--enable-libopenjpeg} to -@file{./configure}. +FFmpeg can use the AMD Advanced Media Framework library under Windows +for accelerated H.264 and HEVC encoding on hardware with Video Coding Engine (VCE). +To enable support you must obtain the AMF framework header files from +@url{https://github.com/GPUOpen-LibrariesAndSDKs/AMF.git}. + +Create an @code{AMF/} directory in the system include path. +Copy the contents of @code{AMF/amf/public/include/} into that directory. +Then configure FFmpeg with @code{--enable-amf}. + +@section AviSynth + +FFmpeg can read AviSynth scripts as input. To enable support, pass +@code{--enable-avisynth} to configure. The correct headers are +included in compat/avisynth/, which allows the user to enable support +without needing to search for these headers themselves. + +For Windows, supported AviSynth variants are +@url{http://avisynth.nl, AviSynth 2.6 RC1 or higher} for 32-bit builds and +@url{http://avisynth.nl/index.php/AviSynth+, AviSynth+ r1718 or higher} for 32-bit and 64-bit builds. + +For Linux and OS X, the supported AviSynth variant is +@url{https://github.com/avxsynth/avxsynth, AvxSynth}. + +@float NOTE +In 2016, AviSynth+ added support for building with GCC. However, due to +the eccentricities of Windows' calling conventions, 32-bit GCC builds +of AviSynth+ are not compatible with typical 32-bit builds of FFmpeg. + +By default, FFmpeg assumes compatibility with 32-bit MSVC builds of +AviSynth+ since that is the most widely-used and entrenched build +configuration. Users can override this and enable support for 32-bit +GCC builds of AviSynth+ by passing @code{-DAVSC_WIN32_GCC32} to +@code{--extra-cflags} when configuring FFmpeg. + +64-bit builds of FFmpeg are not affected, and can use either MSVC or +GCC builds of AviSynth+ without any special flags. +@end float + +@float NOTE +AviSynth and AvxSynth are loaded dynamically. Distributors can build FFmpeg +with @code{--enable-avisynth}, and the binaries will work regardless of the +end user having AviSynth or AvxSynth installed - they'll only need to be +installed to use AviSynth scripts (obviously). +@end float + +@section Chromaprint + +FFmpeg can make use of the Chromaprint library for generating audio fingerprints. +Pass @code{--enable-chromaprint} to configure to +enable it. See @url{https://acoustid.org/chromaprint}. + +@section codec2 + +FFmpeg can make use of the codec2 library for codec2 decoding and encoding. +There is currently no native decoder, so libcodec2 must be used for decoding. + +Go to @url{http://freedv.org/}, download "Codec 2 source archive". +Build and install using CMake. Debian users can install the libcodec2-dev package instead. +Once libcodec2 is installed you can pass @code{--enable-libcodec2} to configure to enable it. + +The easiest way to use codec2 is with .c2 files, since they contain the mode information required for decoding. +To encode such a file, use a .c2 file extension and give the libcodec2 encoder the -mode option: +@code{ffmpeg -i input.wav -mode 700C output.c2}. +Playback is as simple as @code{ffplay output.c2}. +For a list of supported modes, run @code{ffmpeg -h encoder=libcodec2}. +Raw codec2 files are also supported. +To make sense of them the mode in use needs to be specified as a format option: +@code{ffmpeg -f codec2raw -mode 1300 -i input.raw output.wav}. + +@section dav1d + +FFmpeg can make use of the dav1d library for AV1 video decoding. + +Go to @url{https://code.videolan.org/videolan/dav1d} and follow the instructions for +installing the library. Then pass @code{--enable-libdav1d} to configure to enable it. + +@section davs2 + +FFmpeg can make use of the davs2 library for AVS2-P2/IEEE1857.4 video decoding. + +Go to @url{https://github.com/pkuvcl/davs2} and follow the instructions for +installing the library. Then pass @code{--enable-libdavs2} to configure to +enable it. + +@float NOTE +libdavs2 is under the GNU Public License Version 2 or later +(see @url{http://www.gnu.org/licenses/old-licenses/gpl-2.0.html} for +details), you must upgrade FFmpeg's license to GPL in order to use it. +@end float + +@section Game Music Emu + +FFmpeg can make use of the Game Music Emu library to read audio from supported video game +music file formats. Pass @code{--enable-libgme} to configure to +enable it. See @url{https://bitbucket.org/mpyne/game-music-emu/overview}. + +@section Intel QuickSync Video + +FFmpeg can use Intel QuickSync Video (QSV) for accelerated decoding and encoding +of multiple codecs. To use QSV, FFmpeg must be linked against the @code{libmfx} +dispatcher, which loads the actual decoding libraries. + +The dispatcher is open source and can be downloaded from +@url{https://github.com/lu-zero/mfx_dispatch.git}. FFmpeg needs to be configured +with the @code{--enable-libmfx} option and @code{pkg-config} needs to be able to +locate the dispatcher's @code{.pc} files. + +@section Kvazaar + +FFmpeg can make use of the Kvazaar library for HEVC encoding. + +Go to @url{https://github.com/ultravideo/kvazaar} and follow the +instructions for installing the library. Then pass +@code{--enable-libkvazaar} to configure to enable it. + +@section LAME + +FFmpeg can make use of the LAME library for MP3 encoding. + +Go to @url{http://lame.sourceforge.net/} and follow the +instructions for installing the library. +Then pass @code{--enable-libmp3lame} to configure to enable it. + +@section libilbc + +iLBC is a narrowband speech codec that has been made freely available +by Google as part of the WebRTC project. libilbc is a packaging friendly +copy of the iLBC codec. FFmpeg can make use of the libilbc library for +iLBC decoding and encoding. + +Go to @url{https://github.com/TimothyGu/libilbc} and follow the instructions for +installing the library. Then pass @code{--enable-libilbc} to configure to +enable it. + +@section libvpx + +FFmpeg can make use of the libvpx library for VP8/VP9 decoding and encoding. + +Go to @url{http://www.webmproject.org/} and follow the instructions for +installing the library. Then pass @code{--enable-libvpx} to configure to +enable it. + +@section ModPlug + +FFmpeg can make use of this library, originating in Modplug-XMMS, to read from MOD-like music files. +See @url{https://github.com/Konstanty/libmodplug}. Pass @code{--enable-libmodplug} to configure to +enable it. @section OpenCORE, VisualOn, and Fraunhofer libraries @@ -46,9 +189,10 @@ upgrade FFmpeg's license to LGPL version 3 (or if you have enabled GPL components, GPL version 3) by passing @code{--enable-version3} to configure in order to use it. -The Fraunhofer AAC library is licensed under a license incompatible to the GPL -and is not known to be compatible to the LGPL. Therefore, you have to pass -@code{--enable-nonfree} to configure to use it. +The license of the Fraunhofer AAC library is incompatible with the GPL. +Therefore, for GPL builds, you have to pass @code{--enable-nonfree} to +configure in order to use it. To the best of our knowledge, it is +compatible with the LGPL. @end float @subsection OpenCORE AMR @@ -71,73 +215,15 @@ Then pass @code{--enable-libvo-amrwbenc} to configure to enable it. @subsection Fraunhofer AAC library -FFmpeg can make use of the Fraunhofer AAC library for AAC encoding. +FFmpeg can make use of the Fraunhofer AAC library for AAC decoding & encoding. Go to @url{http://sourceforge.net/projects/opencore-amr/} and follow the instructions for installing the library. Then pass @code{--enable-libfdk-aac} to configure to enable it. -@section LAME - -FFmpeg can make use of the LAME library for MP3 encoding. - -Go to @url{http://lame.sourceforge.net/} and follow the -instructions for installing the library. -Then pass @code{--enable-libmp3lame} to configure to enable it. - -@section TwoLAME - -FFmpeg can make use of the TwoLAME library for MP2 encoding. - -Go to @url{http://www.twolame.org/} and follow the -instructions for installing the library. -Then pass @code{--enable-libtwolame} to configure to enable it. - -@section libcodec2 / codec2 general - -FFmpeg can make use of libcodec2 for codec2 encoding and decoding. -There is currently no native decoder, so libcodec2 must be used for decoding. - -Go to @url{http://freedv.org/}, download "Codec 2 source archive". -Build and install using CMake. Debian users can install the libcodec2-dev package instead. -Once libcodec2 is installed you can pass @code{--enable-libcodec2} to configure to enable it. - -The easiest way to use codec2 is with .c2 files, since they contain the mode information required for decoding. -To encode such a file, use a .c2 file extension and give the libcodec2 encoder the -mode option: -@code{ffmpeg -i input.wav -mode 700C output.c2}. -Playback is as simple as @code{ffplay output.c2}. -For a list of supported modes, run @code{ffmpeg -h encoder=libcodec2}. -Raw codec2 files are also supported. -To make sense of them the mode in use needs to be specified as a format option: -@code{ffmpeg -f codec2raw -mode 1300 -i input.raw output.wav}. - -@section libvpx - -FFmpeg can make use of the libvpx library for VP8/VP9 encoding. - -Go to @url{http://www.webmproject.org/} and follow the instructions for -installing the library. Then pass @code{--enable-libvpx} to configure to -enable it. - -@section libwavpack - -FFmpeg can make use of the libwavpack library for WavPack encoding. - -Go to @url{http://www.wavpack.com/} and follow the instructions for -installing the library. Then pass @code{--enable-libwavpack} to configure to -enable it. - -@section libxavs - -FFmpeg can make use of the libxavs library for Xavs encoding. - -Go to @url{http://xavs.sf.net/} and follow the instructions for -installing the library. Then pass @code{--enable-libxavs} to configure to -enable it. - @section OpenH264 -FFmpeg can make use of the OpenH264 library for H.264 encoding and decoding. +FFmpeg can make use of the OpenH264 library for H.264 decoding and encoding. Go to @url{http://www.openh264.org/} and follow the instructions for installing the library. Then pass @code{--enable-libopenh264} to configure to @@ -150,6 +236,40 @@ constrained baseline profile and CABAC.) Using it is mostly useful for testing and for taking advantage of Cisco's patent portfolio license (@url{http://www.openh264.org/BINARY_LICENSE.txt}). +@section OpenJPEG + +FFmpeg can use the OpenJPEG libraries for decoding/encoding J2K videos. Go to +@url{http://www.openjpeg.org/} to get the libraries and follow the installation +instructions. To enable using OpenJPEG in FFmpeg, pass @code{--enable-libopenjpeg} to +@file{./configure}. + +@section TwoLAME + +FFmpeg can make use of the TwoLAME library for MP2 encoding. + +Go to @url{http://www.twolame.org/} and follow the +instructions for installing the library. +Then pass @code{--enable-libtwolame} to configure to enable it. + +@section VapourSynth + +FFmpeg can read VapourSynth scripts as input. To enable support, pass +@code{--enable-vapoursynth} to configure. Vapoursynth is detected via +@code{pkg-config}. Versions 42 or greater supported. +See @url{http://www.vapoursynth.com/}. + +Due to security concerns, Vapoursynth scripts will not +be autodetected so the input format has to be forced. For ff* CLI tools, +add @code{-f vapoursynth} before the input @code{-i yourscript.vpy}. + +@section WavPack + +FFmpeg can make use of the libwavpack library for WavPack encoding. + +Go to @url{http://www.wavpack.com/} and follow the instructions for +installing the library. Then pass @code{--enable-libwavpack} to configure to +enable it. + @section x264 FFmpeg can make use of the x264 library for H.264 encoding. @@ -178,92 +298,37 @@ x265 is under the GNU Public License Version 2 or later details), you must upgrade FFmpeg's license to GPL in order to use it. @end float -@section kvazaar +@section xavs -FFmpeg can make use of the kvazaar library for HEVC encoding. +FFmpeg can make use of the xavs library for AVS encoding. -Go to @url{https://github.com/ultravideo/kvazaar} and follow the -instructions for installing the library. Then pass -@code{--enable-libkvazaar} to configure to enable it. - -@section libilbc - -iLBC is a narrowband speech codec that has been made freely available -by Google as part of the WebRTC project. libilbc is a packaging friendly -copy of the iLBC codec. FFmpeg can make use of the libilbc library for -iLBC encoding and decoding. - -Go to @url{https://github.com/TimothyGu/libilbc} and follow the instructions for -installing the library. Then pass @code{--enable-libilbc} to configure to +Go to @url{http://xavs.sf.net/} and follow the instructions for +installing the library. Then pass @code{--enable-libxavs} to configure to enable it. -@section libzvbi +@section xavs2 -libzvbi is a VBI decoding library which can be used by FFmpeg to decode DVB +FFmpeg can make use of the xavs2 library for AVS2-P2/IEEE1857.4 video encoding. + +Go to @url{https://github.com/pkuvcl/xavs2} and follow the instructions for +installing the library. Then pass @code{--enable-libxavs2} to configure to +enable it. + +@float NOTE +libxavs2 is under the GNU Public License Version 2 or later +(see @url{http://www.gnu.org/licenses/old-licenses/gpl-2.0.html} for +details), you must upgrade FFmpeg's license to GPL in order to use it. +@end float + +@section ZVBI + +ZVBI is a VBI decoding library which can be used by FFmpeg to decode DVB teletext pages and DVB teletext subtitles. Go to @url{http://sourceforge.net/projects/zapping/} and follow the instructions for installing the library. Then pass @code{--enable-libzvbi} to configure to enable it. -@section AviSynth - -FFmpeg can read AviSynth scripts as input. To enable support, pass -@code{--enable-avisynth} to configure. The correct headers are -included in compat/avisynth/, which allows the user to enable support -without needing to search for these headers themselves. - -For Windows, supported AviSynth variants are -@url{http://avisynth.nl, AviSynth 2.6 RC1 or higher} for 32-bit builds and -@url{http://avs-plus.net, AviSynth+ r1718 or higher} for 32-bit and 64-bit builds. - -For Linux and OS X, the supported AviSynth variant is -@url{https://github.com/avxsynth/avxsynth, AvxSynth}. - -@float NOTE -There is currently a regression in AviSynth+'s @code{capi.h} header as of -October 2016, which interferes with the ability for builds of FFmpeg to use -MSVC-built binaries of AviSynth. Until this is resolved, you can make sure -a known good version is installed by checking out a version from before -the regression occurred: - -@code{git clone -b MT git://github.com/AviSynth/AviSynthPlus.git @* -cd AviSynthPlus @* -git checkout -b oldheader b4f292b4dbfad149697fb65c6a037bb3810813f9 @* -make install PREFIX=/install/prefix} -@end float - -@float NOTE -AviSynth and AvxSynth are loaded dynamically. Distributors can build FFmpeg -with @code{--enable-avisynth}, and the binaries will work regardless of the -end user having AviSynth or AvxSynth installed - they'll only need to be -installed to use AviSynth scripts (obviously). -@end float - -@section Intel QuickSync Video - -FFmpeg can use Intel QuickSync Video (QSV) for accelerated encoding and decoding -of multiple codecs. To use QSV, FFmpeg must be linked against the @code{libmfx} -dispatcher, which loads the actual decoding libraries. - -The dispatcher is open source and can be downloaded from -@url{https://github.com/lu-zero/mfx_dispatch.git}. FFmpeg needs to be configured -with the @code{--enable-libmfx} option and @code{pkg-config} needs to be able to -locate the dispatcher's @code{.pc} files. - -@section AMD VCE - -FFmpeg can use the AMD Advanced Media Framework library for accelerated H.264 -and HEVC encoding on VCE enabled hardware under Windows. - -To enable support you must obtain the AMF framework header files from -@url{https://github.com/GPUOpen-LibrariesAndSDKs/AMF.git}. - -Create an @code{AMF/} directory in the system include path. -Copy the contents of @code{AMF/amf/public/include/} into that directory. -Then configure FFmpeg with @code{--enable-amf}. - - @chapter Supported File Formats, Codecs or Features You can use the @code{-formats} and @code{-codecs} options to have an exhaustive list. @@ -403,6 +468,8 @@ library: @item IEC61937 encapsulation @tab X @tab X @item IFF @tab @tab X @tab Interchange File Format +@item IFV @tab @tab X + @tab A format used by some old CCTV DVRs. @item iLBC @tab X @tab X @item Interplay MVE @tab @tab X @tab Format used in various Interplay computer games. @@ -516,6 +583,7 @@ library: @item raw VC-1 @tab X @tab X @item raw PCM A-law @tab X @tab X @item raw PCM mu-law @tab X @tab X +@item raw PCM Archimedes VIDC @tab X @tab X @item raw PCM signed 8 bit @tab X @tab X @item raw PCM signed 16 bit big-endian @tab X @tab X @item raw PCM signed 16 bit little-endian @tab X @tab X @@ -559,6 +627,7 @@ library: @item SAP @tab X @tab X @item SBG @tab @tab X @item SDP @tab @tab X +@item SER @tab @tab X @item Sega FILM/CPK @tab X @tab X @tab Used in many Sega Saturn console games. @item Silicon Graphics Movie @tab @tab X @@ -619,7 +688,7 @@ library: @item Psygnosis YOP @tab @tab X @end multitable -@code{X} means that encoding (resp. decoding) is supported. +@code{X} means that the feature in that column (encoding / decoding) is supported. @section Image Formats @@ -689,7 +758,7 @@ following image formats are supported: @tab X Window Dump image format @end multitable -@code{X} means that encoding (resp. decoding) is supported. +@code{X} means that the feature in that column (encoding / decoding) is supported. @code{E} means that support is provided through an external library. @@ -727,8 +796,8 @@ following image formats are supported: @item Autodesk Animator Flic video @tab @tab X @item Autodesk RLE @tab @tab X @tab fourcc: AASC -@item AV1 @tab @tab E - @tab Supported through external library libaom +@item AV1 @tab E @tab E + @tab Supported through external libraries libaom and libdav1d @item Avid 1:1 10-bit RGB Packer @tab X @tab X @tab fourcc: AVrp @item AVS (Audio Video Standard) video @tab @tab X @@ -802,6 +871,7 @@ following image formats are supported: @tab fourcc: G2M2, G2M3 @item Go2Webinar @tab @tab X @tab fourcc: G2M4 +@item Gremlin Digital Video @tab @tab X @item H.261 @tab X @tab X @item H.263 / H.263-1996 @tab X @tab X @item H.263+ / H.263-1998 / H.263 version 2 @tab X @tab X @@ -822,6 +892,7 @@ following image formats are supported: @tab IFF interleaved bitmap @item IFF ByteRun1 @tab @tab X @tab IFF run length encoded bitmap +@item Infinity IMM4 @tab @tab X @item Intel H.263 @tab @tab X @item Intel Indeo 2 @tab @tab X @item Intel Indeo 3 @tab @tab X @@ -875,6 +946,8 @@ following image formats are supported: @tab Video encoding used in NuppelVideo files. @item On2 VP3 @tab @tab X @tab still experimental +@item On2 VP4 @tab @tab X + @tab fourcc: VP40 @item On2 VP5 @tab @tab X @tab fourcc: VP50 @item On2 VP6 @tab @tab X @@ -969,7 +1042,7 @@ following image formats are supported: @tab Encoder works only in PAL8. @end multitable -@code{X} means that encoding (resp. decoding) is supported. +@code{X} means that the feature in that column (encoding / decoding) is supported. @code{E} means that support is provided through an external library. @@ -1048,6 +1121,7 @@ following image formats are supported: @item ATRAC1 @tab @tab X @item ATRAC3 @tab @tab X @item ATRAC3+ @tab @tab X +@item ATRAC9 @tab @tab X @item Bink Audio @tab @tab X @tab Used in Bink and Smacker files in many games. @item CELT @tab @tab E @@ -1074,10 +1148,10 @@ following image formats are supported: @item DPCM Sol @tab @tab X @item DPCM Xan @tab @tab X @tab Used in Origin's Wing Commander IV AVI files. -@item DSD (Direct Stream Digitial), least significant bit first @tab @tab X -@item DSD (Direct Stream Digitial), most significant bit first @tab @tab X -@item DSD (Direct Stream Digitial), least significant bit first, planar @tab @tab X -@item DSD (Direct Stream Digitial), most significant bit first, planar @tab @tab X +@item DSD (Direct Stream Digital), least significant bit first @tab @tab X +@item DSD (Direct Stream Digital), most significant bit first @tab @tab X +@item DSD (Direct Stream Digital), least significant bit first, planar @tab @tab X +@item DSD (Direct Stream Digital), most significant bit first, planar @tab @tab X @item DSP Group TrueSpeech @tab @tab X @item DST (Direct Stream Transfer) @tab @tab X @item DV audio @tab @tab X @@ -1114,6 +1188,7 @@ following image formats are supported: @tab encoding supported through external library libopus @item PCM A-law @tab X @tab X @item PCM mu-law @tab X @tab X +@item PCM Archimedes VIDC @tab X @tab X @item PCM signed 8-bit planar @tab X @tab X @item PCM signed 16-bit big-endian planar @tab X @tab X @item PCM signed 16-bit little-endian planar @tab X @tab X @@ -1186,7 +1261,7 @@ following image formats are supported: @item Xbox Media Audio 2 @tab @tab X @end multitable -@code{X} means that encoding (resp. decoding) is supported. +@code{X} means that the feature in that column (encoding / decoding) is supported. @code{E} means that support is provided through an external library. diff --git a/doc/indevs.texi b/doc/indevs.texi index 6951940a9..14595774f 100644 --- a/doc/indevs.texi +++ b/doc/indevs.texi @@ -178,6 +178,9 @@ Capture the mouse pointer. Default is 0. @item -capture_mouse_clicks Capture the screen mouse clicks. Default is 0. +@item -capture_raw_data +Capture the raw device data. Default is 0. +Using this option may result in receiving the underlying data delivered to the AVFoundation framework. E.g. for muxed devices that sends raw DV data to the framework (like tape-based camcorders), setting this option to false results in extracted video frames captured in the designated pixel format only. Setting this option to true results in receiving the raw DV stream untouched. @end table @subsection Examples @@ -208,6 +211,13 @@ Record video from the system default video device using the pixel format bgr0 an $ ffmpeg -f avfoundation -pixel_format bgr0 -i "default:none" out.avi @end example +@item +Record raw DV data from a suitable input device and write the output into out.dv: +@example +$ ffmpeg -f avfoundation -capture_raw_data true -i "zr100:none" out.dv +@end example + + @end itemize @section bktr @@ -267,7 +277,8 @@ audio track. @item list_devices If set to @option{true}, print a list of devices and exit. -Defaults to @option{false}. +Defaults to @option{false}. Alternatively you can use the @code{-sources} +option of ffmpeg to list the available input devices. @item list_formats If set to @option{true}, print a list of supported formats and exit. @@ -326,6 +337,12 @@ Defaults to @samp{2}. Sets the decklink device duplex mode. Must be @samp{unset}, @samp{half} or @samp{full}. Defaults to @samp{unset}. +@item timecode_format +Timecode type to include in the frame and video stream metadata. Must be +@samp{none}, @samp{rp188vitc}, @samp{rp188vitc2}, @samp{rp188ltc}, +@samp{rp188any}, @samp{vitc}, @samp{vitc2}, or @samp{serial}. Defaults to +@samp{none} (not included). + @item video_input Sets the video input source. Must be @samp{unset}, @samp{sdi}, @samp{hdmi}, @samp{optical_sdi}, @samp{component}, @samp{composite} or @samp{s_video}. @@ -364,6 +381,20 @@ If set to @option{true}, timestamps are forwarded as they are without removing the initial offset. Defaults to @option{false}. +@item timestamp_align +Capture start time alignment in seconds. If set to nonzero, input frames are +dropped till the system timestamp aligns with configured value. +Alignment difference of up to one frame duration is tolerated. +This is useful for maintaining input synchronization across N different +hardware devices deployed for 'N-way' redundancy. The system time of different +hardware devices should be synchronized with protocols such as NTP or PTP, +before using this option. +Note that this method is not foolproof. In some border cases input +synchronization may not happen due to thread scheduling jitters in the OS. +Either sync could go wrong by 1 frame or in a rarer case +@option{timestamp_align} seconds. +Defaults to @samp{0}. + @end table @subsection Examples @@ -402,116 +433,6 @@ ffmpeg -channels 16 -format_code Hi50 -f decklink -i 'UltraStudio Mini Recorder' @end itemize -@section kmsgrab - -KMS video input device. - -Captures the KMS scanout framebuffer associated with a specified CRTC or plane as a -DRM object that can be passed to other hardware functions. - -Requires either DRM master or CAP_SYS_ADMIN to run. - -If you don't understand what all of that means, you probably don't want this. Look at -@option{x11grab} instead. - -@subsection Options - -@table @option - -@item device -DRM device to capture on. Defaults to @option{/dev/dri/card0}. - -@item format -Pixel format of the framebuffer. Defaults to @option{bgr0}. - -@item format_modifier -Format modifier to signal on output frames. This is necessary to import correctly into -some APIs, but can't be autodetected. See the libdrm documentation for possible values. - -@item crtc_id -KMS CRTC ID to define the capture source. The first active plane on the given CRTC -will be used. - -@item plane_id -KMS plane ID to define the capture source. Defaults to the first active plane found if -neither @option{crtc_id} nor @option{plane_id} are specified. - -@item framerate -Framerate to capture at. This is not synchronised to any page flipping or framebuffer -changes - it just defines the interval at which the framebuffer is sampled. Sampling -faster than the framebuffer update rate will generate independent frames with the same -content. Defaults to @code{30}. - -@end table - -@subsection Examples - -@itemize - -@item -Capture from the first active plane, download the result to normal frames and encode. -This will only work if the framebuffer is both linear and mappable - if not, the result -may be scrambled or fail to download. -@example -ffmpeg -f kmsgrab -i - -vf 'hwdownload,format=bgr0' output.mp4 -@end example - -@item -Capture from CRTC ID 42 at 60fps, map the result to VAAPI, convert to NV12 and encode as H.264. -@example -ffmpeg -crtc_id 42 -framerate 60 -f kmsgrab -i - -vf 'hwmap=derive_device=vaapi,scale_vaapi=w=1920:h=1080:format=nv12' -c:v h264_vaapi output.mp4 -@end example - -@end itemize - -@section libndi_newtek - -The libndi_newtek input device provides capture capabilities for using NDI (Network -Device Interface, standard created by NewTek). - -Input filename is a NDI source name that could be found by sending -find_sources 1 -to command line - it has no specific syntax but human-readable formatted. - -To enable this input device, you need the NDI SDK and you -need to configure with the appropriate @code{--extra-cflags} -and @code{--extra-ldflags}. - -@subsection Options - -@table @option - -@item find_sources -If set to @option{true}, print a list of found/available NDI sources and exit. -Defaults to @option{false}. - -@item wait_sources -Override time to wait until the number of online sources have changed. -Defaults to @option{0.5}. - -@item allow_video_fields -When this flag is @option{false}, all video that you receive will be progressive. -Defaults to @option{true}. - -@end table - -@subsection Examples - -@itemize - -@item -List input devices: -@example -ffmpeg -f libndi_newtek -find_sources 1 -i dummy -@end example - -@item -Restream to NDI: -@example -ffmpeg -f libndi_newtek -i "DEV-5.INTERNAL.M1STEREO.TV (NDI_SOURCE_NAME_1)" -f libndi_newtek -y NDI_SOURCE_NAME_2 -@end example - -@end itemize - @section dshow Windows DirectShow input device. @@ -876,7 +797,7 @@ ffplay -f iec61883 -i auto Grab and record the input of a FireWire DV/HDV device, using a packet buffer of 100000 packets if the source is HDV. @example -ffmpeg -f iec61883 -i auto -hdvbuffer 100000 out.mpg +ffmpeg -f iec61883 -i auto -dvbuffer 100000 out.mpg @end example @end itemize @@ -939,6 +860,76 @@ Set the number of channels. Default is 2. @end table +@section kmsgrab + +KMS video input device. + +Captures the KMS scanout framebuffer associated with a specified CRTC or plane as a +DRM object that can be passed to other hardware functions. + +Requires either DRM master or CAP_SYS_ADMIN to run. + +If you don't understand what all of that means, you probably don't want this. Look at +@option{x11grab} instead. + +@subsection Options + +@table @option + +@item device +DRM device to capture on. Defaults to @option{/dev/dri/card0}. + +@item format +Pixel format of the framebuffer. Defaults to @option{bgr0}. + +@item format_modifier +Format modifier to signal on output frames. This is necessary to import correctly into +some APIs, but can't be autodetected. See the libdrm documentation for possible values. + +@item crtc_id +KMS CRTC ID to define the capture source. The first active plane on the given CRTC +will be used. + +@item plane_id +KMS plane ID to define the capture source. Defaults to the first active plane found if +neither @option{crtc_id} nor @option{plane_id} are specified. + +@item framerate +Framerate to capture at. This is not synchronised to any page flipping or framebuffer +changes - it just defines the interval at which the framebuffer is sampled. Sampling +faster than the framebuffer update rate will generate independent frames with the same +content. Defaults to @code{30}. + +@end table + +@subsection Examples + +@itemize + +@item +Capture from the first active plane, download the result to normal frames and encode. +This will only work if the framebuffer is both linear and mappable - if not, the result +may be scrambled or fail to download. +@example +ffmpeg -f kmsgrab -i - -vf 'hwdownload,format=bgr0' output.mp4 +@end example + +@item +Capture from CRTC ID 42 at 60fps, map the result to VAAPI, convert to NV12 and encode as H.264. +@example +ffmpeg -crtc_id 42 -framerate 60 -f kmsgrab -i - -vf 'hwmap=derive_device=vaapi,scale_vaapi=w=1920:h=1080:format=nv12' -c:v h264_vaapi output.mp4 +@end example + +@item +To capture only part of a plane the output can be cropped - this can be used to capture +a single window, as long as it has a known absolute position and size. For example, to +capture and encode the middle quarter of a 1920x1080 plane: +@example +ffmpeg -f kmsgrab -i - -vf 'hwmap=derive_device=vaapi,crop=960:540:480:270,scale_vaapi=960:540:nv12' -c:v h264_vaapi output.mp4 +@end example + +@end itemize + @section lavfi Libavfilter input virtual device. @@ -1077,6 +1068,21 @@ IIDC1394 input device, based on libdc1394 and libraw1394. Requires the configure option @code{--enable-libdc1394}. +@subsection Options +@table @option + +@item framerate +Set the frame rate. Default is @code{ntsc}, corresponding to a frame +rate of @code{30000/1001}. + +@item pixel_format +Select the pixel format. Default is @code{uyvy422}. + +@item video_size +Set the video size given as a string such as @code{640x480} or @code{hd720}. +Default is @code{qvga}. +@end table + @section openal The OpenAL input device provides audio capture on all systems with a @@ -1195,7 +1201,6 @@ Set the number of channels. Default is 2. @end table - @section pulse PulseAudio input device. diff --git a/doc/libav-merge.txt b/doc/libav-merge.txt index 4ba08fc58..bcd0aacba 100644 --- a/doc/libav-merge.txt +++ b/doc/libav-merge.txt @@ -95,17 +95,16 @@ Stuff that didn't reach the codebase: - 0cef06df0 checkasm: add HEVC MC tests - e7078e842 hevcdsp: add x86 SIMD for MC - 7993ec19a hevc: Add hevc_get_pixel_4/8/12/16/24/32/48/64 -- new bitstream reader (see http://ffmpeg.org/pipermail/ffmpeg-devel/2017-April/209609.html) - use av_cpu_max_align() instead of hardcoding alignment requirements (see https://ffmpeg.org/pipermail/ffmpeg-devel/2017-September/215834.html) - f44ec22e0 lavc: use av_cpu_max_align() instead of hardcoding alignment requirements - 4de220d2e frame: allow align=0 (meaning automatic) for av_frame_get_buffer() - Support recovery from an already present HLS playlist (see 16cb06bb30) - Remove all output devices (see 8e7e042d41, 8d3db95f20, 6ce13070bd, d46cd24986 and https://ffmpeg.org/pipermail/ffmpeg-devel/2017-September/216904.html) +- avcodec/libaomenc: export the Sequence Header OBU as extradata (See a024c3ce9a) Collateral damage that needs work locally: ------------------------------------------ -- Merge proresdec2.c and proresdec_lgpl.c - Merge proresenc_anatoliy.c and proresenc_kostya.c - Fix MIPS AC3 downmix diff --git a/doc/mailing-list-faq.texi b/doc/mailing-list-faq.texi index 9af89815d..439d78395 100644 --- a/doc/mailing-list-faq.texi +++ b/doc/mailing-list-faq.texi @@ -47,7 +47,8 @@ We cannot provide help for scripts and/or third-party tools. @anchor{How do I ask a question or send a message to a mailing list?} @section How do I ask a question or send a message to a mailing list? -All you have to do is send an email: +First you must @ref{How do I subscribe?, subscribe}. Then all you have to do is +send an email: @itemize @item @@ -57,49 +58,14 @@ ffmpeg-user mailing list. @item Email @email{libav-user@@ffmpeg.org} to send a message to the libav-user mailing list. + +@item +Email @email{ffmpeg-devel@@ffmpeg.org} to send a message to the +ffmpeg-devel mailing list. @end itemize -If you are not subscribed to the mailing list then your question must be -manually approved. Approval may take several days, but the wait is -usually less. If you want the message to be sent with no delay then you -must subscribe first. See @ref{How do I subscribe?} - -Please do not send a message, subscribe, and re-send the message: this -results in duplicates, causes more work for the admins, and may lower -your chance at getting an answer. However, you may do so if you first -@ref{How do I delete my message in the moderation queue?, delete your original message from the moderation queue}. - @chapter Subscribing / Unsubscribing -@section What does subscribing do? - -Subscribing allows two things: - -@itemize -@item -Your messages will show up in the mailing list without waiting in the -moderation queue and needing to be manually approved by a mailing list -admin. - -@item -You will receive all messages to the mailing list including replies to -your messages. Non-subscribed users do not receive any messages. -@end itemize - -@section Do I need to subscribe? - -No. You can still send a message to the mailing list without -subscribing. See @ref{How do I ask a question or send a message to a mailing list?} - -However, your message will need to be manually approved by a mailing -list admin, and you will not receive any mailing list messages or -replies. - -You can ask to be CCd in your message, but replying users will -sometimes forget to do so. - -You may also view and reply to messages via the @ref{Where are the archives?, archives}. - @anchor{How do I subscribe?} @section How do I subscribe? @@ -124,6 +90,9 @@ The process is the same for the other mailing lists. Please avoid asking a mailing list admin to unsubscribe you unless you are absolutely unable to do so by yourself. See @ref{Who do I contact if I have a problem with the mailing list?} +Note that it is possible to temporarily halt message delivery (vacation mode). +See @ref{How do I disable mail delivery without unsubscribing?} + @chapter Moderation Queue @anchor{Why is my message awaiting moderator approval?} @section Why is my message awaiting moderator approval? @@ -134,8 +103,6 @@ must be manually approved by a mailing list admin: These are: @itemize -@item -Messages from users who are @strong{not} subscribed. @item Messages that exceed the @ref{What is the message size limit?, message size limit}. @@ -148,13 +115,13 @@ or is abusive towards others). @section How long does it take for my message in the moderation queue to be approved? -The queue is usually checked once or twice a day, but on occasion -several days may pass before someone checks the queue. +The queue is not checked on a regular basis. You can ask on the +@t{#ffmpeg-devel} IRC channel on Freenode for someone to approve your message. @anchor{How do I delete my message in the moderation queue?} @section How do I delete my message in the moderation queue? -You should have received an email with the subject @emph{Your message to ffmpeg-user awaits moderator approval}. +You should have received an email with the subject @emph{Your message to awaits moderator approval}. A link is in the message that will allow you to delete your message unless a mailing list admin already approved or rejected it. @@ -175,6 +142,9 @@ Click the email link at the top of the message just under the subject title. The link will provide the proper headers to keep the message within the thread. +Note that you must be subscribed to send a message to the ffmpeg-user or +libav-user mailing lists. + @section How do I search the archives? Perform a site search using your favorite search engine. Example: @@ -187,11 +157,12 @@ Perform a site search using your favorite search engine. Example: You can ask for help in the official @t{#ffmpeg} IRC channel on Freenode. -Some users prefer the third-party Nabble interface which presents the -mailing lists in a typical forum layout. +Some users prefer the third-party @url{http://www.ffmpeg-archive.org/, Nabble} +interface which presents the mailing lists in a typical forum layout. -There are also numerous third-party help sites such as Super User and -r/ffmpeg on reddit. +There are also numerous third-party help sites such as +@url{https://superuser.com/tags/ffmpeg, Super User} and +@url{https://www.reddit.com/r/ffmpeg/, r/ffmpeg on reddit}. @anchor{What is top-posting?} @section What is top-posting? @@ -203,16 +174,15 @@ Instead, use trimmed interleaved/inline replies (@url{https://lists.ffmpeg.org/p @anchor{What is the message size limit?} @section What is the message size limit? -The message size limit is 500 kilobytes for the user lists and 1000 -kilobytes for ffmpeg-devel. Please provide links to larger files instead -of attaching them. +The message size limit is 1000 kilobytes. Please provide links to larger files +instead of attaching them. @section Where can I upload sample files? Anywhere that is not too annoying for us to use. Google Drive and Dropbox are acceptable if you need a file host, and -0x0.st is good for files under 256 MiB. +@url{https://0x0.st/, 0x0.st} is good for files under 256 MiB. Small, short samples are preferred if possible. @@ -259,6 +229,54 @@ or headers. You can then filter the mailing list messages to their own folder. +@anchor{How do I disable mail delivery without unsubscribing?} +@section How do I disable mail delivery without unsubscribing? + +Sometimes you may want to temporarily stop receiving all mailing list +messages. This "vacation mode" is simple to do: + +@enumerate +@item +Go to the @url{https://lists.ffmpeg.org/mailman/listinfo/ffmpeg-user/, ffmpeg-user mailing list info page} + +@item +Enter your email address in the box at very bottom of the page and click the +@emph{Unsubscribe or edit options} box. + +@item +Enter your password and click the @emph{Log in} button. + +@item +Look for the @emph{Mail delivery} option. Here you can disable/enable mail +delivery. If you check @emph{Set globally} it will apply your choice to all +other FFmpeg mailing lists you are subscribed to. +@end enumerate + +Alternatively, from your subscribed address, send a message to @email{ffmpeg-user-request@@ffmpeg.org} +with the subject @emph{set delivery off}. To re-enable mail delivery send a +message to @email{ffmpeg-user-request@@ffmpeg.org} with the subject +@emph{set delivery on}. + +@anchor{Why is the mailing list munging my address?} +@section Why is the mailing list munging my address? + +This is due to subscribers that use an email service with a DMARC reject policy +which adds difficulties to mailing list operators. + +The mailing list must re-write (munge) the @emph{From:} header for such users; +otherwise their email service will reject and bounce the message resulting in +automatic unsubscribing from the mailing list. + +When sending a message these users will see @emph{via } +added to their name and the @emph{From:} address munged to the address of +the particular mailing list. + +If you want to avoid this then please use a different email service. + +Note that ffmpeg-devel does not apply any munging as it causes issues with +patch authorship. As a result users with an email service with a DMARC reject +policy may be automatically unsubscribed due to rejected and bounced messages. + @chapter Rules and Etiquette @section What are the rules and the proper etiquette? @@ -357,6 +375,15 @@ form a multi-part message is recommended by email standards. Check your spam folder. @end itemize +@anchor{Why do I keep getting unsubscribed from ffmpeg-devel?} +@section Why do I keep getting unsubscribed from ffmpeg-devel? + +Users with an email service that has a DMARC reject or quarantine policy may be +automatically unsubscribed from the ffmpeg-devel mailing list due to the mailing +list messages being continuously rejected and bounced back. + +Consider using a different email service. + @anchor{Who do I contact if I have a problem with the mailing list?} @section Who do I contact if I have a problem with the mailing list? diff --git a/doc/metadata.texi b/doc/metadata.texi index bddcc9947..be91059a9 100644 --- a/doc/metadata.texi +++ b/doc/metadata.texi @@ -33,7 +33,7 @@ At the beginning of a chapter section there may be an optional timebase to be used for start/end values. It must be in form @samp{TIMEBASE=@var{num}/@var{den}}, where @var{num} and @var{den} are integers. If the timebase is missing then start/end times are assumed to -be in milliseconds. +be in nanoseconds. Next a chapter section must contain chapter start and end times in form @samp{START=@var{num}}, @samp{END=@var{num}}, where @var{num} is a positive diff --git a/doc/muxers.texi b/doc/muxers.texi index f288764a2..b10929796 100644 --- a/doc/muxers.texi +++ b/doc/muxers.texi @@ -94,21 +94,23 @@ compatibility with software that only supports a single audio stream in AVI @anchor{chromaprint} @section chromaprint -Chromaprint fingerprinter +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. +This muxer feeds audio data to the Chromaprint library, +which generates a fingerprint for the provided audio data. See @url{https://acoustid.org/chromaprint} + +It takes a single signed native-endian 16-bit raw audio stream of at most 2 channels. @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). +Threshold for detecting silence, ranges from -1 to 32767. -1 disables silence detection and +is required for use with the AcoustID service. Default is -1. @item algorithm -Algorithm index to fingerprint with. +Version of algorithm to fingerprint with. Range is 0 to 4. Version 2 requires that silence +detection be enabled. Default is 1. @item fp_format Format to output the fingerprint as. Accepts the following options: @@ -120,7 +122,7 @@ Binary raw fingerprint Binary compressed fingerprint @item base64 -Base64 compressed fingerprint +Base64 compressed fingerprint @emph{(default)} @end table @@ -214,58 +216,113 @@ It creates a MPD manifest file and segment files for each stream. The segment filename might contain pre-defined identifiers used with SegmentTemplate as defined in section 5.3.9.4.4 of the standard. Available identifiers are "$RepresentationID$", "$Number$", "$Bandwidth$" and "$Time$". +In addition to the standard identifiers, an ffmpeg-specific "$ext$" identifier is also supported. +When specified ffmpeg will replace $ext$ in the file name with muxing format's extensions such as mp4, webm etc., @example -ffmpeg -re -i -map 0 -map 0 -c:a libfdk_aac -c:v libx264 --b:v:0 800k -b:v:1 300k -s:v:1 320x170 -profile:v:1 baseline --profile:v:0 main -bf 1 -keyint_min 120 -g 120 -sc_threshold 0 --b_strategy 0 -ar:a:1 22050 -use_timeline 1 -use_template 1 --window_size 5 -adaptation_sets "id=0,streams=v id=1,streams=a" +ffmpeg -re -i -map 0 -map 0 -c:a libfdk_aac -c:v libx264 \ +-b:v:0 800k -b:v:1 300k -s:v:1 320x170 -profile:v:1 baseline \ +-profile:v:0 main -bf 1 -keyint_min 120 -g 120 -sc_threshold 0 \ +-b_strategy 0 -ar:a:1 22050 -use_timeline 1 -use_template 1 \ +-window_size 5 -adaptation_sets "id=0,streams=v id=1,streams=a" \ -f dash /path/to/out.mpd @end example @table @option -@item -min_seg_duration @var{microseconds} -Set the segment length in microseconds. -@item -window_size @var{size} +@item min_seg_duration @var{microseconds} +This is a deprecated option to set the segment length in microseconds, use @var{seg_duration} instead. +@item seg_duration @var{duration} +Set the segment length in seconds (fractional value can be set). The value is +treated as average segment duration when @var{use_template} is enabled and +@var{use_timeline} is disabled and as minimum segment duration for all the other +use cases. +@item window_size @var{size} Set the maximum number of segments kept in the manifest. -@item -extra_window_size @var{size} +@item extra_window_size @var{size} Set the maximum number of segments kept outside of the manifest before removing from disk. -@item -remove_at_exit @var{remove} +@item remove_at_exit @var{remove} Enable (1) or disable (0) removal of all segments when finished. -@item -use_template @var{template} +@item use_template @var{template} Enable (1) or disable (0) use of SegmentTemplate instead of SegmentList. -@item -use_timeline @var{timeline} +@item use_timeline @var{timeline} Enable (1) or disable (0) use of SegmentTimeline in SegmentTemplate. -@item -single_file @var{single_file} +@item single_file @var{single_file} Enable (1) or disable (0) storing all segments in one file, accessed using byte ranges. -@item -single_file_name @var{file_name} -DASH-templated name to be used for baseURL. Implies @var{single_file} set to "1". -@item -init_seg_name @var{init_name} -DASH-templated name to used for the initialization segment. Default is "init-stream$RepresentationID$.m4s" -@item -media_seg_name @var{segment_name} -DASH-templated name to used for the media segments. Default is "chunk-stream$RepresentationID$-$Number%05d$.m4s" -@item -utc_timing_url @var{utc_url} +@item single_file_name @var{file_name} +DASH-templated name to be used for baseURL. Implies @var{single_file} set to "1". In the template, "$ext$" is replaced with the file name extension specific for the segment format. +@item init_seg_name @var{init_name} +DASH-templated name to used for the initialization segment. Default is "init-stream$RepresentationID$.$ext$". "$ext$" is replaced with the file name extension specific for the segment format. +@item media_seg_name @var{segment_name} +DASH-templated name to used for the media segments. Default is "chunk-stream$RepresentationID$-$Number%05d$.$ext$". "$ext$" is replaced with the file name extension specific for the segment format. +@item utc_timing_url @var{utc_url} URL of the page that will return the UTC timestamp in ISO format. Example: "https://time.akamai.com/?iso" -@item -http_user_agent @var{user_agent} +@item method @var{method} +Use the given HTTP method to create output files. Generally set to PUT or POST. +@item http_user_agent @var{user_agent} Override User-Agent field in HTTP header. Applicable only for HTTP output. -@item -http_persistent @var{http_persistent} +@item http_persistent @var{http_persistent} Use persistent HTTP connections. Applicable only for HTTP output. -@item -hls_playlist @var{hls_playlist} +@item hls_playlist @var{hls_playlist} Generate HLS playlist files as well. The master playlist is generated with the filename master.m3u8. One media playlist file is generated for each stream with filenames media_0.m3u8, media_1.m3u8, etc. -@item -streaming @var{streaming} +@item streaming @var{streaming} Enable (1) or disable (0) chunk streaming mode of output. In chunk streaming mode, each frame will be a moof fragment which forms a chunk. -@item -adaptation_sets @var{adaptation_sets} +@item adaptation_sets @var{adaptation_sets} Assign streams to AdaptationSets. Syntax is "id=x,streams=a,b,c id=y,streams=d,e" with x and y being the IDs of the adaptation sets and a,b,c,d and e are the indices of the mapped streams. To map all video (or audio) streams to an AdaptationSet, "v" (or "a") can be used as stream identifier instead of IDs. When no assignment is defined, this defaults to an AdaptationSet for each stream. -@item -timeout @var{timeout} +@item timeout @var{timeout} Set timeout for socket I/O operations. Applicable only for HTTP output. +@item index_correction @var{index_correction} +Enable (1) or Disable (0) segment index correction logic. Applicable only when +@var{use_template} is enabled and @var{use_timeline} is disabled. + +When enabled, the logic monitors the flow of segment indexes. If a streams's +segment index value is not at the expected real time position, then the logic +corrects that index value. + +Typically this logic is needed in live streaming use cases. The network bandwidth +fluctuations are common during long run streaming. Each fluctuation can cause +the segment indexes fall behind the expected real time position. +@item format_options @var{options_list} +Set container format (mp4/webm) options using a @code{:} separated list of +key=value parameters. Values containing @code{:} special characters must be +escaped. + +@item global_sidx @var{global_sidx} +Write global SIDX atom. Applicable only for single file, mp4 output, non-streaming mode. + +@item dash_segment_type @var{dash_segment_type} +Possible values: +@table @option +@item auto +If this flag is set, the dash segment files format will be selected based on the stream codec. This is the default mode. + +@item mp4 +If this flag is set, the dash segment files will be in in ISOBMFF format. + +@item webm +If this flag is set, the dash segment files will be in in WebM format. +@end table + +@item ignore_io_errors @var{ignore_io_errors} +Ignore IO errors during open and write. Useful for long-duration runs with network output. + +@item lhls @var{lhls} +Enable Low-latency HLS(LHLS). Adds #EXT-X-PREFETCH tag with current segment's URI. +Apple doesn't have an official spec for LHLS. Meanwhile hls.js player folks are +trying to standardize a open LHLS spec. The draft spec is available in https://github.com/video-dev/hlsjs-rfcs/blob/lhls-spec/proposals/0001-lhls.md +This option will also try to comply with the above open spec, till Apple's spec officially supports it. +Applicable only when @var{streaming} and @var{hls_playlist} options are enabled. +This is an experimental feature. + +@item master_m3u8_publish_rate @var{master_m3u8_publish_rate} +Publish master playlist repeatedly every after specified number of segment intervals. + @end table @anchor{framecrc} @@ -586,7 +643,7 @@ This example will produce the playlist, @file{out.m3u8}, and segment files: but only the file name part without any path info will be contained in the m3u8 segment list. Should a relative path be specified, the path of the created segment files will be relative to the current working directory. -When use_localtime_mkdir is set, the whole expanded value of @var{filename} will be written into the m3u8 segment list. +When strftime_mkdir is set, the whole expanded value of @var{filename} will be written into the m3u8 segment list. When @code{var_stream_map} is set with two or more variant streams, the @var{filename} pattern must contain the string "%v", this string specifies @@ -601,7 +658,8 @@ This example will produce the playlists segment file sets: @file{file_1_000.ts}, @file{file_1_001.ts}, @file{file_1_002.ts}, etc. The string "%v" may be present in the filename or in the last directory name -containing the file. If the string is present in the directory name, then +containing the file, but only in one of them. (Additionally, %v may appear multiple times in the last +sub-directory or filename.) If the string %v is present in the directory name, then sub-directories are created after expanding the directory name pattern. This enables creation of segments corresponding to different variant streams in subdirectories. @@ -615,34 +673,40 @@ This example will produce the playlists segment file sets: @file{vs1/file_000.ts}, @file{vs1/file_001.ts}, @file{vs1/file_002.ts}, etc. @item use_localtime +Same as strftime option, will be deprecated. + +@item strftime Use strftime() on @var{filename} to expand the segment filename with localtime. The segment number is also available in this mode, but to use it, you need to specify second_level_segment_index hls_flag and %%d will be the specifier. @example -ffmpeg -i in.nut -use_localtime 1 -hls_segment_filename 'file-%Y%m%d-%s.ts' out.m3u8 +ffmpeg -i in.nut -strftime 1 -hls_segment_filename 'file-%Y%m%d-%s.ts' out.m3u8 @end example This example will produce the playlist, @file{out.m3u8}, and segment files: @file{file-20160215-1455569023.ts}, @file{file-20160215-1455569024.ts}, etc. Note: On some systems/environments, the @code{%s} specifier is not available. See @code{strftime()} documentation. @example -ffmpeg -i in.nut -use_localtime 1 -hls_flags second_level_segment_index -hls_segment_filename 'file-%Y%m%d-%%04d.ts' out.m3u8 +ffmpeg -i in.nut -strftime 1 -hls_flags second_level_segment_index -hls_segment_filename 'file-%Y%m%d-%%04d.ts' out.m3u8 @end example This example will produce the playlist, @file{out.m3u8}, and segment files: @file{file-20160215-0001.ts}, @file{file-20160215-0002.ts}, etc. @item use_localtime_mkdir -Used together with -use_localtime, it will create all subdirectories which +Same as strftime_mkdir option, will be deprecated . + +@item strftime_mkdir +Used together with -strftime_mkdir, it will create all subdirectories which is expanded in @var{filename}. @example -ffmpeg -i in.nut -use_localtime 1 -use_localtime_mkdir 1 -hls_segment_filename '%Y%m%d/file-%Y%m%d-%s.ts' out.m3u8 +ffmpeg -i in.nut -strftime 1 -strftime_mkdir 1 -hls_segment_filename '%Y%m%d/file-%Y%m%d-%s.ts' out.m3u8 @end example This example will create a directory 201560215 (if it does not exist), and then produce the playlist, @file{out.m3u8}, and segment files: @file{20160215/file-20160215-1455569023.ts}, @file{20160215/file-20160215-1455569024.ts}, etc. @example -ffmpeg -i in.nut -use_localtime 1 -use_localtime_mkdir 1 -hls_segment_filename '%Y/%m/%d/file-%Y%m%d-%s.ts' out.m3u8 +ffmpeg -i in.nut -strftime 1 -strftime_mkdir 1 -hls_segment_filename '%Y/%m/%d/file-%Y%m%d-%s.ts' out.m3u8 @end example This example will create a directory hierarchy 2016/02/15 (if any of them do not exist), and then produce the playlist, @file{out.m3u8}, and segment files: @@ -727,17 +791,17 @@ Possible values: @table @samp @item mpegts -If this flag is set, the hls segment files will format to mpegts. -the mpegts files is used in all hls versions. +Output segment files in MPEG-2 Transport Stream format. This is +compatible with all HLS versions. @item fmp4 -If this flag is set, the hls segment files will format to fragment mp4 looks like dash. -the fmp4 files is used in hls after version 7. +Output segment files in fragmented MP4 format, similar to MPEG-DASH. +fmp4 files may be used in HLS version 7 and above. @end table @item hls_fmp4_init_filename @var{filename} -set filename to the fragment files header file, default filename is @file{init.mp4}. +Set filename to the fragment files header file, default filename is @file{init.mp4}. When @code{var_stream_map} is set with two or more variant streams, the @var{filename} pattern must contain the string "%v", this string specifies @@ -791,6 +855,10 @@ including the file containing the AES encryption key. Add the @code{#EXT-X-INDEPENDENT-SEGMENTS} to playlists that has video segments and when all the segments of that playlist are guaranteed to start with a Key frame. +@item iframes_only +Add the @code{#EXT-X-I-FRAMES-ONLY} to playlists that has video segments +and can play only I-frames in the @code{#EXT-X-BYTERANGE} mode. + @item split_by_time Allow segments to start on frames other than keyframes. This improves behavior on some players when the time between keyframes is inconsistent, @@ -802,24 +870,24 @@ Generate @code{EXT-X-PROGRAM-DATE-TIME} tags. @item second_level_segment_index Makes it possible to use segment indexes as %%d in hls_segment_filename expression -besides date/time values when use_localtime is on. +besides date/time values when strftime is on. To get fixed width numbers with trailing zeroes, %%0xd format is available where x is the required width. @item second_level_segment_size Makes it possible to use segment sizes (counted in bytes) as %%s in hls_segment_filename -expression besides date/time values when use_localtime is on. +expression besides date/time values when strftime is on. To get fixed width numbers with trailing zeroes, %%0xs format is available where x is the required width. @item second_level_segment_duration Makes it possible to use segment duration (calculated in microseconds) as %%t in hls_segment_filename -expression besides date/time values when use_localtime is on. +expression besides date/time values when strftime is on. To get fixed width numbers with trailing zeroes, %%0xt format is available where x is the required width. @example ffmpeg -i sample.mpeg \ -f hls -hls_time 3 -hls_list_size 5 \ -hls_flags second_level_segment_index+second_level_segment_size+second_level_segment_duration \ - -use_localtime 1 -use_localtime_mkdir 1 -hls_segment_filename "segment_%Y%m%d%H%M%S_%%04d_%%08s_%%013t.ts" stream.m3u8 + -strftime 1 -strftime_mkdir 1 -hls_segment_filename "segment_%Y%m%d%H%M%S_%%04d_%%08s_%%013t.ts" stream.m3u8 @end example This will produce segments like this: @file{segment_20170102194334_0003_00122200_0000003000000.ts}, @file{segment_20170102194334_0004_00120072_0000003000000.ts} etc. @@ -827,7 +895,11 @@ This will produce segments like this: @item temp_file Write segment data to filename.tmp and rename to filename only once the segment is complete. A webserver serving up segments can be configured to reject requests to *.tmp to prevent access to in-progress segments -before they have been added to the m3u8 playlist. +before they have been added to the m3u8 playlist. This flag also affects how m3u8 playlist files are created. +If this flag is set, all playlist files will written into temporary file and renamed after they are complete, similarly as segments are handled. +But playlists with @code{file} protocol and with type (@code{hls_playlist_type}) other than @code{vod} +are always written into temporary file regardles of this flag. Master playlist files (@code{master_pl_name}), if any, with @code{file} protocol, +are always written into temporary file regardles of this flag if @code{master_pl_publish_rate} value is other than zero. @end table @@ -878,7 +950,21 @@ This example creates two hls variant streams. The first variant stream will contain video stream of bitrate 1000k and audio stream of bitrate 64k and the second variant stream will contain video stream of bitrate 256k and audio stream of bitrate 32k. Here, two media playlist with file names out_0.m3u8 and -out_1.m3u8 will be created. +out_1.m3u8 will be created. If you want something meaningful text instead of indexes +in result names, you may specify names for each or some of the variants +as in the following example. + + +@example +ffmpeg -re -i in.ts -b:v:0 1000k -b:v:1 256k -b:a:0 64k -b:a:1 32k \ + -map 0:v -map 0:a -map 0:v -map 0:a -f hls -var_stream_map "v:0,a:0,name:my_hd v:1,a:1,name:my_sd" \ + http://example.com/live/out_%v.m3u8 +@end example + +This example creates two hls variant streams as in the previous one. +But here, the two media playlist with file names out_my_hd.m3u8 and +out_my_sd.m3u8 will be created. + @example ffmpeg -re -i in.ts -b:v:0 1000k -b:v:1 256k -b:a:0 64k \ -map 0:v -map 0:a -map 0:v -f hls -var_stream_map "v:0 a:0 v:1" \ @@ -912,6 +998,37 @@ and they are mapped to the two video only variant streams with audio group names By default, a single hls variant containing all the encoded streams is created. +@example +ffmpeg -re -i in.ts -b:a:0 32k -b:a:1 64k -b:v:0 1000k \ + -map 0:a -map 0:a -map 0:v -f hls \ + -var_stream_map "a:0,agroup:aud_low,default:yes a:1,agroup:aud_low v:0,agroup:aud_low" \ + -master_pl_name master.m3u8 \ + http://example.com/live/out_%v.m3u8 +@end example +This example creates two audio only and one video only variant streams. In +addition to the #EXT-X-STREAM-INF tag for each variant stream in the master +playlist, #EXT-X-MEDIA tag is also added for the two audio only variant streams +and they are mapped to the one video only variant streams with audio group name +'aud_low', and the audio group have default stat is NO or YES. + +By default, a single hls variant containing all the encoded streams is created. + +@example +ffmpeg -re -i in.ts -b:a:0 32k -b:a:1 64k -b:v:0 1000k \ + -map 0:a -map 0:a -map 0:v -f hls \ + -var_stream_map "a:0,agroup:aud_low,default:yes,language:ENG a:1,agroup:aud_low,language:CHN v:0,agroup:aud_low" \ + -master_pl_name master.m3u8 \ + http://example.com/live/out_%v.m3u8 +@end example +This example creates two audio only and one video only variant streams. In +addition to the #EXT-X-STREAM-INF tag for each variant stream in the master +playlist, #EXT-X-MEDIA tag is also added for the two audio only variant streams +and they are mapped to the one video only variant streams with audio group name +'aud_low', and the audio group have default stat is NO or YES, and one audio +have and language is named ENG, the other audio language is named CHN. + +By default, a single hls variant containing all the encoded streams is created. + @item cc_stream_map Map string which specifies different closed captions groups and their attributes. The closed captions stream groups are separated by space. @@ -932,7 +1049,7 @@ ffmpeg -re -i in.ts -b:v 1000k -b:a 64k -a53cc 1 -f hls \ http://example.com/live/out.m3u8 @end example This example adds @code{#EXT-X-MEDIA} tag with @code{TYPE=CLOSED-CAPTIONS} in -the master playlist with group name 'cc', langauge 'en' (english) and +the master playlist with group name 'cc', language 'en' (english) and INSTREAM-ID 'CC1'. Also, it adds @code{CLOSED-CAPTIONS} attribute with group name 'cc' for the output variant stream. @example @@ -975,6 +1092,12 @@ Use persistent HTTP connections. Applicable only for HTTP output. @item timeout Set timeout for socket I/O operations. Applicable only for HTTP output. +@item -ignore_io_errors +Ignore IO errors during open, write and delete. Useful for long-duration runs with network output. + +@item headers +Set custom HTTP headers, can override built in default headers. Applicable only for HTTP output. + @end table @anchor{ico} @@ -1282,6 +1405,10 @@ more efficient), but with this option set, the muxer writes one moof/mdat pair for each track, making it easier to separate tracks. This option is implicitly set when writing ismv (Smooth Streaming) files. +@item -movflags skip_sidx +Skip writing of sidx atom. When bitrate overhead due to sidx atom is high, +this option could be used for cases where sidx atom is not mandatory. +When global_sidx flag is enabled, this option will be ignored. @item -movflags faststart Run a second pass moving the index (moov atom) to the beginning of the file. This operation can take a while, and will not work in various situations such @@ -1313,6 +1440,18 @@ be negative. This enables the initial sample to have DTS/CTS of zero, and reduces the need for edit lists for some cases such as video tracks with B-frames. Additionally, eases conformance with the DASH-IF interoperability guidelines. + +This option is implicitly set when writing ismv (Smooth Streaming) files. +@item -write_prft +Write producer time reference box (PRFT) with a specified time source for the +NTP field in the PRFT box. Set value as @samp{wallclock} to specify timesource +as wallclock time and @samp{pts} to specify timesource as input packets' PTS +values. + +Setting value to @samp{pts} is applicable only for a live encoding use case, +where PTS values are set as as wallclock time at the source. For example, an +encoding use case with decklink capture source where @option{video_pts} and +@option{audio_pts} are set to @samp{abs_wallclock}. @end table @subsection Example @@ -1418,7 +1557,7 @@ Set the program @samp{service_type}. Default is @code{digital_tv}. Accepts the following options: @table @samp @item hex_value -Any hexdecimal value between @code{0x01} to @code{0xff} as defined in +Any hexadecimal value between @code{0x01} and @code{0xff} as defined in ETSI 300 468. @item digital_tv Digital TV service. @@ -1521,7 +1660,7 @@ ffmpeg -i file.mpg -c copy \ out.ts @end example -@section mxf, mxf_d10 +@section mxf, mxf_d10, mxf_opatom MXF muxer. @@ -1533,7 +1672,7 @@ The muxer options are: @item store_user_comments @var{bool} Set if user comments should be stored if available or never. IRT D-10 does not allow user comments. The default is thus to write them for -mxf but not for mxf_d10 +mxf and mxf_opatom but not for mxf_d10 @end table @section null @@ -2021,20 +2160,35 @@ ffmpeg -re -i ... -c:v libx264 -c:a aac -f fifo -fifo_format flv -map 0:v -map 0 @anchor{tee} @section tee -The tee muxer can be used to write the same data to several files or any -other kind of muxer. It can be used, for example, to both stream a video to -the network and save it to disk at the same time. +The tee muxer can be used to write the same data to several outputs, such as files or streams. +It can be used, for example, to stream a video over a network and save it to disk at the same time. It is different from specifying several outputs to the @command{ffmpeg} -command-line tool because the audio and video data will be encoded only once -with the tee muxer; encoding can be a very expensive process. It is not -useful when using the libavformat API directly because it is then possible -to feed the same packets to several muxers directly. +command-line tool. With the tee muxer, the audio and video data will be encoded only once. +With conventional multiple outputs, multiple encoding operations in parallel are initiated, +which can be a very expensive process. The tee muxer is not useful when using the libavformat API +directly because it is then possible to feed the same packets to several muxers directly. + +Since the tee muxer does not represent any particular output format, ffmpeg cannot auto-select +output streams. So all streams intended for output must be specified using @code{-map}. See +the examples below. + +Some encoders may need different options depending on the output format; +the auto-detection of this can not work with the tee muxer, so they need to be explicitly specified. +The main example is the @option{global_header} flag. + +The slave outputs are specified in the file name given to the muxer, +separated by '|'. If any of the slave name contains the '|' separator, +leading or trailing spaces or any special character, those must be +escaped (see @ref{quoting_and_escaping,,the "Quoting and escaping" +section in the ffmpeg-utils(1) manual,ffmpeg-utils}). + +@subsection Options @table @option @item use_fifo @var{bool} -If set to 1, slave outputs will be processed in separate thread using @ref{fifo} +If set to 1, slave outputs will be processed in separate threads using the @ref{fifo} muxer. This allows to compensate for different speed/latency/reliability of outputs and setup transparent recovery. By default this feature is turned off. @@ -2043,12 +2197,6 @@ Options to pass to fifo pseudo-muxer instances. See @ref{fifo}. @end table -The slave outputs are specified in the file name given to the muxer, -separated by '|'. If any of the slave name contains the '|' separator, -leading or trailing spaces or any special character, it must be -escaped (see @ref{quoting_and_escaping,,the "Quoting and escaping" -section in the ffmpeg-utils(1) manual,ffmpeg-utils}). - Muxer options can be specified for each slave by prepending them as a list of @var{key}=@var{value} pairs separated by ':', between square brackets. If the options values contain a special character or the ':' separator, they @@ -2057,13 +2205,27 @@ must be escaped; note that this is a second level escaping. The following special options are also recognized: @table @option @item f -Specify the format name. Useful if it cannot be guessed from the -output name suffix. +Specify the format name. Required if it cannot be guessed from the +output URL. @item bsfs[/@var{spec}] Specify a list of bitstream filters to apply to the specified output. +It is possible to specify to which streams a given bitstream filter +applies, by appending a stream specifier to the option separated by +@code{/}. @var{spec} must be a stream specifier (see @ref{Format +stream specifiers}). + +If the stream specifier is not specified, the bitstream filters will be +applied to all streams in the output. This will cause that output operation +to fail if the output contains streams to which the bitstream filter cannot +be applied e.g. @code{h264_mp4toannexb} being applied to an output containing an audio stream. + +Options for a bitstream filter must be specified in the form of @code{opt=value}. + +Several bitstream filters can be specified, separated by ",". + @item use_fifo @var{bool} This allows to override tee muxer use_fifo option for individual slave muxer. @@ -2071,19 +2233,13 @@ This allows to override tee muxer use_fifo option for individual slave muxer. This allows to override tee muxer fifo_options for individual slave muxer. See @ref{fifo}. -It is possible to specify to which streams a given bitstream filter -applies, by appending a stream specifier to the option separated by -@code{/}. @var{spec} must be a stream specifier (see @ref{Format -stream specifiers}). If the stream specifier is not specified, the -bitstream filters will be applied to all streams in the output. - -Several bitstream filters can be specified, separated by ",". - @item select Select the streams that should be mapped to the slave output, specified by a stream specifier. If not specified, this defaults to -all the input streams. You may use multiple stream specifiers -separated by commas (@code{,}) e.g.: @code{a:0,v} +all the mapped streams. This will cause that output operation to fail +if the output format does not accept all mapped streams. + +You may use multiple stream specifiers separated by commas (@code{,}) e.g.: @code{a:0,v} @item onfail Specify behaviour on output failure. This can be set to either @code{abort} (which is @@ -2097,7 +2253,7 @@ will continue without being affected. @itemize @item Encode something and both archive it in a WebM file and stream it -as MPEG-TS over UDP (the streams need to be explicitly mapped): +as MPEG-TS over UDP: @example ffmpeg -i ... -c:v libx264 -c:a mp2 -f tee -map 0:v -map 0:a "archive-20121107.mkv|[f=mpegts]udp://10.0.1.255:1234/" @@ -2120,23 +2276,19 @@ option is applied to @file{out.aac} in order to make it contain only audio packets. @example ffmpeg -i ... -map 0 -flags +global_header -c:v libx264 -c:a aac - -f tee "[bsfs/v=dump_extra]out.ts|[movflags=+faststart]out.mp4|[select=a]out.aac" + -f tee "[bsfs/v=dump_extra=freq=keyframe]out.ts|[movflags=+faststart]out.mp4|[select=a]out.aac" @end example @item -As below, but select only stream @code{a:1} for the audio output. Note +As above, but select only stream @code{a:1} for the audio output. Note that a second level escaping must be performed, as ":" is a special character used to separate options. @example ffmpeg -i ... -map 0 -flags +global_header -c:v libx264 -c:a aac - -f tee "[bsfs/v=dump_extra]out.ts|[movflags=+faststart]out.mp4|[select=\'a:1\']out.aac" + -f tee "[bsfs/v=dump_extra=freq=keyframe]out.ts|[movflags=+faststart]out.mp4|[select=\'a:1\']out.aac" @end example @end itemize -Note: some codecs may need different options depending on the output format; -the auto-detection of this can not work with the tee muxer. The main example -is the @option{global_header} flag. - @section webm_dash_manifest WebM DASH Manifest muxer. diff --git a/doc/outdevs.texi b/doc/outdevs.texi index daf7b1ae6..c96d2d0e4 100644 --- a/doc/outdevs.texi +++ b/doc/outdevs.texi @@ -140,7 +140,8 @@ device with @command{-list_formats 1}. Audio sample rate is always 48 kHz. @item list_devices If set to @option{true}, print a list of devices and exit. -Defaults to @option{false}. +Defaults to @option{false}. Alternatively you can use the @code{-sinks} +option of ffmpeg to list the available output devices. @item list_formats If set to @option{true}, print a list of supported formats and exit. @@ -150,6 +151,14 @@ Defaults to @option{false}. Amount of time to preroll video in seconds. Defaults to @option{0.5}. +@item duplex_mode +Sets the decklink device duplex mode. Must be @samp{unset}, @samp{half} or @samp{full}. +Defaults to @samp{unset}. + +@item timing_offset +Sets the genlock timing pixel offset on the used output. +Defaults to @samp{unset}. + @end table @subsection Examples @@ -182,51 +191,6 @@ ffmpeg -i test.avi -f decklink -pix_fmt uyvy422 -s 720x486 -r 24000/1001 'DeckLi @end itemize -@section libndi_newtek - -The libndi_newtek output device provides playback capabilities for using NDI (Network -Device Interface, standard created by NewTek). - -Output filename is a NDI name. - -To enable this output device, you need the NDI SDK and you -need to configure with the appropriate @code{--extra-cflags} -and @code{--extra-ldflags}. - -NDI uses uyvy422 pixel format natively, but also supports bgra, bgr0, rgba and -rgb0. - -@subsection Options - -@table @option - -@item reference_level -The audio reference level in dB. This specifies how many dB above the -reference level (+4dBU) is the full range of 16 bit audio. -Defaults to @option{0}. - -@item clock_video -These specify whether video "clock" themselves. -Defaults to @option{false}. - -@item clock_audio -These specify whether audio "clock" themselves. -Defaults to @option{false}. - -@end table - -@subsection Examples - -@itemize - -@item -Play video clip: -@example -ffmpeg -i "udp://@@239.1.1.1:10480?fifo_size=1000000&overrun_nonfatal=1" -vf "scale=720:576,fps=fps=25,setdar=dar=16/9,format=pix_fmts=uyvy422" -f libndi_newtek NEW_NDI1 -@end example - -@end itemize - @section fbdev Linux framebuffer output device. @@ -393,9 +357,18 @@ Set the SDL window size, can be a string of the form If not specified it defaults to the size of the input video, downscaled according to the aspect ratio. +@item window_x +@item window_y +Set the position of the window on the screen. + @item window_fullscreen Set fullscreen mode when non-zero value is provided. Default value is zero. + +@item window_enable_quit +Enable quit action (using window button or keyboard key) +when non-zero value is provided. +Default value is 1 (enable quit action) @end table @subsection Interactive commands @@ -420,6 +393,10 @@ ffmpeg -i INPUT -c:v rawvideo -pix_fmt yuv420p -window_size qcif -f sdl "SDL out sndio audio output device. +@section v4l2 + +Video4Linux2 output device. + @section xv XV (XVideo) output device. diff --git a/doc/platform.texi b/doc/platform.texi index bdfb6fd6a..4090b8567 100644 --- a/doc/platform.texi +++ b/doc/platform.texi @@ -148,16 +148,11 @@ To target 32 bits replace @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 -and wrapper, or with MSVC 2013 and ICL natively. +FFmpeg can be built with MSVC 2013 or later. You will need the following prerequisites: @itemize -@item @uref{https://github.com/libav/c99-to-c89/, C99-to-C89 Converter & Wrapper} -(if using MSVC 2012 or earlier) -@item @uref{http://code.google.com/p/msinttypes/, msinttypes} -(if using MSVC 2012 or earlier) @item @uref{http://msys2.github.io/, MSYS2} @item @uref{http://www.nasm.us/, NASM} (Also available via MSYS2's package manager.) @@ -166,16 +161,13 @@ You will need the following prerequisites: To set up a proper environment in MSYS2, you need to run @code{msys_shell.bat} from the Visual Studio or Intel Compiler command prompt. -Place @code{yasm.exe} somewhere in your @code{PATH}. If using MSVC 2012 or -earlier, place @code{c99wrap.exe} and @code{c99conv.exe} somewhere in your -@code{PATH} as well. +Place @code{yasm.exe} somewhere in your @code{PATH}. Next, make sure any other headers and libs you want to use, such as zlib, are located in a spot that the compiler can see. Do so by modifying the @code{LIB} and @code{INCLUDE} environment variables to include the @strong{Windows-style} paths to these directories. Alternatively, you can try to use the -@code{--extra-cflags}/@code{--extra-ldflags} configure options. If using MSVC -2012 or earlier, place @code{inttypes.h} somewhere the compiler can see too. +@code{--extra-cflags}/@code{--extra-ldflags} configure options. Finally, run: @@ -217,8 +209,6 @@ can see. @item FFmpeg has been tested with the following on i686 and x86_64: @itemize -@item Visual Studio 2010 Pro and Express -@item Visual Studio 2012 Pro and Express @item Visual Studio 2013 Pro and Express @item Intel Composer XE 2013 @item Intel Composer XE 2013 SP1 diff --git a/doc/protocols.texi b/doc/protocols.texi index e19504d07..3e4e7af3d 100644 --- a/doc/protocols.texi +++ b/doc/protocols.texi @@ -193,6 +193,20 @@ Set I/O operation maximum block size, in bytes. Default value is @code{INT_MAX}, which results in not limiting the requested block size. Setting this value reasonably low improves user termination request reaction time, which is valuable for files on slow medium. + +@item follow +If set to 1, the protocol will retry reading at the end of the file, allowing +reading files that still are being written. In order for this to terminate, +you either need to use the rw_timeout option, or use the interrupt callback +(for API users). + +@item seekable +Controls if seekability is advertised on the file. 0 means non-seekable, -1 +means auto (seekable for normal files, non-seekable for named pipes). + +Many demuxers handle seekable and non-seekable resources differently, +overriding this might speed up opening certain files at the cost of losing some +features (e.g. accurate seeking). @end table @section ftp @@ -229,17 +243,6 @@ it, unless special care is taken (tests, customized server configuration etc.). Different FTP servers behave in different way during seek operation. ff* tools may produce incomplete content due to server limitations. -This protocol accepts the following options: - -@table @option -@item follow -If set to 1, the protocol will retry reading at the end of the file, allowing -reading files that still are being written. In order for this to terminate, -you either need to use the rw_timeout option, or use the interrupt callback -(for API users). - -@end table - @section gopher Gopher protocol. @@ -390,6 +393,11 @@ ffmpeg -i somefile.ogg -chunked_post 0 -c copy -f ogg http://@var{server}:@var{p wget --post-file=somefile.ogg http://@var{server}:@var{port} @end example +@item send_expect_100 +Send an Expect: 100-continue header for POST. If set to 1 it will send, if set +to 0 it won't, if set to -1 it will try to send if it is applicable. Default +value is -1. + @end table @subsection HTTP Cookies @@ -1210,6 +1218,17 @@ IP Type of Service. Applies to sender only. Default value is 0xB8. @item ipttl=@var{ttl} IP Time To Live. Applies to sender only. Default value is 64. +@item latency +Timestamp-based Packet Delivery Delay. +Used to absorb bursts of missed packet retransmissions. +This flag sets both @option{rcvlatency} and @option{peerlatency} +to the same value. Note that prior to version 1.3.0 +this is the only flag to set the latency, however +this is effectively equivalent to setting @option{peerlatency}, +when side is sender and @option{rcvlatency} +when side is receiver, and the bidirectional stream +sending is not supported. + @item listen_timeout Set socket listen timeout. @@ -1255,6 +1274,25 @@ only if @option{pbkeylen} is non-zero. It is used on the receiver only if the received data is encrypted. The configured passphrase cannot be recovered (write-only). +@item payload_size=@var{bytes} +Sets the maximum declared size of a packet transferred +during the single call to the sending function in Live +mode. Use 0 if this value isn't used (which is default in +file mode). +Default is -1 (automatic), which typically means MPEG-TS; +if you are going to use SRT +to send any different kind of payload, such as, for example, +wrapping a live stream in very small frames, then you can +use a bigger maximum frame size, though not greater than +1456 bytes. + +@item pkt_size=@var{bytes} +Alias for @samp{payload_size}. + +@item peerlatency +The latency value (as described in @option{rcvlatency}) that is +set by the sender side as a minimum value for the receiver. + @item pbkeylen=@var{bytes} Sender encryption key length, in bytes. Only can be set to 0, 16, 24 and 32. @@ -1263,11 +1301,23 @@ Not required on receiver (set to 0), key size obtained from sender in HaiCrypt handshake. Default value is 0. +@item rcvlatency +The time that should elapse since the moment when the +packet was sent and the moment when it's delivered to +the receiver application in the receiving function. +This time should be a buffer time large enough to cover +the time spent for sending, unexpectedly extended RTT +time, and the time needed to retransmit the lost UDP +packet. The effective latency value will be the maximum +of this options' value and the value of @option{peerlatency} +set by the peer side. Before version 1.3.0 this option +is only available as @option{latency}. + @item recv_buffer_size=@var{bytes} -Set receive buffer size, expressed in bytes. +Set UDP receive buffer size, expressed in bytes. @item send_buffer_size=@var{bytes} -Set send buffer size, expressed in bytes. +Set UDP send buffer size, expressed in bytes. @item rw_timeout Set raise error timeout for read/write optations. @@ -1287,9 +1337,86 @@ have no chance of being delivered in time. It was automatically enabled in the sender if the receiver supports it. -@item tsbpddelay -Timestamp-based Packet Delivery Delay. -Used to absorb burst of missed packet retransmission. +@item sndbuf=@var{bytes} +Set send buffer size, expressed in bytes. + +@item rcvbuf=@var{bytes} +Set receive buffer size, expressed in bytes. + +Receive buffer must not be greater than @option{ffs}. + +@item lossmaxttl=@var{packets} +The value up to which the Reorder Tolerance may grow. When +Reorder Tolerance is > 0, then packet loss report is delayed +until that number of packets come in. Reorder Tolerance +increases every time a "belated" packet has come, but it +wasn't due to retransmission (that is, when UDP packets tend +to come out of order), with the difference between the latest +sequence and this packet's sequence, and not more than the +value of this option. By default it's 0, which means that this +mechanism is turned off, and the loss report is always sent +immediately upon experiencing a "gap" in sequences. + +@item minversion +The minimum SRT version that is required from the peer. A connection +to a peer that does not satisfy the minimum version requirement +will be rejected. + +The version format in hex is 0xXXYYZZ for x.y.z in human readable +form. + +@item streamid=@var{string} +A string limited to 512 characters that can be set on the socket prior +to connecting. This stream ID will be able to be retrieved by the +listener side from the socket that is returned from srt_accept and +was connected by a socket with that set stream ID. SRT does not enforce +any special interpretation of the contents of this string. +This option doesn’t make sense in Rendezvous connection; the result +might be that simply one side will override the value from the other +side and it’s the matter of luck which one would win + +@item smoother=@var{live|file} +The type of Smoother used for the transmission for that socket, which +is responsible for the transmission and congestion control. The Smoother +type must be exactly the same on both connecting parties, otherwise +the connection is rejected. + +@item messageapi=@var{1|0} +When set, this socket uses the Message API, otherwise it uses Buffer +API. Note that in live mode (see @option{transtype}) there’s only +message API available. In File mode you can chose to use one of two modes: + +Stream API (default, when this option is false). In this mode you may +send as many data as you wish with one sending instruction, or even use +dedicated functions that read directly from a file. The internal facility +will take care of any speed and congestion control. When receiving, you +can also receive as many data as desired, the data not extracted will be +waiting for the next call. There is no boundary between data portions in +the Stream mode. + +Message API. In this mode your single sending instruction passes exactly +one piece of data that has boundaries (a message). Contrary to Live mode, +this message may span across multiple UDP packets and the only size +limitation is that it shall fit as a whole in the sending buffer. The +receiver shall use as large buffer as necessary to receive the message, +otherwise the message will not be given up. When the message is not +complete (not all packets received or there was a packet loss) it will +not be given up. + +@item transtype=@var{live|file} +Sets the transmission type for the socket, in particular, setting this +option sets multiple other parameters to their default values as required +for a particular transmission type. + +live: Set options as for live transmission. In this mode, you should +send by one sending instruction only so many data that fit in one UDP packet, +and limited to the value defined first in @option{payload_size} (1316 is +default in this mode). There is no speed control in this mode, only the +bandwidth control, if configured, in order to not exceed the bandwidth with +the overhead transmission (retransmitted and control packets). + +file: Set options as for non-live transmission. See @option{messageapi} +for further explanations @end table @@ -1397,6 +1524,9 @@ Set send buffer size, expressed bytes. @item tcp_nodelay=@var{1|0} Set TCP_NODELAY to disable Nagle's algorithm. Default value is 0. + +@item tcp_mss=@var{bytes} +Set maximum segment size for outgoing TCP packets, expressed in bytes. @end table The following example shows how to setup a listening TCP connection @@ -1503,9 +1633,8 @@ packet bursts. Override the local UDP port to bind with. @item localaddr=@var{addr} -Choose the local IP address. This is useful e.g. if sending multicast -and the host has multiple interfaces, where the user can choose -which interface to send on by specifying the IP address of that interface. +Local IP address of a network interface used for sending packets or joining +multicast groups. @item pkt_size=@var{size} Set the size in bytes of UDP packets. @@ -1528,12 +1657,12 @@ For receiving, this gives the benefit of only receiving packets from the specified peer address/port. @item sources=@var{address}[,@var{address}] -Only receive packets sent to the multicast group from one of the -specified sender IP addresses. +Only receive packets sent from the specified addresses. In case of multicast, +also subscribe to multicast traffic coming from these addresses only. @item block=@var{address}[,@var{address}] -Ignore packets sent to the multicast group from the specified -sender IP addresses. +Ignore packets sent from the specified addresses. In case of multicast, also +exclude the source addresses in the multicast subscription. @item fifo_size=@var{units} Set the UDP receiving circular buffer size, expressed as a number of diff --git a/doc/scaler.texi b/doc/scaler.texi index f73804adf..eb045de6b 100644 --- a/doc/scaler.texi +++ b/doc/scaler.texi @@ -5,7 +5,8 @@ The video scaler supports the following named options. Options may be set by specifying -@var{option} @var{value} in the -FFmpeg tools. For programmatic use, they can be set explicitly in the +FFmpeg tools, with a few API-only exceptions noted below. +For programmatic use, they can be set explicitly in the @code{SwsContext} options or through the @file{libavutil/opt.h} API. @table @option @@ -47,7 +48,8 @@ Select Gaussian rescaling algorithm. Select sinc rescaling algorithm. @item lanczos -Select Lanczos rescaling algorithm. +Select Lanczos rescaling algorithm. The default width (alpha) is 3 and can be +changed by setting @code{param0}. @item spline Select natural bicubic spline rescaling algorithm. @@ -68,29 +70,31 @@ Select full chroma input. Enable bitexact output. @end table -@item srcw +@item srcw @var{(API only)} Set source width. -@item srch +@item srch @var{(API only)} Set source height. -@item dstw +@item dstw @var{(API only)} Set destination width. -@item dsth +@item dsth @var{(API only)} Set destination height. -@item src_format +@item src_format @var{(API only)} Set source pixel format (must be expressed as an integer). -@item dst_format +@item dst_format @var{(API only)} Set destination pixel format (must be expressed as an integer). -@item src_range -Select source range. +@item src_range @var{(boolean)} +If value is set to @code{1}, indicates source is full range. Default value is +@code{0}, which indicates source is limited range. -@item dst_range -Select destination range. +@item dst_range @var{(boolean)} +If value is set to @code{1}, enable full range for destination. Default value +is @code{0}, which enables limited range. @anchor{sws_params} @item param0, param1 diff --git a/doc/snow.txt b/doc/snow.txt index bbf28bc6c..b4098fd64 100644 --- a/doc/snow.txt +++ b/doc/snow.txt @@ -172,7 +172,7 @@ spatial_decomposition_count FIXME colorspace_type - 0 unspecified YcbCr + 0 unspecified YCbCr 1 Gray 2 Gray + Alpha 3 GBR @@ -235,7 +235,7 @@ spatial_decomposition_type stored as delta from last, last is reset to 0 if always_reset || keyframe qlog - quality (logarthmic quantizer scale) + quality (logarithmic quantizer scale) stored as delta from last, last is reset to 0 if always_reset || keyframe mv_scale @@ -251,11 +251,11 @@ block_max_depth stored as delta from last, last is reset to 0 if always_reset || keyframe quant_table - quantiztation table + quantization table Highlevel bitstream structure: -============================= +============================== -------------------------------------------- | Header | -------------------------------------------- @@ -303,7 +303,7 @@ Decoding process: | Intra DC | | | | LL0 subband prediction ------------ | - \ Dequantizaton + \ Dequantization ------------------- \ | | Reference frames | \ IDWT | ------- ------- | Motion \ | @@ -390,8 +390,8 @@ motion vector prediction (mvx_diff, mvy_diff)*mv_scale -Intra DC Predicton: -====================== +Intra DC Prediction: +==================== the luma and chroma values of the left block are used as predictors the used luma and chroma is the sum of the predictor and y_diff, cb_diff, cr_diff @@ -407,7 +407,7 @@ Motion Compensation: Halfpel interpolation: ---------------------- -halfpel interpolation is done by convolution with the halfpel filter stored +Halfpel interpolation is done by convolution with the halfpel filter stored in the header: horizontal halfpel samples are found by @@ -463,8 +463,8 @@ to the closest available fullpel sample Smaller pel interpolation: -------------------------- if diag_mc is set then points which lie on a line between 2 vertically, -horiziontally or diagonally adjacent halfpel points shall be interpolated -linearls with rounding to nearest and halfway values rounded up. +horizontally or diagonally adjacent halfpel points shall be interpolated +linearly with rounding to nearest and halfway values rounded up. points which lie on 2 diagonals at the same time should only use the one diagonal not containing the fullpel point @@ -519,8 +519,8 @@ width,height here are the width and height of the LL0 subband not of the final video -Dequantizaton: -============== +Dequantization: +=============== FIXME Wavelet Transform: diff --git a/doc/writing_filters.txt b/doc/writing_filters.txt index 98b9c6f3d..2e25cbed7 100644 --- a/doc/writing_filters.txt +++ b/doc/writing_filters.txt @@ -389,7 +389,7 @@ distributor with something like this: td.in = in; td.out = out; - ctx->internal->execute(ctx, filter_slice, &td, NULL, FFMIN(outlink->h, ctx->graph->nb_threads)); + ctx->internal->execute(ctx, filter_slice, &td, NULL, FFMIN(outlink->h, ff_filter_get_nb_threads(ctx))); // ... diff --git a/ffbuild/common.mak b/ffbuild/common.mak index eb41b05ee..7355508ea 100644 --- a/ffbuild/common.mak +++ b/ffbuild/common.mak @@ -38,7 +38,6 @@ OBJCCFLAGS = $(CPPFLAGS) $(CFLAGS) $(OBJCFLAGS) ASFLAGS := $(CPPFLAGS) $(ASFLAGS) CXXFLAGS := $(CPPFLAGS) $(CFLAGS) $(CXXFLAGS) X86ASMFLAGS += $(IFLAGS:%=%/) -I$($@ -%.ptx: %.cu +%.ptx: %.cu $(SRC_PATH)/compat/cuda/cuda_runtime.h $(COMPILE_NVCC) %.ptx.c: %.ptx @@ -161,7 +160,7 @@ $(SLIBOBJS): | $(sort $(dir $(SLIBOBJS))) $(TESTOBJS): | $(sort $(dir $(TESTOBJS))) $(TOOLOBJS): | tools -OBJDIRS := $(OBJDIRS) $(dir $(OBJS) $(HOBJS) $(HOSTOBJS) $(SLIBOBJS) $(TESTOBJS)) +OUTDIRS := $(OUTDIRS) $(dir $(OBJS) $(HOBJS) $(HOSTOBJS) $(SLIBOBJS) $(TESTOBJS)) CLEANSUFFIXES = *.d *.gcda *.gcno *.h.c *.ho *.map *.o *.pc *.ptx *.ptx.c *.ver *.version *$(DEFAULT_X86ASMD).asm *~ LIBSUFFIXES = *.a *.lib *.so *.so.* *.dylib *.dll *.def *.dll.a diff --git a/fftools/Makefile b/fftools/Makefile index c3a0ff340..6cec666dd 100644 --- a/fftools/Makefile +++ b/fftools/Makefile @@ -32,7 +32,7 @@ $(foreach P,$(AVPROGS-yes),$(eval $(call DOFFTOOL,$(P)))) all: $(AVPROGS) fftools/ffprobe.o fftools/cmdutils.o: libavutil/ffversion.h | fftools -OBJDIRS += fftools +OUTDIRS += fftools ifdef AVPROGS install: install-progs install-data diff --git a/fftools/cmdutils.c b/fftools/cmdutils.c index 8ffc9d240..9cfbc45c2 100644 --- a/fftools/cmdutils.c +++ b/fftools/cmdutils.c @@ -1018,7 +1018,7 @@ static int init_report(const char *env) av_free(key); } - av_bprint_init(&filename, 0, 1); + av_bprint_init(&filename, 0, AV_BPRINT_SIZE_AUTOMATIC); expand_filename_template(&filename, av_x_if_null(filename_template, "%p-%t.log"), tm); av_free(filename_template); @@ -1414,6 +1414,16 @@ static void print_codec(const AVCodec *c) AV_CODEC_CAP_SLICE_THREADS | AV_CODEC_CAP_AUTO_THREADS)) printf("threads "); + if (c->capabilities & AV_CODEC_CAP_AVOID_PROBING) + printf("avoidprobe "); + if (c->capabilities & AV_CODEC_CAP_INTRA_ONLY) + printf("intraonly "); + if (c->capabilities & AV_CODEC_CAP_LOSSLESS) + printf("lossless "); + if (c->capabilities & AV_CODEC_CAP_HARDWARE) + printf("hardware "); + if (c->capabilities & AV_CODEC_CAP_HYBRID) + printf("hybrid "); if (!c->capabilities) printf("none"); printf("\n"); @@ -1434,6 +1444,17 @@ static void print_codec(const AVCodec *c) printf("\n"); } + if (avcodec_get_hw_config(c, 0)) { + printf(" Supported hardware devices: "); + for (int i = 0;; i++) { + const AVCodecHWConfig *config = avcodec_get_hw_config(c, i); + if (!config) + break; + printf("%s ", av_hwdevice_get_type_name(config->device_type)); + } + printf("\n"); + } + if (c->supported_framerates) { const AVRational *fps = c->supported_framerates; @@ -1935,7 +1956,10 @@ static void show_help_bsf(const char *name) { const AVBitStreamFilter *bsf = av_bsf_get_by_name(name); - if (!bsf) { + if (!name) { + av_log(NULL, AV_LOG_ERROR, "No bitstream filter name specified.\n"); + return; + } else if (!bsf) { av_log(NULL, AV_LOG_ERROR, "Unknown bit stream filter '%s'.\n", name); return; } diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c index d436a0e71..01f04103c 100644 --- a/fftools/ffmpeg.c +++ b/fftools/ffmpeg.c @@ -120,8 +120,14 @@ const char *const forced_keyframes_const_names[] = { NULL }; +typedef struct BenchmarkTimeStamps { + int64_t real_usec; + int64_t user_usec; + int64_t sys_usec; +} BenchmarkTimeStamps; + static void do_video_stats(OutputStream *ost, int frame_size); -static int64_t getutime(void); +static BenchmarkTimeStamps get_benchmark_time_stamps(void); static int64_t getmaxrss(void); static int ifilter_has_all_input_formats(FilterGraph *fg); @@ -133,7 +139,7 @@ static int64_t decode_error_stat[2]; static int want_sdp = 1; -static int current_time; +static BenchmarkTimeStamps current_time; AVIOContext *progress_avio = NULL; static uint8_t *subtitle_out; @@ -653,7 +659,7 @@ static void abort_codec_experimental(AVCodec *c, int encoder) static void update_benchmark(const char *fmt, ...) { if (do_benchmark_all) { - int64_t t = getutime(); + BenchmarkTimeStamps t = get_benchmark_time_stamps(); va_list va; char buf[1024]; @@ -661,7 +667,11 @@ static void update_benchmark(const char *fmt, ...) va_start(va, fmt); vsnprintf(buf, sizeof(buf), fmt, va); va_end(va); - av_log(NULL, AV_LOG_INFO, "bench: %8"PRIu64" %s \n", t - current_time, buf); + av_log(NULL, AV_LOG_INFO, + "bench: %8" PRIu64 " user %8" PRIu64 " sys %8" PRIu64 " real %s \n", + t.user_usec - current_time.user_usec, + t.sys_usec - current_time.sys_usec, + t.real_usec - current_time.real_usec, buf); } current_time = t; } @@ -714,11 +724,11 @@ static void write_packet(OutputFile *of, AVPacket *pkt, OutputStream *ost, int u if (ret < 0) exit_program(1); } - ret = av_packet_ref(&tmp_pkt, pkt); + ret = av_packet_make_refcounted(pkt); if (ret < 0) exit_program(1); + av_packet_move_ref(&tmp_pkt, pkt); av_fifo_generic_write(ost->muxing_queue, &tmp_pkt, sizeof(tmp_pkt), NULL); - av_packet_unref(pkt); return; } @@ -762,7 +772,7 @@ static void write_packet(OutputFile *of, AVPacket *pkt, OutputStream *ost, int u - FFMIN3(pkt->pts, pkt->dts, ost->last_mux_dts + 1) - FFMAX3(pkt->pts, pkt->dts, ost->last_mux_dts + 1); } - if ((st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO || st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) && + if ((st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO || st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO || st->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE) && pkt->dts != AV_NOPTS_VALUE && !(st->codecpar->codec_id == AV_CODEC_ID_VP9 && ost->stream_copy) && ost->last_mux_dts != AV_NOPTS_VALUE) { @@ -1069,6 +1079,7 @@ static void do_video_out(OutputFile *of, if (!ost->filters_script && !ost->filters && + (nb_filtergraphs == 0 || !filtergraphs[0]->graph_desc) && next_picture && ist && lrintf(next_picture->pkt_duration * av_q2d(ist->st->time_base) / av_q2d(enc->time_base)) > 0) { @@ -1111,7 +1122,7 @@ static void do_video_out(OutputFile *of, format_video_sync != VSYNC_PASSTHROUGH && format_video_sync != VSYNC_DROP) { if (delta0 < -0.6) { - av_log(NULL, AV_LOG_WARNING, "Past duration %f too large\n", -delta0); + av_log(NULL, AV_LOG_VERBOSE, "Past duration %f too large\n", -delta0); } else av_log(NULL, AV_LOG_DEBUG, "Clipping frame in rate conversion by %f\n", -delta0); sync_ipts = ost->sync_opts; @@ -1183,33 +1194,27 @@ static void do_video_out(OutputFile *of, } ost->last_dropped = nb_frames == nb0_frames && next_picture; - /* duplicates frame if needed */ - for (i = 0; i < nb_frames; i++) { - AVFrame *in_picture; - av_init_packet(&pkt); - pkt.data = NULL; - pkt.size = 0; - - if (i < nb0_frames && ost->last_frame) { - in_picture = ost->last_frame; - } else - in_picture = next_picture; - - if (!in_picture) - return; - - in_picture->pts = ost->sync_opts; - -#if 1 - if (!check_recording_time(ost)) -#else - if (ost->frame_number >= ost->max_frames) -#endif - return; - - { + /* duplicates frame if needed */ + for (i = 0; i < nb_frames; i++) { + AVFrame *in_picture; int forced_keyframe = 0; double pts_time; + av_init_packet(&pkt); + pkt.data = NULL; + pkt.size = 0; + + if (i < nb0_frames && ost->last_frame) { + in_picture = ost->last_frame; + } else + in_picture = next_picture; + + if (!in_picture) + return; + + in_picture->pts = ost->sync_opts; + + if (!check_recording_time(ost)) + return; if (enc->flags & (AV_CODEC_FLAG_INTERLACED_DCT | AV_CODEC_FLAG_INTERLACED_ME) && ost->top_field_first >= 0) @@ -1226,8 +1231,12 @@ static void do_video_out(OutputFile *of, in_picture->quality = enc->global_quality; in_picture->pict_type = 0; + if (ost->forced_kf_ref_pts == AV_NOPTS_VALUE && + in_picture->pts != AV_NOPTS_VALUE) + ost->forced_kf_ref_pts = in_picture->pts; + pts_time = in_picture->pts != AV_NOPTS_VALUE ? - in_picture->pts * av_q2d(enc->time_base) : NAN; + (in_picture->pts - ost->forced_kf_ref_pts) * av_q2d(enc->time_base) : NAN; if (ost->forced_kf_index < ost->forced_kf_count && in_picture->pts >= ost->forced_kf_pts[ost->forced_kf_index]) { ost->forced_kf_index++; @@ -1278,6 +1287,8 @@ static void do_video_out(OutputFile *of, ret = avcodec_send_frame(enc, in_picture); if (ret < 0) goto error; + // Make sure Closed Captions will not be duplicated + av_frame_remove_side_data(in_picture, AV_FRAME_DATA_A53_CC); while (1) { ret = avcodec_receive_packet(enc, &pkt); @@ -1314,18 +1325,17 @@ static void do_video_out(OutputFile *of, fprintf(ost->logfile, "%s", enc->stats_out); } } - } - ost->sync_opts++; - /* - * For video, number of frames in == number of packets out. - * But there may be reordering, so we can't throw away frames on encoder - * flush, we need to limit them here, before they go into encoder. - */ - ost->frame_number++; + ost->sync_opts++; + /* + * For video, number of frames in == number of packets out. + * But there may be reordering, so we can't throw away frames on encoder + * flush, we need to limit them here, before they go into encoder. + */ + ost->frame_number++; - if (vstats_filename && frame_size) - do_video_stats(ost, frame_size); - } + if (vstats_filename && frame_size) + do_video_stats(ost, frame_size); + } if (!ost->last_frame) ost->last_frame = av_frame_alloc(); @@ -1478,8 +1488,6 @@ static int reap_filters(int flush) av_rescale_q(filtered_frame->pts, filter_tb, enc->time_base) - av_rescale_q(start_time, AV_TIME_BASE_Q, enc->time_base); } - //if (ost->source_index >= 0) - // *filtered_frame= *input_streams[ost->source_index]->decoded_frame; //for me_threshold switch (av_buffersink_get_type(filter)) { case AVMEDIA_TYPE_VIDEO: @@ -1675,7 +1683,7 @@ static void print_report(int is_last_report, int64_t timer_start, int64_t cur_ti vid = 0; av_bprint_init(&buf, 0, AV_BPRINT_SIZE_AUTOMATIC); - av_bprint_init(&buf_script, 0, 1); + av_bprint_init(&buf_script, 0, AV_BPRINT_SIZE_AUTOMATIC); for (i = 0; i < nb_output_streams; i++) { float q = -1; ost = output_streams[i]; @@ -1696,7 +1704,7 @@ static void print_report(int is_last_report, int64_t timer_start, int64_t cur_ti av_bprintf(&buf, "frame=%5d fps=%3.*f q=%3.1f ", frame_number, fps < 9.95, fps, q); av_bprintf(&buf_script, "frame=%d\n", frame_number); - av_bprintf(&buf_script, "fps=%.1f\n", fps); + av_bprintf(&buf_script, "fps=%.2f\n", fps); av_bprintf(&buf_script, "stream_%d_%d_q=%.1f\n", ost->file_index, ost->index, q); if (is_last_report) @@ -1780,9 +1788,11 @@ static void print_report(int is_last_report, int64_t timer_start, int64_t cur_ti if (total_size < 0) av_bprintf(&buf_script, "total_size=N/A\n"); else av_bprintf(&buf_script, "total_size=%"PRId64"\n", total_size); if (pts == AV_NOPTS_VALUE) { + av_bprintf(&buf_script, "out_time_us=N/A\n"); av_bprintf(&buf_script, "out_time_ms=N/A\n"); av_bprintf(&buf_script, "out_time=N/A\n"); } else { + av_bprintf(&buf_script, "out_time_us=%"PRId64"\n", pts); av_bprintf(&buf_script, "out_time_ms=%"PRId64"\n", pts); av_bprintf(&buf_script, "out_time=%s%02d:%02d:%02d.%06d\n", hours_sign, hours, mins, secs, us); @@ -1808,7 +1818,7 @@ static void print_report(int is_last_report, int64_t timer_start, int64_t cur_ti } else av_log(NULL, AV_LOG_INFO, "%s %c", buf.str, end); - fflush(stderr); + fflush(stderr); } av_bprint_finalize(&buf, NULL); @@ -1915,46 +1925,46 @@ static void flush_encoders(void) av_assert0(0); } - av_init_packet(&pkt); - pkt.data = NULL; - pkt.size = 0; + av_init_packet(&pkt); + pkt.data = NULL; + pkt.size = 0; - update_benchmark(NULL); + update_benchmark(NULL); - while ((ret = avcodec_receive_packet(enc, &pkt)) == AVERROR(EAGAIN)) { - ret = avcodec_send_frame(enc, NULL); - if (ret < 0) { - av_log(NULL, AV_LOG_FATAL, "%s encoding failed: %s\n", - desc, - av_err2str(ret)); - exit_program(1); - } - } - - update_benchmark("flush_%s %d.%d", desc, ost->file_index, ost->index); - if (ret < 0 && ret != AVERROR_EOF) { + while ((ret = avcodec_receive_packet(enc, &pkt)) == AVERROR(EAGAIN)) { + ret = avcodec_send_frame(enc, NULL); + if (ret < 0) { av_log(NULL, AV_LOG_FATAL, "%s encoding failed: %s\n", desc, av_err2str(ret)); exit_program(1); } - if (ost->logfile && enc->stats_out) { - fprintf(ost->logfile, "%s", enc->stats_out); - } - if (ret == AVERROR_EOF) { - output_packet(of, &pkt, ost, 1); - break; - } - if (ost->finished & MUXER_FINISHED) { - av_packet_unref(&pkt); - continue; - } - av_packet_rescale_ts(&pkt, enc->time_base, ost->mux_timebase); - pkt_size = pkt.size; - output_packet(of, &pkt, ost, 0); - if (ost->enc_ctx->codec_type == AVMEDIA_TYPE_VIDEO && vstats_filename) { - do_video_stats(ost, pkt_size); - } + } + + update_benchmark("flush_%s %d.%d", desc, ost->file_index, ost->index); + if (ret < 0 && ret != AVERROR_EOF) { + av_log(NULL, AV_LOG_FATAL, "%s encoding failed: %s\n", + desc, + av_err2str(ret)); + exit_program(1); + } + if (ost->logfile && enc->stats_out) { + fprintf(ost->logfile, "%s", enc->stats_out); + } + if (ret == AVERROR_EOF) { + output_packet(of, &pkt, ost, 1); + break; + } + if (ost->finished & MUXER_FINISHED) { + av_packet_unref(&pkt); + continue; + } + av_packet_rescale_ts(&pkt, enc->time_base, ost->mux_timebase); + pkt_size = pkt.size; + output_packet(of, &pkt, ost, 0); + if (ost->enc_ctx->codec_type == AVMEDIA_TYPE_VIDEO && vstats_filename) { + do_video_stats(ost, pkt_size); + } } } } @@ -2094,10 +2104,12 @@ static void check_decode_result(InputStream *ist, int *got_output, int ret) if (ret < 0 && exit_on_error) exit_program(1); - if (exit_on_error && *got_output && ist) { + if (*got_output && ist) { if (ist->decoded_frame->decode_error_flags || (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->url, ist->st->index); - exit_program(1); + av_log(NULL, exit_on_error ? AV_LOG_FATAL : AV_LOG_WARNING, + "%s: corrupt decoded frame in stream %d\n", input_files[ist->file_index]->ctx->url, ist->st->index); + if (exit_on_error) + exit_program(1); } } } @@ -2301,14 +2313,12 @@ static int decode_audio(InputStream *ist, AVPacket *pkt, int *got_output, ist->samples_decoded += decoded_frame->nb_samples; ist->frames_decoded++; -#if 1 /* increment next_dts to use for the case where the input stream does not have timestamps or there are multiple frames in the packet */ ist->next_pts += ((int64_t)AV_TIME_BASE * decoded_frame->nb_samples) / avctx->sample_rate; ist->next_dts += ((int64_t)AV_TIME_BASE * decoded_frame->nb_samples) / avctx->sample_rate; -#endif if (decoded_frame->pts != AV_NOPTS_VALUE) { decoded_frame_tb = ist->st->time_base; @@ -2700,6 +2710,7 @@ static int process_input_packet(InputStream *ist, const AVPacket *pkt, int no_eo ist->dts = ist->next_dts; switch (ist->dec_ctx->codec_type) { case AVMEDIA_TYPE_AUDIO: + av_assert1(pkt->duration >= 0); if (ist->dec_ctx->sample_rate) { ist->next_dts += ((int64_t)AV_TIME_BASE * ist->dec_ctx->frame_size) / ist->dec_ctx->sample_rate; @@ -3059,7 +3070,13 @@ static int init_output_stream_streamcopy(OutputStream *ost) "Error setting up codec context options.\n"); return ret; } - avcodec_parameters_from_context(par_src, ost->enc_ctx); + + ret = avcodec_parameters_from_context(par_src, ost->enc_ctx); + if (ret < 0) { + av_log(NULL, AV_LOG_FATAL, + "Error getting reference codec parameters.\n"); + return ret; + } if (!codec_tag) { unsigned int codec_tag_tmp; @@ -3324,7 +3341,7 @@ static int init_output_stream_encode(OutputStream *ost) "if you want a different framerate.\n", ost->file_index, ost->index); } -// ost->frame_rate = ist->st->avg_frame_rate.num ? ist->st->avg_frame_rate : (AVRational){25, 1}; + if (ost->enc->supported_framerates && !ost->force_fps) { int idx = av_find_nearest_q_idx(ost->frame_rate, ost->enc->supported_framerates); ost->frame_rate = ost->enc->supported_framerates[idx]; @@ -3387,6 +3404,12 @@ static int init_output_stream_encode(OutputStream *ost) enc_ctx->bits_per_raw_sample = frame_bits_per_raw_sample; } + if (ost->top_field_first == 0) { + enc_ctx->field_order = AV_FIELD_BB; + } else if (ost->top_field_first == 1) { + enc_ctx->field_order = AV_FIELD_TT; + } + if (ost->forced_keyframes) { if (!strncmp(ost->forced_keyframes, "expr:", 5)) { ret = av_expr_parse(&ost->forced_keyframes_pexpr, ost->forced_keyframes+5, @@ -3401,8 +3424,8 @@ static int init_output_stream_encode(OutputStream *ost) ost->forced_keyframes_expr_const_values[FKF_PREV_FORCED_N] = NAN; ost->forced_keyframes_expr_const_values[FKF_PREV_FORCED_T] = NAN; - // Don't parse the 'forced_keyframes' in case of 'keep-source-keyframes', - // parse it only for static kf timings + // Don't parse the 'forced_keyframes' in case of 'keep-source-keyframes', + // parse it only for static kf timings } else if(strncmp(ost->forced_keyframes, "source", 6)) { parse_forced_key_frames(ost->forced_keyframes, ost, ost->enc_ctx); } @@ -3473,6 +3496,23 @@ static int init_output_stream(OutputStream *ost, char *error, int error_len) return ret; } } + if (ist && ist->dec->type == AVMEDIA_TYPE_SUBTITLE && ost->enc->type == AVMEDIA_TYPE_SUBTITLE) { + int input_props = 0, output_props = 0; + AVCodecDescriptor const *input_descriptor = + avcodec_descriptor_get(dec->codec_id); + AVCodecDescriptor const *output_descriptor = + avcodec_descriptor_get(ost->enc_ctx->codec_id); + if (input_descriptor) + input_props = input_descriptor->props & (AV_CODEC_PROP_TEXT_SUB | AV_CODEC_PROP_BITMAP_SUB); + if (output_descriptor) + output_props = output_descriptor->props & (AV_CODEC_PROP_TEXT_SUB | AV_CODEC_PROP_BITMAP_SUB); + if (input_props && output_props && input_props != output_props) { + snprintf(error, error_len, + "Subtitle encoding currently only possible from text to text " + "or bitmap to bitmap"); + return AVERROR_INVALIDDATA; + } + } if ((ret = avcodec_open2(ost->enc_ctx, codec, &ost->encoder_opts)) < 0) { if (ret == AVERROR_EXPERIMENTAL) @@ -3835,7 +3875,9 @@ static OutputStream *choose_output(void) 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"); + av_log(NULL, AV_LOG_DEBUG, + "cur_dts is invalid st:%d (%d) [init:%d i_done:%d finish:%d] (this is harmless if it occurs once at the start per stream)\n", + ost->st->index, ost->st->id, ost->initialized, ost->inputs_done, ost->finished); if (!ost->initialized && !ost->inputs_done) return ost; @@ -4128,7 +4170,7 @@ static void reset_eagain(void) // 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) + AVRational time_base) { int ret; @@ -4308,9 +4350,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->url, pkt.stream_index); - exit_program(1); + if (pkt.flags & AV_PKT_FLAG_CORRUPT) { + av_log(NULL, exit_on_error ? AV_LOG_FATAL : AV_LOG_WARNING, + "%s: corrupt input packet in stream %d\n", is->url, pkt.stream_index); + if (exit_on_error) + exit_program(1); } if (debug_ts) { @@ -4430,7 +4474,10 @@ static int process_input(int file_index) pkt_dts + AV_TIME_BASE/10 < FFMAX(ist->pts, ist->dts)) { ifile->ts_offset -= delta; av_log(NULL, AV_LOG_DEBUG, - "timestamp discontinuity %"PRId64", new offset= %"PRId64"\n", + "timestamp discontinuity for stream #%d:%d " + "(id=%d, type=%s): %"PRId64", new offset= %"PRId64"\n", + ist->file_index, ist->st->index, ist->st->id, + av_get_media_type_string(ist->dec_ctx->codec_type), delta, ifile->ts_offset); pkt.dts -= av_rescale_q(delta, AV_TIME_BASE_Q, ist->st->time_base); if (pkt.pts != AV_NOPTS_VALUE) @@ -4745,23 +4792,30 @@ static int transcode(void) return ret; } - -static int64_t getutime(void) +static BenchmarkTimeStamps get_benchmark_time_stamps(void) { + BenchmarkTimeStamps time_stamps = { av_gettime_relative() }; #if HAVE_GETRUSAGE struct rusage rusage; getrusage(RUSAGE_SELF, &rusage); - return (rusage.ru_utime.tv_sec * 1000000LL) + rusage.ru_utime.tv_usec; + time_stamps.user_usec = + (rusage.ru_utime.tv_sec * 1000000LL) + rusage.ru_utime.tv_usec; + time_stamps.sys_usec = + (rusage.ru_stime.tv_sec * 1000000LL) + rusage.ru_stime.tv_usec; #elif HAVE_GETPROCESSTIMES HANDLE proc; FILETIME c, e, k, u; proc = GetCurrentProcess(); GetProcessTimes(proc, &c, &e, &k, &u); - return ((int64_t) u.dwHighDateTime << 32 | u.dwLowDateTime) / 10; + time_stamps.user_usec = + ((int64_t)u.dwHighDateTime << 32 | u.dwLowDateTime) / 10; + time_stamps.sys_usec = + ((int64_t)k.dwHighDateTime << 32 | k.dwLowDateTime) / 10; #else - return av_gettime_relative(); + time_stamps.user_usec = time_stamps.sys_usec = 0; #endif + return time_stamps; } static int64_t getmaxrss(void) @@ -4789,7 +4843,7 @@ static void log_callback_null(void *ptr, int level, const char *fmt, va_list vl) int main(int argc, char **argv) { int i, ret; - int64_t ti; + BenchmarkTimeStamps ti; init_dynload(); @@ -4831,22 +4885,23 @@ int main(int argc, char **argv) exit_program(1); } -// if (nb_input_files == 0) { -// av_log(NULL, AV_LOG_FATAL, "At least one input file must be specified\n"); -// exit_program(1); -// } - for (i = 0; i < nb_output_files; i++) { if (strcmp(output_files[i]->ctx->oformat->name, "rtp")) want_sdp = 0; } - current_time = ti = getutime(); + current_time = ti = get_benchmark_time_stamps(); if (transcode() < 0) exit_program(1); - ti = getutime() - ti; if (do_benchmark) { - av_log(NULL, AV_LOG_INFO, "bench: utime=%0.3fs\n", ti / 1000000.0); + int64_t utime, stime, rtime; + current_time = get_benchmark_time_stamps(); + utime = current_time.user_usec - ti.user_usec; + stime = current_time.sys_usec - ti.sys_usec; + rtime = current_time.real_usec - ti.real_usec; + av_log(NULL, AV_LOG_INFO, + "bench: utime=%0.3fs stime=%0.3fs rtime=%0.3fs\n", + utime / 1000000.0, stime / 1000000.0, rtime / 1000000.0); } av_log(NULL, AV_LOG_DEBUG, "%"PRIu64" frames successfully decoded, %"PRIu64" decoding errors\n", decode_error_stat[0], decode_error_stat[1]); diff --git a/fftools/ffmpeg.h b/fftools/ffmpeg.h index d44b7a5c7..7b6f80208 100644 --- a/fftools/ffmpeg.h +++ b/fftools/ffmpeg.h @@ -72,7 +72,7 @@ typedef struct HWAccel { } HWAccel; typedef struct HWDevice { - char *name; + const char *name; enum AVHWDeviceType type; AVBufferRef *device_ref; } HWDevice; @@ -484,6 +484,7 @@ typedef struct OutputStream { AVRational frame_aspect_ratio; /* forced key frames */ + int64_t forced_kf_ref_pts; int64_t *forced_kf_pts; int forced_kf_count; int forced_kf_index; diff --git a/fftools/ffmpeg_filter.c b/fftools/ffmpeg_filter.c index 877fd670e..72838de1e 100644 --- a/fftools/ffmpeg_filter.c +++ b/fftools/ffmpeg_filter.c @@ -65,6 +65,7 @@ enum AVPixelFormat choose_pixel_fmt(AVStream *st, AVCodecContext *enc_ctx, AVCod if (codec && codec->pix_fmts) { const enum AVPixelFormat *p = codec->pix_fmts; const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(target); + //FIXME: This should check for AV_PIX_FMT_FLAG_ALPHA after PAL8 pixel format without alpha is implemented int has_alpha = desc ? desc->nb_components % 2 == 0 : 0; enum AVPixelFormat best= AV_PIX_FMT_NONE; @@ -292,10 +293,17 @@ static void init_input_filter(FilterGraph *fg, AVFilterInOut *in) exit_program(1); } ist = input_streams[input_files[file_idx]->ist_index + st->index]; + if (ist->user_set_discard == AVDISCARD_ALL) { + av_log(NULL, AV_LOG_FATAL, "Stream specifier '%s' in filtergraph description %s " + "matches a disabled input stream.\n", p, fg->graph_desc); + exit_program(1); + } } else { /* find the first unused stream of corresponding type */ for (i = 0; i < nb_input_streams; i++) { ist = input_streams[i]; + if (ist->user_set_discard == AVDISCARD_ALL) + continue; if (ist->dec_ctx->codec_type == type && ist->discard) break; } @@ -731,6 +739,7 @@ static int sub2video_prepare(InputStream *ist, InputFilter *ifilter) if (!ist->sub2video.frame) return AVERROR(ENOMEM); ist->sub2video.last_pts = INT64_MIN; + ist->sub2video.end_pts = INT64_MIN; return 0; } @@ -774,7 +783,7 @@ static int configure_input_video_filter(FilterGraph *fg, InputFilter *ifilter, sar = ifilter->sample_aspect_ratio; if(!sar.den) sar = (AVRational){0,1}; - av_bprint_init(&args, 0, 1); + av_bprint_init(&args, 0, AV_BPRINT_SIZE_AUTOMATIC); av_bprintf(&args, "video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:" "pixel_aspect=%d/%d:sws_param=flags=%d", diff --git a/fftools/ffmpeg_hw.c b/fftools/ffmpeg_hw.c index 2ec181385..962d8f7d5 100644 --- a/fftools/ffmpeg_hw.c +++ b/fftools/ffmpeg_hw.c @@ -99,7 +99,7 @@ int hw_device_init_from_string(const char *arg, HWDevice **dev_out) // -> av_hwdevice_ctx_create_derived() AVDictionary *options = NULL; - char *type_name = NULL, *name = NULL, *device = NULL; + const char *type_name = NULL, *name = NULL, *device = NULL; enum AVHWDeviceType type; HWDevice *dev, *src; AVBufferRef *device_ref = NULL; @@ -155,10 +155,12 @@ int hw_device_init_from_string(const char *arg, HWDevice **dev_out) ++p; q = strchr(p, ','); if (q) { - device = av_strndup(p, q - p); - if (!device) { - err = AVERROR(ENOMEM); - goto fail; + if (q - p > 0) { + device = av_strndup(p, q - p); + if (!device) { + err = AVERROR(ENOMEM); + goto fail; + } } err = av_dict_parse_string(&options, q + 1, "=", ",", 0); if (err < 0) { @@ -168,7 +170,8 @@ int hw_device_init_from_string(const char *arg, HWDevice **dev_out) } err = av_hwdevice_ctx_create(&device_ref, type, - device ? device : p, options, 0); + q ? device : p[0] ? p : NULL, + options, 0); if (err < 0) goto fail; diff --git a/fftools/ffmpeg_opt.c b/fftools/ffmpeg_opt.c index d7a7eb066..f5ca18aa6 100644 --- a/fftools/ffmpeg_opt.c +++ b/fftools/ffmpeg_opt.c @@ -268,7 +268,7 @@ static int opt_map(void *optctx, const char *opt, const char *arg) { OptionsContext *o = optctx; StreamMap *m = NULL; - int i, negative = 0, file_idx; + int i, negative = 0, file_idx, disabled = 0; int sync_file_idx = -1, sync_stream_idx = 0; char *p, *sync; char *map; @@ -303,6 +303,11 @@ static int opt_map(void *optctx, const char *opt, const char *arg) "match any streams.\n", arg); exit_program(1); } + if (input_streams[input_files[sync_file_idx]->ist_index + sync_stream_idx]->user_set_discard == AVDISCARD_ALL) { + av_log(NULL, AV_LOG_FATAL, "Sync stream specification in map %s matches a disabled input " + "stream.\n", arg); + exit_program(1); + } } @@ -339,6 +344,10 @@ static int opt_map(void *optctx, const char *opt, const char *arg) if (check_stream_specifier(input_files[file_idx]->ctx, input_files[file_idx]->ctx->streams[i], *p == ':' ? p + 1 : p) <= 0) continue; + if (input_streams[input_files[file_idx]->ist_index + i]->user_set_discard == AVDISCARD_ALL) { + disabled = 1; + continue; + } GROW_ARRAY(o->stream_maps, o->nb_stream_maps); m = &o->stream_maps[o->nb_stream_maps - 1]; @@ -358,6 +367,10 @@ static int opt_map(void *optctx, const char *opt, const char *arg) if (!m) { if (allow_unused) { av_log(NULL, AV_LOG_VERBOSE, "Stream map '%s' matches no streams; ignoring.\n", arg); + } else if (disabled) { + av_log(NULL, AV_LOG_FATAL, "Stream map '%s' matches disabled streams.\n" + "To ignore this, add a trailing '?' to the map.\n", arg); + exit_program(1); } else { av_log(NULL, AV_LOG_FATAL, "Stream map '%s' matches no streams.\n" "To ignore this, add a trailing '?' to the map.\n", arg); @@ -437,7 +450,8 @@ static int opt_map_channel(void *optctx, const char *opt, const char *arg) /* allow trailing ? to map_channel */ if (allow_unused = strchr(mapchan, '?')) *allow_unused = 0; - if (m->channel_idx < 0 || m->channel_idx >= st->codecpar->channels) { + if (m->channel_idx < 0 || m->channel_idx >= st->codecpar->channels || + input_streams[input_files[m->file_idx]->ist_index + m->stream_idx]->user_set_discard == AVDISCARD_ALL) { if (allow_unused) { av_log(NULL, AV_LOG_VERBOSE, "mapchan: invalid audio channel #%d.%d.%d\n", m->file_idx, m->stream_idx, m->channel_idx); @@ -746,6 +760,13 @@ static void add_input_streams(OptionsContext *o, AVFormatContext *ic) MATCH_PER_STREAM_OPT(discard, str, discard_str, ic, st); ist->user_set_discard = AVDISCARD_NONE; + + if ((o->video_disable && ist->st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) || + (o->audio_disable && ist->st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) || + (o->subtitle_disable && ist->st->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE) || + (o->data_disable && ist->st->codecpar->codec_type == AVMEDIA_TYPE_DATA)) + ist->user_set_discard = AVDISCARD_ALL; + if (discard_str && av_opt_eval_int(&cc, discard_opt, discard_str, &ist->user_set_discard) < 0) { av_log(NULL, AV_LOG_ERROR, "Error parsing discard %s.\n", discard_str); @@ -900,13 +921,14 @@ static void add_input_streams(OptionsContext *o, AVFormatContext *ic) static void assert_file_overwrite(const char *filename) { + const char *proto_name = avio_find_protocol_name(filename); + if (file_overwrite && no_file_overwrite) { fprintf(stderr, "Error, both -y and -n supplied. Exiting.\n"); exit_program(1); } if (!file_overwrite) { - const char *proto_name = avio_find_protocol_name(filename); if (proto_name && !strcmp(proto_name, "file") && avio_check(filename, 0) == 0) { if (stdin_interaction && !no_file_overwrite) { fprintf(stderr,"File '%s' already exists. Overwrite ? [y/N] ", filename); @@ -925,6 +947,19 @@ static void assert_file_overwrite(const char *filename) } } } + + if (proto_name && !strcmp(proto_name, "file")) { + for (int i = 0; i < nb_input_files; i++) { + InputFile *file = input_files[i]; + if (file->ctx->iformat->flags & AVFMT_NOFILE) + continue; + if (!strcmp(filename, file->ctx->url)) { + av_log(NULL, AV_LOG_FATAL, "Output %s same as Input #%d - exiting\n", filename, i); + av_log(NULL, AV_LOG_WARNING, "FFmpeg cannot edit existing files in-place.\n"); + exit_program(1); + } + } + } } static void dump_attachment(AVStream *st, const char *filename) @@ -1103,9 +1138,22 @@ static int open_input_file(OptionsContext *o, const char *filename) } } + if (o->start_time != AV_NOPTS_VALUE && o->start_time_eof != AV_NOPTS_VALUE) { + av_log(NULL, AV_LOG_WARNING, "Cannot use -ss and -sseof both, using -ss for %s\n", filename); + o->start_time_eof = AV_NOPTS_VALUE; + } + if (o->start_time_eof != AV_NOPTS_VALUE) { - if (ic->duration>0) { + if (o->start_time_eof >= 0) { + av_log(NULL, AV_LOG_ERROR, "-sseof value must be negative; aborting\n"); + exit_program(1); + } + if (ic->duration > 0) { o->start_time = o->start_time_eof + ic->duration; + if (o->start_time < 0) { + av_log(NULL, AV_LOG_WARNING, "-sseof value seeks to before start of file %s; ignored\n", filename); + o->start_time = AV_NOPTS_VALUE; + } } else av_log(NULL, AV_LOG_WARNING, "Cannot use -sseof, duration of %s not known\n", filename); } @@ -1122,8 +1170,10 @@ static int open_input_file(OptionsContext *o, const char *filename) int dts_heuristic = 0; for (i=0; inb_streams; i++) { const AVCodecParameters *par = ic->streams[i]->codecpar; - if (par->video_delay) + if (par->video_delay) { dts_heuristic = 1; + break; + } } if (dts_heuristic) { seek_timestamp -= 3*AV_TIME_BASE / 23; @@ -1324,6 +1374,7 @@ static OutputStream *new_output_stream(OptionsContext *o, AVFormatContext *oc, e ost->file_index = nb_output_files - 1; ost->index = idx; ost->st = st; + ost->forced_kf_ref_pts = AV_NOPTS_VALUE; st->codecpar->codec_type = type; ret = choose_encoder(o, oc, ost); @@ -1630,6 +1681,8 @@ static OutputStream *new_video_stream(OptionsContext *o, AVFormatContext *oc, in MATCH_PER_STREAM_OPT(filter_scripts, str, ost->filters_script, oc, st); MATCH_PER_STREAM_OPT(filters, str, ost->filters, oc, st); + if (o->nb_filters > 1) + av_log(NULL, AV_LOG_ERROR, "Only '-vf %s' read, ignoring remaining -vf options: Use ',' to separate filters\n", ost->filters); if (!ost->stream_copy) { const char *p = NULL; @@ -1811,6 +1864,8 @@ static OutputStream *new_audio_stream(OptionsContext *o, AVFormatContext *oc, in MATCH_PER_STREAM_OPT(filter_scripts, str, ost->filters_script, oc, st); MATCH_PER_STREAM_OPT(filters, str, ost->filters, oc, st); + if (o->nb_filters > 1) + av_log(NULL, AV_LOG_ERROR, "Only '-af %s' read, ignoring remaining -af options: Use ',' to separate filters\n", ost->filters); if (!ost->stream_copy) { char *sample_fmt = NULL; @@ -2143,7 +2198,10 @@ static int open_output_file(OptionsContext *o, const char *filename) for (i = 0; i < nb_input_streams; i++) { int new_area; ist = input_streams[i]; - new_area = ist->st->codecpar->width * ist->st->codecpar->height + 100000000*!!ist->st->codec_info_nb_frames; + new_area = ist->st->codecpar->width * ist->st->codecpar->height + 100000000*!!ist->st->codec_info_nb_frames + + 5000000*!!(ist->st->disposition & AV_DISPOSITION_DEFAULT); + if (ist->user_set_discard == AVDISCARD_ALL) + continue; if((qcr!=MKTAG('A', 'P', 'I', 'C')) && (ist->st->disposition & AV_DISPOSITION_ATTACHED_PIC)) new_area = 1; if (ist->st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && @@ -2164,7 +2222,10 @@ static int open_output_file(OptionsContext *o, const char *filename) for (i = 0; i < nb_input_streams; i++) { int score; ist = input_streams[i]; - score = ist->st->codecpar->channels + 100000000*!!ist->st->codec_info_nb_frames; + score = ist->st->codecpar->channels + 100000000*!!ist->st->codec_info_nb_frames + + 5000000*!!(ist->st->disposition & AV_DISPOSITION_DEFAULT); + if (ist->user_set_discard == AVDISCARD_ALL) + continue; if (ist->st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && score > best_score) { best_score = score; @@ -2186,6 +2247,8 @@ static int open_output_file(OptionsContext *o, const char *filename) AVCodec const *output_codec = avcodec_find_encoder(oc->oformat->subtitle_codec); int input_props = 0, output_props = 0; + if (input_streams[i]->user_set_discard == AVDISCARD_ALL) + continue; if (output_codec) output_descriptor = avcodec_descriptor_get(output_codec->id); if (input_descriptor) @@ -2207,6 +2270,8 @@ static int open_output_file(OptionsContext *o, const char *filename) if (!o->data_disable ) { enum AVCodecID codec_id = av_guess_codec(oc->oformat, NULL, filename, NULL, AVMEDIA_TYPE_DATA); for (i = 0; codec_id != AV_CODEC_ID_NONE && i < nb_input_streams; i++) { + if (input_streams[i]->user_set_discard == AVDISCARD_ALL) + continue; if (input_streams[i]->st->codecpar->codec_type == AVMEDIA_TYPE_DATA && input_streams[i]->st->codecpar->codec_id == codec_id ) new_data_stream(o, oc, i); @@ -2245,6 +2310,11 @@ loop_end: int src_idx = input_files[map->file_index]->ist_index + map->stream_index; ist = input_streams[input_files[map->file_index]->ist_index + map->stream_index]; + if (ist->user_set_discard == AVDISCARD_ALL) { + av_log(NULL, AV_LOG_FATAL, "Stream #%d:%d is disabled and cannot be mapped.\n", + map->file_index, map->stream_index); + exit_program(1); + } if(o->subtitle_disable && ist->st->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE) continue; if(o-> audio_disable && ist->st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) @@ -3157,7 +3227,9 @@ void show_help_default(const char *opt, const char *arg) #if CONFIG_SWSCALE show_help_children(sws_get_class(), flags); #endif +#if CONFIG_SWRESAMPLE show_help_children(swr_get_class(), AV_OPT_FLAG_AUDIO_PARAM); +#endif show_help_children(avfilter_get_class(), AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_FILTERING_PARAM); show_help_children(av_bsf_get_class(), AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_BSF_PARAM); } @@ -3337,7 +3409,7 @@ const OptionDef options[] = { OPT_INPUT | OPT_OUTPUT, { .off = OFFSET(start_time) }, "set the start time offset", "time_off" }, { "sseof", HAS_ARG | OPT_TIME | OPT_OFFSET | - OPT_INPUT | OPT_OUTPUT, { .off = OFFSET(start_time_eof) }, + OPT_INPUT, { .off = OFFSET(start_time_eof) }, "set the start time offset relative to EOF", "time_off" }, { "seek_timestamp", HAS_ARG | OPT_INT | OPT_OFFSET | OPT_INPUT, { .off = OFFSET(seek_timestamp) }, diff --git a/fftools/ffmpeg_qsv.c b/fftools/ffmpeg_qsv.c index 744275002..9c4285b6c 100644 --- a/fftools/ffmpeg_qsv.c +++ b/fftools/ffmpeg_qsv.c @@ -93,7 +93,7 @@ int qsv_init(AVCodecContext *s) frames_ctx->height = FFALIGN(s->coded_height, 32); frames_ctx->format = AV_PIX_FMT_QSV; frames_ctx->sw_format = s->sw_pix_fmt; - frames_ctx->initial_pool_size = 64; + frames_ctx->initial_pool_size = 64 + s->extra_hw_frames; frames_hwctx->frame_type = MFX_MEMTYPE_VIDEO_MEMORY_DECODER_TARGET; ret = av_hwframe_ctx_init(ist->hw_frames_ctx); diff --git a/fftools/ffmpeg_videotoolbox.c b/fftools/ffmpeg_videotoolbox.c index b820aec01..ad6174d3c 100644 --- a/fftools/ffmpeg_videotoolbox.c +++ b/fftools/ffmpeg_videotoolbox.c @@ -52,6 +52,9 @@ static int videotoolbox_retrieve_data(AVCodecContext *s, AVFrame *frame) case kCVPixelFormatType_32BGRA: vt->tmp_frame->format = AV_PIX_FMT_BGRA; break; #ifdef kCFCoreFoundationVersionNumber10_7 case kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange: vt->tmp_frame->format = AV_PIX_FMT_NV12; break; +#endif +#if HAVE_KCVPIXELFORMATTYPE_420YPCBCR10BIPLANARVIDEORANGE + case kCVPixelFormatType_420YpCbCr10BiPlanarVideoRange: vt->tmp_frame->format = AV_PIX_FMT_P010; break; #endif default: av_log(NULL, AV_LOG_ERROR, diff --git a/fftools/ffplay.c b/fftools/ffplay.c index dcca9c26d..fee0619f7 100644 --- a/fftools/ffplay.c +++ b/fftools/ffplay.c @@ -314,13 +314,17 @@ static int default_width = 640; static int default_height = 480; static int screen_width = 0; static int screen_height = 0; +static int screen_left = SDL_WINDOWPOS_CENTERED; +static int screen_top = SDL_WINDOWPOS_CENTERED; static int audio_disable; static int video_disable; static int subtitle_disable; static const char* wanted_stream_spec[AVMEDIA_TYPE_NB] = {0}; static int seek_by_bytes = -1; +static float seek_interval = 10; static int display_disable; static int borderless; +static int alwaysontop; static int startup_volume = 100; static int show_status = 1; static int av_sync_type = AV_SYNC_AUDIO_MASTER; @@ -350,6 +354,7 @@ static char *afilters = NULL; #endif static int autorotate = 1; static int find_stream_info = 1; +static int filter_nbthreads = 0; /* current context */ static int is_full_screen; @@ -858,31 +863,27 @@ static void calculate_display_rect(SDL_Rect *rect, int scr_xleft, int scr_ytop, int scr_width, int scr_height, int pic_width, int pic_height, AVRational pic_sar) { - float aspect_ratio; - int width, height, x, y; + AVRational aspect_ratio = pic_sar; + int64_t width, height, x, y; - if (pic_sar.num == 0) - aspect_ratio = 0; - else - aspect_ratio = av_q2d(pic_sar); + if (av_cmp_q(aspect_ratio, av_make_q(0, 1)) <= 0) + aspect_ratio = av_make_q(1, 1); - if (aspect_ratio <= 0.0) - aspect_ratio = 1.0; - aspect_ratio *= (float)pic_width / (float)pic_height; + aspect_ratio = av_mul_q(aspect_ratio, av_make_q(pic_width, pic_height)); /* XXX: we suppose the screen has a 1.0 pixel ratio */ height = scr_height; - width = lrint(height * aspect_ratio) & ~1; + width = av_rescale(height, aspect_ratio.num, aspect_ratio.den) & ~1; if (width > scr_width) { width = scr_width; - height = lrint(width / aspect_ratio) & ~1; + height = av_rescale(width, aspect_ratio.den, aspect_ratio.num) & ~1; } x = (scr_width - width) / 2; y = (scr_height - height) / 2; rect->x = scr_xleft + x; rect->y = scr_ytop + y; - rect->w = FFMAX(width, 1); - rect->h = FFMAX(height, 1); + rect->w = FFMAX((int)width, 1); + rect->h = FFMAX((int)height, 1); } static void get_sdl_pix_fmt_and_blendmode(int format, Uint32 *sdl_pix_fmt, SDL_BlendMode *sdl_blendmode) @@ -954,6 +955,22 @@ static int upload_texture(SDL_Texture **tex, AVFrame *frame, struct SwsContext * return ret; } +static void set_sdl_yuv_conversion_mode(AVFrame *frame) +{ +#if SDL_VERSION_ATLEAST(2,0,8) + SDL_YUV_CONVERSION_MODE mode = SDL_YUV_CONVERSION_AUTOMATIC; + if (frame && (frame->format == AV_PIX_FMT_YUV420P || frame->format == AV_PIX_FMT_YUYV422 || frame->format == AV_PIX_FMT_UYVY422)) { + if (frame->color_range == AVCOL_RANGE_JPEG) + mode = SDL_YUV_CONVERSION_JPEG; + else if (frame->colorspace == AVCOL_SPC_BT709) + mode = SDL_YUV_CONVERSION_BT709; + else if (frame->colorspace == AVCOL_SPC_BT470BG || frame->colorspace == AVCOL_SPC_SMPTE170M || frame->colorspace == AVCOL_SPC_SMPTE240M) + mode = SDL_YUV_CONVERSION_BT601; + } + SDL_SetYUVConversionMode(mode); +#endif +} + static void video_image_display(VideoState *is) { Frame *vp; @@ -1015,7 +1032,9 @@ static void video_image_display(VideoState *is) vp->flip_v = vp->frame->linesize[0] < 0; } + set_sdl_yuv_conversion_mode(vp->frame); SDL_RenderCopyEx(renderer, is->vid_texture, NULL, &rect, 0, NULL, vp->flip_v ? SDL_FLIP_VERTICAL : 0); + set_sdl_yuv_conversion_mode(NULL); if (sp) { #if USE_ONEPASS_SUBTITLE_RENDER SDL_RenderCopy(renderer, is->sub_texture, NULL, &rect); @@ -1305,7 +1324,11 @@ static void sigterm_handler(int sig) static void set_default_window_size(int width, int height, AVRational sar) { SDL_Rect rect; - calculate_display_rect(&rect, 0, 0, INT_MAX, height, width, height, sar); + int max_width = screen_width ? screen_width : INT_MAX; + int max_height = screen_height ? screen_height : INT_MAX; + if (max_width == INT_MAX && max_height == INT_MAX) + max_height = height; + calculate_display_rect(&rect, 0, 0, max_width, max_height, width, height, sar); default_width = rect.w; default_height = rect.h; } @@ -1314,20 +1337,15 @@ static int video_open(VideoState *is) { int w,h; - if (screen_width) { - w = screen_width; - h = screen_height; - } else { - w = default_width; - h = default_height; - } + w = screen_width ? screen_width : default_width; + h = screen_height ? screen_height : default_height; if (!window_title) window_title = input_filename; SDL_SetWindowTitle(window, window_title); SDL_SetWindowSize(window, w, h); - SDL_SetWindowPosition(window, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED); + SDL_SetWindowPosition(window, screen_left, screen_top); if (is_full_screen) SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN_DESKTOP); SDL_ShowWindow(window); @@ -1938,6 +1956,7 @@ static int configure_audio_filters(VideoState *is, const char *afilters, int for avfilter_graph_free(&is->agraph); if (!(is->agraph = avfilter_graph_alloc())) return AVERROR(ENOMEM); + is->agraph->nb_threads = filter_nbthreads; while ((e = av_dict_get(swr_opts, "", e, AV_DICT_IGNORE_SUFFIX))) av_strlcatf(aresample_swr_opts, sizeof(aresample_swr_opts), "%s=%s:", e->key, e->value); @@ -2087,10 +2106,10 @@ static int audio_thread(void *arg) return ret; } -static int decoder_start(Decoder *d, int (*fn)(void *), void *arg) +static int decoder_start(Decoder *d, int (*fn)(void *), const char *thread_name, void* arg) { packet_queue_start(d->queue); - d->decoder_tid = SDL_CreateThread(fn, "decoder", arg); + d->decoder_tid = SDL_CreateThread(fn, thread_name, arg); if (!d->decoder_tid) { av_log(NULL, AV_LOG_ERROR, "SDL_CreateThread(): %s\n", SDL_GetError()); return AVERROR(ENOMEM); @@ -2109,26 +2128,17 @@ static int video_thread(void *arg) AVRational frame_rate = av_guess_frame_rate(is->ic, is->video_st, NULL); #if CONFIG_AVFILTER - AVFilterGraph *graph = avfilter_graph_alloc(); + AVFilterGraph *graph = NULL; AVFilterContext *filt_out = NULL, *filt_in = NULL; int last_w = 0; int last_h = 0; enum AVPixelFormat last_format = -2; int last_serial = -1; int last_vfilter_idx = 0; - if (!graph) { - av_frame_free(&frame); - return AVERROR(ENOMEM); - } - #endif - if (!frame) { -#if CONFIG_AVFILTER - avfilter_graph_free(&graph); -#endif + if (!frame) return AVERROR(ENOMEM); - } for (;;) { ret = get_video_frame(is, frame); @@ -2151,6 +2161,11 @@ static int video_thread(void *arg) (const char *)av_x_if_null(av_get_pix_fmt_name(frame->format), "none"), is->viddec.pkt_serial); avfilter_graph_free(&graph); graph = avfilter_graph_alloc(); + if (!graph) { + ret = AVERROR(ENOMEM); + goto the_end; + } + graph->nb_threads = filter_nbthreads; if ((ret = configure_video_filters(graph, is, vfilters_list ? vfilters_list[is->vfilter_idx] : NULL, frame)) < 0) { SDL_Event event; event.type = FF_QUIT_EVENT; @@ -2193,6 +2208,8 @@ static int video_thread(void *arg) ret = queue_picture(is, frame, pts, duration, frame->pkt_pos, is->viddec.pkt_serial); av_frame_unref(frame); #if CONFIG_AVFILTER + if (is->videoq.serial != is->viddec.pkt_serial) + break; } #endif @@ -2578,7 +2595,7 @@ static int stream_component_open(VideoState *is, int stream_index) if (forced_codec_name) av_log(NULL, AV_LOG_WARNING, "No codec could be found with name '%s'\n", forced_codec_name); else av_log(NULL, AV_LOG_WARNING, - "No codec could be found with id %d\n", avctx->codec_id); + "No decoder could be found for codec %s\n", avcodec_get_name(avctx->codec_id)); ret = AVERROR(EINVAL); goto fail; } @@ -2658,7 +2675,7 @@ 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; } - if ((ret = decoder_start(&is->auddec, audio_thread, is)) < 0) + if ((ret = decoder_start(&is->auddec, audio_thread, "audio_decoder", is)) < 0) goto out; SDL_PauseAudioDevice(audio_dev, 0); break; @@ -2667,7 +2684,7 @@ static int stream_component_open(VideoState *is, int stream_index) is->video_st = ic->streams[stream_index]; decoder_init(&is->viddec, avctx, &is->videoq, is->continue_read_thread); - if ((ret = decoder_start(&is->viddec, video_thread, is)) < 0) + if ((ret = decoder_start(&is->viddec, video_thread, "video_decoder", is)) < 0) goto out; is->queue_attachments_req = 1; break; @@ -2676,7 +2693,7 @@ 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); - if ((ret = decoder_start(&is->subdec, subtitle_thread, is)) < 0) + if ((ret = decoder_start(&is->subdec, subtitle_thread, "subtitle_decoder", is)) < 0) goto out; break; default: @@ -3251,15 +3268,14 @@ static void event_loop(VideoState *cur_stream) refresh_loop_wait_event(cur_stream, &event); switch (event.type) { case SDL_KEYDOWN: - if (exit_on_keydown) { + if (exit_on_keydown || event.key.keysym.sym == SDLK_ESCAPE || event.key.keysym.sym == SDLK_q) { do_exit(cur_stream); break; } + // If we don't yet have a window, skip all key events, because read_thread might still be initializing... + if (!cur_stream->width) + continue; switch (event.key.keysym.sym) { - case SDLK_ESCAPE: - case SDLK_q: - do_exit(cur_stream); - break; case SDLK_f: toggle_full_screen(cur_stream); cur_stream->force_refresh = 1; @@ -3324,10 +3340,10 @@ static void event_loop(VideoState *cur_stream) seek_chapter(cur_stream, -1); break; case SDLK_LEFT: - incr = -10.0; + incr = seek_interval ? -seek_interval : -10.0; goto do_seek; case SDLK_RIGHT: - incr = 10.0; + incr = seek_interval ? seek_interval : 10.0; goto do_seek; case SDLK_UP: incr = 60.0; @@ -3420,7 +3436,7 @@ static void event_loop(VideoState *cur_stream) break; case SDL_WINDOWEVENT: switch (event.window.event) { - case SDL_WINDOWEVENT_RESIZED: + case SDL_WINDOWEVENT_SIZE_CHANGED: screen_width = cur_stream->width = event.window.data1; screen_height = cur_stream->height = event.window.data2; if (cur_stream->vis_texture) { @@ -3563,8 +3579,10 @@ static const OptionDef options[] = { { "ss", HAS_ARG, { .func_arg = opt_seek }, "seek to a given position in seconds", "pos" }, { "t", HAS_ARG, { .func_arg = opt_duration }, "play \"duration\" seconds of audio/video", "duration" }, { "bytes", OPT_INT | HAS_ARG, { &seek_by_bytes }, "seek by bytes 0=off 1=on -1=auto", "val" }, + { "seek_interval", OPT_FLOAT | HAS_ARG, { &seek_interval }, "set seek interval for left/right keys, in seconds", "seconds" }, { "nodisp", OPT_BOOL, { &display_disable }, "disable graphical display" }, { "noborder", OPT_BOOL, { &borderless }, "borderless window" }, + { "alwaysontop", OPT_BOOL, { &alwaysontop }, "window always on top" }, { "volume", OPT_INT | HAS_ARG, { &startup_volume}, "set startup volume 0=min 100=max", "volume" }, { "f", HAS_ARG, { .func_arg = opt_format }, "force format", "fmt" }, { "pix_fmt", HAS_ARG | OPT_EXPERT | OPT_VIDEO, { .func_arg = opt_frame_pix_fmt }, "set pixel format", "format" }, @@ -3581,6 +3599,8 @@ static const OptionDef options[] = { { "framedrop", OPT_BOOL | OPT_EXPERT, { &framedrop }, "drop frames when cpu is too slow", "" }, { "infbuf", OPT_BOOL | OPT_EXPERT, { &infinite_buffer }, "don't limit the input buffer size (useful with realtime streams)", "" }, { "window_title", OPT_STRING | HAS_ARG, { &window_title }, "set window title", "window title" }, + { "left", OPT_INT | HAS_ARG | OPT_EXPERT, { &screen_left }, "set the x position for the left of the window", "x pos" }, + { "top", OPT_INT | HAS_ARG | OPT_EXPERT, { &screen_top }, "set the y position for the top of the window", "y pos" }, #if CONFIG_AVFILTER { "vf", OPT_EXPERT | HAS_ARG, { .func_arg = opt_add_vfilter }, "set video filters", "filter_graph" }, { "af", OPT_STRING | HAS_ARG, { &afilters }, "set audio filters", "filter_graph" }, @@ -3596,6 +3616,7 @@ static const OptionDef options[] = { { "autorotate", OPT_BOOL, { &autorotate }, "automatically rotate video", "" }, { "find_stream_info", OPT_BOOL | OPT_INPUT | OPT_EXPERT, { &find_stream_info }, "read and decode the streams to fill missing information with heuristics" }, + { "filter_threads", HAS_ARG | OPT_INT | OPT_EXPERT, { &filter_nbthreads }, "number of filter threads per graph" }, { NULL, }, }; @@ -3633,7 +3654,7 @@ void show_help_default(const char *opt, const char *arg) "c cycle program\n" "w cycle video filters or show modes\n" "s activate frame-step mode\n" - "left/right seek backward/forward 10 seconds\n" + "left/right seek backward/forward 10 seconds or to custom interval if -seek_interval is set\n" "down/up seek backward/forward 1 minute\n" "page down/page up seek backward/forward 10 minutes\n" "right mouse click seek to percentage in file corresponding to fraction of width\n" @@ -3703,6 +3724,12 @@ int main(int argc, char **argv) if (!display_disable) { int flags = SDL_WINDOW_HIDDEN; + if (alwaysontop) +#if SDL_VERSION_ATLEAST(2,0,5) + flags |= SDL_WINDOW_ALWAYS_ON_TOP; +#else + av_log(NULL, AV_LOG_WARNING, "Your SDL version doesn't support SDL_WINDOW_ALWAYS_ON_TOP. Feature will be inactive.\n"); +#endif if (borderless) flags |= SDL_WINDOW_BORDERLESS; else diff --git a/fftools/ffprobe.c b/fftools/ffprobe.c index 544786ec7..5aaddb030 100644 --- a/fftools/ffprobe.c +++ b/fftools/ffprobe.c @@ -165,6 +165,8 @@ typedef enum { SECTION_ID_FRAME_TAGS, SECTION_ID_FRAME_SIDE_DATA_LIST, SECTION_ID_FRAME_SIDE_DATA, + SECTION_ID_FRAME_SIDE_DATA_TIMECODE_LIST, + SECTION_ID_FRAME_SIDE_DATA_TIMECODE, SECTION_ID_FRAME_LOG, SECTION_ID_FRAME_LOGS, SECTION_ID_LIBRARY_VERSION, @@ -209,7 +211,9 @@ static struct section sections[] = { [SECTION_ID_FRAME] = { SECTION_ID_FRAME, "frame", 0, { SECTION_ID_FRAME_TAGS, SECTION_ID_FRAME_SIDE_DATA_LIST, SECTION_ID_FRAME_LOGS, -1 } }, [SECTION_ID_FRAME_TAGS] = { SECTION_ID_FRAME_TAGS, "tags", SECTION_FLAG_HAS_VARIABLE_FIELDS, { -1 }, .element_name = "tag", .unique_name = "frame_tags" }, [SECTION_ID_FRAME_SIDE_DATA_LIST] ={ SECTION_ID_FRAME_SIDE_DATA_LIST, "side_data_list", SECTION_FLAG_IS_ARRAY, { SECTION_ID_FRAME_SIDE_DATA, -1 }, .element_name = "side_data", .unique_name = "frame_side_data_list" }, - [SECTION_ID_FRAME_SIDE_DATA] = { SECTION_ID_FRAME_SIDE_DATA, "side_data", 0, { -1 } }, + [SECTION_ID_FRAME_SIDE_DATA] = { SECTION_ID_FRAME_SIDE_DATA, "side_data", 0, { SECTION_ID_FRAME_SIDE_DATA_TIMECODE_LIST, -1 } }, + [SECTION_ID_FRAME_SIDE_DATA_TIMECODE_LIST] = { SECTION_ID_FRAME_SIDE_DATA_TIMECODE_LIST, "timecodes", SECTION_FLAG_IS_ARRAY, { SECTION_ID_FRAME_SIDE_DATA_TIMECODE, -1 } }, + [SECTION_ID_FRAME_SIDE_DATA_TIMECODE] = { SECTION_ID_FRAME_SIDE_DATA_TIMECODE, "timecode", 0, { -1 } }, [SECTION_ID_FRAME_LOGS] = { SECTION_ID_FRAME_LOGS, "logs", SECTION_FLAG_IS_ARRAY, { SECTION_ID_FRAME_LOG, -1 } }, [SECTION_ID_FRAME_LOG] = { SECTION_ID_FRAME_LOG, "log", 0, { -1 }, }, [SECTION_ID_LIBRARY_VERSIONS] = { SECTION_ID_LIBRARY_VERSIONS, "library_versions", SECTION_FLAG_IS_ARRAY, { SECTION_ID_LIBRARY_VERSION, -1 } }, @@ -2199,6 +2203,18 @@ static void show_frame(WriterContext *w, AVFrame *frame, AVStream *stream, char tcbuf[AV_TIMECODE_STR_SIZE]; av_timecode_make_mpeg_tc_string(tcbuf, *(int64_t *)(sd->data)); print_str("timecode", tcbuf); + } else if (sd->type == AV_FRAME_DATA_S12M_TIMECODE && sd->size == 16) { + uint32_t *tc = (uint32_t*)sd->data; + int m = FFMIN(tc[0],3); + writer_print_section_header(w, SECTION_ID_FRAME_SIDE_DATA_TIMECODE_LIST); + for (int j = 1; j <= m ; j++) { + char tcbuf[AV_TIMECODE_STR_SIZE]; + av_timecode_make_smpte_tc_string(tcbuf, tc[j], 0); + writer_print_section_header(w, SECTION_ID_FRAME_SIDE_DATA_TIMECODE); + print_str("value", tcbuf); + writer_print_section_footer(w); + } + writer_print_section_footer(w); } else if (sd->type == AV_FRAME_DATA_MASTERING_DISPLAY_METADATA) { AVMasteringDisplayMetadata *metadata = (AVMasteringDisplayMetadata *)sd->data; @@ -2413,9 +2429,7 @@ static int read_interval_packets(WriterContext *w, InputFile *ifile, } av_packet_unref(&pkt); } - av_init_packet(&pkt); - pkt.data = NULL; - pkt.size = 0; + av_packet_unref(&pkt); //Flush remaining frames that are cached in the decoder for (i = 0; i < fmt_ctx->nb_streams; i++) { pkt.stream_index = i; @@ -2646,20 +2660,20 @@ static int show_stream(WriterContext *w, AVFormatContext *fmt_ctx, int stream_id } while (0) if (do_show_stream_disposition) { - writer_print_section_header(w, in_program ? SECTION_ID_PROGRAM_STREAM_DISPOSITION : SECTION_ID_STREAM_DISPOSITION); - PRINT_DISPOSITION(DEFAULT, "default"); - PRINT_DISPOSITION(DUB, "dub"); - PRINT_DISPOSITION(ORIGINAL, "original"); - PRINT_DISPOSITION(COMMENT, "comment"); - PRINT_DISPOSITION(LYRICS, "lyrics"); - PRINT_DISPOSITION(KARAOKE, "karaoke"); - PRINT_DISPOSITION(FORCED, "forced"); - PRINT_DISPOSITION(HEARING_IMPAIRED, "hearing_impaired"); - PRINT_DISPOSITION(VISUAL_IMPAIRED, "visual_impaired"); - PRINT_DISPOSITION(CLEAN_EFFECTS, "clean_effects"); - PRINT_DISPOSITION(ATTACHED_PIC, "attached_pic"); - PRINT_DISPOSITION(TIMED_THUMBNAILS, "timed_thumbnails"); - writer_print_section_footer(w); + writer_print_section_header(w, in_program ? SECTION_ID_PROGRAM_STREAM_DISPOSITION : SECTION_ID_STREAM_DISPOSITION); + PRINT_DISPOSITION(DEFAULT, "default"); + PRINT_DISPOSITION(DUB, "dub"); + PRINT_DISPOSITION(ORIGINAL, "original"); + PRINT_DISPOSITION(COMMENT, "comment"); + PRINT_DISPOSITION(LYRICS, "lyrics"); + PRINT_DISPOSITION(KARAOKE, "karaoke"); + PRINT_DISPOSITION(FORCED, "forced"); + PRINT_DISPOSITION(HEARING_IMPAIRED, "hearing_impaired"); + PRINT_DISPOSITION(VISUAL_IMPAIRED, "visual_impaired"); + PRINT_DISPOSITION(CLEAN_EFFECTS, "clean_effects"); + PRINT_DISPOSITION(ATTACHED_PIC, "attached_pic"); + PRINT_DISPOSITION(TIMED_THUMBNAILS, "timed_thumbnails"); + writer_print_section_footer(w); } if (do_show_stream_tags) diff --git a/libavcodec/4xm.c b/libavcodec/4xm.c index 8e05a4c36..1f4e2aee2 100644 --- a/libavcodec/4xm.c +++ b/libavcodec/4xm.c @@ -145,7 +145,7 @@ typedef struct FourXContext { int mv[256]; VLC pre_vlc; int last_dc; - DECLARE_ALIGNED(16, int16_t, block)[6][64]; + DECLARE_ALIGNED(32, int16_t, block)[6][64]; void *bitstream_buffer; unsigned int bitstream_buffer_size; int version; @@ -158,7 +158,7 @@ typedef struct FourXContext { #define FIX_1_847759065 121095 #define FIX_2_613125930 171254 -#define MULTIPLY(var, const) (((var) * (const)) >> 16) +#define MULTIPLY(var, const) ((int)((var) * (unsigned)(const)) >> 16) static void idct(int16_t block[64]) { @@ -351,6 +351,8 @@ static int decode_p_block(FourXContext *f, uint16_t *dst, const uint16_t *src, index = size2index[log2h][log2w]; av_assert0(index >= 0); + if (get_bits_left(&f->gb) < 1) + return AVERROR_INVALIDDATA; h = 1 << log2h; code = get_vlc2(&f->gb, block_type_vlc[1 - (f->version > 1)][index].table, BLOCK_TYPE_VLC_BITS, 1); @@ -697,6 +699,7 @@ static const uint8_t *read_huffman_tables(FourXContext *f, len_tab[j] = len; } + ff_free_vlc(&f->pre_vlc); if (init_vlc(&f->pre_vlc, ACDC_VLC_BITS, 257, len_tab, 1, 1, bits_tab, 4, 4, 0)) return NULL; diff --git a/libavcodec/Makefile b/libavcodec/Makefile index 4b8ad121d..3cd73fbcc 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -44,6 +44,7 @@ OBJS = ac3_parser.o \ options.o \ mjpegenc_huffman.o \ parser.o \ + parsers.o \ profiles.o \ qsv_api.o \ raw.o \ @@ -62,9 +63,12 @@ OBJS-$(CONFIG_BLOCKDSP) += blockdsp.o OBJS-$(CONFIG_BSWAPDSP) += bswapdsp.o OBJS-$(CONFIG_CABAC) += cabac.o OBJS-$(CONFIG_CBS) += cbs.o +OBJS-$(CONFIG_CBS_AV1) += cbs_av1.o OBJS-$(CONFIG_CBS_H264) += cbs_h2645.o h2645_parse.o OBJS-$(CONFIG_CBS_H265) += cbs_h2645.o h2645_parse.o +OBJS-$(CONFIG_CBS_JPEG) += cbs_jpeg.o OBJS-$(CONFIG_CBS_MPEG2) += cbs_mpeg2.o +OBJS-$(CONFIG_CBS_VP9) += cbs_vp9.o OBJS-$(CONFIG_CRYSTALHD) += crystalhd.o OBJS-$(CONFIG_DCT) += dct.o dct32_fixed.o dct32_float.o OBJS-$(CONFIG_ERROR_RESILIENCE) += error_resilience.o @@ -169,6 +173,7 @@ OBJS-$(CONFIG_AC3_FIXED_DECODER) += ac3dec_fixed.o ac3dec_data.o ac3.o kbd 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_AGM_DECODER) += agm.o OBJS-$(CONFIG_AIC_DECODER) += aic.o OBJS-$(CONFIG_ALAC_DECODER) += alac.o alac_data.o alacdsp.o OBJS-$(CONFIG_ALAC_ENCODER) += alacenc.o alac_data.o @@ -194,6 +199,7 @@ OBJS-$(CONFIG_APTX_HD_DECODER) += aptx.o OBJS-$(CONFIG_APTX_HD_ENCODER) += aptx.o OBJS-$(CONFIG_APNG_DECODER) += png.o pngdec.o pngdsp.o OBJS-$(CONFIG_APNG_ENCODER) += png.o pngenc.o +OBJS-$(CONFIG_ARBC_DECODER) += arbc.o OBJS-$(CONFIG_SSA_DECODER) += assdec.o ass.o OBJS-$(CONFIG_SSA_ENCODER) += assenc.o ass.o OBJS-$(CONFIG_ASS_DECODER) += assdec.o ass.o @@ -209,6 +215,7 @@ OBJS-$(CONFIG_ATRAC3P_DECODER) += atrac3plusdec.o atrac3plus.o \ atrac3plusdsp.o atrac.o OBJS-$(CONFIG_ATRAC3PAL_DECODER) += atrac3plusdec.o atrac3plus.o \ atrac3plusdsp.o atrac.o +OBJS-$(CONFIG_ATRAC9_DECODER) += atrac9dec.o OBJS-$(CONFIG_AURA_DECODER) += cyuv.o OBJS-$(CONFIG_AURA2_DECODER) += aura.o OBJS-$(CONFIG_AVRN_DECODER) += avrndec.o mjpegdec.o @@ -351,12 +358,13 @@ OBJS-$(CONFIG_H264_OMX_ENCODER) += omx.o OBJS-$(CONFIG_H264_QSV_DECODER) += qsvdec_h2645.o OBJS-$(CONFIG_H264_QSV_ENCODER) += qsvenc_h264.o OBJS-$(CONFIG_H264_RKMPP_DECODER) += rkmppdec.o -OBJS-$(CONFIG_H264_VAAPI_ENCODER) += vaapi_encode_h264.o +OBJS-$(CONFIG_H264_VAAPI_ENCODER) += vaapi_encode_h264.o h264_levels.o OBJS-$(CONFIG_H264_VIDEOTOOLBOX_ENCODER) += videotoolboxenc.o OBJS-$(CONFIG_H264_V4L2M2M_DECODER) += v4l2_m2m_dec.o OBJS-$(CONFIG_H264_V4L2M2M_ENCODER) += v4l2_m2m_enc.o OBJS-$(CONFIG_HAP_DECODER) += hapdec.o hap.o OBJS-$(CONFIG_HAP_ENCODER) += hapenc.o hap.o +OBJS-$(CONFIG_HCOM_DECODER) += hcom.o OBJS-$(CONFIG_HEVC_DECODER) += hevcdec.o hevc_mvs.o \ hevc_cabac.o hevc_refs.o hevcpred.o \ hevcdsp.o hevc_filter.o hevc_data.o @@ -369,7 +377,7 @@ OBJS-$(CONFIG_HEVC_QSV_DECODER) += qsvdec_h2645.o OBJS-$(CONFIG_HEVC_QSV_ENCODER) += qsvenc_hevc.o hevc_ps_enc.o \ hevc_data.o OBJS-$(CONFIG_HEVC_RKMPP_DECODER) += rkmppdec.o -OBJS-$(CONFIG_HEVC_VAAPI_ENCODER) += vaapi_encode_h265.o +OBJS-$(CONFIG_HEVC_VAAPI_ENCODER) += vaapi_encode_h265.o h265_profile_level.o OBJS-$(CONFIG_HEVC_V4L2M2M_DECODER) += v4l2_m2m_dec.o OBJS-$(CONFIG_HEVC_V4L2M2M_ENCODER) += v4l2_m2m_enc.o OBJS-$(CONFIG_HNM4_VIDEO_DECODER) += hnm4video.o @@ -378,10 +386,13 @@ OBJS-$(CONFIG_HQ_HQA_DECODER) += hq_hqa.o hq_hqadata.o hq_hqadsp.o \ OBJS-$(CONFIG_HQX_DECODER) += hqx.o hqxvlc.o hqxdsp.o canopus.o OBJS-$(CONFIG_HUFFYUV_DECODER) += huffyuv.o huffyuvdec.o OBJS-$(CONFIG_HUFFYUV_ENCODER) += huffyuv.o huffyuvenc.o +OBJS-$(CONFIG_HYMT_DECODER) += huffyuv.o huffyuvdec.o OBJS-$(CONFIG_IDCIN_DECODER) += idcinvideo.o OBJS-$(CONFIG_IDF_DECODER) += bintext.o cga_data.o OBJS-$(CONFIG_IFF_ILBM_DECODER) += iff.o +OBJS-$(CONFIG_ILBC_DECODER) += ilbcdec.o OBJS-$(CONFIG_IMC_DECODER) += imc.o +OBJS-$(CONFIG_IMM4_DECODER) += imm4.o OBJS-$(CONFIG_INDEO2_DECODER) += indeo2.o OBJS-$(CONFIG_INDEO3_DECODER) += indeo3.o OBJS-$(CONFIG_INDEO4_DECODER) += indeo4.o ivi.o @@ -402,6 +413,7 @@ OBJS-$(CONFIG_KMVC_DECODER) += kmvc.o OBJS-$(CONFIG_LAGARITH_DECODER) += lagarith.o lagarithrac.o OBJS-$(CONFIG_LJPEG_ENCODER) += ljpegenc.o mjpegenc_common.o OBJS-$(CONFIG_LOCO_DECODER) += loco.o +OBJS-$(CONFIG_LSCR_DECODER) += png.o pngdec.o pngdsp.o OBJS-$(CONFIG_M101_DECODER) += m101.o OBJS-$(CONFIG_MACE3_DECODER) += mace.o OBJS-$(CONFIG_MACE6_DECODER) += mace.o @@ -478,13 +490,15 @@ OBJS-$(CONFIG_MSZH_DECODER) += lcldec.o OBJS-$(CONFIG_MTS2_DECODER) += mss4.o OBJS-$(CONFIG_MVC1_DECODER) += mvcdec.o OBJS-$(CONFIG_MVC2_DECODER) += mvcdec.o +OBJS-$(CONFIG_MWSC_DECODER) += mwsc.o OBJS-$(CONFIG_MXPEG_DECODER) += mxpegdec.o OBJS-$(CONFIG_NELLYMOSER_DECODER) += nellymoserdec.o nellymoser.o OBJS-$(CONFIG_NELLYMOSER_ENCODER) += nellymoserenc.o nellymoser.o OBJS-$(CONFIG_NUV_DECODER) += nuv.o rtjpeg.o OBJS-$(CONFIG_ON2AVC_DECODER) += on2avc.o on2avcdata.o OBJS-$(CONFIG_OPUS_DECODER) += opusdec.o opus.o opus_celt.o opus_rc.o \ - opus_pvq.o opus_silk.o opustab.o vorbis_data.o + opus_pvq.o opus_silk.o opustab.o vorbis_data.o \ + opusdsp.o OBJS-$(CONFIG_OPUS_ENCODER) += opusenc.o opus.o opus_rc.o opustab.o opus_pvq.o \ opusenc_psy.o OBJS-$(CONFIG_PAF_AUDIO_DECODER) += pafaudio.o @@ -508,10 +522,10 @@ OBJS-$(CONFIG_PNG_ENCODER) += png.o pngenc.o OBJS-$(CONFIG_PPM_DECODER) += pnmdec.o pnm.o OBJS-$(CONFIG_PPM_ENCODER) += pnmenc.o OBJS-$(CONFIG_PRORES_DECODER) += proresdec2.o proresdsp.o proresdata.o -OBJS-$(CONFIG_PRORES_LGPL_DECODER) += proresdec_lgpl.o proresdsp.o proresdata.o -OBJS-$(CONFIG_PRORES_ENCODER) += proresenc_anatoliy.o -OBJS-$(CONFIG_PRORES_AW_ENCODER) += proresenc_anatoliy.o +OBJS-$(CONFIG_PRORES_ENCODER) += proresenc_anatoliy.o proresdata.o +OBJS-$(CONFIG_PRORES_AW_ENCODER) += proresenc_anatoliy.o proresdata.o OBJS-$(CONFIG_PRORES_KS_ENCODER) += proresenc_kostya.o proresdata.o +OBJS-$(CONFIG_PROSUMER_DECODER) += prosumer.o OBJS-$(CONFIG_PSD_DECODER) += psd.o OBJS-$(CONFIG_PTX_DECODER) += ptx.o OBJS-$(CONFIG_QCELP_DECODER) += qcelpdec.o \ @@ -531,6 +545,7 @@ OBJS-$(CONFIG_RA_144_DECODER) += ra144dec.o ra144.o celp_filters.o OBJS-$(CONFIG_RA_144_ENCODER) += ra144enc.o ra144.o celp_filters.o OBJS-$(CONFIG_RA_288_DECODER) += ra288.o celp_filters.o OBJS-$(CONFIG_RALF_DECODER) += ralf.o +OBJS-$(CONFIG_RASC_DECODER) += rasc.o OBJS-$(CONFIG_RAWVIDEO_DECODER) += rawdec.o OBJS-$(CONFIG_RAWVIDEO_ENCODER) += rawenc.o OBJS-$(CONFIG_REALTEXT_DECODER) += realtextdec.o ass.o @@ -574,7 +589,7 @@ OBJS-$(CONFIG_SOL_DPCM_DECODER) += dpcm.o OBJS-$(CONFIG_SONIC_DECODER) += sonic.o OBJS-$(CONFIG_SONIC_ENCODER) += sonic.o OBJS-$(CONFIG_SONIC_LS_ENCODER) += sonic.o -OBJS-$(CONFIG_SPEEDHQ_DECODER) += speedhq.o simple_idct.o +OBJS-$(CONFIG_SPEEDHQ_DECODER) += speedhq.o mpeg12.o mpeg12data.o simple_idct.o OBJS-$(CONFIG_SP5X_DECODER) += sp5xdec.o OBJS-$(CONFIG_SRGC_DECODER) += mscc.o OBJS-$(CONFIG_SRT_DECODER) += srtdec.o ass.o htmlsubtitles.o @@ -672,6 +687,7 @@ OBJS-$(CONFIG_VP9_V4L2M2M_DECODER) += v4l2_m2m_dec.o OBJS-$(CONFIG_VQA_DECODER) += vqavideo.o OBJS-$(CONFIG_WAVPACK_DECODER) += wavpack.o OBJS-$(CONFIG_WAVPACK_ENCODER) += wavpackenc.o +OBJS-$(CONFIG_WCMV_DECODER) += wcmv.o OBJS-$(CONFIG_WEBP_DECODER) += webp.o OBJS-$(CONFIG_WEBVTT_DECODER) += webvttdec.o ass.o OBJS-$(CONFIG_WEBVTT_ENCODER) += webvttenc.o ass_split.o @@ -727,6 +743,7 @@ OBJS-$(CONFIG_PCM_ALAW_DECODER) += pcm.o OBJS-$(CONFIG_PCM_ALAW_ENCODER) += pcm.o OBJS-$(CONFIG_PCM_BLURAY_DECODER) += pcm-bluray.o OBJS-$(CONFIG_PCM_DVD_DECODER) += pcm-dvd.o +OBJS-$(CONFIG_PCM_DVD_ENCODER) += pcm-dvdenc.o OBJS-$(CONFIG_PCM_F16LE_DECODER) += pcm.o OBJS-$(CONFIG_PCM_F24LE_DECODER) += pcm.o OBJS-$(CONFIG_PCM_F32BE_DECODER) += pcm.o @@ -784,12 +801,15 @@ OBJS-$(CONFIG_PCM_U32BE_DECODER) += pcm.o OBJS-$(CONFIG_PCM_U32BE_ENCODER) += pcm.o OBJS-$(CONFIG_PCM_U32LE_DECODER) += pcm.o OBJS-$(CONFIG_PCM_U32LE_ENCODER) += pcm.o +OBJS-$(CONFIG_PCM_VIDC_DECODER) += pcm.o +OBJS-$(CONFIG_PCM_VIDC_ENCODER) += pcm.o OBJS-$(CONFIG_PCM_ZORK_DECODER) += pcm.o OBJS-$(CONFIG_ADPCM_4XM_DECODER) += adpcm.o adpcm_data.o OBJS-$(CONFIG_ADPCM_ADX_DECODER) += adxdec.o adx.o OBJS-$(CONFIG_ADPCM_ADX_ENCODER) += adxenc.o adx.o OBJS-$(CONFIG_ADPCM_AFC_DECODER) += adpcm.o adpcm_data.o +OBJS-$(CONFIG_ADPCM_AGM_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 @@ -941,9 +961,12 @@ OBJS-$(CONFIG_PCM_ALAW_AT_ENCODER) += audiotoolboxenc.o OBJS-$(CONFIG_PCM_MULAW_AT_ENCODER) += audiotoolboxenc.o OBJS-$(CONFIG_LIBAOM_AV1_DECODER) += libaomdec.o OBJS-$(CONFIG_LIBAOM_AV1_ENCODER) += libaomenc.o +OBJS-$(CONFIG_LIBARIBB24_DECODER) += libaribb24.o ass.o OBJS-$(CONFIG_LIBCELT_DECODER) += libcelt_dec.o OBJS-$(CONFIG_LIBCODEC2_DECODER) += libcodec2.o codec2utils.o OBJS-$(CONFIG_LIBCODEC2_ENCODER) += libcodec2.o codec2utils.o +OBJS-$(CONFIG_LIBDAV1D_DECODER) += libdav1d.o +OBJS-$(CONFIG_LIBDAVS2_DECODER) += libdavs2.o OBJS-$(CONFIG_LIBFDK_AAC_DECODER) += libfdk-aacdec.o OBJS-$(CONFIG_LIBFDK_AAC_ENCODER) += libfdk-aacenc.o OBJS-$(CONFIG_LIBGSM_DECODER) += libgsmdec.o @@ -985,7 +1008,8 @@ OBJS-$(CONFIG_LIBX262_ENCODER) += libx264.o OBJS-$(CONFIG_LIBX264_ENCODER) += libx264.o OBJS-$(CONFIG_LIBX265_ENCODER) += libx265.o OBJS-$(CONFIG_LIBXAVS_ENCODER) += libxavs.o -OBJS-$(CONFIG_LIBXVID_ENCODER) += libxvid.o libxvid_rc.o +OBJS-$(CONFIG_LIBXAVS2_ENCODER) += libxavs2.o +OBJS-$(CONFIG_LIBXVID_ENCODER) += libxvid.o OBJS-$(CONFIG_LIBZVBI_TELETEXT_DECODER) += libzvbi-teletextdec.o ass.o # parsers @@ -994,6 +1018,8 @@ OBJS-$(CONFIG_AAC_PARSER) += aac_parser.o aac_ac3_parser.o \ mpeg4audio.o OBJS-$(CONFIG_AC3_PARSER) += ac3tab.o aac_ac3_parser.o OBJS-$(CONFIG_ADX_PARSER) += adx_parser.o adx.o +OBJS-$(CONFIG_AV1_PARSER) += av1_parser.o av1_parse.o +OBJS-$(CONFIG_AVS2_PARSER) += avs2_parser.o OBJS-$(CONFIG_BMP_PARSER) += bmp_parser.o OBJS-$(CONFIG_CAVSVIDEO_PARSER) += cavs_parser.o OBJS-$(CONFIG_COOK_PARSER) += cook_parser.o @@ -1007,14 +1033,16 @@ OBJS-$(CONFIG_DVD_NAV_PARSER) += dvd_nav_parser.o OBJS-$(CONFIG_DVDSUB_PARSER) += dvdsub_parser.o OBJS-$(CONFIG_FLAC_PARSER) += flac_parser.o flacdata.o flac.o \ vorbis_data.o +OBJS-$(CONFIG_G723_1_PARSER) += g723_1_parser.o OBJS-$(CONFIG_G729_PARSER) += g729_parser.o +OBJS-$(CONFIG_GIF_PARSER) += gif_parser.o OBJS-$(CONFIG_GSM_PARSER) += gsm_parser.o OBJS-$(CONFIG_H261_PARSER) += h261_parser.o OBJS-$(CONFIG_H263_PARSER) += h263_parser.o OBJS-$(CONFIG_H264_PARSER) += h264_parser.o h264_sei.o h264data.o OBJS-$(CONFIG_HEVC_PARSER) += hevc_parser.o hevc_data.o OBJS-$(CONFIG_MJPEG_PARSER) += mjpeg_parser.o -OBJS-$(CONFIG_MLP_PARSER) += mlp_parser.o mlp.o +OBJS-$(CONFIG_MLP_PARSER) += mlp_parse.o mlp_parser.o mlp.o OBJS-$(CONFIG_MPEG4VIDEO_PARSER) += mpeg4video_parser.o h263.o \ mpeg4videodec.o mpeg4video.o \ ituh263dec.o h263dec.o h263data.o @@ -1040,18 +1068,20 @@ OBJS-$(CONFIG_XMA_PARSER) += xma_parser.o # bitstream filters OBJS-$(CONFIG_AAC_ADTSTOASC_BSF) += aac_adtstoasc_bsf.o mpeg4audio.o +OBJS-$(CONFIG_AV1_METADATA_BSF) += av1_metadata_bsf.o +OBJS-$(CONFIG_AV1_FRAME_SPLIT_BSF) += av1_frame_split_bsf.o OBJS-$(CONFIG_CHOMP_BSF) += chomp_bsf.o OBJS-$(CONFIG_DUMP_EXTRADATA_BSF) += dump_extradata_bsf.o OBJS-$(CONFIG_DCA_CORE_BSF) += dca_core_bsf.o OBJS-$(CONFIG_EAC3_CORE_BSF) += eac3_core_bsf.o OBJS-$(CONFIG_EXTRACT_EXTRADATA_BSF) += extract_extradata_bsf.o \ - h2645_parse.o + av1_parse.o h2645_parse.o OBJS-$(CONFIG_FILTER_UNITS_BSF) += filter_units_bsf.o -OBJS-$(CONFIG_H264_METADATA_BSF) += h264_metadata_bsf.o +OBJS-$(CONFIG_H264_METADATA_BSF) += h264_metadata_bsf.o h264_levels.o OBJS-$(CONFIG_H264_MP4TOANNEXB_BSF) += h264_mp4toannexb_bsf.o OBJS-$(CONFIG_H264_REDUNDANT_PPS_BSF) += h264_redundant_pps_bsf.o OBJS-$(CONFIG_HAPQA_EXTRACT_BSF) += hapqa_extract_bsf.o hap.o -OBJS-$(CONFIG_HEVC_METADATA_BSF) += h265_metadata_bsf.o +OBJS-$(CONFIG_HEVC_METADATA_BSF) += h265_metadata_bsf.o h265_profile_level.o OBJS-$(CONFIG_HEVC_MP4TOANNEXB_BSF) += hevc_mp4toannexb_bsf.o OBJS-$(CONFIG_IMX_DUMP_HEADER_BSF) += imx_dump_header_bsf.o OBJS-$(CONFIG_MJPEG2JPEG_BSF) += mjpeg2jpeg_bsf.o @@ -1063,9 +1093,12 @@ OBJS-$(CONFIG_MP3_HEADER_DECOMPRESS_BSF) += mp3_header_decompress_bsf.o \ OBJS-$(CONFIG_MPEG2_METADATA_BSF) += mpeg2_metadata_bsf.o OBJS-$(CONFIG_NOISE_BSF) += noise_bsf.o OBJS-$(CONFIG_NULL_BSF) += null_bsf.o +OBJS-$(CONFIG_PRORES_METADATA_BSF) += prores_metadata_bsf.o OBJS-$(CONFIG_REMOVE_EXTRADATA_BSF) += remove_extradata_bsf.o OBJS-$(CONFIG_TEXT2MOVSUB_BSF) += movsub_bsf.o OBJS-$(CONFIG_TRACE_HEADERS_BSF) += trace_headers_bsf.o +OBJS-$(CONFIG_TRUEHD_CORE_BSF) += truehd_core_bsf.o mlp_parse.o mlp.o +OBJS-$(CONFIG_VP9_METADATA_BSF) += vp9_metadata_bsf.o OBJS-$(CONFIG_VP9_RAW_REORDER_BSF) += vp9_raw_reorder_bsf.o OBJS-$(CONFIG_VP9_SUPERFRAME_BSF) += vp9_superframe_bsf.o OBJS-$(CONFIG_VP9_SUPERFRAME_SPLIT_BSF) += vp9_superframe_split_bsf.o @@ -1127,6 +1160,8 @@ TESTPROGS-$(CONFIG_IDCTDSP) += dct TESTPROGS-$(CONFIG_IIRFILTER) += iirfilter TESTPROGS-$(HAVE_MMX) += motion TESTPROGS-$(CONFIG_MPEGVIDEO) += mpeg12framerate +TESTPROGS-$(CONFIG_H264_METADATA_BSF) += h264_levels +TESTPROGS-$(CONFIG_HEVC_METADATA_BSF) += h265_levels TESTPROGS-$(CONFIG_RANGECODER) += rangecoder TESTPROGS-$(CONFIG_SNOW_ENCODER) += snowenc diff --git a/libavcodec/a64multienc.c b/libavcodec/a64multienc.c index 91aac0933..38f25020f 100644 --- a/libavcodec/a64multienc.c +++ b/libavcodec/a64multienc.c @@ -60,11 +60,11 @@ typedef struct A64Context { } A64Context; /* gray gradient */ -static const int mc_colors[5]={0x0,0xb,0xc,0xf,0x1}; +static const uint8_t mc_colors[5]={0x0,0xb,0xc,0xf,0x1}; /* other possible gradients - to be tested */ -//static const int mc_colors[5]={0x0,0x8,0xa,0xf,0x7}; -//static const int mc_colors[5]={0x0,0x9,0x8,0xa,0x3}; +//static const uint8_t mc_colors[5]={0x0,0x8,0xa,0xf,0x7}; +//static const uint8_t mc_colors[5]={0x0,0x9,0x8,0xa,0x3}; static void to_meta_with_crop(AVCodecContext *avctx, const AVFrame *p, int *dest) diff --git a/libavcodec/aac.h b/libavcodec/aac.h index 05bc95385..c2b9c980c 100644 --- a/libavcodec/aac.h +++ b/libavcodec/aac.h @@ -368,7 +368,7 @@ struct AACContext { INTFLOAT *in, IndividualChannelStream *ics); void (*update_ltp)(AACContext *ac, SingleChannelElement *sce); void (*vector_pow43)(int *coefs, int len); - void (*subband_scale)(int *dst, int *src, int scale, int offset, int len); + void (*subband_scale)(int *dst, int *src, int scale, int offset, int len, void *log_context); }; diff --git a/libavcodec/aacdec.c b/libavcodec/aacdec.c index d394700cd..98b6e58be 100644 --- a/libavcodec/aacdec.c +++ b/libavcodec/aacdec.c @@ -247,14 +247,12 @@ static void apply_independent_coupling(AACContext *ac, SingleChannelElement *target, ChannelElement *cce, int index) { - int i; const float gain = cce->coup.gain[index][0]; const float *src = cce->ch[0].ret; float *dest = target->ret; const int len = 1024 << (ac->oc[1].m4ac.sbr == 1); - for (i = 0; i < len; i++) - dest[i] += gain * src[i]; + ac->fdsp->vector_fmac_scalar(dest, src, gain, len); } #include "aacdec_template.c" @@ -561,7 +559,7 @@ 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, + .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE | FF_CODEC_CAP_INIT_CLEANUP, .channel_layouts = aac_channel_layout, .flush = flush, .priv_class = &aac_decoder_class, @@ -586,7 +584,7 @@ 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, + .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE | FF_CODEC_CAP_INIT_CLEANUP, .channel_layouts = aac_channel_layout, .flush = flush, .profiles = NULL_IF_CONFIG_SMALL(ff_aac_profiles), diff --git a/libavcodec/aacdec_fixed.c b/libavcodec/aacdec_fixed.c index 1bdb93f5b..1d0142fdb 100644 --- a/libavcodec/aacdec_fixed.c +++ b/libavcodec/aacdec_fixed.c @@ -162,7 +162,7 @@ static void vector_pow43(int *coefs, int len) } } -static void subband_scale(int *dst, int *src, int scale, int offset, int len) +static void subband_scale(int *dst, int *src, int scale, int offset, int len, void *log_context) { int ssign = scale < 0 ? -1 : 1; int s = FFABS(scale); @@ -189,18 +189,18 @@ static void subband_scale(int *dst, int *src, int scale, int offset, int len) dst[i] = out * (unsigned)ssign; } } else { - av_log(NULL, AV_LOG_ERROR, "Overflow in subband_scale()\n"); + av_log(log_context, AV_LOG_ERROR, "Overflow in subband_scale()\n"); } } static void noise_scale(int *coefs, int scale, int band_energy, int len) { - int ssign = scale < 0 ? -1 : 1; - int s = FFABS(scale); + int s = -scale; unsigned int round; int i, out, c = exp2tab[s & 3]; int nlz = 0; + av_assert0(s >= 0); while (band_energy > 0x7fff) { band_energy >>= 1; nlz++; @@ -216,15 +216,20 @@ static void noise_scale(int *coefs, int scale, int band_energy, int len) round = s ? 1 << (s-1) : 0; for (i=0; i> 32); - coefs[i] = ((int)(out+round) >> s) * ssign; + coefs[i] = -((int)(out+round) >> s); } } else { s = s + 32; - round = 1 << (s-1); - for (i=0; i> s); - coefs[i] = out * ssign; + if (s > 0) { + round = 1 << (s-1); + for (i=0; i> s); + coefs[i] = -out; + } + } else { + for (i=0; irandom_state = lcg_random(ac->random_state); -#if USE_FIXED cfo[k] = ac->random_state >> 3; -#else - cfo[k] = ac->random_state; -#endif /* USE_FIXED */ } -#if USE_FIXED band_energy = ac->fdsp->scalarproduct_fixed(cfo, cfo, off_len); band_energy = fixed_sqrt(band_energy, 31); noise_scale(cfo, sf[idx], band_energy, off_len); #else + float scale; + + for (k = 0; k < off_len; k++) { + ac->random_state = lcg_random(ac->random_state); + cfo[k] = ac->random_state; + } + band_energy = ac->fdsp->scalarproduct_float(cfo, cfo, off_len); scale = sf[idx] / sqrtf(band_energy); ac->fdsp->vector_fmul_scalar(cfo, cfo, scale, off_len); @@ -1927,7 +1926,7 @@ static int decode_spectrum_and_dequant(AACContext *ac, INTFLOAT coef[1024], if (cbt_m1 < NOISE_BT - 1) { for (group = 0; group < (int)g_len; group++, cfo+=128) { ac->vector_pow43(cfo, off_len); - ac->subband_scale(cfo, cfo, sf[idx], 34, off_len); + ac->subband_scale(cfo, cfo, sf[idx], 34, off_len, ac->avctx); } } } @@ -2158,7 +2157,7 @@ static void apply_intensity_stereo(AACContext *ac, coef0 + group * 128 + offsets[i], scale, 23, - offsets[i + 1] - offsets[i]); + offsets[i + 1] - offsets[i] ,ac->avctx); #else ac->fdsp->vector_fmul_scalar(coef1 + group * 128 + offsets[i], coef0 + group * 128 + offsets[i], @@ -2493,6 +2492,9 @@ static void apply_tns(INTFLOAT coef_param[1024], TemporalNoiseShaping *tns, INTFLOAT tmp[TNS_MAX_ORDER+1]; UINTFLOAT *coef = coef_param; + if(!mmm) + return; + for (w = 0; w < ics->num_windows; w++) { bottom = ics->num_swb; for (filt = 0; filt < tns->n_filt[w]; filt++) { @@ -2657,7 +2659,7 @@ static void imdct_and_windowing(AACContext *ac, SingleChannelElement *sce) ac->mdct.imdct_half(&ac->mdct, buf, in); #if USE_FIXED for (i=0; i<1024; i++) - buf[i] = (buf[i] + 4) >> 3; + buf[i] = (buf[i] + 4LL) >> 3; #endif /* USE_FIXED */ } @@ -3122,6 +3124,7 @@ static int aac_decode_frame_int(AVCodecContext *avctx, void *data, int samples = 0, multiplier, audio_found = 0, pce_found = 0; int is_dmono, sce_count = 0; int payload_alignment; + uint8_t che_presence[4][MAX_ELEM_ID] = {{0}}; ac->frame = data; @@ -3159,6 +3162,17 @@ static int aac_decode_frame_int(AVCodecContext *avctx, void *data, } if (elem_type < TYPE_DSE) { + if (che_presence[elem_type][elem_id]) { + int error = che_presence[elem_type][elem_id] > 1; + av_log(ac->avctx, error ? AV_LOG_ERROR : AV_LOG_DEBUG, "channel element %d.%d duplicate\n", + elem_type, elem_id); + if (error) { + err = AVERROR_INVALIDDATA; + goto fail; + } + } + che_presence[elem_type][elem_id]++; + if (!(che=get_che(ac, elem_type, elem_id))) { av_log(ac->avctx, AV_LOG_ERROR, "channel element %d.%d is not allocated\n", elem_type, elem_id); @@ -3324,20 +3338,14 @@ static int aac_decode_frame(AVCodecContext *avctx, void *data, AV_PKT_DATA_JP_DUALMONO, &jp_dualmono_size); - if (new_extradata && 0) { - av_free(avctx->extradata); - avctx->extradata = av_mallocz(new_extradata_size + - AV_INPUT_BUFFER_PADDING_SIZE); - if (!avctx->extradata) - return AVERROR(ENOMEM); - avctx->extradata_size = new_extradata_size; - memcpy(avctx->extradata, new_extradata, new_extradata_size); - push_output_configuration(ac); - if (decode_audio_specific_config(ac, ac->avctx, &ac->oc[1].m4ac, - avctx->extradata, - avctx->extradata_size*8LL, 1) < 0) { - pop_output_configuration(ac); - return AVERROR_INVALIDDATA; + if (new_extradata) { + /* discard previous configuration */ + ac->oc[1].status = OC_NONE; + err = decode_audio_specific_config(ac, ac->avctx, &ac->oc[1].m4ac, + new_extradata, + new_extradata_size * 8LL, 1); + if (err < 0) { + return err; } } diff --git a/libavcodec/aacenc.c b/libavcodec/aacenc.c index 6d94c7690..4d0abb107 100644 --- a/libavcodec/aacenc.c +++ b/libavcodec/aacenc.c @@ -982,11 +982,13 @@ static av_cold int aac_encode_init(AVCodecContext *avctx) } if (s->needs_pce) { + char buf[64]; for (i = 0; i < FF_ARRAY_ELEMS(aac_pce_configs); i++) if (avctx->channel_layout == aac_pce_configs[i].layout) break; - ERROR_IF(i == FF_ARRAY_ELEMS(aac_pce_configs), "Unsupported channel layout\n"); - av_log(avctx, AV_LOG_INFO, "Using a PCE to encode channel layout\n"); + av_get_channel_layout_string(buf, sizeof(buf), -1, avctx->channel_layout); + ERROR_IF(i == FF_ARRAY_ELEMS(aac_pce_configs), "Unsupported channel layout \"%s\"\n", buf); + av_log(avctx, AV_LOG_INFO, "Using a PCE to encode channel layout \"%s\"\n", buf); s->pce = aac_pce_configs[i]; s->reorder_map = s->pce.reorder_map; s->chan_map = s->pce.config_map; diff --git a/libavcodec/aacenc_ltp.c b/libavcodec/aacenc_ltp.c index 674a2a068..f77f0b6a7 100644 --- a/libavcodec/aacenc_ltp.c +++ b/libavcodec/aacenc_ltp.c @@ -144,7 +144,7 @@ void ff_aac_adjust_common_ltp(AACEncContext *s, ChannelElement *cpe) 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) { + } else { count++; } } diff --git a/libavcodec/aacps.c b/libavcodec/aacps.c index b16c3393d..d5dca64b0 100644 --- a/libavcodec/aacps.c +++ b/libavcodec/aacps.c @@ -118,7 +118,7 @@ static int read_ ## PAR ## _data(AVCodecContext *avctx, GetBitContext *gb, PSCon return 0; \ err: \ av_log(avctx, AV_LOG_ERROR, "illegal "#PAR"\n"); \ - return -1; \ + return AVERROR_INVALIDDATA; \ } READ_PAR_DATA(iid, huff_offset[table_idx], 0, FFABS(ps->iid_par[e][b]) > 7 + 8 * ps->iid_quant) diff --git a/libavcodec/aacpsdsp_template.c b/libavcodec/aacpsdsp_template.c index 5f4be017d..eef8adc7e 100644 --- a/libavcodec/aacpsdsp_template.c +++ b/libavcodec/aacpsdsp_template.c @@ -54,10 +54,10 @@ static void ps_hybrid_analysis_c(INTFLOAT (*out)[2], INTFLOAT (*in)[2], INT64FLOAT sum_im = (INT64FLOAT)filter[i][6][0] * in[6][1]; for (j = 0; j < 6; j++) { - INTFLOAT in0_re = in[j][0]; - INTFLOAT in0_im = in[j][1]; - INTFLOAT in1_re = in[12-j][0]; - INTFLOAT in1_im = in[12-j][1]; + INT64FLOAT in0_re = in[j][0]; + INT64FLOAT in0_im = in[j][1]; + INT64FLOAT in1_re = in[12-j][0]; + INT64FLOAT in1_im = in[12-j][1]; sum_re += (INT64FLOAT)filter[i][j][0] * (in0_re + in1_re) - (INT64FLOAT)filter[i][j][1] * (in0_im - in1_im); sum_im += (INT64FLOAT)filter[i][j][0] * (in0_im + in1_im) + diff --git a/libavcodec/aacsbr_tablegen_common.h b/libavcodec/aacsbr_tablegen_common.h index 8c8f6effa..8e0dd9e1f 100644 --- a/libavcodec/aacsbr_tablegen_common.h +++ b/libavcodec/aacsbr_tablegen_common.h @@ -111,16 +111,4 @@ static DECLARE_ALIGNED(32, INTFLOAT, sbr_qmf_window_us)[640] = { Q31( 0.8537385600f), }; -static av_cold void aacsbr_tableinit(void) -{ - int n; - for (n = 1; n < 320; n++) - sbr_qmf_window_us[320 + n] = sbr_qmf_window_us[320 - n]; - sbr_qmf_window_us[384] = -sbr_qmf_window_us[384]; - sbr_qmf_window_us[512] = -sbr_qmf_window_us[512]; - - for (n = 0; n < 320; n++) - sbr_qmf_window_ds[n] = sbr_qmf_window_us[2*n]; -} - #endif /* AVCODEC_AACSBR_TABLEGEN_COMMON_H */ diff --git a/libavcodec/aacsbr_template.c b/libavcodec/aacsbr_template.c index 3fe78d5b6..821615f2a 100644 --- a/libavcodec/aacsbr_template.c +++ b/libavcodec/aacsbr_template.c @@ -34,6 +34,18 @@ #include "libavutil/qsort.h" +static av_cold void aacsbr_tableinit(void) +{ + int n; + for (n = 1; n < 320; n++) + sbr_qmf_window_us[320 + n] = sbr_qmf_window_us[320 - n]; + sbr_qmf_window_us[384] = -sbr_qmf_window_us[384]; + sbr_qmf_window_us[512] = -sbr_qmf_window_us[512]; + + for (n = 0; n < 320; n++) + sbr_qmf_window_ds[n] = sbr_qmf_window_us[2*n]; +} + av_cold void AAC_RENAME(ff_aac_sbr_init)(void) { static const struct { diff --git a/libavcodec/aarch64/Makefile b/libavcodec/aarch64/Makefile index 72080c2db..00f93bf59 100644 --- a/libavcodec/aarch64/Makefile +++ b/libavcodec/aarch64/Makefile @@ -9,11 +9,13 @@ OBJS-$(CONFIG_HPELDSP) += aarch64/hpeldsp_init_aarch64.o OBJS-$(CONFIG_MPEGAUDIODSP) += aarch64/mpegaudiodsp_init.o OBJS-$(CONFIG_NEON_CLOBBER_TEST) += aarch64/neontest.o OBJS-$(CONFIG_VIDEODSP) += aarch64/videodsp_init.o +OBJS-$(CONFIG_VP8DSP) += aarch64/vp8dsp_init_aarch64.o # decoders/encoders OBJS-$(CONFIG_AAC_DECODER) += aarch64/aacpsdsp_init_aarch64.o \ aarch64/sbrdsp_init_aarch64.o OBJS-$(CONFIG_DCA_DECODER) += aarch64/synth_filter_init.o +OBJS-$(CONFIG_OPUS_DECODER) += aarch64/opusdsp_init.o OBJS-$(CONFIG_RV40_DECODER) += aarch64/rv40dsp_init_aarch64.o OBJS-$(CONFIG_VC1DSP) += aarch64/vc1dsp_init_aarch64.o OBJS-$(CONFIG_VORBIS_DECODER) += aarch64/vorbisdsp_init.o @@ -43,10 +45,12 @@ NEON-OBJS-$(CONFIG_IDCTDSP) += aarch64/idctdsp_init_aarch64.o \ aarch64/simple_idct_neon.o NEON-OBJS-$(CONFIG_MDCT) += aarch64/mdct_neon.o NEON-OBJS-$(CONFIG_MPEGAUDIODSP) += aarch64/mpegaudiodsp_neon.o +NEON-OBJS-$(CONFIG_VP8DSP) += aarch64/vp8dsp_neon.o # decoders/encoders NEON-OBJS-$(CONFIG_AAC_DECODER) += aarch64/aacpsdsp_neon.o NEON-OBJS-$(CONFIG_DCA_DECODER) += aarch64/synth_filter_neon.o +NEON-OBJS-$(CONFIG_OPUS_DECODER) += aarch64/opusdsp_neon.o NEON-OBJS-$(CONFIG_VORBIS_DECODER) += aarch64/vorbisdsp_neon.o NEON-OBJS-$(CONFIG_VP9_DECODER) += aarch64/vp9itxfm_16bpp_neon.o \ aarch64/vp9itxfm_neon.o \ diff --git a/libavcodec/aarch64/asm-offsets.h b/libavcodec/aarch64/asm-offsets.h index e05c5ad2e..fc38eed29 100644 --- a/libavcodec/aarch64/asm-offsets.h +++ b/libavcodec/aarch64/asm-offsets.h @@ -19,14 +19,6 @@ #ifndef AVCODEC_AARCH64_ASM_OFFSETS_H #define AVCODEC_AARCH64_ASM_OFFSETS_H -/* CeltIMDCTContext */ -#define CELT_EXPTAB 0x20 -#define CELT_FFT_N 0x00 -#define CELT_LEN2 0x04 -#define CELT_LEN4 (CELT_LEN2 + 0x4) // loaded as pair -#define CELT_TMP 0x10 -#define CELT_TWIDDLE (CELT_TMP + 0x8) // loaded as pair - /* FFTContext */ #define IMDCT_HALF 0x48 diff --git a/libavcodec/aarch64/h264dsp_init_aarch64.c b/libavcodec/aarch64/h264dsp_init_aarch64.c index e0f378f5a..d5baccf23 100644 --- a/libavcodec/aarch64/h264dsp_init_aarch64.c +++ b/libavcodec/aarch64/h264dsp_init_aarch64.c @@ -25,29 +25,43 @@ #include "libavutil/aarch64/cpu.h" #include "libavcodec/h264dsp.h" -void ff_h264_v_loop_filter_luma_neon(uint8_t *pix, int stride, int alpha, +void ff_h264_v_loop_filter_luma_neon(uint8_t *pix, ptrdiff_t stride, int alpha, int beta, int8_t *tc0); -void ff_h264_h_loop_filter_luma_neon(uint8_t *pix, int stride, int alpha, +void ff_h264_h_loop_filter_luma_neon(uint8_t *pix, ptrdiff_t stride, int alpha, int beta, int8_t *tc0); -void ff_h264_v_loop_filter_chroma_neon(uint8_t *pix, int stride, int alpha, +void ff_h264_v_loop_filter_luma_intra_neon(uint8_t *pix, ptrdiff_t stride, int alpha, + int beta); +void ff_h264_h_loop_filter_luma_intra_neon(uint8_t *pix, ptrdiff_t stride, int alpha, + int beta); +void ff_h264_v_loop_filter_chroma_neon(uint8_t *pix, ptrdiff_t stride, int alpha, int beta, int8_t *tc0); -void ff_h264_h_loop_filter_chroma_neon(uint8_t *pix, int stride, int alpha, +void ff_h264_h_loop_filter_chroma_neon(uint8_t *pix, ptrdiff_t stride, int alpha, int beta, int8_t *tc0); +void ff_h264_h_loop_filter_chroma422_neon(uint8_t *pix, ptrdiff_t stride, int alpha, + int beta, int8_t *tc0); +void ff_h264_v_loop_filter_chroma_intra_neon(uint8_t *pix, ptrdiff_t stride, + int alpha, int beta); +void ff_h264_h_loop_filter_chroma_intra_neon(uint8_t *pix, ptrdiff_t stride, + int alpha, int beta); +void ff_h264_h_loop_filter_chroma422_intra_neon(uint8_t *pix, ptrdiff_t stride, + int alpha, int beta); +void ff_h264_h_loop_filter_chroma_mbaff_intra_neon(uint8_t *pix, ptrdiff_t stride, + int alpha, int beta); -void ff_weight_h264_pixels_16_neon(uint8_t *dst, int stride, int height, +void ff_weight_h264_pixels_16_neon(uint8_t *dst, ptrdiff_t stride, int height, int log2_den, int weight, int offset); -void ff_weight_h264_pixels_8_neon(uint8_t *dst, int stride, int height, +void ff_weight_h264_pixels_8_neon(uint8_t *dst, ptrdiff_t stride, int height, int log2_den, int weight, int offset); -void ff_weight_h264_pixels_4_neon(uint8_t *dst, int stride, int height, +void ff_weight_h264_pixels_4_neon(uint8_t *dst, ptrdiff_t stride, int height, int log2_den, int weight, int offset); -void ff_biweight_h264_pixels_16_neon(uint8_t *dst, uint8_t *src, int stride, +void ff_biweight_h264_pixels_16_neon(uint8_t *dst, uint8_t *src, ptrdiff_t stride, int height, int log2_den, int weightd, int weights, int offset); -void ff_biweight_h264_pixels_8_neon(uint8_t *dst, uint8_t *src, int stride, +void ff_biweight_h264_pixels_8_neon(uint8_t *dst, uint8_t *src, ptrdiff_t stride, int height, int log2_den, int weightd, int weights, int offset); -void ff_biweight_h264_pixels_4_neon(uint8_t *dst, uint8_t *src, int stride, +void ff_biweight_h264_pixels_4_neon(uint8_t *dst, uint8_t *src, ptrdiff_t stride, int height, int log2_den, int weightd, int weights, int offset); @@ -77,9 +91,22 @@ av_cold void ff_h264dsp_init_aarch64(H264DSPContext *c, const int bit_depth, if (have_neon(cpu_flags) && bit_depth == 8) { c->h264_v_loop_filter_luma = ff_h264_v_loop_filter_luma_neon; c->h264_h_loop_filter_luma = ff_h264_h_loop_filter_luma_neon; + c->h264_v_loop_filter_luma_intra= ff_h264_v_loop_filter_luma_intra_neon; + c->h264_h_loop_filter_luma_intra= ff_h264_h_loop_filter_luma_intra_neon; + c->h264_v_loop_filter_chroma = ff_h264_v_loop_filter_chroma_neon; - if (chroma_format_idc <= 1) - c->h264_h_loop_filter_chroma = ff_h264_h_loop_filter_chroma_neon; + c->h264_v_loop_filter_chroma_intra = ff_h264_v_loop_filter_chroma_intra_neon; + + if (chroma_format_idc <= 1) { + c->h264_h_loop_filter_chroma = ff_h264_h_loop_filter_chroma_neon; + c->h264_h_loop_filter_chroma_intra = ff_h264_h_loop_filter_chroma_intra_neon; + c->h264_h_loop_filter_chroma_mbaff_intra = ff_h264_h_loop_filter_chroma_mbaff_intra_neon; + } else { + c->h264_h_loop_filter_chroma = ff_h264_h_loop_filter_chroma422_neon; + c->h264_h_loop_filter_chroma_mbaff = ff_h264_h_loop_filter_chroma_neon; + c->h264_h_loop_filter_chroma_intra = ff_h264_h_loop_filter_chroma422_intra_neon; + c->h264_h_loop_filter_chroma_mbaff_intra = ff_h264_h_loop_filter_chroma_intra_neon; + } c->weight_h264_pixels_tab[0] = ff_weight_h264_pixels_16_neon; c->weight_h264_pixels_tab[1] = ff_weight_h264_pixels_8_neon; diff --git a/libavcodec/aarch64/h264dsp_neon.S b/libavcodec/aarch64/h264dsp_neon.S index 4ec35f290..fbb8ecc46 100644 --- a/libavcodec/aarch64/h264dsp_neon.S +++ b/libavcodec/aarch64/h264dsp_neon.S @@ -1,6 +1,7 @@ /* * Copyright (c) 2008 Mans Rullgard * Copyright (c) 2013 Janne Grunau + * Copyright (c) 2014 Janne Grunau * * This file is part of FFmpeg. * @@ -27,9 +28,9 @@ ldr w6, [x4] ccmp w3, #0, #0, ne mov v24.S[0], w6 - and w6, w6, w6, lsl #16 + and w8, w6, w6, lsl #16 b.eq 1f - ands w6, w6, w6, lsl #8 + ands w8, w8, w8, lsl #8 b.ge 2f 1: ret @@ -54,9 +55,12 @@ uabd v17.16B, v20.16B, v16.16B // abs(p2 - p0) and v21.16B, v21.16B, v28.16B uabd v19.16B, v4.16B, v0.16B // abs(q2 - q0) + and v21.16B, v21.16B, v30.16B // < beta + shrn v30.8b, v21.8h, #4 + mov x7, v30.d[0] cmhi v17.16B, v22.16B, v17.16B // < beta - and v21.16B, v21.16B, v30.16B cmhi v19.16B, v22.16B, v19.16B // < beta + cbz x7, 9f and v17.16B, v17.16B, v21.16B and v19.16B, v19.16B, v21.16B and v24.16B, v24.16B, v21.16B @@ -124,12 +128,13 @@ function ff_h264_v_loop_filter_luma_neon, export=1 st1 {v16.16B}, [x0], x1 st1 {v0.16B}, [x0], x1 st1 {v19.16B}, [x0] - +9: ret endfunc function ff_h264_h_loop_filter_luma_neon, export=1 h264_loop_filter_start + sxtw x1, w1 sub x0, x0, #4 ld1 {v6.8B}, [x0], x1 @@ -173,32 +178,231 @@ function ff_h264_h_loop_filter_luma_neon, export=1 st1 {v16.S}[3], [x0], x1 st1 {v0.S}[3], [x0], x1 st1 {v19.S}[3], [x0], x1 - +9: ret endfunc + +.macro h264_loop_filter_start_intra + orr w4, w2, w3 + cbnz w4, 1f + ret +1: + sxtw x1, w1 + dup v30.16b, w2 // alpha + dup v31.16b, w3 // beta +.endm + +.macro h264_loop_filter_luma_intra + uabd v16.16b, v7.16b, v0.16b // abs(p0 - q0) + uabd v17.16b, v6.16b, v7.16b // abs(p1 - p0) + uabd v18.16b, v1.16b, v0.16b // abs(q1 - q0) + cmhi v19.16b, v30.16b, v16.16b // < alpha + cmhi v17.16b, v31.16b, v17.16b // < beta + cmhi v18.16b, v31.16b, v18.16b // < beta + + movi v29.16b, #2 + ushr v30.16b, v30.16b, #2 // alpha >> 2 + add v30.16b, v30.16b, v29.16b // (alpha >> 2) + 2 + cmhi v16.16b, v30.16b, v16.16b // < (alpha >> 2) + 2 + + and v19.16b, v19.16b, v17.16b + and v19.16b, v19.16b, v18.16b + shrn v20.8b, v19.8h, #4 + mov x4, v20.d[0] + cbz x4, 9f + + ushll v20.8h, v6.8b, #1 + ushll v22.8h, v1.8b, #1 + ushll2 v21.8h, v6.16b, #1 + ushll2 v23.8h, v1.16b, #1 + uaddw v20.8h, v20.8h, v7.8b + uaddw v22.8h, v22.8h, v0.8b + uaddw2 v21.8h, v21.8h, v7.16b + uaddw2 v23.8h, v23.8h, v0.16b + uaddw v20.8h, v20.8h, v1.8b + uaddw v22.8h, v22.8h, v6.8b + uaddw2 v21.8h, v21.8h, v1.16b + uaddw2 v23.8h, v23.8h, v6.16b + + rshrn v24.8b, v20.8h, #2 // p0'_1 + rshrn v25.8b, v22.8h, #2 // q0'_1 + rshrn2 v24.16b, v21.8h, #2 // p0'_1 + rshrn2 v25.16b, v23.8h, #2 // q0'_1 + + uabd v17.16b, v5.16b, v7.16b // abs(p2 - p0) + uabd v18.16b, v2.16b, v0.16b // abs(q2 - q0) + cmhi v17.16b, v31.16b, v17.16b // < beta + cmhi v18.16b, v31.16b, v18.16b // < beta + + and v17.16b, v16.16b, v17.16b // if_2 && if_3 + and v18.16b, v16.16b, v18.16b // if_2 && if_4 + + not v30.16b, v17.16b + not v31.16b, v18.16b + + and v30.16b, v30.16b, v19.16b // if_1 && !(if_2 && if_3) + and v31.16b, v31.16b, v19.16b // if_1 && !(if_2 && if_4) + + and v17.16b, v19.16b, v17.16b // if_1 && if_2 && if_3 + and v18.16b, v19.16b, v18.16b // if_1 && if_2 && if_4 + + //calc p, v7, v6, v5, v4, v17, v7, v6, v5, v4 + uaddl v26.8h, v5.8b, v7.8b + uaddl2 v27.8h, v5.16b, v7.16b + uaddw v26.8h, v26.8h, v0.8b + uaddw2 v27.8h, v27.8h, v0.16b + add v20.8h, v20.8h, v26.8h + add v21.8h, v21.8h, v27.8h + uaddw v20.8h, v20.8h, v0.8b + uaddw2 v21.8h, v21.8h, v0.16b + rshrn v20.8b, v20.8h, #3 // p0'_2 + rshrn2 v20.16b, v21.8h, #3 // p0'_2 + uaddw v26.8h, v26.8h, v6.8b + uaddw2 v27.8h, v27.8h, v6.16b + rshrn v21.8b, v26.8h, #2 // p1'_2 + rshrn2 v21.16b, v27.8h, #2 // p1'_2 + uaddl v28.8h, v4.8b, v5.8b + uaddl2 v29.8h, v4.16b, v5.16b + shl v28.8h, v28.8h, #1 + shl v29.8h, v29.8h, #1 + add v28.8h, v28.8h, v26.8h + add v29.8h, v29.8h, v27.8h + rshrn v19.8b, v28.8h, #3 // p2'_2 + rshrn2 v19.16b, v29.8h, #3 // p2'_2 + + //calc q, v0, v1, v2, v3, v18, v0, v1, v2, v3 + uaddl v26.8h, v2.8b, v0.8b + uaddl2 v27.8h, v2.16b, v0.16b + uaddw v26.8h, v26.8h, v7.8b + uaddw2 v27.8h, v27.8h, v7.16b + add v22.8h, v22.8h, v26.8h + add v23.8h, v23.8h, v27.8h + uaddw v22.8h, v22.8h, v7.8b + uaddw2 v23.8h, v23.8h, v7.16b + rshrn v22.8b, v22.8h, #3 // q0'_2 + rshrn2 v22.16b, v23.8h, #3 // q0'_2 + uaddw v26.8h, v26.8h, v1.8b + uaddw2 v27.8h, v27.8h, v1.16b + rshrn v23.8b, v26.8h, #2 // q1'_2 + rshrn2 v23.16b, v27.8h, #2 // q1'_2 + uaddl v28.8h, v2.8b, v3.8b + uaddl2 v29.8h, v2.16b, v3.16b + shl v28.8h, v28.8h, #1 + shl v29.8h, v29.8h, #1 + add v28.8h, v28.8h, v26.8h + add v29.8h, v29.8h, v27.8h + rshrn v26.8b, v28.8h, #3 // q2'_2 + rshrn2 v26.16b, v29.8h, #3 // q2'_2 + + bit v7.16b, v24.16b, v30.16b // p0'_1 + bit v0.16b, v25.16b, v31.16b // q0'_1 + bit v7.16b, v20.16b, v17.16b // p0'_2 + bit v6.16b, v21.16b, v17.16b // p1'_2 + bit v5.16b, v19.16b, v17.16b // p2'_2 + bit v0.16b, v22.16b, v18.16b // q0'_2 + bit v1.16b, v23.16b, v18.16b // q1'_2 + bit v2.16b, v26.16b, v18.16b // q2'_2 +.endm + +function ff_h264_v_loop_filter_luma_intra_neon, export=1 + h264_loop_filter_start_intra + + ld1 {v0.16b}, [x0], x1 // q0 + ld1 {v1.16b}, [x0], x1 // q1 + ld1 {v2.16b}, [x0], x1 // q2 + ld1 {v3.16b}, [x0], x1 // q3 + sub x0, x0, x1, lsl #3 + ld1 {v4.16b}, [x0], x1 // p3 + ld1 {v5.16b}, [x0], x1 // p2 + ld1 {v6.16b}, [x0], x1 // p1 + ld1 {v7.16b}, [x0] // p0 + + h264_loop_filter_luma_intra + + sub x0, x0, x1, lsl #1 + st1 {v5.16b}, [x0], x1 // p2 + st1 {v6.16b}, [x0], x1 // p1 + st1 {v7.16b}, [x0], x1 // p0 + st1 {v0.16b}, [x0], x1 // q0 + st1 {v1.16b}, [x0], x1 // q1 + st1 {v2.16b}, [x0] // q2 +9: + ret +endfunc + +function ff_h264_h_loop_filter_luma_intra_neon, export=1 + h264_loop_filter_start_intra + + sub x0, x0, #4 + ld1 {v4.8b}, [x0], x1 + ld1 {v5.8b}, [x0], x1 + ld1 {v6.8b}, [x0], x1 + ld1 {v7.8b}, [x0], x1 + ld1 {v0.8b}, [x0], x1 + ld1 {v1.8b}, [x0], x1 + ld1 {v2.8b}, [x0], x1 + ld1 {v3.8b}, [x0], x1 + ld1 {v4.d}[1], [x0], x1 + ld1 {v5.d}[1], [x0], x1 + ld1 {v6.d}[1], [x0], x1 + ld1 {v7.d}[1], [x0], x1 + ld1 {v0.d}[1], [x0], x1 + ld1 {v1.d}[1], [x0], x1 + ld1 {v2.d}[1], [x0], x1 + ld1 {v3.d}[1], [x0], x1 + + transpose_8x16B v4, v5, v6, v7, v0, v1, v2, v3, v21, v23 + + h264_loop_filter_luma_intra + + transpose_8x16B v4, v5, v6, v7, v0, v1, v2, v3, v21, v23 + + sub x0, x0, x1, lsl #4 + st1 {v4.8b}, [x0], x1 + st1 {v5.8b}, [x0], x1 + st1 {v6.8b}, [x0], x1 + st1 {v7.8b}, [x0], x1 + st1 {v0.8b}, [x0], x1 + st1 {v1.8b}, [x0], x1 + st1 {v2.8b}, [x0], x1 + st1 {v3.8b}, [x0], x1 + st1 {v4.d}[1], [x0], x1 + st1 {v5.d}[1], [x0], x1 + st1 {v6.d}[1], [x0], x1 + st1 {v7.d}[1], [x0], x1 + st1 {v0.d}[1], [x0], x1 + st1 {v1.d}[1], [x0], x1 + st1 {v2.d}[1], [x0], x1 + st1 {v3.d}[1], [x0], x1 +9: + ret +endfunc + .macro h264_loop_filter_chroma dup v22.8B, w2 // alpha + dup v23.8B, w3 // beta uxtl v24.8H, v24.8B uabd v26.8B, v16.8B, v0.8B // abs(p0 - q0) - uxtl v4.8H, v0.8B uabd v28.8B, v18.8B, v16.8B // abs(p1 - p0) - usubw v4.8H, v4.8H, v16.8B - sli v24.8H, v24.8H, #8 - shl v4.8H, v4.8H, #2 uabd v30.8B, v2.8B, v0.8B // abs(q1 - q0) - uaddw v4.8H, v4.8H, v18.8B cmhi v26.8B, v22.8B, v26.8B // < alpha + cmhi v28.8B, v23.8B, v28.8B // < beta + cmhi v30.8B, v23.8B, v30.8B // < beta + uxtl v4.8H, v0.8B + and v26.8B, v26.8B, v28.8B + usubw v4.8H, v4.8H, v16.8B + and v26.8B, v26.8B, v30.8B + shl v4.8H, v4.8H, #2 + mov x8, v26.d[0] + sli v24.8H, v24.8H, #8 + uaddw v4.8H, v4.8H, v18.8B + cbz x8, 9f usubw v4.8H, v4.8H, v2.8B - dup v22.8B, w3 // beta rshrn v4.8B, v4.8H, #3 - cmhi v28.8B, v22.8B, v28.8B // < beta - cmhi v30.8B, v22.8B, v30.8B // < beta smin v4.8B, v4.8B, v24.8B neg v25.8B, v24.8B - and v26.8B, v26.8B, v28.8B smax v4.8B, v4.8B, v25.8B - and v26.8B, v26.8B, v30.8B uxtl v22.8H, v0.8B and v4.8B, v4.8B, v26.8B uxtl v28.8H, v16.8B @@ -210,6 +414,7 @@ endfunc function ff_h264_v_loop_filter_chroma_neon, export=1 h264_loop_filter_start + sxtw x1, w1 sub x0, x0, x1, lsl #1 ld1 {v18.8B}, [x0], x1 @@ -222,14 +427,16 @@ function ff_h264_v_loop_filter_chroma_neon, export=1 sub x0, x0, x1, lsl #1 st1 {v16.8B}, [x0], x1 st1 {v0.8B}, [x0], x1 - +9: ret endfunc function ff_h264_h_loop_filter_chroma_neon, export=1 h264_loop_filter_start + sxtw x1, w1 sub x0, x0, #2 +h_loop_filter_chroma420: ld1 {v18.S}[0], [x0], x1 ld1 {v16.S}[0], [x0], x1 ld1 {v0.S}[0], [x0], x1 @@ -254,10 +461,134 @@ function ff_h264_h_loop_filter_chroma_neon, export=1 st1 {v16.S}[1], [x0], x1 st1 {v0.S}[1], [x0], x1 st1 {v2.S}[1], [x0], x1 - +9: ret endfunc +function ff_h264_h_loop_filter_chroma422_neon, export=1 + sxtw x1, w1 + h264_loop_filter_start + add x5, x0, x1 + sub x0, x0, #2 + add x1, x1, x1 + mov x7, x30 + bl h_loop_filter_chroma420 + mov x30, x7 + sub x0, x5, #2 + mov v24.s[0], w6 + b h_loop_filter_chroma420 +endfunc + +.macro h264_loop_filter_chroma_intra + uabd v26.8b, v16.8b, v17.8b // abs(p0 - q0) + uabd v27.8b, v18.8b, v16.8b // abs(p1 - p0) + uabd v28.8b, v19.8b, v17.8b // abs(q1 - q0) + cmhi v26.8b, v30.8b, v26.8b // < alpha + cmhi v27.8b, v31.8b, v27.8b // < beta + cmhi v28.8b, v31.8b, v28.8b // < beta + and v26.8b, v26.8b, v27.8b + and v26.8b, v26.8b, v28.8b + mov x2, v26.d[0] + + ushll v4.8h, v18.8b, #1 + ushll v6.8h, v19.8b, #1 + cbz x2, 9f + uaddl v20.8h, v16.8b, v19.8b + uaddl v22.8h, v17.8b, v18.8b + add v20.8h, v20.8h, v4.8h + add v22.8h, v22.8h, v6.8h + uqrshrn v24.8b, v20.8h, #2 + uqrshrn v25.8b, v22.8h, #2 + bit v16.8b, v24.8b, v26.8b + bit v17.8b, v25.8b, v26.8b +.endm + +function ff_h264_v_loop_filter_chroma_intra_neon, export=1 + h264_loop_filter_start_intra + + sub x0, x0, x1, lsl #1 + ld1 {v18.8b}, [x0], x1 + ld1 {v16.8b}, [x0], x1 + ld1 {v17.8b}, [x0], x1 + ld1 {v19.8b}, [x0] + + h264_loop_filter_chroma_intra + + sub x0, x0, x1, lsl #1 + st1 {v16.8b}, [x0], x1 + st1 {v17.8b}, [x0], x1 + +9: + ret +endfunc + +function ff_h264_h_loop_filter_chroma_mbaff_intra_neon, export=1 + h264_loop_filter_start_intra + + sub x4, x0, #2 + sub x0, x0, #1 + ld1 {v18.8b}, [x4], x1 + ld1 {v16.8b}, [x4], x1 + ld1 {v17.8b}, [x4], x1 + ld1 {v19.8b}, [x4], x1 + + transpose_4x8B v18, v16, v17, v19, v26, v27, v28, v29 + + h264_loop_filter_chroma_intra + + st2 {v16.b,v17.b}[0], [x0], x1 + st2 {v16.b,v17.b}[1], [x0], x1 + st2 {v16.b,v17.b}[2], [x0], x1 + st2 {v16.b,v17.b}[3], [x0], x1 + +9: + ret +endfunc + +function ff_h264_h_loop_filter_chroma_intra_neon, export=1 + h264_loop_filter_start_intra + + sub x4, x0, #2 + sub x0, x0, #1 +h_loop_filter_chroma420_intra: + ld1 {v18.8b}, [x4], x1 + ld1 {v16.8b}, [x4], x1 + ld1 {v17.8b}, [x4], x1 + ld1 {v19.8b}, [x4], x1 + ld1 {v18.s}[1], [x4], x1 + ld1 {v16.s}[1], [x4], x1 + ld1 {v17.s}[1], [x4], x1 + ld1 {v19.s}[1], [x4], x1 + + transpose_4x8B v18, v16, v17, v19, v26, v27, v28, v29 + + h264_loop_filter_chroma_intra + + st2 {v16.b,v17.b}[0], [x0], x1 + st2 {v16.b,v17.b}[1], [x0], x1 + st2 {v16.b,v17.b}[2], [x0], x1 + st2 {v16.b,v17.b}[3], [x0], x1 + st2 {v16.b,v17.b}[4], [x0], x1 + st2 {v16.b,v17.b}[5], [x0], x1 + st2 {v16.b,v17.b}[6], [x0], x1 + st2 {v16.b,v17.b}[7], [x0], x1 + +9: + ret +endfunc + +function ff_h264_h_loop_filter_chroma422_intra_neon, export=1 + h264_loop_filter_start_intra + sub x4, x0, #2 + add x5, x0, x1, lsl #3 + sub x0, x0, #1 + mov x7, x30 + bl h_loop_filter_chroma420_intra + sub x0, x5, #1 + mov x30, x7 + b h_loop_filter_chroma420_intra +endfunc + .macro biweight_16 macs, macd dup v0.16B, w5 dup v1.16B, w6 diff --git a/libavcodec/aarch64/h264idct_neon.S b/libavcodec/aarch64/h264idct_neon.S index 825ec49f8..7de44205d 100644 --- a/libavcodec/aarch64/h264idct_neon.S +++ b/libavcodec/aarch64/h264idct_neon.S @@ -23,6 +23,7 @@ #include "neon.S" function ff_h264_idct_add_neon, export=1 +.L_ff_h264_idct_add_neon: ld1 {v0.4H, v1.4H, v2.4H, v3.4H}, [x1] sxtw x2, w2 movi v30.8H, #0 @@ -77,6 +78,7 @@ function ff_h264_idct_add_neon, export=1 endfunc function ff_h264_idct_dc_add_neon, export=1 +.L_ff_h264_idct_dc_add_neon: sxtw x2, w2 mov w3, #0 ld1r {v2.8H}, [x1] @@ -106,8 +108,8 @@ function ff_h264_idct_add16_neon, export=1 mov w9, w3 // stride movrel x7, scan8 mov x10, #16 - movrel x13, X(ff_h264_idct_dc_add_neon) - movrel x14, X(ff_h264_idct_add_neon) + movrel x13, .L_ff_h264_idct_dc_add_neon + movrel x14, .L_ff_h264_idct_add_neon 1: mov w2, w9 ldrb w3, [x7], #1 ldrsw x0, [x5], #4 @@ -133,8 +135,8 @@ function ff_h264_idct_add16intra_neon, export=1 mov w9, w3 // stride movrel x7, scan8 mov x10, #16 - movrel x13, X(ff_h264_idct_dc_add_neon) - movrel x14, X(ff_h264_idct_add_neon) + movrel x13, .L_ff_h264_idct_dc_add_neon + movrel x14, .L_ff_h264_idct_add_neon 1: mov w2, w9 ldrb w3, [x7], #1 ldrsw x0, [x5], #4 @@ -160,8 +162,8 @@ function ff_h264_idct_add8_neon, export=1 add x5, x1, #16*4 // block_offset add x9, x2, #16*32 // block mov w19, w3 // stride - movrel x13, X(ff_h264_idct_dc_add_neon) - movrel x14, X(ff_h264_idct_add_neon) + movrel x13, .L_ff_h264_idct_dc_add_neon + movrel x14, .L_ff_h264_idct_add_neon movrel x7, scan8, 16 mov x10, #0 mov x11, #16 @@ -263,6 +265,7 @@ endfunc .endm function ff_h264_idct8_add_neon, export=1 +.L_ff_h264_idct8_add_neon: movi v19.8H, #0 sxtw x2, w2 ld1 {v24.8H, v25.8H}, [x1] @@ -326,6 +329,7 @@ function ff_h264_idct8_add_neon, export=1 endfunc function ff_h264_idct8_dc_add_neon, export=1 +.L_ff_h264_idct8_dc_add_neon: mov w3, #0 sxtw x2, w2 ld1r {v31.8H}, [x1] @@ -375,8 +379,8 @@ function ff_h264_idct8_add4_neon, export=1 mov w2, w3 movrel x7, scan8 mov w10, #16 - movrel x13, X(ff_h264_idct8_dc_add_neon) - movrel x14, X(ff_h264_idct8_add_neon) + movrel x13, .L_ff_h264_idct8_dc_add_neon + movrel x14, .L_ff_h264_idct8_add_neon 1: ldrb w9, [x7], #4 ldrsw x0, [x5], #16 ldrb w9, [x4, w9, UXTW] diff --git a/libavcodec/aarch64/opusdsp_init.c b/libavcodec/aarch64/opusdsp_init.c new file mode 100644 index 000000000..cc6a1b672 --- /dev/null +++ b/libavcodec/aarch64/opusdsp_init.c @@ -0,0 +1,35 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" + +#include "libavutil/aarch64/cpu.h" +#include "libavcodec/opusdsp.h" + +void ff_opus_postfilter_neon(float *data, int period, float *gains, int len); +float ff_opus_deemphasis_neon(float *out, float *in, float coeff, int len); + +av_cold void ff_opus_dsp_init_aarch64(OpusDSP *ctx) +{ + int cpu_flags = av_get_cpu_flags(); + + if (have_neon(cpu_flags)) { + ctx->postfilter = ff_opus_postfilter_neon; + ctx->deemphasis = ff_opus_deemphasis_neon; + } +} diff --git a/libavcodec/aarch64/opusdsp_neon.S b/libavcodec/aarch64/opusdsp_neon.S new file mode 100644 index 000000000..3d805e2c9 --- /dev/null +++ b/libavcodec/aarch64/opusdsp_neon.S @@ -0,0 +1,113 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/aarch64/asm.S" + + // 0.85..^1 0.85..^2 0.85..^3 0.85..^4 +const tab_st, align=4 + .word 0x3f599a00, 0x3f38f671, 0x3f1d382a, 0x3f05a32f +endconst +const tab_x0, align=4 + .word 0x0, 0x3f599a00, 0x3f38f671, 0x3f1d382a +endconst +const tab_x1, align=4 + .word 0x0, 0x0, 0x3f599a00, 0x3f38f671 +endconst +const tab_x2, align=4 + .word 0x0, 0x0, 0x0, 0x3f599a00 +endconst + +function ff_opus_deemphasis_neon, export=1 + movrel x4, tab_st + ld1 {v4.4s}, [x4] + movrel x4, tab_x0 + ld1 {v5.4s}, [x4] + movrel x4, tab_x1 + ld1 {v6.4s}, [x4] + movrel x4, tab_x2 + ld1 {v7.4s}, [x4] + + fmul v0.4s, v4.4s, v0.s[0] + +1: ld1 {v1.4s, v2.4s}, [x1], #32 + + fmla v0.4s, v5.4s, v1.s[0] + fmul v3.4s, v7.4s, v2.s[2] + + fmla v0.4s, v6.4s, v1.s[1] + fmla v3.4s, v6.4s, v2.s[1] + + fmla v0.4s, v7.4s, v1.s[2] + fmla v3.4s, v5.4s, v2.s[0] + + fadd v1.4s, v1.4s, v0.4s + fadd v2.4s, v2.4s, v3.4s + + fmla v2.4s, v4.4s, v1.s[3] + + st1 {v1.4s, v2.4s}, [x0], #32 + fmul v0.4s, v4.4s, v2.s[3] + + subs w2, w2, #8 + b.gt 1b + + mov s0, v2.s[3] + + ret +endfunc + +function ff_opus_postfilter_neon, export=1 + ld1 {v0.4s}, [x2] + dup v1.4s, v0.s[1] + dup v2.4s, v0.s[2] + dup v0.4s, v0.s[0] + + add w1, w1, #2 + sub x1, x0, x1, lsl #2 + + ld1 {v3.4s}, [x1] + fmul v3.4s, v3.4s, v2.4s + +1: add x1, x1, #4 + ld1 {v4.4s}, [x1] + add x1, x1, #4 + ld1 {v5.4s}, [x1] + add x1, x1, #4 + ld1 {v6.4s}, [x1] + add x1, x1, #4 + ld1 {v7.4s}, [x1] + + fmla v3.4s, v7.4s, v2.4s + fadd v6.4s, v6.4s, v4.4s + + ld1 {v8.4s}, [x0] + fmla v8.4s, v5.4s, v0.4s + + fmul v6.4s, v6.4s, v1.4s + fadd v6.4s, v6.4s, v3.4s + + fadd v8.4s, v8.4s, v6.4s + fmul v3.4s, v7.4s, v2.4s + + st1 {v8.4s}, [x0], #16 + + subs w3, w3, #4 + b.gt 1b + + ret +endfunc diff --git a/libavcodec/aarch64/vp8dsp.h b/libavcodec/aarch64/vp8dsp.h new file mode 100644 index 000000000..871fed7a9 --- /dev/null +++ b/libavcodec/aarch64/vp8dsp.h @@ -0,0 +1,75 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * 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_AARCH64_VP8DSP_H +#define AVCODEC_AARCH64_VP8DSP_H + +#include "libavcodec/vp8dsp.h" + +#define VP8_LF_Y(hv, inner, opt) \ + void ff_vp8_##hv##_loop_filter16##inner##_##opt(uint8_t *dst, \ + ptrdiff_t stride, \ + int flim_E, int flim_I, \ + int hev_thresh) + +#define VP8_LF_UV(hv, inner, opt) \ + void ff_vp8_##hv##_loop_filter8uv##inner##_##opt(uint8_t *dstU, \ + uint8_t *dstV, \ + ptrdiff_t stride, \ + int flim_E, int flim_I, \ + int hev_thresh) + +#define VP8_LF_SIMPLE(hv, opt) \ + void ff_vp8_##hv##_loop_filter16_simple_##opt(uint8_t *dst, \ + ptrdiff_t stride, \ + int flim) + +#define VP8_LF_HV(inner, opt) \ + VP8_LF_Y(h, inner, opt); \ + VP8_LF_Y(v, inner, opt); \ + VP8_LF_UV(h, inner, opt); \ + VP8_LF_UV(v, inner, opt) + +#define VP8_LF(opt) \ + VP8_LF_HV(, opt); \ + VP8_LF_HV(_inner, opt); \ + VP8_LF_SIMPLE(h, opt); \ + VP8_LF_SIMPLE(v, opt) + +#define VP8_MC(n, opt) \ + void ff_put_vp8_##n##_##opt(uint8_t *dst, ptrdiff_t dststride, \ + uint8_t *src, ptrdiff_t srcstride, \ + int h, int x, int y) + +#define VP8_EPEL(w, opt) \ + VP8_MC(pixels ## w, opt); \ + VP8_MC(epel ## w ## _h4, opt); \ + VP8_MC(epel ## w ## _h6, opt); \ + VP8_MC(epel ## w ## _v4, opt); \ + VP8_MC(epel ## w ## _h4v4, opt); \ + VP8_MC(epel ## w ## _h6v4, opt); \ + VP8_MC(epel ## w ## _v6, opt); \ + VP8_MC(epel ## w ## _h4v6, opt); \ + VP8_MC(epel ## w ## _h6v6, opt) + +#define VP8_BILIN(w, opt) \ + VP8_MC(bilin ## w ## _h, opt); \ + VP8_MC(bilin ## w ## _v, opt); \ + VP8_MC(bilin ## w ## _hv, opt) + +#endif /* AVCODEC_AARCH64_VP8DSP_H */ diff --git a/libavcodec/aarch64/vp8dsp_init_aarch64.c b/libavcodec/aarch64/vp8dsp_init_aarch64.c new file mode 100644 index 000000000..fc7e831d1 --- /dev/null +++ b/libavcodec/aarch64/vp8dsp_init_aarch64.c @@ -0,0 +1,124 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include "libavutil/attributes.h" +#include "libavutil/aarch64/cpu.h" +#include "libavcodec/vp8dsp.h" +#include "vp8dsp.h" + +void ff_vp8_luma_dc_wht_neon(int16_t block[4][4][16], int16_t dc[16]); + +void ff_vp8_idct_add_neon(uint8_t *dst, int16_t block[16], ptrdiff_t stride); +void ff_vp8_idct_dc_add_neon(uint8_t *dst, int16_t block[16], ptrdiff_t stride); +void ff_vp8_idct_dc_add4y_neon(uint8_t *dst, int16_t block[4][16], ptrdiff_t stride); +void ff_vp8_idct_dc_add4uv_neon(uint8_t *dst, int16_t block[4][16], ptrdiff_t stride); + +VP8_LF(neon); + +VP8_EPEL(16, neon); +VP8_EPEL(8, neon); +VP8_EPEL(4, neon); + +VP8_BILIN(16, neon); +VP8_BILIN(8, neon); +VP8_BILIN(4, neon); + +av_cold void ff_vp78dsp_init_aarch64(VP8DSPContext *dsp) +{ + if (!have_neon(av_get_cpu_flags())) + return; + dsp->put_vp8_epel_pixels_tab[0][0][0] = ff_put_vp8_pixels16_neon; + dsp->put_vp8_epel_pixels_tab[0][0][2] = ff_put_vp8_epel16_h6_neon; + dsp->put_vp8_epel_pixels_tab[0][2][0] = ff_put_vp8_epel16_v6_neon; + dsp->put_vp8_epel_pixels_tab[0][2][2] = ff_put_vp8_epel16_h6v6_neon; + + dsp->put_vp8_epel_pixels_tab[1][0][0] = ff_put_vp8_pixels8_neon; + dsp->put_vp8_epel_pixels_tab[1][0][1] = ff_put_vp8_epel8_h4_neon; + dsp->put_vp8_epel_pixels_tab[1][0][2] = ff_put_vp8_epel8_h6_neon; + dsp->put_vp8_epel_pixels_tab[1][1][0] = ff_put_vp8_epel8_v4_neon; + dsp->put_vp8_epel_pixels_tab[1][1][1] = ff_put_vp8_epel8_h4v4_neon; + dsp->put_vp8_epel_pixels_tab[1][1][2] = ff_put_vp8_epel8_h6v4_neon; + dsp->put_vp8_epel_pixels_tab[1][2][0] = ff_put_vp8_epel8_v6_neon; + dsp->put_vp8_epel_pixels_tab[1][2][1] = ff_put_vp8_epel8_h4v6_neon; + dsp->put_vp8_epel_pixels_tab[1][2][2] = ff_put_vp8_epel8_h6v6_neon; + + dsp->put_vp8_epel_pixels_tab[2][0][1] = ff_put_vp8_epel4_h4_neon; + dsp->put_vp8_epel_pixels_tab[2][0][2] = ff_put_vp8_epel4_h6_neon; + dsp->put_vp8_epel_pixels_tab[2][1][0] = ff_put_vp8_epel4_v4_neon; + dsp->put_vp8_epel_pixels_tab[2][1][1] = ff_put_vp8_epel4_h4v4_neon; + dsp->put_vp8_epel_pixels_tab[2][1][2] = ff_put_vp8_epel4_h6v4_neon; + dsp->put_vp8_epel_pixels_tab[2][2][0] = ff_put_vp8_epel4_v6_neon; + dsp->put_vp8_epel_pixels_tab[2][2][1] = ff_put_vp8_epel4_h4v6_neon; + dsp->put_vp8_epel_pixels_tab[2][2][2] = ff_put_vp8_epel4_h6v6_neon; + + dsp->put_vp8_bilinear_pixels_tab[0][0][0] = ff_put_vp8_pixels16_neon; + dsp->put_vp8_bilinear_pixels_tab[0][0][1] = ff_put_vp8_bilin16_h_neon; + dsp->put_vp8_bilinear_pixels_tab[0][0][2] = ff_put_vp8_bilin16_h_neon; + dsp->put_vp8_bilinear_pixels_tab[0][1][0] = ff_put_vp8_bilin16_v_neon; + dsp->put_vp8_bilinear_pixels_tab[0][1][1] = ff_put_vp8_bilin16_hv_neon; + dsp->put_vp8_bilinear_pixels_tab[0][1][2] = ff_put_vp8_bilin16_hv_neon; + dsp->put_vp8_bilinear_pixels_tab[0][2][0] = ff_put_vp8_bilin16_v_neon; + dsp->put_vp8_bilinear_pixels_tab[0][2][1] = ff_put_vp8_bilin16_hv_neon; + dsp->put_vp8_bilinear_pixels_tab[0][2][2] = ff_put_vp8_bilin16_hv_neon; + + dsp->put_vp8_bilinear_pixels_tab[1][0][0] = ff_put_vp8_pixels8_neon; + dsp->put_vp8_bilinear_pixels_tab[1][0][1] = ff_put_vp8_bilin8_h_neon; + dsp->put_vp8_bilinear_pixels_tab[1][0][2] = ff_put_vp8_bilin8_h_neon; + dsp->put_vp8_bilinear_pixels_tab[1][1][0] = ff_put_vp8_bilin8_v_neon; + dsp->put_vp8_bilinear_pixels_tab[1][1][1] = ff_put_vp8_bilin8_hv_neon; + dsp->put_vp8_bilinear_pixels_tab[1][1][2] = ff_put_vp8_bilin8_hv_neon; + dsp->put_vp8_bilinear_pixels_tab[1][2][0] = ff_put_vp8_bilin8_v_neon; + dsp->put_vp8_bilinear_pixels_tab[1][2][1] = ff_put_vp8_bilin8_hv_neon; + dsp->put_vp8_bilinear_pixels_tab[1][2][2] = ff_put_vp8_bilin8_hv_neon; + + dsp->put_vp8_bilinear_pixels_tab[2][0][1] = ff_put_vp8_bilin4_h_neon; + dsp->put_vp8_bilinear_pixels_tab[2][0][2] = ff_put_vp8_bilin4_h_neon; + dsp->put_vp8_bilinear_pixels_tab[2][1][0] = ff_put_vp8_bilin4_v_neon; + dsp->put_vp8_bilinear_pixels_tab[2][1][1] = ff_put_vp8_bilin4_hv_neon; + dsp->put_vp8_bilinear_pixels_tab[2][1][2] = ff_put_vp8_bilin4_hv_neon; + dsp->put_vp8_bilinear_pixels_tab[2][2][0] = ff_put_vp8_bilin4_v_neon; + dsp->put_vp8_bilinear_pixels_tab[2][2][1] = ff_put_vp8_bilin4_hv_neon; + dsp->put_vp8_bilinear_pixels_tab[2][2][2] = ff_put_vp8_bilin4_hv_neon; +} + +av_cold void ff_vp8dsp_init_aarch64(VP8DSPContext *dsp) +{ + if (!have_neon(av_get_cpu_flags())) + return; + dsp->vp8_luma_dc_wht = ff_vp8_luma_dc_wht_neon; + + dsp->vp8_idct_add = ff_vp8_idct_add_neon; + dsp->vp8_idct_dc_add = ff_vp8_idct_dc_add_neon; + dsp->vp8_idct_dc_add4y = ff_vp8_idct_dc_add4y_neon; + dsp->vp8_idct_dc_add4uv = ff_vp8_idct_dc_add4uv_neon; + + dsp->vp8_v_loop_filter16y = ff_vp8_v_loop_filter16_neon; + dsp->vp8_h_loop_filter16y = ff_vp8_h_loop_filter16_neon; + dsp->vp8_v_loop_filter8uv = ff_vp8_v_loop_filter8uv_neon; + dsp->vp8_h_loop_filter8uv = ff_vp8_h_loop_filter8uv_neon; + + dsp->vp8_v_loop_filter16y_inner = ff_vp8_v_loop_filter16_inner_neon; + dsp->vp8_h_loop_filter16y_inner = ff_vp8_h_loop_filter16_inner_neon; + dsp->vp8_v_loop_filter8uv_inner = ff_vp8_v_loop_filter8uv_inner_neon; + dsp->vp8_h_loop_filter8uv_inner = ff_vp8_h_loop_filter8uv_inner_neon; + + dsp->vp8_v_loop_filter_simple = ff_vp8_v_loop_filter16_simple_neon; + dsp->vp8_h_loop_filter_simple = ff_vp8_h_loop_filter16_simple_neon; +} diff --git a/libavcodec/aarch64/vp8dsp_neon.S b/libavcodec/aarch64/vp8dsp_neon.S new file mode 100644 index 000000000..4bbf16d1a --- /dev/null +++ b/libavcodec/aarch64/vp8dsp_neon.S @@ -0,0 +1,1790 @@ +/* + * VP8 NEON optimisations + * + * Copyright (c) 2010 Rob Clark + * Copyright (c) 2011 Mans Rullgard + * Copyright (c) 2018 Magnus Röös + * Copyright (c) 2019 Martin Storsjo + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/aarch64/asm.S" +#include "neon.S" + +function ff_vp8_luma_dc_wht_neon, export=1 + ld1 {v0.4h - v3.4h}, [x1] + movi v30.8h, #0 + + add v4.4h, v0.4h, v3.4h + add v6.4h, v1.4h, v2.4h + st1 {v30.8h}, [x1], #16 + sub v7.4h, v1.4h, v2.4h + sub v5.4h, v0.4h, v3.4h + st1 {v30.8h}, [x1] + add v0.4h, v4.4h, v6.4h + add v1.4h, v5.4h, v7.4h + sub v2.4h, v4.4h, v6.4h + sub v3.4h, v5.4h, v7.4h + + movi v16.4h, #3 + + transpose_4x4H v0, v1, v2, v3, v4, v5, v6, v7 + + add v0.4h, v0.4h, v16.4h + + add v4.4h, v0.4h, v3.4h + add v6.4h, v1.4h, v2.4h + sub v7.4h, v1.4h, v2.4h + sub v5.4h, v0.4h, v3.4h + add v0.4h, v4.4h, v6.4h + add v1.4h, v5.4h, v7.4h + sub v2.4h, v4.4h, v6.4h + sub v3.4h, v5.4h, v7.4h + + sshr v0.4h, v0.4h, #3 + sshr v1.4h, v1.4h, #3 + sshr v2.4h, v2.4h, #3 + sshr v3.4h, v3.4h, #3 + + mov x3, #32 + st1 {v0.h}[0], [x0], x3 + st1 {v1.h}[0], [x0], x3 + st1 {v2.h}[0], [x0], x3 + st1 {v3.h}[0], [x0], x3 + st1 {v0.h}[1], [x0], x3 + st1 {v1.h}[1], [x0], x3 + st1 {v2.h}[1], [x0], x3 + st1 {v3.h}[1], [x0], x3 + st1 {v0.h}[2], [x0], x3 + st1 {v1.h}[2], [x0], x3 + st1 {v2.h}[2], [x0], x3 + st1 {v3.h}[2], [x0], x3 + st1 {v0.h}[3], [x0], x3 + st1 {v1.h}[3], [x0], x3 + st1 {v2.h}[3], [x0], x3 + st1 {v3.h}[3], [x0], x3 + + ret +endfunc + +function ff_vp8_idct_add_neon, export=1 + ld1 {v0.8b - v3.8b}, [x1] + mov w4, #20091 + movk w4, #35468/2, lsl #16 + dup v4.2s, w4 + + smull v26.4s, v1.4h, v4.h[0] + smull v27.4s, v3.4h, v4.h[0] + sqdmulh v20.4h, v1.4h, v4.h[1] + sqdmulh v23.4h, v3.4h, v4.h[1] + shrn v21.4h, v26.4s, #16 + shrn v22.4h, v27.4s, #16 + add v21.4h, v21.4h, v1.4h + add v22.4h, v22.4h, v3.4h + + add v16.4h, v0.4h, v2.4h + sub v17.4h, v0.4h, v2.4h + + add v18.4h, v21.4h, v23.4h + sub v19.4h, v20.4h, v22.4h + + add v0.4h, v16.4h, v18.4h + add v1.4h, v17.4h, v19.4h + sub v3.4h, v16.4h, v18.4h + sub v2.4h, v17.4h, v19.4h + + transpose_4x4H v0, v1, v2, v3, v24, v5, v6, v7 + + movi v29.8h, #0 + smull v26.4s, v1.4h, v4.h[0] + st1 {v29.8h}, [x1], #16 + smull v27.4s, v3.4h, v4.h[0] + st1 {v29.16b}, [x1] + sqdmulh v21.4h, v1.4h, v4.h[1] + sqdmulh v23.4h, v3.4h, v4.h[1] + shrn v20.4h, v26.4s, #16 + shrn v22.4h, v27.4s, #16 + add v20.4h, v20.4h, v1.4h + add v22.4h, v22.4h, v3.4h + add v16.4h, v0.4h, v2.4h + sub v17.4h, v0.4h, v2.4h + + add v18.4h, v20.4h, v23.4h + ld1 {v24.s}[0], [x0], x2 + sub v19.4h, v21.4h, v22.4h + ld1 {v25.s}[0], [x0], x2 + add v0.4h, v16.4h, v18.4h + add v1.4h, v17.4h, v19.4h + ld1 {v26.s}[0], [x0], x2 + sub v3.4h, v16.4h, v18.4h + sub v2.4h, v17.4h, v19.4h + ld1 {v27.s}[0], [x0], x2 + srshr v0.4h, v0.4h, #3 + srshr v1.4h, v1.4h, #3 + srshr v2.4h, v2.4h, #3 + srshr v3.4h, v3.4h, #3 + + sub x0, x0, x2, lsl #2 + + transpose_4x4H v0, v1, v2, v3, v5, v6, v7, v16 + + uaddw v0.8h, v0.8h, v24.8b + uaddw v1.8h, v1.8h, v25.8b + uaddw v2.8h, v2.8h, v26.8b + uaddw v3.8h, v3.8h, v27.8b + sqxtun v0.8b, v0.8h + sqxtun v1.8b, v1.8h + sqxtun v2.8b, v2.8h + sqxtun v3.8b, v3.8h + + st1 {v0.s}[0], [x0], x2 + st1 {v1.s}[0], [x0], x2 + st1 {v2.s}[0], [x0], x2 + st1 {v3.s}[0], [x0], x2 + + ret +endfunc + +function ff_vp8_idct_dc_add4uv_neon, export=1 + movi v0.4h, #0 + mov x3, #32 + ld1r {v16.4h}, [x1] + st1 {v0.h}[0], [x1], x3 + ld1r {v17.4h}, [x1] + st1 {v0.h}[0], [x1], x3 + ld1r {v18.4h}, [x1] + st1 {v0.h}[0], [x1], x3 + ld1r {v19.4h}, [x1] + st1 {v0.h}[0], [x1], x3 + ins v16.d[1], v17.d[0] + ins v18.d[1], v19.d[0] + mov x3, x0 + srshr v16.8h, v16.8h, #3 // dc >>= 3 + ld1 {v0.8b}, [x0], x2 + srshr v18.8h, v18.8h, #3 + ld1 {v1.8b}, [x0], x2 + uaddw v20.8h, v16.8h, v0.8b + ld1 {v2.8b}, [x0], x2 + uaddw v0.8h, v16.8h, v1.8b + ld1 {v3.8b}, [x0], x2 + uaddw v22.8h, v16.8h, v2.8b + ld1 {v4.8b}, [x0], x2 + uaddw v2.8h, v16.8h, v3.8b + ld1 {v5.8b}, [x0], x2 + uaddw v24.8h, v18.8h, v4.8b + ld1 {v6.8b}, [x0], x2 + uaddw v4.8h, v18.8h, v5.8b + ld1 {v7.8b}, [x0], x2 + uaddw v26.8h, v18.8h, v6.8b + sqxtun v20.8b, v20.8h + uaddw v6.8h, v18.8h, v7.8b + sqxtun v21.8b, v0.8h + sqxtun v22.8b, v22.8h + st1 {v20.8b}, [x3], x2 + sqxtun v23.8b, v2.8h + st1 {v21.8b}, [x3], x2 + sqxtun v24.8b, v24.8h + st1 {v22.8b}, [x3], x2 + sqxtun v25.8b, v4.8h + st1 {v23.8b}, [x3], x2 + sqxtun v26.8b, v26.8h + st1 {v24.8b}, [x3], x2 + sqxtun v27.8b, v6.8h + st1 {v25.8b}, [x3], x2 + st1 {v26.8b}, [x3], x2 + st1 {v27.8b}, [x3], x2 + + ret +endfunc + +function ff_vp8_idct_dc_add4y_neon, export=1 + movi v0.16b, #0 + mov x3, #32 + ld1r {v16.4h}, [x1] + st1 {v0.h}[0], [x1], x3 + ld1r {v17.4h}, [x1] + st1 {v0.h}[0], [x1], x3 + zip1 v16.2d, v16.2d, v17.2d + ld1r {v18.4h}, [x1] + st1 {v0.h}[0], [x1], x3 + ld1r {v19.4h}, [x1] + st1 {v0.h}[0], [x1], x3 + zip1 v18.2d, v18.2d, v19.2d + srshr v16.8h, v16.8h, #3 // dc >>= 3 + ld1 {v0.16b}, [x0], x2 + srshr v18.8h, v18.8h, #3 + ld1 {v1.16b}, [x0], x2 + uaddw v20.8h, v16.8h, v0.8b + ld1 {v2.16b}, [x0], x2 + uaddw2 v0.8h, v18.8h, v0.16b + ld1 {v3.16b}, [x0], x2 + uaddw v21.8h, v16.8h, v1.8b + uaddw2 v1.8h, v18.8h, v1.16b + uaddw v22.8h, v16.8h, v2.8b + uaddw2 v2.8h, v18.8h, v2.16b + uaddw v23.8h, v16.8h, v3.8b + uaddw2 v3.8h, v18.8h, v3.16b + sub x0, x0, x2, lsl #2 + sqxtun v20.8b, v20.8h + sqxtun2 v20.16b, v0.8h + sqxtun v21.8b, v21.8h + sqxtun2 v21.16b, v1.8h + sqxtun v22.8b, v22.8h + st1 {v20.16b}, [x0], x2 + sqxtun2 v22.16b, v2.8h + st1 {v21.16b}, [x0], x2 + sqxtun v23.8b, v23.8h + st1 {v22.16b}, [x0], x2 + sqxtun2 v23.16b, v3.8h + st1 {v23.16b}, [x0], x2 + + ret +endfunc + +function ff_vp8_idct_dc_add_neon, export=1 + mov w3, #0 + ld1r {v2.8h}, [x1] + strh w3, [x1] + srshr v2.8h, v2.8h, #3 + ld1 {v0.s}[0], [x0], x2 + ld1 {v0.s}[1], [x0], x2 + uaddw v3.8h, v2.8h, v0.8b + ld1 {v1.s}[0], [x0], x2 + ld1 {v1.s}[1], [x0], x2 + uaddw v4.8h, v2.8h, v1.8b + sqxtun v0.8b, v3.8h + sqxtun v1.8b, v4.8h + sub x0, x0, x2, lsl #2 + st1 {v0.s}[0], [x0], x2 + st1 {v0.s}[1], [x0], x2 + st1 {v1.s}[0], [x0], x2 + st1 {v1.s}[1], [x0], x2 + ret +endfunc + +// Register layout: +// P3..Q3 -> v0..v7 +// flim_E -> v22 +// flim_I -> v23 +// hev_thresh -> x5 +// +.macro vp8_loop_filter, inner=0, simple=0, hev_thresh + .if \simple + uabd v17.16b, v3.16b, v4.16b // abs(P0-Q0) + uabd v23.16b, v2.16b, v5.16b // abs(P1-Q1) + uqadd v17.16b, v17.16b, v17.16b // abs(P0-Q0) * 2 + ushr v18.16b, v23.16b, #1 // abs(P1-Q1) / 2 + uqadd v19.16b, v17.16b, v18.16b // (abs(P0-Q0)*2) + (abs(P1-Q1)/2) + movi v21.16b, #0x80 + cmhs v16.16b, v22.16b, v19.16b // (abs(P0-Q0)*2) + (abs(P1-Q1)/2) <= flim + .else + // calculate hev and normal_limit: + uabd v20.16b, v2.16b, v3.16b // abs(P1-P0) + uabd v21.16b, v5.16b, v4.16b // abs(Q1-Q0) + uabd v18.16b, v0.16b, v1.16b // abs(P3-P2) + uabd v19.16b, v1.16b, v2.16b // abs(P2-P1) + cmhs v16.16b, v23.16b, v20.16b // abs(P1-P0) <= flim_I + cmhs v17.16b, v23.16b, v21.16b // abs(Q1-Q0) <= flim_I + cmhs v18.16b, v23.16b, v18.16b // abs(P3-P2) <= flim_I + cmhs v19.16b, v23.16b, v19.16b // abs(P2-P1) <= flim_I + and v16.16b, v17.16b, v16.16b + uabd v17.16b, v7.16b, v6.16b // abs(Q3-Q2) + and v16.16b, v16.16b, v19.16b + uabd v19.16b, v6.16b, v5.16b // abs(Q2-Q1) + and v16.16b, v16.16b, v18.16b + cmhs v18.16b, v23.16b, v17.16b // abs(Q3-Q2) <= flim_I + cmhs v19.16b, v23.16b, v19.16b // abs(Q2-Q1) <= flim_I + uabd v17.16b, v3.16b, v4.16b // abs(P0-Q0) + uabd v23.16b, v2.16b, v5.16b // abs(P1-Q1) + and v16.16b, v16.16b, v18.16b + uqadd v17.16b, v17.16b, v17.16b // abs(P0-Q0) * 2 + and v16.16b, v16.16b, v19.16b + ushr v18.16b, v23.16b, #1 // abs(P1-Q1) / 2 + dup v23.16b, \hev_thresh // hev_thresh + uqadd v19.16b, v17.16b, v18.16b // (abs(P0-Q0)*2) + (abs(P1-Q1)/2) + cmhi v20.16b, v20.16b, v23.16b // abs(P1-P0) > hev_thresh + cmhs v19.16b, v22.16b, v19.16b // (abs(P0-Q0)*2) + (abs(P1-Q1)/2) <= flim_E + cmhi v22.16b, v21.16b, v23.16b // abs(Q1-Q0) > hev_thresh + and v16.16b, v16.16b, v19.16b + movi v21.16b, #0x80 + orr v17.16b, v20.16b, v22.16b + .endif + + // at this point: + // v16: normal_limit + // v17: hev + + // convert to signed value: + eor v3.16b, v3.16b, v21.16b // PS0 = P0 ^ 0x80 + eor v4.16b, v4.16b, v21.16b // QS0 = Q0 ^ 0x80 + + movi v20.8h, #3 + ssubl v18.8h, v4.8b, v3.8b // QS0 - PS0 + ssubl2 v19.8h, v4.16b, v3.16b // (widened to 16bit) + eor v2.16b, v2.16b, v21.16b // PS1 = P1 ^ 0x80 + eor v5.16b, v5.16b, v21.16b // QS1 = Q1 ^ 0x80 + mul v18.8h, v18.8h, v20.8h // w = 3 * (QS0 - PS0) + mul v19.8h, v19.8h, v20.8h + + sqsub v20.16b, v2.16b, v5.16b // clamp(PS1-QS1) + movi v22.16b, #4 + movi v23.16b, #3 + .if \inner + and v20.16b, v20.16b, v17.16b // if(hev) w += clamp(PS1-QS1) + .endif + saddw v18.8h, v18.8h, v20.8b // w += clamp(PS1-QS1) + saddw2 v19.8h, v19.8h, v20.16b + sqxtn v18.8b, v18.8h // narrow result back into v18 + sqxtn2 v18.16b, v19.8h + .if !\inner && !\simple + eor v1.16b, v1.16b, v21.16b // PS2 = P2 ^ 0x80 + eor v6.16b, v6.16b, v21.16b // QS2 = Q2 ^ 0x80 + .endif + and v18.16b, v18.16b, v16.16b // w &= normal_limit + + // registers used at this point.. + // v0 -> P3 (don't corrupt) + // v1-v6 -> PS2-QS2 + // v7 -> Q3 (don't corrupt) + // v17 -> hev + // v18 -> w + // v21 -> #0x80 + // v22 -> #4 + // v23 -> #3 + // v16, v19, v29 -> unused + // + // filter_common: is4tap==1 + // c1 = clamp(w + 4) >> 3; + // c2 = clamp(w + 3) >> 3; + // Q0 = s2u(QS0 - c1); + // P0 = s2u(PS0 + c2); + + .if \simple + sqadd v19.16b, v18.16b, v22.16b // c1 = clamp((w&hev)+4) + sqadd v20.16b, v18.16b, v23.16b // c2 = clamp((w&hev)+3) + sshr v19.16b, v19.16b, #3 // c1 >>= 3 + sshr v20.16b, v20.16b, #3 // c2 >>= 3 + sqsub v4.16b, v4.16b, v19.16b // QS0 = clamp(QS0-c1) + sqadd v3.16b, v3.16b, v20.16b // PS0 = clamp(PS0+c2) + eor v4.16b, v4.16b, v21.16b // Q0 = QS0 ^ 0x80 + eor v3.16b, v3.16b, v21.16b // P0 = PS0 ^ 0x80 + eor v5.16b, v5.16b, v21.16b // Q1 = QS1 ^ 0x80 + eor v2.16b, v2.16b, v21.16b // P1 = PS1 ^ 0x80 + .elseif \inner + // the !is4tap case of filter_common, only used for inner blocks + // c3 = ((c1&~hev) + 1) >> 1; + // Q1 = s2u(QS1 - c3); + // P1 = s2u(PS1 + c3); + sqadd v19.16b, v18.16b, v22.16b // c1 = clamp((w&hev)+4) + sqadd v20.16b, v18.16b, v23.16b // c2 = clamp((w&hev)+3) + sshr v19.16b, v19.16b, #3 // c1 >>= 3 + sshr v20.16b, v20.16b, #3 // c2 >>= 3 + sqsub v4.16b, v4.16b, v19.16b // QS0 = clamp(QS0-c1) + sqadd v3.16b, v3.16b, v20.16b // PS0 = clamp(PS0+c2) + bic v19.16b, v19.16b, v17.16b // c1 & ~hev + eor v4.16b, v4.16b, v21.16b // Q0 = QS0 ^ 0x80 + srshr v19.16b, v19.16b, #1 // c3 >>= 1 + eor v3.16b, v3.16b, v21.16b // P0 = PS0 ^ 0x80 + sqsub v5.16b, v5.16b, v19.16b // QS1 = clamp(QS1-c3) + sqadd v2.16b, v2.16b, v19.16b // PS1 = clamp(PS1+c3) + eor v5.16b, v5.16b, v21.16b // Q1 = QS1 ^ 0x80 + eor v2.16b, v2.16b, v21.16b // P1 = PS1 ^ 0x80 + .else + and v20.16b, v18.16b, v17.16b // w & hev + sqadd v19.16b, v20.16b, v22.16b // c1 = clamp((w&hev)+4) + sqadd v20.16b, v20.16b, v23.16b // c2 = clamp((w&hev)+3) + sshr v19.16b, v19.16b, #3 // c1 >>= 3 + sshr v20.16b, v20.16b, #3 // c2 >>= 3 + bic v18.16b, v18.16b, v17.16b // w &= ~hev + sqsub v4.16b, v4.16b, v19.16b // QS0 = clamp(QS0-c1) + sqadd v3.16b, v3.16b, v20.16b // PS0 = clamp(PS0+c2) + + // filter_mbedge: + // a = clamp((27*w + 63) >> 7); + // Q0 = s2u(QS0 - a); + // P0 = s2u(PS0 + a); + // a = clamp((18*w + 63) >> 7); + // Q1 = s2u(QS1 - a); + // P1 = s2u(PS1 + a); + // a = clamp((9*w + 63) >> 7); + // Q2 = s2u(QS2 - a); + // P2 = s2u(PS2 + a); + movi v17.8h, #63 + sshll v22.8h, v18.8b, #3 + sshll2 v23.8h, v18.16b, #3 + saddw v22.8h, v22.8h, v18.8b + saddw2 v23.8h, v23.8h, v18.16b + add v16.8h, v17.8h, v22.8h + add v17.8h, v17.8h, v23.8h // 9*w + 63 + add v19.8h, v16.8h, v22.8h + add v20.8h, v17.8h, v23.8h // 18*w + 63 + add v22.8h, v19.8h, v22.8h + add v23.8h, v20.8h, v23.8h // 27*w + 63 + sqshrn v16.8b, v16.8h, #7 + sqshrn2 v16.16b, v17.8h, #7 // clamp(( 9*w + 63)>>7) + sqshrn v19.8b, v19.8h, #7 + sqshrn2 v19.16b, v20.8h, #7 // clamp((18*w + 63)>>7) + sqshrn v22.8b, v22.8h, #7 + sqshrn2 v22.16b, v23.8h, #7 // clamp((27*w + 63)>>7) + sqadd v1.16b, v1.16b, v16.16b // PS2 = clamp(PS2+a) + sqsub v6.16b, v6.16b, v16.16b // QS2 = clamp(QS2-a) + sqadd v2.16b, v2.16b, v19.16b // PS1 = clamp(PS1+a) + sqsub v5.16b, v5.16b, v19.16b // QS1 = clamp(QS1-a) + sqadd v3.16b, v3.16b, v22.16b // PS0 = clamp(PS0+a) + sqsub v4.16b, v4.16b, v22.16b // QS0 = clamp(QS0-a) + eor v3.16b, v3.16b, v21.16b // P0 = PS0 ^ 0x80 + eor v4.16b, v4.16b, v21.16b // Q0 = QS0 ^ 0x80 + eor v2.16b, v2.16b, v21.16b // P1 = PS1 ^ 0x80 + eor v5.16b, v5.16b, v21.16b // Q1 = QS1 ^ 0x80 + eor v1.16b, v1.16b, v21.16b // P2 = PS2 ^ 0x80 + eor v6.16b, v6.16b, v21.16b // Q2 = QS2 ^ 0x80 + .endif +.endm + +.macro vp8_v_loop_filter16 name, inner=0, simple=0 +function ff_vp8_v_loop_filter16\name\()_neon, export=1 + sub x0, x0, x1, lsl #1+!\simple + + // Load pixels: + .if !\simple + ld1 {v0.16b}, [x0], x1 // P3 + ld1 {v1.16b}, [x0], x1 // P2 + .endif + ld1 {v2.16b}, [x0], x1 // P1 + ld1 {v3.16b}, [x0], x1 // P0 + ld1 {v4.16b}, [x0], x1 // Q0 + ld1 {v5.16b}, [x0], x1 // Q1 + .if !\simple + ld1 {v6.16b}, [x0], x1 // Q2 + ld1 {v7.16b}, [x0] // Q3 + dup v23.16b, w3 // flim_I + .endif + dup v22.16b, w2 // flim_E + + vp8_loop_filter inner=\inner, simple=\simple, hev_thresh=w4 + + // back up to P2: dst -= stride * 6 + sub x0, x0, x1, lsl #2 + .if !\simple + sub x0, x0, x1, lsl #1 + + // Store pixels: + st1 {v1.16b}, [x0], x1 // P2 + .endif + st1 {v2.16b}, [x0], x1 // P1 + st1 {v3.16b}, [x0], x1 // P0 + st1 {v4.16b}, [x0], x1 // Q0 + st1 {v5.16b}, [x0], x1 // Q1 + .if !\simple + st1 {v6.16b}, [x0] // Q2 + .endif + + ret +endfunc +.endm + +vp8_v_loop_filter16 +vp8_v_loop_filter16 _inner, inner=1 +vp8_v_loop_filter16 _simple, simple=1 + +.macro vp8_v_loop_filter8uv name, inner=0 +function ff_vp8_v_loop_filter8uv\name\()_neon, export=1 + sub x0, x0, x2, lsl #2 + sub x1, x1, x2, lsl #2 + // Load pixels: + ld1 {v0.d}[0], [x0], x2 // P3 + ld1 {v0.d}[1], [x1], x2 // P3 + ld1 {v1.d}[0], [x0], x2 // P2 + ld1 {v1.d}[1], [x1], x2 // P2 + ld1 {v2.d}[0], [x0], x2 // P1 + ld1 {v2.d}[1], [x1], x2 // P1 + ld1 {v3.d}[0], [x0], x2 // P0 + ld1 {v3.d}[1], [x1], x2 // P0 + ld1 {v4.d}[0], [x0], x2 // Q0 + ld1 {v4.d}[1], [x1], x2 // Q0 + ld1 {v5.d}[0], [x0], x2 // Q1 + ld1 {v5.d}[1], [x1], x2 // Q1 + ld1 {v6.d}[0], [x0], x2 // Q2 + ld1 {v6.d}[1], [x1], x2 // Q2 + ld1 {v7.d}[0], [x0] // Q3 + ld1 {v7.d}[1], [x1] // Q3 + + dup v22.16b, w3 // flim_E + dup v23.16b, w4 // flim_I + + vp8_loop_filter inner=\inner, hev_thresh=w5 + + // back up to P2: u,v -= stride * 6 + sub x0, x0, x2, lsl #2 + sub x1, x1, x2, lsl #2 + sub x0, x0, x2, lsl #1 + sub x1, x1, x2, lsl #1 + + // Store pixels: + + st1 {v1.d}[0], [x0], x2 // P2 + st1 {v1.d}[1], [x1], x2 // P2 + st1 {v2.d}[0], [x0], x2 // P1 + st1 {v2.d}[1], [x1], x2 // P1 + st1 {v3.d}[0], [x0], x2 // P0 + st1 {v3.d}[1], [x1], x2 // P0 + st1 {v4.d}[0], [x0], x2 // Q0 + st1 {v4.d}[1], [x1], x2 // Q0 + st1 {v5.d}[0], [x0], x2 // Q1 + st1 {v5.d}[1], [x1], x2 // Q1 + st1 {v6.d}[0], [x0] // Q2 + st1 {v6.d}[1], [x1] // Q2 + + ret +endfunc +.endm + +vp8_v_loop_filter8uv +vp8_v_loop_filter8uv _inner, inner=1 + +.macro vp8_h_loop_filter16 name, inner=0, simple=0 +function ff_vp8_h_loop_filter16\name\()_neon, export=1 + + sub x0, x0, #4 + // Load pixels: + ld1 {v0.d}[0], [x0], x1 + ld1 {v1.d}[0], [x0], x1 + ld1 {v2.d}[0], [x0], x1 + ld1 {v3.d}[0], [x0], x1 + ld1 {v4.d}[0], [x0], x1 + ld1 {v5.d}[0], [x0], x1 + ld1 {v6.d}[0], [x0], x1 + ld1 {v7.d}[0], [x0], x1 + ld1 {v0.d}[1], [x0], x1 + ld1 {v1.d}[1], [x0], x1 + ld1 {v2.d}[1], [x0], x1 + ld1 {v3.d}[1], [x0], x1 + ld1 {v4.d}[1], [x0], x1 + ld1 {v5.d}[1], [x0], x1 + ld1 {v6.d}[1], [x0], x1 + ld1 {v7.d}[1], [x0], x1 + + transpose_8x16B v0, v1, v2, v3, v4, v5, v6, v7, v30, v31 + + dup v22.16b, w2 // flim_E + .if !\simple + dup v23.16b, w3 // flim_I + .endif + + vp8_loop_filter inner=\inner, simple=\simple, hev_thresh=w4 + + sub x0, x0, x1, lsl #4 // backup 16 rows + + transpose_8x16B v0, v1, v2, v3, v4, v5, v6, v7, v30, v31 + + // Store pixels: + st1 {v0.d}[0], [x0], x1 + st1 {v1.d}[0], [x0], x1 + st1 {v2.d}[0], [x0], x1 + st1 {v3.d}[0], [x0], x1 + st1 {v4.d}[0], [x0], x1 + st1 {v5.d}[0], [x0], x1 + st1 {v6.d}[0], [x0], x1 + st1 {v7.d}[0], [x0], x1 + st1 {v0.d}[1], [x0], x1 + st1 {v1.d}[1], [x0], x1 + st1 {v2.d}[1], [x0], x1 + st1 {v3.d}[1], [x0], x1 + st1 {v4.d}[1], [x0], x1 + st1 {v5.d}[1], [x0], x1 + st1 {v6.d}[1], [x0], x1 + st1 {v7.d}[1], [x0] + + ret +endfunc +.endm + +vp8_h_loop_filter16 +vp8_h_loop_filter16 _inner, inner=1 +vp8_h_loop_filter16 _simple, simple=1 + +.macro vp8_h_loop_filter8uv name, inner=0 +function ff_vp8_h_loop_filter8uv\name\()_neon, export=1 + sub x0, x0, #4 + sub x1, x1, #4 + + // Load pixels: + ld1 {v0.d}[0], [x0], x2 // load u + ld1 {v0.d}[1], [x1], x2 // load v + ld1 {v1.d}[0], [x0], x2 + ld1 {v1.d}[1], [x1], x2 + ld1 {v2.d}[0], [x0], x2 + ld1 {v2.d}[1], [x1], x2 + ld1 {v3.d}[0], [x0], x2 + ld1 {v3.d}[1], [x1], x2 + ld1 {v4.d}[0], [x0], x2 + ld1 {v4.d}[1], [x1], x2 + ld1 {v5.d}[0], [x0], x2 + ld1 {v5.d}[1], [x1], x2 + ld1 {v6.d}[0], [x0], x2 + ld1 {v6.d}[1], [x1], x2 + ld1 {v7.d}[0], [x0], x2 + ld1 {v7.d}[1], [x1], x2 + + transpose_8x16B v0, v1, v2, v3, v4, v5, v6, v7, v30, v31 + + dup v22.16b, w3 // flim_E + dup v23.16b, w4 // flim_I + + vp8_loop_filter inner=\inner, hev_thresh=w5 + + sub x0, x0, x2, lsl #3 // backup u 8 rows + sub x1, x1, x2, lsl #3 // backup v 8 rows + + transpose_8x16B v0, v1, v2, v3, v4, v5, v6, v7, v30, v31 + + // Store pixels: + st1 {v0.d}[0], [x0], x2 // load u + st1 {v0.d}[1], [x1], x2 // load v + st1 {v1.d}[0], [x0], x2 + st1 {v1.d}[1], [x1], x2 + st1 {v2.d}[0], [x0], x2 + st1 {v2.d}[1], [x1], x2 + st1 {v3.d}[0], [x0], x2 + st1 {v3.d}[1], [x1], x2 + st1 {v4.d}[0], [x0], x2 + st1 {v4.d}[1], [x1], x2 + st1 {v5.d}[0], [x0], x2 + st1 {v5.d}[1], [x1], x2 + st1 {v6.d}[0], [x0], x2 + st1 {v6.d}[1], [x1], x2 + st1 {v7.d}[0], [x0] + st1 {v7.d}[1], [x1] + + ret + +endfunc +.endm + +vp8_h_loop_filter8uv +vp8_h_loop_filter8uv _inner, inner=1 + + +function ff_put_vp8_pixels16_neon, export=1 +1: + subs w4, w4, #4 + ld1 {v0.16b}, [x2], x3 + ld1 {v1.16b}, [x2], x3 + ld1 {v2.16b}, [x2], x3 + ld1 {v3.16b}, [x2], x3 + st1 {v0.16b}, [x0], x1 + st1 {v1.16b}, [x0], x1 + st1 {v2.16b}, [x0], x1 + st1 {v3.16b}, [x0], x1 + b.gt 1b + ret +endfunc + +function ff_put_vp8_pixels8_neon, export=1 +1: + subs w4, w4, #4 + ld1 {v0.8b}, [x2], x3 + ld1 {v0.d}[1], [x2], x3 + ld1 {v1.8b}, [x2], x3 + ld1 {v1.d}[1], [x2], x3 + st1 {v0.8b}, [x0], x1 + st1 {v0.d}[1], [x0], x1 + st1 {v1.8b}, [x0], x1 + st1 {v1.d}[1], [x0], x1 + b.gt 1b + ret +endfunc + +/* 4/6-tap 8th-pel MC */ + +.macro vp8_epel8_h6 d, s0, s1 + ext v22.8b, \s0\().8b, \s1\().8b, #1 + uxtl v18.8h, \s0\().8b + ext v23.8b, \s0\().8b, \s1\().8b, #2 + uxtl v19.8h, v22.8b + ext v24.8b, \s0\().8b, \s1\().8b, #3 + uxtl v21.8h, v23.8b + ext v25.8b, \s0\().8b, \s1\().8b, #4 + uxtl v22.8h, v24.8b + ext v26.8b, \s0\().8b, \s1\().8b, #5 + uxtl v25.8h, v25.8b + mul v21.8h, v21.8h, v0.h[2] + uxtl v26.8h, v26.8b + mul v22.8h, v22.8h, v0.h[3] + mls v21.8h, v19.8h, v0.h[1] + mls v22.8h, v25.8h, v0.h[4] + mla v21.8h, v18.8h, v0.h[0] + mla v22.8h, v26.8h, v0.h[5] + sqadd v22.8h, v21.8h, v22.8h + sqrshrun \d\().8b, v22.8h, #7 +.endm + +.macro vp8_epel16_h6 d0, v0, v1 + ext v22.16b, \v0\().16b, \v1\().16b, #3 + ext v23.16b, \v0\().16b, \v1\().16b, #4 + uxtl v19.8h, v22.8b + uxtl2 v22.8h, v22.16b + ext v3.16b, \v0\().16b, \v1\().16b, #2 + uxtl v20.8h, v23.8b + uxtl2 v23.8h, v23.16b + ext v16.16b, \v0\().16b, \v1\().16b, #1 + uxtl v18.8h, v3.8b + uxtl2 v3.8h, v3.16b + ext v2.16b, \v0\().16b, \v1\().16b, #5 + uxtl v21.8h, v2.8b + uxtl2 v2.8h, v2.16b + uxtl v17.8h, v16.8b + uxtl2 v16.8h, v16.16b + mul v19.8h, v19.8h, v0.h[3] + mul v18.8h, v18.8h, v0.h[2] + mul v3.8h, v3.8h, v0.h[2] + mul v22.8h, v22.8h, v0.h[3] + mls v19.8h, v20.8h, v0.h[4] + uxtl v20.8h, \v0\().8b + uxtl2 v1.8h, \v0\().16b + mls v18.8h, v17.8h, v0.h[1] + mls v3.8h, v16.8h, v0.h[1] + mls v22.8h, v23.8h, v0.h[4] + mla v18.8h, v20.8h, v0.h[0] + mla v19.8h, v21.8h, v0.h[5] + mla v3.8h, v1.8h, v0.h[0] + mla v22.8h, v2.8h, v0.h[5] + sqadd v19.8h, v18.8h, v19.8h + sqadd v22.8h, v3.8h, v22.8h + sqrshrun \d0\().8b, v19.8h, #7 + sqrshrun2 \d0\().16b, v22.8h, #7 +.endm + +.macro vp8_epel8_v6_y2 d0, d1, s0, s1, s2, s3, s4, s5, s6 + uxtl \s0\().8h, \s0\().8b + uxtl \s3\().8h, \s3\().8b + uxtl \s6\().8h, \s6\().8b + uxtl \s1\().8h, \s1\().8b + uxtl \s4\().8h, \s4\().8b + uxtl \s2\().8h, \s2\().8b + uxtl \s5\().8h, \s5\().8b + mul \s0\().8h, \s0\().8h, v0.h[0] + mul v31.8h , \s3\().8h, v0.h[3] + mul \s3\().8h, \s3\().8h, v0.h[2] + mul \s6\().8h, \s6\().8h, v0.h[5] + + mls \s0\().8h, \s1\().8h, v0.h[1] + mls v31.8h , \s4\().8h, v0.h[4] + mls \s3\().8h, \s2\().8h, v0.h[1] + mls \s6\().8h, \s5\().8h, v0.h[4] + + mla \s0\().8h, \s2\().8h, v0.h[2] + mla v31.8h , \s5\().8h, v0.h[5] + mla \s3\().8h, \s1\().8h, v0.h[0] + mla \s6\().8h, \s4\().8h, v0.h[3] + sqadd v31.8h , \s0\().8h, v31.8h + sqadd \s6\().8h, \s3\().8h, \s6\().8h + sqrshrun \d0\().8b, v31.8h, #7 + sqrshrun \d1\().8b, \s6\().8h, #7 +.endm + +.macro vp8_epel8_h4 d, v0, v1 + ext v22.8b, \v0\().8b, \v1\().8b, #1 + uxtl v19.8h, \v0\().8b + ext v23.8b, \v0\().8b, \v1\().8b, #2 + uxtl v20.8h, v22.8b + ext v25.8b, \v0\().8b, \v1\().8b, #3 + uxtl v22.8h, v23.8b + uxtl v25.8h, v25.8b + mul v20.8h, v20.8h, v0.h[2] + mul v22.8h, v22.8h, v0.h[3] + mls v20.8h, v19.8h, v0.h[1] + mls v22.8h, v25.8h, v0.h[4] + sqadd v22.8h, v20.8h, v22.8h + sqrshrun \d\().8b, v22.8h, #7 +.endm + +.macro vp8_epel8_v4_y2 d0, s0, s1, s2, s3, s4 + uxtl \s0\().8h, \s0\().8b + uxtl \s1\().8h, \s1\().8b + uxtl \s2\().8h, \s2\().8b + uxtl \s3\().8h, \s3\().8b + uxtl \s4\().8h, \s4\().8b + mul v21.8h, \s1\().8h, v0.h[2] + mul v23.8h, \s2\().8h, v0.h[3] + mul \s2\().8h, \s2\().8h, v0.h[2] + mul v22.8h, \s3\().8h, v0.h[3] + mls v21.8h, \s0\().8h, v0.h[1] + mls v23.8h, \s3\().8h, v0.h[4] + mls \s2\().8h, \s1\().8h, v0.h[1] + mls v22.8h, \s4\().8h, v0.h[4] + sqadd v21.8h, v21.8h, v23.8h + sqadd \s2\().8h, \s2\().8h, v22.8h + sqrshrun \d0\().8b, v21.8h, #7 + sqrshrun2 \d0\().16b, \s2\().8h, #7 +.endm + + +// note: worst case sum of all 6-tap filter values * 255 is 0x7f80 so 16 bit +// arithmetic can be used to apply filters +const subpel_filters, align=4 + .short 0, 6, 123, 12, 1, 0, 0, 0 + .short 2, 11, 108, 36, 8, 1, 0, 0 + .short 0, 9, 93, 50, 6, 0, 0, 0 + .short 3, 16, 77, 77, 16, 3, 0, 0 + .short 0, 6, 50, 93, 9, 0, 0, 0 + .short 1, 8, 36, 108, 11, 2, 0, 0 + .short 0, 1, 12, 123, 6, 0, 0, 0 +endconst + +function ff_put_vp8_epel16_v6_neon, export=1 + sub x2, x2, x3, lsl #1 + + sxtw x4, w4 + sxtw x6, w6 + movrel x17, subpel_filters, -16 + add x6, x17, x6, lsl #4 // y + ld1 {v0.8h}, [x6] +1: + ld1 {v1.1d - v2.1d}, [x2], x3 + ld1 {v3.1d - v4.1d}, [x2], x3 + ld1 {v16.1d - v17.1d}, [x2], x3 + ld1 {v18.1d - v19.1d}, [x2], x3 + ld1 {v20.1d - v21.1d}, [x2], x3 + ld1 {v22.1d - v23.1d}, [x2], x3 + ld1 {v24.1d - v25.1d}, [x2] + sub x2, x2, x3, lsl #2 + + vp8_epel8_v6_y2 v1, v3, v1, v3, v16, v18, v20, v22, v24 + vp8_epel8_v6_y2 v2, v4, v2, v4, v17, v19, v21, v23, v25 + + st1 {v1.1d - v2.1d}, [x0], x1 + st1 {v3.1d - v4.1d}, [x0], x1 + subs x4, x4, #2 + b.ne 1b + + ret +endfunc + +function ff_put_vp8_epel16_h6_neon, export=1 + sub x2, x2, #2 + sxtw x5, w5 // x + + // first pass (horizontal): + movrel x17, subpel_filters, -16 + add x5, x17, x5, lsl #4 // x + ld1 {v0.8h}, [x5] +1: + ld1 {v1.16b, v2.16b}, [x2], x3 + vp8_epel16_h6 v1, v1, v2 + st1 {v1.16b}, [x0], x1 + + subs w4, w4, #1 + b.ne 1b + ret +endfunc + + +function ff_put_vp8_epel16_h6v6_neon, export=1 + sub x2, x2, x3, lsl #1 + sub x2, x2, #2 + + // first pass (horizontal): + movrel x17, subpel_filters, -16 + sxtw x5, w5 // x + add x16, x17, x5, lsl #4 // x + sub sp, sp, #336+16 + ld1 {v0.8h}, [x16] + add x7, sp, #15 + sxtw x4, w4 + add x16, x4, #5 // h + bic x7, x7, #15 +1: + ld1 {v1.16b, v2.16b}, [x2], x3 + vp8_epel16_h6 v1, v1, v2 + st1 {v1.16b}, [x7], #16 + subs x16, x16, #1 + b.ne 1b + + + // second pass (vertical): + sxtw x6, w6 + add x6, x17, x6, lsl #4 // y + add x7, sp, #15 + ld1 {v0.8h}, [x6] + bic x7, x7, #15 +2: + ld1 {v1.8b - v4.8b}, [x7], #32 + ld1 {v16.8b - v19.8b}, [x7], #32 + ld1 {v20.8b - v23.8b}, [x7], #32 + ld1 {v24.8b - v25.8b}, [x7] + sub x7, x7, #64 + + vp8_epel8_v6_y2 v1, v3, v1, v3, v16, v18, v20, v22, v24 + vp8_epel8_v6_y2 v2, v4, v2, v4, v17, v19, v21, v23, v25 + trn1 v1.2d, v1.2d, v2.2d + trn1 v3.2d, v3.2d, v4.2d + + st1 {v1.16b}, [x0], x1 + st1 {v3.16b}, [x0], x1 + subs x4, x4, #2 + b.ne 2b + + add sp, sp, #336+16 + ret +endfunc + +function ff_put_vp8_epel8_v6_neon, export=1 + sub x2, x2, x3, lsl #1 + + movrel x7, subpel_filters, -16 + add x6, x7, w6, uxtw #4 + ld1 {v0.8h}, [x6] +1: + ld1 {v2.8b}, [x2], x3 + ld1 {v3.8b}, [x2], x3 + ld1 {v4.8b}, [x2], x3 + ld1 {v5.8b}, [x2], x3 + ld1 {v6.8b}, [x2], x3 + ld1 {v7.8b}, [x2], x3 + ld1 {v28.8b}, [x2] + + sub x2, x2, x3, lsl #2 + + vp8_epel8_v6_y2 v2, v3, v2, v3, v4, v5, v6, v7, v28 + + st1 {v2.8b}, [x0], x1 + st1 {v3.8b}, [x0], x1 + subs w4, w4, #2 + b.ne 1b + + ret +endfunc + +function ff_put_vp8_epel8_h6_neon, export=1 + sub x2, x2, #2 + + movrel x7, subpel_filters, -16 + add x5, x7, w5, uxtw #4 + ld1 {v0.8h}, [x5] +1: + ld1 {v2.8b, v3.8b}, [x2], x3 + + vp8_epel8_h6 v2, v2, v3 + + st1 {v2.8b}, [x0], x1 + subs w4, w4, #1 + b.ne 1b + + ret +endfunc + +function ff_put_vp8_epel8_h6v6_neon, export=1 + sub x2, x2, x3, lsl #1 + sub x2, x2, #2 + sxtw x4, w4 + + // first pass (horizontal): + movrel x17, subpel_filters, -16 + sxtw x5, w5 + add x5, x17, x5, lsl #4 // x + sub sp, sp, #168+16 + ld1 {v0.8h}, [x5] + add x7, sp, #15 + add x16, x4, #5 // h + bic x7, x7, #15 +1: + ld1 {v1.8b, v2.8b}, [x2], x3 + + vp8_epel8_h6 v1, v1, v2 + + st1 {v1.8b}, [x7], #8 + subs x16, x16, #1 + b.ne 1b + + // second pass (vertical): + sxtw x6, w6 + add x6, x17, x6, lsl #4 // y + add x7, sp, #15 + ld1 {v0.8h}, [x6] + bic x7, x7, #15 +2: + ld1 {v1.8b - v4.8b}, [x7], #32 + ld1 {v5.8b - v7.8b}, [x7] + + sub x7, x7, #16 + + vp8_epel8_v6_y2 v1, v2, v1, v2, v3, v4, v5, v6, v7 + + st1 {v1.8b}, [x0], x1 + st1 {v2.8b}, [x0], x1 + subs x4, x4, #2 + b.ne 2b + + add sp, sp, #168+16 + ret +endfunc + +function ff_put_vp8_epel8_v4_neon, export=1 + sub x2, x2, x3 + + movrel x7, subpel_filters, -16 + add x6, x7, w6, uxtw #4 + ld1 {v0.8h}, [x6] +1: + ld1 {v2.8b}, [x2], x3 + ld1 {v3.8b}, [x2], x3 + ld1 {v4.8b}, [x2], x3 + ld1 {v5.8b}, [x2], x3 + ld1 {v6.8b}, [x2] + sub x2, x2, x3, lsl #1 + + vp8_epel8_v4_y2 v2, v2, v3, v4, v5, v6 + + st1 {v2.d}[0], [x0], x1 + st1 {v2.d}[1], [x0], x1 + subs w4, w4, #2 + b.ne 1b + + ret +endfunc + +function ff_put_vp8_epel8_h4_neon, export=1 + sub x2, x2, #1 + + movrel x7, subpel_filters, -16 + add x5, x7, w5, uxtw #4 + ld1 {v0.8h}, [x5] +1: + ld1 {v2.8b,v3.8b}, [x2], x3 + + vp8_epel8_h4 v2, v2, v3 + + st1 {v2.8b}, [x0], x1 + subs w4, w4, #1 + b.ne 1b + + ret +endfunc + +function ff_put_vp8_epel8_h4v6_neon, export=1 + sub x2, x2, x3, lsl #1 + sub x2, x2, #1 + sxtw x4, w4 + + // first pass (horizontal): + movrel x17, subpel_filters, -16 + sxtw x5, w5 + add x5, x17, x5, lsl #4 // x + sub sp, sp, #168+16 + ld1 {v0.8h}, [x5] + add x7, sp, #15 + add x16, x4, #5 // h + bic x7, x7, #15 +1: + ld1 {v1.8b, v2.8b}, [x2], x3 + + vp8_epel8_h4 v1, v1, v2 + + st1 {v1.8b}, [x7], #8 + subs x16, x16, #1 + b.ne 1b + + // second pass (vertical): + sxtw x6, w6 + add x6, x17, x6, lsl #4 // y + add x7, sp, #15 + ld1 {v0.8h}, [x6] + bic x7, x7, #15 +2: + ld1 {v1.8b - v4.8b}, [x7], #32 + ld1 {v5.8b - v7.8b}, [x7] + + sub x7, x7, #16 + + vp8_epel8_v6_y2 v1, v2, v1, v2, v3, v4, v5, v6, v7 + + st1 {v1.8b}, [x0], x1 + st1 {v2.8b}, [x0], x1 + subs x4, x4, #2 + b.ne 2b + + add sp, sp, #168+16 + ret +endfunc + +function ff_put_vp8_epel8_h4v4_neon, export=1 + sub x2, x2, x3 + sub x2, x2, #1 + sxtw x4, w4 + + + // first pass (horizontal): + movrel x17, subpel_filters, -16 + sxtw x5, w5 + add x5, x17, x5, lsl #4 // x + sub sp, sp, #168+16 + ld1 {v0.8h}, [x5] + add x7, sp, #15 + add x16, x4, #3 // h + bic x7, x7, #15 +1: + ld1 {v1.8b, v2.8b}, [x2], x3 + + vp8_epel8_h4 v1, v1, v2 + + st1 {v1.8b}, [x7], #8 + subs x16, x16, #1 + b.ne 1b + + // second pass (vertical): + sxtw x6, w6 + add x6, x17, x6, lsl #4 // y + add x7, sp, #15 + ld1 {v0.8h}, [x6] + bic x7, x7, #15 +2: + ld1 {v1.8b - v2.8b}, [x7], #16 + ld1 {v3.8b - v5.8b}, [x7] + + vp8_epel8_v4_y2 v1, v1, v2, v3, v4, v5 + + st1 {v1.d}[0], [x0], x1 + st1 {v1.d}[1], [x0], x1 + subs x4, x4, #2 + b.ne 2b + + add sp, sp, #168+16 + ret +endfunc + +function ff_put_vp8_epel8_h6v4_neon, export=1 + sub x2, x2, x3 + sub x2, x2, #2 + sxtw x4, w4 + + + // first pass (horizontal): + movrel x17, subpel_filters, -16 + sxtw x5, w5 + add x5, x17, x5, lsl #4 // x + sub sp, sp, #168+16 + ld1 {v0.8h}, [x5] + add x7, sp, #15 + add x16, x4, #3 // h + bic x7, x7, #15 +1: + ld1 {v1.8b, v2.8b}, [x2], x3 + + vp8_epel8_h6 v1, v1, v2 + + st1 {v1.8b}, [x7], #8 + subs x16, x16, #1 + b.ne 1b + + // second pass (vertical): + sxtw x6, w6 + add x6, x17, x6, lsl #4 // y + add x7, sp, #15 + ld1 {v0.8h}, [x6] + bic x7, x7, #15 +2: + ld1 {v1.8b - v2.8b}, [x7], #16 + ld1 {v3.8b - v5.8b}, [x7] + + vp8_epel8_v4_y2 v1, v1, v2, v3, v4, v5 + + st1 {v1.d}[0], [x0], x1 + st1 {v1.d}[1], [x0], x1 + subs x4, x4, #2 + b.ne 2b + + add sp, sp, #168+16 + ret +endfunc + +function ff_put_vp8_epel4_v6_neon, export=1 + sub x2, x2, x3, lsl #1 + + movrel x7, subpel_filters, -16 + add x6, x7, w6, uxtw #4 + ld1 {v0.8h}, [x6] +1: + ld1r {v2.2s}, [x2], x3 + ld1r {v3.2s}, [x2], x3 + ld1r {v4.2s}, [x2], x3 + ld1r {v5.2s}, [x2], x3 + ld1r {v6.2s}, [x2], x3 + ld1r {v7.2s}, [x2], x3 + ld1r {v28.2s}, [x2] + sub x2, x2, x3, lsl #2 + ld1 {v2.s}[1], [x2], x3 + ld1 {v3.s}[1], [x2], x3 + ld1 {v4.s}[1], [x2], x3 + ld1 {v5.s}[1], [x2], x3 + ld1 {v6.s}[1], [x2], x3 + ld1 {v7.s}[1], [x2], x3 + ld1 {v28.s}[1], [x2] + sub x2, x2, x3, lsl #2 + + vp8_epel8_v6_y2 v2, v3, v2, v3, v4, v5, v6, v7, v28 + + st1 {v2.s}[0], [x0], x1 + st1 {v3.s}[0], [x0], x1 + st1 {v2.s}[1], [x0], x1 + st1 {v3.s}[1], [x0], x1 + subs w4, w4, #4 + b.ne 1b + + ret +endfunc + +function ff_put_vp8_epel4_h6_neon, export=1 + sub x2, x2, #2 + + movrel x7, subpel_filters, -16 + add x5, x7, w5, uxtw #4 + ld1 {v0.8h}, [x5] +1: + ld1 {v2.8b,v3.8b}, [x2], x3 + vp8_epel8_h6 v2, v2, v3 + st1 {v2.s}[0], [x0], x1 + subs w4, w4, #1 + b.ne 1b + + ret +endfunc + +function ff_put_vp8_epel4_h6v6_neon, export=1 + sub x2, x2, x3, lsl #1 + sub x2, x2, #2 + + movrel x7, subpel_filters, -16 + add x5, x7, w5, uxtw #4 + ld1 {v0.8h}, [x5] + + sub sp, sp, #52 + add w8, w4, #5 + mov x9, sp +1: + ld1 {v2.8b,v3.8b}, [x2], x3 + vp8_epel8_h6 v2, v2, v3 + st1 {v2.s}[0], [x9], #4 + subs w8, w8, #1 + b.ne 1b + + add x6, x7, w6, uxtw #4 + ld1 {v0.8h}, [x6] + mov x9, sp +2: + ld1 {v2.8b,v3.8b}, [x9], #16 + ld1 {v6.8b}, [x9], #8 + ld1r {v28.2s}, [x9] + sub x9, x9, #16 + ld1 {v4.8b,v5.8b}, [x9], #16 + ld1 {v7.8b}, [x9], #8 + ld1 {v28.s}[1], [x9] + sub x9, x9, #16 + trn1 v1.2s, v2.2s, v4.2s + trn2 v4.2s, v2.2s, v4.2s + trn1 v2.2s, v3.2s, v5.2s + trn2 v5.2s, v3.2s, v5.2s + trn1 v3.2s, v6.2s, v7.2s + trn2 v7.2s, v6.2s, v7.2s + vp8_epel8_v6_y2 v2, v3, v1, v4, v2, v5, v3, v7, v28 + st1 {v2.s}[0], [x0], x1 + st1 {v3.s}[0], [x0], x1 + st1 {v2.s}[1], [x0], x1 + st1 {v3.s}[1], [x0], x1 + subs w4, w4, #4 + b.ne 2b + + add sp, sp, #52 + ret +endfunc + +function ff_put_vp8_epel4_h4v6_neon, export=1 + sub x2, x2, x3, lsl #1 + sub x2, x2, #1 + + movrel x7, subpel_filters, -16 + add x5, x7, w5, uxtw #4 + ld1 {v0.8h}, [x5] + + sub sp, sp, #52 + add w8, w4, #5 + mov x9, sp +1: + ld1 {v2.8b}, [x2], x3 + vp8_epel8_h4 v2, v2, v2 + st1 {v2.s}[0], [x9], #4 + subs w8, w8, #1 + b.ne 1b + + add x6, x7, w6, uxtw #4 + ld1 {v0.8h}, [x6] + mov x9, sp +2: + ld1 {v2.8b,v3.8b}, [x9], #16 + ld1 {v6.8b}, [x9], #8 + ld1r {v28.2s}, [x9] + sub x9, x9, #16 + ld1 {v4.8b,v5.8b}, [x9], #16 + ld1 {v7.8b}, [x9], #8 + ld1 {v28.s}[1], [x9] + sub x9, x9, #16 + trn1 v1.2s, v2.2s, v4.2s + trn2 v4.2s, v2.2s, v4.2s + trn1 v2.2s, v3.2s, v5.2s + trn2 v5.2s, v3.2s, v5.2s + trn1 v3.2s, v6.2s, v7.2s + trn2 v7.2s, v6.2s, v7.2s + vp8_epel8_v6_y2 v2, v3, v1, v4, v2, v5, v3, v7, v28 + st1 {v2.s}[0], [x0], x1 + st1 {v3.s}[0], [x0], x1 + st1 {v2.s}[1], [x0], x1 + st1 {v3.s}[1], [x0], x1 + subs w4, w4, #4 + b.ne 2b + + add sp, sp, #52 + ret +endfunc + +function ff_put_vp8_epel4_h6v4_neon, export=1 + sub x2, x2, x3 + sub x2, x2, #2 + + movrel x7, subpel_filters, -16 + add x5, x7, w5, uxtw #4 + ld1 {v0.8h}, [x5] + + sub sp, sp, #44 + add w8, w4, #3 + mov x9, sp +1: + ld1 {v2.8b,v3.8b}, [x2], x3 + vp8_epel8_h6 v2, v2, v3 + st1 {v2.s}[0], [x9], #4 + subs w8, w8, #1 + b.ne 1b + + add x6, x7, w6, uxtw #4 + ld1 {v0.8h}, [x6] + mov x9, sp +2: + ld1 {v2.8b,v3.8b}, [x9], #16 + ld1r {v6.2s}, [x9] + sub x9, x9, #8 + ld1 {v4.8b,v5.8b}, [x9], #16 + ld1 {v6.s}[1], [x9] + sub x9, x9, #8 + trn1 v1.2s, v2.2s, v4.2s + trn2 v4.2s, v2.2s, v4.2s + trn1 v2.2s, v3.2s, v5.2s + trn2 v5.2s, v3.2s, v5.2s + vp8_epel8_v4_y2 v1, v1, v4, v2, v5, v6 + st1 {v1.s}[0], [x0], x1 + st1 {v1.s}[2], [x0], x1 + st1 {v1.s}[1], [x0], x1 + st1 {v1.s}[3], [x0], x1 + subs w4, w4, #4 + b.ne 2b + + add sp, sp, #44 + ret +endfunc + +function ff_put_vp8_epel4_h4_neon, export=1 + sub x2, x2, #1 + + movrel x7, subpel_filters, -16 + add x5, x7, w5, uxtw #4 + ld1 {v0.8h}, [x5] +1: + ld1 {v2.8b}, [x2], x3 + vp8_epel8_h4 v2, v2, v2 + st1 {v2.s}[0], [x0], x1 + subs w4, w4, #1 + b.ne 1b + + ret +endfunc + +function ff_put_vp8_epel4_v4_neon, export=1 + sub x2, x2, x3 + + movrel x7, subpel_filters, -16 + add x6, x7, w6, uxtw #4 + ld1 {v0.8h}, [x6] +1: + ld1r {v2.2s}, [x2], x3 + ld1r {v3.2s}, [x2], x3 + ld1r {v4.2s}, [x2], x3 + ld1r {v5.2s}, [x2], x3 + ld1r {v6.2s}, [x2] + sub x2, x2, x3, lsl #1 + ld1 {v2.s}[1], [x2], x3 + ld1 {v3.s}[1], [x2], x3 + ld1 {v4.s}[1], [x2], x3 + ld1 {v5.s}[1], [x2], x3 + ld1 {v6.s}[1], [x2] + sub x2, x2, x3, lsl #1 + + vp8_epel8_v4_y2 v2, v2, v3, v4, v5, v6 + + st1 {v2.s}[0], [x0], x1 + st1 {v2.s}[2], [x0], x1 + st1 {v2.s}[1], [x0], x1 + st1 {v2.s}[3], [x0], x1 + subs w4, w4, #4 + b.ne 1b + + ret +endfunc + +function ff_put_vp8_epel4_h4v4_neon, export=1 + sub x2, x2, x3 + sub x2, x2, #1 + + movrel x7, subpel_filters, -16 + add x5, x7, w5, uxtw #4 + ld1 {v0.8h}, [x5] + + sub sp, sp, #44 + add w8, w4, #3 + mov x9, sp +1: + ld1 {v2.8b}, [x2], x3 + vp8_epel8_h4 v2, v2, v3 + st1 {v2.s}[0], [x9], #4 + subs w8, w8, #1 + b.ne 1b + + add x6, x7, w6, uxtw #4 + ld1 {v0.8h}, [x6] + mov x9, sp +2: + ld1 {v2.8b,v3.8b}, [x9], #16 + ld1r {v6.2s}, [x9] + sub x9, x9, #8 + ld1 {v4.8b,v5.8b}, [x9], #16 + ld1 {v6.s}[1], [x9] + sub x9, x9, #8 + trn1 v1.2s, v2.2s, v4.2s + trn2 v4.2s, v2.2s, v4.2s + trn1 v2.2s, v3.2s, v5.2s + trn2 v5.2s, v3.2s, v5.2s + vp8_epel8_v4_y2 v1, v1, v4, v2, v5, v6 + st1 {v1.s}[0], [x0], x1 + st1 {v1.s}[2], [x0], x1 + st1 {v1.s}[1], [x0], x1 + st1 {v1.s}[3], [x0], x1 + subs w4, w4, #4 + b.ne 2b + + add sp, sp, #44 + ret +endfunc + +/* Bilinear MC */ + +function ff_put_vp8_bilin16_h_neon, export=1 + mov w7, #8 + dup v0.8b, w5 + sub w5, w7, w5 + dup v1.8b, w5 +1: + subs w4, w4, #2 + ld1 {v2.8b,v3.8b,v4.8b}, [x2], x3 + ext v5.8b, v3.8b, v4.8b, #1 + ext v4.8b, v2.8b, v3.8b, #1 + umull v16.8h, v2.8b, v1.8b + umlal v16.8h, v4.8b, v0.8b + ld1 {v18.8b,v19.8b,v20.8b}, [x2], x3 + umull v6.8h, v3.8b, v1.8b + umlal v6.8h, v5.8b, v0.8b + ext v21.8b, v19.8b, v20.8b, #1 + ext v20.8b, v18.8b, v19.8b, #1 + umull v22.8h, v18.8b, v1.8b + umlal v22.8h, v20.8b, v0.8b + umull v24.8h, v19.8b, v1.8b + umlal v24.8h, v21.8b, v0.8b + rshrn v4.8b, v16.8h, #3 + rshrn2 v4.16b, v6.8h, #3 + rshrn v6.8b, v22.8h, #3 + rshrn2 v6.16b, v24.8h, #3 + st1 {v4.16b}, [x0], x1 + st1 {v6.16b}, [x0], x1 + b.gt 1b + + ret +endfunc + +function ff_put_vp8_bilin16_v_neon, export=1 + mov w7, #8 + dup v0.16b, w6 + sub w6, w7, w6 + dup v1.16b, w6 + + ld1 {v2.16b}, [x2], x3 +1: + subs w4, w4, #2 + ld1 {v4.16b}, [x2], x3 + umull v6.8h, v2.8b, v1.8b + umlal v6.8h, v4.8b, v0.8b + umull2 v16.8h, v2.16b, v1.16b + umlal2 v16.8h, v4.16b, v0.16b + ld1 {v2.16b}, [x2], x3 + umull v18.8h, v4.8b, v1.8b + umlal v18.8h, v2.8b, v0.8b + umull2 v20.8h, v4.16b, v1.16b + umlal2 v20.8h, v2.16b, v0.16b + rshrn v4.8b, v6.8h, #3 + rshrn2 v4.16b, v16.8h, #3 + rshrn v6.8b, v18.8h, #3 + rshrn2 v6.16b, v20.8h, #3 + st1 {v4.16b}, [x0], x1 + st1 {v6.16b}, [x0], x1 + b.gt 1b + + ret +endfunc + +function ff_put_vp8_bilin16_hv_neon, export=1 + mov w7, #8 + dup v0.8b, w5 // mx + sub w5, w7, w5 + dup v1.8b, w5 + dup v2.16b, w6 // my + sub w6, w7, w6 + dup v3.16b, w6 + + ld1 {v4.8b,v5.8b,v6.8b}, [x2], x3 + + ext v7.8b, v5.8b, v6.8b, #1 + ext v6.8b, v4.8b, v5.8b, #1 + umull v16.8h, v4.8b, v1.8b + umlal v16.8h, v6.8b, v0.8b + umull v18.8h, v5.8b, v1.8b + umlal v18.8h, v7.8b, v0.8b + rshrn v4.8b, v16.8h, #3 + rshrn2 v4.16b, v18.8h, #3 +1: + subs w4, w4, #2 + ld1 {v18.8b,v19.8b,v20.8b}, [x2], x3 + ext v21.8b, v19.8b, v20.8b, #1 + ext v20.8b, v18.8b, v19.8b, #1 + umull v22.8h, v18.8b, v1.8b + umlal v22.8h, v20.8b, v0.8b + ld1 {v26.8b,v27.8b,v28.8b}, [x2], x3 + umull v24.8h, v19.8b, v1.8b + umlal v24.8h, v21.8b, v0.8b + ext v29.8b, v27.8b, v28.8b, #1 + ext v28.8b, v26.8b, v27.8b, #1 + umull v16.8h, v26.8b, v1.8b + umlal v16.8h, v28.8b, v0.8b + umull v18.8h, v27.8b, v1.8b + umlal v18.8h, v29.8b, v0.8b + rshrn v6.8b, v22.8h, #3 + rshrn2 v6.16b, v24.8h, #3 + umull v24.8h, v4.8b, v3.8b + umlal v24.8h, v6.8b, v2.8b + umull2 v30.8h, v4.16b, v3.16b + umlal2 v30.8h, v6.16b, v2.16b + rshrn v4.8b, v16.8h, #3 + rshrn2 v4.16b, v18.8h, #3 + umull v20.8h, v6.8b, v3.8b + umlal v20.8h, v4.8b, v2.8b + umull2 v22.8h, v6.16b, v3.16b + umlal2 v22.8h, v4.16b, v2.16b + rshrn v24.8b, v24.8h, #3 + rshrn2 v24.16b, v30.8h, #3 + st1 {v24.16b}, [x0], x1 + rshrn v20.8b, v20.8h, #3 + rshrn2 v20.16b, v22.8h, #3 + st1 {v20.16b}, [x0], x1 + b.gt 1b + + ret +endfunc + +function ff_put_vp8_bilin8_h_neon, export=1 + mov w7, #8 + dup v0.8b, w5 + sub w5, w7, w5 + dup v1.8b, w5 +1: + subs w4, w4, #2 + ld1 {v2.8b,v3.8b}, [x2], x3 + ext v3.8b, v2.8b, v3.8b, #1 + umull v4.8h, v2.8b, v1.8b + umlal v4.8h, v3.8b, v0.8b + ld1 {v6.8b,v7.8b}, [x2], x3 + ext v7.8b, v6.8b, v7.8b, #1 + umull v16.8h, v6.8b, v1.8b + umlal v16.8h, v7.8b, v0.8b + rshrn v4.8b, v4.8h, #3 + rshrn v16.8b, v16.8h, #3 + st1 {v4.8b}, [x0], x1 + st1 {v16.8b}, [x0], x1 + b.gt 1b + + ret +endfunc + +function ff_put_vp8_bilin8_v_neon, export=1 + mov w7, #8 + dup v0.8b, w6 + sub w6, w7, w6 + dup v1.8b, w6 + + ld1 {v2.8b}, [x2], x3 +1: + subs w4, w4, #2 + ld1 {v3.8b}, [x2], x3 + umull v4.8h, v2.8b, v1.8b + umlal v4.8h, v3.8b, v0.8b + ld1 {v2.8b}, [x2], x3 + umull v6.8h, v3.8b, v1.8b + umlal v6.8h, v2.8b, v0.8b + rshrn v4.8b, v4.8h, #3 + rshrn v6.8b, v6.8h, #3 + st1 {v4.8b}, [x0], x1 + st1 {v6.8b}, [x0], x1 + b.gt 1b + + ret +endfunc + +function ff_put_vp8_bilin8_hv_neon, export=1 + mov w7, #8 + dup v0.8b, w5 // mx + sub w5, w7, w5 + dup v1.8b, w5 + dup v2.8b, w6 // my + sub w6, w7, w6 + dup v3.8b, w6 + + ld1 {v4.8b,v5.8b}, [x2], x3 + ext v5.8b, v4.8b, v5.8b, #1 + umull v18.8h, v4.8b, v1.8b + umlal v18.8h, v5.8b, v0.8b + rshrn v22.8b, v18.8h, #3 +1: + subs w4, w4, #2 + ld1 {v6.8b,v7.8b}, [x2], x3 + ext v7.8b, v6.8b, v7.8b, #1 + umull v16.8h, v6.8b, v1.8b + umlal v16.8h, v7.8b, v0.8b + ld1 {v4.8b,v5.8b}, [x2], x3 + ext v5.8b, v4.8b, v5.8b, #1 + umull v18.8h, v4.8b, v1.8b + umlal v18.8h, v5.8b, v0.8b + rshrn v16.8b, v16.8h, #3 + umull v20.8h, v22.8b, v3.8b + umlal v20.8h, v16.8b, v2.8b + rshrn v22.8b, v18.8h, #3 + umull v24.8h, v16.8b, v3.8b + umlal v24.8h, v22.8b, v2.8b + rshrn v20.8b, v20.8h, #3 + st1 {v20.8b}, [x0], x1 + rshrn v23.8b, v24.8h, #3 + st1 {v23.8b}, [x0], x1 + b.gt 1b + + ret +endfunc + +function ff_put_vp8_bilin4_h_neon, export=1 + mov w7, #8 + dup v0.8b, w5 + sub w5, w7, w5 + dup v1.8b, w5 +1: + subs w4, w4, #2 + ld1 {v2.8b}, [x2], x3 + ext v3.8b, v2.8b, v3.8b, #1 + ld1 {v6.8b}, [x2], x3 + ext v7.8b, v6.8b, v7.8b, #1 + trn1 v2.2s, v2.2s, v6.2s + trn1 v3.2s, v3.2s, v7.2s + umull v4.8h, v2.8b, v1.8b + umlal v4.8h, v3.8b, v0.8b + rshrn v4.8b, v4.8h, #3 + st1 {v4.s}[0], [x0], x1 + st1 {v4.s}[1], [x0], x1 + b.gt 1b + + ret +endfunc + +function ff_put_vp8_bilin4_v_neon, export=1 + mov w7, #8 + dup v0.8b, w6 + sub w6, w7, w6 + dup v1.8b, w6 + + ld1r {v2.2s}, [x2], x3 +1: + ld1r {v3.2s}, [x2] + ld1 {v2.s}[1], [x2], x3 + ld1 {v3.s}[1], [x2], x3 + umull v4.8h, v2.8b, v1.8b + umlal v4.8h, v3.8b, v0.8b + trn2 v2.2s, v3.2s, v2.2s + rshrn v4.8b, v4.8h, #3 + st1 {v4.s}[0], [x0], x1 + st1 {v4.s}[1], [x0], x1 + subs w4, w4, #2 + b.gt 1b + + ret +endfunc + +function ff_put_vp8_bilin4_hv_neon, export=1 + mov w7, #8 + dup v0.8b, w5 // mx + sub w5, w7, w5 + dup v1.8b, w5 + dup v2.8b, w6 // my + sub w6, w7, w6 + dup v3.8b, w6 + + ld1 {v4.8b}, [x2], x3 + ext v5.8b, v4.8b, v4.8b, #1 + umull v18.8h, v4.8b, v1.8b + umlal v18.8h, v5.8b, v0.8b + rshrn v22.8b, v18.8h, #3 +1: + subs w4, w4, #2 + ld1 {v6.8b}, [x2], x3 + ext v7.8b, v6.8b, v6.8b, #1 + ld1 {v4.8b}, [x2], x3 + ext v5.8b, v4.8b, v4.8b, #1 + trn1 v6.2s, v6.2s, v4.2s + trn1 v7.2s, v7.2s, v5.2s + umull v16.8h, v6.8b, v1.8b + umlal v16.8h, v7.8b, v0.8b + rshrn v16.8b, v16.8h, #3 + umull v20.8h, v16.8b, v2.8b + trn1 v22.2s, v22.2s, v16.2s + umlal v20.8h, v22.8b, v3.8b + rev64 v22.2s, v16.2s + rshrn v20.8b, v20.8h, #3 + st1 {v20.s}[0], [x0], x1 + st1 {v20.s}[1], [x0], x1 + b.gt 1b + + ret +endfunc diff --git a/libavcodec/ac3dec.c b/libavcodec/ac3dec.c index 43b22b765..eaa327a3e 100644 --- a/libavcodec/ac3dec.c +++ b/libavcodec/ac3dec.c @@ -452,7 +452,7 @@ static int decode_exponents(AC3DecodeContext *s, prevexp += dexp[i] - 2; if (prevexp > 24U) { av_log(s->avctx, AV_LOG_ERROR, "exponent %d is out-of-range\n", prevexp); - return -1; + return AVERROR_INVALIDDATA; } switch (group_size) { case 4: dexps[j++] = prevexp; @@ -1467,7 +1467,8 @@ static int ac3_decode_frame(AVCodecContext * avctx, void *data, int buf_size, full_buf_size = avpkt->size; AC3DecodeContext *s = avctx->priv_data; int blk, ch, err, offset, ret; - int got_independent_frame = 0; + int i; + int skip = 0, got_independent_frame = 0; const uint8_t *channel_map; uint8_t extended_channel_map[EAC3_MAX_CHANNELS]; const SHORTFLOAT *output[AC3_MAX_CHANNELS]; @@ -1477,6 +1478,23 @@ static int ac3_decode_frame(AVCodecContext * avctx, void *data, s->superframe_size = 0; buf_size = full_buf_size; + for (i = 1; i < buf_size; i += 2) { + if (buf[i] == 0x77 || buf[i] == 0x0B) { + if ((buf[i] ^ buf[i-1]) == (0x77 ^ 0x0B)) { + i--; + break; + } else if ((buf[i] ^ buf[i+1]) == (0x77 ^ 0x0B)) { + break; + } + } + } + if (i >= buf_size) + return AVERROR_INVALIDDATA; + if (i > 10) + return i; + buf += i; + buf_size -= i; + /* copy input buffer to decoder context to avoid reading past the end of the buffer, which can be caused by a damaged input stream. */ if (buf_size >= 2 && AV_RB16(buf) == 0x770B) { @@ -1637,6 +1655,11 @@ dependent_frame: AC3HeaderInfo hdr; int err; + if (buf_size - s->frame_size <= 16) { + skip = buf_size - s->frame_size; + goto skip; + } + if ((ret = init_get_bits8(&s->gbc, buf + s->frame_size, buf_size - s->frame_size)) < 0) return ret; @@ -1657,6 +1680,7 @@ dependent_frame: } } } +skip: frame->decode_error_flags = err ? FF_DECODE_ERROR_INVALID_BITSTREAM : 0; @@ -1796,9 +1820,9 @@ dependent_frame: *got_frame_ptr = 1; if (!s->superframe_size) - return FFMIN(full_buf_size, s->frame_size); + return FFMIN(full_buf_size, s->frame_size + skip); - return FFMIN(full_buf_size, s->superframe_size); + return FFMIN(full_buf_size, s->superframe_size + skip); } /** diff --git a/libavcodec/ac3enc.c b/libavcodec/ac3enc.c index 636ca7205..f1c95ce87 100644 --- a/libavcodec/ac3enc.c +++ b/libavcodec/ac3enc.c @@ -652,7 +652,7 @@ void ff_ac3_process_exponents(AC3EncodeContext *s) */ static void count_frame_bits_fixed(AC3EncodeContext *s) { - static const int frame_bits_inc[8] = { 0, 0, 2, 2, 2, 4, 2, 4 }; + static const uint8_t frame_bits_inc[8] = { 0, 0, 2, 2, 2, 4, 2, 4 }; int blk; int frame_bits; @@ -1800,7 +1800,7 @@ static int validate_float_option(float v, const float *v_list, int v_list_size) break; } if (i == v_list_size) - return -1; + return AVERROR(EINVAL); return i; } diff --git a/libavcodec/acelp_pitch_delay.c b/libavcodec/acelp_pitch_delay.c index c345a99c8..a070d1b25 100644 --- a/libavcodec/acelp_pitch_delay.c +++ b/libavcodec/acelp_pitch_delay.c @@ -118,7 +118,7 @@ int16_t ff_acelp_decode_gain_code( (mr_energy >> 15) - 25 ); #else - mr_energy = gain_corr_factor * exp(M_LN10 / (20 << 23) * mr_energy) / + mr_energy = gain_corr_factor * ff_exp10((double)mr_energy / (20 << 23)) / sqrt(adsp->scalarproduct_int16(fc_v, fc_v, subframe_size)); return mr_energy >> 12; #endif diff --git a/libavcodec/adpcm.c b/libavcodec/adpcm.c index cd3bbd33c..e19476437 100644 --- a/libavcodec/adpcm.c +++ b/libavcodec/adpcm.c @@ -57,7 +57,7 @@ */ /* These are for CD-ROM XA ADPCM */ -static const int xa_adpcm_table[5][2] = { +static const int8_t xa_adpcm_table[5][2] = { { 0, 0 }, { 60, 0 }, { 115, -52 }, @@ -65,7 +65,7 @@ static const int xa_adpcm_table[5][2] = { { 122, -60 } }; -static const int ea_adpcm_table[] = { +static const int16_t ea_adpcm_table[] = { 0, 240, 460, 392, 0, 0, -208, -220, 0, 1, 3, 4, @@ -74,7 +74,7 @@ static const int ea_adpcm_table[] = { }; // padded to zero where table size is less then 16 -static const int swf_index_tables[4][16] = { +static const int8_t swf_index_tables[4][16] = { /*2*/ { -1, 2 }, /*3*/ { -1, -1, 2, 4 }, /*4*/ { -1, -1, -1, -1, 2, 4, 6, 8 }, @@ -177,6 +177,50 @@ static av_cold int adpcm_decode_init(AVCodecContext * avctx) return 0; } +static inline int16_t adpcm_agm_expand_nibble(ADPCMChannelStatus *c, int8_t nibble) +{ + int delta, pred, step, add; + + pred = c->predictor; + delta = nibble & 7; + step = c->step; + add = (delta * 2 + 1) * step; + if (add < 0) + add = add + 7; + + if ((nibble & 8) == 0) + pred = av_clip(pred + (add >> 3), -32767, 32767); + else + pred = av_clip(pred - (add >> 3), -32767, 32767); + + switch (delta) { + case 7: + step *= 0x99; + break; + case 6: + c->step = av_clip(c->step * 2, 127, 24576); + c->predictor = pred; + return pred; + case 5: + step *= 0x66; + break; + case 4: + step *= 0x4d; + break; + default: + step *= 0x39; + break; + } + + if (step < 0) + step += 0x3f; + + c->step = step >> 6; + c->step = av_clip(c->step, 127, 24576); + c->predictor = pred; + return pred; +} + static inline int16_t adpcm_ima_expand_nibble(ADPCMChannelStatus *c, int8_t nibble, int shift) { int step_index; @@ -440,7 +484,7 @@ static void adpcm_swf_decode(AVCodecContext *avctx, const uint8_t *buf, int buf_ { ADPCMDecodeContext *c = avctx->priv_data; GetBitContext gb; - const int *table; + const int8_t *table; int k0, signmask, nb_bits, count; int size = buf_size*8; int i; @@ -549,6 +593,7 @@ static int get_nb_samples(AVCodecContext *avctx, GetByteContext *gb, header_size = 0; switch (avctx->codec->id) { case AV_CODEC_ID_ADPCM_4XM: + case AV_CODEC_ID_ADPCM_AGM: case AV_CODEC_ID_ADPCM_IMA_DAT4: case AV_CODEC_ID_ADPCM_IMA_ISS: header_size = 4 * ch; break; case AV_CODEC_ID_ADPCM_IMA_AMV: header_size = 8; break; @@ -863,6 +908,18 @@ static int adpcm_decode_frame(AVCodecContext *avctx, void *data, } } break; + case AV_CODEC_ID_ADPCM_AGM: + for (i = 0; i < avctx->channels; i++) + c->status[i].predictor = sign_extend(bytestream2_get_le16u(&gb), 16); + for (i = 0; i < avctx->channels; i++) + c->status[i].step = sign_extend(bytestream2_get_le16u(&gb), 16); + + for (n = 0; n < nb_samples >> (1 - st); n++) { + int v = bytestream2_get_byteu(&gb); + *samples++ = adpcm_agm_expand_nibble(&c->status[0], v & 0xF); + *samples++ = adpcm_agm_expand_nibble(&c->status[st], v >> 4 ); + } + break; case AV_CODEC_ID_ADPCM_MS: { int block_predictor; @@ -1679,7 +1736,7 @@ static int adpcm_decode_frame(AVCodecContext *avctx, void *data, break; default: - return -1; + av_assert0(0); // unsupported codec_id should not happen } if (avpkt->size && bytestream2_tell(&gb) == 0) { @@ -1729,6 +1786,7 @@ AVCodec ff_ ## name_ ## _decoder = { \ /* Note: Do not forget to add new entries to the Makefile as well. */ ADPCM_DECODER(AV_CODEC_ID_ADPCM_4XM, sample_fmts_s16p, adpcm_4xm, "ADPCM 4X Movie"); ADPCM_DECODER(AV_CODEC_ID_ADPCM_AFC, sample_fmts_s16p, adpcm_afc, "ADPCM Nintendo Gamecube AFC"); +ADPCM_DECODER(AV_CODEC_ID_ADPCM_AGM, sample_fmts_s16, adpcm_agm, "ADPCM AmuseGraphics Movie"); ADPCM_DECODER(AV_CODEC_ID_ADPCM_AICA, sample_fmts_s16p, adpcm_aica, "ADPCM Yamaha AICA"); ADPCM_DECODER(AV_CODEC_ID_ADPCM_CT, sample_fmts_s16, adpcm_ct, "ADPCM Creative Technology"); ADPCM_DECODER(AV_CODEC_ID_ADPCM_DTK, sample_fmts_s16p, adpcm_dtk, "ADPCM Nintendo Gamecube DTK"); diff --git a/libavcodec/agm.c b/libavcodec/agm.c new file mode 100644 index 000000000..2c4c9805e --- /dev/null +++ b/libavcodec/agm.c @@ -0,0 +1,1289 @@ +/* + * Amuse Graphics Movie decoder + * + * Copyright (c) 2018 Paul B Mahol + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include + +#define BITSTREAM_READER_LE + +#include "avcodec.h" +#include "bytestream.h" +#include "copy_block.h" +#include "get_bits.h" +#include "idctdsp.h" +#include "internal.h" + +static const uint8_t unscaled_luma[64] = { + 16, 11, 10, 16, 24, 40, 51, 61, 12, 12, 14, 19, + 26, 58, 60, 55, 14, 13, 16, 24, 40, 57, 69, 56, + 14, 17, 22, 29, 51, 87, 80, 62, 18, 22, 37, 56, + 68,109,103, 77, 24, 35, 55, 64, 81,104,113, 92, + 49, 64, 78, 87,103,121,120,101, 72, 92, 95, 98, + 112,100,103,99 +}; + +static const uint8_t unscaled_chroma[64] = { + 17, 18, 24, 47, 99, 99, 99, 99, 18, 21, 26, 66, + 99, 99, 99, 99, 24, 26, 56, 99, 99, 99, 99, 99, + 47, 66, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99 +}; + +typedef struct MotionVector { + int16_t x, y; +} MotionVector; + +typedef struct AGMContext { + const AVClass *class; + AVCodecContext *avctx; + GetBitContext gb; + GetByteContext gbyte; + + int key_frame; + int bitstream_size; + int compression; + int blocks_w; + int blocks_h; + int size[3]; + int plus; + int dct; + int rgb; + unsigned flags; + unsigned fflags; + + uint8_t *output; + unsigned padded_output_size; + unsigned output_size; + + MotionVector *mvectors; + unsigned mvectors_size; + + VLC vlc; + + AVFrame *prev_frame; + + int luma_quant_matrix[64]; + int chroma_quant_matrix[64]; + + ScanTable scantable; + DECLARE_ALIGNED(32, int16_t, block)[64]; + + int16_t *wblocks; + unsigned wblocks_size; + + int *map; + unsigned map_size; + + IDCTDSPContext idsp; +} AGMContext; + +static int read_code(GetBitContext *gb, int *oskip, int *level, int *map, int mode) +{ + int len = 0, skip = 0, max; + + if (get_bits_left(gb) < 2) + return AVERROR_INVALIDDATA; + + if (show_bits(gb, 2)) { + switch (show_bits(gb, 4)) { + case 1: + case 9: + len = 1; + skip = 3; + break; + case 2: + len = 3; + skip = 4; + break; + case 3: + len = 7; + skip = 4; + break; + case 5: + case 13: + len = 2; + skip = 3; + break; + case 6: + len = 4; + skip = 4; + break; + case 7: + len = 8; + skip = 4; + break; + case 10: + len = 5; + skip = 4; + break; + case 11: + len = 9; + skip = 4; + break; + case 14: + len = 6; + skip = 4; + break; + case 15: + len = ((show_bits(gb, 5) & 0x10) | 0xA0) >> 4; + skip = 5; + break; + default: + return AVERROR_INVALIDDATA; + } + + skip_bits(gb, skip); + *level = get_bits(gb, len); + *map = 1; + *oskip = 0; + max = 1 << (len - 1); + if (*level < max) + *level = -(max + *level); + } else if (show_bits(gb, 3) & 4) { + skip_bits(gb, 3); + if (mode == 1) { + if (show_bits(gb, 4)) { + if (show_bits(gb, 4) == 1) { + skip_bits(gb, 4); + *oskip = get_bits(gb, 16); + } else { + *oskip = get_bits(gb, 4); + } + } else { + skip_bits(gb, 4); + *oskip = get_bits(gb, 10); + } + } else if (mode == 0) { + *oskip = get_bits(gb, 10); + } + *level = 0; + } else { + skip_bits(gb, 3); + if (mode == 0) + *oskip = get_bits(gb, 4); + else if (mode == 1) + *oskip = 0; + *level = 0; + } + + return 0; +} + +static int decode_intra_blocks(AGMContext *s, GetBitContext *gb, + const int *quant_matrix, int *skip, int *dc_level) +{ + const uint8_t *scantable = s->scantable.permutated; + int level, ret, map = 0; + + memset(s->wblocks, 0, s->wblocks_size); + + for (int i = 0; i < 64; i++) { + int16_t *block = s->wblocks + scantable[i]; + + for (int j = 0; j < s->blocks_w;) { + if (*skip > 0) { + int rskip; + + rskip = FFMIN(*skip, s->blocks_w - j); + j += rskip; + if (i == 0) { + for (int k = 0; k < rskip; k++) + block[64 * k] = *dc_level * quant_matrix[0]; + } + block += rskip * 64; + *skip -= rskip; + } else { + ret = read_code(gb, skip, &level, &map, s->flags & 1); + if (ret < 0) + return ret; + + if (i == 0) + *dc_level += level; + + block[0] = (i == 0 ? *dc_level : level) * quant_matrix[i]; + block += 64; + j++; + } + } + } + + return 0; +} + +static int decode_inter_blocks(AGMContext *s, GetBitContext *gb, + const int *quant_matrix, int *skip, + int *map) +{ + const uint8_t *scantable = s->scantable.permutated; + int level, ret; + + memset(s->wblocks, 0, s->wblocks_size); + memset(s->map, 0, s->map_size); + + for (int i = 0; i < 64; i++) { + int16_t *block = s->wblocks + scantable[i]; + + for (int j = 0; j < s->blocks_w;) { + if (*skip > 0) { + int rskip; + + rskip = FFMIN(*skip, s->blocks_w - j); + j += rskip; + block += rskip * 64; + *skip -= rskip; + } else { + ret = read_code(gb, skip, &level, &map[j], s->flags & 1); + if (ret < 0) + return ret; + + block[0] = level * quant_matrix[i]; + block += 64; + j++; + } + } + } + + return 0; +} + +static int decode_intra_block(AGMContext *s, GetBitContext *gb, + const int *quant_matrix, int *skip, int *dc_level) +{ + const uint8_t *scantable = s->scantable.permutated; + const int offset = s->plus ? 0 : 1024; + int16_t *block = s->block; + int level, ret, map = 0; + + memset(block, 0, sizeof(s->block)); + + if (*skip > 0) { + (*skip)--; + } else { + ret = read_code(gb, skip, &level, &map, s->flags & 1); + if (ret < 0) + return ret; + *dc_level += level; + } + block[scantable[0]] = offset + *dc_level * quant_matrix[0]; + + for (int i = 1; i < 64;) { + if (*skip > 0) { + int rskip; + + rskip = FFMIN(*skip, 64 - i); + i += rskip; + *skip -= rskip; + } else { + ret = read_code(gb, skip, &level, &map, s->flags & 1); + if (ret < 0) + return ret; + + block[scantable[i]] = level * quant_matrix[i]; + i++; + } + } + + return 0; +} + +static int decode_intra_plane(AGMContext *s, GetBitContext *gb, int size, + const int *quant_matrix, AVFrame *frame, + int plane) +{ + int ret, skip = 0, dc_level = 0; + const int offset = s->plus ? 0 : 1024; + + if ((ret = init_get_bits8(gb, s->gbyte.buffer, size)) < 0) + return ret; + + if (s->flags & 1) { + av_fast_padded_malloc(&s->wblocks, &s->wblocks_size, + 64 * s->blocks_w * sizeof(*s->wblocks)); + if (!s->wblocks) + return AVERROR(ENOMEM); + + for (int y = 0; y < s->blocks_h; y++) { + ret = decode_intra_blocks(s, gb, quant_matrix, &skip, &dc_level); + if (ret < 0) + return ret; + + for (int x = 0; x < s->blocks_w; x++) { + s->wblocks[64 * x] += offset; + s->idsp.idct_put(frame->data[plane] + (s->blocks_h - 1 - y) * 8 * frame->linesize[plane] + x * 8, + frame->linesize[plane], s->wblocks + 64 * x); + } + } + } else { + for (int y = 0; y < s->blocks_h; y++) { + for (int x = 0; x < s->blocks_w; x++) { + ret = decode_intra_block(s, gb, quant_matrix, &skip, &dc_level); + if (ret < 0) + return ret; + + s->idsp.idct_put(frame->data[plane] + (s->blocks_h - 1 - y) * 8 * frame->linesize[plane] + x * 8, + frame->linesize[plane], s->block); + } + } + } + + align_get_bits(gb); + if (get_bits_left(gb) < 0) + av_log(s->avctx, AV_LOG_WARNING, "overread\n"); + if (get_bits_left(gb) > 0) + av_log(s->avctx, AV_LOG_WARNING, "underread: %d\n", get_bits_left(gb)); + + return 0; +} + +static int decode_inter_block(AGMContext *s, GetBitContext *gb, + const int *quant_matrix, int *skip, + int *map) +{ + const uint8_t *scantable = s->scantable.permutated; + int16_t *block = s->block; + int level, ret; + + memset(block, 0, sizeof(s->block)); + + for (int i = 0; i < 64;) { + if (*skip > 0) { + int rskip; + + rskip = FFMIN(*skip, 64 - i); + i += rskip; + *skip -= rskip; + } else { + ret = read_code(gb, skip, &level, map, s->flags & 1); + if (ret < 0) + return ret; + + block[scantable[i]] = level * quant_matrix[i]; + i++; + } + } + + return 0; +} + +static int decode_inter_plane(AGMContext *s, GetBitContext *gb, int size, + const int *quant_matrix, AVFrame *frame, + AVFrame *prev, int plane) +{ + int ret, skip = 0; + + if ((ret = init_get_bits8(gb, s->gbyte.buffer, size)) < 0) + return ret; + + if (s->flags == 3) { + av_fast_padded_malloc(&s->wblocks, &s->wblocks_size, + 64 * s->blocks_w * sizeof(*s->wblocks)); + if (!s->wblocks) + return AVERROR(ENOMEM); + + av_fast_padded_malloc(&s->map, &s->map_size, + s->blocks_w * sizeof(*s->map)); + if (!s->map) + return AVERROR(ENOMEM); + + for (int y = 0; y < s->blocks_h; y++) { + ret = decode_inter_blocks(s, gb, quant_matrix, &skip, s->map); + if (ret < 0) + return ret; + + for (int x = 0; x < s->blocks_w; x++) { + int shift = plane == 0; + int mvpos = (y >> shift) * (s->blocks_w >> shift) + (x >> shift); + int orig_mv_x = s->mvectors[mvpos].x; + int mv_x = s->mvectors[mvpos].x / (1 + !shift); + int mv_y = s->mvectors[mvpos].y / (1 + !shift); + int h = s->avctx->coded_height >> !shift; + int w = s->avctx->coded_width >> !shift; + int map = s->map[x]; + + if (orig_mv_x >= -32) { + if (y * 8 + mv_y < 0 || y * 8 + mv_y >= h || + x * 8 + mv_x < 0 || x * 8 + mv_x >= w) + return AVERROR_INVALIDDATA; + + copy_block8(frame->data[plane] + (s->blocks_h - 1 - y) * 8 * frame->linesize[plane] + x * 8, + prev->data[plane] + ((s->blocks_h - 1 - y) * 8 - mv_y) * prev->linesize[plane] + (x * 8 + mv_x), + frame->linesize[plane], prev->linesize[plane], 8); + if (map) { + s->idsp.idct(s->wblocks + x * 64); + for (int i = 0; i < 64; i++) + s->wblocks[i + x * 64] = (s->wblocks[i + x * 64] + 1) & 0xFFFC; + s->idsp.add_pixels_clamped(&s->wblocks[x*64], frame->data[plane] + (s->blocks_h - 1 - y) * 8 * frame->linesize[plane] + x * 8, + frame->linesize[plane]); + } + } else if (map) { + s->idsp.idct_put(frame->data[plane] + (s->blocks_h - 1 - y) * 8 * frame->linesize[plane] + x * 8, + frame->linesize[plane], s->wblocks + x * 64); + } + } + } + } else if (s->flags & 2) { + for (int y = 0; y < s->blocks_h; y++) { + for (int x = 0; x < s->blocks_w; x++) { + int shift = plane == 0; + int mvpos = (y >> shift) * (s->blocks_w >> shift) + (x >> shift); + int orig_mv_x = s->mvectors[mvpos].x; + int mv_x = s->mvectors[mvpos].x / (1 + !shift); + int mv_y = s->mvectors[mvpos].y / (1 + !shift); + int h = s->avctx->coded_height >> !shift; + int w = s->avctx->coded_width >> !shift; + int map = 0; + + ret = decode_inter_block(s, gb, quant_matrix, &skip, &map); + if (ret < 0) + return ret; + + if (orig_mv_x >= -32) { + if (y * 8 + mv_y < 0 || y * 8 + mv_y >= h || + x * 8 + mv_x < 0 || x * 8 + mv_x >= w) + return AVERROR_INVALIDDATA; + + copy_block8(frame->data[plane] + (s->blocks_h - 1 - y) * 8 * frame->linesize[plane] + x * 8, + prev->data[plane] + ((s->blocks_h - 1 - y) * 8 - mv_y) * prev->linesize[plane] + (x * 8 + mv_x), + frame->linesize[plane], prev->linesize[plane], 8); + if (map) { + s->idsp.idct(s->block); + for (int i = 0; i < 64; i++) + s->block[i] = (s->block[i] + 1) & 0xFFFC; + s->idsp.add_pixels_clamped(s->block, frame->data[plane] + (s->blocks_h - 1 - y) * 8 * frame->linesize[plane] + x * 8, + frame->linesize[plane]); + } + } else if (map) { + s->idsp.idct_put(frame->data[plane] + (s->blocks_h - 1 - y) * 8 * frame->linesize[plane] + x * 8, + frame->linesize[plane], s->block); + } + } + } + } else if (s->flags & 1) { + av_fast_padded_malloc(&s->wblocks, &s->wblocks_size, + 64 * s->blocks_w * sizeof(*s->wblocks)); + if (!s->wblocks) + return AVERROR(ENOMEM); + + av_fast_padded_malloc(&s->map, &s->map_size, + s->blocks_w * sizeof(*s->map)); + if (!s->map) + return AVERROR(ENOMEM); + + for (int y = 0; y < s->blocks_h; y++) { + ret = decode_inter_blocks(s, gb, quant_matrix, &skip, s->map); + if (ret < 0) + return ret; + + for (int x = 0; x < s->blocks_w; x++) { + if (!s->map[x]) + continue; + s->idsp.idct_add(frame->data[plane] + (s->blocks_h - 1 - y) * 8 * frame->linesize[plane] + x * 8, + frame->linesize[plane], s->wblocks + 64 * x); + } + } + } else { + for (int y = 0; y < s->blocks_h; y++) { + for (int x = 0; x < s->blocks_w; x++) { + int map = 0; + + ret = decode_inter_block(s, gb, quant_matrix, &skip, &map); + if (ret < 0) + return ret; + + if (!map) + continue; + s->idsp.idct_add(frame->data[plane] + (s->blocks_h - 1 - y) * 8 * frame->linesize[plane] + x * 8, + frame->linesize[plane], s->block); + } + } + } + + align_get_bits(gb); + if (get_bits_left(gb) < 0) + av_log(s->avctx, AV_LOG_WARNING, "overread\n"); + if (get_bits_left(gb) > 0) + av_log(s->avctx, AV_LOG_WARNING, "underread: %d\n", get_bits_left(gb)); + + return 0; +} + +static void compute_quant_matrix(AGMContext *s, double qscale) +{ + int luma[64], chroma[64]; + double f = 1.0 - fabs(qscale); + + if (!s->key_frame && (s->flags & 2)) { + if (qscale >= 0.0) { + for (int i = 0; i < 64; i++) { + luma[i] = FFMAX(1, 16 * f); + chroma[i] = FFMAX(1, 16 * f); + } + } else { + for (int i = 0; i < 64; i++) { + luma[i] = FFMAX(1, 16 - qscale * 32); + chroma[i] = FFMAX(1, 16 - qscale * 32); + } + } + } else { + if (qscale >= 0.0) { + for (int i = 0; i < 64; i++) { + luma[i] = FFMAX(1, unscaled_luma [(i & 7) * 8 + (i >> 3)] * f); + chroma[i] = FFMAX(1, unscaled_chroma[(i & 7) * 8 + (i >> 3)] * f); + } + } else { + for (int i = 0; i < 64; i++) { + luma[i] = FFMAX(1, 255.0 - (255 - unscaled_luma [(i & 7) * 8 + (i >> 3)]) * f); + chroma[i] = FFMAX(1, 255.0 - (255 - unscaled_chroma[(i & 7) * 8 + (i >> 3)]) * f); + } + } + } + + for (int i = 0; i < 64; i++) { + int pos = ff_zigzag_direct[i]; + + s->luma_quant_matrix[i] = luma[pos] * ((pos / 8) & 1 ? -1 : 1); + s->chroma_quant_matrix[i] = chroma[pos] * ((pos / 8) & 1 ? -1 : 1); + } +} + +static int decode_raw_intra_rgb(AVCodecContext *avctx, GetByteContext *gbyte, AVFrame *frame) +{ + uint8_t *dst = frame->data[0] + (avctx->height - 1) * frame->linesize[0]; + uint8_t r = 0, g = 0, b = 0; + + for (int y = 0; y < avctx->height; y++) { + for (int x = 0; x < avctx->width; x++) { + dst[x*3+0] = bytestream2_get_byte(gbyte) + r; + r = dst[x*3+0]; + dst[x*3+1] = bytestream2_get_byte(gbyte) + g; + g = dst[x*3+1]; + dst[x*3+2] = bytestream2_get_byte(gbyte) + b; + b = dst[x*3+2]; + } + dst -= frame->linesize[0]; + } + + return 0; +} + +static int fill_pixels(uint8_t **y0, uint8_t **y1, + uint8_t **u, uint8_t **v, + int ylinesize, int ulinesize, int vlinesize, + uint8_t *fill, + int *nx, int *ny, int *np, int w, int h) +{ + uint8_t *y0dst = *y0; + uint8_t *y1dst = *y1; + uint8_t *udst = *u; + uint8_t *vdst = *v; + int x = *nx, y = *ny, pos = *np; + + if (pos == 0) { + y0dst[2*x+0] += fill[0]; + y0dst[2*x+1] += fill[1]; + y1dst[2*x+0] += fill[2]; + y1dst[2*x+1] += fill[3]; + pos++; + } else if (pos == 1) { + udst[x] += fill[0]; + vdst[x] += fill[1]; + x++; + if (x >= w) { + x = 0; + y++; + if (y >= h) + return 1; + y0dst -= 2*ylinesize; + y1dst -= 2*ylinesize; + udst -= ulinesize; + vdst -= vlinesize; + } + y0dst[2*x+0] += fill[2]; + y0dst[2*x+1] += fill[3]; + pos++; + } else if (pos == 2) { + y1dst[2*x+0] += fill[0]; + y1dst[2*x+1] += fill[1]; + udst[x] += fill[2]; + vdst[x] += fill[3]; + x++; + if (x >= w) { + x = 0; + y++; + if (y >= h) + return 1; + y0dst -= 2*ylinesize; + y1dst -= 2*ylinesize; + udst -= ulinesize; + vdst -= vlinesize; + } + pos = 0; + } + + *y0 = y0dst; + *y1 = y1dst; + *u = udst; + *v = vdst; + *np = pos; + *nx = x; + *ny = y; + + return 0; +} + +static int decode_runlen_rgb(AVCodecContext *avctx, GetByteContext *gbyte, AVFrame *frame) +{ + uint8_t *dst = frame->data[0] + (avctx->height - 1) * frame->linesize[0]; + int runlen, y = 0, x = 0; + uint8_t fill[4]; + unsigned code; + + while (bytestream2_get_bytes_left(gbyte) > 0) { + code = bytestream2_peek_le32(gbyte); + runlen = code & 0xFFFFFF; + + if (code >> 24 == 0x77) { + bytestream2_skip(gbyte, 4); + + for (int i = 0; i < 4; i++) + fill[i] = bytestream2_get_byte(gbyte); + + while (runlen > 0) { + runlen--; + + for (int i = 0; i < 4; i++) { + dst[x] += fill[i]; + x++; + if (x >= frame->width * 3) { + x = 0; + y++; + dst -= frame->linesize[0]; + if (y >= frame->height) + return 0; + } + } + } + } else { + for (int i = 0; i < 4; i++) + fill[i] = bytestream2_get_byte(gbyte); + + for (int i = 0; i < 4; i++) { + dst[x] += fill[i]; + x++; + if (x >= frame->width * 3) { + x = 0; + y++; + dst -= frame->linesize[0]; + if (y >= frame->height) + return 0; + } + } + } + } + + return 0; +} + +static int decode_runlen(AVCodecContext *avctx, GetByteContext *gbyte, AVFrame *frame) +{ + uint8_t *y0dst = frame->data[0] + (avctx->height - 1) * frame->linesize[0]; + uint8_t *y1dst = y0dst - frame->linesize[0]; + uint8_t *udst = frame->data[1] + ((avctx->height >> 1) - 1) * frame->linesize[1]; + uint8_t *vdst = frame->data[2] + ((avctx->height >> 1) - 1) * frame->linesize[2]; + int runlen, y = 0, x = 0, pos = 0; + uint8_t fill[4]; + unsigned code; + + while (bytestream2_get_bytes_left(gbyte) > 0) { + code = bytestream2_peek_le32(gbyte); + runlen = code & 0xFFFFFF; + + if (code >> 24 == 0x77) { + bytestream2_skip(gbyte, 4); + + for (int i = 0; i < 4; i++) + fill[i] = bytestream2_get_byte(gbyte); + + while (runlen > 0) { + runlen--; + + if (fill_pixels(&y0dst, &y1dst, &udst, &vdst, + frame->linesize[0], + frame->linesize[1], + frame->linesize[2], + fill, &x, &y, &pos, + avctx->width / 2, + avctx->height / 2)) + return 0; + } + } else { + for (int i = 0; i < 4; i++) + fill[i] = bytestream2_get_byte(gbyte); + + if (fill_pixels(&y0dst, &y1dst, &udst, &vdst, + frame->linesize[0], + frame->linesize[1], + frame->linesize[2], + fill, &x, &y, &pos, + avctx->width / 2, + avctx->height / 2)) + return 0; + } + } + + return 0; +} + +static int decode_raw_intra(AVCodecContext *avctx, GetByteContext *gbyte, AVFrame *frame) +{ + uint8_t *y0dst = frame->data[0] + (avctx->height - 1) * frame->linesize[0]; + uint8_t *y1dst = y0dst - frame->linesize[0]; + uint8_t *udst = frame->data[1] + ((avctx->height >> 1) - 1) * frame->linesize[1]; + uint8_t *vdst = frame->data[2] + ((avctx->height >> 1) - 1) * frame->linesize[2]; + uint8_t ly0 = 0, ly1 = 0, ly2 = 0, ly3 = 0, lu = 0, lv = 0; + + for (int y = 0; y < avctx->height / 2; y++) { + for (int x = 0; x < avctx->width / 2; x++) { + y0dst[x*2+0] = bytestream2_get_byte(gbyte) + ly0; + ly0 = y0dst[x*2+0]; + y0dst[x*2+1] = bytestream2_get_byte(gbyte) + ly1; + ly1 = y0dst[x*2+1]; + y1dst[x*2+0] = bytestream2_get_byte(gbyte) + ly2; + ly2 = y1dst[x*2+0]; + y1dst[x*2+1] = bytestream2_get_byte(gbyte) + ly3; + ly3 = y1dst[x*2+1]; + udst[x] = bytestream2_get_byte(gbyte) + lu; + lu = udst[x]; + vdst[x] = bytestream2_get_byte(gbyte) + lv; + lv = vdst[x]; + } + + y0dst -= 2*frame->linesize[0]; + y1dst -= 2*frame->linesize[0]; + udst -= frame->linesize[1]; + vdst -= frame->linesize[2]; + } + + return 0; +} + +static int decode_intra(AVCodecContext *avctx, GetBitContext *gb, AVFrame *frame) +{ + AGMContext *s = avctx->priv_data; + int ret; + + compute_quant_matrix(s, (2 * s->compression - 100) / 100.0); + + s->blocks_w = avctx->coded_width >> 3; + s->blocks_h = avctx->coded_height >> 3; + + ret = decode_intra_plane(s, gb, s->size[0], s->luma_quant_matrix, frame, 0); + if (ret < 0) + return ret; + + bytestream2_skip(&s->gbyte, s->size[0]); + + s->blocks_w = avctx->coded_width >> 4; + s->blocks_h = avctx->coded_height >> 4; + + ret = decode_intra_plane(s, gb, s->size[1], s->chroma_quant_matrix, frame, 2); + if (ret < 0) + return ret; + + bytestream2_skip(&s->gbyte, s->size[1]); + + s->blocks_w = avctx->coded_width >> 4; + s->blocks_h = avctx->coded_height >> 4; + + ret = decode_intra_plane(s, gb, s->size[2], s->chroma_quant_matrix, frame, 1); + if (ret < 0) + return ret; + + return 0; +} + +static int decode_motion_vectors(AVCodecContext *avctx, GetBitContext *gb) +{ + AGMContext *s = avctx->priv_data; + int nb_mvs = ((avctx->height + 15) >> 4) * ((avctx->width + 15) >> 4); + int ret, skip = 0, value, map; + + av_fast_padded_malloc(&s->mvectors, &s->mvectors_size, + nb_mvs * sizeof(*s->mvectors)); + if (!s->mvectors) + return AVERROR(ENOMEM); + + if ((ret = init_get_bits8(gb, s->gbyte.buffer, bytestream2_get_bytes_left(&s->gbyte) - + (s->size[0] + s->size[1] + s->size[2]))) < 0) + return ret; + + memset(s->mvectors, 0, sizeof(*s->mvectors) * nb_mvs); + + for (int i = 0; i < nb_mvs; i++) { + ret = read_code(gb, &skip, &value, &map, 1); + if (ret < 0) + return ret; + s->mvectors[i].x = value; + i += skip; + } + + for (int i = 0; i < nb_mvs; i++) { + ret = read_code(gb, &skip, &value, &map, 1); + if (ret < 0) + return ret; + s->mvectors[i].y = value; + i += skip; + } + + if (get_bits_left(gb) <= 0) + return AVERROR_INVALIDDATA; + skip = (get_bits_count(gb) >> 3) + 1; + bytestream2_skip(&s->gbyte, skip); + + return 0; +} + +static int decode_inter(AVCodecContext *avctx, GetBitContext *gb, + AVFrame *frame, AVFrame *prev) +{ + AGMContext *s = avctx->priv_data; + int ret; + + compute_quant_matrix(s, (2 * s->compression - 100) / 100.0); + + if (s->flags & 2) { + ret = decode_motion_vectors(avctx, gb); + if (ret < 0) + return ret; + } + + s->blocks_w = avctx->coded_width >> 3; + s->blocks_h = avctx->coded_height >> 3; + + ret = decode_inter_plane(s, gb, s->size[0], s->luma_quant_matrix, frame, prev, 0); + if (ret < 0) + return ret; + + bytestream2_skip(&s->gbyte, s->size[0]); + + s->blocks_w = avctx->coded_width >> 4; + s->blocks_h = avctx->coded_height >> 4; + + ret = decode_inter_plane(s, gb, s->size[1], s->chroma_quant_matrix, frame, prev, 2); + if (ret < 0) + return ret; + + bytestream2_skip(&s->gbyte, s->size[1]); + + s->blocks_w = avctx->coded_width >> 4; + s->blocks_h = avctx->coded_height >> 4; + + ret = decode_inter_plane(s, gb, s->size[2], s->chroma_quant_matrix, frame, prev, 1); + if (ret < 0) + return ret; + + return 0; +} + +typedef struct Node { + int parent; + int child[2]; +} Node; + +static void get_tree_codes(uint32_t *codes, Node *nodes, int idx, uint32_t pfx, int bitpos) +{ + if (idx < 256 && idx >= 0) { + codes[idx] = pfx; + } else if (idx >= 0) { + get_tree_codes(codes, nodes, nodes[idx].child[0], pfx + (0 << bitpos), bitpos + 1); + get_tree_codes(codes, nodes, nodes[idx].child[1], pfx + (1U << bitpos), bitpos + 1); + } +} + +static int make_new_tree(const uint8_t *bitlens, uint32_t *codes) +{ + int zlcount = 0, curlen, idx, nindex, last, llast; + int blcounts[32] = { 0 }; + int syms[8192]; + Node nodes[512]; + int node_idx[1024]; + int old_idx[512]; + + for (int i = 0; i < 256; i++) { + int bitlen = bitlens[i]; + int blcount = blcounts[bitlen]; + + zlcount += bitlen < 1; + syms[(bitlen << 8) + blcount] = i; + blcounts[bitlen]++; + } + + for (int i = 0; i < 512; i++) { + nodes[i].child[0] = -1; + nodes[i].child[1] = -1; + } + + for (int i = 0; i < 256; i++) { + node_idx[i] = 257 + i; + } + + curlen = 1; + node_idx[512] = 256; + last = 255; + nindex = 1; + + for (curlen = 1; curlen < 32; curlen++) { + if (blcounts[curlen] > 0) { + int max_zlcount = zlcount + blcounts[curlen]; + + for (int i = 0; zlcount < 256 && zlcount < max_zlcount; zlcount++, i++) { + int p = node_idx[nindex - 1 + 512]; + int ch = syms[256 * curlen + i]; + + if (nindex <= 0) + return AVERROR_INVALIDDATA; + + if (nodes[p].child[0] == -1) { + nodes[p].child[0] = ch; + } else { + nodes[p].child[1] = ch; + nindex--; + } + nodes[ch].parent = p; + } + } + llast = last - 1; + idx = 0; + while (nindex > 0) { + int p, ch; + + last = llast - idx; + p = node_idx[nindex - 1 + 512]; + ch = node_idx[last]; + if (nodes[p].child[0] == -1) { + nodes[p].child[0] = ch; + } else { + nodes[p].child[1] = ch; + nindex--; + } + old_idx[idx] = ch; + nodes[ch].parent = p; + if (idx == llast) + goto next; + idx++; + if (nindex <= 0) { + for (int i = 0; i < idx; i++) + node_idx[512 + i] = old_idx[i]; + } + } + nindex = idx; + } + +next: + + get_tree_codes(codes, nodes, 256, 0, 0); + return 0; +} + +static int build_huff(const uint8_t *bitlen, VLC *vlc) +{ + uint32_t new_codes[256]; + uint8_t bits[256]; + uint8_t symbols[256]; + uint32_t codes[256]; + int nb_codes = 0; + + int ret = make_new_tree(bitlen, new_codes); + if (ret < 0) + return ret; + + for (int i = 0; i < 256; i++) { + if (bitlen[i]) { + bits[nb_codes] = bitlen[i]; + codes[nb_codes] = new_codes[i]; + symbols[nb_codes] = i; + nb_codes++; + } + } + + ff_free_vlc(vlc); + return ff_init_vlc_sparse(vlc, 13, nb_codes, + bits, 1, 1, + codes, 4, 4, + symbols, 1, 1, + INIT_VLC_LE); +} + +static int decode_huffman2(AVCodecContext *avctx, int header, int size) +{ + AGMContext *s = avctx->priv_data; + GetBitContext *gb = &s->gb; + uint8_t lens[256]; + int ret, x, len; + + if ((ret = init_get_bits8(gb, s->gbyte.buffer, + bytestream2_get_bytes_left(&s->gbyte))) < 0) + return ret; + + s->output_size = get_bits_long(gb, 32); + + if (s->output_size > avctx->width * avctx->height * 9LL + 10000) + return AVERROR_INVALIDDATA; + + av_fast_padded_malloc(&s->output, &s->padded_output_size, s->output_size); + if (!s->output) + return AVERROR(ENOMEM); + + x = get_bits(gb, 1); + len = 4 + get_bits(gb, 1); + if (x) { + int cb[8] = { 0 }; + int count = get_bits(gb, 3) + 1; + + for (int i = 0; i < count; i++) + cb[i] = get_bits(gb, len); + + for (int i = 0; i < 256; i++) { + int idx = get_bits(gb, 3); + lens[i] = cb[idx]; + } + } else { + for (int i = 0; i < 256; i++) + lens[i] = get_bits(gb, len); + } + + if ((ret = build_huff(lens, &s->vlc)) < 0) + return ret; + + x = 0; + while (get_bits_left(gb) > 0 && x < s->output_size) { + int val = get_vlc2(gb, s->vlc.table, s->vlc.bits, 3); + if (val < 0) + return AVERROR_INVALIDDATA; + s->output[x++] = val; + } + + return 0; +} + +static int decode_frame(AVCodecContext *avctx, void *data, + int *got_frame, AVPacket *avpkt) +{ + AGMContext *s = avctx->priv_data; + GetBitContext *gb = &s->gb; + GetByteContext *gbyte = &s->gbyte; + AVFrame *frame = data; + int w, h, width, height, header; + unsigned compressed_size; + long skip; + int ret; + + if (!avpkt->size) + return 0; + + bytestream2_init(gbyte, avpkt->data, avpkt->size); + + header = bytestream2_get_le32(gbyte); + s->fflags = bytestream2_get_le32(gbyte); + s->bitstream_size = s->fflags & 0x1FFFFFFF; + s->fflags >>= 29; + av_log(avctx, AV_LOG_DEBUG, "fflags: %X\n", s->fflags); + if (avpkt->size < s->bitstream_size + 8) + return AVERROR_INVALIDDATA; + + s->key_frame = (avpkt->flags & AV_PKT_FLAG_KEY); + frame->key_frame = s->key_frame; + frame->pict_type = s->key_frame ? AV_PICTURE_TYPE_I : AV_PICTURE_TYPE_P; + + if (header) { + if (avctx->codec_tag == MKTAG('A', 'G', 'M', '0') || + avctx->codec_tag == MKTAG('A', 'G', 'M', '1')) + return AVERROR_PATCHWELCOME; + else + ret = decode_huffman2(avctx, header, (avpkt->size - s->bitstream_size) - 8); + if (ret < 0) + return ret; + bytestream2_init(gbyte, s->output, s->output_size); + } else if (!s->dct) { + bytestream2_skip(gbyte, 4); + } + + if (s->dct) { + s->flags = 0; + w = bytestream2_get_le32(gbyte); + h = bytestream2_get_le32(gbyte); + if (w == INT32_MIN || h == INT32_MIN) + return AVERROR_INVALIDDATA; + if (w < 0) { + w = -w; + s->flags |= 2; + } + if (h < 0) { + h = -h; + s->flags |= 1; + } + + width = avctx->width; + height = avctx->height; + if (w < width || h < height || w & 7 || h & 7) + return AVERROR_INVALIDDATA; + + ret = ff_set_dimensions(avctx, w, h); + if (ret < 0) + return ret; + avctx->width = width; + avctx->height = height; + + s->compression = bytestream2_get_le32(gbyte); + if (s->compression < 0 || s->compression > 100) + return AVERROR_INVALIDDATA; + + for (int i = 0; i < 3; i++) + s->size[i] = bytestream2_get_le32(gbyte); + if (header) { + compressed_size = s->output_size; + skip = 8LL; + } else { + compressed_size = avpkt->size; + skip = 32LL; + } + if (s->size[0] < 0 || s->size[1] < 0 || s->size[2] < 0 || + skip + s->size[0] + s->size[1] + s->size[2] > compressed_size) { + return AVERROR_INVALIDDATA; + } + } + + if ((ret = ff_get_buffer(avctx, frame, AV_GET_BUFFER_FLAG_REF)) < 0) + return ret; + + if (frame->key_frame) { + if (!s->dct && !s->rgb) + ret = decode_raw_intra(avctx, gbyte, frame); + else if (!s->dct && s->rgb) + ret = decode_raw_intra_rgb(avctx, gbyte, frame); + else + ret = decode_intra(avctx, gb, frame); + } else { + if (!s->prev_frame->data[0]) { + av_log(avctx, AV_LOG_ERROR, "Missing reference frame.\n"); + return AVERROR_INVALIDDATA; + } + if (s->prev_frame-> width != frame->width || + s->prev_frame->height != frame->height) + return AVERROR_INVALIDDATA; + + if (!(s->flags & 2)) { + ret = av_frame_copy(frame, s->prev_frame); + if (ret < 0) + return ret; + } + + if (s->dct) { + ret = decode_inter(avctx, gb, frame, s->prev_frame); + } else if (!s->dct && !s->rgb) { + ret = decode_runlen(avctx, gbyte, frame); + } else { + ret = decode_runlen_rgb(avctx, gbyte, frame); + } + } + if (ret < 0) + return ret; + + av_frame_unref(s->prev_frame); + if ((ret = av_frame_ref(s->prev_frame, frame)) < 0) + return ret; + + frame->crop_top = avctx->coded_height - avctx->height; + frame->crop_left = avctx->coded_width - avctx->width; + + *got_frame = 1; + + return avpkt->size; +} + +static av_cold int decode_init(AVCodecContext *avctx) +{ + AGMContext *s = avctx->priv_data; + + s->rgb = avctx->codec_tag == MKTAG('A', 'G', 'M', '4'); + avctx->pix_fmt = s->rgb ? AV_PIX_FMT_BGR24 : AV_PIX_FMT_YUV420P; + s->avctx = avctx; + s->plus = avctx->codec_tag == MKTAG('A', 'G', 'M', '3') || + avctx->codec_tag == MKTAG('A', 'G', 'M', '7'); + + s->dct = avctx->codec_tag != MKTAG('A', 'G', 'M', '4') && + avctx->codec_tag != MKTAG('A', 'G', 'M', '5'); + + avctx->idct_algo = FF_IDCT_SIMPLE; + ff_idctdsp_init(&s->idsp, avctx); + ff_init_scantable(s->idsp.idct_permutation, &s->scantable, ff_zigzag_direct); + + s->prev_frame = av_frame_alloc(); + if (!s->prev_frame) + return AVERROR(ENOMEM); + + return 0; +} + +static void decode_flush(AVCodecContext *avctx) +{ + AGMContext *s = avctx->priv_data; + + av_frame_unref(s->prev_frame); +} + +static av_cold int decode_close(AVCodecContext *avctx) +{ + AGMContext *s = avctx->priv_data; + + ff_free_vlc(&s->vlc); + av_frame_free(&s->prev_frame); + av_freep(&s->mvectors); + s->mvectors_size = 0; + av_freep(&s->wblocks); + s->wblocks_size = 0; + av_freep(&s->output); + s->padded_output_size = 0; + av_freep(&s->map); + s->map_size = 0; + + return 0; +} + +AVCodec ff_agm_decoder = { + .name = "agm", + .long_name = NULL_IF_CONFIG_SMALL("Amuse Graphics Movie"), + .type = AVMEDIA_TYPE_VIDEO, + .id = AV_CODEC_ID_AGM, + .priv_data_size = sizeof(AGMContext), + .init = decode_init, + .close = decode_close, + .decode = decode_frame, + .flush = decode_flush, + .capabilities = AV_CODEC_CAP_DR1, + .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE | + FF_CODEC_CAP_INIT_CLEANUP | + FF_CODEC_CAP_EXPORTS_CROPPING, +}; diff --git a/libavcodec/aic.c b/libavcodec/aic.c index dc28c8366..956d71fcf 100644 --- a/libavcodec/aic.c +++ b/libavcodec/aic.c @@ -42,9 +42,9 @@ enum AICBands { NUM_BANDS }; -static const int aic_num_band_coeffs[NUM_BANDS] = { 64, 32, 192, 96 }; +static const uint8_t aic_num_band_coeffs[NUM_BANDS] = { 64, 32, 192, 96 }; -static const int aic_band_off[NUM_BANDS] = { 0, 64, 96, 288 }; +static const uint16_t aic_band_off[NUM_BANDS] = { 0, 64, 96, 288 }; static const uint8_t aic_quant_matrix[64] = { 8, 16, 19, 22, 22, 26, 26, 27, diff --git a/libavcodec/alac.c b/libavcodec/alac.c index 93cf198ee..782d461b2 100644 --- a/libavcodec/alac.c +++ b/libavcodec/alac.c @@ -121,7 +121,7 @@ static int rice_decompress(ALACContext *alac, int32_t *output_buffer, unsigned int x; if(get_bits_left(&alac->gb) <= 0) - return -1; + return AVERROR_INVALIDDATA; /* calculate rice param and decode next value */ k = av_log2((history >> 9) + 3); @@ -171,12 +171,12 @@ static inline int sign_only(int v) return v ? FFSIGN(v) : 0; } -static void lpc_prediction(int32_t *error_buffer, int32_t *buffer_out, +static void lpc_prediction(int32_t *error_buffer, uint32_t *buffer_out, int nb_samples, int bps, int16_t *lpc_coefs, int lpc_order, int lpc_quant) { int i; - int32_t *pred = buffer_out; + uint32_t *pred = buffer_out; /* first sample always copies */ *buffer_out = *error_buffer; @@ -208,7 +208,7 @@ static void lpc_prediction(int32_t *error_buffer, int32_t *buffer_out, for (; i < nb_samples; i++) { int j; int val = 0; - int error_val = error_buffer[i]; + unsigned error_val = error_buffer[i]; int error_sign; int d = *pred++; @@ -222,7 +222,7 @@ static void lpc_prediction(int32_t *error_buffer, int32_t *buffer_out, /* adapt LPC coefficients */ error_sign = sign_only(error_val); if (error_sign) { - for (j = 0; j < lpc_order && error_val * error_sign > 0; j++) { + for (j = 0; j < lpc_order && (int)error_val * error_sign > 0; j++) { int sign; val = d - pred[j]; sign = sign_only(val) * error_sign; @@ -250,10 +250,12 @@ static int decode_element(AVCodecContext *avctx, AVFrame *frame, int ch_index, alac->extra_bits = get_bits(&alac->gb, 2) << 3; bps = alac->sample_size - alac->extra_bits + channels - 1; - if (bps > 32U) { + if (bps > 32) { avpriv_report_missing_feature(avctx, "bps %d", bps); return AVERROR_PATCHWELCOME; } + if (bps < 1) + return AVERROR_INVALIDDATA; /* whether the frame is compressed */ is_compressed = !get_bits1(&alac->gb); @@ -306,7 +308,7 @@ static int decode_element(AVCodecContext *avctx, AVFrame *frame, int ch_index, rice_history_mult[ch] = get_bits(&alac->gb, 3); lpc_order[ch] = get_bits(&alac->gb, 5); - if (lpc_order[ch] >= alac->max_samples_per_frame) + if (lpc_order[ch] >= alac->max_samples_per_frame || !lpc_quant[ch]) return AVERROR_INVALIDDATA; /* read the predictor table */ @@ -317,7 +319,7 @@ static int decode_element(AVCodecContext *avctx, AVFrame *frame, int ch_index, if (alac->extra_bits) { for (i = 0; i < alac->nb_samples; i++) { if(get_bits_left(&alac->gb) <= 0) - return -1; + return AVERROR_INVALIDDATA; for (ch = 0; ch < channels; ch++) alac->extra_bits_buffer[ch][i] = get_bits(&alac->gb, alac->extra_bits); } @@ -353,7 +355,7 @@ static int decode_element(AVCodecContext *avctx, AVFrame *frame, int ch_index, /* not compressed, easy case */ for (i = 0; i < alac->nb_samples; i++) { if(get_bits_left(&alac->gb) <= 0) - return -1; + return AVERROR_INVALIDDATA; for (ch = 0; ch < channels; ch++) { alac->output_samples_buffer[ch][i] = get_sbits_long(&alac->gb, alac->sample_size); @@ -486,7 +488,7 @@ static av_cold int alac_decode_close(AVCodecContext *avctx) static int allocate_buffers(ALACContext *alac) { int ch; - int buf_size = alac->max_samples_per_frame * sizeof(int32_t); + unsigned buf_size = alac->max_samples_per_frame * sizeof(int32_t); for (ch = 0; ch < 2; ch++) { alac->predict_error_buffer[ch] = NULL; @@ -555,9 +557,9 @@ static av_cold int alac_decode_init(AVCodecContext * avctx) av_log(avctx, AV_LOG_ERROR, "extradata is too small\n"); return AVERROR_INVALIDDATA; } - if (alac_set_info(alac)) { + if ((ret = alac_set_info(alac)) < 0) { av_log(avctx, AV_LOG_ERROR, "set_info failed\n"); - return -1; + return ret; } switch (alac->sample_size) { diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c index 4d4ef530e..d2f9a39ce 100644 --- a/libavcodec/allcodecs.c +++ b/libavcodec/allcodecs.c @@ -35,12 +35,14 @@ extern AVCodec ff_aasc_decoder; extern AVCodec ff_aic_decoder; extern AVCodec ff_alias_pix_encoder; extern AVCodec ff_alias_pix_decoder; +extern AVCodec ff_agm_decoder; extern AVCodec ff_amv_encoder; extern AVCodec ff_amv_decoder; extern AVCodec ff_anm_decoder; extern AVCodec ff_ansi_decoder; extern AVCodec ff_apng_encoder; extern AVCodec ff_apng_decoder; +extern AVCodec ff_arbc_decoder; extern AVCodec ff_asv1_encoder; extern AVCodec ff_asv1_decoder; extern AVCodec ff_asv2_encoder; @@ -58,6 +60,7 @@ extern AVCodec ff_ayuv_decoder; extern AVCodec ff_bethsoftvid_decoder; extern AVCodec ff_bfi_decoder; extern AVCodec ff_bink_decoder; +extern AVCodec ff_bitpacked_decoder; extern AVCodec ff_bmp_encoder; extern AVCodec ff_bmp_decoder; extern AVCodec ff_bmv_video_decoder; @@ -151,8 +154,10 @@ extern AVCodec ff_hq_hqa_decoder; extern AVCodec ff_hqx_decoder; extern AVCodec ff_huffyuv_encoder; extern AVCodec ff_huffyuv_decoder; +extern AVCodec ff_hymt_decoder; extern AVCodec ff_idcin_decoder; extern AVCodec ff_iff_ilbm_decoder; +extern AVCodec ff_imm4_decoder; extern AVCodec ff_indeo2_decoder; extern AVCodec ff_indeo3_decoder; extern AVCodec ff_indeo4_decoder; @@ -168,6 +173,7 @@ extern AVCodec ff_kmvc_decoder; extern AVCodec ff_lagarith_decoder; extern AVCodec ff_ljpeg_encoder; extern AVCodec ff_loco_decoder; +extern AVCodec ff_lscr_decoder; extern AVCodec ff_m101_decoder; extern AVCodec ff_magicyuv_encoder; extern AVCodec ff_magicyuv_decoder; @@ -211,6 +217,7 @@ extern AVCodec ff_mszh_decoder; extern AVCodec ff_mts2_decoder; extern AVCodec ff_mvc1_decoder; extern AVCodec ff_mvc2_decoder; +extern AVCodec ff_mwsc_decoder; extern AVCodec ff_mxpeg_decoder; extern AVCodec ff_nuv_decoder; extern AVCodec ff_paf_video_decoder; @@ -234,7 +241,7 @@ extern AVCodec ff_prores_encoder; extern AVCodec ff_prores_decoder; extern AVCodec ff_prores_aw_encoder; extern AVCodec ff_prores_ks_encoder; -extern AVCodec ff_prores_lgpl_decoder; +extern AVCodec ff_prosumer_decoder; extern AVCodec ff_psd_decoder; extern AVCodec ff_ptx_decoder; extern AVCodec ff_qdraw_decoder; @@ -245,6 +252,7 @@ extern AVCodec ff_r10k_encoder; extern AVCodec ff_r10k_decoder; extern AVCodec ff_r210_encoder; extern AVCodec ff_r210_decoder; +extern AVCodec ff_rasc_decoder; extern AVCodec ff_rawvideo_encoder; extern AVCodec ff_rawvideo_decoder; extern AVCodec ff_rl2_decoder; @@ -322,6 +330,7 @@ extern AVCodec ff_vcr1_decoder; extern AVCodec ff_vmdvideo_decoder; extern AVCodec ff_vmnc_decoder; extern AVCodec ff_vp3_decoder; +extern AVCodec ff_vp4_decoder; extern AVCodec ff_vp5_decoder; extern AVCodec ff_vp6_decoder; extern AVCodec ff_vp6a_decoder; @@ -334,8 +343,8 @@ extern AVCodec ff_vp9_decoder; extern AVCodec ff_vp9_rkmpp_decoder; extern AVCodec ff_vp9_v4l2m2m_decoder; extern AVCodec ff_vqa_decoder; -extern AVCodec ff_bitpacked_decoder; extern AVCodec ff_webp_decoder; +extern AVCodec ff_wcmv_decoder; extern AVCodec ff_wrapped_avframe_encoder; extern AVCodec ff_wrapped_avframe_decoder; extern AVCodec ff_wmv1_encoder; @@ -393,6 +402,7 @@ extern AVCodec ff_atrac3_decoder; extern AVCodec ff_atrac3al_decoder; extern AVCodec ff_atrac3p_decoder; extern AVCodec ff_atrac3pal_decoder; +extern AVCodec ff_atrac9_decoder; extern AVCodec ff_binkaudio_dct_decoder; extern AVCodec ff_binkaudio_rdft_decoder; extern AVCodec ff_bmv_audio_decoder; @@ -418,7 +428,9 @@ extern AVCodec ff_g723_1_decoder; extern AVCodec ff_g729_decoder; extern AVCodec ff_gsm_decoder; extern AVCodec ff_gsm_ms_decoder; +extern AVCodec ff_hcom_decoder; extern AVCodec ff_iac_decoder; +extern AVCodec ff_ilbc_decoder; extern AVCodec ff_imc_decoder; extern AVCodec ff_interplay_acm_decoder; extern AVCodec ff_mace3_decoder; @@ -488,6 +500,7 @@ extern AVCodec ff_xma2_decoder; extern AVCodec ff_pcm_alaw_encoder; extern AVCodec ff_pcm_alaw_decoder; extern AVCodec ff_pcm_bluray_decoder; +extern AVCodec ff_pcm_dvd_encoder; extern AVCodec ff_pcm_dvd_decoder; extern AVCodec ff_pcm_f16le_decoder; extern AVCodec ff_pcm_f24le_decoder; @@ -546,6 +559,8 @@ extern AVCodec ff_pcm_u32be_encoder; extern AVCodec ff_pcm_u32be_decoder; extern AVCodec ff_pcm_u32le_encoder; extern AVCodec ff_pcm_u32le_decoder; +extern AVCodec ff_pcm_vidc_encoder; +extern AVCodec ff_pcm_vidc_decoder; extern AVCodec ff_pcm_zork_decoder; /* DPCM codecs */ @@ -561,6 +576,7 @@ extern AVCodec ff_adpcm_4xm_decoder; extern AVCodec ff_adpcm_adx_encoder; extern AVCodec ff_adpcm_adx_decoder; extern AVCodec ff_adpcm_afc_decoder; +extern AVCodec ff_adpcm_agm_decoder; extern AVCodec ff_adpcm_aica_decoder; extern AVCodec ff_adpcm_ct_decoder; extern AVCodec ff_adpcm_dtk_decoder; @@ -665,9 +681,12 @@ extern AVCodec ff_qdmc_at_decoder; extern AVCodec ff_qdm2_at_decoder; extern AVCodec ff_libaom_av1_decoder; extern AVCodec ff_libaom_av1_encoder; +extern AVCodec ff_libaribb24_decoder; extern AVCodec ff_libcelt_decoder; extern AVCodec ff_libcodec2_encoder; extern AVCodec ff_libcodec2_decoder; +extern AVCodec ff_libdav1d_decoder; +extern AVCodec ff_libdavs2_decoder; extern AVCodec ff_libfdk_aac_encoder; extern AVCodec ff_libfdk_aac_decoder; extern AVCodec ff_libgsm_encoder; @@ -706,6 +725,7 @@ extern AVCodec ff_libx264_encoder; extern AVCodec ff_libx264rgb_encoder; extern AVCodec ff_libx265_encoder; extern AVCodec ff_libxavs_encoder; +extern AVCodec ff_libxavs2_encoder; extern AVCodec ff_libxvid_encoder; extern AVCodec ff_libzvbi_teletext_decoder; @@ -761,7 +781,15 @@ extern AVCodec ff_vp9_cuvid_decoder; extern AVCodec ff_vp9_mediacodec_decoder; extern AVCodec ff_vp9_vaapi_encoder; +// The iterate API is not usable with ossfuzz due to the excessive size of binaries created +#if CONFIG_OSSFUZZ +AVCodec * codec_list[] = { + NULL, + NULL +}; +#else #include "libavcodec/codec_list.c" +#endif static AVOnce av_codec_static_init = AV_ONCE_INIT; static void av_codec_init_static(void) diff --git a/libavcodec/alsdec.c b/libavcodec/alsdec.c index ca8701e6d..f8d10df8c 100644 --- a/libavcodec/alsdec.c +++ b/libavcodec/alsdec.c @@ -348,6 +348,11 @@ static av_cold int read_specific_config(ALSDecContext *ctx) if (als_id != MKBETAG('A','L','S','\0')) return AVERROR_INVALIDDATA; + if (avctx->channels > FF_SANE_NB_CHANNELS) { + avpriv_request_sample(avctx, "Huge number of channels\n"); + return AVERROR_PATCHWELCOME; + } + ctx->cur_frame_length = sconf->frame_length; // read channel config @@ -487,7 +492,7 @@ static void parse_bs_info(const uint32_t bs_info, unsigned int n, static int32_t decode_rice(GetBitContext *gb, unsigned int k) { int max = get_bits_left(gb) - k; - int q = get_unary(gb, 0, max); + unsigned q = get_unary(gb, 0, max); int r = k ? get_bits1(gb) : !(q & 1); if (k > 1) { @@ -507,7 +512,7 @@ static void parcor_to_lpc(unsigned int k, const int32_t *par, int32_t *cof) int i, j; for (i = 0, j = k - 1; i < j; i++, j--) { - int tmp1 = ((MUL64(par[k], cof[j]) + (1 << 19)) >> 20); + unsigned tmp1 = ((MUL64(par[k], cof[j]) + (1 << 19)) >> 20); cof[j] += ((MUL64(par[k], cof[i]) + (1 << 19)) >> 20); cof[i] += tmp1; } @@ -657,7 +662,7 @@ static int read_var_block_data(ALSDecContext *ctx, ALSBlockData *bd) // do not continue in case of a damaged stream since // block_length must be evenly divisible by sub_blocks - if (bd->block_length & (sub_blocks - 1)) { + if (bd->block_length & (sub_blocks - 1) || bd->block_length <= 0) { av_log(avctx, AV_LOG_WARNING, "Block length is not evenly divisible by the number of subblocks.\n"); return AVERROR_INVALIDDATA; @@ -767,8 +772,8 @@ static int read_var_block_data(ALSDecContext *ctx, ALSBlockData *bd) if (*bd->use_ltp) { int r, c; - bd->ltp_gain[0] = decode_rice(gb, 1) << 3; - bd->ltp_gain[1] = decode_rice(gb, 2) << 3; + bd->ltp_gain[0] = decode_rice(gb, 1) * 8; + bd->ltp_gain[1] = decode_rice(gb, 2) * 8; r = get_unary(gb, 0, 4); c = get_bits(gb, 2); @@ -779,8 +784,8 @@ static int read_var_block_data(ALSDecContext *ctx, ALSBlockData *bd) bd->ltp_gain[2] = ltp_gain_values[r][c]; - bd->ltp_gain[3] = decode_rice(gb, 2) << 3; - bd->ltp_gain[4] = decode_rice(gb, 1) << 3; + bd->ltp_gain[3] = decode_rice(gb, 2) * 8; + bd->ltp_gain[4] = decode_rice(gb, 1) * 8; *bd->ltp_lag = get_bits(gb, ctx->ltp_lag_length); *bd->ltp_lag += FFMAX(4, opt_order + 1); @@ -789,14 +794,20 @@ static int read_var_block_data(ALSDecContext *ctx, ALSBlockData *bd) // read first value and residuals in case of a random access block if (bd->ra_block) { + start = FFMIN(opt_order, 3); + av_assert0(sb_length <= sconf->frame_length); + if (sb_length <= start) { + // opt_order or sb_length may be corrupted, either way this is unsupported and not well defined in the specification + av_log(avctx, AV_LOG_ERROR, "Sub block length smaller or equal start\n"); + return AVERROR_PATCHWELCOME; + } + if (opt_order) bd->raw_samples[0] = decode_rice(gb, avctx->bits_per_raw_sample - 4); if (opt_order > 1) bd->raw_samples[1] = decode_rice(gb, FFMIN(s[0] + 3, ctx->s_max)); if (opt_order > 2) bd->raw_samples[2] = decode_rice(gb, FFMIN(s[0] + 1, ctx->s_max)); - - start = FFMIN(opt_order, 3); } // read all residuals @@ -810,7 +821,9 @@ static int read_var_block_data(ALSDecContext *ctx, ALSBlockData *bd) unsigned int low; unsigned int value; - ff_bgmc_decode_init(gb, &high, &low, &value); + int ret = ff_bgmc_decode_init(gb, &high, &low, &value); + if (ret < 0) + return ret; current_res = bd->raw_samples + start; @@ -861,7 +874,7 @@ static int read_var_block_data(ALSDecContext *ctx, ALSBlockData *bd) res >>= 1; if (cur_k) { - res *= 1 << cur_k; + res *= 1U << cur_k; res |= get_bits_long(gb, cur_k); } } @@ -912,7 +925,7 @@ static int decode_var_block_data(ALSDecContext *ctx, ALSBlockData *bd) y = 1 << 6; for (base = begin; base < end; base++, tab++) - y += MUL64(bd->ltp_gain[tab], raw_samples[base]); + y += (uint64_t)MUL64(bd->ltp_gain[tab], raw_samples[base]); raw_samples[ltp_smp] += y >> 7; } @@ -924,7 +937,7 @@ static int decode_var_block_data(ALSDecContext *ctx, ALSBlockData *bd) y = 1 << 19; for (sb = 0; sb < smp; sb++) - y += MUL64(lpc_cof[sb], raw_samples[-(sb + 1)]); + y += (uint64_t)MUL64(lpc_cof[sb], raw_samples[-(sb + 1)]); *raw_samples++ -= y >> 20; parcor_to_lpc(smp, quant_cof, lpc_cof); @@ -940,7 +953,7 @@ static int decode_var_block_data(ALSDecContext *ctx, ALSBlockData *bd) // reconstruct difference signal for prediction (joint-stereo) if (bd->js_blocks && bd->raw_other) { - int32_t *left, *right; + uint32_t *left, *right; if (bd->raw_other > raw_samples) { // D = R - L left = raw_samples; @@ -974,7 +987,7 @@ static int decode_var_block_data(ALSDecContext *ctx, ALSBlockData *bd) y = 1 << 19; for (sb = -opt_order; sb < 0; sb++) - y += MUL64(lpc_cof[sb], raw_samples[sb]); + y += (uint64_t)MUL64(lpc_cof[sb], raw_samples[sb]); *raw_samples -= y >> 20; } @@ -1033,7 +1046,7 @@ static int decode_block(ALSDecContext *ctx, ALSBlockData *bd) if (*bd->shift_lsbs) for (smp = 0; smp < bd->block_length; smp++) - bd->raw_samples[smp] <<= *bd->shift_lsbs; + bd->raw_samples[smp] = (unsigned)bd->raw_samples[smp] << *bd->shift_lsbs; return 0; } @@ -1169,10 +1182,10 @@ static int decode_blocks(ALSDecContext *ctx, unsigned int ra_frame, av_log(ctx->avctx, AV_LOG_WARNING, "Invalid channel pair.\n"); for (s = 0; s < div_blocks[b]; s++) - bd[0].raw_samples[s] = bd[1].raw_samples[s] - bd[0].raw_samples[s]; + bd[0].raw_samples[s] = bd[1].raw_samples[s] - (unsigned)bd[0].raw_samples[s]; } else if (bd[1].js_blocks) { for (s = 0; s < div_blocks[b]; s++) - bd[1].raw_samples[s] = bd[1].raw_samples[s] + bd[0].raw_samples[s]; + bd[1].raw_samples[s] = bd[1].raw_samples[s] + (unsigned)bd[0].raw_samples[s]; } offset += div_blocks[b]; @@ -1379,6 +1392,9 @@ static SoftFloat_IEEE754 multiply(SoftFloat_IEEE754 a, SoftFloat_IEEE754 b) { mantissa_temp = (uint64_t)a.mant * (uint64_t)b.mant; mask_64 = (uint64_t)0x1 << 47; + if (!mantissa_temp) + return FLOAT_0; + // Count the valid bit count while (!(mantissa_temp & mask_64) && mask_64) { bit_count--; @@ -1395,7 +1411,11 @@ static SoftFloat_IEEE754 multiply(SoftFloat_IEEE754 a, SoftFloat_IEEE754 b) { } } - mantissa = (unsigned int)(mantissa_temp >> cutoff_bit_count); + if (cutoff_bit_count >= 0) { + mantissa = (unsigned int)(mantissa_temp >> cutoff_bit_count); + } else { + mantissa = (unsigned int)(mantissa_temp <<-cutoff_bit_count); + } // Need one more shift? if (mantissa & 0x01000000ul) { @@ -1407,7 +1427,7 @@ static SoftFloat_IEEE754 multiply(SoftFloat_IEEE754 a, SoftFloat_IEEE754 b) { return_val = 0x80000000U; } - return_val |= (a.exp + b.exp + bit_count - 47) << 23; + return_val |= ((unsigned)av_clip(a.exp + b.exp + bit_count - 47, -126, 127) << 23) & 0x7F800000; return_val |= mantissa; return av_bits2sf_ieee754(return_val); } @@ -1796,11 +1816,11 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame_ptr, if (!ctx->cs_switch) { \ for (sample = 0; sample < ctx->cur_frame_length; sample++) \ for (c = 0; c < avctx->channels; c++) \ - *dest++ = ctx->raw_samples[c][sample] << shift; \ + *dest++ = ctx->raw_samples[c][sample] * (1U << shift); \ } else { \ for (sample = 0; sample < ctx->cur_frame_length; sample++) \ for (c = 0; c < avctx->channels; c++) \ - *dest++ = ctx->raw_samples[sconf->chan_pos[c]][sample] << shift; \ + *dest++ = ctx->raw_samples[sconf->chan_pos[c]][sample] * (1U << shift); \ } \ } @@ -1984,6 +2004,8 @@ static av_cold int decode_init(AVCodecContext *avctx) // allocate quantized parcor coefficient buffer num_buffers = sconf->mc_coding ? avctx->channels : 1; + if (num_buffers * (uint64_t)num_buffers > INT_MAX) // protect chan_data_buffer allocation + return AVERROR_INVALIDDATA; ctx->quant_cof = av_malloc_array(num_buffers, sizeof(*ctx->quant_cof)); ctx->lpc_cof = av_malloc_array(num_buffers, sizeof(*ctx->lpc_cof)); @@ -2116,7 +2138,6 @@ static av_cold int decode_init(AVCodecContext *avctx) return 0; fail: - decode_end(avctx); return ret; } @@ -2142,4 +2163,5 @@ AVCodec ff_als_decoder = { .decode = decode_frame, .flush = flush, .capabilities = AV_CODEC_CAP_SUBFRAMES | AV_CODEC_CAP_DR1, + .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; diff --git a/libavcodec/anm.c b/libavcodec/anm.c index ab6a3994e..778f38413 100644 --- a/libavcodec/anm.c +++ b/libavcodec/anm.c @@ -119,6 +119,9 @@ static int decode_frame(AVCodecContext *avctx, uint8_t *dst, *dst_end; int count, ret; + if (buf_size < 7) + return AVERROR_INVALIDDATA; + if ((ret = ff_reget_buffer(avctx, s->frame)) < 0) return ret; dst = s->frame->data[0]; diff --git a/libavcodec/apedec.c b/libavcodec/apedec.c index 15eb416ba..59e829ee5 100644 --- a/libavcodec/apedec.c +++ b/libavcodec/apedec.c @@ -460,7 +460,7 @@ static inline void update_rice(APERice *rice, unsigned int x) if (rice->ksum < lim) rice->k--; - else if (rice->ksum >= (1 << (rice->k + 5))) + else if (rice->ksum >= (1 << (rice->k + 5)) && rice->k < 24) rice->k++; } @@ -554,7 +554,7 @@ static inline int ape_decode_value_3990(APEContext *ctx, APERice *rice) overflow = range_get_symbol(ctx, counts_3980, counts_diff_3980); if (overflow == (MODEL_ELEMENTS - 1)) { - overflow = range_decode_bits(ctx, 16) << 16; + overflow = (unsigned)range_decode_bits(ctx, 16) << 16; overflow |= range_decode_bits(ctx, 16); } @@ -589,7 +589,7 @@ static void decode_array_0000(APEContext *ctx, GetBitContext *gb, int32_t *out, APERice *rice, int blockstodecode) { int i; - int ksummax, ksummin; + unsigned ksummax, ksummin; rice->ksum = 0; for (i = 0; i < FFMIN(blockstodecode, 5); i++) { @@ -836,7 +836,7 @@ static av_always_inline int filter_fast_3320(APEPredictor *p, else p->coeffsA[filter][0]--; - p->filterA[filter] += p->lastA[filter]; + p->filterA[filter] += (unsigned)p->lastA[filter]; return p->filterA[filter]; } @@ -859,9 +859,9 @@ static av_always_inline int filter_3800(APEPredictor *p, return predictionA; } d2 = p->buf[delayA]; - d1 = (p->buf[delayA] - p->buf[delayA - 1]) << 1; - d0 = p->buf[delayA] + ((p->buf[delayA - 2] - p->buf[delayA - 1]) << 3); - d3 = p->buf[delayB] * 2 - p->buf[delayB - 1]; + d1 = (p->buf[delayA] - p->buf[delayA - 1]) * 2U; + d0 = p->buf[delayA] + ((p->buf[delayA - 2] - p->buf[delayA - 1]) * 8U); + d3 = p->buf[delayB] * 2U - p->buf[delayB - 1]; d4 = p->buf[delayB]; predictionA = d0 * p->coeffsA[filter][0] + @@ -881,7 +881,7 @@ static av_always_inline int filter_3800(APEPredictor *p, p->coeffsB[filter][1] -= (((d4 >> 30) & 2) - 1) * sign; p->filterB[filter] = p->lastA[filter] + (predictionB >> shift); - p->filterA[filter] = p->filterB[filter] + ((p->filterA[filter] * 31) >> 5); + p->filterA[filter] = p->filterB[filter] + ((int)(p->filterA[filter] * 31U) >> 5); return p->filterA[filter]; } @@ -902,7 +902,7 @@ static void long_filter_high_3800(int32_t *buffer, int order, int shift, int len dotprod = 0; sign = APESIGN(buffer[i]); for (j = 0; j < order; j++) { - dotprod += delay[j] * coeffs[j]; + dotprod += delay[j] * (unsigned)coeffs[j]; coeffs[j] += ((delay[j] >> 31) | 1) * sign; } buffer[i] -= dotprod >> shift; @@ -1130,7 +1130,7 @@ static av_always_inline int predictor_update_filter(APEPredictor *p, p->buf[delayA - 3] * p->coeffsA[filter][3]; /* Apply a scaled first-order filter compression */ - p->buf[delayB] = p->filterA[filter ^ 1] - ((p->filterB[filter] * 31) >> 5); + p->buf[delayB] = p->filterA[filter ^ 1] - ((int)(p->filterB[filter] * 31U) >> 5); p->buf[adaptB] = APESIGN(p->buf[delayB]); p->buf[delayB - 1] = p->buf[delayB] - p->buf[delayB - 1]; p->buf[adaptB - 1] = APESIGN(p->buf[delayB - 1]); @@ -1142,8 +1142,8 @@ static av_always_inline int predictor_update_filter(APEPredictor *p, p->buf[delayB - 3] * p->coeffsB[filter][3] + p->buf[delayB - 4] * p->coeffsB[filter][4]; - p->lastA[filter] = decoded + ((predictionA + (predictionB >> 1)) >> 10); - p->filterA[filter] = p->lastA[filter] + ((p->filterA[filter] * 31) >> 5); + p->lastA[filter] = decoded + ((int)((unsigned)predictionA + (predictionB >> 1)) >> 10); + p->filterA[filter] = p->lastA[filter] + ((int)(p->filterA[filter] * 31U) >> 5); sign = APESIGN(decoded); p->coeffsA[filter][0] += p->buf[adaptA ] * sign; @@ -1229,7 +1229,7 @@ static void predictor_decode_mono_3950(APEContext *ctx, int count) p->buf = p->historybuffer; } - p->filterA[0] = currentA + ((p->filterA[0] * 31) >> 5); + p->filterA[0] = currentA + ((int)(p->filterA[0] * 31U) >> 5); *(decoded0++) = p->filterA[0]; } @@ -1266,7 +1266,7 @@ static void do_apply_filter(APEContext *ctx, int version, APEFilter *f, f->delay - order, f->adaptcoeffs - order, order, APESIGN(*data)); - res = (res + (1 << (fracbits - 1))) >> fracbits; + res = (int)(res + (1U << (fracbits - 1))) >> fracbits; res += *data; *data++ = res; @@ -1376,7 +1376,7 @@ static void ape_unpack_mono(APEContext *ctx, int count) static void ape_unpack_stereo(APEContext *ctx, int count) { - int32_t left, right; + unsigned left, right; int32_t *decoded0 = ctx->decoded[0]; int32_t *decoded1 = ctx->decoded[1]; @@ -1393,7 +1393,7 @@ static void ape_unpack_stereo(APEContext *ctx, int count) /* Decorrelate and scale to output depth */ while (count--) { - left = *decoded1 - (*decoded0 / 2); + left = *decoded1 - (unsigned)(*decoded0 / 2); right = left + *decoded0; *(decoded0++) = left; @@ -1451,7 +1451,8 @@ static int ape_decode_frame(AVCodecContext *avctx, void *data, if (s->fileversion >= 3900) { if (offset > 3) { av_log(avctx, AV_LOG_ERROR, "Incorrect offset passed\n"); - s->data = NULL; + av_freep(&s->data); + s->data_size = 0; return AVERROR_INVALIDDATA; } if (s->data_end - s->ptr < offset) { diff --git a/libavcodec/arbc.c b/libavcodec/arbc.c new file mode 100644 index 000000000..06970f140 --- /dev/null +++ b/libavcodec/arbc.c @@ -0,0 +1,227 @@ +/* + * Gryphon's Anim Compressor decoder + * Copyright (c) 2019 Paul B Mahol + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include + +#include "libavutil/imgutils.h" +#include "libavutil/internal.h" +#include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" + +#include "avcodec.h" +#include "bytestream.h" +#include "internal.h" + +typedef struct ARBCContext { + GetByteContext gb; + + AVFrame *prev_frame; +} ARBCContext; + +static int fill_tile4(AVCodecContext *avctx, int color, AVFrame *frame) +{ + ARBCContext *s = avctx->priv_data; + GetByteContext *gb = &s->gb; + int nb_tiles = bytestream2_get_le16(gb); + int h = avctx->height - 1; + int pixels_overwritten = 0; + + if ((avctx->width / 4 + 1) * (avctx->height / 4 + 1) < nb_tiles) + return 0; + + for (int i = 0; i < nb_tiles; i++) { + int y = bytestream2_get_byte(gb); + int x = bytestream2_get_byte(gb); + uint16_t mask = bytestream2_get_le16(gb); + int start_y = y * 4, start_x = x * 4; + int end_y = start_y + 4, end_x = start_x + 4; + + for (int j = start_y; j < end_y; j++) { + for (int k = start_x; k < end_x; k++) { + if (mask & 0x8000) { + if (j >= avctx->height || k >= avctx->width) { + mask = mask << 1; + continue; + } + AV_WB24(&frame->data[0][frame->linesize[0] * (h - j) + 3 * k], color); + pixels_overwritten ++; + } + mask = mask << 1; + } + } + } + return pixels_overwritten; +} + +static int fill_tileX(AVCodecContext *avctx, int tile_width, int tile_height, + int color, AVFrame *frame) +{ + ARBCContext *s = avctx->priv_data; + GetByteContext *gb = &s->gb; + const int step_h = tile_height / 4; + const int step_w = tile_width / 4; + int nb_tiles = bytestream2_get_le16(gb); + int h = avctx->height - 1; + int pixels_overwritten = 0; + + if ((avctx->width / tile_width + 1) * (avctx->height / tile_height + 1) < nb_tiles) + return 0; + + for (int i = 0; i < nb_tiles; i++) { + int y = bytestream2_get_byte(gb); + int x = bytestream2_get_byte(gb); + uint16_t mask = bytestream2_get_le16(gb); + int start_y = y * tile_height, start_x = x * tile_width; + int end_y = start_y + tile_height, end_x = start_x + tile_width; + + if (start_x >= avctx->width || start_y >= avctx->height) + continue; + + for (int j = start_y; j < end_y; j += step_h) { + for (int k = start_x; k < end_x; k += step_w) { + if (mask & 0x8000U) { + for (int m = 0; m < step_h; m++) { + for (int n = 0; n < step_w; n++) { + if (j + m >= avctx->height || k + n >= avctx->width) + continue; + AV_WB24(&frame->data[0][frame->linesize[0] * (h - (j + m)) + 3 * (k + n)], color); + } + } + pixels_overwritten += FFMIN(step_h, avctx->height - j) * FFMIN(step_w, avctx->width - k); + } + mask = mask << 1; + } + } + } + return pixels_overwritten; +} + +static int decode_frame(AVCodecContext *avctx, void *data, + int *got_frame, AVPacket *avpkt) +{ + ARBCContext *s = avctx->priv_data; + AVFrame *frame = data; + int ret, nb_segments; + int prev_pixels = avctx->width * avctx->height; + + if (avpkt->size < 10) + return AVERROR_INVALIDDATA; + + bytestream2_init(&s->gb, avpkt->data, avpkt->size); + bytestream2_skip(&s->gb, 8); + nb_segments = bytestream2_get_le16(&s->gb); + if (nb_segments == 0) + return avpkt->size; + + if (7 * nb_segments > bytestream2_get_bytes_left(&s->gb)) + return AVERROR_INVALIDDATA; + + if ((ret = ff_get_buffer(avctx, frame, AV_GET_BUFFER_FLAG_REF)) < 0) + return ret; + + if (s->prev_frame->data[0]) { + ret = av_frame_copy(frame, s->prev_frame); + if (ret < 0) + return ret; + } + + for (int i = 0; i < nb_segments; i++) { + int resolution_flag; + int fill; + + if (bytestream2_get_bytes_left(&s->gb) <= 0) + return AVERROR_INVALIDDATA; + + fill = bytestream2_get_byte(&s->gb) << 16; + bytestream2_skip(&s->gb, 1); + fill |= bytestream2_get_byte(&s->gb) << 8; + bytestream2_skip(&s->gb, 1); + fill |= bytestream2_get_byte(&s->gb) << 0; + bytestream2_skip(&s->gb, 1); + resolution_flag = bytestream2_get_byte(&s->gb); + + if (resolution_flag & 0x10) + prev_pixels -= fill_tileX(avctx, 1024, 1024, fill, frame); + if (resolution_flag & 0x08) + prev_pixels -= fill_tileX(avctx, 256, 256, fill, frame); + if (resolution_flag & 0x04) + prev_pixels -= fill_tileX(avctx, 64, 64, fill, frame); + if (resolution_flag & 0x02) + prev_pixels -= fill_tileX(avctx, 16, 16, fill, frame); + if (resolution_flag & 0x01) + prev_pixels -= fill_tile4(avctx, fill, frame); + } + + av_frame_unref(s->prev_frame); + if ((ret = av_frame_ref(s->prev_frame, frame)) < 0) + return ret; + + frame->pict_type = prev_pixels <= 0 ? AV_PICTURE_TYPE_I : AV_PICTURE_TYPE_P; + frame->key_frame = prev_pixels <= 0; + *got_frame = 1; + + return avpkt->size; +} + +static av_cold int decode_init(AVCodecContext *avctx) +{ + ARBCContext *s = avctx->priv_data; + + avctx->pix_fmt = AV_PIX_FMT_RGB24; + + s->prev_frame = av_frame_alloc(); + if (!s->prev_frame) + return AVERROR(ENOMEM); + + return 0; +} + +static void decode_flush(AVCodecContext *avctx) +{ + ARBCContext *s = avctx->priv_data; + + av_frame_unref(s->prev_frame); +} + +static av_cold int decode_close(AVCodecContext *avctx) +{ + ARBCContext *s = avctx->priv_data; + + av_frame_free(&s->prev_frame); + + return 0; +} + +AVCodec ff_arbc_decoder = { + .name = "arbc", + .long_name = NULL_IF_CONFIG_SMALL("Gryphon's Anim Compressor"), + .type = AVMEDIA_TYPE_VIDEO, + .id = AV_CODEC_ID_ARBC, + .priv_data_size = sizeof(ARBCContext), + .init = decode_init, + .decode = decode_frame, + .flush = decode_flush, + .close = decode_close, + .capabilities = AV_CODEC_CAP_DR1, + .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, +}; diff --git a/libavcodec/arm/h264dsp_init_arm.c b/libavcodec/arm/h264dsp_init_arm.c index 90144d0da..54e1e38c9 100644 --- a/libavcodec/arm/h264dsp_init_arm.c +++ b/libavcodec/arm/h264dsp_init_arm.c @@ -25,14 +25,16 @@ #include "libavcodec/h264dsp.h" #include "libavcodec/arm/startcode.h" -void ff_h264_v_loop_filter_luma_neon(uint8_t *pix, int stride, int alpha, +void ff_h264_v_loop_filter_luma_neon(uint8_t *pix, ptrdiff_t stride, int alpha, int beta, int8_t *tc0); -void ff_h264_h_loop_filter_luma_neon(uint8_t *pix, int stride, int alpha, +void ff_h264_h_loop_filter_luma_neon(uint8_t *pix, ptrdiff_t stride, int alpha, int beta, int8_t *tc0); -void ff_h264_v_loop_filter_chroma_neon(uint8_t *pix, int stride, int alpha, +void ff_h264_v_loop_filter_chroma_neon(uint8_t *pix, ptrdiff_t stride, int alpha, int beta, int8_t *tc0); -void ff_h264_h_loop_filter_chroma_neon(uint8_t *pix, int stride, int alpha, +void ff_h264_h_loop_filter_chroma_neon(uint8_t *pix, ptrdiff_t stride, int alpha, int beta, int8_t *tc0); +void ff_h264_h_loop_filter_chroma422_neon(uint8_t *pix, ptrdiff_t stride, int alpha, + int beta, int8_t *tc0); void ff_weight_h264_pixels_16_neon(uint8_t *dst, int stride, int height, int log2_den, int weight, int offset); @@ -77,9 +79,11 @@ static av_cold void h264dsp_init_neon(H264DSPContext *c, const int bit_depth, c->h264_v_loop_filter_luma = ff_h264_v_loop_filter_luma_neon; c->h264_h_loop_filter_luma = ff_h264_h_loop_filter_luma_neon; c->h264_v_loop_filter_chroma = ff_h264_v_loop_filter_chroma_neon; - if(chroma_format_idc == 1){ - c->h264_h_loop_filter_chroma = ff_h264_h_loop_filter_chroma_neon; - } + + if (chroma_format_idc <= 1) + c->h264_h_loop_filter_chroma = ff_h264_h_loop_filter_chroma_neon; + else + c->h264_h_loop_filter_chroma = ff_h264_h_loop_filter_chroma422_neon; c->weight_h264_pixels_tab[0] = ff_weight_h264_pixels_16_neon; c->weight_h264_pixels_tab[1] = ff_weight_h264_pixels_8_neon; diff --git a/libavcodec/arm/h264dsp_neon.S b/libavcodec/arm/h264dsp_neon.S index 274a547f2..5fed6848d 100644 --- a/libavcodec/arm/h264dsp_neon.S +++ b/libavcodec/arm/h264dsp_neon.S @@ -237,6 +237,7 @@ function ff_h264_h_loop_filter_chroma_neon, export=1 h264_loop_filter_start sub r0, r0, #2 +h_loop_filter_chroma420: vld1.32 {d18[0]}, [r0], r1 vld1.32 {d16[0]}, [r0], r1 vld1.32 {d0[0]}, [r0], r1 @@ -271,6 +272,24 @@ function ff_h264_h_loop_filter_chroma_neon, export=1 bx lr endfunc +function ff_h264_h_loop_filter_chroma422_neon, export=1 + h264_loop_filter_start + push {r4, lr} + add r4, r0, r1 + add r1, r1, r1 + sub r0, r0, #2 + + bl h_loop_filter_chroma420 + + ldr r12, [sp, #8] + ldr r12, [r12] + vmov.32 d24[0], r12 + sub r0, r4, #2 + + bl h_loop_filter_chroma420 + pop {r4, pc} +endfunc + @ Biweighted prediction .macro biweight_16 macs, macd diff --git a/libavcodec/arm/vp8dsp_neon.S b/libavcodec/arm/vp8dsp_neon.S index fcb424881..7cedfc253 100644 --- a/libavcodec/arm/vp8dsp_neon.S +++ b/libavcodec/arm/vp8dsp_neon.S @@ -773,23 +773,6 @@ endfunc vqrshrun.s16 \d1, q14, #7 .endm -.macro vp8_epel8_v6 d0, s0, s1, s2, s3, s4, s5 - vmovl.u8 q10, \s2 - vmovl.u8 q11, \s3 - vmovl.u8 q9, \s1 - vmovl.u8 q12, \s4 - vmovl.u8 q8, \s0 - vmovl.u8 q13, \s5 - vmul.u16 q10, q10, d0[2] - vmul.u16 q11, q11, d0[3] - vmls.u16 q10, q9, d0[1] - vmls.u16 q11, q12, d1[0] - vmla.u16 q10, q8, d0[0] - vmla.u16 q11, q13, d1[1] - vqadd.s16 q11, q10, q11 - vqrshrun.s16 \d0, q11, #7 -.endm - .macro vp8_epel8_v6_y2 d0, d1, s0, s1, s2, s3, s4, s5, s6 vmovl.u8 q10, \s0 vmovl.u8 q11, \s3 @@ -909,12 +892,12 @@ function ff_put_vp8_epel16_h6v6_neon, export=1 sub r2, r2, r3, lsl #1 sub r2, r2, #2 push {r4,lr} - vpush {d8-d9} + vpush {d8-d15} @ first pass (horizontal): - ldr r4, [sp, #28] @ mx + ldr r4, [sp, #64+8+4] @ mx movrel lr, subpel_filters-16 - ldr r12, [sp, #24] @ h + ldr r12, [sp, #64+8+0] @ h add r4, lr, r4, lsl #4 sub sp, sp, #336+16 vld1.16 {q0}, [r4,:128] @@ -931,9 +914,9 @@ function ff_put_vp8_epel16_h6v6_neon, export=1 bne 1b @ second pass (vertical): - ldr r4, [sp, #336+16+32] @ my + ldr r4, [sp, #336+16+64+8+8] @ my movrel lr, subpel_filters-16 - ldr r12, [sp, #336+16+24] @ h + ldr r12, [sp, #336+16+64+8+0] @ h add r4, lr, r4, lsl #4 add lr, sp, #15 vld1.16 {q0}, [r4,:128] @@ -941,18 +924,20 @@ function ff_put_vp8_epel16_h6v6_neon, export=1 2: vld1.8 {d2-d5}, [lr,:128]! vld1.8 {d6-d9}, [lr,:128]! - vld1.8 {d28-d31},[lr,:128] - sub lr, lr, #48 + vld1.8 {d10-d13},[lr,:128]! + vld1.8 {d14-d15},[lr,:128] + sub lr, lr, #64 - vp8_epel8_v6 d2, d2, d4, d6, d8, d28, d30 - vp8_epel8_v6 d3, d3, d5, d7, d9, d29, d31 + vp8_epel8_v6_y2 d2, d4, d2, d4, d6, d8, d10, d12, d14 + vp8_epel8_v6_y2 d3, d5, d3, d5, d7, d9, d11, d13, d15 vst1.8 {d2-d3}, [r0,:128], r1 - subs r12, r12, #1 + vst1.8 {d4-d5}, [r0,:128], r1 + subs r12, r12, #2 bne 2b add sp, sp, #336+16 - vpop {d8-d9} + vpop {d8-d15} pop {r4,pc} endfunc diff --git a/libavcodec/ass_split.c b/libavcodec/ass_split.c index 872528bdf..67da7c6d8 100644 --- a/libavcodec/ass_split.c +++ b/libavcodec/ass_split.c @@ -249,7 +249,7 @@ static const char *ass_split_section(ASSSplitContext *ctx, const char *buf) const ASSSection *section = &ass_sections[ctx->current_section]; int *number = &ctx->field_number[ctx->current_section]; int *order = ctx->field_order[ctx->current_section]; - int *tmp, i, len; + int i, len; while (buf && *buf) { if (buf[0] == '[') { @@ -280,9 +280,9 @@ static const char *ass_split_section(ASSSplitContext *ctx, const char *buf) while (!is_eol(*buf)) { buf = skip_space(buf); len = strcspn(buf, ", \r\n"); - if (!(tmp = av_realloc_array(order, (*number + 1), sizeof(*order)))) + if (av_reallocp_array(&order, (*number + 1), sizeof(*order)) != 0) return NULL; - order = tmp; + order[*number] = -1; for (i=0; section->fields[i].name; i++) if (!strncmp(buf, section->fields[i].name, len)) { diff --git a/libavcodec/assdec.c b/libavcodec/assdec.c index 3178f2953..f0b1069cd 100644 --- a/libavcodec/assdec.c +++ b/libavcodec/assdec.c @@ -31,7 +31,8 @@ static av_cold int ass_decode_init(AVCodecContext *avctx) avctx->subtitle_header = av_malloc(avctx->extradata_size + 1); if (!avctx->subtitle_header) return AVERROR(ENOMEM); - memcpy(avctx->subtitle_header, avctx->extradata, avctx->extradata_size); + if (avctx->extradata_size) + memcpy(avctx->subtitle_header, avctx->extradata, avctx->extradata_size); avctx->subtitle_header[avctx->extradata_size] = 0; avctx->subtitle_header_size = avctx->extradata_size; return 0; diff --git a/libavcodec/assenc.c b/libavcodec/assenc.c index dc4f0ffa9..e54c1d8ec 100644 --- a/libavcodec/assenc.c +++ b/libavcodec/assenc.c @@ -57,7 +57,7 @@ static int ass_encode_frame(AVCodecContext *avctx, if (sub->rects[i]->type != SUBTITLE_ASS) { av_log(avctx, AV_LOG_ERROR, "Only SUBTITLE_ASS type supported.\n"); - return -1; + return AVERROR(EINVAL); } #if FF_API_ASS_TIMING @@ -93,7 +93,7 @@ static int ass_encode_frame(AVCodecContext *avctx, if (len > bufsize-total_len-1) { av_log(avctx, AV_LOG_ERROR, "Buffer too small for ASS event.\n"); - return -1; + return AVERROR(EINVAL); } total_len += len; diff --git a/libavcodec/asvenc.c b/libavcodec/asvenc.c index c4eca2a13..3cc94bf91 100644 --- a/libavcodec/asvenc.c +++ b/libavcodec/asvenc.c @@ -173,10 +173,7 @@ static inline int encode_mb(ASV1Context *a, int16_t block[6][64]) { int i; - if (a->pb.buf_end - a->pb.buf - (put_bits_count(&a->pb) >> 3) < MAX_MB_SIZE) { - av_log(a->avctx, AV_LOG_ERROR, "encoded frame too large\n"); - return -1; - } + av_assert0(a->pb.buf_end - a->pb.buf - (put_bits_count(&a->pb) >> 3) >= MAX_MB_SIZE); if (a->avctx->codec_id == AV_CODEC_ID_ASV1) { for (i = 0; i < 6; i++) diff --git a/libavcodec/atrac3plus.c b/libavcodec/atrac3plus.c index 3e3bba801..9f964efb4 100644 --- a/libavcodec/atrac3plus.c +++ b/libavcodec/atrac3plus.c @@ -81,8 +81,8 @@ av_cold void ff_atrac3p_init_vlcs(void) { int i, wl_vlc_offs, ct_vlc_offs, sf_vlc_offs, tab_offset; - static const int wl_nb_bits[4] = { 2, 3, 5, 5 }; - static const int wl_nb_codes[4] = { 3, 5, 8, 8 }; + static const uint8_t wl_nb_bits[4] = { 2, 3, 5, 5 }; + static const uint8_t wl_nb_codes[4] = { 3, 5, 8, 8 }; static const uint8_t * const wl_bits[4] = { atrac3p_wl_huff_bits1, atrac3p_wl_huff_bits2, atrac3p_wl_huff_bits3, atrac3p_wl_huff_bits4 @@ -95,8 +95,8 @@ av_cold void ff_atrac3p_init_vlcs(void) atrac3p_wl_huff_xlat1, atrac3p_wl_huff_xlat2, NULL, NULL }; - static const int ct_nb_bits[4] = { 3, 4, 4, 4 }; - static const int ct_nb_codes[4] = { 4, 8, 8, 8 }; + static const uint8_t ct_nb_bits[4] = { 3, 4, 4, 4 }; + static const uint8_t ct_nb_codes[4] = { 4, 8, 8, 8 }; static const uint8_t * const ct_bits[4] = { atrac3p_ct_huff_bits1, atrac3p_ct_huff_bits2, atrac3p_ct_huff_bits2, atrac3p_ct_huff_bits3 @@ -109,8 +109,8 @@ av_cold void ff_atrac3p_init_vlcs(void) NULL, NULL, atrac3p_ct_huff_xlat1, NULL }; - static const int sf_nb_bits[8] = { 9, 9, 9, 9, 6, 6, 7, 7 }; - static const int sf_nb_codes[8] = { 64, 64, 64, 64, 16, 16, 16, 16 }; + static const uint8_t sf_nb_bits[8] = { 9, 9, 9, 9, 6, 6, 7, 7 }; + static const uint8_t sf_nb_codes[8] = { 64, 64, 64, 64, 16, 16, 16, 16 }; static const uint8_t * const sf_bits[8] = { atrac3p_sf_huff_bits1, atrac3p_sf_huff_bits1, atrac3p_sf_huff_bits2, atrac3p_sf_huff_bits3, atrac3p_sf_huff_bits4, atrac3p_sf_huff_bits4, diff --git a/libavcodec/atrac3plusdsp.c b/libavcodec/atrac3plusdsp.c index 96aa402c2..ca3154e13 100644 --- a/libavcodec/atrac3plusdsp.c +++ b/libavcodec/atrac3plusdsp.c @@ -248,7 +248,7 @@ void ff_atrac3p_generate_tones(Atrac3pChanUnitCtx *ch_unit, AVFloatDSPContext *f out[i] += wavreg1[i] + wavreg2[i]; } -static const int subband_to_powgrp[ATRAC3P_SUBBANDS] = { +static const uint8_t subband_to_powgrp[ATRAC3P_SUBBANDS] = { 0, 1, 1, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4 }; @@ -411,7 +411,7 @@ static const float pwc_levs[16] = { }; /** Map subband number to quant unit number. */ -static const int subband_to_qu[17] = { +static const uint8_t subband_to_qu[17] = { 0, 8, 12, 16, 18, 20, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32 }; diff --git a/libavcodec/atrac9dec.c b/libavcodec/atrac9dec.c new file mode 100644 index 000000000..082041890 --- /dev/null +++ b/libavcodec/atrac9dec.c @@ -0,0 +1,968 @@ +/* + * ATRAC9 decoder + * Copyright (c) 2018 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 + */ + +#include "internal.h" +#include "get_bits.h" +#include "fft.h" +#include "atrac9tab.h" +#include "libavutil/lfg.h" +#include "libavutil/float_dsp.h" + +typedef struct ATRAC9ChannelData { + int band_ext; + int q_unit_cnt; + int band_ext_data[4]; + int32_t scalefactors[31]; + int32_t scalefactors_prev[31]; + + int precision_coarse[30]; + int precision_fine[30]; + int precision_mask[30]; + + int codebookset[30]; + + int32_t q_coeffs_coarse[256]; + int32_t q_coeffs_fine[256]; + + DECLARE_ALIGNED(32, float, coeffs )[256]; + DECLARE_ALIGNED(32, float, prev_win)[128]; +} ATRAC9ChannelData; + +typedef struct ATRAC9BlockData { + ATRAC9ChannelData channel[2]; + + /* Base */ + int band_count; + int q_unit_cnt; + int q_unit_cnt_prev; + + /* Stereo block only */ + int stereo_q_unit; + + /* Band extension only */ + int has_band_ext; + int has_band_ext_data; + int band_ext_q_unit; + + /* Gradient */ + int grad_mode; + int grad_boundary; + int gradient[31]; + + /* Stereo */ + int cpe_base_channel; + int is_signs[30]; + + int reuseable; + +} ATRAC9BlockData; + +typedef struct ATRAC9Context { + AVCodecContext *avctx; + AVFloatDSPContext *fdsp; + FFTContext imdct; + ATRAC9BlockData block[5]; + AVLFG lfg; + + /* Set on init */ + int frame_log2; + int avg_frame_size; + int frame_count; + int samplerate_idx; + const ATRAC9BlockConfig *block_config; + + /* Generated on init */ + VLC sf_vlc[2][8]; /* Signed/unsigned, length */ + VLC coeff_vlc[2][8][4]; /* Cookbook, precision, cookbook index */ + uint8_t alloc_curve[48][48]; + DECLARE_ALIGNED(32, float, imdct_win)[256]; + + DECLARE_ALIGNED(32, float, temp)[256]; +} ATRAC9Context; + +static inline int parse_gradient(ATRAC9Context *s, ATRAC9BlockData *b, + GetBitContext *gb) +{ + int grad_range[2]; + int grad_value[2]; + int values, sign, base; + uint8_t *curve; + float scale; + + b->grad_mode = get_bits(gb, 2); + if (b->grad_mode) { + grad_range[0] = get_bits(gb, 5); + grad_range[1] = 31; + grad_value[0] = get_bits(gb, 5); + grad_value[1] = 31; + } else { + grad_range[0] = get_bits(gb, 6); + grad_range[1] = get_bits(gb, 6) + 1; + grad_value[0] = get_bits(gb, 5); + grad_value[1] = get_bits(gb, 5); + } + b->grad_boundary = get_bits(gb, 4); + + if (grad_range[0] >= grad_range[1] || grad_range[1] > 31) + return AVERROR_INVALIDDATA; + + if (grad_value[0] > 31 || grad_value[1] > 31) + return AVERROR_INVALIDDATA; + + if (b->grad_boundary > b->q_unit_cnt) + return AVERROR_INVALIDDATA; + + values = grad_value[1] - grad_value[0]; + sign = 1 - 2*(values < 0); + base = grad_value[0] + sign; + scale = (FFABS(values) - 1) / 31.0f; + curve = s->alloc_curve[grad_range[1] - grad_range[0] - 1]; + + for (int i = 0; i <= b->q_unit_cnt; i++) + b->gradient[i] = grad_value[i >= grad_range[0]]; + + for (int i = grad_range[0]; i < grad_range[1]; i++) + b->gradient[i] = base + sign*((int)(scale*curve[i - grad_range[0]])); + + return 0; +} + +static inline void calc_precision(ATRAC9Context *s, ATRAC9BlockData *b, + ATRAC9ChannelData *c) +{ + memset(c->precision_mask, 0, sizeof(c->precision_mask)); + for (int i = 1; i < b->q_unit_cnt; i++) { + const int delta = FFABS(c->scalefactors[i] - c->scalefactors[i - 1]) - 1; + if (delta > 0) { + const int neg = c->scalefactors[i - 1] > c->scalefactors[i]; + c->precision_mask[i - neg] += FFMIN(delta, 5); + } + } + + if (b->grad_mode) { + for (int i = 0; i < b->q_unit_cnt; i++) { + c->precision_coarse[i] = c->scalefactors[i]; + c->precision_coarse[i] += c->precision_mask[i] - b->gradient[i]; + if (c->precision_coarse[i] < 0) + continue; + switch (b->grad_mode) { + case 1: + c->precision_coarse[i] >>= 1; + break; + case 2: + c->precision_coarse[i] = (3 * c->precision_coarse[i]) >> 3; + break; + case 3: + c->precision_coarse[i] >>= 2; + break; + } + } + } else { + for (int i = 0; i < b->q_unit_cnt; i++) + c->precision_coarse[i] = c->scalefactors[i] - b->gradient[i]; + } + + + for (int i = 0; i < b->q_unit_cnt; i++) + c->precision_coarse[i] = FFMAX(c->precision_coarse[i], 1); + + for (int i = 0; i < b->grad_boundary; i++) + c->precision_coarse[i]++; + + for (int i = 0; i < b->q_unit_cnt; i++) { + c->precision_fine[i] = 0; + if (c->precision_coarse[i] > 15) { + c->precision_fine[i] = c->precision_coarse[i] - 15; + c->precision_coarse[i] = 15; + } + } +} + +static inline int parse_band_ext(ATRAC9Context *s, ATRAC9BlockData *b, + GetBitContext *gb, int stereo) +{ + int ext_band = 0; + + if (b->has_band_ext) { + if (b->q_unit_cnt < 13) + return AVERROR_INVALIDDATA; + ext_band = at9_tab_band_ext_group[b->q_unit_cnt - 13][2]; + if (stereo) { + b->channel[1].band_ext = get_bits(gb, 2); + b->channel[1].band_ext = ext_band > 2 ? b->channel[1].band_ext : 4; + } else { + skip_bits1(gb); + } + } + + b->has_band_ext_data = get_bits1(gb); + if (!b->has_band_ext_data) + return 0; + + if (!b->has_band_ext) { + skip_bits(gb, 2); + skip_bits_long(gb, get_bits(gb, 5)); + return 0; + } + + b->channel[0].band_ext = get_bits(gb, 2); + b->channel[0].band_ext = ext_band > 2 ? b->channel[0].band_ext : 4; + + if (!get_bits(gb, 5)) + return 0; + + for (int i = 0; i <= stereo; i++) { + ATRAC9ChannelData *c = &b->channel[i]; + const int count = at9_tab_band_ext_cnt[c->band_ext][ext_band]; + for (int j = 0; j < count; j++) { + int len = at9_tab_band_ext_lengths[c->band_ext][ext_band][j]; + c->band_ext_data[j] = get_bits(gb, len); + } + } + + return 0; +} + +static inline int read_scalefactors(ATRAC9Context *s, ATRAC9BlockData *b, + ATRAC9ChannelData *c, GetBitContext *gb, + int channel_idx, int first_in_pkt) +{ + static const uint8_t mode_map[2][4] = { { 0, 1, 2, 3 }, { 0, 2, 3, 4 } }; + const int mode = mode_map[channel_idx][get_bits(gb, 2)]; + + memset(c->scalefactors, 0, sizeof(c->scalefactors)); + + if (first_in_pkt && (mode == 4 || ((mode == 3) && !channel_idx))) { + av_log(s->avctx, AV_LOG_ERROR, "Invalid scalefactor coding mode!\n"); + return AVERROR_INVALIDDATA; + } + + switch (mode) { + case 0: { /* VLC delta offset */ + const uint8_t *sf_weights = at9_tab_sf_weights[get_bits(gb, 3)]; + const int base = get_bits(gb, 5); + const int len = get_bits(gb, 2) + 3; + const VLC *tab = &s->sf_vlc[0][len]; + + c->scalefactors[0] = get_bits(gb, len); + + for (int i = 1; i < b->band_ext_q_unit; i++) { + int val = c->scalefactors[i - 1] + get_vlc2(gb, tab->table, 9, 2); + c->scalefactors[i] = val & ((1 << len) - 1); + } + + for (int i = 0; i < b->band_ext_q_unit; i++) + c->scalefactors[i] += base - sf_weights[i]; + + break; + } + case 1: { /* CLC offset */ + const int len = get_bits(gb, 2) + 2; + const int base = len < 5 ? get_bits(gb, 5) : 0; + for (int i = 0; i < b->band_ext_q_unit; i++) + c->scalefactors[i] = base + get_bits(gb, len); + break; + } + case 2: + case 4: { /* VLC dist to baseline */ + const int *baseline = mode == 4 ? c->scalefactors_prev : + channel_idx ? b->channel[0].scalefactors : + c->scalefactors_prev; + const int baseline_len = mode == 4 ? b->q_unit_cnt_prev : + channel_idx ? b->band_ext_q_unit : + b->q_unit_cnt_prev; + + const int len = get_bits(gb, 2) + 2; + const int unit_cnt = FFMIN(b->band_ext_q_unit, baseline_len); + const VLC *tab = &s->sf_vlc[1][len]; + + for (int i = 0; i < unit_cnt; i++) { + int dist = get_vlc2(gb, tab->table, 9, 2); + c->scalefactors[i] = baseline[i] + dist; + } + + for (int i = unit_cnt; i < b->band_ext_q_unit; i++) + c->scalefactors[i] = get_bits(gb, 5); + + break; + } + case 3: { /* VLC offset with baseline */ + const int *baseline = channel_idx ? b->channel[0].scalefactors : + c->scalefactors_prev; + const int baseline_len = channel_idx ? b->band_ext_q_unit : + b->q_unit_cnt_prev; + + const int base = get_bits(gb, 5) - (1 << (5 - 1)); + const int len = get_bits(gb, 2) + 1; + const int unit_cnt = FFMIN(b->band_ext_q_unit, baseline_len); + const VLC *tab = &s->sf_vlc[0][len]; + + c->scalefactors[0] = get_bits(gb, len); + + for (int i = 1; i < unit_cnt; i++) { + int val = c->scalefactors[i - 1] + get_vlc2(gb, tab->table, 9, 2); + c->scalefactors[i] = val & ((1 << len) - 1); + } + + for (int i = 0; i < unit_cnt; i++) + c->scalefactors[i] += base + baseline[i]; + + for (int i = unit_cnt; i < b->band_ext_q_unit; i++) + c->scalefactors[i] = get_bits(gb, 5); + break; + } + } + + for (int i = 0; i < b->band_ext_q_unit; i++) + if (c->scalefactors[i] < 0 || c->scalefactors[i] > 31) + return AVERROR_INVALIDDATA; + + memcpy(c->scalefactors_prev, c->scalefactors, sizeof(c->scalefactors)); + + return 0; +} + +static inline void calc_codebook_idx(ATRAC9Context *s, ATRAC9BlockData *b, + ATRAC9ChannelData *c) +{ + int avg = 0; + const int last_sf = c->scalefactors[c->q_unit_cnt]; + + memset(c->codebookset, 0, sizeof(c->codebookset)); + + if (c->q_unit_cnt <= 1) + return; + if (s->samplerate_idx > 7) + return; + + c->scalefactors[c->q_unit_cnt] = c->scalefactors[c->q_unit_cnt - 1]; + + if (c->q_unit_cnt > 12) { + for (int i = 0; i < 12; i++) + avg += c->scalefactors[i]; + avg = (avg + 6) / 12; + } + + for (int i = 8; i < c->q_unit_cnt; i++) { + const int prev = c->scalefactors[i - 1]; + const int cur = c->scalefactors[i ]; + const int next = c->scalefactors[i + 1]; + const int min = FFMIN(prev, next); + if ((cur - min >= 3 || 2*cur - prev - next >= 3)) + c->codebookset[i] = 1; + } + + + for (int i = 12; i < c->q_unit_cnt; i++) { + const int cur = c->scalefactors[i]; + const int cnd = at9_q_unit_to_coeff_cnt[i] == 16; + const int min = FFMIN(c->scalefactors[i + 1], c->scalefactors[i - 1]); + if (c->codebookset[i]) + continue; + + c->codebookset[i] = (((cur - min) >= 2) && (cur >= (avg - cnd))); + } + + c->scalefactors[c->q_unit_cnt] = last_sf; +} + +static inline void read_coeffs_coarse(ATRAC9Context *s, ATRAC9BlockData *b, + ATRAC9ChannelData *c, GetBitContext *gb) +{ + const int max_prec = s->samplerate_idx > 7 ? 1 : 7; + + memset(c->q_coeffs_coarse, 0, sizeof(c->q_coeffs_coarse)); + + for (int i = 0; i < c->q_unit_cnt; i++) { + int *coeffs = &c->q_coeffs_coarse[at9_q_unit_to_coeff_idx[i]]; + const int bands = at9_q_unit_to_coeff_cnt[i]; + const int prec = c->precision_coarse[i] + 1; + + if (prec <= max_prec) { + const int cb = c->codebookset[i]; + const int cbi = at9_q_unit_to_codebookidx[i]; + const VLC *tab = &s->coeff_vlc[cb][prec][cbi]; + const HuffmanCodebook *huff = &at9_huffman_coeffs[cb][prec][cbi]; + const int groups = bands >> huff->value_cnt_pow; + + for (int j = 0; j < groups; j++) { + uint16_t val = get_vlc2(gb, tab->table, 9, huff->max_bit_size); + + for (int k = 0; k < huff->value_cnt; k++) { + coeffs[k] = sign_extend(val, huff->value_bits); + val >>= huff->value_bits; + } + + coeffs += huff->value_cnt; + } + } else { + for (int j = 0; j < bands; j++) + coeffs[j] = sign_extend(get_bits(gb, prec), prec); + } + } +} + +static inline void read_coeffs_fine(ATRAC9Context *s, ATRAC9BlockData *b, + ATRAC9ChannelData *c, GetBitContext *gb) +{ + memset(c->q_coeffs_fine, 0, sizeof(c->q_coeffs_fine)); + + for (int i = 0; i < c->q_unit_cnt; i++) { + const int start = at9_q_unit_to_coeff_idx[i + 0]; + const int end = at9_q_unit_to_coeff_idx[i + 1]; + const int len = c->precision_fine[i] + 1; + + if (c->precision_fine[i] <= 0) + continue; + + for (int j = start; j < end; j++) + c->q_coeffs_fine[j] = sign_extend(get_bits(gb, len), len); + } +} + +static inline void dequantize(ATRAC9Context *s, ATRAC9BlockData *b, + ATRAC9ChannelData *c) +{ + memset(c->coeffs, 0, sizeof(c->coeffs)); + + for (int i = 0; i < c->q_unit_cnt; i++) { + const int start = at9_q_unit_to_coeff_idx[i + 0]; + const int end = at9_q_unit_to_coeff_idx[i + 1]; + + const float coarse_c = at9_quant_step_coarse[c->precision_coarse[i]]; + const float fine_c = at9_quant_step_fine[c->precision_fine[i]]; + + for (int j = start; j < end; j++) { + const float vc = c->q_coeffs_coarse[j] * coarse_c; + const float vf = c->q_coeffs_fine[j] * fine_c; + c->coeffs[j] = vc + vf; + } + } +} + +static inline void apply_intensity_stereo(ATRAC9Context *s, ATRAC9BlockData *b, + const int stereo) +{ + float *src = b->channel[ b->cpe_base_channel].coeffs; + float *dst = b->channel[!b->cpe_base_channel].coeffs; + + if (!stereo) + return; + + if (b->q_unit_cnt <= b->stereo_q_unit) + return; + + for (int i = b->stereo_q_unit; i < b->q_unit_cnt; i++) { + const int sign = b->is_signs[i]; + const int start = at9_q_unit_to_coeff_idx[i + 0]; + const int end = at9_q_unit_to_coeff_idx[i + 1]; + for (int j = start; j < end; j++) + dst[j] = sign*src[j]; + } +} + +static inline void apply_scalefactors(ATRAC9Context *s, ATRAC9BlockData *b, + const int stereo) +{ + for (int i = 0; i <= stereo; i++) { + float *coeffs = b->channel[i].coeffs; + for (int j = 0; j < b->q_unit_cnt; j++) { + const int start = at9_q_unit_to_coeff_idx[j + 0]; + const int end = at9_q_unit_to_coeff_idx[j + 1]; + const int scalefactor = b->channel[i].scalefactors[j]; + const float scale = at9_scalefactor_c[scalefactor]; + for (int k = start; k < end; k++) + coeffs[k] *= scale; + } + } +} + +static inline void fill_with_noise(ATRAC9Context *s, ATRAC9ChannelData *c, + int start, int count) +{ + float maxval = 0.0f; + for (int i = 0; i < count; i += 2) { + double tmp[2]; + av_bmg_get(&s->lfg, tmp); + c->coeffs[start + i + 0] = tmp[0]; + c->coeffs[start + i + 1] = tmp[1]; + maxval = FFMAX(FFMAX(FFABS(tmp[0]), FFABS(tmp[1])), maxval); + } + /* Normalize */ + for (int i = 0; i < count; i++) + c->coeffs[start + i] /= maxval; +} + +static inline void scale_band_ext_coeffs(ATRAC9ChannelData *c, float sf[6], + const int s_unit, const int e_unit) +{ + for (int i = s_unit; i < e_unit; i++) { + const int start = at9_q_unit_to_coeff_idx[i + 0]; + const int end = at9_q_unit_to_coeff_idx[i + 1]; + for (int j = start; j < end; j++) + c->coeffs[j] *= sf[i - s_unit]; + } +} + +static inline void apply_band_extension(ATRAC9Context *s, ATRAC9BlockData *b, + const int stereo) +{ + const int g_units[4] = { /* A, B, C, total units */ + b->q_unit_cnt, + at9_tab_band_ext_group[b->q_unit_cnt - 13][0], + at9_tab_band_ext_group[b->q_unit_cnt - 13][1], + FFMAX(g_units[2], 22), + }; + + const int g_bins[4] = { /* A, B, C, total bins */ + at9_q_unit_to_coeff_idx[g_units[0]], + at9_q_unit_to_coeff_idx[g_units[1]], + at9_q_unit_to_coeff_idx[g_units[2]], + at9_q_unit_to_coeff_idx[g_units[3]], + }; + + for (int ch = 0; ch <= stereo; ch++) { + ATRAC9ChannelData *c = &b->channel[ch]; + + /* Mirror the spectrum */ + for (int i = 0; i < 3; i++) + for (int j = 0; j < (g_bins[i + 1] - g_bins[i + 0]); j++) + c->coeffs[g_bins[i] + j] = c->coeffs[g_bins[i] - j - 1]; + + switch (c->band_ext) { + case 0: { + float sf[6] = { 0.0f }; + const int l = g_units[3] - g_units[0] - 1; + const int n_start = at9_q_unit_to_coeff_idx[g_units[3] - 1]; + const int n_cnt = at9_q_unit_to_coeff_cnt[g_units[3] - 1]; + switch (at9_tab_band_ext_group[b->q_unit_cnt - 13][2]) { + case 3: + sf[0] = at9_band_ext_scales_m0[0][0][c->band_ext_data[0]]; + sf[1] = at9_band_ext_scales_m0[0][1][c->band_ext_data[0]]; + sf[2] = at9_band_ext_scales_m0[0][2][c->band_ext_data[1]]; + sf[3] = at9_band_ext_scales_m0[0][3][c->band_ext_data[2]]; + sf[4] = at9_band_ext_scales_m0[0][4][c->band_ext_data[3]]; + break; + case 4: + sf[0] = at9_band_ext_scales_m0[1][0][c->band_ext_data[0]]; + sf[1] = at9_band_ext_scales_m0[1][1][c->band_ext_data[0]]; + sf[2] = at9_band_ext_scales_m0[1][2][c->band_ext_data[1]]; + sf[3] = at9_band_ext_scales_m0[1][3][c->band_ext_data[2]]; + sf[4] = at9_band_ext_scales_m0[1][4][c->band_ext_data[3]]; + break; + case 5: + sf[0] = at9_band_ext_scales_m0[2][0][c->band_ext_data[0]]; + sf[1] = at9_band_ext_scales_m0[2][1][c->band_ext_data[1]]; + sf[2] = at9_band_ext_scales_m0[2][2][c->band_ext_data[1]]; + break; + } + + sf[l] = at9_scalefactor_c[c->scalefactors[g_units[0]]]; + + fill_with_noise(s, c, n_start, n_cnt); + scale_band_ext_coeffs(c, sf, g_units[0], g_units[3]); + break; + } + case 1: { + float sf[6]; + for (int i = g_units[0]; i < g_units[3]; i++) + sf[i - g_units[0]] = at9_scalefactor_c[c->scalefactors[i]]; + + fill_with_noise(s, c, g_bins[0], g_bins[3] - g_bins[0]); + scale_band_ext_coeffs(c, sf, g_units[0], g_units[3]); + break; + } + case 2: { + const float g_sf[2] = { + at9_band_ext_scales_m2[c->band_ext_data[0]], + at9_band_ext_scales_m2[c->band_ext_data[1]], + }; + + for (int i = 0; i < 2; i++) + for (int j = g_bins[i + 0]; j < g_bins[i + 1]; j++) + c->coeffs[j] *= g_sf[i]; + break; + } + case 3: { + float scale = at9_band_ext_scales_m3[c->band_ext_data[0]][0]; + float rate = at9_band_ext_scales_m3[c->band_ext_data[1]][1]; + rate = pow(2, rate); + for (int i = g_bins[0]; i < g_bins[3]; i++) { + scale *= rate; + c->coeffs[i] *= scale; + } + break; + } + case 4: { + const float m = at9_band_ext_scales_m4[c->band_ext_data[0]]; + const float g_sf[3] = { 0.7079468f*m, 0.5011902f*m, 0.3548279f*m }; + + for (int i = 0; i < 3; i++) + for (int j = g_bins[i + 0]; j < g_bins[i + 1]; j++) + c->coeffs[j] *= g_sf[i]; + break; + } + } + } +} + +static int atrac9_decode_block(ATRAC9Context *s, GetBitContext *gb, + ATRAC9BlockData *b, AVFrame *frame, + int frame_idx, int block_idx) +{ + const int first_in_pkt = !get_bits1(gb); + const int reuse_params = get_bits1(gb); + const int stereo = s->block_config->type[block_idx] == ATRAC9_BLOCK_TYPE_CPE; + + if (s->block_config->type[block_idx] == ATRAC9_BLOCK_TYPE_LFE) { + ATRAC9ChannelData *c = &b->channel[0]; + const int precision = reuse_params ? 8 : 4; + c->q_unit_cnt = b->q_unit_cnt = 2; + + memset(c->scalefactors, 0, sizeof(c->scalefactors)); + memset(c->q_coeffs_fine, 0, sizeof(c->q_coeffs_fine)); + memset(c->q_coeffs_coarse, 0, sizeof(c->q_coeffs_coarse)); + + for (int i = 0; i < b->q_unit_cnt; i++) { + c->scalefactors[i] = get_bits(gb, 5); + c->precision_coarse[i] = precision; + c->precision_fine[i] = 0; + } + + for (int i = 0; i < c->q_unit_cnt; i++) { + const int start = at9_q_unit_to_coeff_idx[i + 0]; + const int end = at9_q_unit_to_coeff_idx[i + 1]; + for (int j = start; j < end; j++) + c->q_coeffs_coarse[j] = get_bits(gb, c->precision_coarse[i] + 1); + } + + dequantize (s, b, c); + apply_scalefactors(s, b, 0); + + goto imdct; + } + + if (first_in_pkt && reuse_params) { + av_log(s->avctx, AV_LOG_ERROR, "Invalid block flags!\n"); + return AVERROR_INVALIDDATA; + } + + /* Band parameters */ + if (!reuse_params) { + int stereo_band, ext_band; + const int min_band_count = s->samplerate_idx > 7 ? 1 : 3; + b->reuseable = 0; + b->band_count = get_bits(gb, 4) + min_band_count; + b->q_unit_cnt = at9_tab_band_q_unit_map[b->band_count]; + + b->band_ext_q_unit = b->stereo_q_unit = b->q_unit_cnt; + + if (b->band_count > at9_tab_sri_max_bands[s->samplerate_idx]) { + av_log(s->avctx, AV_LOG_ERROR, "Invalid band count %i!\n", + b->band_count); + return AVERROR_INVALIDDATA; + } + + if (stereo) { + stereo_band = get_bits(gb, 4) + min_band_count; + if (stereo_band > b->band_count) { + av_log(s->avctx, AV_LOG_ERROR, "Invalid stereo band %i!\n", + stereo_band); + return AVERROR_INVALIDDATA; + } + b->stereo_q_unit = at9_tab_band_q_unit_map[stereo_band]; + } + + b->has_band_ext = get_bits1(gb); + if (b->has_band_ext) { + ext_band = get_bits(gb, 4) + min_band_count; + if (ext_band < b->band_count) { + av_log(s->avctx, AV_LOG_ERROR, "Invalid extension band %i!\n", + ext_band); + return AVERROR_INVALIDDATA; + } + b->band_ext_q_unit = at9_tab_band_q_unit_map[ext_band]; + } + b->reuseable = 1; + } + if (!b->reuseable) { + av_log(s->avctx, AV_LOG_ERROR, "invalid block reused!\n"); + return AVERROR_INVALIDDATA; + } + + /* Calculate bit alloc gradient */ + if (parse_gradient(s, b, gb)) + return AVERROR_INVALIDDATA; + + /* IS data */ + b->cpe_base_channel = 0; + if (stereo) { + b->cpe_base_channel = get_bits1(gb); + if (get_bits1(gb)) { + for (int i = b->stereo_q_unit; i < b->q_unit_cnt; i++) + b->is_signs[i] = 1 - 2*get_bits1(gb); + } else { + for (int i = 0; i < FF_ARRAY_ELEMS(b->is_signs); i++) + b->is_signs[i] = 1; + } + } + + /* Band extension */ + if (parse_band_ext(s, b, gb, stereo)) + return AVERROR_INVALIDDATA; + + /* Scalefactors */ + for (int i = 0; i <= stereo; i++) { + ATRAC9ChannelData *c = &b->channel[i]; + c->q_unit_cnt = i == b->cpe_base_channel ? b->q_unit_cnt : + b->stereo_q_unit; + if (read_scalefactors(s, b, c, gb, i, first_in_pkt)) + return AVERROR_INVALIDDATA; + + calc_precision (s, b, c); + calc_codebook_idx (s, b, c); + read_coeffs_coarse(s, b, c, gb); + read_coeffs_fine (s, b, c, gb); + dequantize (s, b, c); + } + + b->q_unit_cnt_prev = b->has_band_ext ? b->band_ext_q_unit : b->q_unit_cnt; + + apply_intensity_stereo(s, b, stereo); + apply_scalefactors (s, b, stereo); + + if (b->has_band_ext && b->has_band_ext_data) + apply_band_extension (s, b, stereo); + +imdct: + for (int i = 0; i <= stereo; i++) { + ATRAC9ChannelData *c = &b->channel[i]; + const int dst_idx = s->block_config->plane_map[block_idx][i]; + const int wsize = 1 << s->frame_log2; + const ptrdiff_t offset = wsize*frame_idx*sizeof(float); + float *dst = (float *)(frame->extended_data[dst_idx] + offset); + + s->imdct.imdct_half(&s->imdct, s->temp, c->coeffs); + s->fdsp->vector_fmul_window(dst, c->prev_win, s->temp, + s->imdct_win, wsize >> 1); + memcpy(c->prev_win, s->temp + (wsize >> 1), sizeof(float)*wsize >> 1); + } + + return 0; +} + +static int atrac9_decode_frame(AVCodecContext *avctx, void *data, + int *got_frame_ptr, AVPacket *avpkt) +{ + int ret; + GetBitContext gb; + AVFrame *frame = data; + ATRAC9Context *s = avctx->priv_data; + const int frames = FFMIN(avpkt->size / s->avg_frame_size, s->frame_count); + + frame->nb_samples = (1 << s->frame_log2) * frames; + ret = ff_get_buffer(avctx, frame, 0); + if (ret < 0) + return ret; + + init_get_bits8(&gb, avpkt->data, avpkt->size); + + for (int i = 0; i < frames; i++) { + for (int j = 0; j < s->block_config->count; j++) { + ret = atrac9_decode_block(s, &gb, &s->block[j], frame, i, j); + if (ret) + return ret; + align_get_bits(&gb); + } + } + + *got_frame_ptr = 1; + + return avctx->block_align; +} + +static void atrac9_decode_flush(AVCodecContext *avctx) +{ + ATRAC9Context *s = avctx->priv_data; + + for (int j = 0; j < s->block_config->count; j++) { + ATRAC9BlockData *b = &s->block[j]; + const int stereo = s->block_config->type[j] == ATRAC9_BLOCK_TYPE_CPE; + for (int i = 0; i <= stereo; i++) { + ATRAC9ChannelData *c = &b->channel[i]; + memset(c->prev_win, 0, sizeof(c->prev_win)); + } + } +} + +static av_cold int atrac9_decode_close(AVCodecContext *avctx) +{ + ATRAC9Context *s = avctx->priv_data; + + for (int i = 1; i < 7; i++) + ff_free_vlc(&s->sf_vlc[0][i]); + for (int i = 2; i < 6; i++) + ff_free_vlc(&s->sf_vlc[1][i]); + for (int i = 0; i < 2; i++) + for (int j = 0; j < 8; j++) + for (int k = 0; k < 4; k++) + ff_free_vlc(&s->coeff_vlc[i][j][k]); + + ff_mdct_end(&s->imdct); + av_free(s->fdsp); + + return 0; +} + +static av_cold int atrac9_decode_init(AVCodecContext *avctx) +{ + GetBitContext gb; + ATRAC9Context *s = avctx->priv_data; + int version, block_config_idx, superframe_idx, alloc_c_len; + + s->avctx = avctx; + + av_lfg_init(&s->lfg, 0xFBADF00D); + + if (avctx->block_align <= 0) { + av_log(avctx, AV_LOG_ERROR, "Invalid block align\n"); + return AVERROR_INVALIDDATA; + } + + if (avctx->extradata_size != 12) { + av_log(avctx, AV_LOG_ERROR, "Invalid extradata length!\n"); + return AVERROR_INVALIDDATA; + } + + version = AV_RL32(avctx->extradata); + if (version > 2) { + av_log(avctx, AV_LOG_ERROR, "Unsupported version (%i)!\n", version); + return AVERROR_INVALIDDATA; + } + + init_get_bits8(&gb, avctx->extradata + 4, avctx->extradata_size); + + if (get_bits(&gb, 8) != 0xFE) { + av_log(avctx, AV_LOG_ERROR, "Incorrect magic byte!\n"); + return AVERROR_INVALIDDATA; + } + + s->samplerate_idx = get_bits(&gb, 4); + avctx->sample_rate = at9_tab_samplerates[s->samplerate_idx]; + + block_config_idx = get_bits(&gb, 3); + if (block_config_idx > 5) { + av_log(avctx, AV_LOG_ERROR, "Incorrect block config!\n"); + return AVERROR_INVALIDDATA; + } + s->block_config = &at9_block_layout[block_config_idx]; + + avctx->channel_layout = s->block_config->channel_layout; + avctx->sample_fmt = AV_SAMPLE_FMT_FLTP; + + if (get_bits1(&gb)) { + av_log(avctx, AV_LOG_ERROR, "Incorrect verification bit!\n"); + return AVERROR_INVALIDDATA; + } + + /* Average frame size in bytes */ + s->avg_frame_size = get_bits(&gb, 11) + 1; + + superframe_idx = get_bits(&gb, 2); + if (superframe_idx & 1) { + av_log(avctx, AV_LOG_ERROR, "Invalid superframe index!\n"); + return AVERROR_INVALIDDATA; + } + + s->frame_count = 1 << superframe_idx; + s->frame_log2 = at9_tab_sri_frame_log2[s->samplerate_idx]; + + if (ff_mdct_init(&s->imdct, s->frame_log2 + 1, 1, 1.0f / 32768.0f)) + return AVERROR(ENOMEM); + + s->fdsp = avpriv_float_dsp_alloc(avctx->flags & AV_CODEC_FLAG_BITEXACT); + if (!s->fdsp) + return AVERROR(ENOMEM); + + /* iMDCT window */ + for (int i = 0; i < (1 << s->frame_log2); i++) { + const int len = 1 << s->frame_log2; + const float sidx = ( i + 0.5f) / len; + const float eidx = (len - i - 0.5f) / len; + const float s_c = sinf(sidx*M_PI - M_PI_2)*0.5f + 0.5f; + const float e_c = sinf(eidx*M_PI - M_PI_2)*0.5f + 0.5f; + s->imdct_win[i] = s_c / ((s_c * s_c) + (e_c * e_c)); + } + + /* Allocation curve */ + alloc_c_len = FF_ARRAY_ELEMS(at9_tab_b_dist); + for (int i = 1; i <= alloc_c_len; i++) + for (int j = 0; j < i; j++) + s->alloc_curve[i - 1][j] = at9_tab_b_dist[(j * alloc_c_len) / i]; + + /* Unsigned scalefactor VLCs */ + for (int i = 1; i < 7; i++) { + const HuffmanCodebook *hf = &at9_huffman_sf_unsigned[i]; + + init_vlc(&s->sf_vlc[0][i], 9, hf->size, hf->bits, 1, 1, hf->codes, + 2, 2, 0); + } + + /* Signed scalefactor VLCs */ + for (int i = 2; i < 6; i++) { + const HuffmanCodebook *hf = &at9_huffman_sf_signed[i]; + + int nums = hf->size; + int16_t sym[32]; + for (int j = 0; j < nums; j++) + sym[j] = sign_extend(j, hf->value_bits); + + ff_init_vlc_sparse(&s->sf_vlc[1][i], 9, hf->size, hf->bits, 1, 1, + hf->codes, 2, 2, sym, sizeof(*sym), sizeof(*sym), 0); + } + + /* Coefficient VLCs */ + for (int i = 0; i < 2; i++) { + for (int j = 0; j < 8; j++) { + for (int k = 0; k < 4; k++) { + const HuffmanCodebook *hf = &at9_huffman_coeffs[i][j][k]; + init_vlc(&s->coeff_vlc[i][j][k], 9, hf->size, hf->bits, 1, 1, + hf->codes, 2, 2, 0); + } + } + } + + return 0; +} + +AVCodec ff_atrac9_decoder = { + .name = "atrac9", + .long_name = NULL_IF_CONFIG_SMALL("ATRAC9 (Adaptive TRansform Acoustic Coding 9)"), + .type = AVMEDIA_TYPE_AUDIO, + .id = AV_CODEC_ID_ATRAC9, + .priv_data_size = sizeof(ATRAC9Context), + .init = atrac9_decode_init, + .close = atrac9_decode_close, + .decode = atrac9_decode_frame, + .flush = atrac9_decode_flush, + .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE | FF_CODEC_CAP_INIT_CLEANUP, + .capabilities = AV_CODEC_CAP_SUBFRAMES | AV_CODEC_CAP_DR1, +}; diff --git a/libavcodec/atrac9tab.h b/libavcodec/atrac9tab.h new file mode 100644 index 000000000..d25c6f1b7 --- /dev/null +++ b/libavcodec/atrac9tab.h @@ -0,0 +1,1633 @@ +/* + * ATRAC9 decoder + * Copyright (c) 2018 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 + */ + +#ifndef AVCODEC_ATRAC9TAB_H +#define AVCODEC_ATRAC9TAB_H + +#include + +#include "libavutil/channel_layout.h" + +enum ATRAC9BlockType { + ATRAC9_BLOCK_TYPE_SCE, /* Single channel */ + ATRAC9_BLOCK_TYPE_CPE, /* 2 coupled channels */ + ATRAC9_BLOCK_TYPE_LFE, /* Single LFE channel */ +}; + +typedef struct ATRAC9BlockConfig { + uint64_t channel_layout; + enum ATRAC9BlockType type[5]; + int plane_map[5][2]; + int count; +} ATRAC9BlockConfig; + +static const ATRAC9BlockConfig at9_block_layout[] = { + { /* Mono */ + AV_CH_LAYOUT_MONO, + { + ATRAC9_BLOCK_TYPE_SCE, + }, + { { 0 }, }, + 1, + }, + { /* Dual Mono */ + AV_CH_LAYOUT_STEREO, + { + ATRAC9_BLOCK_TYPE_SCE, + ATRAC9_BLOCK_TYPE_SCE, + }, + { { 0 }, { 1 }, }, + 2, + }, + { /* Stereo */ + AV_CH_LAYOUT_STEREO, + { + ATRAC9_BLOCK_TYPE_CPE, + }, + { { 0, 1 }, }, + 1, + }, + { /* 5.1 */ + AV_CH_LAYOUT_5POINT1, + { + ATRAC9_BLOCK_TYPE_CPE, + ATRAC9_BLOCK_TYPE_SCE, + ATRAC9_BLOCK_TYPE_LFE, + ATRAC9_BLOCK_TYPE_CPE, + }, + { { 0, 1 }, { 2 }, { 3 }, { 4, 5 }, }, + 4, + }, + { /* 5.1 */ + AV_CH_LAYOUT_7POINT1, + { + ATRAC9_BLOCK_TYPE_CPE, + ATRAC9_BLOCK_TYPE_SCE, + ATRAC9_BLOCK_TYPE_LFE, + ATRAC9_BLOCK_TYPE_CPE, + ATRAC9_BLOCK_TYPE_CPE, + }, + { { 0, 1 }, { 2 }, { 3 }, { 4, 5 }, { 6, 7 }, }, + 5, + }, + { /* Quad */ + AV_CH_LAYOUT_QUAD, + { + ATRAC9_BLOCK_TYPE_CPE, + ATRAC9_BLOCK_TYPE_CPE, + }, + { { 0, 1 }, { 2, 3 }, }, + 2, + }, +}; + +static const uint8_t at9_tab_sri_frame_log2[] = { + 6, 6, 7, 7, 7, 8, 8, 8, 6, 6, 7, 7, 7, 8, 8, 8, +}; + +static const uint8_t at9_tab_band_q_unit_map[] = { + 0, 4, 8, 10, 12, 13, 14, 15, 16, 18, 20, 21, 22, 23, 24, 25, 26, 28, 30, +}; + +static const uint8_t at9_q_unit_to_coeff_cnt[] = { + 2, 2, 2, 2, 2, 2, 2, 2, 4, 4, 4, 4, 8, 8, 8, + 8, 8, 8, 8, 8, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, +}; + +static const int at9_q_unit_to_coeff_idx[] = { + 0, 2, 4, 6, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, 64, + 72, 80, 88, 96, 112, 128, 144, 160, 176, 192, 208, 224, 240, 256 +}; + +const uint8_t at9_q_unit_to_codebookidx[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, + 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, +}; + +static const uint8_t at9_tab_sri_max_bands[] = { + 8, 8, 12, 12, 12, 18, 18, 18, 8, 8, 12, 12, 12, 16, 16, 16, +}; + +static const int at9_tab_samplerates[] = { + 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000, 44100, 48000, + 64000, 88200, 96000, 128000, 176400, 192000, +}; + +static const uint8_t at9_tab_band_ext_cnt[][6] = { + { 0, 0, 0, 4, 4, 2 }, + { 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 2, 2, 1 }, + { 0, 0, 0, 2, 2, 2 }, + { 1, 1, 1, 0, 0, 0 }, +}; + +/* B unit, C unit, Band count */ +static const uint8_t at9_tab_band_ext_group[][3] = { + { 16, 21, 0 }, + { 18, 22, 1 }, + { 20, 22, 2 }, + { 21, 22, 3 }, + { 21, 22, 3 }, + { 23, 24, 4 }, + { 23, 24, 4 }, + { 24, 24, 5 }, +}; + +static const uint8_t at9_tab_band_ext_lengths[][6][4] = { + { + { 0, 0, 0, 0 }, + { 0, 0, 0, 0 }, + { 0, 0, 0, 0 }, + { 5, 4, 3, 3 }, + { 4, 4, 3, 4 }, + { 4, 5, 0, 0 }, + }, + { + { 0, 0, 0, 0 }, + { 0, 0, 0, 0 }, + { 0, 0, 0, 0 }, + { 0, 0, 0, 0 }, + { 0, 0, 0, 0 }, + { 0, 0, 0, 0 }, + }, + { + { 0, 0, 0, 0 }, + { 0, 0, 0, 0 }, + { 0, 0, 0, 0 }, + { 6, 6, 0, 0 }, + { 6, 6, 0, 0 }, + { 6, 0, 0, 0 }, + }, + { + { 0, 0, 0, 0 }, + { 0, 0, 0, 0 }, + { 0, 0, 0, 0 }, + { 4, 4, 0, 0 }, + { 4, 4, 0, 0 }, + { 4, 4, 0, 0 }, + }, + { + { 3, 0, 0, 0 }, + { 3, 0, 0, 0 }, + { 3, 0, 0, 0 }, + { 0, 0, 0, 0 }, + { 0, 0, 0, 0 }, + { 0, 0, 0, 0 }, + }, +}; + +static const float at9_band_ext_scales_m0[][5][32] = { + { + { + 0.000000e+0f, 1.988220e-1f, 2.514343e-1f, 2.960510e-1f, + 3.263550e-1f, 3.771362e-1f, 3.786926e-1f, 4.540405e-1f, + 4.877625e-1f, 5.262451e-1f, 5.447083e-1f, 5.737000e-1f, + 6.212158e-1f, 6.222839e-1f, 6.560974e-1f, 6.896667e-1f, + 7.555542e-1f, 7.677917e-1f, 7.918091e-1f, 7.971497e-1f, + 8.188171e-1f, 8.446045e-1f, 9.790649e-1f, 9.822083e-1f, + 9.846191e-1f, 9.859314e-1f, 9.863586e-1f, 9.863892e-1f, + 9.873352e-1f, 9.881287e-1f, 9.898682e-1f, 9.913330e-1f, + }, { + 0.000000e+0f, 9.982910e-1f, 7.592773e-2f, 7.179565e-1f, + 9.851379e-1f, 5.340271e-1f, 9.013672e-1f, 6.349182e-1f, + 7.226257e-1f, 1.948547e-1f, 7.628174e-1f, 9.873657e-1f, + 8.112183e-1f, 2.715454e-1f, 9.734192e-1f, 1.443787e-1f, + 4.640198e-1f, 3.249207e-1f, 3.790894e-1f, 8.276367e-2f, + 5.954590e-1f, 2.864380e-1f, 9.806824e-1f, 7.929077e-1f, + 6.292114e-1f, 4.887085e-1f, 2.905273e-1f, 1.301880e-1f, + 3.140869e-1f, 5.482483e-1f, 4.210815e-1f, 1.182861e-1f, + }, { + 0.000000e+0f, 3.155518e-2f, 8.581543e-2f, 1.364746e-1f, + 1.858826e-1f, 2.368469e-1f, 2.888184e-1f, 3.432617e-1f, + 4.012451e-1f, 4.623108e-1f, 5.271301e-1f, 5.954895e-1f, + 6.681213e-1f, 7.448425e-1f, 8.245239e-1f, 9.097290e-1f, + }, { + 0.000000e+0f, 4.418945e-2f, 1.303711e-1f, 2.273560e-1f, + 3.395996e-1f, 4.735718e-1f, 6.267090e-1f, 8.003845e-1f, + }, { + 0.000000e+0f, 2.804565e-2f, 9.683228e-2f, 1.849976e-1f, + 3.005981e-1f, 4.470520e-1f, 6.168518e-1f, 8.007813e-1f, + }, + }, + { + { + 0.000000e+0f, 2.708740e-1f, 3.479614e-1f, 3.578186e-1f, + 5.083618e-1f, 5.299072e-1f, 5.819092e-1f, 6.381836e-1f, + 7.276917e-1f, 7.595520e-1f, 7.878723e-1f, 9.707336e-1f, + 9.713135e-1f, 9.736023e-1f, 9.759827e-1f, 9.832458e-1f, + }, { + 0.000000e+0f, 2.330627e-1f, 5.891418e-1f, 7.170410e-1f, + 2.036438e-1f, 1.613464e-1f, 6.668701e-1f, 9.481201e-1f, + 9.769897e-1f, 5.111694e-1f, 3.522644e-1f, 8.209534e-1f, + 2.933960e-1f, 9.757690e-1f, 5.289917e-1f, 4.372253e-1f, + }, { + 0.000000e+0f, 4.360962e-2f, 1.056519e-1f, 1.590576e-1f, + 2.078857e-1f, 2.572937e-1f, 3.082581e-1f, 3.616028e-1f, + 4.191589e-1f, 4.792175e-1f, 5.438538e-1f, 6.125183e-1f, + 6.841125e-1f, 7.589417e-1f, 8.365173e-1f, 9.148254e-1f, + }, { + 0.000000e+0f, 4.074097e-2f, 1.164551e-1f, 2.077026e-1f, + 3.184509e-1f, 4.532166e-1f, 6.124268e-1f, 7.932129e-1f, + }, { + 0.000000e+0f, 8.880615e-3f, 2.932739e-2f, 5.593872e-2f, + 8.825684e-2f, 1.259155e-1f, 1.721497e-1f, 2.270813e-1f, + 2.901611e-1f, 3.579712e-1f, 4.334106e-1f, 5.147095e-1f, + 6.023254e-1f, 6.956177e-1f, 7.952881e-1f, 8.977356e-1f, + }, + }, + { + { + 0.000000e+0f, 7.379150e-2f, 1.806335e-1f, 2.687073e-1f, + 3.407898e-1f, 4.047546e-1f, 4.621887e-1f, 5.168762e-1f, + 5.703125e-1f, 6.237488e-1f, 6.763611e-1f, 7.288208e-1f, + 7.808533e-1f, 8.337708e-1f, 8.874512e-1f, 9.418030e-1f, + }, { + 0.000000e+0f, 7.980347e-2f, 1.615295e-1f, 1.665649e-1f, + 1.822205e-1f, 2.185669e-1f, 2.292175e-1f, 2.456665e-1f, + 2.666321e-1f, 3.306580e-1f, 3.330688e-1f, 3.765259e-1f, + 4.085083e-1f, 4.400024e-1f, 4.407654e-1f, 4.817505e-1f, + 4.924011e-1f, 5.320740e-1f, 5.893860e-1f, 6.131287e-1f, + 6.212463e-1f, 6.278076e-1f, 6.308899e-1f, 7.660828e-1f, + 7.850647e-1f, 7.910461e-1f, 7.929382e-1f, 8.038330e-1f, + 9.834900e-1f, 9.846191e-1f, 9.852295e-1f, 9.862671e-1f, + }, { + 0.000000e+0f, 6.084290e-1f, 3.672791e-1f, 3.151855e-1f, + 1.488953e-1f, 2.571716e-1f, 5.103455e-1f, 3.311157e-1f, + 5.426025e-2f, 4.254456e-1f, 7.998352e-1f, 7.873230e-1f, + 5.418701e-1f, 2.925110e-1f, 8.468628e-2f, 1.410522e-1f, + 9.819641e-1f, 9.609070e-1f, 3.530884e-2f, 9.729004e-2f, + 5.758362e-1f, 9.941711e-1f, 7.215576e-1f, 7.183228e-1f, + 2.028809e-1f, 9.588623e-2f, 2.032166e-1f, 1.338806e-1f, + 5.003357e-1f, 1.874390e-1f, 9.804993e-1f, 1.107788e-1f, + }, + }, +}; + +static const float at9_band_ext_scales_m2[] = { + 4.272461e-4f, 1.312256e-3f, 2.441406e-3f, 3.692627e-3f, + 4.913330e-3f, 6.134033e-3f, 7.507324e-3f, 8.972168e-3f, + 1.049805e-2f, 1.223755e-2f, 1.406860e-2f, 1.599121e-2f, + 1.800537e-2f, 2.026367e-2f, 2.264404e-2f, 2.517700e-2f, + 2.792358e-2f, 3.073120e-2f, 3.344727e-2f, 3.631592e-2f, + 3.952026e-2f, 4.275513e-2f, 4.608154e-2f, 4.968262e-2f, + 5.355835e-2f, 5.783081e-2f, 6.195068e-2f, 6.677246e-2f, + 7.196045e-2f, 7.745361e-2f, 8.319092e-2f, 8.993530e-2f, + 9.759521e-2f, 1.056213e-1f, 1.138916e-1f, 1.236267e-1f, + 1.348267e-1f, 1.470337e-1f, 1.603394e-1f, 1.755676e-1f, + 1.905823e-1f, 2.071228e-1f, 2.245178e-1f, 2.444153e-1f, + 2.658997e-1f, 2.897644e-1f, 3.146057e-1f, 3.450012e-1f, + 3.766174e-1f, 4.122620e-1f, 4.505615e-1f, 4.893799e-1f, + 5.305481e-1f, 5.731201e-1f, 6.157837e-1f, 6.580811e-1f, + 6.985168e-1f, 7.435303e-1f, 7.865906e-1f, 8.302612e-1f, + 8.718567e-1f, 9.125671e-1f, 9.575806e-1f, 9.996643e-1f, +}; + +static const float at9_band_ext_scales_m3[][2] = { + { 3.491211e-1f, -2.913818e-1f, }, { 5.371094e-1f, -2.541504e-1f, }, + { 6.782227e-1f, -1.664429e-1f, }, { 7.910156e-1f, -1.476440e-1f, }, + { 9.057617e-1f, -1.342163e-1f, }, { 1.024902e+0f, -1.220703e-1f, }, + { 1.156250e+0f, -1.117554e-1f, }, { 1.290527e+0f, -1.026611e-1f, }, + { 1.458984e+0f, -9.436035e-2f, }, { 1.664551e+0f, -8.483887e-2f, }, + { 1.929688e+0f, -7.476807e-2f, }, { 2.278320e+0f, -6.304932e-2f, }, + { 2.831543e+0f, -4.492188e-2f, }, { 3.659180e+0f, -2.447510e-2f, }, + { 5.257813e+0f, +1.831055e-4f, }, { 8.373047e+0f, +4.174805e-2f, }, +}; + +static const float at9_band_ext_scales_m4[] = { + 3.610229e-2f, 1.260681e-1f, 2.227478e-1f, 3.338318e-1f, + 4.662170e-1f, 6.221313e-1f, 7.989197e-1f, 9.939575e-1f, +}; + +static const float at9_quant_step_coarse[] = { + 2.0000000000000000e+0f, 6.6666666666666663e-1f, 2.8571428571428570e-1f, + 1.3333333333333333e-1f, 6.4516129032258063e-2f, 3.1746031746031744e-2f, + 1.5748031496062992e-2f, 7.8431372549019607e-3f, 3.9138943248532287e-3f, + 1.9550342130987292e-3f, 9.7703957010258913e-4f, 4.8840048840048840e-4f, + 2.4417043096081065e-4f, 1.2207776353537203e-4f, 6.1037018951994385e-5f, + 3.0518043793392844e-5f, +}; + +static const float at9_quant_step_fine[] = { + 3.0518043793392844e-05f, 1.0172681264464281e-05f, 4.3597205419132631e-06f, + 2.0345362528928561e-06f, 9.8445302559331759e-07f, 4.8441339354591809e-07f, + 2.4029955742829012e-07f, 1.1967860311134448e-07f, 5.9722199204291275e-08f, + 2.9831909866464167e-08f, 1.4908668194134265e-08f, 7.4525137468602791e-09f, + 3.7258019525568114e-09f, 1.8627872668859698e-09f, 9.3136520869755679e-10f, + 4.6567549848772173e-10f, +}; + +static const float at9_scalefactor_c[] = { + 3.0517578125e-5f, 6.1035156250e-5f, 1.2207031250e-4f, 2.4414062500e-4f, + 4.8828125000e-4f, 9.7656250000e-4f, 1.9531250000e-3f, 3.9062500000e-3f, + 7.8125000000e-3f, 1.5625000000e-2f, 3.1250000000e-2f, 6.2500000000e-2f, + 1.2500000000e-1f, 2.5000000000e-1f, 5.0000000000e-1f, 1.0000000000e+0f, + 2.0000000000e+0f, 4.0000000000e+0f, 8.0000000000e+0f, 1.6000000000e+1f, + 3.2000000000e+1f, 6.4000000000e+1f, 1.2800000000e+2f, 2.5600000000e+2f, + 5.1200000000e+2f, 1.0240000000e+3f, 2.0480000000e+3f, 4.0960000000e+3f, + 8.1920000000e+3f, 1.6384000000e+4f, 3.2768000000e+4f, 6.5536000000e+4f, +}; + +static const uint8_t at9_tab_sf_weights[][32] = { + { + 0, 0, 0, 1, 1, 2, 2, 2, 2, 2, 2, 3, 2, 3, 3, 4, 4, 4, + 4, 4, 4, 5, 5, 6, 6, 7, 7, 8, 10, 12, 12, 12, + }, + { + 3, 2, 2, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, + 1, 1, 1, 1, 1, 2, 3, 3, 4, 5, 7, 10, 10, 10, + }, + { + 0, 2, 4, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 7, 7, 7, 7, 8, 9, 12, 12, 12, + }, + { + 0, 1, 1, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6, + 6, 6, 6, 7, 8, 8, 10, 11, 11, 12, 13, 13, 13, 13, + }, + { + 0, 2, 2, 3, 3, 4, 4, 5, 4, 5, 5, 5, 5, 6, 7, 8, 8, 8, + 8, 9, 9, 9, 10, 10, 11, 12, 12, 13, 13, 14, 14, 14, + }, + { + 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, + 2, 3, 3, 3, 4, 4, 5, 6, 7, 7, 9, 11, 11, 11, + }, + { + 0, 5, 8, 10, 11, 11, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 12, 12, 12, 12, 13, 15, 15, 15, + }, + { + 0, 2, 3, 4, 5, 6, 6, 7, 7, 8, 8, 8, 9, 9, 10, 10, 10, 11, + 11, 11, 11, 11, 11, 12, 12, 12, 12, 13, 13, 15, 15, 15, + }, +}; + +static const uint8_t at9_tab_b_dist[] = { + 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 4, 4, 5, 5, 6, 7, 8, + 9, 10, 11, 12, 13, 15, 6, 18, 19, 20, 21, 22, 23, 24, 25, 26, 26, 27, + 27, 28, 28, 28, 29, 29, 29, 29, 30, 30, 30, 30, +}; + +static const uint8_t huff_sfb_a1_bits[] = { + 1, 1, +}; + +static const uint16_t huff_sfb_a1_codes[] = { + 0x00, 0x01, +}; + +static const uint8_t huff_sfb_a2_bits[] = { + 1, 3, 3, 2, +}; + +static const uint16_t huff_sfb_a2_codes[] = { + 0x00, 0x06, 0x07, 0x02, +}; + +static const uint8_t huff_sfb_a3_bits[] = { + 2, 2, 4, 6, 6, 5, 3, 2, +}; + +static const uint16_t huff_sfb_a3_codes[] = { + 0x00, 0x01, 0x0E, 0x3E, 0x3F, 0x1E, 0x06, 0x02, +}; + +static const uint8_t huff_sfb_a4_bits[] = { + 2, 2, 4, 5, 6, 7, 8, 8, 8, 8, 8, 8, 6, 5, 4, 2, +}; + +static const uint16_t huff_sfb_a4_codes[] = { + 0x01, 0x02, 0x00, 0x06, 0x0F, 0x13, 0x23, 0x24, + 0x25, 0x22, 0x21, 0x20, 0x0E, 0x05, 0x01, 0x03, +}; + +static const uint8_t huff_sfb_a5_bits[] = { + 2, 3, 3, 4, 5, 5, 6, 7, 7, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 6, 5, 5, 4, 3, +}; + +static const uint16_t huff_sfb_a5_codes[] = { + 0x02, 0x01, 0x07, 0x0D, 0x0C, 0x18, 0x1B, 0x21, 0x3F, 0x6A, 0x6B, 0x68, + 0x73, 0x79, 0x7C, 0x7D, 0x7A, 0x7B, 0x78, 0x72, 0x44, 0x45, 0x47, 0x46, + 0x69, 0x38, 0x20, 0x1D, 0x19, 0x09, 0x05, 0x00, +}; + +static const uint8_t huff_sfb_a6_bits[] = { + 3, 3, 4, 4, 5, 5, 6, 6, 6, 7, 7, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 7, 7, 7, 6, 6, 5, 5, 5, 4, 4, 4, +}; + +static const uint16_t huff_sfb_a6_codes[] = { + 0x00, 0x01, 0x04, 0x05, 0x12, 0x13, 0x2E, 0x2F, 0x30, 0x66, 0x67, 0xD6, + 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, 0xE0, 0xE1, 0xE2, + 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, + 0xEF, 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, + 0xFB, 0xFC, 0xFD, 0xFE, 0xFF, 0x68, 0x69, 0x6A, 0x31, 0x32, 0x14, 0x15, + 0x16, 0x06, 0x07, 0x08, +}; + +static const uint8_t huff_sfb_b2_bits[] = { + 1, 2, 0, 2, +}; + +static const uint16_t huff_sfb_b2_codes[] = { + 0x00, 0x03, 0x00, 0x02, +}; + +static const uint8_t huff_sfb_b3_bits[] = { + 1, 3, 5, 6, 0, 6, 4, 2, +}; + +static const uint16_t huff_sfb_b3_codes[] = { + 0x01, 0x00, 0x04, 0x0B, 0x00, 0x0A, 0x03, 0x01, +}; + +static const uint8_t huff_sfb_b4_bits[] = { + 1, 3, 4, 5, 5, 7, 8, 8, 0, 8, 8, 7, 6, 6, 4, 3, +}; + +static const uint16_t huff_sfb_b4_codes[] = { + 0x01, 0x01, 0x04, 0x0E, 0x0F, 0x2C, 0x5A, 0x5D, 0x00, 0x5C, 0x5B, 0x2F, + 0x15, 0x14, 0x06, 0x00, +}; + +static const uint8_t huff_sfb_b5_bits[] = { + 3, 3, 4, 4, 4, 4, 4, 4, 4, 5, 6, 7, 7, 7, 8, 8, + 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, 3, +}; + +static const uint16_t huff_sfb_b5_codes[] = { + 0x00, 0x05, 0x07, 0x0C, 0x04, 0x02, 0x03, 0x05, 0x09, 0x10, 0x23, 0x33, + 0x36, 0x6E, 0x60, 0x65, 0x62, 0x61, 0x63, 0x64, 0x6F, 0x6D, 0x6C, 0x6B, + 0x6A, 0x68, 0x69, 0x45, 0x44, 0x37, 0x1A, 0x07, +}; + +typedef struct HuffmanCodebook { + const uint8_t *bits; + const uint16_t *codes; + const int size; + const int value_cnt; + const int value_cnt_pow; + const int value_bits; + const int max_bit_size; +} HuffmanCodebook; + +static const HuffmanCodebook at9_huffman_sf_unsigned[] = { + { 0 }, + { huff_sfb_a1_bits, huff_sfb_a1_codes, 2, 1, 0, 1, 1, }, + { huff_sfb_a2_bits, huff_sfb_a2_codes, 4, 1, 0, 2, 3, }, + { huff_sfb_a3_bits, huff_sfb_a3_codes, 8, 1, 0, 3, 6, }, + { huff_sfb_a4_bits, huff_sfb_a4_codes, 16, 1, 0, 4, 8, }, + { huff_sfb_a5_bits, huff_sfb_a5_codes, 32, 1, 0, 5, 8, }, + { huff_sfb_a6_bits, huff_sfb_a6_codes, 64, 1, 0, 6, 8, }, +}; + +static const HuffmanCodebook at9_huffman_sf_signed[] = { + { 0 }, + { 0 }, + { huff_sfb_b2_bits, huff_sfb_b2_codes, 4, 1, 0, 2, 2, }, + { huff_sfb_b3_bits, huff_sfb_b3_codes, 8, 1, 0, 3, 6, }, + { huff_sfb_b4_bits, huff_sfb_b4_codes, 16, 1, 0, 4, 8, }, + { huff_sfb_b5_bits, huff_sfb_b5_codes, 32, 1, 0, 5, 8, }, +}; + +static const uint8_t huff_spec_a21_bits[] = { + 0, 3, 0, 3, 3, 3, 0, 3, 0, 0, 0, 0, 3, 3, 0, 3, +}; + +static const uint16_t huff_spec_a21_codes[] = { + 0x00, 0x00, 0x00, 0x01, 0x03, 0x07, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x05, 0x00, 0x06, +}; + +static const uint8_t huff_spec_a22_bits[] = { + 0, 4, 0, 4, 5, 6, 0, 6, 0, 0, 0, 0, 5, 6, 0, 6, + 5, 6, 0, 6, 6, 7, 0, 7, 0, 0, 0, 0, 6, 7, 0, 7, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 5, 6, 0, 6, 6, 7, 0, 7, 0, 0, 0, 0, 6, 7, 0, 7, + 5, 6, 0, 6, 7, 7, 0, 7, 0, 0, 0, 0, 6, 7, 0, 7, + 6, 7, 0, 7, 7, 8, 0, 8, 0, 0, 0, 0, 7, 8, 0, 7, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 6, 7, 0, 7, 7, 8, 0, 8, 0, 0, 0, 0, 7, 7, 0, 8, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 5, 6, 0, 6, 6, 7, 0, 7, 0, 0, 0, 0, 7, 7, 0, 7, + 6, 7, 0, 7, 7, 8, 0, 7, 0, 0, 0, 0, 7, 8, 0, 8, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 6, 7, 0, 7, 7, 7, 0, 8, 0, 0, 0, 0, 7, 8, 0, 8, +}; + +static const uint16_t huff_spec_a22_codes[] = { + 0x00, 0x02, 0x00, 0x03, 0x10, 0x3C, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x11, 0x3E, 0x00, 0x3D, + 0x0E, 0x00, 0x00, 0x39, 0x18, 0x26, 0x00, 0x75, 0x00, 0x00, 0x00, 0x00, 0x1B, 0x24, 0x00, 0x6D, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0F, 0x38, 0x00, 0x01, 0x1A, 0x6C, 0x00, 0x25, 0x00, 0x00, 0x00, 0x00, 0x19, 0x74, 0x00, 0x27, + 0x16, 0x14, 0x00, 0x17, 0x76, 0x06, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x35, 0x64, 0x00, 0x6F, + 0x26, 0x04, 0x00, 0x63, 0x22, 0xA2, 0x00, 0x97, 0x00, 0x00, 0x00, 0x00, 0x67, 0xA0, 0x00, 0x0D, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x2B, 0x52, 0x00, 0x0B, 0x20, 0x92, 0x00, 0x91, 0x00, 0x00, 0x00, 0x00, 0x61, 0x0E, 0x00, 0x95, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x17, 0x16, 0x00, 0x15, 0x34, 0x6E, 0x00, 0x65, 0x00, 0x00, 0x00, 0x00, 0x77, 0x08, 0x00, 0x07, + 0x2A, 0x0A, 0x00, 0x53, 0x60, 0x94, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x21, 0x90, 0x00, 0x93, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x27, 0x62, 0x00, 0x05, 0x66, 0x0C, 0x00, 0xA1, 0x00, 0x00, 0x00, 0x00, 0x23, 0x96, 0x00, 0xA3, +}; + +static const uint8_t huff_spec_a23_bits[] = { + 3, 4, 0, 4, 5, 6, 0, 6, 0, 0, 0, 0, 5, 6, 0, 6, + 5, 7, 0, 6, 6, 8, 0, 7, 0, 0, 0, 0, 6, 8, 0, 7, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 5, 6, 0, 7, 6, 7, 0, 8, 0, 0, 0, 0, 6, 7, 0, 8, + 5, 6, 0, 6, 7, 8, 0, 8, 0, 0, 0, 0, 6, 7, 0, 7, + 6, 8, 0, 7, 8, 9, 0, 9, 0, 0, 0, 0, 7, 9, 0, 8, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 6, 8, 0, 8, 8, 9, 0, 9, 0, 0, 0, 0, 7, 8, 0, 9, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 5, 6, 0, 6, 6, 7, 0, 7, 0, 0, 0, 0, 7, 8, 0, 8, + 6, 8, 0, 8, 7, 9, 0, 8, 0, 0, 0, 0, 8, 9, 0, 9, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 6, 7, 0, 8, 7, 8, 0, 9, 0, 0, 0, 0, 8, 9, 0, 9, +}; + +static const uint16_t huff_spec_a23_codes[] = { + 0x006, 0x002, 0x000, 0x003, 0x016, 0x01E, 0x000, 0x021, 0x000, 0x000, 0x000, 0x000, + 0x017, 0x020, 0x000, 0x01F, 0x01C, 0x054, 0x000, 0x027, 0x010, 0x0A6, 0x000, 0x027, + 0x000, 0x000, 0x000, 0x000, 0x015, 0x0A4, 0x000, 0x02D, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x01D, 0x026, 0x000, 0x055, 0x014, 0x02C, 0x000, 0x0A5, 0x000, 0x000, 0x000, 0x000, + 0x011, 0x026, 0x000, 0x0A7, 0x01E, 0x000, 0x000, 0x003, 0x04A, 0x074, 0x000, 0x071, + 0x000, 0x000, 0x000, 0x000, 0x023, 0x00A, 0x000, 0x009, 0x018, 0x072, 0x000, 0x00D, + 0x0A2, 0x15A, 0x000, 0x123, 0x000, 0x000, 0x000, 0x000, 0x00F, 0x158, 0x000, 0x05D, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x01B, 0x0AE, 0x000, 0x077, 0x092, 0x140, 0x000, 0x121, + 0x000, 0x000, 0x000, 0x000, 0x025, 0x05E, 0x000, 0x143, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x01F, 0x002, 0x000, 0x001, 0x022, 0x008, 0x000, 0x00B, 0x000, 0x000, 0x000, 0x000, + 0x04B, 0x070, 0x000, 0x075, 0x01A, 0x076, 0x000, 0x0AF, 0x024, 0x142, 0x000, 0x05F, + 0x000, 0x000, 0x000, 0x000, 0x093, 0x120, 0x000, 0x141, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x019, 0x00C, 0x000, 0x073, 0x00E, 0x05C, 0x000, 0x159, 0x000, 0x000, 0x000, 0x000, + 0x0A3, 0x122, 0x000, 0x15B, +}; + +static const uint8_t huff_spec_a24_bits[] = { + 2, 4, 0, 4, 5, 6, 0, 6, 0, 0, 0, 0, 5, 6, 0, 6, + 5, 7, 0, 6, 6, 8, 0, 8, 0, 0, 0, 0, 6, 8, 0, 8, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 5, 6, 0, 7, 6, 8, 0, 8, 0, 0, 0, 0, 6, 8, 0, 8, + 5, 7, 0, 7, 7, 9, 0, 9, 0, 0, 0, 0, 6, 8, 0, 8, + 6, 9, 0, 8, 8, 10, 0, 10, 0, 0, 0, 0, 8, 10, 0, 9, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 6, 8, 0, 9, 9, 10, 0, 10, 0, 0, 0, 0, 8, 9, 0, 10, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 5, 7, 0, 7, 6, 8, 0, 8, 0, 0, 0, 0, 7, 9, 0, 9, + 6, 9, 0, 8, 8, 10, 0, 9, 0, 0, 0, 0, 9, 10, 0, 10, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 6, 8, 0, 9, 8, 9, 0, 10, 0, 0, 0, 0, 8, 10, 0, 10, +}; + +static const uint16_t huff_spec_a24_codes[] = { + 0x002, 0x002, 0x000, 0x003, 0x01E, 0x010, 0x000, 0x013, 0x000, 0x000, 0x000, 0x000, + 0x01F, 0x012, 0x000, 0x011, 0x01A, 0x030, 0x000, 0x01B, 0x000, 0x064, 0x000, 0x0C1, + 0x000, 0x000, 0x000, 0x000, 0x003, 0x052, 0x000, 0x07D, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x01B, 0x01A, 0x000, 0x031, 0x002, 0x07C, 0x000, 0x053, 0x000, 0x000, 0x000, 0x000, + 0x001, 0x0C0, 0x000, 0x065, 0x01C, 0x062, 0x000, 0x065, 0x02A, 0x198, 0x000, 0x19B, + 0x000, 0x000, 0x000, 0x000, 0x017, 0x078, 0x000, 0x07B, 0x004, 0x0FE, 0x000, 0x077, + 0x050, 0x33A, 0x000, 0x1F9, 0x000, 0x000, 0x000, 0x000, 0x073, 0x338, 0x000, 0x0E1, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x007, 0x066, 0x000, 0x187, 0x19E, 0x308, 0x000, 0x30B, + 0x000, 0x000, 0x000, 0x000, 0x075, 0x0E2, 0x000, 0x1FB, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x01D, 0x064, 0x000, 0x063, 0x016, 0x07A, 0x000, 0x079, 0x000, 0x000, 0x000, 0x000, + 0x02B, 0x19A, 0x000, 0x199, 0x006, 0x186, 0x000, 0x067, 0x074, 0x1FA, 0x000, 0x0E3, + 0x000, 0x000, 0x000, 0x000, 0x19F, 0x30A, 0x000, 0x309, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x005, 0x076, 0x000, 0x0FF, 0x072, 0x0E0, 0x000, 0x339, 0x000, 0x000, 0x000, 0x000, + 0x051, 0x1F8, 0x000, 0x33B, +}; + +static const uint8_t huff_spec_a31_bits[] = { + 0, 0, 4, 5, 0, 5, 4, 0, 0, 0, 5, 5, 0, 5, 5, 0, + 5, 5, 6, 6, 0, 6, 5, 5, 5, 6, 6, 7, 0, 7, 6, 6, + 0, 0, 0, 0, 0, 0, 0, 0, 5, 6, 6, 7, 0, 7, 6, 6, + 5, 5, 5, 6, 0, 6, 6, 5, 0, 0, 5, 5, 0, 5, 5, 0, +}; + +static const uint16_t huff_spec_a31_codes[] = { + 0x00, 0x00, 0x02, 0x18, 0x00, 0x19, 0x03, 0x00, 0x00, 0x00, 0x12, 0x02, 0x00, 0x09, 0x15, 0x00, + 0x1A, 0x0A, 0x3E, 0x2C, 0x00, 0x2F, 0x01, 0x0D, 0x0E, 0x38, 0x20, 0x78, 0x00, 0x7B, 0x23, 0x3B, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x3A, 0x22, 0x7A, 0x00, 0x79, 0x21, 0x39, + 0x1B, 0x0C, 0x00, 0x2E, 0x00, 0x2D, 0x3F, 0x0B, 0x00, 0x00, 0x14, 0x08, 0x00, 0x03, 0x13, 0x00, +}; + +static const uint8_t huff_spec_a32_bits[] = { + 4, 5, 5, 6, 0, 6, 5, 5, 5, 6, 5, 6, 0, 6, 5, 5, + 5, 5, 6, 7, 0, 7, 6, 5, 6, 6, 7, 7, 0, 7, 7, 6, + 0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 7, 7, 0, 7, 7, 6, + 5, 5, 6, 7, 0, 7, 6, 5, 5, 5, 5, 6, 0, 6, 5, 6, +}; + +static const uint16_t huff_spec_a32_codes[] = { + 0x0D, 0x18, 0x16, 0x3A, 0x00, 0x3B, 0x17, 0x19, 0x12, 0x3E, 0x08, 0x1C, 0x00, 0x1B, 0x07, 0x01, + 0x10, 0x02, 0x28, 0x78, 0x00, 0x7B, 0x1F, 0x05, 0x2A, 0x16, 0x72, 0x2A, 0x00, 0x29, 0x71, 0x19, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2B, 0x18, 0x70, 0x28, 0x00, 0x2B, 0x73, 0x17, + 0x11, 0x04, 0x1E, 0x7A, 0x00, 0x79, 0x29, 0x03, 0x13, 0x00, 0x06, 0x1A, 0x00, 0x1D, 0x09, 0x3F, +}; + +static const uint8_t huff_spec_a33_bits[] = { + 3, 4, 5, 6, 0, 6, 5, 4, 4, 5, 6, 7, 0, 7, 6, 5, + 5, 6, 6, 7, 0, 7, 6, 6, 6, 7, 8, 8, 0, 8, 8, 7, + 0, 0, 0, 0, 0, 0, 0, 0, 6, 7, 8, 8, 0, 8, 8, 7, + 5, 6, 6, 7, 0, 7, 6, 6, 4, 5, 6, 7, 0, 7, 6, 5, +}; + +static const uint16_t huff_spec_a33_codes[] = { + 0x05, 0x06, 0x10, 0x08, 0x00, 0x09, 0x11, 0x07, 0x04, 0x12, 0x3E, 0x6A, 0x00, 0x6D, 0x3D, 0x19, + 0x06, 0x3A, 0x06, 0x02, 0x00, 0x01, 0x05, 0x39, 0x02, 0x16, 0xDC, 0x2A, 0x00, 0x29, 0xDF, 0x69, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x68, 0xDE, 0x28, 0x00, 0x2B, 0xDD, 0x17, + 0x07, 0x38, 0x04, 0x00, 0x00, 0x03, 0x07, 0x3B, 0x05, 0x18, 0x3C, 0x6C, 0x00, 0x6B, 0x3F, 0x13, +}; + +static const uint8_t huff_spec_a34_bits[] = { + 2, 4, 5, 7, 0, 7, 5, 4, 4, 5, 6, 8, 0, 8, 6, 5, + 5, 6, 7, 8, 0, 8, 7, 6, 7, 8, 8, 10, 0, 10, 9, 8, + 0, 0, 0, 0, 0, 0, 0, 0, 7, 8, 9, 10, 0, 10, 8, 8, + 5, 6, 7, 8, 0, 8, 7, 6, 4, 5, 6, 8, 0, 8, 6, 5, +}; + +static const uint16_t huff_spec_a34_codes[] = { + 0x000, 0x00A, 0x00A, 0x034, 0x000, 0x035, 0x00B, 0x00B, 0x008, 0x01C, 0x032, 0x0DA, + 0x000, 0x0DD, 0x035, 0x01F, 0x008, 0x01E, 0x03A, 0x06C, 0x000, 0x063, 0x039, 0x031, + 0x032, 0x06E, 0x060, 0x37A, 0x000, 0x379, 0x1BF, 0x0D9, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x033, 0x0D8, 0x1BE, 0x378, 0x000, 0x37B, 0x061, 0x06F, + 0x009, 0x030, 0x038, 0x062, 0x000, 0x06D, 0x03B, 0x01F, 0x009, 0x01E, 0x034, 0x0DC, + 0x000, 0x0DB, 0x033, 0x01D, +}; + +static const uint8_t huff_spec_a41_bits[] = { + 0, 0, 0, 0, 6, 6, 7, 7, 0, 7, 7, 6, 6, 0, 0, 0, + 0, 0, 0, 0, 7, 7, 7, 7, 0, 7, 7, 7, 6, 0, 0, 0, + 0, 0, 0, 0, 7, 7, 7, 8, 0, 8, 7, 7, 7, 0, 0, 0, + 0, 0, 0, 0, 7, 7, 8, 8, 0, 8, 8, 7, 7, 0, 0, 0, + 7, 7, 7, 8, 7, 8, 8, 8, 0, 8, 8, 8, 7, 8, 7, 7, + 7, 7, 7, 7, 8, 8, 8, 9, 0, 8, 8, 8, 8, 7, 7, 7, + 7, 7, 8, 8, 8, 8, 9, 9, 0, 9, 8, 8, 8, 8, 8, 7, + 8, 8, 8, 8, 8, 9, 9, 9, 0, 9, 9, 9, 8, 8, 8, 8, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 8, 8, 8, 8, 8, 9, 9, 9, 0, 9, 9, 9, 8, 8, 8, 8, + 7, 7, 8, 8, 8, 8, 8, 9, 0, 9, 9, 8, 8, 8, 8, 7, + 7, 7, 7, 7, 8, 8, 8, 8, 0, 9, 8, 8, 8, 7, 7, 7, + 7, 7, 7, 8, 7, 8, 8, 8, 0, 8, 8, 8, 7, 8, 7, 7, + 0, 0, 0, 0, 7, 7, 8, 8, 0, 8, 8, 7, 7, 0, 0, 0, + 0, 0, 0, 0, 7, 7, 7, 8, 0, 8, 7, 7, 7, 0, 0, 0, + 0, 0, 0, 0, 6, 7, 7, 7, 0, 7, 7, 7, 7, 0, 0, 0, +}; + +static const uint16_t huff_spec_a41_codes[] = { + 0x000, 0x000, 0x000, 0x000, 0x018, 0x00E, 0x05E, 0x028, 0x000, 0x029, 0x05F, 0x00F, + 0x019, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x076, 0x06E, 0x03E, 0x004, + 0x000, 0x017, 0x045, 0x07B, 0x013, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x04A, 0x048, 0x010, 0x0CE, 0x000, 0x0E1, 0x023, 0x055, 0x053, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x008, 0x018, 0x0D6, 0x09E, 0x000, 0x09D, 0x0E5, 0x02B, + 0x01B, 0x000, 0x000, 0x000, 0x07C, 0x05C, 0x038, 0x0FC, 0x002, 0x0D2, 0x09A, 0x05C, + 0x000, 0x06B, 0x0A3, 0x0D9, 0x00F, 0x0FF, 0x03D, 0x061, 0x074, 0x056, 0x036, 0x000, + 0x0CC, 0x08C, 0x058, 0x1E2, 0x000, 0x00F, 0x05F, 0x0A1, 0x0D5, 0x00D, 0x03B, 0x059, + 0x040, 0x014, 0x0DA, 0x0B6, 0x084, 0x040, 0x1E0, 0x196, 0x000, 0x1A1, 0x00D, 0x043, + 0x087, 0x0C7, 0x0E3, 0x00B, 0x0F2, 0x0C4, 0x08E, 0x05A, 0x024, 0x1CC, 0x194, 0x168, + 0x000, 0x16B, 0x1A3, 0x1CF, 0x027, 0x069, 0x099, 0x0C9, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x0F3, 0x0C8, 0x098, 0x068, 0x026, 0x1CE, 0x1A2, 0x16A, 0x000, 0x169, 0x195, 0x1CD, + 0x025, 0x05B, 0x08F, 0x0C5, 0x041, 0x00A, 0x0E2, 0x0C6, 0x086, 0x042, 0x00C, 0x1A0, + 0x000, 0x197, 0x1E1, 0x041, 0x085, 0x0B7, 0x0DB, 0x015, 0x075, 0x058, 0x03A, 0x00C, + 0x0D4, 0x0A0, 0x05E, 0x00E, 0x000, 0x1E3, 0x059, 0x08D, 0x0CD, 0x001, 0x037, 0x057, + 0x07D, 0x060, 0x03C, 0x0FE, 0x00E, 0x0D8, 0x0A2, 0x06A, 0x000, 0x05D, 0x09B, 0x0D3, + 0x003, 0x0FD, 0x039, 0x05D, 0x000, 0x000, 0x000, 0x000, 0x01A, 0x02A, 0x0E4, 0x09C, + 0x000, 0x09F, 0x0D7, 0x019, 0x009, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x052, 0x054, 0x022, 0x0E0, 0x000, 0x0CF, 0x011, 0x049, 0x04B, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x012, 0x07A, 0x044, 0x016, 0x000, 0x005, 0x03F, 0x06F, + 0x077, 0x000, 0x000, 0x000, +}; + +static const uint8_t huff_spec_a42_bits[] = { + 5, 6, 7, 7, 7, 7, 8, 8, 0, 8, 8, 7, 7, 7, 7, 6, + 6, 7, 7, 8, 7, 7, 8, 8, 0, 8, 8, 7, 7, 8, 7, 7, + 7, 7, 8, 8, 7, 8, 8, 9, 0, 9, 8, 8, 7, 8, 8, 7, + 8, 8, 8, 8, 8, 8, 8, 9, 0, 9, 8, 8, 8, 8, 8, 8, + 7, 7, 7, 8, 8, 8, 9, 9, 0, 9, 9, 8, 8, 8, 7, 7, + 7, 7, 8, 8, 8, 9, 9, 9, 0, 9, 9, 9, 8, 8, 8, 7, + 8, 8, 8, 8, 9, 9, 9, 10, 0, 10, 9, 9, 9, 8, 8, 8, + 8, 8, 9, 9, 9, 9, 10, 10, 0, 10, 10, 9, 9, 9, 9, 9, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 8, 9, 9, 9, 9, 9, 10, 10, 0, 10, 10, 9, 9, 9, 9, 8, + 8, 8, 8, 8, 9, 9, 9, 10, 0, 10, 9, 9, 9, 8, 8, 8, + 7, 7, 8, 8, 8, 9, 9, 9, 0, 9, 9, 9, 8, 8, 8, 7, + 7, 7, 7, 8, 8, 8, 9, 9, 0, 9, 9, 8, 8, 8, 7, 7, + 8, 8, 8, 8, 8, 8, 8, 9, 0, 9, 8, 8, 8, 8, 8, 8, + 7, 7, 8, 8, 7, 8, 8, 9, 0, 9, 8, 8, 7, 8, 8, 7, + 6, 7, 7, 8, 7, 7, 8, 8, 0, 8, 8, 7, 7, 8, 7, 7, +}; + +static const uint16_t huff_spec_a42_codes[] = { + 0x003, 0x018, 0x058, 0x000, 0x066, 0x03C, 0x0D6, 0x07C, 0x000, 0x07D, 0x0D7, 0x03D, + 0x067, 0x001, 0x059, 0x019, 0x002, 0x064, 0x036, 0x0DA, 0x04C, 0x01C, 0x0BE, 0x02C, + 0x000, 0x037, 0x0C5, 0x029, 0x04B, 0x0E7, 0x03B, 0x069, 0x044, 0x02E, 0x0FA, 0x092, + 0x020, 0x0F8, 0x086, 0x1FC, 0x000, 0x1E7, 0x07F, 0x0F5, 0x023, 0x0AD, 0x0FD, 0x02D, + 0x0F6, 0x0DC, 0x09C, 0x03E, 0x0F0, 0x0B6, 0x026, 0x186, 0x000, 0x18D, 0x02F, 0x0B5, + 0x0E1, 0x03D, 0x0AF, 0x0D9, 0x054, 0x040, 0x014, 0x0EC, 0x0BC, 0x054, 0x1C6, 0x108, + 0x000, 0x10B, 0x1C5, 0x069, 0x0B9, 0x0DF, 0x019, 0x047, 0x026, 0x008, 0x0E4, 0x0A2, + 0x056, 0x1DC, 0x142, 0x06A, 0x000, 0x091, 0x123, 0x1DF, 0x04B, 0x0A7, 0x0EB, 0x00B, + 0x0C0, 0x09E, 0x06A, 0x022, 0x1AA, 0x140, 0x092, 0x3CA, 0x000, 0x3A7, 0x04B, 0x121, + 0x18F, 0x007, 0x071, 0x0A5, 0x020, 0x004, 0x1A8, 0x174, 0x0E4, 0x068, 0x3A4, 0x2EE, + 0x000, 0x2ED, 0x3C9, 0x049, 0x0E7, 0x185, 0x1D1, 0x1FF, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x021, 0x1FE, 0x1D0, 0x184, 0x0E6, 0x048, 0x3C8, 0x2EC, 0x000, 0x2EF, 0x3A5, 0x069, + 0x0E5, 0x175, 0x1A9, 0x005, 0x0C1, 0x0A4, 0x070, 0x006, 0x18E, 0x120, 0x04A, 0x3A6, + 0x000, 0x3CB, 0x093, 0x141, 0x1AB, 0x023, 0x06B, 0x09F, 0x027, 0x00A, 0x0EA, 0x0A6, + 0x04A, 0x1DE, 0x122, 0x090, 0x000, 0x06B, 0x143, 0x1DD, 0x057, 0x0A3, 0x0E5, 0x009, + 0x055, 0x046, 0x018, 0x0DE, 0x0B8, 0x068, 0x1C4, 0x10A, 0x000, 0x109, 0x1C7, 0x055, + 0x0BD, 0x0ED, 0x015, 0x041, 0x0F7, 0x0D8, 0x0AE, 0x03C, 0x0E0, 0x0B4, 0x02E, 0x18C, + 0x000, 0x187, 0x027, 0x0B7, 0x0F1, 0x03F, 0x09D, 0x0DD, 0x045, 0x02C, 0x0FC, 0x0AC, + 0x022, 0x0F4, 0x07E, 0x1E6, 0x000, 0x1FD, 0x087, 0x0F9, 0x021, 0x093, 0x0FB, 0x02F, + 0x003, 0x068, 0x03A, 0x0E6, 0x04A, 0x028, 0x0C4, 0x036, 0x000, 0x02D, 0x0BF, 0x01D, + 0x04D, 0x0DB, 0x037, 0x065, +}; + +static const uint8_t huff_spec_a43_bits[] = { + 4, 6, 6, 7, 7, 8, 8, 9, 0, 9, 8, 8, 7, 7, 6, 6, + 5, 6, 7, 7, 7, 8, 8, 9, 0, 9, 8, 8, 7, 7, 7, 6, + 6, 7, 7, 7, 8, 8, 9, 9, 0, 9, 9, 8, 8, 7, 7, 7, + 7, 7, 7, 8, 8, 8, 9, 10, 0, 10, 9, 9, 8, 8, 7, 7, + 7, 7, 8, 8, 8, 9, 10, 10, 0, 10, 10, 9, 8, 8, 8, 7, + 8, 8, 8, 9, 9, 9, 10, 10, 0, 10, 10, 9, 9, 9, 8, 8, + 8, 9, 9, 9, 10, 10, 10, 10, 0, 10, 10, 10, 10, 9, 9, 9, + 9, 9, 10, 10, 10, 10, 10, 10, 0, 10, 10, 10, 10, 10, 10, 9, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 9, 9, 10, 10, 10, 10, 10, 10, 0, 10, 10, 10, 10, 10, 10, 9, + 8, 9, 9, 9, 10, 10, 10, 10, 0, 10, 10, 10, 10, 9, 9, 9, + 8, 8, 8, 9, 9, 9, 10, 10, 0, 10, 10, 9, 9, 9, 8, 8, + 7, 7, 8, 8, 8, 9, 10, 10, 0, 10, 10, 9, 8, 8, 8, 7, + 7, 7, 7, 8, 8, 9, 9, 10, 0, 10, 9, 8, 8, 8, 7, 7, + 6, 7, 7, 7, 8, 8, 9, 9, 0, 9, 9, 8, 8, 7, 7, 7, + 5, 6, 7, 7, 7, 8, 8, 9, 0, 9, 8, 8, 7, 7, 7, 6, +}; + +static const uint16_t huff_spec_a43_codes[] = { + 0x002, 0x03E, 0x016, 0x060, 0x04E, 0x0DC, 0x04A, 0x130, 0x000, 0x131, 0x04B, 0x0DD, + 0x04F, 0x061, 0x017, 0x03F, 0x002, 0x02C, 0x076, 0x042, 0x034, 0x0CE, 0x002, 0x0E8, + 0x000, 0x0CF, 0x001, 0x0D1, 0x037, 0x045, 0x07B, 0x02F, 0x014, 0x072, 0x052, 0x01A, + 0x0E0, 0x080, 0x198, 0x01E, 0x000, 0x01D, 0x19B, 0x083, 0x0DF, 0x019, 0x055, 0x079, + 0x050, 0x03C, 0x004, 0x0C4, 0x096, 0x00C, 0x0EA, 0x34A, 0x000, 0x34F, 0x0ED, 0x1D7, + 0x095, 0x0AF, 0x003, 0x03F, 0x046, 0x026, 0x0D6, 0x092, 0x046, 0x15A, 0x3A8, 0x108, + 0x000, 0x10F, 0x3A3, 0x135, 0x039, 0x091, 0x0D9, 0x031, 0x0D4, 0x0CA, 0x072, 0x1C6, + 0x136, 0x090, 0x2B2, 0x104, 0x000, 0x103, 0x111, 0x08B, 0x133, 0x1D3, 0x071, 0x0C9, + 0x03E, 0x1B4, 0x18C, 0x0CC, 0x38A, 0x2B0, 0x106, 0x0F2, 0x000, 0x0EF, 0x101, 0x113, + 0x3A1, 0x0CB, 0x18F, 0x1B7, 0x0EE, 0x092, 0x388, 0x348, 0x10A, 0x0F4, 0x0F0, 0x0EA, + 0x000, 0x0E9, 0x0ED, 0x0F7, 0x10D, 0x34D, 0x3AB, 0x0C9, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x0EF, 0x0C8, 0x3AA, 0x34C, 0x10C, 0x0F6, 0x0EC, 0x0E8, 0x000, 0x0EB, 0x0F1, 0x0F5, + 0x10B, 0x349, 0x389, 0x093, 0x03F, 0x1B6, 0x18E, 0x0CA, 0x3A0, 0x112, 0x100, 0x0EE, + 0x000, 0x0F3, 0x107, 0x2B1, 0x38B, 0x0CD, 0x18D, 0x1B5, 0x0D5, 0x0C8, 0x070, 0x1D2, + 0x132, 0x08A, 0x110, 0x102, 0x000, 0x105, 0x2B3, 0x091, 0x137, 0x1C7, 0x073, 0x0CB, + 0x047, 0x030, 0x0D8, 0x090, 0x038, 0x134, 0x3A2, 0x10E, 0x000, 0x109, 0x3A9, 0x15B, + 0x047, 0x093, 0x0D7, 0x027, 0x051, 0x03E, 0x002, 0x0AE, 0x094, 0x1D6, 0x0EC, 0x34E, + 0x000, 0x34B, 0x0EB, 0x00D, 0x097, 0x0C5, 0x005, 0x03D, 0x015, 0x078, 0x054, 0x018, + 0x0DE, 0x082, 0x19A, 0x01C, 0x000, 0x01F, 0x199, 0x081, 0x0E1, 0x01B, 0x053, 0x073, + 0x003, 0x02E, 0x07A, 0x044, 0x036, 0x0D0, 0x000, 0x0CE, 0x000, 0x0E9, 0x003, 0x0CF, + 0x035, 0x043, 0x077, 0x02D, +}; + +static const uint8_t huff_spec_a44_bits[] = { + 4, 5, 6, 7, 7, 8, 9, 10, 0, 10, 9, 8, 7, 7, 6, 5, + 5, 6, 6, 7, 7, 8, 9, 10, 0, 10, 9, 8, 7, 7, 6, 6, + 6, 6, 7, 7, 8, 9, 10, 10, 0, 10, 10, 9, 8, 7, 7, 6, + 7, 7, 7, 8, 8, 9, 10, 10, 0, 10, 10, 9, 8, 8, 7, 7, + 7, 8, 8, 8, 9, 10, 10, 10, 0, 10, 10, 10, 9, 8, 8, 7, + 8, 8, 9, 9, 10, 10, 10, 10, 0, 10, 10, 10, 10, 9, 9, 8, + 9, 9, 10, 10, 10, 10, 10, 10, 0, 10, 10, 10, 10, 10, 10, 9, + 10, 10, 10, 10, 10, 10, 10, 10, 0, 10, 10, 10, 10, 10, 10, 10, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 10, 10, 10, 10, 10, 10, 10, 10, 0, 10, 10, 10, 10, 10, 10, 10, + 9, 9, 10, 10, 10, 10, 10, 10, 0, 10, 10, 10, 10, 10, 10, 9, + 8, 8, 9, 9, 10, 10, 10, 10, 0, 10, 10, 10, 10, 9, 9, 8, + 7, 7, 8, 8, 9, 10, 10, 10, 0, 10, 10, 10, 9, 8, 8, 8, + 7, 7, 7, 8, 8, 9, 10, 10, 0, 10, 10, 9, 8, 8, 7, 7, + 6, 6, 7, 7, 8, 9, 10, 10, 0, 10, 10, 9, 8, 7, 7, 6, + 5, 6, 6, 7, 7, 8, 9, 10, 0, 10, 9, 8, 7, 7, 6, 6, +}; + +static const uint16_t huff_spec_a44_codes[] = { + 0x00A, 0x012, 0x030, 0x06E, 0x024, 0x074, 0x0EC, 0x07E, 0x000, 0x07F, 0x0ED, 0x075, + 0x025, 0x06F, 0x031, 0x013, 0x010, 0x03C, 0x018, 0x05A, 0x002, 0x046, 0x09E, 0x07C, + 0x000, 0x079, 0x0E5, 0x04D, 0x007, 0x065, 0x01B, 0x03F, 0x02E, 0x016, 0x072, 0x01A, + 0x0D6, 0x1C6, 0x3B4, 0x066, 0x000, 0x06B, 0x3B7, 0x1D9, 0x0D5, 0x021, 0x075, 0x015, + 0x06C, 0x03E, 0x01E, 0x0CC, 0x044, 0x0F2, 0x082, 0x05C, 0x000, 0x05F, 0x087, 0x0F5, + 0x031, 0x0CF, 0x017, 0x059, 0x01C, 0x0EE, 0x0D0, 0x024, 0x1C0, 0x08E, 0x06E, 0x048, + 0x000, 0x04D, 0x06D, 0x089, 0x0F7, 0x033, 0x0D3, 0x001, 0x070, 0x028, 0x1C2, 0x0F0, + 0x08A, 0x074, 0x054, 0x040, 0x000, 0x043, 0x053, 0x073, 0x099, 0x0EF, 0x1C5, 0x02B, + 0x0E6, 0x04E, 0x08C, 0x080, 0x068, 0x058, 0x046, 0x02A, 0x000, 0x029, 0x045, 0x051, + 0x065, 0x085, 0x09B, 0x09D, 0x07A, 0x076, 0x060, 0x056, 0x04E, 0x02C, 0x024, 0x022, + 0x000, 0x021, 0x027, 0x02F, 0x04B, 0x05B, 0x063, 0x071, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x07B, 0x070, 0x062, 0x05A, 0x04A, 0x02E, 0x026, 0x020, 0x000, 0x023, 0x025, 0x02D, + 0x04F, 0x057, 0x061, 0x077, 0x0E7, 0x09C, 0x09A, 0x084, 0x064, 0x050, 0x044, 0x028, + 0x000, 0x02B, 0x047, 0x059, 0x069, 0x081, 0x08D, 0x04F, 0x071, 0x02A, 0x1C4, 0x0EE, + 0x098, 0x072, 0x052, 0x042, 0x000, 0x041, 0x055, 0x075, 0x08B, 0x0F1, 0x1C3, 0x029, + 0x01D, 0x000, 0x0D2, 0x032, 0x0F6, 0x088, 0x06C, 0x04C, 0x000, 0x049, 0x06F, 0x08F, + 0x1C1, 0x025, 0x0D1, 0x0EF, 0x06D, 0x058, 0x016, 0x0CE, 0x030, 0x0F4, 0x086, 0x05E, + 0x000, 0x05D, 0x083, 0x0F3, 0x045, 0x0CD, 0x01F, 0x03F, 0x02F, 0x014, 0x074, 0x020, + 0x0D4, 0x1D8, 0x3B6, 0x06A, 0x000, 0x067, 0x3B5, 0x1C7, 0x0D7, 0x01B, 0x073, 0x017, + 0x011, 0x03E, 0x01A, 0x064, 0x006, 0x04C, 0x0E4, 0x078, 0x000, 0x07D, 0x09F, 0x047, + 0x003, 0x05B, 0x019, 0x03D, +}; + +static const uint8_t huff_spec_a51_bits[] = { + 5, 5, 5, 5, 5, 6, 6, 6, 4, 4, 5, 5, 5, 5, 5, 5, + 0, 5, 5, 5, 5, 5, 5, 4, 4, 6, 6, 6, 5, 5, 5, 5, +}; + +static const uint16_t huff_spec_a51_codes[] = { + 0x19, 0x16, 0x12, 0x0E, 0x06, 0x3A, 0x38, 0x30, 0x00, 0x04, 0x1E, 0x1A, + 0x14, 0x10, 0x0C, 0x04, 0x00, 0x05, 0x0D, 0x11, 0x15, 0x1B, 0x1F, 0x05, + 0x01, 0x31, 0x39, 0x3B, 0x07, 0x0F, 0x13, 0x17, +}; + +static const uint8_t huff_spec_a52_bits[] = { + 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, + 0, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, +}; + +static const uint16_t huff_spec_a52_codes[] = { + 0x09, 0x04, 0x00, 0x1E, 0x1A, 0x14, 0x0C, 0x06, 0x18, 0x16, 0x0E, 0x04, + 0x3A, 0x38, 0x22, 0x20, 0x00, 0x21, 0x23, 0x39, 0x3B, 0x05, 0x0F, 0x17, + 0x19, 0x07, 0x0D, 0x15, 0x1B, 0x1F, 0x01, 0x05, +}; + +static const uint8_t huff_spec_a53_bits[] = { + 3, 4, 4, 4, 5, 5, 5, 5, 5, 5, 6, 6, 7, 7, 7, 7, + 0, 7, 7, 7, 7, 6, 6, 5, 5, 5, 5, 5, 5, 4, 4, 4, +}; + +static const uint16_t huff_spec_a53_codes[] = { + 0x00, 0x0C, 0x08, 0x04, 0x1E, 0x16, 0x14, 0x06, 0x0C, 0x04, 0x38, 0x1E, + 0x76, 0x74, 0x3A, 0x38, 0x00, 0x39, 0x3B, 0x75, 0x77, 0x1F, 0x39, 0x05, + 0x0D, 0x07, 0x15, 0x17, 0x1F, 0x05, 0x09, 0x0D, +}; + +static const uint8_t huff_spec_a54_bits[] = { + 3, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 7, 7, 7, 8, 8, + 0, 8, 8, 7, 7, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, +}; + +static const uint16_t huff_spec_a54_codes[] = { + 0x02, 0x0E, 0x0A, 0x08, 0x02, 0x1A, 0x0E, 0x02, 0x00, 0x30, 0x18, 0x66, + 0x36, 0x34, 0xCA, 0xC8, 0x00, 0xC9, 0xCB, 0x35, 0x37, 0x67, 0x19, 0x31, + 0x01, 0x03, 0x0F, 0x1B, 0x03, 0x09, 0x0B, 0x0F, +}; + +static const uint8_t huff_spec_a61_bits[] = { + 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, + 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 0, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, + 5, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, +}; + +static const uint16_t huff_spec_a61_codes[] = { + 0x35, 0x30, 0x2A, 0x28, 0x24, 0x20, 0x18, 0x0E, 0x0C, 0x7E, 0x7C, 0x72, + 0x70, 0x68, 0x5E, 0x5C, 0x04, 0x0E, 0x08, 0x00, 0x3C, 0x3A, 0x36, 0x32, + 0x2C, 0x26, 0x22, 0x1A, 0x16, 0x14, 0x06, 0x04, 0x00, 0x05, 0x07, 0x15, + 0x17, 0x1B, 0x23, 0x27, 0x2D, 0x33, 0x37, 0x3B, 0x3D, 0x01, 0x09, 0x0F, + 0x05, 0x5D, 0x5F, 0x69, 0x71, 0x73, 0x7D, 0x7F, 0x0D, 0x0F, 0x19, 0x21, + 0x25, 0x29, 0x2B, 0x31, +}; + +static const uint8_t huff_spec_a62_bits[] = { + 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, + 0, 7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, +}; + +static const uint16_t huff_spec_a62_codes[] = { + 0x14, 0x0E, 0x08, 0x04, 0x02, 0x3E, 0x3C, 0x38, 0x34, 0x30, 0x2A, 0x24, + 0x1A, 0x18, 0x0E, 0x02, 0x32, 0x36, 0x2C, 0x26, 0x20, 0x16, 0x0C, 0x00, + 0x76, 0x74, 0x5E, 0x5C, 0x46, 0x44, 0x2A, 0x28, 0x00, 0x29, 0x2B, 0x45, + 0x47, 0x5D, 0x5F, 0x75, 0x77, 0x01, 0x0D, 0x17, 0x21, 0x27, 0x2D, 0x37, + 0x33, 0x03, 0x0F, 0x19, 0x1B, 0x25, 0x2B, 0x31, 0x35, 0x39, 0x3D, 0x3F, + 0x03, 0x05, 0x09, 0x0F, +}; + +static const uint8_t huff_spec_a63_bits[] = { + 4, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, + 0, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, +}; + +static const uint16_t huff_spec_a63_codes[] = { + 0x00, 0x1C, 0x18, 0x14, 0x10, 0x0A, 0x08, 0x02, 0x3E, 0x36, 0x2E, 0x2C, + 0x24, 0x1C, 0x0E, 0x08, 0x1E, 0x1A, 0x0C, 0x7A, 0x6A, 0x68, 0x4C, 0x32, + 0x16, 0x14, 0xF2, 0xF0, 0x9E, 0x9C, 0x62, 0x60, 0x00, 0x61, 0x63, 0x9D, + 0x9F, 0xF1, 0xF3, 0x15, 0x17, 0x33, 0x4D, 0x69, 0x6B, 0x7B, 0x0D, 0x1B, + 0x1F, 0x09, 0x0F, 0x1D, 0x25, 0x2D, 0x2F, 0x37, 0x3F, 0x03, 0x09, 0x0B, + 0x11, 0x15, 0x19, 0x1D, +}; + +static const uint8_t huff_spec_a64_bits[] = { + 4, 4, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 7, + 6, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, + 0, 9, 9, 9, 9, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, + 6, 7, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 4, +}; + +static const uint16_t huff_spec_a64_codes[] = { + 0x006, 0x002, 0x01C, 0x01A, 0x016, 0x012, 0x00E, 0x00A, 0x002, 0x03E, + 0x032, 0x02A, 0x022, 0x020, 0x010, 0x07A, 0x000, 0x078, 0x060, 0x050, + 0x024, 0x006, 0x0C6, 0x0C4, 0x0A4, 0x04E, 0x00A, 0x008, 0x14E, 0x14C, + 0x09A, 0x098, 0x000, 0x099, 0x09B, 0x14D, 0x14F, 0x009, 0x00B, 0x04F, + 0x0A5, 0x0C5, 0x0C7, 0x007, 0x025, 0x051, 0x061, 0x079, 0x001, 0x07B, + 0x011, 0x021, 0x023, 0x02B, 0x033, 0x03F, 0x003, 0x00B, 0x00F, 0x013, + 0x017, 0x01B, 0x01D, 0x003, +}; + +static const uint8_t huff_spec_a71_bits[] = { + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 0, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, + 6, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, +}; + +static const uint16_t huff_spec_a71_codes[] = { + 0x6C, 0x66, 0x62, 0x5C, 0x56, 0x50, 0x52, 0x4E, 0x48, 0x3E, 0x36, 0x34, 0x2A, 0x26, 0x1E, 0x16, + 0x0E, 0x08, 0x00, 0xF6, 0xF4, 0xEE, 0xEC, 0xE2, 0xE0, 0xDA, 0xD2, 0xD0, 0xBE, 0xBC, 0xB2, 0xB0, + 0x0C, 0x20, 0x1C, 0x16, 0x10, 0x08, 0x02, 0x7E, 0x7C, 0x78, 0x74, 0x72, 0x6E, 0x6A, 0x64, 0x60, + 0x5A, 0x54, 0x4C, 0x4A, 0x46, 0x44, 0x3C, 0x32, 0x30, 0x28, 0x24, 0x1C, 0x14, 0x0C, 0x0A, 0x02, + 0x00, 0x03, 0x0B, 0x0D, 0x15, 0x1D, 0x25, 0x29, 0x31, 0x33, 0x3D, 0x45, 0x47, 0x4B, 0x4D, 0x55, + 0x5B, 0x61, 0x65, 0x6B, 0x6F, 0x73, 0x75, 0x79, 0x7D, 0x7F, 0x03, 0x09, 0x11, 0x17, 0x1D, 0x21, + 0x0D, 0xB1, 0xB3, 0xBD, 0xBF, 0xD1, 0xD3, 0xDB, 0xE1, 0xE3, 0xED, 0xEF, 0xF5, 0xF7, 0x01, 0x09, + 0x0F, 0x17, 0x1F, 0x27, 0x2B, 0x35, 0x37, 0x3F, 0x49, 0x4F, 0x53, 0x51, 0x57, 0x5D, 0x63, 0x67, +}; + +static const uint8_t huff_spec_a72_bits[] = { + 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 0, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, +}; + +static const uint16_t huff_spec_a72_codes[] = { + 0x2A, 0x24, 0x1C, 0x18, 0x12, 0x0E, 0x0A, 0x06, 0x02, 0x7E, 0x7C, 0x7A, 0x76, 0x72, 0x70, 0x6A, + 0x68, 0x62, 0x5C, 0x5A, 0x52, 0x4E, 0x46, 0x42, 0x3C, 0x34, 0x2A, 0x28, 0x20, 0x12, 0x10, 0x08, + 0x66, 0x74, 0x6C, 0x64, 0x5E, 0x58, 0x50, 0x44, 0x40, 0x36, 0x2C, 0x22, 0x1A, 0x0A, 0x02, 0x00, + 0xF2, 0xF0, 0xDE, 0xDC, 0xC2, 0xC0, 0xAE, 0xAC, 0x9A, 0x98, 0x7E, 0x7C, 0x5E, 0x5C, 0x32, 0x30, + 0x00, 0x31, 0x33, 0x5D, 0x5F, 0x7D, 0x7F, 0x99, 0x9B, 0xAD, 0xAF, 0xC1, 0xC3, 0xDD, 0xDF, 0xF1, + 0xF3, 0x01, 0x03, 0x0B, 0x1B, 0x23, 0x2D, 0x37, 0x41, 0x45, 0x51, 0x59, 0x5F, 0x65, 0x6D, 0x75, + 0x67, 0x09, 0x11, 0x13, 0x21, 0x29, 0x2B, 0x35, 0x3D, 0x43, 0x47, 0x4F, 0x53, 0x5B, 0x5D, 0x63, + 0x69, 0x6B, 0x71, 0x73, 0x77, 0x7B, 0x7D, 0x7F, 0x03, 0x07, 0x0B, 0x0F, 0x13, 0x19, 0x1D, 0x25, +}; + +static const uint8_t huff_spec_a73_bits[] = { + 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, +}; + +static const uint16_t huff_spec_a73_codes[] = { + 0x003, 0x03E, 0x038, 0x034, 0x030, 0x02C, 0x028, 0x024, 0x020, 0x01C, 0x016, 0x014, + 0x00E, 0x00A, 0x004, 0x000, 0x07A, 0x076, 0x06E, 0x06C, 0x064, 0x05E, 0x056, 0x04E, + 0x04C, 0x044, 0x036, 0x030, 0x022, 0x018, 0x012, 0x004, 0x03C, 0x03E, 0x032, 0x024, + 0x020, 0x010, 0x0F2, 0x0F0, 0x0E8, 0x0CE, 0x0BA, 0x0B8, 0x0A8, 0x08C, 0x06A, 0x04E, + 0x04C, 0x034, 0x00E, 0x00C, 0x1D6, 0x1D4, 0x19A, 0x198, 0x156, 0x154, 0x11E, 0x11C, + 0x0D2, 0x0D0, 0x06E, 0x06C, 0x000, 0x06D, 0x06F, 0x0D1, 0x0D3, 0x11D, 0x11F, 0x155, + 0x157, 0x199, 0x19B, 0x1D5, 0x1D7, 0x00D, 0x00F, 0x035, 0x04D, 0x04F, 0x06B, 0x08D, + 0x0A9, 0x0B9, 0x0BB, 0x0CF, 0x0E9, 0x0F1, 0x0F3, 0x011, 0x021, 0x025, 0x033, 0x03F, + 0x03D, 0x005, 0x013, 0x019, 0x023, 0x031, 0x037, 0x045, 0x04D, 0x04F, 0x057, 0x05F, + 0x065, 0x06D, 0x06F, 0x077, 0x07B, 0x001, 0x005, 0x00B, 0x00F, 0x015, 0x017, 0x01D, + 0x021, 0x025, 0x029, 0x02D, 0x031, 0x035, 0x039, 0x03F, +}; + +static const uint8_t huff_spec_a74_bits[] = { + 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, + 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 0, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 7, 8, 8, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, +}; + +static const uint16_t huff_spec_a74_codes[] = { + 0x00D, 0x00A, 0x004, 0x000, 0x03A, 0x036, 0x032, 0x030, 0x02C, 0x028, 0x026, 0x022, + 0x01E, 0x018, 0x012, 0x00E, 0x006, 0x07E, 0x07A, 0x070, 0x06A, 0x05E, 0x056, 0x054, + 0x048, 0x040, 0x038, 0x022, 0x01A, 0x00A, 0x0F8, 0x0E6, 0x008, 0x0FA, 0x0F0, 0x0D2, + 0x0BA, 0x0B8, 0x094, 0x084, 0x074, 0x042, 0x032, 0x1E6, 0x1CA, 0x1C8, 0x1A2, 0x12E, + 0x10E, 0x10C, 0x0EC, 0x082, 0x062, 0x060, 0x3CA, 0x3C8, 0x342, 0x340, 0x25A, 0x258, + 0x1DE, 0x1DC, 0x102, 0x100, 0x000, 0x101, 0x103, 0x1DD, 0x1DF, 0x259, 0x25B, 0x341, + 0x343, 0x3C9, 0x3CB, 0x061, 0x063, 0x083, 0x0ED, 0x10D, 0x10F, 0x12F, 0x1A3, 0x1C9, + 0x1CB, 0x1E7, 0x033, 0x043, 0x075, 0x085, 0x095, 0x0B9, 0x0BB, 0x0D3, 0x0F1, 0x0FB, + 0x009, 0x0E7, 0x0F9, 0x00B, 0x01B, 0x023, 0x039, 0x041, 0x049, 0x055, 0x057, 0x05F, + 0x06B, 0x071, 0x07B, 0x07F, 0x007, 0x00F, 0x013, 0x019, 0x01F, 0x023, 0x027, 0x029, + 0x02D, 0x031, 0x033, 0x037, 0x03B, 0x001, 0x005, 0x00B, +}; + +static const uint8_t huff_spec_b22_bits[] = { + 0, 4, 0, 4, 4, 5, 0, 5, 0, 0, 0, 0, 4, 5, 0, 5, + 4, 7, 0, 6, 6, 9, 0, 7, 0, 0, 0, 0, 6, 9, 0, 7, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 4, 6, 0, 7, 6, 7, 0, 9, 0, 0, 0, 0, 6, 7, 0, 9, + 4, 8, 0, 8, 8, 10, 0, 10, 0, 0, 0, 0, 6, 9, 0, 9, + 5, 10, 0, 9, 9, 10, 0, 10, 0, 0, 0, 0, 7, 10, 0, 10, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 6, 9, 0, 10, 9, 10, 0, 10, 0, 0, 0, 0, 7, 10, 0, 10, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 4, 8, 0, 8, 6, 9, 0, 9, 0, 0, 0, 0, 8, 10, 0, 10, + 6, 10, 0, 9, 7, 10, 0, 10, 0, 0, 0, 0, 9, 10, 0, 10, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 5, 9, 0, 10, 7, 10, 0, 10, 0, 0, 0, 0, 9, 10, 0, 10, +}; + +static const uint16_t huff_spec_b22_codes[] = { + 0x000, 0x00E, 0x000, 0x00F, 0x008, 0x006, 0x000, 0x00B, 0x000, 0x000, 0x000, 0x000, + 0x009, 0x00A, 0x000, 0x007, 0x006, 0x00A, 0x000, 0x029, 0x006, 0x158, 0x000, 0x023, + 0x000, 0x000, 0x000, 0x000, 0x013, 0x174, 0x000, 0x021, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x007, 0x028, 0x000, 0x00B, 0x012, 0x020, 0x000, 0x175, 0x000, 0x000, 0x000, 0x000, + 0x007, 0x022, 0x000, 0x159, 0x00C, 0x0BC, 0x000, 0x0BF, 0x022, 0x2B8, 0x000, 0x2BB, + 0x000, 0x000, 0x000, 0x000, 0x00B, 0x170, 0x000, 0x15B, 0x000, 0x04E, 0x000, 0x15F, + 0x042, 0x04A, 0x000, 0x041, 0x000, 0x000, 0x000, 0x000, 0x055, 0x044, 0x000, 0x04D, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x02D, 0x172, 0x000, 0x2ED, 0x040, 0x042, 0x000, 0x047, + 0x000, 0x000, 0x000, 0x000, 0x013, 0x2EE, 0x000, 0x049, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x00D, 0x0BE, 0x000, 0x0BD, 0x00A, 0x15A, 0x000, 0x171, 0x000, 0x000, 0x000, 0x000, + 0x023, 0x2BA, 0x000, 0x2B9, 0x02C, 0x2EC, 0x000, 0x173, 0x012, 0x048, 0x000, 0x2EF, + 0x000, 0x000, 0x000, 0x000, 0x041, 0x046, 0x000, 0x043, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x001, 0x15E, 0x000, 0x04F, 0x054, 0x04C, 0x000, 0x045, 0x000, 0x000, 0x000, 0x000, + 0x043, 0x040, 0x000, 0x04B, +}; + +static const uint8_t huff_spec_b23_bits[] = { + 2, 4, 0, 4, 4, 6, 0, 6, 0, 0, 0, 0, 4, 6, 0, 6, + 4, 9, 0, 7, 7, 9, 0, 8, 0, 0, 0, 0, 7, 9, 0, 8, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 4, 7, 0, 9, 7, 8, 0, 9, 0, 0, 0, 0, 7, 8, 0, 9, + 4, 8, 0, 8, 9, 10, 0, 10, 0, 0, 0, 0, 7, 10, 0, 10, + 7, 10, 0, 10, 10, 10, 0, 10, 0, 0, 0, 0, 9, 10, 0, 10, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 7, 10, 0, 10, 10, 10, 0, 10, 0, 0, 0, 0, 8, 10, 0, 10, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 4, 8, 0, 8, 7, 10, 0, 10, 0, 0, 0, 0, 9, 10, 0, 10, + 7, 10, 0, 10, 8, 10, 0, 10, 0, 0, 0, 0, 10, 10, 0, 10, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 7, 10, 0, 10, 9, 10, 0, 10, 0, 0, 0, 0, 10, 10, 0, 10, +}; + +static const uint16_t huff_spec_b23_codes[] = { + 0x003, 0x008, 0x000, 0x009, 0x002, 0x018, 0x000, 0x01B, 0x000, 0x000, 0x000, 0x000, + 0x003, 0x01A, 0x000, 0x019, 0x000, 0x17C, 0x000, 0x055, 0x056, 0x0E8, 0x000, 0x07D, + 0x000, 0x000, 0x000, 0x000, 0x059, 0x0F6, 0x000, 0x07F, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x001, 0x054, 0x000, 0x17D, 0x058, 0x07E, 0x000, 0x0F7, 0x000, 0x000, 0x000, 0x000, + 0x057, 0x07C, 0x000, 0x0E9, 0x004, 0x0A2, 0x000, 0x0A1, 0x17A, 0x1DA, 0x000, 0x1D9, + 0x000, 0x000, 0x000, 0x000, 0x053, 0x1E8, 0x000, 0x2F3, 0x05C, 0x1D6, 0x000, 0x1E7, + 0x1EA, 0x1E2, 0x000, 0x1CF, 0x000, 0x000, 0x000, 0x000, 0x17F, 0x1CA, 0x000, 0x1DD, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x05B, 0x2F0, 0x000, 0x1DF, 0x1E4, 0x1CC, 0x000, 0x1D5, + 0x000, 0x000, 0x000, 0x000, 0x071, 0x1E0, 0x000, 0x1C9, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x005, 0x0A0, 0x000, 0x0A3, 0x052, 0x2F2, 0x000, 0x1E9, 0x000, 0x000, 0x000, 0x000, + 0x17B, 0x1D8, 0x000, 0x1DB, 0x05A, 0x1DE, 0x000, 0x2F1, 0x070, 0x1C8, 0x000, 0x1E1, + 0x000, 0x000, 0x000, 0x000, 0x1E5, 0x1D4, 0x000, 0x1CD, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x05D, 0x1E6, 0x000, 0x1D7, 0x17E, 0x1DC, 0x000, 0x1CB, 0x000, 0x000, 0x000, 0x000, + 0x1EB, 0x1CE, 0x000, 0x1E3, +}; + +static const uint8_t huff_spec_b24_bits[] = { + 1, 4, 0, 4, 5, 7, 0, 7, 0, 0, 0, 0, 5, 7, 0, 7, + 5, 9, 0, 7, 8, 10, 0, 9, 0, 0, 0, 0, 7, 10, 0, 9, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 5, 7, 0, 9, 7, 9, 0, 10, 0, 0, 0, 0, 8, 9, 0, 10, + 5, 9, 0, 8, 9, 10, 0, 10, 0, 0, 0, 0, 7, 10, 0, 10, + 7, 10, 0, 10, 10, 10, 0, 10, 0, 0, 0, 0, 10, 10, 0, 10, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 7, 10, 0, 10, 10, 10, 0, 10, 0, 0, 0, 0, 10, 10, 0, 10, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 5, 8, 0, 9, 7, 10, 0, 10, 0, 0, 0, 0, 9, 10, 0, 10, + 7, 10, 0, 10, 10, 10, 0, 10, 0, 0, 0, 0, 10, 10, 0, 10, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 7, 10, 0, 10, 10, 10, 0, 10, 0, 0, 0, 0, 10, 10, 0, 10, +}; + +static const uint16_t huff_spec_b24_codes[] = { + 0x001, 0x000, 0x000, 0x001, 0x00A, 0x01C, 0x000, 0x033, 0x000, 0x000, 0x000, 0x000, + 0x00B, 0x032, 0x000, 0x01D, 0x008, 0x0D8, 0x000, 0x031, 0x06E, 0x0FA, 0x000, 0x0D7, + 0x000, 0x000, 0x000, 0x000, 0x011, 0x0F4, 0x000, 0x0D5, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x009, 0x030, 0x000, 0x0D9, 0x010, 0x0D4, 0x000, 0x0F5, 0x000, 0x000, 0x000, 0x000, + 0x06F, 0x0D6, 0x000, 0x0FB, 0x00E, 0x0DA, 0x000, 0x025, 0x0D2, 0x0D4, 0x000, 0x0DB, + 0x000, 0x000, 0x000, 0x000, 0x017, 0x0FE, 0x000, 0x0FD, 0x014, 0x0DC, 0x000, 0x0F9, + 0x0F2, 0x0D6, 0x000, 0x09B, 0x000, 0x000, 0x000, 0x000, 0x1A3, 0x09C, 0x000, 0x0D3, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x019, 0x0F6, 0x000, 0x0D9, 0x0F0, 0x09E, 0x000, 0x0D1, + 0x000, 0x000, 0x000, 0x000, 0x1A1, 0x0DE, 0x000, 0x099, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x00F, 0x024, 0x000, 0x0DB, 0x016, 0x0FC, 0x000, 0x0FF, 0x000, 0x000, 0x000, 0x000, + 0x0D3, 0x0DA, 0x000, 0x0D5, 0x018, 0x0D8, 0x000, 0x0F7, 0x1A0, 0x098, 0x000, 0x0DF, + 0x000, 0x000, 0x000, 0x000, 0x0F1, 0x0D0, 0x000, 0x09F, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x015, 0x0F8, 0x000, 0x0DD, 0x1A2, 0x0D2, 0x000, 0x09D, 0x000, 0x000, 0x000, 0x000, + 0x0F3, 0x09A, 0x000, 0x0D7 +}; + +static const uint8_t huff_spec_b32_bits[] = { + 2, 4, 5, 6, 0, 6, 5, 4, 5, 6, 6, 7, 0, 6, 5, 6, + 5, 6, 7, 7, 0, 8, 7, 6, 6, 7, 8, 9, 0, 9, 8, 7, + 0, 0, 0, 0, 0, 0, 0, 0, 6, 7, 8, 9, 0, 9, 8, 7, + 5, 6, 7, 8, 0, 7, 7, 6, 5, 6, 5, 6, 0, 7, 6, 6, +}; + +static const uint16_t huff_spec_b32_codes[] = { + 0x001, 0x002, 0x01E, 0x02A, 0x000, 0x02B, 0x01F, 0x003, 0x016, 0x020, 0x03A, 0x064, + 0x000, 0x005, 0x001, 0x023, 0x01A, 0x026, 0x070, 0x00C, 0x000, 0x0CF, 0x073, 0x031, + 0x024, 0x00E, 0x0CC, 0x146, 0x000, 0x145, 0x0A1, 0x053, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x025, 0x052, 0x0A0, 0x144, 0x000, 0x147, 0x0CD, 0x00F, + 0x01B, 0x030, 0x072, 0x0CE, 0x000, 0x00D, 0x071, 0x027, 0x017, 0x022, 0x000, 0x004, + 0x000, 0x065, 0x03B, 0x021, +}; + +static const uint8_t huff_spec_b33_bits[] = { + 2, 4, 5, 7, 0, 7, 5, 4, 4, 5, 6, 8, 0, 7, 6, 5, + 5, 6, 7, 9, 0, 8, 7, 6, 7, 8, 9, 10, 0, 10, 9, 8, + 0, 0, 0, 0, 0, 0, 0, 0, 7, 8, 9, 10, 0, 10, 9, 8, + 5, 6, 7, 8, 0, 9, 7, 6, 4, 5, 6, 7, 0, 8, 6, 5, +}; + +static const uint16_t huff_spec_b33_codes[] = { + 0x003, 0x008, 0x014, 0x05E, 0x000, 0x05F, 0x015, 0x009, 0x004, 0x002, 0x01C, 0x0BA, + 0x000, 0x011, 0x01F, 0x001, 0x00C, 0x00C, 0x014, 0x166, 0x000, 0x02D, 0x013, 0x00F, + 0x05A, 0x0B0, 0x05E, 0x0B8, 0x000, 0x0BB, 0x165, 0x0B9, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x05B, 0x0B8, 0x164, 0x0BA, 0x000, 0x0B9, 0x05F, 0x0B1, + 0x00D, 0x00E, 0x012, 0x02C, 0x000, 0x167, 0x015, 0x00D, 0x005, 0x000, 0x01E, 0x010, + 0x000, 0x0BB, 0x01D, 0x003 +}; + +static const uint8_t huff_spec_b34_bits[] = { + 1, 4, 6, 8, 0, 8, 6, 4, 4, 6, 7, 9, 0, 8, 7, 6, + 6, 7, 8, 10, 0, 10, 8, 7, 8, 9, 10, 10, 0, 10, 10, 9, + 0, 0, 0, 0, 0, 0, 0, 0, 8, 9, 10, 10, 0, 10, 10, 9, + 6, 7, 8, 10, 0, 10, 8, 7, 4, 6, 7, 8, 0, 9, 7, 6, +}; + +static const uint16_t huff_spec_b34_codes[] = { + 0x000, 0x00A, 0x038, 0x0EE, 0x000, 0x0EF, 0x039, 0x00B, 0x008, 0x03C, 0x06E, 0x1D8, + 0x000, 0x0C1, 0x075, 0x03F, 0x032, 0x068, 0x0C4, 0x358, 0x000, 0x30F, 0x0C7, 0x06D, + 0x0D4, 0x1AE, 0x30C, 0x308, 0x000, 0x30B, 0x35B, 0x1DB, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x0D5, 0x1DA, 0x35A, 0x30A, 0x000, 0x309, 0x30D, 0x1AF, + 0x033, 0x06C, 0x0C6, 0x30E, 0x000, 0x359, 0x0C5, 0x069, 0x009, 0x03E, 0x074, 0x0C0, + 0x000, 0x1D9, 0x06F, 0x03D, +}; + +static const uint8_t huff_spec_b42_bits[] = { + 4, 5, 6, 8, 6, 7, 8, 8, 0, 8, 8, 7, 6, 8, 6, 5, + 5, 6, 7, 8, 7, 7, 8, 9, 0, 8, 8, 7, 7, 8, 7, 6, + 7, 7, 8, 9, 7, 8, 9, 9, 0, 9, 9, 8, 7, 9, 8, 7, + 8, 9, 9, 10, 8, 8, 9, 10, 0, 10, 9, 8, 8, 10, 9, 8, + 6, 7, 8, 8, 9, 9, 10, 10, 0, 10, 10, 9, 9, 8, 8, 7, + 7, 7, 8, 9, 9, 10, 10, 10, 0, 10, 10, 10, 9, 9, 8, 7, + 8, 8, 9, 9, 10, 10, 10, 10, 0, 10, 10, 10, 10, 9, 9, 8, + 8, 9, 9, 10, 10, 10, 10, 10, 0, 10, 10, 10, 10, 10, 9, 9, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 8, 9, 9, 10, 10, 10, 10, 10, 0, 10, 10, 10, 10, 10, 9, 9, + 8, 8, 9, 9, 10, 10, 10, 10, 0, 10, 10, 10, 10, 9, 9, 8, + 7, 7, 8, 9, 9, 10, 10, 10, 0, 10, 10, 10, 9, 9, 8, 7, + 6, 7, 8, 8, 9, 9, 10, 10, 0, 10, 10, 9, 9, 8, 8, 7, + 8, 8, 9, 10, 8, 8, 9, 10, 0, 10, 9, 8, 8, 10, 9, 9, + 7, 7, 8, 9, 7, 8, 9, 9, 0, 9, 9, 8, 7, 9, 8, 7, + 5, 6, 7, 8, 7, 7, 8, 8, 0, 9, 8, 7, 7, 8, 7, 6, +}; + +static const uint16_t huff_spec_b42_codes[] = { + 0x00E, 0x018, 0x010, 0x0F0, 0x024, 0x05A, 0x0F6, 0x078, 0x000, 0x079, 0x0F7, 0x05B, + 0x025, 0x0F1, 0x011, 0x019, 0x00C, 0x014, 0x01C, 0x036, 0x05C, 0x012, 0x09E, 0x1E4, + 0x000, 0x00B, 0x0A9, 0x03B, 0x05F, 0x071, 0x019, 0x017, 0x06E, 0x000, 0x03E, 0x114, + 0x002, 0x0B0, 0x1AA, 0x07A, 0x000, 0x099, 0x1E7, 0x0B3, 0x00B, 0x131, 0x07F, 0x00D, + 0x0D8, 0x1FE, 0x112, 0x22E, 0x086, 0x010, 0x134, 0x35C, 0x000, 0x35F, 0x133, 0x013, + 0x081, 0x22D, 0x119, 0x07B, 0x00A, 0x050, 0x0F8, 0x04E, 0x1B4, 0x154, 0x3EC, 0x0D2, + 0x000, 0x0D7, 0x3D7, 0x137, 0x1FD, 0x073, 0x0FD, 0x057, 0x052, 0x010, 0x08E, 0x1E8, + 0x11A, 0x3EE, 0x0F2, 0x03C, 0x000, 0x03F, 0x0F1, 0x3D5, 0x111, 0x1F5, 0x09D, 0x025, + 0x0D2, 0x082, 0x1A0, 0x0F8, 0x36E, 0x0D4, 0x072, 0x03A, 0x000, 0x027, 0x071, 0x07D, + 0x36D, 0x0FB, 0x1AD, 0x085, 0x00C, 0x1A8, 0x03C, 0x346, 0x0D0, 0x076, 0x024, 0x020, + 0x000, 0x023, 0x039, 0x075, 0x07F, 0x345, 0x09B, 0x157, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x00D, 0x156, 0x09A, 0x344, 0x07E, 0x074, 0x038, 0x022, 0x000, 0x021, 0x025, 0x077, + 0x0D1, 0x347, 0x03D, 0x1A9, 0x0D3, 0x084, 0x1AC, 0x0FA, 0x36C, 0x07C, 0x070, 0x026, + 0x000, 0x03B, 0x073, 0x0D5, 0x36F, 0x0F9, 0x1A1, 0x083, 0x053, 0x024, 0x09C, 0x1F4, + 0x110, 0x3D4, 0x0F0, 0x03E, 0x000, 0x03D, 0x0F3, 0x3EF, 0x11B, 0x1E9, 0x08F, 0x011, + 0x00B, 0x056, 0x0FC, 0x072, 0x1FC, 0x136, 0x3D6, 0x0D6, 0x000, 0x0D3, 0x3ED, 0x155, + 0x1B5, 0x04F, 0x0F9, 0x051, 0x0D9, 0x07A, 0x118, 0x22C, 0x080, 0x012, 0x132, 0x35E, + 0x000, 0x35D, 0x135, 0x011, 0x087, 0x22F, 0x113, 0x1FF, 0x06F, 0x00C, 0x07E, 0x130, + 0x00A, 0x0B2, 0x1E6, 0x098, 0x000, 0x07B, 0x1AB, 0x0B1, 0x003, 0x115, 0x03F, 0x001, + 0x00D, 0x016, 0x018, 0x070, 0x05E, 0x03A, 0x0A8, 0x00A, 0x000, 0x1E5, 0x09F, 0x013, + 0x05D, 0x037, 0x01D, 0x015, +}; + +static const uint8_t huff_spec_b43_bits[] = { + 2, 5, 6, 7, 7, 8, 8, 9, 0, 9, 8, 8, 7, 7, 6, 5, + 5, 6, 7, 8, 7, 8, 9, 10, 0, 10, 9, 8, 7, 8, 7, 6, + 6, 7, 8, 9, 8, 9, 10, 10, 0, 10, 10, 9, 8, 9, 8, 7, + 7, 8, 9, 10, 9, 9, 10, 10, 0, 10, 10, 10, 9, 10, 9, 8, + 7, 8, 8, 9, 10, 10, 10, 10, 0, 10, 10, 10, 10, 9, 8, 7, + 8, 8, 9, 10, 10, 10, 10, 10, 0, 10, 10, 10, 10, 10, 9, 8, + 9, 9, 10, 10, 10, 10, 10, 10, 0, 10, 10, 10, 10, 10, 10, 9, + 10, 10, 10, 10, 10, 10, 10, 10, 0, 10, 10, 10, 10, 10, 10, 10, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 10, 10, 10, 10, 10, 10, 10, 10, 0, 10, 10, 10, 10, 10, 10, 10, + 9, 9, 10, 10, 10, 10, 10, 10, 0, 10, 10, 10, 10, 10, 10, 9, + 8, 8, 9, 10, 10, 10, 10, 10, 0, 10, 10, 10, 10, 10, 9, 8, + 7, 7, 8, 9, 10, 10, 10, 10, 0, 10, 10, 10, 10, 9, 8, 8, + 7, 8, 9, 10, 9, 10, 10, 10, 0, 10, 10, 9, 9, 10, 9, 8, + 6, 7, 8, 9, 8, 9, 10, 10, 0, 10, 10, 9, 8, 9, 8, 7, + 5, 6, 7, 8, 7, 8, 9, 10, 0, 10, 9, 8, 7, 8, 7, 6, +}; + +static const uint16_t huff_spec_b43_codes[] = { + 0x001, 0x01E, 0x022, 0x018, 0x064, 0x0EC, 0x008, 0x100, 0x000, 0x101, 0x009, 0x0ED, + 0x065, 0x019, 0x023, 0x01F, 0x01A, 0x030, 0x056, 0x09A, 0x00A, 0x090, 0x12C, 0x0A6, + 0x000, 0x0A9, 0x12F, 0x093, 0x00F, 0x09F, 0x059, 0x039, 0x00E, 0x054, 0x0BC, 0x19E, + 0x082, 0x176, 0x0AC, 0x088, 0x000, 0x08B, 0x0AF, 0x19D, 0x095, 0x1D1, 0x0BF, 0x051, + 0x002, 0x098, 0x1D4, 0x0B8, 0x170, 0x046, 0x090, 0x060, 0x000, 0x067, 0x095, 0x0BD, + 0x173, 0x0B5, 0x1D3, 0x09D, 0x052, 0x0EE, 0x034, 0x174, 0x0BA, 0x09C, 0x080, 0x044, + 0x000, 0x047, 0x06D, 0x099, 0x0BF, 0x16F, 0x085, 0x001, 0x0CC, 0x036, 0x16C, 0x0B0, + 0x09A, 0x084, 0x04E, 0x03E, 0x000, 0x037, 0x04B, 0x06B, 0x0A1, 0x0B3, 0x16B, 0x087, + 0x1D6, 0x102, 0x0A4, 0x092, 0x068, 0x04C, 0x034, 0x030, 0x000, 0x02D, 0x03D, 0x049, + 0x083, 0x097, 0x0AB, 0x169, 0x0B6, 0x09E, 0x06E, 0x064, 0x040, 0x038, 0x02E, 0x02A, + 0x000, 0x029, 0x033, 0x03B, 0x043, 0x063, 0x087, 0x0A3, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x0B7, 0x0A2, 0x086, 0x062, 0x042, 0x03A, 0x032, 0x028, 0x000, 0x02B, 0x02F, 0x039, + 0x041, 0x065, 0x06F, 0x09F, 0x1D7, 0x168, 0x0AA, 0x096, 0x082, 0x048, 0x03C, 0x02C, + 0x000, 0x031, 0x035, 0x04D, 0x069, 0x093, 0x0A5, 0x103, 0x0CD, 0x086, 0x16A, 0x0B2, + 0x0A0, 0x06A, 0x04A, 0x036, 0x000, 0x03F, 0x04F, 0x085, 0x09B, 0x0B1, 0x16D, 0x037, + 0x053, 0x000, 0x084, 0x16E, 0x0BE, 0x098, 0x06C, 0x046, 0x000, 0x045, 0x081, 0x09D, + 0x0BB, 0x175, 0x035, 0x0EF, 0x003, 0x09C, 0x1D2, 0x0B4, 0x172, 0x0BC, 0x094, 0x066, + 0x000, 0x061, 0x091, 0x047, 0x171, 0x0B9, 0x1D5, 0x099, 0x00F, 0x050, 0x0BE, 0x1D0, + 0x094, 0x19C, 0x0AE, 0x08A, 0x000, 0x089, 0x0AD, 0x177, 0x083, 0x19F, 0x0BD, 0x055, + 0x01B, 0x038, 0x058, 0x09E, 0x00E, 0x092, 0x12E, 0x0A8, 0x000, 0x0A7, 0x12D, 0x091, + 0x00B, 0x09B, 0x057, 0x031, +}; + +static const uint8_t huff_spec_b44_bits[] = { + 2, 4, 6, 7, 7, 8, 10, 10, 0, 10, 10, 8, 7, 7, 6, 4, + 5, 5, 7, 8, 8, 10, 10, 10, 0, 10, 10, 10, 8, 8, 7, 5, + 6, 7, 8, 9, 9, 10, 10, 10, 0, 10, 10, 10, 10, 9, 8, 7, + 8, 8, 9, 10, 10, 10, 10, 10, 0, 10, 10, 10, 10, 10, 10, 8, + 8, 8, 10, 10, 10, 10, 10, 10, 0, 10, 10, 10, 10, 10, 10, 8, + 9, 10, 10, 10, 10, 10, 10, 10, 0, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 0, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 0, 10, 10, 10, 10, 10, 10, 10, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 10, 10, 10, 10, 10, 10, 10, 10, 0, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 0, 10, 10, 10, 10, 10, 10, 10, + 9, 10, 10, 10, 10, 10, 10, 10, 0, 10, 10, 10, 10, 10, 10, 10, + 8, 8, 10, 10, 10, 10, 10, 10, 0, 10, 10, 10, 10, 10, 10, 8, + 8, 8, 10, 10, 10, 10, 10, 10, 0, 10, 10, 10, 10, 10, 9, 8, + 6, 7, 8, 9, 10, 10, 10, 10, 0, 10, 10, 10, 9, 9, 8, 7, + 5, 5, 7, 8, 8, 10, 10, 10, 0, 10, 10, 10, 8, 8, 7, 5, +}; + +static const uint16_t huff_spec_b44_codes[] = { + 0x002, 0x002, 0x030, 0x000, 0x002, 0x00C, 0x1D2, 0x1AE, 0x000, 0x1AF, 0x1D3, 0x00D, + 0x003, 0x001, 0x031, 0x003, 0x01E, 0x002, 0x070, 0x0C8, 0x07E, 0x1E8, 0x1C0, 0x176, + 0x000, 0x17F, 0x1C3, 0x1EB, 0x0CF, 0x0D3, 0x073, 0x009, 0x018, 0x06A, 0x0EC, 0x1DE, + 0x1A2, 0x1CA, 0x1AA, 0x164, 0x000, 0x16D, 0x1AD, 0x1D1, 0x1EF, 0x1DD, 0x0EB, 0x06D, + 0x0E8, 0x0CA, 0x1BE, 0x1CE, 0x1DA, 0x1B6, 0x170, 0x154, 0x000, 0x153, 0x173, 0x1B1, + 0x1D7, 0x1D5, 0x343, 0x0CD, 0x0DC, 0x078, 0x340, 0x1CC, 0x1BA, 0x1A8, 0x156, 0x148, + 0x000, 0x145, 0x15F, 0x1A1, 0x1BD, 0x1D9, 0x1ED, 0x07D, 0x1BC, 0x1DC, 0x1C4, 0x1B2, + 0x17C, 0x15A, 0x14A, 0x03A, 0x000, 0x039, 0x147, 0x16B, 0x17B, 0x1B5, 0x1C9, 0x1DF, + 0x1C6, 0x1B8, 0x1A2, 0x168, 0x160, 0x14C, 0x02E, 0x024, 0x000, 0x027, 0x03D, 0x151, + 0x15D, 0x16F, 0x1A7, 0x1BF, 0x1A4, 0x174, 0x162, 0x14E, 0x140, 0x02C, 0x02A, 0x022, + 0x000, 0x021, 0x029, 0x03F, 0x143, 0x159, 0x167, 0x179, 0x000, 0x000, 0x000, 0x000, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, + 0x1A5, 0x178, 0x166, 0x158, 0x142, 0x03E, 0x028, 0x020, 0x000, 0x023, 0x02B, 0x02D, + 0x141, 0x14F, 0x163, 0x175, 0x1C7, 0x1BE, 0x1A6, 0x16E, 0x15C, 0x150, 0x03C, 0x026, + 0x000, 0x025, 0x02F, 0x14D, 0x161, 0x169, 0x1A3, 0x1B9, 0x1BD, 0x1DE, 0x1C8, 0x1B4, + 0x17A, 0x16A, 0x146, 0x038, 0x000, 0x03B, 0x14B, 0x15B, 0x17D, 0x1B3, 0x1C5, 0x1DD, + 0x0DD, 0x07C, 0x1EC, 0x1D8, 0x1BC, 0x1A0, 0x15E, 0x144, 0x000, 0x149, 0x157, 0x1A9, + 0x1BB, 0x1CD, 0x341, 0x079, 0x0E9, 0x0CC, 0x342, 0x1D4, 0x1D6, 0x1B0, 0x172, 0x152, + 0x000, 0x155, 0x171, 0x1B7, 0x1DB, 0x1CF, 0x1BF, 0x0CB, 0x019, 0x06C, 0x0EA, 0x1DC, + 0x1EE, 0x1D0, 0x1AC, 0x16C, 0x000, 0x165, 0x1AB, 0x1CB, 0x1A3, 0x1DF, 0x0ED, 0x06B, + 0x01F, 0x008, 0x072, 0x0D2, 0x0CE, 0x1EA, 0x1C2, 0x17E, 0x000, 0x177, 0x1C1, 0x1E9, + 0x07F, 0x0C9, 0x071, 0x003, +}; + +static const uint8_t huff_spec_b52_bits[] = { + 3, 4, 4, 4, 5, 5, 6, 6, 5, 5, 5, 6, 6, 6, 7, 7, + 0, 7, 7, 6, 6, 6, 5, 5, 5, 6, 6, 5, 5, 4, 4, 4, +}; + +static const uint16_t huff_spec_b52_codes[] = { + 0x06, 0x0E, 0x06, 0x00, 0x0A, 0x04, 0x2C, 0x12, 0x14, 0x10, 0x06, 0x2E, 0x24, 0x10, 0x4E, 0x4C, + 0x00, 0x4D, 0x4F, 0x11, 0x25, 0x2F, 0x07, 0x11, 0x15, 0x13, 0x2D, 0x05, 0x0B, 0x01, 0x07, 0x0F, +}; + +static const uint8_t huff_spec_b53_bits[] = { + 2, 3, 4, 5, 5, 6, 6, 6, 6, 6, 6, 7, 7, 7, 8, 8, + 0, 8, 8, 7, 7, 7, 6, 6, 6, 6, 6, 6, 5, 5, 4, 3, +}; + +static const uint16_t huff_spec_b53_codes[] = { + 0x02, 0x00, 0x06, 0x1C, 0x18, 0x3E, 0x16, 0x10, 0x3C, 0x36, 0x14, 0x6A, 0x26, 0x24, 0xD2, 0xD0, + 0x00, 0xD1, 0xD3, 0x25, 0x27, 0x6B, 0x15, 0x37, 0x3D, 0x11, 0x17, 0x3F, 0x19, 0x1D, 0x07, 0x01, +}; + +static const uint8_t huff_spec_b54_bits[] = { + 2, 3, 4, 4, 5, 6, 6, 7, 6, 6, 7, 8, 8, 8, 9, 9, + 0, 9, 9, 8, 8, 8, 7, 6, 6, 7, 6, 6, 5, 4, 4, 3, +}; + +static const uint16_t huff_spec_b54_codes[] = { + 0x003, 0x002, 0x008, 0x000, 0x014, 0x02E, 0x00E, 0x05A, 0x00A, 0x008, 0x01A, 0x0B2, + 0x032, 0x030, 0x162, 0x160, 0x000, 0x161, 0x163, 0x031, 0x033, 0x0B3, 0x01B, 0x009, + 0x00B, 0x05B, 0x00F, 0x02F, 0x015, 0x001, 0x009, 0x003, +}; + +static const uint8_t huff_spec_b62_bits[] = { + 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, + 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, + 0, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, + 6, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 4, +}; + +static const uint16_t huff_spec_b62_codes[] = { + 0x0D, 0x06, 0x1C, 0x14, 0x0A, 0x04, 0x3E, 0x2E, 0x22, 0x0E, 0x06, 0x00, 0x5A, 0x4E, 0x40, 0x20, + 0x30, 0x32, 0x24, 0x12, 0x0C, 0x02, 0x78, 0x58, 0x42, 0x22, 0x0A, 0x08, 0xF6, 0xF4, 0x9A, 0x98, + 0x00, 0x99, 0x9B, 0xF5, 0xF7, 0x09, 0x0B, 0x23, 0x43, 0x59, 0x79, 0x03, 0x0D, 0x13, 0x25, 0x33, + 0x31, 0x21, 0x41, 0x4F, 0x5B, 0x01, 0x07, 0x0F, 0x23, 0x2F, 0x3F, 0x05, 0x0B, 0x15, 0x1D, 0x07, +}; + +static const uint8_t huff_spec_b63_bits[] = { + 3, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, + 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, + 0, 9, 9, 9, 9, 9, 9, 8, 8, 8, 8, 7, 7, 7, 7, 6, + 6, 8, 7, 7, 7, 7, 6, 6, 6, 6, 5, 5, 5, 5, 4, 4, +}; + +static const uint16_t huff_spec_b63_codes[] = { + 0x006, 0x00E, 0x004, 0x014, 0x010, 0x006, 0x000, 0x026, 0x01C, 0x018, 0x004, 0x05C, + 0x04A, 0x03C, 0x016, 0x0BC, 0x006, 0x008, 0x058, 0x03E, 0x036, 0x014, 0x0B6, 0x0B4, + 0x090, 0x068, 0x17E, 0x17C, 0x126, 0x124, 0x0D6, 0x0D4, 0x000, 0x0D5, 0x0D7, 0x125, + 0x127, 0x17D, 0x17F, 0x069, 0x091, 0x0B5, 0x0B7, 0x015, 0x037, 0x03F, 0x059, 0x009, + 0x007, 0x0BD, 0x017, 0x03D, 0x04B, 0x05D, 0x005, 0x019, 0x01D, 0x027, 0x001, 0x007, + 0x011, 0x015, 0x005, 0x00F, +}; + +static const uint8_t huff_spec_b64_bits[] = { + 3, 3, 4, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 7, 8, + 7, 7, 7, 8, 8, 8, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, + 0, 10, 10, 10, 10, 9, 9, 9, 9, 9, 9, 8, 8, 8, 7, 7, + 7, 8, 7, 7, 7, 7, 7, 6, 6, 6, 6, 5, 5, 5, 4, 3, +}; + +static const uint16_t huff_spec_b64_codes[] = { + 0x007, 0x000, 0x008, 0x01A, 0x014, 0x00C, 0x032, 0x02E, 0x01E, 0x014, 0x062, 0x05A, + 0x03A, 0x026, 0x020, 0x0B2, 0x038, 0x02C, 0x022, 0x0C0, 0x05E, 0x04A, 0x186, 0x184, + 0x160, 0x0BA, 0x092, 0x090, 0x2C6, 0x2C4, 0x172, 0x170, 0x000, 0x171, 0x173, 0x2C5, + 0x2C7, 0x091, 0x093, 0x0BB, 0x161, 0x185, 0x187, 0x04B, 0x05F, 0x0C1, 0x023, 0x02D, + 0x039, 0x0B3, 0x021, 0x027, 0x03B, 0x05B, 0x063, 0x015, 0x01F, 0x02F, 0x033, 0x00D, + 0x015, 0x01B, 0x009, 0x001, +}; + +static const uint8_t huff_spec_b72_bits[] = { + 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, +}; + +static const uint16_t huff_spec_b72_codes[] = { + 0x01E, 0x016, 0x00C, 0x000, 0x038, 0x032, 0x028, 0x022, 0x01C, 0x012, 0x00E, 0x006, + 0x076, 0x06C, 0x060, 0x04E, 0x03E, 0x02A, 0x022, 0x01A, 0x012, 0x00A, 0x0FC, 0x0DC, + 0x0C6, 0x0A8, 0x094, 0x086, 0x058, 0x042, 0x040, 0x02A, 0x068, 0x07C, 0x06A, 0x056, + 0x048, 0x040, 0x02E, 0x028, 0x016, 0x010, 0x008, 0x0EA, 0x0DE, 0x0AA, 0x09A, 0x096, + 0x07A, 0x078, 0x05A, 0x032, 0x030, 0x028, 0x1FE, 0x1FC, 0x1D2, 0x1D0, 0x18A, 0x188, + 0x132, 0x130, 0x10A, 0x108, 0x000, 0x109, 0x10B, 0x131, 0x133, 0x189, 0x18B, 0x1D1, + 0x1D3, 0x1FD, 0x1FF, 0x029, 0x031, 0x033, 0x05B, 0x079, 0x07B, 0x097, 0x09B, 0x0AB, + 0x0DF, 0x0EB, 0x009, 0x011, 0x017, 0x029, 0x02F, 0x041, 0x049, 0x057, 0x06B, 0x07D, + 0x069, 0x02B, 0x041, 0x043, 0x059, 0x087, 0x095, 0x0A9, 0x0C7, 0x0DD, 0x0FD, 0x00B, + 0x013, 0x01B, 0x023, 0x02B, 0x03F, 0x04F, 0x061, 0x06D, 0x077, 0x007, 0x00F, 0x013, + 0x01D, 0x023, 0x029, 0x033, 0x039, 0x001, 0x00D, 0x017, +}; + +static const uint8_t huff_spec_b73_bits[] = { + 3, 4, 5, 5, 5, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, + 8, 7, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 0, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 8, 8, 8, 8, 8, 8, 8, 8, 7, + 8, 9, 9, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 5, 5, 5, 4, +}; + +static const uint16_t huff_spec_b73_codes[] = { + 0x000, 0x006, 0x018, 0x010, 0x004, 0x03A, 0x034, 0x02A, 0x026, 0x014, 0x010, 0x07E, + 0x072, 0x06E, 0x05C, 0x052, 0x04A, 0x02C, 0x024, 0x018, 0x0F4, 0x0E0, 0x0DA, 0x0B6, + 0x0B2, 0x0A0, 0x05E, 0x04E, 0x038, 0x034, 0x1E6, 0x1B2, 0x0FA, 0x01E, 0x0F8, 0x0F0, + 0x0BE, 0x0B4, 0x0A2, 0x090, 0x04C, 0x03A, 0x1EE, 0x1E4, 0x1C6, 0x1B0, 0x178, 0x162, + 0x126, 0x124, 0x0B8, 0x06C, 0x3DA, 0x3D8, 0x38A, 0x388, 0x2F6, 0x2F4, 0x2C2, 0x2C0, + 0x176, 0x174, 0x0DC, 0x0DE, 0x000, 0x0DF, 0x0DD, 0x175, 0x177, 0x2C1, 0x2C3, 0x2F5, + 0x2F7, 0x389, 0x38B, 0x3D9, 0x3DB, 0x06D, 0x0B9, 0x125, 0x127, 0x163, 0x179, 0x1B1, + 0x1C7, 0x1E5, 0x1EF, 0x03B, 0x04D, 0x091, 0x0A3, 0x0B5, 0x0BF, 0x0F1, 0x0F9, 0x01F, + 0x0FB, 0x1B3, 0x1E7, 0x035, 0x039, 0x04F, 0x05F, 0x0A1, 0x0B3, 0x0B7, 0x0DB, 0x0E1, + 0x0F5, 0x019, 0x025, 0x02D, 0x04B, 0x053, 0x05D, 0x06F, 0x073, 0x07F, 0x011, 0x015, + 0x027, 0x02B, 0x035, 0x03B, 0x005, 0x011, 0x019, 0x007, +}; + +static const uint8_t huff_spec_b74_bits[] = { + 3, 4, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, + 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, + 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 0, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 9, 9, 9, 9, 9, 9, 9, 8, 8, 8, 8, + 8, 9, 9, 9, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, + 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 4, +}; + +static const uint16_t huff_spec_b74_codes[] = { + 0x001, 0x008, 0x01E, 0x018, 0x00C, 0x002, 0x03A, 0x034, 0x02C, 0x01E, 0x016, 0x012, + 0x072, 0x06E, 0x05E, 0x056, 0x050, 0x038, 0x022, 0x004, 0x0E2, 0x0DA, 0x0BA, 0x0A8, + 0x076, 0x054, 0x050, 0x002, 0x000, 0x1C0, 0x1B0, 0x156, 0x0A4, 0x0A6, 0x074, 0x052, + 0x004, 0x1C2, 0x1B2, 0x170, 0x154, 0x0AE, 0x0AC, 0x086, 0x2E6, 0x2E4, 0x10A, 0x108, + 0x106, 0x104, 0x102, 0x100, 0x03E, 0x03A, 0x03C, 0x038, 0x036, 0x034, 0x032, 0x030, + 0x01E, 0x01A, 0x01C, 0x018, 0x000, 0x019, 0x01D, 0x01B, 0x01F, 0x031, 0x033, 0x035, + 0x037, 0x039, 0x03D, 0x03B, 0x03F, 0x101, 0x103, 0x105, 0x107, 0x109, 0x10B, 0x2E5, + 0x2E7, 0x087, 0x0AD, 0x0AF, 0x155, 0x171, 0x1B3, 0x1C3, 0x005, 0x053, 0x075, 0x0A7, + 0x0A5, 0x157, 0x1B1, 0x1C1, 0x001, 0x003, 0x051, 0x055, 0x077, 0x0A9, 0x0BB, 0x0DB, + 0x0E3, 0x005, 0x023, 0x039, 0x051, 0x057, 0x05F, 0x06F, 0x073, 0x013, 0x017, 0x01F, + 0x02D, 0x035, 0x03B, 0x003, 0x00D, 0x019, 0x01F, 0x009, +}; + +static const HuffmanCodebook at9_huffman_coeffs[][8][4] = { + { + { { 0 } }, + { { 0 } }, + { + { huff_spec_a21_bits, huff_spec_a21_codes, 16, 2, 1, 2, 3, }, + { huff_spec_a22_bits, huff_spec_a22_codes, 256, 4, 2, 2, 8, }, + { huff_spec_a23_bits, huff_spec_a23_codes, 256, 4, 2, 2, 9, }, + { huff_spec_a24_bits, huff_spec_a24_codes, 256, 4, 2, 2, 10, }, + }, + { + { huff_spec_a31_bits, huff_spec_a31_codes, 64, 2, 1, 3, 7, }, + { huff_spec_a32_bits, huff_spec_a32_codes, 64, 2, 1, 3, 7, }, + { huff_spec_a33_bits, huff_spec_a33_codes, 64, 2, 1, 3, 8, }, + { huff_spec_a34_bits, huff_spec_a34_codes, 64, 2, 1, 3, 10, }, + }, + { + { huff_spec_a41_bits, huff_spec_a41_codes, 256, 2, 1, 4, 9, }, + { huff_spec_a42_bits, huff_spec_a42_codes, 256, 2, 1, 4, 10, }, + { huff_spec_a43_bits, huff_spec_a43_codes, 256, 2, 1, 4, 10, }, + { huff_spec_a44_bits, huff_spec_a44_codes, 256, 2, 1, 4, 10, }, + }, + { + { huff_spec_a51_bits, huff_spec_a51_codes, 32, 1, 0, 5, 6, }, + { huff_spec_a52_bits, huff_spec_a52_codes, 32, 1, 0, 5, 6, }, + { huff_spec_a53_bits, huff_spec_a53_codes, 32, 1, 0, 5, 7, }, + { huff_spec_a54_bits, huff_spec_a54_codes, 32, 1, 0, 5, 8, }, + }, + { + { huff_spec_a61_bits, huff_spec_a61_codes, 64, 1, 0, 6, 7, }, + { huff_spec_a62_bits, huff_spec_a62_codes, 64, 1, 0, 6, 7, }, + { huff_spec_a63_bits, huff_spec_a63_codes, 64, 1, 0, 6, 8, }, + { huff_spec_a64_bits, huff_spec_a64_codes, 64, 1, 0, 6, 9, }, + }, + { + { huff_spec_a71_bits, huff_spec_a71_codes, 128, 1, 0, 7, 8, }, + { huff_spec_a72_bits, huff_spec_a72_codes, 128, 1, 0, 7, 8, }, + { huff_spec_a73_bits, huff_spec_a73_codes, 128, 1, 0, 7, 9, }, + { huff_spec_a74_bits, huff_spec_a74_codes, 128, 1, 0, 7, 10, }, + }, + }, + { + { { 0 } }, + { { 0 } }, + { + { 0 }, + { huff_spec_b22_bits, huff_spec_b22_codes, 256, 4, 2, 2, 10, }, + { huff_spec_b23_bits, huff_spec_b23_codes, 256, 4, 2, 2, 10, }, + { huff_spec_b24_bits, huff_spec_b24_codes, 256, 4, 2, 2, 10, }, + }, + { + { 0 }, + { huff_spec_b32_bits, huff_spec_b32_codes, 64, 2, 1, 3, 9, }, + { huff_spec_b33_bits, huff_spec_b33_codes, 64, 2, 1, 3, 10, }, + { huff_spec_b34_bits, huff_spec_b34_codes, 64, 2, 1, 3, 10, }, + }, + { + { 0 }, + { huff_spec_b42_bits, huff_spec_b42_codes, 256, 2, 1, 4, 10, }, + { huff_spec_b43_bits, huff_spec_b43_codes, 256, 2, 1, 4, 10, }, + { huff_spec_b44_bits, huff_spec_b44_codes, 256, 2, 1, 4, 10, }, + }, + { + { 0 }, + { huff_spec_b52_bits, huff_spec_b52_codes, 32, 1, 0, 5, 7, }, + { huff_spec_b53_bits, huff_spec_b53_codes, 32, 1, 0, 5, 8, }, + { huff_spec_b54_bits, huff_spec_b54_codes, 32, 1, 0, 5, 9, }, + }, + { + { 0 }, + { huff_spec_b62_bits, huff_spec_b62_codes, 64, 1, 0, 6, 8, }, + { huff_spec_b63_bits, huff_spec_b63_codes, 64, 1, 0, 6, 9, }, + { huff_spec_b64_bits, huff_spec_b64_codes, 64, 1, 0, 6, 10, }, + }, + { + { 0 }, + { huff_spec_b72_bits, huff_spec_b72_codes, 128, 1, 0, 7, 9, }, + { huff_spec_b73_bits, huff_spec_b73_codes, 128, 1, 0, 7, 10, }, + { huff_spec_b74_bits, huff_spec_b74_codes, 128, 1, 0, 7, 10, }, + }, + }, +}; + +#endif /* AVCODEC_ATRAC9TAB_H */ diff --git a/libavcodec/av1.h b/libavcodec/av1.h new file mode 100644 index 000000000..6c0e32485 --- /dev/null +++ b/libavcodec/av1.h @@ -0,0 +1,163 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * AV1 common definitions + */ + +#ifndef AVCODEC_AV1_H +#define AVCODEC_AV1_H + +// OBU types (section 6.2.2). +typedef enum { + // 0 reserved. + AV1_OBU_SEQUENCE_HEADER = 1, + AV1_OBU_TEMPORAL_DELIMITER = 2, + AV1_OBU_FRAME_HEADER = 3, + AV1_OBU_TILE_GROUP = 4, + AV1_OBU_METADATA = 5, + AV1_OBU_FRAME = 6, + AV1_OBU_REDUNDANT_FRAME_HEADER = 7, + AV1_OBU_TILE_LIST = 8, + // 9-14 reserved. + AV1_OBU_PADDING = 15, +} AV1_OBU_Type; + +// Metadata types (section 6.7.1). +enum { + AV1_METADATA_TYPE_HDR_CLL = 1, + AV1_METADATA_TYPE_HDR_MDCV = 2, + AV1_METADATA_TYPE_SCALABILITY = 3, + AV1_METADATA_TYPE_ITUT_T35 = 4, + AV1_METADATA_TYPE_TIMECODE = 5, +}; + +// Frame types (section 6.8.2). +enum { + AV1_FRAME_KEY = 0, + AV1_FRAME_INTER = 1, + AV1_FRAME_INTRA_ONLY = 2, + AV1_FRAME_SWITCH = 3, +}; + +// Reference frames (section 6.10.24). +enum { + AV1_REF_FRAME_INTRA = 0, + AV1_REF_FRAME_LAST = 1, + AV1_REF_FRAME_LAST2 = 2, + AV1_REF_FRAME_LAST3 = 3, + AV1_REF_FRAME_GOLDEN = 4, + AV1_REF_FRAME_BWDREF = 5, + AV1_REF_FRAME_ALTREF2 = 6, + AV1_REF_FRAME_ALTREF = 7, +}; + +// Constants (section 3). +enum { + AV1_MAX_OPERATING_POINTS = 32, + + AV1_MAX_SB_SIZE = 128, + AV1_MI_SIZE = 4, + + AV1_MAX_TILE_WIDTH = 4096, + AV1_MAX_TILE_AREA = 4096 * 2304, + AV1_MAX_TILE_ROWS = 64, + AV1_MAX_TILE_COLS = 64, + + AV1_NUM_REF_FRAMES = 8, + AV1_REFS_PER_FRAME = 7, + AV1_TOTAL_REFS_PER_FRAME = 8, + AV1_PRIMARY_REF_NONE = 7, + + AV1_MAX_SEGMENTS = 8, + AV1_SEG_LVL_MAX = 8, + + AV1_SEG_LVL_ALT_Q = 0, + AV1_SEG_LVL_ALT_LF_Y_V = 1, + AV1_SEG_LVL_REF_FRAME = 5, + AV1_SEG_LVL_SKIP = 6, + AV1_SEG_LVL_GLOBAL_MV = 7, + + AV1_SELECT_SCREEN_CONTENT_TOOLS = 2, + AV1_SELECT_INTEGER_MV = 2, + + AV1_SUPERRES_NUM = 8, + AV1_SUPERRES_DENOM_MIN = 9, + + AV1_INTERPOLATION_FILTER_SWITCHABLE = 4, + + AV1_GM_ABS_ALPHA_BITS = 12, + AV1_GM_ALPHA_PREC_BITS = 15, + AV1_GM_ABS_TRANS_ONLY_BITS = 9, + AV1_GM_TRANS_ONLY_PREC_BITS = 3, + AV1_GM_ABS_TRANS_BITS = 12, + AV1_GM_TRANS_PREC_BITS = 6, + AV1_WARPEDMODEL_PREC_BITS = 16, + + AV1_WARP_MODEL_IDENTITY = 0, + AV1_WARP_MODEL_TRANSLATION = 1, + AV1_WARP_MODEL_ROTZOOM = 2, + AV1_WARP_MODEL_AFFINE = 3, +}; + + +// The main colour configuration information uses the same ISO/IEC 23001-8 +// (H.273) enums as FFmpeg does, so separate definitions are not required. + +// Chroma sample position. +enum { + AV1_CSP_UNKNOWN = 0, + AV1_CSP_VERTICAL = 1, // -> AVCHROMA_LOC_LEFT. + AV1_CSP_COLOCATED = 2, // -> AVCHROMA_LOC_TOPLEFT. +}; + +// Scalability modes (section 6.7.5) +enum { + AV1_SCALABILITY_L1T2 = 0, + AV1_SCALABILITY_L1T3 = 1, + AV1_SCALABILITY_L2T1 = 2, + AV1_SCALABILITY_L2T2 = 3, + AV1_SCALABILITY_L2T3 = 4, + AV1_SCALABILITY_S2T1 = 5, + AV1_SCALABILITY_S2T2 = 6, + AV1_SCALABILITY_S2T3 = 7, + AV1_SCALABILITY_L2T1h = 8, + AV1_SCALABILITY_L2T2h = 9, + AV1_SCALABILITY_L2T3h = 10, + AV1_SCALABILITY_S2T1h = 11, + AV1_SCALABILITY_S2T2h = 12, + AV1_SCALABILITY_S2T3h = 13, + AV1_SCALABILITY_SS = 14, + AV1_SCALABILITY_L3T1 = 15, + AV1_SCALABILITY_L3T2 = 16, + AV1_SCALABILITY_L3T3 = 17, + AV1_SCALABILITY_S3T1 = 18, + AV1_SCALABILITY_S3T2 = 19, + AV1_SCALABILITY_S3T3 = 20, + AV1_SCALABILITY_L3T2_KEY = 21, + AV1_SCALABILITY_L3T3_KEY = 22, + AV1_SCALABILITY_L4T5_KEY = 23, + AV1_SCALABILITY_L4T7_KEY = 24, + AV1_SCALABILITY_L3T2_KEY_SHIFT = 25, + AV1_SCALABILITY_L3T3_KEY_SHIFT = 26, + AV1_SCALABILITY_L4T5_KEY_SHIFT = 27, + AV1_SCALABILITY_L4T7_KEY_SHIFT = 28, +}; + +#endif /* AVCODEC_AV1_H */ diff --git a/libavcodec/av1_frame_split_bsf.c b/libavcodec/av1_frame_split_bsf.c new file mode 100644 index 000000000..a386c6edc --- /dev/null +++ b/libavcodec/av1_frame_split_bsf.c @@ -0,0 +1,261 @@ +/* + * Copyright (c) 2019 James Almer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * This bitstream filter splits AV1 Temporal Units into packets containing + * just one frame, plus any leading and trailing OBUs that may be present at + * the beginning or end, respectively. + * + * Temporal Units already containing only one frame will be passed through + * unchanged. When splitting can't be performed, the Temporal Unit will be + * passed through containing only the remaining OBUs starting from the first + * one after the last successfully split frame. + */ + +#include "libavutil/avassert.h" + +#include "avcodec.h" +#include "bsf.h" +#include "cbs.h" +#include "cbs_av1.h" + +typedef struct AV1FSplitContext { + AVPacket *buffer_pkt; + CodedBitstreamContext *cbc; + CodedBitstreamFragment temporal_unit; + + int nb_frames; + int cur_frame; + int cur_frame_idx; + int last_frame_idx; +} AV1FSplitContext; + +static int av1_frame_split_filter(AVBSFContext *ctx, AVPacket *out) +{ + AV1FSplitContext *s = ctx->priv_data; + CodedBitstreamFragment *td = &s->temporal_unit; + int i, ret; + int split = !!s->buffer_pkt->data; + + if (!s->buffer_pkt->data) { + int nb_frames = 0; + + ret = ff_bsf_get_packet_ref(ctx, s->buffer_pkt); + if (ret < 0) + return ret; + + ret = ff_cbs_read_packet(s->cbc, td, s->buffer_pkt); + if (ret < 0) { + av_log(ctx, AV_LOG_WARNING, "Failed to parse temporal unit.\n"); + goto passthrough; + } + + for (i = 0; i < td->nb_units; i++) { + CodedBitstreamUnit *unit = &td->units[i]; + + if (unit->type == AV1_OBU_FRAME || + unit->type == AV1_OBU_FRAME_HEADER) + nb_frames++; + else if (unit->type == AV1_OBU_TILE_LIST) { + av_log(ctx, AV_LOG_VERBOSE, "Large scale tiles are unsupported.\n"); + goto passthrough; + } + } + if (nb_frames > 1) { + s->cur_frame = 0; + s->cur_frame_idx = s->last_frame_idx = 0; + s->nb_frames = nb_frames; + split = 1; + } + } + + if (split) { + AV1RawFrameHeader *frame = NULL; + int cur_frame_type = -1, size = 0; + + for (i = s->cur_frame_idx; i < td->nb_units; i++) { + CodedBitstreamUnit *unit = &td->units[i]; + + size += unit->data_size; + if (unit->type == AV1_OBU_FRAME) { + AV1RawOBU *obu = unit->content; + + if (frame) { + av_log(ctx, AV_LOG_WARNING, "Frame OBU found when Tile data for a " + "previous frame was expected.\n"); + goto passthrough; + } + + frame = &obu->obu.frame.header; + cur_frame_type = obu->header.obu_type; + s->last_frame_idx = s->cur_frame_idx; + s->cur_frame_idx = i + 1; + s->cur_frame++; + + // split here unless it's the last frame, in which case + // include every trailing OBU + if (s->cur_frame < s->nb_frames) + break; + } else if (unit->type == AV1_OBU_FRAME_HEADER) { + AV1RawOBU *obu = unit->content; + + if (frame) { + av_log(ctx, AV_LOG_WARNING, "Frame Header OBU found when Tile data for a " + "previous frame was expected.\n"); + goto passthrough; + } + + frame = &obu->obu.frame_header; + cur_frame_type = obu->header.obu_type; + s->last_frame_idx = s->cur_frame_idx; + s->cur_frame++; + + // split here if show_existing_frame unless it's the last + // frame, in which case include every trailing OBU + if (frame->show_existing_frame && + s->cur_frame < s->nb_frames) { + s->cur_frame_idx = i + 1; + break; + } + } else if (unit->type == AV1_OBU_TILE_GROUP) { + AV1RawOBU *obu = unit->content; + AV1RawTileGroup *group = &obu->obu.tile_group; + + if (!frame || cur_frame_type != AV1_OBU_FRAME_HEADER) { + av_log(ctx, AV_LOG_WARNING, "Unexpected Tile Group OBU found before a " + "Frame Header.\n"); + goto passthrough; + } + + if ((group->tg_end == (frame->tile_cols * frame->tile_rows) - 1) && + // include every trailing OBU with the last frame + s->cur_frame < s->nb_frames) { + s->cur_frame_idx = i + 1; + break; + } + } + } + av_assert0(frame && s->cur_frame <= s->nb_frames); + + ret = av_packet_ref(out, s->buffer_pkt); + if (ret < 0) + goto fail; + + out->data = (uint8_t *)td->units[s->last_frame_idx].data; + out->size = size; + + // skip the frame in the buffer packet if it's split successfully, so it's not present + // if the packet is passed through in case of failure when splitting another frame. + s->buffer_pkt->data += size; + s->buffer_pkt->size -= size; + + if (!frame->show_existing_frame && !frame->show_frame) + out->pts = AV_NOPTS_VALUE; + + if (s->cur_frame == s->nb_frames) { + av_packet_unref(s->buffer_pkt); + ff_cbs_fragment_reset(s->cbc, td); + } + + return 0; + } + +passthrough: + av_packet_move_ref(out, s->buffer_pkt); + + ret = 0; +fail: + if (ret < 0) { + av_packet_unref(out); + av_packet_unref(s->buffer_pkt); + } + ff_cbs_fragment_reset(s->cbc, td); + + return ret; +} + +static const CodedBitstreamUnitType decompose_unit_types[] = { + AV1_OBU_TEMPORAL_DELIMITER, + AV1_OBU_SEQUENCE_HEADER, + AV1_OBU_FRAME_HEADER, + AV1_OBU_TILE_GROUP, + AV1_OBU_FRAME, +}; + +static int av1_frame_split_init(AVBSFContext *ctx) +{ + AV1FSplitContext *s = ctx->priv_data; + CodedBitstreamFragment *td = &s->temporal_unit; + int ret; + + s->buffer_pkt = av_packet_alloc(); + if (!s->buffer_pkt) + return AVERROR(ENOMEM); + + ret = ff_cbs_init(&s->cbc, AV_CODEC_ID_AV1, ctx); + if (ret < 0) + return ret; + + s->cbc->decompose_unit_types = (CodedBitstreamUnitType*)decompose_unit_types; + s->cbc->nb_decompose_unit_types = FF_ARRAY_ELEMS(decompose_unit_types); + + if (!ctx->par_in->extradata_size) + return 0; + + ret = ff_cbs_read_extradata(s->cbc, td, ctx->par_in); + if (ret < 0) + av_log(ctx, AV_LOG_WARNING, "Failed to parse extradata.\n"); + + ff_cbs_fragment_reset(s->cbc, td); + + return 0; +} + +static void av1_frame_split_flush(AVBSFContext *ctx) +{ + AV1FSplitContext *s = ctx->priv_data; + + av_packet_unref(s->buffer_pkt); + ff_cbs_fragment_reset(s->cbc, &s->temporal_unit); +} + +static void av1_frame_split_close(AVBSFContext *ctx) +{ + AV1FSplitContext *s = ctx->priv_data; + + av_packet_free(&s->buffer_pkt); + ff_cbs_fragment_free(s->cbc, &s->temporal_unit); + ff_cbs_close(&s->cbc); +} + +static const enum AVCodecID av1_frame_split_codec_ids[] = { + AV_CODEC_ID_AV1, AV_CODEC_ID_NONE, +}; + +const AVBitStreamFilter ff_av1_frame_split_bsf = { + .name = "av1_frame_split", + .priv_data_size = sizeof(AV1FSplitContext), + .init = av1_frame_split_init, + .flush = av1_frame_split_flush, + .close = av1_frame_split_close, + .filter = av1_frame_split_filter, + .codec_ids = av1_frame_split_codec_ids, +}; diff --git a/libavcodec/av1_metadata_bsf.c b/libavcodec/av1_metadata_bsf.c new file mode 100644 index 000000000..226f7dffa --- /dev/null +++ b/libavcodec/av1_metadata_bsf.c @@ -0,0 +1,313 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/common.h" +#include "libavutil/opt.h" + +#include "bsf.h" +#include "cbs.h" +#include "cbs_av1.h" + +enum { + PASS, + INSERT, + REMOVE, +}; + +typedef struct AV1MetadataContext { + const AVClass *class; + + CodedBitstreamContext *cbc; + CodedBitstreamFragment access_unit; + + int td; + + int color_primaries; + int transfer_characteristics; + int matrix_coefficients; + + int color_range; + int chroma_sample_position; + + AVRational tick_rate; + int num_ticks_per_picture; + + int delete_padding; +} AV1MetadataContext; + + +static int av1_metadata_update_sequence_header(AVBSFContext *bsf, + AV1RawSequenceHeader *seq) +{ + AV1MetadataContext *ctx = bsf->priv_data; + AV1RawColorConfig *clc = &seq->color_config; + AV1RawTimingInfo *tim = &seq->timing_info; + + if (ctx->color_primaries >= 0 || + ctx->transfer_characteristics >= 0 || + ctx->matrix_coefficients >= 0) { + if (!clc->color_description_present_flag) { + clc->color_description_present_flag = 1; + clc->color_primaries = AVCOL_PRI_UNSPECIFIED; + clc->transfer_characteristics = AVCOL_TRC_UNSPECIFIED; + clc->matrix_coefficients = AVCOL_SPC_UNSPECIFIED; + } + + if (ctx->color_primaries >= 0) + clc->color_primaries = ctx->color_primaries; + if (ctx->transfer_characteristics >= 0) + clc->transfer_characteristics = ctx->transfer_characteristics; + if (ctx->matrix_coefficients >= 0) + clc->matrix_coefficients = ctx->matrix_coefficients; + } + + if (ctx->color_range >= 0) { + if (clc->color_primaries == AVCOL_PRI_BT709 && + clc->transfer_characteristics == AVCOL_TRC_IEC61966_2_1 && + clc->matrix_coefficients == AVCOL_SPC_RGB) { + av_log(bsf, AV_LOG_WARNING, "Warning: color_range cannot be set " + "on RGB streams encoded in BT.709 sRGB.\n"); + } else { + clc->color_range = ctx->color_range; + } + } + + if (ctx->chroma_sample_position >= 0) { + if (clc->mono_chrome || !clc->subsampling_x || !clc->subsampling_y) { + av_log(bsf, AV_LOG_WARNING, "Warning: chroma_sample_position " + "can only be set for 4:2:0 streams.\n"); + } else { + clc->chroma_sample_position = ctx->chroma_sample_position; + } + } + + if (ctx->tick_rate.num && ctx->tick_rate.den) { + int num, den; + + av_reduce(&num, &den, ctx->tick_rate.num, ctx->tick_rate.den, + UINT32_MAX > INT_MAX ? UINT32_MAX : INT_MAX); + + tim->time_scale = num; + tim->num_units_in_display_tick = den; + seq->timing_info_present_flag = 1; + + if (ctx->num_ticks_per_picture > 0) { + tim->equal_picture_interval = 1; + tim->num_ticks_per_picture_minus_1 = + ctx->num_ticks_per_picture - 1; + } + } + + return 0; +} + +static int av1_metadata_filter(AVBSFContext *bsf, AVPacket *pkt) +{ + AV1MetadataContext *ctx = bsf->priv_data; + CodedBitstreamFragment *frag = &ctx->access_unit; + AV1RawOBU td, *obu; + int err, i; + + err = ff_bsf_get_packet_ref(bsf, pkt); + if (err < 0) + return err; + + err = ff_cbs_read_packet(ctx->cbc, frag, pkt); + if (err < 0) { + av_log(bsf, AV_LOG_ERROR, "Failed to read packet.\n"); + goto fail; + } + + if (frag->nb_units == 0) { + av_log(bsf, AV_LOG_ERROR, "No OBU in packet.\n"); + err = AVERROR_INVALIDDATA; + goto fail; + } + + for (i = 0; i < frag->nb_units; i++) { + if (frag->units[i].type == AV1_OBU_SEQUENCE_HEADER) { + obu = frag->units[i].content; + err = av1_metadata_update_sequence_header(bsf, &obu->obu.sequence_header); + if (err < 0) + goto fail; + } + } + + // If a Temporal Delimiter is present, it must be the first OBU. + if (frag->units[0].type == AV1_OBU_TEMPORAL_DELIMITER) { + if (ctx->td == REMOVE) + ff_cbs_delete_unit(ctx->cbc, frag, 0); + } else if (ctx->td == INSERT) { + td = (AV1RawOBU) { + .header.obu_type = AV1_OBU_TEMPORAL_DELIMITER, + }; + + err = ff_cbs_insert_unit_content(ctx->cbc, frag, 0, AV1_OBU_TEMPORAL_DELIMITER, + &td, NULL); + if (err < 0) { + av_log(bsf, AV_LOG_ERROR, "Failed to insert Temporal Delimiter.\n"); + goto fail; + } + } + + if (ctx->delete_padding) { + for (i = frag->nb_units - 1; i >= 0; i--) { + if (frag->units[i].type == AV1_OBU_PADDING) + ff_cbs_delete_unit(ctx->cbc, frag, i); + } + } + + err = ff_cbs_write_packet(ctx->cbc, pkt, frag); + if (err < 0) { + av_log(bsf, AV_LOG_ERROR, "Failed to write packet.\n"); + goto fail; + } + + err = 0; +fail: + ff_cbs_fragment_reset(ctx->cbc, frag); + + if (err < 0) + av_packet_unref(pkt); + + return err; +} + +static int av1_metadata_init(AVBSFContext *bsf) +{ + AV1MetadataContext *ctx = bsf->priv_data; + CodedBitstreamFragment *frag = &ctx->access_unit; + AV1RawOBU *obu; + int err, i; + + err = ff_cbs_init(&ctx->cbc, AV_CODEC_ID_AV1, bsf); + if (err < 0) + return err; + + if (bsf->par_in->extradata) { + err = ff_cbs_read_extradata(ctx->cbc, frag, bsf->par_in); + if (err < 0) { + av_log(bsf, AV_LOG_ERROR, "Failed to read extradata.\n"); + goto fail; + } + + for (i = 0; i < frag->nb_units; i++) { + if (frag->units[i].type == AV1_OBU_SEQUENCE_HEADER) { + obu = frag->units[i].content; + err = av1_metadata_update_sequence_header(bsf, &obu->obu.sequence_header); + if (err < 0) + goto fail; + } + } + + err = ff_cbs_write_extradata(ctx->cbc, bsf->par_out, frag); + if (err < 0) { + av_log(bsf, AV_LOG_ERROR, "Failed to write extradata.\n"); + goto fail; + } + } + + err = 0; +fail: + ff_cbs_fragment_reset(ctx->cbc, frag); + return err; +} + +static void av1_metadata_close(AVBSFContext *bsf) +{ + AV1MetadataContext *ctx = bsf->priv_data; + + ff_cbs_fragment_free(ctx->cbc, &ctx->access_unit); + ff_cbs_close(&ctx->cbc); +} + +#define OFFSET(x) offsetof(AV1MetadataContext, x) +#define FLAGS (AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_BSF_PARAM) +static const AVOption av1_metadata_options[] = { + { "td", "Temporal Delimiter OBU", + OFFSET(td), AV_OPT_TYPE_INT, + { .i64 = PASS }, PASS, REMOVE, FLAGS, "td" }, + { "pass", NULL, 0, AV_OPT_TYPE_CONST, + { .i64 = PASS }, .flags = FLAGS, .unit = "td" }, + { "insert", NULL, 0, AV_OPT_TYPE_CONST, + { .i64 = INSERT }, .flags = FLAGS, .unit = "td" }, + { "remove", NULL, 0, AV_OPT_TYPE_CONST, + { .i64 = REMOVE }, .flags = FLAGS, .unit = "td" }, + + { "color_primaries", "Set color primaries (section 6.4.2)", + OFFSET(color_primaries), AV_OPT_TYPE_INT, + { .i64 = -1 }, -1, 255, FLAGS }, + { "transfer_characteristics", "Set transfer characteristics (section 6.4.2)", + OFFSET(transfer_characteristics), AV_OPT_TYPE_INT, + { .i64 = -1 }, -1, 255, FLAGS }, + { "matrix_coefficients", "Set matrix coefficients (section 6.4.2)", + OFFSET(matrix_coefficients), AV_OPT_TYPE_INT, + { .i64 = -1 }, -1, 255, FLAGS }, + + { "color_range", "Set color range flag (section 6.4.2)", + OFFSET(color_range), AV_OPT_TYPE_INT, + { .i64 = -1 }, -1, 1, FLAGS, "cr" }, + { "tv", "TV (limited) range", 0, AV_OPT_TYPE_CONST, + { .i64 = 0 }, .flags = FLAGS, .unit = "cr" }, + { "pc", "PC (full) range", 0, AV_OPT_TYPE_CONST, + { .i64 = 1 }, .flags = FLAGS, .unit = "cr" }, + + { "chroma_sample_position", "Set chroma sample position (section 6.4.2)", + OFFSET(chroma_sample_position), AV_OPT_TYPE_INT, + { .i64 = -1 }, -1, 3, FLAGS, "csp" }, + { "unknown", "Unknown chroma sample position", 0, AV_OPT_TYPE_CONST, + { .i64 = AV1_CSP_UNKNOWN }, .flags = FLAGS, .unit = "csp" }, + { "vertical", "Left chroma sample position", 0, AV_OPT_TYPE_CONST, + { .i64 = AV1_CSP_VERTICAL }, .flags = FLAGS, .unit = "csp" }, + { "colocated", "Top-left chroma sample position", 0, AV_OPT_TYPE_CONST, + { .i64 = AV1_CSP_COLOCATED }, .flags = FLAGS, .unit = "csp" }, + + { "tick_rate", "Set display tick rate (num_units_in_display_tick / time_scale)", + OFFSET(tick_rate), AV_OPT_TYPE_RATIONAL, + { .dbl = 0.0 }, 0, UINT_MAX, FLAGS }, + { "num_ticks_per_picture", "Set display ticks per picture for CFR streams", + OFFSET(num_ticks_per_picture), AV_OPT_TYPE_INT, + { .i64 = -1 }, -1, INT_MAX, FLAGS }, + + { "delete_padding", "Delete all Padding OBUs", + OFFSET(delete_padding), AV_OPT_TYPE_BOOL, + { .i64 = 0 }, 0, 1, FLAGS}, + + { NULL } +}; + +static const AVClass av1_metadata_class = { + .class_name = "av1_metadata_bsf", + .item_name = av_default_item_name, + .option = av1_metadata_options, + .version = LIBAVUTIL_VERSION_INT, +}; + +static const enum AVCodecID av1_metadata_codec_ids[] = { + AV_CODEC_ID_AV1, AV_CODEC_ID_NONE, +}; + +const AVBitStreamFilter ff_av1_metadata_bsf = { + .name = "av1_metadata", + .priv_data_size = sizeof(AV1MetadataContext), + .priv_class = &av1_metadata_class, + .init = &av1_metadata_init, + .close = &av1_metadata_close, + .filter = &av1_metadata_filter, + .codec_ids = av1_metadata_codec_ids, +}; diff --git a/libavcodec/av1_parse.c b/libavcodec/av1_parse.c new file mode 100644 index 000000000..cdd524baa --- /dev/null +++ b/libavcodec/av1_parse.c @@ -0,0 +1,107 @@ +/* + * AV1 common parsing code + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" + +#include "libavutil/mem.h" + +#include "av1.h" +#include "av1_parse.h" +#include "bytestream.h" + +int ff_av1_extract_obu(AV1OBU *obu, const uint8_t *buf, int length, void *logctx) +{ + int64_t obu_size; + int start_pos, type, temporal_id, spatial_id; + int len; + + len = parse_obu_header(buf, length, &obu_size, &start_pos, + &type, &temporal_id, &spatial_id); + if (len < 0) + return len; + + obu->type = type; + obu->temporal_id = temporal_id; + obu->spatial_id = spatial_id; + + obu->data = buf + start_pos; + obu->size = obu_size; + obu->raw_data = buf; + obu->raw_size = len; + + av_log(logctx, AV_LOG_DEBUG, + "obu_type: %d, temporal_id: %d, spatial_id: %d, payload size: %d\n", + obu->type, obu->temporal_id, obu->spatial_id, obu->size); + + return len; +} + +int ff_av1_packet_split(AV1Packet *pkt, const uint8_t *buf, int length, void *logctx) +{ + GetByteContext bc; + int ret, consumed; + + bytestream2_init(&bc, buf, length); + pkt->nb_obus = 0; + + while (bytestream2_get_bytes_left(&bc) > 0) { + AV1OBU *obu; + + if (pkt->obus_allocated < pkt->nb_obus + 1) { + int new_size = pkt->obus_allocated + 1; + AV1OBU *tmp = av_realloc_array(pkt->obus, new_size, sizeof(*tmp)); + if (!tmp) + return AVERROR(ENOMEM); + + pkt->obus = tmp; + memset(pkt->obus + pkt->obus_allocated, 0, + (new_size - pkt->obus_allocated) * sizeof(*tmp)); + pkt->obus_allocated = new_size; + } + obu = &pkt->obus[pkt->nb_obus]; + + consumed = ff_av1_extract_obu(obu, bc.buffer, bytestream2_get_bytes_left(&bc), logctx); + if (consumed < 0) + return consumed; + + bytestream2_skip(&bc, consumed); + + obu->size_bits = get_obu_bit_length(obu->data, obu->size, obu->type); + + if (obu->size_bits < 0 || (!obu->size_bits && obu->type != AV1_OBU_TEMPORAL_DELIMITER)) { + av_log(logctx, AV_LOG_ERROR, "Invalid OBU of type %d, skipping.\n", obu->type); + continue; + } + + pkt->nb_obus++; + + ret = init_get_bits(&obu->gb, obu->data, obu->size_bits); + if (ret < 0) + return ret; + } + + return 0; +} + +void ff_av1_packet_uninit(AV1Packet *pkt) +{ + av_freep(&pkt->obus); + pkt->obus_allocated = 0; +} diff --git a/libavcodec/av1_parse.h b/libavcodec/av1_parse.h new file mode 100644 index 000000000..864308f81 --- /dev/null +++ b/libavcodec/av1_parse.h @@ -0,0 +1,174 @@ +/* + * AV1 common parsing code + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * 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_AV1_PARSE_H +#define AVCODEC_AV1_PARSE_H + +#include + +#include "av1.h" +#include "avcodec.h" +#include "get_bits.h" + +typedef struct AV1OBU { + /** Size of payload */ + int size; + const uint8_t *data; + + /** + * Size, in bits, of just the data, excluding the trailing_one_bit and + * any trailing padding. + */ + int size_bits; + + /** Size of entire OBU, including header */ + int raw_size; + const uint8_t *raw_data; + + /** GetBitContext initialized to the start of the payload */ + GetBitContext gb; + + int type; + + int temporal_id; + int spatial_id; +} AV1OBU; + +/** An input packet split into OBUs */ +typedef struct AV1Packet { + AV1OBU *obus; + int nb_obus; + int obus_allocated; +} AV1Packet; + +/** + * Extract an OBU from a raw bitstream. + * + * @note This function does not copy or store any bitstream data. All + * the pointers in the AV1OBU structure will be valid as long + * as the input buffer also is. + */ +int ff_av1_extract_obu(AV1OBU *obu, const uint8_t *buf, int length, + void *logctx); + +/** + * Split an input packet into OBUs. + * + * @note This function does not copy or store any bitstream data. All + * the pointers in the AV1Packet structure will be valid as + * long as the input buffer also is. + */ +int ff_av1_packet_split(AV1Packet *pkt, const uint8_t *buf, int length, + void *logctx); + +/** + * Free all the allocated memory in the packet. + */ +void ff_av1_packet_uninit(AV1Packet *pkt); + +static inline int64_t leb128(GetBitContext *gb) { + int64_t ret = 0; + int i; + + for (i = 0; i < 8; i++) { + int byte = get_bits(gb, 8); + ret |= (int64_t)(byte & 0x7f) << (i * 7); + if (!(byte & 0x80)) + break; + } + return ret; +} + +static inline int parse_obu_header(const uint8_t *buf, int buf_size, + int64_t *obu_size, int *start_pos, int *type, + int *temporal_id, int *spatial_id) +{ + GetBitContext gb; + int ret, extension_flag, has_size_flag; + int64_t size; + + ret = init_get_bits8(&gb, buf, FFMIN(buf_size, 2 + 8)); // OBU header fields + max leb128 length + if (ret < 0) + return ret; + + if (get_bits1(&gb) != 0) // obu_forbidden_bit + return AVERROR_INVALIDDATA; + + *type = get_bits(&gb, 4); + extension_flag = get_bits1(&gb); + has_size_flag = get_bits1(&gb); + skip_bits1(&gb); // obu_reserved_1bit + + if (extension_flag) { + *temporal_id = get_bits(&gb, 3); + *spatial_id = get_bits(&gb, 2); + skip_bits(&gb, 3); // extension_header_reserved_3bits + } else { + *temporal_id = *spatial_id = 0; + } + + *obu_size = has_size_flag ? leb128(&gb) + : buf_size - 1 - extension_flag; + + if (get_bits_left(&gb) < 0) + return AVERROR_INVALIDDATA; + + *start_pos = get_bits_count(&gb) / 8; + + size = *obu_size + *start_pos; + + if (size > buf_size) + return AVERROR_INVALIDDATA; + + return size; +} + +static inline int get_obu_bit_length(const uint8_t *buf, int size, int type) +{ + int v; + + /* There are no trailing bits on these */ + if (type == AV1_OBU_TILE_GROUP || type == AV1_OBU_FRAME) { + if (size > INT_MAX / 8) + return AVERROR(ERANGE); + else + return size * 8; + } + + while (size > 0 && buf[size - 1] == 0) + size--; + + if (!size) + return 0; + + v = buf[size - 1]; + + if (size > INT_MAX / 8) + return AVERROR(ERANGE); + size *= 8; + + /* Remove the trailing_one_bit and following trailing zeros */ + if (v) + size -= ff_ctz(v) + 1; + + return size; +} + +#endif /* AVCODEC_AV1_PARSE_H */ diff --git a/libavcodec/av1_parser.c b/libavcodec/av1_parser.c new file mode 100644 index 000000000..b916608d6 --- /dev/null +++ b/libavcodec/av1_parser.c @@ -0,0 +1,228 @@ +/* + * AV1 parser + * + * Copyright (C) 2018 James Almer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "av1_parse.h" +#include "cbs.h" +#include "cbs_av1.h" +#include "parser.h" + +typedef struct AV1ParseContext { + CodedBitstreamContext *cbc; + CodedBitstreamFragment temporal_unit; + int parsed_extradata; +} AV1ParseContext; + +static const enum AVPixelFormat pix_fmts_8bit[2][2] = { + { AV_PIX_FMT_YUV444P, AV_PIX_FMT_NONE }, + { AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV420P }, +}; +static const enum AVPixelFormat pix_fmts_10bit[2][2] = { + { AV_PIX_FMT_YUV444P10, AV_PIX_FMT_NONE }, + { AV_PIX_FMT_YUV422P10, AV_PIX_FMT_YUV420P10 }, +}; +static const enum AVPixelFormat pix_fmts_12bit[2][2] = { + { AV_PIX_FMT_YUV444P12, AV_PIX_FMT_NONE }, + { AV_PIX_FMT_YUV422P12, AV_PIX_FMT_YUV420P12 }, +}; + +static int av1_parser_parse(AVCodecParserContext *ctx, + AVCodecContext *avctx, + const uint8_t **out_data, int *out_size, + const uint8_t *data, int size) +{ + AV1ParseContext *s = ctx->priv_data; + CodedBitstreamFragment *td = &s->temporal_unit; + CodedBitstreamAV1Context *av1 = s->cbc->priv_data; + int ret; + + *out_data = data; + *out_size = size; + + ctx->key_frame = -1; + ctx->pict_type = AV_PICTURE_TYPE_NONE; + ctx->picture_structure = AV_PICTURE_STRUCTURE_UNKNOWN; + + s->cbc->log_ctx = avctx; + + if (avctx->extradata_size && !s->parsed_extradata) { + s->parsed_extradata = 1; + + ret = ff_cbs_read(s->cbc, td, avctx->extradata, avctx->extradata_size); + if (ret < 0) { + av_log(avctx, AV_LOG_WARNING, "Failed to parse extradata.\n"); + } + + ff_cbs_fragment_reset(s->cbc, td); + } + + ret = ff_cbs_read(s->cbc, td, data, size); + if (ret < 0) { + av_log(avctx, AV_LOG_ERROR, "Failed to parse temporal unit.\n"); + goto end; + } + + if (!av1->sequence_header) { + av_log(avctx, AV_LOG_ERROR, "No sequence header available\n"); + goto end; + } + + for (int i = 0; i < td->nb_units; i++) { + CodedBitstreamUnit *unit = &td->units[i]; + AV1RawOBU *obu = unit->content; + AV1RawSequenceHeader *seq = av1->sequence_header; + AV1RawColorConfig *color = &seq->color_config; + AV1RawFrameHeader *frame; + int frame_type; + + if (unit->type == AV1_OBU_FRAME) + frame = &obu->obu.frame.header; + else if (unit->type == AV1_OBU_FRAME_HEADER) + frame = &obu->obu.frame_header; + else + continue; + + if (frame->show_existing_frame) { + AV1ReferenceFrameState *ref = &av1->ref[frame->frame_to_show_map_idx]; + + if (!ref->valid) { + av_log(avctx, AV_LOG_ERROR, "Invalid reference frame\n"); + goto end; + } + + ctx->width = ref->frame_width; + ctx->height = ref->frame_height; + frame_type = ref->frame_type; + + ctx->key_frame = 0; + } else if (!frame->show_frame) { + continue; + } else { + ctx->width = av1->frame_width; + ctx->height = av1->frame_height; + frame_type = frame->frame_type; + + ctx->key_frame = frame_type == AV1_FRAME_KEY; + } + + avctx->profile = seq->seq_profile; + avctx->level = seq->seq_level_idx[0]; + + switch (frame_type) { + case AV1_FRAME_KEY: + case AV1_FRAME_INTRA_ONLY: + ctx->pict_type = AV_PICTURE_TYPE_I; + break; + case AV1_FRAME_INTER: + ctx->pict_type = AV_PICTURE_TYPE_P; + break; + case AV1_FRAME_SWITCH: + ctx->pict_type = AV_PICTURE_TYPE_SP; + break; + } + ctx->picture_structure = AV_PICTURE_STRUCTURE_FRAME; + + switch (av1->bit_depth) { + case 8: + ctx->format = color->mono_chrome ? AV_PIX_FMT_GRAY8 + : pix_fmts_8bit [color->subsampling_x][color->subsampling_y]; + break; + case 10: + ctx->format = color->mono_chrome ? AV_PIX_FMT_GRAY10 + : pix_fmts_10bit[color->subsampling_x][color->subsampling_y]; + break; + case 12: + ctx->format = color->mono_chrome ? AV_PIX_FMT_GRAY12 + : pix_fmts_12bit[color->subsampling_x][color->subsampling_y]; + break; + } + av_assert2(ctx->format != AV_PIX_FMT_NONE); + } + +end: + ff_cbs_fragment_reset(s->cbc, td); + + s->cbc->log_ctx = NULL; + + return size; +} + +static const CodedBitstreamUnitType decompose_unit_types[] = { + AV1_OBU_TEMPORAL_DELIMITER, + AV1_OBU_SEQUENCE_HEADER, + AV1_OBU_FRAME_HEADER, + AV1_OBU_TILE_GROUP, + AV1_OBU_FRAME, +}; + +static av_cold int av1_parser_init(AVCodecParserContext *ctx) +{ + AV1ParseContext *s = ctx->priv_data; + int ret; + + ret = ff_cbs_init(&s->cbc, AV_CODEC_ID_AV1, NULL); + if (ret < 0) + return ret; + + s->cbc->decompose_unit_types = (CodedBitstreamUnitType *)decompose_unit_types; + s->cbc->nb_decompose_unit_types = FF_ARRAY_ELEMS(decompose_unit_types); + + return 0; +} + +static void av1_parser_close(AVCodecParserContext *ctx) +{ + AV1ParseContext *s = ctx->priv_data; + + ff_cbs_fragment_free(s->cbc, &s->temporal_unit); + ff_cbs_close(&s->cbc); +} + +static int av1_parser_split(AVCodecContext *avctx, + const uint8_t *buf, int buf_size) +{ + AV1OBU obu; + const uint8_t *ptr = buf, *end = buf + buf_size; + + while (ptr < end) { + int len = ff_av1_extract_obu(&obu, ptr, buf_size, avctx); + if (len < 0) + break; + + if (obu.type == AV1_OBU_FRAME_HEADER || + obu.type == AV1_OBU_FRAME) { + return ptr - buf; + } + ptr += len; + buf_size -= len; + } + + return 0; +} + +AVCodecParser ff_av1_parser = { + .codec_ids = { AV_CODEC_ID_AV1 }, + .priv_data_size = sizeof(AV1ParseContext), + .parser_init = av1_parser_init, + .parser_close = av1_parser_close, + .parser_parse = av1_parser_parse, + .split = av1_parser_split, +}; diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h index 0139d7209..d234271c5 100644 --- a/libavcodec/avcodec.h +++ b/libavcodec/avcodec.h @@ -409,6 +409,7 @@ enum AVCodecID { AV_CODEC_ID_DXV, AV_CODEC_ID_SCREENPRESSO, AV_CODEC_ID_RSCC, + AV_CODEC_ID_AVS2, AV_CODEC_ID_Y41P = 0x8000, AV_CODEC_ID_AVRP, @@ -446,6 +447,16 @@ enum AVCodecID { AV_CODEC_ID_SVG, AV_CODEC_ID_GDV, AV_CODEC_ID_FITS, + AV_CODEC_ID_IMM4, + AV_CODEC_ID_PROSUMER, + AV_CODEC_ID_MWSC, + AV_CODEC_ID_WCMV, + AV_CODEC_ID_RASC, + AV_CODEC_ID_HYMT, + AV_CODEC_ID_ARBC, + AV_CODEC_ID_AGM, + AV_CODEC_ID_LSCR, + AV_CODEC_ID_VP4, /* various PCM "codecs" */ AV_CODEC_ID_FIRST_AUDIO = 0x10000, ///< A dummy id pointing at the start of audio codecs @@ -485,6 +496,7 @@ enum AVCodecID { AV_CODEC_ID_PCM_S64BE, AV_CODEC_ID_PCM_F16LE, AV_CODEC_ID_PCM_F24LE, + AV_CODEC_ID_PCM_VIDC, /* various ADPCM codecs */ AV_CODEC_ID_ADPCM_IMA_QT = 0x11000, @@ -529,6 +541,7 @@ enum AVCodecID { AV_CODEC_ID_ADPCM_AICA, AV_CODEC_ID_ADPCM_IMA_DAT4, AV_CODEC_ID_ADPCM_MTAF, + AV_CODEC_ID_ADPCM_AGM, /* AMR */ AV_CODEC_ID_AMR_NB = 0x12000, @@ -637,6 +650,8 @@ enum AVCodecID { AV_CODEC_ID_APTX, AV_CODEC_ID_APTX_HD, AV_CODEC_ID_SBC, + AV_CODEC_ID_ATRAC9, + AV_CODEC_ID_HCOM, /* subtitle codecs */ AV_CODEC_ID_FIRST_SUBTITLE = 0x17000, ///< A dummy ID pointing at the start of subtitle codecs. @@ -665,6 +680,8 @@ enum AVCodecID { AV_CODEC_ID_PJS, AV_CODEC_ID_ASS, AV_CODEC_ID_HDMV_TEXT_SUBTITLE, + AV_CODEC_ID_TTML, + AV_CODEC_ID_ARIB_CAPTION, /* other specific kind of codecs (generally used for attachments) */ AV_CODEC_ID_FIRST_UNKNOWN = 0x18000, ///< A dummy ID pointing at the start of various fake codecs. @@ -843,6 +860,11 @@ typedef struct RcOverride{ * Use qpel MC. */ #define AV_CODEC_FLAG_QPEL (1 << 4) +/** + * Don't output frames whose parameters differ from first + * decoded frame in stream. + */ +#define AV_CODEC_FLAG_DROPCHANGED (1 << 5) /** * Use internal 2pass ratecontrol in first pass mode. */ @@ -1062,6 +1084,13 @@ typedef struct RcOverride{ */ #define AV_CODEC_CAP_HYBRID (1 << 19) +/** + * This codec takes the reordered_opaque field from input AVFrames + * and returns it in the corresponding field in AVCodecContext after + * encoding. + */ +#define AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE (1 << 20) + /** * Pan Scan area. * This specifies the area which should be displayed. @@ -1101,17 +1130,29 @@ typedef struct AVCPBProperties { * Maximum bitrate of the stream, in bits per second. * Zero if unknown or unspecified. */ +#if FF_API_UNSANITIZED_BITRATES int max_bitrate; +#else + int64_t max_bitrate; +#endif /** * Minimum bitrate of the stream, in bits per second. * Zero if unknown or unspecified. */ +#if FF_API_UNSANITIZED_BITRATES int min_bitrate; +#else + int64_t min_bitrate; +#endif /** * Average bitrate of the stream, in bits per second. * Zero if unknown or unspecified. */ +#if FF_API_UNSANITIZED_BITRATES int avg_bitrate; +#else + int64_t avg_bitrate; +#endif /** * The size of the buffer to which the ratecontrol is applied, in bits. @@ -1357,6 +1398,12 @@ enum AVPacketSideDataType { */ AV_PKT_DATA_ENCRYPTION_INFO, + /** + * Active Format Description data consisting of a single byte as specified + * in ETSI TS 101 154 using AVActiveFormatDescription enum. + */ + AV_PKT_DATA_AFD, + /** * The number of side data types. * This is not part of the public API/ABI in the sense that it may @@ -1612,6 +1659,7 @@ typedef struct AVCodecContext { * The allocated memory should be AV_INPUT_BUFFER_PADDING_SIZE bytes larger * than extradata_size to avoid problems if it is read with the bitstream reader. * The bytewise contents of extradata must not depend on the architecture or CPU endianness. + * Must be allocated with the av_malloc() family of functions. * - encoding: Set/allocated/freed by libavcodec. * - decoding: Set/allocated/freed by user. */ @@ -2009,15 +2057,19 @@ typedef struct AVCodecContext { /** * custom intra quantization matrix - * - encoding: Set by user, can be NULL. - * - decoding: Set by libavcodec. + * Must be allocated with the av_malloc() family of functions, and will be freed in + * avcodec_free_context(). + * - encoding: Set/allocated by user, freed by libavcodec. Can be NULL. + * - decoding: Set/allocated/freed by libavcodec. */ uint16_t *intra_matrix; /** * custom inter quantization matrix - * - encoding: Set by user, can be NULL. - * - decoding: Set by libavcodec. + * Must be allocated with the av_malloc() family of functions, and will be freed in + * avcodec_free_context(). + * - encoding: Set/allocated by user, freed by libavcodec. Can be NULL. + * - decoding: Set/allocated/freed by libavcodec. */ uint16_t *inter_matrix; @@ -2661,7 +2713,10 @@ typedef struct AVCodecContext { /** * opaque 64-bit number (generally a PTS) that will be reordered and * output in AVFrame.reordered_opaque - * - encoding: unused + * - encoding: Set by libavcodec to the reordered_opaque of the input + * frame corresponding to the last returned packet. Only + * supported by encoders with the + * AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE capability. * - decoding: Set by user. */ int64_t reordered_opaque; @@ -2945,6 +3000,16 @@ typedef struct AVCodecContext { #define FF_PROFILE_SBC_MSBC 1 +#define FF_PROFILE_PRORES_PROXY 0 +#define FF_PROFILE_PRORES_LT 1 +#define FF_PROFILE_PRORES_STANDARD 2 +#define FF_PROFILE_PRORES_HQ 3 +#define FF_PROFILE_PRORES_4444 4 +#define FF_PROFILE_PRORES_XQ 5 + +#define FF_PROFILE_ARIB_PROFILE_A 0 +#define FF_PROFILE_ARIB_PROFILE_C 1 + /** * level * - encoding: Set by user. @@ -3297,6 +3362,14 @@ typedef struct AVCodecContext { * used as reference pictures). */ int extra_hw_frames; + + /** + * The percentage of damaged samples to discard a frame. + * + * - decoding: set by user + * - encoding: unused + */ + int discard_damaged_percentage; } AVCodecContext; #if FF_API_CODEC_GET_SET @@ -4349,7 +4422,7 @@ int av_grow_packet(AVPacket *pkt, int grow_by); * Initialize a reference-counted packet from av_malloc()ed data. * * @param pkt packet to be initialized. This function will set the data, size, - * buf and destruct fields, all others are left untouched. + * and buf fields, all others are left untouched. * @param data Data allocated by av_malloc() to be used as packet data. If this * function returns successfully, the data is owned by the underlying AVBuffer. * The caller may not access the data through other means. @@ -4855,6 +4928,9 @@ int avcodec_send_packet(AVCodecContext *avctx, const AVPacket *avpkt); * AVERROR_EOF: the decoder has been fully flushed, and there will be * no more output frames * AVERROR(EINVAL): codec not opened, or it is an encoder + * AVERROR_INPUT_CHANGED: current decoded frame has changed parameters + * with respect to first decoded frame. Applicable + * when flag AV_CODEC_FLAG_DROPCHANGED is set. * other negative values: legitimate decoding errors */ int avcodec_receive_frame(AVCodecContext *avctx, AVFrame *frame); @@ -5766,6 +5842,7 @@ typedef struct AVBitStreamFilter { int (*init)(AVBSFContext *ctx); int (*filter)(AVBSFContext *ctx, AVPacket *pkt); void (*close)(AVBSFContext *ctx); + void (*flush)(AVBSFContext *ctx); } AVBitStreamFilter; #if FF_API_OLD_BSF @@ -5892,6 +5969,11 @@ int av_bsf_send_packet(AVBSFContext *ctx, AVPacket *pkt); */ int av_bsf_receive_packet(AVBSFContext *ctx, AVPacket *pkt); +/** + * Reset the internal bitstream filter state / flush internal buffers. + */ +void av_bsf_flush(AVBSFContext *ctx); + /** * Free a bitstream filter context and everything associated with it; write NULL * into the supplied pointer. diff --git a/libavcodec/avpacket.c b/libavcodec/avpacket.c index 99a0c1383..2b2006721 100644 --- a/libavcodec/avpacket.c +++ b/libavcodec/avpacket.c @@ -112,7 +112,7 @@ int av_grow_packet(AVPacket *pkt, int grow_by) av_assert0((unsigned)pkt->size <= INT_MAX - AV_INPUT_BUFFER_PADDING_SIZE); if ((unsigned)grow_by > INT_MAX - (pkt->size + AV_INPUT_BUFFER_PADDING_SIZE)) - return -1; + return AVERROR(ENOMEM); new_size = pkt->size + grow_by + AV_INPUT_BUFFER_PADDING_SIZE; if (pkt->buf) { @@ -124,7 +124,7 @@ int av_grow_packet(AVPacket *pkt, int grow_by) } else { data_offset = pkt->data - pkt->buf->data; if (data_offset > INT_MAX - new_size) - return -1; + return AVERROR(ENOMEM); } if (new_size + data_offset > pkt->buf->size) { @@ -375,6 +375,9 @@ const char *av_packet_side_data_name(enum AVPacketSideDataType type) case AV_PKT_DATA_DISPLAYMATRIX: return "Display Matrix"; case AV_PKT_DATA_STEREO3D: return "Stereo 3D"; case AV_PKT_DATA_AUDIO_SERVICE_TYPE: return "Audio Service Type"; + case AV_PKT_DATA_QUALITY_STATS: return "Quality stats"; + case AV_PKT_DATA_FALLBACK_TRACK: return "Fallback track"; + case AV_PKT_DATA_CPB_PROPERTIES: return "CPB properties"; case AV_PKT_DATA_SKIP_SAMPLES: return "Skip Samples"; case AV_PKT_DATA_JP_DUALMONO: return "JP Dual Mono"; case AV_PKT_DATA_STRINGS_METADATA: return "Strings Metadata"; @@ -388,6 +391,9 @@ const char *av_packet_side_data_name(enum AVPacketSideDataType type) case AV_PKT_DATA_CONTENT_LIGHT_LEVEL: return "Content light level metadata"; case AV_PKT_DATA_SPHERICAL: return "Spherical Mapping"; case AV_PKT_DATA_A53_CC: return "A53 Closed Captions"; + case AV_PKT_DATA_ENCRYPTION_INIT_INFO: return "Encryption initialization data"; + case AV_PKT_DATA_ENCRYPTION_INFO: return "Encryption info"; + case AV_PKT_DATA_AFD: return "Active Format Description data"; } return NULL; } @@ -516,11 +522,12 @@ fail: int av_packet_unpack_dictionary(const uint8_t *data, int size, AVDictionary **dict) { - const uint8_t *end = data + size; + const uint8_t *end; int ret = 0; if (!dict || !data || !size) return ret; + end = data + size; if (size && end[-1]) return AVERROR_INVALIDDATA; while (data < end) { @@ -574,10 +581,10 @@ FF_ENABLE_DEPRECATION_WARNINGS dst->side_data = NULL; dst->side_data_elems = 0; for (i = 0; i < src->side_data_elems; i++) { - enum AVPacketSideDataType type = src->side_data[i].type; - int size = src->side_data[i].size; - uint8_t *src_data = src->side_data[i].data; - uint8_t *dst_data = av_packet_new_side_data(dst, type, size); + enum AVPacketSideDataType type = src->side_data[i].type; + int size = src->side_data[i].size; + uint8_t *src_data = src->side_data[i].data; + uint8_t *dst_data = av_packet_new_side_data(dst, type, size); if (!dst_data) { av_packet_free_side_data(dst); @@ -610,6 +617,7 @@ int av_packet_ref(AVPacket *dst, const AVPacket *src) ret = packet_alloc(&dst->buf, src->size); if (ret < 0) goto fail; + av_assert1(!src->size || src->data); if (src->size) memcpy(dst->buf->data, src->data, src->size); @@ -662,6 +670,7 @@ int av_packet_make_refcounted(AVPacket *pkt) ret = packet_alloc(&pkt->buf, pkt->size); if (ret < 0) return ret; + av_assert1(!pkt->size || pkt->data); if (pkt->size) memcpy(pkt->buf->data, pkt->data, pkt->size); @@ -681,6 +690,7 @@ int av_packet_make_writable(AVPacket *pkt) ret = packet_alloc(&buf, pkt->size); if (ret < 0) return ret; + av_assert1(!pkt->size || pkt->data); if (pkt->size) memcpy(buf->data, pkt->data, pkt->size); diff --git a/libavcodec/avs2_parser.c b/libavcodec/avs2_parser.c new file mode 100644 index 000000000..1c9b3423f --- /dev/null +++ b/libavcodec/avs2_parser.c @@ -0,0 +1,95 @@ +/* + * AVS2-P2/IEEE1857.4 video parser. + * Copyright (c) 2018 Huiwen Ren + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "parser.h" + +#define SLICE_MAX_START_CODE 0x000001af + +#define ISPIC(x) ((x) == 0xB3 || (x) == 0xB6) +#define ISUNIT(x) ((x) == 0xB0 || (x) == 0xB1 || (x) == 0xB2 || ISPIC(x)) + +static int avs2_find_frame_end(ParseContext *pc, const uint8_t *buf, int buf_size) +{ + int pic_found = pc->frame_start_found; + uint32_t state = pc->state; + int cur = 0; + + if (!pic_found) { + for (; cur < buf_size; ++cur) { + state = (state<<8) | buf[cur]; + if (ISUNIT(buf[cur])){ + ++cur; + pic_found = 1; + break; + } + } + } + + if (pic_found) { + if (!buf_size) + return END_NOT_FOUND; + for (; cur < buf_size; ++cur) { + state = (state << 8) | buf[cur]; + if ((state & 0xFFFFFF00) == 0x100 && state > SLICE_MAX_START_CODE) { + pc->frame_start_found = 0; + pc->state = -1; + return cur - 3; + } + } + } + + pc->frame_start_found = pic_found; + pc->state = state; + + return END_NOT_FOUND; +} + +static int avs2_parse(AVCodecParserContext *s, AVCodecContext *avctx, + const uint8_t **poutbuf, int *poutbuf_size, + const uint8_t *buf, int buf_size) +{ + ParseContext *pc = s->priv_data; + int next; + + if (s->flags & PARSER_FLAG_COMPLETE_FRAMES) { + next = buf_size; + } else { + next = avs2_find_frame_end(pc, buf, buf_size); + if (ff_combine_frame(pc, next, &buf, &buf_size) < 0) { + *poutbuf = NULL; + *poutbuf_size = 0; + return buf_size; + } + } + + *poutbuf = buf; + *poutbuf_size = buf_size; + + return next; +} + +AVCodecParser ff_avs2_parser = { + .codec_ids = { AV_CODEC_ID_AVS2 }, + .priv_data_size = sizeof(ParseContext), + .parser_parse = avs2_parse, + .parser_close = ff_parse_close, + .split = ff_mpeg4video_split, +}; diff --git a/libavcodec/bfi.c b/libavcodec/bfi.c index 233a1d27a..a4cb00205 100644 --- a/libavcodec/bfi.c +++ b/libavcodec/bfi.c @@ -71,7 +71,7 @@ static int bfi_decode_frame(AVCodecContext *avctx, void *data, frame->key_frame = 1; /* Setting the palette */ if (avctx->extradata_size > 768) { - av_log(NULL, AV_LOG_ERROR, "Palette is too large.\n"); + av_log(avctx, AV_LOG_ERROR, "Palette is too large.\n"); return AVERROR_INVALIDDATA; } pal = (uint32_t *)frame->data[1]; diff --git a/libavcodec/bgmc.c b/libavcodec/bgmc.c index 1a6817b73..2d59aa37a 100644 --- a/libavcodec/bgmc.c +++ b/libavcodec/bgmc.c @@ -485,12 +485,17 @@ av_cold void ff_bgmc_end(uint8_t **cf_lut, int **cf_lut_status) /** Initialize decoding and reads the first value */ -void ff_bgmc_decode_init(GetBitContext *gb, unsigned int *h, +int ff_bgmc_decode_init(GetBitContext *gb, unsigned int *h, unsigned int *l, unsigned int *v) { + if (get_bits_left(gb) < VALUE_BITS) + return AVERROR_INVALIDDATA; + *h = TOP_VALUE; *l = 0; *v = get_bits_long(gb, VALUE_BITS); + + return 0; } diff --git a/libavcodec/bgmc.h b/libavcodec/bgmc.h index 4893736af..466df31a2 100644 --- a/libavcodec/bgmc.h +++ b/libavcodec/bgmc.h @@ -40,7 +40,7 @@ int ff_bgmc_init(AVCodecContext *avctx, uint8_t **cf_lut, int **cf_lut_status); void ff_bgmc_end(uint8_t **cf_lut, int **cf_lut_status); -void ff_bgmc_decode_init(GetBitContext *gb, +int ff_bgmc_decode_init(GetBitContext *gb, unsigned int *h, unsigned int *l, unsigned int *v); diff --git a/libavcodec/bink.c b/libavcodec/bink.c index c4cf617a8..d18c0ceae 100644 --- a/libavcodec/bink.c +++ b/libavcodec/bink.c @@ -371,11 +371,19 @@ static const uint8_t bink_rlelens[4] = { 4, 8, 12, 32 }; static int read_block_types(AVCodecContext *avctx, GetBitContext *gb, Bundle *b) { + BinkContext * const c = avctx->priv_data; int t, v; int last = 0; const uint8_t *dec_end; CHECK_READ_VAL(gb, b, t); + if (c->version == 'k') { + t ^= 0xBBu; + if (t == 0) { + b->cur_dec = NULL; + return 0; + } + } dec_end = b->cur_dec + t; if (dec_end > b->data_end) { av_log(avctx, AV_LOG_ERROR, "Too many block type values\n"); @@ -601,7 +609,7 @@ static inline int binkb_get_value(BinkContext *c, int bundle_num) * @param quant_matrices quantization matrices * @return 0 for success, negative value in other cases */ -static int read_dct_coeffs(GetBitContext *gb, int32_t block[64], +static int read_dct_coeffs(BinkContext *c, GetBitContext *gb, int32_t block[64], const uint8_t *scan, int *coef_count_, int coef_idx[64], int q) { @@ -684,7 +692,7 @@ static int read_dct_coeffs(GetBitContext *gb, int32_t block[64], } else { quant_idx = q; if (quant_idx > 15U) { - av_log(NULL, AV_LOG_ERROR, "quant_index %d out of range\n", quant_idx); + av_log(c->avctx, AV_LOG_ERROR, "quant_index %d out of range\n", quant_idx); return AVERROR_INVALIDDATA; } } @@ -694,15 +702,15 @@ static int read_dct_coeffs(GetBitContext *gb, int32_t block[64], return quant_idx; } -static void unquantize_dct_coeffs(int32_t block[64], const int32_t quant[64], +static void unquantize_dct_coeffs(int32_t block[64], const uint32_t quant[64], int coef_count, int coef_idx[64], const uint8_t *scan) { int i; - block[0] = (block[0] * quant[0]) >> 11; + block[0] = (int)(block[0] * quant[0]) >> 11; for (i = 0; i < coef_count; i++) { int idx = coef_idx[i]; - block[scan[idx]] = (block[scan[idx]] * quant[idx]) >> 11; + block[scan[idx]] = (int)(block[scan[idx]] * quant[idx]) >> 11; } } @@ -877,7 +885,7 @@ static int binkb_decode_plane(BinkContext *c, AVFrame *frame, GetBitContext *gb, memset(dctblock, 0, sizeof(*dctblock) * 64); dctblock[0] = binkb_get_value(c, BINKB_SRC_INTRA_DC); qp = binkb_get_value(c, BINKB_SRC_INTRA_Q); - if ((quant_idx = read_dct_coeffs(gb, dctblock, bink_scan, &coef_count, coef_idx, qp)) < 0) + if ((quant_idx = read_dct_coeffs(c, gb, dctblock, bink_scan, &coef_count, coef_idx, qp)) < 0) return quant_idx; unquantize_dct_coeffs(dctblock, binkb_intra_quant[quant_idx], coef_count, coef_idx, bink_scan); c->binkdsp.idct_put(dst, stride, dctblock); @@ -912,7 +920,7 @@ static int binkb_decode_plane(BinkContext *c, AVFrame *frame, GetBitContext *gb, memset(dctblock, 0, sizeof(*dctblock) * 64); dctblock[0] = binkb_get_value(c, BINKB_SRC_INTER_DC); qp = binkb_get_value(c, BINKB_SRC_INTER_Q); - if ((quant_idx = read_dct_coeffs(gb, dctblock, bink_scan, &coef_count, coef_idx, qp)) < 0) + if ((quant_idx = read_dct_coeffs(c, gb, dctblock, bink_scan, &coef_count, coef_idx, qp)) < 0) return quant_idx; unquantize_dct_coeffs(dctblock, binkb_inter_quant[quant_idx], coef_count, coef_idx, bink_scan); c->binkdsp.idct_add(dst, stride, dctblock); @@ -994,6 +1002,17 @@ static int bink_decode_plane(BinkContext *c, AVFrame *frame, GetBitContext *gb, int bw = is_chroma ? (c->avctx->width + 15) >> 4 : (c->avctx->width + 7) >> 3; int bh = is_chroma ? (c->avctx->height + 15) >> 4 : (c->avctx->height + 7) >> 3; int width = c->avctx->width >> is_chroma; + int height = c->avctx->height >> is_chroma; + + if (c->version == 'k' && get_bits1(gb)) { + int fill = get_bits(gb, 8); + + dst = frame->data[plane_idx]; + + for (i = 0; i < height; i++) + memset(dst + i * stride, fill, width); + goto end; + } init_lengths(c, FFMAX(width, 8), bw); for (i = 0; i < BINK_NB_SRC; i++) @@ -1027,8 +1046,6 @@ static int bink_decode_plane(BinkContext *c, AVFrame *frame, GetBitContext *gb, if ((ret = read_runs(c->avctx, gb, &c->bundle[BINK_SRC_RUN])) < 0) return ret; - if (by == bh) - break; dst = frame->data[plane_idx] + 8*by*stride; prev = (c->last->data[plane_idx] ? c->last->data[plane_idx] : frame->data[plane_idx]) + 8*by*stride; @@ -1074,7 +1091,7 @@ static int bink_decode_plane(BinkContext *c, AVFrame *frame, GetBitContext *gb, case INTRA_BLOCK: memset(dctblock, 0, sizeof(*dctblock) * 64); dctblock[0] = get_value(c, BINK_SRC_INTRA_DC); - if ((quant_idx = read_dct_coeffs(gb, dctblock, bink_scan, &coef_count, coef_idx, -1)) < 0) + if ((quant_idx = read_dct_coeffs(c, gb, dctblock, bink_scan, &coef_count, coef_idx, -1)) < 0) return quant_idx; unquantize_dct_coeffs(dctblock, bink_intra_quant[quant_idx], coef_count, coef_idx, bink_scan); c->binkdsp.idct_put(ublock, 8, dctblock); @@ -1149,7 +1166,7 @@ static int bink_decode_plane(BinkContext *c, AVFrame *frame, GetBitContext *gb, case INTRA_BLOCK: memset(dctblock, 0, sizeof(*dctblock) * 64); dctblock[0] = get_value(c, BINK_SRC_INTRA_DC); - if ((quant_idx = read_dct_coeffs(gb, dctblock, bink_scan, &coef_count, coef_idx, -1)) < 0) + if ((quant_idx = read_dct_coeffs(c, gb, dctblock, bink_scan, &coef_count, coef_idx, -1)) < 0) return quant_idx; unquantize_dct_coeffs(dctblock, bink_intra_quant[quant_idx], coef_count, coef_idx, bink_scan); c->binkdsp.idct_put(dst, stride, dctblock); @@ -1165,7 +1182,7 @@ static int bink_decode_plane(BinkContext *c, AVFrame *frame, GetBitContext *gb, return ret; memset(dctblock, 0, sizeof(*dctblock) * 64); dctblock[0] = get_value(c, BINK_SRC_INTER_DC); - if ((quant_idx = read_dct_coeffs(gb, dctblock, bink_scan, &coef_count, coef_idx, -1)) < 0) + if ((quant_idx = read_dct_coeffs(c, gb, dctblock, bink_scan, &coef_count, coef_idx, -1)) < 0) return quant_idx; unquantize_dct_coeffs(dctblock, bink_inter_quant[quant_idx], coef_count, coef_idx, bink_scan); c->binkdsp.idct_add(dst, stride, dctblock); @@ -1190,6 +1207,8 @@ static int bink_decode_plane(BinkContext *c, AVFrame *frame, GetBitContext *gb, } } } + +end: if (get_bits_count(gb) & 0x1F) //next plane data starts at 32-bit boundary skip_bits_long(gb, 32 - (get_bits_count(gb) & 0x1F)); @@ -1314,14 +1333,15 @@ static av_cold int decode_init(AVCodecContext *avctx) } c->avctx = avctx; + if ((ret = av_image_check_size(avctx->width, avctx->height, 0, avctx)) < 0) + return ret; + c->last = av_frame_alloc(); if (!c->last) return AVERROR(ENOMEM); - if ((ret = av_image_check_size(avctx->width, avctx->height, 0, avctx)) < 0) - return ret; - avctx->pix_fmt = c->has_alpha ? AV_PIX_FMT_YUVA420P : AV_PIX_FMT_YUV420P; + avctx->color_range = c->version == 'k' ? AVCOL_RANGE_JPEG : AVCOL_RANGE_MPEG; ff_blockdsp_init(&c->bdsp, avctx); ff_hpeldsp_init(&c->hdsp, avctx->flags); diff --git a/libavcodec/binkaudio.c b/libavcodec/binkaudio.c index e0f3d14ee..96cf968c6 100644 --- a/libavcodec/binkaudio.c +++ b/libavcodec/binkaudio.c @@ -139,7 +139,7 @@ static av_cold int decode_init(AVCodecContext *avctx) else if (CONFIG_BINKAUDIO_DCT_DECODER) ff_dct_init(&s->trans.dct, frame_len_bits, DCT_III); else - return -1; + av_assert0(0); s->pkt = av_packet_alloc(); if (!s->pkt) diff --git a/libavcodec/binkdsp.c b/libavcodec/binkdsp.c index 9d70e2326..a357d3167 100644 --- a/libavcodec/binkdsp.c +++ b/libavcodec/binkdsp.c @@ -33,20 +33,22 @@ #define A3 3784 #define A4 -5352 +#define MUL(X,Y) ((int)((unsigned)(X) * (Y)) >> 11) + #define IDCT_TRANSFORM(dest,s0,s1,s2,s3,s4,s5,s6,s7,d0,d1,d2,d3,d4,d5,d6,d7,munge,src) {\ const int a0 = (src)[s0] + (src)[s4]; \ const int a1 = (src)[s0] - (src)[s4]; \ const int a2 = (src)[s2] + (src)[s6]; \ - const int a3 = (A1*((src)[s2] - (src)[s6])) >> 11; \ + const int a3 = MUL(A1, (src)[s2] - (src)[s6]); \ const int a4 = (src)[s5] + (src)[s3]; \ const int a5 = (src)[s5] - (src)[s3]; \ const int a6 = (src)[s1] + (src)[s7]; \ const int a7 = (src)[s1] - (src)[s7]; \ const int b0 = a4 + a6; \ - const int b1 = (A3*(a5 + a7)) >> 11; \ - const int b2 = ((A4*a5) >> 11) - b0 + b1; \ - const int b3 = (A1*(a6 - a4) >> 11) - b2; \ - const int b4 = ((A2*a7) >> 11) + b3 - b1; \ + const int b1 = MUL(A3, a5 + a7); \ + const int b2 = MUL(A4, a5) - b0 + b1; \ + const int b3 = MUL(A1, a6 - a4) - b2; \ + const int b4 = MUL(A2, a7) + b3 - b1; \ (dest)[d0] = munge(a0+a2 +b0); \ (dest)[d1] = munge(a1+a3-a2+b2); \ (dest)[d2] = munge(a1-a3+a2+b3); \ diff --git a/libavcodec/bintext.c b/libavcodec/bintext.c index d96731767..1aeed21f5 100644 --- a/libavcodec/bintext.c +++ b/libavcodec/bintext.c @@ -63,6 +63,10 @@ static av_cold int decode_init(AVCodecContext *avctx) av_log(avctx, AV_LOG_ERROR, "not enough extradata\n"); return AVERROR_INVALIDDATA; } + if (!s->font_height) { + av_log(avctx, AV_LOG_ERROR, "invalid font height\n"); + return AVERROR_INVALIDDATA; + } } else { s->font_height = 8; s->flags = 0; @@ -93,13 +97,10 @@ static av_cold int decode_init(AVCodecContext *avctx) break; } } - if (avctx->width < FONT_WIDTH || avctx->height < s->font_height) + if (avctx->width < FONT_WIDTH || avctx->height < s->font_height) { + av_log(avctx, AV_LOG_ERROR, "Resolution too small for font.\n"); return AVERROR_INVALIDDATA; - - - s->frame = av_frame_alloc(); - if (!s->frame) - return AVERROR(ENOMEM); + } return 0; } @@ -146,8 +147,12 @@ static int decode_frame(AVCodecContext *avctx, const uint8_t *buf_end = buf+buf_size; int ret; + if ((avctx->width / FONT_WIDTH) * (avctx->height / s->font_height) / 256 > buf_size) + return AVERROR_INVALIDDATA; + + s->frame = data; s->x = s->y = 0; - if ((ret = ff_reget_buffer(avctx, s->frame)) < 0) + if ((ret = ff_get_buffer(avctx, s->frame, 0)) < 0) return ret; s->frame->pict_type = AV_PICTURE_TYPE_I; s->frame->palette_has_changed = 1; @@ -205,21 +210,10 @@ static int decode_frame(AVCodecContext *avctx, } } - if ((ret = av_frame_ref(data, s->frame)) < 0) - return ret; *got_frame = 1; return buf_size; } -static av_cold int decode_end(AVCodecContext *avctx) -{ - XbinContext *s = avctx->priv_data; - - av_frame_free(&s->frame); - - return 0; -} - #if CONFIG_BINTEXT_DECODER AVCodec ff_bintext_decoder = { .name = "bintext", @@ -228,7 +222,6 @@ AVCodec ff_bintext_decoder = { .id = AV_CODEC_ID_BINTEXT, .priv_data_size = sizeof(XbinContext), .init = decode_init, - .close = decode_end, .decode = decode_frame, .capabilities = AV_CODEC_CAP_DR1, }; @@ -241,7 +234,6 @@ AVCodec ff_xbin_decoder = { .id = AV_CODEC_ID_XBIN, .priv_data_size = sizeof(XbinContext), .init = decode_init, - .close = decode_end, .decode = decode_frame, .capabilities = AV_CODEC_CAP_DR1, }; @@ -254,7 +246,6 @@ AVCodec ff_idf_decoder = { .id = AV_CODEC_ID_IDF, .priv_data_size = sizeof(XbinContext), .init = decode_init, - .close = decode_end, .decode = decode_frame, .capabilities = AV_CODEC_CAP_DR1, }; diff --git a/libavcodec/bitstream.c b/libavcodec/bitstream.c index ed528fe4a..be8a0f634 100644 --- a/libavcodec/bitstream.c +++ b/libavcodec/bitstream.c @@ -164,7 +164,7 @@ static int build_table(VLC *vlc, int table_nb_bits, int nb_codes, table_size = 1 << table_nb_bits; if (table_nb_bits > 30) - return -1; + return AVERROR(EINVAL); table_index = alloc_table(vlc, table_size, flags & INIT_VLC_USE_NEW_STATIC); ff_dlog(NULL, "new table index=%d size=%d\n", table_index, table_size); if (table_index < 0) @@ -188,8 +188,9 @@ static int build_table(VLC *vlc, int table_nb_bits, int nb_codes, } for (k = 0; k < nb; k++) { int bits = table[j][1]; + int oldsym = table[j][0]; ff_dlog(NULL, "%4x: code=%d n=%d\n", j, i, n); - if (bits != 0 && bits != n) { + if ((bits || oldsym) && (bits != n || oldsym != symbol)) { av_log(NULL, AV_LOG_ERROR, "incorrect codes\n"); return AVERROR_INVALIDDATA; } @@ -226,6 +227,10 @@ static int build_table(VLC *vlc, int table_nb_bits, int nb_codes, /* note: realloc has been done, so reload tables */ table = (volatile VLC_TYPE (*)[2])&vlc->table[table_index]; table[j][0] = index; //code + if (table[j][0] != index) { + avpriv_request_sample(NULL, "strange codes"); + return AVERROR_PATCHWELCOME; + } i = k-1; } } @@ -306,7 +311,7 @@ int ff_init_vlc_sparse(VLC *vlc_arg, int nb_bits, int nb_codes, av_log(NULL, AV_LOG_ERROR, "Too long VLC (%d) in init_vlc\n", buf[j].bits);\ if (!(flags & INIT_VLC_USE_NEW_STATIC)) \ av_free(buf); \ - return -1; \ + return AVERROR(EINVAL); \ } \ GET_DATA(buf[j].code, codes, i, codes_wrap, codes_size); \ if (buf[j].code >= (1LL<internal->eof = 0; + + av_packet_unref(ctx->internal->buffer_pkt); + + if (ctx->filter->flush) + ctx->filter->flush(ctx); +} + int av_bsf_send_packet(AVBSFContext *ctx, AVPacket *pkt) { int ret; @@ -340,6 +350,15 @@ static int bsf_list_filter(AVBSFContext *bsf, AVPacket *out) return ret; } +static void bsf_list_flush(AVBSFContext *bsf) +{ + BSFListContext *lst = bsf->priv_data; + + for (int i = 0; i < lst->nb_bsfs; i++) + av_bsf_flush(lst->bsfs[i]); + lst->idx = lst->flushed_idx = 0; +} + static void bsf_list_close(AVBSFContext *bsf) { BSFListContext *lst = bsf->priv_data; @@ -388,6 +407,7 @@ const AVBitStreamFilter ff_list_bsf = { .priv_class = &bsf_list_class, .init = bsf_list_init, .filter = bsf_list_filter, + .flush = bsf_list_flush, .close = bsf_list_close, }; diff --git a/libavcodec/cabac_functions.h b/libavcodec/cabac_functions.h index fe72a826c..bb2b4210b 100644 --- a/libavcodec/cabac_functions.h +++ b/libavcodec/cabac_functions.h @@ -45,6 +45,9 @@ #if ARCH_X86 # include "x86/cabac.h" #endif +#if ARCH_MIPS +# include "mips/cabac.h" +#endif static const uint8_t * const ff_h264_norm_shift = ff_h264_cabac_tables + H264_NORM_SHIFT_OFFSET; static const uint8_t * const ff_h264_lps_range = ff_h264_cabac_tables + H264_LPS_RANGE_OFFSET; diff --git a/libavcodec/cavsdec.c b/libavcodec/cavsdec.c index 5f3b35451..1c4f71824 100644 --- a/libavcodec/cavsdec.c +++ b/libavcodec/cavsdec.c @@ -1215,6 +1215,7 @@ static int cavs_decode_frame(AVCodecContext *avctx, void *data, int *got_frame, int input_size, ret; const uint8_t *buf_end; const uint8_t *buf_ptr; + int frame_start = 0; if (buf_size == 0) { if (!h->low_delay && h->DPB[0].f->data[0]) { @@ -1248,6 +1249,9 @@ static int cavs_decode_frame(AVCodecContext *avctx, void *data, int *got_frame, h->got_keyframe = 1; } case PIC_PB_START_CODE: + if (frame_start > 1) + return AVERROR_INVALIDDATA; + frame_start ++; if (*got_frame) av_frame_unref(data); *got_frame = 0; diff --git a/libavcodec/cbs.c b/libavcodec/cbs.c index 897e0bb28..235041650 100644 --- a/libavcodec/cbs.c +++ b/libavcodec/cbs.c @@ -29,26 +29,44 @@ static const CodedBitstreamType *cbs_type_table[] = { +#if CONFIG_CBS_AV1 + &ff_cbs_type_av1, +#endif #if CONFIG_CBS_H264 &ff_cbs_type_h264, #endif #if CONFIG_CBS_H265 &ff_cbs_type_h265, #endif +#if CONFIG_CBS_JPEG + &ff_cbs_type_jpeg, +#endif #if CONFIG_CBS_MPEG2 &ff_cbs_type_mpeg2, #endif +#if CONFIG_CBS_VP9 + &ff_cbs_type_vp9, +#endif }; const enum AVCodecID ff_cbs_all_codec_ids[] = { +#if CONFIG_CBS_AV1 + AV_CODEC_ID_AV1, +#endif #if CONFIG_CBS_H264 AV_CODEC_ID_H264, #endif #if CONFIG_CBS_H265 AV_CODEC_ID_H265, #endif +#if CONFIG_CBS_JPEG + AV_CODEC_ID_MJPEG, +#endif #if CONFIG_CBS_MPEG2 AV_CODEC_ID_MPEG2VIDEO, +#endif +#if CONFIG_CBS_VP9 + AV_CODEC_ID_VP9, #endif AV_CODEC_ID_NONE }; @@ -118,14 +136,13 @@ static void cbs_unit_uninit(CodedBitstreamContext *ctx, unit->data_bit_padding = 0; } -void ff_cbs_fragment_uninit(CodedBitstreamContext *ctx, - CodedBitstreamFragment *frag) +void ff_cbs_fragment_reset(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag) { int i; for (i = 0; i < frag->nb_units; i++) cbs_unit_uninit(ctx, &frag->units[i]); - av_freep(&frag->units); frag->nb_units = 0; av_buffer_unref(&frag->data_ref); @@ -134,32 +151,45 @@ void ff_cbs_fragment_uninit(CodedBitstreamContext *ctx, frag->data_bit_padding = 0; } +void ff_cbs_fragment_free(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag) +{ + ff_cbs_fragment_reset(ctx, frag); + + av_freep(&frag->units); + frag->nb_units_allocated = 0; +} + static int cbs_read_fragment_content(CodedBitstreamContext *ctx, CodedBitstreamFragment *frag) { int err, i, j; for (i = 0; i < frag->nb_units; i++) { + CodedBitstreamUnit *unit = &frag->units[i]; + if (ctx->decompose_unit_types) { for (j = 0; j < ctx->nb_decompose_unit_types; j++) { - if (ctx->decompose_unit_types[j] == frag->units[i].type) + if (ctx->decompose_unit_types[j] == unit->type) break; } if (j >= ctx->nb_decompose_unit_types) continue; } - av_buffer_unref(&frag->units[i].content_ref); - frag->units[i].content = NULL; + av_buffer_unref(&unit->content_ref); + unit->content = NULL; - err = ctx->codec->read_unit(ctx, &frag->units[i]); + av_assert0(unit->data && unit->data_ref); + + err = ctx->codec->read_unit(ctx, unit); if (err == AVERROR(ENOSYS)) { av_log(ctx->log_ctx, AV_LOG_VERBOSE, "Decomposition unimplemented for unit %d " - "(type %"PRIu32").\n", i, frag->units[i].type); + "(type %"PRIu32").\n", i, unit->type); } else if (err < 0) { av_log(ctx->log_ctx, AV_LOG_ERROR, "Failed to read unit %d " - "(type %"PRIu32").\n", i, frag->units[i].type); + "(type %"PRIu32").\n", i, unit->type); return err; } } @@ -167,27 +197,6 @@ static int cbs_read_fragment_content(CodedBitstreamContext *ctx, return 0; } -int ff_cbs_read_extradata(CodedBitstreamContext *ctx, - CodedBitstreamFragment *frag, - const AVCodecParameters *par) -{ - int err; - - memset(frag, 0, sizeof(*frag)); - - frag->data = par->extradata; - frag->data_size = par->extradata_size; - - err = ctx->codec->split_fragment(ctx, frag, 1); - if (err < 0) - return err; - - frag->data = NULL; - frag->data_size = 0; - - return cbs_read_fragment_content(ctx, frag); -} - static int cbs_fill_fragment_data(CodedBitstreamContext *ctx, CodedBitstreamFragment *frag, const uint8_t *data, size_t size) @@ -209,14 +218,30 @@ static int cbs_fill_fragment_data(CodedBitstreamContext *ctx, return 0; } +int ff_cbs_read_extradata(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag, + const AVCodecParameters *par) +{ + int err; + + err = cbs_fill_fragment_data(ctx, frag, par->extradata, + par->extradata_size); + if (err < 0) + return err; + + err = ctx->codec->split_fragment(ctx, frag, 1); + if (err < 0) + return err; + + return cbs_read_fragment_content(ctx, frag); +} + int ff_cbs_read_packet(CodedBitstreamContext *ctx, CodedBitstreamFragment *frag, const AVPacket *pkt) { int err; - memset(frag, 0, sizeof(*frag)); - if (pkt->buf) { frag->data_ref = av_buffer_ref(pkt->buf); if (!frag->data_ref) @@ -244,8 +269,6 @@ int ff_cbs_read(CodedBitstreamContext *ctx, { int err; - memset(frag, 0, sizeof(*frag)); - err = cbs_fill_fragment_data(ctx, frag, data, size); if (err < 0) return err; @@ -278,6 +301,7 @@ int ff_cbs_write_fragment_data(CodedBitstreamContext *ctx, "(type %"PRIu32").\n", i, unit->type); return err; } + av_assert0(unit->data && unit->data_ref); } av_buffer_unref(&frag->data_ref); @@ -288,6 +312,7 @@ int ff_cbs_write_fragment_data(CodedBitstreamContext *ctx, av_log(ctx->log_ctx, AV_LOG_ERROR, "Failed to assemble fragment.\n"); return err; } + av_assert0(frag->data && frag->data_ref); return 0; } @@ -328,12 +353,12 @@ int ff_cbs_write_packet(CodedBitstreamContext *ctx, if (err < 0) return err; - av_assert0(frag->data_ref); buf = av_buffer_ref(frag->data_ref); if (!buf) return AVERROR(ENOMEM); - av_init_packet(pkt); + av_buffer_unref(&pkt->buf); + pkt->buf = buf; pkt->data = frag->data; pkt->size = frag->data_size; @@ -352,17 +377,43 @@ void ff_cbs_trace_header(CodedBitstreamContext *ctx, } void ff_cbs_trace_syntax_element(CodedBitstreamContext *ctx, int position, - const char *name, const char *bits, - int64_t value) + const char *str, const int *subscripts, + const char *bits, int64_t value) { + char name[256]; size_t name_len, bits_len; - int pad; + int pad, subs, i, j, k, n; if (!ctx->trace_enable) return; av_assert0(value >= INT_MIN && value <= UINT32_MAX); + subs = subscripts ? subscripts[0] : 0; + n = 0; + for (i = j = 0; str[i];) { + if (str[i] == '[') { + if (n < subs) { + ++n; + k = snprintf(name + j, sizeof(name) - j, "[%d", subscripts[n]); + av_assert0(k > 0 && j + k < sizeof(name)); + j += k; + for (++i; str[i] && str[i] != ']'; i++); + av_assert0(str[i] == ']'); + } else { + while (str[i] && str[i] != ']') + name[j++] = str[i++]; + av_assert0(str[i] == ']'); + } + } else { + av_assert0(j + 1 < sizeof(name)); + name[j++] = str[i++]; + } + } + av_assert0(j + 1 < sizeof(name)); + name[j] = 0; + av_assert0(n == subs); + name_len = strlen(name); bits_len = strlen(bits); @@ -376,7 +427,8 @@ void ff_cbs_trace_syntax_element(CodedBitstreamContext *ctx, int position, } int ff_cbs_read_unsigned(CodedBitstreamContext *ctx, GetBitContext *gbc, - int width, const char *name, uint32_t *write_to, + int width, const char *name, + const int *subscripts, uint32_t *write_to, uint32_t range_min, uint32_t range_max) { uint32_t value; @@ -402,7 +454,8 @@ int ff_cbs_read_unsigned(CodedBitstreamContext *ctx, GetBitContext *gbc, bits[i] = value >> (width - i - 1) & 1 ? '1' : '0'; bits[i] = 0; - ff_cbs_trace_syntax_element(ctx, position, name, bits, value); + ff_cbs_trace_syntax_element(ctx, position, name, subscripts, + bits, value); } if (value < range_min || value > range_max) { @@ -417,7 +470,8 @@ int ff_cbs_read_unsigned(CodedBitstreamContext *ctx, GetBitContext *gbc, } int ff_cbs_write_unsigned(CodedBitstreamContext *ctx, PutBitContext *pbc, - int width, const char *name, uint32_t value, + int width, const char *name, + const int *subscripts, uint32_t value, uint32_t range_min, uint32_t range_max) { av_assert0(width > 0 && width <= 32); @@ -439,7 +493,8 @@ int ff_cbs_write_unsigned(CodedBitstreamContext *ctx, PutBitContext *pbc, bits[i] = value >> (width - i - 1) & 1 ? '1' : '0'; bits[i] = 0; - ff_cbs_trace_syntax_element(ctx, put_bits_count(pbc), name, bits, value); + ff_cbs_trace_syntax_element(ctx, put_bits_count(pbc), + name, subscripts, bits, value); } if (width < 32) @@ -450,6 +505,85 @@ int ff_cbs_write_unsigned(CodedBitstreamContext *ctx, PutBitContext *pbc, return 0; } +int ff_cbs_read_signed(CodedBitstreamContext *ctx, GetBitContext *gbc, + int width, const char *name, + const int *subscripts, int32_t *write_to, + int32_t range_min, int32_t range_max) +{ + int32_t value; + int position; + + av_assert0(width > 0 && width <= 32); + + if (get_bits_left(gbc) < width) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid value at " + "%s: bitstream ended.\n", name); + return AVERROR_INVALIDDATA; + } + + if (ctx->trace_enable) + position = get_bits_count(gbc); + + value = get_sbits_long(gbc, width); + + if (ctx->trace_enable) { + char bits[33]; + int i; + for (i = 0; i < width; i++) + bits[i] = value & (1U << (width - i - 1)) ? '1' : '0'; + bits[i] = 0; + + ff_cbs_trace_syntax_element(ctx, position, name, subscripts, + bits, value); + } + + if (value < range_min || value > range_max) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "%s out of range: " + "%"PRId32", but must be in [%"PRId32",%"PRId32"].\n", + name, value, range_min, range_max); + return AVERROR_INVALIDDATA; + } + + *write_to = value; + return 0; +} + +int ff_cbs_write_signed(CodedBitstreamContext *ctx, PutBitContext *pbc, + int width, const char *name, + const int *subscripts, int32_t value, + int32_t range_min, int32_t range_max) +{ + av_assert0(width > 0 && width <= 32); + + if (value < range_min || value > range_max) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "%s out of range: " + "%"PRId32", but must be in [%"PRId32",%"PRId32"].\n", + name, value, range_min, range_max); + return AVERROR_INVALIDDATA; + } + + if (put_bits_left(pbc) < width) + return AVERROR(ENOSPC); + + if (ctx->trace_enable) { + char bits[33]; + int i; + for (i = 0; i < width; i++) + bits[i] = value & (1U << (width - i - 1)) ? '1' : '0'; + bits[i] = 0; + + ff_cbs_trace_syntax_element(ctx, put_bits_count(pbc), + name, subscripts, bits, value); + } + + if (width < 32) + put_sbits(pbc, width, value); + else + put_bits32(pbc, value); + + return 0; +} + int ff_cbs_alloc_unit_content(CodedBitstreamContext *ctx, CodedBitstreamUnit *unit, @@ -496,20 +630,34 @@ static int cbs_insert_unit(CodedBitstreamContext *ctx, { CodedBitstreamUnit *units; - units = av_malloc_array(frag->nb_units + 1, sizeof(*units)); - if (!units) - return AVERROR(ENOMEM); + if (frag->nb_units < frag->nb_units_allocated) { + units = frag->units; - if (position > 0) - memcpy(units, frag->units, position * sizeof(*units)); - if (position < frag->nb_units) - memcpy(units + position + 1, frag->units + position, - (frag->nb_units - position) * sizeof(*units)); + if (position < frag->nb_units) + memmove(units + position + 1, units + position, + (frag->nb_units - position) * sizeof(*units)); + } else { + units = av_malloc_array(frag->nb_units + 1, sizeof(*units)); + if (!units) + return AVERROR(ENOMEM); + + ++frag->nb_units_allocated; + + if (position > 0) + memcpy(units, frag->units, position * sizeof(*units)); + + if (position < frag->nb_units) + memcpy(units + position + 1, frag->units + position, + (frag->nb_units - position) * sizeof(*units)); + } memset(units + position, 0, sizeof(*units)); - av_freep(&frag->units); - frag->units = units; + if (units != frag->units) { + av_free(frag->units); + frag->units = units; + } + ++frag->nb_units; return 0; @@ -589,27 +737,19 @@ int ff_cbs_insert_unit_data(CodedBitstreamContext *ctx, return 0; } -int ff_cbs_delete_unit(CodedBitstreamContext *ctx, - CodedBitstreamFragment *frag, - int position) +void ff_cbs_delete_unit(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag, + int position) { - if (position < 0 || position >= frag->nb_units) - return AVERROR(EINVAL); + av_assert0(0 <= position && position < frag->nb_units + && "Unit to be deleted not in fragment."); cbs_unit_uninit(ctx, &frag->units[position]); --frag->nb_units; - if (frag->nb_units == 0) { - av_freep(&frag->units); - - } else { + if (frag->nb_units > 0) memmove(frag->units + position, frag->units + position + 1, (frag->nb_units - position) * sizeof(*frag->units)); - - // Don't bother reallocating the unit array. - } - - return 0; } diff --git a/libavcodec/cbs.h b/libavcodec/cbs.h index 402eb39e0..fe57e7b2a 100644 --- a/libavcodec/cbs.h +++ b/libavcodec/cbs.h @@ -48,6 +48,7 @@ struct CodedBitstreamType; * H.264 / AVC: nal_unit_type * H.265 / HEVC: nal_unit_type * MPEG-2: start code value (without prefix) + * VP9: unused, set to zero (every unit is a frame) */ typedef uint32_t CodedBitstreamUnitType; @@ -84,8 +85,9 @@ typedef struct CodedBitstreamUnit { */ size_t data_bit_padding; /** - * If data is reference counted, a reference to the buffer containing - * data. Null if data is not reference counted. + * A reference to the buffer containing data. + * + * Must be set if data is not NULL. */ AVBufferRef *data_ref; @@ -130,8 +132,9 @@ typedef struct CodedBitstreamFragment { */ size_t data_bit_padding; /** - * If data is reference counted, a reference to the buffer containing - * data. Null if data is not reference counted. + * A reference to the buffer containing data. + * + * Must be set if data is not NULL. */ AVBufferRef *data_ref; @@ -142,10 +145,19 @@ typedef struct CodedBitstreamFragment { * and has not been decomposed. */ int nb_units; + /** - * Pointer to an array of units of length nb_units. + * Number of allocated units. * - * Must be NULL if nb_units is zero. + * Must always be >= nb_units; designed for internal use by cbs. + */ + int nb_units_allocated; + + /** + * Pointer to an array of units of length nb_units_allocated. + * Only the first nb_units are valid. + * + * Must be NULL if nb_units_allocated is zero. */ CodedBitstreamUnit *units; } CodedBitstreamFragment; @@ -228,6 +240,9 @@ void ff_cbs_close(CodedBitstreamContext **ctx); * This also updates the internal state, so will need to be called for * codecs with extradata to read parameter sets necessary for further * parsing even if the fragment itself is not desired. + * + * The fragment must have been zeroed or reset via ff_cbs_fragment_reset + * before use. */ int ff_cbs_read_extradata(CodedBitstreamContext *ctx, CodedBitstreamFragment *frag, @@ -240,6 +255,9 @@ int ff_cbs_read_extradata(CodedBitstreamContext *ctx, * This also updates the internal state of the coded bitstream context * with any persistent data from the fragment which may be required to * read following fragments (e.g. parameter sets). + * + * The fragment must have been zeroed or reset via ff_cbs_fragment_reset + * before use. */ int ff_cbs_read_packet(CodedBitstreamContext *ctx, CodedBitstreamFragment *frag, @@ -252,6 +270,9 @@ int ff_cbs_read_packet(CodedBitstreamContext *ctx, * This also updates the internal state of the coded bitstream context * with any persistent data from the fragment which may be required to * read following fragments (e.g. parameter sets). + * + * The fragment must have been zeroed or reset via ff_cbs_fragment_reset + * before use. */ int ff_cbs_read(CodedBitstreamContext *ctx, CodedBitstreamFragment *frag, @@ -276,7 +297,8 @@ int ff_cbs_write_fragment_data(CodedBitstreamContext *ctx, /** * Write the bitstream of a fragment to the extradata in codec parameters. * - * This replaces any existing extradata in the structure. + * Modifies context and fragment as ff_cbs_write_fragment_data does and + * replaces any existing extradata in the structure. */ int ff_cbs_write_extradata(CodedBitstreamContext *ctx, AVCodecParameters *par, @@ -284,6 +306,13 @@ int ff_cbs_write_extradata(CodedBitstreamContext *ctx, /** * Write the bitstream of a fragment to a packet. + * + * Modifies context and fragment as ff_cbs_write_fragment_data does. + * + * On success, the packet's buf is unreferenced and its buf, data and + * size fields are set to the corresponding values from the newly updated + * fragment; other fields are not touched. On failure, the packet is not + * touched at all. */ int ff_cbs_write_packet(CodedBitstreamContext *ctx, AVPacket *pkt, @@ -291,11 +320,18 @@ int ff_cbs_write_packet(CodedBitstreamContext *ctx, /** - * Free all allocated memory in a fragment. + * Free the units contained in a fragment as well as the fragment's + * own data buffer, but not the units array itself. */ -void ff_cbs_fragment_uninit(CodedBitstreamContext *ctx, +void ff_cbs_fragment_reset(CodedBitstreamContext *ctx, CodedBitstreamFragment *frag); +/** + * Free the units array of a fragment in addition to what + * ff_cbs_fragment_reset does. + */ +void ff_cbs_fragment_free(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag); /** * Allocate a new internal content buffer of the given size in the unit. @@ -344,10 +380,12 @@ int ff_cbs_insert_unit_data(CodedBitstreamContext *ctx, /** * Delete a unit from a fragment and free all memory it uses. + * + * Requires position to be >= 0 and < frag->nb_units. */ -int ff_cbs_delete_unit(CodedBitstreamContext *ctx, - CodedBitstreamFragment *frag, - int position); +void ff_cbs_delete_unit(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag, + int position); #endif /* AVCODEC_CBS_H */ diff --git a/libavcodec/cbs_av1.c b/libavcodec/cbs_av1.c new file mode 100644 index 000000000..eb6b80179 --- /dev/null +++ b/libavcodec/cbs_av1.c @@ -0,0 +1,1316 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/avassert.h" +#include "libavutil/pixfmt.h" + +#include "cbs.h" +#include "cbs_internal.h" +#include "cbs_av1.h" +#include "internal.h" + + +static int cbs_av1_read_uvlc(CodedBitstreamContext *ctx, GetBitContext *gbc, + const char *name, uint32_t *write_to, + uint32_t range_min, uint32_t range_max) +{ + uint32_t zeroes, bits_value, value; + int position; + + if (ctx->trace_enable) + position = get_bits_count(gbc); + + zeroes = 0; + while (1) { + if (get_bits_left(gbc) < 1) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid uvlc code at " + "%s: bitstream ended.\n", name); + return AVERROR_INVALIDDATA; + } + + if (get_bits1(gbc)) + break; + ++zeroes; + } + + if (zeroes >= 32) { + value = MAX_UINT_BITS(32); + } else { + if (get_bits_left(gbc) < zeroes) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid uvlc code at " + "%s: bitstream ended.\n", name); + return AVERROR_INVALIDDATA; + } + + bits_value = get_bits_long(gbc, zeroes); + value = bits_value + (UINT32_C(1) << zeroes) - 1; + } + + if (ctx->trace_enable) { + char bits[65]; + int i, j, k; + + if (zeroes >= 32) { + while (zeroes > 32) { + k = FFMIN(zeroes - 32, 32); + for (i = 0; i < k; i++) + bits[i] = '0'; + bits[i] = 0; + ff_cbs_trace_syntax_element(ctx, position, name, + NULL, bits, 0); + zeroes -= k; + position += k; + } + } + + for (i = 0; i < zeroes; i++) + bits[i] = '0'; + bits[i++] = '1'; + + if (zeroes < 32) { + for (j = 0; j < zeroes; j++) + bits[i++] = (bits_value >> (zeroes - j - 1) & 1) ? '1' : '0'; + } + + bits[i] = 0; + ff_cbs_trace_syntax_element(ctx, position, name, + NULL, bits, value); + } + + if (value < range_min || value > range_max) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "%s out of range: " + "%"PRIu32", but must be in [%"PRIu32",%"PRIu32"].\n", + name, value, range_min, range_max); + return AVERROR_INVALIDDATA; + } + + *write_to = value; + return 0; +} + +static int cbs_av1_write_uvlc(CodedBitstreamContext *ctx, PutBitContext *pbc, + const char *name, uint32_t value, + uint32_t range_min, uint32_t range_max) +{ + uint32_t v; + int position, zeroes; + + if (value < range_min || value > range_max) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "%s out of range: " + "%"PRIu32", but must be in [%"PRIu32",%"PRIu32"].\n", + name, value, range_min, range_max); + return AVERROR_INVALIDDATA; + } + + if (ctx->trace_enable) + position = put_bits_count(pbc); + + if (value == 0) { + zeroes = 0; + put_bits(pbc, 1, 1); + } else { + zeroes = av_log2(value + 1); + v = value - (1 << zeroes) + 1; + put_bits(pbc, zeroes + 1, 1); + put_bits(pbc, zeroes, v); + } + + if (ctx->trace_enable) { + char bits[65]; + int i, j; + i = 0; + for (j = 0; j < zeroes; j++) + bits[i++] = '0'; + bits[i++] = '1'; + for (j = 0; j < zeroes; j++) + bits[i++] = (v >> (zeroes - j - 1) & 1) ? '1' : '0'; + bits[i++] = 0; + ff_cbs_trace_syntax_element(ctx, position, name, NULL, + bits, value); + } + + return 0; +} + +static int cbs_av1_read_leb128(CodedBitstreamContext *ctx, GetBitContext *gbc, + const char *name, uint64_t *write_to) +{ + uint64_t value; + int position, err, i; + + if (ctx->trace_enable) + position = get_bits_count(gbc); + + value = 0; + for (i = 0; i < 8; i++) { + int subscript[2] = { 1, i }; + uint32_t byte; + err = ff_cbs_read_unsigned(ctx, gbc, 8, "leb128_byte[i]", subscript, + &byte, 0x00, 0xff); + if (err < 0) + return err; + + value |= (uint64_t)(byte & 0x7f) << (i * 7); + if (!(byte & 0x80)) + break; + } + + if (ctx->trace_enable) + ff_cbs_trace_syntax_element(ctx, position, name, NULL, "", value); + + *write_to = value; + return 0; +} + +static int cbs_av1_write_leb128(CodedBitstreamContext *ctx, PutBitContext *pbc, + const char *name, uint64_t value) +{ + int position, err, len, i; + uint8_t byte; + + len = (av_log2(value) + 7) / 7; + + if (ctx->trace_enable) + position = put_bits_count(pbc); + + for (i = 0; i < len; i++) { + int subscript[2] = { 1, i }; + + byte = value >> (7 * i) & 0x7f; + if (i < len - 1) + byte |= 0x80; + + err = ff_cbs_write_unsigned(ctx, pbc, 8, "leb128_byte[i]", subscript, + byte, 0x00, 0xff); + if (err < 0) + return err; + } + + if (ctx->trace_enable) + ff_cbs_trace_syntax_element(ctx, position, name, NULL, "", value); + + return 0; +} + +static int cbs_av1_read_ns(CodedBitstreamContext *ctx, GetBitContext *gbc, + uint32_t n, const char *name, + const int *subscripts, uint32_t *write_to) +{ + uint32_t w, m, v, extra_bit, value; + int position; + + av_assert0(n > 0); + + if (ctx->trace_enable) + position = get_bits_count(gbc); + + w = av_log2(n) + 1; + m = (1 << w) - n; + + if (get_bits_left(gbc) < w) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid non-symmetric value at " + "%s: bitstream ended.\n", name); + return AVERROR_INVALIDDATA; + } + + if (w - 1 > 0) + v = get_bits(gbc, w - 1); + else + v = 0; + + if (v < m) { + value = v; + } else { + extra_bit = get_bits1(gbc); + value = (v << 1) - m + extra_bit; + } + + if (ctx->trace_enable) { + char bits[33]; + int i; + for (i = 0; i < w - 1; i++) + bits[i] = (v >> i & 1) ? '1' : '0'; + if (v >= m) + bits[i++] = extra_bit ? '1' : '0'; + bits[i] = 0; + + ff_cbs_trace_syntax_element(ctx, position, + name, subscripts, bits, value); + } + + *write_to = value; + return 0; +} + +static int cbs_av1_write_ns(CodedBitstreamContext *ctx, PutBitContext *pbc, + uint32_t n, const char *name, + const int *subscripts, uint32_t value) +{ + uint32_t w, m, v, extra_bit; + int position; + + if (value > n) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "%s out of range: " + "%"PRIu32", but must be in [0,%"PRIu32"].\n", + name, value, n); + return AVERROR_INVALIDDATA; + } + + if (ctx->trace_enable) + position = put_bits_count(pbc); + + w = av_log2(n) + 1; + m = (1 << w) - n; + + if (put_bits_left(pbc) < w) + return AVERROR(ENOSPC); + + if (value < m) { + v = value; + put_bits(pbc, w - 1, v); + } else { + v = m + ((value - m) >> 1); + extra_bit = (value - m) & 1; + put_bits(pbc, w - 1, v); + put_bits(pbc, 1, extra_bit); + } + + if (ctx->trace_enable) { + char bits[33]; + int i; + for (i = 0; i < w - 1; i++) + bits[i] = (v >> i & 1) ? '1' : '0'; + if (value >= m) + bits[i++] = extra_bit ? '1' : '0'; + bits[i] = 0; + + ff_cbs_trace_syntax_element(ctx, position, + name, subscripts, bits, value); + } + + return 0; +} + +static int cbs_av1_read_increment(CodedBitstreamContext *ctx, GetBitContext *gbc, + uint32_t range_min, uint32_t range_max, + const char *name, uint32_t *write_to) +{ + uint32_t value; + int position, i; + char bits[33]; + + av_assert0(range_min <= range_max && range_max - range_min < sizeof(bits) - 1); + if (ctx->trace_enable) + position = get_bits_count(gbc); + + for (i = 0, value = range_min; value < range_max;) { + if (get_bits_left(gbc) < 1) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid increment value at " + "%s: bitstream ended.\n", name); + return AVERROR_INVALIDDATA; + } + if (get_bits1(gbc)) { + bits[i++] = '1'; + ++value; + } else { + bits[i++] = '0'; + break; + } + } + + if (ctx->trace_enable) { + bits[i] = 0; + ff_cbs_trace_syntax_element(ctx, position, + name, NULL, bits, value); + } + + *write_to = value; + return 0; +} + +static int cbs_av1_write_increment(CodedBitstreamContext *ctx, PutBitContext *pbc, + uint32_t range_min, uint32_t range_max, + const char *name, uint32_t value) +{ + int len; + + av_assert0(range_min <= range_max && range_max - range_min < 32); + if (value < range_min || value > range_max) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "%s out of range: " + "%"PRIu32", but must be in [%"PRIu32",%"PRIu32"].\n", + name, value, range_min, range_max); + return AVERROR_INVALIDDATA; + } + + if (value == range_max) + len = range_max - range_min; + else + len = value - range_min + 1; + if (put_bits_left(pbc) < len) + return AVERROR(ENOSPC); + + if (ctx->trace_enable) { + char bits[33]; + int i; + for (i = 0; i < len; i++) { + if (range_min + i == value) + bits[i] = '0'; + else + bits[i] = '1'; + } + bits[i] = 0; + ff_cbs_trace_syntax_element(ctx, put_bits_count(pbc), + name, NULL, bits, value); + } + + if (len > 0) + put_bits(pbc, len, (1 << len) - 1 - (value != range_max)); + + return 0; +} + +static int cbs_av1_read_subexp(CodedBitstreamContext *ctx, GetBitContext *gbc, + uint32_t range_max, const char *name, + const int *subscripts, uint32_t *write_to) +{ + uint32_t value; + int position, err; + uint32_t max_len, len, range_offset, range_bits; + + if (ctx->trace_enable) + position = get_bits_count(gbc); + + av_assert0(range_max > 0); + max_len = av_log2(range_max - 1) - 3; + + err = cbs_av1_read_increment(ctx, gbc, 0, max_len, + "subexp_more_bits", &len); + if (err < 0) + return err; + + if (len) { + range_bits = 2 + len; + range_offset = 1 << range_bits; + } else { + range_bits = 3; + range_offset = 0; + } + + if (len < max_len) { + err = ff_cbs_read_unsigned(ctx, gbc, range_bits, + "subexp_bits", NULL, &value, + 0, MAX_UINT_BITS(range_bits)); + if (err < 0) + return err; + + } else { + err = cbs_av1_read_ns(ctx, gbc, range_max - range_offset, + "subexp_final_bits", NULL, &value); + if (err < 0) + return err; + } + value += range_offset; + + if (ctx->trace_enable) + ff_cbs_trace_syntax_element(ctx, position, + name, subscripts, "", value); + + *write_to = value; + return err; +} + +static int cbs_av1_write_subexp(CodedBitstreamContext *ctx, PutBitContext *pbc, + uint32_t range_max, const char *name, + const int *subscripts, uint32_t value) +{ + int position, err; + uint32_t max_len, len, range_offset, range_bits; + + if (value > range_max) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "%s out of range: " + "%"PRIu32", but must be in [0,%"PRIu32"].\n", + name, value, range_max); + return AVERROR_INVALIDDATA; + } + + if (ctx->trace_enable) + position = put_bits_count(pbc); + + av_assert0(range_max > 0); + max_len = av_log2(range_max - 1) - 3; + + if (value < 8) { + range_bits = 3; + range_offset = 0; + len = 0; + } else { + range_bits = av_log2(value); + len = range_bits - 2; + if (len > max_len) { + // The top bin is combined with the one below it. + av_assert0(len == max_len + 1); + --range_bits; + len = max_len; + } + range_offset = 1 << range_bits; + } + + err = cbs_av1_write_increment(ctx, pbc, 0, max_len, + "subexp_more_bits", len); + if (err < 0) + return err; + + if (len < max_len) { + err = ff_cbs_write_unsigned(ctx, pbc, range_bits, + "subexp_bits", NULL, + value - range_offset, + 0, MAX_UINT_BITS(range_bits)); + if (err < 0) + return err; + + } else { + err = cbs_av1_write_ns(ctx, pbc, range_max - range_offset, + "subexp_final_bits", NULL, + value - range_offset); + if (err < 0) + return err; + } + + if (ctx->trace_enable) + ff_cbs_trace_syntax_element(ctx, position, + name, subscripts, "", value); + + return err; +} + + +static int cbs_av1_tile_log2(int blksize, int target) +{ + int k; + for (k = 0; (blksize << k) < target; k++); + return k; +} + +static int cbs_av1_get_relative_dist(const AV1RawSequenceHeader *seq, + unsigned int a, unsigned int b) +{ + unsigned int diff, m; + if (!seq->enable_order_hint) + return 0; + diff = a - b; + m = 1 << seq->order_hint_bits_minus_1; + diff = (diff & (m - 1)) - (diff & m); + return diff; +} + +static size_t cbs_av1_get_payload_bytes_left(GetBitContext *gbc) +{ + GetBitContext tmp = *gbc; + size_t size = 0; + for (int i = 0; get_bits_left(&tmp) >= 8; i++) { + if (get_bits(&tmp, 8)) + size = i; + } + return size; +} + + +#define HEADER(name) do { \ + ff_cbs_trace_header(ctx, name); \ + } while (0) + +#define CHECK(call) do { \ + err = (call); \ + if (err < 0) \ + return err; \ + } while (0) + +#define FUNC_NAME(rw, codec, name) cbs_ ## codec ## _ ## rw ## _ ## name +#define FUNC_AV1(rw, name) FUNC_NAME(rw, av1, name) +#define FUNC(name) FUNC_AV1(READWRITE, name) + +#define SUBSCRIPTS(subs, ...) (subs > 0 ? ((int[subs + 1]){ subs, __VA_ARGS__ }) : NULL) + +#define fb(width, name) \ + xf(width, name, current->name, 0, MAX_UINT_BITS(width), 0) +#define fc(width, name, range_min, range_max) \ + xf(width, name, current->name, range_min, range_max, 0) +#define flag(name) fb(1, name) +#define su(width, name) \ + xsu(width, name, current->name, 0) + +#define fbs(width, name, subs, ...) \ + xf(width, name, current->name, 0, MAX_UINT_BITS(width), subs, __VA_ARGS__) +#define fcs(width, name, range_min, range_max, subs, ...) \ + xf(width, name, current->name, range_min, range_max, subs, __VA_ARGS__) +#define flags(name, subs, ...) \ + xf(1, name, current->name, 0, 1, subs, __VA_ARGS__) +#define sus(width, name, subs, ...) \ + xsu(width, name, current->name, subs, __VA_ARGS__) + +#define fixed(width, name, value) do { \ + av_unused uint32_t fixed_value = value; \ + xf(width, name, fixed_value, value, value, 0); \ + } while (0) + + +#define READ +#define READWRITE read +#define RWContext GetBitContext + +#define xf(width, name, var, range_min, range_max, subs, ...) do { \ + uint32_t value = range_min; \ + CHECK(ff_cbs_read_unsigned(ctx, rw, width, #name, \ + SUBSCRIPTS(subs, __VA_ARGS__), \ + &value, range_min, range_max)); \ + var = value; \ + } while (0) + +#define xsu(width, name, var, subs, ...) do { \ + int32_t value = 0; \ + CHECK(ff_cbs_read_signed(ctx, rw, width, #name, \ + SUBSCRIPTS(subs, __VA_ARGS__), &value, \ + MIN_INT_BITS(width), \ + MAX_INT_BITS(width))); \ + var = value; \ + } while (0) + +#define uvlc(name, range_min, range_max) do { \ + uint32_t value = range_min; \ + CHECK(cbs_av1_read_uvlc(ctx, rw, #name, \ + &value, range_min, range_max)); \ + current->name = value; \ + } while (0) + +#define ns(max_value, name, subs, ...) do { \ + uint32_t value = 0; \ + CHECK(cbs_av1_read_ns(ctx, rw, max_value, #name, \ + SUBSCRIPTS(subs, __VA_ARGS__), &value)); \ + current->name = value; \ + } while (0) + +#define increment(name, min, max) do { \ + uint32_t value = 0; \ + CHECK(cbs_av1_read_increment(ctx, rw, min, max, #name, &value)); \ + current->name = value; \ + } while (0) + +#define subexp(name, max, subs, ...) do { \ + uint32_t value = 0; \ + CHECK(cbs_av1_read_subexp(ctx, rw, max, #name, \ + SUBSCRIPTS(subs, __VA_ARGS__), &value)); \ + current->name = value; \ + } while (0) + +#define delta_q(name) do { \ + uint8_t delta_coded; \ + int8_t delta_q; \ + xf(1, name.delta_coded, delta_coded, 0, 1, 0); \ + if (delta_coded) \ + xsu(1 + 6, name.delta_q, delta_q, 0); \ + else \ + delta_q = 0; \ + current->name = delta_q; \ + } while (0) + +#define leb128(name) do { \ + uint64_t value = 0; \ + CHECK(cbs_av1_read_leb128(ctx, rw, #name, &value)); \ + current->name = value; \ + } while (0) + +#define infer(name, value) do { \ + current->name = value; \ + } while (0) + +#define byte_alignment(rw) (get_bits_count(rw) % 8) + +#include "cbs_av1_syntax_template.c" + +#undef READ +#undef READWRITE +#undef RWContext +#undef xf +#undef xsu +#undef uvlc +#undef ns +#undef increment +#undef subexp +#undef delta_q +#undef leb128 +#undef infer +#undef byte_alignment + + +#define WRITE +#define READWRITE write +#define RWContext PutBitContext + +#define xf(width, name, var, range_min, range_max, subs, ...) do { \ + CHECK(ff_cbs_write_unsigned(ctx, rw, width, #name, \ + SUBSCRIPTS(subs, __VA_ARGS__), \ + var, range_min, range_max)); \ + } while (0) + +#define xsu(width, name, var, subs, ...) do { \ + CHECK(ff_cbs_write_signed(ctx, rw, width, #name, \ + SUBSCRIPTS(subs, __VA_ARGS__), var, \ + MIN_INT_BITS(width), \ + MAX_INT_BITS(width))); \ + } while (0) + +#define uvlc(name, range_min, range_max) do { \ + CHECK(cbs_av1_write_uvlc(ctx, rw, #name, current->name, \ + range_min, range_max)); \ + } while (0) + +#define ns(max_value, name, subs, ...) do { \ + CHECK(cbs_av1_write_ns(ctx, rw, max_value, #name, \ + SUBSCRIPTS(subs, __VA_ARGS__), \ + current->name)); \ + } while (0) + +#define increment(name, min, max) do { \ + CHECK(cbs_av1_write_increment(ctx, rw, min, max, #name, \ + current->name)); \ + } while (0) + +#define subexp(name, max, subs, ...) do { \ + CHECK(cbs_av1_write_subexp(ctx, rw, max, #name, \ + SUBSCRIPTS(subs, __VA_ARGS__), \ + current->name)); \ + } while (0) + +#define delta_q(name) do { \ + xf(1, name.delta_coded, current->name != 0, 0, 1, 0); \ + if (current->name) \ + xsu(1 + 6, name.delta_q, current->name, 0); \ + } while (0) + +#define leb128(name) do { \ + CHECK(cbs_av1_write_leb128(ctx, rw, #name, current->name)); \ + } while (0) + +#define infer(name, value) do { \ + if (current->name != (value)) { \ + av_log(ctx->log_ctx, AV_LOG_WARNING, "Warning: " \ + "%s does not match inferred value: " \ + "%"PRId64", but should be %"PRId64".\n", \ + #name, (int64_t)current->name, (int64_t)(value)); \ + } \ + } while (0) + +#define byte_alignment(rw) (put_bits_count(rw) % 8) + +#include "cbs_av1_syntax_template.c" + +#undef WRITE +#undef READWRITE +#undef RWContext +#undef xf +#undef xsu +#undef uvlc +#undef ns +#undef increment +#undef subexp +#undef delta_q +#undef leb128 +#undef infer +#undef byte_alignment + + +static int cbs_av1_split_fragment(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag, + int header) +{ + GetBitContext gbc; + uint8_t *data; + size_t size; + uint64_t obu_length; + int pos, err, trace; + + // Don't include this parsing in trace output. + trace = ctx->trace_enable; + ctx->trace_enable = 0; + + data = frag->data; + size = frag->data_size; + + if (INT_MAX / 8 < size) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid fragment: " + "too large (%"SIZE_SPECIFIER" bytes).\n", size); + err = AVERROR_INVALIDDATA; + goto fail; + } + + while (size > 0) { + AV1RawOBUHeader header; + uint64_t obu_size; + + init_get_bits(&gbc, data, 8 * size); + + err = cbs_av1_read_obu_header(ctx, &gbc, &header); + if (err < 0) + goto fail; + + if (get_bits_left(&gbc) < 8) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid OBU: fragment " + "too short (%"SIZE_SPECIFIER" bytes).\n", size); + err = AVERROR_INVALIDDATA; + goto fail; + } + + if (header.obu_has_size_field) { + err = cbs_av1_read_leb128(ctx, &gbc, "obu_size", &obu_size); + if (err < 0) + goto fail; + } else + obu_size = size - 1 - header.obu_extension_flag; + + pos = get_bits_count(&gbc); + av_assert0(pos % 8 == 0 && pos / 8 <= size); + + obu_length = pos / 8 + obu_size; + + if (size < obu_length) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid OBU length: " + "%"PRIu64", but only %"SIZE_SPECIFIER" bytes remaining in fragment.\n", + obu_length, size); + err = AVERROR_INVALIDDATA; + goto fail; + } + + err = ff_cbs_insert_unit_data(ctx, frag, -1, header.obu_type, + data, obu_length, frag->data_ref); + if (err < 0) + goto fail; + + data += obu_length; + size -= obu_length; + } + + err = 0; +fail: + ctx->trace_enable = trace; + return err; +} + +static void cbs_av1_free_tile_data(AV1RawTileData *td) +{ + av_buffer_unref(&td->data_ref); +} + +static void cbs_av1_free_padding(AV1RawPadding *pd) +{ + av_buffer_unref(&pd->payload_ref); +} + +static void cbs_av1_free_metadata(AV1RawMetadata *md) +{ + switch (md->metadata_type) { + case AV1_METADATA_TYPE_ITUT_T35: + av_buffer_unref(&md->metadata.itut_t35.payload_ref); + break; + } +} + +static void cbs_av1_free_obu(void *unit, uint8_t *content) +{ + AV1RawOBU *obu = (AV1RawOBU*)content; + + switch (obu->header.obu_type) { + case AV1_OBU_TILE_GROUP: + cbs_av1_free_tile_data(&obu->obu.tile_group.tile_data); + break; + case AV1_OBU_FRAME: + cbs_av1_free_tile_data(&obu->obu.frame.tile_group.tile_data); + break; + case AV1_OBU_TILE_LIST: + cbs_av1_free_tile_data(&obu->obu.tile_list.tile_data); + break; + case AV1_OBU_METADATA: + cbs_av1_free_metadata(&obu->obu.metadata); + break; + case AV1_OBU_PADDING: + cbs_av1_free_padding(&obu->obu.padding); + break; + } + + av_freep(&obu); +} + +static int cbs_av1_ref_tile_data(CodedBitstreamContext *ctx, + CodedBitstreamUnit *unit, + GetBitContext *gbc, + AV1RawTileData *td) +{ + int pos; + + pos = get_bits_count(gbc); + if (pos >= 8 * unit->data_size) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Bitstream ended before " + "any data in tile group (%d bits read).\n", pos); + return AVERROR_INVALIDDATA; + } + // Must be byte-aligned at this point. + av_assert0(pos % 8 == 0); + + td->data_ref = av_buffer_ref(unit->data_ref); + if (!td->data_ref) + return AVERROR(ENOMEM); + + td->data = unit->data + pos / 8; + td->data_size = unit->data_size - pos / 8; + + return 0; +} + +static int cbs_av1_read_unit(CodedBitstreamContext *ctx, + CodedBitstreamUnit *unit) +{ + CodedBitstreamAV1Context *priv = ctx->priv_data; + AV1RawOBU *obu; + GetBitContext gbc; + int err, start_pos, end_pos; + + err = ff_cbs_alloc_unit_content(ctx, unit, sizeof(*obu), + &cbs_av1_free_obu); + if (err < 0) + return err; + obu = unit->content; + + err = init_get_bits(&gbc, unit->data, 8 * unit->data_size); + if (err < 0) + return err; + + err = cbs_av1_read_obu_header(ctx, &gbc, &obu->header); + if (err < 0) + return err; + av_assert0(obu->header.obu_type == unit->type); + + if (obu->header.obu_has_size_field) { + uint64_t obu_size; + err = cbs_av1_read_leb128(ctx, &gbc, "obu_size", &obu_size); + if (err < 0) + return err; + obu->obu_size = obu_size; + } else { + if (unit->data_size < 1 + obu->header.obu_extension_flag) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid OBU length: " + "unit too short (%"SIZE_SPECIFIER").\n", unit->data_size); + return AVERROR_INVALIDDATA; + } + obu->obu_size = unit->data_size - 1 - obu->header.obu_extension_flag; + } + + start_pos = get_bits_count(&gbc); + + if (obu->header.obu_extension_flag) { + priv->temporal_id = obu->header.temporal_id; + priv->spatial_id = obu->header.spatial_id; + + if (obu->header.obu_type != AV1_OBU_SEQUENCE_HEADER && + obu->header.obu_type != AV1_OBU_TEMPORAL_DELIMITER && + priv->operating_point_idc) { + int in_temporal_layer = + (priv->operating_point_idc >> priv->temporal_id ) & 1; + int in_spatial_layer = + (priv->operating_point_idc >> (priv->spatial_id + 8)) & 1; + if (!in_temporal_layer || !in_spatial_layer) { + // Decoding will drop this OBU at this operating point. + } + } + } else { + priv->temporal_id = 0; + priv->spatial_id = 0; + } + + switch (obu->header.obu_type) { + case AV1_OBU_SEQUENCE_HEADER: + { + err = cbs_av1_read_sequence_header_obu(ctx, &gbc, + &obu->obu.sequence_header); + if (err < 0) + return err; + + av_buffer_unref(&priv->sequence_header_ref); + priv->sequence_header = NULL; + + priv->sequence_header_ref = av_buffer_ref(unit->content_ref); + if (!priv->sequence_header_ref) + return AVERROR(ENOMEM); + priv->sequence_header = &obu->obu.sequence_header; + } + break; + case AV1_OBU_TEMPORAL_DELIMITER: + { + err = cbs_av1_read_temporal_delimiter_obu(ctx, &gbc); + if (err < 0) + return err; + } + break; + case AV1_OBU_FRAME_HEADER: + case AV1_OBU_REDUNDANT_FRAME_HEADER: + { + err = cbs_av1_read_frame_header_obu(ctx, &gbc, + &obu->obu.frame_header, + obu->header.obu_type == + AV1_OBU_REDUNDANT_FRAME_HEADER, + unit->data_ref); + if (err < 0) + return err; + } + break; + case AV1_OBU_TILE_GROUP: + { + err = cbs_av1_read_tile_group_obu(ctx, &gbc, + &obu->obu.tile_group); + if (err < 0) + return err; + + err = cbs_av1_ref_tile_data(ctx, unit, &gbc, + &obu->obu.tile_group.tile_data); + if (err < 0) + return err; + } + break; + case AV1_OBU_FRAME: + { + err = cbs_av1_read_frame_obu(ctx, &gbc, &obu->obu.frame, + unit->data_ref); + if (err < 0) + return err; + + err = cbs_av1_ref_tile_data(ctx, unit, &gbc, + &obu->obu.frame.tile_group.tile_data); + if (err < 0) + return err; + } + break; + case AV1_OBU_TILE_LIST: + { + err = cbs_av1_read_tile_list_obu(ctx, &gbc, + &obu->obu.tile_list); + if (err < 0) + return err; + + err = cbs_av1_ref_tile_data(ctx, unit, &gbc, + &obu->obu.tile_list.tile_data); + if (err < 0) + return err; + } + break; + case AV1_OBU_METADATA: + { + err = cbs_av1_read_metadata_obu(ctx, &gbc, &obu->obu.metadata); + if (err < 0) + return err; + } + break; + case AV1_OBU_PADDING: + { + err = cbs_av1_read_padding_obu(ctx, &gbc, &obu->obu.padding); + if (err < 0) + return err; + } + break; + default: + return AVERROR(ENOSYS); + } + + end_pos = get_bits_count(&gbc); + av_assert0(end_pos <= unit->data_size * 8); + + if (obu->obu_size > 0 && + obu->header.obu_type != AV1_OBU_TILE_GROUP && + obu->header.obu_type != AV1_OBU_FRAME) { + int nb_bits = obu->obu_size * 8 + start_pos - end_pos; + + if (nb_bits <= 0) + return AVERROR_INVALIDDATA; + + err = cbs_av1_read_trailing_bits(ctx, &gbc, nb_bits); + if (err < 0) + return err; + } + + return 0; +} + +static int cbs_av1_write_obu(CodedBitstreamContext *ctx, + CodedBitstreamUnit *unit, + PutBitContext *pbc) +{ + CodedBitstreamAV1Context *priv = ctx->priv_data; + AV1RawOBU *obu = unit->content; + PutBitContext pbc_tmp; + AV1RawTileData *td; + size_t header_size; + int err, start_pos, end_pos, data_pos; + + // OBUs in the normal bitstream format must contain a size field + // in every OBU (in annex B it is optional, but we don't support + // writing that). + obu->header.obu_has_size_field = 1; + + err = cbs_av1_write_obu_header(ctx, pbc, &obu->header); + if (err < 0) + return err; + + if (obu->header.obu_has_size_field) { + pbc_tmp = *pbc; + // Add space for the size field to fill later. + put_bits32(pbc, 0); + put_bits32(pbc, 0); + } + + td = NULL; + start_pos = put_bits_count(pbc); + + switch (obu->header.obu_type) { + case AV1_OBU_SEQUENCE_HEADER: + { + err = cbs_av1_write_sequence_header_obu(ctx, pbc, + &obu->obu.sequence_header); + if (err < 0) + return err; + + av_buffer_unref(&priv->sequence_header_ref); + priv->sequence_header = NULL; + + priv->sequence_header_ref = av_buffer_ref(unit->content_ref); + if (!priv->sequence_header_ref) + return AVERROR(ENOMEM); + priv->sequence_header = &obu->obu.sequence_header; + } + break; + case AV1_OBU_TEMPORAL_DELIMITER: + { + err = cbs_av1_write_temporal_delimiter_obu(ctx, pbc); + if (err < 0) + return err; + } + break; + case AV1_OBU_FRAME_HEADER: + case AV1_OBU_REDUNDANT_FRAME_HEADER: + { + err = cbs_av1_write_frame_header_obu(ctx, pbc, + &obu->obu.frame_header, + obu->header.obu_type == + AV1_OBU_REDUNDANT_FRAME_HEADER, + NULL); + if (err < 0) + return err; + } + break; + case AV1_OBU_TILE_GROUP: + { + err = cbs_av1_write_tile_group_obu(ctx, pbc, + &obu->obu.tile_group); + if (err < 0) + return err; + + td = &obu->obu.tile_group.tile_data; + } + break; + case AV1_OBU_FRAME: + { + err = cbs_av1_write_frame_obu(ctx, pbc, &obu->obu.frame, NULL); + if (err < 0) + return err; + + td = &obu->obu.frame.tile_group.tile_data; + } + break; + case AV1_OBU_TILE_LIST: + { + err = cbs_av1_write_tile_list_obu(ctx, pbc, &obu->obu.tile_list); + if (err < 0) + return err; + + td = &obu->obu.tile_list.tile_data; + } + break; + case AV1_OBU_METADATA: + { + err = cbs_av1_write_metadata_obu(ctx, pbc, &obu->obu.metadata); + if (err < 0) + return err; + } + break; + case AV1_OBU_PADDING: + { + err = cbs_av1_write_padding_obu(ctx, pbc, &obu->obu.padding); + if (err < 0) + return err; + } + break; + default: + return AVERROR(ENOSYS); + } + + end_pos = put_bits_count(pbc); + header_size = (end_pos - start_pos + 7) / 8; + if (td) { + obu->obu_size = header_size + td->data_size; + } else if (header_size > 0) { + // Add trailing bits and recalculate. + err = cbs_av1_write_trailing_bits(ctx, pbc, 8 - end_pos % 8); + if (err < 0) + return err; + end_pos = put_bits_count(pbc); + obu->obu_size = header_size = (end_pos - start_pos + 7) / 8; + } else { + // Empty OBU. + obu->obu_size = 0; + } + + end_pos = put_bits_count(pbc); + // Must now be byte-aligned. + av_assert0(end_pos % 8 == 0); + flush_put_bits(pbc); + start_pos /= 8; + end_pos /= 8; + + *pbc = pbc_tmp; + err = cbs_av1_write_leb128(ctx, pbc, "obu_size", obu->obu_size); + if (err < 0) + return err; + + data_pos = put_bits_count(pbc) / 8; + flush_put_bits(pbc); + av_assert0(data_pos <= start_pos); + + if (8 * obu->obu_size > put_bits_left(pbc)) + return AVERROR(ENOSPC); + + if (obu->obu_size > 0) { + memmove(priv->write_buffer + data_pos, + priv->write_buffer + start_pos, header_size); + skip_put_bytes(pbc, header_size); + + if (td) { + memcpy(priv->write_buffer + data_pos + header_size, + td->data, td->data_size); + skip_put_bytes(pbc, td->data_size); + } + } + + return 0; +} + +static int cbs_av1_write_unit(CodedBitstreamContext *ctx, + CodedBitstreamUnit *unit) +{ + CodedBitstreamAV1Context *priv = ctx->priv_data; + PutBitContext pbc; + int err; + + if (!priv->write_buffer) { + // Initial write buffer size is 1MB. + priv->write_buffer_size = 1024 * 1024; + + reallocate_and_try_again: + err = av_reallocp(&priv->write_buffer, priv->write_buffer_size); + if (err < 0) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Unable to allocate a " + "sufficiently large write buffer (last attempt " + "%"SIZE_SPECIFIER" bytes).\n", priv->write_buffer_size); + return err; + } + } + + init_put_bits(&pbc, priv->write_buffer, priv->write_buffer_size); + + err = cbs_av1_write_obu(ctx, unit, &pbc); + if (err == AVERROR(ENOSPC)) { + // Overflow. + priv->write_buffer_size *= 2; + goto reallocate_and_try_again; + } + if (err < 0) + return err; + + // Overflow but we didn't notice. + av_assert0(put_bits_count(&pbc) <= 8 * priv->write_buffer_size); + + // OBU data must be byte-aligned. + av_assert0(put_bits_count(&pbc) % 8 == 0); + + unit->data_size = put_bits_count(&pbc) / 8; + flush_put_bits(&pbc); + + err = ff_cbs_alloc_unit_data(ctx, unit, unit->data_size); + if (err < 0) + return err; + + memcpy(unit->data, priv->write_buffer, unit->data_size); + + return 0; +} + +static int cbs_av1_assemble_fragment(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag) +{ + size_t size, pos; + int i; + + size = 0; + for (i = 0; i < frag->nb_units; i++) + size += frag->units[i].data_size; + + frag->data_ref = av_buffer_alloc(size + AV_INPUT_BUFFER_PADDING_SIZE); + if (!frag->data_ref) + return AVERROR(ENOMEM); + frag->data = frag->data_ref->data; + memset(frag->data + size, 0, AV_INPUT_BUFFER_PADDING_SIZE); + + pos = 0; + for (i = 0; i < frag->nb_units; i++) { + memcpy(frag->data + pos, frag->units[i].data, + frag->units[i].data_size); + pos += frag->units[i].data_size; + } + av_assert0(pos == size); + frag->data_size = size; + + return 0; +} + +static void cbs_av1_close(CodedBitstreamContext *ctx) +{ + CodedBitstreamAV1Context *priv = ctx->priv_data; + + av_buffer_unref(&priv->sequence_header_ref); + av_buffer_unref(&priv->frame_header_ref); + + av_freep(&priv->write_buffer); +} + +const CodedBitstreamType ff_cbs_type_av1 = { + .codec_id = AV_CODEC_ID_AV1, + + .priv_data_size = sizeof(CodedBitstreamAV1Context), + + .split_fragment = &cbs_av1_split_fragment, + .read_unit = &cbs_av1_read_unit, + .write_unit = &cbs_av1_write_unit, + .assemble_fragment = &cbs_av1_assemble_fragment, + + .close = &cbs_av1_close, +}; diff --git a/libavcodec/cbs_av1.h b/libavcodec/cbs_av1.h new file mode 100644 index 000000000..1fb668ada --- /dev/null +++ b/libavcodec/cbs_av1.h @@ -0,0 +1,452 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * 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_CBS_AV1_H +#define AVCODEC_CBS_AV1_H + +#include +#include + +#include "av1.h" +#include "cbs.h" + + +typedef struct AV1RawOBUHeader { + uint8_t obu_forbidden_bit; + uint8_t obu_type; + uint8_t obu_extension_flag; + uint8_t obu_has_size_field; + uint8_t obu_reserved_1bit; + + uint8_t temporal_id; + uint8_t spatial_id; + uint8_t extension_header_reserved_3bits; +} AV1RawOBUHeader; + +typedef struct AV1RawColorConfig { + uint8_t high_bitdepth; + uint8_t twelve_bit; + uint8_t mono_chrome; + + uint8_t color_description_present_flag; + uint8_t color_primaries; + uint8_t transfer_characteristics; + uint8_t matrix_coefficients; + + uint8_t color_range; + uint8_t subsampling_x; + uint8_t subsampling_y; + uint8_t chroma_sample_position; + uint8_t separate_uv_delta_q; +} AV1RawColorConfig; + +typedef struct AV1RawTimingInfo { + uint32_t num_units_in_display_tick; + uint32_t time_scale; + + uint8_t equal_picture_interval; + uint32_t num_ticks_per_picture_minus_1; +} AV1RawTimingInfo; + +typedef struct AV1RawDecoderModelInfo { + uint8_t buffer_delay_length_minus_1; + uint32_t num_units_in_decoding_tick; + uint8_t buffer_removal_time_length_minus_1; + uint8_t frame_presentation_time_length_minus_1; +} AV1RawDecoderModelInfo; + +typedef struct AV1RawSequenceHeader { + uint8_t seq_profile; + uint8_t still_picture; + uint8_t reduced_still_picture_header; + + uint8_t timing_info_present_flag; + uint8_t decoder_model_info_present_flag; + uint8_t initial_display_delay_present_flag; + uint8_t operating_points_cnt_minus_1; + + AV1RawTimingInfo timing_info; + AV1RawDecoderModelInfo decoder_model_info; + + uint16_t operating_point_idc[AV1_MAX_OPERATING_POINTS]; + uint8_t seq_level_idx[AV1_MAX_OPERATING_POINTS]; + uint8_t seq_tier[AV1_MAX_OPERATING_POINTS]; + uint8_t decoder_model_present_for_this_op[AV1_MAX_OPERATING_POINTS]; + uint32_t decoder_buffer_delay[AV1_MAX_OPERATING_POINTS]; + uint32_t encoder_buffer_delay[AV1_MAX_OPERATING_POINTS]; + uint8_t low_delay_mode_flag[AV1_MAX_OPERATING_POINTS]; + uint8_t initial_display_delay_present_for_this_op[AV1_MAX_OPERATING_POINTS]; + uint8_t initial_display_delay_minus_1[AV1_MAX_OPERATING_POINTS]; + + uint8_t frame_width_bits_minus_1; + uint8_t frame_height_bits_minus_1; + uint16_t max_frame_width_minus_1; + uint16_t max_frame_height_minus_1; + + uint8_t frame_id_numbers_present_flag; + uint8_t delta_frame_id_length_minus_2; + uint8_t additional_frame_id_length_minus_1; + + uint8_t use_128x128_superblock; + uint8_t enable_filter_intra; + uint8_t enable_intra_edge_filter; + uint8_t enable_intraintra_compound; + uint8_t enable_masked_compound; + uint8_t enable_warped_motion; + uint8_t enable_dual_filter; + + uint8_t enable_order_hint; + uint8_t enable_jnt_comp; + uint8_t enable_ref_frame_mvs; + + uint8_t seq_choose_screen_content_tools; + uint8_t seq_force_screen_content_tools; + uint8_t seq_choose_integer_mv; + uint8_t seq_force_integer_mv; + + uint8_t order_hint_bits_minus_1; + + uint8_t enable_superres; + uint8_t enable_cdef; + uint8_t enable_restoration; + + AV1RawColorConfig color_config; + + uint8_t film_grain_params_present; +} AV1RawSequenceHeader; + +typedef struct AV1RawFrameHeader { + uint8_t show_existing_frame; + uint8_t frame_to_show_map_idx; + uint32_t frame_presentation_time; + uint32_t display_frame_id; + + uint8_t frame_type; + uint8_t show_frame; + uint8_t showable_frame; + + uint8_t error_resilient_mode; + uint8_t disable_cdf_update; + uint8_t allow_screen_content_tools; + uint8_t force_integer_mv; + + uint32_t current_frame_id; + uint8_t frame_size_override_flag; + uint8_t order_hint; + + uint8_t buffer_removal_time_present_flag; + uint32_t buffer_removal_time[AV1_MAX_OPERATING_POINTS]; + + uint8_t primary_ref_frame; + uint16_t frame_width_minus_1; + uint16_t frame_height_minus_1; + uint8_t use_superres; + uint8_t coded_denom; + uint8_t render_and_frame_size_different; + uint8_t render_width_minus_1; + uint8_t render_height_minus_1; + + uint8_t found_ref[AV1_REFS_PER_FRAME]; + + uint8_t refresh_frame_flags; + uint8_t allow_intrabc; + uint8_t ref_order_hint[AV1_NUM_REF_FRAMES]; + uint8_t frame_refs_short_signaling; + uint8_t last_frame_idx; + uint8_t golden_frame_idx; + int8_t ref_frame_idx[AV1_REFS_PER_FRAME]; + uint32_t delta_frame_id_minus1[AV1_REFS_PER_FRAME]; + + uint8_t allow_high_precision_mv; + uint8_t is_filter_switchable; + uint8_t interpolation_filter; + uint8_t is_motion_mode_switchable; + uint8_t use_ref_frame_mvs; + + uint8_t disable_frame_end_update_cdf; + + uint8_t uniform_tile_spacing_flag; + uint8_t tile_cols_log2; + uint8_t tile_rows_log2; + uint8_t width_in_sbs_minus_1[AV1_MAX_TILE_COLS]; + uint8_t height_in_sbs_minus_1[AV1_MAX_TILE_ROWS]; + uint16_t context_update_tile_id; + uint8_t tile_size_bytes_minus1; + + // These are derived values, but it's very unhelpful to have to + // recalculate them all the time so we store them here. + uint16_t tile_cols; + uint16_t tile_rows; + + uint8_t base_q_idx; + int8_t delta_q_y_dc; + uint8_t diff_uv_delta; + int8_t delta_q_u_dc; + int8_t delta_q_u_ac; + int8_t delta_q_v_dc; + int8_t delta_q_v_ac; + uint8_t using_qmatrix; + uint8_t qm_y; + uint8_t qm_u; + uint8_t qm_v; + + uint8_t segmentation_enabled; + uint8_t segmentation_update_map; + uint8_t segmentation_temporal_update; + uint8_t segmentation_update_data; + uint8_t feature_enabled[AV1_MAX_SEGMENTS][AV1_SEG_LVL_MAX]; + int16_t feature_value[AV1_MAX_SEGMENTS][AV1_SEG_LVL_MAX]; + + uint8_t delta_q_present; + uint8_t delta_q_res; + uint8_t delta_lf_present; + uint8_t delta_lf_res; + uint8_t delta_lf_multi; + + uint8_t loop_filter_level[4]; + uint8_t loop_filter_sharpness; + uint8_t loop_filter_delta_enabled; + uint8_t loop_filter_delta_update; + uint8_t update_ref_delta[AV1_TOTAL_REFS_PER_FRAME]; + int8_t loop_filter_ref_deltas[AV1_TOTAL_REFS_PER_FRAME]; + uint8_t update_mode_delta[2]; + int8_t loop_filter_mode_deltas[2]; + + uint8_t cdef_damping_minus_3; + uint8_t cdef_bits; + uint8_t cdef_y_pri_strength[8]; + uint8_t cdef_y_sec_strength[8]; + uint8_t cdef_uv_pri_strength[8]; + uint8_t cdef_uv_sec_strength[8]; + + uint8_t lr_type[3]; + uint8_t lr_unit_shift; + uint8_t lr_uv_shift; + + uint8_t tx_mode; + uint8_t reference_select; + uint8_t skip_mode_present; + + uint8_t allow_warped_motion; + uint8_t reduced_tx_set; + + uint8_t is_global[AV1_TOTAL_REFS_PER_FRAME]; + uint8_t is_rot_zoom[AV1_TOTAL_REFS_PER_FRAME]; + uint8_t is_translation[AV1_TOTAL_REFS_PER_FRAME]; + //AV1RawSubexp gm_params[AV1_TOTAL_REFS_PER_FRAME][6]; + uint32_t gm_params[AV1_TOTAL_REFS_PER_FRAME][6]; + + uint8_t apply_grain; + uint16_t grain_seed; + uint8_t update_grain; + uint8_t film_grain_params_ref_idx; + uint8_t num_y_points; + uint8_t point_y_value[16]; + uint8_t point_y_scaling[16]; + uint8_t chroma_scaling_from_luma; + uint8_t num_cb_points; + uint8_t point_cb_value[16]; + uint8_t point_cb_scaling[16]; + uint8_t num_cr_points; + uint8_t point_cr_value[16]; + uint8_t point_cr_scaling[16]; + uint8_t grain_scaling_minus_8; + uint8_t ar_coeff_lag; + uint8_t ar_coeffs_y_plus_128[24]; + uint8_t ar_coeffs_cb_plus_128[24]; + uint8_t ar_coeffs_cr_plus_128[24]; + uint8_t ar_coeff_shift_minus_6; + uint8_t grain_scale_shift; + uint8_t cb_mult; + uint8_t cb_luma_mult; + uint16_t cb_offset; + uint8_t cr_mult; + uint8_t cr_luma_mult; + uint16_t cr_offset; + uint8_t overlap_flag; + uint8_t clip_to_restricted_range; +} AV1RawFrameHeader; + +typedef struct AV1RawTileData { + uint8_t *data; + size_t data_size; + AVBufferRef *data_ref; +} AV1RawTileData; + +typedef struct AV1RawTileGroup { + uint8_t tile_start_and_end_present_flag; + uint16_t tg_start; + uint16_t tg_end; + + AV1RawTileData tile_data; +} AV1RawTileGroup; + +typedef struct AV1RawFrame { + AV1RawFrameHeader header; + AV1RawTileGroup tile_group; +} AV1RawFrame; + +typedef struct AV1RawTileList { + uint8_t output_frame_width_in_tiles_minus_1; + uint8_t output_frame_height_in_tiles_minus_1; + uint16_t tile_count_minus_1; + + AV1RawTileData tile_data; +} AV1RawTileList; + +typedef struct AV1RawMetadataHDRCLL { + uint16_t max_cll; + uint16_t max_fall; +} AV1RawMetadataHDRCLL; + +typedef struct AV1RawMetadataHDRMDCV { + uint16_t primary_chromaticity_x[3]; + uint16_t primary_chromaticity_y[3]; + uint16_t white_point_chromaticity_x; + uint16_t white_point_chromaticity_y; + uint32_t luminance_max; + uint32_t luminance_min; +} AV1RawMetadataHDRMDCV; + +typedef struct AV1RawMetadataScalability { + uint8_t scalability_mode_idc; + uint8_t spatial_layers_cnt_minus_1; + uint8_t spatial_layer_dimensions_present_flag; + uint8_t spatial_layer_description_present_flag; + uint8_t temporal_group_description_present_flag; + uint8_t scalability_structure_reserved_3bits; + uint16_t spatial_layer_max_width[4]; + uint16_t spatial_layer_max_height[4]; + uint8_t spatial_layer_ref_id[4]; + uint8_t temporal_group_size; + uint8_t temporal_group_temporal_id[255]; + uint8_t temporal_group_temporal_switching_up_point_flag[255]; + uint8_t temporal_group_spatial_switching_up_point_flag[255]; + uint8_t temporal_group_ref_cnt[255]; + uint8_t temporal_group_ref_pic_diff[255][7]; +} AV1RawMetadataScalability; + +typedef struct AV1RawMetadataITUTT35 { + uint8_t itu_t_t35_country_code; + uint8_t itu_t_t35_country_code_extension_byte; + + uint8_t *payload; + size_t payload_size; + AVBufferRef *payload_ref; +} AV1RawMetadataITUTT35; + +typedef struct AV1RawMetadataTimecode { + uint8_t counting_type; + uint8_t full_timestamp_flag; + uint8_t discontinuity_flag; + uint8_t cnt_dropped_flag; + uint16_t n_frames; + uint8_t seconds_value; + uint8_t minutes_value; + uint8_t hours_value; + uint8_t seconds_flag; + uint8_t minutes_flag; + uint8_t hours_flag; + uint8_t time_offset_length; + uint32_t time_offset_value; +} AV1RawMetadataTimecode; + +typedef struct AV1RawMetadata { + uint64_t metadata_type; + union { + AV1RawMetadataHDRCLL hdr_cll; + AV1RawMetadataHDRMDCV hdr_mdcv; + AV1RawMetadataScalability scalability; + AV1RawMetadataITUTT35 itut_t35; + AV1RawMetadataTimecode timecode; + } metadata; +} AV1RawMetadata; + +typedef struct AV1RawPadding { + uint8_t *payload; + size_t payload_size; + AVBufferRef *payload_ref; +} AV1RawPadding; + + +typedef struct AV1RawOBU { + AV1RawOBUHeader header; + + size_t obu_size; + + union { + AV1RawSequenceHeader sequence_header; + AV1RawFrameHeader frame_header; + AV1RawFrame frame; + AV1RawTileGroup tile_group; + AV1RawTileList tile_list; + AV1RawMetadata metadata; + AV1RawPadding padding; + } obu; +} AV1RawOBU; + +typedef struct AV1ReferenceFrameState { + int valid; // RefValid + int frame_id; // RefFrameId + int upscaled_width; // RefUpscaledWidth + int frame_width; // RefFrameWidth + int frame_height; // RefFrameHeight + int render_width; // RefRenderWidth + int render_height; // RefRenderHeight + int frame_type; // RefFrameType + int subsampling_x; // RefSubsamplingX + int subsampling_y; // RefSubsamplingY + int bit_depth; // RefBitDepth + int order_hint; // RefOrderHint +} AV1ReferenceFrameState; + +typedef struct CodedBitstreamAV1Context { + AV1RawSequenceHeader *sequence_header; + AVBufferRef *sequence_header_ref; + + int seen_frame_header; + AVBufferRef *frame_header_ref; + uint8_t *frame_header; + size_t frame_header_size; + + int temporal_id; + int spatial_id; + int operating_point_idc; + + int bit_depth; + int frame_width; + int frame_height; + int upscaled_width; + int render_width; + int render_height; + + int num_planes; + int coded_lossless; + int all_lossless; + int tile_cols; + int tile_rows; + + AV1ReferenceFrameState ref[AV1_NUM_REF_FRAMES]; + + // Write buffer. + uint8_t *write_buffer; + size_t write_buffer_size; +} CodedBitstreamAV1Context; + + +#endif /* AVCODEC_CBS_AV1_H */ diff --git a/libavcodec/cbs_av1_syntax_template.c b/libavcodec/cbs_av1_syntax_template.c new file mode 100644 index 000000000..806b302de --- /dev/null +++ b/libavcodec/cbs_av1_syntax_template.c @@ -0,0 +1,1836 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +static int FUNC(obu_header)(CodedBitstreamContext *ctx, RWContext *rw, + AV1RawOBUHeader *current) +{ + int err; + av_unused int zero = 0; + + HEADER("OBU header"); + + fc(1, obu_forbidden_bit, 0, 0); + + fc(4, obu_type, 0, AV1_OBU_PADDING); + flag(obu_extension_flag); + flag(obu_has_size_field); + + fc(1, obu_reserved_1bit, 0, 0); + + if (current->obu_extension_flag) { + fb(3, temporal_id); + fb(2, spatial_id); + fc(3, extension_header_reserved_3bits, 0, 0); + } + + return 0; +} + +static int FUNC(trailing_bits)(CodedBitstreamContext *ctx, RWContext *rw, int nb_bits) +{ + int err; + + av_assert0(nb_bits > 0); + + fixed(1, trailing_one_bit, 1); + --nb_bits; + + while (nb_bits > 0) { + fixed(1, trailing_zero_bit, 0); + --nb_bits; + } + + return 0; +} + +static int FUNC(byte_alignment)(CodedBitstreamContext *ctx, RWContext *rw) +{ + int err; + + while (byte_alignment(rw) != 0) + fixed(1, zero_bit, 0); + + return 0; +} + +static int FUNC(color_config)(CodedBitstreamContext *ctx, RWContext *rw, + AV1RawColorConfig *current, int seq_profile) +{ + CodedBitstreamAV1Context *priv = ctx->priv_data; + int err; + + flag(high_bitdepth); + + if (seq_profile == FF_PROFILE_AV1_PROFESSIONAL && + current->high_bitdepth) { + flag(twelve_bit); + priv->bit_depth = current->twelve_bit ? 12 : 10; + } else { + priv->bit_depth = current->high_bitdepth ? 10 : 8; + } + + if (seq_profile == FF_PROFILE_AV1_HIGH) + infer(mono_chrome, 0); + else + flag(mono_chrome); + priv->num_planes = current->mono_chrome ? 1 : 3; + + flag(color_description_present_flag); + if (current->color_description_present_flag) { + fb(8, color_primaries); + fb(8, transfer_characteristics); + fb(8, matrix_coefficients); + } else { + infer(color_primaries, AVCOL_PRI_UNSPECIFIED); + infer(transfer_characteristics, AVCOL_TRC_UNSPECIFIED); + infer(matrix_coefficients, AVCOL_SPC_UNSPECIFIED); + } + + if (current->mono_chrome) { + flag(color_range); + + infer(subsampling_x, 1); + infer(subsampling_y, 1); + infer(chroma_sample_position, AV1_CSP_UNKNOWN); + infer(separate_uv_delta_q, 0); + + } else if (current->color_primaries == AVCOL_PRI_BT709 && + current->transfer_characteristics == AVCOL_TRC_IEC61966_2_1 && + current->matrix_coefficients == AVCOL_SPC_RGB) { + infer(color_range, 1); + infer(subsampling_x, 0); + infer(subsampling_y, 0); + flag(separate_uv_delta_q); + + } else { + flag(color_range); + + if (seq_profile == FF_PROFILE_AV1_MAIN) { + infer(subsampling_x, 1); + infer(subsampling_y, 1); + } else if (seq_profile == FF_PROFILE_AV1_HIGH) { + infer(subsampling_x, 0); + infer(subsampling_y, 0); + } else { + if (priv->bit_depth == 12) { + fb(1, subsampling_x); + if (current->subsampling_x) + fb(1, subsampling_y); + else + infer(subsampling_y, 0); + } else { + infer(subsampling_x, 1); + infer(subsampling_y, 0); + } + } + if (current->subsampling_x && current->subsampling_y) { + fc(2, chroma_sample_position, AV1_CSP_UNKNOWN, + AV1_CSP_COLOCATED); + } + + flag(separate_uv_delta_q); + } + + return 0; +} + +static int FUNC(timing_info)(CodedBitstreamContext *ctx, RWContext *rw, + AV1RawTimingInfo *current) +{ + int err; + + fc(32, num_units_in_display_tick, 1, MAX_UINT_BITS(32)); + fc(32, time_scale, 1, MAX_UINT_BITS(32)); + + flag(equal_picture_interval); + if (current->equal_picture_interval) + uvlc(num_ticks_per_picture_minus_1, 0, MAX_UINT_BITS(32) - 1); + + return 0; +} + +static int FUNC(decoder_model_info)(CodedBitstreamContext *ctx, RWContext *rw, + AV1RawDecoderModelInfo *current) +{ + int err; + + fb(5, buffer_delay_length_minus_1); + fb(32, num_units_in_decoding_tick); + fb(5, buffer_removal_time_length_minus_1); + fb(5, frame_presentation_time_length_minus_1); + + return 0; +} + +static int FUNC(sequence_header_obu)(CodedBitstreamContext *ctx, RWContext *rw, + AV1RawSequenceHeader *current) +{ + int i, err; + + HEADER("Sequence Header"); + + fc(3, seq_profile, FF_PROFILE_AV1_MAIN, + FF_PROFILE_AV1_PROFESSIONAL); + flag(still_picture); + flag(reduced_still_picture_header); + + if (current->reduced_still_picture_header) { + infer(timing_info_present_flag, 0); + infer(decoder_model_info_present_flag, 0); + infer(initial_display_delay_present_flag, 0); + infer(operating_points_cnt_minus_1, 0); + infer(operating_point_idc[0], 0); + + fb(5, seq_level_idx[0]); + + infer(seq_tier[0], 0); + infer(decoder_model_present_for_this_op[0], 0); + infer(initial_display_delay_present_for_this_op[0], 0); + + } else { + flag(timing_info_present_flag); + if (current->timing_info_present_flag) { + CHECK(FUNC(timing_info)(ctx, rw, ¤t->timing_info)); + + flag(decoder_model_info_present_flag); + if (current->decoder_model_info_present_flag) { + CHECK(FUNC(decoder_model_info) + (ctx, rw, ¤t->decoder_model_info)); + } + } else { + infer(decoder_model_info_present_flag, 0); + } + + flag(initial_display_delay_present_flag); + + fb(5, operating_points_cnt_minus_1); + for (i = 0; i <= current->operating_points_cnt_minus_1; i++) { + fbs(12, operating_point_idc[i], 1, i); + fbs(5, seq_level_idx[i], 1, i); + + if (current->seq_level_idx[i] > 7) + flags(seq_tier[i], 1, i); + else + infer(seq_tier[i], 0); + + if (current->decoder_model_info_present_flag) { + flags(decoder_model_present_for_this_op[i], 1, i); + if (current->decoder_model_present_for_this_op[i]) { + int n = current->decoder_model_info.buffer_delay_length_minus_1 + 1; + fbs(n, decoder_buffer_delay[i], 1, i); + fbs(n, encoder_buffer_delay[i], 1, i); + flags(low_delay_mode_flag[i], 1, i); + } + } else { + infer(decoder_model_present_for_this_op[i], 0); + } + + if (current->initial_display_delay_present_flag) { + flags(initial_display_delay_present_for_this_op[i], 1, i); + if (current->initial_display_delay_present_for_this_op[i]) + fbs(4, initial_display_delay_minus_1[i], 1, i); + } + } + } + + fb(4, frame_width_bits_minus_1); + fb(4, frame_height_bits_minus_1); + + fb(current->frame_width_bits_minus_1 + 1, max_frame_width_minus_1); + fb(current->frame_height_bits_minus_1 + 1, max_frame_height_minus_1); + + if (current->reduced_still_picture_header) + infer(frame_id_numbers_present_flag, 0); + else + flag(frame_id_numbers_present_flag); + if (current->frame_id_numbers_present_flag) { + fb(4, delta_frame_id_length_minus_2); + fb(3, additional_frame_id_length_minus_1); + } + + flag(use_128x128_superblock); + flag(enable_filter_intra); + flag(enable_intra_edge_filter); + + if (current->reduced_still_picture_header) { + infer(enable_intraintra_compound, 0); + infer(enable_masked_compound, 0); + infer(enable_warped_motion, 0); + infer(enable_dual_filter, 0); + infer(enable_order_hint, 0); + infer(enable_jnt_comp, 0); + infer(enable_ref_frame_mvs, 0); + + infer(seq_force_screen_content_tools, + AV1_SELECT_SCREEN_CONTENT_TOOLS); + infer(seq_force_integer_mv, + AV1_SELECT_INTEGER_MV); + } else { + flag(enable_intraintra_compound); + flag(enable_masked_compound); + flag(enable_warped_motion); + flag(enable_dual_filter); + + flag(enable_order_hint); + if (current->enable_order_hint) { + flag(enable_jnt_comp); + flag(enable_ref_frame_mvs); + } else { + infer(enable_jnt_comp, 0); + infer(enable_ref_frame_mvs, 0); + } + + flag(seq_choose_screen_content_tools); + if (current->seq_choose_screen_content_tools) + infer(seq_force_screen_content_tools, + AV1_SELECT_SCREEN_CONTENT_TOOLS); + else + fb(1, seq_force_screen_content_tools); + if (current->seq_force_screen_content_tools > 0) { + flag(seq_choose_integer_mv); + if (current->seq_choose_integer_mv) + infer(seq_force_integer_mv, + AV1_SELECT_INTEGER_MV); + else + fb(1, seq_force_integer_mv); + } else { + infer(seq_force_integer_mv, AV1_SELECT_INTEGER_MV); + } + + if (current->enable_order_hint) + fb(3, order_hint_bits_minus_1); + } + + flag(enable_superres); + flag(enable_cdef); + flag(enable_restoration); + + CHECK(FUNC(color_config)(ctx, rw, ¤t->color_config, + current->seq_profile)); + + flag(film_grain_params_present); + + return 0; +} + +static int FUNC(temporal_delimiter_obu)(CodedBitstreamContext *ctx, RWContext *rw) +{ + CodedBitstreamAV1Context *priv = ctx->priv_data; + + HEADER("Temporal Delimiter"); + + priv->seen_frame_header = 0; + + return 0; +} + +static int FUNC(superres_params)(CodedBitstreamContext *ctx, RWContext *rw, + AV1RawFrameHeader *current) +{ + CodedBitstreamAV1Context *priv = ctx->priv_data; + const AV1RawSequenceHeader *seq = priv->sequence_header; + int denom, err; + + if (seq->enable_superres) + flag(use_superres); + else + infer(use_superres, 0); + + if (current->use_superres) { + fb(3, coded_denom); + denom = current->coded_denom + AV1_SUPERRES_DENOM_MIN; + } else { + denom = AV1_SUPERRES_NUM; + } + + priv->upscaled_width = priv->frame_width; + priv->frame_width = (priv->upscaled_width * AV1_SUPERRES_NUM + + denom / 2) / denom; + + return 0; +} + +static int FUNC(frame_size)(CodedBitstreamContext *ctx, RWContext *rw, + AV1RawFrameHeader *current) +{ + CodedBitstreamAV1Context *priv = ctx->priv_data; + const AV1RawSequenceHeader *seq = priv->sequence_header; + int err; + + if (current->frame_size_override_flag) { + fb(seq->frame_width_bits_minus_1 + 1, frame_width_minus_1); + fb(seq->frame_height_bits_minus_1 + 1, frame_height_minus_1); + + priv->frame_width = current->frame_width_minus_1 + 1; + priv->frame_height = current->frame_height_minus_1 + 1; + } else { + priv->frame_width = seq->max_frame_width_minus_1 + 1; + priv->frame_height = seq->max_frame_height_minus_1 + 1; + } + + CHECK(FUNC(superres_params)(ctx, rw, current)); + + return 0; +} + +static int FUNC(render_size)(CodedBitstreamContext *ctx, RWContext *rw, + AV1RawFrameHeader *current) +{ + CodedBitstreamAV1Context *priv = ctx->priv_data; + int err; + + flag(render_and_frame_size_different); + + if (current->render_and_frame_size_different) { + fb(16, render_width_minus_1); + fb(16, render_height_minus_1); + + priv->render_width = current->render_width_minus_1 + 1; + priv->render_height = current->render_height_minus_1 + 1; + } else { + priv->render_width = priv->upscaled_width; + priv->render_height = priv->frame_height; + } + + return 0; +} + +static int FUNC(frame_size_with_refs)(CodedBitstreamContext *ctx, RWContext *rw, + AV1RawFrameHeader *current) +{ + CodedBitstreamAV1Context *priv = ctx->priv_data; + int i, err; + + for (i = 0; i < AV1_REFS_PER_FRAME; i++) { + flags(found_ref[i], 1, i); + if (current->found_ref[i]) { + AV1ReferenceFrameState *ref; + + if (current->ref_frame_idx[i] < 0 || + !priv->ref[current->ref_frame_idx[i]].valid) { + av_log(ctx->log_ctx, AV_LOG_ERROR, + "Missing reference frame needed for frame size " + "(ref = %d, ref_frame_idx = %d).\n", + i, current->ref_frame_idx[i]); + return AVERROR_INVALIDDATA; + } + ref = &priv->ref[current->ref_frame_idx[i]]; + + priv->upscaled_width = ref->upscaled_width; + priv->frame_width = ref->frame_width; + priv->frame_height = ref->frame_height; + priv->render_width = ref->render_width; + priv->render_height = ref->render_height; + break; + } + } + + if (i >= AV1_REFS_PER_FRAME) { + CHECK(FUNC(frame_size)(ctx, rw, current)); + CHECK(FUNC(render_size)(ctx, rw, current)); + } else { + CHECK(FUNC(superres_params)(ctx, rw, current)); + } + + return 0; +} + +static int FUNC(interpolation_filter)(CodedBitstreamContext *ctx, RWContext *rw, + AV1RawFrameHeader *current) +{ + int err; + + flag(is_filter_switchable); + if (current->is_filter_switchable) + infer(interpolation_filter, + AV1_INTERPOLATION_FILTER_SWITCHABLE); + else + fb(2, interpolation_filter); + + return 0; +} + +static int FUNC(tile_info)(CodedBitstreamContext *ctx, RWContext *rw, + AV1RawFrameHeader *current) +{ + CodedBitstreamAV1Context *priv = ctx->priv_data; + const AV1RawSequenceHeader *seq = priv->sequence_header; + int mi_cols, mi_rows, sb_cols, sb_rows, sb_shift, sb_size; + int max_tile_width_sb, max_tile_height_sb, max_tile_area_sb; + int min_log2_tile_cols, max_log2_tile_cols, max_log2_tile_rows; + int min_log2_tiles, min_log2_tile_rows; + int i, err; + + mi_cols = 2 * ((priv->frame_width + 7) >> 3); + mi_rows = 2 * ((priv->frame_height + 7) >> 3); + + sb_cols = seq->use_128x128_superblock ? ((mi_cols + 31) >> 5) + : ((mi_cols + 15) >> 4); + sb_rows = seq->use_128x128_superblock ? ((mi_rows + 31) >> 5) + : ((mi_rows + 15) >> 4); + + sb_shift = seq->use_128x128_superblock ? 5 : 4; + sb_size = sb_shift + 2; + + max_tile_width_sb = AV1_MAX_TILE_WIDTH >> sb_size; + max_tile_area_sb = AV1_MAX_TILE_AREA >> (2 * sb_size); + + min_log2_tile_cols = cbs_av1_tile_log2(max_tile_width_sb, sb_cols); + max_log2_tile_cols = cbs_av1_tile_log2(1, FFMIN(sb_cols, AV1_MAX_TILE_COLS)); + max_log2_tile_rows = cbs_av1_tile_log2(1, FFMIN(sb_rows, AV1_MAX_TILE_ROWS)); + min_log2_tiles = FFMAX(min_log2_tile_cols, + cbs_av1_tile_log2(max_tile_area_sb, sb_rows * sb_cols)); + + flag(uniform_tile_spacing_flag); + + if (current->uniform_tile_spacing_flag) { + int tile_width_sb, tile_height_sb; + + increment(tile_cols_log2, min_log2_tile_cols, max_log2_tile_cols); + + tile_width_sb = (sb_cols + (1 << current->tile_cols_log2) - 1) >> + current->tile_cols_log2; + current->tile_cols = (sb_cols + tile_width_sb - 1) / tile_width_sb; + + min_log2_tile_rows = FFMAX(min_log2_tiles - current->tile_cols_log2, 0); + + increment(tile_rows_log2, min_log2_tile_rows, max_log2_tile_rows); + + tile_height_sb = (sb_rows + (1 << current->tile_rows_log2) - 1) >> + current->tile_rows_log2; + current->tile_rows = (sb_rows + tile_height_sb - 1) / tile_height_sb; + + } else { + int widest_tile_sb, start_sb, size_sb, max_width, max_height; + + widest_tile_sb = 0; + + start_sb = 0; + for (i = 0; start_sb < sb_cols && i < AV1_MAX_TILE_COLS; i++) { + max_width = FFMIN(sb_cols - start_sb, max_tile_width_sb); + ns(max_width, width_in_sbs_minus_1[i], 1, i); + size_sb = current->width_in_sbs_minus_1[i] + 1; + widest_tile_sb = FFMAX(size_sb, widest_tile_sb); + start_sb += size_sb; + } + current->tile_cols_log2 = cbs_av1_tile_log2(1, i); + current->tile_cols = i; + + if (min_log2_tiles > 0) + max_tile_area_sb = (sb_rows * sb_cols) >> (min_log2_tiles + 1); + else + max_tile_area_sb = sb_rows * sb_cols; + max_tile_height_sb = FFMAX(max_tile_area_sb / widest_tile_sb, 1); + + start_sb = 0; + for (i = 0; start_sb < sb_rows && i < AV1_MAX_TILE_ROWS; i++) { + max_height = FFMIN(sb_rows - start_sb, max_tile_height_sb); + ns(max_height, height_in_sbs_minus_1[i], 1, i); + size_sb = current->height_in_sbs_minus_1[i] + 1; + start_sb += size_sb; + } + current->tile_rows_log2 = cbs_av1_tile_log2(1, i); + current->tile_rows = i; + } + + if (current->tile_cols_log2 > 0 || + current->tile_rows_log2 > 0) { + fb(current->tile_cols_log2 + current->tile_rows_log2, + context_update_tile_id); + fb(2, tile_size_bytes_minus1); + } else { + infer(context_update_tile_id, 0); + } + + priv->tile_cols = current->tile_cols; + priv->tile_rows = current->tile_rows; + + return 0; +} + +static int FUNC(quantization_params)(CodedBitstreamContext *ctx, RWContext *rw, + AV1RawFrameHeader *current) +{ + CodedBitstreamAV1Context *priv = ctx->priv_data; + const AV1RawSequenceHeader *seq = priv->sequence_header; + int err; + + fb(8, base_q_idx); + + delta_q(delta_q_y_dc); + + if (priv->num_planes > 1) { + if (seq->color_config.separate_uv_delta_q) + flag(diff_uv_delta); + else + infer(diff_uv_delta, 0); + + delta_q(delta_q_u_dc); + delta_q(delta_q_u_ac); + + if (current->diff_uv_delta) { + delta_q(delta_q_v_dc); + delta_q(delta_q_v_ac); + } else { + infer(delta_q_v_dc, current->delta_q_u_dc); + infer(delta_q_v_ac, current->delta_q_u_ac); + } + } else { + infer(delta_q_u_dc, 0); + infer(delta_q_u_ac, 0); + infer(delta_q_v_dc, 0); + infer(delta_q_v_ac, 0); + } + + flag(using_qmatrix); + if (current->using_qmatrix) { + fb(4, qm_y); + fb(4, qm_u); + if (seq->color_config.separate_uv_delta_q) + fb(4, qm_v); + else + infer(qm_v, current->qm_u); + } + + return 0; +} + +static int FUNC(segmentation_params)(CodedBitstreamContext *ctx, RWContext *rw, + AV1RawFrameHeader *current) +{ + static const uint8_t bits[AV1_SEG_LVL_MAX] = { 8, 6, 6, 6, 6, 3, 0, 0 }; + static const uint8_t sign[AV1_SEG_LVL_MAX] = { 1, 1, 1, 1, 1, 0, 0, 0 }; + int i, j, err; + + flag(segmentation_enabled); + + if (current->segmentation_enabled) { + if (current->primary_ref_frame == AV1_PRIMARY_REF_NONE) { + infer(segmentation_update_map, 1); + infer(segmentation_temporal_update, 0); + infer(segmentation_update_data, 1); + } else { + flag(segmentation_update_map); + if (current->segmentation_update_map) + flag(segmentation_temporal_update); + else + infer(segmentation_temporal_update, 0); + flag(segmentation_update_data); + } + + if (current->segmentation_update_data) { + for (i = 0; i < AV1_MAX_SEGMENTS; i++) { + for (j = 0; j < AV1_SEG_LVL_MAX; j++) { + flags(feature_enabled[i][j], 2, i, j); + + if (current->feature_enabled[i][j] && bits[j] > 0) { + if (sign[j]) + sus(1 + bits[j], feature_value[i][j], 2, i, j); + else + fbs(bits[j], feature_value[i][j], 2, i, j); + } else { + infer(feature_value[i][j], 0); + } + } + } + } + } else { + for (i = 0; i < AV1_MAX_SEGMENTS; i++) { + for (j = 0; j < AV1_SEG_LVL_MAX; j++) { + infer(feature_enabled[i][j], 0); + infer(feature_value[i][j], 0); + } + } + } + + return 0; +} + +static int FUNC(delta_q_params)(CodedBitstreamContext *ctx, RWContext *rw, + AV1RawFrameHeader *current) +{ + int err; + + if (current->base_q_idx > 0) + flag(delta_q_present); + else + infer(delta_q_present, 0); + + if (current->delta_q_present) + fb(2, delta_q_res); + + return 0; +} + +static int FUNC(delta_lf_params)(CodedBitstreamContext *ctx, RWContext *rw, + AV1RawFrameHeader *current) +{ + int err; + + if (current->delta_q_present) { + if (!current->allow_intrabc) + flag(delta_lf_present); + else + infer(delta_lf_present, 0); + if (current->delta_lf_present) { + fb(2, delta_lf_res); + flag(delta_lf_multi); + } else { + infer(delta_lf_res, 0); + infer(delta_lf_multi, 0); + } + } else { + infer(delta_lf_present, 0); + infer(delta_lf_res, 0); + infer(delta_lf_multi, 0); + } + + return 0; +} + +static int FUNC(loop_filter_params)(CodedBitstreamContext *ctx, RWContext *rw, + AV1RawFrameHeader *current) +{ + CodedBitstreamAV1Context *priv = ctx->priv_data; + int i, err; + + if (priv->coded_lossless || current->allow_intrabc) { + infer(loop_filter_level[0], 0); + infer(loop_filter_level[1], 0); + infer(loop_filter_ref_deltas[AV1_REF_FRAME_INTRA], 1); + infer(loop_filter_ref_deltas[AV1_REF_FRAME_LAST], 0); + infer(loop_filter_ref_deltas[AV1_REF_FRAME_LAST2], 0); + infer(loop_filter_ref_deltas[AV1_REF_FRAME_LAST3], 0); + infer(loop_filter_ref_deltas[AV1_REF_FRAME_BWDREF], 0); + infer(loop_filter_ref_deltas[AV1_REF_FRAME_GOLDEN], -1); + infer(loop_filter_ref_deltas[AV1_REF_FRAME_ALTREF], -1); + infer(loop_filter_ref_deltas[AV1_REF_FRAME_ALTREF2], -1); + for (i = 0; i < 2; i++) + infer(loop_filter_mode_deltas[i], 0); + return 0; + } + + fb(6, loop_filter_level[0]); + fb(6, loop_filter_level[1]); + + if (priv->num_planes > 1) { + if (current->loop_filter_level[0] || + current->loop_filter_level[1]) { + fb(6, loop_filter_level[2]); + fb(6, loop_filter_level[3]); + } + } + + fb(3, loop_filter_sharpness); + + flag(loop_filter_delta_enabled); + if (current->loop_filter_delta_enabled) { + flag(loop_filter_delta_update); + if (current->loop_filter_delta_update) { + for (i = 0; i < AV1_TOTAL_REFS_PER_FRAME; i++) { + flags(update_ref_delta[i], 1, i); + if (current->update_ref_delta[i]) + sus(1 + 6, loop_filter_ref_deltas[i], 1, i); + } + for (i = 0; i < 2; i++) { + flags(update_mode_delta[i], 1, i); + if (current->update_mode_delta[i]) + sus(1 + 6, loop_filter_mode_deltas[i], 1, i); + } + } + } + + return 0; +} + +static int FUNC(cdef_params)(CodedBitstreamContext *ctx, RWContext *rw, + AV1RawFrameHeader *current) +{ + CodedBitstreamAV1Context *priv = ctx->priv_data; + const AV1RawSequenceHeader *seq = priv->sequence_header; + int i, err; + + if (priv->coded_lossless || current->allow_intrabc || + !seq->enable_cdef) { + infer(cdef_damping_minus_3, 0); + infer(cdef_bits, 0); + infer(cdef_y_pri_strength[0], 0); + infer(cdef_y_sec_strength[0], 0); + infer(cdef_uv_pri_strength[0], 0); + infer(cdef_uv_sec_strength[0], 0); + + return 0; + } + + fb(2, cdef_damping_minus_3); + fb(2, cdef_bits); + + for (i = 0; i < (1 << current->cdef_bits); i++) { + fbs(4, cdef_y_pri_strength[i], 1, i); + fbs(2, cdef_y_sec_strength[i], 1, i); + + if (priv->num_planes > 1) { + fbs(4, cdef_uv_pri_strength[i], 1, i); + fbs(2, cdef_uv_sec_strength[i], 1, i); + } + } + + return 0; +} + +static int FUNC(lr_params)(CodedBitstreamContext *ctx, RWContext *rw, + AV1RawFrameHeader *current) +{ + CodedBitstreamAV1Context *priv = ctx->priv_data; + const AV1RawSequenceHeader *seq = priv->sequence_header; + int uses_lr, uses_chroma_lr; + int i, err; + + if (priv->all_lossless || current->allow_intrabc || + !seq->enable_restoration) { + return 0; + } + + uses_lr = uses_chroma_lr = 0; + for (i = 0; i < priv->num_planes; i++) { + fbs(2, lr_type[i], 1, i); + + if (current->lr_type[i] != 0) { + uses_lr = 1; + if (i > 0) + uses_chroma_lr = 1; + } + } + + if (uses_lr) { + if (seq->use_128x128_superblock) + increment(lr_unit_shift, 1, 2); + else + increment(lr_unit_shift, 0, 2); + + if(seq->color_config.subsampling_x && + seq->color_config.subsampling_y && uses_chroma_lr) { + fb(1, lr_uv_shift); + } else { + infer(lr_uv_shift, 0); + } + } + + return 0; +} + +static int FUNC(read_tx_mode)(CodedBitstreamContext *ctx, RWContext *rw, + AV1RawFrameHeader *current) +{ + CodedBitstreamAV1Context *priv = ctx->priv_data; + int err; + + if (priv->coded_lossless) + infer(tx_mode, 0); + else + increment(tx_mode, 1, 2); + + return 0; +} + +static int FUNC(frame_reference_mode)(CodedBitstreamContext *ctx, RWContext *rw, + AV1RawFrameHeader *current) +{ + int err; + + if (current->frame_type == AV1_FRAME_INTRA_ONLY || + current->frame_type == AV1_FRAME_KEY) + infer(reference_select, 0); + else + flag(reference_select); + + return 0; +} + +static int FUNC(skip_mode_params)(CodedBitstreamContext *ctx, RWContext *rw, + AV1RawFrameHeader *current) +{ + CodedBitstreamAV1Context *priv = ctx->priv_data; + const AV1RawSequenceHeader *seq = priv->sequence_header; + int skip_mode_allowed; + int err; + + if (current->frame_type == AV1_FRAME_KEY || + current->frame_type == AV1_FRAME_INTRA_ONLY || + !current->reference_select || !seq->enable_order_hint) { + skip_mode_allowed = 0; + } else { + int forward_idx, backward_idx; + int forward_hint, backward_hint; + int ref_hint, dist, i; + + forward_idx = -1; + backward_idx = -1; + for (i = 0; i < AV1_REFS_PER_FRAME; i++) { + ref_hint = priv->ref[i].order_hint; + dist = cbs_av1_get_relative_dist(seq, ref_hint, + current->order_hint); + if (dist < 0) { + if (forward_idx < 0 || + cbs_av1_get_relative_dist(seq, ref_hint, + forward_hint) > 0) { + forward_idx = i; + forward_hint = ref_hint; + } + } else if (dist > 0) { + if (backward_idx < 0 || + cbs_av1_get_relative_dist(seq, ref_hint, + backward_hint) < 0) { + backward_idx = i; + backward_hint = ref_hint; + } + } + } + + if (forward_idx < 0) { + skip_mode_allowed = 0; + } else if (backward_idx >= 0) { + skip_mode_allowed = 1; + // Frames for skip mode are forward_idx and backward_idx. + } else { + int second_forward_idx; + int second_forward_hint; + + second_forward_idx = -1; + for (i = 0; i < AV1_REFS_PER_FRAME; i++) { + ref_hint = priv->ref[i].order_hint; + if (cbs_av1_get_relative_dist(seq, ref_hint, + forward_hint) < 0) { + if (second_forward_idx < 0 || + cbs_av1_get_relative_dist(seq, ref_hint, + second_forward_hint) > 0) { + second_forward_idx = i; + second_forward_hint = ref_hint; + } + } + } + + if (second_forward_idx < 0) { + skip_mode_allowed = 0; + } else { + skip_mode_allowed = 1; + // Frames for skip mode are forward_idx and second_forward_idx. + } + } + } + + if (skip_mode_allowed) + flag(skip_mode_present); + else + infer(skip_mode_present, 0); + + return 0; +} + +static int FUNC(global_motion_param)(CodedBitstreamContext *ctx, RWContext *rw, + AV1RawFrameHeader *current, + int type, int ref, int idx) +{ + uint32_t abs_bits, prec_bits, num_syms; + int err; + + if (idx < 2) { + if (type == AV1_WARP_MODEL_TRANSLATION) { + abs_bits = AV1_GM_ABS_TRANS_ONLY_BITS - !current->allow_high_precision_mv; + prec_bits = AV1_GM_TRANS_ONLY_PREC_BITS - !current->allow_high_precision_mv; + } else { + abs_bits = AV1_GM_ABS_TRANS_BITS; + prec_bits = AV1_GM_TRANS_PREC_BITS; + } + } else { + abs_bits = AV1_GM_ABS_ALPHA_BITS; + prec_bits = AV1_GM_ALPHA_PREC_BITS; + } + + num_syms = 2 * (1 << abs_bits) + 1; + subexp(gm_params[ref][idx], num_syms, 2, ref, idx); + + // Actual gm_params value is not reconstructed here. + (void)prec_bits; + + return 0; +} + +static int FUNC(global_motion_params)(CodedBitstreamContext *ctx, RWContext *rw, + AV1RawFrameHeader *current) +{ + int ref, type; + int err; + + if (current->frame_type == AV1_FRAME_KEY || + current->frame_type == AV1_FRAME_INTRA_ONLY) + return 0; + + for (ref = AV1_REF_FRAME_LAST; ref <= AV1_REF_FRAME_ALTREF; ref++) { + flags(is_global[ref], 1, ref); + if (current->is_global[ref]) { + flags(is_rot_zoom[ref], 1, ref); + if (current->is_rot_zoom[ref]) { + type = AV1_WARP_MODEL_ROTZOOM; + } else { + flags(is_translation[ref], 1, ref); + type = current->is_translation[ref] ? AV1_WARP_MODEL_TRANSLATION + : AV1_WARP_MODEL_AFFINE; + } + } else { + type = AV1_WARP_MODEL_IDENTITY; + } + + if (type >= AV1_WARP_MODEL_ROTZOOM) { + CHECK(FUNC(global_motion_param)(ctx, rw, current, type, ref, 2)); + CHECK(FUNC(global_motion_param)(ctx, rw, current, type, ref, 3)); + if (type == AV1_WARP_MODEL_AFFINE) { + CHECK(FUNC(global_motion_param)(ctx, rw, current, type, ref, 4)); + CHECK(FUNC(global_motion_param)(ctx, rw, current, type, ref, 5)); + } else { + // gm_params[ref][4] = -gm_params[ref][3] + // gm_params[ref][5] = gm_params[ref][2] + } + } + if (type >= AV1_WARP_MODEL_TRANSLATION) { + CHECK(FUNC(global_motion_param)(ctx, rw, current, type, ref, 0)); + CHECK(FUNC(global_motion_param)(ctx, rw, current, type, ref, 1)); + } + } + + return 0; +} + +static int FUNC(film_grain_params)(CodedBitstreamContext *ctx, RWContext *rw, + AV1RawFrameHeader *current) +{ + CodedBitstreamAV1Context *priv = ctx->priv_data; + const AV1RawSequenceHeader *seq = priv->sequence_header; + int num_pos_luma, num_pos_chroma; + int i, err; + + if (!seq->film_grain_params_present || + (!current->show_frame && !current->showable_frame)) + return 0; + + flag(apply_grain); + + if (!current->apply_grain) + return 0; + + fb(16, grain_seed); + + if (current->frame_type == AV1_FRAME_INTER) + flag(update_grain); + else + infer(update_grain, 1); + + if (!current->update_grain) { + fb(3, film_grain_params_ref_idx); + return 0; + } + + fb(4, num_y_points); + for (i = 0; i < current->num_y_points; i++) { + fbs(8, point_y_value[i], 1, i); + fbs(8, point_y_scaling[i], 1, i); + } + + if (seq->color_config.mono_chrome) + infer(chroma_scaling_from_luma, 0); + else + flag(chroma_scaling_from_luma); + + if (seq->color_config.mono_chrome || + current->chroma_scaling_from_luma || + (seq->color_config.subsampling_x == 1 && + seq->color_config.subsampling_y == 1 && + current->num_y_points == 0)) { + infer(num_cb_points, 0); + infer(num_cr_points, 0); + } else { + fb(4, num_cb_points); + for (i = 0; i < current->num_cb_points; i++) { + fbs(8, point_cb_value[i], 1, i); + fbs(8, point_cb_scaling[i], 1, i); + } + fb(4, num_cr_points); + for (i = 0; i < current->num_cr_points; i++) { + fbs(8, point_cr_value[i], 1, i); + fbs(8, point_cr_scaling[i], 1, i); + } + } + + fb(2, grain_scaling_minus_8); + fb(2, ar_coeff_lag); + num_pos_luma = 2 * current->ar_coeff_lag * (current->ar_coeff_lag + 1); + if (current->num_y_points) { + num_pos_chroma = num_pos_luma + 1; + for (i = 0; i < num_pos_luma; i++) + fbs(8, ar_coeffs_y_plus_128[i], 1, i); + } else { + num_pos_chroma = num_pos_luma; + } + if (current->chroma_scaling_from_luma || current->num_cb_points) { + for (i = 0; i < num_pos_chroma; i++) + fbs(8, ar_coeffs_cb_plus_128[i], 1, i); + } + if (current->chroma_scaling_from_luma || current->num_cr_points) { + for (i = 0; i < num_pos_chroma; i++) + fbs(8, ar_coeffs_cr_plus_128[i], 1, i); + } + fb(2, ar_coeff_shift_minus_6); + fb(2, grain_scale_shift); + if (current->num_cb_points) { + fb(8, cb_mult); + fb(8, cb_luma_mult); + fb(9, cb_offset); + } + if (current->num_cr_points) { + fb(8, cr_mult); + fb(8, cr_luma_mult); + fb(9, cr_offset); + } + + flag(overlap_flag); + flag(clip_to_restricted_range); + + return 0; +} + +static int FUNC(uncompressed_header)(CodedBitstreamContext *ctx, RWContext *rw, + AV1RawFrameHeader *current) +{ + CodedBitstreamAV1Context *priv = ctx->priv_data; + const AV1RawSequenceHeader *seq; + int id_len, diff_len, all_frames, frame_is_intra, order_hint_bits; + int i, err; + + if (!priv->sequence_header) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "No sequence header available: " + "unable to decode frame header.\n"); + return AVERROR_INVALIDDATA; + } + seq = priv->sequence_header; + + id_len = seq->additional_frame_id_length_minus_1 + + seq->delta_frame_id_length_minus_2 + 3; + all_frames = (1 << AV1_NUM_REF_FRAMES) - 1; + + if (seq->reduced_still_picture_header) { + infer(show_existing_frame, 0); + infer(frame_type, AV1_FRAME_KEY); + infer(show_frame, 1); + infer(showable_frame, 0); + frame_is_intra = 1; + + } else { + flag(show_existing_frame); + + if (current->show_existing_frame) { + AV1ReferenceFrameState *frame; + + fb(3, frame_to_show_map_idx); + frame = &priv->ref[current->frame_to_show_map_idx]; + + if (seq->decoder_model_info_present_flag && + !seq->timing_info.equal_picture_interval) { + fb(seq->decoder_model_info.frame_presentation_time_length_minus_1 + 1, + frame_presentation_time); + } + + if (seq->frame_id_numbers_present_flag) + fb(id_len, display_frame_id); + + if (frame->frame_type == AV1_FRAME_KEY) + infer(refresh_frame_flags, all_frames); + else + infer(refresh_frame_flags, 0); + + return 0; + } + + fb(2, frame_type); + frame_is_intra = (current->frame_type == AV1_FRAME_INTRA_ONLY || + current->frame_type == AV1_FRAME_KEY); + + flag(show_frame); + if (current->show_frame && + seq->decoder_model_info_present_flag && + !seq->timing_info.equal_picture_interval) { + fb(seq->decoder_model_info.frame_presentation_time_length_minus_1 + 1, + frame_presentation_time); + } + if (current->show_frame) + infer(showable_frame, current->frame_type != AV1_FRAME_KEY); + else + flag(showable_frame); + + if (current->frame_type == AV1_FRAME_SWITCH || + (current->frame_type == AV1_FRAME_KEY && current->show_frame)) + infer(error_resilient_mode, 1); + else + flag(error_resilient_mode); + } + + if (current->frame_type == AV1_FRAME_KEY && current->show_frame) { + for (i = 0; i < AV1_NUM_REF_FRAMES; i++) { + priv->ref[i].valid = 0; + priv->ref[i].order_hint = 0; + } + } + + flag(disable_cdf_update); + + if (seq->seq_force_screen_content_tools == + AV1_SELECT_SCREEN_CONTENT_TOOLS) { + flag(allow_screen_content_tools); + } else { + infer(allow_screen_content_tools, + seq->seq_force_screen_content_tools); + } + if (current->allow_screen_content_tools) { + if (seq->seq_force_integer_mv == AV1_SELECT_INTEGER_MV) + flag(force_integer_mv); + else + infer(force_integer_mv, seq->seq_force_integer_mv); + } else { + infer(force_integer_mv, 0); + } + + if (seq->frame_id_numbers_present_flag) { + fb(id_len, current_frame_id); + + diff_len = seq->delta_frame_id_length_minus_2 + 2; + for (i = 0; i < AV1_NUM_REF_FRAMES; i++) { + if (current->current_frame_id > (1 << diff_len)) { + if (priv->ref[i].frame_id > current->current_frame_id || + priv->ref[i].frame_id < (current->current_frame_id - + (1 << diff_len))) + priv->ref[i].valid = 0; + } else { + if (priv->ref[i].frame_id > current->current_frame_id && + priv->ref[i].frame_id < ((1 << id_len) + + current->current_frame_id - + (1 << diff_len))) + priv->ref[i].valid = 0; + } + } + } else { + infer(current_frame_id, 0); + } + + if (current->frame_type == AV1_FRAME_SWITCH) + infer(frame_size_override_flag, 1); + else if(seq->reduced_still_picture_header) + infer(frame_size_override_flag, 0); + else + flag(frame_size_override_flag); + + order_hint_bits = + seq->enable_order_hint ? seq->order_hint_bits_minus_1 + 1 : 0; + if (order_hint_bits > 0) + fb(order_hint_bits, order_hint); + else + infer(order_hint, 0); + + if (frame_is_intra || current->error_resilient_mode) + infer(primary_ref_frame, AV1_PRIMARY_REF_NONE); + else + fb(3, primary_ref_frame); + + if (seq->decoder_model_info_present_flag) { + flag(buffer_removal_time_present_flag); + if (current->buffer_removal_time_present_flag) { + for (i = 0; i <= seq->operating_points_cnt_minus_1; i++) { + if (seq->decoder_model_present_for_this_op[i]) { + int op_pt_idc = seq->operating_point_idc[i]; + int in_temporal_layer = (op_pt_idc >> priv->temporal_id ) & 1; + int in_spatial_layer = (op_pt_idc >> (priv->spatial_id + 8)) & 1; + if (seq->operating_point_idc[i] == 0 || + in_temporal_layer || in_spatial_layer) { + fbs(seq->decoder_model_info.buffer_removal_time_length_minus_1 + 1, + buffer_removal_time[i], 1, i); + } + } + } + } + } + + if (current->frame_type == AV1_FRAME_SWITCH || + (current->frame_type == AV1_FRAME_KEY && current->show_frame)) + infer(refresh_frame_flags, all_frames); + else + fb(8, refresh_frame_flags); + + if (!frame_is_intra || current->refresh_frame_flags != all_frames) { + if (current->error_resilient_mode && seq->enable_order_hint) { + for (i = 0; i < AV1_NUM_REF_FRAMES; i++) { + fbs(order_hint_bits, ref_order_hint[i], 1, i); + if (current->ref_order_hint[i] != priv->ref[i].order_hint) + priv->ref[i].valid = 0; + } + } + } + + if (current->frame_type == AV1_FRAME_KEY || + current->frame_type == AV1_FRAME_INTRA_ONLY) { + CHECK(FUNC(frame_size)(ctx, rw, current)); + CHECK(FUNC(render_size)(ctx, rw, current)); + + if (current->allow_screen_content_tools && + priv->upscaled_width == priv->frame_width) + flag(allow_intrabc); + else + infer(allow_intrabc, 0); + + } else { + if (!seq->enable_order_hint) { + infer(frame_refs_short_signaling, 0); + } else { + flag(frame_refs_short_signaling); + if (current->frame_refs_short_signaling) { + fb(3, last_frame_idx); + fb(3, golden_frame_idx); + + for (i = 0; i < AV1_REFS_PER_FRAME; i++) { + if (i == 0) + infer(ref_frame_idx[i], current->last_frame_idx); + else if (i == AV1_REF_FRAME_GOLDEN - + AV1_REF_FRAME_LAST) + infer(ref_frame_idx[i], current->golden_frame_idx); + else + infer(ref_frame_idx[i], -1); + } + } + } + + for (i = 0; i < AV1_REFS_PER_FRAME; i++) { + if (!current->frame_refs_short_signaling) + fbs(3, ref_frame_idx[i], 1, i); + if (seq->frame_id_numbers_present_flag) { + fbs(seq->delta_frame_id_length_minus_2 + 2, + delta_frame_id_minus1[i], 1, i); + } + } + + if (current->frame_size_override_flag && + !current->error_resilient_mode) { + CHECK(FUNC(frame_size_with_refs)(ctx, rw, current)); + } else { + CHECK(FUNC(frame_size)(ctx, rw, current)); + CHECK(FUNC(render_size)(ctx, rw, current)); + } + + if (current->force_integer_mv) + infer(allow_high_precision_mv, 0); + else + flag(allow_high_precision_mv); + + CHECK(FUNC(interpolation_filter)(ctx, rw, current)); + + flag(is_motion_mode_switchable); + + if (current->error_resilient_mode || + !seq->enable_ref_frame_mvs) + infer(use_ref_frame_mvs, 0); + else + flag(use_ref_frame_mvs); + + infer(allow_intrabc, 0); + } + + if (!frame_is_intra) { + // Derive reference frame sign biases. + } + + if (seq->reduced_still_picture_header || current->disable_cdf_update) + infer(disable_frame_end_update_cdf, 1); + else + flag(disable_frame_end_update_cdf); + + if (current->primary_ref_frame == AV1_PRIMARY_REF_NONE) { + // Init non-coeff CDFs. + // Setup past independence. + } else { + // Load CDF tables from previous frame. + // Load params from previous frame. + } + + if (current->use_ref_frame_mvs) { + // Perform motion field estimation process. + } + + CHECK(FUNC(tile_info)(ctx, rw, current)); + + CHECK(FUNC(quantization_params)(ctx, rw, current)); + + CHECK(FUNC(segmentation_params)(ctx, rw, current)); + + CHECK(FUNC(delta_q_params)(ctx, rw, current)); + + CHECK(FUNC(delta_lf_params)(ctx, rw, current)); + + // Init coeff CDFs / load previous segments. + + priv->coded_lossless = 1; + for (i = 0; i < AV1_MAX_SEGMENTS; i++) { + int qindex; + if (current->feature_enabled[i][AV1_SEG_LVL_ALT_Q]) { + qindex = (current->base_q_idx + + current->feature_value[i][AV1_SEG_LVL_ALT_Q]); + } else { + qindex = current->base_q_idx; + } + qindex = av_clip_uintp2(qindex, 8); + + if (qindex || current->delta_q_y_dc || + current->delta_q_u_ac || current->delta_q_u_dc || + current->delta_q_v_ac || current->delta_q_v_dc) { + priv->coded_lossless = 0; + } + } + priv->all_lossless = priv->coded_lossless && + priv->frame_width == priv->upscaled_width; + + CHECK(FUNC(loop_filter_params)(ctx, rw, current)); + + CHECK(FUNC(cdef_params)(ctx, rw, current)); + + CHECK(FUNC(lr_params)(ctx, rw, current)); + + CHECK(FUNC(read_tx_mode)(ctx, rw, current)); + + CHECK(FUNC(frame_reference_mode)(ctx, rw, current)); + + CHECK(FUNC(skip_mode_params)(ctx, rw, current)); + + if (frame_is_intra || current->error_resilient_mode || + !seq->enable_warped_motion) + infer(allow_warped_motion, 0); + else + flag(allow_warped_motion); + + flag(reduced_tx_set); + + CHECK(FUNC(global_motion_params)(ctx, rw, current)); + + CHECK(FUNC(film_grain_params)(ctx, rw, current)); + + for (i = 0; i < AV1_NUM_REF_FRAMES; i++) { + if (current->refresh_frame_flags & (1 << i)) { + priv->ref[i] = (AV1ReferenceFrameState) { + .valid = 1, + .frame_id = current->current_frame_id, + .upscaled_width = priv->upscaled_width, + .frame_width = priv->frame_width, + .frame_height = priv->frame_height, + .render_width = priv->render_width, + .render_height = priv->render_height, + .frame_type = current->frame_type, + .subsampling_x = seq->color_config.subsampling_x, + .subsampling_y = seq->color_config.subsampling_y, + .bit_depth = priv->bit_depth, + .order_hint = current->order_hint, + }; + } + } + + av_log(ctx->log_ctx, AV_LOG_DEBUG, "Frame %d: size %dx%d " + "upscaled %d render %dx%d subsample %dx%d " + "bitdepth %d tiles %dx%d.\n", current->order_hint, + priv->frame_width, priv->frame_height, priv->upscaled_width, + priv->render_width, priv->render_height, + seq->color_config.subsampling_x + 1, + seq->color_config.subsampling_y + 1, priv->bit_depth, + priv->tile_rows, priv->tile_cols); + + return 0; +} + +static int FUNC(frame_header_obu)(CodedBitstreamContext *ctx, RWContext *rw, + AV1RawFrameHeader *current, int redundant, + AVBufferRef *rw_buffer_ref) +{ + CodedBitstreamAV1Context *priv = ctx->priv_data; + int start_pos, fh_bits, fh_bytes, err; + uint8_t *fh_start; + + if (priv->seen_frame_header) { + if (!redundant) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid repeated " + "frame header OBU.\n"); + return AVERROR_INVALIDDATA; + } else { + GetBitContext fh; + size_t i, b; + uint32_t val; + + HEADER("Redundant Frame Header"); + + av_assert0(priv->frame_header_ref && priv->frame_header); + + init_get_bits(&fh, priv->frame_header, + priv->frame_header_size); + for (i = 0; i < priv->frame_header_size; i += 8) { + b = FFMIN(priv->frame_header_size - i, 8); + val = get_bits(&fh, b); + xf(b, frame_header_copy[i], + val, val, val, 1, i / 8); + } + } + } else { + if (redundant) + HEADER("Redundant Frame Header (used as Frame Header)"); + else + HEADER("Frame Header"); + + priv->seen_frame_header = 1; + +#ifdef READ + start_pos = get_bits_count(rw); +#else + start_pos = put_bits_count(rw); +#endif + + CHECK(FUNC(uncompressed_header)(ctx, rw, current)); + + if (current->show_existing_frame) { + priv->seen_frame_header = 0; + } else { + priv->seen_frame_header = 1; + + av_buffer_unref(&priv->frame_header_ref); + +#ifdef READ + fh_bits = get_bits_count(rw) - start_pos; + fh_start = (uint8_t*)rw->buffer + start_pos / 8; +#else + // Need to flush the bitwriter so that we can copy its output, + // but use a copy so we don't affect the caller's structure. + { + PutBitContext tmp = *rw; + flush_put_bits(&tmp); + } + + fh_bits = put_bits_count(rw) - start_pos; + fh_start = rw->buf + start_pos / 8; +#endif + fh_bytes = (fh_bits + 7) / 8; + + priv->frame_header_size = fh_bits; + + if (rw_buffer_ref) { + priv->frame_header_ref = av_buffer_ref(rw_buffer_ref); + if (!priv->frame_header_ref) + return AVERROR(ENOMEM); + priv->frame_header = fh_start; + } else { + priv->frame_header_ref = + av_buffer_alloc(fh_bytes + AV_INPUT_BUFFER_PADDING_SIZE); + if (!priv->frame_header_ref) + return AVERROR(ENOMEM); + priv->frame_header = priv->frame_header_ref->data; + memcpy(priv->frame_header, fh_start, fh_bytes); + } + } + } + + return 0; +} + +static int FUNC(tile_group_obu)(CodedBitstreamContext *ctx, RWContext *rw, + AV1RawTileGroup *current) +{ + CodedBitstreamAV1Context *priv = ctx->priv_data; + int num_tiles, tile_bits; + int err; + + HEADER("Tile Group"); + + num_tiles = priv->tile_cols * priv->tile_rows; + if (num_tiles > 1) + flag(tile_start_and_end_present_flag); + else + infer(tile_start_and_end_present_flag, 0); + + if (num_tiles == 1 || !current->tile_start_and_end_present_flag) { + infer(tg_start, 0); + infer(tg_end, num_tiles - 1); + } else { + tile_bits = cbs_av1_tile_log2(1, priv->tile_cols) + + cbs_av1_tile_log2(1, priv->tile_rows); + fb(tile_bits, tg_start); + fb(tile_bits, tg_end); + } + + CHECK(FUNC(byte_alignment)(ctx, rw)); + + // Reset header for next frame. + if (current->tg_end == num_tiles - 1) + priv->seen_frame_header = 0; + + // Tile data follows. + + return 0; +} + +static int FUNC(frame_obu)(CodedBitstreamContext *ctx, RWContext *rw, + AV1RawFrame *current, + AVBufferRef *rw_buffer_ref) +{ + int err; + + CHECK(FUNC(frame_header_obu)(ctx, rw, ¤t->header, + 0, rw_buffer_ref)); + + CHECK(FUNC(byte_alignment)(ctx, rw)); + + CHECK(FUNC(tile_group_obu)(ctx, rw, ¤t->tile_group)); + + return 0; +} + +static int FUNC(tile_list_obu)(CodedBitstreamContext *ctx, RWContext *rw, + AV1RawTileList *current) +{ + int err; + + fb(8, output_frame_width_in_tiles_minus_1); + fb(8, output_frame_height_in_tiles_minus_1); + + fb(16, tile_count_minus_1); + + // Tile data follows. + + return 0; +} + +static int FUNC(metadata_hdr_cll)(CodedBitstreamContext *ctx, RWContext *rw, + AV1RawMetadataHDRCLL *current) +{ + int err; + + fb(16, max_cll); + fb(16, max_fall); + + return 0; +} + +static int FUNC(metadata_hdr_mdcv)(CodedBitstreamContext *ctx, RWContext *rw, + AV1RawMetadataHDRMDCV *current) +{ + int err, i; + + for (i = 0; i < 3; i++) { + fbs(16, primary_chromaticity_x[i], 1, i); + fbs(16, primary_chromaticity_y[i], 1, i); + } + + fb(16, white_point_chromaticity_x); + fb(16, white_point_chromaticity_y); + + fc(32, luminance_max, 1, MAX_UINT_BITS(32)); + // luminance_min must be lower than luminance_max. Convert luminance_max from + // 24.8 fixed point to 18.14 fixed point in order to compare them. + fc(32, luminance_min, 0, FFMIN(((uint64_t)current->luminance_max << 6) - 1, + MAX_UINT_BITS(32))); + + return 0; +} + +static int FUNC(scalability_structure)(CodedBitstreamContext *ctx, RWContext *rw, + AV1RawMetadataScalability *current) +{ + CodedBitstreamAV1Context *priv = ctx->priv_data; + const AV1RawSequenceHeader *seq; + int err, i, j; + + if (!priv->sequence_header) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "No sequence header available: " + "unable to parse scalability metadata.\n"); + return AVERROR_INVALIDDATA; + } + seq = priv->sequence_header; + + fb(2, spatial_layers_cnt_minus_1); + flag(spatial_layer_dimensions_present_flag); + flag(spatial_layer_description_present_flag); + flag(temporal_group_description_present_flag); + fc(3, scalability_structure_reserved_3bits, 0, 0); + if (current->spatial_layer_dimensions_present_flag) { + for (i = 0; i <= current->spatial_layers_cnt_minus_1; i++) { + fcs(16, spatial_layer_max_width[i], + 0, seq->max_frame_width_minus_1 + 1, 1, i); + fcs(16, spatial_layer_max_height[i], + 0, seq->max_frame_height_minus_1 + 1, 1, i); + } + } + if (current->spatial_layer_description_present_flag) { + for (i = 0; i <= current->spatial_layers_cnt_minus_1; i++) + fbs(8, spatial_layer_ref_id[i], 1, i); + } + if (current->temporal_group_description_present_flag) { + fb(8, temporal_group_size); + for (i = 0; i < current->temporal_group_size; i++) { + fbs(3, temporal_group_temporal_id[i], 1, i); + flags(temporal_group_temporal_switching_up_point_flag[i], 1, i); + flags(temporal_group_spatial_switching_up_point_flag[i], 1, i); + fbs(3, temporal_group_ref_cnt[i], 1, i); + for (j = 0; j < current->temporal_group_ref_cnt[i]; j++) { + fbs(8, temporal_group_ref_pic_diff[i][j], 2, i, j); + } + } + } + + return 0; +} + +static int FUNC(metadata_scalability)(CodedBitstreamContext *ctx, RWContext *rw, + AV1RawMetadataScalability *current) +{ + int err; + + fb(8, scalability_mode_idc); + + if (current->scalability_mode_idc == AV1_SCALABILITY_SS) + CHECK(FUNC(scalability_structure)(ctx, rw, current)); + + return 0; +} + +static int FUNC(metadata_itut_t35)(CodedBitstreamContext *ctx, RWContext *rw, + AV1RawMetadataITUTT35 *current) +{ + int err; + size_t i; + + fb(8, itu_t_t35_country_code); + if (current->itu_t_t35_country_code == 0xff) + fb(8, itu_t_t35_country_code_extension_byte); + +#ifdef READ + // The payload runs up to the start of the trailing bits, but there might + // be arbitrarily many trailing zeroes so we need to read through twice. + current->payload_size = cbs_av1_get_payload_bytes_left(rw); + + current->payload_ref = av_buffer_alloc(current->payload_size); + if (!current->payload_ref) + return AVERROR(ENOMEM); + current->payload = current->payload_ref->data; +#endif + + for (i = 0; i < current->payload_size; i++) + xf(8, itu_t_t35_payload_bytes[i], current->payload[i], + 0x00, 0xff, 1, i); + + return 0; +} + +static int FUNC(metadata_timecode)(CodedBitstreamContext *ctx, RWContext *rw, + AV1RawMetadataTimecode *current) +{ + int err; + + fb(5, counting_type); + flag(full_timestamp_flag); + flag(discontinuity_flag); + flag(cnt_dropped_flag); + fb(9, n_frames); + + if (current->full_timestamp_flag) { + fc(6, seconds_value, 0, 59); + fc(6, minutes_value, 0, 59); + fc(5, hours_value, 0, 23); + } else { + flag(seconds_flag); + if (current->seconds_flag) { + fc(6, seconds_value, 0, 59); + flag(minutes_flag); + if (current->minutes_flag) { + fc(6, minutes_value, 0, 59); + flag(hours_flag); + if (current->hours_flag) + fc(5, hours_value, 0, 23); + } + } + } + + fb(5, time_offset_length); + if (current->time_offset_length > 0) + fb(current->time_offset_length, time_offset_value); + else + infer(time_offset_length, 0); + + return 0; +} + +static int FUNC(metadata_obu)(CodedBitstreamContext *ctx, RWContext *rw, + AV1RawMetadata *current) +{ + int err; + + leb128(metadata_type); + + switch (current->metadata_type) { + case AV1_METADATA_TYPE_HDR_CLL: + CHECK(FUNC(metadata_hdr_cll)(ctx, rw, ¤t->metadata.hdr_cll)); + break; + case AV1_METADATA_TYPE_HDR_MDCV: + CHECK(FUNC(metadata_hdr_mdcv)(ctx, rw, ¤t->metadata.hdr_mdcv)); + break; + case AV1_METADATA_TYPE_SCALABILITY: + CHECK(FUNC(metadata_scalability)(ctx, rw, ¤t->metadata.scalability)); + break; + case AV1_METADATA_TYPE_ITUT_T35: + CHECK(FUNC(metadata_itut_t35)(ctx, rw, ¤t->metadata.itut_t35)); + break; + case AV1_METADATA_TYPE_TIMECODE: + CHECK(FUNC(metadata_timecode)(ctx, rw, ¤t->metadata.timecode)); + break; + default: + // Unknown metadata type. + return AVERROR_PATCHWELCOME; + } + + return 0; +} + +static int FUNC(padding_obu)(CodedBitstreamContext *ctx, RWContext *rw, + AV1RawPadding *current) +{ + int i, err; + + HEADER("Padding"); + +#ifdef READ + // The payload runs up to the start of the trailing bits, but there might + // be arbitrarily many trailing zeroes so we need to read through twice. + current->payload_size = cbs_av1_get_payload_bytes_left(rw); + + current->payload_ref = av_buffer_alloc(current->payload_size); + if (!current->payload_ref) + return AVERROR(ENOMEM); + current->payload = current->payload_ref->data; +#endif + + for (i = 0; i < current->payload_size; i++) + xf(8, obu_padding_byte[i], current->payload[i], 0x00, 0xff, 1, i); + + return 0; +} diff --git a/libavcodec/cbs_h264.h b/libavcodec/cbs_h264.h index 2219d9da8..b39e7480c 100644 --- a/libavcodec/cbs_h264.h +++ b/libavcodec/cbs_h264.h @@ -38,7 +38,6 @@ enum { typedef struct H264RawNALUnitHeader { - uint8_t forbidden_zero_bit; uint8_t nal_ref_idc; uint8_t nal_unit_type; @@ -253,7 +252,7 @@ typedef struct H264RawSEIPicTimestamp { uint8_t minutes_value; uint8_t hours_flag; uint8_t hours_value; - uint32_t time_offset; + int32_t time_offset; } H264RawSEIPicTimestamp; typedef struct H264RawSEIPicTiming { @@ -264,6 +263,17 @@ typedef struct H264RawSEIPicTiming { H264RawSEIPicTimestamp timestamp[3]; } H264RawSEIPicTiming; +typedef struct H264RawSEIPanScanRect { + uint32_t pan_scan_rect_id; + uint8_t pan_scan_rect_cancel_flag; + uint8_t pan_scan_cnt_minus1; + int32_t pan_scan_rect_left_offset[3]; + int32_t pan_scan_rect_right_offset[3]; + int32_t pan_scan_rect_top_offset[3]; + int32_t pan_scan_rect_bottom_offset[3]; + uint16_t pan_scan_rect_repetition_period; +} H264RawSEIPanScanRect; + typedef struct H264RawSEIUserDataRegistered { uint8_t itu_t_t35_country_code; uint8_t itu_t_t35_country_code_extension_byte; @@ -295,17 +305,34 @@ typedef struct H264RawSEIDisplayOrientation { uint8_t display_orientation_extension_flag; } H264RawSEIDisplayOrientation; +typedef struct H264RawSEIMasteringDisplayColourVolume { + uint16_t display_primaries_x[3]; + uint16_t display_primaries_y[3]; + uint16_t white_point_x; + uint16_t white_point_y; + uint32_t max_display_mastering_luminance; + uint32_t min_display_mastering_luminance; +} H264RawSEIMasteringDisplayColourVolume; + +typedef struct H264RawSEIAlternativeTransferCharacteristics { + uint8_t preferred_transfer_characteristics; +} H264RawSEIAlternativeTransferCharacteristics; + typedef struct H264RawSEIPayload { uint32_t payload_type; uint32_t payload_size; union { H264RawSEIBufferingPeriod buffering_period; H264RawSEIPicTiming pic_timing; + H264RawSEIPanScanRect pan_scan_rect; // H264RawSEIFiller filler -> no fields. H264RawSEIUserDataRegistered user_data_registered; H264RawSEIUserDataUnregistered user_data_unregistered; H264RawSEIRecoveryPoint recovery_point; H264RawSEIDisplayOrientation display_orientation; + H264RawSEIMasteringDisplayColourVolume mastering_display_colour_volume; + H264RawSEIAlternativeTransferCharacteristics + alternative_transfer_characteristics; struct { uint8_t *data; size_t data_length; @@ -421,6 +448,8 @@ typedef struct CodedBitstreamH264Context { // All currently available parameter sets. These are updated when // any parameter set NAL unit is read/written with this context. + AVBufferRef *sps_ref[H264_MAX_SPS_COUNT]; + AVBufferRef *pps_ref[H264_MAX_PPS_COUNT]; H264RawSPS *sps[H264_MAX_SPS_COUNT]; H264RawPPS *pps[H264_MAX_PPS_COUNT]; @@ -449,10 +478,13 @@ int ff_cbs_h264_add_sei_message(CodedBitstreamContext *ctx, * * Deletes from nal_unit, which must be an SEI NAL unit. If this is the * last message in nal_unit, also deletes it from access_unit. + * + * Requires nal_unit to be a unit in access_unit and position to be >= 0 + * and < the payload count of the SEI nal_unit. */ -int ff_cbs_h264_delete_sei_message(CodedBitstreamContext *ctx, - CodedBitstreamFragment *access_unit, - CodedBitstreamUnit *nal_unit, - int position); +void ff_cbs_h264_delete_sei_message(CodedBitstreamContext *ctx, + CodedBitstreamFragment *access_unit, + CodedBitstreamUnit *nal_unit, + int position); #endif /* AVCODEC_CBS_H264_H */ diff --git a/libavcodec/cbs_h2645.c b/libavcodec/cbs_h2645.c index 5585831cf..c95f1308e 100644 --- a/libavcodec/cbs_h2645.c +++ b/libavcodec/cbs_h2645.c @@ -24,15 +24,16 @@ #include "cbs_internal.h" #include "cbs_h264.h" #include "cbs_h265.h" -#include "golomb.h" #include "h264.h" #include "h264_sei.h" #include "h2645_parse.h" #include "hevc.h" +#include "hevc_sei.h" static int cbs_read_ue_golomb(CodedBitstreamContext *ctx, GetBitContext *gbc, - const char *name, uint32_t *write_to, + const char *name, const int *subscripts, + uint32_t *write_to, uint32_t range_min, uint32_t range_max) { uint32_t value; @@ -68,7 +69,8 @@ static int cbs_read_ue_golomb(CodedBitstreamContext *ctx, GetBitContext *gbc, --value; if (ctx->trace_enable) - ff_cbs_trace_syntax_element(ctx, position, name, bits, value); + ff_cbs_trace_syntax_element(ctx, position, name, subscripts, + bits, value); if (value < range_min || value > range_max) { av_log(ctx->log_ctx, AV_LOG_ERROR, "%s out of range: " @@ -82,7 +84,8 @@ static int cbs_read_ue_golomb(CodedBitstreamContext *ctx, GetBitContext *gbc, } static int cbs_read_se_golomb(CodedBitstreamContext *ctx, GetBitContext *gbc, - const char *name, int32_t *write_to, + const char *name, const int *subscripts, + int32_t *write_to, int32_t range_min, int32_t range_max) { int32_t value; @@ -122,7 +125,8 @@ static int cbs_read_se_golomb(CodedBitstreamContext *ctx, GetBitContext *gbc, value = v / 2; if (ctx->trace_enable) - ff_cbs_trace_syntax_element(ctx, position, name, bits, value); + ff_cbs_trace_syntax_element(ctx, position, name, subscripts, + bits, value); if (value < range_min || value > range_max) { av_log(ctx->log_ctx, AV_LOG_ERROR, "%s out of range: " @@ -136,7 +140,8 @@ static int cbs_read_se_golomb(CodedBitstreamContext *ctx, GetBitContext *gbc, } static int cbs_write_ue_golomb(CodedBitstreamContext *ctx, PutBitContext *pbc, - const char *name, uint32_t value, + const char *name, const int *subscripts, + uint32_t value, uint32_t range_min, uint32_t range_max) { int len; @@ -164,7 +169,8 @@ static int cbs_write_ue_golomb(CodedBitstreamContext *ctx, PutBitContext *pbc, bits[len + i + 1] = (value + 1) >> (len - i - 1) & 1 ? '1' : '0'; bits[len + len + 1] = 0; - ff_cbs_trace_syntax_element(ctx, put_bits_count(pbc), name, bits, value); + ff_cbs_trace_syntax_element(ctx, put_bits_count(pbc), + name, subscripts, bits, value); } put_bits(pbc, len, 0); @@ -177,7 +183,8 @@ static int cbs_write_ue_golomb(CodedBitstreamContext *ctx, PutBitContext *pbc, } static int cbs_write_se_golomb(CodedBitstreamContext *ctx, PutBitContext *pbc, - const char *name, int32_t value, + const char *name, const int *subscripts, + int32_t value, int32_t range_min, int32_t range_max) { int len; @@ -213,7 +220,8 @@ static int cbs_write_se_golomb(CodedBitstreamContext *ctx, PutBitContext *pbc, bits[len + i + 1] = (uvalue + 1) >> (len - i - 1) & 1 ? '1' : '0'; bits[len + len + 1] = 0; - ff_cbs_trace_syntax_element(ctx, put_bits_count(pbc), name, bits, value); + ff_cbs_trace_syntax_element(ctx, put_bits_count(pbc), + name, subscripts, bits, value); } put_bits(pbc, len, 0); @@ -239,39 +247,77 @@ static int cbs_write_se_golomb(CodedBitstreamContext *ctx, PutBitContext *pbc, #define FUNC_H264(rw, name) FUNC_NAME(rw, h264, name) #define FUNC_H265(rw, name) FUNC_NAME(rw, h265, name) +#define SUBSCRIPTS(subs, ...) (subs > 0 ? ((int[subs + 1]){ subs, __VA_ARGS__ }) : NULL) + +#define u(width, name, range_min, range_max) \ + xu(width, name, current->name, range_min, range_max, 0) +#define ub(width, name) \ + xu(width, name, current->name, 0, MAX_UINT_BITS(width), 0) +#define flag(name) ub(1, name) +#define ue(name, range_min, range_max) \ + xue(name, current->name, range_min, range_max, 0) +#define i(width, name, range_min, range_max) \ + xi(width, name, current->name, range_min, range_max, 0) +#define ib(width, name) \ + xi(width, name, current->name, MIN_INT_BITS(width), MAX_INT_BITS(width), 0) +#define se(name, range_min, range_max) \ + xse(name, current->name, range_min, range_max, 0) + +#define us(width, name, range_min, range_max, subs, ...) \ + xu(width, name, current->name, range_min, range_max, subs, __VA_ARGS__) +#define ubs(width, name, subs, ...) \ + xu(width, name, current->name, 0, MAX_UINT_BITS(width), subs, __VA_ARGS__) +#define flags(name, subs, ...) \ + xu(1, name, current->name, 0, 1, subs, __VA_ARGS__) +#define ues(name, range_min, range_max, subs, ...) \ + xue(name, current->name, range_min, range_max, subs, __VA_ARGS__) +#define is(width, name, range_min, range_max, subs, ...) \ + xi(width, name, current->name, range_min, range_max, subs, __VA_ARGS__) +#define ibs(width, name, subs, ...) \ + xi(width, name, current->name, MIN_INT_BITS(width), MAX_INT_BITS(width), subs, __VA_ARGS__) +#define ses(name, range_min, range_max, subs, ...) \ + xse(name, current->name, range_min, range_max, subs, __VA_ARGS__) + +#define fixed(width, name, value) do { \ + av_unused uint32_t fixed_value = value; \ + xu(width, name, fixed_value, value, value, 0); \ + } while (0) + #define READ #define READWRITE read #define RWContext GetBitContext -#define xu(width, name, var, range_min, range_max) do { \ +#define xu(width, name, var, range_min, range_max, subs, ...) do { \ uint32_t value = range_min; \ CHECK(ff_cbs_read_unsigned(ctx, rw, width, #name, \ + SUBSCRIPTS(subs, __VA_ARGS__), \ &value, range_min, range_max)); \ var = value; \ } while (0) -#define xue(name, var, range_min, range_max) do { \ +#define xue(name, var, range_min, range_max, subs, ...) do { \ uint32_t value = range_min; \ CHECK(cbs_read_ue_golomb(ctx, rw, #name, \ + SUBSCRIPTS(subs, __VA_ARGS__), \ &value, range_min, range_max)); \ var = value; \ } while (0) -#define xse(name, var, range_min, range_max) do { \ +#define xi(width, name, var, range_min, range_max, subs, ...) do { \ + int32_t value = range_min; \ + CHECK(ff_cbs_read_signed(ctx, rw, width, #name, \ + SUBSCRIPTS(subs, __VA_ARGS__), \ + &value, range_min, range_max)); \ + var = value; \ + } while (0) +#define xse(name, var, range_min, range_max, subs, ...) do { \ int32_t value = range_min; \ CHECK(cbs_read_se_golomb(ctx, rw, #name, \ + SUBSCRIPTS(subs, __VA_ARGS__), \ &value, range_min, range_max)); \ var = value; \ } while (0) -#define u(width, name, range_min, range_max) \ - xu(width, name, current->name, range_min, range_max) -#define flag(name) u(1, name, 0, 1) -#define ue(name, range_min, range_max) \ - xue(name, current->name, range_min, range_max) -#define se(name, range_min, range_max) \ - xse(name, current->name, range_min, range_max) - #define infer(name, value) do { \ current->name = value; \ } while (0) @@ -281,9 +327,11 @@ static int cbs_h2645_read_more_rbsp_data(GetBitContext *gbc) int bits_left = get_bits_left(gbc); if (bits_left > 8) return 1; - if (show_bits(gbc, bits_left) == 1 << (bits_left - 1)) + if (bits_left == 0) return 0; - return 1; + if (show_bits(gbc, bits_left) & MAX_UINT_BITS(bits_left - 1)) + return 1; + return 0; } #define more_rbsp_data(var) ((var) = cbs_h2645_read_more_rbsp_data(rw)) @@ -291,7 +339,8 @@ static int cbs_h2645_read_more_rbsp_data(GetBitContext *gbc) #define byte_alignment(rw) (get_bits_count(rw) % 8) #define allocate(name, size) do { \ - name ## _ref = av_buffer_allocz(size); \ + name ## _ref = av_buffer_allocz(size + \ + AV_INPUT_BUFFER_PADDING_SIZE); \ if (!name ## _ref) \ return AVERROR(ENOMEM); \ name = name ## _ref->data; \ @@ -309,12 +358,9 @@ static int cbs_h2645_read_more_rbsp_data(GetBitContext *gbc) #undef READWRITE #undef RWContext #undef xu +#undef xi #undef xue #undef xse -#undef u -#undef flag -#undef ue -#undef se #undef infer #undef more_rbsp_data #undef byte_alignment @@ -325,30 +371,31 @@ static int cbs_h2645_read_more_rbsp_data(GetBitContext *gbc) #define READWRITE write #define RWContext PutBitContext -#define xu(width, name, var, range_min, range_max) do { \ +#define xu(width, name, var, range_min, range_max, subs, ...) do { \ uint32_t value = var; \ CHECK(ff_cbs_write_unsigned(ctx, rw, width, #name, \ + SUBSCRIPTS(subs, __VA_ARGS__), \ value, range_min, range_max)); \ } while (0) -#define xue(name, var, range_min, range_max) do { \ +#define xue(name, var, range_min, range_max, subs, ...) do { \ uint32_t value = var; \ CHECK(cbs_write_ue_golomb(ctx, rw, #name, \ + SUBSCRIPTS(subs, __VA_ARGS__), \ value, range_min, range_max)); \ } while (0) -#define xse(name, var, range_min, range_max) do { \ +#define xi(width, name, var, range_min, range_max, subs, ...) do { \ + int32_t value = var; \ + CHECK(ff_cbs_write_signed(ctx, rw, width, #name, \ + SUBSCRIPTS(subs, __VA_ARGS__), \ + value, range_min, range_max)); \ + } while (0) +#define xse(name, var, range_min, range_max, subs, ...) do { \ int32_t value = var; \ CHECK(cbs_write_se_golomb(ctx, rw, #name, \ + SUBSCRIPTS(subs, __VA_ARGS__), \ value, range_min, range_max)); \ } while (0) -#define u(width, name, range_min, range_max) \ - xu(width, name, current->name, range_min, range_max) -#define flag(name) u(1, name, 0, 1) -#define ue(name, range_min, range_max) \ - xue(name, current->name, range_min, range_max) -#define se(name, range_min, range_max) \ - xse(name, current->name, range_min, range_max) - #define infer(name, value) do { \ if (current->name != (value)) { \ av_log(ctx->log_ctx, AV_LOG_WARNING, "Warning: " \ @@ -382,9 +429,11 @@ static int cbs_h2645_read_more_rbsp_data(GetBitContext *gbc) #undef READWRITE #undef RWContext #undef xu +#undef xi #undef xue #undef xse #undef u +#undef i #undef flag #undef ue #undef se @@ -406,8 +455,11 @@ static void cbs_h264_free_sei_payload(H264RawSEIPayload *payload) switch (payload->payload_type) { case H264_SEI_TYPE_BUFFERING_PERIOD: case H264_SEI_TYPE_PIC_TIMING: + case H264_SEI_TYPE_PAN_SCAN_RECT: case H264_SEI_TYPE_RECOVERY_POINT: case H264_SEI_TYPE_DISPLAY_ORIENTATION: + case H264_SEI_TYPE_MASTERING_DISPLAY_COLOUR_VOLUME: + case H264_SEI_TYPE_ALTERNATIVE_TRANSFER: break; case H264_SEI_TYPE_USER_DATA_REGISTERED: av_buffer_unref(&payload->payload.user_data_registered.data_ref); @@ -465,6 +517,43 @@ static void cbs_h265_free_slice(void *unit, uint8_t *content) av_freep(&content); } +static void cbs_h265_free_sei_payload(H265RawSEIPayload *payload) +{ + switch (payload->payload_type) { + case HEVC_SEI_TYPE_BUFFERING_PERIOD: + case HEVC_SEI_TYPE_PICTURE_TIMING: + case HEVC_SEI_TYPE_PAN_SCAN_RECT: + case HEVC_SEI_TYPE_RECOVERY_POINT: + case HEVC_SEI_TYPE_DISPLAY_ORIENTATION: + case HEVC_SEI_TYPE_ACTIVE_PARAMETER_SETS: + case HEVC_SEI_TYPE_DECODED_PICTURE_HASH: + case HEVC_SEI_TYPE_TIME_CODE: + case HEVC_SEI_TYPE_MASTERING_DISPLAY_INFO: + case HEVC_SEI_TYPE_CONTENT_LIGHT_LEVEL_INFO: + case HEVC_SEI_TYPE_ALTERNATIVE_TRANSFER_CHARACTERISTICS: + case HEVC_SEI_TYPE_ALPHA_CHANNEL_INFO: + break; + case HEVC_SEI_TYPE_USER_DATA_REGISTERED_ITU_T_T35: + av_buffer_unref(&payload->payload.user_data_registered.data_ref); + break; + case HEVC_SEI_TYPE_USER_DATA_UNREGISTERED: + av_buffer_unref(&payload->payload.user_data_unregistered.data_ref); + break; + default: + av_buffer_unref(&payload->payload.other.data_ref); + break; + } +} + +static void cbs_h265_free_sei(void *unit, uint8_t *content) +{ + H265RawSEI *sei = (H265RawSEI*)content; + int i; + for (i = 0; i < sei->payload_count; i++) + cbs_h265_free_sei_payload(&sei->payload[i]); + av_freep(&content); +} + static int cbs_h2645_fragment_add_nals(CodedBitstreamContext *ctx, CodedBitstreamFragment *frag, const H2645Packet *packet) @@ -473,26 +562,21 @@ static int cbs_h2645_fragment_add_nals(CodedBitstreamContext *ctx, for (i = 0; i < packet->nb_nals; i++) { const H2645NAL *nal = &packet->nals[i]; + AVBufferRef *ref; size_t size = nal->size; - uint8_t *data; // Remove trailing zeroes. while (size > 0 && nal->data[size - 1] == 0) --size; av_assert0(size > 0); - data = av_malloc(size + AV_INPUT_BUFFER_PADDING_SIZE); - if (!data) - return AVERROR(ENOMEM); - memcpy(data, nal->data, size); - memset(data + size, 0, AV_INPUT_BUFFER_PADDING_SIZE); + ref = (nal->data == nal->raw_data) ? frag->data_ref + : packet->rbsp.rbsp_buffer_ref; err = ff_cbs_insert_unit_data(ctx, frag, -1, nal->type, - data, size, NULL); - if (err < 0) { - av_freep(&data); + (uint8_t*)nal->data, size, ref); + if (err < 0) return err; - } } return 0; @@ -548,7 +632,7 @@ static int cbs_h2645_split_fragment(CodedBitstreamContext *ctx, err = ff_h2645_packet_split(&priv->read_packet, frag->data + start, end - start, - ctx->log_ctx, 1, 2, AV_CODEC_ID_H264, 1); + ctx->log_ctx, 1, 2, AV_CODEC_ID_H264, 1, 1); if (err < 0) { av_log(ctx->log_ctx, AV_LOG_ERROR, "Failed to split AVCC SPS array.\n"); return err; @@ -572,7 +656,7 @@ static int cbs_h2645_split_fragment(CodedBitstreamContext *ctx, err = ff_h2645_packet_split(&priv->read_packet, frag->data + start, end - start, - ctx->log_ctx, 1, 2, AV_CODEC_ID_H264, 1); + ctx->log_ctx, 1, 2, AV_CODEC_ID_H264, 1, 1); if (err < 0) { av_log(ctx->log_ctx, AV_LOG_ERROR, "Failed to split AVCC PPS array.\n"); return err; @@ -626,7 +710,7 @@ static int cbs_h2645_split_fragment(CodedBitstreamContext *ctx, err = ff_h2645_packet_split(&priv->read_packet, frag->data + start, end - start, - ctx->log_ctx, 1, 2, AV_CODEC_ID_HEVC, 1); + ctx->log_ctx, 1, 2, AV_CODEC_ID_HEVC, 1, 1); if (err < 0) { av_log(ctx->log_ctx, AV_LOG_ERROR, "Failed to split " "HVCC array %d (%d NAL units of type %d).\n", @@ -645,7 +729,7 @@ static int cbs_h2645_split_fragment(CodedBitstreamContext *ctx, frag->data, frag->data_size, ctx->log_ctx, priv->mp4, priv->nal_length_size, - codec_id, 1); + codec_id, 1, 1); if (err < 0) return err; @@ -659,9 +743,10 @@ static int cbs_h2645_split_fragment(CodedBitstreamContext *ctx, #define cbs_h2645_replace_ps(h26n, ps_name, ps_var, id_element) \ static int cbs_h26 ## h26n ## _replace_ ## ps_var(CodedBitstreamContext *ctx, \ - const H26 ## h26n ## Raw ## ps_name *ps_var) \ + CodedBitstreamUnit *unit) \ { \ CodedBitstreamH26 ## h26n ## Context *priv = ctx->priv_data; \ + H26 ## h26n ## Raw ## ps_name *ps_var = unit->content; \ unsigned int id = ps_var->id_element; \ if (id > FF_ARRAY_ELEMS(priv->ps_var)) { \ av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid " #ps_name \ @@ -670,11 +755,16 @@ static int cbs_h26 ## h26n ## _replace_ ## ps_var(CodedBitstreamContext *ctx, \ } \ if (priv->ps_var[id] == priv->active_ ## ps_var) \ priv->active_ ## ps_var = NULL ; \ - av_freep(&priv->ps_var[id]); \ - priv->ps_var[id] = av_malloc(sizeof(*ps_var)); \ - if (!priv->ps_var[id]) \ + av_buffer_unref(&priv->ps_var ## _ref[id]); \ + if (unit->content_ref) \ + priv->ps_var ## _ref[id] = av_buffer_ref(unit->content_ref); \ + else \ + priv->ps_var ## _ref[id] = av_buffer_alloc(sizeof(*ps_var)); \ + if (!priv->ps_var ## _ref[id]) \ return AVERROR(ENOMEM); \ - memcpy(priv->ps_var[id], ps_var, sizeof(*ps_var)); \ + priv->ps_var[id] = (H26 ## h26n ## Raw ## ps_name *)priv->ps_var ## _ref[id]->data; \ + if (!unit->content_ref) \ + memcpy(priv->ps_var[id], ps_var, sizeof(*ps_var)); \ return 0; \ } @@ -708,7 +798,7 @@ static int cbs_h264_read_nal_unit(CodedBitstreamContext *ctx, if (err < 0) return err; - err = cbs_h264_replace_sps(ctx, sps); + err = cbs_h264_replace_sps(ctx, unit); if (err < 0) return err; } @@ -742,7 +832,7 @@ static int cbs_h264_read_nal_unit(CodedBitstreamContext *ctx, if (err < 0) return err; - err = cbs_h264_replace_pps(ctx, pps); + err = cbs_h264_replace_pps(ctx, unit); if (err < 0) return err; } @@ -776,15 +866,10 @@ static int cbs_h264_read_nal_unit(CodedBitstreamContext *ctx, } slice->data_size = len - pos / 8; - slice->data_ref = av_buffer_alloc(slice->data_size + - AV_INPUT_BUFFER_PADDING_SIZE); + slice->data_ref = av_buffer_ref(unit->data_ref); if (!slice->data_ref) return AVERROR(ENOMEM); - slice->data = slice->data_ref->data; - memcpy(slice->data, - unit->data + pos / 8, slice->data_size); - memset(slice->data + slice->data_size, 0, - AV_INPUT_BUFFER_PADDING_SIZE); + slice->data = unit->data + pos / 8; slice->data_bit_start = pos % 8; } break; @@ -828,6 +913,23 @@ static int cbs_h264_read_nal_unit(CodedBitstreamContext *ctx, } break; + case H264_NAL_END_SEQUENCE: + case H264_NAL_END_STREAM: + { + err = ff_cbs_alloc_unit_content(ctx, unit, + sizeof(H264RawNALUnitHeader), + NULL); + if (err < 0) + return err; + + err = (unit->type == H264_NAL_END_SEQUENCE ? + cbs_h264_read_end_of_sequence : + cbs_h264_read_end_of_stream)(ctx, &gbc, unit->content); + if (err < 0) + return err; + } + break; + default: return AVERROR(ENOSYS); } @@ -860,7 +962,7 @@ static int cbs_h265_read_nal_unit(CodedBitstreamContext *ctx, if (err < 0) return err; - err = cbs_h265_replace_vps(ctx, vps); + err = cbs_h265_replace_vps(ctx, unit); if (err < 0) return err; } @@ -879,7 +981,7 @@ static int cbs_h265_read_nal_unit(CodedBitstreamContext *ctx, if (err < 0) return err; - err = cbs_h265_replace_sps(ctx, sps); + err = cbs_h265_replace_sps(ctx, unit); if (err < 0) return err; } @@ -899,7 +1001,7 @@ static int cbs_h265_read_nal_unit(CodedBitstreamContext *ctx, if (err < 0) return err; - err = cbs_h265_replace_pps(ctx, pps); + err = cbs_h265_replace_pps(ctx, unit); if (err < 0) return err; } @@ -946,15 +1048,10 @@ static int cbs_h265_read_nal_unit(CodedBitstreamContext *ctx, } slice->data_size = len - pos / 8; - slice->data_ref = av_buffer_alloc(slice->data_size + - AV_INPUT_BUFFER_PADDING_SIZE); + slice->data_ref = av_buffer_ref(unit->data_ref); if (!slice->data_ref) return AVERROR(ENOMEM); - slice->data = slice->data_ref->data; - memcpy(slice->data, - unit->data + pos / 8, slice->data_size); - memset(slice->data + slice->data_size, 0, - AV_INPUT_BUFFER_PADDING_SIZE); + slice->data = unit->data + pos / 8; slice->data_bit_start = pos % 8; } break; @@ -972,6 +1069,23 @@ static int cbs_h265_read_nal_unit(CodedBitstreamContext *ctx, } break; + case HEVC_NAL_SEI_PREFIX: + case HEVC_NAL_SEI_SUFFIX: + { + err = ff_cbs_alloc_unit_content(ctx, unit, sizeof(H265RawSEI), + &cbs_h265_free_sei); + + if (err < 0) + return err; + + err = cbs_h265_read_sei(ctx, &gbc, unit->content, + unit->type == HEVC_NAL_SEI_PREFIX); + + if (err < 0) + return err; + } + break; + default: return AVERROR(ENOSYS); } @@ -979,6 +1093,64 @@ static int cbs_h265_read_nal_unit(CodedBitstreamContext *ctx, return 0; } +static int cbs_h2645_write_slice_data(CodedBitstreamContext *ctx, + PutBitContext *pbc, const uint8_t *data, + size_t data_size, int data_bit_start) +{ + size_t rest = data_size - (data_bit_start + 7) / 8; + const uint8_t *pos = data + data_bit_start / 8; + + av_assert0(data_bit_start >= 0 && + 8 * data_size > data_bit_start); + + if (data_size * 8 + 8 > put_bits_left(pbc)) + return AVERROR(ENOSPC); + + if (!rest) + goto rbsp_stop_one_bit; + + // First copy the remaining bits of the first byte + // The above check ensures that we do not accidentally + // copy beyond the rbsp_stop_one_bit. + if (data_bit_start % 8) + put_bits(pbc, 8 - data_bit_start % 8, + *pos++ & MAX_UINT_BITS(8 - data_bit_start % 8)); + + if (put_bits_count(pbc) % 8 == 0) { + // If the writer is aligned at this point, + // memcpy can be used to improve performance. + // This happens normally for CABAC. + flush_put_bits(pbc); + memcpy(put_bits_ptr(pbc), pos, rest); + skip_put_bytes(pbc, rest); + } else { + // If not, we have to copy manually. + // rbsp_stop_one_bit forces us to special-case + // the last byte. + uint8_t temp; + int i; + + for (; rest > 4; rest -= 4, pos += 4) + put_bits32(pbc, AV_RB32(pos)); + + for (; rest > 1; rest--, pos++) + put_bits(pbc, 8, *pos); + + rbsp_stop_one_bit: + temp = rest ? *pos : *pos & MAX_UINT_BITS(8 - data_bit_start % 8); + + av_assert0(temp); + i = ff_ctz(*pos); + temp = temp >> i; + i = rest ? (8 - i) : (8 - i - data_bit_start % 8); + put_bits(pbc, i, temp); + if (put_bits_count(pbc) % 8) + put_bits(pbc, 8 - put_bits_count(pbc) % 8, 0); + } + + return 0; +} + static int cbs_h264_write_nal_unit(CodedBitstreamContext *ctx, CodedBitstreamUnit *unit, PutBitContext *pbc) @@ -994,7 +1166,7 @@ static int cbs_h264_write_nal_unit(CodedBitstreamContext *ctx, if (err < 0) return err; - err = cbs_h264_replace_sps(ctx, sps); + err = cbs_h264_replace_sps(ctx, unit); if (err < 0) return err; } @@ -1018,7 +1190,7 @@ static int cbs_h264_write_nal_unit(CodedBitstreamContext *ctx, if (err < 0) return err; - err = cbs_h264_replace_pps(ctx, pps); + err = cbs_h264_replace_pps(ctx, unit); if (err < 0) return err; } @@ -1029,37 +1201,17 @@ static int cbs_h264_write_nal_unit(CodedBitstreamContext *ctx, case H264_NAL_AUXILIARY_SLICE: { H264RawSlice *slice = unit->content; - GetBitContext gbc; - int bits_left, end, zeroes; err = cbs_h264_write_slice_header(ctx, pbc, &slice->header); if (err < 0) return err; if (slice->data) { - if (slice->data_size * 8 + 8 > put_bits_left(pbc)) - return AVERROR(ENOSPC); - - init_get_bits(&gbc, slice->data, slice->data_size * 8); - skip_bits_long(&gbc, slice->data_bit_start); - - // Copy in two-byte blocks, but stop before copying the - // rbsp_stop_one_bit in the final byte. - while (get_bits_left(&gbc) > 23) - put_bits(pbc, 16, get_bits(&gbc, 16)); - - bits_left = get_bits_left(&gbc); - end = get_bits(&gbc, bits_left); - - // rbsp_stop_one_bit must be present here. - av_assert0(end); - zeroes = ff_ctz(end); - if (bits_left > zeroes + 1) - put_bits(pbc, bits_left - zeroes - 1, - end >> (zeroes + 1)); - put_bits(pbc, 1, 1); - while (put_bits_count(pbc) % 8 != 0) - put_bits(pbc, 1, 0); + err = cbs_h2645_write_slice_data(ctx, pbc, slice->data, + slice->data_size, + slice->data_bit_start); + if (err < 0) + return err; } else { // No slice data - that was just the header. // (Bitstream may be unaligned!) @@ -1091,6 +1243,22 @@ static int cbs_h264_write_nal_unit(CodedBitstreamContext *ctx, } break; + case H264_NAL_END_SEQUENCE: + { + err = cbs_h264_write_end_of_sequence(ctx, pbc, unit->content); + if (err < 0) + return err; + } + break; + + case H264_NAL_END_STREAM: + { + err = cbs_h264_write_end_of_stream(ctx, pbc, unit->content); + if (err < 0) + return err; + } + break; + default: av_log(ctx->log_ctx, AV_LOG_ERROR, "Write unimplemented for " "NAL unit type %"PRIu32".\n", unit->type); @@ -1115,7 +1283,7 @@ static int cbs_h265_write_nal_unit(CodedBitstreamContext *ctx, if (err < 0) return err; - err = cbs_h265_replace_vps(ctx, vps); + err = cbs_h265_replace_vps(ctx, unit); if (err < 0) return err; } @@ -1129,7 +1297,7 @@ static int cbs_h265_write_nal_unit(CodedBitstreamContext *ctx, if (err < 0) return err; - err = cbs_h265_replace_sps(ctx, sps); + err = cbs_h265_replace_sps(ctx, unit); if (err < 0) return err; } @@ -1143,7 +1311,7 @@ static int cbs_h265_write_nal_unit(CodedBitstreamContext *ctx, if (err < 0) return err; - err = cbs_h265_replace_pps(ctx, pps); + err = cbs_h265_replace_pps(ctx, unit); if (err < 0) return err; } @@ -1167,37 +1335,17 @@ static int cbs_h265_write_nal_unit(CodedBitstreamContext *ctx, case HEVC_NAL_CRA_NUT: { H265RawSlice *slice = unit->content; - GetBitContext gbc; - int bits_left, end, zeroes; err = cbs_h265_write_slice_segment_header(ctx, pbc, &slice->header); if (err < 0) return err; if (slice->data) { - if (slice->data_size * 8 + 8 > put_bits_left(pbc)) - return AVERROR(ENOSPC); - - init_get_bits(&gbc, slice->data, slice->data_size * 8); - skip_bits_long(&gbc, slice->data_bit_start); - - // Copy in two-byte blocks, but stop before copying the - // rbsp_stop_one_bit in the final byte. - while (get_bits_left(&gbc) > 23) - put_bits(pbc, 16, get_bits(&gbc, 16)); - - bits_left = get_bits_left(&gbc); - end = get_bits(&gbc, bits_left); - - // rbsp_stop_one_bit must be present here. - av_assert0(end); - zeroes = ff_ctz(end); - if (bits_left > zeroes + 1) - put_bits(pbc, bits_left - zeroes - 1, - end >> (zeroes + 1)); - put_bits(pbc, 1, 1); - while (put_bits_count(pbc) % 8 != 0) - put_bits(pbc, 1, 0); + err = cbs_h2645_write_slice_data(ctx, pbc, slice->data, + slice->data_size, + slice->data_bit_start); + if (err < 0) + return err; } else { // No slice data - that was just the header. } @@ -1212,6 +1360,17 @@ static int cbs_h265_write_nal_unit(CodedBitstreamContext *ctx, } break; + case HEVC_NAL_SEI_PREFIX: + case HEVC_NAL_SEI_SUFFIX: + { + err = cbs_h265_write_sei(ctx, pbc, unit->content, + unit->type == HEVC_NAL_SEI_PREFIX); + + if (err < 0) + return err; + } + break; + default: av_log(ctx->log_ctx, AV_LOG_ERROR, "Write unimplemented for " "NAL unit type %"PRIu32".\n", unit->type); @@ -1377,9 +1536,9 @@ static void cbs_h264_close(CodedBitstreamContext *ctx) av_freep(&h264->common.write_buffer); for (i = 0; i < FF_ARRAY_ELEMS(h264->sps); i++) - av_freep(&h264->sps[i]); + av_buffer_unref(&h264->sps_ref[i]); for (i = 0; i < FF_ARRAY_ELEMS(h264->pps); i++) - av_freep(&h264->pps[i]); + av_buffer_unref(&h264->pps_ref[i]); } static void cbs_h265_close(CodedBitstreamContext *ctx) @@ -1392,11 +1551,11 @@ static void cbs_h265_close(CodedBitstreamContext *ctx) av_freep(&h265->common.write_buffer); for (i = 0; i < FF_ARRAY_ELEMS(h265->vps); i++) - av_freep(&h265->vps[i]); + av_buffer_unref(&h265->vps_ref[i]); for (i = 0; i < FF_ARRAY_ELEMS(h265->sps); i++) - av_freep(&h265->sps[i]); + av_buffer_unref(&h265->sps_ref[i]); for (i = 0; i < FF_ARRAY_ELEMS(h265->pps); i++) - av_freep(&h265->pps[i]); + av_buffer_unref(&h265->pps_ref[i]); } const CodedBitstreamType ff_cbs_type_h264 = { @@ -1487,10 +1646,10 @@ int ff_cbs_h264_add_sei_message(CodedBitstreamContext *ctx, return 0; } -int ff_cbs_h264_delete_sei_message(CodedBitstreamContext *ctx, - CodedBitstreamFragment *au, - CodedBitstreamUnit *nal, - int position) +void ff_cbs_h264_delete_sei_message(CodedBitstreamContext *ctx, + CodedBitstreamFragment *au, + CodedBitstreamUnit *nal, + int position) { H264RawSEI *sei = nal->content; @@ -1505,9 +1664,8 @@ int ff_cbs_h264_delete_sei_message(CodedBitstreamContext *ctx, if (&au->units[i] == nal) break; } - av_assert0(i < au->nb_units && "NAL unit not in access unit."); - return ff_cbs_delete_unit(ctx, au, i); + ff_cbs_delete_unit(ctx, au, i); } else { cbs_h264_free_sei_payload(&sei->payload[position]); @@ -1515,7 +1673,5 @@ int ff_cbs_h264_delete_sei_message(CodedBitstreamContext *ctx, memmove(sei->payload + position, sei->payload + position + 1, (sei->payload_count - position) * sizeof(*sei->payload)); - - return 0; } } diff --git a/libavcodec/cbs_h264_syntax_template.c b/libavcodec/cbs_h264_syntax_template.c index 29089e4b6..26be6e590 100644 --- a/libavcodec/cbs_h264_syntax_template.c +++ b/libavcodec/cbs_h264_syntax_template.c @@ -19,10 +19,10 @@ static int FUNC(rbsp_trailing_bits)(CodedBitstreamContext *ctx, RWContext *rw) { int err; - av_unused int one = 1, zero = 0; - xu(1, rbsp_stop_one_bit, one, 1, 1); + + fixed(1, rbsp_stop_one_bit, 1); while (byte_alignment(rw) != 0) - xu(1, rbsp_alignment_zero_bit, zero, 0, 0); + fixed(1, rbsp_alignment_zero_bit, 0); return 0; } @@ -33,9 +33,9 @@ static int FUNC(nal_unit_header)(CodedBitstreamContext *ctx, RWContext *rw, { int err; - u(1, forbidden_zero_bit, 0, 0); - u(2, nal_ref_idc, 0, 3); - u(5, nal_unit_type, 0, 31); + fixed(1, forbidden_zero_bit, 0); + ub(2, nal_ref_idc); + ub(5, nal_unit_type); if (!(1 << current->nal_unit_type & valid_type_mask)) { av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid NAL unit type %d.\n", @@ -76,7 +76,7 @@ static int FUNC(scaling_list)(CodedBitstreamContext *ctx, RWContext *rw, scale = 8; for (i = 0; i < size_of_scaling_list; i++) { - xse(delta_scale, current->delta_scale[i], -128, +127); + ses(delta_scale[i], -128, +127, 1, i); scale = (scale + current->delta_scale[i] + 256) % 256; if (scale == 0) break; @@ -91,19 +91,19 @@ static int FUNC(hrd_parameters)(CodedBitstreamContext *ctx, RWContext *rw, int err, i; ue(cpb_cnt_minus1, 0, 31); - u(4, bit_rate_scale, 0, 15); - u(4, cpb_size_scale, 0, 15); + ub(4, bit_rate_scale); + ub(4, cpb_size_scale); for (i = 0; i <= current->cpb_cnt_minus1; i++) { - ue(bit_rate_value_minus1[i], 0, UINT32_MAX - 1); - ue(cpb_size_value_minus1[i], 0, UINT32_MAX - 1); - flag(cbr_flag[i]); + ues(bit_rate_value_minus1[i], 0, UINT32_MAX - 1, 1, i); + ues(cpb_size_value_minus1[i], 0, UINT32_MAX - 1, 1, i); + flags(cbr_flag[i], 1, i); } - u(5, initial_cpb_removal_delay_length_minus1, 0, 31); - u(5, cpb_removal_delay_length_minus1, 0, 31); - u(5, dpb_output_delay_length_minus1, 0, 31); - u(5, time_offset_length, 0, 31); + ub(5, initial_cpb_removal_delay_length_minus1); + ub(5, cpb_removal_delay_length_minus1); + ub(5, dpb_output_delay_length_minus1); + ub(5, time_offset_length); return 0; } @@ -115,10 +115,10 @@ static int FUNC(vui_parameters)(CodedBitstreamContext *ctx, RWContext *rw, flag(aspect_ratio_info_present_flag); if (current->aspect_ratio_info_present_flag) { - u(8, aspect_ratio_idc, 0, 255); + ub(8, aspect_ratio_idc); if (current->aspect_ratio_idc == 255) { - u(16, sar_width, 0, 65535); - u(16, sar_height, 0, 65535); + ub(16, sar_width); + ub(16, sar_height); } } else { infer(aspect_ratio_idc, 0); @@ -130,13 +130,13 @@ static int FUNC(vui_parameters)(CodedBitstreamContext *ctx, RWContext *rw, flag(video_signal_type_present_flag); if (current->video_signal_type_present_flag) { - u(3, video_format, 0, 7); + ub(3, video_format); flag(video_full_range_flag); flag(colour_description_present_flag); if (current->colour_description_present_flag) { - u(8, colour_primaries, 0, 255); - u(8, transfer_characteristics, 0, 255); - u(8, matrix_coefficients, 0, 255); + ub(8, colour_primaries); + ub(8, transfer_characteristics); + ub(8, matrix_coefficients); } } else { infer(video_format, 5); @@ -185,6 +185,8 @@ static int FUNC(vui_parameters)(CodedBitstreamContext *ctx, RWContext *rw, flag(motion_vectors_over_pic_boundaries_flag); ue(max_bytes_per_pic_denom, 0, 16); ue(max_bits_per_mb_denom, 0, 16); + // The current version of the standard constrains this to be in + // [0,15], but older versions allow 16. ue(log2_max_mv_length_horizontal, 0, 16); ue(log2_max_mv_length_vertical, 0, 16); ue(max_num_reorder_frames, 0, H264_MAX_DPB_FRAMES); @@ -193,11 +195,11 @@ static int FUNC(vui_parameters)(CodedBitstreamContext *ctx, RWContext *rw, infer(motion_vectors_over_pic_boundaries_flag, 1); infer(max_bytes_per_pic_denom, 2); infer(max_bits_per_mb_denom, 1); - infer(log2_max_mv_length_horizontal, 16); - infer(log2_max_mv_length_vertical, 16); + infer(log2_max_mv_length_horizontal, 15); + infer(log2_max_mv_length_vertical, 15); if ((sps->profile_idc == 44 || sps->profile_idc == 86 || - sps->profile_idc == 110 || sps->profile_idc == 110 || + sps->profile_idc == 100 || sps->profile_idc == 110 || sps->profile_idc == 122 || sps->profile_idc == 244) && sps->constraint_set3_flag) { infer(max_num_reorder_frames, 0); @@ -211,6 +213,46 @@ static int FUNC(vui_parameters)(CodedBitstreamContext *ctx, RWContext *rw, return 0; } +static int FUNC(vui_parameters_default)(CodedBitstreamContext *ctx, + RWContext *rw, H264RawVUI *current, + H264RawSPS *sps) +{ + infer(aspect_ratio_idc, 0); + + infer(video_format, 5); + infer(video_full_range_flag, 0); + infer(colour_primaries, 2); + infer(transfer_characteristics, 2); + infer(matrix_coefficients, 2); + + infer(chroma_sample_loc_type_top_field, 0); + infer(chroma_sample_loc_type_bottom_field, 0); + + infer(fixed_frame_rate_flag, 0); + infer(low_delay_hrd_flag, 1); + + infer(pic_struct_present_flag, 0); + + infer(motion_vectors_over_pic_boundaries_flag, 1); + infer(max_bytes_per_pic_denom, 2); + infer(max_bits_per_mb_denom, 1); + infer(log2_max_mv_length_horizontal, 15); + infer(log2_max_mv_length_vertical, 15); + + if ((sps->profile_idc == 44 || sps->profile_idc == 86 || + sps->profile_idc == 100 || sps->profile_idc == 110 || + sps->profile_idc == 122 || sps->profile_idc == 244) && + sps->constraint_set3_flag) { + infer(max_num_reorder_frames, 0); + infer(max_dec_frame_buffering, 0); + } else { + infer(max_num_reorder_frames, H264_MAX_DPB_FRAMES); + infer(max_dec_frame_buffering, H264_MAX_DPB_FRAMES); + } + + return 0; +} + static int FUNC(sps)(CodedBitstreamContext *ctx, RWContext *rw, H264RawSPS *current) { @@ -221,7 +263,7 @@ static int FUNC(sps)(CodedBitstreamContext *ctx, RWContext *rw, CHECK(FUNC(nal_unit_header)(ctx, rw, ¤t->nal_unit_header, 1 << H264_NAL_SPS)); - u(8, profile_idc, 0, 255); + ub(8, profile_idc); flag(constraint_set0_flag); flag(constraint_set1_flag); @@ -232,7 +274,7 @@ static int FUNC(sps)(CodedBitstreamContext *ctx, RWContext *rw, u(2, reserved_zero_2bits, 0, 0); - u(8, level_idc, 0, 255); + ub(8, level_idc); ue(seq_parameter_set_id, 0, 31); @@ -256,7 +298,7 @@ static int FUNC(sps)(CodedBitstreamContext *ctx, RWContext *rw, flag(seq_scaling_matrix_present_flag); if (current->seq_scaling_matrix_present_flag) { for (i = 0; i < ((current->chroma_format_idc != 3) ? 8 : 12); i++) { - flag(seq_scaling_list_present_flag[i]); + flags(seq_scaling_list_present_flag[i], 1, i); if (current->seq_scaling_list_present_flag[i]) { if (i < 6) CHECK(FUNC(scaling_list)(ctx, rw, @@ -289,7 +331,7 @@ static int FUNC(sps)(CodedBitstreamContext *ctx, RWContext *rw, ue(num_ref_frames_in_pic_order_cnt_cycle, 0, 255); for (i = 0; i < current->num_ref_frames_in_pic_order_cnt_cycle; i++) - se(offset_for_ref_frame[i], INT32_MIN + 1, INT32_MAX); + ses(offset_for_ref_frame[i], INT32_MIN + 1, INT32_MAX, 1, i); } ue(max_num_ref_frames, 0, H264_MAX_DPB_FRAMES); @@ -315,6 +357,8 @@ static int FUNC(sps)(CodedBitstreamContext *ctx, RWContext *rw, flag(vui_parameters_present_flag); if (current->vui_parameters_present_flag) CHECK(FUNC(vui_parameters)(ctx, rw, ¤t->vui, current)); + else + CHECK(FUNC(vui_parameters_default)(ctx, rw, ¤t->vui, current)); CHECK(FUNC(rbsp_trailing_bits)(ctx, rw)); @@ -342,8 +386,8 @@ static int FUNC(sps_extension)(CodedBitstreamContext *ctx, RWContext *rw, flag(alpha_incr_flag); bits = current->bit_depth_aux_minus8 + 9; - u(bits, alpha_opaque_value, 0, MAX_UINT_BITS(bits)); - u(bits, alpha_transparent_value, 0, MAX_UINT_BITS(bits)); + ub(bits, alpha_opaque_value); + ub(bits, alpha_transparent_value); } flag(additional_extension_flag); @@ -390,12 +434,13 @@ static int FUNC(pps)(CodedBitstreamContext *ctx, RWContext *rw, if (current->slice_group_map_type == 0) { for (iGroup = 0; iGroup <= current->num_slice_groups_minus1; iGroup++) - ue(run_length_minus1[iGroup], 0, pic_size - 1); + ues(run_length_minus1[iGroup], 0, pic_size - 1, 1, iGroup); } else if (current->slice_group_map_type == 2) { for (iGroup = 0; iGroup < current->num_slice_groups_minus1; iGroup++) { - ue(top_left[iGroup], 0, pic_size - 1); - ue(bottom_right[iGroup], current->top_left[iGroup], pic_size - 1); + ues(top_left[iGroup], 0, pic_size - 1, 1, iGroup); + ues(bottom_right[iGroup], + current->top_left[iGroup], pic_size - 1, 1, iGroup); } } else if (current->slice_group_map_type == 3 || current->slice_group_map_type == 4 || @@ -408,8 +453,8 @@ static int FUNC(pps)(CodedBitstreamContext *ctx, RWContext *rw, allocate(current->slice_group_id, current->pic_size_in_map_units_minus1 + 1); for (i = 0; i <= current->pic_size_in_map_units_minus1; i++) - u(av_log2(2 * current->num_slice_groups_minus1 + 1), - slice_group_id[i], 0, current->num_slice_groups_minus1); + us(av_log2(2 * current->num_slice_groups_minus1 + 1), + slice_group_id[i], 0, current->num_slice_groups_minus1, 1, i); } } @@ -435,7 +480,7 @@ static int FUNC(pps)(CodedBitstreamContext *ctx, RWContext *rw, if (current->pic_scaling_matrix_present_flag) { for (i = 0; i < 6 + (((sps->chroma_format_idc != 3) ? 2 : 6) * current->transform_8x8_mode_flag); i++) { - flag(pic_scaling_list_present_flag[i]); + flags(pic_scaling_list_present_flag[i], 1, i); if (current->pic_scaling_list_present_flag[i]) { if (i < 6) CHECK(FUNC(scaling_list)(ctx, rw, @@ -468,6 +513,8 @@ static int FUNC(sei_buffering_period)(CodedBitstreamContext *ctx, RWContext *rw, const H264RawSPS *sps; int err, i, length; + HEADER("Buffering Period"); + ue(seq_parameter_set_id, 0, 31); sps = h264->sps[current->seq_parameter_set_id]; @@ -483,10 +530,10 @@ static int FUNC(sei_buffering_period)(CodedBitstreamContext *ctx, RWContext *rw, length = sps->vui.nal_hrd_parameters.initial_cpb_removal_delay_length_minus1 + 1; xu(length, initial_cpb_removal_delay[SchedSelIdx], current->nal.initial_cpb_removal_delay[i], - 1, MAX_UINT_BITS(length)); + 1, MAX_UINT_BITS(length), 1, i); xu(length, initial_cpb_removal_delay_offset[SchedSelIdx], current->nal.initial_cpb_removal_delay_offset[i], - 0, MAX_UINT_BITS(length)); + 0, MAX_UINT_BITS(length), 1, i); } } @@ -495,10 +542,10 @@ static int FUNC(sei_buffering_period)(CodedBitstreamContext *ctx, RWContext *rw, length = sps->vui.vcl_hrd_parameters.initial_cpb_removal_delay_length_minus1 + 1; xu(length, initial_cpb_removal_delay[SchedSelIdx], current->vcl.initial_cpb_removal_delay[i], - 1, MAX_UINT_BITS(length)); + 1, MAX_UINT_BITS(length), 1, i); xu(length, initial_cpb_removal_delay_offset[SchedSelIdx], current->vcl.initial_cpb_removal_delay_offset[i], - 0, MAX_UINT_BITS(length)); + 0, MAX_UINT_BITS(length), 1, i); } } @@ -506,10 +553,9 @@ static int FUNC(sei_buffering_period)(CodedBitstreamContext *ctx, RWContext *rw, } static int FUNC(sei_pic_timestamp)(CodedBitstreamContext *ctx, RWContext *rw, - H264RawSEIPicTimestamp *current) + H264RawSEIPicTimestamp *current, + const H264RawSPS *sps) { - CodedBitstreamH264Context *h264 = ctx->priv_data; - const H264RawSPS *sps; uint8_t time_offset_length; int err; @@ -519,7 +565,7 @@ static int FUNC(sei_pic_timestamp)(CodedBitstreamContext *ctx, RWContext *rw, flag(full_timestamp_flag); flag(discontinuity_flag); flag(cnt_dropped_flag); - u(8, n_frames, 0, 255); + ub(8, n_frames); if (current->full_timestamp_flag) { u(6, seconds_value, 0, 59); u(6, minutes_value, 0, 59); @@ -538,13 +584,6 @@ static int FUNC(sei_pic_timestamp)(CodedBitstreamContext *ctx, RWContext *rw, } } - sps = h264->active_sps; - if (!sps) { - av_log(ctx->log_ctx, AV_LOG_ERROR, - "No active SPS for pic_timestamp.\n"); - return AVERROR_INVALIDDATA; - } - if (sps->vui.nal_hrd_parameters_present_flag) time_offset_length = sps->vui.nal_hrd_parameters.time_offset_length; else if (sps->vui.vcl_hrd_parameters_present_flag) @@ -553,8 +592,7 @@ static int FUNC(sei_pic_timestamp)(CodedBitstreamContext *ctx, RWContext *rw, time_offset_length = 24; if (time_offset_length > 0) - u(time_offset_length, time_offset, - 0, MAX_UINT_BITS(time_offset_length)); + ib(time_offset_length, time_offset); else infer(time_offset, 0); @@ -568,6 +606,8 @@ static int FUNC(sei_pic_timing)(CodedBitstreamContext *ctx, RWContext *rw, const H264RawSPS *sps; int err; + HEADER("Picture Timing"); + sps = h264->active_sps; if (!sps) { // If there is exactly one possible SPS but it is not yet active @@ -605,14 +645,12 @@ static int FUNC(sei_pic_timing)(CodedBitstreamContext *ctx, RWContext *rw, return AVERROR_INVALIDDATA; } - u(hrd->cpb_removal_delay_length_minus1 + 1, cpb_removal_delay, - 0, MAX_UINT_BITS(hrd->cpb_removal_delay_length_minus1 + 1)); - u(hrd->dpb_output_delay_length_minus1 + 1, dpb_output_delay, - 0, MAX_UINT_BITS(hrd->dpb_output_delay_length_minus1 + 1)); + ub(hrd->cpb_removal_delay_length_minus1 + 1, cpb_removal_delay); + ub(hrd->dpb_output_delay_length_minus1 + 1, dpb_output_delay); } if (sps->vui.pic_struct_present_flag) { - static const int num_clock_ts[9] = { + static const uint8_t num_clock_ts[9] = { 1, 1, 1, 2, 2, 3, 3, 2, 3 }; int i; @@ -622,21 +660,50 @@ static int FUNC(sei_pic_timing)(CodedBitstreamContext *ctx, RWContext *rw, return AVERROR_INVALIDDATA; for (i = 0; i < num_clock_ts[current->pic_struct]; i++) { - flag(clock_timestamp_flag[i]); + flags(clock_timestamp_flag[i], 1, i); if (current->clock_timestamp_flag[i]) - CHECK(FUNC(sei_pic_timestamp)(ctx, rw, ¤t->timestamp[i])); + CHECK(FUNC(sei_pic_timestamp)(ctx, rw, + ¤t->timestamp[i], sps)); } } return 0; } +static int FUNC(sei_pan_scan_rect)(CodedBitstreamContext *ctx, RWContext *rw, + H264RawSEIPanScanRect *current) +{ + int err, i; + + HEADER("Pan-Scan Rectangle"); + + ue(pan_scan_rect_id, 0, UINT32_MAX - 1); + flag(pan_scan_rect_cancel_flag); + + if (!current->pan_scan_rect_cancel_flag) { + ue(pan_scan_cnt_minus1, 0, 2); + + for (i = 0; i <= current->pan_scan_cnt_minus1; i++) { + ses(pan_scan_rect_left_offset[i], INT32_MIN + 1, INT32_MAX, 1, i); + ses(pan_scan_rect_right_offset[i], INT32_MIN + 1, INT32_MAX, 1, i); + ses(pan_scan_rect_top_offset[i], INT32_MIN + 1, INT32_MAX, 1, i); + ses(pan_scan_rect_bottom_offset[i], INT32_MIN + 1, INT32_MAX, 1, i); + } + + ue(pan_scan_rect_repetition_period, 0, 16384); + } + + return 0; +} + static int FUNC(sei_user_data_registered)(CodedBitstreamContext *ctx, RWContext *rw, H264RawSEIUserDataRegistered *current, uint32_t *payload_size) { int err, i, j; + HEADER("User Data Registered ITU-T T.35"); + u(8, itu_t_t35_country_code, 0x00, 0xff); if (current->itu_t_t35_country_code != 0xff) i = 1; @@ -656,9 +723,9 @@ static int FUNC(sei_user_data_registered)(CodedBitstreamContext *ctx, RWContext *payload_size = i + current->data_length; #endif - allocate(current->data, current->data_length + AV_INPUT_BUFFER_PADDING_SIZE); + allocate(current->data, current->data_length); for (j = 0; j < current->data_length; j++) - xu(8, itu_t_t35_payload_byte, current->data[j], 0x00, 0xff); + xu(8, itu_t_t35_payload_byte[i], current->data[j], 0x00, 0xff, 1, i + j); return 0; } @@ -669,6 +736,8 @@ static int FUNC(sei_user_data_unregistered)(CodedBitstreamContext *ctx, RWContex { int err, i; + HEADER("User Data Unregistered"); + #ifdef READ if (*payload_size < 16) { av_log(ctx->log_ctx, AV_LOG_ERROR, @@ -680,15 +749,13 @@ static int FUNC(sei_user_data_unregistered)(CodedBitstreamContext *ctx, RWContex *payload_size = 16 + current->data_length; #endif - for (i = 0; i < 16; i++) { - xu(8, uuid_iso_iec_11578, - current->uuid_iso_iec_11578[i], 0x00, 0xff); - } + for (i = 0; i < 16; i++) + us(8, uuid_iso_iec_11578[i], 0x00, 0xff, 1, i); allocate(current->data, current->data_length); for (i = 0; i < current->data_length; i++) - xu(8, user_data_payload_byte, current->data[i], 0x00, 0xff); + xu(8, user_data_payload_byte[i], current->data[i], 0x00, 0xff, 1, i); return 0; } @@ -698,6 +765,8 @@ static int FUNC(sei_recovery_point)(CodedBitstreamContext *ctx, RWContext *rw, { int err; + HEADER("Recovery Point"); + ue(recovery_frame_cnt, 0, 65535); flag(exact_match_flag); flag(broken_link_flag); @@ -711,11 +780,13 @@ static int FUNC(sei_display_orientation)(CodedBitstreamContext *ctx, RWContext * { int err; + HEADER("Display Orientation"); + flag(display_orientation_cancel_flag); if (!current->display_orientation_cancel_flag) { flag(hor_flip); flag(ver_flip); - u(16, anticlockwise_rotation, 0, 65535); + ub(16, anticlockwise_rotation); ue(display_orientation_repetition_period, 0, 16384); flag(display_orientation_extension_flag); } @@ -723,6 +794,40 @@ static int FUNC(sei_display_orientation)(CodedBitstreamContext *ctx, RWContext * return 0; } +static int FUNC(sei_mastering_display_colour_volume)(CodedBitstreamContext *ctx, RWContext *rw, + H264RawSEIMasteringDisplayColourVolume *current) +{ + int err, c; + + HEADER("Mastering Display Colour Volume"); + + for (c = 0; c < 3; c++) { + us(16, display_primaries_x[c], 0, 50000, 1, c); + us(16, display_primaries_y[c], 0, 50000, 1, c); + } + + u(16, white_point_x, 0, 50000); + u(16, white_point_y, 0, 50000); + + u(32, max_display_mastering_luminance, 1, MAX_UINT_BITS(32)); + u(32, min_display_mastering_luminance, 0, current->max_display_mastering_luminance - 1); + + return 0; +} + +static int FUNC(sei_alternative_transfer_characteristics)(CodedBitstreamContext *ctx, + RWContext *rw, + H264RawSEIAlternativeTransferCharacteristics *current) +{ + int err; + + HEADER("Alternative Transfer Characteristics"); + + ub(8, preferred_transfer_characteristics); + + return 0; +} + static int FUNC(sei_payload)(CodedBitstreamContext *ctx, RWContext *rw, H264RawSEIPayload *current) { @@ -744,11 +849,14 @@ static int FUNC(sei_payload)(CodedBitstreamContext *ctx, RWContext *rw, CHECK(FUNC(sei_pic_timing) (ctx, rw, ¤t->payload.pic_timing)); break; + case H264_SEI_TYPE_PAN_SCAN_RECT: + CHECK(FUNC(sei_pan_scan_rect) + (ctx, rw, ¤t->payload.pan_scan_rect)); + break; case H264_SEI_TYPE_FILLER_PAYLOAD: { - av_unused int ff_byte = 0xff; for (i = 0; i < current->payload_size; i++) - xu(8, ff_byte, ff_byte, 0xff, 0xff); + fixed(8, ff_byte, 0xff); } break; case H264_SEI_TYPE_USER_DATA_REGISTERED: @@ -767,19 +875,29 @@ static int FUNC(sei_payload)(CodedBitstreamContext *ctx, RWContext *rw, CHECK(FUNC(sei_display_orientation) (ctx, rw, ¤t->payload.display_orientation)); break; + case H264_SEI_TYPE_MASTERING_DISPLAY_COLOUR_VOLUME: + CHECK(FUNC(sei_mastering_display_colour_volume) + (ctx, rw, ¤t->payload.mastering_display_colour_volume)); + break; + case H264_SEI_TYPE_ALTERNATIVE_TRANSFER: + CHECK(FUNC(sei_alternative_transfer_characteristics) + (ctx, rw, ¤t->payload.alternative_transfer_characteristics)); + break; default: { - allocate(current->payload.other.data, current->payload_size); - for (i = 0; i < current->payload_size; i++) - xu(8, payload_byte, current->payload.other.data[i], 0, 255); +#ifdef READ + current->payload.other.data_length = current->payload_size; +#endif + allocate(current->payload.other.data, current->payload.other.data_length); + for (i = 0; i < current->payload.other.data_length; i++) + xu(8, payload_byte[i], current->payload.other.data[i], 0, 255, 1, i); } } if (byte_alignment(rw)) { - av_unused int one = 1, zero = 0; - xu(1, bit_equal_to_one, one, 1, 1); + fixed(1, bit_equal_to_one, 1); while (byte_alignment(rw)) - xu(1, bit_equal_to_zero, zero, 0, 0); + fixed(1, bit_equal_to_zero, 0); } #ifdef READ @@ -816,17 +934,17 @@ static int FUNC(sei)(CodedBitstreamContext *ctx, RWContext *rw, uint32_t tmp; while (show_bits(rw, 8) == 0xff) { - xu(8, ff_byte, tmp, 0xff, 0xff); + fixed(8, ff_byte, 0xff); payload_type += 255; } - xu(8, last_payload_type_byte, tmp, 0, 254); + xu(8, last_payload_type_byte, tmp, 0, 254, 0); payload_type += tmp; while (show_bits(rw, 8) == 0xff) { - xu(8, ff_byte, tmp, 0xff, 0xff); + fixed(8, ff_byte, 0xff); payload_size += 255; } - xu(8, last_payload_size_byte, tmp, 0, 254); + xu(8, last_payload_size_byte, tmp, 0, 254, 0); payload_size += tmp; current->payload[k].payload_type = payload_type; @@ -859,17 +977,17 @@ static int FUNC(sei)(CodedBitstreamContext *ctx, RWContext *rw, tmp = current->payload[k].payload_type; while (tmp >= 255) { - xu(8, ff_byte, 0xff, 0xff, 0xff); + fixed(8, ff_byte, 0xff); tmp -= 255; } - xu(8, last_payload_type_byte, tmp, 0, 254); + xu(8, last_payload_type_byte, tmp, 0, 254, 0); tmp = current->payload[k].payload_size; while (tmp >= 255) { - xu(8, ff_byte, 0xff, 0xff, 0xff); + fixed(8, ff_byte, 0xff); tmp -= 255; } - xu(8, last_payload_size_byte, tmp, 0, 254); + xu(8, last_payload_size_byte, tmp, 0, 254, 0); CHECK(FUNC(sei_payload)(ctx, rw, ¤t->payload[k])); } @@ -891,7 +1009,7 @@ static int FUNC(aud)(CodedBitstreamContext *ctx, RWContext *rw, CHECK(FUNC(nal_unit_header)(ctx, rw, ¤t->nal_unit_header, 1 << H264_NAL_AUD)); - u(3, primary_pic_type, 0, 7); + ub(3, primary_pic_type); CHECK(FUNC(rbsp_trailing_bits)(ctx, rw)); @@ -911,7 +1029,7 @@ static int FUNC(ref_pic_list_modification)(CodedBitstreamContext *ctx, RWContext if (current->ref_pic_list_modification_flag_l0) { for (i = 0; i < H264_MAX_RPLM_COUNT; i++) { xue(modification_of_pic_nums_idc, - current->rplm_l0[i].modification_of_pic_nums_idc, 0, 3); + current->rplm_l0[i].modification_of_pic_nums_idc, 0, 3, 0); mopn = current->rplm_l0[i].modification_of_pic_nums_idc; if (mopn == 3) @@ -921,11 +1039,11 @@ static int FUNC(ref_pic_list_modification)(CodedBitstreamContext *ctx, RWContext xue(abs_diff_pic_num_minus1, current->rplm_l0[i].abs_diff_pic_num_minus1, 0, (1 + current->field_pic_flag) * - (1 << (sps->log2_max_frame_num_minus4 + 4))); + (1 << (sps->log2_max_frame_num_minus4 + 4)), 0); else if (mopn == 2) xue(long_term_pic_num, current->rplm_l0[i].long_term_pic_num, - 0, sps->max_num_ref_frames - 1); + 0, sps->max_num_ref_frames - 1, 0); } } } @@ -935,7 +1053,7 @@ static int FUNC(ref_pic_list_modification)(CodedBitstreamContext *ctx, RWContext if (current->ref_pic_list_modification_flag_l1) { for (i = 0; i < H264_MAX_RPLM_COUNT; i++) { xue(modification_of_pic_nums_idc, - current->rplm_l1[i].modification_of_pic_nums_idc, 0, 3); + current->rplm_l1[i].modification_of_pic_nums_idc, 0, 3, 0); mopn = current->rplm_l1[i].modification_of_pic_nums_idc; if (mopn == 3) @@ -945,11 +1063,11 @@ static int FUNC(ref_pic_list_modification)(CodedBitstreamContext *ctx, RWContext xue(abs_diff_pic_num_minus1, current->rplm_l1[i].abs_diff_pic_num_minus1, 0, (1 + current->field_pic_flag) * - (1 << (sps->log2_max_frame_num_minus4 + 4))); + (1 << (sps->log2_max_frame_num_minus4 + 4)), 0); else if (mopn == 2) xue(long_term_pic_num, current->rplm_l1[i].long_term_pic_num, - 0, sps->max_num_ref_frames - 1); + 0, sps->max_num_ref_frames - 1, 0); } } } @@ -972,17 +1090,17 @@ static int FUNC(pred_weight_table)(CodedBitstreamContext *ctx, RWContext *rw, ue(chroma_log2_weight_denom, 0, 7); for (i = 0; i <= current->num_ref_idx_l0_active_minus1; i++) { - flag(luma_weight_l0_flag[i]); + flags(luma_weight_l0_flag[i], 1, i); if (current->luma_weight_l0_flag[i]) { - se(luma_weight_l0[i], -128, +127); - se(luma_offset_l0[i], -128, +127); + ses(luma_weight_l0[i], -128, +127, 1, i); + ses(luma_offset_l0[i], -128, +127, 1, i); } if (chroma) { - flag(chroma_weight_l0_flag[i]); + flags(chroma_weight_l0_flag[i], 1, i); if (current->chroma_weight_l0_flag[i]) { for (j = 0; j < 2; j++) { - se(chroma_weight_l0[i][j], -128, +127); - se(chroma_offset_l0[i][j], -128, +127); + ses(chroma_weight_l0[i][j], -128, +127, 2, i, j); + ses(chroma_offset_l0[i][j], -128, +127, 2, i, j); } } } @@ -990,17 +1108,17 @@ static int FUNC(pred_weight_table)(CodedBitstreamContext *ctx, RWContext *rw, if (current->slice_type % 5 == 1) { for (i = 0; i <= current->num_ref_idx_l1_active_minus1; i++) { - flag(luma_weight_l1_flag[i]); + flags(luma_weight_l1_flag[i], 1, i); if (current->luma_weight_l1_flag[i]) { - se(luma_weight_l1[i], -128, +127); - se(luma_offset_l1[i], -128, +127); + ses(luma_weight_l1[i], -128, +127, 1, i); + ses(luma_offset_l1[i], -128, +127, 1, i); } if (chroma) { - flag(chroma_weight_l1_flag[i]); + flags(chroma_weight_l1_flag[i], 1, i); if (current->chroma_weight_l1_flag[i]) { for (j = 0; j < 2; j++) { - se(chroma_weight_l1[i][j], -128, +127); - se(chroma_offset_l1[i][j], -128, +127); + ses(chroma_weight_l1[i][j], -128, +127, 2, i, j); + ses(chroma_offset_l1[i][j], -128, +127, 2, i, j); } } } @@ -1027,7 +1145,7 @@ static int FUNC(dec_ref_pic_marking)(CodedBitstreamContext *ctx, RWContext *rw, for (i = 0; i < H264_MAX_MMCO_COUNT; i++) { xue(memory_management_control_operation, current->mmco[i].memory_management_control_operation, - 0, 6); + 0, 6, 0); mmco = current->mmco[i].memory_management_control_operation; if (mmco == 0) @@ -1036,19 +1154,19 @@ static int FUNC(dec_ref_pic_marking)(CodedBitstreamContext *ctx, RWContext *rw, if (mmco == 1 || mmco == 3) xue(difference_of_pic_nums_minus1, current->mmco[i].difference_of_pic_nums_minus1, - 0, INT32_MAX); + 0, INT32_MAX, 0); if (mmco == 2) xue(long_term_pic_num, current->mmco[i].long_term_pic_num, - 0, sps->max_num_ref_frames - 1); + 0, sps->max_num_ref_frames - 1, 0); if (mmco == 3 || mmco == 6) xue(long_term_frame_idx, current->mmco[i].long_term_frame_idx, - 0, sps->max_num_ref_frames - 1); + 0, sps->max_num_ref_frames - 1, 0); if (mmco == 4) xue(max_long_term_frame_idx_plus1, current->mmco[i].max_long_term_frame_idx_plus1, - 0, sps->max_num_ref_frames); + 0, sps->max_num_ref_frames, 0); } if (i == H264_MAX_MMCO_COUNT) { av_log(ctx->log_ctx, AV_LOG_ERROR, "Too many " @@ -1086,11 +1204,10 @@ static int FUNC(slice_header)(CodedBitstreamContext *ctx, RWContext *rw, "in the same access unit.\n"); return AVERROR_INVALIDDATA; } + idr_pic_flag = h264->last_slice_nal_unit_type == H264_NAL_IDR_SLICE; } else { - h264->last_slice_nal_unit_type = - current->nal_unit_header.nal_unit_type; + idr_pic_flag = current->nal_unit_header.nal_unit_type == H264_NAL_IDR_SLICE; } - idr_pic_flag = h264->last_slice_nal_unit_type == H264_NAL_IDR_SLICE; ue(first_mb_in_slice, 0, H264_MAX_MB_PIC_SIZE - 1); ue(slice_type, 0, 9); @@ -1128,8 +1245,7 @@ static int FUNC(slice_header)(CodedBitstreamContext *ctx, RWContext *rw, if (sps->separate_colour_plane_flag) u(2, colour_plane_id, 0, 2); - u(sps->log2_max_frame_num_minus4 + 4, frame_num, - 0, MAX_UINT_BITS(sps->log2_max_frame_num_minus4 + 4)); + ub(sps->log2_max_frame_num_minus4 + 4, frame_num); if (!sps->frame_mbs_only_flag) { flag(field_pic_flag); @@ -1146,8 +1262,7 @@ static int FUNC(slice_header)(CodedBitstreamContext *ctx, RWContext *rw, ue(idr_pic_id, 0, 65535); if (sps->pic_order_cnt_type == 0) { - u(sps->log2_max_pic_order_cnt_lsb_minus4 + 4, pic_order_cnt_lsb, - 0, MAX_UINT_BITS(sps->log2_max_pic_order_cnt_lsb_minus4 + 4)); + ub(sps->log2_max_pic_order_cnt_lsb_minus4 + 4, pic_order_cnt_lsb); if (pps->bottom_field_pic_order_in_frame_present_flag && !current->field_pic_flag) se(delta_pic_order_cnt_bottom, INT32_MIN + 1, INT32_MAX); @@ -1168,6 +1283,13 @@ static int FUNC(slice_header)(CodedBitstreamContext *ctx, RWContext *rw, if (pps->redundant_pic_cnt_present_flag) ue(redundant_pic_cnt, 0, 127); + else + infer(redundant_pic_cnt, 0); + + if (current->nal_unit_header.nal_unit_type != H264_NAL_AUXILIARY_SLICE + && !current->redundant_pic_cnt) + h264->last_slice_nal_unit_type = + current->nal_unit_header.nal_unit_type; if (slice_type_b) flag(direct_spatial_mv_pred_flag); @@ -1246,9 +1368,8 @@ static int FUNC(slice_header)(CodedBitstreamContext *ctx, RWContext *rw, } if (pps->entropy_coding_mode_flag) { - av_unused int one = 1; while (byte_alignment(rw)) - xu(1, cabac_alignment_one_bit, one, 1, 1); + fixed(1, cabac_alignment_one_bit, 1); } return 0; @@ -1257,7 +1378,6 @@ static int FUNC(slice_header)(CodedBitstreamContext *ctx, RWContext *rw, static int FUNC(filler)(CodedBitstreamContext *ctx, RWContext *rw, H264RawFiller *current) { - av_unused int ff_byte = 0xff; int err; HEADER("Filler Data"); @@ -1267,14 +1387,14 @@ static int FUNC(filler)(CodedBitstreamContext *ctx, RWContext *rw, #ifdef READ while (show_bits(rw, 8) == 0xff) { - xu(8, ff_byte, ff_byte, 0xff, 0xff); + fixed(8, ff_byte, 0xff); ++current->filler_size; } #else { uint32_t i; for (i = 0; i < current->filler_size; i++) - xu(8, ff_byte, ff_byte, 0xff, 0xff); + fixed(8, ff_byte, 0xff); } #endif @@ -1282,3 +1402,21 @@ static int FUNC(filler)(CodedBitstreamContext *ctx, RWContext *rw, return 0; } + +static int FUNC(end_of_sequence)(CodedBitstreamContext *ctx, RWContext *rw, + H264RawNALUnitHeader *current) +{ + HEADER("End of Sequence"); + + return FUNC(nal_unit_header)(ctx, rw, current, + 1 << H264_NAL_END_SEQUENCE); +} + +static int FUNC(end_of_stream)(CodedBitstreamContext *ctx, RWContext *rw, + H264RawNALUnitHeader *current) +{ + HEADER("End of Stream"); + + return FUNC(nal_unit_header)(ctx, rw, current, + 1 << H264_NAL_END_STREAM); +} diff --git a/libavcodec/cbs_h265.h b/libavcodec/cbs_h265.h index 33e71fc23..ad746bf35 100644 --- a/libavcodec/cbs_h265.h +++ b/libavcodec/cbs_h265.h @@ -25,9 +25,16 @@ #include "cbs_h2645.h" #include "hevc.h" +enum { + // This limit is arbitrary - it is sufficient for one message of each + // type plus some repeats, and will therefore easily cover all sane + // streams. However, it is possible to make technically-valid streams + // for which it will fail (for example, by including a large number of + // user-data-unregistered messages). + H265_MAX_SEI_PAYLOADS = 64, +}; typedef struct H265RawNALUnitHeader { - uint8_t forbidden_zero_bit; uint8_t nal_unit_type; uint8_t nuh_layer_id; uint8_t nuh_temporal_id_plus1; @@ -63,7 +70,31 @@ typedef struct H265RawProfileTierLevel { uint8_t sub_layer_profile_present_flag[HEVC_MAX_SUB_LAYERS]; uint8_t sub_layer_level_present_flag[HEVC_MAX_SUB_LAYERS]; - // TODO: much of that again for each sub-layer. + uint8_t sub_layer_profile_space[HEVC_MAX_SUB_LAYERS]; + uint8_t sub_layer_tier_flag[HEVC_MAX_SUB_LAYERS]; + uint8_t sub_layer_profile_idc[HEVC_MAX_SUB_LAYERS]; + + uint8_t sub_layer_profile_compatibility_flag[HEVC_MAX_SUB_LAYERS][32]; + + uint8_t sub_layer_progressive_source_flag[HEVC_MAX_SUB_LAYERS]; + uint8_t sub_layer_interlaced_source_flag[HEVC_MAX_SUB_LAYERS]; + uint8_t sub_layer_non_packed_constraint_flag[HEVC_MAX_SUB_LAYERS]; + uint8_t sub_layer_frame_only_constraint_flag[HEVC_MAX_SUB_LAYERS]; + + uint8_t sub_layer_max_12bit_constraint_flag[HEVC_MAX_SUB_LAYERS]; + uint8_t sub_layer_max_10bit_constraint_flag[HEVC_MAX_SUB_LAYERS]; + uint8_t sub_layer_max_8bit_constraint_flag[HEVC_MAX_SUB_LAYERS]; + uint8_t sub_layer_max_422chroma_constraint_flag[HEVC_MAX_SUB_LAYERS]; + uint8_t sub_layer_max_420chroma_constraint_flag[HEVC_MAX_SUB_LAYERS]; + uint8_t sub_layer_max_monochrome_constraint_flag[HEVC_MAX_SUB_LAYERS]; + uint8_t sub_layer_intra_constraint_flag[HEVC_MAX_SUB_LAYERS]; + uint8_t sub_layer_one_picture_only_constraint_flag[HEVC_MAX_SUB_LAYERS]; + uint8_t sub_layer_lower_bit_rate_constraint_flag[HEVC_MAX_SUB_LAYERS]; + uint8_t sub_layer_max_14bit_constraint_flag[HEVC_MAX_SUB_LAYERS]; + + uint8_t sub_layer_inbld_flag[HEVC_MAX_SUB_LAYERS]; + + uint8_t sub_layer_level_idc[HEVC_MAX_SUB_LAYERS]; } H265RawProfileTierLevel; typedef struct H265RawSubLayerHRDParameters { @@ -517,12 +548,191 @@ typedef struct H265RawSlice { } H265RawSlice; +typedef struct H265RawSEIBufferingPeriod { + uint8_t bp_seq_parameter_set_id; + uint8_t irap_cpb_params_present_flag; + uint32_t cpb_delay_offset; + uint32_t dpb_delay_offset; + uint8_t concatenation_flag; + uint32_t au_cpb_removal_delay_delta_minus1; + + uint32_t nal_initial_cpb_removal_delay[HEVC_MAX_CPB_CNT]; + uint32_t nal_initial_cpb_removal_offset[HEVC_MAX_CPB_CNT]; + uint32_t nal_initial_alt_cpb_removal_delay[HEVC_MAX_CPB_CNT]; + uint32_t nal_initial_alt_cpb_removal_offset[HEVC_MAX_CPB_CNT]; + + uint32_t vcl_initial_cpb_removal_delay[HEVC_MAX_CPB_CNT]; + uint32_t vcl_initial_cpb_removal_offset[HEVC_MAX_CPB_CNT]; + uint32_t vcl_initial_alt_cpb_removal_delay[HEVC_MAX_CPB_CNT]; + uint32_t vcl_initial_alt_cpb_removal_offset[HEVC_MAX_CPB_CNT]; + + uint8_t use_alt_cpb_params_flag; +} H265RawSEIBufferingPeriod; + +typedef struct H265RawSEIPicTiming { + uint8_t pic_struct; + uint8_t source_scan_type; + uint8_t duplicate_flag; + + uint32_t au_cpb_removal_delay_minus1; + uint32_t pic_dpb_output_delay; + uint32_t pic_dpb_output_du_delay; + + uint16_t num_decoding_units_minus1; + uint8_t du_common_cpb_removal_delay_flag; + uint32_t du_common_cpb_removal_delay_increment_minus1; + uint16_t num_nalus_in_du_minus1[HEVC_MAX_SLICE_SEGMENTS]; + uint32_t du_cpb_removal_delay_increment_minus1[HEVC_MAX_SLICE_SEGMENTS]; +} H265RawSEIPicTiming; + +typedef struct H265RawSEIPanScanRect { + uint32_t pan_scan_rect_id; + uint8_t pan_scan_rect_cancel_flag; + uint8_t pan_scan_cnt_minus1; + int32_t pan_scan_rect_left_offset[3]; + int32_t pan_scan_rect_right_offset[3]; + int32_t pan_scan_rect_top_offset[3]; + int32_t pan_scan_rect_bottom_offset[3]; + uint16_t pan_scan_rect_persistence_flag; +} H265RawSEIPanScanRect; + +typedef struct H265RawSEIUserDataRegistered { + uint8_t itu_t_t35_country_code; + uint8_t itu_t_t35_country_code_extension_byte; + uint8_t *data; + size_t data_length; + AVBufferRef *data_ref; +} H265RawSEIUserDataRegistered; + +typedef struct H265RawSEIUserDataUnregistered { + uint8_t uuid_iso_iec_11578[16]; + uint8_t *data; + size_t data_length; + AVBufferRef *data_ref; +} H265RawSEIUserDataUnregistered; + +typedef struct H265RawSEIRecoveryPoint { + int16_t recovery_poc_cnt; + uint8_t exact_match_flag; + uint8_t broken_link_flag; +} H265RawSEIRecoveryPoint; + +typedef struct H265RawSEIDisplayOrientation { + uint8_t display_orientation_cancel_flag; + uint8_t hor_flip; + uint8_t ver_flip; + uint16_t anticlockwise_rotation; + uint16_t display_orientation_repetition_period; + uint8_t display_orientation_persistence_flag; +} H265RawSEIDisplayOrientation; + +typedef struct H265RawSEIActiveParameterSets { + uint8_t active_video_parameter_set_id; + uint8_t self_contained_cvs_flag; + uint8_t no_parameter_set_update_flag; + uint8_t num_sps_ids_minus1; + uint8_t active_seq_parameter_set_id[HEVC_MAX_SPS_COUNT]; + uint8_t layer_sps_idx[HEVC_MAX_LAYERS]; +} H265RawSEIActiveParameterSets; + +typedef struct H265RawSEIDecodedPictureHash { + uint8_t hash_type; + uint8_t picture_md5[3][16]; + uint16_t picture_crc[3]; + uint32_t picture_checksum[3]; +} H265RawSEIDecodedPictureHash; + +typedef struct H265RawSEITimeCode { + uint8_t num_clock_ts; + uint8_t clock_timestamp_flag[3]; + uint8_t units_field_based_flag[3]; + uint8_t counting_type[3]; + uint8_t full_timestamp_flag[3]; + uint8_t discontinuity_flag[3]; + uint8_t cnt_dropped_flag[3]; + uint16_t n_frames[3]; + uint8_t seconds_value[3]; + uint8_t minutes_value[3]; + uint8_t hours_value[3]; + uint8_t seconds_flag[3]; + uint8_t minutes_flag[3]; + uint8_t hours_flag[3]; + uint8_t time_offset_length[3]; + int32_t time_offset_value[3]; +} H265RawSEITimeCode; + +typedef struct H265RawSEIMasteringDisplayColourVolume { + uint16_t display_primaries_x[3]; + uint16_t display_primaries_y[3]; + uint16_t white_point_x; + uint16_t white_point_y; + uint32_t max_display_mastering_luminance; + uint32_t min_display_mastering_luminance; +} H265RawSEIMasteringDisplayColourVolume; + +typedef struct H265RawSEIContentLightLevelInfo { + uint16_t max_content_light_level; + uint16_t max_pic_average_light_level; +} H265RawSEIContentLightLevelInfo; + +typedef struct H265RawSEIAlternativeTransferCharacteristics { + uint8_t preferred_transfer_characteristics; +} H265RawSEIAlternativeTransferCharacteristics; + +typedef struct H265RawSEIAlphaChannelInfo { + uint8_t alpha_channel_cancel_flag; + uint8_t alpha_channel_use_idc; + uint8_t alpha_channel_bit_depth_minus8; + uint16_t alpha_transparent_value; + uint16_t alpha_opaque_value; + uint8_t alpha_channel_incr_flag; + uint8_t alpha_channel_clip_flag; + uint8_t alpha_channel_clip_type_flag; +} H265RawSEIAlphaChannelInfo; + +typedef struct H265RawSEIPayload { + uint32_t payload_type; + uint32_t payload_size; + union { + H265RawSEIBufferingPeriod buffering_period; + H265RawSEIPicTiming pic_timing; + H265RawSEIPanScanRect pan_scan_rect; + H265RawSEIUserDataRegistered user_data_registered; + H265RawSEIUserDataUnregistered user_data_unregistered; + H265RawSEIRecoveryPoint recovery_point; + H265RawSEIDisplayOrientation display_orientation; + H265RawSEIActiveParameterSets active_parameter_sets; + H265RawSEIDecodedPictureHash decoded_picture_hash; + H265RawSEITimeCode time_code; + H265RawSEIMasteringDisplayColourVolume mastering_display; + H265RawSEIContentLightLevelInfo content_light_level; + H265RawSEIAlternativeTransferCharacteristics + alternative_transfer_characteristics; + H265RawSEIAlphaChannelInfo alpha_channel_info; + struct { + uint8_t *data; + size_t data_length; + AVBufferRef *data_ref; + } other; + } payload; +} H265RawSEIPayload; + +typedef struct H265RawSEI { + H265RawNALUnitHeader nal_unit_header; + + H265RawSEIPayload payload[H265_MAX_SEI_PAYLOADS]; + uint8_t payload_count; +} H265RawSEI; + typedef struct CodedBitstreamH265Context { // Reader/writer context in common with the H.264 implementation. CodedBitstreamH2645Context common; // All currently available parameter sets. These are updated when // any parameter set NAL unit is read/written with this context. + AVBufferRef *vps_ref[HEVC_MAX_VPS_COUNT]; + AVBufferRef *sps_ref[HEVC_MAX_SPS_COUNT]; + AVBufferRef *pps_ref[HEVC_MAX_PPS_COUNT]; H265RawVPS *vps[HEVC_MAX_VPS_COUNT]; H265RawSPS *sps[HEVC_MAX_SPS_COUNT]; H265RawPPS *pps[HEVC_MAX_PPS_COUNT]; diff --git a/libavcodec/cbs_h265_syntax_template.c b/libavcodec/cbs_h265_syntax_template.c index 140c827c9..54570929e 100644 --- a/libavcodec/cbs_h265_syntax_template.c +++ b/libavcodec/cbs_h265_syntax_template.c @@ -19,10 +19,10 @@ static int FUNC(rbsp_trailing_bits)(CodedBitstreamContext *ctx, RWContext *rw) { int err; - av_unused int one = 1, zero = 0; - xu(1, rbsp_stop_one_bit, one, 1, 1); + + fixed(1, rbsp_stop_one_bit, 1); while (byte_alignment(rw) != 0) - xu(1, rbsp_alignment_zero_bit, zero, 0, 0); + fixed(1, rbsp_alignment_zero_bit, 0); return 0; } @@ -33,13 +33,13 @@ static int FUNC(nal_unit_header)(CodedBitstreamContext *ctx, RWContext *rw, { int err; - u(1, forbidden_zero_bit, 0, 0); + fixed(1, forbidden_zero_bit, 0); if (expected_nal_unit_type >= 0) u(6, nal_unit_type, expected_nal_unit_type, expected_nal_unit_type); else - u(6, nal_unit_type, 0, 63); + ub(6, nal_unit_type); u(6, nuh_layer_id, 0, 62); u(3, nuh_temporal_id_plus1, 1, 7); @@ -50,10 +50,10 @@ static int FUNC(nal_unit_header)(CodedBitstreamContext *ctx, RWContext *rw, static int FUNC(byte_alignment)(CodedBitstreamContext *ctx, RWContext *rw) { int err; - av_unused int one = 1, zero = 0; - xu(1, alignment_bit_equal_to_one, one, 1, 1); + + fixed(1, alignment_bit_equal_to_one, 1); while (byte_alignment(rw) != 0) - xu(1, alignment_bit_equal_to_zero, zero, 0, 0); + fixed(1, alignment_bit_equal_to_zero, 0); return 0; } @@ -74,13 +74,13 @@ static int FUNC(extension_data)(CodedBitstreamContext *ctx, RWContext *rw, *rw = start; allocate(current->data, (current->bit_length + 7) / 8); for (k = 0; k < current->bit_length; k++) { - xu(1, extension_data, bit, 0, 1); + xu(1, extension_data, bit, 0, 1, 0); current->data[k / 8] |= bit << (7 - k % 8); } } #else for (k = 0; k < current->bit_length; k++) - xu(1, extension_data, current->data[k / 8] >> (7 - k % 8), 0, 1); + xu(1, extension_data, current->data[k / 8] >> (7 - k % 8), 0, 1, 0); #endif return 0; } @@ -90,16 +90,15 @@ static int FUNC(profile_tier_level)(CodedBitstreamContext *ctx, RWContext *rw, int profile_present_flag, int max_num_sub_layers_minus1) { - av_unused unsigned int zero = 0; int err, i, j; if (profile_present_flag) { u(2, general_profile_space, 0, 0); flag(general_tier_flag); - u(5, general_profile_idc, 0, 31); + ub(5, general_profile_idc); for (j = 0; j < 32; j++) - flag(general_profile_compatibility_flag[j]); + flags(general_profile_compatibility_flag[j], 1, j); flag(general_progressive_source_flag); flag(general_interlaced_source_flag); @@ -125,15 +124,20 @@ static int FUNC(profile_tier_level)(CodedBitstreamContext *ctx, RWContext *rw, if (profile_compatible(5) || profile_compatible(9) || profile_compatible(10)) { flag(general_max_14bit_constraint_flag); - xu(24, general_reserved_zero_33bits, zero, 0, 0); - xu(9, general_reserved_zero_33bits, zero, 0, 0); + fixed(24, general_reserved_zero_33bits, 0); + fixed( 9, general_reserved_zero_33bits, 0); } else { - xu(24, general_reserved_zero_34bits, zero, 0, 0); - xu(10, general_reserved_zero_34bits, zero, 0, 0); + fixed(24, general_reserved_zero_34bits, 0); + fixed(10, general_reserved_zero_34bits, 0); } + } else if (profile_compatible(2)) { + fixed(7, general_reserved_zero_7bits, 0); + flag(general_one_picture_only_constraint_flag); + fixed(24, general_reserved_zero_35bits, 0); + fixed(11, general_reserved_zero_35bits, 0); } else { - xu(24, general_reserved_zero_43bits, zero, 0, 0); - xu(19, general_reserved_zero_43bits, zero, 0, 0); + fixed(24, general_reserved_zero_43bits, 0); + fixed(19, general_reserved_zero_43bits, 0); } if (profile_compatible(1) || profile_compatible(2) || @@ -141,30 +145,82 @@ static int FUNC(profile_tier_level)(CodedBitstreamContext *ctx, RWContext *rw, profile_compatible(5) || profile_compatible(9)) { flag(general_inbld_flag); } else { - xu(1, general_reserved_zero_bit, zero, 0, 0); + fixed(1, general_reserved_zero_bit, 0); } #undef profile_compatible } - u(8, general_level_idc, 0, 255); + ub(8, general_level_idc); for (i = 0; i < max_num_sub_layers_minus1; i++) { - flag(sub_layer_profile_present_flag[i]); - flag(sub_layer_level_present_flag[i]); + flags(sub_layer_profile_present_flag[i], 1, i); + flags(sub_layer_level_present_flag[i], 1, i); } if (max_num_sub_layers_minus1 > 0) { - for (i = max_num_sub_layers_minus1; i < 8; i++) { - av_unused int zero = 0; - xu(2, reserved_zero_2bits, zero, 0, 0); - } + for (i = max_num_sub_layers_minus1; i < 8; i++) + fixed(2, reserved_zero_2bits, 0); } for (i = 0; i < max_num_sub_layers_minus1; i++) { - if (current->sub_layer_profile_present_flag[i]) - return AVERROR_PATCHWELCOME; + if (current->sub_layer_profile_present_flag[i]) { + us(2, sub_layer_profile_space[i], 0, 0, 1, i); + flags(sub_layer_tier_flag[i], 1, i); + ubs(5, sub_layer_profile_idc[i], 1, i); + + for (j = 0; j < 32; j++) + flags(sub_layer_profile_compatibility_flag[i][j], 2, i, j); + + flags(sub_layer_progressive_source_flag[i], 1, i); + flags(sub_layer_interlaced_source_flag[i], 1, i); + flags(sub_layer_non_packed_constraint_flag[i], 1, i); + flags(sub_layer_frame_only_constraint_flag[i], 1, i); + +#define profile_compatible(x) (current->sub_layer_profile_idc[i] == (x) || \ + current->sub_layer_profile_compatibility_flag[i][x]) + if (profile_compatible(4) || profile_compatible(5) || + profile_compatible(6) || profile_compatible(7) || + profile_compatible(8) || profile_compatible(9) || + profile_compatible(10)) { + flags(sub_layer_max_12bit_constraint_flag[i], 1, i); + flags(sub_layer_max_10bit_constraint_flag[i], 1, i); + flags(sub_layer_max_8bit_constraint_flag[i], 1, i); + flags(sub_layer_max_422chroma_constraint_flag[i], 1, i); + flags(sub_layer_max_420chroma_constraint_flag[i], 1, i); + flags(sub_layer_max_monochrome_constraint_flag[i], 1, i); + flags(sub_layer_intra_constraint_flag[i], 1, i); + flags(sub_layer_one_picture_only_constraint_flag[i], 1, i); + flags(sub_layer_lower_bit_rate_constraint_flag[i], 1, i); + + if (profile_compatible(5)) { + flags(sub_layer_max_14bit_constraint_flag[i], 1, i); + fixed(24, sub_layer_reserved_zero_33bits, 0); + fixed( 9, sub_layer_reserved_zero_33bits, 0); + } else { + fixed(24, sub_layer_reserved_zero_34bits, 0); + fixed(10, sub_layer_reserved_zero_34bits, 0); + } + } else if (profile_compatible(2)) { + fixed(7, sub_layer_reserved_zero_7bits, 0); + flags(sub_layer_one_picture_only_constraint_flag[i], 1, i); + fixed(24, sub_layer_reserved_zero_43bits, 0); + fixed(11, sub_layer_reserved_zero_43bits, 0); + } else { + fixed(24, sub_layer_reserved_zero_43bits, 0); + fixed(19, sub_layer_reserved_zero_43bits, 0); + } + + if (profile_compatible(1) || profile_compatible(2) || + profile_compatible(3) || profile_compatible(4) || + profile_compatible(5) || profile_compatible(9)) { + flags(sub_layer_inbld_flag[i], 1, i); + } else { + fixed(1, sub_layer_reserved_zero_bit, 0); + } +#undef profile_compatible + } if (current->sub_layer_level_present_flag[i]) - return AVERROR_PATCHWELCOME; + ubs(8, sub_layer_level_idc[i], 1, i); } return 0; @@ -183,13 +239,13 @@ static int FUNC(sub_layer_hrd_parameters)(CodedBitstreamContext *ctx, RWContext current = &hrd->vcl_sub_layer_hrd_parameters[sub_layer_id]; for (i = 0; i <= hrd->cpb_cnt_minus1[sub_layer_id]; i++) { - ue(bit_rate_value_minus1[i], 0, UINT32_MAX - 1); - ue(cpb_size_value_minus1[i], 0, UINT32_MAX - 1); + ues(bit_rate_value_minus1[i], 0, UINT32_MAX - 1, 1, i); + ues(cpb_size_value_minus1[i], 0, UINT32_MAX - 1, 1, i); if (hrd->sub_pic_hrd_params_present_flag) { - ue(cpb_size_du_value_minus1[i], 0, UINT32_MAX - 1); - ue(bit_rate_du_value_minus1[i], 0, UINT32_MAX - 1); + ues(cpb_size_du_value_minus1[i], 0, UINT32_MAX - 1, 1, i); + ues(bit_rate_du_value_minus1[i], 0, UINT32_MAX - 1, 1, i); } - flag(cbr_flag[i]); + flags(cbr_flag[i], 1, i); } return 0; @@ -209,20 +265,20 @@ static int FUNC(hrd_parameters)(CodedBitstreamContext *ctx, RWContext *rw, current->vcl_hrd_parameters_present_flag) { flag(sub_pic_hrd_params_present_flag); if (current->sub_pic_hrd_params_present_flag) { - u(8, tick_divisor_minus2, 0, 255); - u(5, du_cpb_removal_delay_increment_length_minus1, 0, 31); + ub(8, tick_divisor_minus2); + ub(5, du_cpb_removal_delay_increment_length_minus1); flag(sub_pic_cpb_params_in_pic_timing_sei_flag); - u(5, dpb_output_delay_du_length_minus1, 0, 31); + ub(5, dpb_output_delay_du_length_minus1); } - u(4, bit_rate_scale, 0, 15); - u(4, cpb_size_scale, 0, 15); + ub(4, bit_rate_scale); + ub(4, cpb_size_scale); if (current->sub_pic_hrd_params_present_flag) - u(4, cpb_size_du_scale, 0, 15); + ub(4, cpb_size_du_scale); - u(5, initial_cpb_removal_delay_length_minus1, 0, 31); - u(5, au_cpb_removal_delay_length_minus1, 0, 31); - u(5, dpb_output_delay_length_minus1, 0, 31); + ub(5, initial_cpb_removal_delay_length_minus1); + ub(5, au_cpb_removal_delay_length_minus1); + ub(5, dpb_output_delay_length_minus1); } else { infer(sub_pic_hrd_params_present_flag, 0); @@ -233,21 +289,21 @@ static int FUNC(hrd_parameters)(CodedBitstreamContext *ctx, RWContext *rw, } for (i = 0; i <= max_num_sub_layers_minus1; i++) { - flag(fixed_pic_rate_general_flag[i]); + flags(fixed_pic_rate_general_flag[i], 1, i); if (!current->fixed_pic_rate_general_flag[i]) - flag(fixed_pic_rate_within_cvs_flag[i]); + flags(fixed_pic_rate_within_cvs_flag[i], 1, i); else infer(fixed_pic_rate_within_cvs_flag[i], 1); if (current->fixed_pic_rate_within_cvs_flag[i]) { - ue(elemental_duration_in_tc_minus1[i], 0, 2047); + ues(elemental_duration_in_tc_minus1[i], 0, 2047, 1, i); infer(low_delay_hrd_flag[i], 0); } else - flag(low_delay_hrd_flag[i]); + flags(low_delay_hrd_flag[i], 1, i); if (!current->low_delay_hrd_flag[i]) - ue(cpb_cnt_minus1[i], 0, 31); + ues(cpb_cnt_minus1[i], 0, 31, 1, i); else infer(cpb_cnt_minus1[i], 0); @@ -267,10 +323,10 @@ static int FUNC(vui_parameters)(CodedBitstreamContext *ctx, RWContext *rw, flag(aspect_ratio_info_present_flag); if (current->aspect_ratio_info_present_flag) { - u(8, aspect_ratio_idc, 0, 255); + ub(8, aspect_ratio_idc); if (current->aspect_ratio_idc == 255) { - u(16, sar_width, 0, 65535); - u(16, sar_height, 0, 65535); + ub(16, sar_width); + ub(16, sar_height); } } else { infer(aspect_ratio_idc, 0); @@ -282,13 +338,13 @@ static int FUNC(vui_parameters)(CodedBitstreamContext *ctx, RWContext *rw, flag(video_signal_type_present_flag); if (current->video_signal_type_present_flag) { - u(3, video_format, 0, 7); + ub(3, video_format); flag(video_full_range_flag); flag(colour_description_present_flag); if (current->colour_description_present_flag) { - u(8, colour_primaries, 0, 255); - u(8, transfer_characteristics, 0, 255); - u(8, matrix_coefficients, 0, 255); + ub(8, colour_primaries); + ub(8, transfer_characteristics); + ub(8, matrix_coefficients); } else { infer(colour_primaries, 2); infer(transfer_characteristics, 2); @@ -370,7 +426,7 @@ static int FUNC(vps)(CodedBitstreamContext *ctx, RWContext *rw, CHECK(FUNC(nal_unit_header)(ctx, rw, ¤t->nal_unit_header, HEVC_NAL_VPS)); - u(4, vps_video_parameter_set_id, 0, 15); + ub(4, vps_video_parameter_set_id); flag(vps_base_layer_internal_flag); flag(vps_base_layer_available_flag); @@ -386,10 +442,7 @@ static int FUNC(vps)(CodedBitstreamContext *ctx, RWContext *rw, return AVERROR_INVALIDDATA; } - { - av_unused uint16_t ffff = 0xffff; - xu(16, vps_reserved_0xffff_16bits, ffff, 0xffff, 0xffff); - } + fixed(16, vps_reserved_0xffff_16bits, 0xffff); CHECK(FUNC(profile_tier_level)(ctx, rw, ¤t->profile_tier_level, 1, current->vps_max_sub_layers_minus1)); @@ -398,9 +451,12 @@ static int FUNC(vps)(CodedBitstreamContext *ctx, RWContext *rw, for (i = (current->vps_sub_layer_ordering_info_present_flag ? 0 : current->vps_max_sub_layers_minus1); i <= current->vps_max_sub_layers_minus1; i++) { - ue(vps_max_dec_pic_buffering_minus1[i], 0, HEVC_MAX_DPB_SIZE - 1); - ue(vps_max_num_reorder_pics[i], 0, current->vps_max_dec_pic_buffering_minus1[i]); - ue(vps_max_latency_increase_plus1[i], 0, UINT32_MAX - 1); + ues(vps_max_dec_pic_buffering_minus1[i], + 0, HEVC_MAX_DPB_SIZE - 1, 1, i); + ues(vps_max_num_reorder_pics[i], + 0, current->vps_max_dec_pic_buffering_minus1[i], 1, i); + ues(vps_max_latency_increase_plus1[i], + 0, UINT32_MAX - 1, 1, i); } if (!current->vps_sub_layer_ordering_info_present_flag) { for (i = 0; i < current->vps_max_sub_layers_minus1; i++) { @@ -417,7 +473,7 @@ static int FUNC(vps)(CodedBitstreamContext *ctx, RWContext *rw, ue(vps_num_layer_sets_minus1, 0, HEVC_MAX_LAYER_SETS - 1); for (i = 1; i <= current->vps_num_layer_sets_minus1; i++) { for (j = 0; j <= current->vps_max_layer_id; j++) - flag(layer_id_included_flag[i][j]); + flags(layer_id_included_flag[i][j], 2, i, j); } for (j = 0; j <= current->vps_max_layer_id; j++) infer(layer_id_included_flag[0][j], j == 0); @@ -431,11 +487,11 @@ static int FUNC(vps)(CodedBitstreamContext *ctx, RWContext *rw, ue(vps_num_ticks_poc_diff_one_minus1, 0, UINT32_MAX - 1); ue(vps_num_hrd_parameters, 0, current->vps_num_layer_sets_minus1 + 1); for (i = 0; i < current->vps_num_hrd_parameters; i++) { - ue(hrd_layer_set_idx[i], - current->vps_base_layer_internal_flag ? 0 : 1, - current->vps_num_layer_sets_minus1); + ues(hrd_layer_set_idx[i], + current->vps_base_layer_internal_flag ? 0 : 1, + current->vps_num_layer_sets_minus1, 1, i); if (i > 0) - flag(cprms_present_flag[i]); + flags(cprms_present_flag[i], 1, i); else infer(cprms_present_flag[0], 1); @@ -489,9 +545,9 @@ static int FUNC(st_ref_pic_set)(CodedBitstreamContext *ctx, RWContext *rw, (current->abs_delta_rps_minus1 + 1); for (j = 0; j <= num_delta_pocs; j++) { - flag(used_by_curr_pic_flag[j]); + flags(used_by_curr_pic_flag[j], 1, j); if (!current->used_by_curr_pic_flag[j]) - flag(use_delta_flag[j]); + flags(use_delta_flag[j], 1, j); else infer(use_delta_flag[j], 1); } @@ -586,13 +642,13 @@ static int FUNC(st_ref_pic_set)(CodedBitstreamContext *ctx, RWContext *rw, ue(num_positive_pics, 0, 15 - current->num_negative_pics); for (i = 0; i < current->num_negative_pics; i++) { - ue(delta_poc_s0_minus1[i], 0, INT16_MAX); - flag(used_by_curr_pic_s0_flag[i]); + ues(delta_poc_s0_minus1[i], 0, INT16_MAX, 1, i); + flags(used_by_curr_pic_s0_flag[i], 1, i); } for (i = 0; i < current->num_positive_pics; i++) { - ue(delta_poc_s1_minus1[i], 0, INT16_MAX); - flag(used_by_curr_pic_s1_flag[i]); + ues(delta_poc_s1_minus1[i], 0, INT16_MAX, 1, i); + flags(used_by_curr_pic_s1_flag[i], 1, i); } } @@ -607,18 +663,21 @@ static int FUNC(scaling_list_data)(CodedBitstreamContext *ctx, RWContext *rw, for (sizeId = 0; sizeId < 4; sizeId++) { for (matrixId = 0; matrixId < 6; matrixId += (sizeId == 3 ? 3 : 1)) { - flag(scaling_list_pred_mode_flag[sizeId][matrixId]); + flags(scaling_list_pred_mode_flag[sizeId][matrixId], + 2, sizeId, matrixId); if (!current->scaling_list_pred_mode_flag[sizeId][matrixId]) { - ue(scaling_list_pred_matrix_id_delta[sizeId][matrixId], - 0, sizeId == 3 ? matrixId / 3 : matrixId); + ues(scaling_list_pred_matrix_id_delta[sizeId][matrixId], + 0, sizeId == 3 ? matrixId / 3 : matrixId, + 2, sizeId, matrixId); } else { n = FFMIN(64, 1 << (4 + (sizeId << 1))); - if (sizeId > 1) - se(scaling_list_dc_coef_minus8[sizeId - 2][matrixId], -7, +247); + if (sizeId > 1) { + ses(scaling_list_dc_coef_minus8[sizeId - 2][matrixId], -7, +247, + 2, sizeId - 2, matrixId); + } for (i = 0; i < n; i++) { - xse(scaling_list_delta_coeff, - current->scaling_list_delta_coeff[sizeId][matrixId][i], - -128, +127); + ses(scaling_list_delta_coeff[sizeId][matrixId][i], + -128, +127, 3, sizeId, matrixId, i); } } } @@ -664,8 +723,7 @@ static int FUNC(sps_scc_extension)(CodedBitstreamContext *ctx, RWContext *rw, int bit_depth = comp == 0 ? current->bit_depth_luma_minus8 + 8 : current->bit_depth_chroma_minus8 + 8; for (i = 0; i <= current->sps_num_palette_predictor_initializer_minus1; i++) - u(bit_depth, sps_palette_predictor_initializers[comp][i], - 0, MAX_UINT_BITS(bit_depth)); + ubs(bit_depth, sps_palette_predictor_initializers[comp][i], 2, comp, i); } } } @@ -689,7 +747,7 @@ static int FUNC(sps)(CodedBitstreamContext *ctx, RWContext *rw, CHECK(FUNC(nal_unit_header)(ctx, rw, ¤t->nal_unit_header, HEVC_NAL_SPS)); - u(4, sps_video_parameter_set_id, 0, 15); + ub(4, sps_video_parameter_set_id); h265->active_vps = vps = h265->vps[current->sps_video_parameter_set_id]; u(3, sps_max_sub_layers_minus1, 0, HEVC_MAX_SUB_LAYERS - 1); @@ -748,9 +806,12 @@ static int FUNC(sps)(CodedBitstreamContext *ctx, RWContext *rw, for (i = (current->sps_sub_layer_ordering_info_present_flag ? 0 : current->sps_max_sub_layers_minus1); i <= current->sps_max_sub_layers_minus1; i++) { - ue(sps_max_dec_pic_buffering_minus1[i], 0, HEVC_MAX_DPB_SIZE - 1); - ue(sps_max_num_reorder_pics[i], 0, current->sps_max_dec_pic_buffering_minus1[i]); - ue(sps_max_latency_increase_plus1[i], 0, UINT32_MAX - 1); + ues(sps_max_dec_pic_buffering_minus1[i], + 0, HEVC_MAX_DPB_SIZE - 1, 1, i); + ues(sps_max_num_reorder_pics[i], + 0, current->sps_max_dec_pic_buffering_minus1[i], 1, i); + ues(sps_max_latency_increase_plus1[i], + 0, UINT32_MAX - 1, 1, i); } if (!current->sps_sub_layer_ordering_info_present_flag) { for (i = 0; i < current->sps_max_sub_layers_minus1; i++) { @@ -825,10 +886,9 @@ static int FUNC(sps)(CodedBitstreamContext *ctx, RWContext *rw, if (current->long_term_ref_pics_present_flag) { ue(num_long_term_ref_pics_sps, 0, HEVC_MAX_LONG_TERM_REF_PICS); for (i = 0; i < current->num_long_term_ref_pics_sps; i++) { - u(current->log2_max_pic_order_cnt_lsb_minus4 + 4, - lt_ref_pic_poc_lsb_sps[i], - 0, MAX_UINT_BITS(current->log2_max_pic_order_cnt_lsb_minus4 + 4)); - flag(used_by_curr_pic_lt_sps_flag[i]); + ubs(current->log2_max_pic_order_cnt_lsb_minus4 + 4, + lt_ref_pic_poc_lsb_sps[i], 1, i); + flags(used_by_curr_pic_lt_sps_flag[i], 1, i); } } @@ -845,7 +905,7 @@ static int FUNC(sps)(CodedBitstreamContext *ctx, RWContext *rw, flag(sps_multilayer_extension_flag); flag(sps_3d_extension_flag); flag(sps_scc_extension_flag); - u(4, sps_extension_4bits, 0, MAX_UINT_BITS(4)); + ub(4, sps_extension_4bits); } if (current->sps_range_extension_flag) @@ -881,8 +941,8 @@ static int FUNC(pps_range_extension)(CodedBitstreamContext *ctx, RWContext *rw, 0, sps->log2_diff_max_min_luma_coding_block_size); ue(chroma_qp_offset_list_len_minus1, 0, 5); for (i = 0; i <= current->chroma_qp_offset_list_len_minus1; i++) { - se(cb_qp_offset_list[i], -12, +12); - se(cr_qp_offset_list[i], -12, +12); + ses(cb_qp_offset_list[i], -12, +12, 1, i); + ses(cr_qp_offset_list[i], -12, +12, 1, i); } } @@ -924,8 +984,7 @@ static int FUNC(pps_scc_extension)(CodedBitstreamContext *ctx, RWContext *rw, int bit_depth = comp == 0 ? current->luma_bit_depth_entry_minus8 + 8 : current->chroma_bit_depth_entry_minus8 + 8; for (i = 0; i < current->pps_num_palette_predictor_initializer; i++) - u(bit_depth, pps_palette_predictor_initializers[comp][i], - 0, MAX_UINT_BITS(bit_depth)); + ubs(bit_depth, pps_palette_predictor_initializers[comp][i], 2, comp, i); } } } @@ -956,7 +1015,7 @@ static int FUNC(pps)(CodedBitstreamContext *ctx, RWContext *rw, flag(dependent_slice_segments_enabled_flag); flag(output_flag_present_flag); - u(3, num_extra_slice_header_bits, 0, 7); + ub(3, num_extra_slice_header_bits); flag(sign_data_hiding_enabled_flag); flag(cabac_init_present_flag); @@ -991,9 +1050,9 @@ static int FUNC(pps)(CodedBitstreamContext *ctx, RWContext *rw, flag(uniform_spacing_flag); if (!current->uniform_spacing_flag) { for (i = 0; i < current->num_tile_columns_minus1; i++) - ue(column_width_minus1[i], 0, sps->pic_width_in_luma_samples); + ues(column_width_minus1[i], 0, sps->pic_width_in_luma_samples, 1, i); for (i = 0; i < current->num_tile_rows_minus1; i++) - ue(row_height_minus1[i], 0, sps->pic_height_in_luma_samples); + ues(row_height_minus1[i], 0, sps->pic_height_in_luma_samples, 1, i); } flag(loop_filter_across_tiles_enabled_flag); } else { @@ -1038,7 +1097,7 @@ static int FUNC(pps)(CodedBitstreamContext *ctx, RWContext *rw, flag(pps_multilayer_extension_flag); flag(pps_3d_extension_flag); flag(pps_scc_extension_flag); - u(4, pps_extension_4bits, 0, MAX_UINT_BITS(4)); + ub(4, pps_extension_4bits); } if (current->pps_range_extension_flag) CHECK(FUNC(pps_range_extension)(ctx, rw, current)); @@ -1084,14 +1143,14 @@ static int FUNC(ref_pic_lists_modification)(CodedBitstreamContext *ctx, RWContex flag(ref_pic_list_modification_flag_l0); if (current->ref_pic_list_modification_flag_l0) { for (i = 0; i <= current->num_ref_idx_l0_active_minus1; i++) - u(entry_size, list_entry_l0[i], 0, num_pic_total_curr - 1); + us(entry_size, list_entry_l0[i], 0, num_pic_total_curr - 1, 1, i); } if (current->slice_type == HEVC_SLICE_B) { flag(ref_pic_list_modification_flag_l1); if (current->ref_pic_list_modification_flag_l1) { for (i = 0; i <= current->num_ref_idx_l1_active_minus1; i++) - u(entry_size, list_entry_l1[i], 0, num_pic_total_curr - 1); + us(entry_size, list_entry_l1[i], 0, num_pic_total_curr - 1, 1, i); } } @@ -1115,14 +1174,14 @@ static int FUNC(pred_weight_table)(CodedBitstreamContext *ctx, RWContext *rw, for (i = 0; i <= current->num_ref_idx_l0_active_minus1; i++) { if (1 /* is not same POC and same layer_id */) - flag(luma_weight_l0_flag[i]); + flags(luma_weight_l0_flag[i], 1, i); else infer(luma_weight_l0_flag[i], 0); } if (chroma) { for (i = 0; i <= current->num_ref_idx_l0_active_minus1; i++) { if (1 /* is not same POC and same layer_id */) - flag(chroma_weight_l0_flag[i]); + flags(chroma_weight_l0_flag[i], 1, i); else infer(chroma_weight_l0_flag[i], 0); } @@ -1130,20 +1189,20 @@ static int FUNC(pred_weight_table)(CodedBitstreamContext *ctx, RWContext *rw, for (i = 0; i <= current->num_ref_idx_l0_active_minus1; i++) { if (current->luma_weight_l0_flag[i]) { - se(delta_luma_weight_l0[i], -128, +127); - se(luma_offset_l0[i], - -(1 << (sps->bit_depth_luma_minus8 + 8 - 1)), - ((1 << (sps->bit_depth_luma_minus8 + 8 - 1)) - 1)); + ses(delta_luma_weight_l0[i], -128, +127, 1, i); + ses(luma_offset_l0[i], + -(1 << (sps->bit_depth_luma_minus8 + 8 - 1)), + ((1 << (sps->bit_depth_luma_minus8 + 8 - 1)) - 1), 1, i); } else { infer(delta_luma_weight_l0[i], 0); infer(luma_offset_l0[i], 0); } if (current->chroma_weight_l0_flag[i]) { for (j = 0; j < 2; j++) { - se(delta_chroma_weight_l0[i][j], -128, +127); - se(chroma_offset_l0[i][j], - -(4 << (sps->bit_depth_chroma_minus8 + 8 - 1)), - ((4 << (sps->bit_depth_chroma_minus8 + 8 - 1)) - 1)); + ses(delta_chroma_weight_l0[i][j], -128, +127, 2, i, j); + ses(chroma_offset_l0[i][j], + -(4 << (sps->bit_depth_chroma_minus8 + 8 - 1)), + ((4 << (sps->bit_depth_chroma_minus8 + 8 - 1)) - 1), 2, i, j); } } else { for (j = 0; j < 2; j++) { @@ -1156,14 +1215,14 @@ static int FUNC(pred_weight_table)(CodedBitstreamContext *ctx, RWContext *rw, if (current->slice_type == HEVC_SLICE_B) { for (i = 0; i <= current->num_ref_idx_l1_active_minus1; i++) { if (1 /* RefPicList1[i] is not CurrPic, nor is it in a different layer */) - flag(luma_weight_l1_flag[i]); + flags(luma_weight_l1_flag[i], 1, i); else infer(luma_weight_l1_flag[i], 0); } if (chroma) { for (i = 0; i <= current->num_ref_idx_l1_active_minus1; i++) { if (1 /* RefPicList1[i] is not CurrPic, nor is it in a different layer */) - flag(chroma_weight_l1_flag[i]); + flags(chroma_weight_l1_flag[i], 1, i); else infer(chroma_weight_l1_flag[i], 0); } @@ -1171,20 +1230,20 @@ static int FUNC(pred_weight_table)(CodedBitstreamContext *ctx, RWContext *rw, for (i = 0; i <= current->num_ref_idx_l1_active_minus1; i++) { if (current->luma_weight_l1_flag[i]) { - se(delta_luma_weight_l1[i], -128, +127); - se(luma_offset_l1[i], - -(1 << (sps->bit_depth_luma_minus8 + 8 - 1)), - ((1 << (sps->bit_depth_luma_minus8 + 8 - 1)) - 1)); + ses(delta_luma_weight_l1[i], -128, +127, 1, i); + ses(luma_offset_l1[i], + -(1 << (sps->bit_depth_luma_minus8 + 8 - 1)), + ((1 << (sps->bit_depth_luma_minus8 + 8 - 1)) - 1), 1, i); } else { infer(delta_luma_weight_l1[i], 0); infer(luma_offset_l1[i], 0); } if (current->chroma_weight_l1_flag[i]) { for (j = 0; j < 2; j++) { - se(delta_chroma_weight_l1[i][j], -128, +127); - se(chroma_offset_l1[i][j], - -(4 << (sps->bit_depth_chroma_minus8 + 8 - 1)), - ((4 << (sps->bit_depth_chroma_minus8 + 8 - 1)) - 1)); + ses(delta_chroma_weight_l1[i][j], -128, +127, 2, i, j); + ses(chroma_offset_l1[i][j], + -(4 << (sps->bit_depth_chroma_minus8 + 8 - 1)), + ((4 << (sps->bit_depth_chroma_minus8 + 8 - 1)) - 1), 2, i, j); } } else { for (j = 0; j < 2; j++) { @@ -1259,7 +1318,7 @@ static int FUNC(slice_segment_header)(CodedBitstreamContext *ctx, RWContext *rw, if (!current->dependent_slice_segment_flag) { for (i = 0; i < pps->num_extra_slice_header_bits; i++) - flag(slice_reserved_flag[i]); + flags(slice_reserved_flag[i], 1, i); ue(slice_type, 0, 2); @@ -1273,8 +1332,7 @@ static int FUNC(slice_segment_header)(CodedBitstreamContext *ctx, RWContext *rw, current->nal_unit_header.nal_unit_type != HEVC_NAL_IDR_N_LP) { const H265RawSTRefPicSet *rps; - u(sps->log2_max_pic_order_cnt_lsb_minus4 + 4, slice_pic_order_cnt_lsb, - 0, MAX_UINT_BITS(sps->log2_max_pic_order_cnt_lsb_minus4 + 4)); + ub(sps->log2_max_pic_order_cnt_lsb_minus4 + 4, slice_pic_order_cnt_lsb); flag(short_term_ref_pic_set_sps_flag); if (!current->short_term_ref_pic_set_sps_flag) { @@ -1315,20 +1373,19 @@ static int FUNC(slice_segment_header)(CodedBitstreamContext *ctx, RWContext *rw, current->num_long_term_pics; i++) { if (i < current->num_long_term_sps) { if (sps->num_long_term_ref_pics_sps > 1) - u(idx_size, lt_idx_sps[i], - 0, sps->num_long_term_ref_pics_sps - 1); + us(idx_size, lt_idx_sps[i], + 0, sps->num_long_term_ref_pics_sps - 1, 1, i); if (sps->used_by_curr_pic_lt_sps_flag[current->lt_idx_sps[i]]) ++num_pic_total_curr; } else { - u(sps->log2_max_pic_order_cnt_lsb_minus4 + 4, poc_lsb_lt[i], - 0, MAX_UINT_BITS(sps->log2_max_pic_order_cnt_lsb_minus4 + 4)); - flag(used_by_curr_pic_lt_flag[i]); + ubs(sps->log2_max_pic_order_cnt_lsb_minus4 + 4, poc_lsb_lt[i], 1, i); + flags(used_by_curr_pic_lt_flag[i], 1, i); if (current->used_by_curr_pic_lt_flag[i]) ++num_pic_total_curr; } - flag(delta_poc_msb_present_flag[i]); + flags(delta_poc_msb_present_flag[i], 1, i); if (current->delta_poc_msb_present_flag[i]) - ue(delta_poc_msb_cycle_lt[i], 0, UINT32_MAX - 1); + ues(delta_poc_msb_cycle_lt[i], 0, UINT32_MAX - 1, 1, i); else infer(delta_poc_msb_cycle_lt[i], 0); } @@ -1486,18 +1543,692 @@ static int FUNC(slice_segment_header)(CodedBitstreamContext *ctx, RWContext *rw, if (current->num_entry_point_offsets > 0) { ue(offset_len_minus1, 0, 31); for (i = 0; i < current->num_entry_point_offsets; i++) - u(current->offset_len_minus1 + 1, entry_point_offset_minus1[i], - 0, MAX_UINT_BITS(current->offset_len_minus1 + 1)); + ubs(current->offset_len_minus1 + 1, entry_point_offset_minus1[i], 1, i); } } if (pps->slice_segment_header_extension_present_flag) { ue(slice_segment_header_extension_length, 0, 256); for (i = 0; i < current->slice_segment_header_extension_length; i++) - u(8, slice_segment_header_extension_data_byte[i], 0x00, 0xff); + us(8, slice_segment_header_extension_data_byte[i], 0x00, 0xff, 1, i); } CHECK(FUNC(byte_alignment)(ctx, rw)); return 0; } + +static int FUNC(sei_buffering_period)(CodedBitstreamContext *ctx, RWContext *rw, + H265RawSEIBufferingPeriod *current, + uint32_t *payload_size) +{ + CodedBitstreamH265Context *h265 = ctx->priv_data; + const H265RawSPS *sps; + const H265RawHRDParameters *hrd; + int err, i, length; + +#ifdef READ + int start_pos, end_pos, bits_left; + start_pos = get_bits_count(rw); +#endif + + HEADER("Buffering Period"); + + ue(bp_seq_parameter_set_id, 0, HEVC_MAX_SPS_COUNT - 1); + + sps = h265->sps[current->bp_seq_parameter_set_id]; + if (!sps) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "SPS id %d not available.\n", + current->bp_seq_parameter_set_id); + return AVERROR_INVALIDDATA; + } + h265->active_sps = sps; + + if (!sps->vui_parameters_present_flag || + !sps->vui.vui_hrd_parameters_present_flag) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Buffering period SEI requires " + "HRD parameters to be present in SPS.\n"); + return AVERROR_INVALIDDATA; + } + hrd = &sps->vui.hrd_parameters; + if (!hrd->nal_hrd_parameters_present_flag && + !hrd->vcl_hrd_parameters_present_flag) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Buffering period SEI requires " + "NAL or VCL HRD parameters to be present.\n"); + return AVERROR_INVALIDDATA; + } + + if (!hrd->sub_pic_hrd_params_present_flag) + flag(irap_cpb_params_present_flag); + else + infer(irap_cpb_params_present_flag, 0); + if (current->irap_cpb_params_present_flag) { + length = hrd->au_cpb_removal_delay_length_minus1 + 1; + ub(length, cpb_delay_offset); + length = hrd->dpb_output_delay_length_minus1 + 1; + ub(length, dpb_delay_offset); + } else { + infer(cpb_delay_offset, 0); + infer(dpb_delay_offset, 0); + } + + flag(concatenation_flag); + + length = hrd->au_cpb_removal_delay_length_minus1 + 1; + ub(length, au_cpb_removal_delay_delta_minus1); + + if (hrd->nal_hrd_parameters_present_flag) { + for (i = 0; i <= hrd->cpb_cnt_minus1[0]; i++) { + length = hrd->initial_cpb_removal_delay_length_minus1 + 1; + + ubs(length, nal_initial_cpb_removal_delay[i], 1, i); + ubs(length, nal_initial_cpb_removal_offset[i], 1, i); + + if (hrd->sub_pic_hrd_params_present_flag || + current->irap_cpb_params_present_flag) { + ubs(length, nal_initial_alt_cpb_removal_delay[i], 1, i); + ubs(length, nal_initial_alt_cpb_removal_offset[i], 1, i); + } + } + } + if (hrd->vcl_hrd_parameters_present_flag) { + for (i = 0; i <= hrd->cpb_cnt_minus1[0]; i++) { + length = hrd->initial_cpb_removal_delay_length_minus1 + 1; + + ubs(length, vcl_initial_cpb_removal_delay[i], 1, i); + ubs(length, vcl_initial_cpb_removal_offset[i], 1, i); + + if (hrd->sub_pic_hrd_params_present_flag || + current->irap_cpb_params_present_flag) { + ubs(length, vcl_initial_alt_cpb_removal_delay[i], 1, i); + ubs(length, vcl_initial_alt_cpb_removal_offset[i], 1, i); + } + } + } + +#ifdef READ + // payload_extension_present() - true if we are before the last 1-bit + // in the payload structure, which must be in the last byte. + end_pos = get_bits_count(rw); + bits_left = *payload_size * 8 - (end_pos - start_pos); + if (bits_left > 0 && + (bits_left > 7 || ff_ctz(show_bits(rw, bits_left)) < bits_left - 1)) + flag(use_alt_cpb_params_flag); + else + infer(use_alt_cpb_params_flag, 0); +#else + if (current->use_alt_cpb_params_flag) + flag(use_alt_cpb_params_flag); +#endif + + return 0; +} + +static int FUNC(sei_pic_timing)(CodedBitstreamContext *ctx, RWContext *rw, + H265RawSEIPicTiming *current) +{ + CodedBitstreamH265Context *h265 = ctx->priv_data; + const H265RawSPS *sps; + const H265RawHRDParameters *hrd; + int err, expected_source_scan_type, i, length; + + HEADER("Picture Timing"); + + sps = h265->active_sps; + if (!sps) { + av_log(ctx->log_ctx, AV_LOG_ERROR, + "No active SPS for pic_timing.\n"); + return AVERROR_INVALIDDATA; + } + + expected_source_scan_type = 2 - + 2 * sps->profile_tier_level.general_interlaced_source_flag - + sps->profile_tier_level.general_progressive_source_flag; + + if (sps->vui.frame_field_info_present_flag) { + u(4, pic_struct, 0, 12); + u(2, source_scan_type, + expected_source_scan_type >= 0 ? expected_source_scan_type : 0, + expected_source_scan_type >= 0 ? expected_source_scan_type : 2); + flag(duplicate_flag); + } else { + infer(pic_struct, 0); + infer(source_scan_type, + expected_source_scan_type >= 0 ? expected_source_scan_type : 2); + infer(duplicate_flag, 0); + } + + if (sps->vui_parameters_present_flag && + sps->vui.vui_hrd_parameters_present_flag) + hrd = &sps->vui.hrd_parameters; + else + hrd = NULL; + if (hrd && (hrd->nal_hrd_parameters_present_flag || + hrd->vcl_hrd_parameters_present_flag)) { + length = hrd->au_cpb_removal_delay_length_minus1 + 1; + ub(length, au_cpb_removal_delay_minus1); + + length = hrd->dpb_output_delay_length_minus1 + 1; + ub(length, pic_dpb_output_delay); + + if (hrd->sub_pic_hrd_params_present_flag) { + length = hrd->dpb_output_delay_du_length_minus1 + 1; + ub(length, pic_dpb_output_du_delay); + } + + if (hrd->sub_pic_hrd_params_present_flag && + hrd->sub_pic_cpb_params_in_pic_timing_sei_flag) { + // Each decoding unit must contain at least one slice segment. + ue(num_decoding_units_minus1, 0, HEVC_MAX_SLICE_SEGMENTS); + flag(du_common_cpb_removal_delay_flag); + + length = hrd->du_cpb_removal_delay_increment_length_minus1 + 1; + if (current->du_common_cpb_removal_delay_flag) + ub(length, du_common_cpb_removal_delay_increment_minus1); + + for (i = 0; i <= current->num_decoding_units_minus1; i++) { + ues(num_nalus_in_du_minus1[i], + 0, HEVC_MAX_SLICE_SEGMENTS, 1, i); + if (!current->du_common_cpb_removal_delay_flag && + i < current->num_decoding_units_minus1) + ubs(length, du_cpb_removal_delay_increment_minus1[i], 1, i); + } + } + } + + return 0; +} + +static int FUNC(sei_pan_scan_rect)(CodedBitstreamContext *ctx, RWContext *rw, + H265RawSEIPanScanRect *current) +{ + int err, i; + + HEADER("Pan-Scan Rectangle"); + + ue(pan_scan_rect_id, 0, UINT32_MAX - 1); + flag(pan_scan_rect_cancel_flag); + + if (!current->pan_scan_rect_cancel_flag) { + ue(pan_scan_cnt_minus1, 0, 2); + + for (i = 0; i <= current->pan_scan_cnt_minus1; i++) { + ses(pan_scan_rect_left_offset[i], INT32_MIN + 1, INT32_MAX, 1, i); + ses(pan_scan_rect_right_offset[i], INT32_MIN + 1, INT32_MAX, 1, i); + ses(pan_scan_rect_top_offset[i], INT32_MIN + 1, INT32_MAX, 1, i); + ses(pan_scan_rect_bottom_offset[i], INT32_MIN + 1, INT32_MAX, 1, i); + } + + flag(pan_scan_rect_persistence_flag); + } + + return 0; +} + +static int FUNC(sei_user_data_registered)(CodedBitstreamContext *ctx, RWContext *rw, + H265RawSEIUserDataRegistered *current, + uint32_t *payload_size) +{ + int err, i, j; + + HEADER("User Data Registered ITU-T T.35"); + + u(8, itu_t_t35_country_code, 0x00, 0xff); + if (current->itu_t_t35_country_code != 0xff) + i = 1; + else { + u(8, itu_t_t35_country_code_extension_byte, 0x00, 0xff); + i = 2; + } + +#ifdef READ + if (*payload_size < i) { + av_log(ctx->log_ctx, AV_LOG_ERROR, + "Invalid SEI user data registered payload.\n"); + return AVERROR_INVALIDDATA; + } + current->data_length = *payload_size - i; +#else + *payload_size = i + current->data_length; +#endif + + allocate(current->data, current->data_length); + for (j = 0; j < current->data_length; j++) + xu(8, itu_t_t35_payload_byte[i], current->data[j], 0x00, 0xff, 1, i + j); + + return 0; +} + +static int FUNC(sei_user_data_unregistered)(CodedBitstreamContext *ctx, RWContext *rw, + H265RawSEIUserDataUnregistered *current, + uint32_t *payload_size) +{ + int err, i; + + HEADER("User Data Unregistered"); + +#ifdef READ + if (*payload_size < 16) { + av_log(ctx->log_ctx, AV_LOG_ERROR, + "Invalid SEI user data unregistered payload.\n"); + return AVERROR_INVALIDDATA; + } + current->data_length = *payload_size - 16; +#else + *payload_size = 16 + current->data_length; +#endif + + for (i = 0; i < 16; i++) + us(8, uuid_iso_iec_11578[i], 0x00, 0xff, 1, i); + + allocate(current->data, current->data_length); + + for (i = 0; i < current->data_length; i++) + xu(8, user_data_payload_byte[i], current->data[i], 0x00, 0xff, 1, i); + + return 0; +} + +static int FUNC(sei_recovery_point)(CodedBitstreamContext *ctx, RWContext *rw, + H265RawSEIRecoveryPoint *current) +{ + int err; + + HEADER("Recovery Point"); + + se(recovery_poc_cnt, -32768, 32767); + + flag(exact_match_flag); + flag(broken_link_flag); + + return 0; +} + +static int FUNC(sei_display_orientation)(CodedBitstreamContext *ctx, RWContext *rw, + H265RawSEIDisplayOrientation *current) +{ + int err; + + HEADER("Display Orientation"); + + flag(display_orientation_cancel_flag); + if (!current->display_orientation_cancel_flag) { + flag(hor_flip); + flag(ver_flip); + ub(16, anticlockwise_rotation); + flag(display_orientation_persistence_flag); + } + + return 0; +} + +static int FUNC(sei_active_parameter_sets)(CodedBitstreamContext *ctx, RWContext *rw, + H265RawSEIActiveParameterSets *current) +{ + CodedBitstreamH265Context *h265 = ctx->priv_data; + const H265RawVPS *vps; + int err, i; + + HEADER("Active Parameter Sets"); + + u(4, active_video_parameter_set_id, 0, HEVC_MAX_VPS_COUNT); + vps = h265->vps[current->active_video_parameter_set_id]; + if (!vps) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "VPS id %d not available for active " + "parameter sets.\n", current->active_video_parameter_set_id); + return AVERROR_INVALIDDATA; + } + h265->active_vps = vps; + + flag(self_contained_cvs_flag); + flag(no_parameter_set_update_flag); + + ue(num_sps_ids_minus1, 0, HEVC_MAX_SPS_COUNT - 1); + for (i = 0; i <= current->num_sps_ids_minus1; i++) + ues(active_seq_parameter_set_id[i], 0, HEVC_MAX_SPS_COUNT - 1, 1, i); + + for (i = vps->vps_base_layer_internal_flag; + i <= FFMIN(62, vps->vps_max_layers_minus1); i++) { + ues(layer_sps_idx[i], 0, current->num_sps_ids_minus1, 1, i); + + if (i == 0) + h265->active_sps = h265->sps[current->active_seq_parameter_set_id[current->layer_sps_idx[0]]]; + } + + return 0; +} + +static int FUNC(sei_decoded_picture_hash)(CodedBitstreamContext *ctx, RWContext *rw, + H265RawSEIDecodedPictureHash *current) +{ + CodedBitstreamH265Context *h265 = ctx->priv_data; + const H265RawSPS *sps = h265->active_sps; + int err, c, i; + + HEADER("Decoded Picture Hash"); + + if (!sps) { + av_log(ctx->log_ctx, AV_LOG_ERROR, + "No active SPS for decoded picture hash.\n"); + return AVERROR_INVALIDDATA; + } + + u(8, hash_type, 0, 2); + + for (c = 0; c < (sps->chroma_format_idc == 0 ? 1 : 3); c++) { + if (current->hash_type == 0) { + for (i = 0; i < 16; i++) + us(8, picture_md5[c][i], 0x00, 0xff, 2, c, i); + } else if (current->hash_type == 1) { + us(16, picture_crc[c], 0x0000, 0xffff, 1, c); + } else if (current->hash_type == 2) { + us(32, picture_checksum[c], 0x00000000, 0xffffffff, 1, c); + } + } + + return 0; +} + +static int FUNC(sei_time_code)(CodedBitstreamContext *ctx, RWContext *rw, + H265RawSEITimeCode *current) +{ + int err, i; + + HEADER("Time Code"); + + u(2, num_clock_ts, 1, 3); + + for (i = 0; i < current->num_clock_ts; i++) { + flags(clock_timestamp_flag[i], 1, i); + + if (current->clock_timestamp_flag[i]) { + flags(units_field_based_flag[i], 1, i); + us(5, counting_type[i], 0, 6, 1, i); + flags(full_timestamp_flag[i], 1, i); + flags(discontinuity_flag[i], 1, i); + flags(cnt_dropped_flag[i], 1, i); + + ubs(9, n_frames[i], 1, i); + + if (current->full_timestamp_flag[i]) { + us(6, seconds_value[i], 0, 59, 1, i); + us(6, minutes_value[i], 0, 59, 1, i); + us(5, hours_value[i], 0, 23, 1, i); + } else { + flags(seconds_flag[i], 1, i); + if (current->seconds_flag[i]) { + us(6, seconds_value[i], 0, 59, 1, i); + flags(minutes_flag[i], 1, i); + if (current->minutes_flag[i]) { + us(6, minutes_value[i], 0, 59, 1, i); + flags(hours_flag[i], 1, i); + if (current->hours_flag[i]) + us(5, hours_value[i], 0, 23, 1, i); + } + } + } + + ubs(5, time_offset_length[i], 1, i); + if (current->time_offset_length[i] > 0) + ibs(current->time_offset_length[i], time_offset_value[i], 1, i); + else + infer(time_offset_value[i], 0); + } + } + + return 0; +} + +static int FUNC(sei_mastering_display)(CodedBitstreamContext *ctx, RWContext *rw, + H265RawSEIMasteringDisplayColourVolume *current) +{ + int err, c; + + HEADER("Mastering Display Colour Volume"); + + for (c = 0; c < 3; c++) { + us(16, display_primaries_x[c], 0, 50000, 1, c); + us(16, display_primaries_y[c], 0, 50000, 1, c); + } + + u(16, white_point_x, 0, 50000); + u(16, white_point_y, 0, 50000); + + u(32, max_display_mastering_luminance, + 1, MAX_UINT_BITS(32)); + u(32, min_display_mastering_luminance, + 0, current->max_display_mastering_luminance - 1); + + return 0; +} + +static int FUNC(sei_content_light_level)(CodedBitstreamContext *ctx, RWContext *rw, + H265RawSEIContentLightLevelInfo *current) +{ + int err; + + HEADER("Content Light Level"); + + ub(16, max_content_light_level); + ub(16, max_pic_average_light_level); + + return 0; +} + +static int FUNC(sei_alternative_transfer_characteristics)(CodedBitstreamContext *ctx, + RWContext *rw, + H265RawSEIAlternativeTransferCharacteristics *current) +{ + int err; + + HEADER("Alternative Transfer Characteristics"); + + ub(8, preferred_transfer_characteristics); + + return 0; +} + +static int FUNC(sei_alpha_channel_info)(CodedBitstreamContext *ctx, + RWContext *rw, + H265RawSEIAlphaChannelInfo *current) +{ + int err, length; + + HEADER("Alpha Channel Information"); + + flag(alpha_channel_cancel_flag); + if (!current->alpha_channel_cancel_flag) { + ub(3, alpha_channel_use_idc); + ub(3, alpha_channel_bit_depth_minus8); + length = current->alpha_channel_bit_depth_minus8 + 9; + ub(length, alpha_transparent_value); + ub(length, alpha_opaque_value); + flag(alpha_channel_incr_flag); + flag(alpha_channel_clip_flag); + if (current->alpha_channel_clip_flag) + flag(alpha_channel_clip_type_flag); + } else { + infer(alpha_channel_use_idc, 2); + infer(alpha_channel_incr_flag, 0); + infer(alpha_channel_clip_flag, 0); + } + + return 0; +} + +static int FUNC(sei_payload)(CodedBitstreamContext *ctx, RWContext *rw, + H265RawSEIPayload *current, int prefix) +{ + int err, i; + int start_position, end_position; + +#ifdef READ + start_position = get_bits_count(rw); +#else + start_position = put_bits_count(rw); +#endif + + switch (current->payload_type) { +#define SEI_TYPE_CHECK_VALID(name, prefix_valid, suffix_valid) do { \ + if (prefix && !prefix_valid) { \ + av_log(ctx->log_ctx, AV_LOG_ERROR, "SEI type %s invalid " \ + "as prefix SEI!\n", #name); \ + return AVERROR_INVALIDDATA; \ + } \ + if (!prefix && !suffix_valid) { \ + av_log(ctx->log_ctx, AV_LOG_ERROR, "SEI type %s invalid " \ + "as suffix SEI!\n", #name); \ + return AVERROR_INVALIDDATA; \ + } \ + } while (0) +#define SEI_TYPE_N(type, prefix_valid, suffix_valid, name) \ + case HEVC_SEI_TYPE_ ## type: \ + SEI_TYPE_CHECK_VALID(name, prefix_valid, suffix_valid); \ + CHECK(FUNC(sei_ ## name)(ctx, rw, ¤t->payload.name)); \ + break +#define SEI_TYPE_S(type, prefix_valid, suffix_valid, name) \ + case HEVC_SEI_TYPE_ ## type: \ + SEI_TYPE_CHECK_VALID(name, prefix_valid, suffix_valid); \ + CHECK(FUNC(sei_ ## name)(ctx, rw, ¤t->payload.name, \ + ¤t->payload_size)); \ + break + + SEI_TYPE_S(BUFFERING_PERIOD, 1, 0, buffering_period); + SEI_TYPE_N(PICTURE_TIMING, 1, 0, pic_timing); + SEI_TYPE_N(PAN_SCAN_RECT, 1, 0, pan_scan_rect); + SEI_TYPE_S(USER_DATA_REGISTERED_ITU_T_T35, + 1, 1, user_data_registered); + SEI_TYPE_S(USER_DATA_UNREGISTERED, 1, 1, user_data_unregistered); + SEI_TYPE_N(RECOVERY_POINT, 1, 0, recovery_point); + SEI_TYPE_N(DISPLAY_ORIENTATION, 1, 0, display_orientation); + SEI_TYPE_N(ACTIVE_PARAMETER_SETS, 1, 0, active_parameter_sets); + SEI_TYPE_N(DECODED_PICTURE_HASH, 0, 1, decoded_picture_hash); + SEI_TYPE_N(TIME_CODE, 1, 0, time_code); + SEI_TYPE_N(MASTERING_DISPLAY_INFO, 1, 0, mastering_display); + SEI_TYPE_N(CONTENT_LIGHT_LEVEL_INFO, 1, 0, content_light_level); + SEI_TYPE_N(ALTERNATIVE_TRANSFER_CHARACTERISTICS, + 1, 0, alternative_transfer_characteristics); + SEI_TYPE_N(ALPHA_CHANNEL_INFO, 1, 0, alpha_channel_info); + +#undef SEI_TYPE + default: + { +#ifdef READ + current->payload.other.data_length = current->payload_size; +#endif + allocate(current->payload.other.data, current->payload.other.data_length); + + for (i = 0; i < current->payload_size; i++) + xu(8, payload_byte[i], current->payload.other.data[i], 0, 255, + 1, i); + } + } + + if (byte_alignment(rw)) { + fixed(1, bit_equal_to_one, 1); + while (byte_alignment(rw)) + fixed(1, bit_equal_to_zero, 0); + } + +#ifdef READ + end_position = get_bits_count(rw); + if (end_position < start_position + 8 * current->payload_size) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Incorrect SEI payload length: " + "header %"PRIu32" bits, actually %d bits.\n", + 8 * current->payload_size, + end_position - start_position); + return AVERROR_INVALIDDATA; + } +#else + end_position = put_bits_count(rw); + current->payload_size = (end_position - start_position) >> 3; +#endif + + return 0; +} + +static int FUNC(sei)(CodedBitstreamContext *ctx, RWContext *rw, + H265RawSEI *current, int prefix) +{ + int err, k; + + if (prefix) + HEADER("Prefix Supplemental Enhancement Information"); + else + HEADER("Suffix Supplemental Enhancement Information"); + + CHECK(FUNC(nal_unit_header)(ctx, rw, ¤t->nal_unit_header, + prefix ? HEVC_NAL_SEI_PREFIX + : HEVC_NAL_SEI_SUFFIX)); + +#ifdef READ + for (k = 0; k < H265_MAX_SEI_PAYLOADS; k++) { + uint32_t payload_type = 0; + uint32_t payload_size = 0; + uint32_t tmp; + + while (show_bits(rw, 8) == 0xff) { + fixed(8, ff_byte, 0xff); + payload_type += 255; + } + xu(8, last_payload_type_byte, tmp, 0, 254, 0); + payload_type += tmp; + + while (show_bits(rw, 8) == 0xff) { + fixed(8, ff_byte, 0xff); + payload_size += 255; + } + xu(8, last_payload_size_byte, tmp, 0, 254, 0); + payload_size += tmp; + + current->payload[k].payload_type = payload_type; + current->payload[k].payload_size = payload_size; + + CHECK(FUNC(sei_payload)(ctx, rw, ¤t->payload[k], prefix)); + + if (!cbs_h2645_read_more_rbsp_data(rw)) + break; + } + if (k >= H265_MAX_SEI_PAYLOADS) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Too many payloads in " + "SEI message: found %d.\n", k); + return AVERROR_INVALIDDATA; + } + current->payload_count = k + 1; +#else + for (k = 0; k < current->payload_count; k++) { + PutBitContext start_state; + uint32_t tmp; + int need_size, i; + + // Somewhat clumsy: we write the payload twice when + // we don't know the size in advance. This will mess + // with trace output, but is otherwise harmless. + start_state = *rw; + need_size = !current->payload[k].payload_size; + for (i = 0; i < 1 + need_size; i++) { + *rw = start_state; + + tmp = current->payload[k].payload_type; + while (tmp >= 255) { + fixed(8, ff_byte, 0xff); + tmp -= 255; + } + xu(8, last_payload_type_byte, tmp, 0, 254, 0); + + tmp = current->payload[k].payload_size; + while (tmp >= 255) { + fixed(8, ff_byte, 0xff); + tmp -= 255; + } + xu(8, last_payload_size_byte, tmp, 0, 254, 0); + + CHECK(FUNC(sei_payload)(ctx, rw, ¤t->payload[k], prefix)); + } + } +#endif + + CHECK(FUNC(rbsp_trailing_bits)(ctx, rw)); + + return 0; +} diff --git a/libavcodec/cbs_internal.h b/libavcodec/cbs_internal.h index be540e2a4..dd4babf09 100644 --- a/libavcodec/cbs_internal.h +++ b/libavcodec/cbs_internal.h @@ -63,8 +63,8 @@ typedef struct CodedBitstreamType { void ff_cbs_trace_header(CodedBitstreamContext *ctx, const char *name); -void ff_cbs_trace_syntax_element(CodedBitstreamContext *ctx, - int position, const char *name, +void ff_cbs_trace_syntax_element(CodedBitstreamContext *ctx, int position, + const char *name, const int *subscripts, const char *bitstring, int64_t value); @@ -72,21 +72,44 @@ void ff_cbs_trace_syntax_element(CodedBitstreamContext *ctx, // generation of trace output. int ff_cbs_read_unsigned(CodedBitstreamContext *ctx, GetBitContext *gbc, - int width, const char *name, uint32_t *write_to, + int width, const char *name, + const int *subscripts, uint32_t *write_to, uint32_t range_min, uint32_t range_max); int ff_cbs_write_unsigned(CodedBitstreamContext *ctx, PutBitContext *pbc, - int width, const char *name, uint32_t value, + int width, const char *name, + const int *subscripts, uint32_t value, uint32_t range_min, uint32_t range_max); -// The largest value representable in N bits, suitable for use as +int ff_cbs_read_signed(CodedBitstreamContext *ctx, GetBitContext *gbc, + int width, const char *name, + const int *subscripts, int32_t *write_to, + int32_t range_min, int32_t range_max); + +int ff_cbs_write_signed(CodedBitstreamContext *ctx, PutBitContext *pbc, + int width, const char *name, + const int *subscripts, int32_t value, + int32_t range_min, int32_t range_max); + +// The largest unsigned value representable in N bits, suitable for use as // range_max in the above functions. #define MAX_UINT_BITS(length) ((UINT64_C(1) << (length)) - 1) +// The largest signed value representable in N bits, suitable for use as +// range_max in the above functions. +#define MAX_INT_BITS(length) ((INT64_C(1) << ((length) - 1)) - 1) +// The smallest signed value representable in N bits, suitable for use as +// range_min in the above functions. +#define MIN_INT_BITS(length) (-(INT64_C(1) << ((length) - 1))) + + +extern const CodedBitstreamType ff_cbs_type_av1; extern const CodedBitstreamType ff_cbs_type_h264; extern const CodedBitstreamType ff_cbs_type_h265; +extern const CodedBitstreamType ff_cbs_type_jpeg; extern const CodedBitstreamType ff_cbs_type_mpeg2; +extern const CodedBitstreamType ff_cbs_type_vp9; #endif /* AVCODEC_CBS_INTERNAL_H */ diff --git a/libavcodec/cbs_jpeg.c b/libavcodec/cbs_jpeg.c new file mode 100644 index 000000000..83857bbba --- /dev/null +++ b/libavcodec/cbs_jpeg.c @@ -0,0 +1,520 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "cbs.h" +#include "cbs_internal.h" +#include "cbs_jpeg.h" + + +#define HEADER(name) do { \ + ff_cbs_trace_header(ctx, name); \ + } while (0) + +#define CHECK(call) do { \ + err = (call); \ + if (err < 0) \ + return err; \ + } while (0) + +#define SUBSCRIPTS(subs, ...) (subs > 0 ? ((int[subs + 1]){ subs, __VA_ARGS__ }) : NULL) + +#define u(width, name, range_min, range_max) \ + xu(width, name, range_min, range_max, 0) +#define us(width, name, sub, range_min, range_max) \ + xu(width, name, range_min, range_max, 1, sub) + + +#define READ +#define READWRITE read +#define RWContext GetBitContext +#define FUNC(name) cbs_jpeg_read_ ## name + +#define xu(width, name, range_min, range_max, subs, ...) do { \ + uint32_t value = range_min; \ + CHECK(ff_cbs_read_unsigned(ctx, rw, width, #name, \ + SUBSCRIPTS(subs, __VA_ARGS__), \ + &value, range_min, range_max)); \ + current->name = value; \ + } while (0) + +#include "cbs_jpeg_syntax_template.c" + +#undef READ +#undef READWRITE +#undef RWContext +#undef FUNC +#undef xu + +#define WRITE +#define READWRITE write +#define RWContext PutBitContext +#define FUNC(name) cbs_jpeg_write_ ## name + +#define xu(width, name, range_min, range_max, subs, ...) do { \ + uint32_t value = current->name; \ + CHECK(ff_cbs_write_unsigned(ctx, rw, width, #name, \ + SUBSCRIPTS(subs, __VA_ARGS__), \ + value, range_min, range_max)); \ + } while (0) + + +#include "cbs_jpeg_syntax_template.c" + +#undef WRITE +#undef READWRITE +#undef RWContext +#undef FUNC +#undef xu + + +static void cbs_jpeg_free_application_data(void *unit, uint8_t *content) +{ + JPEGRawApplicationData *ad = (JPEGRawApplicationData*)content; + av_buffer_unref(&ad->Ap_ref); + av_freep(&content); +} + +static void cbs_jpeg_free_comment(void *unit, uint8_t *content) +{ + JPEGRawComment *comment = (JPEGRawComment*)content; + av_buffer_unref(&comment->Cm_ref); + av_freep(&content); +} + +static void cbs_jpeg_free_scan(void *unit, uint8_t *content) +{ + JPEGRawScan *scan = (JPEGRawScan*)content; + av_buffer_unref(&scan->data_ref); + av_freep(&content); +} + +static int cbs_jpeg_split_fragment(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag, + int header) +{ + AVBufferRef *data_ref; + uint8_t *data; + size_t data_size; + int unit, start, end, marker, next_start, next_marker; + int err, i, j, length; + + if (frag->data_size < 4) { + // Definitely too short to be meaningful. + return AVERROR_INVALIDDATA; + } + + for (i = 0; i + 1 < frag->data_size && frag->data[i] != 0xff; i++); + if (i > 0) { + av_log(ctx->log_ctx, AV_LOG_WARNING, "Discarding %d bytes at " + "beginning of image.\n", i); + } + for (++i; i + 1 < frag->data_size && frag->data[i] == 0xff; i++); + if (i + 1 >= frag->data_size && frag->data[i]) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid JPEG image: " + "no SOI marker found.\n"); + return AVERROR_INVALIDDATA; + } + marker = frag->data[i]; + if (marker != JPEG_MARKER_SOI) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid JPEG image: first " + "marker is %02x, should be SOI.\n", marker); + return AVERROR_INVALIDDATA; + } + for (++i; i + 1 < frag->data_size && frag->data[i] == 0xff; i++); + if (i + 1 >= frag->data_size) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid JPEG image: " + "no image content found.\n"); + return AVERROR_INVALIDDATA; + } + marker = frag->data[i]; + start = i + 1; + + for (unit = 0;; unit++) { + if (marker == JPEG_MARKER_EOI) { + break; + } else if (marker == JPEG_MARKER_SOS) { + for (i = start; i + 1 < frag->data_size; i++) { + if (frag->data[i] != 0xff) + continue; + end = i; + for (++i; i + 1 < frag->data_size && + frag->data[i] == 0xff; i++); + if (i + 1 >= frag->data_size) { + next_marker = -1; + } else { + if (frag->data[i] == 0x00) + continue; + next_marker = frag->data[i]; + next_start = i + 1; + } + break; + } + } else { + i = start; + if (i + 2 > frag->data_size) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid JPEG image: " + "truncated at %02x marker.\n", marker); + return AVERROR_INVALIDDATA; + } + length = AV_RB16(frag->data + i); + if (i + length > frag->data_size) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid JPEG image: " + "truncated at %02x marker segment.\n", marker); + return AVERROR_INVALIDDATA; + } + end = start + length; + + i = end; + if (frag->data[i] != 0xff) { + next_marker = -1; + } else { + for (++i; i + 1 < frag->data_size && + frag->data[i] == 0xff; i++); + if (i + 1 >= frag->data_size) { + next_marker = -1; + } else { + next_marker = frag->data[i]; + next_start = i + 1; + } + } + } + + if (marker == JPEG_MARKER_SOS) { + length = AV_RB16(frag->data + start); + + data_ref = NULL; + data = av_malloc(end - start + + AV_INPUT_BUFFER_PADDING_SIZE); + if (!data) + return AVERROR(ENOMEM); + + memcpy(data, frag->data + start, length); + for (i = start + length, j = length; i < end; i++, j++) { + if (frag->data[i] == 0xff) { + while (frag->data[i] == 0xff) + ++i; + data[j] = 0xff; + } else { + data[j] = frag->data[i]; + } + } + data_size = j; + + memset(data + data_size, 0, AV_INPUT_BUFFER_PADDING_SIZE); + + } else { + data = frag->data + start; + data_size = end - start; + data_ref = frag->data_ref; + } + + err = ff_cbs_insert_unit_data(ctx, frag, unit, marker, + data, data_size, data_ref); + if (err < 0) { + if (!data_ref) + av_freep(&data); + return err; + } + + if (next_marker == -1) + break; + marker = next_marker; + start = next_start; + } + + return 0; +} + +static int cbs_jpeg_read_unit(CodedBitstreamContext *ctx, + CodedBitstreamUnit *unit) +{ + GetBitContext gbc; + int err; + + err = init_get_bits(&gbc, unit->data, 8 * unit->data_size); + if (err < 0) + return err; + + if (unit->type >= JPEG_MARKER_SOF0 && + unit->type <= JPEG_MARKER_SOF3) { + err = ff_cbs_alloc_unit_content(ctx, unit, + sizeof(JPEGRawFrameHeader), + NULL); + if (err < 0) + return err; + + err = cbs_jpeg_read_frame_header(ctx, &gbc, unit->content); + if (err < 0) + return err; + + } else if (unit->type >= JPEG_MARKER_APPN && + unit->type <= JPEG_MARKER_APPN + 15) { + err = ff_cbs_alloc_unit_content(ctx, unit, + sizeof(JPEGRawApplicationData), + &cbs_jpeg_free_application_data); + if (err < 0) + return err; + + err = cbs_jpeg_read_application_data(ctx, &gbc, unit->content); + if (err < 0) + return err; + + } else if (unit->type == JPEG_MARKER_SOS) { + JPEGRawScan *scan; + int pos; + + err = ff_cbs_alloc_unit_content(ctx, unit, + sizeof(JPEGRawScan), + &cbs_jpeg_free_scan); + if (err < 0) + return err; + scan = unit->content; + + err = cbs_jpeg_read_scan_header(ctx, &gbc, &scan->header); + if (err < 0) + return err; + + pos = get_bits_count(&gbc); + av_assert0(pos % 8 == 0); + if (pos > 0) { + scan->data_size = unit->data_size - pos / 8; + scan->data_ref = av_buffer_ref(unit->data_ref); + if (!scan->data_ref) + return AVERROR(ENOMEM); + scan->data = unit->data + pos / 8; + } + + } else { + switch (unit->type) { +#define SEGMENT(marker, type, func, free) \ + case JPEG_MARKER_ ## marker: \ + { \ + err = ff_cbs_alloc_unit_content(ctx, unit, \ + sizeof(type), free); \ + if (err < 0) \ + return err; \ + err = cbs_jpeg_read_ ## func(ctx, &gbc, unit->content); \ + if (err < 0) \ + return err; \ + } \ + break + SEGMENT(DQT, JPEGRawQuantisationTableSpecification, dqt, NULL); + SEGMENT(DHT, JPEGRawHuffmanTableSpecification, dht, NULL); + SEGMENT(COM, JPEGRawComment, comment, &cbs_jpeg_free_comment); +#undef SEGMENT + default: + return AVERROR(ENOSYS); + } + } + + return 0; +} + +static int cbs_jpeg_write_scan(CodedBitstreamContext *ctx, + CodedBitstreamUnit *unit, + PutBitContext *pbc) +{ + JPEGRawScan *scan = unit->content; + int i, err; + + err = cbs_jpeg_write_scan_header(ctx, pbc, &scan->header); + if (err < 0) + return err; + + if (scan->data) { + if (scan->data_size * 8 > put_bits_left(pbc)) + return AVERROR(ENOSPC); + + for (i = 0; i < scan->data_size; i++) + put_bits(pbc, 8, scan->data[i]); + } + + return 0; +} + +static int cbs_jpeg_write_segment(CodedBitstreamContext *ctx, + CodedBitstreamUnit *unit, + PutBitContext *pbc) +{ + int err; + + if (unit->type >= JPEG_MARKER_SOF0 && + unit->type <= JPEG_MARKER_SOF3) { + err = cbs_jpeg_write_frame_header(ctx, pbc, unit->content); + } else if (unit->type >= JPEG_MARKER_APPN && + unit->type <= JPEG_MARKER_APPN + 15) { + err = cbs_jpeg_write_application_data(ctx, pbc, unit->content); + } else { + switch (unit->type) { +#define SEGMENT(marker, func) \ + case JPEG_MARKER_ ## marker: \ + err = cbs_jpeg_write_ ## func(ctx, pbc, unit->content); \ + break; + SEGMENT(DQT, dqt); + SEGMENT(DHT, dht); + SEGMENT(COM, comment); + default: + return AVERROR_PATCHWELCOME; + } + } + + return err; +} + +static int cbs_jpeg_write_unit(CodedBitstreamContext *ctx, + CodedBitstreamUnit *unit) +{ + CodedBitstreamJPEGContext *priv = ctx->priv_data; + PutBitContext pbc; + int err; + + if (!priv->write_buffer) { + // Initial write buffer size is 1MB. + priv->write_buffer_size = 1024 * 1024; + + reallocate_and_try_again: + err = av_reallocp(&priv->write_buffer, priv->write_buffer_size); + if (err < 0) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Unable to allocate a " + "sufficiently large write buffer (last attempt " + "%"SIZE_SPECIFIER" bytes).\n", priv->write_buffer_size); + return err; + } + } + + init_put_bits(&pbc, priv->write_buffer, priv->write_buffer_size); + + if (unit->type == JPEG_MARKER_SOS) + err = cbs_jpeg_write_scan(ctx, unit, &pbc); + else + err = cbs_jpeg_write_segment(ctx, unit, &pbc); + + if (err == AVERROR(ENOSPC)) { + // Overflow. + priv->write_buffer_size *= 2; + goto reallocate_and_try_again; + } + if (err < 0) { + // Write failed for some other reason. + return err; + } + + if (put_bits_count(&pbc) % 8) + unit->data_bit_padding = 8 - put_bits_count(&pbc) % 8; + else + unit->data_bit_padding = 0; + + unit->data_size = (put_bits_count(&pbc) + 7) / 8; + flush_put_bits(&pbc); + + err = ff_cbs_alloc_unit_data(ctx, unit, unit->data_size); + if (err < 0) + return err; + + memcpy(unit->data, priv->write_buffer, unit->data_size); + + return 0; +} + +static int cbs_jpeg_assemble_fragment(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag) +{ + const CodedBitstreamUnit *unit; + uint8_t *data; + size_t size, dp, sp; + int i; + + size = 4; // SOI + EOI. + for (i = 0; i < frag->nb_units; i++) { + unit = &frag->units[i]; + size += 2 + unit->data_size; + if (unit->type == JPEG_MARKER_SOS) { + for (sp = 0; sp < unit->data_size; sp++) { + if (unit->data[sp] == 0xff) + ++size; + } + } + } + + frag->data_ref = av_buffer_alloc(size + AV_INPUT_BUFFER_PADDING_SIZE); + if (!frag->data_ref) + return AVERROR(ENOMEM); + data = frag->data_ref->data; + + dp = 0; + + data[dp++] = 0xff; + data[dp++] = JPEG_MARKER_SOI; + + for (i = 0; i < frag->nb_units; i++) { + unit = &frag->units[i]; + + data[dp++] = 0xff; + data[dp++] = unit->type; + + if (unit->type != JPEG_MARKER_SOS) { + memcpy(data + dp, unit->data, unit->data_size); + dp += unit->data_size; + } else { + sp = AV_RB16(unit->data); + av_assert0(sp <= unit->data_size); + memcpy(data + dp, unit->data, sp); + dp += sp; + + for (; sp < unit->data_size; sp++) { + if (unit->data[sp] == 0xff) { + data[dp++] = 0xff; + data[dp++] = 0x00; + } else { + data[dp++] = unit->data[sp]; + } + } + } + } + + data[dp++] = 0xff; + data[dp++] = JPEG_MARKER_EOI; + + av_assert0(dp == size); + + memset(data + size, 0, AV_INPUT_BUFFER_PADDING_SIZE); + frag->data = data; + frag->data_size = size; + + return 0; +} + +static void cbs_jpeg_close(CodedBitstreamContext *ctx) +{ + CodedBitstreamJPEGContext *priv = ctx->priv_data; + + av_freep(&priv->write_buffer); +} + +const CodedBitstreamType ff_cbs_type_jpeg = { + .codec_id = AV_CODEC_ID_MJPEG, + + .priv_data_size = sizeof(CodedBitstreamJPEGContext), + + .split_fragment = &cbs_jpeg_split_fragment, + .read_unit = &cbs_jpeg_read_unit, + .write_unit = &cbs_jpeg_write_unit, + .assemble_fragment = &cbs_jpeg_assemble_fragment, + + .close = &cbs_jpeg_close, +}; diff --git a/libavcodec/cbs_jpeg.h b/libavcodec/cbs_jpeg.h new file mode 100644 index 000000000..913d3f90f --- /dev/null +++ b/libavcodec/cbs_jpeg.h @@ -0,0 +1,130 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_CBS_JPEG_H +#define AVCODEC_CBS_JPEG_H + +#include +#include + +#include "libavutil/buffer.h" + + +enum { + JPEG_MARKER_SOF0 = 0xc0, + JPEG_MARKER_SOF1 = 0xc1, + JPEG_MARKER_SOF2 = 0xc2, + JPEG_MARKER_SOF3 = 0xc3, + + JPEG_MARKER_DHT = 0xc4, + JPEG_MARKER_SOI = 0xd8, + JPEG_MARKER_EOI = 0xd9, + JPEG_MARKER_SOS = 0xda, + JPEG_MARKER_DQT = 0xdb, + + JPEG_MARKER_APPN = 0xe0, + JPEG_MARKER_JPGN = 0xf0, + JPEG_MARKER_COM = 0xfe, +}; + +enum { + JPEG_MAX_COMPONENTS = 255, + + JPEG_MAX_HEIGHT = 65535, + JPEG_MAX_WIDTH = 65535, +}; + + +typedef struct JPEGRawFrameHeader { + uint16_t Lf; + uint8_t P; + uint16_t Y; + uint16_t X; + uint16_t Nf; + + uint8_t C [JPEG_MAX_COMPONENTS]; + uint8_t H [JPEG_MAX_COMPONENTS]; + uint8_t V [JPEG_MAX_COMPONENTS]; + uint8_t Tq[JPEG_MAX_COMPONENTS]; +} JPEGRawFrameHeader; + +typedef struct JPEGRawScanHeader { + uint16_t Ls; + uint8_t Ns; + + uint8_t Cs[JPEG_MAX_COMPONENTS]; + uint8_t Td[JPEG_MAX_COMPONENTS]; + uint8_t Ta[JPEG_MAX_COMPONENTS]; + + uint8_t Ss; + uint8_t Se; + uint8_t Ah; + uint8_t Al; +} JPEGRawScanHeader; + +typedef struct JPEGRawScan { + JPEGRawScanHeader header; + uint8_t *data; + size_t data_size; + AVBufferRef *data_ref; +} JPEGRawScan; + +typedef struct JPEGRawQuantisationTable { + uint8_t Pq; + uint8_t Tq; + uint16_t Q[64]; +} JPEGRawQuantisationTable; + +typedef struct JPEGRawQuantisationTableSpecification { + uint16_t Lq; + JPEGRawQuantisationTable table[4]; +} JPEGRawQuantisationTableSpecification; + +typedef struct JPEGRawHuffmanTable { + uint8_t Tc; + uint8_t Th; + uint8_t L[16]; + uint8_t V[224]; +} JPEGRawHuffmanTable; + +typedef struct JPEGRawHuffmanTableSpecification { + uint16_t Lh; + JPEGRawHuffmanTable table[8]; +} JPEGRawHuffmanTableSpecification; + +typedef struct JPEGRawApplicationData { + uint16_t Lp; + uint8_t *Ap; + AVBufferRef *Ap_ref; +} JPEGRawApplicationData; + +typedef struct JPEGRawComment { + uint16_t Lc; + uint8_t *Cm; + AVBufferRef *Cm_ref; +} JPEGRawComment; + + +typedef struct CodedBitstreamJPEGContext { + // Write buffer. + uint8_t *write_buffer; + size_t write_buffer_size; +} CodedBitstreamJPEGContext; + + +#endif /* AVCODEC_CBS_JPEG_H */ diff --git a/libavcodec/cbs_jpeg_syntax_template.c b/libavcodec/cbs_jpeg_syntax_template.c new file mode 100644 index 000000000..d3cd9ff62 --- /dev/null +++ b/libavcodec/cbs_jpeg_syntax_template.c @@ -0,0 +1,191 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +static int FUNC(frame_header)(CodedBitstreamContext *ctx, RWContext *rw, + JPEGRawFrameHeader *current) +{ + int err, i; + + HEADER("Frame Header"); + + u(16, Lf, 8, 8 + 3 * JPEG_MAX_COMPONENTS); + + u(8, P, 2, 16); + u(16, Y, 0, JPEG_MAX_HEIGHT); + u(16, X, 1, JPEG_MAX_WIDTH); + u(8, Nf, 1, JPEG_MAX_COMPONENTS); + + for (i = 0; i < current->Nf; i++) { + us(8, C[i], i, 0, JPEG_MAX_COMPONENTS); + us(4, H[i], i, 1, 4); + us(4, V[i], i, 1, 4); + us(8, Tq[i], i, 0, 3); + } + + return 0; +} + +static int FUNC(quantisation_table)(CodedBitstreamContext *ctx, RWContext *rw, + JPEGRawQuantisationTable *current) +{ + int err, i; + + u(4, Pq, 0, 1); + u(4, Tq, 0, 3); + + if (current->Pq) { + for (i = 0; i < 64; i++) + us(16, Q[i], i, 1, 255); + } else { + for (i = 0; i < 64; i++) + us(8, Q[i], i, 1, 255); + } + + return 0; +} + +static int FUNC(dqt)(CodedBitstreamContext *ctx, RWContext *rw, + JPEGRawQuantisationTableSpecification *current) +{ + int err, i, n; + + HEADER("Quantisation Tables"); + + u(16, Lq, 2, 2 + 4 * 65); + n = current->Lq / 65; + + for (i = 0; i < n; i++) + CHECK(FUNC(quantisation_table)(ctx, rw, ¤t->table[i])); + + return 0; +} + +static int FUNC(huffman_table)(CodedBitstreamContext *ctx, RWContext *rw, + JPEGRawHuffmanTable *current) +{ + int err, i, j, ij; + + u(4, Tc, 0, 1); + u(4, Th, 0, 3); + + for (i = 0; i < 16; i++) + us(8, L[i], i, 0, 224); + + ij = 0; + for (i = 0; i < 16; i++) { + for (j = 0; j < current->L[i]; j++) { + us(8, V[ij], ij, 0, 255); + ++ij; + } + } + + return 0; +} + +static int FUNC(dht)(CodedBitstreamContext *ctx, RWContext *rw, + JPEGRawHuffmanTableSpecification *current) +{ + int err, i, j, n; + + HEADER("Huffman Tables"); + + u(16, Lh, 2, 2 + 8 * (1 + 16 + 256)); + + n = 2; + for (i = 0; n < current->Lh; i++) { + CHECK(FUNC(huffman_table)(ctx, rw, ¤t->table[i])); + + ++n; + for (j = 0; j < 16; j++) + n += 1 + current->table[i].L[j]; + } + + return 0; +} + +static int FUNC(scan_header)(CodedBitstreamContext *ctx, RWContext *rw, + JPEGRawScanHeader *current) +{ + int err, j; + + HEADER("Scan"); + + u(16, Ls, 6, 6 + 2 * JPEG_MAX_COMPONENTS); + + u(8, Ns, 1, 4); + for (j = 0; j < current->Ns; j++) { + us(8, Cs[j], j, 0, JPEG_MAX_COMPONENTS); + us(4, Td[j], j, 0, 3); + us(4, Ta[j], j, 0, 3); + } + + u(8, Ss, 0, 63); + u(8, Se, 0, 63); + u(4, Ah, 0, 13); + u(4, Al, 0, 15); + + return 0; +} + +static int FUNC(application_data)(CodedBitstreamContext *ctx, RWContext *rw, + JPEGRawApplicationData *current) +{ + int err, i; + + HEADER("Application Data"); + + u(16, Lp, 2, 65535); + + if (current->Lp > 2) { +#ifdef READ + current->Ap_ref = av_buffer_alloc(current->Lp - 2); + if (!current->Ap_ref) + return AVERROR(ENOMEM); + current->Ap = current->Ap_ref->data; +#endif + + for (i = 0; i < current->Lp - 2; i++) + us(8, Ap[i], i, 0, 255); + } + + return 0; +} + +static int FUNC(comment)(CodedBitstreamContext *ctx, RWContext *rw, + JPEGRawComment *current) +{ + int err, i; + + HEADER("Comment"); + + u(16, Lc, 2, 65535); + + if (current->Lc > 2) { +#ifdef READ + current->Cm_ref = av_buffer_alloc(current->Lc - 2); + if (!current->Cm_ref) + return AVERROR(ENOMEM); + current->Cm = current->Cm_ref->data; +#endif + + for (i = 0; i < current->Lc - 2; i++) + us(8, Cm[i], i, 0, 255); + } + + return 0; +} diff --git a/libavcodec/cbs_mpeg2.c b/libavcodec/cbs_mpeg2.c index bfb64a085..cb202f835 100644 --- a/libavcodec/cbs_mpeg2.c +++ b/libavcodec/cbs_mpeg2.c @@ -38,24 +38,44 @@ #define FUNC_MPEG2(rw, name) FUNC_NAME(rw, mpeg2, name) #define FUNC(name) FUNC_MPEG2(READWRITE, name) +#define SUBSCRIPTS(subs, ...) (subs > 0 ? ((int[subs + 1]){ subs, __VA_ARGS__ }) : NULL) + +#define ui(width, name) \ + xui(width, name, current->name, 0, MAX_UINT_BITS(width), 0) +#define uir(width, name) \ + xui(width, name, current->name, 1, MAX_UINT_BITS(width), 0) +#define uis(width, name, subs, ...) \ + xui(width, name, current->name, 0, MAX_UINT_BITS(width), subs, __VA_ARGS__) +#define uirs(width, name, subs, ...) \ + xui(width, name, current->name, 1, MAX_UINT_BITS(width), subs, __VA_ARGS__) +#define sis(width, name, subs, ...) \ + xsi(width, name, current->name, subs, __VA_ARGS__) + #define READ #define READWRITE read #define RWContext GetBitContext -#define xui(width, name, var) do { \ +#define xui(width, name, var, range_min, range_max, subs, ...) do { \ uint32_t value = 0; \ CHECK(ff_cbs_read_unsigned(ctx, rw, width, #name, \ - &value, 0, (1 << width) - 1)); \ + SUBSCRIPTS(subs, __VA_ARGS__), \ + &value, range_min, range_max)); \ var = value; \ } while (0) -#define ui(width, name) \ - xui(width, name, current->name) +#define xsi(width, name, var, subs, ...) do { \ + int32_t value; \ + CHECK(ff_cbs_read_signed(ctx, rw, width, #name, \ + SUBSCRIPTS(subs, __VA_ARGS__), &value, \ + MIN_INT_BITS(width), \ + MAX_INT_BITS(width))); \ + var = value; \ + } while (0) #define marker_bit() do { \ av_unused uint32_t one; \ - CHECK(ff_cbs_read_unsigned(ctx, rw, 1, "marker_bit", &one, 1, 1)); \ + CHECK(ff_cbs_read_unsigned(ctx, rw, 1, "marker_bit", NULL, &one, 1, 1)); \ } while (0) #define nextbits(width, compare, var) \ @@ -68,7 +88,7 @@ #undef READWRITE #undef RWContext #undef xui -#undef ui +#undef xsi #undef marker_bit #undef nextbits @@ -77,27 +97,32 @@ #define READWRITE write #define RWContext PutBitContext -#define xui(width, name, var) do { \ +#define xui(width, name, var, range_min, range_max, subs, ...) do { \ CHECK(ff_cbs_write_unsigned(ctx, rw, width, #name, \ - var, 0, (1 << width) - 1)); \ + SUBSCRIPTS(subs, __VA_ARGS__), \ + var, range_min, range_max)); \ } while (0) -#define ui(width, name) \ - xui(width, name, current->name) +#define xsi(width, name, var, subs, ...) do { \ + CHECK(ff_cbs_write_signed(ctx, rw, width, #name, \ + SUBSCRIPTS(subs, __VA_ARGS__), var, \ + MIN_INT_BITS(width), \ + MAX_INT_BITS(width))); \ + } while (0) #define marker_bit() do { \ - CHECK(ff_cbs_write_unsigned(ctx, rw, 1, "marker_bit", 1, 1, 1)); \ + CHECK(ff_cbs_write_unsigned(ctx, rw, 1, "marker_bit", NULL, 1, 1, 1)); \ } while (0) #define nextbits(width, compare, var) (var) #include "cbs_mpeg2_syntax_template.c" -#undef READ +#undef WRITE #undef READWRITE #undef RWContext #undef xui -#undef ui +#undef xsi #undef marker_bit #undef nextbits @@ -146,18 +171,12 @@ static int cbs_mpeg2_split_fragment(CodedBitstreamContext *ctx, unit_size = (end - 4) - (start - 1); } - unit_data = av_malloc(unit_size + AV_INPUT_BUFFER_PADDING_SIZE); - if (!unit_data) - return AVERROR(ENOMEM); - memcpy(unit_data, start - 1, unit_size); - memset(unit_data + unit_size, 0, AV_INPUT_BUFFER_PADDING_SIZE); + unit_data = (uint8_t *)start - 1; err = ff_cbs_insert_unit_data(ctx, frag, i, unit_type, - unit_data, unit_size, NULL); - if (err < 0) { - av_freep(&unit_data); + unit_data, unit_size, frag->data_ref); + if (err < 0) return err; - } if (end == frag->data + frag->data_size) break; @@ -197,16 +216,11 @@ static int cbs_mpeg2_read_unit(CodedBitstreamContext *ctx, len = unit->data_size; slice->data_size = len - pos / 8; - slice->data_ref = av_buffer_alloc(slice->data_size + - AV_INPUT_BUFFER_PADDING_SIZE); + slice->data_ref = av_buffer_ref(unit->data_ref); if (!slice->data_ref) return AVERROR(ENOMEM); - slice->data = slice->data_ref->data; + slice->data = unit->data + pos / 8; - memcpy(slice->data, - unit->data + pos / 8, slice->data_size); - memset(slice->data + slice->data_size, 0, - AV_INPUT_BUFFER_PADDING_SIZE); slice->data_bit_start = pos % 8; } else { @@ -225,18 +239,19 @@ static int cbs_mpeg2_read_unit(CodedBitstreamContext *ctx, return err; \ } \ break; - START(0x00, MPEG2RawPictureHeader, picture_header, NULL); - START(0xb2, MPEG2RawUserData, user_data, - &cbs_mpeg2_free_user_data); - START(0xb3, MPEG2RawSequenceHeader, sequence_header, NULL); - START(0xb5, MPEG2RawExtensionData, extension_data, NULL); - START(0xb8, MPEG2RawGroupOfPicturesHeader, - group_of_pictures_header, NULL); + START(MPEG2_START_PICTURE, MPEG2RawPictureHeader, + picture_header, NULL); + START(MPEG2_START_USER_DATA, MPEG2RawUserData, + user_data, &cbs_mpeg2_free_user_data); + START(MPEG2_START_SEQUENCE_HEADER, MPEG2RawSequenceHeader, + sequence_header, NULL); + START(MPEG2_START_EXTENSION, MPEG2RawExtensionData, + extension_data, NULL); + START(MPEG2_START_GROUP, MPEG2RawGroupOfPicturesHeader, + group_of_pictures_header, NULL); #undef START default: - av_log(ctx->log_ctx, AV_LOG_ERROR, "Unknown start code %02"PRIx32".\n", - unit->type); - return AVERROR_INVALIDDATA; + return AVERROR(ENOSYS); } } @@ -254,11 +269,12 @@ static int cbs_mpeg2_write_header(CodedBitstreamContext *ctx, case start_code: \ err = cbs_mpeg2_write_ ## func(ctx, pbc, unit->content); \ break; - START(0x00, MPEG2RawPictureHeader, picture_header); - START(0xb2, MPEG2RawUserData, user_data); - START(0xb3, MPEG2RawSequenceHeader, sequence_header); - START(0xb5, MPEG2RawExtensionData, extension_data); - START(0xb8, MPEG2RawGroupOfPicturesHeader, group_of_pictures_header); + START(MPEG2_START_PICTURE, MPEG2RawPictureHeader, picture_header); + START(MPEG2_START_USER_DATA, MPEG2RawUserData, user_data); + START(MPEG2_START_SEQUENCE_HEADER, MPEG2RawSequenceHeader, sequence_header); + START(MPEG2_START_EXTENSION, MPEG2RawExtensionData, extension_data); + START(MPEG2_START_GROUP, MPEG2RawGroupOfPicturesHeader, + group_of_pictures_header); #undef START default: av_log(ctx->log_ctx, AV_LOG_ERROR, "Write unimplemented for start " @@ -274,8 +290,6 @@ static int cbs_mpeg2_write_slice(CodedBitstreamContext *ctx, PutBitContext *pbc) { MPEG2RawSlice *slice = unit->content; - GetBitContext gbc; - size_t bits_left; int err; err = cbs_mpeg2_write_slice_header(ctx, pbc, &slice->header); @@ -283,21 +297,38 @@ static int cbs_mpeg2_write_slice(CodedBitstreamContext *ctx, return err; if (slice->data) { + size_t rest = slice->data_size - (slice->data_bit_start + 7) / 8; + uint8_t *pos = slice->data + slice->data_bit_start / 8; + + av_assert0(slice->data_bit_start >= 0 && + 8 * slice->data_size > slice->data_bit_start); + if (slice->data_size * 8 + 8 > put_bits_left(pbc)) return AVERROR(ENOSPC); - init_get_bits(&gbc, slice->data, slice->data_size * 8); - skip_bits_long(&gbc, slice->data_bit_start); + // First copy the remaining bits of the first byte + if (slice->data_bit_start % 8) + put_bits(pbc, 8 - slice->data_bit_start % 8, + *pos++ & MAX_UINT_BITS(8 - slice->data_bit_start % 8)); - while (get_bits_left(&gbc) > 15) - put_bits(pbc, 16, get_bits(&gbc, 16)); + if (put_bits_count(pbc) % 8 == 0) { + // If the writer is aligned at this point, + // memcpy can be used to improve performance. + // This is the normal case. + flush_put_bits(pbc); + memcpy(put_bits_ptr(pbc), pos, rest); + skip_put_bytes(pbc, rest); + } else { + // If not, we have to copy manually: + for (; rest > 3; rest -= 4, pos += 4) + put_bits32(pbc, AV_RB32(pos)); - bits_left = get_bits_left(&gbc); - put_bits(pbc, bits_left, get_bits(&gbc, bits_left)); + for (; rest; rest--, pos++) + put_bits(pbc, 8, *pos); - // Align with zeroes. - while (put_bits_count(pbc) % 8 != 0) - put_bits(pbc, 1, 0); + // Align with zeros + put_bits(pbc, 8 - put_bits_count(pbc) % 8, 0); + } } return 0; @@ -326,7 +357,7 @@ static int cbs_mpeg2_write_unit(CodedBitstreamContext *ctx, init_put_bits(&pbc, priv->write_buffer, priv->write_buffer_size); - if (unit->type >= 0x01 && unit->type <= 0xaf) + if (MPEG2_START_IS_SLICE(unit->type)) err = cbs_mpeg2_write_slice(ctx, unit, &pbc); else err = cbs_mpeg2_write_header(ctx, unit, &pbc); @@ -362,7 +393,7 @@ static int cbs_mpeg2_assemble_fragment(CodedBitstreamContext *ctx, CodedBitstreamFragment *frag) { uint8_t *data; - size_t size, dp, sp; + size_t size, dp; int i; size = 0; @@ -382,8 +413,8 @@ static int cbs_mpeg2_assemble_fragment(CodedBitstreamContext *ctx, data[dp++] = 0; data[dp++] = 1; - for (sp = 0; sp < unit->data_size; sp++) - data[dp++] = unit->data[sp]; + memcpy(data + dp, unit->data, unit->data_size); + dp += unit->data_size; } av_assert0(dp == size); diff --git a/libavcodec/cbs_mpeg2.h b/libavcodec/cbs_mpeg2.h index 92caa99dc..11f93b9df 100644 --- a/libavcodec/cbs_mpeg2.h +++ b/libavcodec/cbs_mpeg2.h @@ -51,7 +51,7 @@ enum { MPEG2_EXTENSION_PICTURE_CODING = 0x8, MPEG2_EXTENSION_PICTURE_SPATIAL_SCALABLE = 0x9, MPEG2_EXTENSION_PICTURE_TEMPORAL_SCALABLE = 0xa, - MPEG2_EXTENSION_CAMAERA_PARAMETERS = 0xb, + MPEG2_EXTENSION_CAMERA_PARAMETERS = 0xb, MPEG2_EXTENSION_ITU_T = 0xc, }; @@ -164,8 +164,8 @@ typedef struct MPEG2RawQuantMatrixExtension { } MPEG2RawQuantMatrixExtension; typedef struct MPEG2RawPictureDisplayExtension { - uint16_t frame_centre_horizontal_offset[3]; - uint16_t frame_centre_vertical_offset[3]; + int16_t frame_centre_horizontal_offset[3]; + int16_t frame_centre_vertical_offset[3]; } MPEG2RawPictureDisplayExtension; typedef struct MPEG2RawExtensionData { diff --git a/libavcodec/cbs_mpeg2_syntax_template.c b/libavcodec/cbs_mpeg2_syntax_template.c index 235f199e5..e0cf71687 100644 --- a/libavcodec/cbs_mpeg2_syntax_template.c +++ b/libavcodec/cbs_mpeg2_syntax_template.c @@ -26,14 +26,14 @@ static int FUNC(sequence_header)(CodedBitstreamContext *ctx, RWContext *rw, ui(8, sequence_header_code); - ui(12, horizontal_size_value); - ui(12, vertical_size_value); + uir(12, horizontal_size_value); + uir(12, vertical_size_value); mpeg2->horizontal_size = current->horizontal_size_value; mpeg2->vertical_size = current->vertical_size_value; - ui(4, aspect_ratio_information); - ui(4, frame_rate_code); + uir(4, aspect_ratio_information); + uir(4, frame_rate_code); ui(18, bit_rate_value); marker_bit(); @@ -44,13 +44,13 @@ static int FUNC(sequence_header)(CodedBitstreamContext *ctx, RWContext *rw, ui(1, load_intra_quantiser_matrix); if (current->load_intra_quantiser_matrix) { for (i = 0; i < 64; i++) - ui(8, intra_quantiser_matrix[i]); + uirs(8, intra_quantiser_matrix[i], 1, i); } ui(1, load_non_intra_quantiser_matrix); if (current->load_non_intra_quantiser_matrix) { for (i = 0; i < 64; i++) - ui(8, non_intra_quantiser_matrix[i]); + uirs(8, non_intra_quantiser_matrix[i], 1, i); } return 0; @@ -79,7 +79,7 @@ static int FUNC(user_data)(CodedBitstreamContext *ctx, RWContext *rw, #endif for (k = 0; k < current->user_data_length; k++) - xui(8, user_data, current->user_data[k]); + uis(8, user_data[k], 1, k); return 0; } @@ -125,9 +125,25 @@ static int FUNC(sequence_display_extension)(CodedBitstreamContext *ctx, RWContex ui(1, colour_description); if (current->colour_description) { - ui(8, colour_primaries); - ui(8, transfer_characteristics); - ui(8, matrix_coefficients); +#ifdef READ +#define READ_AND_PATCH(name) do { \ + ui(8, name); \ + if (current->name == 0) { \ + current->name = 2; \ + av_log(ctx->log_ctx, AV_LOG_WARNING, "%s in a sequence display " \ + "extension had the invalid value 0. Setting it to 2 " \ + "(meaning unknown) instead.\n", #name); \ + } \ + } while (0) + READ_AND_PATCH(colour_primaries); + READ_AND_PATCH(transfer_characteristics); + READ_AND_PATCH(matrix_coefficients); +#undef READ_AND_PATCH +#else + uir(8, colour_primaries); + uir(8, transfer_characteristics); + uir(8, matrix_coefficients); +#endif } ui(14, display_horizontal_size); @@ -163,7 +179,7 @@ static int FUNC(picture_header)(CodedBitstreamContext *ctx, RWContext *rw, ui(8, picture_start_code); ui(10, temporal_reference); - ui(3, picture_coding_type); + uir(3, picture_coding_type); ui(16, vbv_delay); if (current->picture_coding_type == 2 || @@ -190,10 +206,10 @@ static int FUNC(picture_coding_extension)(CodedBitstreamContext *ctx, RWContext HEADER("Picture Coding Extension"); - ui(4, f_code[0][0]); - ui(4, f_code[0][1]); - ui(4, f_code[1][0]); - ui(4, f_code[1][1]); + uir(4, f_code[0][0]); + uir(4, f_code[0][1]); + uir(4, f_code[1][0]); + uir(4, f_code[1][1]); ui(2, intra_dc_precision); ui(2, picture_structure); @@ -250,25 +266,25 @@ static int FUNC(quant_matrix_extension)(CodedBitstreamContext *ctx, RWContext *r ui(1, load_intra_quantiser_matrix); if (current->load_intra_quantiser_matrix) { for (i = 0; i < 64; i++) - ui(8, intra_quantiser_matrix[i]); + uirs(8, intra_quantiser_matrix[i], 1, i); } ui(1, load_non_intra_quantiser_matrix); if (current->load_non_intra_quantiser_matrix) { for (i = 0; i < 64; i++) - ui(8, non_intra_quantiser_matrix[i]); + uirs(8, non_intra_quantiser_matrix[i], 1, i); } ui(1, load_chroma_intra_quantiser_matrix); if (current->load_chroma_intra_quantiser_matrix) { for (i = 0; i < 64; i++) - ui(8, intra_quantiser_matrix[i]); + uirs(8, intra_quantiser_matrix[i], 1, i); } ui(1, load_chroma_non_intra_quantiser_matrix); if (current->load_chroma_non_intra_quantiser_matrix) { for (i = 0; i < 64; i++) - ui(8, chroma_non_intra_quantiser_matrix[i]); + uirs(8, chroma_non_intra_quantiser_matrix[i], 1, i); } return 0; @@ -283,9 +299,9 @@ static int FUNC(picture_display_extension)(CodedBitstreamContext *ctx, RWContext HEADER("Picture Display Extension"); for (i = 0; i < mpeg2->number_of_frame_centre_offsets; i++) { - ui(16, frame_centre_horizontal_offset[i]); + sis(16, frame_centre_horizontal_offset[i], 1, i); marker_bit(); - ui(16, frame_centre_vertical_offset[i]); + sis(16, frame_centre_vertical_offset[i], 1, i); marker_bit(); } @@ -303,25 +319,25 @@ static int FUNC(extension_data)(CodedBitstreamContext *ctx, RWContext *rw, ui(4, extension_start_code_identifier); switch (current->extension_start_code_identifier) { - case 1: + case MPEG2_EXTENSION_SEQUENCE: return FUNC(sequence_extension) (ctx, rw, ¤t->data.sequence); - case 2: + case MPEG2_EXTENSION_SEQUENCE_DISPLAY: return FUNC(sequence_display_extension) (ctx, rw, ¤t->data.sequence_display); - case 3: + case MPEG2_EXTENSION_QUANT_MATRIX: return FUNC(quant_matrix_extension) (ctx, rw, ¤t->data.quant_matrix); - case 7: + case MPEG2_EXTENSION_PICTURE_DISPLAY: return FUNC(picture_display_extension) (ctx, rw, ¤t->data.picture_display); - case 8: + case MPEG2_EXTENSION_PICTURE_CODING: return FUNC(picture_coding_extension) (ctx, rw, ¤t->data.picture_coding); default: - av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid extension ID %d.\n", + av_log(ctx->log_ctx, AV_LOG_ERROR, "Extension ID %d not supported.\n", current->extension_start_code_identifier); - return AVERROR_INVALIDDATA; + return AVERROR_PATCHWELCOME; } } @@ -342,7 +358,7 @@ static int FUNC(slice_header)(CodedBitstreamContext *ctx, RWContext *rw, ui(7, priority_breakpoint); } - ui(5, quantiser_scale_code); + uir(5, quantiser_scale_code); if (nextbits(1, 1, current->slice_extension_flag)) { ui(1, slice_extension_flag); @@ -361,20 +377,22 @@ static int FUNC(slice_header)(CodedBitstreamContext *ctx, RWContext *rw, current->extra_information_length = k; if (k > 0) { *rw = start; - current->extra_information = - av_malloc(current->extra_information_length); - if (!current->extra_information) + current->extra_information_ref = + av_buffer_alloc(current->extra_information_length); + if (!current->extra_information_ref) return AVERROR(ENOMEM); + current->extra_information = current->extra_information_ref->data; for (k = 0; k < current->extra_information_length; k++) { - xui(1, extra_bit_slice, bit); - xui(8, extra_information_slice, - current->extra_information[k]); + xui(1, extra_bit_slice, bit, 1, 1, 0); + xui(8, extra_information_slice[k], + current->extra_information[k], 0, 255, 1, k); } } #else for (k = 0; k < current->extra_information_length; k++) { - xui(1, extra_bit_slice, 1); - xui(8, extra_information_slice, current->extra_information[k]); + xui(1, extra_bit_slice, 1, 1, 1, 0); + xui(8, extra_information_slice[k], + current->extra_information[k], 0, 255, 1, k); } #endif } diff --git a/libavcodec/cbs_vp9.c b/libavcodec/cbs_vp9.c new file mode 100644 index 000000000..5579d9b0a --- /dev/null +++ b/libavcodec/cbs_vp9.c @@ -0,0 +1,692 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/avassert.h" + +#include "cbs.h" +#include "cbs_internal.h" +#include "cbs_vp9.h" +#include "internal.h" + + +static int cbs_vp9_read_s(CodedBitstreamContext *ctx, GetBitContext *gbc, + int width, const char *name, + const int *subscripts, int32_t *write_to) +{ + uint32_t magnitude; + int position, sign; + int32_t value; + + if (ctx->trace_enable) + position = get_bits_count(gbc); + + if (get_bits_left(gbc) < width + 1) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid signed value at " + "%s: bitstream ended.\n", name); + return AVERROR_INVALIDDATA; + } + + magnitude = get_bits(gbc, width); + sign = get_bits1(gbc); + value = sign ? -(int32_t)magnitude : magnitude; + + if (ctx->trace_enable) { + char bits[33]; + int i; + for (i = 0; i < width; i++) + bits[i] = magnitude >> (width - i - 1) & 1 ? '1' : '0'; + bits[i] = sign ? '1' : '0'; + bits[i + 1] = 0; + + ff_cbs_trace_syntax_element(ctx, position, name, subscripts, + bits, value); + } + + *write_to = value; + return 0; +} + +static int cbs_vp9_write_s(CodedBitstreamContext *ctx, PutBitContext *pbc, + int width, const char *name, + const int *subscripts, int32_t value) +{ + uint32_t magnitude; + int sign; + + if (put_bits_left(pbc) < width + 1) + return AVERROR(ENOSPC); + + sign = value < 0; + magnitude = sign ? -value : value; + + if (ctx->trace_enable) { + char bits[33]; + int i; + for (i = 0; i < width; i++) + bits[i] = magnitude >> (width - i - 1) & 1 ? '1' : '0'; + bits[i] = sign ? '1' : '0'; + bits[i + 1] = 0; + + ff_cbs_trace_syntax_element(ctx, put_bits_count(pbc), + name, subscripts, bits, value); + } + + put_bits(pbc, width, magnitude); + put_bits(pbc, 1, sign); + + return 0; +} + +static int cbs_vp9_read_increment(CodedBitstreamContext *ctx, GetBitContext *gbc, + uint32_t range_min, uint32_t range_max, + const char *name, uint32_t *write_to) +{ + uint32_t value; + int position, i; + char bits[8]; + + av_assert0(range_min <= range_max && range_max - range_min < sizeof(bits) - 1); + if (ctx->trace_enable) + position = get_bits_count(gbc); + + for (i = 0, value = range_min; value < range_max;) { + if (get_bits_left(gbc) < 1) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid increment value at " + "%s: bitstream ended.\n", name); + return AVERROR_INVALIDDATA; + } + if (get_bits1(gbc)) { + bits[i++] = '1'; + ++value; + } else { + bits[i++] = '0'; + break; + } + } + + if (ctx->trace_enable) { + bits[i] = 0; + ff_cbs_trace_syntax_element(ctx, position, name, NULL, bits, value); + } + + *write_to = value; + return 0; +} + +static int cbs_vp9_write_increment(CodedBitstreamContext *ctx, PutBitContext *pbc, + uint32_t range_min, uint32_t range_max, + const char *name, uint32_t value) +{ + int len; + + av_assert0(range_min <= range_max && range_max - range_min < 8); + if (value < range_min || value > range_max) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "%s out of range: " + "%"PRIu32", but must be in [%"PRIu32",%"PRIu32"].\n", + name, value, range_min, range_max); + return AVERROR_INVALIDDATA; + } + + if (value == range_max) + len = range_max - range_min; + else + len = value - range_min + 1; + if (put_bits_left(pbc) < len) + return AVERROR(ENOSPC); + + if (ctx->trace_enable) { + char bits[8]; + int i; + for (i = 0; i < len; i++) { + if (range_min + i == value) + bits[i] = '0'; + else + bits[i] = '1'; + } + bits[i] = 0; + ff_cbs_trace_syntax_element(ctx, put_bits_count(pbc), + name, NULL, bits, value); + } + + if (len > 0) + put_bits(pbc, len, (1 << len) - 1 - (value != range_max)); + + return 0; +} + +static int cbs_vp9_read_le(CodedBitstreamContext *ctx, GetBitContext *gbc, + int width, const char *name, + const int *subscripts, uint32_t *write_to) +{ + uint32_t value; + int position, b; + + av_assert0(width % 8 == 0); + + if (ctx->trace_enable) + position = get_bits_count(gbc); + + if (get_bits_left(gbc) < width) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid le value at " + "%s: bitstream ended.\n", name); + return AVERROR_INVALIDDATA; + } + + value = 0; + for (b = 0; b < width; b += 8) + value |= get_bits(gbc, 8) << b; + + if (ctx->trace_enable) { + char bits[33]; + int i; + for (b = 0; b < width; b += 8) + for (i = 0; i < 8; i++) + bits[b + i] = value >> (b + i) & 1 ? '1' : '0'; + bits[b] = 0; + + ff_cbs_trace_syntax_element(ctx, position, name, subscripts, + bits, value); + } + + *write_to = value; + return 0; +} + +static int cbs_vp9_write_le(CodedBitstreamContext *ctx, PutBitContext *pbc, + int width, const char *name, + const int *subscripts, uint32_t value) +{ + int b; + + av_assert0(width % 8 == 0); + + if (put_bits_left(pbc) < width) + return AVERROR(ENOSPC); + + if (ctx->trace_enable) { + char bits[33]; + int i; + for (b = 0; b < width; b += 8) + for (i = 0; i < 8; i++) + bits[b + i] = value >> (b + i) & 1 ? '1' : '0'; + bits[b] = 0; + + ff_cbs_trace_syntax_element(ctx, put_bits_count(pbc), + name, subscripts, bits, value); + } + + for (b = 0; b < width; b += 8) + put_bits(pbc, 8, value >> b & 0xff); + + return 0; +} + +#define HEADER(name) do { \ + ff_cbs_trace_header(ctx, name); \ + } while (0) + +#define CHECK(call) do { \ + err = (call); \ + if (err < 0) \ + return err; \ + } while (0) + +#define FUNC_NAME(rw, codec, name) cbs_ ## codec ## _ ## rw ## _ ## name +#define FUNC_VP9(rw, name) FUNC_NAME(rw, vp9, name) +#define FUNC(name) FUNC_VP9(READWRITE, name) + +#define SUBSCRIPTS(subs, ...) (subs > 0 ? ((int[subs + 1]){ subs, __VA_ARGS__ }) : NULL) + +#define f(width, name) \ + xf(width, name, current->name, 0) +#define s(width, name) \ + xs(width, name, current->name, 0) +#define fs(width, name, subs, ...) \ + xf(width, name, current->name, subs, __VA_ARGS__) +#define ss(width, name, subs, ...) \ + xs(width, name, current->name, subs, __VA_ARGS__) + + +#define READ +#define READWRITE read +#define RWContext GetBitContext + +#define xf(width, name, var, subs, ...) do { \ + uint32_t value = 0; \ + CHECK(ff_cbs_read_unsigned(ctx, rw, width, #name, \ + SUBSCRIPTS(subs, __VA_ARGS__), \ + &value, 0, (1 << width) - 1)); \ + var = value; \ + } while (0) +#define xs(width, name, var, subs, ...) do { \ + int32_t value = 0; \ + CHECK(cbs_vp9_read_s(ctx, rw, width, #name, \ + SUBSCRIPTS(subs, __VA_ARGS__), &value)); \ + var = value; \ + } while (0) + + +#define increment(name, min, max) do { \ + uint32_t value = 0; \ + CHECK(cbs_vp9_read_increment(ctx, rw, min, max, #name, &value)); \ + current->name = value; \ + } while (0) + +#define fle(width, name, subs, ...) do { \ + CHECK(cbs_vp9_read_le(ctx, rw, width, #name, \ + SUBSCRIPTS(subs, __VA_ARGS__), ¤t->name)); \ + } while (0) + +#define delta_q(name) do { \ + uint8_t delta_coded; \ + int8_t delta_q; \ + xf(1, name.delta_coded, delta_coded, 0); \ + if (delta_coded) \ + xs(4, name.delta_q, delta_q, 0); \ + else \ + delta_q = 0; \ + current->name = delta_q; \ + } while (0) + +#define prob(name, subs, ...) do { \ + uint8_t prob_coded; \ + uint8_t prob; \ + xf(1, name.prob_coded, prob_coded, subs, __VA_ARGS__); \ + if (prob_coded) \ + xf(8, name.prob, prob, subs, __VA_ARGS__); \ + else \ + prob = 255; \ + current->name = prob; \ + } while (0) + +#define fixed(width, name, value) do { \ + av_unused uint32_t fixed_value = value; \ + CHECK(ff_cbs_read_unsigned(ctx, rw, width, #name, \ + 0, &fixed_value, value, value)); \ + } while (0) + +#define infer(name, value) do { \ + current->name = value; \ + } while (0) + +#define byte_alignment(rw) (get_bits_count(rw) % 8) + +#include "cbs_vp9_syntax_template.c" + +#undef READ +#undef READWRITE +#undef RWContext +#undef xf +#undef xs +#undef increment +#undef fle +#undef delta_q +#undef prob +#undef fixed +#undef infer +#undef byte_alignment + + +#define WRITE +#define READWRITE write +#define RWContext PutBitContext + +#define xf(width, name, var, subs, ...) do { \ + CHECK(ff_cbs_write_unsigned(ctx, rw, width, #name, \ + SUBSCRIPTS(subs, __VA_ARGS__), \ + var, 0, (1 << width) - 1)); \ + } while (0) +#define xs(width, name, var, subs, ...) do { \ + CHECK(cbs_vp9_write_s(ctx, rw, width, #name, \ + SUBSCRIPTS(subs, __VA_ARGS__), var)); \ + } while (0) + +#define increment(name, min, max) do { \ + CHECK(cbs_vp9_write_increment(ctx, rw, min, max, #name, current->name)); \ + } while (0) + +#define fle(width, name, subs, ...) do { \ + CHECK(cbs_vp9_write_le(ctx, rw, width, #name, \ + SUBSCRIPTS(subs, __VA_ARGS__), current->name)); \ + } while (0) + +#define delta_q(name) do { \ + xf(1, name.delta_coded, !!current->name, 0); \ + if (current->name) \ + xs(4, name.delta_q, current->name, 0); \ + } while (0) + +#define prob(name, subs, ...) do { \ + xf(1, name.prob_coded, current->name != 255, subs, __VA_ARGS__); \ + if (current->name != 255) \ + xf(8, name.prob, current->name, subs, __VA_ARGS__); \ + } while (0) + +#define fixed(width, name, value) do { \ + CHECK(ff_cbs_write_unsigned(ctx, rw, width, #name, \ + 0, value, value, value)); \ + } while (0) + +#define infer(name, value) do { \ + if (current->name != (value)) { \ + av_log(ctx->log_ctx, AV_LOG_WARNING, "Warning: " \ + "%s does not match inferred value: " \ + "%"PRId64", but should be %"PRId64".\n", \ + #name, (int64_t)current->name, (int64_t)(value)); \ + } \ + } while (0) + +#define byte_alignment(rw) (put_bits_count(rw) % 8) + +#include "cbs_vp9_syntax_template.c" + +#undef WRITE +#undef READWRITE +#undef RWContext +#undef xf +#undef xs +#undef increment +#undef fle +#undef delta_q +#undef prob +#undef fixed +#undef infer +#undef byte_alignment + + +static int cbs_vp9_split_fragment(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag, + int header) +{ + uint8_t superframe_header; + int err; + + // Last byte in the packet. + superframe_header = frag->data[frag->data_size - 1]; + + if ((superframe_header & 0xe0) == 0xc0) { + VP9RawSuperframeIndex sfi; + GetBitContext gbc; + size_t index_size, pos; + int i; + + index_size = 2 + (((superframe_header & 0x18) >> 3) + 1) * + ((superframe_header & 0x07) + 1); + + err = init_get_bits(&gbc, frag->data + frag->data_size - index_size, + 8 * index_size); + if (err < 0) + return err; + + err = cbs_vp9_read_superframe_index(ctx, &gbc, &sfi); + if (err < 0) + return err; + + pos = 0; + for (i = 0; i <= sfi.frames_in_superframe_minus_1; i++) { + if (pos + sfi.frame_sizes[i] + index_size > frag->data_size) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Frame %d too large " + "in superframe: %"PRIu32" bytes.\n", + i, sfi.frame_sizes[i]); + return AVERROR_INVALIDDATA; + } + + err = ff_cbs_insert_unit_data(ctx, frag, -1, 0, + frag->data + pos, + sfi.frame_sizes[i], + frag->data_ref); + if (err < 0) + return err; + + pos += sfi.frame_sizes[i]; + } + if (pos + index_size != frag->data_size) { + av_log(ctx->log_ctx, AV_LOG_WARNING, "Extra padding at " + "end of superframe: %"SIZE_SPECIFIER" bytes.\n", + frag->data_size - (pos + index_size)); + } + + return 0; + + } else { + err = ff_cbs_insert_unit_data(ctx, frag, -1, 0, + frag->data, frag->data_size, + frag->data_ref); + if (err < 0) + return err; + } + + return 0; +} + +static void cbs_vp9_free_frame(void *unit, uint8_t *content) +{ + VP9RawFrame *frame = (VP9RawFrame*)content; + av_buffer_unref(&frame->data_ref); + av_freep(&frame); +} + +static int cbs_vp9_read_unit(CodedBitstreamContext *ctx, + CodedBitstreamUnit *unit) +{ + VP9RawFrame *frame; + GetBitContext gbc; + int err, pos; + + err = init_get_bits(&gbc, unit->data, 8 * unit->data_size); + if (err < 0) + return err; + + err = ff_cbs_alloc_unit_content(ctx, unit, sizeof(*frame), + &cbs_vp9_free_frame); + if (err < 0) + return err; + frame = unit->content; + + err = cbs_vp9_read_frame(ctx, &gbc, frame); + if (err < 0) + return err; + + pos = get_bits_count(&gbc); + av_assert0(pos % 8 == 0); + pos /= 8; + av_assert0(pos <= unit->data_size); + + if (pos == unit->data_size) { + // No data (e.g. a show-existing-frame frame). + } else { + frame->data_ref = av_buffer_ref(unit->data_ref); + if (!frame->data_ref) + return AVERROR(ENOMEM); + + frame->data = unit->data + pos; + frame->data_size = unit->data_size - pos; + } + + return 0; +} + +static int cbs_vp9_write_unit(CodedBitstreamContext *ctx, + CodedBitstreamUnit *unit) +{ + CodedBitstreamVP9Context *priv = ctx->priv_data; + VP9RawFrame *frame = unit->content; + PutBitContext pbc; + int err; + + if (!priv->write_buffer) { + // Initial write buffer size is 1MB. + priv->write_buffer_size = 1024 * 1024; + + reallocate_and_try_again: + err = av_reallocp(&priv->write_buffer, priv->write_buffer_size); + if (err < 0) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Unable to allocate a " + "sufficiently large write buffer (last attempt " + "%"SIZE_SPECIFIER" bytes).\n", priv->write_buffer_size); + return err; + } + } + + init_put_bits(&pbc, priv->write_buffer, priv->write_buffer_size); + + err = cbs_vp9_write_frame(ctx, &pbc, frame); + if (err == AVERROR(ENOSPC)) { + priv->write_buffer_size *= 2; + goto reallocate_and_try_again; + } + if (err < 0) + return err; + + // Frame must be byte-aligned. + av_assert0(put_bits_count(&pbc) % 8 == 0); + + unit->data_size = put_bits_count(&pbc) / 8; + unit->data_bit_padding = 0; + flush_put_bits(&pbc); + + if (frame->data) { + if (unit->data_size + frame->data_size > + priv->write_buffer_size) { + priv->write_buffer_size *= 2; + goto reallocate_and_try_again; + } + + memcpy(priv->write_buffer + unit->data_size, + frame->data, frame->data_size); + unit->data_size += frame->data_size; + } + + err = ff_cbs_alloc_unit_data(ctx, unit, unit->data_size); + if (err < 0) + return err; + + memcpy(unit->data, priv->write_buffer, unit->data_size); + + return 0; +} + +static int cbs_vp9_assemble_fragment(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag) +{ + int err; + + if (frag->nb_units == 1) { + // Output is just the content of the single frame. + + CodedBitstreamUnit *frame = &frag->units[0]; + + frag->data_ref = av_buffer_ref(frame->data_ref); + if (!frag->data_ref) + return AVERROR(ENOMEM); + + frag->data = frame->data; + frag->data_size = frame->data_size; + + } else { + // Build superframe out of frames. + + VP9RawSuperframeIndex sfi; + PutBitContext pbc; + AVBufferRef *ref; + uint8_t *data; + size_t size, max, pos; + int i, size_len; + + if (frag->nb_units > 8) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Too many frames to " + "make superframe: %d.\n", frag->nb_units); + return AVERROR(EINVAL); + } + + max = 0; + for (i = 0; i < frag->nb_units; i++) + if (max < frag->units[i].data_size) + max = frag->units[i].data_size; + + if (max < 2) + size_len = 1; + else + size_len = av_log2(max) / 8 + 1; + av_assert0(size_len <= 4); + + sfi.superframe_marker = VP9_SUPERFRAME_MARKER; + sfi.bytes_per_framesize_minus_1 = size_len - 1; + sfi.frames_in_superframe_minus_1 = frag->nb_units - 1; + + size = 2; + for (i = 0; i < frag->nb_units; i++) { + size += size_len + frag->units[i].data_size; + sfi.frame_sizes[i] = frag->units[i].data_size; + } + + ref = av_buffer_alloc(size + AV_INPUT_BUFFER_PADDING_SIZE); + if (!ref) + return AVERROR(ENOMEM); + data = ref->data; + memset(data + size, 0, AV_INPUT_BUFFER_PADDING_SIZE); + + pos = 0; + for (i = 0; i < frag->nb_units; i++) { + av_assert0(size - pos > frag->units[i].data_size); + memcpy(data + pos, frag->units[i].data, + frag->units[i].data_size); + pos += frag->units[i].data_size; + } + av_assert0(size - pos == 2 + frag->nb_units * size_len); + + init_put_bits(&pbc, data + pos, size - pos); + + err = cbs_vp9_write_superframe_index(ctx, &pbc, &sfi); + if (err < 0) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Failed to write " + "superframe index.\n"); + av_buffer_unref(&ref); + return err; + } + + av_assert0(put_bits_left(&pbc) == 0); + flush_put_bits(&pbc); + + frag->data_ref = ref; + frag->data = data; + frag->data_size = size; + } + + return 0; +} + +static void cbs_vp9_close(CodedBitstreamContext *ctx) +{ + CodedBitstreamVP9Context *priv = ctx->priv_data; + + av_freep(&priv->write_buffer); +} + +const CodedBitstreamType ff_cbs_type_vp9 = { + .codec_id = AV_CODEC_ID_VP9, + + .priv_data_size = sizeof(CodedBitstreamVP9Context), + + .split_fragment = &cbs_vp9_split_fragment, + .read_unit = &cbs_vp9_read_unit, + .write_unit = &cbs_vp9_write_unit, + .assemble_fragment = &cbs_vp9_assemble_fragment, + + .close = &cbs_vp9_close, +}; diff --git a/libavcodec/cbs_vp9.h b/libavcodec/cbs_vp9.h new file mode 100644 index 000000000..4c9b2f880 --- /dev/null +++ b/libavcodec/cbs_vp9.h @@ -0,0 +1,217 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * 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_CBS_VP9_H +#define AVCODEC_CBS_VP9_H + +#include +#include + +#include "cbs.h" + + +// Miscellaneous constants (section 3). +enum { + VP9_REFS_PER_FRAME = 3, + + VP9_MIN_TILE_WIDTH_B64 = 4, + VP9_MAX_TILE_WIDTH_B64 = 64, + + VP9_NUM_REF_FRAMES = 8, + VP9_MAX_REF_FRAMES = 4, + + VP9_MAX_SEGMENTS = 8, + VP9_SEG_LVL_MAX = 4, +}; + +// Frame types (section 7.2). +enum { + VP9_KEY_FRAME = 0, + VP9_NON_KEY_FRAME = 1, +}; + +// Frame sync bytes (section 7.2.1). +enum { + VP9_FRAME_SYNC_0 = 0x49, + VP9_FRAME_SYNC_1 = 0x83, + VP9_FRAME_SYNC_2 = 0x42, +}; + +// Color space values (section 7.2.2). +enum { + VP9_CS_UNKNOWN = 0, + VP9_CS_BT_601 = 1, + VP9_CS_BT_709 = 2, + VP9_CS_SMPTE_170 = 3, + VP9_CS_SMPTE_240 = 4, + VP9_CS_BT_2020 = 5, + VP9_CS_RESERVED = 6, + VP9_CS_RGB = 7, +}; + +// Reference frame types (section 7.4.12). +enum { + VP9_INTRA_FRAME = 0, + VP9_LAST_FRAME = 1, + VP9_GOLDEN_FRAME = 2, + VP9_ALTREF_FRAME = 3, +}; + +// Superframe properties (section B.3). +enum { + VP9_MAX_FRAMES_IN_SUPERFRAME = 8, + + VP9_SUPERFRAME_MARKER = 6, +}; + + +typedef struct VP9RawFrameHeader { + uint8_t frame_marker; + uint8_t profile_low_bit; + uint8_t profile_high_bit; + + uint8_t show_existing_frame; + uint8_t frame_to_show_map_idx; + + uint8_t frame_type; + uint8_t show_frame; + uint8_t error_resilient_mode; + + // Color config. + uint8_t ten_or_twelve_bit; + uint8_t color_space; + uint8_t color_range; + uint8_t subsampling_x; + uint8_t subsampling_y; + + uint8_t refresh_frame_flags; + + uint8_t intra_only; + uint8_t reset_frame_context; + + uint8_t ref_frame_idx[VP9_REFS_PER_FRAME]; + uint8_t ref_frame_sign_bias[VP9_MAX_REF_FRAMES]; + + uint8_t allow_high_precision_mv; + + uint8_t refresh_frame_context; + uint8_t frame_parallel_decoding_mode; + + uint8_t frame_context_idx; + + // Frame/render size. + uint8_t found_ref[VP9_REFS_PER_FRAME]; + uint16_t frame_width_minus_1; + uint16_t frame_height_minus_1; + uint8_t render_and_frame_size_different; + uint16_t render_width_minus_1; + uint16_t render_height_minus_1; + + // Interpolation filter. + uint8_t is_filter_switchable; + uint8_t raw_interpolation_filter_type; + + // Loop filter params. + uint8_t loop_filter_level; + uint8_t loop_filter_sharpness; + uint8_t loop_filter_delta_enabled; + uint8_t loop_filter_delta_update; + uint8_t update_ref_delta[VP9_MAX_REF_FRAMES]; + int8_t loop_filter_ref_deltas[VP9_MAX_REF_FRAMES]; + uint8_t update_mode_delta[2]; + int8_t loop_filter_mode_deltas[2]; + + // Quantization params. + uint8_t base_q_idx; + int8_t delta_q_y_dc; + int8_t delta_q_uv_dc; + int8_t delta_q_uv_ac; + + // Segmentation params. + uint8_t segmentation_enabled; + uint8_t segmentation_update_map; + uint8_t segmentation_tree_probs[7]; + uint8_t segmentation_temporal_update; + uint8_t segmentation_pred_prob[3]; + uint8_t segmentation_update_data; + uint8_t segmentation_abs_or_delta_update; + uint8_t feature_enabled[VP9_MAX_SEGMENTS][VP9_SEG_LVL_MAX]; + uint8_t feature_value[VP9_MAX_SEGMENTS][VP9_SEG_LVL_MAX]; + uint8_t feature_sign[VP9_MAX_SEGMENTS][VP9_SEG_LVL_MAX]; + + // Tile info. + uint8_t tile_cols_log2; + uint8_t tile_rows_log2; + + uint16_t header_size_in_bytes; +} VP9RawFrameHeader; + +typedef struct VP9RawFrame { + VP9RawFrameHeader header; + + uint8_t *data; + size_t data_size; + AVBufferRef *data_ref; +} VP9RawFrame; + +typedef struct VP9RawSuperframeIndex { + uint8_t superframe_marker; + uint8_t bytes_per_framesize_minus_1; + uint8_t frames_in_superframe_minus_1; + uint32_t frame_sizes[VP9_MAX_FRAMES_IN_SUPERFRAME]; +} VP9RawSuperframeIndex; + +typedef struct VP9RawSuperframe { + VP9RawFrame frames[VP9_MAX_FRAMES_IN_SUPERFRAME]; + VP9RawSuperframeIndex index; +} VP9RawSuperframe; + +typedef struct VP9ReferenceFrameState { + int frame_width; // RefFrameWidth + int frame_height; // RefFrameHeight + int subsampling_x; // RefSubsamplingX + int subsampling_y; // RefSubsamplingY + int bit_depth; // RefBitDepth +} VP9ReferenceFrameState; + +typedef struct CodedBitstreamVP9Context { + int profile; + + // Frame dimensions in 8x8 mode info blocks. + uint16_t mi_cols; + uint16_t mi_rows; + // Frame dimensions in 64x64 superblocks. + uint16_t sb64_cols; + uint16_t sb64_rows; + + int frame_width; + int frame_height; + + uint8_t subsampling_x; + uint8_t subsampling_y; + int bit_depth; + + VP9ReferenceFrameState ref[VP9_NUM_REF_FRAMES]; + + // Write buffer. + uint8_t *write_buffer; + size_t write_buffer_size; +} CodedBitstreamVP9Context; + + +#endif /* AVCODEC_CBS_VP9_H */ diff --git a/libavcodec/cbs_vp9_syntax_template.c b/libavcodec/cbs_vp9_syntax_template.c new file mode 100644 index 000000000..125eb0258 --- /dev/null +++ b/libavcodec/cbs_vp9_syntax_template.c @@ -0,0 +1,442 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +static int FUNC(frame_sync_code)(CodedBitstreamContext *ctx, RWContext *rw, + VP9RawFrameHeader *current) +{ + uint8_t frame_sync_byte_0 = VP9_FRAME_SYNC_0; + uint8_t frame_sync_byte_1 = VP9_FRAME_SYNC_1; + uint8_t frame_sync_byte_2 = VP9_FRAME_SYNC_2; + int err; + + xf(8, frame_sync_byte_0, frame_sync_byte_0, 0); + xf(8, frame_sync_byte_1, frame_sync_byte_1, 0); + xf(8, frame_sync_byte_2, frame_sync_byte_2, 0); + + if (frame_sync_byte_0 != VP9_FRAME_SYNC_0 || + frame_sync_byte_1 != VP9_FRAME_SYNC_1 || + frame_sync_byte_2 != VP9_FRAME_SYNC_2) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid frame sync code: " + "%02x %02x %02x.\n", frame_sync_byte_0, + frame_sync_byte_1, frame_sync_byte_2); + return AVERROR_INVALIDDATA; + } + + return 0; +} + +static int FUNC(color_config)(CodedBitstreamContext *ctx, RWContext *rw, + VP9RawFrameHeader *current, int profile) +{ + CodedBitstreamVP9Context *vp9 = ctx->priv_data; + int err; + + if (profile >= 2) { + f(1, ten_or_twelve_bit); + vp9->bit_depth = current->ten_or_twelve_bit ? 12 : 10; + } else + vp9->bit_depth = 8; + + f(3, color_space); + + if (current->color_space != VP9_CS_RGB) { + f(1, color_range); + if (profile == 1 || profile == 3) { + f(1, subsampling_x); + f(1, subsampling_y); + fixed(1, reserved_zero, 0); + } else { + infer(subsampling_x, 1); + infer(subsampling_y, 1); + } + } else { + infer(color_range, 1); + if (profile == 1 || profile == 3) { + infer(subsampling_x, 0); + infer(subsampling_y, 0); + fixed(1, reserved_zero, 0); + } + } + + vp9->subsampling_x = current->subsampling_x; + vp9->subsampling_y = current->subsampling_y; + + return 0; +} + +static int FUNC(frame_size)(CodedBitstreamContext *ctx, RWContext *rw, + VP9RawFrameHeader *current) +{ + CodedBitstreamVP9Context *vp9 = ctx->priv_data; + int err; + + f(16, frame_width_minus_1); + f(16, frame_height_minus_1); + + vp9->frame_width = current->frame_width_minus_1 + 1; + vp9->frame_height = current->frame_height_minus_1 + 1; + + vp9->mi_cols = (vp9->frame_width + 7) >> 3; + vp9->mi_rows = (vp9->frame_height + 7) >> 3; + vp9->sb64_cols = (vp9->mi_cols + 7) >> 3; + vp9->sb64_rows = (vp9->mi_rows + 7) >> 3; + + return 0; +} + +static int FUNC(render_size)(CodedBitstreamContext *ctx, RWContext *rw, + VP9RawFrameHeader *current) +{ + int err; + + f(1, render_and_frame_size_different); + + if (current->render_and_frame_size_different) { + f(16, render_width_minus_1); + f(16, render_height_minus_1); + } + + return 0; +} + +static int FUNC(frame_size_with_refs)(CodedBitstreamContext *ctx, RWContext *rw, + VP9RawFrameHeader *current) +{ + CodedBitstreamVP9Context *vp9 = ctx->priv_data; + int err, i; + + for (i = 0; i < VP9_REFS_PER_FRAME; i++) { + fs(1, found_ref[i], 1, i); + if (current->found_ref[i]) { + VP9ReferenceFrameState *ref = + &vp9->ref[current->ref_frame_idx[i]]; + + vp9->frame_width = ref->frame_width; + vp9->frame_height = ref->frame_height; + + vp9->subsampling_x = ref->subsampling_x; + vp9->subsampling_y = ref->subsampling_y; + vp9->bit_depth = ref->bit_depth; + + break; + } + } + if (i >= VP9_REFS_PER_FRAME) + CHECK(FUNC(frame_size)(ctx, rw, current)); + else { + vp9->mi_cols = (vp9->frame_width + 7) >> 3; + vp9->mi_rows = (vp9->frame_height + 7) >> 3; + vp9->sb64_cols = (vp9->mi_cols + 7) >> 3; + vp9->sb64_rows = (vp9->mi_rows + 7) >> 3; + } + CHECK(FUNC(render_size)(ctx, rw, current)); + + return 0; +} + +static int FUNC(interpolation_filter)(CodedBitstreamContext *ctx, RWContext *rw, + VP9RawFrameHeader *current) +{ + int err; + + f(1, is_filter_switchable); + if (!current->is_filter_switchable) + f(2, raw_interpolation_filter_type); + + return 0; +} + +static int FUNC(loop_filter_params)(CodedBitstreamContext *ctx, RWContext *rw, + VP9RawFrameHeader *current) +{ + int err, i; + + f(6, loop_filter_level); + f(3, loop_filter_sharpness); + + f(1, loop_filter_delta_enabled); + if (current->loop_filter_delta_enabled) { + f(1, loop_filter_delta_update); + if (current->loop_filter_delta_update) { + for (i = 0; i < VP9_MAX_REF_FRAMES; i++) { + fs(1, update_ref_delta[i], 1, i); + if (current->update_ref_delta[i]) + ss(6, loop_filter_ref_deltas[i], 1, i); + } + for (i = 0; i < 2; i++) { + fs(1, update_mode_delta[i], 1, i); + if (current->update_mode_delta[i]) + ss(6, loop_filter_mode_deltas[i], 1, i); + } + } + } + + return 0; +} + +static int FUNC(quantization_params)(CodedBitstreamContext *ctx, RWContext *rw, + VP9RawFrameHeader *current) +{ + int err; + + f(8, base_q_idx); + + delta_q(delta_q_y_dc); + delta_q(delta_q_uv_dc); + delta_q(delta_q_uv_ac); + + return 0; +} + +static int FUNC(segmentation_params)(CodedBitstreamContext *ctx, RWContext *rw, + VP9RawFrameHeader *current) +{ + static const uint8_t segmentation_feature_bits[VP9_SEG_LVL_MAX] = { 8, 6, 2, 0 }; + static const uint8_t segmentation_feature_signed[VP9_SEG_LVL_MAX] = { 1, 1, 0, 0 }; + + int err, i, j; + + f(1, segmentation_enabled); + + if (current->segmentation_enabled) { + f(1, segmentation_update_map); + if (current->segmentation_update_map) { + for (i = 0; i < 7; i++) + prob(segmentation_tree_probs[i], 1, i); + f(1, segmentation_temporal_update); + for (i = 0; i < 3; i++) { + if (current->segmentation_temporal_update) + prob(segmentation_pred_prob[i], 1, i); + else + infer(segmentation_pred_prob[i], 255); + } + } + + f(1, segmentation_update_data); + if (current->segmentation_update_data) { + f(1, segmentation_abs_or_delta_update); + for (i = 0; i < VP9_MAX_SEGMENTS; i++) { + for (j = 0; j < VP9_SEG_LVL_MAX; j++) { + fs(1, feature_enabled[i][j], 2, i, j); + if (current->feature_enabled[i][j] && + segmentation_feature_bits[j]) { + fs(segmentation_feature_bits[j], + feature_value[i][j], 2, i, j); + if (segmentation_feature_signed[j]) + fs(1, feature_sign[i][j], 2, i, j); + else + infer(feature_sign[i][j], 0); + } else { + infer(feature_value[i][j], 0); + infer(feature_sign[i][j], 0); + } + } + } + } + } + + return 0; +} + +static int FUNC(tile_info)(CodedBitstreamContext *ctx, RWContext *rw, + VP9RawFrameHeader *current) +{ + CodedBitstreamVP9Context *vp9 = ctx->priv_data; + int min_log2_tile_cols, max_log2_tile_cols; + int err; + + min_log2_tile_cols = 0; + while ((VP9_MAX_TILE_WIDTH_B64 << min_log2_tile_cols) < vp9->sb64_cols) + ++min_log2_tile_cols; + max_log2_tile_cols = 0; + while ((vp9->sb64_cols >> (max_log2_tile_cols + 1)) >= VP9_MIN_TILE_WIDTH_B64) + ++max_log2_tile_cols; + + increment(tile_cols_log2, min_log2_tile_cols, max_log2_tile_cols); + + increment(tile_rows_log2, 0, 2); + + return 0; +} + +static int FUNC(uncompressed_header)(CodedBitstreamContext *ctx, RWContext *rw, + VP9RawFrameHeader *current) +{ + CodedBitstreamVP9Context *vp9 = ctx->priv_data; + int err, i; + + f(2, frame_marker); + + f(1, profile_low_bit); + f(1, profile_high_bit); + vp9->profile = (current->profile_high_bit << 1) + current->profile_low_bit; + if (vp9->profile == 3) + fixed(1, reserved_zero, 0); + + f(1, show_existing_frame); + if (current->show_existing_frame) { + f(3, frame_to_show_map_idx); + infer(header_size_in_bytes, 0); + infer(refresh_frame_flags, 0x00); + infer(loop_filter_level, 0); + return 0; + } + + f(1, frame_type); + f(1, show_frame); + f(1, error_resilient_mode); + + if (current->frame_type == VP9_KEY_FRAME) { + CHECK(FUNC(frame_sync_code)(ctx, rw, current)); + CHECK(FUNC(color_config)(ctx, rw, current, vp9->profile)); + CHECK(FUNC(frame_size)(ctx, rw, current)); + CHECK(FUNC(render_size)(ctx, rw, current)); + + infer(refresh_frame_flags, 0xff); + + } else { + if (current->show_frame == 0) + f(1, intra_only); + else + infer(intra_only, 0); + + if (current->error_resilient_mode == 0) + f(2, reset_frame_context); + else + infer(reset_frame_context, 0); + + if (current->intra_only == 1) { + CHECK(FUNC(frame_sync_code)(ctx, rw, current)); + + if (vp9->profile > 0) { + CHECK(FUNC(color_config)(ctx, rw, current, vp9->profile)); + } else { + infer(color_space, 1); + infer(subsampling_x, 1); + infer(subsampling_y, 1); + vp9->bit_depth = 8; + + vp9->subsampling_x = current->subsampling_x; + vp9->subsampling_y = current->subsampling_y; + } + + f(8, refresh_frame_flags); + + CHECK(FUNC(frame_size)(ctx, rw, current)); + CHECK(FUNC(render_size)(ctx, rw, current)); + } else { + f(8, refresh_frame_flags); + + for (i = 0; i < VP9_REFS_PER_FRAME; i++) { + fs(3, ref_frame_idx[i], 1, i); + fs(1, ref_frame_sign_bias[VP9_LAST_FRAME + i], + 1, VP9_LAST_FRAME + i); + } + + CHECK(FUNC(frame_size_with_refs)(ctx, rw, current)); + f(1, allow_high_precision_mv); + CHECK(FUNC(interpolation_filter)(ctx, rw, current)); + } + } + + if (current->error_resilient_mode == 0) { + f(1, refresh_frame_context); + f(1, frame_parallel_decoding_mode); + } else { + infer(refresh_frame_context, 0); + infer(frame_parallel_decoding_mode, 1); + } + + f(2, frame_context_idx); + + CHECK(FUNC(loop_filter_params)(ctx, rw, current)); + CHECK(FUNC(quantization_params)(ctx, rw, current)); + CHECK(FUNC(segmentation_params)(ctx, rw, current)); + CHECK(FUNC(tile_info)(ctx, rw, current)); + + f(16, header_size_in_bytes); + + for (i = 0; i < VP9_NUM_REF_FRAMES; i++) { + if (current->refresh_frame_flags & (1 << i)) { + vp9->ref[i] = (VP9ReferenceFrameState) { + .frame_width = vp9->frame_width, + .frame_height = vp9->frame_height, + .subsampling_x = vp9->subsampling_x, + .subsampling_y = vp9->subsampling_y, + .bit_depth = vp9->bit_depth, + }; + } + } + + av_log(ctx->log_ctx, AV_LOG_DEBUG, "Frame: size %dx%d " + "subsample %dx%d bit_depth %d tiles %dx%d.\n", + vp9->frame_width, vp9->frame_height, + vp9->subsampling_x, vp9->subsampling_y, + vp9->bit_depth, 1 << current->tile_cols_log2, + 1 << current->tile_rows_log2); + + return 0; +} + +static int FUNC(trailing_bits)(CodedBitstreamContext *ctx, RWContext *rw) +{ + int err; + av_unused int zero = 0; + while (byte_alignment(rw) != 0) + xf(1, zero_bit, zero, 0); + + return 0; +} + +static int FUNC(frame)(CodedBitstreamContext *ctx, RWContext *rw, + VP9RawFrame *current) +{ + int err; + + HEADER("Frame"); + + CHECK(FUNC(uncompressed_header)(ctx, rw, ¤t->header)); + + CHECK(FUNC(trailing_bits)(ctx, rw)); + + return 0; +} + +static int FUNC(superframe_index)(CodedBitstreamContext *ctx, RWContext *rw, + VP9RawSuperframeIndex *current) +{ + int err, i; + + HEADER("Superframe Index"); + + f(3, superframe_marker); + f(2, bytes_per_framesize_minus_1); + f(3, frames_in_superframe_minus_1); + + for (i = 0; i <= current->frames_in_superframe_minus_1; i++) { + // Surprise little-endian! + fle(8 * (current->bytes_per_framesize_minus_1 + 1), + frame_sizes[i], 1, i); + } + + f(3, superframe_marker); + f(2, bytes_per_framesize_minus_1); + f(3, frames_in_superframe_minus_1); + + return 0; +} diff --git a/libavcodec/ccaption_dec.c b/libavcodec/ccaption_dec.c index 09ceb1b3b..bf3563a0b 100644 --- a/libavcodec/ccaption_dec.c +++ b/libavcodec/ccaption_dec.c @@ -212,10 +212,10 @@ static const unsigned char pac2_attribs[32][3] = // Color, font, ident struct Screen { /* +1 is used to compensate null character of string */ - uint8_t characters[SCREEN_ROWS][SCREEN_COLUMNS+1]; - uint8_t charsets[SCREEN_ROWS][SCREEN_COLUMNS+1]; - uint8_t colors[SCREEN_ROWS][SCREEN_COLUMNS+1]; - uint8_t fonts[SCREEN_ROWS][SCREEN_COLUMNS+1]; + uint8_t characters[SCREEN_ROWS+1][SCREEN_COLUMNS+1]; + uint8_t charsets[SCREEN_ROWS+1][SCREEN_COLUMNS+1]; + uint8_t colors[SCREEN_ROWS+1][SCREEN_COLUMNS+1]; + uint8_t fonts[SCREEN_ROWS+1][SCREEN_COLUMNS+1]; /* * Bitmask of used rows; if a bit is not set, the * corresponding row is not used. diff --git a/libavcodec/cdgraphics.c b/libavcodec/cdgraphics.c index da6fb7af0..cf3f01a41 100644 --- a/libavcodec/cdgraphics.c +++ b/libavcodec/cdgraphics.c @@ -69,6 +69,7 @@ typedef struct CDGraphicsContext { int hscroll; int vscroll; int transparency; + int cleared; } CDGraphicsContext; static av_cold int cdg_decode_init(AVCodecContext *avctx) @@ -284,9 +285,10 @@ static int cdg_decode_frame(AVCodecContext *avctx, if ((ret = ff_reget_buffer(avctx, cc->frame)) < 0) return ret; - if (!avctx->frame_number) { + if (!cc->cleared) { memset(cc->frame->data[0], 0, cc->frame->linesize[0] * avctx->height); memset(cc->frame->data[1], 0, AVPALETTE_SIZE); + cc->cleared = 1; } command = bytestream2_get_byte(&gb); diff --git a/libavcodec/cfhd.c b/libavcodec/cfhd.c index f10742f4f..49a5a2c30 100644 --- a/libavcodec/cfhd.c +++ b/libavcodec/cfhd.c @@ -49,12 +49,15 @@ enum CFHDParam { SubbandNumber = 48, Quantization = 53, ChannelNumber = 62, + SampleFlags = 68, BitsPerComponent = 101, ChannelWidth = 104, ChannelHeight = 105, PrescaleShift = 109, }; + + static av_cold int cfhd_init(AVCodecContext *avctx) { CFHDContext *s = avctx->priv_data; @@ -72,6 +75,13 @@ static void init_plane_defaults(CFHDContext *s) s->subband_num_actual = 0; } +static void init_peak_table_defaults(CFHDContext *s) +{ + s->peak.level = 0; + s->peak.offset = 0; + memset(&s->peak.base, 0, sizeof(s->peak.base)); +} + static void init_frame_defaults(CFHDContext *s) { s->coded_width = 0; @@ -86,15 +96,44 @@ static void init_frame_defaults(CFHDContext *s) s->wavelet_depth = 3; s->pshift = 1; s->codebook = 0; + s->difference_coding = 0; + s->progressive = 0; init_plane_defaults(s); + init_peak_table_defaults(s); } /* TODO: merge with VLC tables or use LUT */ -static inline int dequant_and_decompand(int level, int quantisation) +static inline int dequant_and_decompand(int level, int quantisation, int codebook) { - int64_t abslevel = abs(level); - return (abslevel + ((768 * abslevel * abslevel * abslevel) / (255 * 255 * 255))) * - FFSIGN(level) * quantisation; + if (codebook == 0 || codebook == 1) { + int64_t abslevel = abs(level); + if (level < 264) + return (abslevel + ((768 * abslevel * abslevel * abslevel) / (255 * 255 * 255))) * + FFSIGN(level) * quantisation; + else + return level * quantisation; + } else + return level * quantisation; +} + +static inline void difference_coding(int16_t *band, int width, int height) +{ + + int i,j; + for (i = 0; i < height; i++) { + for (j = 1; j < width; j++) { + band[j] += band[j-1]; + } + band += width; + } +} + +static inline void peak_table(int16_t *band, Peak *peak, int length) +{ + int i; + for (i = 0; i < length; i++) + if (abs(band[i]) > peak->level) + band[i] = bytestream2_get_le16(&peak->base); } static inline void process_alpha(int16_t *alpha, int width) @@ -154,6 +193,18 @@ static inline void filter(int16_t *output, ptrdiff_t out_stride, } } +static inline void interlaced_vertical_filter(int16_t *output, int16_t *low, int16_t *high, + int width, int linesize, int plane) +{ + int i; + int16_t even, odd; + for (i = 0; i < width; i++) { + even = (low[i] - high[i])/2; + odd = (low[i] + high[i])/2; + output[i] = av_clip_uintp2(even, 10); + output[i + linesize] = av_clip_uintp2(odd, 10); + } +} static void horiz_filter(int16_t *output, int16_t *low, int16_t *high, int width) { @@ -295,6 +346,9 @@ static int cfhd_decode(AVCodecContext *avctx, void *data, int *got_frame, uint16_t data = bytestream2_get_be16(&gb); if (abs_tag8 >= 0x60 && abs_tag8 <= 0x6f) { av_log(avctx, AV_LOG_DEBUG, "large len %x\n", ((tagu & 0xff) << 16) | data); + } else if (tag == SampleFlags) { + av_log(avctx, AV_LOG_DEBUG, "Progressive?%"PRIu16"\n", data); + s->progressive = data & 0x0001; } else if (tag == ImageWidth) { av_log(avctx, AV_LOG_DEBUG, "Width %"PRIu16"\n", data); s->coded_width = data; @@ -393,6 +447,8 @@ static int cfhd_decode(AVCodecContext *avctx, void *data, int *got_frame, } av_log(avctx, AV_LOG_DEBUG, "Transform-type? %"PRIu16"\n", data); } else if (abstag >= 0x4000 && abstag <= 0x40ff) { + if (abstag == 0x4001) + s->peak.level = 0; av_log(avctx, AV_LOG_DEBUG, "Small chunk length %d %s\n", data * 4, tag < 0 ? "optional" : "required"); bytestream2_skipu(&gb, data * 4); } else if (tag == 23) { @@ -450,7 +506,8 @@ static int cfhd_decode(AVCodecContext *avctx, void *data, int *got_frame, s->codebook = data; av_log(avctx, AV_LOG_DEBUG, "Codebook %i\n", s->codebook); } else if (tag == 72) { - s->codebook = data; + s->codebook = data & 0xf; + s->difference_coding = (data >> 4) & 1; av_log(avctx, AV_LOG_DEBUG, "Other codebook? %i\n", s->codebook); } else if (tag == 70) { av_log(avctx, AV_LOG_DEBUG, "Subsampling or bit-depth flag? %i\n", data); @@ -477,6 +534,19 @@ static int cfhd_decode(AVCodecContext *avctx, void *data, int *got_frame, } else if (tag == -85) { av_log(avctx, AV_LOG_DEBUG, "Cropped height %"PRIu16"\n", data); s->cropped_height = data; + } else if (tag == -75) { + s->peak.offset &= ~0xffff; + s->peak.offset |= (data & 0xffff); + s->peak.base = gb; + s->peak.level = 0; + } else if (tag == -76) { + s->peak.offset &= 0xffff; + s->peak.offset |= (data & 0xffffU)<<16; + s->peak.base = gb; + s->peak.level = 0; + } else if (tag == -74 && s->peak.offset) { + s->peak.level = data; + bytestream2_seek(&s->peak.base, s->peak.offset - 4, SEEK_CUR); } else av_log(avctx, AV_LOG_DEBUG, "Unknown tag %i data %x\n", tag, data); @@ -594,7 +664,7 @@ static int cfhd_decode(AVCodecContext *avctx, void *data, int *got_frame, if (count > expected) break; - coeff = dequant_and_decompand(level, s->quantisation); + coeff = dequant_and_decompand(level, s->quantisation, 0); for (i = 0; i < run; i++) *coeff_data++ = coeff; } @@ -613,7 +683,7 @@ static int cfhd_decode(AVCodecContext *avctx, void *data, int *got_frame, if (count > expected) break; - coeff = dequant_and_decompand(level, s->quantisation); + coeff = dequant_and_decompand(level, s->quantisation, s->codebook); for (i = 0; i < run; i++) *coeff_data++ = coeff; } @@ -626,8 +696,12 @@ static int cfhd_decode(AVCodecContext *avctx, void *data, int *got_frame, ret = AVERROR(EINVAL); goto end; } + if (s->peak.level) + peak_table(coeff_data - count, &s->peak, count); + if (s->difference_coding) + difference_coding(s->plane[s->channel_num].subband[s->subband_num_actual], highpass_width, highpass_height); - bytes = FFALIGN(FF_CEIL_RSHIFT(get_bits_count(&s->gb), 3), 4); + bytes = FFALIGN(AV_CEIL_RSHIFT(get_bits_count(&s->gb), 3), 4); if (bytes > bytestream2_get_bytes_left(&gb)) { av_log(avctx, AV_LOG_ERROR, "Bitstream overread error\n"); ret = AVERROR(EINVAL); @@ -784,37 +858,70 @@ static int cfhd_decode(AVCodecContext *avctx, void *data, int *got_frame, } av_log(avctx, AV_LOG_DEBUG, "Level 3 plane %i %i %i %i\n", plane, lowpass_height, lowpass_width, highpass_stride); + if (s->progressive) { + low = s->plane[plane].subband[0]; + high = s->plane[plane].subband[8]; + output = s->plane[plane].l_h[6]; + for (i = 0; i < lowpass_width; i++) { + vert_filter(output, lowpass_width, low, lowpass_width, high, highpass_stride, lowpass_height); + low++; + high++; + output++; + } - low = s->plane[plane].subband[0]; - high = s->plane[plane].subband[8]; - output = s->plane[plane].l_h[6]; - for (i = 0; i < lowpass_width; i++) { - vert_filter(output, lowpass_width, low, lowpass_width, high, highpass_stride, lowpass_height); - low++; - high++; - output++; - } + low = s->plane[plane].subband[7]; + high = s->plane[plane].subband[9]; + output = s->plane[plane].l_h[7]; + for (i = 0; i < lowpass_width; i++) { + vert_filter(output, lowpass_width, low, highpass_stride, high, highpass_stride, lowpass_height); + low++; + high++; + output++; + } - low = s->plane[plane].subband[7]; - high = s->plane[plane].subband[9]; - output = s->plane[plane].l_h[7]; - for (i = 0; i < lowpass_width; i++) { - vert_filter(output, lowpass_width, low, highpass_stride, high, highpass_stride, lowpass_height); - low++; - high++; - output++; - } + dst = (int16_t *)pic->data[act_plane]; + low = s->plane[plane].l_h[6]; + high = s->plane[plane].l_h[7]; + for (i = 0; i < lowpass_height * 2; i++) { + horiz_filter_clip(dst, low, high, lowpass_width, s->bpc); + if (avctx->pix_fmt == AV_PIX_FMT_GBRAP12 && act_plane == 3) + process_alpha(dst, lowpass_width * 2); + low += lowpass_width; + high += lowpass_width; + dst += pic->linesize[act_plane] / 2; + } + } else { + av_log(avctx, AV_LOG_DEBUG, "interlaced frame ? %d", pic->interlaced_frame); + pic->interlaced_frame = 1; + low = s->plane[plane].subband[0]; + high = s->plane[plane].subband[7]; + output = s->plane[plane].l_h[6]; + for (i = 0; i < lowpass_height; i++) { + horiz_filter(output, low, high, lowpass_width); + low += lowpass_width; + high += lowpass_width; + output += lowpass_width * 2; + } - dst = (int16_t *)pic->data[act_plane]; - low = s->plane[plane].l_h[6]; - high = s->plane[plane].l_h[7]; - for (i = 0; i < lowpass_height * 2; i++) { - horiz_filter_clip(dst, low, high, lowpass_width, s->bpc); - if (act_plane == 3) - process_alpha(dst, lowpass_width * 2); - low += lowpass_width; - high += lowpass_width; - dst += pic->linesize[act_plane] / 2; + low = s->plane[plane].subband[8]; + high = s->plane[plane].subband[9]; + output = s->plane[plane].l_h[7]; + for (i = 0; i < lowpass_height; i++) { + horiz_filter(output, low, high, lowpass_width); + low += lowpass_width; + high += lowpass_width; + output += lowpass_width * 2; + } + + dst = (int16_t *)pic->data[act_plane]; + low = s->plane[plane].l_h[6]; + high = s->plane[plane].l_h[7]; + for (i = 0; i < lowpass_height; i++) { + interlaced_vertical_filter(dst, low, high, lowpass_width * 2, pic->linesize[act_plane]/2, act_plane); + low += lowpass_width * 2; + high += lowpass_width * 2; + dst += pic->linesize[act_plane]; + } } } diff --git a/libavcodec/cfhd.h b/libavcodec/cfhd.h index 2573e750a..4f2c82d8b 100644 --- a/libavcodec/cfhd.h +++ b/libavcodec/cfhd.h @@ -26,6 +26,7 @@ #include "libavutil/avassert.h" #include "avcodec.h" +#include "bytestream.h" #include "get_bits.h" #include "vlc.h" @@ -68,6 +69,12 @@ typedef struct Plane { SubBand band[DWT_LEVELS][4]; } Plane; +typedef struct Peak { + int level; + int offset; + GetByteContext base; +} Peak; + typedef struct CFHDContext { AVCodecContext *avctx; @@ -83,6 +90,7 @@ typedef struct CFHDContext { int coded_height; int cropped_height; enum AVPixelFormat coded_format; + int progressive; int a_width; int a_height; @@ -98,12 +106,14 @@ typedef struct CFHDContext { int pshift; int codebook; + int difference_coding; int subband_num; int level; int subband_num_actual; uint8_t prescale_shift[3]; Plane plane[4]; + Peak peak; } CFHDContext; int ff_cfhd_init_vlcs(CFHDContext *s); diff --git a/libavcodec/cinepak.c b/libavcodec/cinepak.c index 9b0077402..aeb15de0e 100644 --- a/libavcodec/cinepak.c +++ b/libavcodec/cinepak.c @@ -323,6 +323,9 @@ static int cinepak_predecode_check (CinepakContext *s) num_strips = AV_RB16 (&s->data[8]); encoded_buf_size = AV_RB24(&s->data[1]); + if (s->size < encoded_buf_size * (int64_t)(100 - s->avctx->discard_damaged_percentage) / 100) + return AVERROR_INVALIDDATA; + /* if this is the first frame, check for deviant Sega FILM data */ if (s->sega_film_skip_bytes == -1) { if (!encoded_buf_size) { @@ -353,6 +356,13 @@ static int cinepak_predecode_check (CinepakContext *s) if (s->size < 10 + s->sega_film_skip_bytes + num_strips * 12) return AVERROR_INVALIDDATA; + if (num_strips) { + const uint8_t *data = s->data + 10 + s->sega_film_skip_bytes; + int strip_size = AV_RB24 (data + 1); + if (strip_size < 12 || strip_size > encoded_buf_size) + return AVERROR_INVALIDDATA; + } + return 0; } diff --git a/libavcodec/clearvideo.c b/libavcodec/clearvideo.c index a533613a3..26cdfb273 100644 --- a/libavcodec/clearvideo.c +++ b/libavcodec/clearvideo.c @@ -516,11 +516,8 @@ static int clv_decode_frame(AVCodecContext *avctx, void *data, frame_type = bytestream2_get_byte(&gb); if ((frame_type & 0x7f) == 0x30) { - if ((ret = ff_reget_buffer(avctx, c->pic)) < 0) - return ret; - - c->pic->key_frame = 0; - c->pic->pict_type = AV_PICTURE_TYPE_P; + *got_frame = 0; + return buf_size; } else if (frame_type & 0x2) { if (buf_size < c->mb_width * c->mb_height) { av_log(avctx, AV_LOG_ERROR, "Packet too small\n"); @@ -645,6 +642,9 @@ static int clv_decode_frame(AVCodecContext *avctx, void *data, *got_frame = 1; + if (get_bits_left(&c->gb) < 0) + av_log(c->avctx, AV_LOG_WARNING, "overread %d\n", -get_bits_left(&c->gb)); + return mb_ret < 0 ? mb_ret : buf_size; } @@ -665,7 +665,7 @@ static av_cold int clv_decode_init(AVCodecContext *avctx) } c->tile_shift = av_log2(c->tile_size); - if (1 << c->tile_shift != c->tile_size) { + if (1U << c->tile_shift != c->tile_size) { av_log(avctx, AV_LOG_ERROR, "Tile size: %d, is not power of 2.\n", c->tile_size); return AVERROR_INVALIDDATA; } diff --git a/libavcodec/cngdec.c b/libavcodec/cngdec.c index 28432ac71..43b96fea1 100644 --- a/libavcodec/cngdec.c +++ b/libavcodec/cngdec.c @@ -69,7 +69,6 @@ static av_cold int cng_decode_init(AVCodecContext *avctx) p->excitation = av_mallocz_array(avctx->frame_size, sizeof(*p->excitation)); if (!p->refl_coef || !p->target_refl_coef || !p->lpc_coef || !p->filter_out || !p->excitation) { - cng_decode_close(avctx); return AVERROR(ENOMEM); } @@ -175,4 +174,6 @@ AVCodec ff_comfortnoise_decoder = { .sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_NONE }, .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_DR1, + .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE | + FF_CODEC_CAP_INIT_CLEANUP, }; diff --git a/libavcodec/codec_desc.c b/libavcodec/codec_desc.c index 79552a910..4d033c20f 100644 --- a/libavcodec/codec_desc.c +++ b/libavcodec/codec_desc.c @@ -81,6 +81,7 @@ static const AVCodecDescriptor codec_descriptors[] = { .long_name = NULL_IF_CONFIG_SMALL("Motion JPEG"), .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, .mime_types= MT("image/jpeg"), + .profiles = NULL_IF_CONFIG_SMALL(ff_mjpeg_profiles), }, { .id = AV_CODEC_ID_MJPEGB, @@ -722,7 +723,7 @@ static const AVCodecDescriptor codec_descriptors[] = { .id = AV_CODEC_ID_GIF, .type = AVMEDIA_TYPE_VIDEO, .name = "gif", - .long_name = NULL_IF_CONFIG_SMALL("GIF (Graphics Interchange Format)"), + .long_name = NULL_IF_CONFIG_SMALL("CompuServe GIF (Graphics Interchange Format)"), .props = AV_CODEC_PROP_LOSSLESS, .mime_types= MT("image/gif"), }, @@ -1077,6 +1078,7 @@ static const AVCodecDescriptor codec_descriptors[] = { .name = "prores", .long_name = NULL_IF_CONFIG_SMALL("Apple ProRes (iCodec Pro)"), .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, + .profiles = NULL_IF_CONFIG_SMALL(ff_prores_profiles), }, { .id = AV_CODEC_ID_JV, @@ -1394,6 +1396,13 @@ static const AVCodecDescriptor codec_descriptors[] = { .long_name = NULL_IF_CONFIG_SMALL("innoHeim/Rsupport Screen Capture Codec"), .props = AV_CODEC_PROP_LOSSLESS, }, + { + .id = AV_CODEC_ID_AVS2, + .type = AVMEDIA_TYPE_VIDEO, + .name = "avs2", + .long_name = NULL_IF_CONFIG_SMALL("AVS2-P2/IEEE1857.4"), + .props = AV_CODEC_PROP_LOSSY, + }, { .id = AV_CODEC_ID_Y41P, .type = AVMEDIA_TYPE_VIDEO, @@ -1516,7 +1525,7 @@ static const AVCodecDescriptor codec_descriptors[] = { .type = AVMEDIA_TYPE_VIDEO, .name = "truemotion2rt", .long_name = NULL_IF_CONFIG_SMALL("Duck TrueMotion 2.0 Real Time"), - .props = AV_CODEC_PROP_LOSSY, + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, }, { .id = AV_CODEC_ID_M101, @@ -1647,6 +1656,76 @@ static const AVCodecDescriptor codec_descriptors[] = { .long_name = NULL_IF_CONFIG_SMALL("FITS (Flexible Image Transport System)"), .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, }, + { + .id = AV_CODEC_ID_IMM4, + .type = AVMEDIA_TYPE_VIDEO, + .name = "imm4", + .long_name = NULL_IF_CONFIG_SMALL("Infinity IMM4"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_PROSUMER, + .type = AVMEDIA_TYPE_VIDEO, + .name = "prosumer", + .long_name = NULL_IF_CONFIG_SMALL("Brooktree ProSumer Video"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_MWSC, + .type = AVMEDIA_TYPE_VIDEO, + .name = "mwsc", + .long_name = NULL_IF_CONFIG_SMALL("MatchWare Screen Capture Codec"), + .props = AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_WCMV, + .type = AVMEDIA_TYPE_VIDEO, + .name = "wcmv", + .long_name = NULL_IF_CONFIG_SMALL("WinCAM Motion Video"), + .props = AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_RASC, + .type = AVMEDIA_TYPE_VIDEO, + .name = "rasc", + .long_name = NULL_IF_CONFIG_SMALL("RemotelyAnywhere Screen Capture"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_HYMT, + .type = AVMEDIA_TYPE_VIDEO, + .name = "hymt", + .long_name = NULL_IF_CONFIG_SMALL("HuffYUV MT"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_ARBC, + .type = AVMEDIA_TYPE_VIDEO, + .name = "arbc", + .long_name = NULL_IF_CONFIG_SMALL("Gryphon's Anim Compressor"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_AGM, + .type = AVMEDIA_TYPE_VIDEO, + .name = "agm", + .long_name = NULL_IF_CONFIG_SMALL("Amuse Graphics Movie"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_LSCR, + .type = AVMEDIA_TYPE_VIDEO, + .name = "lscr", + .long_name = NULL_IF_CONFIG_SMALL("LEAD Screen Capture"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_VP4, + .type = AVMEDIA_TYPE_VIDEO, + .name = "vp4", + .long_name = NULL_IF_CONFIG_SMALL("On2 VP4"), + .props = AV_CODEC_PROP_LOSSY, + }, /* various PCM "codecs" */ { @@ -1894,6 +1973,13 @@ static const AVCodecDescriptor codec_descriptors[] = { .long_name = NULL_IF_CONFIG_SMALL("PCM 24.0 floating point little-endian"), .props = AV_CODEC_PROP_LOSSLESS, }, + { + .id = AV_CODEC_ID_PCM_VIDC, + .type = AVMEDIA_TYPE_AUDIO, + .name = "pcm_vidc", + .long_name = NULL_IF_CONFIG_SMALL("PCM Archimedes VIDC"), + .props = AV_CODEC_PROP_LOSSY, + }, /* various ADPCM codecs */ { @@ -2183,6 +2269,13 @@ static const AVCodecDescriptor codec_descriptors[] = { .long_name = NULL_IF_CONFIG_SMALL("ADPCM MTAF"), .props = AV_CODEC_PROP_LOSSY, }, + { + .id = AV_CODEC_ID_ADPCM_AGM, + .type = AVMEDIA_TYPE_AUDIO, + .name = "adpcm_agm", + .long_name = NULL_IF_CONFIG_SMALL("ADPCM AmuseGraphics Movie AGM"), + .props = AV_CODEC_PROP_LOSSY, + }, /* AMR */ { @@ -2878,6 +2971,20 @@ static const AVCodecDescriptor codec_descriptors[] = { .long_name = NULL_IF_CONFIG_SMALL("SBC (low-complexity subband codec)"), .props = AV_CODEC_PROP_LOSSY, }, + { + .id = AV_CODEC_ID_ATRAC9, + .type = AVMEDIA_TYPE_AUDIO, + .name = "atrac9", + .long_name = NULL_IF_CONFIG_SMALL("ATRAC9 (Adaptive TRansform Acoustic Coding 9)"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_HCOM, + .type = AVMEDIA_TYPE_AUDIO, + .name = "hcom", + .long_name = NULL_IF_CONFIG_SMALL("HCOM Audio"), + .props = AV_CODEC_PROP_LOSSY, + }, /* subtitle codecs */ { @@ -3047,6 +3154,21 @@ static const AVCodecDescriptor codec_descriptors[] = { .long_name = NULL_IF_CONFIG_SMALL("HDMV Text subtitle"), .props = AV_CODEC_PROP_TEXT_SUB, }, + { + .id = AV_CODEC_ID_TTML, + .type = AVMEDIA_TYPE_SUBTITLE, + .name = "ttml", + .long_name = NULL_IF_CONFIG_SMALL("Timed Text Markup Language"), + .props = AV_CODEC_PROP_TEXT_SUB, + }, + { + .id = AV_CODEC_ID_ARIB_CAPTION, + .type = AVMEDIA_TYPE_SUBTITLE, + .name = "arib_caption", + .long_name = NULL_IF_CONFIG_SMALL("ARIB STD-B24 caption"), + .props = AV_CODEC_PROP_TEXT_SUB, + .profiles = NULL_IF_CONFIG_SMALL(ff_arib_caption_profiles), + }, /* other kind of codecs and pseudo-codecs */ { diff --git a/libavcodec/cook.c b/libavcodec/cook.c index 53cb83852..c5f68c98b 100644 --- a/libavcodec/cook.c +++ b/libavcodec/cook.c @@ -1282,6 +1282,7 @@ AVCodec ff_cook_decoder = { .close = cook_decode_close, .decode = cook_decode_frame, .capabilities = AV_CODEC_CAP_DR1, + .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, .sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_NONE }, }; diff --git a/libavcodec/cookdata.h b/libavcodec/cookdata.h index dcdb912dd..efb8a5394 100644 --- a/libavcodec/cookdata.h +++ b/libavcodec/cookdata.h @@ -453,12 +453,13 @@ static const uint16_t ccpl_huffcodes5[31] = { }; static const uint16_t ccpl_huffcodes6[63] = { - 0x0004,0x0005,0x0005,0x0006,0x0006,0x0007,0x0007,0x0007,0x0007,0x0008,0x0008,0x0008, - 0x0008,0x0009,0x0009,0x0009,0x0009,0x000a,0x000a,0x000a,0x000a,0x000a,0x000b,0x000b, - 0x000b,0x000b,0x000c,0x000d,0x000e,0x000e,0x0010,0x0000,0x000a,0x0018,0x0019,0x0036, - 0x0037,0x0074,0x0075,0x0076,0x0077,0x00f4,0x00f5,0x00f6,0x00f7,0x01f5,0x01f6,0x01f7, - 0x01f8,0x03f6,0x03f7,0x03f8,0x03f9,0x03fa,0x07fa,0x07fb,0x07fc,0x07fd,0x0ffd,0x1ffd, - 0x3ffd,0x3ffe,0xffff, + 0xfffe, 0x7ffe, 0x3ffc, 0x1ffc, 0x0ffc, 0x07f6, 0x07f7, 0x07f8, 0x07f9, + 0x03f2, 0x03f3, 0x03f4, 0x03f5, 0x01f0, 0x01f1, 0x01f2, 0x01f3, 0x01f4, + 0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x0070, 0x0071, 0x0072, 0x0073, 0x0034, + 0x0035, 0x0016, 0x0017, 0x0004, 0x0000, 0x000a, 0x0018, 0x0019, 0x0036, + 0x0037, 0x0074, 0x0075, 0x0076, 0x0077, 0x00f4, 0x00f5, 0x00f6, 0x00f7, + 0x01f5, 0x01f6, 0x01f7, 0x01f8, 0x03f6, 0x03f7, 0x03f8, 0x03f9, 0x03fa, + 0x07fa, 0x07fb, 0x07fc, 0x07fd, 0x0ffd, 0x1ffd, 0x3ffd, 0x3ffe, 0xffff }; static const uint8_t ccpl_huffbits2[3] = { diff --git a/libavcodec/cpia.c b/libavcodec/cpia.c index 58833b2f2..f6d733260 100644 --- a/libavcodec/cpia.c +++ b/libavcodec/cpia.c @@ -63,7 +63,7 @@ static int cpia_decode_frame(AVCodecContext *avctx, uint8_t *y, *u, *v, *y_end, *u_end, *v_end; // Check header - if ( avpkt->size < FRAME_HEADER_SIZE + if ( avpkt->size < FRAME_HEADER_SIZE + avctx->height * 3 || header[0] != MAGIC_0 || header[1] != MAGIC_1 || (header[17] != SUBSAMPLE_420 && header[17] != SUBSAMPLE_422) || (header[18] != YUVORDER_YUYV && header[18] != YUVORDER_UYVY) diff --git a/libavcodec/cscd.c b/libavcodec/cscd.c index 5eb511a56..8781df110 100644 --- a/libavcodec/cscd.c +++ b/libavcodec/cscd.c @@ -38,7 +38,8 @@ typedef struct CamStudioContext { } CamStudioContext; static void copy_frame_default(AVFrame *f, const uint8_t *src, - int linelen, int height) { + int linelen, int height) +{ int i, src_stride = FFALIGN(linelen, 4); uint8_t *dst = f->data[0]; dst += (height - 1) * f->linesize[0]; @@ -50,7 +51,8 @@ static void copy_frame_default(AVFrame *f, const uint8_t *src, } static void add_frame_default(AVFrame *f, const uint8_t *src, - int linelen, int height) { + int linelen, int height) +{ int i, j, src_stride = FFALIGN(linelen, 4); uint8_t *dst = f->data[0]; dst += (height - 1) * f->linesize[0]; @@ -63,7 +65,8 @@ static void add_frame_default(AVFrame *f, const uint8_t *src, } static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, - AVPacket *avpkt) { + AVPacket *avpkt) +{ const uint8_t *buf = avpkt->data; int buf_size = avpkt->size; CamStudioContext *c = avctx->priv_data; @@ -79,30 +82,30 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, // decompress data switch ((buf[0] >> 1) & 7) { - case 0: { // lzo compression - int outlen = c->decomp_size, inlen = buf_size - 2; - if (av_lzo1x_decode(c->decomp_buf, &outlen, &buf[2], &inlen) || outlen) { - av_log(avctx, AV_LOG_ERROR, "error during lzo decompression\n"); - return AVERROR_INVALIDDATA; - } - break; - } - case 1: { // zlib compression -#if CONFIG_ZLIB - unsigned long dlen = c->decomp_size; - if (uncompress(c->decomp_buf, &dlen, &buf[2], buf_size - 2) != Z_OK) { - av_log(avctx, AV_LOG_ERROR, "error during zlib decompression\n"); - return AVERROR_INVALIDDATA; - } - break; -#else - av_log(avctx, AV_LOG_ERROR, "compiled without zlib support\n"); - return AVERROR(ENOSYS); -#endif - } - default: - av_log(avctx, AV_LOG_ERROR, "unknown compression\n"); + case 0: { // lzo compression + int outlen = c->decomp_size, inlen = buf_size - 2; + if (av_lzo1x_decode(c->decomp_buf, &outlen, &buf[2], &inlen) || outlen) { + av_log(avctx, AV_LOG_ERROR, "error during lzo decompression\n"); return AVERROR_INVALIDDATA; + } + break; + } + case 1: { // zlib compression +#if CONFIG_ZLIB + unsigned long dlen = c->decomp_size; + if (uncompress(c->decomp_buf, &dlen, &buf[2], buf_size - 2) != Z_OK) { + av_log(avctx, AV_LOG_ERROR, "error during zlib decompression\n"); + return AVERROR_INVALIDDATA; + } + break; +#else + av_log(avctx, AV_LOG_ERROR, "compiled without zlib support\n"); + return AVERROR(ENOSYS); +#endif + } + default: + av_log(avctx, AV_LOG_ERROR, "unknown compression\n"); + return AVERROR_INVALIDDATA; } // flip upside down, add difference frame @@ -125,18 +128,19 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, return buf_size; } -static av_cold int decode_init(AVCodecContext *avctx) { +static av_cold int decode_init(AVCodecContext *avctx) +{ CamStudioContext *c = avctx->priv_data; int stride; switch (avctx->bits_per_coded_sample) { - case 16: avctx->pix_fmt = AV_PIX_FMT_RGB555LE; break; - case 24: avctx->pix_fmt = AV_PIX_FMT_BGR24; break; - case 32: avctx->pix_fmt = AV_PIX_FMT_BGR0; break; - default: - av_log(avctx, AV_LOG_ERROR, - "CamStudio codec error: invalid depth %i bpp\n", - avctx->bits_per_coded_sample); - return AVERROR_INVALIDDATA; + case 16: avctx->pix_fmt = AV_PIX_FMT_RGB555LE; break; + case 24: avctx->pix_fmt = AV_PIX_FMT_BGR24; break; + case 32: avctx->pix_fmt = AV_PIX_FMT_BGR0; break; + default: + av_log(avctx, AV_LOG_ERROR, + "CamStudio codec error: invalid depth %i bpp\n", + avctx->bits_per_coded_sample); + return AVERROR_INVALIDDATA; } c->bpp = avctx->bits_per_coded_sample; c->linelen = avctx->width * avctx->bits_per_coded_sample / 8; @@ -154,7 +158,8 @@ static av_cold int decode_init(AVCodecContext *avctx) { return 0; } -static av_cold int decode_end(AVCodecContext *avctx) { +static av_cold int decode_end(AVCodecContext *avctx) +{ CamStudioContext *c = avctx->priv_data; av_freep(&c->decomp_buf); av_frame_free(&c->pic); @@ -170,5 +175,6 @@ AVCodec ff_cscd_decoder = { .init = decode_init, .close = decode_end, .decode = decode_frame, + .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, .capabilities = AV_CODEC_CAP_DR1, }; diff --git a/libavcodec/cuviddec.c b/libavcodec/cuviddec.c index 38623806f..acee78cf2 100644 --- a/libavcodec/cuviddec.c +++ b/libavcodec/cuviddec.c @@ -25,6 +25,7 @@ #include "libavutil/mathematics.h" #include "libavutil/hwcontext.h" #include "libavutil/hwcontext_cuda_internal.h" +#include "libavutil/cuda_check.h" #include "libavutil/fifo.h" #include "libavutil/log.h" #include "libavutil/opt.h" @@ -33,8 +34,14 @@ #include "avcodec.h" #include "decode.h" #include "hwaccel.h" +#include "nvdec.h" #include "internal.h" +#if !NVDECAPI_CHECK_VERSION(9, 0) +#define cudaVideoSurfaceFormat_YUV444 2 +#define cudaVideoSurfaceFormat_YUV444_16Bit 3 +#endif + typedef struct CuvidContext { AVClass *avclass; @@ -70,6 +77,7 @@ typedef struct CuvidContext int deint_mode; int deint_mode_current; int64_t prev_pts; + int progressive_sequence; int internal_error; int decoder_flushing; @@ -95,29 +103,7 @@ typedef struct CuvidParsedFrame int is_deinterlacing; } CuvidParsedFrame; -static int check_cu(AVCodecContext *avctx, CUresult err, const char *func) -{ - CuvidContext *ctx = avctx->priv_data; - const char *err_name; - const char *err_string; - - av_log(avctx, AV_LOG_TRACE, "Calling %s\n", func); - - if (err == CUDA_SUCCESS) - return 0; - - ctx->cudl->cuGetErrorName(err, &err_name); - ctx->cudl->cuGetErrorString(err, &err_string); - - av_log(avctx, AV_LOG_ERROR, "%s failed", func); - if (err_name && err_string) - av_log(avctx, AV_LOG_ERROR, " -> %s: %s", err_name, err_string); - av_log(avctx, AV_LOG_ERROR, "\n"); - - return AVERROR_EXTERNAL; -} - -#define CHECK_CU(x) check_cu(avctx, (x), #x) +#define CHECK_CU(x) FF_CUDA_CHECK_DL(avctx, ctx->cudl, x) static int CUDAAPI cuvid_handle_video_sequence(void *opaque, CUVIDEOFORMAT* format) { @@ -127,6 +113,7 @@ static int CUDAAPI cuvid_handle_video_sequence(void *opaque, CUVIDEOFORMAT* form CUVIDDECODECAPS *caps = NULL; CUVIDDECODECREATEINFO cuinfo; int surface_fmt; + int chroma_444; int old_width = avctx->width; int old_height = avctx->height; @@ -169,17 +156,19 @@ static int CUDAAPI cuvid_handle_video_sequence(void *opaque, CUVIDEOFORMAT* form cuinfo.target_rect.right = cuinfo.ulTargetWidth; cuinfo.target_rect.bottom = cuinfo.ulTargetHeight; + chroma_444 = format->chroma_format == cudaVideoChromaFormat_444; + switch (format->bit_depth_luma_minus8) { case 0: // 8-bit - pix_fmts[1] = AV_PIX_FMT_NV12; + pix_fmts[1] = chroma_444 ? AV_PIX_FMT_YUV444P : AV_PIX_FMT_NV12; caps = &ctx->caps8; break; case 2: // 10-bit - pix_fmts[1] = AV_PIX_FMT_P010; + pix_fmts[1] = chroma_444 ? AV_PIX_FMT_YUV444P16 : AV_PIX_FMT_P010; caps = &ctx->caps10; break; case 4: // 12-bit - pix_fmts[1] = AV_PIX_FMT_P016; + pix_fmts[1] = chroma_444 ? AV_PIX_FMT_YUV444P16 : AV_PIX_FMT_P016; caps = &ctx->caps12; break; default: @@ -228,6 +217,8 @@ static int CUDAAPI cuvid_handle_video_sequence(void *opaque, CUVIDEOFORMAT* form ? cudaVideoDeinterlaceMode_Weave : ctx->deint_mode; + ctx->progressive_sequence = format->progressive_sequence; + if (!format->progressive_sequence && ctx->deint_mode_current == cudaVideoDeinterlaceMode_Weave) avctx->flags |= AV_CODEC_FLAG_INTERLACED_DCT; else @@ -282,12 +273,6 @@ static int CUDAAPI cuvid_handle_video_sequence(void *opaque, CUVIDEOFORMAT* form return 0; } - if (format->chroma_format != cudaVideoChromaFormat_420) { - av_log(avctx, AV_LOG_ERROR, "Chroma formats other than 420 are not supported\n"); - ctx->internal_error = AVERROR(EINVAL); - return 0; - } - ctx->chroma_format = format->chroma_format; cuinfo.CodecType = ctx->codec_type = format->codec; @@ -301,8 +286,15 @@ static int CUDAAPI cuvid_handle_video_sequence(void *opaque, CUVIDEOFORMAT* form case AV_PIX_FMT_P016: cuinfo.OutputFormat = cudaVideoSurfaceFormat_P016; break; + case AV_PIX_FMT_YUV444P: + cuinfo.OutputFormat = cudaVideoSurfaceFormat_YUV444; + break; + case AV_PIX_FMT_YUV444P16: + cuinfo.OutputFormat = cudaVideoSurfaceFormat_YUV444_16Bit; + break; default: - av_log(avctx, AV_LOG_ERROR, "Output formats other than NV12, P010 or P016 are not supported\n"); + av_log(avctx, AV_LOG_ERROR, "Unsupported output format: %s\n", + av_get_pix_fmt_name(avctx->sw_pix_fmt)); ctx->internal_error = AVERROR(EINVAL); return 0; } @@ -360,6 +352,9 @@ static int CUDAAPI cuvid_handle_picture_display(void *opaque, CUVIDPARSERDISPINF parsed_frame.dispinfo = *dispinfo; ctx->internal_error = 0; + // For some reason, dispinfo->progressive_frame is sometimes wrong. + parsed_frame.dispinfo.progressive_frame = ctx->progressive_sequence; + if (ctx->deint_mode_current == cudaVideoDeinterlaceMode_Weave) { av_fifo_generic_write(ctx->frame_queue, &parsed_frame, sizeof(CuvidParsedFrame), NULL); } else { @@ -511,6 +506,7 @@ static int cuvid_output_frame(AVCodecContext *avctx, AVFrame *frame) return ret; if (av_fifo_size(ctx->frame_queue)) { + const AVPixFmtDescriptor *pixdesc; CuvidParsedFrame parsed_frame; CUVIDPROCPARAMS params; unsigned int pitch = 0; @@ -541,7 +537,10 @@ static int cuvid_output_frame(AVCodecContext *avctx, AVFrame *frame) goto error; } - for (i = 0; i < 2; i++) { + pixdesc = av_pix_fmt_desc_get(avctx->sw_pix_fmt); + + for (i = 0; i < pixdesc->nb_components; i++) { + int height = avctx->height >> (i ? pixdesc->log2_chroma_h : 0); CUDA_MEMCPY2D cpy = { .srcMemoryType = CU_MEMORYTYPE_DEVICE, .dstMemoryType = CU_MEMORYTYPE_DEVICE, @@ -551,18 +550,21 @@ static int cuvid_output_frame(AVCodecContext *avctx, AVFrame *frame) .dstPitch = frame->linesize[i], .srcY = offset, .WidthInBytes = FFMIN(pitch, frame->linesize[i]), - .Height = avctx->height >> (i ? 1 : 0), + .Height = height, }; - ret = CHECK_CU(ctx->cudl->cuMemcpy2D(&cpy)); + ret = CHECK_CU(ctx->cudl->cuMemcpy2DAsync(&cpy, device_hwctx->stream)); if (ret < 0) goto error; - offset += avctx->height; + offset += height; } - } else if (avctx->pix_fmt == AV_PIX_FMT_NV12 || - avctx->pix_fmt == AV_PIX_FMT_P010 || - avctx->pix_fmt == AV_PIX_FMT_P016) { + } else if (avctx->pix_fmt == AV_PIX_FMT_NV12 || + avctx->pix_fmt == AV_PIX_FMT_P010 || + avctx->pix_fmt == AV_PIX_FMT_P016 || + avctx->pix_fmt == AV_PIX_FMT_YUV444P || + avctx->pix_fmt == AV_PIX_FMT_YUV444P16) { + unsigned int offset = 0; AVFrame *tmp_frame = av_frame_alloc(); if (!tmp_frame) { av_log(avctx, AV_LOG_ERROR, "av_frame_alloc failed\n"); @@ -570,15 +572,24 @@ static int cuvid_output_frame(AVCodecContext *avctx, AVFrame *frame) goto error; } + pixdesc = av_pix_fmt_desc_get(avctx->sw_pix_fmt); + tmp_frame->format = AV_PIX_FMT_CUDA; tmp_frame->hw_frames_ctx = av_buffer_ref(ctx->hwframe); - tmp_frame->data[0] = (uint8_t*)mapped_frame; - tmp_frame->linesize[0] = pitch; - tmp_frame->data[1] = (uint8_t*)(mapped_frame + avctx->height * pitch); - tmp_frame->linesize[1] = pitch; tmp_frame->width = avctx->width; tmp_frame->height = avctx->height; + /* + * Note that the following logic would not work for three plane + * YUV420 because the pitch value is different for the chroma + * planes. + */ + for (i = 0; i < pixdesc->nb_components; i++) { + tmp_frame->data[i] = (uint8_t*)mapped_frame + offset; + tmp_frame->linesize[i] = pitch; + offset += pitch * (avctx->height >> (i ? pixdesc->log2_chroma_h : 0)); + } + ret = ff_get_buffer(avctx, frame, 0); if (ret < 0) { av_log(avctx, AV_LOG_ERROR, "ff_get_buffer failed\n"); @@ -794,6 +805,12 @@ static int cuvid_test_capabilities(AVCodecContext *avctx, return AVERROR(EINVAL); } + if ((probed_width * probed_height) / 256 > caps->nMaxMBCount) { + av_log(avctx, AV_LOG_ERROR, "Video macroblock count %d exceeds maximum of %d\n", + (int)(probed_width * probed_height) / 256, caps->nMaxMBCount); + return AVERROR(EINVAL); + } + return 0; } diff --git a/libavcodec/dcaenc.c b/libavcodec/dcaenc.c index 186997c63..34b3e9416 100644 --- a/libavcodec/dcaenc.c +++ b/libavcodec/dcaenc.c @@ -136,7 +136,7 @@ static int subband_bufer_alloc(DCAEncContext *c) (SUBBAND_SAMPLES + DCA_ADPCM_COEFFS), sizeof(int32_t)); if (!bufer) - return -1; + return AVERROR(ENOMEM); /* we need a place for DCA_ADPCM_COEFF samples from previous frame * to calc prediction coefficients for each subband */ @@ -152,8 +152,11 @@ static int subband_bufer_alloc(DCAEncContext *c) static void subband_bufer_free(DCAEncContext *c) { - int32_t *bufer = c->subband[0][0] - DCA_ADPCM_COEFFS; - av_freep(&bufer); + if (c->subband[0][0]) { + int32_t *bufer = c->subband[0][0] - DCA_ADPCM_COEFFS; + av_free(bufer); + c->subband[0][0] = NULL; + } } static int encode_init(AVCodecContext *avctx) @@ -163,8 +166,8 @@ static int encode_init(AVCodecContext *avctx) int i, j, k, min_frame_bits; int ret; - if (subband_bufer_alloc(c)) - return AVERROR(ENOMEM); + if ((ret = subband_bufer_alloc(c)) < 0) + return ret; c->fullband_channels = c->channels = avctx->channels; c->lfe_channel = (avctx->channels == 3 || avctx->channels == 6); diff --git a/libavcodec/dct.c b/libavcodec/dct.c index cca51eeaf..52f082d06 100644 --- a/libavcodec/dct.c +++ b/libavcodec/dct.c @@ -178,6 +178,7 @@ av_cold int ff_dct_init(DCTContext *s, int nbits, enum DCTTransformType inverse) { int n = 1 << nbits; int i; + int ret; memset(s, 0, sizeof(*s)); @@ -194,9 +195,9 @@ av_cold int ff_dct_init(DCTContext *s, int nbits, enum DCTTransformType inverse) if (!s->csc2) return AVERROR(ENOMEM); - if (ff_rdft_init(&s->rdft, nbits, inverse == DCT_III) < 0) { + if ((ret = ff_rdft_init(&s->rdft, nbits, inverse == DCT_III)) < 0) { av_freep(&s->csc2); - return -1; + return ret; } for (i = 0; i < n / 2; i++) diff --git a/libavcodec/dds.c b/libavcodec/dds.c index f026f9cd5..9154f692f 100644 --- a/libavcodec/dds.c +++ b/libavcodec/dds.c @@ -613,6 +613,7 @@ static int dds_decode(AVCodecContext *avctx, void *data, AVFrame *frame = data; int mipmap; int ret; + int width, height; ff_texturedsp_init(&ctx->texdsp); bytestream2_init(gbc, avpkt->data, avpkt->size); @@ -631,9 +632,9 @@ static int dds_decode(AVCodecContext *avctx, void *data, bytestream2_skip(gbc, 4); // flags - avctx->height = bytestream2_get_le32(gbc); - avctx->width = bytestream2_get_le32(gbc); - ret = av_image_check_size(avctx->width, avctx->height, 0, avctx); + height = bytestream2_get_le32(gbc); + width = bytestream2_get_le32(gbc); + ret = ff_set_dimensions(avctx, width, height); if (ret < 0) { av_log(avctx, AV_LOG_ERROR, "Invalid image size %dx%d.\n", avctx->width, avctx->height); diff --git a/libavcodec/decode.c b/libavcodec/decode.c index 421a8f1a3..6c31166ec 100644 --- a/libavcodec/decode.c +++ b/libavcodec/decode.c @@ -36,6 +36,7 @@ #include "libavutil/imgutils.h" #include "libavutil/internal.h" #include "libavutil/intmath.h" +#include "libavutil/opt.h" #include "avcodec.h" #include "bytestream.h" @@ -181,7 +182,7 @@ static int unrefcount_frame(AVCodecInternal *avci, AVFrame *frame) return 0; } -static int bsfs_init(AVCodecContext *avctx) +int ff_decode_bsfs_init(AVCodecContext *avctx) { AVCodecInternal *avci = avctx->internal; DecodeFilterContext *s = &avci->filter; @@ -195,27 +196,33 @@ static int bsfs_init(AVCodecContext *avctx) while (bsfs_str && *bsfs_str) { AVBSFContext **tmp; const AVBitStreamFilter *filter; - char *bsf; + char *bsf, *bsf_options_str, *bsf_name; bsf = av_get_token(&bsfs_str, ","); if (!bsf) { ret = AVERROR(ENOMEM); goto fail; } + bsf_name = av_strtok(bsf, "=", &bsf_options_str); + if (!bsf_name) { + av_freep(&bsf); + ret = AVERROR(ENOMEM); + goto fail; + } - filter = av_bsf_get_by_name(bsf); + filter = av_bsf_get_by_name(bsf_name); if (!filter) { av_log(avctx, AV_LOG_ERROR, "A non-existing bitstream filter %s " "requested by a decoder. This is a bug, please report it.\n", - bsf); - ret = AVERROR_BUG; + bsf_name); av_freep(&bsf); + ret = AVERROR_BUG; goto fail; } - av_freep(&bsf); tmp = av_realloc_array(s->bsfs, s->nb_bsfs + 1, sizeof(*s->bsfs)); if (!tmp) { + av_freep(&bsf); ret = AVERROR(ENOMEM); goto fail; } @@ -223,8 +230,10 @@ static int bsfs_init(AVCodecContext *avctx) s->nb_bsfs++; ret = av_bsf_alloc(filter, &s->bsfs[s->nb_bsfs - 1]); - if (ret < 0) + if (ret < 0) { + av_freep(&bsf); goto fail; + } if (s->nb_bsfs == 1) { /* We do not currently have an API for passing the input timebase into decoders, @@ -238,12 +247,38 @@ static int bsfs_init(AVCodecContext *avctx) ret = avcodec_parameters_copy(s->bsfs[s->nb_bsfs - 1]->par_in, s->bsfs[s->nb_bsfs - 2]->par_out); } - if (ret < 0) + if (ret < 0) { + av_freep(&bsf); goto fail; + } + + if (bsf_options_str && filter->priv_class) { + const AVOption *opt = av_opt_next(s->bsfs[s->nb_bsfs - 1]->priv_data, NULL); + const char * shorthand[2] = {NULL}; + + if (opt) + shorthand[0] = opt->name; + + ret = av_opt_set_from_string(s->bsfs[s->nb_bsfs - 1]->priv_data, bsf_options_str, shorthand, "=", ":"); + if (ret < 0) { + if (ret != AVERROR(ENOMEM)) { + av_log(avctx, AV_LOG_ERROR, "Invalid options for bitstream filter %s " + "requested by the decoder. This is a bug, please report it.\n", + bsf_name); + ret = AVERROR_BUG; + } + av_freep(&bsf); + goto fail; + } + } + av_freep(&bsf); ret = av_bsf_init(s->bsfs[s->nb_bsfs - 1]); if (ret < 0) goto fail; + + if (*bsfs_str) + bsfs_str++; } return 0; @@ -653,10 +688,6 @@ int attribute_align_arg avcodec_send_packet(AVCodecContext *avctx, const AVPacke if (avpkt && !avpkt->size && avpkt->data) return AVERROR(EINVAL); - ret = bsfs_init(avctx); - if (ret < 0) - return ret; - av_packet_unref(avci->buffer_pkt); if (avpkt && (avpkt->data || avpkt->side_data_elems)) { ret = av_packet_ref(avci->buffer_pkt, avpkt); @@ -709,17 +740,13 @@ static int apply_cropping(AVCodecContext *avctx, AVFrame *frame) int attribute_align_arg avcodec_receive_frame(AVCodecContext *avctx, AVFrame *frame) { AVCodecInternal *avci = avctx->internal; - int ret; + int ret, changed; av_frame_unref(frame); if (!avcodec_is_open(avctx) || !av_codec_is_decoder(avctx->codec)) return AVERROR(EINVAL); - ret = bsfs_init(avctx); - if (ret < 0) - return ret; - if (avci->buffer_frame->buf[0]) { av_frame_move_ref(frame, avci->buffer_frame); } else { @@ -738,6 +765,51 @@ int attribute_align_arg avcodec_receive_frame(AVCodecContext *avctx, AVFrame *fr avctx->frame_number++; + if (avctx->flags & AV_CODEC_FLAG_DROPCHANGED) { + + if (avctx->frame_number == 1) { + avci->initial_format = frame->format; + switch(avctx->codec_type) { + case AVMEDIA_TYPE_VIDEO: + avci->initial_width = frame->width; + avci->initial_height = frame->height; + break; + case AVMEDIA_TYPE_AUDIO: + avci->initial_sample_rate = frame->sample_rate ? frame->sample_rate : + avctx->sample_rate; + avci->initial_channels = frame->channels; + avci->initial_channel_layout = frame->channel_layout; + break; + } + } + + if (avctx->frame_number > 1) { + changed = avci->initial_format != frame->format; + + switch(avctx->codec_type) { + case AVMEDIA_TYPE_VIDEO: + changed |= avci->initial_width != frame->width || + avci->initial_height != frame->height; + break; + case AVMEDIA_TYPE_AUDIO: + changed |= avci->initial_sample_rate != frame->sample_rate || + avci->initial_sample_rate != avctx->sample_rate || + avci->initial_channels != frame->channels || + avci->initial_channel_layout != frame->channel_layout; + break; + } + + if (changed) { + avci->changed_frames_dropped++; + av_log(avctx, AV_LOG_INFO, "dropped changed frame #%d pts %"PRId64 + " drop count: %d \n", + avctx->frame_number, frame->pts, + avci->changed_frames_dropped); + av_frame_unref(frame); + return AVERROR_INPUT_CHANGED; + } + } + } return 0; } @@ -1351,6 +1423,7 @@ int ff_get_format(AVCodecContext *avctx, const enum AVPixelFormat *fmt) if (i == n) { av_log(avctx, AV_LOG_ERROR, "Invalid return from get_format(): " "%s not in possible list.\n", desc->name); + ret = AV_PIX_FMT_NONE; break; } @@ -1469,7 +1542,7 @@ static int update_frame_pool(AVCodecContext *avctx, AVFrame *frame) tmpsize = av_image_fill_pointers(data, avctx->pix_fmt, h, NULL, linesize); if (tmpsize < 0) - return -1; + return tmpsize; for (i = 0; i < 3 && data[i + 1]; i++) size[i] = data[i + 1] - data[i]; @@ -1837,7 +1910,7 @@ static int get_buffer_internal(AVCodecContext *avctx, AVFrame *frame, int flags) int ret; if (avctx->codec_type == AVMEDIA_TYPE_VIDEO) { - if ((ret = av_image_check_size2(avctx->width, avctx->height, avctx->max_pixels, AV_PIX_FMT_NONE, 0, avctx)) < 0 || avctx->pix_fmt<0) { + if ((ret = av_image_check_size2(FFALIGN(avctx->width, STRIDE_ALIGN), avctx->height, avctx->max_pixels, AV_PIX_FMT_NONE, 0, avctx)) < 0 || avctx->pix_fmt<0) { av_log(avctx, AV_LOG_ERROR, "video_get_buffer: image parameters invalid\n"); return AVERROR(EINVAL); } @@ -1943,6 +2016,14 @@ int ff_reget_buffer(AVCodecContext *avctx, AVFrame *frame) return ret; } +static void bsfs_flush(AVCodecContext *avctx) +{ + DecodeFilterContext *s = &avctx->internal->filter; + + for (int i = 0; i < s->nb_bsfs; i++) + av_bsf_flush(s->bsfs[i]); +} + void avcodec_flush_buffers(AVCodecContext *avctx) { avctx->internal->draining = 0; @@ -1963,7 +2044,7 @@ void avcodec_flush_buffers(AVCodecContext *avctx) avctx->pts_correction_last_pts = avctx->pts_correction_last_dts = INT64_MIN; - ff_decode_bsfs_uninit(avctx); + bsfs_flush(avctx); if (!avctx->refcounted_frames) av_frame_unref(avctx->internal->to_free); diff --git a/libavcodec/decode.h b/libavcodec/decode.h index 15271c529..c3e0e82f4 100644 --- a/libavcodec/decode.h +++ b/libavcodec/decode.h @@ -64,6 +64,8 @@ typedef struct FrameDecodeData { */ int ff_decode_get_packet(AVCodecContext *avctx, AVPacket *pkt); +int ff_decode_bsfs_init(AVCodecContext *avctx); + void ff_decode_bsfs_uninit(AVCodecContext *avctx); /** diff --git a/libavcodec/dirac_arith.c b/libavcodec/dirac_arith.c index 7eb9bd60b..36142fe19 100644 --- a/libavcodec/dirac_arith.c +++ b/libavcodec/dirac_arith.c @@ -115,6 +115,8 @@ void ff_dirac_init_arith_decoder(DiracArith *c, GetBitContext *gb, int length) c->counter = -16; c->range = 0xffff; + c->error = 0; + c->overread= 0; for (i = 0; i < DIRAC_CTX_COUNT; i++) c->contexts[i] = 0x8000; diff --git a/libavcodec/dirac_arith.h b/libavcodec/dirac_arith.h index 24a7ca390..79526a7ca 100644 --- a/libavcodec/dirac_arith.h +++ b/libavcodec/dirac_arith.h @@ -81,6 +81,8 @@ typedef struct { const uint8_t *bytestream_end; uint16_t contexts[DIRAC_CTX_COUNT]; + int error; + int overread; } DiracArith; extern const uint8_t ff_dirac_next_ctx[DIRAC_CTX_COUNT]; @@ -118,6 +120,9 @@ static inline void refill(DiracArith *c) new |= 0xff00; c->bytestream = c->bytestream_end; + c->overread ++; + if (c->overread > 4) + c->error = AVERROR_INVALIDDATA; } c->low += new << counter; @@ -173,6 +178,7 @@ static inline int dirac_get_arith_uint(DiracArith *c, int follow_ctx, int data_c while (!dirac_get_arith_bit(c, follow_ctx)) { if (ret >= 0x40000000) { av_log(NULL, AV_LOG_ERROR, "dirac_get_arith_uint overflow\n"); + c->error = AVERROR_INVALIDDATA; return -1; } ret <<= 1; diff --git a/libavcodec/dirac_parser.c b/libavcodec/dirac_parser.c index 1ade44a43..fbc7414c7 100644 --- a/libavcodec/dirac_parser.c +++ b/libavcodec/dirac_parser.c @@ -212,7 +212,7 @@ static int dirac_combine_frame(AVCodecParserContext *s, AVCodecContext *avctx, if (parse_timing_info && pu1.prev_pu_offset >= 13) { uint8_t *cur_pu = pc->buffer + pc->index - 13 - pu1.prev_pu_offset; - int pts = AV_RB32(cur_pu + 13); + int64_t pts = AV_RB32(cur_pu + 13); if (s->last_pts == 0 && s->last_dts == 0) s->dts = pts - 1; else diff --git a/libavcodec/diracdec.c b/libavcodec/diracdec.c index 37c976def..22ec913bf 100644 --- a/libavcodec/diracdec.c +++ b/libavcodec/diracdec.c @@ -488,7 +488,7 @@ UNPACK_ARITH(10, int32_t) * Decode the coeffs in the rectangle defined by left, right, top, bottom * [DIRAC_STD] 13.4.3.2 Codeblock unpacking loop. codeblock() */ -static inline void codeblock(DiracContext *s, SubBand *b, +static inline int codeblock(DiracContext *s, SubBand *b, GetBitContext *gb, DiracArith *c, int left, int right, int top, int bottom, int blockcnt_one, int is_arith) @@ -505,7 +505,7 @@ static inline void codeblock(DiracContext *s, SubBand *b, zero_block = get_bits1(gb); if (zero_block) - return; + return 0; } if (s->codeblock_mode && !(s->old_delta_quant && blockcnt_one)) { @@ -516,7 +516,7 @@ static inline void codeblock(DiracContext *s, SubBand *b, quant = dirac_get_se_golomb(gb); if (quant > INT_MAX - b->quant || b->quant + quant < 0) { av_log(s->avctx, AV_LOG_ERROR, "Invalid quant\n"); - return; + return AVERROR_INVALIDDATA; } b->quant += quant; } @@ -524,7 +524,7 @@ static inline void codeblock(DiracContext *s, SubBand *b, if (b->quant > (DIRAC_MAX_QUANT_INDEX - 1)) { av_log(s->avctx, AV_LOG_ERROR, "Unsupported quant %d\n", b->quant); b->quant = 0; - return; + return AVERROR_INVALIDDATA; } qfactor = ff_dirac_qscale_tab[b->quant]; @@ -537,6 +537,8 @@ static inline void codeblock(DiracContext *s, SubBand *b, buf = b->ibuf + top * b->stride; if (is_arith) { for (y = top; y < bottom; y++) { + if (c->error) + return c->error; for (x = left; x < right; x++) { if (b->pshift) { coeff_unpack_arith_10(c, qfactor, qoffset, b, (int32_t*)(buf)+x, x, y); @@ -548,6 +550,8 @@ static inline void codeblock(DiracContext *s, SubBand *b, } } else { for (y = top; y < bottom; y++) { + if (get_bits_left(gb) < 1) + return AVERROR_INVALIDDATA; for (x = left; x < right; x++) { int val = coeff_unpack_golomb(gb, qfactor, qoffset); if (b->pshift) { @@ -559,6 +563,7 @@ static inline void codeblock(DiracContext *s, SubBand *b, buf += b->stride; } } + return 0; } /** @@ -593,7 +598,7 @@ INTRA_DC_PRED(10, uint32_t) * Dirac Specification -> * 13.4.2 Non-skipped subbands. subband_coeffs() */ -static av_always_inline void decode_subband_internal(DiracContext *s, SubBand *b, int is_arith) +static av_always_inline int decode_subband_internal(DiracContext *s, SubBand *b, int is_arith) { int cb_x, cb_y, left, right, top, bottom; DiracArith c; @@ -601,9 +606,10 @@ static av_always_inline void decode_subband_internal(DiracContext *s, SubBand *b int cb_width = s->codeblock[b->level + (b->orientation != subband_ll)].width; int cb_height = s->codeblock[b->level + (b->orientation != subband_ll)].height; int blockcnt_one = (cb_width + cb_height) == 2; + int ret; if (!b->length) - return; + return 0; init_get_bits8(&gb, b->coeff_data, b->length); @@ -616,7 +622,9 @@ static av_always_inline void decode_subband_internal(DiracContext *s, SubBand *b left = 0; for (cb_x = 0; cb_x < cb_width; cb_x++) { right = (b->width * (cb_x+1LL)) / cb_width; - codeblock(s, b, &gb, &c, left, right, top, bottom, blockcnt_one, is_arith); + ret = codeblock(s, b, &gb, &c, left, right, top, bottom, blockcnt_one, is_arith); + if (ret < 0) + return ret; left = right; } top = bottom; @@ -629,33 +637,35 @@ static av_always_inline void decode_subband_internal(DiracContext *s, SubBand *b intra_dc_prediction_8(b); } } + return 0; } static int decode_subband_arith(AVCodecContext *avctx, void *b) { DiracContext *s = avctx->priv_data; - decode_subband_internal(s, b, 1); - return 0; + return decode_subband_internal(s, b, 1); } static int decode_subband_golomb(AVCodecContext *avctx, void *arg) { DiracContext *s = avctx->priv_data; SubBand **b = arg; - decode_subband_internal(s, *b, 0); - return 0; + return decode_subband_internal(s, *b, 0); } /** * Dirac Specification -> * [DIRAC_STD] 13.4.1 core_transform_data() */ -static void decode_component(DiracContext *s, int comp) +static int decode_component(DiracContext *s, int comp) { AVCodecContext *avctx = s->avctx; SubBand *bands[3*MAX_DWT_LEVELS+1]; enum dirac_subband orientation; int level, num_bands = 0; + int ret[3*MAX_DWT_LEVELS+1]; + int i; + int damaged_count = 0; /* Unpack all subbands at all levels. */ for (level = 0; level < s->wavelet_depth; level++) { @@ -671,21 +681,34 @@ static void decode_component(DiracContext *s, int comp) if (b->quant > (DIRAC_MAX_QUANT_INDEX - 1)) { av_log(s->avctx, AV_LOG_ERROR, "Unsupported quant %d\n", b->quant); b->quant = 0; + return AVERROR_INVALIDDATA; } align_get_bits(&s->gb); b->coeff_data = s->gb.buffer + get_bits_count(&s->gb)/8; - b->length = FFMIN(b->length, FFMAX(get_bits_left(&s->gb)/8, 0)); + if (b->length > FFMAX(get_bits_left(&s->gb)/8, 0)) { + b->length = FFMAX(get_bits_left(&s->gb)/8, 0); + damaged_count ++; + } skip_bits_long(&s->gb, b->length*8); } } /* arithmetic coding has inter-level dependencies, so we can only execute one level at a time */ if (s->is_arith) avctx->execute(avctx, decode_subband_arith, &s->plane[comp].band[level][!!level], - NULL, 4-!!level, sizeof(SubBand)); + ret + 3*level + !!level, 4-!!level, sizeof(SubBand)); } /* golomb coding has no inter-level dependencies, so we can execute all subbands in parallel */ if (!s->is_arith) - avctx->execute(avctx, decode_subband_golomb, bands, NULL, num_bands, sizeof(SubBand*)); + avctx->execute(avctx, decode_subband_golomb, bands, ret, num_bands, sizeof(SubBand*)); + + for (i = 0; i < s->wavelet_depth * 3 + 1; i++) { + if (ret[i] < 0) + damaged_count++; + } + if (damaged_count > (s->wavelet_depth * 3 + 1) /2) + return AVERROR_INVALIDDATA; + + return 0; } #define PARSE_VALUES(type, x, gb, ebits, buf1, buf2) \ @@ -1253,7 +1276,9 @@ static int dirac_unpack_idwt_params(DiracContext *s) s->num_y = get_interleaved_ue_golomb(gb); if (s->num_x * s->num_y == 0 || s->num_x * (uint64_t)s->num_y > INT_MAX || s->num_x * (uint64_t)s->avctx->width > INT_MAX || - s->num_y * (uint64_t)s->avctx->height > INT_MAX + s->num_y * (uint64_t)s->avctx->height > INT_MAX || + s->num_x > s->avctx->width || + s->num_y > s->avctx->height ) { av_log(s->avctx,AV_LOG_ERROR,"Invalid numx/y\n"); s->num_x = s->num_y = 0; @@ -1409,9 +1434,9 @@ static void global_mv(DiracContext *s, DiracBlock *block, int x, int y, int ref) int *b = s->globalmc[ref].pan_tilt; int *c = s->globalmc[ref].perspective; - int m = (1<u.mv[ref][0] = (mx + (1<<(ez+ep))) >> (ez+ep); block->u.mv[ref][1] = (my + (1<<(ez+ep))) >> (ez+ep); @@ -1528,6 +1553,11 @@ static int dirac_unpack_block_motion_data(DiracContext *s) } } + for (i = 0; i < 4 + 2*s->num_refs; i++) { + if (arith[i].error) + return arith[i].error; + } + return 0; } @@ -1871,7 +1901,9 @@ static int dirac_decode_frame_internal(DiracContext *s) if (!s->zero_res && !s->low_delay) { memset(p->idwt.buf, 0, p->idwt.stride * p->idwt.height); - decode_component(s, comp); /* [DIRAC_STD] 13.4.1 core_transform_data() */ + ret = decode_component(s, comp); /* [DIRAC_STD] 13.4.1 core_transform_data() */ + if (ret < 0) + return ret; } ret = ff_spatial_idwt_init(&d, &p->idwt, s->wavelet_idx+2, s->wavelet_depth, s->bit_depth); @@ -2115,7 +2147,7 @@ static int dirac_decode_data_unit(AVCodecContext *avctx, const uint8_t *buf, int return ret; } - if (CALC_PADDING((int64_t)dsh->width, MAX_DWT_LEVELS) * CALC_PADDING((int64_t)dsh->height, MAX_DWT_LEVELS) > avctx->max_pixels) + if (CALC_PADDING((int64_t)dsh->width, MAX_DWT_LEVELS) * CALC_PADDING((int64_t)dsh->height, MAX_DWT_LEVELS) * 5LL > avctx->max_pixels) ret = AVERROR(ERANGE); if (ret >= 0) ret = ff_set_dimensions(avctx, dsh->width, dsh->height); diff --git a/libavcodec/dnxhd_parser.c b/libavcodec/dnxhd_parser.c index 79ca1d671..63b4ff89e 100644 --- a/libavcodec/dnxhd_parser.c +++ b/libavcodec/dnxhd_parser.c @@ -75,14 +75,13 @@ static int dnxhd_find_frame_end(DNXHDParserContext *dctx, remaining = avpriv_dnxhd_get_frame_size(cid); if (remaining <= 0) { - remaining = ff_dnxhd_get_hr_frame_size(cid, dctx->w, dctx->h); + remaining = avpriv_dnxhd_get_hr_frame_size(cid, dctx->w, dctx->h); if (remaining <= 0) continue; } + remaining += i - 47; dctx->remaining = remaining; - if (buf_size - i + 47 >= dctx->remaining) { - int remaining = dctx->remaining; - + if (buf_size >= dctx->remaining) { pc->frame_start_found = 0; pc->state64 = -1; dctx->cur_byte = 0; @@ -90,6 +89,10 @@ static int dnxhd_find_frame_end(DNXHDParserContext *dctx, return remaining; } else { dctx->remaining -= buf_size; + // Update variables for correctness, they are currently not used beyond here + state = -1; + dctx->cur_byte += buf_size - i; + break; } } } diff --git a/libavcodec/dnxhddata.c b/libavcodec/dnxhddata.c index e9dd29ce4..154be8986 100644 --- a/libavcodec/dnxhddata.c +++ b/libavcodec/dnxhddata.c @@ -1092,6 +1092,19 @@ int avpriv_dnxhd_get_frame_size(int cid) return ff_dnxhd_cid_table[i].frame_size; } +int avpriv_dnxhd_get_hr_frame_size(int cid, int w, int h) +{ + int result, i = ff_dnxhd_get_cid_table(cid); + + if (i < 0) + return i; + + result = ((h + 15) / 16) * ((w + 15) / 16) * (int64_t)ff_dnxhd_cid_table[i].packet_scale.num / ff_dnxhd_cid_table[i].packet_scale.den; + result = (result + 2048) / 4096 * 4096; + + return FFMAX(result, 8192); +} + int avpriv_dnxhd_get_interlaced(int cid) { int i = ff_dnxhd_get_cid_table(cid); diff --git a/libavcodec/dnxhddata.h b/libavcodec/dnxhddata.h index f80ce18f3..cfa6b0c99 100644 --- a/libavcodec/dnxhddata.h +++ b/libavcodec/dnxhddata.h @@ -90,20 +90,8 @@ static av_always_inline uint64_t ff_dnxhd_parse_header_prefix(const uint8_t *buf return ff_dnxhd_check_header_prefix(prefix); } -static av_always_inline int ff_dnxhd_get_hr_frame_size(int cid, int w, int h) -{ - int result, i = ff_dnxhd_get_cid_table(cid); - - if (i < 0) - return i; - - result = ((h + 15) / 16) * ((w + 15) / 16) * (int64_t)ff_dnxhd_cid_table[i].packet_scale.num / ff_dnxhd_cid_table[i].packet_scale.den; - result = (result + 2048) / 4096 * 4096; - - return FFMAX(result, 8192); -} - int avpriv_dnxhd_get_frame_size(int cid); +int avpriv_dnxhd_get_hr_frame_size(int cid, int w, int h); int avpriv_dnxhd_get_interlaced(int cid); #endif /* AVCODEC_DNXHDDATA_H */ diff --git a/libavcodec/dnxhddec.c b/libavcodec/dnxhddec.c index 11d0bf424..1e9508669 100644 --- a/libavcodec/dnxhddec.c +++ b/libavcodec/dnxhddec.c @@ -37,7 +37,7 @@ #include "thread.h" typedef struct RowContext { - DECLARE_ALIGNED(16, int16_t, blocks)[12][64]; + DECLARE_ALIGNED(32, int16_t, blocks)[12][64]; int luma_scale[64]; int chroma_scale[64]; GetBitContext gb; @@ -67,6 +67,8 @@ typedef struct DNXHDContext { const CIDEntry *cid_table; int bit_depth; // 8, 10, 12 or 0 if not initialized at all. int is_444; + int alpha; + int lla; int mbaff; int act; int (*decode_dct_block)(const struct DNXHDContext *ctx, @@ -205,6 +207,10 @@ static int dnxhd_decode_header(DNXHDContext *ctx, AVFrame *frame, ctx->cur_field = 0; } ctx->mbaff = (buf[0x6] >> 5) & 1; + ctx->alpha = buf[0x7] & 1; + ctx->lla = (buf[0x7] >> 1) & 1; + if (ctx->alpha) + avpriv_request_sample(ctx->avctx, "alpha"); ctx->height = AV_RB16(buf + 0x18); ctx->width = AV_RB16(buf + 0x1a); @@ -583,12 +589,16 @@ static int dnxhd_decode_row(AVCodecContext *avctx, void *data, const DNXHDContext *ctx = avctx->priv_data; uint32_t offset = ctx->mb_scan_index[rownb]; RowContext *row = ctx->rows + threadnb; - int x; + int x, ret; row->last_dc[0] = row->last_dc[1] = row->last_dc[2] = 1 << (ctx->bit_depth + 2); // for levels +2^(bitdepth-1) - init_get_bits(&row->gb, ctx->buf + offset, (ctx->buf_size - offset) << 3); + ret = init_get_bits8(&row->gb, ctx->buf + offset, ctx->buf_size - offset); + if (ret < 0) { + row->errors++; + return ret; + } for (x = 0; x < ctx->mb_width; x++) { //START_TIMER; int ret = dnxhd_decode_macroblock(ctx, row, data, x, rownb); diff --git a/libavcodec/dnxhdenc.c b/libavcodec/dnxhdenc.c index 86e71ca8b..41b8079a0 100644 --- a/libavcodec/dnxhdenc.c +++ b/libavcodec/dnxhdenc.c @@ -207,17 +207,17 @@ static av_cold int dnxhd_init_vlc(DNXHDEncContext *ctx) int i, j, level, run; int max_level = 1 << (ctx->bit_depth + 2); - FF_ALLOCZ_ARRAY_OR_GOTO(ctx->m.avctx, ctx->vlc_codes, - max_level, 4 * sizeof(*ctx->vlc_codes), fail); - FF_ALLOCZ_ARRAY_OR_GOTO(ctx->m.avctx, ctx->vlc_bits, - max_level, 4 * sizeof(*ctx->vlc_bits), fail); + FF_ALLOCZ_ARRAY_OR_GOTO(ctx->m.avctx, ctx->orig_vlc_codes, + max_level, 4 * sizeof(*ctx->orig_vlc_codes), fail); + FF_ALLOCZ_ARRAY_OR_GOTO(ctx->m.avctx, ctx->orig_vlc_bits, + max_level, 4 * sizeof(*ctx->orig_vlc_bits), fail); FF_ALLOCZ_OR_GOTO(ctx->m.avctx, ctx->run_codes, 63 * 2, fail); FF_ALLOCZ_OR_GOTO(ctx->m.avctx, ctx->run_bits, 63, fail); - ctx->vlc_codes += max_level * 2; - ctx->vlc_bits += max_level * 2; + ctx->vlc_codes = ctx->orig_vlc_codes + max_level * 2; + ctx->vlc_bits = ctx->orig_vlc_bits + max_level * 2; for (level = -max_level; level < max_level; level++) { for (run = 0; run < 2; run++) { int index = (level << 1) | run; @@ -473,10 +473,16 @@ static av_cold int dnxhd_encode_init(AVCodecContext *avctx) ctx->m.mb_height /= 2; } + if (ctx->interlaced && ctx->profile != FF_PROFILE_DNXHD) { + av_log(avctx, AV_LOG_ERROR, + "Interlaced encoding is not supported for DNxHR profiles.\n"); + return AVERROR(EINVAL); + } + ctx->m.mb_num = ctx->m.mb_height * ctx->m.mb_width; if (ctx->cid_table->frame_size == DNXHD_VARIABLE) { - ctx->frame_size = ff_dnxhd_get_hr_frame_size(ctx->cid, + ctx->frame_size = avpriv_dnxhd_get_hr_frame_size(ctx->cid, avctx->width, avctx->height); av_assert0(ctx->frame_size >= 0); ctx->coding_unit_size = ctx->frame_size; @@ -1348,11 +1354,10 @@ FF_ENABLE_DEPRECATION_WARNINGS static av_cold int dnxhd_encode_end(AVCodecContext *avctx) { DNXHDEncContext *ctx = avctx->priv_data; - int max_level = 1 << (ctx->bit_depth + 2); int i; - av_free(ctx->vlc_codes - max_level * 2); - av_free(ctx->vlc_bits - max_level * 2); + av_freep(&ctx->orig_vlc_codes); + av_freep(&ctx->orig_vlc_bits); av_freep(&ctx->run_codes); av_freep(&ctx->run_bits); @@ -1369,8 +1374,10 @@ static av_cold int dnxhd_encode_end(AVCodecContext *avctx) av_freep(&ctx->qmatrix_c16); av_freep(&ctx->qmatrix_l16); - for (i = 1; i < avctx->thread_count; i++) - av_freep(&ctx->thread[i]); + if (avctx->active_thread_type == FF_THREAD_SLICE) { + for (i = 1; i < avctx->thread_count; i++) + av_freep(&ctx->thread[i]); + } return 0; } @@ -1390,6 +1397,7 @@ AVCodec ff_dnxhd_encoder = { .encode2 = dnxhd_encode_picture, .close = dnxhd_encode_end, .capabilities = AV_CODEC_CAP_SLICE_THREADS | AV_CODEC_CAP_FRAME_THREADS | AV_CODEC_CAP_INTRA_ONLY, + .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, .pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV422P10, diff --git a/libavcodec/dnxhdenc.h b/libavcodec/dnxhdenc.h index 963821ac8..7b0d862e2 100644 --- a/libavcodec/dnxhdenc.h +++ b/libavcodec/dnxhdenc.h @@ -86,6 +86,8 @@ typedef struct DNXHDEncContext { unsigned frame_bits; uint8_t *src[3]; + uint32_t *orig_vlc_codes; + uint8_t *orig_vlc_bits; uint32_t *vlc_codes; uint8_t *vlc_bits; uint16_t *run_codes; diff --git a/libavcodec/dolby_e.c b/libavcodec/dolby_e.c index 91a00ce87..429612ec0 100644 --- a/libavcodec/dolby_e.c +++ b/libavcodec/dolby_e.c @@ -681,6 +681,93 @@ static av_cold int dolby_e_close(AVCodecContext *avctx) return 0; } + +static av_cold void init_tables(void) +{ + int i, j; + + for (i = 1; i < 17; i++) + mantissa_tab1[i][0] = 1.0f / (1 << i - 1); + + for (i = 2; i < 16; i++) { + mantissa_tab1[i][1] = 1.0f / ((1 << i) - 1); + mantissa_tab1[i][2] = 0.5f / ((1 << i) - 1); + mantissa_tab1[i][3] = 0.25f / ((1 << i) - 1); + } + + mantissa_tab1[i][1] = 0.5f / (1 << 15); + mantissa_tab1[i][2] = 0.75f / (1 << 15); + mantissa_tab1[i][3] = 0.875f / (1 << 15); + + for (i = 1; i < 17; i++) { + mantissa_tab2[i][1] = mantissa_tab1[i][0] * 0.5f; + mantissa_tab2[i][2] = mantissa_tab1[i][0] * 0.75f; + mantissa_tab2[i][3] = mantissa_tab1[i][0] * 0.875f; + for (j = 1; j < 4; j++) + mantissa_tab3[i][j] = 1.0f / (1 << i) + 1.0f / (1 << j) - 1.0f / (1 << i + j); + } + + mantissa_tab3[1][3] = 0.6875f; + + for (i = 0; i < 25; i++) { + exponent_tab[i * 2 ] = 1.0f / (1 << i); + exponent_tab[i * 2 + 1] = M_SQRT1_2 / (1 << i); + } + + for (i = 1; i < 1024; i++) + gain_tab[i] = exp2f((i - 960) / 64.0f); + + // short 1 + ff_kbd_window_init(window, 3.0f, 128); + for (i = 0; i < 128; i++) + window[128 + i] = window[127 - i]; + + // start + for (i = 0; i < 192; i++) + window[256 + i] = start_window[i]; + + // short 2 + for (i = 0; i < 192; i++) + window[448 + i] = short_window2[i]; + for (i = 0; i < 64; i++) + window[640 + i] = window[63 - i]; + + // short 3 + for (i = 0; i < 64; i++) + window[704 + i] = short_window3[i]; + for (i = 0; i < 192; i++) + window[768 + i] = window[64 + i]; + + // bridge + for (i = 0; i < 128; i++) + window[960 + i] = window[i]; + for (i = 0; i < 64; i++) + window[1088 + i] = 1.0f; + + // long + ff_kbd_window_init(window + 1408, 3.0f, 256); + for (i = 0; i < 640; i++) + window[1664 + i] = 1.0f; + for (i = 0; i < 256; i++) + window[2304 + i] = window[1152 + i] = window[1663 - i]; + + // reverse start + for (i = 0; i < 192; i++) + window[2560 + i] = window[447 - i]; + + // reverse short 2 + for (i = 0; i < 256; i++) + window[2752 + i] = window[703 - i]; + + // reverse short 3 + for (i = 0; i < 256; i++) + window[3008 + i] = window[959 - i]; + + // reverse bridge + for (i = 0; i < 448; i++) + window[3264 + i] = window[1407 - i]; +} + static av_cold int dolby_e_init(AVCodecContext *avctx) { static AVOnce init_once = AV_ONCE_INIT; diff --git a/libavcodec/dolby_e.h b/libavcodec/dolby_e.h index 039023372..ae04bf699 100644 --- a/libavcodec/dolby_e.h +++ b/libavcodec/dolby_e.h @@ -644,90 +644,4 @@ static float gain_tab[1024]; DECLARE_ALIGNED(32, static float, window)[3712]; -static av_cold void init_tables(void) -{ - int i, j; - - for (i = 1; i < 17; i++) - mantissa_tab1[i][0] = 1.0f / (1 << i - 1); - - for (i = 2; i < 16; i++) { - mantissa_tab1[i][1] = 1.0f / ((1 << i) - 1); - mantissa_tab1[i][2] = 0.5f / ((1 << i) - 1); - mantissa_tab1[i][3] = 0.25f / ((1 << i) - 1); - } - - mantissa_tab1[i][1] = 0.5f / (1 << 15); - mantissa_tab1[i][2] = 0.75f / (1 << 15); - mantissa_tab1[i][3] = 0.875f / (1 << 15); - - for (i = 1; i < 17; i++) { - mantissa_tab2[i][1] = mantissa_tab1[i][0] * 0.5f; - mantissa_tab2[i][2] = mantissa_tab1[i][0] * 0.75f; - mantissa_tab2[i][3] = mantissa_tab1[i][0] * 0.875f; - for (j = 1; j < 4; j++) - mantissa_tab3[i][j] = 1.0f / (1 << i) + 1.0f / (1 << j) - 1.0f / (1 << i + j); - } - - mantissa_tab3[1][3] = 0.6875f; - - for (i = 0; i < 25; i++) { - exponent_tab[i * 2 ] = 1.0f / (1 << i); - exponent_tab[i * 2 + 1] = M_SQRT1_2 / (1 << i); - } - - for (i = 1; i < 1024; i++) - gain_tab[i] = exp2f((i - 960) / 64.0f); - - // short 1 - ff_kbd_window_init(window, 3.0f, 128); - for (i = 0; i < 128; i++) - window[128 + i] = window[127 - i]; - - // start - for (i = 0; i < 192; i++) - window[256 + i] = start_window[i]; - - // short 2 - for (i = 0; i < 192; i++) - window[448 + i] = short_window2[i]; - for (i = 0; i < 64; i++) - window[640 + i] = window[63 - i]; - - // short 3 - for (i = 0; i < 64; i++) - window[704 + i] = short_window3[i]; - for (i = 0; i < 192; i++) - window[768 + i] = window[64 + i]; - - // bridge - for (i = 0; i < 128; i++) - window[960 + i] = window[i]; - for (i = 0; i < 64; i++) - window[1088 + i] = 1.0f; - - // long - ff_kbd_window_init(window + 1408, 3.0f, 256); - for (i = 0; i < 640; i++) - window[1664 + i] = 1.0f; - for (i = 0; i < 256; i++) - window[2304 + i] = window[1152 + i] = window[1663 - i]; - - // reverse start - for (i = 0; i < 192; i++) - window[2560 + i] = window[447 - i]; - - // reverse short 2 - for (i = 0; i < 256; i++) - window[2752 + i] = window[703 - i]; - - // reverse short 3 - for (i = 0; i < 256; i++) - window[3008 + i] = window[959 - i]; - - // reverse bridge - for (i = 0; i < 448; i++) - window[3264 + i] = window[1407 - i]; -} - #endif diff --git a/libavcodec/dpx.c b/libavcodec/dpx.c index 720a9b850..b1833ed9e 100644 --- a/libavcodec/dpx.c +++ b/libavcodec/dpx.c @@ -19,6 +19,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "libavutil/avstring.h" #include "libavutil/intreadwrite.h" #include "libavutil/intfloat.h" #include "libavutil/imgutils.h" @@ -50,8 +51,26 @@ static unsigned int read32(const uint8_t **ptr, int is_big) return temp; } -static uint16_t read10in32(const uint8_t **ptr, uint32_t * lbuf, - int * n_datum, int is_big) +static uint16_t read10in32_gray(const uint8_t **ptr, uint32_t *lbuf, + int *n_datum, int is_big, int shift) +{ + uint16_t temp; + + if (*n_datum) + (*n_datum)--; + else { + *lbuf = read32(ptr, is_big); + *n_datum = 2; + } + + temp = *lbuf >> shift & 0x3FF; + *lbuf = *lbuf >> 10; + + return temp; +} + +static uint16_t read10in32(const uint8_t **ptr, uint32_t *lbuf, + int *n_datum, int is_big, int shift) { if (*n_datum) (*n_datum)--; @@ -60,13 +79,13 @@ static uint16_t read10in32(const uint8_t **ptr, uint32_t * lbuf, *n_datum = 2; } - *lbuf = (*lbuf << 10) | (*lbuf >> 22); + *lbuf = *lbuf << 10 | *lbuf >> shift & 0x3FFFFF; return *lbuf & 0x3FF; } -static uint16_t read12in32(const uint8_t **ptr, uint32_t * lbuf, - int * n_datum, int is_big) +static uint16_t read12in32(const uint8_t **ptr, uint32_t *lbuf, + int *n_datum, int is_big) { if (*n_datum) (*n_datum)--; @@ -106,6 +125,9 @@ static int decode_frame(AVCodecContext *avctx, int buf_size = avpkt->size; AVFrame *const p = data; uint8_t *ptr[AV_NUM_DATA_POINTERS]; + uint32_t header_version, version = 0; + char creator[101]; + char input_device[33]; unsigned int offset; int magic_num, endian; @@ -141,6 +163,15 @@ static int decode_frame(AVCodecContext *avctx, return AVERROR_INVALIDDATA; } + header_version = read32(&buf, 0); + if (header_version == MKTAG('V','1','.','0')) + version = 1; + if (header_version == MKTAG('V','2','.','0')) + version = 2; + if (!version) + av_log(avctx, AV_LOG_WARNING, "Unknown header format version %s.\n", + av_fourcc2str(header_version)); + // Check encryption buf = avpkt->data + 660; ret = read32(&buf, endian); @@ -170,10 +201,6 @@ static int decode_frame(AVCodecContext *avctx, packing = read16(&buf, endian); encoding = read16(&buf, endian); - if (packing > 1) { - avpriv_report_missing_feature(avctx, "Packing %d", packing); - return AVERROR_PATCHWELCOME; - } if (encoding) { avpriv_report_missing_feature(avctx, "Encoding %d", encoding); return AVERROR_PATCHWELCOME; @@ -232,16 +259,6 @@ static int decode_frame(AVCodecContext *avctx, stride = (avctx->width * elements + 2) / 3 * 4; break; case 12: - if (!packing) { - int tested = 0; - if (descriptor == 50 && endian && (avctx->width%8) == 0) { // Little endian and widths not a multiple of 8 need tests - tested = 1; - } - if (!tested) { - av_log(avctx, AV_LOG_ERROR, "Packing to 16bit required\n"); - return -1; - } - } stride = avctx->width * elements; if (packing) { stride *= 2; @@ -324,6 +341,10 @@ static int decode_frame(AVCodecContext *avctx, case 51121: avctx->pix_fmt = AV_PIX_FMT_GBRAP12; break; + case 6100: + case 6101: + avctx->pix_fmt = AV_PIX_FMT_GRAY10; + break; case 6161: avctx->pix_fmt = AV_PIX_FMT_GRAY16BE; break; @@ -361,6 +382,14 @@ static int decode_frame(AVCodecContext *avctx, if ((ret = ff_get_buffer(avctx, p, 0)) < 0) return ret; + av_strlcpy(creator, avpkt->data + 160, 100); + creator[100] = '\0'; + av_dict_set(&p->metadata, "Creator", creator, 0); + + av_strlcpy(input_device, avpkt->data + 1556, 32); + input_device[32] = '\0'; + av_dict_set(&p->metadata, "Input Device", input_device, 0); + // Move pointer to offset from start of file buf = avpkt->data + offset; @@ -374,19 +403,27 @@ static int decode_frame(AVCodecContext *avctx, (uint16_t*)ptr[1], (uint16_t*)ptr[2], (uint16_t*)ptr[3]}; + int shift = elements > 1 ? packing == 1 ? 22 : 20 : packing == 1 ? 2 : 0; for (y = 0; y < avctx->width; y++) { - *dst[2]++ = read10in32(&buf, &rgbBuffer, - &n_datum, endian); - *dst[0]++ = read10in32(&buf, &rgbBuffer, - &n_datum, endian); - *dst[1]++ = read10in32(&buf, &rgbBuffer, - &n_datum, endian); + if (elements >= 3) + *dst[2]++ = read10in32(&buf, &rgbBuffer, + &n_datum, endian, shift); + if (elements == 1) + *dst[0]++ = read10in32_gray(&buf, &rgbBuffer, + &n_datum, endian, shift); + else + *dst[0]++ = read10in32(&buf, &rgbBuffer, + &n_datum, endian, shift); + if (elements >= 2) + *dst[1]++ = read10in32(&buf, &rgbBuffer, + &n_datum, endian, shift); if (elements == 4) *dst[3]++ = read10in32(&buf, &rgbBuffer, - &n_datum, endian); + &n_datum, endian, shift); } - n_datum = 0; + if (memcmp(input_device, "Scanity", 7)) + n_datum = 0; for (i = 0; i < elements; i++) ptr[i] += p->linesize[i]; } @@ -397,16 +434,16 @@ static int decode_frame(AVCodecContext *avctx, (uint16_t*)ptr[1], (uint16_t*)ptr[2], (uint16_t*)ptr[3]}; + int shift = packing == 1 ? 4 : 0; for (y = 0; y < avctx->width; y++) { if (packing) { - if (elements >= 3) - *dst[2]++ = read16(&buf, endian) >> 4; - *dst[0] = read16(&buf, endian) >> 4; - dst[0]++; - if (elements >= 2) - *dst[1]++ = read16(&buf, endian) >> 4; - if (elements == 4) - *dst[3]++ = read16(&buf, endian) >> 4; + if (elements >= 3) + *dst[2]++ = read16(&buf, endian) >> shift & 0xFFF; + *dst[0]++ = read16(&buf, endian) >> shift & 0xFFF; + if (elements >= 2) + *dst[1]++ = read16(&buf, endian) >> shift & 0xFFF; + if (elements == 4) + *dst[3]++ = read16(&buf, endian) >> shift & 0xFFF; } else { if (elements >= 3) *dst[2]++ = read12in32(&buf, &rgbBuffer, @@ -421,6 +458,7 @@ static int decode_frame(AVCodecContext *avctx, &n_datum, endian); } } + n_datum = 0; for (i = 0; i < elements; i++) ptr[i] += p->linesize[i]; // Jump to next aligned position diff --git a/libavcodec/dsicinvideo.c b/libavcodec/dsicinvideo.c index aa080417d..d422df068 100644 --- a/libavcodec/dsicinvideo.c +++ b/libavcodec/dsicinvideo.c @@ -266,8 +266,11 @@ static int cinvideo_decode_frame(AVCodecContext *avctx, cin->bitmap_table[CIN_CUR_BMP], cin->bitmap_size); break; case 37: - cin_decode_huffman(buf, bitmap_frame_size, + res = cin_decode_huffman(buf, bitmap_frame_size, cin->bitmap_table[CIN_CUR_BMP], cin->bitmap_size); + + if (cin->bitmap_size - avctx->discard_damaged_percentage*cin->bitmap_size/100 > res) + return AVERROR_INVALIDDATA; break; case 38: res = cin_decode_lzss(buf, bitmap_frame_size, @@ -328,5 +331,6 @@ AVCodec ff_dsicinvideo_decoder = { .init = cinvideo_decode_init, .close = cinvideo_decode_end, .decode = cinvideo_decode_frame, + .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, .capabilities = AV_CODEC_CAP_DR1, }; diff --git a/libavcodec/dstdec.c b/libavcodec/dstdec.c index 368cb6493..0614c99c4 100644 --- a/libavcodec/dstdec.c +++ b/libavcodec/dstdec.c @@ -70,7 +70,7 @@ typedef struct DSTContext { GetBitContext gb; ArithCoder ac; Table fsets, probs; - DECLARE_ALIGNED(64, uint8_t, status)[DST_MAX_CHANNELS][16]; + DECLARE_ALIGNED(16, uint8_t, status)[DST_MAX_CHANNELS][16]; DECLARE_ALIGNED(16, int16_t, filter)[DST_MAX_ELEMENTS][16][256]; DSDContext dsdctx[DST_MAX_CHANNELS]; } DSTContext; @@ -343,8 +343,8 @@ static int decode_frame(AVCodecContext *avctx, void *data, v = ((predict >> 15) ^ residual) & 1; dsd[((i >> 3) * channels + ch) << 2] |= v << (7 - (i & 0x7 )); - AV_WN64A(status + 8, (AV_RN64A(status + 8) << 1) | ((AV_RN64A(status) >> 63) & 1)); - AV_WN64A(status, (AV_RN64A(status) << 1) | v); + AV_WL64A(status + 8, (AV_RL64A(status + 8) << 1) | ((AV_RL64A(status) >> 63) & 1)); + AV_WL64A(status, (AV_RL64A(status) << 1) | v); } } diff --git a/libavcodec/dump_extradata_bsf.c b/libavcodec/dump_extradata_bsf.c index 98703749f..b64150823 100644 --- a/libavcodec/dump_extradata_bsf.c +++ b/libavcodec/dump_extradata_bsf.c @@ -34,22 +34,25 @@ enum DumpFreq { typedef struct DumpExtradataContext { const AVClass *class; + AVPacket pkt; int freq; } DumpExtradataContext; static int dump_extradata(AVBSFContext *ctx, AVPacket *out) { DumpExtradataContext *s = ctx->priv_data; - AVPacket *in; + AVPacket *in = &s->pkt; int ret = 0; - ret = ff_bsf_get_packet(ctx, &in); + ret = ff_bsf_get_packet_ref(ctx, in); if (ret < 0) return ret; if (ctx->par_in->extradata && (s->freq == DUMP_FREQ_ALL || - (s->freq == DUMP_FREQ_KEYFRAME && in->flags & AV_PKT_FLAG_KEY))) { + (s->freq == DUMP_FREQ_KEYFRAME && in->flags & AV_PKT_FLAG_KEY)) && + in->size >= ctx->par_in->extradata_size && + memcmp(in->data, ctx->par_in->extradata, ctx->par_in->extradata_size)) { if (in->size >= INT_MAX - ctx->par_in->extradata_size) { ret = AVERROR(ERANGE); goto fail; @@ -72,7 +75,7 @@ static int dump_extradata(AVBSFContext *ctx, AVPacket *out) } fail: - av_packet_free(&in); + av_packet_unref(in); return ret; } @@ -80,7 +83,7 @@ fail: #define OFFSET(x) offsetof(DumpExtradataContext, x) #define FLAGS (AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_BSF_PARAM) static const AVOption options[] = { - { "freq", "When do dump extradata", OFFSET(freq), AV_OPT_TYPE_INT, + { "freq", "When to dump extradata", OFFSET(freq), AV_OPT_TYPE_INT, { .i64 = DUMP_FREQ_KEYFRAME }, DUMP_FREQ_KEYFRAME, DUMP_FREQ_ALL, FLAGS, "freq" }, { "k", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = DUMP_FREQ_KEYFRAME }, .flags = FLAGS, .unit = "freq" }, { "keyframe", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = DUMP_FREQ_KEYFRAME }, .flags = FLAGS, .unit = "freq" }, diff --git a/libavcodec/dvbsub.c b/libavcodec/dvbsub.c index 8cce702a9..a8d43d81d 100644 --- a/libavcodec/dvbsub.c +++ b/libavcodec/dvbsub.c @@ -247,9 +247,10 @@ static void dvb_encode_rle8(uint8_t **pq, *pq = q; } -static int encode_dvb_subtitles(DVBSubtitleContext *s, +static int encode_dvb_subtitles(AVCodecContext *avctx, uint8_t *outbuf, const AVSubtitle *h) { + DVBSubtitleContext *s = avctx->priv_data; uint8_t *q, *pseg_len; int page_id, region_id, clut_id, object_id, i, bpp_index, page_state; @@ -261,6 +262,19 @@ static int encode_dvb_subtitles(DVBSubtitleContext *s, if (h->num_rects && !h->rects) return -1; + if (avctx->width > 0 && avctx->height > 0) { + /* display definition segment */ + *q++ = 0x0f; /* sync_byte */ + *q++ = 0x14; /* segment_type */ + bytestream_put_be16(&q, page_id); + pseg_len = q; + q += 2; /* segment length */ + *q++ = 0x00; /* dds version number & display window flag */ + bytestream_put_be16(&q, avctx->width - 1); /* display width */ + bytestream_put_be16(&q, avctx->height - 1); /* display height */ + bytestream_put_be16(&pseg_len, q - pseg_len - 2); + } + /* page composition segment */ *q++ = 0x0f; /* sync_byte */ @@ -446,10 +460,9 @@ static int dvbsub_encode(AVCodecContext *avctx, unsigned char *buf, int buf_size, const AVSubtitle *sub) { - DVBSubtitleContext *s = avctx->priv_data; int ret; - ret = encode_dvb_subtitles(s, buf, sub); + ret = encode_dvb_subtitles(avctx, buf, sub); return ret; } diff --git a/libavcodec/dvbsub_parser.c b/libavcodec/dvbsub_parser.c index e77b9655c..8ced3c4c3 100644 --- a/libavcodec/dvbsub_parser.c +++ b/libavcodec/dvbsub_parser.c @@ -57,6 +57,7 @@ static int dvbsub_parse(AVCodecParserContext *s, DVBSubParseContext *pc = s->priv_data; uint8_t *p, *p_end; int i, len, buf_pos = 0; + int out_size = 0; ff_dlog(avctx, "DVB parse packet pts=%"PRIx64", lpts=%"PRIx64", cpts=%"PRIx64":\n", s->pts, s->last_pts, s->cur_frame_pts[s->cur_frame_start_index]); @@ -71,8 +72,8 @@ static int dvbsub_parse(AVCodecParserContext *s, if (i % 16 != 0) ff_dlog(avctx, "\n"); - *poutbuf = NULL; - *poutbuf_size = 0; + *poutbuf = buf; + *poutbuf_size = buf_size; s->fetch_timestamp = 1; @@ -89,7 +90,7 @@ static int dvbsub_parse(AVCodecParserContext *s, if (buf_size < 2 || buf[0] != 0x20 || buf[1] != 0x00) { ff_dlog(avctx, "Bad packet header\n"); - return -1; + return buf_size; } buf_pos = 2; @@ -113,9 +114,9 @@ static int dvbsub_parse(AVCodecParserContext *s, } if (buf_size - buf_pos + pc->packet_index > PARSE_BUF_SIZE) - return -1; + return buf_size; -/* if not currently in a packet, discard data */ +/* if not currently in a packet, pass data */ if (pc->in_packet == 0) return buf_size; @@ -135,7 +136,7 @@ static int dvbsub_parse(AVCodecParserContext *s, if (len + 6 <= p_end - p) { - *poutbuf_size += len + 6; + out_size += len + 6; p += len + 6; } else @@ -159,9 +160,10 @@ static int dvbsub_parse(AVCodecParserContext *s, } } - if (*poutbuf_size > 0) + if (out_size > 0) { *poutbuf = pc->packet_buf; + *poutbuf_size = out_size; pc->packet_start = *poutbuf_size; } diff --git a/libavcodec/dvbsubdec.c b/libavcodec/dvbsubdec.c index 6af6ef7b7..6e7e13b6e 100644 --- a/libavcodec/dvbsubdec.c +++ b/libavcodec/dvbsubdec.c @@ -127,6 +127,7 @@ typedef struct DVBSubContext { int compute_edt; /**< if 1 end display time calculated using pts if 0 (Default) calculated using time out */ int compute_clut; + int clut_count2[257][256]; int substream; int64_t prev_start; DVBSubRegion *region_list; @@ -650,13 +651,17 @@ static int dvbsub_read_8bit_string(AVCodecContext *avctx, return pixels_read; } -static void compute_default_clut(uint8_t *clut, AVSubtitleRect *rect, int w, int h) +static void compute_default_clut(DVBSubContext *ctx, uint8_t *clut, AVSubtitleRect *rect, int w, int h) { uint8_t list[256] = {0}; uint8_t list_inv[256]; int counttab[256] = {0}; + int (*counttab2)[256] = ctx->clut_count2; int count, i, x, y; ptrdiff_t stride = rect->linesize[0]; + + memset(ctx->clut_count2, 0 , sizeof(ctx->clut_count2)); + #define V(x,y) rect->data[0][(x) + (y)*stride] for (y = 0; ydata[0][x + y*stride]; - int v = *d; - int l_m = list[v]; - int l_l = x ? L(-1, 0) : 1; - int l_r = x+1 bestscore) { bestscore = score; bestv = x; @@ -819,7 +825,7 @@ static int save_subtitle_set(AVCodecContext *avctx, AVSubtitle *sub, int *got_ou if ((clut == &default_clut && ctx->compute_clut == -1) || ctx->compute_clut == 1) { if (!region->has_computed_clut) { - compute_default_clut(region->computed_clut, rect, rect->w, rect->h); + compute_default_clut(ctx, region->computed_clut, rect, rect->w, rect->h); region->has_computed_clut = 1; } @@ -1572,8 +1578,9 @@ static int dvbsub_parse_display_definition_segment(AVCodecContext *avctx, display_def->width = bytestream_get_be16(&buf) + 1; display_def->height = bytestream_get_be16(&buf) + 1; if (!avctx->width || !avctx->height) { - avctx->width = display_def->width; - avctx->height = display_def->height; + int ret = ff_set_dimensions(avctx, display_def->width, display_def->height); + if (ret < 0) + return ret; } if (info_byte & 1<<3) { // display_window_flag diff --git a/libavcodec/dvdec.c b/libavcodec/dvdec.c index 7b16787e2..89864f2ed 100644 --- a/libavcodec/dvdec.c +++ b/libavcodec/dvdec.c @@ -49,6 +49,7 @@ #include "internal.h" #include "put_bits.h" #include "simple_idct.h" +#include "thread.h" typedef struct BlockInfo { const uint32_t *factor_table; @@ -499,7 +500,7 @@ static int dvvideo_decode_frame(AVCodecContext *avctx, void *data, uint8_t *buf = avpkt->data; int buf_size = avpkt->size; DVVideoContext *s = avctx->priv_data; - AVFrame *frame = data; + ThreadFrame frame = { .f = data }; const uint8_t *vsc_pack; int apt, is16_9, ret; const AVDVProfile *sys; @@ -520,9 +521,9 @@ static int dvvideo_decode_frame(AVCodecContext *avctx, void *data, s->sys = sys; } - s->frame = frame; - frame->key_frame = 1; - frame->pict_type = AV_PICTURE_TYPE_I; + s->frame = frame.f; + frame.f->key_frame = 1; + frame.f->pict_type = AV_PICTURE_TYPE_I; avctx->pix_fmt = s->sys->pix_fmt; avctx->framerate = av_inv_q(s->sys->time_base); @@ -539,14 +540,14 @@ static int dvvideo_decode_frame(AVCodecContext *avctx, void *data, ff_set_sar(avctx, s->sys->sar[is16_9]); } - if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) + if ((ret = ff_thread_get_buffer(avctx, &frame, 0)) < 0) return ret; - frame->interlaced_frame = 1; - frame->top_field_first = 0; + frame.f->interlaced_frame = 1; + frame.f->top_field_first = 0; /* Determine the codec's field order from the packet */ if ( *vsc_pack == dv_video_control ) { - frame->top_field_first = !(vsc_pack[3] & 0x40); + frame.f->top_field_first = !(vsc_pack[3] & 0x40); } s->buf = buf; @@ -569,6 +570,6 @@ AVCodec ff_dvvideo_decoder = { .priv_data_size = sizeof(DVVideoContext), .init = dvvideo_decode_init, .decode = dvvideo_decode_frame, - .capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_SLICE_THREADS, + .capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_FRAME_THREADS | AV_CODEC_CAP_SLICE_THREADS, .max_lowres = 3, }; diff --git a/libavcodec/dvdsubdec.c b/libavcodec/dvdsubdec.c index cf1084475..741ea9fd1 100644 --- a/libavcodec/dvdsubdec.c +++ b/libavcodec/dvdsubdec.c @@ -42,6 +42,7 @@ typedef struct DVDSubContext uint8_t buf[0x10000]; int buf_size; int forced_subs_only; + uint8_t used_color[256]; #ifdef DEBUG int sub_id; #endif @@ -97,7 +98,7 @@ static int decode_run_8bit(GetBitContext *gb, int *color) return len; } -static int decode_rle(uint8_t *bitmap, int linesize, int w, int h, +static int decode_rle(uint8_t *bitmap, int linesize, int w, int h, uint8_t used_color[256], const uint8_t *buf, int start, int buf_size, int is_8bit) { GetBitContext gb; @@ -128,6 +129,7 @@ static int decode_rle(uint8_t *bitmap, int linesize, int w, int h, return AVERROR_INVALIDDATA; len = FFMIN(len, w - x); memset(d + x, color, len); + used_color[color] = 1; x += len; if (x >= w) { y++; @@ -369,7 +371,7 @@ static int decode_dvd_subtitles(DVDSubContext *ctx, AVSubtitle *sub_header, h = 0; if (w > 0 && h > 1) { reset_rects(sub_header); - + memset(ctx->used_color, 0, sizeof(ctx->used_color)); sub_header->rects = av_mallocz(sizeof(*sub_header->rects)); if (!sub_header->rects) goto fail; @@ -380,10 +382,10 @@ static int decode_dvd_subtitles(DVDSubContext *ctx, AVSubtitle *sub_header, bitmap = sub_header->rects[0]->data[0] = av_malloc(w * h); if (!bitmap) goto fail; - if (decode_rle(bitmap, w * 2, w, (h + 1) / 2, + if (decode_rle(bitmap, w * 2, w, (h + 1) / 2, ctx->used_color, buf, offset1, buf_size, is_8bit) < 0) goto fail; - if (decode_rle(bitmap + w, w * 2, w, h / 2, + if (decode_rle(bitmap + w, w * 2, w, h / 2, ctx->used_color, buf, offset2, buf_size, is_8bit) < 0) goto fail; sub_header->rects[0]->data[1] = av_mallocz(AVPALETTE_SIZE); @@ -447,19 +449,24 @@ static int is_transp(const uint8_t *buf, int pitch, int n, } /* return 0 if empty rectangle, 1 if non empty */ -static int find_smallest_bounding_rectangle(AVSubtitle *s) +static int find_smallest_bounding_rectangle(DVDSubContext *ctx, AVSubtitle *s) { uint8_t transp_color[256] = { 0 }; int y1, y2, x1, x2, y, w, h, i; uint8_t *bitmap; + int transparent = 1; if (s->num_rects == 0 || !s->rects || s->rects[0]->w <= 0 || s->rects[0]->h <= 0) return 0; for(i = 0; i < s->rects[0]->nb_colors; i++) { - if ((((uint32_t *)s->rects[0]->data[1])[i] >> 24) == 0) + if ((((uint32_t *)s->rects[0]->data[1])[i] >> 24) == 0) { transp_color[i] = 1; + } else if (ctx->used_color[i]) + transparent = 0; } + if (transparent) + return 0; y1 = 0; while (y1 < s->rects[0]->h && is_transp(s->rects[0]->data[0] + y1 * s->rects[0]->linesize[0], 1, s->rects[0]->w, transp_color)) @@ -588,13 +595,14 @@ static int dvdsub_decode(AVCodecContext *avctx, } if (is_menu < 0) { + ctx->buf_size = 0; no_subtitle: reset_rects(sub); *data_size = 0; return buf_size; } - if (!is_menu && find_smallest_bounding_rectangle(sub) == 0) + if (!is_menu && find_smallest_bounding_rectangle(ctx, sub) == 0) goto no_subtitle; if (ctx->forced_subs_only && !(sub->rects[0]->flags & AV_SUBTITLE_FLAG_FORCED)) diff --git a/libavcodec/dvdsubenc.c b/libavcodec/dvdsubenc.c index 26afdc666..ff95ed200 100644 --- a/libavcodec/dvdsubenc.c +++ b/libavcodec/dvdsubenc.c @@ -438,7 +438,7 @@ static int dvdsub_init(AVCodecContext *avctx) av_assert0(sizeof(dvdc->global_palette) == sizeof(default_palette)); memcpy(dvdc->global_palette, default_palette, sizeof(dvdc->global_palette)); - av_bprint_init(&extradata, 0, 1); + av_bprint_init(&extradata, 0, AV_BPRINT_SIZE_AUTOMATIC); if (avctx->width && avctx->height) av_bprintf(&extradata, "size: %dx%d\n", avctx->width, avctx->height); av_bprintf(&extradata, "palette:"); diff --git a/libavcodec/dxtory.c b/libavcodec/dxtory.c index 285ca38ef..4dd675316 100644 --- a/libavcodec/dxtory.c +++ b/libavcodec/dxtory.c @@ -272,10 +272,11 @@ static int dxtory_decode_v2(AVCodecContext *avctx, AVFrame *pic, setup_lru_func setup_lru, enum AVPixelFormat fmt) { - GetByteContext gb; + GetByteContext gb, gb_check; GetBitContext gb2; int nslices, slice, line = 0; uint32_t off, slice_size; + uint64_t off_check; uint8_t lru[3][8]; int ret; @@ -283,6 +284,19 @@ static int dxtory_decode_v2(AVCodecContext *avctx, AVFrame *pic, if (ret < 0) return ret; + off_check = off; + gb_check = gb; + for (slice = 0; slice < nslices; slice++) { + slice_size = bytestream2_get_le32(&gb_check); + + if (slice_size <= 16 + (avctx->height * avctx->width / (8 * nslices))) + return AVERROR_INVALIDDATA; + off_check += slice_size; + } + + if (off_check - avctx->discard_damaged_percentage*off_check/100 > src_size) + return AVERROR_INVALIDDATA; + avctx->pix_fmt = fmt; if ((ret = ff_get_buffer(avctx, pic, 0)) < 0) return ret; diff --git a/libavcodec/dxv.c b/libavcodec/dxv.c index aef5ec19d..ae79de981 100644 --- a/libavcodec/dxv.c +++ b/libavcodec/dxv.c @@ -256,6 +256,8 @@ static int decompress_texture_thread(AVCodecContext *avctx, void *arg, #define CHECKPOINT(x) \ do { \ if (state == 0) { \ + if (bytestream2_get_bytes_left(gbc) < 4) \ + return AVERROR_INVALIDDATA; \ value = bytestream2_get_le32(gbc); \ state = 16; \ } \ @@ -743,6 +745,9 @@ static int dxv_decompress_cocg(DXVContext *ctx, GetByteContext *gb, int skip0, skip1, oi0 = 0, oi1 = 0; int ret, state0 = 0, state1 = 0; + if (op_offset < 12) + return AVERROR_INVALIDDATA; + dst = tex_data; bytestream2_skip(gb, op_offset - 12); if (op_size0 > max_op_size0) @@ -1052,6 +1057,10 @@ static int dxv_decode(AVCodecContext *avctx, void *data, avctx->pix_fmt = AV_PIX_FMT_RGBA; avctx->colorspace = AVCOL_SPC_RGB; + ctx->tex_funct = NULL; + ctx->tex_funct_planar[0] = NULL; + ctx->tex_funct_planar[1] = NULL; + tag = bytestream2_get_le32(gbc); switch (tag) { case MKBETAG('D', 'X', 'T', '1'): diff --git a/libavcodec/dxva2_internal.h b/libavcodec/dxva2_internal.h index 8bb334409..b822af59c 100644 --- a/libavcodec/dxva2_internal.h +++ b/libavcodec/dxva2_internal.h @@ -104,9 +104,9 @@ typedef struct FFDXVASharedContext { #if CONFIG_D3D11VA && CONFIG_DXVA2 #define DXVA_CONTEXT_WORKAROUND(avctx, ctx) (ff_dxva2_is_d3d11(avctx) ? ctx->d3d11va.workaround : ctx->dxva2.workaround) #define DXVA_CONTEXT_COUNT(avctx, ctx) (ff_dxva2_is_d3d11(avctx) ? ctx->d3d11va.surface_count : ctx->dxva2.surface_count) -#define DXVA_CONTEXT_DECODER(avctx, ctx) (ff_dxva2_is_d3d11(avctx) ? ctx->d3d11va.decoder : ctx->dxva2.decoder) +#define DXVA_CONTEXT_DECODER(avctx, ctx) (ff_dxva2_is_d3d11(avctx) ? (void *)ctx->d3d11va.decoder : (void *)ctx->dxva2.decoder) #define DXVA_CONTEXT_REPORT_ID(avctx, ctx) (*(ff_dxva2_is_d3d11(avctx) ? &ctx->d3d11va.report_id : &ctx->dxva2.report_id)) -#define DXVA_CONTEXT_CFG(avctx, ctx) (ff_dxva2_is_d3d11(avctx) ? ctx->d3d11va.cfg : ctx->dxva2.cfg) +#define DXVA_CONTEXT_CFG(avctx, ctx) (ff_dxva2_is_d3d11(avctx) ? (void *)ctx->d3d11va.cfg : (void *)ctx->dxva2.cfg) #define DXVA_CONTEXT_CFG_BITSTREAM(avctx, ctx) (ff_dxva2_is_d3d11(avctx) ? ctx->d3d11va.cfg->ConfigBitstreamRaw : ctx->dxva2.cfg->ConfigBitstreamRaw) #define DXVA_CONTEXT_CFG_INTRARESID(avctx, ctx) (ff_dxva2_is_d3d11(avctx) ? ctx->d3d11va.cfg->ConfigIntraResidUnsigned : ctx->dxva2.cfg->ConfigIntraResidUnsigned) #define DXVA_CONTEXT_CFG_RESIDACCEL(avctx, ctx) (ff_dxva2_is_d3d11(avctx) ? ctx->d3d11va.cfg->ConfigResidDiffAccelerator : ctx->dxva2.cfg->ConfigResidDiffAccelerator) diff --git a/libavcodec/eac3dec.c b/libavcodec/eac3dec.c index 73067ded9..3a5c7989b 100644 --- a/libavcodec/eac3dec.c +++ b/libavcodec/eac3dec.c @@ -31,12 +31,6 @@ * No known samples exist. The spec also does not give clear information * on how this is to be implemented. * - * Dependent Streams - * Only the independent stream is currently decoded. Any dependent - * streams are skipped. We have only come across two examples of this, and - * they are both just test streams, one for HD-DVD and the other for - * Blu-ray. - * * Transient Pre-noise Processing * This is side information which a decoder should use to reduce artifacts * caused by transients. There are samples which are known to have this diff --git a/libavcodec/eacmv.c b/libavcodec/eacmv.c index bf4404ce4..6f39d72b8 100644 --- a/libavcodec/eacmv.c +++ b/libavcodec/eacmv.c @@ -191,12 +191,12 @@ static int cmv_decode_frame(AVCodecContext *avctx, if (ret < 0) return ret; if (size > buf_end - buf - EA_PREAMBLE_SIZE) - return -1; + return AVERROR_INVALIDDATA; buf += size; } - if (av_image_check_size(s->width, s->height, 0, s->avctx)) - return -1; + if ((ret = av_image_check_size(s->width, s->height, 0, s->avctx)) < 0) + return ret; if ((ret = ff_get_buffer(avctx, frame, AV_GET_BUFFER_FLAG_REF)) < 0) return ret; diff --git a/libavcodec/eatgv.c b/libavcodec/eatgv.c index 93e291f05..f82f7b9cc 100644 --- a/libavcodec/eatgv.c +++ b/libavcodec/eatgv.c @@ -300,6 +300,9 @@ static int tgv_decode_frame(AVCodecContext *avctx, s->palette[i] = 0xFFU << 24 | AV_RB24(buf); buf += 3; } + if (buf_end - buf < 5) { + return AVERROR_INVALIDDATA; + } } if ((ret = ff_get_buffer(avctx, frame, AV_GET_BUFFER_FLAG_REF)) < 0) diff --git a/libavcodec/eatqi.c b/libavcodec/eatqi.c index 1a847a35d..96536b1a0 100644 --- a/libavcodec/eatqi.c +++ b/libavcodec/eatqi.c @@ -83,7 +83,7 @@ static int tqi_decode_mb(TqiContext *t, int16_t (*block)[64]) if (ret < 0) { av_log(t->avctx, AV_LOG_ERROR, "ac-tex damaged at %d %d\n", t->mb_x, t->mb_y); - return -1; + return ret; } } @@ -131,6 +131,9 @@ static int tqi_decode_frame(AVCodecContext *avctx, AVFrame *frame = data; int ret, w, h; + if (buf_size < 12) + return AVERROR_INVALIDDATA; + t->avctx = avctx; w = AV_RL16(&buf[0]); diff --git a/libavcodec/encode.c b/libavcodec/encode.c index d9761515a..d12c42526 100644 --- a/libavcodec/encode.c +++ b/libavcodec/encode.c @@ -135,7 +135,6 @@ int attribute_align_arg avcodec_encode_audio2(AVCodecContext *avctx, if (!(avctx->codec->capabilities & AV_CODEC_CAP_DELAY) && !frame) { av_packet_unref(avpkt); - av_init_packet(avpkt); return 0; } @@ -235,13 +234,12 @@ int attribute_align_arg avcodec_encode_audio2(AVCodecContext *avctx, if (ret >= 0) avpkt->data = avpkt->buf->data; } - - avctx->frame_number++; + if (frame) + avctx->frame_number++; } if (ret < 0 || !*got_packet_ptr) { av_packet_unref(avpkt); - av_init_packet(avpkt); goto end; } @@ -282,8 +280,6 @@ int attribute_align_arg avcodec_encode_video2(AVCodecContext *avctx, if (!(avctx->codec->capabilities & AV_CODEC_CAP_DELAY) && !frame) { av_packet_unref(avpkt); - av_init_packet(avpkt); - avpkt->size = 0; return 0; } @@ -333,7 +329,8 @@ int attribute_align_arg avcodec_encode_video2(AVCodecContext *avctx, avpkt->data = avpkt->buf->data; } - avctx->frame_number++; + if (frame) + avctx->frame_number++; } if (ret < 0 || !*got_packet_ptr) diff --git a/libavcodec/error_resilience.c b/libavcodec/error_resilience.c index 35d0c609e..ca2287198 100644 --- a/libavcodec/error_resilience.c +++ b/libavcodec/error_resilience.c @@ -1121,6 +1121,8 @@ void ff_er_frame_end(ERContext *s) av_log(s->avctx, AV_LOG_INFO, "concealing %d DC, %d AC, %d MV errors in %c frame\n", dc_error, ac_error, mv_error, av_get_picture_type_char(s->cur_pic.f->pict_type)); + s->cur_pic.f->decode_error_flags |= FF_DECODE_ERROR_CONCEALMENT_ACTIVE; + is_intra_likely = is_intra_more_likely(s); /* set unknown mb-type to most likely */ diff --git a/libavcodec/extract_extradata_bsf.c b/libavcodec/extract_extradata_bsf.c index 082b3e749..17e5deb96 100644 --- a/libavcodec/extract_extradata_bsf.c +++ b/libavcodec/extract_extradata_bsf.c @@ -24,6 +24,8 @@ #include "libavutil/opt.h" #include "avcodec.h" +#include "av1.h" +#include "av1_parse.h" #include "bsf.h" #include "h2645_parse.h" #include "h264.h" @@ -36,6 +38,9 @@ typedef struct ExtractExtradataContext { int (*extract)(AVBSFContext *ctx, AVPacket *pkt, uint8_t **data, int *size); + /* AV1 specifc fields */ + AV1Packet av1_pkt; + /* H264/HEVC specifc fields */ H2645Packet h2645_pkt; @@ -52,6 +57,80 @@ static int val_in_array(const int *arr, int len, int val) return 0; } +static int extract_extradata_av1(AVBSFContext *ctx, AVPacket *pkt, + uint8_t **data, int *size) +{ + static const int extradata_obu_types[] = { + AV1_OBU_SEQUENCE_HEADER, AV1_OBU_METADATA, + }; + ExtractExtradataContext *s = ctx->priv_data; + + int extradata_size = 0, filtered_size = 0; + int nb_extradata_obu_types = FF_ARRAY_ELEMS(extradata_obu_types); + int i, has_seq = 0, ret = 0; + + ret = ff_av1_packet_split(&s->av1_pkt, pkt->data, pkt->size, ctx); + if (ret < 0) + return ret; + + for (i = 0; i < s->av1_pkt.nb_obus; i++) { + AV1OBU *obu = &s->av1_pkt.obus[i]; + if (val_in_array(extradata_obu_types, nb_extradata_obu_types, obu->type)) { + extradata_size += obu->raw_size; + if (obu->type == AV1_OBU_SEQUENCE_HEADER) + has_seq = 1; + } else if (s->remove) { + filtered_size += obu->raw_size; + } + } + + if (extradata_size && has_seq) { + AVBufferRef *filtered_buf; + uint8_t *extradata, *filtered_data; + + if (s->remove) { + filtered_buf = av_buffer_alloc(filtered_size + AV_INPUT_BUFFER_PADDING_SIZE); + if (!filtered_buf) { + return AVERROR(ENOMEM); + } + memset(filtered_buf->data + filtered_size, 0, AV_INPUT_BUFFER_PADDING_SIZE); + + filtered_data = filtered_buf->data; + } + + extradata = av_malloc(extradata_size + AV_INPUT_BUFFER_PADDING_SIZE); + if (!extradata) { + av_buffer_unref(&filtered_buf); + return AVERROR(ENOMEM); + } + memset(extradata + extradata_size, 0, AV_INPUT_BUFFER_PADDING_SIZE); + + *data = extradata; + *size = extradata_size; + + for (i = 0; i < s->av1_pkt.nb_obus; i++) { + AV1OBU *obu = &s->av1_pkt.obus[i]; + if (val_in_array(extradata_obu_types, nb_extradata_obu_types, + obu->type)) { + memcpy(extradata, obu->raw_data, obu->raw_size); + extradata += obu->raw_size; + } else if (s->remove) { + memcpy(filtered_data, obu->raw_data, obu->raw_size); + filtered_data += obu->raw_size; + } + } + + if (s->remove) { + av_buffer_unref(&pkt->buf); + pkt->buf = filtered_buf; + pkt->data = filtered_buf->data; + pkt->size = filtered_size; + } + } + + return 0; +} + static int extract_extradata_h2645(AVBSFContext *ctx, AVPacket *pkt, uint8_t **data, int *size) { @@ -78,7 +157,7 @@ static int extract_extradata_h2645(AVBSFContext *ctx, AVPacket *pkt, } ret = ff_h2645_packet_split(&s->h2645_pkt, pkt->data, pkt->size, - ctx, 0, 0, ctx->par_in->codec_id, 1); + ctx, 0, 0, ctx->par_in->codec_id, 1, 0); if (ret < 0) return ret; @@ -251,6 +330,8 @@ static const struct { int (*extract)(AVBSFContext *ctx, AVPacket *pkt, uint8_t **data, int *size); } extract_tab[] = { + { AV_CODEC_ID_AV1, extract_extradata_av1 }, + { AV_CODEC_ID_AVS2, extract_extradata_mpeg4 }, { AV_CODEC_ID_CAVS, extract_extradata_mpeg4 }, { AV_CODEC_ID_H264, extract_extradata_h2645 }, { AV_CODEC_ID_HEVC, extract_extradata_h2645 }, @@ -311,10 +392,13 @@ fail: static void extract_extradata_close(AVBSFContext *ctx) { ExtractExtradataContext *s = ctx->priv_data; + ff_av1_packet_uninit(&s->av1_pkt); ff_h2645_packet_uninit(&s->h2645_pkt); } static const enum AVCodecID codec_ids[] = { + AV_CODEC_ID_AV1, + AV_CODEC_ID_AVS2, AV_CODEC_ID_CAVS, AV_CODEC_ID_H264, AV_CODEC_ID_HEVC, diff --git a/libavcodec/fft_template.c b/libavcodec/fft_template.c index 6c77854e4..20a62e429 100644 --- a/libavcodec/fft_template.c +++ b/libavcodec/fft_template.c @@ -261,17 +261,41 @@ av_cold int ff_fft_init(FFTContext *s, int nbits, int inverse) if (s->fft_permutation == FF_FFT_PERM_AVX) { fft_perm_avx(s); } else { - for(i=0; ifft_permutation == FF_FFT_PERM_SWAP_LSBS) - j = (j&~3) | ((j>>1)&1) | ((j<<1)&2); - k = -split_radix_permutation(i, n, s->inverse) & (n-1); - if (s->revtab) - s->revtab[k] = j; - if (s->revtab32) - s->revtab32[k] = j; - } +#define PROCESS_FFT_PERM_SWAP_LSBS(num) do {\ + for(i = 0; i < n; i++) {\ + int k;\ + j = i;\ + j = (j & ~3) | ((j >> 1) & 1) | ((j << 1) & 2);\ + k = -split_radix_permutation(i, n, s->inverse) & (n - 1);\ + s->revtab##num[k] = j;\ + } \ +} while(0); + +#define PROCESS_FFT_PERM_DEFAULT(num) do {\ + for(i = 0; i < n; i++) {\ + int k;\ + j = i;\ + k = -split_radix_permutation(i, n, s->inverse) & (n - 1);\ + s->revtab##num[k] = j;\ + } \ +} while(0); + +#define SPLIT_RADIX_PERMUTATION(num) do { \ + if (s->fft_permutation == FF_FFT_PERM_SWAP_LSBS) {\ + PROCESS_FFT_PERM_SWAP_LSBS(num) \ + } else {\ + PROCESS_FFT_PERM_DEFAULT(num) \ + }\ +} while(0); + + if (s->revtab) + SPLIT_RADIX_PERMUTATION() + if (s->revtab32) + SPLIT_RADIX_PERMUTATION(32) + +#undef PROCESS_FFT_PERM_DEFAULT +#undef PROCESS_FFT_PERM_SWAP_LSBS +#undef SPLIT_RADIX_PERMUTATION } return 0; @@ -523,9 +547,11 @@ static void name(FFTComplex *z, const FFTSample *wre, unsigned int n)\ } PASS(pass) +#if !CONFIG_SMALL #undef BUTTERFLIES #define BUTTERFLIES BUTTERFLIES_BIG PASS(pass_big) +#endif #define DECL_FFT(n,n2,n4)\ static void fft##n(FFTComplex *z)\ diff --git a/libavcodec/ffv1.h b/libavcodec/ffv1.h index 653138b07..f0bb19350 100644 --- a/libavcodec/ffv1.h +++ b/libavcodec/ffv1.h @@ -153,9 +153,7 @@ static av_always_inline int fold(int diff, int bits) if (bits == 8) diff = (int8_t)diff; else { - diff += 1 << (bits - 1); - diff = av_mod_uintp2(diff, bits); - diff -= 1 << (bits - 1); + diff = sign_extend(diff, bits); } return diff; @@ -176,19 +174,13 @@ static inline void update_vlc_state(VlcState *const state, const int v) count++; if (drift <= -count) { - if (state->bias > -128) - state->bias--; + state->bias = FFMAX(state->bias - 1, -128); - drift += count; - if (drift <= -count) - drift = -count + 1; + drift = FFMAX(drift + count, -count + 1); } else if (drift > 0) { - if (state->bias < 127) - state->bias++; + state->bias = FFMIN(state->bias + 1, 127); - drift -= count; - if (drift > 0) - drift = 0; + drift = FFMIN(drift - count, 0); } state->drift = drift; diff --git a/libavcodec/ffv1dec.c b/libavcodec/ffv1dec.c index 7658a5168..261e0cf70 100644 --- a/libavcodec/ffv1dec.c +++ b/libavcodec/ffv1dec.c @@ -546,8 +546,14 @@ static int read_header(FFV1Context *f) f->ac = get_symbol(c, state, 0); if (f->ac == AC_RANGE_CUSTOM_TAB) { - for (i = 1; i < 256; i++) - f->state_transition[i] = get_symbol(c, state, 1) + c->one_state[i]; + for (i = 1; i < 256; i++) { + int st = get_symbol(c, state, 1) + c->one_state[i]; + if (st < 1 || st > 255) { + av_log(f->avctx, AV_LOG_ERROR, "invalid state transition %d\n", st); + return AVERROR_INVALIDDATA; + } + f->state_transition[i] = st; + } } colorspace = get_symbol(c, state, 0); //YUV cs type diff --git a/libavcodec/ffv1dec_template.c b/libavcodec/ffv1dec_template.c index f8a42a6d4..0b1d176ba 100644 --- a/libavcodec/ffv1dec_template.c +++ b/libavcodec/ffv1dec_template.c @@ -50,6 +50,11 @@ static av_always_inline int RENAME(decode_line)(FFV1Context *s, int w, for (x = 0; x < w; x++) { int diff, context, sign; + if (!(x & 1023)) { + if (is_input_end(s)) + return AVERROR_INVALIDDATA; + } + context = RENAME(get_context)(p, sample[1] + x, sample[0] + x, sample[1] + x); if (context < 0) { context = -context; @@ -81,6 +86,19 @@ static av_always_inline int RENAME(decode_line)(FFV1Context *s, int w, run_mode = 2; } } + if (sample[1][x - 1] == sample[0][x - 1]) { + while (run_count > 1 && w-x > 1) { + sample[1][x] = sample[0][x]; + x++; + run_count--; + } + } else { + while (run_count > 1 && w-x > 1) { + sample[1][x] = RENAME(predict)(sample[1] + x, sample[0] + x); + x++; + run_count--; + } + } run_count--; if (run_count < 0) { run_mode = 0; @@ -107,7 +125,7 @@ static av_always_inline int RENAME(decode_line)(FFV1Context *s, int w, return 0; } -static void RENAME(decode_rgb_frame)(FFV1Context *s, uint8_t *src[4], int w, int h, int stride[4]) +static int RENAME(decode_rgb_frame)(FFV1Context *s, uint8_t *src[4], int w, int h, int stride[4]) { int x, y, p; TYPE *sample[4][2]; @@ -127,6 +145,7 @@ static void RENAME(decode_rgb_frame)(FFV1Context *s, uint8_t *src[4], int w, int for (y = 0; y < h; y++) { for (p = 0; p < 3 + transparency; p++) { + int ret; TYPE *temp = sample[p][0]; // FIXME: try a normal buffer sample[p][0] = sample[p][1]; @@ -135,9 +154,11 @@ static void RENAME(decode_rgb_frame)(FFV1Context *s, uint8_t *src[4], int w, int sample[p][1][-1]= sample[p][0][0 ]; sample[p][0][ w]= sample[p][0][w-1]; if (lbd && s->slice_coding_mode == 0) - RENAME(decode_line)(s, w, sample[p], (p + 1)/2, 9); + ret = RENAME(decode_line)(s, w, sample[p], (p + 1)/2, 9); else - RENAME(decode_line)(s, w, sample[p], (p + 1)/2, bits + (s->slice_coding_mode != 1)); + ret = RENAME(decode_line)(s, w, sample[p], (p + 1)/2, bits + (s->slice_coding_mode != 1)); + if (ret < 0) + return ret; } for (x = 0; x < w; x++) { int g = sample[0][1][x]; @@ -168,4 +189,5 @@ static void RENAME(decode_rgb_frame)(FFV1Context *s, uint8_t *src[4], int w, int } } } + return 0; } diff --git a/libavcodec/ffv1enc.c b/libavcodec/ffv1enc.c index 23e8d3dfa..796d81f7c 100644 --- a/libavcodec/ffv1enc.c +++ b/libavcodec/ffv1enc.c @@ -123,7 +123,7 @@ static const uint8_t ver2_state[256] = { 40, 40, 41, 79, 43, 44, 45, 45, 48, 48, 64, 50, 51, 52, 88, 52, 53, 74, 55, 57, 58, 58, 74, 60, 101, 61, 62, 84, 66, 66, 68, 69, 87, 82, 71, 97, 73, 73, 82, 75, 111, 77, 94, 78, 87, 81, 83, 97, - 85, 83, 94, 86, 99, 89, 90, 99, 111, 92, 93, 134, 95, 98, 105, 98, + 85, 83, 94, 86, 99, 89, 90, 99, 111, 92, 93, 134, 95, 98, 105, 98, 105, 110, 102, 108, 102, 118, 103, 106, 106, 113, 109, 112, 114, 112, 116, 125, 115, 116, 117, 117, 126, 119, 125, 121, 121, 123, 145, 124, 126, 131, 127, 129, 165, 130, 132, 138, 133, 135, 145, 136, 137, 139, 146, 141, 143, 142, 144, 148, @@ -449,7 +449,7 @@ static int write_extradata(FFV1Context *f) put_symbol(c, state, f->intra = (f->avctx->gop_size < 2), 0); } - f->avctx->extradata_size = ff_rac_terminate(c); + f->avctx->extradata_size = ff_rac_terminate(c, 0); v = av_crc(av_crc_get_table(AV_CRC_32_IEEE), 0, f->avctx->extradata, f->avctx->extradata_size); AV_WL32(f->avctx->extradata + f->avctx->extradata_size, v); f->avctx->extradata_size += 4; @@ -624,7 +624,7 @@ FF_ENABLE_DEPRECATION_WARNINGS case AV_PIX_FMT_YUVA420P: s->chroma_planes = desc->nb_components < 3 ? 0 : 1; s->colorspace = 0; - s->transparency = desc->nb_components == 4 || desc->nb_components == 2; + s->transparency = !!(desc->flags & AV_PIX_FMT_FLAG_ALPHA); if (!avctx->bits_per_raw_sample && !s->bits_per_raw_sample) s->bits_per_raw_sample = 8; else if (!s->bits_per_raw_sample) @@ -676,7 +676,7 @@ FF_ENABLE_DEPRECATION_WARNINGS s->bits_per_raw_sample = 16; else if (!s->bits_per_raw_sample) s->bits_per_raw_sample = avctx->bits_per_raw_sample; - s->transparency = desc->nb_components == 4 || desc->nb_components == 2; + s->transparency = !!(desc->flags & AV_PIX_FMT_FLAG_ALPHA); s->colorspace = 1; s->chroma_planes = 1; if (s->bits_per_raw_sample >= 16) { @@ -1065,9 +1065,7 @@ retry: encode_slice_header(f, fs); } if (fs->ac == AC_GOLOMB_RICE) { - if (f->version > 2) - put_rac(&fs->c, (uint8_t[]) { 129 }, 0); - fs->ac_byte_count = f->version > 2 || (!x && !y) ? ff_rac_terminate(&fs->c) : 0; + fs->ac_byte_count = f->version > 2 || (!x && !y) ? ff_rac_terminate(&fs->c, f->version > 2) : 0; init_put_bits(&fs->pb, fs->c.bytestream_start + fs->ac_byte_count, fs->c.bytestream_end - fs->c.bytestream_start - fs->ac_byte_count); @@ -1232,9 +1230,7 @@ FF_ENABLE_DEPRECATION_WARNINGS int bytes; if (fs->ac != AC_GOLOMB_RICE) { - uint8_t state = 129; - put_rac(&fs->c, &state, 0); - bytes = ff_rac_terminate(&fs->c); + bytes = ff_rac_terminate(&fs->c, 1); } else { flush_put_bits(&fs->pb); // FIXME: nicer padding bytes = fs->ac_byte_count + (put_bits_count(&fs->pb) + 7) / 8; diff --git a/libavcodec/ffwavesynth.c b/libavcodec/ffwavesynth.c index 9d055e401..cfd0951d8 100644 --- a/libavcodec/ffwavesynth.c +++ b/libavcodec/ffwavesynth.c @@ -113,18 +113,12 @@ static uint32_t lcg_next(uint32_t *s) return *s; } -static void lcg_seek(uint32_t *s, int64_t dt) +static void lcg_seek(uint32_t *s, uint32_t dt) { uint32_t a, c, t = *s; - if (dt >= 0) { - a = LCG_A; - c = LCG_C; - } else { /* coefficients for a step backward */ - a = LCG_AI; - c = (uint32_t)(LCG_AI * LCG_C); - dt = -dt; - } + a = LCG_A; + c = LCG_C; while (dt) { if (dt & 1) t = a * t + c; @@ -221,12 +215,12 @@ static void wavesynth_seek(struct wavesynth_context *ws, int64_t ts) ws->next_inter = i; ws->next_ts = i < ws->nb_inter ? ws->inter[i].ts_start : INF_TS; *last = -1; - lcg_seek(&ws->dither_state, ts - ws->cur_ts); + lcg_seek(&ws->dither_state, (uint32_t)ts - (uint32_t)ws->cur_ts); if (ws->pink_need) { int64_t pink_ts_cur = (ws->cur_ts + PINK_UNIT - 1) & ~(PINK_UNIT - 1); int64_t pink_ts_next = ts & ~(PINK_UNIT - 1); int pos = ts & (PINK_UNIT - 1); - lcg_seek(&ws->pink_state, (pink_ts_next - pink_ts_cur) << 1); + lcg_seek(&ws->pink_state, (pink_ts_next - pink_ts_cur) * 2); if (pos) { pink_fill(ws); ws->pink_pos = pos; @@ -253,7 +247,7 @@ static int wavesynth_parse_extradata(AVCodecContext *avc) edata_end = edata + avc->extradata_size; ws->nb_inter = AV_RL32(edata); edata += 4; - if (ws->nb_inter < 0) + if (ws->nb_inter < 0 || (edata_end - edata) / 24 < ws->nb_inter) return AVERROR(EINVAL); ws->inter = av_calloc(ws->nb_inter, sizeof(*ws->inter)); if (!ws->inter) @@ -267,13 +261,16 @@ static int wavesynth_parse_extradata(AVCodecContext *avc) in->type = AV_RL32(edata + 16); in->channels = AV_RL32(edata + 20); edata += 24; - if (in->ts_start < cur_ts || in->ts_end <= in->ts_start) + if (in->ts_start < cur_ts || + in->ts_end <= in->ts_start || + (uint64_t)in->ts_end - in->ts_start > INT64_MAX + ) return AVERROR(EINVAL); cur_ts = in->ts_start; dt = in->ts_end - in->ts_start; switch (in->type) { case WS_SINE: - if (edata_end - edata < 20) + if (edata_end - edata < 20 || avc->sample_rate <= 0) return AVERROR(EINVAL); f1 = AV_RL32(edata + 0); f2 = AV_RL32(edata + 4); @@ -304,8 +301,8 @@ static int wavesynth_parse_extradata(AVCodecContext *avc) default: return AVERROR(EINVAL); } - in->amp0 = (int64_t)a1 << 32; - in->damp = (((int64_t)a2 << 32) - ((int64_t)a1 << 32)) / dt; + in->amp0 = (uint64_t)a1 << 32; + in->damp = (int64_t)(((uint64_t)a2 << 32) - ((uint64_t)a1 << 32)) / dt; } if (edata != edata_end) return AVERROR(EINVAL); diff --git a/libavcodec/fic.c b/libavcodec/fic.c index b7b834596..540078eda 100644 --- a/libavcodec/fic.c +++ b/libavcodec/fic.c @@ -176,9 +176,11 @@ static int fic_decode_slice(AVCodecContext *avctx, void *tdata) int slice_h = tctx->slice_h; int src_size = tctx->src_size; int y_off = tctx->y_off; - int x, y, p; + int x, y, p, ret; - init_get_bits(&gb, src, src_size * 8); + ret = init_get_bits8(&gb, src, src_size); + if (ret < 0) + return ret; for (p = 0; p < 3; p++) { int stride = ctx->frame->linesize[p]; @@ -354,7 +356,7 @@ static int fic_decode_frame(AVCodecContext *avctx, void *data, sdata = src + tsize + FIC_HEADER_SIZE + 4 * nslices; msize = avpkt->size - nslices * 4 - tsize - FIC_HEADER_SIZE; - if (msize <= 0) { + if (msize <= ctx->aligned_width/8 * (ctx->aligned_height/8) / 8) { av_log(avctx, AV_LOG_ERROR, "Not enough frame data to decode.\n"); return AVERROR_INVALIDDATA; } @@ -474,7 +476,7 @@ static const AVOption options[] = { }; static const AVClass fic_decoder_class = { - .class_name = "FIC encoder", + .class_name = "FIC decoder", .item_name = av_default_item_name, .option = options, .version = LIBAVUTIL_VERSION_INT, diff --git a/libavcodec/filter_units_bsf.c b/libavcodec/filter_units_bsf.c index 1ee0afdf2..380f23e5a 100644 --- a/libavcodec/filter_units_bsf.c +++ b/libavcodec/filter_units_bsf.c @@ -98,63 +98,51 @@ invalid: return AVERROR(EINVAL); } -static int filter_units_filter(AVBSFContext *bsf, AVPacket *out) +static int filter_units_filter(AVBSFContext *bsf, AVPacket *pkt) { FilterUnitsContext *ctx = bsf->priv_data; CodedBitstreamFragment *frag = &ctx->fragment; - AVPacket *in = NULL; int err, i, j; - while (1) { - err = ff_bsf_get_packet(bsf, &in); - if (err < 0) - return err; + err = ff_bsf_get_packet_ref(bsf, pkt); + if (err < 0) + return err; - if (ctx->mode == NOOP) { - av_packet_move_ref(out, in); - av_packet_free(&in); - return 0; - } + if (ctx->mode == NOOP) + return 0; - err = ff_cbs_read_packet(ctx->cbc, frag, in); - if (err < 0) { - av_log(bsf, AV_LOG_ERROR, "Failed to read packet.\n"); - goto fail; - } - - for (i = 0; i < frag->nb_units; i++) { - for (j = 0; j < ctx->nb_types; j++) { - if (frag->units[i].type == ctx->type_list[j]) - break; - } - if (ctx->mode == REMOVE ? j < ctx->nb_types - : j >= ctx->nb_types) { - ff_cbs_delete_unit(ctx->cbc, frag, i); - --i; - } - } - - if (frag->nb_units > 0) - break; - - // Don't return packets with nothing in them. - av_packet_free(&in); - ff_cbs_fragment_uninit(ctx->cbc, frag); + err = ff_cbs_read_packet(ctx->cbc, frag, pkt); + if (err < 0) { + av_log(bsf, AV_LOG_ERROR, "Failed to read packet.\n"); + goto fail; } - err = ff_cbs_write_packet(ctx->cbc, out, frag); + for (i = frag->nb_units - 1; i >= 0; i--) { + for (j = 0; j < ctx->nb_types; j++) { + if (frag->units[i].type == ctx->type_list[j]) + break; + } + if (ctx->mode == REMOVE ? j < ctx->nb_types + : j >= ctx->nb_types) + ff_cbs_delete_unit(ctx->cbc, frag, i); + } + + if (frag->nb_units == 0) { + // Don't return packets with nothing in them. + err = AVERROR(EAGAIN); + goto fail; + } + + err = ff_cbs_write_packet(ctx->cbc, pkt, frag); if (err < 0) { av_log(bsf, AV_LOG_ERROR, "Failed to write packet.\n"); goto fail; } - err = av_packet_copy_props(out, in); - if (err < 0) - goto fail; - fail: - ff_cbs_fragment_uninit(ctx->cbc, frag); - av_packet_free(&in); + if (err < 0) + av_packet_unref(pkt); + ff_cbs_fragment_reset(ctx->cbc, frag); return err; } @@ -199,18 +187,18 @@ static int filter_units_init(AVBSFContext *bsf) ctx->cbc->nb_decompose_unit_types = 0; if (bsf->par_in->extradata) { - CodedBitstreamFragment ps; + CodedBitstreamFragment *frag = &ctx->fragment; - err = ff_cbs_read_extradata(ctx->cbc, &ps, bsf->par_in); + err = ff_cbs_read_extradata(ctx->cbc, frag, bsf->par_in); if (err < 0) { av_log(bsf, AV_LOG_ERROR, "Failed to read extradata.\n"); } else { - err = ff_cbs_write_extradata(ctx->cbc, bsf->par_out, &ps); + err = ff_cbs_write_extradata(ctx->cbc, bsf->par_out, frag); if (err < 0) av_log(bsf, AV_LOG_ERROR, "Failed to write extradata.\n"); } - ff_cbs_fragment_uninit(ctx->cbc, &ps); + ff_cbs_fragment_reset(ctx->cbc, frag); } return err; @@ -222,6 +210,7 @@ static void filter_units_close(AVBSFContext *bsf) av_freep(&ctx->type_list); + ff_cbs_fragment_free(ctx->cbc, &ctx->fragment); ff_cbs_close(&ctx->cbc); } diff --git a/libavcodec/fits.c b/libavcodec/fits.c index 365347fc6..ad73ab70d 100644 --- a/libavcodec/fits.c +++ b/libavcodec/fits.c @@ -138,6 +138,17 @@ int avpriv_fits_header_parse_line(void *avcl, FITSHeader *header, const uint8_t case STATE_BITPIX: CHECK_KEYWORD("BITPIX"); CHECK_VALUE("BITPIX", bitpix); + + switch(header->bitpix) { + case 8: + case 16: + case 32: case -32: + case 64: case -64: break; + default: + av_log(avcl, AV_LOG_ERROR, "invalid value of BITPIX %d\n", header->bitpix); \ + return AVERROR_INVALIDDATA; + } + dict_set_if_not_null(metadata, keyword, value); header->state = STATE_NAXIS; diff --git a/libavcodec/fitsdec.c b/libavcodec/fitsdec.c index b0753813c..4f452422e 100644 --- a/libavcodec/fitsdec.c +++ b/libavcodec/fitsdec.c @@ -143,7 +143,7 @@ static int fits_read_header(AVCodecContext *avctx, const uint8_t **ptr, FITSHead size = abs(header->bitpix) >> 3; for (i = 0; i < header->naxis; i++) { - if (header->naxisn[i] > SIZE_MAX / size) { + if (size && header->naxisn[i] > SIZE_MAX / size) { av_log(avctx, AV_LOG_ERROR, "unsupported size of FITS image"); return AVERROR_INVALIDDATA; } @@ -168,6 +168,14 @@ static int fits_read_header(AVCodecContext *avctx, const uint8_t **ptr, FITSHead header->data_min = (header->data_min - header->bzero) / header->bscale; header->data_max = (header->data_max - header->bzero) / header->bscale; } + if (!header->rgb && header->data_min >= header->data_max) { + if (header->data_min > header->data_max) { + av_log(avctx, AV_LOG_ERROR, "data min/max (%g %g) is invalid\n", header->data_min, header->data_max); + return AVERROR_INVALIDDATA; + } + av_log(avctx, AV_LOG_WARNING, "data min/max indicates a blank image\n"); + header->data_max ++; + } return 0; } diff --git a/libavcodec/flashsv.c b/libavcodec/flashsv.c index 90e1d43cd..92d1af9fc 100644 --- a/libavcodec/flashsv.c +++ b/libavcodec/flashsv.c @@ -132,7 +132,6 @@ static av_cold int flashsv_decode_init(AVCodecContext *avctx) s->frame = av_frame_alloc(); if (!s->frame) { - flashsv_decode_end(avctx); return AVERROR(ENOMEM); } @@ -518,6 +517,7 @@ AVCodec ff_flashsv_decoder = { .close = flashsv_decode_end, .decode = flashsv_decode_frame, .capabilities = AV_CODEC_CAP_DR1, + .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, .pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_BGR24, AV_PIX_FMT_NONE }, }; #endif /* CONFIG_FLASHSV_DECODER */ @@ -551,7 +551,11 @@ static const uint32_t ff_flashsv2_default_palette[128] = { static av_cold int flashsv2_decode_init(AVCodecContext *avctx) { FlashSVContext *s = avctx->priv_data; - flashsv_decode_init(avctx); + int ret; + + ret = flashsv_decode_init(avctx); + if (ret < 0) + return ret; s->pal = ff_flashsv2_default_palette; s->ver = 2; @@ -581,6 +585,7 @@ AVCodec ff_flashsv2_decoder = { .close = flashsv2_decode_end, .decode = flashsv_decode_frame, .capabilities = AV_CODEC_CAP_DR1, + .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, .pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_BGR24, AV_PIX_FMT_NONE }, }; #endif /* CONFIG_FLASHSV2_DECODER */ diff --git a/libavcodec/flicvideo.c b/libavcodec/flicvideo.c index ba5bda48c..bf8ffeba4 100644 --- a/libavcodec/flicvideo.c +++ b/libavcodec/flicvideo.c @@ -175,7 +175,7 @@ static int flic_decode_frame_8BPP(AVCodecContext *avctx, int lines; int compressed_lines; int starting_line; - signed short line_packets; + int line_packets; int y_ptr; int byte_run; int pixel_skip; @@ -274,7 +274,7 @@ static int flic_decode_frame_8BPP(AVCodecContext *avctx, break; if (y_ptr > pixel_limit) return AVERROR_INVALIDDATA; - line_packets = bytestream2_get_le16(&g2); + line_packets = sign_extend(bytestream2_get_le16(&g2), 16); if ((line_packets & 0xC000) == 0xC000) { // line skip opcode line_packets = -line_packets; @@ -508,7 +508,7 @@ static int flic_decode_frame_15_16BPP(AVCodecContext *avctx, int lines; int compressed_lines; - signed short line_packets; + int line_packets; int y_ptr; int byte_run; int pixel_skip; @@ -572,7 +572,7 @@ static int flic_decode_frame_15_16BPP(AVCodecContext *avctx, break; if (y_ptr > pixel_limit) return AVERROR_INVALIDDATA; - line_packets = bytestream2_get_le16(&g2); + line_packets = sign_extend(bytestream2_get_le16(&g2), 16); if (line_packets < 0) { line_packets = -line_packets; if (line_packets > s->avctx->height) @@ -806,7 +806,7 @@ static int flic_decode_frame_24BPP(AVCodecContext *avctx, int lines; int compressed_lines; - signed short line_packets; + int line_packets; int y_ptr; int byte_run; int pixel_skip; @@ -870,7 +870,7 @@ static int flic_decode_frame_24BPP(AVCodecContext *avctx, break; if (y_ptr > pixel_limit) return AVERROR_INVALIDDATA; - line_packets = bytestream2_get_le16(&g2); + line_packets = sign_extend(bytestream2_get_le16(&g2), 16); if (line_packets < 0) { line_packets = -line_packets; if (line_packets > s->avctx->height) @@ -900,7 +900,7 @@ static int flic_decode_frame_24BPP(AVCodecContext *avctx, } else { if (bytestream2_tell(&g2) + 2*byte_run > stream_ptr_after_chunk) break; - CHECK_PIXEL_PTR(2 * byte_run); + CHECK_PIXEL_PTR(3 * byte_run); for (j = 0; j < byte_run; j++, pixel_countdown--) { pixel = bytestream2_get_le24(&g2); AV_WL24(&pixels[pixel_ptr], pixel); @@ -1024,14 +1024,7 @@ static int flic_decode_frame_24BPP(AVCodecContext *avctx, for (y_ptr = 0; y_ptr < s->frame->linesize[0] * s->avctx->height; y_ptr += s->frame->linesize[0]) { - pixel_countdown = s->avctx->width; - pixel_ptr = 0; - while (pixel_countdown > 0) { - pixel = bytestream2_get_le24(&g2); - AV_WL24(&pixels[y_ptr + pixel_ptr], pixel); - pixel_ptr += 3; - pixel_countdown--; - } + bytestream2_get_buffer(&g2, pixels + y_ptr, 3*s->avctx->width); if (s->avctx->width & 1) bytestream2_skip(&g2, 3); } diff --git a/libavcodec/fmvc.c b/libavcodec/fmvc.c index a06b90c6f..5bee96a18 100644 --- a/libavcodec/fmvc.c +++ b/libavcodec/fmvc.c @@ -402,6 +402,9 @@ static int decode_frame(AVCodecContext *avctx, void *data, AVFrame *frame = data; int ret, y, x; + if (avpkt->size < 8) + return AVERROR_INVALIDDATA; + if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) return ret; @@ -530,7 +533,7 @@ static av_cold int decode_init(AVCodecContext *avctx) switch (avctx->bits_per_coded_sample) { case 16: - avctx->pix_fmt = AV_PIX_FMT_RGB555; + avctx->pix_fmt = AV_PIX_FMT_RGB555LE; break; case 24: avctx->pix_fmt = AV_PIX_FMT_BGR24; diff --git a/libavcodec/frame_thread_encoder.c b/libavcodec/frame_thread_encoder.c index 5ff3f7863..55756c4c5 100644 --- a/libavcodec/frame_thread_encoder.c +++ b/libavcodec/frame_thread_encoder.c @@ -251,6 +251,23 @@ void ff_frame_thread_encoder_free(AVCodecContext *avctx){ pthread_join(c->worker[i], NULL); } + while (av_fifo_size(c->task_fifo) > 0) { + Task task; + AVFrame *frame; + av_fifo_generic_read(c->task_fifo, &task, sizeof(task), NULL); + frame = task.indata; + av_frame_free(&frame); + task.indata = NULL; + } + + for (i=0; ifinished_tasks[i].outdata != NULL) { + AVPacket *pkt = c->finished_tasks[i].outdata; + av_packet_free(&pkt); + c->finished_tasks[i].outdata = NULL; + } + } + pthread_mutex_destroy(&c->task_fifo_mutex); pthread_mutex_destroy(&c->finished_task_mutex); pthread_mutex_destroy(&c->buffer_mutex); diff --git a/libavcodec/g722dec.c b/libavcodec/g722dec.c index 000b591fe..7c270bc33 100644 --- a/libavcodec/g722dec.c +++ b/libavcodec/g722dec.c @@ -100,7 +100,9 @@ static int g722_decode_frame(AVCodecContext *avctx, void *data, return ret; out_buf = (int16_t *)frame->data[0]; - init_get_bits(&gb, avpkt->data, avpkt->size * 8); + ret = init_get_bits8(&gb, avpkt->data, avpkt->size); + if (ret < 0) + return ret; for (j = 0; j < avpkt->size; j++) { int ilow, ihigh, rlow, rhigh, dhigh; diff --git a/libavcodec/g723_1.h b/libavcodec/g723_1.h index f833af01c..d60d481e6 100644 --- a/libavcodec/g723_1.h +++ b/libavcodec/g723_1.h @@ -116,9 +116,7 @@ typedef struct FCBParam { int pulse_sign[PULSE_MAX]; } FCBParam; -typedef struct g723_1_context { - AVClass *class; - +typedef struct G723_1_ChannelContext { G723_1_Subframe subframe[4]; enum FrameType cur_frame_type; enum FrameType past_frame_type; @@ -144,8 +142,6 @@ typedef struct g723_1_context { int reflection_coef; int pf_gain; ///< formant postfilter ///< gain scaling unit memory - int postfilter; - int16_t audio[FRAME_LEN + LPC_ORDER + PITCH_MAX + 4]; /* encoder */ @@ -158,6 +154,13 @@ typedef struct g723_1_context { int16_t perf_iir_mem[LPC_ORDER]; ///< and iir memories int16_t harmonic_mem[PITCH_MAX]; +} G723_1_ChannelContext; + +typedef struct G723_1_Context { + AVClass *class; + int postfilter; + + G723_1_ChannelContext ch[2]; } G723_1_Context; diff --git a/libavcodec/g723_1_parser.c b/libavcodec/g723_1_parser.c new file mode 100644 index 000000000..0305ca329 --- /dev/null +++ b/libavcodec/g723_1_parser.c @@ -0,0 +1,60 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * G723_1 audio parser + */ + +#include "parser.h" +#include "g723_1.h" + +typedef struct G723_1ParseContext { + ParseContext pc; +} G723_1ParseContext; + +static int g723_1_parse(AVCodecParserContext *s1, AVCodecContext *avctx, + const uint8_t **poutbuf, int *poutbuf_size, + const uint8_t *buf, int buf_size) +{ + G723_1ParseContext *s = s1->priv_data; + ParseContext *pc = &s->pc; + int next = END_NOT_FOUND; + + if (buf_size > 0) + next = frame_size[buf[0] & 3] * FFMAX(1, avctx->channels); + + if (ff_combine_frame(pc, next, &buf, &buf_size) < 0 || !buf_size) { + *poutbuf = NULL; + *poutbuf_size = 0; + return buf_size; + } + + s1->duration = 240; + + *poutbuf = buf; + *poutbuf_size = buf_size; + return next; +} + +AVCodecParser ff_g723_1_parser = { + .codec_ids = { AV_CODEC_ID_G723_1 }, + .priv_data_size = sizeof(G723_1ParseContext), + .parser_parse = g723_1_parse, + .parser_close = ff_parse_close, +}; diff --git a/libavcodec/g723_1dec.c b/libavcodec/g723_1dec.c index ab952ec66..d8bc3f97a 100644 --- a/libavcodec/g723_1dec.c +++ b/libavcodec/g723_1dec.c @@ -42,18 +42,25 @@ static av_cold int g723_1_decode_init(AVCodecContext *avctx) { - G723_1_Context *p = avctx->priv_data; + G723_1_Context *s = avctx->priv_data; - avctx->channel_layout = AV_CH_LAYOUT_MONO; - avctx->sample_fmt = AV_SAMPLE_FMT_S16; - avctx->channels = 1; - p->pf_gain = 1 << 12; + avctx->sample_fmt = AV_SAMPLE_FMT_S16P; + if (avctx->channels < 1 || avctx->channels > 2) { + av_log(avctx, AV_LOG_ERROR, "Only mono and stereo are supported (requested channels: %d).\n", avctx->channels); + return AVERROR(EINVAL); + } + avctx->channel_layout = avctx->channels == 1 ? AV_CH_LAYOUT_MONO : AV_CH_LAYOUT_STEREO; + for (int ch = 0; ch < avctx->channels; ch++) { + G723_1_ChannelContext *p = &s->ch[ch]; - memcpy(p->prev_lsp, dc_lsp, LPC_ORDER * sizeof(*p->prev_lsp)); - memcpy(p->sid_lsp, dc_lsp, LPC_ORDER * sizeof(*p->sid_lsp)); + p->pf_gain = 1 << 12; - p->cng_random_seed = CNG_RANDOM_SEED; - p->past_frame_type = SID_FRAME; + memcpy(p->prev_lsp, dc_lsp, LPC_ORDER * sizeof(*p->prev_lsp)); + memcpy(p->sid_lsp, dc_lsp, LPC_ORDER * sizeof(*p->sid_lsp)); + + p->cng_random_seed = CNG_RANDOM_SEED; + p->past_frame_type = SID_FRAME; + } return 0; } @@ -65,14 +72,17 @@ static av_cold int g723_1_decode_init(AVCodecContext *avctx) * @param buf pointer to the input buffer * @param buf_size size of the input buffer */ -static int unpack_bitstream(G723_1_Context *p, const uint8_t *buf, +static int unpack_bitstream(G723_1_ChannelContext *p, const uint8_t *buf, int buf_size) { GetBitContext gb; int ad_cb_len; int temp, info_bits, i; + int ret; - init_get_bits(&gb, buf, buf_size * 8); + ret = init_get_bits8(&gb, buf, buf_size); + if (ret < 0) + return ret; /* Extract frame type and rate info */ info_bits = get_bits(&gb, 2); @@ -344,7 +354,7 @@ static void comp_ppf_gains(int lag, PPFParam *ppf, enum Rate cur_rate, * @param ppf pitch postfilter parameters * @param cur_rate current bitrate */ -static void comp_ppf_coeff(G723_1_Context *p, int offset, int pitch_lag, +static void comp_ppf_coeff(G723_1_ChannelContext *p, int offset, int pitch_lag, PPFParam *ppf, enum Rate cur_rate) { @@ -430,7 +440,7 @@ static void comp_ppf_coeff(G723_1_Context *p, int offset, int pitch_lag, * * @return residual interpolation index if voiced, 0 otherwise */ -static int comp_interp_index(G723_1_Context *p, int pitch_lag, +static int comp_interp_index(G723_1_ChannelContext *p, int pitch_lag, int *exc_eng, int *scale) { int offset = PITCH_MAX + 2 * SUBFRAME_LEN; @@ -529,7 +539,7 @@ static void residual_interp(int16_t *buf, int16_t *out, int lag, * @param buf postfiltered output vector * @param energy input energy coefficient */ -static void gain_scale(G723_1_Context *p, int16_t * buf, int energy) +static void gain_scale(G723_1_ChannelContext *p, int16_t * buf, int energy) { int num, denom, gain, bits1, bits2; int i; @@ -572,7 +582,7 @@ static void gain_scale(G723_1_Context *p, int16_t * buf, int energy) * @param buf input buffer * @param dst output buffer */ -static void formant_postfilter(G723_1_Context *p, int16_t *lpc, +static void formant_postfilter(G723_1_ChannelContext *p, int16_t *lpc, int16_t *buf, int16_t *dst) { int16_t filter_coef[2][LPC_ORDER]; @@ -655,7 +665,7 @@ static inline int cng_rand(int *state, int base) return (*state & 0x7FFF) * base >> 15; } -static int estimate_sid_gain(G723_1_Context *p) +static int estimate_sid_gain(G723_1_ChannelContext *p) { int i, shift, seg, seg2, t, val, val_add, x, y; @@ -715,7 +725,7 @@ static int estimate_sid_gain(G723_1_Context *p) return val; } -static void generate_noise(G723_1_Context *p) +static void generate_noise(G723_1_ChannelContext *p) { int i, j, idx, t; int off[SUBFRAMES]; @@ -843,7 +853,7 @@ static void generate_noise(G723_1_Context *p) static int g723_1_decode_frame(AVCodecContext *avctx, void *data, int *got_frame_ptr, AVPacket *avpkt) { - G723_1_Context *p = avctx->priv_data; + G723_1_Context *s = avctx->priv_data; AVFrame *frame = data; const uint8_t *buf = avpkt->data; int buf_size = avpkt->size; @@ -855,9 +865,8 @@ static int g723_1_decode_frame(AVCodecContext *avctx, void *data, int16_t acb_vector[SUBFRAME_LEN]; int16_t *out; int bad_frame = 0, i, j, ret; - int16_t *audio = p->audio; - if (buf_size < frame_size[dec_mode]) { + if (buf_size < frame_size[dec_mode] * avctx->channels) { if (buf_size) av_log(avctx, AV_LOG_WARNING, "Expected %d bytes, got %d - skipping packet\n", @@ -866,142 +875,148 @@ static int g723_1_decode_frame(AVCodecContext *avctx, void *data, return buf_size; } - if (unpack_bitstream(p, buf, buf_size) < 0) { - bad_frame = 1; - if (p->past_frame_type == ACTIVE_FRAME) - p->cur_frame_type = ACTIVE_FRAME; - else - p->cur_frame_type = UNTRANSMITTED_FRAME; - } - frame->nb_samples = FRAME_LEN; if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) return ret; - out = (int16_t *)frame->data[0]; + for (int ch = 0; ch < avctx->channels; ch++) { + G723_1_ChannelContext *p = &s->ch[ch]; + int16_t *audio = p->audio; - if (p->cur_frame_type == ACTIVE_FRAME) { - if (!bad_frame) - p->erased_frames = 0; - else if (p->erased_frames != 3) - p->erased_frames++; + if (unpack_bitstream(p, buf + ch * (buf_size / avctx->channels), + buf_size / avctx->channels) < 0) { + bad_frame = 1; + if (p->past_frame_type == ACTIVE_FRAME) + p->cur_frame_type = ACTIVE_FRAME; + else + p->cur_frame_type = UNTRANSMITTED_FRAME; + } - ff_g723_1_inverse_quant(cur_lsp, p->prev_lsp, p->lsp_index, bad_frame); - ff_g723_1_lsp_interpolate(lpc, cur_lsp, p->prev_lsp); + out = (int16_t *)frame->extended_data[ch]; - /* Save the lsp_vector for the next frame */ - memcpy(p->prev_lsp, cur_lsp, LPC_ORDER * sizeof(*p->prev_lsp)); + if (p->cur_frame_type == ACTIVE_FRAME) { + if (!bad_frame) + p->erased_frames = 0; + else if (p->erased_frames != 3) + p->erased_frames++; - /* Generate the excitation for the frame */ - memcpy(p->excitation, p->prev_excitation, - PITCH_MAX * sizeof(*p->excitation)); - if (!p->erased_frames) { - int16_t *vector_ptr = p->excitation + PITCH_MAX; + ff_g723_1_inverse_quant(cur_lsp, p->prev_lsp, p->lsp_index, bad_frame); + ff_g723_1_lsp_interpolate(lpc, cur_lsp, p->prev_lsp); - /* Update interpolation gain memory */ - p->interp_gain = fixed_cb_gain[(p->subframe[2].amp_index + - p->subframe[3].amp_index) >> 1]; - for (i = 0; i < SUBFRAMES; i++) { - gen_fcb_excitation(vector_ptr, &p->subframe[i], p->cur_rate, - p->pitch_lag[i >> 1], i); - ff_g723_1_gen_acb_excitation(acb_vector, - &p->excitation[SUBFRAME_LEN * i], - p->pitch_lag[i >> 1], - &p->subframe[i], p->cur_rate); - /* Get the total excitation */ - for (j = 0; j < SUBFRAME_LEN; j++) { - int v = av_clip_int16(vector_ptr[j] * 2); - vector_ptr[j] = av_clip_int16(v + acb_vector[j]); - } - vector_ptr += SUBFRAME_LEN; - } + /* Save the lsp_vector for the next frame */ + memcpy(p->prev_lsp, cur_lsp, LPC_ORDER * sizeof(*p->prev_lsp)); - vector_ptr = p->excitation + PITCH_MAX; - - p->interp_index = comp_interp_index(p, p->pitch_lag[1], - &p->sid_gain, &p->cur_gain); - - /* Perform pitch postfiltering */ - if (p->postfilter) { - i = PITCH_MAX; - for (j = 0; j < SUBFRAMES; i += SUBFRAME_LEN, j++) - comp_ppf_coeff(p, i, p->pitch_lag[j >> 1], - ppf + j, p->cur_rate); - - for (i = 0, j = 0; j < SUBFRAMES; i += SUBFRAME_LEN, j++) - ff_acelp_weighted_vector_sum(p->audio + LPC_ORDER + i, - vector_ptr + i, - vector_ptr + i + ppf[j].index, - ppf[j].sc_gain, - ppf[j].opt_gain, - 1 << 14, 15, SUBFRAME_LEN); - } else { - audio = vector_ptr - LPC_ORDER; - } - - /* Save the excitation for the next frame */ - memcpy(p->prev_excitation, p->excitation + FRAME_LEN, + /* Generate the excitation for the frame */ + memcpy(p->excitation, p->prev_excitation, PITCH_MAX * sizeof(*p->excitation)); - } else { - p->interp_gain = (p->interp_gain * 3 + 2) >> 2; - if (p->erased_frames == 3) { - /* Mute output */ - memset(p->excitation, 0, - (FRAME_LEN + PITCH_MAX) * sizeof(*p->excitation)); - memset(p->prev_excitation, 0, - PITCH_MAX * sizeof(*p->excitation)); - memset(frame->data[0], 0, - (FRAME_LEN + LPC_ORDER) * sizeof(int16_t)); - } else { - int16_t *buf = p->audio + LPC_ORDER; + if (!p->erased_frames) { + int16_t *vector_ptr = p->excitation + PITCH_MAX; - /* Regenerate frame */ - residual_interp(p->excitation, buf, p->interp_index, - p->interp_gain, &p->random_seed); + /* Update interpolation gain memory */ + p->interp_gain = fixed_cb_gain[(p->subframe[2].amp_index + + p->subframe[3].amp_index) >> 1]; + for (i = 0; i < SUBFRAMES; i++) { + gen_fcb_excitation(vector_ptr, &p->subframe[i], p->cur_rate, + p->pitch_lag[i >> 1], i); + ff_g723_1_gen_acb_excitation(acb_vector, + &p->excitation[SUBFRAME_LEN * i], + p->pitch_lag[i >> 1], + &p->subframe[i], p->cur_rate); + /* Get the total excitation */ + for (j = 0; j < SUBFRAME_LEN; j++) { + int v = av_clip_int16(vector_ptr[j] * 2); + vector_ptr[j] = av_clip_int16(v + acb_vector[j]); + } + vector_ptr += SUBFRAME_LEN; + } + + vector_ptr = p->excitation + PITCH_MAX; + + p->interp_index = comp_interp_index(p, p->pitch_lag[1], + &p->sid_gain, &p->cur_gain); + + /* Perform pitch postfiltering */ + if (s->postfilter) { + i = PITCH_MAX; + for (j = 0; j < SUBFRAMES; i += SUBFRAME_LEN, j++) + comp_ppf_coeff(p, i, p->pitch_lag[j >> 1], + ppf + j, p->cur_rate); + + for (i = 0, j = 0; j < SUBFRAMES; i += SUBFRAME_LEN, j++) + ff_acelp_weighted_vector_sum(p->audio + LPC_ORDER + i, + vector_ptr + i, + vector_ptr + i + ppf[j].index, + ppf[j].sc_gain, + ppf[j].opt_gain, + 1 << 14, 15, SUBFRAME_LEN); + } else { + audio = vector_ptr - LPC_ORDER; + } /* Save the excitation for the next frame */ - memcpy(p->prev_excitation, buf + (FRAME_LEN - PITCH_MAX), + memcpy(p->prev_excitation, p->excitation + FRAME_LEN, PITCH_MAX * sizeof(*p->excitation)); + } else { + p->interp_gain = (p->interp_gain * 3 + 2) >> 2; + if (p->erased_frames == 3) { + /* Mute output */ + memset(p->excitation, 0, + (FRAME_LEN + PITCH_MAX) * sizeof(*p->excitation)); + memset(p->prev_excitation, 0, + PITCH_MAX * sizeof(*p->excitation)); + memset(frame->data[0], 0, + (FRAME_LEN + LPC_ORDER) * sizeof(int16_t)); + } else { + int16_t *buf = p->audio + LPC_ORDER; + + /* Regenerate frame */ + residual_interp(p->excitation, buf, p->interp_index, + p->interp_gain, &p->random_seed); + + /* Save the excitation for the next frame */ + memcpy(p->prev_excitation, buf + (FRAME_LEN - PITCH_MAX), + PITCH_MAX * sizeof(*p->excitation)); + } } - } - p->cng_random_seed = CNG_RANDOM_SEED; - } else { - if (p->cur_frame_type == SID_FRAME) { - p->sid_gain = sid_gain_to_lsp_index(p->subframe[0].amp_index); - ff_g723_1_inverse_quant(p->sid_lsp, p->prev_lsp, p->lsp_index, 0); - } else if (p->past_frame_type == ACTIVE_FRAME) { - p->sid_gain = estimate_sid_gain(p); + p->cng_random_seed = CNG_RANDOM_SEED; + } else { + if (p->cur_frame_type == SID_FRAME) { + p->sid_gain = sid_gain_to_lsp_index(p->subframe[0].amp_index); + ff_g723_1_inverse_quant(p->sid_lsp, p->prev_lsp, p->lsp_index, 0); + } else if (p->past_frame_type == ACTIVE_FRAME) { + p->sid_gain = estimate_sid_gain(p); + } + + if (p->past_frame_type == ACTIVE_FRAME) + p->cur_gain = p->sid_gain; + else + p->cur_gain = (p->cur_gain * 7 + p->sid_gain) >> 3; + generate_noise(p); + ff_g723_1_lsp_interpolate(lpc, p->sid_lsp, p->prev_lsp); + /* Save the lsp_vector for the next frame */ + memcpy(p->prev_lsp, p->sid_lsp, LPC_ORDER * sizeof(*p->prev_lsp)); } - if (p->past_frame_type == ACTIVE_FRAME) - p->cur_gain = p->sid_gain; - else - p->cur_gain = (p->cur_gain * 7 + p->sid_gain) >> 3; - generate_noise(p); - ff_g723_1_lsp_interpolate(lpc, p->sid_lsp, p->prev_lsp); - /* Save the lsp_vector for the next frame */ - memcpy(p->prev_lsp, p->sid_lsp, LPC_ORDER * sizeof(*p->prev_lsp)); - } + p->past_frame_type = p->cur_frame_type; - p->past_frame_type = p->cur_frame_type; + memcpy(p->audio, p->synth_mem, LPC_ORDER * sizeof(*p->audio)); + for (i = LPC_ORDER, j = 0; j < SUBFRAMES; i += SUBFRAME_LEN, j++) + ff_celp_lp_synthesis_filter(p->audio + i, &lpc[j * LPC_ORDER], + audio + i, SUBFRAME_LEN, LPC_ORDER, + 0, 1, 1 << 12); + memcpy(p->synth_mem, p->audio + FRAME_LEN, LPC_ORDER * sizeof(*p->audio)); - memcpy(p->audio, p->synth_mem, LPC_ORDER * sizeof(*p->audio)); - for (i = LPC_ORDER, j = 0; j < SUBFRAMES; i += SUBFRAME_LEN, j++) - ff_celp_lp_synthesis_filter(p->audio + i, &lpc[j * LPC_ORDER], - audio + i, SUBFRAME_LEN, LPC_ORDER, - 0, 1, 1 << 12); - memcpy(p->synth_mem, p->audio + FRAME_LEN, LPC_ORDER * sizeof(*p->audio)); - - if (p->postfilter) { - formant_postfilter(p, lpc, p->audio, out); - } else { // if output is not postfiltered it should be scaled by 2 - for (i = 0; i < FRAME_LEN; i++) - out[i] = av_clip_int16(p->audio[LPC_ORDER + i] << 1); + if (s->postfilter) { + formant_postfilter(p, lpc, p->audio, out); + } else { // if output is not postfiltered it should be scaled by 2 + for (i = 0; i < FRAME_LEN; i++) + out[i] = av_clip_int16(p->audio[LPC_ORDER + i] << 1); + } } *got_frame_ptr = 1; - return frame_size[dec_mode]; + return frame_size[dec_mode] * avctx->channels; } #define OFFSET(x) offsetof(G723_1_Context, x) diff --git a/libavcodec/g723_1enc.c b/libavcodec/g723_1enc.c index 4a4525eda..592840566 100644 --- a/libavcodec/g723_1enc.c +++ b/libavcodec/g723_1enc.c @@ -42,7 +42,8 @@ static av_cold int g723_1_encode_init(AVCodecContext *avctx) { - G723_1_Context *p = avctx->priv_data; + G723_1_Context *s = avctx->priv_data; + G723_1_ChannelContext *p = &s->ch[0]; if (avctx->sample_rate != 8000) { av_log(avctx, AV_LOG_ERROR, "Only 8000Hz sample rate supported\n"); @@ -386,7 +387,7 @@ static void iir_filter(int16_t *fir_coef, int16_t *iir_coef, * @param flt_coef filter coefficients * @param unq_lpc unquantized lpc vector */ -static void perceptual_filter(G723_1_Context *p, int16_t *flt_coef, +static void perceptual_filter(G723_1_ChannelContext *p, int16_t *flt_coef, int16_t *unq_lpc, int16_t *buf) { int16_t vector[FRAME_LEN + LPC_ORDER]; @@ -635,7 +636,7 @@ static void synth_percept_filter(int16_t *qnt_lpc, int16_t *perf_lpc, * @param buf input signal * @param index the current subframe index */ -static void acb_search(G723_1_Context *p, int16_t *residual, +static void acb_search(G723_1_ChannelContext *p, int16_t *residual, int16_t *impulse_resp, const int16_t *buf, int index) { @@ -963,7 +964,7 @@ static void pack_fcb_param(G723_1_Subframe *subfrm, FCBParam *optim, * @param buf target vector * @param impulse_resp impulse response of the combined filter */ -static void fcb_search(G723_1_Context *p, int16_t *impulse_resp, +static void fcb_search(G723_1_ChannelContext *p, int16_t *impulse_resp, int16_t *buf, int index) { FCBParam optim; @@ -995,7 +996,7 @@ static void fcb_search(G723_1_Context *p, int16_t *impulse_resp, * @param frame output buffer * @param size size of the buffer */ -static int pack_bitstream(G723_1_Context *p, AVPacket *avpkt) +static int pack_bitstream(G723_1_ChannelContext *p, AVPacket *avpkt) { PutBitContext pb; int info_bits = 0; @@ -1056,7 +1057,8 @@ static int pack_bitstream(G723_1_Context *p, AVPacket *avpkt) static int g723_1_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, const AVFrame *frame, int *got_packet_ptr) { - G723_1_Context *p = avctx->priv_data; + G723_1_Context *s = avctx->priv_data; + G723_1_ChannelContext *p = &s->ch[0]; int16_t unq_lpc[LPC_ORDER * SUBFRAMES]; int16_t qnt_lpc[LPC_ORDER * SUBFRAMES]; int16_t cur_lsp[LPC_ORDER]; @@ -1189,6 +1191,11 @@ static int g723_1_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, return 0; } +static const AVCodecDefault defaults[] = { + { "b", "6300" }, + { NULL }, +}; + AVCodec ff_g723_1_encoder = { .name = "g723_1", .long_name = NULL_IF_CONFIG_SMALL("G.723.1"), @@ -1197,6 +1204,7 @@ AVCodec ff_g723_1_encoder = { .priv_data_size = sizeof(G723_1_Context), .init = g723_1_encode_init, .encode2 = g723_1_encode_frame, + .defaults = defaults, .sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_NONE }, diff --git a/libavcodec/g729_parser.c b/libavcodec/g729_parser.c index d13c99080..9982dbfff 100644 --- a/libavcodec/g729_parser.c +++ b/libavcodec/g729_parser.c @@ -48,6 +48,7 @@ static int g729_parse(AVCodecParserContext *s1, AVCodecContext *avctx, av_assert1(avctx->codec_id == AV_CODEC_ID_G729); /* FIXME: replace this heuristic block_size with more precise estimate */ s->block_size = (avctx->bit_rate < 8000) ? G729D_6K4_BLOCK_SIZE : G729_8K_BLOCK_SIZE; + s->block_size *= avctx->channels; s->duration = avctx->frame_size; } diff --git a/libavcodec/g729dec.c b/libavcodec/g729dec.c index 2e1bf18e4..2e4756b80 100644 --- a/libavcodec/g729dec.c +++ b/libavcodec/g729dec.c @@ -100,8 +100,6 @@ typedef struct { } G729FormatDescription; typedef struct { - AudioDSPContext adsp; - /// past excitation signal buffer int16_t exc_base[2*SUBFRAME_SIZE+PITCH_DELAY_MAX+INTERPOL_LEN]; @@ -152,7 +150,13 @@ typedef struct { /// high-pass filter data (past output) int16_t hpf_z[2]; -} G729Context; +} G729ChannelContext; + +typedef struct { + AudioDSPContext adsp; + + G729ChannelContext *channel_context; +} G729Context; static const G729FormatDescription format_g729_8k = { .ac_index_bits = {8,5}, @@ -268,8 +272,7 @@ static void g729d_get_new_exc( ff_celp_convolve_circ(fc_new, fc_cur, phase_filter[dstate], subframe_size); - for(i=0; i> 14; out[i] += (gain_code * fc_new[i] + 0x2000) >> 14; @@ -285,10 +288,10 @@ static void g729d_get_new_exc( */ static int g729d_onset_decision(int past_onset, const int16_t* past_gain_code) { - if((past_gain_code[0] >> 1) > past_gain_code[1]) + if ((past_gain_code[0] >> 1) > past_gain_code[1]) return 2; - else - return FFMAX(past_onset-1, 0); + + return FFMAX(past_onset-1, 0); } /** @@ -303,24 +306,25 @@ static int16_t g729d_voice_decision(int onset, int prev_voice_decision, const in { int i, low_gain_pitch_cnt, voice_decision; - if(past_gain_pitch[0] >= 14745) // 0.9 + if (past_gain_pitch[0] >= 14745) { // 0.9 voice_decision = DECISION_VOICE; - else if (past_gain_pitch[0] <= 9830) // 0.6 + } else if (past_gain_pitch[0] <= 9830) { // 0.6 voice_decision = DECISION_NOISE; - else + } else { voice_decision = DECISION_INTERMEDIATE; + } - for(i=0, low_gain_pitch_cnt=0; i<6; i++) - if(past_gain_pitch[i] < 9830) + for (i = 0, low_gain_pitch_cnt = 0; i < 6; i++) + if (past_gain_pitch[i] < 9830) low_gain_pitch_cnt++; - if(low_gain_pitch_cnt > 2 && !onset) + if (low_gain_pitch_cnt > 2 && !onset) voice_decision = DECISION_NOISE; - if(!onset && voice_decision > prev_voice_decision + 1) + if (!onset && voice_decision > prev_voice_decision + 1) voice_decision--; - if(onset && voice_decision < DECISION_VOICE) + if (onset && voice_decision < DECISION_VOICE) voice_decision++; return voice_decision; @@ -338,43 +342,53 @@ static int32_t scalarproduct_int16_c(const int16_t * v1, const int16_t * v2, int static av_cold int decoder_init(AVCodecContext * avctx) { - G729Context* ctx = avctx->priv_data; - int i,k; + G729Context *s = avctx->priv_data; + G729ChannelContext *ctx; + int c,i,k; - if (avctx->channels != 1) { - av_log(avctx, AV_LOG_ERROR, "Only mono sound is supported (requested channels: %d).\n", avctx->channels); + if (avctx->channels < 1 || avctx->channels > 2) { + av_log(avctx, AV_LOG_ERROR, "Only mono and stereo are supported (requested channels: %d).\n", avctx->channels); return AVERROR(EINVAL); } - avctx->sample_fmt = AV_SAMPLE_FMT_S16; + avctx->sample_fmt = AV_SAMPLE_FMT_S16P; /* Both 8kbit/s and 6.4kbit/s modes uses two subframes per frame. */ avctx->frame_size = SUBFRAME_SIZE << 1; - ctx->gain_coeff = 16384; // 1.0 in (1.14) + ctx = + s->channel_context = av_mallocz(sizeof(G729ChannelContext) * avctx->channels); + if (!ctx) + return AVERROR(ENOMEM); - for (k = 0; k < MA_NP + 1; k++) { - ctx->past_quantizer_outputs[k] = ctx->past_quantizer_output_buf[k]; - for (i = 1; i < 11; i++) - ctx->past_quantizer_outputs[k][i - 1] = (18717 * i) >> 3; + for (c = 0; c < avctx->channels; c++) { + ctx->gain_coeff = 16384; // 1.0 in (1.14) + + for (k = 0; k < MA_NP + 1; k++) { + ctx->past_quantizer_outputs[k] = ctx->past_quantizer_output_buf[k]; + for (i = 1; i < 11; i++) + ctx->past_quantizer_outputs[k][i - 1] = (18717 * i) >> 3; + } + + ctx->lsp[0] = ctx->lsp_buf[0]; + ctx->lsp[1] = ctx->lsp_buf[1]; + memcpy(ctx->lsp[0], lsp_init, 10 * sizeof(int16_t)); + + ctx->exc = &ctx->exc_base[PITCH_DELAY_MAX+INTERPOL_LEN]; + + ctx->pitch_delay_int_prev = PITCH_DELAY_MIN; + + /* random seed initialization */ + ctx->rand_value = 21845; + + /* quantized prediction error */ + for (i = 0; i < 4; i++) + ctx->quant_energy[i] = -14336; // -14 in (5.10) + + ctx++; } - ctx->lsp[0] = ctx->lsp_buf[0]; - ctx->lsp[1] = ctx->lsp_buf[1]; - memcpy(ctx->lsp[0], lsp_init, 10 * sizeof(int16_t)); - - ctx->exc = &ctx->exc_base[PITCH_DELAY_MAX+INTERPOL_LEN]; - - ctx->pitch_delay_int_prev = PITCH_DELAY_MIN; - - /* random seed initialization */ - ctx->rand_value = 21845; - - /* quantized prediction error */ - for(i=0; i<4; i++) - ctx->quant_energy[i] = -14336; // -14 in (5.10) - - ff_audiodsp_init(&ctx->adsp); - ctx->adsp.scalarproduct_int16 = scalarproduct_int16_c; + ff_audiodsp_init(&s->adsp); + s->adsp.scalarproduct_int16 = scalarproduct_int16_c; return 0; } @@ -387,12 +401,11 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame_ptr, int16_t *out_frame; GetBitContext gb; const G729FormatDescription *format; - int frame_erasure = 0; ///< frame erasure detected during decoding - int bad_pitch = 0; ///< parity check failed - int i; + int c, i; int16_t *tmp; G729Formats packet_type; - G729Context *ctx = avctx->priv_data; + G729Context *s = avctx->priv_data; + G729ChannelContext *ctx = s->channel_context; int16_t lp[2][11]; // (3.12) uint8_t ma_predictor; ///< switched MA predictor of LSP quantizer uint8_t quantizer_1st; ///< first stage vector of quantizer @@ -405,22 +418,20 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame_ptr, int16_t synth[SUBFRAME_SIZE+10]; // fixed-codebook vector int j, ret; int gain_before, gain_after; - int is_periodic = 0; // whether one of the subframes is declared as periodic or not AVFrame *frame = data; frame->nb_samples = SUBFRAME_SIZE<<1; if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) return ret; - out_frame = (int16_t*) frame->data[0]; - if (buf_size % 10 == 0) { + if (buf_size % (G729_8K_BLOCK_SIZE * avctx->channels) == 0) { packet_type = FORMAT_G729_8K; format = &format_g729_8k; //Reset voice decision ctx->onset = 0; ctx->voice_decision = DECISION_VOICE; av_log(avctx, AV_LOG_DEBUG, "Packet type: %s\n", "G.729 @ 8kbit/s"); - } else if (buf_size == 8) { + } else if (buf_size == G729D_6K4_BLOCK_SIZE * avctx->channels) { packet_type = FORMAT_G729D_6K4; format = &format_g729d_6k4; av_log(avctx, AV_LOG_DEBUG, "Packet type: %s\n", "G.729D @ 6.4kbit/s"); @@ -429,281 +440,302 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame_ptr, return AVERROR_INVALIDDATA; } - for (i=0; i < buf_size; i++) - frame_erasure |= buf[i]; - frame_erasure = !frame_erasure; + for (c = 0; c < avctx->channels; c++) { + int frame_erasure = 0; ///< frame erasure detected during decoding + int bad_pitch = 0; ///< parity check failed + int is_periodic = 0; ///< whether one of the subframes is declared as periodic or not + out_frame = (int16_t*)frame->data[c]; - init_get_bits(&gb, buf, 8*buf_size); + for (i = 0; i < buf_size; i++) + frame_erasure |= buf[i]; + frame_erasure = !frame_erasure; - ma_predictor = get_bits(&gb, 1); - quantizer_1st = get_bits(&gb, VQ_1ST_BITS); - quantizer_2nd_lo = get_bits(&gb, VQ_2ND_BITS); - quantizer_2nd_hi = get_bits(&gb, VQ_2ND_BITS); + init_get_bits(&gb, buf, 8*buf_size); - if(frame_erasure) - lsf_restore_from_previous(ctx->lsfq, ctx->past_quantizer_outputs, - ctx->ma_predictor_prev); - else { - lsf_decode(ctx->lsfq, ctx->past_quantizer_outputs, - ma_predictor, - quantizer_1st, quantizer_2nd_lo, quantizer_2nd_hi); - ctx->ma_predictor_prev = ma_predictor; - } - - tmp = ctx->past_quantizer_outputs[MA_NP]; - memmove(ctx->past_quantizer_outputs + 1, ctx->past_quantizer_outputs, - MA_NP * sizeof(int16_t*)); - ctx->past_quantizer_outputs[0] = tmp; - - ff_acelp_lsf2lsp(ctx->lsp[1], ctx->lsfq, 10); - - ff_acelp_lp_decode(&lp[0][0], &lp[1][0], ctx->lsp[1], ctx->lsp[0], 10); - - FFSWAP(int16_t*, ctx->lsp[1], ctx->lsp[0]); - - for (i = 0; i < 2; i++) { - int gain_corr_factor; - - uint8_t ac_index; ///< adaptive codebook index - uint8_t pulses_signs; ///< fixed-codebook vector pulse signs - int fc_indexes; ///< fixed-codebook indexes - uint8_t gc_1st_index; ///< gain codebook (first stage) index - uint8_t gc_2nd_index; ///< gain codebook (second stage) index - - ac_index = get_bits(&gb, format->ac_index_bits[i]); - if(!i && format->parity_bit) - bad_pitch = av_parity(ac_index >> 2) == get_bits1(&gb); - fc_indexes = get_bits(&gb, format->fc_indexes_bits); - pulses_signs = get_bits(&gb, format->fc_signs_bits); - gc_1st_index = get_bits(&gb, format->gc_1st_index_bits); - gc_2nd_index = get_bits(&gb, format->gc_2nd_index_bits); - - if (frame_erasure) - pitch_delay_3x = 3 * ctx->pitch_delay_int_prev; - else if(!i) { - if (bad_pitch) - pitch_delay_3x = 3 * ctx->pitch_delay_int_prev; - else - pitch_delay_3x = ff_acelp_decode_8bit_to_1st_delay3(ac_index); - } else { - int pitch_delay_min = av_clip(ctx->pitch_delay_int_prev - 5, - PITCH_DELAY_MIN, PITCH_DELAY_MAX - 9); - - if(packet_type == FORMAT_G729D_6K4) - pitch_delay_3x = ff_acelp_decode_4bit_to_2nd_delay3(ac_index, pitch_delay_min); - else - pitch_delay_3x = ff_acelp_decode_5_6_bit_to_2nd_delay3(ac_index, pitch_delay_min); - } - - /* Round pitch delay to nearest (used everywhere except ff_acelp_interpolate). */ - pitch_delay_int[i] = (pitch_delay_3x + 1) / 3; - if (pitch_delay_int[i] > PITCH_DELAY_MAX) { - av_log(avctx, AV_LOG_WARNING, "pitch_delay_int %d is too large\n", pitch_delay_int[i]); - pitch_delay_int[i] = PITCH_DELAY_MAX; - } + ma_predictor = get_bits(&gb, 1); + quantizer_1st = get_bits(&gb, VQ_1ST_BITS); + quantizer_2nd_lo = get_bits(&gb, VQ_2ND_BITS); + quantizer_2nd_hi = get_bits(&gb, VQ_2ND_BITS); if (frame_erasure) { - ctx->rand_value = g729_prng(ctx->rand_value); - fc_indexes = av_mod_uintp2(ctx->rand_value, format->fc_indexes_bits); - - ctx->rand_value = g729_prng(ctx->rand_value); - pulses_signs = ctx->rand_value; - } - - - memset(fc, 0, sizeof(int16_t) * SUBFRAME_SIZE); - switch (packet_type) { - case FORMAT_G729_8K: - ff_acelp_fc_pulse_per_track(fc, ff_fc_4pulses_8bits_tracks_13, - ff_fc_4pulses_8bits_track_4, - fc_indexes, pulses_signs, 3, 3); - break; - case FORMAT_G729D_6K4: - ff_acelp_fc_pulse_per_track(fc, ff_fc_2pulses_9bits_track1_gray, - ff_fc_2pulses_9bits_track2_gray, - fc_indexes, pulses_signs, 1, 4); - break; - } - - /* - This filter enhances harmonic components of the fixed-codebook vector to - improve the quality of the reconstructed speech. - - / fc_v[i], i < pitch_delay - fc_v[i] = < - \ fc_v[i] + gain_pitch * fc_v[i-pitch_delay], i >= pitch_delay - */ - ff_acelp_weighted_vector_sum(fc + pitch_delay_int[i], - fc + pitch_delay_int[i], - fc, 1 << 14, - av_clip(ctx->past_gain_pitch[0], SHARP_MIN, SHARP_MAX), - 0, 14, - SUBFRAME_SIZE - pitch_delay_int[i]); - - memmove(ctx->past_gain_pitch+1, ctx->past_gain_pitch, 5 * sizeof(int16_t)); - ctx->past_gain_code[1] = ctx->past_gain_code[0]; - - if (frame_erasure) { - ctx->past_gain_pitch[0] = (29491 * ctx->past_gain_pitch[0]) >> 15; // 0.90 (0.15) - ctx->past_gain_code[0] = ( 2007 * ctx->past_gain_code[0] ) >> 11; // 0.98 (0.11) - - gain_corr_factor = 0; + lsf_restore_from_previous(ctx->lsfq, ctx->past_quantizer_outputs, + ctx->ma_predictor_prev); } else { - if (packet_type == FORMAT_G729D_6K4) { - ctx->past_gain_pitch[0] = cb_gain_1st_6k4[gc_1st_index][0] + - cb_gain_2nd_6k4[gc_2nd_index][0]; - gain_corr_factor = cb_gain_1st_6k4[gc_1st_index][1] + - cb_gain_2nd_6k4[gc_2nd_index][1]; + lsf_decode(ctx->lsfq, ctx->past_quantizer_outputs, + ma_predictor, + quantizer_1st, quantizer_2nd_lo, quantizer_2nd_hi); + ctx->ma_predictor_prev = ma_predictor; + } - /* Without check below overflow can occur in ff_acelp_update_past_gain. - It is not issue for G.729, because gain_corr_factor in it's case is always - greater than 1024, while in G.729D it can be even zero. */ - gain_corr_factor = FFMAX(gain_corr_factor, 1024); -#ifndef G729_BITEXACT - gain_corr_factor >>= 1; -#endif + tmp = ctx->past_quantizer_outputs[MA_NP]; + memmove(ctx->past_quantizer_outputs + 1, ctx->past_quantizer_outputs, + MA_NP * sizeof(int16_t*)); + ctx->past_quantizer_outputs[0] = tmp; + + ff_acelp_lsf2lsp(ctx->lsp[1], ctx->lsfq, 10); + + ff_acelp_lp_decode(&lp[0][0], &lp[1][0], ctx->lsp[1], ctx->lsp[0], 10); + + FFSWAP(int16_t*, ctx->lsp[1], ctx->lsp[0]); + + for (i = 0; i < 2; i++) { + int gain_corr_factor; + + uint8_t ac_index; ///< adaptive codebook index + uint8_t pulses_signs; ///< fixed-codebook vector pulse signs + int fc_indexes; ///< fixed-codebook indexes + uint8_t gc_1st_index; ///< gain codebook (first stage) index + uint8_t gc_2nd_index; ///< gain codebook (second stage) index + + ac_index = get_bits(&gb, format->ac_index_bits[i]); + if (!i && format->parity_bit) + bad_pitch = av_parity(ac_index >> 2) == get_bits1(&gb); + fc_indexes = get_bits(&gb, format->fc_indexes_bits); + pulses_signs = get_bits(&gb, format->fc_signs_bits); + gc_1st_index = get_bits(&gb, format->gc_1st_index_bits); + gc_2nd_index = get_bits(&gb, format->gc_2nd_index_bits); + + if (frame_erasure) { + pitch_delay_3x = 3 * ctx->pitch_delay_int_prev; + } else if (!i) { + if (bad_pitch) { + pitch_delay_3x = 3 * ctx->pitch_delay_int_prev; + } else { + pitch_delay_3x = ff_acelp_decode_8bit_to_1st_delay3(ac_index); + } } else { - ctx->past_gain_pitch[0] = cb_gain_1st_8k[gc_1st_index][0] + - cb_gain_2nd_8k[gc_2nd_index][0]; - gain_corr_factor = cb_gain_1st_8k[gc_1st_index][1] + - cb_gain_2nd_8k[gc_2nd_index][1]; + int pitch_delay_min = av_clip(ctx->pitch_delay_int_prev - 5, + PITCH_DELAY_MIN, PITCH_DELAY_MAX - 9); + + if (packet_type == FORMAT_G729D_6K4) { + pitch_delay_3x = ff_acelp_decode_4bit_to_2nd_delay3(ac_index, pitch_delay_min); + } else { + pitch_delay_3x = ff_acelp_decode_5_6_bit_to_2nd_delay3(ac_index, pitch_delay_min); + } + } + + /* Round pitch delay to nearest (used everywhere except ff_acelp_interpolate). */ + pitch_delay_int[i] = (pitch_delay_3x + 1) / 3; + if (pitch_delay_int[i] > PITCH_DELAY_MAX) { + av_log(avctx, AV_LOG_WARNING, "pitch_delay_int %d is too large\n", pitch_delay_int[i]); + pitch_delay_int[i] = PITCH_DELAY_MAX; + } + + if (frame_erasure) { + ctx->rand_value = g729_prng(ctx->rand_value); + fc_indexes = av_mod_uintp2(ctx->rand_value, format->fc_indexes_bits); + + ctx->rand_value = g729_prng(ctx->rand_value); + pulses_signs = ctx->rand_value; + } + + + memset(fc, 0, sizeof(int16_t) * SUBFRAME_SIZE); + switch (packet_type) { + case FORMAT_G729_8K: + ff_acelp_fc_pulse_per_track(fc, ff_fc_4pulses_8bits_tracks_13, + ff_fc_4pulses_8bits_track_4, + fc_indexes, pulses_signs, 3, 3); + break; + case FORMAT_G729D_6K4: + ff_acelp_fc_pulse_per_track(fc, ff_fc_2pulses_9bits_track1_gray, + ff_fc_2pulses_9bits_track2_gray, + fc_indexes, pulses_signs, 1, 4); + break; } - /* Decode the fixed-codebook gain. */ - ctx->past_gain_code[0] = ff_acelp_decode_gain_code(&ctx->adsp, gain_corr_factor, - fc, MR_ENERGY, - ctx->quant_energy, - ma_prediction_coeff, - SUBFRAME_SIZE, 4); -#ifdef G729_BITEXACT /* - This correction required to get bit-exact result with - reference code, because gain_corr_factor in G.729D is - two times larger than in original G.729. + This filter enhances harmonic components of the fixed-codebook vector to + improve the quality of the reconstructed speech. - If bit-exact result is not issue then gain_corr_factor - can be simpler divided by 2 before call to g729_get_gain_code - instead of using correction below. + / fc_v[i], i < pitch_delay + fc_v[i] = < + \ fc_v[i] + gain_pitch * fc_v[i-pitch_delay], i >= pitch_delay */ - if (packet_type == FORMAT_G729D_6K4) { - gain_corr_factor >>= 1; - ctx->past_gain_code[0] >>= 1; + ff_acelp_weighted_vector_sum(fc + pitch_delay_int[i], + fc + pitch_delay_int[i], + fc, 1 << 14, + av_clip(ctx->past_gain_pitch[0], SHARP_MIN, SHARP_MAX), + 0, 14, + SUBFRAME_SIZE - pitch_delay_int[i]); + + memmove(ctx->past_gain_pitch+1, ctx->past_gain_pitch, 5 * sizeof(int16_t)); + ctx->past_gain_code[1] = ctx->past_gain_code[0]; + + if (frame_erasure) { + ctx->past_gain_pitch[0] = (29491 * ctx->past_gain_pitch[0]) >> 15; // 0.90 (0.15) + ctx->past_gain_code[0] = ( 2007 * ctx->past_gain_code[0] ) >> 11; // 0.98 (0.11) + + gain_corr_factor = 0; + } else { + if (packet_type == FORMAT_G729D_6K4) { + ctx->past_gain_pitch[0] = cb_gain_1st_6k4[gc_1st_index][0] + + cb_gain_2nd_6k4[gc_2nd_index][0]; + gain_corr_factor = cb_gain_1st_6k4[gc_1st_index][1] + + cb_gain_2nd_6k4[gc_2nd_index][1]; + + /* Without check below overflow can occur in ff_acelp_update_past_gain. + It is not issue for G.729, because gain_corr_factor in it's case is always + greater than 1024, while in G.729D it can be even zero. */ + gain_corr_factor = FFMAX(gain_corr_factor, 1024); + #ifndef G729_BITEXACT + gain_corr_factor >>= 1; + #endif + } else { + ctx->past_gain_pitch[0] = cb_gain_1st_8k[gc_1st_index][0] + + cb_gain_2nd_8k[gc_2nd_index][0]; + gain_corr_factor = cb_gain_1st_8k[gc_1st_index][1] + + cb_gain_2nd_8k[gc_2nd_index][1]; + } + + /* Decode the fixed-codebook gain. */ + ctx->past_gain_code[0] = ff_acelp_decode_gain_code(&s->adsp, gain_corr_factor, + fc, MR_ENERGY, + ctx->quant_energy, + ma_prediction_coeff, + SUBFRAME_SIZE, 4); + #ifdef G729_BITEXACT + /* + This correction required to get bit-exact result with + reference code, because gain_corr_factor in G.729D is + two times larger than in original G.729. + + If bit-exact result is not issue then gain_corr_factor + can be simpler divided by 2 before call to g729_get_gain_code + instead of using correction below. + */ + if (packet_type == FORMAT_G729D_6K4) { + gain_corr_factor >>= 1; + ctx->past_gain_code[0] >>= 1; + } + #endif } -#endif - } - ff_acelp_update_past_gain(ctx->quant_energy, gain_corr_factor, 2, frame_erasure); + ff_acelp_update_past_gain(ctx->quant_energy, gain_corr_factor, 2, frame_erasure); - /* Routine requires rounding to lowest. */ - ff_acelp_interpolate(ctx->exc + i * SUBFRAME_SIZE, - ctx->exc + i * SUBFRAME_SIZE - pitch_delay_3x / 3, - ff_acelp_interp_filter, 6, - (pitch_delay_3x % 3) << 1, - 10, SUBFRAME_SIZE); + /* Routine requires rounding to lowest. */ + ff_acelp_interpolate(ctx->exc + i * SUBFRAME_SIZE, + ctx->exc + i * SUBFRAME_SIZE - pitch_delay_3x / 3, + ff_acelp_interp_filter, 6, + (pitch_delay_3x % 3) << 1, + 10, SUBFRAME_SIZE); - ff_acelp_weighted_vector_sum(ctx->exc + i * SUBFRAME_SIZE, - ctx->exc + i * SUBFRAME_SIZE, fc, - (!ctx->was_periodic && frame_erasure) ? 0 : ctx->past_gain_pitch[0], - ( ctx->was_periodic && frame_erasure) ? 0 : ctx->past_gain_code[0], - 1 << 13, 14, SUBFRAME_SIZE); + ff_acelp_weighted_vector_sum(ctx->exc + i * SUBFRAME_SIZE, + ctx->exc + i * SUBFRAME_SIZE, fc, + (!ctx->was_periodic && frame_erasure) ? 0 : ctx->past_gain_pitch[0], + ( ctx->was_periodic && frame_erasure) ? 0 : ctx->past_gain_code[0], + 1 << 13, 14, SUBFRAME_SIZE); - memcpy(synth, ctx->syn_filter_data, 10 * sizeof(int16_t)); + memcpy(synth, ctx->syn_filter_data, 10 * sizeof(int16_t)); - if (ff_celp_lp_synthesis_filter( - synth+10, - &lp[i][1], - ctx->exc + i * SUBFRAME_SIZE, - SUBFRAME_SIZE, - 10, - 1, - 0, - 0x800)) - /* Overflow occurred, downscale excitation signal... */ - for (j = 0; j < 2 * SUBFRAME_SIZE + PITCH_DELAY_MAX + INTERPOL_LEN; j++) - ctx->exc_base[j] >>= 2; - - /* ... and make synthesis again. */ - if (packet_type == FORMAT_G729D_6K4) { - int16_t exc_new[SUBFRAME_SIZE]; - - ctx->onset = g729d_onset_decision(ctx->onset, ctx->past_gain_code); - ctx->voice_decision = g729d_voice_decision(ctx->onset, ctx->voice_decision, ctx->past_gain_pitch); - - g729d_get_new_exc(exc_new, ctx->exc + i * SUBFRAME_SIZE, fc, ctx->voice_decision, ctx->past_gain_code[0], SUBFRAME_SIZE); - - ff_celp_lp_synthesis_filter( - synth+10, - &lp[i][1], - exc_new, - SUBFRAME_SIZE, - 10, - 0, - 0, - 0x800); - } else { - ff_celp_lp_synthesis_filter( - synth+10, - &lp[i][1], - ctx->exc + i * SUBFRAME_SIZE, - SUBFRAME_SIZE, - 10, - 0, - 0, - 0x800); - } - /* Save data (without postfilter) for use in next subframe. */ - memcpy(ctx->syn_filter_data, synth+SUBFRAME_SIZE, 10 * sizeof(int16_t)); - - /* Calculate gain of unfiltered signal for use in AGC. */ - gain_before = 0; - for (j = 0; j < SUBFRAME_SIZE; j++) - gain_before += FFABS(synth[j+10]); - - /* Call postfilter and also update voicing decision for use in next frame. */ - ff_g729_postfilter( - &ctx->adsp, - &ctx->ht_prev_data, - &is_periodic, - &lp[i][0], - pitch_delay_int[0], - ctx->residual, - ctx->res_filter_data, - ctx->pos_filter_data, - synth+10, - SUBFRAME_SIZE); - - /* Calculate gain of filtered signal for use in AGC. */ - gain_after = 0; - for(j=0; jgain_coeff = ff_g729_adaptive_gain_control( - gain_before, - gain_after, + if (ff_celp_lp_synthesis_filter( synth+10, + &lp[i][1], + ctx->exc + i * SUBFRAME_SIZE, SUBFRAME_SIZE, - ctx->gain_coeff); + 10, + 1, + 0, + 0x800)) + /* Overflow occurred, downscale excitation signal... */ + for (j = 0; j < 2 * SUBFRAME_SIZE + PITCH_DELAY_MAX + INTERPOL_LEN; j++) + ctx->exc_base[j] >>= 2; - if (frame_erasure) - ctx->pitch_delay_int_prev = FFMIN(ctx->pitch_delay_int_prev + 1, PITCH_DELAY_MAX); - else - ctx->pitch_delay_int_prev = pitch_delay_int[i]; + /* ... and make synthesis again. */ + if (packet_type == FORMAT_G729D_6K4) { + int16_t exc_new[SUBFRAME_SIZE]; - memcpy(synth+8, ctx->hpf_z, 2*sizeof(int16_t)); - ff_acelp_high_pass_filter( - out_frame + i*SUBFRAME_SIZE, - ctx->hpf_f, - synth+10, - SUBFRAME_SIZE); - memcpy(ctx->hpf_z, synth+8+SUBFRAME_SIZE, 2*sizeof(int16_t)); + ctx->onset = g729d_onset_decision(ctx->onset, ctx->past_gain_code); + ctx->voice_decision = g729d_voice_decision(ctx->onset, ctx->voice_decision, ctx->past_gain_pitch); + + g729d_get_new_exc(exc_new, ctx->exc + i * SUBFRAME_SIZE, fc, ctx->voice_decision, ctx->past_gain_code[0], SUBFRAME_SIZE); + + ff_celp_lp_synthesis_filter( + synth+10, + &lp[i][1], + exc_new, + SUBFRAME_SIZE, + 10, + 0, + 0, + 0x800); + } else { + ff_celp_lp_synthesis_filter( + synth+10, + &lp[i][1], + ctx->exc + i * SUBFRAME_SIZE, + SUBFRAME_SIZE, + 10, + 0, + 0, + 0x800); + } + /* Save data (without postfilter) for use in next subframe. */ + memcpy(ctx->syn_filter_data, synth+SUBFRAME_SIZE, 10 * sizeof(int16_t)); + + /* Calculate gain of unfiltered signal for use in AGC. */ + gain_before = 0; + for (j = 0; j < SUBFRAME_SIZE; j++) + gain_before += FFABS(synth[j+10]); + + /* Call postfilter and also update voicing decision for use in next frame. */ + ff_g729_postfilter( + &s->adsp, + &ctx->ht_prev_data, + &is_periodic, + &lp[i][0], + pitch_delay_int[0], + ctx->residual, + ctx->res_filter_data, + ctx->pos_filter_data, + synth+10, + SUBFRAME_SIZE); + + /* Calculate gain of filtered signal for use in AGC. */ + gain_after = 0; + for (j = 0; j < SUBFRAME_SIZE; j++) + gain_after += FFABS(synth[j+10]); + + ctx->gain_coeff = ff_g729_adaptive_gain_control( + gain_before, + gain_after, + synth+10, + SUBFRAME_SIZE, + ctx->gain_coeff); + + if (frame_erasure) { + ctx->pitch_delay_int_prev = FFMIN(ctx->pitch_delay_int_prev + 1, PITCH_DELAY_MAX); + } else { + ctx->pitch_delay_int_prev = pitch_delay_int[i]; + } + + memcpy(synth+8, ctx->hpf_z, 2*sizeof(int16_t)); + ff_acelp_high_pass_filter( + out_frame + i*SUBFRAME_SIZE, + ctx->hpf_f, + synth+10, + SUBFRAME_SIZE); + memcpy(ctx->hpf_z, synth+8+SUBFRAME_SIZE, 2*sizeof(int16_t)); + } + + ctx->was_periodic = is_periodic; + + /* Save signal for use in next frame. */ + memmove(ctx->exc_base, ctx->exc_base + 2 * SUBFRAME_SIZE, (PITCH_DELAY_MAX+INTERPOL_LEN)*sizeof(int16_t)); + + buf += packet_type == FORMAT_G729_8K ? G729_8K_BLOCK_SIZE : G729D_6K4_BLOCK_SIZE; + ctx++; } - ctx->was_periodic = is_periodic; - - /* Save signal for use in next frame. */ - memmove(ctx->exc_base, ctx->exc_base + 2 * SUBFRAME_SIZE, (PITCH_DELAY_MAX+INTERPOL_LEN)*sizeof(int16_t)); - *got_frame_ptr = 1; - return packet_type == FORMAT_G729_8K ? 10 : 8; + return packet_type == FORMAT_G729_8K ? G729_8K_BLOCK_SIZE * avctx->channels : G729D_6K4_BLOCK_SIZE * avctx->channels; +} + +static av_cold int decode_close(AVCodecContext *avctx) +{ + G729Context *s = avctx->priv_data; + av_freep(&s->channel_context); + + return 0; } AVCodec ff_g729_decoder = { @@ -714,5 +746,6 @@ AVCodec ff_g729_decoder = { .priv_data_size = sizeof(G729Context), .init = decoder_init, .decode = decode_frame, + .close = decode_close, .capabilities = AV_CODEC_CAP_SUBFRAMES | AV_CODEC_CAP_DR1, }; diff --git a/libavcodec/gdv.c b/libavcodec/gdv.c index addd51309..a5ce6b799 100644 --- a/libavcodec/gdv.c +++ b/libavcodec/gdv.c @@ -72,56 +72,102 @@ static av_cold int gdv_decode_init(AVCodecContext *avctx) return 0; } +static void scaleup(uint8_t *dst, const uint8_t *src, int w) +{ + int x; + for (x = 0; x < w - 7; x+=8) { + dst[x + 0] = + dst[x + 1] = src[(x>>1) + 0]; + dst[x + 2] = + dst[x + 3] = src[(x>>1) + 1]; + dst[x + 4] = + dst[x + 5] = src[(x>>1) + 2]; + dst[x + 6] = + dst[x + 7] = src[(x>>1) + 3]; + } + for (; x < w; x++) { + dst[x] = src[(x>>1)]; + } +} + +static void scaleup_rev(uint8_t *dst, const uint8_t *src, int w) +{ + int x; + + for (x = w - 1; (x+1) & 7; x--) { + dst[x] = src[(x>>1)]; + } + for (x -= 7; x >= 0; x -= 8) { + dst[x + 6] = + dst[x + 7] = src[(x>>1) + 3]; + dst[x + 4] = + dst[x + 5] = src[(x>>1) + 2]; + dst[x + 2] = + dst[x + 3] = src[(x>>1) + 1]; + dst[x + 0] = + dst[x + 1] = src[(x>>1) + 0]; + } +} + +static void scaledown(uint8_t *dst, const uint8_t *src, int w) +{ + int x; + for (x = 0; x < w - 7; x+=8) { + dst[x + 0] = src[2*x + 0]; + dst[x + 1] = src[2*x + 2]; + dst[x + 2] = src[2*x + 4]; + dst[x + 3] = src[2*x + 6]; + dst[x + 4] = src[2*x + 8]; + dst[x + 5] = src[2*x +10]; + dst[x + 6] = src[2*x +12]; + dst[x + 7] = src[2*x +14]; + } + for (; x < w; x++) { + dst[x] = src[2*x]; + } +} + static void rescale(GDVContext *gdv, uint8_t *dst, int w, int h, int scale_v, int scale_h) { - int i, j, y, x; + int j, y; if ((gdv->scale_v == scale_v) && (gdv->scale_h == scale_h)) { return; } - if (gdv->scale_h && gdv->scale_v) { + if (gdv->scale_v) { for (j = 0; j < h; j++) { int y = h - j - 1; - for (i = 0; i < w; i++) { - int x = w - i - 1; - dst[PREAMBLE_SIZE + x + y * w] = dst[PREAMBLE_SIZE + (x>>1) + (y>>1) * (w>>1)]; - } + uint8_t *dst1 = dst + PREAMBLE_SIZE + y * w; + uint8_t *src1 = dst + PREAMBLE_SIZE + (y>>!!gdv->scale_h) * (w>>1); + + scaleup_rev(dst1, src1, w); } } else if (gdv->scale_h) { for (j = 0; j < h; j++) { int y = h - j - 1; - for (x = 0; x < w; x++) { - dst[PREAMBLE_SIZE + x + y * w] = dst[PREAMBLE_SIZE + x + (y>>1) * w]; - } - } - } else if (gdv->scale_v) { - for (j = 0; j < h; j++) { - int y = h - j - 1; - for (i = 0; i < w; i++) { - int x = w - i - 1; - dst[PREAMBLE_SIZE + x + y * w] = dst[PREAMBLE_SIZE + (x>>1) + y * (w>>1)]; - } + uint8_t *dst1 = dst + PREAMBLE_SIZE + y * w; + uint8_t *src1 = dst + PREAMBLE_SIZE + (y>>1) * w; + memcpy(dst1, src1, w); } } if (scale_h && scale_v) { for (y = 0; y < (h>>1); y++) { - for (x = 0; x < (w>>1); x++) { - dst[PREAMBLE_SIZE + x + y * (w>>1)] = dst[PREAMBLE_SIZE + x*2 + y*2 * w]; - } + uint8_t *dst1 = dst + PREAMBLE_SIZE + y * (w>>1); + uint8_t *src1 = dst + PREAMBLE_SIZE + y*2 * w; + scaledown(dst1, src1, w>>1); } } else if (scale_h) { for (y = 0; y < (h>>1); y++) { - for (x = 0; x < w; x++) { - dst[PREAMBLE_SIZE + x + y * w] = dst[PREAMBLE_SIZE + x + y*2 * w]; - } + uint8_t *dst1 = dst + PREAMBLE_SIZE + y * w; + uint8_t *src1 = dst + PREAMBLE_SIZE + y*2 * w; + memcpy(dst1, src1, w); } } else if (scale_v) { for (y = 0; y < h; y++) { - for (x = 0; x < (w>>1); x++) { - dst[PREAMBLE_SIZE + x + y * w] = dst[PREAMBLE_SIZE + x*2 + y * w]; - } + uint8_t *dst1 = dst + PREAMBLE_SIZE + y * w; + scaledown(dst1, dst1, w>>1); } } @@ -228,6 +274,10 @@ static int decompress_2(AVCodecContext *avctx) break; } } + + if (bytestream2_get_bytes_left_p(pb) > 0) + return AVERROR_INVALIDDATA; + return 0; } @@ -258,7 +308,7 @@ static int decompress_5(AVCodecContext *avctx, unsigned skip) int len; int b = bytestream2_get_byte(gb); if (b == 0) { - break; + return 0; } if (b != 0xFF) { len = b; @@ -273,6 +323,8 @@ static int decompress_5(AVCodecContext *avctx, unsigned skip) lz_copy(pb, g2, off, len); } } + if (bytestream2_get_bytes_left_p(pb) > 0) + return AVERROR_INVALIDDATA; return 0; } @@ -395,6 +447,9 @@ static int decompress_68(AVCodecContext *avctx, unsigned skip, unsigned use8) } } + if (bytestream2_get_bytes_left_p(pb) > 0) + return AVERROR_INVALIDDATA; + return 0; } @@ -425,6 +480,8 @@ static int gdv_decode_frame(AVCodecContext *avctx, void *data, if (pal && pal_size == AVPALETTE_SIZE) memcpy(gdv->pal, pal, AVPALETTE_SIZE); + if (compression < 2 && bytestream2_get_bytes_left(gb) < 256*3) + return AVERROR_INVALIDDATA; rescale(gdv, gdv->frame, avctx->width, avctx->height, !!(flags & 0x10), !!(flags & 0x20)); @@ -432,8 +489,6 @@ static int gdv_decode_frame(AVCodecContext *avctx, void *data, case 1: memset(gdv->frame + PREAMBLE_SIZE, 0, gdv->frame_size - PREAMBLE_SIZE); case 0: - if (bytestream2_get_bytes_left(gb) < 256*3) - return AVERROR_INVALIDDATA; for (i = 0; i < 256; i++) { unsigned r = bytestream2_get_byte(gb); unsigned g = bytestream2_get_byte(gb); @@ -458,34 +513,33 @@ static int gdv_decode_frame(AVCodecContext *avctx, void *data, default: av_assert0(0); } + if (ret < 0) + return ret; memcpy(frame->data[1], gdv->pal, AVPALETTE_SIZE); dst = frame->data[0]; if (!gdv->scale_v && !gdv->scale_h) { int sidx = PREAMBLE_SIZE, didx = 0; - int y, x; + int y; for (y = 0; y < avctx->height; y++) { - for (x = 0; x < avctx->width; x++) { - dst[x+didx] = gdv->frame[x+sidx]; - } + memcpy(dst + didx, gdv->frame + sidx, avctx->width); sidx += avctx->width; didx += frame->linesize[0]; } } else { int sidx = PREAMBLE_SIZE, didx = 0; - int y, x; + int y; for (y = 0; y < avctx->height; y++) { if (!gdv->scale_v) { - for (x = 0; x < avctx->width; x++) { - dst[didx + x] = gdv->frame[sidx + x]; - } + memcpy(dst + didx, gdv->frame + sidx, avctx->width); } else { - for (x = 0; x < avctx->width; x++) { - dst[didx + x] = gdv->frame[sidx + x/2]; - } + uint8_t *dst2 = dst + didx; + uint8_t *src2 = gdv->frame + sidx; + + scaleup(dst2, src2, avctx->width); } if (!gdv->scale_h || ((y & 1) == 1)) { sidx += !gdv->scale_v ? avctx->width : avctx->width/2; diff --git a/libavcodec/get_bits.h b/libavcodec/get_bits.h index 56ef5f0cb..c4ab60774 100644 --- a/libavcodec/get_bits.h +++ b/libavcodec/get_bits.h @@ -1,5 +1,6 @@ /* - * copyright (c) 2004 Michael Niedermayer + * Copyright (c) 2004 Michael Niedermayer + * Copyright (c) 2016 Alexandra Hájková * * This file is part of FFmpeg. * @@ -53,13 +54,25 @@ #define UNCHECKED_BITSTREAM_READER !CONFIG_SAFE_BITSTREAM_READER #endif +#ifndef CACHED_BITSTREAM_READER +#define CACHED_BITSTREAM_READER 0 +#endif + typedef struct GetBitContext { const uint8_t *buffer, *buffer_end; +#if CACHED_BITSTREAM_READER + uint64_t cache; + unsigned bits_left; +#endif int index; int size_in_bits; int size_in_bits_plus8; } GetBitContext; +static inline unsigned int get_bits(GetBitContext *s, int n); +static inline void skip_bits(GetBitContext *s, int n); +static inline unsigned int show_bits(GetBitContext *s, int n); + /* Bitstream reader API docs: * name * arbitrary name which is used as prefix for the internal variables @@ -107,12 +120,16 @@ typedef struct GetBitContext { * For examples see get_bits, show_bits, skip_bits, get_vlc. */ -#ifdef LONG_BITSTREAM_READER +#if CACHED_BITSTREAM_READER +# define MIN_CACHE_BITS 64 +#elif defined LONG_BITSTREAM_READER # define MIN_CACHE_BITS 32 #else # define MIN_CACHE_BITS 25 #endif +#if !CACHED_BITSTREAM_READER + #define OPEN_READER_NOSIZE(name, gb) \ unsigned int name ## _index = (gb)->index; \ unsigned int av_unused name ## _cache @@ -197,11 +214,73 @@ typedef struct GetBitContext { #define GET_CACHE(name, gb) ((uint32_t) name ## _cache) +#endif + static inline int get_bits_count(const GetBitContext *s) { +#if CACHED_BITSTREAM_READER + return s->index - s->bits_left; +#else return s->index; +#endif } +#if CACHED_BITSTREAM_READER +static inline void refill_32(GetBitContext *s, int is_le) +{ +#if !UNCHECKED_BITSTREAM_READER + if (s->index >> 3 >= s->buffer_end - s->buffer) + return; +#endif + + if (is_le) + s->cache = (uint64_t)AV_RL32(s->buffer + (s->index >> 3)) << s->bits_left | s->cache; + else + s->cache = s->cache | (uint64_t)AV_RB32(s->buffer + (s->index >> 3)) << (32 - s->bits_left); + s->index += 32; + s->bits_left += 32; +} + +static inline void refill_64(GetBitContext *s, int is_le) +{ +#if !UNCHECKED_BITSTREAM_READER + if (s->index >> 3 >= s->buffer_end - s->buffer) + return; +#endif + + if (is_le) + s->cache = AV_RL64(s->buffer + (s->index >> 3)); + else + s->cache = AV_RB64(s->buffer + (s->index >> 3)); + s->index += 64; + s->bits_left = 64; +} + +static inline uint64_t get_val(GetBitContext *s, unsigned n, int is_le) +{ + uint64_t ret; + av_assert2(n>0 && n<=63); + if (is_le) { + ret = s->cache & ((UINT64_C(1) << n) - 1); + s->cache >>= n; + } else { + ret = s->cache >> (64 - n); + s->cache <<= n; + } + s->bits_left -= n; + return ret; +} + +static inline unsigned show_val(const GetBitContext *s, unsigned n) +{ +#ifdef BITSTREAM_READER_LE + return s->cache & ((UINT64_C(1) << n) - 1); +#else + return s->cache >> (64 - n); +#endif +} +#endif + /** * Skips the specified number of bits. * @param n the number of bits to skip, @@ -211,13 +290,29 @@ static inline int get_bits_count(const GetBitContext *s) */ static inline void skip_bits_long(GetBitContext *s, int n) { +#if CACHED_BITSTREAM_READER + skip_bits(s, n); +#else #if UNCHECKED_BITSTREAM_READER s->index += n; #else s->index += av_clip(n, -s->index, s->size_in_bits_plus8 - s->index); #endif +#endif } +#if CACHED_BITSTREAM_READER +static inline void skip_remaining(GetBitContext *s, unsigned n) +{ +#ifdef BITSTREAM_READER_LE + s->cache >>= n; +#else + s->cache <<= n; +#endif + s->bits_left -= n; +} +#endif + /** * Read MPEG-1 dc-style VLC (sign bit + mantissa with no MSB). * if MSB not set it is negative @@ -225,6 +320,13 @@ static inline void skip_bits_long(GetBitContext *s, int n) */ static inline int get_xbits(GetBitContext *s, int n) { +#if CACHED_BITSTREAM_READER + int32_t cache = show_bits(s, 32); + int sign = ~cache >> 31; + skip_remaining(s, n); + + return ((((uint32_t)(sign ^ cache)) >> (32 - n)) ^ sign) - sign; +#else register int sign; register int32_t cache; OPEN_READER(re, s); @@ -235,8 +337,10 @@ static inline int get_xbits(GetBitContext *s, int n) LAST_SKIP_BITS(re, s, n); CLOSE_READER(re, s); return (NEG_USR32(sign ^ cache, n) ^ sign) - sign; +#endif } +#if !CACHED_BITSTREAM_READER static inline int get_xbits_le(GetBitContext *s, int n) { register int sign; @@ -250,16 +354,22 @@ static inline int get_xbits_le(GetBitContext *s, int n) CLOSE_READER(re, s); return (zero_extend(sign ^ cache, n) ^ sign) - sign; } +#endif static inline int get_sbits(GetBitContext *s, int n) { register int tmp; +#if CACHED_BITSTREAM_READER + av_assert2(n>0 && n<=25); + tmp = sign_extend(get_bits(s, n), n); +#else OPEN_READER(re, s); av_assert2(n>0 && n<=25); UPDATE_CACHE(re, s); tmp = SHOW_SBITS(re, s, n); LAST_SKIP_BITS(re, s, n); CLOSE_READER(re, s); +#endif return tmp; } @@ -268,13 +378,34 @@ static inline int get_sbits(GetBitContext *s, int n) */ static inline unsigned int get_bits(GetBitContext *s, int n) { - register int tmp; + register unsigned int tmp; +#if CACHED_BITSTREAM_READER + + av_assert2(n>0 && n<=32); + if (n > s->bits_left) { +#ifdef BITSTREAM_READER_LE + refill_32(s, 1); +#else + refill_32(s, 0); +#endif + if (s->bits_left < 32) + s->bits_left = n; + } + +#ifdef BITSTREAM_READER_LE + tmp = get_val(s, n, 1); +#else + tmp = get_val(s, n, 0); +#endif +#else OPEN_READER(re, s); av_assert2(n>0 && n<=25); UPDATE_CACHE(re, s); tmp = SHOW_UBITS(re, s, n); LAST_SKIP_BITS(re, s, n); CLOSE_READER(re, s); +#endif + av_assert2(tmp < UINT64_C(1) << n); return tmp; } @@ -288,6 +419,16 @@ static av_always_inline int get_bitsz(GetBitContext *s, int n) static inline unsigned int get_bits_le(GetBitContext *s, int n) { +#if CACHED_BITSTREAM_READER + av_assert2(n>0 && n<=32); + if (n > s->bits_left) { + refill_32(s, 1); + if (s->bits_left < 32) + s->bits_left = n; + } + + return get_val(s, n, 1); +#else register int tmp; OPEN_READER(re, s); av_assert2(n>0 && n<=25); @@ -296,6 +437,7 @@ static inline unsigned int get_bits_le(GetBitContext *s, int n) LAST_SKIP_BITS(re, s, n); CLOSE_READER(re, s); return tmp; +#endif } /** @@ -303,23 +445,72 @@ static inline unsigned int get_bits_le(GetBitContext *s, int n) */ static inline unsigned int show_bits(GetBitContext *s, int n) { - register int tmp; + register unsigned int tmp; +#if CACHED_BITSTREAM_READER + if (n > s->bits_left) +#ifdef BITSTREAM_READER_LE + refill_32(s, 1); +#else + refill_32(s, 0); +#endif + + tmp = show_val(s, n); +#else OPEN_READER_NOSIZE(re, s); av_assert2(n>0 && n<=25); UPDATE_CACHE(re, s); tmp = SHOW_UBITS(re, s, n); +#endif return tmp; } static inline void skip_bits(GetBitContext *s, int n) { +#if CACHED_BITSTREAM_READER + if (n < s->bits_left) + skip_remaining(s, n); + else { + n -= s->bits_left; + s->cache = 0; + s->bits_left = 0; + + if (n >= 64) { + unsigned skip = (n / 8) * 8; + + n -= skip; + s->index += skip; + } +#ifdef BITSTREAM_READER_LE + refill_64(s, 1); +#else + refill_64(s, 0); +#endif + if (n) + skip_remaining(s, n); + } +#else OPEN_READER(re, s); LAST_SKIP_BITS(re, s, n); CLOSE_READER(re, s); +#endif } static inline unsigned int get_bits1(GetBitContext *s) { +#if CACHED_BITSTREAM_READER + if (!s->bits_left) +#ifdef BITSTREAM_READER_LE + refill_64(s, 1); +#else + refill_64(s, 0); +#endif + +#ifdef BITSTREAM_READER_LE + return get_val(s, 1, 1); +#else + return get_val(s, 1, 0); +#endif +#else unsigned int index = s->index; uint8_t result = s->buffer[index >> 3]; #ifdef BITSTREAM_READER_LE @@ -336,6 +527,7 @@ static inline unsigned int get_bits1(GetBitContext *s) s->index = index; return result; +#endif } static inline unsigned int show_bits1(GetBitContext *s) @@ -356,6 +548,10 @@ static inline unsigned int get_bits_long(GetBitContext *s, int n) av_assert2(n>=0 && n<=32); if (!n) { return 0; +#if CACHED_BITSTREAM_READER + } + return get_bits(s, n); +#else } else if (n <= MIN_CACHE_BITS) { return get_bits(s, n); } else { @@ -367,6 +563,7 @@ static inline unsigned int get_bits_long(GetBitContext *s, int n) return ret | get_bits(s, n - 16); #endif } +#endif } /** @@ -422,16 +619,8 @@ static inline int check_marker(void *logctx, GetBitContext *s, const char *msg) return bit; } -/** - * Initialize GetBitContext. - * @param buffer bitstream buffer, must be AV_INPUT_BUFFER_PADDING_SIZE bytes - * larger than the actual read bits because some optimized bitstream - * readers read 32 or 64 bit at once and could read over the end - * @param bit_size the size of the buffer in bits - * @return 0 on success, AVERROR_INVALIDDATA if the buffer_size would overflow. - */ -static inline int init_get_bits(GetBitContext *s, const uint8_t *buffer, - int bit_size) +static inline int init_get_bits_xe(GetBitContext *s, const uint8_t *buffer, + int bit_size, int is_le) { int buffer_size; int ret = 0; @@ -450,9 +639,33 @@ static inline int init_get_bits(GetBitContext *s, const uint8_t *buffer, s->buffer_end = buffer + buffer_size; s->index = 0; +#if CACHED_BITSTREAM_READER + s->cache = 0; + s->bits_left = 0; + refill_64(s, is_le); +#endif + return ret; } +/** + * Initialize GetBitContext. + * @param buffer bitstream buffer, must be AV_INPUT_BUFFER_PADDING_SIZE bytes + * larger than the actual read bits because some optimized bitstream + * readers read 32 or 64 bit at once and could read over the end + * @param bit_size the size of the buffer in bits + * @return 0 on success, AVERROR_INVALIDDATA if the buffer_size would overflow. + */ +static inline int init_get_bits(GetBitContext *s, const uint8_t *buffer, + int bit_size) +{ +#ifdef BITSTREAM_READER_LE + return init_get_bits_xe(s, buffer, bit_size, 1); +#else + return init_get_bits_xe(s, buffer, bit_size, 0); +#endif +} + /** * Initialize GetBitContext. * @param buffer bitstream buffer, must be AV_INPUT_BUFFER_PADDING_SIZE bytes @@ -469,6 +682,14 @@ static inline int init_get_bits8(GetBitContext *s, const uint8_t *buffer, return init_get_bits(s, buffer, byte_size * 8); } +static inline int init_get_bits8_le(GetBitContext *s, const uint8_t *buffer, + int byte_size) +{ + if (byte_size > INT_MAX / 8 || byte_size < 0) + byte_size = -1; + return init_get_bits_xe(s, buffer, byte_size * 8, 1); +} + static inline const uint8_t *align_get_bits(GetBitContext *s) { int n = -get_bits_count(s) & 7; @@ -551,6 +772,19 @@ static inline const uint8_t *align_get_bits(GetBitContext *s) SKIP_BITS(name, gb, n); \ } while (0) +/* Return the LUT element for the given bitstream configuration. */ +static inline int set_idx(GetBitContext *s, int code, int *n, int *nb_bits, + VLC_TYPE (*table)[2]) +{ + unsigned idx; + + *nb_bits = -*n; + idx = show_bits(s, *nb_bits) + code; + *n = table[idx][1]; + + return table[idx][0]; +} + /** * Parse a vlc code. * @param bits is the number of bits which will be read at once, must be @@ -563,6 +797,24 @@ static inline const uint8_t *align_get_bits(GetBitContext *s) static av_always_inline int get_vlc2(GetBitContext *s, VLC_TYPE (*table)[2], int bits, int max_depth) { +#if CACHED_BITSTREAM_READER + int nb_bits; + unsigned idx = show_bits(s, bits); + int code = table[idx][0]; + int n = table[idx][1]; + + if (max_depth > 1 && n < 0) { + skip_remaining(s, bits); + code = set_idx(s, code, &n, &nb_bits, table); + if (max_depth > 2 && n < 0) { + skip_remaining(s, nb_bits); + code = set_idx(s, code, &n, &nb_bits, table); + } + } + skip_remaining(s, n); + + return code; +#else int code; OPEN_READER(re, s); @@ -573,6 +825,7 @@ static av_always_inline int get_vlc2(GetBitContext *s, VLC_TYPE (*table)[2], CLOSE_READER(re, s); return code; +#endif } static inline int decode012(GetBitContext *gb) diff --git a/libavcodec/gif.c b/libavcodec/gif.c index d9c99d52c..e2242d043 100644 --- a/libavcodec/gif.c +++ b/libavcodec/gif.c @@ -2,6 +2,8 @@ * Copyright (c) 2000 Fabrice Bellard * Copyright (c) 2002 Francois Revol * Copyright (c) 2006 Baptiste Coudurier + * Copyright (c) 2018 Bjorn Roche + * Copyright (c) 2018 Paul B Mahol * * first version by Francois Revol * @@ -39,6 +41,8 @@ #include "put_bits.h" +#define DEFAULT_TRANSPARENCY_INDEX 0x1f + typedef struct GIFContext { const AVClass *class; LZWState *lzw; @@ -46,10 +50,10 @@ typedef struct GIFContext { int buf_size; AVFrame *last_frame; int flags; + int image; uint32_t palette[AVPALETTE_COUNT]; ///< local reference palette for !pal8 int palette_loaded; int transparent_index; - uint8_t *pal_exdata; uint8_t *tmpl; ///< temporary line buffer } GIFContext; @@ -58,6 +62,45 @@ enum { GF_TRANSDIFF = 1<<1, }; +static int is_image_translucent(AVCodecContext *avctx, + const uint8_t *buf, const int linesize) +{ + GIFContext *s = avctx->priv_data; + int trans = s->transparent_index; + + if (trans < 0) + return 0; + + for (int y = 0; y < avctx->height; y++) { + for (int x = 0; x < avctx->width; x++) { + if (buf[x] == trans) { + return 1; + } + } + buf += linesize; + } + + return 0; +} + +static int get_palette_transparency_index(const uint32_t *palette) +{ + int transparent_color_index = -1; + unsigned i, smallest_alpha = 0xff; + + if (!palette) + return -1; + + for (i = 0; i < AVPALETTE_COUNT; i++) { + const uint32_t v = palette[i]; + if (v >> 24 < smallest_alpha) { + smallest_alpha = v >> 24; + transparent_color_index = i; + } + } + return smallest_alpha < 128 ? transparent_color_index : -1; +} + static int pick_palette_entry(const uint8_t *buf, int linesize, int w, int h) { int histogram[AVPALETTE_COUNT] = {0}; @@ -74,17 +117,91 @@ static int pick_palette_entry(const uint8_t *buf, int linesize, int w, int h) return -1; } -static int gif_image_write_image(AVCodecContext *avctx, - uint8_t **bytestream, uint8_t *end, - const uint32_t *palette, +static void gif_crop_translucent(AVCodecContext *avctx, const uint8_t *buf, const int linesize, - AVPacket *pkt) + int *width, int *height, + int *x_start, int *y_start) +{ + GIFContext *s = avctx->priv_data; + int trans = s->transparent_index; + + /* Crop image */ + if ((s->flags & GF_OFFSETTING) && trans >= 0) { + const int w = avctx->width; + const int h = avctx->height; + int x_end = w - 1, + y_end = h - 1; + + // crop top + while (*y_start < y_end) { + int is_trans = 1; + for (int i = 0; i < w; i++) { + if (buf[linesize * *y_start + i] != trans) { + is_trans = 0; + break; + } + } + + if (!is_trans) + break; + (*y_start)++; + } + + // crop bottom + while (y_end > *y_start) { + int is_trans = 1; + for (int i = 0; i < w; i++) { + if (buf[linesize * y_end + i] != trans) { + is_trans = 0; + break; + } + } + if (!is_trans) + break; + y_end--; + } + + // crop left + while (*x_start < x_end) { + int is_trans = 1; + for (int i = *y_start; i < y_end; i++) { + if (buf[linesize * i + *x_start] != trans) { + is_trans = 0; + break; + } + } + if (!is_trans) + break; + (*x_start)++; + } + + // crop right + while (x_end > *x_start) { + int is_trans = 1; + for (int i = *y_start; i < y_end; i++) { + if (buf[linesize * i + x_end] != trans) { + is_trans = 0; + break; + } + } + if (!is_trans) + break; + x_end--; + } + + *height = y_end + 1 - *y_start; + *width = x_end + 1 - *x_start; + av_log(avctx, AV_LOG_DEBUG,"%dx%d image at pos (%d;%d) [area:%dx%d]\n", + *width, *height, *x_start, *y_start, avctx->width, avctx->height); + } +} + +static void gif_crop_opaque(AVCodecContext *avctx, + const uint32_t *palette, + const uint8_t *buf, const int linesize, + int *width, int *height, int *x_start, int *y_start) { GIFContext *s = avctx->priv_data; - int len = 0, height = avctx->height, width = avctx->width, x, y; - int x_start = 0, y_start = 0, trans = s->transparent_index; - int honor_transparency = (s->flags & GF_TRANSDIFF) && s->last_frame && !palette; - const uint8_t *ptr; /* Crop image */ if ((s->flags & GF_OFFSETTING) && s->last_frame && !palette) { @@ -94,34 +211,34 @@ static int gif_image_write_image(AVCodecContext *avctx, y_end = avctx->height - 1; /* skip common lines */ - while (y_start < y_end) { - if (memcmp(ref + y_start*ref_linesize, buf + y_start*linesize, width)) + while (*y_start < y_end) { + if (memcmp(ref + *y_start*ref_linesize, buf + *y_start*linesize, *width)) break; - y_start++; + (*y_start)++; } - while (y_end > y_start) { - if (memcmp(ref + y_end*ref_linesize, buf + y_end*linesize, width)) + while (y_end > *y_start) { + if (memcmp(ref + y_end*ref_linesize, buf + y_end*linesize, *width)) break; y_end--; } - height = y_end + 1 - y_start; + *height = y_end + 1 - *y_start; /* skip common columns */ - while (x_start < x_end) { + while (*x_start < x_end) { int same_column = 1; - for (y = y_start; y <= y_end; y++) { - if (ref[y*ref_linesize + x_start] != buf[y*linesize + x_start]) { + for (int y = *y_start; y <= y_end; y++) { + if (ref[y*ref_linesize + *x_start] != buf[y*linesize + *x_start]) { same_column = 0; break; } } if (!same_column) break; - x_start++; + (*x_start)++; } - while (x_end > x_start) { + while (x_end > *x_start) { int same_column = 1; - for (y = y_start; y <= y_end; y++) { + for (int y = *y_start; y <= y_end; y++) { if (ref[y*ref_linesize + x_end] != buf[y*linesize + x_end]) { same_column = 0; break; @@ -131,11 +248,80 @@ static int gif_image_write_image(AVCodecContext *avctx, break; x_end--; } - width = x_end + 1 - x_start; + *width = x_end + 1 - *x_start; av_log(avctx, AV_LOG_DEBUG,"%dx%d image at pos (%d;%d) [area:%dx%d]\n", - width, height, x_start, y_start, avctx->width, avctx->height); + *width, *height, *x_start, *y_start, avctx->width, avctx->height); } +} + +static int gif_image_write_image(AVCodecContext *avctx, + uint8_t **bytestream, uint8_t *end, + const uint32_t *palette, + const uint8_t *buf, const int linesize, + AVPacket *pkt) +{ + GIFContext *s = avctx->priv_data; + int disposal, len = 0, height = avctx->height, width = avctx->width, x, y; + int x_start = 0, y_start = 0, trans = s->transparent_index; + int bcid = -1, honor_transparency = (s->flags & GF_TRANSDIFF) && s->last_frame && !palette; + const uint8_t *ptr; + + if (!s->image && avctx->frame_number && is_image_translucent(avctx, buf, linesize)) { + gif_crop_translucent(avctx, buf, linesize, &width, &height, &x_start, &y_start); + honor_transparency = 0; + disposal = GCE_DISPOSAL_BACKGROUND; + } else { + gif_crop_opaque(avctx, palette, buf, linesize, &width, &height, &x_start, &y_start); + disposal = GCE_DISPOSAL_INPLACE; + } + + if (s->image || !avctx->frame_number) { /* GIF header */ + const uint32_t *global_palette = palette ? palette : s->palette; + const AVRational sar = avctx->sample_aspect_ratio; + int64_t aspect = 0; + + if (sar.num > 0 && sar.den > 0) { + aspect = sar.num * 64LL / sar.den - 15; + if (aspect < 0 || aspect > 255) + aspect = 0; + } + + bytestream_put_buffer(bytestream, gif89a_sig, sizeof(gif89a_sig)); + bytestream_put_le16(bytestream, avctx->width); + bytestream_put_le16(bytestream, avctx->height); + + bcid = get_palette_transparency_index(global_palette); + + bytestream_put_byte(bytestream, 0xf7); /* flags: global clut, 256 entries */ + bytestream_put_byte(bytestream, bcid < 0 ? DEFAULT_TRANSPARENCY_INDEX : bcid); /* background color index */ + bytestream_put_byte(bytestream, aspect); + for (int i = 0; i < 256; i++) { + const uint32_t v = global_palette[i] & 0xffffff; + bytestream_put_be24(bytestream, v); + } + } + + if (honor_transparency && trans < 0) { + trans = pick_palette_entry(buf + y_start*linesize + x_start, + linesize, width, height); + if (trans < 0) // TODO, patch welcome + av_log(avctx, AV_LOG_DEBUG, "No available color, can not use transparency\n"); + } + + if (trans < 0) + honor_transparency = 0; + + bcid = honor_transparency || disposal == GCE_DISPOSAL_BACKGROUND ? trans : get_palette_transparency_index(palette); + + /* graphic control extension */ + bytestream_put_byte(bytestream, GIF_EXTENSION_INTRODUCER); + bytestream_put_byte(bytestream, GIF_GCE_EXT_LABEL); + bytestream_put_byte(bytestream, 0x04); /* block size */ + bytestream_put_byte(bytestream, disposal<<2 | (bcid >= 0)); + bytestream_put_le16(bytestream, 5); // default delay + bytestream_put_byte(bytestream, bcid < 0 ? DEFAULT_TRANSPARENCY_INDEX : bcid); + bytestream_put_byte(bytestream, 0x00); /* image block */ bytestream_put_byte(bytestream, GIF_IMAGE_SEPARATOR); @@ -155,24 +341,6 @@ static int gif_image_write_image(AVCodecContext *avctx, } } - if (honor_transparency && trans < 0) { - trans = pick_palette_entry(buf + y_start*linesize + x_start, - linesize, width, height); - if (trans < 0) { // TODO, patch welcome - av_log(avctx, AV_LOG_DEBUG, "No available color, can not use transparency\n"); - } else { - uint8_t *pal_exdata = s->pal_exdata; - if (!pal_exdata) - pal_exdata = av_packet_new_side_data(pkt, AV_PKT_DATA_PALETTE, AVPALETTE_SIZE); - if (!pal_exdata) - return AVERROR(ENOMEM); - memcpy(pal_exdata, s->palette, AVPALETTE_SIZE); - pal_exdata[trans*4 + 3*!HAVE_BIGENDIAN] = 0x00; - } - } - if (trans < 0) - honor_transparency = 0; - bytestream_put_byte(bytestream, 0x08); ff_lzw_encode_init(s->lzw, s->buf, s->buf_size, @@ -222,12 +390,6 @@ static av_cold int gif_encode_init(AVCodecContext *avctx) av_log(avctx, AV_LOG_ERROR, "GIF does not support resolutions above 65535x65535\n"); return AVERROR(EINVAL); } -#if FF_API_CODED_FRAME -FF_DISABLE_DEPRECATION_WARNINGS - avctx->coded_frame->pict_type = AV_PICTURE_TYPE_I; - avctx->coded_frame->key_frame = 1; -FF_ENABLE_DEPRECATION_WARNINGS -#endif s->transparent_index = -1; @@ -244,25 +406,6 @@ FF_ENABLE_DEPRECATION_WARNINGS return 0; } -/* FIXME: duplicated with lavc */ -static int get_palette_transparency_index(const uint32_t *palette) -{ - int transparent_color_index = -1; - unsigned i, smallest_alpha = 0xff; - - if (!palette) - return -1; - - for (i = 0; i < AVPALETTE_COUNT; i++) { - const uint32_t v = palette[i]; - if (v >> 24 < smallest_alpha) { - smallest_alpha = v >> 24; - transparent_color_index = i; - } - } - return smallest_alpha < 128 ? transparent_color_index : -1; -} - static int gif_encode_frame(AVCodecContext *avctx, AVPacket *pkt, const AVFrame *pict, int *got_packet) { @@ -277,22 +420,12 @@ static int gif_encode_frame(AVCodecContext *avctx, AVPacket *pkt, end = pkt->data + pkt->size; if (avctx->pix_fmt == AV_PIX_FMT_PAL8) { - uint8_t *pal_exdata = av_packet_new_side_data(pkt, AV_PKT_DATA_PALETTE, AVPALETTE_SIZE); - if (!pal_exdata) - return AVERROR(ENOMEM); - memcpy(pal_exdata, pict->data[1], AVPALETTE_SIZE); palette = (uint32_t*)pict->data[1]; - s->pal_exdata = pal_exdata; - - /* The first palette with PAL8 will be used as generic palette by the - * muxer so we don't need to write it locally in the packet. We store - * it as a reference here in case it changes later. */ if (!s->palette_loaded) { memcpy(s->palette, palette, AVPALETTE_SIZE); s->transparent_index = get_palette_transparency_index(palette); s->palette_loaded = 1; - palette = NULL; } else if (!memcmp(s->palette, palette, AVPALETTE_SIZE)) { palette = NULL; } @@ -300,18 +433,22 @@ static int gif_encode_frame(AVCodecContext *avctx, AVPacket *pkt, gif_image_write_image(avctx, &outbuf_ptr, end, palette, pict->data[0], pict->linesize[0], pkt); - if (!s->last_frame) { + if (!s->last_frame && !s->image) { s->last_frame = av_frame_alloc(); if (!s->last_frame) return AVERROR(ENOMEM); } - av_frame_unref(s->last_frame); - ret = av_frame_ref(s->last_frame, (AVFrame*)pict); - if (ret < 0) - return ret; + + if (!s->image) { + av_frame_unref(s->last_frame); + ret = av_frame_ref(s->last_frame, (AVFrame*)pict); + if (ret < 0) + return ret; + } pkt->size = outbuf_ptr - pkt->data; - pkt->flags |= AV_PKT_FLAG_KEY; + if (s->image || !avctx->frame_number) + pkt->flags |= AV_PKT_FLAG_KEY; *got_packet = 1; return 0; @@ -335,6 +472,7 @@ static const AVOption gif_options[] = { { "gifflags", "set GIF flags", OFFSET(flags), AV_OPT_TYPE_FLAGS, {.i64 = GF_OFFSETTING|GF_TRANSDIFF}, 0, INT_MAX, FLAGS, "flags" }, { "offsetting", "enable picture offsetting", 0, AV_OPT_TYPE_CONST, {.i64=GF_OFFSETTING}, INT_MIN, INT_MAX, FLAGS, "flags" }, { "transdiff", "enable transparency detection between frames", 0, AV_OPT_TYPE_CONST, {.i64=GF_TRANSDIFF}, INT_MIN, INT_MAX, FLAGS, "flags" }, + { "gifimage", "enable encoding only images per frame", OFFSET(image), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS }, { NULL } }; diff --git a/libavcodec/gif.h b/libavcodec/gif.h index 9f3577885..7fb61495b 100644 --- a/libavcodec/gif.h +++ b/libavcodec/gif.h @@ -43,6 +43,7 @@ static const uint8_t gif89a_sig[6] = "GIF89a"; #define GIF_EXTENSION_INTRODUCER 0x21 #define GIF_IMAGE_SEPARATOR 0x2c #define GIF_GCE_EXT_LABEL 0xf9 +#define GIF_COM_EXT_LABEL 0xfe #define GIF_APP_EXT_LABEL 0xff #define NETSCAPE_EXT_STR "NETSCAPE2.0" diff --git a/libavcodec/gif_parser.c b/libavcodec/gif_parser.c new file mode 100644 index 000000000..e88338fd4 --- /dev/null +++ b/libavcodec/gif_parser.c @@ -0,0 +1,188 @@ +/* + * GIF parser + * Copyright (c) 2018 Paul B Mahol + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * GIF parser + */ + +#include "libavutil/avassert.h" +#include "libavutil/bswap.h" +#include "libavutil/common.h" + +#include "gif.h" +#include "parser.h" + +typedef enum GIFParseStates { + GIF_HEADER = 1, + GIF_EXTENSION, + GIF_EXTENSION_BLOCK, + GIF_IMAGE, + GIF_IMAGE_BLOCK, +} gif_states; + +typedef struct GIFParseContext { + ParseContext pc; + unsigned found_sig; + int found_start; + int found_end; + int index; + int state; + int gct_flag; + int gct_size; + int block_size; + int etype; + int delay; +} GIFParseContext; + +static int gif_find_frame_end(GIFParseContext *g, const uint8_t *buf, + int buf_size, void *logctx) +{ + int index, next = END_NOT_FOUND; + + for (index = 0; index < buf_size; index++) { + if (!g->state) { + if (!memcmp(buf + index, gif87a_sig, 6) || + !memcmp(buf + index, gif89a_sig, 6)) { + g->state = GIF_HEADER; + g->found_sig++; + } else if (buf[index] == GIF_EXTENSION_INTRODUCER) { + g->state = GIF_EXTENSION; + g->found_start = 1; + } else if (buf[index] == GIF_IMAGE_SEPARATOR) { + g->state = GIF_IMAGE; + } else if (buf[index] == GIF_TRAILER) { + g->state = 0; + g->found_end = 1; + g->found_sig = 0; + } else { + g->found_sig = 0; + } + } + + if (g->state == GIF_HEADER) { + if (g->index == 10) { + g->gct_flag = !!(buf[index] & 0x80); + g->gct_size = 3 * (1 << ((buf[index] & 0x07) + 1)); + } + if (g->index >= 12 + g->gct_flag * g->gct_size) { + g->state = 0; + g->index = 0; + g->gct_flag = 0; + g->gct_size = 0; + continue; + } + g->index++; + } else if (g->state == GIF_EXTENSION) { + if (g->found_start && g->found_end && g->found_sig) { + next = index; + g->found_start = 0; + g->found_end = 0; + g->index = 0; + g->gct_flag = 0; + g->gct_size = 0; + g->state = 0; + break; + } + if (g->index == 1) { + g->etype = buf[index]; + } + if (g->index >= 2) { + g->block_size = buf[index]; + g->index = 0; + g->state = GIF_EXTENSION_BLOCK; + continue; + } + g->index++; + } else if (g->state == GIF_IMAGE_BLOCK) { + if (!g->index) + g->block_size = buf[index]; + if (g->index >= g->block_size) { + g->index = 0; + if (!g->block_size) { + g->state = 0; + g->found_end = 1; + } + continue; + } + g->index++; + } else if (g->state == GIF_EXTENSION_BLOCK) { + if (g->etype == GIF_GCE_EXT_LABEL) { + if (g->index == 0) + g->delay = 0; + if (g->index >= 1 && g->index <= 2) { + g->delay |= buf[index] << (8 * (g->index - 1)); + } + } + if (g->index >= g->block_size) { + g->block_size = buf[index]; + g->index = 0; + if (!g->block_size) + g->state = 0; + continue; + } + g->index++; + } else if (g->state == GIF_IMAGE) { + if (g->index == 8) { + g->gct_flag = !!(buf[index] & 0x80); + g->gct_size = 3 * (1 << ((buf[index] & 0x07) + 1)); + } + if (g->index >= 10 + g->gct_flag * g->gct_size) { + g->state = GIF_IMAGE_BLOCK; + g->index = 0; + g->gct_flag = 0; + g->gct_size = 0; + continue; + } + g->index++; + } + } + + return next; +} + +static int gif_parse(AVCodecParserContext *s, AVCodecContext *avctx, + const uint8_t **poutbuf, int *poutbuf_size, + const uint8_t *buf, int buf_size) +{ + GIFParseContext *g = s->priv_data; + int next; + + next = gif_find_frame_end(g, buf, buf_size, avctx); + if (ff_combine_frame(&g->pc, next, &buf, &buf_size) < 0) { + *poutbuf = NULL; + *poutbuf_size = 0; + return buf_size; + } + + s->duration = g->delay; + + *poutbuf = buf; + *poutbuf_size = buf_size; + return next; +} + +AVCodecParser ff_gif_parser = { + .codec_ids = { AV_CODEC_ID_GIF }, + .priv_data_size = sizeof(GIFParseContext), + .parser_parse = gif_parse, + .parser_close = ff_parse_close, +}; diff --git a/libavcodec/gifdec.c b/libavcodec/gifdec.c index 2eeed4c4c..2115da163 100644 --- a/libavcodec/gifdec.c +++ b/libavcodec/gifdec.c @@ -179,12 +179,20 @@ static int gif_read_image(GifState *s, AVFrame *frame) } /* verify that all the image is inside the screen dimensions */ - if (!width || width > s->screen_width || left >= s->screen_width) { - av_log(s->avctx, AV_LOG_ERROR, "Invalid image width.\n"); + if (!width || width > s->screen_width) { + av_log(s->avctx, AV_LOG_WARNING, "Invalid image width: %d, truncating.\n", width); + width = s->screen_width; + } + if (left >= s->screen_width) { + av_log(s->avctx, AV_LOG_ERROR, "Invalid left position: %d.\n", left); return AVERROR_INVALIDDATA; } - if (!height || height > s->screen_height || top >= s->screen_height) { - av_log(s->avctx, AV_LOG_ERROR, "Invalid image height.\n"); + if (!height || height > s->screen_height) { + av_log(s->avctx, AV_LOG_WARNING, "Invalid image height: %d, truncating.\n", height); + height = s->screen_height; + } + if (top >= s->screen_height) { + av_log(s->avctx, AV_LOG_ERROR, "Invalid top position: %d.\n", top); return AVERROR_INVALIDDATA; } if (left + width > s->screen_width) { @@ -451,6 +459,8 @@ static av_cold int gif_decode_init(AVCodecContext *avctx) if (!s->frame) return AVERROR(ENOMEM); ff_lzw_decode_open(&s->lzw); + if (!s->lzw) + return AVERROR(ENOMEM); return 0; } @@ -559,5 +569,7 @@ AVCodec ff_gif_decoder = { .close = gif_decode_close, .decode = gif_decode_frame, .capabilities = AV_CODEC_CAP_DR1, + .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE | + FF_CODEC_CAP_INIT_CLEANUP, .priv_class = &decoder_class, }; diff --git a/libavcodec/golomb.h b/libavcodec/golomb.h index efb1eff8a..5cdfa0945 100644 --- a/libavcodec/golomb.h +++ b/libavcodec/golomb.h @@ -49,11 +49,30 @@ extern const uint8_t ff_interleaved_dirac_golomb_vlc_code[256]; /** * Read an unsigned Exp-Golomb code in the range 0 to 8190. + * + * @returns the read value or a negative error code. */ static inline int get_ue_golomb(GetBitContext *gb) { unsigned int buf; +#if CACHED_BITSTREAM_READER + buf = show_bits_long(gb, 32); + + if (buf >= (1 << 27)) { + buf >>= 32 - 9; + skip_bits_long(gb, ff_golomb_vlc_len[buf]); + + return ff_ue_golomb_vlc_code[buf]; + } else { + int log = 2 * av_log2(buf) - 31; + buf >>= log; + buf--; + skip_bits_long(gb, 32 - log); + + return buf; + } +#else OPEN_READER(re, gb); UPDATE_CACHE(re, gb); buf = GET_CACHE(re, gb); @@ -77,6 +96,7 @@ static inline int get_ue_golomb(GetBitContext *gb) return buf; } +#endif } /** @@ -101,6 +121,13 @@ static inline int get_ue_golomb_31(GetBitContext *gb) { unsigned int buf; +#if CACHED_BITSTREAM_READER + buf = show_bits_long(gb, 32); + + buf >>= 32 - 9; + skip_bits_long(gb, ff_golomb_vlc_len[buf]); +#else + OPEN_READER(re, gb); UPDATE_CACHE(re, gb); buf = GET_CACHE(re, gb); @@ -108,6 +135,7 @@ static inline int get_ue_golomb_31(GetBitContext *gb) buf >>= 32 - 9; LAST_SKIP_BITS(re, gb, ff_golomb_vlc_len[buf]); CLOSE_READER(re, gb); +#endif return ff_ue_golomb_vlc_code[buf]; } @@ -116,6 +144,33 @@ static inline unsigned get_interleaved_ue_golomb(GetBitContext *gb) { uint32_t buf; +#if CACHED_BITSTREAM_READER + buf = show_bits_long(gb, 32); + + if (buf & 0xAA800000) { + buf >>= 32 - 8; + skip_bits_long(gb, ff_interleaved_golomb_vlc_len[buf]); + + return ff_interleaved_ue_golomb_vlc_code[buf]; + } else { + unsigned ret = 1; + + do { + buf >>= 32 - 8; + skip_bits_long(gb, FFMIN(ff_interleaved_golomb_vlc_len[buf], 8)); + + if (ff_interleaved_golomb_vlc_len[buf] != 9) { + ret <<= (ff_interleaved_golomb_vlc_len[buf] - 1) >> 1; + ret |= ff_interleaved_dirac_golomb_vlc_code[buf]; + break; + } + ret = (ret << 4) | ff_interleaved_dirac_golomb_vlc_code[buf]; + buf = show_bits_long(gb, 32); + } while (get_bits_left(gb) > 0); + + return ret - 1; + } +#else OPEN_READER(re, gb); UPDATE_CACHE(re, gb); buf = GET_CACHE(re, gb); @@ -147,6 +202,7 @@ static inline unsigned get_interleaved_ue_golomb(GetBitContext *gb) CLOSE_READER(re, gb); return ret - 1; } +#endif } /** @@ -184,6 +240,28 @@ static inline int get_se_golomb(GetBitContext *gb) { unsigned int buf; +#if CACHED_BITSTREAM_READER + buf = show_bits_long(gb, 32); + + if (buf >= (1 << 27)) { + buf >>= 32 - 9; + skip_bits_long(gb, ff_golomb_vlc_len[buf]); + + return ff_se_golomb_vlc_code[buf]; + } else { + int log = 2 * av_log2(buf) - 31; + buf >>= log; + + skip_bits_long(gb, 32 - log); + + if (buf & 1) + buf = -(buf >> 1); + else + buf = (buf >> 1); + + return buf; + } +#else OPEN_READER(re, gb); UPDATE_CACHE(re, gb); buf = GET_CACHE(re, gb); @@ -210,6 +288,7 @@ static inline int get_se_golomb(GetBitContext *gb) return buf; } +#endif } static inline int get_se_golomb_long(GetBitContext *gb) @@ -223,6 +302,30 @@ static inline int get_interleaved_se_golomb(GetBitContext *gb) { unsigned int buf; +#if CACHED_BITSTREAM_READER + buf = show_bits_long(gb, 32); + + if (buf & 0xAA800000) { + buf >>= 32 - 8; + skip_bits_long(gb, ff_interleaved_golomb_vlc_len[buf]); + + return ff_interleaved_se_golomb_vlc_code[buf]; + } else { + int log; + skip_bits(gb, 8); + buf |= 1 | show_bits_long(gb, 24); + + if ((buf & 0xAAAAAAAA) == 0) + return INVALID_VLC; + + for (log = 31; (buf & 0x80000000) == 0; log--) + buf = (buf << 2) - ((buf << log) >> (log - 1)) + (buf >> 30); + + skip_bits_long(gb, 63 - 2 * log - 8); + + return (signed) (((((buf << log) >> log) - 1) ^ -(buf & 0x1)) + 1) >> 1; + } +#else OPEN_READER(re, gb); UPDATE_CACHE(re, gb); buf = GET_CACHE(re, gb); @@ -250,6 +353,7 @@ static inline int get_interleaved_se_golomb(GetBitContext *gb) return (signed) (((((buf << log) >> log) - 1) ^ -(buf & 0x1)) + 1) >> 1; } +#endif } static inline int dirac_get_se_golomb(GetBitContext *gb) @@ -273,6 +377,24 @@ static inline int get_ur_golomb(GetBitContext *gb, int k, int limit, unsigned int buf; int log; +#if CACHED_BITSTREAM_READER + buf = show_bits_long(gb, 32); + + log = av_log2(buf); + + if (log > 31 - limit) { + buf >>= log - k; + buf += (30 - log) << k; + skip_bits_long(gb, 32 + k - log); + + return buf; + } else { + skip_bits_long(gb, limit); + buf = get_bits_long(gb, esc_len); + + return buf + limit - 1; + } +#else OPEN_READER(re, gb); UPDATE_CACHE(re, gb); buf = GET_CACHE(re, gb); @@ -297,6 +419,7 @@ static inline int get_ur_golomb(GetBitContext *gb, int k, int limit, return buf + limit - 1; } +#endif } /** @@ -308,6 +431,35 @@ static inline int get_ur_golomb_jpegls(GetBitContext *gb, int k, int limit, unsigned int buf; int log; +#if CACHED_BITSTREAM_READER + buf = show_bits_long(gb, 32); + + log = av_log2(buf); + + if (log - k >= 1 && 32 - log < limit) { + buf >>= log - k; + buf += (30 - log) << k; + skip_bits_long(gb, 32 + k - log); + + return buf; + } else { + int i; + for (i = 0; + i < limit && get_bits1(gb) == 0 && get_bits_left(gb) > 0; + i++); + + if (i < limit - 1) { + buf = get_bits_long(gb, k); + + return buf + (i << k); + } else if (i == limit - 1) { + buf = get_bits_long(gb, esc_len); + + return buf + 1; + } else + return -1; + } +#else OPEN_READER(re, gb); UPDATE_CACHE(re, gb); buf = GET_CACHE(re, gb); @@ -326,15 +478,19 @@ static inline int get_ur_golomb_jpegls(GetBitContext *gb, int k, int limit, return buf; } else { int i; - for (i = 0; i < limit && SHOW_UBITS(re, gb, 1) == 0; i++) { + for (i = 0; i + MIN_CACHE_BITS <= limit && SHOW_UBITS(re, gb, MIN_CACHE_BITS) == 0; i += MIN_CACHE_BITS) { if (gb->size_in_bits <= re_index) { CLOSE_READER(re, gb); return -1; } - LAST_SKIP_BITS(re, gb, 1); + LAST_SKIP_BITS(re, gb, MIN_CACHE_BITS); UPDATE_CACHE(re, gb); } - SKIP_BITS(re, gb, 1); + for (; i < limit && SHOW_UBITS(re, gb, 1) == 0; i++) { + SKIP_BITS(re, gb, 1); + } + LAST_SKIP_BITS(re, gb, 1); + UPDATE_CACHE(re, gb); if (i < limit - 1) { if (k) { @@ -364,6 +520,7 @@ static inline int get_ur_golomb_jpegls(GetBitContext *gb, int k, int limit, CLOSE_READER(re, gb); return buf; } +#endif } /** diff --git a/libavcodec/h263dec.c b/libavcodec/h263dec.c index a2326ac1a..8ee844e29 100644 --- a/libavcodec/h263dec.c +++ b/libavcodec/h263dec.c @@ -47,10 +47,9 @@ static enum AVPixelFormat h263_get_format(AVCodecContext *avctx) { - MpegEncContext *s = avctx->priv_data; /* MPEG-4 Studio Profile only, not supported by hardware */ if (avctx->bits_per_raw_sample > 8) { - av_assert1(s->studio_profile); + av_assert1(((MpegEncContext *)avctx->priv_data)->studio_profile); return avctx->pix_fmt; } @@ -319,6 +318,7 @@ static int decode_slice(MpegEncContext *s) av_assert1(s->mb_x == 0 && s->mb_y == s->mb_height); + // Detect incorrect padding with wrong stuffing codes used by NEC N-02B if (s->codec_id == AV_CODEC_ID_MPEG4 && (s->workaround_bugs & FF_BUG_AUTODETECT) && get_bits_left(&s->gb) >= 48 && @@ -500,9 +500,9 @@ retry: GetBitContext gb; if (init_get_bits8(&gb, s->avctx->extradata, s->avctx->extradata_size) >= 0 ) - ff_mpeg4_decode_picture_header(avctx->priv_data, &gb); + ff_mpeg4_decode_picture_header(avctx->priv_data, &gb, 1); } - ret = ff_mpeg4_decode_picture_header(avctx->priv_data, &s->gb); + ret = ff_mpeg4_decode_picture_header(avctx->priv_data, &s->gb, 0); } else if (CONFIG_H263I_DECODER && s->codec_id == AV_CODEC_ID_H263I) { ret = ff_intel_h263_decode_picture_header(s); } else if (CONFIG_FLV_DECODER && s->h263_flv) { @@ -614,7 +614,7 @@ retry: if ((ret = ff_mpv_frame_start(s, avctx)) < 0) return ret; - if (!s->divx_packed) + if (!s->divx_packed && !avctx->hwaccel) ff_thread_finish_setup(avctx); if (avctx->hwaccel) { @@ -743,6 +743,22 @@ const enum AVPixelFormat ff_h263_hwaccel_pixfmt_list_420[] = { AV_PIX_FMT_NONE }; +const AVCodecHWConfigInternal *ff_h263_hw_config_list[] = { +#if CONFIG_H263_VAAPI_HWACCEL + HWACCEL_VAAPI(h263), +#endif +#if CONFIG_MPEG4_NVDEC_HWACCEL + HWACCEL_NVDEC(mpeg4), +#endif +#if CONFIG_MPEG4_VDPAU_HWACCEL + HWACCEL_VDPAU(mpeg4), +#endif +#if CONFIG_H263_VIDEOTOOLBOX_HWACCEL + HWACCEL_VIDEOTOOLBOX(h263), +#endif + NULL +}; + AVCodec ff_h263_decoder = { .name = "h263", .long_name = NULL_IF_CONFIG_SMALL("H.263 / H.263-1996, H.263+ / H.263-1998 / H.263 version 2"), @@ -758,6 +774,7 @@ AVCodec ff_h263_decoder = { .flush = ff_mpeg_flush, .max_lowres = 3, .pix_fmts = ff_h263_hwaccel_pixfmt_list_420, + .hw_configs = ff_h263_hw_config_list, }; AVCodec ff_h263p_decoder = { @@ -775,16 +792,5 @@ AVCodec ff_h263p_decoder = { .flush = ff_mpeg_flush, .max_lowres = 3, .pix_fmts = ff_h263_hwaccel_pixfmt_list_420, - .hw_configs = (const AVCodecHWConfigInternal*[]) { -#if CONFIG_H263_VAAPI_HWACCEL - HWACCEL_VAAPI(h263), -#endif -#if CONFIG_MPEG4_VDPAU_HWACCEL - HWACCEL_VDPAU(mpeg4), -#endif -#if CONFIG_H263_VIDEOTOOLBOX_HWACCEL - HWACCEL_VIDEOTOOLBOX(h263), -#endif - NULL - }, + .hw_configs = ff_h263_hw_config_list, }; diff --git a/libavcodec/h264.h b/libavcodec/h264.h index 650580bf3..7a1fb6d68 100644 --- a/libavcodec/h264.h +++ b/libavcodec/h264.h @@ -26,8 +26,12 @@ #define QP_MAX_NUM (51 + 6*6) // The maximum supported qp -/* NAL unit types */ +/* + * Table 7-1 – NAL unit type codes, syntax element categories, and NAL unit type classes in + * T-REC-H.264-201704 + */ enum { + H264_NAL_UNSPECIFIED = 0, H264_NAL_SLICE = 1, H264_NAL_DPA = 2, H264_NAL_DPB = 3, @@ -41,7 +45,24 @@ enum { H264_NAL_END_STREAM = 11, H264_NAL_FILLER_DATA = 12, H264_NAL_SPS_EXT = 13, + H264_NAL_PREFIX = 14, + H264_NAL_SUB_SPS = 15, + H264_NAL_DPS = 16, + H264_NAL_RESERVED17 = 17, + H264_NAL_RESERVED18 = 18, H264_NAL_AUXILIARY_SLICE = 19, + H264_NAL_EXTEN_SLICE = 20, + H264_NAL_DEPTH_EXTEN_SLICE = 21, + H264_NAL_RESERVED22 = 22, + H264_NAL_RESERVED23 = 23, + H264_NAL_UNSPECIFIED24 = 24, + H264_NAL_UNSPECIFIED25 = 25, + H264_NAL_UNSPECIFIED26 = 26, + H264_NAL_UNSPECIFIED27 = 27, + H264_NAL_UNSPECIFIED28 = 28, + H264_NAL_UNSPECIFIED29 = 29, + H264_NAL_UNSPECIFIED30 = 30, + H264_NAL_UNSPECIFIED31 = 31, }; diff --git a/libavcodec/h2645_parse.c b/libavcodec/h2645_parse.c index f35c02d1b..307e8643e 100644 --- a/libavcodec/h2645_parse.c +++ b/libavcodec/h2645_parse.c @@ -28,6 +28,7 @@ #include "bytestream.h" #include "hevc.h" +#include "h264.h" #include "h2645_parse.h" int ff_h2645_extract_rbsp(const uint8_t *src, int length, @@ -53,8 +54,8 @@ int ff_h2645_extract_rbsp(const uint8_t *src, int length, i++ #if HAVE_FAST_64BIT for (i = 0; i + 1 < length; i += 9) { - if (!((~AV_RN64A(src + i) & - (AV_RN64A(src + i) - 0x0100010001000101ULL)) & + if (!((~AV_RN64(src + i) & + (AV_RN64(src + i) - 0x0100010001000101ULL)) & 0x8000800080008080ULL)) continue; FIND_FIRST_ZERO; @@ -63,8 +64,8 @@ int ff_h2645_extract_rbsp(const uint8_t *src, int length, } #else for (i = 0; i + 1 < length; i += 5) { - if (!((~AV_RN32A(src + i) & - (AV_RN32A(src + i) - 0x01000101U)) & + if (!((~AV_RN32(src + i) & + (AV_RN32(src + i) - 0x01000101U)) & 0x80008080U)) continue; FIND_FIRST_ZERO; @@ -145,36 +146,118 @@ nsc: return si; } -static const char *nal_unit_name(int nal_type) +static const char *hevc_nal_type_name[64] = { + "TRAIL_N", // HEVC_NAL_TRAIL_N + "TRAIL_R", // HEVC_NAL_TRAIL_R + "TSA_N", // HEVC_NAL_TSA_N + "TSA_R", // HEVC_NAL_TSA_R + "STSA_N", // HEVC_NAL_STSA_N + "STSA_R", // HEVC_NAL_STSA_R + "RADL_N", // HEVC_NAL_RADL_N + "RADL_R", // HEVC_NAL_RADL_R + "RASL_N", // HEVC_NAL_RASL_N + "RASL_R", // HEVC_NAL_RASL_R + "RSV_VCL_N10", // HEVC_NAL_VCL_N10 + "RSV_VCL_R11", // HEVC_NAL_VCL_R11 + "RSV_VCL_N12", // HEVC_NAL_VCL_N12 + "RSV_VLC_R13", // HEVC_NAL_VCL_R13 + "RSV_VCL_N14", // HEVC_NAL_VCL_N14 + "RSV_VCL_R15", // HEVC_NAL_VCL_R15 + "BLA_W_LP", // HEVC_NAL_BLA_W_LP + "BLA_W_RADL", // HEVC_NAL_BLA_W_RADL + "BLA_N_LP", // HEVC_NAL_BLA_N_LP + "IDR_W_RADL", // HEVC_NAL_IDR_W_RADL + "IDR_N_LP", // HEVC_NAL_IDR_N_LP + "CRA_NUT", // HEVC_NAL_CRA_NUT + "IRAP_IRAP_VCL22", // HEVC_NAL_IRAP_VCL22 + "IRAP_IRAP_VCL23", // HEVC_NAL_IRAP_VCL23 + "RSV_VCL24", // HEVC_NAL_RSV_VCL24 + "RSV_VCL25", // HEVC_NAL_RSV_VCL25 + "RSV_VCL26", // HEVC_NAL_RSV_VCL26 + "RSV_VCL27", // HEVC_NAL_RSV_VCL27 + "RSV_VCL28", // HEVC_NAL_RSV_VCL28 + "RSV_VCL29", // HEVC_NAL_RSV_VCL29 + "RSV_VCL30", // HEVC_NAL_RSV_VCL30 + "RSV_VCL31", // HEVC_NAL_RSV_VCL31 + "VPS", // HEVC_NAL_VPS + "SPS", // HEVC_NAL_SPS + "PPS", // HEVC_NAL_PPS + "AUD", // HEVC_NAL_AUD + "EOS_NUT", // HEVC_NAL_EOS_NUT + "EOB_NUT", // HEVC_NAL_EOB_NUT + "FD_NUT", // HEVC_NAL_FD_NUT + "SEI_PREFIX", // HEVC_NAL_SEI_PREFIX + "SEI_SUFFIX", // HEVC_NAL_SEI_SUFFIX + "RSV_NVCL41", // HEVC_NAL_RSV_NVCL41 + "RSV_NVCL42", // HEVC_NAL_RSV_NVCL42 + "RSV_NVCL43", // HEVC_NAL_RSV_NVCL43 + "RSV_NVCL44", // HEVC_NAL_RSV_NVCL44 + "RSV_NVCL45", // HEVC_NAL_RSV_NVCL45 + "RSV_NVCL46", // HEVC_NAL_RSV_NVCL46 + "RSV_NVCL47", // HEVC_NAL_RSV_NVCL47 + "UNSPEC48", // HEVC_NAL_UNSPEC48 + "UNSPEC49", // HEVC_NAL_UNSPEC49 + "UNSPEC50", // HEVC_NAL_UNSPEC50 + "UNSPEC51", // HEVC_NAL_UNSPEC51 + "UNSPEC52", // HEVC_NAL_UNSPEC52 + "UNSPEC53", // HEVC_NAL_UNSPEC53 + "UNSPEC54", // HEVC_NAL_UNSPEC54 + "UNSPEC55", // HEVC_NAL_UNSPEC55 + "UNSPEC56", // HEVC_NAL_UNSPEC56 + "UNSPEC57", // HEVC_NAL_UNSPEC57 + "UNSPEC58", // HEVC_NAL_UNSPEC58 + "UNSPEC59", // HEVC_NAL_UNSPEC59 + "UNSPEC60", // HEVC_NAL_UNSPEC60 + "UNSPEC61", // HEVC_NAL_UNSPEC61 + "UNSPEC62", // HEVC_NAL_UNSPEC62 + "UNSPEC63", // HEVC_NAL_UNSPEC63 +}; + +static const char *hevc_nal_unit_name(int nal_type) { - switch(nal_type) { - case HEVC_NAL_TRAIL_N : return "TRAIL_N"; - case HEVC_NAL_TRAIL_R : return "TRAIL_R"; - case HEVC_NAL_TSA_N : return "TSA_N"; - case HEVC_NAL_TSA_R : return "TSA_R"; - case HEVC_NAL_STSA_N : return "STSA_N"; - case HEVC_NAL_STSA_R : return "STSA_R"; - case HEVC_NAL_RADL_N : return "RADL_N"; - case HEVC_NAL_RADL_R : return "RADL_R"; - case HEVC_NAL_RASL_N : return "RASL_N"; - case HEVC_NAL_RASL_R : return "RASL_R"; - case HEVC_NAL_BLA_W_LP : return "BLA_W_LP"; - case HEVC_NAL_BLA_W_RADL : return "BLA_W_RADL"; - case HEVC_NAL_BLA_N_LP : return "BLA_N_LP"; - case HEVC_NAL_IDR_W_RADL : return "IDR_W_RADL"; - case HEVC_NAL_IDR_N_LP : return "IDR_N_LP"; - case HEVC_NAL_CRA_NUT : return "CRA_NUT"; - case HEVC_NAL_VPS : return "VPS"; - case HEVC_NAL_SPS : return "SPS"; - case HEVC_NAL_PPS : return "PPS"; - case HEVC_NAL_AUD : return "AUD"; - case HEVC_NAL_EOS_NUT : return "EOS_NUT"; - case HEVC_NAL_EOB_NUT : return "EOB_NUT"; - case HEVC_NAL_FD_NUT : return "FD_NUT"; - case HEVC_NAL_SEI_PREFIX : return "SEI_PREFIX"; - case HEVC_NAL_SEI_SUFFIX : return "SEI_SUFFIX"; - default : return "?"; - } + av_assert0(nal_type >= 0 && nal_type < 64); + return hevc_nal_type_name[nal_type]; +} + +static const char *h264_nal_type_name[32] = { + "Unspecified 0", //H264_NAL_UNSPECIFIED + "Coded slice of a non-IDR picture", // H264_NAL_SLICE + "Coded slice data partition A", // H264_NAL_DPA + "Coded slice data partition B", // H264_NAL_DPB + "Coded slice data partition C", // H264_NAL_DPC + "IDR", // H264_NAL_IDR_SLICE + "SEI", // H264_NAL_SEI + "SPS", // H264_NAL_SPS + "PPS", // H264_NAL_PPS + "AUD", // H264_NAL_AUD + "End of sequence", // H264_NAL_END_SEQUENCE + "End of stream", // H264_NAL_END_STREAM + "Filler data", // H264_NAL_FILLER_DATA + "SPS extension", // H264_NAL_SPS_EXT + "Prefix", // H264_NAL_PREFIX + "Subset SPS", // H264_NAL_SUB_SPS + "Depth parameter set", // H264_NAL_DPS + "Reserved 17", // H264_NAL_RESERVED17 + "Reserved 18", // H264_NAL_RESERVED18 + "Auxiliary coded picture without partitioning", // H264_NAL_AUXILIARY_SLICE + "Slice extension", // H264_NAL_EXTEN_SLICE + "Slice extension for a depth view or a 3D-AVC texture view", // H264_NAL_DEPTH_EXTEN_SLICE + "Reserved 22", // H264_NAL_RESERVED22 + "Reserved 23", // H264_NAL_RESERVED23 + "Unspecified 24", // H264_NAL_UNSPECIFIED24 + "Unspecified 25", // H264_NAL_UNSPECIFIED25 + "Unspecified 26", // H264_NAL_UNSPECIFIED26 + "Unspecified 27", // H264_NAL_UNSPECIFIED27 + "Unspecified 28", // H264_NAL_UNSPECIFIED28 + "Unspecified 29", // H264_NAL_UNSPECIFIED29 + "Unspecified 30", // H264_NAL_UNSPECIFIED30 + "Unspecified 31", // H264_NAL_UNSPECIFIED31 +}; + +static const char *h264_nal_unit_name(int nal_type) +{ + av_assert0(nal_type >= 0 && nal_type < 32); + return h264_nal_type_name[nal_type]; } static int get_bit_length(H2645NAL *nal, int skip_trailing_zeros) @@ -223,7 +306,7 @@ static int hevc_parse_nal_header(H2645NAL *nal, void *logctx) av_log(logctx, AV_LOG_DEBUG, "nal_unit_type: %d(%s), nuh_layer_id: %d, temporal_id: %d\n", - nal->type, nal_unit_name(nal->type), nuh_layer_id, nal->temporal_id); + nal->type, hevc_nal_unit_name(nal->type), nuh_layer_id, nal->temporal_id); return nuh_layer_id == 0; } @@ -239,8 +322,8 @@ static int h264_parse_nal_header(H2645NAL *nal, void *logctx) nal->type = get_bits(gb, 5); av_log(logctx, AV_LOG_DEBUG, - "nal_unit_type: %d, nal_ref_idc: %d\n", - nal->type, nal->ref_idc); + "nal_unit_type: %d(%s), nal_ref_idc: %d\n", + nal->type, h264_nal_unit_name(nal->type), nal->ref_idc); return 1; } @@ -260,9 +343,56 @@ static int find_next_start_code(const uint8_t *buf, const uint8_t *next_avc) return i + 3; } +static void alloc_rbsp_buffer(H2645RBSP *rbsp, unsigned int size, int use_ref) +{ + int min_size = size; + + if (size > INT_MAX - AV_INPUT_BUFFER_PADDING_SIZE) + goto fail; + size += AV_INPUT_BUFFER_PADDING_SIZE; + + if (rbsp->rbsp_buffer_alloc_size >= size && + (!rbsp->rbsp_buffer_ref || av_buffer_is_writable(rbsp->rbsp_buffer_ref))) { + av_assert0(rbsp->rbsp_buffer); + memset(rbsp->rbsp_buffer + min_size, 0, AV_INPUT_BUFFER_PADDING_SIZE); + return; + } + + size = FFMIN(size + size / 16 + 32, INT_MAX); + + if (rbsp->rbsp_buffer_ref) + av_buffer_unref(&rbsp->rbsp_buffer_ref); + else + av_free(rbsp->rbsp_buffer); + + rbsp->rbsp_buffer = av_mallocz(size); + if (!rbsp->rbsp_buffer) + goto fail; + rbsp->rbsp_buffer_alloc_size = size; + + if (use_ref) { + rbsp->rbsp_buffer_ref = av_buffer_create(rbsp->rbsp_buffer, size, + NULL, NULL, 0); + if (!rbsp->rbsp_buffer_ref) + goto fail; + } + + return; + +fail: + rbsp->rbsp_buffer_alloc_size = 0; + if (rbsp->rbsp_buffer_ref) { + av_buffer_unref(&rbsp->rbsp_buffer_ref); + rbsp->rbsp_buffer = NULL; + } else + av_freep(&rbsp->rbsp_buffer); + + return; +} + int ff_h2645_packet_split(H2645Packet *pkt, const uint8_t *buf, int length, void *logctx, int is_nalff, int nal_length_size, - enum AVCodecID codec_id, int small_padding) + enum AVCodecID codec_id, int small_padding, int use_ref) { GetByteContext bc; int consumed, ret = 0; @@ -270,7 +400,8 @@ int ff_h2645_packet_split(H2645Packet *pkt, const uint8_t *buf, int length, int64_t padding = small_padding ? 0 : MAX_MBPAIR_SIZE; bytestream2_init(&bc, buf, length); - av_fast_padded_malloc(&pkt->rbsp.rbsp_buffer, &pkt->rbsp.rbsp_buffer_alloc_size, length + padding); + alloc_rbsp_buffer(&pkt->rbsp, length + padding, use_ref); + if (!pkt->rbsp.rbsp_buffer) return AVERROR(ENOMEM); @@ -373,7 +504,7 @@ int ff_h2645_packet_split(H2645Packet *pkt, const uint8_t *buf, int length, ret = h264_parse_nal_header(nal, logctx); if (ret <= 0 || nal->size <= 0 || nal->size_bits <= 0) { if (ret < 0) { - av_log(logctx, AV_LOG_ERROR, "Invalid NAL unit %d, skipping.\n", + av_log(logctx, AV_LOG_WARNING, "Invalid NAL unit %d, skipping.\n", nal->type); } pkt->nb_nals--; @@ -391,6 +522,10 @@ void ff_h2645_packet_uninit(H2645Packet *pkt) } av_freep(&pkt->nals); pkt->nals_allocated = 0; - av_freep(&pkt->rbsp.rbsp_buffer); + if (pkt->rbsp.rbsp_buffer_ref) { + av_buffer_unref(&pkt->rbsp.rbsp_buffer_ref); + pkt->rbsp.rbsp_buffer = NULL; + } else + av_freep(&pkt->rbsp.rbsp_buffer); pkt->rbsp.rbsp_buffer_alloc_size = pkt->rbsp.rbsp_buffer_size = 0; } diff --git a/libavcodec/h2645_parse.h b/libavcodec/h2645_parse.h index 2e29ad26c..2c29ca517 100644 --- a/libavcodec/h2645_parse.h +++ b/libavcodec/h2645_parse.h @@ -23,6 +23,7 @@ #include +#include "libavutil/buffer.h" #include "avcodec.h" #include "get_bits.h" @@ -66,6 +67,7 @@ typedef struct H2645NAL { typedef struct H2645RBSP { uint8_t *rbsp_buffer; + AVBufferRef *rbsp_buffer_ref; int rbsp_buffer_alloc_size; int rbsp_buffer_size; } H2645RBSP; @@ -86,10 +88,21 @@ int ff_h2645_extract_rbsp(const uint8_t *src, int length, H2645RBSP *rbsp, /** * Split an input packet into NAL units. + * + * If data == raw_data holds true for a NAL unit of the returned pkt, then + * said NAL unit does not contain any emulation_prevention_three_byte and + * the data is contained in the input buffer pointed to by buf. + * Otherwise, the unescaped data is part of the rbsp_buffer described by the + * packet's H2645RBSP. + * + * If the packet's rbsp_buffer_ref is not NULL, the underlying AVBuffer must + * own rbsp_buffer. If not and rbsp_buffer is not NULL, use_ref must be 0. + * If use_ref is set, rbsp_buffer will be reference-counted and owned by + * the underlying AVBuffer of rbsp_buffer_ref. */ int ff_h2645_packet_split(H2645Packet *pkt, const uint8_t *buf, int length, void *logctx, int is_nalff, int nal_length_size, - enum AVCodecID codec_id, int small_padding); + enum AVCodecID codec_id, int small_padding, int use_ref); /** * Free all the allocated memory in the packet. diff --git a/libavcodec/h264_cavlc.c b/libavcodec/h264_cavlc.c index d82144e3c..6481992e5 100644 --- a/libavcodec/h264_cavlc.c +++ b/libavcodec/h264_cavlc.c @@ -923,8 +923,8 @@ decode_intra_mb: const int index= 4*i + block_width*j; int16_t (* mv_cache)[2]= &sl->mv_cache[list][ scan8[index] ]; pred_motion(h, sl, index, block_width, list, sl->ref_cache[list][ scan8[index] ], &mx, &my); - mx += get_se_golomb(&sl->gb); - my += get_se_golomb(&sl->gb); + mx += (unsigned)get_se_golomb(&sl->gb); + my += (unsigned)get_se_golomb(&sl->gb); ff_tlog(h->avctx, "final mv:%d %d\n", mx, my); if(IS_SUB_8X8(sub_mb_type)){ @@ -977,8 +977,8 @@ decode_intra_mb: for (list = 0; list < sl->list_count; list++) { if(IS_DIR(mb_type, 0, list)){ pred_motion(h, sl, 0, 4, list, sl->ref_cache[list][ scan8[0] ], &mx, &my); - mx += get_se_golomb(&sl->gb); - my += get_se_golomb(&sl->gb); + mx += (unsigned)get_se_golomb(&sl->gb); + my += (unsigned)get_se_golomb(&sl->gb); ff_tlog(h->avctx, "final mv:%d %d\n", mx, my); fill_rectangle(sl->mv_cache[list][ scan8[0] ], 4, 4, 8, pack16to32(mx,my), 4); @@ -1012,8 +1012,8 @@ decode_intra_mb: unsigned int val; if(IS_DIR(mb_type, i, list)){ pred_16x8_motion(h, sl, 8*i, list, sl->ref_cache[list][scan8[0] + 16*i], &mx, &my); - mx += get_se_golomb(&sl->gb); - my += get_se_golomb(&sl->gb); + mx += (unsigned)get_se_golomb(&sl->gb); + my += (unsigned)get_se_golomb(&sl->gb); ff_tlog(h->avctx, "final mv:%d %d\n", mx, my); val= pack16to32(mx,my); @@ -1050,8 +1050,8 @@ decode_intra_mb: unsigned int val; if(IS_DIR(mb_type, i, list)){ pred_8x16_motion(h, sl, i*4, list, sl->ref_cache[list][ scan8[0] + 2*i ], &mx, &my); - mx += get_se_golomb(&sl->gb); - my += get_se_golomb(&sl->gb); + mx += (unsigned)get_se_golomb(&sl->gb); + my += (unsigned)get_se_golomb(&sl->gb); ff_tlog(h->avctx, "final mv:%d %d\n", mx, my); val= pack16to32(mx,my); diff --git a/libavcodec/h264_levels.c b/libavcodec/h264_levels.c new file mode 100644 index 000000000..dd517f100 --- /dev/null +++ b/libavcodec/h264_levels.c @@ -0,0 +1,134 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "avcodec.h" +#include "h264_levels.h" + +// H.264 table A-1. +static const H264LevelDescriptor h264_levels[] = { + // Name MaxMBPS MaxBR MinCR + // | level_idc | MaxFS | MaxCPB | MaxMvsPer2Mb + // | | cs3f | | MaxDpbMbs | | MaxVmvR | | + { "1", 10, 0, 1485, 99, 396, 64, 175, 64, 2, 0 }, + { "1b", 11, 1, 1485, 99, 396, 128, 350, 64, 2, 0 }, + { "1b", 9, 0, 1485, 99, 396, 128, 350, 64, 2, 0 }, + { "1.1", 11, 0, 3000, 396, 900, 192, 500, 128, 2, 0 }, + { "1.2", 12, 0, 6000, 396, 2376, 384, 1000, 128, 2, 0 }, + { "1.3", 13, 0, 11880, 396, 2376, 768, 2000, 128, 2, 0 }, + { "2", 20, 0, 11880, 396, 2376, 2000, 2000, 128, 2, 0 }, + { "2.1", 21, 0, 19800, 792, 4752, 4000, 4000, 256, 2, 0 }, + { "2.2", 22, 0, 20250, 1620, 8100, 4000, 4000, 256, 2, 0 }, + { "3", 30, 0, 40500, 1620, 8100, 10000, 10000, 256, 2, 32 }, + { "3.1", 31, 0, 108000, 3600, 18000, 14000, 14000, 512, 4, 16 }, + { "3.2", 32, 0, 216000, 5120, 20480, 20000, 20000, 512, 4, 16 }, + { "4", 40, 0, 245760, 8192, 32768, 20000, 25000, 512, 4, 16 }, + { "4.1", 41, 0, 245760, 8192, 32768, 50000, 62500, 512, 2, 16 }, + { "4.2", 42, 0, 522240, 8704, 34816, 50000, 62500, 512, 2, 16 }, + { "5", 50, 0, 589824, 22080, 110400, 135000, 135000, 512, 2, 16 }, + { "5.1", 51, 0, 983040, 36864, 184320, 240000, 240000, 512, 2, 16 }, + { "5.2", 52, 0, 2073600, 36864, 184320, 240000, 240000, 512, 2, 16 }, + { "6", 60, 0, 4177920, 139264, 696320, 240000, 240000, 8192, 2, 16 }, + { "6.1", 61, 0, 8355840, 139264, 696320, 480000, 480000, 8192, 2, 16 }, + { "6.2", 62, 0, 16711680, 139264, 696320, 800000, 800000, 8192, 2, 16 }, +}; + +// H.264 table A-2 plus values from A-1. +static const struct { + int profile_idc; + int cpb_br_vcl_factor; + int cpb_br_nal_factor; +} h264_br_factors[] = { + { 66, 1000, 1200 }, + { 77, 1000, 1200 }, + { 88, 1000, 1200 }, + { 100, 1250, 1500 }, + { 110, 3000, 3600 }, + { 122, 4000, 4800 }, + { 244, 4000, 4800 }, + { 44, 4000, 4800 }, +}; + +// We are only ever interested in the NAL bitrate factor. +static int h264_get_br_factor(int profile_idc) +{ + int i; + for (i = 0; i < FF_ARRAY_ELEMS(h264_br_factors); i++) { + if (h264_br_factors[i].profile_idc == profile_idc) + return h264_br_factors[i].cpb_br_nal_factor; + } + // Default to the non-high profile value if not specified. + return 1200; +} + +const H264LevelDescriptor *ff_h264_get_level(int level_idc, + int constraint_set3_flag) +{ + int i; + for (i = 0; i < FF_ARRAY_ELEMS(h264_levels); i++) { + if (h264_levels[i].level_idc == level_idc && + h264_levels[i].constraint_set3_flag == constraint_set3_flag) + return &h264_levels[i]; + } + return NULL; +} + +const H264LevelDescriptor *ff_h264_guess_level(int profile_idc, + int64_t bitrate, + int framerate, + int width, int height, + int max_dec_frame_buffering) +{ + int width_mbs = (width + 15) / 16; + int height_mbs = (height + 15) / 16; + int no_cs3f = !(profile_idc == 66 || + profile_idc == 77 || + profile_idc == 88); + int i; + + for (i = 0; i < FF_ARRAY_ELEMS(h264_levels); i++) { + const H264LevelDescriptor *level = &h264_levels[i]; + + if (level->constraint_set3_flag && no_cs3f) + continue; + + if (bitrate > (int64_t)level->max_br * h264_get_br_factor(profile_idc)) + continue; + + if (width_mbs * height_mbs > level->max_fs) + continue; + if (width_mbs * width_mbs > 8 * level->max_fs) + continue; + if (height_mbs * height_mbs > 8 * level->max_fs) + continue; + + if (width_mbs && height_mbs) { + int max_dpb_frames = + FFMIN(level->max_dpb_mbs / (width_mbs * height_mbs), 16); + if (max_dec_frame_buffering > max_dpb_frames) + continue; + + if (framerate > (level->max_mbps / (width_mbs * height_mbs))) + continue; + } + + return level; + } + + // No usable levels found - frame is too big or bitrate is too high. + return NULL; +} diff --git a/libavcodec/h264_levels.h b/libavcodec/h264_levels.h new file mode 100644 index 000000000..0a0f41032 --- /dev/null +++ b/libavcodec/h264_levels.h @@ -0,0 +1,54 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * 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_H264_LEVELS_H +#define AVCODEC_H264_LEVELS_H + + +#include + +typedef struct H264LevelDescriptor { + const char *name; + uint8_t level_idc; + uint8_t constraint_set3_flag; + uint32_t max_mbps; + uint32_t max_fs; + uint32_t max_dpb_mbs; + uint32_t max_br; + uint32_t max_cpb; + uint16_t max_v_mv_r; + uint8_t min_cr; + uint8_t max_mvs_per_2mb; +} H264LevelDescriptor; + +const H264LevelDescriptor *ff_h264_get_level(int level_idc, + int constraint_set3_flag); + +/** + * Guess the level of a stream from some parameters. + * + * Unknown parameters may be zero, in which case they are ignored. + */ +const H264LevelDescriptor *ff_h264_guess_level(int profile_idc, + int64_t bitrate, + int framerate, + int width, int height, + int max_dec_frame_buffering); + + +#endif /* AVCODEC_H264_LEVELS_H */ diff --git a/libavcodec/h264_metadata_bsf.c b/libavcodec/h264_metadata_bsf.c index 27053dbdc..1c1c340d8 100644 --- a/libavcodec/h264_metadata_bsf.c +++ b/libavcodec/h264_metadata_bsf.c @@ -25,6 +25,7 @@ #include "cbs.h" #include "cbs_h264.h" #include "h264.h" +#include "h264_levels.h" #include "h264_sei.h" enum { @@ -39,6 +40,11 @@ enum { FLIP_VERTICAL = 2, }; +enum { + LEVEL_UNSET = -2, + LEVEL_AUTO = -1, +}; + typedef struct H264MetadataContext { const AVClass *class; @@ -74,6 +80,8 @@ typedef struct H264MetadataContext { int display_orientation; double rotate; int flip; + + int level; } H264MetadataContext; @@ -208,26 +216,85 @@ static int h264_metadata_update_sps(AVBSFContext *bsf, CROP(bottom, crop_unit_y); #undef CROP + if (ctx->level != LEVEL_UNSET) { + int level_idc; + + if (ctx->level == LEVEL_AUTO) { + const H264LevelDescriptor *desc; + int64_t bit_rate; + int width, height, dpb_frames; + int framerate; + + if (sps->vui.nal_hrd_parameters_present_flag) { + bit_rate = (sps->vui.nal_hrd_parameters.bit_rate_value_minus1[0] + 1) * + (INT64_C(1) << (sps->vui.nal_hrd_parameters.bit_rate_scale + 6)); + } else if (sps->vui.vcl_hrd_parameters_present_flag) { + bit_rate = (sps->vui.vcl_hrd_parameters.bit_rate_value_minus1[0] + 1) * + (INT64_C(1) << (sps->vui.vcl_hrd_parameters.bit_rate_scale + 6)); + // Adjust for VCL vs. NAL limits. + bit_rate = bit_rate * 6 / 5; + } else { + bit_rate = 0; + } + + // Don't use max_dec_frame_buffering if it is only inferred. + dpb_frames = sps->vui.bitstream_restriction_flag ? + sps->vui.max_dec_frame_buffering : H264_MAX_DPB_FRAMES; + + width = 16 * (sps->pic_width_in_mbs_minus1 + 1); + height = 16 * (sps->pic_height_in_map_units_minus1 + 1) * + (2 - sps->frame_mbs_only_flag); + + if (sps->vui.timing_info_present_flag) + framerate = sps->vui.time_scale / sps->vui.num_units_in_tick / 2; + else + framerate = 0; + + desc = ff_h264_guess_level(sps->profile_idc, bit_rate, framerate, + width, height, dpb_frames); + if (desc) { + level_idc = desc->level_idc; + } else { + av_log(bsf, AV_LOG_WARNING, "Stream does not appear to " + "conform to any level: using level 6.2.\n"); + level_idc = 62; + } + } else { + level_idc = ctx->level; + } + + if (level_idc == 9) { + if (sps->profile_idc == 66 || + sps->profile_idc == 77 || + sps->profile_idc == 88) { + sps->level_idc = 11; + sps->constraint_set3_flag = 1; + } else { + sps->level_idc = 9; + } + } else { + sps->level_idc = level_idc; + } + } + if (need_vui) sps->vui_parameters_present_flag = 1; return 0; } -static int h264_metadata_filter(AVBSFContext *bsf, AVPacket *out) +static int h264_metadata_filter(AVBSFContext *bsf, AVPacket *pkt) { H264MetadataContext *ctx = bsf->priv_data; - AVPacket *in = NULL; CodedBitstreamFragment *au = &ctx->access_unit; int err, i, j, has_sps; - uint8_t *displaymatrix_side_data = NULL; - size_t displaymatrix_side_data_size = 0; + H264RawAUD aud; - err = ff_bsf_get_packet(bsf, &in); + err = ff_bsf_get_packet_ref(bsf, pkt); if (err < 0) return err; - err = ff_cbs_read_packet(ctx->cbc, au, in); + err = ff_cbs_read_packet(ctx->cbc, au, pkt); if (err < 0) { av_log(bsf, AV_LOG_ERROR, "Failed to read packet.\n"); goto fail; @@ -256,9 +323,6 @@ static int h264_metadata_filter(AVBSFContext *bsf, AVPacket *out) 0x3ff, // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; int primary_pic_type_mask = 0xff; - H264RawAUD aud = { - .nal_unit_header.nal_unit_type = H264_NAL_AUD, - }; for (i = 0; i < au->nb_units; i++) { if (au->units[i].type == H264_NAL_SLICE || @@ -281,7 +345,10 @@ static int h264_metadata_filter(AVBSFContext *bsf, AVPacket *out) goto fail; } - aud.primary_pic_type = j; + aud = (H264RawAUD) { + .nal_unit_header.nal_unit_type = H264_NAL_AUD, + .primary_pic_type = j, + }; err = ff_cbs_insert_unit_content(ctx->cbc, au, 0, H264_NAL_AUD, &aud, NULL); @@ -341,8 +408,6 @@ static int h264_metadata_filter(AVBSFContext *bsf, AVPacket *out) udu->data_length = len + 1; memcpy(udu->data, ctx->sei_user_data + i + 1, len + 1); - payload.payload_size = 16 + udu->data_length; - err = ff_cbs_h264_add_sei_message(ctx->cbc, au, &payload); if (err < 0) { av_log(bsf, AV_LOG_ERROR, "Failed to add user data SEI " @@ -360,16 +425,9 @@ static int h264_metadata_filter(AVBSFContext *bsf, AVPacket *out) } if (ctx->delete_filler) { - for (i = 0; i < au->nb_units; i++) { + for (i = au->nb_units - 1; i >= 0; i--) { if (au->units[i].type == H264_NAL_FILLER_DATA) { - // Filler NAL units. - err = ff_cbs_delete_unit(ctx->cbc, au, i); - if (err < 0) { - av_log(bsf, AV_LOG_ERROR, "Failed to delete " - "filler NAL.\n"); - goto fail; - } - --i; + ff_cbs_delete_unit(ctx->cbc, au, i); continue; } @@ -377,34 +435,24 @@ static int h264_metadata_filter(AVBSFContext *bsf, AVPacket *out) // Filler SEI messages. H264RawSEI *sei = au->units[i].content; - for (j = 0; j < sei->payload_count; j++) { + for (j = sei->payload_count - 1; j >= 0; j--) { if (sei->payload[j].payload_type == - H264_SEI_TYPE_FILLER_PAYLOAD) { - err = ff_cbs_h264_delete_sei_message(ctx->cbc, au, - &au->units[i], j); - if (err < 0) { - av_log(bsf, AV_LOG_ERROR, "Failed to delete " - "filler SEI message.\n"); - goto fail; - } - // Renumbering might have happened, start again at - // the same NAL unit position. - --i; - break; - } + H264_SEI_TYPE_FILLER_PAYLOAD) + ff_cbs_h264_delete_sei_message(ctx->cbc, au, + &au->units[i], j); } } } } if (ctx->display_orientation != PASS) { - for (i = 0; i < au->nb_units; i++) { + for (i = au->nb_units - 1; i >= 0; i--) { H264RawSEI *sei; if (au->units[i].type != H264_NAL_SEI) continue; sei = au->units[i].content; - for (j = 0; j < sei->payload_count; j++) { + for (j = sei->payload_count - 1; j >= 0; j--) { H264RawSEIDisplayOrientation *disp; int32_t *matrix; @@ -415,18 +463,12 @@ static int h264_metadata_filter(AVBSFContext *bsf, AVPacket *out) if (ctx->display_orientation == REMOVE || ctx->display_orientation == INSERT) { - err = ff_cbs_h264_delete_sei_message(ctx->cbc, au, - &au->units[i], j); - if (err < 0) { - av_log(bsf, AV_LOG_ERROR, "Failed to delete " - "display orientation SEI message.\n"); - goto fail; - } - --i; - break; + ff_cbs_h264_delete_sei_message(ctx->cbc, au, + &au->units[i], j); + continue; } - matrix = av_mallocz(9 * sizeof(int32_t)); + matrix = av_malloc(9 * sizeof(int32_t)); if (!matrix) { err = AVERROR(ENOMEM); goto fail; @@ -438,11 +480,17 @@ static int h264_metadata_filter(AVBSFContext *bsf, AVPacket *out) av_display_matrix_flip(matrix, disp->hor_flip, disp->ver_flip); // If there are multiple display orientation messages in an - // access unit then ignore all but the last one. - av_freep(&displaymatrix_side_data); - - displaymatrix_side_data = (uint8_t*)matrix; - displaymatrix_side_data_size = 9 * sizeof(int32_t); + // access unit, then the last one added to the packet (i.e. + // the first one in the access unit) will prevail. + err = av_packet_add_side_data(pkt, AV_PKT_DATA_DISPLAYMATRIX, + (uint8_t*)matrix, + 9 * sizeof(int32_t)); + if (err < 0) { + av_log(bsf, AV_LOG_ERROR, "Failed to attach extracted " + "displaymatrix side data to packet.\n"); + av_freep(matrix); + goto fail; + } } } } @@ -456,7 +504,7 @@ static int h264_metadata_filter(AVBSFContext *bsf, AVPacket *out) int size; int write = 0; - data = av_packet_get_side_data(in, AV_PKT_DATA_DISPLAYMATRIX, &size); + data = av_packet_get_side_data(pkt, AV_PKT_DATA_DISPLAYMATRIX, &size); if (data && size >= 9 * sizeof(int32_t)) { int32_t matrix[9]; int hflip, vflip; @@ -516,38 +564,20 @@ static int h264_metadata_filter(AVBSFContext *bsf, AVPacket *out) } } - err = ff_cbs_write_packet(ctx->cbc, out, au); + err = ff_cbs_write_packet(ctx->cbc, pkt, au); if (err < 0) { av_log(bsf, AV_LOG_ERROR, "Failed to write packet.\n"); goto fail; } - err = av_packet_copy_props(out, in); - if (err < 0) - goto fail; - - if (displaymatrix_side_data) { - err = av_packet_add_side_data(out, AV_PKT_DATA_DISPLAYMATRIX, - displaymatrix_side_data, - displaymatrix_side_data_size); - if (err) { - av_log(bsf, AV_LOG_ERROR, "Failed to attach extracted " - "displaymatrix side data to packet.\n"); - goto fail; - } - displaymatrix_side_data = NULL; - } - ctx->done_first_au = 1; err = 0; fail: - ff_cbs_fragment_uninit(ctx->cbc, au); - av_freep(&displaymatrix_side_data); + ff_cbs_fragment_reset(ctx->cbc, au); if (err < 0) - av_packet_unref(out); - av_packet_free(&in); + av_packet_unref(pkt); return err; } @@ -586,13 +616,15 @@ static int h264_metadata_init(AVBSFContext *bsf) err = 0; fail: - ff_cbs_fragment_uninit(ctx->cbc, au); + ff_cbs_fragment_reset(ctx->cbc, au); return err; } static void h264_metadata_close(AVBSFContext *bsf) { H264MetadataContext *ctx = bsf->priv_data; + + ff_cbs_fragment_free(ctx->cbc, &ctx->access_unit); ff_cbs_close(&ctx->cbc); } @@ -684,6 +716,36 @@ static const AVOption h264_metadata_options[] = { 0, AV_OPT_TYPE_CONST, { .i64 = FLIP_VERTICAL }, .flags = FLAGS, .unit = "flip" }, + { "level", "Set level (table A-1)", + OFFSET(level), AV_OPT_TYPE_INT, + { .i64 = LEVEL_UNSET }, LEVEL_UNSET, 0xff, FLAGS, "level" }, + { "auto", "Attempt to guess level from stream properties", + 0, AV_OPT_TYPE_CONST, + { .i64 = LEVEL_AUTO }, .flags = FLAGS, .unit = "level" }, +#define LEVEL(name, value) name, NULL, 0, AV_OPT_TYPE_CONST, \ + { .i64 = value }, .flags = FLAGS, .unit = "level" + { LEVEL("1", 10) }, + { LEVEL("1b", 9) }, + { LEVEL("1.1", 11) }, + { LEVEL("1.2", 12) }, + { LEVEL("1.3", 13) }, + { LEVEL("2", 20) }, + { LEVEL("2.1", 21) }, + { LEVEL("2.2", 22) }, + { LEVEL("3", 30) }, + { LEVEL("3.1", 31) }, + { LEVEL("3.2", 32) }, + { LEVEL("4", 40) }, + { LEVEL("4.1", 41) }, + { LEVEL("4.2", 42) }, + { LEVEL("5", 50) }, + { LEVEL("5.1", 51) }, + { LEVEL("5.2", 52) }, + { LEVEL("6", 60) }, + { LEVEL("6.1", 61) }, + { LEVEL("6.2", 62) }, +#undef LEVEL + { NULL } }; diff --git a/libavcodec/h264_mp4toannexb_bsf.c b/libavcodec/h264_mp4toannexb_bsf.c index 292d10643..fb3f24ea4 100644 --- a/libavcodec/h264_mp4toannexb_bsf.c +++ b/libavcodec/h264_mp4toannexb_bsf.c @@ -26,6 +26,7 @@ #include "avcodec.h" #include "bsf.h" +#include "h264.h" typedef struct H264BSFContext { int32_t sps_offset; @@ -209,9 +210,9 @@ static int h264_mp4toannexb_filter(AVBSFContext *ctx, AVPacket *out) if (nal_size > buf_end - buf || nal_size < 0) goto fail; - if (unit_type == 7) + if (unit_type == H264_NAL_SPS) s->idr_sps_seen = s->new_idr = 1; - else if (unit_type == 8) { + else if (unit_type == H264_NAL_PPS) { s->idr_pps_seen = s->new_idr = 1; /* if SPS has not been seen yet, prepend the AVCC one to PPS */ if (!s->idr_sps_seen) { @@ -232,18 +233,18 @@ static int h264_mp4toannexb_filter(AVBSFContext *ctx, AVPacket *out) /* if this is a new IDR picture following an IDR picture, reset the idr flag. * Just check first_mb_in_slice to be 0 as this is the simplest solution. * This could be checking idr_pic_id instead, but would complexify the parsing. */ - if (!s->new_idr && unit_type == 5 && (buf[1] & 0x80)) + if (!s->new_idr && unit_type == H264_NAL_IDR_SLICE && (buf[1] & 0x80)) s->new_idr = 1; /* prepend only to the first type 5 NAL unit of an IDR picture, if no sps/pps are already present */ - if (s->new_idr && unit_type == 5 && !s->idr_sps_seen && !s->idr_pps_seen) { + if (s->new_idr && unit_type == H264_NAL_IDR_SLICE && !s->idr_sps_seen && !s->idr_pps_seen) { if ((ret=alloc_and_copy(out, ctx->par_out->extradata, ctx->par_out->extradata_size, buf, nal_size, 1)) < 0) goto fail; s->new_idr = 0; /* if only SPS has been seen, also insert PPS */ - } else if (s->new_idr && unit_type == 5 && s->idr_sps_seen && !s->idr_pps_seen) { + } else if (s->new_idr && unit_type == H264_NAL_IDR_SLICE && s->idr_sps_seen && !s->idr_pps_seen) { if (s->pps_offset == -1) { av_log(ctx, AV_LOG_WARNING, "PPS not present in the stream, nor in AVCC, stream may be unreadable\n"); if ((ret = alloc_and_copy(out, NULL, 0, buf, nal_size, 0)) < 0) @@ -253,9 +254,9 @@ static int h264_mp4toannexb_filter(AVBSFContext *ctx, AVPacket *out) buf, nal_size, 1)) < 0) goto fail; } else { - if ((ret=alloc_and_copy(out, NULL, 0, buf, nal_size, unit_type == 7 || unit_type == 8)) < 0) + if ((ret=alloc_and_copy(out, NULL, 0, buf, nal_size, unit_type == H264_NAL_SPS || unit_type == H264_NAL_PPS)) < 0) goto fail; - if (!s->new_idr && unit_type == 1) { + if (!s->new_idr && unit_type == H264_NAL_SLICE) { s->new_idr = 1; s->idr_sps_seen = 0; s->idr_pps_seen = 0; @@ -279,6 +280,15 @@ fail: return ret; } +static void h264_mp4toannexb_flush(AVBSFContext *ctx) +{ + H264BSFContext *s = ctx->priv_data; + + s->idr_sps_seen = 0; + s->idr_pps_seen = 0; + s->new_idr = s->extradata_parsed; +} + static const enum AVCodecID codec_ids[] = { AV_CODEC_ID_H264, AV_CODEC_ID_NONE, }; @@ -288,5 +298,6 @@ const AVBitStreamFilter ff_h264_mp4toannexb_bsf = { .priv_data_size = sizeof(H264BSFContext), .init = h264_mp4toannexb_init, .filter = h264_mp4toannexb_filter, + .flush = h264_mp4toannexb_flush, .codec_ids = codec_ids, }; diff --git a/libavcodec/h264_parse.c b/libavcodec/h264_parse.c index 87e5b3cdc..ac31f54e0 100644 --- a/libavcodec/h264_parse.c +++ b/libavcodec/h264_parse.c @@ -120,7 +120,7 @@ int ff_h264_pred_weight_table(GetBitContext *gb, const SPS *sps, pwt->use_weight = pwt->use_weight || pwt->use_weight_chroma; return 0; out_range_weight: - avpriv_request_sample(logctx, "Out of range weight\n"); + avpriv_request_sample(logctx, "Out of range weight"); return AVERROR_INVALIDDATA; } @@ -242,18 +242,23 @@ int ff_h264_parse_ref_count(int *plist_count, int ref_count[2], ref_count[1] = 1; } - if (ref_count[0] - 1 > max[0] || ref_count[1] - 1 > max[1]) { + if (slice_type_nos == AV_PICTURE_TYPE_B) + list_count = 2; + else + list_count = 1; + + if (ref_count[0] - 1 > max[0] || (list_count == 2 && (ref_count[1] - 1 > max[1]))) { av_log(logctx, AV_LOG_ERROR, "reference overflow %u > %u or %u > %u\n", ref_count[0] - 1, max[0], ref_count[1] - 1, max[1]); ref_count[0] = ref_count[1] = 0; *plist_count = 0; goto fail; + } else if (ref_count[1] - 1 > max[1]) { + av_log(logctx, AV_LOG_DEBUG, "reference overflow %u > %u \n", + ref_count[1] - 1, max[1]); + ref_count[1] = 0; } - if (slice_type_nos == AV_PICTURE_TYPE_B) - list_count = 2; - else - list_count = 1; } else { list_count = 0; ref_count[0] = ref_count[1] = 0; @@ -296,7 +301,8 @@ int ff_h264_init_poc(int pic_field_poc[2], int *pic_poc, if (picture_structure == PICT_FRAME) field_poc[1] += pc->delta_poc_bottom; } else if (sps->poc_type == 1) { - int abs_frame_num, expected_delta_per_poc_cycle, expectedpoc; + int abs_frame_num; + int64_t expected_delta_per_poc_cycle, expectedpoc; int i; if (sps->poc_cycle_length != 0) @@ -359,7 +365,7 @@ static int decode_extradata_ps(const uint8_t *data, int size, H264ParamSets *ps, H2645Packet pkt = { 0 }; int i, ret = 0; - ret = ff_h2645_packet_split(&pkt, data, size, logctx, is_avc, 2, AV_CODEC_ID_H264, 1); + ret = ff_h2645_packet_split(&pkt, data, size, logctx, is_avc, 2, AV_CODEC_ID_H264, 1, 0); if (ret < 0) { ret = 0; goto fail; diff --git a/libavcodec/h264_ps.c b/libavcodec/h264_ps.c index 17bfa780c..e8738d850 100644 --- a/libavcodec/h264_ps.c +++ b/libavcodec/h264_ps.c @@ -449,8 +449,17 @@ int ff_h264_decode_seq_parameter_set(GetBitContext *gb, AVCodecContext *avctx, sps->log2_max_poc_lsb = t + 4; } else if (sps->poc_type == 1) { // FIXME #define sps->delta_pic_order_always_zero_flag = get_bits1(gb); - sps->offset_for_non_ref_pic = get_se_golomb(gb); - sps->offset_for_top_to_bottom_field = get_se_golomb(gb); + sps->offset_for_non_ref_pic = get_se_golomb_long(gb); + sps->offset_for_top_to_bottom_field = get_se_golomb_long(gb); + + if ( sps->offset_for_non_ref_pic == INT32_MIN + || sps->offset_for_top_to_bottom_field == INT32_MIN + ) { + av_log(avctx, AV_LOG_ERROR, + "offset_for_non_ref_pic or offset_for_top_to_bottom_field is out of range\n"); + goto fail; + } + sps->poc_cycle_length = get_ue_golomb(gb); if ((unsigned)sps->poc_cycle_length >= @@ -460,8 +469,14 @@ int ff_h264_decode_seq_parameter_set(GetBitContext *gb, AVCodecContext *avctx, goto fail; } - for (i = 0; i < sps->poc_cycle_length; i++) - sps->offset_for_ref_frame[i] = get_se_golomb(gb); + for (i = 0; i < sps->poc_cycle_length; i++) { + sps->offset_for_ref_frame[i] = get_se_golomb_long(gb); + if (sps->offset_for_ref_frame[i] == INT32_MIN) { + av_log(avctx, AV_LOG_ERROR, + "offset_for_ref_frame is out of range\n"); + goto fail; + } + } } else if (sps->poc_type != 2) { av_log(avctx, AV_LOG_ERROR, "illegal POC type %d\n", sps->poc_type); goto fail; diff --git a/libavcodec/h264_ps.h b/libavcodec/h264_ps.h index e967b9cbc..9014326df 100644 --- a/libavcodec/h264_ps.h +++ b/libavcodec/h264_ps.h @@ -81,7 +81,7 @@ typedef struct SPS { uint32_t num_units_in_tick; uint32_t time_scale; int fixed_frame_rate_flag; - short offset_for_ref_frame[256]; // FIXME dyn aloc? + int32_t offset_for_ref_frame[256]; int bitstream_restriction_flag; int num_reorder_frames; int scaling_matrix_present; diff --git a/libavcodec/h264_redundant_pps_bsf.c b/libavcodec/h264_redundant_pps_bsf.c index 46cd77a7c..8405738c4 100644 --- a/libavcodec/h264_redundant_pps_bsf.c +++ b/libavcodec/h264_redundant_pps_bsf.c @@ -35,6 +35,7 @@ typedef struct H264RedundantPPSContext { int global_pic_init_qp; int current_pic_init_qp; + int extradata_pic_init_qp; } H264RedundantPPSContext; @@ -65,21 +66,20 @@ static int h264_redundant_pps_fixup_slice(H264RedundantPPSContext *ctx, return 0; } -static int h264_redundant_pps_filter(AVBSFContext *bsf, AVPacket *out) +static int h264_redundant_pps_filter(AVBSFContext *bsf, AVPacket *pkt) { H264RedundantPPSContext *ctx = bsf->priv_data; - AVPacket *in; CodedBitstreamFragment *au = &ctx->access_unit; int au_has_sps; int err, i; - err = ff_bsf_get_packet(bsf, &in); + err = ff_bsf_get_packet_ref(bsf, pkt); if (err < 0) return err; - err = ff_cbs_read_packet(ctx->input, au, in); + err = ff_cbs_read_packet(ctx->input, au, pkt); if (err < 0) - return err; + goto fail; au_has_sps = 0; for (i = 0; i < au->nb_units; i++) { @@ -88,11 +88,15 @@ static int h264_redundant_pps_filter(AVBSFContext *bsf, AVPacket *out) if (nal->type == H264_NAL_SPS) au_has_sps = 1; if (nal->type == H264_NAL_PPS) { - h264_redundant_pps_fixup_pps(ctx, nal->content); + err = h264_redundant_pps_fixup_pps(ctx, nal->content); + if (err < 0) + goto fail; if (!au_has_sps) { av_log(bsf, AV_LOG_VERBOSE, "Deleting redundant PPS " - "at %"PRId64".\n", in->pts); + "at %"PRId64".\n", pkt->pts); ff_cbs_delete_unit(ctx->input, au, i); + i--; + continue; } } if (nal->type == H264_NAL_SLICE || @@ -102,19 +106,17 @@ static int h264_redundant_pps_filter(AVBSFContext *bsf, AVPacket *out) } } - err = ff_cbs_write_packet(ctx->output, out, au); + err = ff_cbs_write_packet(ctx->output, pkt, au); if (err < 0) - return err; + goto fail; - ff_cbs_fragment_uninit(ctx->output, au); - - err = av_packet_copy_props(out, in); + err = 0; +fail: + ff_cbs_fragment_reset(ctx->output, au); if (err < 0) - return err; + av_packet_unref(pkt); - av_packet_free(&in); - - return 0; + return err; } static int h264_redundant_pps_init(AVBSFContext *bsf) @@ -137,29 +139,42 @@ static int h264_redundant_pps_init(AVBSFContext *bsf) err = ff_cbs_read_extradata(ctx->input, au, bsf->par_in); if (err < 0) { av_log(bsf, AV_LOG_ERROR, "Failed to read extradata.\n"); - return err; + goto fail; } for (i = 0; i < au->nb_units; i++) { - if (au->units[i].type == H264_NAL_PPS) - h264_redundant_pps_fixup_pps(ctx, au->units[i].content); + if (au->units[i].type == H264_NAL_PPS) { + err = h264_redundant_pps_fixup_pps(ctx, au->units[i].content); + if (err < 0) + goto fail; + } } + ctx->extradata_pic_init_qp = ctx->current_pic_init_qp; err = ff_cbs_write_extradata(ctx->output, bsf->par_out, au); if (err < 0) { av_log(bsf, AV_LOG_ERROR, "Failed to write extradata.\n"); - return err; + goto fail; } - - ff_cbs_fragment_uninit(ctx->output, au); } - return 0; + err = 0; +fail: + ff_cbs_fragment_reset(ctx->output, au); + return err; +} + +static void h264_redundant_pps_flush(AVBSFContext *bsf) +{ + H264RedundantPPSContext *ctx = bsf->priv_data; + ctx->current_pic_init_qp = ctx->extradata_pic_init_qp; } static void h264_redundant_pps_close(AVBSFContext *bsf) { H264RedundantPPSContext *ctx = bsf->priv_data; + + ff_cbs_fragment_free(ctx->input, &ctx->access_unit); ff_cbs_close(&ctx->input); ff_cbs_close(&ctx->output); } @@ -172,6 +187,7 @@ const AVBitStreamFilter ff_h264_redundant_pps_bsf = { .name = "h264_redundant_pps", .priv_data_size = sizeof(H264RedundantPPSContext), .init = &h264_redundant_pps_init, + .flush = &h264_redundant_pps_flush, .close = &h264_redundant_pps_close, .filter = &h264_redundant_pps_filter, .codec_ids = h264_redundant_pps_codec_ids, diff --git a/libavcodec/h264_refs.c b/libavcodec/h264_refs.c index 388bd7881..74087ff26 100644 --- a/libavcodec/h264_refs.c +++ b/libavcodec/h264_refs.c @@ -373,9 +373,11 @@ int ff_h264_build_ref_list(H264Context *h, H264SliceContext *sl) av_assert0(0); } - if (i < 0) { + if (i < 0 || mismatches_ref(h, ref)) { av_log(h->avctx, AV_LOG_ERROR, - "reference picture missing during reorder\n"); + i < 0 ? "reference picture missing during reorder\n" : + "mismatching reference\n" + ); memset(&sl->ref_list[list][index], 0, sizeof(sl->ref_list[0][0])); // FIXME } else { for (i = index; i + 1 < sl->ref_count[list]; i++) { @@ -816,6 +818,7 @@ int ff_h264_execute_ref_pic_marking(H264Context *h) if ( err >= 0 && h->long_ref_count==0 && ( h->short_ref_count<=2 + || pps_ref_count[0] <= 2 && pps_ref_count[1] <= 1 && h->avctx->has_b_frames || pps_ref_count[0] <= 1 + (h->picture_structure != PICT_FRAME) && pps_ref_count[1] <= 1) && pps_ref_count[0]<=2 + (h->picture_structure != PICT_FRAME) + (2*!h->has_recovery_point) && h->cur_pic_ptr->f->pict_type == AV_PICTURE_TYPE_I){ diff --git a/libavcodec/h264_sei.c b/libavcodec/h264_sei.c index 649908621..d4eb9c0da 100644 --- a/libavcodec/h264_sei.c +++ b/libavcodec/h264_sei.c @@ -51,8 +51,7 @@ void ff_h264_sei_uninit(H264SEIContext *h) h->display_orientation.present = 0; h->afd.present = 0; - h->a53_caption.a53_caption_size = 0; - av_freep(&h->a53_caption.a53_caption); + av_buffer_unref(&h->a53_caption.buf_ref); } static int decode_picture_timing(H264SEIPictureTiming *h, GetBitContext *gb, @@ -85,32 +84,38 @@ static int decode_picture_timing(H264SEIPictureTiming *h, GetBitContext *gb, return AVERROR_INVALIDDATA; num_clock_ts = sei_num_clock_ts_table[h->pic_struct]; - + h->timecode_cnt = 0; for (i = 0; i < num_clock_ts; i++) { - if (get_bits(gb, 1)) { /* clock_timestamp_flag */ + if (get_bits(gb, 1)) { /* clock_timestamp_flag */ + H264SEITimeCode *tc = &h->timecode[h->timecode_cnt++]; unsigned int full_timestamp_flag; - + unsigned int counting_type, cnt_dropped_flag; h->ct_type |= 1 << get_bits(gb, 2); - skip_bits(gb, 1); /* nuit_field_based_flag */ - skip_bits(gb, 5); /* counting_type */ + skip_bits(gb, 1); /* nuit_field_based_flag */ + counting_type = get_bits(gb, 5); /* counting_type */ full_timestamp_flag = get_bits(gb, 1); - skip_bits(gb, 1); /* discontinuity_flag */ - skip_bits(gb, 1); /* cnt_dropped_flag */ - skip_bits(gb, 8); /* n_frames */ + skip_bits(gb, 1); /* discontinuity_flag */ + cnt_dropped_flag = get_bits(gb, 1); /* cnt_dropped_flag */ + if (cnt_dropped_flag && counting_type > 1 && counting_type < 7) + tc->dropframe = 1; + tc->frame = get_bits(gb, 8); /* n_frames */ if (full_timestamp_flag) { - skip_bits(gb, 6); /* seconds_value 0..59 */ - skip_bits(gb, 6); /* minutes_value 0..59 */ - skip_bits(gb, 5); /* hours_value 0..23 */ + tc->full = 1; + tc->seconds = get_bits(gb, 6); /* seconds_value 0..59 */ + tc->minutes = get_bits(gb, 6); /* minutes_value 0..59 */ + tc->hours = get_bits(gb, 5); /* hours_value 0..23 */ } else { - if (get_bits(gb, 1)) { /* seconds_flag */ - skip_bits(gb, 6); /* seconds_value range 0..59 */ - if (get_bits(gb, 1)) { /* minutes_flag */ - skip_bits(gb, 6); /* minutes_value 0..59 */ - if (get_bits(gb, 1)) /* hours_flag */ - skip_bits(gb, 5); /* hours_value 0..23 */ + tc->seconds = tc->minutes = tc->hours = tc->full = 0; + if (get_bits(gb, 1)) { /* seconds_flag */ + tc->seconds = get_bits(gb, 6); + if (get_bits(gb, 1)) { /* minutes_flag */ + tc->minutes = get_bits(gb, 6); + if (get_bits(gb, 1)) /* hours_flag */ + tc->hours = get_bits(gb, 5); } } } + if (sps->time_offset_length > 0) skip_bits(gb, sps->time_offset_length); /* time_offset */ @@ -169,7 +174,8 @@ static int decode_registered_user_data_closed_caption(H264SEIA53Caption *h, size -= 2; if (cc_count && size >= cc_count * 3) { - const uint64_t new_size = (h->a53_caption_size + cc_count + int old_size = h->buf_ref ? h->buf_ref->size : 0; + const uint64_t new_size = (old_size + cc_count * UINT64_C(3)); int i, ret; @@ -177,14 +183,15 @@ static int decode_registered_user_data_closed_caption(H264SEIA53Caption *h, return AVERROR(EINVAL); /* Allow merging of the cc data from two fields. */ - ret = av_reallocp(&h->a53_caption, new_size); + ret = av_buffer_realloc(&h->buf_ref, new_size); if (ret < 0) return ret; + /* Use of av_buffer_realloc assumes buffer is writeable */ for (i = 0; i < cc_count; i++) { - h->a53_caption[h->a53_caption_size++] = get_bits(gb, 8); - h->a53_caption[h->a53_caption_size++] = get_bits(gb, 8); - h->a53_caption[h->a53_caption_size++] = get_bits(gb, 8); + h->buf_ref->data[old_size++] = get_bits(gb, 8); + h->buf_ref->data[old_size++] = get_bits(gb, 8); + h->buf_ref->data[old_size++] = get_bits(gb, 8); } skip_bits(gb, 8); // marker_bits diff --git a/libavcodec/h264_sei.h b/libavcodec/h264_sei.h index 9488382b9..a75c3aa17 100644 --- a/libavcodec/h264_sei.h +++ b/libavcodec/h264_sei.h @@ -27,6 +27,7 @@ typedef enum { H264_SEI_TYPE_BUFFERING_PERIOD = 0, ///< buffering period (H.264, D.1.1) H264_SEI_TYPE_PIC_TIMING = 1, ///< picture timing + H264_SEI_TYPE_PAN_SCAN_RECT = 2, ///< pan-scan rectangle H264_SEI_TYPE_FILLER_PAYLOAD = 3, ///< filler data H264_SEI_TYPE_USER_DATA_REGISTERED = 4, ///< registered user data as specified by Rec. ITU-T T.35 H264_SEI_TYPE_USER_DATA_UNREGISTERED = 5, ///< unregistered user data @@ -34,6 +35,7 @@ typedef enum { H264_SEI_TYPE_FRAME_PACKING = 45, ///< frame packing arrangement H264_SEI_TYPE_DISPLAY_ORIENTATION = 47, ///< display orientation H264_SEI_TYPE_GREEN_METADATA = 56, ///< GreenMPEG information + H264_SEI_TYPE_MASTERING_DISPLAY_COLOUR_VOLUME = 137, ///< mastering display properties H264_SEI_TYPE_ALTERNATIVE_TRANSFER = 147, ///< alternative transfer } H264_SEI_Type; @@ -65,6 +67,17 @@ typedef enum { H264_SEI_FPA_TYPE_2D = 6, } H264_SEI_FpaType; +typedef struct H264SEITimeCode { + /* When not continuously receiving full timecodes, we have to reference + the previous timecode received */ + int full; + int frame; + int seconds; + int minutes; + int hours; + int dropframe; +} H264SEITimeCode; + typedef struct H264SEIPictureTiming { int present; H264_SEI_PicStructType pic_struct; @@ -85,6 +98,16 @@ typedef struct H264SEIPictureTiming { * cpb_removal_delay in picture timing SEI message, see H.264 C.1.2 */ int cpb_removal_delay; + + /** + * Maximum three timecodes in a pic_timing SEI. + */ + H264SEITimeCode timecode[3]; + + /** + * Number of timecode in use + */ + int timecode_cnt; } H264SEIPictureTiming; typedef struct H264SEIAFD { @@ -93,8 +116,7 @@ typedef struct H264SEIAFD { } H264SEIAFD; typedef struct H264SEIA53Caption { - int a53_caption_size; - uint8_t *a53_caption; + AVBufferRef *buf_ref; } H264SEIA53Caption; typedef struct H264SEIUnregistered { diff --git a/libavcodec/h264_slice.c b/libavcodec/h264_slice.c index 0790f32a4..5ceee107a 100644 --- a/libavcodec/h264_slice.c +++ b/libavcodec/h264_slice.c @@ -358,6 +358,7 @@ int ff_h264_update_thread_context(AVCodecContext *dst, h->mb_num = h1->mb_num; h->mb_stride = h1->mb_stride; h->b_stride = h1->b_stride; + h->x264_build = h1->x264_build; if (h->context_initialized || h1->context_initialized) { if ((err = h264_slice_header_init(h)) < 0) { @@ -399,7 +400,6 @@ int ff_h264_update_thread_context(AVCodecContext *dst, h->enable_er = h1->enable_er; h->workaround_bugs = h1->workaround_bugs; - h->x264_build = h1->x264_build; h->droppable = h1->droppable; // extradata/NAL handling @@ -430,6 +430,13 @@ int ff_h264_update_thread_context(AVCodecContext *dst, h->frame_recovered = h1->frame_recovered; + av_buffer_unref(&h->sei.a53_caption.buf_ref); + if (h1->sei.a53_caption.buf_ref) { + h->sei.a53_caption.buf_ref = av_buffer_ref(h1->sei.a53_caption.buf_ref); + if (!h->sei.a53_caption.buf_ref) + return AVERROR(ENOMEM); + } + if (!h->cur_pic_ptr) return 0; @@ -1085,6 +1092,12 @@ static int h264_init_ps(H264Context *h, const H264SliceContext *sl, int first_sl h->avctx->colorspace = sps->colorspace; } } + + if (h->sei.alternative_transfer.present && + av_color_transfer_name(h->sei.alternative_transfer.preferred_transfer_characteristics) && + h->sei.alternative_transfer.preferred_transfer_characteristics != AVCOL_TRC_UNSPECIFIED) { + h->avctx->color_trc = h->sei.alternative_transfer.preferred_transfer_characteristics; + } } if (!h->context_initialized || must_reinit || needs_reinit) { @@ -1269,22 +1282,60 @@ static int h264_export_frame_props(H264Context *h) } } - if (h->sei.a53_caption.a53_caption) { + if (h->sei.a53_caption.buf_ref) { H264SEIA53Caption *a53 = &h->sei.a53_caption; - AVFrameSideData *sd = av_frame_new_side_data(cur->f, - AV_FRAME_DATA_A53_CC, - a53->a53_caption_size); - if (sd) - memcpy(sd->data, a53->a53_caption, a53->a53_caption_size); - av_freep(&a53->a53_caption); - a53->a53_caption_size = 0; + + AVFrameSideData *sd = av_frame_new_side_data_from_buf(cur->f, AV_FRAME_DATA_A53_CC, a53->buf_ref); + if (!sd) + av_buffer_unref(&a53->buf_ref); + a53->buf_ref = NULL; + h->avctx->properties |= FF_CODEC_PROPERTY_CLOSED_CAPTIONS; } - if (h->sei.alternative_transfer.present && - av_color_transfer_name(h->sei.alternative_transfer.preferred_transfer_characteristics) && - h->sei.alternative_transfer.preferred_transfer_characteristics != AVCOL_TRC_UNSPECIFIED) { - h->avctx->color_trc = cur->f->color_trc = h->sei.alternative_transfer.preferred_transfer_characteristics; + if (h->sei.picture_timing.timecode_cnt > 0) { + uint32_t tc = 0; + uint32_t *tc_sd; + + AVFrameSideData *tcside = av_frame_new_side_data(cur->f, + AV_FRAME_DATA_S12M_TIMECODE, + sizeof(uint32_t)*4); + if (!tcside) + return AVERROR(ENOMEM); + + tc_sd = (uint32_t*)tcside->data; + tc_sd[0] = h->sei.picture_timing.timecode_cnt; + + for (int i = 0; i < tc_sd[0]; i++) { + uint32_t frames; + + /* For SMPTE 12-M timecodes, frame count is a special case if > 30 FPS. + See SMPTE ST 12-1:2014 Sec 12.1 for more info. */ + if (av_cmp_q(h->avctx->framerate, (AVRational) {30, 1}) == 1) { + frames = h->sei.picture_timing.timecode[i].frame / 2; + if (h->sei.picture_timing.timecode[i].frame % 2 == 1) { + if (av_cmp_q(h->avctx->framerate, (AVRational) {50, 1}) == 0) + tc |= (1 << 7); + else + tc |= (1 << 23); + } + } else { + frames = h->sei.picture_timing.timecode[i].frame; + } + + tc |= h->sei.picture_timing.timecode[i].dropframe << 30; + tc |= (frames / 10) << 28; + tc |= (frames % 10) << 24; + tc |= (h->sei.picture_timing.timecode[i].seconds / 10) << 20; + tc |= (h->sei.picture_timing.timecode[i].seconds % 10) << 16; + tc |= (h->sei.picture_timing.timecode[i].minutes / 10) << 12; + tc |= (h->sei.picture_timing.timecode[i].minutes % 10) << 8; + tc |= (h->sei.picture_timing.timecode[i].hours / 10) << 4; + tc |= (h->sei.picture_timing.timecode[i].hours % 10); + + tc_sd[i + 1] = tc; + } + h->sei.picture_timing.timecode_cnt = 0; } return 0; @@ -1407,6 +1458,11 @@ static int h264_field_start(H264Context *h, const H264SliceContext *sl, sps = h->ps.sps; + if (sps && sps->bitstream_restriction_flag && + h->avctx->has_b_frames < sps->num_reorder_frames) { + h->avctx->has_b_frames = sps->num_reorder_frames; + } + last_pic_droppable = h->droppable; last_pic_structure = h->picture_structure; h->droppable = (nal->ref_idc == 0); diff --git a/libavcodec/h264dec.c b/libavcodec/h264dec.c index 7494c7a8f..8d1bd16a8 100644 --- a/libavcodec/h264dec.c +++ b/libavcodec/h264dec.c @@ -609,9 +609,10 @@ static int decode_nal_units(H264Context *h, const uint8_t *buf, int buf_size) if (!(avctx->flags2 & AV_CODEC_FLAG2_CHUNKS)) { h->current_slice = 0; - if (!h->first_field) + if (!h->first_field) { h->cur_pic_ptr = NULL; - ff_h264_sei_uninit(&h->sei); + ff_h264_sei_uninit(&h->sei); + } } if (h->nal_length_size == 4) { @@ -621,8 +622,8 @@ static int decode_nal_units(H264Context *h, const uint8_t *buf, int buf_size) h->is_avc = 1; } - ret = ff_h2645_packet_split(&h->pkt, buf, buf_size, avctx, h->is_avc, - h->nal_length_size, avctx->codec_id, avctx->flags2 & AV_CODEC_FLAG2_FAST); + ret = ff_h2645_packet_split(&h->pkt, buf, buf_size, avctx, h->is_avc, h->nal_length_size, + avctx->codec_id, avctx->flags2 & AV_CODEC_FLAG2_FAST, 0); if (ret < 0) { av_log(avctx, AV_LOG_ERROR, "Error splitting the input into NAL units.\n"); @@ -656,11 +657,6 @@ static int decode_nal_units(H264Context *h, const uint8_t *buf, int buf_size) goto end; } if(!idr_cleared) { - if (h->current_slice && (avctx->active_thread_type & FF_THREAD_SLICE)) { - av_log(h, AV_LOG_ERROR, "invalid mixed IDR / non IDR frames cannot be decoded in slice multithreading mode\n"); - ret = AVERROR_INVALIDDATA; - goto end; - } idr(h); // FIXME ensure we don't lose some frames if there is reordering } idr_cleared = 1; @@ -765,6 +761,11 @@ static int decode_nal_units(H264Context *h, const uint8_t *buf, int buf_size) if (ret < 0 && (h->avctx->err_recognition & AV_EF_EXPLODE)) goto end; + // set decode_error_flags to allow users to detect concealed decoding errors + if ((ret < 0 || h->slice_ctx->er.error_occurred) && h->cur_pic_ptr) { + h->cur_pic_ptr->f->decode_error_flags |= FF_DECODE_ERROR_DECODE_SLICES; + } + ret = 0; end: @@ -854,6 +855,8 @@ static int is_extra(const uint8_t *buf, int buf_size) { int cnt= buf[5]&0x1f; const uint8_t *p= buf+6; + if (!cnt) + return 0; while(cnt--){ int nalsize= AV_RB16(p) + 2; if(nalsize > buf_size - (p-buf) || (p[2] & 0x9F) != 7) @@ -983,7 +986,7 @@ static int h264_decode_frame(AVCodecContext *avctx, void *data, &h->ps, &h->is_avc, &h->nal_length_size, avctx->err_recognition, avctx); } - if(h->is_avc && buf_size >= 9 && buf[0]==1 && buf[2]==0 && (buf[4]&0xFC)==0xFC && (buf[5]&0x1F) && buf[8]==0x67){ + if (h->is_avc && buf_size >= 9 && buf[0]==1 && buf[2]==0 && (buf[4]&0xFC)==0xFC) { if (is_extra(buf, buf_size)) return ff_h264_decode_extradata(buf, buf_size, &h->ps, &h->is_avc, &h->nal_length_size, diff --git a/libavcodec/h264dsp.h b/libavcodec/h264dsp.h index bcd76abcc..cbea3173c 100644 --- a/libavcodec/h264dsp.h +++ b/libavcodec/h264dsp.h @@ -45,32 +45,32 @@ typedef struct H264DSPContext { h264_biweight_func biweight_h264_pixels_tab[4]; /* loop filter */ - void (*h264_v_loop_filter_luma)(uint8_t *pix /*align 16*/, int stride, + void (*h264_v_loop_filter_luma)(uint8_t *pix /*align 16*/, ptrdiff_t stride, int alpha, int beta, int8_t *tc0); - void (*h264_h_loop_filter_luma)(uint8_t *pix /*align 4 */, int stride, + void (*h264_h_loop_filter_luma)(uint8_t *pix /*align 4 */, ptrdiff_t stride, int alpha, int beta, int8_t *tc0); - void (*h264_h_loop_filter_luma_mbaff)(uint8_t *pix /*align 16*/, int stride, + void (*h264_h_loop_filter_luma_mbaff)(uint8_t *pix /*align 16*/, ptrdiff_t stride, int alpha, int beta, int8_t *tc0); /* v/h_loop_filter_luma_intra: align 16 */ - void (*h264_v_loop_filter_luma_intra)(uint8_t *pix, int stride, + void (*h264_v_loop_filter_luma_intra)(uint8_t *pix, ptrdiff_t stride, int alpha, int beta); - void (*h264_h_loop_filter_luma_intra)(uint8_t *pix, int stride, + void (*h264_h_loop_filter_luma_intra)(uint8_t *pix, ptrdiff_t stride, int alpha, int beta); void (*h264_h_loop_filter_luma_mbaff_intra)(uint8_t *pix /*align 16*/, - int stride, int alpha, int beta); - void (*h264_v_loop_filter_chroma)(uint8_t *pix /*align 8*/, int stride, + ptrdiff_t stride, int alpha, int beta); + void (*h264_v_loop_filter_chroma)(uint8_t *pix /*align 8*/, ptrdiff_t stride, int alpha, int beta, int8_t *tc0); - void (*h264_h_loop_filter_chroma)(uint8_t *pix /*align 4*/, int stride, + void (*h264_h_loop_filter_chroma)(uint8_t *pix /*align 4*/, ptrdiff_t stride, int alpha, int beta, int8_t *tc0); void (*h264_h_loop_filter_chroma_mbaff)(uint8_t *pix /*align 8*/, - int stride, int alpha, int beta, + ptrdiff_t stride, int alpha, int beta, int8_t *tc0); void (*h264_v_loop_filter_chroma_intra)(uint8_t *pix /*align 8*/, - int stride, int alpha, int beta); + ptrdiff_t stride, int alpha, int beta); void (*h264_h_loop_filter_chroma_intra)(uint8_t *pix /*align 8*/, - int stride, int alpha, int beta); + ptrdiff_t stride, int alpha, int beta); void (*h264_h_loop_filter_chroma_mbaff_intra)(uint8_t *pix /*align 8*/, - int stride, int alpha, int beta); + ptrdiff_t stride, int alpha, int beta); // h264_loop_filter_strength: simd only. the C version is inlined in h264_loopfilter.c void (*h264_loop_filter_strength)(int16_t bS[2][4][4], uint8_t nnz[40], int8_t ref[2][40], int16_t mv[2][40][2], diff --git a/libavcodec/h264dsp_template.c b/libavcodec/h264dsp_template.c index 0288cc761..fe23a2cff 100644 --- a/libavcodec/h264dsp_template.c +++ b/libavcodec/h264dsp_template.c @@ -101,7 +101,7 @@ H264_WEIGHT(2) #undef op_scale2 #undef H264_WEIGHT -static av_always_inline av_flatten void FUNCC(h264_loop_filter_luma)(uint8_t *p_pix, int xstride, int ystride, int inner_iters, int alpha, int beta, int8_t *tc0) +static av_always_inline av_flatten void FUNCC(h264_loop_filter_luma)(uint8_t *p_pix, ptrdiff_t xstride, ptrdiff_t ystride, int inner_iters, int alpha, int beta, int8_t *tc0) { pixel *pix = (pixel*)p_pix; int i, d; @@ -149,20 +149,20 @@ static av_always_inline av_flatten void FUNCC(h264_loop_filter_luma)(uint8_t *p_ } } } -static void FUNCC(h264_v_loop_filter_luma)(uint8_t *pix, int stride, int alpha, int beta, int8_t *tc0) +static void FUNCC(h264_v_loop_filter_luma)(uint8_t *pix, ptrdiff_t stride, int alpha, int beta, int8_t *tc0) { FUNCC(h264_loop_filter_luma)(pix, stride, sizeof(pixel), 4, alpha, beta, tc0); } -static void FUNCC(h264_h_loop_filter_luma)(uint8_t *pix, int stride, int alpha, int beta, int8_t *tc0) +static void FUNCC(h264_h_loop_filter_luma)(uint8_t *pix, ptrdiff_t stride, int alpha, int beta, int8_t *tc0) { FUNCC(h264_loop_filter_luma)(pix, sizeof(pixel), stride, 4, alpha, beta, tc0); } -static void FUNCC(h264_h_loop_filter_luma_mbaff)(uint8_t *pix, int stride, int alpha, int beta, int8_t *tc0) +static void FUNCC(h264_h_loop_filter_luma_mbaff)(uint8_t *pix, ptrdiff_t stride, int alpha, int beta, int8_t *tc0) { FUNCC(h264_loop_filter_luma)(pix, sizeof(pixel), stride, 2, alpha, beta, tc0); } -static av_always_inline av_flatten void FUNCC(h264_loop_filter_luma_intra)(uint8_t *p_pix, int xstride, int ystride, int inner_iters, int alpha, int beta) +static av_always_inline av_flatten void FUNCC(h264_loop_filter_luma_intra)(uint8_t *p_pix, ptrdiff_t xstride, ptrdiff_t ystride, int inner_iters, int alpha, int beta) { pixel *pix = (pixel*)p_pix; int d; @@ -215,20 +215,20 @@ static av_always_inline av_flatten void FUNCC(h264_loop_filter_luma_intra)(uint8 pix += ystride; } } -static void FUNCC(h264_v_loop_filter_luma_intra)(uint8_t *pix, int stride, int alpha, int beta) +static void FUNCC(h264_v_loop_filter_luma_intra)(uint8_t *pix, ptrdiff_t stride, int alpha, int beta) { FUNCC(h264_loop_filter_luma_intra)(pix, stride, sizeof(pixel), 4, alpha, beta); } -static void FUNCC(h264_h_loop_filter_luma_intra)(uint8_t *pix, int stride, int alpha, int beta) +static void FUNCC(h264_h_loop_filter_luma_intra)(uint8_t *pix, ptrdiff_t stride, int alpha, int beta) { FUNCC(h264_loop_filter_luma_intra)(pix, sizeof(pixel), stride, 4, alpha, beta); } -static void FUNCC(h264_h_loop_filter_luma_mbaff_intra)(uint8_t *pix, int stride, int alpha, int beta) +static void FUNCC(h264_h_loop_filter_luma_mbaff_intra)(uint8_t *pix, ptrdiff_t stride, int alpha, int beta) { FUNCC(h264_loop_filter_luma_intra)(pix, sizeof(pixel), stride, 2, alpha, beta); } -static av_always_inline av_flatten void FUNCC(h264_loop_filter_chroma)(uint8_t *p_pix, int xstride, int ystride, int inner_iters, int alpha, int beta, int8_t *tc0) +static av_always_inline av_flatten void FUNCC(h264_loop_filter_chroma)(uint8_t *p_pix, ptrdiff_t xstride, ptrdiff_t ystride, int inner_iters, int alpha, int beta, int8_t *tc0) { pixel *pix = (pixel*)p_pix; int i, d; @@ -261,28 +261,28 @@ static av_always_inline av_flatten void FUNCC(h264_loop_filter_chroma)(uint8_t * } } } -static void FUNCC(h264_v_loop_filter_chroma)(uint8_t *pix, int stride, int alpha, int beta, int8_t *tc0) +static void FUNCC(h264_v_loop_filter_chroma)(uint8_t *pix, ptrdiff_t stride, int alpha, int beta, int8_t *tc0) { FUNCC(h264_loop_filter_chroma)(pix, stride, sizeof(pixel), 2, alpha, beta, tc0); } -static void FUNCC(h264_h_loop_filter_chroma)(uint8_t *pix, int stride, int alpha, int beta, int8_t *tc0) +static void FUNCC(h264_h_loop_filter_chroma)(uint8_t *pix, ptrdiff_t stride, int alpha, int beta, int8_t *tc0) { FUNCC(h264_loop_filter_chroma)(pix, sizeof(pixel), stride, 2, alpha, beta, tc0); } -static void FUNCC(h264_h_loop_filter_chroma_mbaff)(uint8_t *pix, int stride, int alpha, int beta, int8_t *tc0) +static void FUNCC(h264_h_loop_filter_chroma_mbaff)(uint8_t *pix, ptrdiff_t stride, int alpha, int beta, int8_t *tc0) { FUNCC(h264_loop_filter_chroma)(pix, sizeof(pixel), stride, 1, alpha, beta, tc0); } -static void FUNCC(h264_h_loop_filter_chroma422)(uint8_t *pix, int stride, int alpha, int beta, int8_t *tc0) +static void FUNCC(h264_h_loop_filter_chroma422)(uint8_t *pix, ptrdiff_t stride, int alpha, int beta, int8_t *tc0) { FUNCC(h264_loop_filter_chroma)(pix, sizeof(pixel), stride, 4, alpha, beta, tc0); } -static void FUNCC(h264_h_loop_filter_chroma422_mbaff)(uint8_t *pix, int stride, int alpha, int beta, int8_t *tc0) +static void FUNCC(h264_h_loop_filter_chroma422_mbaff)(uint8_t *pix, ptrdiff_t stride, int alpha, int beta, int8_t *tc0) { FUNCC(h264_loop_filter_chroma)(pix, sizeof(pixel), stride, 2, alpha, beta, tc0); } -static av_always_inline av_flatten void FUNCC(h264_loop_filter_chroma_intra)(uint8_t *p_pix, int xstride, int ystride, int inner_iters, int alpha, int beta) +static av_always_inline av_flatten void FUNCC(h264_loop_filter_chroma_intra)(uint8_t *p_pix, ptrdiff_t xstride, ptrdiff_t ystride, int inner_iters, int alpha, int beta) { pixel *pix = (pixel*)p_pix; int d; @@ -306,23 +306,23 @@ static av_always_inline av_flatten void FUNCC(h264_loop_filter_chroma_intra)(uin pix += ystride; } } -static void FUNCC(h264_v_loop_filter_chroma_intra)(uint8_t *pix, int stride, int alpha, int beta) +static void FUNCC(h264_v_loop_filter_chroma_intra)(uint8_t *pix, ptrdiff_t stride, int alpha, int beta) { FUNCC(h264_loop_filter_chroma_intra)(pix, stride, sizeof(pixel), 2, alpha, beta); } -static void FUNCC(h264_h_loop_filter_chroma_intra)(uint8_t *pix, int stride, int alpha, int beta) +static void FUNCC(h264_h_loop_filter_chroma_intra)(uint8_t *pix, ptrdiff_t stride, int alpha, int beta) { FUNCC(h264_loop_filter_chroma_intra)(pix, sizeof(pixel), stride, 2, alpha, beta); } -static void FUNCC(h264_h_loop_filter_chroma_mbaff_intra)(uint8_t *pix, int stride, int alpha, int beta) +static void FUNCC(h264_h_loop_filter_chroma_mbaff_intra)(uint8_t *pix, ptrdiff_t stride, int alpha, int beta) { FUNCC(h264_loop_filter_chroma_intra)(pix, sizeof(pixel), stride, 1, alpha, beta); } -static void FUNCC(h264_h_loop_filter_chroma422_intra)(uint8_t *pix, int stride, int alpha, int beta) +static void FUNCC(h264_h_loop_filter_chroma422_intra)(uint8_t *pix, ptrdiff_t stride, int alpha, int beta) { FUNCC(h264_loop_filter_chroma_intra)(pix, sizeof(pixel), stride, 4, alpha, beta); } -static void FUNCC(h264_h_loop_filter_chroma422_mbaff_intra)(uint8_t *pix, int stride, int alpha, int beta) +static void FUNCC(h264_h_loop_filter_chroma422_mbaff_intra)(uint8_t *pix, ptrdiff_t stride, int alpha, int beta) { FUNCC(h264_loop_filter_chroma_intra)(pix, sizeof(pixel), stride, 2, alpha, beta); } diff --git a/libavcodec/h265_metadata_bsf.c b/libavcodec/h265_metadata_bsf.c index 26eb2d05d..b3a1fda14 100644 --- a/libavcodec/h265_metadata_bsf.c +++ b/libavcodec/h265_metadata_bsf.c @@ -23,6 +23,7 @@ #include "cbs.h" #include "cbs_h265.h" #include "hevc.h" +#include "h265_profile_level.h" enum { PASS, @@ -30,6 +31,11 @@ enum { REMOVE, }; +enum { + LEVEL_UNSET = -2, + LEVEL_AUTO = -1, +}; + typedef struct H265MetadataContext { const AVClass *class; @@ -58,9 +64,105 @@ typedef struct H265MetadataContext { int crop_right; int crop_top; int crop_bottom; + + int level; + int level_guess; + int level_warned; } H265MetadataContext; +static void h265_metadata_guess_level(AVBSFContext *bsf, + const CodedBitstreamFragment *au) +{ + H265MetadataContext *ctx = bsf->priv_data; + const H265LevelDescriptor *desc; + const H265RawProfileTierLevel *ptl = NULL; + const H265RawHRDParameters *hrd = NULL; + int64_t bit_rate = 0; + int width = 0, height = 0; + int tile_cols = 0, tile_rows = 0; + int max_dec_pic_buffering = 0; + int i; + + for (i = 0; i < au->nb_units; i++) { + const CodedBitstreamUnit *unit = &au->units[i]; + + if (unit->type == HEVC_NAL_VPS) { + const H265RawVPS *vps = unit->content; + + ptl = &vps->profile_tier_level; + max_dec_pic_buffering = vps->vps_max_dec_pic_buffering_minus1[0] + 1; + + if (vps->vps_num_hrd_parameters > 0) + hrd = &vps->hrd_parameters[0]; + + } else if (unit->type == HEVC_NAL_SPS) { + const H265RawSPS *sps = unit->content; + + ptl = &sps->profile_tier_level; + max_dec_pic_buffering = sps->sps_max_dec_pic_buffering_minus1[0] + 1; + + width = sps->pic_width_in_luma_samples; + height = sps->pic_height_in_luma_samples; + + if (sps->vui.vui_hrd_parameters_present_flag) + hrd = &sps->vui.hrd_parameters; + + } else if (unit->type == HEVC_NAL_PPS) { + const H265RawPPS *pps = unit->content; + + if (pps->tiles_enabled_flag) { + tile_cols = pps->num_tile_columns_minus1 + 1; + tile_rows = pps->num_tile_rows_minus1 + 1; + } + } + } + + if (hrd) { + if (hrd->nal_hrd_parameters_present_flag) { + bit_rate = (hrd->nal_sub_layer_hrd_parameters[0].bit_rate_value_minus1[0] + 1) * + (INT64_C(1) << hrd->bit_rate_scale + 6); + } else if (hrd->vcl_hrd_parameters_present_flag) { + bit_rate = (hrd->vcl_sub_layer_hrd_parameters[0].bit_rate_value_minus1[0] + 1) * + (INT64_C(1) << hrd->bit_rate_scale + 6); + // Adjust for VCL vs. NAL limits. + bit_rate = bit_rate * 11 / 10; + } + } + + desc = ff_h265_guess_level(ptl, bit_rate, width, height, + 0, tile_cols, tile_rows, + max_dec_pic_buffering); + if (desc) { + av_log(bsf, AV_LOG_DEBUG, "Stream appears to conform to " + "level %s.\n", desc->name); + ctx->level_guess = desc->level_idc; + } +} + +static void h265_metadata_update_level(AVBSFContext *bsf, + uint8_t *level_idc) +{ + H265MetadataContext *ctx = bsf->priv_data; + + if (ctx->level != LEVEL_UNSET) { + if (ctx->level == LEVEL_AUTO) { + if (ctx->level_guess) { + *level_idc = ctx->level_guess; + } else { + if (!ctx->level_warned) { + av_log(bsf, AV_LOG_WARNING, "Unable to determine level " + "of stream: using level 8.5.\n"); + ctx->level_warned = 1; + } + *level_idc = 255; + } + } else { + *level_idc = ctx->level; + } + } +} + static int h265_metadata_update_vps(AVBSFContext *bsf, H265RawVPS *vps) { @@ -86,6 +188,8 @@ static int h265_metadata_update_vps(AVBSFContext *bsf, } } + h265_metadata_update_level(bsf, &vps->profile_tier_level.general_level_idc); + return 0; } @@ -227,21 +331,22 @@ static int h265_metadata_update_sps(AVBSFContext *bsf, if (need_vui) sps->vui_parameters_present_flag = 1; + h265_metadata_update_level(bsf, &sps->profile_tier_level.general_level_idc); + return 0; } -static int h265_metadata_filter(AVBSFContext *bsf, AVPacket *out) +static int h265_metadata_filter(AVBSFContext *bsf, AVPacket *pkt) { H265MetadataContext *ctx = bsf->priv_data; - AVPacket *in = NULL; CodedBitstreamFragment *au = &ctx->access_unit; int err, i; - err = ff_bsf_get_packet(bsf, &in); + err = ff_bsf_get_packet_ref(bsf, pkt); if (err < 0) return err; - err = ff_cbs_read_packet(ctx->cbc, au, in); + err = ff_cbs_read_packet(ctx->cbc, au, pkt); if (err < 0) { av_log(bsf, AV_LOG_ERROR, "Failed to read packet.\n"); goto fail; @@ -290,13 +395,16 @@ static int h265_metadata_filter(AVBSFContext *bsf, AVPacket *out) err = ff_cbs_insert_unit_content(ctx->cbc, au, 0, HEVC_NAL_AUD, aud, NULL); - if (err) { + if (err < 0) { av_log(bsf, AV_LOG_ERROR, "Failed to insert AUD.\n"); goto fail; } } } + if (ctx->level == LEVEL_AUTO && !ctx->level_guess) + h265_metadata_guess_level(bsf, au); + for (i = 0; i < au->nb_units; i++) { if (au->units[i].type == HEVC_NAL_VPS) { err = h265_metadata_update_vps(bsf, au->units[i].content); @@ -310,23 +418,18 @@ static int h265_metadata_filter(AVBSFContext *bsf, AVPacket *out) } } - err = ff_cbs_write_packet(ctx->cbc, out, au); + err = ff_cbs_write_packet(ctx->cbc, pkt, au); if (err < 0) { av_log(bsf, AV_LOG_ERROR, "Failed to write packet.\n"); goto fail; } - err = av_packet_copy_props(out, in); - if (err < 0) - goto fail; - err = 0; fail: - ff_cbs_fragment_uninit(ctx->cbc, au); + ff_cbs_fragment_reset(ctx->cbc, au); if (err < 0) - av_packet_unref(out); - av_packet_free(&in); + av_packet_unref(pkt); return err; } @@ -348,6 +451,9 @@ static int h265_metadata_init(AVBSFContext *bsf) goto fail; } + if (ctx->level == LEVEL_AUTO) + h265_metadata_guess_level(bsf, au); + for (i = 0; i < au->nb_units; i++) { if (au->units[i].type == HEVC_NAL_VPS) { err = h265_metadata_update_vps(bsf, au->units[i].content); @@ -370,13 +476,15 @@ static int h265_metadata_init(AVBSFContext *bsf) err = 0; fail: - ff_cbs_fragment_uninit(ctx->cbc, au); + ff_cbs_fragment_reset(ctx->cbc, au); return err; } static void h265_metadata_close(AVBSFContext *bsf) { H265MetadataContext *ctx = bsf->priv_data; + + ff_cbs_fragment_free(ctx->cbc, &ctx->access_unit); ff_cbs_close(&ctx->cbc); } @@ -439,6 +547,30 @@ static const AVOption h265_metadata_options[] = { OFFSET(crop_bottom), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, HEVC_MAX_HEIGHT, FLAGS }, + { "level", "Set level (tables A.6 and A.7)", + OFFSET(level), AV_OPT_TYPE_INT, + { .i64 = LEVEL_UNSET }, LEVEL_UNSET, 0xff, FLAGS, "level" }, + { "auto", "Attempt to guess level from stream properties", + 0, AV_OPT_TYPE_CONST, + { .i64 = LEVEL_AUTO }, .flags = FLAGS, .unit = "level" }, +#define LEVEL(name, value) name, NULL, 0, AV_OPT_TYPE_CONST, \ + { .i64 = value }, .flags = FLAGS, .unit = "level" + { LEVEL("1", 30) }, + { LEVEL("2", 60) }, + { LEVEL("2.1", 63) }, + { LEVEL("3", 90) }, + { LEVEL("3.1", 93) }, + { LEVEL("4", 120) }, + { LEVEL("4.1", 123) }, + { LEVEL("5", 150) }, + { LEVEL("5.1", 153) }, + { LEVEL("5.2", 156) }, + { LEVEL("6", 180) }, + { LEVEL("6.1", 183) }, + { LEVEL("6.2", 186) }, + { LEVEL("8.5", 255) }, +#undef LEVEL + { NULL } }; diff --git a/libavcodec/h265_profile_level.c b/libavcodec/h265_profile_level.c new file mode 100644 index 000000000..70db1a52f --- /dev/null +++ b/libavcodec/h265_profile_level.c @@ -0,0 +1,259 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "h265_profile_level.h" + + +static const H265LevelDescriptor h265_levels[] = { + // Name CpbFactor-Main MaxSliceSegmentsPerPicture + // | level_idc | CpbFactor-High MaxLumaSr BrFactor-High + // | | MaxLumaPs | | | MaxTileRows | BrFactor-Main | MinCr-Main + // | | | | | | | MaxTileCols | | | MinCr-High + { "1", 30, 36864, 350, 0, 16, 1, 1, 552960, 128, 0, 2, 2 }, + { "2", 60, 122880, 1500, 0, 16, 1, 1, 3686400, 1500, 0, 2, 2 }, + { "2.1", 63, 245760, 3000, 0, 20, 1, 1, 7372800, 3000, 0, 2, 2 }, + { "3", 90, 552960, 6000, 0, 30, 2, 2, 16588800, 6000, 0, 2, 2 }, + { "3.1", 93, 983040, 10000, 0, 40, 3, 3, 33177600, 10000, 0, 2, 2 }, + { "4", 120, 2228224, 12000, 30000, 75, 5, 5, 66846720, 12000, 30000, 4, 4 }, + { "4.1", 123, 2228224, 20000, 50000, 75, 5, 5, 133693440, 20000, 50000, 4, 4 }, + { "5", 150, 8912896, 25000, 100000, 200, 11, 10, 267386880, 25000, 100000, 6, 4 }, + { "5.1", 153, 8912896, 40000, 160000, 200, 11, 10, 534773760, 40000, 160000, 8, 4 }, + { "5.2", 156, 8912896, 60000, 240000, 200, 11, 10, 1069547520, 60000, 240000, 8, 4 }, + { "6", 180, 35651584, 60000, 240000, 600, 22, 20, 1069547520, 60000, 240000, 8, 4 }, + { "6.1", 183, 35651584, 120000, 480000, 600, 22, 20, 2139095040, 120000, 480000, 8, 4 }, + { "6.2", 186, 35651584, 240000, 800000, 600, 22, 20, 4278190080, 240000, 800000, 6, 4 }, +}; + +static const H265ProfileDescriptor h265_profiles[] = { + // profile_idc 8bit one-picture + // HT-profile | 422chroma | lower-bit-rate + // | 14bit | | 420chroma | | CpbVclFactor MinCrScaleFactor + // | | 12bit | | | monochrome| | CpbNalFactor | maxDpbPicBuf + // | | | 10bit | | | intra | | | FormatCapabilityFactor + { "Monochrome", // | | | | | | | | | | | + 4, 0, 2, 1, 1, 1, 1, 1, 1, 0, 0, 1, 667, 733, 1.000, 1.0, 6 }, + { "Monochrome 10", + 4, 0, 2, 1, 1, 0, 1, 1, 1, 0, 0, 1, 833, 917, 1.250, 1.0, 6 }, + { "Monochrome 12", + 4, 0, 2, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1000, 1100, 1.500, 1.0, 6 }, + { "Monochrome 16", + 4, 0, 2, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1333, 1467, 2.000, 1.0, 6 }, + { "Main", + 1, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1000, 1100, 1.500, 1.0, 6 }, + { "Screen-Extended Main", + 9, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1000, 1100, 1.500, 1.0, 7 }, + { "Main 10", + 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 1000, 1100, 1.875, 1.0, 6 }, + { "Screen-Extended Main 10", + 9, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1000, 1100, 1.875, 1.0, 7 }, + { "Main 12", + 4, 0, 2, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1500, 1650, 2.250, 1.0, 6 }, + { "Main Still Picture", + 3, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1000, 1100, 1.500, 1.0, 6 }, + { "Main 10 Still Picture", + 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 1000, 1100, 1.875, 1.0, 6 }, + { "Main 4:2:2 10", + 4, 0, 2, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1667, 1833, 2.500, 0.5, 6 }, + { "Main 4:2:2 12", + 4, 0, 2, 1, 0, 0, 1, 0, 0, 0, 0, 1, 2000, 2200, 3.000, 0.5, 6 }, + { "Main 4:4:4", + 4, 0, 2, 1, 1, 1, 0, 0, 0, 0, 0, 1, 2000, 2200, 3.000, 0.5, 6 }, + { "High Throughput 4:4:4", + 5, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 2000, 2200, 3.000, 0.5, 6 }, + { "Screen-Extended Main 4:4:4", + 9, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 2000, 2200, 3.000, 0.5, 7 }, + { "Screen-Extended High Throughput 4:4:4", + 9, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 2000, 2200, 3.000, 0.5, 7 }, + { "Main 4:4:4 10", + 4, 0, 2, 1, 1, 0, 0, 0, 0, 0, 0, 1, 2500, 2750, 3.750, 0.5, 6 }, + { "High Throughput 4:4:4 10", + 5, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 2500, 2750, 3.750, 0.5, 6 }, + { "Screen-Extended Main 4:4:4 10", + 9, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 2500, 2750, 3.750, 0.5, 7 }, + { "Screen-Extended High Throughput 4:4:4 10", + 9, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 2500, 2750, 3.750, 0.5, 7 }, + { "Main 4:4:4 12", + 4, 0, 2, 1, 0, 0, 0, 0, 0, 0, 0, 1, 3000, 3300, 4.500, 0.5, 6 }, + { "High Throughput 4:4:4 14", + 5, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 3500, 3850, 5.250, 0.5, 6 }, + { "Screen-Extended High Throughput 4:4:4 14", + 9, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 3500, 3850, 5.250, 0.5, 7 }, + { "Main Intra", + 4, 0, 2, 1, 1, 1, 1, 1, 0, 1, 0, 2, 1000, 1100, 1.500, 1.0, 6 }, + { "Main 10 Intra", + 4, 0, 2, 1, 1, 0, 1, 1, 0, 1, 0, 2, 1000, 1100, 1.875, 1.0, 6 }, + { "Main 12 Intra", + 4, 0, 2, 1, 0, 0, 1, 1, 0, 1, 0, 2, 1500, 1650, 2.250, 1.0, 6 }, + { "Main 4:2:2 10 Intra", + 4, 0, 2, 1, 1, 0, 1, 0, 0, 1, 0, 2, 1667, 1833, 2.500, 0.5, 6 }, + { "Main 4:2:2 12 Intra", + 4, 0, 2, 1, 0, 0, 1, 0, 0, 1, 0, 2, 2000, 2200, 3.000, 0.5, 6 }, + { "Main 4:4:4 Intra", + 4, 0, 2, 1, 1, 1, 0, 0, 0, 1, 0, 2, 2000, 2200, 3.000, 0.5, 6 }, + { "Main 4:4:4 10 Intra", + 4, 0, 2, 1, 1, 0, 0, 0, 0, 1, 0, 2, 2500, 2750, 3.750, 0.5, 6 }, + { "Main 4:4:4 12 Intra", + 4, 0, 2, 1, 0, 0, 0, 0, 0, 1, 0, 2, 3000, 3300, 4.500, 0.5, 6 }, + { "Main 4:4:4 16 Intra", + 4, 0, 2, 0, 0, 0, 0, 0, 0, 1, 0, 2, 4000, 4400, 6.000, 0.5, 6 }, + { "Main 4:4:4 Still Picture", + 4, 0, 2, 1, 1, 1, 0, 0, 0, 1, 1, 2, 2000, 2200, 3.000, 0.5, 6 }, + { "Main 4:4:4 16 Still Picture", + 4, 0, 2, 0, 0, 0, 0, 0, 0, 1, 1, 2, 4000, 4400, 6.000, 0.5, 6 }, + { "High Throughput 4:4:4 16 Intra", + 5, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 2, 4000, 4400, 6.000, 0.5, 6 }, +}; + + +const H265LevelDescriptor *ff_h265_get_level(int level_idc) +{ + int i; + + for (i = 0; i < FF_ARRAY_ELEMS(h265_levels); i++) { + if (h265_levels[i].level_idc == level_idc) + return &h265_levels[i]; + } + + return NULL; +} + +const H265ProfileDescriptor *ff_h265_get_profile(const H265RawProfileTierLevel *ptl) +{ + int i; + + if (ptl->general_profile_space) + return NULL; + + for (i = 0; i < FF_ARRAY_ELEMS(h265_profiles); i++) { + const H265ProfileDescriptor *profile = &h265_profiles[i]; + + if (ptl->general_profile_idc && + ptl->general_profile_idc != profile->profile_idc) + continue; + if (!ptl->general_profile_compatibility_flag[profile->profile_idc]) + continue; + +#define check_flag(name) \ + if (profile->name < 2) { \ + if (profile->name != ptl->general_ ## name ## _constraint_flag) \ + continue; \ + } + check_flag(max_14bit); + check_flag(max_12bit); + check_flag(max_10bit); + check_flag(max_8bit); + check_flag(max_422chroma); + check_flag(max_420chroma); + check_flag(max_monochrome); + check_flag(intra); + check_flag(one_picture_only); + check_flag(lower_bit_rate); +#undef check_flag + + return profile; + } + + return NULL; +} + +const H265LevelDescriptor *ff_h265_guess_level(const H265RawProfileTierLevel *ptl, + int64_t bitrate, + int width, int height, + int slice_segments, + int tile_rows, int tile_cols, + int max_dec_pic_buffering) +{ + const H265ProfileDescriptor *profile; + int pic_size, tier_flag, lbr_flag, hbr_factor; + int i; + + if (ptl) + profile = ff_h265_get_profile(ptl); + else + profile = NULL; + if (!profile) { + // Default to using multiplication factors for Main profile. + profile = &h265_profiles[3]; + } + + pic_size = width * height; + + if (ptl) { + tier_flag = ptl->general_tier_flag; + lbr_flag = ptl->general_lower_bit_rate_constraint_flag; + } else { + tier_flag = 0; + lbr_flag = profile->lower_bit_rate > 0; + } + if (profile->profile_idc == 1 || profile->profile_idc == 2) { + hbr_factor = 1; + } else if (profile->high_throughput) { + if (profile->intra) + hbr_factor = 24 - 12 * lbr_flag; + else + hbr_factor = 6; + } else { + hbr_factor = 2 - lbr_flag; + } + + for (i = 0; i < FF_ARRAY_ELEMS(h265_levels); i++) { + const H265LevelDescriptor *level = &h265_levels[i]; + int max_br, max_dpb_size; + + if (tier_flag && !level->max_br_high) + continue; + + if (pic_size > level->max_luma_ps) + continue; + if (width * width > 8 * level->max_luma_ps) + continue; + if (height * height > 8 * level->max_luma_ps) + continue; + + if (slice_segments > level->max_slice_segments_per_picture) + continue; + if (tile_rows > level->max_tile_rows) + continue; + if (tile_cols > level->max_tile_cols) + continue; + + if (tier_flag) + max_br = level->max_br_high; + else + max_br = level->max_br_main; + if (!max_br) + continue; + if (bitrate > (int64_t)profile->cpb_nal_factor * hbr_factor * max_br) + continue; + + if (pic_size <= (level->max_luma_ps >> 2)) + max_dpb_size = FFMIN(4 * profile->max_dpb_pic_buf, 16); + else if (pic_size <= (level->max_luma_ps >> 1)) + max_dpb_size = FFMIN(2 * profile->max_dpb_pic_buf, 16); + else if (pic_size <= (3 * level->max_luma_ps >> 2)) + max_dpb_size = FFMIN(4 * profile->max_dpb_pic_buf / 3, 16); + else + max_dpb_size = profile->max_dpb_pic_buf; + if (max_dec_pic_buffering > max_dpb_size) + continue; + + return level; + } + + return NULL; +} diff --git a/libavcodec/h265_profile_level.h b/libavcodec/h265_profile_level.h new file mode 100644 index 000000000..2d5bebaec --- /dev/null +++ b/libavcodec/h265_profile_level.h @@ -0,0 +1,90 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * 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_H265_PROFILE_LEVEL_H +#define AVCODEC_H265_PROFILE_LEVEL_H + +#include + +#include "cbs_h265.h" + + +typedef struct H265LevelDescriptor { + const char *name; + uint8_t level_idc; + + // Table A.6. + uint32_t max_luma_ps; + uint32_t max_cpb_main; + uint32_t max_cpb_high; + uint16_t max_slice_segments_per_picture; + uint8_t max_tile_rows; + uint8_t max_tile_cols; + + // Table A.7. + uint32_t max_luma_sr; + uint32_t max_br_main; + uint32_t max_br_high; + uint8_t min_cr_base_main; + uint8_t min_cr_base_high; +} H265LevelDescriptor; + +typedef struct H265ProfileDescriptor { + const char *name; + uint8_t profile_idc; + uint8_t high_throughput; + + // Tables A.2, A.3 and A.5. + uint8_t max_14bit; + uint8_t max_12bit; + uint8_t max_10bit; + uint8_t max_8bit; + uint8_t max_422chroma; + uint8_t max_420chroma; + uint8_t max_monochrome; + uint8_t intra; + uint8_t one_picture_only; + uint8_t lower_bit_rate; + + // Table A.8. + uint16_t cpb_vcl_factor; + uint16_t cpb_nal_factor; + float format_capability_factor; + float min_cr_scale_factor; + uint8_t max_dpb_pic_buf; +} H265ProfileDescriptor; + + +const H265LevelDescriptor *ff_h265_get_level(int level_idc); + +const H265ProfileDescriptor *ff_h265_get_profile(const H265RawProfileTierLevel *ptl); + + +/** + * Guess the level of a stream from some parameters. + * + * Unknown parameters may be zero, in which case they are ignored. + */ +const H265LevelDescriptor *ff_h265_guess_level(const H265RawProfileTierLevel *ptl, + int64_t bitrate, + int width, int height, + int slice_segments, + int tile_rows, int tile_cols, + int max_dec_pic_buffering); + +#endif /* AVCODEC_H265_PROFILE_LEVEL_H */ diff --git a/libavcodec/hcom.c b/libavcodec/hcom.c new file mode 100644 index 000000000..bce9e80aa --- /dev/null +++ b/libavcodec/hcom.c @@ -0,0 +1,143 @@ +/* + * HCOM audio decoder + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/intreadwrite.h" + +#include "avcodec.h" +#include "get_bits.h" +#include "internal.h" + +typedef struct HEntry { + int16_t l, r; +} HEntry; + +typedef struct HCOMContext { + AVCodecContext *avctx; + + uint8_t first_sample; + uint8_t sample; + int dict_entries; + int dict_entry; + int delta_compression; + + HEntry *dict; +} HCOMContext; + +static av_cold int hcom_init(AVCodecContext *avctx) +{ + HCOMContext *s = avctx->priv_data; + + if (avctx->channels != 1) { + av_log(avctx, AV_LOG_ERROR, "invalid number of channels\n"); + return AVERROR_INVALIDDATA; + } + + if (avctx->extradata_size <= 7) + return AVERROR_INVALIDDATA; + s->dict_entries = AV_RB16(avctx->extradata); + if (avctx->extradata_size < s->dict_entries * 4 + 7) + return AVERROR_INVALIDDATA; + s->delta_compression = AV_RB32(avctx->extradata + 2); + s->sample = s->first_sample = avctx->extradata[avctx->extradata_size - 1]; + + s->dict = av_calloc(s->dict_entries, sizeof(*s->dict)); + if (!s->dict) + return AVERROR(ENOMEM); + for (int i = 0; i < s->dict_entries; i++) { + s->dict[i].l = AV_RB16(avctx->extradata + 6 + 4 * i); + s->dict[i].r = AV_RB16(avctx->extradata + 6 + 4 * i + 2); + if (s->dict[i].l >= 0 && + (s->dict[i].l >= s->dict_entries || + s->dict[i].r >= s->dict_entries)) + return AVERROR_INVALIDDATA; + } + + avctx->sample_fmt = AV_SAMPLE_FMT_U8; + s->dict_entry = 0; + + return 0; +} + +static int hcom_decode(AVCodecContext *avctx, void *data, + int *got_frame, AVPacket *pkt) +{ + HCOMContext *s = avctx->priv_data; + AVFrame *frame = data; + GetBitContext gb; + int ret, n = 0; + + if (pkt->size > INT16_MAX) + return AVERROR_INVALIDDATA; + + frame->nb_samples = pkt->size * 8; + if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) + return ret; + + if ((ret = init_get_bits8(&gb, pkt->data, pkt->size)) < 0) + return ret; + + while (get_bits_left(&gb) > 0) { + if (get_bits1(&gb)) + s->dict_entry = s->dict[s->dict_entry].r; + else + s->dict_entry = s->dict[s->dict_entry].l; + + if (s->dict[s->dict_entry].l < 0) { + int16_t datum; + + datum = s->dict[s->dict_entry].r; + + if (!s->delta_compression) + s->sample = 0; + s->sample = (s->sample + datum) & 0xFF; + + frame->data[0][n++] = s->sample; + + s->dict_entry = 0; + } + } + + frame->nb_samples = n; + + *got_frame = 1; + + return pkt->size; +} + +static av_cold int hcom_close(AVCodecContext *avctx) +{ + HCOMContext *s = avctx->priv_data; + + av_freep(&s->dict); + + return 0; +} + +AVCodec ff_hcom_decoder = { + .name = "hcom", + .long_name = NULL_IF_CONFIG_SMALL("HCOM Audio"), + .type = AVMEDIA_TYPE_AUDIO, + .id = AV_CODEC_ID_HCOM, + .priv_data_size = sizeof(HCOMContext), + .init = hcom_init, + .close = hcom_close, + .decode = hcom_decode, + .capabilities = AV_CODEC_CAP_DR1, +}; diff --git a/libavcodec/hevc.h b/libavcodec/hevc.h index 2f20db828..56b5541d9 100644 --- a/libavcodec/hevc.h +++ b/libavcodec/hevc.h @@ -22,7 +22,8 @@ #define AVCODEC_HEVC_H /** - * Table 7-3: NAL unit type codes + * Table 7-1 – NAL unit type codes and NAL unit type classes in + * T-REC-H.265-201802 */ enum HEVCNALUnitType { HEVC_NAL_TRAIL_N = 0, @@ -66,6 +67,29 @@ enum HEVCNALUnitType { HEVC_NAL_FD_NUT = 38, HEVC_NAL_SEI_PREFIX = 39, HEVC_NAL_SEI_SUFFIX = 40, + HEVC_NAL_RSV_NVCL41 = 41, + HEVC_NAL_RSV_NVCL42 = 42, + HEVC_NAL_RSV_NVCL43 = 43, + HEVC_NAL_RSV_NVCL44 = 44, + HEVC_NAL_RSV_NVCL45 = 45, + HEVC_NAL_RSV_NVCL46 = 46, + HEVC_NAL_RSV_NVCL47 = 47, + HEVC_NAL_UNSPEC48 = 48, + HEVC_NAL_UNSPEC49 = 49, + HEVC_NAL_UNSPEC50 = 50, + HEVC_NAL_UNSPEC51 = 51, + HEVC_NAL_UNSPEC52 = 52, + HEVC_NAL_UNSPEC53 = 53, + HEVC_NAL_UNSPEC54 = 54, + HEVC_NAL_UNSPEC55 = 55, + HEVC_NAL_UNSPEC56 = 56, + HEVC_NAL_UNSPEC57 = 57, + HEVC_NAL_UNSPEC58 = 58, + HEVC_NAL_UNSPEC59 = 59, + HEVC_NAL_UNSPEC60 = 60, + HEVC_NAL_UNSPEC61 = 61, + HEVC_NAL_UNSPEC62 = 62, + HEVC_NAL_UNSPEC63 = 63, }; enum HEVCSliceType { @@ -119,6 +143,9 @@ enum { // A.4.1: table A.6 allows at most 20 tile columns for any level. HEVC_MAX_TILE_COLUMNS = 20, + // A.4.2: table A.6 allows at most 600 slice segments for any level. + HEVC_MAX_SLICE_SEGMENTS = 600, + // 7.4.7.1: in the worst case (tiles_enabled_flag and // entropy_coding_sync_enabled_flag are both set), entry points can be // placed at the beginning of every Ctb row in every tile, giving an diff --git a/libavcodec/hevc_parse.c b/libavcodec/hevc_parse.c index b1b27eef0..dddb293df 100644 --- a/libavcodec/hevc_parse.c +++ b/libavcodec/hevc_parse.c @@ -29,7 +29,8 @@ static int hevc_decode_nal_units(const uint8_t *buf, int buf_size, HEVCParamSets int ret = 0; H2645Packet pkt = { 0 }; - ret = ff_h2645_packet_split(&pkt, buf, buf_size, logctx, is_nalff, nal_length_size, AV_CODEC_ID_HEVC, 1); + ret = ff_h2645_packet_split(&pkt, buf, buf_size, logctx, is_nalff, + nal_length_size, AV_CODEC_ID_HEVC, 1, 0); if (ret < 0) { goto done; } diff --git a/libavcodec/hevc_parser.c b/libavcodec/hevc_parser.c index a468682ed..b444b9995 100644 --- a/libavcodec/hevc_parser.c +++ b/libavcodec/hevc_parser.c @@ -194,7 +194,7 @@ static int parse_nal_units(AVCodecParserContext *s, const uint8_t *buf, ff_hevc_reset_sei(sei); ret = ff_h2645_packet_split(&ctx->pkt, buf, buf_size, avctx, ctx->is_avc, - ctx->nal_length_size, AV_CODEC_ID_HEVC, 1); + ctx->nal_length_size, AV_CODEC_ID_HEVC, 1, 0); if (ret < 0) return ret; @@ -239,7 +239,7 @@ static int parse_nal_units(AVCodecParserContext *s, const uint8_t *buf, } } /* didn't find a picture! */ - av_log(avctx, AV_LOG_ERROR, "missing picture in access unit\n"); + av_log(avctx, AV_LOG_ERROR, "missing picture in access unit with size %d\n", buf_size); return -1; } @@ -294,6 +294,8 @@ static int hevc_parse(AVCodecParserContext *s, AVCodecContext *avctx, int next; HEVCParserContext *ctx = s->priv_data; ParseContext *pc = &ctx->pc; + int is_dummy_buf = !buf_size; + const uint8_t *dummy_buf = buf; if (avctx->extradata && !ctx->parsed_extradata) { ff_hevc_decode_extradata(avctx->extradata, avctx->extradata_size, &ctx->ps, &ctx->sei, @@ -313,7 +315,10 @@ static int hevc_parse(AVCodecParserContext *s, AVCodecContext *avctx, } } - parse_nal_units(s, buf, buf_size, avctx); + is_dummy_buf &= (dummy_buf == buf); + + if (!is_dummy_buf) + parse_nal_units(s, buf, buf_size, avctx); *poutbuf = buf; *poutbuf_size = buf_size; diff --git a/libavcodec/hevc_ps.c b/libavcodec/hevc_ps.c index f877fa572..abf08b919 100644 --- a/libavcodec/hevc_ps.c +++ b/libavcodec/hevc_ps.c @@ -70,6 +70,14 @@ static const AVRational vui_sar[] = { { 2, 1 }, }; +static const uint8_t hevc_sub_width_c[] = { + 1, 2, 2, 1 +}; + +static const uint8_t hevc_sub_height_c[] = { + 1, 2, 1, 1 +}; + static void remove_pps(HEVCParamSets *s, int id) { if (s->pps_list[id] && s->pps == (const HEVCPPS*)s->pps_list[id]->data) @@ -628,8 +636,8 @@ static void decode_vui(GetBitContext *gb, AVCodecContext *avctx, vui->default_display_window_flag = get_bits1(gb); if (vui->default_display_window_flag) { - int vert_mult = 1 + (sps->chroma_format_idc < 2); - int horiz_mult = 1 + (sps->chroma_format_idc < 3); + int vert_mult = hevc_sub_height_c[sps->chroma_format_idc]; + int horiz_mult = hevc_sub_width_c[sps->chroma_format_idc]; vui->def_disp_win.left_offset = get_ue_golomb_long(gb) * horiz_mult; vui->def_disp_win.right_offset = get_ue_golomb_long(gb) * horiz_mult; vui->def_disp_win.top_offset = get_ue_golomb_long(gb) * vert_mult; @@ -825,7 +833,7 @@ static int map_pixel_format(AVCodecContext *avctx, HEVCSPS *sps) if (sps->chroma_format_idc == 3) sps->pix_fmt = AV_PIX_FMT_YUV444P; break; case 9: - if (sps->chroma_format_idc == 0) sps->pix_fmt = AV_PIX_FMT_GRAY16; + if (sps->chroma_format_idc == 0) sps->pix_fmt = AV_PIX_FMT_GRAY9; if (sps->chroma_format_idc == 1) sps->pix_fmt = AV_PIX_FMT_YUV420P9; if (sps->chroma_format_idc == 2) sps->pix_fmt = AV_PIX_FMT_YUV422P9; if (sps->chroma_format_idc == 3) sps->pix_fmt = AV_PIX_FMT_YUV444P9; @@ -923,8 +931,8 @@ int ff_hevc_parse_sps(HEVCSPS *sps, GetBitContext *gb, unsigned int *sps_id, return ret; if (get_bits1(gb)) { // pic_conformance_flag - int vert_mult = 1 + (sps->chroma_format_idc < 2); - int horiz_mult = 1 + (sps->chroma_format_idc < 3); + int vert_mult = hevc_sub_height_c[sps->chroma_format_idc]; + int horiz_mult = hevc_sub_width_c[sps->chroma_format_idc]; sps->pic_conf_win.left_offset = get_ue_golomb_long(gb) * horiz_mult; sps->pic_conf_win.right_offset = get_ue_golomb_long(gb) * horiz_mult; sps->pic_conf_win.top_offset = get_ue_golomb_long(gb) * vert_mult; @@ -1094,22 +1102,17 @@ int ff_hevc_parse_sps(HEVCSPS *sps, GetBitContext *gb, unsigned int *sps_id, decode_vui(gb, avctx, apply_defdispwin, sps); if (get_bits1(gb)) { // sps_extension_flag - int sps_extension_flag[1]; - for (i = 0; i < 1; i++) - sps_extension_flag[i] = get_bits1(gb); + sps->sps_range_extension_flag = get_bits1(gb); skip_bits(gb, 7); //sps_extension_7bits = get_bits(gb, 7); - if (sps_extension_flag[0]) { - int extended_precision_processing_flag; - int cabac_bypass_alignment_enabled_flag; - + if (sps->sps_range_extension_flag) { sps->transform_skip_rotation_enabled_flag = get_bits1(gb); sps->transform_skip_context_enabled_flag = get_bits1(gb); sps->implicit_rdpcm_enabled_flag = get_bits1(gb); sps->explicit_rdpcm_enabled_flag = get_bits1(gb); - extended_precision_processing_flag = get_bits1(gb); - if (extended_precision_processing_flag) + sps->extended_precision_processing_flag = get_bits1(gb); + if (sps->extended_precision_processing_flag) av_log(avctx, AV_LOG_WARNING, "extended_precision_processing_flag not yet implemented\n"); @@ -1121,8 +1124,8 @@ int ff_hevc_parse_sps(HEVCSPS *sps, GetBitContext *gb, unsigned int *sps_id, sps->persistent_rice_adaptation_enabled_flag = get_bits1(gb); - cabac_bypass_alignment_enabled_flag = get_bits1(gb); - if (cabac_bypass_alignment_enabled_flag) + sps->cabac_bypass_alignment_enabled_flag = get_bits1(gb); + if (sps->cabac_bypass_alignment_enabled_flag) av_log(avctx, AV_LOG_WARNING, "cabac_bypass_alignment_enabled_flag not yet implemented\n"); } @@ -1581,22 +1584,25 @@ int ff_hevc_decode_nal_pps(GetBitContext *gb, AVCodecContext *avctx, pps->entropy_coding_sync_enabled_flag = get_bits1(gb); if (pps->tiles_enabled_flag) { - pps->num_tile_columns = get_ue_golomb_long(gb) + 1; - pps->num_tile_rows = get_ue_golomb_long(gb) + 1; - if (pps->num_tile_columns <= 0 || - pps->num_tile_columns >= sps->width) { + int num_tile_columns_minus1 = get_ue_golomb(gb); + int num_tile_rows_minus1 = get_ue_golomb(gb); + + if (num_tile_columns_minus1 < 0 || + num_tile_columns_minus1 >= sps->ctb_width) { av_log(avctx, AV_LOG_ERROR, "num_tile_columns_minus1 out of range: %d\n", - pps->num_tile_columns - 1); - ret = AVERROR_INVALIDDATA; + num_tile_columns_minus1); + ret = num_tile_columns_minus1 < 0 ? num_tile_columns_minus1 : AVERROR_INVALIDDATA; goto err; } - if (pps->num_tile_rows <= 0 || - pps->num_tile_rows >= sps->height) { + if (num_tile_rows_minus1 < 0 || + num_tile_rows_minus1 >= sps->ctb_height) { av_log(avctx, AV_LOG_ERROR, "num_tile_rows_minus1 out of range: %d\n", - pps->num_tile_rows - 1); - ret = AVERROR_INVALIDDATA; + num_tile_rows_minus1); + ret = num_tile_rows_minus1 < 0 ? num_tile_rows_minus1 : AVERROR_INVALIDDATA; goto err; } + pps->num_tile_columns = num_tile_columns_minus1 + 1; + pps->num_tile_rows = num_tile_rows_minus1 + 1; pps->column_width = av_malloc_array(pps->num_tile_columns, sizeof(*pps->column_width)); pps->row_height = av_malloc_array(pps->num_tile_rows, sizeof(*pps->row_height)); @@ -1680,9 +1686,9 @@ int ff_hevc_decode_nal_pps(GetBitContext *gb, AVCodecContext *avctx, pps->slice_header_extension_present_flag = get_bits1(gb); if (get_bits1(gb)) { // pps_extension_present_flag - int pps_range_extensions_flag = get_bits1(gb); - /* int pps_extension_7bits = */ get_bits(gb, 7); - if (sps->ptl.general_ptl.profile_idc == FF_PROFILE_HEVC_REXT && pps_range_extensions_flag) { + pps->pps_range_extensions_flag = get_bits1(gb); + skip_bits(gb, 7); // pps_extension_7bits + if (sps->ptl.general_ptl.profile_idc == FF_PROFILE_HEVC_REXT && pps->pps_range_extensions_flag) { if ((ret = pps_range_extensions(gb, avctx, pps, sps)) < 0) goto err; } diff --git a/libavcodec/hevc_ps.h b/libavcodec/hevc_ps.h index 1fbda199e..2840dc416 100644 --- a/libavcodec/hevc_ps.h +++ b/libavcodec/hevc_ps.h @@ -284,13 +284,16 @@ typedef struct HEVCSPS { int max_transform_hierarchy_depth_inter; int max_transform_hierarchy_depth_intra; + int sps_range_extension_flag; int transform_skip_rotation_enabled_flag; int transform_skip_context_enabled_flag; int implicit_rdpcm_enabled_flag; int explicit_rdpcm_enabled_flag; + int extended_precision_processing_flag; int intra_smoothing_disabled_flag; int high_precision_offsets_enabled_flag; int persistent_rice_adaptation_enabled_flag; + int cabac_bypass_alignment_enabled_flag; ///< coded frame dimension in various units int width; @@ -344,8 +347,8 @@ typedef struct HEVCPPS { uint8_t tiles_enabled_flag; uint8_t entropy_coding_sync_enabled_flag; - int num_tile_columns; ///< num_tile_columns_minus1 + 1 - int num_tile_rows; ///< num_tile_rows_minus1 + 1 + uint16_t num_tile_columns; ///< num_tile_columns_minus1 + 1 + uint16_t num_tile_rows; ///< num_tile_rows_minus1 + 1 uint8_t uniform_spacing_flag; uint8_t loop_filter_across_tiles_enabled_flag; @@ -365,6 +368,7 @@ typedef struct HEVCPPS { int num_extra_slice_header_bits; uint8_t slice_header_extension_present_flag; uint8_t log2_max_transform_skip_block_size; + uint8_t pps_range_extensions_flag; uint8_t cross_component_prediction_enabled_flag; uint8_t chroma_qp_offset_list_enabled_flag; uint8_t diff_cu_chroma_qp_offset_depth; diff --git a/libavcodec/hevc_ps_enc.c b/libavcodec/hevc_ps_enc.c index 4c71cf41c..78a73a5c0 100644 --- a/libavcodec/hevc_ps_enc.c +++ b/libavcodec/hevc_ps_enc.c @@ -67,7 +67,7 @@ int ff_hevc_encode_nal_vps(HEVCVPS *vps, unsigned int id, uint8_t *buf, int buf_size) { PutBitContext pb; - int i; + int i, data_size; init_put_bits(&pb, buf, buf_size); put_bits(&pb, 4, id); @@ -103,6 +103,7 @@ int ff_hevc_encode_nal_vps(HEVCVPS *vps, unsigned int id, if (vps->vps_poc_proportional_to_timing_flag) set_ue_golomb(&pb, vps->vps_num_ticks_poc_diff_one - 1); + set_ue_golomb(&pb, vps->vps_num_hrd_parameters); if (vps->vps_num_hrd_parameters) { avpriv_report_missing_feature(NULL, "Writing HRD parameters"); return AVERROR_PATCHWELCOME; @@ -114,5 +115,8 @@ int ff_hevc_encode_nal_vps(HEVCVPS *vps, unsigned int id, put_bits(&pb, 1, 1); // stop bit avpriv_align_put_bits(&pb); - return put_bits_count(&pb) / 8; + data_size = put_bits_count(&pb) / 8; + flush_put_bits(&pb); + + return data_size; } diff --git a/libavcodec/hevc_refs.c b/libavcodec/hevc_refs.c index 7cf3a5572..7870a72fd 100644 --- a/libavcodec/hevc_refs.c +++ b/libavcodec/hevc_refs.c @@ -394,7 +394,7 @@ static void mark_ref(HEVCFrame *frame, int flag) static HEVCFrame *generate_missing_ref(HEVCContext *s, int poc) { HEVCFrame *frame; - int i, x, y; + int i, y; frame = alloc_frame(s); if (!frame) @@ -407,11 +407,11 @@ static HEVCFrame *generate_missing_ref(HEVCContext *s, int poc) frame->frame->buf[i]->size); } else { for (i = 0; frame->frame->data[i]; i++) - for (y = 0; y < (s->ps.sps->height >> s->ps.sps->vshift[i]); y++) - for (x = 0; x < (s->ps.sps->width >> s->ps.sps->hshift[i]); x++) { - AV_WN16(frame->frame->data[i] + y * frame->frame->linesize[i] + 2 * x, - 1 << (s->ps.sps->bit_depth - 1)); - } + for (y = 0; y < (s->ps.sps->height >> s->ps.sps->vshift[i]); y++) { + uint8_t *dst = frame->frame->data[i] + y * frame->frame->linesize[i]; + AV_WN16(dst, 1 << (s->ps.sps->bit_depth - 1)); + av_memcpy_backptr(dst + 2, 2, 2*(s->ps.sps->width >> s->ps.sps->hshift[i]) - 2); + } } } diff --git a/libavcodec/hevc_sei.h b/libavcodec/hevc_sei.h index e92da25bb..f6516ae98 100644 --- a/libavcodec/hevc_sei.h +++ b/libavcodec/hevc_sei.h @@ -52,9 +52,11 @@ typedef enum { HEVC_SEI_TYPE_DECODED_PICTURE_HASH = 132, HEVC_SEI_TYPE_SCALABLE_NESTING = 133, HEVC_SEI_TYPE_REGION_REFRESH_INFO = 134, + HEVC_SEI_TYPE_TIME_CODE = 136, HEVC_SEI_TYPE_MASTERING_DISPLAY_INFO = 137, HEVC_SEI_TYPE_CONTENT_LIGHT_LEVEL_INFO = 144, HEVC_SEI_TYPE_ALTERNATIVE_TRANSFER_CHARACTERISTICS = 147, + HEVC_SEI_TYPE_ALPHA_CHANNEL_INFO = 165, } HEVC_SEI_Type; typedef struct HEVCSEIPictureHash { diff --git a/libavcodec/hevcdec.c b/libavcodec/hevcdec.c index 2c33a1ff5..eed031913 100644 --- a/libavcodec/hevcdec.c +++ b/libavcodec/hevcdec.c @@ -182,6 +182,8 @@ static int pred_weight_table(HEVCContext *s, GetBitContext *gb) for (i = 0; i < s->sh.nb_refs[L0]; i++) { if (luma_weight_l0_flag[i]) { int delta_luma_weight_l0 = get_se_golomb(gb); + if ((int8_t)delta_luma_weight_l0 != delta_luma_weight_l0) + return AVERROR_INVALIDDATA; s->sh.luma_weight_l0[i] = (1 << s->sh.luma_log2_weight_denom) + delta_luma_weight_l0; s->sh.luma_offset_l0[i] = get_se_golomb(gb); } @@ -224,6 +226,8 @@ static int pred_weight_table(HEVCContext *s, GetBitContext *gb) for (i = 0; i < s->sh.nb_refs[L1]; i++) { if (luma_weight_l1_flag[i]) { int delta_luma_weight_l1 = get_se_golomb(gb); + if ((int8_t)delta_luma_weight_l1 != delta_luma_weight_l1) + return AVERROR_INVALIDDATA; s->sh.luma_weight_l1[i] = (1 << s->sh.luma_log2_weight_denom) + delta_luma_weight_l1; s->sh.luma_offset_l1[i] = get_se_golomb(gb); } @@ -310,9 +314,10 @@ static int decode_lt_rps(HEVCContext *s, LongTermRPS *rps, GetBitContext *gb) return 0; } -static void export_stream_params(AVCodecContext *avctx, const HEVCParamSets *ps, - const HEVCSPS *sps) +static void export_stream_params(HEVCContext *s, const HEVCSPS *sps) { + AVCodecContext *avctx = s->avctx; + const HEVCParamSets *ps = &s->ps; const HEVCVPS *vps = (const HEVCVPS*)ps->vps_list[sps->vps_id]->data; const HEVCWindow *ow = &sps->output_window; unsigned int num = 0, den = 0; @@ -355,6 +360,12 @@ static void export_stream_params(AVCodecContext *avctx, const HEVCParamSets *ps, if (num != 0 && den != 0) av_reduce(&avctx->framerate.den, &avctx->framerate.num, num, den, 1 << 30); + + if (s->sei.alternative_transfer.present && + av_color_transfer_name(s->sei.alternative_transfer.preferred_transfer_characteristics) && + s->sei.alternative_transfer.preferred_transfer_characteristics != AVCOL_TRC_UNSPECIFIED) { + avctx->color_trc = s->sei.alternative_transfer.preferred_transfer_characteristics; + } } static enum AVPixelFormat get_format(HEVCContext *s, const HEVCSPS *sps) @@ -404,11 +415,21 @@ static enum AVPixelFormat get_format(HEVCContext *s, const HEVCSPS *sps) #if CONFIG_HEVC_VIDEOTOOLBOX_HWACCEL *fmt++ = AV_PIX_FMT_VIDEOTOOLBOX; #endif +#if CONFIG_HEVC_NVDEC_HWACCEL + *fmt++ = AV_PIX_FMT_CUDA; +#endif + break; + case AV_PIX_FMT_YUV444P: +#if CONFIG_HEVC_VDPAU_HWACCEL + *fmt++ = AV_PIX_FMT_VDPAU; +#endif #if CONFIG_HEVC_NVDEC_HWACCEL *fmt++ = AV_PIX_FMT_CUDA; #endif break; case AV_PIX_FMT_YUV420P12: + case AV_PIX_FMT_YUV444P10: + case AV_PIX_FMT_YUV444P12: #if CONFIG_HEVC_NVDEC_HWACCEL *fmt++ = AV_PIX_FMT_CUDA; #endif @@ -437,7 +458,7 @@ static int set_sps(HEVCContext *s, const HEVCSPS *sps, if (ret < 0) goto fail; - export_stream_params(s->avctx, &s->ps, sps); + export_stream_params(s, sps); s->avctx->pix_fmt = pix_fmt; @@ -2768,12 +2789,6 @@ static int set_side_data(HEVCContext *s) s->avctx->properties |= FF_CODEC_PROPERTY_CLOSED_CAPTIONS; } - if (s->sei.alternative_transfer.present && - av_color_transfer_name(s->sei.alternative_transfer.preferred_transfer_characteristics) && - s->sei.alternative_transfer.preferred_transfer_characteristics != AVCOL_TRC_UNSPECIFIED) { - s->avctx->color_trc = out->color_trc = s->sei.alternative_transfer.preferred_transfer_characteristics; - } - return 0; } @@ -2929,7 +2944,7 @@ static int decode_nal_unit(HEVCContext *s, const H2645NAL *nal) if ( (s->avctx->skip_frame >= AVDISCARD_BIDIR && s->sh.slice_type == HEVC_SLICE_B) || (s->avctx->skip_frame >= AVDISCARD_NONINTRA && s->sh.slice_type != HEVC_SLICE_I) || - (s->avctx->skip_frame >= AVDISCARD_NONKEY && !IS_IDR(s))) { + (s->avctx->skip_frame >= AVDISCARD_NONKEY && !IS_IRAP(s))) { break; } @@ -2952,6 +2967,7 @@ static int decode_nal_unit(HEVCContext *s, const H2645NAL *nal) s->max_ra = INT_MIN; } + s->overlap ++; ret = hevc_frame_start(s); if (ret < 0) return ret; @@ -3030,11 +3046,12 @@ static int decode_nal_units(HEVCContext *s, const uint8_t *buf, int length) s->ref = NULL; s->last_eos = s->eos; s->eos = 0; + s->overlap = 0; /* split the input packet into NAL units, so we know the upper bound on the * number of slices in the frame */ ret = ff_h2645_packet_split(&s->pkt, buf, length, s->avctx, s->is_nalff, - s->nal_length_size, s->avctx->codec_id, 1); + s->nal_length_size, s->avctx->codec_id, 1, 0); if (ret < 0) { av_log(s->avctx, AV_LOG_ERROR, "Error splitting the input into NAL units.\n"); @@ -3064,6 +3081,8 @@ static int decode_nal_units(HEVCContext *s, const uint8_t *buf, int length) continue; ret = decode_nal_unit(s, nal); + if (ret >= 0 && s->overlap > 2) + ret = AVERROR_INVALIDDATA; if (ret < 0) { av_log(s->avctx, AV_LOG_WARNING, "Error parsing NAL unit #%d.\n", i); @@ -3165,7 +3184,7 @@ static int hevc_decode_extradata(HEVCContext *s, uint8_t *buf, int length, int f for (i = 0; i < FF_ARRAY_ELEMS(s->ps.sps_list); i++) { if (first && s->ps.sps_list[i]) { const HEVCSPS *sps = (const HEVCSPS*)s->ps.sps_list[i]->data; - export_stream_params(s->avctx, &s->ps, sps); + export_stream_params(s, sps); break; } } @@ -3368,6 +3387,7 @@ fail: return AVERROR(ENOMEM); } +#if HAVE_THREADS static int hevc_update_thread_context(AVCodecContext *dst, const AVCodecContext *src) { @@ -3449,6 +3469,7 @@ static int hevc_update_thread_context(AVCodecContext *dst, return 0; } +#endif static av_cold int hevc_decode_init(AVCodecContext *avctx) { @@ -3488,6 +3509,7 @@ static av_cold int hevc_decode_init(AVCodecContext *avctx) return 0; } +#if HAVE_THREADS static av_cold int hevc_init_thread_copy(AVCodecContext *avctx) { HEVCContext *s = avctx->priv_data; @@ -3501,6 +3523,7 @@ static av_cold int hevc_init_thread_copy(AVCodecContext *avctx) return 0; } +#endif static void hevc_decode_flush(AVCodecContext *avctx) { @@ -3539,8 +3562,8 @@ AVCodec ff_hevc_decoder = { .close = hevc_decode_free, .decode = hevc_decode_frame, .flush = hevc_decode_flush, - .update_thread_context = hevc_update_thread_context, - .init_thread_copy = hevc_init_thread_copy, + .update_thread_context = ONLY_IF_THREADS_ENABLED(hevc_update_thread_context), + .init_thread_copy = ONLY_IF_THREADS_ENABLED(hevc_init_thread_copy), .capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY | AV_CODEC_CAP_SLICE_THREADS | AV_CODEC_CAP_FRAME_THREADS, .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE | FF_CODEC_CAP_EXPORTS_CROPPING, diff --git a/libavcodec/hevcdec.h b/libavcodec/hevcdec.h index dd951aae0..b45969b7e 100644 --- a/libavcodec/hevcdec.h +++ b/libavcodec/hevcdec.h @@ -430,6 +430,7 @@ typedef struct HEVCContext { int max_ra; int bs_width; int bs_height; + int overlap; int is_decoded; int no_rasl_output_flag; diff --git a/libavcodec/hnm4video.c b/libavcodec/hnm4video.c index 9e1ac49dd..177ce1d47 100644 --- a/libavcodec/hnm4video.c +++ b/libavcodec/hnm4video.c @@ -117,14 +117,17 @@ static void unpack_intraframe(AVCodecContext *avctx, uint8_t *src, static void postprocess_current_frame(AVCodecContext *avctx) { Hnm4VideoContext *hnm = avctx->priv_data; - uint32_t x, y, src_x, src_y; + uint32_t x, y, src_y; + int width = hnm->width; for (y = 0; y < hnm->height; y++) { + uint8_t *dst = hnm->processed + y * width; + const uint8_t *src = hnm->current; src_y = y - (y % 2); - src_x = src_y * hnm->width + (y % 2); - for (x = 0; x < hnm->width; x++) { - hnm->processed[(y * hnm->width) + x] = hnm->current[src_x]; - src_x += 2; + src += src_y * width + (y % 2); + for (x = 0; x < width; x++) { + dst[x] = *src; + src += 2; } } } @@ -143,7 +146,7 @@ static void copy_processed_frame(AVCodecContext *avctx, AVFrame *frame) } } -static void decode_interframe_v4(AVCodecContext *avctx, uint8_t *src, uint32_t size) +static int decode_interframe_v4(AVCodecContext *avctx, uint8_t *src, uint32_t size) { Hnm4VideoContext *hnm = avctx->priv_data; GetByteContext gb; @@ -162,7 +165,7 @@ static void decode_interframe_v4(AVCodecContext *avctx, uint8_t *src, uint32_t s if (tag == 0) { if (writeoffset + 2 > hnm->width * hnm->height) { av_log(avctx, AV_LOG_ERROR, "writeoffset out of bounds\n"); - break; + return AVERROR_INVALIDDATA; } hnm->current[writeoffset++] = bytestream2_get_byte(&gb); hnm->current[writeoffset++] = bytestream2_get_byte(&gb); @@ -176,7 +179,7 @@ static void decode_interframe_v4(AVCodecContext *avctx, uint8_t *src, uint32_t s count = bytestream2_get_byte(&gb) * 2; if (writeoffset + count > hnm->width * hnm->height) { av_log(avctx, AV_LOG_ERROR, "writeoffset out of bounds\n"); - break; + return AVERROR_INVALIDDATA; } while (count > 0) { hnm->current[writeoffset++] = bytestream2_peek_byte(&gb); @@ -188,7 +191,7 @@ static void decode_interframe_v4(AVCodecContext *avctx, uint8_t *src, uint32_t s } if (writeoffset > hnm->width * hnm->height) { av_log(avctx, AV_LOG_ERROR, "writeoffset out of bounds\n"); - break; + return AVERROR_INVALIDDATA; } } else { previous = bytestream2_peek_byte(&gb) & 0x20; @@ -204,24 +207,25 @@ static void decode_interframe_v4(AVCodecContext *avctx, uint8_t *src, uint32_t s if (!backward && offset + 2*count > hnm->width * hnm->height) { av_log(avctx, AV_LOG_ERROR, "Attempting to read out of bounds\n"); - break; + return AVERROR_INVALIDDATA; } else if (backward && offset + 1 >= hnm->width * hnm->height) { av_log(avctx, AV_LOG_ERROR, "Attempting to read out of bounds\n"); - break; + return AVERROR_INVALIDDATA; } else if (writeoffset + 2*count > hnm->width * hnm->height) { av_log(avctx, AV_LOG_ERROR, "Attempting to write out of bounds\n"); - break; + return AVERROR_INVALIDDATA; + } if(backward) { if (offset < (!!backline)*(2 * hnm->width - 1) + 2*(left-1)) { av_log(avctx, AV_LOG_ERROR, "Attempting to read out of bounds\n"); - break; + return AVERROR_INVALIDDATA; } } else { if (offset < (!!backline)*(2 * hnm->width - 1)) { av_log(avctx, AV_LOG_ERROR, "Attempting to read out of bounds\n"); - break; + return AVERROR_INVALIDDATA; } } @@ -268,6 +272,7 @@ static void decode_interframe_v4(AVCodecContext *avctx, uint8_t *src, uint32_t s } } } + return 0; } static void decode_interframe_v4a(AVCodecContext *avctx, uint8_t *src, @@ -435,7 +440,9 @@ static int hnm_decode_frame(AVCodecContext *avctx, void *data, decode_interframe_v4a(avctx, avpkt->data + 8, avpkt->size - 8); memcpy(hnm->processed, hnm->current, hnm->width * hnm->height); } else { - decode_interframe_v4(avctx, avpkt->data + 8, avpkt->size - 8); + int ret = decode_interframe_v4(avctx, avpkt->data + 8, avpkt->size - 8); + if (ret < 0) + return ret; postprocess_current_frame(avctx); } copy_processed_frame(avctx, frame); diff --git a/libavcodec/hq_hqa.c b/libavcodec/hq_hqa.c index ec9da3e04..eec2e980b 100644 --- a/libavcodec/hq_hqa.c +++ b/libavcodec/hq_hqa.c @@ -248,13 +248,18 @@ static int hqa_decode_frame(HQContext *ctx, AVFrame *pic, size_t data_size) int width, height, quant; const uint8_t *src = ctx->gbc.buffer; + if (bytestream2_get_bytes_left(&ctx->gbc) < 8 + 4*(num_slices + 1)) + return AVERROR_INVALIDDATA; + width = bytestream2_get_be16(&ctx->gbc); height = bytestream2_get_be16(&ctx->gbc); + ret = ff_set_dimensions(ctx->avctx, width, height); + if (ret < 0) + return ret; + ctx->avctx->coded_width = FFALIGN(width, 16); ctx->avctx->coded_height = FFALIGN(height, 16); - ctx->avctx->width = width; - ctx->avctx->height = height; ctx->avctx->bits_per_raw_sample = 8; ctx->avctx->pix_fmt = AV_PIX_FMT_YUVA422P; diff --git a/libavcodec/huffyuvdec.c b/libavcodec/huffyuvdec.c index 66357bfb4..46dcfa823 100644 --- a/libavcodec/huffyuvdec.c +++ b/libavcodec/huffyuvdec.c @@ -418,9 +418,6 @@ static av_cold int decode_init(AVCodecContext *avctx) case 0x0F0: avctx->pix_fmt = AV_PIX_FMT_GRAY16; break; - case 0x170: - avctx->pix_fmt = AV_PIX_FMT_GRAY8A; - break; case 0x470: avctx->pix_fmt = AV_PIX_FMT_GBRP; break; @@ -905,54 +902,23 @@ static void add_median_prediction(HYuvContext *s, uint8_t *dst, const uint8_t *s s->hdsp.add_hfyu_median_pred_int16((uint16_t *)dst, (const uint16_t *)src, (const uint16_t *)diff, s->n-1, w, left, left_top); } } -static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, - AVPacket *avpkt) + +static int decode_slice(AVCodecContext *avctx, AVFrame *p, int height, + int buf_size, int y_offset, int table_size) { - const uint8_t *buf = avpkt->data; - int buf_size = avpkt->size; HYuvContext *s = avctx->priv_data; + int fake_ystride, fake_ustride, fake_vstride; const int width = s->width; const int width2 = s->width >> 1; - const int height = s->height; - int fake_ystride, fake_ustride, fake_vstride; - ThreadFrame frame = { .f = data }; - AVFrame *const p = data; - int table_size = 0, ret; + int ret; - if (buf_size < (width * height + 7)/8) - return AVERROR_INVALIDDATA; - - av_fast_padded_malloc(&s->bitstream_buffer, - &s->bitstream_buffer_size, - buf_size); - if (!s->bitstream_buffer) - return AVERROR(ENOMEM); - - s->bdsp.bswap_buf((uint32_t *) s->bitstream_buffer, - (const uint32_t *) buf, buf_size / 4); - - if ((ret = ff_thread_get_buffer(avctx, &frame, 0)) < 0) - return ret; - - if (s->context) { - table_size = read_huffman_tables(s, s->bitstream_buffer, buf_size); - if (table_size < 0) - return table_size; - } - - if ((unsigned) (buf_size - table_size) >= INT_MAX / 8) - return AVERROR_INVALIDDATA; - - if ((ret = init_get_bits(&s->gb, s->bitstream_buffer + table_size, - (buf_size - table_size) * 8)) < 0) + if ((ret = init_get_bits8(&s->gb, s->bitstream_buffer + table_size, buf_size - table_size)) < 0) return ret; fake_ystride = s->interlaced ? p->linesize[0] * 2 : p->linesize[0]; fake_ustride = s->interlaced ? p->linesize[1] * 2 : p->linesize[1]; fake_vstride = s->interlaced ? p->linesize[2] * 2 : p->linesize[2]; - s->last_slice_end = 0; - if (s->version > 2) { int plane; for(plane = 0; plane < 1 + 2*s->chroma + s->alpha; plane++) { @@ -1034,31 +1000,31 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, return AVERROR_PATCHWELCOME; } else { leftv = - p->data[2][0] = get_bits(&s->gb, 8); + p->data[2][0 + y_offset * p->linesize[2]] = get_bits(&s->gb, 8); lefty = - p->data[0][1] = get_bits(&s->gb, 8); + p->data[0][1 + y_offset * p->linesize[0]] = get_bits(&s->gb, 8); leftu = - p->data[1][0] = get_bits(&s->gb, 8); - p->data[0][0] = get_bits(&s->gb, 8); + p->data[1][0 + y_offset * p->linesize[1]] = get_bits(&s->gb, 8); + p->data[0][0 + y_offset * p->linesize[0]] = get_bits(&s->gb, 8); switch (s->predictor) { case LEFT: case PLANE: decode_422_bitstream(s, width - 2); - lefty = s->llviddsp.add_left_pred(p->data[0] + 2, s->temp[0], + lefty = s->llviddsp.add_left_pred(p->data[0] + p->linesize[0] * y_offset + 2, s->temp[0], width - 2, lefty); if (!(s->flags & AV_CODEC_FLAG_GRAY)) { - leftu = s->llviddsp.add_left_pred(p->data[1] + 1, s->temp[1], width2 - 1, leftu); - leftv = s->llviddsp.add_left_pred(p->data[2] + 1, s->temp[2], width2 - 1, leftv); + leftu = s->llviddsp.add_left_pred(p->data[1] + p->linesize[1] * y_offset + 1, s->temp[1], width2 - 1, leftu); + leftv = s->llviddsp.add_left_pred(p->data[2] + p->linesize[2] * y_offset + 1, s->temp[2], width2 - 1, leftv); } - for (cy = y = 1; y < s->height; y++, cy++) { + for (cy = y = 1; y < height; y++, cy++) { uint8_t *ydst, *udst, *vdst; if (s->bitstream_bpp == 12) { decode_gray_bitstream(s, width); - ydst = p->data[0] + p->linesize[0] * y; + ydst = p->data[0] + p->linesize[0] * (y + y_offset); lefty = s->llviddsp.add_left_pred(ydst, s->temp[0], width, lefty); @@ -1067,15 +1033,15 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, s->llviddsp.add_bytes(ydst, ydst - fake_ystride, width); } y++; - if (y >= s->height) + if (y >= height) break; } draw_slice(s, p, y); - ydst = p->data[0] + p->linesize[0] * y; - udst = p->data[1] + p->linesize[1] * cy; - vdst = p->data[2] + p->linesize[2] * cy; + ydst = p->data[0] + p->linesize[0] * (y + y_offset); + udst = p->data[1] + p->linesize[1] * (cy + y_offset); + vdst = p->data[2] + p->linesize[2] * (cy + y_offset); decode_422_bitstream(s, width); lefty = s->llviddsp.add_left_pred(ydst, s->temp[0], @@ -1185,7 +1151,7 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, } else { int y; uint8_t left[4]; - const int last_line = (height - 1) * p->linesize[0]; + const int last_line = (y_offset + height - 1) * p->linesize[0]; if (s->bitstream_bpp == 32) { left[A] = p->data[0][last_line + A] = get_bits(&s->gb, 8); @@ -1208,17 +1174,17 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, s->hdsp.add_hfyu_left_pred_bgr32(p->data[0] + last_line + 4, s->temp[0], width - 1, left); - for (y = s->height - 2; y >= 0; y--) { // Yes it is stored upside down. + for (y = height - 2; y >= 0; y--) { // Yes it is stored upside down. decode_bgr_bitstream(s, width); - s->hdsp.add_hfyu_left_pred_bgr32(p->data[0] + p->linesize[0] * y, + s->hdsp.add_hfyu_left_pred_bgr32(p->data[0] + p->linesize[0] * (y + y_offset), s->temp[0], width, left); if (s->predictor == PLANE) { if (s->bitstream_bpp != 32) left[A] = 0; - if (y < s->height - 1 - s->interlaced) { - s->llviddsp.add_bytes(p->data[0] + p->linesize[0] * y, - p->data[0] + p->linesize[0] * y + + if (y < height - 1 - s->interlaced) { + s->llviddsp.add_bytes(p->data[0] + p->linesize[0] * (y + y_offset), + p->data[0] + p->linesize[0] * (y + y_offset) + fake_ystride, 4 * width); } } @@ -1236,7 +1202,89 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, return AVERROR_PATCHWELCOME; } } - emms_c(); + + return 0; +} + +static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, + AVPacket *avpkt) +{ + const uint8_t *buf = avpkt->data; + int buf_size = avpkt->size; + HYuvContext *s = avctx->priv_data; + const int width = s->width; + const int height = s->height; + ThreadFrame frame = { .f = data }; + AVFrame *const p = data; + int slice, table_size = 0, ret, nb_slices; + unsigned slices_info_offset; + int slice_height; + + if (buf_size < (width * height + 7)/8) + return AVERROR_INVALIDDATA; + + av_fast_padded_malloc(&s->bitstream_buffer, + &s->bitstream_buffer_size, + buf_size); + if (!s->bitstream_buffer) + return AVERROR(ENOMEM); + + s->bdsp.bswap_buf((uint32_t *) s->bitstream_buffer, + (const uint32_t *) buf, buf_size / 4); + + if ((ret = ff_thread_get_buffer(avctx, &frame, 0)) < 0) + return ret; + + if (s->context) { + table_size = read_huffman_tables(s, s->bitstream_buffer, buf_size); + if (table_size < 0) + return table_size; + } + + if ((unsigned) (buf_size - table_size) >= INT_MAX / 8) + return AVERROR_INVALIDDATA; + + s->last_slice_end = 0; + + if (avctx->codec_id == AV_CODEC_ID_HYMT && + (buf_size > 32 && AV_RL32(avpkt->data + buf_size - 16) == 0)) { + slices_info_offset = AV_RL32(avpkt->data + buf_size - 4); + slice_height = AV_RL32(avpkt->data + buf_size - 8); + nb_slices = AV_RL32(avpkt->data + buf_size - 12); + if (nb_slices * 8LL + slices_info_offset > buf_size - 16 || + s->chroma_v_shift || + slice_height <= 0 || nb_slices * (uint64_t)slice_height > height) + return AVERROR_INVALIDDATA; + } else { + slice_height = height; + nb_slices = 1; + } + + for (slice = 0; slice < nb_slices; slice++) { + int y_offset, slice_offset, slice_size; + + if (nb_slices > 1) { + slice_offset = AV_RL32(avpkt->data + slices_info_offset + slice * 8); + slice_size = AV_RL32(avpkt->data + slices_info_offset + slice * 8 + 4); + + if (slice_offset < 0 || slice_size <= 0 || (slice_offset&3) || + slice_offset + (int64_t)slice_size > buf_size) + return AVERROR_INVALIDDATA; + + y_offset = height - (slice + 1) * slice_height; + s->bdsp.bswap_buf((uint32_t *)s->bitstream_buffer, + (const uint32_t *)(buf + slice_offset), slice_size / 4); + } else { + y_offset = 0; + slice_offset = 0; + slice_size = buf_size; + } + + ret = decode_slice(avctx, p, slice_height, slice_size, y_offset, table_size); + emms_c(); + if (ret < 0) + return ret; + } *got_frame = 1; @@ -1272,3 +1320,19 @@ AVCodec ff_ffvhuff_decoder = { .init_thread_copy = ONLY_IF_THREADS_ENABLED(decode_init_thread_copy), }; #endif /* CONFIG_FFVHUFF_DECODER */ + +#if CONFIG_HYMT_DECODER +AVCodec ff_hymt_decoder = { + .name = "hymt", + .long_name = NULL_IF_CONFIG_SMALL("HuffYUV MT"), + .type = AVMEDIA_TYPE_VIDEO, + .id = AV_CODEC_ID_HYMT, + .priv_data_size = sizeof(HYuvContext), + .init = decode_init, + .close = decode_end, + .decode = decode_frame, + .capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DRAW_HORIZ_BAND | + AV_CODEC_CAP_FRAME_THREADS, + .init_thread_copy = ONLY_IF_THREADS_ENABLED(decode_init_thread_copy), +}; +#endif /* CONFIG_HYMT_DECODER */ diff --git a/libavcodec/huffyuvenc.c b/libavcodec/huffyuvenc.c index 8be752844..a6f0d0644 100644 --- a/libavcodec/huffyuvenc.c +++ b/libavcodec/huffyuvenc.c @@ -268,7 +268,6 @@ FF_ENABLE_DEPRECATION_WARNINGS case AV_PIX_FMT_YUVA420P: case AV_PIX_FMT_YUVA422P: case AV_PIX_FMT_GBRAP: - case AV_PIX_FMT_GRAY8A: case AV_PIX_FMT_YUV420P9: case AV_PIX_FMT_YUV420P10: case AV_PIX_FMT_YUV420P12: @@ -1118,11 +1117,10 @@ AVCodec ff_ffvhuff_encoder = { AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUV411P, AV_PIX_FMT_YUV410P, AV_PIX_FMT_YUV440P, AV_PIX_FMT_GBRP, - AV_PIX_FMT_GBRP9, AV_PIX_FMT_GBRP10, AV_PIX_FMT_GBRP12, AV_PIX_FMT_GBRP14, + AV_PIX_FMT_GBRP9, AV_PIX_FMT_GBRP10, AV_PIX_FMT_GBRP12, AV_PIX_FMT_GBRP14, AV_PIX_FMT_GBRP16, AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY16, AV_PIX_FMT_YUVA420P, AV_PIX_FMT_YUVA422P, AV_PIX_FMT_YUVA444P, AV_PIX_FMT_GBRAP, - AV_PIX_FMT_GRAY8A, AV_PIX_FMT_YUV420P9, AV_PIX_FMT_YUV420P10, AV_PIX_FMT_YUV420P12, AV_PIX_FMT_YUV420P14, AV_PIX_FMT_YUV420P16, AV_PIX_FMT_YUV422P9, AV_PIX_FMT_YUV422P10, AV_PIX_FMT_YUV422P12, AV_PIX_FMT_YUV422P14, AV_PIX_FMT_YUV422P16, AV_PIX_FMT_YUV444P9, AV_PIX_FMT_YUV444P10, AV_PIX_FMT_YUV444P12, AV_PIX_FMT_YUV444P14, AV_PIX_FMT_YUV444P16, diff --git a/libavcodec/idcinvideo.c b/libavcodec/idcinvideo.c index cff9ad31a..6b2d8087a 100644 --- a/libavcodec/idcinvideo.c +++ b/libavcodec/idcinvideo.c @@ -243,6 +243,11 @@ static int idcin_decode_frame(AVCodecContext *avctx, return buf_size; } +static const AVCodecDefault idcin_defaults[] = { + { "max_pixels", "320*240" }, + { NULL }, +}; + AVCodec ff_idcin_decoder = { .name = "idcinvideo", .long_name = NULL_IF_CONFIG_SMALL("id Quake II CIN video"), @@ -252,4 +257,5 @@ AVCodec ff_idcin_decoder = { .init = idcin_decode_init, .decode = idcin_decode_frame, .capabilities = AV_CODEC_CAP_DR1, + .defaults = idcin_defaults, }; diff --git a/libavcodec/iff.c b/libavcodec/iff.c index 33cf2e3a9..c18bac1ea 100644 --- a/libavcodec/iff.c +++ b/libavcodec/iff.c @@ -111,23 +111,23 @@ static const uint64_t plane8_lut[8][256] = { LUT8(4), LUT8(5), LUT8(6), LUT8(7), }; -#define LUT32(plane) { \ - 0, 0, 0, 0, \ - 0, 0, 0, 1 << plane, \ - 0, 0, 1 << plane, 0, \ - 0, 0, 1 << plane, 1 << plane, \ - 0, 1 << plane, 0, 0, \ - 0, 1 << plane, 0, 1 << plane, \ - 0, 1 << plane, 1 << plane, 0, \ - 0, 1 << plane, 1 << plane, 1 << plane, \ - 1 << plane, 0, 0, 0, \ - 1 << plane, 0, 0, 1 << plane, \ - 1 << plane, 0, 1 << plane, 0, \ - 1 << plane, 0, 1 << plane, 1 << plane, \ - 1 << plane, 1 << plane, 0, 0, \ - 1 << plane, 1 << plane, 0, 1 << plane, \ - 1 << plane, 1 << plane, 1 << plane, 0, \ - 1 << plane, 1 << plane, 1 << plane, 1 << plane, \ +#define LUT32(plane) { \ + 0, 0, 0, 0, \ + 0, 0, 0, 1U << plane, \ + 0, 0, 1U << plane, 0, \ + 0, 0, 1U << plane, 1U << plane, \ + 0, 1U << plane, 0, 0, \ + 0, 1U << plane, 0, 1U << plane, \ + 0, 1U << plane, 1U << plane, 0, \ + 0, 1U << plane, 1U << plane, 1U << plane, \ + 1U << plane, 0, 0, 0, \ + 1U << plane, 0, 0, 1U << plane, \ + 1U << plane, 0, 1U << plane, 0, \ + 1U << plane, 0, 1U << plane, 1U << plane, \ + 1U << plane, 1U << plane, 0, 0, \ + 1U << plane, 1U << plane, 0, 1U << plane, \ + 1U << plane, 1U << plane, 1U << plane, 0, \ + 1U << plane, 1U << plane, 1U << plane, 1U << plane, \ } // 32 planes * 4-bit mask * 4 lookup tables each @@ -180,6 +180,10 @@ static int cmap_read_palette(AVCodecContext *avctx, uint32_t *pal) pal[i] = 0xFF000000 | gray2rgb((i * 255) >> avctx->bits_per_coded_sample); } if (s->masking == MASK_HAS_MASK) { + if ((1 << avctx->bits_per_coded_sample) < count) { + avpriv_request_sample(avctx, "overlapping mask"); + return AVERROR_PATCHWELCOME; + } memcpy(pal + (1 << avctx->bits_per_coded_sample), pal, count * 4); for (i = 0; i < count; i++) pal[i] &= 0xFFFFFF; @@ -280,6 +284,16 @@ static int extract_header(AVCodecContext *const avctx, for (i = 0; i < 16; i++) s->tvdc[i] = bytestream_get_be16(&buf); + if (s->ham) { + if (s->bpp > 8) { + av_log(avctx, AV_LOG_ERROR, "Invalid number of hold bits for HAM: %u\n", s->ham); + return AVERROR_INVALIDDATA; + } else if (s->ham != (s->bpp > 6 ? 6 : 4)) { + av_log(avctx, AV_LOG_ERROR, "Invalid number of hold bits for HAM: %u, BPP: %u\n", s->ham, s->bpp); + return AVERROR_INVALIDDATA; + } + } + if (s->masking == MASK_HAS_MASK) { if (s->bpp >= 8 && !s->ham) { avctx->pix_fmt = AV_PIX_FMT_RGB32; @@ -307,9 +321,6 @@ static int extract_header(AVCodecContext *const avctx, if (!s->bpp || s->bpp > 32) { av_log(avctx, AV_LOG_ERROR, "Invalid number of bitplanes: %u\n", s->bpp); return AVERROR_INVALIDDATA; - } else if (s->ham >= 8) { - av_log(avctx, AV_LOG_ERROR, "Invalid number of hold bits for HAM: %u\n", s->ham); - return AVERROR_INVALIDDATA; } av_freep(&s->ham_buf); @@ -371,6 +382,8 @@ static av_cold int decode_end(AVCodecContext *avctx) av_freep(&s->planebuf); av_freep(&s->ham_buf); av_freep(&s->ham_palbuf); + av_freep(&s->mask_buf); + av_freep(&s->mask_palbuf); av_freep(&s->video[0]); av_freep(&s->video[1]); av_freep(&s->pal); @@ -1512,7 +1525,7 @@ static int decode_frame(AVCodecContext *avctx, buf_size -= bytestream2_tell(gb); desc = av_pix_fmt_desc_get(avctx->pix_fmt); - if (!s->init && avctx->bits_per_coded_sample <= 8 && + if (!s->init && avctx->bits_per_coded_sample <= 8 - (s->masking == MASK_HAS_MASK) && avctx->pix_fmt == AV_PIX_FMT_PAL8) { if ((res = cmap_read_palette(avctx, (uint32_t *)frame->data[1])) < 0) return res; diff --git a/libavcodec/ilbcdata.h b/libavcodec/ilbcdata.h new file mode 100644 index 000000000..8d145bc18 --- /dev/null +++ b/libavcodec/ilbcdata.h @@ -0,0 +1,243 @@ +/* + * Copyright (c) 2013, The WebRTC project authors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Google nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef AVCODEC_ILBCDATA_H +#define AVCODEC_ILBCDATA_H + +#include "libavutil/common.h" + +static const uint8_t lsf_dim_codebook[] = { 3, 3, 4 }; +static const uint8_t lsf_size_codebook[] = { 64, 128, 128 }; +static const int16_t lsf_weight_20ms[] = { 12288, 8192, 4096, 0 }; +static const int16_t lsf_weight_30ms[] = { 8192, 16384, 10923, 5461, 0, 0 }; + +static const int16_t hp_out_coeffs[] = { 3849, -7699, 3849, 7918, -3833 }; + +static const int16_t kPlcPfSlope[] = { 26667, 18729, 13653, 10258, 7901, 6214 }; + +static const int16_t kPlcPitchFact[] = { 0, 5462, 10922, 16384, 21846, 27306 }; + +static const int16_t kCbFiltersRev[] = { + -140, 446, -755, 3302, 2922, -590, 343, -138 +}; + +static const int16_t kPlcPerSqr[] = { 839, 1343, 2048, 2998, 4247, 5849 }; + +static const int16_t alpha[] = { + 6554, 13107, 19661, 26214 +}; + +static const int16_t kLpcChirpSyntDenum[] = { + 32767, 29573, 26690, 24087, 21739, 19619, 17707, 15980, 14422, 13016, 11747 +}; + +static const int16_t LpcChirpWeightDenum[] = { + 32767, 13835, 5841, 2466, 1041, 440, 186, 78, 33, 14, 6 +}; + +static const int16_t cos_tbl[64] = { + 32767, 32729, 32610, 32413, 32138, 31786, 31357, 30853, + 30274, 29622, 28899, 28106, 27246, 26320, 25330, 24279, + 23170, 22006, 20788, 19520, 18205, 16846, 15447, 14010, + 12540, 11039, 9512, 7962, 6393, 4808, 3212, 1608, + 0, -1608, -3212, -4808, -6393, -7962, -9512, -11039, + -12540, -14010, -15447, -16846, -18205, -19520, -20788, -22006, + -23170, -24279, -25330, -26320, -27246, -28106, -28899, -29622, + -30274, -30853, -31357, -31786, -32138, -32413, -32610, -32729, +}; + +static const int16_t cos_derivative_tbl[64] = { + -632, -1893, -3150, -4399, -5638, -6863, -8072, -9261, + -10428, -11570, -12684, -13767, -14817, -15832, -16808, -17744, + -18637, -19486, -20287, -21039, -21741, -22390, -22986, -23526, + -24009, -24435, -24801, -25108, -25354, -25540, -25664, -25726, + -25726, -25664, -25540, -25354, -25108, -24801, -24435, -24009, + -23526, -22986, -22390, -21741, -21039, -20287, -19486, -18637, + -17744, -16808, -15832, -14817, -13767, -12684, -11570, -10428, + -9261, -8072, -6863, -5638, -4399, -3150, -1893, -632 +}; + +static const int16_t lsf_codebook[64 * 3 + 128 * 3 + 128 * 4] = { + 1273, 2238, 3696, 3199, 5309, 8209, 3606, 5671, 7829, + 2815, 5262, 8778, 2608, 4027, 5493, 1582, 3076, 5945, + 2983, 4181, 5396, 2437, 4322, 6902, 1861, 2998, 4613, + 2007, 3250, 5214, 1388, 2459, 4262, 2563, 3805, 5269, + 2036, 3522, 5129, 1935, 4025, 6694, 2744, 5121, 7338, + 2810, 4248, 5723, 3054, 5405, 7745, 1449, 2593, 4763, + 3411, 5128, 6596, 2484, 4659, 7496, 1668, 2879, 4818, + 1812, 3072, 5036, 1638, 2649, 3900, 2464, 3550, 4644, + 1853, 2900, 4158, 2458, 4163, 5830, 2556, 4036, 6254, + 2703, 4432, 6519, 3062, 4953, 7609, 1725, 3703, 6187, + 2221, 3877, 5427, 2339, 3579, 5197, 2021, 4633, 7037, + 2216, 3328, 4535, 2961, 4739, 6667, 2807, 3955, 5099, + 2788, 4501, 6088, 1642, 2755, 4431, 3341, 5282, 7333, + 2414, 3726, 5727, 1582, 2822, 5269, 2259, 3447, 4905, + 3117, 4986, 7054, 1825, 3491, 5542, 3338, 5736, 8627, + 1789, 3090, 5488, 2566, 3720, 4923, 2846, 4682, 7161, + 1950, 3321, 5976, 1834, 3383, 6734, 3238, 4769, 6094, + 2031, 3978, 5903, 1877, 4068, 7436, 2131, 4644, 8296, + 2764, 5010, 8013, 2194, 3667, 6302, 2053, 3127, 4342, + 3523, 6595, 10010, 3134, 4457, 5748, 3142, 5819, 9414, + 2223, 4334, 6353, 2022, 3224, 4822, 2186, 3458, 5544, + 2552, 4757, 6870, 10905, 12917, 14578, 9503, 11485, 14485, + 9518, 12494, 14052, 6222, 7487, 9174, 7759, 9186, 10506, + 8315, 12755, 14786, 9609, 11486, 13866, 8909, 12077, 13643, + 7369, 9054, 11520, 9408, 12163, 14715, 6436, 9911, 12843, + 7109, 9556, 11884, 7557, 10075, 11640, 6482, 9202, 11547, + 6463, 7914, 10980, 8611, 10427, 12752, 7101, 9676, 12606, + 7428, 11252, 13172, 10197, 12955, 15842, 7487, 10955, 12613, + 5575, 7858, 13621, 7268, 11719, 14752, 7476, 11744, 13795, + 7049, 8686, 11922, 8234, 11314, 13983, 6560, 11173, 14984, + 6405, 9211, 12337, 8222, 12054, 13801, 8039, 10728, 13255, + 10066, 12733, 14389, 6016, 7338, 10040, 6896, 8648, 10234, + 7538, 9170, 12175, 7327, 12608, 14983, 10516, 12643, 15223, + 5538, 7644, 12213, 6728, 12221, 14253, 7563, 9377, 12948, + 8661, 11023, 13401, 7280, 8806, 11085, 7723, 9793, 12333, + 12225, 14648, 16709, 8768, 13389, 15245, 10267, 12197, 13812, + 5301, 7078, 11484, 7100, 10280, 11906, 8716, 12555, 14183, + 9567, 12464, 15434, 7832, 12305, 14300, 7608, 10556, 12121, + 8913, 11311, 12868, 7414, 9722, 11239, 8666, 11641, 13250, + 9079, 10752, 12300, 8024, 11608, 13306, 10453, 13607, 16449, + 8135, 9573, 10909, 6375, 7741, 10125, 10025, 12217, 14874, + 6985, 11063, 14109, 9296, 13051, 14642, 8613, 10975, 12542, + 6583, 10414, 13534, 6191, 9368, 13430, 5742, 6859, 9260, + 7723, 9813, 13679, 8137, 11291, 12833, 6562, 8973, 10641, + 6062, 8462, 11335, 6928, 8784, 12647, 7501, 8784, 10031, + 8372, 10045, 12135, 8191, 9864, 12746, 5917, 7487, 10979, + 5516, 6848, 10318, 6819, 9899, 11421, 7882, 12912, 15670, + 9558, 11230, 12753, 7752, 9327, 11472, 8479, 9980, 11358, + 11418, 14072, 16386, 7968, 10330, 14423, 8423, 10555, 12162, + 6337, 10306, 14391, 8850, 10879, 14276, 6750, 11885, 15710, + 7037, 8328, 9764, 6914, 9266, 13476, 9746, 13949, 15519, + 11032, 14444, 16925, 8032, 10271, 11810, 10962, 13451, 15833, + 10021, 11667, 13324, 6273, 8226, 12936, 8543, 10397, 13496, + 7936, 10302, 12745, 6769, 8138, 10446, 6081, 7786, 11719, + 8637, 11795, 14975, 8790, 10336, 11812, 7040, 8490, 10771, + 7338, 10381, 13153, 6598, 7888, 9358, 6518, 8237, 12030, + 9055, 10763, 12983, 6490, 10009, 12007, 9589, 12023, 13632, + 6867, 9447, 10995, 7930, 9816, 11397, 10241, 13300, 14939, + 5830, 8670, 12387, 9870, 11915, 14247, 9318, 11647, 13272, + 6721, 10836, 12929, 6543, 8233, 9944, 8034, 10854, 12394, + 9112, 11787, 14218, 9302, 11114, 13400, 9022, 11366, 13816, + 6962, 10461, 12480, 11288, 13333, 15222, 7249, 8974, 10547, + 10566, 12336, 14390, 6697, 11339, 13521, 11851, 13944, 15826, + 6847, 8381, 11349, 7509, 9331, 10939, 8029, 9618, 11909, + 13973, 17644, 19647, 22474, 14722, 16522, 20035, 22134, 16305, 18179, 21106, 23048, + 15150, 17948, 21394, 23225, 13582, 15191, 17687, 22333, 11778, 15546, 18458, 21753, + 16619, 18410, 20827, 23559, 14229, 15746, 17907, 22474, 12465, 15327, 20700, 22831, + 15085, 16799, 20182, 23410, 13026, 16935, 19890, 22892, 14310, 16854, 19007, 22944, + 14210, 15897, 18891, 23154, 14633, 18059, 20132, 22899, 15246, 17781, 19780, 22640, + 16396, 18904, 20912, 23035, 14618, 17401, 19510, 21672, 15473, 17497, 19813, 23439, + 18851, 20736, 22323, 23864, 15055, 16804, 18530, 20916, 16490, 18196, 19990, 21939, + 11711, 15223, 21154, 23312, 13294, 15546, 19393, 21472, 12956, 16060, 20610, 22417, + 11628, 15843, 19617, 22501, 14106, 16872, 19839, 22689, 15655, 18192, 20161, 22452, + 12953, 15244, 20619, 23549, 15322, 17193, 19926, 21762, 16873, 18676, 20444, 22359, + 14874, 17871, 20083, 21959, 11534, 14486, 19194, 21857, 17766, 19617, 21338, 23178, + 13404, 15284, 19080, 23136, 15392, 17527, 19470, 21953, 14462, 16153, 17985, 21192, + 17734, 19750, 21903, 23783, 16973, 19096, 21675, 23815, 16597, 18936, 21257, 23461, + 15966, 17865, 20602, 22920, 15416, 17456, 20301, 22972, 18335, 20093, 21732, 23497, + 15548, 17217, 20679, 23594, 15208, 16995, 20816, 22870, 13890, 18015, 20531, 22468, + 13211, 15377, 19951, 22388, 12852, 14635, 17978, 22680, 16002, 17732, 20373, 23544, + 11373, 14134, 19534, 22707, 17329, 19151, 21241, 23462, 15612, 17296, 19362, 22850, + 15422, 19104, 21285, 23164, 13792, 17111, 19349, 21370, 15352, 17876, 20776, 22667, + 15253, 16961, 18921, 22123, 14108, 17264, 20294, 23246, 15785, 17897, 20010, 21822, + 17399, 19147, 20915, 22753, 13010, 15659, 18127, 20840, 16826, 19422, 22218, 24084, + 18108, 20641, 22695, 24237, 18018, 20273, 22268, 23920, 16057, 17821, 21365, 23665, + 16005, 17901, 19892, 23016, 13232, 16683, 21107, 23221, 13280, 16615, 19915, 21829, + 14950, 18575, 20599, 22511, 16337, 18261, 20277, 23216, 14306, 16477, 21203, 23158, + 12803, 17498, 20248, 22014, 14327, 17068, 20160, 22006, 14402, 17461, 21599, 23688, + 16968, 18834, 20896, 23055, 15070, 17157, 20451, 22315, 15419, 17107, 21601, 23946, + 16039, 17639, 19533, 21424, 16326, 19261, 21745, 23673, 16489, 18534, 21658, 23782, + 16594, 18471, 20549, 22807, 18973, 21212, 22890, 24278, 14264, 18674, 21123, 23071, + 15117, 16841, 19239, 23118, 13762, 15782, 20478, 23230, 14111, 15949, 20058, 22354, + 14990, 16738, 21139, 23492, 13735, 16971, 19026, 22158, 14676, 17314, 20232, 22807, + 16196, 18146, 20459, 22339, 14747, 17258, 19315, 22437, 14973, 17778, 20692, 23367, + 15715, 17472, 20385, 22349, 15702, 18228, 20829, 23410, 14428, 16188, 20541, 23630, + 16824, 19394, 21365, 23246, 13069, 16392, 18900, 21121, 12047, 16640, 19463, 21689, + 14757, 17433, 19659, 23125, 15185, 16930, 19900, 22540, 16026, 17725, 19618, 22399, + 16086, 18643, 21179, 23472, 15462, 17248, 19102, 21196, 17368, 20016, 22396, 24096, + 12340, 14475, 19665, 23362, 13636, 16229, 19462, 22728, 14096, 16211, 19591, 21635, + 12152, 14867, 19943, 22301, 14492, 17503, 21002, 22728, 14834, 16788, 19447, 21411, + 14650, 16433, 19326, 22308, 14624, 16328, 19659, 23204, 13888, 16572, 20665, 22488, + 12977, 16102, 18841, 22246, 15523, 18431, 21757, 23738, 14095, 16349, 18837, 20947, + 13266, 17809, 21088, 22839, 15427, 18190, 20270, 23143, 11859, 16753, 20935, 22486, + 12310, 17667, 21736, 23319, 14021, 15926, 18702, 22002, 12286, 15299, 19178, 21126, + 15703, 17491, 21039, 23151, 12272, 14018, 18213, 22570, 14817, 16364, 18485, 22598, + 17109, 19683, 21851, 23677, 12657, 14903, 19039, 22061, 14713, 16487, 20527, 22814, + 14635, 16726, 18763, 21715, 15878, 18550, 20718, 22906 +}; + +static const int16_t gain3[9]={ + -16384, -10813, -5407, 0, 4096, 8192, 12288, 16384, 32767 +}; + +static const int16_t gain4[17]={ + -17203, -14746, -12288, -9830, -7373, -4915, -2458, 0, 2458, 4915, 7373, 9830, + 12288, 14746, 17203, 19661, 32767 +}; + +static const int16_t gain5[33]={ + 614, 1229, 1843, 2458, 3072, 3686, + 4301, 4915, 5530, 6144, 6758, 7373, + 7987, 8602, 9216, 9830, 10445, 11059, + 11674, 12288, 12902, 13517, 14131, 14746, + 15360, 15974, 16589, 17203, 17818, 18432, + 19046, 19661, 32767 +}; + +static const int16_t *const ilbc_gain[] = { + gain5, gain4, gain3, +}; + +static const int16_t ilbc_state[8] = { + -30473, -17838, -9257, -2537, 3639, 10893, 19958, 32636 +}; + +static const int16_t frg_quant_mod[64] = { + /* First 37 values in Q8 */ + 569, 671, 786, 916, 1077, 1278, + 1529, 1802, 2109, 2481, 2898, 3440, + 3943, 4535, 5149, 5778, 6464, 7208, + 7904, 8682, 9397, 10285, 11240, 12246, + 13313, 14382, 15492, 16735, 18131, 19693, + 21280, 22912, 24624, 26544, 28432, 30488, + 32720, + /* 22 values in Q5 */ + 4383, 4684, 5012, 5363, 5739, 6146, + 6603, 7113, 7679, 8285, 9040, 9850, + 10838, 11882, 13103, 14467, 15950, 17669, + 19712, 22016, 24800, 28576, + /* 5 values in Q3 */ + 8240, 9792, 12040, 15440, 22472 +}; + +#endif /* AVCODEC_ILBCDATA_H */ diff --git a/libavcodec/ilbcdec.c b/libavcodec/ilbcdec.c new file mode 100644 index 000000000..a82a27525 --- /dev/null +++ b/libavcodec/ilbcdec.c @@ -0,0 +1,1489 @@ +/* + * Copyright (c) 2013, The WebRTC project authors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Google nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "avcodec.h" +#include "internal.h" +#include "get_bits.h" +#include "ilbcdata.h" + +#define LPC_N_20MS 1 +#define LPC_N_30MS 2 +#define LPC_N_MAX 2 +#define LSF_NSPLIT 3 +#define NASUB_MAX 4 +#define LPC_FILTERORDER 10 +#define NSUB_MAX 6 +#define SUBL 40 + +#define ST_MEM_L_TBL 85 +#define MEM_LF_TBL 147 +#define STATE_SHORT_LEN_20MS 57 +#define STATE_SHORT_LEN_30MS 58 + +#define BLOCKL_MAX 240 +#define CB_MEML 147 +#define CB_NSTAGES 3 +#define CB_HALFFILTERLEN 4 +#define CB_FILTERLEN 8 + +#define ENH_NBLOCKS_TOT 8 +#define ENH_BLOCKL 80 +#define ENH_BUFL (ENH_NBLOCKS_TOT)*ENH_BLOCKL +#define ENH_BUFL_FILTEROVERHEAD 3 +#define BLOCKL_MAX 240 +#define NSUB_20MS 4 +#define NSUB_30MS 6 +#define NSUB_MAX 6 +#define NASUB_20MS 2 +#define NASUB_30MS 4 +#define NASUB_MAX 4 +#define STATE_LEN 80 +#define STATE_SHORT_LEN_30MS 58 +#define STATE_SHORT_LEN_20MS 57 + +#define SPL_MUL_16_16(a, b) ((int32_t) (((int16_t)(a)) * ((int16_t)(b)))) +#define SPL_MUL_16_16_RSFT(a, b, c) (SPL_MUL_16_16(a, b) >> (c)) + +typedef struct ILBCFrame { + int16_t lsf[LSF_NSPLIT*LPC_N_MAX]; + int16_t cb_index[CB_NSTAGES*(NASUB_MAX + 1)]; + int16_t gain_index[CB_NSTAGES*(NASUB_MAX + 1)]; + int16_t ifm; + int16_t state_first; + int16_t idx[STATE_SHORT_LEN_30MS]; + int16_t firstbits; + int16_t start; +} ILBCFrame; + +typedef struct ILBCContext { + AVClass *class; + int enhancer; + + int mode; + GetBitContext gb; + ILBCFrame frame; + + int prev_enh_pl; + int consPLICount; + int last_lag; + int state_short_len; + int lpc_n; + int16_t nasub; + int16_t nsub; + int block_samples; + int16_t no_of_words; + int16_t no_of_bytes; + int16_t lsfdeq[LPC_FILTERORDER*LPC_N_MAX]; + int16_t lsfold[LPC_FILTERORDER]; + int16_t syntMem[LPC_FILTERORDER]; + int16_t lsfdeqold[LPC_FILTERORDER]; + int16_t weightdenum[(LPC_FILTERORDER + 1) * NSUB_MAX]; + int16_t syntdenum[NSUB_MAX * (LPC_FILTERORDER + 1)]; + int16_t old_syntdenum[NSUB_MAX * (LPC_FILTERORDER + 1)]; + int16_t enh_buf[ENH_BUFL+ENH_BUFL_FILTEROVERHEAD]; + int16_t enh_period[ENH_NBLOCKS_TOT]; + int16_t prevResidual[NSUB_MAX*SUBL]; + int16_t decresidual[BLOCKL_MAX]; + int16_t plc_residual[BLOCKL_MAX + LPC_FILTERORDER]; + int16_t seed; + int16_t prevPLI; + int16_t prevScale; + int16_t prevLag; + int16_t per_square; + int16_t prev_lpc[LPC_FILTERORDER + 1]; + int16_t plc_lpc[LPC_FILTERORDER + 1]; + int16_t hpimemx[2]; + int16_t hpimemy[4]; +} ILBCContext; + +static int unpack_frame(ILBCContext *s) +{ + ILBCFrame *frame = &s->frame; + GetBitContext *gb = &s->gb; + int j; + + frame->lsf[0] = get_bits(gb, 6); + frame->lsf[1] = get_bits(gb, 7); + frame->lsf[2] = get_bits(gb, 7); + + if (s->mode == 20) { + frame->start = get_bits(gb, 2); + frame->state_first = get_bits1(gb); + frame->ifm = get_bits(gb, 6); + frame->cb_index[0] = get_bits(gb, 6) << 1; + frame->gain_index[0] = get_bits(gb, 2) << 3; + frame->gain_index[1] = get_bits1(gb) << 3; + frame->cb_index[3] = get_bits(gb, 7) << 1; + frame->gain_index[3] = get_bits1(gb) << 4; + frame->gain_index[4] = get_bits1(gb) << 3; + frame->gain_index[6] = get_bits1(gb) << 4; + } else { + frame->lsf[3] = get_bits(gb, 6); + frame->lsf[4] = get_bits(gb, 7); + frame->lsf[5] = get_bits(gb, 7); + frame->start = get_bits(gb, 3); + frame->state_first = get_bits1(gb); + frame->ifm = get_bits(gb, 6); + frame->cb_index[0] = get_bits(gb, 4) << 3; + frame->gain_index[0] = get_bits1(gb) << 4; + frame->gain_index[1] = get_bits1(gb) << 3; + frame->cb_index[3] = get_bits(gb, 6) << 2; + frame->gain_index[3] = get_bits1(gb) << 4; + frame->gain_index[4] = get_bits1(gb) << 3; + } + + for (j = 0; j < 48; j++) + frame->idx[j] = get_bits1(gb) << 2; + + if (s->mode == 20) { + for (; j < 57; j++) + frame->idx[j] = get_bits1(gb) << 2; + + frame->gain_index[1] |= get_bits1(gb) << 2; + frame->gain_index[3] |= get_bits(gb, 2) << 2; + frame->gain_index[4] |= get_bits1(gb) << 2; + frame->gain_index[6] |= get_bits1(gb) << 3; + frame->gain_index[7] = get_bits(gb, 2) << 2; + } else { + for (; j < 58; j++) + frame->idx[j] = get_bits1(gb) << 2; + + frame->cb_index[0] |= get_bits(gb, 2) << 1; + frame->gain_index[0] |= get_bits1(gb) << 3; + frame->gain_index[1] |= get_bits1(gb) << 2; + frame->cb_index[3] |= get_bits1(gb) << 1; + frame->cb_index[6] = get_bits1(gb) << 7; + frame->cb_index[6] |= get_bits(gb, 6) << 1; + frame->cb_index[9] = get_bits(gb, 7) << 1; + frame->cb_index[12] = get_bits(gb, 3) << 5; + frame->cb_index[12] |= get_bits(gb, 4) << 1; + frame->gain_index[3] |= get_bits(gb, 2) << 2; + frame->gain_index[4] |= get_bits(gb, 2) << 1; + frame->gain_index[6] = get_bits(gb, 2) << 3; + frame->gain_index[7] = get_bits(gb, 2) << 2; + frame->gain_index[9] = get_bits1(gb) << 4; + frame->gain_index[10] = get_bits1(gb) << 3; + frame->gain_index[12] = get_bits1(gb) << 4; + frame->gain_index[13] = get_bits1(gb) << 3; + } + + for (j = 0; j < 56; j++) + frame->idx[j] |= get_bits(gb, 2); + + if (s->mode == 20) { + frame->idx[56] |= get_bits(gb, 2); + frame->cb_index[0] |= get_bits1(gb); + frame->cb_index[1] = get_bits(gb, 7); + frame->cb_index[2] = get_bits(gb, 6) << 1; + frame->cb_index[2] |= get_bits1(gb); + frame->gain_index[0] |= get_bits(gb, 3); + frame->gain_index[1] |= get_bits(gb, 2); + frame->gain_index[2] = get_bits(gb, 3); + frame->cb_index[3] |= get_bits1(gb); + frame->cb_index[4] = get_bits(gb, 6) << 1; + frame->cb_index[4] |= get_bits1(gb); + frame->cb_index[5] = get_bits(gb, 7); + frame->cb_index[6] = get_bits(gb, 8); + frame->cb_index[7] = get_bits(gb, 8); + frame->cb_index[8] = get_bits(gb, 8); + frame->gain_index[3] |= get_bits(gb, 2); + frame->gain_index[4] |= get_bits(gb, 2); + frame->gain_index[5] = get_bits(gb, 3); + frame->gain_index[6] |= get_bits(gb, 3); + frame->gain_index[7] |= get_bits(gb, 2); + frame->gain_index[8] = get_bits(gb, 3); + } else { + frame->idx[56] |= get_bits(gb, 2); + frame->idx[57] |= get_bits(gb, 2); + frame->cb_index[0] |= get_bits1(gb); + frame->cb_index[1] = get_bits(gb, 7); + frame->cb_index[2] = get_bits(gb, 4) << 3; + frame->cb_index[2] |= get_bits(gb, 3); + frame->gain_index[0] |= get_bits(gb, 3); + frame->gain_index[1] |= get_bits(gb, 2); + frame->gain_index[2] = get_bits(gb, 3); + frame->cb_index[3] |= get_bits1(gb); + frame->cb_index[4] = get_bits(gb, 4) << 3; + frame->cb_index[4] |= get_bits(gb, 3); + frame->cb_index[5] = get_bits(gb, 7); + frame->cb_index[6] |= get_bits1(gb); + frame->cb_index[7] = get_bits(gb, 5) << 3; + frame->cb_index[7] |= get_bits(gb, 3); + frame->cb_index[8] = get_bits(gb, 8); + frame->cb_index[9] |= get_bits1(gb); + frame->cb_index[10] = get_bits(gb, 4) << 4; + frame->cb_index[10] |= get_bits(gb, 4); + frame->cb_index[11] = get_bits(gb, 8); + frame->cb_index[12] |= get_bits1(gb); + frame->cb_index[13] = get_bits(gb, 3) << 5; + frame->cb_index[13] |= get_bits(gb, 5); + frame->cb_index[14] = get_bits(gb, 8); + frame->gain_index[3] |= get_bits(gb, 2); + frame->gain_index[4] |= get_bits1(gb); + frame->gain_index[5] = get_bits(gb, 3); + frame->gain_index[6] |= get_bits(gb, 3); + frame->gain_index[7] |= get_bits(gb, 2); + frame->gain_index[8] = get_bits(gb, 3); + frame->gain_index[9] |= get_bits(gb, 4); + frame->gain_index[10] |= get_bits1(gb) << 2; + frame->gain_index[10] |= get_bits(gb, 2); + frame->gain_index[11] = get_bits(gb, 3); + frame->gain_index[12] |= get_bits(gb, 4); + frame->gain_index[13] |= get_bits(gb, 3); + frame->gain_index[14] = get_bits(gb, 3); + } + + return get_bits1(gb); +} + +static void index_conv(int16_t *index) +{ + int k; + + for (k = 4; k < 6; k++) { + if (index[k] >= 44 && index[k] < 108) { + index[k] += 64; + } else if (index[k] >= 108 && index[k] < 128) { + index[k] += 128; + } + } +} + +static void lsf_dequantization(int16_t *lsfdeq, int16_t *index, int16_t lpc_n) +{ + int i, j, pos = 0, cb_pos = 0; + + for (i = 0; i < LSF_NSPLIT; i++) { + for (j = 0; j < lsf_dim_codebook[i]; j++) { + lsfdeq[pos + j] = lsf_codebook[cb_pos + index[i] * lsf_dim_codebook[i] + j]; + } + + pos += lsf_dim_codebook[i]; + cb_pos += lsf_size_codebook[i] * lsf_dim_codebook[i]; + } + + if (lpc_n > 1) { + pos = 0; + cb_pos = 0; + for (i = 0; i < LSF_NSPLIT; i++) { + for (j = 0; j < lsf_dim_codebook[i]; j++) { + lsfdeq[LPC_FILTERORDER + pos + j] = lsf_codebook[cb_pos + + index[LSF_NSPLIT + i] * lsf_dim_codebook[i] + j]; + } + + pos += lsf_dim_codebook[i]; + cb_pos += lsf_size_codebook[i] * lsf_dim_codebook[i]; + } + } +} + +static void lsf_check_stability(int16_t *lsf, int dim, int nb_vectors) +{ + for (int n = 0; n < 2; n++) { + for (int m = 0; m < nb_vectors; m++) { + for (int k = 0; k < dim - 1; k++) { + int i = m * dim + k; + + if ((lsf[i + 1] - lsf[i]) < 319) { + if (lsf[i + 1] < lsf[i]) { + lsf[i + 1] = lsf[i] + 160; + lsf[i] = lsf[i + 1] - 160; + } else { + lsf[i] -= 160; + lsf[i + 1] += 160; + } + } + + lsf[i] = av_clip(lsf[i], 82, 25723); + } + } + } +} + +static void lsf_interpolate(int16_t *out, int16_t *in1, + int16_t *in2, int16_t coef, + int size) +{ + int invcoef = 16384 - coef, i; + + for (i = 0; i < size; i++) + out[i] = (coef * in1[i] + invcoef * in2[i] + 8192) >> 14; +} + +static void lsf2lsp(int16_t *lsf, int16_t *lsp, int order) +{ + int16_t diff, freq; + int32_t tmp; + int i, k; + + for (i = 0; i < order; i++) { + freq = (lsf[i] * 20861) >> 15; + /* 20861: 1.0/(2.0*PI) in Q17 */ + /* + Upper 8 bits give the index k and + Lower 8 bits give the difference, which needs + to be approximated linearly + */ + k = FFMIN(freq >> 8, 63); + diff = freq & 0xFF; + + /* Calculate linear approximation */ + tmp = cos_derivative_tbl[k] * diff; + lsp[i] = cos_tbl[k] + (tmp >> 12); + } +} + +static void get_lsp_poly(int16_t *lsp, int32_t *f) +{ + int16_t high, low; + int i, j, k, l; + int32_t tmp; + + f[0] = 16777216; + f[1] = lsp[0] * -1024; + + for (i = 2, k = 2, l = 2; i <= 5; i++, k += 2) { + f[l] = f[l - 2]; + + for (j = i; j > 1; j--, l--) { + high = f[l - 1] >> 16; + low = (f[l - 1] - (high * (1 << 16))) >> 1; + + tmp = ((high * lsp[k]) * 4) + (((low * lsp[k]) >> 15) * 4); + + f[l] += f[l - 2]; + f[l] -= (unsigned)tmp; + } + + f[l] -= lsp[k] * (1 << 10); + l += i; + } +} + +static void lsf2poly(int16_t *a, int16_t *lsf) +{ + int32_t f[2][6]; + int16_t lsp[10]; + int32_t tmp; + int i; + + lsf2lsp(lsf, lsp, LPC_FILTERORDER); + + get_lsp_poly(&lsp[0], f[0]); + get_lsp_poly(&lsp[1], f[1]); + + for (i = 5; i > 0; i--) { + f[0][i] += (unsigned)f[0][i - 1]; + f[1][i] -= (unsigned)f[1][i - 1]; + } + + a[0] = 4096; + for (i = 5; i > 0; i--) { + tmp = f[0][6 - i] + (unsigned)f[1][6 - i] + 4096; + a[6 - i] = tmp >> 13; + + tmp = f[0][6 - i] - (unsigned)f[1][6 - i] + 4096; + a[5 + i] = tmp >> 13; + } +} + +static void lsp_interpolate2polydec(int16_t *a, int16_t *lsf1, + int16_t *lsf2, int coef, int length) +{ + int16_t lsftmp[LPC_FILTERORDER]; + + lsf_interpolate(lsftmp, lsf1, lsf2, coef, length); + lsf2poly(a, lsftmp); +} + +static void bw_expand(int16_t *out, const int16_t *in, const int16_t *coef, int length) +{ + int i; + + out[0] = in[0]; + for (i = 1; i < length; i++) + out[i] = (coef[i] * in[i] + 16384) >> 15; +} + +static void lsp_interpolate(int16_t *syntdenum, int16_t *weightdenum, + int16_t *lsfdeq, int16_t length, + ILBCContext *s) +{ + int16_t lp[LPC_FILTERORDER + 1], *lsfdeq2; + int i, pos, lp_length; + + lsfdeq2 = lsfdeq + length; + lp_length = length + 1; + + if (s->mode == 30) { + lsp_interpolate2polydec(lp, (*s).lsfdeqold, lsfdeq, lsf_weight_30ms[0], length); + memcpy(syntdenum, lp, lp_length * 2); + bw_expand(weightdenum, lp, kLpcChirpSyntDenum, lp_length); + + pos = lp_length; + for (i = 1; i < 6; i++) { + lsp_interpolate2polydec(lp, lsfdeq, lsfdeq2, + lsf_weight_30ms[i], + length); + memcpy(syntdenum + pos, lp, lp_length * 2); + bw_expand(weightdenum + pos, lp, kLpcChirpSyntDenum, lp_length); + pos += lp_length; + } + } else { + pos = 0; + for (i = 0; i < s->nsub; i++) { + lsp_interpolate2polydec(lp, s->lsfdeqold, lsfdeq, + lsf_weight_20ms[i], length); + memcpy(syntdenum + pos, lp, lp_length * 2); + bw_expand(weightdenum + pos, lp, kLpcChirpSyntDenum, lp_length); + pos += lp_length; + } + } + + if (s->mode == 30) { + memcpy(s->lsfdeqold, lsfdeq2, length * 2); + } else { + memcpy(s->lsfdeqold, lsfdeq, length * 2); + } +} + +static void filter_mafq12(int16_t *in_ptr, int16_t *out_ptr, + int16_t *B, int16_t B_length, + int16_t length) +{ + int o, i, j; + + for (i = 0; i < length; i++) { + const int16_t *b_ptr = &B[0]; + const int16_t *x_ptr = &in_ptr[i]; + + o = 0; + for (j = 0; j < B_length; j++) + o += b_ptr[j] * *x_ptr--; + + o = av_clip(o, -134217728, 134215679); + + out_ptr[i] = ((o + 2048) >> 12); + } +} + +static void filter_arfq12(const int16_t *data_in, + int16_t *data_out, + const int16_t *coefficients, + int coefficients_length, + int data_length) +{ + int i, j; + + for (i = 0; i < data_length; i++) { + int output = 0, sum = 0; + + for (j = coefficients_length - 1; j > 0; j--) { + sum += (unsigned)(coefficients[j] * data_out[i - j]); + } + + output = coefficients[0] * data_in[i] - (unsigned)sum; + output = av_clip(output, -134217728, 134215679); + + data_out[i] = (output + 2048) >> 12; + } +} + +static void state_construct(int16_t ifm, int16_t *idx, + int16_t *synt_denum, int16_t *Out_fix, + int16_t len) +{ + int k; + int16_t maxVal; + int16_t *tmp1, *tmp2, *tmp3; + /* Stack based */ + int16_t numerator[1 + LPC_FILTERORDER]; + int16_t sampleValVec[2 * STATE_SHORT_LEN_30MS + LPC_FILTERORDER]; + int16_t sampleMaVec[2 * STATE_SHORT_LEN_30MS + LPC_FILTERORDER]; + int16_t *sampleVal = &sampleValVec[LPC_FILTERORDER]; + int16_t *sampleMa = &sampleMaVec[LPC_FILTERORDER]; + int16_t *sampleAr = &sampleValVec[LPC_FILTERORDER]; + + /* initialization of coefficients */ + + for (k = 0; k < LPC_FILTERORDER + 1; k++) { + numerator[k] = synt_denum[LPC_FILTERORDER - k]; + } + + /* decoding of the maximum value */ + + maxVal = frg_quant_mod[ifm]; + + /* decoding of the sample values */ + tmp1 = sampleVal; + tmp2 = &idx[len - 1]; + + if (ifm < 37) { + for (k = 0; k < len; k++) { + /*the shifting is due to the Q13 in sq4_fixQ13[i], also the adding of 2097152 (= 0.5 << 22) + maxVal is in Q8 and result is in Q(-1) */ + (*tmp1) = (int16_t) ((SPL_MUL_16_16(maxVal, ilbc_state[(*tmp2)]) + 2097152) >> 22); + tmp1++; + tmp2--; + } + } else if (ifm < 59) { + for (k = 0; k < len; k++) { + /*the shifting is due to the Q13 in sq4_fixQ13[i], also the adding of 262144 (= 0.5 << 19) + maxVal is in Q5 and result is in Q(-1) */ + (*tmp1) = (int16_t) ((SPL_MUL_16_16(maxVal, ilbc_state[(*tmp2)]) + 262144) >> 19); + tmp1++; + tmp2--; + } + } else { + for (k = 0; k < len; k++) { + /*the shifting is due to the Q13 in sq4_fixQ13[i], also the adding of 65536 (= 0.5 << 17) + maxVal is in Q3 and result is in Q(-1) */ + (*tmp1) = (int16_t) ((SPL_MUL_16_16(maxVal, ilbc_state[(*tmp2)]) + 65536) >> 17); + tmp1++; + tmp2--; + } + } + + /* Set the rest of the data to zero */ + memset(&sampleVal[len], 0, len * 2); + + /* circular convolution with all-pass filter */ + + /* Set the state to zero */ + memset(sampleValVec, 0, LPC_FILTERORDER * 2); + + /* Run MA filter + AR filter */ + filter_mafq12(sampleVal, sampleMa, numerator, LPC_FILTERORDER + 1, len + LPC_FILTERORDER); + memset(&sampleMa[len + LPC_FILTERORDER], 0, (len - LPC_FILTERORDER) * 2); + filter_arfq12(sampleMa, sampleAr, synt_denum, LPC_FILTERORDER + 1, 2 * len); + + tmp1 = &sampleAr[len - 1]; + tmp2 = &sampleAr[2 * len - 1]; + tmp3 = Out_fix; + for (k = 0; k < len; k++) { + (*tmp3) = (*tmp1) + (*tmp2); + tmp1--; + tmp2--; + tmp3++; + } +} + +static int16_t gain_dequantization(int index, int max_in, int stage) +{ + int16_t scale = FFMAX(1638, FFABS(max_in)); + + return ((scale * ilbc_gain[stage][index]) + 8192) >> 14; +} + +static void vector_rmultiplication(int16_t *out, const int16_t *in, + const int16_t *win, + int length, int shift) +{ + for (int i = 0; i < length; i++) + out[i] = (in[i] * win[-i]) >> shift; +} + +static void vector_multiplication(int16_t *out, const int16_t *in, + const int16_t *win, int length, + int shift) +{ + for (int i = 0; i < length; i++) + out[i] = (in[i] * win[i]) >> shift; +} + +static void add_vector_and_shift(int16_t *out, const int16_t *in1, + const int16_t *in2, int length, + int shift) +{ + for (int i = 0; i < length; i++) + out[i] = (in1[i] + in2[i]) >> shift; +} + +static void create_augmented_vector(int index, int16_t *buffer, int16_t *cbVec) +{ + int16_t cbVecTmp[4]; + int interpolation_length = FFMIN(4, index); + int16_t ilow = index - interpolation_length; + + memcpy(cbVec, buffer - index, index * 2); + + vector_multiplication(&cbVec[ilow], buffer - index - interpolation_length, alpha, interpolation_length, 15); + vector_rmultiplication(cbVecTmp, buffer - interpolation_length, &alpha[interpolation_length - 1], interpolation_length, 15); + add_vector_and_shift(&cbVec[ilow], &cbVec[ilow], cbVecTmp, interpolation_length, 0); + + memcpy(cbVec + index, buffer - index, FFMIN(SUBL - index, index) * sizeof(*cbVec)); +} + +static void get_codebook(int16_t * cbvec, /* (o) Constructed codebook vector */ + int16_t * mem, /* (i) Codebook buffer */ + int16_t index, /* (i) Codebook index */ + int16_t lMem, /* (i) Length of codebook buffer */ + int16_t cbveclen /* (i) Codebook vector length */ +) +{ + int16_t k, base_size; + int16_t lag; + /* Stack based */ + int16_t tempbuff2[SUBL + 5]; + + /* Determine size of codebook sections */ + base_size = lMem - cbveclen + 1; + + if (cbveclen == SUBL) { + base_size += cbveclen / 2; + } + + /* No filter -> First codebook section */ + if (index < lMem - cbveclen + 1) { + /* first non-interpolated vectors */ + + k = index + cbveclen; + /* get vector */ + memcpy(cbvec, mem + lMem - k, cbveclen * 2); + } else if (index < base_size) { + + /* Calculate lag */ + + k = (int16_t) SPL_MUL_16_16(2, (index - (lMem - cbveclen + 1))) + cbveclen; + + lag = k / 2; + + create_augmented_vector(lag, mem + lMem, cbvec); + } else { + int16_t memIndTest; + + /* first non-interpolated vectors */ + + if (index - base_size < lMem - cbveclen + 1) { + + /* Set up filter memory, stuff zeros outside memory buffer */ + + memIndTest = lMem - (index - base_size + cbveclen); + + memset(mem - CB_HALFFILTERLEN, 0, CB_HALFFILTERLEN * 2); + memset(mem + lMem, 0, CB_HALFFILTERLEN * 2); + + /* do filtering to get the codebook vector */ + + filter_mafq12(&mem[memIndTest + 4], cbvec, (int16_t *) kCbFiltersRev, CB_FILTERLEN, cbveclen); + } else { + /* interpolated vectors */ + /* Stuff zeros outside memory buffer */ + memIndTest = lMem - cbveclen - CB_FILTERLEN; + memset(mem + lMem, 0, CB_HALFFILTERLEN * 2); + + /* do filtering */ + filter_mafq12(&mem[memIndTest + 7], tempbuff2, (int16_t *) kCbFiltersRev, CB_FILTERLEN, (int16_t) (cbveclen + 5)); + + /* Calculate lag index */ + lag = (cbveclen << 1) - 20 + index - base_size - lMem - 1; + + create_augmented_vector(lag, tempbuff2 + SUBL + 5, cbvec); + } + } +} + +static void construct_vector ( + int16_t *decvector, /* (o) Decoded vector */ + int16_t *index, /* (i) Codebook indices */ + int16_t *gain_index, /* (i) Gain quantization indices */ + int16_t *mem, /* (i) Buffer for codevector construction */ + int16_t lMem, /* (i) Length of buffer */ + int16_t veclen) +{ + int16_t gain[CB_NSTAGES]; + int16_t cbvec0[SUBL]; + int16_t cbvec1[SUBL]; + int16_t cbvec2[SUBL]; + unsigned a32; + int16_t *gainPtr; + int j; + + /* gain de-quantization */ + + gain[0] = gain_dequantization(gain_index[0], 16384, 0); + gain[1] = gain_dequantization(gain_index[1], gain[0], 1); + gain[2] = gain_dequantization(gain_index[2], gain[1], 2); + + /* codebook vector construction and construction of total vector */ + + /* Stack based */ + get_codebook(cbvec0, mem, index[0], lMem, veclen); + get_codebook(cbvec1, mem, index[1], lMem, veclen); + get_codebook(cbvec2, mem, index[2], lMem, veclen); + + gainPtr = &gain[0]; + for (j = 0; j < veclen; j++) { + a32 = SPL_MUL_16_16(*gainPtr++, cbvec0[j]); + a32 += SPL_MUL_16_16(*gainPtr++, cbvec1[j]); + a32 += SPL_MUL_16_16(*gainPtr, cbvec2[j]); + gainPtr -= 2; + decvector[j] = (int)(a32 + 8192) >> 14; + } +} + +static void reverse_memcpy(int16_t *dest, int16_t *source, int length) +{ + int16_t* destPtr = dest; + int16_t* sourcePtr = source; + int j; + + for (j = 0; j < length; j++) + *destPtr-- = *sourcePtr++; +} + +static void decode_residual(ILBCContext *s, + ILBCFrame *encbits, + int16_t *decresidual, + int16_t *syntdenum) +{ + int16_t meml_gotten, Nfor, Nback, diff, start_pos; + int16_t subcount, subframe; + int16_t *reverseDecresidual = s->enh_buf; /* Reversed decoded data, used for decoding backwards in time (reuse memory in state) */ + int16_t *memVec = s->prevResidual; + int16_t *mem = &memVec[CB_HALFFILTERLEN]; /* Memory for codebook */ + + diff = STATE_LEN - s->state_short_len; + + if (encbits->state_first == 1) { + start_pos = (encbits->start - 1) * SUBL; + } else { + start_pos = (encbits->start - 1) * SUBL + diff; + } + + /* decode scalar part of start state */ + + state_construct(encbits->ifm, encbits->idx, &syntdenum[(encbits->start - 1) * (LPC_FILTERORDER + 1)], &decresidual[start_pos], s->state_short_len); + + if (encbits->state_first) { /* put adaptive part in the end */ + /* setup memory */ + memset(mem, 0, (int16_t) (CB_MEML - s->state_short_len) * 2); + memcpy(mem + CB_MEML - s->state_short_len, decresidual + start_pos, s->state_short_len * 2); + + /* construct decoded vector */ + + construct_vector(&decresidual[start_pos + s->state_short_len], encbits->cb_index, encbits->gain_index, mem + CB_MEML - ST_MEM_L_TBL, ST_MEM_L_TBL, (int16_t) diff); + + } else { /* put adaptive part in the beginning */ + /* setup memory */ + meml_gotten = s->state_short_len; + reverse_memcpy(mem + CB_MEML - 1, decresidual + start_pos, meml_gotten); + memset(mem, 0, (int16_t) (CB_MEML - meml_gotten) * 2); + + /* construct decoded vector */ + construct_vector(reverseDecresidual, encbits->cb_index, encbits->gain_index, mem + CB_MEML - ST_MEM_L_TBL, ST_MEM_L_TBL, diff); + + /* get decoded residual from reversed vector */ + reverse_memcpy(&decresidual[start_pos - 1], reverseDecresidual, diff); + } + + /* counter for predicted subframes */ + subcount = 1; + + /* forward prediction of subframes */ + Nfor = s->nsub - encbits->start - 1; + + if (Nfor > 0) { + /* setup memory */ + memset(mem, 0, (CB_MEML - STATE_LEN) * 2); + memcpy(mem + CB_MEML - STATE_LEN, decresidual + (encbits->start - 1) * SUBL, STATE_LEN * 2); + + /* loop over subframes to encode */ + for (subframe = 0; subframe < Nfor; subframe++) { + /* construct decoded vector */ + construct_vector(&decresidual[(encbits->start + 1 + subframe) * SUBL], encbits->cb_index + subcount * CB_NSTAGES, encbits->gain_index + subcount * CB_NSTAGES, mem, MEM_LF_TBL, SUBL); + + /* update memory */ + memmove(mem, mem + SUBL, (CB_MEML - SUBL) * sizeof(*mem)); + memcpy(mem + CB_MEML - SUBL, &decresidual[(encbits->start + 1 + subframe) * SUBL], SUBL * 2); + + subcount++; + } + + } + + /* backward prediction of subframes */ + Nback = encbits->start - 1; + + if (Nback > 0) { + /* setup memory */ + meml_gotten = SUBL * (s->nsub + 1 - encbits->start); + if (meml_gotten > CB_MEML) { + meml_gotten = CB_MEML; + } + + reverse_memcpy(mem + CB_MEML - 1, decresidual + (encbits->start - 1) * SUBL, meml_gotten); + memset(mem, 0, (int16_t) (CB_MEML - meml_gotten) * 2); + + /* loop over subframes to decode */ + for (subframe = 0; subframe < Nback; subframe++) { + /* construct decoded vector */ + construct_vector(&reverseDecresidual[subframe * SUBL], encbits->cb_index + subcount * CB_NSTAGES, + encbits->gain_index + subcount * CB_NSTAGES, mem, MEM_LF_TBL, SUBL); + + /* update memory */ + memmove(mem, mem + SUBL, (CB_MEML - SUBL) * sizeof(*mem)); + memcpy(mem + CB_MEML - SUBL, &reverseDecresidual[subframe * SUBL], SUBL * 2); + + subcount++; + } + + /* get decoded residual from reversed vector */ + reverse_memcpy(decresidual + SUBL * Nback - 1, reverseDecresidual, SUBL * Nback); + } +} + +static int16_t max_abs_value_w16(const int16_t* vector, int length) +{ + int i = 0, absolute = 0, maximum = 0; + + if (vector == NULL || length <= 0) { + return -1; + } + + for (i = 0; i < length; i++) { + absolute = FFABS(vector[i]); + if (absolute > maximum) + maximum = absolute; + } + + // Guard the case for abs(-32768). + return FFMIN(maximum, INT16_MAX); +} + +static int16_t get_size_in_bits(uint32_t n) +{ + int16_t bits; + + if (0xFFFF0000 & n) { + bits = 16; + } else { + bits = 0; + } + + if (0x0000FF00 & (n >> bits)) bits += 8; + if (0x000000F0 & (n >> bits)) bits += 4; + if (0x0000000C & (n >> bits)) bits += 2; + if (0x00000002 & (n >> bits)) bits += 1; + if (0x00000001 & (n >> bits)) bits += 1; + + return bits; +} + +static int32_t scale_dot_product(const int16_t *v1, const int16_t *v2, int length, int scaling) +{ + int64_t sum = 0; + + for (int i = 0; i < length; i++) + sum += (v1[i] * v2[i]) >> scaling; + + return av_clipl_int32(sum); +} + +static void correlation(int32_t *corr, int32_t *ener, int16_t *buffer, + int16_t lag, int16_t blen, int16_t srange, int16_t scale) +{ + int16_t *w16ptr; + + w16ptr = &buffer[blen - srange - lag]; + + *corr = scale_dot_product(&buffer[blen - srange], w16ptr, srange, scale); + *ener = scale_dot_product(w16ptr, w16ptr, srange, scale); + + if (*ener == 0) { + *corr = 0; + *ener = 1; + } +} + +#define SPL_SHIFT_W32(x, c) (((c) >= 0) ? ((x) << (c)) : ((x) >> (-(c)))) + +static int16_t norm_w32(int32_t a) +{ + if (a == 0) { + return 0; + } else if (a < 0) { + a = ~a; + } + + return ff_clz(a); +} + +static int32_t div_w32_w16(int32_t num, int16_t den) +{ + if (den != 0) + return num / den; + else + return 0x7FFFFFFF; +} + +static void do_plc(int16_t *plc_residual, /* (o) concealed residual */ + int16_t *plc_lpc, /* (o) concealed LP parameters */ + int16_t PLI, /* (i) packet loss indicator + 0 - no PL, 1 = PL */ + int16_t *decresidual, /* (i) decoded residual */ + int16_t *lpc, /* (i) decoded LPC (only used for no PL) */ + int16_t inlag, /* (i) pitch lag */ + ILBCContext *s) /* (i/o) decoder instance */ +{ + int16_t i, pick; + int32_t cross, ener, cross_comp, ener_comp = 0; + int32_t measure, max_measure, energy; + int16_t max, cross_square_max, cross_square; + int16_t j, lag, tmp1, tmp2, randlag; + int16_t shift1, shift2, shift3, shift_max; + int16_t scale3; + int16_t corrLen; + int32_t tmpW32, tmp2W32; + int16_t use_gain; + int16_t tot_gain; + int16_t max_perSquare; + int16_t scale1, scale2; + int16_t totscale; + int32_t nom; + int16_t denom; + int16_t pitchfact; + int16_t use_lag; + int ind; + int16_t randvec[BLOCKL_MAX]; + + /* Packet Loss */ + if (PLI == 1) { + + s->consPLICount += 1; + + /* if previous frame not lost, + determine pitch pred. gain */ + + if (s->prevPLI != 1) { + + /* Maximum 60 samples are correlated, preserve as high accuracy + as possible without getting overflow */ + max = max_abs_value_w16(s->prevResidual, s->block_samples); + scale3 = (get_size_in_bits(max) << 1) - 25; + if (scale3 < 0) { + scale3 = 0; + } + + /* Store scale for use when interpolating between the + * concealment and the received packet */ + s->prevScale = scale3; + + /* Search around the previous lag +/-3 to find the + best pitch period */ + lag = inlag - 3; + + /* Guard against getting outside the frame */ + corrLen = FFMIN(60, s->block_samples - (inlag + 3)); + + correlation(&cross, &ener, s->prevResidual, lag, s->block_samples, corrLen, scale3); + + /* Normalize and store cross^2 and the number of shifts */ + shift_max = get_size_in_bits(FFABS(cross)) - 15; + cross_square_max = (int16_t) SPL_MUL_16_16_RSFT(SPL_SHIFT_W32(cross, -shift_max), SPL_SHIFT_W32(cross, -shift_max), 15); + + for (j = inlag - 2; j <= inlag + 3; j++) { + correlation(&cross_comp, &ener_comp, s->prevResidual, j, s->block_samples, corrLen, scale3); + + /* Use the criteria (corr*corr)/energy to compare if + this lag is better or not. To avoid the division, + do a cross multiplication */ + shift1 = get_size_in_bits(FFABS(cross_comp)) - 15; + cross_square = (int16_t) SPL_MUL_16_16_RSFT(SPL_SHIFT_W32(cross_comp, -shift1), SPL_SHIFT_W32(cross_comp, -shift1), 15); + + shift2 = get_size_in_bits(ener) - 15; + measure = SPL_MUL_16_16(SPL_SHIFT_W32(ener, -shift2), cross_square); + + shift3 = get_size_in_bits(ener_comp) - 15; + max_measure = SPL_MUL_16_16(SPL_SHIFT_W32(ener_comp, -shift3), cross_square_max); + + /* Calculate shift value, so that the two measures can + be put in the same Q domain */ + if (((shift_max << 1) + shift3) > ((shift1 << 1) + shift2)) { + tmp1 = FFMIN(31, (shift_max << 1) + shift3 - (shift1 << 1) - shift2); + tmp2 = 0; + } else { + tmp1 = 0; + tmp2 = FFMIN(31, (shift1 << 1) + shift2 - (shift_max << 1) - shift3); + } + + if ((measure >> tmp1) > (max_measure >> tmp2)) { + /* New lag is better => record lag, measure and domain */ + lag = j; + cross_square_max = cross_square; + cross = cross_comp; + shift_max = shift1; + ener = ener_comp; + } + } + + /* Calculate the periodicity for the lag with the maximum correlation. + + Definition of the periodicity: + abs(corr(vec1, vec2))/(sqrt(energy(vec1))*sqrt(energy(vec2))) + + Work in the Square domain to simplify the calculations + max_perSquare is less than 1 (in Q15) + */ + tmp2W32 = scale_dot_product(&s->prevResidual[s->block_samples - corrLen], &s->prevResidual[s->block_samples - corrLen], corrLen, scale3); + + if ((tmp2W32 > 0) && (ener_comp > 0)) { + /* norm energies to int16_t, compute the product of the energies and + use the upper int16_t as the denominator */ + + scale1 = norm_w32(tmp2W32) - 16; + tmp1 = SPL_SHIFT_W32(tmp2W32, scale1); + + scale2 = norm_w32(ener) - 16; + tmp2 = SPL_SHIFT_W32(ener, scale2); + denom = SPL_MUL_16_16_RSFT(tmp1, tmp2, 16); /* denom in Q(scale1+scale2-16) */ + + /* Square the cross correlation and norm it such that max_perSquare + will be in Q15 after the division */ + + totscale = scale1 + scale2 - 1; + tmp1 = SPL_SHIFT_W32(cross, (totscale >> 1)); + tmp2 = SPL_SHIFT_W32(cross, totscale - (totscale >> 1)); + + nom = SPL_MUL_16_16(tmp1, tmp2); + max_perSquare = div_w32_w16(nom, denom); + } else { + max_perSquare = 0; + } + } else { + /* previous frame lost, use recorded lag and gain */ + lag = s->prevLag; + max_perSquare = s->per_square; + } + + /* Attenuate signal and scale down pitch pred gain if + several frames lost consecutively */ + + use_gain = 32767; /* 1.0 in Q15 */ + + if (s->consPLICount * s->block_samples > 320) { + use_gain = 29491; /* 0.9 in Q15 */ + } else if (s->consPLICount * s->block_samples > 640) { + use_gain = 22938; /* 0.7 in Q15 */ + } else if (s->consPLICount * s->block_samples > 960) { + use_gain = 16384; /* 0.5 in Q15 */ + } else if (s->consPLICount * s->block_samples > 1280) { + use_gain = 0; /* 0.0 in Q15 */ + } + + /* Compute mixing factor of picth repeatition and noise: + for max_per>0.7 set periodicity to 1.0 + 0.4 7868) { /* periodicity > 0.7 (0.7^4=0.2401 in Q15) */ + pitchfact = 32767; + } else if (max_perSquare > 839) { /* 0.4 < periodicity < 0.7 (0.4^4=0.0256 in Q15) */ + /* find best index and interpolate from that */ + ind = 5; + while ((max_perSquare < kPlcPerSqr[ind]) && (ind > 0)) { + ind--; + } + /* pitch fact is approximated by first order */ + tmpW32 = kPlcPitchFact[ind] + SPL_MUL_16_16_RSFT(kPlcPfSlope[ind], (max_perSquare - kPlcPerSqr[ind]), 11); + + pitchfact = FFMIN(tmpW32, 32767); /* guard against overflow */ + + } else { /* periodicity < 0.4 */ + pitchfact = 0; + } + + /* avoid repetition of same pitch cycle (buzzyness) */ + use_lag = lag; + if (lag < 80) { + use_lag = 2 * lag; + } + + /* compute concealed residual */ + energy = 0; + + for (i = 0; i < s->block_samples; i++) { + /* noise component - 52 < randlagFIX < 117 */ + s->seed = SPL_MUL_16_16(s->seed, 31821) + 13849; + randlag = 53 + (s->seed & 63); + + pick = i - randlag; + + if (pick < 0) { + randvec[i] = s->prevResidual[s->block_samples + pick]; + } else { + randvec[i] = s->prevResidual[pick]; + } + + /* pitch repeatition component */ + pick = i - use_lag; + + if (pick < 0) { + plc_residual[i] = s->prevResidual[s->block_samples + pick]; + } else { + plc_residual[i] = plc_residual[pick]; + } + + /* Attinuate total gain for each 10 ms */ + if (i < 80) { + tot_gain = use_gain; + } else if (i < 160) { + tot_gain = SPL_MUL_16_16_RSFT(31130, use_gain, 15); /* 0.95*use_gain */ + } else { + tot_gain = SPL_MUL_16_16_RSFT(29491, use_gain, 15); /* 0.9*use_gain */ + } + + /* mix noise and pitch repeatition */ + plc_residual[i] = SPL_MUL_16_16_RSFT(tot_gain, (pitchfact * plc_residual[i] + (32767 - pitchfact) * randvec[i] + 16384) >> 15, 15); + + /* Shifting down the result one step extra to ensure that no overflow + will occur */ + energy += SPL_MUL_16_16_RSFT(plc_residual[i], plc_residual[i], (s->prevScale + 1)); + + } + + /* less than 30 dB, use only noise */ + if (energy < SPL_SHIFT_W32(s->block_samples * 900, -s->prevScale - 1)) { + energy = 0; + for (i = 0; i < s->block_samples; i++) { + plc_residual[i] = randvec[i]; + } + } + + /* use the old LPC */ + memcpy(plc_lpc, (*s).prev_lpc, (LPC_FILTERORDER + 1) * 2); + + /* Update state in case there are multiple frame losses */ + s->prevLag = lag; + s->per_square = max_perSquare; + } else { /* no packet loss, copy input */ + memcpy(plc_residual, decresidual, s->block_samples * 2); + memcpy(plc_lpc, lpc, (LPC_FILTERORDER + 1) * 2); + s->consPLICount = 0; + } + + /* update state */ + s->prevPLI = PLI; + memcpy(s->prev_lpc, plc_lpc, (LPC_FILTERORDER + 1) * 2); + memcpy(s->prevResidual, plc_residual, s->block_samples * 2); + + return; +} + +static int xcorr_coeff(int16_t *target, int16_t *regressor, + int16_t subl, int16_t searchLen, + int16_t offset, int16_t step) +{ + int16_t maxlag; + int16_t pos; + int16_t max; + int16_t cross_corr_scale, energy_scale; + int16_t cross_corr_sg_mod, cross_corr_sg_mod_max; + int32_t cross_corr, energy; + int16_t cross_corr_mod, energy_mod, enery_mod_max; + int16_t *tp, *rp; + int16_t *rp_beg, *rp_end; + int16_t totscale, totscale_max; + int16_t scalediff; + int32_t new_crit, max_crit; + int shifts; + int k; + + /* Initializations, to make sure that the first one is selected */ + cross_corr_sg_mod_max = 0; + enery_mod_max = INT16_MAX; + totscale_max = -500; + maxlag = 0; + pos = 0; + + /* Find scale value and start position */ + if (step == 1) { + max = max_abs_value_w16(regressor, (int16_t) (subl + searchLen - 1)); + rp_beg = regressor; + rp_end = ®ressor[subl]; + } else { /* step== -1 */ + max = max_abs_value_w16(®ressor[-searchLen], (int16_t) (subl + searchLen - 1)); + rp_beg = ®ressor[-1]; + rp_end = ®ressor[subl - 1]; + } + + /* Introduce a scale factor on the energy in int32_t in + order to make sure that the calculation does not + overflow */ + + if (max > 5000) { + shifts = 2; + } else { + shifts = 0; + } + + /* Calculate the first energy, then do a +/- to get the other energies */ + energy = scale_dot_product(regressor, regressor, subl, shifts); + + for (k = 0; k < searchLen; k++) { + tp = target; + rp = ®ressor[pos]; + + cross_corr = scale_dot_product(tp, rp, subl, shifts); + + if ((energy > 0) && (cross_corr > 0)) { + /* Put cross correlation and energy on 16 bit word */ + cross_corr_scale = norm_w32(cross_corr) - 16; + cross_corr_mod = (int16_t) SPL_SHIFT_W32(cross_corr, cross_corr_scale); + energy_scale = norm_w32(energy) - 16; + energy_mod = (int16_t) SPL_SHIFT_W32(energy, energy_scale); + + /* Square cross correlation and store upper int16_t */ + cross_corr_sg_mod = (int16_t) SPL_MUL_16_16_RSFT(cross_corr_mod, cross_corr_mod, 16); + + /* Calculate the total number of (dynamic) right shifts that have + been performed on (cross_corr*cross_corr)/energy + */ + totscale = energy_scale - (cross_corr_scale * 2); + + /* Calculate the shift difference in order to be able to compare the two + (cross_corr*cross_corr)/energy in the same domain + */ + scalediff = totscale - totscale_max; + scalediff = FFMIN(scalediff, 31); + scalediff = FFMAX(scalediff, -31); + + /* Compute the cross multiplication between the old best criteria + and the new one to be able to compare them without using a + division */ + + if (scalediff < 0) { + new_crit = ((int32_t) cross_corr_sg_mod * enery_mod_max) >> (-scalediff); + max_crit = ((int32_t) cross_corr_sg_mod_max * energy_mod); + } else { + new_crit = ((int32_t) cross_corr_sg_mod * enery_mod_max); + max_crit = ((int32_t) cross_corr_sg_mod_max * energy_mod) >> scalediff; + } + + /* Store the new lag value if the new criteria is larger + than previous largest criteria */ + + if (new_crit > max_crit) { + cross_corr_sg_mod_max = cross_corr_sg_mod; + enery_mod_max = energy_mod; + totscale_max = totscale; + maxlag = k; + } + } + pos += step; + + /* Do a +/- to get the next energy */ + energy += (unsigned)step * ((*rp_end * *rp_end - *rp_beg * *rp_beg) >> shifts); + + rp_beg += step; + rp_end += step; + } + + return maxlag + offset; +} + +static void hp_output(int16_t *signal, const int16_t *ba, int16_t *y, + int16_t *x, int16_t len) +{ + int32_t tmp; + + for (int i = 0; i < len; i++) { + tmp = SPL_MUL_16_16(y[1], ba[3]); /* (-a[1])*y[i-1] (low part) */ + tmp += SPL_MUL_16_16(y[3], ba[4]); /* (-a[2])*y[i-2] (low part) */ + tmp = (tmp >> 15); + tmp += SPL_MUL_16_16(y[0], ba[3]); /* (-a[1])*y[i-1] (high part) */ + tmp += SPL_MUL_16_16(y[2], ba[4]); /* (-a[2])*y[i-2] (high part) */ + tmp = (tmp * 2); + + tmp += SPL_MUL_16_16(signal[i], ba[0]); /* b[0]*x[0] */ + tmp += SPL_MUL_16_16(x[0], ba[1]); /* b[1]*x[i-1] */ + tmp += SPL_MUL_16_16(x[1], ba[2]); /* b[2]*x[i-2] */ + + /* Update state (input part) */ + x[1] = x[0]; + x[0] = signal[i]; + + /* Convert back to Q0 and multiply with 2 */ + signal[i] = av_clip_intp2(tmp + 1024, 26) >> 11; + + /* Update state (filtered part) */ + y[2] = y[0]; + y[3] = y[1]; + + /* upshift tmp by 3 with saturation */ + if (tmp > 268435455) { + tmp = INT32_MAX; + } else if (tmp < -268435456) { + tmp = INT32_MIN; + } else { + tmp = tmp * 8; + } + + y[0] = tmp >> 16; + y[1] = (tmp - (y[0] * (1 << 16))) >> 1; + } +} + +static int ilbc_decode_frame(AVCodecContext *avctx, void *data, + int *got_frame_ptr, AVPacket *avpkt) +{ + const uint8_t *buf = avpkt->data; + AVFrame *frame = data; + ILBCContext *s = avctx->priv_data; + int mode = s->mode, ret; + int16_t *plc_data = &s->plc_residual[LPC_FILTERORDER]; + + if ((ret = init_get_bits8(&s->gb, buf, avpkt->size)) < 0) + return ret; + memset(&s->frame, 0, sizeof(ILBCFrame)); + + frame->nb_samples = s->block_samples; + if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) + return ret; + + if (unpack_frame(s)) + mode = 0; + if (s->frame.start < 1 || s->frame.start > 5) + mode = 0; + + if (mode) { + index_conv(s->frame.cb_index); + + lsf_dequantization(s->lsfdeq, s->frame.lsf, s->lpc_n); + lsf_check_stability(s->lsfdeq, LPC_FILTERORDER, s->lpc_n); + lsp_interpolate(s->syntdenum, s->weightdenum, + s->lsfdeq, LPC_FILTERORDER, s); + decode_residual(s, &s->frame, s->decresidual, s->syntdenum); + + do_plc(s->plc_residual, s->plc_lpc, 0, + s->decresidual, s->syntdenum + (LPC_FILTERORDER + 1) * (s->nsub - 1), + s->last_lag, s); + + memcpy(s->decresidual, s->plc_residual, s->block_samples * 2); + } + + if (s->enhancer) { + /* TODO */ + } else { + int16_t lag, i; + + /* Find last lag (since the enhancer is not called to give this info) */ + if (s->mode == 20) { + lag = xcorr_coeff(&s->decresidual[s->block_samples-60], &s->decresidual[s->block_samples-80], + 60, 80, 20, -1); + } else { + lag = xcorr_coeff(&s->decresidual[s->block_samples-ENH_BLOCKL], + &s->decresidual[s->block_samples-ENH_BLOCKL-20], + ENH_BLOCKL, 100, 20, -1); + } + + /* Store lag (it is needed if next packet is lost) */ + s->last_lag = lag; + + /* copy data and run synthesis filter */ + memcpy(plc_data, s->decresidual, s->block_samples * 2); + + /* Set up the filter state */ + memcpy(&plc_data[-LPC_FILTERORDER], s->syntMem, LPC_FILTERORDER * 2); + + for (i = 0; i < s->nsub; i++) { + filter_arfq12(plc_data+i*SUBL, plc_data+i*SUBL, + s->syntdenum + i*(LPC_FILTERORDER + 1), + LPC_FILTERORDER + 1, SUBL); + } + + /* Save the filter state */ + memcpy(s->syntMem, &plc_data[s->block_samples-LPC_FILTERORDER], LPC_FILTERORDER * 2); + } + + memcpy(frame->data[0], plc_data, s->block_samples * 2); + + hp_output((int16_t *)frame->data[0], hp_out_coeffs, + s->hpimemy, s->hpimemx, s->block_samples); + + memcpy(s->old_syntdenum, s->syntdenum, s->nsub*(LPC_FILTERORDER + 1) * 2); + + s->prev_enh_pl = 0; + if (mode == 0) + s->prev_enh_pl = 1; + + *got_frame_ptr = 1; + + return avpkt->size; +} + +static av_cold int ilbc_decode_init(AVCodecContext *avctx) +{ + ILBCContext *s = avctx->priv_data; + + if (avctx->block_align == 38) + s->mode = 20; + else if (avctx->block_align == 50) + s->mode = 30; + else if (avctx->bit_rate > 0) + s->mode = avctx->bit_rate <= 14000 ? 30 : 20; + else + return AVERROR_INVALIDDATA; + + avctx->channels = 1; + avctx->channel_layout = AV_CH_LAYOUT_MONO; + avctx->sample_rate = 8000; + avctx->sample_fmt = AV_SAMPLE_FMT_S16; + + if (s->mode == 30) { + s->block_samples = 240; + s->nsub = NSUB_30MS; + s->nasub = NASUB_30MS; + s->lpc_n = LPC_N_30MS; + s->state_short_len = STATE_SHORT_LEN_30MS; + } else { + s->block_samples = 160; + s->nsub = NSUB_20MS; + s->nasub = NASUB_20MS; + s->lpc_n = LPC_N_20MS; + s->state_short_len = STATE_SHORT_LEN_20MS; + } + + return 0; +} + +AVCodec ff_ilbc_decoder = { + .name = "ilbc", + .long_name = NULL_IF_CONFIG_SMALL("iLBC (Internet Low Bitrate Codec)"), + .type = AVMEDIA_TYPE_AUDIO, + .id = AV_CODEC_ID_ILBC, + .init = ilbc_decode_init, + .decode = ilbc_decode_frame, + .capabilities = AV_CODEC_CAP_DR1, + .priv_data_size = sizeof(ILBCContext), +}; diff --git a/libavcodec/imc.c b/libavcodec/imc.c index 7cd6db930..82a908160 100644 --- a/libavcodec/imc.c +++ b/libavcodec/imc.c @@ -104,6 +104,8 @@ typedef struct IMCContext { int8_t cyclTab[32], cyclTab2[32]; float weights1[31], weights2[31]; + + AVCodecContext *avctx; } IMCContext; static VLC huffman_vlc[4][4]; @@ -466,7 +468,7 @@ static int bit_allocation(IMCContext *q, IMCChannel *chctx, for (i = 0; i < BANDS - 1; i++) { if (chctx->flcoeffs5[i] <= 0) { - av_log(NULL, AV_LOG_ERROR, "flcoeffs5 %f invalid\n", chctx->flcoeffs5[i]); + av_log(q->avctx, AV_LOG_ERROR, "flcoeffs5 %f invalid\n", chctx->flcoeffs5[i]); return AVERROR_INVALIDDATA; } chctx->flcoeffs4[i] = chctx->flcoeffs3[i] - log2f(chctx->flcoeffs5[i]); @@ -1022,6 +1024,8 @@ static int imc_decode_frame(AVCodecContext *avctx, void *data, LOCAL_ALIGNED_16(uint16_t, buf16, [(IMC_BLOCK_SIZE + AV_INPUT_BUFFER_PADDING_SIZE) / 2]); + q->avctx = avctx; + if (buf_size < IMC_BLOCK_SIZE * avctx->channels) { av_log(avctx, AV_LOG_ERROR, "frame too small!\n"); return AVERROR_INVALIDDATA; diff --git a/libavcodec/imm4.c b/libavcodec/imm4.c new file mode 100644 index 000000000..d92bc30dd --- /dev/null +++ b/libavcodec/imm4.c @@ -0,0 +1,557 @@ +/* + * Infinity IMM4 decoder + * + * Copyright (c) 2018 Paul B Mahol + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include + +#include "libavutil/thread.h" + +#include "avcodec.h" +#include "bswapdsp.h" +#include "copy_block.h" +#include "get_bits.h" +#include "idctdsp.h" +#include "internal.h" + +typedef struct IMM4Context { + BswapDSPContext bdsp; + GetBitContext gb; + + AVFrame *prev_frame; + uint8_t *bitstream; + int bitstream_size; + + int factor; + unsigned lo; + unsigned hi; + + ScanTable intra_scantable; + DECLARE_ALIGNED(32, int16_t, block)[6][64]; + IDCTDSPContext idsp; +} IMM4Context; + +static const uint8_t intra_cb[] = { + 24, 18, 12 +}; + +static const uint8_t inter_cb[] = { + 30, 20, 15 +}; + +static const uint8_t cbplo_symbols[] = { + 3, 4, 19, 20, 35, 36, 51, 52 +}; + +static const uint8_t cbplo_bits[] = { + 1, 4, 3, 6, 3, 6, 3, 6 +}; + +static const uint8_t cbplo_codes[] = { + 1, 1, 1, 1, 2, 2, 3, 3 +}; + +static const uint8_t cbphi_bits[] = { + 4, 5, 5, 4, 5, 4, 6, 4, 5, 6, 4, 4, 4, 4, 4, 2 +}; + +static const uint8_t cbphi_codes[] = { + 3, 5, 4, 9, 3, 7, 2, 11, 2, 3, 5, 10, 4, 8, 6, 3 +}; + +static const uint8_t blktype_symbols[] = { + 0, 1, 2, 3, 4, 16, 17, 18, 19, 20, 32, 33, 34, 35, 48, 50, 51, 52 +}; + +static const uint8_t blktype_bits[] = { + 1, 3, 3, 5, 6, 4, 7, 7, 8, 9, 4, 7, 7, 8, 6, 8, 7, 9 +}; + +static const uint8_t blktype_codes[] = { + 1, 3, 2, 3, 4, 3, 7, 5, 4, 4, 2, 6, 4, 3, 5, 5, 3, 2 +}; + +static const uint16_t block_symbols[] = { + 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0x81, 0x82, 0x83, + 0x84, 0x85, 0x86, 0x101, 0x102, 0x103, 0x104, 0x181, 0x182, 0x183, 0x201, 0x202, + 0x203, 0x281, 0x282, 0x283, 0x301, 0x302, 0x303, 0x381, 0x382, 0x401, 0x402, + 0x481, 0x482, 0x501, 0x502, 0x581, 0x601, 0x681, 0x701, 0x781, 0x801, 0x881, + 0x901, 0x981, 0xA01, 0xA81, 0xB01, 0xB81, 0xC01, 0xC81, 0xD01, 0x4001, 0x4002, + 0x4003, 0x4081, 0x4082, 0x4101, 0x4181, 0x4201, 0x4281, 0x4301, 0x4381, 0x4401, + 0x4481, 0x4501, 0x4581, 0x4601, 0x4681, 0x4701, 0x4781, 0x4801, 0x4881, 0x4901, + 0x4981, 0x4A01, 0x4A81, 0x4B01, 0x4B81, 0x4C01, 0x4C81, 0x4D01, 0x4D81, 0x4E01, + 0x4E81, 0x4F01, 0x4F81, 0x5001, 0x5081, 0x5101, 0x5181, 0x5201, 0x5281, 0x5301, + 0x5381, 0x5401 +}; + +static const uint8_t block_bits[] = { + 7, 2, 4, 6, 7, 8, 9, 9, 10, 10, 11, 11, 11, 3, 6, 8, 10, 11, 12, 4, 8, + 10, 12, 5, 9, 10, 5, 9, 12, 5, 10, 12, 6, 10, 12, 6, 10, 6, 10, 6, + 10, 7, 12, 7, 7, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 11, 11, 12, 12, 4, 9, + 11, 6, 11, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, + 9, 9, 9, 9, 10, 10, 10, 10, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, + 12, 12 +}; + +static const uint8_t block_codes[] = { + 3, 2, 15, 21, 23, 31, 37, 36, 33, 32, 7, 6, 32, 6, 20, 30, 15, 33, 80, + 14, 29, 14, 81, 13, 35, 13, 12, 34, 82, 11, 12, 83, 19, 11, 84, 18, + 10, 17, 9, 16, 8, 22, 85, 21, 20, 28, 27, 33, 32, 31, 30, 29, 28, + 27, 26, 34, 35, 86, 87, 7, 25, 5, 15, 4, 14, 13, 12, 19, 18, 17, 16, + 26, 25, 24, 23, 22, 21, 20, 19, 24, 23, 22, 21, 20, 19, 18, 17, 7, + 6, 5, 4, 36, 37, 38, 39, 88, 89, 90, 91, 92, 93, 94, 95 +}; + +static VLC cbplo_tab; +static VLC cbphi_tab; +static VLC blktype_tab; +static VLC block_tab; + +static int get_cbphi(GetBitContext *gb, int x) +{ + int value; + + value = get_vlc2(gb, cbphi_tab.table, cbphi_tab.bits, 1); + if (value < 0) + return AVERROR_INVALIDDATA; + + return x ? value : 15 - value; +} + +static int decode_block(AVCodecContext *avctx, GetBitContext *gb, + int block, int factor, int flag, int offset, int flag2) +{ + IMM4Context *s = avctx->priv_data; + const uint8_t *scantable = s->intra_scantable.permutated; + int i, last, len, factor2; + + for (i = !flag; i < 64; i++) { + int value; + + value = get_vlc2(gb, block_tab.table, block_tab.bits, 1); + if (value < 0) + return AVERROR_INVALIDDATA; + if (value == 0) { + last = get_bits1(gb); + len = get_bits(gb, 6); + factor2 = get_sbits(gb, 8); + } else { + factor2 = value & 0x7F; + last = (value >> 14) & 1; + len = (value >> 7) & 0x3F; + if (get_bits1(gb)) + factor2 = -factor2; + } + i += len; + if (i >= 64) + break; + s->block[block][scantable[i]] = offset * (factor2 < 0 ? -1 : 1) + factor * factor2; + if (last) + break; + } + + if (s->hi == 2 && flag2 && block < 4) { + if (flag) + s->block[block][scantable[0]] *= 2; + s->block[block][scantable[1]] *= 2; + s->block[block][scantable[8]] *= 2; + s->block[block][scantable[16]] *= 2; + } + + return 0; +} + +static int decode_blocks(AVCodecContext *avctx, GetBitContext *gb, + unsigned cbp, int flag, int offset, unsigned flag2) +{ + IMM4Context *s = avctx->priv_data; + const uint8_t *scantable = s->intra_scantable.permutated; + int ret, i; + + memset(s->block, 0, sizeof(s->block)); + + for (i = 0; i < 6; i++) { + if (!flag) { + int x = get_bits(gb, 8); + + if (x == 255) + x = 128; + x *= 8; + + s->block[i][scantable[0]] = x; + } + + if (cbp & (1 << (5 - i))) { + ret = decode_block(avctx, gb, i, s->factor, flag, offset, flag2); + if (ret < 0) + return ret; + } + } + + return 0; +} + +static int decode_intra(AVCodecContext *avctx, GetBitContext *gb, AVFrame *frame) +{ + IMM4Context *s = avctx->priv_data; + int ret, x, y, offset = 0; + + if (s->hi == 0) { + if (s->lo > 2) + return AVERROR_INVALIDDATA; + s->factor = intra_cb[s->lo]; + } else { + s->factor = s->lo * 2; + } + + if (s->hi) { + offset = s->factor; + offset >>= 1; + if (!(offset & 1)) + offset--; + } + + for (y = 0; y < avctx->height; y += 16) { + for (x = 0; x < avctx->width; x += 16) { + unsigned flag, cbphi, cbplo; + + cbplo = get_vlc2(gb, cbplo_tab.table, cbplo_tab.bits, 1) >> 4; + flag = get_bits1(gb); + + cbphi = get_cbphi(gb, 1); + + ret = decode_blocks(avctx, gb, cbplo | (cbphi << 2), 0, offset, flag); + if (ret < 0) + return ret; + + s->idsp.idct_put(frame->data[0] + y * frame->linesize[0] + x, + frame->linesize[0], s->block[0]); + s->idsp.idct_put(frame->data[0] + y * frame->linesize[0] + x + 8, + frame->linesize[0], s->block[1]); + s->idsp.idct_put(frame->data[0] + (y + 8) * frame->linesize[0] + x, + frame->linesize[0], s->block[2]); + s->idsp.idct_put(frame->data[0] + (y + 8) * frame->linesize[0] + x + 8, + frame->linesize[0], s->block[3]); + s->idsp.idct_put(frame->data[1] + (y >> 1) * frame->linesize[1] + (x >> 1), + frame->linesize[1], s->block[4]); + s->idsp.idct_put(frame->data[2] + (y >> 1) * frame->linesize[2] + (x >> 1), + frame->linesize[2], s->block[5]); + } + } + + return 0; +} + +static int decode_inter(AVCodecContext *avctx, GetBitContext *gb, + AVFrame *frame, AVFrame *prev) +{ + IMM4Context *s = avctx->priv_data; + int ret, x, y, offset = 0; + + if (s->hi == 0) { + if (s->lo > 2) + return AVERROR_INVALIDDATA; + s->factor = inter_cb[s->lo]; + } else { + s->factor = s->lo * 2; + } + + if (s->hi) { + offset = s->factor; + offset >>= 1; + if (!(offset & 1)) + offset--; + } + + for (y = 0; y < avctx->height; y += 16) { + for (x = 0; x < avctx->width; x += 16) { + int reverse, intra_block, value; + unsigned cbphi, cbplo, flag2 = 0; + + if (get_bits1(gb)) { + copy_block16(frame->data[0] + y * frame->linesize[0] + x, + prev->data[0] + y * prev->linesize[0] + x, + frame->linesize[0], prev->linesize[0], 16); + copy_block8(frame->data[1] + (y >> 1) * frame->linesize[1] + (x >> 1), + prev->data[1] + (y >> 1) * prev->linesize[1] + (x >> 1), + frame->linesize[1], prev->linesize[1], 8); + copy_block8(frame->data[2] + (y >> 1) * frame->linesize[2] + (x >> 1), + prev->data[2] + (y >> 1) * prev->linesize[2] + (x >> 1), + frame->linesize[2], prev->linesize[2], 8); + continue; + } + + value = get_vlc2(gb, blktype_tab.table, blktype_tab.bits, 1); + if (value < 0) + return AVERROR_INVALIDDATA; + + intra_block = value & 0x07; + reverse = intra_block == 3; + if (reverse) + flag2 = get_bits1(gb); + + cbplo = value >> 4; + cbphi = get_cbphi(gb, reverse); + if (intra_block) { + ret = decode_blocks(avctx, gb, cbplo | (cbphi << 2), 0, offset, flag2); + if (ret < 0) + return ret; + + s->idsp.idct_put(frame->data[0] + y * frame->linesize[0] + x, + frame->linesize[0], s->block[0]); + s->idsp.idct_put(frame->data[0] + y * frame->linesize[0] + x + 8, + frame->linesize[0], s->block[1]); + s->idsp.idct_put(frame->data[0] + (y + 8) * frame->linesize[0] + x, + frame->linesize[0], s->block[2]); + s->idsp.idct_put(frame->data[0] + (y + 8) * frame->linesize[0] + x + 8, + frame->linesize[0], s->block[3]); + s->idsp.idct_put(frame->data[1] + (y >> 1) * frame->linesize[1] + (x >> 1), + frame->linesize[1], s->block[4]); + s->idsp.idct_put(frame->data[2] + (y >> 1) * frame->linesize[2] + (x >> 1), + frame->linesize[2], s->block[5]); + } else { + flag2 = get_bits1(gb); + skip_bits1(gb); + ret = decode_blocks(avctx, gb, cbplo | (cbphi << 2), 1, offset, flag2); + if (ret < 0) + return ret; + + copy_block16(frame->data[0] + y * frame->linesize[0] + x, + prev->data[0] + y * prev->linesize[0] + x, + frame->linesize[0], prev->linesize[0], 16); + copy_block8(frame->data[1] + (y >> 1) * frame->linesize[1] + (x >> 1), + prev->data[1] + (y >> 1) * prev->linesize[1] + (x >> 1), + frame->linesize[1], prev->linesize[1], 8); + copy_block8(frame->data[2] + (y >> 1) * frame->linesize[2] + (x >> 1), + prev->data[2] + (y >> 1) * prev->linesize[2] + (x >> 1), + frame->linesize[2], prev->linesize[2], 8); + + s->idsp.idct_add(frame->data[0] + y * frame->linesize[0] + x, + frame->linesize[0], s->block[0]); + s->idsp.idct_add(frame->data[0] + y * frame->linesize[0] + x + 8, + frame->linesize[0], s->block[1]); + s->idsp.idct_add(frame->data[0] + (y + 8) * frame->linesize[0] + x, + frame->linesize[0], s->block[2]); + s->idsp.idct_add(frame->data[0] + (y + 8) * frame->linesize[0] + x + 8, + frame->linesize[0], s->block[3]); + s->idsp.idct_add(frame->data[1] + (y >> 1) * frame->linesize[1] + (x >> 1), + frame->linesize[1], s->block[4]); + s->idsp.idct_add(frame->data[2] + (y >> 1) * frame->linesize[2] + (x >> 1), + frame->linesize[2], s->block[5]); + } + } + } + + return 0; +} + +static int decode_frame(AVCodecContext *avctx, void *data, + int *got_frame, AVPacket *avpkt) +{ + IMM4Context *s = avctx->priv_data; + GetBitContext *gb = &s->gb; + AVFrame *frame = data; + int width, height; + unsigned type; + int ret, scaled; + + if (avpkt->size <= 32) + return AVERROR_INVALIDDATA; + + av_fast_padded_malloc(&s->bitstream, &s->bitstream_size, + FFALIGN(avpkt->size, 4)); + if (!s->bitstream) + return AVERROR(ENOMEM); + + s->bdsp.bswap_buf((uint32_t *)s->bitstream, + (uint32_t *)avpkt->data, + (avpkt->size + 3) >> 2); + + if ((ret = init_get_bits8(gb, s->bitstream, FFALIGN(avpkt->size, 4))) < 0) + return ret; + + avctx->pix_fmt = AV_PIX_FMT_YUV420P; + avctx->color_range = AVCOL_RANGE_JPEG; + + width = avctx->width; + height = avctx->height; + + scaled = avpkt->data[8]; + if (scaled < 2) { + int mode = avpkt->data[10]; + + switch (mode) { + case 1: + width = 352; + height = 240; + break; + case 2: + width = 704; + height = 240; + break; + case 4: + width = 480; + height = 704; + break; + case 17: + width = 352; + height = 288; + break; + case 18: + width = 704; + height = 288; + break; + default: + width = 704; + height = 576; + break; + } + } + + skip_bits_long(gb, 24 * 8); + type = get_bits_long(gb, 32); + s->hi = get_bits(gb, 16); + s->lo = get_bits(gb, 16); + + switch (type) { + case 0x19781977: + frame->key_frame = 1; + frame->pict_type = AV_PICTURE_TYPE_I; + break; + case 0x12250926: + frame->key_frame = 0; + frame->pict_type = AV_PICTURE_TYPE_P; + break; + default: + avpriv_request_sample(avctx, "type %X", type); + return AVERROR_PATCHWELCOME; + } + + if (avctx->width != width || + avctx->height != height) { + if (!frame->key_frame) { + av_log(avctx, AV_LOG_ERROR, "Frame size change is unsupported.\n"); + return AVERROR_INVALIDDATA; + } + av_frame_unref(s->prev_frame); + } + + ret = ff_set_dimensions(avctx, width, height); + if (ret < 0) + return ret; + + if ((ret = ff_get_buffer(avctx, frame, frame->key_frame ? AV_GET_BUFFER_FLAG_REF : 0)) < 0) + return ret; + + if (frame->key_frame) { + ret = decode_intra(avctx, gb, frame); + if (ret < 0) + return ret; + + av_frame_unref(s->prev_frame); + if ((ret = av_frame_ref(s->prev_frame, frame)) < 0) + return ret; + } else { + if (!s->prev_frame->data[0]) { + av_log(avctx, AV_LOG_ERROR, "Missing reference frame.\n"); + return AVERROR_INVALIDDATA; + } + + ret = decode_inter(avctx, gb, frame, s->prev_frame); + if (ret < 0) + return ret; + } + + *got_frame = 1; + + return avpkt->size; +} + +static av_cold void imm4_init_static_data(void) +{ + INIT_VLC_SPARSE_STATIC(&cbplo_tab, 9, FF_ARRAY_ELEMS(cbplo_bits), + cbplo_bits, 1, 1, cbplo_codes, 1, 1, cbplo_symbols, 1, 1, 512); + + INIT_VLC_SPARSE_STATIC(&cbphi_tab, 6, FF_ARRAY_ELEMS(cbphi_bits), + cbphi_bits, 1, 1, cbphi_codes, 1, 1, NULL, 0, 0, 64); + + INIT_VLC_SPARSE_STATIC(&blktype_tab, 9, FF_ARRAY_ELEMS(blktype_bits), + blktype_bits, 1, 1, blktype_codes, 1, 1, blktype_symbols, 1, 1, 512); + + INIT_VLC_SPARSE_STATIC(&block_tab, 12, FF_ARRAY_ELEMS(block_bits), + block_bits, 1, 1, block_codes, 1, 1, block_symbols, 2, 2, 4096); +} + +static av_cold int decode_init(AVCodecContext *avctx) +{ + static AVOnce init_static_once = AV_ONCE_INIT; + IMM4Context *s = avctx->priv_data; + uint8_t table[64]; + + for (int i = 0; i < 64; i++) + table[i] = i; + + ff_bswapdsp_init(&s->bdsp); + ff_idctdsp_init(&s->idsp, avctx); + ff_init_scantable(s->idsp.idct_permutation, &s->intra_scantable, table); + + s->prev_frame = av_frame_alloc(); + if (!s->prev_frame) + return AVERROR(ENOMEM); + + ff_thread_once(&init_static_once, imm4_init_static_data); + + return 0; +} + +static void decode_flush(AVCodecContext *avctx) +{ + IMM4Context *s = avctx->priv_data; + + av_frame_unref(s->prev_frame); +} + +static av_cold int decode_close(AVCodecContext *avctx) +{ + IMM4Context *s = avctx->priv_data; + + av_frame_free(&s->prev_frame); + av_freep(&s->bitstream); + s->bitstream_size = 0; + + return 0; +} + +AVCodec ff_imm4_decoder = { + .name = "imm4", + .long_name = NULL_IF_CONFIG_SMALL("Infinity IMM4"), + .type = AVMEDIA_TYPE_VIDEO, + .id = AV_CODEC_ID_IMM4, + .priv_data_size = sizeof(IMM4Context), + .init = decode_init, + .close = decode_close, + .decode = decode_frame, + .flush = decode_flush, + .capabilities = AV_CODEC_CAP_DR1, + .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE | + FF_CODEC_CAP_INIT_CLEANUP, +}; diff --git a/libavcodec/indeo2.c b/libavcodec/indeo2.c index 4971b8430..f367682e6 100644 --- a/libavcodec/indeo2.c +++ b/libavcodec/indeo2.c @@ -56,7 +56,7 @@ static int ir2_decode_plane(Ir2Context *ctx, int width, int height, uint8_t *dst int j; int out = 0; - if (width & 1) + if ((width & 1) || width * height / (2*(IR2_CODES - 0x7F)) > get_bits_left(&ctx->gb)) return AVERROR_INVALIDDATA; /* first line contain absolute values, other lines contain deltas */ @@ -79,10 +79,11 @@ static int ir2_decode_plane(Ir2Context *ctx, int width, int height, uint8_t *dst for (j = 1; j < height; j++) { out = 0; - if (get_bits_left(&ctx->gb) <= 0) - return AVERROR_INVALIDDATA; while (out < width) { - int c = ir2_get_code(&ctx->gb); + int c; + if (get_bits_left(&ctx->gb) <= 0) + return AVERROR_INVALIDDATA; + c = ir2_get_code(&ctx->gb); if (c >= 0x80) { /* we have a skip */ c -= 0x7F; if (out + c*2 > width) @@ -123,9 +124,9 @@ static int ir2_decode_plane_inter(Ir2Context *ctx, int width, int height, uint8_ for (j = 0; j < height; j++) { out = 0; - if (get_bits_left(&ctx->gb) <= 0) - return AVERROR_INVALIDDATA; while (out < width) { + if (get_bits_left(&ctx->gb) <= 0) + return AVERROR_INVALIDDATA; c = ir2_get_code(&ctx->gb); if (c >= 0x80) { /* we have a skip */ c -= 0x7F; diff --git a/libavcodec/indeo5.c b/libavcodec/indeo5.c index b39cffd9a..7b9da53df 100644 --- a/libavcodec/indeo5.c +++ b/libavcodec/indeo5.c @@ -642,6 +642,8 @@ static av_cold int decode_init(AVCodecContext *avctx) IVI45DecContext *ctx = avctx->priv_data; int result; + ctx->gop_invalid = 1; + ff_ivi_init_static_vlc(); /* copy rvmap tables in our context so we can apply changes to them */ diff --git a/libavcodec/internal.h b/libavcodec/internal.h index bb92873d7..5096ffa1d 100644 --- a/libavcodec/internal.h +++ b/libavcodec/internal.h @@ -83,7 +83,7 @@ #define FF_QSCALE_TYPE_H264 2 #define FF_QSCALE_TYPE_VP56 3 -#define FF_SANE_NB_CHANNELS 64U +#define FF_SANE_NB_CHANNELS 256U #define FF_SIGNBIT(x) ((x) >> CHAR_BIT * sizeof(x) - 1) @@ -218,6 +218,14 @@ typedef struct AVCodecInternal { /* to prevent infinite loop on errors when draining */ int nb_draining_errors; + + /* used when avctx flag AV_CODEC_FLAG_DROPCHANGED is set */ + int changed_frames_dropped; + int initial_format; + int initial_width, initial_height; + int initial_sample_rate; + int initial_channels; + uint64_t initial_channel_layout; } AVCodecInternal; struct AVCodecDefault { @@ -404,6 +412,18 @@ int ff_alloc_a53_sei(const AVFrame *frame, size_t prefix_len, */ int64_t ff_guess_coded_bitrate(AVCodecContext *avctx); +/** + * Check if a value is in the list. If not, return the default value + * + * @param ctx Context for the log msg + * @param val_name Name of the checked value, for log msg + * @param array_valid_values Array of valid int, ended with INT_MAX + * @param default_value Value return if checked value is not in the array + * @return Value or default_value. + */ +int ff_int_from_list_or_default(void *ctx, const char * val_name, int val, + const int * array_valid_values, int default_value); + #if defined(_WIN32) && CONFIG_SHARED && !defined(BUILDING_avcodec) # define av_export_avcodec __declspec(dllimport) #else diff --git a/libavcodec/interplayacm.c b/libavcodec/interplayacm.c index c897e72bb..5639d8de8 100644 --- a/libavcodec/interplayacm.c +++ b/libavcodec/interplayacm.c @@ -629,5 +629,6 @@ AVCodec ff_interplay_acm_decoder = { .close = decode_close, .decode = decode_frame, .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_DR1, + .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, .priv_data_size = sizeof(InterplayACMContext), }; diff --git a/libavcodec/interplayvideo.c b/libavcodec/interplayvideo.c index deaa09cba..4313fdf7a 100644 --- a/libavcodec/interplayvideo.c +++ b/libavcodec/interplayvideo.c @@ -1260,7 +1260,7 @@ static int ipvideo_decode_frame(AVCodecContext *avctx, s->decoding_map_size = ((s->avctx->width / 8) * (s->avctx->height / 8)) * 2; s->decoding_map = buf + 8 + 14; /* 14 bits of op data */ video_data_size -= s->decoding_map_size + 14; - if (video_data_size <= 0) + if (video_data_size <= 0 || s->decoding_map_size == 0) return AVERROR_INVALIDDATA; if (buf_size < 8 + s->decoding_map_size + 14 + video_data_size) diff --git a/libavcodec/ivi.c b/libavcodec/ivi.c index cea40d82c..73fcf51b7 100644 --- a/libavcodec/ivi.c +++ b/libavcodec/ivi.c @@ -79,7 +79,7 @@ typedef void (*ivi_mc_avg_func) (int16_t *buf, const int16_t *ref_buf1, const int16_t *ref_buf2, ptrdiff_t pitch, int mc_type, int mc_type2); -static int ivi_mc(IVIBandDesc *band, ivi_mc_func mc, ivi_mc_avg_func mc_avg, +static int ivi_mc(const IVIBandDesc *band, ivi_mc_func mc, ivi_mc_avg_func mc_avg, int offs, int mv_x, int mv_y, int mv_x2, int mv_y2, int mc_type, int mc_type2) { @@ -379,7 +379,7 @@ av_cold int ff_ivi_init_planes(AVCodecContext *avctx, IVIPlaneDesc *planes, cons return 0; } -static int ivi_init_tiles(IVIBandDesc *band, IVITile *ref_tile, +static int ivi_init_tiles(const IVIBandDesc *band, IVITile *ref_tile, int p, int b, int t_height, int t_width) { int x, y; @@ -429,6 +429,10 @@ av_cold int ff_ivi_init_tiles(IVIPlaneDesc *planes, t_height = !p ? tile_height : (tile_height + 3) >> 2; if (!p && planes[0].num_bands == 4) { + if (t_width % 2 || t_height % 2) { + avpriv_request_sample(NULL, "Odd tiles"); + return AVERROR_PATCHWELCOME; + } t_width >>= 1; t_height >>= 1; } @@ -437,6 +441,14 @@ av_cold int ff_ivi_init_tiles(IVIPlaneDesc *planes, for (b = 0; b < planes[p].num_bands; b++) { band = &planes[p].bands[b]; + + if (band->tiles) { + int t; + for (t = 0; t < band->num_tiles; t++) { + av_freep(&band->tiles[t].mbs); + } + } + x_tiles = IVI_NUM_TILES(band->width, t_width); y_tiles = IVI_NUM_TILES(band->height, t_height); band->num_tiles = x_tiles * y_tiles; @@ -485,22 +497,16 @@ static int ivi_dec_tile_data_size(GetBitContext *gb) return len; } -static int ivi_dc_transform(IVIBandDesc *band, int *prev_dc, int buf_offs, +static int ivi_dc_transform(const IVIBandDesc *band, int *prev_dc, int buf_offs, int blk_size) { - int buf_size = band->pitch * band->aheight - buf_offs; - int min_size = (blk_size - 1) * band->pitch + blk_size; - - if (min_size > buf_size) - return AVERROR_INVALIDDATA; - band->dc_transform(prev_dc, band->buf + buf_offs, band->pitch, blk_size); return 0; } -static int ivi_decode_coded_blocks(GetBitContext *gb, IVIBandDesc *band, +static int ivi_decode_coded_blocks(GetBitContext *gb, const IVIBandDesc *band, ivi_mc_func mc, ivi_mc_avg_func mc_avg, int mv_x, int mv_y, int mv_x2, int mv_y2, @@ -611,7 +617,7 @@ static int ivi_decode_coded_blocks(GetBitContext *gb, IVIBandDesc *band, * @param[in] tile pointer to the tile descriptor * @return result code: 0 - OK, -1 = error (corrupted blocks data) */ -static int ivi_decode_blocks(GetBitContext *gb, IVIBandDesc *band, +static int ivi_decode_blocks(GetBitContext *gb, const IVIBandDesc *band, IVITile *tile, AVCodecContext *avctx) { int mbn, blk, num_blocks, blk_size, ret, is_intra; @@ -724,6 +730,11 @@ static int ivi_decode_blocks(GetBitContext *gb, IVIBandDesc *band, if (ret < 0) return ret; } else { + int buf_size = band->pitch * band->aheight - buf_offs; + int min_size = (blk_size - 1) * band->pitch + blk_size; + + if (min_size > buf_size) + return AVERROR_INVALIDDATA; /* block not coded */ /* for intra blocks apply the dc slant transform */ /* for inter - perform the motion compensation without delta */ @@ -758,7 +769,7 @@ static int ivi_decode_blocks(GetBitContext *gb, IVIBandDesc *band, * @param[in] tile pointer to the tile descriptor * @param[in] mv_scale scaling factor for motion vectors */ -static int ivi_process_empty_tile(AVCodecContext *avctx, IVIBandDesc *band, +static int ivi_process_empty_tile(AVCodecContext *avctx, const IVIBandDesc *band, IVITile *tile, int32_t mv_scale) { int x, y, need_mc, mbn, blk, num_blocks, mv_x, mv_y, mc_type; @@ -767,24 +778,29 @@ static int ivi_process_empty_tile(AVCodecContext *avctx, IVIBandDesc *band, const int16_t *src; int16_t *dst; ivi_mc_func mc_no_delta_func; + int clear_first = !band->qdelta_present && !band->plane && !band->band_num; + int mb_size = band->mb_size; + int xend = tile->xpos + tile->width; + int is_halfpel = band->is_halfpel; + int pitch = band->pitch; - if (tile->num_MBs != IVI_MBs_PER_TILE(tile->width, tile->height, band->mb_size)) { + if (tile->num_MBs != IVI_MBs_PER_TILE(tile->width, tile->height, mb_size)) { av_log(avctx, AV_LOG_ERROR, "Allocated tile size %d mismatches " "parameters %d in ivi_process_empty_tile()\n", - tile->num_MBs, IVI_MBs_PER_TILE(tile->width, tile->height, band->mb_size)); + tile->num_MBs, IVI_MBs_PER_TILE(tile->width, tile->height, mb_size)); return AVERROR_INVALIDDATA; } - offs = tile->ypos * band->pitch + tile->xpos; + offs = tile->ypos * pitch + tile->xpos; mb = tile->mbs; ref_mb = tile->ref_mbs; - row_offset = band->mb_size * band->pitch; + row_offset = mb_size * pitch; need_mc = 0; /* reset the mc tracking flag */ - for (y = tile->ypos; y < (tile->ypos + tile->height); y += band->mb_size) { + for (y = tile->ypos; y < (tile->ypos + tile->height); y += mb_size) { mb_offset = offs; - for (x = tile->xpos; x < (tile->xpos + tile->width); x += band->mb_size) { + for (x = tile->xpos; x < xend; x += mb_size) { mb->xpos = x; mb->ypos = y; mb->buf_offs = mb_offset; @@ -792,53 +808,54 @@ static int ivi_process_empty_tile(AVCodecContext *avctx, IVIBandDesc *band, mb->type = 1; /* set the macroblocks type = INTER */ mb->cbp = 0; /* all blocks are empty */ - if (!band->qdelta_present && !band->plane && !band->band_num) { + if (clear_first) { mb->q_delta = band->glob_quant; mb->mv_x = 0; mb->mv_y = 0; } - if (band->inherit_qdelta && ref_mb) - mb->q_delta = ref_mb->q_delta; + if (ref_mb) { + if (band->inherit_qdelta) + mb->q_delta = ref_mb->q_delta; - if (band->inherit_mv && ref_mb) { - /* motion vector inheritance */ - if (mv_scale) { - mb->mv_x = ivi_scale_mv(ref_mb->mv_x, mv_scale); - mb->mv_y = ivi_scale_mv(ref_mb->mv_y, mv_scale); - } else { - mb->mv_x = ref_mb->mv_x; - mb->mv_y = ref_mb->mv_y; - } - need_mc |= mb->mv_x || mb->mv_y; /* tracking non-zero motion vectors */ - { - int dmv_x, dmv_y, cx, cy; + if (band->inherit_mv) { + /* motion vector inheritance */ + if (mv_scale) { + mb->mv_x = ivi_scale_mv(ref_mb->mv_x, mv_scale); + mb->mv_y = ivi_scale_mv(ref_mb->mv_y, mv_scale); + } else { + mb->mv_x = ref_mb->mv_x; + mb->mv_y = ref_mb->mv_y; + } + need_mc |= mb->mv_x || mb->mv_y; /* tracking non-zero motion vectors */ + { + int dmv_x, dmv_y, cx, cy; - dmv_x = mb->mv_x >> band->is_halfpel; - dmv_y = mb->mv_y >> band->is_halfpel; - cx = mb->mv_x & band->is_halfpel; - cy = mb->mv_y & band->is_halfpel; + dmv_x = mb->mv_x >> is_halfpel; + dmv_y = mb->mv_y >> is_halfpel; + cx = mb->mv_x & is_halfpel; + cy = mb->mv_y & is_halfpel; - if ( mb->xpos + dmv_x < 0 - || mb->xpos + dmv_x + band->mb_size + cx > band->pitch - || mb->ypos + dmv_y < 0 - || mb->ypos + dmv_y + band->mb_size + cy > band->aheight) { - av_log(avctx, AV_LOG_ERROR, "MV out of bounds\n"); - return AVERROR_INVALIDDATA; + if ( mb->xpos + dmv_x < 0 + || mb->xpos + dmv_x + mb_size + cx > pitch + || mb->ypos + dmv_y < 0 + || mb->ypos + dmv_y + mb_size + cy > band->aheight) { + av_log(avctx, AV_LOG_ERROR, "MV out of bounds\n"); + return AVERROR_INVALIDDATA; + } } } + ref_mb++; } mb++; - if (ref_mb) - ref_mb++; - mb_offset += band->mb_size; + mb_offset += mb_size; } // for x offs += row_offset; } // for y if (band->inherit_mv && need_mc) { /* apply motion compensation if there is at least one non-zero motion vector */ - num_blocks = (band->mb_size != band->blk_size) ? 4 : 1; /* number of blocks per mb */ + num_blocks = (mb_size != band->blk_size) ? 4 : 1; /* number of blocks per mb */ mc_no_delta_func = (band->blk_size == 8) ? ff_ivi_mc_8x8_no_delta : ff_ivi_mc_4x4_no_delta; @@ -855,7 +872,7 @@ static int ivi_process_empty_tile(AVCodecContext *avctx, IVIBandDesc *band, for (blk = 0; blk < num_blocks; blk++) { /* adjust block position in the buffer according with its number */ - offs = mb->buf_offs + band->blk_size * ((blk & 1) + !!(blk & 2) * band->pitch); + offs = mb->buf_offs + band->blk_size * ((blk & 1) + !!(blk & 2) * pitch); ret = ivi_mc(band, mc_no_delta_func, 0, offs, mv_x, mv_y, 0, 0, mc_type, -1); if (ret < 0) @@ -864,12 +881,12 @@ static int ivi_process_empty_tile(AVCodecContext *avctx, IVIBandDesc *band, } } else { /* copy data from the reference tile into the current one */ - src = band->ref_buf + tile->ypos * band->pitch + tile->xpos; - dst = band->buf + tile->ypos * band->pitch + tile->xpos; + src = band->ref_buf + tile->ypos * pitch + tile->xpos; + dst = band->buf + tile->ypos * pitch + tile->xpos; for (y = 0; y < tile->height; y++) { memcpy(dst, src, tile->width*sizeof(band->buf[0])); - src += band->pitch; - dst += band->pitch; + src += pitch; + dst += pitch; } } @@ -878,7 +895,7 @@ static int ivi_process_empty_tile(AVCodecContext *avctx, IVIBandDesc *band, #ifdef DEBUG -static uint16_t ivi_calc_band_checksum(IVIBandDesc *band) +static uint16_t ivi_calc_band_checksum(const IVIBandDesc *band) { int x, y; int16_t *src, checksum; @@ -913,8 +930,16 @@ static void ivi_output_plane(IVIPlaneDesc *plane, uint8_t *dst, ptrdiff_t dst_pi return; for (y = 0; y < plane->height; y++) { - for (x = 0; x < plane->width; x++) - dst[x] = av_clip_uint8(src[x] + 128); + int m = 0; + int w = plane->width; + for (x = 0; x < w; x++) { + int t = src[x] + 128; + dst[x] = t; + m |= t; + } + if (m & ~255) + for (x = 0; x < w; x++) + dst[x] = av_clip_uint8(src[x] + 128); src += pitch; dst += dst_pitch; } diff --git a/libavcodec/j2kenc.c b/libavcodec/j2kenc.c index 3e542af3c..e91d932bb 100644 --- a/libavcodec/j2kenc.c +++ b/libavcodec/j2kenc.c @@ -71,6 +71,7 @@ #include "libavutil/common.h" #include "libavutil/pixdesc.h" #include "libavutil/opt.h" +#include "libavutil/intreadwrite.h" #define NMSEDEC_BITS 7 #define NMSEDEC_FRACBITS (NMSEDEC_BITS-1) @@ -1054,14 +1055,38 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt, bytestream_put_byte(&s->buf, 1); bytestream_put_byte(&s->buf, 0); bytestream_put_byte(&s->buf, 0); - if (s->ncomponents == 1) { - bytestream_put_be32(&s->buf, 17); - } else if (avctx->pix_fmt == AV_PIX_FMT_RGB24) { + if (avctx->pix_fmt == AV_PIX_FMT_RGB24 || avctx->pix_fmt == AV_PIX_FMT_PAL8) { bytestream_put_be32(&s->buf, 16); + } else if (s->ncomponents == 1) { + bytestream_put_be32(&s->buf, 17); } else { bytestream_put_be32(&s->buf, 18); } update_size(chunkstart, s->buf); + if (avctx->pix_fmt == AV_PIX_FMT_PAL8) { + int i; + uint8_t *palette = pict->data[1]; + chunkstart = s->buf; + bytestream_put_be32(&s->buf, 0); + bytestream_put_buffer(&s->buf, "pclr", 4); + bytestream_put_be16(&s->buf, AVPALETTE_COUNT); + bytestream_put_byte(&s->buf, 3); // colour channels + bytestream_put_be24(&s->buf, 0x070707); //colour depths + for (i = 0; i < AVPALETTE_COUNT; i++) { + bytestream_put_be24(&s->buf, HAVE_BIGENDIAN ? AV_RB24(palette + 1) : AV_RL24(palette)); + palette += 4; + } + update_size(chunkstart, s->buf); + chunkstart = s->buf; + bytestream_put_be32(&s->buf, 0); + bytestream_put_buffer(&s->buf, "cmap", 4); + for (i = 0; i < 3; i++) { + bytestream_put_be16(&s->buf, 0); // component + bytestream_put_byte(&s->buf, 1); // palette mapping + bytestream_put_byte(&s->buf, i); // index + } + update_size(chunkstart, s->buf); + } update_size(jp2hstart, s->buf); jp2cstart = s->buf; @@ -1124,6 +1149,12 @@ FF_DISABLE_DEPRECATION_WARNINGS FF_ENABLE_DEPRECATION_WARNINGS #endif + if (avctx->pix_fmt == AV_PIX_FMT_PAL8 && (s->pred != FF_DWT97_INT || s->format != CODEC_JP2)) { + av_log(s->avctx, AV_LOG_WARNING, "Forcing lossless jp2 for pal8\n"); + s->pred = FF_DWT97_INT; + s->format = CODEC_JP2; + } + // defaults: // TODO: implement setting non-standard precinct size memset(codsty->log2_prec_widths , 15, sizeof(codsty->log2_prec_widths )); @@ -1154,7 +1185,7 @@ FF_ENABLE_DEPRECATION_WARNINGS if (avctx->pix_fmt == AV_PIX_FMT_RGB24){ s->ncomponents = 3; - } else if (avctx->pix_fmt == AV_PIX_FMT_GRAY8){ + } else if (avctx->pix_fmt == AV_PIX_FMT_GRAY8 || avctx->pix_fmt == AV_PIX_FMT_PAL8){ s->ncomponents = 1; } else{ // planar YUV s->planar = 1; @@ -1223,6 +1254,7 @@ AVCodec ff_jpeg2000_encoder = { AV_PIX_FMT_RGB24, AV_PIX_FMT_YUV444P, AV_PIX_FMT_GRAY8, AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV410P, AV_PIX_FMT_YUV411P, + AV_PIX_FMT_PAL8, AV_PIX_FMT_NONE }, .priv_class = &j2k_class, diff --git a/libavcodec/jpeg2000.c b/libavcodec/jpeg2000.c index 8e9098097..3f50bf9fb 100644 --- a/libavcodec/jpeg2000.c +++ b/libavcodec/jpeg2000.c @@ -247,6 +247,11 @@ static void init_band_stepsize(AVCodecContext *avctx, } } + if (band->f_stepsize > (INT_MAX >> 15)) { + band->f_stepsize = 0; + av_log(avctx, AV_LOG_ERROR, "stepsize out of range\n"); + } + band->i_stepsize = band->f_stepsize * (1 << 15); /* FIXME: In OpenJPEG code stepsize = stepsize * 0.5. Why? diff --git a/libavcodec/jpeg2000dec.c b/libavcodec/jpeg2000dec.c index fc14fb3bd..019dc81f5 100644 --- a/libavcodec/jpeg2000dec.c +++ b/libavcodec/jpeg2000dec.c @@ -82,7 +82,7 @@ typedef struct Jpeg2000Tile { Jpeg2000CodingStyle codsty[4]; Jpeg2000QuantStyle qntsty[4]; Jpeg2000POC poc; - Jpeg2000TilePart tile_part[256]; + Jpeg2000TilePart tile_part[32]; uint16_t tp_idx; // Tile-part index int coord[2][2]; // border coordinates {{x0, x1}, {y0, y1}} } Jpeg2000Tile; @@ -764,7 +764,10 @@ static int get_sot(Jpeg2000DecoderContext *s, int n) return AVERROR_INVALIDDATA; } - av_assert0(TPsot < FF_ARRAY_ELEMS(s->tile[Isot].tile_part)); + if (TPsot >= FF_ARRAY_ELEMS(s->tile[Isot].tile_part)) { + avpriv_request_sample(s->avctx, "Too many tile parts"); + return AVERROR_PATCHWELCOME; + } s->tile[Isot].tp_idx = TPsot; tp = s->tile[Isot].tile_part + TPsot; @@ -826,18 +829,24 @@ static uint8_t get_tlm(Jpeg2000DecoderContext *s, int n) return 0; } -static uint8_t get_plt(Jpeg2000DecoderContext *s, int n) +static int get_plt(Jpeg2000DecoderContext *s, int n) { int i; + int v; av_log(s->avctx, AV_LOG_DEBUG, "PLT marker at pos 0x%X\n", bytestream2_tell(&s->g) - 4); + if (n < 4) + return AVERROR_INVALIDDATA; + /*Zplt =*/ bytestream2_get_byte(&s->g); for (i = 0; i < n - 3; i++) { - bytestream2_get_byte(&s->g); + v = bytestream2_get_byte(&s->g); } + if (v & 0x80) + return AVERROR_INVALIDDATA; return 0; } @@ -1168,7 +1177,10 @@ static int jpeg2000_decode_packets_po_iteration(Jpeg2000DecoderContext *s, Jpeg2 step_x = FFMIN(step_x, rlevel->log2_prec_width + reducedresno); step_y = FFMIN(step_y, rlevel->log2_prec_height + reducedresno); } - av_assert0(step_x < 32 && step_y < 32); + if (step_x >= 31 || step_y >= 31){ + avpriv_request_sample(s->avctx, "CPRL with large step"); + return AVERROR_PATCHWELCOME; + } step_x = 1<data + cblk->length - 2*(term_cnt < cblk->nb_terminations) - t1->mqc.bp); } - return 0; + return 1; } /* TODO: Verify dequantization for lossless case @@ -1691,6 +1703,7 @@ static inline void tile_codeblocks(Jpeg2000DecoderContext *s, Jpeg2000Tile *tile for (compno = 0; compno < s->ncomponents; compno++) { Jpeg2000Component *comp = tile->comp + compno; Jpeg2000CodingStyle *codsty = tile->codsty + compno; + int coded = 0; t1.stride = (1<log2_cblk_width) + 2; @@ -1720,11 +1733,14 @@ static inline void tile_codeblocks(Jpeg2000DecoderContext *s, Jpeg2000Tile *tile cblkno++) { int x, y; Jpeg2000Cblk *cblk = prec->cblk + cblkno; - decode_cblk(s, codsty, &t1, cblk, + int ret = decode_cblk(s, codsty, &t1, cblk, cblk->coord[0][1] - cblk->coord[0][0], cblk->coord[1][1] - cblk->coord[1][0], bandpos); - + if (ret) + coded = 1; + else + continue; x = cblk->coord[0][0] - band->coord[0][0]; y = cblk->coord[1][0] - band->coord[1][0]; @@ -1740,7 +1756,9 @@ static inline void tile_codeblocks(Jpeg2000DecoderContext *s, Jpeg2000Tile *tile } /* end reslevel */ /* inverse DWT */ - ff_dwt_decode(&comp->dwt, codsty->transform == FF_DWT97 ? (void*)comp->f_data : (void*)comp->i_data); + if (coded) + ff_dwt_decode(&comp->dwt, codsty->transform == FF_DWT97 ? (void*)comp->f_data : (void*)comp->i_data); + } /*end comp */ } @@ -2053,7 +2071,6 @@ static int jp2_find_codestream(Jpeg2000DecoderContext *s) } } else if (atom2 == MKBETAG('p','c','l','r') && atom2_size >= 6) { int i, size, colour_count, colour_channels, colour_depth[3]; - uint32_t r, g, b; colour_count = bytestream2_get_be16u(&s->g); colour_channels = bytestream2_get_byteu(&s->g); // FIXME: Do not ignore channel_sign @@ -2063,7 +2080,7 @@ static int jp2_find_codestream(Jpeg2000DecoderContext *s) size = (colour_depth[0] + 7 >> 3) * colour_count + (colour_depth[1] + 7 >> 3) * colour_count + (colour_depth[2] + 7 >> 3) * colour_count; - if (colour_count > 256 || + if (colour_count > AVPALETTE_COUNT || colour_channels != 3 || colour_depth[0] > 16 || colour_depth[1] > 16 || @@ -2075,6 +2092,7 @@ static int jp2_find_codestream(Jpeg2000DecoderContext *s) } s->pal8 = 1; for (i = 0; i < colour_count; i++) { + uint32_t r, g, b; if (colour_depth[0] <= 8) { r = bytestream2_get_byteu(&s->g) << 8 - colour_depth[0]; r |= r >> colour_depth[0]; diff --git a/libavcodec/jrevdct.c b/libavcodec/jrevdct.c index 3b15a5267..a1a0f571a 100644 --- a/libavcodec/jrevdct.c +++ b/libavcodec/jrevdct.c @@ -63,6 +63,7 @@ */ #include "libavutil/common.h" +#include "libavutil/intreadwrite.h" #include "dct.h" #include "idctdsp.h" @@ -234,7 +235,7 @@ void ff_j_rev_dct(DCTBLOCK data) * row DCT calculations can be simplified this way. */ - register int *idataptr = (int*)dataptr; + register uint8_t *idataptr = (uint8_t*)dataptr; /* WARNING: we do the same permutation as MMX idct to simplify the video core */ @@ -254,10 +255,10 @@ void ff_j_rev_dct(DCTBLOCK data) int16_t dcval = (int16_t) (d0 * (1 << PASS1_BITS)); register int v = (dcval & 0xffff) | ((dcval * (1 << 16)) & 0xffff0000); - idataptr[0] = v; - idataptr[1] = v; - idataptr[2] = v; - idataptr[3] = v; + AV_WN32A(&idataptr[ 0], v); + AV_WN32A(&idataptr[ 4], v); + AV_WN32A(&idataptr[ 8], v); + AV_WN32A(&idataptr[12], v); } dataptr += DCTSIZE; /* advance pointer to next row */ @@ -974,7 +975,7 @@ void ff_j_rev_dct4(DCTBLOCK data) * row DCT calculations can be simplified this way. */ - register int *idataptr = (int*)dataptr; + register uint8_t *idataptr = (uint8_t*)dataptr; d0 = dataptr[0]; d2 = dataptr[1]; @@ -988,8 +989,8 @@ void ff_j_rev_dct4(DCTBLOCK data) int16_t dcval = (int16_t) (d0 << PASS1_BITS); register int v = (dcval & 0xffff) | ((dcval << 16) & 0xffff0000); - idataptr[0] = v; - idataptr[1] = v; + AV_WN32A(&idataptr[0], v); + AV_WN32A(&idataptr[4], v); } dataptr += DCTSTRIDE; /* advance pointer to next row */ diff --git a/libavcodec/jvdec.c b/libavcodec/jvdec.c index 4337d5681..b06e7cf2b 100644 --- a/libavcodec/jvdec.c +++ b/libavcodec/jvdec.c @@ -163,13 +163,14 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, av_log(avctx, AV_LOG_ERROR, "video size %d invalid\n", video_size); return AVERROR_INVALIDDATA; } - if ((ret = ff_reget_buffer(avctx, s->frame)) < 0) - return ret; if (video_type == 0 || video_type == 1) { GetBitContext gb; init_get_bits(&gb, buf, 8 * video_size); + if ((ret = ff_reget_buffer(avctx, s->frame)) < 0) + return ret; + if (avctx->height/8 * (avctx->width/8) > 4 * video_size) { av_log(avctx, AV_LOG_ERROR, "Insufficient input data for dimensions\n"); return AVERROR_INVALIDDATA; @@ -184,6 +185,11 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, buf += video_size; } else if (video_type == 2) { int v = *buf++; + + av_frame_unref(s->frame); + if ((ret = ff_get_buffer(avctx, s->frame, AV_GET_BUFFER_FLAG_REF)) < 0) + return ret; + for (j = 0; j < avctx->height; j++) memset(s->frame->data[0] + j * s->frame->linesize[0], v, avctx->width); diff --git a/libavcodec/lagarith.c b/libavcodec/lagarith.c index 0f4aa8948..59169be5d 100644 --- a/libavcodec/lagarith.c +++ b/libavcodec/lagarith.c @@ -53,9 +53,6 @@ typedef struct LagarithContext { LLVidDSPContext llviddsp; int zeros; /**< number of consecutive zero bytes encountered */ int zeros_rem; /**< number of zero bytes remaining to output */ - uint8_t *rgb_planes; - int rgb_planes_allocated; - int rgb_stride; } LagarithContext; /** @@ -141,6 +138,7 @@ static int lag_read_prob_header(lag_rac *rac, GetBitContext *gb) unsigned prob, cumulative_target; unsigned cumul_prob = 0; unsigned scaled_cumul_prob = 0; + int nnz = 0; rac->prob[0] = 0; rac->prob[257] = UINT_MAX; @@ -164,6 +162,8 @@ static int lag_read_prob_header(lag_rac *rac, GetBitContext *gb) prob = 256 - i; for (j = 0; j < prob; j++) rac->prob[++i] = 0; + }else { + nnz++; } } @@ -172,6 +172,10 @@ static int lag_read_prob_header(lag_rac *rac, GetBitContext *gb) return -1; } + if (nnz == 1 && (show_bits_long(gb, 32) & 0xFFFFFF)) { + return AVERROR_INVALIDDATA; + } + /* Scale probabilities so cumulative probability is an even power of 2. */ scale_factor = av_log2(cumul_prob); @@ -534,14 +538,15 @@ static int lag_decode_frame(AVCodecContext *avctx, LagarithContext *l = avctx->priv_data; ThreadFrame frame = { .f = data }; AVFrame *const p = data; - uint8_t frametype = 0; + uint8_t frametype; uint32_t offset_gu = 0, offset_bv = 0, offset_ry = 9; uint32_t offs[4]; - uint8_t *srcs[4], *dst; + uint8_t *srcs[4]; int i, j, planes = 3; int ret; p->key_frame = 1; + p->pict_type = AV_PICTURE_TYPE_I; frametype = buf[0]; @@ -550,64 +555,60 @@ static int lag_decode_frame(AVCodecContext *avctx, switch (frametype) { case FRAME_SOLID_RGBA: - avctx->pix_fmt = AV_PIX_FMT_RGB32; + avctx->pix_fmt = AV_PIX_FMT_GBRAP; case FRAME_SOLID_GRAY: if (frametype == FRAME_SOLID_GRAY) if (avctx->bits_per_coded_sample == 24) { - avctx->pix_fmt = AV_PIX_FMT_RGB24; + avctx->pix_fmt = AV_PIX_FMT_GBRP; } else { - avctx->pix_fmt = AV_PIX_FMT_0RGB32; + avctx->pix_fmt = AV_PIX_FMT_GBRAP; planes = 4; } if ((ret = ff_thread_get_buffer(avctx, &frame, 0)) < 0) return ret; - dst = p->data[0]; if (frametype == FRAME_SOLID_RGBA) { - for (j = 0; j < avctx->height; j++) { - for (i = 0; i < avctx->width; i++) - AV_WN32(dst + i * 4, offset_gu); - dst += p->linesize[0]; - } + for (i = 0; i < avctx->height; i++) { + memset(p->data[0] + i * p->linesize[0], buf[2], avctx->width); + memset(p->data[1] + i * p->linesize[1], buf[1], avctx->width); + memset(p->data[2] + i * p->linesize[2], buf[3], avctx->width); + memset(p->data[3] + i * p->linesize[3], buf[4], avctx->width); + } } else { - for (j = 0; j < avctx->height; j++) { - memset(dst, buf[1], avctx->width * planes); - dst += p->linesize[0]; + for (i = 0; i < avctx->height; i++) { + for (j = 0; j < planes; j++) + memset(p->data[j] + i * p->linesize[j], buf[1], avctx->width); } } break; case FRAME_SOLID_COLOR: if (avctx->bits_per_coded_sample == 24) { - avctx->pix_fmt = AV_PIX_FMT_RGB24; + avctx->pix_fmt = AV_PIX_FMT_GBRP; } else { - avctx->pix_fmt = AV_PIX_FMT_RGB32; - offset_gu |= 0xFFU << 24; + avctx->pix_fmt = AV_PIX_FMT_GBRAP; } if ((ret = ff_thread_get_buffer(avctx, &frame,0)) < 0) return ret; - dst = p->data[0]; - for (j = 0; j < avctx->height; j++) { - for (i = 0; i < avctx->width; i++) - if (avctx->bits_per_coded_sample == 24) { - AV_WB24(dst + i * 3, offset_gu); - } else { - AV_WN32(dst + i * 4, offset_gu); - } - dst += p->linesize[0]; + for (i = 0; i < avctx->height; i++) { + memset(p->data[0] + i * p->linesize[0], buf[2], avctx->width); + memset(p->data[1] + i * p->linesize[1], buf[1], avctx->width); + memset(p->data[2] + i * p->linesize[2], buf[3], avctx->width); + if (avctx->pix_fmt == AV_PIX_FMT_GBRAP) + memset(p->data[3] + i * p->linesize[3], 0xFFu, avctx->width); } break; case FRAME_ARITH_RGBA: - avctx->pix_fmt = AV_PIX_FMT_RGB32; + avctx->pix_fmt = AV_PIX_FMT_GBRAP; planes = 4; offset_ry += 4; offs[3] = AV_RL32(buf + 9); case FRAME_ARITH_RGB24: case FRAME_U_RGB24: if (frametype == FRAME_ARITH_RGB24 || frametype == FRAME_U_RGB24) - avctx->pix_fmt = AV_PIX_FMT_RGB24; + avctx->pix_fmt = AV_PIX_FMT_GBRP; if ((ret = ff_thread_get_buffer(avctx, &frame, 0)) < 0) return ret; @@ -616,15 +617,8 @@ static int lag_decode_frame(AVCodecContext *avctx, offs[1] = offset_gu; offs[2] = offset_ry; - l->rgb_stride = FFALIGN(avctx->width, 16); - av_fast_malloc(&l->rgb_planes, &l->rgb_planes_allocated, - l->rgb_stride * avctx->height * planes + 1); - if (!l->rgb_planes) { - av_log(avctx, AV_LOG_ERROR, "cannot allocate temporary buffer\n"); - return AVERROR(ENOMEM); - } for (i = 0; i < planes; i++) - srcs[i] = l->rgb_planes + (i + 1) * l->rgb_stride * avctx->height - l->rgb_stride; + srcs[i] = p->data[i] + (avctx->height - 1) * p->linesize[i]; for (i = 0; i < planes; i++) if (buf_size <= offs[i]) { av_log(avctx, AV_LOG_ERROR, @@ -635,32 +629,16 @@ static int lag_decode_frame(AVCodecContext *avctx, for (i = 0; i < planes; i++) lag_decode_arith_plane(l, srcs[i], avctx->width, avctx->height, - -l->rgb_stride, buf + offs[i], + -p->linesize[i], buf + offs[i], buf_size - offs[i]); - dst = p->data[0]; - for (i = 0; i < planes; i++) - srcs[i] = l->rgb_planes + i * l->rgb_stride * avctx->height; - for (j = 0; j < avctx->height; j++) { - for (i = 0; i < avctx->width; i++) { - uint8_t r, g, b, a; - r = srcs[0][i]; - g = srcs[1][i]; - b = srcs[2][i]; - r += g; - b += g; - if (frametype == FRAME_ARITH_RGBA) { - a = srcs[3][i]; - AV_WN32(dst + i * 4, MKBETAG(a, r, g, b)); - } else { - dst[i * 3 + 0] = r; - dst[i * 3 + 1] = g; - dst[i * 3 + 2] = b; - } - } - dst += p->linesize[0]; - for (i = 0; i < planes; i++) - srcs[i] += l->rgb_stride; + for (i = 0; i < avctx->height; i++) { + l->llviddsp.add_bytes(p->data[0] + i * p->linesize[0], p->data[1] + i * p->linesize[1], avctx->width); + l->llviddsp.add_bytes(p->data[2] + i * p->linesize[2], p->data[1] + i * p->linesize[1], avctx->width); } + FFSWAP(uint8_t*, p->data[0], p->data[1]); + FFSWAP(int, p->linesize[0], p->linesize[1]); + FFSWAP(uint8_t*, p->data[2], p->data[1]); + FFSWAP(int, p->linesize[2], p->linesize[1]); break; case FRAME_ARITH_YUY2: avctx->pix_fmt = AV_PIX_FMT_YUV422P; @@ -691,9 +669,6 @@ static int lag_decode_frame(AVCodecContext *avctx, if ((ret = ff_thread_get_buffer(avctx, &frame, 0)) < 0) return ret; - if (buf_size <= offset_ry || buf_size <= offset_gu || buf_size <= offset_bv) { - return AVERROR_INVALIDDATA; - } if (offset_ry >= buf_size || offset_gu >= buf_size || @@ -744,15 +719,6 @@ static av_cold int lag_decode_init_thread_copy(AVCodecContext *avctx) } #endif -static av_cold int lag_decode_end(AVCodecContext *avctx) -{ - LagarithContext *l = avctx->priv_data; - - av_freep(&l->rgb_planes); - - return 0; -} - AVCodec ff_lagarith_decoder = { .name = "lagarith", .long_name = NULL_IF_CONFIG_SMALL("Lagarith lossless"), @@ -761,7 +727,6 @@ AVCodec ff_lagarith_decoder = { .priv_data_size = sizeof(LagarithContext), .init = lag_decode_init, .init_thread_copy = ONLY_IF_THREADS_ENABLED(lag_decode_init_thread_copy), - .close = lag_decode_end, .decode = lag_decode_frame, .capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_FRAME_THREADS, }; diff --git a/libavcodec/libaomdec.c b/libavcodec/libaomdec.c index 6a2de6d47..a72ac984e 100644 --- a/libavcodec/libaomdec.c +++ b/libavcodec/libaomdec.c @@ -42,8 +42,7 @@ static av_cold int aom_init(AVCodecContext *avctx, { AV1DecodeContext *ctx = avctx->priv_data; struct aom_codec_dec_cfg deccfg = { - /* token partitions+1 would be a decent choice */ - .threads = FFMIN(avctx->thread_count, 16) + .threads = FFMIN(avctx->thread_count ? avctx->thread_count : av_cpu_count(), 16) }; av_log(avctx, AV_LOG_INFO, "%s\n", aom_codec_version_str()); diff --git a/libavcodec/libaomenc.c b/libavcodec/libaomenc.c index 3e1bbb5af..9b4fb3b4e 100644 --- a/libavcodec/libaomenc.c +++ b/libavcodec/libaomenc.c @@ -34,6 +34,7 @@ #include "libavutil/opt.h" #include "libavutil/pixdesc.h" +#include "av1.h" #include "avcodec.h" #include "internal.h" #include "profiles.h" @@ -50,34 +51,84 @@ struct FrameListData { unsigned long duration; /**< duration to show frame (in timebase units) */ uint32_t flags; /**< flags for this frame */ + uint64_t sse[4]; + int have_sse; /**< true if we have pending sse[] */ + uint64_t frame_number; struct FrameListData *next; }; typedef struct AOMEncoderContext { AVClass *class; + AVBSFContext *bsf; struct aom_codec_ctx encoder; struct aom_image rawimg; struct aom_fixed_buf twopass_stats; struct FrameListData *coded_frame_list; int cpu_used; int auto_alt_ref; + int arnr_max_frames; + int arnr_strength; + int aq_mode; int lag_in_frames; int error_resilient; int crf; int static_thresh; int drop_threshold; - int noise_sensitivity; + int denoise_noise_level; + int denoise_block_size; + uint64_t sse[4]; + int have_sse; /**< true if we have pending sse[] */ + uint64_t frame_number; + int rc_undershoot_pct; + int rc_overshoot_pct; + int minsection_pct; + int maxsection_pct; + int frame_parallel; + int tile_cols, tile_rows; + int tile_cols_log2, tile_rows_log2; + aom_superblock_size_t superblock_size; + int uniform_tiles; + int row_mt; + int enable_cdef; + int enable_global_motion; + int enable_intrabc; } AOMContext; static const char *const ctlidstr[] = { [AOME_SET_CPUUSED] = "AOME_SET_CPUUSED", [AOME_SET_CQ_LEVEL] = "AOME_SET_CQ_LEVEL", [AOME_SET_ENABLEAUTOALTREF] = "AOME_SET_ENABLEAUTOALTREF", + [AOME_SET_ARNR_MAXFRAMES] = "AOME_SET_ARNR_MAXFRAMES", + [AOME_SET_ARNR_STRENGTH] = "AOME_SET_ARNR_STRENGTH", [AOME_SET_STATIC_THRESHOLD] = "AOME_SET_STATIC_THRESHOLD", [AV1E_SET_COLOR_RANGE] = "AV1E_SET_COLOR_RANGE", [AV1E_SET_COLOR_PRIMARIES] = "AV1E_SET_COLOR_PRIMARIES", [AV1E_SET_MATRIX_COEFFICIENTS] = "AV1E_SET_MATRIX_COEFFICIENTS", [AV1E_SET_TRANSFER_CHARACTERISTICS] = "AV1E_SET_TRANSFER_CHARACTERISTICS", + [AV1E_SET_AQ_MODE] = "AV1E_SET_AQ_MODE", + [AV1E_SET_FRAME_PARALLEL_DECODING] = "AV1E_SET_FRAME_PARALLEL_DECODING", + [AV1E_SET_SUPERBLOCK_SIZE] = "AV1E_SET_SUPERBLOCK_SIZE", + [AV1E_SET_TILE_COLUMNS] = "AV1E_SET_TILE_COLUMNS", + [AV1E_SET_TILE_ROWS] = "AV1E_SET_TILE_ROWS", +#ifdef AOM_CTRL_AV1E_SET_ROW_MT + [AV1E_SET_ROW_MT] = "AV1E_SET_ROW_MT", +#endif +#ifdef AOM_CTRL_AV1E_SET_DENOISE_NOISE_LEVEL + [AV1E_SET_DENOISE_NOISE_LEVEL] = "AV1E_SET_DENOISE_NOISE_LEVEL", +#endif +#ifdef AOM_CTRL_AV1E_SET_DENOISE_BLOCK_SIZE + [AV1E_SET_DENOISE_BLOCK_SIZE] = "AV1E_SET_DENOISE_BLOCK_SIZE", +#endif +#ifdef AOM_CTRL_AV1E_SET_MAX_REFERENCE_FRAMES + [AV1E_SET_MAX_REFERENCE_FRAMES] = "AV1E_SET_MAX_REFERENCE_FRAMES", +#endif +#ifdef AOM_CTRL_AV1E_SET_ENABLE_GLOBAL_MOTION + [AV1E_SET_ENABLE_GLOBAL_MOTION] = "AV1E_SET_ENABLE_GLOBAL_MOTION", +#endif +#ifdef AOM_CTRL_AV1E_SET_ENABLE_INTRABC + [AV1E_SET_ENABLE_INTRABC] = "AV1E_SET_ENABLE_INTRABC", +#endif + [AV1E_SET_ENABLE_CDEF] = "AV1E_SET_ENABLE_CDEF", }; static av_cold void log_encoder_error(AVCodecContext *avctx, const char *desc) @@ -142,6 +193,10 @@ static av_cold void dump_enc_cfg(AVCodecContext *avctx, width, "kf_mode:", cfg->kf_mode, width, "kf_min_dist:", cfg->kf_min_dist, width, "kf_max_dist:", cfg->kf_max_dist); + av_log(avctx, level, "tile settings\n" + " %*s%d\n %*s%d\n", + width, "tile_width_count:", cfg->tile_width_count, + width, "tile_height_count:", cfg->tile_height_count); av_log(avctx, level, "\n"); } @@ -173,7 +228,12 @@ static av_cold void free_frame_list(struct FrameListData *list) } static av_cold int codecctl_int(AVCodecContext *avctx, - enum aome_enc_control_id id, int val) +#ifdef UENUM1BYTE + aome_enc_control_id id, +#else + enum aome_enc_control_id id, +#endif + int val) { AOMContext *ctx = avctx->priv_data; char buf[80]; @@ -202,6 +262,7 @@ static av_cold int aom_free(AVCodecContext *avctx) av_freep(&ctx->twopass_stats.buf); av_freep(&avctx->stats_out); free_frame_list(ctx->coded_frame_list); + av_bsf_free(&ctx->bsf); return 0; } @@ -268,7 +329,7 @@ static int set_pix_fmt(AVCodecContext *avctx, aom_codec_caps_t codec_caps, static void set_color_range(AVCodecContext *avctx) { - enum aom_color_range aom_cr; + aom_color_range_t aom_cr; switch (avctx->color_range) { case AVCOL_RANGE_UNSPECIFIED: case AVCOL_RANGE_MPEG: aom_cr = AOM_CR_STUDIO_RANGE; break; @@ -282,12 +343,180 @@ static void set_color_range(AVCodecContext *avctx) codecctl_int(avctx, AV1E_SET_COLOR_RANGE, aom_cr); } +static int count_uniform_tiling(int dim, int sb_size, int tiles_log2) +{ + int sb_dim = (dim + sb_size - 1) / sb_size; + int tile_dim = (sb_dim + (1 << tiles_log2) - 1) >> tiles_log2; + av_assert0(tile_dim > 0); + return (sb_dim + tile_dim - 1) / tile_dim; +} + +static int choose_tiling(AVCodecContext *avctx, + struct aom_codec_enc_cfg *enccfg) +{ + AOMContext *ctx = avctx->priv_data; + int sb_128x128_possible, sb_size, sb_width, sb_height; + int uniform_rows, uniform_cols; + int uniform_64x64_possible, uniform_128x128_possible; + int tile_size, rounding, i; + + if (ctx->tile_cols_log2 >= 0) + ctx->tile_cols = 1 << ctx->tile_cols_log2; + if (ctx->tile_rows_log2 >= 0) + ctx->tile_rows = 1 << ctx->tile_rows_log2; + + if (ctx->tile_cols == 0) { + ctx->tile_cols = (avctx->width + AV1_MAX_TILE_WIDTH - 1) / + AV1_MAX_TILE_WIDTH; + if (ctx->tile_cols > 1) { + av_log(avctx, AV_LOG_DEBUG, "Automatically using %d tile " + "columns to fill width.\n", ctx->tile_cols); + } + } + av_assert0(ctx->tile_cols > 0); + if (ctx->tile_rows == 0) { + int max_tile_width = + FFALIGN((FFALIGN(avctx->width, 128) + + ctx->tile_cols - 1) / ctx->tile_cols, 128); + ctx->tile_rows = + (max_tile_width * FFALIGN(avctx->height, 128) + + AV1_MAX_TILE_AREA - 1) / AV1_MAX_TILE_AREA; + if (ctx->tile_rows > 1) { + av_log(avctx, AV_LOG_DEBUG, "Automatically using %d tile " + "rows to fill area.\n", ctx->tile_rows); + } + } + av_assert0(ctx->tile_rows > 0); + + if ((avctx->width + 63) / 64 < ctx->tile_cols || + (avctx->height + 63) / 64 < ctx->tile_rows) { + av_log(avctx, AV_LOG_ERROR, "Invalid tile sizing: frame not " + "large enough to fit specified tile arrangement.\n"); + return AVERROR(EINVAL); + } + if (ctx->tile_cols > AV1_MAX_TILE_COLS || + ctx->tile_rows > AV1_MAX_TILE_ROWS) { + av_log(avctx, AV_LOG_ERROR, "Invalid tile sizing: AV1 does " + "not allow more than %dx%d tiles.\n", + AV1_MAX_TILE_COLS, AV1_MAX_TILE_ROWS); + return AVERROR(EINVAL); + } + if (avctx->width / ctx->tile_cols > AV1_MAX_TILE_WIDTH) { + av_log(avctx, AV_LOG_ERROR, "Invalid tile sizing: AV1 does " + "not allow tiles of width greater than %d.\n", + AV1_MAX_TILE_WIDTH); + return AVERROR(EINVAL); + } + + ctx->superblock_size = AOM_SUPERBLOCK_SIZE_DYNAMIC; + + if (ctx->tile_cols == 1 && ctx->tile_rows == 1) { + av_log(avctx, AV_LOG_DEBUG, "Using a single tile.\n"); + return 0; + } + + sb_128x128_possible = + (avctx->width + 127) / 128 >= ctx->tile_cols && + (avctx->height + 127) / 128 >= ctx->tile_rows; + + ctx->tile_cols_log2 = ctx->tile_cols == 1 ? 0 : + av_log2(ctx->tile_cols - 1) + 1; + ctx->tile_rows_log2 = ctx->tile_rows == 1 ? 0 : + av_log2(ctx->tile_rows - 1) + 1; + + uniform_cols = count_uniform_tiling(avctx->width, + 64, ctx->tile_cols_log2); + uniform_rows = count_uniform_tiling(avctx->height, + 64, ctx->tile_rows_log2); + av_log(avctx, AV_LOG_DEBUG, "Uniform with 64x64 superblocks " + "-> %dx%d tiles.\n", uniform_cols, uniform_rows); + uniform_64x64_possible = uniform_cols == ctx->tile_cols && + uniform_rows == ctx->tile_rows; + + if (sb_128x128_possible) { + uniform_cols = count_uniform_tiling(avctx->width, + 128, ctx->tile_cols_log2); + uniform_rows = count_uniform_tiling(avctx->height, + 128, ctx->tile_rows_log2); + av_log(avctx, AV_LOG_DEBUG, "Uniform with 128x128 superblocks " + "-> %dx%d tiles.\n", uniform_cols, uniform_rows); + uniform_128x128_possible = uniform_cols == ctx->tile_cols && + uniform_rows == ctx->tile_rows; + } else { + av_log(avctx, AV_LOG_DEBUG, "128x128 superblocks not possible.\n"); + uniform_128x128_possible = 0; + } + + ctx->uniform_tiles = 1; + if (uniform_64x64_possible && uniform_128x128_possible) { + av_log(avctx, AV_LOG_DEBUG, "Using uniform tiling with dynamic " + "superblocks (tile_cols_log2 = %d, tile_rows_log2 = %d).\n", + ctx->tile_cols_log2, ctx->tile_rows_log2); + return 0; + } + if (uniform_64x64_possible && !sb_128x128_possible) { + av_log(avctx, AV_LOG_DEBUG, "Using uniform tiling with 64x64 " + "superblocks (tile_cols_log2 = %d, tile_rows_log2 = %d).\n", + ctx->tile_cols_log2, ctx->tile_rows_log2); + ctx->superblock_size = AOM_SUPERBLOCK_SIZE_64X64; + return 0; + } + if (uniform_128x128_possible) { + av_log(avctx, AV_LOG_DEBUG, "Using uniform tiling with 128x128 " + "superblocks (tile_cols_log2 = %d, tile_rows_log2 = %d).\n", + ctx->tile_cols_log2, ctx->tile_rows_log2); + ctx->superblock_size = AOM_SUPERBLOCK_SIZE_128X128; + return 0; + } + ctx->uniform_tiles = 0; + + if (sb_128x128_possible) { + sb_size = 128; + ctx->superblock_size = AOM_SUPERBLOCK_SIZE_128X128; + } else { + sb_size = 64; + ctx->superblock_size = AOM_SUPERBLOCK_SIZE_64X64; + } + av_log(avctx, AV_LOG_DEBUG, "Using fixed tiling with %dx%d " + "superblocks (tile_cols = %d, tile_rows = %d).\n", + sb_size, sb_size, ctx->tile_cols, ctx->tile_rows); + + enccfg->tile_width_count = ctx->tile_cols; + enccfg->tile_height_count = ctx->tile_rows; + + sb_width = (avctx->width + sb_size - 1) / sb_size; + sb_height = (avctx->height + sb_size - 1) / sb_size; + + tile_size = sb_width / ctx->tile_cols; + rounding = sb_width % ctx->tile_cols; + for (i = 0; i < ctx->tile_cols; i++) { + enccfg->tile_widths[i] = tile_size + + (i < rounding / 2 || + i > ctx->tile_cols - 1 - (rounding + 1) / 2); + } + + tile_size = sb_height / ctx->tile_rows; + rounding = sb_height % ctx->tile_rows; + for (i = 0; i < ctx->tile_rows; i++) { + enccfg->tile_heights[i] = tile_size + + (i < rounding / 2 || + i > ctx->tile_rows - 1 - (rounding + 1) / 2); + } + + return 0; +} + static av_cold int aom_init(AVCodecContext *avctx, const struct aom_codec_iface *iface) { AOMContext *ctx = avctx->priv_data; struct aom_codec_enc_cfg enccfg = { 0 }; +#ifdef AOM_FRAME_IS_INTRAONLY + aom_codec_flags_t flags = + (avctx->flags & AV_CODEC_FLAG_PSNR) ? AOM_CODEC_USE_PSNR : 0; +#else aom_codec_flags_t flags = 0; +#endif AVCPBProperties *cpb_props; int res; aom_img_fmt_t img_fmt; @@ -317,7 +546,8 @@ static av_cold int aom_init(AVCodecContext *avctx, enccfg.g_h = avctx->height; enccfg.g_timebase.num = avctx->time_base.num; enccfg.g_timebase.den = avctx->time_base.den; - enccfg.g_threads = avctx->thread_count; + enccfg.g_threads = + FFMIN(avctx->thread_count ? avctx->thread_count : av_cpu_count(), 64); if (ctx->lag_in_frames >= 0) enccfg.g_lag_in_frames = ctx->lag_in_frames; @@ -370,10 +600,14 @@ static av_cold int aom_init(AVCodecContext *avctx, // 0-100 (0 => CBR, 100 => VBR) enccfg.rc_2pass_vbr_bias_pct = round(avctx->qcompress * 100); - if (avctx->bit_rate) + if (ctx->minsection_pct >= 0) + enccfg.rc_2pass_vbr_minsection_pct = ctx->minsection_pct; + else if (avctx->bit_rate) enccfg.rc_2pass_vbr_minsection_pct = avctx->rc_min_rate * 100LL / avctx->bit_rate; - if (avctx->rc_max_rate) + if (ctx->maxsection_pct >= 0) + enccfg.rc_2pass_vbr_maxsection_pct = ctx->maxsection_pct; + else if (avctx->rc_max_rate) enccfg.rc_2pass_vbr_maxsection_pct = avctx->rc_max_rate * 100LL / avctx->bit_rate; @@ -385,6 +619,11 @@ static av_cold int aom_init(AVCodecContext *avctx, avctx->rc_initial_buffer_occupancy * 1000LL / avctx->bit_rate; enccfg.rc_buf_optimal_sz = enccfg.rc_buf_sz * 5 / 6; + if (ctx->rc_undershoot_pct >= 0) + enccfg.rc_undershoot_pct = ctx->rc_undershoot_pct; + if (ctx->rc_overshoot_pct >= 0) + enccfg.rc_overshoot_pct = ctx->rc_overshoot_pct; + // _enc_init() will balk if kf_min_dist differs from max w/AOM_KF_AUTO if (avctx->keyint_min >= 0 && avctx->keyint_min == avctx->gop_size) enccfg.kf_min_dist = avctx->keyint_min; @@ -429,6 +668,10 @@ static av_cold int aom_init(AVCodecContext *avctx, enccfg.g_error_resilient = ctx->error_resilient; + res = choose_tiling(avctx, &enccfg); + if (res < 0) + return res; + dump_enc_cfg(avctx, &enccfg); /* Construct Encoder Context */ res = aom_codec_enc_init(&ctx->encoder, iface, &enccfg, flags); @@ -442,7 +685,12 @@ static av_cold int aom_init(AVCodecContext *avctx, codecctl_int(avctx, AOME_SET_CPUUSED, ctx->cpu_used); if (ctx->auto_alt_ref >= 0) codecctl_int(avctx, AOME_SET_ENABLEAUTOALTREF, ctx->auto_alt_ref); - + if (ctx->arnr_max_frames >= 0) + codecctl_int(avctx, AOME_SET_ARNR_MAXFRAMES, ctx->arnr_max_frames); + if (ctx->arnr_strength >= 0) + codecctl_int(avctx, AOME_SET_ARNR_STRENGTH, ctx->arnr_strength); + if (ctx->enable_cdef >= 0) + codecctl_int(avctx, AV1E_SET_ENABLE_CDEF, ctx->enable_cdef); codecctl_int(avctx, AOME_SET_STATIC_THRESHOLD, ctx->static_thresh); if (ctx->crf >= 0) codecctl_int(avctx, AOME_SET_CQ_LEVEL, ctx->crf); @@ -450,8 +698,44 @@ static av_cold int aom_init(AVCodecContext *avctx, codecctl_int(avctx, AV1E_SET_COLOR_PRIMARIES, avctx->color_primaries); codecctl_int(avctx, AV1E_SET_MATRIX_COEFFICIENTS, avctx->colorspace); codecctl_int(avctx, AV1E_SET_TRANSFER_CHARACTERISTICS, avctx->color_trc); + if (ctx->aq_mode >= 0) + codecctl_int(avctx, AV1E_SET_AQ_MODE, ctx->aq_mode); + if (ctx->frame_parallel >= 0) + codecctl_int(avctx, AV1E_SET_FRAME_PARALLEL_DECODING, ctx->frame_parallel); set_color_range(avctx); + codecctl_int(avctx, AV1E_SET_SUPERBLOCK_SIZE, ctx->superblock_size); + if (ctx->uniform_tiles) { + codecctl_int(avctx, AV1E_SET_TILE_COLUMNS, ctx->tile_cols_log2); + codecctl_int(avctx, AV1E_SET_TILE_ROWS, ctx->tile_rows_log2); + } + +#ifdef AOM_CTRL_AV1E_SET_DENOISE_NOISE_LEVEL + if (ctx->denoise_noise_level >= 0) + codecctl_int(avctx, AV1E_SET_DENOISE_NOISE_LEVEL, ctx->denoise_noise_level); +#endif +#ifdef AOM_CTRL_AV1E_SET_DENOISE_BLOCK_SIZE + if (ctx->denoise_block_size >= 0) + codecctl_int(avctx, AV1E_SET_DENOISE_BLOCK_SIZE, ctx->denoise_block_size); +#endif +#ifdef AOM_CTRL_AV1E_SET_ENABLE_GLOBAL_MOTION + if (ctx->enable_global_motion >= 0) + codecctl_int(avctx, AV1E_SET_ENABLE_GLOBAL_MOTION, ctx->enable_global_motion); +#endif +#ifdef AOM_CTRL_AV1E_SET_MAX_REFERENCE_FRAMES + if (avctx->refs >= 3) { + codecctl_int(avctx, AV1E_SET_MAX_REFERENCE_FRAMES, avctx->refs); + } +#endif +#ifdef AOM_CTRL_AV1E_SET_ROW_MT + if (ctx->row_mt >= 0) + codecctl_int(avctx, AV1E_SET_ROW_MT, ctx->row_mt); +#endif +#ifdef AOM_CTRL_AV1E_SET_ENABLE_INTRABC + if (ctx->enable_intrabc >= 0) + codecctl_int(avctx, AV1E_SET_ENABLE_INTRABC, ctx->enable_intrabc); +#endif + // provide dummy value to initialize wrapper, values will be updated each _encode() aom_img_wrap(&ctx->rawimg, img_fmt, avctx->width, avctx->height, 1, (unsigned char*)1); @@ -463,6 +747,28 @@ static av_cold int aom_init(AVCodecContext *avctx, if (!cpb_props) return AVERROR(ENOMEM); + if (avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER) { + const AVBitStreamFilter *filter = av_bsf_get_by_name("extract_extradata"); + int ret; + + if (!filter) { + av_log(avctx, AV_LOG_ERROR, "extract_extradata bitstream filter " + "not found. This is a bug, please report it.\n"); + return AVERROR_BUG; + } + ret = av_bsf_alloc(filter, &ctx->bsf); + if (ret < 0) + return ret; + + ret = avcodec_parameters_from_context(ctx->bsf->par_in, avctx); + if (ret < 0) + return ret; + + ret = av_bsf_init(ctx->bsf); + if (ret < 0) + return ret; + } + if (enccfg.rc_end_usage == AOM_CBR || enccfg.g_pass != AOM_RC_ONE_PASS) { cpb_props->max_bitrate = avctx->rc_max_rate; @@ -474,7 +780,8 @@ static av_cold int aom_init(AVCodecContext *avctx, return 0; } -static inline void cx_pktcpy(struct FrameListData *dst, +static inline void cx_pktcpy(AOMContext *ctx, + struct FrameListData *dst, const struct aom_codec_cx_pkt *src) { dst->pts = src->data.frame.pts; @@ -482,6 +789,17 @@ static inline void cx_pktcpy(struct FrameListData *dst, dst->flags = src->data.frame.flags; dst->sz = src->data.frame.sz; dst->buf = src->data.frame.buf; +#ifdef AOM_FRAME_IS_INTRAONLY + dst->have_sse = 0; + dst->frame_number = ++ctx->frame_number; + dst->have_sse = ctx->have_sse; + if (ctx->have_sse) { + /* associate last-seen SSE to the frame. */ + /* Transfers ownership from ctx to dst. */ + memcpy(dst->sse, ctx->sse, sizeof(dst->sse)); + ctx->have_sse = 0; + } +#endif } /** @@ -494,6 +812,8 @@ static inline void cx_pktcpy(struct FrameListData *dst, static int storeframe(AVCodecContext *avctx, struct FrameListData *cx_frame, AVPacket *pkt) { + AOMContext *ctx = avctx->priv_data; + int av_unused pict_type; int ret = ff_alloc_packet2(avctx, pkt, cx_frame->sz, 0); if (ret < 0) { av_log(avctx, AV_LOG_ERROR, @@ -503,8 +823,43 @@ static int storeframe(AVCodecContext *avctx, struct FrameListData *cx_frame, memcpy(pkt->data, cx_frame->buf, pkt->size); pkt->pts = pkt->dts = cx_frame->pts; - if (!!(cx_frame->flags & AOM_FRAME_IS_KEY)) + if (!!(cx_frame->flags & AOM_FRAME_IS_KEY)) { pkt->flags |= AV_PKT_FLAG_KEY; +#ifdef AOM_FRAME_IS_INTRAONLY + pict_type = AV_PICTURE_TYPE_I; + } else if (cx_frame->flags & AOM_FRAME_IS_INTRAONLY) { + pict_type = AV_PICTURE_TYPE_I; + } else { + pict_type = AV_PICTURE_TYPE_P; + } + + ff_side_data_set_encoder_stats(pkt, 0, cx_frame->sse + 1, + cx_frame->have_sse ? 3 : 0, pict_type); + + if (cx_frame->have_sse) { + int i; + for (i = 0; i < 3; ++i) { + avctx->error[i] += cx_frame->sse[i + 1]; + } + cx_frame->have_sse = 0; +#endif + } + + if (avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER) { + ret = av_bsf_send_packet(ctx->bsf, pkt); + if (ret < 0) { + av_log(avctx, AV_LOG_ERROR, "extract_extradata filter " + "failed to send input packet\n"); + return ret; + } + ret = av_bsf_receive_packet(ctx->bsf, pkt); + + if (ret < 0) { + av_log(avctx, AV_LOG_ERROR, "extract_extradata filter " + "failed to receive output packet\n"); + return ret; + } + } return pkt->size; } @@ -544,7 +899,7 @@ static int queue_frames(AVCodecContext *avctx, AVPacket *pkt_out) /* avoid storing the frame when the list is empty and we haven't yet * provided a frame for output */ av_assert0(!ctx->coded_frame_list); - cx_pktcpy(&cx_frame, pkt); + cx_pktcpy(ctx, &cx_frame, pkt); size = storeframe(avctx, &cx_frame, pkt_out); if (size < 0) return size; @@ -557,7 +912,7 @@ static int queue_frames(AVCodecContext *avctx, AVPacket *pkt_out) "Frame queue element alloc failed\n"); return AVERROR(ENOMEM); } - cx_pktcpy(cx_frame, pkt); + cx_pktcpy(ctx, cx_frame, pkt); cx_frame->buf = av_malloc(cx_frame->sz); if (!cx_frame->buf) { @@ -587,7 +942,18 @@ static int queue_frames(AVCodecContext *avctx, AVPacket *pkt_out) stats->sz += pkt->data.twopass_stats.sz; break; } - case AOM_CODEC_PSNR_PKT: // FIXME add support for AV_CODEC_FLAG_PSNR +#ifdef AOM_FRAME_IS_INTRAONLY + case AOM_CODEC_PSNR_PKT: + { + av_assert0(!ctx->have_sse); + ctx->sse[0] = pkt->data.psnr.sse[0]; + ctx->sse[1] = pkt->data.psnr.sse[1]; + ctx->sse[2] = pkt->data.psnr.sse[2]; + ctx->sse[3] = pkt->data.psnr.sse[3]; + ctx->have_sse = 1; + break; + } +#endif case AOM_CODEC_CUSTOM_PKT: // ignore unsupported/unrecognized packet types break; @@ -690,21 +1056,42 @@ static av_cold int av1_init(AVCodecContext *avctx) #define OFFSET(x) offsetof(AOMContext, x) #define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM static const AVOption options[] = { - { "cpu-used", "Quality/Speed ratio modifier", OFFSET(cpu_used), AV_OPT_TYPE_INT, {.i64 = 1}, -8, 8, VE}, + { "cpu-used", "Quality/Speed ratio modifier", OFFSET(cpu_used), AV_OPT_TYPE_INT, {.i64 = 1}, 0, 8, VE}, { "auto-alt-ref", "Enable use of alternate reference " "frames (2-pass only)", OFFSET(auto_alt_ref), AV_OPT_TYPE_INT, {.i64 = -1}, -1, 2, VE}, { "lag-in-frames", "Number of frames to look ahead at for " "alternate reference frame selection", OFFSET(lag_in_frames), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, VE}, + { "arnr-max-frames", "altref noise reduction max frame count", OFFSET(arnr_max_frames), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, VE}, + { "arnr-strength", "altref noise reduction filter strength", OFFSET(arnr_strength), AV_OPT_TYPE_INT, {.i64 = -1}, -1, 6, VE}, + { "aq-mode", "adaptive quantization mode", OFFSET(aq_mode), AV_OPT_TYPE_INT, {.i64 = -1}, -1, 4, VE, "aq_mode"}, + { "none", "Aq not used", 0, AV_OPT_TYPE_CONST, {.i64 = 0}, 0, 0, VE, "aq_mode"}, + { "variance", "Variance based Aq", 0, AV_OPT_TYPE_CONST, {.i64 = 1}, 0, 0, VE, "aq_mode"}, + { "complexity", "Complexity based Aq", 0, AV_OPT_TYPE_CONST, {.i64 = 2}, 0, 0, VE, "aq_mode"}, + { "cyclic", "Cyclic Refresh Aq", 0, AV_OPT_TYPE_CONST, {.i64 = 3}, 0, 0, VE, "aq_mode"}, { "error-resilience", "Error resilience configuration", OFFSET(error_resilient), AV_OPT_TYPE_FLAGS, {.i64 = 0}, INT_MIN, INT_MAX, VE, "er"}, { "default", "Improve resiliency against losses of whole frames", 0, AV_OPT_TYPE_CONST, {.i64 = AOM_ERROR_RESILIENT_DEFAULT}, 0, 0, VE, "er"}, { "crf", "Select the quality for constant quality mode", offsetof(AOMContext, crf), AV_OPT_TYPE_INT, {.i64 = -1}, -1, 63, VE }, { "static-thresh", "A change threshold on blocks below which they will be skipped by the encoder", OFFSET(static_thresh), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, VE }, { "drop-threshold", "Frame drop threshold", offsetof(AOMContext, drop_threshold), AV_OPT_TYPE_INT, {.i64 = 0 }, INT_MIN, INT_MAX, VE }, - { "noise-sensitivity", "Noise sensitivity", OFFSET(noise_sensitivity), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, 4, VE}, - { NULL } + { "denoise-noise-level", "Amount of noise to be removed", OFFSET(denoise_noise_level), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, VE}, + { "denoise-block-size", "Denoise block size ", OFFSET(denoise_block_size), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, VE}, + { "undershoot-pct", "Datarate undershoot (min) target (%)", OFFSET(rc_undershoot_pct), AV_OPT_TYPE_INT, {.i64 = -1}, -1, 100, VE}, + { "overshoot-pct", "Datarate overshoot (max) target (%)", OFFSET(rc_overshoot_pct), AV_OPT_TYPE_INT, {.i64 = -1}, -1, 1000, VE}, + { "minsection-pct", "GOP min bitrate (% of target)", OFFSET(minsection_pct), AV_OPT_TYPE_INT, {.i64 = -1}, -1, 100, VE}, + { "maxsection-pct", "GOP max bitrate (% of target)", OFFSET(maxsection_pct), AV_OPT_TYPE_INT, {.i64 = -1}, -1, 5000, VE}, + { "frame-parallel", "Enable frame parallel decodability features", OFFSET(frame_parallel), AV_OPT_TYPE_BOOL, {.i64 = -1}, -1, 1, VE}, + { "tiles", "Tile columns x rows", OFFSET(tile_cols), AV_OPT_TYPE_IMAGE_SIZE, { .str = NULL }, 0, 0, VE }, + { "tile-columns", "Log2 of number of tile columns to use", OFFSET(tile_cols_log2), AV_OPT_TYPE_INT, {.i64 = -1}, -1, 6, VE}, + { "tile-rows", "Log2 of number of tile rows to use", OFFSET(tile_rows_log2), AV_OPT_TYPE_INT, {.i64 = -1}, -1, 6, VE}, + { "row-mt", "Enable row based multi-threading", OFFSET(row_mt), AV_OPT_TYPE_BOOL, {.i64 = -1}, -1, 1, VE}, + { "enable-cdef", "Enable CDEF filtering", OFFSET(enable_cdef), AV_OPT_TYPE_BOOL, {.i64 = -1}, -1, 1, VE}, + { "enable-global-motion", "Enable global motion", OFFSET(enable_global_motion), AV_OPT_TYPE_BOOL, {.i64 = -1}, -1, 1, VE}, + { "enable-intrabc", "Enable intra block copy prediction mode", OFFSET(enable_intrabc), AV_OPT_TYPE_BOOL, {.i64 = -1}, -1, 1, VE}, + { NULL }, }; static const AVCodecDefault defaults[] = { + { "b", "256*1000" }, { "qmin", "-1" }, { "qmax", "-1" }, { "g", "-1" }, diff --git a/libavcodec/libaribb24.c b/libavcodec/libaribb24.c new file mode 100644 index 000000000..3a5993845 --- /dev/null +++ b/libavcodec/libaribb24.c @@ -0,0 +1,395 @@ +/* + * ARIB STD-B24 caption decoder using the libaribb24 library + * Copyright (c) 2019 Jan Ekström + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "avcodec.h" +#include "libavcodec/ass.h" +#include "libavutil/log.h" +#include "libavutil/opt.h" + +#include +#include +#include + +typedef struct Libaribb24Context { + AVClass *class; + + arib_instance_t *lib_instance; + arib_parser_t *parser; + arib_decoder_t *decoder; + + int read_order; + + char *aribb24_base_path; + unsigned int aribb24_skip_ruby; +} Libaribb24Context; + +static unsigned int get_profile_font_size(int profile) +{ + switch (profile) { + case FF_PROFILE_ARIB_PROFILE_A: + return 36; + case FF_PROFILE_ARIB_PROFILE_C: + return 18; + default: + return 0; + } +} + +static void libaribb24_log(void *p, const char *msg) +{ + av_log((AVCodecContext *)p, AV_LOG_INFO, "%s\n", msg); +} + +static int libaribb24_generate_ass_header(AVCodecContext *avctx) +{ + unsigned int plane_width = 0; + unsigned int plane_height = 0; + unsigned int font_size = 0; + + switch (avctx->profile) { + case FF_PROFILE_ARIB_PROFILE_A: + plane_width = 960; + plane_height = 540; + font_size = get_profile_font_size(avctx->profile); + break; + case FF_PROFILE_ARIB_PROFILE_C: + plane_width = 320; + plane_height = 180; + font_size = get_profile_font_size(avctx->profile); + break; + default: + av_log(avctx, AV_LOG_ERROR, "Unknown or unsupported profile set!\n"); + return AVERROR(EINVAL); + } + + avctx->subtitle_header = av_asprintf( + "[Script Info]\r\n" + "; Script generated by FFmpeg/Lavc%s\r\n" + "ScriptType: v4.00+\r\n" + "PlayResX: %d\r\n" + "PlayResY: %d\r\n" + "\r\n" + "[V4+ Styles]\r\n" + + /* ASSv4 header */ + "Format: Name, " + "Fontname, Fontsize, " + "PrimaryColour, SecondaryColour, OutlineColour, BackColour, " + "Bold, Italic, Underline, StrikeOut, " + "ScaleX, ScaleY, " + "Spacing, Angle, " + "BorderStyle, Outline, Shadow, " + "Alignment, MarginL, MarginR, MarginV, " + "Encoding\r\n" + + "Style: " + "Default," /* Name */ + "%s,%d," /* Font{name,size} */ + "&H%x,&H%x,&H%x,&H%x," /* {Primary,Secondary,Outline,Back}Colour */ + "%d,%d,%d,0," /* Bold, Italic, Underline, StrikeOut */ + "100,100," /* Scale{X,Y} */ + "0,0," /* Spacing, Angle */ + "%d,1,0," /* BorderStyle, Outline, Shadow */ + "%d,10,10,10," /* Alignment, Margin[LRV] */ + "0\r\n" /* Encoding */ + + "\r\n" + "[Events]\r\n" + "Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text\r\n", + !(avctx->flags & AV_CODEC_FLAG_BITEXACT) ? AV_STRINGIFY(LIBAVCODEC_VERSION) : "", + plane_width, plane_height, + ASS_DEFAULT_FONT, font_size, ASS_DEFAULT_COLOR, + ASS_DEFAULT_COLOR, ASS_DEFAULT_BACK_COLOR, ASS_DEFAULT_BACK_COLOR, + -ASS_DEFAULT_BOLD, -ASS_DEFAULT_ITALIC, -ASS_DEFAULT_UNDERLINE, + ASS_DEFAULT_BORDERSTYLE, ASS_DEFAULT_ALIGNMENT); + + if (!avctx->subtitle_header) + return AVERROR(ENOMEM); + + avctx->subtitle_header_size = strlen(avctx->subtitle_header); + + return 0; +} + +static int libaribb24_init(AVCodecContext *avctx) +{ + Libaribb24Context *b24 = avctx->priv_data; + void(* arib_dec_init)(arib_decoder_t* decoder) = NULL; + int ret_code = AVERROR_EXTERNAL; + + if (!(b24->lib_instance = arib_instance_new(avctx))) { + av_log(avctx, AV_LOG_ERROR, "Failed to initialize libaribb24!\n"); + goto init_fail; + } + + if (b24->aribb24_base_path) { + av_log(avctx, AV_LOG_INFO, "Setting the libaribb24 base path to '%s'\n", + b24->aribb24_base_path); + arib_set_base_path(b24->lib_instance, b24->aribb24_base_path); + } + + arib_register_messages_callback(b24->lib_instance, libaribb24_log); + + if (!(b24->parser = arib_get_parser(b24->lib_instance))) { + av_log(avctx, AV_LOG_ERROR, "Failed to initialize libaribb24 PES parser!\n"); + goto init_fail; + } + if (!(b24->decoder = arib_get_decoder(b24->lib_instance))) { + av_log(avctx, AV_LOG_ERROR, "Failed to initialize libaribb24 decoder!\n"); + goto init_fail; + } + + switch (avctx->profile) { + case FF_PROFILE_ARIB_PROFILE_A: + arib_dec_init = arib_initialize_decoder_a_profile; + break; + case FF_PROFILE_ARIB_PROFILE_C: + arib_dec_init = arib_initialize_decoder_c_profile; + break; + default: + av_log(avctx, AV_LOG_ERROR, "Unknown or unsupported profile set!\n"); + ret_code = AVERROR(EINVAL); + goto init_fail; + } + + arib_dec_init(b24->decoder); + + if (libaribb24_generate_ass_header(avctx) < 0) { + ret_code = AVERROR(ENOMEM); + goto init_fail; + } + + return 0; + +init_fail: + if (b24->decoder) + arib_finalize_decoder(b24->decoder); + + if (b24->lib_instance) + arib_instance_destroy(b24->lib_instance); + + return ret_code; +} + +static int libaribb24_close(AVCodecContext *avctx) +{ + Libaribb24Context *b24 = avctx->priv_data; + + if (b24->decoder) + arib_finalize_decoder(b24->decoder); + + if (b24->lib_instance) + arib_instance_destroy(b24->lib_instance); + + return 0; +} + +#define RGB_TO_BGR(c) (((c) & 0xff) << 16 | ((c) & 0xff00) | (((c) >> 16) & 0xff)) + +static int libaribb24_handle_regions(AVCodecContext *avctx, AVSubtitle *sub) +{ + Libaribb24Context *b24 = avctx->priv_data; + const arib_buf_region_t *region = arib_decoder_get_regions(b24->decoder); + unsigned int profile_font_size = get_profile_font_size(avctx->profile); + AVBPrint buf = { 0 }; + int ret = 0; + + av_bprint_init(&buf, 0, AV_BPRINT_SIZE_UNLIMITED); + + while (region) { + ptrdiff_t region_length = region->p_end - region->p_start; + unsigned int ruby_region = + region->i_fontheight == (profile_font_size / 2); + + // ASS requires us to make the colors BGR, so we convert here + int foreground_bgr_color = RGB_TO_BGR(region->i_foreground_color); + int background_bgr_color = RGB_TO_BGR(region->i_background_color); + + if (region_length < 0) { + av_log(avctx, AV_LOG_ERROR, "Invalid negative region length!\n"); + ret = AVERROR_INVALIDDATA; + break; + } + + if (region_length == 0 || (ruby_region && b24->aribb24_skip_ruby)) { + goto next_region; + } + + // color and alpha + if (foreground_bgr_color != ASS_DEFAULT_COLOR) + av_bprintf(&buf, "{\\1c&H%06x&}", foreground_bgr_color); + + if (region->i_foreground_alpha != 0) + av_bprintf(&buf, "{\\1a&H%02x&}", region->i_foreground_alpha); + + if (background_bgr_color != ASS_DEFAULT_BACK_COLOR) + av_bprintf(&buf, "{\\3c&H%06x&}", background_bgr_color); + + if (region->i_background_alpha != 0) + av_bprintf(&buf, "{\\3a&H%02x&}", region->i_background_alpha); + + // font size + if (region->i_fontwidth != profile_font_size || + region->i_fontheight != profile_font_size) { + av_bprintf(&buf, "{\\fscx%"PRId64"\\fscy%"PRId64"}", + av_rescale(region->i_fontwidth, 100, + profile_font_size), + av_rescale(region->i_fontheight, 100, + profile_font_size)); + } + + // TODO: positioning + + av_bprint_append_data(&buf, region->p_start, region_length); + + av_bprintf(&buf, "{\\r}"); + +next_region: + region = region->p_next; + } + + if (!av_bprint_is_complete(&buf)) + ret = AVERROR(ENOMEM); + + if (ret == 0) { + av_log(avctx, AV_LOG_DEBUG, "Styled ASS line: %s\n", + buf.str); + + ret = ff_ass_add_rect(sub, buf.str, b24->read_order++, + 0, NULL, NULL); + } + + av_bprint_finalize(&buf, NULL); + + return ret; +} + +static int libaribb24_decode(AVCodecContext *avctx, void *data, int *got_sub_ptr, AVPacket *pkt) +{ + Libaribb24Context *b24 = avctx->priv_data; + AVSubtitle *sub = data; + size_t parsed_data_size = 0; + size_t decoded_subtitle_size = 0; + const unsigned char *parsed_data = NULL; + char *decoded_subtitle = NULL; + time_t subtitle_duration = 0; + int ret = 0; + + if (pkt->size <= 0) + return pkt->size; + + arib_parse_pes(b24->parser, pkt->data, pkt->size); + + parsed_data = arib_parser_get_data(b24->parser, + &parsed_data_size); + if (!parsed_data || !parsed_data_size) { + av_log(avctx, AV_LOG_DEBUG, "No decode'able data was received from " + "packet (dts: %"PRId64", pts: %"PRId64").\n", + pkt->dts, pkt->pts); + return pkt->size; + } + + decoded_subtitle_size = parsed_data_size * 4; + if (!(decoded_subtitle = av_mallocz(decoded_subtitle_size + 1))) { + av_log(avctx, AV_LOG_ERROR, + "Failed to allocate buffer for decoded subtitle!\n"); + return AVERROR(ENOMEM); + } + + decoded_subtitle_size = arib_decode_buffer(b24->decoder, + parsed_data, + parsed_data_size, + decoded_subtitle, + decoded_subtitle_size); + + subtitle_duration = arib_decoder_get_time(b24->decoder); + + if (avctx->pkt_timebase.num && pkt->pts != AV_NOPTS_VALUE) + sub->pts = av_rescale_q(pkt->pts, + avctx->pkt_timebase, AV_TIME_BASE_Q); + + sub->end_display_time = subtitle_duration ? + av_rescale_q(subtitle_duration, + AV_TIME_BASE_Q, + (AVRational){1, 1000}) : + UINT32_MAX; + + av_log(avctx, AV_LOG_DEBUG, + "Result: '%s' (size: %zu, pkt_pts: %"PRId64", sub_pts: %"PRId64" " + "duration: %"PRIu32", pkt_timebase: %d/%d, time_base: %d/%d')\n", + decoded_subtitle ? decoded_subtitle : "", + decoded_subtitle_size, + pkt->pts, sub->pts, + sub->end_display_time, + avctx->pkt_timebase.num, avctx->pkt_timebase.den, + avctx->time_base.num, avctx->time_base.den); + + if (decoded_subtitle) + ret = libaribb24_handle_regions(avctx, sub); + + *got_sub_ptr = sub->num_rects > 0; + + av_free(decoded_subtitle); + + // flush the region buffers, otherwise the linked list keeps getting + // longer and longer... + arib_finalize_decoder(b24->decoder); + + return ret < 0 ? ret : pkt->size; +} + +static void libaribb24_flush(AVCodecContext *avctx) +{ + Libaribb24Context *b24 = avctx->priv_data; + if (!(avctx->flags2 & AV_CODEC_FLAG2_RO_FLUSH_NOOP)) + b24->read_order = 0; +} + +#define OFFSET(x) offsetof(Libaribb24Context, x) +#define SD AV_OPT_FLAG_SUBTITLE_PARAM | AV_OPT_FLAG_DECODING_PARAM +static const AVOption options[] = { + { "aribb24-base-path", "set the base path for the libaribb24 library", + OFFSET(aribb24_base_path), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, SD }, + { "aribb24-skip-ruby-text", "skip ruby text blocks during decoding", + OFFSET(aribb24_skip_ruby), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, SD }, + { NULL } +}; + +static const AVClass aribb24_class = { + .class_name = "libaribb24 decoder", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; + +AVCodec ff_libaribb24_decoder = { + .name = "libaribb24", + .long_name = NULL_IF_CONFIG_SMALL("libaribb24 ARIB STD-B24 caption decoder"), + .type = AVMEDIA_TYPE_SUBTITLE, + .id = AV_CODEC_ID_ARIB_CAPTION, + .priv_data_size = sizeof(Libaribb24Context), + .init = libaribb24_init, + .close = libaribb24_close, + .decode = libaribb24_decode, + .flush = libaribb24_flush, + .priv_class= &aribb24_class, + .wrapper_name = "libaribb24", +}; diff --git a/libavcodec/libdav1d.c b/libavcodec/libdav1d.c new file mode 100644 index 000000000..12c63245f --- /dev/null +++ b/libavcodec/libdav1d.c @@ -0,0 +1,369 @@ +/* + * Copyright (c) 2018 Ronald S. Bultje + * Copyright (c) 2018 James Almer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include "libavutil/avassert.h" +#include "libavutil/mastering_display_metadata.h" +#include "libavutil/imgutils.h" +#include "libavutil/opt.h" + +#include "avcodec.h" +#include "decode.h" +#include "internal.h" + +typedef struct Libdav1dContext { + AVClass *class; + Dav1dContext *c; + AVBufferPool *pool; + int pool_size; + + Dav1dData data; + int tile_threads; + int frame_threads; + int apply_grain; +} Libdav1dContext; + +static const enum AVPixelFormat pix_fmt[][3] = { + [DAV1D_PIXEL_LAYOUT_I400] = { AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY10, AV_PIX_FMT_GRAY12 }, + [DAV1D_PIXEL_LAYOUT_I420] = { AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV420P10, AV_PIX_FMT_YUV420P12 }, + [DAV1D_PIXEL_LAYOUT_I422] = { AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV422P10, AV_PIX_FMT_YUV422P12 }, + [DAV1D_PIXEL_LAYOUT_I444] = { AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUV444P10, AV_PIX_FMT_YUV444P12 }, +}; + +static const enum AVPixelFormat pix_fmt_rgb[3] = { + AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRP10, AV_PIX_FMT_GBRP12, +}; + +static void libdav1d_log_callback(void *opaque, const char *fmt, va_list vl) +{ + AVCodecContext *c = opaque; + + av_vlog(c, AV_LOG_ERROR, fmt, vl); +} + +static int libdav1d_picture_allocator(Dav1dPicture *p, void *cookie) +{ + Libdav1dContext *dav1d = cookie; + enum AVPixelFormat format = pix_fmt[p->p.layout][p->seq_hdr->hbd]; + int ret, linesize[4], h = FFALIGN(p->p.h, 128); + uint8_t *aligned_ptr, *data[4]; + AVBufferRef *buf; + + ret = av_image_fill_arrays(data, linesize, NULL, format, FFALIGN(p->p.w, 128), + h, DAV1D_PICTURE_ALIGNMENT); + if (ret < 0) + return ret; + + if (ret != dav1d->pool_size) { + av_buffer_pool_uninit(&dav1d->pool); + // Use twice the amount of required padding bytes for aligned_ptr below. + dav1d->pool = av_buffer_pool_init(ret + DAV1D_PICTURE_ALIGNMENT * 2, NULL); + if (!dav1d->pool) { + dav1d->pool_size = 0; + return AVERROR(ENOMEM); + } + dav1d->pool_size = ret; + } + buf = av_buffer_pool_get(dav1d->pool); + if (!buf) + return AVERROR(ENOMEM); + + // libdav1d requires DAV1D_PICTURE_ALIGNMENT aligned buffers, which av_malloc() + // doesn't guarantee for example when AVX is disabled at configure time. + // Use the extra DAV1D_PICTURE_ALIGNMENT padding bytes in the buffer to align it + // if required. + aligned_ptr = (uint8_t *)FFALIGN((uintptr_t)buf->data, DAV1D_PICTURE_ALIGNMENT); + ret = av_image_fill_pointers(data, format, h, aligned_ptr, linesize); + if (ret < 0) { + av_buffer_unref(&buf); + return ret; + } + + p->data[0] = data[0]; + p->data[1] = data[1]; + p->data[2] = data[2]; + p->stride[0] = linesize[0]; + p->stride[1] = linesize[1]; + p->allocator_data = buf; + + return 0; +} + +static void libdav1d_picture_release(Dav1dPicture *p, void *cookie) +{ + AVBufferRef *buf = p->allocator_data; + + av_buffer_unref(&buf); +} + +static av_cold int libdav1d_init(AVCodecContext *c) +{ + Libdav1dContext *dav1d = c->priv_data; + Dav1dSettings s; + int threads = (c->thread_count ? c->thread_count : av_cpu_count()) * 3 / 2; + int res; + + av_log(c, AV_LOG_INFO, "libdav1d %s\n", dav1d_version()); + + dav1d_default_settings(&s); + s.logger.cookie = c; + s.logger.callback = libdav1d_log_callback; + s.allocator.cookie = dav1d; + s.allocator.alloc_picture_callback = libdav1d_picture_allocator; + s.allocator.release_picture_callback = libdav1d_picture_release; + s.apply_grain = dav1d->apply_grain; + + s.n_tile_threads = dav1d->tile_threads + ? dav1d->tile_threads + : FFMIN(floor(sqrt(threads)), DAV1D_MAX_TILE_THREADS); + s.n_frame_threads = dav1d->frame_threads + ? dav1d->frame_threads + : FFMIN(ceil(threads / s.n_tile_threads), DAV1D_MAX_FRAME_THREADS); + av_log(c, AV_LOG_DEBUG, "Using %d frame threads, %d tile threads\n", + s.n_frame_threads, s.n_tile_threads); + + res = dav1d_open(&dav1d->c, &s); + if (res < 0) + return AVERROR(ENOMEM); + + return 0; +} + +static void libdav1d_flush(AVCodecContext *c) +{ + Libdav1dContext *dav1d = c->priv_data; + + dav1d_data_unref(&dav1d->data); + dav1d_flush(dav1d->c); +} + +static void libdav1d_data_free(const uint8_t *data, void *opaque) { + AVBufferRef *buf = opaque; + + av_buffer_unref(&buf); +} + +static int libdav1d_receive_frame(AVCodecContext *c, AVFrame *frame) +{ + Libdav1dContext *dav1d = c->priv_data; + Dav1dData *data = &dav1d->data; + Dav1dPicture pic = { 0 }, *p = &pic; + int res; + + if (!data->sz) { + AVPacket pkt = { 0 }; + + res = ff_decode_get_packet(c, &pkt); + if (res < 0 && res != AVERROR_EOF) + return res; + + if (pkt.size) { + res = dav1d_data_wrap(data, pkt.data, pkt.size, libdav1d_data_free, pkt.buf); + if (res < 0) { + av_packet_unref(&pkt); + return res; + } + + data->m.timestamp = pkt.pts; + data->m.offset = pkt.pos; + data->m.duration = pkt.duration; + + pkt.buf = NULL; + av_packet_unref(&pkt); + } + } + + res = dav1d_send_data(dav1d->c, data); + if (res < 0) { + if (res == AVERROR(EINVAL)) + res = AVERROR_INVALIDDATA; + if (res != AVERROR(EAGAIN)) + return res; + } + + res = dav1d_get_picture(dav1d->c, p); + if (res < 0) { + if (res == AVERROR(EINVAL)) + res = AVERROR_INVALIDDATA; + else if (res == AVERROR(EAGAIN) && c->internal->draining) + res = AVERROR_EOF; + + return res; + } + + av_assert0(p->data[0] && p->allocator_data); + + // This requires the custom allocator above + frame->buf[0] = av_buffer_ref(p->allocator_data); + if (!frame->buf[0]) { + dav1d_picture_unref(p); + return AVERROR(ENOMEM); + } + + frame->data[0] = p->data[0]; + frame->data[1] = p->data[1]; + frame->data[2] = p->data[2]; + frame->linesize[0] = p->stride[0]; + frame->linesize[1] = p->stride[1]; + frame->linesize[2] = p->stride[1]; + + c->profile = p->seq_hdr->profile; + c->level = ((p->seq_hdr->operating_points[0].major_level - 2) << 2) + | p->seq_hdr->operating_points[0].minor_level; + frame->width = p->p.w; + frame->height = p->p.h; + if (c->width != p->p.w || c->height != p->p.h) { + res = ff_set_dimensions(c, p->p.w, p->p.h); + if (res < 0) + goto fail; + } + + switch (p->seq_hdr->chr) { + case DAV1D_CHR_VERTICAL: + frame->chroma_location = c->chroma_sample_location = AVCHROMA_LOC_LEFT; + break; + case DAV1D_CHR_COLOCATED: + frame->chroma_location = c->chroma_sample_location = AVCHROMA_LOC_TOPLEFT; + break; + } + frame->colorspace = c->colorspace = (enum AVColorSpace) p->seq_hdr->mtrx; + frame->color_primaries = c->color_primaries = (enum AVColorPrimaries) p->seq_hdr->pri; + frame->color_trc = c->color_trc = (enum AVColorTransferCharacteristic) p->seq_hdr->trc; + frame->color_range = c->color_range = p->seq_hdr->color_range ? AVCOL_RANGE_JPEG : AVCOL_RANGE_MPEG; + + if (p->p.layout == DAV1D_PIXEL_LAYOUT_I444 && + p->seq_hdr->mtrx == DAV1D_MC_IDENTITY && + p->seq_hdr->pri == DAV1D_COLOR_PRI_BT709 && + p->seq_hdr->trc == DAV1D_TRC_SRGB) + frame->format = c->pix_fmt = pix_fmt_rgb[p->seq_hdr->hbd]; + else + frame->format = c->pix_fmt = pix_fmt[p->p.layout][p->seq_hdr->hbd]; + + // match timestamps and packet size + frame->pts = frame->best_effort_timestamp = p->m.timestamp; +#if FF_API_PKT_PTS +FF_DISABLE_DEPRECATION_WARNINGS + frame->pkt_pts = p->m.timestamp; +FF_ENABLE_DEPRECATION_WARNINGS +#endif + frame->pkt_dts = p->m.timestamp; + frame->pkt_pos = p->m.offset; + frame->pkt_size = p->m.size; + frame->pkt_duration = p->m.duration; + frame->key_frame = p->frame_hdr->frame_type == DAV1D_FRAME_TYPE_KEY; + + switch (p->frame_hdr->frame_type) { + case DAV1D_FRAME_TYPE_KEY: + case DAV1D_FRAME_TYPE_INTRA: + frame->pict_type = AV_PICTURE_TYPE_I; + break; + case DAV1D_FRAME_TYPE_INTER: + frame->pict_type = AV_PICTURE_TYPE_P; + break; + case DAV1D_FRAME_TYPE_SWITCH: + frame->pict_type = AV_PICTURE_TYPE_SP; + break; + default: + res = AVERROR_INVALIDDATA; + goto fail; + } + + if (p->mastering_display) { + AVMasteringDisplayMetadata *mastering = av_mastering_display_metadata_create_side_data(frame); + if (!mastering) { + res = AVERROR(ENOMEM); + goto fail; + } + + for (int i = 0; i < 3; i++) { + mastering->display_primaries[i][0] = av_make_q(p->mastering_display->primaries[i][0], 1 << 16); + mastering->display_primaries[i][1] = av_make_q(p->mastering_display->primaries[i][1], 1 << 16); + } + mastering->white_point[0] = av_make_q(p->mastering_display->white_point[0], 1 << 16); + mastering->white_point[1] = av_make_q(p->mastering_display->white_point[1], 1 << 16); + + mastering->max_luminance = av_make_q(p->mastering_display->max_luminance, 1 << 8); + mastering->min_luminance = av_make_q(p->mastering_display->min_luminance, 1 << 14); + + mastering->has_primaries = 1; + mastering->has_luminance = 1; + } + if (p->content_light) { + AVContentLightMetadata *light = av_content_light_metadata_create_side_data(frame); + if (!light) { + res = AVERROR(ENOMEM); + goto fail; + } + light->MaxCLL = p->content_light->max_content_light_level; + light->MaxFALL = p->content_light->max_frame_average_light_level; + } + + res = 0; +fail: + dav1d_picture_unref(p); + if (res < 0) + av_frame_unref(frame); + return res; +} + +static av_cold int libdav1d_close(AVCodecContext *c) +{ + Libdav1dContext *dav1d = c->priv_data; + + av_buffer_pool_uninit(&dav1d->pool); + dav1d_data_unref(&dav1d->data); + dav1d_close(&dav1d->c); + + return 0; +} + +#define OFFSET(x) offsetof(Libdav1dContext, x) +#define VD AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_DECODING_PARAM +static const AVOption libdav1d_options[] = { + { "tilethreads", "Tile threads", OFFSET(tile_threads), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, DAV1D_MAX_TILE_THREADS, VD }, + { "framethreads", "Frame threads", OFFSET(frame_threads), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, DAV1D_MAX_FRAME_THREADS, VD }, + { "filmgrain", "Apply Film Grain", OFFSET(apply_grain), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, VD }, + { NULL } +}; + +static const AVClass libdav1d_class = { + .class_name = "libdav1d decoder", + .item_name = av_default_item_name, + .option = libdav1d_options, + .version = LIBAVUTIL_VERSION_INT, +}; + +AVCodec ff_libdav1d_decoder = { + .name = "libdav1d", + .long_name = NULL_IF_CONFIG_SMALL("dav1d AV1 decoder by VideoLAN"), + .type = AVMEDIA_TYPE_VIDEO, + .id = AV_CODEC_ID_AV1, + .priv_data_size = sizeof(Libdav1dContext), + .init = libdav1d_init, + .close = libdav1d_close, + .flush = libdav1d_flush, + .receive_frame = libdav1d_receive_frame, + .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AUTO_THREADS, + .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE | FF_CODEC_CAP_SETS_PKT_DTS, + .priv_class = &libdav1d_class, + .wrapper_name = "libdav1d", +}; diff --git a/libavcodec/libdavs2.c b/libavcodec/libdavs2.c new file mode 100644 index 000000000..218f3ec23 --- /dev/null +++ b/libavcodec/libdavs2.c @@ -0,0 +1,228 @@ +/* + * AVS2 decoding using the davs2 library + * + * Copyright (C) 2018 Yiqun Xu, + * Falei Luo, + * Huiwen Ren, + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "avcodec.h" +#include "davs2.h" + +typedef struct DAVS2Context { + void *decoder; + + AVFrame *frame; + davs2_param_t param; // decoding parameters + davs2_packet_t packet; // input bitstream + + davs2_picture_t out_frame; // output data, frame data + davs2_seq_info_t headerset; // output data, sequence header + +}DAVS2Context; + +static av_cold int davs2_init(AVCodecContext *avctx) +{ + DAVS2Context *cad = avctx->priv_data; + int cpu_flags = av_get_cpu_flags(); + + /* init the decoder */ + cad->param.threads = avctx->thread_count; + cad->param.info_level = 0; + cad->param.disable_avx = !(cpu_flags & AV_CPU_FLAG_AVX && + cpu_flags & AV_CPU_FLAG_AVX2); + cad->decoder = davs2_decoder_open(&cad->param); + + if (!cad->decoder) { + av_log(avctx, AV_LOG_ERROR, "decoder created error."); + return AVERROR_EXTERNAL; + } + + av_log(avctx, AV_LOG_VERBOSE, "decoder created. %p\n", cad->decoder); + return 0; +} + +static int davs2_dump_frames(AVCodecContext *avctx, davs2_picture_t *pic, int *got_frame, + davs2_seq_info_t *headerset, int ret_type, AVFrame *frame) +{ + DAVS2Context *cad = avctx->priv_data; + int bytes_per_sample = pic->bytes_per_sample; + int plane = 0; + int line = 0; + + if (!headerset) { + *got_frame = 0; + return 0; + } + + if (!pic || ret_type == DAVS2_GOT_HEADER) { + avctx->width = headerset->width; + avctx->height = headerset->height; + avctx->pix_fmt = headerset->output_bit_depth == 10 ? + AV_PIX_FMT_YUV420P10 : AV_PIX_FMT_YUV420P; + + avctx->framerate = av_d2q(headerset->frame_rate,4096); + *got_frame = 0; + return 0; + } + + switch (pic->type) { + case DAVS2_PIC_I: + case DAVS2_PIC_G: + frame->pict_type = AV_PICTURE_TYPE_I; + break; + case DAVS2_PIC_P: + case DAVS2_PIC_S: + frame->pict_type = AV_PICTURE_TYPE_P; + break; + case DAVS2_PIC_B: + frame->pict_type = AV_PICTURE_TYPE_B; + break; + case DAVS2_PIC_F: + frame->pict_type = AV_PICTURE_TYPE_S; + break; + default: + av_log(avctx, AV_LOG_ERROR, "Decoder error: unknown frame type\n"); + return AVERROR_EXTERNAL; + } + + for (plane = 0; plane < 3; ++plane) { + int size_line = pic->widths[plane] * bytes_per_sample; + frame->buf[plane] = av_buffer_alloc(size_line * pic->lines[plane]); + + if (!frame->buf[plane]){ + av_log(avctx, AV_LOG_ERROR, "Decoder error: allocation failure, can't dump frames.\n"); + return AVERROR(ENOMEM); + } + + frame->data[plane] = frame->buf[plane]->data; + frame->linesize[plane] = size_line; + + for (line = 0; line < pic->lines[plane]; ++line) + memcpy(frame->data[plane] + line * size_line, + pic->planes[plane] + line * pic->strides[plane], + pic->widths[plane] * bytes_per_sample); + } + + frame->width = cad->headerset.width; + frame->height = cad->headerset.height; + frame->pts = cad->out_frame.pts; + frame->format = avctx->pix_fmt; + + *got_frame = 1; + return 0; +} + +static void davs2_flush(AVCodecContext *avctx) +{ + DAVS2Context *cad = avctx->priv_data; + int ret = DAVS2_GOT_FRAME; + + while (ret == DAVS2_GOT_FRAME) { + ret = davs2_decoder_flush(cad->decoder, &cad->headerset, &cad->out_frame); + davs2_decoder_frame_unref(cad->decoder, &cad->out_frame); + } + + if (ret == DAVS2_ERROR) { + av_log(avctx, AV_LOG_WARNING, "Decoder flushing failed.\n"); + } +} + +static int send_delayed_frame(AVCodecContext *avctx, AVFrame *frame, int *got_frame) +{ + DAVS2Context *cad = avctx->priv_data; + int ret = DAVS2_DEFAULT; + + ret = davs2_decoder_flush(cad->decoder, &cad->headerset, &cad->out_frame); + if (ret == DAVS2_ERROR) { + av_log(avctx, AV_LOG_ERROR, "Decoder error: can't flush delayed frame\n"); + return AVERROR_EXTERNAL; + } + if (ret == DAVS2_GOT_FRAME) { + ret = davs2_dump_frames(avctx, &cad->out_frame, got_frame, &cad->headerset, ret, frame); + davs2_decoder_frame_unref(cad->decoder, &cad->out_frame); + } + return ret; +} + +static av_cold int davs2_end(AVCodecContext *avctx) +{ + DAVS2Context *cad = avctx->priv_data; + + /* close the decoder */ + if (cad->decoder) { + davs2_decoder_close(cad->decoder); + cad->decoder = NULL; + } + + return 0; +} + +static int davs2_decode_frame(AVCodecContext *avctx, void *data, + int *got_frame, AVPacket *avpkt) +{ + DAVS2Context *cad = avctx->priv_data; + int buf_size = avpkt->size; + uint8_t *buf_ptr = avpkt->data; + AVFrame *frame = data; + int ret = DAVS2_DEFAULT; + + /* end of stream, output what is still in the buffers */ + if (!buf_size) { + return send_delayed_frame(avctx, frame, got_frame); + } + + cad->packet.data = buf_ptr; + cad->packet.len = buf_size; + cad->packet.pts = avpkt->pts; + cad->packet.dts = avpkt->dts; + + ret = davs2_decoder_send_packet(cad->decoder, &cad->packet); + + + if (ret == DAVS2_ERROR) { + av_log(avctx, AV_LOG_ERROR, "Decoder error: can't read packet\n"); + return AVERROR_EXTERNAL; + } + + ret = davs2_decoder_recv_frame(cad->decoder, &cad->headerset, &cad->out_frame); + + if (ret != DAVS2_DEFAULT) { + ret = davs2_dump_frames(avctx, &cad->out_frame, got_frame, &cad->headerset, ret, frame); + davs2_decoder_frame_unref(cad->decoder, &cad->out_frame); + } + + return ret == 0 ? buf_size : ret; +} + +AVCodec ff_libdavs2_decoder = { + .name = "libdavs2", + .long_name = NULL_IF_CONFIG_SMALL("libdavs2 AVS2-P2/IEEE1857.4"), + .type = AVMEDIA_TYPE_VIDEO, + .id = AV_CODEC_ID_AVS2, + .priv_data_size = sizeof(DAVS2Context), + .init = davs2_init, + .close = davs2_end, + .decode = davs2_decode_frame, + .flush = davs2_flush, + .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AUTO_THREADS, + .pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_YUV420P, + AV_PIX_FMT_NONE }, + .wrapper_name = "libdavs2", +}; diff --git a/libavcodec/libfdk-aacdec.c b/libavcodec/libfdk-aacdec.c index 677b11088..1abe1d843 100644 --- a/libavcodec/libfdk-aacdec.c +++ b/libavcodec/libfdk-aacdec.c @@ -25,9 +25,15 @@ #include "avcodec.h" #include "internal.h" -/* The version macro is introduced the same time as the setting enum was - * changed, so this check should suffice. */ -#ifndef AACDECODER_LIB_VL0 +#ifdef AACDECODER_LIB_VL0 +#define FDKDEC_VER_AT_LEAST(vl0, vl1) \ + ((AACDECODER_LIB_VL0 > vl0) || \ + (AACDECODER_LIB_VL0 == vl0 && AACDECODER_LIB_VL1 >= vl1)) +#else +#define FDKDEC_VER_AT_LEAST(vl0, vl1) 0 +#endif + +#if !FDKDEC_VER_AT_LEAST(2, 5) // < 2.5.10 #define AAC_PCM_MAX_OUTPUT_CHANNELS AAC_PCM_OUTPUT_CHANNELS #endif @@ -48,6 +54,7 @@ typedef struct FDKAACDecContext { int drc_level; int drc_boost; int drc_heavy; + int drc_effect; int drc_cut; int level_limit; } FDKAACDecContext; @@ -72,8 +79,12 @@ static const AVOption fdk_aac_dec_options[] = { OFFSET(drc_level), AV_OPT_TYPE_INT, { .i64 = -1}, -1, 127, AD, NULL }, { "drc_heavy", "Dynamic Range Control: heavy compression, where [1] is on (RF mode) and [0] is off", OFFSET(drc_heavy), AV_OPT_TYPE_INT, { .i64 = -1}, -1, 1, AD, NULL }, -#ifdef AACDECODER_LIB_VL0 +#if FDKDEC_VER_AT_LEAST(2, 5) // 2.5.10 { "level_limit", "Signal level limiting", OFFSET(level_limit), AV_OPT_TYPE_INT, { .i64 = 0 }, -1, 1, AD }, +#endif +#if FDKDEC_VER_AT_LEAST(3, 0) // 3.0.0 + { "drc_effect","Dynamic Range Control: effect type, where e.g. [0] is none and [6] is general", + OFFSET(drc_effect), AV_OPT_TYPE_INT, { .i64 = -1}, -1, 8, AD, NULL }, #endif { NULL } }; @@ -296,13 +307,22 @@ static av_cold int fdk_aac_decode_init(AVCodecContext *avctx) } } -#ifdef AACDECODER_LIB_VL0 +#if FDKDEC_VER_AT_LEAST(2, 5) // 2.5.10 if (aacDecoder_SetParam(s->handle, AAC_PCM_LIMITER_ENABLE, s->level_limit) != AAC_DEC_OK) { av_log(avctx, AV_LOG_ERROR, "Unable to set in signal level limiting in the decoder\n"); return AVERROR_UNKNOWN; } #endif +#if FDKDEC_VER_AT_LEAST(3, 0) // 3.0.0 + if (s->drc_effect != -1) { + if (aacDecoder_SetParam(s->handle, AAC_UNIDRC_SET_EFFECT, s->drc_effect) != AAC_DEC_OK) { + av_log(avctx, AV_LOG_ERROR, "Unable to set DRC effect type in the decoder\n"); + return AVERROR_UNKNOWN; + } + } +#endif + avctx->sample_fmt = AV_SAMPLE_FMT_S16; s->decoder_buffer_size = DECODER_BUFFSIZE * DECODER_MAX_CHANNELS; diff --git a/libavcodec/libfdk-aacenc.c b/libavcodec/libfdk-aacenc.c index d47137b22..5620bb595 100644 --- a/libavcodec/libfdk-aacenc.c +++ b/libavcodec/libfdk-aacenc.c @@ -26,11 +26,20 @@ #include "audio_frame_queue.h" #include "internal.h" +#ifdef AACENCODER_LIB_VL0 +#define FDKENC_VER_AT_LEAST(vl0, vl1) \ + ((AACENCODER_LIB_VL0 > vl0) || \ + (AACENCODER_LIB_VL0 == vl0 && AACENCODER_LIB_VL1 >= vl1)) +#else +#define FDKENC_VER_AT_LEAST(vl0, vl1) 0 +#endif + typedef struct AACContext { const AVClass *class; HANDLE_AACENCODER handle; int afterburner; int eld_sbr; + int eld_v2; int signaling; int latm; int header_period; @@ -42,6 +51,9 @@ typedef struct AACContext { static const AVOption aac_enc_options[] = { { "afterburner", "Afterburner (improved quality)", offsetof(AACContext, afterburner), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, 1, AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_ENCODING_PARAM }, { "eld_sbr", "Enable SBR for ELD (for SBR in other configurations, use the -profile parameter)", offsetof(AACContext, eld_sbr), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_ENCODING_PARAM }, +#if FDKENC_VER_AT_LEAST(4, 0) // 4.0.0 + { "eld_v2", "Enable ELDv2 (LD-MPS extension for ELD stereo signals)", offsetof(AACContext, eld_v2), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_ENCODING_PARAM }, +#endif { "signaling", "SBR/PS signaling style", offsetof(AACContext, signaling), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 2, AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_ENCODING_PARAM, "signaling" }, { "default", "Choose signaling implicitly (explicit hierarchical by default, implicit if global header is disabled)", 0, AV_OPT_TYPE_CONST, { .i64 = -1 }, 0, 0, AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_ENCODING_PARAM, "signaling" }, { "implicit", "Implicit backwards compatible signaling", 0, AV_OPT_TYPE_CONST, { .i64 = 0 }, 0, 0, AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_ENCODING_PARAM, "signaling" }, @@ -147,14 +159,35 @@ static av_cold int aac_encode_init(AVCodecContext *avctx) switch (avctx->channels) { case 1: mode = MODE_1; sce = 1; cpe = 0; break; - case 2: mode = MODE_2; sce = 0; cpe = 1; break; + case 2: +#if FDKENC_VER_AT_LEAST(4, 0) // 4.0.0 + // (profile + 1) to map from profile range to AOT range + if (aot == FF_PROFILE_AAC_ELD + 1 && s->eld_v2) { + if ((err = aacEncoder_SetParam(s->handle, AACENC_CHANNELMODE, + 128)) != AACENC_OK) { + av_log(avctx, AV_LOG_ERROR, "Unable to enable ELDv2: %s\n", + aac_get_error(err)); + goto error; + } else { + mode = MODE_212; + sce = 1; + cpe = 0; + } + } else +#endif + { + mode = MODE_2; + sce = 0; + cpe = 1; + } + break; case 3: mode = MODE_1_2; sce = 1; cpe = 1; break; case 4: mode = MODE_1_2_1; sce = 2; cpe = 1; break; case 5: mode = MODE_1_2_2; sce = 1; cpe = 2; break; case 6: mode = MODE_1_2_2_1; sce = 2; cpe = 2; break; /* The version macro is introduced the same time as the 7.1 support, so this should suffice. */ -#ifdef AACENCODER_LIB_VL0 +#if FDKENC_VER_AT_LEAST(3, 4) // 3.4.12 case 8: sce = 2; cpe = 3; @@ -227,7 +260,8 @@ static av_cold int aac_encode_init(AVCodecContext *avctx) /* Choose bitstream format - if global header is requested, use * raw access units, otherwise use ADTS. */ if ((err = aacEncoder_SetParam(s->handle, AACENC_TRANSMUX, - avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER ? 0 : s->latm ? 10 : 2)) != AACENC_OK) { + avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER ? TT_MP4_RAW : + s->latm ? TT_MP4_LOAS : TT_MP4_ADTS)) != AACENC_OK) { av_log(avctx, AV_LOG_ERROR, "Unable to set the transmux format: %s\n", aac_get_error(err)); goto error; @@ -289,7 +323,11 @@ static av_cold int aac_encode_init(AVCodecContext *avctx) } avctx->frame_size = info.frameLength; +#if FDKENC_VER_AT_LEAST(4, 0) // 4.0.0 + avctx->initial_padding = info.nDelay; +#else avctx->initial_padding = info.encoderDelay; +#endif ff_af_queue_init(avctx, &s->afq); if (avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER) { @@ -322,28 +360,35 @@ static int aac_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, int out_buffer_size, out_buffer_element_size; void *in_ptr, *out_ptr; int ret; + uint8_t dummy_buf[1]; AACENC_ERROR err; /* handle end-of-stream small frame and flushing */ if (!frame) { + /* Must be a non-null pointer, even if it's a dummy. We could use + * the address of anything else on the stack as well. */ + in_ptr = dummy_buf; + in_buffer_size = 0; + in_args.numInSamples = -1; } else { - in_ptr = frame->data[0]; - in_buffer_size = 2 * avctx->channels * frame->nb_samples; - in_buffer_element_size = 2; + in_ptr = frame->data[0]; + in_buffer_size = 2 * avctx->channels * frame->nb_samples; - in_args.numInSamples = avctx->channels * frame->nb_samples; - in_buf.numBufs = 1; - in_buf.bufs = &in_ptr; - in_buf.bufferIdentifiers = &in_buffer_identifier; - in_buf.bufSizes = &in_buffer_size; - in_buf.bufElSizes = &in_buffer_element_size; + in_args.numInSamples = avctx->channels * frame->nb_samples; /* add current frame to the queue */ if ((ret = ff_af_queue_add(&s->afq, frame)) < 0) return ret; } + in_buffer_element_size = 2; + in_buf.numBufs = 1; + in_buf.bufs = &in_ptr; + in_buf.bufferIdentifiers = &in_buffer_identifier; + in_buf.bufSizes = &in_buffer_size; + in_buf.bufElSizes = &in_buffer_element_size; + /* The maximum packet size is 6144 bits aka 768 bytes per channel. */ if ((ret = ff_alloc_packet2(avctx, avpkt, FFMAX(8192, 768 * avctx->channels), 0)) < 0) return ret; @@ -399,7 +444,7 @@ static const uint64_t aac_channel_layout[] = { AV_CH_LAYOUT_4POINT0, AV_CH_LAYOUT_5POINT0_BACK, AV_CH_LAYOUT_5POINT1_BACK, -#ifdef AACENCODER_LIB_VL0 +#if FDKENC_VER_AT_LEAST(3, 4) // 3.4.12 AV_CH_LAYOUT_7POINT1_WIDE_BACK, AV_CH_LAYOUT_7POINT1, #endif diff --git a/libavcodec/libgsmenc.c b/libavcodec/libgsmenc.c index c9e7ba056..fdb11c705 100644 --- a/libavcodec/libgsmenc.c +++ b/libavcodec/libgsmenc.c @@ -114,6 +114,10 @@ static int libgsm_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, return 0; } +static const AVCodecDefault libgsm_defaults[] = { + { "b", "13000" }, + { NULL }, +}; #if CONFIG_LIBGSM_ENCODER AVCodec ff_libgsm_encoder = { @@ -124,6 +128,8 @@ AVCodec ff_libgsm_encoder = { .init = libgsm_encode_init, .encode2 = libgsm_encode_frame, .close = libgsm_encode_close, + .defaults = libgsm_defaults, + .channel_layouts= (const uint64_t[]) { AV_CH_LAYOUT_MONO, 0 }, .sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_NONE }, .wrapper_name = "libgsm", @@ -138,6 +144,8 @@ AVCodec ff_libgsm_ms_encoder = { .init = libgsm_encode_init, .encode2 = libgsm_encode_frame, .close = libgsm_encode_close, + .defaults = libgsm_defaults, + .channel_layouts= (const uint64_t[]) { AV_CH_LAYOUT_MONO, 0 }, .sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_NONE }, .wrapper_name = "libgsm", diff --git a/libavcodec/libkvazaar.c b/libavcodec/libkvazaar.c index 41a1bbb45..a89ca7f74 100644 --- a/libavcodec/libkvazaar.c +++ b/libavcodec/libkvazaar.c @@ -79,13 +79,23 @@ static av_cold int libkvazaar_init(AVCodecContext *avctx) cfg->width = avctx->width; cfg->height = avctx->height; - if (avctx->ticks_per_frame > INT_MAX / avctx->time_base.num) { - av_log(avctx, AV_LOG_ERROR, - "Could not set framerate for kvazaar: integer overflow\n"); - return AVERROR(EINVAL); + if (avctx->framerate.num > 0 && avctx->framerate.den > 0) { + if (avctx->ticks_per_frame > INT_MAX / avctx->framerate.den) { + av_log(avctx, AV_LOG_ERROR, + "Could not set framerate for kvazaar: integer overflow\n"); + return AVERROR(EINVAL); + } + cfg->framerate_num = avctx->framerate.num; + cfg->framerate_denom = avctx->time_base.den * avctx->ticks_per_frame; + } else { + if (avctx->ticks_per_frame > INT_MAX / avctx->time_base.num) { + av_log(avctx, AV_LOG_ERROR, + "Could not set framerate for kvazaar: integer overflow\n"); + return AVERROR(EINVAL); + } + cfg->framerate_num = avctx->time_base.den; + cfg->framerate_denom = avctx->time_base.num * avctx->ticks_per_frame; } - cfg->framerate_num = avctx->time_base.den; - cfg->framerate_denom = avctx->time_base.num * avctx->ticks_per_frame; cfg->target_bitrate = avctx->bit_rate; cfg->vui.sar_width = avctx->sample_aspect_ratio.num; cfg->vui.sar_height = avctx->sample_aspect_ratio.den; @@ -143,8 +153,8 @@ static av_cold int libkvazaar_close(AVCodecContext *avctx) LibkvazaarContext *ctx = avctx->priv_data; if (ctx->api) { - ctx->api->encoder_close(ctx->encoder); - ctx->api->config_destroy(ctx->config); + ctx->api->encoder_close(ctx->encoder); + ctx->api->config_destroy(ctx->config); } if (avctx->extradata) @@ -170,7 +180,7 @@ static int libkvazaar_encode(AVCodecContext *avctx, if (frame) { if (frame->width != ctx->config->width || - frame->height != ctx->config->height) { + frame->height != ctx->config->height) { av_log(avctx, AV_LOG_ERROR, "Changing video dimensions during encoding is not supported. " "(changed from %dx%d to %dx%d)\n", @@ -207,7 +217,7 @@ static int libkvazaar_encode(AVCodecContext *avctx, 0 }; av_image_copy(input_pic->data, dst_linesizes, - frame->data, frame->linesize, + (const uint8_t **)frame->data, frame->linesize, frame->format, frame->width, frame->height); } @@ -223,8 +233,7 @@ static int libkvazaar_encode(AVCodecContext *avctx, av_log(avctx, AV_LOG_ERROR, "Failed to encode frame.\n"); retval = AVERROR_INVALIDDATA; goto done; - } - else + } else retval = 0; /* kvazaar returns 1 on success */ if (data_out) { @@ -249,7 +258,7 @@ static int libkvazaar_encode(AVCodecContext *avctx, // IRAP VCL NAL unit types span the range // [BLA_W_LP (16), RSV_IRAP_VCL23 (23)]. if (frame_info.nal_unit_type >= KVZ_NAL_BLA_W_LP && - frame_info.nal_unit_type <= KVZ_NAL_RSV_IRAP_VCL23) { + frame_info.nal_unit_type <= KVZ_NAL_RSV_IRAP_VCL23) { avpkt->flags |= AV_PKT_FLAG_KEY; } @@ -293,7 +302,7 @@ AVCodec ff_libkvazaar_encoder = { .long_name = NULL_IF_CONFIG_SMALL("libkvazaar H.265 / HEVC"), .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_HEVC, - .capabilities = AV_CODEC_CAP_DELAY, + .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AUTO_THREADS, .pix_fmts = pix_fmts, .priv_class = &class, diff --git a/libavcodec/libopenh264dec.c b/libavcodec/libopenh264dec.c index b7ed85d17..c7aa7fa19 100644 --- a/libavcodec/libopenh264dec.c +++ b/libavcodec/libopenh264dec.c @@ -95,10 +95,32 @@ static int svc_decode_frame(AVCodecContext *avctx, void *data, int ret, linesize[3]; AVFrame *avframe = data; DECODING_STATE state; +#if OPENH264_VER_AT_LEAST(1, 7) + int opt; +#endif - state = (*s->decoder)->DecodeFrame2(s->decoder, avpkt->data, avpkt->size, ptrs, &info); + if (!avpkt->data) { +#if OPENH264_VER_AT_LEAST(1, 9) + int end_of_stream = 1; + (*s->decoder)->SetOption(s->decoder, DECODER_OPTION_END_OF_STREAM, &end_of_stream); + state = (*s->decoder)->FlushFrame(s->decoder, ptrs, &info); +#else + return 0; +#endif + } else { + info.uiInBsTimeStamp = avpkt->pts; +#if OPENH264_VER_AT_LEAST(1, 4) + // Contrary to the name, DecodeFrameNoDelay actually does buffering + // and reordering of frames, and is the recommended decoding entry + // point since 1.4. This is essential for successfully decoding + // B-frames. + state = (*s->decoder)->DecodeFrameNoDelay(s->decoder, avpkt->data, avpkt->size, ptrs, &info); +#else + state = (*s->decoder)->DecodeFrame2(s->decoder, avpkt->data, avpkt->size, ptrs, &info); +#endif + } if (state != dsErrorFree) { - av_log(avctx, AV_LOG_ERROR, "DecodeFrame2 failed\n"); + av_log(avctx, AV_LOG_ERROR, "DecodeFrame failed\n"); return AVERROR_UNKNOWN; } if (info.iBufferStatus != 1) { @@ -120,12 +142,18 @@ static int svc_decode_frame(AVCodecContext *avctx, void *data, linesize[1] = linesize[2] = info.UsrData.sSystemBuffer.iStride[1]; av_image_copy(avframe->data, avframe->linesize, (const uint8_t **) ptrs, linesize, avctx->pix_fmt, avctx->width, avctx->height); - avframe->pts = avpkt->pts; - avframe->pkt_dts = avpkt->dts; + avframe->pts = info.uiOutYuvTimeStamp; + avframe->pkt_dts = AV_NOPTS_VALUE; #if FF_API_PKT_PTS FF_DISABLE_DEPRECATION_WARNINGS avframe->pkt_pts = avpkt->pts; FF_ENABLE_DEPRECATION_WARNINGS +#endif +#if OPENH264_VER_AT_LEAST(1, 7) + (*s->decoder)->GetOption(s->decoder, DECODER_OPTION_PROFILE, &opt); + avctx->profile = opt; + (*s->decoder)->GetOption(s->decoder, DECODER_OPTION_LEVEL, &opt); + avctx->level = opt; #endif *got_frame = 1; @@ -141,8 +169,6 @@ AVCodec ff_libopenh264_decoder = { .init = svc_decode_init, .decode = svc_decode_frame, .close = svc_decode_close, - // The decoder doesn't currently support B-frames, and the decoder's API - // doesn't support reordering/delay, but the BSF could incur delay. .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_DR1, .caps_internal = FF_CODEC_CAP_SETS_PKT_DTS | FF_CODEC_CAP_INIT_THREADSAFE | FF_CODEC_CAP_INIT_CLEANUP, diff --git a/libavcodec/libopenh264enc.c b/libavcodec/libopenh264enc.c index 83c3f0ce2..ae6d17c6d 100644 --- a/libavcodec/libopenh264enc.c +++ b/libavcodec/libopenh264enc.c @@ -75,7 +75,7 @@ static const AVOption options[] = { }; static const AVClass class = { - .class_name = "libvo_amrwbenc", + .class_name = "libopenh264enc", .item_name = av_default_item_name, .option = options, .version = LIBAVUTIL_VERSION_INT, @@ -164,6 +164,47 @@ FF_ENABLE_DEPRECATION_WARNINGS param.sSpatialLayers[0].iSpatialBitrate = param.iTargetBitrate; param.sSpatialLayers[0].iMaxSpatialBitrate = param.iMaxBitrate; +#if OPENH264_VER_AT_LEAST(1, 7) + if (avctx->sample_aspect_ratio.num && avctx->sample_aspect_ratio.den) { + // Table E-1. + static const AVRational sar_idc[] = { + { 0, 0 }, // Unspecified (never written here). + { 1, 1 }, { 12, 11 }, { 10, 11 }, { 16, 11 }, + { 40, 33 }, { 24, 11 }, { 20, 11 }, { 32, 11 }, + { 80, 33 }, { 18, 11 }, { 15, 11 }, { 64, 33 }, + { 160, 99 }, // Last 3 are unknown to openh264: { 4, 3 }, { 3, 2 }, { 2, 1 }, + }; + static const ESampleAspectRatio asp_idc[] = { + ASP_UNSPECIFIED, + ASP_1x1, ASP_12x11, ASP_10x11, ASP_16x11, + ASP_40x33, ASP_24x11, ASP_20x11, ASP_32x11, + ASP_80x33, ASP_18x11, ASP_15x11, ASP_64x33, + ASP_160x99, + }; + int num, den, i; + + av_reduce(&num, &den, avctx->sample_aspect_ratio.num, + avctx->sample_aspect_ratio.den, 65535); + + for (i = 1; i < FF_ARRAY_ELEMS(sar_idc); i++) { + if (num == sar_idc[i].num && + den == sar_idc[i].den) + break; + } + if (i == FF_ARRAY_ELEMS(sar_idc)) { + param.sSpatialLayers[0].eAspectRatio = ASP_EXT_SAR; + param.sSpatialLayers[0].sAspectRatioExtWidth = num; + param.sSpatialLayers[0].sAspectRatioExtHeight = den; + } else { + param.sSpatialLayers[0].eAspectRatio = asp_idc[i]; + } + param.sSpatialLayers[0].bAspectRatioPresent = true; + } + else { + param.sSpatialLayers[0].bAspectRatioPresent = false; + } +#endif + if ((avctx->slices > 1) && (s->max_nal_size)) { av_log(avctx, AV_LOG_ERROR, "Invalid combination -slices %d and -max_nal_size %d.\n", diff --git a/libavcodec/libopenjpegdec.c b/libavcodec/libopenjpegdec.c index 5e66cd99c..344c5ba5a 100644 --- a/libavcodec/libopenjpegdec.c +++ b/libavcodec/libopenjpegdec.c @@ -45,6 +45,7 @@ AV_PIX_FMT_RGB48, AV_PIX_FMT_RGBA64 #define GRAY_PIXEL_FORMATS AV_PIX_FMT_GRAY8, AV_PIX_FMT_YA8, \ + AV_PIX_FMT_GRAY10, AV_PIX_FMT_GRAY12, AV_PIX_FMT_GRAY14, \ AV_PIX_FMT_GRAY16, AV_PIX_FMT_YA16 #define YUV_PIXEL_FORMATS AV_PIX_FMT_YUV410P, AV_PIX_FMT_YUV411P, AV_PIX_FMT_YUVA420P, \ diff --git a/libavcodec/libopenjpegenc.c b/libavcodec/libopenjpegenc.c index 7c7d0aa6b..199800898 100644 --- a/libavcodec/libopenjpegenc.c +++ b/libavcodec/libopenjpegenc.c @@ -189,6 +189,9 @@ static opj_image_t *mj2_create_image(AVCodecContext *avctx, opj_cparameters_t *p switch (avctx->pix_fmt) { case AV_PIX_FMT_GRAY8: case AV_PIX_FMT_YA8: + case AV_PIX_FMT_GRAY10: + case AV_PIX_FMT_GRAY12: + case AV_PIX_FMT_GRAY14: case AV_PIX_FMT_GRAY16: case AV_PIX_FMT_YA16: color_space = OPJ_CLRSPC_GRAY; @@ -612,6 +615,9 @@ static int libopenjpeg_encode_frame(AVCodecContext *avctx, AVPacket *pkt, case AV_PIX_FMT_YUVA444P: cpyresult = libopenjpeg_copy_unpacked8(avctx, frame, image); break; + case AV_PIX_FMT_GRAY10: + case AV_PIX_FMT_GRAY12: + case AV_PIX_FMT_GRAY14: case AV_PIX_FMT_GRAY16: case AV_PIX_FMT_YUV420P9: case AV_PIX_FMT_YUV422P9: @@ -763,6 +769,7 @@ AVCodec ff_libopenjpeg_encoder = { AV_PIX_FMT_RGBA64, AV_PIX_FMT_GBR24P, AV_PIX_FMT_GBRP9, AV_PIX_FMT_GBRP10, AV_PIX_FMT_GBRP12, AV_PIX_FMT_GBRP14, AV_PIX_FMT_GBRP16, AV_PIX_FMT_GRAY8, AV_PIX_FMT_YA8, AV_PIX_FMT_GRAY16, AV_PIX_FMT_YA16, + AV_PIX_FMT_GRAY10, AV_PIX_FMT_GRAY12, AV_PIX_FMT_GRAY14, AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUVA420P, AV_PIX_FMT_YUV440P, AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUVA422P, AV_PIX_FMT_YUV411P, AV_PIX_FMT_YUV410P, AV_PIX_FMT_YUVA444P, diff --git a/libavcodec/libopusdec.c b/libavcodec/libopusdec.c index 2a97811d1..1724a4990 100644 --- a/libavcodec/libopusdec.c +++ b/libavcodec/libopusdec.c @@ -63,6 +63,8 @@ static av_cold int libopus_decode_init(AVCodecContext *avc) avc->sample_rate = 48000; avc->sample_fmt = avc->request_sample_fmt == AV_SAMPLE_FMT_FLT ? AV_SAMPLE_FMT_FLT : AV_SAMPLE_FMT_S16; + avc->channel_layout = avc->channels > 8 ? 0 : + ff_vorbis_channel_layouts[avc->channels - 1]; if (avc->extradata_size >= OPUS_HEAD_SIZE) { opus->pre_skip = AV_RL16(avc->extradata + 10); @@ -86,35 +88,14 @@ static av_cold int libopus_decode_init(AVCodecContext *avc) mapping = mapping_arr; } - if (channel_map == 1) { - avc->channel_layout = avc->channels > 8 ? 0 : - ff_vorbis_channel_layouts[avc->channels - 1]; - if (avc->channels > 2 && avc->channels <= 8) { - const uint8_t *vorbis_offset = ff_vorbis_channel_layout_offsets[avc->channels - 1]; - int ch; + if (avc->channels > 2 && avc->channels <= 8) { + const uint8_t *vorbis_offset = ff_vorbis_channel_layout_offsets[avc->channels - 1]; + int ch; - /* Remap channels from Vorbis order to ffmpeg order */ - for (ch = 0; ch < avc->channels; ch++) - mapping_arr[ch] = mapping[vorbis_offset[ch]]; - mapping = mapping_arr; - } - } else if (channel_map == 2) { - int ambisonic_order = ff_sqrt(avc->channels) - 1; - if (avc->channels != (ambisonic_order + 1) * (ambisonic_order + 1) && - avc->channels != (ambisonic_order + 1) * (ambisonic_order + 1) + 2) { - av_log(avc, AV_LOG_ERROR, - "Channel mapping 2 is only specified for channel counts" - " which can be written as (n + 1)^2 or (n + 2)^2 + 2" - " for nonnegative integer n\n"); - return AVERROR_INVALIDDATA; - } - if (avc->channels > 227) { - av_log(avc, AV_LOG_ERROR, "Too many channels\n"); - return AVERROR_INVALIDDATA; - } - avc->channel_layout = 0; - } else { - avc->channel_layout = 0; + /* Remap channels from Vorbis order to ffmpeg order */ + for (ch = 0; ch < avc->channels; ch++) + mapping_arr[ch] = mapping[vorbis_offset[ch]]; + mapping = mapping_arr; } opus->dec = opus_multistream_decoder_create(avc->sample_rate, avc->channels, diff --git a/libavcodec/libopusenc.c b/libavcodec/libopusenc.c index 4ae81b0bb..7c025a66d 100644 --- a/libavcodec/libopusenc.c +++ b/libavcodec/libopusenc.c @@ -271,12 +271,22 @@ static av_cold int libopus_encode_init(AVCodecContext *avctx) case 960: case 1920: case 2880: +#ifdef OPUS_FRAMESIZE_120_MS + case 3840: + case 4800: + case 5760: +#endif opus->opts.packet_size = avctx->frame_size = frame_size * avctx->sample_rate / 48000; break; default: av_log(avctx, AV_LOG_ERROR, "Invalid frame duration: %g.\n" - "Frame duration must be exactly one of: 2.5, 5, 10, 20, 40 or 60.\n", + "Frame duration must be exactly one of: 2.5, 5, 10, 20, 40" +#ifdef OPUS_FRAMESIZE_120_MS + ", 60, 80, 100 or 120.\n", +#else + " or 60.\n", +#endif opus->opts.frame_duration); return AVERROR(EINVAL); } @@ -463,10 +473,10 @@ static int libopus_encode(AVCodecContext *avctx, AVPacket *avpkt, memset(audio, 0, opus->opts.packet_size * sample_size); } - /* Maximum packet size taken from opusenc in opus-tools. 60ms packets - * consist of 3 frames in one packet. The maximum frame size is 1275 + /* Maximum packet size taken from opusenc in opus-tools. 120ms packets + * consist of 6 frames in one packet. The maximum frame size is 1275 * bytes along with the largest possible packet header of 7 bytes. */ - if ((ret = ff_alloc_packet2(avctx, avpkt, (1275 * 3 + 7) * opus->stream_count, 0)) < 0) + if ((ret = ff_alloc_packet2(avctx, avpkt, (1275 * 6 + 7) * opus->stream_count, 0)) < 0) return ret; if (avctx->sample_fmt == AV_SAMPLE_FMT_FLT) @@ -534,7 +544,7 @@ static const AVOption libopus_options[] = { { "voip", "Favor improved speech intelligibility", 0, AV_OPT_TYPE_CONST, { .i64 = OPUS_APPLICATION_VOIP }, 0, 0, FLAGS, "application" }, { "audio", "Favor faithfulness to the input", 0, AV_OPT_TYPE_CONST, { .i64 = OPUS_APPLICATION_AUDIO }, 0, 0, FLAGS, "application" }, { "lowdelay", "Restrict to only the lowest delay modes", 0, AV_OPT_TYPE_CONST, { .i64 = OPUS_APPLICATION_RESTRICTED_LOWDELAY }, 0, 0, FLAGS, "application" }, - { "frame_duration", "Duration of a frame in milliseconds", OFFSET(frame_duration), AV_OPT_TYPE_FLOAT, { .dbl = 20.0 }, 2.5, 60.0, FLAGS }, + { "frame_duration", "Duration of a frame in milliseconds", OFFSET(frame_duration), AV_OPT_TYPE_FLOAT, { .dbl = 20.0 }, 2.5, 120.0, FLAGS }, { "packet_loss", "Expected packet loss percentage", OFFSET(packet_loss), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 100, FLAGS }, { "vbr", "Variable bit rate mode", OFFSET(vbr), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, 2, FLAGS, "vbr" }, { "off", "Use constant bit rate", 0, AV_OPT_TYPE_CONST, { .i64 = 0 }, 0, 0, FLAGS, "vbr" }, diff --git a/libavcodec/libvorbisdec.c b/libavcodec/libvorbisdec.c index ecf690a55..89cbbb41b 100644 --- a/libavcodec/libvorbisdec.c +++ b/libavcodec/libvorbisdec.c @@ -49,8 +49,16 @@ static int oggvorbis_decode_init(AVCodecContext *avccontext) { vorbis_comment_init(&context->vc) ; if(p[0] == 0 && p[1] == 30) { + int sizesum = 0; for(i = 0; i < 3; i++){ hsizes[i] = bytestream_get_be16((const uint8_t **)&p); + sizesum += 2 + hsizes[i]; + if (sizesum > avccontext->extradata_size) { + av_log(avccontext, AV_LOG_ERROR, "vorbis extradata too small\n"); + ret = AVERROR_INVALIDDATA; + goto error; + } + headers[i] = p; p += hsizes[i]; } diff --git a/libavcodec/libvpxdec.c b/libavcodec/libvpxdec.c index 04f27d339..164dbda49 100644 --- a/libavcodec/libvpxdec.c +++ b/libavcodec/libvpxdec.c @@ -47,8 +47,7 @@ static av_cold int vpx_init(AVCodecContext *avctx, { VPxContext *ctx = avctx->priv_data; struct vpx_codec_dec_cfg deccfg = { - /* token partitions+1 would be a decent choice */ - .threads = FFMIN(avctx->thread_count, 16) + .threads = FFMIN(avctx->thread_count ? avctx->thread_count : av_cpu_count(), 16) }; av_log(avctx, AV_LOG_INFO, "%s\n", vpx_codec_version_str()); diff --git a/libavcodec/libvpxenc.c b/libavcodec/libvpxenc.c index d0bd1e997..feb52ea0d 100644 --- a/libavcodec/libvpxenc.c +++ b/libavcodec/libvpxenc.c @@ -33,6 +33,7 @@ #include "libavutil/avassert.h" #include "libvpx.h" #include "profiles.h" +#include "libavutil/avstring.h" #include "libavutil/base64.h" #include "libavutil/common.h" #include "libavutil/internal.h" @@ -75,6 +76,7 @@ typedef struct VPxEncoderContext { struct FrameListData *coded_frame_list; int cpu_used; + int sharpness; /** * VP8 specific flags, see VP8F_* below. */ @@ -98,6 +100,8 @@ typedef struct VPxEncoderContext { int rc_undershoot_pct; int rc_overshoot_pct; + char *vp8_ts_parameters; + // VP9-only int lossless; int tile_columns; @@ -111,6 +115,7 @@ typedef struct VPxEncoderContext { int row_mt; int tune_content; int corpus_complexity; + int tpl_model; } VPxContext; /** String mappings for enum vp8e_enc_control_id */ @@ -126,6 +131,7 @@ static const char *const ctlidstr[] = { [VP8E_SET_TUNING] = "VP8E_SET_TUNING", [VP8E_SET_CQ_LEVEL] = "VP8E_SET_CQ_LEVEL", [VP8E_SET_MAX_INTRA_BITRATE_PCT] = "VP8E_SET_MAX_INTRA_BITRATE_PCT", + [VP8E_SET_SHARPNESS] = "VP8E_SET_SHARPNESS", #if CONFIG_LIBVPX_VP9_ENCODER [VP9E_SET_LOSSLESS] = "VP9E_SET_LOSSLESS", [VP9E_SET_TILE_COLUMNS] = "VP9E_SET_TILE_COLUMNS", @@ -146,6 +152,9 @@ static const char *const ctlidstr[] = { #ifdef VPX_CTRL_VP9E_SET_TUNE_CONTENT [VP9E_SET_TUNE_CONTENT] = "VP9E_SET_TUNE_CONTENT", #endif +#ifdef VPX_CTRL_VP9E_SET_TPL + [VP9E_SET_TPL] = "VP9E_SET_TPL", +#endif #endif }; @@ -165,6 +174,7 @@ static av_cold void dump_enc_cfg(AVCodecContext *avctx, { int width = -30; int level = AV_LOG_DEBUG; + int i; av_log(avctx, level, "vpx_codec_enc_cfg\n"); av_log(avctx, level, "generic settings\n" @@ -204,6 +214,25 @@ static av_cold void dump_enc_cfg(AVCodecContext *avctx, " %*s%u\n %*s%u\n", width, "rc_undershoot_pct:", cfg->rc_undershoot_pct, width, "rc_overshoot_pct:", cfg->rc_overshoot_pct); + av_log(avctx, level, "temporal layering settings\n" + " %*s%u\n", width, "ts_number_layers:", cfg->ts_number_layers); + av_log(avctx, level, + "\n %*s", width, "ts_target_bitrate:"); + for (i = 0; i < VPX_TS_MAX_LAYERS; i++) + av_log(avctx, level, "%u ", cfg->ts_target_bitrate[i]); + av_log(avctx, level, "\n"); + av_log(avctx, level, + "\n %*s", width, "ts_rate_decimator:"); + for (i = 0; i < VPX_TS_MAX_LAYERS; i++) + av_log(avctx, level, "%u ", cfg->ts_rate_decimator[i]); + av_log(avctx, level, "\n"); + av_log(avctx, level, + "\n %*s%u\n", width, "ts_periodicity:", cfg->ts_periodicity); + av_log(avctx, level, + "\n %*s", width, "ts_layer_id:"); + for (i = 0; i < VPX_TS_MAX_PERIODICITY; i++) + av_log(avctx, level, "%u ", cfg->ts_layer_id[i]); + av_log(avctx, level, "\n"); av_log(avctx, level, "decoder buffer model\n" " %*s%u\n %*s%u\n %*s%u\n", width, "rc_buf_sz:", cfg->rc_buf_sz, @@ -321,6 +350,39 @@ static av_cold int vpx_free(AVCodecContext *avctx) return 0; } +static void vp8_ts_parse_int_array(int *dest, char *value, size_t value_len, int max_entries) +{ + int dest_idx = 0; + char *saveptr = NULL; + char *token = av_strtok(value, ",", &saveptr); + + while (token && dest_idx < max_entries) { + dest[dest_idx++] = strtoul(token, NULL, 10); + token = av_strtok(NULL, ",", &saveptr); + } +} + +static int vp8_ts_param_parse(struct vpx_codec_enc_cfg *enccfg, char *key, char *value) +{ + size_t value_len = strlen(value); + + if (!value_len) + return -1; + + if (!strcmp(key, "ts_number_layers")) + enccfg->ts_number_layers = strtoul(value, &value, 10); + else if (!strcmp(key, "ts_target_bitrate")) + vp8_ts_parse_int_array(enccfg->ts_target_bitrate, value, value_len, VPX_TS_MAX_LAYERS); + else if (!strcmp(key, "ts_rate_decimator")) + vp8_ts_parse_int_array(enccfg->ts_rate_decimator, value, value_len, VPX_TS_MAX_LAYERS); + else if (!strcmp(key, "ts_periodicity")) + enccfg->ts_periodicity = strtoul(value, &value, 10); + else if (!strcmp(key, "ts_layer_id")) + vp8_ts_parse_int_array(enccfg->ts_layer_id, value, value_len, VPX_TS_MAX_PERIODICITY); + + return 0; +} + #if CONFIG_LIBVPX_VP9_ENCODER static int set_pix_fmt(AVCodecContext *avctx, vpx_codec_caps_t codec_caps, struct vpx_codec_enc_cfg *enccfg, vpx_codec_flags_t *flags, @@ -493,7 +555,8 @@ static av_cold int vpx_init(AVCodecContext *avctx, enccfg.g_h = avctx->height; enccfg.g_timebase.num = avctx->time_base.num; enccfg.g_timebase.den = avctx->time_base.den; - enccfg.g_threads = avctx->thread_count; + enccfg.g_threads = + FFMIN(avctx->thread_count ? avctx->thread_count : av_cpu_count(), 16); enccfg.g_lag_in_frames= ctx->lag_in_frames; if (avctx->flags & AV_CODEC_FLAG_PASS1) @@ -635,6 +698,22 @@ FF_ENABLE_DEPRECATION_WARNINGS enccfg.g_error_resilient = ctx->error_resilient || ctx->flags & VP8F_ERROR_RESILIENT; + if (CONFIG_LIBVPX_VP8_ENCODER && avctx->codec_id == AV_CODEC_ID_VP8 && ctx->vp8_ts_parameters) { + AVDictionary *dict = NULL; + AVDictionaryEntry* en = NULL; + + if (!av_dict_parse_string(&dict, ctx->vp8_ts_parameters, "=", ":", 0)) { + while ((en = av_dict_get(dict, "", en, AV_DICT_IGNORE_SUFFIX))) { + if (vp8_ts_param_parse(&enccfg, en->key, en->value) < 0) + av_log(avctx, AV_LOG_WARNING, + "Error parsing option '%s = %s'.\n", + en->key, en->value); + } + + av_dict_free(&dict); + } + } + dump_enc_cfg(avctx, &enccfg); /* Construct Encoder Context */ res = vpx_codec_enc_init(&ctx->encoder, iface, &enccfg, flags); @@ -674,6 +753,9 @@ FF_ENABLE_DEPRECATION_WARNINGS return AVERROR(EINVAL); } + if (ctx->sharpness >= 0) + codecctl_int(avctx, VP8E_SET_SHARPNESS, ctx->sharpness); + if (CONFIG_LIBVPX_VP8_ENCODER && avctx->codec_id == AV_CODEC_ID_VP8) { #if FF_API_PRIVATE_OPT FF_DISABLE_DEPRECATION_WARNINGS @@ -716,6 +798,10 @@ FF_ENABLE_DEPRECATION_WARNINGS #ifdef VPX_CTRL_VP9E_SET_TUNE_CONTENT if (ctx->tune_content >= 0) codecctl_int(avctx, VP9E_SET_TUNE_CONTENT, ctx->tune_content); +#endif +#ifdef VPX_CTRL_VP9E_SET_TPL + if (ctx->tpl_model >= 0) + codecctl_int(avctx, VP9E_SET_TPL, ctx->tpl_model); #endif } #endif @@ -892,7 +978,7 @@ static int queue_frames(AVCodecContext *avctx, AVPacket *pkt_out) are only good through the next vpx_codec call */ while ((pkt = vpx_codec_get_cx_data(&ctx->encoder, &iter)) && (!ctx->is_alpha || - (ctx->is_alpha && (pkt_alpha = vpx_codec_get_cx_data(&ctx->encoder_alpha, &iter_alpha))))) { + (pkt_alpha = vpx_codec_get_cx_data(&ctx->encoder_alpha, &iter_alpha)))) { switch (pkt->kind) { case VPX_CODEC_CX_FRAME_PKT: if (!size) { @@ -1021,6 +1107,12 @@ static int vpx_encode(AVCodecContext *avctx, AVPacket *pkt, #endif if (frame->pict_type == AV_PICTURE_TYPE_I) flags |= VPX_EFLAG_FORCE_KF; + if (CONFIG_LIBVPX_VP8_ENCODER && avctx->codec_id == AV_CODEC_ID_VP8 && frame->metadata) { + AVDictionaryEntry* en = av_dict_get(frame->metadata, "vp8-flags", NULL, 0); + if (en) { + flags |= strtoul(en->value, NULL, 10); + } + } } res = vpx_codec_encode(&ctx->encoder, rawimg, timestamp, @@ -1067,8 +1159,6 @@ static int vpx_encode(AVCodecContext *avctx, AVPacket *pkt, #define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM #define COMMON_OPTIONS \ - { "auto-alt-ref", "Enable use of alternate reference " \ - "frames (2-pass only)", OFFSET(auto_alt_ref), AV_OPT_TYPE_INT, {.i64 = -1}, -1, 2, VE}, \ { "lag-in-frames", "Number of frames to look ahead for " \ "alternate reference frame selection", OFFSET(lag_in_frames), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, VE}, \ { "arnr-maxframes", "altref noise reduction max frame count", OFFSET(arnr_max_frames), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, VE}, \ @@ -1108,11 +1198,16 @@ static int vpx_encode(AVCodecContext *avctx, AVPacket *pkt, {"arnr_strength", "altref noise reduction filter strength", offsetof(VPxContext, arnr_strength), AV_OPT_TYPE_INT, {.i64 = 3}, 0, 6, VE}, \ {"arnr_type", "altref noise reduction filter type", offsetof(VPxContext, arnr_type), AV_OPT_TYPE_INT, {.i64 = 3}, 1, 3, VE}, \ {"rc_lookahead", "Number of frames to look ahead for alternate reference frame selection", offsetof(VPxContext, lag_in_frames), AV_OPT_TYPE_INT, {.i64 = 25}, 0, 25, VE}, \ + {"sharpness", "Increase sharpness at the expense of lower PSNR", offsetof(VPxContext, sharpness), AV_OPT_TYPE_INT, {.i64 = -1}, -1, 7, VE}, #if CONFIG_LIBVPX_VP8_ENCODER static const AVOption vp8_options[] = { COMMON_OPTIONS + { "auto-alt-ref", "Enable use of alternate reference " + "frames (2-pass only)", OFFSET(auto_alt_ref), AV_OPT_TYPE_INT, {.i64 = -1}, -1, 2, VE}, { "cpu-used", "Quality/Speed ratio modifier", OFFSET(cpu_used), AV_OPT_TYPE_INT, {.i64 = 1}, -16, 16, VE}, + { "ts-parameters", "Temporal scaling configuration using a " + ":-separated list of key=value parameters", OFFSET(vp8_ts_parameters), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 0, VE}, LEGACY_OPTIONS { NULL } }; @@ -1121,6 +1216,8 @@ static const AVOption vp8_options[] = { #if CONFIG_LIBVPX_VP9_ENCODER static const AVOption vp9_options[] = { COMMON_OPTIONS + { "auto-alt-ref", "Enable use of alternate reference " + "frames (2-pass only)", OFFSET(auto_alt_ref), AV_OPT_TYPE_INT, {.i64 = -1}, -1, 6, VE}, { "cpu-used", "Quality/Speed ratio modifier", OFFSET(cpu_used), AV_OPT_TYPE_INT, {.i64 = 1}, -8, 8, VE}, { "lossless", "Lossless mode", OFFSET(lossless), AV_OPT_TYPE_INT, {.i64 = -1}, -1, 1, VE}, { "tile-columns", "Number of tile columns to use, log2", OFFSET(tile_columns), AV_OPT_TYPE_INT, {.i64 = -1}, -1, 6, VE}, @@ -1156,6 +1253,9 @@ static const AVOption vp9_options[] = { #endif #if VPX_ENCODER_ABI_VERSION >= 14 { "corpus-complexity", "corpus vbr complexity midpoint", OFFSET(corpus_complexity), AV_OPT_TYPE_INT, {.i64 = -1}, -1, 10000, VE }, +#endif +#ifdef VPX_CTRL_VP9E_SET_TPL + { "enable-tpl", "Enable temporal dependency model", OFFSET(tpl_model), AV_OPT_TYPE_BOOL, {.i64 = -1}, -1, 1, VE }, #endif LEGACY_OPTIONS { NULL } diff --git a/libavcodec/libx264.c b/libavcodec/libx264.c index 801affe82..dc4b4b100 100644 --- a/libavcodec/libx264.c +++ b/libavcodec/libx264.c @@ -40,6 +40,10 @@ #include #include +// from x264.h, for quant_offsets, Macroblocks are 16x16 +// blocks of pixels (with respect to the luma plane) +#define MB_SIZE 16 + typedef struct X264Context { AVClass *class; x264_param_t params; @@ -92,6 +96,9 @@ typedef struct X264Context { int noise_reduction; char *x264_params; + + int nb_reordered_opaque, next_reordered_opaque; + int64_t *reordered_opaque; } X264Context; static void X264_log(void *p, int level, const char *fmt, va_list args) @@ -161,6 +168,8 @@ static int avfmt2_num_planes(int avfmt) case AV_PIX_FMT_BGR0: case AV_PIX_FMT_BGR24: case AV_PIX_FMT_RGB24: + case AV_PIX_FMT_GRAY8: + case AV_PIX_FMT_GRAY10: return 1; default: @@ -276,14 +285,18 @@ static int X264_frame(AVCodecContext *ctx, AVPacket *pkt, const AVFrame *frame, int nnal, i, ret; x264_picture_t pic_out = {0}; int pict_type; + int bit_depth; + int64_t *out_opaque; + AVFrameSideData *sd; x264_picture_init( &x4->pic ); x4->pic.img.i_csp = x4->params.i_csp; #if X264_BUILD >= 153 - if (x4->params.i_bitdepth > 8) + bit_depth = x4->params.i_bitdepth; #else - if (x264_bit_depth > 8) + bit_depth = x264_bit_depth; #endif + if (bit_depth > 8) x4->pic.img.i_csp |= X264_CSP_HIGH_DEPTH; x4->pic.img.i_plane = avfmt2_num_planes(ctx->pix_fmt); @@ -295,6 +308,11 @@ static int X264_frame(AVCodecContext *ctx, AVPacket *pkt, const AVFrame *frame, x4->pic.i_pts = frame->pts; + x4->reordered_opaque[x4->next_reordered_opaque] = frame->reordered_opaque; + x4->pic.opaque = &x4->reordered_opaque[x4->next_reordered_opaque]; + x4->next_reordered_opaque++; + x4->next_reordered_opaque %= x4->nb_reordered_opaque; + switch (frame->pict_type) { case AV_PICTURE_TYPE_I: x4->pic.i_type = x4->forced_idr > 0 ? X264_TYPE_IDR @@ -334,6 +352,68 @@ static int X264_frame(AVCodecContext *ctx, AVPacket *pkt, const AVFrame *frame, } } } + + sd = av_frame_get_side_data(frame, AV_FRAME_DATA_REGIONS_OF_INTEREST); + if (sd) { + if (x4->params.rc.i_aq_mode == X264_AQ_NONE) { + av_log(ctx, AV_LOG_WARNING, "Adaptive quantization must be enabled to use ROI encoding, skipping ROI.\n"); + } else { + if (frame->interlaced_frame == 0) { + int mbx = (frame->width + MB_SIZE - 1) / MB_SIZE; + int mby = (frame->height + MB_SIZE - 1) / MB_SIZE; + int qp_range = 51 + 6 * (bit_depth - 8); + int nb_rois; + const AVRegionOfInterest *roi; + uint32_t roi_size; + float *qoffsets; + + roi = (const AVRegionOfInterest*)sd->data; + roi_size = roi->self_size; + if (!roi_size || sd->size % roi_size != 0) { + av_log(ctx, AV_LOG_ERROR, "Invalid AVRegionOfInterest.self_size.\n"); + return AVERROR(EINVAL); + } + nb_rois = sd->size / roi_size; + + qoffsets = av_mallocz_array(mbx * mby, sizeof(*qoffsets)); + if (!qoffsets) + return AVERROR(ENOMEM); + + // This list must be iterated in reverse because the first + // region in the list applies when regions overlap. + for (int i = nb_rois - 1; i >= 0; i--) { + int startx, endx, starty, endy; + float qoffset; + + roi = (const AVRegionOfInterest*)(sd->data + roi_size * i); + + starty = FFMIN(mby, roi->top / MB_SIZE); + endy = FFMIN(mby, (roi->bottom + MB_SIZE - 1)/ MB_SIZE); + startx = FFMIN(mbx, roi->left / MB_SIZE); + endx = FFMIN(mbx, (roi->right + MB_SIZE - 1)/ MB_SIZE); + + if (roi->qoffset.den == 0) { + av_free(qoffsets); + av_log(ctx, AV_LOG_ERROR, "AVRegionOfInterest.qoffset.den must not be zero.\n"); + return AVERROR(EINVAL); + } + qoffset = roi->qoffset.num * 1.0f / roi->qoffset.den; + qoffset = av_clipf(qoffset * qp_range, -qp_range, +qp_range); + + for (int y = starty; y < endy; y++) { + for (int x = startx; x < endx; x++) { + qoffsets[x + y*mbx] = qoffset; + } + } + } + + x4->pic.prop.quant_offsets = qoffsets; + x4->pic.prop.quant_offsets_free = av_free; + } else { + av_log(ctx, AV_LOG_WARNING, "interlaced_frame not supported for ROI encoding yet, skipping ROI.\n"); + } + } + } } do { @@ -348,6 +428,14 @@ static int X264_frame(AVCodecContext *ctx, AVPacket *pkt, const AVFrame *frame, pkt->pts = pic_out.i_pts; pkt->dts = pic_out.i_dts; + out_opaque = pic_out.opaque; + if (out_opaque >= x4->reordered_opaque && + out_opaque < &x4->reordered_opaque[x4->nb_reordered_opaque]) { + ctx->reordered_opaque = *out_opaque; + } else { + // Unexpected opaque pointer on picture output + ctx->reordered_opaque = 0; + } switch (pic_out.i_type) { case X264_TYPE_IDR: @@ -391,6 +479,7 @@ static av_cold int X264_close(AVCodecContext *avctx) av_freep(&avctx->extradata); av_freep(&x4->sei); + av_freep(&x4->reordered_opaque); if (x4->enc) { x264_encoder_close(x4->enc); @@ -442,6 +531,10 @@ static int convert_pix_fmt(enum AVPixelFormat pix_fmt) case AV_PIX_FMT_NV20: return X264_CSP_NV16; #ifdef X264_CSP_NV21 case AV_PIX_FMT_NV21: return X264_CSP_NV21; +#endif +#ifdef X264_CSP_I400 + case AV_PIX_FMT_GRAY8: + case AV_PIX_FMT_GRAY10: return X264_CSP_I400; #endif }; return 0; @@ -735,8 +828,13 @@ FF_ENABLE_DEPRECATION_WARNINGS x4->params.vui.i_sar_height = sh; x4->params.i_timebase_den = avctx->time_base.den; x4->params.i_timebase_num = avctx->time_base.num; - x4->params.i_fps_num = avctx->time_base.den; - x4->params.i_fps_den = avctx->time_base.num * avctx->ticks_per_frame; + if (avctx->framerate.num > 0 && avctx->framerate.den > 0) { + x4->params.i_fps_num = avctx->framerate.num; + x4->params.i_fps_den = avctx->framerate.den; + } else { + x4->params.i_fps_num = avctx->time_base.den; + x4->params.i_fps_den = avctx->time_base.num * avctx->ticks_per_frame; + } x4->params.analyse.b_psnr = avctx->flags & AV_CODEC_FLAG_PSNR; @@ -840,6 +938,14 @@ FF_ENABLE_DEPRECATION_WARNINGS cpb_props->max_bitrate = x4->params.rc.i_vbv_max_bitrate * 1000; cpb_props->avg_bitrate = x4->params.rc.i_bitrate * 1000; + // Overestimate the reordered opaque buffer size, in case a runtime + // reconfigure would increase the delay (which it shouldn't). + x4->nb_reordered_opaque = x264_encoder_maximum_delayed_frames(x4->enc) + 17; + x4->reordered_opaque = av_malloc_array(x4->nb_reordered_opaque, + sizeof(*x4->reordered_opaque)); + if (!x4->reordered_opaque) + return AVERROR(ENOMEM); + return 0; } @@ -885,6 +991,10 @@ static const enum AVPixelFormat pix_fmts_all[] = { AV_PIX_FMT_YUV422P10, AV_PIX_FMT_YUV444P10, AV_PIX_FMT_NV20, +#ifdef X264_CSP_I400 + AV_PIX_FMT_GRAY8, + AV_PIX_FMT_GRAY10, +#endif AV_PIX_FMT_NONE }; #if CONFIG_LIBX264RGB_ENCODER @@ -1049,7 +1159,8 @@ AVCodec ff_libx264_encoder = { .init = X264_init, .encode2 = X264_frame, .close = X264_close, - .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AUTO_THREADS, + .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AUTO_THREADS | + AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, .priv_class = &x264_class, .defaults = x264_defaults, .init_static_data = X264_init_static, @@ -1075,7 +1186,8 @@ AVCodec ff_libx264rgb_encoder = { .init = X264_init, .encode2 = X264_frame, .close = X264_close, - .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AUTO_THREADS, + .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AUTO_THREADS | + AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, .priv_class = &rgbclass, .defaults = x264_defaults, .pix_fmts = pix_fmts_8bit_rgb, @@ -1100,7 +1212,8 @@ AVCodec ff_libx262_encoder = { .init = X264_init, .encode2 = X264_frame, .close = X264_close, - .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AUTO_THREADS, + .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AUTO_THREADS | + AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE, .priv_class = &X262_class, .defaults = x264_defaults, .pix_fmts = pix_fmts_8bit, diff --git a/libavcodec/libx265.c b/libavcodec/libx265.c index c208c0f2d..665b78064 100644 --- a/libavcodec/libx265.c +++ b/libavcodec/libx265.c @@ -79,6 +79,7 @@ static av_cold int libx265_encode_close(AVCodecContext *avctx) static av_cold int libx265_encode_init(AVCodecContext *avctx) { libx265Context *ctx = avctx->priv_data; + AVCPBProperties *cpb_props = NULL; ctx->api = x265_api_get(av_pix_fmt_desc_get(avctx->pix_fmt)->comp[0].depth); if (!ctx->api) @@ -109,11 +110,17 @@ static av_cold int libx265_encode_init(AVCodecContext *avctx) } ctx->params->frameNumThreads = avctx->thread_count; - ctx->params->fpsNum = avctx->time_base.den; - ctx->params->fpsDenom = avctx->time_base.num * avctx->ticks_per_frame; + if (avctx->framerate.num > 0 && avctx->framerate.den > 0) { + ctx->params->fpsNum = avctx->framerate.num; + ctx->params->fpsDenom = avctx->framerate.den; + } else { + ctx->params->fpsNum = avctx->time_base.den; + ctx->params->fpsDenom = avctx->time_base.num * avctx->ticks_per_frame; + } ctx->params->sourceWidth = avctx->width; ctx->params->sourceHeight = avctx->height; ctx->params->bEnablePsnr = !!(avctx->flags & AV_CODEC_FLAG_PSNR); + ctx->params->bOpenGOP = !(avctx->flags & AV_CODEC_FLAG_CLOSED_GOP); /* Tune the CTU size based on input resolution. */ if (ctx->params->sourceWidth < 64 || ctx->params->sourceHeight < 64) @@ -126,6 +133,14 @@ static av_cold int libx265_encode_init(AVCodecContext *avctx) return AVERROR(EINVAL); } + + ctx->params->vui.bEnableVideoSignalTypePresentFlag = 1; + + ctx->params->vui.bEnableVideoFullRangeFlag = avctx->pix_fmt == AV_PIX_FMT_YUVJ420P || + avctx->pix_fmt == AV_PIX_FMT_YUVJ422P || + avctx->pix_fmt == AV_PIX_FMT_YUVJ444P || + avctx->color_range == AVCOL_RANGE_JPEG; + if ((avctx->color_primaries <= AVCOL_PRI_SMPTE432 && avctx->color_primaries != AVCOL_PRI_UNSPECIFIED) || (avctx->color_trc <= AVCOL_TRC_ARIB_STD_B67 && @@ -133,7 +148,6 @@ static av_cold int libx265_encode_init(AVCodecContext *avctx) (avctx->colorspace <= AVCOL_SPC_ICTCP && avctx->colorspace != AVCOL_SPC_UNSPECIFIED)) { - ctx->params->vui.bEnableVideoSignalTypePresentFlag = 1; ctx->params->vui.bEnableColorDescriptionPresentFlag = 1; // x265 validates the parameters internally @@ -204,6 +218,16 @@ static av_cold int libx265_encode_init(AVCodecContext *avctx) ctx->params->rc.rateControlMode = X265_RC_ABR; } + ctx->params->rc.vbvBufferSize = avctx->rc_buffer_size / 1000; + ctx->params->rc.vbvMaxBitrate = avctx->rc_max_rate / 1000; + + cpb_props = ff_add_cpb_side_data(avctx); + if (!cpb_props) + return AVERROR(ENOMEM); + cpb_props->buffer_size = ctx->params->rc.vbvBufferSize * 1000; + cpb_props->max_bitrate = ctx->params->rc.vbvMaxBitrate * 1000; + cpb_props->avg_bitrate = ctx->params->rc.bitrate * 1000; + if (!(avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER)) ctx->params->bRepeatHeaders = 1; @@ -232,6 +256,11 @@ static av_cold int libx265_encode_init(AVCodecContext *avctx) } } + if (ctx->params->rc.vbvBufferSize && avctx->rc_initial_buffer_occupancy > 1000 && + ctx->params->rc.vbvBufferInit == 0.9) { + ctx->params->rc.vbvBufferInit = (float)avctx->rc_initial_buffer_occupancy / 1000; + } + if (ctx->profile) { if (ctx->api->param_apply_profile(ctx->params, ctx->profile) < 0) { int i; @@ -276,6 +305,67 @@ static av_cold int libx265_encode_init(AVCodecContext *avctx) return 0; } +static av_cold int libx265_encode_set_roi(libx265Context *ctx, const AVFrame *frame, x265_picture* pic) +{ + AVFrameSideData *sd = av_frame_get_side_data(frame, AV_FRAME_DATA_REGIONS_OF_INTEREST); + if (sd) { + if (ctx->params->rc.aqMode == X265_AQ_NONE) { + av_log(ctx, AV_LOG_WARNING, "Adaptive quantization must be enabled to use ROI encoding, skipping ROI.\n"); + } else { + /* 8x8 block when qg-size is 8, 16*16 block otherwise. */ + int mb_size = (ctx->params->rc.qgSize == 8) ? 8 : 16; + int mbx = (frame->width + mb_size - 1) / mb_size; + int mby = (frame->height + mb_size - 1) / mb_size; + int qp_range = 51 + 6 * (pic->bitDepth - 8); + int nb_rois; + const AVRegionOfInterest *roi; + uint32_t roi_size; + float *qoffsets; /* will be freed after encode is called. */ + + roi = (const AVRegionOfInterest*)sd->data; + roi_size = roi->self_size; + if (!roi_size || sd->size % roi_size != 0) { + av_log(ctx, AV_LOG_ERROR, "Invalid AVRegionOfInterest.self_size.\n"); + return AVERROR(EINVAL); + } + nb_rois = sd->size / roi_size; + + qoffsets = av_mallocz_array(mbx * mby, sizeof(*qoffsets)); + if (!qoffsets) + return AVERROR(ENOMEM); + + // This list must be iterated in reverse because the first + // region in the list applies when regions overlap. + for (int i = nb_rois - 1; i >= 0; i--) { + int startx, endx, starty, endy; + float qoffset; + + roi = (const AVRegionOfInterest*)(sd->data + roi_size * i); + + starty = FFMIN(mby, roi->top / mb_size); + endy = FFMIN(mby, (roi->bottom + mb_size - 1)/ mb_size); + startx = FFMIN(mbx, roi->left / mb_size); + endx = FFMIN(mbx, (roi->right + mb_size - 1)/ mb_size); + + if (roi->qoffset.den == 0) { + av_free(qoffsets); + av_log(ctx, AV_LOG_ERROR, "AVRegionOfInterest.qoffset.den must not be zero.\n"); + return AVERROR(EINVAL); + } + qoffset = roi->qoffset.num * 1.0f / roi->qoffset.den; + qoffset = av_clipf(qoffset * qp_range, -qp_range, +qp_range); + + for (int y = starty; y < endy; y++) + for (int x = startx; x < endx; x++) + qoffsets[x + y*mbx] = qoffset; + } + + pic->quantOffsets = qoffsets; + } + } + return 0; +} + static int libx265_encode_frame(AVCodecContext *avctx, AVPacket *pkt, const AVFrame *pic, int *got_packet) { @@ -305,10 +395,17 @@ static int libx265_encode_frame(AVCodecContext *avctx, AVPacket *pkt, pic->pict_type == AV_PICTURE_TYPE_P ? X265_TYPE_P : pic->pict_type == AV_PICTURE_TYPE_B ? X265_TYPE_B : X265_TYPE_AUTO; + + ret = libx265_encode_set_roi(ctx, pic, &x265pic); + if (ret < 0) + return ret; } ret = ctx->api->encoder_encode(ctx->encoder, &nal, &nnal, pic ? &x265pic : NULL, &x265pic_out); + + av_freep(&x265pic.quantOffsets); + if (ret < 0) return AVERROR_EXTERNAL; @@ -366,8 +463,11 @@ FF_ENABLE_DEPRECATION_WARNINGS static const enum AVPixelFormat x265_csp_eight[] = { AV_PIX_FMT_YUV420P, + AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUV422P, + AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUV444P, + AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_GBRP, AV_PIX_FMT_GRAY8, AV_PIX_FMT_NONE @@ -375,8 +475,11 @@ static const enum AVPixelFormat x265_csp_eight[] = { static const enum AVPixelFormat x265_csp_ten[] = { AV_PIX_FMT_YUV420P, + AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUV422P, + AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUV444P, + AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_GBRP, AV_PIX_FMT_YUV420P10, AV_PIX_FMT_YUV422P10, @@ -389,8 +492,11 @@ static const enum AVPixelFormat x265_csp_ten[] = { static const enum AVPixelFormat x265_csp_twelve[] = { AV_PIX_FMT_YUV420P, + AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUV422P, + AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUV444P, + AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_GBRP, AV_PIX_FMT_YUV420P10, AV_PIX_FMT_YUV422P10, diff --git a/libavcodec/libxavs2.c b/libavcodec/libxavs2.c new file mode 100644 index 000000000..d5c455797 --- /dev/null +++ b/libavcodec/libxavs2.c @@ -0,0 +1,293 @@ +/* + * AVS2 encoding using the xavs2 library + * + * Copyright (C) 2018 Yiqun Xu, + * Falei Luo, + * Huiwen Ren, + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "xavs2.h" +#include "mpeg12.h" +#include "libavutil/avstring.h" + +#define xavs2_opt_set2(name, format, ...) do{ \ + char opt_str[16] = {0}; \ + int err; \ + av_strlcatf(opt_str, sizeof(opt_str), format, __VA_ARGS__); \ + err = cae->api->opt_set2(cae->param, name, opt_str); \ + if (err) {\ + av_log(avctx, AV_LOG_WARNING, "Invalid value for %s: %s\n", name, opt_str);\ + }\ +} while(0); + +typedef struct XAVS2EContext { + AVClass *class; + + int lcu_row_threads; + int initial_qp; + int qp; + int max_qp; + int min_qp; + int preset_level; + int log_level; + + void *encoder; + char *xavs2_opts; + + xavs2_outpacket_t packet; + xavs2_param_t *param; + + const xavs2_api_t *api; + +} XAVS2EContext; + +static av_cold int xavs2_init(AVCodecContext *avctx) +{ + XAVS2EContext *cae= avctx->priv_data; + int bit_depth, code; + + bit_depth = avctx->pix_fmt == AV_PIX_FMT_YUV420P ? 8 : 10; + + /* get API handler */ + cae->api = xavs2_api_get(bit_depth); + if (!cae->api) { + av_log(avctx, AV_LOG_ERROR, "api get failed\n"); + return AVERROR_EXTERNAL; + } + + cae->param = cae->api->opt_alloc(); + if (!cae->param) { + av_log(avctx, AV_LOG_ERROR, "param alloc failed\n"); + return AVERROR(ENOMEM); + } + + xavs2_opt_set2("Width", "%d", avctx->width); + xavs2_opt_set2("Height", "%d", avctx->height); + xavs2_opt_set2("BFrames", "%d", avctx->max_b_frames); + xavs2_opt_set2("BitDepth", "%d", bit_depth); + xavs2_opt_set2("Log", "%d", cae->log_level); + xavs2_opt_set2("Preset", "%d", cae->preset_level); + + xavs2_opt_set2("IntraPeriodMax", "%d", avctx->gop_size); + xavs2_opt_set2("IntraPeriodMin", "%d", avctx->gop_size); + + xavs2_opt_set2("ThreadFrames", "%d", avctx->thread_count); + xavs2_opt_set2("ThreadRows", "%d", cae->lcu_row_threads); + + xavs2_opt_set2("OpenGOP", "%d", !(avctx->flags & AV_CODEC_FLAG_CLOSED_GOP)); + + if (cae->xavs2_opts) { + AVDictionary *dict = NULL; + AVDictionaryEntry *en = NULL; + + if (!av_dict_parse_string(&dict, cae->xavs2_opts, "=", ":", 0)) { + while ((en = av_dict_get(dict, "", en, AV_DICT_IGNORE_SUFFIX))) { + xavs2_opt_set2(en->key, "%s", en->value); + } + av_dict_free(&dict); + } + } + + /* Rate control */ + if (avctx->bit_rate > 0) { + xavs2_opt_set2("RateControl", "%d", 1); + xavs2_opt_set2("TargetBitRate", "%"PRId64"", avctx->bit_rate); + xavs2_opt_set2("InitialQP", "%d", cae->initial_qp); + xavs2_opt_set2("MaxQP", "%d", avctx->qmax >= 0 ? avctx->qmax : cae->max_qp); + xavs2_opt_set2("MinQP", "%d", avctx->qmin >= 0 ? avctx->qmin : cae->min_qp); + } else { + xavs2_opt_set2("InitialQP", "%d", cae->qp); + } + + + ff_mpeg12_find_best_frame_rate(avctx->framerate, &code, NULL, NULL, 0); + + xavs2_opt_set2("FrameRate", "%d", code); + + cae->encoder = cae->api->encoder_create(cae->param); + + if (!cae->encoder) { + av_log(avctx,AV_LOG_ERROR, "Can not create encoder. Null pointer returned\n"); + return AVERROR(EINVAL); + } + + return 0; +} + +static void xavs2_copy_frame_with_shift(xavs2_picture_t *pic, const AVFrame *frame, const int shift_in) +{ + int j, k; + for (k = 0; k < 3; k++) { + int i_stride = pic->img.i_stride[k]; + for (j = 0; j < pic->img.i_lines[k]; j++) { + uint16_t *p_plane = (uint16_t *)&pic->img.img_planes[k][j * i_stride]; + int i; + uint8_t *p_buffer = frame->data[k] + frame->linesize[k] * j; + memset(p_plane, 0, i_stride); + for (i = 0; i < pic->img.i_width[k]; i++) { + p_plane[i] = p_buffer[i] << shift_in; + } + } + } +} + +static void xavs2_copy_frame(xavs2_picture_t *pic, const AVFrame *frame) +{ + int j, k; + for (k = 0; k < 3; k++) { + for (j = 0; j < pic->img.i_lines[k]; j++) { + memcpy( pic->img.img_planes[k] + pic->img.i_stride[k] * j, + frame->data[k]+frame->linesize[k] * j, + pic->img.i_width[k] * pic->img.in_sample_size); + } + } +} + +static int xavs2_encode_frame(AVCodecContext *avctx, AVPacket *pkt, + const AVFrame *frame, int *got_packet) +{ + XAVS2EContext *cae = avctx->priv_data; + xavs2_picture_t pic; + int ret; + + /* create the XAVS2 video encoder */ + /* read frame data and send to the XAVS2 video encoder */ + if (cae->api->encoder_get_buffer(cae->encoder, &pic) < 0) { + av_log(avctx,AV_LOG_ERROR, "failed to get frame buffer\n"); + return AVERROR_EXTERNAL; + } + if (frame) { + switch (frame->format) { + case AV_PIX_FMT_YUV420P: + if (pic.img.in_sample_size == pic.img.enc_sample_size) { + xavs2_copy_frame(&pic, frame); + } else { + const int shift_in = atoi(cae->api->opt_get(cae->param, "SampleShift")); + xavs2_copy_frame_with_shift(&pic, frame, shift_in); + } + break; + case AV_PIX_FMT_YUV420P10: + if (pic.img.in_sample_size == pic.img.enc_sample_size) { + xavs2_copy_frame(&pic, frame); + break; + } + default: + av_log(avctx, AV_LOG_ERROR, "Unsupported pixel format\n"); + return AVERROR(EINVAL); + break; + } + + pic.i_state = 0; + pic.i_pts = frame->pts; + pic.i_type = XAVS2_TYPE_AUTO; + + ret = cae->api->encoder_encode(cae->encoder, &pic, &cae->packet); + + if (ret) { + av_log(avctx, AV_LOG_ERROR, "encode failed\n"); + return AVERROR_EXTERNAL; + } + + } else { + cae->api->encoder_encode(cae->encoder, NULL, &cae->packet); + } + + if ((cae->packet.len) && (cae->packet.state != XAVS2_STATE_FLUSH_END)){ + + if (av_new_packet(pkt, cae->packet.len) < 0){ + av_log(avctx, AV_LOG_ERROR, "packet alloc failed\n"); + cae->api->encoder_packet_unref(cae->encoder, &cae->packet); + return AVERROR(ENOMEM); + } + + pkt->pts = cae->packet.pts; + pkt->dts = cae->packet.dts; + + memcpy(pkt->data, cae->packet.stream, cae->packet.len); + pkt->size = cae->packet.len; + + cae->api->encoder_packet_unref(cae->encoder, &cae->packet); + + *got_packet = 1; + } else { + *got_packet = 0; + } + + return 0; +} + +static av_cold int xavs2_close(AVCodecContext *avctx) +{ + XAVS2EContext *cae = avctx->priv_data; + /* destroy the encoder */ + if (cae->api) { + cae->api->encoder_destroy(cae->encoder); + + if (cae->param) { + cae->api->opt_destroy(cae->param); + } + } + return 0; +} + +#define OFFSET(x) offsetof(XAVS2EContext, x) +#define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM + +static const AVOption options[] = { + { "lcu_row_threads" , "number of parallel threads for rows" , OFFSET(lcu_row_threads) , AV_OPT_TYPE_INT, {.i64 = 0 }, 0, INT_MAX, VE }, + { "initial_qp" , "Quantization initial parameter" , OFFSET(initial_qp) , AV_OPT_TYPE_INT, {.i64 = 34 }, 1, 63, VE }, + { "qp" , "Quantization parameter" , OFFSET(qp) , AV_OPT_TYPE_INT, {.i64 = 34 }, 1, 63, VE }, + { "max_qp" , "max qp for rate control" , OFFSET(max_qp) , AV_OPT_TYPE_INT, {.i64 = 55 }, 0, 63, VE }, + { "min_qp" , "min qp for rate control" , OFFSET(min_qp) , AV_OPT_TYPE_INT, {.i64 = 20 }, 0, 63, VE }, + { "speed_level" , "Speed level, higher is better but slower", OFFSET(preset_level) , AV_OPT_TYPE_INT, {.i64 = 0 }, 0, 9, VE }, + { "log_level" , "log level: -1: none, 0: error, 1: warning, 2: info, 3: debug", OFFSET(log_level) , AV_OPT_TYPE_INT, {.i64 = 0 }, -1, 3, VE }, + { "xavs2-params" , "set the xavs2 configuration using a :-separated list of key=value parameters", OFFSET(xavs2_opts), AV_OPT_TYPE_STRING, { 0 }, 0, 0, VE }, + { NULL }, +}; + +static const AVClass libxavs2 = { + .class_name = "XAVS2EContext", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; + +static const AVCodecDefault xavs2_defaults[] = { + { "b", "0" }, + { "g", "48"}, + { "bf", "7" }, + { NULL }, +}; + +AVCodec ff_libxavs2_encoder = { + .name = "libxavs2", + .long_name = NULL_IF_CONFIG_SMALL("libxavs2 AVS2-P2/IEEE1857.4"), + .type = AVMEDIA_TYPE_VIDEO, + .id = AV_CODEC_ID_AVS2, + .priv_data_size = sizeof(XAVS2EContext), + .init = xavs2_init, + .encode2 = xavs2_encode_frame, + .close = xavs2_close, + .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AUTO_THREADS, + .pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_YUV420P, + AV_PIX_FMT_NONE }, + .priv_class = &libxavs2, + .defaults = xavs2_defaults, + .wrapper_name = "libxavs2", +} ; diff --git a/libavcodec/libzvbi-teletextdec.c b/libavcodec/libzvbi-teletextdec.c index 30d059343..3515f3392 100644 --- a/libavcodec/libzvbi-teletextdec.c +++ b/libavcodec/libzvbi-teletextdec.c @@ -26,6 +26,7 @@ #include "libavutil/internal.h" #include "libavutil/intreadwrite.h" #include "libavutil/log.h" +#include "libavutil/common.h" #include @@ -56,7 +57,7 @@ typedef struct TeletextContext char *pgno; int x_offset; int y_offset; - int format_id; /* 0 = bitmap, 1 = text/ass */ + int format_id; /* 0 = bitmap, 1 = text/ass, 2 = ass */ int chop_top; int sub_duration; /* in msec */ int transparent_bg; @@ -70,14 +71,61 @@ typedef struct TeletextContext int handler_ret; vbi_decoder * vbi; -#ifdef DEBUG - vbi_export * ex; -#endif vbi_sliced sliced[MAX_SLICES]; int readorder; + uint8_t subtitle_map[2048]; + int last_pgno; + int last_p5; + int last_ass_alignment; } TeletextContext; +static int my_ass_subtitle_header(AVCodecContext *avctx) +{ + int ret = ff_ass_subtitle_header_default(avctx); + char *new_header; + uint8_t *event_pos; + + if (ret < 0) + return ret; + + event_pos = strstr(avctx->subtitle_header, "\r\n[Events]\r\n"); + if (!event_pos) + return AVERROR_BUG; + + new_header = av_asprintf("%.*s%s%s", + (int)(event_pos - avctx->subtitle_header), avctx->subtitle_header, + "Style: " + "Teletext," /* Name */ + "Monospace,11," /* Font{name,size} */ + "&Hffffff,&Hffffff,&H0,&H0," /* {Primary,Secondary,Outline,Back}Colour */ + "0,0,0,0," /* Bold, Italic, Underline, StrikeOut */ + "160,100," /* Scale{X,Y} */ + "0,0," /* Spacing, Angle */ + "3,0.1,0," /* BorderStyle, Outline, Shadow */ + "5,1,1,1," /* Alignment, Margin[LRV] */ + "0\r\n" /* Encoding */ + "Style: " + "Subtitle," /* Name */ + "Monospace,16," /* Font{name,size} */ + "&Hffffff,&Hffffff,&H0,&H0," /* {Primary,Secondary,Outline,Back}Colour */ + "0,0,0,0," /* Bold, Italic, Underline, StrikeOut */ + "100,100," /* Scale{X,Y} */ + "0,0," /* Spacing, Angle */ + "1,1,1," /* BorderStyle, Outline, Shadow */ + "8,48,48,20," /* Alignment, Margin[LRV] */ + "0\r\n" /* Encoding */ + , event_pos); + + if (!new_header) + return AVERROR(ENOMEM); + + av_free(avctx->subtitle_header); + avctx->subtitle_header = new_header; + avctx->subtitle_header_size = strlen(new_header); + return 0; +} + static int chop_spaces_utf8(const unsigned char* t, int len) { t += len; @@ -181,6 +229,184 @@ static int gen_sub_text(TeletextContext *ctx, AVSubtitleRect *sub_rect, vbi_page return 0; } +static void bprint_color(const char *type, AVBPrint *buf, vbi_page *page, unsigned ci) +{ + int r = VBI_R(page->color_map[ci]); + int g = VBI_G(page->color_map[ci]); + int b = VBI_B(page->color_map[ci]); + av_bprintf(buf, "{\\%s&H%02X%02X%02X&}", type, b, g, r); +} + +#define IS_TXT_SPACE(ch) ((ch).unicode < 0x0020 || (ch).unicode >= 0xe000 || (ch).unicode == 0x00a0 ||\ + (ch).size > VBI_DOUBLE_SIZE || (ch).opacity == VBI_TRANSPARENT_SPACE) + +static void get_trim_info(vbi_page *page, vbi_char *row, int *leading, int *trailing, int *olen) +{ + int i, len = 0; + int char_seen = 0; + + *leading = 0; + + for (i = 0; i < page->columns; i++) { + uint16_t out = IS_TXT_SPACE(row[i]) ? 32 : row[i].unicode; + + if (out == 32 && !char_seen) + (*leading)++; + else if (out != 32) + char_seen = 1, len = i - (*leading) + 1; + } + + *olen = len; + *trailing = len > 0 ? page->columns - *leading - len : page->columns; +} + +static void decode_string(vbi_page *page, vbi_char *row, AVBPrint *buf, + int start, int end, vbi_color *cur_color, vbi_color *cur_back_color) +{ + int i; + + for (i = start; i < end; i++) { + uint16_t out = IS_TXT_SPACE(row[i]) ? 32 : row[i].unicode; + + if (*cur_color != row[i].foreground) { + bprint_color("c", buf, page, row[i].foreground); + *cur_color = row[i].foreground; + } + if (*cur_back_color != row[i].background) { + bprint_color("3c", buf, page, row[i].background); + *cur_back_color = row[i].background; + } + + if (out == 32) { + av_bprintf(buf, "\\h"); + } else if (out == '\\' || out == '{' || out == '}') { + av_bprintf(buf, "\\%c", (char)out); + } else { + char tmp; + /* convert to utf-8 */ + PUT_UTF8(out, tmp, av_bprint_chars(buf, tmp, 1);); + } + } +} + +/* Draw a page as ass formatted text */ +static int gen_sub_ass(TeletextContext *ctx, AVSubtitleRect *sub_rect, vbi_page *page, int chop_top) +{ + int i; + int leading, trailing, len; + int last_trailing = -1, last_leading = -1; + int min_trailing = page->columns, min_leading = page->columns; + int alignment = 2; + int vertical_align = -1; + int can_align_left = 1, can_align_right = 1, can_align_center = 1; + int is_subtitle_page = ctx->subtitle_map[page->pgno & 0x7ff]; + int empty_lines = 0; + vbi_color cur_color = VBI_WHITE; + vbi_color cur_back_color = VBI_BLACK; + AVBPrint buf; + + av_bprint_init(&buf, 0, AV_BPRINT_SIZE_UNLIMITED); + + for (i = chop_top; i < page->rows; i++) { + vbi_char *row = page->text + i * page->columns; + + get_trim_info(page, row, &leading, &trailing, &len); + + if (len) { + if (last_leading != -1 && last_leading != leading || leading > 5) + can_align_left = 0; + if (last_trailing != -1 && last_trailing != trailing || trailing > 2) + can_align_right = 0; + if (last_trailing != -1 && (FFABS((trailing - leading) - (last_trailing - last_leading)) > 1) || trailing - leading > 4) + can_align_center = 0; + last_leading = leading; + last_trailing = trailing; + min_leading = FFMIN(leading, min_leading); + min_trailing = FFMIN(trailing, min_trailing); + } + } + + if (!can_align_right && can_align_left && !can_align_center) { + ctx->last_ass_alignment = alignment = 1; + } else if (!can_align_right && !can_align_left && can_align_center) { + ctx->last_ass_alignment = alignment = 2; + } else if (can_align_right && !can_align_left && !can_align_center) { + ctx->last_ass_alignment = alignment = 3; + } else { + if (ctx->last_ass_alignment == 1 && can_align_left || + ctx->last_ass_alignment == 2 && can_align_center || + ctx->last_ass_alignment == 3 && can_align_right) + alignment = ctx->last_ass_alignment; + } + + for (i = chop_top; i < page->rows; i++) { + int j; + vbi_char *row = page->text + i * page->columns; + int is_transparent_line; + + for (j = 0; j < page->columns; j++) + if (row[j].opacity != VBI_TRANSPARENT_SPACE) + break; + is_transparent_line = (j == page->columns); + + len = is_transparent_line ? 0 : page->columns; + leading = trailing = is_transparent_line ? page->columns : 0; + + if (is_subtitle_page) { + if (!is_transparent_line) + get_trim_info(page, row, &leading, &trailing, &len); + + if (vertical_align == -1 && len) { + vertical_align = (2 - (av_clip(i + 1, 0, 23) / 8)); + av_bprintf(&buf, "{\\an%d}", alignment + vertical_align * 3); + if (vertical_align != 2) + empty_lines = 0; + } + + if (len && empty_lines > 1) + for (empty_lines /= 2; empty_lines > 0; empty_lines--) + av_bprintf(&buf, " \\N"); + + if (alignment == 1 || alignment == 2 && !can_align_center) + leading = min_leading; + if (alignment == 3 || alignment == 2 && !can_align_center) + trailing = min_trailing; + } + + if (len || !is_subtitle_page) { + decode_string(page, row, &buf, leading, page->columns - trailing, &cur_color, &cur_back_color); + av_bprintf(&buf, " \\N"); + empty_lines = 0; + } else { + empty_lines++; + } + } + + if (vertical_align == 0) + for (empty_lines = (empty_lines - 1) / 2; empty_lines > 0; empty_lines--) + av_bprintf(&buf, " \\N"); + + if (!av_bprint_is_complete(&buf)) { + av_bprint_finalize(&buf, NULL); + return AVERROR(ENOMEM); + } + + if (buf.len) { + sub_rect->type = SUBTITLE_ASS; + sub_rect->ass = ff_ass_get_dialog(ctx->readorder++, 0, is_subtitle_page ? "Subtitle" : "Teletext", NULL, buf.str); + + if (!sub_rect->ass) { + av_bprint_finalize(&buf, NULL); + return AVERROR(ENOMEM); + } + av_log(ctx, AV_LOG_DEBUG, "subtext:%s:txetbus\n", sub_rect->ass); + } else { + sub_rect->type = SUBTITLE_NONE; + } + av_bprint_finalize(&buf, NULL); + return 0; +} + static void fix_transparency(TeletextContext *ctx, AVSubtitleRect *sub_rect, vbi_page *page, int chop_top, int resx, int resy) { @@ -284,16 +510,14 @@ static void handler(vbi_event *ev, void *user_data) vbi_page page; int res; char pgno_str[12]; - vbi_subno subno; - vbi_page_type vpt; int chop_top; - char *lang; + int is_subtitle_page = ctx->subtitle_map[ev->ev.ttx_page.pgno & 0x7ff]; snprintf(pgno_str, sizeof pgno_str, "%03x", ev->ev.ttx_page.pgno); av_log(ctx, AV_LOG_DEBUG, "decoded page %s.%02x\n", pgno_str, ev->ev.ttx_page.subno & 0xFF); - if (strcmp(ctx->pgno, "*") && !strstr(ctx->pgno, pgno_str)) + if (strcmp(ctx->pgno, "*") && (strcmp(ctx->pgno, "subtitle") || !is_subtitle_page) && !strstr(ctx->pgno, pgno_str)) return; if (ctx->handler_ret < 0) return; @@ -306,18 +530,7 @@ static void handler(vbi_event *ev, void *user_data) if (!res) return; -#ifdef DEBUG - fprintf(stderr, "\nSaving res=%d dy0=%d dy1=%d...\n", - res, page.dirty.y0, page.dirty.y1); - fflush(stderr); - - if (!vbi_export_stdio(ctx->ex, stderr, &page)) - fprintf(stderr, "failed: %s\n", vbi_export_errstr(ctx->ex)); -#endif - - vpt = vbi_classify_page(ctx->vbi, ev->ev.ttx_page.pgno, &subno, &lang); - chop_top = ctx->chop_top || - ((page.rows > 1) && (vpt == VBI_SUBTITLE_PAGE)); + chop_top = ctx->chop_top || ((page.rows > 1) && is_subtitle_page); av_log(ctx, AV_LOG_DEBUG, "%d x %d page chop:%d\n", page.columns, page.rows, chop_top); @@ -331,9 +544,20 @@ static void handler(vbi_event *ev, void *user_data) cur_page->pgno = ev->ev.ttx_page.pgno; cur_page->subno = ev->ev.ttx_page.subno; if (cur_page->sub_rect) { - res = (ctx->format_id == 0) ? - gen_sub_bitmap(ctx, cur_page->sub_rect, &page, chop_top) : - gen_sub_text (ctx, cur_page->sub_rect, &page, chop_top); + switch (ctx->format_id) { + case 0: + res = gen_sub_bitmap(ctx, cur_page->sub_rect, &page, chop_top); + break; + case 1: + res = gen_sub_text(ctx, cur_page->sub_rect, &page, chop_top); + break; + case 2: + res = gen_sub_ass(ctx, cur_page->sub_rect, &page, chop_top); + break; + default: + res = AVERROR_BUG; + break; + } if (res < 0) { av_freep(&cur_page->sub_rect); ctx->handler_ret = res; @@ -369,11 +593,37 @@ static int slice_to_vbi_lines(TeletextContext *ctx, uint8_t* buf, int size) else { int line_offset = buf[2] & 0x1f; int field_parity = buf[2] & 0x20; - int i; + uint8_t *p = ctx->sliced[lines].data; + int i, pmag; ctx->sliced[lines].id = VBI_SLICED_TELETEXT_B; ctx->sliced[lines].line = (line_offset > 0 ? (line_offset + (field_parity ? 0 : 313)) : 0); for (i = 0; i < 42; i++) - ctx->sliced[lines].data[i] = vbi_rev8(buf[4 + i]); + p[i] = vbi_rev8(buf[4 + i]); + /* Unfortunately libzvbi does not expose page flags, and + * vbi_classify_page only checks MIP, so we have to manually + * decode the page flags and store the results. */ + pmag = vbi_unham16p(p); + if (pmag >= 0 && pmag >> 3 == 0) { // We found a row 0 header + int page = vbi_unham16p(p + 2); + int flags1 = vbi_unham16p(p + 6); + int flags2 = vbi_unham16p(p + 8); + if (page >= 0 && flags1 >= 0 && flags2 >= 0) { + int pgno = ((pmag & 7) << 8) + page; + // Check for disabled NEWSFLASH flag and enabled SUBTITLE and SUPRESS_HEADER flags + ctx->subtitle_map[pgno] = (!(flags1 & 0x40) && flags1 & 0x80 && flags2 & 0x01); + // Propagate ERASE_PAGE flag for repeated page headers to work around a libzvbi bug + if (ctx->subtitle_map[pgno] && pgno == ctx->last_pgno) { + int last_byte9 = vbi_unham8(ctx->last_p5); + if (last_byte9 >= 0 && last_byte9 & 0x8) { + int byte9 = vbi_unham8(p[5]); + if (byte9 >= 0) + p[5] = vbi_ham8(byte9 | 0x8); + } + } + ctx->last_pgno = pgno; + ctx->last_p5 = p[5]; + } + } lines++; } } @@ -421,13 +671,6 @@ static int teletext_decode_frame(AVCodecContext *avctx, void *data, int *data_si ff_dlog(avctx, "ctx=%p buf_size=%d lines=%u pkt_pts=%7.3f\n", ctx, pkt->size, lines, (double)pkt->pts/90000.0); if (lines > 0) { -#ifdef DEBUG - int i; - av_log(avctx, AV_LOG_DEBUG, "line numbers:"); - for(i = 0; i < lines; i++) - av_log(avctx, AV_LOG_DEBUG, " %d", ctx->sliced[i].line); - av_log(avctx, AV_LOG_DEBUG, "\n"); -#endif vbi_decode(ctx->vbi, ctx->sliced, lines, 0.0); ctx->lines_processed += lines; } @@ -442,7 +685,7 @@ static int teletext_decode_frame(AVCodecContext *avctx, void *data, int *data_si // is there a subtitle to pass? if (ctx->nb_pages) { int i; - sub->format = ctx->format_id; + sub->format = !!ctx->format_id; sub->start_display_time = 0; sub->end_display_time = ctx->sub_duration; sub->num_rects = 0; @@ -501,18 +744,23 @@ static int teletext_init_decoder(AVCodecContext *avctx) ctx->vbi = NULL; ctx->pts = AV_NOPTS_VALUE; + ctx->last_pgno = -1; + ctx->last_ass_alignment = 2; if (ctx->opacity == -1) ctx->opacity = ctx->transparent_bg ? 0 : 255; -#ifdef DEBUG - { - char *t; - ctx->ex = vbi_export_new("text", &t); - } -#endif av_log(avctx, AV_LOG_VERBOSE, "page filter: %s\n", ctx->pgno); - return (ctx->format_id == 1) ? ff_ass_subtitle_header_default(avctx) : 0; + + switch (ctx->format_id) { + case 0: + return 0; + case 1: + return ff_ass_subtitle_header_default(avctx); + case 2: + return my_ass_subtitle_header(avctx); + } + return AVERROR_BUG; } static int teletext_close_decoder(AVCodecContext *avctx) @@ -527,6 +775,9 @@ static int teletext_close_decoder(AVCodecContext *avctx) vbi_decoder_delete(ctx->vbi); ctx->vbi = NULL; ctx->pts = AV_NOPTS_VALUE; + ctx->last_pgno = -1; + ctx->last_ass_alignment = 2; + memset(ctx->subtitle_map, 0, sizeof(ctx->subtitle_map)); if (!(avctx->flags2 & AV_CODEC_FLAG2_RO_FLUSH_NOOP)) ctx->readorder = 0; return 0; @@ -540,15 +791,16 @@ static void teletext_flush(AVCodecContext *avctx) #define OFFSET(x) offsetof(TeletextContext, x) #define SD AV_OPT_FLAG_SUBTITLE_PARAM | AV_OPT_FLAG_DECODING_PARAM static const AVOption options[] = { - {"txt_page", "list of teletext page numbers to decode, * is all", OFFSET(pgno), AV_OPT_TYPE_STRING, {.str = "*"}, 0, 0, SD}, + {"txt_page", "page numbers to decode, subtitle for subtitles, * for all", OFFSET(pgno), AV_OPT_TYPE_STRING, {.str = "*"}, 0, 0, SD}, {"txt_chop_top", "discards the top teletext line", OFFSET(chop_top), AV_OPT_TYPE_INT, {.i64 = 1}, 0, 1, SD}, - {"txt_format", "format of the subtitles (bitmap or text)", OFFSET(format_id), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, SD, "txt_format"}, + {"txt_format", "format of the subtitles (bitmap or text or ass)", OFFSET(format_id), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 2, SD, "txt_format"}, {"bitmap", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 0}, 0, 0, SD, "txt_format"}, {"text", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 1}, 0, 0, SD, "txt_format"}, + {"ass", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 2}, 0, 0, SD, "txt_format"}, {"txt_left", "x offset of generated bitmaps", OFFSET(x_offset), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 65535, SD}, {"txt_top", "y offset of generated bitmaps", OFFSET(y_offset), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 65535, SD}, {"txt_chop_spaces", "chops leading and trailing spaces from text", OFFSET(chop_spaces), AV_OPT_TYPE_INT, {.i64 = 1}, 0, 1, SD}, - {"txt_duration", "display duration of teletext pages in msecs", OFFSET(sub_duration), AV_OPT_TYPE_INT, {.i64 = 30000}, 0, 86400000, SD}, + {"txt_duration", "display duration of teletext pages in msecs", OFFSET(sub_duration), AV_OPT_TYPE_INT, {.i64 = -1}, -1, 86400000, SD}, {"txt_transparent", "force transparent background of the teletext", OFFSET(transparent_bg), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, SD}, {"txt_opacity", "set opacity of the transparent background", OFFSET(opacity), AV_OPT_TYPE_INT, {.i64 = -1}, -1, 255, SD}, { NULL }, diff --git a/libavcodec/loco.c b/libavcodec/loco.c index 9d0f14445..d8bf68a10 100644 --- a/libavcodec/loco.c +++ b/libavcodec/loco.c @@ -88,6 +88,8 @@ static inline int loco_get_rice(RICEContext *r) loco_update_rice_param(r, 0); return 0; } + if (get_bits_left(&r->gb) < 1) + return INT_MIN; v = get_ur_golomb_jpegls(&r->gb, loco_get_rice_param(r), INT_MAX, 0); loco_update_rice_param(r, (v + 1) >> 1); if (!v) { @@ -114,19 +116,19 @@ static inline int loco_get_rice(RICEContext *r) } /* LOCO main predictor - LOCO-I/JPEG-LS predictor */ -static inline int loco_predict(uint8_t* data, int stride, int step) +static inline int loco_predict(uint8_t* data, int stride) { int a, b, c; a = data[-stride]; - b = data[-step]; - c = data[-stride - step]; + b = data[-1]; + c = data[-stride - 1]; return mid_pred(a, a + b - c, b); } static int loco_decode_plane(LOCOContext *l, uint8_t *data, int width, int height, - int stride, const uint8_t *buf, int buf_size, int step) + int stride, const uint8_t *buf, int buf_size) { RICEContext rc; int val; @@ -153,17 +155,21 @@ static int loco_decode_plane(LOCOContext *l, uint8_t *data, int width, int heigh /* restore top line */ for (i = 1; i < width; i++) { val = loco_get_rice(&rc); - data[i * step] = data[i * step - step] + val; + data[i] = data[i - 1] + val; } data += stride; for (j = 1; j < height; j++) { /* restore left column */ val = loco_get_rice(&rc); + if (val == INT_MIN) + return AVERROR_INVALIDDATA; data[0] = data[-stride] + val; /* restore all other pixels */ for (i = 1; i < width; i++) { val = loco_get_rice(&rc); - data[i * step] = loco_predict(&data[i * step], stride, step) + val; + if (val == INT_MIN) + return -1; + data[i] = loco_predict(&data[i], stride) + val; } data += stride; } @@ -171,19 +177,18 @@ static int loco_decode_plane(LOCOContext *l, uint8_t *data, int width, int heigh return (get_bits_count(&rc.gb) + 7) >> 3; } -static void rotate_faulty_loco(uint8_t *data, int width, int height, int stride, int step) +static void rotate_faulty_loco(uint8_t *data, int width, int height, int stride) { int y; for (y=1; y=y) { memmove(data + y*stride, - data + y*(stride + step), - step*(width-y)); + data + y*(stride + 1), + (width-y)); if (y+1 < height) - memmove(data + y*stride + step*(width-y), - data + (y+1)*stride, - step*y); + memmove(data + y*stride + (width-y), + data + (y+1)*stride, y); } } } @@ -209,49 +214,52 @@ static int decode_frame(AVCodecContext *avctx, switch(l->mode) { case LOCO_CYUY2: case LOCO_YUY2: case LOCO_UYVY: decoded = loco_decode_plane(l, p->data[0], avctx->width, avctx->height, - p->linesize[0], buf, buf_size, 1); + p->linesize[0], buf, buf_size); ADVANCE_BY_DECODED; decoded = loco_decode_plane(l, p->data[1], avctx->width / 2, avctx->height, - p->linesize[1], buf, buf_size, 1); + p->linesize[1], buf, buf_size); ADVANCE_BY_DECODED; decoded = loco_decode_plane(l, p->data[2], avctx->width / 2, avctx->height, - p->linesize[2], buf, buf_size, 1); + p->linesize[2], buf, buf_size); break; case LOCO_CYV12: case LOCO_YV12: decoded = loco_decode_plane(l, p->data[0], avctx->width, avctx->height, - p->linesize[0], buf, buf_size, 1); + p->linesize[0], buf, buf_size); ADVANCE_BY_DECODED; decoded = loco_decode_plane(l, p->data[2], avctx->width / 2, avctx->height / 2, - p->linesize[2], buf, buf_size, 1); + p->linesize[2], buf, buf_size); ADVANCE_BY_DECODED; decoded = loco_decode_plane(l, p->data[1], avctx->width / 2, avctx->height / 2, - p->linesize[1], buf, buf_size, 1); + p->linesize[1], buf, buf_size); break; case LOCO_CRGB: case LOCO_RGB: + decoded = loco_decode_plane(l, p->data[1] + p->linesize[1]*(avctx->height-1), avctx->width, avctx->height, + -p->linesize[1], buf, buf_size); + ADVANCE_BY_DECODED; decoded = loco_decode_plane(l, p->data[0] + p->linesize[0]*(avctx->height-1), avctx->width, avctx->height, - -p->linesize[0], buf, buf_size, 3); + -p->linesize[0], buf, buf_size); ADVANCE_BY_DECODED; - decoded = loco_decode_plane(l, p->data[0] + p->linesize[0]*(avctx->height-1) + 1, avctx->width, avctx->height, - -p->linesize[0], buf, buf_size, 3); - ADVANCE_BY_DECODED; - decoded = loco_decode_plane(l, p->data[0] + p->linesize[0]*(avctx->height-1) + 2, avctx->width, avctx->height, - -p->linesize[0], buf, buf_size, 3); - if (avctx->width & 1) - rotate_faulty_loco(p->data[0] + p->linesize[0]*(avctx->height-1), avctx->width, avctx->height, -p->linesize[0], 3); + decoded = loco_decode_plane(l, p->data[2] + p->linesize[2]*(avctx->height-1), avctx->width, avctx->height, + -p->linesize[2], buf, buf_size); + if (avctx->width & 1) { + rotate_faulty_loco(p->data[0] + p->linesize[0]*(avctx->height-1), avctx->width, avctx->height, -p->linesize[0]); + rotate_faulty_loco(p->data[1] + p->linesize[1]*(avctx->height-1), avctx->width, avctx->height, -p->linesize[1]); + rotate_faulty_loco(p->data[2] + p->linesize[2]*(avctx->height-1), avctx->width, avctx->height, -p->linesize[2]); + } break; case LOCO_CRGBA: case LOCO_RGBA: + decoded = loco_decode_plane(l, p->data[1] + p->linesize[1]*(avctx->height-1), avctx->width, avctx->height, + -p->linesize[1], buf, buf_size); + ADVANCE_BY_DECODED; decoded = loco_decode_plane(l, p->data[0] + p->linesize[0]*(avctx->height-1), avctx->width, avctx->height, - -p->linesize[0], buf, buf_size, 4); + -p->linesize[0], buf, buf_size); ADVANCE_BY_DECODED; - decoded = loco_decode_plane(l, p->data[0] + p->linesize[0]*(avctx->height-1) + 1, avctx->width, avctx->height, - -p->linesize[0], buf, buf_size, 4); + decoded = loco_decode_plane(l, p->data[2] + p->linesize[2]*(avctx->height-1), avctx->width, avctx->height, + -p->linesize[2], buf, buf_size); ADVANCE_BY_DECODED; - decoded = loco_decode_plane(l, p->data[0] + p->linesize[0]*(avctx->height-1) + 2, avctx->width, avctx->height, - -p->linesize[0], buf, buf_size, 4); - ADVANCE_BY_DECODED; - decoded = loco_decode_plane(l, p->data[0] + p->linesize[0]*(avctx->height-1) + 3, avctx->width, avctx->height, - -p->linesize[0], buf, buf_size, 4); + decoded = loco_decode_plane(l, p->data[3] + p->linesize[3]*(avctx->height-1), avctx->width, avctx->height, + -p->linesize[3], buf, buf_size); break; default: av_assert0(0); @@ -293,6 +301,11 @@ static av_cold int decode_init(AVCodecContext *avctx) avpriv_request_sample(avctx, "LOCO codec version %i", version); } + if (l->lossy > 65536U) { + av_log(avctx, AV_LOG_ERROR, "lossy %i is too large\n", l->lossy); + return AVERROR_INVALIDDATA; + } + l->mode = AV_RL32(avctx->extradata + 4); switch (l->mode) { case LOCO_CYUY2: @@ -302,7 +315,7 @@ static av_cold int decode_init(AVCodecContext *avctx) break; case LOCO_CRGB: case LOCO_RGB: - avctx->pix_fmt = AV_PIX_FMT_BGR24; + avctx->pix_fmt = AV_PIX_FMT_GBRP; break; case LOCO_CYV12: case LOCO_YV12: @@ -310,7 +323,7 @@ static av_cold int decode_init(AVCodecContext *avctx) break; case LOCO_CRGBA: case LOCO_RGBA: - avctx->pix_fmt = AV_PIX_FMT_BGRA; + avctx->pix_fmt = AV_PIX_FMT_GBRAP; break; default: av_log(avctx, AV_LOG_INFO, "Unknown colorspace, index = %i\n", l->mode); diff --git a/libavcodec/lzw.c b/libavcodec/lzw.c index b0b9a3435..e26e4829e 100644 --- a/libavcodec/lzw.c +++ b/libavcodec/lzw.c @@ -71,6 +71,9 @@ static int lzw_get_code(struct LZWState * s) { int c; + if (s->bbits < s->cursize && bytestream2_get_bytes_left(&s->gb) <= 0) + return s->end_code; + if(s->mode == FF_LZW_GIF) { while (s->bbits < s->cursize) { if (!s->bs) { diff --git a/libavcodec/m101.c b/libavcodec/m101.c index d2549668f..70f1da4f4 100644 --- a/libavcodec/m101.c +++ b/libavcodec/m101.c @@ -61,7 +61,7 @@ static int m101_decode_frame(AVCodecContext *avctx, void *data, int *got_frame, stride = AV_RL32(avctx->extradata + 5*4); if (avctx->pix_fmt == AV_PIX_FMT_YUV422P10) - min_stride = (avctx->width + 15) / 16 * 20; + min_stride = (avctx->width + 15) / 16 * 40; if (stride < min_stride || avpkt->size < stride * (uint64_t)avctx->height) { av_log(avctx, AV_LOG_ERROR, "stride (%d) is invalid for packet sized %d\n", diff --git a/libavcodec/magicyuv.c b/libavcodec/magicyuv.c index 1a129c261..f4fb2a780 100644 --- a/libavcodec/magicyuv.c +++ b/libavcodec/magicyuv.c @@ -592,6 +592,13 @@ static int magy_decode_frame(AVCodecContext *avctx, void *data, s->magy_decode_slice = magy_decode_slice10; s->bps = 10; break; + case 0x76: + avctx->pix_fmt = AV_PIX_FMT_YUV444P10; + s->max = 1024; + s->huff_build = huff_build10; + s->magy_decode_slice = magy_decode_slice10; + s->bps = 10; + break; case 0x6d: avctx->pix_fmt = AV_PIX_FMT_GBRP10; s->decorrelate = 1; diff --git a/libavcodec/magicyuvenc.c b/libavcodec/magicyuvenc.c index bbfb8d0c6..16e9a1c28 100644 --- a/libavcodec/magicyuvenc.c +++ b/libavcodec/magicyuvenc.c @@ -57,7 +57,6 @@ typedef struct MagicYUVContext { int planes; uint8_t format; AVFrame *p; - int max; int slice_height; int nb_slices; int correlate; @@ -148,6 +147,7 @@ static void median_predict(MagicYUVContext *s, static av_cold int magy_encode_init(AVCodecContext *avctx) { MagicYUVContext *s = avctx->priv_data; + PutByteContext pb; int i; switch (avctx->pix_fmt) { @@ -214,6 +214,34 @@ static av_cold int magy_encode_init(AVCodecContext *avctx) case MEDIAN: s->predict = median_predict; break; } + avctx->extradata_size = 32; + + avctx->extradata = av_mallocz(avctx->extradata_size + + AV_INPUT_BUFFER_PADDING_SIZE); + + if (!avctx->extradata) { + av_log(avctx, AV_LOG_ERROR, "Could not allocate extradata.\n"); + return AVERROR(ENOMEM); + } + + bytestream2_init_writer(&pb, avctx->extradata, avctx->extradata_size); + bytestream2_put_le32(&pb, MKTAG('M', 'A', 'G', 'Y')); + bytestream2_put_le32(&pb, 32); + bytestream2_put_byte(&pb, 7); + bytestream2_put_byte(&pb, s->format); + bytestream2_put_byte(&pb, 12); + bytestream2_put_byte(&pb, 0); + + bytestream2_put_byte(&pb, 0); + bytestream2_put_byte(&pb, 0); + bytestream2_put_byte(&pb, 32); + bytestream2_put_byte(&pb, 0); + + bytestream2_put_le32(&pb, avctx->width); + bytestream2_put_le32(&pb, avctx->height); + bytestream2_put_le32(&pb, avctx->width); + bytestream2_put_le32(&pb, avctx->height); + return 0; } @@ -347,7 +375,7 @@ static int encode_table(AVCodecContext *avctx, uint8_t *dst, counts[i].value = 255 - i; } - magy_huffman_compute_bits(counts, he, 256, 16); + magy_huffman_compute_bits(counts, he, 256, 12); calculate_codes(he); @@ -407,12 +435,16 @@ static int magy_encode_frame(AVCodecContext *avctx, AVPacket *pkt, bytestream2_init_writer(&pb, pkt->data, pkt->size); bytestream2_put_le32(&pb, MKTAG('M', 'A', 'G', 'Y')); - bytestream2_put_le32(&pb, 32); - bytestream2_put_byte(&pb, 7); + bytestream2_put_le32(&pb, 32); // header size + bytestream2_put_byte(&pb, 7); // version bytestream2_put_byte(&pb, s->format); + bytestream2_put_byte(&pb, 12); // max huffman length + bytestream2_put_byte(&pb, 0); + bytestream2_put_byte(&pb, 0); bytestream2_put_byte(&pb, 0); - bytestream2_put_le32(&pb, 0); + bytestream2_put_byte(&pb, 32); // coder type + bytestream2_put_byte(&pb, 0); bytestream2_put_le32(&pb, avctx->width); bytestream2_put_le32(&pb, avctx->height); @@ -549,7 +581,7 @@ AVCodec ff_magicyuv_encoder = { .init = magy_encode_init, .close = magy_encode_close, .encode2 = magy_encode_frame, - .capabilities = AV_CODEC_CAP_FRAME_THREADS | AV_CODEC_CAP_INTRA_ONLY | AV_CODEC_CAP_EXPERIMENTAL, + .capabilities = AV_CODEC_CAP_FRAME_THREADS | AV_CODEC_CAP_INTRA_ONLY, .pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRAP, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUVA444P, AV_PIX_FMT_GRAY8, diff --git a/libavcodec/mediacodec.c b/libavcodec/mediacodec.c index b0aae43a8..aa14624fd 100644 --- a/libavcodec/mediacodec.c +++ b/libavcodec/mediacodec.c @@ -102,6 +102,22 @@ int av_mediacodec_release_buffer(AVMediaCodecBuffer *buffer, int render) return 0; } +int av_mediacodec_render_buffer_at_time(AVMediaCodecBuffer *buffer, int64_t time) +{ + MediaCodecDecContext *ctx = buffer->ctx; + int released = atomic_fetch_add(&buffer->released, 1); + + if (!released && (ctx->delay_flush || buffer->serial == atomic_load(&ctx->serial))) { + atomic_fetch_sub(&ctx->hw_buffer_count, 1); + av_log(ctx->avctx, AV_LOG_DEBUG, + "Rendering output buffer %zd (%p) ts=%"PRId64" with time=%"PRId64" [%d pending]\n", + buffer->index, buffer, buffer->pts, time, atomic_load(&ctx->hw_buffer_count)); + return ff_AMediaCodec_releaseOutputBufferAtTime(ctx->codec, buffer->index, time); + } + + return 0; +} + #else #include @@ -125,4 +141,9 @@ int av_mediacodec_release_buffer(AVMediaCodecBuffer *buffer, int render) return AVERROR(ENOSYS); } +int av_mediacodec_render_buffer_at_time(AVMediaCodecBuffer *buffer, int64_t time) +{ + return AVERROR(ENOSYS); +} + #endif diff --git a/libavcodec/mediacodec.h b/libavcodec/mediacodec.h index 5606d24a1..4c8545df0 100644 --- a/libavcodec/mediacodec.h +++ b/libavcodec/mediacodec.h @@ -85,4 +85,17 @@ typedef struct MediaCodecBuffer AVMediaCodecBuffer; */ int av_mediacodec_release_buffer(AVMediaCodecBuffer *buffer, int render); +/** + * Release a MediaCodec buffer and render it at the given time to the surface + * that is associated with the decoder. The timestamp must be within one second + * of the current java/lang/System#nanoTime() (which is implemented using + * CLOCK_MONOTONIC on Android). See the Android MediaCodec documentation + * of android/media/MediaCodec#releaseOutputBuffer(int,long) for more details. + * + * @param buffer the buffer to render + * @param time timestamp in nanoseconds of when to render the buffer + * @return 0 on success, < 0 otherwise + */ +int av_mediacodec_render_buffer_at_time(AVMediaCodecBuffer *buffer, int64_t time); + #endif /* AVCODEC_MEDIACODEC_H */ diff --git a/libavcodec/mediacodec_wrapper.c b/libavcodec/mediacodec_wrapper.c index c47c2c9a4..5213cf640 100644 --- a/libavcodec/mediacodec_wrapper.c +++ b/libavcodec/mediacodec_wrapper.c @@ -392,8 +392,6 @@ char *ff_AMediaCodecList_getCodecNameByType(const char *mime, int profile, int e struct JNIAMediaCodecListFields jfields = { 0 }; struct JNIAMediaFormatFields mediaformat_jfields = { 0 }; - jobject format = NULL; - jobject codec = NULL; jobject codec_name = NULL; jobject info = NULL; @@ -469,6 +467,11 @@ char *ff_AMediaCodecList_getCodecNameByType(const char *mime, int profile, int e goto done; } + if (codec_name) { + (*env)->DeleteLocalRef(env, codec_name); + codec_name = NULL; + } + /* Skip software decoders */ if ( strstr(name, "OMX.google") || @@ -566,14 +569,6 @@ done_with_info: } done: - if (format) { - (*env)->DeleteLocalRef(env, format); - } - - if (codec) { - (*env)->DeleteLocalRef(env, codec); - } - if (codec_name) { (*env)->DeleteLocalRef(env, codec_name); } @@ -1337,6 +1332,10 @@ char *ff_AMediaCodec_getName(FFAMediaCodec *codec) ret = ff_jni_jstring_to_utf_chars(env, name, codec); fail: + if (name) { + (*env)->DeleteLocalRef(env, name); + } + return ret; } @@ -1432,7 +1431,7 @@ int ff_AMediaCodec_releaseOutputBufferAtTime(FFAMediaCodec *codec, size_t idx, i JNI_GET_ENV_OR_RETURN(env, codec, AVERROR_EXTERNAL); - (*env)->CallVoidMethod(env, codec->object, codec->jfields.release_output_buffer_at_time_id, (jint)idx, timestampNs); + (*env)->CallVoidMethod(env, codec->object, codec->jfields.release_output_buffer_at_time_id, (jint)idx, (jlong)timestampNs); if (ff_jni_exception_check(env, 1, codec) < 0) { ret = AVERROR_EXTERNAL; goto fail; diff --git a/libavcodec/mediacodec_wrapper.h b/libavcodec/mediacodec_wrapper.h index f0de16d66..b106ff315 100644 --- a/libavcodec/mediacodec_wrapper.h +++ b/libavcodec/mediacodec_wrapper.h @@ -26,6 +26,8 @@ #include #include +#include "avcodec.h" + /** * The following API around MediaCodec and MediaFormat is based on the * NDK one provided by Google since Android 5.0. diff --git a/libavcodec/mediacodecdec.c b/libavcodec/mediacodecdec.c index 3a4240aa9..e353e34bd 100644 --- a/libavcodec/mediacodecdec.c +++ b/libavcodec/mediacodecdec.c @@ -461,6 +461,7 @@ static int mediacodec_receive_frame(AVCodecContext *avctx, AVFrame *frame) ret = ff_mediacodec_dec_send(avctx, s->ctx, &null_pkt, true); if (ret < 0) return ret; + return ff_mediacodec_dec_receive(avctx, s->ctx, frame, true); } else if (ret == AVERROR(EAGAIN) && s->ctx->current_input_buffer < 0) { return ff_mediacodec_dec_receive(avctx, s->ctx, frame, true); } else if (ret < 0) { diff --git a/libavcodec/mediacodecdec_common.c b/libavcodec/mediacodecdec_common.c index f235dae71..1656cd666 100644 --- a/libavcodec/mediacodecdec_common.c +++ b/libavcodec/mediacodecdec_common.c @@ -312,7 +312,7 @@ FF_ENABLE_DEPRECATION_WARNINGS av_log(avctx, AV_LOG_TRACE, "Frame: width=%d stride=%d height=%d slice-height=%d " - "crop-top=%d crop-bottom=%d crop-left=%d crop-right=%d encoder=%s\n" + "crop-top=%d crop-bottom=%d crop-left=%d crop-right=%d encoder=%s " "destination linesizes=%d,%d,%d\n" , avctx->width, s->stride, avctx->height, s->slice_height, s->crop_top, s->crop_bottom, s->crop_left, s->crop_right, s->codec_name, @@ -631,21 +631,21 @@ int ff_mediacodec_dec_send(AVCodecContext *avctx, MediaCodecDecContext *s, "Queued input buffer %zd size=%zd ts=%"PRIi64"\n", index, size, pts); s->draining = 1; - break; - } else { - size = FFMIN(pkt->size - offset, size); - memcpy(data, pkt->data + offset, size); - offset += size; - - status = ff_AMediaCodec_queueInputBuffer(codec, index, 0, size, pts, 0); - if (status < 0) { - av_log(avctx, AV_LOG_ERROR, "Failed to queue input buffer (status = %d)\n", status); - return AVERROR_EXTERNAL; - } - - av_log(avctx, AV_LOG_TRACE, - "Queued input buffer %zd size=%zd ts=%"PRIi64"\n", index, size, pts); + return 0; } + + size = FFMIN(pkt->size - offset, size); + memcpy(data, pkt->data + offset, size); + offset += size; + + status = ff_AMediaCodec_queueInputBuffer(codec, index, 0, size, pts, 0); + if (status < 0) { + av_log(avctx, AV_LOG_ERROR, "Failed to queue input buffer (status = %d)\n", status); + return AVERROR_EXTERNAL; + } + + av_log(avctx, AV_LOG_TRACE, + "Queued input buffer %zd size=%zd ts=%"PRIi64"\n", index, size, pts); } if (offset == 0) diff --git a/libavcodec/microdvddec.c b/libavcodec/microdvddec.c index 4a3426779..dad0ec8a2 100644 --- a/libavcodec/microdvddec.c +++ b/libavcodec/microdvddec.c @@ -99,7 +99,7 @@ static char *microdvd_load_tags(struct microdvd_tag *tags, char *s) case 'Y': tag.persistent = MICRODVD_PERSISTENT_ON; case 'y': - while (*s && *s != '}') { + while (*s && *s != '}' && s - start < 256) { int style_index = indexof(MICRODVD_STYLES, *s); if (style_index >= 0) diff --git a/libavcodec/mips/Makefile b/libavcodec/mips/Makefile index 1f659a003..c5b54d55c 100644 --- a/libavcodec/mips/Makefile +++ b/libavcodec/mips/Makefile @@ -22,6 +22,7 @@ OBJS-$(CONFIG_HEVC_DECODER) += mips/hevcdsp_init_mips.o \ mips/hevcpred_init_mips.o OBJS-$(CONFIG_VP9_DECODER) += mips/vp9dsp_init_mips.o OBJS-$(CONFIG_VP8_DECODER) += mips/vp8dsp_init_mips.o +OBJS-$(CONFIG_VP3DSP) += mips/vp3dsp_init_mips.o OBJS-$(CONFIG_H264DSP) += mips/h264dsp_init_mips.o OBJS-$(CONFIG_H264QPEL) += mips/h264qpel_init_mips.o OBJS-$(CONFIG_H264CHROMA) += mips/h264chroma_init_mips.o @@ -54,6 +55,7 @@ MSA-OBJS-$(CONFIG_VP9_DECODER) += mips/vp9_mc_msa.o \ MSA-OBJS-$(CONFIG_VP8_DECODER) += mips/vp8_mc_msa.o \ mips/vp8_idct_msa.o \ mips/vp8_lpf_msa.o +MSA-OBJS-$(CONFIG_VP3DSP) += mips/vp3dsp_idct_msa.o MSA-OBJS-$(CONFIG_H264DSP) += mips/h264dsp_msa.o \ mips/h264idct_msa.o MSA-OBJS-$(CONFIG_H264QPEL) += mips/h264qpel_msa.o @@ -84,3 +86,6 @@ MMI-OBJS-$(CONFIG_VP8_DECODER) += mips/vp8dsp_mmi.o MMI-OBJS-$(CONFIG_HPELDSP) += mips/hpeldsp_mmi.o MMI-OBJS-$(CONFIG_VC1_DECODER) += mips/vc1dsp_mmi.o MMI-OBJS-$(CONFIG_WMV2DSP) += mips/wmv2dsp_mmi.o +MMI-OBJS-$(CONFIG_HEVC_DECODER) += mips/hevcdsp_mmi.o +MMI-OBJS-$(CONFIG_VP3DSP) += mips/vp3dsp_idct_mmi.o +MMI-OBJS-$(CONFIG_VP9_DECODER) += mips/vp9_mc_mmi.o diff --git a/libavcodec/mips/blockdsp_init_mips.c b/libavcodec/mips/blockdsp_init_mips.c index 30ae95fa1..55ac1c3e9 100644 --- a/libavcodec/mips/blockdsp_init_mips.c +++ b/libavcodec/mips/blockdsp_init_mips.c @@ -45,10 +45,10 @@ static av_cold void blockdsp_init_mmi(BlockDSPContext *c) void ff_blockdsp_init_mips(BlockDSPContext *c) { -#if HAVE_MSA - blockdsp_init_msa(c); -#endif // #if HAVE_MSA #if HAVE_MMI blockdsp_init_mmi(c); #endif /* HAVE_MMI */ +#if HAVE_MSA + blockdsp_init_msa(c); +#endif // #if HAVE_MSA } diff --git a/libavcodec/mips/cabac.h b/libavcodec/mips/cabac.h new file mode 100644 index 000000000..2a05e5ab3 --- /dev/null +++ b/libavcodec/mips/cabac.h @@ -0,0 +1,119 @@ +/* + * Loongson SIMD optimized h264chroma + * + * Copyright (c) 2018 Loongson Technology Corporation Limited + * Copyright (c) 2018 Shiyou Yin + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * 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_MIPS_CABAC_H +#define AVCODEC_MIPS_CABAC_H + +#include "libavcodec/cabac.h" +#include "libavutil/mips/mmiutils.h" +#include "config.h" + +#define get_cabac_inline get_cabac_inline_mips +static av_always_inline int get_cabac_inline(CABACContext *c, + uint8_t * const state){ + mips_reg tmp0, tmp1, tmp2, bit; + + __asm__ volatile ( + "lbu %[bit], 0(%[state]) \n\t" + "and %[tmp0], %[c_range], 0xC0 \n\t" + PTR_ADDU "%[tmp0], %[tmp0], %[tmp0] \n\t" + PTR_ADDU "%[tmp0], %[tmp0], %[tables] \n\t" + PTR_ADDU "%[tmp0], %[tmp0], %[bit] \n\t" + /* tmp1: RangeLPS */ + "lbu %[tmp1], %[lps_off](%[tmp0]) \n\t" + + PTR_SUBU "%[c_range], %[c_range], %[tmp1] \n\t" + PTR_SLL "%[tmp0], %[c_range], 0x11 \n\t" + PTR_SUBU "%[tmp0], %[tmp0], %[c_low] \n\t" + + /* tmp2: lps_mask */ + PTR_SRA "%[tmp2], %[tmp0], 0x1F \n\t" + /* If tmp0 < 0, lps_mask == 0xffffffff*/ + /* If tmp0 >= 0, lps_mask == 0x00000000*/ + "beqz %[tmp2], 1f \n\t" + PTR_SLL "%[tmp0], %[c_range], 0x11 \n\t" + PTR_SUBU "%[c_low], %[c_low], %[tmp0] \n\t" + PTR_SUBU "%[tmp0], %[tmp1], %[c_range] \n\t" + PTR_ADDU "%[c_range], %[c_range], %[tmp0] \n\t" + "xor %[bit], %[bit], %[tmp2] \n\t" + + "1: \n\t" + /* tmp1: *state */ + PTR_ADDU "%[tmp0], %[tables], %[bit] \n\t" + "lbu %[tmp1], %[mlps_off](%[tmp0]) \n\t" + /* tmp2: lps_mask */ + PTR_ADDU "%[tmp0], %[tables], %[c_range] \n\t" + "lbu %[tmp2], %[norm_off](%[tmp0]) \n\t" + + "sb %[tmp1], 0(%[state]) \n\t" + "and %[bit], %[bit], 0x01 \n\t" + PTR_SLL "%[c_range], %[c_range], %[tmp2] \n\t" + PTR_SLL "%[c_low], %[c_low], %[tmp2] \n\t" + + "and %[tmp0], %[c_low], %[cabac_mask] \n\t" + "bnez %[tmp0], 1f \n\t" + PTR_ADDIU "%[tmp0], %[c_low], -0x01 \n\t" + "xor %[tmp0], %[c_low], %[tmp0] \n\t" + PTR_SRA "%[tmp0], %[tmp0], 0x0f \n\t" + PTR_ADDU "%[tmp0], %[tmp0], %[tables] \n\t" + "lbu %[tmp2], %[norm_off](%[tmp0]) \n\t" +#if CABAC_BITS == 16 + "lbu %[tmp0], 0(%[c_bytestream]) \n\t" + "lbu %[tmp1], 1(%[c_bytestream]) \n\t" + PTR_SLL "%[tmp0], %[tmp0], 0x09 \n\t" + PTR_SLL "%[tmp1], %[tmp1], 0x01 \n\t" + PTR_ADDU "%[tmp0], %[tmp0], %[tmp1] \n\t" +#else + "lbu %[tmp0], 0(%[c_bytestream]) \n\t" + PTR_SLL "%[tmp0], %[tmp0], 0x01 \n\t" +#endif + PTR_SUBU "%[tmp0], %[tmp0], %[cabac_mask] \n\t" + + "li %[tmp1], 0x07 \n\t" + PTR_SUBU "%[tmp1], %[tmp1], %[tmp2] \n\t" + PTR_SLL "%[tmp0], %[tmp0], %[tmp1] \n\t" + PTR_ADDU "%[c_low], %[c_low], %[tmp0] \n\t" + +#if !UNCHECKED_BITSTREAM_READER + "bge %[c_bytestream], %[c_bytestream_end], 1f \n\t" +#endif + PTR_ADDIU "%[c_bytestream], %[c_bytestream], 0X02 \n\t" + "1: \n\t" + : [bit]"=&r"(bit), [tmp0]"=&r"(tmp0), [tmp1]"=&r"(tmp1), [tmp2]"=&r"(tmp2), + [c_range]"+&r"(c->range), [c_low]"+&r"(c->low), + [c_bytestream]"+&r"(c->bytestream) + : [state]"r"(state), [tables]"r"(ff_h264_cabac_tables), +#if !UNCHECKED_BITSTREAM_READER + [c_bytestream_end]"r"(c->bytestream_end), +#endif + [lps_off]"i"(H264_LPS_RANGE_OFFSET), + [mlps_off]"i"(H264_MLPS_STATE_OFFSET + 128), + [norm_off]"i"(H264_NORM_SHIFT_OFFSET), + [cabac_mask]"i"(CABAC_MASK) + : "memory" + ); + + return bit; +} + +#endif /* AVCODEC_MIPS_CABAC_H */ diff --git a/libavcodec/mips/h263dsp_msa.c b/libavcodec/mips/h263dsp_msa.c index 472bcbd70..2e1ca0183 100644 --- a/libavcodec/mips/h263dsp_msa.c +++ b/libavcodec/mips/h263dsp_msa.c @@ -86,10 +86,7 @@ static void h263_h_loop_filter_msa(uint8_t *src, int32_t stride, int32_t qscale) ILVR_B2_SH(in3, in0, in1, in2, temp0, temp1); in0 = (v16u8) __msa_ilvr_h(temp1, temp0); in3 = (v16u8) __msa_ilvl_h(temp1, temp0); - ST4x4_UB(in0, in0, 0, 1, 2, 3, src, stride); - src += 4 * stride; - ST4x4_UB(in3, in3, 0, 1, 2, 3, src, stride); - src += 4 * stride; + ST_W8(in0, in3, 0, 1, 2, 3, 0, 1, 2, 3, src, stride); } static void h263_v_loop_filter_msa(uint8_t *src, int32_t stride, int32_t qscale) diff --git a/libavcodec/mips/h264chroma_init_mips.c b/libavcodec/mips/h264chroma_init_mips.c index 122148dc7..ae817e47a 100644 --- a/libavcodec/mips/h264chroma_init_mips.c +++ b/libavcodec/mips/h264chroma_init_mips.c @@ -54,10 +54,10 @@ static av_cold void h264chroma_init_mmi(H264ChromaContext *c, int bit_depth) av_cold void ff_h264chroma_init_mips(H264ChromaContext *c, int bit_depth) { -#if HAVE_MSA - h264chroma_init_msa(c, bit_depth); -#endif // #if HAVE_MSA #if HAVE_MMI h264chroma_init_mmi(c, bit_depth); #endif /* HAVE_MMI */ +#if HAVE_MSA + h264chroma_init_msa(c, bit_depth); +#endif // #if HAVE_MSA } diff --git a/libavcodec/mips/h264chroma_mmi.c b/libavcodec/mips/h264chroma_mmi.c index bafe0f92a..739dd7d4d 100644 --- a/libavcodec/mips/h264chroma_mmi.c +++ b/libavcodec/mips/h264chroma_mmi.c @@ -29,75 +29,136 @@ void ff_put_h264_chroma_mc8_mmi(uint8_t *dst, uint8_t *src, ptrdiff_t stride, int h, int x, int y) { - const int A = (8 - x) * (8 - y); - const int B = x * (8 - y); - const int C = (8 - x) * y; - const int D = x * y; - const int E = B + C; - double ftmp[10]; + int A = 64, B, C, D, E; + double ftmp[12]; uint64_t tmp[1]; - mips_reg addr[1]; - DECLARE_VAR_ALL64; - if (D) { + if (!(x || y)) { + /* x=0, y=0, A=64 */ __asm__ volatile ( - "xor %[ftmp0], %[ftmp0], %[ftmp0] \n\t" - "dli %[tmp0], 0x06 \n\t" - "pshufh %[A], %[A], %[ftmp0] \n\t" - "pshufh %[B], %[B], %[ftmp0] \n\t" - "mtc1 %[tmp0], %[ftmp9] \n\t" - "pshufh %[C], %[C], %[ftmp0] \n\t" - "pshufh %[D], %[D], %[ftmp0] \n\t" + "1: \n\t" + MMI_ULDC1(%[ftmp0], %[src], 0x00) + PTR_ADDU "%[src], %[src], %[stride] \n\t" + MMI_ULDC1(%[ftmp1], %[src], 0x00) + PTR_ADDU "%[src], %[src], %[stride] \n\t" + MMI_ULDC1(%[ftmp2], %[src], 0x00) + PTR_ADDU "%[src], %[src], %[stride] \n\t" + MMI_ULDC1(%[ftmp3], %[src], 0x00) + PTR_ADDU "%[src], %[src], %[stride] \n\t" - "1: \n\t" - PTR_ADDU "%[addr0], %[src], %[stride] \n\t" + "addi %[h], %[h], -0x04 \n\t" + + MMI_SDC1(%[ftmp0], %[dst], 0x00) + PTR_ADDU "%[dst], %[dst], %[stride] \n\t" + MMI_SDC1(%[ftmp1], %[dst], 0x00) + PTR_ADDU "%[dst], %[dst], %[stride] \n\t" + MMI_SDC1(%[ftmp2], %[dst], 0x00) + PTR_ADDU "%[dst], %[dst], %[stride] \n\t" + MMI_SDC1(%[ftmp3], %[dst], 0x00) + PTR_ADDU "%[dst], %[dst], %[stride] \n\t" + "bnez %[h], 1b \n\t" + : [ftmp0]"=&f"(ftmp[0]), [ftmp1]"=&f"(ftmp[1]), + [ftmp2]"=&f"(ftmp[2]), [ftmp3]"=&f"(ftmp[3]), + [dst]"+&r"(dst), [src]"+&r"(src), + [h]"+&r"(h) + : [stride]"r"((mips_reg)stride) + : "memory" + ); + } else if (x && y) { + /* x!=0, y!=0 */ + D = x * y; + B = (x << 3) - D; + C = (y << 3) - D; + A = 64 - D - B - C; + + __asm__ volatile ( + "xor %[ftmp0], %[ftmp0], %[ftmp0] \n\t" + "dli %[tmp0], 0x06 \n\t" + "pshufh %[A], %[A], %[ftmp0] \n\t" + "pshufh %[B], %[B], %[ftmp0] \n\t" + "mtc1 %[tmp0], %[ftmp9] \n\t" + "pshufh %[C], %[C], %[ftmp0] \n\t" + "pshufh %[D], %[D], %[ftmp0] \n\t" + + "1: \n\t" MMI_ULDC1(%[ftmp1], %[src], 0x00) MMI_ULDC1(%[ftmp2], %[src], 0x01) - MMI_ULDC1(%[ftmp3], %[addr0], 0x00) - MMI_ULDC1(%[ftmp4], %[addr0], 0x01) + PTR_ADDU "%[src], %[src], %[stride] \n\t" + MMI_ULDC1(%[ftmp3], %[src], 0x00) + MMI_ULDC1(%[ftmp4], %[src], 0x01) + PTR_ADDU "%[src], %[src], %[stride] \n\t" + MMI_ULDC1(%[ftmp10], %[src], 0x00) + MMI_ULDC1(%[ftmp11], %[src], 0x01) + "addi %[h], %[h], -0x02 \n\t" - "punpcklbh %[ftmp5], %[ftmp1], %[ftmp0] \n\t" - "punpckhbh %[ftmp6], %[ftmp1], %[ftmp0] \n\t" - "punpcklbh %[ftmp7], %[ftmp2], %[ftmp0] \n\t" - "punpckhbh %[ftmp8], %[ftmp2], %[ftmp0] \n\t" - "pmullh %[ftmp5], %[ftmp5], %[A] \n\t" - "pmullh %[ftmp7], %[ftmp7], %[B] \n\t" - "paddh %[ftmp1], %[ftmp5], %[ftmp7] \n\t" - "pmullh %[ftmp6], %[ftmp6], %[A] \n\t" - "pmullh %[ftmp8], %[ftmp8], %[B] \n\t" - "paddh %[ftmp2], %[ftmp6], %[ftmp8] \n\t" + "punpcklbh %[ftmp5], %[ftmp1], %[ftmp0] \n\t" + "punpckhbh %[ftmp6], %[ftmp1], %[ftmp0] \n\t" + "punpcklbh %[ftmp7], %[ftmp2], %[ftmp0] \n\t" + "punpckhbh %[ftmp8], %[ftmp2], %[ftmp0] \n\t" + "pmullh %[ftmp5], %[ftmp5], %[A] \n\t" + "pmullh %[ftmp7], %[ftmp7], %[B] \n\t" + "paddh %[ftmp1], %[ftmp5], %[ftmp7] \n\t" + "pmullh %[ftmp6], %[ftmp6], %[A] \n\t" + "pmullh %[ftmp8], %[ftmp8], %[B] \n\t" + "paddh %[ftmp2], %[ftmp6], %[ftmp8] \n\t" + "punpcklbh %[ftmp5], %[ftmp3], %[ftmp0] \n\t" + "punpckhbh %[ftmp6], %[ftmp3], %[ftmp0] \n\t" + "punpcklbh %[ftmp7], %[ftmp4], %[ftmp0] \n\t" + "punpckhbh %[ftmp8], %[ftmp4], %[ftmp0] \n\t" + "pmullh %[ftmp5], %[ftmp5], %[C] \n\t" + "pmullh %[ftmp7], %[ftmp7], %[D] \n\t" + "paddh %[ftmp5], %[ftmp5], %[ftmp7] \n\t" + "pmullh %[ftmp6], %[ftmp6], %[C] \n\t" + "pmullh %[ftmp8], %[ftmp8], %[D] \n\t" + "paddh %[ftmp6], %[ftmp6], %[ftmp8] \n\t" + "paddh %[ftmp1], %[ftmp1], %[ftmp5] \n\t" + "paddh %[ftmp2], %[ftmp2], %[ftmp6] \n\t" + "paddh %[ftmp1], %[ftmp1], %[ff_pw_32] \n\t" + "paddh %[ftmp2], %[ftmp2], %[ff_pw_32] \n\t" + "psrlh %[ftmp1], %[ftmp1], %[ftmp9] \n\t" + "psrlh %[ftmp2], %[ftmp2], %[ftmp9] \n\t" + "packushb %[ftmp1], %[ftmp1], %[ftmp2] \n\t" - "punpcklbh %[ftmp5], %[ftmp3], %[ftmp0] \n\t" - "punpckhbh %[ftmp6], %[ftmp3], %[ftmp0] \n\t" - "punpcklbh %[ftmp7], %[ftmp4], %[ftmp0] \n\t" - "punpckhbh %[ftmp8], %[ftmp4], %[ftmp0] \n\t" - "pmullh %[ftmp5], %[ftmp5], %[C] \n\t" - "pmullh %[ftmp7], %[ftmp7], %[D] \n\t" - "paddh %[ftmp3], %[ftmp5], %[ftmp7] \n\t" - "pmullh %[ftmp6], %[ftmp6], %[C] \n\t" - "pmullh %[ftmp8], %[ftmp8], %[D] \n\t" - "paddh %[ftmp4], %[ftmp6], %[ftmp8] \n\t" + "punpcklbh %[ftmp5], %[ftmp3], %[ftmp0] \n\t" + "punpckhbh %[ftmp6], %[ftmp3], %[ftmp0] \n\t" + "punpcklbh %[ftmp7], %[ftmp4], %[ftmp0] \n\t" + "punpckhbh %[ftmp8], %[ftmp4], %[ftmp0] \n\t" + "pmullh %[ftmp5], %[ftmp5], %[A] \n\t" + "pmullh %[ftmp7], %[ftmp7], %[B] \n\t" + "paddh %[ftmp3], %[ftmp5], %[ftmp7] \n\t" + "pmullh %[ftmp6], %[ftmp6], %[A] \n\t" + "pmullh %[ftmp8], %[ftmp8], %[B] \n\t" + "paddh %[ftmp4], %[ftmp6], %[ftmp8] \n\t" + "punpcklbh %[ftmp5], %[ftmp10], %[ftmp0] \n\t" + "punpckhbh %[ftmp6], %[ftmp10], %[ftmp0] \n\t" + "punpcklbh %[ftmp7], %[ftmp11], %[ftmp0] \n\t" + "punpckhbh %[ftmp8], %[ftmp11], %[ftmp0] \n\t" + "pmullh %[ftmp5], %[ftmp5], %[C] \n\t" + "pmullh %[ftmp7], %[ftmp7], %[D] \n\t" + "paddh %[ftmp5], %[ftmp5], %[ftmp7] \n\t" + "pmullh %[ftmp6], %[ftmp6], %[C] \n\t" + "pmullh %[ftmp8], %[ftmp8], %[D] \n\t" + "paddh %[ftmp6], %[ftmp6], %[ftmp8] \n\t" + "paddh %[ftmp3], %[ftmp3], %[ftmp5] \n\t" + "paddh %[ftmp4], %[ftmp4], %[ftmp6] \n\t" + "paddh %[ftmp3], %[ftmp3], %[ff_pw_32] \n\t" + "paddh %[ftmp4], %[ftmp4], %[ff_pw_32] \n\t" + "psrlh %[ftmp3], %[ftmp3], %[ftmp9] \n\t" + "psrlh %[ftmp4], %[ftmp4], %[ftmp9] \n\t" + "packushb %[ftmp3], %[ftmp3], %[ftmp4] \n\t" - "paddh %[ftmp1], %[ftmp1], %[ftmp3] \n\t" - "paddh %[ftmp2], %[ftmp2], %[ftmp4] \n\t" - "paddh %[ftmp1], %[ftmp1], %[ff_pw_32] \n\t" - "paddh %[ftmp2], %[ftmp2], %[ff_pw_32] \n\t" - "psrlh %[ftmp1], %[ftmp1], %[ftmp9] \n\t" - "psrlh %[ftmp2], %[ftmp2], %[ftmp9] \n\t" - "packushb %[ftmp1], %[ftmp1], %[ftmp2] \n\t" - "addi %[h], %[h], -0x01 \n\t" MMI_SDC1(%[ftmp1], %[dst], 0x00) - PTR_ADDU "%[src], %[src], %[stride] \n\t" - PTR_ADDU "%[dst], %[dst], %[stride] \n\t" - "bnez %[h], 1b \n\t" + PTR_ADDU "%[dst], %[dst], %[stride] \n\t" + MMI_SDC1(%[ftmp3], %[dst], 0x00) + PTR_ADDU "%[dst], %[dst], %[stride] \n\t" + "bnez %[h], 1b \n\t" : [ftmp0]"=&f"(ftmp[0]), [ftmp1]"=&f"(ftmp[1]), [ftmp2]"=&f"(ftmp[2]), [ftmp3]"=&f"(ftmp[3]), [ftmp4]"=&f"(ftmp[4]), [ftmp5]"=&f"(ftmp[5]), [ftmp6]"=&f"(ftmp[6]), [ftmp7]"=&f"(ftmp[7]), [ftmp8]"=&f"(ftmp[8]), [ftmp9]"=&f"(ftmp[9]), + [ftmp10]"=&f"(ftmp[10]), [ftmp11]"=&f"(ftmp[11]), [tmp0]"=&r"(tmp[0]), - RESTRICT_ASM_ALL64 - [addr0]"=&r"(addr[0]), [dst]"+&r"(dst), [src]"+&r"(src), [h]"+&r"(h) : [stride]"r"((mips_reg)stride),[ff_pw_32]"f"(ff_pw_32), @@ -105,103 +166,122 @@ void ff_put_h264_chroma_mc8_mmi(uint8_t *dst, uint8_t *src, ptrdiff_t stride, [C]"f"(C), [D]"f"(D) : "memory" ); - } else if (E) { - const int step = C ? stride : 1; + } else if (x) { + /* x!=0, y==0 */ + E = x << 3; + A = 64 - E; __asm__ volatile ( - "xor %[ftmp0], %[ftmp0], %[ftmp0] \n\t" - "dli %[tmp0], 0x06 \n\t" - "pshufh %[A], %[A], %[ftmp0] \n\t" - "pshufh %[E], %[E], %[ftmp0] \n\t" - "mtc1 %[tmp0], %[ftmp7] \n\t" + "xor %[ftmp0], %[ftmp0], %[ftmp0] \n\t" + "dli %[tmp0], 0x06 \n\t" + "pshufh %[A], %[A], %[ftmp0] \n\t" + "pshufh %[E], %[E], %[ftmp0] \n\t" + "mtc1 %[tmp0], %[ftmp7] \n\t" - "1: \n\t" - PTR_ADDU "%[addr0], %[src], %[step] \n\t" + "1: \n\t" MMI_ULDC1(%[ftmp1], %[src], 0x00) - MMI_ULDC1(%[ftmp2], %[addr0], 0x00) + MMI_ULDC1(%[ftmp2], %[src], 0x01) + "addi %[h], %[h], -0x01 \n\t" + PTR_ADDU "%[src], %[src], %[stride] \n\t" - "punpcklbh %[ftmp3], %[ftmp1], %[ftmp0] \n\t" - "punpckhbh %[ftmp4], %[ftmp1], %[ftmp0] \n\t" - "punpcklbh %[ftmp5], %[ftmp2], %[ftmp0] \n\t" - "punpckhbh %[ftmp6], %[ftmp2], %[ftmp0] \n\t" - "pmullh %[ftmp3], %[ftmp3], %[A] \n\t" - "pmullh %[ftmp5], %[ftmp5], %[E] \n\t" - "paddh %[ftmp1], %[ftmp3], %[ftmp5] \n\t" - "pmullh %[ftmp4], %[ftmp4], %[A] \n\t" - "pmullh %[ftmp6], %[ftmp6], %[E] \n\t" - "paddh %[ftmp2], %[ftmp4], %[ftmp6] \n\t" + "punpcklbh %[ftmp3], %[ftmp1], %[ftmp0] \n\t" + "punpckhbh %[ftmp4], %[ftmp1], %[ftmp0] \n\t" + "punpcklbh %[ftmp5], %[ftmp2], %[ftmp0] \n\t" + "punpckhbh %[ftmp6], %[ftmp2], %[ftmp0] \n\t" + "pmullh %[ftmp3], %[ftmp3], %[A] \n\t" + "pmullh %[ftmp5], %[ftmp5], %[E] \n\t" + "paddh %[ftmp1], %[ftmp3], %[ftmp5] \n\t" + "pmullh %[ftmp4], %[ftmp4], %[A] \n\t" + "pmullh %[ftmp6], %[ftmp6], %[E] \n\t" + "paddh %[ftmp2], %[ftmp4], %[ftmp6] \n\t" - "paddh %[ftmp1], %[ftmp1], %[ff_pw_32] \n\t" - "paddh %[ftmp2], %[ftmp2], %[ff_pw_32] \n\t" - "psrlh %[ftmp1], %[ftmp1], %[ftmp7] \n\t" - "psrlh %[ftmp2], %[ftmp2], %[ftmp7] \n\t" - "packushb %[ftmp1], %[ftmp1], %[ftmp2] \n\t" - "addi %[h], %[h], -0x01 \n\t" + "paddh %[ftmp1], %[ftmp1], %[ff_pw_32] \n\t" + "paddh %[ftmp2], %[ftmp2], %[ff_pw_32] \n\t" + "psrlh %[ftmp1], %[ftmp1], %[ftmp7] \n\t" + "psrlh %[ftmp2], %[ftmp2], %[ftmp7] \n\t" + "packushb %[ftmp1], %[ftmp1], %[ftmp2] \n\t" MMI_SDC1(%[ftmp1], %[dst], 0x00) - PTR_ADDU "%[src], %[src], %[stride] \n\t" - PTR_ADDU "%[dst], %[dst], %[stride] \n\t" - "bnez %[h], 1b \n\t" + PTR_ADDU "%[dst], %[dst], %[stride] \n\t" + "bnez %[h], 1b \n\t" : [ftmp0]"=&f"(ftmp[0]), [ftmp1]"=&f"(ftmp[1]), [ftmp2]"=&f"(ftmp[2]), [ftmp3]"=&f"(ftmp[3]), [ftmp4]"=&f"(ftmp[4]), [ftmp5]"=&f"(ftmp[5]), [ftmp6]"=&f"(ftmp[6]), [ftmp7]"=&f"(ftmp[7]), [tmp0]"=&r"(tmp[0]), - RESTRICT_ASM_ALL64 - [addr0]"=&r"(addr[0]), [dst]"+&r"(dst), [src]"+&r"(src), [h]"+&r"(h) - : [stride]"r"((mips_reg)stride),[step]"r"((mips_reg)step), + : [stride]"r"((mips_reg)stride), [ff_pw_32]"f"(ff_pw_32), [A]"f"(A), [E]"f"(E) : "memory" ); } else { + /* x==0, y!=0 */ + E = y << 3; + A = 64 - E; + __asm__ volatile ( - "xor %[ftmp0], %[ftmp0], %[ftmp0] \n\t" - "dli %[tmp0], 0x06 \n\t" - "pshufh %[A], %[A], %[ftmp0] \n\t" - "mtc1 %[tmp0], %[ftmp4] \n\t" + "xor %[ftmp0], %[ftmp0], %[ftmp0] \n\t" + "dli %[tmp0], 0x06 \n\t" + "pshufh %[A], %[A], %[ftmp0] \n\t" + "pshufh %[E], %[E], %[ftmp0] \n\t" + "mtc1 %[tmp0], %[ftmp7] \n\t" - "1: \n\t" + "1: \n\t" MMI_ULDC1(%[ftmp1], %[src], 0x00) - "punpcklbh %[ftmp2], %[ftmp1], %[ftmp0] \n\t" - "punpckhbh %[ftmp3], %[ftmp1], %[ftmp0] \n\t" - "pmullh %[ftmp1], %[ftmp2], %[A] \n\t" - "pmullh %[ftmp2], %[ftmp3], %[A] \n\t" - "paddh %[ftmp1], %[ftmp1], %[ff_pw_32] \n\t" - "paddh %[ftmp2], %[ftmp2], %[ff_pw_32] \n\t" - "psrlh %[ftmp1], %[ftmp1], %[ftmp4] \n\t" - "psrlh %[ftmp2], %[ftmp2], %[ftmp4] \n\t" - "packushb %[ftmp1], %[ftmp1], %[ftmp2] \n\t" - PTR_ADDU "%[src], %[src], %[stride] \n\t" - MMI_SDC1(%[ftmp1], %[dst], 0x00) + PTR_ADDU "%[src], %[src], %[stride] \n\t" + MMI_ULDC1(%[ftmp2], %[src], 0x00) + PTR_ADDU "%[src], %[src], %[stride] \n\t" + MMI_ULDC1(%[ftmp8], %[src], 0x00) + "addi %[h], %[h], -0x02 \n\t" - PTR_ADDU "%[dst], %[dst], %[stride] \n\t" - MMI_ULDC1(%[ftmp1], %[src], 0x00) - "punpcklbh %[ftmp2], %[ftmp1], %[ftmp0] \n\t" - "punpckhbh %[ftmp3], %[ftmp1], %[ftmp0] \n\t" - "pmullh %[ftmp1], %[ftmp2], %[A] \n\t" - "pmullh %[ftmp2], %[ftmp3], %[A] \n\t" - "paddh %[ftmp1], %[ftmp1], %[ff_pw_32] \n\t" - "paddh %[ftmp2], %[ftmp2], %[ff_pw_32] \n\t" - "psrlh %[ftmp1], %[ftmp1], %[ftmp4] \n\t" - "psrlh %[ftmp2], %[ftmp2], %[ftmp4] \n\t" - "packushb %[ftmp1], %[ftmp1], %[ftmp2] \n\t" - "addi %[h], %[h], -0x02 \n\t" - MMI_SDC1(%[ftmp1], %[dst], 0x00) + "punpcklbh %[ftmp3], %[ftmp1], %[ftmp0] \n\t" + "punpckhbh %[ftmp4], %[ftmp1], %[ftmp0] \n\t" + "punpcklbh %[ftmp5], %[ftmp2], %[ftmp0] \n\t" + "punpckhbh %[ftmp6], %[ftmp2], %[ftmp0] \n\t" + "pmullh %[ftmp3], %[ftmp3], %[A] \n\t" + "pmullh %[ftmp5], %[ftmp5], %[E] \n\t" + "paddh %[ftmp3], %[ftmp3], %[ftmp5] \n\t" + "pmullh %[ftmp4], %[ftmp4], %[A] \n\t" + "pmullh %[ftmp6], %[ftmp6], %[E] \n\t" + "paddh %[ftmp4], %[ftmp4], %[ftmp6] \n\t" + "paddh %[ftmp3], %[ftmp3], %[ff_pw_32] \n\t" + "paddh %[ftmp4], %[ftmp4], %[ff_pw_32] \n\t" + "psrlh %[ftmp3], %[ftmp3], %[ftmp7] \n\t" + "psrlh %[ftmp4], %[ftmp4], %[ftmp7] \n\t" + "packushb %[ftmp1], %[ftmp3], %[ftmp4] \n\t" - PTR_ADDU "%[src], %[src], %[stride] \n\t" - PTR_ADDU "%[dst], %[dst], %[stride] \n\t" - "bnez %[h], 1b \n\t" + "punpcklbh %[ftmp3], %[ftmp2], %[ftmp0] \n\t" + "punpckhbh %[ftmp4], %[ftmp2], %[ftmp0] \n\t" + "punpcklbh %[ftmp5], %[ftmp8], %[ftmp0] \n\t" + "punpckhbh %[ftmp6], %[ftmp8], %[ftmp0] \n\t" + "pmullh %[ftmp3], %[ftmp3], %[A] \n\t" + "pmullh %[ftmp5], %[ftmp5], %[E] \n\t" + "paddh %[ftmp3], %[ftmp3], %[ftmp5] \n\t" + "pmullh %[ftmp4], %[ftmp4], %[A] \n\t" + "pmullh %[ftmp6], %[ftmp6], %[E] \n\t" + "paddh %[ftmp4], %[ftmp4], %[ftmp6] \n\t" + "paddh %[ftmp3], %[ftmp3], %[ff_pw_32] \n\t" + "paddh %[ftmp4], %[ftmp4], %[ff_pw_32] \n\t" + "psrlh %[ftmp3], %[ftmp3], %[ftmp7] \n\t" + "psrlh %[ftmp4], %[ftmp4], %[ftmp7] \n\t" + "packushb %[ftmp2], %[ftmp3], %[ftmp4] \n\t" + + MMI_SDC1(%[ftmp1], %[dst], 0x00) + PTR_ADDU "%[dst], %[dst], %[stride] \n\t" + MMI_SDC1(%[ftmp2], %[dst], 0x00) + PTR_ADDU "%[dst], %[dst], %[stride] \n\t" + "bnez %[h], 1b \n\t" : [ftmp0]"=&f"(ftmp[0]), [ftmp1]"=&f"(ftmp[1]), [ftmp2]"=&f"(ftmp[2]), [ftmp3]"=&f"(ftmp[3]), - [ftmp4]"=&f"(ftmp[4]), - [tmp0]"=&r"(tmp[0]), - RESTRICT_ASM_ALL64 + [ftmp4]"=&f"(ftmp[4]), [ftmp5]"=&f"(ftmp[5]), + [ftmp6]"=&f"(ftmp[6]), [ftmp7]"=&f"(ftmp[7]), + [ftmp8]"=&f"(ftmp[8]), [tmp0]"=&r"(tmp[0]), [dst]"+&r"(dst), [src]"+&r"(src), [h]"+&r"(h) - : [stride]"r"((mips_reg)stride),[ff_pw_32]"f"(ff_pw_32), - [A]"f"(A) + : [stride]"r"((mips_reg)stride), + [ff_pw_32]"f"(ff_pw_32), + [A]"f"(A), [E]"f"(E) : "memory" ); } @@ -210,77 +290,100 @@ void ff_put_h264_chroma_mc8_mmi(uint8_t *dst, uint8_t *src, ptrdiff_t stride, void ff_avg_h264_chroma_mc8_mmi(uint8_t *dst, uint8_t *src, ptrdiff_t stride, int h, int x, int y) { - const int A = (8 - x) * (8 - y); - const int B = x * (8 - y); - const int C = (8 - x) * y; - const int D = x * y; - const int E = B + C; + int A = 64, B, C, D, E; double ftmp[10]; uint64_t tmp[1]; - mips_reg addr[1]; - DECLARE_VAR_ALL64; - if (D) { + if(!(x || y)){ + /* x=0, y=0, A=64 */ __asm__ volatile ( - "xor %[ftmp0], %[ftmp0], %[ftmp0] \n\t" - "dli %[tmp0], 0x06 \n\t" - "pshufh %[A], %[A], %[ftmp0] \n\t" - "pshufh %[B], %[B], %[ftmp0] \n\t" - "mtc1 %[tmp0], %[ftmp9] \n\t" - "pshufh %[C], %[C], %[ftmp0] \n\t" - "pshufh %[D], %[D], %[ftmp0] \n\t" - "1: \n\t" - PTR_ADDU "%[addr0], %[src], %[stride] \n\t" + MMI_ULDC1(%[ftmp0], %[src], 0x00) + PTR_ADDU "%[src], %[src], %[stride] \n\t" MMI_ULDC1(%[ftmp1], %[src], 0x00) - MMI_ULDC1(%[ftmp2], %[src], 0x01) - MMI_ULDC1(%[ftmp3], %[addr0], 0x00) - MMI_ULDC1(%[ftmp4], %[addr0], 0x01) - - "punpcklbh %[ftmp5], %[ftmp1], %[ftmp0] \n\t" - "punpckhbh %[ftmp6], %[ftmp1], %[ftmp0] \n\t" - "punpcklbh %[ftmp7], %[ftmp2], %[ftmp0] \n\t" - "punpckhbh %[ftmp8], %[ftmp2], %[ftmp0] \n\t" - "pmullh %[ftmp5], %[ftmp5], %[A] \n\t" - "pmullh %[ftmp7], %[ftmp7], %[B] \n\t" - "paddh %[ftmp1], %[ftmp5], %[ftmp7] \n\t" - "pmullh %[ftmp6], %[ftmp6], %[A] \n\t" - "pmullh %[ftmp8], %[ftmp8], %[B] \n\t" - "paddh %[ftmp2], %[ftmp6], %[ftmp8] \n\t" - - "punpcklbh %[ftmp5], %[ftmp3], %[ftmp0] \n\t" - "punpckhbh %[ftmp6], %[ftmp3], %[ftmp0] \n\t" - "punpcklbh %[ftmp7], %[ftmp4], %[ftmp0] \n\t" - "punpckhbh %[ftmp8], %[ftmp4], %[ftmp0] \n\t" - "pmullh %[ftmp5], %[ftmp5], %[C] \n\t" - "pmullh %[ftmp7], %[ftmp7], %[D] \n\t" - "paddh %[ftmp3], %[ftmp5], %[ftmp7] \n\t" - "pmullh %[ftmp6], %[ftmp6], %[C] \n\t" - "pmullh %[ftmp8], %[ftmp8], %[D] \n\t" - "paddh %[ftmp4], %[ftmp6], %[ftmp8] \n\t" - - "paddh %[ftmp1], %[ftmp1], %[ftmp3] \n\t" - "paddh %[ftmp2], %[ftmp2], %[ftmp4] \n\t" - "paddh %[ftmp1], %[ftmp1], %[ff_pw_32] \n\t" - "paddh %[ftmp2], %[ftmp2], %[ff_pw_32] \n\t" - "psrlh %[ftmp1], %[ftmp1], %[ftmp9] \n\t" - "psrlh %[ftmp2], %[ftmp2], %[ftmp9] \n\t" - "packushb %[ftmp1], %[ftmp1], %[ftmp2] \n\t" + PTR_ADDU "%[src], %[src], %[stride] \n\t" MMI_LDC1(%[ftmp2], %[dst], 0x00) - "pavgb %[ftmp1], %[ftmp1], %[ftmp2] \n\t" - "addi %[h], %[h], -0x01 \n\t" + PTR_ADDU "%[dst], %[dst], %[stride] \n\t" + MMI_LDC1(%[ftmp3], %[dst], 0x00) + PTR_SUBU "%[dst], %[dst], %[stride] \n\t" + "pavgb %[ftmp0], %[ftmp0], %[ftmp2] \n\t" + "pavgb %[ftmp1], %[ftmp1], %[ftmp3] \n\t" + MMI_SDC1(%[ftmp0], %[dst], 0x00) + PTR_ADDU "%[dst], %[dst], %[stride] \n\t" MMI_SDC1(%[ftmp1], %[dst], 0x00) PTR_ADDU "%[dst], %[dst], %[stride] \n\t" - PTR_ADDU "%[src], %[src], %[stride] \n\t" + "addi %[h], %[h], -0x02 \n\t" "bnez %[h], 1b \n\t" + : [ftmp0]"=&f"(ftmp[0]), [ftmp1]"=&f"(ftmp[1]), + [ftmp2]"=&f"(ftmp[2]), [ftmp3]"=&f"(ftmp[3]), + [dst]"+&r"(dst), [src]"+&r"(src), + [h]"+&r"(h) + : [stride]"r"((mips_reg)stride) + : "memory" + ); + } else if (x && y) { + /* x!=0, y!=0 */ + D = x * y; + B = (x << 3) - D; + C = (y << 3) - D; + A = 64 - D - B - C; + __asm__ volatile ( + "xor %[ftmp0], %[ftmp0], %[ftmp0] \n\t" + "dli %[tmp0], 0x06 \n\t" + "pshufh %[A], %[A], %[ftmp0] \n\t" + "pshufh %[B], %[B], %[ftmp0] \n\t" + "mtc1 %[tmp0], %[ftmp9] \n\t" + "pshufh %[C], %[C], %[ftmp0] \n\t" + "pshufh %[D], %[D], %[ftmp0] \n\t" + + "1: \n\t" + MMI_ULDC1(%[ftmp1], %[src], 0x00) + MMI_ULDC1(%[ftmp2], %[src], 0x01) + PTR_ADDU "%[src], %[src], %[stride] \n\t" + MMI_ULDC1(%[ftmp3], %[src], 0x00) + MMI_ULDC1(%[ftmp4], %[src], 0x01) + "addi %[h], %[h], -0x01 \n\t" + + "punpcklbh %[ftmp5], %[ftmp1], %[ftmp0] \n\t" + "punpckhbh %[ftmp6], %[ftmp1], %[ftmp0] \n\t" + "punpcklbh %[ftmp7], %[ftmp2], %[ftmp0] \n\t" + "punpckhbh %[ftmp8], %[ftmp2], %[ftmp0] \n\t" + "pmullh %[ftmp5], %[ftmp5], %[A] \n\t" + "pmullh %[ftmp7], %[ftmp7], %[B] \n\t" + "paddh %[ftmp1], %[ftmp5], %[ftmp7] \n\t" + "pmullh %[ftmp6], %[ftmp6], %[A] \n\t" + "pmullh %[ftmp8], %[ftmp8], %[B] \n\t" + "paddh %[ftmp2], %[ftmp6], %[ftmp8] \n\t" + + "punpcklbh %[ftmp5], %[ftmp3], %[ftmp0] \n\t" + "punpckhbh %[ftmp6], %[ftmp3], %[ftmp0] \n\t" + "punpcklbh %[ftmp7], %[ftmp4], %[ftmp0] \n\t" + "punpckhbh %[ftmp8], %[ftmp4], %[ftmp0] \n\t" + "pmullh %[ftmp5], %[ftmp5], %[C] \n\t" + "pmullh %[ftmp7], %[ftmp7], %[D] \n\t" + "paddh %[ftmp3], %[ftmp5], %[ftmp7] \n\t" + "pmullh %[ftmp6], %[ftmp6], %[C] \n\t" + "pmullh %[ftmp8], %[ftmp8], %[D] \n\t" + "paddh %[ftmp4], %[ftmp6], %[ftmp8] \n\t" + + "paddh %[ftmp1], %[ftmp1], %[ftmp3] \n\t" + "paddh %[ftmp2], %[ftmp2], %[ftmp4] \n\t" + "paddh %[ftmp1], %[ftmp1], %[ff_pw_32] \n\t" + "paddh %[ftmp2], %[ftmp2], %[ff_pw_32] \n\t" + "psrlh %[ftmp1], %[ftmp1], %[ftmp9] \n\t" + "psrlh %[ftmp2], %[ftmp2], %[ftmp9] \n\t" + "packushb %[ftmp1], %[ftmp1], %[ftmp2] \n\t" + MMI_LDC1(%[ftmp2], %[dst], 0x00) + "pavgb %[ftmp1], %[ftmp1], %[ftmp2] \n\t" + MMI_SDC1(%[ftmp1], %[dst], 0x00) + PTR_ADDU "%[dst], %[dst], %[stride] \n\t" + "bnez %[h], 1b \n\t" : [ftmp0]"=&f"(ftmp[0]), [ftmp1]"=&f"(ftmp[1]), [ftmp2]"=&f"(ftmp[2]), [ftmp3]"=&f"(ftmp[3]), [ftmp4]"=&f"(ftmp[4]), [ftmp5]"=&f"(ftmp[5]), [ftmp6]"=&f"(ftmp[6]), [ftmp7]"=&f"(ftmp[7]), [ftmp8]"=&f"(ftmp[8]), [ftmp9]"=&f"(ftmp[9]), [tmp0]"=&r"(tmp[0]), - RESTRICT_ASM_ALL64 - [addr0]"=&r"(addr[0]), [dst]"+&r"(dst), [src]"+&r"(src), [h]"+&r"(h) : [stride]"r"((mips_reg)stride),[ff_pw_32]"f"(ff_pw_32), @@ -288,109 +391,104 @@ void ff_avg_h264_chroma_mc8_mmi(uint8_t *dst, uint8_t *src, ptrdiff_t stride, [C]"f"(C), [D]"f"(D) : "memory" ); - } else if (E) { - const int step = C ? stride : 1; - + } else if (x) { + /* x!=0, y==0 */ + E = x << 3; + A = 64 - E; __asm__ volatile ( - "xor %[ftmp0], %[ftmp0], %[ftmp0] \n\t" - "dli %[tmp0], 0x06 \n\t" - "pshufh %[A], %[A], %[ftmp0] \n\t" - "pshufh %[E], %[E], %[ftmp0] \n\t" - "mtc1 %[tmp0], %[ftmp7] \n\t" + "xor %[ftmp0], %[ftmp0], %[ftmp0] \n\t" + "dli %[tmp0], 0x06 \n\t" + "pshufh %[A], %[A], %[ftmp0] \n\t" + "pshufh %[E], %[E], %[ftmp0] \n\t" + "mtc1 %[tmp0], %[ftmp7] \n\t" - "1: \n\t" - PTR_ADDU "%[addr0], %[src], %[step] \n\t" + "1: \n\t" MMI_ULDC1(%[ftmp1], %[src], 0x00) - MMI_ULDC1(%[ftmp2], %[addr0], 0x00) + MMI_ULDC1(%[ftmp2], %[src], 0x01) + PTR_ADDU "%[src], %[src], %[stride] \n\t" + "addi %[h], %[h], -0x01 \n\t" - "punpcklbh %[ftmp3], %[ftmp1], %[ftmp0] \n\t" - "punpckhbh %[ftmp4], %[ftmp1], %[ftmp0] \n\t" - "punpcklbh %[ftmp5], %[ftmp2], %[ftmp0] \n\t" - "punpckhbh %[ftmp6], %[ftmp2], %[ftmp0] \n\t" - "pmullh %[ftmp3], %[ftmp3], %[A] \n\t" - "pmullh %[ftmp5], %[ftmp5], %[E] \n\t" - "paddh %[ftmp1], %[ftmp3], %[ftmp5] \n\t" - "pmullh %[ftmp4], %[ftmp4], %[A] \n\t" - "pmullh %[ftmp6], %[ftmp6], %[E] \n\t" - "paddh %[ftmp2], %[ftmp4], %[ftmp6] \n\t" + "punpcklbh %[ftmp3], %[ftmp1], %[ftmp0] \n\t" + "punpckhbh %[ftmp4], %[ftmp1], %[ftmp0] \n\t" + "punpcklbh %[ftmp5], %[ftmp2], %[ftmp0] \n\t" + "punpckhbh %[ftmp6], %[ftmp2], %[ftmp0] \n\t" + "pmullh %[ftmp3], %[ftmp3], %[A] \n\t" + "pmullh %[ftmp5], %[ftmp5], %[E] \n\t" + "paddh %[ftmp1], %[ftmp3], %[ftmp5] \n\t" + "pmullh %[ftmp4], %[ftmp4], %[A] \n\t" + "pmullh %[ftmp6], %[ftmp6], %[E] \n\t" + "paddh %[ftmp2], %[ftmp4], %[ftmp6] \n\t" - "paddh %[ftmp1], %[ftmp1], %[ff_pw_32] \n\t" - "paddh %[ftmp2], %[ftmp2], %[ff_pw_32] \n\t" - "psrlh %[ftmp1], %[ftmp1], %[ftmp7] \n\t" - "psrlh %[ftmp2], %[ftmp2], %[ftmp7] \n\t" - "packushb %[ftmp1], %[ftmp1], %[ftmp2] \n\t" + "paddh %[ftmp1], %[ftmp1], %[ff_pw_32] \n\t" + "paddh %[ftmp2], %[ftmp2], %[ff_pw_32] \n\t" + "psrlh %[ftmp1], %[ftmp1], %[ftmp7] \n\t" + "psrlh %[ftmp2], %[ftmp2], %[ftmp7] \n\t" + "packushb %[ftmp1], %[ftmp1], %[ftmp2] \n\t" MMI_LDC1(%[ftmp2], %[dst], 0x00) - "pavgb %[ftmp1], %[ftmp1], %[ftmp2] \n\t" - "addi %[h], %[h], -0x01 \n\t" + "pavgb %[ftmp1], %[ftmp1], %[ftmp2] \n\t" MMI_SDC1(%[ftmp1], %[dst], 0x00) - PTR_ADDU "%[src], %[src], %[stride] \n\t" - PTR_ADDU "%[dst], %[dst], %[stride] \n\t" - "bnez %[h], 1b \n\t" + PTR_ADDU "%[dst], %[dst], %[stride] \n\t" + "bnez %[h], 1b \n\t" : [ftmp0]"=&f"(ftmp[0]), [ftmp1]"=&f"(ftmp[1]), [ftmp2]"=&f"(ftmp[2]), [ftmp3]"=&f"(ftmp[3]), [ftmp4]"=&f"(ftmp[4]), [ftmp5]"=&f"(ftmp[5]), [ftmp6]"=&f"(ftmp[6]), [ftmp7]"=&f"(ftmp[7]), [tmp0]"=&r"(tmp[0]), - RESTRICT_ASM_ALL64 - [addr0]"=&r"(addr[0]), [dst]"+&r"(dst), [src]"+&r"(src), [h]"+&r"(h) - : [stride]"r"((mips_reg)stride),[step]"r"((mips_reg)step), + : [stride]"r"((mips_reg)stride), [ff_pw_32]"f"(ff_pw_32), [A]"f"(A), [E]"f"(E) : "memory" ); } else { + /* x==0, y!=0 */ + E = y << 3; + A = 64 - E; __asm__ volatile ( - "xor %[ftmp0], %[ftmp0], %[ftmp0] \n\t" - "dli %[tmp0], 0x06 \n\t" - "pshufh %[A], %[A], %[ftmp0] \n\t" - "mtc1 %[tmp0], %[ftmp4] \n\t" + "xor %[ftmp0], %[ftmp0], %[ftmp0] \n\t" + "dli %[tmp0], 0x06 \n\t" + "pshufh %[A], %[A], %[ftmp0] \n\t" + "pshufh %[E], %[E], %[ftmp0] \n\t" + "mtc1 %[tmp0], %[ftmp7] \n\t" - "1: \n\t" + "1: \n\t" MMI_ULDC1(%[ftmp1], %[src], 0x00) - "punpcklbh %[ftmp2], %[ftmp1], %[ftmp0] \n\t" - "punpckhbh %[ftmp3], %[ftmp1], %[ftmp0] \n\t" - "pmullh %[ftmp1], %[ftmp2], %[A] \n\t" - "pmullh %[ftmp2], %[ftmp3], %[A] \n\t" - "paddh %[ftmp1], %[ftmp1], %[ff_pw_32] \n\t" - "paddh %[ftmp2], %[ftmp2], %[ff_pw_32] \n\t" - "psrlh %[ftmp1], %[ftmp1], %[ftmp4] \n\t" - "psrlh %[ftmp2], %[ftmp2], %[ftmp4] \n\t" - "packushb %[ftmp1], %[ftmp1], %[ftmp2] \n\t" - MMI_LDC1(%[ftmp2], %[dst], 0x00) - "pavgb %[ftmp1], %[ftmp1], %[ftmp2] \n\t" - PTR_ADDU "%[src], %[src], %[stride] \n\t" - MMI_SDC1(%[ftmp1], %[dst], 0x00) - PTR_ADDU "%[dst], %[dst], %[stride] \n\t" + PTR_ADDU "%[src], %[src], %[stride] \n\t" + MMI_ULDC1(%[ftmp2], %[src], 0x00) + "addi %[h], %[h], -0x01 \n\t" - MMI_ULDC1(%[ftmp1], %[src], 0x00) - "punpcklbh %[ftmp2], %[ftmp1], %[ftmp0] \n\t" - "punpckhbh %[ftmp3], %[ftmp1], %[ftmp0] \n\t" - "pmullh %[ftmp1], %[ftmp2], %[A] \n\t" - "pmullh %[ftmp2], %[ftmp3], %[A] \n\t" - "paddh %[ftmp1], %[ftmp1], %[ff_pw_32] \n\t" - "paddh %[ftmp2], %[ftmp2], %[ff_pw_32] \n\t" - "psrlh %[ftmp1], %[ftmp1], %[ftmp4] \n\t" - "psrlh %[ftmp2], %[ftmp2], %[ftmp4] \n\t" - "packushb %[ftmp1], %[ftmp1], %[ftmp2] \n\t" - MMI_LDC1(%[ftmp2], %[dst], 0x00) - "pavgb %[ftmp1], %[ftmp1], %[ftmp2] \n\t" - "addi %[h], %[h], -0x02 \n\t" - MMI_SDC1(%[ftmp1], %[dst], 0x00) + "punpcklbh %[ftmp3], %[ftmp1], %[ftmp0] \n\t" + "punpckhbh %[ftmp4], %[ftmp1], %[ftmp0] \n\t" + "punpcklbh %[ftmp5], %[ftmp2], %[ftmp0] \n\t" + "punpckhbh %[ftmp6], %[ftmp2], %[ftmp0] \n\t" + "pmullh %[ftmp3], %[ftmp3], %[A] \n\t" + "pmullh %[ftmp5], %[ftmp5], %[E] \n\t" + "paddh %[ftmp1], %[ftmp3], %[ftmp5] \n\t" + "pmullh %[ftmp4], %[ftmp4], %[A] \n\t" + "pmullh %[ftmp6], %[ftmp6], %[E] \n\t" + "paddh %[ftmp2], %[ftmp4], %[ftmp6] \n\t" - PTR_ADDU "%[src], %[src], %[stride] \n\t" - PTR_ADDU "%[dst], %[dst], %[stride] \n\t" - "bnez %[h], 1b \n\t" + "paddh %[ftmp1], %[ftmp1], %[ff_pw_32] \n\t" + "paddh %[ftmp2], %[ftmp2], %[ff_pw_32] \n\t" + "psrlh %[ftmp1], %[ftmp1], %[ftmp7] \n\t" + "psrlh %[ftmp2], %[ftmp2], %[ftmp7] \n\t" + "packushb %[ftmp1], %[ftmp1], %[ftmp2] \n\t" + MMI_LDC1(%[ftmp2], %[dst], 0x00) + "pavgb %[ftmp1], %[ftmp1], %[ftmp2] \n\t" + MMI_SDC1(%[ftmp1], %[dst], 0x00) + PTR_ADDU "%[dst], %[dst], %[stride] \n\t" + "bnez %[h], 1b \n\t" : [ftmp0]"=&f"(ftmp[0]), [ftmp1]"=&f"(ftmp[1]), [ftmp2]"=&f"(ftmp[2]), [ftmp3]"=&f"(ftmp[3]), - [ftmp4]"=&f"(ftmp[4]), + [ftmp4]"=&f"(ftmp[4]), [ftmp5]"=&f"(ftmp[5]), + [ftmp6]"=&f"(ftmp[6]), [ftmp7]"=&f"(ftmp[7]), [tmp0]"=&r"(tmp[0]), - RESTRICT_ASM_ALL64 [dst]"+&r"(dst), [src]"+&r"(src), [h]"+&r"(h) - : [stride]"r"((mips_reg)stride),[ff_pw_32]"f"(ff_pw_32), - [A]"f"(A) + : [stride]"r"((mips_reg)stride), + [ff_pw_32]"f"(ff_pw_32), + [A]"f"(A), [E]"f"(E) : "memory" ); } @@ -401,8 +499,8 @@ void ff_put_h264_chroma_mc4_mmi(uint8_t *dst, uint8_t *src, ptrdiff_t stride, { const int A = (8 - x) * (8 - y); const int B = x * (8 - y); - const int C = (8 - x) * y; - const int D = x * y; + const int C = (8 - x) * y; + const int D = x * y; const int E = B + C; double ftmp[8]; uint64_t tmp[1]; @@ -420,31 +518,29 @@ void ff_put_h264_chroma_mc4_mmi(uint8_t *dst, uint8_t *src, ptrdiff_t stride, "pshufh %[D], %[D], %[ftmp0] \n\t" "1: \n\t" - PTR_ADDU "%[addr0], %[src], %[stride] \n\t" MMI_ULWC1(%[ftmp1], %[src], 0x00) MMI_ULWC1(%[ftmp2], %[src], 0x01) - MMI_ULWC1(%[ftmp3], %[addr0], 0x00) - MMI_ULWC1(%[ftmp4], %[addr0], 0x01) + PTR_ADDU "%[src], %[src], %[stride] \n\t" + MMI_ULWC1(%[ftmp3], %[src], 0x00) + MMI_ULWC1(%[ftmp4], %[src], 0x01) "punpcklbh %[ftmp5], %[ftmp1], %[ftmp0] \n\t" "punpcklbh %[ftmp6], %[ftmp2], %[ftmp0] \n\t" "pmullh %[ftmp5], %[ftmp5], %[A] \n\t" "pmullh %[ftmp6], %[ftmp6], %[B] \n\t" "paddh %[ftmp1], %[ftmp5], %[ftmp6] \n\t" - "punpcklbh %[ftmp5], %[ftmp3], %[ftmp0] \n\t" "punpcklbh %[ftmp6], %[ftmp4], %[ftmp0] \n\t" "pmullh %[ftmp5], %[ftmp5], %[C] \n\t" "pmullh %[ftmp6], %[ftmp6], %[D] \n\t" "paddh %[ftmp2], %[ftmp5], %[ftmp6] \n\t" - "paddh %[ftmp1], %[ftmp1], %[ftmp2] \n\t" "paddh %[ftmp1], %[ftmp1], %[ff_pw_32] \n\t" "psrlh %[ftmp1], %[ftmp1], %[ftmp7] \n\t" "packushb %[ftmp1], %[ftmp1], %[ftmp0] \n\t" + "addi %[h], %[h], -0x01 \n\t" MMI_SWC1(%[ftmp1], %[dst], 0x00) - PTR_ADDU "%[src], %[src], %[stride] \n\t" PTR_ADDU "%[dst], %[dst], %[stride] \n\t" "bnez %[h], 1b \n\t" : [ftmp0]"=&f"(ftmp[0]), [ftmp1]"=&f"(ftmp[1]), @@ -453,7 +549,6 @@ void ff_put_h264_chroma_mc4_mmi(uint8_t *dst, uint8_t *src, ptrdiff_t stride, [ftmp6]"=&f"(ftmp[6]), [ftmp7]"=&f"(ftmp[7]), [tmp0]"=&r"(tmp[0]), RESTRICT_ASM_LOW32 - [addr0]"=&r"(addr[0]), [dst]"+&r"(dst), [src]"+&r"(src), [h]"+&r"(h) : [stride]"r"((mips_reg)stride),[ff_pw_32]"f"(ff_pw_32), @@ -463,7 +558,6 @@ void ff_put_h264_chroma_mc4_mmi(uint8_t *dst, uint8_t *src, ptrdiff_t stride, ); } else if (E) { const int step = C ? stride : 1; - __asm__ volatile ( "xor %[ftmp0], %[ftmp0], %[ftmp0] \n\t" "dli %[tmp0], 0x06 \n\t" @@ -472,22 +566,20 @@ void ff_put_h264_chroma_mc4_mmi(uint8_t *dst, uint8_t *src, ptrdiff_t stride, "mtc1 %[tmp0], %[ftmp5] \n\t" "1: \n\t" - PTR_ADDU "%[addr0], %[src], %[step] \n\t" MMI_ULWC1(%[ftmp1], %[src], 0x00) + PTR_ADDU "%[addr0], %[src], %[step] \n\t" MMI_ULWC1(%[ftmp2], %[addr0], 0x00) - + PTR_ADDU "%[src], %[src], %[stride] \n\t" + "addi %[h], %[h], -0x01 \n\t" "punpcklbh %[ftmp3], %[ftmp1], %[ftmp0] \n\t" "punpcklbh %[ftmp4], %[ftmp2], %[ftmp0] \n\t" "pmullh %[ftmp3], %[ftmp3], %[A] \n\t" "pmullh %[ftmp4], %[ftmp4], %[E] \n\t" "paddh %[ftmp1], %[ftmp3], %[ftmp4] \n\t" - "paddh %[ftmp1], %[ftmp1], %[ff_pw_32] \n\t" "psrlh %[ftmp1], %[ftmp1], %[ftmp5] \n\t" "packushb %[ftmp1], %[ftmp1], %[ftmp0] \n\t" - "addi %[h], %[h], -0x01 \n\t" MMI_SWC1(%[ftmp1], %[dst], 0x00) - PTR_ADDU "%[src], %[src], %[stride] \n\t" PTR_ADDU "%[dst], %[dst], %[stride] \n\t" "bnez %[h], 1b \n\t" : [ftmp0]"=&f"(ftmp[0]), [ftmp1]"=&f"(ftmp[1]), @@ -505,42 +597,22 @@ void ff_put_h264_chroma_mc4_mmi(uint8_t *dst, uint8_t *src, ptrdiff_t stride, ); } else { __asm__ volatile ( - "xor %[ftmp0], %[ftmp0], %[ftmp0] \n\t" - "dli %[tmp0], 0x06 \n\t" - "pshufh %[A], %[A], %[ftmp0] \n\t" - "mtc1 %[tmp0], %[ftmp3] \n\t" - "1: \n\t" - MMI_ULWC1(%[ftmp1], %[src], 0x00) - "punpcklbh %[ftmp2], %[ftmp1], %[ftmp0] \n\t" - "pmullh %[ftmp1], %[ftmp2], %[A] \n\t" - "paddh %[ftmp1], %[ftmp1], %[ff_pw_32] \n\t" - "psrlh %[ftmp1], %[ftmp1], %[ftmp3] \n\t" - "packushb %[ftmp1], %[ftmp1], %[ftmp0] \n\t" + MMI_ULWC1(%[ftmp0], %[src], 0x00) PTR_ADDU "%[src], %[src], %[stride] \n\t" - MMI_SWC1(%[ftmp1], %[dst], 0x00) - PTR_ADDU "%[dst], %[dst], %[stride] \n\t" - MMI_ULWC1(%[ftmp1], %[src], 0x00) - "punpcklbh %[ftmp2], %[ftmp1], %[ftmp0] \n\t" - "pmullh %[ftmp1], %[ftmp2], %[A] \n\t" - "paddh %[ftmp1], %[ftmp1], %[ff_pw_32] \n\t" - "psrlh %[ftmp1], %[ftmp1], %[ftmp3] \n\t" - "packushb %[ftmp1], %[ftmp1], %[ftmp0] \n\t" + PTR_ADDU "%[src], %[src], %[stride] \n\t" "addi %[h], %[h], -0x02 \n\t" + MMI_SWC1(%[ftmp0], %[dst], 0x00) + PTR_ADDU "%[dst], %[dst], %[stride] \n\t" MMI_SWC1(%[ftmp1], %[dst], 0x00) - - PTR_ADDU "%[src], %[src], %[stride] \n\t" PTR_ADDU "%[dst], %[dst], %[stride] \n\t" "bnez %[h], 1b \n\t" : [ftmp0]"=&f"(ftmp[0]), [ftmp1]"=&f"(ftmp[1]), - [ftmp2]"=&f"(ftmp[2]), [ftmp3]"=&f"(ftmp[3]), - [tmp0]"=&r"(tmp[0]), - RESTRICT_ASM_LOW32 [dst]"+&r"(dst), [src]"+&r"(src), + RESTRICT_ASM_LOW32 [h]"+&r"(h) - : [stride]"r"((mips_reg)stride),[ff_pw_32]"f"(ff_pw_32), - [A]"f"(A) + : [stride]"r"((mips_reg)stride) : "memory" ); } @@ -570,33 +642,31 @@ void ff_avg_h264_chroma_mc4_mmi(uint8_t *dst, uint8_t *src, ptrdiff_t stride, "pshufh %[D], %[D], %[ftmp0] \n\t" "1: \n\t" - PTR_ADDU "%[addr0], %[src], %[stride] \n\t" MMI_ULWC1(%[ftmp1], %[src], 0x00) MMI_ULWC1(%[ftmp2], %[src], 0x01) - MMI_ULWC1(%[ftmp3], %[addr0], 0x00) - MMI_ULWC1(%[ftmp4], %[addr0], 0x01) + PTR_ADDU "%[src], %[src], %[stride] \n\t" + MMI_ULWC1(%[ftmp3], %[src], 0x00) + MMI_ULWC1(%[ftmp4], %[src], 0x01) "punpcklbh %[ftmp5], %[ftmp1], %[ftmp0] \n\t" "punpcklbh %[ftmp6], %[ftmp2], %[ftmp0] \n\t" "pmullh %[ftmp5], %[ftmp5], %[A] \n\t" "pmullh %[ftmp6], %[ftmp6], %[B] \n\t" "paddh %[ftmp1], %[ftmp5], %[ftmp6] \n\t" - "punpcklbh %[ftmp5], %[ftmp3], %[ftmp0] \n\t" "punpcklbh %[ftmp6], %[ftmp4], %[ftmp0] \n\t" "pmullh %[ftmp5], %[ftmp5], %[C] \n\t" "pmullh %[ftmp6], %[ftmp6], %[D] \n\t" "paddh %[ftmp2], %[ftmp5], %[ftmp6] \n\t" - "paddh %[ftmp1], %[ftmp1], %[ftmp2] \n\t" "paddh %[ftmp1], %[ftmp1], %[ff_pw_32] \n\t" "psrlh %[ftmp1], %[ftmp1], %[ftmp7] \n\t" "packushb %[ftmp1], %[ftmp1], %[ftmp0] \n\t" MMI_LWC1(%[ftmp2], %[dst], 0x00) "pavgb %[ftmp1], %[ftmp1], %[ftmp2] \n\t" + "addi %[h], %[h], -0x01 \n\t" MMI_SWC1(%[ftmp1], %[dst], 0x00) - PTR_ADDU "%[src], %[src], %[stride] \n\t" PTR_ADDU "%[dst], %[dst], %[stride] \n\t" "bnez %[h], 1b \n\t" : [ftmp0]"=&f"(ftmp[0]), [ftmp1]"=&f"(ftmp[1]), @@ -605,7 +675,6 @@ void ff_avg_h264_chroma_mc4_mmi(uint8_t *dst, uint8_t *src, ptrdiff_t stride, [ftmp6]"=&f"(ftmp[6]), [ftmp7]"=&f"(ftmp[7]), [tmp0]"=&r"(tmp[0]), RESTRICT_ASM_LOW32 - [addr0]"=&r"(addr[0]), [dst]"+&r"(dst), [src]"+&r"(src), [h]"+&r"(h) : [stride]"r"((mips_reg)stride),[ff_pw_32]"f"(ff_pw_32), @@ -615,32 +684,30 @@ void ff_avg_h264_chroma_mc4_mmi(uint8_t *dst, uint8_t *src, ptrdiff_t stride, ); } else if (E) { const int step = C ? stride : 1; - __asm__ volatile ( "xor %[ftmp0], %[ftmp0], %[ftmp0] \n\t" "dli %[tmp0], 0x06 \n\t" "pshufh %[A], %[A], %[ftmp0] \n\t" "pshufh %[E], %[E], %[ftmp0] \n\t" "mtc1 %[tmp0], %[ftmp5] \n\t" - "1: \n\t" - PTR_ADDU "%[addr0], %[src], %[step] \n\t" - MMI_ULWC1(%[ftmp1], %[src], 0x00) - MMI_ULWC1(%[ftmp2], %[addr0], 0x00) + "1: \n\t" + MMI_ULWC1(%[ftmp1], %[src], 0x00) + PTR_ADDU "%[addr0], %[src], %[step] \n\t" + MMI_ULWC1(%[ftmp2], %[addr0], 0x00) + PTR_ADDU "%[src], %[src], %[stride] \n\t" + "addi %[h], %[h], -0x01 \n\t" "punpcklbh %[ftmp3], %[ftmp1], %[ftmp0] \n\t" "punpcklbh %[ftmp4], %[ftmp2], %[ftmp0] \n\t" "pmullh %[ftmp3], %[ftmp3], %[A] \n\t" "pmullh %[ftmp4], %[ftmp4], %[E] \n\t" "paddh %[ftmp1], %[ftmp3], %[ftmp4] \n\t" - "paddh %[ftmp1], %[ftmp1], %[ff_pw_32] \n\t" "psrlh %[ftmp1], %[ftmp1], %[ftmp5] \n\t" "packushb %[ftmp1], %[ftmp1], %[ftmp0] \n\t" MMI_LWC1(%[ftmp2], %[dst], 0x00) "pavgb %[ftmp1], %[ftmp1], %[ftmp2] \n\t" - "addi %[h], %[h], -0x01 \n\t" MMI_SWC1(%[ftmp1], %[dst], 0x00) - PTR_ADDU "%[src], %[src], %[stride] \n\t" PTR_ADDU "%[dst], %[dst], %[stride] \n\t" "bnez %[h], 1b \n\t" : [ftmp0]"=&f"(ftmp[0]), [ftmp1]"=&f"(ftmp[1]), @@ -658,46 +725,27 @@ void ff_avg_h264_chroma_mc4_mmi(uint8_t *dst, uint8_t *src, ptrdiff_t stride, ); } else { __asm__ volatile ( - "xor %[ftmp0], %[ftmp0], %[ftmp0] \n\t" - "dli %[tmp0], 0x06 \n\t" - "pshufh %[A], %[A], %[ftmp0] \n\t" - "mtc1 %[tmp0], %[ftmp3] \n\t" - "1: \n\t" - MMI_ULWC1(%[ftmp1], %[src], 0x00) - "punpcklbh %[ftmp2], %[ftmp1], %[ftmp0] \n\t" - "pmullh %[ftmp1], %[ftmp2], %[A] \n\t" - "paddh %[ftmp1], %[ftmp1], %[ff_pw_32] \n\t" - "psrlh %[ftmp1], %[ftmp1], %[ftmp3] \n\t" - "packushb %[ftmp1], %[ftmp1], %[ftmp0] \n\t" - MMI_LWC1(%[ftmp2], %[dst], 0x00) - "pavgb %[ftmp1], %[ftmp1], %[ftmp2] \n\t" + MMI_ULWC1(%[ftmp0], %[src], 0x00) PTR_ADDU "%[src], %[src], %[stride] \n\t" - MMI_SWC1(%[ftmp1], %[dst], 0x00) - PTR_ADDU "%[dst], %[dst], %[stride] \n\t" - MMI_ULWC1(%[ftmp1], %[src], 0x00) - "punpcklbh %[ftmp2], %[ftmp1], %[ftmp0] \n\t" - "pmullh %[ftmp1], %[ftmp2], %[A] \n\t" - "paddh %[ftmp1], %[ftmp1], %[ff_pw_32] \n\t" - "psrlh %[ftmp1], %[ftmp1], %[ftmp3] \n\t" - "packushb %[ftmp1], %[ftmp1], %[ftmp0] \n\t" - MMI_LWC1(%[ftmp2], %[dst], 0x00) - "pavgb %[ftmp1], %[ftmp1], %[ftmp2] \n\t" + PTR_ADDU "%[src], %[src], %[stride] \n\t" "addi %[h], %[h], -0x02 \n\t" + MMI_LWC1(%[ftmp2], %[dst], 0x00) + "pavgb %[ftmp0], %[ftmp0], %[ftmp2] \n\t" + MMI_SWC1(%[ftmp0], %[dst], 0x00) + PTR_ADDU "%[dst], %[dst], %[stride] \n\t" + MMI_LWC1(%[ftmp3], %[dst], 0x00) + "pavgb %[ftmp1], %[ftmp1], %[ftmp3] \n\t" MMI_SWC1(%[ftmp1], %[dst], 0x00) - - PTR_ADDU "%[src], %[src], %[stride] \n\t" PTR_ADDU "%[dst], %[dst], %[stride] \n\t" "bnez %[h], 1b \n\t" : [ftmp0]"=&f"(ftmp[0]), [ftmp1]"=&f"(ftmp[1]), [ftmp2]"=&f"(ftmp[2]), [ftmp3]"=&f"(ftmp[3]), - [tmp0]"=&r"(tmp[0]), - RESTRICT_ASM_LOW32 [dst]"+&r"(dst), [src]"+&r"(src), + RESTRICT_ASM_LOW32 [h]"+&r"(h) - : [stride]"r"((mips_reg)stride),[ff_pw_32]"f"(ff_pw_32), - [A]"f"(A) + : [stride]"r"((mips_reg)stride) : "memory" ); } diff --git a/libavcodec/mips/h264chroma_msa.c b/libavcodec/mips/h264chroma_msa.c index 4c2576119..4a68d9e13 100644 --- a/libavcodec/mips/h264chroma_msa.c +++ b/libavcodec/mips/h264chroma_msa.c @@ -85,7 +85,7 @@ static void avc_chroma_hz_2x4_msa(uint8_t *src, uint8_t *dst, int32_t stride, res_r = __msa_sat_u_h(res_r, 7); res = (v8i16) __msa_pckev_b((v16i8) res_r, (v16i8) res_r); - ST2x4_UB(res, 0, dst, stride); + ST_H4(res, 0, 1, 2, 3, dst, stride); } static void avc_chroma_hz_2w_msa(uint8_t *src, uint8_t *dst, int32_t stride, @@ -121,7 +121,7 @@ static void avc_chroma_hz_4x2_msa(uint8_t *src, uint8_t *dst, int32_t stride, res_r = __msa_sat_u_h(res_r, 7); res = (v4i32) __msa_pckev_b((v16i8) res_r, (v16i8) res_r); - ST4x2_UB(res, dst, stride); + ST_W2(res, 0, 1, dst, stride); } static void avc_chroma_hz_4x4_msa(uint8_t *src, uint8_t *dst, int32_t stride, @@ -144,7 +144,7 @@ static void avc_chroma_hz_4x4_msa(uint8_t *src, uint8_t *dst, int32_t stride, SRARI_H2_UH(res0_r, res1_r, 6); SAT_UH2_UH(res0_r, res1_r, 7); out = (v16u8) __msa_pckev_b((v16i8) res1_r, (v16i8) res0_r); - ST4x4_UB(out, out, 0, 1, 2, 3, dst, stride); + ST_W4(out, 0, 1, 2, 3, dst, stride); } static void avc_chroma_hz_4x8_msa(uint8_t *src, uint8_t *dst, int32_t stride, @@ -168,7 +168,7 @@ static void avc_chroma_hz_4x8_msa(uint8_t *src, uint8_t *dst, int32_t stride, SRARI_H4_UH(res0, res1, res2, res3, 6); SAT_UH4_UH(res0, res1, res2, res3, 7); PCKEV_B2_UB(res1, res0, res3, res2, out0, out1); - ST4x8_UB(out0, out1, dst, stride); + ST_W8(out0, out1, 0, 1, 2, 3, 0, 1, 2, 3, dst, stride); } static void avc_chroma_hz_4w_msa(uint8_t *src, uint8_t *dst, int32_t stride, @@ -204,7 +204,7 @@ static void avc_chroma_hz_8x4_msa(uint8_t *src, uint8_t *dst, int32_t stride, SRARI_H4_UH(res0, res1, res2, res3, 6); SAT_UH4_UH(res0, res1, res2, res3, 7); PCKEV_B2_UB(res1, res0, res3, res2, out0, out1); - ST8x4_UB(out0, out1, dst, stride); + ST_D4(out0, out1, 0, 1, 0, 1, dst, stride); } static void avc_chroma_hz_8x8_msa(uint8_t *src, uint8_t *dst, int32_t stride, @@ -237,7 +237,7 @@ static void avc_chroma_hz_8x8_msa(uint8_t *src, uint8_t *dst, int32_t stride, SAT_UH4_UH(res4, res5, res6, res7, 7); PCKEV_B2_UB(res1, res0, res3, res2, out0, out1); PCKEV_B2_UB(res5, res4, res7, res6, out2, out3); - ST8x8_UB(out0, out1, out2, out3, dst, stride); + ST_D8(out0, out1, out2, out3, 0, 1, 0, 1, 0, 1, 0, 1, dst, stride); } static void avc_chroma_hz_nonmult_msa(uint8_t *src, uint8_t *dst, @@ -266,7 +266,7 @@ static void avc_chroma_hz_nonmult_msa(uint8_t *src, uint8_t *dst, SRARI_H4_UH(res0, res1, res2, res3, 6); SAT_UH4_UH(res0, res1, res2, res3, 7); PCKEV_B2_UB(res1, res0, res3, res2, out0, out1); - ST8x4_UB(out0, out1, dst, stride); + ST_D4(out0, out1, 0, 1, 0, 1, dst, stride); dst += (4 * stride); } @@ -283,7 +283,7 @@ static void avc_chroma_hz_nonmult_msa(uint8_t *src, uint8_t *dst, res0 = __msa_sat_u_h(res0, 7); res0 = (v8u16) __msa_pckev_b((v16i8) res0, (v16i8) res0); - ST8x1_UB(res0, dst); + ST_D1(res0, 0, dst); dst += stride; } } @@ -359,7 +359,7 @@ static void avc_chroma_vt_2x4_msa(uint8_t *src, uint8_t *dst, int32_t stride, res = (v8i16) __msa_pckev_b((v16i8) res_r, (v16i8) res_r); - ST2x4_UB(res, 0, dst, stride); + ST_H4(res, 0, 1, 2, 3, dst, stride); } static void avc_chroma_vt_2w_msa(uint8_t *src, uint8_t *dst, int32_t stride, @@ -394,7 +394,7 @@ static void avc_chroma_vt_4x2_msa(uint8_t *src, uint8_t *dst, int32_t stride, res_r = __msa_sat_u_h(res_r, 7); res = (v4i32) __msa_pckev_b((v16i8) res_r, (v16i8) res_r); - ST4x2_UB(res, dst, stride); + ST_W2(res, 0, 1, dst, stride); } static void avc_chroma_vt_4x4_msa(uint8_t *src, uint8_t *dst, int32_t stride, @@ -418,7 +418,7 @@ static void avc_chroma_vt_4x4_msa(uint8_t *src, uint8_t *dst, int32_t stride, SRARI_H2_UH(res0_r, res1_r, 6); SAT_UH2_UH(res0_r, res1_r, 7); out = (v16u8) __msa_pckev_b((v16i8) res1_r, (v16i8) res0_r); - ST4x4_UB(out, out, 0, 1, 2, 3, dst, stride); + ST_W4(out, 0, 1, 2, 3, dst, stride); } static void avc_chroma_vt_4x8_msa(uint8_t *src, uint8_t *dst, int32_t stride, @@ -446,7 +446,7 @@ static void avc_chroma_vt_4x8_msa(uint8_t *src, uint8_t *dst, int32_t stride, SRARI_H4_UH(res0, res1, res2, res3, 6); SAT_UH4_UH(res0, res1, res2, res3, 7); PCKEV_B2_UB(res1, res0, res3, res2, out0, out1); - ST4x8_UB(out0, out1, dst, stride); + ST_W8(out0, out1, 0, 1, 2, 3, 0, 1, 2, 3, dst, stride); } static void avc_chroma_vt_4w_msa(uint8_t *src, uint8_t *dst, int32_t stride, @@ -480,7 +480,7 @@ static void avc_chroma_vt_8x4_msa(uint8_t *src, uint8_t *dst, int32_t stride, SRARI_H4_UH(res0, res1, res2, res3, 6); SAT_UH4_UH(res0, res1, res2, res3, 7); PCKEV_B2_UB(res1, res0, res3, res2, out0, out1); - ST8x4_UB(out0, out1, dst, stride); + ST_D4(out0, out1, 0, 1, 0, 1, dst, stride); } static void avc_chroma_vt_8x8_msa(uint8_t *src, uint8_t *dst, int32_t stride, @@ -512,7 +512,7 @@ static void avc_chroma_vt_8x8_msa(uint8_t *src, uint8_t *dst, int32_t stride, SAT_UH4_UH(res0, res1, res2, res3, 7); PCKEV_B2_UB(res1, res0, res3, res2, out0, out1); PCKEV_B2_UB(res5, res4, res7, res6, out2, out3); - ST8x8_UB(out0, out1, out2, out3, dst, stride); + ST_D8(out0, out1, out2, out3, 0, 1, 0, 1, 0, 1, 0, 1, dst, stride); } static void avc_chroma_vt_8w_msa(uint8_t *src, uint8_t *dst, int32_t stride, @@ -592,7 +592,7 @@ static void avc_chroma_hv_2x4_msa(uint8_t *src, uint8_t *dst, int32_t stride, res = (v8i16) __msa_pckev_b((v16i8) res_vt0, (v16i8) res_vt0); - ST2x4_UB(res, 0, dst, stride); + ST_H4(res, 0, 1, 2, 3, dst, stride); } static void avc_chroma_hv_2w_msa(uint8_t *src, uint8_t *dst, int32_t stride, @@ -634,7 +634,7 @@ static void avc_chroma_hv_4x2_msa(uint8_t *src, uint8_t *dst, int32_t stride, res_vt0 = __msa_sat_u_h(res_vt0, 7); res = (v4i32) __msa_pckev_b((v16i8) res_vt0, (v16i8) res_vt0); - ST4x2_UB(res, dst, stride); + ST_W2(res, 0, 1, dst, stride); } static void avc_chroma_hv_4x4_msa(uint8_t *src, uint8_t *dst, int32_t stride, @@ -666,7 +666,8 @@ static void avc_chroma_hv_4x4_msa(uint8_t *src, uint8_t *dst, int32_t stride, SRARI_H2_UH(res_vt0, res_vt1, 6); SAT_UH2_UH(res_vt0, res_vt1, 7); PCKEV_B2_SW(res_vt0, res_vt0, res_vt1, res_vt1, res0, res1); - ST4x4_UB(res0, res1, 0, 1, 0, 1, dst, stride); + ST_W2(res0, 0, 1, dst, stride); + ST_W2(res1, 0, 1, dst + 2 * stride, stride); } static void avc_chroma_hv_4x8_msa(uint8_t *src, uint8_t *dst, int32_t stride, @@ -706,7 +707,7 @@ static void avc_chroma_hv_4x8_msa(uint8_t *src, uint8_t *dst, int32_t stride, SRARI_H4_UH(res_vt0, res_vt1, res_vt2, res_vt3, 6); SAT_UH4_UH(res_vt0, res_vt1, res_vt2, res_vt3, 7); PCKEV_B2_UB(res_vt1, res_vt0, res_vt3, res_vt2, res0, res1); - ST4x8_UB(res0, res1, dst, stride); + ST_W8(res0, res1, 0, 1, 2, 3, 0, 1, 2, 3, dst, stride); } static void avc_chroma_hv_4w_msa(uint8_t *src, uint8_t *dst, int32_t stride, @@ -766,7 +767,7 @@ static void avc_chroma_hv_8x4_msa(uint8_t *src, uint8_t *dst, int32_t stride, SRARI_H4_UH(res_vt0, res_vt1, res_vt2, res_vt3, 6); SAT_UH4_UH(res_vt0, res_vt1, res_vt2, res_vt3, 7); PCKEV_B2_UB(res_vt1, res_vt0, res_vt3, res_vt2, out0, out1); - ST8x4_UB(out0, out1, dst, stride); + ST_D4(out0, out1, 0, 1, 0, 1, dst, stride); } static void avc_chroma_hv_8x8_msa(uint8_t *src, uint8_t *dst, int32_t stride, @@ -822,7 +823,7 @@ static void avc_chroma_hv_8x8_msa(uint8_t *src, uint8_t *dst, int32_t stride, SAT_UH4_UH(res_vt4, res_vt5, res_vt6, res_vt7, 7); PCKEV_B2_UB(res_vt1, res_vt0, res_vt3, res_vt2, out0, out1); PCKEV_B2_UB(res_vt5, res_vt4, res_vt7, res_vt6, out2, out3); - ST8x8_UB(out0, out1, out2, out3, dst, stride); + ST_D8(out0, out1, out2, out3, 0, 1, 0, 1, 0, 1, 0, 1, dst, stride); } static void avc_chroma_hv_8w_msa(uint8_t *src, uint8_t *dst, int32_t stride, @@ -918,7 +919,7 @@ static void avc_chroma_hz_and_aver_dst_2x4_msa(uint8_t *src, uint8_t *dst, dst0 = (v16u8) __msa_pckev_b((v16i8) res_r, (v16i8) res_r); dst0 = __msa_aver_u_b(dst0, dst_data); - ST2x4_UB(dst0, 0, dst, stride); + ST_H4(dst0, 0, 1, 2, 3, dst, stride); } static void avc_chroma_hz_and_aver_dst_2w_msa(uint8_t *src, uint8_t *dst, @@ -962,7 +963,7 @@ static void avc_chroma_hz_and_aver_dst_4x2_msa(uint8_t *src, uint8_t *dst, res = __msa_pckev_b((v16i8) res_r, (v16i8) res_r); dst_data = __msa_aver_u_b((v16u8) res, dst_data); - ST4x2_UB(dst_data, dst, stride); + ST_W2(dst_data, 0, 1, dst, stride); } static void avc_chroma_hz_and_aver_dst_4x4_msa(uint8_t *src, uint8_t *dst, @@ -991,7 +992,7 @@ static void avc_chroma_hz_and_aver_dst_4x4_msa(uint8_t *src, uint8_t *dst, SAT_UH2_UH(res0_r, res1_r, 7); out = (v16u8) __msa_pckev_b((v16i8) res1_r, (v16i8) res0_r); out = __msa_aver_u_b(out, dst_data); - ST4x4_UB(out, out, 0, 1, 2, 3, dst, stride); + ST_W4(out, 0, 1, 2, 3, dst, stride); } static void avc_chroma_hz_and_aver_dst_4x8_msa(uint8_t *src, uint8_t *dst, @@ -1023,7 +1024,7 @@ static void avc_chroma_hz_and_aver_dst_4x8_msa(uint8_t *src, uint8_t *dst, SAT_UH4_UH(res0, res1, res2, res3, 7); PCKEV_B2_UB(res1, res0, res3, res2, out0, out1); AVER_UB2_UB(out0, dst0, out1, dst1, out0, out1); - ST4x8_UB(out0, out1, dst, stride); + ST_W8(out0, out1, 0, 1, 2, 3, 0, 1, 2, 3, dst, stride); } static void avc_chroma_hz_and_aver_dst_4w_msa(uint8_t *src, uint8_t *dst, @@ -1066,7 +1067,7 @@ static void avc_chroma_hz_and_aver_dst_8x4_msa(uint8_t *src, uint8_t *dst, SAT_UH4_UH(res0, res1, res2, res3, 7); PCKEV_B2_UB(res1, res0, res3, res2, out0, out1); AVER_UB2_UB(out0, dst0, out1, dst1, dst0, dst1); - ST8x4_UB(dst0, dst1, dst, stride); + ST_D4(dst0, dst1, 0, 1, 0, 1, dst, stride); } static void avc_chroma_hz_and_aver_dst_8x8_msa(uint8_t *src, uint8_t *dst, @@ -1110,7 +1111,7 @@ static void avc_chroma_hz_and_aver_dst_8x8_msa(uint8_t *src, uint8_t *dst, PCKEV_B2_UB(res5, res4, res7, res6, out2, out3); AVER_UB2_UB(out0, dst0, out1, dst1, out0, out1); AVER_UB2_UB(out2, dst2, out3, dst3, out2, out3); - ST8x8_UB(out0, out1, out2, out3, dst, stride); + ST_D8(out0, out1, out2, out3, 0, 1, 0, 1, 0, 1, 0, 1, dst, stride); } static void avc_chroma_hz_and_aver_dst_8w_msa(uint8_t *src, uint8_t *dst, @@ -1200,7 +1201,7 @@ static void avc_chroma_vt_and_aver_dst_2x4_msa(uint8_t *src, uint8_t *dst, res = (v8i16) __msa_pckev_b((v16i8) res_r, (v16i8) res_r); res = (v8i16) __msa_aver_u_b((v16u8) res, dst_data); - ST2x4_UB(res, 0, dst, stride); + ST_H4(res, 0, 1, 2, 3, dst, stride); } static void avc_chroma_vt_and_aver_dst_2w_msa(uint8_t *src, uint8_t *dst, @@ -1243,7 +1244,7 @@ static void avc_chroma_vt_and_aver_dst_4x2_msa(uint8_t *src, uint8_t *dst, res = (v16u8) __msa_pckev_b((v16i8) res_r, (v16i8) res_r); res = __msa_aver_u_b(res, dst_data); - ST4x2_UB(res, dst, stride); + ST_W2(res, 0, 1, dst, stride); } static void avc_chroma_vt_and_aver_dst_4x4_msa(uint8_t *src, uint8_t *dst, @@ -1273,7 +1274,7 @@ static void avc_chroma_vt_and_aver_dst_4x4_msa(uint8_t *src, uint8_t *dst, SAT_UH2_UH(res0_r, res1_r, 7); out = (v16u8) __msa_pckev_b((v16i8) res1_r, (v16i8) res0_r); out = __msa_aver_u_b(out, dst0); - ST4x4_UB(out, out, 0, 1, 2, 3, dst, stride); + ST_W4(out, 0, 1, 2, 3, dst, stride); } static void avc_chroma_vt_and_aver_dst_4x8_msa(uint8_t *src, uint8_t *dst, @@ -1309,7 +1310,7 @@ static void avc_chroma_vt_and_aver_dst_4x8_msa(uint8_t *src, uint8_t *dst, SAT_UH4_UH(res0, res1, res2, res3, 7); PCKEV_B2_UB(res1, res0, res3, res2, out0, out1); AVER_UB2_UB(out0, dst0, out1, dst1, out0, out1); - ST4x8_UB(out0, out1, dst, stride); + ST_W8(out0, out1, 0, 1, 2, 3, 0, 1, 2, 3, dst, stride); } static void avc_chroma_vt_and_aver_dst_4w_msa(uint8_t *src, uint8_t *dst, @@ -1351,7 +1352,7 @@ static void avc_chroma_vt_and_aver_dst_8x4_msa(uint8_t *src, uint8_t *dst, SAT_UH4_UH(res0, res1, res2, res3, 7); PCKEV_B2_UB(res1, res0, res3, res2, out0, out1); AVER_UB2_UB(out0, dst0, out1, dst1, out0, out1); - ST8x4_UB(out0, out1, dst, stride); + ST_D4(out0, out1, 0, 1, 0, 1, dst, stride); } static void avc_chroma_vt_and_aver_dst_8x8_msa(uint8_t *src, uint8_t *dst, @@ -1394,7 +1395,7 @@ static void avc_chroma_vt_and_aver_dst_8x8_msa(uint8_t *src, uint8_t *dst, PCKEV_B2_UB(res5, res4, res7, res6, out2, out3); AVER_UB2_UB(out0, dst0, out1, dst1, out0, out1); AVER_UB2_UB(out2, dst2, out3, dst3, out2, out3); - ST8x8_UB(out0, out1, out2, out3, dst, stride); + ST_D8(out0, out1, out2, out3, 0, 1, 0, 1, 0, 1, 0, 1, dst, stride); } static void avc_chroma_vt_and_aver_dst_8w_msa(uint8_t *src, uint8_t *dst, @@ -1492,7 +1493,7 @@ static void avc_chroma_hv_and_aver_dst_2x4_msa(uint8_t *src, uint8_t *dst, res = __msa_pckev_b((v16i8) res_vt0, (v16i8) res_vt0); dst0 = __msa_aver_u_b((v16u8) res, dst0); - ST2x4_UB(dst0, 0, dst, stride); + ST_H4(dst0, 0, 1, 2, 3, dst, stride); } static void avc_chroma_hv_and_aver_dst_2w_msa(uint8_t *src, uint8_t *dst, @@ -1545,7 +1546,7 @@ static void avc_chroma_hv_and_aver_dst_4x2_msa(uint8_t *src, uint8_t *dst, dst0 = (v16u8) __msa_pckev_b((v16i8) res_vt0, (v16i8) res_vt0); dst0 = __msa_aver_u_b(dst0, dst_data); - ST4x2_UB(dst0, dst, stride); + ST_W2(dst0, 0, 1, dst, stride); } static void avc_chroma_hv_and_aver_dst_4x4_msa(uint8_t *src, uint8_t *dst, @@ -1584,7 +1585,7 @@ static void avc_chroma_hv_and_aver_dst_4x4_msa(uint8_t *src, uint8_t *dst, SAT_UH2_UH(res_vt0, res_vt1, 7); out = (v16u8) __msa_pckev_b((v16i8) res_vt1, (v16i8) res_vt0); out = __msa_aver_u_b(out, dst_data); - ST4x4_UB(out, out, 0, 1, 2, 3, dst, stride); + ST_W4(out, 0, 1, 2, 3, dst, stride); } static void avc_chroma_hv_and_aver_dst_4x8_msa(uint8_t *src, uint8_t *dst, @@ -1633,7 +1634,7 @@ static void avc_chroma_hv_and_aver_dst_4x8_msa(uint8_t *src, uint8_t *dst, SAT_UH4_UH(res_vt0, res_vt1, res_vt2, res_vt3, 7); PCKEV_B2_UB(res_vt1, res_vt0, res_vt3, res_vt2, res0, res1); AVER_UB2_UB(res0, dst0, res1, dst1, res0, res1); - ST4x8_UB(res0, res1, dst, stride); + ST_W8(res0, res1, 0, 1, 2, 3, 0, 1, 2, 3, dst, stride); } static void avc_chroma_hv_and_aver_dst_4w_msa(uint8_t *src, uint8_t *dst, @@ -1701,7 +1702,7 @@ static void avc_chroma_hv_and_aver_dst_8x4_msa(uint8_t *src, uint8_t *dst, SAT_UH4_UH(res_vt0, res_vt1, res_vt2, res_vt3, 7); PCKEV_B2_UB(res_vt1, res_vt0, res_vt3, res_vt2, out0, out1); AVER_UB2_UB(out0, dst0, out1, dst1, out0, out1); - ST8x4_UB(out0, out1, dst, stride); + ST_D4(out0, out1, 0, 1, 0, 1, dst, stride); } static void avc_chroma_hv_and_aver_dst_8x8_msa(uint8_t *src, uint8_t *dst, @@ -1770,7 +1771,7 @@ static void avc_chroma_hv_and_aver_dst_8x8_msa(uint8_t *src, uint8_t *dst, PCKEV_B2_UB(res_vt5, res_vt4, res_vt7, res_vt6, out2, out3); AVER_UB2_UB(out0, dst0, out1, dst1, out0, out1); AVER_UB2_UB(out2, dst2, out3, dst3, out2, out3); - ST8x8_UB(out0, out1, out2, out3, dst, stride); + ST_D8(out0, out1, out2, out3, 0, 1, 0, 1, 0, 1, 0, 1, dst, stride); } static void avc_chroma_hv_and_aver_dst_8w_msa(uint8_t *src, uint8_t *dst, @@ -1848,21 +1849,21 @@ static void avg_width4_msa(uint8_t *src, uint8_t *dst, int32_t stride, LW4(dst + 4 * stride, stride, tp0, tp1, tp2, tp3); INSERT_W4_UB(tp0, tp1, tp2, tp3, dst1); AVER_UB2_UB(src0, dst0, src1, dst1, dst0, dst1); - ST4x8_UB(dst0, dst1, dst, stride); + ST_W8(dst0, dst1, 0, 1, 2, 3, 0, 1, 2, 3, dst, stride); } else if (4 == height) { LW4(src, stride, tp0, tp1, tp2, tp3); INSERT_W4_UB(tp0, tp1, tp2, tp3, src0); LW4(dst, stride, tp0, tp1, tp2, tp3); INSERT_W4_UB(tp0, tp1, tp2, tp3, dst0); dst0 = __msa_aver_u_b(src0, dst0); - ST4x4_UB(dst0, dst0, 0, 1, 2, 3, dst, stride); + ST_W4(dst0, 0, 1, 2, 3, dst, stride); } else if (2 == height) { LW2(src, stride, tp0, tp1); INSERT_W2_UB(tp0, tp1, src0); LW2(dst, stride, tp0, tp1); INSERT_W2_UB(tp0, tp1, dst0); dst0 = __msa_aver_u_b(src0, dst0); - ST4x2_UB(dst0, dst, stride); + ST_W2(dst0, 0, 1, dst, stride); } } @@ -1889,7 +1890,7 @@ static void avg_width8_msa(uint8_t *src, uint8_t *dst, int32_t stride, INSERT_D2_UB(tp6, tp7, dst3); AVER_UB4_UB(src0, dst0, src1, dst1, src2, dst2, src3, dst3, dst0, dst1, dst2, dst3); - ST8x8_UB(dst0, dst1, dst2, dst3, dst, stride); + ST_D8(dst0, dst1, dst2, dst3, 0, 1, 0, 1, 0, 1, 0, 1, dst, stride); } else if (4 == height) { LD4(src, stride, tp0, tp1, tp2, tp3); INSERT_D2_UB(tp0, tp1, src0); @@ -1898,7 +1899,7 @@ static void avg_width8_msa(uint8_t *src, uint8_t *dst, int32_t stride, INSERT_D2_UB(tp0, tp1, dst0); INSERT_D2_UB(tp2, tp3, dst1); AVER_UB2_UB(src0, dst0, src1, dst1, dst0, dst1); - ST8x4_UB(dst0, dst1, dst, stride); + ST_D4(dst0, dst1, 0, 1, 0, 1, dst, stride); } } diff --git a/libavcodec/mips/h264dsp_init_mips.c b/libavcodec/mips/h264dsp_init_mips.c index 1fe7f8468..dc08a2580 100644 --- a/libavcodec/mips/h264dsp_init_mips.c +++ b/libavcodec/mips/h264dsp_init_mips.c @@ -138,10 +138,10 @@ static av_cold void h264dsp_init_mmi(H264DSPContext * c, const int bit_depth, av_cold void ff_h264dsp_init_mips(H264DSPContext *c, const int bit_depth, const int chroma_format_idc) { -#if HAVE_MSA - h264dsp_init_msa(c, bit_depth, chroma_format_idc); -#endif // #if HAVE_MSA #if HAVE_MMI h264dsp_init_mmi(c, bit_depth, chroma_format_idc); #endif /* HAVE_MMI */ +#if HAVE_MSA + h264dsp_init_msa(c, bit_depth, chroma_format_idc); +#endif // #if HAVE_MSA } diff --git a/libavcodec/mips/h264dsp_mmi.c b/libavcodec/mips/h264dsp_mmi.c index ac6fa996a..ac65a20db 100644 --- a/libavcodec/mips/h264dsp_mmi.c +++ b/libavcodec/mips/h264dsp_mmi.c @@ -31,7 +31,6 @@ void ff_h264_add_pixels4_8_mmi(uint8_t *dst, int16_t *src, int stride) { double ftmp[9]; DECLARE_VAR_LOW32; - DECLARE_VAR_ALL64; __asm__ volatile ( "xor %[ftmp0], %[ftmp0], %[ftmp0] \n\t" @@ -59,12 +58,16 @@ void ff_h264_add_pixels4_8_mmi(uint8_t *dst, int16_t *src, int stride) MMI_SWC1(%[ftmp2], %[dst1], 0x00) MMI_SWC1(%[ftmp3], %[dst2], 0x00) MMI_SWC1(%[ftmp4], %[dst3], 0x00) + + /* memset(src, 0, 32); */ + "xor %[ftmp0], %[ftmp0], %[ftmp0] \n\t" + "gssqc1 %[ftmp0], %[ftmp0], 0x00(%[src]) \n\t" + "gssqc1 %[ftmp0], %[ftmp0], 0x10(%[src]) \n\t" : [ftmp0]"=&f"(ftmp[0]), [ftmp1]"=&f"(ftmp[1]), [ftmp2]"=&f"(ftmp[2]), [ftmp3]"=&f"(ftmp[3]), [ftmp4]"=&f"(ftmp[4]), [ftmp5]"=&f"(ftmp[5]), [ftmp6]"=&f"(ftmp[6]), [ftmp7]"=&f"(ftmp[7]), RESTRICT_ASM_LOW32 - RESTRICT_ASM_ALL64 [ftmp8]"=&f"(ftmp[8]) : [dst0]"r"(dst), [dst1]"r"(dst+stride), [dst2]"r"(dst+2*stride), [dst3]"r"(dst+3*stride), @@ -72,7 +75,6 @@ void ff_h264_add_pixels4_8_mmi(uint8_t *dst, int16_t *src, int stride) : "memory" ); - memset(src, 0, 32); } void ff_h264_idct_add_8_mmi(uint8_t *dst, int16_t *block, int stride) @@ -80,7 +82,6 @@ void ff_h264_idct_add_8_mmi(uint8_t *dst, int16_t *block, int stride) double ftmp[12]; uint64_t tmp[1]; DECLARE_VAR_LOW32; - DECLARE_VAR_ALL64; DECLARE_VAR_ADDRT; __asm__ volatile ( @@ -152,6 +153,11 @@ void ff_h264_idct_add_8_mmi(uint8_t *dst, int16_t *block, int stride) MMI_SWC1(%[ftmp2], %[dst], 0x00) "packushb %[ftmp0], %[ftmp0], %[ftmp7] \n\t" MMI_SWXC1(%[ftmp0], %[dst], %[stride], 0x00) + + /* memset(block, 0, 32) */ + "xor %[ftmp0], %[ftmp0], %[ftmp0] \n\t" + "gssqc1 %[ftmp0], %[ftmp0], 0x00(%[block]) \n\t" + "gssqc1 %[ftmp0], %[ftmp0], 0x10(%[block]) \n\t" : [ftmp0]"=&f"(ftmp[0]), [ftmp1]"=&f"(ftmp[1]), [ftmp2]"=&f"(ftmp[2]), [ftmp3]"=&f"(ftmp[3]), [ftmp4]"=&f"(ftmp[4]), [ftmp5]"=&f"(ftmp[5]), @@ -159,7 +165,6 @@ void ff_h264_idct_add_8_mmi(uint8_t *dst, int16_t *block, int stride) [ftmp8]"=&f"(ftmp[8]), [ftmp9]"=&f"(ftmp[9]), [ftmp10]"=&f"(ftmp[10]), [ftmp11]"=&f"(ftmp[11]), RESTRICT_ASM_LOW32 - RESTRICT_ASM_ALL64 RESTRICT_ASM_ADDRT [tmp0]"=&r"(tmp[0]) : [dst]"r"(dst), [block]"r"(block), @@ -167,7 +172,6 @@ void ff_h264_idct_add_8_mmi(uint8_t *dst, int16_t *block, int stride) : "memory" ); - memset(block, 0, 32); } void ff_h264_idct8_add_8_mmi(uint8_t *dst, int16_t *block, int stride) @@ -176,7 +180,6 @@ void ff_h264_idct8_add_8_mmi(uint8_t *dst, int16_t *block, int stride) uint64_t tmp[7]; mips_reg addr[1]; DECLARE_VAR_LOW32; - DECLARE_VAR_ALL64; DECLARE_VAR_ADDRT; __asm__ volatile ( @@ -617,6 +620,17 @@ void ff_h264_idct8_add_8_mmi(uint8_t *dst, int16_t *block, int stride) MMI_SWC1(%[ftmp6], %[addr0], 0x00) MMI_SWXC1(%[ftmp7], %[addr0], %[stride], 0x00) PTR_ADDIU "$29, $29, 0x20 \n\t" + + /* memset(block, 0, 128) */ + "xor %[ftmp0], %[ftmp0], %[ftmp0] \n\t" + "gssqc1 %[ftmp0], %[ftmp0], 0x00(%[block]) \n\t" + "gssqc1 %[ftmp0], %[ftmp0], 0x10(%[block]) \n\t" + "gssqc1 %[ftmp0], %[ftmp0], 0x20(%[block]) \n\t" + "gssqc1 %[ftmp0], %[ftmp0], 0x30(%[block]) \n\t" + "gssqc1 %[ftmp0], %[ftmp0], 0x40(%[block]) \n\t" + "gssqc1 %[ftmp0], %[ftmp0], 0x50(%[block]) \n\t" + "gssqc1 %[ftmp0], %[ftmp0], 0x60(%[block]) \n\t" + "gssqc1 %[ftmp0], %[ftmp0], 0x70(%[block]) \n\t" : [ftmp0]"=&f"(ftmp[0]), [ftmp1]"=&f"(ftmp[1]), [ftmp2]"=&f"(ftmp[2]), [ftmp3]"=&f"(ftmp[3]), [ftmp4]"=&f"(ftmp[4]), [ftmp5]"=&f"(ftmp[5]), @@ -630,7 +644,6 @@ void ff_h264_idct8_add_8_mmi(uint8_t *dst, int16_t *block, int stride) [tmp4]"=&r"(tmp[4]), [tmp5]"=&r"(tmp[5]), [tmp6]"=&r"(tmp[6]), RESTRICT_ASM_LOW32 - RESTRICT_ASM_ALL64 RESTRICT_ASM_ADDRT [addr0]"=&r"(addr[0]) : [dst]"r"(dst), [block]"r"(block), @@ -638,7 +651,6 @@ void ff_h264_idct8_add_8_mmi(uint8_t *dst, int16_t *block, int stride) : "$29","memory" ); - memset(block, 0, 128); } void ff_h264_idct_dc_add_8_mmi(uint8_t *dst, int16_t *block, int stride) diff --git a/libavcodec/mips/h264dsp_msa.c b/libavcodec/mips/h264dsp_msa.c index e50f5ca0a..89fe39946 100644 --- a/libavcodec/mips/h264dsp_msa.c +++ b/libavcodec/mips/h264dsp_msa.c @@ -45,7 +45,7 @@ static void avc_wgt_4x2_msa(uint8_t *data, int32_t stride, tmp0 = __msa_srlr_h(tmp0, denom); tmp0 = (v8i16) __msa_sat_u_h((v8u16) tmp0, 7); src0 = (v16u8) __msa_pckev_b((v16i8) tmp0, (v16i8) tmp0); - ST4x2_UB(src0, data, stride); + ST_W2(src0, 0, 1, data, stride); } static void avc_wgt_4x4_msa(uint8_t *data, int32_t stride, int32_t log2_denom, @@ -71,7 +71,7 @@ static void avc_wgt_4x4_msa(uint8_t *data, int32_t stride, int32_t log2_denom, tmp1 = __msa_srlr_h(tmp1, denom); SAT_UH2_SH(tmp0, tmp1, 7); src0 = (v16u8) __msa_pckev_b((v16i8) tmp1, (v16i8) tmp0); - ST4x4_UB(src0, src0, 0, 1, 2, 3, data, stride); + ST_W4(src0, 0, 1, 2, 3, data, stride); } static void avc_wgt_4x8_msa(uint8_t *data, int32_t stride, int32_t log2_denom, @@ -102,7 +102,7 @@ static void avc_wgt_4x8_msa(uint8_t *data, int32_t stride, int32_t log2_denom, SRLR_H4_SH(tmp0, tmp1, tmp2, tmp3, denom); SAT_UH4_SH(tmp0, tmp1, tmp2, tmp3, 7); PCKEV_B2_UB(tmp1, tmp0, tmp3, tmp2, src0, src1); - ST4x8_UB(src0, src1, data, stride); + ST_W8(src0, src1, 0, 1, 2, 3, 0, 1, 2, 3, data, stride); } static void avc_wgt_8x4_msa(uint8_t *data, int32_t stride, int32_t log2_denom, @@ -133,7 +133,7 @@ static void avc_wgt_8x4_msa(uint8_t *data, int32_t stride, int32_t log2_denom, SRLR_H4_SH(tmp0, tmp1, tmp2, tmp3, denom); SAT_UH4_SH(tmp0, tmp1, tmp2, tmp3, 7); PCKEV_B2_UB(tmp1, tmp0, tmp3, tmp2, src0, src1); - ST8x4_UB(src0, src1, data, stride); + ST_D4(src0, src1, 0, 1, 0, 1, data, stride); } static void avc_wgt_8x8_msa(uint8_t *data, int32_t stride, int32_t log2_denom, @@ -175,7 +175,7 @@ static void avc_wgt_8x8_msa(uint8_t *data, int32_t stride, int32_t log2_denom, SAT_UH8_SH(tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7, 7); PCKEV_B4_UB(tmp1, tmp0, tmp3, tmp2, tmp5, tmp4, tmp7, tmp6, src0, src1, src2, src3); - ST8x8_UB(src0, src1, src2, src3, data, stride); + ST_D8(src0, src1, src2, src3, 0, 1, 0, 1, 0, 1, 0, 1, data, stride); } static void avc_wgt_8x16_msa(uint8_t *data, int32_t stride, int32_t log2_denom, @@ -218,7 +218,7 @@ static void avc_wgt_8x16_msa(uint8_t *data, int32_t stride, int32_t log2_denom, SAT_UH8_SH(tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7, 7); PCKEV_B4_UB(tmp1, tmp0, tmp3, tmp2, tmp5, tmp4, tmp7, tmp6, src0, src1, src2, src3); - ST8x8_UB(src0, src1, src2, src3, data, stride); + ST_D8(src0, src1, src2, src3, 0, 1, 0, 1, 0, 1, 0, 1, data, stride); data += 8 * stride; } } @@ -253,7 +253,7 @@ static void avc_biwgt_4x2_msa(uint8_t *src, uint8_t *dst, int32_t stride, tmp0 = __msa_maxi_s_h(tmp0, 0); tmp0 = __msa_min_s_h(max255, tmp0); dst0 = (v16u8) __msa_pckev_b((v16i8) tmp0, (v16i8) tmp0); - ST4x2_UB(dst0, dst, stride); + ST_W2(dst0, 0, 1, dst, stride); } static void avc_biwgt_4x4_msa(uint8_t *src, uint8_t *dst, int32_t stride, @@ -287,7 +287,7 @@ static void avc_biwgt_4x4_msa(uint8_t *src, uint8_t *dst, int32_t stride, tmp1 >>= denom; CLIP_SH2_0_255(tmp0, tmp1); dst0 = (v16u8) __msa_pckev_b((v16i8) tmp1, (v16i8) tmp0); - ST4x4_UB(dst0, dst0, 0, 1, 2, 3, dst, stride); + ST_W4(dst0, 0, 1, 2, 3, dst, stride); } static void avc_biwgt_4x8_msa(uint8_t *src, uint8_t *dst, int32_t stride, @@ -327,7 +327,7 @@ static void avc_biwgt_4x8_msa(uint8_t *src, uint8_t *dst, int32_t stride, SRA_4V(tmp0, tmp1, tmp2, tmp3, denom); CLIP_SH4_0_255(tmp0, tmp1, tmp2, tmp3); PCKEV_B2_UB(tmp1, tmp0, tmp3, tmp2, dst0, dst1); - ST4x8_UB(dst0, dst1, dst, stride); + ST_W8(dst0, dst1, 0, 1, 2, 3, 0, 1, 2, 3, dst, stride); } static void avc_biwgt_8x4_msa(uint8_t *src, uint8_t *dst, int32_t stride, @@ -365,7 +365,7 @@ static void avc_biwgt_8x4_msa(uint8_t *src, uint8_t *dst, int32_t stride, SRA_4V(tmp0, tmp1, tmp2, tmp3, denom); CLIP_SH4_0_255(tmp0, tmp1, tmp2, tmp3); PCKEV_B2_UB(tmp1, tmp0, tmp3, tmp2, dst0, dst1); - ST8x4_UB(dst0, dst1, dst, stride); + ST_D4(dst0, dst1, 0, 1, 0, 1, dst, stride); } static void avc_biwgt_8x8_msa(uint8_t *src, uint8_t *dst, int32_t stride, @@ -417,7 +417,7 @@ static void avc_biwgt_8x8_msa(uint8_t *src, uint8_t *dst, int32_t stride, CLIP_SH4_0_255(tmp4, tmp5, tmp6, tmp7); PCKEV_B2_UB(tmp1, tmp0, tmp3, tmp2, dst0, dst1); PCKEV_B2_UB(tmp5, tmp4, tmp7, tmp6, dst2, dst3); - ST8x8_UB(dst0, dst1, dst2, dst3, dst, stride); + ST_D8(dst0, dst1, dst2, dst3, 0, 1, 0, 1, 0, 1, 0, 1, dst, stride); } static void avc_biwgt_8x16_msa(uint8_t *src, uint8_t *dst, int32_t stride, @@ -479,7 +479,7 @@ static void avc_biwgt_8x16_msa(uint8_t *src, uint8_t *dst, int32_t stride, CLIP_SH4_0_255(temp4, temp5, temp6, temp7); PCKEV_B4_UB(temp1, temp0, temp3, temp2, temp5, temp4, temp7, temp6, dst0, dst1, dst2, dst3); - ST8x8_UB(dst0, dst1, dst2, dst3, dst, stride); + ST_D8(dst0, dst1, dst2, dst3, 0, 1, 0, 1, 0, 1, 0, 1, dst, stride); dst += 8 * stride; } } @@ -955,18 +955,18 @@ static void avc_loopfilter_luma_intra_edge_ver_msa(uint8_t *data, ILVRL_H2_SH(tp3, tp2, tmp6, tmp7); src = data - 3; - ST4x4_UB(tmp3, tmp3, 0, 1, 2, 3, src, img_width); - ST2x4_UB(tmp2, 0, src + 4, img_width); + ST_W4(tmp3, 0, 1, 2, 3, src, img_width); + ST_H4(tmp2, 0, 1, 2, 3, src + 4, img_width); src += 4 * img_width; - ST4x4_UB(tmp4, tmp4, 0, 1, 2, 3, src, img_width); - ST2x4_UB(tmp2, 4, src + 4, img_width); + ST_W4(tmp4, 0, 1, 2, 3, src, img_width); + ST_H4(tmp2, 4, 5, 6, 7, src + 4, img_width); src += 4 * img_width; - ST4x4_UB(tmp6, tmp6, 0, 1, 2, 3, src, img_width); - ST2x4_UB(tmp5, 0, src + 4, img_width); + ST_W4(tmp6, 0, 1, 2, 3, src, img_width); + ST_H4(tmp5, 0, 1, 2, 3, src + 4, img_width); src += 4 * img_width; - ST4x4_UB(tmp7, tmp7, 0, 1, 2, 3, src, img_width); - ST2x4_UB(tmp5, 4, src + 4, img_width); + ST_W4(tmp7, 0, 1, 2, 3, src, img_width); + ST_H4(tmp5, 4, 5, 6, 7, src + 4, img_width); } } } @@ -1274,9 +1274,9 @@ static void avc_loopfilter_cb_or_cr_intra_edge_ver_msa(uint8_t *data_cb_or_cr, tmp1 = (v8i16) __msa_ilvr_b((v16i8) q0_or_p0_org, (v16i8) p0_or_q0_org); data_cb_or_cr -= 1; - ST2x4_UB(tmp1, 0, data_cb_or_cr, img_width); + ST_H4(tmp1, 0, 1, 2, 3, data_cb_or_cr, img_width); data_cb_or_cr += 4 * img_width; - ST2x4_UB(tmp1, 4, data_cb_or_cr, img_width); + ST_H4(tmp1, 4, 5, 6, 7, data_cb_or_cr, img_width); } } @@ -2110,9 +2110,9 @@ static void avc_loopfilter_cb_or_cr_inter_edge_ver_msa(uint8_t *data, q0_org = __msa_bmnz_v(q0_org, q0, is_less_than); tmp1 = (v8i16) __msa_ilvr_b((v16i8) q0_org, (v16i8) p0_org); src = data - 1; - ST2x4_UB(tmp1, 0, src, img_width); + ST_H4(tmp1, 0, 1, 2, 3, src, img_width); src += 4 * img_width; - ST2x4_UB(tmp1, 4, src, img_width); + ST_H4(tmp1, 4, 5, 6, 7, src, img_width); } } } @@ -2136,7 +2136,7 @@ static void avc_h_loop_filter_chroma422_msa(uint8_t *src, int32_t stride, } AVC_LPF_H_CHROMA_422(src, stride, tc_val, alpha, beta, res); - ST2x4_UB(res, 0, (src - 1), stride); + ST_H4(res, 0, 1, 2, 3, (src - 1), stride); src += (4 * stride); } } diff --git a/libavcodec/mips/h264idct_msa.c b/libavcodec/mips/h264idct_msa.c index 1e1a5c8cb..7851bfdf4 100644 --- a/libavcodec/mips/h264idct_msa.c +++ b/libavcodec/mips/h264idct_msa.c @@ -237,9 +237,7 @@ static void avc_idct8_addblk_msa(uint8_t *dst, int16_t *src, int32_t dst_stride) CLIP_SH4_0_255(res4, res5, res6, res7); PCKEV_B4_SB(res1, res0, res3, res2, res5, res4, res7, res6, dst0, dst1, dst2, dst3); - ST8x4_UB(dst0, dst1, dst, dst_stride); - dst += (4 * dst_stride); - ST8x4_UB(dst2, dst3, dst, dst_stride); + ST_D8(dst0, dst1, dst2, dst3, 0, 1, 0, 1, 0, 1, 0, 1, dst, dst_stride) } static void avc_idct8_dc_addblk_msa(uint8_t *dst, int16_t *src, @@ -269,9 +267,7 @@ static void avc_idct8_dc_addblk_msa(uint8_t *dst, int16_t *src, CLIP_SH4_0_255(dst4_r, dst5_r, dst6_r, dst7_r); PCKEV_B4_SB(dst1_r, dst0_r, dst3_r, dst2_r, dst5_r, dst4_r, dst7_r, dst6_r, dst0, dst1, dst2, dst3); - ST8x4_UB(dst0, dst1, dst, dst_stride); - dst += (4 * dst_stride); - ST8x4_UB(dst2, dst3, dst, dst_stride); + ST_D8(dst0, dst1, dst2, dst3, 0, 1, 0, 1, 0, 1, 0, 1, dst, dst_stride) } void ff_h264_idct_add_msa(uint8_t *dst, int16_t *src, int32_t dst_stride) @@ -340,7 +336,7 @@ void ff_h264_idct4x4_addblk_dc_msa(uint8_t *dst, int16_t *src, ADD2(pred_r, input_dc, pred_l, input_dc, pred_r, pred_l); CLIP_SH2_0_255(pred_r, pred_l); out = __msa_pckev_b((v16i8) pred_l, (v16i8) pred_r); - ST4x4_UB(out, out, 0, 1, 2, 3, dst, dst_stride); + ST_W4(out, 0, 1, 2, 3, dst, dst_stride); } void ff_h264_idct8_dc_addblk_msa(uint8_t *dst, int16_t *src, diff --git a/libavcodec/mips/h264pred_init_mips.c b/libavcodec/mips/h264pred_init_mips.c index c33d8f7cd..63637b873 100644 --- a/libavcodec/mips/h264pred_init_mips.c +++ b/libavcodec/mips/h264pred_init_mips.c @@ -146,10 +146,10 @@ av_cold void ff_h264_pred_init_mips(H264PredContext *h, int codec_id, int bit_depth, const int chroma_format_idc) { -#if HAVE_MSA - h264_pred_init_msa(h, codec_id, bit_depth, chroma_format_idc); -#endif // #if HAVE_MSA #if HAVE_MMI h264_pred_init_mmi(h, codec_id, bit_depth, chroma_format_idc); #endif /* HAVE_MMI */ +#if HAVE_MSA + h264_pred_init_msa(h, codec_id, bit_depth, chroma_format_idc); +#endif // #if HAVE_MSA } diff --git a/libavcodec/mips/h264qpel_init_mips.c b/libavcodec/mips/h264qpel_init_mips.c index 92219f887..33bae3093 100644 --- a/libavcodec/mips/h264qpel_init_mips.c +++ b/libavcodec/mips/h264qpel_init_mips.c @@ -240,10 +240,10 @@ static av_cold void h264qpel_init_mmi(H264QpelContext *c, int bit_depth) av_cold void ff_h264qpel_init_mips(H264QpelContext *c, int bit_depth) { -#if HAVE_MSA - h264qpel_init_msa(c, bit_depth); -#endif // #if HAVE_MSA #if HAVE_MMI h264qpel_init_mmi(c, bit_depth); #endif /* HAVE_MMI */ +#if HAVE_MSA + h264qpel_init_msa(c, bit_depth); +#endif // #if HAVE_MSA } diff --git a/libavcodec/mips/h264qpel_msa.c b/libavcodec/mips/h264qpel_msa.c index 9c779bdd4..df7e3e2a3 100644 --- a/libavcodec/mips/h264qpel_msa.c +++ b/libavcodec/mips/h264qpel_msa.c @@ -149,7 +149,7 @@ static void avc_luma_hv_qrt_4x4_msa(const uint8_t *src_x, const uint8_t *src_y, SAT_SH2_SH(out0, out1, 7); out = PCKEV_XORI128_UB(out0, out1); - ST4x4_UB(out, out, 0, 1, 2, 3, dst, stride); + ST_W4(out, 0, 1, 2, 3, dst, stride); } static void avc_luma_hv_qrt_8x8_msa(const uint8_t *src_x, const uint8_t *src_y, @@ -220,7 +220,7 @@ static void avc_luma_hv_qrt_8x8_msa(const uint8_t *src_x, const uint8_t *src_y, SAT_SH4_SH(tmp0, tmp1, tmp2, tmp3, 7); out0 = PCKEV_XORI128_UB(tmp0, tmp1); out1 = PCKEV_XORI128_UB(tmp2, tmp3); - ST8x4_UB(out0, out1, dst, stride); + ST_D4(out0, out1, 0, 1, 0, 1, dst, stride); dst += (4 * stride); LD_SB4(src_y, stride, src_vt9, src_vt10, src_vt11, src_vt12); @@ -256,8 +256,7 @@ static void avc_luma_hv_qrt_8x8_msa(const uint8_t *src_x, const uint8_t *src_y, SAT_SH4_SH(tmp0, tmp1, tmp2, tmp3, 7); out0 = PCKEV_XORI128_UB(tmp0, tmp1); out1 = PCKEV_XORI128_UB(tmp2, tmp3); - ST8x4_UB(out0, out1, dst, stride); - dst += (4 * stride); + ST_D4(out0, out1, 0, 1, 0, 1, dst, stride); } static void avc_luma_hv_qrt_16x16_msa(const uint8_t *src_x, @@ -337,7 +336,7 @@ static void avc_luma_hv_qrt_16x16_msa(const uint8_t *src_x, SAT_SH4_SH(out0, out1, out2, out3, 7); tmp0 = PCKEV_XORI128_UB(out0, out1); tmp1 = PCKEV_XORI128_UB(out2, out3); - ST8x4_UB(tmp0, tmp1, dst, stride); + ST_D4(tmp0, tmp1, 0, 1, 0, 1, dst, stride); dst += (4 * stride); src_vt0 = src_vt4; @@ -419,7 +418,7 @@ static void avc_luma_hv_qrt_and_aver_dst_4x4_msa(const uint8_t *src_x, res = PCKEV_XORI128_UB(res0, res1); dst0 = __msa_aver_u_b(res, dst0); - ST4x4_UB(dst0, dst0, 0, 1, 2, 3, dst, stride); + ST_W4(dst0, 0, 1, 2, 3, dst, stride); } static void avc_luma_hv_qrt_and_aver_dst_8x8_msa(const uint8_t *src_x, @@ -498,7 +497,7 @@ static void avc_luma_hv_qrt_and_aver_dst_8x8_msa(const uint8_t *src_x, out0 = PCKEV_XORI128_UB(tmp0, tmp1); out1 = PCKEV_XORI128_UB(tmp2, tmp3); AVER_UB2_UB(out0, dst0, out1, dst1, dst0, dst1); - ST8x4_UB(dst0, dst1, dst, stride); + ST_D4(dst0, dst1, 0, 1, 0, 1, dst, stride); dst += (4 * stride); LD_SB4(src_y, stride, src_vt9, src_vt10, src_vt11, src_vt12); @@ -539,8 +538,7 @@ static void avc_luma_hv_qrt_and_aver_dst_8x8_msa(const uint8_t *src_x, out0 = PCKEV_XORI128_UB(tmp0, tmp1); out1 = PCKEV_XORI128_UB(tmp2, tmp3); AVER_UB2_UB(out0, dst0, out1, dst1, dst0, dst1); - ST8x4_UB(dst0, dst1, dst, stride); - dst += (4 * stride); + ST_D4(dst0, dst1, 0, 1, 0, 1, dst, stride); } static void avc_luma_hv_qrt_and_aver_dst_16x16_msa(const uint8_t *src_x, @@ -627,7 +625,7 @@ static void avc_luma_hv_qrt_and_aver_dst_16x16_msa(const uint8_t *src_x, tmp0 = PCKEV_XORI128_UB(out0, out1); tmp1 = PCKEV_XORI128_UB(out2, out3); AVER_UB2_UB(tmp0, dst0, tmp1, dst1, dst0, dst1); - ST8x4_UB(dst0, dst1, dst, stride); + ST_D4(dst0, dst1, 0, 1, 0, 1, dst, stride); dst += (4 * stride); src_vt0 = src_vt4; @@ -723,7 +721,7 @@ void ff_avg_h264_qpel8_mc00_msa(uint8_t *dst, const uint8_t *src, AVER_UB4_UB(src0, dst0, src1, dst1, src2, dst2, src3, dst3, dst0, dst1, dst2, dst3); - ST8x8_UB(dst0, dst1, dst2, dst3, dst, stride); + ST_D8(dst0, dst1, dst2, dst3, 0, 1, 0, 1, 0, 1, 0, 1, dst, stride); } void ff_avg_h264_qpel4_mc00_msa(uint8_t *dst, const uint8_t *src, @@ -739,7 +737,7 @@ void ff_avg_h264_qpel4_mc00_msa(uint8_t *dst, const uint8_t *src, dst0 = __msa_aver_u_b(src0, dst0); - ST4x4_UB(dst0, dst0, 0, 1, 2, 3, dst, stride); + ST_W4(dst0, 0, 1, 2, 3, dst, stride); } void ff_put_h264_qpel16_mc10_msa(uint8_t *dst, const uint8_t *src, @@ -930,7 +928,7 @@ void ff_put_h264_qpel8_mc10_msa(uint8_t *dst, const uint8_t *src, tmp2 = __msa_aver_s_b(tmp2, src4); tmp3 = __msa_aver_s_b(tmp3, src5); XORI_B4_128_SB(tmp0, tmp1, tmp2, tmp3); - ST8x8_UB(tmp0, tmp1, tmp2, tmp3, dst, stride); + ST_D8(tmp0, tmp1, tmp2, tmp3, 0, 1, 0, 1, 0, 1, 0, 1, dst, stride); } void ff_put_h264_qpel8_mc30_msa(uint8_t *dst, const uint8_t *src, @@ -985,7 +983,7 @@ void ff_put_h264_qpel8_mc30_msa(uint8_t *dst, const uint8_t *src, tmp2 = __msa_aver_s_b(tmp2, src4); tmp3 = __msa_aver_s_b(tmp3, src5); XORI_B4_128_SB(tmp0, tmp1, tmp2, tmp3); - ST8x8_UB(tmp0, tmp1, tmp2, tmp3, dst, stride); + ST_D8(tmp0, tmp1, tmp2, tmp3, 0, 1, 0, 1, 0, 1, 0, 1, dst, stride); } void ff_put_h264_qpel4_mc10_msa(uint8_t *dst, const uint8_t *src, @@ -1016,7 +1014,7 @@ void ff_put_h264_qpel4_mc10_msa(uint8_t *dst, const uint8_t *src, src0 = (v16i8) __msa_insve_d((v2i64) src0, 1, (v2i64) src1); res = __msa_aver_s_b(res, src0); res = (v16i8) __msa_xori_b((v16u8) res, 128); - ST4x4_UB(res, res, 0, 1, 2, 3, dst, stride); + ST_W4(res, 0, 1, 2, 3, dst, stride); } void ff_put_h264_qpel4_mc30_msa(uint8_t *dst, const uint8_t *src, @@ -1047,7 +1045,7 @@ void ff_put_h264_qpel4_mc30_msa(uint8_t *dst, const uint8_t *src, src0 = (v16i8) __msa_insve_d((v2i64) src0, 1, (v2i64) src1); res = __msa_aver_s_b(res, src0); res = (v16i8) __msa_xori_b((v16u8) res, 128); - ST4x4_UB(res, res, 0, 1, 2, 3, dst, stride); + ST_W4(res, 0, 1, 2, 3, dst, stride); } void ff_put_h264_qpel16_mc20_msa(uint8_t *dst, const uint8_t *src, @@ -1153,7 +1151,7 @@ void ff_put_h264_qpel8_mc20_msa(uint8_t *dst, const uint8_t *src, out1 = PCKEV_XORI128_UB(res2, res3); out2 = PCKEV_XORI128_UB(res4, res5); out3 = PCKEV_XORI128_UB(res6, res7); - ST8x8_UB(out0, out1, out2, out3, dst, stride); + ST_D8(out0, out1, out2, out3, 0, 1, 0, 1, 0, 1, 0, 1, dst, stride); } void ff_put_h264_qpel4_mc20_msa(uint8_t *dst, const uint8_t *src, @@ -1178,7 +1176,7 @@ void ff_put_h264_qpel4_mc20_msa(uint8_t *dst, const uint8_t *src, SRARI_H2_SH(res0, res1, 5); SAT_SH2_SH(res0, res1, 7); out = PCKEV_XORI128_UB(res0, res1); - ST4x4_UB(out, out, 0, 1, 2, 3, dst, stride); + ST_W4(out, 0, 1, 2, 3, dst, stride); } void ff_put_h264_qpel16_mc01_msa(uint8_t *dst, const uint8_t *src, @@ -1378,7 +1376,7 @@ void ff_put_h264_qpel8_mc01_msa(uint8_t *dst, const uint8_t *src, out2 = __msa_aver_s_b(out2, tmp2); out3 = __msa_aver_s_b(out3, tmp3); XORI_B4_128_SB(out0, out1, out2, out3); - ST8x8_UB(out0, out1, out2, out3, dst, stride); + ST_D8(out0, out1, out2, out3, 0, 1, 0, 1, 0, 1, 0, 1, dst, stride); } void ff_put_h264_qpel8_mc03_msa(uint8_t *dst, const uint8_t *src, @@ -1431,7 +1429,7 @@ void ff_put_h264_qpel8_mc03_msa(uint8_t *dst, const uint8_t *src, out2 = __msa_aver_s_b(out2, tmp2); out3 = __msa_aver_s_b(out3, tmp3); XORI_B4_128_SB(out0, out1, out2, out3); - ST8x8_UB(out0, out1, out2, out3, dst, stride); + ST_D8(out0, out1, out2, out3, 0, 1, 0, 1, 0, 1, 0, 1, dst, stride); } void ff_put_h264_qpel4_mc01_msa(uint8_t *dst, const uint8_t *src, @@ -1472,7 +1470,7 @@ void ff_put_h264_qpel4_mc01_msa(uint8_t *dst, const uint8_t *src, src54_r = (v16i8) __msa_insve_w((v4i32) src4, 1, (v4i32) src5); src32_r = (v16i8) __msa_insve_d((v2i64) src32_r, 1, (v2i64) src54_r); out = __msa_aver_u_b(out, (v16u8) src32_r); - ST4x4_UB(out, out, 0, 1, 2, 3, dst, stride); + ST_W4(out, 0, 1, 2, 3, dst, stride); } void ff_put_h264_qpel4_mc03_msa(uint8_t *dst, const uint8_t *src, @@ -1513,7 +1511,7 @@ void ff_put_h264_qpel4_mc03_msa(uint8_t *dst, const uint8_t *src, src54_r = (v16i8) __msa_insve_w((v4i32) src5, 1, (v4i32) src6); src32_r = (v16i8) __msa_insve_d((v2i64) src32_r, 1, (v2i64) src54_r); out = __msa_aver_u_b(out, (v16u8) src32_r); - ST4x4_UB(out, out, 0, 1, 2, 3, dst, stride); + ST_W4(out, 0, 1, 2, 3, dst, stride); } void ff_put_h264_qpel16_mc11_msa(uint8_t *dst, const uint8_t *src, @@ -1691,7 +1689,7 @@ void ff_put_h264_qpel16_mc21_msa(uint8_t *dst, const uint8_t *src, out0 = PCKEV_XORI128_UB(dst0, dst1); out1 = PCKEV_XORI128_UB(dst2, dst3); - ST8x4_UB(out0, out1, dst, stride); + ST_D4(out0, out1, 0, 1, 0, 1, dst, stride); dst += (4 * stride); hz_out0 = hz_out4; @@ -1804,7 +1802,7 @@ void ff_put_h264_qpel16_mc23_msa(uint8_t *dst, const uint8_t *src, out0 = PCKEV_XORI128_UB(dst0, dst1); out1 = PCKEV_XORI128_UB(dst2, dst3); - ST8x4_UB(out0, out1, dst, stride); + ST_D4(out0, out1, 0, 1, 0, 1, dst, stride); dst += (4 * stride); hz_out0 = hz_out4; @@ -1905,7 +1903,7 @@ void ff_put_h264_qpel8_mc21_msa(uint8_t *dst, const uint8_t *src, out0 = PCKEV_XORI128_UB(dst0, dst1); out1 = PCKEV_XORI128_UB(dst2, dst3); - ST8x4_UB(out0, out1, dst, stride); + ST_D4(out0, out1, 0, 1, 0, 1, dst, stride); dst += (4 * stride); LD_SB4(src, stride, src9, src10, src11, src12); @@ -1951,7 +1949,7 @@ void ff_put_h264_qpel8_mc21_msa(uint8_t *dst, const uint8_t *src, out0 = PCKEV_XORI128_UB(dst0, dst1); out1 = PCKEV_XORI128_UB(dst2, dst3); - ST8x4_UB(out0, out1, dst, stride); + ST_D4(out0, out1, 0, 1, 0, 1, dst, stride); } void ff_put_h264_qpel8_mc23_msa(uint8_t *dst, const uint8_t *src, @@ -2040,7 +2038,7 @@ void ff_put_h264_qpel8_mc23_msa(uint8_t *dst, const uint8_t *src, out0 = PCKEV_XORI128_UB(dst0, dst1); out1 = PCKEV_XORI128_UB(dst2, dst3); - ST8x4_UB(out0, out1, dst, stride); + ST_D4(out0, out1, 0, 1, 0, 1, dst, stride); dst += (4 * stride); LD_SB4(src, stride, src9, src10, src11, src12); @@ -2086,7 +2084,7 @@ void ff_put_h264_qpel8_mc23_msa(uint8_t *dst, const uint8_t *src, out0 = PCKEV_XORI128_UB(dst0, dst1); out1 = PCKEV_XORI128_UB(dst2, dst3); - ST8x4_UB(out0, out1, dst, stride); + ST_D4(out0, out1, 0, 1, 0, 1, dst, stride); } void ff_put_h264_qpel4_mc21_msa(uint8_t *dst, const uint8_t *src, @@ -2150,7 +2148,7 @@ void ff_put_h264_qpel4_mc21_msa(uint8_t *dst, const uint8_t *src, dst1 = __msa_aver_s_h(dst1, hz_out4); res = PCKEV_XORI128_UB(dst0, dst1); - ST4x4_UB(res, res, 0, 1, 2, 3, dst, stride); + ST_W4(res, 0, 1, 2, 3, dst, stride); } void ff_put_h264_qpel4_mc23_msa(uint8_t *dst, const uint8_t *src, @@ -2215,7 +2213,7 @@ void ff_put_h264_qpel4_mc23_msa(uint8_t *dst, const uint8_t *src, dst1 = __msa_aver_s_h(dst1, hz_out1); res = PCKEV_XORI128_UB(dst0, dst1); - ST4x4_UB(res, res, 0, 1, 2, 3, dst, stride); + ST_W4(res, 0, 1, 2, 3, dst, stride); } void ff_put_h264_qpel16_mc02_msa(uint8_t *dst, const uint8_t *src, @@ -2332,7 +2330,7 @@ void ff_put_h264_qpel8_mc02_msa(uint8_t *dst, const uint8_t *src, out1 = PCKEV_XORI128_UB(out2_r, out3_r); out2 = PCKEV_XORI128_UB(out4_r, out5_r); out3 = PCKEV_XORI128_UB(out6_r, out7_r); - ST8x8_UB(out0, out1, out2, out3, dst, stride); + ST_D8(out0, out1, out2, out3, 0, 1, 0, 1, 0, 1, 0, 1, dst, stride); } void ff_put_h264_qpel4_mc02_msa(uint8_t *dst, const uint8_t *src, @@ -2369,7 +2367,7 @@ void ff_put_h264_qpel4_mc02_msa(uint8_t *dst, const uint8_t *src, SRARI_H2_SH(out10, out32, 5); SAT_SH2_SH(out10, out32, 7); out = PCKEV_XORI128_UB(out10, out32); - ST4x4_UB(out, out, 0, 1, 2, 3, dst, stride); + ST_W4(out, 0, 1, 2, 3, dst, stride); } void ff_put_h264_qpel16_mc12_msa(uint8_t *dst, const uint8_t *src, @@ -2601,7 +2599,7 @@ void ff_put_h264_qpel8_mc12_msa(uint8_t *dst, const uint8_t *src, dst0 = __msa_aver_s_h(dst2, dst0); dst1 = __msa_aver_s_h(dst3, dst1); out = PCKEV_XORI128_UB(dst0, dst1); - ST8x2_UB(out, dst, stride); + ST_D2(out, 0, 1, dst, stride); dst += (2 * stride); src0 = src2; @@ -2677,7 +2675,7 @@ void ff_put_h264_qpel8_mc32_msa(uint8_t *dst, const uint8_t *src, dst0 = __msa_aver_s_h(dst2, dst0); dst1 = __msa_aver_s_h(dst3, dst1); out = PCKEV_XORI128_UB(dst0, dst1); - ST8x2_UB(out, dst, stride); + ST_D2(out, 0, 1, dst, stride); dst += (2 * stride); src0 = src2; @@ -2777,7 +2775,7 @@ void ff_put_h264_qpel4_mc12_msa(uint8_t *dst, const uint8_t *src, PCKEV_H2_SH(hz_res1, hz_res0, hz_res3, hz_res2, dst0, dst2); out = PCKEV_XORI128_UB(dst0, dst2); - ST4x4_UB(out, out, 0, 1, 2, 3, dst, stride); + ST_W4(out, 0, 1, 2, 3, dst, stride); } void ff_put_h264_qpel4_mc32_msa(uint8_t *dst, const uint8_t *src, @@ -2873,7 +2871,7 @@ void ff_put_h264_qpel4_mc32_msa(uint8_t *dst, const uint8_t *src, PCKEV_H2_SH(hz_res1, hz_res0, hz_res3, hz_res2, dst0, dst2); out = PCKEV_XORI128_UB(dst0, dst2); - ST4x4_UB(out, out, 0, 1, 2, 3, dst, stride); + ST_W4(out, 0, 1, 2, 3, dst, stride); } void ff_put_h264_qpel16_mc22_msa(uint8_t *dst, const uint8_t *src, @@ -2961,7 +2959,7 @@ void ff_put_h264_qpel16_mc22_msa(uint8_t *dst, const uint8_t *src, out0 = PCKEV_XORI128_UB(dst0, dst1); out1 = PCKEV_XORI128_UB(dst2, dst3); - ST8x4_UB(out0, out1, dst, stride); + ST_D4(out0, out1, 0, 1, 0, 1, dst, stride); dst += (4 * stride); hz_out0 = hz_out4; @@ -3049,7 +3047,7 @@ void ff_put_h264_qpel8_mc22_msa(uint8_t *dst, const uint8_t *src, dst3 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); out0 = PCKEV_XORI128_UB(dst0, dst1); out1 = PCKEV_XORI128_UB(dst2, dst3); - ST8x4_UB(out0, out1, dst, stride); + ST_D4(out0, out1, 0, 1, 0, 1, dst, stride); dst += (4 * stride); LD_SB4(src, stride, src0, src1, src2, src3); @@ -3086,7 +3084,7 @@ void ff_put_h264_qpel8_mc22_msa(uint8_t *dst, const uint8_t *src, dst3 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); out0 = PCKEV_XORI128_UB(dst0, dst1); out1 = PCKEV_XORI128_UB(dst2, dst3); - ST8x4_UB(out0, out1, dst, stride); + ST_D4(out0, out1, 0, 1, 0, 1, dst, stride); } void ff_put_h264_qpel4_mc22_msa(uint8_t *dst, const uint8_t *src, @@ -3141,7 +3139,7 @@ void ff_put_h264_qpel4_mc22_msa(uint8_t *dst, const uint8_t *src, filt2); dst1 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); res = PCKEV_XORI128_UB(dst0, dst1); - ST4x4_UB(res, res, 0, 1, 2, 3, dst, stride); + ST_W4(res, 0, 1, 2, 3, dst, stride); } void ff_avg_h264_qpel16_mc10_msa(uint8_t *dst, const uint8_t *src, @@ -3350,7 +3348,7 @@ void ff_avg_h264_qpel8_mc10_msa(uint8_t *dst, const uint8_t *src, INSERT_D2_UB(tp2, tp3, dst3); AVER_UB2_UB(tmp0, dst0, tmp1, dst1, dst0, dst1); AVER_UB2_UB(tmp2, dst2, tmp3, dst3, dst2, dst3); - ST8x8_UB(dst0, dst1, dst2, dst3, dst, stride); + ST_D8(dst0, dst1, dst2, dst3, 0, 1, 0, 1, 0, 1, 0, 1, dst, stride); } void ff_avg_h264_qpel8_mc30_msa(uint8_t *dst, const uint8_t *src, @@ -3415,7 +3413,7 @@ void ff_avg_h264_qpel8_mc30_msa(uint8_t *dst, const uint8_t *src, INSERT_D2_UB(tp2, tp3, dst3); AVER_UB2_UB(tmp0, dst0, tmp1, dst1, dst0, dst1); AVER_UB2_UB(tmp2, dst2, tmp3, dst3, dst2, dst3); - ST8x8_UB(dst0, dst1, dst2, dst3, dst, stride); + ST_D8(dst0, dst1, dst2, dst3, 0, 1, 0, 1, 0, 1, 0, 1, dst, stride); } void ff_avg_h264_qpel4_mc10_msa(uint8_t *dst, const uint8_t *src, @@ -3451,7 +3449,7 @@ void ff_avg_h264_qpel4_mc10_msa(uint8_t *dst, const uint8_t *src, LW4(dst, stride, tp0, tp1, tp2, tp3); INSERT_W4_UB(tp0, tp1, tp2, tp3, dst0); dst0 = __msa_aver_u_b((v16u8) res, dst0); - ST4x4_UB(dst0, dst0, 0, 1, 2, 3, dst, stride); + ST_W4(dst0, 0, 1, 2, 3, dst, stride); } void ff_avg_h264_qpel4_mc30_msa(uint8_t *dst, const uint8_t *src, @@ -3487,7 +3485,7 @@ void ff_avg_h264_qpel4_mc30_msa(uint8_t *dst, const uint8_t *src, LW4(dst, stride, tp0, tp1, tp2, tp3); INSERT_W4_UB(tp0, tp1, tp2, tp3, dst0); dst0 = __msa_aver_u_b((v16u8) res, dst0); - ST4x4_UB(dst0, dst0, 0, 1, 2, 3, dst, stride); + ST_W4(dst0, 0, 1, 2, 3, dst, stride); } void ff_avg_h264_qpel16_mc20_msa(uint8_t *dst, const uint8_t *src, @@ -3608,7 +3606,7 @@ void ff_avg_h264_qpel8_mc20_msa(uint8_t *dst, const uint8_t *src, INSERT_D2_UB(tp2, tp3, out7); AVER_UB2_UB(out0, out2, out1, out3, out0, out1); AVER_UB2_UB(out4, out6, out5, out7, out4, out5); - ST8x8_UB(out0, out1, out4, out5, dst, stride); + ST_D8(out0, out1, out4, out5, 0, 1, 0, 1, 0, 1, 0, 1, dst, stride); } void ff_avg_h264_qpel4_mc20_msa(uint8_t *dst, const uint8_t *src, @@ -3637,7 +3635,7 @@ void ff_avg_h264_qpel4_mc20_msa(uint8_t *dst, const uint8_t *src, LW4(dst, stride, tp0, tp1, tp2, tp3); INSERT_W4_UB(tp0, tp1, tp2, tp3, dst0); res = __msa_aver_u_b(res, dst0); - ST4x4_UB(res, res, 0, 1, 2, 3, dst, stride); + ST_W4(res, 0, 1, 2, 3, dst, stride); } void ff_avg_h264_qpel16_mc01_msa(uint8_t *dst, const uint8_t *src, @@ -3856,7 +3854,7 @@ void ff_avg_h264_qpel8_mc01_msa(uint8_t *dst, const uint8_t *src, XORI_B4_128_SB(out0, out1, out2, out3); AVER_UB4_UB(out0, dst0, out1, dst1, out2, dst2, out3, dst3, dst0, dst1, dst2, dst3); - ST8x8_UB(dst0, dst1, dst2, dst3, dst, stride); + ST_D8(dst0, dst1, dst2, dst3, 0, 1, 0, 1, 0, 1, 0, 1, dst, stride); } void ff_avg_h264_qpel8_mc03_msa(uint8_t *dst, const uint8_t *src, @@ -3922,7 +3920,7 @@ void ff_avg_h264_qpel8_mc03_msa(uint8_t *dst, const uint8_t *src, XORI_B4_128_SB(out0, out1, out2, out3); AVER_UB4_UB(out0, dst0, out1, dst1, out2, dst2, out3, dst3, dst0, dst1, dst2, dst3); - ST8x8_UB(dst0, dst1, dst2, dst3, dst, stride); + ST_D8(dst0, dst1, dst2, dst3, 0, 1, 0, 1, 0, 1, 0, 1, dst, stride); } void ff_avg_h264_qpel4_mc01_msa(uint8_t *dst, const uint8_t *src, @@ -3967,7 +3965,7 @@ void ff_avg_h264_qpel4_mc01_msa(uint8_t *dst, const uint8_t *src, res = PCKEV_XORI128_UB(out10, out32); res = __msa_aver_u_b(res, (v16u8) src32_r); dst0 = __msa_aver_u_b(res, dst0); - ST4x4_UB(dst0, dst0, 0, 1, 2, 3, dst, stride); + ST_W4(dst0, 0, 1, 2, 3, dst, stride); } void ff_avg_h264_qpel4_mc03_msa(uint8_t *dst, const uint8_t *src, @@ -4013,7 +4011,7 @@ void ff_avg_h264_qpel4_mc03_msa(uint8_t *dst, const uint8_t *src, src32_r = (v16i8) __msa_insve_d((v2i64) src32_r, 1, (v2i64) src54_r); res = __msa_aver_u_b(res, (v16u8) src32_r); dst0 = __msa_aver_u_b(res, dst0); - ST4x4_UB(dst0, dst0, 0, 1, 2, 3, dst, stride); + ST_W4(dst0, 0, 1, 2, 3, dst, stride); } void ff_avg_h264_qpel16_mc11_msa(uint8_t *dst, const uint8_t *src, @@ -4196,7 +4194,7 @@ void ff_avg_h264_qpel16_mc21_msa(uint8_t *dst, const uint8_t *src, out0 = PCKEV_XORI128_UB(tmp0, tmp1); dst0 = __msa_aver_u_b(out0, dst0); - ST8x2_UB(dst0, dst, stride); + ST_D2(dst0, 0, 1, dst, stride); dst += (2 * stride); LD_SB2(src, stride, src7, src8); @@ -4232,7 +4230,7 @@ void ff_avg_h264_qpel16_mc21_msa(uint8_t *dst, const uint8_t *src, out1 = PCKEV_XORI128_UB(tmp2, tmp3); dst1 = __msa_aver_u_b(out1, dst1); - ST8x2_UB(dst1, dst, stride); + ST_D2(dst1, 0, 1, dst, stride); dst += (2 * stride); hz_out0 = hz_out4; @@ -4326,7 +4324,7 @@ void ff_avg_h264_qpel16_mc23_msa(uint8_t *dst, const uint8_t *src, INSERT_D2_UB(tp0, tp1, dst0); out0 = PCKEV_XORI128_UB(tmp0, tmp1); dst0 = __msa_aver_u_b(out0, dst0); - ST8x2_UB(dst0, dst, stride); + ST_D2(dst0, 0, 1, dst, stride); dst += (2 * stride); LD_SB2(src, stride, src7, src8); @@ -4361,7 +4359,7 @@ void ff_avg_h264_qpel16_mc23_msa(uint8_t *dst, const uint8_t *src, INSERT_D2_UB(tp2, tp3, dst1); out1 = PCKEV_XORI128_UB(tmp2, tmp3); dst1 = __msa_aver_u_b(out1, dst1); - ST8x2_UB(dst1, dst, stride); + ST_D2(dst1, 0, 1, dst, stride); dst += (2 * stride); hz_out0 = hz_out4; @@ -4468,7 +4466,7 @@ void ff_avg_h264_qpel8_mc21_msa(uint8_t *dst, const uint8_t *src, out0 = PCKEV_XORI128_UB(tmp0, tmp1); out1 = PCKEV_XORI128_UB(tmp2, tmp3); AVER_UB2_UB(out0, dst0, out1, dst1, dst0, dst1); - ST8x4_UB(dst0, dst1, dst, stride); + ST_D4(dst0, dst1, 0, 1, 0, 1, dst, stride); dst += (4 * stride); LD_SB4(src, stride, src9, src10, src11, src12); @@ -4519,7 +4517,7 @@ void ff_avg_h264_qpel8_mc21_msa(uint8_t *dst, const uint8_t *src, out0 = PCKEV_XORI128_UB(tmp0, tmp1); out1 = PCKEV_XORI128_UB(tmp2, tmp3); AVER_UB2_UB(out0, dst0, out1, dst1, dst0, dst1); - ST8x4_UB(dst0, dst1, dst, stride); + ST_D4(dst0, dst1, 0, 1, 0, 1, dst, stride); } void ff_avg_h264_qpel8_mc23_msa(uint8_t *dst, const uint8_t *src, @@ -4614,7 +4612,7 @@ void ff_avg_h264_qpel8_mc23_msa(uint8_t *dst, const uint8_t *src, out0 = PCKEV_XORI128_UB(tmp0, tmp1); out1 = PCKEV_XORI128_UB(tmp2, tmp3); AVER_UB2_UB(out0, dst0, out1, dst1, dst0, dst1); - ST8x4_UB(dst0, dst1, dst, stride); + ST_D4(dst0, dst1, 0, 1, 0, 1, dst, stride); dst += (4 * stride); LD_SB4(src, stride, src9, src10, src11, src12); @@ -4665,7 +4663,7 @@ void ff_avg_h264_qpel8_mc23_msa(uint8_t *dst, const uint8_t *src, out0 = PCKEV_XORI128_UB(tmp0, tmp1); out1 = PCKEV_XORI128_UB(tmp2, tmp3); AVER_UB2_UB(out0, dst0, out1, dst1, dst0, dst1); - ST8x4_UB(dst0, dst1, dst, stride); + ST_D4(dst0, dst1, 0, 1, 0, 1, dst, stride); } void ff_avg_h264_qpel4_mc21_msa(uint8_t *dst, const uint8_t *src, @@ -4732,7 +4730,7 @@ void ff_avg_h264_qpel4_mc21_msa(uint8_t *dst, const uint8_t *src, INSERT_W4_UB(tp0, tp1, tp2, tp3, out); res = PCKEV_XORI128_UB(dst0, dst1); res = __msa_aver_u_b(res, out); - ST4x4_UB(res, res, 0, 1, 2, 3, dst, stride); + ST_W4(res, 0, 1, 2, 3, dst, stride); } void ff_avg_h264_qpel4_mc23_msa(uint8_t *dst, const uint8_t *src, @@ -4800,7 +4798,7 @@ void ff_avg_h264_qpel4_mc23_msa(uint8_t *dst, const uint8_t *src, INSERT_W4_UB(tp0, tp1, tp2, tp3, out); res = PCKEV_XORI128_UB(dst0, dst1); res = __msa_aver_u_b(res, out); - ST4x4_UB(res, res, 0, 1, 2, 3, dst, stride); + ST_W4(res, 0, 1, 2, 3, dst, stride); } void ff_avg_h264_qpel16_mc02_msa(uint8_t *dst, const uint8_t *src, @@ -4936,7 +4934,7 @@ void ff_avg_h264_qpel8_mc02_msa(uint8_t *dst, const uint8_t *src, out3 = PCKEV_XORI128_UB(out6_r, out7_r); AVER_UB4_UB(out0, dst0, out1, dst1, out2, dst2, out3, dst3, dst0, dst1, dst2, dst3); - ST8x8_UB(dst0, dst1, dst2, dst3, dst, stride); + ST_D8(dst0, dst1, dst2, dst3, 0, 1, 0, 1, 0, 1, 0, 1, dst, stride); } void ff_avg_h264_qpel4_mc02_msa(uint8_t *dst, const uint8_t *src, @@ -4977,7 +4975,7 @@ void ff_avg_h264_qpel4_mc02_msa(uint8_t *dst, const uint8_t *src, INSERT_W4_UB(tp0, tp1, tp2, tp3, dst0); res = PCKEV_XORI128_UB(out10, out32); dst0 = __msa_aver_u_b(res, dst0); - ST4x4_UB(dst0, dst0, 0, 1, 2, 3, dst, stride); + ST_W4(dst0, 0, 1, 2, 3, dst, stride); } void ff_avg_h264_qpel16_mc12_msa(uint8_t *dst, const uint8_t *src, @@ -5217,7 +5215,7 @@ void ff_avg_h264_qpel8_mc12_msa(uint8_t *dst, const uint8_t *src, tmp1 = __msa_aver_s_h(tmp3, tmp1); out = PCKEV_XORI128_UB(tmp0, tmp1); out = __msa_aver_u_b(out, dst0); - ST8x2_UB(out, dst, stride); + ST_D2(out, 0, 1, dst, stride); dst += (2 * stride); src0 = src2; @@ -5297,7 +5295,7 @@ void ff_avg_h264_qpel8_mc32_msa(uint8_t *dst, const uint8_t *src, tmp1 = __msa_aver_s_h(tmp3, tmp1); out = PCKEV_XORI128_UB(tmp0, tmp1); out = __msa_aver_u_b(out, dst0); - ST8x2_UB(out, dst, stride); + ST_D2(out, 0, 1, dst, stride); dst += (2 * stride); src0 = src2; @@ -5401,7 +5399,7 @@ void ff_avg_h264_qpel4_mc12_msa(uint8_t *dst, const uint8_t *src, PCKEV_H2_SH(hz_res1, hz_res0, hz_res3, hz_res2, dst0, dst2); out = PCKEV_XORI128_UB(dst0, dst2); out = __msa_aver_u_b(out, dstv); - ST4x4_UB(out, out, 0, 1, 2, 3, dst, stride); + ST_W4(out, 0, 1, 2, 3, dst, stride); } void ff_avg_h264_qpel4_mc32_msa(uint8_t *dst, const uint8_t *src, @@ -5500,7 +5498,7 @@ void ff_avg_h264_qpel4_mc32_msa(uint8_t *dst, const uint8_t *src, PCKEV_H2_SH(hz_res1, hz_res0, hz_res3, hz_res2, dst0, dst2); out = PCKEV_XORI128_UB(dst0, dst2); out = __msa_aver_u_b(out, dstv); - ST4x4_UB(out, out, 0, 1, 2, 3, dst, stride); + ST_W4(out, 0, 1, 2, 3, dst, stride); } void ff_avg_h264_qpel16_mc22_msa(uint8_t *dst, const uint8_t *src, @@ -5592,7 +5590,7 @@ void ff_avg_h264_qpel16_mc22_msa(uint8_t *dst, const uint8_t *src, out0 = PCKEV_XORI128_UB(res0, res1); out1 = PCKEV_XORI128_UB(res2, res3); AVER_UB2_UB(out0, dst0, out1, dst1, out0, out1); - ST8x4_UB(out0, out1, dst, stride); + ST_D4(out0, out1, 0, 1, 0, 1, dst, stride); dst += (4 * stride); hz_out0 = hz_out4; @@ -5685,7 +5683,7 @@ void ff_avg_h264_qpel8_mc22_msa(uint8_t *dst, const uint8_t *src, out0 = PCKEV_XORI128_UB(res0, res1); out1 = PCKEV_XORI128_UB(res2, res3); AVER_UB2_UB(out0, dst0, out1, dst1, dst0, dst1); - ST8x4_UB(dst0, dst1, dst, stride); + ST_D4(dst0, dst1, 0, 1, 0, 1, dst, stride); dst += (4 * stride); LD_SB4(src, stride, src0, src1, src2, src3); @@ -5726,7 +5724,7 @@ void ff_avg_h264_qpel8_mc22_msa(uint8_t *dst, const uint8_t *src, out0 = PCKEV_XORI128_UB(res0, res1); out1 = PCKEV_XORI128_UB(res2, res3); AVER_UB2_UB(out0, dst0, out1, dst1, dst0, dst1); - ST8x4_UB(dst0, dst1, dst, stride); + ST_D4(dst0, dst1, 0, 1, 0, 1, dst, stride); } void ff_avg_h264_qpel4_mc22_msa(uint8_t *dst, const uint8_t *src, @@ -5785,5 +5783,5 @@ void ff_avg_h264_qpel4_mc22_msa(uint8_t *dst, const uint8_t *src, INSERT_W4_UB(tp0, tp1, tp2, tp3, dst0); res = PCKEV_XORI128_UB(res0, res1); res = __msa_aver_u_b(res, dst0); - ST4x4_UB(res, res, 0, 1, 2, 3, dst, stride); + ST_W4(res, 0, 1, 2, 3, dst, stride); } diff --git a/libavcodec/mips/hevc_idct_msa.c b/libavcodec/mips/hevc_idct_msa.c index 09431196b..b14aec95e 100644 --- a/libavcodec/mips/hevc_idct_msa.c +++ b/libavcodec/mips/hevc_idct_msa.c @@ -727,7 +727,7 @@ static void hevc_addblk_4x4_msa(int16_t *coeffs, uint8_t *dst, int32_t stride) ADD2(dst_r0, in0, dst_l0, in1, dst_r0, dst_l0); CLIP_SH2_0_255(dst_r0, dst_l0); dst_vec = (v4i32) __msa_pckev_b((v16i8) dst_l0, (v16i8) dst_r0); - ST4x4_UB(dst_vec, dst_vec, 0, 1, 2, 3, dst, stride); + ST_W4(dst_vec, 0, 1, 2, 3, dst, stride); } static void hevc_addblk_8x8_msa(int16_t *coeffs, uint8_t *dst, int32_t stride) @@ -752,8 +752,7 @@ static void hevc_addblk_8x8_msa(int16_t *coeffs, uint8_t *dst, int32_t stride) dst_r0, dst_l0, dst_r1, dst_l1); CLIP_SH4_0_255(dst_r0, dst_l0, dst_r1, dst_l1); PCKEV_B2_SH(dst_l0, dst_r0, dst_l1, dst_r1, dst_r0, dst_r1); - ST8x4_UB(dst_r0, dst_r1, dst, stride); - dst += (4 * stride); + ST_D4(dst_r0, dst_r1, 0, 1, 0, 1, dst, stride); LD4(temp_dst, stride, dst0, dst1, dst2, dst3); INSERT_D2_SD(dst0, dst1, dst_vec0); @@ -764,7 +763,7 @@ static void hevc_addblk_8x8_msa(int16_t *coeffs, uint8_t *dst, int32_t stride) dst_r0, dst_l0, dst_r1, dst_l1); CLIP_SH4_0_255(dst_r0, dst_l0, dst_r1, dst_l1); PCKEV_B2_SH(dst_l0, dst_r0, dst_l1, dst_r1, dst_r0, dst_r1); - ST8x4_UB(dst_r0, dst_r1, dst, stride); + ST_D4(dst_r0, dst_r1, 0, 1, 0, 1, dst + 4 * stride, stride); } static void hevc_addblk_16x16_msa(int16_t *coeffs, uint8_t *dst, int32_t stride) diff --git a/libavcodec/mips/hevc_lpf_sao_msa.c b/libavcodec/mips/hevc_lpf_sao_msa.c index adcafde62..ac2180640 100644 --- a/libavcodec/mips/hevc_lpf_sao_msa.c +++ b/libavcodec/mips/hevc_lpf_sao_msa.c @@ -199,11 +199,9 @@ static void hevc_loopfilter_luma_hor_msa(uint8_t *src, int32_t stride, dst_val0 = __msa_copy_u_d((v2i64) dst2, 0); dst_val1 = __msa_copy_u_d((v2i64) dst2, 1); - ST8x4_UB(dst0, dst1, p2, stride); - p2 += (4 * stride); - SD(dst_val0, p2); - p2 += stride; - SD(dst_val1, p2); + ST_D4(dst0, dst1, 0, 1, 0, 1, p2, stride); + SD(dst_val0, p2 + 4 * stride); + SD(dst_val1, p2 + 5 * stride); /* strong filter ends */ } else if (flag0 == flag1) { /* weak only */ /* weak filter */ @@ -288,7 +286,7 @@ static void hevc_loopfilter_luma_hor_msa(uint8_t *src, int32_t stride, dst1 = __msa_bmz_v(dst1, dst3, (v16u8) cmp3); p2 += stride; - ST8x4_UB(dst0, dst1, p2, stride); + ST_D4(dst0, dst1, 0, 1, 0, 1, p2, stride); /* weak filter ends */ } else { /* strong + weak */ /* strong filter */ @@ -442,11 +440,9 @@ static void hevc_loopfilter_luma_hor_msa(uint8_t *src, int32_t stride, dst_val0 = __msa_copy_u_d((v2i64) dst2, 0); dst_val1 = __msa_copy_u_d((v2i64) dst2, 1); - ST8x4_UB(dst0, dst1, p2, stride); - p2 += (4 * stride); - SD(dst_val0, p2); - p2 += stride; - SD(dst_val1, p2); + ST_D4(dst0, dst1, 0, 1, 0, 1, p2, stride); + SD(dst_val0, p2 + 4 * stride); + SD(dst_val1, p2 + 5 * stride); } } } @@ -976,7 +972,7 @@ static void hevc_loopfilter_chroma_hor_msa(uint8_t *src, int32_t stride, temp1 = (v8i16) __msa_bmnz_v((v16u8) temp1, (v16u8) q0, (v16u8) tc_pos); temp0 = (v8i16) __msa_pckev_b((v16i8) temp1, (v16i8) temp0); - ST8x2_UB(temp0, p0_ptr, stride); + ST_D2(temp0, 0, 1, p0_ptr, stride); } } @@ -1037,9 +1033,7 @@ static void hevc_loopfilter_chroma_ver_msa(uint8_t *src, int32_t stride, temp0 = (v8i16) __msa_ilvev_b((v16i8) temp1, (v16i8) temp0); src += 1; - ST2x4_UB(temp0, 0, src, stride); - src += (4 * stride); - ST2x4_UB(temp0, 4, src, stride); + ST_H8(temp0, 0, 1, 2, 3, 4, 5, 6, 7, src, stride); } } @@ -1087,7 +1081,7 @@ static void hevc_sao_band_filter_4width_msa(uint8_t *dst, int32_t dst_stride, LD_UB4(src, src_stride, src0, src1, src2, src3); /* store results */ - ST4x4_UB(dst0, dst0, 0, 1, 2, 3, dst, dst_stride); + ST_W4(dst0, 0, 1, 2, 3, dst, dst_stride); dst += (4 * dst_stride); } @@ -1102,7 +1096,7 @@ static void hevc_sao_band_filter_4width_msa(uint8_t *dst, int32_t dst_stride, dst0 = (v16i8) __msa_xori_b((v16u8) dst0, 128); /* store results */ - ST4x4_UB(dst0, dst0, 0, 1, 2, 3, dst, dst_stride); + ST_W4(dst0, 0, 1, 2, 3, dst, dst_stride); } static void hevc_sao_band_filter_8width_msa(uint8_t *dst, int32_t dst_stride, @@ -1153,7 +1147,7 @@ static void hevc_sao_band_filter_8width_msa(uint8_t *dst, int32_t dst_stride, XORI_B2_128_SB(dst0, dst1); /* store results */ - ST8x4_UB(dst0, dst1, dst, dst_stride); + ST_D4(dst0, dst1, 0, 1, 0, 1, dst, dst_stride); dst += dst_stride << 2; } @@ -1173,7 +1167,7 @@ static void hevc_sao_band_filter_8width_msa(uint8_t *dst, int32_t dst_stride, XORI_B2_128_SB(dst0, dst1); /* store results */ - ST8x4_UB(dst0, dst1, dst, dst_stride); + ST_D4(dst0, dst1, 0, 1, 0, 1, dst, dst_stride); } static void hevc_sao_band_filter_16multiple_msa(uint8_t *dst, diff --git a/libavcodec/mips/hevc_mc_bi_msa.c b/libavcodec/mips/hevc_mc_bi_msa.c index b555517b2..34613c84b 100644 --- a/libavcodec/mips/hevc_mc_bi_msa.c +++ b/libavcodec/mips/hevc_mc_bi_msa.c @@ -86,7 +86,7 @@ static void hevc_bi_copy_4w_msa(uint8_t *src0_ptr, dst0 = CLIP_SH_0_255_MAX_SATU(dst0); dst0 = (v8i16) __msa_pckev_b((v16i8) dst0, (v16i8) dst0); - ST4x2_UB(dst0, dst, dst_stride); + ST_W2(dst0, 0, 1, dst, dst_stride); } else if (4 == height) { LW4(src0_ptr, src_stride, tp0, tp1, tp2, tp3); INSERT_W4_SB(tp0, tp1, tp2, tp3, src0); @@ -97,7 +97,7 @@ static void hevc_bi_copy_4w_msa(uint8_t *src0_ptr, SLLI_2V(dst0, dst1, 6); HEVC_BI_RND_CLIP2_MAX_SATU(in0, in1, dst0, dst1, 7, dst0, dst1); dst0 = (v8i16) __msa_pckev_b((v16i8) dst1, (v16i8) dst0); - ST4x4_UB(dst0, dst0, 0, 1, 2, 3, dst, dst_stride); + ST_W4(dst0, 0, 1, 2, 3, dst, dst_stride); } else if (0 == height % 8) { for (loop_cnt = (height >> 3); loop_cnt--;) { LW4(src0_ptr, src_stride, tp0, tp1, tp2, tp3); @@ -120,7 +120,7 @@ static void hevc_bi_copy_4w_msa(uint8_t *src0_ptr, HEVC_BI_RND_CLIP4_MAX_SATU(in0, in1, in2, in3, dst0, dst1, dst2, dst3, 7, dst0, dst1, dst2, dst3); PCKEV_B2_SH(dst1, dst0, dst3, dst2, dst0, dst1); - ST4x8_UB(dst0, dst1, dst, dst_stride); + ST_W8(dst0, dst1, 0, 1, 2, 3, 0, 1, 2, 3, dst, dst_stride); dst += (8 * dst_stride); } } @@ -165,9 +165,15 @@ static void hevc_bi_copy_6w_msa(uint8_t *src0_ptr, 7, dst4, dst5, dst6, dst7); PCKEV_B2_UB(dst1, dst0, dst3, dst2, out0, out1); PCKEV_B2_UB(dst5, dst4, dst7, dst6, out2, out3); - ST6x4_UB(out0, out1, dst, dst_stride); + ST_W2(out0, 0, 2, dst, dst_stride); + ST_H2(out0, 2, 6, dst + 4, dst_stride); + ST_W2(out1, 0, 2, dst + 2 * dst_stride, dst_stride); + ST_H2(out1, 2, 6, dst + 2 * dst_stride + 4, dst_stride); dst += (4 * dst_stride); - ST6x4_UB(out2, out3, dst, dst_stride); + ST_W2(out2, 0, 2, dst, dst_stride); + ST_H2(out2, 2, 6, dst + 4, dst_stride); + ST_W2(out3, 0, 2, dst + 2 * dst_stride, dst_stride); + ST_H2(out3, 2, 6, dst + 2 * dst_stride + 4, dst_stride); dst += (4 * dst_stride); } } @@ -195,7 +201,7 @@ static void hevc_bi_copy_8w_msa(uint8_t *src0_ptr, SLLI_2V(dst0, dst1, 6); HEVC_BI_RND_CLIP2_MAX_SATU(in0, in1, dst0, dst1, 7, dst0, dst1); out0 = (v16u8) __msa_pckev_b((v16i8) dst1, (v16i8) dst0); - ST8x2_UB(out0, dst, dst_stride); + ST_D2(out0, 0, 1, dst, dst_stride); } else if (4 == height) { LD4(src0_ptr, src_stride, tp0, tp1, tp2, tp3); INSERT_D2_SB(tp0, tp1, src0); @@ -207,7 +213,7 @@ static void hevc_bi_copy_8w_msa(uint8_t *src0_ptr, HEVC_BI_RND_CLIP4_MAX_SATU(in0, in1, in2, in3, dst0, dst1, dst2, dst3, 7, dst0, dst1, dst2, dst3); PCKEV_B2_UB(dst1, dst0, dst3, dst2, out0, out1); - ST8x4_UB(out0, out1, dst, dst_stride); + ST_D4(out0, out1, 0, 1, 0, 1, dst, dst_stride); } else if (6 == height) { LD4(src0_ptr, src_stride, tp0, tp1, tp2, tp3); src0_ptr += 4 * src_stride; @@ -225,9 +231,8 @@ static void hevc_bi_copy_8w_msa(uint8_t *src0_ptr, 7, dst0, dst1, dst2, dst3); HEVC_BI_RND_CLIP2_MAX_SATU(in4, in5, dst4, dst5, 7, dst4, dst5); PCKEV_B3_UB(dst1, dst0, dst3, dst2, dst5, dst4, out0, out1, out2); - ST8x4_UB(out0, out1, dst, dst_stride); - dst += (4 * dst_stride); - ST8x2_UB(out2, dst, dst_stride); + ST_D4(out0, out1, 0, 1, 0, 1, dst, dst_stride); + ST_D2(out2, 0, 1, dst + 4 * dst_stride, dst_stride); } else if (0 == height % 8) { uint32_t loop_cnt; @@ -255,7 +260,7 @@ static void hevc_bi_copy_8w_msa(uint8_t *src0_ptr, dst7, 7, dst4, dst5, dst6, dst7); PCKEV_B2_UB(dst1, dst0, dst3, dst2, out0, out1); PCKEV_B2_UB(dst5, dst4, dst7, dst6, out2, out3); - ST8x8_UB(out0, out1, out2, out3, dst, dst_stride); + ST_D8(out0, out1, out2, out3, 0, 1, 0, 1, 0, 1, 0, 1, dst, dst_stride); dst += (8 * dst_stride); } } @@ -294,7 +299,8 @@ static void hevc_bi_copy_12w_msa(uint8_t *src0_ptr, 7, dst0, dst1, dst2, dst3); HEVC_BI_RND_CLIP2_MAX_SATU(in4, in5, dst4, dst5, 7, dst4, dst5); PCKEV_B3_UB(dst1, dst0, dst3, dst2, dst5, dst4, out0, out1, out2); - ST12x4_UB(out0, out1, out2, dst, dst_stride); + ST_D4(out0, out1, 0, 1, 0, 1, dst, dst_stride); + ST_W4(out2, 0, 1, 2, 3, dst + 8, dst_stride); dst += (4 * dst_stride); } } @@ -378,7 +384,7 @@ static void hevc_bi_copy_24w_msa(uint8_t *src0_ptr, PCKEV_B3_UB(dst1, dst0, dst3, dst2, dst5, dst4, out0, out1, out2); PCKEV_B3_UB(dst7, dst6, dst9, dst8, dst11, dst10, out3, out4, out5); ST_UB4(out0, out1, out3, out4, dst, dst_stride); - ST8x4_UB(out2, out5, dst + 16, dst_stride); + ST_D4(out2, out5, 0, 1, 0, 1, dst + 16, dst_stride); dst += (4 * dst_stride); } } @@ -588,7 +594,7 @@ static void hevc_hz_bi_8t_4w_msa(uint8_t *src0_ptr, dst0, dst1, dst2, dst3, 7, dst0, dst1, dst2, dst3); PCKEV_B2_SH(dst1, dst0, dst3, dst2, dst0, dst1); - ST4x8_UB(dst0, dst1, dst, dst_stride); + ST_W8(dst0, dst1, 0, 1, 2, 3, 0, 1, 2, 3, dst, dst_stride); dst += (8 * dst_stride); } } @@ -656,7 +662,7 @@ static void hevc_hz_bi_8t_8w_msa(uint8_t *src0_ptr, dst0, dst1, dst2, dst3, 7, dst0, dst1, dst2, dst3); PCKEV_B2_SH(dst1, dst0, dst3, dst2, dst0, dst1); - ST8x4_UB(dst0, dst1, dst, dst_stride); + ST_D4(dst0, dst1, 0, 1, 0, 1, dst, dst_stride); dst += (4 * dst_stride); } } @@ -1242,7 +1248,7 @@ static void hevc_vt_bi_8t_4w_msa(uint8_t *src0_ptr, dst10, dst32, dst54, dst76); PCKEV_B2_SH(dst32, dst10, dst76, dst54, dst10, dst54); - ST4x8_UB(dst10, dst54, dst, dst_stride); + ST_W8(dst10, dst54, 0, 1, 2, 3, 0, 1, 2, 3, dst, dst_stride); dst += (8 * dst_stride); src2110 = src10998; @@ -1316,7 +1322,7 @@ static void hevc_vt_bi_8t_8w_msa(uint8_t *src0_ptr, dst0_r, dst1_r, dst2_r, dst3_r); PCKEV_B2_SH(dst1_r, dst0_r, dst3_r, dst2_r, dst0_r, dst1_r); - ST8x4_UB(dst0_r, dst1_r, dst, dst_stride); + ST_D4(dst0_r, dst1_r, 0, 1, 0, 1, dst, dst_stride); dst += (4 * dst_stride); src10_r = src54_r; @@ -1420,7 +1426,8 @@ static void hevc_vt_bi_8t_12w_msa(uint8_t *src0_ptr, PCKEV_B2_SH(dst1_r, dst0_r, dst3_r, dst2_r, dst0_r, dst1_r); dst0_l = (v8i16) __msa_pckev_b((v16i8) dst1_l, (v16i8) dst0_l); - ST12x4_UB(dst0_r, dst1_r, dst0_l, dst, dst_stride); + ST_D4(dst0_r, dst1_r, 0, 1, 0, 1, dst, dst_stride); + ST_W4(dst0_l, 0, 1, 2, 3, dst + 8, dst_stride); dst += (4 * dst_stride); src10_r = src54_r; @@ -1721,7 +1728,7 @@ static void hevc_hv_bi_8t_4w_msa(uint8_t *src0_ptr, SRARI_H2_SH(out0, out1, 7); CLIP_SH2_0_255_MAX_SATU(out0, out1); out = (v16u8) __msa_pckev_b((v16i8) out1, (v16i8) out0); - ST4x4_UB(out, out, 0, 1, 2, 3, dst, dst_stride); + ST_W4(out, 0, 1, 2, 3, dst, dst_stride); dst += (4 * dst_stride); dst10 = dst54; @@ -1849,7 +1856,7 @@ static void hevc_hv_bi_8t_8multx1mult_msa(uint8_t *src0_ptr, tmp = __msa_srari_h(tmp, 7); tmp = CLIP_SH_0_255_MAX_SATU(tmp); out = (v16u8) __msa_pckev_b((v16i8) tmp, (v16i8) tmp); - ST8x1_UB(out, dst_tmp); + ST_D1(out, 0, dst_tmp); dst_tmp += dst_stride; dst0 = dst1; @@ -1995,7 +2002,7 @@ static void hevc_hv_bi_8t_12w_msa(uint8_t *src0_ptr, tmp = __msa_srari_h(tmp, 7); tmp = CLIP_SH_0_255_MAX_SATU(tmp); out = (v16u8) __msa_pckev_b((v16i8) tmp, (v16i8) tmp); - ST8x1_UB(out, dst_tmp); + ST_D1(out, 0, dst_tmp); dst_tmp += dst_stride; dst0 = dst1; @@ -2083,7 +2090,7 @@ static void hevc_hv_bi_8t_12w_msa(uint8_t *src0_ptr, SRARI_H2_SH(out0, out1, 7); CLIP_SH2_0_255_MAX_SATU(out0, out1); out = (v16u8) __msa_pckev_b((v16i8) out1, (v16i8) out0); - ST4x4_UB(out, out, 0, 1, 2, 3, dst, dst_stride); + ST_W4(out, 0, 1, 2, 3, dst, dst_stride); dst += (4 * dst_stride); dst10 = dst54; @@ -2211,7 +2218,7 @@ static void hevc_hz_bi_4t_4x2_msa(uint8_t *src0_ptr, tmp0 = CLIP_SH_0_255(tmp0); dst0 = __msa_pckev_b((v16i8) tmp0, (v16i8) tmp0); - ST4x2_UB(dst0, dst, dst_stride); + ST_W2(dst0, 0, 1, dst, dst_stride); } static void hevc_hz_bi_4t_4x4_msa(uint8_t *src0_ptr, @@ -2257,7 +2264,7 @@ static void hevc_hz_bi_4t_4x4_msa(uint8_t *src0_ptr, HEVC_BI_RND_CLIP2(in0, in1, tmp0, tmp1, 7, tmp0, tmp1); dst0 = __msa_pckev_b((v16i8) tmp1, (v16i8) tmp0); - ST4x4_UB(dst0, dst0, 0, 1, 2, 3, dst, dst_stride); + ST_W4(dst0, 0, 1, 2, 3, dst, dst_stride); } static void hevc_hz_bi_4t_4x8multiple_msa(uint8_t *src0_ptr, @@ -2318,7 +2325,7 @@ static void hevc_hz_bi_4t_4x8multiple_msa(uint8_t *src0_ptr, tmp0, tmp1, tmp2, tmp3, 7, tmp0, tmp1, tmp2, tmp3); PCKEV_B2_SB(tmp1, tmp0, tmp3, tmp2, dst0, dst1); - ST4x8_UB(dst0, dst1, dst, dst_stride); + ST_W8(dst0, dst1, 0, 1, 2, 3, 0, 1, 2, 3, dst, dst_stride); dst += (8 * dst_stride); } } @@ -2398,7 +2405,10 @@ static void hevc_hz_bi_4t_6w_msa(uint8_t *src0_ptr, dst0, dst1, dst2, dst3, 7, dst0, dst1, dst2, dst3); PCKEV_B2_SH(dst1, dst0, dst3, dst2, dst0, dst1); - ST6x4_UB(dst0, dst1, dst, dst_stride); + ST_W2(dst0, 0, 2, dst, dst_stride); + ST_H2(dst0, 2, 6, dst + 4, dst_stride); + ST_W2(dst1, 0, 2, dst + 2 * dst_stride, dst_stride); + ST_H2(dst1, 2, 6, dst + 2 * dst_stride + 4, dst_stride); dst += (4 * dst_stride); } } @@ -2443,7 +2453,7 @@ static void hevc_hz_bi_4t_8x2_msa(uint8_t *src0_ptr, HEVC_BI_RND_CLIP2(in0, in1, dst0, dst1, 7, dst0, dst1); dst0 = (v8i16) __msa_pckev_b((v16i8) dst1, (v16i8) dst0); - ST8x2_UB(dst0, dst, dst_stride); + ST_D2(dst0, 0, 1, dst, dst_stride); } static void hevc_hz_bi_4t_8x6_msa(uint8_t *src0_ptr, @@ -2506,9 +2516,8 @@ static void hevc_hz_bi_4t_8x6_msa(uint8_t *src0_ptr, PCKEV_B2_SH(dst1, dst0, dst3, dst2, dst0, dst1); dst2 = (v8i16) __msa_pckev_b((v16i8) dst5, (v16i8) dst4); - ST8x4_UB(dst0, dst1, dst, dst_stride); - dst += (4 * dst_stride); - ST8x2_UB(dst2, dst, dst_stride); + ST_D4(dst0, dst1, 0, 1, 0, 1, dst, dst_stride); + ST_D2(dst2, 0, 1, dst + 4 * dst_stride, dst_stride); } static void hevc_hz_bi_4t_8x4multiple_msa(uint8_t *src0_ptr, @@ -2564,7 +2573,7 @@ static void hevc_hz_bi_4t_8x4multiple_msa(uint8_t *src0_ptr, dst0, dst1, dst2, dst3, 7, dst0, dst1, dst2, dst3); PCKEV_B2_SH(dst1, dst0, dst3, dst2, dst0, dst1); - ST8x4_UB(dst0, dst1, dst, dst_stride); + ST_D4(dst0, dst1, 0, 1, 0, 1, dst, dst_stride); dst += (4 * dst_stride); } } @@ -2659,7 +2668,8 @@ static void hevc_hz_bi_4t_12w_msa(uint8_t *src0_ptr, PCKEV_B2_SH(dst1, dst0, dst3, dst2, dst0, dst1); dst2 = (v8i16) __msa_pckev_b((v16i8) dst5, (v16i8) dst4); - ST12x4_UB(dst0, dst1, dst2, dst, dst_stride); + ST_D4(dst0, dst1, 0, 1, 0, 1, dst, dst_stride); + ST_W4(dst2, 0, 1, 2, 3, dst + 8, dst_stride); dst += (4 * dst_stride); } } @@ -2825,7 +2835,7 @@ static void hevc_hz_bi_4t_24w_msa(uint8_t *src0_ptr, dst0, dst1, dst2, dst3, 7, dst0, dst1, dst2, dst3); PCKEV_B2_SH(dst1, dst0, dst3, dst2, dst0, dst1); - ST8x4_UB(dst0, dst1, dst_tmp, dst_stride); + ST_D4(dst0, dst1, 0, 1, 0, 1, dst_tmp, dst_stride); dst_tmp += (4 * dst_stride); } } @@ -2936,7 +2946,7 @@ static void hevc_vt_bi_4t_4x2_msa(uint8_t *src0_ptr, dst10 = CLIP_SH_0_255(dst10); dst10 = (v8i16) __msa_pckev_b((v16i8) dst10, (v16i8) dst10); - ST4x2_UB(dst10, dst, dst_stride); + ST_W2(dst10, 0, 1, dst, dst_stride); } static void hevc_vt_bi_4t_4x4_msa(uint8_t *src0_ptr, @@ -2985,7 +2995,7 @@ static void hevc_vt_bi_4t_4x4_msa(uint8_t *src0_ptr, HEVC_BI_RND_CLIP2(in0, in1, dst10, dst32, 7, dst10, dst32); dst10 = (v8i16) __msa_pckev_b((v16i8) dst32, (v16i8) dst10); - ST4x4_UB(dst10, dst10, 0, 1, 2, 3, dst, dst_stride); + ST_W4(dst10, 0, 1, 2, 3, dst, dst_stride); } static void hevc_vt_bi_4t_4x8multiple_msa(uint8_t *src0_ptr, @@ -3056,7 +3066,7 @@ static void hevc_vt_bi_4t_4x8multiple_msa(uint8_t *src0_ptr, dst10, dst32, dst54, dst76); PCKEV_B2_SH(dst32, dst10, dst76, dst54, dst10, dst54); - ST4x8_UB(dst10, dst54, dst, dst_stride); + ST_W8(dst10, dst54, 0, 1, 2, 3, 0, 1, 2, 3, dst, dst_stride); dst += (8 * dst_stride); } } @@ -3147,7 +3157,10 @@ static void hevc_vt_bi_4t_6w_msa(uint8_t *src0_ptr, dst0_r, dst1_r, dst2_r, dst3_r); PCKEV_B2_SH(dst1_r, dst0_r, dst3_r, dst2_r, dst0_r, dst1_r); - ST6x4_UB(dst0_r, dst1_r, dst, dst_stride); + ST_W2(dst0_r, 0, 2, dst, dst_stride); + ST_H2(dst0_r, 2, 6, dst + 4, dst_stride); + ST_W2(dst1_r, 0, 2, dst + 2 * dst_stride, dst_stride); + ST_H2(dst1_r, 2, 6, dst + 2 * dst_stride + 4, dst_stride); dst += (4 * dst_stride); LD_SH4(src1_ptr, src2_stride, in0, in1, in2, in3); @@ -3171,7 +3184,10 @@ static void hevc_vt_bi_4t_6w_msa(uint8_t *src0_ptr, dst0_r, dst1_r, dst2_r, dst3_r); PCKEV_B2_SH(dst1_r, dst0_r, dst3_r, dst2_r, dst0_r, dst1_r); - ST6x4_UB(dst0_r, dst1_r, dst, dst_stride); + ST_W2(dst0_r, 0, 2, dst, dst_stride); + ST_H2(dst0_r, 2, 6, dst + 4, dst_stride); + ST_W2(dst1_r, 0, 2, dst + 2 * dst_stride, dst_stride); + ST_H2(dst1_r, 2, 6, dst + 2 * dst_stride + 4, dst_stride); dst += (4 * dst_stride); } @@ -3216,7 +3232,7 @@ static void hevc_vt_bi_4t_8x2_msa(uint8_t *src0_ptr, HEVC_BI_RND_CLIP2(in0, in1, dst0_r, dst1_r, 7, dst0_r, dst1_r); dst0_r = (v8i16) __msa_pckev_b((v16i8) dst1_r, (v16i8) dst0_r); - ST8x2_UB(dst0_r, dst, dst_stride); + ST_D2(dst0_r, 0, 1, dst, dst_stride); } static void hevc_vt_bi_4t_8x6_msa(uint8_t *src0_ptr, @@ -3275,9 +3291,8 @@ static void hevc_vt_bi_4t_8x6_msa(uint8_t *src0_ptr, PCKEV_B2_SH(dst1_r, dst0_r, dst3_r, dst2_r, dst0_r, dst1_r); dst2_r = (v8i16) __msa_pckev_b((v16i8) dst5_r, (v16i8) dst4_r); - ST8x4_UB(dst0_r, dst1_r, dst, dst_stride); - dst += (4 * dst_stride); - ST8x2_UB(dst2_r, dst, dst_stride); + ST_D4(dst0_r, dst1_r, 0, 1, 0, 1, dst, dst_stride); + ST_D2(dst2_r, 0, 1, dst + 4 * dst_stride, dst_stride); } static void hevc_vt_bi_4t_8x4multiple_msa(uint8_t *src0_ptr, @@ -3337,7 +3352,7 @@ static void hevc_vt_bi_4t_8x4multiple_msa(uint8_t *src0_ptr, dst0_r, dst1_r, dst2_r, dst3_r); PCKEV_B2_SH(dst1_r, dst0_r, dst3_r, dst2_r, dst0_r, dst1_r); - ST8x4_UB(dst0_r, dst1_r, dst, dst_stride); + ST_D4(dst0_r, dst1_r, 0, 1, 0, 1, dst, dst_stride); dst += (4 * dst_stride); } } @@ -3436,7 +3451,8 @@ static void hevc_vt_bi_4t_12w_msa(uint8_t *src0_ptr, PCKEV_B2_SH(dst1_r, dst0_r, dst3_r, dst2_r, dst0_r, dst1_r); dst0_l = (v8i16) __msa_pckev_b((v16i8) dst1_l, (v16i8) dst0_l); - ST12x4_UB(dst0_r, dst1_r, dst0_l, dst, dst_stride); + ST_D4(dst0_r, dst1_r, 0, 1, 0, 1, dst, dst_stride); + ST_W4(dst0_l, 0, 1, 2, 3, dst + 8, dst_stride); dst += (4 * dst_stride); src2 = src6; @@ -3610,7 +3626,7 @@ static void hevc_vt_bi_4t_24w_msa(uint8_t *src0_ptr, PCKEV_B2_SH(dst0_l, dst0_r, dst1_l, dst1_r, dst0_r, dst1_r); dst2_r = (v8i16) __msa_pckev_b((v16i8) dst3_r, (v16i8) dst2_r); ST_SH2(dst0_r, dst1_r, dst, dst_stride); - ST8x2_UB(dst2_r, dst + 16, dst_stride); + ST_D2(dst2_r, 0, 1, dst + 16, dst_stride); dst += (2 * dst_stride); /* 16width */ @@ -3650,7 +3666,7 @@ static void hevc_vt_bi_4t_24w_msa(uint8_t *src0_ptr, PCKEV_B2_SH(dst0_l, dst0_r, dst1_l, dst1_r, dst0_r, dst1_r); dst2_r = (v8i16) __msa_pckev_b((v16i8) dst3_r, (v16i8) dst2_r); ST_SH2(dst0_r, dst1_r, dst, dst_stride); - ST8x2_UB(dst2_r, dst + 16, dst_stride); + ST_D2(dst2_r, 0, 1, dst + 16, dst_stride); dst += (2 * dst_stride); } } @@ -3829,7 +3845,7 @@ static void hevc_hv_bi_4t_4x2_msa(uint8_t *src0_ptr, tmp = __msa_srari_h(tmp, 7); tmp = CLIP_SH_0_255_MAX_SATU(tmp); out = (v16u8) __msa_pckev_b((v16i8) tmp, (v16i8) tmp); - ST4x2_UB(out, dst, dst_stride); + ST_W2(out, 0, 1, dst, dst_stride); } static void hevc_hv_bi_4t_4x4_msa(uint8_t *src0_ptr, @@ -3905,7 +3921,7 @@ static void hevc_hv_bi_4t_4x4_msa(uint8_t *src0_ptr, SRARI_H2_SH(tmp0, tmp1, 7); CLIP_SH2_0_255_MAX_SATU(tmp0, tmp1); out = (v16u8) __msa_pckev_b((v16i8) tmp1, (v16i8) tmp0); - ST4x4_UB(out, out, 0, 1, 2, 3, dst, dst_stride); + ST_W4(out, 0, 1, 2, 3, dst, dst_stride); } static void hevc_hv_bi_4t_4multx8mult_msa(uint8_t *src0_ptr, @@ -4018,7 +4034,7 @@ static void hevc_hv_bi_4t_4multx8mult_msa(uint8_t *src0_ptr, SRARI_H4_SH(tmp0, tmp1, tmp2, tmp3, 7); CLIP_SH4_0_255_MAX_SATU(tmp0, tmp1, tmp2, tmp3); PCKEV_B2_UB(tmp1, tmp0, tmp3, tmp2, out0, out1); - ST4x8_UB(out0, out1, dst, dst_stride); + ST_W8(out0, out1, 0, 1, 2, 3, 0, 1, 2, 3, dst, dst_stride); dst += (8 * dst_stride); dst10_r = dst98_r; @@ -4186,7 +4202,7 @@ static void hevc_hv_bi_4t_6w_msa(uint8_t *src0_ptr, SRARI_H4_SH(tmp0, tmp1, tmp2, tmp3, 7); CLIP_SH4_0_255_MAX_SATU(tmp0, tmp1, tmp2, tmp3); PCKEV_B2_UB(tmp1, tmp0, tmp3, tmp2, out0, out1); - ST4x8_UB(out0, out1, dst, dst_stride); + ST_W8(out0, out1, 0, 1, 2, 3, 0, 1, 2, 3, dst, dst_stride); LW4(src1_ptr + 4, src2_stride, tpw0, tpw1, tpw2, tpw3); src1_ptr += (4 * src2_stride); @@ -4198,9 +4214,7 @@ static void hevc_hv_bi_4t_6w_msa(uint8_t *src0_ptr, SRARI_H2_SH(tmp4, tmp5, 7); CLIP_SH2_0_255_MAX_SATU(tmp4, tmp5); out2 = (v16u8) __msa_pckev_b((v16i8) tmp5, (v16i8) tmp4); - ST2x4_UB(out2, 0, dst + 4, dst_stride); - dst += 4 * dst_stride; - ST2x4_UB(out2, 4, dst + 4, dst_stride); + ST_H8(out2, 0, 1, 2, 3, 4, 5, 6, 7, dst + 4, dst_stride); } static void hevc_hv_bi_4t_8x2_msa(uint8_t *src0_ptr, @@ -4274,7 +4288,7 @@ static void hevc_hv_bi_4t_8x2_msa(uint8_t *src0_ptr, SRARI_H2_SH(tmp0, tmp1, 7); CLIP_SH2_0_255_MAX_SATU(tmp0, tmp1); out = (v16u8) __msa_pckev_b((v16i8) tmp1, (v16i8) tmp0); - ST8x2_UB(out, dst, dst_stride); + ST_D2(out, 0, 1, dst, dst_stride); } static void hevc_hv_bi_4t_8multx4_msa(uint8_t *src0_ptr, @@ -4368,7 +4382,7 @@ static void hevc_hv_bi_4t_8multx4_msa(uint8_t *src0_ptr, SRARI_H4_SH(tmp0, tmp1, tmp2, tmp3, 7); CLIP_SH4_0_255_MAX_SATU(tmp0, tmp1, tmp2, tmp3); PCKEV_B2_UB(tmp1, tmp0, tmp3, tmp2, out0, out1); - ST8x4_UB(out0, out1, dst, dst_stride); + ST_D4(out0, out1, 0, 1, 0, 1, dst, dst_stride); dst += 8; } } @@ -4485,9 +4499,8 @@ static void hevc_hv_bi_4t_8x6_msa(uint8_t *src0_ptr, CLIP_SH2_0_255_MAX_SATU(tmp4, tmp5); PCKEV_B2_UB(tmp1, tmp0, tmp3, tmp2, out0, out1); out2 = (v16u8) __msa_pckev_b((v16i8) tmp5, (v16i8) tmp4); - ST8x4_UB(out0, out1, dst, dst_stride); - dst += (4 * dst_stride); - ST8x2_UB(out2, dst, dst_stride); + ST_D4(out0, out1, 0, 1, 0, 1, dst, dst_stride); + ST_D2(out2, 0, 1, dst + 4 * dst_stride, dst_stride); } static void hevc_hv_bi_4t_8multx4mult_msa(uint8_t *src0_ptr, @@ -4599,7 +4612,7 @@ static void hevc_hv_bi_4t_8multx4mult_msa(uint8_t *src0_ptr, SRARI_H4_SH(tmp0, tmp1, tmp2, tmp3, 7); CLIP_SH4_0_255_MAX_SATU(tmp0, tmp1, tmp2, tmp3); PCKEV_B2_UB(tmp1, tmp0, tmp3, tmp2, out0, out1); - ST8x4_UB(out0, out1, dst_tmp, dst_stride); + ST_D4(out0, out1, 0, 1, 0, 1, dst_tmp, dst_stride); dst_tmp += (4 * dst_stride); dst10_r = dst54_r; @@ -4749,7 +4762,7 @@ static void hevc_hv_bi_4t_12w_msa(uint8_t *src0_ptr, SRARI_H4_SH(tmp0, tmp1, tmp2, tmp3, 7); CLIP_SH4_0_255_MAX_SATU(tmp0, tmp1, tmp2, tmp3); PCKEV_B2_UB(tmp1, tmp0, tmp3, tmp2, out0, out1); - ST8x4_UB(out0, out1, dst_tmp, dst_stride); + ST_D4(out0, out1, 0, 1, 0, 1, dst_tmp, dst_stride); dst_tmp += (4 * dst_stride); dst10_r = dst54_r; @@ -4835,7 +4848,7 @@ static void hevc_hv_bi_4t_12w_msa(uint8_t *src0_ptr, SRARI_H4_SH(tmp0, tmp1, tmp2, tmp3, 7); CLIP_SH4_0_255_MAX_SATU(tmp0, tmp1, tmp2, tmp3); PCKEV_B2_UB(tmp1, tmp0, tmp3, tmp2, out0, out1); - ST4x8_UB(out0, out1, dst, dst_stride); + ST_W8(out0, out1, 0, 1, 2, 3, 0, 1, 2, 3, dst, dst_stride); dst += (8 * dst_stride); dst10_r = dst98_r; diff --git a/libavcodec/mips/hevc_mc_biw_msa.c b/libavcodec/mips/hevc_mc_biw_msa.c index ea65f0049..68f122ea4 100644 --- a/libavcodec/mips/hevc_mc_biw_msa.c +++ b/libavcodec/mips/hevc_mc_biw_msa.c @@ -126,7 +126,7 @@ static void hevc_biwgt_copy_4w_msa(uint8_t *src0_ptr, dst0 = (v8i16) __msa_pckev_h((v8i16) dst0_l, (v8i16) dst0_r); dst0 = CLIP_SH_0_255_MAX_SATU(dst0); out0 = (v16u8) __msa_pckev_b((v16i8) dst0, (v16i8) dst0); - ST4x2_UB(out0, dst, dst_stride); + ST_W2(out0, 0, 1, dst, dst_stride); } else if (4 == height) { LW4(src0_ptr, src_stride, tp0, tp1, tp2, tp3); INSERT_W4_SB(tp0, tp1, tp2, tp3, src0); @@ -138,7 +138,7 @@ static void hevc_biwgt_copy_4w_msa(uint8_t *src0_ptr, HEVC_BIW_RND_CLIP2_MAX_SATU(dst0, dst1, in0, in1, weight_vec, rnd_vec, offset_vec, dst0, dst1); out0 = (v16u8) __msa_pckev_b((v16i8) dst1, (v16i8) dst0); - ST4x4_UB(out0, out0, 0, 1, 2, 3, dst, dst_stride); + ST_W4(out0, 0, 1, 2, 3, dst, dst_stride); } else if (0 == height % 8) { for (loop_cnt = (height >> 3); loop_cnt--;) { LW4(src0_ptr, src_stride, tp0, tp1, tp2, tp3); @@ -162,7 +162,7 @@ static void hevc_biwgt_copy_4w_msa(uint8_t *src0_ptr, in3, weight_vec, rnd_vec, offset_vec, dst0, dst1, dst2, dst3); PCKEV_B2_UB(dst1, dst0, dst3, dst2, out0, out1); - ST4x8_UB(out0, out1, dst, dst_stride); + ST_W8(out0, out1, 0, 1, 2, 3, 0, 1, 2, 3, dst, dst_stride); dst += (8 * dst_stride); } } @@ -214,7 +214,10 @@ static void hevc_biwgt_copy_6w_msa(uint8_t *src0_ptr, weight_vec, rnd_vec, offset_vec, dst0, dst1, dst2, dst3); PCKEV_B2_UB(dst1, dst0, dst3, dst2, out0, out1); - ST6x4_UB(out0, out1, dst, dst_stride); + ST_W2(out0, 0, 2, dst, dst_stride); + ST_H2(out0, 2, 6, dst + 4, dst_stride); + ST_W2(out1, 0, 2, dst + 2 * dst_stride, dst_stride); + ST_H2(out1, 2, 6, dst + 2 * dst_stride + 4, dst_stride); dst += (4 * dst_stride); } } @@ -261,7 +264,7 @@ static void hevc_biwgt_copy_8w_msa(uint8_t *src0_ptr, dst0, dst1); out0 = (v16u8) __msa_pckev_b((v16i8) dst1, (v16i8) dst0); - ST8x2_UB(out0, dst, dst_stride); + ST_D2(out0, 0, 1, dst, dst_stride); } else if (6 == height) { LD4(src0_ptr, src_stride, tp0, tp1, tp2, tp3); src0_ptr += 4 * src_stride; @@ -281,9 +284,8 @@ static void hevc_biwgt_copy_8w_msa(uint8_t *src0_ptr, HEVC_BIW_RND_CLIP2_MAX_SATU(dst4, dst5, in4, in5, weight_vec, rnd_vec, offset_vec, dst4, dst5); PCKEV_B3_UB(dst1, dst0, dst3, dst2, dst5, dst4, out0, out1, out2); - ST8x4_UB(out0, out1, dst, dst_stride); - dst += (4 * dst_stride); - ST8x2_UB(out2, dst, dst_stride); + ST_D4(out0, out1, 0, 1, 0, 1, dst, dst_stride); + ST_D2(out2, 0, 1, dst + 4 * dst_stride, dst_stride); } else if (0 == height % 4) { uint32_t loop_cnt; @@ -302,7 +304,7 @@ static void hevc_biwgt_copy_8w_msa(uint8_t *src0_ptr, in3, weight_vec, rnd_vec, offset_vec, dst0, dst1, dst2, dst3); PCKEV_B2_UB(dst1, dst0, dst3, dst2, out0, out1); - ST8x4_UB(out0, out1, dst, dst_stride); + ST_D4(out0, out1, 0, 1, 0, 1, dst, dst_stride); dst += (4 * dst_stride); } } @@ -361,7 +363,8 @@ static void hevc_biwgt_copy_12w_msa(uint8_t *src0_ptr, HEVC_BIW_RND_CLIP2_MAX_SATU(dst4, dst5, in4, in5, weight_vec, rnd_vec, offset_vec, dst4, dst5); PCKEV_B3_UB(dst1, dst0, dst3, dst2, dst5, dst4, out0, out1, out2); - ST12x4_UB(out0, out1, out2, dst, dst_stride); + ST_D4(out0, out1, 0, 1, 0, 1, dst, dst_stride); + ST_W4(out2, 0, 1, 2, 3, dst + 8, dst_stride); dst += (4 * dst_stride); } } @@ -480,7 +483,7 @@ static void hevc_biwgt_copy_24w_msa(uint8_t *src0_ptr, PCKEV_B3_UB(dst1, dst0, dst3, dst2, dst5, dst4, out0, out1, out2); PCKEV_B3_UB(dst7, dst6, dst9, dst8, dst11, dst10, out3, out4, out5); ST_UB4(out0, out1, out3, out4, dst, dst_stride); - ST8x4_UB(out2, out5, dst + 16, dst_stride); + ST_D4(out2, out5, 0, 1, 0, 1, dst + 16, dst_stride); dst += (4 * dst_stride); } } @@ -720,7 +723,7 @@ static void hevc_hz_biwgt_8t_4w_msa(uint8_t *src0_ptr, out0, out1); out0 = (v8i16) __msa_pckev_b((v16i8) out1, (v16i8) out0); - ST4x4_UB(out0, out0, 0, 1, 2, 3, dst, dst_stride); + ST_W4(out0, 0, 1, 2, 3, dst, dst_stride); dst += (4 * dst_stride); } } @@ -800,7 +803,7 @@ static void hevc_hz_biwgt_8t_8w_msa(uint8_t *src0_ptr, out0, out1, out2, out3); PCKEV_B2_SH(out1, out0, out3, out2, out0, out1); - ST8x4_UB(out0, out1, dst, dst_stride); + ST_D4(out0, out1, 0, 1, 0, 1, dst, dst_stride); dst += (4 * dst_stride); } } @@ -876,7 +879,7 @@ static void hevc_hz_biwgt_8t_12w_msa(uint8_t *src0_ptr, weight_vec, rnd_vec, offset_vec, out0, out1, out2, out3); PCKEV_B2_SH(out1, out0, out3, out2, out0, out1); - ST8x4_UB(out0, out1, dst, dst_stride); + ST_D4(out0, out1, 0, 1, 0, 1, dst, dst_stride); LD_SB4(src0_ptr + 8, src_stride, src0, src1, src2, src3); src0_ptr += (4 * src_stride); @@ -895,7 +898,7 @@ static void hevc_hz_biwgt_8t_12w_msa(uint8_t *src0_ptr, HEVC_BIW_RND_CLIP2(dst0, dst1, in0, in1, weight_vec, rnd_vec, offset_vec, out0, out1); out0 = (v8i16) __msa_pckev_b((v16i8) out1, (v16i8) out0); - ST4x4_UB(out0, out0, 0, 1, 2, 3, dst + 8, dst_stride); + ST_W4(out0, 0, 1, 2, 3, dst + 8, dst_stride); dst += (4 * dst_stride); } } @@ -1483,7 +1486,7 @@ static void hevc_vt_biwgt_8t_4w_msa(uint8_t *src0_ptr, out0, out1, out2, out3); PCKEV_B2_SH(out1, out0, out3, out2, out0, out1); - ST4x8_UB(out0, out1, dst, dst_stride); + ST_W8(out0, out1, 0, 1, 2, 3, 0, 1, 2, 3, dst, dst_stride); dst += (8 * dst_stride); src2110 = src10998; @@ -1568,7 +1571,7 @@ static void hevc_vt_biwgt_8t_8w_msa(uint8_t *src0_ptr, out0, out1, out2, out3); PCKEV_B2_SH(out1, out0, out3, out2, out0, out1); - ST8x4_UB(out0, out1, dst, dst_stride); + ST_D4(out0, out1, 0, 1, 0, 1, dst, dst_stride); dst += (4 * dst_stride); src10_r = src54_r; @@ -1674,8 +1677,8 @@ static void hevc_vt_biwgt_8t_12w_msa(uint8_t *src0_ptr, dst2_r = (v4i32) __msa_pckev_h((v8i16) dst2_l, (v8i16) dst2_r); out2 = CLIP_SH_0_255(dst2_r); PCKEV_B2_SH(out1, out0, out2, out2, out0, out2); - ST8x2_UB(out0, dst, dst_stride); - ST4x2_UB(out2, dst + 8, dst_stride); + ST_D2(out0, 0, 1, dst, dst_stride); + ST_W2(out2, 0, 1, dst + 8, dst_stride); dst += (2 * dst_stride); src10_r = src32_r; @@ -2048,7 +2051,7 @@ static void hevc_hv_biwgt_8t_4w_msa(uint8_t *src0_ptr, CLIP_SW4_0_255_MAX_SATU(dst0, dst1, dst2, dst3); PCKEV_H2_SH(dst1, dst0, dst3, dst2, tmp0, tmp1); out = (v16u8) __msa_pckev_b((v16i8) tmp1, (v16i8) tmp0); - ST4x4_UB(out, out, 0, 1, 2, 3, dst, dst_stride); + ST_W4(out, 0, 1, 2, 3, dst, dst_stride); dst += (4 * dst_stride); dst10 = dst54; @@ -2226,7 +2229,7 @@ static void hevc_hv_biwgt_8t_8multx2mult_msa(uint8_t *src0_ptr, CLIP_SW4_0_255_MAX_SATU(dst0_l, dst0_r, dst1_l, dst1_r); PCKEV_H2_SH(dst0_l, dst0_r, dst1_l, dst1_r, tmp0, tmp1); out = (v16u8) __msa_pckev_b((v16i8) tmp1, (v16i8) tmp0); - ST8x2_UB(out, dst_tmp, dst_stride); + ST_D2(out, 0, 1, dst_tmp, dst_stride); dst_tmp += (2 * dst_stride); dst0 = dst2; @@ -2412,7 +2415,7 @@ static void hevc_hv_biwgt_8t_12w_msa(uint8_t *src0_ptr, CLIP_SW4_0_255_MAX_SATU(dst1, dst0, dst3, dst2); PCKEV_H2_SH(dst1, dst0, dst3, dst2, tmp0, tmp1); out = (v16u8) __msa_pckev_b((v16i8) tmp1, (v16i8) tmp0); - ST8x2_UB(out, dst_tmp, dst_stride); + ST_D2(out, 0, 1, dst_tmp, dst_stride); dst_tmp += (2 * dst_stride); dsth0 = dsth2; @@ -2503,7 +2506,7 @@ static void hevc_hv_biwgt_8t_12w_msa(uint8_t *src0_ptr, CLIP_SW4_0_255_MAX_SATU(dst0, dst1, dst2, dst3); PCKEV_H2_SH(dst1, dst0, dst3, dst2, tmp0, tmp1); out = (v16u8) __msa_pckev_b((v16i8) tmp1, (v16i8) tmp0); - ST4x4_UB(out, out, 0, 1, 2, 3, dst, dst_stride); + ST_W4(out, 0, 1, 2, 3, dst, dst_stride); dst += (4 * dst_stride); dst10 = dst54; @@ -2683,7 +2686,7 @@ static void hevc_hz_biwgt_4t_4x2_msa(uint8_t *src0_ptr, dst0_r = (v4i32) __msa_pckev_h((v8i16) dst0_l, (v8i16) dst0_r); out0 = CLIP_SH_0_255(dst0_r); out0 = (v8i16) __msa_pckev_b((v16i8) out0, (v16i8) out0); - ST4x2_UB(out0, dst, dst_stride); + ST_W2(out0, 0, 1, dst, dst_stride); } static void hevc_hz_biwgt_4t_4x4_msa(uint8_t *src0_ptr, @@ -2743,7 +2746,7 @@ static void hevc_hz_biwgt_4t_4x4_msa(uint8_t *src0_ptr, dst0, dst1); dst0 = (v8i16) __msa_pckev_b((v16i8) dst1, (v16i8) dst0); - ST4x4_UB(dst0, dst0, 0, 1, 2, 3, dst, dst_stride); + ST_W4(dst0, 0, 1, 2, 3, dst, dst_stride); } static void hevc_hz_biwgt_4t_4x8multiple_msa(uint8_t *src0_ptr, @@ -2816,7 +2819,7 @@ static void hevc_hz_biwgt_4t_4x8multiple_msa(uint8_t *src0_ptr, dst0, dst1, dst2, dst3); PCKEV_B2_SH(dst1, dst0, dst3, dst2, dst0, dst1); - ST4x8_UB(dst0, dst1, dst, dst_stride); + ST_W8(dst0, dst1, 0, 1, 2, 3, 0, 1, 2, 3, dst, dst_stride); dst += (8 * dst_stride); } } @@ -2918,7 +2921,10 @@ static void hevc_hz_biwgt_4t_6w_msa(uint8_t *src0_ptr, dst0, dst1, dst2, dst3); PCKEV_B2_SH(dst1, dst0, dst3, dst2, dst0, dst1); - ST6x4_UB(dst0, dst1, dst, dst_stride); + ST_W2(dst0, 0, 2, dst, dst_stride); + ST_H2(dst0, 2, 6, dst + 4, dst_stride); + ST_W2(dst1, 0, 2, dst + 2 * dst_stride, dst_stride); + ST_H2(dst1, 2, 6, dst + 2 * dst_stride + 4, dst_stride); dst += (4 * dst_stride); } } @@ -2976,7 +2982,7 @@ static void hevc_hz_biwgt_4t_8x2_msa(uint8_t *src0_ptr, dst0, dst1); dst0 = (v8i16) __msa_pckev_b((v16i8) dst1, (v16i8) dst0); - ST8x2_UB(dst0, dst, dst_stride); + ST_D2(dst0, 0, 1, dst, dst_stride); } static void hevc_hz_biwgt_4t_8x6_msa(uint8_t *src0_ptr, @@ -3049,9 +3055,8 @@ static void hevc_hz_biwgt_4t_8x6_msa(uint8_t *src0_ptr, PCKEV_B2_SH(dst1, dst0, dst3, dst2, dst0, dst1); dst3 = (v8i16) __msa_pckev_b((v16i8) dst5, (v16i8) dst4); - ST8x4_UB(dst0, dst1, dst, dst_stride); - dst += (4 * dst_stride); - ST8x2_UB(dst3, dst, dst_stride); + ST_D4(dst0, dst1, 0, 1, 0, 1, dst, dst_stride); + ST_D2(dst3, 0, 1, dst + 4 * dst_stride, dst_stride); } static void hevc_hz_biwgt_4t_8x4multiple_msa(uint8_t *src0_ptr, @@ -3119,7 +3124,7 @@ static void hevc_hz_biwgt_4t_8x4multiple_msa(uint8_t *src0_ptr, dst0, dst1, dst2, dst3); PCKEV_B2_SH(dst1, dst0, dst3, dst2, dst0, dst1); - ST8x4_UB(dst0, dst1, dst, dst_stride); + ST_D4(dst0, dst1, 0, 1, 0, 1, dst, dst_stride); dst += (4 * dst_stride); } } @@ -3235,7 +3240,8 @@ static void hevc_hz_biwgt_4t_12w_msa(uint8_t *src0_ptr, PCKEV_B2_SH(dst1, dst0, dst3, dst2, dst0, dst1); dst3 = (v8i16) __msa_pckev_b((v16i8) dst5, (v16i8) dst4); - ST12x4_UB(dst0, dst1, dst3, dst, dst_stride); + ST_D4(dst0, dst1, 0, 1, 0, 1, dst, dst_stride); + ST_W4(dst3, 0, 1, 2, 3, dst + 8, dst_stride); dst += (4 * dst_stride); } } @@ -3411,7 +3417,7 @@ static void hevc_hz_biwgt_4t_24w_msa(uint8_t *src0_ptr, dst0, dst1); dst0 = (v8i16) __msa_pckev_b((v16i8) dst1, (v16i8) dst0); - ST8x2_UB(dst0, (dst + 16), dst_stride); + ST_D2(dst0, 0, 1, (dst + 16), dst_stride); dst += (2 * dst_stride); } } @@ -3551,7 +3557,7 @@ static void hevc_vt_biwgt_4t_4x2_msa(uint8_t *src0_ptr, dst10_r = (v4i32) __msa_pckev_h((v8i16) dst10_l, (v8i16) dst10_r); out = CLIP_SH_0_255(dst10_r); out = (v8i16) __msa_pckev_b((v16i8) out, (v16i8) out); - ST4x2_UB(out, dst, dst_stride); + ST_W2(out, 0, 1, dst, dst_stride); } static void hevc_vt_biwgt_4t_4x4_msa(uint8_t *src0_ptr, @@ -3617,7 +3623,7 @@ static void hevc_vt_biwgt_4t_4x4_msa(uint8_t *src0_ptr, dst10, dst32); dst10 = (v8i16) __msa_pckev_b((v16i8) dst32, (v16i8) dst10); - ST4x4_UB(dst10, dst10, 0, 1, 2, 3, dst, dst_stride); + ST_W4(dst10, 0, 1, 2, 3, dst, dst_stride); dst += (4 * dst_stride); } @@ -3702,7 +3708,7 @@ static void hevc_vt_biwgt_4t_4x8multiple_msa(uint8_t *src0_ptr, dst10, dst32, dst54, dst76); PCKEV_B2_SH(dst32, dst10, dst76, dst54, dst10, dst32); - ST4x8_UB(dst10, dst32, dst, dst_stride); + ST_W8(dst10, dst32, 0, 1, 2, 3, 0, 1, 2, 3, dst, dst_stride); dst += (8 * dst_stride); } } @@ -3807,7 +3813,10 @@ static void hevc_vt_biwgt_4t_6w_msa(uint8_t *src0_ptr, tmp0, tmp1, tmp2, tmp3); PCKEV_B2_SH(tmp1, tmp0, tmp3, tmp2, tmp0, tmp1); - ST6x4_UB(tmp0, tmp1, dst, dst_stride); + ST_W2(tmp0, 0, 2, dst, dst_stride); + ST_H2(tmp0, 2, 6, dst + 4, dst_stride); + ST_W2(tmp1, 0, 2, dst + 2 * dst_stride, dst_stride); + ST_H2(tmp1, 2, 6, dst + 2 * dst_stride + 4, dst_stride); dst += (4 * dst_stride); } } @@ -3866,7 +3875,7 @@ static void hevc_vt_biwgt_4t_8x2_msa(uint8_t *src0_ptr, tmp0, tmp1); tmp0 = (v8i16) __msa_pckev_b((v16i8) tmp1, (v16i8) tmp0); - ST8x2_UB(tmp0, dst, dst_stride); + ST_D2(tmp0, 0, 1, dst, dst_stride); } static void hevc_vt_biwgt_4t_8x6_msa(uint8_t *src0_ptr, @@ -3936,9 +3945,8 @@ static void hevc_vt_biwgt_4t_8x6_msa(uint8_t *src0_ptr, PCKEV_B2_SH(tmp1, tmp0, tmp3, tmp2, tmp0, tmp1); tmp3 = (v8i16) __msa_pckev_b((v16i8) tmp5, (v16i8) tmp4); - ST8x4_UB(tmp0, tmp1, dst, dst_stride); - dst += (4 * dst_stride); - ST8x2_UB(tmp3, dst, dst_stride); + ST_D4(tmp0, tmp1, 0, 1, 0, 1, dst, dst_stride); + ST_D2(tmp3, 0, 1, dst + 4 * dst_stride, dst_stride); } static void hevc_vt_biwgt_4t_8x4multiple_msa(uint8_t *src0_ptr, @@ -4010,7 +4018,7 @@ static void hevc_vt_biwgt_4t_8x4multiple_msa(uint8_t *src0_ptr, tmp0, tmp1, tmp2, tmp3); PCKEV_B2_SH(tmp1, tmp0, tmp3, tmp2, tmp0, tmp1); - ST8x4_UB(tmp0, tmp1, dst, dst_stride); + ST_D4(tmp0, tmp1, 0, 1, 0, 1, dst, dst_stride); dst += (4 * dst_stride); } } @@ -4132,7 +4140,8 @@ static void hevc_vt_biwgt_4t_12w_msa(uint8_t *src0_ptr, PCKEV_B2_SH(tmp1, tmp0, tmp3, tmp2, tmp0, tmp1); tmp2 = (v8i16) __msa_pckev_b((v16i8) tmp5, (v16i8) tmp4); - ST12x4_UB(tmp0, tmp1, tmp2, dst, dst_stride); + ST_D4(tmp0, tmp1, 0, 1, 0, 1, dst, dst_stride); + ST_W4(tmp2, 0, 1, 2, 3, dst + 8, dst_stride); dst += (4 * dst_stride); } } @@ -4323,7 +4332,7 @@ static void hevc_vt_biwgt_4t_24w_msa(uint8_t *src0_ptr, /* 8width */ tmp2 = (v8i16) __msa_pckev_b((v16i8) tmp3, (v16i8) tmp2); ST_SH2(tmp0, tmp1, dst, dst_stride); - ST8x2_UB(tmp2, dst + 16, dst_stride); + ST_D2(tmp2, 0, 1, dst + 16, dst_stride); dst += (2 * dst_stride); /* 16width */ @@ -4363,7 +4372,7 @@ static void hevc_vt_biwgt_4t_24w_msa(uint8_t *src0_ptr, /* 8width */ tmp2 = (v8i16) __msa_pckev_b((v16i8) tmp3, (v16i8) tmp2); ST_SH2(tmp0, tmp1, dst, dst_stride); - ST8x2_UB(tmp2, dst + 16, dst_stride); + ST_D2(tmp2, 0, 1, dst + 16, dst_stride); dst += (2 * dst_stride); } } @@ -4568,7 +4577,7 @@ static void hevc_hv_biwgt_4t_4x2_msa(uint8_t *src0_ptr, tmp = __msa_pckev_h((v8i16) dst1, (v8i16) dst0); tmp = CLIP_SH_0_255_MAX_SATU(tmp); out = (v16u8) __msa_pckev_b((v16i8) tmp, (v16i8) tmp); - ST4x2_UB(out, dst, dst_stride); + ST_W2(out, 0, 1, dst, dst_stride); } static void hevc_hv_biwgt_4t_4x4_msa(uint8_t *src0_ptr, @@ -4665,7 +4674,7 @@ static void hevc_hv_biwgt_4t_4x4_msa(uint8_t *src0_ptr, PCKEV_H2_SH(dst1, dst0, dst3, dst2, tmp0, tmp1); CLIP_SH2_0_255_MAX_SATU(tmp0, tmp1); out = (v16u8) __msa_pckev_b((v16i8) tmp1, (v16i8) tmp0); - ST4x4_UB(out, out, 0, 1, 2, 3, dst, dst_stride); + ST_W4(out, 0, 1, 2, 3, dst, dst_stride); } static void hevc_hv_biwgt_4t_4multx8mult_msa(uint8_t *src0_ptr, @@ -4803,7 +4812,7 @@ static void hevc_hv_biwgt_4t_4multx8mult_msa(uint8_t *src0_ptr, tmp2, tmp3); CLIP_SH4_0_255_MAX_SATU(tmp0, tmp1, tmp2, tmp3); PCKEV_B2_UB(tmp1, tmp0, tmp3, tmp2, out0, out1); - ST4x8_UB(out0, out1, dst, dst_stride); + ST_W8(out0, out1, 0, 1, 2, 3, 0, 1, 2, 3, dst, dst_stride); dst += (8 * dst_stride); dst10_r = dst98_r; @@ -5001,7 +5010,7 @@ static void hevc_hv_biwgt_4t_6w_msa(uint8_t *src0_ptr, tmp2, tmp3); CLIP_SH4_0_255_MAX_SATU(tmp0, tmp1, tmp2, tmp3); PCKEV_B2_UB(tmp1, tmp0, tmp3, tmp2, out0, out1); - ST4x8_UB(out0, out1, dst, dst_stride); + ST_W8(out0, out1, 0, 1, 2, 3, 0, 1, 2, 3, dst, dst_stride); PCKEV_H2_SW(dst1_l, dst0_l, dst3_l, dst2_l, dst4, dst5); @@ -5023,9 +5032,7 @@ static void hevc_hv_biwgt_4t_6w_msa(uint8_t *src0_ptr, CLIP_SH2_0_255_MAX_SATU(tmp4, tmp5); out2 = (v16u8) __msa_pckev_b((v16i8) tmp5, (v16i8) tmp4); - ST2x4_UB(out2, 0, dst + 4, dst_stride); - dst += 4 * dst_stride; - ST2x4_UB(out2, 4, dst + 4, dst_stride); + ST_H8(out2, 0, 1, 2, 3, 4, 5, 6, 7, dst + 4, dst_stride); } static void hevc_hv_biwgt_4t_8x2_msa(uint8_t *src0_ptr, @@ -5121,7 +5128,7 @@ static void hevc_hv_biwgt_4t_8x2_msa(uint8_t *src0_ptr, PCKEV_H2_SH(dst0_l, dst0_r, dst1_l, dst1_r, tmp0, tmp1); CLIP_SH2_0_255_MAX_SATU(tmp0, tmp1); out = (v16u8) __msa_pckev_b((v16i8) tmp1, (v16i8) tmp0); - ST8x2_UB(out, dst, dst_stride); + ST_D2(out, 0, 1, dst, dst_stride); } static void hevc_hv_biwgt_4t_8multx4_msa(uint8_t *src0_ptr, @@ -5243,7 +5250,7 @@ static void hevc_hv_biwgt_4t_8multx4_msa(uint8_t *src0_ptr, tmp0, tmp1, tmp2, tmp3); CLIP_SH4_0_255_MAX_SATU(tmp0, tmp1, tmp2, tmp3); PCKEV_B2_UB(tmp1, tmp0, tmp3, tmp2, out0, out1); - ST8x4_UB(out0, out1, dst, dst_stride); + ST_D4(out0, out1, 0, 1, 0, 1, dst, dst_stride); dst += 8; } } @@ -5394,9 +5401,8 @@ static void hevc_hv_biwgt_4t_8x6_msa(uint8_t *src0_ptr, PCKEV_H2_SH(dst1, dst0, dst3, dst2, tmp4, tmp5); CLIP_SH2_0_255_MAX_SATU(tmp4, tmp5); out2 = (v16u8) __msa_pckev_b((v16i8) tmp5, (v16i8) tmp4); - ST8x4_UB(out0, out1, dst, dst_stride); - dst += (4 * dst_stride); - ST8x2_UB(out2, dst, dst_stride); + ST_D4(out0, out1, 0, 1, 0, 1, dst, dst_stride); + ST_D2(out2, 0, 1, dst + 4 * dst_stride, dst_stride); } static void hevc_hv_biwgt_4t_8multx4mult_msa(uint8_t *src0_ptr, @@ -5533,7 +5539,7 @@ static void hevc_hv_biwgt_4t_8multx4mult_msa(uint8_t *src0_ptr, tmp0, tmp1, tmp2, tmp3); CLIP_SH4_0_255_MAX_SATU(tmp0, tmp1, tmp2, tmp3); PCKEV_B2_UB(tmp1, tmp0, tmp3, tmp2, out0, out1); - ST8x4_UB(out0, out1, dst_tmp, dst_stride); + ST_D4(out0, out1, 0, 1, 0, 1, dst_tmp, dst_stride); dst_tmp += (4 * dst_stride); dst10_r = dst54_r; @@ -5720,7 +5726,7 @@ static void hevc_hv_biwgt_4t_12w_msa(uint8_t *src0_ptr, tmp0, tmp1, tmp2, tmp3); CLIP_SH4_0_255_MAX_SATU(tmp0, tmp1, tmp2, tmp3); PCKEV_B2_UB(tmp1, tmp0, tmp3, tmp2, out0, out1); - ST8x4_UB(out0, out1, dst_tmp, dst_stride); + ST_D4(out0, out1, 0, 1, 0, 1, dst_tmp, dst_stride); dst_tmp += (4 * dst_stride); dst10_r = dst54_r; @@ -5816,7 +5822,7 @@ static void hevc_hv_biwgt_4t_12w_msa(uint8_t *src0_ptr, tmp0, tmp1, tmp2, tmp3); CLIP_SH4_0_255_MAX_SATU(tmp0, tmp1, tmp2, tmp3); PCKEV_B2_UB(tmp1, tmp0, tmp3, tmp2, out0, out1); - ST4x8_UB(out0, out1, dst, dst_stride); + ST_W8(out0, out1, 0, 1, 2, 3, 0, 1, 2, 3, dst, dst_stride); dst += (8 * dst_stride); dst10_r = dst98_r; diff --git a/libavcodec/mips/hevc_mc_uni_msa.c b/libavcodec/mips/hevc_mc_uni_msa.c index 740c970ca..36e65527a 100644 --- a/libavcodec/mips/hevc_mc_uni_msa.c +++ b/libavcodec/mips/hevc_mc_uni_msa.c @@ -309,7 +309,7 @@ static void common_hz_8t_4x4_msa(uint8_t *src, int32_t src_stride, SRARI_H2_SH(out0, out1, 6); SAT_SH2_SH(out0, out1, 7); out = PCKEV_XORI128_UB(out0, out1); - ST4x4_UB(out, out, 0, 1, 2, 3, dst, dst_stride); + ST_W4(out, 0, 1, 2, 3, dst, dst_stride); } static void common_hz_8t_4x8_msa(uint8_t *src, int32_t src_stride, @@ -344,10 +344,9 @@ static void common_hz_8t_4x8_msa(uint8_t *src, int32_t src_stride, SRARI_H4_SH(out0, out1, out2, out3, 6); SAT_SH4_SH(out0, out1, out2, out3, 7); out = PCKEV_XORI128_UB(out0, out1); - ST4x4_UB(out, out, 0, 1, 2, 3, dst, dst_stride); - dst += (4 * dst_stride); + ST_W4(out, 0, 1, 2, 3, dst, dst_stride); out = PCKEV_XORI128_UB(out2, out3); - ST4x4_UB(out, out, 0, 1, 2, 3, dst, dst_stride); + ST_W4(out, 0, 1, 2, 3, dst + 4 * dst_stride, dst_stride); } static void common_hz_8t_4x16_msa(uint8_t *src, int32_t src_stride, @@ -382,11 +381,10 @@ static void common_hz_8t_4x16_msa(uint8_t *src, int32_t src_stride, SRARI_H4_SH(out0, out1, out2, out3, 6); SAT_SH4_SH(out0, out1, out2, out3, 7); out = PCKEV_XORI128_UB(out0, out1); - ST4x4_UB(out, out, 0, 1, 2, 3, dst, dst_stride); - dst += (4 * dst_stride); + ST_W4(out, 0, 1, 2, 3, dst, dst_stride); out = PCKEV_XORI128_UB(out2, out3); - ST4x4_UB(out, out, 0, 1, 2, 3, dst, dst_stride); - dst += (4 * dst_stride); + ST_W4(out, 0, 1, 2, 3, dst + 4 * dst_stride, dst_stride); + dst += (8 * dst_stride); LD_SB4(src, src_stride, src0, src1, src2, src3); XORI_B4_128_SB(src0, src1, src2, src3); @@ -402,10 +400,9 @@ static void common_hz_8t_4x16_msa(uint8_t *src, int32_t src_stride, SRARI_H4_SH(out0, out1, out2, out3, 6); SAT_SH4_SH(out0, out1, out2, out3, 7); out = PCKEV_XORI128_UB(out0, out1); - ST4x4_UB(out, out, 0, 1, 2, 3, dst, dst_stride); - dst += (4 * dst_stride); + ST_W4(out, 0, 1, 2, 3, dst, dst_stride); out = PCKEV_XORI128_UB(out2, out3); - ST4x4_UB(out, out, 0, 1, 2, 3, dst, dst_stride); + ST_W4(out, 0, 1, 2, 3, dst + 4 * dst_stride, dst_stride); } static void common_hz_8t_4w_msa(uint8_t *src, int32_t src_stride, @@ -468,7 +465,7 @@ static void common_hz_8t_8w_msa(uint8_t *src, int32_t src_stride, SAT_SH4_SH(out0, out1, out2, out3, 7); tmp0 = PCKEV_XORI128_UB(out0, out1); tmp1 = PCKEV_XORI128_UB(out2, out3); - ST8x4_UB(tmp0, tmp1, dst, dst_stride); + ST_D4(tmp0, tmp1, 0, 1, 0, 1, dst, dst_stride); dst += (4 * dst_stride); } } @@ -546,8 +543,8 @@ static void common_hz_8t_12w_msa(uint8_t *src, int32_t src_stride, tmp1 = PCKEV_XORI128_UB(out2, out3); tmp2 = PCKEV_XORI128_UB(out4, out5); - ST8x4_UB(tmp0, tmp1, dst, dst_stride); - ST4x4_UB(tmp2, tmp2, 0, 1, 2, 3, dst + 8, dst_stride); + ST_D4(tmp0, tmp1, 0, 1, 0, 1, dst, dst_stride); + ST_W4(tmp2, 0, 1, 2, 3, dst + 8, dst_stride); dst += (4 * dst_stride); } } @@ -670,7 +667,7 @@ static void common_hz_8t_24w_msa(uint8_t *src, int32_t src_stride, SAT_SH4_SH(out0, out8, out2, out9, 7); SAT_SH2_SH(out1, out3, 7); out = PCKEV_XORI128_UB(out8, out9); - ST8x2_UB(out, dst + 16, dst_stride); + ST_D2(out, 0, 1, dst + 16, dst_stride); out = PCKEV_XORI128_UB(out0, out1); ST_UB(out, dst); dst += dst_stride; @@ -965,10 +962,8 @@ static void common_vt_8t_4w_msa(uint8_t *src, int32_t src_stride, SAT_SH2_SH(out54, out76, 7); out0 = PCKEV_XORI128_UB(out10, out32); out1 = PCKEV_XORI128_UB(out54, out76); - ST4x4_UB(out0, out0, 0, 1, 2, 3, dst, dst_stride); - dst += (4 * dst_stride); - ST4x4_UB(out1, out1, 0, 1, 2, 3, dst, dst_stride); - dst += (4 * dst_stride); + ST_W8(out0, out1, 0, 1, 2, 3, 0, 1, 2, 3, dst, dst_stride); + dst += (8 * dst_stride); src2110 = src10998; src4332 = src12111110; @@ -1019,7 +1014,7 @@ static void common_vt_8t_8w_msa(uint8_t *src, int32_t src_stride, SAT_SH4_SH(out0_r, out1_r, out2_r, out3_r, 7); tmp0 = PCKEV_XORI128_UB(out0_r, out1_r); tmp1 = PCKEV_XORI128_UB(out2_r, out3_r); - ST8x4_UB(tmp0, tmp1, dst, dst_stride); + ST_D4(tmp0, tmp1, 0, 1, 0, 1, dst, dst_stride); dst += (4 * dst_stride); src10_r = src54_r; @@ -1458,10 +1453,8 @@ static void hevc_hv_uni_8t_4w_msa(uint8_t *src, PCKEV_H2_SW(dst5_r, dst4_r, dst7_r, dst6_r, dst4_r, dst5_r); out0 = PCKEV_XORI128_UB(dst0_r, dst1_r); out1 = PCKEV_XORI128_UB(dst4_r, dst5_r); - ST4x4_UB(out0, out0, 0, 1, 2, 3, dst, dst_stride); - dst += (4 * dst_stride); - ST4x4_UB(out1, out1, 0, 1, 2, 3, dst, dst_stride); - dst += (4 * dst_stride); + ST_W8(out0, out1, 0, 1, 2, 3, 0, 1, 2, 3, dst, dst_stride); + dst += (8 * dst_stride); dst10_r = dst98_r; dst32_r = dst1110_r; @@ -1595,7 +1588,7 @@ static void hevc_hv_uni_8t_8multx2mult_msa(uint8_t *src, PCKEV_H2_SH(dst0_l, dst0_r, dst1_l, dst1_r, dst0, dst1); out = PCKEV_XORI128_UB(dst0, dst1); - ST8x2_UB(out, dst_tmp, dst_stride); + ST_D2(out, 0, 1, dst_tmp, dst_stride); dst_tmp += (2 * dst_stride); dst0 = dst2; @@ -1741,7 +1734,7 @@ static void hevc_hv_uni_8t_12w_msa(uint8_t *src, PCKEV_H2_SH(dst0_l, dst0_r, dst1_l, dst1_r, dst0, dst1); out0 = PCKEV_XORI128_UB(dst0, dst1); - ST8x2_UB(out0, dst_tmp, dst_stride); + ST_D2(out0, 0, 1, dst_tmp, dst_stride); dst_tmp += (2 * dst_stride); dst0 = dst2; @@ -1845,10 +1838,8 @@ static void hevc_hv_uni_8t_12w_msa(uint8_t *src, PCKEV_H2_SW(dst5_r, dst4_r, dst7_r, dst6_r, dst4_r, dst5_r); out0 = PCKEV_XORI128_UB(dst0_r, dst1_r); out1 = PCKEV_XORI128_UB(dst4_r, dst5_r); - ST4x4_UB(out0, out0, 0, 1, 2, 3, dst, dst_stride); - dst += (4 * dst_stride); - ST4x4_UB(out1, out1, 0, 1, 2, 3, dst, dst_stride); - dst += (4 * dst_stride); + ST_W8(out0, out1, 0, 1, 2, 3, 0, 1, 2, 3, dst, dst_stride); + dst += (8 * dst_stride); dst10_r = dst98_r; dst32_r = dst1110_r; @@ -1944,7 +1935,7 @@ static void common_hz_4t_4x2_msa(uint8_t *src, int32_t src_stride, res0 = __msa_srari_h(res0, 6); res0 = __msa_sat_s_h(res0, 7); out = PCKEV_XORI128_UB(res0, res0); - ST4x2_UB(out, dst, dst_stride); + ST_W2(out, 0, 1, dst, dst_stride); } static void common_hz_4t_4x4_msa(uint8_t *src, int32_t src_stride, @@ -1971,7 +1962,7 @@ static void common_hz_4t_4x4_msa(uint8_t *src, int32_t src_stride, SRARI_H2_SH(out0, out1, 6); SAT_SH2_SH(out0, out1, 7); out = PCKEV_XORI128_UB(out0, out1); - ST4x4_UB(out, out, 0, 1, 2, 3, dst, dst_stride); + ST_W4(out, 0, 1, 2, 3, dst, dst_stride); } static void common_hz_4t_4x8_msa(uint8_t *src, int32_t src_stride, @@ -2004,10 +1995,9 @@ static void common_hz_4t_4x8_msa(uint8_t *src, int32_t src_stride, SRARI_H4_SH(out0, out1, out2, out3, 6); SAT_SH4_SH(out0, out1, out2, out3, 7); out = PCKEV_XORI128_UB(out0, out1); - ST4x4_UB(out, out, 0, 1, 2, 3, dst, dst_stride); - dst += (4 * dst_stride); + ST_W4(out, 0, 1, 2, 3, dst, dst_stride); out = PCKEV_XORI128_UB(out2, out3); - ST4x4_UB(out, out, 0, 1, 2, 3, dst, dst_stride); + ST_W4(out, 0, 1, 2, 3, dst + 4 * dst_stride, dst_stride); } static void common_hz_4t_4x16_msa(uint8_t *src, int32_t src_stride, @@ -2038,11 +2028,10 @@ static void common_hz_4t_4x16_msa(uint8_t *src, int32_t src_stride, SRARI_H4_SH(out0, out1, out2, out3, 6); SAT_SH4_SH(out0, out1, out2, out3, 7); out = PCKEV_XORI128_UB(out0, out1); - ST4x4_UB(out, out, 0, 1, 2, 3, dst, dst_stride); - dst += (4 * dst_stride); + ST_W4(out, 0, 1, 2, 3, dst, dst_stride); out = PCKEV_XORI128_UB(out2, out3); - ST4x4_UB(out, out, 0, 1, 2, 3, dst, dst_stride); - dst += (4 * dst_stride); + ST_W4(out, 0, 1, 2, 3, dst + 4 * dst_stride, dst_stride); + dst += (8 * dst_stride); LD_SB8(src, src_stride, src0, src1, src2, src3, src4, src5, src6, src7); src += (8 * src_stride); @@ -2054,10 +2043,9 @@ static void common_hz_4t_4x16_msa(uint8_t *src, int32_t src_stride, SRARI_H4_SH(out0, out1, out2, out3, 6); SAT_SH4_SH(out0, out1, out2, out3, 7); out = PCKEV_XORI128_UB(out0, out1); - ST4x4_UB(out, out, 0, 1, 2, 3, dst, dst_stride); - dst += (4 * dst_stride); + ST_W4(out, 0, 1, 2, 3, dst, dst_stride); out = PCKEV_XORI128_UB(out2, out3); - ST4x4_UB(out, out, 0, 1, 2, 3, dst, dst_stride); + ST_W4(out, 0, 1, 2, 3, dst + 4 * dst_stride, dst_stride); } static void common_hz_4t_4w_msa(uint8_t *src, int32_t src_stride, @@ -2102,7 +2090,10 @@ static void common_hz_4t_6w_msa(uint8_t *src, int32_t src_stride, SAT_SH4_SH(out0, out1, out2, out3, 7); out4 = PCKEV_XORI128_UB(out0, out1); out5 = PCKEV_XORI128_UB(out2, out3); - ST6x4_UB(out4, out5, dst, dst_stride); + ST_W2(out4, 0, 2, dst, dst_stride); + ST_H2(out4, 2, 6, dst + 4, dst_stride); + ST_W2(out5, 0, 2, dst + 2 * dst_stride, dst_stride); + ST_H2(out5, 2, 6, dst + 2 * dst_stride + 4, dst_stride); dst += (4 * dst_stride); LD_SB4(src, src_stride, src0, src1, src2, src3); @@ -2115,8 +2106,10 @@ static void common_hz_4t_6w_msa(uint8_t *src, int32_t src_stride, SAT_SH4_SH(out0, out1, out2, out3, 7); out4 = PCKEV_XORI128_UB(out0, out1); out5 = PCKEV_XORI128_UB(out2, out3); - ST6x4_UB(out4, out5, dst, dst_stride); - dst += (4 * dst_stride); + ST_W2(out4, 0, 2, dst, dst_stride); + ST_H2(out4, 2, 6, dst + 4, dst_stride); + ST_W2(out5, 0, 2, dst + 2 * dst_stride, dst_stride); + ST_H2(out5, 2, 6, dst + 2 * dst_stride + 4, dst_stride); } static void common_hz_4t_8x2mult_msa(uint8_t *src, int32_t src_stride, @@ -2148,7 +2141,7 @@ static void common_hz_4t_8x2mult_msa(uint8_t *src, int32_t src_stride, SRARI_H2_SH(vec0, vec1, 6); SAT_SH2_SH(vec0, vec1, 7); out = PCKEV_XORI128_UB(vec0, vec1); - ST8x2_UB(out, dst, dst_stride); + ST_D2(out, 0, 1, dst, dst_stride); dst += (2 * dst_stride); } } @@ -2182,7 +2175,7 @@ static void common_hz_4t_8x4mult_msa(uint8_t *src, int32_t src_stride, SAT_SH4_SH(out0, out1, out2, out3, 7); tmp0 = PCKEV_XORI128_UB(out0, out1); tmp1 = PCKEV_XORI128_UB(out2, out3); - ST8x4_UB(tmp0, tmp1, dst, dst_stride); + ST_D4(tmp0, tmp1, 0, 1, 0, 1, dst, dst_stride); dst += (4 * dst_stride); } } @@ -2235,7 +2228,7 @@ static void common_hz_4t_12w_msa(uint8_t *src, int32_t src_stride, SRARI_H2_SH(out0, out1, 6); SAT_SH2_SH(out0, out1, 7); tmp0 = PCKEV_XORI128_UB(out0, out1); - ST4x4_UB(tmp0, tmp0, 0, 1, 2, 3, dst + 8, dst_stride); + ST_W4(tmp0, 0, 1, 2, 3, dst + 8, dst_stride); VSHF_B2_SB(src0, src0, src1, src1, mask0, mask0, vec4, vec5); VSHF_B2_SB(src2, src2, src3, src3, mask0, mask0, vec6, vec7); @@ -2249,7 +2242,7 @@ static void common_hz_4t_12w_msa(uint8_t *src, int32_t src_stride, SAT_SH4_SH(out2, out3, out4, out5, 7); tmp0 = PCKEV_XORI128_UB(out2, out3); tmp1 = PCKEV_XORI128_UB(out4, out5); - ST8x4_UB(tmp0, tmp1, dst, dst_stride); + ST_D4(tmp0, tmp1, 0, 1, 0, 1, dst, dst_stride); dst += (4 * dst_stride); } } @@ -2395,7 +2388,7 @@ static void common_hz_4t_24w_msa(uint8_t *src, int32_t src_stride, SAT_SH4_SH(out0, out1, out2, out3, 7); tmp0 = PCKEV_XORI128_UB(out0, out1); tmp1 = PCKEV_XORI128_UB(out2, out3); - ST8x4_UB(tmp0, tmp1, dst1, dst_stride); + ST_D4(tmp0, tmp1, 0, 1, 0, 1, dst1, dst_stride); dst1 += (4 * dst_stride); } } @@ -2496,7 +2489,7 @@ static void common_vt_4t_4x2_msa(uint8_t *src, int32_t src_stride, out10 = __msa_srari_h(out10, 6); out10 = __msa_sat_s_h(out10, 7); out = PCKEV_XORI128_UB(out10, out10); - ST4x2_UB(out, dst, dst_stride); + ST_W2(out, 0, 1, dst, dst_stride); } static void common_vt_4t_4x4multiple_msa(uint8_t *src, int32_t src_stride, @@ -2540,7 +2533,7 @@ static void common_vt_4t_4x4multiple_msa(uint8_t *src, int32_t src_stride, SRARI_H2_SH(out10, out32, 6); SAT_SH2_SH(out10, out32, 7); out = PCKEV_XORI128_UB(out10, out32); - ST4x4_UB(out, out, 0, 1, 2, 3, dst, dst_stride); + ST_W4(out, 0, 1, 2, 3, dst, dst_stride); dst += (4 * dst_stride); } } @@ -2596,7 +2589,10 @@ static void common_vt_4t_6w_msa(uint8_t *src, int32_t src_stride, SAT_SH4_SH(dst0_r, dst1_r, dst2_r, dst3_r, 7); out0 = PCKEV_XORI128_UB(dst0_r, dst1_r); out1 = PCKEV_XORI128_UB(dst2_r, dst3_r); - ST6x4_UB(out0, out1, dst, dst_stride); + ST_W2(out0, 0, 2, dst, dst_stride); + ST_H2(out0, 2, 6, dst + 4, dst_stride); + ST_W2(out1, 0, 2, dst + 2 * dst_stride, dst_stride); + ST_H2(out1, 2, 6, dst + 2 * dst_stride + 4, dst_stride); dst += (4 * dst_stride); LD_SB2(src, src_stride, src3, src4); @@ -2619,7 +2615,10 @@ static void common_vt_4t_6w_msa(uint8_t *src, int32_t src_stride, SAT_SH4_SH(dst0_r, dst1_r, dst2_r, dst3_r, 7); out0 = PCKEV_XORI128_UB(dst0_r, dst1_r); out1 = PCKEV_XORI128_UB(dst2_r, dst3_r); - ST6x4_UB(out0, out1, dst, dst_stride); + ST_W2(out0, 0, 2, dst, dst_stride); + ST_H2(out0, 2, 6, dst + 4, dst_stride); + ST_W2(out1, 0, 2, dst + 2 * dst_stride, dst_stride); + ST_H2(out1, 2, 6, dst + 2 * dst_stride + 4, dst_stride); } static void common_vt_4t_8x2_msa(uint8_t *src, int32_t src_stride, @@ -2645,7 +2644,7 @@ static void common_vt_4t_8x2_msa(uint8_t *src, int32_t src_stride, SRARI_H2_SH(tmp0, tmp1, 6); SAT_SH2_SH(tmp0, tmp1, 7); out = PCKEV_XORI128_UB(tmp0, tmp1); - ST8x2_UB(out, dst, dst_stride); + ST_D2(out, 0, 1, dst, dst_stride); } static void common_vt_4t_8x6_msa(uint8_t *src, int32_t src_stride, @@ -2737,7 +2736,7 @@ static void common_vt_4t_8x4mult_msa(uint8_t *src, int32_t src_stride, SAT_SH4_SH(out0_r, out1_r, out2_r, out3_r, 7); tmp0 = PCKEV_XORI128_UB(out0_r, out1_r); tmp1 = PCKEV_XORI128_UB(out2_r, out3_r); - ST8x4_UB(tmp0, tmp1, dst, dst_stride); + ST_D4(tmp0, tmp1, 0, 1, 0, 1, dst, dst_stride); dst += (4 * dst_stride); src10_r = src98_r; @@ -2811,9 +2810,9 @@ static void common_vt_4t_12w_msa(uint8_t *src, int32_t src_stride, SAT_SH2_SH(dst0_l, dst1_l, 7); out0 = PCKEV_XORI128_UB(dst0_r, dst1_r); out1 = PCKEV_XORI128_UB(dst2_r, dst3_r); - ST8x4_UB(out0, out1, dst, dst_stride); + ST_D4(out0, out1, 0, 1, 0, 1, dst, dst_stride); out0 = PCKEV_XORI128_UB(dst0_l, dst1_l); - ST4x4_UB(out0, out0, 0, 1, 2, 3, dst + 8, dst_stride); + ST_W4(out0, 0, 1, 2, 3, dst + 8, dst_stride); dst += (4 * dst_stride); src2 = src6; @@ -2982,12 +2981,12 @@ static void common_vt_4t_24w_msa(uint8_t *src, int32_t src_stride, out = PCKEV_XORI128_UB(out0_r, out0_l); ST_UB(out, dst); out = PCKEV_XORI128_UB(out2_r, out2_r); - ST8x1_UB(out, dst + 16); + ST_D1(out, 0, dst + 16); dst += dst_stride; out = PCKEV_XORI128_UB(out1_r, out1_l); ST_UB(out, dst); out = PCKEV_XORI128_UB(out3_r, out3_r); - ST8x1_UB(out, dst + 16); + ST_D1(out, 0, dst + 16); dst += dst_stride; } } @@ -3137,7 +3136,7 @@ static void hevc_hv_uni_4t_4x2_msa(uint8_t *src, tmp = __msa_srari_h(tmp, 6); tmp = __msa_sat_s_h(tmp, 7); out = PCKEV_XORI128_UB(tmp, tmp); - ST4x2_UB(out, dst, dst_stride); + ST_W2(out, 0, 1, dst, dst_stride); } static void hevc_hv_uni_4t_4x4_msa(uint8_t *src, @@ -3196,7 +3195,7 @@ static void hevc_hv_uni_4t_4x4_msa(uint8_t *src, SRARI_H2_SH(tmp0, tmp1, 6); SAT_SH2_SH(tmp0, tmp1, 7); out = PCKEV_XORI128_UB(tmp0, tmp1); - ST4x4_UB(out, out, 0, 1, 2, 3, dst, dst_stride); + ST_W4(out, 0, 1, 2, 3, dst, dst_stride); } static void hevc_hv_uni_4t_4multx8mult_msa(uint8_t *src, @@ -3288,7 +3287,7 @@ static void hevc_hv_uni_4t_4multx8mult_msa(uint8_t *src, SAT_SH4_SH(tmp0, tmp1, tmp2, tmp3, 7); out0 = PCKEV_XORI128_UB(tmp0, tmp1); out1 = PCKEV_XORI128_UB(tmp2, tmp3); - ST4x8_UB(out0, out1, dst, dst_stride); + ST_W8(out0, out1, 0, 1, 2, 3, 0, 1, 2, 3, dst, dst_stride); dst += (8 * dst_stride); dst10_r = dst98_r; @@ -3432,10 +3431,8 @@ static void hevc_hv_uni_4t_6w_msa(uint8_t *src, out0 = PCKEV_XORI128_UB(tmp0, tmp1); out1 = PCKEV_XORI128_UB(tmp2, tmp3); out2 = PCKEV_XORI128_UB(tmp4, tmp5); - ST4x8_UB(out0, out1, dst, dst_stride); - ST2x4_UB(out2, 0, dst + 4, dst_stride); - dst += 4 * dst_stride; - ST2x4_UB(out2, 4, dst + 4, dst_stride); + ST_W8(out0, out1, 0, 1, 2, 3, 0, 1, 2, 3, dst, dst_stride); + ST_H8(out2, 0, 1, 2, 3, 4, 5, 6, 7, dst + 4, dst_stride); } static void hevc_hv_uni_4t_8x2_msa(uint8_t *src, @@ -3497,7 +3494,7 @@ static void hevc_hv_uni_4t_8x2_msa(uint8_t *src, SRARI_H2_SH(out0_r, out1_r, 6); SAT_SH2_SH(out0_r, out1_r, 7); out = PCKEV_XORI128_UB(out0_r, out1_r); - ST8x2_UB(out, dst, dst_stride); + ST_D2(out, 0, 1, dst, dst_stride); } static void hevc_hv_uni_4t_8multx4_msa(uint8_t *src, @@ -3580,7 +3577,7 @@ static void hevc_hv_uni_4t_8multx4_msa(uint8_t *src, SAT_SH4_SH(tmp0, tmp1, tmp2, tmp3, 7); out0 = PCKEV_XORI128_UB(tmp0, tmp1); out1 = PCKEV_XORI128_UB(tmp2, tmp3); - ST8x4_UB(out0, out1, dst, dst_stride); + ST_D4(out0, out1, 0, 1, 0, 1, dst, dst_stride); dst += 8; } } @@ -3684,9 +3681,8 @@ static void hevc_hv_uni_4t_8x6_msa(uint8_t *src, out1 = PCKEV_XORI128_UB(out2_r, out3_r); out2 = PCKEV_XORI128_UB(out4_r, out5_r); - ST8x4_UB(out0, out1, dst, dst_stride); - dst += (4 * dst_stride); - ST8x2_UB(out2, dst, dst_stride); + ST_D4(out0, out1, 0, 1, 0, 1, dst, dst_stride); + ST_D2(out2, 0, 1, dst + 4 * dst_stride, dst_stride); } static void hevc_hv_uni_4t_8multx4mult_msa(uint8_t *src, @@ -3788,7 +3784,7 @@ static void hevc_hv_uni_4t_8multx4mult_msa(uint8_t *src, SAT_SH4_SH(out0_r, out1_r, out2_r, out3_r, 7); out0 = PCKEV_XORI128_UB(out0_r, out1_r); out1 = PCKEV_XORI128_UB(out2_r, out3_r); - ST8x4_UB(out0, out1, dst_tmp, dst_stride); + ST_D4(out0, out1, 0, 1, 0, 1, dst_tmp, dst_stride); dst_tmp += (4 * dst_stride); dst10_r = dst54_r; @@ -3919,7 +3915,7 @@ static void hevc_hv_uni_4t_12w_msa(uint8_t *src, SAT_SH4_SH(tmp0, tmp1, tmp2, tmp3, 7); out0 = PCKEV_XORI128_UB(tmp0, tmp1); out1 = PCKEV_XORI128_UB(tmp2, tmp3); - ST8x4_UB(out0, out1, dst_tmp, dst_stride); + ST_D4(out0, out1, 0, 1, 0, 1, dst_tmp, dst_stride); dst_tmp += (4 * dst_stride); dst10_r = dst54_r; @@ -3985,7 +3981,7 @@ static void hevc_hv_uni_4t_12w_msa(uint8_t *src, SAT_SH4_SH(tmp0, tmp1, tmp2, tmp3, 7); out0 = PCKEV_XORI128_UB(tmp0, tmp1); out1 = PCKEV_XORI128_UB(tmp2, tmp3); - ST4x8_UB(out0, out1, dst, dst_stride); + ST_W8(out0, out1, 0, 1, 2, 3, 0, 1, 2, 3, dst, dst_stride); dst += (8 * dst_stride); dst10_r = dst98_r; diff --git a/libavcodec/mips/hevc_mc_uniw_msa.c b/libavcodec/mips/hevc_mc_uniw_msa.c index f9ecb414b..cad1240b4 100644 --- a/libavcodec/mips/hevc_mc_uniw_msa.c +++ b/libavcodec/mips/hevc_mc_uniw_msa.c @@ -90,7 +90,7 @@ static void hevc_uniwgt_copy_4w_msa(uint8_t *src, dst0 += offset_vec; dst0 = CLIP_SH_0_255_MAX_SATU(dst0); out0 = (v16u8) __msa_pckev_b((v16i8) dst0, (v16i8) dst0); - ST4x2_UB(out0, dst, dst_stride); + ST_W2(out0, 0, 1, dst, dst_stride); } else if (4 == height) { LW4(src, src_stride, tp0, tp1, tp2, tp3); INSERT_W4_SB(tp0, tp1, tp2, tp3, src0); @@ -99,7 +99,7 @@ static void hevc_uniwgt_copy_4w_msa(uint8_t *src, HEVC_UNIW_RND_CLIP2_MAX_SATU_H(dst0, dst1, weight_vec, offset_vec, rnd_vec, dst0, dst1); out0 = (v16u8) __msa_pckev_b((v16i8) dst1, (v16i8) dst0); - ST4x4_UB(out0, out0, 0, 1, 2, 3, dst, dst_stride); + ST_W4(out0, 0, 1, 2, 3, dst, dst_stride); } else if (0 == (height % 8)) { for (loop_cnt = (height >> 3); loop_cnt--;) { LW4(src, src_stride, tp0, tp1, tp2, tp3); @@ -115,7 +115,7 @@ static void hevc_uniwgt_copy_4w_msa(uint8_t *src, offset_vec, rnd_vec, dst0, dst1, dst2, dst3); PCKEV_B2_UB(dst1, dst0, dst3, dst2, out0, out1); - ST4x8_UB(out0, out1, dst, dst_stride); + ST_W8(out0, out1, 0, 1, 2, 3, 0, 1, 2, 3, dst, dst_stride); dst += 8 * dst_stride; } } @@ -170,9 +170,15 @@ static void hevc_uniwgt_copy_6w_msa(uint8_t *src, PCKEV_B2_UB(dst1, dst0, dst3, dst2, out0, out1); PCKEV_B2_UB(dst5, dst4, dst7, dst6, out2, out3); - ST6x4_UB(out0, out1, dst, dst_stride); + ST_W2(out0, 0, 2, dst, dst_stride); + ST_H2(out0, 2, 6, dst + 4, dst_stride); + ST_W2(out1, 0, 2, dst + 2 * dst_stride, dst_stride); + ST_H2(out1, 2, 6, dst + 2 * dst_stride + 4, dst_stride); dst += (4 * dst_stride); - ST6x4_UB(out2, out3, dst, dst_stride); + ST_W2(out2, 0, 2, dst, dst_stride); + ST_H2(out2, 2, 6, dst + 4, dst_stride); + ST_W2(out3, 0, 2, dst + 2 * dst_stride, dst_stride); + ST_H2(out3, 2, 6, dst + 2 * dst_stride + 4, dst_stride); dst += (4 * dst_stride); } } @@ -207,7 +213,7 @@ static void hevc_uniwgt_copy_8w_msa(uint8_t *src, HEVC_UNIW_RND_CLIP2_MAX_SATU_H(dst0, dst1, weight_vec, offset_vec, rnd_vec, dst0, dst1); out0 = (v16u8) __msa_pckev_b((v16i8) dst1, (v16i8) dst0); - ST8x2_UB(out0, dst, dst_stride); + ST_D2(out0, 0, 1, dst, dst_stride); } else if (4 == height) { LD4(src, src_stride, tp0, tp1, tp2, tp3); INSERT_D2_SB(tp0, tp1, src0); @@ -219,7 +225,7 @@ static void hevc_uniwgt_copy_8w_msa(uint8_t *src, offset_vec, rnd_vec, dst0, dst1, dst2, dst3); PCKEV_B2_UB(dst1, dst0, dst3, dst2, out0, out1); - ST8x4_UB(out0, out1, dst, dst_stride); + ST_D4(out0, out1, 0, 1, 0, 1, dst, dst_stride); } else if (6 == height) { LD4(src, src_stride, tp0, tp1, tp2, tp3); src += 4 * src_stride; @@ -238,9 +244,8 @@ static void hevc_uniwgt_copy_8w_msa(uint8_t *src, HEVC_UNIW_RND_CLIP2_MAX_SATU_H(dst4, dst5, weight_vec, offset_vec, rnd_vec, dst4, dst5); PCKEV_B3_UB(dst1, dst0, dst3, dst2, dst5, dst4, out0, out1, out2); - ST8x4_UB(out0, out1, dst, dst_stride); - dst += (4 * dst_stride); - ST8x2_UB(out2, dst, dst_stride); + ST_D4(out0, out1, 0, 1, 0, 1, dst, dst_stride); + ST_D2(out2, 0, 1, dst + 4 * dst_stride, dst_stride); } else if (0 == height % 8) { for (loop_cnt = (height >> 3); loop_cnt--;) { LD4(src, src_stride, tp0, tp1, tp2, tp3); @@ -266,10 +271,9 @@ static void hevc_uniwgt_copy_8w_msa(uint8_t *src, dst6, dst7); PCKEV_B2_UB(dst1, dst0, dst3, dst2, out0, out1); PCKEV_B2_UB(dst5, dst4, dst7, dst6, out2, out3); - ST8x4_UB(out0, out1, dst, dst_stride); - dst += (4 * dst_stride); - ST8x4_UB(out2, out3, dst, dst_stride); - dst += (4 * dst_stride); + ST_D8(out0, out1, out2, out3, 0, 1, 0, 1, 0, 1, 0, 1, + dst, dst_stride); + dst += (8 * dst_stride); } } } @@ -313,7 +317,8 @@ static void hevc_uniwgt_copy_12w_msa(uint8_t *src, rnd_vec, dst4, dst5); PCKEV_B3_UB(dst1, dst0, dst3, dst2, dst5, dst4, out0, out1, out2); - ST12x4_UB(out0, out1, out2, dst, dst_stride); + ST_D4(out0, out1, 0, 1, 0, 1, dst, dst_stride); + ST_W4(out2, 0, 1, 2, 3, dst + 8, dst_stride); dst += (4 * dst_stride); } } @@ -409,7 +414,7 @@ static void hevc_uniwgt_copy_24w_msa(uint8_t *src, PCKEV_B3_UB(dst1, dst0, dst3, dst2, dst5, dst4, out0, out1, out2); PCKEV_B3_UB(dst7, dst6, dst9, dst8, dst11, dst10, out3, out4, out5); ST_UB4(out0, out1, out3, out4, dst, dst_stride); - ST8x4_UB(out2, out5, dst + 16, dst_stride); + ST_D4(out2, out5, 0, 1, 0, 1, dst + 16, dst_stride); dst += (4 * dst_stride); } } @@ -651,7 +656,7 @@ static void hevc_hz_uniwgt_8t_4w_msa(uint8_t *src, dst3); PCKEV_B2_UB(dst1, dst0, dst3, dst2, out0, out1); - ST4x8_UB(out0, out1, dst, dst_stride); + ST_W8(out0, out1, 0, 1, 2, 3, 0, 1, 2, 3, dst, dst_stride); dst += (8 * dst_stride); } } @@ -729,7 +734,7 @@ static void hevc_hz_uniwgt_8t_8w_msa(uint8_t *src, dst3); PCKEV_B2_UB(dst1, dst0, dst3, dst2, out0, out1); - ST8x4_UB(out0, out1, dst, dst_stride); + ST_D4(out0, out1, 0, 1, 0, 1, dst, dst_stride); dst += (4 * dst_stride); } } @@ -822,8 +827,8 @@ static void hevc_hz_uniwgt_8t_12w_msa(uint8_t *src, rnd_vec, dst4, dst5); PCKEV_B3_UB(dst1, dst0, dst3, dst2, dst5, dst4, out0, out1, out2); - ST8x4_UB(out0, out1, dst, dst_stride); - ST4x4_UB(out2, out2, 0, 1, 2, 3, dst + 8, dst_stride); + ST_D4(out0, out1, 0, 1, 0, 1, dst, dst_stride); + ST_W4(out2, 0, 1, 2, 3, dst + 8, dst_stride); dst += (4 * dst_stride); } } @@ -994,7 +999,7 @@ static void hevc_hz_uniwgt_8t_24w_msa(uint8_t *src, PCKEV_B3_UB(dst1, dst0, dst4, dst3, dst5, dst2, out0, out1, out2); ST_UB2(out0, out1, dst, dst_stride); - ST8x2_UB(out2, dst + 16, dst_stride); + ST_D2(out2, 0, 1, dst + 16, dst_stride); dst += (2 * dst_stride); } } @@ -1368,7 +1373,7 @@ static void hevc_vt_uniwgt_8t_4w_msa(uint8_t *src, dst3); PCKEV_B2_UB(dst1, dst0, dst3, dst2, out0, out1); - ST4x8_UB(out0, out1, dst, dst_stride); + ST_W8(out0, out1, 0, 1, 2, 3, 0, 1, 2, 3, dst, dst_stride); dst += (8 * dst_stride); src2110 = src10998; @@ -1444,7 +1449,7 @@ static void hevc_vt_uniwgt_8t_8w_msa(uint8_t *src, dst3); PCKEV_B2_UB(dst1, dst0, dst3, dst2, out0, out1); - ST8x4_UB(out0, out1, dst, dst_stride); + ST_D4(out0, out1, 0, 1, 0, 1, dst, dst_stride); dst += (4 * dst_stride); src10_r = src54_r; @@ -1543,8 +1548,8 @@ static void hevc_vt_uniwgt_8t_12w_msa(uint8_t *src, rnd_vec, dst4, dst5); PCKEV_B3_UB(dst1, dst0, dst3, dst2, dst5, dst4, out0, out1, out2); - ST8x4_UB(out0, out1, dst, dst_stride); - ST4x4_UB(out2, out2, 0, 1, 2, 3, dst + 8, dst_stride); + ST_D4(out0, out1, 0, 1, 0, 1, dst, dst_stride); + ST_W4(out2, 0, 1, 2, 3, dst + 8, dst_stride); dst += (4 * dst_stride); src10_r = src54_r; @@ -1861,7 +1866,7 @@ static void hevc_hv_uniwgt_8t_4w_msa(uint8_t *src, CLIP_SW4_0_255_MAX_SATU(dst0_r, dst1_r, dst2_r, dst3_r); PCKEV_H2_SW(dst1_r, dst0_r, dst3_r, dst2_r, dst0_r, dst1_r); out = (v16u8) __msa_pckev_b((v16i8) dst1_r, (v16i8) dst0_r); - ST4x4_UB(out, out, 0, 1, 2, 3, dst, dst_stride); + ST_W4(out, 0, 1, 2, 3, dst, dst_stride); dst += (4 * dst_stride); dst10_r = dst54_r; @@ -2013,7 +2018,7 @@ static void hevc_hv_uniwgt_8t_8multx2mult_msa(uint8_t *src, PCKEV_H2_SW(dst0_l, dst0_r, dst1_l, dst1_r, dst0_r, dst1_r); dst0_r = (v4i32) __msa_pckev_b((v16i8) dst1_r, (v16i8) dst0_r); - ST8x2_UB(dst0_r, dst_tmp, dst_stride); + ST_D2(dst0_r, 0, 1, dst_tmp, dst_stride); dst_tmp += (2 * dst_stride); dst10_r = dst32_r; @@ -2163,7 +2168,7 @@ static void hevc_hv_uniwgt_8t_12w_msa(uint8_t *src, CLIP_SW2_0_255_MAX_SATU(dst0_r, dst0_l); dst0_r = (v4i32) __msa_pckev_h((v8i16) dst0_l, (v8i16) dst0_r); out = (v16u8) __msa_pckev_b((v16i8) dst0_r, (v16i8) dst0_r); - ST8x1_UB(out, dst_tmp); + ST_D1(out, 0, dst_tmp); dst_tmp += dst_stride; dst0 = dst1; @@ -2244,7 +2249,7 @@ static void hevc_hv_uniwgt_8t_12w_msa(uint8_t *src, CLIP_SW4_0_255_MAX_SATU(dst0_r, dst1_r, dst2_r, dst3_r); PCKEV_H2_SW(dst1_r, dst0_r, dst3_r, dst2_r, dst0_r, dst1_r); out = (v16u8) __msa_pckev_b((v16i8) dst1_r, (v16i8) dst0_r); - ST4x4_UB(out, out, 0, 1, 2, 3, dst, dst_stride); + ST_W4(out, 0, 1, 2, 3, dst, dst_stride); dst += (4 * dst_stride); dst10_r = dst54_r; @@ -2391,7 +2396,7 @@ static void hevc_hz_uniwgt_4t_4x2_msa(uint8_t *src, dst0 = __msa_adds_s_h(dst0, offset_vec); dst0 = CLIP_SH_0_255_MAX_SATU(dst0); out = (v16u8) __msa_pckev_b((v16i8) dst0, (v16i8) dst0); - ST4x2_UB(out, dst, dst_stride); + ST_W2(out, 0, 1, dst, dst_stride); dst += (4 * dst_stride); } @@ -2448,7 +2453,7 @@ static void hevc_hz_uniwgt_4t_4x4_msa(uint8_t *src, dst0, dst1); out = (v16u8) __msa_pckev_b((v16i8) dst1, (v16i8) dst0); - ST4x4_UB(out, out, 0, 1, 2, 3, dst, dst_stride); + ST_W4(out, 0, 1, 2, 3, dst, dst_stride); dst += (4 * dst_stride); } @@ -2515,7 +2520,7 @@ static void hevc_hz_uniwgt_4t_4x8multiple_msa(uint8_t *src, dst0, dst1, dst2, dst3); PCKEV_B2_UB(dst1, dst0, dst3, dst2, out0, out1); - ST4x8_UB(out0, out1, dst, dst_stride); + ST_W8(out0, out1, 0, 1, 2, 3, 0, 1, 2, 3, dst, dst_stride); dst += (8 * dst_stride); } } @@ -2613,9 +2618,15 @@ static void hevc_hz_uniwgt_4t_6w_msa(uint8_t *src, PCKEV_B2_UB(dst1, dst0, dst3, dst2, out0, out1); PCKEV_B2_UB(dst5, dst4, dst7, dst6, out2, out3); - ST6x4_UB(out0, out1, dst, dst_stride); + ST_W2(out0, 0, 2, dst, dst_stride); + ST_H2(out0, 2, 6, dst + 4, dst_stride); + ST_W2(out1, 0, 2, dst + 2 * dst_stride, dst_stride); + ST_H2(out1, 2, 6, dst + 2 * dst_stride + 4, dst_stride); dst += (4 * dst_stride); - ST6x4_UB(out2, out3, dst, dst_stride); + ST_W2(out2, 0, 2, dst, dst_stride); + ST_H2(out2, 2, 6, dst + 4, dst_stride); + ST_W2(out3, 0, 2, dst + 2 * dst_stride, dst_stride); + ST_H2(out3, 2, 6, dst + 2 * dst_stride + 4, dst_stride); } static void hevc_hz_uniwgt_4t_8x2_msa(uint8_t *src, @@ -2670,7 +2681,7 @@ static void hevc_hz_uniwgt_4t_8x2_msa(uint8_t *src, dst0, dst1); out = (v16u8) __msa_pckev_b((v16i8) dst1, (v16i8) dst0); - ST8x2_UB(out, dst, dst_stride); + ST_D2(out, 0, 1, dst, dst_stride); } static void hevc_hz_uniwgt_4t_8x4_msa(uint8_t *src, @@ -2727,7 +2738,7 @@ static void hevc_hz_uniwgt_4t_8x4_msa(uint8_t *src, dst0, dst1, dst2, dst3); PCKEV_B2_UB(dst1, dst0, dst3, dst2, out0, out1); - ST8x4_UB(out0, out1, dst, dst_stride); + ST_D4(out0, out1, 0, 1, 0, 1, dst, dst_stride); } static void hevc_hz_uniwgt_4t_8x6_msa(uint8_t *src, @@ -2796,9 +2807,8 @@ static void hevc_hz_uniwgt_4t_8x6_msa(uint8_t *src, dst4, dst5); PCKEV_B3_UB(dst1, dst0, dst3, dst2, dst5, dst4, out0, out1, out2); - ST8x4_UB(out0, out1, dst, dst_stride); - dst += (4 * dst_stride); - ST8x2_UB(out2, dst, dst_stride); + ST_D4(out0, out1, 0, 1, 0, 1, dst, dst_stride); + ST_D2(out2, 0, 1, dst + 4 * dst_stride, dst_stride); } static void hevc_hz_uniwgt_4t_8x8multiple_msa(uint8_t *src, @@ -2876,7 +2886,7 @@ static void hevc_hz_uniwgt_4t_8x8multiple_msa(uint8_t *src, PCKEV_B2_UB(dst1, dst0, dst3, dst2, out0, out1); PCKEV_B2_UB(dst5, dst4, dst7, dst6, out2, out3); - ST8x8_UB(out0, out1, out2, out3, dst, dst_stride); + ST_D8(out0, out1, out2, out3, 0, 1, 0, 1, 0, 1, 0, 1, dst, dst_stride); dst += (8 * dst_stride); } } @@ -2981,7 +2991,8 @@ static void hevc_hz_uniwgt_4t_12w_msa(uint8_t *src, rnd_vec, dst4, dst5); PCKEV_B3_UB(dst1, dst0, dst3, dst2, dst5, dst4, out0, out1, out2); - ST12x4_UB(out0, out1, out2, dst, dst_stride); + ST_D4(out0, out1, 0, 1, 0, 1, dst, dst_stride); + ST_W4(out2, 0, 1, 2, 3, dst + 8, dst_stride); dst += (4 * dst_stride); } } @@ -3142,7 +3153,7 @@ static void hevc_hz_uniwgt_4t_24w_msa(uint8_t *src, PCKEV_B3_UB(dst1, dst0, dst3, dst2, dst5, dst4, out0, out1, out2); ST_UB2(out0, out1, dst, dst_stride); - ST8x2_UB(out2, dst + 16, dst_stride); + ST_D2(out2, 0, 1, dst + 16, dst_stride); dst += (2 * dst_stride); } } @@ -3286,7 +3297,7 @@ static void hevc_vt_uniwgt_4t_4x2_msa(uint8_t *src, dst0 = __msa_adds_s_h(dst0, offset_vec); dst0 = CLIP_SH_0_255_MAX_SATU(dst0); out = (v16u8) __msa_pckev_b((v16i8) dst0, (v16i8) dst0); - ST4x2_UB(out, dst, dst_stride); + ST_W2(out, 0, 1, dst, dst_stride); } static void hevc_vt_uniwgt_4t_4x4_msa(uint8_t *src, @@ -3340,7 +3351,7 @@ static void hevc_vt_uniwgt_4t_4x4_msa(uint8_t *src, dst0, dst1); out = (v16u8) __msa_pckev_b((v16i8) dst1, (v16i8) dst0); - ST4x4_UB(out, out, 0, 1, 2, 3, dst, dst_stride); + ST_W4(out, 0, 1, 2, 3, dst, dst_stride); } static void hevc_vt_uniwgt_4t_4x8multiple_msa(uint8_t *src, @@ -3411,7 +3422,7 @@ static void hevc_vt_uniwgt_4t_4x8multiple_msa(uint8_t *src, dst0, dst1, dst2, dst3); PCKEV_B2_UB(dst1, dst0, dst3, dst2, out0, out1); - ST4x8_UB(out0, out1, dst, dst_stride); + ST_W8(out0, out1, 0, 1, 2, 3, 0, 1, 2, 3, dst, dst_stride); dst += (8 * dst_stride); src2 = src10; @@ -3509,9 +3520,15 @@ static void hevc_vt_uniwgt_4t_6w_msa(uint8_t *src, PCKEV_B2_UB(dst1, dst0, dst3, dst2, out0, out1); PCKEV_B2_UB(dst5, dst4, dst7, dst6, out2, out3); - ST6x4_UB(out0, out1, dst, dst_stride); + ST_W2(out0, 0, 2, dst, dst_stride); + ST_H2(out0, 2, 6, dst + 4, dst_stride); + ST_W2(out1, 0, 2, dst + 2 * dst_stride, dst_stride); + ST_H2(out1, 2, 6, dst + 2 * dst_stride + 4, dst_stride); dst += (4 * dst_stride); - ST6x4_UB(out2, out3, dst, dst_stride); + ST_W2(out2, 0, 2, dst, dst_stride); + ST_H2(out2, 2, 6, dst + 4, dst_stride); + ST_W2(out3, 0, 2, dst + 2 * dst_stride, dst_stride); + ST_H2(out3, 2, 6, dst + 2 * dst_stride + 4, dst_stride); } static void hevc_vt_uniwgt_4t_8x2_msa(uint8_t *src, @@ -3562,7 +3579,7 @@ static void hevc_vt_uniwgt_4t_8x2_msa(uint8_t *src, dst0, dst1); out = (v16u8) __msa_pckev_b((v16i8) dst1, (v16i8) dst0); - ST8x2_UB(out, dst, dst_stride); + ST_D2(out, 0, 1, dst, dst_stride); } static void hevc_vt_uniwgt_4t_8x4_msa(uint8_t *src, @@ -3617,7 +3634,7 @@ static void hevc_vt_uniwgt_4t_8x4_msa(uint8_t *src, offset_vec, rnd_vec, dst0, dst1, dst2, dst3); PCKEV_B2_UB(dst1, dst0, dst3, dst2, out0, out1); - ST8x4_UB(out0, out1, dst, dst_stride); + ST_D4(out0, out1, 0, 1, 0, 1, dst, dst_stride); } static void hevc_vt_uniwgt_4t_8x6_msa(uint8_t *src, @@ -3679,9 +3696,8 @@ static void hevc_vt_uniwgt_4t_8x6_msa(uint8_t *src, HEVC_UNIW_RND_CLIP2_MAX_SATU_H(dst4, dst5, weight_vec, offset_vec, rnd_vec, dst4, dst5); PCKEV_B3_UB(dst1, dst0, dst3, dst2, dst5, dst4, out0, out1, out2); - ST8x4_UB(out0, out1, dst, dst_stride); - dst += (4 * dst_stride); - ST8x2_UB(out2, dst, dst_stride); + ST_D4(out0, out1, 0, 1, 0, 1, dst, dst_stride); + ST_D2(out2, 0, 1, dst + 4 * dst_stride, dst_stride); } static void hevc_vt_uniwgt_4t_8x8mult_msa(uint8_t *src, @@ -3754,7 +3770,7 @@ static void hevc_vt_uniwgt_4t_8x8mult_msa(uint8_t *src, dst7); PCKEV_B2_UB(dst1, dst0, dst3, dst2, out0, out1); PCKEV_B2_UB(dst5, dst4, dst7, dst6, out2, out3); - ST8x8_UB(out0, out1, out2, out3, dst, dst_stride); + ST_D8(out0, out1, out2, out3, 0, 1, 0, 1, 0, 1, 0, 1, dst, dst_stride); dst += (8 * dst_stride); src2 = src10; @@ -3861,7 +3877,8 @@ static void hevc_vt_uniwgt_4t_12w_msa(uint8_t *src, HEVC_UNIW_RND_CLIP2_MAX_SATU_H(dst4, dst5, weight_vec, offset_vec, rnd_vec, dst4, dst5); PCKEV_B3_UB(dst1, dst0, dst3, dst2, dst5, dst4, out0, out1, out2); - ST12x4_UB(out0, out1, out2, dst, dst_stride); + ST_D4(out0, out1, 0, 1, 0, 1, dst, dst_stride); + ST_W4(out2, 0, 1, 2, 3, dst + 8, dst_stride); dst += (4 * dst_stride); ILVRL_B2_SB(src7, src6, src76_r, src76_l); @@ -3882,7 +3899,8 @@ static void hevc_vt_uniwgt_4t_12w_msa(uint8_t *src, HEVC_UNIW_RND_CLIP2_MAX_SATU_H(dst10, dst11, weight_vec, offset_vec, rnd_vec, dst10, dst11); PCKEV_B3_UB(dst7, dst6, dst9, dst8, dst11, dst10, out3, out4, out5); - ST12x4_UB(out3, out4, out5, dst, dst_stride); + ST_D4(out3, out4, 0, 1, 0, 1, dst, dst_stride); + ST_W4(out5, 0, 1, 2, 3, dst + 8, dst_stride); dst += (4 * dst_stride); src2 = src10; @@ -4062,7 +4080,7 @@ static void hevc_vt_uniwgt_4t_24w_msa(uint8_t *src, out2, out3); PCKEV_B2_UB(dst9, dst8, dst11, dst10, out4, out5); ST_UB4(out0, out1, out2, out3, dst, dst_stride); - ST8x4_UB(out4, out5, dst + 16, dst_stride); + ST_D4(out4, out5, 0, 1, 0, 1, dst + 16, dst_stride); dst += (4 * dst_stride); src2 = src6; @@ -4231,7 +4249,7 @@ static void hevc_hv_uniwgt_4t_4x2_msa(uint8_t *src, tmp += offset_vec; tmp = CLIP_SH_0_255_MAX_SATU(tmp); out = (v16u8) __msa_pckev_b((v16i8) tmp, (v16i8) tmp); - ST4x2_UB(out, dst, dst_stride); + ST_W2(out, 0, 1, dst, dst_stride); } static void hevc_hv_uniwgt_4t_4x4_msa(uint8_t *src, @@ -4300,7 +4318,7 @@ static void hevc_hv_uniwgt_4t_4x4_msa(uint8_t *src, ADD2(tmp0, offset_vec, tmp1, offset_vec, tmp0, tmp1); CLIP_SH2_0_255_MAX_SATU(tmp0, tmp1); out = (v16u8) __msa_pckev_b((v16i8) tmp1, (v16i8) tmp0); - ST4x4_UB(out, out, 0, 1, 2, 3, dst, dst_stride); + ST_W4(out, 0, 1, 2, 3, dst, dst_stride); } static void hevc_hv_uniwgt_4t_4multx8mult_msa(uint8_t *src, @@ -4401,7 +4419,7 @@ static void hevc_hv_uniwgt_4t_4multx8mult_msa(uint8_t *src, ADD2(tmp2, offset_vec, tmp3, offset_vec, tmp2, tmp3); CLIP_SH4_0_255_MAX_SATU(tmp0, tmp1, tmp2, tmp3); PCKEV_B2_UB(tmp1, tmp0, tmp3, tmp2, out0, out1); - ST4x8_UB(out0, out1, dst, dst_stride); + ST_W8(out0, out1, 0, 1, 2, 3, 0, 1, 2, 3, dst, dst_stride); dst += (8 * dst_stride); dst10_r = dst98_r; @@ -4559,10 +4577,8 @@ static void hevc_hv_uniwgt_4t_6w_msa(uint8_t *src, CLIP_SH4_0_255_MAX_SATU(tmp0, tmp1, tmp2, tmp3); CLIP_SH2_0_255_MAX_SATU(tmp4, tmp5); PCKEV_B3_UB(tmp1, tmp0, tmp3, tmp2, tmp5, tmp4, out0, out1, out2); - ST4x8_UB(out0, out1, dst, dst_stride); - ST2x4_UB(out2, 0, dst + 4, dst_stride); - dst += 4 * dst_stride; - ST2x4_UB(out2, 4, dst + 4, dst_stride); + ST_W8(out0, out1, 0, 1, 2, 3, 0, 1, 2, 3, dst, dst_stride); + ST_H8(out2, 0, 1, 2, 3, 4, 5, 6, 7, dst + 4, dst_stride); } static void hevc_hv_uniwgt_4t_8x2_msa(uint8_t *src, @@ -4638,7 +4654,7 @@ static void hevc_hv_uniwgt_4t_8x2_msa(uint8_t *src, ADD2(tmp0, offset_vec, tmp1, offset_vec, tmp0, tmp1); CLIP_SH2_0_255_MAX_SATU(tmp0, tmp1); out = (v16u8) __msa_pckev_b((v16i8) tmp1, (v16i8) tmp0); - ST8x2_UB(out, dst, dst_stride); + ST_D2(out, 0, 1, dst, dst_stride); } static void hevc_hv_uniwgt_4t_8multx4_msa(uint8_t *src, @@ -4731,7 +4747,7 @@ static void hevc_hv_uniwgt_4t_8multx4_msa(uint8_t *src, ADD2(tmp2, offset_vec, tmp3, offset_vec, tmp2, tmp3); CLIP_SH4_0_255_MAX_SATU(tmp0, tmp1, tmp2, tmp3); PCKEV_B2_UB(tmp1, tmp0, tmp3, tmp2, out0, out1); - ST8x4_UB(out0, out1, dst, dst_stride); + ST_D4(out0, out1, 0, 1, 0, 1, dst, dst_stride); dst += 8; } } @@ -4848,9 +4864,8 @@ static void hevc_hv_uniwgt_4t_8x6_msa(uint8_t *src, CLIP_SH4_0_255_MAX_SATU(tmp0, tmp1, tmp2, tmp3); CLIP_SH2_0_255_MAX_SATU(tmp4, tmp5); PCKEV_B3_UB(tmp1, tmp0, tmp3, tmp2, tmp5, tmp4, out0, out1, out2); - ST8x4_UB(out0, out1, dst, dst_stride); - dst += (4 * dst_stride); - ST8x2_UB(out2, dst, dst_stride); + ST_D4(out0, out1, 0, 1, 0, 1, dst, dst_stride); + ST_D2(out2, 0, 1, dst + 4 * dst_stride, dst_stride); } static void hevc_hv_uniwgt_4t_8multx4mult_msa(uint8_t *src, @@ -4960,7 +4975,7 @@ static void hevc_hv_uniwgt_4t_8multx4mult_msa(uint8_t *src, ADD2(tmp2, offset_vec, tmp3, offset_vec, tmp2, tmp3); CLIP_SH4_0_255_MAX_SATU(tmp0, tmp1, tmp2, tmp3); PCKEV_B2_UB(tmp1, tmp0, tmp3, tmp2, out0, out1); - ST8x4_UB(out0, out1, dst_tmp, dst_stride); + ST_D4(out0, out1, 0, 1, 0, 1, dst_tmp, dst_stride); dst_tmp += (4 * dst_stride); dst10_r = dst54_r; @@ -5107,7 +5122,7 @@ static void hevc_hv_uniwgt_4t_12w_msa(uint8_t *src, ADD2(tmp2, offset_vec, tmp3, offset_vec, tmp2, tmp3); CLIP_SH4_0_255_MAX_SATU(tmp0, tmp1, tmp2, tmp3); PCKEV_B2_UB(tmp1, tmp0, tmp3, tmp2, out0, out1); - ST8x4_UB(out0, out1, dst_tmp, dst_stride); + ST_D4(out0, out1, 0, 1, 0, 1, dst_tmp, dst_stride); dst_tmp += (4 * dst_stride); dst10_r = dst54_r; @@ -5174,7 +5189,7 @@ static void hevc_hv_uniwgt_4t_12w_msa(uint8_t *src, ADD2(tmp2, offset_vec, tmp3, offset_vec, tmp2, tmp3); CLIP_SH4_0_255_MAX_SATU(tmp0, tmp1, tmp2, tmp3); PCKEV_B2_UB(tmp1, tmp0, tmp3, tmp2, out0, out1); - ST4x8_UB(out0, out1, dst, dst_stride); + ST_W8(out0, out1, 0, 1, 2, 3, 0, 1, 2, 3, dst, dst_stride); dst += (8 * dst_stride); dst10_r = dst98_r; diff --git a/libavcodec/mips/hevcdsp_init_mips.c b/libavcodec/mips/hevcdsp_init_mips.c index 776d13e4d..88337f462 100644 --- a/libavcodec/mips/hevcdsp_init_mips.c +++ b/libavcodec/mips/hevcdsp_init_mips.c @@ -20,6 +20,78 @@ #include "libavcodec/mips/hevcdsp_mips.h" +#if HAVE_MMI +static av_cold void hevc_dsp_init_mmi(HEVCDSPContext *c, + const int bit_depth) +{ + if (8 == bit_depth) { + c->put_hevc_qpel[1][0][1] = ff_hevc_put_hevc_qpel_h4_8_mmi; + c->put_hevc_qpel[3][0][1] = ff_hevc_put_hevc_qpel_h8_8_mmi; + c->put_hevc_qpel[4][0][1] = ff_hevc_put_hevc_qpel_h12_8_mmi; + c->put_hevc_qpel[5][0][1] = ff_hevc_put_hevc_qpel_h16_8_mmi; + c->put_hevc_qpel[6][0][1] = ff_hevc_put_hevc_qpel_h24_8_mmi; + c->put_hevc_qpel[7][0][1] = ff_hevc_put_hevc_qpel_h32_8_mmi; + c->put_hevc_qpel[8][0][1] = ff_hevc_put_hevc_qpel_h48_8_mmi; + c->put_hevc_qpel[9][0][1] = ff_hevc_put_hevc_qpel_h64_8_mmi; + + c->put_hevc_qpel[1][1][1] = ff_hevc_put_hevc_qpel_hv4_8_mmi; + c->put_hevc_qpel[3][1][1] = ff_hevc_put_hevc_qpel_hv8_8_mmi; + c->put_hevc_qpel[4][1][1] = ff_hevc_put_hevc_qpel_hv12_8_mmi; + c->put_hevc_qpel[5][1][1] = ff_hevc_put_hevc_qpel_hv16_8_mmi; + c->put_hevc_qpel[6][1][1] = ff_hevc_put_hevc_qpel_hv24_8_mmi; + c->put_hevc_qpel[7][1][1] = ff_hevc_put_hevc_qpel_hv32_8_mmi; + c->put_hevc_qpel[8][1][1] = ff_hevc_put_hevc_qpel_hv48_8_mmi; + c->put_hevc_qpel[9][1][1] = ff_hevc_put_hevc_qpel_hv64_8_mmi; + + c->put_hevc_qpel_bi[1][0][1] = ff_hevc_put_hevc_qpel_bi_h4_8_mmi; + c->put_hevc_qpel_bi[3][0][1] = ff_hevc_put_hevc_qpel_bi_h8_8_mmi; + c->put_hevc_qpel_bi[4][0][1] = ff_hevc_put_hevc_qpel_bi_h12_8_mmi; + c->put_hevc_qpel_bi[5][0][1] = ff_hevc_put_hevc_qpel_bi_h16_8_mmi; + c->put_hevc_qpel_bi[6][0][1] = ff_hevc_put_hevc_qpel_bi_h24_8_mmi; + c->put_hevc_qpel_bi[7][0][1] = ff_hevc_put_hevc_qpel_bi_h32_8_mmi; + c->put_hevc_qpel_bi[8][0][1] = ff_hevc_put_hevc_qpel_bi_h48_8_mmi; + c->put_hevc_qpel_bi[9][0][1] = ff_hevc_put_hevc_qpel_bi_h64_8_mmi; + + c->put_hevc_qpel_bi[1][1][1] = ff_hevc_put_hevc_qpel_bi_hv4_8_mmi; + c->put_hevc_qpel_bi[3][1][1] = ff_hevc_put_hevc_qpel_bi_hv8_8_mmi; + c->put_hevc_qpel_bi[4][1][1] = ff_hevc_put_hevc_qpel_bi_hv12_8_mmi; + c->put_hevc_qpel_bi[5][1][1] = ff_hevc_put_hevc_qpel_bi_hv16_8_mmi; + c->put_hevc_qpel_bi[6][1][1] = ff_hevc_put_hevc_qpel_bi_hv24_8_mmi; + c->put_hevc_qpel_bi[7][1][1] = ff_hevc_put_hevc_qpel_bi_hv32_8_mmi; + c->put_hevc_qpel_bi[8][1][1] = ff_hevc_put_hevc_qpel_bi_hv48_8_mmi; + c->put_hevc_qpel_bi[9][1][1] = ff_hevc_put_hevc_qpel_bi_hv64_8_mmi; + + c->put_hevc_qpel_bi[3][0][0] = ff_hevc_put_hevc_pel_bi_pixels8_8_mmi; + c->put_hevc_qpel_bi[5][0][0] = ff_hevc_put_hevc_pel_bi_pixels16_8_mmi; + c->put_hevc_qpel_bi[6][0][0] = ff_hevc_put_hevc_pel_bi_pixels24_8_mmi; + c->put_hevc_qpel_bi[7][0][0] = ff_hevc_put_hevc_pel_bi_pixels32_8_mmi; + c->put_hevc_qpel_bi[8][0][0] = ff_hevc_put_hevc_pel_bi_pixels48_8_mmi; + c->put_hevc_qpel_bi[9][0][0] = ff_hevc_put_hevc_pel_bi_pixels64_8_mmi; + + c->put_hevc_epel_bi[3][0][0] = ff_hevc_put_hevc_pel_bi_pixels8_8_mmi; + c->put_hevc_epel_bi[5][0][0] = ff_hevc_put_hevc_pel_bi_pixels16_8_mmi; + c->put_hevc_epel_bi[6][0][0] = ff_hevc_put_hevc_pel_bi_pixels24_8_mmi; + c->put_hevc_epel_bi[7][0][0] = ff_hevc_put_hevc_pel_bi_pixels32_8_mmi; + + c->put_hevc_epel_bi[1][1][1] = ff_hevc_put_hevc_epel_bi_hv4_8_mmi; + c->put_hevc_epel_bi[3][1][1] = ff_hevc_put_hevc_epel_bi_hv8_8_mmi; + c->put_hevc_epel_bi[4][1][1] = ff_hevc_put_hevc_epel_bi_hv12_8_mmi; + c->put_hevc_epel_bi[5][1][1] = ff_hevc_put_hevc_epel_bi_hv16_8_mmi; + c->put_hevc_epel_bi[6][1][1] = ff_hevc_put_hevc_epel_bi_hv24_8_mmi; + c->put_hevc_epel_bi[7][1][1] = ff_hevc_put_hevc_epel_bi_hv32_8_mmi; + + c->put_hevc_qpel_uni[1][1][1] = ff_hevc_put_hevc_qpel_uni_hv4_8_mmi; + c->put_hevc_qpel_uni[3][1][1] = ff_hevc_put_hevc_qpel_uni_hv8_8_mmi; + c->put_hevc_qpel_uni[4][1][1] = ff_hevc_put_hevc_qpel_uni_hv12_8_mmi; + c->put_hevc_qpel_uni[5][1][1] = ff_hevc_put_hevc_qpel_uni_hv16_8_mmi; + c->put_hevc_qpel_uni[6][1][1] = ff_hevc_put_hevc_qpel_uni_hv24_8_mmi; + c->put_hevc_qpel_uni[7][1][1] = ff_hevc_put_hevc_qpel_uni_hv32_8_mmi; + c->put_hevc_qpel_uni[8][1][1] = ff_hevc_put_hevc_qpel_uni_hv48_8_mmi; + c->put_hevc_qpel_uni[9][1][1] = ff_hevc_put_hevc_qpel_uni_hv64_8_mmi; + } +} +#endif // #if HAVE_MMI + #if HAVE_MSA static av_cold void hevc_dsp_init_msa(HEVCDSPContext *c, const int bit_depth) @@ -448,6 +520,9 @@ static av_cold void hevc_dsp_init_msa(HEVCDSPContext *c, void ff_hevc_dsp_init_mips(HEVCDSPContext *c, const int bit_depth) { +#if HAVE_MMI + hevc_dsp_init_mmi(c, bit_depth); +#endif // #if HAVE_MMI #if HAVE_MSA hevc_dsp_init_msa(c, bit_depth); #endif // #if HAVE_MSA diff --git a/libavcodec/mips/hevcdsp_mips.h b/libavcodec/mips/hevcdsp_mips.h index 1573d1cc9..c84e08d16 100644 --- a/libavcodec/mips/hevcdsp_mips.h +++ b/libavcodec/mips/hevcdsp_mips.h @@ -479,4 +479,95 @@ void ff_hevc_addblk_32x32_msa(uint8_t *dst, int16_t *pi16Coeffs, ptrdiff_t stride); void ff_hevc_idct_luma_4x4_msa(int16_t *pi16Coeffs); +/* Loongson optimization */ +#define L_MC(PEL, DIR, WIDTH, TYPE) \ +void ff_hevc_put_hevc_##PEL##_##DIR##WIDTH##_8_##TYPE(int16_t *dst, \ + uint8_t *src, \ + ptrdiff_t src_stride, \ + int height, \ + intptr_t mx, \ + intptr_t my, \ + int width) +L_MC(qpel, h, 4, mmi); +L_MC(qpel, h, 8, mmi); +L_MC(qpel, h, 12, mmi); +L_MC(qpel, h, 16, mmi); +L_MC(qpel, h, 24, mmi); +L_MC(qpel, h, 32, mmi); +L_MC(qpel, h, 48, mmi); +L_MC(qpel, h, 64, mmi); + +L_MC(qpel, hv, 4, mmi); +L_MC(qpel, hv, 8, mmi); +L_MC(qpel, hv, 12, mmi); +L_MC(qpel, hv, 16, mmi); +L_MC(qpel, hv, 24, mmi); +L_MC(qpel, hv, 32, mmi); +L_MC(qpel, hv, 48, mmi); +L_MC(qpel, hv, 64, mmi); + +#define L_BI_MC(PEL, DIR, WIDTH, TYPE) \ +void ff_hevc_put_hevc_##PEL##_bi_##DIR##WIDTH##_8_##TYPE(uint8_t *dst, \ + ptrdiff_t dst_stride, \ + uint8_t *src, \ + ptrdiff_t src_stride, \ + int16_t *src2, \ + int height, \ + intptr_t mx, \ + intptr_t my, \ + int width) + +L_BI_MC(pel, pixels, 8, mmi); +L_BI_MC(pel, pixels, 16, mmi); +L_BI_MC(pel, pixels, 24, mmi); +L_BI_MC(pel, pixels, 32, mmi); +L_BI_MC(pel, pixels, 48, mmi); +L_BI_MC(pel, pixels, 64, mmi); + +L_BI_MC(qpel, hv, 4, mmi); +L_BI_MC(qpel, hv, 8, mmi); +L_BI_MC(qpel, hv, 12, mmi); +L_BI_MC(qpel, hv, 16, mmi); +L_BI_MC(qpel, hv, 24, mmi); +L_BI_MC(qpel, hv, 32, mmi); +L_BI_MC(qpel, hv, 48, mmi); +L_BI_MC(qpel, hv, 64, mmi); + +L_BI_MC(qpel, h, 4, mmi); +L_BI_MC(qpel, h, 8, mmi); +L_BI_MC(qpel, h, 12, mmi); +L_BI_MC(qpel, h, 16, mmi); +L_BI_MC(qpel, h, 24, mmi); +L_BI_MC(qpel, h, 32, mmi); +L_BI_MC(qpel, h, 48, mmi); +L_BI_MC(qpel, h, 64, mmi); + +L_BI_MC(epel, hv, 4, mmi); +L_BI_MC(epel, hv, 8, mmi); +L_BI_MC(epel, hv, 12, mmi); +L_BI_MC(epel, hv, 16, mmi); +L_BI_MC(epel, hv, 24, mmi); +L_BI_MC(epel, hv, 32, mmi); +#undef L_BI_MC + +#define L_UNI_MC(PEL, DIR, WIDTH, TYPE) \ +void ff_hevc_put_hevc_##PEL##_uni_##DIR##WIDTH##_8_##TYPE(uint8_t *dst, \ + ptrdiff_t dst_stride, \ + uint8_t *src, \ + ptrdiff_t src_stride, \ + int height, \ + intptr_t mx, \ + intptr_t my, \ + int width) + +L_UNI_MC(qpel, hv, 4, mmi); +L_UNI_MC(qpel, hv, 8, mmi); +L_UNI_MC(qpel, hv, 12, mmi); +L_UNI_MC(qpel, hv, 16, mmi); +L_UNI_MC(qpel, hv, 24, mmi); +L_UNI_MC(qpel, hv, 32, mmi); +L_UNI_MC(qpel, hv, 48, mmi); +L_UNI_MC(qpel, hv, 64, mmi); +#undef L_UNI_MC + #endif // #ifndef AVCODEC_MIPS_HEVCDSP_MIPS_H diff --git a/libavcodec/mips/hevcdsp_mmi.c b/libavcodec/mips/hevcdsp_mmi.c new file mode 100644 index 000000000..aa83e1f9a --- /dev/null +++ b/libavcodec/mips/hevcdsp_mmi.c @@ -0,0 +1,1183 @@ +/* + * Copyright (c) 2019 Shiyou Yin (yinshiyou-hf@loongson.cn) + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavcodec/hevcdec.h" +#include "libavcodec/bit_depth_template.c" +#include "libavcodec/mips/hevcdsp_mips.h" +#include "libavutil/mips/mmiutils.h" + +#define PUT_HEVC_QPEL_H(w, x_step, src_step, dst_step) \ +void ff_hevc_put_hevc_qpel_h##w##_8_mmi(int16_t *dst, uint8_t *_src, \ + ptrdiff_t _srcstride, \ + int height, intptr_t mx, \ + intptr_t my, int width) \ +{ \ + int x, y; \ + pixel *src = (pixel*)_src - 3; \ + ptrdiff_t srcstride = _srcstride / sizeof(pixel); \ + uint64_t ftmp[15]; \ + uint64_t rtmp[1]; \ + const int8_t *filter = ff_hevc_qpel_filters[mx - 1]; \ + \ + x = x_step; \ + y = height; \ + __asm__ volatile( \ + MMI_LDC1(%[ftmp1], %[filter], 0x00) \ + "li %[rtmp0], 0x08 \n\t" \ + "dmtc1 %[rtmp0], %[ftmp0] \n\t" \ + "punpckhbh %[ftmp2], %[ftmp0], %[ftmp1] \n\t" \ + "punpcklbh %[ftmp1], %[ftmp0], %[ftmp1] \n\t" \ + "psrah %[ftmp1], %[ftmp1], %[ftmp0] \n\t" \ + "psrah %[ftmp2], %[ftmp2], %[ftmp0] \n\t" \ + "xor %[ftmp0], %[ftmp0], %[ftmp0] \n\t" \ + \ + "1: \n\t" \ + "2: \n\t" \ + "gsldlc1 %[ftmp3], 0x07(%[src]) \n\t" \ + "gsldrc1 %[ftmp3], 0x00(%[src]) \n\t" \ + "gsldlc1 %[ftmp4], 0x08(%[src]) \n\t" \ + "gsldrc1 %[ftmp4], 0x01(%[src]) \n\t" \ + "gsldlc1 %[ftmp5], 0x09(%[src]) \n\t" \ + "gsldrc1 %[ftmp5], 0x02(%[src]) \n\t" \ + "gsldlc1 %[ftmp6], 0x0a(%[src]) \n\t" \ + "gsldrc1 %[ftmp6], 0x03(%[src]) \n\t" \ + "punpcklbh %[ftmp7], %[ftmp3], %[ftmp0] \n\t" \ + "punpckhbh %[ftmp8], %[ftmp3], %[ftmp0] \n\t" \ + "pmullh %[ftmp7], %[ftmp7], %[ftmp1] \n\t" \ + "pmullh %[ftmp8], %[ftmp8], %[ftmp2] \n\t" \ + "paddh %[ftmp3], %[ftmp7], %[ftmp8] \n\t" \ + "punpcklbh %[ftmp7], %[ftmp4], %[ftmp0] \n\t" \ + "punpckhbh %[ftmp8], %[ftmp4], %[ftmp0] \n\t" \ + "pmullh %[ftmp7], %[ftmp7], %[ftmp1] \n\t" \ + "pmullh %[ftmp8], %[ftmp8], %[ftmp2] \n\t" \ + "paddh %[ftmp4], %[ftmp7], %[ftmp8] \n\t" \ + "punpcklbh %[ftmp7], %[ftmp5], %[ftmp0] \n\t" \ + "punpckhbh %[ftmp8], %[ftmp5], %[ftmp0] \n\t" \ + "pmullh %[ftmp7], %[ftmp7], %[ftmp1] \n\t" \ + "pmullh %[ftmp8], %[ftmp8], %[ftmp2] \n\t" \ + "paddh %[ftmp5], %[ftmp7], %[ftmp8] \n\t" \ + "punpcklbh %[ftmp7], %[ftmp6], %[ftmp0] \n\t" \ + "punpckhbh %[ftmp8], %[ftmp6], %[ftmp0] \n\t" \ + "pmullh %[ftmp7], %[ftmp7], %[ftmp1] \n\t" \ + "pmullh %[ftmp8], %[ftmp8], %[ftmp2] \n\t" \ + "paddh %[ftmp6], %[ftmp7], %[ftmp8] \n\t" \ + TRANSPOSE_4H(%[ftmp3], %[ftmp4], %[ftmp5], %[ftmp6], \ + %[ftmp7], %[ftmp8], %[ftmp9], %[ftmp10]) \ + "paddh %[ftmp3], %[ftmp3], %[ftmp4] \n\t" \ + "paddh %[ftmp5], %[ftmp5], %[ftmp6] \n\t" \ + "paddh %[ftmp3], %[ftmp3], %[ftmp5] \n\t" \ + "gssdlc1 %[ftmp3], 0x07(%[dst]) \n\t" \ + "gssdrc1 %[ftmp3], 0x00(%[dst]) \n\t" \ + \ + "daddi %[x], %[x], -0x01 \n\t" \ + PTR_ADDIU "%[src], %[src], 0x04 \n\t" \ + PTR_ADDIU "%[dst], %[dst], 0x08 \n\t" \ + "bnez %[x], 2b \n\t" \ + \ + "daddi %[y], %[y], -0x01 \n\t" \ + "li %[x], " #x_step " \n\t" \ + PTR_ADDIU "%[src], %[src], " #src_step " \n\t" \ + PTR_ADDIU "%[dst], %[dst], " #dst_step " \n\t" \ + PTR_ADDU "%[src], %[src], %[stride] \n\t" \ + PTR_ADDIU "%[dst], %[dst], 0x80 \n\t" \ + "bnez %[y], 1b \n\t" \ + : [ftmp0]"=&f"(ftmp[0]), [ftmp1]"=&f"(ftmp[1]), \ + [ftmp2]"=&f"(ftmp[2]), [ftmp3]"=&f"(ftmp[3]), \ + [ftmp4]"=&f"(ftmp[4]), [ftmp5]"=&f"(ftmp[5]), \ + [ftmp6]"=&f"(ftmp[6]), [ftmp7]"=&f"(ftmp[7]), \ + [ftmp8]"=&f"(ftmp[8]), [ftmp9]"=&f"(ftmp[9]), \ + [ftmp10]"=&f"(ftmp[10]), [rtmp0]"=&r"(rtmp[0]), \ + [src]"+&r"(src), [dst]"+&r"(dst), [y]"+&r"(y), \ + [x]"+&r"(x) \ + : [filter]"r"(filter), [stride]"r"(srcstride) \ + : "memory" \ + ); \ +} + +PUT_HEVC_QPEL_H(4, 1, -4, -8); +PUT_HEVC_QPEL_H(8, 2, -8, -16); +PUT_HEVC_QPEL_H(12, 3, -12, -24); +PUT_HEVC_QPEL_H(16, 4, -16, -32); +PUT_HEVC_QPEL_H(24, 6, -24, -48); +PUT_HEVC_QPEL_H(32, 8, -32, -64); +PUT_HEVC_QPEL_H(48, 12, -48, -96); +PUT_HEVC_QPEL_H(64, 16, -64, -128); + +#define PUT_HEVC_QPEL_HV(w, x_step, src_step, dst_step) \ +void ff_hevc_put_hevc_qpel_hv##w##_8_mmi(int16_t *dst, uint8_t *_src, \ + ptrdiff_t _srcstride, \ + int height, intptr_t mx, \ + intptr_t my, int width) \ +{ \ + int x, y; \ + const int8_t *filter; \ + pixel *src = (pixel*)_src; \ + ptrdiff_t srcstride = _srcstride / sizeof(pixel); \ + int16_t tmp_array[(MAX_PB_SIZE + QPEL_EXTRA) * MAX_PB_SIZE]; \ + int16_t *tmp = tmp_array; \ + uint64_t ftmp[15]; \ + uint64_t rtmp[1]; \ + \ + src -= (QPEL_EXTRA_BEFORE * srcstride + 3); \ + filter = ff_hevc_qpel_filters[mx - 1]; \ + x = x_step; \ + y = height + QPEL_EXTRA; \ + __asm__ volatile( \ + MMI_LDC1(%[ftmp1], %[filter], 0x00) \ + "li %[rtmp0], 0x08 \n\t" \ + "dmtc1 %[rtmp0], %[ftmp0] \n\t" \ + "punpckhbh %[ftmp2], %[ftmp0], %[ftmp1] \n\t" \ + "punpcklbh %[ftmp1], %[ftmp0], %[ftmp1] \n\t" \ + "psrah %[ftmp1], %[ftmp1], %[ftmp0] \n\t" \ + "psrah %[ftmp2], %[ftmp2], %[ftmp0] \n\t" \ + "xor %[ftmp0], %[ftmp0], %[ftmp0] \n\t" \ + \ + "1: \n\t" \ + "2: \n\t" \ + "gsldlc1 %[ftmp3], 0x07(%[src]) \n\t" \ + "gsldrc1 %[ftmp3], 0x00(%[src]) \n\t" \ + "gsldlc1 %[ftmp4], 0x08(%[src]) \n\t" \ + "gsldrc1 %[ftmp4], 0x01(%[src]) \n\t" \ + "gsldlc1 %[ftmp5], 0x09(%[src]) \n\t" \ + "gsldrc1 %[ftmp5], 0x02(%[src]) \n\t" \ + "gsldlc1 %[ftmp6], 0x0a(%[src]) \n\t" \ + "gsldrc1 %[ftmp6], 0x03(%[src]) \n\t" \ + "punpcklbh %[ftmp7], %[ftmp3], %[ftmp0] \n\t" \ + "punpckhbh %[ftmp8], %[ftmp3], %[ftmp0] \n\t" \ + "pmullh %[ftmp7], %[ftmp7], %[ftmp1] \n\t" \ + "pmullh %[ftmp8], %[ftmp8], %[ftmp2] \n\t" \ + "paddh %[ftmp3], %[ftmp7], %[ftmp8] \n\t" \ + "punpcklbh %[ftmp7], %[ftmp4], %[ftmp0] \n\t" \ + "punpckhbh %[ftmp8], %[ftmp4], %[ftmp0] \n\t" \ + "pmullh %[ftmp7], %[ftmp7], %[ftmp1] \n\t" \ + "pmullh %[ftmp8], %[ftmp8], %[ftmp2] \n\t" \ + "paddh %[ftmp4], %[ftmp7], %[ftmp8] \n\t" \ + "punpcklbh %[ftmp7], %[ftmp5], %[ftmp0] \n\t" \ + "punpckhbh %[ftmp8], %[ftmp5], %[ftmp0] \n\t" \ + "pmullh %[ftmp7], %[ftmp7], %[ftmp1] \n\t" \ + "pmullh %[ftmp8], %[ftmp8], %[ftmp2] \n\t" \ + "paddh %[ftmp5], %[ftmp7], %[ftmp8] \n\t" \ + "punpcklbh %[ftmp7], %[ftmp6], %[ftmp0] \n\t" \ + "punpckhbh %[ftmp8], %[ftmp6], %[ftmp0] \n\t" \ + "pmullh %[ftmp7], %[ftmp7], %[ftmp1] \n\t" \ + "pmullh %[ftmp8], %[ftmp8], %[ftmp2] \n\t" \ + "paddh %[ftmp6], %[ftmp7], %[ftmp8] \n\t" \ + TRANSPOSE_4H(%[ftmp3], %[ftmp4], %[ftmp5], %[ftmp6], \ + %[ftmp7], %[ftmp8], %[ftmp9], %[ftmp10]) \ + "paddh %[ftmp3], %[ftmp3], %[ftmp4] \n\t" \ + "paddh %[ftmp5], %[ftmp5], %[ftmp6] \n\t" \ + "paddh %[ftmp3], %[ftmp3], %[ftmp5] \n\t" \ + "gssdlc1 %[ftmp3], 0x07(%[tmp]) \n\t" \ + "gssdrc1 %[ftmp3], 0x00(%[tmp]) \n\t" \ + \ + "daddi %[x], %[x], -0x01 \n\t" \ + PTR_ADDIU "%[src], %[src], 0x04 \n\t" \ + PTR_ADDIU "%[tmp], %[tmp], 0x08 \n\t" \ + "bnez %[x], 2b \n\t" \ + \ + "daddi %[y], %[y], -0x01 \n\t" \ + "li %[x], " #x_step " \n\t" \ + PTR_ADDIU "%[src], %[src], " #src_step " \n\t" \ + PTR_ADDIU "%[tmp], %[tmp], " #dst_step " \n\t" \ + PTR_ADDU "%[src], %[src], %[stride] \n\t" \ + PTR_ADDIU "%[tmp], %[tmp], 0x80 \n\t" \ + "bnez %[y], 1b \n\t" \ + : [ftmp0]"=&f"(ftmp[0]), [ftmp1]"=&f"(ftmp[1]), \ + [ftmp2]"=&f"(ftmp[2]), [ftmp3]"=&f"(ftmp[3]), \ + [ftmp4]"=&f"(ftmp[4]), [ftmp5]"=&f"(ftmp[5]), \ + [ftmp6]"=&f"(ftmp[6]), [ftmp7]"=&f"(ftmp[7]), \ + [ftmp8]"=&f"(ftmp[8]), [ftmp9]"=&f"(ftmp[9]), \ + [ftmp10]"=&f"(ftmp[10]), [rtmp0]"=&r"(rtmp[0]), \ + [src]"+&r"(src), [tmp]"+&r"(tmp), [y]"+&r"(y), \ + [x]"+&r"(x) \ + : [filter]"r"(filter), [stride]"r"(srcstride) \ + : "memory" \ + ); \ + \ + tmp = tmp_array + QPEL_EXTRA_BEFORE * 4 -12; \ + filter = ff_hevc_qpel_filters[my - 1]; \ + x = x_step; \ + y = height; \ + __asm__ volatile( \ + MMI_LDC1(%[ftmp1], %[filter], 0x00) \ + "li %[rtmp0], 0x08 \n\t" \ + "dmtc1 %[rtmp0], %[ftmp0] \n\t" \ + "punpckhbh %[ftmp2], %[ftmp0], %[ftmp1] \n\t" \ + "punpcklbh %[ftmp1], %[ftmp0], %[ftmp1] \n\t" \ + "psrah %[ftmp1], %[ftmp1], %[ftmp0] \n\t" \ + "psrah %[ftmp2], %[ftmp2], %[ftmp0] \n\t" \ + "li %[rtmp0], 0x06 \n\t" \ + "dmtc1 %[rtmp0], %[ftmp0] \n\t" \ + \ + "1: \n\t" \ + "2: \n\t" \ + "gsldlc1 %[ftmp3], 0x07(%[tmp]) \n\t" \ + "gsldrc1 %[ftmp3], 0x00(%[tmp]) \n\t" \ + PTR_ADDIU "%[tmp], %[tmp], 0x80 \n\t" \ + "gsldlc1 %[ftmp4], 0x07(%[tmp]) \n\t" \ + "gsldrc1 %[ftmp4], 0x00(%[tmp]) \n\t" \ + PTR_ADDIU "%[tmp], %[tmp], 0x80 \n\t" \ + "gsldlc1 %[ftmp5], 0x07(%[tmp]) \n\t" \ + "gsldrc1 %[ftmp5], 0x00(%[tmp]) \n\t" \ + PTR_ADDIU "%[tmp], %[tmp], 0x80 \n\t" \ + "gsldlc1 %[ftmp6], 0x07(%[tmp]) \n\t" \ + "gsldrc1 %[ftmp6], 0x00(%[tmp]) \n\t" \ + PTR_ADDIU "%[tmp], %[tmp], 0x80 \n\t" \ + "gsldlc1 %[ftmp7], 0x07(%[tmp]) \n\t" \ + "gsldrc1 %[ftmp7], 0x00(%[tmp]) \n\t" \ + PTR_ADDIU "%[tmp], %[tmp], 0x80 \n\t" \ + "gsldlc1 %[ftmp8], 0x07(%[tmp]) \n\t" \ + "gsldrc1 %[ftmp8], 0x00(%[tmp]) \n\t" \ + PTR_ADDIU "%[tmp], %[tmp], 0x80 \n\t" \ + "gsldlc1 %[ftmp9], 0x07(%[tmp]) \n\t" \ + "gsldrc1 %[ftmp9], 0x00(%[tmp]) \n\t" \ + PTR_ADDIU "%[tmp], %[tmp], 0x80 \n\t" \ + "gsldlc1 %[ftmp10], 0x07(%[tmp]) \n\t" \ + "gsldrc1 %[ftmp10], 0x00(%[tmp]) \n\t" \ + PTR_ADDIU "%[tmp], %[tmp], -0x380 \n\t" \ + TRANSPOSE_4H(%[ftmp3], %[ftmp4], %[ftmp5], %[ftmp6], \ + %[ftmp11], %[ftmp12], %[ftmp13], %[ftmp14]) \ + TRANSPOSE_4H(%[ftmp7], %[ftmp8], %[ftmp9], %[ftmp10], \ + %[ftmp11], %[ftmp12], %[ftmp13], %[ftmp14]) \ + "pmaddhw %[ftmp11], %[ftmp3], %[ftmp1] \n\t" \ + "pmaddhw %[ftmp12], %[ftmp7], %[ftmp2] \n\t" \ + "pmaddhw %[ftmp13], %[ftmp4], %[ftmp1] \n\t" \ + "pmaddhw %[ftmp14], %[ftmp8], %[ftmp2] \n\t" \ + "paddw %[ftmp11], %[ftmp11], %[ftmp12] \n\t" \ + "paddw %[ftmp13], %[ftmp13], %[ftmp14] \n\t" \ + TRANSPOSE_2W(%[ftmp11], %[ftmp13], %[ftmp3], %[ftmp4]) \ + "paddw %[ftmp3], %[ftmp3], %[ftmp4] \n\t" \ + "psraw %[ftmp3], %[ftmp3], %[ftmp0] \n\t" \ + "pmaddhw %[ftmp11], %[ftmp5], %[ftmp1] \n\t" \ + "pmaddhw %[ftmp12], %[ftmp9], %[ftmp2] \n\t" \ + "pmaddhw %[ftmp13], %[ftmp6], %[ftmp1] \n\t" \ + "pmaddhw %[ftmp14], %[ftmp10], %[ftmp2] \n\t" \ + "paddw %[ftmp11], %[ftmp11], %[ftmp12] \n\t" \ + "paddw %[ftmp13], %[ftmp13], %[ftmp14] \n\t" \ + TRANSPOSE_2W(%[ftmp11], %[ftmp13], %[ftmp5], %[ftmp6]) \ + "paddw %[ftmp5], %[ftmp5], %[ftmp6] \n\t" \ + "psraw %[ftmp5], %[ftmp5], %[ftmp0] \n\t" \ + "packsswh %[ftmp3], %[ftmp3], %[ftmp5] \n\t" \ + "gssdlc1 %[ftmp3], 0x07(%[dst]) \n\t" \ + "gssdrc1 %[ftmp3], 0x00(%[dst]) \n\t" \ + \ + "daddi %[x], %[x], -0x01 \n\t" \ + PTR_ADDIU "%[dst], %[dst], 0x08 \n\t" \ + PTR_ADDIU "%[tmp], %[tmp], 0x08 \n\t" \ + "bnez %[x], 2b \n\t" \ + \ + "daddi %[y], %[y], -0x01 \n\t" \ + "li %[x], " #x_step " \n\t" \ + PTR_ADDIU "%[dst], %[dst], " #dst_step " \n\t" \ + PTR_ADDIU "%[tmp], %[tmp], " #dst_step " \n\t" \ + PTR_ADDIU "%[dst], %[dst], 0x80 \n\t" \ + PTR_ADDIU "%[tmp], %[tmp], 0x80 \n\t" \ + "bnez %[y], 1b \n\t" \ + : [ftmp0]"=&f"(ftmp[0]), [ftmp1]"=&f"(ftmp[1]), \ + [ftmp2]"=&f"(ftmp[2]), [ftmp3]"=&f"(ftmp[3]), \ + [ftmp4]"=&f"(ftmp[4]), [ftmp5]"=&f"(ftmp[5]), \ + [ftmp6]"=&f"(ftmp[6]), [ftmp7]"=&f"(ftmp[7]), \ + [ftmp8]"=&f"(ftmp[8]), [ftmp9]"=&f"(ftmp[9]), \ + [ftmp10]"=&f"(ftmp[10]), [ftmp11]"=&f"(ftmp[11]), \ + [ftmp12]"=&f"(ftmp[12]), [ftmp13]"=&f"(ftmp[13]), \ + [ftmp14]"=&f"(ftmp[14]), [rtmp0]"=&r"(rtmp[0]), \ + [dst]"+&r"(dst), [tmp]"+&r"(tmp), [y]"+&r"(y), \ + [x]"+&r"(x) \ + : [filter]"r"(filter), [stride]"r"(srcstride) \ + : "memory" \ + ); \ +} + +PUT_HEVC_QPEL_HV(4, 1, -4, -8); +PUT_HEVC_QPEL_HV(8, 2, -8, -16); +PUT_HEVC_QPEL_HV(12, 3, -12, -24); +PUT_HEVC_QPEL_HV(16, 4, -16, -32); +PUT_HEVC_QPEL_HV(24, 6, -24, -48); +PUT_HEVC_QPEL_HV(32, 8, -32, -64); +PUT_HEVC_QPEL_HV(48, 12, -48, -96); +PUT_HEVC_QPEL_HV(64, 16, -64, -128); + +#define PUT_HEVC_QPEL_BI_H(w, x_step, src_step, src2_step, dst_step) \ +void ff_hevc_put_hevc_qpel_bi_h##w##_8_mmi(uint8_t *_dst, \ + ptrdiff_t _dststride, \ + uint8_t *_src, \ + ptrdiff_t _srcstride, \ + int16_t *src2, int height, \ + intptr_t mx, intptr_t my, \ + int width) \ +{ \ + int x, y; \ + pixel *src = (pixel*)_src - 3; \ + ptrdiff_t srcstride = _srcstride / sizeof(pixel); \ + pixel *dst = (pixel *)_dst; \ + ptrdiff_t dststride = _dststride / sizeof(pixel); \ + const int8_t *filter = ff_hevc_qpel_filters[mx - 1]; \ + uint64_t ftmp[20]; \ + uint64_t rtmp[1]; \ + int shift = 7; \ + int offset = 64; \ + \ + x = width >> 2; \ + y = height; \ + __asm__ volatile( \ + MMI_LDC1(%[ftmp1], %[filter], 0x00) \ + "li %[rtmp0], 0x08 \n\t" \ + "dmtc1 %[rtmp0], %[ftmp0] \n\t" \ + "punpckhbh %[ftmp2], %[ftmp0], %[ftmp1] \n\t" \ + "punpcklbh %[ftmp1], %[ftmp0], %[ftmp1] \n\t" \ + "psrah %[ftmp1], %[ftmp1], %[ftmp0] \n\t" \ + "psrah %[ftmp2], %[ftmp2], %[ftmp0] \n\t" \ + "xor %[ftmp0], %[ftmp0], %[ftmp0] \n\t" \ + "punpcklhw %[offset], %[offset], %[offset] \n\t" \ + "punpcklwd %[offset], %[offset], %[offset] \n\t" \ + \ + "1: \n\t" \ + "li %[x], " #x_step " \n\t" \ + "2: \n\t" \ + "gsldlc1 %[ftmp3], 0x07(%[src]) \n\t" \ + "gsldrc1 %[ftmp3], 0x00(%[src]) \n\t" \ + "gsldlc1 %[ftmp4], 0x08(%[src]) \n\t" \ + "gsldrc1 %[ftmp4], 0x01(%[src]) \n\t" \ + "gsldlc1 %[ftmp5], 0x09(%[src]) \n\t" \ + "gsldrc1 %[ftmp5], 0x02(%[src]) \n\t" \ + "gsldlc1 %[ftmp6], 0x0a(%[src]) \n\t" \ + "gsldrc1 %[ftmp6], 0x03(%[src]) \n\t" \ + "punpcklbh %[ftmp7], %[ftmp3], %[ftmp0] \n\t" \ + "punpckhbh %[ftmp8], %[ftmp3], %[ftmp0] \n\t" \ + "pmullh %[ftmp7], %[ftmp7], %[ftmp1] \n\t" \ + "pmullh %[ftmp8], %[ftmp8], %[ftmp2] \n\t" \ + "paddh %[ftmp3], %[ftmp7], %[ftmp8] \n\t" \ + "punpcklbh %[ftmp7], %[ftmp4], %[ftmp0] \n\t" \ + "punpckhbh %[ftmp8], %[ftmp4], %[ftmp0] \n\t" \ + "pmullh %[ftmp7], %[ftmp7], %[ftmp1] \n\t" \ + "pmullh %[ftmp8], %[ftmp8], %[ftmp2] \n\t" \ + "paddh %[ftmp4], %[ftmp7], %[ftmp8] \n\t" \ + "punpcklbh %[ftmp7], %[ftmp5], %[ftmp0] \n\t" \ + "punpckhbh %[ftmp8], %[ftmp5], %[ftmp0] \n\t" \ + "pmullh %[ftmp7], %[ftmp7], %[ftmp1] \n\t" \ + "pmullh %[ftmp8], %[ftmp8], %[ftmp2] \n\t" \ + "paddh %[ftmp5], %[ftmp7], %[ftmp8] \n\t" \ + "punpcklbh %[ftmp7], %[ftmp6], %[ftmp0] \n\t" \ + "punpckhbh %[ftmp8], %[ftmp6], %[ftmp0] \n\t" \ + "pmullh %[ftmp7], %[ftmp7], %[ftmp1] \n\t" \ + "pmullh %[ftmp8], %[ftmp8], %[ftmp2] \n\t" \ + "paddh %[ftmp6], %[ftmp7], %[ftmp8] \n\t" \ + TRANSPOSE_4H(%[ftmp3], %[ftmp4], %[ftmp5], %[ftmp6], \ + %[ftmp7], %[ftmp8], %[ftmp9], %[ftmp10]) \ + "paddh %[ftmp3], %[ftmp3], %[ftmp4] \n\t" \ + "paddh %[ftmp5], %[ftmp5], %[ftmp6] \n\t" \ + "paddh %[ftmp3], %[ftmp3], %[ftmp5] \n\t" \ + "paddh %[ftmp3], %[ftmp3], %[offset] \n\t" \ + "gsldlc1 %[ftmp4], 0x07(%[src2]) \n\t" \ + "gsldrc1 %[ftmp4], 0x00(%[src2]) \n\t" \ + "li %[rtmp0], 0x10 \n\t" \ + "dmtc1 %[rtmp0], %[ftmp8] \n\t" \ + "punpcklhw %[ftmp5], %[ftmp0], %[ftmp3] \n\t" \ + "punpckhhw %[ftmp6], %[ftmp0], %[ftmp3] \n\t" \ + "punpckhhw %[ftmp3], %[ftmp0], %[ftmp4] \n\t" \ + "punpcklhw %[ftmp4], %[ftmp0], %[ftmp4] \n\t" \ + "psraw %[ftmp5], %[ftmp5], %[ftmp8] \n\t" \ + "psraw %[ftmp6], %[ftmp6], %[ftmp8] \n\t" \ + "psraw %[ftmp3], %[ftmp3], %[ftmp8] \n\t" \ + "psraw %[ftmp4], %[ftmp4], %[ftmp8] \n\t" \ + "paddw %[ftmp5], %[ftmp5], %[ftmp4] \n\t" \ + "paddw %[ftmp6], %[ftmp6], %[ftmp3] \n\t" \ + "psraw %[ftmp5], %[ftmp5], %[shift] \n\t" \ + "psraw %[ftmp6], %[ftmp6], %[shift] \n\t" \ + "packsswh %[ftmp5], %[ftmp5], %[ftmp6] \n\t" \ + "pcmpgth %[ftmp7], %[ftmp5], %[ftmp0] \n\t" \ + "and %[ftmp3], %[ftmp5], %[ftmp7] \n\t" \ + "packushb %[ftmp3], %[ftmp3], %[ftmp3] \n\t" \ + "gsswlc1 %[ftmp3], 0x03(%[dst]) \n\t" \ + "gsswrc1 %[ftmp3], 0x00(%[dst]) \n\t" \ + \ + "daddi %[x], %[x], -0x01 \n\t" \ + PTR_ADDIU "%[src], %[src], 0x04 \n\t" \ + PTR_ADDIU "%[dst], %[dst], 0x04 \n\t" \ + PTR_ADDIU "%[src2], %[src2], 0x08 \n\t" \ + "bnez %[x], 2b \n\t" \ + \ + "daddi %[y], %[y], -0x01 \n\t" \ + PTR_ADDIU "%[src], %[src], " #src_step " \n\t" \ + PTR_ADDIU "%[dst], %[dst], " #dst_step " \n\t" \ + PTR_ADDIU "%[src2], %[src2], " #src2_step " \n\t" \ + PTR_ADDU "%[src], %[src], %[src_stride] \n\t" \ + PTR_ADDU "%[dst], %[dst], %[dst_stride] \n\t" \ + PTR_ADDIU "%[src2], %[src2], 0x80 \n\t" \ + "bnez %[y], 1b \n\t" \ + : [ftmp0]"=&f"(ftmp[0]), [ftmp1]"=&f"(ftmp[1]), \ + [ftmp2]"=&f"(ftmp[2]), [ftmp3]"=&f"(ftmp[3]), \ + [ftmp4]"=&f"(ftmp[4]), [ftmp5]"=&f"(ftmp[5]), \ + [ftmp6]"=&f"(ftmp[6]), [ftmp7]"=&f"(ftmp[7]), \ + [ftmp8]"=&f"(ftmp[8]), [ftmp9]"=&f"(ftmp[9]), \ + [ftmp10]"=&f"(ftmp[10]), [ftmp11]"=&f"(ftmp[11]), \ + [ftmp12]"=&f"(ftmp[12]), [src2]"+&r"(src2), \ + [dst]"+&r"(dst), [src]"+&r"(src), [y]"+&r"(y), [x]"=&r"(x), \ + [offset]"+&f"(offset), [rtmp0]"=&r"(rtmp[0]) \ + : [src_stride]"r"(srcstride), [dst_stride]"r"(dststride), \ + [filter]"r"(filter), [shift]"f"(shift) \ + : "memory" \ + ); \ +} + +PUT_HEVC_QPEL_BI_H(4, 1, -4, -8, -4); +PUT_HEVC_QPEL_BI_H(8, 2, -8, -16, -8); +PUT_HEVC_QPEL_BI_H(12, 3, -12, -24, -12); +PUT_HEVC_QPEL_BI_H(16, 4, -16, -32, -16); +PUT_HEVC_QPEL_BI_H(24, 6, -24, -48, -24); +PUT_HEVC_QPEL_BI_H(32, 8, -32, -64, -32); +PUT_HEVC_QPEL_BI_H(48, 12, -48, -96, -48); +PUT_HEVC_QPEL_BI_H(64, 16, -64, -128, -64); + +#define PUT_HEVC_QPEL_BI_HV(w, x_step, src_step, src2_step, dst_step) \ +void ff_hevc_put_hevc_qpel_bi_hv##w##_8_mmi(uint8_t *_dst, \ + ptrdiff_t _dststride, \ + uint8_t *_src, \ + ptrdiff_t _srcstride, \ + int16_t *src2, int height, \ + intptr_t mx, intptr_t my, \ + int width) \ +{ \ + int x, y; \ + const int8_t *filter; \ + pixel *src = (pixel*)_src; \ + ptrdiff_t srcstride = _srcstride / sizeof(pixel); \ + pixel *dst = (pixel *)_dst; \ + ptrdiff_t dststride = _dststride / sizeof(pixel); \ + int16_t tmp_array[(MAX_PB_SIZE + QPEL_EXTRA) * MAX_PB_SIZE]; \ + int16_t *tmp = tmp_array; \ + uint64_t ftmp[20]; \ + uint64_t rtmp[1]; \ + int shift = 7; \ + int offset = 64; \ + \ + src -= (QPEL_EXTRA_BEFORE * srcstride + 3); \ + filter = ff_hevc_qpel_filters[mx - 1]; \ + x = width >> 2; \ + y = height + QPEL_EXTRA; \ + __asm__ volatile( \ + MMI_LDC1(%[ftmp1], %[filter], 0x00) \ + "li %[rtmp0], 0x08 \n\t" \ + "dmtc1 %[rtmp0], %[ftmp0] \n\t" \ + "punpckhbh %[ftmp2], %[ftmp0], %[ftmp1] \n\t" \ + "punpcklbh %[ftmp1], %[ftmp0], %[ftmp1] \n\t" \ + "psrah %[ftmp1], %[ftmp1], %[ftmp0] \n\t" \ + "psrah %[ftmp2], %[ftmp2], %[ftmp0] \n\t" \ + "xor %[ftmp0], %[ftmp0], %[ftmp0] \n\t" \ + \ + "1: \n\t" \ + "2: \n\t" \ + "gsldlc1 %[ftmp3], 0x07(%[src]) \n\t" \ + "gsldrc1 %[ftmp3], 0x00(%[src]) \n\t" \ + "gsldlc1 %[ftmp4], 0x08(%[src]) \n\t" \ + "gsldrc1 %[ftmp4], 0x01(%[src]) \n\t" \ + "gsldlc1 %[ftmp5], 0x09(%[src]) \n\t" \ + "gsldrc1 %[ftmp5], 0x02(%[src]) \n\t" \ + "gsldlc1 %[ftmp6], 0x0a(%[src]) \n\t" \ + "gsldrc1 %[ftmp6], 0x03(%[src]) \n\t" \ + "punpcklbh %[ftmp7], %[ftmp3], %[ftmp0] \n\t" \ + "punpckhbh %[ftmp8], %[ftmp3], %[ftmp0] \n\t" \ + "pmullh %[ftmp7], %[ftmp7], %[ftmp1] \n\t" \ + "pmullh %[ftmp8], %[ftmp8], %[ftmp2] \n\t" \ + "paddh %[ftmp3], %[ftmp7], %[ftmp8] \n\t" \ + "punpcklbh %[ftmp7], %[ftmp4], %[ftmp0] \n\t" \ + "punpckhbh %[ftmp8], %[ftmp4], %[ftmp0] \n\t" \ + "pmullh %[ftmp7], %[ftmp7], %[ftmp1] \n\t" \ + "pmullh %[ftmp8], %[ftmp8], %[ftmp2] \n\t" \ + "paddh %[ftmp4], %[ftmp7], %[ftmp8] \n\t" \ + "punpcklbh %[ftmp7], %[ftmp5], %[ftmp0] \n\t" \ + "punpckhbh %[ftmp8], %[ftmp5], %[ftmp0] \n\t" \ + "pmullh %[ftmp7], %[ftmp7], %[ftmp1] \n\t" \ + "pmullh %[ftmp8], %[ftmp8], %[ftmp2] \n\t" \ + "paddh %[ftmp5], %[ftmp7], %[ftmp8] \n\t" \ + "punpcklbh %[ftmp7], %[ftmp6], %[ftmp0] \n\t" \ + "punpckhbh %[ftmp8], %[ftmp6], %[ftmp0] \n\t" \ + "pmullh %[ftmp7], %[ftmp7], %[ftmp1] \n\t" \ + "pmullh %[ftmp8], %[ftmp8], %[ftmp2] \n\t" \ + "paddh %[ftmp6], %[ftmp7], %[ftmp8] \n\t" \ + TRANSPOSE_4H(%[ftmp3], %[ftmp4], %[ftmp5], %[ftmp6], \ + %[ftmp7], %[ftmp8], %[ftmp9], %[ftmp10]) \ + "paddh %[ftmp3], %[ftmp3], %[ftmp4] \n\t" \ + "paddh %[ftmp5], %[ftmp5], %[ftmp6] \n\t" \ + "paddh %[ftmp3], %[ftmp3], %[ftmp5] \n\t" \ + "gssdlc1 %[ftmp3], 0x07(%[tmp]) \n\t" \ + "gssdrc1 %[ftmp3], 0x00(%[tmp]) \n\t" \ + \ + "daddi %[x], %[x], -0x01 \n\t" \ + PTR_ADDIU "%[src], %[src], 0x04 \n\t" \ + PTR_ADDIU "%[tmp], %[tmp], 0x08 \n\t" \ + "bnez %[x], 2b \n\t" \ + \ + "daddi %[y], %[y], -0x01 \n\t" \ + "li %[x], " #x_step " \n\t" \ + PTR_ADDIU "%[src], %[src], " #src_step " \n\t" \ + PTR_ADDIU "%[tmp], %[tmp], " #src2_step " \n\t" \ + PTR_ADDU "%[src], %[src], %[stride] \n\t" \ + PTR_ADDIU "%[tmp], %[tmp], 0x80 \n\t" \ + "bnez %[y], 1b \n\t" \ + : [ftmp0]"=&f"(ftmp[0]), [ftmp1]"=&f"(ftmp[1]), \ + [ftmp2]"=&f"(ftmp[2]), [ftmp3]"=&f"(ftmp[3]), \ + [ftmp4]"=&f"(ftmp[4]), [ftmp5]"=&f"(ftmp[5]), \ + [ftmp6]"=&f"(ftmp[6]), [ftmp7]"=&f"(ftmp[7]), \ + [ftmp8]"=&f"(ftmp[8]), [ftmp9]"=&f"(ftmp[9]), \ + [ftmp10]"=&f"(ftmp[10]), [rtmp0]"=&r"(rtmp[0]), \ + [src]"+&r"(src), [tmp]"+&r"(tmp), [y]"+&r"(y), \ + [x]"+&r"(x) \ + : [filter]"r"(filter), [stride]"r"(srcstride) \ + : "memory" \ + ); \ + \ + tmp = tmp_array; \ + filter = ff_hevc_qpel_filters[my - 1]; \ + x = width >> 2; \ + y = height; \ + __asm__ volatile( \ + MMI_LDC1(%[ftmp1], %[filter], 0x00) \ + "li %[rtmp0], 0x08 \n\t" \ + "dmtc1 %[rtmp0], %[ftmp0] \n\t" \ + "punpckhbh %[ftmp2], %[ftmp0], %[ftmp1] \n\t" \ + "punpcklbh %[ftmp1], %[ftmp0], %[ftmp1] \n\t" \ + "psrah %[ftmp1], %[ftmp1], %[ftmp0] \n\t" \ + "psrah %[ftmp2], %[ftmp2], %[ftmp0] \n\t" \ + "li %[rtmp0], 0x06 \n\t" \ + "dmtc1 %[rtmp0], %[ftmp0] \n\t" \ + "punpcklwd %[offset], %[offset], %[offset] \n\t" \ + \ + "1: \n\t" \ + "li %[x], " #x_step " \n\t" \ + "2: \n\t" \ + "gsldlc1 %[ftmp3], 0x07(%[tmp]) \n\t" \ + "gsldrc1 %[ftmp3], 0x00(%[tmp]) \n\t" \ + PTR_ADDIU "%[tmp], %[tmp], 0x80 \n\t" \ + "gsldlc1 %[ftmp4], 0x07(%[tmp]) \n\t" \ + "gsldrc1 %[ftmp4], 0x00(%[tmp]) \n\t" \ + PTR_ADDIU "%[tmp], %[tmp], 0x80 \n\t" \ + "gsldlc1 %[ftmp5], 0x07(%[tmp]) \n\t" \ + "gsldrc1 %[ftmp5], 0x00(%[tmp]) \n\t" \ + PTR_ADDIU "%[tmp], %[tmp], 0x80 \n\t" \ + "gsldlc1 %[ftmp6], 0x07(%[tmp]) \n\t" \ + "gsldrc1 %[ftmp6], 0x00(%[tmp]) \n\t" \ + PTR_ADDIU "%[tmp], %[tmp], 0x80 \n\t" \ + "gsldlc1 %[ftmp7], 0x07(%[tmp]) \n\t" \ + "gsldrc1 %[ftmp7], 0x00(%[tmp]) \n\t" \ + PTR_ADDIU "%[tmp], %[tmp], 0x80 \n\t" \ + "gsldlc1 %[ftmp8], 0x07(%[tmp]) \n\t" \ + "gsldrc1 %[ftmp8], 0x00(%[tmp]) \n\t" \ + PTR_ADDIU "%[tmp], %[tmp], 0x80 \n\t" \ + "gsldlc1 %[ftmp9], 0x07(%[tmp]) \n\t" \ + "gsldrc1 %[ftmp9], 0x00(%[tmp]) \n\t" \ + PTR_ADDIU "%[tmp], %[tmp], 0x80 \n\t" \ + "gsldlc1 %[ftmp10], 0x07(%[tmp]) \n\t" \ + "gsldrc1 %[ftmp10], 0x00(%[tmp]) \n\t" \ + PTR_ADDIU "%[tmp], %[tmp], -0x380 \n\t" \ + TRANSPOSE_4H(%[ftmp3], %[ftmp4], %[ftmp5], %[ftmp6], \ + %[ftmp11], %[ftmp12], %[ftmp13], %[ftmp14]) \ + TRANSPOSE_4H(%[ftmp7], %[ftmp8], %[ftmp9], %[ftmp10], \ + %[ftmp11], %[ftmp12], %[ftmp13], %[ftmp14]) \ + "pmaddhw %[ftmp11], %[ftmp3], %[ftmp1] \n\t" \ + "pmaddhw %[ftmp12], %[ftmp7], %[ftmp2] \n\t" \ + "pmaddhw %[ftmp13], %[ftmp4], %[ftmp1] \n\t" \ + "pmaddhw %[ftmp14], %[ftmp8], %[ftmp2] \n\t" \ + "paddw %[ftmp11], %[ftmp11], %[ftmp12] \n\t" \ + "paddw %[ftmp13], %[ftmp13], %[ftmp14] \n\t" \ + TRANSPOSE_2W(%[ftmp11], %[ftmp13], %[ftmp3], %[ftmp4]) \ + "paddw %[ftmp3], %[ftmp3], %[ftmp4] \n\t" \ + "psraw %[ftmp3], %[ftmp3], %[ftmp0] \n\t" \ + "pmaddhw %[ftmp11], %[ftmp5], %[ftmp1] \n\t" \ + "pmaddhw %[ftmp12], %[ftmp9], %[ftmp2] \n\t" \ + "pmaddhw %[ftmp13], %[ftmp6], %[ftmp1] \n\t" \ + "pmaddhw %[ftmp14], %[ftmp10], %[ftmp2] \n\t" \ + "paddw %[ftmp11], %[ftmp11], %[ftmp12] \n\t" \ + "paddw %[ftmp13], %[ftmp13], %[ftmp14] \n\t" \ + TRANSPOSE_2W(%[ftmp11], %[ftmp13], %[ftmp5], %[ftmp6]) \ + "paddw %[ftmp5], %[ftmp5], %[ftmp6] \n\t" \ + "psraw %[ftmp5], %[ftmp5], %[ftmp0] \n\t" \ + "packsswh %[ftmp3], %[ftmp3], %[ftmp5] \n\t" \ + "gsldlc1 %[ftmp4], 0x07(%[src2]) \n\t" \ + "gsldrc1 %[ftmp4], 0x00(%[src2]) \n\t" \ + "xor %[ftmp7], %[ftmp7], %[ftmp7] \n\t" \ + "li %[rtmp0], 0x10 \n\t" \ + "dmtc1 %[rtmp0], %[ftmp8] \n\t" \ + "punpcklhw %[ftmp5], %[ftmp7], %[ftmp3] \n\t" \ + "punpckhhw %[ftmp6], %[ftmp7], %[ftmp3] \n\t" \ + "punpckhhw %[ftmp3], %[ftmp7], %[ftmp4] \n\t" \ + "punpcklhw %[ftmp4], %[ftmp7], %[ftmp4] \n\t" \ + "psraw %[ftmp5], %[ftmp5], %[ftmp8] \n\t" \ + "psraw %[ftmp6], %[ftmp6], %[ftmp8] \n\t" \ + "psraw %[ftmp3], %[ftmp3], %[ftmp8] \n\t" \ + "psraw %[ftmp4], %[ftmp4], %[ftmp8] \n\t" \ + "paddw %[ftmp5], %[ftmp5], %[ftmp4] \n\t" \ + "paddw %[ftmp6], %[ftmp6], %[ftmp3] \n\t" \ + "paddw %[ftmp5], %[ftmp5], %[offset] \n\t" \ + "paddw %[ftmp6], %[ftmp6], %[offset] \n\t" \ + "psraw %[ftmp5], %[ftmp5], %[shift] \n\t" \ + "psraw %[ftmp6], %[ftmp6], %[shift] \n\t" \ + "packsswh %[ftmp5], %[ftmp5], %[ftmp6] \n\t" \ + "pcmpgth %[ftmp7], %[ftmp5], %[ftmp7] \n\t" \ + "and %[ftmp3], %[ftmp5], %[ftmp7] \n\t" \ + "packushb %[ftmp3], %[ftmp3], %[ftmp3] \n\t" \ + "gsswlc1 %[ftmp3], 0x03(%[dst]) \n\t" \ + "gsswrc1 %[ftmp3], 0x00(%[dst]) \n\t" \ + \ + "daddi %[x], %[x], -0x01 \n\t" \ + PTR_ADDIU "%[src2], %[src2], 0x08 \n\t" \ + PTR_ADDIU "%[tmp], %[tmp], 0x08 \n\t" \ + PTR_ADDIU "%[dst], %[dst], 0x04 \n\t" \ + "bnez %[x], 2b \n\t" \ + \ + "daddi %[y], %[y], -0x01 \n\t" \ + PTR_ADDIU "%[src2], %[src2], " #src2_step " \n\t" \ + PTR_ADDIU "%[tmp], %[tmp], " #src2_step " \n\t" \ + PTR_ADDIU "%[dst], %[dst], " #dst_step " \n\t" \ + PTR_ADDIU "%[src2], %[src2], 0x80 \n\t" \ + PTR_ADDU "%[dst], %[dst], %[stride] \n\t" \ + PTR_ADDIU "%[tmp], %[tmp], 0x80 \n\t" \ + "bnez %[y], 1b \n\t" \ + : [ftmp0]"=&f"(ftmp[0]), [ftmp1]"=&f"(ftmp[1]), \ + [ftmp2]"=&f"(ftmp[2]), [ftmp3]"=&f"(ftmp[3]), \ + [ftmp4]"=&f"(ftmp[4]), [ftmp5]"=&f"(ftmp[5]), \ + [ftmp6]"=&f"(ftmp[6]), [ftmp7]"=&f"(ftmp[7]), \ + [ftmp8]"=&f"(ftmp[8]), [ftmp9]"=&f"(ftmp[9]), \ + [ftmp10]"=&f"(ftmp[10]), [ftmp11]"=&f"(ftmp[11]), \ + [ftmp12]"=&f"(ftmp[12]), [ftmp13]"=&f"(ftmp[13]), \ + [ftmp14]"=&f"(ftmp[14]), [src2]"+&r"(src2), \ + [dst]"+&r"(dst), [tmp]"+&r"(tmp), [y]"+&r"(y), [x]"=&r"(x), \ + [offset]"+&f"(offset), [rtmp0]"=&r"(rtmp[0]) \ + : [filter]"r"(filter), [stride]"r"(dststride), \ + [shift]"f"(shift) \ + : "memory" \ + ); \ +} + +PUT_HEVC_QPEL_BI_HV(4, 1, -4, -8, -4); +PUT_HEVC_QPEL_BI_HV(8, 2, -8, -16, -8); +PUT_HEVC_QPEL_BI_HV(12, 3, -12, -24, -12); +PUT_HEVC_QPEL_BI_HV(16, 4, -16, -32, -16); +PUT_HEVC_QPEL_BI_HV(24, 6, -24, -48, -24); +PUT_HEVC_QPEL_BI_HV(32, 8, -32, -64, -32); +PUT_HEVC_QPEL_BI_HV(48, 12, -48, -96, -48); +PUT_HEVC_QPEL_BI_HV(64, 16, -64, -128, -64); + +#define PUT_HEVC_EPEL_BI_HV(w, x_step, src_step, src2_step, dst_step) \ +void ff_hevc_put_hevc_epel_bi_hv##w##_8_mmi(uint8_t *_dst, \ + ptrdiff_t _dststride, \ + uint8_t *_src, \ + ptrdiff_t _srcstride, \ + int16_t *src2, int height, \ + intptr_t mx, intptr_t my, \ + int width) \ +{ \ + int x, y; \ + pixel *src = (pixel *)_src; \ + ptrdiff_t srcstride = _srcstride / sizeof(pixel); \ + pixel *dst = (pixel *)_dst; \ + ptrdiff_t dststride = _dststride / sizeof(pixel); \ + const int8_t *filter = ff_hevc_epel_filters[mx - 1]; \ + int16_t tmp_array[(MAX_PB_SIZE + EPEL_EXTRA) * MAX_PB_SIZE]; \ + int16_t *tmp = tmp_array; \ + uint64_t ftmp[12]; \ + uint64_t rtmp[1]; \ + int shift = 7; \ + int offset = 64; \ + \ + src -= (EPEL_EXTRA_BEFORE * srcstride + 1); \ + x = width >> 2; \ + y = height + EPEL_EXTRA; \ + __asm__ volatile( \ + MMI_LWC1(%[ftmp1], %[filter], 0x00) \ + "li %[rtmp0], 0x08 \n\t" \ + "dmtc1 %[rtmp0], %[ftmp0] \n\t" \ + "punpcklbh %[ftmp1], %[ftmp0], %[ftmp1] \n\t" \ + "psrah %[ftmp1], %[ftmp1], %[ftmp0] \n\t" \ + "xor %[ftmp0], %[ftmp0], %[ftmp0] \n\t" \ + \ + "1: \n\t" \ + "2: \n\t" \ + "gslwlc1 %[ftmp2], 0x03(%[src]) \n\t" \ + "gslwrc1 %[ftmp2], 0x00(%[src]) \n\t" \ + "gslwlc1 %[ftmp3], 0x04(%[src]) \n\t" \ + "gslwrc1 %[ftmp3], 0x01(%[src]) \n\t" \ + "gslwlc1 %[ftmp4], 0x05(%[src]) \n\t" \ + "gslwrc1 %[ftmp4], 0x02(%[src]) \n\t" \ + "gslwlc1 %[ftmp5], 0x06(%[src]) \n\t" \ + "gslwrc1 %[ftmp5], 0x03(%[src]) \n\t" \ + "punpcklbh %[ftmp2], %[ftmp2], %[ftmp0] \n\t" \ + "pmullh %[ftmp2], %[ftmp2], %[ftmp1] \n\t" \ + "punpcklbh %[ftmp3], %[ftmp3], %[ftmp0] \n\t" \ + "pmullh %[ftmp3], %[ftmp3], %[ftmp1] \n\t" \ + "punpcklbh %[ftmp4], %[ftmp4], %[ftmp0] \n\t" \ + "pmullh %[ftmp4], %[ftmp4], %[ftmp1] \n\t" \ + "punpcklbh %[ftmp5], %[ftmp5], %[ftmp0] \n\t" \ + "pmullh %[ftmp5], %[ftmp5], %[ftmp1] \n\t" \ + TRANSPOSE_4H(%[ftmp2], %[ftmp3], %[ftmp4], %[ftmp5], \ + %[ftmp6], %[ftmp7], %[ftmp8], %[ftmp9]) \ + "paddh %[ftmp2], %[ftmp2], %[ftmp3] \n\t" \ + "paddh %[ftmp4], %[ftmp4], %[ftmp5] \n\t" \ + "paddh %[ftmp2], %[ftmp2], %[ftmp4] \n\t" \ + "gssdlc1 %[ftmp2], 0x07(%[tmp]) \n\t" \ + "gssdrc1 %[ftmp2], 0x00(%[tmp]) \n\t" \ + \ + "daddi %[x], %[x], -0x01 \n\t" \ + PTR_ADDIU "%[src], %[src], 0x04 \n\t" \ + PTR_ADDIU "%[tmp], %[tmp], 0x08 \n\t" \ + "bnez %[x], 2b \n\t" \ + \ + "daddi %[y], %[y], -0x01 \n\t" \ + "li %[x], " #x_step " \n\t" \ + PTR_ADDIU "%[src], %[src], " #src_step " \n\t" \ + PTR_ADDIU "%[tmp], %[tmp], " #src2_step " \n\t" \ + PTR_ADDU "%[src], %[src], %[stride] \n\t" \ + PTR_ADDIU "%[tmp], %[tmp], 0x80 \n\t" \ + "bnez %[y], 1b \n\t" \ + : [ftmp0]"=&f"(ftmp[0]), [ftmp1]"=&f"(ftmp[1]), \ + [ftmp2]"=&f"(ftmp[2]), [ftmp3]"=&f"(ftmp[3]), \ + [ftmp4]"=&f"(ftmp[4]), [ftmp5]"=&f"(ftmp[5]), \ + [ftmp6]"=&f"(ftmp[6]), [ftmp7]"=&f"(ftmp[7]), \ + [ftmp8]"=&f"(ftmp[8]), [ftmp9]"=&f"(ftmp[9]), \ + [rtmp0]"=&r"(rtmp[0]), \ + [src]"+&r"(src), [tmp]"+&r"(tmp), [y]"+&r"(y), \ + [x]"+&r"(x) \ + : [filter]"r"(filter), [stride]"r"(srcstride) \ + : "memory" \ + ); \ + \ + tmp = tmp_array; \ + filter = ff_hevc_epel_filters[my - 1]; \ + x = width >> 2; \ + y = height; \ + __asm__ volatile( \ + MMI_LWC1(%[ftmp1], %[filter], 0x00) \ + "li %[rtmp0], 0x08 \n\t" \ + "dmtc1 %[rtmp0], %[ftmp0] \n\t" \ + "punpcklbh %[ftmp1], %[ftmp0], %[ftmp1] \n\t" \ + "psrah %[ftmp1], %[ftmp1], %[ftmp0] \n\t" \ + "li %[rtmp0], 0x06 \n\t" \ + "dmtc1 %[rtmp0], %[ftmp0] \n\t" \ + "punpcklwd %[offset], %[offset], %[offset] \n\t" \ + "xor %[ftmp2], %[ftmp2], %[ftmp2] \n\t" \ + \ + "1: \n\t" \ + "li %[x], " #x_step " \n\t" \ + "2: \n\t" \ + "gsldlc1 %[ftmp3], 0x07(%[tmp]) \n\t" \ + "gsldrc1 %[ftmp3], 0x00(%[tmp]) \n\t" \ + PTR_ADDIU "%[tmp], %[tmp], 0x80 \n\t" \ + "gsldlc1 %[ftmp4], 0x07(%[tmp]) \n\t" \ + "gsldrc1 %[ftmp4], 0x00(%[tmp]) \n\t" \ + PTR_ADDIU "%[tmp], %[tmp], 0x80 \n\t" \ + "gsldlc1 %[ftmp5], 0x07(%[tmp]) \n\t" \ + "gsldrc1 %[ftmp5], 0x00(%[tmp]) \n\t" \ + PTR_ADDIU "%[tmp], %[tmp], 0x80 \n\t" \ + "gsldlc1 %[ftmp6], 0x07(%[tmp]) \n\t" \ + "gsldrc1 %[ftmp6], 0x00(%[tmp]) \n\t" \ + PTR_ADDIU "%[tmp], %[tmp], -0x180 \n\t" \ + TRANSPOSE_4H(%[ftmp3], %[ftmp4], %[ftmp5], %[ftmp6], \ + %[ftmp7], %[ftmp8], %[ftmp9], %[ftmp10]) \ + "pmaddhw %[ftmp7], %[ftmp3], %[ftmp1] \n\t" \ + "pmaddhw %[ftmp8], %[ftmp4], %[ftmp1] \n\t" \ + TRANSPOSE_2W(%[ftmp7], %[ftmp8], %[ftmp3], %[ftmp4]) \ + "paddw %[ftmp3], %[ftmp3], %[ftmp4] \n\t" \ + "psraw %[ftmp3], %[ftmp3], %[ftmp0] \n\t" \ + "pmaddhw %[ftmp7], %[ftmp5], %[ftmp1] \n\t" \ + "pmaddhw %[ftmp8], %[ftmp6], %[ftmp1] \n\t" \ + TRANSPOSE_2W(%[ftmp7], %[ftmp8], %[ftmp5], %[ftmp6]) \ + "paddw %[ftmp5], %[ftmp5], %[ftmp6] \n\t" \ + "psraw %[ftmp5], %[ftmp5], %[ftmp0] \n\t" \ + "packsswh %[ftmp3], %[ftmp3], %[ftmp5] \n\t" \ + "gsldlc1 %[ftmp4], 0x07(%[src2]) \n\t" \ + "gsldrc1 %[ftmp4], 0x00(%[src2]) \n\t" \ + "li %[rtmp0], 0x10 \n\t" \ + "dmtc1 %[rtmp0], %[ftmp8] \n\t" \ + "punpcklhw %[ftmp5], %[ftmp2], %[ftmp3] \n\t" \ + "punpckhhw %[ftmp6], %[ftmp2], %[ftmp3] \n\t" \ + "punpckhhw %[ftmp3], %[ftmp2], %[ftmp4] \n\t" \ + "punpcklhw %[ftmp4], %[ftmp2], %[ftmp4] \n\t" \ + "psraw %[ftmp5], %[ftmp5], %[ftmp8] \n\t" \ + "psraw %[ftmp6], %[ftmp6], %[ftmp8] \n\t" \ + "psraw %[ftmp3], %[ftmp3], %[ftmp8] \n\t" \ + "psraw %[ftmp4], %[ftmp4], %[ftmp8] \n\t" \ + "paddw %[ftmp5], %[ftmp5], %[ftmp4] \n\t" \ + "paddw %[ftmp6], %[ftmp6], %[ftmp3] \n\t" \ + "paddw %[ftmp5], %[ftmp5], %[offset] \n\t" \ + "paddw %[ftmp6], %[ftmp6], %[offset] \n\t" \ + "psraw %[ftmp5], %[ftmp5], %[shift] \n\t" \ + "psraw %[ftmp6], %[ftmp6], %[shift] \n\t" \ + "packsswh %[ftmp5], %[ftmp5], %[ftmp6] \n\t" \ + "pcmpgth %[ftmp7], %[ftmp5], %[ftmp2] \n\t" \ + "and %[ftmp3], %[ftmp5], %[ftmp7] \n\t" \ + "packushb %[ftmp3], %[ftmp3], %[ftmp3] \n\t" \ + "gsswlc1 %[ftmp3], 0x03(%[dst]) \n\t" \ + "gsswrc1 %[ftmp3], 0x00(%[dst]) \n\t" \ + \ + "daddi %[x], %[x], -0x01 \n\t" \ + PTR_ADDIU "%[src2], %[src2], 0x08 \n\t" \ + PTR_ADDIU "%[tmp], %[tmp], 0x08 \n\t" \ + PTR_ADDIU "%[dst], %[dst], 0x04 \n\t" \ + "bnez %[x], 2b \n\t" \ + \ + "daddi %[y], %[y], -0x01 \n\t" \ + PTR_ADDIU "%[src2], %[src2], " #src2_step " \n\t" \ + PTR_ADDIU "%[tmp], %[tmp], " #src2_step " \n\t" \ + PTR_ADDIU "%[dst], %[dst], " #dst_step " \n\t" \ + PTR_ADDIU "%[src2], %[src2], 0x80 \n\t" \ + PTR_ADDU "%[dst], %[dst], %[stride] \n\t" \ + PTR_ADDIU "%[tmp], %[tmp], 0x80 \n\t" \ + "bnez %[y], 1b \n\t" \ + : [ftmp0]"=&f"(ftmp[0]), [ftmp1]"=&f"(ftmp[1]), \ + [ftmp2]"=&f"(ftmp[2]), [ftmp3]"=&f"(ftmp[3]), \ + [ftmp4]"=&f"(ftmp[4]), [ftmp5]"=&f"(ftmp[5]), \ + [ftmp6]"=&f"(ftmp[6]), [ftmp7]"=&f"(ftmp[7]), \ + [ftmp8]"=&f"(ftmp[8]), [ftmp9]"=&f"(ftmp[9]), \ + [ftmp10]"=&f"(ftmp[10]), [src2]"+&r"(src2), \ + [dst]"+&r"(dst), [tmp]"+&r"(tmp), [y]"+&r"(y), [x]"=&r"(x), \ + [offset]"+&f"(offset), [rtmp0]"=&r"(rtmp[0]) \ + : [filter]"r"(filter), [stride]"r"(dststride), \ + [shift]"f"(shift) \ + : "memory" \ + ); \ +} + +PUT_HEVC_EPEL_BI_HV(4, 1, -4, -8, -4); +PUT_HEVC_EPEL_BI_HV(8, 2, -8, -16, -8); +PUT_HEVC_EPEL_BI_HV(12, 3, -12, -24, -12); +PUT_HEVC_EPEL_BI_HV(16, 4, -16, -32, -16); +PUT_HEVC_EPEL_BI_HV(24, 6, -24, -48, -24); +PUT_HEVC_EPEL_BI_HV(32, 8, -32, -64, -32); + +#define PUT_HEVC_PEL_BI_PIXELS(w, x_step, src_step, dst_step, src2_step) \ +void ff_hevc_put_hevc_pel_bi_pixels##w##_8_mmi(uint8_t *_dst, \ + ptrdiff_t _dststride, \ + uint8_t *_src, \ + ptrdiff_t _srcstride, \ + int16_t *src2, int height, \ + intptr_t mx, intptr_t my, \ + int width) \ +{ \ + int x, y; \ + pixel *src = (pixel *)_src; \ + ptrdiff_t srcstride = _srcstride / sizeof(pixel); \ + pixel *dst = (pixel *)_dst; \ + ptrdiff_t dststride = _dststride / sizeof(pixel); \ + uint64_t ftmp[12]; \ + uint64_t rtmp[1]; \ + int shift = 7; \ + \ + y = height; \ + x = width >> 3; \ + __asm__ volatile( \ + "xor %[ftmp0], %[ftmp0], %[ftmp0] \n\t" \ + "li %[rtmp0], 0x06 \n\t" \ + "dmtc1 %[rtmp0], %[ftmp1] \n\t" \ + "li %[rtmp0], 0x10 \n\t" \ + "dmtc1 %[rtmp0], %[ftmp10] \n\t" \ + "li %[rtmp0], 0x40 \n\t" \ + "dmtc1 %[rtmp0], %[offset] \n\t" \ + "punpcklhw %[offset], %[offset], %[offset] \n\t" \ + "punpcklwd %[offset], %[offset], %[offset] \n\t" \ + \ + "1: \n\t" \ + "2: \n\t" \ + "gsldlc1 %[ftmp5], 0x07(%[src]) \n\t" \ + "gsldrc1 %[ftmp5], 0x00(%[src]) \n\t" \ + "gsldlc1 %[ftmp2], 0x07(%[src2]) \n\t" \ + "gsldrc1 %[ftmp2], 0x00(%[src2]) \n\t" \ + "gsldlc1 %[ftmp3], 0x0f(%[src2]) \n\t" \ + "gsldrc1 %[ftmp3], 0x08(%[src2]) \n\t" \ + "punpcklbh %[ftmp4], %[ftmp5], %[ftmp0] \n\t" \ + "punpckhbh %[ftmp5], %[ftmp5], %[ftmp0] \n\t" \ + "psllh %[ftmp4], %[ftmp4], %[ftmp1] \n\t" \ + "psllh %[ftmp5], %[ftmp5], %[ftmp1] \n\t" \ + "paddh %[ftmp4], %[ftmp4], %[offset] \n\t" \ + "paddh %[ftmp5], %[ftmp5], %[offset] \n\t" \ + "punpcklhw %[ftmp6], %[ftmp4], %[ftmp0] \n\t" \ + "punpckhhw %[ftmp7], %[ftmp4], %[ftmp0] \n\t" \ + "punpcklhw %[ftmp8], %[ftmp5], %[ftmp0] \n\t" \ + "punpckhhw %[ftmp9], %[ftmp5], %[ftmp0] \n\t" \ + "punpcklhw %[ftmp4], %[ftmp0], %[ftmp3] \n\t" \ + "punpckhhw %[ftmp5], %[ftmp0], %[ftmp3] \n\t" \ + "punpckhhw %[ftmp3], %[ftmp0], %[ftmp2] \n\t" \ + "punpcklhw %[ftmp2], %[ftmp0], %[ftmp2] \n\t" \ + "psraw %[ftmp2], %[ftmp2], %[ftmp10] \n\t" \ + "psraw %[ftmp3], %[ftmp3], %[ftmp10] \n\t" \ + "psraw %[ftmp4], %[ftmp4], %[ftmp10] \n\t" \ + "psraw %[ftmp5], %[ftmp5], %[ftmp10] \n\t" \ + "paddw %[ftmp2], %[ftmp2], %[ftmp6] \n\t" \ + "paddw %[ftmp3], %[ftmp3], %[ftmp7] \n\t" \ + "paddw %[ftmp4], %[ftmp4], %[ftmp8] \n\t" \ + "paddw %[ftmp5], %[ftmp5], %[ftmp9] \n\t" \ + "psraw %[ftmp2], %[ftmp2], %[shift] \n\t" \ + "psraw %[ftmp3], %[ftmp3], %[shift] \n\t" \ + "psraw %[ftmp4], %[ftmp4], %[shift] \n\t" \ + "psraw %[ftmp5], %[ftmp5], %[shift] \n\t" \ + "packsswh %[ftmp2], %[ftmp2], %[ftmp3] \n\t" \ + "packsswh %[ftmp4], %[ftmp4], %[ftmp5] \n\t" \ + "pcmpgth %[ftmp3], %[ftmp2], %[ftmp0] \n\t" \ + "pcmpgth %[ftmp5], %[ftmp4], %[ftmp0] \n\t" \ + "and %[ftmp2], %[ftmp2], %[ftmp3] \n\t" \ + "and %[ftmp4], %[ftmp4], %[ftmp5] \n\t" \ + "packushb %[ftmp2], %[ftmp2], %[ftmp4] \n\t" \ + "gssdlc1 %[ftmp2], 0x07(%[dst]) \n\t" \ + "gssdrc1 %[ftmp2], 0x00(%[dst]) \n\t" \ + \ + "daddi %[x], %[x], -0x01 \n\t" \ + PTR_ADDIU "%[src], %[src], 0x08 \n\t" \ + PTR_ADDIU "%[dst], %[dst], 0x08 \n\t" \ + PTR_ADDIU "%[src2], %[src2], 0x10 \n\t" \ + "bnez %[x], 2b \n\t" \ + \ + PTR_ADDIU "%[src], %[src], " #src_step " \n\t" \ + PTR_ADDIU "%[dst], %[dst], " #dst_step " \n\t" \ + PTR_ADDIU "%[src2], %[src2], " #src2_step " \n\t" \ + "li %[x], " #x_step " \n\t" \ + "daddi %[y], %[y], -0x01 \n\t" \ + PTR_ADDU "%[src], %[src], %[srcstride] \n\t" \ + PTR_ADDU "%[dst], %[dst], %[dststride] \n\t" \ + PTR_ADDIU "%[src2], %[src2], 0x80 \n\t" \ + "bnez %[y], 1b \n\t" \ + : [ftmp0]"=&f"(ftmp[0]), [ftmp1]"=&f"(ftmp[1]), \ + [ftmp2]"=&f"(ftmp[2]), [ftmp3]"=&f"(ftmp[3]), \ + [ftmp4]"=&f"(ftmp[4]), [ftmp5]"=&f"(ftmp[5]), \ + [ftmp6]"=&f"(ftmp[6]), [ftmp7]"=&f"(ftmp[7]), \ + [ftmp8]"=&f"(ftmp[8]), [ftmp9]"=&f"(ftmp[9]), \ + [ftmp10]"=&f"(ftmp[10]), [offset]"=&f"(ftmp[11]), \ + [src2]"+&r"(src2), [dst]"+&r"(dst), [src]"+&r"(src), \ + [x]"+&r"(x), [y]"+&r"(y), [rtmp0]"=&r"(rtmp[0]) \ + : [dststride]"r"(dststride), [shift]"f"(shift), \ + [srcstride]"r"(srcstride) \ + : "memory" \ + ); \ +} \ + +PUT_HEVC_PEL_BI_PIXELS(8, 1, -8, -8, -16); +PUT_HEVC_PEL_BI_PIXELS(16, 2, -16, -16, -32); +PUT_HEVC_PEL_BI_PIXELS(24, 3, -24, -24, -48); +PUT_HEVC_PEL_BI_PIXELS(32, 4, -32, -32, -64); +PUT_HEVC_PEL_BI_PIXELS(48, 6, -48, -48, -96); +PUT_HEVC_PEL_BI_PIXELS(64, 8, -64, -64, -128); + +#define PUT_HEVC_QPEL_UNI_HV(w, x_step, src_step, dst_step, tmp_step) \ +void ff_hevc_put_hevc_qpel_uni_hv##w##_8_mmi(uint8_t *_dst, \ + ptrdiff_t _dststride, \ + uint8_t *_src, \ + ptrdiff_t _srcstride, \ + int height, \ + intptr_t mx, intptr_t my, \ + int width) \ +{ \ + int x, y; \ + const int8_t *filter; \ + pixel *src = (pixel*)_src; \ + ptrdiff_t srcstride = _srcstride / sizeof(pixel); \ + pixel *dst = (pixel *)_dst; \ + ptrdiff_t dststride = _dststride / sizeof(pixel); \ + int16_t tmp_array[(MAX_PB_SIZE + QPEL_EXTRA) * MAX_PB_SIZE]; \ + int16_t *tmp = tmp_array; \ + uint64_t ftmp[20]; \ + uint64_t rtmp[1]; \ + int shift = 6; \ + int offset = 32; \ + \ + src -= (QPEL_EXTRA_BEFORE * srcstride + 3); \ + filter = ff_hevc_qpel_filters[mx - 1]; \ + x = width >> 2; \ + y = height + QPEL_EXTRA; \ + __asm__ volatile( \ + MMI_LDC1(%[ftmp1], %[filter], 0x00) \ + "li %[rtmp0], 0x08 \n\t" \ + "dmtc1 %[rtmp0], %[ftmp0] \n\t" \ + "punpckhbh %[ftmp2], %[ftmp0], %[ftmp1] \n\t" \ + "punpcklbh %[ftmp1], %[ftmp0], %[ftmp1] \n\t" \ + "psrah %[ftmp1], %[ftmp1], %[ftmp0] \n\t" \ + "psrah %[ftmp2], %[ftmp2], %[ftmp0] \n\t" \ + "xor %[ftmp0], %[ftmp0], %[ftmp0] \n\t" \ + \ + "1: \n\t" \ + "2: \n\t" \ + "gsldlc1 %[ftmp3], 0x07(%[src]) \n\t" \ + "gsldrc1 %[ftmp3], 0x00(%[src]) \n\t" \ + "gsldlc1 %[ftmp4], 0x08(%[src]) \n\t" \ + "gsldrc1 %[ftmp4], 0x01(%[src]) \n\t" \ + "gsldlc1 %[ftmp5], 0x09(%[src]) \n\t" \ + "gsldrc1 %[ftmp5], 0x02(%[src]) \n\t" \ + "gsldlc1 %[ftmp6], 0x0a(%[src]) \n\t" \ + "gsldrc1 %[ftmp6], 0x03(%[src]) \n\t" \ + "punpcklbh %[ftmp7], %[ftmp3], %[ftmp0] \n\t" \ + "punpckhbh %[ftmp8], %[ftmp3], %[ftmp0] \n\t" \ + "pmullh %[ftmp7], %[ftmp7], %[ftmp1] \n\t" \ + "pmullh %[ftmp8], %[ftmp8], %[ftmp2] \n\t" \ + "paddh %[ftmp3], %[ftmp7], %[ftmp8] \n\t" \ + "punpcklbh %[ftmp7], %[ftmp4], %[ftmp0] \n\t" \ + "punpckhbh %[ftmp8], %[ftmp4], %[ftmp0] \n\t" \ + "pmullh %[ftmp7], %[ftmp7], %[ftmp1] \n\t" \ + "pmullh %[ftmp8], %[ftmp8], %[ftmp2] \n\t" \ + "paddh %[ftmp4], %[ftmp7], %[ftmp8] \n\t" \ + "punpcklbh %[ftmp7], %[ftmp5], %[ftmp0] \n\t" \ + "punpckhbh %[ftmp8], %[ftmp5], %[ftmp0] \n\t" \ + "pmullh %[ftmp7], %[ftmp7], %[ftmp1] \n\t" \ + "pmullh %[ftmp8], %[ftmp8], %[ftmp2] \n\t" \ + "paddh %[ftmp5], %[ftmp7], %[ftmp8] \n\t" \ + "punpcklbh %[ftmp7], %[ftmp6], %[ftmp0] \n\t" \ + "punpckhbh %[ftmp8], %[ftmp6], %[ftmp0] \n\t" \ + "pmullh %[ftmp7], %[ftmp7], %[ftmp1] \n\t" \ + "pmullh %[ftmp8], %[ftmp8], %[ftmp2] \n\t" \ + "paddh %[ftmp6], %[ftmp7], %[ftmp8] \n\t" \ + TRANSPOSE_4H(%[ftmp3], %[ftmp4], %[ftmp5], %[ftmp6], \ + %[ftmp7], %[ftmp8], %[ftmp9], %[ftmp10]) \ + "paddh %[ftmp3], %[ftmp3], %[ftmp4] \n\t" \ + "paddh %[ftmp5], %[ftmp5], %[ftmp6] \n\t" \ + "paddh %[ftmp3], %[ftmp3], %[ftmp5] \n\t" \ + "gssdlc1 %[ftmp3], 0x07(%[tmp]) \n\t" \ + "gssdrc1 %[ftmp3], 0x00(%[tmp]) \n\t" \ + \ + "daddi %[x], %[x], -0x01 \n\t" \ + PTR_ADDIU "%[src], %[src], 0x04 \n\t" \ + PTR_ADDIU "%[tmp], %[tmp], 0x08 \n\t" \ + "bnez %[x], 2b \n\t" \ + \ + "daddi %[y], %[y], -0x01 \n\t" \ + "li %[x], " #x_step " \n\t" \ + PTR_ADDIU "%[src], %[src], " #src_step " \n\t" \ + PTR_ADDIU "%[tmp], %[tmp], " #tmp_step " \n\t" \ + PTR_ADDU "%[src], %[src], %[stride] \n\t" \ + PTR_ADDIU "%[tmp], %[tmp], 0x80 \n\t" \ + "bnez %[y], 1b \n\t" \ + : [ftmp0]"=&f"(ftmp[0]), [ftmp1]"=&f"(ftmp[1]), \ + [ftmp2]"=&f"(ftmp[2]), [ftmp3]"=&f"(ftmp[3]), \ + [ftmp4]"=&f"(ftmp[4]), [ftmp5]"=&f"(ftmp[5]), \ + [ftmp6]"=&f"(ftmp[6]), [ftmp7]"=&f"(ftmp[7]), \ + [ftmp8]"=&f"(ftmp[8]), [ftmp9]"=&f"(ftmp[9]), \ + [ftmp10]"=&f"(ftmp[10]), [rtmp0]"=&r"(rtmp[0]), \ + [src]"+&r"(src), [tmp]"+&r"(tmp), [y]"+&r"(y), \ + [x]"+&r"(x) \ + : [filter]"r"(filter), [stride]"r"(srcstride) \ + : "memory" \ + ); \ + \ + tmp = tmp_array; \ + filter = ff_hevc_qpel_filters[my - 1]; \ + x = width >> 2; \ + y = height; \ + __asm__ volatile( \ + MMI_LDC1(%[ftmp1], %[filter], 0x00) \ + "li %[rtmp0], 0x08 \n\t" \ + "dmtc1 %[rtmp0], %[ftmp0] \n\t" \ + "punpckhbh %[ftmp2], %[ftmp0], %[ftmp1] \n\t" \ + "punpcklbh %[ftmp1], %[ftmp0], %[ftmp1] \n\t" \ + "psrah %[ftmp1], %[ftmp1], %[ftmp0] \n\t" \ + "psrah %[ftmp2], %[ftmp2], %[ftmp0] \n\t" \ + "li %[rtmp0], 0x06 \n\t" \ + "dmtc1 %[rtmp0], %[ftmp0] \n\t" \ + "punpcklhw %[offset], %[offset], %[offset] \n\t" \ + "punpcklwd %[offset], %[offset], %[offset] \n\t" \ + \ + "1: \n\t" \ + "li %[x], " #x_step " \n\t" \ + "2: \n\t" \ + "gsldlc1 %[ftmp3], 0x07(%[tmp]) \n\t" \ + "gsldrc1 %[ftmp3], 0x00(%[tmp]) \n\t" \ + PTR_ADDIU "%[tmp], %[tmp], 0x80 \n\t" \ + "gsldlc1 %[ftmp4], 0x07(%[tmp]) \n\t" \ + "gsldrc1 %[ftmp4], 0x00(%[tmp]) \n\t" \ + PTR_ADDIU "%[tmp], %[tmp], 0x80 \n\t" \ + "gsldlc1 %[ftmp5], 0x07(%[tmp]) \n\t" \ + "gsldrc1 %[ftmp5], 0x00(%[tmp]) \n\t" \ + PTR_ADDIU "%[tmp], %[tmp], 0x80 \n\t" \ + "gsldlc1 %[ftmp6], 0x07(%[tmp]) \n\t" \ + "gsldrc1 %[ftmp6], 0x00(%[tmp]) \n\t" \ + PTR_ADDIU "%[tmp], %[tmp], 0x80 \n\t" \ + "gsldlc1 %[ftmp7], 0x07(%[tmp]) \n\t" \ + "gsldrc1 %[ftmp7], 0x00(%[tmp]) \n\t" \ + PTR_ADDIU "%[tmp], %[tmp], 0x80 \n\t" \ + "gsldlc1 %[ftmp8], 0x07(%[tmp]) \n\t" \ + "gsldrc1 %[ftmp8], 0x00(%[tmp]) \n\t" \ + PTR_ADDIU "%[tmp], %[tmp], 0x80 \n\t" \ + "gsldlc1 %[ftmp9], 0x07(%[tmp]) \n\t" \ + "gsldrc1 %[ftmp9], 0x00(%[tmp]) \n\t" \ + PTR_ADDIU "%[tmp], %[tmp], 0x80 \n\t" \ + "gsldlc1 %[ftmp10], 0x07(%[tmp]) \n\t" \ + "gsldrc1 %[ftmp10], 0x00(%[tmp]) \n\t" \ + PTR_ADDIU "%[tmp], %[tmp], -0x380 \n\t" \ + TRANSPOSE_4H(%[ftmp3], %[ftmp4], %[ftmp5], %[ftmp6], \ + %[ftmp11], %[ftmp12], %[ftmp13], %[ftmp14]) \ + TRANSPOSE_4H(%[ftmp7], %[ftmp8], %[ftmp9], %[ftmp10], \ + %[ftmp11], %[ftmp12], %[ftmp13], %[ftmp14]) \ + "pmaddhw %[ftmp11], %[ftmp3], %[ftmp1] \n\t" \ + "pmaddhw %[ftmp12], %[ftmp7], %[ftmp2] \n\t" \ + "pmaddhw %[ftmp13], %[ftmp4], %[ftmp1] \n\t" \ + "pmaddhw %[ftmp14], %[ftmp8], %[ftmp2] \n\t" \ + "paddw %[ftmp11], %[ftmp11], %[ftmp12] \n\t" \ + "paddw %[ftmp13], %[ftmp13], %[ftmp14] \n\t" \ + TRANSPOSE_2W(%[ftmp11], %[ftmp13], %[ftmp3], %[ftmp4]) \ + "paddw %[ftmp3], %[ftmp3], %[ftmp4] \n\t" \ + "psraw %[ftmp3], %[ftmp3], %[ftmp0] \n\t" \ + "pmaddhw %[ftmp11], %[ftmp5], %[ftmp1] \n\t" \ + "pmaddhw %[ftmp12], %[ftmp9], %[ftmp2] \n\t" \ + "pmaddhw %[ftmp13], %[ftmp6], %[ftmp1] \n\t" \ + "pmaddhw %[ftmp14], %[ftmp10], %[ftmp2] \n\t" \ + "paddw %[ftmp11], %[ftmp11], %[ftmp12] \n\t" \ + "paddw %[ftmp13], %[ftmp13], %[ftmp14] \n\t" \ + TRANSPOSE_2W(%[ftmp11], %[ftmp13], %[ftmp5], %[ftmp6]) \ + "paddw %[ftmp5], %[ftmp5], %[ftmp6] \n\t" \ + "psraw %[ftmp5], %[ftmp5], %[ftmp0] \n\t" \ + "packsswh %[ftmp3], %[ftmp3], %[ftmp5] \n\t" \ + "paddh %[ftmp3], %[ftmp3], %[offset] \n\t" \ + "psrah %[ftmp3], %[ftmp3], %[shift] \n\t" \ + "xor %[ftmp7], %[ftmp7], %[ftmp7] \n\t" \ + "pcmpgth %[ftmp7], %[ftmp3], %[ftmp7] \n\t" \ + "and %[ftmp3], %[ftmp3], %[ftmp7] \n\t" \ + "packushb %[ftmp3], %[ftmp3], %[ftmp3] \n\t" \ + "gsswlc1 %[ftmp3], 0x03(%[dst]) \n\t" \ + "gsswrc1 %[ftmp3], 0x00(%[dst]) \n\t" \ + \ + "daddi %[x], %[x], -0x01 \n\t" \ + PTR_ADDIU "%[tmp], %[tmp], 0x08 \n\t" \ + PTR_ADDIU "%[dst], %[dst], 0x04 \n\t" \ + "bnez %[x], 2b \n\t" \ + \ + "daddi %[y], %[y], -0x01 \n\t" \ + PTR_ADDIU "%[tmp], %[tmp], " #tmp_step " \n\t" \ + PTR_ADDIU "%[dst], %[dst], " #dst_step " \n\t" \ + PTR_ADDU "%[dst], %[dst], %[stride] \n\t" \ + PTR_ADDIU "%[tmp], %[tmp], 0x80 \n\t" \ + "bnez %[y], 1b \n\t" \ + : [ftmp0]"=&f"(ftmp[0]), [ftmp1]"=&f"(ftmp[1]), \ + [ftmp2]"=&f"(ftmp[2]), [ftmp3]"=&f"(ftmp[3]), \ + [ftmp4]"=&f"(ftmp[4]), [ftmp5]"=&f"(ftmp[5]), \ + [ftmp6]"=&f"(ftmp[6]), [ftmp7]"=&f"(ftmp[7]), \ + [ftmp8]"=&f"(ftmp[8]), [ftmp9]"=&f"(ftmp[9]), \ + [ftmp10]"=&f"(ftmp[10]), [ftmp11]"=&f"(ftmp[11]), \ + [ftmp12]"=&f"(ftmp[12]), [ftmp13]"=&f"(ftmp[13]), \ + [ftmp14]"=&f"(ftmp[14]), \ + [dst]"+&r"(dst), [tmp]"+&r"(tmp), [y]"+&r"(y), [x]"=&r"(x), \ + [offset]"+&f"(offset), [rtmp0]"=&r"(rtmp[0]) \ + : [filter]"r"(filter), [stride]"r"(dststride), \ + [shift]"f"(shift) \ + : "memory" \ + ); \ +} + +PUT_HEVC_QPEL_UNI_HV(4, 1, -4, -4, -8); +PUT_HEVC_QPEL_UNI_HV(8, 2, -8, -8, -16); +PUT_HEVC_QPEL_UNI_HV(12, 3, -12, -12, -24); +PUT_HEVC_QPEL_UNI_HV(16, 4, -16, -16, -32); +PUT_HEVC_QPEL_UNI_HV(24, 6, -24, -24, -48); +PUT_HEVC_QPEL_UNI_HV(32, 8, -32, -32, -64); +PUT_HEVC_QPEL_UNI_HV(48, 12, -48, -48, -96); +PUT_HEVC_QPEL_UNI_HV(64, 16, -64, -64, -128); diff --git a/libavcodec/mips/hevcdsp_msa.c b/libavcodec/mips/hevcdsp_msa.c index 81db62b87..2c57ec857 100644 --- a/libavcodec/mips/hevcdsp_msa.c +++ b/libavcodec/mips/hevcdsp_msa.c @@ -44,7 +44,7 @@ static void hevc_copy_4w_msa(uint8_t *src, int32_t src_stride, src0 = (v16i8) __msa_ilvr_w((v4i32) src1, (v4i32) src0); in0 = (v8i16) __msa_ilvr_b(zero, src0); in0 <<= 6; - ST8x2_UB(in0, dst, 2 * dst_stride); + ST_D2(in0, 0, 1, dst, dst_stride); } else if (4 == height) { v16i8 src0, src1, src2, src3; v8i16 in0, in1; @@ -55,7 +55,7 @@ static void hevc_copy_4w_msa(uint8_t *src, int32_t src_stride, ILVR_B2_SH(zero, src0, zero, src1, in0, in1); in0 <<= 6; in1 <<= 6; - ST8x4_UB(in0, in1, dst, 2 * dst_stride); + ST_D4(in0, in1, 0, 1, 0, 1, dst, dst_stride); } else if (0 == height % 8) { v16i8 src0, src1, src2, src3, src4, src5, src6, src7; v8i16 in0, in1, in2, in3; @@ -71,7 +71,7 @@ static void hevc_copy_4w_msa(uint8_t *src, int32_t src_stride, ILVR_B4_SH(zero, src0, zero, src1, zero, src2, zero, src3, in0, in1, in2, in3); SLLI_4V(in0, in1, in2, in3, 6); - ST8x8_UB(in0, in1, in2, in3, dst, 2 * dst_stride); + ST_D8(in0, in1, in2, in3, 0, 1, 0, 1, 0, 1, 0, 1, dst, dst_stride); dst += (8 * dst_stride); } } @@ -183,7 +183,7 @@ static void hevc_copy_12w_msa(uint8_t *src, int32_t src_stride, in0 <<= 6; in1 <<= 6; ST_SH4(in0_r, in1_r, in2_r, in3_r, dst, dst_stride); - ST8x4_UB(in0, in1, dst + 8, 2 * dst_stride); + ST_D4(in0, in1, 0, 1, 0, 1, dst + 8, dst_stride); dst += (4 * dst_stride); ILVR_B4_SH(zero, src4, zero, src5, zero, src6, zero, src7, @@ -194,7 +194,7 @@ static void hevc_copy_12w_msa(uint8_t *src, int32_t src_stride, in0 <<= 6; in1 <<= 6; ST_SH4(in0_r, in1_r, in2_r, in3_r, dst, dst_stride); - ST8x4_UB(in0, in1, dst + 8, 2 * dst_stride); + ST_D4(in0, in1, 0, 1, 0, 1, dst + 8, dst_stride); dst += (4 * dst_stride); } } @@ -495,7 +495,7 @@ static void hevc_hz_8t_4w_msa(uint8_t *src, int32_t src_stride, DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, dst3, dst3, dst3, dst3); - ST8x8_UB(dst0, dst1, dst2, dst3, dst, 2 * dst_stride); + ST_D8(dst0, dst1, dst2, dst3, 0, 1, 0, 1, 0, 1, 0, 1, dst, dst_stride); dst += (8 * dst_stride); } } @@ -1047,7 +1047,7 @@ static void hevc_vt_8t_4w_msa(uint8_t *src, int32_t src_stride, DPADD_SB4_SH(src8776, src10998, src12111110, src14131312, filt0, filt1, filt2, filt3, dst76, dst76, dst76, dst76); - ST8x8_UB(dst10, dst32, dst54, dst76, dst, 2 * dst_stride); + ST_D8(dst10, dst32, dst54, dst76, 0, 1, 0, 1, 0, 1, 0, 1, dst, dst_stride); dst += (8 * dst_stride); src2110 = src10998; @@ -1191,7 +1191,7 @@ static void hevc_vt_8t_12w_msa(uint8_t *src, int32_t src_stride, dst1_l, dst1_l, dst1_l, dst1_l); ST_SH4(dst0_r, dst1_r, dst2_r, dst3_r, dst, dst_stride); - ST8x4_UB(dst0_l, dst1_l, dst + 8, 2 * dst_stride); + ST_D4(dst0_l, dst1_l, 0, 1, 0, 1, dst + 8, dst_stride); dst += (4 * dst_stride); src10_r = src54_r; @@ -1363,7 +1363,6 @@ static void hevc_hv_8t_4w_msa(uint8_t *src, int32_t src_stride, int32_t height) { uint32_t loop_cnt; - int32_t dst_stride_in_bytes = 2 * dst_stride; v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, src9, src10; v8i16 filt0, filt1, filt2, filt3; v8i16 filt_h0, filt_h1, filt_h2, filt_h3; @@ -1452,7 +1451,7 @@ static void hevc_hv_8t_4w_msa(uint8_t *src, int32_t src_stride, filt_h0, filt_h1, filt_h2, filt_h3); SRA_4V(dst0_r, dst1_r, dst2_r, dst3_r, 6); PCKEV_H2_SW(dst1_r, dst0_r, dst3_r, dst2_r, dst0_r, dst2_r); - ST8x4_UB(dst0_r, dst2_r, dst, dst_stride_in_bytes); + ST_D4(dst0_r, dst2_r, 0, 1, 0, 1, dst, dst_stride); dst += (4 * dst_stride); dst10_r = dst54_r; @@ -1607,7 +1606,6 @@ static void hevc_hv_8t_12w_msa(uint8_t *src, int32_t src_stride, int32_t height) { uint32_t loop_cnt; - int32_t dst_stride_in_bytes = 2 * dst_stride; uint8_t *src_tmp; int16_t *dst_tmp; v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, src9, src10; @@ -1784,7 +1782,7 @@ static void hevc_hv_8t_12w_msa(uint8_t *src, int32_t src_stride, filt_h1, filt_h2, filt_h3); SRA_4V(dst0_r, dst1_r, dst2_r, dst3_r, 6); PCKEV_H2_SW(dst1_r, dst0_r, dst3_r, dst2_r, dst0_r, dst2_r); - ST8x4_UB(dst0_r, dst2_r, dst, dst_stride_in_bytes); + ST_D4(dst0_r, dst2_r, 0, 1, 0, 1, dst, dst_stride); dst += (4 * dst_stride); dst10_r = dst54_r; @@ -1872,7 +1870,7 @@ static void hevc_hz_4t_4x2_msa(uint8_t *src, dst0 = const_vec; DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); - ST8x2_UB(dst0, dst, 2 * dst_stride); + ST_D2(dst0, 0, 1, dst, dst_stride); } static void hevc_hz_4t_4x4_msa(uint8_t *src, @@ -1909,7 +1907,7 @@ static void hevc_hz_4t_4x4_msa(uint8_t *src, dst1 = const_vec; DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst1, dst1); - ST8x4_UB(dst0, dst1, dst, 2 * dst_stride); + ST_D4(dst0, dst1, 0, 1, 0, 1, dst, dst_stride); } static void hevc_hz_4t_4x8multiple_msa(uint8_t *src, @@ -1956,7 +1954,7 @@ static void hevc_hz_4t_4x8multiple_msa(uint8_t *src, dst3 = const_vec; DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); - ST8x8_UB(dst0, dst1, dst2, dst3, dst, 2 * dst_stride); + ST_D8(dst0, dst1, dst2, dst3, 0, 1, 0, 1, 0, 1, 0, 1, dst, dst_stride); dst += (8 * dst_stride); } } @@ -2218,7 +2216,7 @@ static void hevc_hz_4t_12w_msa(uint8_t *src, DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst5, dst5); ST_SH4(dst0, dst1, dst2, dst3, dst, dst_stride); - ST8x4_UB(dst4, dst5, dst + 8, 2 * dst_stride); + ST_D4(dst4, dst5, 0, 1, 0, 1, dst + 8, dst_stride); dst += (4 * dst_stride); } } @@ -2478,7 +2476,7 @@ static void hevc_vt_4t_4x2_msa(uint8_t *src, dst10 = const_vec; DPADD_SB2_SH(src2110, src4332, filt0, filt1, dst10, dst10); - ST8x2_UB(dst10, dst, 2 * dst_stride); + ST_D2(dst10, 0, 1, dst, dst_stride); } static void hevc_vt_4t_4x4_msa(uint8_t *src, @@ -2515,7 +2513,7 @@ static void hevc_vt_4t_4x4_msa(uint8_t *src, dst32 = const_vec; DPADD_SB2_SH(src4332, src6554, filt0, filt1, dst32, dst32); - ST8x4_UB(dst10, dst32, dst, 2 * dst_stride); + ST_D4(dst10, dst32, 0, 1, 0, 1, dst, dst_stride); } static void hevc_vt_4t_4x8_msa(uint8_t *src, @@ -2564,8 +2562,7 @@ static void hevc_vt_4t_4x8_msa(uint8_t *src, DPADD_SB2_SH(src4332, src6554, filt0, filt1, dst32, dst32); DPADD_SB2_SH(src6554, src8776, filt0, filt1, dst54, dst54); DPADD_SB2_SH(src8776, src10998, filt0, filt1, dst76, dst76); - ST8x8_UB(dst10, dst32, dst54, dst76, dst, 2 * dst_stride); - dst += (8 * dst_stride); + ST_D8(dst10, dst32, dst54, dst76, 0, 1, 0, 1, 0, 1, 0, 1, dst, dst_stride); } static void hevc_vt_4t_4x16_msa(uint8_t *src, int32_t src_stride, @@ -2610,7 +2607,7 @@ static void hevc_vt_4t_4x16_msa(uint8_t *src, int32_t src_stride, DPADD_SB2_SH(src4332, src6554, filt0, filt1, dst32, dst32); DPADD_SB2_SH(src6554, src8776, filt0, filt1, dst54, dst54); DPADD_SB2_SH(src8776, src10998, filt0, filt1, dst76, dst76); - ST8x8_UB(dst10, dst32, dst54, dst76, dst, 2 * dst_stride); + ST_D8(dst10, dst32, dst54, dst76, 0, 1, 0, 1, 0, 1, 0, 1, dst, dst_stride); dst += (8 * dst_stride); src2 = src10; @@ -2635,8 +2632,7 @@ static void hevc_vt_4t_4x16_msa(uint8_t *src, int32_t src_stride, DPADD_SB2_SH(src4332, src6554, filt0, filt1, dst32, dst32); DPADD_SB2_SH(src6554, src8776, filt0, filt1, dst54, dst54); DPADD_SB2_SH(src8776, src10998, filt0, filt1, dst76, dst76); - ST8x8_UB(dst10, dst32, dst54, dst76, dst, 2 * dst_stride); - dst += (8 * dst_stride); + ST_D8(dst10, dst32, dst54, dst76, 0, 1, 0, 1, 0, 1, 0, 1, dst, dst_stride); } static void hevc_vt_4t_4w_msa(uint8_t *src, @@ -2955,7 +2951,7 @@ static void hevc_vt_4t_12w_msa(uint8_t *src, DPADD_SB2_SH(src4332, src6554, filt0, filt1, dst1_l, dst1_l); ST_SH4(dst0_r, dst1_r, dst2_r, dst3_r, dst, dst_stride); - ST8x4_UB(dst0_l, dst1_l, dst + 8, (2 * dst_stride)); + ST_D4(dst0_l, dst1_l, 0, 1, 0, 1, dst + 8, dst_stride); dst += (4 * dst_stride); src2 = src6; @@ -3243,7 +3239,6 @@ static void hevc_hv_4t_4x2_msa(uint8_t *src, const int8_t *filter_x, const int8_t *filter_y) { - int32_t dst_stride_in_bytes = 2 * dst_stride; v16i8 src0, src1, src2, src3, src4; v8i16 filt0, filt1; v8i16 filt_h0, filt_h1; @@ -3288,7 +3283,7 @@ static void hevc_hv_4t_4x2_msa(uint8_t *src, dst0 >>= 6; dst1 >>= 6; dst0 = (v4i32) __msa_pckev_h((v8i16) dst1, (v8i16) dst0); - ST8x2_UB(dst0, dst, dst_stride_in_bytes); + ST_D2(dst0, 0, 1, dst, dst_stride); } static void hevc_hv_4t_4x4_msa(uint8_t *src, @@ -3298,7 +3293,6 @@ static void hevc_hv_4t_4x4_msa(uint8_t *src, const int8_t *filter_x, const int8_t *filter_y) { - int32_t dst_stride_in_bytes = 2 * dst_stride; v16i8 src0, src1, src2, src3, src4, src5, src6; v8i16 filt0, filt1; v8i16 filt_h0, filt_h1; @@ -3351,7 +3345,7 @@ static void hevc_hv_4t_4x4_msa(uint8_t *src, dst3 = HEVC_FILT_4TAP(dst43, dst65, filt_h0, filt_h1); SRA_4V(dst0, dst1, dst2, dst3, 6); PCKEV_H2_SW(dst1, dst0, dst3, dst2, dst0, dst2); - ST8x4_UB(dst0, dst2, dst, dst_stride_in_bytes); + ST_D4(dst0, dst2, 0, 1, 0, 1, dst, dst_stride); } @@ -3442,7 +3436,7 @@ static void hevc_hv_4t_4multx8mult_msa(uint8_t *src, SRA_4V(dst4, dst5, dst6, dst7, 6); PCKEV_H4_SW(dst1, dst0, dst3, dst2, dst5, dst4, dst7, dst6, dst0, dst1, dst2, dst3); - ST8x8_UB(dst0, dst1, dst2, dst3, dst, 2 * dst_stride); + ST_D8(dst0, dst1, dst2, dst3, 0, 1, 0, 1, 0, 1, 0, 1, dst, dst_stride); dst += (8 * dst_stride); dst10_r = dst98_r; @@ -3479,7 +3473,6 @@ static void hevc_hv_4t_6w_msa(uint8_t *src, const int8_t *filter_y, int32_t height) { - int32_t dst_stride_in_bytes = 2 * dst_stride; v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, src9, src10; v8i16 filt0, filt1; v8i16 filt_h0, filt_h1; @@ -3590,11 +3583,11 @@ static void hevc_hv_4t_6w_msa(uint8_t *src, PCKEV_H2_SH(dst1_r, dst0_r, dst3_r, dst2_r, tmp0, tmp1); PCKEV_H2_SH(dst5_r, dst4_r, dst7_r, dst6_r, tmp2, tmp3); PCKEV_H2_SH(dst1_l, dst0_l, dst3_l, dst2_l, tmp4, tmp5); - ST8x4_UB(tmp0, tmp1, dst, dst_stride_in_bytes); - ST4x4_UB(tmp4, tmp4, 0, 1, 2, 3, dst + 4, dst_stride_in_bytes); + ST_D4(tmp0, tmp1, 0, 1, 0, 1, dst, dst_stride); + ST_W4(tmp4, 0, 1, 2, 3, dst + 4, dst_stride); dst += 4 * dst_stride; - ST8x4_UB(tmp2, tmp3, dst, dst_stride_in_bytes); - ST4x4_UB(tmp5, tmp5, 0, 1, 2, 3, dst + 4, dst_stride_in_bytes); + ST_D4(tmp2, tmp3, 0, 1, 0, 1, dst, dst_stride); + ST_W4(tmp5, 0, 1, 2, 3, dst + 4, dst_stride); } static void hevc_hv_4t_8x2_msa(uint8_t *src, @@ -4164,7 +4157,7 @@ static void hevc_hv_4t_12w_msa(uint8_t *src, SRA_4V(tmp4, tmp5, tmp6, tmp7, 6); PCKEV_H4_SW(tmp1, tmp0, tmp3, tmp2, tmp5, tmp4, tmp7, tmp6, tmp0, tmp1, tmp2, tmp3); - ST8x8_UB(tmp0, tmp1, tmp2, tmp3, dst, 2 * dst_stride); + ST_D8(tmp0, tmp1, tmp2, tmp3, 0, 1, 0, 1, 0, 1, 0, 1, dst, dst_stride); dst += (8 * dst_stride); dst10_r = dst98_r; diff --git a/libavcodec/mips/hevcpred_msa.c b/libavcodec/mips/hevcpred_msa.c index 963c64c86..b8df089e0 100644 --- a/libavcodec/mips/hevcpred_msa.c +++ b/libavcodec/mips/hevcpred_msa.c @@ -589,7 +589,7 @@ static void hevc_intra_pred_plane_4x4_msa(const uint8_t *src_top, PCKEV_D2_SH(res1, res0, res3, res2, res0, res1); SRARI_H2_SH(res0, res1, 3); src_vec0 = __msa_pckev_b((v16i8) res1, (v16i8) res0); - ST4x4_UB(src_vec0, src_vec0, 0, 1, 2, 3, dst, stride); + ST_W4(src_vec0, 0, 1, 2, 3, dst, stride); } static void hevc_intra_pred_plane_8x8_msa(const uint8_t *src_top, @@ -656,7 +656,8 @@ static void hevc_intra_pred_plane_8x8_msa(const uint8_t *src_top, PCKEV_B4_SB(res1, res0, res3, res2, res5, res4, res7, res6, src_vec0, src_vec1, src_vec2, src_vec3); - ST8x8_UB(src_vec0, src_vec1, src_vec2, src_vec3, dst, stride); + ST_D8(src_vec0, src_vec1, src_vec2, src_vec3, 0, 1, 0, 1, + 0, 1, 0, 1, dst, stride); } static void hevc_intra_pred_plane_16x16_msa(const uint8_t *src_top, @@ -1007,7 +1008,7 @@ static void hevc_intra_pred_angular_upper_4width_msa(const uint8_t *src_top, SRARI_H2_SH(diff1, diff3, 5); dst_val0 = __msa_pckev_b((v16i8) diff3, (v16i8) diff1); - ST4x4_UB(dst_val0, dst_val0, 0, 1, 2, 3, dst, stride); + ST_W4(dst_val0, 0, 1, 2, 3, dst, stride); } static void hevc_intra_pred_angular_upper_8width_msa(const uint8_t *src_top, @@ -1104,7 +1105,7 @@ static void hevc_intra_pred_angular_upper_8width_msa(const uint8_t *src_top, SRARI_H4_SH(diff1, diff3, diff5, diff7, 5); PCKEV_B2_UB(diff3, diff1, diff7, diff5, dst_val0, dst_val1); - ST8x4_UB(dst_val0, dst_val1, dst, stride); + ST_D4(dst_val0, dst_val1, 0, 1, 0, 1, dst, stride); dst += (4 * stride); } } @@ -1425,9 +1426,8 @@ static void hevc_intra_pred_angular_lower_4width_msa(const uint8_t *src_top, dst_val0 = __msa_pckev_b((v16i8) diff2, (v16i8) diff2); dst_val1 = __msa_pckod_b((v16i8) diff2, (v16i8) diff2); - ST4x2_UB(dst_val0, dst, stride); - dst += (2 * stride); - ST4x2_UB(dst_val1, dst, stride); + ST_W2(dst_val0, 0, 1, dst, stride); + ST_W2(dst_val1, 0, 1, dst + 2 * stride, stride); } static void hevc_intra_pred_angular_lower_8width_msa(const uint8_t *src_top, @@ -1526,7 +1526,7 @@ static void hevc_intra_pred_angular_lower_8width_msa(const uint8_t *src_top, dst_val0, dst_val1, dst_val2, dst_val3); ILVR_B2_SH(dst_val1, dst_val0, dst_val3, dst_val2, diff0, diff1); ILVRL_H2_SH(diff1, diff0, diff3, diff4); - ST4x8_UB(diff3, diff4, dst_org, stride); + ST_W8(diff3, diff4, 0, 1, 2, 3, 0, 1, 2, 3, dst_org, stride); dst += 4; } } @@ -1640,9 +1640,9 @@ static void hevc_intra_pred_angular_lower_16width_msa(const uint8_t *src_top, ILVL_B2_SH(dst_val1, dst_val0, dst_val3, dst_val2, diff2, diff3); ILVRL_H2_SH(diff1, diff0, diff4, diff5); ILVRL_H2_SH(diff3, diff2, diff6, diff7); - ST4x8_UB(diff4, diff5, dst_org, stride); + ST_W8(diff4, diff5, 0, 1, 2, 3, 0, 1, 2, 3, dst_org, stride); dst_org += (8 * stride); - ST4x8_UB(diff6, diff7, dst_org, stride); + ST_W8(diff6, diff7, 0, 1, 2, 3, 0, 1, 2, 3, dst_org, stride); dst += 4; } } @@ -1746,23 +1746,14 @@ static void hevc_intra_pred_angular_lower_32width_msa(const uint8_t *src_top, ILVRL_B2_SH(dst_val2, dst_val0, diff0, diff1); ILVRL_B2_SH(dst_val3, dst_val1, diff2, diff3); - ST2x4_UB(diff0, 0, dst_org, stride); - dst_org += (4 * stride); - ST2x4_UB(diff0, 4, dst_org, stride); - dst_org += (4 * stride); - ST2x4_UB(diff1, 0, dst_org, stride); - dst_org += (4 * stride); - ST2x4_UB(diff1, 4, dst_org, stride); - dst_org += (4 * stride); - - ST2x4_UB(diff2, 0, dst_org, stride); - dst_org += (4 * stride); - ST2x4_UB(diff2, 4, dst_org, stride); - dst_org += (4 * stride); - ST2x4_UB(diff3, 0, dst_org, stride); - dst_org += (4 * stride); - ST2x4_UB(diff3, 4, dst_org, stride); - dst_org += (4 * stride); + ST_H8(diff0, 0, 1, 2, 3, 4, 5, 6, 7, dst_org, stride) + dst_org += (8 * stride); + ST_H8(diff1, 0, 1, 2, 3, 4, 5, 6, 7, dst_org, stride) + dst_org += (8 * stride); + ST_H8(diff2, 0, 1, 2, 3, 4, 5, 6, 7, dst_org, stride) + dst_org += (8 * stride); + ST_H8(diff3, 0, 1, 2, 3, 4, 5, 6, 7, dst_org, stride) + dst_org += (8 * stride); dst += 2; } diff --git a/libavcodec/mips/hpeldsp_init_mips.c b/libavcodec/mips/hpeldsp_init_mips.c index 363a04514..d6f7a9793 100644 --- a/libavcodec/mips/hpeldsp_init_mips.c +++ b/libavcodec/mips/hpeldsp_init_mips.c @@ -113,10 +113,10 @@ static void ff_hpeldsp_init_mmi(HpelDSPContext *c, int flags) void ff_hpeldsp_init_mips(HpelDSPContext *c, int flags) { -#if HAVE_MSA - ff_hpeldsp_init_msa(c, flags); -#endif // #if HAVE_MSA #if HAVE_MMI ff_hpeldsp_init_mmi(c, flags); #endif // #if HAVE_MMI +#if HAVE_MSA + ff_hpeldsp_init_msa(c, flags); +#endif // #if HAVE_MSA } diff --git a/libavcodec/mips/hpeldsp_mmi.c b/libavcodec/mips/hpeldsp_mmi.c index 2dbef22cc..e69b2bd98 100644 --- a/libavcodec/mips/hpeldsp_mmi.c +++ b/libavcodec/mips/hpeldsp_mmi.c @@ -29,36 +29,27 @@ void ff_put_pixels4_8_mmi(uint8_t *block, const uint8_t *pixels, ptrdiff_t line_size, int h) { - double ftmp[2]; - mips_reg addr[2]; + double ftmp[4]; DECLARE_VAR_LOW32; - DECLARE_VAR_ADDRT; __asm__ volatile ( - PTR_ADDU "%[addr1], %[line_size], %[line_size] \n\t" "1: \n\t" - PTR_ADDU "%[addr0], %[pixels], %[line_size] \n\t" MMI_ULWC1(%[ftmp0], %[pixels], 0x00) - MMI_ULWC1(%[ftmp1], %[addr0], 0x00) - MMI_SWC1(%[ftmp0], %[block], 0x00) - MMI_SWXC1(%[ftmp1], %[block], %[line_size], 0x00) - PTR_ADDU "%[pixels], %[pixels], %[addr1] \n\t" - PTR_ADDU "%[block], %[block], %[addr1] \n\t" + PTR_ADDU "%[pixels], %[pixels], %[line_size] \n\t" + MMI_ULWC1(%[ftmp1], %[pixels], 0x00) + PTR_ADDU "%[pixels], %[pixels], %[line_size] \n\t" - PTR_ADDU "%[addr0], %[pixels], %[line_size] \n\t" - MMI_ULWC1(%[ftmp0], %[pixels], 0x00) - MMI_ULWC1(%[ftmp1], %[addr0], 0x00) + PTR_ADDI "%[h], %[h], -0x02 \n\t" + MMI_SWC1(%[ftmp0], %[block], 0x00) - MMI_SWXC1(%[ftmp1], %[block], %[line_size], 0x00) - PTR_ADDU "%[pixels], %[pixels], %[addr1] \n\t" - PTR_ADDU "%[block], %[block], %[addr1] \n\t" + PTR_ADDU "%[block], %[block], %[line_size] \n\t" + MMI_SWC1(%[ftmp1], %[block], 0x00) + PTR_ADDU "%[block], %[block], %[line_size] \n\t" - PTR_ADDI "%[h], %[h], -0x04 \n\t" "bnez %[h], 1b \n\t" : [ftmp0]"=&f"(ftmp[0]), [ftmp1]"=&f"(ftmp[1]), + [ftmp2]"=&f"(ftmp[2]), [ftmp3]"=&f"(ftmp[3]), RESTRICT_ASM_LOW32 - RESTRICT_ASM_ADDRT - [addr0]"=&r"(addr[0]), [addr1]"=&r"(addr[1]), [block]"+&r"(block), [pixels]"+&r"(pixels), [h]"+&r"(h) : [line_size]"r"((mips_reg)line_size) @@ -69,37 +60,35 @@ void ff_put_pixels4_8_mmi(uint8_t *block, const uint8_t *pixels, void ff_put_pixels8_8_mmi(uint8_t *block, const uint8_t *pixels, ptrdiff_t line_size, int h) { - double ftmp[2]; - mips_reg addr[3]; + double ftmp[4]; DECLARE_VAR_ALL64; __asm__ volatile ( - PTR_ADDU "%[addr1], %[line_size], %[line_size] \n\t" "1: \n\t" MMI_ULDC1(%[ftmp0], %[pixels], 0x00) - PTR_ADDU "%[addr0], %[pixels], %[line_size] \n\t" - MMI_ULDC1(%[ftmp1], %[addr0], 0x00) - MMI_SDC1(%[ftmp0], %[block], 0x00) - PTR_ADDU "%[addr2], %[block], %[line_size] \n\t" - MMI_SDC1(%[ftmp1], %[addr2], 0x00) - PTR_ADDU "%[pixels], %[pixels], %[addr1] \n\t" - PTR_ADDU "%[block], %[block], %[addr1] \n\t" - - MMI_ULDC1(%[ftmp0], %[pixels], 0x00) - PTR_ADDU "%[addr0], %[pixels], %[line_size] \n\t" - MMI_ULDC1(%[ftmp1], %[addr0], 0x00) - MMI_SDC1(%[ftmp0], %[block], 0x00) - PTR_ADDU "%[addr2], %[block], %[line_size] \n\t" - MMI_SDC1(%[ftmp1], %[addr2], 0x00) - PTR_ADDU "%[pixels], %[pixels], %[addr1] \n\t" - PTR_ADDU "%[block], %[block], %[addr1] \n\t" + PTR_ADDU "%[pixels], %[pixels], %[line_size] \n\t" + MMI_ULDC1(%[ftmp1], %[pixels], 0x00) + PTR_ADDU "%[pixels], %[pixels], %[line_size] \n\t" + MMI_ULDC1(%[ftmp2], %[pixels], 0x00) + PTR_ADDU "%[pixels], %[pixels], %[line_size] \n\t" + MMI_ULDC1(%[ftmp3], %[pixels], 0x00) + PTR_ADDU "%[pixels], %[pixels], %[line_size] \n\t" PTR_ADDI "%[h], %[h], -0x04 \n\t" + + MMI_SDC1(%[ftmp0], %[block], 0x00) + PTR_ADDU "%[block], %[block], %[line_size] \n\t" + MMI_SDC1(%[ftmp1], %[block], 0x00) + PTR_ADDU "%[block], %[block], %[line_size] \n\t" + MMI_SDC1(%[ftmp2], %[block], 0x00) + PTR_ADDU "%[block], %[block], %[line_size] \n\t" + MMI_SDC1(%[ftmp3], %[block], 0x00) + PTR_ADDU "%[block], %[block], %[line_size] \n\t" + "bnez %[h], 1b \n\t" : [ftmp0]"=&f"(ftmp[0]), [ftmp1]"=&f"(ftmp[1]), + [ftmp2]"=&f"(ftmp[2]), [ftmp3]"=&f"(ftmp[3]), RESTRICT_ASM_ALL64 - [addr0]"=&r"(addr[0]), [addr1]"=&r"(addr[1]), - [addr2]"=&r"(addr[2]), [block]"+&r"(block), [pixels]"+&r"(pixels), [h]"+&r"(h) : [line_size]"r"((mips_reg)line_size) @@ -110,45 +99,45 @@ void ff_put_pixels8_8_mmi(uint8_t *block, const uint8_t *pixels, void ff_put_pixels16_8_mmi(uint8_t *block, const uint8_t *pixels, ptrdiff_t line_size, int h) { - double ftmp[4]; - mips_reg addr[2]; + double ftmp[8]; DECLARE_VAR_ALL64; - DECLARE_VAR_ADDRT; __asm__ volatile ( - PTR_ADDU "%[addr1], %[line_size], %[line_size] \n\t" - "1: \n\t" - PTR_ADDU "%[addr0], %[pixels], %[line_size] \n\t" + "1: \n\t" MMI_ULDC1(%[ftmp0], %[pixels], 0x00) MMI_ULDC1(%[ftmp2], %[pixels], 0x08) - MMI_ULDC1(%[ftmp1], %[addr0], 0x00) - MMI_ULDC1(%[ftmp3], %[addr0], 0x08) - MMI_SDC1(%[ftmp0], %[block], 0x00) - MMI_SDXC1(%[ftmp1], %[block], %[line_size], 0x00) - MMI_SDC1(%[ftmp2], %[block], 0x08) - MMI_SDXC1(%[ftmp3], %[block], %[line_size], 0x08) - PTR_ADDU "%[pixels], %[pixels], %[addr1] \n\t" - PTR_ADDU "%[block], %[block], %[addr1] \n\t" + PTR_ADDU "%[pixels], %[pixels], %[line_size] \n\t" + MMI_ULDC1(%[ftmp1], %[pixels], 0x00) + MMI_ULDC1(%[ftmp3], %[pixels], 0x08) + PTR_ADDU "%[pixels], %[pixels], %[line_size] \n\t" + MMI_ULDC1(%[ftmp4], %[pixels], 0x00) + MMI_ULDC1(%[ftmp6], %[pixels], 0x08) + PTR_ADDU "%[pixels], %[pixels], %[line_size] \n\t" + MMI_ULDC1(%[ftmp5], %[pixels], 0x00) + MMI_ULDC1(%[ftmp7], %[pixels], 0x08) + PTR_ADDU "%[pixels], %[pixels], %[line_size] \n\t" - PTR_ADDU "%[addr0], %[pixels], %[line_size] \n\t" - MMI_ULDC1(%[ftmp0], %[pixels], 0x00) - MMI_ULDC1(%[ftmp2], %[pixels], 0x08) - MMI_ULDC1(%[ftmp1], %[addr0], 0x00) - MMI_ULDC1(%[ftmp3], %[addr0], 0x08) - MMI_SDC1(%[ftmp0], %[block], 0x00) - MMI_SDXC1(%[ftmp1], %[block], %[line_size], 0x00) - MMI_SDC1(%[ftmp2], %[block], 0x08) - MMI_SDXC1(%[ftmp3], %[block], %[line_size], 0x08) - PTR_ADDU "%[pixels], %[pixels], %[addr1] \n\t" - PTR_ADDU "%[block], %[block], %[addr1] \n\t" + PTR_ADDI "%[h], %[h], -0x04 \n\t" - PTR_ADDI "%[h], %[h], -0x04 \n\t" - "bnez %[h], 1b \n\t" + MMI_SDC1(%[ftmp0], %[block], 0x00) + MMI_SDC1(%[ftmp2], %[block], 0x08) + PTR_ADDU "%[block], %[block], %[line_size] \n\t" + MMI_SDC1(%[ftmp1], %[block], 0x00) + MMI_SDC1(%[ftmp3], %[block], 0x08) + PTR_ADDU "%[block], %[block], %[line_size] \n\t" + MMI_SDC1(%[ftmp4], %[block], 0x00) + MMI_SDC1(%[ftmp6], %[block], 0x08) + PTR_ADDU "%[block], %[block], %[line_size] \n\t" + MMI_SDC1(%[ftmp5], %[block], 0x00) + MMI_SDC1(%[ftmp7], %[block], 0x08) + PTR_ADDU "%[block], %[block], %[line_size] \n\t" + + "bnez %[h], 1b \n\t" : [ftmp0]"=&f"(ftmp[0]), [ftmp1]"=&f"(ftmp[1]), [ftmp2]"=&f"(ftmp[2]), [ftmp3]"=&f"(ftmp[3]), + [ftmp4]"=&f"(ftmp[4]), [ftmp5]"=&f"(ftmp[5]), + [ftmp6]"=&f"(ftmp[6]), [ftmp7]"=&f"(ftmp[7]), RESTRICT_ASM_ALL64 - RESTRICT_ASM_ADDRT - [addr0]"=&r"(addr[0]), [addr1]"=&r"(addr[1]), [block]"+&r"(block), [pixels]"+&r"(pixels), [h]"+&r"(h) : [line_size]"r"((mips_reg)line_size) @@ -160,12 +149,10 @@ void ff_avg_pixels4_8_mmi(uint8_t *block, const uint8_t *pixels, ptrdiff_t line_size, int h) { double ftmp[4]; - mips_reg addr[3]; + mips_reg addr[2]; DECLARE_VAR_LOW32; - DECLARE_VAR_ADDRT; __asm__ volatile ( - PTR_ADDU "%[addr2], %[line_size], %[line_size] \n\t" "1: \n\t" PTR_ADDU "%[addr0], %[pixels], %[line_size] \n\t" MMI_ULWC1(%[ftmp0], %[pixels], 0x00) @@ -173,34 +160,21 @@ void ff_avg_pixels4_8_mmi(uint8_t *block, const uint8_t *pixels, PTR_ADDU "%[addr1], %[block], %[line_size] \n\t" MMI_ULWC1(%[ftmp2], %[block], 0x00) MMI_ULWC1(%[ftmp3], %[addr1], 0x00) + + PTR_ADDI "%[h], %[h], -0x02 \n\t" + "pavgb %[ftmp0], %[ftmp0], %[ftmp2] \n\t" "pavgb %[ftmp1], %[ftmp1], %[ftmp3] \n\t" MMI_SWC1(%[ftmp0], %[block], 0x00) - MMI_SWXC1(%[ftmp1], %[block], %[line_size], 0x00) - PTR_ADDU "%[pixels], %[pixels], %[addr2] \n\t" - PTR_ADDU "%[block], %[block], %[addr2] \n\t" + MMI_SWC1(%[ftmp1], %[addr1], 0x00) + PTR_ADDU "%[pixels], %[addr0], %[line_size] \n\t" + PTR_ADDU "%[block], %[addr1], %[line_size] \n\t" - PTR_ADDU "%[addr0], %[pixels], %[line_size] \n\t" - MMI_ULWC1(%[ftmp0], %[pixels], 0x00) - MMI_ULWC1(%[ftmp1], %[addr0], 0x00) - PTR_ADDU "%[addr1], %[block], %[line_size] \n\t" - MMI_ULWC1(%[ftmp2], %[block], 0x00) - MMI_ULWC1(%[ftmp3], %[addr1], 0x00) - "pavgb %[ftmp0], %[ftmp0], %[ftmp2] \n\t" - "pavgb %[ftmp1], %[ftmp1], %[ftmp3] \n\t" - MMI_SWC1(%[ftmp0], %[block], 0x00) - MMI_SWXC1(%[ftmp1], %[block], %[line_size], 0x00) - PTR_ADDU "%[pixels], %[pixels], %[addr2] \n\t" - PTR_ADDU "%[block], %[block], %[addr2] \n\t" - - PTR_ADDI "%[h], %[h], -0x04 \n\t" "bnez %[h], 1b \n\t" : [ftmp0]"=&f"(ftmp[0]), [ftmp1]"=&f"(ftmp[1]), [ftmp2]"=&f"(ftmp[2]), [ftmp3]"=&f"(ftmp[3]), RESTRICT_ASM_LOW32 - RESTRICT_ASM_ADDRT [addr0]"=&r"(addr[0]), [addr1]"=&r"(addr[1]), - [addr2]"=&r"(addr[2]), [block]"+&r"(block), [pixels]"+&r"(pixels), [h]"+&r"(h) : [line_size]"r"((mips_reg)line_size) @@ -264,65 +238,61 @@ void ff_avg_pixels16_8_mmi(uint8_t *block, const uint8_t *pixels, ptrdiff_t line_size, int h) { double ftmp[8]; - mips_reg addr[3]; + mips_reg addr[1]; DECLARE_VAR_ALL64; - DECLARE_VAR_ADDRT; __asm__ volatile ( - PTR_ADDU "%[addr2], %[line_size], %[line_size] \n\t" "1: \n\t" - MMI_ULDC1(%[ftmp0], %[pixels], 0x00) - PTR_ADDU "%[addr0], %[pixels], %[line_size] \n\t" - MMI_ULDC1(%[ftmp4], %[pixels], 0x08) - PTR_ADDU "%[addr1], %[block], %[line_size] \n\t" - MMI_ULDC1(%[ftmp1], %[addr0], 0x00) - MMI_ULDC1(%[ftmp5], %[addr0], 0x08) - MMI_ULDC1(%[ftmp2], %[block], 0x00) - MMI_ULDC1(%[ftmp6], %[block], 0x08) - MMI_ULDC1(%[ftmp3], %[addr1], 0x00) - MMI_ULDC1(%[ftmp7], %[addr1], 0x08) - "pavgb %[ftmp0], %[ftmp0], %[ftmp2] \n\t" - "pavgb %[ftmp4], %[ftmp4], %[ftmp6] \n\t" - "pavgb %[ftmp1], %[ftmp1], %[ftmp3] \n\t" - "pavgb %[ftmp5], %[ftmp5], %[ftmp7] \n\t" - MMI_SDC1(%[ftmp0], %[block], 0x00) - MMI_SDXC1(%[ftmp1], %[block], %[line_size], 0x00) - MMI_SDC1(%[ftmp4], %[block], 0x08) - MMI_SDXC1(%[ftmp5], %[block], %[line_size], 0x08) - PTR_ADDU "%[pixels], %[pixels], %[addr2] \n\t" - PTR_ADDU "%[block], %[block], %[addr2] \n\t" - - MMI_ULDC1(%[ftmp0], %[pixels], 0x00) - PTR_ADDU "%[addr0], %[pixels], %[line_size] \n\t" - MMI_ULDC1(%[ftmp4], %[pixels], 0x08) - PTR_ADDU "%[addr1], %[block], %[line_size] \n\t" - MMI_ULDC1(%[ftmp1], %[addr0], 0x00) - MMI_ULDC1(%[ftmp5], %[addr0], 0x08) - MMI_ULDC1(%[ftmp2], %[block], 0x00) - MMI_ULDC1(%[ftmp6], %[block], 0x08) - MMI_ULDC1(%[ftmp3], %[addr1], 0x00) - MMI_ULDC1(%[ftmp7], %[addr1], 0x08) - "pavgb %[ftmp0], %[ftmp0], %[ftmp2] \n\t" - "pavgb %[ftmp4], %[ftmp4], %[ftmp6] \n\t" - "pavgb %[ftmp1], %[ftmp1], %[ftmp3] \n\t" - "pavgb %[ftmp5], %[ftmp5], %[ftmp7] \n\t" - MMI_SDC1(%[ftmp0], %[block], 0x00) - MMI_SDXC1(%[ftmp1], %[block], %[line_size], 0x00) - MMI_SDC1(%[ftmp4], %[block], 0x08) - MMI_SDXC1(%[ftmp5], %[block], %[line_size], 0x08) - PTR_ADDU "%[pixels], %[pixels], %[addr2] \n\t" - PTR_ADDU "%[block], %[block], %[addr2] \n\t" - PTR_ADDI "%[h], %[h], -0x04 \n\t" + MMI_ULDC1(%[ftmp0], %[pixels], 0x00) + MMI_ULDC1(%[ftmp4], %[pixels], 0x08) + PTR_ADDU "%[pixels], %[pixels], %[line_size] \n\t" + MMI_ULDC1(%[ftmp1], %[pixels], 0x00) + MMI_ULDC1(%[ftmp5], %[pixels], 0x08) + PTR_ADDU "%[pixels], %[pixels], %[line_size] \n\t" + MMI_ULDC1(%[ftmp2], %[block], 0x00) + MMI_ULDC1(%[ftmp6], %[block], 0x08) + PTR_ADDU "%[addr0], %[block], %[line_size] \n\t" + MMI_ULDC1(%[ftmp3], %[addr0], 0x00) + MMI_ULDC1(%[ftmp7], %[addr0], 0x08) + "pavgb %[ftmp0], %[ftmp0], %[ftmp2] \n\t" + "pavgb %[ftmp4], %[ftmp4], %[ftmp6] \n\t" + "pavgb %[ftmp1], %[ftmp1], %[ftmp3] \n\t" + "pavgb %[ftmp5], %[ftmp5], %[ftmp7] \n\t" + MMI_SDC1(%[ftmp0], %[block], 0x00) + MMI_SDC1(%[ftmp4], %[block], 0x08) + MMI_SDC1(%[ftmp1], %[addr0], 0x00) + MMI_SDC1(%[ftmp5], %[addr0], 0x08) + PTR_ADDU "%[block], %[addr0], %[line_size] \n\t" + + MMI_ULDC1(%[ftmp0], %[pixels], 0x00) + MMI_ULDC1(%[ftmp4], %[pixels], 0x08) + PTR_ADDU "%[pixels], %[pixels], %[line_size] \n\t" + MMI_ULDC1(%[ftmp1], %[pixels], 0x00) + MMI_ULDC1(%[ftmp5], %[pixels], 0x08) + PTR_ADDU "%[pixels], %[pixels], %[line_size] \n\t" + MMI_ULDC1(%[ftmp2], %[block], 0x00) + MMI_ULDC1(%[ftmp6], %[block], 0x08) + PTR_ADDU "%[addr0], %[block], %[line_size] \n\t" + MMI_ULDC1(%[ftmp3], %[addr0], 0x00) + MMI_ULDC1(%[ftmp7], %[addr0], 0x08) + "pavgb %[ftmp0], %[ftmp0], %[ftmp2] \n\t" + "pavgb %[ftmp4], %[ftmp4], %[ftmp6] \n\t" + "pavgb %[ftmp1], %[ftmp1], %[ftmp3] \n\t" + "pavgb %[ftmp5], %[ftmp5], %[ftmp7] \n\t" + MMI_SDC1(%[ftmp0], %[block], 0x00) + MMI_SDC1(%[ftmp4], %[block], 0x08) + MMI_SDC1(%[ftmp1], %[addr0], 0x00) + MMI_SDC1(%[ftmp5], %[addr0], 0x08) + PTR_ADDU "%[block], %[addr0], %[line_size] \n\t" + "bnez %[h], 1b \n\t" : [ftmp0]"=&f"(ftmp[0]), [ftmp1]"=&f"(ftmp[1]), [ftmp2]"=&f"(ftmp[2]), [ftmp3]"=&f"(ftmp[3]), [ftmp4]"=&f"(ftmp[4]), [ftmp5]"=&f"(ftmp[5]), [ftmp6]"=&f"(ftmp[6]), [ftmp7]"=&f"(ftmp[7]), RESTRICT_ASM_ALL64 - RESTRICT_ASM_ADDRT - [addr0]"=&r"(addr[0]), [addr1]"=&r"(addr[1]), - [addr2]"=&r"(addr[2]), + [addr0]"=&r"(addr[0]), [block]"+&r"(block), [pixels]"+&r"(pixels), [h]"+&r"(h) : [line_size]"r"((mips_reg)line_size) @@ -337,50 +307,33 @@ inline void ff_put_pixels4_l2_8_mmi(uint8_t *dst, const uint8_t *src1, double ftmp[4]; mips_reg addr[5]; DECLARE_VAR_LOW32; - DECLARE_VAR_ADDRT; __asm__ volatile ( - PTR_ADDU "%[addr2], %[src_stride1], %[src_stride1] \n\t" - PTR_ADDU "%[addr3], %[src_stride2], %[src_stride2] \n\t" - PTR_ADDU "%[addr4], %[dst_stride], %[dst_stride] \n\t" "1: \n\t" PTR_ADDU "%[addr0], %[src1], %[src_stride1] \n\t" MMI_ULWC1(%[ftmp0], %[src1], 0x00) MMI_ULWC1(%[ftmp1], %[addr0], 0x00) - MMI_ULWC1(%[ftmp2], %[src2], 0x00) PTR_ADDU "%[addr1], %[src2], %[src_stride2] \n\t" + MMI_ULWC1(%[ftmp2], %[src2], 0x00) MMI_ULWC1(%[ftmp3], %[addr1], 0x00) - PTR_ADDU "%[src1], %[src1], %[addr2] \n\t" + PTR_ADDU "%[src1], %[addr0], %[src_stride1] \n\t" + PTR_ADDU "%[src2], %[addr1], %[src_stride2] \n\t" + + PTR_ADDI "%[h], %[h], -0x02 \n\t" + "pavgb %[ftmp0], %[ftmp0], %[ftmp2] \n\t" "pavgb %[ftmp1], %[ftmp1], %[ftmp3] \n\t" MMI_SWC1(%[ftmp0], %[dst], 0x00) - MMI_SWXC1(%[ftmp1], %[dst], %[dst_stride], 0x00) - PTR_ADDU "%[src2], %[src2], %[addr3] \n\t" - PTR_ADDU "%[dst], %[dst], %[addr4] \n\t" + PTR_ADDU "%[dst], %[dst], %[dst_stride] \n\t" + MMI_SWC1(%[ftmp1], %[dst], 0x00) + PTR_ADDU "%[dst], %[dst], %[dst_stride] \n\t" - PTR_ADDU "%[addr0], %[src1], %[src_stride1] \n\t" - MMI_ULWC1(%[ftmp0], %[src1], 0x00) - MMI_ULWC1(%[ftmp1], %[addr0], 0x00) - MMI_ULWC1(%[ftmp2], %[src2], 0x00) - PTR_ADDU "%[addr1], %[src2], %[src_stride2] \n\t" - MMI_ULWC1(%[ftmp3], %[addr1], 0x00) - PTR_ADDU "%[src1], %[src1], %[addr2] \n\t" - "pavgb %[ftmp0], %[ftmp0], %[ftmp2] \n\t" - "pavgb %[ftmp1], %[ftmp1], %[ftmp3] \n\t" - MMI_SWC1(%[ftmp0], %[dst], 0x00) - MMI_SWXC1(%[ftmp1], %[dst], %[dst_stride], 0x00) - PTR_ADDU "%[src2], %[src2], %[addr3] \n\t" - PTR_ADDU "%[dst], %[dst], %[addr4] \n\t" - - PTR_ADDI "%[h], %[h], -0x04 \n\t" "bnez %[h], 1b \n\t" : [ftmp0]"=&f"(ftmp[0]), [ftmp1]"=&f"(ftmp[1]), [ftmp2]"=&f"(ftmp[2]), [ftmp3]"=&f"(ftmp[3]), RESTRICT_ASM_LOW32 RESTRICT_ASM_ADDRT [addr0]"=&r"(addr[0]), [addr1]"=&r"(addr[1]), - [addr2]"=&r"(addr[2]), [addr3]"=&r"(addr[3]), - [addr4]"=&r"(addr[4]), [dst]"+&r"(dst), [src1]"+&r"(src1), [src2]"+&r"(src2), [h]"+&r"(h) : [dst_stride]"r"((mips_reg)dst_stride), @@ -537,62 +490,36 @@ inline void ff_avg_pixels4_l2_8_mmi(uint8_t *dst, const uint8_t *src1, double ftmp[6]; mips_reg addr[6]; DECLARE_VAR_LOW32; - DECLARE_VAR_ADDRT; __asm__ volatile ( - PTR_ADDU "%[addr2], %[src_stride1], %[src_stride1] \n\t" - PTR_ADDU "%[addr3], %[src_stride2], %[src_stride2] \n\t" - PTR_ADDU "%[addr4], %[dst_stride], %[dst_stride] \n\t" - "1: \n\t" PTR_ADDU "%[addr0], %[src1], %[src_stride1] \n\t" MMI_ULWC1(%[ftmp0], %[src1], 0x00) MMI_ULWC1(%[ftmp1], %[addr0], 0x00) - MMI_ULWC1(%[ftmp2], %[src2], 0x00) PTR_ADDU "%[addr1], %[src2], %[src_stride2] \n\t" + MMI_ULWC1(%[ftmp2], %[src2], 0x00) MMI_ULWC1(%[ftmp3], %[addr1], 0x00) - PTR_ADDU "%[src1], %[src1], %[addr2] \n\t" + PTR_ADDU "%[src1], %[addr0], %[src_stride1] \n\t" + PTR_ADDU "%[src2], %[addr1], %[src_stride2] \n\t" "pavgb %[ftmp0], %[ftmp0], %[ftmp2] \n\t" "pavgb %[ftmp1], %[ftmp1], %[ftmp3] \n\t" - PTR_ADDU "%[addr5], %[dst], %[dst_stride] \n\t" + PTR_ADDU "%[addr2], %[dst], %[dst_stride] \n\t" MMI_ULWC1(%[ftmp4], %[dst], 0x00) - MMI_ULWC1(%[ftmp5], %[addr5], 0x00) + MMI_ULWC1(%[ftmp5], %[addr2], 0x00) + PTR_ADDI "%[h], %[h], -0x02 \n\t" "pavgb %[ftmp0], %[ftmp0], %[ftmp4] \n\t" "pavgb %[ftmp1], %[ftmp1], %[ftmp5] \n\t" MMI_SWC1(%[ftmp0], %[dst], 0x00) - MMI_SWXC1(%[ftmp1], %[dst], %[dst_stride], 0x00) - PTR_ADDU "%[src2], %[src2], %[addr3] \n\t" - PTR_ADDU "%[dst], %[dst], %[addr4] \n\t" + MMI_SWC1(%[ftmp1], %[addr2], 0x00) + PTR_ADDU "%[dst], %[addr2], %[dst_stride] \n\t" - PTR_ADDU "%[addr0], %[src1], %[src_stride1] \n\t" - MMI_ULWC1(%[ftmp0], %[src1], 0x00) - MMI_ULWC1(%[ftmp1], %[addr0], 0x00) - MMI_ULWC1(%[ftmp2], %[src2], 0x00) - PTR_ADDU "%[addr1], %[src2], %[src_stride2] \n\t" - MMI_ULWC1(%[ftmp3], %[addr1], 0x00) - PTR_ADDU "%[src1], %[src1], %[addr2] \n\t" - "pavgb %[ftmp0], %[ftmp0], %[ftmp2] \n\t" - "pavgb %[ftmp1], %[ftmp1], %[ftmp3] \n\t" - PTR_ADDU "%[addr5], %[dst], %[dst_stride] \n\t" - MMI_ULWC1(%[ftmp4], %[dst], 0x00) - MMI_ULWC1(%[ftmp5], %[addr5], 0x00) - "pavgb %[ftmp0], %[ftmp0], %[ftmp4] \n\t" - "pavgb %[ftmp1], %[ftmp1], %[ftmp5] \n\t" - MMI_SWC1(%[ftmp0], %[dst], 0x00) - MMI_SWXC1(%[ftmp1], %[dst], %[dst_stride], 0x00) - PTR_ADDU "%[src2], %[src2], %[addr3] \n\t" - PTR_ADDU "%[dst], %[dst], %[addr4] \n\t" - - PTR_ADDI "%[h], %[h], -0x04 \n\t" "bnez %[h], 1b \n\t" : [ftmp0]"=&f"(ftmp[0]), [ftmp1]"=&f"(ftmp[1]), [ftmp2]"=&f"(ftmp[2]), [ftmp3]"=&f"(ftmp[3]), [ftmp4]"=&f"(ftmp[4]), [ftmp5]"=&f"(ftmp[5]), RESTRICT_ASM_LOW32 - RESTRICT_ASM_ADDRT [addr0]"=&r"(addr[0]), [addr1]"=&r"(addr[1]), - [addr2]"=&r"(addr[2]), [addr3]"=&r"(addr[3]), - [addr4]"=&r"(addr[4]), [addr5]"=&r"(addr[5]), + [addr2]"=&r"(addr[2]), [dst]"+&r"(dst), [src1]"+&r"(src1), [src2]"+&r"(src2), [h]"+&r"(h) : [dst_stride]"r"((mips_reg)dst_stride), diff --git a/libavcodec/mips/hpeldsp_msa.c b/libavcodec/mips/hpeldsp_msa.c index 40a0dca0f..ad92f8f11 100644 --- a/libavcodec/mips/hpeldsp_msa.c +++ b/libavcodec/mips/hpeldsp_msa.c @@ -49,7 +49,7 @@ PCKEV_B2_UB(in2, in1, in4, in3, tmp0_m, tmp1_m); \ PCKEV_D2_UB(dst1, dst0, dst3, dst2, tmp2_m, tmp3_m); \ AVER_UB2_UB(tmp0_m, tmp2_m, tmp1_m, tmp3_m, tmp0_m, tmp1_m); \ - ST8x4_UB(tmp0_m, tmp1_m, pdst_m, stride); \ + ST_D4(tmp0_m, tmp1_m, 0, 1, 0, 1, pdst_m, stride); \ } static void common_hz_bil_4w_msa(const uint8_t *src, int32_t src_stride, @@ -584,7 +584,7 @@ static void common_hv_bil_8w_msa(const uint8_t *src, int32_t src_stride, sum0, sum1, sum2, sum3); SRARI_H4_UH(sum0, sum1, sum2, sum3, 2); PCKEV_B2_SB(sum1, sum0, sum3, sum2, src0, src1); - ST8x4_UB(src0, src1, dst, dst_stride); + ST_D4(src0, src1, 0, 1, 0, 1, dst, dst_stride); dst += (4 * dst_stride); src0 = src4; } @@ -689,9 +689,9 @@ static void common_hv_bil_no_rnd_8x8_msa(const uint8_t *src, int32_t src_stride, SRA_4V(sum0, sum1, sum2, sum3, 2); SRA_4V(sum4, sum5, sum6, sum7, 2); PCKEV_B2_SB(sum1, sum0, sum3, sum2, out0, out1); - ST8x4_UB(out0, out1, dst, dst_stride); + ST_D4(out0, out1, 0, 1, 0, 1, dst, dst_stride); PCKEV_B2_SB(sum5, sum4, sum7, sum6, out0, out1); - ST8x4_UB(out0, out1, dst + 4 * dst_stride, dst_stride); + ST_D4(out0, out1, 0, 1, 0, 1, dst + 4 * dst_stride, dst_stride); } static void common_hv_bil_no_rnd_4x8_msa(const uint8_t *src, int32_t src_stride, @@ -723,7 +723,7 @@ static void common_hv_bil_no_rnd_4x8_msa(const uint8_t *src, int32_t src_stride, SRA_4V(sum0, sum1, sum2, sum3, 2); PCKEV_B2_SB(sum1, sum0, sum3, sum2, out0, out1); - ST8x4_UB(out0, out1, dst, dst_stride); + ST_D4(out0, out1, 0, 1, 0, 1, dst, dst_stride); } static void common_hv_bil_no_rnd_16x16_msa(const uint8_t *src, diff --git a/libavcodec/mips/idctdsp_init_mips.c b/libavcodec/mips/idctdsp_init_mips.c index 8c26bca53..85b76ca47 100644 --- a/libavcodec/mips/idctdsp_init_mips.c +++ b/libavcodec/mips/idctdsp_init_mips.c @@ -20,6 +20,7 @@ */ #include "idctdsp_mips.h" +#include "xvididct_mips.h" #if HAVE_MSA static av_cold void idctdsp_init_msa(IDCTDSPContext *c, AVCodecContext *avctx, @@ -48,8 +49,10 @@ static av_cold void idctdsp_init_mmi(IDCTDSPContext *c, AVCodecContext *avctx, if ((avctx->lowres != 1) && (avctx->lowres != 2) && (avctx->lowres != 3) && (avctx->bits_per_raw_sample != 10) && (avctx->bits_per_raw_sample != 12) && - (avctx->idct_algo == FF_IDCT_AUTO)) { - c->idct = ff_simple_idct_mmi; + ((avctx->idct_algo == FF_IDCT_AUTO) || (avctx->idct_algo == FF_IDCT_SIMPLE))) { + c->idct_put = ff_simple_idct_put_8_mmi; + c->idct_add = ff_simple_idct_add_8_mmi; + c->idct = ff_simple_idct_8_mmi; c->perm_type = FF_IDCT_PERM_NONE; } @@ -62,10 +65,10 @@ static av_cold void idctdsp_init_mmi(IDCTDSPContext *c, AVCodecContext *avctx, av_cold void ff_idctdsp_init_mips(IDCTDSPContext *c, AVCodecContext *avctx, unsigned high_bit_depth) { -#if HAVE_MSA - idctdsp_init_msa(c, avctx, high_bit_depth); -#endif // #if HAVE_MSA #if HAVE_MMI idctdsp_init_mmi(c, avctx, high_bit_depth); #endif /* HAVE_MMI */ +#if HAVE_MSA + idctdsp_init_msa(c, avctx, high_bit_depth); +#endif // #if HAVE_MSA } diff --git a/libavcodec/mips/idctdsp_mips.h b/libavcodec/mips/idctdsp_mips.h index 7ca7c1c93..829efebff 100644 --- a/libavcodec/mips/idctdsp_mips.h +++ b/libavcodec/mips/idctdsp_mips.h @@ -46,8 +46,8 @@ void ff_put_signed_pixels_clamped_mmi(const int16_t *block, uint8_t *av_restrict pixels, ptrdiff_t line_size); void ff_add_pixels_clamped_mmi(const int16_t *block, uint8_t *av_restrict pixels, ptrdiff_t line_size); -void ff_simple_idct_mmi(int16_t *block); -void ff_simple_idct_put_mmi(uint8_t *dest, ptrdiff_t line_size, int16_t *block); -void ff_simple_idct_add_mmi(uint8_t *dest, ptrdiff_t line_size, int16_t *block); +void ff_simple_idct_8_mmi(int16_t *block); +void ff_simple_idct_put_8_mmi(uint8_t *dest, ptrdiff_t line_size, int16_t *block); +void ff_simple_idct_add_8_mmi(uint8_t *dest, ptrdiff_t line_size, int16_t *block); #endif // #ifndef AVCODEC_MIPS_IDCTDSP_MIPS_H diff --git a/libavcodec/mips/idctdsp_mmi.c b/libavcodec/mips/idctdsp_mmi.c index b7979650f..a96dac470 100644 --- a/libavcodec/mips/idctdsp_mmi.c +++ b/libavcodec/mips/idctdsp_mmi.c @@ -29,9 +29,6 @@ void ff_put_pixels_clamped_mmi(const int16_t *block, uint8_t *av_restrict pixels, ptrdiff_t line_size) { double ftmp[8]; - mips_reg addr[1]; - DECLARE_VAR_ALL64; - DECLARE_VAR_ADDRT; __asm__ volatile ( MMI_LDC1(%[ftmp0], %[block], 0x00) @@ -42,60 +39,44 @@ void ff_put_pixels_clamped_mmi(const int16_t *block, MMI_LDC1(%[ftmp5], %[block], 0x28) MMI_LDC1(%[ftmp6], %[block], 0x30) MMI_LDC1(%[ftmp7], %[block], 0x38) - PTR_ADDU "%[addr0], %[pixels], %[line_size] \n\t" "packushb %[ftmp0], %[ftmp0], %[ftmp1] \n\t" "packushb %[ftmp2], %[ftmp2], %[ftmp3] \n\t" "packushb %[ftmp4], %[ftmp4], %[ftmp5] \n\t" "packushb %[ftmp6], %[ftmp6], %[ftmp7] \n\t" MMI_SDC1(%[ftmp0], %[pixels], 0x00) - MMI_SDC1(%[ftmp2], %[addr0], 0x00) - MMI_SDXC1(%[ftmp4], %[addr0], %[line_size], 0x00) - MMI_SDXC1(%[ftmp6], %[pixels], %[line_sizex3], 0x00) - : [ftmp0]"=&f"(ftmp[0]), [ftmp1]"=&f"(ftmp[1]), - [ftmp2]"=&f"(ftmp[2]), [ftmp3]"=&f"(ftmp[3]), - [ftmp4]"=&f"(ftmp[4]), [ftmp5]"=&f"(ftmp[5]), - [ftmp6]"=&f"(ftmp[6]), [ftmp7]"=&f"(ftmp[7]), - RESTRICT_ASM_ALL64 - RESTRICT_ASM_ADDRT - [addr0]"=&r"(addr[0]), - [pixels]"+&r"(pixels) - : [line_size]"r"((mips_reg)line_size), - [line_sizex3]"r"((mips_reg)(line_size*3)), - [block]"r"(block) - : "memory" - ); + PTR_ADDU "%[pixels], %[pixels], %[line_size] \n\t" + MMI_SDC1(%[ftmp2], %[pixels], 0x00) + PTR_ADDU "%[pixels], %[pixels], %[line_size] \n\t" + MMI_SDC1(%[ftmp4], %[pixels], 0x00) + PTR_ADDU "%[pixels], %[pixels], %[line_size] \n\t" + MMI_SDC1(%[ftmp6], %[pixels], 0x00) + PTR_ADDU "%[pixels], %[pixels], %[line_size] \n\t" - pixels += line_size*4; - block += 32; - - __asm__ volatile ( - MMI_LDC1(%[ftmp0], %[block], 0x00) - MMI_LDC1(%[ftmp1], %[block], 0x08) - MMI_LDC1(%[ftmp2], %[block], 0x10) - MMI_LDC1(%[ftmp3], %[block], 0x18) - MMI_LDC1(%[ftmp4], %[block], 0x20) - MMI_LDC1(%[ftmp5], %[block], 0x28) - MMI_LDC1(%[ftmp6], %[block], 0x30) - MMI_LDC1(%[ftmp7], %[block], 0x38) - PTR_ADDU "%[addr0], %[pixels], %[line_size] \n\t" + MMI_LDC1(%[ftmp0], %[block], 0x40) + MMI_LDC1(%[ftmp1], %[block], 0x48) + MMI_LDC1(%[ftmp2], %[block], 0x50) + MMI_LDC1(%[ftmp3], %[block], 0x58) + MMI_LDC1(%[ftmp4], %[block], 0x60) + MMI_LDC1(%[ftmp5], %[block], 0x68) + MMI_LDC1(%[ftmp6], %[block], 0x70) + MMI_LDC1(%[ftmp7], %[block], 0x78) "packushb %[ftmp0], %[ftmp0], %[ftmp1] \n\t" "packushb %[ftmp2], %[ftmp2], %[ftmp3] \n\t" "packushb %[ftmp4], %[ftmp4], %[ftmp5] \n\t" "packushb %[ftmp6], %[ftmp6], %[ftmp7] \n\t" MMI_SDC1(%[ftmp0], %[pixels], 0x00) - MMI_SDC1(%[ftmp2], %[addr0], 0x00) - MMI_SDXC1(%[ftmp4], %[addr0], %[line_size], 0x00) - MMI_SDXC1(%[ftmp6], %[pixels], %[line_sizex3], 0x00) + PTR_ADDU "%[pixels], %[pixels], %[line_size] \n\t" + MMI_SDC1(%[ftmp2], %[pixels], 0x00) + PTR_ADDU "%[pixels], %[pixels], %[line_size] \n\t" + MMI_SDC1(%[ftmp4], %[pixels], 0x00) + PTR_ADDU "%[pixels], %[pixels], %[line_size] \n\t" + MMI_SDC1(%[ftmp6], %[pixels], 0x00) : [ftmp0]"=&f"(ftmp[0]), [ftmp1]"=&f"(ftmp[1]), [ftmp2]"=&f"(ftmp[2]), [ftmp3]"=&f"(ftmp[3]), [ftmp4]"=&f"(ftmp[4]), [ftmp5]"=&f"(ftmp[5]), [ftmp6]"=&f"(ftmp[6]), [ftmp7]"=&f"(ftmp[7]), - RESTRICT_ASM_ALL64 - RESTRICT_ASM_ADDRT - [addr0]"=&r"(addr[0]), [pixels]"+&r"(pixels) : [line_size]"r"((mips_reg)line_size), - [line_sizex3]"r"((mips_reg)(line_size*3)), [block]"r"(block) : "memory" ); @@ -104,15 +85,9 @@ void ff_put_pixels_clamped_mmi(const int16_t *block, void ff_put_signed_pixels_clamped_mmi(const int16_t *block, uint8_t *av_restrict pixels, ptrdiff_t line_size) { - int64_t line_skip = line_size; - int64_t line_skip3 = 0; double ftmp[5]; - mips_reg addr[1]; - DECLARE_VAR_ALL64; - DECLARE_VAR_ADDRT; __asm__ volatile ( - PTR_ADDU "%[line_skip3], %[line_skip], %[line_skip] \n\t" MMI_LDC1(%[ftmp1], %[block], 0x00) MMI_LDC1(%[ftmp0], %[block], 0x08) "packsshb %[ftmp1], %[ftmp1], %[ftmp0] \n\t" @@ -130,12 +105,14 @@ void ff_put_signed_pixels_clamped_mmi(const int16_t *block, "paddb %[ftmp3], %[ftmp3], %[ff_pb_80] \n\t" "paddb %[ftmp4], %[ftmp4], %[ff_pb_80] \n\t" MMI_SDC1(%[ftmp1], %[pixels], 0x00) - MMI_SDXC1(%[ftmp2], %[pixels], %[line_skip], 0x00) - MMI_SDXC1(%[ftmp3], %[pixels], %[line_skip3], 0x00) - PTR_ADDU "%[line_skip3], %[line_skip3], %[line_skip] \n\t" - MMI_SDXC1(%[ftmp4], %[pixels], %[line_skip3], 0x00) - PTR_ADDU "%[addr0], %[line_skip3], %[line_skip] \n\t" - PTR_ADDU "%[pixels], %[pixels], %[addr0] \n\t" + PTR_ADDU "%[pixels], %[pixels], %[line_size] \n\t" + MMI_SDC1(%[ftmp2], %[pixels], 0x00) + PTR_ADDU "%[pixels], %[pixels], %[line_size] \n\t" + MMI_SDC1(%[ftmp3], %[pixels], 0x00) + PTR_ADDU "%[pixels], %[pixels], %[line_size] \n\t" + MMI_SDC1(%[ftmp4], %[pixels], 0x00) + PTR_ADDU "%[pixels], %[pixels], %[line_size] \n\t" + MMI_LDC1(%[ftmp1], %[block], 0x40) MMI_LDC1(%[ftmp0], %[block], 0x48) "packsshb %[ftmp1], %[ftmp1], %[ftmp0] \n\t" @@ -153,19 +130,18 @@ void ff_put_signed_pixels_clamped_mmi(const int16_t *block, "paddb %[ftmp3], %[ftmp3], %[ff_pb_80] \n\t" "paddb %[ftmp4], %[ftmp4], %[ff_pb_80] \n\t" MMI_SDC1(%[ftmp1], %[pixels], 0x00) - MMI_SDXC1(%[ftmp2], %[pixels], %[line_skip], 0x00) - PTR_ADDU "%[addr0], %[line_skip], %[line_skip] \n\t" - MMI_SDXC1(%[ftmp3], %[pixels], %[addr0], 0x00) - MMI_SDXC1(%[ftmp4], %[pixels], %[line_skip3], 0x00) + PTR_ADDU "%[pixels], %[pixels], %[line_size] \n\t" + MMI_SDC1(%[ftmp2], %[pixels], 0x00) + PTR_ADDU "%[pixels], %[pixels], %[line_size] \n\t" + MMI_SDC1(%[ftmp3], %[pixels], 0x00) + PTR_ADDU "%[pixels], %[pixels], %[line_size] \n\t" + MMI_SDC1(%[ftmp4], %[pixels], 0x00) : [ftmp0]"=&f"(ftmp[0]), [ftmp1]"=&f"(ftmp[1]), [ftmp2]"=&f"(ftmp[2]), [ftmp3]"=&f"(ftmp[3]), [ftmp4]"=&f"(ftmp[4]), - RESTRICT_ASM_ALL64 - RESTRICT_ASM_ADDRT - [addr0]"=&r"(addr[0]), - [pixels]"+&r"(pixels), [line_skip3]"+&r"(line_skip3) + [pixels]"+&r"(pixels) : [block]"r"(block), - [line_skip]"r"((mips_reg)line_skip), + [line_size]"r"((mips_reg)line_size), [ff_pb_80]"f"(ff_pb_80) : "memory" ); @@ -174,49 +150,42 @@ void ff_put_signed_pixels_clamped_mmi(const int16_t *block, void ff_add_pixels_clamped_mmi(const int16_t *block, uint8_t *av_restrict pixels, ptrdiff_t line_size) { - double ftmp[8]; + double ftmp[9]; uint64_t tmp[1]; - mips_reg addr[1]; - DECLARE_VAR_ALL64; - DECLARE_VAR_ADDRT; - __asm__ volatile ( - "li %[tmp0], 0x04 \n\t" - "xor %[ftmp0], %[ftmp0], %[ftmp0] \n\t" - "1: \n\t" + "li %[tmp0], 0x04 \n\t" + "xor %[ftmp0], %[ftmp0], %[ftmp0] \n\t" + "1: \n\t" + MMI_LDC1(%[ftmp5], %[pixels], 0x00) + PTR_ADDU "%[pixels], %[pixels], %[line_size] \n\t" + MMI_LDC1(%[ftmp6], %[pixels], 0x00) + PTR_SUBU "%[pixels], %[pixels], %[line_size] \n\t" MMI_LDC1(%[ftmp1], %[block], 0x00) MMI_LDC1(%[ftmp2], %[block], 0x08) MMI_LDC1(%[ftmp3], %[block], 0x10) MMI_LDC1(%[ftmp4], %[block], 0x18) - MMI_LDC1(%[ftmp5], %[pixels], 0x00) - MMI_LDXC1(%[ftmp6], %[pixels], %[line_size], 0x00) - "mov.d %[ftmp7], %[ftmp5] \n\t" - "punpcklbh %[ftmp5], %[ftmp5], %[ftmp0] \n\t" - "punpckhbh %[ftmp7], %[ftmp7], %[ftmp0] \n\t" - "paddh %[ftmp1], %[ftmp1], %[ftmp5] \n\t" - "paddh %[ftmp2], %[ftmp2], %[ftmp7] \n\t" - "mov.d %[ftmp7], %[ftmp6] \n\t" - "punpcklbh %[ftmp6], %[ftmp6], %[ftmp0] \n\t" - "punpckhbh %[ftmp7], %[ftmp7], %[ftmp0] \n\t" - "paddh %[ftmp3], %[ftmp3], %[ftmp6] \n\t" - "paddh %[ftmp4], %[ftmp4], %[ftmp7] \n\t" - "packushb %[ftmp1], %[ftmp1], %[ftmp2] \n\t" - "packushb %[ftmp3], %[ftmp3], %[ftmp4] \n\t" + PTR_ADDIU "%[block], %[block], 0x20 \n\t" + "punpckhbh %[ftmp7], %[ftmp5], %[ftmp0] \n\t" + "punpcklbh %[ftmp5], %[ftmp5], %[ftmp0] \n\t" + "punpckhbh %[ftmp8], %[ftmp6], %[ftmp0] \n\t" + "punpcklbh %[ftmp6], %[ftmp6], %[ftmp0] \n\t" + "paddh %[ftmp1], %[ftmp1], %[ftmp5] \n\t" + "paddh %[ftmp2], %[ftmp2], %[ftmp7] \n\t" + "paddh %[ftmp3], %[ftmp3], %[ftmp6] \n\t" + "paddh %[ftmp4], %[ftmp4], %[ftmp8] \n\t" + "packushb %[ftmp1], %[ftmp1], %[ftmp2] \n\t" + "packushb %[ftmp3], %[ftmp3], %[ftmp4] \n\t" MMI_SDC1(%[ftmp1], %[pixels], 0x00) - MMI_SDXC1(%[ftmp3], %[pixels], %[line_size], 0x00) - "addi %[tmp0], %[tmp0], -0x01 \n\t" - PTR_ADDIU "%[block], %[block], 0x20 \n\t" - PTR_ADDU "%[pixels], %[pixels], %[line_size] \n\t" - PTR_ADDU "%[pixels], %[pixels], %[line_size] \n\t" - "bnez %[tmp0], 1b" + PTR_ADDU "%[pixels], %[pixels], %[line_size] \n\t" + MMI_SDC1(%[ftmp3], %[pixels], 0x00) + "addi %[tmp0], %[tmp0], -0x01 \n\t" + PTR_ADDU "%[pixels], %[pixels], %[line_size] \n\t" + "bnez %[tmp0], 1b \n\t" : [ftmp0]"=&f"(ftmp[0]), [ftmp1]"=&f"(ftmp[1]), [ftmp2]"=&f"(ftmp[2]), [ftmp3]"=&f"(ftmp[3]), [ftmp4]"=&f"(ftmp[4]), [ftmp5]"=&f"(ftmp[5]), [ftmp6]"=&f"(ftmp[6]), [ftmp7]"=&f"(ftmp[7]), - [tmp0]"=&r"(tmp[0]), - RESTRICT_ASM_ALL64 - RESTRICT_ASM_ADDRT - [addr0]"=&r"(addr[0]), + [ftmp8]"=&f"(ftmp[8]), [tmp0]"=&r"(tmp[0]), [pixels]"+&r"(pixels), [block]"+&r"(block) : [line_size]"r"((mips_reg)line_size) : "memory" diff --git a/libavcodec/mips/mpegvideo_init_mips.c b/libavcodec/mips/mpegvideo_init_mips.c index 1918da5f4..be7730814 100644 --- a/libavcodec/mips/mpegvideo_init_mips.c +++ b/libavcodec/mips/mpegvideo_init_mips.c @@ -49,10 +49,10 @@ static av_cold void dct_unquantize_init_mmi(MpegEncContext *s) av_cold void ff_mpv_common_init_mips(MpegEncContext *s) { -#if HAVE_MSA - dct_unquantize_init_msa(s); -#endif // #if HAVE_MSA #if HAVE_MMI dct_unquantize_init_mmi(s); #endif /* HAVE_MMI */ +#if HAVE_MSA + dct_unquantize_init_msa(s); +#endif // #if HAVE_MSA } diff --git a/libavcodec/mips/mpegvideo_mmi.c b/libavcodec/mips/mpegvideo_mmi.c index 18058e492..e4aba0866 100644 --- a/libavcodec/mips/mpegvideo_mmi.c +++ b/libavcodec/mips/mpegvideo_mmi.c @@ -410,9 +410,9 @@ void ff_dct_unquantize_mpeg2_intra_mmi(MpegEncContext *s, int16_t *block, "psubh %[ftmp2], %[ftmp2], %[ftmp8] \n\t" "pandn %[ftmp5], %[ftmp5], %[ftmp1] \n\t" "pandn %[ftmp6], %[ftmp6], %[ftmp2] \n\t" - PTR_ADDIU "%[addr0], %[addr0], 0x10 \n\t" MMI_SDXC1(%[ftmp5], %[addr0], %[block], 0x00) MMI_SDXC1(%[ftmp6], %[addr0], %[block], 0x08) + PTR_ADDIU "%[addr0], %[addr0], 0x10 \n\t" "blez %[addr0], 1b \n\t" : [ftmp0]"=&f"(ftmp[0]), [ftmp1]"=&f"(ftmp[1]), [ftmp2]"=&f"(ftmp[2]), [ftmp3]"=&f"(ftmp[3]), diff --git a/libavcodec/mips/pixblockdsp_init_mips.c b/libavcodec/mips/pixblockdsp_init_mips.c index 1b3741ea7..fd0238d79 100644 --- a/libavcodec/mips/pixblockdsp_init_mips.c +++ b/libavcodec/mips/pixblockdsp_init_mips.c @@ -60,10 +60,10 @@ static av_cold void pixblockdsp_init_mmi(PixblockDSPContext *c, void ff_pixblockdsp_init_mips(PixblockDSPContext *c, AVCodecContext *avctx, unsigned high_bit_depth) { -#if HAVE_MSA - pixblockdsp_init_msa(c, avctx, high_bit_depth); -#endif // #if HAVE_MSA #if HAVE_MMI pixblockdsp_init_mmi(c, avctx, high_bit_depth); #endif /* HAVE_MMI */ +#if HAVE_MSA + pixblockdsp_init_msa(c, avctx, high_bit_depth); +#endif // #if HAVE_MSA } diff --git a/libavcodec/mips/qpeldsp_msa.c b/libavcodec/mips/qpeldsp_msa.c index 4710b3f73..fba42b300 100644 --- a/libavcodec/mips/qpeldsp_msa.c +++ b/libavcodec/mips/qpeldsp_msa.c @@ -334,7 +334,7 @@ static void horiz_mc_qpel_aver_src0_8width_msa(const uint8_t *src, inp0 = (v16u8) __msa_insve_d((v2i64) inp0, 1, (v2i64) inp1); inp2 = (v16u8) __msa_insve_d((v2i64) inp2, 1, (v2i64) inp3); AVER_UB2_UB(inp0, res0, inp2, res1, res0, res1); - ST8x4_UB(res0, res1, dst, dst_stride); + ST_D4(res0, res1, 0, 1, 0, 1, dst, dst_stride); dst += (4 * dst_stride); } } @@ -409,7 +409,7 @@ static void horiz_mc_qpel_8width_msa(const uint8_t *src, res1 = APPLY_HORIZ_QPEL_FILTER_8BYTE(inp2, inp3, mask0, mask1, mask2, mask3, const20, const6, const3); - ST8x4_UB(res0, res1, dst, dst_stride); + ST_D4(res0, res1, 0, 1, 0, 1, dst, dst_stride); dst += (4 * dst_stride); } } @@ -485,7 +485,7 @@ static void horiz_mc_qpel_aver_src1_8width_msa(const uint8_t *src, inp0 = (v16u8) __msa_insve_d((v2i64) inp0, 1, (v2i64) inp1); inp2 = (v16u8) __msa_insve_d((v2i64) inp2, 1, (v2i64) inp3); AVER_UB2_UB(inp0, res0, inp2, res1, res0, res1); - ST8x4_UB(res0, res1, dst, dst_stride); + ST_D4(res0, res1, 0, 1, 0, 1, dst, dst_stride); dst += (4 * dst_stride); } } @@ -564,7 +564,7 @@ static void horiz_mc_qpel_no_rnd_aver_src0_8width_msa(const uint8_t *src, inp2 = (v16u8) __msa_insve_d((v2i64) inp2, 1, (v2i64) inp3); res0 = __msa_ave_u_b(inp0, res0); res1 = __msa_ave_u_b(inp2, res1); - ST8x4_UB(res0, res1, dst, dst_stride); + ST_D4(res0, res1, 0, 1, 0, 1, dst, dst_stride); dst += (4 * dst_stride); } } @@ -639,7 +639,7 @@ static void horiz_mc_qpel_no_rnd_8width_msa(const uint8_t *src, res1 = APPLY_HORIZ_QPEL_NO_ROUND_FILTER_8BYTE(inp2, inp3, mask0, mask1, mask2, mask3, const20, const6, const3); - ST8x4_UB(res0, res1, dst, dst_stride); + ST_D4(res0, res1, 0, 1, 0, 1, dst, dst_stride); dst += (4 * dst_stride); } } @@ -716,7 +716,7 @@ static void horiz_mc_qpel_no_rnd_aver_src1_8width_msa(const uint8_t *src, inp2 = (v16u8) __msa_insve_d((v2i64) inp2, 1, (v2i64) inp3); res0 = __msa_ave_u_b(inp0, res0); res1 = __msa_ave_u_b(inp2, res1); - ST8x4_UB(res0, res1, dst, dst_stride); + ST_D4(res0, res1, 0, 1, 0, 1, dst, dst_stride); dst += (4 * dst_stride); } } @@ -799,7 +799,7 @@ static void horiz_mc_qpel_avg_dst_aver_src0_8width_msa(const uint8_t *src, dst2 = (v16u8) __msa_insve_d((v2i64) dst2, 1, (v2i64) dst3); AVER_UB2_UB(inp0, res0, inp2, res1, res0, res1); AVER_UB2_UB(dst0, res0, dst2, res1, res0, res1); - ST8x4_UB(res0, res1, dst, dst_stride); + ST_D4(res0, res1, 0, 1, 0, 1, dst, dst_stride); dst += (4 * dst_stride); } } @@ -876,7 +876,7 @@ static void horiz_mc_qpel_avg_dst_8width_msa(const uint8_t *src, dst0 = (v16u8) __msa_insve_d((v2i64) dst0, 1, (v2i64) dst1); dst2 = (v16u8) __msa_insve_d((v2i64) dst2, 1, (v2i64) dst3); AVER_UB2_UB(dst0, res0, dst2, res1, res0, res1); - ST8x4_UB(res0, res1, dst, dst_stride); + ST_D4(res0, res1, 0, 1, 0, 1, dst, dst_stride); dst += (4 * dst_stride); } } @@ -956,7 +956,7 @@ static void horiz_mc_qpel_avg_dst_aver_src1_8width_msa(const uint8_t *src, dst2 = (v16u8) __msa_insve_d((v2i64) dst2, 1, (v2i64) dst3); AVER_UB2_UB(inp0, res0, inp2, res1, res0, res1); AVER_UB2_UB(dst0, res0, dst2, res1, res0, res1); - ST8x4_UB(res0, res1, dst, dst_stride); + ST_D4(res0, res1, 0, 1, 0, 1, dst, dst_stride); dst += (4 * dst_stride); } } @@ -1031,8 +1031,7 @@ static void vert_mc_qpel_aver_src0_8x8_msa(const uint8_t *src, tmp0 = (v16u8) __msa_insve_d((v2i64) inp0, 1, (v2i64) inp1); tmp1 = (v16u8) __msa_insve_d((v2i64) inp2, 1, (v2i64) inp3); AVER_UB2_UB(res0, tmp0, res1, tmp1, res0, res1); - ST8x4_UB(res0, res1, dst, dst_stride); - dst += (4 * dst_stride); + ST_D4(res0, res1, 0, 1, 0, 1, dst, dst_stride); inp8 = LD_UB(src); res0 = APPLY_VERT_QPEL_FILTER_8BYTE(inp4, inp3, inp2, inp1, @@ -1048,8 +1047,7 @@ static void vert_mc_qpel_aver_src0_8x8_msa(const uint8_t *src, tmp0 = (v16u8) __msa_insve_d((v2i64) inp4, 1, (v2i64) inp5); tmp1 = (v16u8) __msa_insve_d((v2i64) inp6, 1, (v2i64) inp7); AVER_UB2_UB(res0, tmp0, res1, tmp1, res0, res1); - ST8x4_UB(res0, res1, dst, dst_stride); - dst += (4 * dst_stride); + ST_D4(res0, res1, 0, 1, 0, 1, dst + 4 * dst_stride, dst_stride); } static void vert_mc_qpel_aver_src0_16x16_msa(const uint8_t *src, @@ -1220,8 +1218,7 @@ static void vert_mc_qpel_8x8_msa(const uint8_t *src, inp3, inp2, inp1, inp0, inp4, inp5, inp6, inp7, const20, const6, const3); - ST8x4_UB(res0, res1, dst, dst_stride); - dst += (4 * dst_stride); + ST_D4(res0, res1, 0, 1, 0, 1, dst, dst_stride); inp8 = LD_UB(src); res0 = APPLY_VERT_QPEL_FILTER_8BYTE(inp4, inp3, inp2, inp1, @@ -1234,8 +1231,7 @@ static void vert_mc_qpel_8x8_msa(const uint8_t *src, inp7, inp6, inp5, inp4, inp8, inp8, inp7, inp6, const20, const6, const3); - ST8x4_UB(res0, res1, dst, dst_stride); - dst += (4 * dst_stride); + ST_D4(res0, res1, 0, 1, 0, 1, dst + 4 * dst_stride, dst_stride); } static void vert_mc_qpel_16x16_msa(const uint8_t *src, @@ -1405,8 +1401,7 @@ static void vert_mc_qpel_aver_src1_8x8_msa(const uint8_t *src, tmp0 = (v16u8) __msa_insve_d((v2i64) inp1, 1, (v2i64) inp2); tmp1 = (v16u8) __msa_insve_d((v2i64) inp3, 1, (v2i64) inp4); AVER_UB2_UB(res0, tmp0, res1, tmp1, res0, res1); - ST8x4_UB(res0, res1, dst, dst_stride); - dst += (4 * dst_stride); + ST_D4(res0, res1, 0, 1, 0, 1, dst, dst_stride); inp8 = LD_UB(src); res0 = APPLY_VERT_QPEL_FILTER_8BYTE(inp4, inp3, inp2, inp1, @@ -1422,7 +1417,7 @@ static void vert_mc_qpel_aver_src1_8x8_msa(const uint8_t *src, tmp0 = (v16u8) __msa_insve_d((v2i64) inp5, 1, (v2i64) inp6); tmp1 = (v16u8) __msa_insve_d((v2i64) inp7, 1, (v2i64) inp8); AVER_UB2_UB(res0, tmp0, res1, tmp1, res0, res1); - ST8x4_UB(res0, res1, dst, dst_stride); + ST_D4(res0, res1, 0, 1, 0, 1, dst + 4 * dst_stride, dst_stride); } static void vert_mc_qpel_aver_src1_16x16_msa(const uint8_t *src, @@ -1607,8 +1602,7 @@ static void vert_mc_qpel_no_rnd_aver_src0_8x8_msa(const uint8_t *src, tmp1 = (v16u8) __msa_insve_d((v2i64) inp2, 1, (v2i64) inp3); res0 = __msa_ave_u_b(res0, tmp0); res1 = __msa_ave_u_b(res1, tmp1); - ST8x4_UB(res0, res1, dst, dst_stride); - dst += (4 * dst_stride); + ST_D4(res0, res1, 0, 1, 0, 1, dst, dst_stride); inp8 = LD_UB(src); res0 = APPLY_VERT_QPEL_NO_ROUND_FILTER_8BYTE(inp4, inp3, inp2, inp1, @@ -1625,8 +1619,7 @@ static void vert_mc_qpel_no_rnd_aver_src0_8x8_msa(const uint8_t *src, tmp1 = (v16u8) __msa_insve_d((v2i64) inp6, 1, (v2i64) inp7); res0 = __msa_ave_u_b(res0, tmp0); res1 = __msa_ave_u_b(res1, tmp1); - ST8x4_UB(res0, res1, dst, dst_stride); - dst += (4 * dst_stride); + ST_D4(res0, res1, 0, 1, 0, 1, dst + 4 * dst_stride, dst_stride); } static void vert_mc_qpel_no_rnd_aver_src0_16x16_msa(const uint8_t *src, @@ -1806,8 +1799,7 @@ static void vert_mc_qpel_no_rnd_8x8_msa(const uint8_t *src, inp3, inp2, inp1, inp0, inp4, inp5, inp6, inp7, const20, const6, const3); - ST8x4_UB(res0, res1, dst, dst_stride); - dst += (4 * dst_stride); + ST_D4(res0, res1, 0, 1, 0, 1, dst, dst_stride); inp8 = LD_UB(src); res0 = APPLY_VERT_QPEL_NO_ROUND_FILTER_8BYTE(inp4, inp3, inp2, inp1, @@ -1820,8 +1812,7 @@ static void vert_mc_qpel_no_rnd_8x8_msa(const uint8_t *src, inp7, inp6, inp5, inp4, inp8, inp8, inp7, inp6, const20, const6, const3); - ST8x4_UB(res0, res1, dst, dst_stride); - dst += (4 * dst_stride); + ST_D4(res0, res1, 0, 1, 0, 1, dst + 4 * dst_stride, dst_stride); } static void vert_mc_qpel_no_rnd_16x16_msa(const uint8_t *src, @@ -1988,8 +1979,7 @@ static void vert_mc_qpel_no_rnd_aver_src1_8x8_msa(const uint8_t *src, tmp1 = (v16u8) __msa_insve_d((v2i64) inp3, 1, (v2i64) inp4); res0 = __msa_ave_u_b(res0, tmp0); res1 = __msa_ave_u_b(res1, tmp1); - ST8x4_UB(res0, res1, dst, dst_stride); - dst += (4 * dst_stride); + ST_D4(res0, res1, 0, 1, 0, 1, dst, dst_stride); inp8 = LD_UB(src); res0 = APPLY_VERT_QPEL_NO_ROUND_FILTER_8BYTE(inp4, inp3, inp2, inp1, @@ -2006,7 +1996,7 @@ static void vert_mc_qpel_no_rnd_aver_src1_8x8_msa(const uint8_t *src, tmp1 = (v16u8) __msa_insve_d((v2i64) inp7, 1, (v2i64) inp8); res0 = __msa_ave_u_b(res0, tmp0); res1 = __msa_ave_u_b(res1, tmp1); - ST8x4_UB(res0, res1, dst, dst_stride); + ST_D4(res0, res1, 0, 1, 0, 1, dst + 4 * dst_stride, dst_stride); } static void vert_mc_qpel_no_rnd_aver_src1_16x16_msa(const uint8_t *src, @@ -2195,7 +2185,7 @@ static void vert_mc_qpel_avg_dst_aver_src0_8x8_msa(const uint8_t *src, dst2 = (v16u8) __msa_insve_d((v2i64) dst2, 1, (v2i64) dst3); AVER_UB2_UB(res0, tmp0, res1, tmp1, res0, res1); AVER_UB2_UB(dst0, res0, dst2, res1, res0, res1); - ST8x4_UB(res0, res1, dst, dst_stride); + ST_D4(res0, res1, 0, 1, 0, 1, dst, dst_stride); dst += (4 * dst_stride); inp8 = LD_UB(src); @@ -2217,7 +2207,7 @@ static void vert_mc_qpel_avg_dst_aver_src0_8x8_msa(const uint8_t *src, dst2 = (v16u8) __msa_insve_d((v2i64) dst2, 1, (v2i64) dst3); AVER_UB2_UB(res0, tmp0, res1, tmp1, res0, res1); AVER_UB2_UB(dst0, res0, dst2, res1, res0, res1); - ST8x4_UB(res0, res1, dst, dst_stride); + ST_D4(res0, res1, 0, 1, 0, 1, dst, dst_stride); } static void vert_mc_qpel_avg_dst_aver_src0_16x16_msa(const uint8_t *src, @@ -2384,7 +2374,7 @@ static void vert_mc_qpel_avg_dst_8x8_msa(const uint8_t *src, dst0 = (v16u8) __msa_insve_d((v2i64) dst0, 1, (v2i64) dst1); dst2 = (v16u8) __msa_insve_d((v2i64) dst2, 1, (v2i64) dst3); AVER_UB2_UB(dst0, res0, dst2, res1, res0, res1); - ST8x4_UB(res0, res1, dst, dst_stride); + ST_D4(res0, res1, 0, 1, 0, 1, dst, dst_stride); dst += (4 * dst_stride); inp8 = LD_UB(src); @@ -2402,8 +2392,7 @@ static void vert_mc_qpel_avg_dst_8x8_msa(const uint8_t *src, dst0 = (v16u8) __msa_insve_d((v2i64) dst0, 1, (v2i64) dst1); dst2 = (v16u8) __msa_insve_d((v2i64) dst2, 1, (v2i64) dst3); AVER_UB2_UB(dst0, res0, dst2, res1, res0, res1); - ST8x4_UB(res0, res1, dst, dst_stride); - dst += (4 * dst_stride); + ST_D4(res0, res1, 0, 1, 0, 1, dst, dst_stride); } static void vert_mc_qpel_avg_dst_16x16_msa(const uint8_t *src, @@ -2566,7 +2555,7 @@ static void vert_mc_qpel_avg_dst_aver_src1_8x8_msa(const uint8_t *src, dst2 = (v16u8) __msa_insve_d((v2i64) dst2, 1, (v2i64) dst3); AVER_UB2_UB(res0, tmp0, res1, tmp1, res0, res1); AVER_UB2_UB(dst0, res0, dst2, res1, res0, res1); - ST8x4_UB(res0, res1, dst, dst_stride); + ST_D4(res0, res1, 0, 1, 0, 1, dst, dst_stride); dst += (4 * dst_stride); inp8 = LD_UB(src); @@ -2587,7 +2576,7 @@ static void vert_mc_qpel_avg_dst_aver_src1_8x8_msa(const uint8_t *src, dst2 = (v16u8) __msa_insve_d((v2i64) dst2, 1, (v2i64) dst3); AVER_UB2_UB(res0, tmp0, res1, tmp1, res0, res1); AVER_UB2_UB(dst0, res0, dst2, res1, res0, res1); - ST8x4_UB(res0, res1, dst, dst_stride); + ST_D4(res0, res1, 0, 1, 0, 1, dst, dst_stride); } static void vert_mc_qpel_avg_dst_aver_src1_16x16_msa(const uint8_t *src, @@ -2832,7 +2821,7 @@ static void hv_mc_qpel_no_rnd_aver_hv_src00_8x8_msa(const uint8_t *src, const20, const6, const3); avg0 = (v16u8) __msa_ilvr_d((v2i64) horiz1, (v2i64) horiz0); res0 = __msa_ave_u_b(avg0, res0); - ST8x2_UB(res0, dst, dst_stride); + ST_D2(res0, 0, 1, dst, dst_stride); dst += (2 * dst_stride); LD_UB2(src, src_stride, inp2, inp3); @@ -2860,7 +2849,7 @@ static void hv_mc_qpel_no_rnd_aver_hv_src00_8x8_msa(const uint8_t *src, horiz5, horiz4, horiz3, horiz2, horiz6, horiz7, horiz8, horiz8, const20, const6, const3); - ST8x2_UB(res1, dst, dst_stride); + ST_D2(res1, 0, 1, dst, dst_stride); dst += 2 * dst_stride; avg0 = (v16u8) __msa_ilvr_d((v2i64) horiz5, (v2i64) horiz4); @@ -2870,12 +2859,12 @@ static void hv_mc_qpel_no_rnd_aver_hv_src00_8x8_msa(const uint8_t *src, horiz7, horiz6, horiz5, horiz4, horiz8, horiz8, horiz7, horiz6, const20, const6, const3); - ST8x2_UB(res0, dst, dst_stride); + ST_D2(res0, 0, 1, dst, dst_stride); dst += 2 * dst_stride; avg1 = (v16u8) __msa_ilvr_d((v2i64) horiz7, (v2i64) horiz6); res1 = __msa_ave_u_b(avg1, res1); - ST8x2_UB(res1, dst, dst_stride); + ST_D2(res1, 0, 1, dst, dst_stride); } static void hv_mc_qpel_no_rnd_horiz_16x16_msa(const uint8_t *src, @@ -2977,7 +2966,7 @@ static void hv_mc_qpel_no_rnd_aver_v_src0_8x8_msa(const uint8_t *src, const20, const6, const3); avg0 = (v16u8) __msa_ilvr_d((v2i64) horiz1, (v2i64) horiz0); res0 = __msa_ave_u_b(avg0, res0); - ST8x2_UB(res0, dst, dst_stride); + ST_D2(res0, 0, 1, dst, dst_stride); dst += (2 * dst_stride); LD_UB2(src, src_stride, inp2, inp3); @@ -2999,7 +2988,7 @@ static void hv_mc_qpel_no_rnd_aver_v_src0_8x8_msa(const uint8_t *src, res1 = __msa_ave_u_b(avg1, res1); avg0 = (v16u8) __msa_ilvr_d((v2i64) horiz1, (v2i64) horiz0); res0 = __msa_ave_u_b(avg0, res0); - ST8x2_UB(res1, dst, dst_stride); + ST_D2(res1, 0, 1, dst, dst_stride); dst += (2 * dst_stride); res0 = APPLY_VERT_QPEL_NO_ROUND_FILTER_8BYTE(horiz4, horiz3, horiz2, horiz1, @@ -3009,7 +2998,7 @@ static void hv_mc_qpel_no_rnd_aver_v_src0_8x8_msa(const uint8_t *src, const20, const6, const3); avg0 = (v16u8) __msa_ilvr_d((v2i64) horiz5, (v2i64) horiz4); res0 = __msa_ave_u_b(avg0, res0); - ST8x2_UB(res0, dst, dst_stride); + ST_D2(res0, 0, 1, dst, dst_stride); dst += (2 * dst_stride); res1 = APPLY_VERT_QPEL_NO_ROUND_FILTER_8BYTE(horiz6, horiz5, horiz4, horiz3, @@ -3019,7 +3008,7 @@ static void hv_mc_qpel_no_rnd_aver_v_src0_8x8_msa(const uint8_t *src, const20, const6, const3); avg1 = (v16u8) __msa_ilvr_d((v2i64) horiz7, (v2i64) horiz6); res1 = __msa_ave_u_b(avg1, res1); - ST8x2_UB(res1, dst, dst_stride); + ST_D2(res1, 0, 1, dst, dst_stride); } static void hv_mc_qpel_no_rnd_horiz_src1_16x16_msa(const uint8_t *src, @@ -3137,7 +3126,7 @@ static void hv_mc_qpel_no_rnd_aver_hv_src10_8x8_msa(const uint8_t *src, const20, const6, const3); avg0 = (v16u8) __msa_ilvr_d((v2i64) horiz1, (v2i64) horiz0); res0 = __msa_ave_u_b(avg0, res0); - ST8x2_UB(res0, dst, dst_stride); + ST_D2(res0, 0, 1, dst, dst_stride); dst += (2 * dst_stride); LD_UB2(src, src_stride, inp2, inp3); @@ -3163,7 +3152,7 @@ static void hv_mc_qpel_no_rnd_aver_hv_src10_8x8_msa(const uint8_t *src, const20, const6, const3); avg1 = (v16u8) __msa_ilvr_d((v2i64) horiz3, (v2i64) horiz2); res1 = __msa_ave_u_b(avg1, res1); - ST8x2_UB(res1, dst, dst_stride); + ST_D2(res1, 0, 1, dst, dst_stride); dst += (2 * dst_stride); res0 = APPLY_VERT_QPEL_NO_ROUND_FILTER_8BYTE(horiz4, horiz3, horiz2, horiz1, @@ -3173,7 +3162,7 @@ static void hv_mc_qpel_no_rnd_aver_hv_src10_8x8_msa(const uint8_t *src, const20, const6, const3); avg0 = (v16u8) __msa_ilvr_d((v2i64) horiz5, (v2i64) horiz4); res0 = __msa_ave_u_b(avg0, res0); - ST8x2_UB(res0, dst, dst_stride); + ST_D2(res0, 0, 1, dst, dst_stride); dst += (2 * dst_stride); res1 = APPLY_VERT_QPEL_NO_ROUND_FILTER_8BYTE(horiz6, horiz5, horiz4, horiz3, @@ -3183,7 +3172,7 @@ static void hv_mc_qpel_no_rnd_aver_hv_src10_8x8_msa(const uint8_t *src, const20, const6, const3); avg1 = (v16u8) __msa_ilvr_d((v2i64) horiz7, (v2i64) horiz6); res1 = __msa_ave_u_b(avg1, res1); - ST8x2_UB(res1, dst, dst_stride); + ST_D2(res1, 0, 1, dst, dst_stride); } static void hv_mc_qpel_no_rnd_aver_h_src0_16x16_msa(const uint8_t *src, @@ -3246,7 +3235,7 @@ static void hv_mc_qpel_no_rnd_aver_h_src0_8x8_msa(const uint8_t *src, LD_UB2(src, src_stride, inp2, inp3); src += (2 * src_stride); - ST8x2_UB(res0, dst, dst_stride); + ST_D2(res0, 0, 1, dst, dst_stride); dst += 2 * dst_stride; res1 = APPLY_HORIZ_QPEL_NO_ROUND_FILTER_8BYTE(inp2, inp3, mask0, mask1, @@ -3270,18 +3259,15 @@ static void hv_mc_qpel_no_rnd_aver_h_src0_8x8_msa(const uint8_t *src, horiz5, horiz4, horiz3, horiz2, horiz6, horiz7, horiz8, horiz8, const20, const6, const3); - ST8x2_UB(res1, dst, dst_stride); - dst += 2 * dst_stride; - - ST8x2_UB(res0, dst, dst_stride); - dst += (2 * dst_stride); + ST_D4(res1, res0, 0, 1, 0, 1, dst, dst_stride); + dst += (4 * dst_stride); res1 = APPLY_VERT_QPEL_NO_ROUND_FILTER_8BYTE(horiz6, horiz5, horiz4, horiz3, horiz7, horiz8, horiz8, horiz7, horiz7, horiz6, horiz5, horiz4, horiz8, horiz8, horiz7, horiz6, const20, const6, const3); - ST8x2_UB(res1, dst, dst_stride); + ST_D2(res1, 0, 1, dst, dst_stride); } static void hv_mc_qpel_no_rnd_16x16_msa(const uint8_t *src, @@ -3337,7 +3323,7 @@ static void hv_mc_qpel_no_rnd_8x8_msa(const uint8_t *src, const20, const6, const3); LD_UB2(src, src_stride, inp2, inp3); src += (2 * src_stride); - ST8x2_UB(res0, dst, dst_stride); + ST_D2(res0, 0, 1, dst, dst_stride); dst += 2 * dst_stride; horiz6 = APPLY_HORIZ_QPEL_NO_ROUND_FILTER_8BYTE(inp2, inp3, mask0, mask1, @@ -3358,7 +3344,7 @@ static void hv_mc_qpel_no_rnd_8x8_msa(const uint8_t *src, horiz5, horiz4, horiz3, horiz2, horiz6, horiz7, horiz8, horiz8, const20, const6, const3); - ST8x2_UB(res1, dst, dst_stride); + ST_D2(res1, 0, 1, dst, dst_stride); dst += 2 * dst_stride; @@ -3367,9 +3353,7 @@ static void hv_mc_qpel_no_rnd_8x8_msa(const uint8_t *src, horiz7, horiz6, horiz5, horiz4, horiz8, horiz8, horiz7, horiz6, const20, const6, const3); - ST8x2_UB(res0, dst, dst_stride); - dst += 2 * dst_stride; - ST8x2_UB(res1, dst, dst_stride); + ST_D4(res0, res1, 0, 1, 0, 1, dst, dst_stride); } static void hv_mc_qpel_no_rnd_aver_h_src1_16x16_msa(const uint8_t *src, @@ -3437,7 +3421,7 @@ static void hv_mc_qpel_no_rnd_aver_h_src1_8x8_msa(const uint8_t *src, const20, const6, const3); LD_UB2(src, src_stride, inp2, inp3); src += (2 * src_stride); - ST8x2_UB(res0, dst, dst_stride); + ST_D2(res0, 0, 1, dst, dst_stride); dst += 2 * dst_stride; res1 = APPLY_HORIZ_QPEL_NO_ROUND_FILTER_8BYTE(inp2, inp3, mask0, mask1, @@ -3464,7 +3448,7 @@ static void hv_mc_qpel_no_rnd_aver_h_src1_8x8_msa(const uint8_t *src, horiz5, horiz4, horiz3, horiz2, horiz6, horiz7, horiz8, horiz8, const20, const6, const3); - ST8x2_UB(res1, dst, dst_stride); + ST_D2(res1, 0, 1, dst, dst_stride); dst += 2 * dst_stride; res1 = APPLY_VERT_QPEL_NO_ROUND_FILTER_8BYTE(horiz6, horiz5, horiz4, horiz3, @@ -3472,9 +3456,7 @@ static void hv_mc_qpel_no_rnd_aver_h_src1_8x8_msa(const uint8_t *src, horiz7, horiz6, horiz5, horiz4, horiz8, horiz8, horiz7, horiz6, const20, const6, const3); - ST8x2_UB(res0, dst, dst_stride); - dst += 2 * dst_stride; - ST8x2_UB(res1, dst, dst_stride); + ST_D4(res0, res1, 0, 1, 0, 1, dst, dst_stride); } static void hv_mc_qpel_no_rnd_aver_hv_src01_16x16_msa(const uint8_t *src, @@ -3536,7 +3518,7 @@ static void hv_mc_qpel_no_rnd_aver_hv_src01_8x8_msa(const uint8_t *src, const20, const6, const3); avg0 = (v16u8) __msa_ilvr_d((v2i64) horiz2, (v2i64) horiz1); res0 = __msa_ave_u_b(avg0, res0); - ST8x2_UB(res0, dst, dst_stride); + ST_D2(res0, 0, 1, dst, dst_stride); dst += (2 * dst_stride); LD_UB2(src, src_stride, inp2, inp3); @@ -3564,7 +3546,7 @@ static void hv_mc_qpel_no_rnd_aver_hv_src01_8x8_msa(const uint8_t *src, horiz5, horiz4, horiz3, horiz2, horiz6, horiz7, horiz8, horiz8, const20, const6, const3); - ST8x2_UB(res1, dst, dst_stride); + ST_D2(res1, 0, 1, dst, dst_stride); dst += 2 * dst_stride; avg0 = (v16u8) __msa_ilvr_d((v2i64) horiz6, (v2i64) horiz5); @@ -3575,12 +3557,12 @@ static void hv_mc_qpel_no_rnd_aver_hv_src01_8x8_msa(const uint8_t *src, horiz7, horiz6, horiz5, horiz4, horiz8, horiz8, horiz7, horiz6, const20, const6, const3); - ST8x2_UB(res0, dst, dst_stride); + ST_D2(res0, 0, 1, dst, dst_stride); dst += 2 * dst_stride; avg1 = (v16u8) __msa_ilvr_d((v2i64) horiz8, (v2i64) horiz7); res1 = __msa_ave_u_b(avg1, res1); - ST8x2_UB(res1, dst, dst_stride); + ST_D2(res1, 0, 1, dst, dst_stride); } static void hv_mc_qpel_no_rnd_aver_v_src1_16x16_msa(const uint8_t *src, @@ -3638,7 +3620,7 @@ static void hv_mc_qpel_no_rnd_aver_v_src1_8x8_msa(const uint8_t *src, res0 = __msa_ave_u_b(avg0, res0); LD_UB2(src, src_stride, inp2, inp3); src += (2 * src_stride); - ST8x2_UB(res0, dst, dst_stride); + ST_D2(res0, 0, 1, dst, dst_stride); dst += 2 * dst_stride; horiz6 = APPLY_HORIZ_QPEL_NO_ROUND_FILTER_8BYTE(inp2, inp3, mask0, mask1, @@ -3656,7 +3638,7 @@ static void hv_mc_qpel_no_rnd_aver_v_src1_8x8_msa(const uint8_t *src, horiz8 = APPLY_HORIZ_QPEL_NO_ROUND_FILTER_8BYTE_1ROW(inp0, mask0, mask1, mask2, mask3, const20, const6, const3); - ST8x2_UB(res1, dst, dst_stride); + ST_D2(res1, 0, 1, dst, dst_stride); dst += 2 * dst_stride; res0 = APPLY_VERT_QPEL_NO_ROUND_FILTER_8BYTE(horiz4, horiz3, horiz2, horiz1, @@ -3671,12 +3653,9 @@ static void hv_mc_qpel_no_rnd_aver_v_src1_8x8_msa(const uint8_t *src, horiz7, horiz6, horiz5, horiz4, horiz8, horiz8, horiz7, horiz6, const20, const6, const3); - ST8x2_UB(res0, dst, dst_stride); - dst += 2 * dst_stride; - avg1 = (v16u8) __msa_ilvr_d((v2i64) horiz8, (v2i64) horiz7); res1 = __msa_ave_u_b(avg1, res1); - ST8x2_UB(res1, dst, dst_stride); + ST_D4(res0, res1, 0, 1, 0, 1, dst, dst_stride); } static void hv_mc_qpel_no_rnd_aver_hv_src11_16x16_msa(const uint8_t *src, @@ -3744,7 +3723,7 @@ static void hv_mc_qpel_no_rnd_aver_hv_src11_8x8_msa(const uint8_t *src, const20, const6, const3); avg0 = (v16u8) __msa_ilvr_d((v2i64) horiz2, (v2i64) horiz1); res0 = __msa_ave_u_b(avg0, res0); - ST8x2_UB(res0, dst, dst_stride); + ST_D2(res0, 0, 1, dst, dst_stride); dst += (2 * dst_stride); LD_UB2(src, src_stride, inp2, inp3); @@ -3764,7 +3743,7 @@ static void hv_mc_qpel_no_rnd_aver_hv_src11_8x8_msa(const uint8_t *src, const20, const6, const3); avg1 = (v16u8) __msa_ilvr_d((v2i64) horiz4, (v2i64) horiz3); res1 = __msa_ave_u_b(avg1, res1); - ST8x2_UB(res1, dst, dst_stride); + ST_D2(res1, 0, 1, dst, dst_stride); dst += (2 * dst_stride); inp0 = LD_UB(src); @@ -3787,7 +3766,7 @@ static void hv_mc_qpel_no_rnd_aver_hv_src11_8x8_msa(const uint8_t *src, res0 = __msa_ave_u_b(avg0, res0); avg1 = (v16u8) __msa_ilvr_d((v2i64) horiz8, (v2i64) horiz7); res1 = __msa_ave_u_b(avg1, res1); - ST8x4_UB(res0, res1, dst, dst_stride); + ST_D4(res0, res1, 0, 1, 0, 1, dst, dst_stride); } static void hv_mc_qpel_aver_horiz_src0_16x16_msa(const uint8_t *src, @@ -3893,7 +3872,7 @@ static void hv_mc_qpel_aver_hv_src00_8x8_msa(const uint8_t *src, const20, const6, const3); avg0 = (v16u8) __msa_ilvr_d((v2i64) horiz1, (v2i64) horiz0); res0 = __msa_aver_u_b(avg0, res0); - ST8x2_UB(res0, dst, dst_stride); + ST_D2(res0, 0, 1, dst, dst_stride); dst += (2 * dst_stride); LD_UB2(src, src_stride, inp2, inp3); @@ -3915,7 +3894,7 @@ static void hv_mc_qpel_aver_hv_src00_8x8_msa(const uint8_t *src, res0 = APPLY_HORIZ_QPEL_FILTER_8BYTE_1ROW(inp0, mask0, mask1, mask2, mask3, const20, const6, const3); horiz8 = __msa_aver_u_b(inp0, res0); - ST8x2_UB(res1, dst, dst_stride); + ST_D2(res1, 0, 1, dst, dst_stride); dst += 2 * dst_stride; res0 = APPLY_VERT_QPEL_FILTER_8BYTE(horiz4, horiz3, horiz2, horiz1, @@ -3930,11 +3909,9 @@ static void hv_mc_qpel_aver_hv_src00_8x8_msa(const uint8_t *src, horiz7, horiz6, horiz5, horiz4, horiz8, horiz8, horiz7, horiz6, const20, const6, const3); - ST8x2_UB(res0, dst, dst_stride); - dst += 2 * dst_stride; avg1 = (v16u8) __msa_ilvr_d((v2i64) horiz7, (v2i64) horiz6); res1 = __msa_aver_u_b(avg1, res1); - ST8x2_UB(res1, dst, dst_stride); + ST_D4(res0, res1, 0, 1, 0, 1, dst, dst_stride); } static void hv_mc_qpel_aver_horiz_16x16_msa(const uint8_t *src, @@ -4034,7 +4011,7 @@ static void hv_mc_qpel_aver_v_src0_8x8_msa(const uint8_t *src, const20, const6, const3); avg0 = (v16u8) __msa_ilvr_d((v2i64) horiz1, (v2i64) horiz0); res0 = __msa_aver_u_b(avg0, res0); - ST8x2_UB(res0, dst, dst_stride); + ST_D2(res0, 0, 1, dst, dst_stride); dst += (2 * dst_stride); LD_UB2(src, src_stride, inp2, inp3); @@ -4059,7 +4036,7 @@ static void hv_mc_qpel_aver_v_src0_8x8_msa(const uint8_t *src, horiz5, horiz4, horiz3, horiz2, horiz6, horiz7, horiz8, horiz8, const20, const6, const3); - ST8x2_UB(res1, dst, dst_stride); + ST_D2(res1, 0, 1, dst, dst_stride); dst += 2 * dst_stride; avg0 = (v16u8) __msa_ilvr_d((v2i64) horiz5, (v2i64) horiz4); @@ -4069,11 +4046,9 @@ static void hv_mc_qpel_aver_v_src0_8x8_msa(const uint8_t *src, horiz7, horiz6, horiz5, horiz4, horiz8, horiz8, horiz7, horiz6, const20, const6, const3); - ST8x2_UB(res0, dst, dst_stride); - dst += 2 * dst_stride; avg1 = (v16u8) __msa_ilvr_d((v2i64) horiz7, (v2i64) horiz6); res1 = __msa_aver_u_b(avg1, res1); - ST8x2_UB(res1, dst, dst_stride); + ST_D4(res0, res1, 0, 1, 0, 1, dst, dst_stride); } static void hv_mc_qpel_aver_horiz_src1_16x16_msa(const uint8_t *src, @@ -4197,7 +4172,7 @@ static void hv_mc_qpel_aver_hv_src10_8x8_msa(const uint8_t *src, horiz3, horiz2, horiz1, horiz0, horiz4, horiz5, horiz6, horiz7, const20, const6, const3); - ST8x2_UB(res0, dst, dst_stride); + ST_D2(res0, 0, 1, dst, dst_stride); dst += 2 * dst_stride; inp0 = LD_UB(src); @@ -4212,7 +4187,7 @@ static void hv_mc_qpel_aver_hv_src10_8x8_msa(const uint8_t *src, horiz5, horiz4, horiz3, horiz2, horiz6, horiz7, horiz8, horiz8, const20, const6, const3); - ST8x2_UB(res1, dst, dst_stride); + ST_D2(res1, 0, 1, dst, dst_stride); dst += 2 * dst_stride; avg0 = (v16u8) __msa_ilvr_d((v2i64) horiz5, (v2i64) horiz4); @@ -4222,12 +4197,9 @@ static void hv_mc_qpel_aver_hv_src10_8x8_msa(const uint8_t *src, horiz7, horiz6, horiz5, horiz4, horiz8, horiz8, horiz7, horiz6, const20, const6, const3); - ST8x2_UB(res0, dst, dst_stride); - dst += 2 * dst_stride; - avg1 = (v16u8) __msa_ilvr_d((v2i64) horiz7, (v2i64) horiz6); res1 = __msa_aver_u_b(avg1, res1); - ST8x2_UB(res1, dst, dst_stride); + ST_D4(res0, res1, 0, 1, 0, 1, dst, dst_stride); } static void hv_mc_qpel_aver_h_src0_16x16_msa(const uint8_t *src, @@ -4285,7 +4257,7 @@ static void hv_mc_qpel_aver_h_src0_8x8_msa(const uint8_t *src, horiz1, horiz0, horiz0, horiz1, horiz2, horiz3, horiz4, horiz5, const20, const6, const3); - ST8x2_UB(res0, dst, dst_stride); + ST_D2(res0, 0, 1, dst, dst_stride); dst += (2 * dst_stride); LD_UB2(src, src_stride, inp2, inp3); @@ -4309,7 +4281,7 @@ static void hv_mc_qpel_aver_h_src0_8x8_msa(const uint8_t *src, horiz5, horiz4, horiz3, horiz2, horiz6, horiz7, horiz8, horiz8, const20, const6, const3); - ST8x2_UB(res1, dst, dst_stride); + ST_D2(res1, 0, 1, dst, dst_stride); dst += 2 * dst_stride; res1 = APPLY_VERT_QPEL_FILTER_8BYTE(horiz6, horiz5, horiz4, horiz3, @@ -4317,9 +4289,7 @@ static void hv_mc_qpel_aver_h_src0_8x8_msa(const uint8_t *src, horiz7, horiz6, horiz5, horiz4, horiz8, horiz8, horiz7, horiz6, const20, const6, const3); - ST8x2_UB(res0, dst, dst_stride); - dst += 2 * dst_stride; - ST8x2_UB(res1, dst, dst_stride); + ST_D4(res0, res1, 0, 1, 0, 1, dst, dst_stride); } static void hv_mc_qpel_16x16_msa(const uint8_t *src, @@ -4371,7 +4341,7 @@ static void hv_mc_qpel_8x8_msa(const uint8_t *src, int32_t src_stride, horiz1, horiz0, horiz0, horiz1, horiz2, horiz3, horiz4, horiz5, const20, const6, const3); - ST8x2_UB(res0, dst, dst_stride); + ST_D2(res0, 0, 1, dst, dst_stride); dst += (2 * dst_stride); LD_UB2(src, src_stride, inp2, inp3); @@ -4389,7 +4359,7 @@ static void hv_mc_qpel_8x8_msa(const uint8_t *src, int32_t src_stride, horiz8 = APPLY_HORIZ_QPEL_FILTER_8BYTE_1ROW(inp0, mask0, mask1, mask2, mask3, const20, const6, const3); - ST8x2_UB(res1, dst, dst_stride); + ST_D2(res1, 0, 1, dst, dst_stride); dst += 2 * dst_stride; res0 = APPLY_VERT_QPEL_FILTER_8BYTE(horiz4, horiz3, horiz2, horiz1, @@ -4402,9 +4372,7 @@ static void hv_mc_qpel_8x8_msa(const uint8_t *src, int32_t src_stride, horiz7, horiz6, horiz5, horiz4, horiz8, horiz8, horiz7, horiz6, const20, const6, const3); - ST8x2_UB(res0, dst, dst_stride); - dst += 2 * dst_stride; - ST8x2_UB(res1, dst, dst_stride); + ST_D4(res0, res1, 0, 1, 0, 1, dst, dst_stride); } static void hv_mc_qpel_aver_h_src1_16x16_msa(const uint8_t *src, @@ -4478,31 +4446,25 @@ static void hv_mc_qpel_aver_h_src1_8x8_msa(const uint8_t *src, horiz1, horiz0, horiz0, horiz1, horiz2, horiz3, horiz4, horiz5, const20, const6, const3); - ST8x2_UB(res0, dst, dst_stride); - dst += (2 * dst_stride); - res1 = APPLY_VERT_QPEL_FILTER_8BYTE(horiz2, horiz1, horiz0, horiz0, horiz3, horiz4, horiz5, horiz6, horiz3, horiz2, horiz1, horiz0, horiz4, horiz5, horiz6, horiz7, const20, const6, const3); - ST8x2_UB(res1, dst, dst_stride); - dst += (2 * dst_stride); + ST_D4(res0, res1, 0, 1, 0, 1, dst, dst_stride); + dst += (4 * dst_stride); res0 = APPLY_VERT_QPEL_FILTER_8BYTE(horiz4, horiz3, horiz2, horiz1, horiz5, horiz6, horiz7, horiz8, horiz5, horiz4, horiz3, horiz2, horiz6, horiz7, horiz8, horiz8, const20, const6, const3); - ST8x2_UB(res0, dst, dst_stride); - dst += (2 * dst_stride); - res1 = APPLY_VERT_QPEL_FILTER_8BYTE(horiz6, horiz5, horiz4, horiz3, horiz7, horiz8, horiz8, horiz7, horiz7, horiz6, horiz5, horiz4, horiz8, horiz8, horiz7, horiz6, const20, const6, const3); - ST8x2_UB(res1, dst, dst_stride); + ST_D4(res0, res1, 0, 1, 0, 1, dst, dst_stride); } static void hv_mc_qpel_aver_hv_src01_16x16_msa(const uint8_t *src, @@ -4561,7 +4523,7 @@ static void hv_mc_qpel_aver_hv_src01_8x8_msa(const uint8_t *src, const20, const6, const3); avg0 = (v16u8) __msa_insve_d((v2i64) horiz1, 1, (v2i64) horiz2); res0 = __msa_aver_u_b(avg0, res0); - ST8x2_UB(res0, dst, dst_stride); + ST_D2(res0, 0, 1, dst, dst_stride); dst += (2 * dst_stride); LD_UB2(src, src_stride, inp2, inp3); @@ -4587,7 +4549,7 @@ static void hv_mc_qpel_aver_hv_src01_8x8_msa(const uint8_t *src, horiz5, horiz4, horiz3, horiz2, horiz6, horiz7, horiz8, horiz8, const20, const6, const3); - ST8x2_UB(res1, dst, dst_stride); + ST_D2(res1, 0, 1, dst, dst_stride); dst += 2 * dst_stride; avg0 = (v16u8) __msa_insve_d((v2i64) horiz5, 1, (v2i64) horiz6); @@ -4597,13 +4559,9 @@ static void hv_mc_qpel_aver_hv_src01_8x8_msa(const uint8_t *src, horiz7, horiz6, horiz5, horiz4, horiz8, horiz8, horiz7, horiz6, const20, const6, const3); - ST8x2_UB(res0, dst, dst_stride); - dst += 2 * dst_stride; - avg1 = (v16u8) __msa_insve_d((v2i64) horiz7, 1, (v2i64) horiz8); res1 = __msa_aver_u_b(avg1, res1); - ST8x2_UB(res1, dst, dst_stride); - dst += (2 * dst_stride); + ST_D4(res0, res1, 0, 1, 0, 1, dst, dst_stride); } static void hv_mc_qpel_aver_v_src1_16x16_msa(const uint8_t *src, @@ -4660,7 +4618,7 @@ static void hv_mc_qpel_aver_v_src1_8x8_msa(const uint8_t *src, const20, const6, const3); avg0 = (v16u8) __msa_insve_d((v2i64) horiz1, 1, (v2i64) horiz2); res0 = __msa_aver_u_b(avg0, res0); - ST8x2_UB(res0, dst, dst_stride); + ST_D2(res0, 0, 1, dst, dst_stride); dst += (2 * dst_stride); LD_UB2(src, src_stride, inp2, inp3); @@ -4685,7 +4643,7 @@ static void hv_mc_qpel_aver_v_src1_8x8_msa(const uint8_t *src, horiz5, horiz4, horiz3, horiz2, horiz6, horiz7, horiz8, horiz8, const20, const6, const3); - ST8x2_UB(res1, dst, dst_stride); + ST_D2(res1, 0, 1, dst, dst_stride); dst += 2 * dst_stride; avg0 = (v16u8) __msa_insve_d((v2i64) horiz5, 1, (v2i64) horiz6); res0 = __msa_aver_u_b(avg0, res0); @@ -4695,11 +4653,9 @@ static void hv_mc_qpel_aver_v_src1_8x8_msa(const uint8_t *src, horiz7, horiz6, horiz5, horiz4, horiz8, horiz8, horiz7, horiz6, const20, const6, const3); - ST8x2_UB(res0, dst, dst_stride); - dst += 2 * dst_stride; avg1 = (v16u8) __msa_insve_d((v2i64) horiz7, 1, (v2i64) horiz8); res1 = __msa_aver_u_b(avg1, res1); - ST8x2_UB(res1, dst, dst_stride); + ST_D4(res0, res1, 0, 1, 0, 1, dst, dst_stride); } static void hv_mc_qpel_aver_hv_src11_16x16_msa(const uint8_t *src, @@ -4764,7 +4720,7 @@ static void hv_mc_qpel_aver_hv_src11_8x8_msa(const uint8_t *src, res0 = __msa_aver_u_b(avg0, res0); LD_UB2(src, src_stride, inp2, inp3); src += (2 * src_stride); - ST8x2_UB(res0, dst, dst_stride); + ST_D2(res0, 0, 1, dst, dst_stride); dst += 2 * dst_stride; res1 = APPLY_HORIZ_QPEL_FILTER_8BYTE(inp2, inp3, mask0, mask1, mask2, mask3, @@ -4791,7 +4747,7 @@ static void hv_mc_qpel_aver_hv_src11_8x8_msa(const uint8_t *src, horiz5, horiz4, horiz3, horiz2, horiz6, horiz7, horiz8, horiz8, const20, const6, const3); - ST8x2_UB(res1, dst, dst_stride); + ST_D2(res1, 0, 1, dst, dst_stride); dst += 2 * dst_stride; avg0 = (v16u8) __msa_ilvr_d((v2i64) horiz6, (v2i64) horiz5); @@ -4801,12 +4757,9 @@ static void hv_mc_qpel_aver_hv_src11_8x8_msa(const uint8_t *src, horiz7, horiz6, horiz5, horiz4, horiz8, horiz8, horiz7, horiz6, const20, const6, const3); - ST8x2_UB(res0, dst, dst_stride); - dst += 2 * dst_stride; - avg1 = (v16u8) __msa_ilvr_d((v2i64) horiz8, (v2i64) horiz7); res1 = __msa_aver_u_b(avg1, res1); - ST8x2_UB(res1, dst, dst_stride); + ST_D4(res0, res1, 0, 1, 0, 1, dst, dst_stride); } static void hv_mc_qpel_avg_dst_aver_hv_src00_16x16_msa(const uint8_t *src, @@ -4869,7 +4822,7 @@ static void hv_mc_qpel_avg_dst_aver_hv_src00_8x8_msa(const uint8_t *src, res0 = __msa_aver_u_b(avg0, res0); avg0 = (v16u8) __msa_ilvr_d((v2i64) dst1, (v2i64) dst0); res0 = __msa_aver_u_b(avg0, res0); - ST8x2_UB(res0, dst, dst_stride); + ST_D2(res0, 0, 1, dst, dst_stride); dst += (2 * dst_stride); LD_UB2(src, src_stride, inp2, inp3); @@ -4889,7 +4842,7 @@ static void hv_mc_qpel_avg_dst_aver_hv_src00_8x8_msa(const uint8_t *src, res1 = __msa_aver_u_b(avg1, res1); avg1 = (v16u8) __msa_ilvr_d((v2i64) dst1, (v2i64) dst0); res1 = __msa_aver_u_b(avg1, res1); - ST8x2_UB(res1, dst, dst_stride); + ST_D2(res1, 0, 1, dst, dst_stride); dst += (2 * dst_stride); inp0 = LD_UB(src); @@ -4906,7 +4859,7 @@ static void hv_mc_qpel_avg_dst_aver_hv_src00_8x8_msa(const uint8_t *src, res0 = __msa_aver_u_b(avg0, res0); avg0 = (v16u8) __msa_ilvr_d((v2i64) dst1, (v2i64) dst0); res0 = __msa_aver_u_b(avg0, res0); - ST8x2_UB(res0, dst, dst_stride); + ST_D2(res0, 0, 1, dst, dst_stride); dst += (2 * dst_stride); LD_UB2(dst, dst_stride, dst0, dst1); @@ -4919,7 +4872,7 @@ static void hv_mc_qpel_avg_dst_aver_hv_src00_8x8_msa(const uint8_t *src, res1 = __msa_aver_u_b(avg1, res1); avg1 = (v16u8) __msa_ilvr_d((v2i64) dst1, (v2i64) dst0); res1 = __msa_aver_u_b(avg1, res1); - ST8x2_UB(res1, dst, dst_stride); + ST_D2(res1, 0, 1, dst, dst_stride); } static void hv_mc_qpel_avg_dst_aver_v_src0_16x16_msa(const uint8_t *src, @@ -4979,7 +4932,7 @@ static void hv_mc_qpel_avg_dst_aver_v_src0_8x8_msa(const uint8_t *src, res0 = __msa_aver_u_b(avg0, res0); avg0 = (v16u8) __msa_ilvr_d((v2i64) dst1, (v2i64) dst0); res0 = __msa_aver_u_b(avg0, res0); - ST8x2_UB(res0, dst, dst_stride); + ST_D2(res0, 0, 1, dst, dst_stride); dst += (2 * dst_stride); LD_UB2(src, src_stride, inp2, inp3); @@ -4998,7 +4951,7 @@ static void hv_mc_qpel_avg_dst_aver_v_src0_8x8_msa(const uint8_t *src, res1 = __msa_aver_u_b(avg1, res1); avg1 = (v16u8) __msa_ilvr_d((v2i64) dst1, (v2i64) dst0); res1 = __msa_aver_u_b(avg1, res1); - ST8x2_UB(res1, dst, dst_stride); + ST_D2(res1, 0, 1, dst, dst_stride); dst += (2 * dst_stride); inp0 = LD_UB(src); @@ -5015,7 +4968,7 @@ static void hv_mc_qpel_avg_dst_aver_v_src0_8x8_msa(const uint8_t *src, res0 = __msa_aver_u_b(avg0, res0); avg0 = (v16u8) __msa_ilvr_d((v2i64) dst1, (v2i64) dst0); res0 = __msa_aver_u_b(avg0, res0); - ST8x2_UB(res0, dst, dst_stride); + ST_D2(res0, 0, 1, dst, dst_stride); dst += (2 * dst_stride); LD_UB2(dst, dst_stride, dst0, dst1); @@ -5028,7 +4981,7 @@ static void hv_mc_qpel_avg_dst_aver_v_src0_8x8_msa(const uint8_t *src, res1 = __msa_aver_u_b(avg1, res1); avg1 = (v16u8) __msa_ilvr_d((v2i64) dst1, (v2i64) dst0); res1 = __msa_aver_u_b(avg1, res1); - ST8x2_UB(res1, dst, dst_stride); + ST_D2(res1, 0, 1, dst, dst_stride); } static void hv_mc_qpel_avg_dst_aver_hv_src10_16x16_msa(const uint8_t *src, @@ -5099,7 +5052,7 @@ static void hv_mc_qpel_avg_dst_aver_hv_src10_8x8_msa(const uint8_t *src, res0 = __msa_aver_u_b(avg0, res0); avg0 = (v16u8) __msa_ilvr_d((v2i64) dst1, (v2i64) dst0); res0 = __msa_aver_u_b(avg0, res0); - ST8x2_UB(res0, dst, dst_stride); + ST_D2(res0, 0, 1, dst, dst_stride); dst += (2 * dst_stride); LD_UB2(src, src_stride, inp2, inp3); @@ -5122,7 +5075,7 @@ static void hv_mc_qpel_avg_dst_aver_hv_src10_8x8_msa(const uint8_t *src, res1 = __msa_aver_u_b(avg1, res1); avg1 = (v16u8) __msa_ilvr_d((v2i64) dst1, (v2i64) dst0); res1 = __msa_aver_u_b(avg1, res1); - ST8x2_UB(res1, dst, dst_stride); + ST_D2(res1, 0, 1, dst, dst_stride); dst += (2 * dst_stride); inp0 = LD_UB(src); @@ -5140,7 +5093,7 @@ static void hv_mc_qpel_avg_dst_aver_hv_src10_8x8_msa(const uint8_t *src, res0 = __msa_aver_u_b(avg0, res0); avg0 = (v16u8) __msa_ilvr_d((v2i64) dst1, (v2i64) dst0); res0 = __msa_aver_u_b(avg0, res0); - ST8x2_UB(res0, dst, dst_stride); + ST_D2(res0, 0, 1, dst, dst_stride); dst += (2 * dst_stride); LD_UB2(dst, dst_stride, dst0, dst1); @@ -5153,7 +5106,7 @@ static void hv_mc_qpel_avg_dst_aver_hv_src10_8x8_msa(const uint8_t *src, res1 = __msa_aver_u_b(avg1, res1); avg1 = (v16u8) __msa_ilvr_d((v2i64) dst1, (v2i64) dst0); res1 = __msa_aver_u_b(avg1, res1); - ST8x2_UB(res1, dst, dst_stride); + ST_D2(res1, 0, 1, dst, dst_stride); } static void hv_mc_qpel_avg_dst_aver_h_src0_16x16_msa(const uint8_t *src, @@ -5214,7 +5167,7 @@ static void hv_mc_qpel_avg_dst_aver_h_src0_8x8_msa(const uint8_t *src, const20, const6, const3); avg0 = (v16u8) __msa_ilvr_d((v2i64) dst1, (v2i64) dst0); res0 = __msa_aver_u_b(avg0, res0); - ST8x2_UB(res0, dst, dst_stride); + ST_D2(res0, 0, 1, dst, dst_stride); dst += (2 * dst_stride); LD_UB2(src, src_stride, inp2, inp3); @@ -5232,7 +5185,7 @@ static void hv_mc_qpel_avg_dst_aver_h_src0_8x8_msa(const uint8_t *src, const20, const6, const3); avg1 = (v16u8) __msa_ilvr_d((v2i64) dst1, (v2i64) dst0); res1 = __msa_aver_u_b(avg1, res1); - ST8x2_UB(res1, dst, dst_stride); + ST_D2(res1, 0, 1, dst, dst_stride); dst += (2 * dst_stride); inp0 = LD_UB(src); @@ -5247,7 +5200,7 @@ static void hv_mc_qpel_avg_dst_aver_h_src0_8x8_msa(const uint8_t *src, const20, const6, const3); avg0 = (v16u8) __msa_ilvr_d((v2i64) dst1, (v2i64) dst0); res0 = __msa_aver_u_b(avg0, res0); - ST8x2_UB(res0, dst, dst_stride); + ST_D2(res0, 0, 1, dst, dst_stride); dst += (2 * dst_stride); LD_UB2(dst, dst_stride, dst0, dst1); @@ -5258,8 +5211,7 @@ static void hv_mc_qpel_avg_dst_aver_h_src0_8x8_msa(const uint8_t *src, const20, const6, const3); avg1 = (v16u8) __msa_ilvr_d((v2i64) dst1, (v2i64) dst0); res1 = __msa_aver_u_b(avg1, res1); - ST8x2_UB(res1, dst, dst_stride); - dst += (2 * dst_stride); + ST_D2(res1, 0, 1, dst, dst_stride); } static void hv_mc_qpel_avg_dst_16x16_msa(const uint8_t *src, int32_t src_stride, @@ -5324,7 +5276,7 @@ static void hv_mc_qpel_avg_dst_8x8_msa(const uint8_t *src, int32_t src_stride, const20, const6, const3); avg0 = (v16u8) __msa_ilvr_d((v2i64) dst1, (v2i64) dst0); res0 = __msa_aver_u_b(avg0, res0); - ST8x2_UB(res0, dst, dst_stride); + ST_D2(res0, 0, 1, dst, dst_stride); dst += (2 * dst_stride); LD_UB2(dst, dst_stride, dst0, dst1); @@ -5335,7 +5287,7 @@ static void hv_mc_qpel_avg_dst_8x8_msa(const uint8_t *src, int32_t src_stride, const20, const6, const3); avg1 = (v16u8) __msa_ilvr_d((v2i64) dst1, (v2i64) dst0); res1 = __msa_aver_u_b(avg1, res1); - ST8x2_UB(res1, dst, dst_stride); + ST_D2(res1, 0, 1, dst, dst_stride); dst += (2 * dst_stride); LD_UB2(dst, dst_stride, dst0, dst1); @@ -5346,7 +5298,7 @@ static void hv_mc_qpel_avg_dst_8x8_msa(const uint8_t *src, int32_t src_stride, const20, const6, const3); avg0 = (v16u8) __msa_ilvr_d((v2i64) dst1, (v2i64) dst0); res0 = __msa_aver_u_b(avg0, res0); - ST8x2_UB(res0, dst, dst_stride); + ST_D2(res0, 0, 1, dst, dst_stride); dst += (2 * dst_stride); LD_UB2(dst, dst_stride, dst0, dst1); @@ -5357,7 +5309,7 @@ static void hv_mc_qpel_avg_dst_8x8_msa(const uint8_t *src, int32_t src_stride, const20, const6, const3); avg1 = (v16u8) __msa_ilvr_d((v2i64) dst1, (v2i64) dst0); res1 = __msa_aver_u_b(avg1, res1); - ST8x2_UB(res1, dst, dst_stride); + ST_D2(res1, 0, 1, dst, dst_stride); } static void hv_mc_qpel_avg_dst_aver_h_src1_16x16_msa(const uint8_t *src, @@ -5425,7 +5377,7 @@ static void hv_mc_qpel_avg_dst_aver_h_src1_8x8_msa(const uint8_t *src, const20, const6, const3); avg0 = (v16u8) __msa_ilvr_d((v2i64) dst1, (v2i64) dst0); res0 = __msa_aver_u_b(avg0, res0); - ST8x2_UB(res0, dst, dst_stride); + ST_D2(res0, 0, 1, dst, dst_stride); dst += (2 * dst_stride); LD_UB2(src, src_stride, inp2, inp3); @@ -5446,7 +5398,7 @@ static void hv_mc_qpel_avg_dst_aver_h_src1_8x8_msa(const uint8_t *src, const20, const6, const3); avg1 = (v16u8) __msa_ilvr_d((v2i64) dst1, (v2i64) dst0); res1 = __msa_aver_u_b(avg1, res1); - ST8x2_UB(res1, dst, dst_stride); + ST_D2(res1, 0, 1, dst, dst_stride); dst += (2 * dst_stride); inp0 = LD_UB(src); @@ -5462,7 +5414,7 @@ static void hv_mc_qpel_avg_dst_aver_h_src1_8x8_msa(const uint8_t *src, const20, const6, const3); avg0 = (v16u8) __msa_ilvr_d((v2i64) dst1, (v2i64) dst0); res0 = __msa_aver_u_b(avg0, res0); - ST8x2_UB(res0, dst, dst_stride); + ST_D2(res0, 0, 1, dst, dst_stride); dst += (2 * dst_stride); LD_UB2(dst, dst_stride, dst0, dst1); @@ -5473,7 +5425,7 @@ static void hv_mc_qpel_avg_dst_aver_h_src1_8x8_msa(const uint8_t *src, const20, const6, const3); avg1 = (v16u8) __msa_ilvr_d((v2i64) dst1, (v2i64) dst0); res1 = __msa_aver_u_b(avg1, res1); - ST8x2_UB(res1, dst, dst_stride); + ST_D2(res1, 0, 1, dst, dst_stride); } static void hv_mc_qpel_avg_dst_aver_hv_src01_16x16_msa(const uint8_t *src, @@ -5537,7 +5489,7 @@ static void hv_mc_qpel_avg_dst_aver_hv_src01_8x8_msa(const uint8_t *src, res0 = __msa_aver_u_b(avg0, res0); avg0 = (v16u8) __msa_ilvr_d((v2i64) dst1, (v2i64) dst0); res0 = __msa_aver_u_b(avg0, res0); - ST8x2_UB(res0, dst, dst_stride); + ST_D2(res0, 0, 1, dst, dst_stride); dst += (2 * dst_stride); LD_UB2(dst, dst_stride, dst0, dst1); @@ -5557,7 +5509,7 @@ static void hv_mc_qpel_avg_dst_aver_hv_src01_8x8_msa(const uint8_t *src, res1 = __msa_aver_u_b(avg1, res1); avg1 = (v16u8) __msa_ilvr_d((v2i64) dst1, (v2i64) dst0); res1 = __msa_aver_u_b(avg1, res1); - ST8x2_UB(res1, dst, dst_stride); + ST_D2(res1, 0, 1, dst, dst_stride); dst += (2 * dst_stride); inp0 = LD_UB(src); @@ -5579,7 +5531,7 @@ static void hv_mc_qpel_avg_dst_aver_hv_src01_8x8_msa(const uint8_t *src, LD_UB2(dst, dst_stride, dst0, dst1); avg0 = (v16u8) __msa_ilvr_d((v2i64) dst1, (v2i64) dst0); res0 = __msa_aver_u_b(avg0, res0); - ST8x2_UB(res0, dst, dst_stride); + ST_D2(res0, 0, 1, dst, dst_stride); dst += (2 * dst_stride); avg1 = (v16u8) __msa_ilvr_d((v2i64) horiz8, (v2i64) horiz7); @@ -5587,7 +5539,7 @@ static void hv_mc_qpel_avg_dst_aver_hv_src01_8x8_msa(const uint8_t *src, LD_UB2(dst, dst_stride, dst0, dst1); avg1 = (v16u8) __msa_ilvr_d((v2i64) dst1, (v2i64) dst0); res1 = __msa_aver_u_b(avg1, res1); - ST8x2_UB(res1, dst, dst_stride); + ST_D2(res1, 0, 1, dst, dst_stride); } static void hv_mc_qpel_avg_dst_aver_v_src1_16x16_msa(const uint8_t *src, @@ -5647,7 +5599,7 @@ static void hv_mc_qpel_avg_dst_aver_v_src1_8x8_msa(const uint8_t *src, res0 = __msa_aver_u_b(avg0, res0); avg0 = (v16u8) __msa_ilvr_d((v2i64) dst1, (v2i64) dst0); res0 = __msa_aver_u_b(avg0, res0); - ST8x2_UB(res0, dst, dst_stride); + ST_D2(res0, 0, 1, dst, dst_stride); dst += (2 * dst_stride); LD_UB2(dst, dst_stride, dst0, dst1); @@ -5666,7 +5618,7 @@ static void hv_mc_qpel_avg_dst_aver_v_src1_8x8_msa(const uint8_t *src, res1 = __msa_aver_u_b(avg1, res1); avg1 = (v16u8) __msa_ilvr_d((v2i64) dst1, (v2i64) dst0); res1 = __msa_aver_u_b(avg1, res1); - ST8x2_UB(res1, dst, dst_stride); + ST_D2(res1, 0, 1, dst, dst_stride); dst += (2 * dst_stride); inp0 = LD_UB(src); @@ -5686,7 +5638,7 @@ static void hv_mc_qpel_avg_dst_aver_v_src1_8x8_msa(const uint8_t *src, LD_UB2(dst, dst_stride, dst0, dst1); avg0 = (v16u8) __msa_ilvr_d((v2i64) dst1, (v2i64) dst0); res0 = __msa_aver_u_b(avg0, res0); - ST8x2_UB(res0, dst, dst_stride); + ST_D2(res0, 0, 1, dst, dst_stride); dst += (2 * dst_stride); avg1 = (v16u8) __msa_ilvr_d((v2i64) horiz8, (v2i64) horiz7); @@ -5694,7 +5646,7 @@ static void hv_mc_qpel_avg_dst_aver_v_src1_8x8_msa(const uint8_t *src, LD_UB2(dst, dst_stride, dst0, dst1); avg1 = (v16u8) __msa_ilvr_d((v2i64) dst1, (v2i64) dst0); res1 = __msa_aver_u_b(avg1, res1); - ST8x2_UB(res1, dst, dst_stride); + ST_D2(res1, 0, 1, dst, dst_stride); } static void hv_mc_qpel_avg_dst_aver_hv_src11_16x16_msa(const uint8_t *src, @@ -5762,7 +5714,7 @@ static void hv_mc_qpel_avg_dst_aver_hv_src11_8x8_msa(const uint8_t *src, res0 = __msa_aver_u_b(avg0, res0); avg0 = (v16u8) __msa_ilvr_d((v2i64) dst1, (v2i64) dst0); res0 = __msa_aver_u_b(avg0, res0); - ST8x2_UB(res0, dst, dst_stride); + ST_D2(res0, 0, 1, dst, dst_stride); dst += (2 * dst_stride); LD_UB2(src, src_stride, inp2, inp3); @@ -5783,7 +5735,7 @@ static void hv_mc_qpel_avg_dst_aver_hv_src11_8x8_msa(const uint8_t *src, res1 = __msa_aver_u_b(avg1, res1); avg1 = (v16u8) __msa_ilvr_d((v2i64) dst1, (v2i64) dst0); res1 = __msa_aver_u_b(avg1, res1); - ST8x2_UB(res1, dst, dst_stride); + ST_D2(res1, 0, 1, dst, dst_stride); dst += (2 * dst_stride); inp0 = LD_UB(src); @@ -5800,7 +5752,7 @@ static void hv_mc_qpel_avg_dst_aver_hv_src11_8x8_msa(const uint8_t *src, res0 = __msa_aver_u_b(avg0, res0); avg0 = (v16u8) __msa_ilvr_d((v2i64) dst1, (v2i64) dst0); res0 = __msa_aver_u_b(avg0, res0); - ST8x2_UB(res0, dst, dst_stride); + ST_D2(res0, 0, 1, dst, dst_stride); dst += (2 * dst_stride); LD_UB2(dst, dst_stride, dst0, dst1); @@ -5812,7 +5764,7 @@ static void hv_mc_qpel_avg_dst_aver_hv_src11_8x8_msa(const uint8_t *src, res1 = __msa_aver_u_b(avg1, res1); avg1 = (v16u8) __msa_ilvr_d((v2i64) dst1, (v2i64) dst0); res1 = __msa_aver_u_b(avg1, res1); - ST8x2_UB(res1, dst, dst_stride); + ST_D2(res1, 0, 1, dst, dst_stride); } static void copy_8x8_msa(const uint8_t *src, int32_t src_stride, diff --git a/libavcodec/mips/simple_idct_mmi.c b/libavcodec/mips/simple_idct_mmi.c index 628e13f7d..7f4bb74fd 100644 --- a/libavcodec/mips/simple_idct_mmi.c +++ b/libavcodec/mips/simple_idct_mmi.c @@ -24,793 +24,400 @@ #include "idctdsp_mips.h" #include "constants.h" +#include "libavutil/mips/asmdefs.h" +#include "libavutil/mips/mmiutils.h" -#define C0 23170 //cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5 -#define C1 22725 //cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5 -#define C2 21407 //cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5 -#define C3 19266 //cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5 -#define C4 16383 //cos(i*M_PI/16)*sqrt(2)*(1<<14) - 0.5 -#define C5 12873 //cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5 -#define C6 8867 //cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5 -#define C7 4520 //cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5 +#define W1 22725 //cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5 +#define W2 21407 //cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5 +#define W3 19266 //cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5 +#define W4 16383 //cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5 +#define W5 12873 //cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5 +#define W6 8867 //cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5 +#define W7 4520 //cos(i*M_PI/16)*sqrt(2)*(1<<14) + 0.5 #define ROW_SHIFT 11 #define COL_SHIFT 20 +#define DC_SHIFT 3 -DECLARE_ALIGNED(8, static const int16_t, coeffs)[]= { - 1<<(ROW_SHIFT-1), 0, 1<<(ROW_SHIFT-1), 0, - 1<<(ROW_SHIFT-1), 1, 1<<(ROW_SHIFT-1), 0, - C4, C4, C4, C4, - C4, -C4, C4, -C4, - C2, C6, C2, C6, - C6, -C2, C6, -C2, - C1, C3, C1, C3, - C5, C7, C5, C7, - C3, -C7, C3, -C7, - -C1, -C5, -C1, -C5, - C5, -C1, C5, -C1, - C7, C3, C7, C3, - C7, -C5, C7, -C5, - C3, -C1, C3, -C1 +DECLARE_ALIGNED(8, const int16_t, W_arr)[46] = { + W4, W2, W4, W6, + W1, W3, W5, W7, + W4, W6, -W4, -W2, + W3, -W7, -W1, -W5, + W4, -W6, -W4, W2, + W5, -W1, W7, W3, + W4, -W2, W4, -W6, + W7, -W5, W3, -W1, + 1024, 0, 1024, 0, //ff_p32_1024 = 0x0000040000000400ULL + 0, -1, -1, -1, //mask = 0xffffffffffff0000ULL + 32, 32, 32, 32 //ff_p16_32 = 0x0020002000200020ULL }; -void ff_simple_idct_mmi(int16_t *block) +void ff_simple_idct_8_mmi(int16_t *block) { - DECLARE_ALIGNED(8, int64_t, align_tmp)[16]; - int16_t * const temp= (int16_t*)align_tmp; + BACKUP_REG + __asm__ volatile ( - __asm__ volatile ( -#undef DC_COND_IDCT -#define DC_COND_IDCT(src0, src4, src1, src5, dst, rounder, rarg, shift) \ - "ldc1 $f0, " #src0 " \n\t" /* R4 R0 r4 r0 */\ - "ldc1 $f2, " #src4 " \n\t" /* R6 R2 r6 r2 */\ - "ldc1 $f4, " #src1 " \n\t" /* R3 R1 r3 r1 */\ - "ldc1 $f6, " #src5 " \n\t" /* R7 R5 r7 r5 */\ - "ldc1 $f8, %3 \n\t" \ - "and $f8, $f8, $f0 \n\t" \ - "or $f8, $f8, $f2 \n\t" \ - "or $f8, $f8, $f4 \n\t" \ - "or $f8, $f8, $f6 \n\t" \ - "packsswh $f8, $f8, $f8 \n\t" \ - "li $11, " #shift " \n\t" \ - "mfc1 $10, $f8 \n\t" \ - "mtc1 $11, $f18 \n\t" \ - "beqz $10, 1f \n\t" \ - "ldc1 $f8, 16(%2) \n\t" /* C4 C4 C4 C4 */\ - "pmaddhw $f8, $f8, $f0 \n\t" /* C4R4+C4R0 C4r4+C4r0 */\ - "ldc1 $f10, 24(%2) \n\t" /* -C4 C4 -C4 C4 */\ - "pmaddhw $f0, $f0, $f10 \n\t" /* -C4R4+C4R0 -C4r4+C4r0 */\ - "ldc1 $f10, 32(%2) \n\t" /* C6 C2 C6 C2 */\ - "pmaddhw $f10, $f10, $f2 \n\t" /* C6R6+C2R2 C6r6+C2r2 */\ - "ldc1 $f12, 40(%2) \n\t" /* -C2 C6 -C2 C6 */\ - "pmaddhw $f2, $f2, $f12 \n\t" /* -C2R6+C6R2 -C2r6+C6r2 */\ - "ldc1 $f14, 48(%2) \n\t" /* C3 C1 C3 C1 */\ - "ldc1 $f16, " #rarg " \n\t" \ - "pmaddhw $f14, $f14, $f4 \n\t" /* C3R3+C1R1 C3r3+C1r1 */\ - #rounder " $f8, $f8, $f16 \n\t" \ - "mov.d $f12, $f8 \n\t" /* C4R4+C4R0 C4r4+C4r0 */\ - "paddw $f8, $f8, $f10 \n\t" /* A0 a0 */\ - "psubw $f12, $f12, $f10 \n\t" /* A3 a3 */\ - "ldc1 $f10, 56(%2) \n\t" /* C7 C5 C7 C5 */\ - "ldc1 $f16, " #rarg " \n\t" \ - "pmaddhw $f10, $f10, $f6 \n\t" /* C7R7+C5R5 C7r7+C5r5 */\ - #rounder " $f0, $f0, $f16 \n\t" \ - "paddw $f2, $f2, $f0 \n\t" /* A1 a1 */\ - "ldc1 $f16, 64(%2) \n\t" \ - "paddw $f0, $f0, $f0 \n\t" \ - "psubw $f0, $f0, $f2 \n\t" /* A2 a2 */\ - "pmaddhw $f4, $f4, $f16 \n\t" /* -C7R3+C3R1 -C7r3+C3r1 */\ - "paddw $f14, $f14, $f10 \n\t" /* B0 b0 */\ - "ldc1 $f10, 72(%2) \n\t" /* -C5 -C1 -C5 -C1 */\ - "pmaddhw $f10, $f10, $f6 \n\t" /* -C5R7-C1R5 -C5r7-C1r5 */\ - "paddw $f14, $f14, $f8 \n\t" /* A0+B0 a0+b0 */\ - "paddw $f8, $f8, $f8 \n\t" /* 2A0 2a0 */\ - "psubw $f8, $f8, $f14 \n\t" /* A0-B0 a0-b0 */\ - "paddw $f10, $f10, $f4 \n\t" /* B1 b1 */\ - "psraw $f14, $f14, $f18 \n\t" \ - "psraw $f8, $f8, $f18 \n\t" \ - "mov.d $f4, $f2 \n\t" /* A1 a1 */\ - "paddw $f2, $f2, $f10 \n\t" /* A1+B1 a1+b1 */\ - "psubw $f4, $f4, $f10 \n\t" /* A1-B1 a1-b1 */\ - "psraw $f2, $f2, $f18 \n\t" \ - "psraw $f4, $f4, $f18 \n\t" \ - "packsswh $f14, $f14, $f2 \n\t" /* A1+B1 a1+b1 A0+B0 a0+b0 */\ - "packsswh $f4, $f4, $f8 \n\t" /* A0-B0 a0-b0 A1-B1 a1-b1 */\ - "sdc1 $f14, " #dst " \n\t" \ - "ldc1 $f2, " #src1 " \n\t" /* R3 R1 r3 r1 */\ - "ldc1 $f8, 80(%2) \n\t" /* -C1 C5 -C1 C5 */\ - "sdc1 $f4, 24+" #dst " \n\t" \ - "pmaddhw $f8, $f8, $f2 \n\t" /* -C1R3+C5R1 -C1r3+C5r1 */\ - "ldc1 $f16, 96(%2) \n\t" \ - "ldc1 $f14, 88(%2) \n\t" /* C3 C7 C3 C7 */\ - "pmaddhw $f2, $f2, $f16 \n\t" /* -C5R3+C7R1 -C5r3+C7r1 */\ - "pmaddhw $f14, $f14, $f6 \n\t" /* C3R7+C7R5 C3r7+C7r5 */\ - "ldc1 $f16, 104(%2) \n\t" \ - "mov.d $f4, $f0 \n\t" /* A2 a2 */\ - "pmaddhw $f6, $f6, $f16 \n\t" /* -C1R7+C3R5 -C1r7+C3r5 */\ - "paddw $f8, $f8, $f14 \n\t" /* B2 b2 */\ - "paddw $f4, $f4, $f8 \n\t" /* A2+B2 a2+b2 */\ - "psubw $f0, $f0, $f8 \n\t" /* a2-B2 a2-b2 */\ - "psraw $f4, $f4, $f18 \n\t" \ - "psraw $f0, $f0, $f18 \n\t" \ - "mov.d $f8, $f12 \n\t" /* A3 a3 */\ - "paddw $f6, $f6, $f2 \n\t" /* B3 b3 */\ - "paddw $f12, $f12, $f6 \n\t" /* A3+B3 a3+b3 */\ - "psubw $f8, $f8, $f6 \n\t" /* a3-B3 a3-b3 */\ - "psraw $f12, $f12, $f18 \n\t" \ - "packsswh $f4, $f4, $f12 \n\t" /* A3+B3 a3+b3 A2+B2 a2+b2 */\ - "sdc1 $f4, 8+" #dst " \n\t" \ - "psraw $f8, $f8, $f18 \n\t" \ - "packsswh $f8, $f8, $f0 \n\t" /* A2-B2 a2-b2 A3-B3 a3-b3 */\ - "sdc1 $f8, 16+" #dst " \n\t" \ - "b 2f \n\t" \ - "1: \n\t" \ - "li $10, 16 \n\t" \ - "mtc1 $10, $f16 \n\t" \ - "psllw $f0, $f0, $f16 \n\t" \ - "ldc1 $f16, %4 \n\t" \ - "paddw $f0, $f0, $f16 \n\t" \ - "li $10, 13 \n\t" \ - "mtc1 $10, $f16 \n\t" \ - "psraw $f0, $f0, $f16 \n\t" \ - "packsswh $f0, $f0, $f0 \n\t" \ - "sdc1 $f0, " #dst " \n\t" \ - "sdc1 $f0, 8+" #dst " \n\t" \ - "sdc1 $f0, 16+" #dst " \n\t" \ - "sdc1 $f0, 24+" #dst " \n\t" \ - "2: \n\t" +#define IDCT_ROW_COND_DC(src1, src2) \ + "dmfc1 $11, "#src1" \n\t" \ + "dmfc1 $12, "#src2" \n\t" \ + "and $11, $11, $9 \n\t" \ + "or $10, $11, $12 \n\t" \ + "beqz $10, 1f \n\t" \ + \ + "punpcklhw $f30, "#src1", "#src2" \n\t" \ + "punpckhhw $f31, "#src1", "#src2" \n\t" \ + /* s6, s4, s2, s0 */ \ + "punpcklhw "#src1", $f30, $f31 \n\t" \ + /* s7, s5, s3, s1 */ \ + "punpckhhw "#src2", $f30, $f31 \n\t" \ + \ + "pmaddhw $f30, "#src1", $f18 \n\t" \ + "pmaddhw $f31, "#src2", $f19 \n\t" \ + "paddw $f28, $f30, $f31 \n\t" \ + "psubw $f29, $f30, $f31 \n\t" \ + "punpcklwd $f30, $f28, $f29 \n\t" \ + "punpckhwd $f31, $f28, $f29 \n\t" \ + "paddw $f26, $f30, $f31 \n\t" \ + "paddw $f26, $f26, $f16 \n\t" \ + /* $f26: src[7], src[0] */ \ + "psraw $f26, $f26, $f17 \n\t" \ + \ + "pmaddhw $f30, "#src1", $f20 \n\t" \ + "pmaddhw $f31, "#src2", $f21 \n\t" \ + "paddw $f28, $f30, $f31 \n\t" \ + "psubw $f29, $f30, $f31 \n\t" \ + "punpcklwd $f30, $f28, $f29 \n\t" \ + "punpckhwd $f31, $f28, $f29 \n\t" \ + "paddw $f27, $f30, $f31 \n\t" \ + "paddw $f27, $f27, $f16 \n\t" \ + /* $f27: src[6], src[1] */ \ + "psraw $f27, $f27, $f17 \n\t" \ + \ + "pmaddhw $f30, "#src1", $f22 \n\t" \ + "pmaddhw $f31, "#src2", $f23 \n\t" \ + "paddw $f28, $f30, $f31 \n\t" \ + "psubw $f29, $f30, $f31 \n\t" \ + "punpcklwd $f30, $f28, $f29 \n\t" \ + "punpckhwd $f31, $f28, $f29 \n\t" \ + "paddw $f28, $f30, $f31 \n\t" \ + "paddw $f28, $f28, $f16 \n\t" \ + /* $f28: src[5], src[2] */ \ + "psraw $f28, $f28, $f17 \n\t" \ + \ + "pmaddhw $f30, "#src1", $f24 \n\t" \ + "pmaddhw $f31, "#src2", $f25 \n\t" \ + "paddw "#src1", $f30, $f31 \n\t" \ + "psubw "#src2", $f30, $f31 \n\t" \ + "punpcklwd $f30, "#src1", "#src2" \n\t" \ + "punpckhwd $f31, "#src1", "#src2" \n\t" \ + "paddw $f29, $f30, $f31 \n\t" \ + "paddw $f29, $f29, $f16 \n\t" \ + /* $f29: src[4], src[3] */ \ + "psraw $f29, $f29, $f17 \n\t" \ + \ + "punpcklhw "#src1", $f26, $f27 \n\t" \ + "punpckhhw $f30, $f27, $f26 \n\t" \ + "punpcklhw $f31, $f28, $f29 \n\t" \ + "punpckhhw "#src2", $f29, $f28 \n\t" \ + /* src[3], src[2], src[1], src[0] */ \ + "punpcklwd "#src1", "#src1", $f31 \n\t" \ + /* src[7], src[6], src[5], src[4] */ \ + "punpcklwd "#src2", "#src2", $f30 \n\t" \ + "j 2f \n\t" \ + \ + "1: \n\t" \ + "li $10, 3 \n\t" \ + "dmtc1 $10, $f30 \n\t" \ + "psllh $f28, "#src1", $f30 \n\t" \ + "dmtc1 $9, $f31 \n\t" \ + "punpcklhw $f29, $f28, $f28 \n\t" \ + "and $f29, $f29, $f31 \n\t" \ + "paddw $f28, $f28, $f29 \n\t" \ + "punpcklwd "#src1", $f28, $f28 \n\t" \ + "punpcklwd "#src2", $f28, $f28 \n\t" \ + "2: \n\t" \ -#undef Z_COND_IDCT -#define Z_COND_IDCT(src0, src4, src1, src5, dst, rounder, rarg, shift, bt) \ - "ldc1 $f0, " #src0 " \n\t" /* R4 R0 r4 r0 */\ - "ldc1 $f2, " #src4 " \n\t" /* R6 R2 r6 r2 */\ - "ldc1 $f4, " #src1 " \n\t" /* R3 R1 r3 r1 */\ - "ldc1 $f6, " #src5 " \n\t" /* R7 R5 r7 r5 */\ - "mov.d $f8, $f0 \n\t" \ - "or $f8, $f8, $f2 \n\t" \ - "or $f8, $f8, $f4 \n\t" \ - "or $f8, $f8, $f6 \n\t" \ - "packsswh $f8, $f8, $f8 \n\t" \ - "mfc1 $10, $f8 \n\t" \ - "beqz $10, " #bt " \n\t" \ - "ldc1 $f8, 16(%2) \n\t" /* C4 C4 C4 C4 */\ - "pmaddhw $f8, $f8, $f0 \n\t" /* C4R4+C4R0 C4r4+C4r0 */\ - "ldc1 $f10, 24(%2) \n\t" /* -C4 C4 -C4 C4 */\ - "pmaddhw $f0, $f0, $f10 \n\t" /* -C4R4+C4R0 -C4r4+C4r0 */\ - "ldc1 $f10, 32(%2) \n\t" /* C6 C2 C6 C2 */\ - "pmaddhw $f10, $f10, $f2 \n\t" /* C6R6+C2R2 C6r6+C2r2 */\ - "ldc1 $f12, 40(%2) \n\t" /* -C2 C6 -C2 C6 */\ - "pmaddhw $f2, $f2, $f12 \n\t" /* -C2R6+C6R2 -C2r6+C6r2 */\ - "ldc1 $f14, 48(%2) \n\t" /* C3 C1 C3 C1 */\ - "ldc1 $f16, " #rarg " \n\t" \ - "pmaddhw $f14, $f14, $f4 \n\t" /* C3R3+C1R1 C3r3+C1r1 */\ - #rounder " $f8, $f8, $f16 \n\t" \ - "mov.d $f12, $f8 \n\t" /* C4R4+C4R0 C4r4+C4r0 */\ - "paddw $f8, $f8, $f10 \n\t" /* A0 a0 */\ - "psubw $f12, $f12, $f10 \n\t" /* A3 a3 */\ - "ldc1 $f10, 56(%2) \n\t" /* C7 C5 C7 C5 */\ - "ldc1 $f16, " #rarg " \n\t" \ - "pmaddhw $f10, $f10, $f6 \n\t" /* C7R7+C5R5 C7r7+C5r5 */\ - #rounder " $f0, $f0, $f16 \n\t" \ - "paddw $f2, $f2, $f0 \n\t" /* A1 a1 */\ - "paddw $f0, $f0, $f0 \n\t" \ - "ldc1 $f16, 64(%2) \n\t" \ - "psubw $f0, $f0, $f2 \n\t" /* A2 a2 */\ - "pmaddhw $f4, $f4, $f16 \n\t" /* -C7R3+C3R1 -C7r3+C3r1 */\ - "paddw $f14, $f14, $f10 \n\t" /* B0 b0 */\ - "ldc1 $f10, 72(%2) \n\t" /* -C5 -C1 -C5 -C1 */\ - "pmaddhw $f10, $f10, $f6 \n\t" /* -C5R7-C1R5 -C5r7-C1r5 */\ - "paddw $f14, $f14, $f8 \n\t" /* A0+B0 a0+b0 */\ - "paddw $f8, $f8, $f8 \n\t" /* 2A0 2a0 */\ - "li $10, " #shift " \n\t" \ - "psubw $f8, $f8, $f14 \n\t" /* A0-B0 a0-b0 */\ - "mtc1 $10, $f18 \n\t" \ - "paddw $f10, $f10, $f4 \n\t" /* B1 b1 */\ - "psraw $f14, $f14, $f18 \n\t" \ - "psraw $f8, $f8, $f18 \n\t" \ - "mov.d $f4, $f2 \n\t" /* A1 a1 */\ - "paddw $f2, $f2, $f10 \n\t" /* A1+B1 a1+b1 */\ - "psubw $f4, $f4, $f10 \n\t" /* A1-B1 a1-b1 */\ - "psraw $f2, $f2, $f18 \n\t" \ - "psraw $f4, $f4, $f18 \n\t" \ - "packsswh $f14, $f14, $f2 \n\t" /* A1+B1 a1+b1 A0+B0 a0+b0 */\ - "packsswh $f4, $f4, $f8 \n\t" /* A0-B0 a0-b0 A1-B1 a1-b1 */\ - "sdc1 $f14, " #dst " \n\t" \ - "ldc1 $f2, " #src1 " \n\t" /* R3 R1 r3 r1 */\ - "ldc1 $f8, 80(%2) \n\t" /* -C1 C5 -C1 C5 */\ - "sdc1 $f4, 24+" #dst " \n\t" \ - "pmaddhw $f8, $f8, $f2 \n\t" /* -C1R3+C5R1 -C1r3+C5r1 */\ - "ldc1 $f16, 96(%2) \n\t" \ - "ldc1 $f14, 88(%2) \n\t" /* C3 C7 C3 C7 */\ - "pmaddhw $f2, $f2, $f16 \n\t" /* -C5R3+C7R1 -C5r3+C7r1 */\ - "pmaddhw $f14, $f14, $f6 \n\t" /* C3R7+C7R5 C3r7+C7r5 */\ - "ldc1 $f16, 104(%2) \n\t" \ - "mov.d $f4, $f0 \n\t" /* A2 a2 */\ - "pmaddhw $f6, $f6, $f16 \n\t" /* -C1R7+C3R5 -C1r7+C3r5 */\ - "paddw $f8, $f8, $f14 \n\t" /* B2 b2 */\ - "paddw $f4, $f4, $f8 \n\t" /* A2+B2 a2+b2 */\ - "psubw $f0, $f0, $f8 \n\t" /* a2-B2 a2-b2 */\ - "psraw $f4, $f4, $f18 \n\t" \ - "psraw $f0, $f0, $f18 \n\t" \ - "mov.d $f8, $f12 \n\t" /* A3 a3 */\ - "paddw $f6, $f6, $f2 \n\t" /* B3 b3 */\ - "paddw $f12, $f12, $f6 \n\t" /* A3+B3 a3+b3 */\ - "psubw $f8, $f8, $f6 \n\t" /* a3-B3 a3-b3 */\ - "psraw $f12, $f12, $f18 \n\t" \ - "packsswh $f4, $f4, $f12 \n\t" /* A3+B3 a3+b3 A2+B2 a2+b2 */\ - "sdc1 $f4, 8+" #dst " \n\t" \ - "psraw $f8, $f8, $f18 \n\t" \ - "packsswh $f8, $f8, $f0 \n\t" /* A2-B2 a2-b2 A3-B3 a3-b3 */\ - "sdc1 $f8, 16+" #dst " \n\t" \ + /* idctRowCondDC row0~8 */ - //IDCT( src0, src4, src1, src5, dst, rounder, shift) - DC_COND_IDCT(0(%0), 8(%0), 16(%0), 24(%0), 0(%1), paddw,8(%2), 11) - Z_COND_IDCT(32(%0), 40(%0), 48(%0), 56(%0), 32(%1), paddw,(%2), 11, 4f) - Z_COND_IDCT(64(%0), 72(%0), 80(%0), 88(%0), 64(%1), paddw,(%2), 11, 2f) - Z_COND_IDCT(96(%0),104(%0),112(%0),120(%0), 96(%1), paddw,(%2), 11, 1f) + /* load W */ + "gslqc1 $f19, $f18, 0x00(%[w_arr]) \n\t" + "gslqc1 $f21, $f20, 0x10(%[w_arr]) \n\t" + "gslqc1 $f23, $f22, 0x20(%[w_arr]) \n\t" + "gslqc1 $f25, $f24, 0x30(%[w_arr]) \n\t" + "gslqc1 $f17, $f16, 0x40(%[w_arr]) \n\t" + /* load source in block */ + "gslqc1 $f1, $f0, 0x00(%[block]) \n\t" + "gslqc1 $f3, $f2, 0x10(%[block]) \n\t" + "gslqc1 $f5, $f4, 0x20(%[block]) \n\t" + "gslqc1 $f7, $f6, 0x30(%[block]) \n\t" + "gslqc1 $f9, $f8, 0x40(%[block]) \n\t" + "gslqc1 $f11, $f10, 0x50(%[block]) \n\t" + "gslqc1 $f13, $f12, 0x60(%[block]) \n\t" + "gslqc1 $f15, $f14, 0x70(%[block]) \n\t" -#undef IDCT -#define IDCT(src0, src4, src1, src5, dst, shift) \ - "ldc1 $f0, " #src0 " \n\t" /* R4 R0 r4 r0 */\ - "ldc1 $f2, " #src4 " \n\t" /* R6 R2 r6 r2 */\ - "ldc1 $f4, " #src1 " \n\t" /* R3 R1 r3 r1 */\ - "ldc1 $f6, " #src5 " \n\t" /* R7 R5 r7 r5 */\ - "ldc1 $f8, 16(%2) \n\t" /* C4 C4 C4 C4 */\ - "pmaddhw $f8, $f8, $f0 \n\t" /* C4R4+C4R0 C4r4+C4r0 */\ - "ldc1 $f10, 24(%2) \n\t" /* -C4 C4 -C4 C4 */\ - "pmaddhw $f0, $f0, $f10 \n\t" /* -C4R4+C4R0 -C4r4+C4r0 */\ - "ldc1 $f10, 32(%2) \n\t" /* C6 C2 C6 C2 */\ - "pmaddhw $f10, $f10, $f2 \n\t" /* C6R6+C2R2 C6r6+C2r2 */\ - "ldc1 $f12, 40(%2) \n\t" /* -C2 C6 -C2 C6 */\ - "pmaddhw $f2, $f2, $f12 \n\t" /* -C2R6+C6R2 -C2r6+C6r2 */\ - "mov.d $f12, $f8 \n\t" /* C4R4+C4R0 C4r4+C4r0 */\ - "ldc1 $f14, 48(%2) \n\t" /* C3 C1 C3 C1 */\ - "pmaddhw $f14, $f14, $f4 \n\t" /* C3R3+C1R1 C3r3+C1r1 */\ - "paddw $f8, $f8, $f10 \n\t" /* A0 a0 */\ - "psubw $f12, $f12, $f10 \n\t" /* A3 a3 */\ - "mov.d $f10, $f0 \n\t" /* -C4R4+C4R0 -C4r4+C4r0 */\ - "paddw $f0, $f0, $f2 \n\t" /* A1 a1 */\ - "psubw $f10, $f10, $f2 \n\t" /* A2 a2 */\ - "ldc1 $f2, 56(%2) \n\t" /* C7 C5 C7 C5 */\ - "ldc1 $f16, 64(%2) \n\t" \ - "pmaddhw $f2, $f2, $f6 \n\t" /* C7R7+C5R5 C7r7+C5r5 */\ - "pmaddhw $f4, $f4, $f16 \n\t" /* -C7R3+C3R1 -C7r3+C3r1 */\ - "li $10, " #shift " \n\t" \ - "paddw $f14, $f14, $f2 \n\t" /* B0 b0 */\ - "ldc1 $f2, 72(%2) \n\t" /* -C5 -C1 -C5 -C1 */\ - "mtc1 $10, $f18 \n\t" \ - "pmaddhw $f2, $f2, $f6 \n\t" /* -C5R7-C1R5 -C5r7-C1r5 */\ - "paddw $f14, $f14, $f8 \n\t" /* A0+B0 a0+b0 */\ - "paddw $f8, $f8, $f8 \n\t" /* 2A0 2a0 */\ - "psubw $f8, $f8, $f14 \n\t" /* A0-B0 a0-b0 */\ - "paddw $f2, $f2, $f4 \n\t" /* B1 b1 */\ - "psraw $f14, $f14, $f18 \n\t" \ - "psraw $f8, $f8, $f18 \n\t" \ - "mov.d $f4, $f0 \n\t" /* A1 a1 */\ - "paddw $f0, $f0, $f2 \n\t" /* A1+B1 a1+b1 */\ - "psubw $f4, $f4, $f2 \n\t" /* A1-B1 a1-b1 */\ - "psraw $f0, $f0, $f18 \n\t" \ - "psraw $f4, $f4, $f18 \n\t" \ - "packsswh $f14, $f14, $f14 \n\t" /* A0+B0 a0+b0 */\ - "swc1 $f14, " #dst " \n\t" \ - "packsswh $f0, $f0, $f0 \n\t" /* A1+B1 a1+b1 */\ - "swc1 $f0, 16+" #dst " \n\t" \ - "packsswh $f4, $f4, $f4 \n\t" /* A1-B1 a1-b1 */\ - "swc1 $f4, 96+" #dst " \n\t" \ - "packsswh $f8, $f8, $f8 \n\t" /* A0-B0 a0-b0 */\ - "swc1 $f8, 112+" #dst " \n\t" \ - "ldc1 $f0, " #src1 " \n\t" /* R3 R1 r3 r1 */\ - "ldc1 $f8, 80(%2) \n\t" /* -C1 C5 -C1 C5 */\ - "pmaddhw $f8, $f8, $f0 \n\t" /* -C1R3+C5R1 -C1r3+C5r1 */\ - "ldc1 $f16, 96(%2) \n\t" \ - "ldc1 $f14, 88(%2) \n\t" /* C3 C7 C3 C7 */\ - "pmaddhw $f0, $f0, $f16 \n\t" /* -C5R3+C7R1 -C5r3+C7r1 */\ - "pmaddhw $f14, $f14, $f6 \n\t" /* C3R7+C7R5 C3r7+C7r5 */\ - "ldc1 $f16, 104(%2) \n\t" \ - "mov.d $f4, $f10 \n\t" /* A2 a2 */\ - "pmaddhw $f6, $f6, $f16 \n\t" /* -C1R7+C3R5 -C1r7+C3r5 */\ - "paddw $f8, $f8, $f14 \n\t" /* B2 b2 */\ - "paddw $f4, $f4, $f8 \n\t" /* A2+B2 a2+b2 */\ - "psubw $f10, $f10, $f8 \n\t" /* a2-B2 a2-b2 */\ - "psraw $f4, $f4, $f18 \n\t" \ - "psraw $f10, $f10, $f18 \n\t" \ - "mov.d $f8, $f12 \n\t" /* A3 a3 */\ - "paddw $f6, $f6, $f0 \n\t" /* B3 b3 */\ - "paddw $f12, $f12, $f6 \n\t" /* A3+B3 a3+b3 */\ - "psubw $f8, $f8, $f6 \n\t" /* a3-B3 a3-b3 */\ - "psraw $f12, $f12, $f18 \n\t" \ - "psraw $f8, $f8, $f18 \n\t" \ - "packsswh $f4, $f4, $f4 \n\t" /* A2+B2 a2+b2 */\ - "packsswh $f12, $f12, $f12 \n\t" /* A3+B3 a3+b3 */\ - "swc1 $f4, 32+" #dst " \n\t" \ - "packsswh $f8, $f8, $f8 \n\t" /* A3-B3 a3-b3 */\ - "packsswh $f10, $f10, $f10 \n\t" /* A2-B2 a2-b2 */\ - "swc1 $f12, 48+" #dst " \n\t" \ - "swc1 $f8, 64+" #dst " \n\t" \ - "swc1 $f10, 80+" #dst " \n\t" + /* $9: mask ; $f17: ROW_SHIFT */ + "dmfc1 $9, $f17 \n\t" + "li $10, 11 \n\t" + "mtc1 $10, $f17 \n\t" + IDCT_ROW_COND_DC($f0,$f1) + IDCT_ROW_COND_DC($f2,$f3) + IDCT_ROW_COND_DC($f4,$f5) + IDCT_ROW_COND_DC($f6,$f7) + IDCT_ROW_COND_DC($f8,$f9) + IDCT_ROW_COND_DC($f10,$f11) + IDCT_ROW_COND_DC($f12,$f13) + IDCT_ROW_COND_DC($f14,$f15) - //IDCT( src0, src4, src1, src5, dst, shift) - IDCT( (%1), 64(%1), 32(%1), 96(%1), 0(%0), 20) - IDCT( 8(%1), 72(%1), 40(%1), 104(%1), 4(%0), 20) - IDCT( 16(%1), 80(%1), 48(%1), 112(%1), 8(%0), 20) - IDCT( 24(%1), 88(%1), 56(%1), 120(%1), 12(%0), 20) - "b 9f \n\t" +#define IDCT_COL_CASE1(src, out1, out2) \ + "pmaddhw $f26, "#src", $f18 \n\t" \ + "pmaddhw $f27, "#src", $f20 \n\t" \ + "pmaddhw $f28, "#src", $f22 \n\t" \ + "pmaddhw $f29, "#src", $f24 \n\t" \ + \ + "punpcklwd $f30, $f26, $f26 \n\t" \ + "punpckhwd $f31, $f26, $f26 \n\t" \ + /* $f26: src[0], src[56] */ \ + "paddw $f26, $f30, $f31 \n\t" \ + "punpcklwd $f30, $f27, $f27 \n\t" \ + "punpckhwd $f31, $f27, $f27 \n\t" \ + /* $f27: src[8], src[48] */ \ + "paddw $f27, $f30, $f31 \n\t" \ + "punpcklwd $f30, $f28, $f28 \n\t" \ + "punpckhwd $f31, $f28, $f28 \n\t" \ + /* $f28: src[16], src[40] */ \ + "paddw $f28, $f30, $f31 \n\t" \ + "punpcklwd $f30, $f29, $f29 \n\t" \ + "punpckhwd $f31, $f29, $f29 \n\t" \ + /* $f29: src[24], src[32] */ \ + "paddw $f29, $f30, $f31 \n\t" \ + \ + /* out1: src[24], src[16], src[8], src[0] */ \ + /* out2: src[56], src[48], src[40], src[32] */ \ + "punpcklhw $f30, $f26, $f27 \n\t" \ + "punpcklhw $f31, $f28, $f29 \n\t" \ + "punpckhwd "#out1", $f30, $f31 \n\t" \ + "psrah "#out1", "#out1", $f16 \n\t" \ + "punpcklhw $f30, $f27, $f26 \n\t" \ + "punpcklhw $f31, $f29, $f28 \n\t" \ + "punpckhwd "#out2", $f31, $f30 \n\t" \ + "psrah "#out2", "#out2", $f16 \n\t" - "# .p2align 4 \n\t" - "4: \n\t" - Z_COND_IDCT(64(%0), 72(%0), 80(%0), 88(%0), 64(%1),paddw,(%2), 11, 6f) - Z_COND_IDCT(96(%0),104(%0),112(%0),120(%0), 96(%1),paddw,(%2), 11, 5f) +#define IDCT_COL_CASE2(src1, src2, out1, out2) \ + "pmaddhw $f28, "#src1", $f18 \n\t" \ + "pmaddhw $f29, "#src2", $f19 \n\t" \ + "paddw $f30, $f28, $f29 \n\t" \ + "psubw $f31, $f28, $f29 \n\t" \ + "punpcklwd $f28, $f30, $f31 \n\t" \ + "punpckhwd $f29, $f30, $f31 \n\t" \ + "pmaddhw $f30, "#src1", $f20 \n\t" \ + "pmaddhw $f31, "#src2", $f21 \n\t" \ + /* $f26: src[0], src[56] */ \ + "paddw $f26, $f28, $f29 \n\t" \ + "paddw $f28, $f30, $f31 \n\t" \ + "psubw $f29, $f30, $f31 \n\t" \ + "punpcklwd $f30, $f28, $f29 \n\t" \ + "punpckhwd $f31, $f28, $f29 \n\t" \ + "pmaddhw $f28, "#src1", $f22 \n\t" \ + "pmaddhw $f29, "#src2", $f23 \n\t" \ + /* $f27: src[8], src[48] */ \ + "paddw $f27, $f30, $f31 \n\t" \ + "paddw $f30, $f28, $f29 \n\t" \ + "psubw $f31, $f28, $f29 \n\t" \ + "punpcklwd $f28, $f30, $f31 \n\t" \ + "punpckhwd $f29, $f30, $f31 \n\t" \ + "pmaddhw $f30, "#src1", $f24 \n\t" \ + "pmaddhw $f31, "#src2", $f25 \n\t" \ + /* $f28: src[16], src[40] */ \ + "paddw $f28, $f28, $f29 \n\t" \ + "paddw "#out1", $f30, $f31 \n\t" \ + "psubw "#out2", $f30, $f31 \n\t" \ + "punpcklwd $f30, "#out1", "#out2" \n\t" \ + "punpckhwd $f31, "#out1", "#out2" \n\t" \ + /* $f29: src[24], src[32] */ \ + "paddw $f29, $f30, $f31 \n\t" \ + \ + /* out1: src[24], src[16], src[8], src[0] */ \ + /* out2: src[56], src[48], src[40], src[32] */ \ + "punpcklhw "#out1", $f26, $f27 \n\t" \ + "punpckhhw "#out2", $f27, $f26 \n\t" \ + "punpcklhw $f30, $f28, $f29 \n\t" \ + "punpckhhw $f31, $f29, $f28 \n\t" \ + "punpckhwd "#out1", "#out1", $f30 \n\t" \ + "punpckhwd "#out2", $f31, "#out2" \n\t" \ + "psrah "#out1", "#out1", $f16 \n\t" \ + "psrah "#out2", "#out2", $f16 \n\t" -#undef IDCT -#define IDCT(src0, src4, src1, src5, dst, shift) \ - "ldc1 $f0, " #src0 " \n\t" /* R4 R0 r4 r0 */\ - "ldc1 $f2, " #src4 " \n\t" /* R6 R2 r6 r2 */\ - "ldc1 $f6, " #src5 " \n\t" /* R7 R5 r7 r5 */\ - "ldc1 $f8, 16(%2) \n\t" /* C4 C4 C4 C4 */\ - "pmaddhw $f8, $f8, $f0 \n\t" /* C4R4+C4R0 C4r4+C4r0 */\ - "ldc1 $f10, 24(%2) \n\t" /* -C4 C4 -C4 C4 */\ - "pmaddhw $f0, $f0, $f10 \n\t" /* -C4R4+C4R0 -C4r4+C4r0 */\ - "ldc1 $f10, 32(%2) \n\t" /* C6 C2 C6 C2 */\ - "pmaddhw $f10, $f10, $f2 \n\t" /* C6R6+C2R2 C6r6+C2r2 */\ - "ldc1 $f12, 40(%2) \n\t" /* -C2 C6 -C2 C6 */\ - "pmaddhw $f2, $f2, $f12 \n\t" /* -C2R6+C6R2 -C2r6+C6r2 */\ - "mov.d $f12, $f8 \n\t" /* C4R4+C4R0 C4r4+C4r0 */\ - "paddw $f8, $f8, $f10 \n\t" /* A0 a0 */\ - "psubw $f12, $f12, $f10 \n\t" /* A3 a3 */\ - "mov.d $f10, $f0 \n\t" /* -C4R4+C4R0 -C4r4+C4r0 */\ - "paddw $f0, $f0, $f2 \n\t" /* A1 a1 */\ - "psubw $f10, $f10, $f2 \n\t" /* A2 a2 */\ - "ldc1 $f2, 56(%2) \n\t" /* C7 C5 C7 C5 */\ - "li $10, " #shift " \n\t" \ - "pmaddhw $f2, $f2, $f6 \n\t" /* C7R7+C5R5 C7r7+C5r5 */\ - "ldc1 $f14, 72(%2) \n\t" /* -C5 -C1 -C5 -C1 */\ - "mtc1 $10, $f18 \n\t" \ - "pmaddhw $f14, $f14, $f6 \n\t" /* -C5R7-C1R5 -C5r7-C1r5 */\ - "paddw $f2, $f2, $f8 \n\t" /* A0+B0 a0+b0 */\ - "paddw $f8, $f8, $f8 \n\t" /* 2A0 2a0 */\ - "psubw $f8, $f8, $f2 \n\t" /* A0-B0 a0-b0 */\ - "psraw $f2, $f2, $f18 \n\t" \ - "psraw $f8, $f8, $f18 \n\t" \ - "mov.d $f4, $f0 \n\t" /* A1 a1 */\ - "paddw $f0, $f0, $f14 \n\t" /* A1+B1 a1+b1 */\ - "psubw $f4, $f4, $f14 \n\t" /* A1-B1 a1-b1 */\ - "psraw $f0, $f0, $f18 \n\t" \ - "psraw $f4, $f4, $f18 \n\t" \ - "packsswh $f2, $f2, $f2 \n\t" /* A0+B0 a0+b0 */\ - "swc1 $f2, " #dst " \n\t" \ - "packsswh $f0, $f0, $f0 \n\t" /* A1+B1 a1+b1 */\ - "swc1 $f0, 16+" #dst " \n\t" \ - "packsswh $f4, $f4, $f4 \n\t" /* A1-B1 a1-b1 */\ - "swc1 $f4, 96+" #dst " \n\t" \ - "packsswh $f8, $f8, $f8 \n\t" /* A0-B0 a0-b0 */\ - "swc1 $f8, 112+" #dst " \n\t" \ - "ldc1 $f2, 88(%2) \n\t" /* C3 C7 C3 C7 */\ - "ldc1 $f16, 104(%2) \n\t" \ - "pmaddhw $f2, $f2, $f6 \n\t" /* C3R7+C7R5 C3r7+C7r5 */\ - "mov.d $f4, $f10 \n\t" /* A2 a2 */\ - "pmaddhw $f6, $f6, $f16 \n\t" /* -C1R7+C3R5 -C1r7+C3r5 */\ - "paddw $f4, $f4, $f2 \n\t" /* A2+B2 a2+b2 */\ - "psubw $f10, $f10, $f2 \n\t" /* a2-B2 a2-b2 */\ - "psraw $f4, $f4, $f18 \n\t" \ - "psraw $f10, $f10, $f18 \n\t" \ - "mov.d $f2, $f12 \n\t" /* A3 a3 */\ - "paddw $f12, $f12, $f6 \n\t" /* A3+B3 a3+b3 */\ - "psubw $f2, $f2, $f6 \n\t" /* a3-B3 a3-b3 */\ - "psraw $f12, $f12, $f18 \n\t" \ - "psraw $f2, $f2, $f18 \n\t" \ - "packsswh $f4, $f4, $f4 \n\t" /* A2+B2 a2+b2 */\ - "packsswh $f12, $f12, $f12 \n\t" /* A3+B3 a3+b3 */\ - "swc1 $f4, 32+" #dst " \n\t" \ - "packsswh $f2, $f2, $f2 \n\t" /* A3-B3 a3-b3 */\ - "packsswh $f10, $f10, $f10 \n\t" /* A2-B2 a2-b2 */\ - "swc1 $f12, 48+" #dst " \n\t" \ - "swc1 $f2, 64+" #dst " \n\t" \ - "swc1 $f10, 80+" #dst " \n\t" - //IDCT( src0, src4, src1, src5, dst, shift) - IDCT( (%1), 64(%1), 32(%1), 96(%1), 0(%0), 20) - IDCT( 8(%1), 72(%1), 40(%1), 104(%1), 4(%0), 20) - IDCT( 16(%1), 80(%1), 48(%1), 112(%1), 8(%0), 20) - IDCT( 24(%1), 88(%1), 56(%1), 120(%1), 12(%0), 20) - "b 9f \n\t" + /* idctSparseCol col0~3 */ - "# .p2align 4 \n\t" - "6: \n\t" - Z_COND_IDCT(96(%0),104(%0),112(%0),120(%0), 96(%1),paddw,(%2), 11, 7f) + /* $f17: ff_p16_32; $f16: COL_SHIFT-16 */ + "gsldlc1 $f17, 0x57(%[w_arr]) \n\t" + "gsldrc1 $f17, 0x50(%[w_arr]) \n\t" + "li $10, 4 \n\t" + "dmtc1 $10, $f16 \n\t" + "paddh $f0, $f0, $f17 \n\t" + /* Transpose row[0,2,4,6] */ + "punpcklhw $f26, $f0, $f4 \n\t" + "punpckhhw $f27, $f0, $f4 \n\t" + "punpcklhw $f28, $f8, $f12 \n\t" + "punpckhhw $f29, $f8, $f12 \n\t" + "punpcklwd $f0, $f26, $f28 \n\t" + "punpckhwd $f4, $f26, $f28 \n\t" + "punpcklwd $f8, $f27, $f29 \n\t" + "punpckhwd $f12, $f27, $f29 \n\t" -#undef IDCT -#define IDCT(src0, src4, src1, src5, dst, shift) \ - "ldc1 $f0, " #src0 " \n\t" /* R4 R0 r4 r0 */\ - "ldc1 $f6, " #src5 " \n\t" /* R7 R5 r7 r5 */\ - "ldc1 $f8, 16(%2) \n\t" /* C4 C4 C4 C4 */\ - "pmaddhw $f8, $f8, $f0 \n\t" /* C4R4+C4R0 C4r4+C4r0 */\ - "ldc1 $f10, 24(%2) \n\t" /* -C4 C4 -C4 C4 */\ - "pmaddhw $f0, $f0, $f10 \n\t" /* -C4R4+C4R0 -C4r4+C4r0 */\ - "mov.d $f12, $f8 \n\t" /* C4R4+C4R0 C4r4+C4r0 */\ - "mov.d $f10, $f0 \n\t" /* -C4R4+C4R0 -C4r4+C4r0 */\ - "ldc1 $f2, 56(%2) \n\t" /* C7 C5 C7 C5 */\ - "pmaddhw $f2, $f2, $f6 \n\t" /* C7R7+C5R5 C7r7+C5r5 */\ - "ldc1 $f14, 72(%2) \n\t" /* -C5 -C1 -C5 -C1 */\ - "li $10, " #shift " \n\t" \ - "pmaddhw $f14, $f14, $f6 \n\t" /* -C5R7-C1R5 -C5r7-C1r5 */\ - "paddw $f2, $f2, $f8 \n\t" /* A0+B0 a0+b0 */\ - "mtc1 $10, $f18 \n\t" \ - "paddw $f8, $f8, $f8 \n\t" /* 2A0 2a0 */\ - "psubw $f8, $f8, $f2 \n\t" /* A0-B0 a0-b0 */\ - "psraw $f2, $f2, $f18 \n\t" \ - "psraw $f8, $f8, $f18 \n\t" \ - "mov.d $f4, $f0 \n\t" /* A1 a1 */\ - "paddw $f0, $f0, $f14 \n\t" /* A1+B1 a1+b1 */\ - "psubw $f4, $f4, $f14 \n\t" /* A1-B1 a1-b1 */\ - "psraw $f0, $f0, $f18 \n\t" \ - "psraw $f4, $f4, $f18 \n\t" \ - "packsswh $f2, $f2, $f2 \n\t" /* A0+B0 a0+b0 */\ - "swc1 $f2, " #dst " \n\t" \ - "packsswh $f0, $f0, $f0 \n\t" /* A1+B1 a1+b1 */\ - "swc1 $f0, 16+" #dst " \n\t" \ - "packsswh $f4, $f4, $f4 \n\t" /* A1-B1 a1-b1 */\ - "swc1 $f4, 96+" #dst " \n\t" \ - "packsswh $f8, $f8, $f8 \n\t" /* A0-B0 a0-b0 */\ - "swc1 $f8, 112+" #dst " \n\t" \ - "ldc1 $f2, 88(%2) \n\t" /* C3 C7 C3 C7 */\ - "ldc1 $f16, 104(%2) \n\t" \ - "pmaddhw $f2, $f2, $f6 \n\t" /* C3R7+C7R5 C3r7+C7r5 */\ - "mov.d $f4, $f10 \n\t" /* A2 a2 */\ - "pmaddhw $f6, $f6, $f16 \n\t" /* -C1R7+C3R5 -C1r7+C3r5 */\ - "paddw $f4, $f4, $f2 \n\t" /* A2+B2 a2+b2 */\ - "psubw $f10, $f10, $f2 \n\t" /* a2-B2 a2-b2 */\ - "psraw $f4, $f4, $f18 \n\t" \ - "psraw $f10, $f10, $f18 \n\t" \ - "mov.d $f2, $f12 \n\t" /* A3 a3 */\ - "paddw $f12, $f12, $f6 \n\t" /* A3+B3 a3+b3 */\ - "psubw $f2, $f2, $f6 \n\t" /* a3-B3 a3-b3 */\ - "psraw $f12, $f12, $f18 \n\t" \ - "psraw $f2, $f2, $f18 \n\t" \ - "packsswh $f4, $f4, $f4 \n\t" /* A2+B2 a2+b2 */\ - "packsswh $f12, $f12, $f12 \n\t" /* A3+B3 a3+b3 */\ - "swc1 $f4, 32+" #dst " \n\t" \ - "packsswh $f2, $f2, $f2 \n\t" /* A3-B3 a3-b3 */\ - "packsswh $f10, $f10, $f10 \n\t" /* A2-B2 a2-b2 */\ - "swc1 $f12, 48+" #dst " \n\t" \ - "swc1 $f2, 64+" #dst " \n\t" \ - "swc1 $f10, 80+" #dst " \n\t" + "or $f26, $f2, $f6 \n\t" + "or $f26, $f26, $f10 \n\t" + "or $f26, $f26, $f14 \n\t" + "dmfc1 $10, $f26 \n\t" + "bnez $10, 1f \n\t" + /* case1: In this case, row[1,3,5,7] are all zero */ + /* col0: $f0: col[24,16,8,0]; $f2: col[56,48,40,32] */ + IDCT_COL_CASE1($f0, $f0, $f2) + /* col1: $f4: col[25,17,9,1]; $f6: col[57,49,41,33] */ + IDCT_COL_CASE1($f4, $f4, $f6) + /* col2: $f8: col[26,18,10,2]; $f10: col[58,50,42,34] */ + IDCT_COL_CASE1($f8, $f8, $f10) + /* col3: $f12: col[27,19,11,3]; $f14: col[59,51,43,35] */ + IDCT_COL_CASE1($f12, $f12, $f14) + "j 2f \n\t" - //IDCT( src0, src4, src1, src5, dst, shift) - IDCT( (%1), 64(%1), 32(%1), 96(%1), 0(%0), 20) - IDCT( 8(%1), 72(%1), 40(%1), 104(%1), 4(%0), 20) - IDCT( 16(%1), 80(%1), 48(%1), 112(%1), 8(%0), 20) - IDCT( 24(%1), 88(%1), 56(%1), 120(%1), 12(%0), 20) - "b 9f \n\t" + "1: \n\t" + /* case2: row[1,3,5,7] are not all zero */ + /* Transpose */ + "punpcklhw $f26, $f2, $f6 \n\t" + "punpckhhw $f27, $f2, $f6 \n\t" + "punpcklhw $f28, $f10, $f14 \n\t" + "punpckhhw $f29, $f10, $f14 \n\t" + "punpcklwd $f2, $f26, $f28 \n\t" + "punpckhwd $f6, $f26, $f28 \n\t" + "punpcklwd $f10, $f27, $f29 \n\t" + "punpckhwd $f14, $f27, $f29 \n\t" - "# .p2align 4 \n\t" - "2: \n\t" - Z_COND_IDCT(96(%0),104(%0),112(%0),120(%0), 96(%1),paddw,(%2), 11, 3f) + /* col0: $f0: col[24,16,8,0]; $f2: col[56,48,40,32] */ + IDCT_COL_CASE2($f0, $f2, $f0, $f2) + /* col1: $f4: col[25,17,9,1]; $f6: col[57,49,41,33] */ + IDCT_COL_CASE2($f4, $f6, $f4, $f6) + /* col2: $f8: col[26,18,10,2]; $f10: col[58,50,42,34] */ + IDCT_COL_CASE2($f8, $f10, $f8, $f10) + /* col3: $f12: col[27,19,11,3]; $f14: col[59,51,43,35] */ + IDCT_COL_CASE2($f12, $f14, $f12, $f14) -#undef IDCT -#define IDCT(src0, src4, src1, src5, dst, shift) \ - "ldc1 $f0, " #src0 " \n\t" /* R4 R0 r4 r0 */\ - "ldc1 $f4, " #src1 " \n\t" /* R3 R1 r3 r1 */\ - "ldc1 $f6, " #src5 " \n\t" /* R7 R5 r7 r5 */\ - "ldc1 $f8, 16(%2) \n\t" /* C4 C4 C4 C4 */\ - "pmaddhw $f8, $f8, $f0 \n\t" /* C4R4+C4R0 C4r4+C4r0 */\ - "ldc1 $f10, 24(%2) \n\t" /* -C4 C4 -C4 C4 */\ - "pmaddhw $f0, $f0, $f10 \n\t" /* -C4R4+C4R0 -C4r4+C4r0 */\ - "mov.d $f12, $f8 \n\t" /* C4R4+C4R0 C4r4+C4r0 */\ - "ldc1 $f14, 48(%2) \n\t" /* C3 C1 C3 C1 */\ - "pmaddhw $f14, $f14, $f4 \n\t" /* C3R3+C1R1 C3r3+C1r1 */\ - "mov.d $f10, $f0 \n\t" /* -C4R4+C4R0 -C4r4+C4r0 */\ - "ldc1 $f2, 56(%2) \n\t" /* C7 C5 C7 C5 */\ - "pmaddhw $f2, $f2, $f6 \n\t" /* C7R7+C5R5 C7r7+C5r5 */\ - "ldc1 $f16, 64(%2) \n\t" \ - "pmaddhw $f4, $f4, $f16 \n\t" /* -C7R3+C3R1 -C7r3+C3r1 */\ - "paddw $f14, $f14, $f2 \n\t" /* B0 b0 */\ - "ldc1 $f2, 72(%2) \n\t" /* -C5 -C1 -C5 -C1 */\ - "li $10, " #shift " \n\t" \ - "pmaddhw $f2, $f2, $f6 \n\t" /* -C5R7-C1R5 -C5r7-C1r5 */\ - "paddw $f14, $f14, $f8 \n\t" /* A0+B0 a0+b0 */\ - "mtc1 $10, $f18 \n\t" \ - "paddw $f8, $f8, $f8 \n\t" /* 2A0 2a0 */\ - "psubw $f8, $f8, $f14 \n\t" /* A0-B0 a0-b0 */\ - "paddw $f2, $f2, $f4 \n\t" /* B1 b1 */\ - "psraw $f14, $f14, $f18 \n\t" \ - "psraw $f8, $f8, $f18 \n\t" \ - "mov.d $f4, $f0 \n\t" /* A1 a1 */\ - "paddw $f0, $f0, $f2 \n\t" /* A1+B1 a1+b1 */\ - "psubw $f4, $f4, $f2 \n\t" /* A1-B1 a1-b1 */\ - "psraw $f0, $f0, $f18 \n\t" \ - "psraw $f4, $f4, $f18 \n\t" \ - "packsswh $f14, $f14, $f14 \n\t" /* A0+B0 a0+b0 */\ - "swc1 $f14, " #dst " \n\t" \ - "packsswh $f0, $f0, $f0 \n\t" /* A1+B1 a1+b1 */\ - "swc1 $f0, 16+" #dst " \n\t" \ - "packsswh $f4, $f4, $f4 \n\t" /* A1-B1 a1-b1 */\ - "swc1 $f4, 96+" #dst " \n\t" \ - "packsswh $f8, $f8, $f8 \n\t" /* A0-B0 a0-b0 */\ - "swc1 $f8, 112+" #dst " \n\t" \ - "ldc1 $f0, " #src1 " \n\t" /* R3 R1 r3 r1 */\ - "ldc1 $f8, 80(%2) \n\t" /* -C1 C5 -C1 C5 */\ - "pmaddhw $f8, $f8, $f0 \n\t" /* -C1R3+C5R1 -C1r3+C5r1 */\ - "ldc1 $f14, 88(%2) \n\t" /* C3 C7 C3 C7 */\ - "ldc1 $f16, 96(%2) \n\t" \ - "pmaddhw $f0, $f0, $f16 \n\t" /* -C5R3+C7R1 -C5r3+C7r1 */\ - "pmaddhw $f14, $f14, $f6 \n\t" /* C3R7+C7R5 C3r7+C7r5 */\ - "mov.d $f4, $f10 \n\t" /* A2 a2 */\ - "ldc1 $f16, 104(%2) \n\t" \ - "pmaddhw $f6, $f6, $f16 \n\t" /* -C1R7+C3R5 -C1r7+C3r5 */\ - "paddw $f8, $f8, $f14 \n\t" /* B2 b2 */\ - "paddw $f4, $f4, $f8 \n\t" /* A2+B2 a2+b2 */\ - "psubw $f10, $f10, $f8 \n\t" /* a2-B2 a2-b2 */\ - "psraw $f4, $f4, $f18 \n\t" \ - "psraw $f10, $f10, $f18 \n\t" \ - "mov.d $f8, $f12 \n\t" /* A3 a3 */\ - "paddw $f6, $f6, $f0 \n\t" /* B3 b3 */\ - "paddw $f12, $f12, $f6 \n\t" /* A3+B3 a3+b3 */\ - "psubw $f8, $f8, $f6 \n\t" /* a3-B3 a3-b3 */\ - "psraw $f12, $f12, $f18 \n\t" \ - "psraw $f8, $f8, $f18 \n\t" \ - "packsswh $f4, $f4, $f4 \n\t" /* A2+B2 a2+b2 */\ - "packsswh $f12, $f12, $f12 \n\t" /* A3+B3 a3+b3 */\ - "swc1 $f4, 32+" #dst " \n\t" \ - "packsswh $f8, $f8, $f8 \n\t" /* A3-B3 a3-b3 */\ - "packsswh $f10, $f10, $f10 \n\t" /* A2-B2 a2-b2 */\ - "swc1 $f12, 48+" #dst " \n\t" \ - "swc1 $f8, 64+" #dst " \n\t" \ - "swc1 $f10, 80+" #dst " \n\t" + "2: \n\t" + /* Transpose */ + "punpcklhw $f26, $f0, $f4 \n\t" + "punpckhhw $f27, $f0, $f4 \n\t" + "punpcklhw $f28, $f8, $f12 \n\t" + "punpckhhw $f29, $f8, $f12 \n\t" + "punpcklwd $f0, $f26, $f28 \n\t" + "punpckhwd $f4, $f26, $f28 \n\t" + "punpcklwd $f8, $f27, $f29 \n\t" + "punpckhwd $f12, $f27, $f29 \n\t" + /* Transpose */ + "punpcklhw $f26, $f2, $f6 \n\t" + "punpckhhw $f27, $f2, $f6 \n\t" + "punpcklhw $f28, $f10, $f14 \n\t" + "punpckhhw $f29, $f10, $f14 \n\t" + "punpcklwd $f2, $f26, $f28 \n\t" + "punpckhwd $f6, $f26, $f28 \n\t" + "punpcklwd $f10, $f27, $f29 \n\t" + "punpckhwd $f14, $f27, $f29 \n\t" - //IDCT( src0, src4, src1, src5, dst, shift) - IDCT( (%1), 64(%1), 32(%1), 96(%1), 0(%0), 20) - IDCT( 8(%1), 72(%1), 40(%1), 104(%1), 4(%0), 20) - IDCT( 16(%1), 80(%1), 48(%1), 112(%1), 8(%0), 20) - IDCT( 24(%1), 88(%1), 56(%1), 120(%1), 12(%0), 20) - "b 9f \n\t" + /* idctSparseCol col4~7 */ - "# .p2align 4 \n\t" - "3: \n\t" + "paddh $f1, $f1, $f17 \n\t" + /* Transpose */ + "punpcklhw $f26, $f1, $f5 \n\t" + "punpckhhw $f27, $f1, $f5 \n\t" + "punpcklhw $f28, $f9, $f13 \n\t" + "punpckhhw $f29, $f9, $f13 \n\t" + "punpcklwd $f1, $f26, $f28 \n\t" + "punpckhwd $f5, $f26, $f28 \n\t" + "punpcklwd $f9, $f27, $f29 \n\t" + "punpckhwd $f13, $f27, $f29 \n\t" -#undef IDCT -#define IDCT(src0, src4, src1, src5, dst, shift) \ - "ldc1 $f0, " #src0 " \n\t" /* R4 R0 r4 r0 */\ - "ldc1 $f4, " #src1 " \n\t" /* R3 R1 r3 r1 */\ - "ldc1 $f8, 16(%2) \n\t" /* C4 C4 C4 C4 */\ - "pmaddhw $f8, $f8, $f0 \n\t" /* C4R4+C4R0 C4r4+C4r0 */\ - "ldc1 $f10, 24(%2) \n\t" /* -C4 C4 -C4 C4 */\ - "pmaddhw $f0, $f0, $f10 \n\t" /* -C4R4+C4R0 -C4r4+C4r0 */\ - "mov.d $f12, $f8 \n\t" /* C4R4+C4R0 C4r4+C4r0 */\ - "ldc1 $f14, 48(%2) \n\t" /* C3 C1 C3 C1 */\ - "pmaddhw $f14, $f14, $f4 \n\t" /* C3R3+C1R1 C3r3+C1r1 */\ - "mov.d $f10, $f0 \n\t" /* -C4R4+C4R0 -C4r4+C4r0 */\ - "ldc1 $f6, 64(%2) \n\t" \ - "pmaddhw $f6, $f6, $f4 \n\t" /* -C7R3+C3R1 -C7r3+C3r1 */\ - "li $10, " #shift " \n\t" \ - "paddw $f14, $f14, $f8 \n\t" /* A0+B0 a0+b0 */\ - "mtc1 $10, $f18 \n\t" \ - "paddw $f8, $f8, $f8 \n\t" /* 2A0 2a0 */\ - "psubw $f8, $f8, $f14 \n\t" /* A0-B0 a0-b0 */\ - "psraw $f14, $f14, $f18 \n\t" \ - "psraw $f8, $f8, $f18 \n\t" \ - "mov.d $f2, $f0 \n\t" /* A1 a1 */\ - "paddw $f0, $f0, $f6 \n\t" /* A1+B1 a1+b1 */\ - "psubw $f2, $f2, $f6 \n\t" /* A1-B1 a1-b1 */\ - "psraw $f0, $f0, $f18 \n\t" \ - "psraw $f2, $f2, $f18 \n\t" \ - "packsswh $f14, $f14, $f14 \n\t" /* A0+B0 a0+b0 */\ - "swc1 $f14, " #dst " \n\t" \ - "packsswh $f0, $f0, $f0 \n\t" /* A1+B1 a1+b1 */\ - "swc1 $f0, 16+" #dst " \n\t" \ - "packsswh $f2, $f2, $f2 \n\t" /* A1-B1 a1-b1 */\ - "swc1 $f2, 96+" #dst " \n\t" \ - "packsswh $f8, $f8, $f8 \n\t" /* A0-B0 a0-b0 */\ - "swc1 $f8, 112+" #dst " \n\t" \ - "ldc1 $f8, 80(%2) \n\t" /* -C1 C5 -C1 C5 */\ - "ldc1 $f16, 96(%2) \n\t" \ - "pmaddhw $f8, $f8, $f4 \n\t" /* -C1R3+C5R1 -C1r3+C5r1 */\ - "pmaddhw $f4, $f4, $f16 \n\t" /* -C5R3+C7R1 -C5r3+C7r1 */\ - "mov.d $f2, $f10 \n\t" /* A2 a2 */\ - "paddw $f2, $f2, $f8 \n\t" /* A2+B2 a2+b2 */\ - "psubw $f10, $f10, $f8 \n\t" /* a2-B2 a2-b2 */\ - "psraw $f2, $f2, $f18 \n\t" \ - "psraw $f10, $f10, $f18 \n\t" \ - "mov.d $f8, $f12 \n\t" /* A3 a3 */\ - "paddw $f12, $f12, $f4 \n\t" /* A3+B3 a3+b3 */\ - "psubw $f8, $f8, $f4 \n\t" /* a3-B3 a3-b3 */\ - "psraw $f12, $f12, $f18 \n\t" \ - "psraw $f8, $f8, $f18 \n\t" \ - "packsswh $f2, $f2, $f2 \n\t" /* A2+B2 a2+b2 */\ - "packsswh $f12, $f12, $f12 \n\t" /* A3+B3 a3+b3 */\ - "swc1 $f2, 32+" #dst " \n\t" \ - "packsswh $f8, $f8, $f8 \n\t" /* A3-B3 a3-b3 */\ - "packsswh $f10, $f10, $f10 \n\t" /* A2-B2 a2-b2 */\ - "swc1 $f12, 48+" #dst " \n\t" \ - "swc1 $f8, 64+" #dst " \n\t" \ - "swc1 $f10, 80+" #dst " \n\t" + "or $f26, $f3, $f7 \n\t" + "or $f26, $f26, $f11 \n\t" + "or $f26, $f26, $f15 \n\t" + "dmfc1 $10, $f26 \n\t" + "bnez $10, 1f \n\t" + /* case1: In this case, row[1,3,5,7] are all zero */ + /* col4: $f1: col[24,16,8,0]; $f3: col[56,48,40,32] */ + IDCT_COL_CASE1($f1, $f1, $f3) + /* col5: $f5: col[25,17,9,1]; $f7: col[57,49,41,33] */ + IDCT_COL_CASE1($f5, $f5, $f7) + /* col6: $f9: col[26,18,10,2]; $f11: col[58,50,42,34] */ + IDCT_COL_CASE1($f9, $f9, $f11) + /* col7: $f13: col[27,19,11,3]; $f15: col[59,51,43,35] */ + IDCT_COL_CASE1($f13, $f13, $f15) + "j 2f \n\t" - //IDCT( src0, src4, src1, src5, dst, shift) - IDCT( (%1), 64(%1), 32(%1), 96(%1), 0(%0), 20) - IDCT( 8(%1), 72(%1), 40(%1), 104(%1), 4(%0), 20) - IDCT( 16(%1), 80(%1), 48(%1), 112(%1), 8(%0), 20) - IDCT( 24(%1), 88(%1), 56(%1), 120(%1), 12(%0), 20) - "b 9f \n\t" + "1: \n\t" + /* case2: row[1,3,5,7] are not all zero */ + /* Transpose */ + "punpcklhw $f26, $f3, $f7 \n\t" + "punpckhhw $f27, $f3, $f7 \n\t" + "punpcklhw $f28, $f11, $f15 \n\t" + "punpckhhw $f29, $f11, $f15 \n\t" + "punpcklwd $f3, $f26, $f28 \n\t" + "punpckhwd $f7, $f26, $f28 \n\t" + "punpcklwd $f11, $f27, $f29 \n\t" + "punpckhwd $f15, $f27, $f29 \n\t" - "# .p2align 4 \n\t" - "5: \n\t" + /* col4: $f1: col[24,16,8,0]; $f3: col[56,48,40,32] */ + IDCT_COL_CASE2($f1, $f3, $f1, $f3) + /* col5: $f5: col[25,17,9,1]; $f7: col[57,49,41,33] */ + IDCT_COL_CASE2($f5, $f7, $f5, $f7) + /* col6: $f9: col[26,18,10,2]; $f11: col[58,50,42,34] */ + IDCT_COL_CASE2($f9, $f11, $f9, $f11) + /* col7: $f13: col[27,19,11,3]; $f15: col[59,51,43,35] */ + IDCT_COL_CASE2($f13, $f15, $f13, $f15) -#undef IDCT -#define IDCT(src0, src4, src1, src5, dst, shift) \ - "ldc1 $f0, " #src0 " \n\t" /* R4 R0 r4 r0 */\ - "ldc1 $f2, " #src4 " \n\t" /* R6 R2 r6 r2 */\ - "ldc1 $f8, 16(%2) \n\t" /* C4 C4 C4 C4 */\ - "pmaddhw $f8, $f8, $f0 \n\t" /* C4R4+C4R0 C4r4+C4r0 */\ - "ldc1 $f10, 24(%2) \n\t" /* -C4 C4 -C4 C4 */\ - "pmaddhw $f0, $f0, $f10 \n\t" /* -C4R4+C4R0 -C4r4+C4r0 */\ - "ldc1 $f10, 32(%2) \n\t" /* C6 C2 C6 C2 */\ - "pmaddhw $f10, $f10, $f2 \n\t" /* C6R6+C2R2 C6r6+C2r2 */\ - "ldc1 $f12, 40(%2) \n\t" /* -C2 C6 -C2 C6 */\ - "pmaddhw $f2, $f2, $f12 \n\t" /* -C2R6+C6R2 -C2r6+C6r2 */\ - "mov.d $f12, $f8 \n\t" /* C4R4+C4R0 C4r4+C4r0 */\ - "paddw $f8, $f8, $f10 \n\t" /* A0 a0 */\ - "psubw $f12, $f12, $f10 \n\t" /* A3 a3 */\ - "mov.d $f10, $f0 \n\t" /* -C4R4+C4R0 -C4r4+C4r0 */\ - "paddw $f0, $f0, $f2 \n\t" /* A1 a1 */\ - "psubw $f10, $f10, $f2 \n\t" /* A2 a2 */\ - "ldc1 $f4, 8+" #src0 " \n\t" /* R4 R0 r4 r0 */\ - "ldc1 $f6, 8+" #src4 " \n\t" /* R6 R2 r6 r2 */\ - "ldc1 $f2, 16(%2) \n\t" /* C4 C4 C4 C4 */\ - "pmaddhw $f2, $f2, $f4 \n\t" /* C4R4+C4R0 C4r4+C4r0 */\ - "ldc1 $f14, 24(%2) \n\t" /* -C4 C4 -C4 C4 */\ - "pmaddhw $f4, $f4, $f14 \n\t" /* -C4R4+C4R0 -C4r4+C4r0 */\ - "ldc1 $f14, 32(%2) \n\t" /* C6 C2 C6 C2 */\ - "ldc1 $f16, 40(%2) \n\t" \ - "pmaddhw $f14, $f14, $f6 \n\t" /* C6R6+C2R2 C6r6+C2r2 */\ - "pmaddhw $f6, $f6, $f16 \n\t" /* -C2R6+C6R2 -C2r6+C6r2 */\ - "paddw $f14, $f14, $f2 \n\t" /* A0 a0 */\ - "paddw $f2, $f2, $f2 \n\t" /* 2C0 2c0 */\ - "psubw $f2, $f2, $f14 \n\t" /* A3 a3 */\ - "li $10, " #shift " \n\t" \ - "paddw $f6, $f6, $f4 \n\t" /* A1 a1 */\ - "mtc1 $10, $f18 \n\t" \ - "paddw $f4, $f4, $f4 \n\t" /* 2C1 2c1 */\ - "psubw $f4, $f4, $f6 \n\t" /* A2 a2 */\ - "psraw $f8, $f8, $f18 \n\t" \ - "psraw $f14, $f14, $f18 \n\t" \ - "psraw $f6, $f6, $f18 \n\t" \ - "packsswh $f8, $f8, $f14 \n\t" /* A0 a0 */\ - "sdc1 $f8, " #dst " \n\t" \ - "psraw $f0, $f0, $f18 \n\t" \ - "packsswh $f0, $f0, $f6 \n\t" /* A1 a1 */\ - "sdc1 $f0, 16+" #dst " \n\t" \ - "sdc1 $f0, 96+" #dst " \n\t" \ - "sdc1 $f8, 112+" #dst " \n\t" \ - "psraw $f10, $f10, $f18 \n\t" \ - "psraw $f12, $f12, $f18 \n\t" \ - "psraw $f4, $f4, $f18 \n\t" \ - "packsswh $f10, $f10, $f4 \n\t" /* A2-B2 a2-b2 */\ - "sdc1 $f10, 32+" #dst " \n\t" \ - "psraw $f2, $f2, $f18 \n\t" \ - "packsswh $f12, $f12, $f2 \n\t" /* A3+B3 a3+b3 */\ - "sdc1 $f12, 48+" #dst " \n\t" \ - "sdc1 $f12, 64+" #dst " \n\t" \ - "sdc1 $f10, 80+" #dst " \n\t" + "2: \n\t" + /* Transpose */ + "punpcklhw $f26, $f1, $f5 \n\t" + "punpckhhw $f27, $f1, $f5 \n\t" + "punpcklhw $f28, $f9, $f13 \n\t" + "punpckhhw $f29, $f9, $f13 \n\t" + "punpcklwd $f1, $f26, $f28 \n\t" + "punpckhwd $f5, $f26, $f28 \n\t" + "punpcklwd $f9, $f27, $f29 \n\t" + "punpckhwd $f13, $f27, $f29 \n\t" + /* Transpose */ + "punpcklhw $f26, $f3, $f7 \n\t" + "punpckhhw $f27, $f3, $f7 \n\t" + "punpcklhw $f28, $f11, $f15 \n\t" + "punpckhhw $f29, $f11, $f15 \n\t" + "punpcklwd $f3, $f26, $f28 \n\t" + "punpckhwd $f7, $f26, $f28 \n\t" + "punpcklwd $f11, $f27, $f29 \n\t" + "punpckhwd $f15, $f27, $f29 \n\t" + /* Store */ + "gssqc1 $f1, $f0, 0x00(%[block]) \n\t" + "gssqc1 $f5, $f4, 0x10(%[block]) \n\t" + "gssqc1 $f9, $f8, 0x20(%[block]) \n\t" + "gssqc1 $f13, $f12, 0x30(%[block]) \n\t" + "gssqc1 $f3, $f2, 0x40(%[block]) \n\t" + "gssqc1 $f7, $f6, 0x50(%[block]) \n\t" + "gssqc1 $f11, $f10, 0x60(%[block]) \n\t" + "gssqc1 $f15, $f14, 0x70(%[block]) \n\t" - //IDCT( src0, src4, src1, src5, dst, shift) - IDCT( 0(%1), 64(%1), 32(%1), 96(%1), 0(%0), 20) - IDCT( 16(%1), 80(%1), 48(%1), 112(%1), 8(%0), 20) - "b 9f \n\t" - - "# .p2align 4 \n\t" - "1: \n\t" - -#undef IDCT -#define IDCT(src0, src4, src1, src5, dst, shift) \ - "ldc1 $f0, " #src0 " \n\t" /* R4 R0 r4 r0 */\ - "ldc1 $f2, " #src4 " \n\t" /* R6 R2 r6 r2 */\ - "ldc1 $f4, " #src1 " \n\t" /* R3 R1 r3 r1 */\ - "ldc1 $f8, 16(%2) \n\t" /* C4 C4 C4 C4 */\ - "li $10, " #shift " \n\t" \ - "pmaddhw $f8, $f8, $f0 \n\t" /* C4R4+C4R0 C4r4+C4r0 */\ - "ldc1 $f10, 24(%2) \n\t" /* -C4 C4 -C4 C4 */\ - "mtc1 $10, $f18 \n\t" \ - "pmaddhw $f0, $f0, $f10 \n\t" /* -C4R4+C4R0 -C4r4+C4r0 */\ - "ldc1 $f10, 32(%2) \n\t" /* C6 C2 C6 C2 */\ - "pmaddhw $f10, $f10, $f2 \n\t" /* C6R6+C2R2 C6r6+C2r2 */\ - "ldc1 $f12, 40(%2) \n\t" /* -C2 C6 -C2 C6 */\ - "pmaddhw $f2, $f2, $f12 \n\t" /* -C2R6+C6R2 -C2r6+C6r2 */\ - "mov.d $f12, $f8 \n\t" /* C4R4+C4R0 C4r4+C4r0 */\ - "ldc1 $f14, 48(%2) \n\t" /* C3 C1 C3 C1 */\ - "pmaddhw $f14, $f14, $f4 \n\t" /* C3R3+C1R1 C3r3+C1r1 */\ - "paddw $f8, $f8, $f10 \n\t" /* A0 a0 */\ - "psubw $f12, $f12, $f10 \n\t" /* A3 a3 */\ - "mov.d $f10, $f0 \n\t" /* -C4R4+C4R0 -C4r4+C4r0 */\ - "paddw $f0, $f0, $f2 \n\t" /* A1 a1 */\ - "psubw $f10, $f10, $f2 \n\t" /* A2 a2 */\ - "ldc1 $f2, 64(%2) \n\t" \ - "pmaddhw $f2, $f2, $f4 \n\t" /* -C7R3+C3R1 -C7r3+C3r1 */\ - "paddw $f14, $f14, $f8 \n\t" /* A0+B0 a0+b0 */\ - "paddw $f8, $f8, $f8 \n\t" /* 2A0 2a0 */\ - "psubw $f8, $f8, $f14 \n\t" /* A0-B0 a0-b0 */\ - "psraw $f14, $f14, $f18 \n\t" \ - "psraw $f8, $f8, $f18 \n\t" \ - "mov.d $f6, $f0 \n\t" /* A1 a1 */\ - "paddw $f0, $f0, $f2 \n\t" /* A1+B1 a1+b1 */\ - "psubw $f6, $f6, $f2 \n\t" /* A1-B1 a1-b1 */\ - "psraw $f0, $f0, $f18 \n\t" \ - "psraw $f6, $f6, $f18 \n\t" \ - "packsswh $f14, $f14, $f14 \n\t" /* A0+B0 a0+b0 */\ - "swc1 $f14, " #dst " \n\t" \ - "packsswh $f0, $f0, $f0 \n\t" /* A1+B1 a1+b1 */\ - "swc1 $f0, 16+" #dst " \n\t" \ - "packsswh $f6, $f6, $f6 \n\t" /* A1-B1 a1-b1 */\ - "swc1 $f6, 96+" #dst " \n\t" \ - "packsswh $f8, $f8, $f8 \n\t" /* A0-B0 a0-b0 */\ - "swc1 $f8, 112+" #dst " \n\t" \ - "ldc1 $f8, 80(%2) \n\t" /* -C1 C5 -C1 C5 */\ - "ldc1 $f16, 96(%2) \n\t" \ - "pmaddhw $f8, $f8, $f4 \n\t" /* -C1R3+C5R1 -C1r3+C5r1 */\ - "pmaddhw $f4, $f4, $f16 \n\t" /* -C5R3+C7R1 -C5r3+C7r1 */\ - "mov.d $f6, $f10 \n\t" /* A2 a2 */\ - "paddw $f6, $f6, $f8 \n\t" /* A2+B2 a2+b2 */\ - "psubw $f10, $f10, $f8 \n\t" /* a2-B2 a2-b2 */\ - "psraw $f6, $f6, $f18 \n\t" \ - "psraw $f10, $f10, $f18 \n\t" \ - "mov.d $f8, $f12 \n\t" /* A3 a3 */\ - "paddw $f12, $f12, $f4 \n\t" /* A3+B3 a3+b3 */\ - "psubw $f8, $f8, $f4 \n\t" /* a3-B3 a3-b3 */\ - "psraw $f12, $f12, $f18 \n\t" \ - "packsswh $f6, $f6, $f6 \n\t" /* A2+B2 a2+b2 */\ - "swc1 $f6, 32+" #dst " \n\t" \ - "psraw $f8, $f8, $f18 \n\t" \ - "packsswh $f12, $f12, $f12 \n\t" /* A3+B3 a3+b3 */\ - "swc1 $f12, 48+" #dst " \n\t" \ - "packsswh $f8, $f8, $f8 \n\t" /* A3-B3 a3-b3 */\ - "packsswh $f10, $f10, $f10 \n\t" /* A2-B2 a2-b2 */\ - "swc1 $f8, 64+" #dst " \n\t" \ - "swc1 $f10, 80+" #dst " \n\t" - - //IDCT( src0, src4, src1, src5, dst, shift) - IDCT( (%1), 64(%1), 32(%1), 96(%1), 0(%0), 20) - IDCT( 8(%1), 72(%1), 40(%1), 104(%1), 4(%0), 20) - IDCT( 16(%1), 80(%1), 48(%1), 112(%1), 8(%0), 20) - IDCT( 24(%1), 88(%1), 56(%1), 120(%1), 12(%0), 20) - "b 9f \n\t" - - "# .p2align 4 \n\t" - "7: \n\t" - -#undef IDCT -#define IDCT(src0, src4, src1, src5, dst, shift) \ - "ldc1 $f0, " #src0 " \n\t" /* R4 R0 r4 r0 */\ - "ldc1 $f8, 16(%2) \n\t" /* C4 C4 C4 C4 */\ - "li $10, " #shift " \n\t" \ - "pmaddhw $f8, $f8, $f0 \n\t" /* C4R4+C4R0 C4r4+C4r0 */\ - "mtc1 $10, $f18 \n\t" \ - "ldc1 $f10, 24(%2) \n\t" /* -C4 C4 -C4 C4 */\ - "pmaddhw $f0, $f0, $f10 \n\t" /* -C4R4+C4R0 -C4r4+C4r0 */\ - "psraw $f8, $f8, $f18 \n\t" \ - "psraw $f0, $f0, $f18 \n\t" \ - "ldc1 $f4, 8+" #src0 " \n\t" /* R4 R0 r4 r0 */\ - "ldc1 $f2, 16(%2) \n\t" /* C4 C4 C4 C4 */\ - "pmaddhw $f2, $f2, $f4 \n\t" /* C4R4+C4R0 C4r4+C4r0 */\ - "ldc1 $f14, 24(%2) \n\t" /* -C4 C4 -C4 C4 */\ - "pmaddhw $f4, $f4, $f14 \n\t" /* -C4R4+C4R0 -C4r4+C4r0 */\ - "ldc1 $f14, 32(%2) \n\t" /* C6 C2 C6 C2 */\ - "psraw $f2, $f2, $f18 \n\t" \ - "packsswh $f8, $f8, $f2 \n\t" /* A0 a0 */\ - "sdc1 $f8, " #dst " \n\t" \ - "psraw $f4, $f4, $f18 \n\t" \ - "packsswh $f0, $f0, $f4 \n\t" /* A1 a1 */\ - "sdc1 $f0, 16+" #dst " \n\t" \ - "sdc1 $f0, 96+" #dst " \n\t" \ - "sdc1 $f8, 112+" #dst " \n\t" \ - "sdc1 $f0, 32+" #dst " \n\t" \ - "sdc1 $f8, 48+" #dst " \n\t" \ - "sdc1 $f8, 64+" #dst " \n\t" \ - "sdc1 $f0, 80+" #dst " \n\t" - - //IDCT( src0, src4, src1, src5, dst, shift) - IDCT( 0(%1), 64(%1), 32(%1), 96(%1), 0(%0), 20) - IDCT( 16(%1), 80(%1), 48(%1), 112(%1), 8(%0), 20) - - "9: \n\t" - ::"r"(block),"r"(temp),"r"(coeffs),"m"(ff_wm1010),"m"(ff_d40000) - : "$10","$11" + : [block]"+&r"(block) + : [w_arr]"r"(W_arr) + : "memory" ); + + RECOVER_REG +} + +void ff_simple_idct_put_8_mmi(uint8_t *dest, ptrdiff_t line_size, int16_t *block) +{ + ff_simple_idct_8_mmi(block); + ff_put_pixels_clamped_mmi(block, dest, line_size); +} +void ff_simple_idct_add_8_mmi(uint8_t *dest, ptrdiff_t line_size, int16_t *block) +{ + ff_simple_idct_8_mmi(block); + ff_add_pixels_clamped_mmi(block, dest, line_size); } diff --git a/libavcodec/mips/vc1dsp_mips.h b/libavcodec/mips/vc1dsp_mips.h index b9b07e1ce..0db85fac9 100644 --- a/libavcodec/mips/vc1dsp_mips.h +++ b/libavcodec/mips/vc1dsp_mips.h @@ -169,7 +169,7 @@ void ff_vc1_inv_trans_8x8_dc_mmi(uint8_t *dest, ptrdiff_t linesize, int16_t *blo void ff_vc1_v_overlap_mmi(uint8_t *src, int stride); void ff_vc1_h_overlap_mmi(uint8_t *src, int stride); void ff_vc1_v_s_overlap_mmi(int16_t *top, int16_t *bottom); -void ff_vc1_h_s_overlap_mmi(int16_t *left, int16_t *right); +void ff_vc1_h_s_overlap_mmi(int16_t *left, int16_t *right, int left_stride, int right_stride, int flags); void ff_vc1_v_loop_filter4_mmi(uint8_t *src, int stride, int pq); void ff_vc1_h_loop_filter4_mmi(uint8_t *src, int stride, int pq); diff --git a/libavcodec/mips/vc1dsp_mmi.c b/libavcodec/mips/vc1dsp_mmi.c index 01e7f9f32..db314de49 100644 --- a/libavcodec/mips/vc1dsp_mmi.c +++ b/libavcodec/mips/vc1dsp_mmi.c @@ -27,118 +27,97 @@ #include "hpeldsp_mips.h" #include "libavutil/mips/mmiutils.h" +#define VC1_INV_TRANCS_8_TYPE1(o1, o2, r1, r2, r3, r4, c0) \ + "li %[tmp0], "#r1" \n\t" \ + "mtc1 %[tmp0], %[ftmp13] \n\t" \ + "punpcklwd %[ftmp13], %[ftmp13], %[ftmp13] \n\t" \ + "li %[tmp0], "#r2" \n\t" \ + "mtc1 %[tmp0], %[ftmp14] \n\t" \ + "punpcklwd %[ftmp14], %[ftmp14], %[ftmp14] \n\t" \ + "pmaddhw %[ftmp1], %[ftmp5], %[ftmp13] \n\t" \ + "pmaddhw %[ftmp2], %[ftmp7], %[ftmp14] \n\t" \ + "paddw %[ftmp1], %[ftmp1], %[ftmp2] \n\t" \ + "pmaddhw %[ftmp2], %[ftmp6], %[ftmp13] \n\t" \ + "pmaddhw %[ftmp3], %[ftmp8], %[ftmp14] \n\t" \ + "paddw %[ftmp2], %[ftmp2], %[ftmp3] \n\t" \ + \ + "li %[tmp0], "#r3" \n\t" \ + "mtc1 %[tmp0], %[ftmp13] \n\t" \ + "punpcklwd %[ftmp13], %[ftmp13], %[ftmp13] \n\t" \ + "li %[tmp0], "#r4" \n\t" \ + "mtc1 %[tmp0], %[ftmp14] \n\t" \ + "punpcklwd %[ftmp14], %[ftmp14], %[ftmp14] \n\t" \ + "pmaddhw %[ftmp3], %[ftmp9], %[ftmp13] \n\t" \ + "pmaddhw %[ftmp4], %[ftmp11], %[ftmp14] \n\t" \ + "paddw %[ftmp3], %[ftmp3], %[ftmp4] \n\t" \ + "pmaddhw %[ftmp4], %[ftmp10], %[ftmp13] \n\t" \ + "pmaddhw %[ftmp13], %[ftmp12], %[ftmp14] \n\t" \ + "paddw %[ftmp4], %[ftmp4], %[ftmp13] \n\t" \ + \ + "paddw %[ftmp1], %[ftmp1], "#c0" \n\t" \ + "paddw %[ftmp2], %[ftmp2], "#c0" \n\t" \ + "paddw %[ftmp13], %[ftmp1], %[ftmp3] \n\t" \ + "psubw %[ftmp14], %[ftmp1], %[ftmp3] \n\t" \ + "paddw %[ftmp1], %[ftmp2], %[ftmp4] \n\t" \ + "psubw %[ftmp3], %[ftmp2], %[ftmp4] \n\t" \ + "psraw %[ftmp13], %[ftmp13], %[ftmp0] \n\t" \ + "psraw %[ftmp1], %[ftmp1], %[ftmp0] \n\t" \ + "psraw %[ftmp14], %[ftmp14], %[ftmp0] \n\t" \ + "psraw %[ftmp3], %[ftmp3], %[ftmp0] \n\t" \ + "punpcklhw %[ftmp2], %[ftmp13], %[ftmp1] \n\t" \ + "punpckhhw %[ftmp4], %[ftmp13], %[ftmp1] \n\t" \ + "punpcklhw "#o1", %[ftmp2], %[ftmp4] \n\t" \ + "punpcklhw %[ftmp2], %[ftmp14], %[ftmp3] \n\t" \ + "punpckhhw %[ftmp4], %[ftmp14], %[ftmp3] \n\t" \ + "punpcklhw "#o2", %[ftmp2], %[ftmp4] \n\t" -#define VC1_INV_TRANCS_8_STEP1_MMI(fp1, fp2, fp3, fp4, \ - o1, o2, o3, o4, \ - t1, t2, t3, t4, \ - ff_p1, ff_p2, ff_p3, ff_p4) \ - "pmullh "#t1" , "#fp1" , "#ff_p1" \n\t" \ - "pmullh "#t2" , "#fp2" , "#ff_p2" \n\t" \ - "pmullh "#t3" , "#fp3" , "#ff_p3" \n\t" \ - "pmullh "#t4" , "#fp4" , "#ff_p4" \n\t" \ - "paddh "#o1" , "#t1" , "#t2" \n\t" \ - "paddh "#o1" , "#o1" , "#t3" \n\t" \ - "paddh "#o1" , "#o1" , "#t4" \n\t" \ +#define VC1_INV_TRANCS_8_TYPE2(o1, o2, r1, r2, r3, r4, c0, c1) \ + "li %[tmp0], "#r1" \n\t" \ + "mtc1 %[tmp0], %[ftmp13] \n\t" \ + "punpcklwd %[ftmp13], %[ftmp13], %[ftmp13] \n\t" \ + "li %[tmp0], "#r2" \n\t" \ + "mtc1 %[tmp0], %[ftmp14] \n\t" \ + "punpcklwd %[ftmp14], %[ftmp14], %[ftmp14] \n\t" \ + "pmaddhw %[ftmp1], %[ftmp5], %[ftmp13] \n\t" \ + "pmaddhw %[ftmp2], %[ftmp7], %[ftmp14] \n\t" \ + "paddw %[ftmp1], %[ftmp1], %[ftmp2] \n\t" \ + "pmaddhw %[ftmp2], %[ftmp6], %[ftmp13] \n\t" \ + "pmaddhw %[ftmp3], %[ftmp8], %[ftmp14] \n\t" \ + "paddw %[ftmp2], %[ftmp2], %[ftmp3] \n\t" \ \ - "pmullh "#t1" , "#fp1" , "#ff_p2" \n\t" \ - "pmullh "#t2" , "#fp2" , "#ff_p4" \n\t" \ - "pmullh "#t3" , "#fp3" , "#ff_p1" \n\t" \ - "pmullh "#t4" , "#fp4" , "#ff_p3" \n\t" \ - "psubh "#o2" , "#t1" , "#t2" \n\t" \ - "psubh "#o2" , "#o2" , "#t3" \n\t" \ - "psubh "#o2" , "#o2" , "#t4" \n\t" \ + "li %[tmp0], "#r3" \n\t" \ + "mtc1 %[tmp0], %[ftmp13] \n\t" \ + "punpcklwd %[ftmp13], %[ftmp13], %[ftmp13] \n\t" \ + "li %[tmp0], "#r4" \n\t" \ + "mtc1 %[tmp0], %[ftmp14] \n\t" \ + "punpcklwd %[ftmp14], %[ftmp14], %[ftmp14] \n\t" \ + "pmaddhw %[ftmp3], %[ftmp9], %[ftmp13] \n\t" \ + "pmaddhw %[ftmp4], %[ftmp11], %[ftmp14] \n\t" \ + "paddw %[ftmp3], %[ftmp3], %[ftmp4] \n\t" \ + "pmaddhw %[ftmp4], %[ftmp10], %[ftmp13] \n\t" \ + "pmaddhw %[ftmp13], %[ftmp12], %[ftmp14] \n\t" \ + "paddw %[ftmp4], %[ftmp4], %[ftmp13] \n\t" \ \ - "pmullh "#t1" , "#fp1" , "#ff_p3" \n\t" \ - "pmullh "#t2" , "#fp2" , "#ff_p1" \n\t" \ - "pmullh "#t3" , "#fp3" , "#ff_p4" \n\t" \ - "pmullh "#t4" , "#fp4" , "#ff_p2" \n\t" \ - "psubh "#o3" , "#t1" , "#t2" \n\t" \ - "paddh "#o3" , "#o3" , "#t3" \n\t" \ - "paddh "#o3" , "#o3" , "#t4" \n\t" \ - \ - "pmullh "#t1" , "#fp1" , "#ff_p4" \n\t" \ - "pmullh "#t2" , "#fp2" , "#ff_p3" \n\t" \ - "pmullh "#t3" , "#fp3" , "#ff_p2" \n\t" \ - "pmullh "#t4" , "#fp4" , "#ff_p1" \n\t" \ - "psubh "#o4" , "#t1" , "#t2" \n\t" \ - "paddh "#o4" , "#o4" , "#t3" \n\t" \ - "psubh "#o4" , "#o4" , "#t4" \n\t" - - -#define VC1_INV_TRANCS_8_STEP2_MMI(fp1, fp2, fp3, fp4, \ - fp5, fp6, fp7, fp8, \ - o1, o2, o3, o4, \ - ff_p1, ff_p2, ff_p3, ff_pw) \ - "paddh "#fp5" , "#fp1" , "#fp2" \n\t" \ - "psubh "#fp6" , "#fp1" , "#fp2" \n\t" \ - "pmullh "#fp5" , "#fp5" , "#ff_p1" \n\t" \ - "pmullh "#fp6" , "#fp6" , "#ff_p1" \n\t" \ - "paddh "#fp5" , "#fp5" , "#ff_pw" \n\t" \ - "paddh "#fp6" , "#fp6" , "#ff_pw" \n\t" \ - \ - "pmullh "#fp1" , "#fp3" , "#ff_p2" \n\t" \ - "pmullh "#fp2" , "#fp4" , "#ff_p3" \n\t" \ - "pmullh "#fp3" , "#fp3" , "#ff_p3" \n\t" \ - "pmullh "#fp4" , "#fp4" , "#ff_p2" \n\t" \ - "paddh "#fp7" , "#fp1" , "#fp2" \n\t" \ - "psubh "#fp8" , "#fp3" , "#fp4" \n\t" \ - \ - "paddh "#fp1" , "#fp5" , "#fp7" \n\t" \ - "paddh "#fp2" , "#fp6" , "#fp8" \n\t" \ - "psubh "#fp3" , "#fp6" , "#fp8" \n\t" \ - "psubh "#fp4" , "#fp5" , "#fp7" \n\t" \ - \ - "paddh "#fp5" , "#fp1" , "#o1" \n\t" \ - "paddh "#fp6" , "#fp2" , "#o2" \n\t" \ - "paddh "#fp7" , "#fp3" , "#o3" \n\t" \ - "paddh "#fp8" , "#fp4" , "#o4" \n\t" \ - \ - "psubh "#fp4" , "#fp4" , "#o4" \n\t" \ - "psubh "#fp3" , "#fp3" , "#o3" \n\t" \ - "psubh "#fp2" , "#fp2" , "#o2" \n\t" \ - "psubh "#fp1" , "#fp1" , "#o1" \n\t" - - -#define VC1_INV_TRANCS_4_STEP1_MMI(fp1, fp2, fp3, fp4, \ - fp5, fp6, fp7, fp8, \ - ff_p1, ff_p2, ff_p3, ff_pw) \ - "paddh "#fp5" , "#fp1" , "#fp2" \n\t" \ - "psubh "#fp6" , "#fp1" , "#fp2" \n\t" \ - "pmullh "#fp5" , "#fp5" , "#ff_p1" \n\t" \ - "pmullh "#fp6" , "#fp6" , "#ff_p1" \n\t" \ - "paddh "#fp5" , "#fp5" , "#ff_pw" \n\t" \ - "paddh "#fp6" , "#fp6" , "#ff_pw" \n\t" \ - \ - "pmullh "#fp1" , "#fp3" , "#ff_p2" \n\t" \ - "pmullh "#fp2" , "#fp4" , "#ff_p3" \n\t" \ - "pmullh "#fp3" , "#fp3" , "#ff_p3" \n\t" \ - "pmullh "#fp4" , "#fp4" , "#ff_p2" \n\t" \ - "paddh "#fp7" , "#fp1" , "#fp2" \n\t" \ - "psubh "#fp8" , "#fp3" , "#fp4" \n\t" \ - \ - "paddh "#fp1" , "#fp5" , "#fp7" \n\t" \ - "psubh "#fp2" , "#fp6" , "#fp8" \n\t" \ - "paddh "#fp3" , "#fp6" , "#fp8" \n\t" \ - "psubh "#fp4" , "#fp5" , "#fp7" \n\t" - - -#define VC1_INV_TRANCS_4_STEP2_MMI(fp1, fp2, fp3, fp4, \ - fp5, fp6, fp7, fp8, zero) \ - "punpcklbh "#fp5" , "#fp5" , "#zero" \n\t" \ - "punpcklbh "#fp6" , "#fp6" , "#zero" \n\t" \ - "punpcklbh "#fp7" , "#fp7" , "#zero" \n\t" \ - "punpcklbh "#fp8" , "#fp8" , "#zero" \n\t" \ - \ - "paddh "#fp1" , "#fp1" , "#fp5" \n\t" \ - "paddh "#fp2" , "#fp2" , "#fp6" \n\t" \ - "paddh "#fp3" , "#fp3" , "#fp7" \n\t" \ - "paddh "#fp4" , "#fp4" , "#fp8" \n\t" \ - \ - "packushb "#fp1" , "#fp1" , "#zero" \n\t" \ - "packushb "#fp2" , "#fp2" , "#zero" \n\t" \ - "packushb "#fp3" , "#fp3" , "#zero" \n\t" \ - "packushb "#fp4" , "#fp4" , "#zero" \n\t" - + "paddw %[ftmp13], %[ftmp1], %[ftmp3] \n\t" \ + "psubw %[ftmp14], %[ftmp1], %[ftmp3] \n\t" \ + "paddw %[ftmp14], %[ftmp14], "#c1" \n\t" \ + "paddw %[ftmp1], %[ftmp2], %[ftmp4] \n\t" \ + "psubw %[ftmp3], %[ftmp2], %[ftmp4] \n\t" \ + "paddw %[ftmp3], %[ftmp3], "#c1" \n\t" \ + "paddw %[ftmp13], %[ftmp13], "#c0" \n\t" \ + "paddw %[ftmp14], %[ftmp14], "#c0" \n\t" \ + "paddw %[ftmp1], %[ftmp1], "#c0" \n\t" \ + "paddw %[ftmp3], %[ftmp3], "#c0" \n\t" \ + "psraw %[ftmp13], %[ftmp13], %[ftmp0] \n\t" \ + "psraw %[ftmp1], %[ftmp1], %[ftmp0] \n\t" \ + "psraw %[ftmp14], %[ftmp14], %[ftmp0] \n\t" \ + "psraw %[ftmp3], %[ftmp3], %[ftmp0] \n\t" \ + "punpcklhw %[ftmp2], %[ftmp13], %[ftmp1] \n\t" \ + "punpckhhw %[ftmp4], %[ftmp13], %[ftmp1] \n\t" \ + "punpcklhw "#o1", %[ftmp2], %[ftmp4] \n\t" \ + "punpcklhw %[ftmp2], %[ftmp14], %[ftmp3] \n\t" \ + "punpckhhw %[ftmp4], %[ftmp14], %[ftmp3] \n\t" \ + "punpcklhw "#o2", %[ftmp2], %[ftmp4] \n\t" /* Do inverse transform on 8x8 block */ void ff_vc1_inv_trans_8x8_dc_mmi(uint8_t *dest, ptrdiff_t linesize, int16_t *block) @@ -216,137 +195,202 @@ void ff_vc1_inv_trans_8x8_dc_mmi(uint8_t *dest, ptrdiff_t linesize, int16_t *blo void ff_vc1_inv_trans_8x8_mmi(int16_t block[64]) { DECLARE_ALIGNED(16, int16_t, temp[64]); - int16_t *src = block; - int16_t *dst = temp; - double ftmp[16]; - uint32_t count, tmp[1]; + DECLARE_ALIGNED(8, const uint64_t, ff_pw_1_local) = {0x0000000100000001ULL}; + DECLARE_ALIGNED(8, const uint64_t, ff_pw_4_local) = {0x0000000400000004ULL}; + DECLARE_ALIGNED(8, const uint64_t, ff_pw_64_local)= {0x0000004000000040ULL}; + double ftmp[23]; + uint64_t tmp[1]; - // 1st loop __asm__ volatile ( + /* 1st loop: start */ "li %[tmp0], 0x03 \n\t" "mtc1 %[tmp0], %[ftmp0] \n\t" - "li %[count], 0x02 \n\t" - "1: \n\t" - MMI_LDC1(%[ftmp5], %[src], 0x10) - MMI_LDC1(%[ftmp6], %[src], 0x30) - MMI_LDC1(%[ftmp7], %[src], 0x50) - MMI_LDC1(%[ftmp8], %[src], 0x70) + // 1st part + MMI_LDC1(%[ftmp1], %[block], 0x00) + MMI_LDC1(%[ftmp11], %[block], 0x10) + MMI_LDC1(%[ftmp2], %[block], 0x20) + MMI_LDC1(%[ftmp12], %[block], 0x30) + MMI_LDC1(%[ftmp3], %[block], 0x40) + MMI_LDC1(%[ftmp13], %[block], 0x50) + MMI_LDC1(%[ftmp4], %[block], 0x60) + MMI_LDC1(%[ftmp14], %[block], 0x70) + "punpcklhw %[ftmp5], %[ftmp1], %[ftmp2] \n\t" + "punpckhhw %[ftmp6], %[ftmp1], %[ftmp2] \n\t" + "punpcklhw %[ftmp7], %[ftmp3], %[ftmp4] \n\t" + "punpckhhw %[ftmp8], %[ftmp3], %[ftmp4] \n\t" - VC1_INV_TRANCS_8_STEP1_MMI(%[ftmp5], %[ftmp6], %[ftmp7], %[ftmp8], - %[ftmp9], %[ftmp10], %[ftmp11], %[ftmp12], - %[ftmp1], %[ftmp2], %[ftmp3], %[ftmp4], - %[ff_pw_16], %[ff_pw_15], %[ff_pw_9], - %[ff_pw_4]) + "punpcklhw %[ftmp9], %[ftmp11], %[ftmp12] \n\t" + "punpckhhw %[ftmp10], %[ftmp11], %[ftmp12] \n\t" + "punpcklhw %[ftmp11], %[ftmp13], %[ftmp14] \n\t" + "punpckhhw %[ftmp12], %[ftmp13], %[ftmp14] \n\t" - MMI_LDC1(%[ftmp1], %[src], 0x00) - MMI_LDC1(%[ftmp2], %[src], 0x40) - MMI_LDC1(%[ftmp3], %[src], 0x20) - MMI_LDC1(%[ftmp4], %[src], 0x60) + /* ftmp15:dst03,dst02,dst01,dst00 ftmp22:dst73,dst72,dst71,dst70 */ + VC1_INV_TRANCS_8_TYPE1(%[ftmp15], %[ftmp22], 0x0010000c, 0x0006000c, + 0x000f0010, 0x00040009, %[ff_pw_4]) - VC1_INV_TRANCS_8_STEP2_MMI(%[ftmp1], %[ftmp2], %[ftmp3], %[ftmp4], - %[ftmp5], %[ftmp6], %[ftmp7], %[ftmp8], - %[ftmp9], %[ftmp10], %[ftmp11], %[ftmp12], - %[ff_pw_12], %[ff_pw_16], %[ff_pw_6], - %[ff_pw_4]) + /* ftmp16:dst13,dst12,dst11,dst10 ftmp21:dst63,dst62,dst61,dst60 */ + VC1_INV_TRANCS_8_TYPE1(%[ftmp16], %[ftmp21], 0x0006000c, 0xfff0fff4, + 0xfffc000f, 0xfff7fff0, %[ff_pw_4]) + /* ftmp17:dst23,dst22,dst21,dst20 ftmp20:dst53,dst52,dst51,dst50 */ + VC1_INV_TRANCS_8_TYPE1(%[ftmp17], %[ftmp20], 0xfffa000c, 0x0010fff4, + 0xfff00009, 0x000f0004, %[ff_pw_4]) - PSRAH_8_MMI(%[ftmp5], %[ftmp6], %[ftmp7], %[ftmp8], - %[ftmp4], %[ftmp3], %[ftmp2], %[ftmp1], %[ftmp0]) + /* ftmp18:dst33,dst32,dst31,dst30 ftmp19:dst43,dst42,dst41,dst40 */ + VC1_INV_TRANCS_8_TYPE1(%[ftmp18], %[ftmp19], 0xfff0000c, 0xfffa000c, + 0xfff70004, 0xfff0000f, %[ff_pw_4]) - TRANSPOSE_4H(%[ftmp5], %[ftmp6], %[ftmp7], %[ftmp8], - %[ftmp9], %[ftmp10], %[ftmp11], %[ftmp12], - %[ftmp13], %[tmp0], %[ftmp14], %[ftmp15]) + TRANSPOSE_4H(%[ftmp15], %[ftmp16], %[ftmp17], %[ftmp18], + %[ftmp1], %[ftmp2], %[ftmp3], %[ftmp4]) - MMI_SDC1(%[ftmp5], %[dst], 0x00) - MMI_SDC1(%[ftmp6], %[dst], 0x10) - MMI_SDC1(%[ftmp7], %[dst], 0x20) - MMI_SDC1(%[ftmp8], %[dst], 0x30) + TRANSPOSE_4H(%[ftmp19], %[ftmp20], %[ftmp21], %[ftmp22], + %[ftmp1], %[ftmp2], %[ftmp3], %[ftmp4]) - TRANSPOSE_4H(%[ftmp4], %[ftmp3], %[ftmp2], %[ftmp1], - %[ftmp9], %[ftmp10], %[ftmp11], %[ftmp12], - %[ftmp13], %[tmp0], %[ftmp14], %[ftmp15]) + MMI_SDC1(%[ftmp15], %[temp], 0x00) + MMI_SDC1(%[ftmp19], %[temp], 0x08) + MMI_SDC1(%[ftmp16], %[temp], 0x10) + MMI_SDC1(%[ftmp20], %[temp], 0x18) + MMI_SDC1(%[ftmp17], %[temp], 0x20) + MMI_SDC1(%[ftmp21], %[temp], 0x28) + MMI_SDC1(%[ftmp18], %[temp], 0x30) + MMI_SDC1(%[ftmp22], %[temp], 0x38) - MMI_SDC1(%[ftmp4], %[dst], 0x08) - MMI_SDC1(%[ftmp3], %[dst], 0x18) - MMI_SDC1(%[ftmp2], %[dst], 0x28) - MMI_SDC1(%[ftmp1], %[dst], 0x38) + // 2nd part + MMI_LDC1(%[ftmp1], %[block], 0x08) + MMI_LDC1(%[ftmp11], %[block], 0x18) + MMI_LDC1(%[ftmp2], %[block], 0x28) + MMI_LDC1(%[ftmp12], %[block], 0x38) + MMI_LDC1(%[ftmp3], %[block], 0x48) + MMI_LDC1(%[ftmp13], %[block], 0x58) + MMI_LDC1(%[ftmp4], %[block], 0x68) + MMI_LDC1(%[ftmp14], %[block], 0x78) + "punpcklhw %[ftmp5], %[ftmp1], %[ftmp2] \n\t" + "punpckhhw %[ftmp6], %[ftmp1], %[ftmp2] \n\t" + "punpcklhw %[ftmp7], %[ftmp3], %[ftmp4] \n\t" + "punpckhhw %[ftmp8], %[ftmp3], %[ftmp4] \n\t" - "addiu %[count], %[count], -0x01 \n\t" - PTR_ADDIU "%[src], %[src], 0x08 \n\t" - PTR_ADDIU "%[dst], %[dst], 0x40 \n\t" - "bnez %[count], 1b \n\t" - : [ftmp0]"=&f"(ftmp[0]), [ftmp1]"=&f"(ftmp[1]), - [ftmp2]"=&f"(ftmp[2]), [ftmp3]"=&f"(ftmp[3]), - [ftmp4]"=&f"(ftmp[4]), [ftmp5]"=&f"(ftmp[5]), - [ftmp6]"=&f"(ftmp[6]), [ftmp7]"=&f"(ftmp[7]), - [ftmp8]"=&f"(ftmp[8]), [ftmp9]"=&f"(ftmp[9]), - [ftmp10]"=&f"(ftmp[10]), [ftmp11]"=&f"(ftmp[11]), - [ftmp12]"=&f"(ftmp[12]), [ftmp13]"=&f"(ftmp[13]), - [ftmp14]"=&f"(ftmp[14]), [ftmp15]"=&f"(ftmp[15]), - [tmp0]"=&r"(tmp[0]), - [count]"=&r"(count), - [src]"+&r"(src), [dst]"+&r"(dst) - : [ff_pw_4]"f"(ff_pw_4), [ff_pw_6]"f"(ff_pw_6), - [ff_pw_9]"f"(ff_pw_9), [ff_pw_12]"f"(ff_pw_12), - [ff_pw_15]"f"(ff_pw_15), [ff_pw_16]"f"(ff_pw_16) - : "memory" - ); + "punpcklhw %[ftmp9], %[ftmp11], %[ftmp12] \n\t" + "punpckhhw %[ftmp10], %[ftmp11], %[ftmp12] \n\t" + "punpcklhw %[ftmp11], %[ftmp13], %[ftmp14] \n\t" + "punpckhhw %[ftmp12], %[ftmp13], %[ftmp14] \n\t" - src = temp; - dst = block; + /* ftmp15:dst03,dst02,dst01,dst00 ftmp22:dst73,dst72,dst71,dst70 */ + VC1_INV_TRANCS_8_TYPE1(%[ftmp15], %[ftmp22], 0x0010000c, 0x0006000c, + 0x000f0010, 0x00040009, %[ff_pw_4]) - // 2nd loop - __asm__ volatile ( + /* ftmp16:dst13,dst12,dst11,dst10 ftmp21:dst63,dst62,dst61,dst60 */ + VC1_INV_TRANCS_8_TYPE1(%[ftmp16], %[ftmp21], 0x0006000c, 0xfff0fff4, + 0xfffc000f, 0xfff7fff0, %[ff_pw_4]) + + /* ftmp17:dst23,dst22,dst21,dst20 ftmp20:dst53,dst52,dst51,dst50 */ + VC1_INV_TRANCS_8_TYPE1(%[ftmp17], %[ftmp20], 0xfffa000c, 0x0010fff4, + 0xfff00009, 0x000f0004, %[ff_pw_4]) + + /* ftmp18:dst33,dst32,dst31,dst30 ftmp19:dst43,dst42,dst41,dst40 */ + VC1_INV_TRANCS_8_TYPE1(%[ftmp18], %[ftmp19], 0xfff0000c, 0xfffa000c, + 0xfff70004, 0xfff0000f, %[ff_pw_4]) + + TRANSPOSE_4H(%[ftmp15], %[ftmp16], %[ftmp17], %[ftmp18], + %[ftmp1], %[ftmp2], %[ftmp3], %[ftmp4]) + + TRANSPOSE_4H(%[ftmp19], %[ftmp20], %[ftmp21], %[ftmp22], + %[ftmp1], %[ftmp2], %[ftmp3], %[ftmp4]) + + MMI_SDC1(%[ftmp19], %[temp], 0x48) + MMI_SDC1(%[ftmp20], %[temp], 0x58) + MMI_SDC1(%[ftmp21], %[temp], 0x68) + MMI_SDC1(%[ftmp22], %[temp], 0x78) + /* 1st loop: end */ + + /* 2nd loop: start */ "li %[tmp0], 0x07 \n\t" "mtc1 %[tmp0], %[ftmp0] \n\t" - "li %[count], 0x02 \n\t" - "1: \n\t" - MMI_LDC1(%[ftmp5], %[src], 0x10) - MMI_LDC1(%[ftmp6], %[src], 0x30) - MMI_LDC1(%[ftmp7], %[src], 0x50) - MMI_LDC1(%[ftmp8], %[src], 0x70) + // 1st part + MMI_LDC1(%[ftmp1], %[temp], 0x00) + MMI_LDC1(%[ftmp11], %[temp], 0x10) + MMI_LDC1(%[ftmp2], %[temp], 0x20) + MMI_LDC1(%[ftmp12], %[temp], 0x30) + "punpcklhw %[ftmp5], %[ftmp1], %[ftmp2] \n\t" + "punpckhhw %[ftmp6], %[ftmp1], %[ftmp2] \n\t" + "punpcklhw %[ftmp7], %[ftmp15], %[ftmp17] \n\t" + "punpckhhw %[ftmp8], %[ftmp15], %[ftmp17] \n\t" - VC1_INV_TRANCS_8_STEP1_MMI(%[ftmp5], %[ftmp6], %[ftmp7], %[ftmp8], - %[ftmp9], %[ftmp10], %[ftmp11], %[ftmp12], - %[ftmp1], %[ftmp2], %[ftmp3], %[ftmp4], - %[ff_pw_16], %[ff_pw_15], %[ff_pw_9], - %[ff_pw_4]) + "punpcklhw %[ftmp9], %[ftmp11], %[ftmp12] \n\t" + "punpckhhw %[ftmp10], %[ftmp11], %[ftmp12] \n\t" + "punpcklhw %[ftmp11], %[ftmp16], %[ftmp18] \n\t" + "punpckhhw %[ftmp12], %[ftmp16], %[ftmp18] \n\t" - MMI_LDC1(%[ftmp1], %[src], 0x00) - MMI_LDC1(%[ftmp2], %[src], 0x40) - MMI_LDC1(%[ftmp3], %[src], 0x20) - MMI_LDC1(%[ftmp4], %[src], 0x60) + /* ftmp15:dst03,dst02,dst01,dst00 ftmp22:dst73,dst72,dst71,dst70 */ + VC1_INV_TRANCS_8_TYPE2(%[ftmp15], %[ftmp22], 0x0010000c, 0x0006000c, + 0x000f0010, 0x00040009, %[ff_pw_64], %[ff_pw_1]) - VC1_INV_TRANCS_8_STEP2_MMI(%[ftmp1], %[ftmp2], %[ftmp3], %[ftmp4], - %[ftmp5], %[ftmp6], %[ftmp7], %[ftmp8], - %[ftmp9], %[ftmp10], %[ftmp11], %[ftmp12], - %[ff_pw_12], %[ff_pw_16], %[ff_pw_6], - %[ff_pw_64]) + /* ftmp16:dst13,dst12,dst11,dst10 ftmp21:dst63,dst62,dst61,dst60 */ + VC1_INV_TRANCS_8_TYPE2(%[ftmp16], %[ftmp21], 0x0006000c, 0xfff0fff4, + 0xfffc000f, 0xfff7fff0, %[ff_pw_64], %[ff_pw_1]) - "paddh %[ftmp4], %[ftmp4], %[ff_pw_1] \n\t" - "paddh %[ftmp3], %[ftmp3], %[ff_pw_1] \n\t" - "paddh %[ftmp2], %[ftmp2], %[ff_pw_1] \n\t" - "paddh %[ftmp1], %[ftmp1], %[ff_pw_1] \n\t" + /* ftmp17:dst23,dst22,dst21,dst20 ftmp20:dst53,dst52,dst51,dst50 */ + VC1_INV_TRANCS_8_TYPE2(%[ftmp17], %[ftmp20], 0xfffa000c, 0x0010fff4, + 0xfff00009, 0x000f0004, %[ff_pw_64], %[ff_pw_1]) - PSRAH_8_MMI(%[ftmp5], %[ftmp6], %[ftmp7], %[ftmp8], - %[ftmp4], %[ftmp3], %[ftmp2], %[ftmp1], %[ftmp0]) + /* ftmp18:dst33,dst32,dst31,dst30 ftmp19:dst43,dst42,dst41,dst40 */ + VC1_INV_TRANCS_8_TYPE2(%[ftmp18], %[ftmp19], 0xfff0000c, 0xfffa000c, + 0xfff70004, 0xfff0000f, %[ff_pw_64], %[ff_pw_1]) - MMI_SDC1(%[ftmp5], %[dst], 0x00) - MMI_SDC1(%[ftmp6], %[dst], 0x10) - MMI_SDC1(%[ftmp7], %[dst], 0x20) - MMI_SDC1(%[ftmp8], %[dst], 0x30) + MMI_SDC1(%[ftmp15], %[block], 0x00) + MMI_SDC1(%[ftmp16], %[block], 0x10) + MMI_SDC1(%[ftmp17], %[block], 0x20) + MMI_SDC1(%[ftmp18], %[block], 0x30) + MMI_SDC1(%[ftmp19], %[block], 0x40) + MMI_SDC1(%[ftmp20], %[block], 0x50) + MMI_SDC1(%[ftmp21], %[block], 0x60) + MMI_SDC1(%[ftmp22], %[block], 0x70) - MMI_SDC1(%[ftmp4], %[dst], 0x40) - MMI_SDC1(%[ftmp3], %[dst], 0x50) - MMI_SDC1(%[ftmp2], %[dst], 0x60) - MMI_SDC1(%[ftmp1], %[dst], 0x70) + // 2nd part + MMI_LDC1(%[ftmp1], %[temp], 0x08) + MMI_LDC1(%[ftmp11], %[temp], 0x18) + MMI_LDC1(%[ftmp2], %[temp], 0x28) + MMI_LDC1(%[ftmp12], %[temp], 0x38) + MMI_LDC1(%[ftmp3], %[temp], 0x48) + MMI_LDC1(%[ftmp13], %[temp], 0x58) + MMI_LDC1(%[ftmp4], %[temp], 0x68) + MMI_LDC1(%[ftmp14], %[temp], 0x78) + "punpcklhw %[ftmp5], %[ftmp1], %[ftmp2] \n\t" + "punpckhhw %[ftmp6], %[ftmp1], %[ftmp2] \n\t" + "punpcklhw %[ftmp7], %[ftmp3], %[ftmp4] \n\t" + "punpckhhw %[ftmp8], %[ftmp3], %[ftmp4] \n\t" - "addiu %[count], %[count], -0x01 \n\t" - PTR_ADDIU "%[src], %[src], 0x08 \n\t" - PTR_ADDIU "%[dst], %[dst], 0x08 \n\t" - "bnez %[count], 1b \n\t" + "punpcklhw %[ftmp9], %[ftmp11], %[ftmp12] \n\t" + "punpckhhw %[ftmp10], %[ftmp11], %[ftmp12] \n\t" + "punpcklhw %[ftmp11], %[ftmp13], %[ftmp14] \n\t" + "punpckhhw %[ftmp12], %[ftmp13], %[ftmp14] \n\t" + + /* ftmp15:dst03,dst02,dst01,dst00 ftmp22:dst73,dst72,dst71,dst70 */ + VC1_INV_TRANCS_8_TYPE2(%[ftmp15], %[ftmp22], 0x0010000c, 0x0006000c, + 0x000f0010, 0x00040009, %[ff_pw_64], %[ff_pw_1]) + + /* ftmp16:dst13,dst12,dst11,dst10 ftmp21:dst63,dst62,dst61,dst60 */ + VC1_INV_TRANCS_8_TYPE2(%[ftmp16], %[ftmp21], 0x0006000c, 0xfff0fff4, + 0xfffc000f, 0xfff7fff0, %[ff_pw_64], %[ff_pw_1]) + + /* ftmp17:dst23,dst22,dst21,dst20 ftmp20:dst53,dst52,dst51,dst50 */ + VC1_INV_TRANCS_8_TYPE2(%[ftmp17], %[ftmp20], 0xfffa000c, 0x0010fff4, + 0xfff00009, 0x000f0004, %[ff_pw_64], %[ff_pw_1]) + + /* ftmp18:dst33,dst32,dst31,dst30 ftmp19:dst43,dst42,dst41,dst40 */ + VC1_INV_TRANCS_8_TYPE2(%[ftmp18], %[ftmp19], 0xfff0000c, 0xfffa000c, + 0xfff70004, 0xfff0000f, %[ff_pw_64], %[ff_pw_1]) + + MMI_SDC1(%[ftmp15], %[block], 0x08) + MMI_SDC1(%[ftmp16], %[block], 0x18) + MMI_SDC1(%[ftmp17], %[block], 0x28) + MMI_SDC1(%[ftmp18], %[block], 0x38) + MMI_SDC1(%[ftmp19], %[block], 0x48) + MMI_SDC1(%[ftmp20], %[block], 0x58) + MMI_SDC1(%[ftmp21], %[block], 0x68) + MMI_SDC1(%[ftmp22], %[block], 0x78) + /* 2nd loop: end */ : [ftmp0]"=&f"(ftmp[0]), [ftmp1]"=&f"(ftmp[1]), [ftmp2]"=&f"(ftmp[2]), [ftmp3]"=&f"(ftmp[3]), [ftmp4]"=&f"(ftmp[4]), [ftmp5]"=&f"(ftmp[5]), @@ -355,13 +399,14 @@ void ff_vc1_inv_trans_8x8_mmi(int16_t block[64]) [ftmp10]"=&f"(ftmp[10]), [ftmp11]"=&f"(ftmp[11]), [ftmp12]"=&f"(ftmp[12]), [ftmp13]"=&f"(ftmp[13]), [ftmp14]"=&f"(ftmp[14]), [ftmp15]"=&f"(ftmp[15]), - [tmp0]"=&r"(tmp[0]), - [count]"=&r"(count), - [src]"+&r"(src), [dst]"+&r"(dst) - : [ff_pw_1]"f"(ff_pw_1), [ff_pw_4]"f"(ff_pw_4), - [ff_pw_6]"f"(ff_pw_6), [ff_pw_9]"f"(ff_pw_9), - [ff_pw_12]"f"(ff_pw_12), [ff_pw_15]"f"(ff_pw_15), - [ff_pw_16]"f"(ff_pw_16), [ff_pw_64]"f"(ff_pw_64) + [ftmp16]"=&f"(ftmp[16]), [ftmp17]"=&f"(ftmp[17]), + [ftmp18]"=&f"(ftmp[18]), [ftmp19]"=&f"(ftmp[19]), + [ftmp20]"=&f"(ftmp[20]), [ftmp21]"=&f"(ftmp[21]), + [ftmp22]"=&f"(ftmp[22]), + [tmp0]"=&r"(tmp[0]) + : [ff_pw_1]"f"(ff_pw_1_local), [ff_pw_64]"f"(ff_pw_64_local), + [ff_pw_4]"f"(ff_pw_4_local), [block]"r"(block), + [temp]"r"(temp) : "memory" ); } @@ -431,66 +476,377 @@ void ff_vc1_inv_trans_8x4_mmi(uint8_t *dest, ptrdiff_t linesize, int16_t *block) int16_t *dst = block; double ftmp[16]; uint32_t tmp[1]; - mips_reg addr[1]; - DECLARE_VAR_LOW32; + int16_t count = 4; + DECLARE_ALIGNED(16, const uint64_t, ff_pw_4_local) = {0x0000000400000004ULL}; + DECLARE_ALIGNED(16, const uint64_t, ff_pw_64_local)= {0x0000004000000040ULL}; + int16_t coeff[64] = {12, 16, 16, 15, 12, 9, 6, 4, + 12, 15, 6, -4, -12, -16, -16, -9, + 12, 9, -6, -16, -12, 4, 16, 15, + 12, 4, -16, -9, 12, 15, -6, -16, + 12, -4, -16, 9, 12, -15, -6, 16, + 12, -9, -6, 16, -12, -4, 16, -15, + 12, -15, 6, 4, -12, 16, -16, 9, + 12, -16, 16, -15, 12, -9, 6, -4}; // 1st loop __asm__ volatile ( - MMI_LDC1(%[ftmp1], %[src], 0x00) - MMI_LDC1(%[ftmp2], %[src], 0x08) - MMI_LDC1(%[ftmp3], %[src], 0x10) - MMI_LDC1(%[ftmp4], %[src], 0x18) - MMI_LDC1(%[ftmp5], %[src], 0x20) - MMI_LDC1(%[ftmp6], %[src], 0x28) - MMI_LDC1(%[ftmp7], %[src], 0x30) - MMI_LDC1(%[ftmp8], %[src], 0x38) - - // a1 b1 a3 b2 - TRANSPOSE_4H(%[ftmp1], %[ftmp3], %[ftmp5], %[ftmp7], - %[ftmp9], %[ftmp10], %[ftmp11], %[ftmp12], - %[ftmp13], %[tmp0], %[ftmp14], %[ftmp15]) - - // a2 b3 a4 b4 - TRANSPOSE_4H(%[ftmp2], %[ftmp4], %[ftmp6], %[ftmp8], - %[ftmp9], %[ftmp10], %[ftmp11], %[ftmp12], - %[ftmp13], %[tmp0], %[ftmp14], %[ftmp15]) - - // input b1 b2 b3 b4 - VC1_INV_TRANCS_8_STEP1_MMI(%[ftmp3], %[ftmp7], %[ftmp4], %[ftmp8], - %[ftmp9], %[ftmp10], %[ftmp11], %[ftmp12], - %[ftmp0], %[ftmp13], %[ftmp14], %[ftmp15], - %[ff_pw_16], %[ff_pw_15], %[ff_pw_9], - %[ff_pw_4]) - // input a1 a2 a3 a4 - VC1_INV_TRANCS_8_STEP2_MMI(%[ftmp1], %[ftmp2], %[ftmp5], %[ftmp6], - %[ftmp3], %[ftmp7], %[ftmp4], %[ftmp8], - %[ftmp9], %[ftmp10], %[ftmp11], %[ftmp12], - %[ff_pw_12], %[ff_pw_16], %[ff_pw_6], - %[ff_pw_4]) - "li %[tmp0], 0x03 \n\t" "mtc1 %[tmp0], %[ftmp0] \n\t" - PSRAH_8_MMI(%[ftmp3], %[ftmp7], %[ftmp4], %[ftmp8], - %[ftmp6], %[ftmp5], %[ftmp2], %[ftmp1], %[ftmp0]) + "1: \n\t" + MMI_LDC1(%[ftmp1], %[src], 0x00) + MMI_LDC1(%[ftmp2], %[src], 0x08) - TRANSPOSE_4H(%[ftmp3], %[ftmp7], %[ftmp4], %[ftmp8], - %[ftmp9], %[ftmp10], %[ftmp11], %[ftmp12], - %[ftmp13], %[tmp0], %[ftmp14], %[ftmp15]) + /* ftmp11: dst1,dst0 */ + MMI_LDC1(%[ftmp3], %[coeff], 0x00) + MMI_LDC1(%[ftmp4], %[coeff], 0x08) + MMI_LDC1(%[ftmp5], %[coeff], 0x10) + MMI_LDC1(%[ftmp6], %[coeff], 0x18) + "pmaddhw %[ftmp7], %[ftmp1], %[ftmp3] \n\t" + "pmaddhw %[ftmp8], %[ftmp2], %[ftmp4] \n\t" + "paddw %[ftmp9], %[ftmp7], %[ftmp8] \n\t" + "pmaddhw %[ftmp7], %[ftmp1], %[ftmp5] \n\t" + "pmaddhw %[ftmp8], %[ftmp2], %[ftmp6] \n\t" + "paddw %[ftmp10], %[ftmp7], %[ftmp8] \n\t" + "punpcklwd %[ftmp7], %[ftmp9], %[ftmp10] \n\t" + "punpckhwd %[ftmp8], %[ftmp9], %[ftmp10] \n\t" + "paddw %[ftmp11], %[ftmp7], %[ftmp8] \n\t" + "paddw %[ftmp11], %[ftmp11], %[ff_pw_4] \n\t" - MMI_SDC1(%[ftmp3], %[dst], 0x00) - MMI_SDC1(%[ftmp7], %[dst], 0x10) - MMI_SDC1(%[ftmp4], %[dst], 0x20) - MMI_SDC1(%[ftmp8], %[dst], 0x30) + /* ftmp12: dst3,dst2 */ + MMI_LDC1(%[ftmp3], %[coeff], 0x20) + MMI_LDC1(%[ftmp4], %[coeff], 0x28) + MMI_LDC1(%[ftmp5], %[coeff], 0x30) + MMI_LDC1(%[ftmp6], %[coeff], 0x38) + "pmaddhw %[ftmp7], %[ftmp1], %[ftmp3] \n\t" + "pmaddhw %[ftmp8], %[ftmp2], %[ftmp4] \n\t" + "paddw %[ftmp9], %[ftmp7], %[ftmp8] \n\t" + "pmaddhw %[ftmp7], %[ftmp1], %[ftmp5] \n\t" + "pmaddhw %[ftmp8], %[ftmp2], %[ftmp6] \n\t" + "paddw %[ftmp10], %[ftmp7], %[ftmp8] \n\t" + "punpcklwd %[ftmp7], %[ftmp9], %[ftmp10] \n\t" + "punpckhwd %[ftmp8], %[ftmp9], %[ftmp10] \n\t" + "paddw %[ftmp12], %[ftmp7], %[ftmp8] \n\t" + "paddw %[ftmp12], %[ftmp12], %[ff_pw_4] \n\t" - TRANSPOSE_4H(%[ftmp6], %[ftmp5], %[ftmp2], %[ftmp1], - %[ftmp9], %[ftmp10], %[ftmp11], %[ftmp12], - %[ftmp13], %[tmp0], %[ftmp14], %[ftmp15]) + /* ftmp13: dst5,dst4 */ + MMI_LDC1(%[ftmp3], %[coeff], 0x40) + MMI_LDC1(%[ftmp4], %[coeff], 0x48) + MMI_LDC1(%[ftmp5], %[coeff], 0x50) + MMI_LDC1(%[ftmp6], %[coeff], 0x58) + "pmaddhw %[ftmp7], %[ftmp1], %[ftmp3] \n\t" + "pmaddhw %[ftmp8], %[ftmp2], %[ftmp4] \n\t" + "paddw %[ftmp9], %[ftmp7], %[ftmp8] \n\t" + "pmaddhw %[ftmp7], %[ftmp1], %[ftmp5] \n\t" + "pmaddhw %[ftmp8], %[ftmp2], %[ftmp6] \n\t" + "paddw %[ftmp10], %[ftmp7], %[ftmp8] \n\t" + "punpcklwd %[ftmp7], %[ftmp9], %[ftmp10] \n\t" + "punpckhwd %[ftmp8], %[ftmp9], %[ftmp10] \n\t" + "paddw %[ftmp13], %[ftmp7], %[ftmp8] \n\t" + "paddw %[ftmp13], %[ftmp13], %[ff_pw_4] \n\t" + + /* ftmp14: dst7,dst6 */ + MMI_LDC1(%[ftmp3], %[coeff], 0x60) + MMI_LDC1(%[ftmp4], %[coeff], 0x68) + MMI_LDC1(%[ftmp5], %[coeff], 0x70) + MMI_LDC1(%[ftmp6], %[coeff], 0x78) + "pmaddhw %[ftmp7], %[ftmp1], %[ftmp3] \n\t" + "pmaddhw %[ftmp8], %[ftmp2], %[ftmp4] \n\t" + "paddw %[ftmp9], %[ftmp7], %[ftmp8] \n\t" + "pmaddhw %[ftmp7], %[ftmp1], %[ftmp5] \n\t" + "pmaddhw %[ftmp8], %[ftmp2], %[ftmp6] \n\t" + "paddw %[ftmp10], %[ftmp7], %[ftmp8] \n\t" + "punpcklwd %[ftmp7], %[ftmp9], %[ftmp10] \n\t" + "punpckhwd %[ftmp8], %[ftmp9], %[ftmp10] \n\t" + "paddw %[ftmp14], %[ftmp7], %[ftmp8] \n\t" + "paddw %[ftmp14], %[ftmp14], %[ff_pw_4] \n\t" + + /* ftmp9: dst3,dst2,dst1,dst0 ftmp10: dst7,dst6,dst5,dst4 */ + "psraw %[ftmp11], %[ftmp11], %[ftmp0] \n\t" + "psraw %[ftmp12], %[ftmp12], %[ftmp0] \n\t" + "psraw %[ftmp13], %[ftmp13], %[ftmp0] \n\t" + "psraw %[ftmp14], %[ftmp14], %[ftmp0] \n\t" + "punpcklhw %[ftmp7], %[ftmp11], %[ftmp12] \n\t" + "punpckhhw %[ftmp8], %[ftmp11], %[ftmp12] \n\t" + "punpcklhw %[ftmp9], %[ftmp7], %[ftmp8] \n\t" + "punpcklhw %[ftmp7], %[ftmp13], %[ftmp14] \n\t" + "punpckhhw %[ftmp8], %[ftmp13], %[ftmp14] \n\t" + "punpcklhw %[ftmp10], %[ftmp7], %[ftmp8] \n\t" + MMI_SDC1(%[ftmp9], %[dst], 0x00) + MMI_SDC1(%[ftmp10], %[dst], 0x08) + + PTR_ADDIU "%[src], %[src], 0x10 \n\t" + PTR_ADDIU "%[dst], %[dst], 0x10 \n\t" + "addiu %[count], %[count], -0x01 \n\t" + "bnez %[count], 1b \n\t" + : [ftmp0]"=&f"(ftmp[0]), [ftmp1]"=&f"(ftmp[1]), + [ftmp2]"=&f"(ftmp[2]), [ftmp3]"=&f"(ftmp[3]), + [ftmp4]"=&f"(ftmp[4]), [ftmp5]"=&f"(ftmp[5]), + [ftmp6]"=&f"(ftmp[6]), [ftmp7]"=&f"(ftmp[7]), + [ftmp8]"=&f"(ftmp[8]), [ftmp9]"=&f"(ftmp[9]), + [ftmp10]"=&f"(ftmp[10]), [ftmp11]"=&f"(ftmp[11]), + [ftmp12]"=&f"(ftmp[12]), [ftmp13]"=&f"(ftmp[13]), + [ftmp14]"=&f"(ftmp[14]), [tmp0]"=&r"(tmp[0]), + [src]"+&r"(src), [dst]"+&r"(dst), [count]"+&r"(count) + : [ff_pw_4]"f"(ff_pw_4_local), [coeff]"r"(coeff) + : "memory" + ); + + src = block; + + // 2nd loop + __asm__ volatile ( + "li %[tmp0], 0x44 \n\t" + "mtc1 %[tmp0], %[ftmp15] \n\t" + + // 1st part + "li %[tmp0], 0x07 \n\t" + "mtc1 %[tmp0], %[ftmp0] \n\t" + MMI_LDC1(%[ftmp1], %[src], 0x00) + MMI_LDC1(%[ftmp2], %[src], 0x10) + MMI_LDC1(%[ftmp3], %[src], 0x20) + MMI_LDC1(%[ftmp4], %[src], 0x30) + "punpcklhw %[ftmp5], %[ftmp1], %[ftmp2] \n\t" + "punpckhhw %[ftmp6], %[ftmp1], %[ftmp2] \n\t" + "punpcklhw %[ftmp7], %[ftmp3], %[ftmp4] \n\t" + "punpckhhw %[ftmp8], %[ftmp3], %[ftmp4] \n\t" + + /* ftmp11: dst03,dst02,dst01,dst00 */ + "li %[tmp0], 0x00160011 \n\t" + "mtc1 %[tmp0], %[ftmp3] \n\t" + "pshufh %[ftmp3], %[ftmp3], %[ftmp15] \n\t" + "li %[tmp0], 0x000a0011 \n\t" + "mtc1 %[tmp0], %[ftmp4] \n\t" + "pshufh %[ftmp4], %[ftmp4], %[ftmp15] \n\t" + "pmaddhw %[ftmp1], %[ftmp5], %[ftmp3] \n\t" + "pmaddhw %[ftmp2], %[ftmp7], %[ftmp4] \n\t" + "paddw %[ftmp9], %[ftmp1], %[ftmp2] \n\t" + "pmaddhw %[ftmp1], %[ftmp6], %[ftmp3] \n\t" + "pmaddhw %[ftmp2], %[ftmp8], %[ftmp4] \n\t" + "paddw %[ftmp10], %[ftmp1], %[ftmp2] \n\t" + "paddw %[ftmp9], %[ftmp9], %[ff_pw_64] \n\t" + "paddw %[ftmp10], %[ftmp10], %[ff_pw_64] \n\t" + "psraw %[ftmp9], %[ftmp9], %[ftmp0] \n\t" + "psraw %[ftmp10], %[ftmp10], %[ftmp0] \n\t" + "punpcklhw %[ftmp1], %[ftmp9], %[ftmp10] \n\t" + "punpckhhw %[ftmp2], %[ftmp9], %[ftmp10] \n\t" + "punpcklhw %[ftmp11], %[ftmp1], %[ftmp2] \n\t" + + /* ftmp12: dst13,dst12,dst11,dst10 */ + "li %[tmp0], 0x000a0011 \n\t" + "mtc1 %[tmp0], %[ftmp3] \n\t" + "pshufh %[ftmp3], %[ftmp3], %[ftmp15] \n\t" + "li %[tmp0], 0xffeaffef \n\t" + "mtc1 %[tmp0], %[ftmp4] \n\t" + "pshufh %[ftmp4], %[ftmp4], %[ftmp15] \n\t" + "pmaddhw %[ftmp1], %[ftmp5], %[ftmp3] \n\t" + "pmaddhw %[ftmp2], %[ftmp7], %[ftmp4] \n\t" + "paddw %[ftmp9], %[ftmp1], %[ftmp2] \n\t" + "pmaddhw %[ftmp1], %[ftmp6], %[ftmp3] \n\t" + "pmaddhw %[ftmp2], %[ftmp8], %[ftmp4] \n\t" + "paddw %[ftmp10], %[ftmp1], %[ftmp2] \n\t" + "paddw %[ftmp9], %[ftmp9], %[ff_pw_64] \n\t" + "paddw %[ftmp10], %[ftmp10], %[ff_pw_64] \n\t" + "psraw %[ftmp9], %[ftmp9], %[ftmp0] \n\t" + "psraw %[ftmp10], %[ftmp10], %[ftmp0] \n\t" + "punpcklhw %[ftmp1], %[ftmp9], %[ftmp10] \n\t" + "punpckhhw %[ftmp2], %[ftmp9], %[ftmp10] \n\t" + "punpcklhw %[ftmp12], %[ftmp1], %[ftmp2] \n\t" + + /* ftmp13: dst23,dst22,dst21,dst20 */ + "li %[tmp0], 0xfff60011 \n\t" + "mtc1 %[tmp0], %[ftmp3] \n\t" + "pshufh %[ftmp3], %[ftmp3], %[ftmp15] \n\t" + "li %[tmp0], 0x0016ffef \n\t" + "mtc1 %[tmp0], %[ftmp4] \n\t" + "pshufh %[ftmp4], %[ftmp4], %[ftmp15] \n\t" + "pmaddhw %[ftmp1], %[ftmp5], %[ftmp3] \n\t" + "pmaddhw %[ftmp2], %[ftmp7], %[ftmp4] \n\t" + "paddw %[ftmp9], %[ftmp1], %[ftmp2] \n\t" + "pmaddhw %[ftmp1], %[ftmp6], %[ftmp3] \n\t" + "pmaddhw %[ftmp2], %[ftmp8], %[ftmp4] \n\t" + "paddw %[ftmp10], %[ftmp1], %[ftmp2] \n\t" + "paddw %[ftmp9], %[ftmp9], %[ff_pw_64] \n\t" + "paddw %[ftmp10], %[ftmp10], %[ff_pw_64] \n\t" + "psraw %[ftmp9], %[ftmp9], %[ftmp0] \n\t" + "psraw %[ftmp10], %[ftmp10], %[ftmp0] \n\t" + "punpcklhw %[ftmp1], %[ftmp9], %[ftmp10] \n\t" + "punpckhhw %[ftmp2], %[ftmp9], %[ftmp10] \n\t" + "punpcklhw %[ftmp13], %[ftmp1], %[ftmp2] \n\t" + + /* ftmp14: dst33,dst32,dst31,dst30 */ + "li %[tmp0], 0xffea0011 \n\t" + "mtc1 %[tmp0], %[ftmp3] \n\t" + "pshufh %[ftmp3], %[ftmp3], %[ftmp15] \n\t" + "li %[tmp0], 0xfff60011 \n\t" + "mtc1 %[tmp0], %[ftmp4] \n\t" + "pshufh %[ftmp4], %[ftmp4], %[ftmp15] \n\t" + "pmaddhw %[ftmp1], %[ftmp5], %[ftmp3] \n\t" + "pmaddhw %[ftmp2], %[ftmp7], %[ftmp4] \n\t" + "paddw %[ftmp9], %[ftmp1], %[ftmp2] \n\t" + "pmaddhw %[ftmp1], %[ftmp6], %[ftmp3] \n\t" + "pmaddhw %[ftmp2], %[ftmp8], %[ftmp4] \n\t" + "paddw %[ftmp10], %[ftmp1], %[ftmp2] \n\t" + "paddw %[ftmp9], %[ftmp9], %[ff_pw_64] \n\t" + "paddw %[ftmp10], %[ftmp10], %[ff_pw_64] \n\t" + "psraw %[ftmp9], %[ftmp9], %[ftmp0] \n\t" + "psraw %[ftmp10], %[ftmp10], %[ftmp0] \n\t" + "punpcklhw %[ftmp1], %[ftmp9], %[ftmp10] \n\t" + "punpckhhw %[ftmp2], %[ftmp9], %[ftmp10] \n\t" + "punpcklhw %[ftmp14], %[ftmp1], %[ftmp2] \n\t" + + MMI_LWC1(%[ftmp1], %[dest], 0x00) + PTR_ADDU "%[tmp0], %[dest], %[linesize] \n\t" + MMI_LWC1(%[ftmp2], %[tmp0], 0x00) + PTR_ADDU "%[tmp0], %[tmp0], %[linesize] \n\t" + MMI_LWC1(%[ftmp3], %[tmp0], 0x00) + PTR_ADDU "%[tmp0], %[tmp0], %[linesize] \n\t" + MMI_LWC1(%[ftmp4], %[tmp0], 0x00) + "xor %[ftmp0], %[ftmp0], %[ftmp0] \n\t" + "punpcklbh %[ftmp1], %[ftmp1], %[ftmp0] \n\t" + "punpcklbh %[ftmp2], %[ftmp2], %[ftmp0] \n\t" + "punpcklbh %[ftmp3], %[ftmp3], %[ftmp0] \n\t" + "punpcklbh %[ftmp4], %[ftmp4], %[ftmp0] \n\t" + "paddh %[ftmp1], %[ftmp1], %[ftmp11] \n\t" + "paddh %[ftmp2], %[ftmp2], %[ftmp12] \n\t" + "paddh %[ftmp3], %[ftmp3], %[ftmp13] \n\t" + "paddh %[ftmp4], %[ftmp4], %[ftmp14] \n\t" + "packushb %[ftmp1], %[ftmp1], %[ftmp0] \n\t" + "packushb %[ftmp2], %[ftmp2], %[ftmp0] \n\t" + "packushb %[ftmp3], %[ftmp3], %[ftmp0] \n\t" + "packushb %[ftmp4], %[ftmp4], %[ftmp0] \n\t" + MMI_SWC1(%[ftmp1], %[dest], 0x00) + PTR_ADDU "%[tmp0], %[dest], %[linesize] \n\t" + MMI_SWC1(%[ftmp2], %[tmp0], 0x00) + PTR_ADDU "%[tmp0], %[tmp0], %[linesize] \n\t" + MMI_SWC1(%[ftmp3], %[tmp0], 0x00) + PTR_ADDU "%[tmp0], %[tmp0], %[linesize] \n\t" + MMI_SWC1(%[ftmp4], %[tmp0], 0x00) + + // 2nd part + "li %[tmp0], 0x07 \n\t" + "mtc1 %[tmp0], %[ftmp0] \n\t" + MMI_LDC1(%[ftmp1], %[src], 0x08) + MMI_LDC1(%[ftmp2], %[src], 0x18) + MMI_LDC1(%[ftmp3], %[src], 0x28) + MMI_LDC1(%[ftmp4], %[src], 0x38) + "punpcklhw %[ftmp5], %[ftmp1], %[ftmp2] \n\t" + "punpckhhw %[ftmp6], %[ftmp1], %[ftmp2] \n\t" + "punpcklhw %[ftmp7], %[ftmp3], %[ftmp4] \n\t" + "punpckhhw %[ftmp8], %[ftmp3], %[ftmp4] \n\t" + + /* ftmp11: dst03,dst02,dst01,dst00 */ + "li %[tmp0], 0x00160011 \n\t" + "mtc1 %[tmp0], %[ftmp3] \n\t" + "pshufh %[ftmp3], %[ftmp3], %[ftmp15] \n\t" + "li %[tmp0], 0x000a0011 \n\t" + "mtc1 %[tmp0], %[ftmp4] \n\t" + "pshufh %[ftmp4], %[ftmp4], %[ftmp15] \n\t" + "pmaddhw %[ftmp1], %[ftmp5], %[ftmp3] \n\t" + "pmaddhw %[ftmp2], %[ftmp7], %[ftmp4] \n\t" + "paddw %[ftmp9], %[ftmp1], %[ftmp2] \n\t" + "pmaddhw %[ftmp1], %[ftmp6], %[ftmp3] \n\t" + "pmaddhw %[ftmp2], %[ftmp8], %[ftmp4] \n\t" + "paddw %[ftmp10], %[ftmp1], %[ftmp2] \n\t" + "paddw %[ftmp9], %[ftmp9], %[ff_pw_64] \n\t" + "paddw %[ftmp10], %[ftmp10], %[ff_pw_64] \n\t" + "psraw %[ftmp9], %[ftmp9], %[ftmp0] \n\t" + "psraw %[ftmp10], %[ftmp10], %[ftmp0] \n\t" + "punpcklhw %[ftmp1], %[ftmp9], %[ftmp10] \n\t" + "punpckhhw %[ftmp2], %[ftmp9], %[ftmp10] \n\t" + "punpcklhw %[ftmp11], %[ftmp1], %[ftmp2] \n\t" + + /* ftmp12: dst13,dst12,dst11,dst10 */ + "li %[tmp0], 0x000a0011 \n\t" + "mtc1 %[tmp0], %[ftmp3] \n\t" + "pshufh %[ftmp3], %[ftmp3], %[ftmp15] \n\t" + "li %[tmp0], 0xffeaffef \n\t" + "mtc1 %[tmp0], %[ftmp4] \n\t" + "pshufh %[ftmp4], %[ftmp4], %[ftmp15] \n\t" + "pmaddhw %[ftmp1], %[ftmp5], %[ftmp3] \n\t" + "pmaddhw %[ftmp2], %[ftmp7], %[ftmp4] \n\t" + "paddw %[ftmp9], %[ftmp1], %[ftmp2] \n\t" + "pmaddhw %[ftmp1], %[ftmp6], %[ftmp3] \n\t" + "pmaddhw %[ftmp2], %[ftmp8], %[ftmp4] \n\t" + "paddw %[ftmp10], %[ftmp1], %[ftmp2] \n\t" + "paddw %[ftmp9], %[ftmp9], %[ff_pw_64] \n\t" + "paddw %[ftmp10], %[ftmp10], %[ff_pw_64] \n\t" + "psraw %[ftmp9], %[ftmp9], %[ftmp0] \n\t" + "psraw %[ftmp10], %[ftmp10], %[ftmp0] \n\t" + "punpcklhw %[ftmp1], %[ftmp9], %[ftmp10] \n\t" + "punpckhhw %[ftmp2], %[ftmp9], %[ftmp10] \n\t" + "punpcklhw %[ftmp12], %[ftmp1], %[ftmp2] \n\t" + + /* ftmp13: dst23,dst22,dst21,dst20 */ + "li %[tmp0], 0xfff60011 \n\t" + "mtc1 %[tmp0], %[ftmp3] \n\t" + "pshufh %[ftmp3], %[ftmp3], %[ftmp15] \n\t" + "li %[tmp0], 0x0016ffef \n\t" + "mtc1 %[tmp0], %[ftmp4] \n\t" + "pshufh %[ftmp4], %[ftmp4], %[ftmp15] \n\t" + "pmaddhw %[ftmp1], %[ftmp5], %[ftmp3] \n\t" + "pmaddhw %[ftmp2], %[ftmp7], %[ftmp4] \n\t" + "paddw %[ftmp9], %[ftmp1], %[ftmp2] \n\t" + "pmaddhw %[ftmp1], %[ftmp6], %[ftmp3] \n\t" + "pmaddhw %[ftmp2], %[ftmp8], %[ftmp4] \n\t" + "paddw %[ftmp10], %[ftmp1], %[ftmp2] \n\t" + "paddw %[ftmp9], %[ftmp9], %[ff_pw_64] \n\t" + "paddw %[ftmp10], %[ftmp10], %[ff_pw_64] \n\t" + "psraw %[ftmp9], %[ftmp9], %[ftmp0] \n\t" + "psraw %[ftmp10], %[ftmp10], %[ftmp0] \n\t" + "punpcklhw %[ftmp1], %[ftmp9], %[ftmp10] \n\t" + "punpckhhw %[ftmp2], %[ftmp9], %[ftmp10] \n\t" + "punpcklhw %[ftmp13], %[ftmp1], %[ftmp2] \n\t" + + /* ftmp14: dst33,dst32,dst31,dst30 */ + "li %[tmp0], 0xffea0011 \n\t" + "mtc1 %[tmp0], %[ftmp3] \n\t" + "pshufh %[ftmp3], %[ftmp3], %[ftmp15] \n\t" + "li %[tmp0], 0xfff60011 \n\t" + "mtc1 %[tmp0], %[ftmp4] \n\t" + "pshufh %[ftmp4], %[ftmp4], %[ftmp15] \n\t" + "pmaddhw %[ftmp1], %[ftmp5], %[ftmp3] \n\t" + "pmaddhw %[ftmp2], %[ftmp7], %[ftmp4] \n\t" + "paddw %[ftmp9], %[ftmp1], %[ftmp2] \n\t" + "pmaddhw %[ftmp1], %[ftmp6], %[ftmp3] \n\t" + "pmaddhw %[ftmp2], %[ftmp8], %[ftmp4] \n\t" + "paddw %[ftmp10], %[ftmp1], %[ftmp2] \n\t" + "paddw %[ftmp9], %[ftmp9], %[ff_pw_64] \n\t" + "paddw %[ftmp10], %[ftmp10], %[ff_pw_64] \n\t" + "psraw %[ftmp9], %[ftmp9], %[ftmp0] \n\t" + "psraw %[ftmp10], %[ftmp10], %[ftmp0] \n\t" + "punpcklhw %[ftmp1], %[ftmp9], %[ftmp10] \n\t" + "punpckhhw %[ftmp2], %[ftmp9], %[ftmp10] \n\t" + "punpcklhw %[ftmp14], %[ftmp1], %[ftmp2] \n\t" + + MMI_LWC1(%[ftmp1], %[dest], 0x04) + PTR_ADDU "%[tmp0], %[dest], %[linesize] \n\t" + MMI_LWC1(%[ftmp2], %[tmp0], 0x04) + PTR_ADDU "%[tmp0], %[tmp0], %[linesize] \n\t" + MMI_LWC1(%[ftmp3], %[tmp0], 0x04) + PTR_ADDU "%[tmp0], %[tmp0], %[linesize] \n\t" + MMI_LWC1(%[ftmp4], %[tmp0], 0x04) + "xor %[ftmp0], %[ftmp0], %[ftmp0] \n\t" + "punpcklbh %[ftmp1], %[ftmp1], %[ftmp0] \n\t" + "punpcklbh %[ftmp2], %[ftmp2], %[ftmp0] \n\t" + "punpcklbh %[ftmp3], %[ftmp3], %[ftmp0] \n\t" + "punpcklbh %[ftmp4], %[ftmp4], %[ftmp0] \n\t" + "paddh %[ftmp1], %[ftmp1], %[ftmp11] \n\t" + "paddh %[ftmp2], %[ftmp2], %[ftmp12] \n\t" + "paddh %[ftmp3], %[ftmp3], %[ftmp13] \n\t" + "paddh %[ftmp4], %[ftmp4], %[ftmp14] \n\t" + "packushb %[ftmp1], %[ftmp1], %[ftmp0] \n\t" + "packushb %[ftmp2], %[ftmp2], %[ftmp0] \n\t" + "packushb %[ftmp3], %[ftmp3], %[ftmp0] \n\t" + "packushb %[ftmp4], %[ftmp4], %[ftmp0] \n\t" + MMI_SWC1(%[ftmp1], %[dest], 0x04) + PTR_ADDU "%[tmp0], %[dest], %[linesize] \n\t" + MMI_SWC1(%[ftmp2], %[tmp0], 0x04) + PTR_ADDU "%[tmp0], %[tmp0], %[linesize] \n\t" + MMI_SWC1(%[ftmp3], %[tmp0], 0x04) + PTR_ADDU "%[tmp0], %[tmp0], %[linesize] \n\t" + MMI_SWC1(%[ftmp4], %[tmp0], 0x04) - MMI_SDC1(%[ftmp6], %[dst], 0x08) - MMI_SDC1(%[ftmp5], %[dst], 0x18) - MMI_SDC1(%[ftmp2], %[dst], 0x28) - MMI_SDC1(%[ftmp1], %[dst], 0x38) : [ftmp0]"=&f"(ftmp[0]), [ftmp1]"=&f"(ftmp[1]), [ftmp2]"=&f"(ftmp[2]), [ftmp3]"=&f"(ftmp[3]), [ftmp4]"=&f"(ftmp[4]), [ftmp5]"=&f"(ftmp[5]), @@ -500,100 +856,9 @@ void ff_vc1_inv_trans_8x4_mmi(uint8_t *dest, ptrdiff_t linesize, int16_t *block) [ftmp12]"=&f"(ftmp[12]), [ftmp13]"=&f"(ftmp[13]), [ftmp14]"=&f"(ftmp[14]), [ftmp15]"=&f"(ftmp[15]), [tmp0]"=&r"(tmp[0]) - : [src]"r"(src), [dst]"r"(dst), - [ff_pw_4]"f"(ff_pw_4), [ff_pw_6]"f"(ff_pw_6), - [ff_pw_9]"f"(ff_pw_9), [ff_pw_12]"f"(ff_pw_12), - [ff_pw_15]"f"(ff_pw_15), [ff_pw_16]"f"(ff_pw_16) - : "memory" - ); - - src = block; - - // 2nd loop - __asm__ volatile ( - "li %[tmp0], 0x07 \n\t" - "xor %[ftmp0], %[ftmp0], %[ftmp0] \n\t" - "mtc1 %[tmp0], %[ftmp9] \n\t" - - // dest low 32bit - MMI_LDC1(%[ftmp1], %[src], 0x00) - MMI_LDC1(%[ftmp2], %[src], 0x20) - MMI_LDC1(%[ftmp3], %[src], 0x30) - MMI_LDC1(%[ftmp4], %[src], 0x10) - - VC1_INV_TRANCS_4_STEP1_MMI(%[ftmp1], %[ftmp2], %[ftmp3], %[ftmp4], - %[ftmp5], %[ftmp6], %[ftmp7], %[ftmp8], - %[ff_pw_17], %[ff_pw_10], %[ff_pw_22], - %[ff_pw_64]) - - PSRAH_4_MMI(%[ftmp1], %[ftmp2], %[ftmp3], %[ftmp4], %[ftmp9]) - - MMI_LWC1(%[ftmp5], %[dest], 0x00) - PTR_ADDU "%[addr0], %[dest], %[linesize] \n\t" - MMI_LWC1(%[ftmp6], %[addr0], 0x00) - PTR_ADDU "%[addr0], %[addr0], %[linesize] \n\t" - MMI_LWC1(%[ftmp7], %[addr0], 0x00) - PTR_ADDU "%[addr0], %[addr0], %[linesize] \n\t" - MMI_LWC1(%[ftmp8], %[addr0], 0x00) - - VC1_INV_TRANCS_4_STEP2_MMI(%[ftmp1], %[ftmp2], %[ftmp3], %[ftmp4], - %[ftmp5], %[ftmp6], %[ftmp7], %[ftmp8], - %[ftmp0]) - - MMI_SWC1(%[ftmp1], %[dest], 0x00) - PTR_ADDU "%[addr0], %[dest], %[linesize] \n\t" - MMI_SWC1(%[ftmp2], %[addr0], 0x00) - PTR_ADDU "%[addr0], %[addr0], %[linesize] \n\t" - MMI_SWC1(%[ftmp3], %[addr0], 0x00) - PTR_ADDU "%[addr0], %[addr0], %[linesize] \n\t" - MMI_SWC1(%[ftmp4], %[addr0], 0x00) - - // dest high 32bit - MMI_LDC1(%[ftmp1], %[src], 0x08) - MMI_LDC1(%[ftmp2], %[src], 0x28) - MMI_LDC1(%[ftmp3], %[src], 0x38) - MMI_LDC1(%[ftmp4], %[src], 0x18) - - VC1_INV_TRANCS_4_STEP1_MMI(%[ftmp1], %[ftmp2], %[ftmp3], %[ftmp4], - %[ftmp5], %[ftmp6], %[ftmp7], %[ftmp8], - %[ff_pw_17], %[ff_pw_10], %[ff_pw_22], - %[ff_pw_64]) - - PSRAH_4_MMI(%[ftmp1], %[ftmp2], %[ftmp3], %[ftmp4], %[ftmp9]) - - MMI_LWC1(%[ftmp5], %[dest], 0x04) - PTR_ADDU "%[addr0], %[dest], %[linesize] \n\t" - MMI_LWC1(%[ftmp6], %[addr0], 0x04) - PTR_ADDU "%[addr0], %[addr0], %[linesize] \n\t" - MMI_LWC1(%[ftmp7], %[addr0], 0x04) - PTR_ADDU "%[addr0], %[addr0], %[linesize] \n\t" - MMI_LWC1(%[ftmp8], %[addr0], 0x04) - - VC1_INV_TRANCS_4_STEP2_MMI(%[ftmp1], %[ftmp2], %[ftmp3], %[ftmp4], - %[ftmp5], %[ftmp6], %[ftmp7], %[ftmp8], - %[ftmp0]) - - MMI_SWC1(%[ftmp1], %[dest], 0x04) - PTR_ADDU "%[addr0], %[dest], %[linesize] \n\t" - MMI_SWC1(%[ftmp2], %[addr0], 0x04) - PTR_ADDU "%[addr0], %[addr0], %[linesize] \n\t" - MMI_SWC1(%[ftmp3], %[addr0], 0x04) - PTR_ADDU "%[addr0], %[addr0], %[linesize] \n\t" - MMI_SWC1(%[ftmp4], %[addr0], 0x04) - - : [ftmp0]"=&f"(ftmp[0]), [ftmp1]"=&f"(ftmp[1]), - [ftmp2]"=&f"(ftmp[2]), [ftmp3]"=&f"(ftmp[3]), - [ftmp4]"=&f"(ftmp[4]), [ftmp5]"=&f"(ftmp[5]), - [ftmp6]"=&f"(ftmp[6]), [ftmp7]"=&f"(ftmp[7]), - [ftmp8]"=&f"(ftmp[8]), [ftmp9]"=&f"(ftmp[9]), - [tmp0]"=&r"(tmp[0]), - RESTRICT_ASM_LOW32 - [addr0]"=&r"(addr[0]) - : [src]"r"(src), [dest]"r"(dest), - [linesize]"r"((mips_reg)linesize), - [ff_pw_17]"f"(ff_pw_17), [ff_pw_22]"f"(ff_pw_22), - [ff_pw_10]"f"(ff_pw_10), [ff_pw_64]"f"(ff_pw_64) - : "memory" + : [ff_pw_64]"f"(ff_pw_64_local), + [src]"r"(src), [dest]"r"(dest), [linesize]"r"(linesize) + :"memory" ); } #endif @@ -676,47 +941,51 @@ void ff_vc1_inv_trans_4x8_mmi(uint8_t *dest, ptrdiff_t linesize, int16_t *block) { int16_t *src = block; int16_t *dst = block; - double ftmp[16]; - uint32_t count, tmp[1]; - mips_reg addr[1]; - DECLARE_VAR_LOW32; + double ftmp[23]; + uint32_t count = 8, tmp[1]; + int16_t coeff[16] = {17, 22, 17, 10, + 17, 10,-17,-22, + 17,-10,-17, 22, + 17,-22, 17,-10}; + DECLARE_ALIGNED(8, const uint64_t, ff_pw_1_local) = {0x0000000100000001ULL}; + DECLARE_ALIGNED(8, const uint64_t, ff_pw_4_local) = {0x0000000400000004ULL}; + DECLARE_ALIGNED(8, const uint64_t, ff_pw_64_local)= {0x0000004000000040ULL}; // 1st loop __asm__ volatile ( - "li %[count], 0x02 \n\t" + "li %[tmp0], 0x03 \n\t" "mtc1 %[tmp0], %[ftmp0] \n\t" + MMI_LDC1(%[ftmp2], %[coeff], 0x00) + MMI_LDC1(%[ftmp3], %[coeff], 0x08) + MMI_LDC1(%[ftmp4], %[coeff], 0x10) + MMI_LDC1(%[ftmp5], %[coeff], 0x18) "1: \n\t" + /* ftmp8: dst3,dst2,dst1,dst0 */ MMI_LDC1(%[ftmp1], %[src], 0x00) - MMI_LDC1(%[ftmp2], %[src], 0x10) - MMI_LDC1(%[ftmp3], %[src], 0x20) - MMI_LDC1(%[ftmp4], %[src], 0x30) + "pmaddhw %[ftmp6], %[ftmp2], %[ftmp1] \n\t" + "pmaddhw %[ftmp7], %[ftmp3], %[ftmp1] \n\t" + "pmaddhw %[ftmp8], %[ftmp4], %[ftmp1] \n\t" + "pmaddhw %[ftmp9], %[ftmp5], %[ftmp1] \n\t" + "punpcklwd %[ftmp10], %[ftmp6], %[ftmp7] \n\t" + "punpckhwd %[ftmp11], %[ftmp6], %[ftmp7] \n\t" + "punpcklwd %[ftmp6], %[ftmp8], %[ftmp9] \n\t" + "punpckhwd %[ftmp7], %[ftmp8], %[ftmp9] \n\t" + "paddw %[ftmp8], %[ftmp10], %[ftmp11] \n\t" + "paddw %[ftmp9], %[ftmp6], %[ftmp7] \n\t" + "paddw %[ftmp8], %[ftmp8], %[ff_pw_4] \n\t" + "paddw %[ftmp9], %[ftmp9], %[ff_pw_4] \n\t" + "psraw %[ftmp8], %[ftmp8], %[ftmp0] \n\t" + "psraw %[ftmp9], %[ftmp9], %[ftmp0] \n\t" + "punpcklhw %[ftmp6], %[ftmp8], %[ftmp9] \n\t" + "punpckhhw %[ftmp7], %[ftmp8], %[ftmp9] \n\t" + "punpcklhw %[ftmp8], %[ftmp6], %[ftmp7] \n\t" + MMI_SDC1(%[ftmp8], %[dst], 0x00) - TRANSPOSE_4H(%[ftmp1], %[ftmp2], %[ftmp3], %[ftmp4], - %[ftmp5], %[ftmp6], %[ftmp7], %[ftmp8], - %[ftmp9], %[tmp0], %[ftmp10], %[ftmp11]) - - // t1 t2 t3 t4 - VC1_INV_TRANCS_4_STEP1_MMI(%[ftmp1], %[ftmp3], %[ftmp4], %[ftmp2], - %[ftmp5], %[ftmp6], %[ftmp7], %[ftmp8], - %[ff_pw_17], %[ff_pw_10], %[ff_pw_22], - %[ff_pw_4]) - - PSRAH_4_MMI(%[ftmp1], %[ftmp3], %[ftmp4], %[ftmp2], %[ftmp0]) - - TRANSPOSE_4H(%[ftmp1], %[ftmp3], %[ftmp4], %[ftmp2], - %[ftmp5], %[ftmp6], %[ftmp7], %[ftmp8], - %[ftmp9], %[tmp0], %[ftmp10], %[ftmp11]) - - MMI_SDC1(%[ftmp1], %[dst], 0x00) - MMI_SDC1(%[ftmp3], %[dst], 0x10) - MMI_SDC1(%[ftmp4], %[dst], 0x20) - MMI_SDC1(%[ftmp2], %[dst], 0x30) - - "addiu %[count], %[count], -0x01 \n\t" - PTR_ADDIU "%[src], %[src], 0x40 \n\t" - PTR_ADDIU "%[dst], %[dst], 0x40 \n\t" + PTR_ADDIU "%[src], %[src], 0x10 \n\t" + PTR_ADDIU "%[dst], %[dst], 0x10 \n\t" + "addiu %[count], %[count], -0x01 \n\t" "bnez %[count], 1b \n\t" : [ftmp0]"=&f"(ftmp[0]), [ftmp1]"=&f"(ftmp[1]), [ftmp2]"=&f"(ftmp[2]), [ftmp3]"=&f"(ftmp[3]), @@ -724,11 +993,9 @@ void ff_vc1_inv_trans_4x8_mmi(uint8_t *dest, ptrdiff_t linesize, int16_t *block) [ftmp6]"=&f"(ftmp[6]), [ftmp7]"=&f"(ftmp[7]), [ftmp8]"=&f"(ftmp[8]), [ftmp9]"=&f"(ftmp[9]), [ftmp10]"=&f"(ftmp[10]), [ftmp11]"=&f"(ftmp[11]), - [tmp0]"=&r"(tmp[0]), - [count]"=&r"(count), + [tmp0]"=&r"(tmp[0]), [count]"+&r"(count), [src]"+&r"(src), [dst]"+&r"(dst) - : [ff_pw_17]"f"(ff_pw_17), [ff_pw_10]"f"(ff_pw_10), - [ff_pw_22]"f"(ff_pw_22), [ff_pw_4]"f"(ff_pw_4) + : [ff_pw_4]"f"(ff_pw_4_local), [coeff]"r"(coeff) : "memory" ); @@ -739,99 +1006,114 @@ void ff_vc1_inv_trans_4x8_mmi(uint8_t *dest, ptrdiff_t linesize, int16_t *block) "li %[tmp0], 0x07 \n\t" "mtc1 %[tmp0], %[ftmp0] \n\t" - MMI_LDC1(%[ftmp5], %[src], 0x10) - MMI_LDC1(%[ftmp6], %[src], 0x30) - MMI_LDC1(%[ftmp7], %[src], 0x50) - MMI_LDC1(%[ftmp8], %[src], 0x70) - - VC1_INV_TRANCS_8_STEP1_MMI(%[ftmp5], %[ftmp6], %[ftmp7], %[ftmp8], - %[ftmp9], %[ftmp10], %[ftmp11], %[ftmp12], - %[ftmp1], %[ftmp2], %[ftmp3], %[ftmp4], - %[ff_pw_16], %[ff_pw_15], %[ff_pw_9], - %[ff_pw_4]) - MMI_LDC1(%[ftmp1], %[src], 0x00) - MMI_LDC1(%[ftmp2], %[src], 0x40) - MMI_LDC1(%[ftmp3], %[src], 0x20) + MMI_LDC1(%[ftmp2], %[src], 0x20) + MMI_LDC1(%[ftmp3], %[src], 0x40) MMI_LDC1(%[ftmp4], %[src], 0x60) + "punpcklhw %[ftmp5], %[ftmp1], %[ftmp2] \n\t" + "punpckhhw %[ftmp6], %[ftmp1], %[ftmp2] \n\t" + "punpcklhw %[ftmp7], %[ftmp3], %[ftmp4] \n\t" + "punpckhhw %[ftmp8], %[ftmp3], %[ftmp4] \n\t" - VC1_INV_TRANCS_8_STEP2_MMI(%[ftmp1], %[ftmp2], %[ftmp3], %[ftmp4], - %[ftmp5], %[ftmp6], %[ftmp7], %[ftmp8], - %[ftmp9], %[ftmp10], %[ftmp11], %[ftmp12], - %[ff_pw_12], %[ff_pw_16], %[ff_pw_6], - %[ff_pw_64]) + MMI_LDC1(%[ftmp1], %[src], 0x10) + MMI_LDC1(%[ftmp2], %[src], 0x30) + MMI_LDC1(%[ftmp3], %[src], 0x50) + MMI_LDC1(%[ftmp4], %[src], 0x70) + "punpcklhw %[ftmp9], %[ftmp1], %[ftmp2] \n\t" + "punpckhhw %[ftmp10], %[ftmp1], %[ftmp2] \n\t" + "punpcklhw %[ftmp11], %[ftmp3], %[ftmp4] \n\t" + "punpckhhw %[ftmp12], %[ftmp3], %[ftmp4] \n\t" - "paddh %[ftmp4], %[ftmp4], %[ff_pw_1] \n\t" - "paddh %[ftmp3], %[ftmp3], %[ff_pw_1] \n\t" - "paddh %[ftmp2], %[ftmp2], %[ff_pw_1] \n\t" - "paddh %[ftmp1], %[ftmp1], %[ff_pw_1] \n\t" + /* ftmp15:dst03,dst02,dst01,dst00 ftmp22:dst73,dst72,dst71,dst70 */ + VC1_INV_TRANCS_8_TYPE2(%[ftmp15], %[ftmp22], 0x0010000c, 0x0006000c, + 0x000f0010, 0x00040009, %[ff_pw_64], %[ff_pw_1]) - PSRAH_8_MMI(%[ftmp5], %[ftmp6], %[ftmp7], %[ftmp8], - %[ftmp4], %[ftmp3], %[ftmp2], %[ftmp1], %[ftmp0]) + /* ftmp16:dst13,dst12,dst11,dst10 ftmp21:dst63,dst62,dst61,dst60 */ + VC1_INV_TRANCS_8_TYPE2(%[ftmp16], %[ftmp21], 0x0006000c, 0xfff0fff4, + 0xfffc000f, 0xfff7fff0, %[ff_pw_64], %[ff_pw_1]) + /* ftmp17:dst23,dst22,dst21,dst20 ftmp20:dst53,dst52,dst51,dst50 */ + VC1_INV_TRANCS_8_TYPE2(%[ftmp17], %[ftmp20], 0xfffa000c, 0x0010fff4, + 0xfff00009, 0x000f0004, %[ff_pw_64], %[ff_pw_1]) + + /* ftmp18:dst33,dst32,dst31,dst30 ftmp19:dst43,dst42,dst41,dst40 */ + VC1_INV_TRANCS_8_TYPE2(%[ftmp18], %[ftmp19], 0xfff0000c, 0xfffa000c, + 0xfff70004, 0xfff0000f, %[ff_pw_64], %[ff_pw_1]) + + MMI_LWC1(%[ftmp1], %[dest], 0x00) + PTR_ADDU "%[tmp0], %[dest], %[linesize] \n\t" + MMI_LWC1(%[ftmp2], %[tmp0], 0x00) + PTR_ADDU "%[tmp0], %[tmp0], %[linesize] \n\t" + MMI_LWC1(%[ftmp3], %[tmp0], 0x00) + PTR_ADDU "%[tmp0], %[tmp0], %[linesize] \n\t" + MMI_LWC1(%[ftmp4], %[tmp0], 0x00) + PTR_ADDU "%[tmp0], %[tmp0], %[linesize] \n\t" + MMI_LWC1(%[ftmp5], %[tmp0], 0x00) + PTR_ADDU "%[tmp0], %[tmp0], %[linesize] \n\t" + MMI_LWC1(%[ftmp6], %[tmp0], 0x00) + PTR_ADDU "%[tmp0], %[tmp0], %[linesize] \n\t" + MMI_LWC1(%[ftmp7], %[tmp0], 0x00) + PTR_ADDU "%[tmp0], %[tmp0], %[linesize] \n\t" + MMI_LWC1(%[ftmp8], %[tmp0], 0x00) "xor %[ftmp0], %[ftmp0], %[ftmp0] \n\t" + "punpcklbh %[ftmp1], %[ftmp1], %[ftmp0] \n\t" + "punpcklbh %[ftmp2], %[ftmp2], %[ftmp0] \n\t" + "punpcklbh %[ftmp3], %[ftmp3], %[ftmp0] \n\t" + "punpcklbh %[ftmp4], %[ftmp4], %[ftmp0] \n\t" + "punpcklbh %[ftmp5], %[ftmp5], %[ftmp0] \n\t" + "punpcklbh %[ftmp6], %[ftmp6], %[ftmp0] \n\t" + "punpcklbh %[ftmp7], %[ftmp7], %[ftmp0] \n\t" + "punpcklbh %[ftmp8], %[ftmp8], %[ftmp0] \n\t" - // dest low - MMI_LWC1(%[ftmp9], %[dest], 0x00) - PTR_ADDU "%[addr0], %[dest], %[linesize] \n\t" - MMI_LWC1(%[ftmp10], %[addr0], 0x00) - PTR_ADDU "%[addr0], %[addr0], %[linesize] \n\t" - MMI_LWC1(%[ftmp11], %[addr0], 0x00) - PTR_ADDU "%[addr0], %[addr0], %[linesize] \n\t" - MMI_LWC1(%[ftmp12], %[addr0], 0x00) - PTR_ADDU "%[addr0], %[addr0], %[linesize] \n\t" + "paddh %[ftmp1], %[ftmp1], %[ftmp15] \n\t" + "paddh %[ftmp2], %[ftmp2], %[ftmp16] \n\t" + "paddh %[ftmp3], %[ftmp3], %[ftmp17] \n\t" + "paddh %[ftmp4], %[ftmp4], %[ftmp18] \n\t" + "paddh %[ftmp5], %[ftmp5], %[ftmp19] \n\t" + "paddh %[ftmp6], %[ftmp6], %[ftmp20] \n\t" + "paddh %[ftmp7], %[ftmp7], %[ftmp21] \n\t" + "paddh %[ftmp8], %[ftmp8], %[ftmp22] \n\t" - VC1_INV_TRANCS_4_STEP2_MMI(%[ftmp5], %[ftmp6], %[ftmp7], %[ftmp8], - %[ftmp9], %[ftmp10], %[ftmp11], %[ftmp12], - %[ftmp0]) + "packushb %[ftmp1], %[ftmp1], %[ftmp0] \n\t" + "packushb %[ftmp2], %[ftmp2], %[ftmp0] \n\t" + "packushb %[ftmp3], %[ftmp3], %[ftmp0] \n\t" + "packushb %[ftmp4], %[ftmp4], %[ftmp0] \n\t" + "packushb %[ftmp5], %[ftmp5], %[ftmp0] \n\t" + "packushb %[ftmp6], %[ftmp6], %[ftmp0] \n\t" + "packushb %[ftmp7], %[ftmp7], %[ftmp0] \n\t" + "packushb %[ftmp8], %[ftmp8], %[ftmp0] \n\t" - // dest high - MMI_LWC1(%[ftmp9], %[addr0], 0x00) - PTR_ADDU "%[addr0], %[addr0], %[linesize] \n\t" - MMI_LWC1(%[ftmp10], %[addr0], 0x00) - PTR_ADDU "%[addr0], %[addr0], %[linesize] \n\t" - MMI_LWC1(%[ftmp11], %[addr0], 0x00) - PTR_ADDU "%[addr0], %[addr0], %[linesize] \n\t" - MMI_LWC1(%[ftmp12], %[addr0], 0x00) + MMI_SWC1(%[ftmp1], %[dest], 0x00) + PTR_ADDU "%[tmp0], %[dest], %[linesize] \n\t" + MMI_SWC1(%[ftmp2], %[tmp0], 0x00) + PTR_ADDU "%[tmp0], %[tmp0], %[linesize] \n\t" + MMI_SWC1(%[ftmp3], %[tmp0], 0x00) + PTR_ADDU "%[tmp0], %[tmp0], %[linesize] \n\t" + MMI_SWC1(%[ftmp4], %[tmp0], 0x00) + PTR_ADDU "%[tmp0], %[tmp0], %[linesize] \n\t" + MMI_SWC1(%[ftmp5], %[tmp0], 0x00) + PTR_ADDU "%[tmp0], %[tmp0], %[linesize] \n\t" + MMI_SWC1(%[ftmp6], %[tmp0], 0x00) + PTR_ADDU "%[tmp0], %[tmp0], %[linesize] \n\t" + MMI_SWC1(%[ftmp7], %[tmp0], 0x00) + PTR_ADDU "%[tmp0], %[tmp0], %[linesize] \n\t" + MMI_SWC1(%[ftmp8], %[tmp0], 0x00) - VC1_INV_TRANCS_4_STEP2_MMI(%[ftmp4], %[ftmp3], %[ftmp2], %[ftmp1], - %[ftmp9], %[ftmp10], %[ftmp11], %[ftmp12], - %[ftmp0]) - - // dest low - MMI_SWC1(%[ftmp5], %[dest], 0x00) - PTR_ADDU "%[addr0], %[dest], %[linesize] \n\t" - MMI_SWC1(%[ftmp6], %[addr0], 0x00) - PTR_ADDU "%[addr0], %[addr0], %[linesize] \n\t" - MMI_SWC1(%[ftmp7], %[addr0], 0x00) - PTR_ADDU "%[addr0], %[addr0], %[linesize] \n\t" - MMI_SWC1(%[ftmp8], %[addr0], 0x00) - PTR_ADDU "%[addr0], %[addr0], %[linesize] \n\t" - - // dest high - MMI_SWC1(%[ftmp4], %[addr0], 0x00) - PTR_ADDU "%[addr0], %[addr0], %[linesize] \n\t" - MMI_SWC1(%[ftmp3], %[addr0], 0x00) - PTR_ADDU "%[addr0], %[addr0], %[linesize] \n\t" - MMI_SWC1(%[ftmp2], %[addr0], 0x00) - PTR_ADDU "%[addr0], %[addr0], %[linesize] \n\t" - MMI_SWC1(%[ftmp1], %[addr0], 0x00) : [ftmp0]"=&f"(ftmp[0]), [ftmp1]"=&f"(ftmp[1]), [ftmp2]"=&f"(ftmp[2]), [ftmp3]"=&f"(ftmp[3]), [ftmp4]"=&f"(ftmp[4]), [ftmp5]"=&f"(ftmp[5]), [ftmp6]"=&f"(ftmp[6]), [ftmp7]"=&f"(ftmp[7]), [ftmp8]"=&f"(ftmp[8]), [ftmp9]"=&f"(ftmp[9]), [ftmp10]"=&f"(ftmp[10]), [ftmp11]"=&f"(ftmp[11]), - [ftmp12]"=&f"(ftmp[12]), - [tmp0]"=&r"(tmp[0]), - RESTRICT_ASM_LOW32 - [addr0]"=&r"(addr[0]), - [dest]"+&r"(dest) - : [src]"r"(src), [linesize]"r"(linesize), - [ff_pw_1]"f"(ff_pw_1), [ff_pw_4]"f"(ff_pw_4), - [ff_pw_6]"f"(ff_pw_6), [ff_pw_9]"f"(ff_pw_9), - [ff_pw_12]"f"(ff_pw_12), [ff_pw_15]"f"(ff_pw_15), - [ff_pw_16]"f"(ff_pw_16), [ff_pw_64]"f"(ff_pw_64) + [ftmp12]"=&f"(ftmp[12]), [ftmp13]"=&f"(ftmp[13]), + [ftmp14]"=&f"(ftmp[14]), [ftmp15]"=&f"(ftmp[15]), + [ftmp16]"=&f"(ftmp[16]), [ftmp17]"=&f"(ftmp[17]), + [ftmp18]"=&f"(ftmp[18]), [ftmp19]"=&f"(ftmp[19]), + [ftmp20]"=&f"(ftmp[20]), [ftmp21]"=&f"(ftmp[21]), + [ftmp22]"=&f"(ftmp[22]), + [tmp0]"=&r"(tmp[0]) + : [ff_pw_1]"f"(ff_pw_1_local), [ff_pw_64]"f"(ff_pw_64_local), + [src]"r"(src), [dest]"r"(dest), [linesize]"r"(linesize) : "memory" ); } @@ -890,51 +1172,58 @@ void ff_vc1_inv_trans_4x4_mmi(uint8_t *dest, ptrdiff_t linesize, int16_t *block) { int16_t *src = block; int16_t *dst = block; - double ftmp[12]; - uint32_t tmp[1]; - mips_reg addr[1]; - DECLARE_VAR_LOW32; - + double ftmp[16]; + uint32_t count = 4, tmp[1]; + int16_t coeff[16] = {17, 22, 17, 10, + 17, 10,-17,-22, + 17,-10,-17, 22, + 17,-22, 17,-10}; + DECLARE_ALIGNED(8, const uint64_t, ff_pw_4_local) = {0x0000000400000004ULL}; + DECLARE_ALIGNED(8, const uint64_t, ff_pw_64_local)= {0x0000004000000040ULL}; // 1st loop __asm__ volatile ( + "li %[tmp0], 0x03 \n\t" "mtc1 %[tmp0], %[ftmp0] \n\t" - + MMI_LDC1(%[ftmp2], %[coeff], 0x00) + MMI_LDC1(%[ftmp3], %[coeff], 0x08) + MMI_LDC1(%[ftmp4], %[coeff], 0x10) + MMI_LDC1(%[ftmp5], %[coeff], 0x18) + "1: \n\t" + /* ftmp8: dst3,dst2,dst1,dst0 */ MMI_LDC1(%[ftmp1], %[src], 0x00) - MMI_LDC1(%[ftmp2], %[src], 0x10) - MMI_LDC1(%[ftmp3], %[src], 0x20) - MMI_LDC1(%[ftmp4], %[src], 0x30) + "pmaddhw %[ftmp6], %[ftmp2], %[ftmp1] \n\t" + "pmaddhw %[ftmp7], %[ftmp3], %[ftmp1] \n\t" + "pmaddhw %[ftmp8], %[ftmp4], %[ftmp1] \n\t" + "pmaddhw %[ftmp9], %[ftmp5], %[ftmp1] \n\t" + "punpcklwd %[ftmp10], %[ftmp6], %[ftmp7] \n\t" + "punpckhwd %[ftmp11], %[ftmp6], %[ftmp7] \n\t" + "punpcklwd %[ftmp6], %[ftmp8], %[ftmp9] \n\t" + "punpckhwd %[ftmp7], %[ftmp8], %[ftmp9] \n\t" + "paddw %[ftmp8], %[ftmp10], %[ftmp11] \n\t" + "paddw %[ftmp9], %[ftmp6], %[ftmp7] \n\t" + "paddw %[ftmp8], %[ftmp8], %[ff_pw_4] \n\t" + "paddw %[ftmp9], %[ftmp9], %[ff_pw_4] \n\t" + "psraw %[ftmp8], %[ftmp8], %[ftmp0] \n\t" + "psraw %[ftmp9], %[ftmp9], %[ftmp0] \n\t" + "punpcklhw %[ftmp6], %[ftmp8], %[ftmp9] \n\t" + "punpckhhw %[ftmp7], %[ftmp8], %[ftmp9] \n\t" + "punpcklhw %[ftmp8], %[ftmp6], %[ftmp7] \n\t" + MMI_SDC1(%[ftmp8], %[dst], 0x00) - TRANSPOSE_4H(%[ftmp1], %[ftmp2], %[ftmp3], %[ftmp4], - %[ftmp5], %[ftmp6], %[ftmp7], %[ftmp8], - %[ftmp9], %[tmp0], %[ftmp10], %[ftmp11]) - - // t1 t2 t3 t4 - VC1_INV_TRANCS_4_STEP1_MMI(%[ftmp1], %[ftmp3], %[ftmp4], %[ftmp2], - %[ftmp5], %[ftmp6], %[ftmp7], %[ftmp8], - %[ff_pw_17], %[ff_pw_10], %[ff_pw_22], - %[ff_pw_4]) - - PSRAH_4_MMI(%[ftmp1], %[ftmp3], %[ftmp4], %[ftmp2], %[ftmp0]) - - TRANSPOSE_4H(%[ftmp1], %[ftmp3], %[ftmp4], %[ftmp2], - %[ftmp5], %[ftmp6], %[ftmp7], %[ftmp8], - %[ftmp9], %[tmp0], %[ftmp10], %[ftmp11]) - - MMI_SDC1(%[ftmp1], %[dst], 0x00) - MMI_SDC1(%[ftmp3], %[dst], 0x10) - MMI_SDC1(%[ftmp4], %[dst], 0x20) - MMI_SDC1(%[ftmp2], %[dst], 0x30) + PTR_ADDIU "%[src], %[src], 0x10 \n\t" + PTR_ADDIU "%[dst], %[dst], 0x10 \n\t" + "addiu %[count], %[count], -0x01 \n\t" + "bnez %[count], 1b \n\t" : [ftmp0]"=&f"(ftmp[0]), [ftmp1]"=&f"(ftmp[1]), [ftmp2]"=&f"(ftmp[2]), [ftmp3]"=&f"(ftmp[3]), [ftmp4]"=&f"(ftmp[4]), [ftmp5]"=&f"(ftmp[5]), [ftmp6]"=&f"(ftmp[6]), [ftmp7]"=&f"(ftmp[7]), [ftmp8]"=&f"(ftmp[8]), [ftmp9]"=&f"(ftmp[9]), [ftmp10]"=&f"(ftmp[10]), [ftmp11]"=&f"(ftmp[11]), - [tmp0]"=&r"(tmp[0]), + [tmp0]"=&r"(tmp[0]), [count]"+&r"(count), [src]"+&r"(src), [dst]"+&r"(dst) - : [ff_pw_17]"f"(ff_pw_17), [ff_pw_10]"f"(ff_pw_10), - [ff_pw_22]"f"(ff_pw_22), [ff_pw_4]"f"(ff_pw_4) + : [ff_pw_4]"f"(ff_pw_4_local), [coeff]"r"(coeff) : "memory" ); @@ -944,54 +1233,143 @@ void ff_vc1_inv_trans_4x4_mmi(uint8_t *dest, ptrdiff_t linesize, int16_t *block) __asm__ volatile ( "li %[tmp0], 0x07 \n\t" "mtc1 %[tmp0], %[ftmp0] \n\t" + "li %[tmp0], 0x44 \n\t" + "mtc1 %[tmp0], %[ftmp15] \n\t" - // dest low 32bit MMI_LDC1(%[ftmp1], %[src], 0x00) - MMI_LDC1(%[ftmp2], %[src], 0x20) - MMI_LDC1(%[ftmp3], %[src], 0x30) - MMI_LDC1(%[ftmp4], %[src], 0x10) + MMI_LDC1(%[ftmp2], %[src], 0x10) + MMI_LDC1(%[ftmp3], %[src], 0x20) + MMI_LDC1(%[ftmp4], %[src], 0x30) + "punpcklhw %[ftmp5], %[ftmp1], %[ftmp2] \n\t" + "punpckhhw %[ftmp6], %[ftmp1], %[ftmp2] \n\t" + "punpcklhw %[ftmp7], %[ftmp3], %[ftmp4] \n\t" + "punpckhhw %[ftmp8], %[ftmp3], %[ftmp4] \n\t" - VC1_INV_TRANCS_4_STEP1_MMI(%[ftmp1], %[ftmp2], %[ftmp3], %[ftmp4], - %[ftmp5], %[ftmp6], %[ftmp7], %[ftmp8], - %[ff_pw_17], %[ff_pw_10], %[ff_pw_22], - %[ff_pw_64]) + /* ftmp11: dst03,dst02,dst01,dst00 */ + "li %[tmp0], 0x00160011 \n\t" + "mtc1 %[tmp0], %[ftmp3] \n\t" + "pshufh %[ftmp3], %[ftmp3], %[ftmp15] \n\t" + "li %[tmp0], 0x000a0011 \n\t" + "mtc1 %[tmp0], %[ftmp4] \n\t" + "pshufh %[ftmp4], %[ftmp4], %[ftmp15] \n\t" + "pmaddhw %[ftmp1], %[ftmp5], %[ftmp3] \n\t" + "pmaddhw %[ftmp2], %[ftmp7], %[ftmp4] \n\t" + "paddw %[ftmp9], %[ftmp1], %[ftmp2] \n\t" + "pmaddhw %[ftmp1], %[ftmp6], %[ftmp3] \n\t" + "pmaddhw %[ftmp2], %[ftmp8], %[ftmp4] \n\t" + "paddw %[ftmp10], %[ftmp1], %[ftmp2] \n\t" + "paddw %[ftmp9], %[ftmp9], %[ff_pw_64] \n\t" + "paddw %[ftmp10], %[ftmp10], %[ff_pw_64] \n\t" + "psraw %[ftmp9], %[ftmp9], %[ftmp0] \n\t" + "psraw %[ftmp10], %[ftmp10], %[ftmp0] \n\t" + "punpcklhw %[ftmp1], %[ftmp9], %[ftmp10] \n\t" + "punpckhhw %[ftmp2], %[ftmp9], %[ftmp10] \n\t" + "punpcklhw %[ftmp11], %[ftmp1], %[ftmp2] \n\t" - PSRAH_4_MMI(%[ftmp1], %[ftmp2], %[ftmp3], %[ftmp4], %[ftmp0]) + /* ftmp12: dst13,dst12,dst11,dst10 */ + "li %[tmp0], 0x000a0011 \n\t" + "mtc1 %[tmp0], %[ftmp3] \n\t" + "pshufh %[ftmp3], %[ftmp3], %[ftmp15] \n\t" + "li %[tmp0], 0xffeaffef \n\t" + "mtc1 %[tmp0], %[ftmp4] \n\t" + "pshufh %[ftmp4], %[ftmp4], %[ftmp15] \n\t" + "pmaddhw %[ftmp1], %[ftmp5], %[ftmp3] \n\t" + "pmaddhw %[ftmp2], %[ftmp7], %[ftmp4] \n\t" + "paddw %[ftmp9], %[ftmp1], %[ftmp2] \n\t" + "pmaddhw %[ftmp1], %[ftmp6], %[ftmp3] \n\t" + "pmaddhw %[ftmp2], %[ftmp8], %[ftmp4] \n\t" + "paddw %[ftmp10], %[ftmp1], %[ftmp2] \n\t" + "paddw %[ftmp9], %[ftmp9], %[ff_pw_64] \n\t" + "paddw %[ftmp10], %[ftmp10], %[ff_pw_64] \n\t" + "psraw %[ftmp9], %[ftmp9], %[ftmp0] \n\t" + "psraw %[ftmp10], %[ftmp10], %[ftmp0] \n\t" + "punpcklhw %[ftmp1], %[ftmp9], %[ftmp10] \n\t" + "punpckhhw %[ftmp2], %[ftmp9], %[ftmp10] \n\t" + "punpcklhw %[ftmp12], %[ftmp1], %[ftmp2] \n\t" - MMI_LWC1(%[ftmp5], %[dest], 0x00) - PTR_ADDU "%[addr0], %[dest], %[linesize] \n\t" - MMI_LWC1(%[ftmp6], %[addr0], 0x00) - PTR_ADDU "%[addr0], %[addr0], %[linesize] \n\t" - MMI_LWC1(%[ftmp7], %[addr0], 0x00) - PTR_ADDU "%[addr0], %[addr0], %[linesize] \n\t" - MMI_LWC1(%[ftmp8], %[addr0], 0x00) + /* ftmp13: dst23,dst22,dst21,dst20 */ + "li %[tmp0], 0xfff60011 \n\t" + "mtc1 %[tmp0], %[ftmp3] \n\t" + "pshufh %[ftmp3], %[ftmp3], %[ftmp15] \n\t" + "li %[tmp0], 0x0016ffef \n\t" + "mtc1 %[tmp0], %[ftmp4] \n\t" + "pshufh %[ftmp4], %[ftmp4], %[ftmp15] \n\t" + "pmaddhw %[ftmp1], %[ftmp5], %[ftmp3] \n\t" + "pmaddhw %[ftmp2], %[ftmp7], %[ftmp4] \n\t" + "paddw %[ftmp9], %[ftmp1], %[ftmp2] \n\t" + "pmaddhw %[ftmp1], %[ftmp6], %[ftmp3] \n\t" + "pmaddhw %[ftmp2], %[ftmp8], %[ftmp4] \n\t" + "paddw %[ftmp10], %[ftmp1], %[ftmp2] \n\t" + "paddw %[ftmp9], %[ftmp9], %[ff_pw_64] \n\t" + "paddw %[ftmp10], %[ftmp10], %[ff_pw_64] \n\t" + "psraw %[ftmp9], %[ftmp9], %[ftmp0] \n\t" + "psraw %[ftmp10], %[ftmp10], %[ftmp0] \n\t" + "punpcklhw %[ftmp1], %[ftmp9], %[ftmp10] \n\t" + "punpckhhw %[ftmp2], %[ftmp9], %[ftmp10] \n\t" + "punpcklhw %[ftmp13], %[ftmp1], %[ftmp2] \n\t" - "xor %[ftmp9], %[ftmp9], %[ftmp9] \n\t" + /* ftmp14: dst33,dst32,dst31,dst30 */ + "li %[tmp0], 0xffea0011 \n\t" + "mtc1 %[tmp0], %[ftmp3] \n\t" + "pshufh %[ftmp3], %[ftmp3], %[ftmp15] \n\t" + "li %[tmp0], 0xfff60011 \n\t" + "mtc1 %[tmp0], %[ftmp4] \n\t" + "pshufh %[ftmp4], %[ftmp4], %[ftmp15] \n\t" + "pmaddhw %[ftmp1], %[ftmp5], %[ftmp3] \n\t" + "pmaddhw %[ftmp2], %[ftmp7], %[ftmp4] \n\t" + "paddw %[ftmp9], %[ftmp1], %[ftmp2] \n\t" + "pmaddhw %[ftmp1], %[ftmp6], %[ftmp3] \n\t" + "pmaddhw %[ftmp2], %[ftmp8], %[ftmp4] \n\t" + "paddw %[ftmp10], %[ftmp1], %[ftmp2] \n\t" + "paddw %[ftmp9], %[ftmp9], %[ff_pw_64] \n\t" + "paddw %[ftmp10], %[ftmp10], %[ff_pw_64] \n\t" + "psraw %[ftmp9], %[ftmp9], %[ftmp0] \n\t" + "psraw %[ftmp10], %[ftmp10], %[ftmp0] \n\t" + "punpcklhw %[ftmp1], %[ftmp9], %[ftmp10] \n\t" + "punpckhhw %[ftmp2], %[ftmp9], %[ftmp10] \n\t" + "punpcklhw %[ftmp14], %[ftmp1], %[ftmp2] \n\t" - VC1_INV_TRANCS_4_STEP2_MMI(%[ftmp1], %[ftmp2], %[ftmp3], %[ftmp4], - %[ftmp5], %[ftmp6], %[ftmp7], %[ftmp8], - %[ftmp9]) + MMI_LWC1(%[ftmp1], %[dest], 0x00) + PTR_ADDU "%[tmp0], %[dest], %[linesize] \n\t" + MMI_LWC1(%[ftmp2], %[tmp0], 0x00) + PTR_ADDU "%[tmp0], %[tmp0], %[linesize] \n\t" + MMI_LWC1(%[ftmp3], %[tmp0], 0x00) + PTR_ADDU "%[tmp0], %[tmp0], %[linesize] \n\t" + MMI_LWC1(%[ftmp4], %[tmp0], 0x00) + "xor %[ftmp0], %[ftmp0], %[ftmp0] \n\t" + "punpcklbh %[ftmp1], %[ftmp1], %[ftmp0] \n\t" + "punpcklbh %[ftmp2], %[ftmp2], %[ftmp0] \n\t" + "punpcklbh %[ftmp3], %[ftmp3], %[ftmp0] \n\t" + "punpcklbh %[ftmp4], %[ftmp4], %[ftmp0] \n\t" + "paddh %[ftmp1], %[ftmp1], %[ftmp11] \n\t" + "paddh %[ftmp2], %[ftmp2], %[ftmp12] \n\t" + "paddh %[ftmp3], %[ftmp3], %[ftmp13] \n\t" + "paddh %[ftmp4], %[ftmp4], %[ftmp14] \n\t" + "packushb %[ftmp1], %[ftmp1], %[ftmp0] \n\t" + "packushb %[ftmp2], %[ftmp2], %[ftmp0] \n\t" + "packushb %[ftmp3], %[ftmp3], %[ftmp0] \n\t" + "packushb %[ftmp4], %[ftmp4], %[ftmp0] \n\t" MMI_SWC1(%[ftmp1], %[dest], 0x00) - PTR_ADDU "%[addr0], %[dest], %[linesize] \n\t" - MMI_SWC1(%[ftmp2], %[addr0], 0x00) - PTR_ADDU "%[addr0], %[addr0], %[linesize] \n\t" - MMI_SWC1(%[ftmp3], %[addr0], 0x00) - PTR_ADDU "%[addr0], %[addr0], %[linesize] \n\t" - MMI_SWC1(%[ftmp4], %[addr0], 0x00) + PTR_ADDU "%[tmp0], %[dest], %[linesize] \n\t" + MMI_SWC1(%[ftmp2], %[tmp0], 0x00) + PTR_ADDU "%[tmp0], %[tmp0], %[linesize] \n\t" + MMI_SWC1(%[ftmp3], %[tmp0], 0x00) + PTR_ADDU "%[tmp0], %[tmp0], %[linesize] \n\t" + MMI_SWC1(%[ftmp4], %[tmp0], 0x00) + : [ftmp0]"=&f"(ftmp[0]), [ftmp1]"=&f"(ftmp[1]), [ftmp2]"=&f"(ftmp[2]), [ftmp3]"=&f"(ftmp[3]), [ftmp4]"=&f"(ftmp[4]), [ftmp5]"=&f"(ftmp[5]), [ftmp6]"=&f"(ftmp[6]), [ftmp7]"=&f"(ftmp[7]), [ftmp8]"=&f"(ftmp[8]), [ftmp9]"=&f"(ftmp[9]), - [tmp0]"=&r"(tmp[0]), - RESTRICT_ASM_LOW32 - [addr0]"=&r"(addr[0]) - : [src]"r"(src), [dest]"r"(dest), - [linesize]"r"((mips_reg)linesize), - [ff_pw_17]"f"(ff_pw_17), [ff_pw_22]"f"(ff_pw_22), - [ff_pw_10]"f"(ff_pw_10), [ff_pw_64]"f"(ff_pw_64) - : "memory" + [ftmp10]"=&f"(ftmp[10]), [ftmp11]"=&f"(ftmp[11]), + [ftmp12]"=&f"(ftmp[12]), [ftmp13]"=&f"(ftmp[13]), + [ftmp14]"=&f"(ftmp[14]), [ftmp15]"=&f"(ftmp[15]), + [tmp0]"=&r"(tmp[0]) + : [ff_pw_64]"f"(ff_pw_64_local), + [src]"r"(src), [dest]"r"(dest), [linesize]"r"(linesize) + :"memory" ); } @@ -1019,12 +1397,13 @@ void ff_vc1_h_overlap_mmi(uint8_t *src, int stride) } } -void ff_vc1_h_s_overlap_mmi(int16_t *left, int16_t *right) +void ff_vc1_h_s_overlap_mmi(int16_t *left, int16_t *right, int left_stride, int right_stride, int flags) { int i; int a, b, c, d; int d1, d2; - int rnd1 = 4, rnd2 = 3; + int rnd1 = flags & 2 ? 3 : 4; + int rnd2 = 7 - rnd1; for (i = 0; i < 8; i++) { a = left[6]; b = left[7]; @@ -1038,10 +1417,12 @@ void ff_vc1_h_s_overlap_mmi(int16_t *left, int16_t *right) right[0] = ((c << 3) + d2 + rnd1) >> 3; right[1] = ((d << 3) + d1 + rnd2) >> 3; - right += 8; - left += 8; - rnd2 = 7 - rnd2; - rnd1 = 7 - rnd1; + right += right_stride; + left += left_stride; + if (flags & 1) { + rnd2 = 7 - rnd2; + rnd1 = 7 - rnd1; + } } } @@ -1433,8 +1814,8 @@ static void OPNAME ## vc1_shift2_mmi(uint8_t *dst, const uint8_t *src, \ : RESTRICT_ASM_LOW32 RESTRICT_ASM_ADDRT \ [src]"+r"(src), [dst]"+r"(dst) \ : [offset]"r"(offset), [offset_x2n]"r"(-2*offset), \ - [stride]"g"(stride), [rnd]"m"(rnd), \ - [stride1]"g"(stride-offset), \ + [stride]"r"(stride), [rnd]"m"(rnd), \ + [stride1]"r"(stride-offset), \ [ff_pw_9]"m"(ff_pw_9) \ : "$8", "$9", "$10", "$f0", "$f2", "$f4", "$f6", "$f8", "$f10", \ "$f12", "$f14", "$f16", "memory" \ @@ -1658,7 +2039,7 @@ OPNAME ## vc1_## NAME ## _mmi(uint8_t *dst, const uint8_t *src, \ [h]"+r"(h), \ [src]"+r"(src), [dst]"+r"(dst) \ : [offset_x1]"r"(offset), [offset_x2]"r"(2*offset), \ - [offset_x3]"r"(3*offset), [stride]"g"(stride), \ + [offset_x3]"r"(3*offset), [stride]"r"(stride), \ [rnd]"m"(rnd), \ [ff_pw_53]"m"(ff_pw_53), [ff_pw_18]"m"(ff_pw_18), \ [ff_pw_3]"f"(ff_pw_3) \ diff --git a/libavcodec/mips/vp3dsp_idct_mmi.c b/libavcodec/mips/vp3dsp_idct_mmi.c new file mode 100644 index 000000000..c5c4cf312 --- /dev/null +++ b/libavcodec/mips/vp3dsp_idct_mmi.c @@ -0,0 +1,769 @@ +/* + * Copyright (c) 2018 gxw + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "vp3dsp_mips.h" +#include "libavutil/intreadwrite.h" +#include "libavutil/mips/mmiutils.h" +#include "libavutil/common.h" +#include "libavcodec/rnd_avg.h" + +#define LOAD_CONST(dst, value) \ + "li %[tmp1], "#value" \n\t" \ + "dmtc1 %[tmp1], "#dst" \n\t" \ + "pshufh "#dst", "#dst", %[ftmp10] \n\t" + +static void idct_row_mmi(int16_t *input) +{ + double ftmp[23]; + uint64_t tmp[2]; + __asm__ volatile ( + "xor %[ftmp10], %[ftmp10], %[ftmp10] \n\t" + LOAD_CONST(%[csth_1], 1) + "li %[tmp0], 0x02 \n\t" + "1: \n\t" + /* Load input */ + "ldc1 %[ftmp0], 0x00(%[input]) \n\t" + "ldc1 %[ftmp1], 0x10(%[input]) \n\t" + "ldc1 %[ftmp2], 0x20(%[input]) \n\t" + "ldc1 %[ftmp3], 0x30(%[input]) \n\t" + "ldc1 %[ftmp4], 0x40(%[input]) \n\t" + "ldc1 %[ftmp5], 0x50(%[input]) \n\t" + "ldc1 %[ftmp6], 0x60(%[input]) \n\t" + "ldc1 %[ftmp7], 0x70(%[input]) \n\t" + LOAD_CONST(%[ftmp8], 64277) + LOAD_CONST(%[ftmp9], 12785) + "pmulhh %[A], %[ftmp9], %[ftmp7] \n\t" + "pcmpgth %[C], %[ftmp10], %[ftmp1] \n\t" + "or %[mask], %[C], %[csth_1] \n\t" + "pmullh %[B], %[ftmp1], %[mask] \n\t" + "pmulhuh %[B], %[ftmp8], %[B] \n\t" + "pmullh %[B], %[B], %[mask] \n\t" + "paddh %[A], %[A], %[B] \n\t" + "paddh %[A], %[A], %[C] \n\t" + "pcmpgth %[D], %[ftmp10], %[ftmp7] \n\t" + "or %[mask], %[D], %[csth_1] \n\t" + "pmullh %[ftmp7], %[ftmp7], %[mask] \n\t" + "pmulhuh %[B], %[ftmp8], %[ftmp7] \n\t" + "pmullh %[B], %[B], %[mask] \n\t" + "pmulhh %[C], %[ftmp9], %[ftmp1] \n\t" + "psubh %[B], %[C], %[B] \n\t" + "psubh %[B], %[B], %[D] \n\t" + + LOAD_CONST(%[ftmp8], 54491) + LOAD_CONST(%[ftmp9], 36410) + "pcmpgth %[Ad], %[ftmp10], %[ftmp5] \n\t" + "or %[mask], %[Ad], %[csth_1] \n\t" + "pmullh %[ftmp1], %[ftmp5], %[mask] \n\t" + "pmulhuh %[C], %[ftmp9], %[ftmp1] \n\t" + "pmullh %[C], %[C], %[mask] \n\t" + "pcmpgth %[Bd], %[ftmp10], %[ftmp3] \n\t" + "or %[mask], %[Bd], %[csth_1] \n\t" + "pmullh %[D], %[ftmp3], %[mask] \n\t" + "pmulhuh %[D], %[ftmp8], %[D] \n\t" + "pmullh %[D], %[D], %[mask] \n\t" + "paddh %[C], %[C], %[D] \n\t" + "paddh %[C], %[C], %[Ad] \n\t" + "paddh %[C], %[C], %[Bd] \n\t" + "pcmpgth %[Bd], %[ftmp10], %[ftmp3] \n\t" + "or %[mask], %[Bd], %[csth_1] \n\t" + "pmullh %[ftmp1], %[ftmp3], %[mask] \n\t" + "pmulhuh %[D], %[ftmp9], %[ftmp1] \n\t" + "pmullh %[D], %[D], %[mask] \n\t" + "pcmpgth %[Ed], %[ftmp10], %[ftmp5] \n\t" + "or %[mask], %[Ed], %[csth_1] \n\t" + "pmullh %[Ad], %[ftmp5], %[mask] \n\t" + "pmulhuh %[Ad], %[ftmp8], %[Ad] \n\t" + "pmullh %[Ad], %[Ad], %[mask] \n\t" + "psubh %[D], %[Ad], %[D] \n\t" + "paddh %[D], %[D], %[Ed] \n\t" + "psubh %[D], %[D], %[Bd] \n\t" + + LOAD_CONST(%[ftmp8], 46341) + "psubh %[Ad], %[A], %[C] \n\t" + "pcmpgth %[Bd], %[ftmp10], %[Ad] \n\t" + "or %[mask], %[Bd], %[csth_1] \n\t" + "pmullh %[Ad], %[Ad], %[mask] \n\t" + "pmulhuh %[Ad], %[ftmp8], %[Ad] \n\t" + "pmullh %[Ad], %[Ad], %[mask] \n\t" + "paddh %[Ad], %[Ad], %[Bd] \n\t" + "psubh %[Bd], %[B], %[D] \n\t" + "pcmpgth %[Cd], %[ftmp10], %[Bd] \n\t" + "or %[mask], %[Cd], %[csth_1] \n\t" + "pmullh %[Bd], %[Bd], %[mask] \n\t" + "pmulhuh %[Bd], %[ftmp8], %[Bd] \n\t" + "pmullh %[Bd], %[Bd], %[mask] \n\t" + "paddh %[Bd], %[Bd], %[Cd] \n\t" + "paddh %[Cd], %[A], %[C] \n\t" + "paddh %[Dd], %[B], %[D] \n\t" + "paddh %[A], %[ftmp0], %[ftmp4] \n\t" + "pcmpgth %[B], %[ftmp10], %[A] \n\t" + "or %[mask], %[B], %[csth_1] \n\t" + "pmullh %[A], %[A], %[mask] \n\t" + "pmulhuh %[A], %[ftmp8], %[A] \n\t" + "pmullh %[A], %[A], %[mask] \n\t" + "paddh %[A], %[A], %[B] \n\t" + "psubh %[B], %[ftmp0], %[ftmp4] \n\t" + "pcmpgth %[C], %[ftmp10], %[B] \n\t" + "or %[mask], %[C], %[csth_1] \n\t" + "pmullh %[B], %[B], %[mask] \n\t" + "pmulhuh %[B], %[ftmp8], %[B] \n\t" + "pmullh %[B], %[B], %[mask] \n\t" + "paddh %[B], %[B], %[C] \n\t" + + LOAD_CONST(%[ftmp8], 60547) + LOAD_CONST(%[ftmp9], 25080) + "pmulhh %[C], %[ftmp9], %[ftmp6] \n\t" + "pcmpgth %[D], %[ftmp10], %[ftmp2] \n\t" + "or %[mask], %[D], %[csth_1] \n\t" + "pmullh %[Ed], %[ftmp2], %[mask] \n\t" + "pmulhuh %[Ed], %[ftmp8], %[Ed] \n\t" + "pmullh %[Ed], %[Ed], %[mask] \n\t" + "paddh %[C], %[C], %[Ed] \n\t" + "paddh %[C], %[C], %[D] \n\t" + "pcmpgth %[Ed], %[ftmp10], %[ftmp6] \n\t" + "or %[mask], %[Ed], %[csth_1] \n\t" + "pmullh %[ftmp6], %[ftmp6], %[mask] \n\t" + "pmulhuh %[D], %[ftmp8], %[ftmp6] \n\t" + "pmullh %[D], %[D], %[mask] \n\t" + "pmulhh %[Gd], %[ftmp9], %[ftmp2] \n\t" + "psubh %[D], %[Gd], %[D] \n\t" + "psubh %[D], %[D], %[Ed] \n\t" + "psubh %[Ed], %[A], %[C] \n\t" + "paddh %[Gd], %[A], %[C] \n\t" + "paddh %[A], %[B], %[Ad] \n\t" + "psubh %[C], %[B], %[Ad] \n\t" + "psubh %[B], %[Bd], %[D] \n\t" + "paddh %[D], %[Bd], %[D] \n\t" + /* Final sequence of operations over-write original inputs */ + "paddh %[ftmp0], %[Gd], %[Cd] \n\t" + "paddh %[ftmp1], %[A], %[D] \n\t" + "psubh %[ftmp2], %[A], %[D] \n\t" + "paddh %[ftmp3], %[Ed], %[Dd] \n\t" + "psubh %[ftmp4], %[Ed], %[Dd] \n\t" + "paddh %[ftmp5], %[C], %[B] \n\t" + "psubh %[ftmp6], %[C], %[B] \n\t" + "psubh %[ftmp7], %[Gd], %[Cd] \n\t" + "sdc1 %[ftmp0], 0x00(%[input]) \n\t" + "sdc1 %[ftmp1], 0x10(%[input]) \n\t" + "sdc1 %[ftmp2], 0x20(%[input]) \n\t" + "sdc1 %[ftmp3], 0x30(%[input]) \n\t" + "sdc1 %[ftmp4], 0x40(%[input]) \n\t" + "sdc1 %[ftmp5], 0x50(%[input]) \n\t" + "sdc1 %[ftmp6], 0x60(%[input]) \n\t" + "sdc1 %[ftmp7], 0x70(%[input]) \n\t" + PTR_ADDU "%[tmp0], %[tmp0], -0x01 \n\t" + PTR_ADDIU "%[input], %[input], 0x08 \n\t" + "bnez %[tmp0], 1b \n\t" + : [input]"+&r"(input), [tmp0]"=&r"(tmp[0]), [tmp1]"=&r"(tmp[1]), + [ftmp0]"=&f"(ftmp[0]), [ftmp1]"=&f"(ftmp[1]), [ftmp2]"=&f"(ftmp[2]), + [ftmp3]"=&f"(ftmp[3]), [ftmp4]"=&f"(ftmp[4]), [ftmp5]"=&f"(ftmp[5]), + [ftmp6]"=&f"(ftmp[6]), [ftmp7]"=&f"(ftmp[7]), [ftmp8]"=&f"(ftmp[8]), + [ftmp9]"=&f"(ftmp[9]), [ftmp10]"=&f"(ftmp[10]), [mask]"=&f"(ftmp[11]), + [A]"=&f"(ftmp[12]), [B]"=&f"(ftmp[13]), [C]"=&f"(ftmp[14]), + [D]"=&f"(ftmp[15]), [Ad]"=&f"(ftmp[16]), [Bd]"=&f"(ftmp[17]), + [Cd]"=&f"(ftmp[18]), [Dd]"=&f"(ftmp[19]), [Ed]"=&f"(ftmp[20]), + [Gd]"=&f"(ftmp[21]), [csth_1]"=&f"(ftmp[22]) + : + : "memory" + ); +} + +static void idct_column_true_mmi(uint8_t *dst, int stride, int16_t *input) +{ + uint8_t temp_value[8]; + double ftmp[23]; + uint64_t tmp[2]; + for (int i = 0; i < 8; ++i) + temp_value[i] = av_clip_uint8(128 + ((46341 * input[i << 3] + (8 << 16)) >> 20)); + __asm__ volatile ( + "xor %[ftmp10], %[ftmp10], %[ftmp10] \n\t" + "li %[tmp0], 0x02 \n\t" + "1: \n\t" + "ldc1 %[ftmp0], 0x00(%[input]) \n\t" + "ldc1 %[ftmp4], 0x08(%[input]) \n\t" + "ldc1 %[ftmp1], 0x10(%[input]) \n\t" + "ldc1 %[ftmp5], 0x18(%[input]) \n\t" + "ldc1 %[ftmp2], 0x20(%[input]) \n\t" + "ldc1 %[ftmp6], 0x28(%[input]) \n\t" + "ldc1 %[ftmp3], 0x30(%[input]) \n\t" + "ldc1 %[ftmp7], 0x38(%[input]) \n\t" + TRANSPOSE_4H(%[ftmp0], %[ftmp1], %[ftmp2], %[ftmp3], + %[A], %[B], %[C], %[D]) + TRANSPOSE_4H(%[ftmp4], %[ftmp5], %[ftmp6], %[ftmp7], + %[A], %[B], %[C], %[D]) + LOAD_CONST(%[ftmp8], 64277) + LOAD_CONST(%[ftmp9], 12785) + LOAD_CONST(%[Gd], 1) + "pmulhh %[A], %[ftmp9], %[ftmp7] \n\t" + "pcmpgth %[C], %[ftmp10], %[ftmp1] \n\t" + "or %[mask], %[C], %[Gd] \n\t" + "pmullh %[B], %[ftmp1], %[mask] \n\t" + "pmulhuh %[B], %[ftmp8], %[B] \n\t" + "pmullh %[B], %[B], %[mask] \n\t" + "paddh %[A], %[A], %[B] \n\t" + "paddh %[A], %[A], %[C] \n\t" + "pcmpgth %[D], %[ftmp10], %[ftmp7] \n\t" + "or %[mask], %[D], %[Gd] \n\t" + "pmullh %[Ad], %[ftmp7], %[mask] \n\t" + "pmulhuh %[B], %[ftmp8], %[Ad] \n\t" + "pmullh %[B], %[B], %[mask] \n\t" + "pmulhh %[C], %[ftmp9], %[ftmp1] \n\t" + "psubh %[B], %[C], %[B] \n\t" + "psubh %[B], %[B], %[D] \n\t" + + LOAD_CONST(%[ftmp8], 54491) + LOAD_CONST(%[ftmp9], 36410) + "pcmpgth %[Ad], %[ftmp10], %[ftmp5] \n\t" + "or %[mask], %[Ad], %[Gd] \n\t" + "pmullh %[Cd], %[ftmp5], %[mask] \n\t" + "pmulhuh %[C], %[ftmp9], %[Cd] \n\t" + "pmullh %[C], %[C], %[mask] \n\t" + "pcmpgth %[Bd], %[ftmp10], %[ftmp3] \n\t" + "or %[mask], %[Bd], %[Gd] \n\t" + "pmullh %[D], %[ftmp3], %[mask] \n\t" + "pmulhuh %[D], %[ftmp8], %[D] \n\t" + "pmullh %[D], %[D], %[mask] \n\t" + "paddh %[C], %[C], %[D] \n\t" + "paddh %[C], %[C], %[Ad] \n\t" + "paddh %[C], %[C], %[Bd] \n\t" + "pcmpgth %[Bd], %[ftmp10], %[ftmp3] \n\t" + "or %[mask], %[Bd], %[Gd] \n\t" + "pmullh %[Cd], %[ftmp3], %[mask] \n\t" + "pmulhuh %[D], %[ftmp9], %[Cd] \n\t" + "pmullh %[D], %[D], %[mask] \n\t" + "pcmpgth %[Ed], %[ftmp10], %[ftmp5] \n\t" + "or %[mask], %[Ed], %[Gd] \n\t" + "pmullh %[Ad], %[ftmp5], %[mask] \n\t" + "pmulhuh %[Ad], %[ftmp8], %[Ad] \n\t" + "pmullh %[Ad], %[Ad], %[mask] \n\t" + "psubh %[D], %[Ad], %[D] \n\t" + "paddh %[D], %[D], %[Ed] \n\t" + "psubh %[D], %[D], %[Bd] \n\t" + + LOAD_CONST(%[ftmp8], 46341) + "psubh %[Ad], %[A], %[C] \n\t" + "pcmpgth %[Bd], %[ftmp10], %[Ad] \n\t" + "or %[mask], %[Bd], %[Gd] \n\t" + "pmullh %[Ad], %[Ad], %[mask] \n\t" + "pmulhuh %[Ad], %[ftmp8], %[Ad] \n\t" + "pmullh %[Ad], %[Ad], %[mask] \n\t" + "paddh %[Ad], %[Ad], %[Bd] \n\t" + "psubh %[Bd], %[B], %[D] \n\t" + "pcmpgth %[Cd], %[ftmp10], %[Bd] \n\t" + "or %[mask], %[Cd], %[Gd] \n\t" + "pmullh %[Bd], %[Bd], %[mask] \n\t" + "pmulhuh %[Bd], %[ftmp8], %[Bd] \n\t" + "pmullh %[Bd], %[Bd], %[mask] \n\t" + "paddh %[Bd], %[Bd], %[Cd] \n\t" + "paddh %[Cd], %[A], %[C] \n\t" + "paddh %[Dd], %[B], %[D] \n\t" + + LOAD_CONST(%[Ed], 2056) + "paddh %[A], %[ftmp0], %[ftmp4] \n\t" + "pcmpgth %[B], %[ftmp10], %[A] \n\t" + "or %[mask], %[B], %[Gd] \n\t" + "pmullh %[A], %[A], %[mask] \n\t" + "pmulhuh %[A], %[ftmp8], %[A] \n\t" + "pmullh %[A], %[A], %[mask] \n\t" + "paddh %[A], %[A], %[B] \n\t" + "paddh %[A], %[A], %[Ed] \n\t" + "psubh %[B], %[ftmp0], %[ftmp4] \n\t" + "pcmpgth %[C], %[ftmp10], %[B] \n\t" + "or %[mask], %[C], %[Gd] \n\t" + "pmullh %[B], %[B], %[mask] \n\t" + "pmulhuh %[B], %[ftmp8], %[B] \n\t" + "pmullh %[B], %[B], %[mask] \n\t" + "paddh %[B], %[B], %[C] \n\t" + "paddh %[B], %[B], %[Ed] \n\t" + + LOAD_CONST(%[ftmp8], 60547) + LOAD_CONST(%[ftmp9], 25080) + "pmulhh %[C], %[ftmp9], %[ftmp6] \n\t" + "pcmpgth %[D], %[ftmp10], %[ftmp2] \n\t" + "or %[mask], %[D], %[Gd] \n\t" + "pmullh %[Ed], %[ftmp2], %[mask] \n\t" + "pmulhuh %[Ed], %[ftmp8], %[Ed] \n\t" + "pmullh %[Ed], %[Ed], %[mask] \n\t" + "paddh %[C], %[C], %[Ed] \n\t" + "paddh %[C], %[C], %[D] \n\t" + "pcmpgth %[Ed], %[ftmp10], %[ftmp6] \n\t" + "or %[mask], %[Ed], %[Gd] \n\t" + "pmullh %[D], %[ftmp6], %[mask] \n\t" + "pmulhuh %[D], %[ftmp8], %[D] \n\t" + "pmullh %[D], %[D], %[mask] \n\t" + "pmulhh %[Gd], %[ftmp9], %[ftmp2] \n\t" + "psubh %[D], %[Gd], %[D] \n\t" + "psubh %[D], %[D], %[Ed] \n\t" + "psubh %[Ed], %[A], %[C] \n\t" + "paddh %[Gd], %[A], %[C] \n\t" + "paddh %[A], %[B], %[Ad] \n\t" + "psubh %[C], %[B], %[Ad] \n\t" + "psubh %[B], %[Bd], %[D] \n\t" + "paddh %[D], %[Bd], %[D] \n\t" + "or %[mask], %[ftmp1], %[ftmp2] \n\t" + "or %[mask], %[mask], %[ftmp3] \n\t" + "or %[mask], %[mask], %[ftmp4] \n\t" + "or %[mask], %[mask], %[ftmp5] \n\t" + "or %[mask], %[mask], %[ftmp6] \n\t" + "or %[mask], %[mask], %[ftmp7] \n\t" + "pcmpeqh %[mask], %[mask], %[ftmp10] \n\t" + "packushb %[mask], %[mask], %[ftmp10] \n\t" + "li %[tmp1], 0x04 \n\t" + "dmtc1 %[tmp1], %[ftmp8] \n\t" + "paddh %[ftmp0], %[Gd], %[Cd] \n\t" + "psrah %[ftmp0], %[ftmp0], %[ftmp8] \n\t" + "paddh %[ftmp1], %[A], %[D] \n\t" + "psrah %[ftmp1], %[ftmp1], %[ftmp8] \n\t" + "psubh %[ftmp2], %[A], %[D] \n\t" + "psrah %[ftmp2], %[ftmp2], %[ftmp8] \n\t" + "paddh %[ftmp3], %[Ed], %[Dd] \n\t" + "psrah %[ftmp3], %[ftmp3], %[ftmp8] \n\t" + "psubh %[ftmp4], %[Ed], %[Dd] \n\t" + "psrah %[ftmp4], %[ftmp4], %[ftmp8] \n\t" + "paddh %[ftmp5], %[C], %[B] \n\t" + "psrah %[ftmp5], %[ftmp5], %[ftmp8] \n\t" + "psubh %[ftmp6], %[C], %[B] \n\t" + "psrah %[ftmp6], %[ftmp6], %[ftmp8] \n\t" + "psubh %[ftmp7], %[Gd], %[Cd] \n\t" + "psrah %[ftmp7], %[ftmp7], %[ftmp8] \n\t" + "pmaxsh %[ftmp0], %[ftmp0], %[ftmp10] \n\t" + "packushb %[ftmp0], %[ftmp0], %[ftmp10] \n\t" + "pmaxsh %[ftmp1], %[ftmp1], %[ftmp10] \n\t" + "packushb %[ftmp1], %[ftmp1], %[ftmp10] \n\t" + "pmaxsh %[ftmp2], %[ftmp2], %[ftmp10] \n\t" + "packushb %[ftmp2], %[ftmp2], %[ftmp10] \n\t" + "pmaxsh %[ftmp3], %[ftmp3], %[ftmp10] \n\t" + "packushb %[ftmp3], %[ftmp3], %[ftmp10] \n\t" + "pmaxsh %[ftmp4], %[ftmp4], %[ftmp10] \n\t" + "packushb %[ftmp4], %[ftmp4], %[ftmp10] \n\t" + "pmaxsh %[ftmp5], %[ftmp5], %[ftmp10] \n\t" + "packushb %[ftmp5], %[ftmp5], %[ftmp10] \n\t" + "pmaxsh %[ftmp6], %[ftmp6], %[ftmp10] \n\t" + "packushb %[ftmp6], %[ftmp6], %[ftmp10] \n\t" + "pmaxsh %[ftmp7], %[ftmp7], %[ftmp10] \n\t" + "packushb %[ftmp7], %[ftmp7], %[ftmp10] \n\t" + + "lwc1 %[Ed], 0x00(%[temp_value]) \n\t" + "and %[Ed], %[Ed], %[mask] \n\t" + "paddb %[ftmp0], %[ftmp0], %[Ed] \n\t" + "paddb %[ftmp1], %[ftmp1], %[Ed] \n\t" + "paddb %[ftmp2], %[ftmp2], %[Ed] \n\t" + "paddb %[ftmp3], %[ftmp3], %[Ed] \n\t" + "paddb %[ftmp4], %[ftmp4], %[Ed] \n\t" + "paddb %[ftmp5], %[ftmp5], %[Ed] \n\t" + "paddb %[ftmp6], %[ftmp6], %[Ed] \n\t" + "paddb %[ftmp7], %[ftmp7], %[Ed] \n\t" + "swc1 %[ftmp0], 0x00(%[dst]) \n\t" + PTR_ADDU "%[tmp1], %[dst], %[stride] \n\t" + "swc1 %[ftmp1], 0x00(%[tmp1]) \n\t" + PTR_ADDU "%[tmp1], %[tmp1], %[stride] \n\t" + "swc1 %[ftmp2], 0x00(%[tmp1]) \n\t" + PTR_ADDU "%[tmp1], %[tmp1], %[stride] \n\t" + "swc1 %[ftmp3], 0x00(%[tmp1]) \n\t" + PTR_ADDU "%[tmp1], %[tmp1], %[stride] \n\t" + "swc1 %[ftmp4], 0x00(%[tmp1]) \n\t" + PTR_ADDU "%[tmp1], %[tmp1], %[stride] \n\t" + "swc1 %[ftmp5], 0x00(%[tmp1]) \n\t" + PTR_ADDU "%[tmp1], %[tmp1], %[stride] \n\t" + "swc1 %[ftmp6], 0x00(%[tmp1]) \n\t" + PTR_ADDU "%[tmp1], %[tmp1], %[stride] \n\t" + "swc1 %[ftmp7], 0x00(%[tmp1]) \n\t" + PTR_ADDIU "%[dst], %[dst], 0x04 \n\t" + PTR_ADDIU "%[input], %[input], 0x40 \n\t" + PTR_ADDIU "%[temp_value], %[temp_value], 0x04 \n\t" + PTR_ADDIU "%[tmp0], %[tmp0], -0x01 \n\t" + "bnez %[tmp0], 1b \n\t" + : [dst]"+&r"(dst), [tmp0]"=&r"(tmp[0]), [tmp1]"=&r"(tmp[1]), + [ftmp0]"=&f"(ftmp[0]), [ftmp1]"=&f"(ftmp[1]), [ftmp2]"=&f"(ftmp[2]), + [ftmp3]"=&f"(ftmp[3]), [ftmp4]"=&f"(ftmp[4]), [ftmp5]"=&f"(ftmp[5]), + [ftmp6]"=&f"(ftmp[6]), [ftmp7]"=&f"(ftmp[7]), [ftmp8]"=&f"(ftmp[8]), + [ftmp9]"=&f"(ftmp[9]), [ftmp10]"=&f"(ftmp[10]), [mask]"=&f"(ftmp[11]), + [A]"=&f"(ftmp[12]), [B]"=&f"(ftmp[13]), [C]"=&f"(ftmp[14]), + [D]"=&f"(ftmp[15]), [Ad]"=&f"(ftmp[16]), [Bd]"=&f"(ftmp[17]), + [Cd]"=&f"(ftmp[18]), [Dd]"=&f"(ftmp[19]), [Ed]"=&f"(ftmp[20]), + [Gd]"=&f"(ftmp[21]), [input]"+&r"(input) + : [stride]"r"(stride), [temp_value]"r"(temp_value) + : "memory" + ); +} + +static void idct_column_false_mmi(uint8_t *dst, int stride, int16_t *input) +{ + int16_t temp_value[8]; + double ftmp[23]; + uint64_t tmp[2]; + for (int i = 0; i < 8; ++i) + temp_value[i] = (46341 * input[i << 3] + (8 << 16)) >> 20; + __asm__ volatile ( + "xor %[ftmp10], %[ftmp10], %[ftmp10] \n\t" + "li %[tmp0], 0x02 \n\t" + "1: \n\t" + "ldc1 %[ftmp0], 0x00(%[input]) \n\t" + "ldc1 %[ftmp4], 0x08(%[input]) \n\t" + "ldc1 %[ftmp1], 0x10(%[input]) \n\t" + "ldc1 %[ftmp5], 0x18(%[input]) \n\t" + "ldc1 %[ftmp2], 0x20(%[input]) \n\t" + "ldc1 %[ftmp6], 0x28(%[input]) \n\t" + "ldc1 %[ftmp3], 0x30(%[input]) \n\t" + "ldc1 %[ftmp7], 0x38(%[input]) \n\t" + TRANSPOSE_4H(%[ftmp0], %[ftmp1], %[ftmp2], %[ftmp3], + %[A], %[B], %[C], %[D]) + TRANSPOSE_4H(%[ftmp4], %[ftmp5], %[ftmp6], %[ftmp7], + %[A], %[B], %[C], %[D]) + LOAD_CONST(%[ftmp8], 64277) + LOAD_CONST(%[ftmp9], 12785) + LOAD_CONST(%[Gd], 1) + "pmulhh %[A], %[ftmp9], %[ftmp7] \n\t" + "pcmpgth %[C], %[ftmp10], %[ftmp1] \n\t" + "or %[mask], %[C], %[Gd] \n\t" + "pmullh %[B], %[ftmp1], %[mask] \n\t" + "pmulhuh %[B], %[ftmp8], %[B] \n\t" + "pmullh %[B], %[B], %[mask] \n\t" + "paddh %[A], %[A], %[B] \n\t" + "paddh %[A], %[A], %[C] \n\t" + "pcmpgth %[D], %[ftmp10], %[ftmp7] \n\t" + "or %[mask], %[D], %[Gd] \n\t" + "pmullh %[Ad], %[ftmp7], %[mask] \n\t" + "pmulhuh %[B], %[ftmp8], %[Ad] \n\t" + "pmullh %[B], %[B], %[mask] \n\t" + "pmulhh %[C], %[ftmp9], %[ftmp1] \n\t" + "psubh %[B], %[C], %[B] \n\t" + "psubh %[B], %[B], %[D] \n\t" + + LOAD_CONST(%[ftmp8], 54491) + LOAD_CONST(%[ftmp9], 36410) + "pcmpgth %[Ad], %[ftmp10], %[ftmp5] \n\t" + "or %[mask], %[Ad], %[Gd] \n\t" + "pmullh %[Cd], %[ftmp5], %[mask] \n\t" + "pmulhuh %[C], %[ftmp9], %[Cd] \n\t" + "pmullh %[C], %[C], %[mask] \n\t" + "pcmpgth %[Bd], %[ftmp10], %[ftmp3] \n\t" + "or %[mask], %[Bd], %[Gd] \n\t" + "pmullh %[D], %[ftmp3], %[mask] \n\t" + "pmulhuh %[D], %[ftmp8], %[D] \n\t" + "pmullh %[D], %[D], %[mask] \n\t" + "paddh %[C], %[C], %[D] \n\t" + "paddh %[C], %[C], %[Ad] \n\t" + "paddh %[C], %[C], %[Bd] \n\t" + "pcmpgth %[Bd], %[ftmp10], %[ftmp3] \n\t" + "or %[mask], %[Bd], %[Gd] \n\t" + "pmullh %[Cd], %[ftmp3], %[mask] \n\t" + "pmulhuh %[D], %[ftmp9], %[Cd] \n\t" + "pmullh %[D], %[D], %[mask] \n\t" + "pcmpgth %[Ed], %[ftmp10], %[ftmp5] \n\t" + "or %[mask], %[Ed], %[Gd] \n\t" + "pmullh %[Ad], %[ftmp5], %[mask] \n\t" + "pmulhuh %[Ad], %[ftmp8], %[Ad] \n\t" + "pmullh %[Ad], %[Ad], %[mask] \n\t" + "psubh %[D], %[Ad], %[D] \n\t" + "paddh %[D], %[D], %[Ed] \n\t" + "psubh %[D], %[D], %[Bd] \n\t" + + LOAD_CONST(%[ftmp8], 46341) + "psubh %[Ad], %[A], %[C] \n\t" + "pcmpgth %[Bd], %[ftmp10], %[Ad] \n\t" + "or %[mask], %[Bd], %[Gd] \n\t" + "pmullh %[Ad], %[Ad], %[mask] \n\t" + "pmulhuh %[Ad], %[ftmp8], %[Ad] \n\t" + "pmullh %[Ad], %[Ad], %[mask] \n\t" + "paddh %[Ad], %[Ad], %[Bd] \n\t" + "psubh %[Bd], %[B], %[D] \n\t" + "pcmpgth %[Cd], %[ftmp10], %[Bd] \n\t" + "or %[mask], %[Cd], %[Gd] \n\t" + "pmullh %[Bd], %[Bd], %[mask] \n\t" + "pmulhuh %[Bd], %[ftmp8], %[Bd] \n\t" + "pmullh %[Bd], %[Bd], %[mask] \n\t" + "paddh %[Bd], %[Bd], %[Cd] \n\t" + "paddh %[Cd], %[A], %[C] \n\t" + "paddh %[Dd], %[B], %[D] \n\t" + + LOAD_CONST(%[Ed], 8) + "paddh %[A], %[ftmp0], %[ftmp4] \n\t" + "pcmpgth %[B], %[ftmp10], %[A] \n\t" + "or %[mask], %[B], %[Gd] \n\t" + "pmullh %[A], %[A], %[mask] \n\t" + "pmulhuh %[A], %[ftmp8], %[A] \n\t" + "pmullh %[A], %[A], %[mask] \n\t" + "paddh %[A], %[A], %[B] \n\t" + "paddh %[A], %[A], %[Ed] \n\t" + "psubh %[B], %[ftmp0], %[ftmp4] \n\t" + "pcmpgth %[C], %[ftmp10], %[B] \n\t" + "or %[mask], %[C], %[Gd] \n\t" + "pmullh %[B], %[B], %[mask] \n\t" + "pmulhuh %[B], %[ftmp8], %[B] \n\t" + "pmullh %[B], %[B], %[mask] \n\t" + "paddh %[B], %[B], %[C] \n\t" + "paddh %[B], %[B], %[Ed] \n\t" + + LOAD_CONST(%[ftmp8], 60547) + LOAD_CONST(%[ftmp9], 25080) + "pmulhh %[C], %[ftmp9], %[ftmp6] \n\t" + "pcmpgth %[D], %[ftmp10], %[ftmp2] \n\t" + "or %[mask], %[D], %[Gd] \n\t" + "pmullh %[Ed], %[ftmp2], %[mask] \n\t" + "pmulhuh %[Ed], %[ftmp8], %[Ed] \n\t" + "pmullh %[Ed], %[Ed], %[mask] \n\t" + "paddh %[C], %[C], %[Ed] \n\t" + "paddh %[C], %[C], %[D] \n\t" + "pcmpgth %[Ed], %[ftmp10], %[ftmp6] \n\t" + "or %[mask], %[Ed], %[Gd] \n\t" + "pmullh %[D], %[ftmp6], %[mask] \n\t" + "pmulhuh %[D], %[ftmp8], %[D] \n\t" + "pmullh %[D], %[D], %[mask] \n\t" + "pmulhh %[Gd], %[ftmp9], %[ftmp2] \n\t" + "psubh %[D], %[Gd], %[D] \n\t" + "psubh %[D], %[D], %[Ed] \n\t" + "psubh %[Ed], %[A], %[C] \n\t" + "paddh %[Gd], %[A], %[C] \n\t" + "paddh %[A], %[B], %[Ad] \n\t" + "psubh %[C], %[B], %[Ad] \n\t" + "psubh %[B], %[Bd], %[D] \n\t" + "paddh %[D], %[Bd], %[D] \n\t" + "or %[mask], %[ftmp1], %[ftmp2] \n\t" + "or %[mask], %[mask], %[ftmp3] \n\t" + "or %[mask], %[mask], %[ftmp4] \n\t" + "or %[mask], %[mask], %[ftmp5] \n\t" + "or %[mask], %[mask], %[ftmp6] \n\t" + "or %[mask], %[mask], %[ftmp7] \n\t" + "pcmpeqh %[mask], %[mask], %[ftmp10] \n\t" + "li %[tmp1], 0x04 \n\t" + "dmtc1 %[tmp1], %[ftmp8] \n\t" + "paddh %[ftmp0], %[Gd], %[Cd] \n\t" + "psrah %[ftmp0], %[ftmp0], %[ftmp8] \n\t" + "paddh %[ftmp1], %[A], %[D] \n\t" + "psrah %[ftmp1], %[ftmp1], %[ftmp8] \n\t" + "psubh %[ftmp2], %[A], %[D] \n\t" + "psrah %[ftmp2], %[ftmp2], %[ftmp8] \n\t" + "paddh %[ftmp3], %[Ed], %[Dd] \n\t" + "psrah %[ftmp3], %[ftmp3], %[ftmp8] \n\t" + "psubh %[ftmp4], %[Ed], %[Dd] \n\t" + "psrah %[ftmp4], %[ftmp4], %[ftmp8] \n\t" + "paddh %[ftmp5], %[C], %[B] \n\t" + "psrah %[ftmp5], %[ftmp5], %[ftmp8] \n\t" + "psubh %[ftmp6], %[C], %[B] \n\t" + "psrah %[ftmp6], %[ftmp6], %[ftmp8] \n\t" + "psubh %[ftmp7], %[Gd], %[Cd] \n\t" + "psrah %[ftmp7], %[ftmp7], %[ftmp8] \n\t" + + /* Load from dst */ + "lwc1 %[A], 0x00(%[dst]) \n\t" + PTR_ADDU "%[tmp1], %[dst], %[stride] \n\t" + "lwc1 %[B], 0x00(%[tmp1]) \n\t" + PTR_ADDU "%[tmp1], %[tmp1], %[stride] \n\t" + "lwc1 %[C], 0x00(%[tmp1]) \n\t" + PTR_ADDU "%[tmp1], %[tmp1], %[stride] \n\t" + "lwc1 %[D], 0x00(%[tmp1]) \n\t" + PTR_ADDU "%[tmp1], %[tmp1], %[stride] \n\t" + "lwc1 %[Ad], 0x00(%[tmp1]) \n\t" + PTR_ADDU "%[tmp1], %[tmp1], %[stride] \n\t" + "lwc1 %[Bd], 0x00(%[tmp1]) \n\t" + PTR_ADDU "%[tmp1], %[tmp1], %[stride] \n\t" + "lwc1 %[Cd], 0x00(%[tmp1]) \n\t" + PTR_ADDU "%[tmp1], %[tmp1], %[stride] \n\t" + "lwc1 %[Dd], 0x00(%[tmp1]) \n\t" + "punpcklbh %[A], %[A], %[ftmp10] \n\t" + "punpcklbh %[B], %[B], %[ftmp10] \n\t" + "punpcklbh %[C], %[C], %[ftmp10] \n\t" + "punpcklbh %[D], %[D], %[ftmp10] \n\t" + "punpcklbh %[Ad], %[Ad], %[ftmp10] \n\t" + "punpcklbh %[Bd], %[Bd], %[ftmp10] \n\t" + "punpcklbh %[Cd], %[Cd], %[ftmp10] \n\t" + "punpcklbh %[Dd], %[Dd], %[ftmp10] \n\t" + "ldc1 %[Ed], 0x00(%[temp_value]) \n\t" + "and %[Ed], %[Ed], %[mask] \n\t" + "nor %[mask], %[mask], %[mask] \n\t" + "and %[ftmp0], %[ftmp0], %[mask] \n\t" + "and %[ftmp1], %[ftmp1], %[mask] \n\t" + "and %[ftmp2], %[ftmp2], %[mask] \n\t" + "and %[ftmp3], %[ftmp3], %[mask] \n\t" + "and %[ftmp4], %[ftmp4], %[mask] \n\t" + "and %[ftmp5], %[ftmp5], %[mask] \n\t" + "and %[ftmp6], %[ftmp6], %[mask] \n\t" + "and %[ftmp7], %[ftmp7], %[mask] \n\t" + "paddh %[ftmp0], %[ftmp0], %[A] \n\t" + "paddh %[ftmp1], %[ftmp1], %[B] \n\t" + "paddh %[ftmp2], %[ftmp2], %[C] \n\t" + "paddh %[ftmp3], %[ftmp3], %[D] \n\t" + "paddh %[ftmp4], %[ftmp4], %[Ad] \n\t" + "paddh %[ftmp5], %[ftmp5], %[Bd] \n\t" + "paddh %[ftmp6], %[ftmp6], %[Cd] \n\t" + "paddh %[ftmp7], %[ftmp7], %[Dd] \n\t" + "paddh %[ftmp0], %[ftmp0], %[Ed] \n\t" + "paddh %[ftmp1], %[ftmp1], %[Ed] \n\t" + "paddh %[ftmp2], %[ftmp2], %[Ed] \n\t" + "paddh %[ftmp3], %[ftmp3], %[Ed] \n\t" + "paddh %[ftmp4], %[ftmp4], %[Ed] \n\t" + "paddh %[ftmp5], %[ftmp5], %[Ed] \n\t" + "paddh %[ftmp6], %[ftmp6], %[Ed] \n\t" + "paddh %[ftmp7], %[ftmp7], %[Ed] \n\t" + "pmaxsh %[ftmp0], %[ftmp0], %[ftmp10] \n\t" + "packushb %[ftmp0], %[ftmp0], %[ftmp10] \n\t" + "pmaxsh %[ftmp1], %[ftmp1], %[ftmp10] \n\t" + "packushb %[ftmp1], %[ftmp1], %[ftmp10] \n\t" + "pmaxsh %[ftmp2], %[ftmp2], %[ftmp10] \n\t" + "packushb %[ftmp2], %[ftmp2], %[ftmp10] \n\t" + "pmaxsh %[ftmp3], %[ftmp3], %[ftmp10] \n\t" + "packushb %[ftmp3], %[ftmp3], %[ftmp10] \n\t" + "pmaxsh %[ftmp4], %[ftmp4], %[ftmp10] \n\t" + "packushb %[ftmp4], %[ftmp4], %[ftmp10] \n\t" + "pmaxsh %[ftmp5], %[ftmp5], %[ftmp10] \n\t" + "packushb %[ftmp5], %[ftmp5], %[ftmp10] \n\t" + "pmaxsh %[ftmp6], %[ftmp6], %[ftmp10] \n\t" + "packushb %[ftmp6], %[ftmp6], %[ftmp10] \n\t" + "pmaxsh %[ftmp7], %[ftmp7], %[ftmp10] \n\t" + "packushb %[ftmp7], %[ftmp7], %[ftmp10] \n\t" + "swc1 %[ftmp0], 0x00(%[dst]) \n\t" + PTR_ADDU "%[tmp1], %[dst], %[stride] \n\t" + "swc1 %[ftmp1], 0x00(%[tmp1]) \n\t" + PTR_ADDU "%[tmp1], %[tmp1], %[stride] \n\t" + "swc1 %[ftmp2], 0x00(%[tmp1]) \n\t" + PTR_ADDU "%[tmp1], %[tmp1], %[stride] \n\t" + "swc1 %[ftmp3], 0x00(%[tmp1]) \n\t" + PTR_ADDU "%[tmp1], %[tmp1], %[stride] \n\t" + "swc1 %[ftmp4], 0x00(%[tmp1]) \n\t" + PTR_ADDU "%[tmp1], %[tmp1], %[stride] \n\t" + "swc1 %[ftmp5], 0x00(%[tmp1]) \n\t" + PTR_ADDU "%[tmp1], %[tmp1], %[stride] \n\t" + "swc1 %[ftmp6], 0x00(%[tmp1]) \n\t" + PTR_ADDU "%[tmp1], %[tmp1], %[stride] \n\t" + "swc1 %[ftmp7], 0x00(%[tmp1]) \n\t" + PTR_ADDIU "%[dst], %[dst], 0x04 \n\t" + PTR_ADDIU "%[input], %[input], 0x40 \n\t" + PTR_ADDIU "%[temp_value], %[temp_value], 0x08 \n\t" + PTR_ADDIU "%[tmp0], %[tmp0], -0x01 \n\t" + "bnez %[tmp0], 1b \n\t" + : [dst]"+&r"(dst), [tmp0]"=&r"(tmp[0]), [tmp1]"=&r"(tmp[1]), + [ftmp0]"=&f"(ftmp[0]), [ftmp1]"=&f"(ftmp[1]), [ftmp2]"=&f"(ftmp[2]), + [ftmp3]"=&f"(ftmp[3]), [ftmp4]"=&f"(ftmp[4]), [ftmp5]"=&f"(ftmp[5]), + [ftmp6]"=&f"(ftmp[6]), [ftmp7]"=&f"(ftmp[7]), [ftmp8]"=&f"(ftmp[8]), + [ftmp9]"=&f"(ftmp[9]), [ftmp10]"=&f"(ftmp[10]), [mask]"=&f"(ftmp[11]), + [A]"=&f"(ftmp[12]), [B]"=&f"(ftmp[13]), [C]"=&f"(ftmp[14]), + [D]"=&f"(ftmp[15]), [Ad]"=&f"(ftmp[16]), [Bd]"=&f"(ftmp[17]), + [Cd]"=&f"(ftmp[18]), [Dd]"=&f"(ftmp[19]), [Ed]"=&f"(ftmp[20]), + [Gd]"=&f"(ftmp[21]), [input]"+&r"(input) + : [stride]"r"(stride), [temp_value]"r"(temp_value) + : "memory" + ); +} +static void idct_mmi(uint8_t *dst, int stride, int16_t *input, int type) +{ + idct_row_mmi(input); + if (type == 1) + idct_column_true_mmi(dst, stride, input); + else + idct_column_false_mmi(dst, stride, input); +} + +void ff_vp3_idct_put_mmi(uint8_t *dest, ptrdiff_t line_size, int16_t *block) +{ + idct_mmi(dest, line_size, block, 1); + memset(block, 0, sizeof(*block) << 6); +} + +void ff_vp3_idct_add_mmi(uint8_t *dest, ptrdiff_t line_size, int16_t *block) +{ + idct_mmi(dest, line_size, block, 2); + memset(block, 0, sizeof(*block) << 6); +} +void ff_vp3_idct_dc_add_mmi(uint8_t *dest, ptrdiff_t line_size, int16_t *block) +{ + int dc = (block[0] + 15) >> 5; + + double ftmp[7]; + uint64_t tmp; + __asm__ volatile ( + "xor %[ftmp0], %[ftmp0], %[ftmp0] \n\t" + "mtc1 %[dc], %[ftmp5] \n\t" + "pshufh %[ftmp5], %[ftmp5], %[ftmp0] \n\t" + "li %[tmp0], 0x08 \n\t" + "1: \n\t" + "ldc1 %[ftmp1], 0x00(%[dest]) \n\t" + "punpcklbh %[ftmp2], %[ftmp1], %[ftmp0] \n\t" + "punpckhbh %[ftmp3], %[ftmp1], %[ftmp0] \n\t" + "paddh %[ftmp4], %[ftmp2], %[ftmp5] \n\t" + "paddh %[ftmp6], %[ftmp3], %[ftmp5] \n\t" + "packushb %[ftmp4], %[ftmp4], %[ftmp0] \n\t" + "packushb %[ftmp6], %[ftmp6], %[ftmp0] \n\t" + "swc1 %[ftmp4], 0x00(%[dest]) \n\t" + "swc1 %[ftmp6], 0x04(%[dest]) \n\t" + PTR_ADDU "%[dest], %[dest], %[line_size] \n\t" + PTR_ADDIU "%[tmp0], %[tmp0], -0x01 \n\t" + "bnez %[tmp0], 1b \n\t" + : [dest]"+&r"(dest), [block]"+&r"(block), [tmp0]"=&r"(tmp), + [ftmp0]"=&f"(ftmp[0]), [ftmp1]"=&f"(ftmp[1]), [ftmp2]"=&f"(ftmp[2]), + [ftmp3]"=&f"(ftmp[3]), [ftmp4]"=&f"(ftmp[4]), [ftmp5]"=&f"(ftmp[5]), + [ftmp6]"=&f"(ftmp[6]) + : [line_size]"r"(line_size), [dc]"r"(dc) + : "memory" + ); + block[0] = 0; +} + +void ff_put_no_rnd_pixels_l2_mmi(uint8_t *dst, const uint8_t *src1, + const uint8_t *src2, ptrdiff_t stride, int h) +{ + if (h == 8) { + double ftmp[6]; + uint64_t tmp[2]; + __asm__ volatile ( + "li %[tmp0], 0x08 \n\t" + "li %[tmp1], 0xfefefefe \n\t" + "dmtc1 %[tmp1], %[ftmp4] \n\t" + "punpcklwd %[ftmp4], %[ftmp4], %[ftmp4] \n\t" + "li %[tmp1], 0x01 \n\t" + "dmtc1 %[tmp1], %[ftmp5] \n\t" + "1: \n\t" + "gsldlc1 %[ftmp1], 0x07(%[src1]) \n\t" + "gsldrc1 %[ftmp1], 0x00(%[src1]) \n\t" + "gsldlc1 %[ftmp2], 0x07(%[src2]) \n\t" + "gsldrc1 %[ftmp2], 0x00(%[src2]) \n\t" + "xor %[ftmp3], %[ftmp1], %[ftmp2] \n\t" + "and %[ftmp3], %[ftmp3], %[ftmp4] \n\t" + "psrlw %[ftmp3], %[ftmp3], %[ftmp5] \n\t" + "and %[ftmp6], %[ftmp1], %[ftmp2] \n\t" + "paddw %[ftmp3], %[ftmp3], %[ftmp6] \n\t" + "sdc1 %[ftmp3], 0x00(%[dst]) \n\t" + PTR_ADDU "%[src1], %[src1], %[stride] \n\t" + PTR_ADDU "%[src2], %[src2], %[stride] \n\t" + PTR_ADDU "%[dst], %[dst], %[stride] \n\t" + PTR_ADDIU "%[tmp0], %[tmp0], -0x01 \n\t" + "bnez %[tmp0], 1b \n\t" + : [dst]"+&r"(dst), [src1]"+&r"(src1), [src2]"+&r"(src2), + [ftmp1]"=&f"(ftmp[0]), [ftmp2]"=&f"(ftmp[1]), [ftmp3]"=&f"(ftmp[2]), + [ftmp4]"=&f"(ftmp[3]), [ftmp5]"=&f"(ftmp[4]), [ftmp6]"=&f"(ftmp[5]), + [tmp0]"=&r"(tmp[0]), [tmp1]"=&r"(tmp[1]) + : [stride]"r"(stride) + : "memory" + ); + } else { + int i; + + for (i = 0; i < h; i++) { + uint32_t a, b; + + a = AV_RN32(&src1[i * stride]); + b = AV_RN32(&src2[i * stride]); + AV_WN32A(&dst[i * stride], no_rnd_avg32(a, b)); + a = AV_RN32(&src1[i * stride + 4]); + b = AV_RN32(&src2[i * stride + 4]); + AV_WN32A(&dst[i * stride + 4], no_rnd_avg32(a, b)); + } + } +} diff --git a/libavcodec/mips/vp3dsp_idct_msa.c b/libavcodec/mips/vp3dsp_idct_msa.c new file mode 100644 index 000000000..b2899eea4 --- /dev/null +++ b/libavcodec/mips/vp3dsp_idct_msa.c @@ -0,0 +1,646 @@ +/* + * Copyright (c) 2018 gxw + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "vp3dsp_mips.h" +#include "libavutil/mips/generic_macros_msa.h" +#include "libavutil/intreadwrite.h" +#include "libavcodec/rnd_avg.h" + +static void idct_msa(uint8_t *dst, int stride, int16_t *input, int type) +{ + v8i16 r0, r1, r2, r3, r4, r5, r6, r7, sign; + v4i32 r0_r, r0_l, r1_r, r1_l, r2_r, r2_l, r3_r, r3_l, + r4_r, r4_l, r5_r, r5_l, r6_r, r6_l, r7_r, r7_l; + v4i32 A, B, C, D, Ad, Bd, Cd, Dd, E, F, G, H; + v4i32 Ed, Gd, Add, Bdd, Fd, Hd; + v16u8 sign_l; + v16i8 d0, d1, d2, d3, d4, d5, d6, d7; + v4i32 c0, c1, c2, c3, c4, c5, c6, c7; + v4i32 f0, f1, f2, f3, f4, f5, f6, f7; + v4i32 sign_t; + v16i8 zero = {0}; + v16i8 mask = {0, 4, 8, 12, 16, 20, 24, 28, 0, 0, 0, 0, 0, 0, 0, 0}; + v4i32 cnst64277w = {64277, 64277, 64277, 64277}; + v4i32 cnst60547w = {60547, 60547, 60547, 60547}; + v4i32 cnst54491w = {54491, 54491, 54491, 54491}; + v4i32 cnst46341w = {46341, 46341, 46341, 46341}; + v4i32 cnst36410w = {36410, 36410, 36410, 36410}; + v4i32 cnst25080w = {25080, 25080, 25080, 25080}; + v4i32 cnst12785w = {12785, 12785, 12785, 12785}; + v4i32 cnst8w = {8, 8, 8, 8}; + v4i32 cnst2048w = {2048, 2048, 2048, 2048}; + v4i32 cnst128w = {128, 128, 128, 128}; + + /* Extended input data */ + LD_SH8(input, 8, r0, r1, r2, r3, r4, r5, r6, r7); + sign = __msa_clti_s_h(r0, 0); + r0_r = (v4i32) __msa_ilvr_h(sign, r0); + r0_l = (v4i32) __msa_ilvl_h(sign, r0); + sign = __msa_clti_s_h(r1, 0); + r1_r = (v4i32) __msa_ilvr_h(sign, r1); + r1_l = (v4i32) __msa_ilvl_h(sign, r1); + sign = __msa_clti_s_h(r2, 0); + r2_r = (v4i32) __msa_ilvr_h(sign, r2); + r2_l = (v4i32) __msa_ilvl_h(sign, r2); + sign = __msa_clti_s_h(r3, 0); + r3_r = (v4i32) __msa_ilvr_h(sign, r3); + r3_l = (v4i32) __msa_ilvl_h(sign, r3); + sign = __msa_clti_s_h(r4, 0); + r4_r = (v4i32) __msa_ilvr_h(sign, r4); + r4_l = (v4i32) __msa_ilvl_h(sign, r4); + sign = __msa_clti_s_h(r5, 0); + r5_r = (v4i32) __msa_ilvr_h(sign, r5); + r5_l = (v4i32) __msa_ilvl_h(sign, r5); + sign = __msa_clti_s_h(r6, 0); + r6_r = (v4i32) __msa_ilvr_h(sign, r6); + r6_l = (v4i32) __msa_ilvl_h(sign, r6); + sign = __msa_clti_s_h(r7, 0); + r7_r = (v4i32) __msa_ilvr_h(sign, r7); + r7_l = (v4i32) __msa_ilvl_h(sign, r7); + + /* Right part */ + A = ((r1_r * cnst64277w) >> 16) + ((r7_r * cnst12785w) >> 16); + B = ((r1_r * cnst12785w) >> 16) - ((r7_r * cnst64277w) >> 16); + C = ((r3_r * cnst54491w) >> 16) + ((r5_r * cnst36410w) >> 16); + D = ((r5_r * cnst54491w) >> 16) - ((r3_r * cnst36410w) >> 16); + Ad = ((A - C) * cnst46341w) >> 16; + Bd = ((B - D) * cnst46341w) >> 16; + Cd = A + C; + Dd = B + D; + E = ((r0_r + r4_r) * cnst46341w) >> 16; + F = ((r0_r - r4_r) * cnst46341w) >> 16; + G = ((r2_r * cnst60547w) >> 16) + ((r6_r * cnst25080w) >> 16); + H = ((r2_r * cnst25080w) >> 16) - ((r6_r * cnst60547w) >> 16); + Ed = E - G; + Gd = E + G; + Add = F + Ad; + Bdd = Bd - H; + Fd = F - Ad; + Hd = Bd + H; + r0_r = Gd + Cd; + r7_r = Gd - Cd; + r1_r = Add + Hd; + r2_r = Add - Hd; + r3_r = Ed + Dd; + r4_r = Ed - Dd; + r5_r = Fd + Bdd; + r6_r = Fd - Bdd; + + /* Left part */ + A = ((r1_l * cnst64277w) >> 16) + ((r7_l * cnst12785w) >> 16); + B = ((r1_l * cnst12785w) >> 16) - ((r7_l * cnst64277w) >> 16); + C = ((r3_l * cnst54491w) >> 16) + ((r5_l * cnst36410w) >> 16); + D = ((r5_l * cnst54491w) >> 16) - ((r3_l * cnst36410w) >> 16); + Ad = ((A - C) * cnst46341w) >> 16; + Bd = ((B - D) * cnst46341w) >> 16; + Cd = A + C; + Dd = B + D; + E = ((r0_l + r4_l) * cnst46341w) >> 16; + F = ((r0_l - r4_l) * cnst46341w) >> 16; + G = ((r2_l * cnst60547w) >> 16) + ((r6_l * cnst25080w) >> 16); + H = ((r2_l * cnst25080w) >> 16) - ((r6_l * cnst60547w) >> 16); + Ed = E - G; + Gd = E + G; + Add = F + Ad; + Bdd = Bd - H; + Fd = F - Ad; + Hd = Bd + H; + r0_l = Gd + Cd; + r7_l = Gd - Cd; + r1_l = Add + Hd; + r2_l = Add - Hd; + r3_l = Ed + Dd; + r4_l = Ed - Dd; + r5_l = Fd + Bdd; + r6_l = Fd - Bdd; + + /* Row 0 to 3 */ + TRANSPOSE4x4_SW_SW(r0_r, r1_r, r2_r, r3_r, + r0_r, r1_r, r2_r, r3_r); + TRANSPOSE4x4_SW_SW(r0_l, r1_l, r2_l, r3_l, + r0_l, r1_l, r2_l, r3_l); + A = ((r1_r * cnst64277w) >> 16) + ((r3_l * cnst12785w) >> 16); + B = ((r1_r * cnst12785w) >> 16) - ((r3_l * cnst64277w) >> 16); + C = ((r3_r * cnst54491w) >> 16) + ((r1_l * cnst36410w) >> 16); + D = ((r1_l * cnst54491w) >> 16) - ((r3_r * cnst36410w) >> 16); + Ad = ((A - C) * cnst46341w) >> 16; + Bd = ((B - D) * cnst46341w) >> 16; + Cd = A + C; + Dd = B + D; + E = ((r0_r + r0_l) * cnst46341w) >> 16; + E += cnst8w; + F = ((r0_r - r0_l) * cnst46341w) >> 16; + F += cnst8w; + if (type == 1) { // HACK + E += cnst2048w; + F += cnst2048w; + } + G = ((r2_r * cnst60547w) >> 16) + ((r2_l * cnst25080w) >> 16); + H = ((r2_r * cnst25080w) >> 16) - ((r2_l * cnst60547w) >> 16); + Ed = E - G; + Gd = E + G; + Add = F + Ad; + Bdd = Bd - H; + Fd = F - Ad; + Hd = Bd + H; + A = (Gd + Cd) >> 4; + B = (Gd - Cd) >> 4; + C = (Add + Hd) >> 4; + D = (Add - Hd) >> 4; + E = (Ed + Dd) >> 4; + F = (Ed - Dd) >> 4; + G = (Fd + Bdd) >> 4; + H = (Fd - Bdd) >> 4; + if (type != 1) { + LD_SB8(dst, stride, d0, d1, d2, d3, d4, d5, d6, d7); + ILVR_B4_SW(zero, d0, zero, d1, zero, d2, zero, d3, + f0, f1, f2, f3); + ILVR_B4_SW(zero, d4, zero, d5, zero, d6, zero, d7, + f4, f5, f6, f7); + ILVR_H4_SW(zero, f0, zero, f1, zero, f2, zero, f3, + c0, c1, c2, c3); + ILVR_H4_SW(zero, f4, zero, f5, zero, f6, zero, f7, + c4, c5, c6, c7); + A += c0; + B += c7; + C += c1; + D += c2; + E += c3; + F += c4; + G += c5; + H += c6; + } + A = CLIP_SW_0_255(A); + B = CLIP_SW_0_255(B); + C = CLIP_SW_0_255(C); + D = CLIP_SW_0_255(D); + E = CLIP_SW_0_255(E); + F = CLIP_SW_0_255(F); + G = CLIP_SW_0_255(G); + H = CLIP_SW_0_255(H); + sign_l = __msa_or_v((v16u8)r1_r, (v16u8)r2_r); + sign_l = __msa_or_v(sign_l, (v16u8)r3_r); + sign_l = __msa_or_v(sign_l, (v16u8)r0_l); + sign_l = __msa_or_v(sign_l, (v16u8)r1_l); + sign_l = __msa_or_v(sign_l, (v16u8)r2_l); + sign_l = __msa_or_v(sign_l, (v16u8)r3_l); + sign_t = __msa_ceqi_w((v4i32)sign_l, 0); + Add = ((r0_r * cnst46341w) + (8 << 16)) >> 20; + if (type == 1) { + Bdd = Add + cnst128w; + Bdd = CLIP_SW_0_255(Bdd); + Ad = Bdd; + Bd = Bdd; + Cd = Bdd; + Dd = Bdd; + Ed = Bdd; + Fd = Bdd; + Gd = Bdd; + Hd = Bdd; + } else { + Ad = Add + c0; + Bd = Add + c1; + Cd = Add + c2; + Dd = Add + c3; + Ed = Add + c4; + Fd = Add + c5; + Gd = Add + c6; + Hd = Add + c7; + Ad = CLIP_SW_0_255(Ad); + Bd = CLIP_SW_0_255(Bd); + Cd = CLIP_SW_0_255(Cd); + Dd = CLIP_SW_0_255(Dd); + Ed = CLIP_SW_0_255(Ed); + Fd = CLIP_SW_0_255(Fd); + Gd = CLIP_SW_0_255(Gd); + Hd = CLIP_SW_0_255(Hd); + } + Ad = (v4i32)__msa_and_v((v16u8)Ad, (v16u8)sign_t); + Bd = (v4i32)__msa_and_v((v16u8)Bd, (v16u8)sign_t); + Cd = (v4i32)__msa_and_v((v16u8)Cd, (v16u8)sign_t); + Dd = (v4i32)__msa_and_v((v16u8)Dd, (v16u8)sign_t); + Ed = (v4i32)__msa_and_v((v16u8)Ed, (v16u8)sign_t); + Fd = (v4i32)__msa_and_v((v16u8)Fd, (v16u8)sign_t); + Gd = (v4i32)__msa_and_v((v16u8)Gd, (v16u8)sign_t); + Hd = (v4i32)__msa_and_v((v16u8)Hd, (v16u8)sign_t); + sign_t = __msa_ceqi_w(sign_t, 0); + A = (v4i32)__msa_and_v((v16u8)A, (v16u8)sign_t); + B = (v4i32)__msa_and_v((v16u8)B, (v16u8)sign_t); + C = (v4i32)__msa_and_v((v16u8)C, (v16u8)sign_t); + D = (v4i32)__msa_and_v((v16u8)D, (v16u8)sign_t); + E = (v4i32)__msa_and_v((v16u8)E, (v16u8)sign_t); + F = (v4i32)__msa_and_v((v16u8)F, (v16u8)sign_t); + G = (v4i32)__msa_and_v((v16u8)G, (v16u8)sign_t); + H = (v4i32)__msa_and_v((v16u8)H, (v16u8)sign_t); + r0_r = Ad + A; + r1_r = Bd + C; + r2_r = Cd + D; + r3_r = Dd + E; + r0_l = Ed + F; + r1_l = Fd + G; + r2_l = Gd + H; + r3_l = Hd + B; + + /* Row 4 to 7 */ + TRANSPOSE4x4_SW_SW(r4_r, r5_r, r6_r, r7_r, + r4_r, r5_r, r6_r, r7_r); + TRANSPOSE4x4_SW_SW(r4_l, r5_l, r6_l, r7_l, + r4_l, r5_l, r6_l, r7_l); + A = ((r5_r * cnst64277w) >> 16) + ((r7_l * cnst12785w) >> 16); + B = ((r5_r * cnst12785w) >> 16) - ((r7_l * cnst64277w) >> 16); + C = ((r7_r * cnst54491w) >> 16) + ((r5_l * cnst36410w) >> 16); + D = ((r5_l * cnst54491w) >> 16) - ((r7_r * cnst36410w) >> 16); + Ad = ((A - C) * cnst46341w) >> 16; + Bd = ((B - D) * cnst46341w) >> 16; + Cd = A + C; + Dd = B + D; + E = ((r4_r + r4_l) * cnst46341w) >> 16; + E += cnst8w; + F = ((r4_r - r4_l) * cnst46341w) >> 16; + F += cnst8w; + if (type == 1) { // HACK + E += cnst2048w; + F += cnst2048w; + } + G = ((r6_r * cnst60547w) >> 16) + ((r6_l * cnst25080w) >> 16); + H = ((r6_r * cnst25080w) >> 16) - ((r6_l * cnst60547w) >> 16); + Ed = E - G; + Gd = E + G; + Add = F + Ad; + Bdd = Bd - H; + Fd = F - Ad; + Hd = Bd + H; + A = (Gd + Cd) >> 4; + B = (Gd - Cd) >> 4; + C = (Add + Hd) >> 4; + D = (Add - Hd) >> 4; + E = (Ed + Dd) >> 4; + F = (Ed - Dd) >> 4; + G = (Fd + Bdd) >> 4; + H = (Fd - Bdd) >> 4; + if (type != 1) { + ILVL_H4_SW(zero, f0, zero, f1, zero, f2, zero, f3, + c0, c1, c2, c3); + ILVL_H4_SW(zero, f4, zero, f5, zero, f6, zero, f7, + c4, c5, c6, c7); + A += c0; + B += c7; + C += c1; + D += c2; + E += c3; + F += c4; + G += c5; + H += c6; + } + A = CLIP_SW_0_255(A); + B = CLIP_SW_0_255(B); + C = CLIP_SW_0_255(C); + D = CLIP_SW_0_255(D); + E = CLIP_SW_0_255(E); + F = CLIP_SW_0_255(F); + G = CLIP_SW_0_255(G); + H = CLIP_SW_0_255(H); + sign_l = __msa_or_v((v16u8)r5_r, (v16u8)r6_r); + sign_l = __msa_or_v(sign_l, (v16u8)r7_r); + sign_l = __msa_or_v(sign_l, (v16u8)r4_l); + sign_l = __msa_or_v(sign_l, (v16u8)r5_l); + sign_l = __msa_or_v(sign_l, (v16u8)r6_l); + sign_l = __msa_or_v(sign_l, (v16u8)r7_l); + sign_t = __msa_ceqi_w((v4i32)sign_l, 0); + Add = ((r4_r * cnst46341w) + (8 << 16)) >> 20; + if (type == 1) { + Bdd = Add + cnst128w; + Bdd = CLIP_SW_0_255(Bdd); + Ad = Bdd; + Bd = Bdd; + Cd = Bdd; + Dd = Bdd; + Ed = Bdd; + Fd = Bdd; + Gd = Bdd; + Hd = Bdd; + } else { + Ad = Add + c0; + Bd = Add + c1; + Cd = Add + c2; + Dd = Add + c3; + Ed = Add + c4; + Fd = Add + c5; + Gd = Add + c6; + Hd = Add + c7; + Ad = CLIP_SW_0_255(Ad); + Bd = CLIP_SW_0_255(Bd); + Cd = CLIP_SW_0_255(Cd); + Dd = CLIP_SW_0_255(Dd); + Ed = CLIP_SW_0_255(Ed); + Fd = CLIP_SW_0_255(Fd); + Gd = CLIP_SW_0_255(Gd); + Hd = CLIP_SW_0_255(Hd); + } + Ad = (v4i32)__msa_and_v((v16u8)Ad, (v16u8)sign_t); + Bd = (v4i32)__msa_and_v((v16u8)Bd, (v16u8)sign_t); + Cd = (v4i32)__msa_and_v((v16u8)Cd, (v16u8)sign_t); + Dd = (v4i32)__msa_and_v((v16u8)Dd, (v16u8)sign_t); + Ed = (v4i32)__msa_and_v((v16u8)Ed, (v16u8)sign_t); + Fd = (v4i32)__msa_and_v((v16u8)Fd, (v16u8)sign_t); + Gd = (v4i32)__msa_and_v((v16u8)Gd, (v16u8)sign_t); + Hd = (v4i32)__msa_and_v((v16u8)Hd, (v16u8)sign_t); + sign_t = __msa_ceqi_w(sign_t, 0); + A = (v4i32)__msa_and_v((v16u8)A, (v16u8)sign_t); + B = (v4i32)__msa_and_v((v16u8)B, (v16u8)sign_t); + C = (v4i32)__msa_and_v((v16u8)C, (v16u8)sign_t); + D = (v4i32)__msa_and_v((v16u8)D, (v16u8)sign_t); + E = (v4i32)__msa_and_v((v16u8)E, (v16u8)sign_t); + F = (v4i32)__msa_and_v((v16u8)F, (v16u8)sign_t); + G = (v4i32)__msa_and_v((v16u8)G, (v16u8)sign_t); + H = (v4i32)__msa_and_v((v16u8)H, (v16u8)sign_t); + r4_r = Ad + A; + r5_r = Bd + C; + r6_r = Cd + D; + r7_r = Dd + E; + r4_l = Ed + F; + r5_l = Fd + G; + r6_l = Gd + H; + r7_l = Hd + B; + VSHF_B2_SB(r0_r, r4_r, r1_r, r5_r, mask, mask, d0, d1); + VSHF_B2_SB(r2_r, r6_r, r3_r, r7_r, mask, mask, d2, d3); + VSHF_B2_SB(r0_l, r4_l, r1_l, r5_l, mask, mask, d4, d5); + VSHF_B2_SB(r2_l, r6_l, r3_l, r7_l, mask, mask, d6, d7); + + /* Final sequence of operations over-write original dst */ + ST_D1(d0, 0, dst); + ST_D1(d1, 0, dst + stride); + ST_D1(d2, 0, dst + 2 * stride); + ST_D1(d3, 0, dst + 3 * stride); + ST_D1(d4, 0, dst + 4 * stride); + ST_D1(d5, 0, dst + 5 * stride); + ST_D1(d6, 0, dst + 6 * stride); + ST_D1(d7, 0, dst + 7 * stride); +} + +void ff_vp3_idct_put_msa(uint8_t *dest, ptrdiff_t line_size, int16_t *block) +{ + idct_msa(dest, line_size, block, 1); + memset(block, 0, sizeof(*block) * 64); +} + +void ff_vp3_idct_add_msa(uint8_t *dest, ptrdiff_t line_size, int16_t *block) +{ + idct_msa(dest, line_size, block, 2); + memset(block, 0, sizeof(*block) * 64); +} + +void ff_vp3_idct_dc_add_msa(uint8_t *dest, ptrdiff_t line_size, int16_t *block) +{ + int i = (block[0] + 15) >> 5; + v4i32 dc = {i, i, i, i}; + v16i8 d0, d1, d2, d3, d4, d5, d6, d7; + v4i32 c0, c1, c2, c3, c4, c5, c6, c7; + v4i32 e0, e1, e2, e3, e4, e5, e6, e7; + v4i32 r0, r1, r2, r3, r4, r5, r6, r7; + v16i8 mask = {0, 4, 8, 12, 16, 20, 24, 28, 0, 0, 0, 0, 0, 0, 0, 0}; + v16i8 zero = {0}; + + LD_SB8(dest, line_size, d0, d1, d2, d3, d4, d5, d6, d7); + ILVR_B4_SW(zero, d0, zero, d1, zero, d2, zero, d3, + c0, c1, c2, c3); + ILVR_B4_SW(zero, d4, zero, d5, zero, d6, zero, d7, + c4, c5, c6, c7); + /* Right part */ + ILVR_H4_SW(zero, c0, zero, c1, zero, c2, zero, c3, + e0, e1, e2, e3); + ILVR_H4_SW(zero, c4, zero, c5, zero, c6, zero, c7, + e4, e5, e6, e7); + e0 += dc; + e1 += dc; + e2 += dc; + e3 += dc; + e4 += dc; + e5 += dc; + e6 += dc; + e7 += dc; + e0 = CLIP_SW_0_255(e0); + e1 = CLIP_SW_0_255(e1); + e2 = CLIP_SW_0_255(e2); + e3 = CLIP_SW_0_255(e3); + e4 = CLIP_SW_0_255(e4); + e5 = CLIP_SW_0_255(e5); + e6 = CLIP_SW_0_255(e6); + e7 = CLIP_SW_0_255(e7); + + /* Left part */ + ILVL_H4_SW(zero, c0, zero, c1, zero, c2, zero, c3, + r0, r1, r2, r3); + ILVL_H4_SW(zero, c4, zero, c5, zero, c6, zero, c7, + r4, r5, r6, r7); + r0 += dc; + r1 += dc; + r2 += dc; + r3 += dc; + r4 += dc; + r5 += dc; + r6 += dc; + r7 += dc; + r0 = CLIP_SW_0_255(r0); + r1 = CLIP_SW_0_255(r1); + r2 = CLIP_SW_0_255(r2); + r3 = CLIP_SW_0_255(r3); + r4 = CLIP_SW_0_255(r4); + r5 = CLIP_SW_0_255(r5); + r6 = CLIP_SW_0_255(r6); + r7 = CLIP_SW_0_255(r7); + VSHF_B2_SB(e0, r0, e1, r1, mask, mask, d0, d1); + VSHF_B2_SB(e2, r2, e3, r3, mask, mask, d2, d3); + VSHF_B2_SB(e4, r4, e5, r5, mask, mask, d4, d5); + VSHF_B2_SB(e6, r6, e7, r7, mask, mask, d6, d7); + + /* Final sequence of operations over-write original dst */ + ST_D1(d0, 0, dest); + ST_D1(d1, 0, dest + line_size); + ST_D1(d2, 0, dest + 2 * line_size); + ST_D1(d3, 0, dest + 3 * line_size); + ST_D1(d4, 0, dest + 4 * line_size); + ST_D1(d5, 0, dest + 5 * line_size); + ST_D1(d6, 0, dest + 6 * line_size); + ST_D1(d7, 0, dest + 7 * line_size); + + block[0] = 0; +} + +void ff_vp3_v_loop_filter_msa(uint8_t *first_pixel, ptrdiff_t stride, + int *bounding_values) +{ + int nstride = -stride; + v4i32 e0, e1, f0, f1, g0, g1; + v16i8 zero = {0}; + v16i8 d0, d1, d2, d3; + v8i16 c0, c1, c2, c3; + v8i16 r0; + v8i16 cnst3h = {3, 3, 3, 3, 3, 3, 3, 3}, + cnst4h = {4, 4, 4, 4, 4, 4, 4, 4}; + v16i8 mask = {0, 4, 8, 12, 16, 20, 24, 28, 0, 0, 0, 0, 0, 0, 0, 0}; + int16_t temp_16[8]; + int temp_32[8]; + + LD_SB4(first_pixel + nstride * 2, stride, d0, d1, d2, d3); + ILVR_B4_SH(zero, d0, zero, d1, zero, d2, zero, d3, + c0, c1, c2, c3); + r0 = (c0 - c3) + (c2 - c1) * cnst3h; + r0 += cnst4h; + r0 = r0 >> 3; + /* Get filter_value from bounding_values one by one */ + ST_SH(r0, temp_16); + for (int i = 0; i < 8; i++) + temp_32[i] = bounding_values[temp_16[i]]; + LD_SW2(temp_32, 4, e0, e1); + ILVR_H2_SW(zero, c1, zero, c2, f0, g0); + ILVL_H2_SW(zero, c1, zero, c2, f1, g1); + f0 += e0; + f1 += e1; + g0 -= e0; + g1 -= e1; + f0 = CLIP_SW_0_255(f0); + f1 = CLIP_SW_0_255(f1); + g0 = CLIP_SW_0_255(g0); + g1 = CLIP_SW_0_255(g1); + VSHF_B2_SB(f0, f1, g0, g1, mask, mask, d1, d2); + + /* Final move to first_pixel */ + ST_D1(d1, 0, first_pixel + nstride); + ST_D1(d2, 0, first_pixel); +} + +void ff_vp3_h_loop_filter_msa(uint8_t *first_pixel, ptrdiff_t stride, + int *bounding_values) +{ + v16i8 d0, d1, d2, d3, d4, d5, d6, d7; + v8i16 c0, c1, c2, c3, c4, c5, c6, c7; + v8i16 r0; + v4i32 e0, e1, f0, f1, g0, g1; + v16i8 zero = {0}; + v8i16 cnst3h = {3, 3, 3, 3, 3, 3, 3, 3}, + cnst4h = {4, 4, 4, 4, 4, 4, 4, 4}; + v16i8 mask = {0, 16, 4, 20, 8, 24, 12, 28, 0, 0, 0, 0, 0, 0, 0, 0}; + int16_t temp_16[8]; + int temp_32[8]; + + LD_SB8(first_pixel - 2, stride, d0, d1, d2, d3, d4, d5, d6, d7); + ILVR_B4_SH(zero, d0, zero, d1, zero, d2, zero, d3, + c0, c1, c2, c3); + ILVR_B4_SH(zero, d4, zero, d5, zero, d6, zero, d7, + c4, c5, c6, c7); + TRANSPOSE8x8_SH_SH(c0, c1, c2, c3, c4, c5, c6, c7, + c0, c1, c2, c3, c4, c5, c6, c7); + r0 = (c0 - c3) + (c2 - c1) * cnst3h; + r0 += cnst4h; + r0 = r0 >> 3; + + /* Get filter_value from bounding_values one by one */ + ST_SH(r0, temp_16); + for (int i = 0; i < 8; i++) + temp_32[i] = bounding_values[temp_16[i]]; + LD_SW2(temp_32, 4, e0, e1); + ILVR_H2_SW(zero, c1, zero, c2, f0, g0); + ILVL_H2_SW(zero, c1, zero, c2, f1, g1); + f0 += e0; + f1 += e1; + g0 -= e0; + g1 -= e1; + f0 = CLIP_SW_0_255(f0); + f1 = CLIP_SW_0_255(f1); + g0 = CLIP_SW_0_255(g0); + g1 = CLIP_SW_0_255(g1); + VSHF_B2_SB(f0, g0, f1, g1, mask, mask, d1, d2); + /* Final move to first_pixel */ + ST_H4(d1, 0, 1, 2, 3, first_pixel - 1, stride); + ST_H4(d2, 0, 1, 2, 3, first_pixel - 1 + 4 * stride, stride); +} + +void ff_put_no_rnd_pixels_l2_msa(uint8_t *dst, const uint8_t *src1, + const uint8_t *src2, ptrdiff_t stride, int h) +{ + if (h == 8) { + v16i8 d0, d1, d2, d3, d4, d5, d6, d7; + v16i8 c0, c1, c2, c3; + v4i32 a0, a1, a2, a3, b0, b1, b2, b3; + v4i32 e0, e1, e2; + v4i32 f0, f1, f2; + v4u32 t0, t1, t2, t3; + v16i8 mask = {0, 1, 2, 3, 16, 17, 18, 19, 4, 5, 6, 7, 20, 21, 22, 23}; + int32_t value = 0xfefefefe; + v4i32 fmask = {value, value, value, value}; + + LD_SB8(src1, stride, d0, d1, d2, d3, d4, d5, d6, d7); + VSHF_B2_SB(d0, d1, d2, d3, mask, mask, c0, c1); + VSHF_B2_SB(d4, d5, d6, d7, mask, mask, c2, c3); + a0 = (v4i32) __msa_pckev_d((v2i64)c1, (v2i64)c0); + a2 = (v4i32) __msa_pckod_d((v2i64)c1, (v2i64)c0); + a1 = (v4i32) __msa_pckev_d((v2i64)c3, (v2i64)c2); + a3 = (v4i32) __msa_pckod_d((v2i64)c3, (v2i64)c2); + + LD_SB8(src2, stride, d0, d1, d2, d3, d4, d5, d6, d7); + VSHF_B2_SB(d0, d1, d2, d3, mask, mask, c0, c1); + VSHF_B2_SB(d4, d5, d6, d7, mask, mask, c2, c3); + b0 = (v4i32) __msa_pckev_d((v2i64)c1, (v2i64)c0); + b2 = (v4i32) __msa_pckod_d((v2i64)c1, (v2i64)c0); + b1 = (v4i32) __msa_pckev_d((v2i64)c3, (v2i64)c2); + b3 = (v4i32) __msa_pckod_d((v2i64)c3, (v2i64)c2); + + e0 = (v4i32) __msa_xor_v((v16u8)a0, (v16u8)b0); + e0 = (v4i32) __msa_and_v((v16u8)e0, (v16u8)fmask); + t0 = ((v4u32)e0) >> 1; + e2 = (v4i32) __msa_and_v((v16u8)a0, (v16u8)b0); + t0 = t0 + (v4u32)e2; + + e1 = (v4i32) __msa_xor_v((v16u8)a1, (v16u8)b1); + e1 = (v4i32) __msa_and_v((v16u8)e1, (v16u8)fmask); + t1 = ((v4u32)e1) >> 1; + e2 = (v4i32) __msa_and_v((v16u8)a1, (v16u8)b1); + t1 = t1 + (v4u32)e2; + + f0 = (v4i32) __msa_xor_v((v16u8)a2, (v16u8)b2); + f0 = (v4i32) __msa_and_v((v16u8)f0, (v16u8)fmask); + t2 = ((v4u32)f0) >> 1; + f2 = (v4i32) __msa_and_v((v16u8)a2, (v16u8)b2); + t2 = t2 + (v4u32)f2; + + f1 = (v4i32) __msa_xor_v((v16u8)a3, (v16u8)b3); + f1 = (v4i32) __msa_and_v((v16u8)f1, (v16u8)fmask); + t3 = ((v4u32)f1) >> 1; + f2 = (v4i32) __msa_and_v((v16u8)a3, (v16u8)b3); + t3 = t3 + (v4u32)f2; + + ST_W8(t0, t1, 0, 1, 2, 3, 0, 1, 2, 3, dst, stride); + ST_W8(t2, t3, 0, 1, 2, 3, 0, 1, 2, 3, dst + 4, stride); + } else { + int i; + + for (i = 0; i < h; i++) { + uint32_t a, b; + + a = AV_RN32(&src1[i * stride]); + b = AV_RN32(&src2[i * stride]); + AV_WN32A(&dst[i * stride], no_rnd_avg32(a, b)); + a = AV_RN32(&src1[i * stride + 4]); + b = AV_RN32(&src2[i * stride + 4]); + AV_WN32A(&dst[i * stride + 4], no_rnd_avg32(a, b)); + } + } +} diff --git a/libavcodec/mips/vp3dsp_init_mips.c b/libavcodec/mips/vp3dsp_init_mips.c new file mode 100644 index 000000000..e183db35b --- /dev/null +++ b/libavcodec/mips/vp3dsp_init_mips.c @@ -0,0 +1,60 @@ + +/* + * Copyright (c) 2018 gxw + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" +#include "libavutil/attributes.h" +#include "libavcodec/avcodec.h" +#include "libavcodec/vp3dsp.h" +#include "vp3dsp_mips.h" + +#if HAVE_MSA +static av_cold void vp3dsp_init_msa(VP3DSPContext *c, int flags) +{ + c->put_no_rnd_pixels_l2 = ff_put_no_rnd_pixels_l2_msa; + + c->idct_add = ff_vp3_idct_add_msa; + c->idct_put = ff_vp3_idct_put_msa; + c->idct_dc_add = ff_vp3_idct_dc_add_msa; + c->v_loop_filter = ff_vp3_v_loop_filter_msa; + c->h_loop_filter = ff_vp3_h_loop_filter_msa; +} +#endif /* HAVE_MSA */ + +#if HAVE_MMI +static av_cold void vp3dsp_init_mmi(VP3DSPContext *c, int flags) +{ + c->put_no_rnd_pixels_l2 = ff_put_no_rnd_pixels_l2_mmi; + + c->idct_add = ff_vp3_idct_add_mmi; + c->idct_put = ff_vp3_idct_put_mmi; + c->idct_dc_add = ff_vp3_idct_dc_add_mmi; +} +#endif /* HAVE_MMI */ + +av_cold void ff_vp3dsp_init_mips(VP3DSPContext *c, int flags) +{ +#if HAVE_MMI + vp3dsp_init_mmi(c, flags); +#endif /* HAVE_MMI */ +#if HAVE_MSA + vp3dsp_init_msa(c, flags); +#endif /* HAVE_MSA */ +} diff --git a/libavcodec/mips/vp3dsp_mips.h b/libavcodec/mips/vp3dsp_mips.h new file mode 100644 index 000000000..4685a825c --- /dev/null +++ b/libavcodec/mips/vp3dsp_mips.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2018 gxw + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * 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_MIPS_VP3DSP_MIPS_H +#define AVCODEC_MIPS_VP3DSP_MIPS_H + +#include "libavcodec/vp3dsp.h" +#include + +void ff_vp3_idct_add_msa(uint8_t *dest, ptrdiff_t line_size, int16_t *block); +void ff_vp3_idct_put_msa(uint8_t *dest, ptrdiff_t line_size, int16_t *block); +void ff_vp3_idct_dc_add_msa(uint8_t *dest, ptrdiff_t line_size, int16_t *block); +void ff_vp3_v_loop_filter_msa(uint8_t *first_pixel, ptrdiff_t stride, + int *bounding_values); +void ff_put_no_rnd_pixels_l2_msa(uint8_t *dst, const uint8_t *src1, + const uint8_t *src2, ptrdiff_t stride, int h); +void ff_vp3_h_loop_filter_msa(uint8_t *first_pixel, ptrdiff_t stride, + int *bounding_values); + +void ff_vp3_idct_add_mmi(uint8_t *dest, ptrdiff_t line_size, int16_t *block); +void ff_vp3_idct_put_mmi(uint8_t *dest, ptrdiff_t line_size, int16_t *block); +void ff_vp3_idct_dc_add_mmi(uint8_t *dest, ptrdiff_t line_size, int16_t *block); +void ff_put_no_rnd_pixels_l2_mmi(uint8_t *dst, const uint8_t *src1, + const uint8_t *src2, ptrdiff_t stride, int h); + +#endif /* #ifndef AVCODEC_MIPS_VP3DSP_MIPS_H */ diff --git a/libavcodec/mips/vp8_idct_msa.c b/libavcodec/mips/vp8_idct_msa.c index 11ac9ff83..ae6fec0d6 100644 --- a/libavcodec/mips/vp8_idct_msa.c +++ b/libavcodec/mips/vp8_idct_msa.c @@ -76,7 +76,8 @@ void ff_vp8_idct_add_msa(uint8_t *dst, int16_t input[16], ptrdiff_t stride) res2 = CLIP_SW_0_255(res2); res3 = CLIP_SW_0_255(res3); VSHF_B2_SB(res0, res1, res2, res3, mask, mask, dest0, dest1); - ST4x4_UB(dest0, dest1, 0, 1, 0, 1, dst, stride); + ST_W2(dest0, 0, 1, dst, stride); + ST_W2(dest1, 0, 1, dst + 2 * stride, stride); memset(input, 0, 4 * 4 * sizeof(*input)); } @@ -97,7 +98,8 @@ void ff_vp8_idct_dc_add_msa(uint8_t *dst, int16_t in_dc[16], ptrdiff_t stride) ADD4(res0, vec, res1, vec, res2, vec, res3, vec, res0, res1, res2, res3); CLIP_SH4_0_255(res0, res1, res2, res3); VSHF_B2_SB(res0, res1, res2, res3, mask, mask, dest0, dest1); - ST4x4_UB(dest0, dest1, 0, 1, 0, 1, dst, stride); + ST_W2(dest0, 0, 1, dst, stride); + ST_W2(dest1, 0, 1, dst + 2 * stride, stride); in_dc[0] = 0; } diff --git a/libavcodec/mips/vp8_lpf_msa.c b/libavcodec/mips/vp8_lpf_msa.c index 359096174..1b5133460 100644 --- a/libavcodec/mips/vp8_lpf_msa.c +++ b/libavcodec/mips/vp8_lpf_msa.c @@ -540,14 +540,8 @@ void ff_vp8_h_loop_filter_simple_msa(uint8_t *src, ptrdiff_t pitch, ILVRL_B2_SH(q0, p0, tmp1, tmp0); src -= 1; - ST2x4_UB(tmp1, 0, src, pitch); - src += 4 * pitch; - ST2x4_UB(tmp1, 4, src, pitch); - src += 4 * pitch; - ST2x4_UB(tmp0, 0, src, pitch); - src += 4 * pitch; - ST2x4_UB(tmp0, 4, src, pitch); - src += 4 * pitch; + ST_H8(tmp1, 0, 1, 2, 3, 4, 5, 6, 7, src, pitch) + ST_H8(tmp0, 0, 1, 2, 3, 4, 5, 6, 7, src + 8 * pitch, pitch) } void ff_vp8_v_loop_filter8uv_inner_msa(uint8_t *src_u, uint8_t *src_v, @@ -596,7 +590,6 @@ void ff_vp8_h_loop_filter8uv_inner_msa(uint8_t *src_u, uint8_t *src_v, ptrdiff_t pitch, int b_limit_in, int limit_in, int thresh_in) { - uint8_t *temp_src_u, *temp_src_v; v16u8 p3, p2, p1, p0, q3, q2, q1, q0; v16u8 mask, hev, flat, thresh, limit, b_limit; v16u8 row0, row1, row2, row3, row4, row5, row6, row7, row8; @@ -623,15 +616,8 @@ void ff_vp8_h_loop_filter8uv_inner_msa(uint8_t *src_u, uint8_t *src_v, tmp1 = (v4i32) __msa_ilvl_b((v16i8) q1, (v16i8) q0); ILVRL_H2_SW(tmp1, tmp0, tmp4, tmp5); - temp_src_u = src_u - 2; - ST4x4_UB(tmp2, tmp2, 0, 1, 2, 3, temp_src_u, pitch); - temp_src_u += 4 * pitch; - ST4x4_UB(tmp3, tmp3, 0, 1, 2, 3, temp_src_u, pitch); - - temp_src_v = src_v - 2; - ST4x4_UB(tmp4, tmp4, 0, 1, 2, 3, temp_src_v, pitch); - temp_src_v += 4 * pitch; - ST4x4_UB(tmp5, tmp5, 0, 1, 2, 3, temp_src_v, pitch); + ST_W8(tmp2, tmp3, 0, 1, 2, 3, 0, 1, 2, 3, src_u - 2, pitch); + ST_W8(tmp4, tmp5, 0, 1, 2, 3, 0, 1, 2, 3, src_v - 2, pitch); } void ff_vp8_v_loop_filter16_inner_msa(uint8_t *src, ptrdiff_t pitch, @@ -684,7 +670,6 @@ void ff_vp8_h_loop_filter16_inner_msa(uint8_t *src, ptrdiff_t pitch, ILVRL_H2_SH(tmp1, tmp0, tmp4, tmp5); src -= 2; - ST4x8_UB(tmp2, tmp3, src, pitch); - src += (8 * pitch); - ST4x8_UB(tmp4, tmp5, src, pitch); + ST_W8(tmp2, tmp3, 0, 1, 2, 3, 0, 1, 2, 3, src, pitch) + ST_W8(tmp4, tmp5, 0, 1, 2, 3, 0, 1, 2, 3, src + 8 * pitch, pitch) } diff --git a/libavcodec/mips/vp8_mc_msa.c b/libavcodec/mips/vp8_mc_msa.c index 2bf0abd8c..57af6b45f 100644 --- a/libavcodec/mips/vp8_mc_msa.c +++ b/libavcodec/mips/vp8_mc_msa.c @@ -181,7 +181,7 @@ static void common_hz_6t_4x4_msa(uint8_t *src, int32_t src_stride, SRARI_H2_SH(out0, out1, 7); SAT_SH2_SH(out0, out1, 7); out = PCKEV_XORI128_UB(out0, out1); - ST4x4_UB(out, out, 0, 1, 2, 3, dst, dst_stride); + ST_W4(out, 0, 1, 2, 3, dst, dst_stride); } static void common_hz_6t_4x8_msa(uint8_t *src, int32_t src_stride, @@ -214,10 +214,9 @@ static void common_hz_6t_4x8_msa(uint8_t *src, int32_t src_stride, SRARI_H4_SH(out0, out1, out2, out3, 7); SAT_SH4_SH(out0, out1, out2, out3, 7); out = PCKEV_XORI128_UB(out0, out1); - ST4x4_UB(out, out, 0, 1, 2, 3, dst, dst_stride); - dst += (4 * dst_stride); + ST_W4(out, 0, 1, 2, 3, dst, dst_stride); out = PCKEV_XORI128_UB(out2, out3); - ST4x4_UB(out, out, 0, 1, 2, 3, dst, dst_stride); + ST_W4(out, 0, 1, 2, 3, dst + 4 * dst_stride, dst_stride); } void ff_put_vp8_epel4_h6_msa(uint8_t *dst, ptrdiff_t dst_stride, @@ -263,7 +262,7 @@ void ff_put_vp8_epel8_h6_msa(uint8_t *dst, ptrdiff_t dst_stride, SAT_SH4_SH(out0, out1, out2, out3, 7); tmp0 = PCKEV_XORI128_UB(out0, out1); tmp1 = PCKEV_XORI128_UB(out2, out3); - ST8x4_UB(tmp0, tmp1, dst, dst_stride); + ST_D4(tmp0, tmp1, 0, 1, 0, 1, dst, dst_stride); dst += (4 * dst_stride); for (loop_cnt = (height >> 2) - 1; loop_cnt--;) { @@ -276,7 +275,7 @@ void ff_put_vp8_epel8_h6_msa(uint8_t *dst, ptrdiff_t dst_stride, SAT_SH4_SH(out0, out1, out2, out3, 7); tmp0 = PCKEV_XORI128_UB(out0, out1); tmp1 = PCKEV_XORI128_UB(out2, out3); - ST8x4_UB(tmp0, tmp1, dst, dst_stride); + ST_D4(tmp0, tmp1, 0, 1, 0, 1, dst, dst_stride); dst += (4 * dst_stride); } } @@ -368,7 +367,7 @@ void ff_put_vp8_epel4_v6_msa(uint8_t *dst, ptrdiff_t dst_stride, SRARI_H2_SH(out10, out32, 7); SAT_SH2_SH(out10, out32, 7); out = PCKEV_XORI128_UB(out10, out32); - ST4x4_UB(out, out, 0, 1, 2, 3, dst, dst_stride); + ST_W4(out, 0, 1, 2, 3, dst, dst_stride); dst += (4 * dst_stride); src2110 = src6554; @@ -416,7 +415,7 @@ void ff_put_vp8_epel8_v6_msa(uint8_t *dst, ptrdiff_t dst_stride, SAT_SH4_SH(out0_r, out1_r, out2_r, out3_r, 7); tmp0 = PCKEV_XORI128_UB(out0_r, out1_r); tmp1 = PCKEV_XORI128_UB(out2_r, out3_r); - ST8x4_UB(tmp0, tmp1, dst, dst_stride); + ST_D4(tmp0, tmp1, 0, 1, 0, 1, dst, dst_stride); dst += (4 * dst_stride); src10_r = src76_r; @@ -567,7 +566,7 @@ void ff_put_vp8_epel4_h6v6_msa(uint8_t *dst, ptrdiff_t dst_stride, SRARI_H2_SH(tmp0, tmp1, 7); SAT_SH2_SH(tmp0, tmp1, 7); out = PCKEV_XORI128_UB(tmp0, tmp1); - ST4x4_UB(out, out, 0, 1, 2, 3, dst, dst_stride); + ST_W4(out, 0, 1, 2, 3, dst, dst_stride); dst += (4 * dst_stride); hz_out3 = hz_out7; @@ -651,7 +650,7 @@ void ff_put_vp8_epel8_h6v6_msa(uint8_t *dst, ptrdiff_t dst_stride, SAT_SH4_SH(tmp0, tmp1, tmp2, tmp3, 7); vec0 = PCKEV_XORI128_UB(tmp0, tmp1); vec1 = PCKEV_XORI128_UB(tmp2, tmp3); - ST8x4_UB(vec0, vec1, dst, dst_stride); + ST_D4(vec0, vec1, 0, 1, 0, 1, dst, dst_stride); dst += (4 * dst_stride); hz_out4 = hz_out8; @@ -702,7 +701,7 @@ static void common_hz_4t_4x4_msa(uint8_t *src, int32_t src_stride, SRARI_H2_SH(out0, out1, 7); SAT_SH2_SH(out0, out1, 7); out = PCKEV_XORI128_UB(out0, out1); - ST4x4_UB(out, out, 0, 1, 2, 3, dst, dst_stride); + ST_W4(out, 0, 1, 2, 3, dst, dst_stride); } static void common_hz_4t_4x8_msa(uint8_t *src, int32_t src_stride, @@ -735,10 +734,9 @@ static void common_hz_4t_4x8_msa(uint8_t *src, int32_t src_stride, SRARI_H4_SH(out0, out1, out2, out3, 7); SAT_SH4_SH(out0, out1, out2, out3, 7); out = PCKEV_XORI128_UB(out0, out1); - ST4x4_UB(out, out, 0, 1, 2, 3, dst, dst_stride); - dst += (4 * dst_stride); + ST_W4(out, 0, 1, 2, 3, dst, dst_stride); out = PCKEV_XORI128_UB(out2, out3); - ST4x4_UB(out, out, 0, 1, 2, 3, dst, dst_stride); + ST_W4(out, 0, 1, 2, 3, dst + 4 * dst_stride, dst_stride); } static void common_hz_4t_4x16_msa(uint8_t *src, int32_t src_stride, @@ -769,10 +767,10 @@ static void common_hz_4t_4x16_msa(uint8_t *src, int32_t src_stride, SRARI_H4_SH(out0, out1, out2, out3, 7); SAT_SH4_SH(out0, out1, out2, out3, 7); out = PCKEV_XORI128_UB(out0, out1); - ST4x4_UB(out, out, 0, 1, 2, 3, dst, dst_stride); + ST_W4(out, 0, 1, 2, 3, dst, dst_stride); dst += (4 * dst_stride); out = PCKEV_XORI128_UB(out2, out3); - ST4x4_UB(out, out, 0, 1, 2, 3, dst, dst_stride); + ST_W4(out, 0, 1, 2, 3, dst, dst_stride); dst += (4 * dst_stride); LD_SB8(src, src_stride, src0, src1, src2, src3, src4, src5, src6, src7); @@ -785,10 +783,10 @@ static void common_hz_4t_4x16_msa(uint8_t *src, int32_t src_stride, SRARI_H4_SH(out0, out1, out2, out3, 7); SAT_SH4_SH(out0, out1, out2, out3, 7); out = PCKEV_XORI128_UB(out0, out1); - ST4x4_UB(out, out, 0, 1, 2, 3, dst, dst_stride); + ST_W4(out, 0, 1, 2, 3, dst, dst_stride); dst += (4 * dst_stride); out = PCKEV_XORI128_UB(out2, out3); - ST4x4_UB(out, out, 0, 1, 2, 3, dst, dst_stride); + ST_W4(out, 0, 1, 2, 3, dst, dst_stride); } void ff_put_vp8_epel4_h4_msa(uint8_t *dst, ptrdiff_t dst_stride, @@ -836,7 +834,7 @@ void ff_put_vp8_epel8_h4_msa(uint8_t *dst, ptrdiff_t dst_stride, SAT_SH4_SH(out0, out1, out2, out3, 7); tmp0 = PCKEV_XORI128_UB(out0, out1); tmp1 = PCKEV_XORI128_UB(out2, out3); - ST8x4_UB(tmp0, tmp1, dst, dst_stride); + ST_D4(tmp0, tmp1, 0, 1, 0, 1, dst, dst_stride); dst += (4 * dst_stride); } } @@ -932,7 +930,7 @@ void ff_put_vp8_epel4_v4_msa(uint8_t *dst, ptrdiff_t dst_stride, SRARI_H2_SH(out10, out32, 7); SAT_SH2_SH(out10, out32, 7); out = PCKEV_XORI128_UB(out10, out32); - ST4x4_UB(out, out, 0, 1, 2, 3, dst, dst_stride); + ST_W4(out, 0, 1, 2, 3, dst, dst_stride); dst += (4 * dst_stride); } } @@ -974,7 +972,7 @@ void ff_put_vp8_epel8_v4_msa(uint8_t *dst, ptrdiff_t dst_stride, SAT_SH4_SH(out0_r, out1_r, out2_r, out3_r, 7); tmp0 = PCKEV_XORI128_UB(out0_r, out1_r); tmp1 = PCKEV_XORI128_UB(out2_r, out3_r); - ST8x4_UB(tmp0, tmp1, dst, dst_stride); + ST_D4(tmp0, tmp1, 0, 1, 0, 1, dst, dst_stride); dst += (4 * dst_stride); src10_r = src98_r; @@ -1093,7 +1091,7 @@ void ff_put_vp8_epel4_h4v4_msa(uint8_t *dst, ptrdiff_t dst_stride, SRARI_H2_SH(tmp0, tmp1, 7); SAT_SH2_SH(tmp0, tmp1, 7); out = PCKEV_XORI128_UB(tmp0, tmp1); - ST4x4_UB(out, out, 0, 1, 2, 3, dst, dst_stride); + ST_W4(out, 0, 1, 2, 3, dst, dst_stride); dst += (4 * dst_stride); hz_out1 = hz_out5; @@ -1160,7 +1158,7 @@ void ff_put_vp8_epel8_h4v4_msa(uint8_t *dst, ptrdiff_t dst_stride, SAT_SH4_SH(tmp0, tmp1, tmp2, tmp3, 7); out0 = PCKEV_XORI128_UB(tmp0, tmp1); out1 = PCKEV_XORI128_UB(tmp2, tmp3); - ST8x4_UB(out0, out1, dst, dst_stride); + ST_D4(out0, out1, 0, 1, 0, 1, dst, dst_stride); dst += (4 * dst_stride); vec0 = vec4; @@ -1240,7 +1238,8 @@ void ff_put_vp8_epel4_h6v4_msa(uint8_t *dst, ptrdiff_t dst_stride, SAT_SH2_SH(tmp0, tmp1, 7); PCKEV_B2_UB(tmp0, tmp0, tmp1, tmp1, res0, res1); XORI_B2_128_UB(res0, res1); - ST4x4_UB(res0, res1, 0, 1, 0, 1, dst, dst_stride); + ST_W2(res0, 0, 1, dst, dst_stride); + ST_W2(res1, 0, 1, dst + 2 * dst_stride, dst_stride); dst += (4 * dst_stride); hz_out1 = hz_out5; @@ -1316,7 +1315,7 @@ void ff_put_vp8_epel8_h6v4_msa(uint8_t *dst, ptrdiff_t dst_stride, SAT_SH4_SH(tmp0, tmp1, tmp2, tmp3, 7); out0 = PCKEV_XORI128_UB(tmp0, tmp1); out1 = PCKEV_XORI128_UB(tmp2, tmp3); - ST8x4_UB(out0, out1, dst, dst_stride); + ST_D4(out0, out1, 0, 1, 0, 1, dst, dst_stride); dst += (4 * dst_stride); } } @@ -1391,7 +1390,7 @@ void ff_put_vp8_epel4_h4v6_msa(uint8_t *dst, ptrdiff_t dst_stride, SRARI_H2_SH(tmp0, tmp1, 7); SAT_SH2_SH(tmp0, tmp1, 7); out = PCKEV_XORI128_UB(tmp0, tmp1); - ST4x4_UB(out, out, 0, 1, 2, 3, dst, dst_stride); + ST_W4(out, 0, 1, 2, 3, dst, dst_stride); dst += (4 * dst_stride); hz_out3 = hz_out7; @@ -1464,7 +1463,7 @@ void ff_put_vp8_epel8_h4v6_msa(uint8_t *dst, ptrdiff_t dst_stride, SAT_SH4_SH(tmp0, tmp1, tmp2, tmp3, 7); vec0 = PCKEV_XORI128_UB(tmp0, tmp1); vec1 = PCKEV_XORI128_UB(tmp2, tmp3); - ST8x4_UB(vec0, vec1, dst, dst_stride); + ST_D4(vec0, vec1, 0, 1, 0, 1, dst, dst_stride); dst += (4 * dst_stride); hz_out4 = hz_out8; @@ -1509,7 +1508,8 @@ static void common_hz_2t_4x4_msa(uint8_t *src, int32_t src_stride, DOTP_UB2_UH(vec0, vec1, filt0, filt0, vec2, vec3); SRARI_H2_UH(vec2, vec3, 7); PCKEV_B2_UB(vec2, vec2, vec3, vec3, res0, res1); - ST4x4_UB(res0, res1, 0, 1, 0, 1, dst, dst_stride); + ST_W2(res0, 0, 1, dst, dst_stride); + ST_W2(res1, 0, 1, dst + 2 * dst_stride, dst_stride); } static void common_hz_2t_4x8_msa(uint8_t *src, int32_t src_stride, @@ -1535,9 +1535,10 @@ static void common_hz_2t_4x8_msa(uint8_t *src, int32_t src_stride, SRARI_H4_UH(vec4, vec5, vec6, vec7, 7); PCKEV_B4_SB(vec4, vec4, vec5, vec5, vec6, vec6, vec7, vec7, res0, res1, res2, res3); - ST4x4_UB(res0, res1, 0, 1, 0, 1, dst, dst_stride); - dst += (4 * dst_stride); - ST4x4_UB(res2, res3, 0, 1, 0, 1, dst, dst_stride); + ST_W2(res0, 0, 1, dst, dst_stride); + ST_W2(res1, 0, 1, dst + 2 * dst_stride, dst_stride); + ST_W2(res2, 0, 1, dst + 4 * dst_stride, dst_stride); + ST_W2(res3, 0, 1, dst + 6 * dst_stride, dst_stride); } void ff_put_vp8_bilinear4_h_msa(uint8_t *dst, ptrdiff_t dst_stride, @@ -1574,7 +1575,7 @@ static void common_hz_2t_8x4_msa(uint8_t *src, int32_t src_stride, vec0, vec1, vec2, vec3); SRARI_H4_UH(vec0, vec1, vec2, vec3, 7); PCKEV_B2_SB(vec1, vec0, vec3, vec2, src0, src1); - ST8x4_UB(src0, src1, dst, dst_stride); + ST_D4(src0, src1, 0, 1, 0, 1, dst, dst_stride); } static void common_hz_2t_8x8mult_msa(uint8_t *src, int32_t src_stride, @@ -1604,8 +1605,7 @@ static void common_hz_2t_8x8mult_msa(uint8_t *src, int32_t src_stride, src += (4 * src_stride); PCKEV_B2_SB(vec1, vec0, vec3, vec2, out0, out1); - ST8x4_UB(out0, out1, dst, dst_stride); - dst += (4 * dst_stride); + ST_D4(out0, out1, 0, 1, 0, 1, dst, dst_stride); VSHF_B2_UH(src0, src0, src1, src1, mask, mask, vec0, vec1); VSHF_B2_UH(src2, src2, src3, src3, mask, mask, vec2, vec3); @@ -1613,8 +1613,8 @@ static void common_hz_2t_8x8mult_msa(uint8_t *src, int32_t src_stride, vec0, vec1, vec2, vec3); SRARI_H4_UH(vec0, vec1, vec2, vec3, 7); PCKEV_B2_SB(vec1, vec0, vec3, vec2, out0, out1); - ST8x4_UB(out0, out1, dst, dst_stride); - dst += (4 * dst_stride); + ST_D4(out0, out1, 0, 1, 0, 1, dst + 4 * dst_stride, dst_stride); + dst += (8 * dst_stride); if (16 == height) { LD_SB4(src, src_stride, src0, src1, src2, src3); @@ -1629,7 +1629,7 @@ static void common_hz_2t_8x8mult_msa(uint8_t *src, int32_t src_stride, src += (4 * src_stride); PCKEV_B2_SB(vec1, vec0, vec3, vec2, out0, out1); - ST8x4_UB(out0, out1, dst, dst_stride); + ST_D4(out0, out1, 0, 1, 0, 1, dst, dst_stride); VSHF_B2_UH(src0, src0, src1, src1, mask, mask, vec0, vec1); VSHF_B2_UH(src2, src2, src3, src3, mask, mask, vec2, vec3); @@ -1637,7 +1637,7 @@ static void common_hz_2t_8x8mult_msa(uint8_t *src, int32_t src_stride, vec0, vec1, vec2, vec3); SRARI_H4_UH(vec0, vec1, vec2, vec3, 7); PCKEV_B2_SB(vec1, vec0, vec3, vec2, out0, out1); - ST8x4_UB(out0, out1, dst + 4 * dst_stride, dst_stride); + ST_D4(out0, out1, 0, 1, 0, 1, dst + 4 * dst_stride, dst_stride); } } @@ -1745,7 +1745,7 @@ static void common_vt_2t_4x4_msa(uint8_t *src, int32_t src_stride, SRARI_H2_UH(tmp0, tmp1, 7); SAT_UH2_UH(tmp0, tmp1, 7); src2110 = __msa_pckev_b((v16i8) tmp1, (v16i8) tmp0); - ST4x4_UB(src2110, src2110, 0, 1, 2, 3, dst, dst_stride); + ST_W4(src2110, 0, 1, 2, 3, dst, dst_stride); } static void common_vt_2t_4x8_msa(uint8_t *src, int32_t src_stride, @@ -1779,8 +1779,7 @@ static void common_vt_2t_4x8_msa(uint8_t *src, int32_t src_stride, SRARI_H4_UH(tmp0, tmp1, tmp2, tmp3, 7); SAT_UH4_UH(tmp0, tmp1, tmp2, tmp3, 7); PCKEV_B2_SB(tmp1, tmp0, tmp3, tmp2, src2110, src4332); - ST4x4_UB(src2110, src2110, 0, 1, 2, 3, dst, dst_stride); - ST4x4_UB(src4332, src4332, 0, 1, 2, 3, dst + 4 * dst_stride, dst_stride); + ST_W8(src2110, src4332, 0, 1, 2, 3, 0, 1, 2, 3, dst, dst_stride); } void ff_put_vp8_bilinear4_v_msa(uint8_t *dst, ptrdiff_t dst_stride, @@ -1817,7 +1816,7 @@ static void common_vt_2t_8x4_msa(uint8_t *src, int32_t src_stride, SRARI_H4_UH(tmp0, tmp1, tmp2, tmp3, 7); SAT_UH4_UH(tmp0, tmp1, tmp2, tmp3, 7); PCKEV_B2_SB(tmp1, tmp0, tmp3, tmp2, out0, out1); - ST8x4_UB(out0, out1, dst, dst_stride); + ST_D4(out0, out1, 0, 1, 0, 1, dst, dst_stride); } static void common_vt_2t_8x8mult_msa(uint8_t *src, int32_t src_stride, @@ -1851,16 +1850,15 @@ static void common_vt_2t_8x8mult_msa(uint8_t *src, int32_t src_stride, SRARI_H4_UH(tmp0, tmp1, tmp2, tmp3, 7); SAT_UH4_UH(tmp0, tmp1, tmp2, tmp3, 7); PCKEV_B2_SB(tmp1, tmp0, tmp3, tmp2, out0, out1); - ST8x4_UB(out0, out1, dst, dst_stride); - dst += (4 * dst_stride); + ST_D4(out0, out1, 0, 1, 0, 1, dst, dst_stride); DOTP_UB4_UH(vec4, vec5, vec6, vec7, filt0, filt0, filt0, filt0, tmp0, tmp1, tmp2, tmp3); SRARI_H4_UH(tmp0, tmp1, tmp2, tmp3, 7); SAT_UH4_UH(tmp0, tmp1, tmp2, tmp3, 7); PCKEV_B2_SB(tmp1, tmp0, tmp3, tmp2, out0, out1); - ST8x4_UB(out0, out1, dst, dst_stride); - dst += (4 * dst_stride); + ST_D4(out0, out1, 0, 1, 0, 1, dst + 4 * dst_stride, dst_stride); + dst += (8 * dst_stride); src0 = src8; } @@ -1964,7 +1962,8 @@ static void common_hv_2ht_2vt_4x4_msa(uint8_t *src, int32_t src_stride, SRARI_H2_UH(tmp0, tmp1, 7); SAT_UH2_UH(tmp0, tmp1, 7); PCKEV_B2_UB(tmp0, tmp0, tmp1, tmp1, res0, res1); - ST4x4_UB(res0, res1, 0, 1, 0, 1, dst, dst_stride); + ST_W2(res0, 0, 1, dst, dst_stride); + ST_W2(res1, 0, 1, dst + 2 * dst_stride, dst_stride); } static void common_hv_2ht_2vt_4x8_msa(uint8_t *src, int32_t src_stride, @@ -2008,9 +2007,10 @@ static void common_hv_2ht_2vt_4x8_msa(uint8_t *src, int32_t src_stride, SAT_UH4_UH(vec4, vec5, vec6, vec7, 7); PCKEV_B4_SB(vec4, vec4, vec5, vec5, vec6, vec6, vec7, vec7, res0, res1, res2, res3); - ST4x4_UB(res0, res1, 0, 1, 0, 1, dst, dst_stride); - dst += (4 * dst_stride); - ST4x4_UB(res2, res3, 0, 1, 0, 1, dst, dst_stride); + ST_W2(res0, 0, 1, dst, dst_stride); + ST_W2(res1, 0, 1, dst + 2 * dst_stride, dst_stride); + ST_W2(res2, 0, 1, dst + 4 * dst_stride, dst_stride); + ST_W2(res3, 0, 1, dst + 6 * dst_stride, dst_stride); } void ff_put_vp8_bilinear4_hv_msa(uint8_t *dst, ptrdiff_t dst_stride, @@ -2070,7 +2070,7 @@ static void common_hv_2ht_2vt_8x4_msa(uint8_t *src, int32_t src_stride, SRARI_H4_UH(tmp0, tmp1, tmp2, tmp3, 7); SAT_UH4_UH(tmp0, tmp1, tmp2, tmp3, 7); PCKEV_B2_SB(tmp1, tmp0, tmp3, tmp2, out0, out1); - ST8x4_UB(out0, out1, dst, dst_stride); + ST_D4(out0, out1, 0, 1, 0, 1, dst, dst_stride); } static void common_hv_2ht_2vt_8x8mult_msa(uint8_t *src, int32_t src_stride, @@ -2127,8 +2127,7 @@ static void common_hv_2ht_2vt_8x8mult_msa(uint8_t *src, int32_t src_stride, SRARI_H2_UH(tmp3, tmp4, 7); SAT_UH2_UH(tmp3, tmp4, 7); PCKEV_B2_SB(tmp2, tmp1, tmp4, tmp3, out0, out1); - ST8x4_UB(out0, out1, dst, dst_stride); - dst += (4 * dst_stride); + ST_D4(out0, out1, 0, 1, 0, 1, dst, dst_stride); hz_out1 = HORIZ_2TAP_FILT_UH(src1, src1, mask, filt_hz, 7); vec0 = (v16u8) __msa_ilvev_b((v16i8) hz_out1, (v16i8) hz_out0); @@ -2149,8 +2148,8 @@ static void common_hv_2ht_2vt_8x8mult_msa(uint8_t *src, int32_t src_stride, SRARI_H4_UH(tmp5, tmp6, tmp7, tmp8, 7); SAT_UH4_UH(tmp5, tmp6, tmp7, tmp8, 7); PCKEV_B2_SB(tmp6, tmp5, tmp8, tmp7, out0, out1); - ST8x4_UB(out0, out1, dst, dst_stride); - dst += (4 * dst_stride); + ST_D4(out0, out1, 0, 1, 0, 1, dst + 4 * dst_stride, dst_stride); + dst += (8 * dst_stride); } } diff --git a/libavcodec/mips/vp8dsp_init_mips.c b/libavcodec/mips/vp8dsp_init_mips.c index 3fc5f8e0a..7fd8fb0d3 100644 --- a/libavcodec/mips/vp8dsp_init_mips.c +++ b/libavcodec/mips/vp8dsp_init_mips.c @@ -193,10 +193,10 @@ static av_cold void vp8dsp_init_mmi(VP8DSPContext *dsp) av_cold void ff_vp8dsp_init_mips(VP8DSPContext *dsp) { -#if HAVE_MSA - vp8dsp_init_msa(dsp); -#endif // #if HAVE_MSA #if HAVE_MMI vp8dsp_init_mmi(dsp); #endif /* HAVE_MMI */ +#if HAVE_MSA + vp8dsp_init_msa(dsp); +#endif // #if HAVE_MSA } diff --git a/libavcodec/mips/vp8dsp_mmi.c b/libavcodec/mips/vp8dsp_mmi.c index f97262839..bd80aa144 100644 --- a/libavcodec/mips/vp8dsp_mmi.c +++ b/libavcodec/mips/vp8dsp_mmi.c @@ -25,6 +25,169 @@ #include "constants.h" #include "libavutil/mips/mmiutils.h" +#define DECLARE_DOUBLE_1 double db_1 +#define DECLARE_DOUBLE_2 double db_2 +#define DECLARE_UINT32_T uint32_t it_1 +#define RESTRICT_ASM_DOUBLE_1 [db_1]"=&f"(db_1) +#define RESTRICT_ASM_DOUBLE_2 [db_2]"=&f"(db_2) +#define RESTRICT_ASM_UINT32_T [it_1]"=&r"(it_1) + +#define MMI_PCMPGTUB(dst, src1, src2) \ + "pcmpeqb %[db_1], "#src1", "#src2" \n\t" \ + "pmaxub %[db_2], "#src1", "#src2" \n\t" \ + "pcmpeqb %[db_2], %[db_2], "#src1" \n\t" \ + "xor "#dst", %[db_2], %[db_1] \n\t" + +#define MMI_BTOH(dst_l, dst_r, src) \ + "xor %[db_1], %[db_1], %[db_1] \n\t" \ + "pcmpgtb %[db_2], %[db_1], "#src" \n\t" \ + "punpcklbh "#dst_r", "#src", %[db_2] \n\t" \ + "punpckhbh "#dst_l", "#src", %[db_2] \n\t" + +#define MMI_VP8_LOOP_FILTER \ + /* Calculation of hev */ \ + "dmtc1 %[thresh], %[ftmp3] \n\t" \ + "punpcklbh %[ftmp3], %[ftmp3], %[ftmp3] \n\t" \ + "punpcklhw %[ftmp3], %[ftmp3], %[ftmp3] \n\t" \ + "punpcklwd %[ftmp3], %[ftmp3], %[ftmp3] \n\t" \ + "pasubub %[ftmp0], %[p1], %[p0] \n\t" \ + "pasubub %[ftmp1], %[q1], %[q0] \n\t" \ + "pmaxub %[ftmp0], %[ftmp0], %[ftmp1] \n\t" \ + MMI_PCMPGTUB(%[hev], %[ftmp0], %[ftmp3]) \ + /* Calculation of mask */ \ + "pasubub %[ftmp1], %[p0], %[q0] \n\t" \ + "paddusb %[ftmp1], %[ftmp1], %[ftmp1] \n\t" \ + "pasubub %[ftmp2], %[p1], %[q1] \n\t" \ + "li %[tmp0], 0x09 \n\t" \ + "dmtc1 %[tmp0], %[ftmp3] \n\t" \ + PSRLB_MMI(%[ftmp2], %[ftmp3], %[ftmp4], %[ftmp5], %[ftmp2]) \ + "paddusb %[ftmp1], %[ftmp1], %[ftmp2] \n\t" \ + "dmtc1 %[e], %[ftmp3] \n\t" \ + "punpcklbh %[ftmp3], %[ftmp3], %[ftmp3] \n\t" \ + "punpcklhw %[ftmp3], %[ftmp3], %[ftmp3] \n\t" \ + "punpcklwd %[ftmp3], %[ftmp3], %[ftmp3] \n\t" \ + MMI_PCMPGTUB(%[mask], %[ftmp1], %[ftmp3]) \ + "pmaxub %[mask], %[mask], %[ftmp0] \n\t" \ + "pasubub %[ftmp1], %[p3], %[p2] \n\t" \ + "pasubub %[ftmp2], %[p2], %[p1] \n\t" \ + "pmaxub %[ftmp1], %[ftmp1], %[ftmp2] \n\t" \ + "pmaxub %[mask], %[mask], %[ftmp1] \n\t" \ + "pasubub %[ftmp1], %[q3], %[q2] \n\t" \ + "pasubub %[ftmp2], %[q2], %[q1] \n\t" \ + "pmaxub %[ftmp1], %[ftmp1], %[ftmp2] \n\t" \ + "pmaxub %[mask], %[mask], %[ftmp1] \n\t" \ + "dmtc1 %[i], %[ftmp3] \n\t" \ + "punpcklbh %[ftmp3], %[ftmp3], %[ftmp3] \n\t" \ + "punpcklhw %[ftmp3], %[ftmp3], %[ftmp3] \n\t" \ + "punpcklwd %[ftmp3], %[ftmp3], %[ftmp3] \n\t" \ + MMI_PCMPGTUB(%[mask], %[mask], %[ftmp3]) \ + "pcmpeqw %[ftmp3], %[ftmp3], %[ftmp3] \n\t" \ + "xor %[mask], %[mask], %[ftmp3] \n\t" \ + /* VP8_MBFILTER */ \ + "li %[tmp0], 0x80808080 \n\t" \ + "dmtc1 %[tmp0], %[ftmp7] \n\t" \ + "punpcklwd %[ftmp7], %[ftmp7], %[ftmp7] \n\t" \ + "xor %[p2], %[p2], %[ftmp7] \n\t" \ + "xor %[p1], %[p1], %[ftmp7] \n\t" \ + "xor %[p0], %[p0], %[ftmp7] \n\t" \ + "xor %[q0], %[q0], %[ftmp7] \n\t" \ + "xor %[q1], %[q1], %[ftmp7] \n\t" \ + "xor %[q2], %[q2], %[ftmp7] \n\t" \ + "psubsb %[ftmp4], %[p1], %[q1] \n\t" \ + "psubb %[ftmp5], %[q0], %[p0] \n\t" \ + MMI_BTOH(%[ftmp1], %[ftmp0], %[ftmp5]) \ + MMI_BTOH(%[ftmp3], %[ftmp2], %[ftmp4]) \ + /* Right part */ \ + "paddh %[ftmp5], %[ftmp0], %[ftmp0] \n\t" \ + "paddh %[ftmp0], %[ftmp0], %[ftmp5] \n\t" \ + "paddh %[ftmp0], %[ftmp2], %[ftmp0] \n\t" \ + /* Left part */ \ + "paddh %[ftmp5], %[ftmp1], %[ftmp1] \n\t" \ + "paddh %[ftmp1], %[ftmp1], %[ftmp5] \n\t" \ + "paddh %[ftmp1], %[ftmp3], %[ftmp1] \n\t" \ + /* Combine left and right part */ \ + "packsshb %[ftmp1], %[ftmp0], %[ftmp1] \n\t" \ + "and %[ftmp1], %[ftmp1], %[mask] \n\t" \ + "and %[ftmp2], %[ftmp1], %[hev] \n\t" \ + "li %[tmp0], 0x04040404 \n\t" \ + "dmtc1 %[tmp0], %[ftmp0] \n\t" \ + "punpcklwd %[ftmp0], %[ftmp0], %[ftmp0] \n\t" \ + "paddsb %[ftmp3], %[ftmp2], %[ftmp0] \n\t" \ + "li %[tmp0], 0x0B \n\t" \ + "dmtc1 %[tmp0], %[ftmp4] \n\t" \ + PSRAB_MMI(%[ftmp3], %[ftmp4], %[ftmp5], %[ftmp6], %[ftmp3]) \ + "li %[tmp0], 0x03030303 \n\t" \ + "dmtc1 %[tmp0], %[ftmp0] \n\t" \ + "punpcklwd %[ftmp0], %[ftmp0], %[ftmp0] \n\t" \ + "paddsb %[ftmp4], %[ftmp2], %[ftmp0] \n\t" \ + "li %[tmp0], 0x0B \n\t" \ + "dmtc1 %[tmp0], %[ftmp2] \n\t" \ + PSRAB_MMI(%[ftmp4], %[ftmp2], %[ftmp5], %[ftmp6], %[ftmp4]) \ + "psubsb %[q0], %[q0], %[ftmp3] \n\t" \ + "paddsb %[p0], %[p0], %[ftmp4] \n\t" \ + /* filt_val &= ~hev */ \ + "pcmpeqw %[ftmp0], %[ftmp0], %[ftmp0] \n\t" \ + "xor %[hev], %[hev], %[ftmp0] \n\t" \ + "and %[ftmp1], %[ftmp1], %[hev] \n\t" \ + MMI_BTOH(%[ftmp5], %[ftmp6], %[ftmp1]) \ + "li %[tmp0], 0x07 \n\t" \ + "dmtc1 %[tmp0], %[ftmp2] \n\t" \ + "li %[tmp0], 0x001b001b \n\t" \ + "dmtc1 %[tmp0], %[ftmp1] \n\t" \ + "punpcklwd %[ftmp1], %[ftmp1], %[ftmp1] \n\t" \ + "li %[tmp0], 0x003f003f \n\t" \ + "dmtc1 %[tmp0], %[ftmp0] \n\t" \ + "punpcklwd %[ftmp0], %[ftmp0], %[ftmp0] \n\t" \ + /* Right part */ \ + "pmullh %[ftmp3], %[ftmp6], %[ftmp1] \n\t" \ + "paddh %[ftmp3], %[ftmp3], %[ftmp0] \n\t" \ + "psrah %[ftmp3], %[ftmp3], %[ftmp2] \n\t" \ + /* Left part */ \ + "pmullh %[ftmp4], %[ftmp5], %[ftmp1] \n\t" \ + "paddh %[ftmp4], %[ftmp4], %[ftmp0] \n\t" \ + "psrah %[ftmp4], %[ftmp4], %[ftmp2] \n\t" \ + /* Combine left and right part */ \ + "packsshb %[ftmp4], %[ftmp3], %[ftmp4] \n\t" \ + "psubsb %[q0], %[q0], %[ftmp4] \n\t" \ + "xor %[q0], %[q0], %[ftmp7] \n\t" \ + "paddsb %[p0], %[p0], %[ftmp4] \n\t" \ + "xor %[p0], %[p0], %[ftmp7] \n\t" \ + "li %[tmp0], 0x00120012 \n\t" \ + "dmtc1 %[tmp0], %[ftmp1] \n\t" \ + "punpcklwd %[ftmp1], %[ftmp1], %[ftmp1] \n\t" \ + /* Right part */ \ + "pmullh %[ftmp3], %[ftmp6], %[ftmp1] \n\t" \ + "paddh %[ftmp3], %[ftmp3], %[ftmp0] \n\t" \ + "psrah %[ftmp3], %[ftmp3], %[ftmp2] \n\t" \ + /* Left part */ \ + "pmullh %[ftmp4], %[ftmp5], %[ftmp1] \n\t" \ + "paddh %[ftmp4], %[ftmp4], %[ftmp0] \n\t" \ + "psrah %[ftmp4], %[ftmp4], %[ftmp2] \n\t" \ + /* Combine left and right part */ \ + "packsshb %[ftmp4], %[ftmp3], %[ftmp4] \n\t" \ + "psubsb %[q1], %[q1], %[ftmp4] \n\t" \ + "xor %[q1], %[q1], %[ftmp7] \n\t" \ + "paddsb %[p1], %[p1], %[ftmp4] \n\t" \ + "xor %[p1], %[p1], %[ftmp7] \n\t" \ + "li %[tmp0], 0x03 \n\t" \ + "dmtc1 %[tmp0], %[ftmp1] \n\t" \ + /* Right part */ \ + "psllh %[ftmp3], %[ftmp6], %[ftmp1] \n\t" \ + "paddh %[ftmp3], %[ftmp3], %[ftmp6] \n\t" \ + "paddh %[ftmp3], %[ftmp3], %[ftmp0] \n\t" \ + "psrah %[ftmp3], %[ftmp3], %[ftmp2] \n\t" \ + /* Left part */ \ + "psllh %[ftmp4], %[ftmp5], %[ftmp1] \n\t" \ + "paddh %[ftmp4], %[ftmp4], %[ftmp5] \n\t" \ + "paddh %[ftmp4], %[ftmp4], %[ftmp0] \n\t" \ + "psrah %[ftmp4], %[ftmp4], %[ftmp2] \n\t" \ + /* Combine left and right part */ \ + "packsshb %[ftmp4], %[ftmp3], %[ftmp4] \n\t" \ + "psubsb %[q2], %[q2], %[ftmp4] \n\t" \ + "xor %[q2], %[q2], %[ftmp7] \n\t" \ + "paddsb %[p2], %[p2], %[ftmp4] \n\t" \ + "xor %[p2], %[p2], %[ftmp7] \n\t" + #define PUT_VP8_EPEL4_H6_MMI(src, dst) \ MMI_ULWC1(%[ftmp1], src, 0x00) \ "punpcklbh %[ftmp2], %[ftmp1], %[ftmp0] \n\t" \ @@ -621,15 +784,71 @@ static av_always_inline int vp8_normal_limit(uint8_t *p, ptrdiff_t stride, static av_always_inline void vp8_v_loop_filter8_mmi(uint8_t *dst, ptrdiff_t stride, int flim_E, int flim_I, int hev_thresh) { - int i; - - for (i = 0; i < 8; i++) - if (vp8_normal_limit(dst + i * 1, stride, flim_E, flim_I)) { - if (hev(dst + i * 1, stride, hev_thresh)) - vp8_filter_common_is4tap(dst + i * 1, stride); - else - filter_mbedge(dst + i * 1, stride); - } + double ftmp[18]; + uint32_t tmp[1]; + DECLARE_DOUBLE_1; + DECLARE_DOUBLE_2; + DECLARE_UINT32_T; + __asm__ volatile( + /* Get data from dst */ + "gsldlc1 %[q0], 0x07(%[dst]) \n\t" + "gsldrc1 %[q0], 0x00(%[dst]) \n\t" + PTR_SUBU "%[tmp0], %[dst], %[stride] \n\t" + "gsldlc1 %[p0], 0x07(%[tmp0]) \n\t" + "gsldrc1 %[p0], 0x00(%[tmp0]) \n\t" + PTR_SUBU "%[tmp0], %[tmp0], %[stride] \n\t" + "gsldlc1 %[p1], 0x07(%[tmp0]) \n\t" + "gsldrc1 %[p1], 0x00(%[tmp0]) \n\t" + PTR_SUBU "%[tmp0], %[tmp0], %[stride] \n\t" + "gsldlc1 %[p2], 0x07(%[tmp0]) \n\t" + "gsldrc1 %[p2], 0x00(%[tmp0]) \n\t" + PTR_SUBU "%[tmp0], %[tmp0], %[stride] \n\t" + "gsldlc1 %[p3], 0x07(%[tmp0]) \n\t" + "gsldrc1 %[p3], 0x00(%[tmp0]) \n\t" + PTR_ADDU "%[tmp0], %[dst], %[stride] \n\t" + "gsldlc1 %[q1], 0x07(%[tmp0]) \n\t" + "gsldrc1 %[q1], 0x00(%[tmp0]) \n\t" + PTR_ADDU "%[tmp0], %[tmp0], %[stride] \n\t" + "gsldlc1 %[q2], 0x07(%[tmp0]) \n\t" + "gsldrc1 %[q2], 0x00(%[tmp0]) \n\t" + PTR_ADDU "%[tmp0], %[tmp0], %[stride] \n\t" + "gsldlc1 %[q3], 0x07(%[tmp0]) \n\t" + "gsldrc1 %[q3], 0x00(%[tmp0]) \n\t" + MMI_VP8_LOOP_FILTER + /* Move to dst */ + "gssdlc1 %[q0], 0x07(%[dst]) \n\t" + "gssdrc1 %[q0], 0x00(%[dst]) \n\t" + PTR_SUBU "%[tmp0], %[dst], %[stride] \n\t" + "gssdlc1 %[p0], 0x07(%[tmp0]) \n\t" + "gssdrc1 %[p0], 0x00(%[tmp0]) \n\t" + PTR_SUBU "%[tmp0], %[tmp0], %[stride] \n\t" + "gssdlc1 %[p1], 0x07(%[tmp0]) \n\t" + "gssdrc1 %[p1], 0x00(%[tmp0]) \n\t" + PTR_SUBU "%[tmp0], %[tmp0], %[stride] \n\t" + "gssdlc1 %[p2], 0x07(%[tmp0]) \n\t" + "gssdrc1 %[p2], 0x00(%[tmp0]) \n\t" + PTR_ADDU "%[tmp0], %[dst], %[stride] \n\t" + "gssdlc1 %[q1], 0x07(%[tmp0]) \n\t" + "gssdrc1 %[q1], 0x00(%[tmp0]) \n\t" + PTR_ADDU "%[tmp0], %[tmp0], %[stride] \n\t" + "gssdlc1 %[q2], 0x07(%[tmp0]) \n\t" + "gssdrc1 %[q2], 0x00(%[tmp0]) \n\t" + : [p3]"=&f"(ftmp[0]), [p2]"=&f"(ftmp[1]), + [p1]"=&f"(ftmp[2]), [p0]"=&f"(ftmp[3]), + [q0]"=&f"(ftmp[4]), [q1]"=&f"(ftmp[5]), + [q2]"=&f"(ftmp[6]), [q3]"=&f"(ftmp[7]), + [ftmp0]"=&f"(ftmp[8]), [ftmp1]"=&f"(ftmp[9]), + [ftmp2]"=&f"(ftmp[10]), [ftmp3]"=&f"(ftmp[11]), + [hev]"=&f"(ftmp[12]), [mask]"=&f"(ftmp[13]), + [ftmp4]"=&f"(ftmp[14]), [ftmp5]"=&f"(ftmp[15]), + [ftmp6]"=&f"(ftmp[16]), [ftmp7]"=&f"(ftmp[17]), + [dst]"+&r"(dst), [tmp0]"=&r"(tmp[0]), + RESTRICT_ASM_DOUBLE_1, RESTRICT_ASM_DOUBLE_2, + RESTRICT_ASM_UINT32_T + : [e]"r"((mips_reg)flim_E), [thresh]"r"((mips_reg)hev_thresh), + [i]"r"((mips_reg)flim_I), [stride]"r"((mips_reg)stride) + : "memory" + ); } static av_always_inline void vp8_v_loop_filter8_inner_mmi(uint8_t *dst, @@ -650,15 +869,85 @@ static av_always_inline void vp8_v_loop_filter8_inner_mmi(uint8_t *dst, static av_always_inline void vp8_h_loop_filter8_mmi(uint8_t *dst, ptrdiff_t stride, int flim_E, int flim_I, int hev_thresh) { - int i; - - for (i = 0; i < 8; i++) - if (vp8_normal_limit(dst + i * stride, 1, flim_E, flim_I)) { - if (hev(dst + i * stride, 1, hev_thresh)) - vp8_filter_common_is4tap(dst + i * stride, 1); - else - filter_mbedge(dst + i * stride, 1); - } + double ftmp[18]; + uint32_t tmp[1]; + DECLARE_DOUBLE_1; + DECLARE_DOUBLE_2; + DECLARE_UINT32_T; + __asm__ volatile( + /* Get data from dst */ + "gsldlc1 %[p3], 0x03(%[dst]) \n\t" + "gsldrc1 %[p3], -0x04(%[dst]) \n\t" + PTR_ADDU "%[tmp0], %[dst], %[stride] \n\t" + "gsldlc1 %[p2], 0x03(%[tmp0]) \n\t" + "gsldrc1 %[p2], -0x04(%[tmp0]) \n\t" + PTR_ADDU "%[tmp0], %[tmp0], %[stride] \n\t" + "gsldlc1 %[p1], 0x03(%[tmp0]) \n\t" + "gsldrc1 %[p1], -0x04(%[tmp0]) \n\t" + PTR_ADDU "%[tmp0], %[tmp0], %[stride] \n\t" + "gsldlc1 %[p0], 0x03(%[tmp0]) \n\t" + "gsldrc1 %[p0], -0x04(%[tmp0]) \n\t" + PTR_ADDU "%[tmp0], %[tmp0], %[stride] \n\t" + "gsldlc1 %[q0], 0x03(%[tmp0]) \n\t" + "gsldrc1 %[q0], -0x04(%[tmp0]) \n\t" + PTR_ADDU "%[tmp0], %[tmp0], %[stride] \n\t" + "gsldlc1 %[q1], 0x03(%[tmp0]) \n\t" + "gsldrc1 %[q1], -0x04(%[tmp0]) \n\t" + PTR_ADDU "%[tmp0], %[tmp0], %[stride] \n\t" + "gsldlc1 %[q2], 0x03(%[tmp0]) \n\t" + "gsldrc1 %[q2], -0x04(%[tmp0]) \n\t" + PTR_ADDU "%[tmp0], %[tmp0], %[stride] \n\t" + "gsldlc1 %[q3], 0x03(%[tmp0]) \n\t" + "gsldrc1 %[q3], -0x04(%[tmp0]) \n\t" + /* Matrix transpose */ + TRANSPOSE_8B(%[p3], %[p2], %[p1], %[p0], + %[q0], %[q1], %[q2], %[q3], + %[ftmp1], %[ftmp2], %[ftmp3], %[ftmp4]) + MMI_VP8_LOOP_FILTER + /* Matrix transpose */ + TRANSPOSE_8B(%[p3], %[p2], %[p1], %[p0], + %[q0], %[q1], %[q2], %[q3], + %[ftmp1], %[ftmp2], %[ftmp3], %[ftmp4]) + /* Move to dst */ + "gssdlc1 %[p3], 0x03(%[dst]) \n\t" + "gssdrc1 %[p3], -0x04(%[dst]) \n\t" + PTR_ADDU "%[dst], %[dst], %[stride] \n\t" + "gssdlc1 %[p2], 0x03(%[dst]) \n\t" + "gssdrc1 %[p2], -0x04(%[dst]) \n\t" + PTR_ADDU "%[dst], %[dst], %[stride] \n\t" + "gssdlc1 %[p1], 0x03(%[dst]) \n\t" + "gssdrc1 %[p1], -0x04(%[dst]) \n\t" + PTR_ADDU "%[dst], %[dst], %[stride] \n\t" + "gssdlc1 %[p0], 0x03(%[dst]) \n\t" + "gssdrc1 %[p0], -0x04(%[dst]) \n\t" + PTR_ADDU "%[dst], %[dst], %[stride] \n\t" + "gssdlc1 %[q0], 0x03(%[dst]) \n\t" + "gssdrc1 %[q0], -0x04(%[dst]) \n\t" + PTR_ADDU "%[dst], %[dst], %[stride] \n\t" + "gssdlc1 %[q1], 0x03(%[dst]) \n\t" + "gssdrc1 %[q1], -0x04(%[dst]) \n\t" + PTR_ADDU "%[dst], %[dst], %[stride] \n\t" + "gssdlc1 %[q2], 0x03(%[dst]) \n\t" + "gssdrc1 %[q2], -0x04(%[dst]) \n\t" + PTR_ADDU "%[dst], %[dst], %[stride] \n\t" + "gssdlc1 %[q3], 0x03(%[dst]) \n\t" + "gssdrc1 %[q3], -0x04(%[dst]) \n\t" + : [p3]"=&f"(ftmp[0]), [p2]"=&f"(ftmp[1]), + [p1]"=&f"(ftmp[2]), [p0]"=&f"(ftmp[3]), + [q0]"=&f"(ftmp[4]), [q1]"=&f"(ftmp[5]), + [q2]"=&f"(ftmp[6]), [q3]"=&f"(ftmp[7]), + [ftmp0]"=&f"(ftmp[8]), [ftmp1]"=&f"(ftmp[9]), + [ftmp2]"=&f"(ftmp[10]), [ftmp3]"=&f"(ftmp[11]), + [hev]"=&f"(ftmp[12]), [mask]"=&f"(ftmp[13]), + [ftmp4]"=&f"(ftmp[14]), [ftmp5]"=&f"(ftmp[15]), + [ftmp6]"=&f"(ftmp[16]), [ftmp7]"=&f"(ftmp[17]), + [dst]"+&r"(dst), [tmp0]"=&r"(tmp[0]), + RESTRICT_ASM_DOUBLE_1, RESTRICT_ASM_DOUBLE_2, + RESTRICT_ASM_UINT32_T + : [e]"r"((mips_reg)flim_E), [thresh]"r"((mips_reg)hev_thresh), + [i]"r"((mips_reg)flim_I), [stride]"r"((mips_reg)stride) + : "memory" + ); } static av_always_inline void vp8_h_loop_filter8_inner_mmi(uint8_t *dst, @@ -890,8 +1179,7 @@ void ff_vp8_idct_add_mmi(uint8_t *dst, int16_t block[16], ptrdiff_t stride) MMI_SDC1(%[ftmp0], %[block], 0x18) TRANSPOSE_4H(%[ftmp1], %[ftmp2], %[ftmp3], %[ftmp4], - %[ftmp5], %[ftmp6], %[ftmp7], %[ftmp8], - %[ftmp9], %[tmp0], %[ftmp0], %[ftmp10]) + %[ftmp5], %[ftmp6], %[ftmp7], %[ftmp8]) // t[0 4 8 12] "paddh %[ftmp5], %[ftmp1], %[ftmp3] \n\t" @@ -926,8 +1214,7 @@ void ff_vp8_idct_add_mmi(uint8_t *dst, int16_t block[16], ptrdiff_t stride) "psrah %[ftmp4], %[ftmp4], %[ftmp11] \n\t" TRANSPOSE_4H(%[ftmp1], %[ftmp2], %[ftmp3], %[ftmp4], - %[ftmp5], %[ftmp6], %[ftmp7], %[ftmp8], - %[ftmp9], %[tmp0], %[ftmp0], %[ftmp10]) + %[ftmp5], %[ftmp6], %[ftmp7], %[ftmp8]) MMI_LWC1(%[ftmp5], %[dst0], 0x00) MMI_LWC1(%[ftmp6], %[dst1], 0x00) @@ -1083,29 +1370,16 @@ void ff_vp8_idct_dc_add4uv_mmi(uint8_t *dst, int16_t block[4][16], void ff_vp8_v_loop_filter16_mmi(uint8_t *dst, ptrdiff_t stride, int flim_E, int flim_I, int hev_thresh) { - int i; - - for (i = 0; i < 16; i++) - if (vp8_normal_limit(dst + i * 1, stride, flim_E, flim_I)) { - if (hev(dst + i * 1, stride, hev_thresh)) - vp8_filter_common_is4tap(dst + i * 1, stride); - else - filter_mbedge(dst + i * 1, stride); - } + vp8_v_loop_filter8_mmi(dst, stride, flim_E, flim_I, hev_thresh); + vp8_v_loop_filter8_mmi(dst + 8, stride, flim_E, flim_I, hev_thresh); } void ff_vp8_h_loop_filter16_mmi(uint8_t *dst, ptrdiff_t stride, int flim_E, int flim_I, int hev_thresh) { - int i; - - for (i = 0; i < 16; i++) - if (vp8_normal_limit(dst + i * stride, 1, flim_E, flim_I)) { - if (hev(dst + i * stride, 1, hev_thresh)) - vp8_filter_common_is4tap(dst + i * stride, 1); - else - filter_mbedge(dst + i * stride, 1); - } + vp8_h_loop_filter8_mmi(dst, stride, flim_E, flim_I, hev_thresh); + vp8_h_loop_filter8_mmi(dst + 8 * stride, stride, flim_E, flim_I, + hev_thresh); } void ff_vp8_v_loop_filter8uv_mmi(uint8_t *dstU, uint8_t *dstV, ptrdiff_t stride, diff --git a/libavcodec/mips/vp9_idct_msa.c b/libavcodec/mips/vp9_idct_msa.c index bd762f269..1f3277013 100644 --- a/libavcodec/mips/vp9_idct_msa.c +++ b/libavcodec/mips/vp9_idct_msa.c @@ -241,7 +241,7 @@ static const int32_t sinpi_4_9 = 15212; res0_m, res1_m, res2_m, res3_m); \ CLIP_SH4_0_255(res0_m, res1_m, res2_m, res3_m); \ PCKEV_B2_SB(res1_m, res0_m, res3_m, res2_m, tmp0_m, tmp1_m); \ - ST8x4_UB(tmp0_m, tmp1_m, dst_m, dst_stride); \ + ST_D4(tmp0_m, tmp1_m, 0, 1, 0, 1, dst_m, dst_stride); \ } #define VP9_IDCT4x4(in0, in1, in2, in3, out0, out1, out2, out3) \ @@ -364,7 +364,10 @@ static void vp9_idct4x4_colcol_addblk_msa(int16_t *input, uint8_t *dst, v8i16 zero = { 0 }; /* load vector elements of 4x4 block */ - LD4x4_SH(input, in0, in1, in2, in3); + in0 = LD_SH(input); + in2 = LD_SH(input + 8); + in1 = (v8i16) __msa_ilvl_d((v2i64) in0, (v2i64) in0); + in3 = (v8i16) __msa_ilvl_d((v2i64) in2, (v2i64) in2); ST_SH2(zero, zero, input, 8); /* rows */ VP9_IDCT4x4(in0, in1, in2, in3, in0, in1, in2, in3); @@ -383,7 +386,10 @@ static void vp9_iadst4x4_colcol_addblk_msa(int16_t *input, uint8_t *dst, v8i16 zero = { 0 }; /* load vector elements of 4x4 block */ - LD4x4_SH(input, in0, in1, in2, in3); + in0 = LD_SH(input); + in2 = LD_SH(input + 8); + in1 = (v8i16) __msa_ilvl_d((v2i64) in0, (v2i64) in0); + in3 = (v8i16) __msa_ilvl_d((v2i64) in2, (v2i64) in2); ST_SH2(zero, zero, input, 8); /* rows */ VP9_IADST4x4(in0, in1, in2, in3, in0, in1, in2, in3); @@ -402,7 +408,10 @@ static void vp9_iadst_idct_4x4_add_msa(int16_t *input, uint8_t *dst, v8i16 zero = { 0 }; /* load vector elements of 4x4 block */ - LD4x4_SH(input, in0, in1, in2, in3); + in0 = LD_SH(input); + in2 = LD_SH(input + 8); + in1 = (v8i16) __msa_ilvl_d((v2i64) in0, (v2i64) in0); + in3 = (v8i16) __msa_ilvl_d((v2i64) in2, (v2i64) in2); ST_SH2(zero, zero, input, 8); /* cols */ VP9_IADST4x4(in0, in1, in2, in3, in0, in1, in2, in3); @@ -421,7 +430,10 @@ static void vp9_idct_iadst_4x4_add_msa(int16_t *input, uint8_t *dst, v8i16 zero = { 0 }; /* load vector elements of 4x4 block */ - LD4x4_SH(input, in0, in1, in2, in3); + in0 = LD_SH(input); + in2 = LD_SH(input + 8); + in1 = (v8i16) __msa_ilvl_d((v2i64) in0, (v2i64) in0); + in3 = (v8i16) __msa_ilvl_d((v2i64) in2, (v2i64) in2); ST_SH2(zero, zero, input, 8); /* cols */ VP9_IDCT4x4(in0, in1, in2, in3, in0, in1, in2, in3); @@ -753,13 +765,13 @@ static void vp9_iadst8x8_colcol_addblk_msa(int16_t *input, uint8_t *dst, res0 += out0; res0 = CLIP_SH_0_255(res0); res0 = (v8i16) __msa_pckev_b((v16i8) res0, (v16i8) res0); - ST8x1_UB(res0, dst); + ST_D1(res0, 0, dst); res7 = (v8i16) __msa_ilvr_b((v16i8) zero, (v16i8) dst7); res7 += out7; res7 = CLIP_SH_0_255(res7); res7 = (v8i16) __msa_pckev_b((v16i8) res7, (v16i8) res7); - ST8x1_UB(res7, dst + 7 * dst_stride); + ST_D1(res7, 0, dst + 7 * dst_stride); cnst1 = __msa_fill_h(cospi_24_64); cnst0 = __msa_fill_h(cospi_8_64); @@ -782,8 +794,8 @@ static void vp9_iadst8x8_colcol_addblk_msa(int16_t *input, uint8_t *dst, ADD2(res1, out1, res6, out6, res1, res6); CLIP_SH2_0_255(res1, res6); PCKEV_B2_SH(res1, res1, res6, res6, res1, res6); - ST8x1_UB(res1, dst + dst_stride); - ST8x1_UB(res6, dst + 6 * dst_stride); + ST_D1(res1, 0, dst + dst_stride); + ST_D1(res6, 0, dst + 6 * dst_stride); cnst0 = __msa_fill_h(cospi_16_64); cnst1 = -cnst0; @@ -801,8 +813,8 @@ static void vp9_iadst8x8_colcol_addblk_msa(int16_t *input, uint8_t *dst, ADD2(res3, out3, res4, out4, res3, res4); CLIP_SH2_0_255(res3, res4); PCKEV_B2_SH(res3, res3, res4, res4, res3, res4); - ST8x1_UB(res3, dst + 3 * dst_stride); - ST8x1_UB(res4, dst + 4 * dst_stride); + ST_D1(res3, 0, dst + 3 * dst_stride); + ST_D1(res4, 0, dst + 4 * dst_stride); out2 = VP9_DOT_SHIFT_RIGHT_PCK_H(temp2, temp3, cnst0); out5 = VP9_DOT_SHIFT_RIGHT_PCK_H(temp2, temp3, cnst1); @@ -814,8 +826,8 @@ static void vp9_iadst8x8_colcol_addblk_msa(int16_t *input, uint8_t *dst, ADD2(res2, out2, res5, out5, res2, res5); CLIP_SH2_0_255(res2, res5); PCKEV_B2_SH(res2, res2, res5, res5, res2, res5); - ST8x1_UB(res2, dst + 2 * dst_stride); - ST8x1_UB(res5, dst + 5 * dst_stride); + ST_D1(res2, 0, dst + 2 * dst_stride); + ST_D1(res5, 0, dst + 5 * dst_stride); } static void vp9_iadst_idct_8x8_add_msa(int16_t *input, uint8_t *dst, @@ -1354,8 +1366,8 @@ static void vp9_iadst16_1d_columns_addblk_msa(int16_t *input, uint8_t *dst, ADD2(res0, out0, res1, out1, res0, res1); CLIP_SH2_0_255(res0, res1); PCKEV_B2_SH(res0, res0, res1, res1, res0, res1); - ST8x1_UB(res0, dst); - ST8x1_UB(res1, dst + 15 * dst_stride); + ST_D1(res0, 0, dst); + ST_D1(res1, 0, dst + 15 * dst_stride); k0 = VP9_SET_COSPI_PAIR(cospi_12_64, cospi_20_64); k1 = VP9_SET_COSPI_PAIR(-cospi_20_64, cospi_12_64); @@ -1371,8 +1383,8 @@ static void vp9_iadst16_1d_columns_addblk_msa(int16_t *input, uint8_t *dst, ADD2(res8, out8, res9, out9, res8, res9); CLIP_SH2_0_255(res8, res9); PCKEV_B2_SH(res8, res8, res9, res9, res8, res9); - ST8x1_UB(res8, dst + dst_stride); - ST8x1_UB(res9, dst + 14 * dst_stride); + ST_D1(res8, 0, dst + dst_stride); + ST_D1(res9, 0, dst + 14 * dst_stride); k0 = VP9_SET_COSPI_PAIR(cospi_8_64, cospi_24_64); k1 = VP9_SET_COSPI_PAIR(cospi_24_64, -cospi_8_64); @@ -1386,8 +1398,8 @@ static void vp9_iadst16_1d_columns_addblk_msa(int16_t *input, uint8_t *dst, ADD2(res4, out4, res5, out5, res4, res5); CLIP_SH2_0_255(res4, res5); PCKEV_B2_SH(res4, res4, res5, res5, res4, res5); - ST8x1_UB(res4, dst + 3 * dst_stride); - ST8x1_UB(res5, dst + 12 * dst_stride); + ST_D1(res4, 0, dst + 3 * dst_stride); + ST_D1(res5, 0, dst + 12 * dst_stride); VP9_MADD_BF(h1, h3, h5, h7, k0, k1, k2, k0, out12, out14, out13, out15); out13 = -out13; @@ -1398,8 +1410,8 @@ static void vp9_iadst16_1d_columns_addblk_msa(int16_t *input, uint8_t *dst, ADD2(res12, out12, res13, out13, res12, res13); CLIP_SH2_0_255(res12, res13); PCKEV_B2_SH(res12, res12, res13, res13, res12, res13); - ST8x1_UB(res12, dst + 2 * dst_stride); - ST8x1_UB(res13, dst + 13 * dst_stride); + ST_D1(res12, 0, dst + 2 * dst_stride); + ST_D1(res13, 0, dst + 13 * dst_stride); k0 = VP9_SET_COSPI_PAIR(cospi_16_64, cospi_16_64); k3 = VP9_SET_COSPI_PAIR(-cospi_16_64, cospi_16_64); @@ -1411,8 +1423,8 @@ static void vp9_iadst16_1d_columns_addblk_msa(int16_t *input, uint8_t *dst, ADD2(res6, out6, res7, out7, res6, res7); CLIP_SH2_0_255(res6, res7); PCKEV_B2_SH(res6, res6, res7, res7, res6, res7); - ST8x1_UB(res6, dst + 4 * dst_stride); - ST8x1_UB(res7, dst + 11 * dst_stride); + ST_D1(res6, 0, dst + 4 * dst_stride); + ST_D1(res7, 0, dst + 11 * dst_stride); VP9_MADD_SHORT(out10, out11, k0, k3, out10, out11); SRARI_H2_SH(out10, out11, 6); @@ -1422,8 +1434,8 @@ static void vp9_iadst16_1d_columns_addblk_msa(int16_t *input, uint8_t *dst, ADD2(res10, out10, res11, out11, res10, res11); CLIP_SH2_0_255(res10, res11); PCKEV_B2_SH(res10, res10, res11, res11, res10, res11); - ST8x1_UB(res10, dst + 6 * dst_stride); - ST8x1_UB(res11, dst + 9 * dst_stride); + ST_D1(res10, 0, dst + 6 * dst_stride); + ST_D1(res11, 0, dst + 9 * dst_stride); k1 = VP9_SET_COSPI_PAIR(-cospi_16_64, -cospi_16_64); k2 = VP9_SET_COSPI_PAIR(cospi_16_64, -cospi_16_64); @@ -1435,8 +1447,8 @@ static void vp9_iadst16_1d_columns_addblk_msa(int16_t *input, uint8_t *dst, ADD2(res2, out2, res3, out3, res2, res3); CLIP_SH2_0_255(res2, res3); PCKEV_B2_SH(res2, res2, res3, res3, res2, res3); - ST8x1_UB(res2, dst + 7 * dst_stride); - ST8x1_UB(res3, dst + 8 * dst_stride); + ST_D1(res2, 0, dst + 7 * dst_stride); + ST_D1(res3, 0, dst + 8 * dst_stride); VP9_MADD_SHORT(out14, out15, k1, k2, out14, out15); SRARI_H2_SH(out14, out15, 6); @@ -1446,8 +1458,8 @@ static void vp9_iadst16_1d_columns_addblk_msa(int16_t *input, uint8_t *dst, ADD2(res14, out14, res15, out15, res14, res15); CLIP_SH2_0_255(res14, res15); PCKEV_B2_SH(res14, res14, res15, res15, res14, res15); - ST8x1_UB(res14, dst + 5 * dst_stride); - ST8x1_UB(res15, dst + 10 * dst_stride); + ST_D1(res14, 0, dst + 5 * dst_stride); + ST_D1(res15, 0, dst + 10 * dst_stride); } static void vp9_iadst16x16_colcol_addblk_msa(int16_t *input, uint8_t *dst, diff --git a/libavcodec/mips/vp9_intra_msa.c b/libavcodec/mips/vp9_intra_msa.c index 54cf0ae94..97cf21290 100644 --- a/libavcodec/mips/vp9_intra_msa.c +++ b/libavcodec/mips/vp9_intra_msa.c @@ -378,7 +378,8 @@ void ff_tm_4x4_msa(uint8_t *dst, ptrdiff_t dst_stride, IPRED_SUBS_UH2_UH(src_top_left, src_top_left, vec2, vec3); SAT_UH4_UH(vec0, vec1, vec2, vec3, 7); PCKEV_B2_SB(vec1, vec0, vec3, vec2, tmp0, tmp1); - ST4x4_UB(tmp0, tmp1, 0, 2, 0, 2, dst, dst_stride); + ST_W2(tmp0, 0, 2, dst, dst_stride); + ST_W2(tmp1, 0, 2, dst + 2 * dst_stride, dst_stride); } void ff_tm_8x8_msa(uint8_t *dst, ptrdiff_t dst_stride, @@ -409,7 +410,7 @@ void ff_tm_8x8_msa(uint8_t *dst, ptrdiff_t dst_stride, IPRED_SUBS_UH2_UH(src_top_left, src_top_left, vec2, vec3); SAT_UH4_UH(vec0, vec1, vec2, vec3, 7); PCKEV_B2_SB(vec1, vec0, vec3, vec2, tmp0, tmp1); - ST8x4_UB(tmp0, tmp1, dst, dst_stride); + ST_D4(tmp0, tmp1, 0, 1, 0, 1, dst, dst_stride); dst += (4 * dst_stride); } } diff --git a/libavcodec/mips/vp9_lpf_msa.c b/libavcodec/mips/vp9_lpf_msa.c index c82a9e98b..2450c741d 100644 --- a/libavcodec/mips/vp9_lpf_msa.c +++ b/libavcodec/mips/vp9_lpf_msa.c @@ -1219,9 +1219,7 @@ void ff_loop_filter_h_4_8_msa(uint8_t *src, ptrdiff_t pitch, ILVRL_H2_SH(vec1, vec0, vec2, vec3); src -= 2; - ST4x4_UB(vec2, vec2, 0, 1, 2, 3, src, pitch); - src += 4 * pitch; - ST4x4_UB(vec3, vec3, 0, 1, 2, 3, src, pitch); + ST_W8(vec2, vec3, 0, 1, 2, 3, 0, 1, 2, 3, src, pitch); } void ff_loop_filter_h_44_16_msa(uint8_t *src, ptrdiff_t pitch, @@ -1266,9 +1264,8 @@ void ff_loop_filter_h_44_16_msa(uint8_t *src, ptrdiff_t pitch, src -= 2; - ST4x8_UB(tmp2, tmp3, src, pitch); - src += (8 * pitch); - ST4x8_UB(tmp4, tmp5, src, pitch); + ST_W8(tmp2, tmp3, 0, 1, 2, 3, 0, 1, 2, 3, src, pitch); + ST_W8(tmp4, tmp5, 0, 1, 2, 3, 0, 1, 2, 3, src + 8 * pitch, pitch); } void ff_loop_filter_h_8_8_msa(uint8_t *src, ptrdiff_t pitch, @@ -1313,9 +1310,7 @@ void ff_loop_filter_h_8_8_msa(uint8_t *src, ptrdiff_t pitch, ILVRL_H2_SH(vec1, vec0, vec2, vec3); src -= 2; - ST4x4_UB(vec2, vec2, 0, 1, 2, 3, src, pitch); - src += 4 * pitch; - ST4x4_UB(vec3, vec3, 0, 1, 2, 3, src, pitch); + ST_W8(vec2, vec3, 0, 1, 2, 3, 0, 1, 2, 3, src, pitch); } else { ILVR_B8_UH(zero, p3, zero, p2, zero, p1, zero, p0, zero, q0, zero, q1, zero, q2, zero, q3, p3_r, p2_r, p1_r, p0_r, q0_r, q1_r, q2_r, @@ -1343,11 +1338,11 @@ void ff_loop_filter_h_8_8_msa(uint8_t *src, ptrdiff_t pitch, vec4 = (v8i16) __msa_ilvr_b((v16i8) q2, (v16i8) q1); src -= 3; - ST4x4_UB(vec2, vec2, 0, 1, 2, 3, src, pitch); - ST2x4_UB(vec4, 0, src + 4, pitch); + ST_W4(vec2, 0, 1, 2, 3, src, pitch); + ST_H4(vec4, 0, 1, 2, 3, src + 4, pitch); src += (4 * pitch); - ST4x4_UB(vec3, vec3, 0, 1, 2, 3, src, pitch); - ST2x4_UB(vec4, 4, src + 4, pitch); + ST_W4(vec3, 0, 1, 2, 3, src, pitch); + ST_H4(vec4, 4, 5, 6, 7, src + 4, pitch); } } @@ -1410,9 +1405,8 @@ void ff_loop_filter_h_88_16_msa(uint8_t *src, ptrdiff_t pitch, ILVRL_H2_SH(vec1, vec0, vec4, vec5); src -= 2; - ST4x8_UB(vec2, vec3, src, pitch); - src += 8 * pitch; - ST4x8_UB(vec4, vec5, src, pitch); + ST_W8(vec2, vec3, 0, 1, 2, 3, 0, 1, 2, 3, src, pitch); + ST_W8(vec4, vec5, 0, 1, 2, 3, 0, 1, 2, 3, src + 8 * pitch, pitch); } else { ILVR_B8_UH(zero, p3, zero, p2, zero, p1, zero, p0, zero, q0, zero, q1, zero, q2, zero, q3, p3_r, p2_r, p1_r, p0_r, q0_r, q1_r, q2_r, @@ -1451,17 +1445,17 @@ void ff_loop_filter_h_88_16_msa(uint8_t *src, ptrdiff_t pitch, ILVRL_B2_SH(q2, q1, vec2, vec5); src -= 3; - ST4x4_UB(vec3, vec3, 0, 1, 2, 3, src, pitch); - ST2x4_UB(vec2, 0, src + 4, pitch); + ST_W4(vec3, 0, 1, 2, 3, src, pitch); + ST_H4(vec2, 0, 1, 2, 3, src + 4, pitch); src += (4 * pitch); - ST4x4_UB(vec4, vec4, 0, 1, 2, 3, src, pitch); - ST2x4_UB(vec2, 4, src + 4, pitch); + ST_W4(vec4, 0, 1, 2, 3, src, pitch); + ST_H4(vec2, 4, 5, 6, 7, src + 4, pitch); src += (4 * pitch); - ST4x4_UB(vec6, vec6, 0, 1, 2, 3, src, pitch); - ST2x4_UB(vec5, 0, src + 4, pitch); + ST_W4(vec6, 0, 1, 2, 3, src, pitch); + ST_H4(vec5, 0, 1, 2, 3, src + 4, pitch); src += (4 * pitch); - ST4x4_UB(vec7, vec7, 0, 1, 2, 3, src, pitch); - ST2x4_UB(vec5, 4, src + 4, pitch); + ST_W4(vec7, 0, 1, 2, 3, src, pitch); + ST_H4(vec5, 4, 5, 6, 7, src + 4, pitch); } } @@ -1523,9 +1517,8 @@ void ff_loop_filter_h_84_16_msa(uint8_t *src, ptrdiff_t pitch, ILVRL_H2_SH(vec1, vec0, vec4, vec5); src -= 2; - ST4x8_UB(vec2, vec3, src, pitch); - src += 8 * pitch; - ST4x8_UB(vec4, vec5, src, pitch); + ST_W8(vec2, vec3, 0, 1, 2, 3, 0, 1, 2, 3, src, pitch); + ST_W8(vec4, vec5, 0, 1, 2, 3, 0, 1, 2, 3, src + 8 * pitch, pitch); } else { ILVR_B8_UH(zero, p3, zero, p2, zero, p1, zero, p0, zero, q0, zero, q1, zero, q2, zero, q3, p3_r, p2_r, p1_r, p0_r, q0_r, q1_r, q2_r, @@ -1555,17 +1548,17 @@ void ff_loop_filter_h_84_16_msa(uint8_t *src, ptrdiff_t pitch, ILVRL_B2_SH(q2, q1, vec2, vec5); src -= 3; - ST4x4_UB(vec3, vec3, 0, 1, 2, 3, src, pitch); - ST2x4_UB(vec2, 0, src + 4, pitch); + ST_W4(vec3, 0, 1, 2, 3, src, pitch); + ST_H4(vec2, 0, 1, 2, 3, src + 4, pitch); src += (4 * pitch); - ST4x4_UB(vec4, vec4, 0, 1, 2, 3, src, pitch); - ST2x4_UB(vec2, 4, src + 4, pitch); + ST_W4(vec4, 0, 1, 2, 3, src, pitch); + ST_H4(vec2, 4, 5, 6, 7, src + 4, pitch); src += (4 * pitch); - ST4x4_UB(vec6, vec6, 0, 1, 2, 3, src, pitch); - ST2x4_UB(vec5, 0, src + 4, pitch); + ST_W4(vec6, 0, 1, 2, 3, src, pitch); + ST_H4(vec5, 0, 1, 2, 3, src + 4, pitch); src += (4 * pitch); - ST4x4_UB(vec7, vec7, 0, 1, 2, 3, src, pitch); - ST2x4_UB(vec5, 4, src + 4, pitch); + ST_W4(vec7, 0, 1, 2, 3, src, pitch); + ST_H4(vec5, 4, 5, 6, 7, src + 4, pitch); } } @@ -1627,9 +1620,8 @@ void ff_loop_filter_h_48_16_msa(uint8_t *src, ptrdiff_t pitch, ILVRL_H2_SH(vec1, vec0, vec4, vec5); src -= 2; - ST4x8_UB(vec2, vec3, src, pitch); - src += 8 * pitch; - ST4x8_UB(vec4, vec5, src, pitch); + ST_W8(vec2, vec3, 0, 1, 2, 3, 0, 1, 2, 3, src, pitch); + ST_W8(vec4, vec5, 0, 1, 2, 3, 0, 1, 2, 3, src + 8 * pitch, pitch); } else { ILVL_B4_UH(zero, p3, zero, p2, zero, p1, zero, p0, p3_l, p2_l, p1_l, p0_l); @@ -1661,17 +1653,17 @@ void ff_loop_filter_h_48_16_msa(uint8_t *src, ptrdiff_t pitch, ILVRL_B2_SH(q2, q1, vec2, vec5); src -= 3; - ST4x4_UB(vec3, vec3, 0, 1, 2, 3, src, pitch); - ST2x4_UB(vec2, 0, src + 4, pitch); + ST_W4(vec3, 0, 1, 2, 3, src, pitch); + ST_H4(vec2, 0, 1, 2, 3, src + 4, pitch); src += (4 * pitch); - ST4x4_UB(vec4, vec4, 0, 1, 2, 3, src, pitch); - ST2x4_UB(vec2, 4, src + 4, pitch); + ST_W4(vec4, 0, 1, 2, 3, src, pitch); + ST_H4(vec2, 4, 5, 6, 7, src + 4, pitch); src += (4 * pitch); - ST4x4_UB(vec6, vec6, 0, 1, 2, 3, src, pitch); - ST2x4_UB(vec5, 0, src + 4, pitch); + ST_W4(vec6, 0, 1, 2, 3, src, pitch); + ST_H4(vec5, 0, 1, 2, 3, src + 4, pitch); src += (4 * pitch); - ST4x4_UB(vec7, vec7, 0, 1, 2, 3, src, pitch); - ST2x4_UB(vec5, 4, src + 4, pitch); + ST_W4(vec7, 0, 1, 2, 3, src, pitch); + ST_H4(vec5, 4, 5, 6, 7, src + 4, pitch); } } @@ -1811,7 +1803,7 @@ static int32_t vp9_vt_lpf_t4_and_t8_8w(uint8_t *src, uint8_t *filter48, if (__msa_test_bz_v(flat)) { ILVR_B2_SH(p0_out, p1_out, q1_out, q0_out, vec0, vec1); ILVRL_H2_SH(vec1, vec0, vec2, vec3); - ST4x8_UB(vec2, vec3, (src_org - 2), pitch_org); + ST_W8(vec2, vec3, 0, 1, 2, 3, 0, 1, 2, 3, (src_org - 2), pitch_org); return 1; } else { ILVR_B8_UH(zero, p3, zero, p2, zero, p1, zero, p0, zero, q0, zero, q1, @@ -1878,11 +1870,11 @@ static int32_t vp9_vt_lpf_t16_8w(uint8_t *src, uint8_t *src_org, ptrdiff_t pitch vec2 = (v8i16) __msa_ilvr_b((v16i8) q2, (v16i8) q1); src_org -= 3; - ST4x4_UB(vec3, vec3, 0, 1, 2, 3, src_org, pitch); - ST2x4_UB(vec2, 0, (src_org + 4), pitch); + ST_W4(vec3, 0, 1, 2, 3, src_org, pitch); + ST_H4(vec2, 0, 1, 2, 3, (src_org + 4), pitch); src_org += (4 * pitch); - ST4x4_UB(vec4, vec4, 0, 1, 2, 3, src_org, pitch); - ST2x4_UB(vec2, 4, (src_org + 4), pitch); + ST_W4(vec4, 0, 1, 2, 3, src_org, pitch); + ST_H4(vec2, 4, 5, 6, 7, (src_org + 4), pitch); return 1; } else { @@ -1908,7 +1900,7 @@ static int32_t vp9_vt_lpf_t16_8w(uint8_t *src, uint8_t *src_org, ptrdiff_t pitch r_out = __msa_srari_h((v8i16) tmp1_r, 4); r_out = (v8i16) __msa_pckev_b((v16i8) r_out, (v16i8) r_out); p6 = __msa_bmnz_v(p6, (v16u8) r_out, flat2); - ST8x1_UB(p6, src); + ST_D1(p6, 0, src); src += 16; /* p5 */ @@ -1920,7 +1912,7 @@ static int32_t vp9_vt_lpf_t16_8w(uint8_t *src, uint8_t *src_org, ptrdiff_t pitch r_out = __msa_srari_h((v8i16) tmp1_r, 4); r_out = (v8i16) __msa_pckev_b((v16i8) r_out, (v16i8) r_out); p5 = __msa_bmnz_v(p5, (v16u8) r_out, flat2); - ST8x1_UB(p5, src); + ST_D1(p5, 0, src); src += 16; /* p4 */ @@ -1932,7 +1924,7 @@ static int32_t vp9_vt_lpf_t16_8w(uint8_t *src, uint8_t *src_org, ptrdiff_t pitch r_out = __msa_srari_h((v8i16) tmp1_r, 4); r_out = (v8i16) __msa_pckev_b((v16i8) r_out, (v16i8) r_out); p4 = __msa_bmnz_v(p4, (v16u8) r_out, flat2); - ST8x1_UB(p4, src); + ST_D1(p4, 0, src); src += 16; /* p3 */ @@ -1944,7 +1936,7 @@ static int32_t vp9_vt_lpf_t16_8w(uint8_t *src, uint8_t *src_org, ptrdiff_t pitch r_out = __msa_srari_h((v8i16) tmp1_r, 4); r_out = (v8i16) __msa_pckev_b((v16i8) r_out, (v16i8) r_out); p3 = __msa_bmnz_v(p3, (v16u8) r_out, flat2); - ST8x1_UB(p3, src); + ST_D1(p3, 0, src); src += 16; /* p2 */ @@ -1957,7 +1949,7 @@ static int32_t vp9_vt_lpf_t16_8w(uint8_t *src, uint8_t *src_org, ptrdiff_t pitch r_out = __msa_srari_h((v8i16) tmp1_r, 4); r_out = (v8i16) __msa_pckev_b((v16i8) r_out, (v16i8) r_out); filter8 = __msa_bmnz_v(filter8, (v16u8) r_out, flat2); - ST8x1_UB(filter8, src); + ST_D1(filter8, 0, src); src += 16; /* p1 */ @@ -1970,7 +1962,7 @@ static int32_t vp9_vt_lpf_t16_8w(uint8_t *src, uint8_t *src_org, ptrdiff_t pitch r_out = __msa_srari_h((v8i16) tmp1_r, 4); r_out = (v8i16) __msa_pckev_b((v16i8) r_out, (v16i8) r_out); filter8 = __msa_bmnz_v(filter8, (v16u8) r_out, flat2); - ST8x1_UB(filter8, src); + ST_D1(filter8, 0, src); src += 16; /* p0 */ @@ -1983,7 +1975,7 @@ static int32_t vp9_vt_lpf_t16_8w(uint8_t *src, uint8_t *src_org, ptrdiff_t pitch r_out = __msa_srari_h((v8i16) tmp1_r, 4); r_out = (v8i16) __msa_pckev_b((v16i8) r_out, (v16i8) r_out); filter8 = __msa_bmnz_v(filter8, (v16u8) r_out, flat2); - ST8x1_UB(filter8, src); + ST_D1(filter8, 0, src); src += 16; /* q0 */ @@ -1996,7 +1988,7 @@ static int32_t vp9_vt_lpf_t16_8w(uint8_t *src, uint8_t *src_org, ptrdiff_t pitch r_out = __msa_srari_h((v8i16) tmp1_r, 4); r_out = (v8i16) __msa_pckev_b((v16i8) r_out, (v16i8) r_out); filter8 = __msa_bmnz_v(filter8, (v16u8) r_out, flat2); - ST8x1_UB(filter8, src); + ST_D1(filter8, 0, src); src += 16; /* q1 */ @@ -2008,7 +2000,7 @@ static int32_t vp9_vt_lpf_t16_8w(uint8_t *src, uint8_t *src_org, ptrdiff_t pitch r_out = __msa_srari_h((v8i16) tmp1_r, 4); r_out = (v8i16) __msa_pckev_b((v16i8) r_out, (v16i8) r_out); filter8 = __msa_bmnz_v(filter8, (v16u8) r_out, flat2); - ST8x1_UB(filter8, src); + ST_D1(filter8, 0, src); src += 16; /* q2 */ @@ -2020,7 +2012,7 @@ static int32_t vp9_vt_lpf_t16_8w(uint8_t *src, uint8_t *src_org, ptrdiff_t pitch r_out = __msa_srari_h((v8i16) tmp1_r, 4); r_out = (v8i16) __msa_pckev_b((v16i8) r_out, (v16i8) r_out); filter8 = __msa_bmnz_v(filter8, (v16u8) r_out, flat2); - ST8x1_UB(filter8, src); + ST_D1(filter8, 0, src); src += 16; /* q3 */ @@ -2031,7 +2023,7 @@ static int32_t vp9_vt_lpf_t16_8w(uint8_t *src, uint8_t *src_org, ptrdiff_t pitch r_out = __msa_srari_h((v8i16) tmp1_r, 4); r_out = (v8i16) __msa_pckev_b((v16i8) r_out, (v16i8) r_out); q3 = __msa_bmnz_v(q3, (v16u8) r_out, flat2); - ST8x1_UB(q3, src); + ST_D1(q3, 0, src); src += 16; /* q4 */ @@ -2042,7 +2034,7 @@ static int32_t vp9_vt_lpf_t16_8w(uint8_t *src, uint8_t *src_org, ptrdiff_t pitch r_out = __msa_srari_h((v8i16) tmp1_r, 4); r_out = (v8i16) __msa_pckev_b((v16i8) r_out, (v16i8) r_out); q4 = __msa_bmnz_v(q4, (v16u8) r_out, flat2); - ST8x1_UB(q4, src); + ST_D1(q4, 0, src); src += 16; /* q5 */ @@ -2053,7 +2045,7 @@ static int32_t vp9_vt_lpf_t16_8w(uint8_t *src, uint8_t *src_org, ptrdiff_t pitch r_out = __msa_srari_h((v8i16) tmp1_r, 4); r_out = (v8i16) __msa_pckev_b((v16i8) r_out, (v16i8) r_out); q5 = __msa_bmnz_v(q5, (v16u8) r_out, flat2); - ST8x1_UB(q5, src); + ST_D1(q5, 0, src); src += 16; /* q6 */ @@ -2064,7 +2056,7 @@ static int32_t vp9_vt_lpf_t16_8w(uint8_t *src, uint8_t *src_org, ptrdiff_t pitch r_out = __msa_srari_h((v8i16) tmp1_r, 4); r_out = (v8i16) __msa_pckev_b((v16i8) r_out, (v16i8) r_out); q6 = __msa_bmnz_v(q6, (v16u8) r_out, flat2); - ST8x1_UB(q6, src); + ST_D1(q6, 0, src); return 0; } @@ -2137,9 +2129,8 @@ static int32_t vp9_vt_lpf_t4_and_t8_16w(uint8_t *src, uint8_t *filter48, ILVRL_H2_SH(vec1, vec0, vec4, vec5); src_org -= 2; - ST4x8_UB(vec2, vec3, src_org, pitch); - src_org += 8 * pitch; - ST4x8_UB(vec4, vec5, src_org, pitch); + ST_W8(vec2, vec3, 0, 1, 2, 3, 0, 1, 2, 3, src_org, pitch); + ST_W8(vec4, vec5, 0, 1, 2, 3, 0, 1, 2, 3, src_org + 8 * pitch, pitch); return 1; } else { @@ -2218,17 +2209,17 @@ static int32_t vp9_vt_lpf_t16_16w(uint8_t *src, uint8_t *src_org, ptrdiff_t pitc ILVRL_B2_SH(q2, q1, vec2, vec5); src_org -= 3; - ST4x4_UB(vec3, vec3, 0, 1, 2, 3, src_org, pitch); - ST2x4_UB(vec2, 0, (src_org + 4), pitch); + ST_W4(vec3, 0, 1, 2, 3, src_org, pitch); + ST_H4(vec2, 0, 1, 2, 3, (src_org + 4), pitch); src_org += (4 * pitch); - ST4x4_UB(vec4, vec4, 0, 1, 2, 3, src_org, pitch); - ST2x4_UB(vec2, 4, (src_org + 4), pitch); + ST_W4(vec4, 0, 1, 2, 3, src_org, pitch); + ST_H4(vec2, 4, 5, 6, 7, (src_org + 4), pitch); src_org += (4 * pitch); - ST4x4_UB(vec6, vec6, 0, 1, 2, 3, src_org, pitch); - ST2x4_UB(vec5, 0, (src_org + 4), pitch); + ST_W4(vec6, 0, 1, 2, 3, src_org, pitch); + ST_H4(vec5, 0, 1, 2, 3, (src_org + 4), pitch); src_org += (4 * pitch); - ST4x4_UB(vec7, vec7, 0, 1, 2, 3, src_org, pitch); - ST2x4_UB(vec5, 4, (src_org + 4), pitch); + ST_W4(vec7, 0, 1, 2, 3, src_org, pitch); + ST_H4(vec5, 4, 5, 6, 7, (src_org + 4), pitch); return 1; } else { diff --git a/libavcodec/mips/vp9_mc_mmi.c b/libavcodec/mips/vp9_mc_mmi.c new file mode 100644 index 000000000..e7a83875b --- /dev/null +++ b/libavcodec/mips/vp9_mc_mmi.c @@ -0,0 +1,628 @@ +/* + * Copyright (c) 2019 gxw + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavcodec/vp9dsp.h" +#include "libavutil/mips/mmiutils.h" +#include "vp9dsp_mips.h" + +#define GET_DATA_H_MMI \ + "pmaddhw %[ftmp4], %[ftmp4], %[filter1] \n\t" \ + "pmaddhw %[ftmp5], %[ftmp5], %[filter2] \n\t" \ + "paddw %[ftmp4], %[ftmp4], %[ftmp5] \n\t" \ + "punpckhwd %[ftmp5], %[ftmp4], %[ftmp0] \n\t" \ + "paddw %[ftmp4], %[ftmp4], %[ftmp5] \n\t" \ + "pmaddhw %[ftmp6], %[ftmp6], %[filter1] \n\t" \ + "pmaddhw %[ftmp7], %[ftmp7], %[filter2] \n\t" \ + "paddw %[ftmp6], %[ftmp6], %[ftmp7] \n\t" \ + "punpckhwd %[ftmp7], %[ftmp6], %[ftmp0] \n\t" \ + "paddw %[ftmp6], %[ftmp6], %[ftmp7] \n\t" \ + "punpcklwd %[srcl], %[ftmp4], %[ftmp6] \n\t" \ + "pmaddhw %[ftmp8], %[ftmp8], %[filter1] \n\t" \ + "pmaddhw %[ftmp9], %[ftmp9], %[filter2] \n\t" \ + "paddw %[ftmp8], %[ftmp8], %[ftmp9] \n\t" \ + "punpckhwd %[ftmp9], %[ftmp8], %[ftmp0] \n\t" \ + "paddw %[ftmp8], %[ftmp8], %[ftmp9] \n\t" \ + "pmaddhw %[ftmp10], %[ftmp10], %[filter1] \n\t" \ + "pmaddhw %[ftmp11], %[ftmp11], %[filter2] \n\t" \ + "paddw %[ftmp10], %[ftmp10], %[ftmp11] \n\t" \ + "punpckhwd %[ftmp11], %[ftmp10], %[ftmp0] \n\t" \ + "paddw %[ftmp10], %[ftmp10], %[ftmp11] \n\t" \ + "punpcklwd %[srch], %[ftmp8], %[ftmp10] \n\t" + +#define GET_DATA_V_MMI \ + "punpcklhw %[srcl], %[ftmp4], %[ftmp5] \n\t" \ + "pmaddhw %[srcl], %[srcl], %[filter10] \n\t" \ + "punpcklhw %[ftmp12], %[ftmp6], %[ftmp7] \n\t" \ + "pmaddhw %[ftmp12], %[ftmp12], %[filter32] \n\t" \ + "paddw %[srcl], %[srcl], %[ftmp12] \n\t" \ + "punpcklhw %[ftmp12], %[ftmp8], %[ftmp9] \n\t" \ + "pmaddhw %[ftmp12], %[ftmp12], %[filter54] \n\t" \ + "paddw %[srcl], %[srcl], %[ftmp12] \n\t" \ + "punpcklhw %[ftmp12], %[ftmp10], %[ftmp11] \n\t" \ + "pmaddhw %[ftmp12], %[ftmp12], %[filter76] \n\t" \ + "paddw %[srcl], %[srcl], %[ftmp12] \n\t" \ + "punpckhhw %[srch], %[ftmp4], %[ftmp5] \n\t" \ + "pmaddhw %[srch], %[srch], %[filter10] \n\t" \ + "punpckhhw %[ftmp12], %[ftmp6], %[ftmp7] \n\t" \ + "pmaddhw %[ftmp12], %[ftmp12], %[filter32] \n\t" \ + "paddw %[srch], %[srch], %[ftmp12] \n\t" \ + "punpckhhw %[ftmp12], %[ftmp8], %[ftmp9] \n\t" \ + "pmaddhw %[ftmp12], %[ftmp12], %[filter54] \n\t" \ + "paddw %[srch], %[srch], %[ftmp12] \n\t" \ + "punpckhhw %[ftmp12], %[ftmp10], %[ftmp11] \n\t" \ + "pmaddhw %[ftmp12], %[ftmp12], %[filter76] \n\t" \ + "paddw %[srch], %[srch], %[ftmp12] \n\t" + +static void convolve_horiz_mmi(const uint8_t *src, int32_t src_stride, + uint8_t *dst, int32_t dst_stride, + const uint16_t *filter_x, int32_t w, + int32_t h) +{ + double ftmp[15]; + uint32_t tmp[2]; + src -= 3; + src_stride -= w; + dst_stride -= w; + __asm__ volatile ( + "move %[tmp1], %[width] \n\t" + "xor %[ftmp0], %[ftmp0], %[ftmp0] \n\t" + "gsldlc1 %[filter1], 0x03(%[filter]) \n\t" + "gsldrc1 %[filter1], 0x00(%[filter]) \n\t" + "gsldlc1 %[filter2], 0x0b(%[filter]) \n\t" + "gsldrc1 %[filter2], 0x08(%[filter]) \n\t" + "li %[tmp0], 0x07 \n\t" + "dmtc1 %[tmp0], %[ftmp13] \n\t" + "punpcklwd %[ftmp13], %[ftmp13], %[ftmp13] \n\t" + "1: \n\t" + /* Get 8 data per row */ + "gsldlc1 %[ftmp5], 0x07(%[src]) \n\t" + "gsldrc1 %[ftmp5], 0x00(%[src]) \n\t" + "gsldlc1 %[ftmp7], 0x08(%[src]) \n\t" + "gsldrc1 %[ftmp7], 0x01(%[src]) \n\t" + "gsldlc1 %[ftmp9], 0x09(%[src]) \n\t" + "gsldrc1 %[ftmp9], 0x02(%[src]) \n\t" + "gsldlc1 %[ftmp11], 0x0A(%[src]) \n\t" + "gsldrc1 %[ftmp11], 0x03(%[src]) \n\t" + "punpcklbh %[ftmp4], %[ftmp5], %[ftmp0] \n\t" + "punpckhbh %[ftmp5], %[ftmp5], %[ftmp0] \n\t" + "punpcklbh %[ftmp6], %[ftmp7], %[ftmp0] \n\t" + "punpckhbh %[ftmp7], %[ftmp7], %[ftmp0] \n\t" + "punpcklbh %[ftmp8], %[ftmp9], %[ftmp0] \n\t" + "punpckhbh %[ftmp9], %[ftmp9], %[ftmp0] \n\t" + "punpcklbh %[ftmp10], %[ftmp11], %[ftmp0] \n\t" + "punpckhbh %[ftmp11], %[ftmp11], %[ftmp0] \n\t" + PTR_ADDIU "%[width], %[width], -0x04 \n\t" + /* Get raw data */ + GET_DATA_H_MMI + ROUND_POWER_OF_TWO_MMI(%[srcl], %[ftmp13], %[ftmp5], + %[ftmp6], %[tmp0]) + ROUND_POWER_OF_TWO_MMI(%[srch], %[ftmp13], %[ftmp5], + %[ftmp6], %[tmp0]) + "packsswh %[srcl], %[srcl], %[srch] \n\t" + "packushb %[ftmp12], %[srcl], %[ftmp0] \n\t" + "swc1 %[ftmp12], 0x00(%[dst]) \n\t" + PTR_ADDIU "%[dst], %[dst], 0x04 \n\t" + PTR_ADDIU "%[src], %[src], 0x04 \n\t" + /* Loop count */ + "bnez %[width], 1b \n\t" + "move %[width], %[tmp1] \n\t" + PTR_ADDU "%[src], %[src], %[src_stride] \n\t" + PTR_ADDU "%[dst], %[dst], %[dst_stride] \n\t" + PTR_ADDIU "%[height], %[height], -0x01 \n\t" + "bnez %[height], 1b \n\t" + : [srcl]"=&f"(ftmp[0]), [srch]"=&f"(ftmp[1]), + [filter1]"=&f"(ftmp[2]), [filter2]"=&f"(ftmp[3]), + [ftmp0]"=&f"(ftmp[4]), [ftmp4]"=&f"(ftmp[5]), + [ftmp5]"=&f"(ftmp[6]), [ftmp6]"=&f"(ftmp[7]), + [ftmp7]"=&f"(ftmp[8]), [ftmp8]"=&f"(ftmp[9]), + [ftmp9]"=&f"(ftmp[10]), [ftmp10]"=&f"(ftmp[11]), + [ftmp11]"=&f"(ftmp[12]), [ftmp12]"=&f"(ftmp[13]), + [tmp0]"=&r"(tmp[0]), [tmp1]"=&r"(tmp[1]), + [src]"+&r"(src), [width]"+&r"(w), + [dst]"+&r"(dst), [height]"+&r"(h), + [ftmp13]"=&f"(ftmp[14]) + : [filter]"r"(filter_x), + [src_stride]"r"((mips_reg)src_stride), + [dst_stride]"r"((mips_reg)dst_stride) + : "memory" + ); +} + +static void convolve_vert_mmi(const uint8_t *src, int32_t src_stride, + uint8_t *dst, int32_t dst_stride, + const int16_t *filter_y, int32_t w, + int32_t h) +{ + double ftmp[17]; + uint32_t tmp[1]; + ptrdiff_t addr = src_stride; + src_stride -= w; + dst_stride -= w; + + __asm__ volatile ( + "xor %[ftmp0], %[ftmp0], %[ftmp0] \n\t" + "gsldlc1 %[ftmp4], 0x03(%[filter]) \n\t" + "gsldrc1 %[ftmp4], 0x00(%[filter]) \n\t" + "gsldlc1 %[ftmp5], 0x0b(%[filter]) \n\t" + "gsldrc1 %[ftmp5], 0x08(%[filter]) \n\t" + "punpcklwd %[filter10], %[ftmp4], %[ftmp4] \n\t" + "punpckhwd %[filter32], %[ftmp4], %[ftmp4] \n\t" + "punpcklwd %[filter54], %[ftmp5], %[ftmp5] \n\t" + "punpckhwd %[filter76], %[ftmp5], %[ftmp5] \n\t" + "li %[tmp0], 0x07 \n\t" + "dmtc1 %[tmp0], %[ftmp13] \n\t" + "punpcklwd %[ftmp13], %[ftmp13], %[ftmp13] \n\t" + "1: \n\t" + /* Get 8 data per column */ + "gsldlc1 %[ftmp4], 0x07(%[src]) \n\t" + "gsldrc1 %[ftmp4], 0x00(%[src]) \n\t" + PTR_ADDU "%[tmp0], %[src], %[addr] \n\t" + "gsldlc1 %[ftmp5], 0x07(%[tmp0]) \n\t" + "gsldrc1 %[ftmp5], 0x00(%[tmp0]) \n\t" + PTR_ADDU "%[tmp0], %[tmp0], %[addr] \n\t" + "gsldlc1 %[ftmp6], 0x07(%[tmp0]) \n\t" + "gsldrc1 %[ftmp6], 0x00(%[tmp0]) \n\t" + PTR_ADDU "%[tmp0], %[tmp0], %[addr] \n\t" + "gsldlc1 %[ftmp7], 0x07(%[tmp0]) \n\t" + "gsldrc1 %[ftmp7], 0x00(%[tmp0]) \n\t" + PTR_ADDU "%[tmp0], %[tmp0], %[addr] \n\t" + "gsldlc1 %[ftmp8], 0x07(%[tmp0]) \n\t" + "gsldrc1 %[ftmp8], 0x00(%[tmp0]) \n\t" + PTR_ADDU "%[tmp0], %[tmp0], %[addr] \n\t" + "gsldlc1 %[ftmp9], 0x07(%[tmp0]) \n\t" + "gsldrc1 %[ftmp9], 0x00(%[tmp0]) \n\t" + PTR_ADDU "%[tmp0], %[tmp0], %[addr] \n\t" + "gsldlc1 %[ftmp10], 0x07(%[tmp0]) \n\t" + "gsldrc1 %[ftmp10], 0x00(%[tmp0]) \n\t" + PTR_ADDU "%[tmp0], %[tmp0], %[addr] \n\t" + "gsldlc1 %[ftmp11], 0x07(%[tmp0]) \n\t" + "gsldrc1 %[ftmp11], 0x00(%[tmp0]) \n\t" + "punpcklbh %[ftmp4], %[ftmp4], %[ftmp0] \n\t" + "punpcklbh %[ftmp5], %[ftmp5], %[ftmp0] \n\t" + "punpcklbh %[ftmp6], %[ftmp6], %[ftmp0] \n\t" + "punpcklbh %[ftmp7], %[ftmp7], %[ftmp0] \n\t" + "punpcklbh %[ftmp8], %[ftmp8], %[ftmp0] \n\t" + "punpcklbh %[ftmp9], %[ftmp9], %[ftmp0] \n\t" + "punpcklbh %[ftmp10], %[ftmp10], %[ftmp0] \n\t" + "punpcklbh %[ftmp11], %[ftmp11], %[ftmp0] \n\t" + PTR_ADDIU "%[width], %[width], -0x04 \n\t" + /* Get raw data */ + GET_DATA_V_MMI + ROUND_POWER_OF_TWO_MMI(%[srcl], %[ftmp13], %[ftmp5], + %[ftmp6], %[tmp0]) + ROUND_POWER_OF_TWO_MMI(%[srch], %[ftmp13], %[ftmp5], + %[ftmp6], %[tmp0]) + "packsswh %[srcl], %[srcl], %[srch] \n\t" + "packushb %[ftmp12], %[srcl], %[ftmp0] \n\t" + "swc1 %[ftmp12], 0x00(%[dst]) \n\t" + PTR_ADDIU "%[dst], %[dst], 0x04 \n\t" + PTR_ADDIU "%[src], %[src], 0x04 \n\t" + /* Loop count */ + "bnez %[width], 1b \n\t" + PTR_SUBU "%[width], %[addr], %[src_stride] \n\t" + PTR_ADDU "%[src], %[src], %[src_stride] \n\t" + PTR_ADDU "%[dst], %[dst], %[dst_stride] \n\t" + PTR_ADDIU "%[height], %[height], -0x01 \n\t" + "bnez %[height], 1b \n\t" + : [srcl]"=&f"(ftmp[0]), [srch]"=&f"(ftmp[1]), + [filter10]"=&f"(ftmp[2]), [filter32]"=&f"(ftmp[3]), + [filter54]"=&f"(ftmp[4]), [filter76]"=&f"(ftmp[5]), + [ftmp0]"=&f"(ftmp[6]), [ftmp4]"=&f"(ftmp[7]), + [ftmp5]"=&f"(ftmp[8]), [ftmp6]"=&f"(ftmp[9]), + [ftmp7]"=&f"(ftmp[10]), [ftmp8]"=&f"(ftmp[11]), + [ftmp9]"=&f"(ftmp[12]), [ftmp10]"=&f"(ftmp[13]), + [ftmp11]"=&f"(ftmp[14]), [ftmp12]"=&f"(ftmp[15]), + [src]"+&r"(src), [dst]"+&r"(dst), + [width]"+&r"(w), [height]"+&r"(h), + [tmp0]"=&r"(tmp[0]), [ftmp13]"=&f"(ftmp[16]) + : [filter]"r"(filter_y), + [src_stride]"r"((mips_reg)src_stride), + [dst_stride]"r"((mips_reg)dst_stride), + [addr]"r"((mips_reg)addr) + : "memory" + ); +} + +static void convolve_avg_horiz_mmi(const uint8_t *src, int32_t src_stride, + uint8_t *dst, int32_t dst_stride, + const uint16_t *filter_x, int32_t w, + int32_t h) +{ + double ftmp[15]; + uint32_t tmp[2]; + src -= 3; + src_stride -= w; + dst_stride -= w; + + __asm__ volatile ( + "move %[tmp1], %[width] \n\t" + "xor %[ftmp0], %[ftmp0], %[ftmp0] \n\t" + "gsldlc1 %[filter1], 0x03(%[filter]) \n\t" + "gsldrc1 %[filter1], 0x00(%[filter]) \n\t" + "gsldlc1 %[filter2], 0x0b(%[filter]) \n\t" + "gsldrc1 %[filter2], 0x08(%[filter]) \n\t" + "li %[tmp0], 0x07 \n\t" + "dmtc1 %[tmp0], %[ftmp13] \n\t" + "punpcklwd %[ftmp13], %[ftmp13], %[ftmp13] \n\t" + "1: \n\t" + /* Get 8 data per row */ + "gsldlc1 %[ftmp5], 0x07(%[src]) \n\t" + "gsldrc1 %[ftmp5], 0x00(%[src]) \n\t" + "gsldlc1 %[ftmp7], 0x08(%[src]) \n\t" + "gsldrc1 %[ftmp7], 0x01(%[src]) \n\t" + "gsldlc1 %[ftmp9], 0x09(%[src]) \n\t" + "gsldrc1 %[ftmp9], 0x02(%[src]) \n\t" + "gsldlc1 %[ftmp11], 0x0A(%[src]) \n\t" + "gsldrc1 %[ftmp11], 0x03(%[src]) \n\t" + "punpcklbh %[ftmp4], %[ftmp5], %[ftmp0] \n\t" + "punpckhbh %[ftmp5], %[ftmp5], %[ftmp0] \n\t" + "punpcklbh %[ftmp6], %[ftmp7], %[ftmp0] \n\t" + "punpckhbh %[ftmp7], %[ftmp7], %[ftmp0] \n\t" + "punpcklbh %[ftmp8], %[ftmp9], %[ftmp0] \n\t" + "punpckhbh %[ftmp9], %[ftmp9], %[ftmp0] \n\t" + "punpcklbh %[ftmp10], %[ftmp11], %[ftmp0] \n\t" + "punpckhbh %[ftmp11], %[ftmp11], %[ftmp0] \n\t" + PTR_ADDIU "%[width], %[width], -0x04 \n\t" + /* Get raw data */ + GET_DATA_H_MMI + ROUND_POWER_OF_TWO_MMI(%[srcl], %[ftmp13], %[ftmp5], + %[ftmp6], %[tmp0]) + ROUND_POWER_OF_TWO_MMI(%[srch], %[ftmp13], %[ftmp5], + %[ftmp6], %[tmp0]) + "packsswh %[srcl], %[srcl], %[srch] \n\t" + "packushb %[ftmp12], %[srcl], %[ftmp0] \n\t" + "punpcklbh %[ftmp12], %[ftmp12], %[ftmp0] \n\t" + "gsldlc1 %[ftmp4], 0x07(%[dst]) \n\t" + "gsldrc1 %[ftmp4], 0x00(%[dst]) \n\t" + "punpcklbh %[ftmp4], %[ftmp4], %[ftmp0] \n\t" + "paddh %[ftmp12], %[ftmp12], %[ftmp4] \n\t" + "li %[tmp0], 0x10001 \n\t" + "dmtc1 %[tmp0], %[ftmp5] \n\t" + "punpcklhw %[ftmp5], %[ftmp5], %[ftmp5] \n\t" + "paddh %[ftmp12], %[ftmp12], %[ftmp5] \n\t" + "psrah %[ftmp12], %[ftmp12], %[ftmp5] \n\t" + "packushb %[ftmp12], %[ftmp12], %[ftmp0] \n\t" + "swc1 %[ftmp12], 0x00(%[dst]) \n\t" + PTR_ADDIU "%[dst], %[dst], 0x04 \n\t" + PTR_ADDIU "%[src], %[src], 0x04 \n\t" + /* Loop count */ + "bnez %[width], 1b \n\t" + "move %[width], %[tmp1] \n\t" + PTR_ADDU "%[src], %[src], %[src_stride] \n\t" + PTR_ADDU "%[dst], %[dst], %[dst_stride] \n\t" + PTR_ADDIU "%[height], %[height], -0x01 \n\t" + "bnez %[height], 1b \n\t" + : [srcl]"=&f"(ftmp[0]), [srch]"=&f"(ftmp[1]), + [filter1]"=&f"(ftmp[2]), [filter2]"=&f"(ftmp[3]), + [ftmp0]"=&f"(ftmp[4]), [ftmp4]"=&f"(ftmp[5]), + [ftmp5]"=&f"(ftmp[6]), [ftmp6]"=&f"(ftmp[7]), + [ftmp7]"=&f"(ftmp[8]), [ftmp8]"=&f"(ftmp[9]), + [ftmp9]"=&f"(ftmp[10]), [ftmp10]"=&f"(ftmp[11]), + [ftmp11]"=&f"(ftmp[12]), [ftmp12]"=&f"(ftmp[13]), + [tmp0]"=&r"(tmp[0]), [tmp1]"=&r"(tmp[1]), + [src]"+&r"(src), [width]"+&r"(w), + [dst]"+&r"(dst), [height]"+&r"(h), + [ftmp13]"=&f"(ftmp[14]) + : [filter]"r"(filter_x), + [src_stride]"r"((mips_reg)src_stride), + [dst_stride]"r"((mips_reg)dst_stride) + : "memory" + ); +} + +static void convolve_avg_vert_mmi(const uint8_t *src, int32_t src_stride, + uint8_t *dst, int32_t dst_stride, + const int16_t *filter_y, int32_t w, + int32_t h) +{ + double ftmp[17]; + uint32_t tmp[1]; + ptrdiff_t addr = src_stride; + src_stride -= w; + dst_stride -= w; + + __asm__ volatile ( + "xor %[ftmp0], %[ftmp0], %[ftmp0] \n\t" + "gsldlc1 %[ftmp4], 0x03(%[filter]) \n\t" + "gsldrc1 %[ftmp4], 0x00(%[filter]) \n\t" + "gsldlc1 %[ftmp5], 0x0b(%[filter]) \n\t" + "gsldrc1 %[ftmp5], 0x08(%[filter]) \n\t" + "punpcklwd %[filter10], %[ftmp4], %[ftmp4] \n\t" + "punpckhwd %[filter32], %[ftmp4], %[ftmp4] \n\t" + "punpcklwd %[filter54], %[ftmp5], %[ftmp5] \n\t" + "punpckhwd %[filter76], %[ftmp5], %[ftmp5] \n\t" + "li %[tmp0], 0x07 \n\t" + "dmtc1 %[tmp0], %[ftmp13] \n\t" + "punpcklwd %[ftmp13], %[ftmp13], %[ftmp13] \n\t" + "1: \n\t" + /* Get 8 data per column */ + "gsldlc1 %[ftmp4], 0x07(%[src]) \n\t" + "gsldrc1 %[ftmp4], 0x00(%[src]) \n\t" + PTR_ADDU "%[tmp0], %[src], %[addr] \n\t" + "gsldlc1 %[ftmp5], 0x07(%[tmp0]) \n\t" + "gsldrc1 %[ftmp5], 0x00(%[tmp0]) \n\t" + PTR_ADDU "%[tmp0], %[tmp0], %[addr] \n\t" + "gsldlc1 %[ftmp6], 0x07(%[tmp0]) \n\t" + "gsldrc1 %[ftmp6], 0x00(%[tmp0]) \n\t" + PTR_ADDU "%[tmp0], %[tmp0], %[addr] \n\t" + "gsldlc1 %[ftmp7], 0x07(%[tmp0]) \n\t" + "gsldrc1 %[ftmp7], 0x00(%[tmp0]) \n\t" + PTR_ADDU "%[tmp0], %[tmp0], %[addr] \n\t" + "gsldlc1 %[ftmp8], 0x07(%[tmp0]) \n\t" + "gsldrc1 %[ftmp8], 0x00(%[tmp0]) \n\t" + PTR_ADDU "%[tmp0], %[tmp0], %[addr] \n\t" + "gsldlc1 %[ftmp9], 0x07(%[tmp0]) \n\t" + "gsldrc1 %[ftmp9], 0x00(%[tmp0]) \n\t" + PTR_ADDU "%[tmp0], %[tmp0], %[addr] \n\t" + "gsldlc1 %[ftmp10], 0x07(%[tmp0]) \n\t" + "gsldrc1 %[ftmp10], 0x00(%[tmp0]) \n\t" + PTR_ADDU "%[tmp0], %[tmp0], %[addr] \n\t" + "gsldlc1 %[ftmp11], 0x07(%[tmp0]) \n\t" + "gsldrc1 %[ftmp11], 0x00(%[tmp0]) \n\t" + "punpcklbh %[ftmp4], %[ftmp4], %[ftmp0] \n\t" + "punpcklbh %[ftmp5], %[ftmp5], %[ftmp0] \n\t" + "punpcklbh %[ftmp6], %[ftmp6], %[ftmp0] \n\t" + "punpcklbh %[ftmp7], %[ftmp7], %[ftmp0] \n\t" + "punpcklbh %[ftmp8], %[ftmp8], %[ftmp0] \n\t" + "punpcklbh %[ftmp9], %[ftmp9], %[ftmp0] \n\t" + "punpcklbh %[ftmp10], %[ftmp10], %[ftmp0] \n\t" + "punpcklbh %[ftmp11], %[ftmp11], %[ftmp0] \n\t" + PTR_ADDIU "%[width], %[width], -0x04 \n\t" + /* Get raw data */ + GET_DATA_V_MMI + ROUND_POWER_OF_TWO_MMI(%[srcl], %[ftmp13], %[ftmp5], + %[ftmp6], %[tmp0]) + ROUND_POWER_OF_TWO_MMI(%[srch], %[ftmp13], %[ftmp5], + %[ftmp6], %[tmp0]) + "packsswh %[srcl], %[srcl], %[srch] \n\t" + "packushb %[ftmp12], %[srcl], %[ftmp0] \n\t" + "punpcklbh %[ftmp12], %[ftmp12], %[ftmp0] \n\t" + "gsldlc1 %[ftmp4], 0x07(%[dst]) \n\t" + "gsldrc1 %[ftmp4], 0x00(%[dst]) \n\t" + "punpcklbh %[ftmp4], %[ftmp4], %[ftmp0] \n\t" + "paddh %[ftmp12], %[ftmp12], %[ftmp4] \n\t" + "li %[tmp0], 0x10001 \n\t" + "dmtc1 %[tmp0], %[ftmp5] \n\t" + "punpcklhw %[ftmp5], %[ftmp5], %[ftmp5] \n\t" + "paddh %[ftmp12], %[ftmp12], %[ftmp5] \n\t" + "psrah %[ftmp12], %[ftmp12], %[ftmp5] \n\t" + "packushb %[ftmp12], %[ftmp12], %[ftmp0] \n\t" + "swc1 %[ftmp12], 0x00(%[dst]) \n\t" + PTR_ADDIU "%[dst], %[dst], 0x04 \n\t" + PTR_ADDIU "%[src], %[src], 0x04 \n\t" + /* Loop count */ + "bnez %[width], 1b \n\t" + PTR_SUBU "%[width], %[addr], %[src_stride] \n\t" + PTR_ADDU "%[src], %[src], %[src_stride] \n\t" + PTR_ADDU "%[dst], %[dst], %[dst_stride] \n\t" + PTR_ADDIU "%[height], %[height], -0x01 \n\t" + "bnez %[height], 1b \n\t" + : [srcl]"=&f"(ftmp[0]), [srch]"=&f"(ftmp[1]), + [filter10]"=&f"(ftmp[2]), [filter32]"=&f"(ftmp[3]), + [filter54]"=&f"(ftmp[4]), [filter76]"=&f"(ftmp[5]), + [ftmp0]"=&f"(ftmp[6]), [ftmp4]"=&f"(ftmp[7]), + [ftmp5]"=&f"(ftmp[8]), [ftmp6]"=&f"(ftmp[9]), + [ftmp7]"=&f"(ftmp[10]), [ftmp8]"=&f"(ftmp[11]), + [ftmp9]"=&f"(ftmp[12]), [ftmp10]"=&f"(ftmp[13]), + [ftmp11]"=&f"(ftmp[14]), [ftmp12]"=&f"(ftmp[15]), + [src]"+&r"(src), [dst]"+&r"(dst), + [width]"+&r"(w), [height]"+&r"(h), + [tmp0]"=&r"(tmp[0]), [ftmp13]"=&f"(ftmp[16]) + : [filter]"r"(filter_y), + [src_stride]"r"((mips_reg)src_stride), + [dst_stride]"r"((mips_reg)dst_stride), + [addr]"r"((mips_reg)addr) + : "memory" + ); +} + +static void convolve_avg_mmi(const uint8_t *src, int32_t src_stride, + uint8_t *dst, int32_t dst_stride, + int32_t w, int32_t h) +{ + double ftmp[4]; + uint32_t tmp[2]; + src_stride -= w; + dst_stride -= w; + + __asm__ volatile ( + "move %[tmp1], %[width] \n\t" + "xor %[ftmp0], %[ftmp0], %[ftmp0] \n\t" + "li %[tmp0], 0x10001 \n\t" + "dmtc1 %[tmp0], %[ftmp3] \n\t" + "punpcklhw %[ftmp3], %[ftmp3], %[ftmp3] \n\t" + "1: \n\t" + "gslwlc1 %[ftmp1], 0x07(%[src]) \n\t" + "gslwrc1 %[ftmp1], 0x00(%[src]) \n\t" + "gslwlc1 %[ftmp2], 0x07(%[dst]) \n\t" + "gslwrc1 %[ftmp2], 0x00(%[dst]) \n\t" + "punpcklbh %[ftmp1], %[ftmp1], %[ftmp0] \n\t" + "punpcklbh %[ftmp2], %[ftmp2], %[ftmp0] \n\t" + "paddh %[ftmp1], %[ftmp1], %[ftmp2] \n\t" + "paddh %[ftmp1], %[ftmp1], %[ftmp3] \n\t" + "psrah %[ftmp1], %[ftmp1], %[ftmp3] \n\t" + "packushb %[ftmp1], %[ftmp1], %[ftmp0] \n\t" + "swc1 %[ftmp1], 0x00(%[dst]) \n\t" + PTR_ADDIU "%[width], %[width], -0x04 \n\t" + PTR_ADDIU "%[dst], %[dst], 0x04 \n\t" + PTR_ADDIU "%[src], %[src], 0x04 \n\t" + "bnez %[width], 1b \n\t" + "move %[width], %[tmp1] \n\t" + PTR_ADDU "%[dst], %[dst], %[dst_stride] \n\t" + PTR_ADDU "%[src], %[src], %[src_stride] \n\t" + PTR_ADDIU "%[height], %[height], -0x01 \n\t" + "bnez %[height], 1b \n\t" + : [ftmp0]"=&f"(ftmp[0]), [ftmp1]"=&f"(ftmp[1]), + [ftmp2]"=&f"(ftmp[2]), [ftmp3]"=&f"(ftmp[3]), + [tmp0]"=&r"(tmp[0]), [tmp1]"=&r"(tmp[1]), + [src]"+&r"(src), [dst]"+&r"(dst), + [width]"+&r"(w), [height]"+&r"(h) + : [src_stride]"r"((mips_reg)src_stride), + [dst_stride]"r"((mips_reg)dst_stride) + : "memory" + ); +} + +static const int16_t vp9_subpel_filters_mmi[3][15][8] = { + [FILTER_8TAP_REGULAR] = { + {0, 1, -5, 126, 8, -3, 1, 0}, + {-1, 3, -10, 122, 18, -6, 2, 0}, + {-1, 4, -13, 118, 27, -9, 3, -1}, + {-1, 4, -16, 112, 37, -11, 4, -1}, + {-1, 5, -18, 105, 48, -14, 4, -1}, + {-1, 5, -19, 97, 58, -16, 5, -1}, + {-1, 6, -19, 88, 68, -18, 5, -1}, + {-1, 6, -19, 78, 78, -19, 6, -1}, + {-1, 5, -18, 68, 88, -19, 6, -1}, + {-1, 5, -16, 58, 97, -19, 5, -1}, + {-1, 4, -14, 48, 105, -18, 5, -1}, + {-1, 4, -11, 37, 112, -16, 4, -1}, + {-1, 3, -9, 27, 118, -13, 4, -1}, + {0, 2, -6, 18, 122, -10, 3, -1}, + {0, 1, -3, 8, 126, -5, 1, 0}, + }, [FILTER_8TAP_SHARP] = { + {-1, 3, -7, 127, 8, -3, 1, 0}, + {-2, 5, -13, 125, 17, -6, 3, -1}, + {-3, 7, -17, 121, 27, -10, 5, -2}, + {-4, 9, -20, 115, 37, -13, 6, -2}, + {-4, 10, -23, 108, 48, -16, 8, -3}, + {-4, 10, -24, 100, 59, -19, 9, -3}, + {-4, 11, -24, 90, 70, -21, 10, -4}, + {-4, 11, -23, 80, 80, -23, 11, -4}, + {-4, 10, -21, 70, 90, -24, 11, -4}, + {-3, 9, -19, 59, 100, -24, 10, -4}, + {-3, 8, -16, 48, 108, -23, 10, -4}, + {-2, 6, -13, 37, 115, -20, 9, -4}, + {-2, 5, -10, 27, 121, -17, 7, -3}, + {-1, 3, -6, 17, 125, -13, 5, -2}, + {0, 1, -3, 8, 127, -7, 3, -1}, + }, [FILTER_8TAP_SMOOTH] = { + {-3, -1, 32, 64, 38, 1, -3, 0}, + {-2, -2, 29, 63, 41, 2, -3, 0}, + {-2, -2, 26, 63, 43, 4, -4, 0}, + {-2, -3, 24, 62, 46, 5, -4, 0}, + {-2, -3, 21, 60, 49, 7, -4, 0}, + {-1, -4, 18, 59, 51, 9, -4, 0}, + {-1, -4, 16, 57, 53, 12, -4, -1}, + {-1, -4, 14, 55, 55, 14, -4, -1}, + {-1, -4, 12, 53, 57, 16, -4, -1}, + {0, -4, 9, 51, 59, 18, -4, -1}, + {0, -4, 7, 49, 60, 21, -3, -2}, + {0, -4, 5, 46, 62, 24, -3, -2}, + {0, -4, 4, 43, 63, 26, -2, -2}, + {0, -3, 2, 41, 63, 29, -2, -2}, + {0, -3, 1, 38, 64, 32, -1, -3}, + } +}; + +#define VP9_8TAP_MIPS_MMI_FUNC(SIZE, TYPE, TYPE_IDX) \ +void ff_put_8tap_##TYPE##_##SIZE##h_mmi(uint8_t *dst, ptrdiff_t dststride, \ + const uint8_t *src, \ + ptrdiff_t srcstride, \ + int h, int mx, int my) \ +{ \ + const int16_t *filter = vp9_subpel_filters_mmi[TYPE_IDX][mx-1]; \ + \ + convolve_horiz_mmi(src, srcstride, dst, dststride, filter, SIZE, h); \ +} \ + \ +void ff_put_8tap_##TYPE##_##SIZE##v_mmi(uint8_t *dst, ptrdiff_t dststride, \ + const uint8_t *src, \ + ptrdiff_t srcstride, \ + int h, int mx, int my) \ +{ \ + const int16_t *filter = vp9_subpel_filters_mmi[TYPE_IDX][my-1]; \ + \ + src -= (3 * srcstride); \ + convolve_vert_mmi(src, srcstride, dst, dststride, filter, SIZE, h); \ +} \ + \ +void ff_put_8tap_##TYPE##_##SIZE##hv_mmi(uint8_t *dst, ptrdiff_t dststride, \ + const uint8_t *src, \ + ptrdiff_t srcstride, \ + int h, int mx, int my) \ +{ \ + const uint16_t *hfilter = vp9_subpel_filters_mmi[TYPE_IDX][mx-1]; \ + const uint16_t *vfilter = vp9_subpel_filters_mmi[TYPE_IDX][my-1]; \ + \ + int tmp_h = h + 7; \ + uint8_t temp[64 * 71]; \ + src -= (3 * srcstride); \ + convolve_horiz_mmi(src, srcstride, temp, 64, hfilter, SIZE, tmp_h); \ + convolve_vert_mmi(temp, 64, dst, dststride, vfilter, SIZE, h); \ +} \ + \ +void ff_avg_8tap_##TYPE##_##SIZE##h_mmi(uint8_t *dst, ptrdiff_t dststride, \ + const uint8_t *src, \ + ptrdiff_t srcstride, \ + int h, int mx, int my) \ +{ \ + const int16_t *filter = vp9_subpel_filters_mmi[TYPE_IDX][mx-1]; \ + \ + convolve_avg_horiz_mmi(src, srcstride, dst, dststride, filter, SIZE, h); \ +} \ + \ +void ff_avg_8tap_##TYPE##_##SIZE##v_mmi(uint8_t *dst, ptrdiff_t dststride, \ + const uint8_t *src, \ + ptrdiff_t srcstride, \ + int h, int mx, int my) \ +{ \ + const int16_t *filter = vp9_subpel_filters_mmi[TYPE_IDX][my-1]; \ + \ + src -= (3 * srcstride); \ + convolve_avg_vert_mmi(src, srcstride, dst, dststride, filter, SIZE, h); \ +} \ + \ +void ff_avg_8tap_##TYPE##_##SIZE##hv_mmi(uint8_t *dst, ptrdiff_t dststride, \ + const uint8_t *src, \ + ptrdiff_t srcstride, \ + int h, int mx, int my) \ +{ \ + const uint16_t *hfilter = vp9_subpel_filters_mmi[TYPE_IDX][mx-1]; \ + const uint16_t *vfilter = vp9_subpel_filters_mmi[TYPE_IDX][my-1]; \ + \ + uint8_t temp1[64 * 64]; \ + uint8_t temp2[64 * 71]; \ + int tmp_h = h + 7; \ + src -= (3 * srcstride); \ + convolve_horiz_mmi(src, srcstride, temp2, 64, hfilter, SIZE, tmp_h); \ + convolve_vert_mmi(temp2, 64, temp1, 64, vfilter, SIZE, h); \ + convolve_avg_mmi(temp1, 64, dst, dststride, SIZE, h); \ +} + +VP9_8TAP_MIPS_MMI_FUNC(64, regular, FILTER_8TAP_REGULAR); +VP9_8TAP_MIPS_MMI_FUNC(32, regular, FILTER_8TAP_REGULAR); +VP9_8TAP_MIPS_MMI_FUNC(16, regular, FILTER_8TAP_REGULAR); +VP9_8TAP_MIPS_MMI_FUNC(8, regular, FILTER_8TAP_REGULAR); +VP9_8TAP_MIPS_MMI_FUNC(4, regular, FILTER_8TAP_REGULAR); + +VP9_8TAP_MIPS_MMI_FUNC(64, sharp, FILTER_8TAP_SHARP); +VP9_8TAP_MIPS_MMI_FUNC(32, sharp, FILTER_8TAP_SHARP); +VP9_8TAP_MIPS_MMI_FUNC(16, sharp, FILTER_8TAP_SHARP); +VP9_8TAP_MIPS_MMI_FUNC(8, sharp, FILTER_8TAP_SHARP); +VP9_8TAP_MIPS_MMI_FUNC(4, sharp, FILTER_8TAP_SHARP); + +VP9_8TAP_MIPS_MMI_FUNC(64, smooth, FILTER_8TAP_SMOOTH); +VP9_8TAP_MIPS_MMI_FUNC(32, smooth, FILTER_8TAP_SMOOTH); +VP9_8TAP_MIPS_MMI_FUNC(16, smooth, FILTER_8TAP_SMOOTH); +VP9_8TAP_MIPS_MMI_FUNC(8, smooth, FILTER_8TAP_SMOOTH); +VP9_8TAP_MIPS_MMI_FUNC(4, smooth, FILTER_8TAP_SMOOTH); + +#undef VP9_8TAP_MIPS_MMI_FUNC diff --git a/libavcodec/mips/vp9_mc_msa.c b/libavcodec/mips/vp9_mc_msa.c index 749e8cbe8..1d8a89276 100644 --- a/libavcodec/mips/vp9_mc_msa.c +++ b/libavcodec/mips/vp9_mc_msa.c @@ -153,7 +153,7 @@ static const int8_t vp9_bilinear_filters_msa[15][2] = { \ PCKEV_B2_UB(in1, in0, in3, in2, tmp0_m, tmp1_m); \ AVER_UB2_UB(tmp0_m, dst0, tmp1_m, dst1, tmp0_m, tmp1_m); \ - ST8x4_UB(tmp0_m, tmp1_m, pdst_m, stride); \ + ST_D4(tmp0_m, tmp1_m, 0, 1, 0, 1, pdst_m, stride); \ } static void common_hz_8t_4x4_msa(const uint8_t *src, int32_t src_stride, @@ -182,7 +182,7 @@ static void common_hz_8t_4x4_msa(const uint8_t *src, int32_t src_stride, SRARI_H2_SH(out0, out1, 7); SAT_SH2_SH(out0, out1, 7); out = PCKEV_XORI128_UB(out0, out1); - ST4x4_UB(out, out, 0, 1, 2, 3, dst, dst_stride); + ST_W4(out, 0, 1, 2, 3, dst, dst_stride); } static void common_hz_8t_4x8_msa(const uint8_t *src, int32_t src_stride, @@ -217,10 +217,9 @@ static void common_hz_8t_4x8_msa(const uint8_t *src, int32_t src_stride, SRARI_H4_SH(out0, out1, out2, out3, 7); SAT_SH4_SH(out0, out1, out2, out3, 7); out = PCKEV_XORI128_UB(out0, out1); - ST4x4_UB(out, out, 0, 1, 2, 3, dst, dst_stride); - dst += (4 * dst_stride); + ST_W4(out, 0, 1, 2, 3, dst, dst_stride); out = PCKEV_XORI128_UB(out2, out3); - ST4x4_UB(out, out, 0, 1, 2, 3, dst, dst_stride); + ST_W4(out, 0, 1, 2, 3, dst + 4 * dst_stride, dst_stride); } static void common_hz_8t_4w_msa(const uint8_t *src, int32_t src_stride, @@ -262,7 +261,7 @@ static void common_hz_8t_8x4_msa(const uint8_t *src, int32_t src_stride, SAT_SH4_SH(out0, out1, out2, out3, 7); tmp0 = PCKEV_XORI128_UB(out0, out1); tmp1 = PCKEV_XORI128_UB(out2, out3); - ST8x4_UB(tmp0, tmp1, dst, dst_stride); + ST_D4(tmp0, tmp1, 0, 1, 0, 1, dst, dst_stride); } static void common_hz_8t_8x8mult_msa(const uint8_t *src, int32_t src_stride, @@ -296,7 +295,7 @@ static void common_hz_8t_8x8mult_msa(const uint8_t *src, int32_t src_stride, SAT_SH4_SH(out0, out1, out2, out3, 7); tmp0 = PCKEV_XORI128_UB(out0, out1); tmp1 = PCKEV_XORI128_UB(out2, out3); - ST8x4_UB(tmp0, tmp1, dst, dst_stride); + ST_D4(tmp0, tmp1, 0, 1, 0, 1, dst, dst_stride); dst += (4 * dst_stride); } } @@ -510,7 +509,7 @@ static void common_vt_8t_4w_msa(const uint8_t *src, int32_t src_stride, SRARI_H2_SH(out10, out32, 7); SAT_SH2_SH(out10, out32, 7); out = PCKEV_XORI128_UB(out10, out32); - ST4x4_UB(out, out, 0, 1, 2, 3, dst, dst_stride); + ST_W4(out, 0, 1, 2, 3, dst, dst_stride); dst += (4 * dst_stride); src2110 = src6554; @@ -562,7 +561,7 @@ static void common_vt_8t_8w_msa(const uint8_t *src, int32_t src_stride, SAT_SH4_SH(out0_r, out1_r, out2_r, out3_r, 7); tmp0 = PCKEV_XORI128_UB(out0_r, out1_r); tmp1 = PCKEV_XORI128_UB(out2_r, out3_r); - ST8x4_UB(tmp0, tmp1, dst, dst_stride); + ST_D4(tmp0, tmp1, 0, 1, 0, 1, dst, dst_stride); dst += (4 * dst_stride); src10_r = src54_r; @@ -825,7 +824,7 @@ static void common_hv_8ht_8vt_4w_msa(const uint8_t *src, int32_t src_stride, SRARI_H2_SH(tmp0, tmp1, 7); SAT_SH2_SH(tmp0, tmp1, 7); out = PCKEV_XORI128_UB(tmp0, tmp1); - ST4x4_UB(out, out, 0, 1, 2, 3, dst, dst_stride); + ST_W4(out, 0, 1, 2, 3, dst, dst_stride); dst += (4 * dst_stride); hz_out5 = hz_out9; @@ -920,7 +919,7 @@ static void common_hv_8ht_8vt_8w_msa(const uint8_t *src, int32_t src_stride, SAT_SH4_SH(tmp0, tmp1, tmp2, tmp3, 7); vec0 = PCKEV_XORI128_UB(tmp0, tmp1); vec1 = PCKEV_XORI128_UB(tmp2, tmp3); - ST8x4_UB(vec0, vec1, dst, dst_stride); + ST_D4(vec0, vec1, 0, 1, 0, 1, dst, dst_stride); dst += (4 * dst_stride); hz_out6 = hz_out10; @@ -1016,7 +1015,7 @@ static void common_hz_8t_and_aver_dst_4x4_msa(const uint8_t *src, SAT_SH2_SH(res0, res1, 7); res = PCKEV_XORI128_UB(res0, res1); res = (v16u8) __msa_aver_u_b(res, dst0); - ST4x4_UB(res, res, 0, 1, 2, 3, dst, dst_stride); + ST_W4(res, 0, 1, 2, 3, dst, dst_stride); } static void common_hz_8t_and_aver_dst_4x8_msa(const uint8_t *src, @@ -1061,7 +1060,7 @@ static void common_hz_8t_and_aver_dst_4x8_msa(const uint8_t *src, ILVR_D2_UB(res1, res0, res3, res2, res0, res2); XORI_B2_128_UB(res0, res2); AVER_UB2_UB(res0, dst0, res2, dst1, res0, res2); - ST4x8_UB(res0, res2, dst, dst_stride); + ST_W8(res0, res2, 0, 1, 2, 3, 0, 1, 2, 3, dst, dst_stride); } static void common_hz_8t_and_aver_dst_4w_msa(const uint8_t *src, @@ -1348,7 +1347,7 @@ static void common_vt_8t_and_aver_dst_4w_msa(const uint8_t *src, out = PCKEV_XORI128_UB(out10, out32); out = __msa_aver_u_b(out, dst0); - ST4x4_UB(out, out, 0, 1, 2, 3, dst, dst_stride); + ST_W4(out, 0, 1, 2, 3, dst, dst_stride); dst += (4 * dst_stride); src2110 = src6554; @@ -1619,7 +1618,7 @@ static void common_hv_8ht_8vt_and_aver_dst_4w_msa(const uint8_t *src, SAT_SH2_SH(res0, res1, 7); res = PCKEV_XORI128_UB(res0, res1); res = (v16u8) __msa_aver_u_b(res, dst0); - ST4x4_UB(res, res, 0, 1, 2, 3, dst, dst_stride); + ST_W4(res, 0, 1, 2, 3, dst, dst_stride); dst += (4 * dst_stride); hz_out5 = hz_out9; @@ -1812,7 +1811,8 @@ static void common_hz_2t_4x4_msa(const uint8_t *src, int32_t src_stride, DOTP_UB2_UH(vec0, vec1, filt0, filt0, vec2, vec3); SRARI_H2_UH(vec2, vec3, 7); PCKEV_B2_UB(vec2, vec2, vec3, vec3, res0, res1); - ST4x4_UB(res0, res1, 0, 1, 0, 1, dst, dst_stride); + ST_W2(res0, 0, 1, dst, dst_stride); + ST_W2(res1, 0, 1, dst + 2 * dst_stride, dst_stride); } static void common_hz_2t_4x8_msa(const uint8_t *src, int32_t src_stride, @@ -1838,9 +1838,10 @@ static void common_hz_2t_4x8_msa(const uint8_t *src, int32_t src_stride, SRARI_H4_UH(vec4, vec5, vec6, vec7, 7); PCKEV_B4_SB(vec4, vec4, vec5, vec5, vec6, vec6, vec7, vec7, res0, res1, res2, res3); - ST4x4_UB(res0, res1, 0, 1, 0, 1, dst, dst_stride); - dst += (4 * dst_stride); - ST4x4_UB(res2, res3, 0, 1, 0, 1, dst, dst_stride); + ST_W2(res0, 0, 1, dst, dst_stride); + ST_W2(res1, 0, 1, dst + 2 * dst_stride, dst_stride); + ST_W2(res2, 0, 1, dst + 4 * dst_stride, dst_stride); + ST_W2(res3, 0, 1, dst + 6 * dst_stride, dst_stride); } void ff_put_bilin_4h_msa(uint8_t *dst, ptrdiff_t dst_stride, @@ -1877,7 +1878,7 @@ static void common_hz_2t_8x4_msa(const uint8_t *src, int32_t src_stride, vec0, vec1, vec2, vec3); SRARI_H4_UH(vec0, vec1, vec2, vec3, 7); PCKEV_B2_SB(vec1, vec0, vec3, vec2, src0, src1); - ST8x4_UB(src0, src1, dst, dst_stride); + ST_D4(src0, src1, 0, 1, 0, 1, dst, dst_stride); } static void common_hz_2t_8x8mult_msa(const uint8_t *src, int32_t src_stride, @@ -1906,8 +1907,7 @@ static void common_hz_2t_8x8mult_msa(const uint8_t *src, int32_t src_stride, src += (4 * src_stride); PCKEV_B2_SB(vec1, vec0, vec3, vec2, out0, out1); - ST8x4_UB(out0, out1, dst, dst_stride); - dst += (4 * dst_stride); + ST_D4(out0, out1, 0, 1, 0, 1, dst, dst_stride); VSHF_B2_UH(src0, src0, src1, src1, mask, mask, vec0, vec1); VSHF_B2_UH(src2, src2, src3, src3, mask, mask, vec2, vec3); @@ -1915,8 +1915,8 @@ static void common_hz_2t_8x8mult_msa(const uint8_t *src, int32_t src_stride, vec0, vec1, vec2, vec3); SRARI_H4_UH(vec0, vec1, vec2, vec3, 7); PCKEV_B2_SB(vec1, vec0, vec3, vec2, out0, out1); - ST8x4_UB(out0, out1, dst, dst_stride); - dst += (4 * dst_stride); + ST_D4(out0, out1, 0, 1, 0, 1, dst + 4 * dst_stride, dst_stride); + dst += (8 * dst_stride); if (16 == height) { LD_SB4(src, src_stride, src0, src1, src2, src3); @@ -1931,7 +1931,7 @@ static void common_hz_2t_8x8mult_msa(const uint8_t *src, int32_t src_stride, src += (4 * src_stride); PCKEV_B2_SB(vec1, vec0, vec3, vec2, out0, out1); - ST8x4_UB(out0, out1, dst, dst_stride); + ST_D4(out0, out1, 0, 1, 0, 1, dst, dst_stride); VSHF_B2_UH(src0, src0, src1, src1, mask, mask, vec0, vec1); VSHF_B2_UH(src2, src2, src3, src3, mask, mask, vec2, vec3); @@ -1939,7 +1939,7 @@ static void common_hz_2t_8x8mult_msa(const uint8_t *src, int32_t src_stride, vec0, vec1, vec2, vec3); SRARI_H4_UH(vec0, vec1, vec2, vec3, 7); PCKEV_B2_SB(vec1, vec0, vec3, vec2, out0, out1); - ST8x4_UB(out0, out1, dst + 4 * dst_stride, dst_stride); + ST_D4(out0, out1, 0, 1, 0, 1, dst + 4 * dst_stride, dst_stride); } } @@ -2137,7 +2137,7 @@ static void common_vt_2t_4x4_msa(const uint8_t *src, int32_t src_stride, SRARI_H2_UH(tmp0, tmp1, 7); SAT_UH2_UH(tmp0, tmp1, 7); src2110 = __msa_pckev_b((v16i8) tmp1, (v16i8) tmp0); - ST4x4_UB(src2110, src2110, 0, 1, 2, 3, dst, dst_stride); + ST_W4(src2110, 0, 1, 2, 3, dst, dst_stride); } static void common_vt_2t_4x8_msa(const uint8_t *src, int32_t src_stride, @@ -2171,8 +2171,7 @@ static void common_vt_2t_4x8_msa(const uint8_t *src, int32_t src_stride, SRARI_H4_UH(tmp0, tmp1, tmp2, tmp3, 7); SAT_UH4_UH(tmp0, tmp1, tmp2, tmp3, 7); PCKEV_B2_SB(tmp1, tmp0, tmp3, tmp2, src2110, src4332); - ST4x4_UB(src2110, src2110, 0, 1, 2, 3, dst, dst_stride); - ST4x4_UB(src4332, src4332, 0, 1, 2, 3, dst + 4 * dst_stride, dst_stride); + ST_W8(src2110, src4332, 0, 1, 2, 3, 0, 1, 2, 3, dst, dst_stride); } void ff_put_bilin_4v_msa(uint8_t *dst, ptrdiff_t dst_stride, @@ -2209,7 +2208,7 @@ static void common_vt_2t_8x4_msa(const uint8_t *src, int32_t src_stride, SRARI_H4_UH(tmp0, tmp1, tmp2, tmp3, 7); SAT_UH4_UH(tmp0, tmp1, tmp2, tmp3, 7); PCKEV_B2_SB(tmp1, tmp0, tmp3, tmp2, out0, out1); - ST8x4_UB(out0, out1, dst, dst_stride); + ST_D4(out0, out1, 0, 1, 0, 1, dst, dst_stride); } static void common_vt_2t_8x8mult_msa(const uint8_t *src, int32_t src_stride, @@ -2243,16 +2242,15 @@ static void common_vt_2t_8x8mult_msa(const uint8_t *src, int32_t src_stride, SRARI_H4_UH(tmp0, tmp1, tmp2, tmp3, 7); SAT_UH4_UH(tmp0, tmp1, tmp2, tmp3, 7); PCKEV_B2_SB(tmp1, tmp0, tmp3, tmp2, out0, out1); - ST8x4_UB(out0, out1, dst, dst_stride); - dst += (4 * dst_stride); + ST_D4(out0, out1, 0, 1, 0, 1, dst, dst_stride); DOTP_UB4_UH(vec4, vec5, vec6, vec7, filt0, filt0, filt0, filt0, tmp0, tmp1, tmp2, tmp3); SRARI_H4_UH(tmp0, tmp1, tmp2, tmp3, 7); SAT_UH4_UH(tmp0, tmp1, tmp2, tmp3, 7); PCKEV_B2_SB(tmp1, tmp0, tmp3, tmp2, out0, out1); - ST8x4_UB(out0, out1, dst, dst_stride); - dst += (4 * dst_stride); + ST_D4(out0, out1, 0, 1, 0, 1, dst + 4 * dst_stride, dst_stride); + dst += (8 * dst_stride); src0 = src8; } @@ -2514,7 +2512,8 @@ static void common_hv_2ht_2vt_4x4_msa(const uint8_t *src, int32_t src_stride, SRARI_H2_UH(tmp0, tmp1, 7); SAT_UH2_UH(tmp0, tmp1, 7); PCKEV_B2_UB(tmp0, tmp0, tmp1, tmp1, res0, res1); - ST4x4_UB(res0, res1, 0, 1, 0, 1, dst, dst_stride); + ST_W2(res0, 0, 1, dst, dst_stride); + ST_W2(res1, 0, 1, dst + 2 * dst_stride, dst_stride); } static void common_hv_2ht_2vt_4x8_msa(const uint8_t *src, int32_t src_stride, @@ -2557,9 +2556,10 @@ static void common_hv_2ht_2vt_4x8_msa(const uint8_t *src, int32_t src_stride, SAT_UH4_UH(vec4, vec5, vec6, vec7, 7); PCKEV_B4_SB(vec4, vec4, vec5, vec5, vec6, vec6, vec7, vec7, res0, res1, res2, res3); - ST4x4_UB(res0, res1, 0, 1, 0, 1, dst, dst_stride); - dst += (4 * dst_stride); - ST4x4_UB(res2, res3, 0, 1, 0, 1, dst, dst_stride); + ST_W2(res0, 0, 1, dst, dst_stride); + ST_W2(res1, 0, 1, dst + 2 * dst_stride, dst_stride); + ST_W2(res2, 0, 1, dst + 4 * dst_stride, dst_stride); + ST_W2(res3, 0, 1, dst + 6 * dst_stride, dst_stride); } void ff_put_bilin_4hv_msa(uint8_t *dst, ptrdiff_t dst_stride, @@ -2618,7 +2618,7 @@ static void common_hv_2ht_2vt_8x4_msa(const uint8_t *src, int32_t src_stride, SRARI_H4_UH(tmp0, tmp1, tmp2, tmp3, 7); SAT_UH4_UH(tmp0, tmp1, tmp2, tmp3, 7); PCKEV_B2_SB(tmp1, tmp0, tmp3, tmp2, out0, out1); - ST8x4_UB(out0, out1, dst, dst_stride); + ST_D4(out0, out1, 0, 1, 0, 1, dst, dst_stride); } static void common_hv_2ht_2vt_8x8mult_msa(const uint8_t *src, int32_t src_stride, @@ -2674,8 +2674,7 @@ static void common_hv_2ht_2vt_8x8mult_msa(const uint8_t *src, int32_t src_stride SRARI_H2_UH(tmp3, tmp4, 7); SAT_UH2_UH(tmp3, tmp4, 7); PCKEV_B2_SB(tmp2, tmp1, tmp4, tmp3, out0, out1); - ST8x4_UB(out0, out1, dst, dst_stride); - dst += (4 * dst_stride); + ST_D4(out0, out1, 0, 1, 0, 1, dst, dst_stride); hz_out1 = HORIZ_2TAP_FILT_UH(src1, src1, mask, filt_hz, 7); vec0 = (v16u8) __msa_ilvev_b((v16i8) hz_out1, (v16i8) hz_out0); @@ -2696,8 +2695,8 @@ static void common_hv_2ht_2vt_8x8mult_msa(const uint8_t *src, int32_t src_stride SRARI_H4_UH(tmp5, tmp6, tmp7, tmp8, 7); SAT_UH4_UH(tmp5, tmp6, tmp7, tmp8, 7); PCKEV_B2_SB(tmp6, tmp5, tmp8, tmp7, out0, out1); - ST8x4_UB(out0, out1, dst, dst_stride); - dst += (4 * dst_stride); + ST_D4(out0, out1, 0, 1, 0, 1, dst + 4 * dst_stride, dst_stride); + dst += (8 * dst_stride); } } @@ -2842,7 +2841,7 @@ static void common_hz_2t_and_aver_dst_4x4_msa(const uint8_t *src, res = (v16u8) __msa_pckev_b((v16i8) vec3, (v16i8) vec2); res = (v16u8) __msa_aver_u_b(res, dst0); - ST4x4_UB(res, res, 0, 1, 2, 3, dst, dst_stride); + ST_W4(res, 0, 1, 2, 3, dst, dst_stride); } static void common_hz_2t_and_aver_dst_4x8_msa(const uint8_t *src, @@ -2876,7 +2875,7 @@ static void common_hz_2t_and_aver_dst_4x8_msa(const uint8_t *src, res2, res3); ILVR_D2_UB(res1, res0, res3, res2, res0, res2); AVER_UB2_UB(res0, dst0, res2, dst1, res0, res2); - ST4x8_UB(res0, res2, dst, dst_stride); + ST_W8(res0, res2, 0, 1, 2, 3, 0, 1, 2, 3, dst, dst_stride); } void ff_avg_bilin_4h_msa(uint8_t *dst, ptrdiff_t dst_stride, @@ -3202,7 +3201,7 @@ static void common_vt_2t_and_aver_dst_4x4_msa(const uint8_t *src, out = (v16u8) __msa_pckev_b((v16i8) tmp1, (v16i8) tmp0); out = __msa_aver_u_b(out, dst0); - ST4x4_UB(out, out, 0, 1, 2, 3, dst, dst_stride); + ST_W4(out, 0, 1, 2, 3, dst, dst_stride); } static void common_vt_2t_and_aver_dst_4x8_msa(const uint8_t *src, @@ -3241,7 +3240,7 @@ static void common_vt_2t_and_aver_dst_4x8_msa(const uint8_t *src, SAT_UH4_UH(tmp0, tmp1, tmp2, tmp3, 7); PCKEV_B2_UB(tmp1, tmp0, tmp3, tmp2, src2110, src4332); AVER_UB2_UB(src2110, dst0, src4332, dst1, src2110, src4332); - ST4x8_UB(src2110, src4332, dst, dst_stride); + ST_W8(src2110, src4332, 0, 1, 2, 3, 0, 1, 2, 3, dst, dst_stride); } void ff_avg_bilin_4v_msa(uint8_t *dst, ptrdiff_t dst_stride, @@ -3620,7 +3619,7 @@ static void common_hv_2ht_2vt_and_aver_dst_4x4_msa(const uint8_t *src, out = (v16u8) __msa_pckev_b((v16i8) tmp1, (v16i8) tmp0); out = __msa_aver_u_b(out, dst0); - ST4x4_UB(out, out, 0, 1, 2, 3, dst, dst_stride); + ST_W4(out, 0, 1, 2, 3, dst, dst_stride); } static void common_hv_2ht_2vt_and_aver_dst_4x8_msa(const uint8_t *src, @@ -3672,7 +3671,7 @@ static void common_hv_2ht_2vt_and_aver_dst_4x8_msa(const uint8_t *src, SAT_UH4_UH(tmp0, tmp1, tmp2, tmp3, 7); PCKEV_B2_UB(tmp1, tmp0, tmp3, tmp2, res0, res1); AVER_UB2_UB(res0, dst0, res1, dst1, res0, res1); - ST4x8_UB(res0, res1, dst, dst_stride); + ST_W8(res0, res1, 0, 1, 2, 3, 0, 1, 2, 3, dst, dst_stride); } void ff_avg_bilin_4hv_msa(uint8_t *dst, ptrdiff_t dst_stride, @@ -4071,14 +4070,14 @@ static void avg_width4_msa(const uint8_t *src, int32_t src_stride, LW4(dst + 4 * dst_stride, dst_stride, tp0, tp1, tp2, tp3); INSERT_W4_UB(tp0, tp1, tp2, tp3, dst1); AVER_UB2_UB(src0, dst0, src1, dst1, dst0, dst1); - ST4x8_UB(dst0, dst1, dst, dst_stride); + ST_W8(dst0, dst1, 0, 1, 2, 3, 0, 1, 2, 3, dst, dst_stride); } else if (4 == height) { LW4(src, src_stride, tp0, tp1, tp2, tp3); INSERT_W4_UB(tp0, tp1, tp2, tp3, src0); LW4(dst, dst_stride, tp0, tp1, tp2, tp3); INSERT_W4_UB(tp0, tp1, tp2, tp3, dst0); dst0 = __msa_aver_u_b(src0, dst0); - ST4x4_UB(dst0, dst0, 0, 1, 2, 3, dst, dst_stride); + ST_W4(dst0, 0, 1, 2, 3, dst, dst_stride); } } @@ -4109,7 +4108,7 @@ static void avg_width8_msa(const uint8_t *src, int32_t src_stride, INSERT_D2_UB(tp6, tp7, dst3); AVER_UB4_UB(src0, dst0, src1, dst1, src2, dst2, src3, dst3, dst0, dst1, dst2, dst3); - ST8x8_UB(dst0, dst1, dst2, dst3, dst, dst_stride); + ST_D8(dst0, dst1, dst2, dst3, 0, 1, 0, 1, 0, 1, 0, 1, dst, dst_stride); dst += 8 * dst_stride; } } else if (4 == height) { @@ -4120,7 +4119,7 @@ static void avg_width8_msa(const uint8_t *src, int32_t src_stride, INSERT_D2_UB(tp0, tp1, dst0); INSERT_D2_UB(tp2, tp3, dst1); AVER_UB2_UB(src0, dst0, src1, dst1, dst0, dst1); - ST8x4_UB(dst0, dst1, dst, dst_stride); + ST_D4(dst0, dst1, 0, 1, 0, 1, dst, dst_stride); } } diff --git a/libavcodec/mips/vp9dsp_init_mips.c b/libavcodec/mips/vp9dsp_init_mips.c index c8a48908a..5990fa695 100644 --- a/libavcodec/mips/vp9dsp_init_mips.c +++ b/libavcodec/mips/vp9dsp_init_mips.c @@ -168,8 +168,50 @@ static av_cold void vp9dsp_init_msa(VP9DSPContext *dsp, int bpp) } #endif // #if HAVE_MSA +#if HAVE_MMI +static av_cold void vp9dsp_mc_init_mmi(VP9DSPContext *dsp) +{ +#define init_subpel1(idx1, idx2, idxh, idxv, sz, dir, type) \ + dsp->mc[idx1][FILTER_8TAP_SMOOTH ][idx2][idxh][idxv] = \ + ff_##type##_8tap_smooth_##sz##dir##_mmi; \ + dsp->mc[idx1][FILTER_8TAP_REGULAR][idx2][idxh][idxv] = \ + ff_##type##_8tap_regular_##sz##dir##_mmi; \ + dsp->mc[idx1][FILTER_8TAP_SHARP ][idx2][idxh][idxv] = \ + ff_##type##_8tap_sharp_##sz##dir##_mmi; + +#define init_subpel2(idx, idxh, idxv, dir, type) \ + init_subpel1(0, idx, idxh, idxv, 64, dir, type); \ + init_subpel1(1, idx, idxh, idxv, 32, dir, type); \ + init_subpel1(2, idx, idxh, idxv, 16, dir, type); \ + init_subpel1(3, idx, idxh, idxv, 8, dir, type); \ + init_subpel1(4, idx, idxh, idxv, 4, dir, type) + +#define init_subpel3(idx, type) \ + init_subpel2(idx, 1, 1, hv, type); \ + init_subpel2(idx, 0, 1, v, type); \ + init_subpel2(idx, 1, 0, h, type) + + init_subpel3(0, put); + init_subpel3(1, avg); + +#undef init_subpel1 +#undef init_subpel2 +#undef init_subpel3 +} + +static av_cold void vp9dsp_init_mmi(VP9DSPContext *dsp, int bpp) +{ + if (bpp == 8) { + vp9dsp_mc_init_mmi(dsp); + } +} +#endif // #if HAVE_MMI + av_cold void ff_vp9dsp_init_mips(VP9DSPContext *dsp, int bpp) { +#if HAVE_MMI + vp9dsp_init_mmi(dsp, bpp); +#endif // #if HAVE_MMI #if HAVE_MSA vp9dsp_init_msa(dsp, bpp); #endif // #if HAVE_MSA diff --git a/libavcodec/mips/vp9dsp_mips.h b/libavcodec/mips/vp9dsp_mips.h index 4d7303888..0b6ce7cd7 100644 --- a/libavcodec/mips/vp9dsp_mips.h +++ b/libavcodec/mips/vp9dsp_mips.h @@ -234,4 +234,54 @@ void ff_tm_16x16_msa(uint8_t *dst, ptrdiff_t stride, const uint8_t *left, void ff_tm_32x32_msa(uint8_t *dst, ptrdiff_t stride, const uint8_t *left, const uint8_t *top); +#define VP9_8TAP_MIPS_MMI_FUNC(SIZE, type, type_idx) \ +void ff_put_8tap_##type##_##SIZE##h_mmi(uint8_t *dst, ptrdiff_t dststride, \ + const uint8_t *src, \ + ptrdiff_t srcstride, \ + int h, int mx, int my); \ + \ +void ff_put_8tap_##type##_##SIZE##v_mmi(uint8_t *dst, ptrdiff_t dststride, \ + const uint8_t *src, \ + ptrdiff_t srcstride, \ + int h, int mx, int my); \ + \ +void ff_put_8tap_##type##_##SIZE##hv_mmi(uint8_t *dst, ptrdiff_t dststride, \ + const uint8_t *src, \ + ptrdiff_t srcstride, \ + int h, int mx, int my); \ + \ +void ff_avg_8tap_##type##_##SIZE##h_mmi(uint8_t *dst, ptrdiff_t dststride, \ + const uint8_t *src, \ + ptrdiff_t srcstride, \ + int h, int mx, int my); \ + \ +void ff_avg_8tap_##type##_##SIZE##v_mmi(uint8_t *dst, ptrdiff_t dststride, \ + const uint8_t *src, \ + ptrdiff_t srcstride, \ + int h, int mx, int my); \ + \ +void ff_avg_8tap_##type##_##SIZE##hv_mmi(uint8_t *dst, ptrdiff_t dststride, \ + const uint8_t *src, \ + ptrdiff_t srcstride, \ + int h, int mx, int my); + +VP9_8TAP_MIPS_MMI_FUNC(64, regular, FILTER_8TAP_REGULAR); +VP9_8TAP_MIPS_MMI_FUNC(32, regular, FILTER_8TAP_REGULAR); +VP9_8TAP_MIPS_MMI_FUNC(16, regular, FILTER_8TAP_REGULAR); +VP9_8TAP_MIPS_MMI_FUNC(8, regular, FILTER_8TAP_REGULAR); +VP9_8TAP_MIPS_MMI_FUNC(4, regular, FILTER_8TAP_REGULAR); + +VP9_8TAP_MIPS_MMI_FUNC(64, sharp, FILTER_8TAP_SHARP); +VP9_8TAP_MIPS_MMI_FUNC(32, sharp, FILTER_8TAP_SHARP); +VP9_8TAP_MIPS_MMI_FUNC(16, sharp, FILTER_8TAP_SHARP); +VP9_8TAP_MIPS_MMI_FUNC(8, sharp, FILTER_8TAP_SHARP); +VP9_8TAP_MIPS_MMI_FUNC(4, sharp, FILTER_8TAP_SHARP); + +VP9_8TAP_MIPS_MMI_FUNC(64, smooth, FILTER_8TAP_SMOOTH); +VP9_8TAP_MIPS_MMI_FUNC(32, smooth, FILTER_8TAP_SMOOTH); +VP9_8TAP_MIPS_MMI_FUNC(16, smooth, FILTER_8TAP_SMOOTH); +VP9_8TAP_MIPS_MMI_FUNC(8, smooth, FILTER_8TAP_SMOOTH); +VP9_8TAP_MIPS_MMI_FUNC(4, smooth, FILTER_8TAP_SMOOTH); +#undef VP9_8TAP_MIPS_MMI_FUNC + #endif // #ifndef AVCODEC_MIPS_VP9DSP_MIPS_H diff --git a/libavcodec/mjpegbdec.c b/libavcodec/mjpegbdec.c index 8583fcb4f..37d7bb822 100644 --- a/libavcodec/mjpegbdec.c +++ b/libavcodec/mjpegbdec.c @@ -87,9 +87,9 @@ read_header: if (dqt_offs) { init_get_bits(&s->gb, buf_ptr+dqt_offs, (buf_end - (buf_ptr+dqt_offs))*8); s->start_code = DQT; - if (ff_mjpeg_decode_dqt(s) < 0 && - (avctx->err_recognition & AV_EF_EXPLODE)) - return AVERROR_INVALIDDATA; + ret = ff_mjpeg_decode_dqt(s); + if (ret < 0 && (avctx->err_recognition & AV_EF_EXPLODE)) + return ret; } dht_offs = read_offs(avctx, &hgb, buf_end - buf_ptr, "dht is %d and size is %d\n"); @@ -105,8 +105,8 @@ read_header: if (sof_offs) { init_get_bits(&s->gb, buf_ptr+sof_offs, (buf_end - (buf_ptr+sof_offs))*8); s->start_code = SOF0; - if (ff_mjpeg_decode_sof(s) < 0) - return -1; + if ((ret = ff_mjpeg_decode_sof(s)) < 0) + return ret; } sos_offs = read_offs(avctx, &hgb, buf_end - buf_ptr, "sos is %d and size is %d\n"); @@ -118,9 +118,9 @@ read_header: 8 * FFMIN(field_size, buf_end - buf_ptr - sos_offs)); s->mjpb_skiptosod = (sod_offs - sos_offs - show_bits(&s->gb, 16)); s->start_code = SOS; - if (ff_mjpeg_decode_sos(s, NULL, 0, NULL) < 0 && - (avctx->err_recognition & AV_EF_EXPLODE)) - return AVERROR_INVALIDDATA; + ret = ff_mjpeg_decode_sos(s, NULL, 0, NULL); + if (ret < 0 && (avctx->err_recognition & AV_EF_EXPLODE)) + return ret; } if (s->interlaced) { diff --git a/libavcodec/mjpegdec.c b/libavcodec/mjpegdec.c index 58c4c053a..a65bc8df1 100644 --- a/libavcodec/mjpegdec.c +++ b/libavcodec/mjpegdec.c @@ -43,6 +43,7 @@ #include "mjpeg.h" #include "mjpegdec.h" #include "jpeglsdec.h" +#include "profiles.h" #include "put_bits.h" #include "tiff.h" #include "exif.h" @@ -72,34 +73,45 @@ static int build_vlc(VLC *vlc, const uint8_t *bits_table, huff_code, 2, 2, huff_sym, 2, 2, use_static); } -static int build_basic_mjpeg_vlc(MJpegDecodeContext *s) +static int init_default_huffman_tables(MJpegDecodeContext *s) { - int ret; + static const struct { + int class; + int index; + const uint8_t *bits; + const uint8_t *values; + int codes; + int length; + } ht[] = { + { 0, 0, avpriv_mjpeg_bits_dc_luminance, + avpriv_mjpeg_val_dc, 12, 12 }, + { 0, 1, avpriv_mjpeg_bits_dc_chrominance, + avpriv_mjpeg_val_dc, 12, 12 }, + { 1, 0, avpriv_mjpeg_bits_ac_luminance, + avpriv_mjpeg_val_ac_luminance, 251, 162 }, + { 1, 1, avpriv_mjpeg_bits_ac_chrominance, + avpriv_mjpeg_val_ac_chrominance, 251, 162 }, + { 2, 0, avpriv_mjpeg_bits_ac_luminance, + avpriv_mjpeg_val_ac_luminance, 251, 162 }, + { 2, 1, avpriv_mjpeg_bits_ac_chrominance, + avpriv_mjpeg_val_ac_chrominance, 251, 162 }, + }; + int i, ret; - if ((ret = build_vlc(&s->vlcs[0][0], avpriv_mjpeg_bits_dc_luminance, - avpriv_mjpeg_val_dc, 12, 0, 0)) < 0) - return ret; - - if ((ret = build_vlc(&s->vlcs[0][1], avpriv_mjpeg_bits_dc_chrominance, - avpriv_mjpeg_val_dc, 12, 0, 0)) < 0) - return ret; - - if ((ret = build_vlc(&s->vlcs[1][0], avpriv_mjpeg_bits_ac_luminance, - avpriv_mjpeg_val_ac_luminance, 251, 0, 1)) < 0) - return ret; - - if ((ret = build_vlc(&s->vlcs[1][1], avpriv_mjpeg_bits_ac_chrominance, - avpriv_mjpeg_val_ac_chrominance, 251, 0, 1)) < 0) - return ret; - - if ((ret = build_vlc(&s->vlcs[2][0], avpriv_mjpeg_bits_ac_luminance, - avpriv_mjpeg_val_ac_luminance, 251, 0, 0)) < 0) - return ret; - - if ((ret = build_vlc(&s->vlcs[2][1], avpriv_mjpeg_bits_ac_chrominance, - avpriv_mjpeg_val_ac_chrominance, 251, 0, 0)) < 0) - return ret; + for (i = 0; i < FF_ARRAY_ELEMS(ht); i++) { + ret = build_vlc(&s->vlcs[ht[i].class][ht[i].index], + ht[i].bits, ht[i].values, ht[i].codes, + 0, ht[i].class == 1); + if (ret < 0) + return ret; + if (ht[i].class < 2) { + memcpy(s->raw_huffman_lengths[ht[i].class][ht[i].index], + ht[i].bits + 1, 16); + memcpy(s->raw_huffman_values[ht[i].class][ht[i].index], + ht[i].values, ht[i].length); + } + } return 0; } @@ -150,7 +162,7 @@ av_cold int ff_mjpeg_decode_init(AVCodecContext *avctx) avctx->colorspace = AVCOL_SPC_BT470BG; s->hwaccel_pix_fmt = s->hwaccel_sw_pix_fmt = AV_PIX_FMT_NONE; - if ((ret = build_basic_mjpeg_vlc(s)) < 0) + if ((ret = init_default_huffman_tables(s)) < 0) return ret; if (s->extern_huff) { @@ -160,7 +172,7 @@ av_cold int ff_mjpeg_decode_init(AVCodecContext *avctx) if (ff_mjpeg_decode_dht(s)) { av_log(avctx, AV_LOG_ERROR, "error using external huffman table, switching back to internal\n"); - build_basic_mjpeg_vlc(s); + init_default_huffman_tables(s); } } if (avctx->field_order == AV_FIELD_BB) { /* quicktime icefloe 019 */ @@ -301,7 +313,6 @@ int ff_mjpeg_decode_sof(MJpegDecodeContext *s) memset(s->upscale_h, 0, sizeof(s->upscale_h)); memset(s->upscale_v, 0, sizeof(s->upscale_v)); - /* XXX: verify len field validity */ len = get_bits(&s->gb, 16); bits = get_bits(&s->gb, 8); @@ -355,6 +366,11 @@ int ff_mjpeg_decode_sof(MJpegDecodeContext *s) "bits/component or 16-bit gray"); return AVERROR_PATCHWELCOME; } + if (len != 8 + 3 * nb_components) { + av_log(s->avctx, AV_LOG_ERROR, "decode_sof0: error, len(%d) mismatch %d components\n", len, nb_components); + return AVERROR_INVALIDDATA; + } + s->nb_components = nb_components; s->h_max = 1; s->v_max = 1; @@ -437,269 +453,275 @@ int ff_mjpeg_decode_sof(MJpegDecodeContext *s) avpriv_request_sample(s->avctx, "progressively coded interlaced picture"); return AVERROR_INVALIDDATA; } - } else{ + } else { if (s->v_max == 1 && s->h_max == 1 && s->lossless==1 && (nb_components==3 || nb_components==4)) s->rgb = 1; else if (!s->lossless) s->rgb = 0; - /* XXX: not complete test ! */ - pix_fmt_id = ((unsigned)s->h_count[0] << 28) | (s->v_count[0] << 24) | - (s->h_count[1] << 20) | (s->v_count[1] << 16) | - (s->h_count[2] << 12) | (s->v_count[2] << 8) | - (s->h_count[3] << 4) | s->v_count[3]; - av_log(s->avctx, AV_LOG_DEBUG, "pix fmt id %x\n", pix_fmt_id); - /* NOTE we do not allocate pictures large enough for the possible - * padding of h/v_count being 4 */ - if (!(pix_fmt_id & 0xD0D0D0D0)) - pix_fmt_id -= (pix_fmt_id & 0xF0F0F0F0) >> 1; - if (!(pix_fmt_id & 0x0D0D0D0D)) - pix_fmt_id -= (pix_fmt_id & 0x0F0F0F0F) >> 1; + /* XXX: not complete test ! */ + pix_fmt_id = ((unsigned)s->h_count[0] << 28) | (s->v_count[0] << 24) | + (s->h_count[1] << 20) | (s->v_count[1] << 16) | + (s->h_count[2] << 12) | (s->v_count[2] << 8) | + (s->h_count[3] << 4) | s->v_count[3]; + av_log(s->avctx, AV_LOG_DEBUG, "pix fmt id %x\n", pix_fmt_id); + /* NOTE we do not allocate pictures large enough for the possible + * padding of h/v_count being 4 */ + if (!(pix_fmt_id & 0xD0D0D0D0)) + pix_fmt_id -= (pix_fmt_id & 0xF0F0F0F0) >> 1; + if (!(pix_fmt_id & 0x0D0D0D0D)) + pix_fmt_id -= (pix_fmt_id & 0x0F0F0F0F) >> 1; - for (i = 0; i < 8; i++) { - int j = 6 + (i&1) - (i&6); - int is = (pix_fmt_id >> (4*i)) & 0xF; - int js = (pix_fmt_id >> (4*j)) & 0xF; + for (i = 0; i < 8; i++) { + int j = 6 + (i&1) - (i&6); + int is = (pix_fmt_id >> (4*i)) & 0xF; + int js = (pix_fmt_id >> (4*j)) & 0xF; - if (is == 1 && js != 2 && (i < 2 || i > 5)) - js = (pix_fmt_id >> ( 8 + 4*(i&1))) & 0xF; - if (is == 1 && js != 2 && (i < 2 || i > 5)) - js = (pix_fmt_id >> (16 + 4*(i&1))) & 0xF; + if (is == 1 && js != 2 && (i < 2 || i > 5)) + js = (pix_fmt_id >> ( 8 + 4*(i&1))) & 0xF; + if (is == 1 && js != 2 && (i < 2 || i > 5)) + js = (pix_fmt_id >> (16 + 4*(i&1))) & 0xF; - if (is == 1 && js == 2) { - if (i & 1) s->upscale_h[j/2] = 1; - else s->upscale_v[j/2] = 1; - } - } - - switch (pix_fmt_id) { - case 0x11111100: - if (s->rgb) - s->avctx->pix_fmt = s->bits <= 9 ? AV_PIX_FMT_BGR24 : AV_PIX_FMT_BGR48; - else { - if (s->component_id[0] == 'Q' && s->component_id[1] == 'F' && s->component_id[2] == 'A') { - s->avctx->pix_fmt = s->bits <= 8 ? AV_PIX_FMT_GBRP : AV_PIX_FMT_GBRP16; - } else { - if (s->bits <= 8) s->avctx->pix_fmt = s->cs_itu601 ? AV_PIX_FMT_YUV444P : AV_PIX_FMT_YUVJ444P; - else s->avctx->pix_fmt = AV_PIX_FMT_YUV444P16; - s->avctx->color_range = s->cs_itu601 ? AVCOL_RANGE_MPEG : AVCOL_RANGE_JPEG; + if (is == 1 && js == 2) { + if (i & 1) s->upscale_h[j/2] = 1; + else s->upscale_v[j/2] = 1; } } - av_assert0(s->nb_components == 3); - break; - case 0x11111111: - if (s->rgb) - s->avctx->pix_fmt = s->bits <= 9 ? AV_PIX_FMT_ABGR : AV_PIX_FMT_RGBA64; - else { + + switch (pix_fmt_id) { + case 0x11111100: + if (s->rgb) + s->avctx->pix_fmt = s->bits <= 9 ? AV_PIX_FMT_BGR24 : AV_PIX_FMT_BGR48; + else { + if ( s->adobe_transform == 0 + || s->component_id[0] == 'R' - 1 && s->component_id[1] == 'G' - 1 && s->component_id[2] == 'B' - 1) { + s->avctx->pix_fmt = s->bits <= 8 ? AV_PIX_FMT_GBRP : AV_PIX_FMT_GBRP16; + } else { + if (s->bits <= 8) s->avctx->pix_fmt = s->cs_itu601 ? AV_PIX_FMT_YUV444P : AV_PIX_FMT_YUVJ444P; + else s->avctx->pix_fmt = AV_PIX_FMT_YUV444P16; + s->avctx->color_range = s->cs_itu601 ? AVCOL_RANGE_MPEG : AVCOL_RANGE_JPEG; + } + } + av_assert0(s->nb_components == 3); + break; + case 0x11111111: + if (s->rgb) + s->avctx->pix_fmt = s->bits <= 9 ? AV_PIX_FMT_ABGR : AV_PIX_FMT_RGBA64; + else { + if (s->adobe_transform == 0 && s->bits <= 8) { + s->avctx->pix_fmt = AV_PIX_FMT_GBRAP; + } else { + s->avctx->pix_fmt = s->bits <= 8 ? AV_PIX_FMT_YUVA444P : AV_PIX_FMT_YUVA444P16; + s->avctx->color_range = s->cs_itu601 ? AVCOL_RANGE_MPEG : AVCOL_RANGE_JPEG; + } + } + av_assert0(s->nb_components == 4); + break; + case 0x22111122: + case 0x22111111: if (s->adobe_transform == 0 && s->bits <= 8) { s->avctx->pix_fmt = AV_PIX_FMT_GBRAP; + s->upscale_v[1] = s->upscale_v[2] = 1; + s->upscale_h[1] = s->upscale_h[2] = 1; + } else if (s->adobe_transform == 2 && s->bits <= 8) { + s->avctx->pix_fmt = AV_PIX_FMT_YUVA444P; + s->upscale_v[1] = s->upscale_v[2] = 1; + s->upscale_h[1] = s->upscale_h[2] = 1; + s->avctx->color_range = s->cs_itu601 ? AVCOL_RANGE_MPEG : AVCOL_RANGE_JPEG; } else { - s->avctx->pix_fmt = s->bits <= 8 ? AV_PIX_FMT_YUVA444P : AV_PIX_FMT_YUVA444P16; + if (s->bits <= 8) s->avctx->pix_fmt = AV_PIX_FMT_YUVA420P; + else s->avctx->pix_fmt = AV_PIX_FMT_YUVA420P16; s->avctx->color_range = s->cs_itu601 ? AVCOL_RANGE_MPEG : AVCOL_RANGE_JPEG; } - } - av_assert0(s->nb_components == 4); - break; - case 0x22111122: - case 0x22111111: - if (s->adobe_transform == 0 && s->bits <= 8) { - s->avctx->pix_fmt = AV_PIX_FMT_GBRAP; - s->upscale_v[1] = s->upscale_v[2] = 1; - s->upscale_h[1] = s->upscale_h[2] = 1; - } else if (s->adobe_transform == 2 && s->bits <= 8) { - s->avctx->pix_fmt = AV_PIX_FMT_YUVA444P; - s->upscale_v[1] = s->upscale_v[2] = 1; - s->upscale_h[1] = s->upscale_h[2] = 1; - s->avctx->color_range = s->cs_itu601 ? AVCOL_RANGE_MPEG : AVCOL_RANGE_JPEG; - } else { - if (s->bits <= 8) s->avctx->pix_fmt = AV_PIX_FMT_YUVA420P; - else s->avctx->pix_fmt = AV_PIX_FMT_YUVA420P16; - s->avctx->color_range = s->cs_itu601 ? AVCOL_RANGE_MPEG : AVCOL_RANGE_JPEG; - } - av_assert0(s->nb_components == 4); - break; - case 0x12121100: - case 0x22122100: - case 0x21211100: - case 0x22211200: - if (s->bits <= 8) s->avctx->pix_fmt = s->cs_itu601 ? AV_PIX_FMT_YUV444P : AV_PIX_FMT_YUVJ444P; - else - goto unk_pixfmt; - s->avctx->color_range = s->cs_itu601 ? AVCOL_RANGE_MPEG : AVCOL_RANGE_JPEG; - break; - case 0x22221100: - case 0x22112200: - case 0x11222200: - if (s->bits <= 8) s->avctx->pix_fmt = s->cs_itu601 ? AV_PIX_FMT_YUV444P : AV_PIX_FMT_YUVJ444P; - else - goto unk_pixfmt; - s->avctx->color_range = s->cs_itu601 ? AVCOL_RANGE_MPEG : AVCOL_RANGE_JPEG; - break; - case 0x11000000: - case 0x13000000: - case 0x14000000: - case 0x31000000: - case 0x33000000: - case 0x34000000: - case 0x41000000: - case 0x43000000: - case 0x44000000: - if(s->bits <= 8) - s->avctx->pix_fmt = AV_PIX_FMT_GRAY8; - else - s->avctx->pix_fmt = AV_PIX_FMT_GRAY16; - break; - case 0x12111100: - case 0x14121200: - case 0x14111100: - case 0x22211100: - case 0x22112100: - if (s->component_id[0] == 'Q' && s->component_id[1] == 'F' && s->component_id[2] == 'A') { - if (s->bits <= 8) s->avctx->pix_fmt = AV_PIX_FMT_GBRP; - else - goto unk_pixfmt; - s->upscale_v[0] = s->upscale_v[1] = 1; - } else { - if (pix_fmt_id == 0x14111100) - s->upscale_v[1] = s->upscale_v[2] = 1; - if (s->bits <= 8) s->avctx->pix_fmt = s->cs_itu601 ? AV_PIX_FMT_YUV440P : AV_PIX_FMT_YUVJ440P; + av_assert0(s->nb_components == 4); + break; + case 0x12121100: + case 0x22122100: + case 0x21211100: + case 0x22211200: + if (s->bits <= 8) s->avctx->pix_fmt = s->cs_itu601 ? AV_PIX_FMT_YUV444P : AV_PIX_FMT_YUVJ444P; else goto unk_pixfmt; s->avctx->color_range = s->cs_itu601 ? AVCOL_RANGE_MPEG : AVCOL_RANGE_JPEG; - } - break; - case 0x21111100: - if (s->component_id[0] == 'Q' && s->component_id[1] == 'F' && s->component_id[2] == 'A') { - if (s->bits <= 8) s->avctx->pix_fmt = AV_PIX_FMT_GBRP; + break; + case 0x22221100: + case 0x22112200: + case 0x11222200: + if (s->bits <= 8) s->avctx->pix_fmt = s->cs_itu601 ? AV_PIX_FMT_YUV444P : AV_PIX_FMT_YUVJ444P; else goto unk_pixfmt; - s->upscale_h[0] = s->upscale_h[1] = 1; - } else { + s->avctx->color_range = s->cs_itu601 ? AVCOL_RANGE_MPEG : AVCOL_RANGE_JPEG; + break; + case 0x11000000: + case 0x13000000: + case 0x14000000: + case 0x31000000: + case 0x33000000: + case 0x34000000: + case 0x41000000: + case 0x43000000: + case 0x44000000: + if(s->bits <= 8) + s->avctx->pix_fmt = AV_PIX_FMT_GRAY8; + else + s->avctx->pix_fmt = AV_PIX_FMT_GRAY16; + break; + case 0x12111100: + case 0x14121200: + case 0x14111100: + case 0x22211100: + case 0x22112100: + if (s->component_id[0] == 'Q' && s->component_id[1] == 'F' && s->component_id[2] == 'A') { + if (s->bits <= 8) s->avctx->pix_fmt = AV_PIX_FMT_GBRP; + else + goto unk_pixfmt; + s->upscale_v[0] = s->upscale_v[1] = 1; + } else { + if (pix_fmt_id == 0x14111100) + s->upscale_v[1] = s->upscale_v[2] = 1; + if (s->bits <= 8) s->avctx->pix_fmt = s->cs_itu601 ? AV_PIX_FMT_YUV440P : AV_PIX_FMT_YUVJ440P; + else + goto unk_pixfmt; + s->avctx->color_range = s->cs_itu601 ? AVCOL_RANGE_MPEG : AVCOL_RANGE_JPEG; + } + break; + case 0x21111100: + if (s->component_id[0] == 'Q' && s->component_id[1] == 'F' && s->component_id[2] == 'A') { + if (s->bits <= 8) s->avctx->pix_fmt = AV_PIX_FMT_GBRP; + else + goto unk_pixfmt; + s->upscale_h[0] = s->upscale_h[1] = 1; + } else { + if (s->bits <= 8) s->avctx->pix_fmt = s->cs_itu601 ? AV_PIX_FMT_YUV422P : AV_PIX_FMT_YUVJ422P; + else s->avctx->pix_fmt = AV_PIX_FMT_YUV422P16; + s->avctx->color_range = s->cs_itu601 ? AVCOL_RANGE_MPEG : AVCOL_RANGE_JPEG; + } + break; + case 0x31111100: + if (s->bits > 8) + goto unk_pixfmt; + s->avctx->pix_fmt = s->cs_itu601 ? AV_PIX_FMT_YUV444P : AV_PIX_FMT_YUVJ444P; + s->avctx->color_range = s->cs_itu601 ? AVCOL_RANGE_MPEG : AVCOL_RANGE_JPEG; + s->upscale_h[1] = s->upscale_h[2] = 2; + break; + case 0x22121100: + case 0x22111200: if (s->bits <= 8) s->avctx->pix_fmt = s->cs_itu601 ? AV_PIX_FMT_YUV422P : AV_PIX_FMT_YUVJ422P; - else s->avctx->pix_fmt = AV_PIX_FMT_YUV422P16; + else + goto unk_pixfmt; s->avctx->color_range = s->cs_itu601 ? AVCOL_RANGE_MPEG : AVCOL_RANGE_JPEG; - } - break; - case 0x31111100: - if (s->bits > 8) - goto unk_pixfmt; - s->avctx->pix_fmt = s->cs_itu601 ? AV_PIX_FMT_YUV444P : AV_PIX_FMT_YUVJ444P; - s->avctx->color_range = s->cs_itu601 ? AVCOL_RANGE_MPEG : AVCOL_RANGE_JPEG; - s->upscale_h[1] = s->upscale_h[2] = 2; - break; - case 0x22121100: - case 0x22111200: - if (s->bits <= 8) s->avctx->pix_fmt = s->cs_itu601 ? AV_PIX_FMT_YUV422P : AV_PIX_FMT_YUVJ422P; - else - goto unk_pixfmt; - s->avctx->color_range = s->cs_itu601 ? AVCOL_RANGE_MPEG : AVCOL_RANGE_JPEG; - break; - case 0x22111100: - case 0x42111100: - case 0x24111100: - if (s->bits <= 8) s->avctx->pix_fmt = s->cs_itu601 ? AV_PIX_FMT_YUV420P : AV_PIX_FMT_YUVJ420P; - else s->avctx->pix_fmt = AV_PIX_FMT_YUV420P16; - s->avctx->color_range = s->cs_itu601 ? AVCOL_RANGE_MPEG : AVCOL_RANGE_JPEG; - if (pix_fmt_id == 0x42111100) { - if (s->bits > 8) + break; + case 0x22111100: + case 0x23111100: + case 0x42111100: + case 0x24111100: + if (s->bits <= 8) s->avctx->pix_fmt = s->cs_itu601 ? AV_PIX_FMT_YUV420P : AV_PIX_FMT_YUVJ420P; + else s->avctx->pix_fmt = AV_PIX_FMT_YUV420P16; + s->avctx->color_range = s->cs_itu601 ? AVCOL_RANGE_MPEG : AVCOL_RANGE_JPEG; + if (pix_fmt_id == 0x42111100) { + if (s->bits > 8) + goto unk_pixfmt; + s->upscale_h[1] = s->upscale_h[2] = 1; + } else if (pix_fmt_id == 0x24111100) { + if (s->bits > 8) + goto unk_pixfmt; + s->upscale_v[1] = s->upscale_v[2] = 1; + } else if (pix_fmt_id == 0x23111100) { + if (s->bits > 8) + goto unk_pixfmt; + s->upscale_v[1] = s->upscale_v[2] = 2; + } + break; + case 0x41111100: + if (s->bits <= 8) s->avctx->pix_fmt = s->cs_itu601 ? AV_PIX_FMT_YUV411P : AV_PIX_FMT_YUVJ411P; + else goto unk_pixfmt; - s->upscale_h[1] = s->upscale_h[2] = 1; - } else if (pix_fmt_id == 0x24111100) { - if (s->bits > 8) - goto unk_pixfmt; - s->upscale_v[1] = s->upscale_v[2] = 1; - } - break; - case 0x41111100: - if (s->bits <= 8) s->avctx->pix_fmt = s->cs_itu601 ? AV_PIX_FMT_YUV411P : AV_PIX_FMT_YUVJ411P; - else - goto unk_pixfmt; - s->avctx->color_range = s->cs_itu601 ? AVCOL_RANGE_MPEG : AVCOL_RANGE_JPEG; - break; - default: -unk_pixfmt: - avpriv_report_missing_feature(s->avctx, "Pixel format 0x%x bits:%d", pix_fmt_id, s->bits); - memset(s->upscale_h, 0, sizeof(s->upscale_h)); - memset(s->upscale_v, 0, sizeof(s->upscale_v)); - return AVERROR_PATCHWELCOME; - } - if ((AV_RB32(s->upscale_h) || AV_RB32(s->upscale_v)) && s->avctx->lowres) { - avpriv_report_missing_feature(s->avctx, "Lowres for weird subsampling"); - return AVERROR_PATCHWELCOME; - } - if ((AV_RB32(s->upscale_h) || AV_RB32(s->upscale_v)) && s->progressive && s->avctx->pix_fmt == AV_PIX_FMT_GBRP) { - avpriv_report_missing_feature(s->avctx, "progressive for weird subsampling"); - return AVERROR_PATCHWELCOME; - } - if (s->ls) { - memset(s->upscale_h, 0, sizeof(s->upscale_h)); - memset(s->upscale_v, 0, sizeof(s->upscale_v)); - if (s->nb_components == 3) { - s->avctx->pix_fmt = AV_PIX_FMT_RGB24; - } else if (s->nb_components != 1) { - av_log(s->avctx, AV_LOG_ERROR, "Unsupported number of components %d\n", s->nb_components); + s->avctx->color_range = s->cs_itu601 ? AVCOL_RANGE_MPEG : AVCOL_RANGE_JPEG; + break; + default: + unk_pixfmt: + avpriv_report_missing_feature(s->avctx, "Pixel format 0x%x bits:%d", pix_fmt_id, s->bits); + memset(s->upscale_h, 0, sizeof(s->upscale_h)); + memset(s->upscale_v, 0, sizeof(s->upscale_v)); return AVERROR_PATCHWELCOME; - } else if (s->palette_index && s->bits <= 8) - s->avctx->pix_fmt = AV_PIX_FMT_PAL8; - else if (s->bits <= 8) - s->avctx->pix_fmt = AV_PIX_FMT_GRAY8; - else - s->avctx->pix_fmt = AV_PIX_FMT_GRAY16; - } + } + if ((AV_RB32(s->upscale_h) || AV_RB32(s->upscale_v)) && s->avctx->lowres) { + avpriv_report_missing_feature(s->avctx, "Lowres for weird subsampling"); + return AVERROR_PATCHWELCOME; + } + if ((AV_RB32(s->upscale_h) || AV_RB32(s->upscale_v)) && s->progressive && s->avctx->pix_fmt == AV_PIX_FMT_GBRP) { + avpriv_report_missing_feature(s->avctx, "progressive for weird subsampling"); + return AVERROR_PATCHWELCOME; + } + if (s->ls) { + memset(s->upscale_h, 0, sizeof(s->upscale_h)); + memset(s->upscale_v, 0, sizeof(s->upscale_v)); + if (s->nb_components == 3) { + s->avctx->pix_fmt = AV_PIX_FMT_RGB24; + } else if (s->nb_components != 1) { + av_log(s->avctx, AV_LOG_ERROR, "Unsupported number of components %d\n", s->nb_components); + return AVERROR_PATCHWELCOME; + } else if (s->palette_index && s->bits <= 8) + s->avctx->pix_fmt = AV_PIX_FMT_PAL8; + else if (s->bits <= 8) + s->avctx->pix_fmt = AV_PIX_FMT_GRAY8; + else + s->avctx->pix_fmt = AV_PIX_FMT_GRAY16; + } - s->pix_desc = av_pix_fmt_desc_get(s->avctx->pix_fmt); - if (!s->pix_desc) { - av_log(s->avctx, AV_LOG_ERROR, "Could not get a pixel format descriptor.\n"); - return AVERROR_BUG; - } + s->pix_desc = av_pix_fmt_desc_get(s->avctx->pix_fmt); + if (!s->pix_desc) { + av_log(s->avctx, AV_LOG_ERROR, "Could not get a pixel format descriptor.\n"); + return AVERROR_BUG; + } - if (s->avctx->pix_fmt == s->hwaccel_sw_pix_fmt && !size_change) { - s->avctx->pix_fmt = s->hwaccel_pix_fmt; - } else { - enum AVPixelFormat pix_fmts[] = { + if (s->avctx->pix_fmt == s->hwaccel_sw_pix_fmt && !size_change) { + s->avctx->pix_fmt = s->hwaccel_pix_fmt; + } else { + enum AVPixelFormat pix_fmts[] = { #if CONFIG_MJPEG_NVDEC_HWACCEL - AV_PIX_FMT_CUDA, + AV_PIX_FMT_CUDA, #endif #if CONFIG_MJPEG_VAAPI_HWACCEL - AV_PIX_FMT_VAAPI, + AV_PIX_FMT_VAAPI, #endif - s->avctx->pix_fmt, - AV_PIX_FMT_NONE, - }; - s->hwaccel_pix_fmt = ff_get_format(s->avctx, pix_fmts); - if (s->hwaccel_pix_fmt < 0) - return AVERROR(EINVAL); + s->avctx->pix_fmt, + AV_PIX_FMT_NONE, + }; + s->hwaccel_pix_fmt = ff_get_format(s->avctx, pix_fmts); + if (s->hwaccel_pix_fmt < 0) + return AVERROR(EINVAL); - s->hwaccel_sw_pix_fmt = s->avctx->pix_fmt; - s->avctx->pix_fmt = s->hwaccel_pix_fmt; - } + s->hwaccel_sw_pix_fmt = s->avctx->pix_fmt; + s->avctx->pix_fmt = s->hwaccel_pix_fmt; + } - if (s->avctx->skip_frame == AVDISCARD_ALL) { + if (s->avctx->skip_frame == AVDISCARD_ALL) { + s->picture_ptr->pict_type = AV_PICTURE_TYPE_I; + s->picture_ptr->key_frame = 1; + s->got_picture = 1; + return 0; + } + + av_frame_unref(s->picture_ptr); + if (ff_get_buffer(s->avctx, s->picture_ptr, AV_GET_BUFFER_FLAG_REF) < 0) + return -1; s->picture_ptr->pict_type = AV_PICTURE_TYPE_I; s->picture_ptr->key_frame = 1; s->got_picture = 1; - return 0; - } - av_frame_unref(s->picture_ptr); - if (ff_get_buffer(s->avctx, s->picture_ptr, AV_GET_BUFFER_FLAG_REF) < 0) - return -1; - s->picture_ptr->pict_type = AV_PICTURE_TYPE_I; - s->picture_ptr->key_frame = 1; - s->got_picture = 1; + for (i = 0; i < 4; i++) + s->linesize[i] = s->picture_ptr->linesize[i] << s->interlaced; - for (i = 0; i < 4; i++) - s->linesize[i] = s->picture_ptr->linesize[i] << s->interlaced; + ff_dlog(s->avctx, "%d %d %d %d %d %d\n", + s->width, s->height, s->linesize[0], s->linesize[1], + s->interlaced, s->avctx->height); - ff_dlog(s->avctx, "%d %d %d %d %d %d\n", - s->width, s->height, s->linesize[0], s->linesize[1], - s->interlaced, s->avctx->height); - - if (len != (8 + (3 * nb_components))) - av_log(s->avctx, AV_LOG_DEBUG, "decode_sof0: error, len(%d) mismatch\n", len); } if ((s->rgb && !s->lossless && !s->ls) || - (!s->rgb && s->ls && s->nb_components > 1)) { + (!s->rgb && s->ls && s->nb_components > 1) || + (s->avctx->pix_fmt == AV_PIX_FMT_PAL8 && !s->ls) + ) { av_log(s->avctx, AV_LOG_ERROR, "Unsupported coding and pixel format combination\n"); return AVERROR_PATCHWELCOME; } @@ -1600,9 +1622,7 @@ int ff_mjpeg_decode_sos(MJpegDecodeContext *s, const uint8_t *mb_bitmask, s->h_scount[i] = s->h_count[index]; s->v_scount[i] = s->v_count[index]; - if(nb_components == 3 && s->nb_components == 3 && s->avctx->pix_fmt == AV_PIX_FMT_GBR24P) - index = (i+2)%3; - if(nb_components == 1 && s->nb_components == 3 && s->avctx->pix_fmt == AV_PIX_FMT_GBR24P) + if((nb_components == 1 || nb_components == 3) && s->nb_components == 3 && s->avctx->pix_fmt == AV_PIX_FMT_GBR24P) index = (index+2)%3; s->comp_index[i] = index; @@ -1885,6 +1905,7 @@ static int mjpeg_decode_app(MJpegDecodeContext *s) type = get_bits(&s->gb, 8); len -= 4; + av_freep(&s->stereo3d); s->stereo3d = av_stereo3d_alloc(); if (!s->stereo3d) { goto out; @@ -2094,7 +2115,7 @@ static int find_marker(const uint8_t **pbuf_ptr, const uint8_t *buf_end) while (buf_end - buf_ptr > 1) { v = *buf_ptr++; v2 = *buf_ptr; - if ((v == 0xff) && (v2 >= 0xc0) && (v2 <= 0xfe) && buf_ptr < buf_end) { + if ((v == 0xff) && (v2 >= SOF0) && (v2 <= COM) && buf_ptr < buf_end) { val = *buf_ptr++; goto found; } @@ -2159,7 +2180,7 @@ int ff_mjpeg_find_marker(MJpegDecodeContext *s, src--; } - if (x < 0xd0 || x > 0xd7) { + if (x < RST0 || x > RST7) { copy_data_segment(1); if (x) break; @@ -2298,7 +2319,7 @@ int ff_mjpeg_decode_frame(AVCodecContext *avctx, void *data, int *got_frame, av_log(avctx, AV_LOG_DEBUG, "startcode: %X\n", start_code); /* process markers */ - if (start_code >= 0xd0 && start_code <= 0xd7) { + if (start_code >= RST0 && start_code <= RST7) { av_log(avctx, AV_LOG_DEBUG, "restart marker: %d\n", start_code & 0x0f); /* APP fields */ @@ -2530,7 +2551,7 @@ the_end: w = AV_CEIL_RSHIFT(w, hshift); h = AV_CEIL_RSHIFT(h, vshift); } - if (s->upscale_v[p]) + if (s->upscale_v[p] == 1) h = (h+1)>>1; av_assert0(w > 0); for (i = 0; i < h; i++) { @@ -2594,9 +2615,9 @@ the_end: } dst = &((uint8_t *)s->picture_ptr->data[p])[(h - 1) * s->linesize[p]]; for (i = h - 1; i; i--) { - uint8_t *src1 = &((uint8_t *)s->picture_ptr->data[p])[i / 2 * s->linesize[p]]; - uint8_t *src2 = &((uint8_t *)s->picture_ptr->data[p])[(i + 1) / 2 * s->linesize[p]]; - if (src1 == src2 || i == h - 1) { + uint8_t *src1 = &((uint8_t *)s->picture_ptr->data[p])[i * s->upscale_v[p] / (s->upscale_v[p] + 1) * s->linesize[p]]; + uint8_t *src2 = &((uint8_t *)s->picture_ptr->data[p])[(i + 1) * s->upscale_v[p] / (s->upscale_v[p] + 1) * s->linesize[p]]; + if (s->upscale_v[p] != 2 && (src1 == src2 || i == h - 1)) { memcpy(dst, src1, w); } else { for (index = 0; index < w; index++) @@ -2793,6 +2814,7 @@ AVCodec ff_mjpeg_decoder = { .capabilities = AV_CODEC_CAP_DR1, .max_lowres = 3, .priv_class = &mjpegdec_class, + .profiles = NULL_IF_CONFIG_SMALL(ff_mjpeg_profiles), .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE | FF_CODEC_CAP_SKIP_FRAME_FILL_PARAM, .hw_configs = (const AVCodecHWConfigInternal*[]) { diff --git a/libavcodec/mjpegenc.c b/libavcodec/mjpegenc.c index d2fcb8e19..0ea7bd3d1 100644 --- a/libavcodec/mjpegenc.c +++ b/libavcodec/mjpegenc.c @@ -38,6 +38,7 @@ #include "mpegvideo.h" #include "mjpeg.h" #include "mjpegenc.h" +#include "profiles.h" static int alloc_huffman(MpegEncContext *s) { @@ -418,6 +419,7 @@ AVCodec ff_mjpeg_encoder = { AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_NONE }, .priv_class = &mjpeg_class, + .profiles = NULL_IF_CONFIG_SMALL(ff_mjpeg_profiles), }; #endif diff --git a/libavcodec/mlp_parse.c b/libavcodec/mlp_parse.c new file mode 100644 index 000000000..067735303 --- /dev/null +++ b/libavcodec/mlp_parse.c @@ -0,0 +1,215 @@ +/* + * Copyright (c) 2007 Ian Caulfield + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include "libavutil/channel_layout.h" +#include "get_bits.h" +#include "mlp_parse.h" +#include "mlp.h" + +static const uint8_t mlp_quants[16] = { + 16, 20, 24, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const uint8_t mlp_channels[32] = { + 1, 2, 3, 4, 3, 4, 5, 3, 4, 5, 4, 5, 6, 4, 5, 4, + 5, 6, 5, 5, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const uint64_t mlp_layout[32] = { + AV_CH_LAYOUT_MONO, + AV_CH_LAYOUT_STEREO, + AV_CH_LAYOUT_2_1, + AV_CH_LAYOUT_QUAD, + AV_CH_LAYOUT_STEREO|AV_CH_LOW_FREQUENCY, + AV_CH_LAYOUT_2_1|AV_CH_LOW_FREQUENCY, + AV_CH_LAYOUT_QUAD|AV_CH_LOW_FREQUENCY, + AV_CH_LAYOUT_SURROUND, + AV_CH_LAYOUT_4POINT0, + AV_CH_LAYOUT_5POINT0_BACK, + AV_CH_LAYOUT_SURROUND|AV_CH_LOW_FREQUENCY, + AV_CH_LAYOUT_4POINT0|AV_CH_LOW_FREQUENCY, + AV_CH_LAYOUT_5POINT1_BACK, + AV_CH_LAYOUT_4POINT0, + AV_CH_LAYOUT_5POINT0_BACK, + AV_CH_LAYOUT_SURROUND|AV_CH_LOW_FREQUENCY, + AV_CH_LAYOUT_4POINT0|AV_CH_LOW_FREQUENCY, + AV_CH_LAYOUT_5POINT1_BACK, + AV_CH_LAYOUT_QUAD|AV_CH_LOW_FREQUENCY, + AV_CH_LAYOUT_5POINT0_BACK, + AV_CH_LAYOUT_5POINT1_BACK, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +static const uint8_t thd_chancount[13] = { +// LR C LFE LRs LRvh LRc LRrs Cs Ts LRsd LRw Cvh LFE2 + 2, 1, 1, 2, 2, 2, 2, 1, 1, 2, 2, 1, 1 +}; + +static const uint64_t thd_layout[13] = { + AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT, // LR + AV_CH_FRONT_CENTER, // C + AV_CH_LOW_FREQUENCY, // LFE + AV_CH_SIDE_LEFT|AV_CH_SIDE_RIGHT, // LRs + AV_CH_TOP_FRONT_LEFT|AV_CH_TOP_FRONT_RIGHT, // LRvh + AV_CH_FRONT_LEFT_OF_CENTER|AV_CH_FRONT_RIGHT_OF_CENTER, // LRc + AV_CH_BACK_LEFT|AV_CH_BACK_RIGHT, // LRrs + AV_CH_BACK_CENTER, // Cs + AV_CH_TOP_CENTER, // Ts + AV_CH_SURROUND_DIRECT_LEFT|AV_CH_SURROUND_DIRECT_RIGHT, // LRsd + AV_CH_WIDE_LEFT|AV_CH_WIDE_RIGHT, // LRw + AV_CH_TOP_FRONT_CENTER, // Cvh + AV_CH_LOW_FREQUENCY_2, // LFE2 +}; + +static int mlp_samplerate(int in) +{ + if (in == 0xF) + return 0; + + return (in & 8 ? 44100 : 48000) << (in & 7) ; +} + +static int truehd_channels(int chanmap) +{ + int channels = 0, i; + + for (i = 0; i < 13; i++) + channels += thd_chancount[i] * ((chanmap >> i) & 1); + + return channels; +} + +static uint64_t truehd_layout(int chanmap) +{ + int i; + uint64_t layout = 0; + + for (i = 0; i < 13; i++) + layout |= thd_layout[i] * ((chanmap >> i) & 1); + + return layout; +} + +static int mlp_get_major_sync_size(const uint8_t * buf, int bufsize) +{ + int has_extension, extensions = 0; + int size = 28; + if (bufsize < 28) + return -1; + + if (AV_RB32(buf) == 0xf8726fba) { + has_extension = buf[25] & 1; + if (has_extension) { + extensions = buf[26] >> 4; + size += 2 + extensions * 2; + } + } + return size; +} + +/** Read a major sync info header - contains high level information about + * the stream - sample rate, channel arrangement etc. Most of this + * information is not actually necessary for decoding, only for playback. + * gb must be a freshly initialized GetBitContext with no bits read. + */ + +int ff_mlp_read_major_sync(void *log, MLPHeaderInfo *mh, GetBitContext *gb) +{ + int ratebits, channel_arrangement, header_size; + uint16_t checksum; + + av_assert1(get_bits_count(gb) == 0); + + header_size = mlp_get_major_sync_size(gb->buffer, gb->size_in_bits >> 3); + if (header_size < 0 || gb->size_in_bits < header_size << 3) { + av_log(log, AV_LOG_ERROR, "packet too short, unable to read major sync\n"); + return -1; + } + + checksum = ff_mlp_checksum16(gb->buffer, header_size - 2); + if (checksum != AV_RL16(gb->buffer+header_size-2)) { + av_log(log, AV_LOG_ERROR, "major sync info header checksum error\n"); + return AVERROR_INVALIDDATA; + } + + if (get_bits_long(gb, 24) != 0xf8726f) /* Sync words */ + return AVERROR_INVALIDDATA; + + mh->stream_type = get_bits(gb, 8); + mh->header_size = header_size; + + if (mh->stream_type == 0xbb) { + mh->group1_bits = mlp_quants[get_bits(gb, 4)]; + mh->group2_bits = mlp_quants[get_bits(gb, 4)]; + + ratebits = get_bits(gb, 4); + mh->group1_samplerate = mlp_samplerate(ratebits); + mh->group2_samplerate = mlp_samplerate(get_bits(gb, 4)); + + skip_bits(gb, 11); + + mh->channel_arrangement= + channel_arrangement = get_bits(gb, 5); + mh->channels_mlp = mlp_channels[channel_arrangement]; + mh->channel_layout_mlp = mlp_layout[channel_arrangement]; + } else if (mh->stream_type == 0xba) { + mh->group1_bits = 24; // TODO: Is this information actually conveyed anywhere? + mh->group2_bits = 0; + + ratebits = get_bits(gb, 4); + mh->group1_samplerate = mlp_samplerate(ratebits); + mh->group2_samplerate = 0; + + skip_bits(gb, 4); + + mh->channel_modifier_thd_stream0 = get_bits(gb, 2); + mh->channel_modifier_thd_stream1 = get_bits(gb, 2); + + mh->channel_arrangement= + channel_arrangement = get_bits(gb, 5); + mh->channels_thd_stream1 = truehd_channels(channel_arrangement); + mh->channel_layout_thd_stream1 = truehd_layout(channel_arrangement); + + mh->channel_modifier_thd_stream2 = get_bits(gb, 2); + + channel_arrangement = get_bits(gb, 13); + mh->channels_thd_stream2 = truehd_channels(channel_arrangement); + mh->channel_layout_thd_stream2 = truehd_layout(channel_arrangement); + } else + return AVERROR_INVALIDDATA; + + mh->access_unit_size = 40 << (ratebits & 7); + mh->access_unit_size_pow2 = 64 << (ratebits & 7); + + skip_bits_long(gb, 48); + + mh->is_vbr = get_bits1(gb); + + mh->peak_bitrate = (get_bits(gb, 15) * mh->group1_samplerate + 8) >> 4; + + mh->num_substreams = get_bits(gb, 4); + + skip_bits_long(gb, 4 + (header_size - 17) * 8); + + return 0; +} diff --git a/libavcodec/mlp_parse.h b/libavcodec/mlp_parse.h new file mode 100644 index 000000000..c6025d1a1 --- /dev/null +++ b/libavcodec/mlp_parse.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2007 Ian Caulfield + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * 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_MLP_PARSE_H +#define AVCODEC_MLP_PARSE_H + +#include "get_bits.h" + +typedef struct MLPHeaderInfo +{ + int stream_type; ///< 0xBB for MLP, 0xBA for TrueHD + int header_size; ///< Size of the major sync header, in bytes + + int group1_bits; ///< The bit depth of the first substream + int group2_bits; ///< Bit depth of the second substream (MLP only) + + int group1_samplerate; ///< Sample rate of first substream + int group2_samplerate; ///< Sample rate of second substream (MLP only) + + int channel_arrangement; + + int channel_modifier_thd_stream0; ///< Channel modifier for substream 0 of TrueHD streams ("2-channel presentation") + int channel_modifier_thd_stream1; ///< Channel modifier for substream 1 of TrueHD streams ("6-channel presentation") + int channel_modifier_thd_stream2; ///< Channel modifier for substream 2 of TrueHD streams ("8-channel presentation") + + int channels_mlp; ///< Channel count for MLP streams + int channels_thd_stream1; ///< Channel count for substream 1 of TrueHD streams ("6-channel presentation") + int channels_thd_stream2; ///< Channel count for substream 2 of TrueHD streams ("8-channel presentation") + uint64_t channel_layout_mlp; ///< Channel layout for MLP streams + uint64_t channel_layout_thd_stream1; ///< Channel layout for substream 1 of TrueHD streams ("6-channel presentation") + uint64_t channel_layout_thd_stream2; ///< Channel layout for substream 2 of TrueHD streams ("8-channel presentation") + + int access_unit_size; ///< Number of samples per coded frame + int access_unit_size_pow2; ///< Next power of two above number of samples per frame + + int is_vbr; ///< Stream is VBR instead of CBR + int peak_bitrate; ///< Peak bitrate for VBR, actual bitrate (==peak) for CBR + + int num_substreams; ///< Number of substreams within stream +} MLPHeaderInfo; + + +int ff_mlp_read_major_sync(void *log, MLPHeaderInfo *mh, GetBitContext *gb); + +#endif /* AVCODEC_MLP_PARSE_H */ diff --git a/libavcodec/mlp_parser.c b/libavcodec/mlp_parser.c index eb3435b6c..9a076f6a7 100644 --- a/libavcodec/mlp_parser.c +++ b/libavcodec/mlp_parser.c @@ -26,203 +26,12 @@ #include -#include "libavutil/channel_layout.h" -#include "libavutil/crc.h" #include "libavutil/internal.h" #include "get_bits.h" #include "parser.h" -#include "mlp_parser.h" +#include "mlp_parse.h" #include "mlp.h" -static const uint8_t mlp_quants[16] = { - 16, 20, 24, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, -}; - -static const uint8_t mlp_channels[32] = { - 1, 2, 3, 4, 3, 4, 5, 3, 4, 5, 4, 5, 6, 4, 5, 4, - 5, 6, 5, 5, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -}; - -const uint64_t ff_mlp_layout[32] = { - AV_CH_LAYOUT_MONO, - AV_CH_LAYOUT_STEREO, - AV_CH_LAYOUT_2_1, - AV_CH_LAYOUT_QUAD, - AV_CH_LAYOUT_STEREO|AV_CH_LOW_FREQUENCY, - AV_CH_LAYOUT_2_1|AV_CH_LOW_FREQUENCY, - AV_CH_LAYOUT_QUAD|AV_CH_LOW_FREQUENCY, - AV_CH_LAYOUT_SURROUND, - AV_CH_LAYOUT_4POINT0, - AV_CH_LAYOUT_5POINT0_BACK, - AV_CH_LAYOUT_SURROUND|AV_CH_LOW_FREQUENCY, - AV_CH_LAYOUT_4POINT0|AV_CH_LOW_FREQUENCY, - AV_CH_LAYOUT_5POINT1_BACK, - AV_CH_LAYOUT_4POINT0, - AV_CH_LAYOUT_5POINT0_BACK, - AV_CH_LAYOUT_SURROUND|AV_CH_LOW_FREQUENCY, - AV_CH_LAYOUT_4POINT0|AV_CH_LOW_FREQUENCY, - AV_CH_LAYOUT_5POINT1_BACK, - AV_CH_LAYOUT_QUAD|AV_CH_LOW_FREQUENCY, - AV_CH_LAYOUT_5POINT0_BACK, - AV_CH_LAYOUT_5POINT1_BACK, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 -}; - -static const uint8_t thd_chancount[13] = { -// LR C LFE LRs LRvh LRc LRrs Cs Ts LRsd LRw Cvh LFE2 - 2, 1, 1, 2, 2, 2, 2, 1, 1, 2, 2, 1, 1 -}; - -static const uint64_t thd_layout[13] = { - AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT, // LR - AV_CH_FRONT_CENTER, // C - AV_CH_LOW_FREQUENCY, // LFE - AV_CH_SIDE_LEFT|AV_CH_SIDE_RIGHT, // LRs - AV_CH_TOP_FRONT_LEFT|AV_CH_TOP_FRONT_RIGHT, // LRvh - AV_CH_FRONT_LEFT_OF_CENTER|AV_CH_FRONT_RIGHT_OF_CENTER, // LRc - AV_CH_BACK_LEFT|AV_CH_BACK_RIGHT, // LRrs - AV_CH_BACK_CENTER, // Cs - AV_CH_TOP_CENTER, // Ts - AV_CH_SURROUND_DIRECT_LEFT|AV_CH_SURROUND_DIRECT_RIGHT, // LRsd - AV_CH_WIDE_LEFT|AV_CH_WIDE_RIGHT, // LRw - AV_CH_TOP_FRONT_CENTER, // Cvh - AV_CH_LOW_FREQUENCY_2, // LFE2 -}; - -static int mlp_samplerate(int in) -{ - if (in == 0xF) - return 0; - - return (in & 8 ? 44100 : 48000) << (in & 7) ; -} - -static int truehd_channels(int chanmap) -{ - int channels = 0, i; - - for (i = 0; i < 13; i++) - channels += thd_chancount[i] * ((chanmap >> i) & 1); - - return channels; -} - -uint64_t ff_truehd_layout(int chanmap) -{ - int i; - uint64_t layout = 0; - - for (i = 0; i < 13; i++) - layout |= thd_layout[i] * ((chanmap >> i) & 1); - - return layout; -} - -static int mlp_get_major_sync_size(const uint8_t * buf, int bufsize) -{ - int has_extension, extensions = 0; - int size = 28; - if (bufsize < 28) - return -1; - - if (AV_RB32(buf) == 0xf8726fba) { - has_extension = buf[25] & 1; - if (has_extension) { - extensions = buf[26] >> 4; - size += 2 + extensions * 2; - } - } - return size; -} - -/** Read a major sync info header - contains high level information about - * the stream - sample rate, channel arrangement etc. Most of this - * information is not actually necessary for decoding, only for playback. - * gb must be a freshly initialized GetBitContext with no bits read. - */ - -int ff_mlp_read_major_sync(void *log, MLPHeaderInfo *mh, GetBitContext *gb) -{ - int ratebits, channel_arrangement, header_size; - uint16_t checksum; - - av_assert1(get_bits_count(gb) == 0); - - header_size = mlp_get_major_sync_size(gb->buffer, gb->size_in_bits >> 3); - if (header_size < 0 || gb->size_in_bits < header_size << 3) { - av_log(log, AV_LOG_ERROR, "packet too short, unable to read major sync\n"); - return -1; - } - - checksum = ff_mlp_checksum16(gb->buffer, header_size - 2); - if (checksum != AV_RL16(gb->buffer+header_size-2)) { - av_log(log, AV_LOG_ERROR, "major sync info header checksum error\n"); - return AVERROR_INVALIDDATA; - } - - if (get_bits_long(gb, 24) != 0xf8726f) /* Sync words */ - return AVERROR_INVALIDDATA; - - mh->stream_type = get_bits(gb, 8); - mh->header_size = header_size; - - if (mh->stream_type == 0xbb) { - mh->group1_bits = mlp_quants[get_bits(gb, 4)]; - mh->group2_bits = mlp_quants[get_bits(gb, 4)]; - - ratebits = get_bits(gb, 4); - mh->group1_samplerate = mlp_samplerate(ratebits); - mh->group2_samplerate = mlp_samplerate(get_bits(gb, 4)); - - skip_bits(gb, 11); - - mh->channel_arrangement= - channel_arrangement = get_bits(gb, 5); - mh->channels_mlp = mlp_channels[channel_arrangement]; - mh->channel_layout_mlp = ff_mlp_layout[channel_arrangement]; - } else if (mh->stream_type == 0xba) { - mh->group1_bits = 24; // TODO: Is this information actually conveyed anywhere? - mh->group2_bits = 0; - - ratebits = get_bits(gb, 4); - mh->group1_samplerate = mlp_samplerate(ratebits); - mh->group2_samplerate = 0; - - skip_bits(gb, 4); - - mh->channel_modifier_thd_stream0 = get_bits(gb, 2); - mh->channel_modifier_thd_stream1 = get_bits(gb, 2); - - mh->channel_arrangement= - channel_arrangement = get_bits(gb, 5); - mh->channels_thd_stream1 = truehd_channels(channel_arrangement); - mh->channel_layout_thd_stream1 = ff_truehd_layout(channel_arrangement); - - mh->channel_modifier_thd_stream2 = get_bits(gb, 2); - - channel_arrangement = get_bits(gb, 13); - mh->channels_thd_stream2 = truehd_channels(channel_arrangement); - mh->channel_layout_thd_stream2 = ff_truehd_layout(channel_arrangement); - } else - return AVERROR_INVALIDDATA; - - mh->access_unit_size = 40 << (ratebits & 7); - mh->access_unit_size_pow2 = 64 << (ratebits & 7); - - skip_bits_long(gb, 48); - - mh->is_vbr = get_bits1(gb); - - mh->peak_bitrate = (get_bits(gb, 15) * mh->group1_samplerate + 8) >> 4; - - mh->num_substreams = get_bits(gb, 4); - - skip_bits_long(gb, 4 + (header_size - 17) * 8); - - return 0; -} - typedef struct MLPParseContext { ParseContext pc; diff --git a/libavcodec/mlpdec.c b/libavcodec/mlpdec.c index 3139a0172..39c40914c 100644 --- a/libavcodec/mlpdec.c +++ b/libavcodec/mlpdec.c @@ -34,7 +34,7 @@ #include "internal.h" #include "libavutil/crc.h" #include "parser.h" -#include "mlp_parser.h" +#include "mlp_parse.h" #include "mlpdsp.h" #include "mlp.h" #include "config.h" diff --git a/libavcodec/mlpenc.c b/libavcodec/mlpenc.c index 7536d3b2f..deb171645 100644 --- a/libavcodec/mlpenc.c +++ b/libavcodec/mlpenc.c @@ -2232,10 +2232,8 @@ static int mlp_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, return 1; /* add current frame to queue */ - if (frame) { - if ((ret = ff_af_queue_add(&ctx->afq, frame)) < 0) - return ret; - } + if ((ret = ff_af_queue_add(&ctx->afq, frame)) < 0) + return ret; data = frame->data[0]; diff --git a/libavcodec/motion_est.c b/libavcodec/motion_est.c index 8b5ce2117..759eea479 100644 --- a/libavcodec/motion_est.c +++ b/libavcodec/motion_est.c @@ -633,7 +633,7 @@ static inline int h263_mv4_search(MpegEncContext *s, int mx, int my, int shift) if(P[i][1] > (c->ymax<ymax<p_mv_table, (1<<16)>>shift); + dmin4 = epzs_motion_search2(s, &mx4, &my4, P, block, block, s->p_mv_table, (1<<16)>>shift, 1); dmin4= c->sub_motion_search(s, &mx4, &my4, dmin4, block, block, size, h); @@ -795,7 +795,7 @@ static int interlaced_search(MpegEncContext *s, int ref_index, P_MV1[0]= mx; //FIXME not correct if block != field_select P_MV1[1]= my / 2; - dmin = epzs_motion_search2(s, &mx_i, &my_i, P, block, field_select+ref_index, mv_table, (1<<16)>>1); + dmin = epzs_motion_search2(s, &mx_i, &my_i, P, block, field_select+ref_index, mv_table, (1<<16)>>1, 0); dmin= c->sub_motion_search(s, &mx_i, &my_i, dmin, block, field_select+ref_index, size, h); diff --git a/libavcodec/motion_est_template.c b/libavcodec/motion_est_template.c index 0c21bbfe1..014038e54 100644 --- a/libavcodec/motion_est_template.c +++ b/libavcodec/motion_est_template.c @@ -989,76 +989,16 @@ int ff_epzs_motion_search(MpegEncContext *s, int *mx_ptr, int *my_ptr, } } -static int epzs_motion_search4(MpegEncContext * s, - int *mx_ptr, int *my_ptr, int P[10][2], - int src_index, int ref_index, int16_t (*last_mv)[2], - int ref_mv_scale) -{ - MotionEstContext * const c= &s->me; - int best[2]={0, 0}; - int d, dmin; - unsigned map_generation; - const int penalty_factor= c->penalty_factor; - const int size=1; - const int h=8; - const int ref_mv_stride= s->mb_stride; - const int ref_mv_xy= s->mb_x + s->mb_y *ref_mv_stride; - me_cmp_func cmpf, chroma_cmpf; - LOAD_COMMON - int flags= c->flags; - LOAD_COMMON2 - - cmpf = s->mecc.me_cmp[size]; - chroma_cmpf = s->mecc.me_cmp[size + 1]; - - map_generation= update_map_generation(c); - - dmin = 1000000; - - /* first line */ - if (s->first_slice_line) { - CHECK_MV(P_LEFT[0]>>shift, P_LEFT[1]>>shift) - CHECK_CLIPPED_MV((last_mv[ref_mv_xy][0]*ref_mv_scale + (1<<15))>>16, - (last_mv[ref_mv_xy][1]*ref_mv_scale + (1<<15))>>16) - CHECK_MV(P_MV1[0]>>shift, P_MV1[1]>>shift) - }else{ - CHECK_MV(P_MV1[0]>>shift, P_MV1[1]>>shift) - //FIXME try some early stop - CHECK_MV(P_MEDIAN[0]>>shift, P_MEDIAN[1]>>shift) - CHECK_MV(P_LEFT[0]>>shift, P_LEFT[1]>>shift) - CHECK_MV(P_TOP[0]>>shift, P_TOP[1]>>shift) - CHECK_MV(P_TOPRIGHT[0]>>shift, P_TOPRIGHT[1]>>shift) - CHECK_CLIPPED_MV((last_mv[ref_mv_xy][0]*ref_mv_scale + (1<<15))>>16, - (last_mv[ref_mv_xy][1]*ref_mv_scale + (1<<15))>>16) - } - if(dmin>64*4){ - CHECK_CLIPPED_MV((last_mv[ref_mv_xy+1][0]*ref_mv_scale + (1<<15))>>16, - (last_mv[ref_mv_xy+1][1]*ref_mv_scale + (1<<15))>>16) - if(s->mb_y+1end_mb_y) //FIXME replace at least with last_slice_line - CHECK_CLIPPED_MV((last_mv[ref_mv_xy+ref_mv_stride][0]*ref_mv_scale + (1<<15))>>16, - (last_mv[ref_mv_xy+ref_mv_stride][1]*ref_mv_scale + (1<<15))>>16) - } - - dmin= diamond_search(s, best, dmin, src_index, ref_index, penalty_factor, size, h, flags); - - *mx_ptr= best[0]; - *my_ptr= best[1]; - - return dmin; -} - -//try to merge with above FIXME (needs PSNR test) static int epzs_motion_search2(MpegEncContext * s, int *mx_ptr, int *my_ptr, int P[10][2], int src_index, int ref_index, int16_t (*last_mv)[2], - int ref_mv_scale) + int ref_mv_scale, const int size) { MotionEstContext * const c= &s->me; int best[2]={0, 0}; int d, dmin; unsigned map_generation; const int penalty_factor= c->penalty_factor; - const int size=0; //FIXME pass as arg const int h=8; const int ref_mv_stride= s->mb_stride; const int ref_mv_xy= s->mb_x + s->mb_y *ref_mv_stride; diff --git a/libavcodec/motionpixels.c b/libavcodec/motionpixels.c index a88b837b3..73977664a 100644 --- a/libavcodec/motionpixels.c +++ b/libavcodec/motionpixels.c @@ -201,6 +201,8 @@ static int mp_get_vlc(MotionPixelsContext *mp, GetBitContext *gb) int i; i = (mp->codes_count == 1) ? 0 : get_vlc2(gb, mp->vlc.table, mp->max_codes_bits, 1); + if (i < 0) + return i; return mp->codes[i].delta; } diff --git a/libavcodec/movsub_bsf.c b/libavcodec/movsub_bsf.c index 587860706..cd48aa7bb 100644 --- a/libavcodec/movsub_bsf.c +++ b/libavcodec/movsub_bsf.c @@ -75,8 +75,8 @@ static int mov2textsub(AVBSFContext *ctx, AVPacket *pkt) return AVERROR_INVALIDDATA; } - pkt->data += 2; pkt->size = FFMIN(pkt->size - 2, AV_RB16(pkt->data)); + pkt->data += 2; return 0; } diff --git a/libavcodec/mpc8.c b/libavcodec/mpc8.c index 3be2f79a5..03838a935 100644 --- a/libavcodec/mpc8.c +++ b/libavcodec/mpc8.c @@ -62,7 +62,7 @@ static inline int mpc8_dec_enum(GetBitContext *gb, int k, int n) do { n--; if (code >= C[n]) { - bits |= 1 << n; + bits |= 1U << n; code -= C[n]; C -= 32; k--; @@ -364,8 +364,9 @@ static int mpc8_decode_frame(AVCodecContext * avctx, void *data, for(j = 0; j < SAMPLES_PER_BAND; j += SAMPLES_PER_BAND / 2){ cnt = get_vlc2(gb, q1_vlc.table, MPC8_Q1_BITS, 2); t = mpc8_get_mask(gb, 18, cnt); - for(k = 0; k < SAMPLES_PER_BAND / 2; k++, t <<= 1) - c->Q[ch][off + j + k] = (t & 0x20000) ? (get_bits1(gb) << 1) - 1 : 0; + for(k = 0; k < SAMPLES_PER_BAND / 2; k++) + c->Q[ch][off + j + k] = t & (1 << (SAMPLES_PER_BAND / 2 - k - 1)) + ? (get_bits1(gb) << 1) - 1 : 0; } break; case 2: diff --git a/libavcodec/mpeg12enc.c b/libavcodec/mpeg12enc.c index d0b458e34..2bc5289d6 100644 --- a/libavcodec/mpeg12enc.c +++ b/libavcodec/mpeg12enc.c @@ -61,6 +61,8 @@ static uint32_t mpeg1_chr_dc_uni[512]; static uint8_t mpeg1_index_run[2][64]; static int8_t mpeg1_max_level[2][64]; +#define A53_MAX_CC_COUNT 0x1f + static av_cold void init_uni_ac_vlc(RLTable *rl, uint8_t *uni_ac_vlc_len) { int i; @@ -544,6 +546,36 @@ void ff_mpeg1_encode_picture_header(MpegEncContext *s, int picture_number) } } + if (s->codec_id == AV_CODEC_ID_MPEG2VIDEO && s->a53_cc) { + side_data = av_frame_get_side_data(s->current_picture_ptr->f, + AV_FRAME_DATA_A53_CC); + if (side_data) { + if (side_data->size <= A53_MAX_CC_COUNT * 3 && side_data->size % 3 == 0) { + int i = 0; + + put_header (s, USER_START_CODE); + + put_bits(&s->pb, 8, 'G'); // user_identifier + put_bits(&s->pb, 8, 'A'); + put_bits(&s->pb, 8, '9'); + put_bits(&s->pb, 8, '4'); + put_bits(&s->pb, 8, 3); // user_data_type_code + put_bits(&s->pb, 8, + (side_data->size / 3 & A53_MAX_CC_COUNT) | 0x40); // flags, cc_count + put_bits(&s->pb, 8, 0xff); // em_data + + for (i = 0; i < side_data->size; i++) + put_bits(&s->pb, 8, side_data->data[i]); + + put_bits(&s->pb, 8, 0xff); // marker_bits + } else { + av_log(s->avctx, AV_LOG_WARNING, + "Warning Closed Caption size (%d) can not exceed 93 bytes " + "and must be a multiple of 3\n", side_data->size); + } + } + } + s->mb_y = 0; ff_mpeg1_encode_slice_header(s); } diff --git a/libavcodec/mpeg2_metadata_bsf.c b/libavcodec/mpeg2_metadata_bsf.c index e787cb378..6779ffd4c 100644 --- a/libavcodec/mpeg2_metadata_bsf.c +++ b/libavcodec/mpeg2_metadata_bsf.c @@ -53,7 +53,7 @@ static int mpeg2_metadata_update_fragment(AVBSFContext *bsf, MPEG2RawSequenceHeader *sh = NULL; MPEG2RawSequenceExtension *se = NULL; MPEG2RawSequenceDisplayExtension *sde = NULL; - int i, se_pos, add_sde = 0; + int i, se_pos; for (i = 0; i < frag->nb_units; i++) { if (frag->units[i].type == MPEG2_START_SEQUENCE_HEADER) { @@ -115,7 +115,7 @@ static int mpeg2_metadata_update_fragment(AVBSFContext *bsf, ctx->transfer_characteristics >= 0 || ctx->matrix_coefficients >= 0) { if (!sde) { - add_sde = 1; + int err; ctx->sequence_display_extension.extension_start_code = MPEG2_START_EXTENSION; ctx->sequence_display_extension.extension_start_code_identifier = @@ -135,6 +135,16 @@ static int mpeg2_metadata_update_fragment(AVBSFContext *bsf, .display_vertical_size = se->vertical_size_extension << 12 | sh->vertical_size_value, }; + + err = ff_cbs_insert_unit_content(ctx->cbc, frag, se_pos + 1, + MPEG2_START_EXTENSION, + &ctx->sequence_display_extension, + NULL); + if (err < 0) { + av_log(bsf, AV_LOG_ERROR, "Failed to insert new sequence " + "display extension.\n"); + return err; + } } if (ctx->video_format >= 0) @@ -147,50 +157,29 @@ static int mpeg2_metadata_update_fragment(AVBSFContext *bsf, if (ctx->colour_primaries >= 0) sde->colour_primaries = ctx->colour_primaries; - else if (add_sde) - sde->colour_primaries = 2; if (ctx->transfer_characteristics >= 0) sde->transfer_characteristics = ctx->transfer_characteristics; - else if (add_sde) - sde->transfer_characteristics = 2; if (ctx->matrix_coefficients >= 0) sde->matrix_coefficients = ctx->matrix_coefficients; - else if (add_sde) - sde->matrix_coefficients = 2; - } - } - - if (add_sde) { - int err; - - err = ff_cbs_insert_unit_content(ctx->cbc, frag, se_pos + 1, - MPEG2_START_EXTENSION, - &ctx->sequence_display_extension, - NULL); - if (err < 0) { - av_log(bsf, AV_LOG_ERROR, "Failed to insert new sequence " - "display extension.\n"); - return err; } } return 0; } -static int mpeg2_metadata_filter(AVBSFContext *bsf, AVPacket *out) +static int mpeg2_metadata_filter(AVBSFContext *bsf, AVPacket *pkt) { MPEG2MetadataContext *ctx = bsf->priv_data; - AVPacket *in = NULL; CodedBitstreamFragment *frag = &ctx->fragment; int err; - err = ff_bsf_get_packet(bsf, &in); + err = ff_bsf_get_packet_ref(bsf, pkt); if (err < 0) return err; - err = ff_cbs_read_packet(ctx->cbc, frag, in); + err = ff_cbs_read_packet(ctx->cbc, frag, pkt); if (err < 0) { av_log(bsf, AV_LOG_ERROR, "Failed to read packet.\n"); goto fail; @@ -202,23 +191,18 @@ static int mpeg2_metadata_filter(AVBSFContext *bsf, AVPacket *out) goto fail; } - err = ff_cbs_write_packet(ctx->cbc, out, frag); + err = ff_cbs_write_packet(ctx->cbc, pkt, frag); if (err < 0) { av_log(bsf, AV_LOG_ERROR, "Failed to write packet.\n"); goto fail; } - err = av_packet_copy_props(out, in); - if (err < 0) - goto fail; - err = 0; fail: - ff_cbs_fragment_uninit(ctx->cbc, frag); + ff_cbs_fragment_reset(ctx->cbc, frag); if (err < 0) - av_packet_unref(out); - av_packet_free(&in); + av_packet_unref(pkt); return err; } @@ -255,13 +239,15 @@ static int mpeg2_metadata_init(AVBSFContext *bsf) err = 0; fail: - ff_cbs_fragment_uninit(ctx->cbc, frag); + ff_cbs_fragment_reset(ctx->cbc, frag); return err; } static void mpeg2_metadata_close(AVBSFContext *bsf) { MPEG2MetadataContext *ctx = bsf->priv_data; + + ff_cbs_fragment_free(ctx->cbc, &ctx->fragment); ff_cbs_close(&ctx->cbc); } diff --git a/libavcodec/mpeg4_unpack_bframes_bsf.c b/libavcodec/mpeg4_unpack_bframes_bsf.c index 3a0ba105f..1daf133ce 100644 --- a/libavcodec/mpeg4_unpack_bframes_bsf.c +++ b/libavcodec/mpeg4_unpack_bframes_bsf.c @@ -21,68 +21,41 @@ #include "avcodec.h" #include "bsf.h" +#include "internal.h" #include "mpeg4video.h" typedef struct UnpackBFramesBSFContext { - uint8_t *b_frame_buf; - int b_frame_buf_size; + AVPacket *b_frame; } UnpackBFramesBSFContext; -/* search next start code */ -static unsigned int find_startcode(const uint8_t *buf, int buf_size, int *pos) -{ - unsigned int startcode = 0xFF; - - for (; *pos < buf_size;) { - startcode = ((startcode << 8) | buf[*pos]) & 0xFFFFFFFF; - *pos +=1; - if ((startcode & 0xFFFFFF00) != 0x100) - continue; /* no startcode */ - return startcode; - } - - return 0; -} - /* determine the position of the packed marker in the userdata, * the number of VOPs and the position of the second VOP */ static void scan_buffer(const uint8_t *buf, int buf_size, int *pos_p, int *nb_vop, int *pos_vop2) { - unsigned int startcode; - int pos, i; + uint32_t startcode; + const uint8_t *end = buf + buf_size, *pos = buf; - for (pos = 0; pos < buf_size;) { - startcode = find_startcode(buf, buf_size, &pos); + while (pos < end) { + startcode = -1; + pos = avpriv_find_start_code(pos, end, &startcode); if (startcode == USER_DATA_STARTCODE && pos_p) { /* check if the (DivX) userdata string ends with 'p' (packed) */ - for (i = 0; i < 255 && pos + i + 1 < buf_size; i++) { - if (buf[pos + i] == 'p' && buf[pos + i + 1] == '\0') { - *pos_p = pos + i; + for (int i = 0; i < 255 && pos + i + 1 < end; i++) { + if (pos[i] == 'p' && pos[i + 1] == '\0') { + *pos_p = pos + i - buf; break; } } } else if (startcode == VOP_STARTCODE && nb_vop) { *nb_vop += 1; if (*nb_vop == 2 && pos_vop2) { - *pos_vop2 = pos - 4; /* subtract 4 bytes startcode */ + *pos_vop2 = pos - buf - 4; /* subtract 4 bytes startcode */ } } } } -/* allocate new buffer and copy size bytes from src */ -static uint8_t *create_new_buffer(const uint8_t *src, int size) { - uint8_t *dst = av_malloc(size + AV_INPUT_BUFFER_PADDING_SIZE); - - if (dst) { - memcpy(dst, src, size); - memset(dst + size, 0, AV_INPUT_BUFFER_PADDING_SIZE); - } - - return dst; -} - static int mpeg4_unpack_bframes_filter(AVBSFContext *ctx, AVPacket *out) { UnpackBFramesBSFContext *s = ctx->priv_data; @@ -97,20 +70,18 @@ static int mpeg4_unpack_bframes_filter(AVBSFContext *ctx, AVPacket *out) av_log(ctx, AV_LOG_DEBUG, "Found %d VOP startcode(s) in this packet.\n", nb_vop); if (pos_vop2 >= 0) { - if (s->b_frame_buf) { + if (s->b_frame->data) { av_log(ctx, AV_LOG_WARNING, "Missing one N-VOP packet, discarding one B-frame.\n"); - av_freep(&s->b_frame_buf); - s->b_frame_buf_size = 0; + av_packet_unref(s->b_frame); } /* store the packed B-frame in the BSFContext */ - s->b_frame_buf_size = in->size - pos_vop2; - s->b_frame_buf = create_new_buffer(in->data + pos_vop2, s->b_frame_buf_size); - if (!s->b_frame_buf) { - s->b_frame_buf_size = 0; - ret = AVERROR(ENOMEM); + ret = av_packet_ref(s->b_frame, in); + if (ret < 0) { goto fail; } + s->b_frame->size -= pos_vop2; + s->b_frame->data += pos_vop2; } if (nb_vop > 2) { @@ -118,31 +89,22 @@ static int mpeg4_unpack_bframes_filter(AVBSFContext *ctx, AVPacket *out) "Found %d VOP headers in one packet, only unpacking one.\n", nb_vop); } - if (nb_vop == 1 && s->b_frame_buf) { + if (nb_vop == 1 && s->b_frame->data) { /* use frame from BSFContext */ + av_packet_move_ref(out, s->b_frame); + + /* use properties from current input packet */ ret = av_packet_copy_props(out, in); if (ret < 0) { goto fail; } - ret = av_packet_from_data(out, s->b_frame_buf, s->b_frame_buf_size); - if (ret < 0) { - goto fail; - } if (in->size <= MAX_NVOP_SIZE) { /* N-VOP */ av_log(ctx, AV_LOG_DEBUG, "Skipping N-VOP.\n"); - s->b_frame_buf = NULL; - s->b_frame_buf_size = 0; } else { /* copy packet into BSFContext */ - s->b_frame_buf_size = in->size; - s->b_frame_buf = create_new_buffer(in->data, in->size); - if (!s->b_frame_buf) { - s->b_frame_buf_size = 0; - ret = AVERROR(ENOMEM); - goto fail; - } + av_packet_move_ref(s->b_frame, in); } } else if (nb_vop >= 2) { /* use first frame of the packet */ @@ -171,6 +133,12 @@ fail: static int mpeg4_unpack_bframes_init(AVBSFContext *ctx) { + UnpackBFramesBSFContext *s = ctx->priv_data; + + s->b_frame = av_packet_alloc(); + if (!s->b_frame) + return AVERROR(ENOMEM); + if (ctx->par_in->extradata) { int pos_p_ext = -1; scan_buffer(ctx->par_in->extradata, ctx->par_in->extradata_size, &pos_p_ext, NULL, NULL); @@ -184,10 +152,16 @@ static int mpeg4_unpack_bframes_init(AVBSFContext *ctx) return 0; } +static void mpeg4_unpack_bframes_flush(AVBSFContext *bsfc) +{ + UnpackBFramesBSFContext *ctx = bsfc->priv_data; + av_packet_unref(ctx->b_frame); +} + static void mpeg4_unpack_bframes_close(AVBSFContext *bsfc) { UnpackBFramesBSFContext *ctx = bsfc->priv_data; - av_freep(&ctx->b_frame_buf); + av_packet_free(&ctx->b_frame); } static const enum AVCodecID codec_ids[] = { @@ -199,6 +173,7 @@ const AVBitStreamFilter ff_mpeg4_unpack_bframes_bsf = { .priv_data_size = sizeof(UnpackBFramesBSFContext), .init = mpeg4_unpack_bframes_init, .filter = mpeg4_unpack_bframes_filter, + .flush = mpeg4_unpack_bframes_flush, .close = mpeg4_unpack_bframes_close, .codec_ids = codec_ids, }; diff --git a/libavcodec/mpeg4video.h b/libavcodec/mpeg4video.h index dd0a59038..1a5da3192 100644 --- a/libavcodec/mpeg4video.h +++ b/libavcodec/mpeg4video.h @@ -163,7 +163,7 @@ void ff_mpeg4_pred_ac(MpegEncContext *s, int16_t *block, int n, void ff_set_mpeg4_time(MpegEncContext *s); int ff_mpeg4_encode_picture_header(MpegEncContext *s, int picture_number); -int ff_mpeg4_decode_picture_header(Mpeg4DecContext *ctx, GetBitContext *gb); +int ff_mpeg4_decode_picture_header(Mpeg4DecContext *ctx, GetBitContext *gb, int header); void ff_mpeg4_encode_video_packet_header(MpegEncContext *s); void ff_mpeg4_clean_buffers(MpegEncContext *s); void ff_mpeg4_stuffing(PutBitContext *pbc); diff --git a/libavcodec/mpeg4video_parser.c b/libavcodec/mpeg4video_parser.c index 9ebb09a63..9ca0f1497 100644 --- a/libavcodec/mpeg4video_parser.c +++ b/libavcodec/mpeg4video_parser.c @@ -89,13 +89,13 @@ static int mpeg4_decode_header(AVCodecParserContext *s1, AVCodecContext *avctx, if (avctx->extradata_size && pc->first_picture) { init_get_bits(gb, avctx->extradata, avctx->extradata_size * 8); - ret = ff_mpeg4_decode_picture_header(dec_ctx, gb); - if (ret < -1) + ret = ff_mpeg4_decode_picture_header(dec_ctx, gb, 1); + if (ret < 0) av_log(avctx, AV_LOG_WARNING, "Failed to parse extradata\n"); } init_get_bits(gb, buf, 8 * buf_size); - ret = ff_mpeg4_decode_picture_header(dec_ctx, gb); + ret = ff_mpeg4_decode_picture_header(dec_ctx, gb, 0); if (s->width && (!avctx->width || !avctx->height || !avctx->coded_width || !avctx->coded_height)) { ret = ff_set_dimensions(avctx, s->width, s->height); diff --git a/libavcodec/mpeg4videodec.c b/libavcodec/mpeg4videodec.c index c9823807b..b6f2ae7b7 100644 --- a/libavcodec/mpeg4videodec.c +++ b/libavcodec/mpeg4videodec.c @@ -24,6 +24,7 @@ #include "libavutil/internal.h" #include "libavutil/opt.h" +#include "libavutil/pixdesc.h" #include "error_resilience.h" #include "hwaccel.h" #include "idctdsp.h" @@ -36,6 +37,7 @@ #include "profiles.h" #include "thread.h" #include "xvididct.h" +#include "unary.h" /* The defines below define the number of bits that are read at once for * reading vlc values. Changing these may improve speed and data cache needs @@ -1929,10 +1931,95 @@ static int mpeg4_decode_studio_block(MpegEncContext *s, int32_t block[64], int n return 0; } +static int mpeg4_decode_dpcm_macroblock(MpegEncContext *s, int16_t macroblock[256], int n) +{ + int i, j, w, h, idx = 0; + int block_mean, rice_parameter, rice_prefix_code, rice_suffix_code, + dpcm_residual, left, top, topleft, min_left_top, max_left_top, p, p2, output; + h = 16 >> (n ? s->chroma_y_shift : 0); + w = 16 >> (n ? s->chroma_x_shift : 0); + + block_mean = get_bits(&s->gb, s->avctx->bits_per_raw_sample); + if (block_mean == 0){ + av_log(s->avctx, AV_LOG_ERROR, "Forbidden block_mean\n"); + return AVERROR_INVALIDDATA; + } + s->last_dc[n] = block_mean * (1 << (s->dct_precision + s->intra_dc_precision)); + + rice_parameter = get_bits(&s->gb, 4); + if (rice_parameter == 0) { + av_log(s->avctx, AV_LOG_ERROR, "Forbidden rice_parameter\n"); + return AVERROR_INVALIDDATA; + } + + if (rice_parameter == 15) + rice_parameter = 0; + + if (rice_parameter > 11) { + av_log(s->avctx, AV_LOG_ERROR, "Forbidden rice_parameter\n"); + return AVERROR_INVALIDDATA; + } + + for (i = 0; i < h; i++) { + output = 1 << (s->avctx->bits_per_raw_sample - 1); + top = 1 << (s->avctx->bits_per_raw_sample - 1); + + for (j = 0; j < w; j++) { + left = output; + topleft = top; + + rice_prefix_code = get_unary(&s->gb, 1, 12); + + /* Escape */ + if (rice_prefix_code == 11) + dpcm_residual = get_bits(&s->gb, s->avctx->bits_per_raw_sample); + else { + if (rice_prefix_code == 12) { + av_log(s->avctx, AV_LOG_ERROR, "Forbidden rice_prefix_code\n"); + return AVERROR_INVALIDDATA; + } + rice_suffix_code = get_bitsz(&s->gb, rice_parameter); + dpcm_residual = (rice_prefix_code << rice_parameter) + rice_suffix_code; + } + + /* Map to a signed residual */ + if (dpcm_residual & 1) + dpcm_residual = (-1 * dpcm_residual) >> 1; + else + dpcm_residual = (dpcm_residual >> 1); + + if (i != 0) + top = macroblock[idx-w]; + + p = left + top - topleft; + min_left_top = FFMIN(left, top); + if (p < min_left_top) + p = min_left_top; + + max_left_top = FFMAX(left, top); + if (p > max_left_top) + p = max_left_top; + + p2 = (FFMIN(min_left_top, topleft) + FFMAX(max_left_top, topleft)) >> 1; + if (p2 == p) + p2 = block_mean; + + if (p2 > p) + dpcm_residual *= -1; + + macroblock[idx++] = output = (dpcm_residual + p) & ((1 << s->avctx->bits_per_raw_sample) - 1); + } + } + + return 0; +} + static int mpeg4_decode_studio_mb(MpegEncContext *s, int16_t block_[12][64]) { int i; + s->dpcm_direction = 0; + /* StudioMacroblock */ /* Assumes I-VOP */ s->mb_intra = 1; @@ -1951,9 +2038,11 @@ static int mpeg4_decode_studio_mb(MpegEncContext *s, int16_t block_[12][64]) } else { /* DPCM */ check_marker(s->avctx, &s->gb, "DPCM block start"); - avpriv_request_sample(s->avctx, "DPCM encoded block"); - next_start_code_studio(&s->gb); - return SLICE_ERROR; + s->dpcm_direction = get_bits1(&s->gb) ? -1 : 1; + for (i = 0; i < 3; i++) { + if (mpeg4_decode_dpcm_macroblock(s, (*s->dpcm_macroblock)[i], i) < 0) + return AVERROR_INVALIDDATA; + } } if (get_bits_left(&s->gb) >= 24 && show_bits(&s->gb, 23) == 0) { @@ -3120,11 +3209,13 @@ static int decode_studio_vol_header(Mpeg4DecContext *ctx, GetBitContext *gb) /** * Decode MPEG-4 headers. - * @return <0 if no VOP found (or a damaged one) + * + * @param header If set the absence of a VOP is not treated as error; otherwise, it is treated as such. + * @return <0 if an error occured * FRAME_SKIPPED if a not coded VOP is found - * 0 if a VOP is found + * 0 else */ -int ff_mpeg4_decode_picture_header(Mpeg4DecContext *ctx, GetBitContext *gb) +int ff_mpeg4_decode_picture_header(Mpeg4DecContext *ctx, GetBitContext *gb, int header) { MpegEncContext *s = &ctx->m; unsigned startcode, v; @@ -3153,6 +3244,8 @@ int ff_mpeg4_decode_picture_header(Mpeg4DecContext *ctx, GetBitContext *gb) (ctx->divx_version >= 0 || ctx->xvid_build >= 0) || s->codec_tag == AV_RL32("QMP4")) { av_log(s->avctx, AV_LOG_VERBOSE, "frame skip %d\n", gb->size_in_bits); return FRAME_SKIPPED; // divx bug + } else if (header && get_bits_count(gb) == gb->size_in_bits) { + return 0; // ordinary return value for parsing of extradata } else return AVERROR_INVALIDDATA; // end of stream } diff --git a/libavcodec/mpeg_er.c b/libavcodec/mpeg_er.c index ada1a1692..f54cb8548 100644 --- a/libavcodec/mpeg_er.c +++ b/libavcodec/mpeg_er.c @@ -78,6 +78,8 @@ static void mpeg_er_decode_mb(void *opaque, int ref, int mv_dir, int mv_type, ff_update_block_index(s); s->bdsp.clear_blocks(s->block[0]); + if (!s->chroma_y_shift) + s->bdsp.clear_blocks(s->block[6]); s->dest[0] = s->current_picture.f->data[0] + s->mb_y * 16 * s->linesize + diff --git a/libavcodec/mpegaudiodecheader.h b/libavcodec/mpegaudiodecheader.h index 1cb921646..1da2a4cb6 100644 --- a/libavcodec/mpegaudiodecheader.h +++ b/libavcodec/mpegaudiodecheader.h @@ -62,6 +62,9 @@ static inline int ff_mpa_check_header(uint32_t header){ /* header */ if ((header & 0xffe00000) != 0xffe00000) return -1; + /* version check */ + if ((header & (3<<19)) == 1<<19) + return -1; /* layer check */ if ((header & (3<<17)) == 0) return -1; diff --git a/libavcodec/mpegvideo.c b/libavcodec/mpegvideo.c index f75c0fd9b..dbb6ab9b3 100644 --- a/libavcodec/mpegvideo.c +++ b/libavcodec/mpegvideo.c @@ -390,6 +390,8 @@ static int init_duplicate_context(MpegEncContext *s) } FF_ALLOCZ_OR_GOTO(s->avctx, s->block32, sizeof(*s->block32), fail) + s->dpcm_direction = 0; + FF_ALLOCZ_OR_GOTO(s->avctx, s->dpcm_macroblock, sizeof(*s->dpcm_macroblock), fail) if (s->avctx->codec_tag == AV_RL32("VCR2")) { // exchange uv @@ -427,6 +429,7 @@ static void free_duplicate_context(MpegEncContext *s) av_freep(&s->me.score_map); av_freep(&s->blocks); av_freep(&s->block32); + av_freep(&s->dpcm_macroblock); av_freep(&s->ac_val_base); s->block = NULL; } @@ -445,6 +448,8 @@ static void backup_duplicate_context(MpegEncContext *bak, MpegEncContext *src) COPY(blocks); COPY(block); COPY(block32); + COPY(dpcm_macroblock); + COPY(dpcm_direction); COPY(start_mb_y); COPY(end_mb_y); COPY(me.map_generation); @@ -533,6 +538,8 @@ int ff_mpeg_update_thread_context(AVCodecContext *dst, s->avctx->width = s1->avctx->width; s->avctx->height = s1->avctx->height; + s->quarter_sample = s1->quarter_sample; + s->coded_picture_number = s1->coded_picture_number; s->picture_number = s1->picture_number; @@ -820,6 +827,8 @@ static void clear_context(MpegEncContext *s) s->blocks = NULL; s->block32 = NULL; memset(s->pblocks, 0, sizeof(s->pblocks)); + s->dpcm_direction = 0; + s->dpcm_macroblock = NULL; s->ac_val_base = NULL; s->ac_val[0] = s->ac_val[1] = @@ -2132,23 +2141,55 @@ void mpv_reconstruct_mb_internal(MpegEncContext *s, int16_t block[12][64], TODO: Integrate 10-bit properly into mpegvideo.c so that ER works properly */ if (s->avctx->bits_per_raw_sample > 8){ const int act_block_size = block_size * 2; - s->idsp.idct_put(dest_y, dct_linesize, (int16_t*)(*s->block32)[0]); - s->idsp.idct_put(dest_y + act_block_size, dct_linesize, (int16_t*)(*s->block32)[1]); - s->idsp.idct_put(dest_y + dct_offset, dct_linesize, (int16_t*)(*s->block32)[2]); - s->idsp.idct_put(dest_y + dct_offset + act_block_size, dct_linesize, (int16_t*)(*s->block32)[3]); - dct_linesize = uvlinesize << s->interlaced_dct; - dct_offset = s->interlaced_dct ? uvlinesize : uvlinesize*block_size; + if(s->dpcm_direction == 0) { + s->idsp.idct_put(dest_y, dct_linesize, (int16_t*)(*s->block32)[0]); + s->idsp.idct_put(dest_y + act_block_size, dct_linesize, (int16_t*)(*s->block32)[1]); + s->idsp.idct_put(dest_y + dct_offset, dct_linesize, (int16_t*)(*s->block32)[2]); + s->idsp.idct_put(dest_y + dct_offset + act_block_size, dct_linesize, (int16_t*)(*s->block32)[3]); - s->idsp.idct_put(dest_cb, dct_linesize, (int16_t*)(*s->block32)[4]); - s->idsp.idct_put(dest_cr, dct_linesize, (int16_t*)(*s->block32)[5]); - s->idsp.idct_put(dest_cb + dct_offset, dct_linesize, (int16_t*)(*s->block32)[6]); - s->idsp.idct_put(dest_cr + dct_offset, dct_linesize, (int16_t*)(*s->block32)[7]); - if(!s->chroma_x_shift){//Chroma444 - s->idsp.idct_put(dest_cb + act_block_size, dct_linesize, (int16_t*)(*s->block32)[8]); - s->idsp.idct_put(dest_cr + act_block_size, dct_linesize, (int16_t*)(*s->block32)[9]); - s->idsp.idct_put(dest_cb + act_block_size + dct_offset, dct_linesize, (int16_t*)(*s->block32)[10]); - s->idsp.idct_put(dest_cr + act_block_size + dct_offset, dct_linesize, (int16_t*)(*s->block32)[11]); + dct_linesize = uvlinesize << s->interlaced_dct; + dct_offset = s->interlaced_dct ? uvlinesize : uvlinesize*block_size; + + s->idsp.idct_put(dest_cb, dct_linesize, (int16_t*)(*s->block32)[4]); + s->idsp.idct_put(dest_cr, dct_linesize, (int16_t*)(*s->block32)[5]); + s->idsp.idct_put(dest_cb + dct_offset, dct_linesize, (int16_t*)(*s->block32)[6]); + s->idsp.idct_put(dest_cr + dct_offset, dct_linesize, (int16_t*)(*s->block32)[7]); + if(!s->chroma_x_shift){//Chroma444 + s->idsp.idct_put(dest_cb + act_block_size, dct_linesize, (int16_t*)(*s->block32)[8]); + s->idsp.idct_put(dest_cr + act_block_size, dct_linesize, (int16_t*)(*s->block32)[9]); + s->idsp.idct_put(dest_cb + act_block_size + dct_offset, dct_linesize, (int16_t*)(*s->block32)[10]); + s->idsp.idct_put(dest_cr + act_block_size + dct_offset, dct_linesize, (int16_t*)(*s->block32)[11]); + } + } else if(s->dpcm_direction == 1) { + int i, w, h; + uint16_t *dest_pcm[3] = {(uint16_t*)dest_y, (uint16_t*)dest_cb, (uint16_t*)dest_cr}; + int linesize[3] = {dct_linesize, uvlinesize, uvlinesize}; + for(i = 0; i < 3; i++) { + int idx = 0; + int vsub = i ? s->chroma_y_shift : 0; + int hsub = i ? s->chroma_x_shift : 0; + for(h = 0; h < (16 >> vsub); h++){ + for(w = 0; w < (16 >> hsub); w++) + dest_pcm[i][w] = (*s->dpcm_macroblock)[i][idx++]; + dest_pcm[i] += linesize[i] / 2; + } + } + } else if(s->dpcm_direction == -1) { + int i, w, h; + uint16_t *dest_pcm[3] = {(uint16_t*)dest_y, (uint16_t*)dest_cb, (uint16_t*)dest_cr}; + int linesize[3] = {dct_linesize, uvlinesize, uvlinesize}; + for(i = 0; i < 3; i++) { + int idx = 0; + int vsub = i ? s->chroma_y_shift : 0; + int hsub = i ? s->chroma_x_shift : 0; + dest_pcm[i] += (linesize[i] / 2) * ((16 >> vsub) - 1); + for(h = (16 >> vsub)-1; h >= 1; h--){ + for(w = (16 >> hsub)-1; w >= 1; w--) + dest_pcm[i][w] = (*s->dpcm_macroblock)[i][idx++]; + dest_pcm[i] -= linesize[i] / 2; + } + } } } /* dct only in intra block */ diff --git a/libavcodec/mpegvideo.h b/libavcodec/mpegvideo.h index 541909cbb..e1ff5f97d 100644 --- a/libavcodec/mpegvideo.h +++ b/libavcodec/mpegvideo.h @@ -369,7 +369,7 @@ typedef struct MpegEncContext { uint8_t *mb_info_ptr; int mb_info_size; int ehc_mode; - int rc_strategy; + int rc_strategy; ///< deprecated /* H.263+ specific */ int umvplus; ///< == H.263+ && unrestricted_mv @@ -455,6 +455,7 @@ typedef struct MpegEncContext { /* MPEG-2-specific - I wished not to have to support this mess. */ int progressive_sequence; int mpeg_f_code[2][2]; + int a53_cc; // picture structure defines are loaded from mpegutils.h int picture_structure; @@ -509,6 +510,8 @@ typedef struct MpegEncContext { int (*decode_mb)(struct MpegEncContext *s, int16_t block[12][64]); // used by some codecs to avoid a switch() int32_t (*block32)[12][64]; + int dpcm_direction; // 0 = DCT, 1 = DPCM top to bottom scan, -1 = DPCM bottom to top scan + int16_t (*dpcm_macroblock)[3][256]; #define SLICE_OK 0 #define SLICE_ERROR -1 @@ -587,12 +590,6 @@ typedef struct MpegEncContext { #define FF_MPV_FLAG_NAQ 0x0010 #define FF_MPV_FLAG_MV0 0x0020 -enum rc_strategy { - MPV_RC_STRATEGY_FFMPEG, - MPV_RC_STRATEGY_XVID, - NB_MPV_RC_STRATEGY -}; - #define FF_MPV_OPT_CMP_FUNC \ { "sad", "Sum of absolute differences, fast", 0, AV_OPT_TYPE_CONST, {.i64 = FF_CMP_SAD }, INT_MIN, INT_MAX, FF_MPV_OPT_FLAGS, "cmp_func" }, \ { "sse", "Sum of squared errors", 0, AV_OPT_TYPE_CONST, {.i64 = FF_CMP_SSE }, INT_MIN, INT_MAX, FF_MPV_OPT_FLAGS, "cmp_func" }, \ @@ -646,9 +643,9 @@ FF_MPV_OPT_CMP_FUNC, \ {"lmax", "maximum Lagrange factor (VBR)", FF_MPV_OFFSET(lmax), AV_OPT_TYPE_INT, {.i64 = 31*FF_QP2LAMBDA }, 0, INT_MAX, FF_MPV_OPT_FLAGS }, \ {"ibias", "intra quant bias", FF_MPV_OFFSET(intra_quant_bias), AV_OPT_TYPE_INT, {.i64 = FF_DEFAULT_QUANT_BIAS }, INT_MIN, INT_MAX, FF_MPV_OPT_FLAGS }, \ {"pbias", "inter quant bias", FF_MPV_OFFSET(inter_quant_bias), AV_OPT_TYPE_INT, {.i64 = FF_DEFAULT_QUANT_BIAS }, INT_MIN, INT_MAX, FF_MPV_OPT_FLAGS }, \ -{"rc_strategy", "ratecontrol method", FF_MPV_OFFSET(rc_strategy), AV_OPT_TYPE_INT, {.i64 = MPV_RC_STRATEGY_FFMPEG }, 0, NB_MPV_RC_STRATEGY-1, FF_MPV_OPT_FLAGS, "rc_strategy" }, \ - { "ffmpeg", "default native rate control", 0, AV_OPT_TYPE_CONST, { .i64 = MPV_RC_STRATEGY_FFMPEG }, 0, 0, FF_MPV_OPT_FLAGS, "rc_strategy" }, \ - { "xvid", "libxvid (2 pass only)", 0, AV_OPT_TYPE_CONST, { .i64 = MPV_RC_STRATEGY_XVID }, 0, 0, FF_MPV_OPT_FLAGS, "rc_strategy" }, \ +{"rc_strategy", "ratecontrol method", FF_MPV_OFFSET(rc_strategy), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, 1, FF_MPV_OPT_FLAGS | AV_OPT_FLAG_DEPRECATED, "rc_strategy" }, \ + { "ffmpeg", "deprecated, does nothing", 0, AV_OPT_TYPE_CONST, { .i64 = 0 }, 0, 0, FF_MPV_OPT_FLAGS | AV_OPT_FLAG_DEPRECATED, "rc_strategy" }, \ + { "xvid", "deprecated, does nothing", 0, AV_OPT_TYPE_CONST, { .i64 = 0 }, 0, 0, FF_MPV_OPT_FLAGS | AV_OPT_FLAG_DEPRECATED, "rc_strategy" }, \ {"motion_est", "motion estimation algorithm", FF_MPV_OFFSET(motion_est), AV_OPT_TYPE_INT, {.i64 = FF_ME_EPZS }, FF_ME_ZERO, FF_ME_XONE, FF_MPV_OPT_FLAGS, "motion_est" }, \ { "zero", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FF_ME_ZERO }, 0, 0, FF_MPV_OPT_FLAGS, "motion_est" }, \ { "epzs", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = FF_ME_EPZS }, 0, 0, FF_MPV_OPT_FLAGS, "motion_est" }, \ @@ -667,6 +664,7 @@ FF_MPV_OPT_CMP_FUNC, \ {"ps", "RTP payload size in bytes", FF_MPV_OFFSET(rtp_payload_size), AV_OPT_TYPE_INT, {.i64 = 0 }, INT_MIN, INT_MAX, FF_MPV_OPT_FLAGS }, \ {"mepc", "Motion estimation bitrate penalty compensation (1.0 = 256)", FF_MPV_OFFSET(me_penalty_compensation), AV_OPT_TYPE_INT, {.i64 = 256 }, INT_MIN, INT_MAX, FF_MPV_OPT_FLAGS }, \ {"mepre", "pre motion estimation", FF_MPV_OFFSET(me_pre), AV_OPT_TYPE_INT, {.i64 = 0 }, INT_MIN, INT_MAX, FF_MPV_OPT_FLAGS }, \ +{"a53cc", "Use A53 Closed Captions (if available)", FF_MPV_OFFSET(a53_cc), AV_OPT_TYPE_BOOL, {.i64 = 1}, 0, 1, FF_MPV_OPT_FLAGS }, \ extern const AVOption ff_mpv_generic_options[]; diff --git a/libavcodec/mpegvideo_enc.c b/libavcodec/mpegvideo_enc.c index 979e138b8..ae3b13122 100644 --- a/libavcodec/mpegvideo_enc.c +++ b/libavcodec/mpegvideo_enc.c @@ -1024,18 +1024,6 @@ FF_ENABLE_DEPRECATION_WARNINGS if (ff_rate_control_init(s) < 0) return -1; - if ((s->avctx->flags & AV_CODEC_FLAG_PASS2) && s->rc_strategy == MPV_RC_STRATEGY_XVID) { -#if CONFIG_LIBXVID - ret = ff_xvid_rate_control_init(s); -#else - ret = AVERROR(ENOSYS); - av_log(s->avctx, AV_LOG_ERROR, - "Xvid ratecontrol requires libavcodec compiled with Xvid support.\n"); -#endif - if (ret < 0) - return ret; - } - #if FF_API_PRIVATE_OPT FF_DISABLE_DEPRECATION_WARNINGS if (avctx->brd_scale) @@ -1082,10 +1070,6 @@ av_cold int ff_mpv_encode_end(AVCodecContext *avctx) int i; ff_rate_control_uninit(s); -#if CONFIG_LIBXVID - if ((avctx->flags & AV_CODEC_FLAG_PASS2) && s->rc_strategy == MPV_RC_STRATEGY_XVID) - ff_xvid_rate_control_uninit(s); -#endif ff_mpv_common_end(s); if (CONFIG_MJPEG_ENCODER && @@ -2021,7 +2005,7 @@ FF_ENABLE_DEPRECATION_WARNINGS av_log(s->avctx, AV_LOG_ERROR, "Internal error, negative bits\n"); - assert(s->repeat_first_field == 0); + av_assert1(s->repeat_first_field == 0); vbv_delay = bits * 90000 / s->avctx->rc_max_rate; min_delay = (minbits * 90000LL + s->avctx->rc_max_rate - 1) / @@ -3072,7 +3056,7 @@ static int encode_thread(AVCodecContext *c, void *arg){ if(r % d == 0){ current_packet_size=0; s->pb.buf_ptr= s->ptr_lastgob; - assert(put_bits_ptr(&s->pb) == s->ptr_lastgob); + av_assert1(put_bits_ptr(&s->pb) == s->ptr_lastgob); } } @@ -3608,8 +3592,8 @@ static void merge_context_after_encode(MpegEncContext *dst, MpegEncContext *src) } } - assert(put_bits_count(&src->pb) % 8 ==0); - assert(put_bits_count(&dst->pb) % 8 ==0); + av_assert1(put_bits_count(&src->pb) % 8 ==0); + av_assert1(put_bits_count(&dst->pb) % 8 ==0); avpriv_copy_bits(&dst->pb, src->pb.buf, put_bits_count(&src->pb)); flush_put_bits(&dst->pb); } @@ -3620,13 +3604,7 @@ static int estimate_qp(MpegEncContext *s, int dry_run){ s->current_picture.f->quality = s->next_lambda; if(!dry_run) s->next_lambda= 0; } else if (!s->fixed_qscale) { - int quality; -#if CONFIG_LIBXVID - if ((s->avctx->flags & AV_CODEC_FLAG_PASS2) && s->rc_strategy == MPV_RC_STRATEGY_XVID) - quality = ff_xvid_rate_estimate_qscale(s, dry_run); - else -#endif - quality = ff_rate_estimate_qscale(s, dry_run); + int quality = ff_rate_estimate_qscale(s, dry_run); s->current_picture_ptr->f->quality = s->current_picture.f->quality = quality; if (s->current_picture.f->quality < 0) @@ -3664,11 +3642,11 @@ static void set_frame_distances(MpegEncContext * s){ if(s->pict_type==AV_PICTURE_TYPE_B){ s->pb_time= s->pp_time - (s->last_non_b_time - s->time); - assert(s->pb_time > 0 && s->pb_time < s->pp_time); + av_assert1(s->pb_time > 0 && s->pb_time < s->pp_time); }else{ s->pp_time= s->time - s->last_non_b_time; s->last_non_b_time= s->time; - assert(s->picture_number==0 || s->pp_time > 0); + av_assert1(s->picture_number==0 || s->pp_time > 0); } } diff --git a/libavcodec/mscc.c b/libavcodec/mscc.c index 6e4dbb014..86e4e88ed 100644 --- a/libavcodec/mscc.c +++ b/libavcodec/mscc.c @@ -37,10 +37,15 @@ typedef struct MSCCContext { unsigned int uncomp_size; uint8_t *uncomp_buf; z_stream zstream; + + uint32_t pal[256]; } MSCCContext; -static int rle_uncompress(AVCodecContext *avctx, GetByteContext *gb, PutByteContext *pb, int bpp) +static int rle_uncompress(AVCodecContext *avctx, GetByteContext *gb, PutByteContext *pb) { + MSCCContext *s = avctx->priv_data; + unsigned x = 0, y = 0; + while (bytestream2_get_bytes_left(gb) > 0) { uint32_t fill; int j; @@ -78,19 +83,22 @@ static int rle_uncompress(AVCodecContext *avctx, GetByteContext *gb, PutByteCont break; } } + x += run; } else { unsigned copy = bytestream2_get_byte(gb); - if (copy == 1) { + if (copy == 0) { + x = 0; + y++; + bytestream2_seek_p(pb, y * avctx->width * s->bpp, SEEK_SET); + } else if (copy == 1) { return 0; } else if (copy == 2) { - unsigned x, y; - x = bytestream2_get_byte(gb); - y = bytestream2_get_byte(gb); + x += bytestream2_get_byte(gb); + y += bytestream2_get_byte(gb); - bytestream2_skip_p(pb, x * bpp); - bytestream2_skip_p(pb, y * bpp * avctx->width); + bytestream2_seek_p(pb, y * avctx->width * s->bpp + x * s->bpp, SEEK_SET); } else { for (j = 0; j < copy; j++) { switch (avctx->bits_per_coded_sample) { @@ -108,6 +116,10 @@ static int rle_uncompress(AVCodecContext *avctx, GetByteContext *gb, PutByteCont break; } } + + if (s->bpp == 1 && (copy & 1)) + bytestream2_skip(gb, 1); + x += copy; } } } @@ -128,7 +140,8 @@ static int decode_frame(AVCodecContext *avctx, int ret, j; if (avpkt->size < 3) - return AVERROR_INVALIDDATA; + return buf_size; + if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) return ret; @@ -138,6 +151,20 @@ static int decode_frame(AVCodecContext *avctx, buf_size -= 2; } + if (avctx->pix_fmt == AV_PIX_FMT_PAL8) { + int size; + const uint8_t *pal = av_packet_get_side_data(avpkt, AV_PKT_DATA_PALETTE, &size); + + if (pal && size == AVPALETTE_SIZE) { + frame->palette_has_changed = 1; + for (j = 0; j < 256; j++) + s->pal[j] = 0xFF000000 | AV_RL32(pal + j * 4); + } else if (pal) { + av_log(avctx, AV_LOG_ERROR, "Palette size %d is wrong\n", size); + } + memcpy(frame->data[1], s->pal, AVPALETTE_SIZE); + } + ret = inflateReset(&s->zstream); if (ret != Z_OK) { av_log(avctx, AV_LOG_ERROR, "Inflate reset error: %d\n", ret); @@ -156,7 +183,7 @@ static int decode_frame(AVCodecContext *avctx, bytestream2_init(&gb, s->decomp_buf, s->zstream.total_out); bytestream2_init_writer(&pb, s->uncomp_buf, s->uncomp_size); - ret = rle_uncompress(avctx, &gb, &pb, s->bpp); + ret = rle_uncompress(avctx, &gb, &pb); if (ret) return ret; @@ -176,10 +203,10 @@ static int decode_frame(AVCodecContext *avctx, static av_cold int decode_init(AVCodecContext *avctx) { MSCCContext *s = avctx->priv_data; - int zret; + int stride, zret; switch (avctx->bits_per_coded_sample) { - case 8: avctx->pix_fmt = AV_PIX_FMT_GRAY8; break; + case 8: avctx->pix_fmt = AV_PIX_FMT_PAL8; break; case 16: avctx->pix_fmt = AV_PIX_FMT_RGB555; break; case 24: avctx->pix_fmt = AV_PIX_FMT_BGR24; break; case 32: avctx->pix_fmt = AV_PIX_FMT_BGRA; break; @@ -189,13 +216,13 @@ static av_cold int decode_init(AVCodecContext *avctx) } s->bpp = avctx->bits_per_coded_sample >> 3; - memset(&s->zstream, 0, sizeof(z_stream)); + stride = 4 * ((avctx->width * avctx->bits_per_coded_sample + 31) / 32); - s->decomp_size = 4 * avctx->height * ((avctx->width * avctx->bits_per_coded_sample + 31) / 32); + s->decomp_size = 2 * avctx->height * stride; if (!(s->decomp_buf = av_malloc(s->decomp_size))) return AVERROR(ENOMEM); - s->uncomp_size = 4 * avctx->height * ((avctx->width * avctx->bits_per_coded_sample + 31) / 32); + s->uncomp_size = avctx->height * stride; if (!(s->uncomp_buf = av_malloc(s->uncomp_size))) return AVERROR(ENOMEM); @@ -234,6 +261,7 @@ AVCodec ff_mscc_decoder = { .close = decode_close, .decode = decode_frame, .capabilities = AV_CODEC_CAP_DR1, + .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; AVCodec ff_srgc_decoder = { @@ -246,4 +274,5 @@ AVCodec ff_srgc_decoder = { .close = decode_close, .decode = decode_frame, .capabilities = AV_CODEC_CAP_DR1, + .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; diff --git a/libavcodec/mss1.c b/libavcodec/mss1.c index a579d9d9a..84b7a3700 100644 --- a/libavcodec/mss1.c +++ b/libavcodec/mss1.c @@ -56,6 +56,8 @@ static void arith_normalise(ArithCoder *c) c->low <<= 1; c->high <<= 1; c->high |= 1; + if (get_bits_left(c->gbc.gb) < 1) + c->overread++; c->value |= get_bits1(c->gbc.gb); } } @@ -112,6 +114,7 @@ static void arith_init(ArithCoder *c, GetBitContext *gb) c->low = 0; c->high = 0xFFFF; c->value = get_bits(gb, 16); + c->overread = 0; c->gbc.gb = gb; c->get_model_sym = arith_get_model_sym; c->get_number = arith_get_number; diff --git a/libavcodec/mss12.c b/libavcodec/mss12.c index 3b1a3029e..5a5bd9a91 100644 --- a/libavcodec/mss12.c +++ b/libavcodec/mss12.c @@ -161,6 +161,8 @@ static av_always_inline int decode_pixel(ArithCoder *acoder, PixContext *pctx, { int i, val, pix; + if (acoder->overread > MAX_OVERREAD) + return AVERROR_INVALIDDATA; val = acoder->get_model_sym(acoder, &pctx->cache_model); if (val < pctx->num_syms) { if (any_ngb) { @@ -306,6 +308,8 @@ static int decode_region(ArithCoder *acoder, uint8_t *dst, uint8_t *rgb_pic, else p = decode_pixel_in_context(acoder, pctx, dst + i, stride, i, j, width - i - 1); + if (p < 0) + return p; dst[i] = p; if (rgb_pic) @@ -398,6 +402,8 @@ static int decode_region_masked(MSS12Context const *c, ArithCoder *acoder, else p = decode_pixel_in_context(acoder, pctx, dst + i, stride, i, j, width - i - 1); + if (p < 0) + return p; dst[i] = p; if (c->rgb_pic) AV_WB24(rgb_dst + i * 3, c->pal[p]); @@ -473,6 +479,8 @@ static int decode_region_intra(SliceContext *sc, ArithCoder *acoder, uint8_t *rgb_dst = c->rgb_pic + x * 3 + y * rgb_stride; pix = decode_pixel(acoder, &sc->intra_pix_ctx, NULL, 0, 0); + if (pix < 0) + return pix; rgb_pix = c->pal[pix]; for (i = 0; i < height; i++, dst += stride, rgb_dst += rgb_stride) { memset(dst, pix, width); @@ -499,6 +507,8 @@ static int decode_region_inter(SliceContext *sc, ArithCoder *acoder, if (!mode) { mode = decode_pixel(acoder, &sc->inter_pix_ctx, NULL, 0, 0); + if (mode < 0) + return mode; if (c->avctx->err_recognition & AV_EF_EXPLODE && ( c->rgb_pic && mode != 0x01 && mode != 0x02 && mode != 0x04 || @@ -530,6 +540,8 @@ int ff_mss12_decode_rect(SliceContext *sc, ArithCoder *acoder, int x, int y, int width, int height) { int mode, pivot; + if (acoder->overread > MAX_OVERREAD) + return AVERROR_INVALIDDATA; mode = acoder->get_model_sym(acoder, &sc->split_mode); diff --git a/libavcodec/mss12.h b/libavcodec/mss12.h index 45c407465..6f68fc3db 100644 --- a/libavcodec/mss12.h +++ b/libavcodec/mss12.h @@ -47,6 +47,8 @@ typedef struct Model { typedef struct ArithCoder { int low, high, value; + int overread; +#define MAX_OVERREAD 16 union { GetBitContext *gb; GetByteContext *gB; diff --git a/libavcodec/mss2.c b/libavcodec/mss2.c index 3180af1d6..29897cea2 100644 --- a/libavcodec/mss2.c +++ b/libavcodec/mss2.c @@ -152,6 +152,7 @@ static void arith2_init(ArithCoder *c, GetByteContext *gB) c->low = 0; c->high = 0xFFFFFF; c->value = bytestream2_get_be24(gB); + c->overread = 0; c->gbc.gB = gB; c->get_model_sym = arith2_get_model_sym; c->get_number = arith2_get_number; @@ -174,7 +175,7 @@ static int decode_pal_v2(MSS12Context *ctx, const uint8_t *buf, int buf_size) return 1 + ncol * 3; } -static int decode_555(GetByteContext *gB, uint16_t *dst, ptrdiff_t stride, +static int decode_555(AVCodecContext *avctx, GetByteContext *gB, uint16_t *dst, ptrdiff_t stride, int keyframe, int w, int h) { int last_symbol = 0, repeat = 0, prev_avail = 0; @@ -212,7 +213,7 @@ static int decode_555(GetByteContext *gB, uint16_t *dst, ptrdiff_t stride, repeat = 0; while (b-- > 130) { if (repeat >= (INT_MAX >> 8) - 1) { - av_log(NULL, AV_LOG_ERROR, "repeat overflow\n"); + av_log(avctx, AV_LOG_ERROR, "repeat overflow\n"); return AVERROR_INVALIDDATA; } repeat = (repeat << 8) + bytestream2_get_byte(gB) + 1; @@ -634,7 +635,7 @@ static int mss2_decode_frame(AVCodecContext *avctx, void *data, int *got_frame, if (is_555) { bytestream2_init(&gB, buf, buf_size); - if (decode_555(&gB, (uint16_t *)c->rgb_pic, c->rgb_stride >> 1, + if (decode_555(avctx, &gB, (uint16_t *)c->rgb_pic, c->rgb_stride >> 1, keyframe, avctx->width, avctx->height)) return AVERROR_INVALIDDATA; diff --git a/libavcodec/mss3.c b/libavcodec/mss3.c index 21226f908..02bd36099 100644 --- a/libavcodec/mss3.c +++ b/libavcodec/mss3.c @@ -298,6 +298,10 @@ static void rac_normalise(RangeCoder *c) c->got_error = 1; c->low = 1; } + if (c->low > c->range) { + c->got_error = 1; + c->low = 1; + } if (c->range >= RAC_BOTTOM) return; } diff --git a/libavcodec/mss4.c b/libavcodec/mss4.c index b58c21be9..76c746a2d 100644 --- a/libavcodec/mss4.c +++ b/libavcodec/mss4.c @@ -552,6 +552,11 @@ static int mss4_decode_frame(AVCodecContext *avctx, void *data, int *got_frame, "Empty frame found but it is not a skip frame.\n"); return AVERROR_INVALIDDATA; } + mb_width = FFALIGN(width, 16) >> 4; + mb_height = FFALIGN(height, 16) >> 4; + + if (frame_type != SKIP_FRAME && 8*buf_size < 8*HEADER_SIZE + mb_width*mb_height) + return AVERROR_INVALIDDATA; if ((ret = ff_reget_buffer(avctx, c->pic)) < 0) return ret; @@ -574,9 +579,6 @@ static int mss4_decode_frame(AVCodecContext *avctx, void *data, int *got_frame, if ((ret = init_get_bits8(&gb, buf + HEADER_SIZE, buf_size - HEADER_SIZE)) < 0) return ret; - - mb_width = FFALIGN(width, 16) >> 4; - mb_height = FFALIGN(height, 16) >> 4; dst[0] = c->pic->data[0]; dst[1] = c->pic->data[1]; dst[2] = c->pic->data[2]; diff --git a/libavcodec/mwsc.c b/libavcodec/mwsc.c new file mode 100644 index 000000000..4db7642e8 --- /dev/null +++ b/libavcodec/mwsc.c @@ -0,0 +1,192 @@ +/* + * MatchWare Screen Capture Codec decoder + * + * Copyright (c) 2018 Paul B Mahol + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include + +#include "avcodec.h" +#include "bytestream.h" +#include "internal.h" + +#include + +typedef struct MWSCContext { + unsigned int decomp_size; + uint8_t *decomp_buf; + z_stream zstream; + AVFrame *prev_frame; +} MWSCContext; + +static int rle_uncompress(GetByteContext *gb, PutByteContext *pb, GetByteContext *gbp, + int width, int height, int stride, int pb_linesize, int gbp_linesize) +{ + int intra = 1, w = 0; + + bytestream2_seek_p(pb, (height - 1) * pb_linesize, SEEK_SET); + + while (bytestream2_get_bytes_left(gb) > 0) { + uint32_t fill = bytestream2_get_le24(gb); + unsigned run = bytestream2_get_byte(gb); + + if (run == 0) { + run = bytestream2_get_le32(gb); + for (int j = 0; j < run; j++, w++) { + if (w == width) { + w = 0; + bytestream2_seek_p(pb, -(pb_linesize + stride), SEEK_CUR); + } + bytestream2_put_le24(pb, fill); + } + } else if (run == 255) { + int pos = bytestream2_tell_p(pb); + + bytestream2_seek(gbp, pos, SEEK_SET); + for (int j = 0; j < fill; j++, w++) { + if (w == width) { + w = 0; + bytestream2_seek_p(pb, -(pb_linesize + stride), SEEK_CUR); + bytestream2_seek(gbp, -(gbp_linesize + stride), SEEK_CUR); + } + bytestream2_put_le24(pb, bytestream2_get_le24(gbp)); + } + + intra = 0; + } else { + for (int j = 0; j < run; j++, w++) { + if (w == width) { + w = 0; + bytestream2_seek_p(pb, -(pb_linesize + stride), SEEK_CUR); + } + bytestream2_put_le24(pb, fill); + } + } + } + + return intra; +} + +static int decode_frame(AVCodecContext *avctx, + void *data, int *got_frame, + AVPacket *avpkt) +{ + MWSCContext *s = avctx->priv_data; + AVFrame *frame = data; + uint8_t *buf = avpkt->data; + int buf_size = avpkt->size; + GetByteContext gb; + GetByteContext gbp; + PutByteContext pb; + int ret; + + ret = inflateReset(&s->zstream); + if (ret != Z_OK) { + av_log(avctx, AV_LOG_ERROR, "Inflate reset error: %d\n", ret); + return AVERROR_EXTERNAL; + } + s->zstream.next_in = buf; + s->zstream.avail_in = buf_size; + s->zstream.next_out = s->decomp_buf; + s->zstream.avail_out = s->decomp_size; + ret = inflate(&s->zstream, Z_FINISH); + if (ret != Z_STREAM_END) { + av_log(avctx, AV_LOG_ERROR, "Inflate error: %d\n", ret); + return AVERROR_EXTERNAL; + } + + if ((ret = ff_get_buffer(avctx, frame, AV_GET_BUFFER_FLAG_REF)) < 0) + return ret; + + bytestream2_init(&gb, s->decomp_buf, s->zstream.total_out); + bytestream2_init(&gbp, s->prev_frame->data[0], avctx->height * s->prev_frame->linesize[0]); + bytestream2_init_writer(&pb, frame->data[0], avctx->height * frame->linesize[0]); + + frame->key_frame = rle_uncompress(&gb, &pb, &gbp, avctx->width, avctx->height, avctx->width * 3, + frame->linesize[0], s->prev_frame->linesize[0]); + + frame->pict_type = frame->key_frame ? AV_PICTURE_TYPE_I : AV_PICTURE_TYPE_P; + + av_frame_unref(s->prev_frame); + if ((ret = av_frame_ref(s->prev_frame, frame)) < 0) + return ret; + + *got_frame = 1; + + return avpkt->size; +} + +static av_cold int decode_init(AVCodecContext *avctx) +{ + MWSCContext *s = avctx->priv_data; + int64_t size; + int zret; + + avctx->pix_fmt = AV_PIX_FMT_BGR24; + + size = 32LL * avctx->height * avctx->width; + if (size >= INT32_MAX) + return AVERROR_INVALIDDATA; + s->decomp_size = size; + if (!(s->decomp_buf = av_malloc(s->decomp_size))) + return AVERROR(ENOMEM); + + s->zstream.zalloc = Z_NULL; + s->zstream.zfree = Z_NULL; + s->zstream.opaque = Z_NULL; + zret = inflateInit(&s->zstream); + if (zret != Z_OK) { + av_log(avctx, AV_LOG_ERROR, "Inflate init error: %d\n", zret); + return AVERROR_EXTERNAL; + } + + s->prev_frame = av_frame_alloc(); + if (!s->prev_frame) + return AVERROR(ENOMEM); + + return 0; +} + +static av_cold int decode_close(AVCodecContext *avctx) +{ + MWSCContext *s = avctx->priv_data; + + av_frame_free(&s->prev_frame); + av_freep(&s->decomp_buf); + s->decomp_size = 0; + inflateEnd(&s->zstream); + + return 0; +} + +AVCodec ff_mwsc_decoder = { + .name = "mwsc", + .long_name = NULL_IF_CONFIG_SMALL("MatchWare Screen Capture Codec"), + .type = AVMEDIA_TYPE_VIDEO, + .id = AV_CODEC_ID_MWSC, + .priv_data_size = sizeof(MWSCContext), + .init = decode_init, + .close = decode_close, + .decode = decode_frame, + .capabilities = AV_CODEC_CAP_DR1, + .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE | + FF_CODEC_CAP_INIT_CLEANUP, +}; diff --git a/libavcodec/nuv.c b/libavcodec/nuv.c index 32ed65899..75b14bce5 100644 --- a/libavcodec/nuv.c +++ b/libavcodec/nuv.c @@ -365,4 +365,5 @@ AVCodec ff_nuv_decoder = { .close = decode_end, .decode = decode_frame, .capabilities = AV_CODEC_CAP_DR1, + .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; diff --git a/libavcodec/nvdec.c b/libavcodec/nvdec.c index ab3cb88b2..b60da2430 100644 --- a/libavcodec/nvdec.c +++ b/libavcodec/nvdec.c @@ -26,6 +26,7 @@ #include "libavutil/error.h" #include "libavutil/hwcontext.h" #include "libavutil/hwcontext_cuda_internal.h" +#include "libavutil/cuda_check.h" #include "libavutil/pixdesc.h" #include "libavutil/pixfmt.h" @@ -34,11 +35,17 @@ #include "nvdec.h" #include "internal.h" +#if !NVDECAPI_CHECK_VERSION(9, 0) +#define cudaVideoSurfaceFormat_YUV444 2 +#define cudaVideoSurfaceFormat_YUV444_16Bit 3 +#endif + typedef struct NVDECDecoder { CUvideodecoder decoder; AVBufferRef *hw_device_ref; CUcontext cuda_ctx; + CUstream stream; CudaFunctions *cudl; CuvidFunctions *cvdl; @@ -49,6 +56,8 @@ typedef struct NVDECFramePool { unsigned int nb_allocated; } NVDECFramePool; +#define CHECK_CU(x) FF_CUDA_CHECK_DL(logctx, decoder->cudl, x) + static int map_avcodec_id(enum AVCodecID id) { switch (id) { @@ -85,7 +94,7 @@ static int map_chroma_format(enum AVPixelFormat pix_fmt) static int nvdec_test_capabilities(NVDECDecoder *decoder, CUVIDDECODECREATEINFO *params, void *logctx) { - CUresult err; + int ret; CUVIDDECODECAPS caps = { 0 }; caps.eCodecType = params->CodecType; @@ -104,11 +113,9 @@ static int nvdec_test_capabilities(NVDECDecoder *decoder, return 0; } - err = decoder->cvdl->cuvidGetDecoderCaps(&caps); - if (err != CUDA_SUCCESS) { - av_log(logctx, AV_LOG_ERROR, "Failed querying decoder capabilities\n"); - return AVERROR_UNKNOWN; - } + ret = CHECK_CU(decoder->cvdl->cuvidGetDecoderCaps(&caps)); + if (ret < 0) + return ret; av_log(logctx, AV_LOG_VERBOSE, "NVDEC capabilities:\n"); av_log(logctx, AV_LOG_VERBOSE, "format supported: %s, max_mb_count: %d\n", @@ -148,8 +155,13 @@ static void nvdec_decoder_free(void *opaque, uint8_t *data) { NVDECDecoder *decoder = (NVDECDecoder*)data; - if (decoder->decoder) - decoder->cvdl->cuvidDestroyDecoder(decoder->decoder); + if (decoder->decoder) { + void *logctx = decoder->hw_device_ref->data; + CUcontext dummy; + CHECK_CU(decoder->cudl->cuCtxPushCurrent(decoder->cuda_ctx)); + CHECK_CU(decoder->cvdl->cuvidDestroyDecoder(decoder->decoder)); + CHECK_CU(decoder->cudl->cuCtxPopCurrent(&dummy)); + } av_buffer_unref(&decoder->hw_device_ref); @@ -168,7 +180,6 @@ static int nvdec_decoder_create(AVBufferRef **out, AVBufferRef *hw_device_ref, NVDECDecoder *decoder; CUcontext dummy; - CUresult err; int ret; decoder = av_mallocz(sizeof(*decoder)); @@ -189,6 +200,7 @@ static int nvdec_decoder_create(AVBufferRef **out, AVBufferRef *hw_device_ref, } decoder->cuda_ctx = device_hwctx->cuda_ctx; decoder->cudl = device_hwctx->internal->cuda_dl; + decoder->stream = device_hwctx->stream; ret = cuvid_load_functions(&decoder->cvdl, logctx); if (ret < 0) { @@ -196,25 +208,21 @@ static int nvdec_decoder_create(AVBufferRef **out, AVBufferRef *hw_device_ref, goto fail; } - err = decoder->cudl->cuCtxPushCurrent(decoder->cuda_ctx); - if (err != CUDA_SUCCESS) { - ret = AVERROR_UNKNOWN; + ret = CHECK_CU(decoder->cudl->cuCtxPushCurrent(decoder->cuda_ctx)); + if (ret < 0) goto fail; - } ret = nvdec_test_capabilities(decoder, params, logctx); if (ret < 0) { - decoder->cudl->cuCtxPopCurrent(&dummy); + CHECK_CU(decoder->cudl->cuCtxPopCurrent(&dummy)); goto fail; } - err = decoder->cvdl->cuvidCreateDecoder(&decoder->decoder, params); + ret = CHECK_CU(decoder->cvdl->cuvidCreateDecoder(&decoder->decoder, params)); - decoder->cudl->cuCtxPopCurrent(&dummy); + CHECK_CU(decoder->cudl->cuCtxPopCurrent(&dummy)); - if (err != CUDA_SUCCESS) { - av_log(logctx, AV_LOG_ERROR, "Error creating a NVDEC decoder: %d\n", err); - ret = AVERROR_UNKNOWN; + if (ret < 0) { goto fail; } @@ -271,7 +279,8 @@ int ff_nvdec_decode_init(AVCodecContext *avctx) CUVIDDECODECREATEINFO params = { 0 }; - int cuvid_codec_type, cuvid_chroma_format; + cudaVideoSurfaceFormat output_format; + int cuvid_codec_type, cuvid_chroma_format, chroma_444; int ret = 0; sw_desc = av_pix_fmt_desc_get(avctx->sw_pix_fmt); @@ -289,6 +298,7 @@ int ff_nvdec_decode_init(AVCodecContext *avctx) av_log(avctx, AV_LOG_ERROR, "Unsupported chroma format\n"); return AVERROR(ENOSYS); } + chroma_444 = ctx->supports_444 && cuvid_chroma_format == cudaVideoChromaFormat_444; if (!avctx->hw_frames_ctx) { ret = ff_decode_get_hw_frames_ctx(avctx, AV_HWDEVICE_TYPE_CUDA); @@ -296,6 +306,21 @@ int ff_nvdec_decode_init(AVCodecContext *avctx) return ret; } + switch (sw_desc->comp[0].depth) { + case 8: + output_format = chroma_444 ? cudaVideoSurfaceFormat_YUV444 : + cudaVideoSurfaceFormat_NV12; + break; + case 10: + case 12: + output_format = chroma_444 ? cudaVideoSurfaceFormat_YUV444_16Bit : + cudaVideoSurfaceFormat_P016; + break; + default: + av_log(avctx, AV_LOG_ERROR, "Unsupported bit depth\n"); + return AVERROR(ENOSYS); + } + frames_ctx = (AVHWFramesContext*)avctx->hw_frames_ctx->data; params.ulWidth = avctx->coded_width; @@ -303,12 +328,11 @@ int ff_nvdec_decode_init(AVCodecContext *avctx) params.ulTargetWidth = avctx->coded_width; params.ulTargetHeight = avctx->coded_height; params.bitDepthMinus8 = sw_desc->comp[0].depth - 8; - params.OutputFormat = params.bitDepthMinus8 ? - cudaVideoSurfaceFormat_P016 : cudaVideoSurfaceFormat_NV12; + params.OutputFormat = output_format; params.CodecType = cuvid_codec_type; params.ChromaFormat = cuvid_chroma_format; params.ulNumDecodeSurfaces = frames_ctx->initial_pool_size; - params.ulNumOutputSurfaces = 1; + params.ulNumOutputSurfaces = frames_ctx->initial_pool_size; ret = nvdec_decoder_create(&ctx->decoder_ref, frames_ctx->device_ref, ¶ms, avctx); if (ret < 0) { @@ -354,64 +378,98 @@ static void nvdec_fdd_priv_free(void *priv) av_freep(&priv); } +static void nvdec_unmap_mapped_frame(void *opaque, uint8_t *data) +{ + NVDECFrame *unmap_data = (NVDECFrame*)data; + NVDECDecoder *decoder = (NVDECDecoder*)unmap_data->decoder_ref->data; + void *logctx = decoder->hw_device_ref->data; + CUdeviceptr devptr = (CUdeviceptr)opaque; + int ret; + CUcontext dummy; + + ret = CHECK_CU(decoder->cudl->cuCtxPushCurrent(decoder->cuda_ctx)); + if (ret < 0) + goto finish; + + CHECK_CU(decoder->cvdl->cuvidUnmapVideoFrame(decoder->decoder, devptr)); + + CHECK_CU(decoder->cudl->cuCtxPopCurrent(&dummy)); + +finish: + av_buffer_unref(&unmap_data->idx_ref); + av_buffer_unref(&unmap_data->decoder_ref); + av_free(unmap_data); +} + static int nvdec_retrieve_data(void *logctx, AVFrame *frame) { FrameDecodeData *fdd = (FrameDecodeData*)frame->private_ref->data; NVDECFrame *cf = (NVDECFrame*)fdd->hwaccel_priv; NVDECDecoder *decoder = (NVDECDecoder*)cf->decoder_ref->data; - CUVIDPROCPARAMS vpp = { .progressive_frame = 1 }; + AVHWFramesContext *hwctx = (AVHWFramesContext *)frame->hw_frames_ctx->data; + + CUVIDPROCPARAMS vpp = { 0 }; + NVDECFrame *unmap_data = NULL; - CUresult err; CUcontext dummy; CUdeviceptr devptr; unsigned int pitch, i; unsigned int offset = 0; + int shift_h = 0, shift_v = 0; int ret = 0; - err = decoder->cudl->cuCtxPushCurrent(decoder->cuda_ctx); - if (err != CUDA_SUCCESS) - return AVERROR_UNKNOWN; + vpp.progressive_frame = 1; + vpp.output_stream = decoder->stream; - err = decoder->cvdl->cuvidMapVideoFrame(decoder->decoder, cf->idx, &devptr, - &pitch, &vpp); - if (err != CUDA_SUCCESS) { - av_log(logctx, AV_LOG_ERROR, "Error mapping a picture with CUVID: %d\n", - err); - ret = AVERROR_UNKNOWN; + ret = CHECK_CU(decoder->cudl->cuCtxPushCurrent(decoder->cuda_ctx)); + if (ret < 0) + return ret; + + ret = CHECK_CU(decoder->cvdl->cuvidMapVideoFrame(decoder->decoder, + cf->idx, &devptr, + &pitch, &vpp)); + if (ret < 0) goto finish; + + unmap_data = av_mallocz(sizeof(*unmap_data)); + if (!unmap_data) { + ret = AVERROR(ENOMEM); + goto copy_fail; } - for (i = 0; frame->data[i]; i++) { - CUDA_MEMCPY2D cpy = { - .srcMemoryType = CU_MEMORYTYPE_DEVICE, - .dstMemoryType = CU_MEMORYTYPE_DEVICE, - .srcDevice = devptr, - .dstDevice = (CUdeviceptr)frame->data[i], - .srcPitch = pitch, - .dstPitch = frame->linesize[i], - .srcY = offset, - .WidthInBytes = FFMIN(pitch, frame->linesize[i]), - .Height = frame->height >> (i ? 1 : 0), - }; - - err = decoder->cudl->cuMemcpy2D(&cpy); - if (err != CUDA_SUCCESS) { - av_log(logctx, AV_LOG_ERROR, "Error copying decoded frame: %d\n", - err); - ret = AVERROR_UNKNOWN; - goto copy_fail; - } - - offset += cpy.Height; + frame->buf[1] = av_buffer_create((uint8_t *)unmap_data, sizeof(*unmap_data), + nvdec_unmap_mapped_frame, (void*)devptr, + AV_BUFFER_FLAG_READONLY); + if (!frame->buf[1]) { + ret = AVERROR(ENOMEM); + goto copy_fail; } + unmap_data->idx = cf->idx; + unmap_data->idx_ref = av_buffer_ref(cf->idx_ref); + unmap_data->decoder_ref = av_buffer_ref(cf->decoder_ref); + + av_pix_fmt_get_chroma_sub_sample(hwctx->sw_format, &shift_h, &shift_v); + for (i = 0; frame->linesize[i]; i++) { + frame->data[i] = (uint8_t*)(devptr + offset); + frame->linesize[i] = pitch; + offset += pitch * (frame->height >> (i ? shift_v : 0)); + } + + goto finish; + copy_fail: - decoder->cvdl->cuvidUnmapVideoFrame(decoder->decoder, devptr); + if (!frame->buf[1]) { + CHECK_CU(decoder->cvdl->cuvidUnmapVideoFrame(decoder->decoder, devptr)); + av_freep(&unmap_data); + } else { + av_buffer_unref(&frame->buf[1]); + } finish: - decoder->cudl->cuCtxPopCurrent(&dummy); + CHECK_CU(decoder->cudl->cuCtxPopCurrent(&dummy)); return ret; } @@ -461,9 +519,9 @@ int ff_nvdec_end_frame(AVCodecContext *avctx) { NVDECContext *ctx = avctx->internal->hwaccel_priv_data; NVDECDecoder *decoder = (NVDECDecoder*)ctx->decoder_ref->data; + void *logctx = avctx; CUVIDPICPARAMS *pp = &ctx->pic_params; - CUresult err; CUcontext dummy; int ret = 0; @@ -473,20 +531,16 @@ int ff_nvdec_end_frame(AVCodecContext *avctx) pp->nNumSlices = ctx->nb_slices; pp->pSliceDataOffsets = ctx->slice_offsets; - err = decoder->cudl->cuCtxPushCurrent(decoder->cuda_ctx); - if (err != CUDA_SUCCESS) - return AVERROR_UNKNOWN; + ret = CHECK_CU(decoder->cudl->cuCtxPushCurrent(decoder->cuda_ctx)); + if (ret < 0) + return ret; - err = decoder->cvdl->cuvidDecodePicture(decoder->decoder, &ctx->pic_params); - if (err != CUDA_SUCCESS) { - av_log(avctx, AV_LOG_ERROR, "Error decoding a picture with NVDEC: %d\n", - err); - ret = AVERROR_UNKNOWN; + ret = CHECK_CU(decoder->cvdl->cuvidDecodePicture(decoder->decoder, &ctx->pic_params)); + if (ret < 0) goto finish; - } finish: - decoder->cudl->cuCtxPopCurrent(&dummy); + CHECK_CU(decoder->cudl->cuCtxPopCurrent(&dummy)); return ret; } @@ -521,13 +575,24 @@ int ff_nvdec_simple_decode_slice(AVCodecContext *avctx, const uint8_t *buffer, return 0; } +static void nvdec_free_dummy(struct AVHWFramesContext *ctx) +{ + av_buffer_pool_uninit(&ctx->pool); +} + +static AVBufferRef *nvdec_alloc_dummy(int size) +{ + return av_buffer_create(NULL, 0, NULL, NULL, 0); +} + int ff_nvdec_frame_params(AVCodecContext *avctx, AVBufferRef *hw_frames_ctx, - int dpb_size) + int dpb_size, + int supports_444) { AVHWFramesContext *frames_ctx = (AVHWFramesContext*)hw_frames_ctx->data; const AVPixFmtDescriptor *sw_desc; - int cuvid_codec_type, cuvid_chroma_format; + int cuvid_codec_type, cuvid_chroma_format, chroma_444; sw_desc = av_pix_fmt_desc_get(avctx->sw_pix_fmt); if (!sw_desc) @@ -544,21 +609,32 @@ int ff_nvdec_frame_params(AVCodecContext *avctx, av_log(avctx, AV_LOG_VERBOSE, "Unsupported chroma format\n"); return AVERROR(EINVAL); } + chroma_444 = supports_444 && cuvid_chroma_format == cudaVideoChromaFormat_444; frames_ctx->format = AV_PIX_FMT_CUDA; frames_ctx->width = (avctx->coded_width + 1) & ~1; frames_ctx->height = (avctx->coded_height + 1) & ~1; - frames_ctx->initial_pool_size = dpb_size; + /* + * We add two extra frames to the pool to account for deinterlacing filters + * holding onto their frames. + */ + frames_ctx->initial_pool_size = dpb_size + 2; + + frames_ctx->free = nvdec_free_dummy; + frames_ctx->pool = av_buffer_pool_init(0, nvdec_alloc_dummy); + + if (!frames_ctx->pool) + return AVERROR(ENOMEM); switch (sw_desc->comp[0].depth) { case 8: - frames_ctx->sw_format = AV_PIX_FMT_NV12; + frames_ctx->sw_format = chroma_444 ? AV_PIX_FMT_YUV444P : AV_PIX_FMT_NV12; break; case 10: - frames_ctx->sw_format = AV_PIX_FMT_P010; + frames_ctx->sw_format = chroma_444 ? AV_PIX_FMT_YUV444P16 : AV_PIX_FMT_P010; break; case 12: - frames_ctx->sw_format = AV_PIX_FMT_P016; + frames_ctx->sw_format = chroma_444 ? AV_PIX_FMT_YUV444P16 : AV_PIX_FMT_P016; break; default: return AVERROR(EINVAL); diff --git a/libavcodec/nvdec.h b/libavcodec/nvdec.h index 85a0fcf72..09ae8c37e 100644 --- a/libavcodec/nvdec.h +++ b/libavcodec/nvdec.h @@ -61,6 +61,8 @@ typedef struct NVDECContext { unsigned *slice_offsets; int nb_slices; unsigned int slice_offsets_allocated; + + int supports_444; } NVDECContext; int ff_nvdec_decode_init(AVCodecContext *avctx); @@ -72,7 +74,8 @@ int ff_nvdec_simple_decode_slice(AVCodecContext *avctx, const uint8_t *buffer, uint32_t size); int ff_nvdec_frame_params(AVCodecContext *avctx, AVBufferRef *hw_frames_ctx, - int dpb_size); + int dpb_size, + int supports_444); int ff_nvdec_get_ref_idx(AVFrame *frame); #endif /* AVCODEC_NVDEC_H */ diff --git a/libavcodec/nvdec_h264.c b/libavcodec/nvdec_h264.c index 25b30329d..116bd4fb5 100644 --- a/libavcodec/nvdec_h264.c +++ b/libavcodec/nvdec_h264.c @@ -166,7 +166,7 @@ static int nvdec_h264_frame_params(AVCodecContext *avctx, { const H264Context *h = avctx->priv_data; const SPS *sps = h->ps.sps; - return ff_nvdec_frame_params(avctx, hw_frames_ctx, sps->ref_frame_count + sps->num_reorder_frames); + return ff_nvdec_frame_params(avctx, hw_frames_ctx, sps->ref_frame_count + sps->num_reorder_frames, 0); } const AVHWAccel ff_h264_nvdec_hwaccel = { diff --git a/libavcodec/nvdec_hevc.c b/libavcodec/nvdec_hevc.c index e04a701f3..590278ba0 100644 --- a/libavcodec/nvdec_hevc.c +++ b/libavcodec/nvdec_hevc.c @@ -131,6 +131,17 @@ static int nvdec_hevc_start_frame(AVCodecContext *avctx, .IdrPicFlag = IS_IDR(s), .bit_depth_luma_minus8 = sps->bit_depth - 8, .bit_depth_chroma_minus8 = sps->bit_depth - 8, +#if NVDECAPI_CHECK_VERSION(9, 0) + .sps_range_extension_flag = sps->sps_range_extension_flag, + .transform_skip_rotation_enabled_flag = sps->transform_skip_rotation_enabled_flag, + .transform_skip_context_enabled_flag = sps->transform_skip_context_enabled_flag, + .implicit_rdpcm_enabled_flag = sps->implicit_rdpcm_enabled_flag, + .explicit_rdpcm_enabled_flag = sps->explicit_rdpcm_enabled_flag, + .extended_precision_processing_flag = sps->extended_precision_processing_flag, + .intra_smoothing_disabled_flag = sps->intra_smoothing_disabled_flag, + .persistent_rice_adaptation_enabled_flag = sps->persistent_rice_adaptation_enabled_flag, + .cabac_bypass_alignment_enabled_flag = sps->cabac_bypass_alignment_enabled_flag, +#endif .dependent_slice_segments_enabled_flag = pps->dependent_slice_segments_enabled_flag, .slice_segment_header_extension_present_flag = pps->slice_header_extension_present_flag, @@ -164,6 +175,13 @@ static int nvdec_hevc_start_frame(AVCodecContext *avctx, .uniform_spacing_flag = pps->uniform_spacing_flag, .num_tile_columns_minus1 = pps->num_tile_columns - 1, .num_tile_rows_minus1 = pps->num_tile_rows - 1, +#if NVDECAPI_CHECK_VERSION(9, 0) + .pps_range_extension_flag = pps->pps_range_extensions_flag, + .cross_component_prediction_enabled_flag = pps->cross_component_prediction_enabled_flag, + .chroma_qp_offset_list_enabled_flag = pps->chroma_qp_offset_list_enabled_flag, + .diff_cu_chroma_qp_offset_depth = pps->diff_cu_chroma_qp_offset_depth, + .chroma_qp_offset_list_len_minus1 = pps->chroma_qp_offset_list_len_minus1, +#endif .NumBitsForShortTermRPSInSlice = s->sh.short_term_rps ? s->sh.short_term_ref_pic_set_size : 0, .NumDeltaPocsOfRefRpsIdx = s->sh.short_term_rps ? s->sh.short_term_rps->rps_idx_num_delta_pocs : 0, @@ -185,6 +203,18 @@ static int nvdec_hevc_start_frame(AVCodecContext *avctx, for (i = 0; i < pps->num_tile_rows; i++) ppc->row_height_minus1[i] = pps->row_height[i] - 1; +#if NVDECAPI_CHECK_VERSION(9, 0) + if (pps->chroma_qp_offset_list_len_minus1 > FF_ARRAY_ELEMS(ppc->cb_qp_offset_list) || + pps->chroma_qp_offset_list_len_minus1 > FF_ARRAY_ELEMS(ppc->cr_qp_offset_list)) { + av_log(avctx, AV_LOG_ERROR, "Too many chroma_qp_offsets\n"); + return AVERROR(ENOSYS); + } + for (i = 0; i <= pps->chroma_qp_offset_list_len_minus1; i++) { + ppc->cb_qp_offset_list[i] = pps->cb_qp_offset_list[i]; + ppc->cr_qp_offset_list[i] = pps->cr_qp_offset_list[i]; + } +#endif + if (s->rps[LT_CURR].nb_refs > FF_ARRAY_ELEMS(ppc->RefPicSetLtCurr) || s->rps[ST_CURR_BEF].nb_refs > FF_ARRAY_ELEMS(ppc->RefPicSetStCurrBefore) || s->rps[ST_CURR_AFT].nb_refs > FF_ARRAY_ELEMS(ppc->RefPicSetStCurrAfter)) { @@ -269,7 +299,13 @@ static int nvdec_hevc_frame_params(AVCodecContext *avctx, { const HEVCContext *s = avctx->priv_data; const HEVCSPS *sps = s->ps.sps; - return ff_nvdec_frame_params(avctx, hw_frames_ctx, sps->temporal_layer[sps->max_sub_layers - 1].max_dec_pic_buffering + 1); + return ff_nvdec_frame_params(avctx, hw_frames_ctx, sps->temporal_layer[sps->max_sub_layers - 1].max_dec_pic_buffering + 1, 1); +} + +static int nvdec_hevc_decode_init(AVCodecContext *avctx) { + NVDECContext *ctx = avctx->internal->hwaccel_priv_data; + ctx->supports_444 = 1; + return ff_nvdec_decode_init(avctx); } const AVHWAccel ff_hevc_nvdec_hwaccel = { @@ -281,7 +317,7 @@ const AVHWAccel ff_hevc_nvdec_hwaccel = { .end_frame = ff_nvdec_end_frame, .decode_slice = nvdec_hevc_decode_slice, .frame_params = nvdec_hevc_frame_params, - .init = ff_nvdec_decode_init, + .init = nvdec_hevc_decode_init, .uninit = ff_nvdec_decode_uninit, .priv_data_size = sizeof(NVDECContext), }; diff --git a/libavcodec/nvdec_mjpeg.c b/libavcodec/nvdec_mjpeg.c index 7e404246c..be39d23ba 100644 --- a/libavcodec/nvdec_mjpeg.c +++ b/libavcodec/nvdec_mjpeg.c @@ -66,7 +66,7 @@ static int nvdec_mjpeg_frame_params(AVCodecContext *avctx, AVBufferRef *hw_frames_ctx) { // Only need storage for the current frame - return ff_nvdec_frame_params(avctx, hw_frames_ctx, 1); + return ff_nvdec_frame_params(avctx, hw_frames_ctx, 1, 0); } #if CONFIG_MJPEG_NVDEC_HWACCEL diff --git a/libavcodec/nvdec_mpeg12.c b/libavcodec/nvdec_mpeg12.c index 7293d5055..300e1d3d8 100644 --- a/libavcodec/nvdec_mpeg12.c +++ b/libavcodec/nvdec_mpeg12.c @@ -87,7 +87,7 @@ static int nvdec_mpeg12_frame_params(AVCodecContext *avctx, AVBufferRef *hw_frames_ctx) { // Each frame can at most have one P and one B reference - return ff_nvdec_frame_params(avctx, hw_frames_ctx, 2); + return ff_nvdec_frame_params(avctx, hw_frames_ctx, 2, 0); } #if CONFIG_MPEG2_NVDEC_HWACCEL diff --git a/libavcodec/nvdec_mpeg4.c b/libavcodec/nvdec_mpeg4.c index 907af1391..739b04993 100644 --- a/libavcodec/nvdec_mpeg4.c +++ b/libavcodec/nvdec_mpeg4.c @@ -103,7 +103,7 @@ static int nvdec_mpeg4_frame_params(AVCodecContext *avctx, AVBufferRef *hw_frames_ctx) { // Each frame can at most have one P and one B reference - return ff_nvdec_frame_params(avctx, hw_frames_ctx, 2); + return ff_nvdec_frame_params(avctx, hw_frames_ctx, 2, 0); } const AVHWAccel ff_mpeg4_nvdec_hwaccel = { diff --git a/libavcodec/nvdec_vc1.c b/libavcodec/nvdec_vc1.c index 7257692d6..10e7b5ab0 100644 --- a/libavcodec/nvdec_vc1.c +++ b/libavcodec/nvdec_vc1.c @@ -107,7 +107,7 @@ static int nvdec_vc1_frame_params(AVCodecContext *avctx, AVBufferRef *hw_frames_ctx) { // Each frame can at most have one P and one B reference - return ff_nvdec_frame_params(avctx, hw_frames_ctx, 2); + return ff_nvdec_frame_params(avctx, hw_frames_ctx, 2, 0); } const AVHWAccel ff_vc1_nvdec_hwaccel = { diff --git a/libavcodec/nvdec_vp8.c b/libavcodec/nvdec_vp8.c index 7b3744561..9c4608d8c 100644 --- a/libavcodec/nvdec_vp8.c +++ b/libavcodec/nvdec_vp8.c @@ -87,7 +87,7 @@ static int nvdec_vp8_frame_params(AVCodecContext *avctx, AVBufferRef *hw_frames_ctx) { // VP8 uses a fixed size pool of 3 possible reference frames - return ff_nvdec_frame_params(avctx, hw_frames_ctx, 3); + return ff_nvdec_frame_params(avctx, hw_frames_ctx, 3, 0); } AVHWAccel ff_vp8_nvdec_hwaccel = { diff --git a/libavcodec/nvdec_vp9.c b/libavcodec/nvdec_vp9.c index 3b665a9bc..a76bcf994 100644 --- a/libavcodec/nvdec_vp9.c +++ b/libavcodec/nvdec_vp9.c @@ -166,7 +166,7 @@ static int nvdec_vp9_frame_params(AVCodecContext *avctx, AVBufferRef *hw_frames_ctx) { // VP9 uses a fixed size pool of 8 possible reference frames - return ff_nvdec_frame_params(avctx, hw_frames_ctx, 8); + return ff_nvdec_frame_params(avctx, hw_frames_ctx, 8, 0); } const AVHWAccel ff_vp9_nvdec_hwaccel = { diff --git a/libavcodec/nvenc.c b/libavcodec/nvenc.c index c14112c36..3fe64bba8 100644 --- a/libavcodec/nvenc.c +++ b/libavcodec/nvenc.c @@ -25,12 +25,15 @@ #include "libavutil/hwcontext_cuda.h" #include "libavutil/hwcontext.h" +#include "libavutil/cuda_check.h" #include "libavutil/imgutils.h" #include "libavutil/avassert.h" #include "libavutil/mem.h" #include "libavutil/pixdesc.h" #include "internal.h" +#define CHECK_CU(x) FF_CUDA_CHECK_DL(avctx, dl_fn->cuda_dl, x) + #define NVENC_CAP 0x30 #define IS_CBR(rc) (rc == NV_ENC_PARAMS_RC_CBR || \ rc == NV_ENC_PARAMS_RC_CBR_LOWDELAY_HQ || \ @@ -119,7 +122,19 @@ static int nvenc_print_error(void *log_ctx, NVENCSTATUS err, static void nvenc_print_driver_requirement(AVCodecContext *avctx, int level) { -#if NVENCAPI_CHECK_VERSION(8, 1) +#if NVENCAPI_CHECK_VERSION(9, 0) +# if defined(_WIN32) || defined(__CYGWIN__) + const char *minver = "418.81"; +# else + const char *minver = "418.30"; +# endif +#elif NVENCAPI_CHECK_VERSION(8, 2) +# if defined(_WIN32) || defined(__CYGWIN__) + const char *minver = "397.93"; +# else + const char *minver = "396.24"; +#endif +#elif NVENCAPI_CHECK_VERSION(8, 1) # if defined(_WIN32) || defined(__CYGWIN__) const char *minver = "390.77"; # else @@ -183,37 +198,23 @@ static int nvenc_push_context(AVCodecContext *avctx) { NvencContext *ctx = avctx->priv_data; NvencDynLoadFunctions *dl_fn = &ctx->nvenc_dload_funcs; - CUresult cu_res; if (ctx->d3d11_device) return 0; - cu_res = dl_fn->cuda_dl->cuCtxPushCurrent(ctx->cu_context); - if (cu_res != CUDA_SUCCESS) { - av_log(avctx, AV_LOG_ERROR, "cuCtxPushCurrent failed\n"); - return AVERROR_EXTERNAL; - } - - return 0; + return CHECK_CU(dl_fn->cuda_dl->cuCtxPushCurrent(ctx->cu_context)); } static int nvenc_pop_context(AVCodecContext *avctx) { NvencContext *ctx = avctx->priv_data; NvencDynLoadFunctions *dl_fn = &ctx->nvenc_dload_funcs; - CUresult cu_res; CUcontext dummy; if (ctx->d3d11_device) return 0; - cu_res = dl_fn->cuda_dl->cuCtxPopCurrent(&dummy); - if (cu_res != CUDA_SUCCESS) { - av_log(avctx, AV_LOG_ERROR, "cuCtxPopCurrent failed\n"); - return AVERROR_EXTERNAL; - } - - return 0; + return CHECK_CU(dl_fn->cuda_dl->cuCtxPopCurrent(&dummy)); } static av_cold int nvenc_open_session(AVCodecContext *avctx) @@ -394,6 +395,8 @@ static int nvenc_check_capabilities(AVCodecContext *avctx) } #endif + ctx->support_dyn_bitrate = nvenc_check_cap(avctx, NV_ENC_CAPS_SUPPORT_DYN_BITRATE_CHANGE); + return 0; } @@ -404,32 +407,23 @@ static av_cold int nvenc_check_device(AVCodecContext *avctx, int idx) NV_ENCODE_API_FUNCTION_LIST *p_nvenc = &dl_fn->nvenc_funcs; char name[128] = { 0}; int major, minor, ret; - CUresult cu_res; CUdevice cu_device; int loglevel = AV_LOG_VERBOSE; if (ctx->device == LIST_DEVICES) loglevel = AV_LOG_INFO; - cu_res = dl_fn->cuda_dl->cuDeviceGet(&cu_device, idx); - if (cu_res != CUDA_SUCCESS) { - av_log(avctx, AV_LOG_ERROR, - "Cannot access the CUDA device %d\n", - idx); - return -1; - } + ret = CHECK_CU(dl_fn->cuda_dl->cuDeviceGet(&cu_device, idx)); + if (ret < 0) + return ret; - cu_res = dl_fn->cuda_dl->cuDeviceGetName(name, sizeof(name), cu_device); - if (cu_res != CUDA_SUCCESS) { - av_log(avctx, AV_LOG_ERROR, "cuDeviceGetName failed on device %d\n", idx); - return -1; - } + ret = CHECK_CU(dl_fn->cuda_dl->cuDeviceGetName(name, sizeof(name), cu_device)); + if (ret < 0) + return ret; - cu_res = dl_fn->cuda_dl->cuDeviceComputeCapability(&major, &minor, cu_device); - if (cu_res != CUDA_SUCCESS) { - av_log(avctx, AV_LOG_ERROR, "cuDeviceComputeCapability failed on device %d\n", idx); - return -1; - } + ret = CHECK_CU(dl_fn->cuda_dl->cuDeviceComputeCapability(&major, &minor, cu_device)); + if (ret < 0) + return ret; av_log(avctx, loglevel, "[ GPU #%d - < %s > has Compute SM %d.%d ]\n", idx, name, major, minor); if (((major << 4) | minor) < NVENC_CAP) { @@ -440,11 +434,9 @@ static av_cold int nvenc_check_device(AVCodecContext *avctx, int idx) if (ctx->device != idx && ctx->device != ANY_DEVICE) return -1; - cu_res = dl_fn->cuda_dl->cuCtxCreate(&ctx->cu_context_internal, 0, cu_device); - if (cu_res != CUDA_SUCCESS) { - av_log(avctx, AV_LOG_FATAL, "Failed creating CUDA context for NVENC: 0x%x\n", (int)cu_res); + ret = CHECK_CU(dl_fn->cuda_dl->cuCtxCreate(&ctx->cu_context_internal, 0, cu_device)); + if (ret < 0) goto fail; - } ctx->cu_context = ctx->cu_context_internal; @@ -475,7 +467,7 @@ fail3: return ret; fail2: - dl_fn->cuda_dl->cuCtxDestroy(ctx->cu_context_internal); + CHECK_CU(dl_fn->cuda_dl->cuCtxDestroy(ctx->cu_context_internal)); ctx->cu_context_internal = NULL; fail: @@ -553,17 +545,11 @@ static av_cold int nvenc_setup_device(AVCodecContext *avctx) } else { int i, nb_devices = 0; - if ((dl_fn->cuda_dl->cuInit(0)) != CUDA_SUCCESS) { - av_log(avctx, AV_LOG_ERROR, - "Cannot init CUDA\n"); + if (CHECK_CU(dl_fn->cuda_dl->cuInit(0)) < 0) return AVERROR_UNKNOWN; - } - if ((dl_fn->cuda_dl->cuDeviceGetCount(&nb_devices)) != CUDA_SUCCESS) { - av_log(avctx, AV_LOG_ERROR, - "Cannot enumerate the CUDA devices\n"); + if (CHECK_CU(dl_fn->cuda_dl->cuDeviceGetCount(&nb_devices)) < 0) return AVERROR_UNKNOWN; - } if (!nb_devices) { av_log(avctx, AV_LOG_FATAL, "No CUDA capable devices found\n"); @@ -873,7 +859,7 @@ static av_cold void nvenc_setup_rate_control(AVCodecContext *avctx) if (avctx->rc_buffer_size > 0) { ctx->encode_config.rcParams.vbvBufferSize = avctx->rc_buffer_size; } else if (ctx->encode_config.rcParams.averageBitRate > 0) { - ctx->encode_config.rcParams.vbvBufferSize = 2 * ctx->encode_config.rcParams.averageBitRate; + avctx->rc_buffer_size = ctx->encode_config.rcParams.vbvBufferSize = 2 * ctx->encode_config.rcParams.averageBitRate; } if (ctx->aq) { @@ -1096,6 +1082,10 @@ static av_cold int nvenc_setup_hevc_config(AVCodecContext *avctx) hevc->tier = ctx->tier; +#ifdef NVENC_HAVE_HEVC_BFRAME_REF_MODE + hevc->useBFramesAsRef = ctx->b_ref_mode; +#endif + return 0; } @@ -1112,6 +1102,20 @@ static av_cold int nvenc_setup_codec_config(AVCodecContext *avctx) return 0; } +static void compute_dar(AVCodecContext *avctx, int *dw, int *dh) { + int sw, sh; + + sw = avctx->width; + sh = avctx->height; + + if (avctx->sample_aspect_ratio.num > 0 && avctx->sample_aspect_ratio.den > 0) { + sw *= avctx->sample_aspect_ratio.num; + sh *= avctx->sample_aspect_ratio.den; + } + + av_reduce(dw, dh, sw, sh, 1024 * 1024); +} + static av_cold int nvenc_setup_encoder(AVCodecContext *avctx) { NvencContext *ctx = avctx->priv_data; @@ -1148,13 +1152,7 @@ static av_cold int nvenc_setup_encoder(AVCodecContext *avctx) ctx->encode_config.version = NV_ENC_CONFIG_VER; - dw = avctx->width; - dh = avctx->height; - if (avctx->sample_aspect_ratio.num > 0 && avctx->sample_aspect_ratio.den > 0) { - dw*= avctx->sample_aspect_ratio.num; - dh*= avctx->sample_aspect_ratio.den; - } - av_reduce(&dw, &dh, dw, dh, 1024 * 1024); + compute_dar(avctx, &dw, &dh); ctx->init_encode_params.darHeight = dh; ctx->init_encode_params.darWidth = dw; @@ -1450,7 +1448,7 @@ av_cold int ff_nvenc_encode_close(AVCodecContext *avctx) ctx->nvencoder = NULL; if (ctx->cu_context_internal) - dl_fn->cuda_dl->cuCtxDestroy(ctx->cu_context_internal); + CHECK_CU(dl_fn->cuda_dl->cuCtxDestroy(ctx->cu_context_internal)); ctx->cu_context = ctx->cu_context_internal = NULL; #if CONFIG_D3D11VA @@ -1562,19 +1560,23 @@ static int nvenc_find_free_reg_resource(AVCodecContext *avctx) NV_ENCODE_API_FUNCTION_LIST *p_nvenc = &dl_fn->nvenc_funcs; NVENCSTATUS nv_status; - int i; + int i, first_round; if (ctx->nb_registered_frames == FF_ARRAY_ELEMS(ctx->registered_frames)) { - for (i = 0; i < ctx->nb_registered_frames; i++) { - if (!ctx->registered_frames[i].mapped) { - if (ctx->registered_frames[i].regptr) { - nv_status = p_nvenc->nvEncUnregisterResource(ctx->nvencoder, ctx->registered_frames[i].regptr); - if (nv_status != NV_ENC_SUCCESS) - return nvenc_print_error(avctx, nv_status, "Failed unregistering unused input resource"); - ctx->registered_frames[i].ptr = NULL; - ctx->registered_frames[i].regptr = NULL; + for (first_round = 1; first_round >= 0; first_round--) { + for (i = 0; i < ctx->nb_registered_frames; i++) { + if (!ctx->registered_frames[i].mapped) { + if (ctx->registered_frames[i].regptr) { + if (first_round) + continue; + nv_status = p_nvenc->nvEncUnregisterResource(ctx->nvencoder, ctx->registered_frames[i].regptr); + if (nv_status != NV_ENC_SUCCESS) + return nvenc_print_error(avctx, nv_status, "Failed unregistering unused input resource"); + ctx->registered_frames[i].ptr = NULL; + ctx->registered_frames[i].regptr = NULL; + } + return i; } - return i; } } } else { @@ -1702,7 +1704,8 @@ static int nvenc_upload_frame(AVCodecContext *avctx, const AVFrame *frame, } static void nvenc_codec_specific_pic_params(AVCodecContext *avctx, - NV_ENC_PIC_PARAMS *params) + NV_ENC_PIC_PARAMS *params, + NV_ENC_SEI_PAYLOAD *sei_data) { NvencContext *ctx = avctx->priv_data; @@ -1712,12 +1715,22 @@ static void nvenc_codec_specific_pic_params(AVCodecContext *avctx, ctx->encode_config.encodeCodecConfig.h264Config.sliceMode; params->codecPicParams.h264PicParams.sliceModeData = ctx->encode_config.encodeCodecConfig.h264Config.sliceModeData; + if (sei_data) { + params->codecPicParams.h264PicParams.seiPayloadArray = sei_data; + params->codecPicParams.h264PicParams.seiPayloadArrayCnt = 1; + } + break; case AV_CODEC_ID_HEVC: params->codecPicParams.hevcPicParams.sliceMode = ctx->encode_config.encodeCodecConfig.hevcConfig.sliceMode; params->codecPicParams.hevcPicParams.sliceModeData = ctx->encode_config.encodeCodecConfig.hevcConfig.sliceModeData; + if (sei_data) { + params->codecPicParams.hevcPicParams.seiPayloadArray = sei_data; + params->codecPicParams.hevcPicParams.seiPayloadArrayCnt = 1; + } + break; } } @@ -1837,13 +1850,6 @@ static int process_output_surface(AVCodecContext *avctx, AVPacket *pkt, NvencSur res = nvenc_print_error(avctx, nv_status, "Failed unmapping input resource"); goto error; } - nv_status = p_nvenc->nvEncUnregisterResource(ctx->nvencoder, ctx->registered_frames[tmpoutsurf->reg_idx].regptr); - if (nv_status != NV_ENC_SUCCESS) { - res = nvenc_print_error(avctx, nv_status, "Failed unregistering input resource"); - goto error; - } - ctx->registered_frames[tmpoutsurf->reg_idx].ptr = NULL; - ctx->registered_frames[tmpoutsurf->reg_idx].regptr = NULL; } else if (ctx->registered_frames[tmpoutsurf->reg_idx].mapped < 0) { res = AVERROR_BUG; goto error; @@ -1920,11 +1926,105 @@ static int output_ready(AVCodecContext *avctx, int flush) return (nb_ready > 0) && (nb_ready + nb_pending >= ctx->async_depth); } +static void reconfig_encoder(AVCodecContext *avctx, const AVFrame *frame) +{ + NvencContext *ctx = avctx->priv_data; + NV_ENCODE_API_FUNCTION_LIST *p_nvenc = &ctx->nvenc_dload_funcs.nvenc_funcs; + NVENCSTATUS ret; + + NV_ENC_RECONFIGURE_PARAMS params = { 0 }; + int needs_reconfig = 0; + int needs_encode_config = 0; + int reconfig_bitrate = 0, reconfig_dar = 0; + int dw, dh; + + params.version = NV_ENC_RECONFIGURE_PARAMS_VER; + params.reInitEncodeParams = ctx->init_encode_params; + + compute_dar(avctx, &dw, &dh); + if (dw != ctx->init_encode_params.darWidth || dh != ctx->init_encode_params.darHeight) { + av_log(avctx, AV_LOG_VERBOSE, + "aspect ratio change (DAR): %d:%d -> %d:%d\n", + ctx->init_encode_params.darWidth, + ctx->init_encode_params.darHeight, dw, dh); + + params.reInitEncodeParams.darHeight = dh; + params.reInitEncodeParams.darWidth = dw; + + needs_reconfig = 1; + reconfig_dar = 1; + } + + if (ctx->rc != NV_ENC_PARAMS_RC_CONSTQP && ctx->support_dyn_bitrate) { + if (avctx->bit_rate > 0 && params.reInitEncodeParams.encodeConfig->rcParams.averageBitRate != avctx->bit_rate) { + av_log(avctx, AV_LOG_VERBOSE, + "avg bitrate change: %d -> %d\n", + params.reInitEncodeParams.encodeConfig->rcParams.averageBitRate, + (uint32_t)avctx->bit_rate); + + params.reInitEncodeParams.encodeConfig->rcParams.averageBitRate = avctx->bit_rate; + reconfig_bitrate = 1; + } + + if (avctx->rc_max_rate > 0 && ctx->encode_config.rcParams.maxBitRate != avctx->rc_max_rate) { + av_log(avctx, AV_LOG_VERBOSE, + "max bitrate change: %d -> %d\n", + params.reInitEncodeParams.encodeConfig->rcParams.maxBitRate, + (uint32_t)avctx->rc_max_rate); + + params.reInitEncodeParams.encodeConfig->rcParams.maxBitRate = avctx->rc_max_rate; + reconfig_bitrate = 1; + } + + if (avctx->rc_buffer_size > 0 && ctx->encode_config.rcParams.vbvBufferSize != avctx->rc_buffer_size) { + av_log(avctx, AV_LOG_VERBOSE, + "vbv buffer size change: %d -> %d\n", + params.reInitEncodeParams.encodeConfig->rcParams.vbvBufferSize, + avctx->rc_buffer_size); + + params.reInitEncodeParams.encodeConfig->rcParams.vbvBufferSize = avctx->rc_buffer_size; + reconfig_bitrate = 1; + } + + if (reconfig_bitrate) { + params.resetEncoder = 1; + params.forceIDR = 1; + + needs_encode_config = 1; + needs_reconfig = 1; + } + } + + if (!needs_encode_config) + params.reInitEncodeParams.encodeConfig = NULL; + + if (needs_reconfig) { + ret = p_nvenc->nvEncReconfigureEncoder(ctx->nvencoder, ¶ms); + if (ret != NV_ENC_SUCCESS) { + nvenc_print_error(avctx, ret, "failed to reconfigure nvenc"); + } else { + if (reconfig_dar) { + ctx->init_encode_params.darHeight = dh; + ctx->init_encode_params.darWidth = dw; + } + + if (reconfig_bitrate) { + ctx->encode_config.rcParams.averageBitRate = params.reInitEncodeParams.encodeConfig->rcParams.averageBitRate; + ctx->encode_config.rcParams.maxBitRate = params.reInitEncodeParams.encodeConfig->rcParams.maxBitRate; + ctx->encode_config.rcParams.vbvBufferSize = params.reInitEncodeParams.encodeConfig->rcParams.vbvBufferSize; + } + + } + } +} + int ff_nvenc_send_frame(AVCodecContext *avctx, const AVFrame *frame) { NVENCSTATUS nv_status; NvencSurface *tmp_out_surf, *in_surf; int res, res2; + NV_ENC_SEI_PAYLOAD *sei_data = NULL; + size_t sei_size; NvencContext *ctx = avctx->priv_data; NvencDynLoadFunctions *dl_fn = &ctx->nvenc_dload_funcs; @@ -1936,8 +2036,16 @@ int ff_nvenc_send_frame(AVCodecContext *avctx, const AVFrame *frame) if ((!ctx->cu_context && !ctx->d3d11_device) || !ctx->nvencoder) return AVERROR(EINVAL); - if (ctx->encoder_flushing) - return AVERROR_EOF; + if (ctx->encoder_flushing) { + if (avctx->internal->draining) + return AVERROR_EOF; + + ctx->encoder_flushing = 0; + ctx->first_packet_output = 0; + ctx->initial_pts[0] = AV_NOPTS_VALUE; + ctx->initial_pts[1] = AV_NOPTS_VALUE; + av_fifo_reset(ctx->timestamp_list); + } if (frame) { in_surf = get_free_frame(ctx); @@ -1948,6 +2056,8 @@ int ff_nvenc_send_frame(AVCodecContext *avctx, const AVFrame *frame) if (res < 0) return res; + reconfig_encoder(avctx, frame); + res = nvenc_upload_frame(avctx, frame, in_surf); res2 = nvenc_pop_context(avctx); @@ -1982,7 +2092,19 @@ int ff_nvenc_send_frame(AVCodecContext *avctx, const AVFrame *frame) pic_params.inputTimeStamp = frame->pts; - nvenc_codec_specific_pic_params(avctx, &pic_params); + if (ctx->a53_cc && av_frame_get_side_data(frame, AV_FRAME_DATA_A53_CC)) { + if (ff_alloc_a53_sei(frame, sizeof(NV_ENC_SEI_PAYLOAD), (void**)&sei_data, &sei_size) < 0) { + av_log(ctx, AV_LOG_ERROR, "Not enough memory for closed captions, skipping\n"); + } + + if (sei_data) { + sei_data->payloadSize = (uint32_t)sei_size; + sei_data->payloadType = 4; + sei_data->payload = (uint8_t*)(sei_data + 1); + } + } + + nvenc_codec_specific_pic_params(avctx, &pic_params, sei_data); } else { pic_params.encodePicFlags = NV_ENC_PIC_FLAG_EOS; ctx->encoder_flushing = 1; @@ -1993,6 +2115,7 @@ int ff_nvenc_send_frame(AVCodecContext *avctx, const AVFrame *frame) return res; nv_status = p_nvenc->nvEncEncodePicture(ctx->nvencoder, &pic_params); + av_free(sei_data); res = nvenc_pop_context(avctx); if (res < 0) diff --git a/libavcodec/nvenc.h b/libavcodec/nvenc.h index c7506d6a1..ddd616840 100644 --- a/libavcodec/nvenc.h +++ b/libavcodec/nvenc.h @@ -49,6 +49,11 @@ typedef void ID3D11Device; #define NVENC_HAVE_QP_MAP_MODE #endif +// SDK 9.0 compile time feature checks +#if NVENCAPI_CHECK_VERSION(9, 0) +#define NVENC_HAVE_HEVC_BFRAME_REF_MODE +#endif + typedef struct NvencSurface { NV_ENC_INPUT_PTR input_surface; @@ -152,6 +157,8 @@ typedef struct NvencContext int64_t initial_pts[2]; int first_packet_output; + int support_dyn_bitrate; + void *nvencoder; int preset; @@ -184,6 +191,7 @@ typedef struct NvencContext int weighted_pred; int coder; int b_ref_mode; + int a53_cc; } NvencContext; int ff_nvenc_encode_init(AVCodecContext *avctx); diff --git a/libavcodec/nvenc_h264.c b/libavcodec/nvenc_h264.c index d446f9b33..a6623f5f3 100644 --- a/libavcodec/nvenc_h264.c +++ b/libavcodec/nvenc_h264.c @@ -137,6 +137,7 @@ static const AVOption options[] = { { "each", "", 0, AV_OPT_TYPE_CONST, { .i64 = 1 }, 0, 0, VE, "b_ref_mode" }, { "middle", "", 0, AV_OPT_TYPE_CONST, { .i64 = 2 }, 0, 0, VE, "b_ref_mode" }, #endif + { "a53cc", "Use A53 Closed Captions (if available)", OFFSET(a53_cc), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, VE }, { NULL } }; diff --git a/libavcodec/nvenc_hevc.c b/libavcodec/nvenc_hevc.c index 0df7eab8c..d567d960b 100644 --- a/libavcodec/nvenc_hevc.c +++ b/libavcodec/nvenc_hevc.c @@ -116,6 +116,17 @@ static const AVOption options[] = { OFFSET(cqp), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 51, VE }, { "weighted_pred","Set 1 to enable weighted prediction", OFFSET(weighted_pred),AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, VE }, +#ifdef NVENC_HAVE_HEVC_BFRAME_REF_MODE + { "b_ref_mode", "Use B frames as references", OFFSET(b_ref_mode), AV_OPT_TYPE_INT, { .i64 = NV_ENC_BFRAME_REF_MODE_DISABLED }, NV_ENC_BFRAME_REF_MODE_DISABLED, NV_ENC_BFRAME_REF_MODE_MIDDLE, VE, "b_ref_mode" }, + { "disabled", "B frames will not be used for reference", 0, AV_OPT_TYPE_CONST, { .i64 = NV_ENC_BFRAME_REF_MODE_DISABLED }, 0, 0, VE, "b_ref_mode" }, + { "each", "Each B frame will be used for reference", 0, AV_OPT_TYPE_CONST, { .i64 = NV_ENC_BFRAME_REF_MODE_EACH }, 0, 0, VE, "b_ref_mode" }, + { "middle", "Only (number of B frames)/2 will be used for reference", 0,AV_OPT_TYPE_CONST, { .i64 = NV_ENC_BFRAME_REF_MODE_MIDDLE }, 0, 0, VE, "b_ref_mode" }, +#else + { "b_ref_mode", "(not supported)", OFFSET(b_ref_mode), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, VE, "b_ref_mode" }, + { "disabled", "", 0, AV_OPT_TYPE_CONST, { .i64 = 0 }, 0, 0, VE, "b_ref_mode" }, + { "each", "", 0, AV_OPT_TYPE_CONST, { .i64 = 1 }, 0, 0, VE, "b_ref_mode" }, + { "middle", "", 0, AV_OPT_TYPE_CONST, { .i64 = 2 }, 0, 0, VE, "b_ref_mode" }, +#endif { NULL } }; diff --git a/libavcodec/omx.c b/libavcodec/omx.c index 466e0be9f..a555c3c07 100644 --- a/libavcodec/omx.c +++ b/libavcodec/omx.c @@ -100,7 +100,7 @@ static av_cold int omx_try_load(OMXContext *s, void *logctx, if (libname2) { s->lib2 = dlopen(libname2, RTLD_NOW | RTLD_GLOBAL); if (!s->lib2) { - av_log(logctx, AV_LOG_WARNING, "%s not found\n", libname); + av_log(logctx, AV_LOG_WARNING, "%s not found\n", libname2); return AVERROR_ENCODER_NOT_FOUND; } s->host_init = dlsym(s->lib2, "bcm_host_init"); @@ -473,9 +473,9 @@ static av_cold int omx_component_init(AVCodecContext *avctx, const char *role) in_port_params.format.video.nFrameWidth = avctx->width; in_port_params.format.video.nFrameHeight = avctx->height; if (avctx->framerate.den > 0 && avctx->framerate.num > 0) - in_port_params.format.video.xFramerate = (1 << 16) * avctx->framerate.num / avctx->framerate.den; + in_port_params.format.video.xFramerate = (1LL << 16) * avctx->framerate.num / avctx->framerate.den; else - in_port_params.format.video.xFramerate = (1 << 16) * avctx->time_base.den / avctx->time_base.num; + in_port_params.format.video.xFramerate = (1LL << 16) * avctx->time_base.den / avctx->time_base.num; err = OMX_SetParameter(s->handle, OMX_IndexParamPortDefinition, &in_port_params); CHECK(err); @@ -644,10 +644,6 @@ static av_cold int omx_encode_init(AVCodecContext *avctx) OMX_BUFFERHEADERTYPE *buffer; OMX_ERRORTYPE err; -#if CONFIG_OMX_RPI - s->input_zerocopy = 1; -#endif - s->omx_context = omx_init(avctx, s->libname, s->libprefix); if (!s->omx_context) return AVERROR_ENCODER_NOT_FOUND; @@ -739,6 +735,7 @@ static int omx_encode_frame(AVCodecContext *avctx, AVPacket *pkt, int ret = 0; OMX_BUFFERHEADERTYPE* buffer; OMX_ERRORTYPE err; + int had_partial = 0; if (frame) { uint8_t *dst[4]; @@ -830,7 +827,7 @@ static int omx_encode_frame(AVCodecContext *avctx, AVPacket *pkt, // packet, or get EOS. buffer = get_buffer(&s->output_mutex, &s->output_cond, &s->num_done_out_buffers, s->done_out_buffers, - !frame); + !frame || had_partial); if (!buffer) break; @@ -865,6 +862,9 @@ static int omx_encode_frame(AVCodecContext *avctx, AVPacket *pkt, s->output_buf = NULL; s->output_buf_size = 0; } +#if CONFIG_OMX_RPI + had_partial = 1; +#endif } else { // End of frame, and the caller provided a preallocated frame if ((ret = ff_alloc_packet2(avctx, pkt, s->output_buf_size + buffer->nFilledLen, 0)) < 0) { @@ -913,7 +913,7 @@ static av_cold int omx_encode_end(AVCodecContext *avctx) static const AVOption options[] = { { "omx_libname", "OpenMAX library name", OFFSET(libname), AV_OPT_TYPE_STRING, { 0 }, 0, 0, VDE }, { "omx_libprefix", "OpenMAX library prefix", OFFSET(libprefix), AV_OPT_TYPE_STRING, { 0 }, 0, 0, VDE }, - { "zerocopy", "Try to avoid copying input frames if possible", OFFSET(input_zerocopy), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, VE }, + { "zerocopy", "Try to avoid copying input frames if possible", OFFSET(input_zerocopy), AV_OPT_TYPE_INT, { .i64 = CONFIG_OMX_RPI }, 0, 1, VE }, { "profile", "Set the encoding profile", OFFSET(profile), AV_OPT_TYPE_INT, { .i64 = FF_PROFILE_UNKNOWN }, FF_PROFILE_UNKNOWN, FF_PROFILE_H264_HIGH, VE, "profile" }, { "baseline", "", 0, AV_OPT_TYPE_CONST, { .i64 = FF_PROFILE_H264_BASELINE }, 0, 0, VE, "profile" }, { "main", "", 0, AV_OPT_TYPE_CONST, { .i64 = FF_PROFILE_H264_MAIN }, 0, 0, VE, "profile" }, diff --git a/libavcodec/on2avc.c b/libavcodec/on2avc.c index 4e4be7530..00e5bf539 100644 --- a/libavcodec/on2avc.c +++ b/libavcodec/on2avc.c @@ -1018,6 +1018,7 @@ AVCodec ff_on2avc_decoder = { .decode = on2avc_decode_frame, .close = on2avc_decode_close, .capabilities = AV_CODEC_CAP_DR1, + .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, .sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_NONE }, }; diff --git a/libavcodec/options.c b/libavcodec/options.c index 41b60521c..35e8ac931 100644 --- a/libavcodec/options.c +++ b/libavcodec/options.c @@ -347,172 +347,3 @@ const AVClass *avcodec_get_subtitle_rect_class(void) { return &av_subtitle_rect_class; } - -#ifdef TEST -static int dummy_init(AVCodecContext *ctx) -{ - //TODO: this code should set every possible pointer that could be set by codec and is not an option; - ctx->extradata_size = 8; - ctx->extradata = av_malloc(ctx->extradata_size); - return 0; -} - -static int dummy_close(AVCodecContext *ctx) -{ - av_freep(&ctx->extradata); - ctx->extradata_size = 0; - return 0; -} - -static int dummy_encode(AVCodecContext *ctx, AVPacket *pkt, const AVFrame *frame, int *got_packet) -{ - return AVERROR(ENOSYS); -} - -typedef struct Dummy12Context { - AVClass *av_class; - int num; - char* str; -} Dummy12Context; - -typedef struct Dummy3Context { - void *fake_av_class; - int num; - char* str; -} Dummy3Context; - -#define OFFSET(x) offsetof(Dummy12Context, x) -#define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM -static const AVOption dummy_options[] = { - { "str", "set str", OFFSET(str), AV_OPT_TYPE_STRING, { .str = "i'm src default value" }, 0, 0, VE}, - { "num", "set num", OFFSET(num), AV_OPT_TYPE_INT, { .i64 = 1500100900 }, 0, INT_MAX, VE}, - { NULL }, -}; - -static const AVClass dummy_v1_class = { - .class_name = "dummy_v1_class", - .item_name = av_default_item_name, - .option = dummy_options, - .version = LIBAVUTIL_VERSION_INT, -}; - -static const AVClass dummy_v2_class = { - .class_name = "dummy_v2_class", - .item_name = av_default_item_name, - .option = dummy_options, - .version = LIBAVUTIL_VERSION_INT, -}; - -/* codec with options */ -static AVCodec dummy_v1_encoder = { - .name = "dummy_v1_codec", - .type = AVMEDIA_TYPE_VIDEO, - .id = AV_CODEC_ID_NONE - 1, - .encode2 = dummy_encode, - .init = dummy_init, - .close = dummy_close, - .priv_class = &dummy_v1_class, - .priv_data_size = sizeof(Dummy12Context), -}; - -/* codec with options, different class */ -static AVCodec dummy_v2_encoder = { - .name = "dummy_v2_codec", - .type = AVMEDIA_TYPE_VIDEO, - .id = AV_CODEC_ID_NONE - 2, - .encode2 = dummy_encode, - .init = dummy_init, - .close = dummy_close, - .priv_class = &dummy_v2_class, - .priv_data_size = sizeof(Dummy12Context), -}; - -/* codec with priv data, but no class */ -static AVCodec dummy_v3_encoder = { - .name = "dummy_v3_codec", - .type = AVMEDIA_TYPE_VIDEO, - .id = AV_CODEC_ID_NONE - 3, - .encode2 = dummy_encode, - .init = dummy_init, - .close = dummy_close, - .priv_data_size = sizeof(Dummy3Context), -}; - -/* codec without priv data */ -static AVCodec dummy_v4_encoder = { - .name = "dummy_v4_codec", - .type = AVMEDIA_TYPE_VIDEO, - .id = AV_CODEC_ID_NONE - 4, - .encode2 = dummy_encode, - .init = dummy_init, - .close = dummy_close, -}; - -static void test_copy_print_codec(const AVCodecContext *ctx) -{ - printf("%-14s: %dx%d prv: %s", - ctx->codec ? ctx->codec->name : "NULL", - ctx->width, ctx->height, - ctx->priv_data ? "set" : "null"); - if (ctx->codec && ctx->codec->priv_class && ctx->codec->priv_data_size) { - int64_t i64; - char *str = NULL; - av_opt_get_int(ctx->priv_data, "num", 0, &i64); - av_opt_get(ctx->priv_data, "str", 0, (uint8_t**)&str); - printf(" opts: %"PRId64" %s", i64, str); - av_free(str); - } - printf("\n"); -} - -static void test_copy(const AVCodec *c1, const AVCodec *c2) -{ - AVCodecContext *ctx1, *ctx2; - printf("%s -> %s\nclosed:\n", c1 ? c1->name : "NULL", c2 ? c2->name : "NULL"); - ctx1 = avcodec_alloc_context3(c1); - ctx2 = avcodec_alloc_context3(c2); - ctx1->width = ctx1->height = 128; - if (ctx2->codec && ctx2->codec->priv_class && ctx2->codec->priv_data_size) { - av_opt_set(ctx2->priv_data, "num", "667", 0); - av_opt_set(ctx2->priv_data, "str", "i'm dest value before copy", 0); - } - avcodec_copy_context(ctx2, ctx1); - test_copy_print_codec(ctx1); - test_copy_print_codec(ctx2); - if (ctx1->codec) { - printf("opened:\n"); - avcodec_open2(ctx1, ctx1->codec, NULL); - if (ctx2->codec && ctx2->codec->priv_class && ctx2->codec->priv_data_size) { - av_opt_set(ctx2->priv_data, "num", "667", 0); - av_opt_set(ctx2->priv_data, "str", "i'm dest value before copy", 0); - } - avcodec_copy_context(ctx2, ctx1); - test_copy_print_codec(ctx1); - test_copy_print_codec(ctx2); - avcodec_close(ctx1); - } - avcodec_free_context(&ctx1); - avcodec_free_context(&ctx2); -} - -int main(void) -{ - AVCodec *dummy_codec[] = { - &dummy_v1_encoder, - &dummy_v2_encoder, - &dummy_v3_encoder, - &dummy_v4_encoder, - NULL, - }; - int i, j; - - for (i = 0; dummy_codec[i]; i++) - avcodec_register(dummy_codec[i]); - - printf("testing avcodec_copy_context()\n"); - for (i = 0; i < FF_ARRAY_ELEMS(dummy_codec); i++) - for (j = 0; j < FF_ARRAY_ELEMS(dummy_codec); j++) - test_copy(dummy_codec[i], dummy_codec[j]); - return 0; -} -#endif diff --git a/libavcodec/options_table.h b/libavcodec/options_table.h index 099261e16..4a266eca1 100644 --- a/libavcodec/options_table.h +++ b/libavcodec/options_table.h @@ -67,6 +67,8 @@ static const AVOption avcodec_options[] = { {"ilme", "interlaced motion estimation", 0, AV_OPT_TYPE_CONST, {.i64 = AV_CODEC_FLAG_INTERLACED_ME }, INT_MIN, INT_MAX, V|E, "flags"}, {"cgop", "closed GOP", 0, AV_OPT_TYPE_CONST, {.i64 = AV_CODEC_FLAG_CLOSED_GOP }, INT_MIN, INT_MAX, V|E, "flags"}, {"output_corrupt", "Output even potentially corrupted frames", 0, AV_OPT_TYPE_CONST, {.i64 = AV_CODEC_FLAG_OUTPUT_CORRUPT }, INT_MIN, INT_MAX, V|D, "flags"}, +{"drop_changed", "Drop frames whose parameters differ from first decoded frame", 0, AV_OPT_TYPE_CONST, {.i64 = AV_CODEC_FLAG_DROPCHANGED }, INT_MIN, INT_MAX, A|V|D, "flags"}, +{"flags2", NULL, OFFSET(flags2), AV_OPT_TYPE_FLAGS, {.i64 = DEFAULT}, 0, UINT_MAX, V|A|E|D, "flags2"}, {"fast", "allow non-spec-compliant speedup tricks", 0, AV_OPT_TYPE_CONST, {.i64 = AV_CODEC_FLAG2_FAST }, INT_MIN, INT_MAX, V|E, "flags2"}, {"noout", "skip bitstream encoding", 0, AV_OPT_TYPE_CONST, {.i64 = AV_CODEC_FLAG2_NO_OUTPUT }, INT_MIN, INT_MAX, V|E, "flags2"}, {"ignorecrop", "ignore cropping information from sps", 0, AV_OPT_TYPE_CONST, {.i64 = AV_CODEC_FLAG2_IGNORE_CROP }, INT_MIN, INT_MAX, V|D, "flags2"}, @@ -217,34 +219,11 @@ static const AVOption avcodec_options[] = { {"buffers", "picture buffer allocations", 0, AV_OPT_TYPE_CONST, {.i64 = FF_DEBUG_BUFFERS }, INT_MIN, INT_MAX, V|D, "debug"}, {"thread_ops", "threading operations", 0, AV_OPT_TYPE_CONST, {.i64 = FF_DEBUG_THREADS }, INT_MIN, INT_MAX, V|A|D, "debug"}, {"nomc", "skip motion compensation", 0, AV_OPT_TYPE_CONST, {.i64 = FF_DEBUG_NOMC }, INT_MIN, INT_MAX, V|A|D, "debug"}, -{"cmp", "full-pel ME compare function", OFFSET(me_cmp), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, V|E, "cmp_func"}, -{"subcmp", "sub-pel ME compare function", OFFSET(me_sub_cmp), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, V|E, "cmp_func"}, -{"mbcmp", "macroblock compare function", OFFSET(mb_cmp), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, V|E, "cmp_func"}, -{"ildctcmp", "interlaced DCT compare function", OFFSET(ildct_cmp), AV_OPT_TYPE_INT, {.i64 = FF_CMP_VSAD }, INT_MIN, INT_MAX, V|E, "cmp_func"}, {"dia_size", "diamond type & size for motion estimation", OFFSET(dia_size), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, V|E}, {"last_pred", "amount of motion predictors from the previous frame", OFFSET(last_predictor_count), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, V|E}, #if FF_API_PRIVATE_OPT {"preme", "pre motion estimation", OFFSET(pre_me), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, V|E}, #endif -{"precmp", "pre motion estimation compare function", OFFSET(me_pre_cmp), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, V|E, "cmp_func"}, -{"sad", "sum of absolute differences, fast", 0, AV_OPT_TYPE_CONST, {.i64 = FF_CMP_SAD }, INT_MIN, INT_MAX, V|E, "cmp_func"}, -{"sse", "sum of squared errors", 0, AV_OPT_TYPE_CONST, {.i64 = FF_CMP_SSE }, INT_MIN, INT_MAX, V|E, "cmp_func"}, -{"satd", "sum of absolute Hadamard transformed differences", 0, AV_OPT_TYPE_CONST, {.i64 = FF_CMP_SATD }, INT_MIN, INT_MAX, V|E, "cmp_func"}, -{"dct", "sum of absolute DCT transformed differences", 0, AV_OPT_TYPE_CONST, {.i64 = FF_CMP_DCT }, INT_MIN, INT_MAX, V|E, "cmp_func"}, -{"psnr", "sum of squared quantization errors (avoid, low quality)", 0, AV_OPT_TYPE_CONST, {.i64 = FF_CMP_PSNR }, INT_MIN, INT_MAX, V|E, "cmp_func"}, -{"bit", "number of bits needed for the block", 0, AV_OPT_TYPE_CONST, {.i64 = FF_CMP_BIT }, INT_MIN, INT_MAX, V|E, "cmp_func"}, -{"rd", "rate distortion optimal, slow", 0, AV_OPT_TYPE_CONST, {.i64 = FF_CMP_RD }, INT_MIN, INT_MAX, V|E, "cmp_func"}, -{"zero", "0", 0, AV_OPT_TYPE_CONST, {.i64 = FF_CMP_ZERO }, INT_MIN, INT_MAX, V|E, "cmp_func"}, -{"vsad", "sum of absolute vertical differences", 0, AV_OPT_TYPE_CONST, {.i64 = FF_CMP_VSAD }, INT_MIN, INT_MAX, V|E, "cmp_func"}, -{"vsse", "sum of squared vertical differences", 0, AV_OPT_TYPE_CONST, {.i64 = FF_CMP_VSSE }, INT_MIN, INT_MAX, V|E, "cmp_func"}, -{"nsse", "noise preserving sum of squared differences", 0, AV_OPT_TYPE_CONST, {.i64 = FF_CMP_NSSE }, INT_MIN, INT_MAX, V|E, "cmp_func"}, -#if CONFIG_SNOW_ENCODER -{"w53", "5/3 wavelet, only used in snow", 0, AV_OPT_TYPE_CONST, {.i64 = FF_CMP_W53 }, INT_MIN, INT_MAX, V|E, "cmp_func"}, -{"w97", "9/7 wavelet, only used in snow", 0, AV_OPT_TYPE_CONST, {.i64 = FF_CMP_W97 }, INT_MIN, INT_MAX, V|E, "cmp_func"}, -#endif -{"dctmax", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_CMP_DCTMAX }, INT_MIN, INT_MAX, V|E, "cmp_func"}, -{"chroma", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_CMP_CHROMA }, INT_MIN, INT_MAX, V|E, "cmp_func"}, -{"msad", "sum of absolute differences, median predicted", 0, AV_OPT_TYPE_CONST, {.i64 = FF_CMP_MEDIAN_SAD }, INT_MIN, INT_MAX, V|E, "cmp_func"}, {"pre_dia_size", "diamond type & size for motion estimation pre-pass", OFFSET(pre_dia_size), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, V|E}, {"subq", "sub-pel motion estimation quality", OFFSET(me_subpel_quality), AV_OPT_TYPE_INT, {.i64 = 8 }, INT_MIN, INT_MAX, V|E}, {"me_range", "limit motion vectors range (1023 for DivX player)", OFFSET(me_range), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, V|E}, @@ -271,7 +250,6 @@ static const AVOption avcodec_options[] = { {"nr", "noise reduction", OFFSET(noise_reduction), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, V|E}, #endif {"rc_init_occupancy", "number of bits which should be loaded into the rc buffer before decoding starts", OFFSET(rc_initial_buffer_occupancy), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, V|E}, -{"flags2", NULL, OFFSET(flags2), AV_OPT_TYPE_FLAGS, {.i64 = DEFAULT}, 0, UINT_MAX, V|A|E|D, "flags2"}, {"threads", "set the number of threads", OFFSET(thread_count), AV_OPT_TYPE_INT, {.i64 = 1 }, 0, INT_MAX, V|A|E|D, "threads"}, {"auto", "autodetect a suitable number of threads to use", 0, AV_OPT_TYPE_CONST, {.i64 = 0 }, INT_MIN, INT_MAX, V|E|D, "threads"}, {"dc", "intra_dc_precision", OFFSET(intra_dc_precision), AV_OPT_TYPE_INT, {.i64 = 0 }, -8, 16, V|E}, @@ -310,6 +288,29 @@ static const AVOption avcodec_options[] = { {"skip_exp", "frame skip exponent", OFFSET(frame_skip_exp), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, V|E}, {"skipcmp", "frame skip compare function", OFFSET(frame_skip_cmp), AV_OPT_TYPE_INT, {.i64 = FF_CMP_DCTMAX }, INT_MIN, INT_MAX, V|E, "cmp_func"}, #endif +{"cmp", "full-pel ME compare function", OFFSET(me_cmp), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, V|E, "cmp_func"}, +{"subcmp", "sub-pel ME compare function", OFFSET(me_sub_cmp), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, V|E, "cmp_func"}, +{"mbcmp", "macroblock compare function", OFFSET(mb_cmp), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, V|E, "cmp_func"}, +{"ildctcmp", "interlaced DCT compare function", OFFSET(ildct_cmp), AV_OPT_TYPE_INT, {.i64 = FF_CMP_VSAD }, INT_MIN, INT_MAX, V|E, "cmp_func"}, +{"precmp", "pre motion estimation compare function", OFFSET(me_pre_cmp), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, V|E, "cmp_func"}, +{"sad", "sum of absolute differences, fast", 0, AV_OPT_TYPE_CONST, {.i64 = FF_CMP_SAD }, INT_MIN, INT_MAX, V|E, "cmp_func"}, +{"sse", "sum of squared errors", 0, AV_OPT_TYPE_CONST, {.i64 = FF_CMP_SSE }, INT_MIN, INT_MAX, V|E, "cmp_func"}, +{"satd", "sum of absolute Hadamard transformed differences", 0, AV_OPT_TYPE_CONST, {.i64 = FF_CMP_SATD }, INT_MIN, INT_MAX, V|E, "cmp_func"}, +{"dct", "sum of absolute DCT transformed differences", 0, AV_OPT_TYPE_CONST, {.i64 = FF_CMP_DCT }, INT_MIN, INT_MAX, V|E, "cmp_func"}, +{"psnr", "sum of squared quantization errors (avoid, low quality)", 0, AV_OPT_TYPE_CONST, {.i64 = FF_CMP_PSNR }, INT_MIN, INT_MAX, V|E, "cmp_func"}, +{"bit", "number of bits needed for the block", 0, AV_OPT_TYPE_CONST, {.i64 = FF_CMP_BIT }, INT_MIN, INT_MAX, V|E, "cmp_func"}, +{"rd", "rate distortion optimal, slow", 0, AV_OPT_TYPE_CONST, {.i64 = FF_CMP_RD }, INT_MIN, INT_MAX, V|E, "cmp_func"}, +{"zero", "0", 0, AV_OPT_TYPE_CONST, {.i64 = FF_CMP_ZERO }, INT_MIN, INT_MAX, V|E, "cmp_func"}, +{"vsad", "sum of absolute vertical differences", 0, AV_OPT_TYPE_CONST, {.i64 = FF_CMP_VSAD }, INT_MIN, INT_MAX, V|E, "cmp_func"}, +{"vsse", "sum of squared vertical differences", 0, AV_OPT_TYPE_CONST, {.i64 = FF_CMP_VSSE }, INT_MIN, INT_MAX, V|E, "cmp_func"}, +{"nsse", "noise preserving sum of squared differences", 0, AV_OPT_TYPE_CONST, {.i64 = FF_CMP_NSSE }, INT_MIN, INT_MAX, V|E, "cmp_func"}, +#if CONFIG_SNOW_ENCODER +{"w53", "5/3 wavelet, only used in snow", 0, AV_OPT_TYPE_CONST, {.i64 = FF_CMP_W53 }, INT_MIN, INT_MAX, V|E, "cmp_func"}, +{"w97", "9/7 wavelet, only used in snow", 0, AV_OPT_TYPE_CONST, {.i64 = FF_CMP_W97 }, INT_MIN, INT_MAX, V|E, "cmp_func"}, +#endif +{"dctmax", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_CMP_DCTMAX }, INT_MIN, INT_MAX, V|E, "cmp_func"}, +{"chroma", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_CMP_CHROMA }, INT_MIN, INT_MAX, V|E, "cmp_func"}, +{"msad", "sum of absolute differences, median predicted", 0, AV_OPT_TYPE_CONST, {.i64 = FF_CMP_MEDIAN_SAD }, INT_MIN, INT_MAX, V|E, "cmp_func"}, {"mblmin", "minimum macroblock Lagrange factor (VBR)", OFFSET(mb_lmin), AV_OPT_TYPE_INT, {.i64 = FF_QP2LAMBDA * 2 }, 1, FF_LAMBDA_MAX, V|E}, {"mblmax", "maximum macroblock Lagrange factor (VBR)", OFFSET(mb_lmax), AV_OPT_TYPE_INT, {.i64 = FF_QP2LAMBDA * 31 }, 1, FF_LAMBDA_MAX, V|E}, #if FF_API_PRIVATE_OPT @@ -479,6 +480,7 @@ static const AVOption avcodec_options[] = { {"allow_high_depth", "allow to output YUV pixel formats with a different chroma sampling than 4:2:0 and/or other than 8 bits per component", 0, AV_OPT_TYPE_CONST, {.i64 = AV_HWACCEL_FLAG_ALLOW_HIGH_DEPTH }, INT_MIN, INT_MAX, V | D, "hwaccel_flags"}, {"allow_profile_mismatch", "attempt to decode anyway if HW accelerated decoder's supported profiles do not exactly match the stream", 0, AV_OPT_TYPE_CONST, {.i64 = AV_HWACCEL_FLAG_ALLOW_PROFILE_MISMATCH }, INT_MIN, INT_MAX, V | D, "hwaccel_flags"}, {"extra_hw_frames", "Number of extra hardware frames to allocate for the user", OFFSET(extra_hw_frames), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, V|D }, +{"discard_damaged_percentage", "Percentage of damaged samples to discard a frame", OFFSET(discard_damaged_percentage), AV_OPT_TYPE_INT, {.i64 = 95 }, 0, 100, V|D }, {NULL}, }; diff --git a/libavcodec/opus.c b/libavcodec/opus.c index aa827b604..f74278a7e 100644 --- a/libavcodec/opus.c +++ b/libavcodec/opus.c @@ -31,6 +31,7 @@ #include "opus_celt.h" #include "opustab.h" +#include "internal.h" #include "vorbis.h" static const uint16_t opus_frame_duration[32] = { @@ -326,6 +327,8 @@ av_cold int ff_opus_parse_extradata(AVCodecContext *avctx, } avctx->delay = AV_RL16(extradata + 10); + if (avctx->internal) + avctx->internal->skip_samples = avctx->delay; channels = avctx->extradata ? extradata[9] : (avctx->channels == 1) ? 1 : 2; if (!channels) { diff --git a/libavcodec/opus.h b/libavcodec/opus.h index edbaab5ce..63ecd0aff 100644 --- a/libavcodec/opus.h +++ b/libavcodec/opus.h @@ -112,7 +112,7 @@ typedef struct OpusStreamContext { DECLARE_ALIGNED(32, float, celt_buf)[2][960]; float *celt_output[2]; - float redundancy_buf[2][960]; + DECLARE_ALIGNED(32, float, redundancy_buf)[2][960]; float *redundancy_output[2]; /* data buffers for the final output data */ diff --git a/libavcodec/opus_celt.c b/libavcodec/opus_celt.c index 115dd8c63..4655172b0 100644 --- a/libavcodec/opus_celt.c +++ b/libavcodec/opus_celt.c @@ -202,40 +202,10 @@ static void celt_postfilter_apply_transition(CeltBlock *block, float *data) } } -static void celt_postfilter_apply(CeltBlock *block, float *data, int len) -{ - const int T = block->pf_period; - float g0, g1, g2; - float x0, x1, x2, x3, x4; - int i; - - if (block->pf_gains[0] == 0.0 || len <= 0) - return; - - g0 = block->pf_gains[0]; - g1 = block->pf_gains[1]; - g2 = block->pf_gains[2]; - - x4 = data[-T - 2]; - x3 = data[-T - 1]; - x2 = data[-T]; - x1 = data[-T + 1]; - - for (i = 0; i < len; i++) { - x0 = data[i - T + 2]; - data[i] += g0 * x2 + - g1 * (x1 + x3) + - g2 * (x0 + x4); - x4 = x3; - x3 = x2; - x2 = x1; - x1 = x0; - } -} - static void celt_postfilter(CeltFrame *f, CeltBlock *block) { int len = f->blocksize * f->blocks; + const int filter_len = len - 2 * CELT_OVERLAP; celt_postfilter_apply_transition(block, block->buf + 1024); @@ -247,8 +217,11 @@ static void celt_postfilter(CeltFrame *f, CeltBlock *block) if (len > CELT_OVERLAP) { celt_postfilter_apply_transition(block, block->buf + 1024 + CELT_OVERLAP); - celt_postfilter_apply(block, block->buf + 1024 + 2 * CELT_OVERLAP, - len - 2 * CELT_OVERLAP); + + if (block->pf_gains[0] > FLT_EPSILON && filter_len > 0) + f->opusdsp.postfilter(block->buf + 1024 + 2 * CELT_OVERLAP, + block->pf_period, block->pf_gains, + filter_len); block->pf_period_old = block->pf_period; memcpy(block->pf_gains_old, block->pf_gains, sizeof(block->pf_gains)); @@ -462,7 +435,6 @@ int ff_celt_decode_frame(CeltFrame *f, OpusRangeCoder *rc, /* transform and output for each output channel */ for (i = 0; i < f->output_channels; i++) { CeltBlock *block = &f->block[i]; - float m = block->emph_coeff; /* iMDCT and overlap-add */ for (j = 0; j < f->blocks; j++) { @@ -480,14 +452,10 @@ int ff_celt_decode_frame(CeltFrame *f, OpusRangeCoder *rc, /* postfilter */ celt_postfilter(f, block); - /* deemphasis and output scaling */ - for (j = 0; j < frame_size; j++) { - const float tmp = block->buf[1024 - frame_size + j] + m; - m = tmp * CELT_EMPH_COEFF; - output[i][j] = tmp; - } - - block->emph_coeff = m; + /* deemphasis */ + block->emph_coeff = f->opusdsp.deemphasis(output[i], + &block->buf[1024 - frame_size], + block->emph_coeff, frame_size); } if (channels == 1) @@ -596,6 +564,7 @@ int ff_celt_init(AVCodecContext *avctx, CeltFrame **f, int output_channels, goto fail; } + ff_opus_dsp_init(&frm->opusdsp); ff_celt_flush(frm); *f = frm; diff --git a/libavcodec/opus_celt.h b/libavcodec/opus_celt.h index 9289a1867..7c1c5316b 100644 --- a/libavcodec/opus_celt.h +++ b/libavcodec/opus_celt.h @@ -28,6 +28,7 @@ #include "opus.h" #include "opus_pvq.h" +#include "opusdsp.h" #include "mdct15.h" #include "libavutil/float_dsp.h" @@ -40,7 +41,6 @@ #define CELT_NORM_SCALE 16384 #define CELT_QTHETA_OFFSET 4 #define CELT_QTHETA_OFFSET_TWOPHASE 16 -#define CELT_EMPH_COEFF 0.85000610f #define CELT_POSTFILTER_MINPERIOD 15 #define CELT_ENERGY_SILENCE (-28.0f) @@ -96,6 +96,7 @@ struct CeltFrame { AVFloatDSPContext *dsp; CeltBlock block[2]; CeltPVQ *pvq; + OpusDSP opusdsp; int channels; int output_channels; int apply_phase_inv; diff --git a/libavcodec/opus_pvq.c b/libavcodec/opus_pvq.c index 0dbf14184..9c21d6729 100644 --- a/libavcodec/opus_pvq.c +++ b/libavcodec/opus_pvq.c @@ -903,8 +903,8 @@ int av_cold ff_celt_pvq_init(CeltPVQ **pvq, int encode) s->pvq_search = ppp_pvq_search_c; s->quant_band = encode ? pvq_encode_band : pvq_decode_band; - if (ARCH_X86) - ff_opus_dsp_init_x86(s); + if (CONFIG_OPUS_ENCODER && ARCH_X86) + ff_celt_pvq_init_x86(s); *pvq = s; diff --git a/libavcodec/opus_pvq.h b/libavcodec/opus_pvq.h index e2f01a01b..52f9a4e6d 100644 --- a/libavcodec/opus_pvq.h +++ b/libavcodec/opus_pvq.h @@ -40,7 +40,7 @@ struct CeltPVQ { QUANT_FN(*quant_band); }; -void ff_opus_dsp_init_x86(struct CeltPVQ *s); +void ff_celt_pvq_init_x86(struct CeltPVQ *s); int ff_celt_pvq_init(struct CeltPVQ **pvq, int encode); void ff_celt_pvq_uninit(struct CeltPVQ **pvq); diff --git a/libavcodec/opus_rc.c b/libavcodec/opus_rc.c index 3972bb0b0..c432eb90c 100644 --- a/libavcodec/opus_rc.c +++ b/libavcodec/opus_rc.c @@ -167,7 +167,7 @@ void ff_opus_rc_put_raw(OpusRangeCoder *rc, uint32_t val, uint32_t count) rc->rb.cachelen = (rc->rb.cachelen + to_write) % 32; if (!rc->rb.cachelen && count) { - AV_WB32(rc->rb.position, rc->rb.cacheval); + AV_WB32((uint8_t *)rc->rb.position, rc->rb.cacheval); rc->rb.bytes += 4; rc->rb.position -= 4; rc->rb.cachelen = count - to_write; diff --git a/libavcodec/opusdsp.c b/libavcodec/opusdsp.c new file mode 100644 index 000000000..0e179c98c --- /dev/null +++ b/libavcodec/opusdsp.c @@ -0,0 +1,67 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "opusdsp.h" + +static void postfilter_c(float *data, int period, float *gains, int len) +{ + const float g0 = gains[0]; + const float g1 = gains[1]; + const float g2 = gains[2]; + + float x4 = data[-period - 2]; + float x3 = data[-period - 1]; + float x2 = data[-period + 0]; + float x1 = data[-period + 1]; + + for (int i = 0; i < len; i++) { + float x0 = data[i - period + 2]; + data[i] += g0 * x2 + + g1 * (x1 + x3) + + g2 * (x0 + x4); + x4 = x3; + x3 = x2; + x2 = x1; + x1 = x0; + } +} + +static float deemphasis_c(float *y, float *x, float coeff, int len) +{ + float state = coeff; + + for (int i = 0; i < len; i++) { + const float tmp = x[i] + state; + state = tmp * CELT_EMPH_COEFF; + y[i] = tmp; + } + + return state; +} + +av_cold void ff_opus_dsp_init(OpusDSP *ctx) +{ + ctx->postfilter = postfilter_c; + ctx->deemphasis = deemphasis_c; + + if (ARCH_X86) + ff_opus_dsp_init_x86(ctx); + + if (ARCH_AARCH64) + ff_opus_dsp_init_aarch64(ctx); +} diff --git a/libavcodec/opusdsp.h b/libavcodec/opusdsp.h new file mode 100644 index 000000000..ee3186dd4 --- /dev/null +++ b/libavcodec/opusdsp.h @@ -0,0 +1,36 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_OPUSDSP_H +#define AVCODEC_OPUSDSP_H + +#include "libavutil/common.h" + +#define CELT_EMPH_COEFF 0.8500061035f + +typedef struct OpusDSP { + void (*postfilter)(float *data, int period, float *gains, int len); + float (*deemphasis)(float *out, float *in, float coeff, int len); +} OpusDSP; + +void ff_opus_dsp_init(OpusDSP *ctx); + +void ff_opus_dsp_init_x86(OpusDSP *ctx); +void ff_opus_dsp_init_aarch64(OpusDSP *ctx); + +#endif /* AVCODEC_OPUSDSP_H */ diff --git a/libavcodec/opusenc.c b/libavcodec/opusenc.c index 4068c4359..3c08ebcf6 100644 --- a/libavcodec/opusenc.c +++ b/libavcodec/opusenc.c @@ -72,7 +72,7 @@ static void opus_write_extradata(AVCodecContext *avctx) static int opus_gen_toc(OpusEncContext *s, uint8_t *toc, int *size, int *fsize_needed) { - int i, tmp = 0x0, extended_toc = 0; + int tmp = 0x0, extended_toc = 0; static const int toc_cfg[][OPUS_MODE_NB][OPUS_BANDWITH_NB] = { /* Silk Hybrid Celt Layer */ /* NB MB WB SWB FB NB MB WB SWB FB NB MB WB SWB FB Bandwidth */ @@ -102,7 +102,7 @@ static int opus_gen_toc(OpusEncContext *s, uint8_t *toc, int *size, int *fsize_n tmp |= (cfg - 1) << 3; /* codec configuration */ *toc++ = tmp; if (extended_toc) { - for (i = 0; i < (s->packet.frames - 1); i++) + for (int i = 0; i < (s->packet.frames - 1); i++) *fsize_needed |= (s->frame[i].framebits != s->frame[i + 1].framebits); tmp = (*fsize_needed) << 7; /* vbr flag */ tmp |= (0) << 6; /* padding flag */ @@ -115,14 +115,13 @@ static int opus_gen_toc(OpusEncContext *s, uint8_t *toc, int *size, int *fsize_n static void celt_frame_setup_input(OpusEncContext *s, CeltFrame *f) { - int sf, ch; AVFrame *cur = NULL; const int subframesize = s->avctx->frame_size; int subframes = OPUS_BLOCK_SIZE(s->packet.framesize) / subframesize; cur = ff_bufqueue_get(&s->bufqueue); - for (ch = 0; ch < f->channels; ch++) { + for (int ch = 0; ch < f->channels; ch++) { CeltBlock *b = &f->block[ch]; const void *input = cur->extended_data[ch]; size_t bps = av_get_bytes_per_sample(cur->format); @@ -131,13 +130,13 @@ static void celt_frame_setup_input(OpusEncContext *s, CeltFrame *f) av_frame_free(&cur); - for (sf = 0; sf < subframes; sf++) { + for (int sf = 0; sf < subframes; sf++) { if (sf != (subframes - 1)) cur = ff_bufqueue_get(&s->bufqueue); else cur = ff_bufqueue_peek(&s->bufqueue, 0); - for (ch = 0; ch < f->channels; ch++) { + for (int ch = 0; ch < f->channels; ch++) { CeltBlock *b = &f->block[ch]; const void *input = cur->extended_data[ch]; const size_t bps = av_get_bytes_per_sample(cur->format); @@ -156,15 +155,14 @@ static void celt_frame_setup_input(OpusEncContext *s, CeltFrame *f) /* Apply the pre emphasis filter */ static void celt_apply_preemph_filter(OpusEncContext *s, CeltFrame *f) { - int i, sf, ch; const int subframesize = s->avctx->frame_size; const int subframes = OPUS_BLOCK_SIZE(s->packet.framesize) / subframesize; /* Filter overlap */ - for (ch = 0; ch < f->channels; ch++) { + for (int ch = 0; ch < f->channels; ch++) { CeltBlock *b = &f->block[ch]; float m = b->emph_coeff; - for (i = 0; i < CELT_OVERLAP; i++) { + for (int i = 0; i < CELT_OVERLAP; i++) { float sample = b->overlap[i]; b->overlap[i] = sample - m; m = sample * CELT_EMPH_COEFF; @@ -173,11 +171,11 @@ static void celt_apply_preemph_filter(OpusEncContext *s, CeltFrame *f) } /* Filter the samples but do not update the last subframe's coeff - overlap ^^^ */ - for (sf = 0; sf < subframes; sf++) { - for (ch = 0; ch < f->channels; ch++) { + for (int sf = 0; sf < subframes; sf++) { + for (int ch = 0; ch < f->channels; ch++) { CeltBlock *b = &f->block[ch]; float m = b->emph_coeff; - for (i = 0; i < subframesize; i++) { + for (int i = 0; i < subframesize; i++) { float sample = b->samples[sf*subframesize + i]; b->samples[sf*subframesize + i] = sample - m; m = sample * CELT_EMPH_COEFF; @@ -191,14 +189,13 @@ static void celt_apply_preemph_filter(OpusEncContext *s, CeltFrame *f) /* Create the window and do the mdct */ static void celt_frame_mdct(OpusEncContext *s, CeltFrame *f) { - int i, j, t, ch; float *win = s->scratch, *temp = s->scratch + 1920; if (f->transient) { - for (ch = 0; ch < f->channels; ch++) { + for (int ch = 0; ch < f->channels; ch++) { CeltBlock *b = &f->block[ch]; float *src1 = b->overlap; - for (t = 0; t < f->blocks; t++) { + for (int t = 0; t < f->blocks; t++) { float *src2 = &b->samples[CELT_OVERLAP*t]; s->dsp->vector_fmul(win, src1, ff_celt_window, 128); s->dsp->vector_fmul_reverse(&win[CELT_OVERLAP], src2, @@ -211,7 +208,7 @@ static void celt_frame_mdct(OpusEncContext *s, CeltFrame *f) int blk_len = OPUS_BLOCK_SIZE(f->size), wlen = OPUS_BLOCK_SIZE(f->size + 1); int rwin = blk_len - CELT_OVERLAP, lap_dst = (wlen - blk_len - CELT_OVERLAP) >> 1; memset(win, 0, wlen*sizeof(float)); - for (ch = 0; ch < f->channels; ch++) { + for (int ch = 0; ch < f->channels; ch++) { CeltBlock *b = &f->block[ch]; /* Overlap */ @@ -230,21 +227,21 @@ static void celt_frame_mdct(OpusEncContext *s, CeltFrame *f) } } - for (ch = 0; ch < f->channels; ch++) { + for (int ch = 0; ch < f->channels; ch++) { CeltBlock *block = &f->block[ch]; - for (i = 0; i < CELT_MAX_BANDS; i++) { + for (int i = 0; i < CELT_MAX_BANDS; i++) { float ener = 0.0f; int band_offset = ff_celt_freq_bands[i] << f->size; int band_size = ff_celt_freq_range[i] << f->size; float *coeffs = &block->coeffs[band_offset]; - for (j = 0; j < band_size; j++) + for (int j = 0; j < band_size; j++) ener += coeffs[j]*coeffs[j]; block->lin_energy[i] = sqrtf(ener) + FLT_EPSILON; ener = 1.0f/block->lin_energy[i]; - for (j = 0; j < band_size; j++) + for (int j = 0; j < band_size; j++) coeffs[j] *= ener; block->energy[i] = log2f(block->lin_energy[i]) - ff_celt_mean_energy[i]; @@ -257,12 +254,12 @@ static void celt_frame_mdct(OpusEncContext *s, CeltFrame *f) static void celt_enc_tf(CeltFrame *f, OpusRangeCoder *rc) { - int i, tf_select = 0, diff = 0, tf_changed = 0, tf_select_needed; + int tf_select = 0, diff = 0, tf_changed = 0, tf_select_needed; int bits = f->transient ? 2 : 4; tf_select_needed = ((f->size && (opus_rc_tell(rc) + bits + 1) <= f->framebits)); - for (i = f->start_band; i < f->end_band; i++) { + for (int i = f->start_band; i < f->end_band; i++) { if ((opus_rc_tell(rc) + bits + tf_select_needed) <= f->framebits) { const int tbit = (diff ^ 1) == f->tf_change[i]; ff_opus_rc_enc_log(rc, tbit, bits); @@ -278,14 +275,14 @@ static void celt_enc_tf(CeltFrame *f, OpusRangeCoder *rc) tf_select = f->tf_select; } - for (i = f->start_band; i < f->end_band; i++) + for (int i = f->start_band; i < f->end_band; i++) f->tf_change[i] = ff_celt_tf_select[f->size][f->transient][tf_select][f->tf_change[i]]; } static void celt_enc_quant_pfilter(OpusRangeCoder *rc, CeltFrame *f) { float gain = f->pf_gain; - int i, txval, octave = f->pf_octave, period = f->pf_period, tapset = f->pf_tapset; + int txval, octave = f->pf_octave, period = f->pf_period, tapset = f->pf_tapset; ff_opus_rc_enc_log(rc, f->pfilter, 1); if (!f->pfilter) @@ -309,7 +306,7 @@ static void celt_enc_quant_pfilter(OpusRangeCoder *rc, CeltFrame *f) else tapset = 0; /* Finally create the coeffs */ - for (i = 0; i < 2; i++) { + for (int i = 0; i < 2; i++) { CeltBlock *block = &f->block[i]; block->pf_period_new = FFMAX(period, CELT_POSTFILTER_MINPERIOD); @@ -322,7 +319,6 @@ static void celt_enc_quant_pfilter(OpusRangeCoder *rc, CeltFrame *f) static void exp_quant_coarse(OpusRangeCoder *rc, CeltFrame *f, float last_energy[][CELT_MAX_BANDS], int intra) { - int i, ch; float alpha, beta, prev[2] = { 0, 0 }; const uint8_t *pmod = ff_celt_coarse_energy_dist[f->size][intra]; @@ -340,8 +336,8 @@ static void exp_quant_coarse(OpusRangeCoder *rc, CeltFrame *f, beta = ff_celt_beta_coef[f->size]; } - for (i = f->start_band; i < f->end_band; i++) { - for (ch = 0; ch < f->channels; ch++) { + for (int i = f->start_band; i < f->end_band; i++) { + for (int ch = 0; ch < f->channels; ch++) { CeltBlock *block = &f->block[ch]; const int left = f->framebits - opus_rc_tell(rc); const float last = FFMAX(-9.0f, last_energy[ch][i]); @@ -385,11 +381,10 @@ static void celt_quant_coarse(CeltFrame *f, OpusRangeCoder *rc, static void celt_quant_fine(CeltFrame *f, OpusRangeCoder *rc) { - int i, ch; - for (i = f->start_band; i < f->end_band; i++) { + for (int i = f->start_band; i < f->end_band; i++) { if (!f->fine_bits[i]) continue; - for (ch = 0; ch < f->channels; ch++) { + for (int ch = 0; ch < f->channels; ch++) { CeltBlock *block = &f->block[ch]; int quant, lim = (1 << f->fine_bits[i]); float offset, diff = 0.5f - block->error_energy[i]; @@ -403,12 +398,11 @@ static void celt_quant_fine(CeltFrame *f, OpusRangeCoder *rc) static void celt_quant_final(OpusEncContext *s, OpusRangeCoder *rc, CeltFrame *f) { - int i, ch, priority; - for (priority = 0; priority < 2; priority++) { - for (i = f->start_band; i < f->end_band && (f->framebits - opus_rc_tell(rc)) >= f->channels; i++) { + for (int priority = 0; priority < 2; priority++) { + for (int i = f->start_band; i < f->end_band && (f->framebits - opus_rc_tell(rc)) >= f->channels; i++) { if (f->fine_priority[i] != priority || f->fine_bits[i] >= CELT_MAX_FINE_BITS) continue; - for (ch = 0; ch < f->channels; ch++) { + for (int ch = 0; ch < f->channels; ch++) { CeltBlock *block = &f->block[ch]; const float err = block->error_energy[i]; const float offset = 0.5f * (1 << (14 - f->fine_bits[i] - 1)) / 16384.0f; @@ -423,8 +417,6 @@ static void celt_quant_final(OpusEncContext *s, OpusRangeCoder *rc, CeltFrame *f static void celt_encode_frame(OpusEncContext *s, OpusRangeCoder *rc, CeltFrame *f, int index) { - int i, ch; - ff_opus_rc_enc_init(rc); ff_opus_psy_celt_frame_init(&s->psyctx, f, index); @@ -434,7 +426,7 @@ static void celt_encode_frame(OpusEncContext *s, OpusRangeCoder *rc, if (f->silence) { if (f->framebits >= 16) ff_opus_rc_enc_log(rc, 1, 15); /* Silence (if using explicit singalling) */ - for (ch = 0; ch < s->channels; ch++) + for (int ch = 0; ch < s->channels; ch++) memset(s->last_quantized_energy[ch], 0.0f, sizeof(float)*CELT_MAX_BANDS); return; } @@ -480,9 +472,9 @@ static void celt_encode_frame(OpusEncContext *s, OpusRangeCoder *rc, /* Final per-band energy adjustments from leftover bits */ celt_quant_final(s, rc, f); - for (ch = 0; ch < f->channels; ch++) { + for (int ch = 0; ch < f->channels; ch++) { CeltBlock *block = &f->block[ch]; - for (i = 0; i < CELT_MAX_BANDS; i++) + for (int i = 0; i < CELT_MAX_BANDS; i++) s->last_quantized_energy[ch][i] = block->energy[i] + block->error_energy[i]; } } @@ -496,21 +488,21 @@ static inline int write_opuslacing(uint8_t *dst, int v) static void opus_packet_assembler(OpusEncContext *s, AVPacket *avpkt) { - int i, offset, fsize_needed; + int offset, fsize_needed; /* Write toc */ opus_gen_toc(s, avpkt->data, &offset, &fsize_needed); /* Frame sizes if needed */ if (fsize_needed) { - for (i = 0; i < s->packet.frames - 1; i++) { + for (int i = 0; i < s->packet.frames - 1; i++) { offset += write_opuslacing(avpkt->data + offset, s->frame[i].framebits >> 3); } } /* Packets */ - for (i = 0; i < s->packet.frames; i++) { + for (int i = 0; i < s->packet.frames; i++) { ff_opus_rc_enc_end(&s->rc[i], avpkt->data + offset, s->frame[i].framebits >> 3); offset += s->frame[i].framebits >> 3; @@ -522,7 +514,6 @@ static void opus_packet_assembler(OpusEncContext *s, AVPacket *avpkt) /* Used as overlap for the first frame and padding for the last encoded packet */ static AVFrame *spawn_empty_frame(OpusEncContext *s) { - int i; AVFrame *f = av_frame_alloc(); if (!f) return NULL; @@ -533,7 +524,7 @@ static AVFrame *spawn_empty_frame(OpusEncContext *s) av_frame_free(&f); return NULL; } - for (i = 0; i < s->channels; i++) { + for (int i = 0; i < s->channels; i++) { size_t bps = av_get_bytes_per_sample(f->format); memset(f->extended_data[i], 0, bps*f->nb_samples); } @@ -544,7 +535,7 @@ static int opus_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, const AVFrame *frame, int *got_packet_ptr) { OpusEncContext *s = avctx->priv_data; - int i, ret, frame_size, alloc_size = 0; + int ret, frame_size, alloc_size = 0; if (frame) { /* Add new frame to queue */ if ((ret = ff_af_queue_add(&s->afq, frame)) < 0) @@ -552,7 +543,7 @@ static int opus_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, ff_bufqueue_add(avctx, &s->bufqueue, av_frame_clone(frame)); } else { ff_opus_psy_signal_eof(&s->psyctx); - if (!s->afq.remaining_samples) + if (!s->afq.remaining_samples || !avctx->frame_number) return 0; /* We've been flushed and there's nothing left to encode */ } @@ -569,7 +560,7 @@ static int opus_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, * this should only happen at the very last flush frame. The frames * allocated here will be freed (because they have no other references) * after they get used by celt_frame_setup_input() */ - for (i = 0; i < pad_empty; i++) { + for (int i = 0; i < pad_empty; i++) { AVFrame *empty = spawn_empty_frame(s); if (!empty) return AVERROR(ENOMEM); @@ -577,7 +568,7 @@ static int opus_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, } } - for (i = 0; i < s->packet.frames; i++) { + for (int i = 0; i < s->packet.frames; i++) { celt_encode_frame(s, &s->rc[i], &s->frame[i], i); alloc_size += s->frame[i].framebits >> 3; } @@ -610,10 +601,9 @@ static int opus_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, static av_cold int opus_encode_end(AVCodecContext *avctx) { - int i; OpusEncContext *s = avctx->priv_data; - for (i = 0; i < CELT_BLOCK_NB; i++) + for (int i = 0; i < CELT_BLOCK_NB; i++) ff_mdct15_uninit(&s->mdct[i]); ff_celt_pvq_uninit(&s->pvq); @@ -630,7 +620,7 @@ static av_cold int opus_encode_end(AVCodecContext *avctx) static av_cold int opus_encode_init(AVCodecContext *avctx) { - int i, ch, ret, max_frames; + int ret, max_frames; OpusEncContext *s = avctx->priv_data; s->avctx = avctx; @@ -671,12 +661,12 @@ static av_cold int opus_encode_init(AVCodecContext *avctx) return AVERROR(ENOMEM); /* I have no idea why a base scaling factor of 68 works, could be the twiddles */ - for (i = 0; i < CELT_BLOCK_NB; i++) + for (int i = 0; i < CELT_BLOCK_NB; i++) if ((ret = ff_mdct15_init(&s->mdct[i], 0, i + 3, 68 << (CELT_BLOCK_NB - 1 - i)))) return AVERROR(ENOMEM); /* Zero out previous energy (matters for inter first frame) */ - for (ch = 0; ch < s->channels; ch++) + for (int ch = 0; ch < s->channels; ch++) memset(s->last_quantized_energy[ch], 0.0f, sizeof(float)*CELT_MAX_BANDS); /* Allocate an empty frame to use as overlap for the first frame of audio */ @@ -696,7 +686,7 @@ static av_cold int opus_encode_init(AVCodecContext *avctx) if (!s->rc) return AVERROR(ENOMEM); - for (i = 0; i < max_frames; i++) { + for (int i = 0; i < max_frames; i++) { s->frame[i].dsp = s->dsp; s->frame[i].avctx = s->avctx; s->frame[i].seed = 0; diff --git a/libavcodec/pafvideo.c b/libavcodec/pafvideo.c index 7c5861dfa..323c662c5 100644 --- a/libavcodec/pafvideo.c +++ b/libavcodec/pafvideo.c @@ -285,13 +285,14 @@ static int paf_video_decode(AVCodecContext *avctx, void *data, return AVERROR_INVALIDDATA; } + if ((code & 0xF) == 0 && + c->video_size / 32 - (int64_t)bytestream2_get_bytes_left(&c->gb) > c->video_size / 32 * (int64_t)avctx->discard_damaged_percentage / 100) + return AVERROR_INVALIDDATA; + if ((ret = ff_reget_buffer(avctx, c->pic)) < 0) return ret; if (code & 0x20) { // frame is keyframe - for (i = 0; i < 4; i++) - memset(c->frame[i], 0, c->frame_size); - memset(c->pic->data[1], 0, AVPALETTE_SIZE); c->current_frame = 0; c->pic->key_frame = 1; @@ -328,6 +329,10 @@ static int paf_video_decode(AVCodecContext *avctx, void *data, c->pic->palette_has_changed = 1; } + if (code & 0x20) + for (i = 0; i < 4; i++) + memset(c->frame[i], 0, c->frame_size); + switch (code & 0x0F) { case 0: /* Block-based motion compensation using 4x4 blocks with either diff --git a/libavcodec/parser.c b/libavcodec/parser.c index f43b197d5..3e19810a9 100644 --- a/libavcodec/parser.c +++ b/libavcodec/parser.c @@ -27,95 +27,10 @@ #include "libavutil/avassert.h" #include "libavutil/internal.h" #include "libavutil/mem.h" -#include "libavutil/thread.h" #include "internal.h" #include "parser.h" -/* Parsers */ -extern AVCodecParser ff_aac_parser; -extern AVCodecParser ff_aac_latm_parser; -extern AVCodecParser ff_ac3_parser; -extern AVCodecParser ff_adx_parser; -extern AVCodecParser ff_bmp_parser; -extern AVCodecParser ff_cavsvideo_parser; -extern AVCodecParser ff_cook_parser; -extern AVCodecParser ff_dca_parser; -extern AVCodecParser ff_dirac_parser; -extern AVCodecParser ff_dnxhd_parser; -extern AVCodecParser ff_dpx_parser; -extern AVCodecParser ff_dvaudio_parser; -extern AVCodecParser ff_dvbsub_parser; -extern AVCodecParser ff_dvdsub_parser; -extern AVCodecParser ff_dvd_nav_parser; -extern AVCodecParser ff_flac_parser; -extern AVCodecParser ff_g729_parser; -extern AVCodecParser ff_gsm_parser; -extern AVCodecParser ff_h261_parser; -extern AVCodecParser ff_h263_parser; -extern AVCodecParser ff_h264_parser; -extern AVCodecParser ff_hevc_parser; -extern AVCodecParser ff_mjpeg_parser; -extern AVCodecParser ff_mlp_parser; -extern AVCodecParser ff_mpeg4video_parser; -extern AVCodecParser ff_mpegaudio_parser; -extern AVCodecParser ff_mpegvideo_parser; -extern AVCodecParser ff_opus_parser; -extern AVCodecParser ff_png_parser; -extern AVCodecParser ff_pnm_parser; -extern AVCodecParser ff_rv30_parser; -extern AVCodecParser ff_rv40_parser; -extern AVCodecParser ff_sbc_parser; -extern AVCodecParser ff_sipr_parser; -extern AVCodecParser ff_tak_parser; -extern AVCodecParser ff_vc1_parser; -extern AVCodecParser ff_vorbis_parser; -extern AVCodecParser ff_vp3_parser; -extern AVCodecParser ff_vp8_parser; -extern AVCodecParser ff_vp9_parser; -extern AVCodecParser ff_xma_parser; - -#include "libavcodec/parser_list.c" - -static AVOnce av_parser_next_init = AV_ONCE_INIT; - -static void av_parser_init_next(void) -{ - AVCodecParser *prev = NULL, *p; - int i = 0; - while ((p = (AVCodecParser*)parser_list[i++])) { - if (prev) - prev->next = p; - prev = p; - } -} - -AVCodecParser *av_parser_next(const AVCodecParser *p) -{ - ff_thread_once(&av_parser_next_init, av_parser_init_next); - - if (p) - return p->next; - else - return (AVCodecParser*)parser_list[0]; -} - -const AVCodecParser *av_parser_iterate(void **opaque) -{ - uintptr_t i = (uintptr_t)*opaque; - const AVCodecParser *p = parser_list[i]; - - if (p) - *opaque = (void*)(i + 1); - - return p; -} - -void av_register_codec_parser(AVCodecParser *parser) -{ - ff_thread_once(&av_parser_next_init, av_parser_init_next); -} - AVCodecParserContext *av_parser_init(int codec_id) { AVCodecParserContext *s = NULL; @@ -330,6 +245,9 @@ int ff_combine_frame(ParseContext *pc, int next, for (; pc->overread > 0; pc->overread--) pc->buffer[pc->index++] = pc->buffer[pc->overread_index++]; + if (next > *buf_size) + return AVERROR(EINVAL); + /* flush remaining if EOF */ if (!*buf_size && next == END_NOT_FOUND) next = 0; diff --git a/libavcodec/parsers.c b/libavcodec/parsers.c new file mode 100644 index 000000000..33a71de8a --- /dev/null +++ b/libavcodec/parsers.c @@ -0,0 +1,110 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include "libavutil/thread.h" + +#include "avcodec.h" + +extern AVCodecParser ff_aac_parser; +extern AVCodecParser ff_aac_latm_parser; +extern AVCodecParser ff_ac3_parser; +extern AVCodecParser ff_adx_parser; +extern AVCodecParser ff_av1_parser; +extern AVCodecParser ff_avs2_parser; +extern AVCodecParser ff_bmp_parser; +extern AVCodecParser ff_cavsvideo_parser; +extern AVCodecParser ff_cook_parser; +extern AVCodecParser ff_dca_parser; +extern AVCodecParser ff_dirac_parser; +extern AVCodecParser ff_dnxhd_parser; +extern AVCodecParser ff_dpx_parser; +extern AVCodecParser ff_dvaudio_parser; +extern AVCodecParser ff_dvbsub_parser; +extern AVCodecParser ff_dvdsub_parser; +extern AVCodecParser ff_dvd_nav_parser; +extern AVCodecParser ff_flac_parser; +extern AVCodecParser ff_g723_1_parser; +extern AVCodecParser ff_g729_parser; +extern AVCodecParser ff_gif_parser; +extern AVCodecParser ff_gsm_parser; +extern AVCodecParser ff_h261_parser; +extern AVCodecParser ff_h263_parser; +extern AVCodecParser ff_h264_parser; +extern AVCodecParser ff_hevc_parser; +extern AVCodecParser ff_mjpeg_parser; +extern AVCodecParser ff_mlp_parser; +extern AVCodecParser ff_mpeg4video_parser; +extern AVCodecParser ff_mpegaudio_parser; +extern AVCodecParser ff_mpegvideo_parser; +extern AVCodecParser ff_opus_parser; +extern AVCodecParser ff_png_parser; +extern AVCodecParser ff_pnm_parser; +extern AVCodecParser ff_rv30_parser; +extern AVCodecParser ff_rv40_parser; +extern AVCodecParser ff_sbc_parser; +extern AVCodecParser ff_sipr_parser; +extern AVCodecParser ff_tak_parser; +extern AVCodecParser ff_vc1_parser; +extern AVCodecParser ff_vorbis_parser; +extern AVCodecParser ff_vp3_parser; +extern AVCodecParser ff_vp8_parser; +extern AVCodecParser ff_vp9_parser; +extern AVCodecParser ff_xma_parser; + +#include "libavcodec/parser_list.c" + +static AVOnce av_parser_next_init = AV_ONCE_INIT; + +static void av_parser_init_next(void) +{ + AVCodecParser *prev = NULL, *p; + int i = 0; + while ((p = (AVCodecParser*)parser_list[i++])) { + if (prev) + prev->next = p; + prev = p; + } +} + +AVCodecParser *av_parser_next(const AVCodecParser *p) +{ + ff_thread_once(&av_parser_next_init, av_parser_init_next); + + if (p) + return p->next; + else + return (AVCodecParser*)parser_list[0]; +} + +const AVCodecParser *av_parser_iterate(void **opaque) +{ + uintptr_t i = (uintptr_t)*opaque; + const AVCodecParser *p = parser_list[i]; + + if (p) + *opaque = (void*)(i + 1); + + return p; +} + +void av_register_codec_parser(AVCodecParser *parser) +{ + ff_thread_once(&av_parser_next_init, av_parser_init_next); +} diff --git a/libavcodec/pcm-dvdenc.c b/libavcodec/pcm-dvdenc.c new file mode 100644 index 000000000..d26eaf071 --- /dev/null +++ b/libavcodec/pcm-dvdenc.c @@ -0,0 +1,197 @@ +/* + * LPCM codecs for PCM formats found in Video DVD streams + * Copyright (c) 2018 Paul B Mahol + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "avcodec.h" +#include "bytestream.h" +#include "internal.h" + +typedef struct PCMDVDContext { + uint8_t header[3]; // Header added to every frame + int block_size; // Size of a block of samples in bytes + int samples_per_block; // Number of samples per channel per block + int groups_per_block; // Number of 20/24-bit sample groups per block + uint8_t *extra_samples; // Pointer to leftover samples from a frame + int extra_sample_count; // Number of leftover samples in the buffer +} PCMDVDContext; + +static av_cold int pcm_dvd_encode_init(AVCodecContext *avctx) +{ + PCMDVDContext *s = avctx->priv_data; + int quant, freq, frame_size; + + switch (avctx->sample_rate) { + case 48000: + freq = 0; + break; + case 96000: + freq = 1; + break; + } + + switch (avctx->sample_fmt) { + case AV_SAMPLE_FMT_S16: + avctx->bits_per_coded_sample = 16; + quant = 0; + break; + case AV_SAMPLE_FMT_S32: + avctx->bits_per_coded_sample = 24; + quant = 2; + break; + } + + avctx->bits_per_coded_sample = 16 + quant * 4; + avctx->block_align = avctx->channels * avctx->bits_per_coded_sample / 8; + avctx->bit_rate = avctx->block_align * 8LL * avctx->sample_rate; + if (avctx->bit_rate > 9800000) { + av_log(avctx, AV_LOG_ERROR, "Too big bitrate: reduce sample rate, bitdepth or channels.\n"); + return AVERROR(EINVAL); + } + + if (avctx->sample_fmt == AV_SAMPLE_FMT_S16) { + s->samples_per_block = 1; + s->block_size = avctx->channels * 2; + frame_size = 2008 / s->block_size; + } else { + switch (avctx->channels) { + case 1: + case 2: + case 4: + /* one group has all the samples needed */ + s->block_size = 4 * avctx->bits_per_coded_sample / 8; + s->samples_per_block = 4 / avctx->channels; + s->groups_per_block = 1; + break; + case 8: + /* two groups have all the samples needed */ + s->block_size = 8 * avctx->bits_per_coded_sample / 8; + s->samples_per_block = 1; + s->groups_per_block = 2; + break; + default: + /* need avctx->channels groups */ + s->block_size = 4 * avctx->channels * + avctx->bits_per_coded_sample / 8; + s->samples_per_block = 4; + s->groups_per_block = avctx->channels; + break; + } + + frame_size = FFALIGN(2008 / s->block_size, s->samples_per_block); + } + + s->header[0] = 0x0c; + s->header[1] = (quant << 6) | (freq << 4) | (avctx->channels - 1); + s->header[2] = 0x80; + + if (!avctx->frame_size) + avctx->frame_size = frame_size; + + return 0; +} + +static int pcm_dvd_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, + const AVFrame *frame, int *got_packet_ptr) +{ + PCMDVDContext *s = avctx->priv_data; + int samples = frame->nb_samples * avctx->channels; + int64_t pkt_size = (frame->nb_samples / s->samples_per_block) * s->block_size + 3; + int blocks = (pkt_size - 3) / s->block_size; + const int16_t *src16; + const int32_t *src32; + PutByteContext pb; + int ret; + + if ((ret = ff_alloc_packet2(avctx, avpkt, pkt_size, 0)) < 0) + return ret; + + memcpy(avpkt->data, s->header, 3); + + src16 = (const int16_t *)frame->data[0]; + src32 = (const int32_t *)frame->data[0]; + + bytestream2_init_writer(&pb, avpkt->data + 3, avpkt->size - 3); + + switch (avctx->sample_fmt) { + case AV_SAMPLE_FMT_S16: + do { + bytestream2_put_be16(&pb, *src16++); + } while (--samples); + break; + case AV_SAMPLE_FMT_S32: + if (avctx->channels == 1) { + do { + for (int i = 2; i; i--) { + bytestream2_put_be16(&pb, src32[0] >> 16); + bytestream2_put_be16(&pb, src32[1] >> 16); + bytestream2_put_byte(&pb, (*src32++) >> 24); + bytestream2_put_byte(&pb, (*src32++) >> 24); + } + } while (--blocks); + } else { + do { + for (int i = s->groups_per_block; i; i--) { + bytestream2_put_be16(&pb, src32[0] >> 16); + bytestream2_put_be16(&pb, src32[1] >> 16); + bytestream2_put_be16(&pb, src32[2] >> 16); + bytestream2_put_be16(&pb, src32[3] >> 16); + bytestream2_put_byte(&pb, (*src32++) >> 24); + bytestream2_put_byte(&pb, (*src32++) >> 24); + bytestream2_put_byte(&pb, (*src32++) >> 24); + bytestream2_put_byte(&pb, (*src32++) >> 24); + } + } while (--blocks); + } + break; + } + + avpkt->pts = frame->pts; + avpkt->size = pkt_size; + avpkt->duration = ff_samples_to_time_base(avctx, frame->nb_samples); + *got_packet_ptr = 1; + + return 0; +} + +static av_cold int pcm_dvd_encode_close(AVCodecContext *avctx) +{ + return 0; +} + +AVCodec ff_pcm_dvd_encoder = { + .name = "pcm_dvd", + .long_name = NULL_IF_CONFIG_SMALL("PCM signed 16|20|24-bit big-endian for DVD media"), + .type = AVMEDIA_TYPE_AUDIO, + .id = AV_CODEC_ID_PCM_DVD, + .priv_data_size = sizeof(PCMDVDContext), + .init = pcm_dvd_encode_init, + .close = pcm_dvd_encode_close, + .encode2 = pcm_dvd_encode_frame, + .capabilities = AV_CODEC_CAP_SMALL_LAST_FRAME, + .supported_samplerates = (const int[]) { 48000, 96000, 0}, + .channel_layouts = (const uint64_t[]) { AV_CH_LAYOUT_MONO, + AV_CH_LAYOUT_STEREO, + AV_CH_LAYOUT_5POINT1, + AV_CH_LAYOUT_7POINT1, + 0 }, + .sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S16, + AV_SAMPLE_FMT_S32, + AV_SAMPLE_FMT_NONE }, +}; diff --git a/libavcodec/pcm.c b/libavcodec/pcm.c index 8c326c682..ffcbccc77 100644 --- a/libavcodec/pcm.c +++ b/libavcodec/pcm.c @@ -42,6 +42,9 @@ static av_cold int pcm_encode_init(AVCodecContext *avctx) case AV_CODEC_ID_PCM_MULAW: pcm_ulaw_tableinit(); break; + case AV_CODEC_ID_PCM_VIDC: + pcm_vidc_tableinit(); + break; default: break; } @@ -216,6 +219,12 @@ static int pcm_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, *dst++ = linear_to_ulaw[(v + 32768) >> 2]; } break; + case AV_CODEC_ID_PCM_VIDC: + for (; n > 0; n--) { + v = *samples++; + *dst++ = linear_to_vidc[(v + 32768) >> 2]; + } + break; default: return -1; } @@ -249,6 +258,10 @@ static av_cold int pcm_decode_init(AVCodecContext *avctx) for (i = 0; i < 256; i++) s->table[i] = ulaw2linear(i); break; + case AV_CODEC_ID_PCM_VIDC: + for (i = 0; i < 256; i++) + s->table[i] = vidc2linear(i); + break; case AV_CODEC_ID_PCM_F16LE: case AV_CODEC_ID_PCM_F24LE: s->scale = 1. / (1 << (avctx->bits_per_coded_sample - 1)); @@ -485,6 +498,7 @@ static int pcm_decode_frame(AVCodecContext *avctx, void *data, break; case AV_CODEC_ID_PCM_ALAW: case AV_CODEC_ID_PCM_MULAW: + case AV_CODEC_ID_PCM_VIDC: for (; n > 0; n--) { AV_WN16A(samples, s->table[*src++]); samples += 2; @@ -612,3 +626,4 @@ PCM_CODEC (PCM_U32LE, AV_SAMPLE_FMT_S32, pcm_u32le, "PCM unsigned PCM_DECODER(PCM_ZORK, AV_SAMPLE_FMT_U8, pcm_zork, "PCM Zork"); PCM_CODEC (PCM_S64BE, AV_SAMPLE_FMT_S64, pcm_s64be, "PCM signed 64-bit big-endian"); PCM_CODEC (PCM_S64LE, AV_SAMPLE_FMT_S64, pcm_s64le, "PCM signed 64-bit little-endian"); +PCM_CODEC (PCM_VIDC, AV_SAMPLE_FMT_S16, pcm_vidc, "PCM Archimedes VIDC"); diff --git a/libavcodec/pcm_tablegen.c b/libavcodec/pcm_tablegen.c index bf8e7fb70..473a47f6d 100644 --- a/libavcodec/pcm_tablegen.c +++ b/libavcodec/pcm_tablegen.c @@ -29,11 +29,13 @@ int main(void) { pcm_alaw_tableinit(); pcm_ulaw_tableinit(); + pcm_vidc_tableinit(); write_fileheader(); WRITE_ARRAY("static const", uint8_t, linear_to_alaw); WRITE_ARRAY("static const", uint8_t, linear_to_ulaw); + WRITE_ARRAY("static const", uint8_t, linear_to_vidc); return 0; } diff --git a/libavcodec/pcm_tablegen.h b/libavcodec/pcm_tablegen.h index 7ce147f76..d8763abc4 100644 --- a/libavcodec/pcm_tablegen.h +++ b/libavcodec/pcm_tablegen.h @@ -36,6 +36,12 @@ #define BIAS (0x84) /* Bias for linear code. */ +#define VIDC_SIGN_BIT (1) +#define VIDC_QUANT_MASK (0x1E) +#define VIDC_QUANT_SHIFT (1) +#define VIDC_SEG_SHIFT (5) +#define VIDC_SEG_MASK (0xE0) + /* alaw2linear() - Convert an A-law value to 16-bit linear PCM */ static av_cold int alaw2linear(unsigned char a_val) { @@ -69,14 +75,30 @@ static av_cold int ulaw2linear(unsigned char u_val) return (u_val & SIGN_BIT) ? (BIAS - t) : (t - BIAS); } +static av_cold int vidc2linear(unsigned char u_val) +{ + int t; + + /* + * Extract and bias the quantization bits. Then + * shift up by the segment number and subtract out the bias. + */ + t = (((u_val & VIDC_QUANT_MASK) >> VIDC_QUANT_SHIFT) << 3) + BIAS; + t <<= ((unsigned)u_val & VIDC_SEG_MASK) >> VIDC_SEG_SHIFT; + + return (u_val & VIDC_SIGN_BIT) ? (BIAS - t) : (t - BIAS); +} + #if CONFIG_HARDCODED_TABLES #define pcm_alaw_tableinit() #define pcm_ulaw_tableinit() +#define pcm_vidc_tableinit() #include "libavcodec/pcm_tables.h" #else /* 16384 entries per table */ static uint8_t linear_to_alaw[16384]; static uint8_t linear_to_ulaw[16384]; +static uint8_t linear_to_vidc[16384]; static av_cold void build_xlaw_table(uint8_t *linear_to_xlaw, int (*xlaw2linear)(unsigned char), @@ -111,6 +133,11 @@ static void pcm_ulaw_tableinit(void) { build_xlaw_table(linear_to_ulaw, ulaw2linear, 0xff); } + +static void pcm_vidc_tableinit(void) +{ + build_xlaw_table(linear_to_vidc, vidc2linear, 0xff); +} #endif /* CONFIG_HARDCODED_TABLES */ #endif /* AVCODEC_PCM_TABLEGEN_H */ diff --git a/libavcodec/pcx.c b/libavcodec/pcx.c index 58a5e1e06..4505db75b 100644 --- a/libavcodec/pcx.c +++ b/libavcodec/pcx.c @@ -30,7 +30,7 @@ #define PCX_HEADER_SIZE 128 -static void pcx_rle_decode(GetByteContext *gb, +static int pcx_rle_decode(GetByteContext *gb, uint8_t *dst, unsigned int bytes_per_scanline, int compressed) @@ -38,6 +38,9 @@ static void pcx_rle_decode(GetByteContext *gb, unsigned int i = 0; unsigned char run, value; + if (bytestream2_get_bytes_left(gb) < 1) + return AVERROR_INVALIDDATA; + if (compressed) { while (i < bytes_per_scanline && bytestream2_get_bytes_left(gb)>0) { run = 1; @@ -52,6 +55,7 @@ static void pcx_rle_decode(GetByteContext *gb, } else { bytestream2_get_buffer(gb, dst, bytes_per_scanline); } + return 0; } static void pcx_palette(GetByteContext *gb, uint32_t *dst, int pallen) @@ -153,7 +157,9 @@ static int pcx_decode_frame(AVCodecContext *avctx, void *data, int *got_frame, if (nplanes == 3 && bits_per_pixel == 8) { for (y = 0; y < h; y++) { - pcx_rle_decode(&gb, scanline, bytes_per_scanline, compressed); + ret = pcx_rle_decode(&gb, scanline, bytes_per_scanline, compressed); + if (ret < 0) + goto end; for (x = 0; x < w; x++) { ptr[3 * x] = scanline[x]; @@ -174,7 +180,9 @@ static int pcx_decode_frame(AVCodecContext *avctx, void *data, int *got_frame, } for (y = 0; y < h; y++, ptr += stride) { - pcx_rle_decode(&gb, scanline, bytes_per_scanline, compressed); + ret = pcx_rle_decode(&gb, scanline, bytes_per_scanline, compressed); + if (ret < 0) + goto end; memcpy(ptr, scanline, w); } @@ -194,7 +202,9 @@ static int pcx_decode_frame(AVCodecContext *avctx, void *data, int *got_frame, for (y = 0; y < h; y++) { init_get_bits8(&s, scanline, bytes_per_scanline); - pcx_rle_decode(&gb, scanline, bytes_per_scanline, compressed); + ret = pcx_rle_decode(&gb, scanline, bytes_per_scanline, compressed); + if (ret < 0) + goto end; for (x = 0; x < w; x++) ptr[x] = get_bits(&s, bits_per_pixel); @@ -204,7 +214,9 @@ static int pcx_decode_frame(AVCodecContext *avctx, void *data, int *got_frame, int i; for (y = 0; y < h; y++) { - pcx_rle_decode(&gb, scanline, bytes_per_scanline, compressed); + ret = pcx_rle_decode(&gb, scanline, bytes_per_scanline, compressed); + if (ret < 0) + goto end; for (x = 0; x < w; x++) { int m = 0x80 >> (x & 7), v = 0; diff --git a/libavcodec/pictordec.c b/libavcodec/pictordec.c index b29a48453..2e6fcdca5 100644 --- a/libavcodec/pictordec.c +++ b/libavcodec/pictordec.c @@ -63,29 +63,37 @@ static void picmemset(PicContext *s, AVFrame *frame, unsigned value, int run, uint8_t *d; int shift = *plane * bits_per_plane; unsigned mask = ((1U << bits_per_plane) - 1) << shift; + int xl = *x; + int yl = *y; + int planel = *plane; value <<= shift; + d = frame->data[0] + yl * frame->linesize[0]; while (run > 0) { int j; for (j = 8-bits_per_plane; j >= 0; j -= bits_per_plane) { - d = frame->data[0] + *y * frame->linesize[0]; - d[*x] |= (value >> j) & mask; - *x += 1; - if (*x == s->width) { - *y -= 1; - *x = 0; - if (*y < 0) { - *y = s->height - 1; - *plane += 1; - if (*plane >= s->nb_planes) - return; + d[xl] |= (value >> j) & mask; + xl += 1; + if (xl == s->width) { + yl -= 1; + xl = 0; + if (yl < 0) { + yl = s->height - 1; + planel += 1; + if (planel >= s->nb_planes) + goto end; value <<= bits_per_plane; mask <<= bits_per_plane; } + d = frame->data[0] + yl * frame->linesize[0]; } } run--; } +end: + *x = xl; + *y = yl; + *plane = planel; } static const uint8_t cga_mode45_index[6][4] = { @@ -236,6 +244,9 @@ static int decode_frame(AVCodecContext *avctx, } } + if (s->nb_planes - plane > 1) + return AVERROR_INVALIDDATA; + if (plane < s->nb_planes && x < avctx->width) { int run = (y + 1) * avctx->width - x; if (bits_per_plane == 8) diff --git a/libavcodec/pngdec.c b/libavcodec/pngdec.c index f761f2f7d..cad579654 100644 --- a/libavcodec/pngdec.c +++ b/libavcodec/pngdec.c @@ -446,7 +446,7 @@ static int decode_zbuf(AVBPrint *bp, const uint8_t *data, return AVERROR_EXTERNAL; zstream.next_in = (unsigned char *)data; zstream.avail_in = data_end - data; - av_bprint_init(bp, 0, -1); + av_bprint_init(bp, 0, AV_BPRINT_SIZE_UNLIMITED); while (zstream.avail_in > 0) { av_bprint_get_buffer(bp, 2, &buf, &buf_size); @@ -1319,7 +1319,7 @@ static int decode_frame_common(AVCodecContext *avctx, PNGDecContext *s, char *gamma_str; int num = bytestream2_get_be32(&s->gb); - av_bprint_init(&bp, 0, -1); + av_bprint_init(&bp, 0, AV_BPRINT_SIZE_UNLIMITED); av_bprintf(&bp, "%i/%i", num, 100000); ret = av_bprint_finalize(&bp, &gamma_str); if (ret < 0) @@ -1391,6 +1391,9 @@ exit_loop: if (CONFIG_PNG_DECODER && avctx->codec_id != AV_CODEC_ID_APNG) handle_p_frame_png(s, p); else if (CONFIG_APNG_DECODER && + s->previous_picture.f->width == p->width && + s->previous_picture.f->height== p->height && + s->previous_picture.f->format== p->format && avctx->codec_id == AV_CODEC_ID_APNG && (ret = handle_p_frame_apng(avctx, s, p)) < 0) goto fail; @@ -1525,6 +1528,146 @@ end: } #endif +#if CONFIG_LSCR_DECODER +static int decode_frame_lscr(AVCodecContext *avctx, + void *data, int *got_frame, + AVPacket *avpkt) +{ + PNGDecContext *const s = avctx->priv_data; + GetByteContext *gb = &s->gb; + AVFrame *frame = data; + int ret, nb_blocks, offset = 0; + + if (avpkt->size < 2) + return AVERROR_INVALIDDATA; + + bytestream2_init(gb, avpkt->data, avpkt->size); + + if ((ret = ff_get_buffer(avctx, frame, AV_GET_BUFFER_FLAG_REF)) < 0) + return ret; + + nb_blocks = bytestream2_get_le16(gb); + if (bytestream2_get_bytes_left(gb) < 2 + nb_blocks * (12 + 8)) + return AVERROR_INVALIDDATA; + + if (s->last_picture.f->data[0]) { + ret = av_frame_copy(frame, s->last_picture.f); + if (ret < 0) + return ret; + } + + for (int b = 0; b < nb_blocks; b++) { + int x, y, x2, y2, w, h, left; + uint32_t csize, size; + + s->zstream.zalloc = ff_png_zalloc; + s->zstream.zfree = ff_png_zfree; + s->zstream.opaque = NULL; + + if ((ret = inflateInit(&s->zstream)) != Z_OK) { + av_log(avctx, AV_LOG_ERROR, "inflateInit returned error %d\n", ret); + ret = AVERROR_EXTERNAL; + goto end; + } + + bytestream2_seek(gb, 2 + b * 12, SEEK_SET); + + x = bytestream2_get_le16(gb); + y = bytestream2_get_le16(gb); + x2 = bytestream2_get_le16(gb); + y2 = bytestream2_get_le16(gb); + s->width = s->cur_w = w = x2-x; + s->height = s->cur_h = h = y2-y; + + if (w <= 0 || x < 0 || x >= avctx->width || w + x > avctx->width || + h <= 0 || y < 0 || y >= avctx->height || h + y > avctx->height) { + ret = AVERROR_INVALIDDATA; + goto end; + } + + size = bytestream2_get_le32(gb); + + frame->key_frame = (nb_blocks == 1) && + (w == avctx->width) && + (h == avctx->height) && + (x == 0) && (y == 0); + + bytestream2_seek(gb, 2 + nb_blocks * 12 + offset, SEEK_SET); + csize = bytestream2_get_be32(gb); + if (bytestream2_get_le32(gb) != MKTAG('I', 'D', 'A', 'T')) { + ret = AVERROR_INVALIDDATA; + goto end; + } + + offset += size; + left = size; + + s->y = 0; + s->row_size = w * 3; + + av_fast_padded_malloc(&s->buffer, &s->buffer_size, s->row_size + 16); + if (!s->buffer) { + ret = AVERROR(ENOMEM); + goto end; + } + + av_fast_padded_malloc(&s->last_row, &s->last_row_size, s->row_size); + if (!s->last_row) { + ret = AVERROR(ENOMEM); + goto end; + } + + s->crow_size = w * 3 + 1; + s->crow_buf = s->buffer + 15; + s->zstream.avail_out = s->crow_size; + s->zstream.next_out = s->crow_buf; + s->image_buf = frame->data[0] + (avctx->height - y - 1) * frame->linesize[0] + x * 3; + s->image_linesize =-frame->linesize[0]; + s->bpp = 3; + s->pic_state = 0; + + while (left > 16) { + ret = png_decode_idat(s, csize); + if (ret < 0) + goto end; + left -= csize + 16; + if (left > 16) { + bytestream2_skip(gb, 4); + csize = bytestream2_get_be32(gb); + if (bytestream2_get_le32(gb) != MKTAG('I', 'D', 'A', 'T')) { + ret = AVERROR_INVALIDDATA; + goto end; + } + } + } + + inflateEnd(&s->zstream); + } + + frame->pict_type = frame->key_frame ? AV_PICTURE_TYPE_I : AV_PICTURE_TYPE_P; + + av_frame_unref(s->last_picture.f); + if ((ret = av_frame_ref(s->last_picture.f, frame)) < 0) + return ret; + + *got_frame = 1; +end: + inflateEnd(&s->zstream); + + if (ret < 0) + return ret; + return avpkt->size; +} + +static void decode_flush(AVCodecContext *avctx) +{ + PNGDecContext *s = avctx->priv_data; + + av_frame_unref(s->last_picture.f); +} + +#endif + #if HAVE_THREADS static int update_thread_context(AVCodecContext *dst, const AVCodecContext *src) { @@ -1581,6 +1724,9 @@ static av_cold int png_dec_init(AVCodecContext *avctx) avctx->color_range = AVCOL_RANGE_JPEG; + if (avctx->codec_id == AV_CODEC_ID_LSCR) + avctx->pix_fmt = AV_PIX_FMT_BGR24; + s->avctx = avctx; s->previous_picture.f = av_frame_alloc(); s->last_picture.f = av_frame_alloc(); @@ -1653,3 +1799,19 @@ AVCodec ff_png_decoder = { .caps_internal = FF_CODEC_CAP_SKIP_FRAME_FILL_PARAM | FF_CODEC_CAP_INIT_THREADSAFE, }; #endif + +#if CONFIG_LSCR_DECODER +AVCodec ff_lscr_decoder = { + .name = "lscr", + .long_name = NULL_IF_CONFIG_SMALL("LEAD Screen Capture"), + .type = AVMEDIA_TYPE_VIDEO, + .id = AV_CODEC_ID_LSCR, + .priv_data_size = sizeof(PNGDecContext), + .init = png_dec_init, + .close = png_dec_end, + .decode = decode_frame_lscr, + .flush = decode_flush, + .capabilities = AV_CODEC_CAP_DR1 /*| AV_CODEC_CAP_DRAW_HORIZ_BAND*/, + .caps_internal = FF_CODEC_CAP_SKIP_FRAME_FILL_PARAM | FF_CODEC_CAP_INIT_THREADSAFE, +}; +#endif diff --git a/libavcodec/pngenc.c b/libavcodec/pngenc.c index 69b449540..d4d8dc8b5 100644 --- a/libavcodec/pngenc.c +++ b/libavcodec/pngenc.c @@ -748,11 +748,11 @@ static int apng_encode_frame(AVCodecContext *avctx, const AVFrame *pict, original_bytestream_end = s->bytestream_end; temp_bytestream = av_malloc(original_bytestream_end - original_bytestream); - temp_bytestream_end = temp_bytestream + (original_bytestream_end - original_bytestream); if (!temp_bytestream) { ret = AVERROR(ENOMEM); goto fail; } + temp_bytestream_end = temp_bytestream + (original_bytestream_end - original_bytestream); for (last_fctl_chunk.dispose_op = 0; last_fctl_chunk.dispose_op < 3; ++last_fctl_chunk.dispose_op) { // 0: APNG_DISPOSE_OP_NONE diff --git a/libavcodec/pnm.c b/libavcodec/pnm.c index b06a6e81b..a9771710c 100644 --- a/libavcodec/pnm.c +++ b/libavcodec/pnm.c @@ -36,13 +36,15 @@ static void pnm_get(PNMContext *sc, char *str, int buf_size) { char *s; int c; + uint8_t *bs = sc->bytestream; + const uint8_t *end = sc->bytestream_end; /* skip spaces and comments */ - while (sc->bytestream < sc->bytestream_end) { - c = *sc->bytestream++; + while (bs < end) { + c = *bs++; if (c == '#') { - while (c != '\n' && sc->bytestream < sc->bytestream_end) { - c = *sc->bytestream++; + while (c != '\n' && bs < end) { + c = *bs++; } } else if (!pnm_space(c)) { break; @@ -50,12 +52,14 @@ static void pnm_get(PNMContext *sc, char *str, int buf_size) } s = str; - while (sc->bytestream < sc->bytestream_end && !pnm_space(c)) { - if ((s - str) < buf_size - 1) - *s++ = c; - c = *sc->bytestream++; + while (bs < end && !pnm_space(c) && (s - str) < buf_size - 1) { + *s++ = c; + c = *bs++; } *s = '\0'; + while (bs < end && !pnm_space(c)) + c = *bs++; + sc->bytestream = bs; } int ff_pnm_decode_header(AVCodecContext *avctx, PNMContext * const s) diff --git a/libavcodec/pnm_parser.c b/libavcodec/pnm_parser.c index bdd7f2b50..5339bebde 100644 --- a/libavcodec/pnm_parser.c +++ b/libavcodec/pnm_parser.c @@ -19,23 +19,42 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "libavutil/avassert.h" #include "libavutil/imgutils.h" #include "parser.h" //for ParseContext #include "pnm.h" +typedef struct PNMParseContext { + ParseContext pc; + int remaining_bytes; + int ascii_scan; +}PNMParseContext; static int pnm_parse(AVCodecParserContext *s, AVCodecContext *avctx, const uint8_t **poutbuf, int *poutbuf_size, const uint8_t *buf, int buf_size) { - ParseContext *pc = s->priv_data; + PNMParseContext *pnmpc = s->priv_data; + ParseContext *pc = &pnmpc->pc; PNMContext pnmctx; - int next; + int next = END_NOT_FOUND; + int skip = 0; for (; pc->overread > 0; pc->overread--) { pc->buffer[pc->index++]= pc->buffer[pc->overread_index++]; } + + if (pnmpc->remaining_bytes) { + int inc = FFMIN(pnmpc->remaining_bytes, buf_size); + skip += inc; + pnmpc->remaining_bytes -= inc; + + if (!pnmpc->remaining_bytes) + next = skip; + goto end; + } + retry: if (pc->index) { pnmctx.bytestream_start = @@ -43,31 +62,57 @@ retry: pnmctx.bytestream_end = pc->buffer + pc->index; } else { pnmctx.bytestream_start = - pnmctx.bytestream = (uint8_t *) buf; /* casts avoid warnings */ - pnmctx.bytestream_end = (uint8_t *) buf + buf_size; + pnmctx.bytestream = (uint8_t *) buf + skip; /* casts avoid warnings */ + pnmctx.bytestream_end = (uint8_t *) buf + buf_size - skip; } if (ff_pnm_decode_header(avctx, &pnmctx) < 0) { if (pnmctx.bytestream < pnmctx.bytestream_end) { if (pc->index) { pc->index = 0; + pnmpc->ascii_scan = 0; } else { - buf++; - buf_size--; + unsigned step = FFMAX(1, pnmctx.bytestream - pnmctx.bytestream_start); + + skip += step; } goto retry; } - next = END_NOT_FOUND; } else if (pnmctx.type < 4) { - next = END_NOT_FOUND; - } else { - next = pnmctx.bytestream - pnmctx.bytestream_start - + av_image_get_buffer_size(avctx->pix_fmt, avctx->width, avctx->height, 1); - if (pnmctx.bytestream_start != buf) - next -= pc->index; - if (next > buf_size) - next = END_NOT_FOUND; - } + uint8_t *bs = pnmctx.bytestream; + const uint8_t *end = pnmctx.bytestream_end; + uint8_t *sync = bs; + if (pc->index) { + av_assert0(pnmpc->ascii_scan <= end - bs); + bs += pnmpc->ascii_scan; + } + + while (bs < end) { + int c; + sync = bs; + c = *bs++; + if (c == '#') { + while (c != '\n' && bs < end) + c = *bs++; + } else if (c == 'P') { + next = bs - pnmctx.bytestream_start + skip - 1; + pnmpc->ascii_scan = 0; + break; + } + } + if (next == END_NOT_FOUND) + pnmpc->ascii_scan = sync - pnmctx.bytestream + skip; + } else { + next = pnmctx.bytestream - pnmctx.bytestream_start + skip + + av_image_get_buffer_size(avctx->pix_fmt, avctx->width, avctx->height, 1); + } + if (next != END_NOT_FOUND && pnmctx.bytestream_start != buf + skip) + next -= pc->index; + if (next > buf_size) { + pnmpc->remaining_bytes = next - buf_size; + next = END_NOT_FOUND; + } +end: if (ff_combine_frame(pc, next, &buf, &buf_size) < 0) { *poutbuf = NULL; *poutbuf_size = 0; @@ -81,7 +126,7 @@ retry: AVCodecParser ff_pnm_parser = { .codec_ids = { AV_CODEC_ID_PGM, AV_CODEC_ID_PGMYUV, AV_CODEC_ID_PPM, AV_CODEC_ID_PBM, AV_CODEC_ID_PAM }, - .priv_data_size = sizeof(ParseContext), + .priv_data_size = sizeof(PNMParseContext), .parser_parse = pnm_parse, .parser_close = ff_parse_close, }; diff --git a/libavcodec/ppc/h264dsp.c b/libavcodec/ppc/h264dsp.c index f510544dd..d8a3baa34 100644 --- a/libavcodec/ppc/h264dsp.c +++ b/libavcodec/ppc/h264dsp.c @@ -625,7 +625,7 @@ static inline vec_u8 h264_deblock_q1(register vec_u8 p0, q1 = newq1; \ } -static void h264_v_loop_filter_luma_altivec(uint8_t *pix, int stride, int alpha, int beta, int8_t *tc0) { +static void h264_v_loop_filter_luma_altivec(uint8_t *pix, ptrdiff_t stride, int alpha, int beta, int8_t *tc0) { if ((tc0[0] & tc0[1] & tc0[2] & tc0[3]) >= 0) { register vec_u8 p2 = vec_ld(-3*stride, pix); @@ -642,7 +642,7 @@ static void h264_v_loop_filter_luma_altivec(uint8_t *pix, int stride, int alpha, } } -static void h264_h_loop_filter_luma_altivec(uint8_t *pix, int stride, int alpha, int beta, int8_t *tc0) { +static void h264_h_loop_filter_luma_altivec(uint8_t *pix, ptrdiff_t stride, int alpha, int beta, int8_t *tc0) { register vec_u8 line0, line1, line2, line3, line4, line5; if ((tc0[0] & tc0[1] & tc0[2] & tc0[3]) < 0) diff --git a/libavcodec/ppc/hevcdsp.c b/libavcodec/ppc/hevcdsp.c index 42a5bc487..c1d562a40 100644 --- a/libavcodec/ppc/hevcdsp.c +++ b/libavcodec/ppc/hevcdsp.c @@ -41,8 +41,9 @@ static const vec_u8 mask[2] = { { 0x04, 0x05, 0x0C, 0x0D, 0x14, 0x15, 0x1C, 0x1D, 0x06, 0x07, 0x0E, 0x0F, 0x16, 0x17, 0x1E, 0x1F }, }; -static void transform4x4(vec_s16 src_01, vec_s16 src_23, vec_s32 res[4], - const int shift, int16_t *coeffs) +static av_always_inline void transform4x4(vec_s16 src_01, vec_s16 src_23, + vec_s32 res[4], const int shift, + int16_t *coeffs) { vec_s16 src_02, src_13; vec_s32 zero = vec_splat_s32(0); @@ -73,7 +74,8 @@ static void transform4x4(vec_s16 src_01, vec_s16 src_23, vec_s32 res[4], res[3] = vec_sub(e0, o0); } -static void scale(vec_s32 res[4], vec_s16 res_packed[2], int shift) +static av_always_inline void scale(vec_s32 res[4], vec_s16 res_packed[2], + const int shift) { int i; vec_u32 v_shift; diff --git a/libavcodec/profiles.c b/libavcodec/profiles.c index d7dc960f3..eaf0d68d3 100644 --- a/libavcodec/profiles.c +++ b/libavcodec/profiles.c @@ -30,7 +30,6 @@ const AVProfile ff_aac_profiles[] = { { FF_PROFILE_AAC_LD, "LD" }, { FF_PROFILE_AAC_ELD, "ELD" }, { FF_PROFILE_AAC_MAIN, "Main" }, - { FF_PROFILE_AAC_LOW, "LC" }, { FF_PROFILE_AAC_SSR, "SSR" }, { FF_PROFILE_AAC_LTP, "LTP" }, { FF_PROFILE_UNKNOWN }, @@ -152,4 +151,29 @@ const AVProfile ff_sbc_profiles[] = { { FF_PROFILE_UNKNOWN }, }; +const AVProfile ff_prores_profiles[] = { + { FF_PROFILE_PRORES_PROXY, "Proxy" }, + { FF_PROFILE_PRORES_LT, "LT" }, + { FF_PROFILE_PRORES_STANDARD, "Standard" }, + { FF_PROFILE_PRORES_HQ, "HQ" }, + { FF_PROFILE_PRORES_4444, "4444" }, + { FF_PROFILE_PRORES_XQ, "XQ" }, + { FF_PROFILE_UNKNOWN } +}; + +const AVProfile ff_mjpeg_profiles[] = { + { FF_PROFILE_MJPEG_HUFFMAN_BASELINE_DCT, "Baseline" }, + { FF_PROFILE_MJPEG_HUFFMAN_EXTENDED_SEQUENTIAL_DCT, "Sequential" }, + { FF_PROFILE_MJPEG_HUFFMAN_PROGRESSIVE_DCT, "Progressive" }, + { FF_PROFILE_MJPEG_HUFFMAN_LOSSLESS, "Lossless" }, + { FF_PROFILE_MJPEG_JPEG_LS, "JPEG LS" }, + { FF_PROFILE_UNKNOWN } +}; + +const AVProfile ff_arib_caption_profiles[] = { + { FF_PROFILE_ARIB_PROFILE_A, "Profile A" }, + { FF_PROFILE_ARIB_PROFILE_C, "Profile C" }, + { FF_PROFILE_UNKNOWN } +}; + #endif /* !CONFIG_SMALL */ diff --git a/libavcodec/profiles.h b/libavcodec/profiles.h index 9d7e211e1..a53b67e7f 100644 --- a/libavcodec/profiles.h +++ b/libavcodec/profiles.h @@ -33,5 +33,8 @@ extern const AVProfile ff_vc1_profiles[]; extern const AVProfile ff_vp9_profiles[]; extern const AVProfile ff_av1_profiles[]; extern const AVProfile ff_sbc_profiles[]; +extern const AVProfile ff_prores_profiles[]; +extern const AVProfile ff_mjpeg_profiles[]; +extern const AVProfile ff_arib_caption_profiles[]; #endif /* AVCODEC_PROFILES_H */ diff --git a/libavcodec/prores_metadata_bsf.c b/libavcodec/prores_metadata_bsf.c new file mode 100644 index 000000000..0510d3520 --- /dev/null +++ b/libavcodec/prores_metadata_bsf.c @@ -0,0 +1,172 @@ +/* + * Prores Metadata bitstream filter + * Copyright (c) 2018 Jokyo Images + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * Prores Metadata bitstream filter + * set frame colorspace property + */ + +#include "libavutil/common.h" +#include "libavutil/intreadwrite.h" +#include "libavutil/opt.h" +#include "bsf.h" + +typedef struct ProresMetadataContext { + const AVClass *class; + + int color_primaries; + int transfer_characteristics; + int matrix_coefficients; +} ProresMetadataContext; + +static int prores_metadata(AVBSFContext *bsf, AVPacket *pkt) +{ + ProresMetadataContext *ctx = bsf->priv_data; + int ret = 0; + int buf_size; + uint8_t *buf; + + ret = ff_bsf_get_packet_ref(bsf, pkt); + if (ret < 0) + return ret; + + ret = av_packet_make_writable(pkt); + if (ret < 0) + goto fail; + + buf = pkt->data; + buf_size = pkt->size; + + /* check start of the prores frame */ + if (buf_size < 28) { + av_log(bsf, AV_LOG_ERROR, "not enough data in prores frame\n"); + ret = AVERROR_INVALIDDATA; + goto fail; + } + + if (AV_RL32(buf + 4) != AV_RL32("icpf")) { + av_log(bsf, AV_LOG_ERROR, "invalid frame header\n"); + ret = AVERROR_INVALIDDATA; + goto fail; + } + + if (AV_RB16(buf + 8) < 28) { + av_log(bsf, AV_LOG_ERROR, "invalid frame header size\n"); + ret = AVERROR_INVALIDDATA; + goto fail; + } + + /* set the new values */ + if (ctx->color_primaries != -1) + buf[8+14] = ctx->color_primaries; + if (ctx->transfer_characteristics != -1) + buf[8+15] = ctx->transfer_characteristics; + if (ctx->matrix_coefficients != -1) + buf[8+16] = ctx->matrix_coefficients; + +fail: + if (ret < 0) + av_packet_unref(pkt); + return ret; +} + +static const enum AVCodecID codec_ids[] = { + AV_CODEC_ID_PRORES, AV_CODEC_ID_NONE, +}; + +static int prores_metadata_init(AVBSFContext *bsf) +{ + ProresMetadataContext *ctx = bsf->priv_data; + /*! check options */ + switch (ctx->color_primaries) { + case -1: + case 0: + case AVCOL_PRI_BT709: + case AVCOL_PRI_BT470BG: + case AVCOL_PRI_SMPTE170M: + case AVCOL_PRI_BT2020: + case AVCOL_PRI_SMPTE431: + case AVCOL_PRI_SMPTE432: + break; + default: + av_log(bsf, AV_LOG_ERROR, "Color primaries %d is not a valid value\n", ctx->color_primaries); + return AVERROR(EINVAL); + } + + switch (ctx->matrix_coefficients) { + case -1: + case 0: + case AVCOL_SPC_BT709: + case AVCOL_SPC_SMPTE170M: + case AVCOL_SPC_BT2020_NCL: + break; + default: + av_log(bsf, AV_LOG_ERROR, "Colorspace %d is not a valid value\n", ctx->matrix_coefficients); + return AVERROR(EINVAL); + } + + return 0; +} + +#define OFFSET(x) offsetof(ProresMetadataContext, x) +#define FLAGS (AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_BSF_PARAM) +static const AVOption options[] = { + {"color_primaries", "select color primaries", OFFSET(color_primaries), AV_OPT_TYPE_INT, {.i64=-1}, -1, AVCOL_PRI_SMPTE432, FLAGS, "color_primaries"}, + {"auto", "keep the same color primaries", 0, AV_OPT_TYPE_CONST, {.i64=-1}, INT_MIN, INT_MAX, FLAGS, "color_primaries"}, + {"unknown", NULL, 0, AV_OPT_TYPE_CONST, {.i64=0}, INT_MIN, INT_MAX, FLAGS, "color_primaries"}, + {"bt709", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_PRI_BT709}, INT_MIN, INT_MAX, FLAGS, "color_primaries"}, + {"bt470bg", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_PRI_BT470BG}, INT_MIN, INT_MAX, FLAGS, "color_primaries"}, + {"smpte170m", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_PRI_SMPTE170M}, INT_MIN, INT_MAX, FLAGS, "color_primaries"}, + {"bt2020", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_PRI_BT2020}, INT_MIN, INT_MAX, FLAGS, "color_primaries"}, + {"smpte431", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_PRI_SMPTE431}, INT_MIN, INT_MAX, FLAGS, "color_primaries"}, + {"smpte432", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_PRI_SMPTE432}, INT_MIN, INT_MAX, FLAGS, "color_primaries"}, + + {"color_trc", "select color transfer", OFFSET(transfer_characteristics), AV_OPT_TYPE_INT, {.i64=-1}, -1, AVCOL_TRC_BT709, FLAGS, "color_trc"}, + {"auto", "keep the same color transfer", 0, AV_OPT_TYPE_CONST, {.i64=-1}, INT_MIN, INT_MAX, FLAGS, "color_trc"}, + {"unknown", NULL, 0, AV_OPT_TYPE_CONST, {.i64=0}, INT_MIN, INT_MAX, FLAGS, "color_trc"}, + {"bt709", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_BT709}, INT_MIN, INT_MAX, FLAGS, "color_trc"}, + + {"colorspace", "select colorspace", OFFSET(matrix_coefficients), AV_OPT_TYPE_INT, {.i64=-1}, -1, AVCOL_SPC_BT2020_NCL, FLAGS, "colorspace"}, + {"auto", "keep the same colorspace", 0, AV_OPT_TYPE_CONST, {.i64=-1}, INT_MIN, INT_MAX, FLAGS, "colorspace"}, + {"unknown", NULL, 0, AV_OPT_TYPE_CONST, {.i64=0}, INT_MIN, INT_MAX, FLAGS, "colorspace"}, + {"bt709", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_SPC_BT709}, INT_MIN, INT_MAX, FLAGS, "colorspace"}, + {"smpte170m", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_SPC_SMPTE170M}, INT_MIN, INT_MAX, FLAGS, "colorspace"}, + {"bt2020nc", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_SPC_BT2020_NCL}, INT_MIN, INT_MAX, FLAGS, "colorspace"}, + + { NULL }, +}; + +static const AVClass prores_metadata_class = { + .class_name = "prores_metadata_bsf", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; + +const AVBitStreamFilter ff_prores_metadata_bsf = { + .name = "prores_metadata", + .init = prores_metadata_init, + .filter = prores_metadata, + .priv_data_size = sizeof(ProresMetadataContext), + .priv_class = &prores_metadata_class, + .codec_ids = codec_ids, +}; diff --git a/libavcodec/proresdec.h b/libavcodec/proresdec.h index 14ede5d16..06e41dd09 100644 --- a/libavcodec/proresdec.h +++ b/libavcodec/proresdec.h @@ -22,6 +22,7 @@ #ifndef AVCODEC_PRORESDEC_H #define AVCODEC_PRORESDEC_H +#include "get_bits.h" #include "blockdsp.h" #include "proresdsp.h" @@ -50,6 +51,7 @@ typedef struct { const uint8_t *scan; int first_field; int alpha_info; + void (*unpack_alpha)(GetBitContext *gb, uint16_t *dst, int num_coeffs, const int num_bits); } ProresContext; #endif /* AVCODEC_PRORESDEC_H */ diff --git a/libavcodec/proresdec2.c b/libavcodec/proresdec2.c index d97e264e4..2652a31c8 100644 --- a/libavcodec/proresdec2.c +++ b/libavcodec/proresdec2.c @@ -33,9 +33,11 @@ #include "get_bits.h" #include "idctdsp.h" #include "internal.h" +#include "profiles.h" #include "simple_idct.h" #include "proresdec.h" #include "proresdata.h" +#include "thread.h" static void permute(uint8_t *dst, const uint8_t *src, const uint8_t permutation[64]) { @@ -44,15 +46,138 @@ static void permute(uint8_t *dst, const uint8_t *src, const uint8_t permutation[ dst[i] = permutation[src[i]]; } +#define ALPHA_SHIFT_16_TO_10(alpha_val) (alpha_val >> 6) +#define ALPHA_SHIFT_8_TO_10(alpha_val) ((alpha_val << 2) | (alpha_val >> 6)) +#define ALPHA_SHIFT_16_TO_12(alpha_val) (alpha_val >> 4) +#define ALPHA_SHIFT_8_TO_12(alpha_val) ((alpha_val << 4) | (alpha_val >> 4)) + +static void inline unpack_alpha(GetBitContext *gb, uint16_t *dst, int num_coeffs, + const int num_bits, const int decode_precision) { + const int mask = (1 << num_bits) - 1; + int i, idx, val, alpha_val; + + idx = 0; + alpha_val = mask; + do { + do { + if (get_bits1(gb)) { + val = get_bits(gb, num_bits); + } else { + int sign; + val = get_bits(gb, num_bits == 16 ? 7 : 4); + sign = val & 1; + val = (val + 2) >> 1; + if (sign) + val = -val; + } + alpha_val = (alpha_val + val) & mask; + if (num_bits == 16) { + if (decode_precision == 10) { + dst[idx++] = ALPHA_SHIFT_16_TO_10(alpha_val); + } else { /* 12b */ + dst[idx++] = ALPHA_SHIFT_16_TO_12(alpha_val); + } + } else { + if (decode_precision == 10) { + dst[idx++] = ALPHA_SHIFT_8_TO_10(alpha_val); + } else { /* 12b */ + dst[idx++] = ALPHA_SHIFT_8_TO_12(alpha_val); + } + } + if (idx >= num_coeffs) + break; + } while (get_bits_left(gb)>0 && get_bits1(gb)); + val = get_bits(gb, 4); + if (!val) + val = get_bits(gb, 11); + if (idx + val > num_coeffs) + val = num_coeffs - idx; + if (num_bits == 16) { + for (i = 0; i < val; i++) { + if (decode_precision == 10) { + dst[idx++] = ALPHA_SHIFT_16_TO_10(alpha_val); + } else { /* 12b */ + dst[idx++] = ALPHA_SHIFT_16_TO_12(alpha_val); + } + } + } else { + for (i = 0; i < val; i++) { + if (decode_precision == 10) { + dst[idx++] = ALPHA_SHIFT_8_TO_10(alpha_val); + } else { /* 12b */ + dst[idx++] = ALPHA_SHIFT_8_TO_12(alpha_val); + } + } + } + } while (idx < num_coeffs); +} + +static void unpack_alpha_10(GetBitContext *gb, uint16_t *dst, int num_coeffs, + const int num_bits) +{ + if (num_bits == 16) { + unpack_alpha(gb, dst, num_coeffs, 16, 10); + } else { /* 8 bits alpha */ + unpack_alpha(gb, dst, num_coeffs, 8, 10); + } +} + +static void unpack_alpha_12(GetBitContext *gb, uint16_t *dst, int num_coeffs, + const int num_bits) +{ + if (num_bits == 16) { + unpack_alpha(gb, dst, num_coeffs, 16, 12); + } else { /* 8 bits alpha */ + unpack_alpha(gb, dst, num_coeffs, 8, 12); + } +} + static av_cold int decode_init(AVCodecContext *avctx) { + int ret = 0; ProresContext *ctx = avctx->priv_data; uint8_t idct_permutation[64]; avctx->bits_per_raw_sample = 10; + switch (avctx->codec_tag) { + case MKTAG('a','p','c','o'): + avctx->profile = FF_PROFILE_PRORES_PROXY; + break; + case MKTAG('a','p','c','s'): + avctx->profile = FF_PROFILE_PRORES_LT; + break; + case MKTAG('a','p','c','n'): + avctx->profile = FF_PROFILE_PRORES_STANDARD; + break; + case MKTAG('a','p','c','h'): + avctx->profile = FF_PROFILE_PRORES_HQ; + break; + case MKTAG('a','p','4','h'): + avctx->profile = FF_PROFILE_PRORES_4444; + avctx->bits_per_raw_sample = 12; + break; + case MKTAG('a','p','4','x'): + avctx->profile = FF_PROFILE_PRORES_XQ; + avctx->bits_per_raw_sample = 12; + break; + default: + avctx->profile = FF_PROFILE_UNKNOWN; + av_log(avctx, AV_LOG_WARNING, "Unknown prores profile %d\n", avctx->codec_tag); + } + + if (avctx->bits_per_raw_sample == 10) { + av_log(avctx, AV_LOG_DEBUG, "Auto bitdepth precision. Use 10b decoding based on codec tag.\n"); + } else { /* 12b */ + av_log(avctx, AV_LOG_DEBUG, "Auto bitdepth precision. Use 12b decoding based on codec tag.\n"); + } + ff_blockdsp_init(&ctx->bdsp, avctx); - ff_proresdsp_init(&ctx->prodsp, avctx); + ret = ff_proresdsp_init(&ctx->prodsp, avctx); + if (ret < 0) { + av_log(avctx, AV_LOG_ERROR, "Fail to init proresdsp for bits per raw sample %d\n", avctx->bits_per_raw_sample); + return ret; + } ff_init_scantable_permutation(idct_permutation, ctx->prodsp.idct_permutation_type); @@ -60,7 +185,15 @@ static av_cold int decode_init(AVCodecContext *avctx) permute(ctx->progressive_scan, ff_prores_progressive_scan, idct_permutation); permute(ctx->interlaced_scan, ff_prores_interlaced_scan, idct_permutation); - return 0; + if (avctx->bits_per_raw_sample == 10){ + ctx->unpack_alpha = unpack_alpha_10; + } else if (avctx->bits_per_raw_sample == 12){ + ctx->unpack_alpha = unpack_alpha_12; + } else { + av_log(avctx, AV_LOG_ERROR, "Fail to set unpack_alpha for bits per raw sample %d\n", avctx->bits_per_raw_sample); + return AVERROR_BUG; + } + return ret; } static int decode_frame_header(ProresContext *ctx, const uint8_t *buf, @@ -86,10 +219,14 @@ static int decode_frame_header(ProresContext *ctx, const uint8_t *buf, width = AV_RB16(buf + 8); height = AV_RB16(buf + 10); + if (width != avctx->width || height != avctx->height) { - av_log(avctx, AV_LOG_ERROR, "picture resolution change: %dx%d -> %dx%d\n", + int ret; + + av_log(avctx, AV_LOG_WARNING, "picture resolution change: %dx%d -> %dx%d\n", avctx->width, avctx->height, width, height); - return AVERROR_PATCHWELCOME; + if ((ret = ff_set_dimensions(avctx, width, height)) < 0) + return ret; } ctx->frame_type = (buf[12] >> 2) & 3; @@ -112,11 +249,24 @@ static int decode_frame_header(ProresContext *ctx, const uint8_t *buf, } if (ctx->alpha_info) { - avctx->pix_fmt = (buf[12] & 0xC0) == 0xC0 ? AV_PIX_FMT_YUVA444P10 : AV_PIX_FMT_YUVA422P10; + if (avctx->bits_per_raw_sample == 10) { + avctx->pix_fmt = (buf[12] & 0xC0) == 0xC0 ? AV_PIX_FMT_YUVA444P10 : AV_PIX_FMT_YUVA422P10; + } else { /* 12b */ + avctx->pix_fmt = (buf[12] & 0xC0) == 0xC0 ? AV_PIX_FMT_YUVA444P12 : AV_PIX_FMT_YUVA422P12; + } } else { - avctx->pix_fmt = (buf[12] & 0xC0) == 0xC0 ? AV_PIX_FMT_YUV444P10 : AV_PIX_FMT_YUV422P10; + if (avctx->bits_per_raw_sample == 10) { + avctx->pix_fmt = (buf[12] & 0xC0) == 0xC0 ? AV_PIX_FMT_YUV444P10 : AV_PIX_FMT_YUV422P10; + } else { /* 12b */ + avctx->pix_fmt = (buf[12] & 0xC0) == 0xC0 ? AV_PIX_FMT_YUV444P12 : AV_PIX_FMT_YUV422P12; + } } + avctx->color_primaries = buf[14]; + avctx->color_trc = buf[15]; + avctx->colorspace = buf[16]; + avctx->color_range = AVCOL_RANGE_MPEG; + ptr = buf + 20; flags = buf[19]; ff_dlog(avctx, "flags %x\n", flags); @@ -430,51 +580,6 @@ static int decode_slice_chroma(AVCodecContext *avctx, SliceContext *slice, return 0; } -static void unpack_alpha(GetBitContext *gb, uint16_t *dst, int num_coeffs, - const int num_bits) -{ - const int mask = (1 << num_bits) - 1; - int i, idx, val, alpha_val; - - idx = 0; - alpha_val = mask; - do { - do { - if (get_bits1(gb)) { - val = get_bits(gb, num_bits); - } else { - int sign; - val = get_bits(gb, num_bits == 16 ? 7 : 4); - sign = val & 1; - val = (val + 2) >> 1; - if (sign) - val = -val; - } - alpha_val = (alpha_val + val) & mask; - if (num_bits == 16) { - dst[idx++] = alpha_val >> 6; - } else { - dst[idx++] = (alpha_val << 2) | (alpha_val >> 6); - } - if (idx >= num_coeffs) - break; - } while (get_bits_left(gb)>0 && get_bits1(gb)); - val = get_bits(gb, 4); - if (!val) - val = get_bits(gb, 11); - if (idx + val > num_coeffs) - val = num_coeffs - idx; - if (num_bits == 16) { - for (i = 0; i < val; i++) - dst[idx++] = alpha_val >> 6; - } else { - for (i = 0; i < val; i++) - dst[idx++] = (alpha_val << 2) | (alpha_val >> 6); - - } - } while (idx < num_coeffs); -} - /** * Decode alpha slice plane. */ @@ -494,12 +599,13 @@ static void decode_slice_alpha(ProresContext *ctx, init_get_bits(&gb, buf, buf_size << 3); if (ctx->alpha_info == 2) { - unpack_alpha(&gb, blocks, blocks_per_slice * 4 * 64, 16); + ctx->unpack_alpha(&gb, blocks, blocks_per_slice * 4 * 64, 16); } else { - unpack_alpha(&gb, blocks, blocks_per_slice * 4 * 64, 8); + ctx->unpack_alpha(&gb, blocks, blocks_per_slice * 4 * 64, 8); } block = blocks; + for (i = 0; i < 16; i++) { memcpy(dst, block, 16 * blocks_per_slice * sizeof(*dst)); dst += dst_stride >> 1; @@ -521,6 +627,7 @@ static int decode_slice_thread(AVCodecContext *avctx, void *arg, int jobnr, int LOCAL_ALIGNED_16(int16_t, qmat_chroma_scaled,[64]); int mb_x_shift; int ret; + uint16_t val_no_chroma; slice->ret = -1; //av_log(avctx, AV_LOG_INFO, "slice %d mb width %d mb x %d y %d\n", @@ -558,7 +665,8 @@ static int decode_slice_thread(AVCodecContext *avctx, void *arg, int jobnr, int chroma_stride = pic->linesize[1] << 1; } - if (avctx->pix_fmt == AV_PIX_FMT_YUV444P10 || avctx->pix_fmt == AV_PIX_FMT_YUVA444P10) { + if (avctx->pix_fmt == AV_PIX_FMT_YUV444P10 || avctx->pix_fmt == AV_PIX_FMT_YUVA444P10 || + avctx->pix_fmt == AV_PIX_FMT_YUV444P12 || avctx->pix_fmt == AV_PIX_FMT_YUVA444P12) { mb_x_shift = 5; log2_chroma_blocks_per_mb = 2; } else { @@ -599,10 +707,15 @@ static int decode_slice_thread(AVCodecContext *avctx, void *arg, int jobnr, int else { size_t mb_max_x = slice->mb_count << (mb_x_shift - 1); size_t i, j; + if (avctx->bits_per_raw_sample == 10) { + val_no_chroma = 511; + } else { /* 12b */ + val_no_chroma = 511 * 4; + } for (i = 0; i < 16; ++i) for (j = 0; j < mb_max_x; ++j) { - *(uint16_t*)(dest_u + (i * chroma_stride) + (j << 1)) = 511; - *(uint16_t*)(dest_v + (i * chroma_stride) + (j << 1)) = 511; + *(uint16_t*)(dest_u + (i * chroma_stride) + (j << 1)) = val_no_chroma; + *(uint16_t*)(dest_v + (i * chroma_stride) + (j << 1)) = val_no_chroma; } } @@ -639,6 +752,7 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, AVPacket *avpkt) { ProresContext *ctx = avctx->priv_data; + ThreadFrame tframe = { .f = data }; AVFrame *frame = data; const uint8_t *buf = avpkt->data; int buf_size = avpkt->size; @@ -664,9 +778,6 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, buf += frame_hdr_size; buf_size -= frame_hdr_size; - if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) - return ret; - decode_picture: pic_size = decode_picture_header(avctx, buf, buf_size); if (pic_size < 0) { @@ -674,6 +785,10 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, return pic_size; } + if (ctx->first_field) + if ((ret = ff_thread_get_buffer(avctx, &tframe, 0)) < 0) + return ret; + if ((ret = decode_picture(avctx)) < 0) { av_log(avctx, AV_LOG_ERROR, "error decoding picture\n"); return ret; @@ -692,6 +807,17 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, return avpkt->size; } +#if HAVE_THREADS +static int decode_init_thread_copy(AVCodecContext *avctx) +{ + ProresContext *ctx = avctx->priv_data; + + ctx->slices = NULL; + + return 0; +} +#endif + static av_cold int decode_close(AVCodecContext *avctx) { ProresContext *ctx = avctx->priv_data; @@ -703,12 +829,14 @@ static av_cold int decode_close(AVCodecContext *avctx) AVCodec ff_prores_decoder = { .name = "prores", - .long_name = NULL_IF_CONFIG_SMALL("ProRes"), + .long_name = NULL_IF_CONFIG_SMALL("ProRes (iCodec Pro)"), .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_PRORES, .priv_data_size = sizeof(ProresContext), .init = decode_init, + .init_thread_copy = ONLY_IF_THREADS_ENABLED(decode_init_thread_copy), .close = decode_close, .decode = decode_frame, - .capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_SLICE_THREADS, + .capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_SLICE_THREADS | AV_CODEC_CAP_FRAME_THREADS, + .profiles = NULL_IF_CONFIG_SMALL(ff_prores_profiles), }; diff --git a/libavcodec/proresdsp.c b/libavcodec/proresdsp.c index 5b5ada21f..a3c618cdd 100644 --- a/libavcodec/proresdsp.c +++ b/libavcodec/proresdsp.c @@ -27,42 +27,71 @@ #include "proresdsp.h" #include "simple_idct.h" -#define BIAS (1 << (PRORES_BITS_PER_SAMPLE - 1)) ///< bias value for converting signed pixels into unsigned ones -#define CLIP_MIN (1 << (PRORES_BITS_PER_SAMPLE - 8)) ///< minimum value for clipping resulting pixels -#define CLIP_MAX (1 << PRORES_BITS_PER_SAMPLE) - CLIP_MIN - 1 ///< maximum value for clipping resulting pixels +#define CLIP_MIN (1 << 2) ///< minimum value for clipping resulting pixels +#define CLIP_MAX_10 (1 << 10) - CLIP_MIN - 1 ///< maximum value for clipping resulting pixels +#define CLIP_MAX_12 (1 << 12) - CLIP_MIN - 1 ///< maximum value for clipping resulting pixels -#define CLIP(x) (av_clip((x), CLIP_MIN, CLIP_MAX)) +#define CLIP_10(x) (av_clip((x), CLIP_MIN, CLIP_MAX_10)) +#define CLIP_12(x) (av_clip((x), CLIP_MIN, CLIP_MAX_12)) /** * Add bias value, clamp and output pixels of a slice */ -static void put_pixels(uint16_t *dst, ptrdiff_t linesize, const int16_t *in) -{ + +static inline void put_pixel(uint16_t *dst, ptrdiff_t linesize, const int16_t *in, int bits_per_raw_sample) { int x, y, src_offset, dst_offset; for (y = 0, dst_offset = 0; y < 8; y++, dst_offset += linesize) { for (x = 0; x < 8; x++) { src_offset = (y << 3) + x; - dst[dst_offset + x] = CLIP(in[src_offset]); + if (bits_per_raw_sample == 10) { + dst[dst_offset + x] = CLIP_10(in[src_offset]); + } else {//12b + dst[dst_offset + x] = CLIP_12(in[src_offset]); + } } } } -static void prores_idct_put_c(uint16_t *out, ptrdiff_t linesize, int16_t *block, const int16_t *qmat) +static void put_pixels_10(uint16_t *dst, ptrdiff_t linesize, const int16_t *in) { - ff_prores_idct(block, qmat); - put_pixels(out, linesize >> 1, block); + put_pixel(dst, linesize, in, 10); } -av_cold void ff_proresdsp_init(ProresDSPContext *dsp, AVCodecContext *avctx) +static void put_pixels_12(uint16_t *dst, ptrdiff_t linesize, const int16_t *in) { - dsp->idct_put = prores_idct_put_c; - dsp->idct_permutation_type = FF_IDCT_PERM_NONE; + put_pixel(dst, linesize, in, 12); +} + +static void prores_idct_put_10_c(uint16_t *out, ptrdiff_t linesize, int16_t *block, const int16_t *qmat) +{ + ff_prores_idct_10(block, qmat); + put_pixels_10(out, linesize >> 1, block); +} + +static void prores_idct_put_12_c(uint16_t *out, ptrdiff_t linesize, int16_t *block, const int16_t *qmat) +{ + ff_prores_idct_12(block, qmat); + put_pixels_12(out, linesize >> 1, block); +} + +av_cold int ff_proresdsp_init(ProresDSPContext *dsp, AVCodecContext *avctx) +{ + if (avctx->bits_per_raw_sample == 10) { + dsp->idct_put = prores_idct_put_10_c; + dsp->idct_permutation_type = FF_IDCT_PERM_NONE; + } else if (avctx->bits_per_raw_sample == 12) { + dsp->idct_put = prores_idct_put_12_c; + dsp->idct_permutation_type = FF_IDCT_PERM_NONE; + } else { + return AVERROR_BUG; + } if (ARCH_X86) ff_proresdsp_init_x86(dsp, avctx); ff_init_scantable_permutation(dsp->idct_permutation, dsp->idct_permutation_type); + return 0; } diff --git a/libavcodec/proresdsp.h b/libavcodec/proresdsp.h index 558fae53b..37ba76b8e 100644 --- a/libavcodec/proresdsp.h +++ b/libavcodec/proresdsp.h @@ -27,15 +27,13 @@ #include #include "avcodec.h" -#define PRORES_BITS_PER_SAMPLE 10 ///< output precision of prores decoder - typedef struct ProresDSPContext { int idct_permutation_type; uint8_t idct_permutation[64]; void (*idct_put)(uint16_t *out, ptrdiff_t linesize, int16_t *block, const int16_t *qmat); } ProresDSPContext; -void ff_proresdsp_init(ProresDSPContext *dsp, AVCodecContext *avctx); +int ff_proresdsp_init(ProresDSPContext *dsp, AVCodecContext *avctx); void ff_proresdsp_init_x86(ProresDSPContext *dsp, AVCodecContext *avctx); diff --git a/libavcodec/proresenc_anatoliy.c b/libavcodec/proresenc_anatoliy.c index 051606616..0fc79fc1d 100644 --- a/libavcodec/proresenc_anatoliy.c +++ b/libavcodec/proresenc_anatoliy.c @@ -2,6 +2,7 @@ * Apple ProRes encoder * * Copyright (c) 2011 Anatoliy Wasserman + * Copyright (c) 2012 Konstantin Shishkov * * This file is part of FFmpeg. * @@ -23,47 +24,42 @@ /** * @file * Apple ProRes encoder (Anatoliy Wasserman version) - * Known FOURCCs: 'apch' (HQ), 'apcn' (SD), 'apcs' (LT), 'acpo' (Proxy) + * Known FOURCCs: 'ap4h' (444), 'apch' (HQ), 'apcn' (422), 'apcs' (LT), 'acpo' (Proxy) */ +#include "libavutil/opt.h" #include "avcodec.h" #include "dct.h" #include "internal.h" +#include "profiles.h" +#include "proresdata.h" #include "put_bits.h" #include "bytestream.h" #include "fdctdsp.h" #define DEFAULT_SLICE_MB_WIDTH 8 -#define FF_PROFILE_PRORES_PROXY 0 -#define FF_PROFILE_PRORES_LT 1 -#define FF_PROFILE_PRORES_STANDARD 2 -#define FF_PROFILE_PRORES_HQ 3 - static const AVProfile profiles[] = { { FF_PROFILE_PRORES_PROXY, "apco"}, { FF_PROFILE_PRORES_LT, "apcs"}, { FF_PROFILE_PRORES_STANDARD, "apcn"}, { FF_PROFILE_PRORES_HQ, "apch"}, + { FF_PROFILE_PRORES_4444, "ap4h"}, + { FF_PROFILE_PRORES_XQ, "ap4x"}, { FF_PROFILE_UNKNOWN } }; -static const int qp_start_table[4] = { 4, 1, 1, 1 }; -static const int qp_end_table[4] = { 8, 9, 6, 6 }; -static const int bitrate_table[5] = { 1000, 2100, 3500, 5400 }; +static const int qp_start_table[6] = { 8, 3, 2, 1, 1, 1}; +static const int qp_end_table[6] = { 13, 9, 6, 6, 5, 4}; +static const int bitrate_table[6] = { 1000, 2100, 3500, 5400, 7000, 10000}; -static const uint8_t progressive_scan[64] = { - 0, 1, 8, 9, 2, 3, 10, 11, - 16, 17, 24, 25, 18, 19, 26, 27, - 4, 5, 12, 20, 13, 6, 7, 14, - 21, 28, 29, 22, 15, 23, 30, 31, - 32, 33, 40, 48, 41, 34, 35, 42, - 49, 56, 57, 50, 43, 36, 37, 44, - 51, 58, 59, 52, 45, 38, 39, 46, - 53, 60, 61, 54, 47, 55, 62, 63 -}; +static const int valid_primaries[9] = { AVCOL_PRI_RESERVED0, AVCOL_PRI_BT709, AVCOL_PRI_UNSPECIFIED, AVCOL_PRI_BT470BG, + AVCOL_PRI_SMPTE170M, AVCOL_PRI_BT2020, AVCOL_PRI_SMPTE431, AVCOL_PRI_SMPTE432,INT_MAX }; +static const int valid_trc[4] = { AVCOL_TRC_RESERVED0, AVCOL_TRC_BT709, AVCOL_TRC_UNSPECIFIED, INT_MAX }; +static const int valid_colorspace[5] = { AVCOL_SPC_BT709, AVCOL_SPC_UNSPECIFIED, AVCOL_SPC_SMPTE170M, + AVCOL_SPC_BT2020_NCL, INT_MAX }; -static const uint8_t QMAT_LUMA[4][64] = { +static const uint8_t QMAT_LUMA[6][64] = { { 4, 7, 9, 11, 13, 14, 15, 63, 7, 7, 11, 12, 14, 15, 63, 63, @@ -100,10 +96,28 @@ static const uint8_t QMAT_LUMA[4][64] = { 4, 4, 4, 4, 4, 5, 5, 6, 4, 4, 4, 4, 5, 5, 6, 7, 4, 4, 4, 4, 5, 6, 7, 7 + }, { /* 444 */ + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 5, + 4, 4, 4, 4, 4, 4, 5, 5, + 4, 4, 4, 4, 4, 5, 5, 6, + 4, 4, 4, 4, 5, 5, 6, 7, + 4, 4, 4, 4, 5, 6, 7, 7 + }, { /* 444 XQ */ + 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 3, + 2, 2, 2, 2, 2, 2, 3, 3, + 2, 2, 2, 2, 2, 3, 3, 3, + 2, 2, 2, 2, 3, 3, 3, 4, + 2, 2, 2, 2, 3, 3, 4, 4, } }; -static const uint8_t QMAT_CHROMA[4][64] = { +static const uint8_t QMAT_CHROMA[6][64] = { { 4, 7, 9, 11, 13, 14, 63, 63, 7, 7, 11, 12, 14, 63, 63, 63, @@ -140,18 +154,45 @@ static const uint8_t QMAT_CHROMA[4][64] = { 4, 4, 4, 4, 4, 5, 5, 6, 4, 4, 4, 4, 5, 5, 6, 7, 4, 4, 4, 4, 5, 6, 7, 7 + }, { /* 444 */ + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 5, + 4, 4, 4, 4, 4, 4, 5, 5, + 4, 4, 4, 4, 4, 5, 5, 6, + 4, 4, 4, 4, 5, 5, 6, 7, + 4, 4, 4, 4, 5, 6, 7, 7 + }, { /* 444 xq */ + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 5, + 4, 4, 4, 4, 4, 4, 5, 5, + 4, 4, 4, 4, 4, 5, 5, 6, + 4, 4, 4, 4, 5, 5, 6, 7, + 4, 4, 4, 4, 5, 6, 7, 7 } }; typedef struct { + AVClass *class; FDCTDSPContext fdsp; uint8_t* fill_y; uint8_t* fill_u; uint8_t* fill_v; + uint8_t* fill_a; int qmat_luma[16][64]; int qmat_chroma[16][64]; + const uint8_t *scantable; + + int is_422; + int need_alpha; + int is_interlaced; + + char *vendor; } ProresContext; static void encode_codeword(PutBitContext *pb, int val, int codebook) @@ -229,15 +270,15 @@ static const uint8_t run_to_cb[16] = { 0x06, 0x06, 0x05, 0x05, 0x04, 0x29, static const uint8_t lev_to_cb[10] = { 0x04, 0x0A, 0x05, 0x06, 0x04, 0x28, 0x28, 0x28, 0x28, 0x4C }; -static void encode_ac_coeffs(AVCodecContext *avctx, PutBitContext *pb, - int16_t *in, int blocks_per_slice, int *qmat) +static void encode_ac_coeffs(PutBitContext *pb, + int16_t *in, int blocks_per_slice, int *qmat, const uint8_t ff_prores_scan[64]) { int prev_run = 4; int prev_level = 2; int run = 0, level, code, i, j; for (i = 1; i < 64; i++) { - int indp = progressive_scan[i]; + int indp = ff_prores_scan[i]; for (j = 0; j < blocks_per_slice; j++) { int val = QSCALE(qmat, indp, in[(j << 6) + indp]); if (val) { @@ -278,81 +319,190 @@ static void fdct_get(FDCTDSPContext *fdsp, uint8_t *pixels, int stride, int16_t* fdsp->fdct(block); } -static int encode_slice_plane(AVCodecContext *avctx, int mb_count, - uint8_t *src, int src_stride, uint8_t *buf, unsigned buf_size, - int *qmat, int chroma) +static void calc_plane_dct(FDCTDSPContext *fdsp, uint8_t *src, int16_t * blocks, int src_stride, int mb_count, int chroma, int is_422) { - ProresContext* ctx = avctx->priv_data; - FDCTDSPContext *fdsp = &ctx->fdsp; - LOCAL_ALIGNED(16, int16_t, blocks, [DEFAULT_SLICE_MB_WIDTH << 8]); int16_t *block; - int i, blocks_per_slice; - PutBitContext pb; + int i; block = blocks; - for (i = 0; i < mb_count; i++) { - fdct_get(fdsp, src, src_stride, block + (0 << 6)); - fdct_get(fdsp, src + 8 * src_stride, src_stride, block + ((2 - chroma) << 6)); - if (!chroma) { + + if (!chroma) { /* Luma plane */ + for (i = 0; i < mb_count; i++) { + fdct_get(fdsp, src, src_stride, block + (0 << 6)); fdct_get(fdsp, src + 16, src_stride, block + (1 << 6)); + fdct_get(fdsp, src + 8 * src_stride, src_stride, block + (2 << 6)); fdct_get(fdsp, src + 16 + 8 * src_stride, src_stride, block + (3 << 6)); + + block += 256; + src += 32; } + } else if (chroma && is_422){ /* chroma plane 422 */ + for (i = 0; i < mb_count; i++) { + fdct_get(fdsp, src, src_stride, block + (0 << 6)); + fdct_get(fdsp, src + 8 * src_stride, src_stride, block + (1 << 6)); + block += (256 >> 1); + src += (32 >> 1); + } + } else { /* chroma plane 444 */ + for (i = 0; i < mb_count; i++) { + fdct_get(fdsp, src, src_stride, block + (0 << 6)); + fdct_get(fdsp, src + 8 * src_stride, src_stride, block + (1 << 6)); + fdct_get(fdsp, src + 16, src_stride, block + (2 << 6)); + fdct_get(fdsp, src + 16 + 8 * src_stride, src_stride, block + (3 << 6)); - block += (256 >> chroma); - src += (32 >> chroma); + block += 256; + src += 32; + } } +} - blocks_per_slice = mb_count << (2 - chroma); +static int encode_slice_plane(int16_t *blocks, int mb_count, uint8_t *buf, unsigned buf_size, int *qmat, int sub_sample_chroma, + const uint8_t ff_prores_scan[64]) +{ + int blocks_per_slice; + PutBitContext pb; + + blocks_per_slice = mb_count << (2 - sub_sample_chroma); init_put_bits(&pb, buf, buf_size); encode_dc_coeffs(&pb, blocks, blocks_per_slice, qmat); - encode_ac_coeffs(avctx, &pb, blocks, blocks_per_slice, qmat); + encode_ac_coeffs(&pb, blocks, blocks_per_slice, qmat, ff_prores_scan); flush_put_bits(&pb); return put_bits_ptr(&pb) - pb.buf; } static av_always_inline unsigned encode_slice_data(AVCodecContext *avctx, - uint8_t *dest_y, uint8_t *dest_u, uint8_t *dest_v, int luma_stride, - int chroma_stride, unsigned mb_count, uint8_t *buf, unsigned data_size, - unsigned* y_data_size, unsigned* u_data_size, unsigned* v_data_size, - int qp) + int16_t * blocks_y, int16_t * blocks_u, int16_t * blocks_v, + unsigned mb_count, uint8_t *buf, unsigned data_size, + unsigned* y_data_size, unsigned* u_data_size, unsigned* v_data_size, + int qp) { ProresContext* ctx = avctx->priv_data; - *y_data_size = encode_slice_plane(avctx, mb_count, dest_y, luma_stride, - buf, data_size, ctx->qmat_luma[qp - 1], 0); + *y_data_size = encode_slice_plane(blocks_y, mb_count, + buf, data_size, ctx->qmat_luma[qp - 1], 0, ctx->scantable); if (!(avctx->flags & AV_CODEC_FLAG_GRAY)) { - *u_data_size = encode_slice_plane(avctx, mb_count, dest_u, - chroma_stride, buf + *y_data_size, data_size - *y_data_size, - ctx->qmat_chroma[qp - 1], 1); + *u_data_size = encode_slice_plane(blocks_u, mb_count, buf + *y_data_size, data_size - *y_data_size, + ctx->qmat_chroma[qp - 1], ctx->is_422, ctx->scantable); - *v_data_size = encode_slice_plane(avctx, mb_count, dest_v, - chroma_stride, buf + *y_data_size + *u_data_size, - data_size - *y_data_size - *u_data_size, - ctx->qmat_chroma[qp - 1], 1); + *v_data_size = encode_slice_plane(blocks_v, mb_count, buf + *y_data_size + *u_data_size, + data_size - *y_data_size - *u_data_size, + ctx->qmat_chroma[qp - 1], ctx->is_422, ctx->scantable); } return *y_data_size + *u_data_size + *v_data_size; } -static void subimage_with_fill(uint16_t *src, unsigned x, unsigned y, - unsigned stride, unsigned width, unsigned height, uint16_t *dst, - unsigned dst_width, unsigned dst_height) +static void put_alpha_diff(PutBitContext *pb, int cur, int prev) { + const int abits = 16; + const int dbits = 7; + const int dsize = 1 << dbits - 1; + int diff = cur - prev; + diff = av_mod_uintp2(diff, abits); + if (diff >= (1 << abits) - dsize) + diff -= 1 << abits; + if (diff < -dsize || diff > dsize || !diff) { + put_bits(pb, 1, 1); + put_bits(pb, abits, diff); + } else { + put_bits(pb, 1, 0); + put_bits(pb, dbits - 1, FFABS(diff) - 1); + put_bits(pb, 1, diff < 0); + } +} + +static inline void put_alpha_run(PutBitContext *pb, int run) +{ + if (run) { + put_bits(pb, 1, 0); + if (run < 0x10) + put_bits(pb, 4, run); + else + put_bits(pb, 15, run); + } else { + put_bits(pb, 1, 1); + } +} + +static av_always_inline int encode_alpha_slice_data(AVCodecContext *avctx, int8_t * src_a, + unsigned mb_count, uint8_t *buf, unsigned data_size, unsigned* a_data_size) +{ + const int abits = 16; + const int mask = (1 << abits) - 1; + const int num_coeffs = mb_count * 256; + int prev = mask, cur; + int idx = 0; + int run = 0; + int16_t * blocks = (int16_t *)src_a; + PutBitContext pb; + init_put_bits(&pb, buf, data_size); + + cur = blocks[idx++]; + put_alpha_diff(&pb, cur, prev); + prev = cur; + do { + cur = blocks[idx++]; + if (cur != prev) { + put_alpha_run (&pb, run); + put_alpha_diff(&pb, cur, prev); + prev = cur; + run = 0; + } else { + run++; + } + } while (idx < num_coeffs); + if (run) + put_alpha_run(&pb, run); + flush_put_bits(&pb); + *a_data_size = put_bits_count(&pb) >> 3; + + if (put_bits_left(&pb) < 0) { + av_log(avctx, AV_LOG_ERROR, + "Underestimated required buffer size.\n"); + return AVERROR_BUG; + } else { + return 0; + } +} + +static inline void subimage_with_fill_template(uint16_t *src, unsigned x, unsigned y, + unsigned stride, unsigned width, unsigned height, uint16_t *dst, + unsigned dst_width, unsigned dst_height, int is_alpha_plane, + int is_interlaced, int is_top_field) +{ int box_width = FFMIN(width - x, dst_width); - int box_height = FFMIN(height - y, dst_height); - int i, j, src_stride = stride >> 1; + int i, j, src_stride, box_height; uint16_t last_pix, *last_line; - src += y * src_stride + x; + if (!is_interlaced) { + src_stride = stride >> 1; + src += y * src_stride + x; + box_height = FFMIN(height - y, dst_height); + } else { + src_stride = stride; /* 2 lines stride */ + src += y * src_stride + x; + box_height = FFMIN(height/2 - y, dst_height); + if (!is_top_field) + src += stride >> 1; + } + for (i = 0; i < box_height; ++i) { for (j = 0; j < box_width; ++j) { - dst[j] = src[j]; + if (!is_alpha_plane) { + dst[j] = src[j]; + } else { + dst[j] = src[j] << 6; /* alpha 10b to 16b */ + } + } + if (!is_alpha_plane) { + last_pix = dst[j - 1]; + } else { + last_pix = dst[j - 1] << 6; /* alpha 10b to 16b */ } - last_pix = dst[j - 1]; for (; j < dst_width; j++) dst[j] = last_pix; src += src_stride; @@ -367,64 +517,113 @@ static void subimage_with_fill(uint16_t *src, unsigned x, unsigned y, } } +static void subimage_with_fill(uint16_t *src, unsigned x, unsigned y, + unsigned stride, unsigned width, unsigned height, uint16_t *dst, + unsigned dst_width, unsigned dst_height, int is_interlaced, int is_top_field) +{ + subimage_with_fill_template(src, x, y, stride, width, height, dst, dst_width, dst_height, 0, is_interlaced, is_top_field); +} + +/* reorganize alpha data and convert 10b -> 16b */ +static void subimage_alpha_with_fill(uint16_t *src, unsigned x, unsigned y, + unsigned stride, unsigned width, unsigned height, uint16_t *dst, + unsigned dst_width, unsigned dst_height, int is_interlaced, int is_top_field) +{ + subimage_with_fill_template(src, x, y, stride, width, height, dst, dst_width, dst_height, 1, is_interlaced, is_top_field); +} + static int encode_slice(AVCodecContext *avctx, const AVFrame *pic, int mb_x, int mb_y, unsigned mb_count, uint8_t *buf, unsigned data_size, - int unsafe, int *qp) + int unsafe, int *qp, int is_interlaced, int is_top_field) { - int luma_stride, chroma_stride; - int hdr_size = 6, slice_size; - uint8_t *dest_y, *dest_u, *dest_v; - unsigned y_data_size = 0, u_data_size = 0, v_data_size = 0; + int luma_stride, chroma_stride, alpha_stride = 0; ProresContext* ctx = avctx->priv_data; + int hdr_size = 6 + (ctx->need_alpha * 2); /* v data size is write when there is alpha */ + int ret = 0, slice_size; + uint8_t *dest_y, *dest_u, *dest_v; + unsigned y_data_size = 0, u_data_size = 0, v_data_size = 0, a_data_size = 0; + FDCTDSPContext *fdsp = &ctx->fdsp; int tgt_bits = (mb_count * bitrate_table[avctx->profile]) >> 2; int low_bytes = (tgt_bits - (tgt_bits >> 3)) >> 3; // 12% bitrate fluctuation int high_bytes = (tgt_bits + (tgt_bits >> 3)) >> 3; + LOCAL_ALIGNED(16, int16_t, blocks_y, [DEFAULT_SLICE_MB_WIDTH << 8]); + LOCAL_ALIGNED(16, int16_t, blocks_u, [DEFAULT_SLICE_MB_WIDTH << 8]); + LOCAL_ALIGNED(16, int16_t, blocks_v, [DEFAULT_SLICE_MB_WIDTH << 8]); + luma_stride = pic->linesize[0]; chroma_stride = pic->linesize[1]; - dest_y = pic->data[0] + (mb_y << 4) * luma_stride + (mb_x << 5); - dest_u = pic->data[1] + (mb_y << 4) * chroma_stride + (mb_x << 4); - dest_v = pic->data[2] + (mb_y << 4) * chroma_stride + (mb_x << 4); + if (ctx->need_alpha) + alpha_stride = pic->linesize[3]; + + if (!is_interlaced) { + dest_y = pic->data[0] + (mb_y << 4) * luma_stride + (mb_x << 5); + dest_u = pic->data[1] + (mb_y << 4) * chroma_stride + (mb_x << (5 - ctx->is_422)); + dest_v = pic->data[2] + (mb_y << 4) * chroma_stride + (mb_x << (5 - ctx->is_422)); + } else { + dest_y = pic->data[0] + (mb_y << 4) * luma_stride * 2 + (mb_x << 5); + dest_u = pic->data[1] + (mb_y << 4) * chroma_stride * 2 + (mb_x << (5 - ctx->is_422)); + dest_v = pic->data[2] + (mb_y << 4) * chroma_stride * 2 + (mb_x << (5 - ctx->is_422)); + if (!is_top_field){ /* bottom field, offset dest */ + dest_y += luma_stride; + dest_u += chroma_stride; + dest_v += chroma_stride; + } + } if (unsafe) { - subimage_with_fill((uint16_t *) pic->data[0], mb_x << 4, mb_y << 4, luma_stride, avctx->width, avctx->height, - (uint16_t *) ctx->fill_y, mb_count << 4, 16); - subimage_with_fill((uint16_t *) pic->data[1], mb_x << 3, mb_y << 4, - chroma_stride, avctx->width >> 1, avctx->height, - (uint16_t *) ctx->fill_u, mb_count << 3, 16); - subimage_with_fill((uint16_t *) pic->data[2], mb_x << 3, mb_y << 4, - chroma_stride, avctx->width >> 1, avctx->height, - (uint16_t *) ctx->fill_v, mb_count << 3, 16); + (uint16_t *) ctx->fill_y, mb_count << 4, 16, is_interlaced, is_top_field); + subimage_with_fill((uint16_t *) pic->data[1], mb_x << (4 - ctx->is_422), mb_y << 4, + chroma_stride, avctx->width >> ctx->is_422, avctx->height, + (uint16_t *) ctx->fill_u, mb_count << (4 - ctx->is_422), 16, is_interlaced, is_top_field); + subimage_with_fill((uint16_t *) pic->data[2], mb_x << (4 - ctx->is_422), mb_y << 4, + chroma_stride, avctx->width >> ctx->is_422, avctx->height, + (uint16_t *) ctx->fill_v, mb_count << (4 - ctx->is_422), 16, is_interlaced, is_top_field); - encode_slice_data(avctx, ctx->fill_y, ctx->fill_u, ctx->fill_v, - mb_count << 5, mb_count << 4, mb_count, buf + hdr_size, - data_size - hdr_size, &y_data_size, &u_data_size, &v_data_size, - *qp); + /* no need for interlaced special case, data already reorganized in subimage_with_fill */ + calc_plane_dct(fdsp, ctx->fill_y, blocks_y, mb_count << 5, mb_count, 0, 0); + calc_plane_dct(fdsp, ctx->fill_u, blocks_u, mb_count << (5 - ctx->is_422), mb_count, 1, ctx->is_422); + calc_plane_dct(fdsp, ctx->fill_v, blocks_v, mb_count << (5 - ctx->is_422), mb_count, 1, ctx->is_422); + + slice_size = encode_slice_data(avctx, blocks_y, blocks_u, blocks_v, + mb_count, buf + hdr_size, data_size - hdr_size, + &y_data_size, &u_data_size, &v_data_size, + *qp); } else { - slice_size = encode_slice_data(avctx, dest_y, dest_u, dest_v, - luma_stride, chroma_stride, mb_count, buf + hdr_size, - data_size - hdr_size, &y_data_size, &u_data_size, &v_data_size, - *qp); + if (!is_interlaced) { + calc_plane_dct(fdsp, dest_y, blocks_y, luma_stride, mb_count, 0, 0); + calc_plane_dct(fdsp, dest_u, blocks_u, chroma_stride, mb_count, 1, ctx->is_422); + calc_plane_dct(fdsp, dest_v, blocks_v, chroma_stride, mb_count, 1, ctx->is_422); + } else { + calc_plane_dct(fdsp, dest_y, blocks_y, luma_stride * 2, mb_count, 0, 0); + calc_plane_dct(fdsp, dest_u, blocks_u, chroma_stride * 2, mb_count, 1, ctx->is_422); + calc_plane_dct(fdsp, dest_v, blocks_v, chroma_stride * 2, mb_count, 1, ctx->is_422); + } + + slice_size = encode_slice_data(avctx, blocks_y, blocks_u, blocks_v, + mb_count, buf + hdr_size, data_size - hdr_size, + &y_data_size, &u_data_size, &v_data_size, + *qp); if (slice_size > high_bytes && *qp < qp_end_table[avctx->profile]) { do { *qp += 1; - slice_size = encode_slice_data(avctx, dest_y, dest_u, dest_v, - luma_stride, chroma_stride, mb_count, buf + hdr_size, - data_size - hdr_size, &y_data_size, &u_data_size, - &v_data_size, *qp); + slice_size = encode_slice_data(avctx, blocks_y, blocks_u, blocks_v, + mb_count, buf + hdr_size, data_size - hdr_size, + &y_data_size, &u_data_size, &v_data_size, + *qp); } while (slice_size > high_bytes && *qp < qp_end_table[avctx->profile]); } else if (slice_size < low_bytes && *qp > qp_start_table[avctx->profile]) { do { *qp -= 1; - slice_size = encode_slice_data(avctx, dest_y, dest_u, dest_v, - luma_stride, chroma_stride, mb_count, buf + hdr_size, - data_size - hdr_size, &y_data_size, &u_data_size, - &v_data_size, *qp); + slice_size = encode_slice_data(avctx, blocks_y, blocks_u, blocks_v, + mb_count, buf + hdr_size, data_size - hdr_size, + &y_data_size, &u_data_size, &v_data_size, + *qp); } while (slice_size < low_bytes && *qp > qp_start_table[avctx->profile]); } } @@ -434,20 +633,47 @@ static int encode_slice(AVCodecContext *avctx, const AVFrame *pic, int mb_x, AV_WB16(buf + 2, y_data_size); AV_WB16(buf + 4, u_data_size); - return hdr_size + y_data_size + u_data_size + v_data_size; + if (ctx->need_alpha) { + AV_WB16(buf + 6, v_data_size); /* write v data size only if there is alpha */ + + subimage_alpha_with_fill((uint16_t *) pic->data[3], mb_x << 4, mb_y << 4, + alpha_stride, avctx->width, avctx->height, + (uint16_t *) ctx->fill_a, mb_count << 4, 16, is_interlaced, is_top_field); + ret = encode_alpha_slice_data(avctx, ctx->fill_a, mb_count, + buf + hdr_size + slice_size, + data_size - hdr_size - slice_size, &a_data_size); + } + + if (ret != 0) { + return ret; + } + return hdr_size + y_data_size + u_data_size + v_data_size + a_data_size; } static int prores_encode_picture(AVCodecContext *avctx, const AVFrame *pic, - uint8_t *buf, const int buf_size) + uint8_t *buf, const int buf_size, const int picture_index, const int is_top_field) { + ProresContext *ctx = avctx->priv_data; int mb_width = (avctx->width + 15) >> 4; - int mb_height = (avctx->height + 15) >> 4; int hdr_size, sl_size, i; - int mb_y, sl_data_size, qp; + int mb_y, sl_data_size, qp, mb_height, picture_height, unsafe_mb_height_limit; int unsafe_bot, unsafe_right; uint8_t *sl_data, *sl_data_sizes; int slice_per_line = 0, rem = mb_width; + if (!ctx->is_interlaced) { /* progressive encoding */ + mb_height = (avctx->height + 15) >> 4; + unsafe_mb_height_limit = mb_height; + } else { + if (is_top_field) { + picture_height = (avctx->height + 1) / 2; + } else { + picture_height = avctx->height / 2; + } + mb_height = (picture_height + 15) >> 4; + unsafe_mb_height_limit = mb_height; + } + for (i = av_log2(DEFAULT_SLICE_MB_WIDTH); i >= 0; --i) { slice_per_line += rem >> i; rem &= (1 << i) - 1; @@ -464,11 +690,14 @@ static int prores_encode_picture(AVCodecContext *avctx, const AVFrame *pic, while (mb_width - mb_x < slice_mb_count) slice_mb_count >>= 1; - unsafe_bot = (avctx->height & 0xf) && (mb_y == mb_height - 1); + unsafe_bot = (avctx->height & 0xf) && (mb_y == unsafe_mb_height_limit - 1); unsafe_right = (avctx->width & 0xf) && (mb_x + slice_mb_count == mb_width); sl_size = encode_slice(avctx, pic, mb_x, mb_y, slice_mb_count, - sl_data, sl_data_size, unsafe_bot || unsafe_right, &qp); + sl_data, sl_data_size, unsafe_bot || unsafe_right, &qp, ctx->is_interlaced, is_top_field); + if (sl_size < 0){ + return sl_size; + } bytestream_put_be16(&sl_data_sizes, sl_size); sl_data += sl_size; @@ -479,8 +708,8 @@ static int prores_encode_picture(AVCodecContext *avctx, const AVFrame *pic, buf[0] = hdr_size << 3; AV_WB32(buf + 1, sl_data - buf); - AV_WB16(buf + 5, slice_per_line * mb_height); - buf[7] = av_log2(DEFAULT_SLICE_MB_WIDTH) << 4; + AV_WB16(buf + 5, slice_per_line * mb_height); /* picture size */ + buf[7] = av_log2(DEFAULT_SLICE_MB_WIDTH) << 4; /* number of slices */ return sl_data - buf; } @@ -488,9 +717,11 @@ static int prores_encode_picture(AVCodecContext *avctx, const AVFrame *pic, static int prores_encode_frame(AVCodecContext *avctx, AVPacket *pkt, const AVFrame *pict, int *got_packet) { + ProresContext *ctx = avctx->priv_data; int header_size = 148; uint8_t *buf; - int pic_size, ret; + int compress_frame_size, pic_size, ret, is_top_field_first = 0; + uint8_t frame_flags; int frame_size = FFALIGN(avctx->width, 16) * FFALIGN(avctx->height, 16)*16 + 500 + AV_INPUT_BUFFER_MIN_SIZE; //FIXME choose tighter limit @@ -498,31 +729,71 @@ static int prores_encode_frame(AVCodecContext *avctx, AVPacket *pkt, return ret; buf = pkt->data; - pic_size = prores_encode_picture(avctx, pict, buf + header_size + 8, - pkt->size - header_size - 8); + compress_frame_size = 8 + header_size; - bytestream_put_be32(&buf, pic_size + 8 + header_size); + bytestream_put_be32(&buf, compress_frame_size);/* frame size will be update after picture(s) encoding */ bytestream_put_buffer(&buf, "icpf", 4); bytestream_put_be16(&buf, header_size); - bytestream_put_be16(&buf, 0); - bytestream_put_buffer(&buf, "fmpg", 4); + bytestream_put_be16(&buf, 0); /* version */ + bytestream_put_buffer(&buf, ctx->vendor, 4); bytestream_put_be16(&buf, avctx->width); bytestream_put_be16(&buf, avctx->height); - *buf++ = 0x83; // {10}(422){00}{00}(frame){11} - *buf++ = 0; - *buf++ = 2; - *buf++ = 2; - *buf++ = 6; - *buf++ = 32; - *buf++ = 0; - *buf++ = 3; + frame_flags = 0x82; /* 422 not interlaced */ + if (avctx->profile >= FF_PROFILE_PRORES_4444) /* 4444 or 4444 Xq */ + frame_flags |= 0x40; /* 444 chroma */ + if (ctx->is_interlaced) { + if (pict->top_field_first || !pict->interlaced_frame) { /* tff frame or progressive frame interpret as tff */ + av_log(avctx, AV_LOG_DEBUG, "use interlaced encoding, top field first\n"); + frame_flags |= 0x04; /* interlaced tff */ + is_top_field_first = 1; + } else { + av_log(avctx, AV_LOG_DEBUG, "use interlaced encoding, bottom field first\n"); + frame_flags |= 0x08; /* interlaced bff */ + } + } else { + av_log(avctx, AV_LOG_DEBUG, "use progressive encoding\n"); + } + *buf++ = frame_flags; + *buf++ = 0; /* reserved */ + /* only write color properties, if valid value. set to unspecified otherwise */ + *buf++ = ff_int_from_list_or_default(avctx, "frame color primaries", pict->color_primaries, valid_primaries, 0); + *buf++ = ff_int_from_list_or_default(avctx, "frame color trc", pict->color_trc, valid_trc, 0); + *buf++ = ff_int_from_list_or_default(avctx, "frame colorspace", pict->colorspace, valid_colorspace, 0); + if (avctx->profile >= FF_PROFILE_PRORES_4444) { + if (avctx->pix_fmt == AV_PIX_FMT_YUV444P10) { + *buf++ = 0xA0;/* src b64a and no alpha */ + } else { + *buf++ = 0xA2;/* src b64a and 16b alpha */ + } + } else { + *buf++ = 32;/* src v210 and no alpha */ + } + *buf++ = 0; /* reserved */ + *buf++ = 3; /* luma and chroma matrix present */ bytestream_put_buffer(&buf, QMAT_LUMA[avctx->profile], 64); bytestream_put_buffer(&buf, QMAT_CHROMA[avctx->profile], 64); + pic_size = prores_encode_picture(avctx, pict, buf, + pkt->size - compress_frame_size, 0, is_top_field_first);/* encode progressive or first field */ + if (pic_size < 0) { + return pic_size; + } + compress_frame_size += pic_size; + + if (ctx->is_interlaced) { /* encode second field */ + pic_size = prores_encode_picture(avctx, pict, pkt->data + compress_frame_size, + pkt->size - compress_frame_size, 1, !is_top_field_first); + if (pic_size < 0) { + return pic_size; + } + compress_frame_size += pic_size; + } + + AV_WB32(pkt->data, compress_frame_size);/* update frame size */ pkt->flags |= AV_PKT_FLAG_KEY; - pkt->size = pic_size + 8 + header_size; + pkt->size = compress_frame_size; *got_packet = 1; return 0; @@ -540,11 +811,14 @@ static av_cold int prores_encode_init(AVCodecContext *avctx) int i; ProresContext* ctx = avctx->priv_data; - if (avctx->pix_fmt != AV_PIX_FMT_YUV422P10) { - av_log(avctx, AV_LOG_ERROR, "need YUV422P10\n"); - return AVERROR_PATCHWELCOME; - } avctx->bits_per_raw_sample = 10; + ctx->need_alpha = 0; + ctx->is_interlaced = !!(avctx->flags & AV_CODEC_FLAG_INTERLACED_DCT); + if (ctx->is_interlaced) { + ctx->scantable = ff_prores_interlaced_scan; + } else { + ctx->scantable = ff_prores_progressive_scan; + } if (avctx->width & 0x1) { av_log(avctx, AV_LOG_ERROR, @@ -558,27 +832,71 @@ static av_cold int prores_encode_init(AVCodecContext *avctx) return AVERROR(EINVAL); } - if ((avctx->height & 0xf) || (avctx->width & 0xf)) { - ctx->fill_y = av_malloc(4 * (DEFAULT_SLICE_MB_WIDTH << 8)); - if (!ctx->fill_y) - return AVERROR(ENOMEM); - ctx->fill_u = ctx->fill_y + (DEFAULT_SLICE_MB_WIDTH << 9); - ctx->fill_v = ctx->fill_u + (DEFAULT_SLICE_MB_WIDTH << 8); + if (strlen(ctx->vendor) != 4) { + av_log(avctx, AV_LOG_ERROR, "vendor ID should be 4 bytes\n"); + return AVERROR(EINVAL); } if (avctx->profile == FF_PROFILE_UNKNOWN) { - avctx->profile = FF_PROFILE_PRORES_STANDARD; - av_log(avctx, AV_LOG_INFO, + if (avctx->pix_fmt == AV_PIX_FMT_YUV422P10) { + avctx->profile = FF_PROFILE_PRORES_STANDARD; + av_log(avctx, AV_LOG_INFO, "encoding with ProRes standard (apcn) profile\n"); - + } else if (avctx->pix_fmt == AV_PIX_FMT_YUV444P10) { + avctx->profile = FF_PROFILE_PRORES_4444; + av_log(avctx, AV_LOG_INFO, + "encoding with ProRes 4444 (ap4h) profile\n"); + } else if (avctx->pix_fmt == AV_PIX_FMT_YUVA444P10) { + avctx->profile = FF_PROFILE_PRORES_4444; + av_log(avctx, AV_LOG_INFO, + "encoding with ProRes 4444+ (ap4h) profile\n"); + } else { + av_log(avctx, AV_LOG_ERROR, "Unknown pixel format\n"); + return AVERROR(EINVAL); + } } else if (avctx->profile < FF_PROFILE_PRORES_PROXY - || avctx->profile > FF_PROFILE_PRORES_HQ) { + || avctx->profile > FF_PROFILE_PRORES_XQ) { av_log( avctx, AV_LOG_ERROR, - "unknown profile %d, use [0 - apco, 1 - apcs, 2 - apcn (default), 3 - apch]\n", + "unknown profile %d, use [0 - apco, 1 - apcs, 2 - apcn (default), 3 - apch, 4 - ap4h, 5 - ap4x]\n", avctx->profile); return AVERROR(EINVAL); + } else if ((avctx->pix_fmt == AV_PIX_FMT_YUV422P10) && (avctx->profile > FF_PROFILE_PRORES_HQ)){ + av_log(avctx, AV_LOG_ERROR, + "encoding with ProRes 444/Xq (ap4h/ap4x) profile, need YUV444P10 input\n"); + return AVERROR(EINVAL); + } else if ((avctx->pix_fmt == AV_PIX_FMT_YUV444P10 || avctx->pix_fmt == AV_PIX_FMT_YUVA444P10) + && (avctx->profile < FF_PROFILE_PRORES_4444)){ + av_log(avctx, AV_LOG_ERROR, + "encoding with ProRes Proxy/LT/422/422 HQ (apco, apcs, apcn, ap4h) profile, need YUV422P10 input\n"); + return AVERROR(EINVAL); + } + + if (avctx->profile < FF_PROFILE_PRORES_4444) { /* 422 versions */ + ctx->is_422 = 1; + if ((avctx->height & 0xf) || (avctx->width & 0xf)) { + ctx->fill_y = av_malloc(4 * (DEFAULT_SLICE_MB_WIDTH << 8)); + if (!ctx->fill_y) + return AVERROR(ENOMEM); + ctx->fill_u = ctx->fill_y + (DEFAULT_SLICE_MB_WIDTH << 9); + ctx->fill_v = ctx->fill_u + (DEFAULT_SLICE_MB_WIDTH << 8); + } + } else { /* 444 */ + ctx->is_422 = 0; + if ((avctx->height & 0xf) || (avctx->width & 0xf)) { + ctx->fill_y = av_malloc(3 * (DEFAULT_SLICE_MB_WIDTH << 9)); + if (!ctx->fill_y) + return AVERROR(ENOMEM); + ctx->fill_u = ctx->fill_y + (DEFAULT_SLICE_MB_WIDTH << 9); + ctx->fill_v = ctx->fill_u + (DEFAULT_SLICE_MB_WIDTH << 9); + } + if (avctx->pix_fmt == AV_PIX_FMT_YUVA444P10) { + ctx->need_alpha = 1; + ctx->fill_a = av_malloc(DEFAULT_SLICE_MB_WIDTH << 9); /* 8 blocks x 16px x 16px x sizeof (uint16) */ + if (!ctx->fill_a) + return AVERROR(ENOMEM); + } } ff_fdctdsp_init(&ctx->fdsp, avctx); @@ -597,10 +915,33 @@ static av_cold int prores_encode_close(AVCodecContext *avctx) { ProresContext* ctx = avctx->priv_data; av_freep(&ctx->fill_y); + av_freep(&ctx->fill_a); return 0; } +#define OFFSET(x) offsetof(ProresContext, x) +#define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM + +static const AVOption options[] = { + { "vendor", "vendor ID", OFFSET(vendor), AV_OPT_TYPE_STRING, { .str = "fmpg" }, CHAR_MIN, CHAR_MAX, VE }, + { NULL } +}; + +static const AVClass proresaw_enc_class = { + .class_name = "ProResAw encoder", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; + +static const AVClass prores_enc_class = { + .class_name = "ProRes encoder", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; + AVCodec ff_prores_aw_encoder = { .name = "prores_aw", .long_name = NULL_IF_CONFIG_SMALL("Apple ProRes"), @@ -610,9 +951,10 @@ AVCodec ff_prores_aw_encoder = { .init = prores_encode_init, .close = prores_encode_close, .encode2 = prores_encode_frame, - .pix_fmts = (const enum AVPixelFormat[]){AV_PIX_FMT_YUV422P10, AV_PIX_FMT_NONE}, + .pix_fmts = (const enum AVPixelFormat[]){AV_PIX_FMT_YUV422P10, AV_PIX_FMT_YUV444P10, AV_PIX_FMT_YUVA444P10, AV_PIX_FMT_NONE}, .capabilities = AV_CODEC_CAP_FRAME_THREADS | AV_CODEC_CAP_INTRA_ONLY, - .profiles = profiles + .priv_class = &proresaw_enc_class, + .profiles = NULL_IF_CONFIG_SMALL(ff_prores_profiles), }; AVCodec ff_prores_encoder = { @@ -624,7 +966,8 @@ AVCodec ff_prores_encoder = { .init = prores_encode_init, .close = prores_encode_close, .encode2 = prores_encode_frame, - .pix_fmts = (const enum AVPixelFormat[]){AV_PIX_FMT_YUV422P10, AV_PIX_FMT_NONE}, + .pix_fmts = (const enum AVPixelFormat[]){AV_PIX_FMT_YUV422P10, AV_PIX_FMT_YUV444P10, AV_PIX_FMT_YUVA444P10, AV_PIX_FMT_NONE}, .capabilities = AV_CODEC_CAP_FRAME_THREADS | AV_CODEC_CAP_INTRA_ONLY, - .profiles = profiles + .priv_class = &prores_enc_class, + .profiles = NULL_IF_CONFIG_SMALL(ff_prores_profiles), }; diff --git a/libavcodec/proresenc_kostya.c b/libavcodec/proresenc_kostya.c index 06d5aa31e..e045a972f 100644 --- a/libavcodec/proresenc_kostya.c +++ b/libavcodec/proresenc_kostya.c @@ -28,6 +28,7 @@ #include "avcodec.h" #include "fdctdsp.h" #include "put_bits.h" +#include "profiles.h" #include "bytestream.h" #include "internal.h" #include "proresdata.h" @@ -51,9 +52,11 @@ enum { enum { QUANT_MAT_PROXY = 0, + QUANT_MAT_PROXY_CHROMA, QUANT_MAT_LT, QUANT_MAT_STANDARD, QUANT_MAT_HQ, + QUANT_MAT_XQ_LUMA, QUANT_MAT_DEFAULT, }; @@ -68,6 +71,16 @@ static const uint8_t prores_quant_matrices[][64] = { 13, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, }, + { // proxy chromas + 4, 7, 9, 11, 13, 14, 63, 63, + 7, 7, 11, 12, 14, 63, 63, 63, + 9, 11, 13, 14, 63, 63, 63, 63, + 11, 11, 13, 14, 63, 63, 63, 63, + 11, 13, 14, 63, 63, 63, 63, 63, + 13, 14, 63, 63, 63, 63, 63, 63, + 13, 63, 63, 63, 63, 63, 63, 63, + 63, 63, 63, 63, 63, 63, 63, 63 + }, { // LT 4, 5, 6, 7, 9, 11, 13, 15, 5, 5, 7, 8, 11, 13, 15, 17, @@ -98,6 +111,16 @@ static const uint8_t prores_quant_matrices[][64] = { 4, 4, 4, 4, 5, 5, 6, 7, 4, 4, 4, 4, 5, 6, 7, 7, }, + { // XQ luma + 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 3, + 2, 2, 2, 2, 2, 2, 3, 3, + 2, 2, 2, 2, 2, 3, 3, 3, + 2, 2, 2, 2, 3, 3, 3, 4, + 2, 2, 2, 2, 3, 3, 4, 4, + }, { // codec default 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, @@ -125,6 +148,7 @@ static const struct prores_profile { int max_quant; int br_tab[NUM_MB_LIMITS]; int quant; + int quant_chroma; } prores_profile_info[6] = { { .full_name = "proxy", @@ -133,6 +157,7 @@ static const struct prores_profile { .max_quant = 8, .br_tab = { 300, 242, 220, 194 }, .quant = QUANT_MAT_PROXY, + .quant_chroma = QUANT_MAT_PROXY_CHROMA, }, { .full_name = "LT", @@ -141,6 +166,7 @@ static const struct prores_profile { .max_quant = 9, .br_tab = { 720, 560, 490, 440 }, .quant = QUANT_MAT_LT, + .quant_chroma = QUANT_MAT_LT, }, { .full_name = "standard", @@ -149,6 +175,7 @@ static const struct prores_profile { .max_quant = 6, .br_tab = { 1050, 808, 710, 632 }, .quant = QUANT_MAT_STANDARD, + .quant_chroma = QUANT_MAT_STANDARD, }, { .full_name = "high quality", @@ -157,6 +184,7 @@ static const struct prores_profile { .max_quant = 6, .br_tab = { 1566, 1216, 1070, 950 }, .quant = QUANT_MAT_HQ, + .quant_chroma = QUANT_MAT_HQ, }, { .full_name = "4444", @@ -165,6 +193,7 @@ static const struct prores_profile { .max_quant = 6, .br_tab = { 2350, 1828, 1600, 1425 }, .quant = QUANT_MAT_HQ, + .quant_chroma = QUANT_MAT_HQ, }, { .full_name = "4444XQ", @@ -172,7 +201,8 @@ static const struct prores_profile { .min_quant = 1, .max_quant = 6, .br_tab = { 3525, 2742, 2400, 2137 }, - .quant = QUANT_MAT_HQ, + .quant = QUANT_MAT_HQ, /* Fix me : use QUANT_MAT_XQ_LUMA */ + .quant_chroma = QUANT_MAT_HQ, } }; @@ -192,6 +222,7 @@ typedef struct ProresThreadData { DECLARE_ALIGNED(16, int16_t, blocks)[MAX_PLANES][64 * 4 * MAX_MBS_PER_SLICE]; DECLARE_ALIGNED(16, uint16_t, emu_buf)[16 * 16]; int16_t custom_q[64]; + int16_t custom_chroma_q[64]; struct TrellisNode *nodes; } ProresThreadData; @@ -200,8 +231,11 @@ typedef struct ProresContext { DECLARE_ALIGNED(16, int16_t, blocks)[MAX_PLANES][64 * 4 * MAX_MBS_PER_SLICE]; DECLARE_ALIGNED(16, uint16_t, emu_buf)[16*16]; int16_t quants[MAX_STORED_Q][64]; + int16_t quants_chroma[MAX_STORED_Q][64]; int16_t custom_q[64]; + int16_t custom_chroma_q[64]; const uint8_t *quant_mat; + const uint8_t *quant_chroma_mat; const uint8_t *scantable; void (*fdct)(FDCTDSPContext *fdsp, const uint16_t *src, @@ -527,6 +561,7 @@ static int encode_slice(AVCodecContext *avctx, const AVFrame *pic, ptrdiff_t linesize; int plane_factor, is_chroma; uint16_t *qmat; + uint16_t *qmat_chroma; if (ctx->pictures_per_frame == 1) line_add = 0; @@ -535,12 +570,17 @@ static int encode_slice(AVCodecContext *avctx, const AVFrame *pic, if (ctx->force_quant) { qmat = ctx->quants[0]; + qmat_chroma = ctx->quants_chroma[0]; } else if (quant < MAX_STORED_Q) { qmat = ctx->quants[quant]; + qmat_chroma = ctx->quants_chroma[quant]; } else { qmat = ctx->custom_q; - for (i = 0; i < 64; i++) + qmat_chroma = ctx->custom_chroma_q; + for (i = 0; i < 64; i++) { qmat[i] = ctx->quant_mat[i] * quant; + qmat_chroma[i] = ctx->quant_chroma_mat[i] * quant; + } } for (i = 0; i < ctx->num_planes; i++) { @@ -569,10 +609,17 @@ static int encode_slice(AVCodecContext *avctx, const AVFrame *pic, pwidth, avctx->height / ctx->pictures_per_frame, ctx->blocks[0], ctx->emu_buf, mbs_per_slice, num_cblocks, is_chroma); - sizes[i] = encode_slice_plane(ctx, pb, src, linesize, - mbs_per_slice, ctx->blocks[0], - num_cblocks, plane_factor, - qmat); + if (!is_chroma) {/* luma quant */ + sizes[i] = encode_slice_plane(ctx, pb, src, linesize, + mbs_per_slice, ctx->blocks[0], + num_cblocks, plane_factor, + qmat); + } else { /* chroma plane */ + sizes[i] = encode_slice_plane(ctx, pb, src, linesize, + mbs_per_slice, ctx->blocks[0], + num_cblocks, plane_factor, + qmat_chroma); + } } else { get_alpha_data(ctx, src, linesize, xp, yp, pwidth, avctx->height / ctx->pictures_per_frame, @@ -771,6 +818,7 @@ static int find_slice_quant(AVCodecContext *avctx, int slice_bits[TRELLIS_WIDTH], slice_score[TRELLIS_WIDTH]; int overquant; uint16_t *qmat; + uint16_t *qmat_chroma; int linesize[4], line_add; int alpha_bits = 0; @@ -825,12 +873,17 @@ static int find_slice_quant(AVCodecContext *avctx, for (q = min_quant; q <= max_quant; q++) { bits = alpha_bits; error = 0; - for (i = 0; i < ctx->num_planes - !!ctx->alpha_bits; i++) { + bits += estimate_slice_plane(ctx, &error, 0, + src, linesize[0], + mbs_per_slice, + num_cblocks[0], plane_factor[0], + ctx->quants[q], td); /* estimate luma plane */ + for (i = 1; i < ctx->num_planes - !!ctx->alpha_bits; i++) { /* estimate chroma plane */ bits += estimate_slice_plane(ctx, &error, i, src, linesize[i], mbs_per_slice, num_cblocks[i], plane_factor[i], - ctx->quants[q], td); + ctx->quants_chroma[q], td); } if (bits > 65000 * 8) error = SCORE_LIMIT; @@ -848,17 +901,26 @@ static int find_slice_quant(AVCodecContext *avctx, error = 0; if (q < MAX_STORED_Q) { qmat = ctx->quants[q]; + qmat_chroma = ctx->quants_chroma[q]; } else { qmat = td->custom_q; - for (i = 0; i < 64; i++) + qmat_chroma = td->custom_chroma_q; + for (i = 0; i < 64; i++) { qmat[i] = ctx->quant_mat[i] * q; + qmat_chroma[i] = ctx->quant_chroma_mat[i] * q; + } } - for (i = 0; i < ctx->num_planes - !!ctx->alpha_bits; i++) { + bits += estimate_slice_plane(ctx, &error, 0, + src, linesize[0], + mbs_per_slice, + num_cblocks[0], plane_factor[0], + qmat, td);/* estimate luma plane */ + for (i = 1; i < ctx->num_planes - !!ctx->alpha_bits; i++) { /* estimate chroma plane */ bits += estimate_slice_plane(ctx, &error, i, src, linesize[i], mbs_per_slice, num_cblocks[i], plane_factor[i], - qmat, td); + qmat_chroma, td); } if (bits <= ctx->bits_per_mb * mbs_per_slice) break; @@ -1194,10 +1256,13 @@ FF_ENABLE_DEPRECATION_WARNINGS ctx->slices_per_picture = ctx->mb_height * ctx->slices_width; ctx->pictures_per_frame = 1 + interlaced; - if (ctx->quant_sel == -1) + if (ctx->quant_sel == -1) { ctx->quant_mat = prores_quant_matrices[ctx->profile_info->quant]; - else + ctx->quant_chroma_mat = prores_quant_matrices[ctx->profile_info->quant_chroma]; + } else { ctx->quant_mat = prores_quant_matrices[ctx->quant_sel]; + ctx->quant_chroma_mat = prores_quant_matrices[ctx->quant_sel]; + } if (strlen(ctx->vendor) != 4) { av_log(avctx, AV_LOG_ERROR, "vendor ID should be 4 bytes\n"); @@ -1222,8 +1287,10 @@ FF_ENABLE_DEPRECATION_WARNINGS min_quant = ctx->profile_info->min_quant; max_quant = ctx->profile_info->max_quant; for (i = min_quant; i < MAX_STORED_Q; i++) { - for (j = 0; j < 64; j++) + for (j = 0; j < 64; j++) { ctx->quants[i][j] = ctx->quant_mat[j] * i; + ctx->quants_chroma[i][j] = ctx->quant_chroma_mat[j] * i; + } } ctx->slice_q = av_malloc(ctx->slices_per_picture * sizeof(*ctx->slice_q)); @@ -1254,6 +1321,7 @@ FF_ENABLE_DEPRECATION_WARNINGS } } else { int ls = 0; + int ls_chroma = 0; if (ctx->force_quant > 64) { av_log(avctx, AV_LOG_ERROR, "too large quantiser, maximum is 64\n"); @@ -1262,12 +1330,14 @@ FF_ENABLE_DEPRECATION_WARNINGS for (j = 0; j < 64; j++) { ctx->quants[0][j] = ctx->quant_mat[j] * ctx->force_quant; + ctx->quants_chroma[0][j] = ctx->quant_chroma_mat[j] * ctx->force_quant; ls += av_log2((1 << 11) / ctx->quants[0][j]) * 2 + 1; + ls_chroma += av_log2((1 << 11) / ctx->quants_chroma[0][j]) * 2 + 1; } - ctx->bits_per_mb = ls * 8; + ctx->bits_per_mb = ls * 4 + ls_chroma * 4; if (ctx->chroma_factor == CFACTOR_Y444) - ctx->bits_per_mb += ls * 4; + ctx->bits_per_mb += ls_chroma * 4; } ctx->frame_size_upper_bound = (ctx->pictures_per_frame * @@ -1364,4 +1434,5 @@ AVCodec ff_prores_ks_encoder = { AV_PIX_FMT_YUVA444P10, AV_PIX_FMT_NONE }, .priv_class = &proresenc_class, + .profiles = NULL_IF_CONFIG_SMALL(ff_prores_profiles), }; diff --git a/libavcodec/prosumer.c b/libavcodec/prosumer.c new file mode 100644 index 000000000..995051960 --- /dev/null +++ b/libavcodec/prosumer.c @@ -0,0 +1,380 @@ +/* + * Brooktree ProSumer Video decoder + * Copyright (c) 2018 Paul B Mahol + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include + +#include "libavutil/imgutils.h" +#include "libavutil/internal.h" +#include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" + +#include "avcodec.h" +#include "bytestream.h" +#include "internal.h" + +typedef struct ProSumerContext { + GetByteContext gb; + PutByteContext pb; + + unsigned stride; + unsigned size; + uint32_t lut[0x2000]; + uint8_t *initial_line; + uint8_t *decbuffer; +} ProSumerContext; + +#define PAIR(high, low) (((uint64_t)(high) << 32) | low) + +static int decompress(GetByteContext *gb, int size, PutByteContext *pb, const uint32_t *lut) +{ + int pos, idx, cnt, fill; + uint32_t a, b, c; + + bytestream2_skip(gb, 32); + cnt = 4; + a = bytestream2_get_le32(gb); + idx = a >> 20; + b = lut[2 * idx]; + + while (1) { + if (bytestream2_get_bytes_left_p(pb) <= 0 || bytestream2_get_eof(pb)) + return 0; + if ((b & 0xFF00u) != 0x8000u || (b & 0xFFu)) { + if ((b & 0xFF00u) != 0x8000u) { + bytestream2_put_le16(pb, b); + } else { + idx = 0; + for (int i = 0; i < (b & 0xFFu); i++) + bytestream2_put_le32(pb, 0); + } + c = b >> 16; + if (c & 0xFF00u) { + fill = lut[2 * idx + 1]; + if ((c & 0xF000u) == 0x1000) { + bytestream2_put_le16(pb, fill); + } else { + bytestream2_put_le32(pb, fill); + } + c = (c >> 8) & 0x0Fu; + } + while (c) { + a <<= 4; + cnt--; + if (!cnt) { + if (bytestream2_get_bytes_left(gb) <= 0) { + if (!a) + return 0; + } else { + pos = bytestream2_tell(gb); + bytestream2_seek(gb, pos ^ 2, SEEK_SET); + AV_WN16(&a, bytestream2_peek_le16(gb)); + bytestream2_seek(gb, pos + 2, SEEK_SET); + } + cnt = 4; + } + c--; + } + idx = a >> 20; + b = lut[2 * idx]; + if (!b) + return AVERROR_INVALIDDATA; + continue; + } + idx = 2; + while (idx) { + a <<= 4; + cnt--; + if (cnt) { + idx--; + continue; + } + if (bytestream2_get_bytes_left(gb) <= 0) { + if (a) { + cnt = 4; + idx--; + continue; + } + return 0; + } + pos = bytestream2_tell(gb); + bytestream2_seek(gb, pos ^ 2, SEEK_SET); + AV_WN16(&a, bytestream2_peek_le16(gb)); + bytestream2_seek(gb, pos + 2, SEEK_SET); + cnt = 4; + idx--; + } + b = PAIR(4, a) >> 16; + } + + return 0; +} + +static void vertical_predict(uint32_t *dst, int offset, const uint32_t *src, int stride, int height) +{ + dst += offset >> 2; + + for (int i = 0; i < height; i++) { + for (int j = 0; j < stride >> 2; j++) { + dst[j] = (((src[j] >> 3) + (0x3F3F3F3F & dst[j])) << 3) & 0xFCFCFCFC; + } + + dst += stride >> 2; + src += stride >> 2; + } +} + +static int decode_frame(AVCodecContext *avctx, void *data, + int *got_frame, AVPacket *avpkt) +{ + ProSumerContext *s = avctx->priv_data; + AVFrame * const frame = data; + int ret; + + if (avpkt->size <= 32) + return AVERROR_INVALIDDATA; + + bytestream2_init(&s->gb, avpkt->data, avpkt->size); + bytestream2_init_writer(&s->pb, s->decbuffer, s->size); + ret = decompress(&s->gb, AV_RL32(avpkt->data + 28) >> 1, &s->pb, s->lut); + if (ret < 0) + return ret; + if (bytestream2_get_bytes_left_p(&s->pb) > s->size * (int64_t)avctx->discard_damaged_percentage / 100) + return AVERROR_INVALIDDATA; + + av_assert0(s->size >= bytestream2_get_bytes_left_p(&s->pb)); + memset(s->decbuffer + bytestream2_tell_p(&s->pb), 0, bytestream2_get_bytes_left_p(&s->pb)); + + vertical_predict((uint32_t *)s->decbuffer, 0, (uint32_t *)s->initial_line, s->stride, 1); + vertical_predict((uint32_t *)s->decbuffer, s->stride, (uint32_t *)s->decbuffer, s->stride, avctx->height - 1); + + ret = ff_get_buffer(avctx, frame, 0); + if (ret < 0) + return ret; + + for (int i = avctx->height - 1; i >= 0 ; i--) { + uint8_t *y = &frame->data[0][i * frame->linesize[0]]; + uint8_t *u = &frame->data[1][i * frame->linesize[1]]; + uint8_t *v = &frame->data[2][i * frame->linesize[2]]; + const uint8_t *src = s->decbuffer + (avctx->height - 1 - i) * s->stride; + + for (int j = 0; j < avctx->width; j += 8) { + *(u++) = *src++; + *(y++) = *src++; + *(v++) = *src++; + *(y++) = *src++; + + *(u++) = *src++; + *(y++) = *src++; + *(v++) = *src++; + *(y++) = *src++; + + *(y++) = *src++; + *(y++) = *src++; + *(y++) = *src++; + *(y++) = *src++; + } + } + + frame->pict_type = AV_PICTURE_TYPE_I; + frame->key_frame = 1; + *got_frame = 1; + + return avpkt->size; +} + +#define TB(i) (1 + ((i) > 10) + ((i) > 49)) +static const uint16_t table[] = { + 0x0000, 0x100, 0x0101, 0x200, 0x0202, 0x300, 0xFFFF, 0x400, 0xFEFE, 0x500, + 0x0001, 0x700, 0x0100, 0x800, 0x00FF, 0x900, 0xFF00, 0xA00, 0x8001, 0x600, + 0x8002, 0xB00, 0xFCFC, 0x010, 0x0404, 0x030, 0x0002, 0xD30, 0xFEFC, 0x020, + 0xFCFE, 0x040, 0xFEFF, 0xD20, 0x0808, 0x060, 0xFFFE, 0x050, 0x0402, 0xC00, + 0x0204, 0xC10, 0xF8F8, 0xC30, 0x0201, 0xC40, 0x0102, 0xC60, 0x0804, 0xF30, + 0x0408, 0xE00, 0xF8FC, 0xE10, 0xFCF8, 0xC70, 0x00FE, 0xD00, 0xFE00, 0xD40, + 0xFF01, 0xD50, 0x01FF, 0xD60, 0x0200, 0xD70, 0xFCFF, 0xE20, 0x0104, 0xE30, + 0xF0F0, 0xE50, 0x0401, 0xE70, 0x02FE, 0xF00, 0xFE02, 0xF10, 0xFE01, 0xF20, + 0x01FE, 0xF40, 0xFF02, 0xF50, 0x02FF, 0xF60, 0x8003, 0xC20, 0x8004, 0x070, + 0x8005, 0xD10, 0x8006, 0xC50, 0x8007, 0xE60, 0x8008, 0xE40, 0x8009, 0xF70, + 0xFC02, 0x080, 0xFE04, 0x081, 0xFC00, 0x082, 0x02FC, 0x083, 0x1010, 0x084, + 0x00FC, 0x085, 0x0004, 0x086, 0x0400, 0x087, 0xFFFC, 0x088, 0x1008, 0x089, + 0x0810, 0x08A, 0x0802, 0x08B, 0x0208, 0x08C, 0xFEF8, 0x08D, 0xFC01, 0x08E, + 0x04FF, 0x08F, 0xF8FE, 0x090, 0xFC04, 0x091, 0x04FC, 0x092, 0xFF04, 0x093, + 0x01FC, 0x094, 0xF0F8, 0x095, 0xF8F0, 0x096, 0x04FE, 0x097, 0xF0FC, 0x098, + 0x0008, 0x099, 0x08FE, 0x09A, 0x01F8, 0x09B, 0x0800, 0x09C, 0x08FC, 0x09D, + 0xFE08, 0x09E, 0xFC08, 0x09F, 0xF800, 0x0A0, 0x0108, 0x0A1, 0xF802, 0x0A2, + 0x0801, 0x0A3, 0x00F8, 0x0A4, 0xF804, 0x0A5, 0xF8FF, 0x0A6, 0xFFF8, 0x0A7, + 0x04F8, 0x0A8, 0x02F8, 0x0A9, 0x1004, 0x0AA, 0x08F8, 0x0AB, 0xF808, 0x0AC, + 0x0410, 0x0AD, 0xFF08, 0x0AE, 0x08FF, 0x0AF, 0xFCF0, 0x0B0, 0xF801, 0x0B1, + 0xE0F0, 0x0B2, 0xF3F3, 0x0B3, 0xF0E0, 0x0B4, 0xFAFA, 0x0B5, 0xF7F7, 0x0B6, + 0xFEF0, 0x0B7, 0xF0FE, 0x0B8, 0xE9E9, 0x0B9, 0xF9F9, 0x0BA, 0x2020, 0x0BB, + 0xE0E0, 0x0BC, 0x02F0, 0x0BD, 0x04F0, 0x0BE, 0x2010, 0x0BF, 0xECEC, 0x0C0, + 0xEFEF, 0x0C1, 0x1020, 0x0C2, 0xF5F5, 0x0C3, 0xF4F4, 0x0C4, 0xEDED, 0x0C5, + 0xEAEA, 0x0C6, 0xFBFB, 0x0C7, 0x1002, 0x0C8, 0xF2F2, 0x0C9, 0xF6F6, 0x0CA, + 0xF1F1, 0x0CB, 0xFDFD, 0x0CC, 0x0210, 0x0CD, 0x10FF, 0x0CE, 0xFDFE, 0x0CF, + 0x10F8, 0x0D0, 0x1000, 0x0D1, 0xF001, 0x0D2, 0x1001, 0x0D3, 0x0010, 0x0D4, + 0x10FE, 0x0D5, 0xEBEB, 0x0D6, 0xFE10, 0x0D7, 0x0110, 0x0D8, 0xF000, 0x0D9, + 0x08F0, 0x0DA, 0x01F0, 0x0DB, 0x0303, 0x0DC, 0x00F0, 0x0DD, 0xF002, 0x0DE, + 0x10FC, 0x0DF, 0xFC10, 0x0E0, 0xF0FF, 0x0E1, 0xEEEE, 0x0E2, 0xF004, 0x0E3, + 0xFFF0, 0x0E4, 0xF7F8, 0x0E5, 0xF3F2, 0x0E6, 0xF9FA, 0x0E7, 0x0820, 0x0E8, + 0x0302, 0x0E9, 0xE0F8, 0x0EA, 0x0505, 0x0EB, 0x2008, 0x0EC, 0xE8E8, 0x0ED, + 0x0403, 0x0EE, 0xFBFC, 0x0EF, 0xFCFD, 0x0F0, 0xFBFA, 0x0F1, 0x0203, 0x0F2, + 0xFCFB, 0x0F3, 0x0304, 0x0F4, 0xF810, 0x0F5, 0xFF10, 0x0F6, 0xF008, 0x0F7, + 0xFEFD, 0x0F8, 0xF7F6, 0x0F9, 0xF2F1, 0x0FA, 0xF3F4, 0x0FB, 0xEDEC, 0x0FC, + 0xF4F1, 0x0FD, 0xF5F6, 0x0FE, 0xF0F1, 0x0FF, 0xF9F8, 0xC80, 0x10F0, 0xC81, + 0xF2F3, 0xC82, 0xF7F9, 0xC83, 0xF6F5, 0xC84, 0xF0EF, 0xC85, 0xF4F5, 0xC86, + 0xF6F7, 0xC87, 0xFAF9, 0xC88, 0x0405, 0xC89, 0xF8F9, 0xC8A, 0xFAFB, 0xC8B, + 0xF1F0, 0xC8C, 0xF4F3, 0xC8D, 0xF1F2, 0xC8E, 0xF8E0, 0xC8F, 0xF8F7, 0xC90, + 0xFDFC, 0xC91, 0xF8FA, 0xC92, 0xFAF6, 0xC93, 0xEEEF, 0xC94, 0xF5F7, 0xC95, + 0xFDFB, 0xC96, 0xF4F6, 0xC97, 0xFCFA, 0xC98, 0xECED, 0xC99, 0xF0F3, 0xC9A, + 0xF3F1, 0xC9B, 0xECEB, 0xC9C, 0xEDEE, 0xC9D, 0xF9F7, 0xC9E, 0x0420, 0xC9F, + 0xEBEA, 0xCA0, 0xF0F4, 0xCA1, 0xF3F5, 0xCA2, 0xFAF7, 0xCA3, 0x0301, 0xCA4, + 0xF3F7, 0xCA5, 0xF7F3, 0xCA6, 0xEFF0, 0xCA7, 0xF9F6, 0xCA8, 0xEFEE, 0xCA9, + 0xF4F7, 0xCAA, 0x0504, 0xCAB, 0xF5F4, 0xCAC, 0xF1F3, 0xCAD, 0xEBEE, 0xCAE, + 0xF2F5, 0xCAF, 0xF3EF, 0xCB0, 0xF5F1, 0xCB1, 0xF9F3, 0xCB2, 0xEDF0, 0xCB3, + 0xEEF1, 0xCB4, 0xF6F9, 0xCB5, 0xF8FB, 0xCB6, 0xF010, 0xCB7, 0xF2F6, 0xCB8, + 0xF4ED, 0xCB9, 0xF7FB, 0xCBA, 0xF8F3, 0xCBB, 0xEDEB, 0xCBC, 0xF0F2, 0xCBD, + 0xF2F9, 0xCBE, 0xF8F1, 0xCBF, 0xFAFC, 0xCC0, 0xFBF8, 0xCC1, 0xF6F0, 0xCC2, + 0xFAF8, 0xCC3, 0x0103, 0xCC4, 0xF3F6, 0xCC5, 0xF4F9, 0xCC6, 0xF7F2, 0xCC7, + 0x2004, 0xCC8, 0xF2F0, 0xCC9, 0xF4F2, 0xCCA, 0xEEED, 0xCCB, 0xFCE0, 0xCCC, + 0xEAE9, 0xCCD, 0xEAEB, 0xCCE, 0xF6F4, 0xCCF, 0xFFFD, 0xCD0, 0xE9EA, 0xCD1, + 0xF1F4, 0xCD2, 0xF6EF, 0xCD3, 0xF6F8, 0xCD4, 0xF8F6, 0xCD5, 0xEFF2, 0xCD6, + 0xEFF1, 0xCD7, 0xF7F1, 0xCD8, 0xFBFD, 0xCD9, 0xFEF6, 0xCDA, 0xFFF7, 0xCDB, + 0x0605, 0xCDC, 0xF0F5, 0xCDD, 0xF0FA, 0xCDE, 0xF1F9, 0xCDF, 0xF2FC, 0xCE0, + 0xF7EE, 0xCE1, 0xF7F5, 0xCE2, 0xF9FC, 0xCE3, 0xFAF5, 0xCE4, 0xFBF1, 0xCE5, + 0xF1EF, 0xCE6, 0xF1FA, 0xCE7, 0xF4F8, 0xCE8, 0xF7F0, 0xCE9, 0xF7F4, 0xCEA, + 0xF7FC, 0xCEB, 0xF9FB, 0xCEC, 0xFAF1, 0xCED, 0xFBF9, 0xCEE, 0xFDFF, 0xCEF, + 0xE0FC, 0xCF0, 0xEBEC, 0xCF1, 0xEDEF, 0xCF2, 0xEFED, 0xCF3, 0xF1F6, 0xCF4, + 0xF2F7, 0xCF5, 0xF3EE, 0xCF6, 0xF3F8, 0xCF7, 0xF5F2, 0xCF8, 0xF8F2, 0xCF9, + 0xF9F1, 0xCFA, 0xF9F2, 0xCFB, 0xFBEF, 0xCFC, 0x00FD, 0xCFD, 0xECEE, 0xCFE, + 0xF2EF, 0xCFF, 0xF2F8, 0xD80, 0xF5F0, 0xD81, 0xF6F2, 0xD82, 0xFCF7, 0xD83, + 0xFCF9, 0xD84, 0x0506, 0xD85, 0xEEEC, 0xD86, 0xF0F6, 0xD87, 0xF2F4, 0xD88, + 0xF6F1, 0xD89, 0xF8F5, 0xD8A, 0xF9F4, 0xD8B, 0xFBF7, 0xD8C, 0x0503, 0xD8D, + 0xEFEC, 0xD8E, 0xF3F0, 0xD8F, 0xF4F0, 0xD90, 0xF5F3, 0xD91, 0xF6F3, 0xD92, + 0xF7FA, 0xD93, 0x800A, 0xD94, 0x800B, 0xD95, 0x800C, 0xD96, 0x800D, 0xD97, + 0x800E, 0xD98, 0x800F, 0xD99, 0x8010, 0xD9A, 0x8011, 0xD9B, 0x8012, 0xD9C, + 0x8013, 0xD9D, 0x8014, 0xD9E, 0x8015, 0xD9F, 0x8016, 0xDA0, 0x8017, 0xDA1, + 0x8018, 0xDA2, 0x8019, 0xDA3, 0x801A, 0xDA4, 0x801B, 0xDA5, 0x801C, 0xDA6, + 0x801D, 0xDA7, 0x801E, 0xDA8, 0x801F, 0xDA9, 0x8020, 0xDAA, 0x8021, 0xDAB, + 0x8022, 0xDAC, 0x8023, 0xDAD, 0x8024, 0xDAE, 0x8025, 0xDAF, 0x8026, 0xDB0, + 0x8027, 0xDB1, 0x8028, 0xDB2, 0x8029, 0xDB3, 0x802A, 0xDB4, 0x802B, 0xDB5, + 0x802C, 0xDB6, 0x802D, 0xDB7, 0x802E, 0xDB8, 0x802F, 0xDB9, 0x80FF, 0xDBA, +}; + +static void fill_elements(uint32_t idx, uint32_t shift, uint32_t *e0, uint32_t *e1) +{ + uint32_t b, h = idx << (32 - shift); + + for (int j = 0; j < 2; j++) { + for (int i = 0; i < 43; i++) { + b = 4 * TB(i); + if (shift >= b && ((h & (0xFFF00000u << (12 - b))) >> 20) == table[2 * i + 1]) { + if (table[2 * i] >> 8 == 0x80u) { + return; + } else { + *e0 = (*e0 & 0xFFFFFFu) | (((12 + b - shift) | (0x40u<>1); + uint32_t c, d; + + c = (b << 16) | table[i-1]; + d = 4 * (3 - b); + if (d <= 0) { + lut[2 * a] = c; + lut[2 * a + 1] = 0; + } else { + for (int j = 0; j < 1 << d; j++) { + uint32_t f = 0xFFFFFFFFu; + c &= 0xFFFFFFu; + if ((c & 0xFF00u) != 0x8000u) + fill_elements(j, d, &c, &f); + lut[2 * a + 2 * j] = c; + lut[2 * a + 2 * j + 1] = f; + } + } + } + + for (int i = 0; i < 32; i += 2) { + lut[i ] = 0x68000; + lut[i+1] = 0; + } +} + +static av_cold int decode_init(AVCodecContext *avctx) +{ + ProSumerContext *s = avctx->priv_data; + + s->stride = 3LL * FFALIGN(avctx->width, 8) >> 1; + s->size = avctx->height * s->stride; + + avctx->pix_fmt = AV_PIX_FMT_YUV411P; + + s->initial_line = av_malloc(s->stride); + s->decbuffer = av_malloc(s->size); + if (!s->initial_line || !s->decbuffer) + return AVERROR(ENOMEM); + memset(s->initial_line, 0x80u, s->stride); + + fill_lut(s->lut); + + return 0; +} + +static av_cold int decode_close(AVCodecContext *avctx) +{ + ProSumerContext *s = avctx->priv_data; + + av_freep(&s->initial_line); + av_freep(&s->decbuffer); + + return 0; +} + +AVCodec ff_prosumer_decoder = { + .name = "prosumer", + .long_name = NULL_IF_CONFIG_SMALL("Brooktree ProSumer Video"), + .type = AVMEDIA_TYPE_VIDEO, + .id = AV_CODEC_ID_PROSUMER, + .priv_data_size = sizeof(ProSumerContext), + .init = decode_init, + .decode = decode_frame, + .close = decode_close, + .capabilities = AV_CODEC_CAP_DR1, + .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE | + FF_CODEC_CAP_INIT_CLEANUP, +}; diff --git a/libavcodec/psd.c b/libavcodec/psd.c index 66f2ec28d..a31f73857 100644 --- a/libavcodec/psd.c +++ b/libavcodec/psd.c @@ -337,6 +337,30 @@ static int decode_frame(AVCodecContext *avctx, void *data, } avctx->pix_fmt = AV_PIX_FMT_PAL8; break; + case PSD_CMYK: + if (s->channel_count == 4) { + if (s->channel_depth == 8) { + avctx->pix_fmt = AV_PIX_FMT_GBRP; + } else if (s->channel_depth == 16) { + avctx->pix_fmt = AV_PIX_FMT_GBRP16BE; + } else { + avpriv_report_missing_feature(avctx, "channel depth %d for cmyk", s->channel_depth); + return AVERROR_PATCHWELCOME; + } + } else if (s->channel_count == 5) { + if (s->channel_depth == 8) { + avctx->pix_fmt = AV_PIX_FMT_GBRAP; + } else if (s->channel_depth == 16) { + avctx->pix_fmt = AV_PIX_FMT_GBRAP16BE; + } else { + avpriv_report_missing_feature(avctx, "channel depth %d for cmyk", s->channel_depth); + return AVERROR_PATCHWELCOME; + } + } else { + avpriv_report_missing_feature(avctx, "channel count %d for cmyk", s->channel_count); + return AVERROR_PATCHWELCOME; + } + break; case PSD_RGB: if (s->channel_count == 3) { if (s->channel_depth == 8) { @@ -369,6 +393,8 @@ static int decode_frame(AVCodecContext *avctx, void *data, avctx->pix_fmt = AV_PIX_FMT_GRAY8; } else if (s->channel_depth == 16) { avctx->pix_fmt = AV_PIX_FMT_GRAY16BE; + } else if (s->channel_depth == 32) { + avctx->pix_fmt = AV_PIX_FMT_GRAYF32BE; } else { avpriv_report_missing_feature(avctx, "channel depth %d for grayscale", s->channel_depth); return AVERROR_PATCHWELCOME; @@ -433,6 +459,66 @@ static int decode_frame(AVCodecContext *avctx, void *data, } } } + } else if (s->color_mode == PSD_CMYK) { + uint8_t *dst[4] = { picture->data[0], picture->data[1], picture->data[2], picture->data[3] }; + const uint8_t *src[5] = { ptr_data }; + src[1] = src[0] + s->line_size * s->height; + src[2] = src[1] + s->line_size * s->height; + src[3] = src[2] + s->line_size * s->height; + src[4] = src[3] + s->line_size * s->height; + if (s->channel_depth == 8) { + for (y = 0; y < s->height; y++) { + for (x = 0; x < s->width; x++) { + int k = src[3][x]; + int r = src[0][x] * k; + int g = src[1][x] * k; + int b = src[2][x] * k; + dst[0][x] = g * 257 >> 16; + dst[1][x] = b * 257 >> 16; + dst[2][x] = r * 257 >> 16; + } + dst[0] += picture->linesize[0]; + dst[1] += picture->linesize[1]; + dst[2] += picture->linesize[2]; + src[0] += s->line_size; + src[1] += s->line_size; + src[2] += s->line_size; + src[3] += s->line_size; + } + if (avctx->pix_fmt == AV_PIX_FMT_GBRAP) { + for (y = 0; y < s->height; y++) { + memcpy(dst[3], src[4], s->line_size); + src[4] += s->line_size; + dst[3] += picture->linesize[3]; + } + } + } else { + for (y = 0; y < s->height; y++) { + for (x = 0; x < s->width; x++) { + int64_t k = AV_RB16(&src[3][x * 2]); + int64_t r = AV_RB16(&src[0][x * 2]) * k; + int64_t g = AV_RB16(&src[1][x * 2]) * k; + int64_t b = AV_RB16(&src[2][x * 2]) * k; + AV_WB16(&dst[0][x * 2], g * 65537 >> 32); + AV_WB16(&dst[1][x * 2], b * 65537 >> 32); + AV_WB16(&dst[2][x * 2], r * 65537 >> 32); + } + dst[0] += picture->linesize[0]; + dst[1] += picture->linesize[1]; + dst[2] += picture->linesize[2]; + src[0] += s->line_size; + src[1] += s->line_size; + src[2] += s->line_size; + src[3] += s->line_size; + } + if (avctx->pix_fmt == AV_PIX_FMT_GBRAP16BE) { + for (y = 0; y < s->height; y++) { + memcpy(dst[3], src[4], s->line_size); + src[4] += s->line_size; + dst[3] += picture->linesize[3]; + } + } + } } else {/* Planar */ if (s->channel_count == 1)/* gray 8 or gray 16be */ eq_channel[0] = 0;/* assign first channel, to first plane */ diff --git a/libavcodec/pthread_frame.c b/libavcodec/pthread_frame.c index 5104b1beb..36ac0ac1e 100644 --- a/libavcodec/pthread_frame.c +++ b/libavcodec/pthread_frame.c @@ -908,8 +908,7 @@ static int thread_get_buffer_internal(AVCodecContext *avctx, ThreadFrame *f, int } pthread_mutex_lock(&p->parent->buffer_mutex); - if (avctx->thread_safe_callbacks || - avctx->get_buffer2 == avcodec_default_get_buffer2) { + if (THREAD_SAFE_CALLBACKS(avctx)) { err = ff_get_buffer(avctx, f->f, flags); } else { pthread_mutex_lock(&p->progress_mutex); @@ -976,8 +975,7 @@ void ff_thread_release_buffer(AVCodecContext *avctx, ThreadFrame *f) FrameThreadContext *fctx; AVFrame *dst, *tmp; int can_direct_free = !(avctx->active_thread_type & FF_THREAD_FRAME) || - avctx->thread_safe_callbacks || - avctx->get_buffer2 == avcodec_default_get_buffer2; + THREAD_SAFE_CALLBACKS(avctx); if (!f->f || !f->f->buf[0]) return; diff --git a/libavcodec/qdm2.c b/libavcodec/qdm2.c index 88b6b19d1..ac8ae8cbb 100644 --- a/libavcodec/qdm2.c +++ b/libavcodec/qdm2.c @@ -408,7 +408,12 @@ static int fix_coding_method_array(int sb, int channels, } for (k = 0; k < run; k++) { if (j + k < 128) { - if (coding_method[ch][sb + (j + k) / 64][(j + k) % 64] > coding_method[ch][sb][j]) { + int sbjk = sb + (j + k) / 64; + if (sbjk > 29) { + SAMPLES_NEEDED + continue; + } + if (coding_method[ch][sbjk][(j + k) % 64] > coding_method[ch][sb][j]) { if (k > 0) { SAMPLES_NEEDED //not debugged, almost never used @@ -1284,6 +1289,10 @@ static void qdm2_fft_decode_tones(QDM2Context *q, int duration, } offset += (n - 2); } else { + if (local_int_10 <= 2) { + av_log(NULL, AV_LOG_ERROR, "qdm2_fft_decode_tones() stuck\n"); + return; + } offset += qdm2_get_vlc(gb, &vlc_tab_fft_tone_offset[local_int_8], 1, 2); while (offset >= (local_int_10 - 1)) { offset += (1 - (local_int_10 - 1)); @@ -1695,13 +1704,19 @@ static av_cold int qdm2_decode_init(AVCodecContext *avctx) s->group_size = bytestream2_get_be32(&gb); s->fft_size = bytestream2_get_be32(&gb); s->checksum_size = bytestream2_get_be32(&gb); - if (s->checksum_size >= 1U << 28) { - av_log(avctx, AV_LOG_ERROR, "data block size too large (%u)\n", s->checksum_size); + if (s->checksum_size >= 1U << 28 || !s->checksum_size) { + av_log(avctx, AV_LOG_ERROR, "data block size invalid (%u)\n", s->checksum_size); return AVERROR_INVALIDDATA; } s->fft_order = av_log2(s->fft_size) + 1; + // Fail on unknown fft order + if ((s->fft_order < 7) || (s->fft_order > 9)) { + avpriv_request_sample(avctx, "Unknown FFT order %d", s->fft_order); + return AVERROR_PATCHWELCOME; + } + // something like max decodable tones s->group_order = av_log2(s->group_size) + 1; s->frame_size = s->group_size / 16; // 16 iterations per super block @@ -1712,6 +1727,11 @@ static av_cold int qdm2_decode_init(AVCodecContext *avctx) s->sub_sampling = s->fft_order - 7; s->frequency_range = 255 / (1 << (2 - s->sub_sampling)); + if (s->frame_size * 4 >> s->sub_sampling > MPA_FRAME_SIZE) { + avpriv_request_sample(avctx, "large frames"); + return AVERROR_PATCHWELCOME; + } + switch ((s->sub_sampling * 2 + s->channels - 1)) { case 0: tmp = 40; break; case 1: tmp = 48; break; @@ -1735,11 +1755,6 @@ static av_cold int qdm2_decode_init(AVCodecContext *avctx) else s->coeff_per_sb_select = 2; - // Fail on unknown fft order - if ((s->fft_order < 7) || (s->fft_order > 9)) { - avpriv_request_sample(avctx, "Unknown FFT order %d", s->fft_order); - return AVERROR_PATCHWELCOME; - } if (s->fft_size != (1 << (s->fft_order - 1))) { av_log(avctx, AV_LOG_ERROR, "FFT size %d not power of 2.\n", s->fft_size); return AVERROR_INVALIDDATA; diff --git a/libavcodec/qdmc.c b/libavcodec/qdmc.c index f1f86accd..8bea1552e 100644 --- a/libavcodec/qdmc.c +++ b/libavcodec/qdmc.c @@ -253,7 +253,7 @@ static av_cold int qdmc_decode_init(AVCodecContext *avctx) { static AVOnce init_static_once = AV_ONCE_INIT; QDMCContext *s = avctx->priv_data; - int fft_size, fft_order, size, g, j, x; + int ret, fft_size, fft_order, size, g, j, x; GetByteContext b; ff_thread_once(&init_static_once, qdmc_init_static_data); @@ -338,7 +338,9 @@ static av_cold int qdmc_decode_init(AVCodecContext *avctx) return AVERROR_INVALIDDATA; } - ff_fft_init(&s->fft_ctx, fft_order, 1); + ret = ff_fft_init(&s->fft_ctx, fft_order, 1); + if (ret < 0) + return ret; avctx->sample_fmt = AV_SAMPLE_FMT_S16; @@ -575,9 +577,9 @@ static void add_noise(QDMCContext *s, int ch, int current_subframe) for (j = 2; j < s->subframe_size - 1; j++) { float rnd_re, rnd_im; - s->rndval = 214013 * s->rndval + 2531011; + s->rndval = 214013U * s->rndval + 2531011; rnd_im = ((s->rndval & 0x7FFF) - 16384.0f) * 0.000030517578f * s->noise2_buffer[j]; - s->rndval = 214013 * s->rndval + 2531011; + s->rndval = 214013U * s->rndval + 2531011; rnd_re = ((s->rndval & 0x7FFF) - 16384.0f) * 0.000030517578f * s->noise2_buffer[j]; im[j ] += rnd_im; re[j ] += rnd_re; diff --git a/libavcodec/qdrw.c b/libavcodec/qdrw.c index 82cc528a3..32ba41096 100644 --- a/libavcodec/qdrw.c +++ b/libavcodec/qdrw.c @@ -45,14 +45,14 @@ enum QuickdrawOpcodes { }; static int parse_palette(AVCodecContext *avctx, GetByteContext *gbc, - uint32_t *pal, int colors) + uint32_t *pal, int colors, int pixmap) { int i; for (i = 0; i <= colors; i++) { uint8_t r, g, b; unsigned int idx = bytestream2_get_be16(gbc); /* color index */ - if (idx > 255) { + if (idx > 255 && !pixmap) { av_log(avctx, AV_LOG_WARNING, "Palette index out of range: %u\n", idx); bytestream2_skip(gbc, 6); @@ -66,7 +66,7 @@ static int parse_palette(AVCodecContext *avctx, GetByteContext *gbc, bytestream2_skip(gbc, 1); b = bytestream2_get_byte(gbc); bytestream2_skip(gbc, 1); - pal[idx] = (0xFFU << 24) | (r << 16) | (g << 8) | b; + pal[pixmap ? i : idx] = (0xFFU << 24) | (r << 16) | (g << 8) | b; } return 0; } @@ -335,6 +335,7 @@ static int decode_frame(AVCodecContext *avctx, while (bytestream2_get_bytes_left(&gbc) >= 4) { int bppcnt, bpp; int rowbytes, pack_type; + int flags; int opcode = bytestream2_get_be16(&gbc); switch(opcode) { @@ -345,7 +346,8 @@ static int decode_frame(AVCodecContext *avctx, case PACKBITSRGN: av_log(avctx, AV_LOG_DEBUG, "Parsing Packbit opcode\n"); - bytestream2_skip(&gbc, 30); + flags = bytestream2_get_be16(&gbc) & 0xC000; + bytestream2_skip(&gbc, 28); bppcnt = bytestream2_get_be16(&gbc); /* cmpCount */ bpp = bytestream2_get_be16(&gbc); /* cmpSize */ @@ -380,7 +382,7 @@ static int decode_frame(AVCodecContext *avctx, if ((ret = ff_get_buffer(avctx, p, 0)) < 0) return ret; - ret = parse_palette(avctx, &gbc, (uint32_t *)p->data[1], colors); + ret = parse_palette(avctx, &gbc, (uint32_t *)p->data[1], colors, flags & 0x8000); if (ret < 0) return ret; p->palette_has_changed = 1; diff --git a/libavcodec/qpeg.c b/libavcodec/qpeg.c index 10b55d2df..d4195c5f0 100644 --- a/libavcodec/qpeg.c +++ b/libavcodec/qpeg.c @@ -80,11 +80,20 @@ static void qpeg_decode_intra(QpegContext *qctx, uint8_t *dst, p = bytestream2_get_byte(&qctx->buffer); for(i = 0; i < run; i++) { - dst[filled++] = p; + int step = FFMIN(run - i, width - filled); + memset(dst+filled, p, step); + filled += step; + i += step - 1; if (filled >= width) { filled = 0; dst -= stride; rows_to_go--; + while (run - i > width && rows_to_go > 0) { + memset(dst, p, width); + dst -= stride; + rows_to_go--; + i += width; + } if(rows_to_go <= 0) break; } diff --git a/libavcodec/qsv.c b/libavcodec/qsv.c index 45e1c25c6..986d4f602 100644 --- a/libavcodec/qsv.c +++ b/libavcodec/qsv.c @@ -31,6 +31,7 @@ #include "libavutil/hwcontext.h" #include "libavutil/hwcontext_qsv.h" #include "libavutil/imgutils.h" +#include "libavutil/avassert.h" #include "avcodec.h" #include "qsv_internal.h" @@ -66,22 +67,71 @@ int ff_qsv_codec_id_to_mfx(enum AVCodecID codec_id) return AVERROR(ENOSYS); } + +static const struct { + enum AVCodecID codec_id; + int codec_profile; + int mfx_profile; +} qsv_profile_map[] = { +#define MAP(c, p, v) { AV_CODEC_ID_ ## c, FF_PROFILE_ ## p, MFX_PROFILE_ ## v } + MAP(MPEG2VIDEO, MPEG2_SIMPLE, MPEG2_SIMPLE ), + MAP(MPEG2VIDEO, MPEG2_MAIN, MPEG2_MAIN ), + MAP(MPEG2VIDEO, MPEG2_HIGH, MPEG2_HIGH ), + + MAP(H264, H264_BASELINE, AVC_BASELINE ), + MAP(H264, H264_CONSTRAINED_BASELINE, AVC_BASELINE), +#if QSV_VERSION_ATLEAST(1, 3) + MAP(H264, H264_EXTENDED, AVC_EXTENDED ), +#endif + MAP(H264, H264_MAIN, AVC_MAIN ), + MAP(H264, H264_HIGH, AVC_HIGH ), + MAP(H264, H264_HIGH_422, AVC_HIGH_422 ), + +#if QSV_VERSION_ATLEAST(1, 8) + MAP(HEVC, HEVC_MAIN, HEVC_MAIN ), + MAP(HEVC, HEVC_MAIN_10, HEVC_MAIN10 ), + MAP(HEVC, HEVC_MAIN_STILL_PICTURE, HEVC_MAINSP ), +#endif +#if QSV_VERSION_ATLEAST(1, 16) + MAP(HEVC, HEVC_REXT, HEVC_REXT ), +#endif + + MAP(VC1, VC1_SIMPLE, VC1_SIMPLE ), + MAP(VC1, VC1_MAIN, VC1_MAIN ), + MAP(VC1, VC1_COMPLEX, VC1_ADVANCED ), + MAP(VC1, VC1_ADVANCED, VC1_ADVANCED ), +#undef MAP +}; + int ff_qsv_profile_to_mfx(enum AVCodecID codec_id, int profile) { + int i; if (profile == FF_PROFILE_UNKNOWN) return MFX_PROFILE_UNKNOWN; - switch (codec_id) { - case AV_CODEC_ID_H264: - case AV_CODEC_ID_HEVC: - return profile; - case AV_CODEC_ID_VC1: - return 4 * profile + 1; - case AV_CODEC_ID_MPEG2VIDEO: - return 0x10 * profile; + + for (i = 0; i < FF_ARRAY_ELEMS(qsv_profile_map); i++) { + if (qsv_profile_map[i].codec_id != codec_id) + continue; + if (qsv_profile_map[i].codec_profile == profile) + return qsv_profile_map[i].mfx_profile; } + return MFX_PROFILE_UNKNOWN; } +int ff_qsv_level_to_mfx(enum AVCodecID codec_id, int level) +{ + if (level == FF_LEVEL_UNKNOWN) + return MFX_LEVEL_UNKNOWN; + + switch (codec_id) { + case AV_CODEC_ID_HEVC: + return level / 3; + default: + return level; + } +} + static const struct { mfxStatus mfxerr; int averr; @@ -214,6 +264,11 @@ enum AVPictureType ff_qsv_map_pictype(int mfx_pic_type) else type = AV_PICTURE_TYPE_P; break; + case MFX_FRAMETYPE_UNKNOWN: + type = AV_PICTURE_TYPE_NONE; + break; + default: + av_assert0(0); } return type; diff --git a/libavcodec/qsv_internal.h b/libavcodec/qsv_internal.h index 394c55888..b63a7d6a3 100644 --- a/libavcodec/qsv_internal.h +++ b/libavcodec/qsv_internal.h @@ -39,8 +39,8 @@ MFX_VERSION_MAJOR == (MAJOR) && MFX_VERSION_MINOR >= (MINOR)) #define QSV_RUNTIME_VERSION_ATLEAST(MFX_VERSION, MAJOR, MINOR) \ - (MFX_VERSION.Major > (MAJOR)) || \ - (MFX_VERSION.Major == (MAJOR) && MFX_VERSION.Minor >= (MINOR)) + ((MFX_VERSION.Major > (MAJOR)) || \ + (MFX_VERSION.Major == (MAJOR) && MFX_VERSION.Minor >= (MINOR))) typedef struct QSVMid { AVBufferRef *hw_frames_ref; @@ -90,6 +90,7 @@ int ff_qsv_print_warning(void *log_ctx, mfxStatus err, int ff_qsv_codec_id_to_mfx(enum AVCodecID codec_id); int ff_qsv_profile_to_mfx(enum AVCodecID codec_id, int profile); +int ff_qsv_level_to_mfx(enum AVCodecID codec_id, int level); int ff_qsv_map_pixfmt(enum AVPixelFormat format, uint32_t *fourcc); enum AVPictureType ff_qsv_map_pictype(int mfx_pic_type); diff --git a/libavcodec/qsvdec.c b/libavcodec/qsvdec.c index 32f1fe79d..46aa2d681 100644 --- a/libavcodec/qsvdec.c +++ b/libavcodec/qsvdec.c @@ -110,6 +110,43 @@ static int qsv_init_session(AVCodecContext *avctx, QSVContext *q, mfxSession ses return 0; } +static inline unsigned int qsv_fifo_item_size(void) +{ + return sizeof(mfxSyncPoint*) + sizeof(QSVFrame*); +} + +static inline unsigned int qsv_fifo_size(const AVFifoBuffer* fifo) +{ + return av_fifo_size(fifo) / qsv_fifo_item_size(); +} + +static int check_dec_param(AVCodecContext *avctx, QSVContext *q, mfxVideoParam *param_in) +{ + mfxVideoParam param_out = { .mfx.CodecId = param_in->mfx.CodecId }; + mfxStatus ret; + +#define CHECK_MATCH(x) \ + do { \ + if (param_out.mfx.x != param_in->mfx.x) { \ + av_log(avctx, AV_LOG_WARNING, "Required "#x" %d is unsupported\n", \ + param_in->mfx.x); \ + } \ + } while (0) + + ret = MFXVideoDECODE_Query(q->session, param_in, ¶m_out); + + if (ret < 0) { + CHECK_MATCH(CodecId); + CHECK_MATCH(CodecProfile); + CHECK_MATCH(CodecLevel); + CHECK_MATCH(FrameInfo.Width); + CHECK_MATCH(FrameInfo.Height); +#undef CHECK_MATCH + return 0; + } + return 1; +} + static int qsv_decode_init(AVCodecContext *avctx, QSVContext *q) { const AVPixFmtDescriptor *desc; @@ -125,8 +162,7 @@ static int qsv_decode_init(AVCodecContext *avctx, QSVContext *q) return AVERROR_BUG; if (!q->async_fifo) { - q->async_fifo = av_fifo_alloc((1 + q->async_depth) * - (sizeof(mfxSyncPoint*) + sizeof(QSVFrame*))); + q->async_fifo = av_fifo_alloc(q->async_depth * qsv_fifo_item_size()); if (!q->async_fifo) return AVERROR(ENOMEM); } @@ -167,7 +203,7 @@ static int qsv_decode_init(AVCodecContext *avctx, QSVContext *q) param.mfx.CodecId = ret; param.mfx.CodecProfile = ff_qsv_profile_to_mfx(avctx->codec_id, avctx->profile); - param.mfx.CodecLevel = avctx->level == FF_LEVEL_UNKNOWN ? MFX_LEVEL_UNKNOWN : avctx->level; + param.mfx.CodecLevel = ff_qsv_level_to_mfx(avctx->codec_id, avctx->level); param.mfx.FrameInfo.BitDepthLuma = desc->comp[0].depth; param.mfx.FrameInfo.BitDepthChroma = desc->comp[0].depth; @@ -197,6 +233,12 @@ static int qsv_decode_init(AVCodecContext *avctx, QSVContext *q) param.ExtParam = q->ext_buffers; param.NumExtParam = q->nb_ext_buffers; + if (!check_dec_param(avctx, q, ¶m)) { + //Just give a warning instead of an error since it is still decodable possibly. + av_log(avctx, AV_LOG_WARNING, + "Current input bitstream is not supported by QSV decoder.\n"); + } + ret = MFXVideoDECODE_Init(q->session, ¶m); if (ret < 0) return ff_qsv_print_error(avctx, ret, @@ -363,6 +405,8 @@ static int qsv_decode(AVCodecContext *avctx, QSVContext *q, ++q->zero_consume_run; if (q->zero_consume_run > 1) ff_qsv_print_warning(avctx, ret, "A decode call did not consume any data"); + } else if (!*sync && bs.DataOffset) { + ++q->buffered_count; } else { q->zero_consume_run = 0; } @@ -384,7 +428,7 @@ static int qsv_decode(AVCodecContext *avctx, QSVContext *q, av_freep(&sync); } - if (!av_fifo_space(q->async_fifo) || + if ((qsv_fifo_size(q->async_fifo) >= q->async_depth) || (!avpkt->size && av_fifo_size(q->async_fifo))) { AVFrame *src_frame; @@ -490,6 +534,8 @@ int ff_qsv_process_data(AVCodecContext *avctx, QSVContext *q, if (!q->avctx_internal) return AVERROR(ENOMEM); + q->avctx_internal->codec_id = avctx->codec_id; + q->parser = av_parser_init(avctx->codec_id); if (!q->parser) return AVERROR(ENOMEM); @@ -517,6 +563,16 @@ int ff_qsv_process_data(AVCodecContext *avctx, QSVContext *q, AV_PIX_FMT_NONE, AV_PIX_FMT_NONE }; enum AVPixelFormat qsv_format; + AVPacket zero_pkt = {0}; + + if (q->buffered_count) { + q->reinit_flag = 1; + /* decode zero-size pkt to flush the buffered pkt before reinit */ + q->buffered_count--; + return qsv_decode(avctx, q, frame, got_frame, &zero_pkt); + } + + q->reinit_flag = 0; qsv_format = ff_qsv_map_pixfmt(q->parser->format, &q->fourcc); if (qsv_format < 0) { diff --git a/libavcodec/qsvdec.h b/libavcodec/qsvdec.h index 5b7b03a48..111536cab 100644 --- a/libavcodec/qsvdec.h +++ b/libavcodec/qsvdec.h @@ -53,6 +53,8 @@ typedef struct QSVContext { AVFifoBuffer *async_fifo; int zero_consume_run; + int buffered_count; + int reinit_flag; // the internal parser and codec context for parsing the data AVCodecParserContext *parser; diff --git a/libavcodec/qsvdec_h2645.c b/libavcodec/qsvdec_h2645.c index 831252f2d..9b49f5506 100644 --- a/libavcodec/qsvdec_h2645.c +++ b/libavcodec/qsvdec_h2645.c @@ -146,10 +146,11 @@ static int qsv_decode_frame(AVCodecContext *avctx, void *data, /* no more data */ if (av_fifo_size(s->packet_fifo) < sizeof(AVPacket)) return avpkt->size ? avpkt->size : ff_qsv_process_data(avctx, &s->qsv, frame, got_frame, avpkt); - - av_packet_unref(&s->buffer_pkt); - - av_fifo_generic_read(s->packet_fifo, &s->buffer_pkt, sizeof(s->buffer_pkt), NULL); + /* in progress of reinit, no read from fifo and keep the buffer_pkt */ + if (!s->qsv.reinit_flag) { + av_packet_unref(&s->buffer_pkt); + av_fifo_generic_read(s->packet_fifo, &s->buffer_pkt, sizeof(s->buffer_pkt), NULL); + } } ret = ff_qsv_process_data(avctx, &s->qsv, frame, got_frame, &s->buffer_pkt); @@ -159,6 +160,8 @@ static int qsv_decode_frame(AVCodecContext *avctx, void *data, av_packet_unref(&s->buffer_pkt); return ret; } + if (s->qsv.reinit_flag) + continue; s->buffer_pkt.size -= ret; s->buffer_pkt.data += ret; @@ -175,20 +178,14 @@ static void qsv_decode_flush(AVCodecContext *avctx) ff_qsv_decode_flush(avctx, &s->qsv); } -#if defined(_WIN32) -#define LOAD_PLUGIN_DEFAULT LOAD_PLUGIN_HEVC_SW -#else -#define LOAD_PLUGIN_DEFAULT LOAD_PLUGIN_HEVC_HW -#endif - #define OFFSET(x) offsetof(QSVH2645Context, x) #define VD AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_DECODING_PARAM #if CONFIG_HEVC_QSV_DECODER static const AVOption hevc_options[] = { - { "async_depth", "Internal parallelization depth, the higher the value the higher the latency.", OFFSET(qsv.async_depth), AV_OPT_TYPE_INT, { .i64 = ASYNC_DEPTH_DEFAULT }, 0, INT_MAX, VD }, + { "async_depth", "Internal parallelization depth, the higher the value the higher the latency.", OFFSET(qsv.async_depth), AV_OPT_TYPE_INT, { .i64 = ASYNC_DEPTH_DEFAULT }, 1, INT_MAX, VD }, - { "load_plugin", "A user plugin to load in an internal session", OFFSET(load_plugin), AV_OPT_TYPE_INT, { .i64 = LOAD_PLUGIN_DEFAULT }, LOAD_PLUGIN_NONE, LOAD_PLUGIN_HEVC_HW, VD, "load_plugin" }, + { "load_plugin", "A user plugin to load in an internal session", OFFSET(load_plugin), AV_OPT_TYPE_INT, { .i64 = LOAD_PLUGIN_HEVC_HW }, LOAD_PLUGIN_NONE, LOAD_PLUGIN_HEVC_HW, VD, "load_plugin" }, { "none", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = LOAD_PLUGIN_NONE }, 0, 0, VD, "load_plugin" }, { "hevc_sw", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = LOAD_PLUGIN_HEVC_SW }, 0, 0, VD, "load_plugin" }, { "hevc_hw", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = LOAD_PLUGIN_HEVC_HW }, 0, 0, VD, "load_plugin" }, @@ -229,7 +226,7 @@ AVCodec ff_hevc_qsv_decoder = { #if CONFIG_H264_QSV_DECODER static const AVOption options[] = { - { "async_depth", "Internal parallelization depth, the higher the value the higher the latency.", OFFSET(qsv.async_depth), AV_OPT_TYPE_INT, { .i64 = ASYNC_DEPTH_DEFAULT }, 0, INT_MAX, VD }, + { "async_depth", "Internal parallelization depth, the higher the value the higher the latency.", OFFSET(qsv.async_depth), AV_OPT_TYPE_INT, { .i64 = ASYNC_DEPTH_DEFAULT }, 1, INT_MAX, VD }, { NULL }, }; diff --git a/libavcodec/qsvdec_other.c b/libavcodec/qsvdec_other.c index 3c872dcfc..03251d2c8 100644 --- a/libavcodec/qsvdec_other.c +++ b/libavcodec/qsvdec_other.c @@ -132,14 +132,23 @@ static int qsv_decode_frame(AVCodecContext *avctx, void *data, /* no more data */ if (av_fifo_size(s->packet_fifo) < sizeof(AVPacket)) return avpkt->size ? avpkt->size : ff_qsv_process_data(avctx, &s->qsv, frame, got_frame, avpkt); - - av_packet_unref(&s->input_ref); - av_fifo_generic_read(s->packet_fifo, &s->input_ref, sizeof(s->input_ref), NULL); + /* in progress of reinit, no read from fifo and keep the buffer_pkt */ + if (!s->qsv.reinit_flag) { + av_packet_unref(&s->input_ref); + av_fifo_generic_read(s->packet_fifo, &s->input_ref, sizeof(s->input_ref), NULL); + } } ret = ff_qsv_process_data(avctx, &s->qsv, frame, got_frame, &s->input_ref); - if (ret < 0) + if (ret < 0) { + /* Drop input packet when failed to decode the packet. Otherwise, + the decoder will keep decoding the failure packet. */ + av_packet_unref(&s->input_ref); + return ret; + } + if (s->qsv.reinit_flag) + continue; s->input_ref.size -= ret; s->input_ref.data += ret; @@ -159,7 +168,7 @@ static void qsv_decode_flush(AVCodecContext *avctx) #define OFFSET(x) offsetof(QSVOtherContext, x) #define VD AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_DECODING_PARAM static const AVOption options[] = { - { "async_depth", "Internal parallelization depth, the higher the value the higher the latency.", OFFSET(qsv.async_depth), AV_OPT_TYPE_INT, { .i64 = ASYNC_DEPTH_DEFAULT }, 0, INT_MAX, VD }, + { "async_depth", "Internal parallelization depth, the higher the value the higher the latency.", OFFSET(qsv.async_depth), AV_OPT_TYPE_INT, { .i64 = ASYNC_DEPTH_DEFAULT }, 1, INT_MAX, VD }, { NULL }, }; diff --git a/libavcodec/qsvenc.c b/libavcodec/qsvenc.c index 3ce5ffecd..9bf8574e3 100644 --- a/libavcodec/qsvenc.c +++ b/libavcodec/qsvenc.c @@ -136,6 +136,9 @@ static void dump_video_param(AVCodecContext *avctx, QSVEncContext *q, #if QSV_HAVE_CO2 mfxExtCodingOption2 *co2 = (mfxExtCodingOption2*)coding_opts[1]; #endif +#if QSV_HAVE_CO3 + mfxExtCodingOption3 *co3 = (mfxExtCodingOption3*)coding_opts[2]; +#endif av_log(avctx, AV_LOG_VERBOSE, "profile: %s; level: %"PRIu16"\n", print_profile(info->CodecProfile), info->CodecLevel); @@ -158,8 +161,8 @@ static void dump_video_param(AVCodecContext *avctx, QSVEncContext *q, #endif ) { av_log(avctx, AV_LOG_VERBOSE, - "InitialDelayInKB: %"PRIu16"; TargetKbps: %"PRIu16"; MaxKbps: %"PRIu16"\n", - info->InitialDelayInKB, info->TargetKbps, info->MaxKbps); + "BufferSizeInKB: %"PRIu16"; InitialDelayInKB: %"PRIu16"; TargetKbps: %"PRIu16"; MaxKbps: %"PRIu16"; BRCParamMultiplier: %"PRIu16"\n", + info->BufferSizeInKB, info->InitialDelayInKB, info->TargetKbps, info->MaxKbps, info->BRCParamMultiplier); } else if (info->RateControlMethod == MFX_RATECONTROL_CQP) { av_log(avctx, AV_LOG_VERBOSE, "QPI: %"PRIu16"; QPP: %"PRIu16"; QPB: %"PRIu16"\n", info->QPI, info->QPP, info->QPB); @@ -167,8 +170,8 @@ static void dump_video_param(AVCodecContext *avctx, QSVEncContext *q, #if QSV_HAVE_AVBR else if (info->RateControlMethod == MFX_RATECONTROL_AVBR) { av_log(avctx, AV_LOG_VERBOSE, - "TargetKbps: %"PRIu16"; Accuracy: %"PRIu16"; Convergence: %"PRIu16"\n", - info->TargetKbps, info->Accuracy, info->Convergence); + "TargetKbps: %"PRIu16"; Accuracy: %"PRIu16"; Convergence: %"PRIu16"; BRCParamMultiplier: %"PRIu16"\n", + info->TargetKbps, info->Accuracy, info->Convergence, info->BRCParamMultiplier); } #endif #if QSV_HAVE_LA @@ -178,8 +181,8 @@ static void dump_video_param(AVCodecContext *avctx, QSVEncContext *q, #endif ) { av_log(avctx, AV_LOG_VERBOSE, - "TargetKbps: %"PRIu16"; LookAheadDepth: %"PRIu16"\n", - info->TargetKbps, co2->LookAheadDepth); + "TargetKbps: %"PRIu16"; LookAheadDepth: %"PRIu16"; BRCParamMultiplier: %"PRIu16"\n", + info->TargetKbps, co2->LookAheadDepth, info->BRCParamMultiplier); } #endif #if QSV_HAVE_ICQ @@ -190,7 +193,12 @@ static void dump_video_param(AVCodecContext *avctx, QSVEncContext *q, info->ICQQuality, co2->LookAheadDepth); } #endif - +#if QSV_HAVE_QVBR + else if (info->RateControlMethod == MFX_RATECONTROL_QVBR) { + av_log(avctx, AV_LOG_VERBOSE, "QVBRQuality: %"PRIu16"\n", + co3->QVBRQuality); + } +#endif av_log(avctx, AV_LOG_VERBOSE, "NumSlice: %"PRIu16"; NumRefFrame: %"PRIu16"\n", info->NumSlice, info->NumRefFrame); av_log(avctx, AV_LOG_VERBOSE, "RateDistortionOpt: %s\n", @@ -226,6 +234,10 @@ static void dump_video_param(AVCodecContext *avctx, QSVEncContext *q, av_log(avctx, AV_LOG_VERBOSE, "\n"); #endif +#if QSV_HAVE_VDENC + av_log(avctx, AV_LOG_VERBOSE, "VDENC: %s\n", print_threestate(info->LowPower)); +#endif + #if QSV_VERSION_ATLEAST(1, 8) av_log(avctx, AV_LOG_VERBOSE, "RepeatPPS: %s; NumMbPerSlice: %"PRIu16"; LookAheadDS: ", @@ -255,6 +267,11 @@ static void dump_video_param(AVCodecContext *avctx, QSVEncContext *q, #endif #endif +#if QSV_HAVE_GPB + if (avctx->codec_id == AV_CODEC_ID_HEVC) + av_log(avctx, AV_LOG_VERBOSE,"GPB: %s\n", print_threestate(co3->GPB)); +#endif + if (avctx->codec_id == AV_CODEC_ID_H264) { av_log(avctx, AV_LOG_VERBOSE, "Entropy coding: %s; MaxDecFrameBuffering: %"PRIu16"\n", co->CAVLC == MFX_CODINGOPTION_ON ? "CAVLC" : "CABAC", co->MaxDecFrameBuffering); @@ -263,6 +280,10 @@ static void dump_video_param(AVCodecContext *avctx, QSVEncContext *q, print_threestate(co->NalHrdConformance), print_threestate(co->SingleSeiNalUnit), print_threestate(co->VuiVclHrdParameters), print_threestate(co->VuiNalHrdParameters)); } + + av_log(avctx, AV_LOG_VERBOSE, "FrameRateExtD: %"PRIu32"; FrameRateExtN: %"PRIu32" \n", + info->FrameInfo.FrameRateExtD, info->FrameInfo.FrameRateExtN); + } static int select_rc_mode(AVCodecContext *avctx, QSVEncContext *q) @@ -322,7 +343,7 @@ static int select_rc_mode(AVCodecContext *avctx, QSVEncContext *q) } #endif #if QSV_HAVE_ICQ - else if (avctx->global_quality > 0) { + else if (avctx->global_quality > 0 && !avctx->rc_max_rate) { rc_mode = MFX_RATECONTROL_ICQ; rc_desc = "intelligent constant quality (ICQ)"; } @@ -336,6 +357,12 @@ static int select_rc_mode(AVCodecContext *avctx, QSVEncContext *q) rc_mode = MFX_RATECONTROL_AVBR; rc_desc = "average variable bitrate (AVBR)"; } +#endif +#if QSV_HAVE_QVBR + else if (avctx->global_quality > 0) { + rc_mode = MFX_RATECONTROL_QVBR; + rc_desc = "constant quality with VBR algorithm (QVBR)"; + } #endif else { rc_mode = MFX_RATECONTROL_VBR; @@ -443,6 +470,8 @@ static int init_video_param(AVCodecContext *avctx, QSVEncContext *q) avctx->sw_pix_fmt : avctx->pix_fmt; const AVPixFmtDescriptor *desc; float quant; + int target_bitrate_kbps, max_bitrate_kbps, brc_param_multiplier; + int buffer_size_in_kilobytes, initial_delay_in_kilobytes; int ret; ret = ff_qsv_codec_id_to_mfx(avctx->codec_id); @@ -453,8 +482,31 @@ static int init_video_param(AVCodecContext *avctx, QSVEncContext *q) if (avctx->level > 0) q->param.mfx.CodecLevel = avctx->level; + if (avctx->compression_level == FF_COMPRESSION_DEFAULT) { + avctx->compression_level = q->preset; + } else if (avctx->compression_level >= 0) { + if (avctx->compression_level > MFX_TARGETUSAGE_BEST_SPEED) { + av_log(avctx, AV_LOG_WARNING, "Invalid compression level: " + "valid range is 0-%d, using %d instead\n", + MFX_TARGETUSAGE_BEST_SPEED, MFX_TARGETUSAGE_BEST_SPEED); + avctx->compression_level = MFX_TARGETUSAGE_BEST_SPEED; + } + } + + if (q->low_power) { +#if QSV_HAVE_VDENC + q->param.mfx.LowPower = MFX_CODINGOPTION_ON; +#else + av_log(avctx, AV_LOG_WARNING, "The low_power option is " + "not supported with this MSDK version.\n"); + q->low_power = 0; + q->param.mfx.LowPower = MFX_CODINGOPTION_OFF; +#endif + } else + q->param.mfx.LowPower = MFX_CODINGOPTION_OFF; + q->param.mfx.CodecProfile = q->profile; - q->param.mfx.TargetUsage = q->preset; + q->param.mfx.TargetUsage = avctx->compression_level; q->param.mfx.GopPicSize = FFMAX(0, avctx->gop_size); q->param.mfx.GopRefDist = FFMAX(-1, avctx->max_b_frames) + 1; q->param.mfx.GopOptFlag = avctx->flags & AV_CODEC_FLAG_CLOSED_GOP ? @@ -482,10 +534,10 @@ static int init_video_param(AVCodecContext *avctx, QSVEncContext *q) q->param.mfx.FrameInfo.BitDepthChroma = desc->comp[0].depth; q->param.mfx.FrameInfo.Shift = desc->comp[0].depth > 8; - // TODO: detect version of MFX--if the minor version is greater than - // or equal to 19, then can use the same alignment settings as H.264 - // for HEVC - q->width_align = avctx->codec_id == AV_CODEC_ID_HEVC ? 32 : 16; + // If the minor version is greater than or equal to 19, + // then can use the same alignment settings as H.264 for HEVC + q->width_align = (avctx->codec_id != AV_CODEC_ID_HEVC || + QSV_RUNTIME_VERSION_ATLEAST(q->ver, 1, 19)) ? 16 : 32; q->param.mfx.FrameInfo.Width = FFALIGN(avctx->width, q->width_align); if (avctx->flags & AV_CODEC_FLAG_INTERLACED_DCT) { @@ -523,16 +575,32 @@ static int init_video_param(AVCodecContext *avctx, QSVEncContext *q) if (ret < 0) return ret; + //libmfx BRC parameters are 16 bits thus maybe overflow, then BRCParamMultiplier is needed + buffer_size_in_kilobytes = avctx->rc_buffer_size / 8000; + initial_delay_in_kilobytes = avctx->rc_initial_buffer_occupancy / 8000; + target_bitrate_kbps = avctx->bit_rate / 1000; + max_bitrate_kbps = avctx->rc_max_rate / 1000; + brc_param_multiplier = (FFMAX(FFMAX3(target_bitrate_kbps, max_bitrate_kbps, buffer_size_in_kilobytes), + initial_delay_in_kilobytes) + 0x10000) / 0x10000; + switch (q->param.mfx.RateControlMethod) { case MFX_RATECONTROL_CBR: case MFX_RATECONTROL_VBR: #if QSV_HAVE_VCM case MFX_RATECONTROL_VCM: #endif - q->param.mfx.BufferSizeInKB = avctx->rc_buffer_size / 8000; - q->param.mfx.InitialDelayInKB = avctx->rc_initial_buffer_occupancy / 1000; - q->param.mfx.TargetKbps = avctx->bit_rate / 1000; - q->param.mfx.MaxKbps = avctx->rc_max_rate / 1000; +#if QSV_HAVE_QVBR + case MFX_RATECONTROL_QVBR: +#endif + q->param.mfx.BufferSizeInKB = buffer_size_in_kilobytes / brc_param_multiplier; + q->param.mfx.InitialDelayInKB = initial_delay_in_kilobytes / brc_param_multiplier; + q->param.mfx.TargetKbps = target_bitrate_kbps / brc_param_multiplier; + q->param.mfx.MaxKbps = max_bitrate_kbps / brc_param_multiplier; + q->param.mfx.BRCParamMultiplier = brc_param_multiplier; +#if QSV_HAVE_QVBR + if (q->param.mfx.RateControlMethod == MFX_RATECONTROL_QVBR) + q->extco3.QVBRQuality = av_clip(avctx->global_quality, 0, 51); +#endif break; case MFX_RATECONTROL_CQP: quant = avctx->global_quality / FF_QP2LAMBDA; @@ -544,15 +612,17 @@ static int init_video_param(AVCodecContext *avctx, QSVEncContext *q) break; #if QSV_HAVE_AVBR case MFX_RATECONTROL_AVBR: - q->param.mfx.TargetKbps = avctx->bit_rate / 1000; + q->param.mfx.TargetKbps = target_bitrate_kbps / brc_param_multiplier; q->param.mfx.Convergence = q->avbr_convergence; q->param.mfx.Accuracy = q->avbr_accuracy; + q->param.mfx.BRCParamMultiplier = brc_param_multiplier; break; #endif #if QSV_HAVE_LA case MFX_RATECONTROL_LA: - q->param.mfx.TargetKbps = avctx->bit_rate / 1000; + q->param.mfx.TargetKbps = target_bitrate_kbps / brc_param_multiplier; q->extco2.LookAheadDepth = q->look_ahead_depth; + q->param.mfx.BRCParamMultiplier = brc_param_multiplier; break; #if QSV_HAVE_ICQ case MFX_RATECONTROL_LA_ICQ: @@ -564,9 +634,10 @@ static int init_video_param(AVCodecContext *avctx, QSVEncContext *q) #endif } - // the HEVC encoder plugin currently fails if coding options - // are provided - if (avctx->codec_id != AV_CODEC_ID_HEVC) { + // The HEVC encoder plugin currently fails with some old libmfx version if coding options + // are provided. Can't find the extract libmfx version which fixed it, just enable it from + // V1.28 in order to keep compatibility security. + if ((avctx->codec_id != AV_CODEC_ID_HEVC) || QSV_RUNTIME_VERSION_ATLEAST(q->ver, 1, 28)) { q->extco.Header.BufferId = MFX_EXTBUFF_CODING_OPTION; q->extco.Header.BufferSz = sizeof(q->extco); @@ -600,8 +671,8 @@ FF_ENABLE_DEPRECATION_WARNINGS q->extparam_internal[q->nb_extparam_internal++] = (mfxExtBuffer *)&q->extco; -#if QSV_HAVE_CO2 if (avctx->codec_id == AV_CODEC_ID_H264) { +#if QSV_HAVE_CO2 q->extco2.Header.BufferId = MFX_EXTBUFF_CODING_OPTION2; q->extco2.Header.BufferSz = sizeof(q->extco2); @@ -627,14 +698,16 @@ FF_ENABLE_DEPRECATION_WARNINGS #endif #if QSV_HAVE_TRELLIS - q->extco2.Trellis = q->trellis; + if (avctx->trellis >= 0) + q->extco2.Trellis = (avctx->trellis == 0) ? MFX_TRELLIS_OFF : (MFX_TRELLIS_I | MFX_TRELLIS_P | MFX_TRELLIS_B); + else + q->extco2.Trellis = MFX_TRELLIS_UNKNOWN; #endif -#if QSV_HAVE_LA_DS +#if QSV_VERSION_ATLEAST(1, 8) q->extco2.LookAheadDS = q->look_ahead_downsampling; -#endif + q->extco2.RepeatPPS = q->repeat_pps ? MFX_CODINGOPTION_ON : MFX_CODINGOPTION_OFF; -#if QSV_HAVE_BREF_TYPE #if FF_API_PRIVATE_OPT FF_DISABLE_DEPRECATION_WARNINGS if (avctx->b_frame_strategy >= 0) @@ -649,14 +722,25 @@ FF_ENABLE_DEPRECATION_WARNINGS q->extco2.AdaptiveB = q->adaptive_b ? MFX_CODINGOPTION_ON : MFX_CODINGOPTION_OFF; #endif - q->extparam_internal[q->nb_extparam_internal++] = (mfxExtBuffer *)&q->extco2; - } +#if QSV_VERSION_ATLEAST(1, 9) + if (avctx->qmin >= 0 && avctx->qmax >= 0 && avctx->qmin > avctx->qmax) { + av_log(avctx, AV_LOG_ERROR, "qmin and or qmax are set but invalid, please make sure min <= max\n"); + return AVERROR(EINVAL); + } + if (avctx->qmin >= 0) { + q->extco2.MinQPI = avctx->qmin > 51 ? 51 : avctx->qmin; + q->extco2.MinQPP = q->extco2.MinQPB = q->extco2.MinQPI; + } + if (avctx->qmax >= 0) { + q->extco2.MaxQPI = avctx->qmax > 51 ? 51 : avctx->qmax; + q->extco2.MaxQPP = q->extco2.MaxQPB = q->extco2.MaxQPI; + } #endif + q->extparam_internal[q->nb_extparam_internal++] = (mfxExtBuffer *)&q->extco2; +#endif + #if QSV_HAVE_MF - if (avctx->codec_id == AV_CODEC_ID_H264) { - mfxVersion ver; - ret = MFXQueryVersion(q->session,&ver); - if (ret >= MFX_ERR_NONE && QSV_RUNTIME_VERSION_ATLEAST(ver, 1, 25)) { + if (QSV_RUNTIME_VERSION_ATLEAST(q->ver, 1, 25)) { q->extmfp.Header.BufferId = MFX_EXTBUFF_MULTI_FRAME_PARAM; q->extmfp.Header.BufferSz = sizeof(q->extmfp); @@ -664,7 +748,16 @@ FF_ENABLE_DEPRECATION_WARNINGS av_log(avctx,AV_LOG_VERBOSE,"MFMode:%d\n", q->extmfp.MFMode); q->extparam_internal[q->nb_extparam_internal++] = (mfxExtBuffer *)&q->extmfp; } +#endif } +#if QSV_HAVE_CO3 + q->extco3.Header.BufferId = MFX_EXTBUFF_CODING_OPTION3; + q->extco3.Header.BufferSz = sizeof(q->extco3); +#if QSV_HAVE_GPB + if (avctx->codec_id == AV_CODEC_ID_HEVC) + q->extco3.GPB = q->gpb ? MFX_CODINGOPTION_ON : MFX_CODINGOPTION_OFF; +#endif + q->extparam_internal[q->nb_extparam_internal++] = (mfxExtBuffer *)&q->extco3; #endif } @@ -687,7 +780,7 @@ static int qsv_retrieve_enc_jpeg_params(AVCodecContext *avctx, QSVEncContext *q) return ff_qsv_print_error(avctx, ret, "Error calling GetVideoParam"); - q->packet_size = q->param.mfx.BufferSizeInKB * 1000; + q->packet_size = q->param.mfx.BufferSizeInKB * q->param.mfx.BRCParamMultiplier * 1000; // for qsv mjpeg the return value maybe 0 so alloc the buffer if (q->packet_size == 0) @@ -720,42 +813,83 @@ static int qsv_retrieve_enc_params(AVCodecContext *avctx, QSVEncContext *q) .Header.BufferSz = sizeof(co2), }; #endif - - mfxExtBuffer *ext_buffers[] = { - (mfxExtBuffer*)&extradata, - (mfxExtBuffer*)&co, -#if QSV_HAVE_CO2 - (mfxExtBuffer*)&co2, -#endif +#if QSV_HAVE_CO3 + mfxExtCodingOption3 co3 = { + .Header.BufferId = MFX_EXTBUFF_CODING_OPTION3, + .Header.BufferSz = sizeof(co3), }; +#endif + +#if QSV_HAVE_CO_VPS + uint8_t vps_buf[128]; + mfxExtCodingOptionVPS extradata_vps = { + .Header.BufferId = MFX_EXTBUFF_CODING_OPTION_VPS, + .Header.BufferSz = sizeof(extradata_vps), + .VPSBuffer = vps_buf, + .VPSBufSize = sizeof(vps_buf), + }; +#endif + + mfxExtBuffer *ext_buffers[2 + QSV_HAVE_CO2 + QSV_HAVE_CO3 + QSV_HAVE_CO_VPS]; int need_pps = avctx->codec_id != AV_CODEC_ID_MPEG2VIDEO; - int ret; + int ret, ext_buf_num = 0, extradata_offset = 0; + + ext_buffers[ext_buf_num++] = (mfxExtBuffer*)&extradata; + ext_buffers[ext_buf_num++] = (mfxExtBuffer*)&co; +#if QSV_HAVE_CO2 + ext_buffers[ext_buf_num++] = (mfxExtBuffer*)&co2; +#endif +#if QSV_HAVE_CO3 + ext_buffers[ext_buf_num++] = (mfxExtBuffer*)&co3; +#endif +#if QSV_HAVE_CO_VPS + q->hevc_vps = ((avctx->codec_id == AV_CODEC_ID_HEVC) && QSV_RUNTIME_VERSION_ATLEAST(q->ver, 1, 17)); + if (q->hevc_vps) + ext_buffers[ext_buf_num++] = (mfxExtBuffer*)&extradata_vps; +#endif q->param.ExtParam = ext_buffers; - q->param.NumExtParam = FF_ARRAY_ELEMS(ext_buffers); + q->param.NumExtParam = ext_buf_num; ret = MFXVideoENCODE_GetVideoParam(q->session, &q->param); if (ret < 0) return ff_qsv_print_error(avctx, ret, "Error calling GetVideoParam"); - q->packet_size = q->param.mfx.BufferSizeInKB * 1000; + q->packet_size = q->param.mfx.BufferSizeInKB * q->param.mfx.BRCParamMultiplier * 1000; - if (!extradata.SPSBufSize || (need_pps && !extradata.PPSBufSize)) { + if (!extradata.SPSBufSize || (need_pps && !extradata.PPSBufSize) +#if QSV_HAVE_CO_VPS + || (q->hevc_vps && !extradata_vps.VPSBufSize) +#endif + ) { av_log(avctx, AV_LOG_ERROR, "No extradata returned from libmfx.\n"); return AVERROR_UNKNOWN; } - avctx->extradata = av_malloc(extradata.SPSBufSize + need_pps * extradata.PPSBufSize + - AV_INPUT_BUFFER_PADDING_SIZE); + avctx->extradata_size = extradata.SPSBufSize + need_pps * extradata.PPSBufSize; +#if QSV_HAVE_CO_VPS + avctx->extradata_size += q->hevc_vps * extradata_vps.VPSBufSize; +#endif + + avctx->extradata = av_malloc(avctx->extradata_size + AV_INPUT_BUFFER_PADDING_SIZE); if (!avctx->extradata) return AVERROR(ENOMEM); - memcpy(avctx->extradata, sps_buf, extradata.SPSBufSize); - if (need_pps) - memcpy(avctx->extradata + extradata.SPSBufSize, pps_buf, extradata.PPSBufSize); - avctx->extradata_size = extradata.SPSBufSize + need_pps * extradata.PPSBufSize; +#if QSV_HAVE_CO_VPS + if (q->hevc_vps) { + memcpy(avctx->extradata, vps_buf, extradata_vps.VPSBufSize); + extradata_offset += extradata_vps.VPSBufSize; + } +#endif + + memcpy(avctx->extradata + extradata_offset, sps_buf, extradata.SPSBufSize); + extradata_offset += extradata.SPSBufSize; + if (need_pps) { + memcpy(avctx->extradata + extradata_offset, pps_buf, extradata.PPSBufSize); + extradata_offset += extradata.PPSBufSize; + } memset(avctx->extradata + avctx->extradata_size, 0, AV_INPUT_BUFFER_PADDING_SIZE); cpb_props = ff_add_cpb_side_data(avctx); @@ -777,7 +911,7 @@ static int qsv_init_opaque_alloc(AVCodecContext *avctx, QSVEncContext *q) mfxFrameSurface1 *surfaces; int nb_surfaces, i; - nb_surfaces = qsv->nb_opaque_surfaces + q->req.NumFrameSuggested + q->async_depth; + nb_surfaces = qsv->nb_opaque_surfaces + q->req.NumFrameSuggested; q->opaque_alloc_buf = av_buffer_allocz(sizeof(*surfaces) * nb_surfaces); if (!q->opaque_alloc_buf) @@ -848,6 +982,16 @@ static int qsvenc_init_session(AVCodecContext *avctx, QSVEncContext *q) return 0; } +static inline unsigned int qsv_fifo_item_size(void) +{ + return sizeof(AVPacket) + sizeof(mfxSyncPoint*) + sizeof(mfxBitstream*); +} + +static inline unsigned int qsv_fifo_size(const AVFifoBuffer* fifo) +{ + return av_fifo_size(fifo)/qsv_fifo_item_size(); +} + int ff_qsv_enc_init(AVCodecContext *avctx, QSVEncContext *q) { int iopattern = 0; @@ -856,8 +1000,7 @@ int ff_qsv_enc_init(AVCodecContext *avctx, QSVEncContext *q) q->param.AsyncDepth = q->async_depth; - q->async_fifo = av_fifo_alloc((1 + q->async_depth) * - (sizeof(AVPacket) + sizeof(mfxSyncPoint*) + sizeof(mfxBitstream*))); + q->async_fifo = av_fifo_alloc(q->async_depth * qsv_fifo_item_size()); if (!q->async_fifo) return AVERROR(ENOMEM); @@ -889,6 +1032,12 @@ int ff_qsv_enc_init(AVCodecContext *avctx, QSVEncContext *q) if (ret < 0) return ret; + ret = MFXQueryVersion(q->session,&q->ver); + if (ret < 0) { + return ff_qsv_print_error(avctx, ret, + "Error querying mfx version"); + } + // in the mfxInfoMFX struct, JPEG is different from other codecs switch (avctx->codec_id) { case AV_CODEC_ID_MJPEG: @@ -992,7 +1141,9 @@ static void clear_unused_frames(QSVEncContext *q) while (cur) { if (cur->used && !cur->surface.Data.Locked) { free_encoder_ctrl_payloads(&cur->enc_ctrl); - av_frame_unref(cur->frame); + if (cur->frame->format == AV_PIX_FMT_QSV) { + av_frame_unref(cur->frame); + } cur->used = 0; } cur = cur->next; @@ -1065,16 +1216,23 @@ static int submit_frame(QSVEncContext *q, const AVFrame *frame, } } else { /* make a copy if the input is not padded as libmfx requires */ - if (frame->height & 31 || frame->linesize[0] & (q->width_align - 1)) { + /* and to make allocation continious for data[0]/data[1] */ + if ((frame->height & 31 || frame->linesize[0] & (q->width_align - 1)) || + (frame->data[1] - frame->data[0] != frame->linesize[0] * FFALIGN(qf->frame->height, q->height_align))) { qf->frame->height = FFALIGN(frame->height, q->height_align); qf->frame->width = FFALIGN(frame->width, q->width_align); - ret = ff_get_buffer(q->avctx, qf->frame, AV_GET_BUFFER_FLAG_REF); - if (ret < 0) - return ret; + qf->frame->format = frame->format; + + if (!qf->frame->data[0]) { + ret = av_frame_get_buffer(qf->frame, q->width_align); + if (ret < 0) + return ret; + } qf->frame->height = frame->height; qf->frame->width = frame->width; + ret = av_frame_copy(qf->frame, frame); if (ret < 0) { av_frame_unref(qf->frame); @@ -1119,7 +1277,7 @@ static void print_interlace_msg(AVCodecContext *avctx, QSVEncContext *q) q->param.mfx.CodecLevel > MFX_LEVEL_AVC_41) av_log(avctx, AV_LOG_WARNING, "Interlaced coding is supported" - " at Main/High Profile Level 2.1-4.1\n"); + " at Main/High Profile Level 2.2-4.0\n"); } } @@ -1128,6 +1286,10 @@ static int encode_frame(AVCodecContext *avctx, QSVEncContext *q, { AVPacket new_pkt = { 0 }; mfxBitstream *bs; +#if QSV_VERSION_ATLEAST(1, 26) + mfxExtAVCEncodedFrameInfo *enc_info; + mfxExtBuffer **enc_buf; +#endif mfxFrameSurface1 *surf = NULL; mfxSyncPoint *sync = NULL; @@ -1145,6 +1307,12 @@ static int encode_frame(AVCodecContext *avctx, QSVEncContext *q, if (qsv_frame) { surf = &qsv_frame->surface; enc_ctrl = &qsv_frame->enc_ctrl; + + if (frame->pict_type == AV_PICTURE_TYPE_I) { + enc_ctrl->FrameType = MFX_FRAMETYPE_I | MFX_FRAMETYPE_REF; + if (q->forced_idr) + enc_ctrl->FrameType |= MFX_FRAMETYPE_IDR; + } } ret = av_new_packet(&new_pkt, q->packet_size); @@ -1161,6 +1329,24 @@ static int encode_frame(AVCodecContext *avctx, QSVEncContext *q, bs->Data = new_pkt.data; bs->MaxLength = new_pkt.size; +#if QSV_VERSION_ATLEAST(1, 26) + if (avctx->codec_id == AV_CODEC_ID_H264) { + enc_info = av_mallocz(sizeof(*enc_info)); + if (!enc_info) + return AVERROR(ENOMEM); + + enc_info->Header.BufferId = MFX_EXTBUFF_ENCODED_FRAME_INFO; + enc_info->Header.BufferSz = sizeof (*enc_info); + bs->NumExtParam = 1; + enc_buf = av_mallocz(sizeof(mfxExtBuffer *)); + if (!enc_buf) + return AVERROR(ENOMEM); + enc_buf[0] = (mfxExtBuffer *)enc_info; + + bs->ExtParam = enc_buf; + } +#endif + if (q->set_encode_ctrl_cb) { q->set_encode_ctrl_cb(avctx, frame, &qsv_frame->enc_ctrl); } @@ -1168,6 +1354,12 @@ static int encode_frame(AVCodecContext *avctx, QSVEncContext *q, sync = av_mallocz(sizeof(*sync)); if (!sync) { av_freep(&bs); + #if QSV_VERSION_ATLEAST(1, 26) + if (avctx->codec_id == AV_CODEC_ID_H264) { + av_freep(&enc_info); + av_freep(&enc_buf); + } + #endif av_packet_unref(&new_pkt); return AVERROR(ENOMEM); } @@ -1184,6 +1376,12 @@ static int encode_frame(AVCodecContext *avctx, QSVEncContext *q, if (ret < 0) { av_packet_unref(&new_pkt); av_freep(&bs); +#if QSV_VERSION_ATLEAST(1, 26) + if (avctx->codec_id == AV_CODEC_ID_H264) { + av_freep(&enc_info); + av_freep(&enc_buf); + } +#endif av_freep(&sync); return (ret == MFX_ERR_MORE_DATA) ? 0 : ff_qsv_print_error(avctx, ret, "Error during encoding"); @@ -1200,6 +1398,12 @@ static int encode_frame(AVCodecContext *avctx, QSVEncContext *q, av_freep(&sync); av_packet_unref(&new_pkt); av_freep(&bs); +#if QSV_VERSION_ATLEAST(1, 26) + if (avctx->codec_id == AV_CODEC_ID_H264) { + av_freep(&enc_info); + av_freep(&enc_buf); + } +#endif } return 0; @@ -1214,11 +1418,16 @@ int ff_qsv_encode(AVCodecContext *avctx, QSVEncContext *q, if (ret < 0) return ret; - if (!av_fifo_space(q->async_fifo) || + if ((qsv_fifo_size(q->async_fifo) >= q->async_depth) || (!frame && av_fifo_size(q->async_fifo))) { AVPacket new_pkt; mfxBitstream *bs; mfxSyncPoint *sync; +#if QSV_VERSION_ATLEAST(1, 26) + mfxExtAVCEncodedFrameInfo *enc_info; + mfxExtBuffer **enc_buf; +#endif + enum AVPictureType pict_type; av_fifo_generic_read(q->async_fifo, &new_pkt, sizeof(new_pkt), NULL); av_fifo_generic_read(q->async_fifo, &sync, sizeof(sync), NULL); @@ -1232,21 +1441,39 @@ int ff_qsv_encode(AVCodecContext *avctx, QSVEncContext *q, new_pkt.pts = av_rescale_q(bs->TimeStamp, (AVRational){1, 90000}, avctx->time_base); new_pkt.size = bs->DataLength; - if (bs->FrameType & MFX_FRAMETYPE_IDR || - bs->FrameType & MFX_FRAMETYPE_xIDR) + if (bs->FrameType & MFX_FRAMETYPE_IDR || bs->FrameType & MFX_FRAMETYPE_xIDR) { new_pkt.flags |= AV_PKT_FLAG_KEY; + pict_type = AV_PICTURE_TYPE_I; + } else if (bs->FrameType & MFX_FRAMETYPE_I || bs->FrameType & MFX_FRAMETYPE_xI) + pict_type = AV_PICTURE_TYPE_I; + else if (bs->FrameType & MFX_FRAMETYPE_P || bs->FrameType & MFX_FRAMETYPE_xP) + pict_type = AV_PICTURE_TYPE_P; + else if (bs->FrameType & MFX_FRAMETYPE_B || bs->FrameType & MFX_FRAMETYPE_xB) + pict_type = AV_PICTURE_TYPE_B; + else if (bs->FrameType == MFX_FRAMETYPE_UNKNOWN) { + pict_type = AV_PICTURE_TYPE_NONE; + av_log(avctx, AV_LOG_WARNING, "Unknown FrameType, set pict_type to AV_PICTURE_TYPE_NONE.\n"); + } else { + av_log(avctx, AV_LOG_ERROR, "Invalid FrameType:%d.\n", bs->FrameType); + return AVERROR_INVALIDDATA; + } #if FF_API_CODED_FRAME FF_DISABLE_DEPRECATION_WARNINGS - if (bs->FrameType & MFX_FRAMETYPE_I || bs->FrameType & MFX_FRAMETYPE_xI) - avctx->coded_frame->pict_type = AV_PICTURE_TYPE_I; - else if (bs->FrameType & MFX_FRAMETYPE_P || bs->FrameType & MFX_FRAMETYPE_xP) - avctx->coded_frame->pict_type = AV_PICTURE_TYPE_P; - else if (bs->FrameType & MFX_FRAMETYPE_B || bs->FrameType & MFX_FRAMETYPE_xB) - avctx->coded_frame->pict_type = AV_PICTURE_TYPE_B; + avctx->coded_frame->pict_type = pict_type; FF_ENABLE_DEPRECATION_WARNINGS #endif +#if QSV_VERSION_ATLEAST(1, 26) + if (avctx->codec_id == AV_CODEC_ID_H264) { + enc_buf = bs->ExtParam; + enc_info = (mfxExtAVCEncodedFrameInfo *)(*bs->ExtParam); + ff_side_data_set_encoder_stats(&new_pkt, + enc_info->QP * FF_QP2LAMBDA, NULL, 0, pict_type); + av_freep(&enc_info); + av_freep(&enc_buf); + } +#endif av_freep(&bs); av_freep(&sync); diff --git a/libavcodec/qsvenc.h b/libavcodec/qsvenc.h index d48272224..f2f4d3850 100644 --- a/libavcodec/qsvenc.h +++ b/libavcodec/qsvenc.h @@ -36,6 +36,7 @@ #define QSV_HAVE_CO2 QSV_VERSION_ATLEAST(1, 6) #define QSV_HAVE_CO3 QSV_VERSION_ATLEAST(1, 11) +#define QSV_HAVE_CO_VPS QSV_VERSION_ATLEAST(1, 17) #define QSV_HAVE_TRELLIS QSV_VERSION_ATLEAST(1, 8) #define QSV_HAVE_MAX_SLICE_SIZE QSV_VERSION_ATLEAST(1, 9) @@ -44,8 +45,11 @@ #define QSV_HAVE_LA QSV_VERSION_ATLEAST(1, 7) #define QSV_HAVE_LA_DS QSV_VERSION_ATLEAST(1, 8) #define QSV_HAVE_LA_HRD QSV_VERSION_ATLEAST(1, 11) +#define QSV_HAVE_VDENC QSV_VERSION_ATLEAST(1, 15) -#if defined(_WIN32) +#define QSV_HAVE_GPB QSV_VERSION_ATLEAST(1, 18) + +#if defined(_WIN32) || defined(__CYGWIN__) #define QSV_HAVE_AVBR QSV_VERSION_ATLEAST(1, 3) #define QSV_HAVE_ICQ QSV_VERSION_ATLEAST(1, 8) #define QSV_HAVE_VCM QSV_VERSION_ATLEAST(1, 8) @@ -53,9 +57,9 @@ #define QSV_HAVE_MF 0 #else #define QSV_HAVE_AVBR 0 -#define QSV_HAVE_ICQ 0 +#define QSV_HAVE_ICQ QSV_VERSION_ATLEAST(1, 28) #define QSV_HAVE_VCM 0 -#define QSV_HAVE_QVBR 0 +#define QSV_HAVE_QVBR QSV_VERSION_ATLEAST(1, 28) #define QSV_HAVE_MF QSV_VERSION_ATLEAST(1, 25) #endif @@ -67,7 +71,7 @@ #endif #define QSV_COMMON_OPTS \ -{ "async_depth", "Maximum processing parallelism", OFFSET(qsv.async_depth), AV_OPT_TYPE_INT, { .i64 = ASYNC_DEPTH_DEFAULT }, 0, INT_MAX, VE }, \ +{ "async_depth", "Maximum processing parallelism", OFFSET(qsv.async_depth), AV_OPT_TYPE_INT, { .i64 = ASYNC_DEPTH_DEFAULT }, 1, INT_MAX, VE }, \ { "avbr_accuracy", "Accuracy of the AVBR ratecontrol", OFFSET(qsv.avbr_accuracy), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, VE }, \ { "avbr_convergence", "Convergence of the AVBR ratecontrol", OFFSET(qsv.avbr_convergence), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, VE }, \ { "preset", NULL, OFFSET(qsv.preset), AV_OPT_TYPE_INT, { .i64 = MFX_TARGETUSAGE_BALANCED }, MFX_TARGETUSAGE_BEST_QUALITY, MFX_TARGETUSAGE_BEST_SPEED, VE, "preset" }, \ @@ -78,7 +82,6 @@ { "slow", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MFX_TARGETUSAGE_3 }, INT_MIN, INT_MAX, VE, "preset" }, \ { "slower", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MFX_TARGETUSAGE_2 }, INT_MIN, INT_MAX, VE, "preset" }, \ { "veryslow", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MFX_TARGETUSAGE_BEST_QUALITY }, INT_MIN, INT_MAX, VE, "preset" }, \ -{ "vcm", "Use the video conferencing mode ratecontrol", OFFSET(qsv.vcm), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, VE }, \ { "rdo", "Enable rate distortion optimization", OFFSET(qsv.rdo), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 1, VE }, \ { "max_frame_size", "Maximum encoded frame size in bytes", OFFSET(qsv.max_frame_size), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, UINT16_MAX, VE }, \ { "max_slice_size", "Maximum encoded slice size in bytes", OFFSET(qsv.max_slice_size), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, UINT16_MAX, VE }, \ @@ -88,6 +91,8 @@ { "adaptive_i", "Adaptive I-frame placement", OFFSET(qsv.adaptive_i), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 1, VE }, \ { "adaptive_b", "Adaptive B-frame placement", OFFSET(qsv.adaptive_b), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 1, VE }, \ { "b_strategy", "Strategy to choose between I/P/B-frames", OFFSET(qsv.b_strategy), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 1, VE }, \ +{ "forced_idr", "Forcing I frames as IDR frames", OFFSET(qsv.forced_idr), AV_OPT_TYPE_BOOL,{ .i64 = 0 }, 0, 1, VE }, \ +{ "low_power", "enable low power mode(experimental: many limitations by mfx version, BRC modes, etc.)", OFFSET(qsv.low_power), AV_OPT_TYPE_BOOL, { .i64 = 0}, 0, 1, VE},\ typedef int SetEncodeCtrlCB (AVCodecContext *avctx, const AVFrame *frame, mfxEncodeCtrl* enc_ctrl); @@ -110,6 +115,9 @@ typedef struct QSVEncContext { #if QSV_HAVE_CO2 mfxExtCodingOption2 extco2; #endif +#if QSV_HAVE_CO3 + mfxExtCodingOption3 extco3; +#endif #if QSV_HAVE_MF mfxExtMultiFrameParam extmfp; mfxExtMultiFrameControl extmfc; @@ -118,7 +126,7 @@ typedef struct QSVEncContext { mfxFrameSurface1 **opaque_surfaces; AVBufferRef *opaque_alloc_buf; - mfxExtBuffer *extparam_internal[2 + QSV_HAVE_CO2 + (QSV_HAVE_MF * 2)]; + mfxExtBuffer *extparam_internal[2 + QSV_HAVE_CO2 + QSV_HAVE_CO3 + (QSV_HAVE_MF * 2)]; int nb_extparam_internal; mfxExtBuffer **extparam; @@ -127,6 +135,10 @@ typedef struct QSVEncContext { QSVFramesContext frames_ctx; + mfxVersion ver; + + int hevc_vps; + // options set by the caller int async_depth; int idr_interval; @@ -147,7 +159,6 @@ typedef struct QSVEncContext { int single_sei_nal_unit; int max_dec_frame_buffering; - int trellis; int bitrate_limit; int mbbrc; @@ -162,6 +173,10 @@ typedef struct QSVEncContext { int int_ref_qp_delta; int recovery_point_sei; + int repeat_pps; + int low_power; + int gpb; + int a53_cc; #if QSV_HAVE_MF @@ -169,6 +184,7 @@ typedef struct QSVEncContext { #endif char *load_plugins; SetEncodeCtrlCB *set_encode_ctrl_cb; + int forced_idr; } QSVEncContext; int ff_qsv_enc_init(AVCodecContext *avctx, QSVEncContext *q); diff --git a/libavcodec/qsvenc_h264.c b/libavcodec/qsvenc_h264.c index 718bf9cb2..27f36b9f7 100644 --- a/libavcodec/qsvenc_h264.c +++ b/libavcodec/qsvenc_h264.c @@ -1,5 +1,5 @@ /* - * Intel MediaSDK QSV based H.264 enccoder + * Intel MediaSDK QSV based H.264 encoder * * copyright (c) 2013 Yukinori Yamazoe * @@ -103,6 +103,9 @@ static const AVOption options[] = { QSV_COMMON_OPTS { "cavlc", "Enable CAVLC", OFFSET(qsv.cavlc), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, VE }, +#if QSV_HAVE_VCM + { "vcm", "Use the video conferencing mode ratecontrol", OFFSET(qsv.vcm), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, VE }, +#endif { "idr_interval", "Distance (in I-frames) between IDR frames", OFFSET(qsv.idr_interval), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, VE }, { "pic_timing_sei", "Insert picture timing SEI with pic_struct_syntax element", OFFSET(qsv.pic_timing_sei), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, 1, VE }, { "single_sei_nal_unit", "Put all the SEI messages into one NALU", OFFSET(qsv.single_sei_nal_unit), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 1, VE }, @@ -114,7 +117,7 @@ static const AVOption options[] = { #endif #if QSV_HAVE_LA_DS { "look_ahead_downsampling", "Downscaling factor for the frames saved for the lookahead analysis", OFFSET(qsv.look_ahead_downsampling), - AV_OPT_TYPE_INT, { .i64 = MFX_LOOKAHEAD_DS_UNKNOWN }, MFX_LOOKAHEAD_DS_UNKNOWN, MFX_LOOKAHEAD_DS_2x, VE, "look_ahead_downsampling" }, + AV_OPT_TYPE_INT, { .i64 = MFX_LOOKAHEAD_DS_UNKNOWN }, MFX_LOOKAHEAD_DS_UNKNOWN, MFX_LOOKAHEAD_DS_4x, VE, "look_ahead_downsampling" }, { "unknown" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MFX_LOOKAHEAD_DS_UNKNOWN }, INT_MIN, INT_MAX, VE, "look_ahead_downsampling" }, { "auto" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MFX_LOOKAHEAD_DS_UNKNOWN }, INT_MIN, INT_MAX, VE, "look_ahead_downsampling" }, { "off" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MFX_LOOKAHEAD_DS_OFF }, INT_MIN, INT_MAX, VE, "look_ahead_downsampling" }, @@ -129,12 +132,6 @@ static const AVOption options[] = { { "int_ref_qp_delta", "QP difference for the refresh MBs", OFFSET(qsv.int_ref_qp_delta), AV_OPT_TYPE_INT, { .i64 = INT16_MIN }, INT16_MIN, INT16_MAX, VE }, { "recovery_point_sei", "Insert recovery point SEI messages", OFFSET(qsv.recovery_point_sei), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 1, VE }, - { "trellis", "Trellis quantization", OFFSET(qsv.trellis), AV_OPT_TYPE_FLAGS, { .i64 = 0 }, 0, UINT_MAX, VE, "trellis" }, - { "off", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MFX_TRELLIS_OFF }, .flags = VE, "trellis" }, - { "I", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MFX_TRELLIS_I }, .flags = VE, "trellis" }, - { "P", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MFX_TRELLIS_P }, .flags = VE, "trellis" }, - { "B", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MFX_TRELLIS_B }, .flags = VE, "trellis" }, - { "profile", NULL, OFFSET(qsv.profile), AV_OPT_TYPE_INT, { .i64 = MFX_PROFILE_UNKNOWN }, 0, INT_MAX, VE, "profile" }, { "unknown" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MFX_PROFILE_UNKNOWN }, INT_MIN, INT_MAX, VE, "profile" }, { "baseline", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MFX_PROFILE_AVC_BASELINE }, INT_MIN, INT_MAX, VE, "profile" }, @@ -146,9 +143,13 @@ static const AVOption options[] = { { "aud", "Insert the Access Unit Delimiter NAL", OFFSET(qsv.aud), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, VE}, #if QSV_HAVE_MF - { "mfmode", "Multi-Frame Mode", OFFSET(qsv.mfmode), AV_OPT_TYPE_INT, { .i64 = MFX_MF_AUTO }, 0, INT_MAX, VE }, + { "mfmode", "Multi-Frame Mode", OFFSET(qsv.mfmode), AV_OPT_TYPE_INT, { .i64 = MFX_MF_AUTO }, MFX_MF_DEFAULT, MFX_MF_AUTO, VE, "mfmode"}, + { "off" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MFX_MF_DISABLED }, INT_MIN, INT_MAX, VE, "mfmode" }, + { "auto" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MFX_MF_AUTO }, INT_MIN, INT_MAX, VE, "mfmode" }, #endif + { "repeat_pps", "repeat pps for every frame", OFFSET(qsv.repeat_pps), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, + { NULL }, }; @@ -165,10 +166,12 @@ static const AVCodecDefault qsv_enc_defaults[] = { // same as the x264 default { "g", "250" }, { "bf", "3" }, + { "qmin", "-1" }, + { "qmax", "-1" }, #if FF_API_CODER_TYPE { "coder", "-1" }, #endif - + { "trellis", "-1" }, { "flags", "+cgop" }, #if FF_API_PRIVATE_OPT { "b_strategy", "-1" }, diff --git a/libavcodec/qsvenc_hevc.c b/libavcodec/qsvenc_hevc.c index 4339b316a..da64b4c21 100644 --- a/libavcodec/qsvenc_hevc.c +++ b/libavcodec/qsvenc_hevc.c @@ -107,6 +107,7 @@ static int generate_fake_vps(QSVEncContext *q, AVCodecContext *avctx) /* generate the VPS */ vps.vps_max_layers = 1; vps.vps_max_sub_layers = sps.max_sub_layers; + vps.vps_temporal_id_nesting_flag = sps.temporal_id_nesting_flag; memcpy(&vps.ptl, &sps.ptl, sizeof(vps.ptl)); vps.vps_sub_layer_ordering_info_present_flag = 1; for (i = 0; i < HEVC_MAX_SUB_LAYERS; i++) { @@ -121,6 +122,7 @@ static int generate_fake_vps(QSVEncContext *q, AVCodecContext *avctx) vps.vps_time_scale = sps.vui.vui_time_scale; vps.vps_poc_proportional_to_timing_flag = sps.vui.vui_poc_proportional_to_timing_flag; vps.vps_num_ticks_poc_diff_one = sps.vui.vui_num_ticks_poc_diff_one_minus1 + 1; + vps.vps_num_hrd_parameters = 0; /* generate the encoded RBSP form of the VPS */ ret = ff_hevc_encode_nal_vps(&vps, sps.vps_id, vps_rbsp_buf, sizeof(vps_rbsp_buf)); @@ -138,8 +140,7 @@ static int generate_fake_vps(QSVEncContext *q, AVCodecContext *avctx) bytestream2_put_byte(&pbc, 1); // header while (bytestream2_get_bytes_left(&gbc)) { - uint32_t b = bytestream2_peek_be24(&gbc); - if (b <= 3) { + if (bytestream2_get_bytes_left(&gbc) >= 3 && bytestream2_peek_be24(&gbc) <= 3) { bytestream2_put_be24(&pbc, 3); bytestream2_skip(&gbc, 2); } else @@ -193,10 +194,12 @@ static av_cold int qsv_enc_init(AVCodecContext *avctx) if (ret < 0) return ret; - ret = generate_fake_vps(&q->qsv, avctx); - if (ret < 0) { - ff_qsv_enc_close(avctx, &q->qsv); - return ret; + if (!q->qsv.hevc_vps) { + ret = generate_fake_vps(&q->qsv, avctx); + if (ret < 0) { + ff_qsv_enc_close(avctx, &q->qsv); + return ret; + } } return 0; @@ -217,12 +220,6 @@ static av_cold int qsv_enc_close(AVCodecContext *avctx) return ff_qsv_enc_close(avctx, &q->qsv); } -#if defined(_WIN32) -#define LOAD_PLUGIN_DEFAULT LOAD_PLUGIN_HEVC_SW -#else -#define LOAD_PLUGIN_DEFAULT LOAD_PLUGIN_HEVC_HW -#endif - #define OFFSET(x) offsetof(QSVHEVCEncContext, x) #define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM static const AVOption options[] = { @@ -230,7 +227,7 @@ static const AVOption options[] = { { "idr_interval", "Distance (in I-frames) between IDR frames", OFFSET(qsv.idr_interval), AV_OPT_TYPE_INT, { .i64 = 0 }, -1, INT_MAX, VE, "idr_interval" }, { "begin_only", "Output an IDR-frame only at the beginning of the stream", 0, AV_OPT_TYPE_CONST, { .i64 = -1 }, 0, 0, VE, "idr_interval" }, - { "load_plugin", "A user plugin to load in an internal session", OFFSET(load_plugin), AV_OPT_TYPE_INT, { .i64 = LOAD_PLUGIN_DEFAULT }, LOAD_PLUGIN_NONE, LOAD_PLUGIN_HEVC_HW, VE, "load_plugin" }, + { "load_plugin", "A user plugin to load in an internal session", OFFSET(load_plugin), AV_OPT_TYPE_INT, { .i64 = LOAD_PLUGIN_HEVC_HW }, LOAD_PLUGIN_NONE, LOAD_PLUGIN_HEVC_HW, VE, "load_plugin" }, { "none", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = LOAD_PLUGIN_NONE }, 0, 0, VE, "load_plugin" }, { "hevc_sw", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = LOAD_PLUGIN_HEVC_SW }, 0, 0, VE, "load_plugin" }, { "hevc_hw", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = LOAD_PLUGIN_HEVC_HW }, 0, 0, VE, "load_plugin" }, @@ -244,6 +241,8 @@ static const AVOption options[] = { { "main10", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MFX_PROFILE_HEVC_MAIN10 }, INT_MIN, INT_MAX, VE, "profile" }, { "mainsp", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MFX_PROFILE_HEVC_MAINSP }, INT_MIN, INT_MAX, VE, "profile" }, + { "gpb", "1: GPB (generalized P/B frame); 0: regular P frame", OFFSET(qsv.gpb), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, VE}, + { NULL }, }; @@ -260,7 +259,7 @@ static const AVCodecDefault qsv_enc_defaults[] = { // same as the x264 default { "g", "248" }, { "bf", "8" }, - + { "trellis", "-1" }, { "flags", "+cgop" }, #if FF_API_PRIVATE_OPT { "b_strategy", "-1" }, diff --git a/libavcodec/qsvenc_jpeg.c b/libavcodec/qsvenc_jpeg.c index c18fe9194..1619a335c 100644 --- a/libavcodec/qsvenc_jpeg.c +++ b/libavcodec/qsvenc_jpeg.c @@ -29,7 +29,6 @@ #include "avcodec.h" #include "internal.h" -#include "h264.h" #include "qsv.h" #include "qsv_internal.h" #include "qsvenc.h" @@ -64,6 +63,7 @@ static av_cold int qsv_enc_close(AVCodecContext *avctx) #define OFFSET(x) offsetof(QSVMJPEGEncContext, x) #define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM static const AVOption options[] = { + { "async_depth", "Maximum processing parallelism", OFFSET(qsv.async_depth), AV_OPT_TYPE_INT, { .i64 = ASYNC_DEPTH_DEFAULT }, 1, INT_MAX, VE }, { NULL }, }; @@ -74,6 +74,11 @@ static const AVClass class = { .version = LIBAVUTIL_VERSION_INT, }; +static const AVCodecDefault qsv_enc_defaults[] = { + { "global_quality", "80" }, + { NULL }, +}; + AVCodec ff_mjpeg_qsv_encoder = { .name = "mjpeg_qsv", .long_name = NULL_IF_CONFIG_SMALL("MJPEG (Intel Quick Sync Video acceleration)"), @@ -88,5 +93,6 @@ AVCodec ff_mjpeg_qsv_encoder = { AV_PIX_FMT_QSV, AV_PIX_FMT_NONE }, .priv_class = &class, + .defaults = qsv_enc_defaults, .wrapper_name = "qsv", }; diff --git a/libavcodec/qsvenc_mpeg2.c b/libavcodec/qsvenc_mpeg2.c index a7427d810..e4ade56d6 100644 --- a/libavcodec/qsvenc_mpeg2.c +++ b/libavcodec/qsvenc_mpeg2.c @@ -87,7 +87,7 @@ static const AVCodecDefault qsv_enc_defaults[] = { // same as the x264 default { "g", "250" }, { "bf", "3" }, - + { "trellis", "-1" }, { "flags", "+cgop" }, #if FF_API_PRIVATE_OPT { "b_strategy", "-1" }, diff --git a/libavcodec/qtrle.c b/libavcodec/qtrle.c index cd8301d14..2c29547e5 100644 --- a/libavcodec/qtrle.c +++ b/libavcodec/qtrle.c @@ -297,10 +297,11 @@ static void qtrle_decode_16bpp(QtrleContext *s, int row_ptr, int lines_to_change static void qtrle_decode_24bpp(QtrleContext *s, int row_ptr, int lines_to_change) { - int rle_code; + int rle_code, rle_code_half; int pixel_ptr; int row_inc = s->frame->linesize[0]; - uint8_t r, g, b; + uint8_t b; + uint16_t rg; uint8_t *rgb = s->frame->data[0]; int pixel_limit = s->frame->linesize[0] * s->avctx->height; @@ -318,25 +319,31 @@ static void qtrle_decode_24bpp(QtrleContext *s, int row_ptr, int lines_to_change } else if (rle_code < 0) { /* decode the run length code */ rle_code = -rle_code; - r = bytestream2_get_byte(&s->g); - g = bytestream2_get_byte(&s->g); + rg = bytestream2_get_ne16(&s->g); b = bytestream2_get_byte(&s->g); CHECK_PIXEL_PTR(rle_code * 3); while (rle_code--) { - rgb[pixel_ptr++] = r; - rgb[pixel_ptr++] = g; - rgb[pixel_ptr++] = b; + AV_WN16(rgb + pixel_ptr, rg); + rgb[pixel_ptr + 2] = b; + pixel_ptr += 3; } } else { CHECK_PIXEL_PTR(rle_code * 3); - /* copy pixels directly to output */ - while (rle_code--) { - rgb[pixel_ptr++] = bytestream2_get_byte(&s->g); - rgb[pixel_ptr++] = bytestream2_get_byte(&s->g); - rgb[pixel_ptr++] = bytestream2_get_byte(&s->g); + rle_code_half = rle_code / 2; + + while (rle_code_half--) { /* copy 2 raw rgb value at the same time */ + AV_WN32(rgb + pixel_ptr, bytestream2_get_ne32(&s->g)); /* rgbr */ + AV_WN16(rgb + pixel_ptr + 4, bytestream2_get_ne16(&s->g)); /* rgbr */ + pixel_ptr += 6; + } + + if (rle_code % 2 != 0){ /* not even raw value */ + AV_WN16(rgb + pixel_ptr, bytestream2_get_ne16(&s->g)); + rgb[pixel_ptr + 2] = bytestream2_get_byte(&s->g); + pixel_ptr += 3; } } } @@ -346,7 +353,7 @@ static void qtrle_decode_24bpp(QtrleContext *s, int row_ptr, int lines_to_change static void qtrle_decode_32bpp(QtrleContext *s, int row_ptr, int lines_to_change) { - int rle_code; + int rle_code, rle_code_half; int pixel_ptr; int row_inc = s->frame->linesize[0]; unsigned int argb; @@ -367,7 +374,7 @@ static void qtrle_decode_32bpp(QtrleContext *s, int row_ptr, int lines_to_change } else if (rle_code < 0) { /* decode the run length code */ rle_code = -rle_code; - argb = bytestream2_get_be32(&s->g); + argb = bytestream2_get_ne32(&s->g); CHECK_PIXEL_PTR(rle_code * 4); @@ -379,10 +386,15 @@ static void qtrle_decode_32bpp(QtrleContext *s, int row_ptr, int lines_to_change CHECK_PIXEL_PTR(rle_code * 4); /* copy pixels directly to output */ - while (rle_code--) { - argb = bytestream2_get_be32(&s->g); - AV_WN32A(rgb + pixel_ptr, argb); - pixel_ptr += 4; + rle_code_half = rle_code / 2; + while (rle_code_half--) { /* copy 2 argb raw value at the same time */ + AV_WN64(rgb + pixel_ptr, bytestream2_get_ne64(&s->g)); + pixel_ptr += 8; + } + + if (rle_code % 2 != 0){ /* not even raw value */ + AV_WN32A(rgb + pixel_ptr, bytestream2_get_ne32(&s->g)); + pixel_ptr += 4; } } } @@ -416,7 +428,7 @@ static av_cold int qtrle_decode_init(AVCodecContext *avctx) break; case 32: - avctx->pix_fmt = AV_PIX_FMT_RGB32; + avctx->pix_fmt = AV_PIX_FMT_ARGB; break; default: @@ -440,18 +452,19 @@ static int qtrle_decode_frame(AVCodecContext *avctx, int header, start_line; int height, row_ptr; int has_palette = 0; - int ret; + int ret, size; bytestream2_init(&s->g, avpkt->data, avpkt->size); - if ((ret = ff_reget_buffer(avctx, s->frame)) < 0) - return ret; /* check if this frame is even supposed to change */ if (avpkt->size < 8) - goto done; + return avpkt->size; /* start after the chunk size */ - bytestream2_seek(&s->g, 4, SEEK_SET); + size = bytestream2_get_be32(&s->g) & 0x3FFFFFFF; + if (size - avpkt->size > size * (int64_t)avctx->discard_damaged_percentage / 100) + return AVERROR_INVALIDDATA; + /* fetch the header */ header = bytestream2_get_be16(&s->g); @@ -459,17 +472,20 @@ static int qtrle_decode_frame(AVCodecContext *avctx, /* if a header is present, fetch additional decoding parameters */ if (header & 0x0008) { if (avpkt->size < 14) - goto done; + return avpkt->size; start_line = bytestream2_get_be16(&s->g); bytestream2_skip(&s->g, 2); height = bytestream2_get_be16(&s->g); bytestream2_skip(&s->g, 2); if (height > s->avctx->height - start_line) - goto done; + return avpkt->size; } else { start_line = 0; height = s->avctx->height; } + if ((ret = ff_reget_buffer(avctx, s->frame)) < 0) + return ret; + row_ptr = s->frame->linesize[0] * start_line; switch (avctx->bits_per_coded_sample) { @@ -530,7 +546,6 @@ static int qtrle_decode_frame(AVCodecContext *avctx, memcpy(s->frame->data[1], s->pal, AVPALETTE_SIZE); } -done: if ((ret = av_frame_ref(data, s->frame)) < 0) return ret; *got_frame = 1; diff --git a/libavcodec/r210dec.c b/libavcodec/r210dec.c index dbc94c76b..407684c7f 100644 --- a/libavcodec/r210dec.c +++ b/libavcodec/r210dec.c @@ -27,11 +27,7 @@ static av_cold int decode_init(AVCodecContext *avctx) { - if ((avctx->codec_tag & 0xFFFFFF) == MKTAG('r', '1', '0', 0)) { - avctx->pix_fmt = AV_PIX_FMT_BGR48; - } else { - avctx->pix_fmt = AV_PIX_FMT_RGB48; - } + avctx->pix_fmt = AV_PIX_FMT_GBRP10; avctx->bits_per_raw_sample = 10; return 0; @@ -45,7 +41,7 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, const uint32_t *src = (const uint32_t *)avpkt->data; int aligned_width = FFALIGN(avctx->width, avctx->codec_id == AV_CODEC_ID_R10K ? 1 : 64); - uint8_t *dst_line; + uint8_t *g_line, *b_line, *r_line; int r10 = (avctx->codec_tag & 0xFFFFFF) == MKTAG('r', '1', '0', 0); int le = avctx->codec_tag == MKTAG('R', '1', '0', 'k') && avctx->extradata_size >= 12 && !memcmp(&avctx->extradata[4], "DpxE", 4) && @@ -61,10 +57,14 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, pic->pict_type = AV_PICTURE_TYPE_I; pic->key_frame = 1; - dst_line = pic->data[0]; + g_line = pic->data[0]; + b_line = pic->data[1]; + r_line = pic->data[2]; for (h = 0; h < avctx->height; h++) { - uint16_t *dst = (uint16_t *)dst_line; + uint16_t *dstg = (uint16_t *)g_line; + uint16_t *dstb = (uint16_t *)b_line; + uint16_t *dstr = (uint16_t *)r_line; for (w = 0; w < avctx->width; w++) { uint32_t pixel; uint16_t r, g, b; @@ -73,21 +73,27 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, } else { pixel = av_be2ne32(*src++); } - if (avctx->codec_id == AV_CODEC_ID_R210 || r10) { - b = pixel << 6; - g = (pixel >> 4) & 0xffc0; - r = (pixel >> 14) & 0xffc0; + if (avctx->codec_id == AV_CODEC_ID_R210) { + b = pixel & 0x3ff; + g = (pixel >> 10) & 0x3ff; + r = (pixel >> 20) & 0x3ff; + } else if (r10) { + r = pixel & 0x3ff; + g = (pixel >> 10) & 0x3ff; + b = (pixel >> 20) & 0x3ff; } else { - b = (pixel << 4) & 0xffc0; - g = (pixel >> 6) & 0xffc0; - r = (pixel >> 16) & 0xffc0; + b = (pixel >> 2) & 0x3ff; + g = (pixel >> 12) & 0x3ff; + r = (pixel >> 22) & 0x3ff; } - *dst++ = r | (r >> 10); - *dst++ = g | (g >> 10); - *dst++ = b | (b >> 10); + *dstr++ = r; + *dstg++ = g; + *dstb++ = b; } src += aligned_width - avctx->width; - dst_line += pic->linesize[0]; + g_line += pic->linesize[0]; + b_line += pic->linesize[1]; + r_line += pic->linesize[2]; } *got_frame = 1; diff --git a/libavcodec/r210enc.c b/libavcodec/r210enc.c index a55e5434f..02412f368 100644 --- a/libavcodec/r210enc.c +++ b/libavcodec/r210enc.c @@ -43,22 +43,26 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt, int aligned_width = FFALIGN(avctx->width, avctx->codec_id == AV_CODEC_ID_R10K ? 1 : 64); int pad = (aligned_width - avctx->width) * 4; - uint8_t *src_line; + uint8_t *srcr_line, *srcg_line, *srcb_line; uint8_t *dst; if ((ret = ff_alloc_packet2(avctx, pkt, 4 * aligned_width * avctx->height, 0)) < 0) return ret; - src_line = pic->data[0]; + srcg_line = pic->data[0]; + srcb_line = pic->data[1]; + srcr_line = pic->data[2]; dst = pkt->data; for (i = 0; i < avctx->height; i++) { - uint16_t *src = (uint16_t *)src_line; + uint16_t *srcr = (uint16_t *)srcr_line; + uint16_t *srcg = (uint16_t *)srcg_line; + uint16_t *srcb = (uint16_t *)srcb_line; for (j = 0; j < avctx->width; j++) { uint32_t pixel; - uint16_t r = *src++ >> 6; - uint16_t g = *src++ >> 6; - uint16_t b = *src++ >> 6; + uint16_t r = *srcr++; + uint16_t g = *srcg++; + uint16_t b = *srcb++; if (avctx->codec_id == AV_CODEC_ID_R210) pixel = (r << 20) | (g << 10) | b; else @@ -70,7 +74,9 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt, } memset(dst, 0, pad); dst += pad; - src_line += pic->linesize[0]; + srcr_line += pic->linesize[2]; + srcg_line += pic->linesize[0]; + srcb_line += pic->linesize[1]; } pkt->flags |= AV_PKT_FLAG_KEY; @@ -87,7 +93,7 @@ AVCodec ff_r210_encoder = { .id = AV_CODEC_ID_R210, .init = encode_init, .encode2 = encode_frame, - .pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_RGB48, AV_PIX_FMT_NONE }, + .pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_GBRP10, AV_PIX_FMT_NONE }, .capabilities = AV_CODEC_CAP_INTRA_ONLY, }; #endif @@ -99,7 +105,7 @@ AVCodec ff_r10k_encoder = { .id = AV_CODEC_ID_R10K, .init = encode_init, .encode2 = encode_frame, - .pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_RGB48, AV_PIX_FMT_NONE }, + .pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_GBRP10, AV_PIX_FMT_NONE }, .capabilities = AV_CODEC_CAP_INTRA_ONLY, }; #endif @@ -111,7 +117,7 @@ AVCodec ff_avrp_encoder = { .id = AV_CODEC_ID_AVRP, .init = encode_init, .encode2 = encode_frame, - .pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_RGB48, AV_PIX_FMT_NONE }, + .pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_GBRP10, AV_PIX_FMT_NONE }, .capabilities = AV_CODEC_CAP_INTRA_ONLY, }; #endif diff --git a/libavcodec/ralf.c b/libavcodec/ralf.c index 3f7953c6d..75c9371b9 100644 --- a/libavcodec/ralf.c +++ b/libavcodec/ralf.c @@ -220,7 +220,7 @@ static inline int extend_code(GetBitContext *gb, int val, int range, int bits) val -= range; } if (bits) - val = (val << bits) | get_bits(gb, bits); + val = ((unsigned)val << bits) | get_bits(gb, bits); return val; } @@ -286,7 +286,7 @@ static int decode_channel(RALFContext *ctx, GetBitContext *gb, int ch, add_bits--; range = 10; range2 = 21; - code_vlc = set->long_codes + code_params - 15; + code_vlc = set->long_codes + (code_params - 15); } else { add_bits = 0; range = 6; @@ -300,8 +300,8 @@ static int decode_channel(RALFContext *ctx, GetBitContext *gb, int ch, t = get_vlc2(gb, code_vlc->table, code_vlc->bits, 2); code1 = t / range2; code2 = t % range2; - dst[i] = extend_code(gb, code1, range, 0) << add_bits; - dst[i + 1] = extend_code(gb, code2, range, 0) << add_bits; + dst[i] = extend_code(gb, code1, range, 0) * (1 << add_bits); + dst[i + 1] = extend_code(gb, code2, range, 0) * (1 << add_bits); if (add_bits) { dst[i] |= get_bits(gb, add_bits); dst[i + 1] |= get_bits(gb, add_bits); @@ -323,7 +323,7 @@ static void apply_lpc(RALFContext *ctx, int ch, int length, int bits) acc = 0; for (j = 0; j < flen; j++) - acc += ctx->filter[j] * audio[i - j - 1]; + acc += (unsigned)ctx->filter[j] * audio[i - j - 1]; if (acc < 0) { acc = (acc + bias - 1) >> ctx->filter_bits; acc = FFMAX(acc, min_clip); diff --git a/libavcodec/rangecoder.c b/libavcodec/rangecoder.c index 0d53bef07..a6a3f082e 100644 --- a/libavcodec/rangecoder.c +++ b/libavcodec/rangecoder.c @@ -106,8 +106,10 @@ void ff_build_rac_states(RangeCoder *c, int factor, int max_p) } /* Return the number of bytes written. */ -int ff_rac_terminate(RangeCoder *c) +int ff_rac_terminate(RangeCoder *c, int version) { + if (version == 1) + put_rac(c, (uint8_t[]) { 129 }, 0); c->range = 0xFF; c->low += 0xFF; renorm_encoder(c); @@ -119,3 +121,22 @@ int ff_rac_terminate(RangeCoder *c) return c->bytestream - c->bytestream_start; } + +int ff_rac_check_termination(RangeCoder *c, int version) +{ + if (version == 1) { + RangeCoder tmp = *c; + get_rac(c, (uint8_t[]) { 129 }); + + if (c->bytestream == tmp.bytestream && c->bytestream > c->bytestream_start) + tmp.low -= *--tmp.bytestream; + tmp.bytestream_end = tmp.bytestream; + + if (get_rac(&tmp, (uint8_t[]) { 129 })) + return AVERROR_INVALIDDATA; + } else { + if (c->bytestream_end != c->bytestream) + return AVERROR_INVALIDDATA; + } + return 0; +} diff --git a/libavcodec/rangecoder.h b/libavcodec/rangecoder.h index 44af88b8f..4d4ca4d52 100644 --- a/libavcodec/rangecoder.h +++ b/libavcodec/rangecoder.h @@ -48,7 +48,24 @@ typedef struct RangeCoder { void ff_init_range_encoder(RangeCoder *c, uint8_t *buf, int buf_size); void ff_init_range_decoder(RangeCoder *c, const uint8_t *buf, int buf_size); -int ff_rac_terminate(RangeCoder *c); + +/** + * Terminates the range coder + * @param version version 0 requires the decoder to know the data size in bytes + * version 1 needs about 1 bit more space but does not need to + * carry the size from encoder to decoder + */ +int ff_rac_terminate(RangeCoder *c, int version); + +/** + * Check if at the current position there is a valid looking termination + * @param version version 0 requires the decoder to know the data size in bytes + * version 1 needs about 1 bit more space but does not need to + * carry the size from encoder to decoder + * @returns negative AVERROR code on error or non negative. + */ +int ff_rac_check_termination(RangeCoder *c, int version); + void ff_build_rac_states(RangeCoder *c, int factor, int max_p); static inline void renorm_encoder(RangeCoder *c) diff --git a/libavcodec/rasc.c b/libavcodec/rasc.c new file mode 100644 index 000000000..21fc43f32 --- /dev/null +++ b/libavcodec/rasc.c @@ -0,0 +1,817 @@ +/* + * RemotelyAnywhere Screen Capture decoder + * + * Copyright (c) 2018 Paul B Mahol + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include + +#include "libavutil/avassert.h" +#include "libavutil/imgutils.h" +#include "libavutil/opt.h" + +#include "avcodec.h" +#include "bytestream.h" +#include "internal.h" + +#include + +#define KBND MKTAG('K', 'B', 'N', 'D') +#define FINT MKTAG('F', 'I', 'N', 'T') +#define INIT MKTAG('I', 'N', 'I', 'T') +#define BNDL MKTAG('B', 'N', 'D', 'L') +#define KFRM MKTAG('K', 'F', 'R', 'M') +#define DLTA MKTAG('D', 'L', 'T', 'A') +#define MOUS MKTAG('M', 'O', 'U', 'S') +#define MPOS MKTAG('M', 'P', 'O', 'S') +#define MOVE MKTAG('M', 'O', 'V', 'E') +#define EMPT MKTAG('E', 'M', 'P', 'T') + +typedef struct RASCContext { + AVClass *class; + int skip_cursor; + GetByteContext gb; + uint8_t *delta; + int delta_size; + uint8_t *cursor; + int cursor_size; + unsigned cursor_w; + unsigned cursor_h; + unsigned cursor_x; + unsigned cursor_y; + int stride; + int bpp; + z_stream zstream; + AVFrame *frame; + AVFrame *frame1; + AVFrame *frame2; +} RASCContext; + +static void clear_plane(AVCodecContext *avctx, AVFrame *frame) +{ + RASCContext *s = avctx->priv_data; + uint8_t *dst = frame->data[0]; + + for (int y = 0; y < avctx->height; y++) { + memset(dst, 0, avctx->width * s->bpp); + dst += frame->linesize[0]; + } +} + +static void copy_plane(AVCodecContext *avctx, AVFrame *src, AVFrame *dst) +{ + RASCContext *s = avctx->priv_data; + uint8_t *srcp = src->data[0]; + uint8_t *dstp = dst->data[0]; + + for (int y = 0; y < avctx->height; y++) { + memcpy(dstp, srcp, s->stride); + srcp += src->linesize[0]; + dstp += dst->linesize[0]; + } +} + +static int init_frames(AVCodecContext *avctx) +{ + RASCContext *s = avctx->priv_data; + int ret; + + av_frame_unref(s->frame1); + av_frame_unref(s->frame2); + if ((ret = ff_get_buffer(avctx, s->frame1, 0)) < 0) + return ret; + + if ((ret = ff_get_buffer(avctx, s->frame2, 0)) < 0) + return ret; + + clear_plane(avctx, s->frame2); + clear_plane(avctx, s->frame1); + + return 0; +} + +static int decode_fint(AVCodecContext *avctx, + AVPacket *avpkt, unsigned size) +{ + RASCContext *s = avctx->priv_data; + GetByteContext *gb = &s->gb; + unsigned w, h, fmt; + int ret; + + if (bytestream2_peek_le32(gb) != 0x65) { + if (!s->frame2->data[0] || !s->frame1->data[0]) + return AVERROR_INVALIDDATA; + + clear_plane(avctx, s->frame2); + clear_plane(avctx, s->frame1); + return 0; + } + + bytestream2_skip(gb, 8); + w = bytestream2_get_le32(gb); + h = bytestream2_get_le32(gb); + bytestream2_skip(gb, 30); + fmt = bytestream2_get_le16(gb); + bytestream2_skip(gb, 24); + + switch (fmt) { + case 8: s->stride = FFALIGN(w, 4); + s->bpp = 1; + fmt = AV_PIX_FMT_PAL8; break; + case 16: s->stride = w * 2; + s->bpp = 2; + fmt = AV_PIX_FMT_RGB555LE; break; + case 32: s->stride = w * 4; + s->bpp = 4; + fmt = AV_PIX_FMT_BGR0; break; + default: return AVERROR_INVALIDDATA; + } + + ret = ff_set_dimensions(avctx, w, h); + if (ret < 0) + return ret; + avctx->width = w; + avctx->height = h; + avctx->pix_fmt = fmt; + + ret = init_frames(avctx); + if (ret < 0) + return ret; + + if (avctx->pix_fmt == AV_PIX_FMT_PAL8) { + uint32_t *pal = (uint32_t *)s->frame2->data[1]; + + for (int i = 0; i < 256; i++) + pal[i] = bytestream2_get_le32(gb) | 0xFF000000u; + } + + return 0; +} + +static int decode_zlib(AVCodecContext *avctx, AVPacket *avpkt, + unsigned size, unsigned uncompressed_size) +{ + RASCContext *s = avctx->priv_data; + GetByteContext *gb = &s->gb; + int zret; + + zret = inflateReset(&s->zstream); + if (zret != Z_OK) { + av_log(avctx, AV_LOG_ERROR, "Inflate reset error: %d\n", zret); + return AVERROR_EXTERNAL; + } + + av_fast_padded_malloc(&s->delta, &s->delta_size, uncompressed_size); + if (!s->delta) + return AVERROR(ENOMEM); + + s->zstream.next_in = avpkt->data + bytestream2_tell(gb); + s->zstream.avail_in = FFMIN(size, bytestream2_get_bytes_left(gb)); + + s->zstream.next_out = s->delta; + s->zstream.avail_out = s->delta_size; + + zret = inflate(&s->zstream, Z_FINISH); + if (zret != Z_STREAM_END) { + av_log(avctx, AV_LOG_ERROR, + "Inflate failed with return code: %d.\n", zret); + return AVERROR_INVALIDDATA; + } + + return 0; +} + +static int decode_move(AVCodecContext *avctx, + AVPacket *avpkt, unsigned size) +{ + RASCContext *s = avctx->priv_data; + GetByteContext *gb = &s->gb; + GetByteContext mc; + unsigned pos, compression, nb_moves; + unsigned uncompressed_size; + int ret; + + pos = bytestream2_tell(gb); + bytestream2_skip(gb, 8); + nb_moves = bytestream2_get_le32(gb); + bytestream2_skip(gb, 8); + compression = bytestream2_get_le32(gb); + + if (nb_moves > INT32_MAX / 16 || nb_moves > avctx->width * avctx->height) + return AVERROR_INVALIDDATA; + + uncompressed_size = 16 * nb_moves; + + if (compression == 1) { + ret = decode_zlib(avctx, avpkt, + size - (bytestream2_tell(gb) - pos), + uncompressed_size); + if (ret < 0) + return ret; + bytestream2_init(&mc, s->delta, uncompressed_size); + } else if (compression == 0) { + bytestream2_init(&mc, avpkt->data + bytestream2_tell(gb), + bytestream2_get_bytes_left(gb)); + } else if (compression == 2) { + avpriv_request_sample(avctx, "compression %d", compression); + return AVERROR_PATCHWELCOME; + } else { + return AVERROR_INVALIDDATA; + } + + if (bytestream2_get_bytes_left(&mc) < uncompressed_size) + return AVERROR_INVALIDDATA; + + for (int i = 0; i < nb_moves; i++) { + int type, start_x, start_y, end_x, end_y, mov_x, mov_y; + uint8_t *e2, *b1, *b2; + int w, h; + + type = bytestream2_get_le16(&mc); + start_x = bytestream2_get_le16(&mc); + start_y = bytestream2_get_le16(&mc); + end_x = bytestream2_get_le16(&mc); + end_y = bytestream2_get_le16(&mc); + mov_x = bytestream2_get_le16(&mc); + mov_y = bytestream2_get_le16(&mc); + bytestream2_skip(&mc, 2); + + if (start_x >= avctx->width || start_y >= avctx->height || + end_x >= avctx->width || end_y >= avctx->height || + mov_x >= avctx->width || mov_y >= avctx->height) { + continue; + } + + if (start_x >= end_x || start_y >= end_y) + continue; + + w = end_x - start_x; + h = end_y - start_y; + + if (mov_x + w > avctx->width || mov_y + h > avctx->height) + continue; + + if (!s->frame2->data[0] || !s->frame1->data[0]) + return AVERROR_INVALIDDATA; + + b1 = s->frame1->data[0] + s->frame1->linesize[0] * (start_y + h - 1) + start_x * s->bpp; + b2 = s->frame2->data[0] + s->frame2->linesize[0] * (start_y + h - 1) + start_x * s->bpp; + e2 = s->frame2->data[0] + s->frame2->linesize[0] * (mov_y + h - 1) + mov_x * s->bpp; + + if (type == 2) { + for (int j = 0; j < h; j++) { + memcpy(b1, b2, w * s->bpp); + b1 -= s->frame1->linesize[0]; + b2 -= s->frame2->linesize[0]; + } + } else if (type == 1) { + for (int j = 0; j < h; j++) { + memset(b2, 0, w * s->bpp); + b2 -= s->frame2->linesize[0]; + } + } else if (type == 0) { + uint8_t *buffer; + + av_fast_padded_malloc(&s->delta, &s->delta_size, w * h * s->bpp); + buffer = s->delta; + if (!buffer) + return AVERROR(ENOMEM); + + for (int j = 0; j < h; j++) { + memcpy(buffer + j * w * s->bpp, e2, w * s->bpp); + e2 -= s->frame2->linesize[0]; + } + + for (int j = 0; j < h; j++) { + memcpy(b2, buffer + j * w * s->bpp, w * s->bpp); + b2 -= s->frame2->linesize[0]; + } + } else { + return AVERROR_INVALIDDATA; + } + } + + bytestream2_skip(gb, size - (bytestream2_tell(gb) - pos)); + + return 0; +} + +#define NEXT_LINE \ + if (cx >= w * s->bpp) { \ + cx = 0; \ + cy--; \ + b1 -= s->frame1->linesize[0]; \ + b2 -= s->frame2->linesize[0]; \ + } \ + len--; + +static int decode_dlta(AVCodecContext *avctx, + AVPacket *avpkt, unsigned size) +{ + RASCContext *s = avctx->priv_data; + GetByteContext *gb = &s->gb; + GetByteContext dc; + unsigned uncompressed_size, pos; + unsigned x, y, w, h; + int ret, cx, cy, compression; + uint8_t *b1, *b2; + + pos = bytestream2_tell(gb); + bytestream2_skip(gb, 12); + uncompressed_size = bytestream2_get_le32(gb); + x = bytestream2_get_le32(gb); + y = bytestream2_get_le32(gb); + w = bytestream2_get_le32(gb); + h = bytestream2_get_le32(gb); + + if (x >= avctx->width || y >= avctx->height || + w > avctx->width || h > avctx->height) + return AVERROR_INVALIDDATA; + + if (x + w > avctx->width || y + h > avctx->height) + return AVERROR_INVALIDDATA; + + bytestream2_skip(gb, 4); + compression = bytestream2_get_le32(gb); + + if (compression == 1) { + if (w * h * s->bpp * 3 < uncompressed_size) + return AVERROR_INVALIDDATA; + ret = decode_zlib(avctx, avpkt, size, uncompressed_size); + if (ret < 0) + return ret; + bytestream2_init(&dc, s->delta, uncompressed_size); + } else if (compression == 0) { + if (bytestream2_get_bytes_left(gb) < uncompressed_size) + return AVERROR_INVALIDDATA; + bytestream2_init(&dc, avpkt->data + bytestream2_tell(gb), + uncompressed_size); + } else if (compression == 2) { + avpriv_request_sample(avctx, "compression %d", compression); + return AVERROR_PATCHWELCOME; + } else { + return AVERROR_INVALIDDATA; + } + + if (!s->frame2->data[0] || !s->frame1->data[0]) + return AVERROR_INVALIDDATA; + + b1 = s->frame1->data[0] + s->frame1->linesize[0] * (y + h - 1) + x * s->bpp; + b2 = s->frame2->data[0] + s->frame2->linesize[0] * (y + h - 1) + x * s->bpp; + cx = 0, cy = h; + while (bytestream2_get_bytes_left(&dc) > 0) { + int type = bytestream2_get_byte(&dc); + int len = bytestream2_get_byte(&dc); + unsigned fill; + + switch (type) { + case 1: + while (len > 0 && cy > 0) { + cx++; + NEXT_LINE + } + break; + case 2: + while (len > 0 && cy > 0) { + int v0 = b1[cx]; + int v1 = b2[cx]; + + b2[cx] = v0; + b1[cx] = v1; + cx++; + NEXT_LINE + } + break; + case 3: + while (len > 0 && cy > 0) { + fill = bytestream2_get_byte(&dc); + b1[cx] = b2[cx]; + b2[cx] = fill; + cx++; + NEXT_LINE + } + break; + case 4: + fill = bytestream2_get_byte(&dc); + while (len > 0 && cy > 0) { + AV_WL32(b1 + cx, AV_RL32(b2 + cx)); + AV_WL32(b2 + cx, fill); + cx++; + NEXT_LINE + } + break; + case 7: + fill = bytestream2_get_le32(&dc); + while (len > 0 && cy > 0) { + AV_WL32(b1 + cx, AV_RL32(b2 + cx)); + AV_WL32(b2 + cx, fill); + cx += 4; + NEXT_LINE + } + break; + case 10: + while (len > 0 && cy > 0) { + cx += 4; + NEXT_LINE + } + break; + case 12: + while (len > 0 && cy > 0) { + unsigned v0, v1; + + v0 = AV_RL32(b2 + cx); + v1 = AV_RL32(b1 + cx); + AV_WL32(b2 + cx, v1); + AV_WL32(b1 + cx, v0); + cx += 4; + NEXT_LINE + } + break; + case 13: + while (len > 0 && cy > 0) { + fill = bytestream2_get_le32(&dc); + AV_WL32(b1 + cx, AV_RL32(b2 + cx)); + AV_WL32(b2 + cx, fill); + cx += 4; + NEXT_LINE + } + break; + default: + avpriv_request_sample(avctx, "runlen %d", type); + return AVERROR_INVALIDDATA; + } + } + + bytestream2_skip(gb, size - (bytestream2_tell(gb) - pos)); + + return 0; +} + +static int decode_kfrm(AVCodecContext *avctx, + AVPacket *avpkt, unsigned size) +{ + RASCContext *s = avctx->priv_data; + GetByteContext *gb = &s->gb; + uint8_t *dst; + unsigned pos; + int zret, ret; + + pos = bytestream2_tell(gb); + if (bytestream2_peek_le32(gb) == 0x65) { + ret = decode_fint(avctx, avpkt, size); + if (ret < 0) + return ret; + } + + if (!s->frame2->data[0]) + return AVERROR_INVALIDDATA; + + zret = inflateReset(&s->zstream); + if (zret != Z_OK) { + av_log(avctx, AV_LOG_ERROR, "Inflate reset error: %d\n", zret); + return AVERROR_EXTERNAL; + } + + s->zstream.next_in = avpkt->data + bytestream2_tell(gb); + s->zstream.avail_in = bytestream2_get_bytes_left(gb); + + dst = s->frame2->data[0] + (avctx->height - 1) * s->frame2->linesize[0]; + for (int i = 0; i < avctx->height; i++) { + s->zstream.next_out = dst; + s->zstream.avail_out = s->stride; + + zret = inflate(&s->zstream, Z_SYNC_FLUSH); + if (zret != Z_OK && zret != Z_STREAM_END) { + av_log(avctx, AV_LOG_ERROR, + "Inflate failed with return code: %d.\n", zret); + return AVERROR_INVALIDDATA; + } + + dst -= s->frame2->linesize[0]; + } + + dst = s->frame1->data[0] + (avctx->height - 1) * s->frame1->linesize[0]; + for (int i = 0; i < avctx->height; i++) { + s->zstream.next_out = dst; + s->zstream.avail_out = s->stride; + + zret = inflate(&s->zstream, Z_SYNC_FLUSH); + if (zret != Z_OK && zret != Z_STREAM_END) { + av_log(avctx, AV_LOG_ERROR, + "Inflate failed with return code: %d.\n", zret); + return AVERROR_INVALIDDATA; + } + + dst -= s->frame1->linesize[0]; + } + + bytestream2_skip(gb, size - (bytestream2_tell(gb) - pos)); + + return 0; +} + +static int decode_mous(AVCodecContext *avctx, + AVPacket *avpkt, unsigned size) +{ + RASCContext *s = avctx->priv_data; + GetByteContext *gb = &s->gb; + unsigned w, h, pos, uncompressed_size; + int ret; + + pos = bytestream2_tell(gb); + bytestream2_skip(gb, 8); + w = bytestream2_get_le32(gb); + h = bytestream2_get_le32(gb); + bytestream2_skip(gb, 12); + uncompressed_size = bytestream2_get_le32(gb); + + if (w > avctx->width || h > avctx->height) + return AVERROR_INVALIDDATA; + + if (uncompressed_size != 3 * w * h) + return AVERROR_INVALIDDATA; + + av_fast_padded_malloc(&s->cursor, &s->cursor_size, uncompressed_size); + if (!s->cursor) + return AVERROR(ENOMEM); + + ret = decode_zlib(avctx, avpkt, + size - (bytestream2_tell(gb) - pos), + uncompressed_size); + if (ret < 0) + return ret; + memcpy(s->cursor, s->delta, uncompressed_size); + + bytestream2_skip(gb, size - (bytestream2_tell(gb) - pos)); + + s->cursor_w = w; + s->cursor_h = h; + + return 0; +} + +static int decode_mpos(AVCodecContext *avctx, + AVPacket *avpkt, unsigned size) +{ + RASCContext *s = avctx->priv_data; + GetByteContext *gb = &s->gb; + unsigned pos; + + pos = bytestream2_tell(gb); + bytestream2_skip(gb, 8); + s->cursor_x = bytestream2_get_le32(gb); + s->cursor_y = bytestream2_get_le32(gb); + + bytestream2_skip(gb, size - (bytestream2_tell(gb) - pos)); + + return 0; +} + +static void draw_cursor(AVCodecContext *avctx) +{ + RASCContext *s = avctx->priv_data; + uint8_t *dst, *pal; + + if (!s->cursor) + return; + + if (s->cursor_x >= avctx->width || s->cursor_y >= avctx->height) + return; + + if (s->cursor_x + s->cursor_w > avctx->width || + s->cursor_y + s->cursor_h > avctx->height) + return; + + if (avctx->pix_fmt == AV_PIX_FMT_PAL8) { + pal = s->frame->data[1]; + for (int i = 0; i < s->cursor_h; i++) { + for (int j = 0; j < s->cursor_w; j++) { + int cr = s->cursor[3 * s->cursor_w * (s->cursor_h - i - 1) + 3 * j + 0]; + int cg = s->cursor[3 * s->cursor_w * (s->cursor_h - i - 1) + 3 * j + 1]; + int cb = s->cursor[3 * s->cursor_w * (s->cursor_h - i - 1) + 3 * j + 2]; + int best = INT_MAX; + int index = 0; + int dist; + + if (cr == s->cursor[0] && cg == s->cursor[1] && cb == s->cursor[2]) + continue; + + dst = s->frame->data[0] + s->frame->linesize[0] * (s->cursor_y + i) + (s->cursor_x + j); + for (int k = 0; k < 256; k++) { + int pr = pal[k * 4 + 0]; + int pg = pal[k * 4 + 1]; + int pb = pal[k * 4 + 2]; + + dist = FFABS(cr - pr) + FFABS(cg - pg) + FFABS(cb - pb); + if (dist < best) { + best = dist; + index = k; + } + } + dst[0] = index; + } + } + } else if (avctx->pix_fmt == AV_PIX_FMT_RGB555LE) { + for (int i = 0; i < s->cursor_h; i++) { + for (int j = 0; j < s->cursor_w; j++) { + int cr = s->cursor[3 * s->cursor_w * (s->cursor_h - i - 1) + 3 * j + 0]; + int cg = s->cursor[3 * s->cursor_w * (s->cursor_h - i - 1) + 3 * j + 1]; + int cb = s->cursor[3 * s->cursor_w * (s->cursor_h - i - 1) + 3 * j + 2]; + + if (cr == s->cursor[0] && cg == s->cursor[1] && cb == s->cursor[2]) + continue; + + cr >>= 3; cg >>=3; cb >>= 3; + dst = s->frame->data[0] + s->frame->linesize[0] * (s->cursor_y + i) + 2 * (s->cursor_x + j); + AV_WL16(dst, cr | cg << 5 | cb << 10); + } + } + } else if (avctx->pix_fmt == AV_PIX_FMT_BGR0) { + for (int i = 0; i < s->cursor_h; i++) { + for (int j = 0; j < s->cursor_w; j++) { + int cr = s->cursor[3 * s->cursor_w * (s->cursor_h - i - 1) + 3 * j + 0]; + int cg = s->cursor[3 * s->cursor_w * (s->cursor_h - i - 1) + 3 * j + 1]; + int cb = s->cursor[3 * s->cursor_w * (s->cursor_h - i - 1) + 3 * j + 2]; + + if (cr == s->cursor[0] && cg == s->cursor[1] && cb == s->cursor[2]) + continue; + + dst = s->frame->data[0] + s->frame->linesize[0] * (s->cursor_y + i) + 4 * (s->cursor_x + j); + dst[0] = cb; + dst[1] = cg; + dst[2] = cr; + } + } + } +} + +static int decode_frame(AVCodecContext *avctx, + void *data, int *got_frame, + AVPacket *avpkt) +{ + RASCContext *s = avctx->priv_data; + GetByteContext *gb = &s->gb; + int ret, intra = 0; + AVFrame *frame = data; + + bytestream2_init(gb, avpkt->data, avpkt->size); + + if (bytestream2_peek_le32(gb) == EMPT) + return avpkt->size; + + s->frame = frame; + + while (bytestream2_get_bytes_left(gb) > 0) { + unsigned type, size = 0; + + if (bytestream2_get_bytes_left(gb) < 8) + return AVERROR_INVALIDDATA; + + type = bytestream2_get_le32(gb); + if (type == KBND || type == BNDL) { + intra = type == KBND; + type = bytestream2_get_le32(gb); + } + + size = bytestream2_get_le32(gb); + if (bytestream2_get_bytes_left(gb) < size) + return AVERROR_INVALIDDATA; + + switch (type) { + case FINT: + case INIT: + ret = decode_fint(avctx, avpkt, size); + break; + case KFRM: + ret = decode_kfrm(avctx, avpkt, size); + break; + case DLTA: + ret = decode_dlta(avctx, avpkt, size); + break; + case MOVE: + ret = decode_move(avctx, avpkt, size); + break; + case MOUS: + ret = decode_mous(avctx, avpkt, size); + break; + case MPOS: + ret = decode_mpos(avctx, avpkt, size); + break; + default: + bytestream2_skip(gb, size); + } + + if (ret < 0) + return ret; + } + + if (!s->frame2->data[0] || !s->frame1->data[0]) + return AVERROR_INVALIDDATA; + + if ((ret = ff_get_buffer(avctx, s->frame, 0)) < 0) + return ret; + + copy_plane(avctx, s->frame2, s->frame); + if (avctx->pix_fmt == AV_PIX_FMT_PAL8) + memcpy(s->frame->data[1], s->frame2->data[1], 1024); + if (!s->skip_cursor) + draw_cursor(avctx); + + s->frame->key_frame = intra; + s->frame->pict_type = intra ? AV_PICTURE_TYPE_I : AV_PICTURE_TYPE_P; + + *got_frame = 1; + + return avpkt->size; +} + +static av_cold int decode_init(AVCodecContext *avctx) +{ + RASCContext *s = avctx->priv_data; + int zret; + + s->zstream.zalloc = Z_NULL; + s->zstream.zfree = Z_NULL; + s->zstream.opaque = Z_NULL; + zret = inflateInit(&s->zstream); + if (zret != Z_OK) { + av_log(avctx, AV_LOG_ERROR, "Inflate init error: %d\n", zret); + return AVERROR_EXTERNAL; + } + + s->frame1 = av_frame_alloc(); + s->frame2 = av_frame_alloc(); + if (!s->frame1 || !s->frame2) + return AVERROR(ENOMEM); + + return 0; +} + +static av_cold int decode_close(AVCodecContext *avctx) +{ + RASCContext *s = avctx->priv_data; + + av_freep(&s->cursor); + s->cursor_size = 0; + av_freep(&s->delta); + s->delta_size = 0; + av_frame_free(&s->frame1); + av_frame_free(&s->frame2); + inflateEnd(&s->zstream); + + return 0; +} + +static void decode_flush(AVCodecContext *avctx) +{ + RASCContext *s = avctx->priv_data; + + clear_plane(avctx, s->frame1); + clear_plane(avctx, s->frame2); +} + +static const AVOption options[] = { +{ "skip_cursor", "skip the cursor", offsetof(RASCContext, skip_cursor), AV_OPT_TYPE_BOOL, {.i64 = 0 }, 0, 1, AV_OPT_FLAG_DECODING_PARAM | AV_OPT_FLAG_VIDEO_PARAM }, +{ NULL }, +}; + +static const AVClass rasc_decoder_class = { + .class_name = "rasc decoder", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; + +AVCodec ff_rasc_decoder = { + .name = "rasc", + .long_name = NULL_IF_CONFIG_SMALL("RemotelyAnywhere Screen Capture"), + .type = AVMEDIA_TYPE_VIDEO, + .id = AV_CODEC_ID_RASC, + .priv_data_size = sizeof(RASCContext), + .init = decode_init, + .close = decode_close, + .decode = decode_frame, + .flush = decode_flush, + .capabilities = AV_CODEC_CAP_DR1, + .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE | + FF_CODEC_CAP_INIT_CLEANUP, + .priv_class = &rasc_decoder_class, +}; diff --git a/libavcodec/raw.c b/libavcodec/raw.c index 8da2a9735..b6fb91c1c 100644 --- a/libavcodec/raw.c +++ b/libavcodec/raw.c @@ -125,6 +125,8 @@ const PixelFormatTag ff_raw_pix_fmt_tags[] = { { AV_PIX_FMT_GRAY10BE, MKTAG(10 , 0 , '1', 'Y') }, { AV_PIX_FMT_GRAY12LE, MKTAG('Y', '1', 0 , 12 ) }, { AV_PIX_FMT_GRAY12BE, MKTAG(12 , 0 , '1', 'Y') }, + { AV_PIX_FMT_GRAY14LE, MKTAG('Y', '1', 0 , 14 ) }, + { AV_PIX_FMT_GRAY14BE, MKTAG(14 , 0 , '1', 'Y') }, { AV_PIX_FMT_GRAY16LE, MKTAG('Y', '1', 0 , 16 ) }, { AV_PIX_FMT_GRAY16BE, MKTAG(16 , 0 , '1', 'Y') }, { AV_PIX_FMT_YUV420P9LE, MKTAG('Y', '3', 11 , 9 ) }, @@ -175,6 +177,10 @@ const PixelFormatTag ff_raw_pix_fmt_tags[] = { { AV_PIX_FMT_YUVA422P10BE, MKTAG(10 , 10 , '4', 'Y') }, { AV_PIX_FMT_YUVA444P10LE, MKTAG('Y', '4', 0 , 10 ) }, { AV_PIX_FMT_YUVA444P10BE, MKTAG(10 , 0 , '4', 'Y') }, + { AV_PIX_FMT_YUVA422P12LE, MKTAG('Y', '4', 10 , 12 ) }, + { AV_PIX_FMT_YUVA422P12BE, MKTAG(12 , 10 , '4', 'Y') }, + { AV_PIX_FMT_YUVA444P12LE, MKTAG('Y', '4', 0 , 12 ) }, + { AV_PIX_FMT_YUVA444P12BE, MKTAG(12 , 0 , '4', 'Y') }, { AV_PIX_FMT_YUVA420P16LE, MKTAG('Y', '4', 11 , 16 ) }, { AV_PIX_FMT_YUVA420P16BE, MKTAG(16 , 11 , '4', 'Y') }, { AV_PIX_FMT_YUVA422P16LE, MKTAG('Y', '4', 10 , 16 ) }, diff --git a/libavcodec/rl2.c b/libavcodec/rl2.c index 6662979c5..2d336a61e 100644 --- a/libavcodec/rl2.c +++ b/libavcodec/rl2.c @@ -134,10 +134,15 @@ static av_cold int rl2_decode_init(AVCodecContext *avctx) Rl2Context *s = avctx->priv_data; int back_size; int i; + int ret; s->avctx = avctx; avctx->pix_fmt = AV_PIX_FMT_PAL8; + ret = ff_set_dimensions(avctx, 320, 200); + if (ret < 0) + return ret; + /** parse extra data */ if (!avctx->extradata || avctx->extradata_size < EXTRADATA1_SIZE) { av_log(avctx, AV_LOG_ERROR, "invalid extradata size\n"); diff --git a/libavcodec/rscc.c b/libavcodec/rscc.c index dae5e8463..f494c30ed 100644 --- a/libavcodec/rscc.c +++ b/libavcodec/rscc.c @@ -64,6 +64,7 @@ typedef struct RsccContext { /* zlib interaction */ uint8_t *inflated_buf; uLongf inflated_size; + int valid_pixels; } RsccContext; static av_cold int rscc_init(AVCodecContext *avctx) @@ -85,8 +86,18 @@ static av_cold int rscc_init(AVCodecContext *avctx) /* Get pixel format and the size of the pixel */ if (avctx->codec_tag == MKTAG('I', 'S', 'C', 'C')) { - avctx->pix_fmt = AV_PIX_FMT_BGRA; - ctx->component_size = 4; + if (avctx->extradata && avctx->extradata_size == 4) { + if ((avctx->extradata[0] >> 1) & 1) { + avctx->pix_fmt = AV_PIX_FMT_BGRA; + ctx->component_size = 4; + } else { + avctx->pix_fmt = AV_PIX_FMT_BGR24; + ctx->component_size = 3; + } + } else { + avctx->pix_fmt = AV_PIX_FMT_BGRA; + ctx->component_size = 4; + } } else if (avctx->codec_tag == MKTAG('R', 'S', 'C', 'C')) { ctx->component_size = avctx->bits_per_coded_sample / 8; switch (avctx->bits_per_coded_sample) { @@ -188,6 +199,12 @@ static int rscc_decode_frame(AVCodecContext *avctx, void *data, /* If necessary, uncompress tiles, and hijack the bytestream reader */ if (packed_tiles_size != tiles_nb * TILE_SIZE) { uLongf length = tiles_nb * TILE_SIZE; + + if (bytestream2_get_bytes_left(gbc) < packed_tiles_size) { + ret = AVERROR_INVALIDDATA; + goto end; + } + inflated_tiles = av_malloc(length); if (!inflated_tiles) { ret = AVERROR(ENOMEM); @@ -337,8 +354,11 @@ static int rscc_decode_frame(AVCodecContext *avctx, void *data, } memcpy (frame->data[1], ctx->palette, AVPALETTE_SIZE); } - - *got_frame = 1; + // We only return a picture when enough of it is undamaged, this avoids copying nearly broken frames around + if (ctx->valid_pixels < ctx->inflated_size) + ctx->valid_pixels += pixel_size; + if (ctx->valid_pixels >= ctx->inflated_size * (100 - avctx->discard_damaged_percentage) / 100) + *got_frame = 1; ret = avpkt->size; end: diff --git a/libavcodec/rv10.c b/libavcodec/rv10.c index 595e21751..729e4a8d2 100644 --- a/libavcodec/rv10.c +++ b/libavcodec/rv10.c @@ -388,9 +388,9 @@ static int rv20_decode_picture_header(RVDecContext *rv) // attempt to keep aspect during typical resolution switches if (!old_aspect.num) old_aspect = (AVRational){1, 1}; - if (2 * new_w * s->height == new_h * s->width) + if (2 * (int64_t)new_w * s->height == (int64_t)new_h * s->width) s->avctx->sample_aspect_ratio = av_mul_q(old_aspect, (AVRational){2, 1}); - if (new_w * s->height == 2 * new_h * s->width) + if ((int64_t)new_w * s->height == 2 * (int64_t)new_h * s->width) s->avctx->sample_aspect_ratio = av_mul_q(old_aspect, (AVRational){1, 2}); ret = ff_set_dimensions(s->avctx, new_w, new_h); @@ -646,7 +646,7 @@ static int rv10_decode_packet(AVCodecContext *avctx, const uint8_t *buf, // Repeat the slice end check from ff_h263_decode_mb with our active // bitstream size - if (ret != SLICE_ERROR) { + if (ret != SLICE_ERROR && active_bits_size >= get_bits_count(&s->gb)) { int v = show_bits(&s->gb, 16); if (get_bits_count(&s->gb) + 16 > active_bits_size) diff --git a/libavcodec/sanm.c b/libavcodec/sanm.c index 811fd2188..d0000ebd0 100644 --- a/libavcodec/sanm.c +++ b/libavcodec/sanm.c @@ -491,6 +491,11 @@ static av_cold int decode_init(AVCodecContext *avctx) ctx->avctx = avctx; ctx->version = !avctx->extradata_size; + // early sanity check before allocations to avoid need for deallocation code. + if (!ctx->version && avctx->extradata_size < 1026) { + av_log(avctx, AV_LOG_ERROR, "Not enough extradata.\n"); + return AVERROR_INVALIDDATA; + } avctx->pix_fmt = ctx->version ? AV_PIX_FMT_RGB565 : AV_PIX_FMT_PAL8; @@ -506,11 +511,6 @@ static av_cold int decode_init(AVCodecContext *avctx) if (!ctx->version) { int i; - if (avctx->extradata_size < 1026) { - av_log(avctx, AV_LOG_ERROR, "Not enough extradata.\n"); - return AVERROR_INVALIDDATA; - } - ctx->subversion = AV_RL16(avctx->extradata); for (i = 0; i < PALETTE_SIZE; i++) ctx->pal[i] = 0xFFU << 24 | AV_RL32(avctx->extradata + 2 + i * 4); @@ -1358,8 +1358,10 @@ static int read_frame_header(SANMVideoContext *ctx, SANMFrameHeader *hdr) static void fill_frame(uint16_t *pbuf, int buf_size, uint16_t color) { - while (buf_size--) + if (buf_size--) { *pbuf++ = color; + av_memcpy_backptr((uint8_t*)pbuf, 2, 2*buf_size); + } } static int copy_output(SANMVideoContext *ctx, SANMFrameHeader *hdr) diff --git a/libavcodec/scpr.c b/libavcodec/scpr.c index 485609522..dc890a87e 100644 --- a/libavcodec/scpr.c +++ b/libavcodec/scpr.c @@ -27,44 +27,13 @@ #include "avcodec.h" #include "bytestream.h" #include "internal.h" +#include "scpr.h" +#include "scpr3.h" #define TOP 0x01000000 #define BOT 0x010000 -typedef struct RangeCoder { - unsigned code; - unsigned range; - unsigned code1; -} RangeCoder; - -typedef struct PixelModel { - unsigned freq[256]; - unsigned lookup[16]; - unsigned total_freq; -} PixelModel; - -typedef struct SCPRContext { - AVFrame *last_frame; - AVFrame *current_frame; - GetByteContext gb; - RangeCoder rc; - PixelModel pixel_model[3][4096]; - unsigned op_model[6][7]; - unsigned run_model[6][257]; - unsigned range_model[257]; - unsigned count_model[257]; - unsigned fill_model[6]; - unsigned sxy_model[4][17]; - unsigned mv_model[2][513]; - unsigned nbx, nby; - unsigned nbcount; - unsigned *blocks; - unsigned cbits; - int cxshift; - - int (*get_freq)(RangeCoder *rc, unsigned total_freq, unsigned *freq); - int (*decode)(GetByteContext *gb, RangeCoder *rc, unsigned cumFreq, unsigned freq, unsigned total_freq); -} SCPRContext; +#include "scpr3.c" static void init_rangecoder(RangeCoder *rc, GetByteContext *gb) { @@ -90,14 +59,14 @@ static void reinit_tables(SCPRContext *s) } for (j = 0; j < 6; j++) { - unsigned *p = s->run_model[j]; + uint32_t *p = s->run_model[j]; for (i = 0; i < 256; i++) p[i] = 1; p[256] = 256; } for (j = 0; j < 6; j++) { - unsigned *op = s->op_model[j]; + uint32_t *op = s->op_model[j]; for (i = 0; i < 6; i++) op[i] = 1; op[6] = 6; @@ -130,13 +99,13 @@ static void reinit_tables(SCPRContext *s) s->mv_model[1][512] = 512; } -static int decode(GetByteContext *gb, RangeCoder *rc, unsigned cumFreq, unsigned freq, unsigned total_freq) +static int decode(GetByteContext *gb, RangeCoder *rc, uint32_t cumFreq, uint32_t freq, uint32_t total_freq) { rc->code -= cumFreq * rc->range; rc->range *= freq; while (rc->range < TOP && bytestream2_get_bytes_left(gb) > 0) { - unsigned byte = bytestream2_get_byte(gb); + uint32_t byte = bytestream2_get_byteu(gb); rc->code = (rc->code << 8) | byte; rc->range <<= 8; } @@ -144,7 +113,7 @@ static int decode(GetByteContext *gb, RangeCoder *rc, unsigned cumFreq, unsigned return 0; } -static int get_freq(RangeCoder *rc, unsigned total_freq, unsigned *freq) +static int get_freq(RangeCoder *rc, uint32_t total_freq, uint32_t *freq) { if (total_freq == 0) return AVERROR_INVALIDDATA; @@ -159,9 +128,9 @@ static int get_freq(RangeCoder *rc, unsigned total_freq, unsigned *freq) return 0; } -static int decode0(GetByteContext *gb, RangeCoder *rc, unsigned cumFreq, unsigned freq, unsigned total_freq) +static int decode0(GetByteContext *gb, RangeCoder *rc, uint32_t cumFreq, uint32_t freq, uint32_t total_freq) { - unsigned t; + uint32_t t; if (total_freq == 0) return AVERROR_INVALIDDATA; @@ -172,7 +141,7 @@ static int decode0(GetByteContext *gb, RangeCoder *rc, unsigned cumFreq, unsigne rc->range = rc->range * (uint64_t)(freq + cumFreq) / total_freq - (t + 1); while (rc->range < TOP && bytestream2_get_bytes_left(gb) > 0) { - unsigned byte = bytestream2_get_byte(gb); + uint32_t byte = bytestream2_get_byteu(gb); rc->code = (rc->code << 8) | byte; rc->code1 <<= 8; rc->range <<= 8; @@ -181,7 +150,7 @@ static int decode0(GetByteContext *gb, RangeCoder *rc, unsigned cumFreq, unsigne return 0; } -static int get_freq0(RangeCoder *rc, unsigned total_freq, unsigned *freq) +static int get_freq0(RangeCoder *rc, uint32_t total_freq, uint32_t *freq) { if (rc->range == 0) return AVERROR_INVALIDDATA; @@ -191,13 +160,13 @@ static int get_freq0(RangeCoder *rc, unsigned total_freq, unsigned *freq) return 0; } -static int decode_value(SCPRContext *s, unsigned *cnt, unsigned maxc, unsigned step, unsigned *rval) +static int decode_value(SCPRContext *s, uint32_t *cnt, uint32_t maxc, uint32_t step, uint32_t *rval) { GetByteContext *gb = &s->gb; RangeCoder *rc = &s->rc; - unsigned totfr = cnt[maxc]; - unsigned value; - unsigned c = 0, cumfr = 0, cnt_c = 0; + uint32_t totfr = cnt[maxc]; + uint32_t value; + uint32_t c = 0, cumfr = 0, cnt_c = 0; int i, ret; if ((ret = s->get_freq(rc, totfr, &value)) < 0) @@ -223,7 +192,7 @@ static int decode_value(SCPRContext *s, unsigned *cnt, unsigned maxc, unsigned s if (totfr > BOT) { totfr = 0; for (i = 0; i < maxc; i++) { - unsigned nc = (cnt[i] >> 1) + 1; + uint32_t nc = (cnt[i] >> 1) + 1; cnt[i] = nc; totfr += nc; } @@ -235,12 +204,12 @@ static int decode_value(SCPRContext *s, unsigned *cnt, unsigned maxc, unsigned s return 0; } -static int decode_unit(SCPRContext *s, PixelModel *pixel, unsigned step, unsigned *rval) +static int decode_unit(SCPRContext *s, PixelModel *pixel, uint32_t step, uint32_t *rval) { GetByteContext *gb = &s->gb; RangeCoder *rc = &s->rc; - unsigned totfr = pixel->total_freq; - unsigned value, x = 0, cumfr = 0, cnt_x = 0; + uint32_t totfr = pixel->total_freq; + uint32_t value, x = 0, cumfr = 0, cnt_x = 0; int i, j, ret, c, cnt_c; if ((ret = s->get_freq(rc, totfr, &value)) < 0) @@ -278,13 +247,13 @@ static int decode_unit(SCPRContext *s, PixelModel *pixel, unsigned step, unsigne if (totfr > BOT) { totfr = 0; for (i = 0; i < 256; i++) { - unsigned nc = (pixel->freq[i] >> 1) + 1; + uint32_t nc = (pixel->freq[i] >> 1) + 1; pixel->freq[i] = nc; totfr += nc; } for (i = 0; i < 16; i++) { - unsigned sum = 0; - unsigned i16_17 = i << 4; + uint32_t sum = 0; + uint32_t i16_17 = i << 4; for (j = 0; j < 16; j++) sum += pixel->freq[i16_17 + j]; pixel->lookup[i] = sum; @@ -297,43 +266,57 @@ static int decode_unit(SCPRContext *s, PixelModel *pixel, unsigned step, unsigne return 0; } +static int decode_units(SCPRContext *s, uint32_t *r, uint32_t *g, uint32_t *b, + int *cx, int *cx1) +{ + const int cxshift = s->cxshift; + int ret; + + ret = decode_unit(s, &s->pixel_model[0][*cx + *cx1], 400, r); + if (ret < 0) + return ret; + + *cx1 = (*cx << 6) & 0xFC0; + *cx = *r >> cxshift; + ret = decode_unit(s, &s->pixel_model[1][*cx + *cx1], 400, g); + if (ret < 0) + return ret; + + *cx1 = (*cx << 6) & 0xFC0; + *cx = *g >> cxshift; + ret = decode_unit(s, &s->pixel_model[2][*cx + *cx1], 400, b); + if (ret < 0) + return ret; + + *cx1 = (*cx << 6) & 0xFC0; + *cx = *b >> cxshift; + + return 0; +} + static int decompress_i(AVCodecContext *avctx, uint32_t *dst, int linesize) { SCPRContext *s = avctx->priv_data; GetByteContext *gb = &s->gb; - int cx = 0, cx1 = 0, k = 0, clr = 0; - int run, r, g, b, off, y = 0, x = 0, z, ret; - unsigned backstep = linesize - avctx->width; - const int cxshift = s->cxshift; - unsigned lx, ly, ptype; + int cx = 0, cx1 = 0, k = 0; + int run, off, y = 0, x = 0, ret; + uint32_t clr = 0, r, g, b, backstep = linesize - avctx->width; + uint32_t lx, ly, ptype; reinit_tables(s); bytestream2_skip(gb, 2); init_rangecoder(&s->rc, gb); while (k < avctx->width + 1) { - ret = decode_unit(s, &s->pixel_model[0][cx + cx1], 400, &r); + ret = decode_units(s, &r, &g, &b, &cx, &cx1); if (ret < 0) return ret; - cx1 = (cx << 6) & 0xFC0; - cx = r >> cxshift; - ret = decode_unit(s, &s->pixel_model[1][cx + cx1], 400, &g); - if (ret < 0) - return ret; - - cx1 = (cx << 6) & 0xFC0; - cx = g >> cxshift; - ret = decode_unit(s, &s->pixel_model[2][cx + cx1], 400, &b); - if (ret < 0) - return ret; - - cx1 = (cx << 6) & 0xFC0; - cx = b >> cxshift; - ret = decode_value(s, s->run_model[0], 256, 400, &run); if (ret < 0) return ret; + if (run <= 0) + return AVERROR_INVALIDDATA; clr = (b << 16) + (g << 8) + r; k += run; @@ -359,19 +342,7 @@ static int decompress_i(AVCodecContext *avctx, uint32_t *dst, int linesize) if (ret < 0) return ret; if (ptype == 0) { - ret = decode_unit(s, &s->pixel_model[0][cx + cx1], 400, &r); - if (ret < 0) - return ret; - - cx1 = (cx << 6) & 0xFC0; - cx = r >> cxshift; - ret = decode_unit(s, &s->pixel_model[1][cx + cx1], 400, &g); - if (ret < 0) - return ret; - - cx1 = (cx << 6) & 0xFC0; - cx = g >> cxshift; - ret = decode_unit(s, &s->pixel_model[2][cx + cx1], 400, &b); + ret = decode_units(s, &r, &g, &b, &cx, &cx1); if (ret < 0) return ret; @@ -382,121 +353,14 @@ static int decompress_i(AVCodecContext *avctx, uint32_t *dst, int linesize) ret = decode_value(s, s->run_model[ptype], 256, 400, &run); if (ret < 0) return ret; + if (run <= 0) + return AVERROR_INVALIDDATA; - switch (ptype) { - case 0: - while (run-- > 0) { - if (y >= avctx->height) - return AVERROR_INVALIDDATA; - - dst[y * linesize + x] = clr; - lx = x; - ly = y; - x++; - if (x >= avctx->width) { - x = 0; - y++; - } - } - break; - case 1: - while (run-- > 0) { - if (y >= avctx->height) - return AVERROR_INVALIDDATA; - - dst[y * linesize + x] = dst[ly * linesize + lx]; - lx = x; - ly = y; - x++; - if (x >= avctx->width) { - x = 0; - y++; - } - } - clr = dst[ly * linesize + lx]; - break; - case 2: - while (run-- > 0) { - if (y < 1 || y >= avctx->height) - return AVERROR_INVALIDDATA; - - clr = dst[y * linesize + x + off + 1]; - dst[y * linesize + x] = clr; - lx = x; - ly = y; - x++; - if (x >= avctx->width) { - x = 0; - y++; - } - } - break; - case 4: - while (run-- > 0) { - uint8_t *odst = (uint8_t *)dst; - - if (y < 1 || y >= avctx->height || - (y == 1 && x == 0)) - return AVERROR_INVALIDDATA; - - if (x == 0) { - z = backstep; - } else { - z = 0; - } - - r = odst[(ly * linesize + lx) * 4] + - odst[((y * linesize + x) + off) * 4 + 4] - - odst[((y * linesize + x) + off - z) * 4]; - g = odst[(ly * linesize + lx) * 4 + 1] + - odst[((y * linesize + x) + off) * 4 + 5] - - odst[((y * linesize + x) + off - z) * 4 + 1]; - b = odst[(ly * linesize + lx) * 4 + 2] + - odst[((y * linesize + x) + off) * 4 + 6] - - odst[((y * linesize + x) + off - z) * 4 + 2]; - clr = ((b & 0xFF) << 16) + ((g & 0xFF) << 8) + (r & 0xFF); - dst[y * linesize + x] = clr; - lx = x; - ly = y; - x++; - if (x >= avctx->width) { - x = 0; - y++; - } - } - break; - case 5: - while (run-- > 0) { - if (y < 1 || y >= avctx->height || - (y == 1 && x == 0)) - return AVERROR_INVALIDDATA; - - if (x == 0) { - z = backstep; - } else { - z = 0; - } - - clr = dst[y * linesize + x + off - z]; - dst[y * linesize + x] = clr; - lx = x; - ly = y; - x++; - if (x >= avctx->width) { - x = 0; - y++; - } - } - break; - } - - if (avctx->bits_per_coded_sample == 16) { - cx1 = (clr & 0x3F00) >> 2; - cx = (clr & 0x3FFFFF) >> 16; - } else { - cx1 = (clr & 0xFC00) >> 4; - cx = (clr & 0xFFFFFF) >> 18; - } + ret = decode_run_i(avctx, ptype, run, &x, &y, clr, + dst, linesize, &lx, &ly, + backstep, off, &cx, &cx1); + if (ret < 0) + return ret; } return 0; @@ -510,23 +374,25 @@ static int decompress_p(AVCodecContext *avctx, GetByteContext *gb = &s->gb; int ret, temp = 0, min, max, x, y, cx = 0, cx1 = 0; int backstep = linesize - avctx->width; - const int cxshift = s->cxshift; if (bytestream2_get_byte(gb) == 0) - return 0; + return 1; bytestream2_skip(gb, 1); init_rangecoder(&s->rc, gb); ret = decode_value(s, s->range_model, 256, 1, &min); ret |= decode_value(s, s->range_model, 256, 1, &temp); + if (ret < 0) + return ret; + min += temp << 8; - ret |= decode_value(s, s->range_model, 256, 1, &max); + ret = decode_value(s, s->range_model, 256, 1, &max); ret |= decode_value(s, s->range_model, 256, 1, &temp); if (ret < 0) return ret; max += temp << 8; - if (min > max) + if (min > max || min >= s->nbcount) return AVERROR_INVALIDDATA; memset(s->blocks, 0, sizeof(*s->blocks) * s->nbcount); @@ -538,12 +404,18 @@ static int decompress_p(AVCodecContext *avctx, ret |= decode_value(s, s->count_model, 256, 20, &count); if (ret < 0) return ret; + if (count <= 0) + return AVERROR_INVALIDDATA; while (min < s->nbcount && count-- > 0) { s->blocks[min++] = fill; } } + ret = av_frame_copy(s->current_frame, s->last_frame); + if (ret < 0) + return ret; + for (y = 0; y < s->nby; y++) { for (x = 0; x < s->nbx; x++) { int sy1 = 0, sy2 = 16, sx1 = 0, sx2 = 16; @@ -584,27 +456,15 @@ static int decompress_p(AVCodecContext *avctx, } } } else { - int run, r, g, b, z, bx = x * 16 + sx1, by = y * 16 + sy1; - unsigned clr, ptype = 0; + int run, bx = x * 16 + sx1, by = y * 16 + sy1; + uint32_t r, g, b, clr, ptype = 0; for (; by < y * 16 + sy2 && by < avctx->height;) { ret = decode_value(s, s->op_model[ptype], 6, 1000, &ptype); if (ret < 0) return ret; if (ptype == 0) { - ret = decode_unit(s, &s->pixel_model[0][cx + cx1], 400, &r); - if (ret < 0) - return ret; - - cx1 = (cx << 6) & 0xFC0; - cx = r >> cxshift; - ret = decode_unit(s, &s->pixel_model[1][cx + cx1], 400, &g); - if (ret < 0) - return ret; - - cx1 = (cx << 6) & 0xFC0; - cx = g >> cxshift; - ret = decode_unit(s, &s->pixel_model[2][cx + cx1], 400, &b); + ret = decode_units(s, &r, &g, &b, &cx, &cx1); if (ret < 0) return ret; @@ -615,135 +475,14 @@ static int decompress_p(AVCodecContext *avctx, ret = decode_value(s, s->run_model[ptype], 256, 400, &run); if (ret < 0) return ret; + if (run <= 0) + return AVERROR_INVALIDDATA; - switch (ptype) { - case 0: - while (run-- > 0) { - if (by >= avctx->height) - return AVERROR_INVALIDDATA; - - dst[by * linesize + bx] = clr; - bx++; - if (bx >= x * 16 + sx2 || bx >= avctx->width) { - bx = x * 16 + sx1; - by++; - } - } - break; - case 1: - while (run-- > 0) { - if (bx == 0) { - if (by < 1) - return AVERROR_INVALIDDATA; - z = backstep; - } else { - z = 0; - } - - if (by >= avctx->height) - return AVERROR_INVALIDDATA; - - clr = dst[by * linesize + bx - 1 - z]; - dst[by * linesize + bx] = clr; - bx++; - if (bx >= x * 16 + sx2 || bx >= avctx->width) { - bx = x * 16 + sx1; - by++; - } - } - break; - case 2: - while (run-- > 0) { - if (by < 1 || by >= avctx->height) - return AVERROR_INVALIDDATA; - - clr = dst[(by - 1) * linesize + bx]; - dst[by * linesize + bx] = clr; - bx++; - if (bx >= x * 16 + sx2 || bx >= avctx->width) { - bx = x * 16 + sx1; - by++; - } - } - break; - case 3: - while (run-- > 0) { - if (by >= avctx->height) - return AVERROR_INVALIDDATA; - - clr = prev[by * plinesize + bx]; - dst[by * linesize + bx] = clr; - bx++; - if (bx >= x * 16 + sx2 || bx >= avctx->width) { - bx = x * 16 + sx1; - by++; - } - } - break; - case 4: - while (run-- > 0) { - uint8_t *odst = (uint8_t *)dst; - - if (by < 1 || by >= avctx->height) - return AVERROR_INVALIDDATA; - - if (bx == 0) { - if (by < 2) - return AVERROR_INVALIDDATA; - z = backstep; - } else { - z = 0; - } - - r = odst[((by - 1) * linesize + bx) * 4] + - odst[(by * linesize + bx - 1 - z) * 4] - - odst[((by - 1) * linesize + bx - 1 - z) * 4]; - g = odst[((by - 1) * linesize + bx) * 4 + 1] + - odst[(by * linesize + bx - 1 - z) * 4 + 1] - - odst[((by - 1) * linesize + bx - 1 - z) * 4 + 1]; - b = odst[((by - 1) * linesize + bx) * 4 + 2] + - odst[(by * linesize + bx - 1 - z) * 4 + 2] - - odst[((by - 1) * linesize + bx - 1 - z) * 4 + 2]; - clr = ((b & 0xFF) << 16) + ((g & 0xFF) << 8) + (r & 0xFF); - dst[by * linesize + bx] = clr; - bx++; - if (bx >= x * 16 + sx2 || bx >= avctx->width) { - bx = x * 16 + sx1; - by++; - } - } - break; - case 5: - while (run-- > 0) { - if (by < 1 || by >= avctx->height) - return AVERROR_INVALIDDATA; - - if (bx == 0) { - if (by < 2) - return AVERROR_INVALIDDATA; - z = backstep; - } else { - z = 0; - } - - clr = dst[(by - 1) * linesize + bx - 1 - z]; - dst[by * linesize + bx] = clr; - bx++; - if (bx >= x * 16 + sx2 || bx >= avctx->width) { - bx = x * 16 + sx1; - by++; - } - } - break; - } - - if (avctx->bits_per_coded_sample == 16) { - cx1 = (clr & 0x3F00) >> 2; - cx = (clr & 0x3FFFFF) >> 16; - } else { - cx1 = (clr & 0xFC00) >> 4; - cx = (clr & 0xFFFFFF) >> 18; - } + ret = decode_run_p(avctx, ptype, run, x, y, clr, + dst, prev, linesize, plinesize, &bx, &by, + backstep, sx1, sx2, &cx, &cx1); + if (ret < 0) + return ret; } } } @@ -773,20 +512,27 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, type = bytestream2_peek_byte(gb); if (type == 2) { + s->version = 1; s->get_freq = get_freq0; s->decode = decode0; frame->key_frame = 1; ret = decompress_i(avctx, (uint32_t *)s->current_frame->data[0], s->current_frame->linesize[0] / 4); } else if (type == 18) { + s->version = 2; s->get_freq = get_freq; s->decode = decode; frame->key_frame = 1; ret = decompress_i(avctx, (uint32_t *)s->current_frame->data[0], s->current_frame->linesize[0] / 4); - } else if (type == 17) { + } else if (type == 34) { + frame->key_frame = 1; + s->version = 3; + ret = decompress_i3(avctx, (uint32_t *)s->current_frame->data[0], + s->current_frame->linesize[0] / 4); + } else if (type == 17 || type == 33) { uint32_t clr, *dst = (uint32_t *)s->current_frame->data[0]; - int x, y; + int y; frame->key_frame = 1; bytestream2_skip(gb, 1); @@ -802,22 +548,25 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, clr = bytestream2_get_le24(gb); } for (y = 0; y < avctx->height; y++) { - for (x = 0; x < avctx->width; x++) { - dst[x] = clr; - } + dst[0] = clr; + av_memcpy_backptr((uint8_t*)(dst+1), 4, 4*avctx->width - 4); dst += s->current_frame->linesize[0] / 4; } } else if (type == 0 || type == 1) { frame->key_frame = 0; - ret = av_frame_copy(s->current_frame, s->last_frame); - if (ret < 0) - return ret; - - ret = decompress_p(avctx, (uint32_t *)s->current_frame->data[0], - s->current_frame->linesize[0] / 4, - (uint32_t *)s->last_frame->data[0], - s->last_frame->linesize[0] / 4); + if (s->version == 1 || s->version == 2) + ret = decompress_p(avctx, (uint32_t *)s->current_frame->data[0], + s->current_frame->linesize[0] / 4, + (uint32_t *)s->last_frame->data[0], + s->last_frame->linesize[0] / 4); + else + ret = decompress_p3(avctx, (uint32_t *)s->current_frame->data[0], + s->current_frame->linesize[0] / 4, + (uint32_t *)s->last_frame->data[0], + s->last_frame->linesize[0] / 4); + if (ret == 1) + return avpkt->size; } else { return AVERROR_PATCHWELCOME; } @@ -825,6 +574,9 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, if (ret < 0) return ret; + if (bytestream2_get_bytes_left(gb) > 5) + return AVERROR_INVALIDDATA; + if (avctx->bits_per_coded_sample != 16) { ret = av_frame_ref(data, s->current_frame); if (ret < 0) diff --git a/libavcodec/scpr.h b/libavcodec/scpr.h new file mode 100644 index 000000000..15cb87c46 --- /dev/null +++ b/libavcodec/scpr.h @@ -0,0 +1,365 @@ +/* + * ScreenPressor decoder + * + * Copyright (c) 2017 Paul B Mahol + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_SCPR_H +#define AVCODEC_SCPR_H + +#include +#include +#include + +#include "avcodec.h" +#include "bytestream.h" +#include "internal.h" +#include "scpr3.h" + +typedef struct RangeCoder { + uint32_t code; + uint32_t range; + uint32_t code1; +} RangeCoder; + +typedef struct PixelModel { + uint32_t freq[256]; + uint32_t lookup[16]; + uint32_t total_freq; +} PixelModel; + +typedef struct SCPRContext { + int version; + AVFrame *last_frame; + AVFrame *current_frame; + GetByteContext gb; + RangeCoder rc; + PixelModel pixel_model[3][4096]; + uint32_t op_model[6][7]; + uint32_t run_model[6][257]; + uint32_t range_model[257]; + uint32_t count_model[257]; + uint32_t fill_model[6]; + uint32_t sxy_model[4][17]; + uint32_t mv_model[2][513]; + uint32_t nbx, nby; + uint32_t nbcount; + uint32_t *blocks; + uint32_t cbits; + int cxshift; + + PixelModel3 pixel_model3[3][4096]; + RunModel3 run_model3[6]; + RunModel3 range_model3; + RunModel3 count_model3; + FillModel3 fill_model3; + SxyModel3 sxy_model3[4]; + MVModel3 mv_model3[2]; + OpModel3 op_model3[6]; + + int (*get_freq)(RangeCoder *rc, uint32_t total_freq, uint32_t *freq); + int (*decode)(GetByteContext *gb, RangeCoder *rc, uint32_t cumFreq, uint32_t freq, uint32_t total_freq); +} SCPRContext; + +static int decode_run_i(AVCodecContext *avctx, uint32_t ptype, int run, + int *px, int *py, uint32_t clr, uint32_t *dst, + int linesize, uint32_t *plx, uint32_t *ply, + uint32_t backstep, int off, int *cx, int *cx1) +{ + uint32_t r, g, b; + int z; + int x = *px, + y = *py; + uint32_t lx = *plx, + ly = *ply; + + if (y >= avctx->height) + return AVERROR_INVALIDDATA; + + switch (ptype) { + case 0: + while (run-- > 0) { + dst[y * linesize + x] = clr; + lx = x; + ly = y; + (x)++; + if (x >= avctx->width) { + x = 0; + (y)++; + if (y >= avctx->height && run) + return AVERROR_INVALIDDATA; + } + } + break; + case 1: + while (run-- > 0) { + dst[y * linesize + x] = dst[ly * linesize + lx]; + lx = x; + ly = y; + (x)++; + if (x >= avctx->width) { + x = 0; + (y)++; + if (y >= avctx->height && run) + return AVERROR_INVALIDDATA; + } + } + clr = dst[ly * linesize + lx]; + break; + case 2: + if (y < 1) + return AVERROR_INVALIDDATA; + + while (run-- > 0) { + clr = dst[y * linesize + x + off + 1]; + dst[y * linesize + x] = clr; + lx = x; + ly = y; + (x)++; + if (x >= avctx->width) { + x = 0; + (y)++; + if (y >= avctx->height && run) + return AVERROR_INVALIDDATA; + } + } + break; + case 4: + if (y < 1 || (y == 1 && x == 0)) + return AVERROR_INVALIDDATA; + + while (run-- > 0) { + uint8_t *odst = (uint8_t *)dst; + int off1 = (ly * linesize + lx) * 4; + int off2 = ((y * linesize + x) + off) * 4; + + if (x == 0) { + z = backstep * 4; + } else { + z = 0; + } + + r = odst[off1] + + odst[off2 + 4] - + odst[off2 - z ]; + g = odst[off1 + 1] + + odst[off2 + 5] - + odst[off2 - z + 1]; + b = odst[off1 + 2] + + odst[off2 + 6] - + odst[off2 - z + 2]; + clr = ((b & 0xFF) << 16) + ((g & 0xFF) << 8) + (r & 0xFF); + dst[y * linesize + x] = clr; + lx = x; + ly = y; + (x)++; + if (x >= avctx->width) { + x = 0; + (y)++; + if (y >= avctx->height && run) + return AVERROR_INVALIDDATA; + } + } + break; + case 5: + if (y < 1 || (y == 1 && x == 0)) + return AVERROR_INVALIDDATA; + + while (run-- > 0) { + if (x == 0) { + z = backstep; + } else { + z = 0; + } + + clr = dst[y * linesize + x + off - z]; + dst[y * linesize + x] = clr; + lx = x; + ly = y; + (x)++; + if (x >= avctx->width) { + x = 0; + (y)++; + if (y >= avctx->height && run) + return AVERROR_INVALIDDATA; + } + } + break; + } + + *px = x; + *py = y; + *plx= lx; + *ply= ly; + + if (avctx->bits_per_coded_sample == 16) { + *cx1 = (clr & 0x3F00) >> 2; + *cx = (clr & 0x3FFFFF) >> 16; + } else { + *cx1 = (clr & 0xFC00) >> 4; + *cx = (clr & 0xFFFFFF) >> 18; + } + + return 0; +} + +static int decode_run_p(AVCodecContext *avctx, uint32_t ptype, int run, + int x, int y, uint32_t clr, + uint32_t *dst, uint32_t *prev, + int linesize, int plinesize, + uint32_t *bx, uint32_t *by, + uint32_t backstep, int sx1, int sx2, + int *cx, int *cx1) +{ + uint32_t r, g, b; + int z; + + switch (ptype) { + case 0: + while (run-- > 0) { + if (*by >= avctx->height) + return AVERROR_INVALIDDATA; + + dst[*by * linesize + *bx] = clr; + (*bx)++; + if (*bx >= x * 16 + sx2 || *bx >= avctx->width) { + *bx = x * 16 + sx1; + (*by)++; + } + } + break; + case 1: + while (run-- > 0) { + if (*bx == 0) { + if (*by < 1) + return AVERROR_INVALIDDATA; + z = backstep; + } else { + z = 0; + } + + if (*by >= avctx->height) + return AVERROR_INVALIDDATA; + + clr = dst[*by * linesize + *bx - 1 - z]; + dst[*by * linesize + *bx] = clr; + (*bx)++; + if (*bx >= x * 16 + sx2 || *bx >= avctx->width) { + *bx = x * 16 + sx1; + (*by)++; + } + } + break; + case 2: + while (run-- > 0) { + if (*by < 1 || *by >= avctx->height) + return AVERROR_INVALIDDATA; + + clr = dst[(*by - 1) * linesize + *bx]; + dst[*by * linesize + *bx] = clr; + (*bx)++; + if (*bx >= x * 16 + sx2 || *bx >= avctx->width) { + *bx = x * 16 + sx1; + (*by)++; + } + } + break; + case 3: + while (run-- > 0) { + if (*by >= avctx->height) + return AVERROR_INVALIDDATA; + + clr = prev[*by * plinesize + *bx]; + dst[*by * linesize + *bx] = clr; + (*bx)++; + if (*bx >= x * 16 + sx2 || *bx >= avctx->width) { + *bx = x * 16 + sx1; + (*by)++; + } + } + break; + case 4: + while (run-- > 0) { + uint8_t *odst = (uint8_t *)dst; + + if (*by < 1 || *by >= avctx->height) + return AVERROR_INVALIDDATA; + + if (*bx == 0) { + if (*by < 2) + return AVERROR_INVALIDDATA; + z = backstep; + } else { + z = 0; + } + + r = odst[((*by - 1) * linesize + *bx) * 4] + + odst[(*by * linesize + *bx - 1 - z) * 4] - + odst[((*by - 1) * linesize + *bx - 1 - z) * 4]; + g = odst[((*by - 1) * linesize + *bx) * 4 + 1] + + odst[(*by * linesize + *bx - 1 - z) * 4 + 1] - + odst[((*by - 1) * linesize + *bx - 1 - z) * 4 + 1]; + b = odst[((*by - 1) * linesize + *bx) * 4 + 2] + + odst[(*by * linesize + *bx - 1 - z) * 4 + 2] - + odst[((*by - 1) * linesize + *bx - 1 - z) * 4 + 2]; + clr = ((b & 0xFF) << 16) + ((g & 0xFF) << 8) + (r & 0xFF); + dst[*by * linesize + *bx] = clr; + (*bx)++; + if (*bx >= x * 16 + sx2 || *bx >= avctx->width) { + *bx = x * 16 + sx1; + (*by)++; + } + } + break; + case 5: + while (run-- > 0) { + if (*by < 1 || *by >= avctx->height) + return AVERROR_INVALIDDATA; + + if (*bx == 0) { + if (*by < 2) + return AVERROR_INVALIDDATA; + z = backstep; + } else { + z = 0; + } + + clr = dst[(*by - 1) * linesize + *bx - 1 - z]; + dst[*by * linesize + *bx] = clr; + (*bx)++; + if (*bx >= x * 16 + sx2 || *bx >= avctx->width) { + *bx = x * 16 + sx1; + (*by)++; + } + } + break; + } + + if (avctx->bits_per_coded_sample == 16) { + *cx1 = (clr & 0x3F00) >> 2; + *cx = (clr & 0x3FFFFF) >> 16; + } else { + *cx1 = (clr & 0xFC00) >> 4; + *cx = (clr & 0xFFFFFF) >> 18; + } + + return 0; +} + +#endif /* AVCODEC_SCPR_H */ diff --git a/libavcodec/scpr3.c b/libavcodec/scpr3.c new file mode 100644 index 000000000..b4d2e21a1 --- /dev/null +++ b/libavcodec/scpr3.c @@ -0,0 +1,1214 @@ +/* + * ScreenPressor version 3 decoder + * + * Copyright (c) 2017 Paul B Mahol + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include + +#include "libavutil/qsort.h" + +#include "avcodec.h" +#include "bytestream.h" +#include "internal.h" +#include "scpr.h" + +static void renew_table3(uint32_t nsym, uint32_t *cntsum, + uint16_t *freqs, uint16_t *freqs1, + uint16_t *cnts, uint8_t *dectab) +{ + uint32_t a = 0, b = 4096 / nsym, c = b - (b >> 1); + + *cntsum = c * nsym; + + for (int d = 0; d < nsym; d++) { + freqs[d] = b; + freqs1[d] = a; + cnts[d] = c; + for (int q = a + 128 - 1 >> 7, f = (a + b - 1 >> 7) + 1; q < f; q++) + dectab[q] = d; + + a += b; + } +} + +static void reinit_tables3(SCPRContext * s) +{ + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 4096; j++) { + PixelModel3 *m = &s->pixel_model3[i][j]; + m->type = 0; + } + } + + for (int i = 0; i < 6; i++) { + renew_table3(256, &s->run_model3[i].cntsum, + s->run_model3[i].freqs[0], s->run_model3[i].freqs[1], + s->run_model3[i].cnts, s->run_model3[i].dectab); + } + + renew_table3(256, &s->range_model3.cntsum, + s->range_model3.freqs[0], s->range_model3.freqs[1], + s->range_model3.cnts, s->range_model3.dectab); + + renew_table3(5, &s->fill_model3.cntsum, + s->fill_model3.freqs[0], s->fill_model3.freqs[1], + s->fill_model3.cnts, s->fill_model3.dectab); + + renew_table3(256, &s->count_model3.cntsum, + s->count_model3.freqs[0], s->count_model3.freqs[1], + s->count_model3.cnts, s->count_model3.dectab); + + for (int i = 0; i < 4; i++) { + renew_table3(16, &s->sxy_model3[i].cntsum, + s->sxy_model3[i].freqs[0], s->sxy_model3[i].freqs[1], + s->sxy_model3[i].cnts, s->sxy_model3[i].dectab); + } + + for (int i = 0; i < 2; i++) { + renew_table3(512, &s->mv_model3[i].cntsum, + s->mv_model3[i].freqs[0], s->mv_model3[i].freqs[1], + s->mv_model3[i].cnts, s->mv_model3[i].dectab); + } + + for (int i = 0; i < 6; i++) { + renew_table3(6, &s->op_model3[i].cntsum, + s->op_model3[i].freqs[0], s->op_model3[i].freqs[1], + s->op_model3[i].cnts, s->op_model3[i].dectab); + } +} + +static int decode3(GetByteContext *gb, RangeCoder *rc, uint32_t a, uint32_t b) +{ + uint32_t code = a * (rc->code >> 12) + (rc->code & 0xFFF) - b; + + while (code < 0x800000 && bytestream2_get_bytes_left(gb) > 0) + code = bytestream2_get_byteu(gb) | (code << 8); + rc->code = code; + + return 0; +} + +static void rescale(PixelModel3 *m, int *totfr) +{ + uint32_t a; + + a = 256 - m->size; + for (int b = 0; b < m->size; b++) { + m->freqs[b] -= m->freqs[b] >> 1; + a += m->freqs[b]; + } + + *totfr = a; +} + +static int add_symbol(PixelModel3 *m, int index, uint32_t symbol, int *totfr, int max) +{ + if (m->size == max) + return 0; + + for (int c = m->size - 1; c >= index; c--) { + m->symbols[c + 1] = m->symbols[c]; + m->freqs[c + 1] = m->freqs[c]; + } + + m->symbols[index] = symbol; + m->freqs[index] = 50; + m->size++; + + if (m->maxpos >= index) + m->maxpos++; + + *totfr += 50; + if (*totfr + 50 > 4096) + rescale(m, totfr); + + return 1; +} + +static int decode_adaptive45(PixelModel3 *m, int rccode, uint32_t *value, + uint16_t *a, uint16_t *b, uint32_t *c, int max) +{ + uint32_t q, g, maxpos, d, e = *c, totfr = *c; + int ret; + + for (d = 0; e <= 2048; d++) + e <<= 1; + maxpos = m->maxpos; + rccode >>= d; + *c = m->freqs[maxpos]; + m->freqs[maxpos] += 4096 - e >> d; + + for (q = 0, g = 0, e = 0; q < m->size; q++) { + uint32_t f = m->symbols[q]; + uint32_t p = e + f - g; + uint32_t k = m->freqs[q]; + + if (rccode < p) { + *value = rccode - e + g; + *b = rccode << d; + *a = 1 << d; + m->freqs[maxpos] = *c; + ret = add_symbol(m, q, *value, &totfr, max); + *c = totfr; + return ret; + } + + if (p + k > rccode) { + *value = f; + e += *value - g; + *b = e << d; + *a = k << d; + m->freqs[maxpos] = *c; + m->freqs[q] += 50; + totfr += 50; + if ((q != maxpos) && (m->freqs[q] > m->freqs[maxpos])) + m->maxpos = q; + if (totfr + 50 > 4096) + rescale(m, &totfr); + *c = totfr; + return 1; + } + + e += f - g + k; + g = f + 1; + } + + m->freqs[maxpos] = *c; + *value = g + rccode - e; + *b = rccode << d; + *a = 1 << d; + ret = add_symbol(m, q, *value, &totfr, max); + *c = totfr; + return ret; +} + +static int update_model6_to_7(PixelModel3 *m) +{ + PixelModel3 n = {0}; + int c, d, e, f, k, p, length, i, j, index; + uint16_t *freqs, *freqs1, *cnts; + + n.type = 7; + + length = m->length; + freqs = n.freqs; + freqs1 = n.freqs1; + cnts = n.cnts; + n.cntsum = m->cnts[length]; + for (i = 0; i < length; i++) { + if (!m->cnts[i]) + continue; + index = m->symbols[i]; + freqs[index] = m->freqs[2 * i]; + freqs1[index] = m->freqs[2 * i + 1]; + cnts[index] = m->cnts[i]; + } + c = 1 << m->fshift; + d = c - (c >> 1); + for (j = 0, e = 0; j < 256; j++) { + f = freqs[j]; + if (!f) { + f = c; + freqs[j] = c; + freqs1[j] = e; + cnts[j] = d; + } + p = (e + 127) >> 7; + k = ((f + e - 1) >> 7) + 1; + for (i = 0; i < k - p; i++) + n.dectab[p + i] = j; + e += f; + } + + memcpy(m, &n, sizeof(n)); + + return 0; +} + +static void calc_sum(PixelModel3 *m) +{ + uint32_t a; + int len; + + len = m->length; + a = 256 - m->size << (m->fshift > 0 ? m->fshift - 1 : 0); + for (int c = 0; c < len; c++) + a += m->cnts[c]; + m->cnts[len] = a; +} + +static void rescale_dec(PixelModel3 *m) +{ + uint16_t cnts[256] = {0}; + uint16_t freqs[512] = {0}; + int b, c, e, g; + uint32_t a; + + for (a = 1 << (0 < m->fshift ? m->fshift - 1 : 0), b = 0; b < 256; b++) + cnts[b] = a; + + for (a = 0, b = m->size; a < b; a++) + cnts[m->symbols[a]] = m->cnts[a]; + + for (b = a = 0; b < 256; b++) { + freqs[2 * b] = cnts[b]; + freqs[2 * b + 1] = a; + a += cnts[b]; + } + + if (m->fshift > 0) + m->fshift--; + + a = 256 - m->size << (0 < m->fshift ? m->fshift - 1 : 0); + for (b = 0, c = m->size; b < c; b++) { + m->cnts[b] -= m->cnts[b] >> 1; + a = a + m->cnts[b]; + e = m->symbols[b]; + g = freqs[2 * e + 1]; + m->freqs[2 * b] = freqs[2 * e]; + m->freqs[2 * b + 1] = g; + } + m->cnts[m->length] = a; +} + +static int update_model5_to_6(PixelModel3 *m, uint8_t value) +{ + PixelModel3 n = {0}; + int c, d, e, f, g, k, q, p; + + n.type = 6; + n.length = 32; + + for (c = m->size, d = 256 - c, e = 0; e < c; e++) + d = d + m->freqs[e]; + + for (e = 0; d <= 2048; e++) + d <<= 1; + + for (q = d = 0, g = q = 0; g < c; g++) { + p = m->symbols[g]; + d = d + (p - q); + q = m->freqs[g]; + k = q << e; + n.freqs[2 * g] = k; + n.freqs[2 * g + 1] = d << e; + n.cnts[g] = k - (k >> 1); + n.symbols[g] = p; + d += q; + q = p + 1; + } + + n.fshift = e; + e = 1 << n.fshift; + d = 0; + if (value > 0) { + d = -1; + for (p = f = g = 0; p < c; p++) { + k = n.symbols[p]; + if (k > d && k < value) { + d = k; + g = n.freqs[2 * p]; + f = n.freqs[2 * p + 1]; + } + } + d = 0 < g ? f + g + (value - d - 1 << n.fshift) : value << n.fshift; + } + n.freqs[2 * c] = e; + n.freqs[2 * c + 1] = d; + n.cnts[c] = e - (e >> 1); + n.symbols[c] = value; + n.size = c + 1; + e = 25 << n.fshift; + n.cnts[c] += e; + n.cnts[32] += e; + if (n.cnts[32] + e > 4096) + rescale_dec(&n); + + calc_sum(&n); + for (c = 0, e = n.size - 1; c < e; c++) { + for (g = c + 1, f = n.size; g < f; g++) { + if (q = n.freqs[2 * g], k = n.freqs[2 * c], q > k) { + int l = n.freqs[2 * c + 1]; + int h = n.freqs[2 * g + 1]; + n.freqs[2 * c] = q; + n.freqs[2 * c + 1] = h; + n.freqs[2 * g] = k; + n.freqs[2 * g + 1] = l; + FFSWAP(uint16_t, n.cnts[c], n.cnts[g]); + FFSWAP(uint8_t, n.symbols[c], n.symbols[g]); + } + } + } + + memcpy(m, &n, sizeof(n)); + + return 0; +} + +static void grow_dec(PixelModel3 *m) +{ + int a; + + a = 2 * m->length; + m->cnts[2 * m->length] = m->cnts[m->length]; + m->length = a; +} + +static int add_dec(PixelModel3 *m, int sym, int f1, int f2) +{ + int size; + + if (m->size >= 40 || m->size >= m->length) + return -1; + + size = m->size; + m->symbols[size] = sym; + m->freqs[2 * size] = f1; + m->freqs[2 * size + 1] = f2; + m->cnts[size] = f1 - (f1 >> 1); + m->size++; + + return size; +} + +static void incr_cntdec(PixelModel3 *m, int a) +{ + int b, len, d, e, g; + + b = 25 << m->fshift; + len = m->length; + m->cnts[a] += b; + m->cnts[len] += b; + if (a > 0 && m->cnts[a] > m->cnts[a - 1]) { + FFSWAP(uint16_t, m->cnts[a], m->cnts[a - 1]); + d = m->freqs[2 * a]; + e = m->freqs[2 * a + 1]; + g = m->freqs[2 * (a - 1) + 1]; + m->freqs[2 * a] = m->freqs[2 * (a - 1)]; + m->freqs[2 * a + 1] = g; + g = a - 1; + m->freqs[2 * g] = d; + m->freqs[2 * g + 1] = e; + FFSWAP(uint8_t, m->symbols[a], m->symbols[a - 1]); + } + + if (m->cnts[len] + b > 4096) + rescale_dec(m); +} + +static int decode_adaptive6(PixelModel3 *m, uint32_t code, uint32_t *value, + uint16_t *a, uint16_t *b) +{ + int c, d, e, f, g, q; + + for (c = 0, d = 0, e = 0, f = 0, g = 0, q = m->size; g < q; g++) { + uint32_t p = m->freqs[2 * g + 1]; + + if (p <= code) { + uint32_t k = m->freqs[2 * g]; + + if (p + k > code) { + *value = m->symbols[g]; + *a = k; + *b = p; + incr_cntdec(m, g); + return 1; + } + + if (p >= d) { + c = k; + d = p; + e = m->symbols[g]; + } + } + } + + g = 1 << m->fshift; + q = f = 0; + + if (c > 0) { + f = code - (d + c) >> m->fshift; + q = f + e + 1; + f = d + c + (f << m->fshift); + } else { + q = code >> m->fshift; + f = q << m->fshift; + } + + *a = g; + *b = f; + *value = q; + + c = add_dec(m, q, g, f); + if (c < 0) { + if (m->length == 64) + return 0; + grow_dec(m); + c = add_dec(m, q, g, f); + } + + incr_cntdec(m, c); + return 1; +} + +static int cmpbytes(const void *p1, const void *p2) +{ + int left = *(const uint8_t *)p1; + int right = *(const uint8_t *)p2; + return FFDIFFSIGN(left, right); +} + +static int update_model1_to_2(PixelModel3 *m, uint32_t val) +{ + PixelModel3 n = {0}; + int i, b; + + n.type = 2; + n.size = m->size + 1; + b = m->size; + for (i = 0; i < b; i++) + n.symbols[i] = m->symbols[i]; + n.symbols[b] = val; + + memcpy(m, &n, sizeof(n)); + + return 0; +} + +static int update_model1_to_4(PixelModel3 *m, uint32_t val) +{ + PixelModel3 n = {0}; + int size, i; + + size = m->size; + n.type = 4; + n.size = size; + for (i = 0; i < n.size; i++) { + n.symbols[i] = m->symbols[i]; + } + AV_QSORT(n.symbols, size, uint8_t, cmpbytes); + for (i = 0; i < n.size; i++) { + if (val == n.symbols[i]) { + n.freqs[i] = 100; + n.maxpos = i; + } else { + n.freqs[i] = 50; + } + } + + memcpy(m, &n, sizeof(n)); + + return 0; +} + +static int update_model1_to_5(PixelModel3 *m, uint32_t val) +{ + PixelModel3 n = {0}; + int i, size, freqs; + uint32_t a; + + size = m->size; + n.size = size; + for (i = 0; i < size; i++) { + n.symbols[i] = m->symbols[i]; + } + AV_QSORT(n.symbols, size, uint8_t, cmpbytes); + size = n.size; + for (i = 0; i < size; i++) { + if (val == n.symbols[i]) { + n.freqs[i] = 100; + n.maxpos = i; + } else { + n.freqs[i] = 50; + } + } + a = 256 - size; + for (i = 0; i < size; i++, a += freqs) + freqs = n.freqs[i]; + n.type = 5; + n.cntsum = a; + + memcpy(m, &n, sizeof(n)); + + return 0; +} + +static int decode_static1(PixelModel3 *m, uint32_t val) +{ + uint32_t size; + + size = m->size; + for (int i = 0; i < size; i++) { + if (val == m->symbols[i]) { + if (size <= 4) + return update_model1_to_4(m, val); + else + return update_model1_to_5(m, val); + } + } + + if (size >= 14) + return update_model1_to_2(m, val); + + m->symbols[size] = val; + m->size++; + return 0; +} + +static int update_model2_to_6(PixelModel3 *m, uint8_t value, int a4) +{ + PixelModel3 n = {0}; + int c, d, e, f, g, q; + + n.type = 6; + n.length = a4; + + memset(n.symbols, 1u, a4); + + c = m->size; + d = 256 - c + (64 * c + 64); + for (e = 0; d <= 2048; e++) { + d <<= 1; + } + + g = q = 0; + AV_QSORT(m->symbols, c, uint8_t, cmpbytes); + for (f = d = 0; f < c; f++) { + int p = f; + int k = m->symbols[p]; + int l; + g = g + (k - q); + + if (k == value) { + d = p; + q = 128; + } else { + q = 64; + } + l = q << e; + n.freqs[2 * p] = l; + n.freqs[2 * p + 1] = g << e; + n.symbols[p] = k; + n.cnts[p] = l - (l >> 1); + g += q; + q = k + 1; + } + n.size = c; + n.fshift = e; + calc_sum(&n); + + if (d > 0) { + c = n.freqs[0]; + e = n.freqs[1]; + g = n.freqs[2 * d + 1]; + n.freqs[0] = n.freqs[2 * d]; + n.freqs[1] = g; + n.freqs[2 * d] = c; + n.freqs[2 * d + 1] = e; + FFSWAP(uint16_t, n.cnts[0], n.cnts[d]); + FFSWAP(uint8_t, n.symbols[0], n.symbols[d]); + } + + memcpy(m, &n, sizeof(n)); + + return 0; +} + +static int update_model2_to_3(PixelModel3 *m, uint32_t val) +{ + PixelModel3 n = {0}; + uint32_t size; + + n.type = 3; + n.size = m->size + 1; + + size = m->size; + for (int i = 0; i < size; i++) + n.symbols[i] = m->symbols[i]; + n.symbols[size] = val; + + memcpy(m, &n, sizeof(n)); + + return 0; +} + +static int decode_static2(PixelModel3 *m, uint32_t val) +{ + uint32_t size; + + size = m->size; + for (int i = 0; i < size; i++) { + if (val == m->symbols[i]) { + int a; + + if (m->size <= 32) + a = 32; + else + a = 64; + return update_model2_to_6(m, val, a); + } + } + + if (size >= 64) + return update_model2_to_3(m, val); + + m->symbols[size] = val; + m->size++; + + return 0; +} + +static int update_model3_to_7(PixelModel3 *m, uint8_t value) +{ + PixelModel3 n = {0}; + int c, d, e, f, g, q; + + n.type = 7; + + for (c = 0; c < 256; c++) { + d = c; + n.freqs[d] = 1; + n.cnts[d] = 1; + } + + for (c = m->size, d = (4096 - (256 - c)) / (c + 1) | 0, e = d - (d >> 1), g = 0; g < c;) { + q = g++; + q = m->symbols[q]; + n.freqs[q] = d; + n.cnts[q] = e; + } + n.freqs[value] += d; + n.cnts[value] += 16; + for (d = c = n.cntsum = 0; 256 > d; d++) { + e = d; + n.cntsum += n.cnts[e]; + n.freqs1[e] = c; + for (g = n.freqs[e], q = c + 128 - 1 >> 7, f = (c + g - 1 >> 7) + 1; q < f; q++) { + n.dectab[q] = e; + } + c += g; + } + + memcpy(m, &n, sizeof(n)); + + return 0; +} + +static int decode_static3(PixelModel3 *m, uint32_t val) +{ + uint32_t size = m->size; + + for (int i = 0; i < size; i++) { + if (val == m->symbols[i]) + return update_model3_to_7(m, val); + } + + if (size >= 256) + return 0; + + m->symbols[size] = val; + m->size++; + return 0; +} + +static void sync_code3(GetByteContext *gb, RangeCoder *rc) +{ + rc->code1++; + if (rc->code1 == 0x20000) { + rc->code = bytestream2_get_le32(gb); + rc->code1 = 0; + } +} + +static int decode_value3(SCPRContext *s, uint32_t max, uint32_t *cntsum, + uint16_t *freqs1, uint16_t *freqs2, + uint16_t *cnts, uint8_t *dectable, + uint32_t *value) +{ + GetByteContext *gb = &s->gb; + RangeCoder *rc = &s->rc; + uint32_t r, y, a, b, e, g, q; + + r = dectable[(rc->code & 0xFFFu) >> 7]; + if (r < max) { + while (freqs2[r + 1] <= (rc->code & 0xFFF)) { + if (++r >= max) + break; + } + } + + if (r > max) + return AVERROR_INVALIDDATA; + + cnts[r] += 16; + a = freqs1[r]; + b = freqs2[r]; + *cntsum += 16; + if (*cntsum + 16 > 4096) { + *cntsum = 0; + for (int c = 0, i = 0; i < max + 1; i++) { + e = cnts[i]; + freqs2[i] = c; + freqs1[i] = e; + g = (c + 127) >> 7; + c += e; + q = ((c - 1) >> 7) + 1; + if (q > g) { + for (int j = 0; j < q - g; j++) + dectable[j + g] = i; + } + y = e - (e >> 1); + cnts[i] = y; + *cntsum += y; + } + } + + decode3(gb, rc, a, b); + sync_code3(gb, rc); + + *value = r; + + return 0; +} + +static void calc_sum5(PixelModel3 *m) +{ + uint32_t a; + + a = 256 - m->size; + for (int b = 0; b < m->size; b++) + a += m->freqs[b]; + m->cntsum = a; +} + +static int update_model4_to_5(PixelModel3 *m, uint32_t value) +{ + PixelModel3 n = {0}; + int c, e, g, totfr; + + n.type = 5; + + for (c = 0, e = 0; c < m->size && m->symbols[c] < value; c++) { + n.symbols[c] = m->symbols[c]; + e += n.freqs[c] = m->freqs[c]; + } + + g = c; + n.symbols[g] = value; + e += n.freqs[g++] = 50; + for (; c < m->size; g++, c++) { + n.symbols[g] = m->symbols[c]; + e += n.freqs[g] = m->freqs[c]; + } + n.size = m->size + 1; + if (e > 4096) + rescale(&n, &totfr); + + calc_sum5(&n); + + memcpy(m, &n, sizeof(n)); + + return 0; +} + +static int decode_unit3(SCPRContext *s, PixelModel3 *m, uint32_t code, uint32_t *value) +{ + GetByteContext *gb = &s->gb; + RangeCoder *rc = &s->rc; + uint16_t a = 0, b = 0; + uint32_t param; + int type; + + type = m->type; + switch (type) { + case 0: + *value = bytestream2_get_byte(&s->gb); + m->type = 1; + m->size = 1; + m->symbols[0] = *value; + sync_code3(gb, rc); + break; + case 1: + *value = bytestream2_get_byte(&s->gb); + decode_static1(m, *value); + sync_code3(gb, rc); + break; + case 2: + *value = bytestream2_get_byte(&s->gb); + decode_static2(m, *value); + sync_code3(gb, rc); + break; + case 3: + *value = bytestream2_get_byte(&s->gb); + decode_static3(m, *value); + sync_code3(gb, rc); + break; + case 4: + param = m->freqs[0] + m->freqs[1] + m->freqs[2] + m->freqs[3] + 256 - m->size; + if (!decode_adaptive45(m, code, value, &a, &b, ¶m, 4)) + update_model4_to_5(m, *value); + decode3(gb, rc, a, b); + sync_code3(gb, rc); + break; + case 5: + if (!decode_adaptive45(m, code, value, &a, &b, &m->cntsum, 16)) + update_model5_to_6(m, *value); + decode3(gb, rc, a, b); + sync_code3(gb, rc); + break; + case 6: + if (!decode_adaptive6(m, code, value, &a, &b)) { + update_model6_to_7(m); + } + decode3(gb, rc, a, b); + sync_code3(gb, rc); + break; + case 7: + return decode_value3(s, 255, &m->cntsum, + m->freqs, m->freqs1, + m->cnts, m->dectab, value); + } + + if (*value > 255) + return AVERROR_INVALIDDATA; + + return 0; +} + +static int decode_units3(SCPRContext * s, uint32_t *red, + uint32_t *green, uint32_t *blue, + int *cx, int *cx1) +{ + RangeCoder *rc = &s->rc; + int ret; + + ret = decode_unit3(s, &s->pixel_model3[0][*cx + *cx1], rc->code & 0xFFF, red); + if (ret < 0) + return ret; + + *cx1 = (*cx << 6) & 0xFC0; + *cx = *red >> 2; + + ret = decode_unit3(s, &s->pixel_model3[1][*cx + *cx1], rc->code & 0xFFF, green); + if (ret < 0) + return ret; + + *cx1 = (*cx << 6) & 0xFC0; + *cx = *green >> 2; + + ret = decode_unit3(s, &s->pixel_model3[2][*cx + *cx1], rc->code & 0xFFF, blue); + if (ret < 0) + return ret; + + *cx1 = (*cx << 6) & 0xFC0; + *cx = *blue >> 2; + + return 0; +} + +static void init_rangecoder3(RangeCoder *rc, GetByteContext *gb) +{ + rc->code = bytestream2_get_le32(gb); + rc->code1 = 0; +} + +static int decompress_i3(AVCodecContext *avctx, uint32_t *dst, int linesize) +{ + SCPRContext *s = avctx->priv_data; + GetByteContext *gb = &s->gb; + RangeCoder *rc = &s->rc; + int cx = 0, cx1 = 0, k = 0; + int run, off, y = 0, x = 0, ret; + uint32_t backstep = linesize - avctx->width; + uint32_t clr = 0, lx, ly, ptype, r, g, b; + + bytestream2_skip(gb, 1); + init_rangecoder3(rc, gb); + reinit_tables3(s); + + while (k < avctx->width + 1) { + ret = decode_units3(s, &r, &g, &b, &cx, &cx1); + if (ret < 0) + return ret; + ret = decode_value3(s, 255, &s->run_model3[0].cntsum, + s->run_model3[0].freqs[0], + s->run_model3[0].freqs[1], + s->run_model3[0].cnts, + s->run_model3[0].dectab, &run); + if (ret < 0) + return ret; + if (run <= 0) + return AVERROR_INVALIDDATA; + + clr = (b << 16) + (g << 8) + r; + k += run; + while (run-- > 0) { + if (y >= avctx->height) + return AVERROR_INVALIDDATA; + + dst[y * linesize + x] = clr; + lx = x; + ly = y; + x++; + if (x >= avctx->width) { + x = 0; + y++; + } + } + } + off = -linesize - 1; + ptype = 0; + + while (x < avctx->width && y < avctx->height) { + ret = decode_value3(s, 5, &s->op_model3[ptype].cntsum, + s->op_model3[ptype].freqs[0], + s->op_model3[ptype].freqs[1], + s->op_model3[ptype].cnts, + s->op_model3[ptype].dectab, &ptype); + if (ret < 0) + return ret; + if (ptype == 0) { + ret = decode_units3(s, &r, &g, &b, &cx, &cx1); + if (ret < 0) + return ret; + clr = (b << 16) + (g << 8) + r; + } + if (ptype > 5) + return AVERROR_INVALIDDATA; + ret = decode_value3(s, 255, &s->run_model3[ptype].cntsum, + s->run_model3[ptype].freqs[0], + s->run_model3[ptype].freqs[1], + s->run_model3[ptype].cnts, + s->run_model3[ptype].dectab, &run); + if (ret < 0) + return ret; + if (run <= 0) + return AVERROR_INVALIDDATA; + + ret = decode_run_i(avctx, ptype, run, &x, &y, clr, + dst, linesize, &lx, &ly, + backstep, off, &cx, &cx1); + if (ret < 0) + return ret; + } + + return 0; +} + +static int decompress_p3(AVCodecContext *avctx, + uint32_t *dst, int linesize, + uint32_t *prev, int plinesize) +{ + SCPRContext *s = avctx->priv_data; + GetByteContext *gb = &s->gb; + int ret, temp, min, max, x, y, cx = 0, cx1 = 0; + int backstep = linesize - avctx->width; + int mvx = 0, mvy = 0; + + if (bytestream2_get_byte(gb) == 0) + return 1; + init_rangecoder3(&s->rc, gb); + + ret = decode_value3(s, 255, &s->range_model3.cntsum, + s->range_model3.freqs[0], + s->range_model3.freqs[1], + s->range_model3.cnts, + s->range_model3.dectab, &min); + ret |= decode_value3(s, 255, &s->range_model3.cntsum, + s->range_model3.freqs[0], + s->range_model3.freqs[1], + s->range_model3.cnts, + s->range_model3.dectab, &temp); + if (ret < 0) + return ret; + + min += temp << 8; + ret |= decode_value3(s, 255, &s->range_model3.cntsum, + s->range_model3.freqs[0], + s->range_model3.freqs[1], + s->range_model3.cnts, + s->range_model3.dectab, &max); + ret |= decode_value3(s, 255, &s->range_model3.cntsum, + s->range_model3.freqs[0], + s->range_model3.freqs[1], + s->range_model3.cnts, + s->range_model3.dectab, &temp); + if (ret < 0) + return ret; + + max += temp << 8; + if (min > max || min >= s->nbcount) + return AVERROR_INVALIDDATA; + + memset(s->blocks, 0, sizeof(*s->blocks) * s->nbcount); + + while (min <= max) { + int fill, count; + + ret = decode_value3(s, 4, &s->fill_model3.cntsum, + s->fill_model3.freqs[0], + s->fill_model3.freqs[1], + s->fill_model3.cnts, + s->fill_model3.dectab, &fill); + ret |= decode_value3(s, 255, &s->count_model3.cntsum, + s->count_model3.freqs[0], + s->count_model3.freqs[1], + s->count_model3.cnts, + s->count_model3.dectab, &count); + if (ret < 0) + return ret; + if (count <= 0) + return AVERROR_INVALIDDATA; + + while (min < s->nbcount && count-- > 0) { + s->blocks[min++] = fill; + } + } + + ret = av_frame_copy(s->current_frame, s->last_frame); + if (ret < 0) + return ret; + + for (y = 0; y < s->nby; y++) { + for (x = 0; x < s->nbx; x++) { + int sy1 = 0, sy2 = 16, sx1 = 0, sx2 = 16; + + if (s->blocks[y * s->nbx + x] == 0) + continue; + + if (((s->blocks[y * s->nbx + x] + 1) & 1) > 0) { + ret = decode_value3(s, 15, &s->sxy_model3[0].cntsum, + s->sxy_model3[0].freqs[0], + s->sxy_model3[0].freqs[1], + s->sxy_model3[0].cnts, + s->sxy_model3[0].dectab, &sx1); + ret |= decode_value3(s, 15, &s->sxy_model3[1].cntsum, + s->sxy_model3[1].freqs[0], + s->sxy_model3[1].freqs[1], + s->sxy_model3[1].cnts, + s->sxy_model3[1].dectab, &sy1); + ret |= decode_value3(s, 15, &s->sxy_model3[2].cntsum, + s->sxy_model3[2].freqs[0], + s->sxy_model3[2].freqs[1], + s->sxy_model3[2].cnts, + s->sxy_model3[2].dectab, &sx2); + ret |= decode_value3(s, 15, &s->sxy_model3[3].cntsum, + s->sxy_model3[3].freqs[0], + s->sxy_model3[3].freqs[1], + s->sxy_model3[3].cnts, + s->sxy_model3[3].dectab, &sy2); + if (ret < 0) + return ret; + + sx2++; + sy2++; + } + if (((s->blocks[y * s->nbx + x] + 3) & 2) > 0) { + int i, a, b, c, j, by = y * 16, bx = x * 16; + uint32_t code; + + a = s->rc.code & 0xFFF; + c = 1; + + if (a < 0x800) + c = 0; + b = 2048; + if (!c) + b = 0; + + code = a + ((s->rc.code >> 1) & 0xFFFFF800) - b; + while (code < 0x800000 && bytestream2_get_bytes_left(gb) > 0) + code = bytestream2_get_byteu(gb) | (code << 8); + s->rc.code = code; + + sync_code3(gb, &s->rc); + + if (!c) { + ret = decode_value3(s, 511, &s->mv_model3[0].cntsum, + s->mv_model3[0].freqs[0], + s->mv_model3[0].freqs[1], + s->mv_model3[0].cnts, + s->mv_model3[0].dectab, &mvx); + ret |= decode_value3(s, 511, &s->mv_model3[1].cntsum, + s->mv_model3[1].freqs[0], + s->mv_model3[1].freqs[1], + s->mv_model3[1].cnts, + s->mv_model3[1].dectab, &mvy); + if (ret < 0) + return ret; + + mvx -= 256; + mvy -= 256; + } + + if (by + mvy + sy1 < 0 || bx + mvx + sx1 < 0 || + by + mvy + sy1 >= avctx->height || bx + mvx + sx1 >= avctx->width) + return AVERROR_INVALIDDATA; + + for (i = 0; i < sy2 - sy1 && (by + sy1 + i) < avctx->height && (by + mvy + sy1 + i) < avctx->height; i++) { + for (j = 0; j < sx2 - sx1 && (bx + sx1 + j) < avctx->width && (bx + mvx + sx1 + j) < avctx->width; j++) { + dst[(by + i + sy1) * linesize + bx + sx1 + j] = prev[(by + mvy + sy1 + i) * plinesize + bx + sx1 + mvx + j]; + } + } + } else { + int run, bx = x * 16 + sx1, by = y * 16 + sy1; + uint32_t clr, ptype = 0, r, g, b; + + for (; by < y * 16 + sy2 && by < avctx->height;) { + ret = decode_value3(s, 5, &s->op_model3[ptype].cntsum, + s->op_model3[ptype].freqs[0], + s->op_model3[ptype].freqs[1], + s->op_model3[ptype].cnts, + s->op_model3[ptype].dectab, &ptype); + if (ret < 0) + return ret; + if (ptype == 0) { + ret = decode_units3(s, &r, &g, &b, &cx, &cx1); + if (ret < 0) + return ret; + + clr = (b << 16) + (g << 8) + r; + } + if (ptype > 5) + return AVERROR_INVALIDDATA; + ret = decode_value3(s, 255, &s->run_model3[ptype].cntsum, + s->run_model3[ptype].freqs[0], + s->run_model3[ptype].freqs[1], + s->run_model3[ptype].cnts, + s->run_model3[ptype].dectab, &run); + if (ret < 0) + return ret; + if (run <= 0) + return AVERROR_INVALIDDATA; + + ret = decode_run_p(avctx, ptype, run, x, y, clr, + dst, prev, linesize, plinesize, &bx, &by, + backstep, sx1, sx2, &cx, &cx1); + if (ret < 0) + return ret; + } + } + } + } + + return 0; +} diff --git a/libavcodec/scpr3.h b/libavcodec/scpr3.h new file mode 100644 index 000000000..92ad96888 --- /dev/null +++ b/libavcodec/scpr3.h @@ -0,0 +1,82 @@ +/* + * ScreenPressor version 3 decoder + * + * Copyright (c) 2017 Paul B Mahol + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_SCPR3_H +#define AVCODEC_SCPR3_H + +#include +#include +#include + +#include "avcodec.h" +#include "internal.h" + +typedef struct PixelModel3 { + uint8_t type; + uint8_t length; + uint8_t maxpos; + uint8_t fshift; + uint16_t size; + uint32_t cntsum; + uint8_t symbols[256]; + uint16_t freqs[256]; + uint16_t freqs1[256]; + uint16_t cnts[256]; + uint8_t dectab[32]; +} PixelModel3; + +typedef struct FillModel3 { + uint32_t cntsum; + uint16_t freqs[2][5]; + uint16_t cnts[5]; + uint8_t dectab[32]; +} FillModel3; + +typedef struct OpModel3 { + uint32_t cntsum; + uint16_t freqs[2][6]; + uint16_t cnts[6]; + uint8_t dectab[32]; +} OpModel3; + +typedef struct RunModel3 { + uint32_t cntsum; + uint16_t freqs[2][256]; + uint16_t cnts[256]; + uint8_t dectab[32]; +} RunModel3; + +typedef struct SxyModel3 { + uint32_t cntsum; + uint16_t freqs[2][16]; + uint16_t cnts[16]; + uint8_t dectab[32]; +} SxyModel3; + +typedef struct MVModel3 { + uint32_t cntsum; + uint16_t freqs[2][512]; + uint16_t cnts[512]; + uint8_t dectab[32]; +} MVModel3; + +#endif /* AVCODEC_SCPR3_H */ diff --git a/libavcodec/simple_idct.c b/libavcodec/simple_idct.c index 78b29c0fe..3b2e73653 100644 --- a/libavcodec/simple_idct.c +++ b/libavcodec/simple_idct.c @@ -236,7 +236,7 @@ void ff_simple_idct44_add(uint8_t *dest, ptrdiff_t line_size, int16_t *block) } } -void ff_prores_idct(int16_t *block, const int16_t *qmat) +void ff_prores_idct_10(int16_t *block, const int16_t *qmat) { int i; @@ -251,3 +251,19 @@ void ff_prores_idct(int16_t *block, const int16_t *qmat) idctSparseCol_extrashift_10(block + i); } } + +void ff_prores_idct_12(int16_t *block, const int16_t *qmat) +{ + int i; + + for (i = 0; i < 64; i++) + block[i] *= qmat[i]; + + for (i = 0; i < 8; i++) + idctRowCondDC_int16_12bit(block + i*8, 0); + + for (i = 0; i < 8; i++) { + block[i] += 8192; + idctSparseCol_int16_12bit(block + i); + } +} diff --git a/libavcodec/simple_idct.h b/libavcodec/simple_idct.h index 39df2308c..20578b334 100644 --- a/libavcodec/simple_idct.h +++ b/libavcodec/simple_idct.h @@ -52,7 +52,8 @@ void ff_simple_idct_int16_12bit(int16_t *block); * and scales by a factor of 2 more between the two IDCTs to account * for larger scale of input coefficients. */ -void ff_prores_idct(int16_t *block, const int16_t *qmat); +void ff_prores_idct_10(int16_t *block, const int16_t *qmat); +void ff_prores_idct_12(int16_t *block, const int16_t *qmat); void ff_simple_idct248_put(uint8_t *dest, ptrdiff_t line_size, int16_t *block); diff --git a/libavcodec/simple_idct_template.c b/libavcodec/simple_idct_template.c index 904263fc7..d8fcfd7c5 100644 --- a/libavcodec/simple_idct_template.c +++ b/libavcodec/simple_idct_template.c @@ -101,8 +101,8 @@ #define DC_SHIFT -1 # endif -#define MUL(a, b) ((a) * (b)) -#define MAC(a, b, c) ((a) += (b) * (c)) +#define MUL(a, b) ((int)((SUINT)(a) * (b))) +#define MAC(a, b, c) ((a) += (SUINT)(b) * (c)) #else @@ -156,15 +156,15 @@ static inline void FUNC6(idctRowCondDC)(idctin *row, int extra_shift) #endif #endif - a0 = (W4 * row[0]) + (1 << (ROW_SHIFT + extra_shift - 1)); + a0 = ((SUINT)W4 * row[0]) + (1 << (ROW_SHIFT + extra_shift - 1)); a1 = a0; a2 = a0; a3 = a0; - a0 += W2 * row[2]; - a1 += W6 * row[2]; - a2 -= W6 * row[2]; - a3 -= W2 * row[2]; + a0 += (SUINT)W2 * row[2]; + a1 += (SUINT)W6 * row[2]; + a2 -= (SUINT)W6 * row[2]; + a3 -= (SUINT)W2 * row[2]; b0 = MUL(W1, row[1]); MAC(b0, W3, row[3]); @@ -180,10 +180,10 @@ static inline void FUNC6(idctRowCondDC)(idctin *row, int extra_shift) #else if (AV_RN64A(row + 4)) { #endif - a0 += W4*row[4] + W6*row[6]; - a1 += - W4*row[4] - W2*row[6]; - a2 += - W4*row[4] + W2*row[6]; - a3 += W4*row[4] - W6*row[6]; + a0 += (SUINT) W4*row[4] + (SUINT)W6*row[6]; + a1 += (SUINT)- W4*row[4] - (SUINT)W2*row[6]; + a2 += (SUINT)- W4*row[4] + (SUINT)W2*row[6]; + a3 += (SUINT) W4*row[4] - (SUINT)W6*row[6]; MAC(b0, W5, row[5]); MAC(b0, W7, row[7]); @@ -209,15 +209,15 @@ static inline void FUNC6(idctRowCondDC)(idctin *row, int extra_shift) } #define IDCT_COLS do { \ - a0 = W4 * (col[8*0] + ((1<<(COL_SHIFT-1))/W4)); \ + a0 = (SUINT)W4 * (col[8*0] + ((1<<(COL_SHIFT-1))/W4)); \ a1 = a0; \ a2 = a0; \ a3 = a0; \ \ - a0 += W2*col[8*2]; \ - a1 += W6*col[8*2]; \ - a2 += -W6*col[8*2]; \ - a3 += -W2*col[8*2]; \ + a0 += (SUINT) W2*col[8*2]; \ + a1 += (SUINT) W6*col[8*2]; \ + a2 += (SUINT)-W6*col[8*2]; \ + a3 += (SUINT)-W2*col[8*2]; \ \ b0 = MUL(W1, col[8*1]); \ b1 = MUL(W3, col[8*1]); \ @@ -230,10 +230,10 @@ static inline void FUNC6(idctRowCondDC)(idctin *row, int extra_shift) MAC(b3, -W5, col[8*3]); \ \ if (col[8*4]) { \ - a0 += W4*col[8*4]; \ - a1 += -W4*col[8*4]; \ - a2 += -W4*col[8*4]; \ - a3 += W4*col[8*4]; \ + a0 += (SUINT) W4*col[8*4]; \ + a1 += (SUINT)-W4*col[8*4]; \ + a2 += (SUINT)-W4*col[8*4]; \ + a3 += (SUINT) W4*col[8*4]; \ } \ \ if (col[8*5]) { \ @@ -244,10 +244,10 @@ static inline void FUNC6(idctRowCondDC)(idctin *row, int extra_shift) } \ \ if (col[8*6]) { \ - a0 += W6*col[8*6]; \ - a1 += -W2*col[8*6]; \ - a2 += W2*col[8*6]; \ - a3 += -W6*col[8*6]; \ + a0 += (SUINT) W6*col[8*6]; \ + a1 += (SUINT)-W2*col[8*6]; \ + a2 += (SUINT) W2*col[8*6]; \ + a3 += (SUINT)-W6*col[8*6]; \ } \ \ if (col[8*7]) { \ @@ -288,42 +288,42 @@ static inline void FUNC6(idctSparseColPut)(pixel *dest, ptrdiff_t line_size, static inline void FUNC6(idctSparseColAdd)(pixel *dest, ptrdiff_t line_size, idctin *col) { - int a0, a1, a2, a3, b0, b1, b2, b3; + unsigned a0, a1, a2, a3, b0, b1, b2, b3; IDCT_COLS; - dest[0] = av_clip_pixel(dest[0] + ((a0 + b0) >> COL_SHIFT)); + dest[0] = av_clip_pixel(dest[0] + ((int)(a0 + b0) >> COL_SHIFT)); dest += line_size; - dest[0] = av_clip_pixel(dest[0] + ((a1 + b1) >> COL_SHIFT)); + dest[0] = av_clip_pixel(dest[0] + ((int)(a1 + b1) >> COL_SHIFT)); dest += line_size; - dest[0] = av_clip_pixel(dest[0] + ((a2 + b2) >> COL_SHIFT)); + dest[0] = av_clip_pixel(dest[0] + ((int)(a2 + b2) >> COL_SHIFT)); dest += line_size; - dest[0] = av_clip_pixel(dest[0] + ((a3 + b3) >> COL_SHIFT)); + dest[0] = av_clip_pixel(dest[0] + ((int)(a3 + b3) >> COL_SHIFT)); dest += line_size; - dest[0] = av_clip_pixel(dest[0] + ((a3 - b3) >> COL_SHIFT)); + dest[0] = av_clip_pixel(dest[0] + ((int)(a3 - b3) >> COL_SHIFT)); dest += line_size; - dest[0] = av_clip_pixel(dest[0] + ((a2 - b2) >> COL_SHIFT)); + dest[0] = av_clip_pixel(dest[0] + ((int)(a2 - b2) >> COL_SHIFT)); dest += line_size; - dest[0] = av_clip_pixel(dest[0] + ((a1 - b1) >> COL_SHIFT)); + dest[0] = av_clip_pixel(dest[0] + ((int)(a1 - b1) >> COL_SHIFT)); dest += line_size; - dest[0] = av_clip_pixel(dest[0] + ((a0 - b0) >> COL_SHIFT)); + dest[0] = av_clip_pixel(dest[0] + ((int)(a0 - b0) >> COL_SHIFT)); } static inline void FUNC6(idctSparseCol)(idctin *col) #endif { - int a0, a1, a2, a3, b0, b1, b2, b3; + unsigned a0, a1, a2, a3, b0, b1, b2, b3; IDCT_COLS; - col[0 ] = ((a0 + b0) >> COL_SHIFT); - col[8 ] = ((a1 + b1) >> COL_SHIFT); - col[16] = ((a2 + b2) >> COL_SHIFT); - col[24] = ((a3 + b3) >> COL_SHIFT); - col[32] = ((a3 - b3) >> COL_SHIFT); - col[40] = ((a2 - b2) >> COL_SHIFT); - col[48] = ((a1 - b1) >> COL_SHIFT); - col[56] = ((a0 - b0) >> COL_SHIFT); + col[0 ] = ((int)(a0 + b0) >> COL_SHIFT); + col[8 ] = ((int)(a1 + b1) >> COL_SHIFT); + col[16] = ((int)(a2 + b2) >> COL_SHIFT); + col[24] = ((int)(a3 + b3) >> COL_SHIFT); + col[32] = ((int)(a3 - b3) >> COL_SHIFT); + col[40] = ((int)(a2 - b2) >> COL_SHIFT); + col[48] = ((int)(a1 - b1) >> COL_SHIFT); + col[56] = ((int)(a0 - b0) >> COL_SHIFT); } #ifndef EXTRA_SHIFT diff --git a/libavcodec/sinewin.h b/libavcodec/sinewin.h index 6b97a7185..329e9bb5b 100644 --- a/libavcodec/sinewin.h +++ b/libavcodec/sinewin.h @@ -38,6 +38,9 @@ #define SINETABLE(size) \ SINETABLE_CONST DECLARE_ALIGNED(32, INTFLOAT, AAC_RENAME(ff_sine_##size))[size] +#define SINETABLE120960(size) \ + DECLARE_ALIGNED(32, INTFLOAT, AAC_RENAME(ff_sine_##size))[size] + /** * Generate a sine window. * @param window pointer to half window @@ -52,11 +55,11 @@ void AAC_RENAME(ff_init_ff_sine_windows)(int index); extern SINETABLE( 32); extern SINETABLE( 64); -extern SINETABLE( 120); +extern SINETABLE120960(120); extern SINETABLE( 128); extern SINETABLE( 256); extern SINETABLE( 512); -extern SINETABLE( 960); +extern SINETABLE120960(960); extern SINETABLE(1024); extern SINETABLE(2048); extern SINETABLE(4096); diff --git a/libavcodec/sinewin_tablegen.h b/libavcodec/sinewin_tablegen.h index 0fa3561ab..dc52234ed 100644 --- a/libavcodec/sinewin_tablegen.h +++ b/libavcodec/sinewin_tablegen.h @@ -32,8 +32,8 @@ #include "libavutil/common.h" #if !USE_FIXED -SINETABLE( 120); -SINETABLE( 960); +SINETABLE120960(120); +SINETABLE120960(960); #endif #if !CONFIG_HARDCODED_TABLES SINETABLE( 32); diff --git a/libavcodec/sinewin_tablegen_template.c b/libavcodec/sinewin_tablegen_template.c index 43ce1ba82..b8eb407bd 100644 --- a/libavcodec/sinewin_tablegen_template.c +++ b/libavcodec/sinewin_tablegen_template.c @@ -33,6 +33,8 @@ #define SINETABLE_CONST #define SINETABLE(size) \ INTFLOAT AAC_RENAME(ff_sine_##size)[size] +#define SINETABLE120960(size) \ + INTFLOAT AAC_RENAME(ff_sine_##size)[size] #define FF_ARRAY_ELEMS(a) (sizeof(a) / sizeof((a)[0])) #include "sinewin_tablegen.h" #include "tableprint.h" diff --git a/libavcodec/snowenc.c b/libavcodec/snowenc.c index 61a658fa4..df1729a08 100644 --- a/libavcodec/snowenc.c +++ b/libavcodec/snowenc.c @@ -1899,7 +1899,7 @@ FF_DISABLE_DEPRECATION_WARNINGS FF_ENABLE_DEPRECATION_WARNINGS #endif - pkt->size = ff_rac_terminate(c); + pkt->size = ff_rac_terminate(c, 0); if (s->current_picture->key_frame) pkt->flags |= AV_PKT_FLAG_KEY; *got_packet = 1; diff --git a/libavcodec/sonic.c b/libavcodec/sonic.c index 2e3ca79fd..34d2952e6 100644 --- a/libavcodec/sonic.c +++ b/libavcodec/sonic.c @@ -842,7 +842,7 @@ static int sonic_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, // av_log(avctx, AV_LOG_DEBUG, "used bytes: %d\n", (put_bits_count(&pb)+7)/8); - avpkt->size = ff_rac_terminate(&c); + avpkt->size = ff_rac_terminate(&c, 0); *got_packet_ptr = 1; return 0; diff --git a/libavcodec/speedhq.c b/libavcodec/speedhq.c index 6d3487ca1..890b8253c 100644 --- a/libavcodec/speedhq.c +++ b/libavcodec/speedhq.c @@ -58,40 +58,40 @@ typedef struct SHQContext { /* AC codes: Very similar but not identical to MPEG-2. */ -static uint16_t speedhq_vlc[123][2] = { - {0x02, 2}, {0x06, 3}, {0x07, 4}, {0x1c, 5}, - {0x1d, 5}, {0x05, 6}, {0x04, 6}, {0x7b, 7}, - {0x7c, 7}, {0x23, 8}, {0x22, 8}, {0xfa, 8}, - {0xfb, 8}, {0xfe, 8}, {0xff, 8}, {0x1f,14}, - {0x1e,14}, {0x1d,14}, {0x1c,14}, {0x1b,14}, - {0x1a,14}, {0x19,14}, {0x18,14}, {0x17,14}, - {0x16,14}, {0x15,14}, {0x14,14}, {0x13,14}, - {0x12,14}, {0x11,14}, {0x10,14}, {0x18,15}, - {0x17,15}, {0x16,15}, {0x15,15}, {0x14,15}, - {0x13,15}, {0x12,15}, {0x11,15}, {0x10,15}, - {0x02, 3}, {0x06, 5}, {0x79, 7}, {0x27, 8}, - {0x20, 8}, {0x16,13}, {0x15,13}, {0x1f,15}, - {0x1e,15}, {0x1d,15}, {0x1c,15}, {0x1b,15}, - {0x1a,15}, {0x19,15}, {0x13,16}, {0x12,16}, - {0x11,16}, {0x10,16}, {0x18,13}, {0x17,13}, - {0x05, 5}, {0x07, 7}, {0xfc, 8}, {0x0c,10}, - {0x14,13}, {0x18,12}, {0x14,12}, {0x13,12}, - {0x10,12}, {0x1a,13}, {0x19,13}, {0x07, 5}, - {0x26, 8}, {0x1c,12}, {0x13,13}, {0x1b,12}, - {0x06, 6}, {0xfd, 8}, {0x12,12}, {0x1d,12}, - {0x07, 6}, {0x04, 9}, {0x12,13}, {0x06, 7}, - {0x1e,12}, {0x14,16}, {0x04, 7}, {0x15,12}, - {0x05, 7}, {0x11,12}, {0x78, 7}, {0x11,13}, - {0x7a, 7}, {0x10,13}, {0x21, 8}, {0x1a,16}, - {0x25, 8}, {0x19,16}, {0x24, 8}, {0x18,16}, - {0x05, 9}, {0x17,16}, {0x07, 9}, {0x16,16}, - {0x0d,10}, {0x15,16}, {0x1f,12}, {0x1a,12}, - {0x19,12}, {0x17,12}, {0x16,12}, {0x1f,13}, - {0x1e,13}, {0x1d,13}, {0x1c,13}, {0x1b,13}, - {0x1f,16}, {0x1e,16}, {0x1d,16}, {0x1c,16}, - {0x1b,16}, - {0x01,6}, /* escape */ - {0x06,4}, /* EOB */ +static const uint16_t speedhq_vlc[123][2] = { + {0x0001, 2}, {0x0003, 3}, {0x000E, 4}, {0x0007, 5}, + {0x0017, 5}, {0x0028, 6}, {0x0008, 6}, {0x006F, 7}, + {0x001F, 7}, {0x00C4, 8}, {0x0044, 8}, {0x005F, 8}, + {0x00DF, 8}, {0x007F, 8}, {0x00FF, 8}, {0x3E00, 14}, + {0x1E00, 14}, {0x2E00, 14}, {0x0E00, 14}, {0x3600, 14}, + {0x1600, 14}, {0x2600, 14}, {0x0600, 14}, {0x3A00, 14}, + {0x1A00, 14}, {0x2A00, 14}, {0x0A00, 14}, {0x3200, 14}, + {0x1200, 14}, {0x2200, 14}, {0x0200, 14}, {0x0C00, 15}, + {0x7400, 15}, {0x3400, 15}, {0x5400, 15}, {0x1400, 15}, + {0x6400, 15}, {0x2400, 15}, {0x4400, 15}, {0x0400, 15}, + {0x0002, 3}, {0x000C, 5}, {0x004F, 7}, {0x00E4, 8}, + {0x0004, 8}, {0x0D00, 13}, {0x1500, 13}, {0x7C00, 15}, + {0x3C00, 15}, {0x5C00, 15}, {0x1C00, 15}, {0x6C00, 15}, + {0x2C00, 15}, {0x4C00, 15}, {0xC800, 16}, {0x4800, 16}, + {0x8800, 16}, {0x0800, 16}, {0x0300, 13}, {0x1D00, 13}, + {0x0014, 5}, {0x0070, 7}, {0x003F, 8}, {0x00C0, 10}, + {0x0500, 13}, {0x0180, 12}, {0x0280, 12}, {0x0C80, 12}, + {0x0080, 12}, {0x0B00, 13}, {0x1300, 13}, {0x001C, 5}, + {0x0064, 8}, {0x0380, 12}, {0x1900, 13}, {0x0D80, 12}, + {0x0018, 6}, {0x00BF, 8}, {0x0480, 12}, {0x0B80, 12}, + {0x0038, 6}, {0x0040, 9}, {0x0900, 13}, {0x0030, 7}, + {0x0780, 12}, {0x2800, 16}, {0x0010, 7}, {0x0A80, 12}, + {0x0050, 7}, {0x0880, 12}, {0x000F, 7}, {0x1100, 13}, + {0x002F, 7}, {0x0100, 13}, {0x0084, 8}, {0x5800, 16}, + {0x00A4, 8}, {0x9800, 16}, {0x0024, 8}, {0x1800, 16}, + {0x0140, 9}, {0xE800, 16}, {0x01C0, 9}, {0x6800, 16}, + {0x02C0, 10}, {0xA800, 16}, {0x0F80, 12}, {0x0580, 12}, + {0x0980, 12}, {0x0E80, 12}, {0x0680, 12}, {0x1F00, 13}, + {0x0F00, 13}, {0x1700, 13}, {0x0700, 13}, {0x1B00, 13}, + {0xF800, 16}, {0x7800, 16}, {0xB800, 16}, {0x3800, 16}, + {0xD800, 16}, + {0x0020, 6}, /* escape */ + {0x0006, 4} /* EOB */ }; static const uint8_t speedhq_level[121] = { @@ -580,7 +580,6 @@ static av_cold void speedhq_static_init(void) { uint16_t ff_mpeg12_vlc_dc_lum_code_reversed[12]; uint16_t ff_mpeg12_vlc_dc_chroma_code_reversed[12]; - int i; /* Exactly the same as MPEG-2, except little-endian. */ reverse_code(ff_mpeg12_vlc_dc_lum_code, @@ -598,10 +597,6 @@ static av_cold void speedhq_static_init(void) ff_mpeg12_vlc_dc_chroma_bits, 1, 1, ff_mpeg12_vlc_dc_chroma_code_reversed, 2, 2, 514); - /* Reverse the AC VLC, because INIT_VLC_LE wants it in that order. */ - for (i = 0; i < FF_ARRAY_ELEMS(speedhq_vlc); ++i) { - speedhq_vlc[i][0] = reverse(speedhq_vlc[i][0], speedhq_vlc[i][1]); - } ff_rl_init(&ff_rl_speedhq, ff_speedhq_static_rl_table_store); INIT_2D_VLC_RL(ff_rl_speedhq, 674, INIT_VLC_LE); diff --git a/libavcodec/svq3.c b/libavcodec/svq3.c index 18a4448ff..9cea9ac84 100644 --- a/libavcodec/svq3.c +++ b/libavcodec/svq3.c @@ -1183,6 +1183,7 @@ static av_cold int svq3_decode_init(AVCodecContext *avctx) GetBitContext gb; int frame_size_code; int unk0, unk1, unk2, unk3, unk4; + int w,h; size = AV_RB32(&extradata[4]); if (size > extradata_end - extradata - 8) { @@ -1195,38 +1196,41 @@ static av_cold int svq3_decode_init(AVCodecContext *avctx) frame_size_code = get_bits(&gb, 3); switch (frame_size_code) { case 0: - avctx->width = 160; - avctx->height = 120; + w = 160; + h = 120; break; case 1: - avctx->width = 128; - avctx->height = 96; + w = 128; + h = 96; break; case 2: - avctx->width = 176; - avctx->height = 144; + w = 176; + h = 144; break; case 3: - avctx->width = 352; - avctx->height = 288; + w = 352; + h = 288; break; case 4: - avctx->width = 704; - avctx->height = 576; + w = 704; + h = 576; break; case 5: - avctx->width = 240; - avctx->height = 180; + w = 240; + h = 180; break; case 6: - avctx->width = 320; - avctx->height = 240; + w = 320; + h = 240; break; case 7: - avctx->width = get_bits(&gb, 12); - avctx->height = get_bits(&gb, 12); + w = get_bits(&gb, 12); + h = get_bits(&gb, 12); break; } + ret = ff_set_dimensions(avctx, w, h); + if (ret < 0) + goto fail; s->halfpel_flag = get_bits1(&gb); s->thirdpel_flag = get_bits1(&gb); diff --git a/libavcodec/tableprint_vlc.h b/libavcodec/tableprint_vlc.h index 3004be3f9..b3ff36562 100644 --- a/libavcodec/tableprint_vlc.h +++ b/libavcodec/tableprint_vlc.h @@ -36,6 +36,7 @@ #define AVCODEC_AVCODEC_H #define AVCODEC_INTERNAL_H #define AV_INPUT_BUFFER_PADDING_SIZE 64 // the value does not matter for this +#define avpriv_request_sample(...) #include "tableprint.h" #include "get_bits.h" #include "mathtables.c" diff --git a/libavcodec/tak_parser.c b/libavcodec/tak_parser.c index 835a47bd5..3604b3544 100644 --- a/libavcodec/tak_parser.c +++ b/libavcodec/tak_parser.c @@ -46,15 +46,16 @@ static int tak_parse(AVCodecParserContext *s, AVCodecContext *avctx, int needed = buf_size ? TAK_MAX_FRAME_HEADER_BYTES : 8; int ret; + *poutbuf = buf; + *poutbuf_size = buf_size; + if (s->flags & PARSER_FLAG_COMPLETE_FRAMES) { TAKStreamInfo ti; if ((ret = init_get_bits8(&gb, buf, buf_size)) < 0) - return ret; + return buf_size; if (!ff_tak_decode_frame_header(avctx, &gb, &ti, 127)) s->duration = t->ti.last_frame_samples ? t->ti.last_frame_samples : t->ti.frame_samples; - *poutbuf = buf; - *poutbuf_size = buf_size; return buf_size; } @@ -65,7 +66,7 @@ static int tak_parse(AVCodecParserContext *s, AVCodecContext *avctx, const uint8_t *tmp_buf = buf; if (ff_combine_frame(pc, END_NOT_FOUND, &tmp_buf, &tmp_buf_size) != -1) - return AVERROR(ENOMEM); + goto fail; consumed += tmp_buf_size; buf += tmp_buf_size; buf_size -= tmp_buf_size; @@ -78,7 +79,7 @@ static int tak_parse(AVCodecParserContext *s, AVCodecContext *avctx, if ((ret = init_get_bits8(&gb, pc->buffer + t->index, pc->index - t->index)) < 0) - return ret; + goto fail; if (!ff_tak_decode_frame_header(avctx, &gb, pc->frame_start_found ? &ti : &t->ti, 127) && !ff_tak_check_crc(pc->buffer + t->index, @@ -103,9 +104,7 @@ found: if (consumed && !buf_size && next == END_NOT_FOUND || ff_combine_frame(pc, next, &buf, &buf_size) < 0) { - *poutbuf = NULL; - *poutbuf_size = 0; - return buf_size + consumed; + goto fail; } if (next != END_NOT_FOUND) { @@ -116,6 +115,11 @@ found: *poutbuf = buf; *poutbuf_size = buf_size; return next; + +fail: + *poutbuf = NULL; + *poutbuf_size = 0; + return buf_size + consumed; } AVCodecParser ff_tak_parser = { diff --git a/libavcodec/tests/dct.c b/libavcodec/tests/dct.c index e8fa4a3cc..2ca8039c0 100644 --- a/libavcodec/tests/dct.c +++ b/libavcodec/tests/dct.c @@ -73,7 +73,7 @@ static void ff_prores_idct_wrap(int16_t *dst){ for(i=0; i<64; i++){ qmat[i]=4; } - ff_prores_idct(dst, qmat); + ff_prores_idct_10(dst, qmat); for(i=0; i<64; i++) { dst[i] -= 512; } diff --git a/libavcodec/tests/h264_levels.c b/libavcodec/tests/h264_levels.c new file mode 100644 index 000000000..98febcc41 --- /dev/null +++ b/libavcodec/tests/h264_levels.c @@ -0,0 +1,235 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/common.h" +#include "libavcodec/h264_levels.h" + +static const struct { + int width; + int height; + int level_idc; +} test_sizes[] = { + // First level usable at some standard sizes. + // (From H.264 table A-6.) + { 176, 144, 10 }, // QCIF + { 352, 288, 11 }, // CIF + { 640, 480, 22 }, // VGA + { 720, 480, 22 }, // NTSC + { 720, 576, 22 }, // PAL + { 800, 600, 31 }, // SVGA + { 1280, 720, 31 }, // 720p + { 1280, 1024, 32 }, // SXGA + { 1920, 1080, 40 }, // 1080p + { 2048, 1080, 42 }, // 2Kx1080 + { 2048, 1536, 50 }, // 4XGA + { 3840, 2160, 51 }, // 4K + { 7680, 4320, 60 }, // 8K + + // Overly wide or tall sizes. + { 1, 256, 10 }, + { 1, 512, 11 }, + { 1, 1024, 21 }, + { 1, 1808, 22 }, + { 1, 1824, 31 }, + { 256, 1, 10 }, + { 512, 1, 11 }, + { 1024, 1, 21 }, + { 1808, 1, 22 }, + { 1824, 1, 31 }, + { 512, 4096, 40 }, + { 256, 4112, 42 }, + { 8688, 1024, 51 }, + { 8704, 512, 60 }, + { 16880, 1, 60 }, + { 16896, 1, 0 }, +}; + +static const struct { + int width; + int height; + int framerate; + int level_idc; +} test_framerate[] = { + // Some typical sizes and frame rates. + // (From H.264 table A-1 and table A-6) + { 176, 144, 15, 10 }, + { 176, 144, 16, 11 }, + { 320, 240, 10, 11 }, + { 320, 240, 20, 12 }, + { 320, 240, 40, 21 }, + { 352, 288, 30, 13 }, + { 352, 288, 51, 22 }, + { 352, 576, 25, 21 }, + { 352, 576, 26, 30 }, + { 640, 480, 33, 30 }, + { 640, 480, 34, 31 }, + { 720, 480, 50, 31 }, + { 720, 576, 25, 30 }, + { 800, 600, 55, 31 }, + { 1024, 768, 35, 31 }, + { 1024, 768, 70, 32 }, + { 1280, 720, 30, 31 }, + { 1280, 720, 31, 32 }, + { 1280, 960, 45, 32 }, + { 1280, 960, 46, 40 }, + { 1280, 1024, 42, 32 }, + { 1600, 1200, 32, 40 }, + { 1600, 1200, 33, 42 }, + { 1920, 1088, 30, 40 }, + { 1920, 1088, 55, 42 }, + { 2048, 1024, 30, 40 }, + { 2048, 1024, 62, 42 }, + { 2048, 1088, 60, 42 }, + { 3680, 1536, 26, 50 }, + { 4096, 2048, 30, 51 }, + { 4096, 2048, 59, 52 }, + { 4096, 2160, 60, 52 }, +}; + +static const struct { + int width; + int height; + int dpb_size; + int level_idc; +} test_dpb[] = { + // First level usable for some DPB sizes. + // (From H.264 table A-7.) + { 176, 144, 4, 10 }, + { 176, 144, 8, 11 }, + { 176, 144, 16, 12 }, + { 1280, 720, 1, 31 }, + { 1280, 720, 5, 31 }, + { 1280, 720, 9, 40 }, + { 1280, 720, 10, 50 }, + { 1920, 1080, 1, 40 }, + { 1920, 1080, 5, 50 }, + { 1920, 1080, 13, 50 }, + { 1920, 1080, 14, 51 }, + { 3840, 2160, 5, 51 }, + { 3840, 2160, 6, 60 }, + { 3840, 2160, 16, 60 }, + { 7680, 4320, 5, 60 }, + { 7680, 4320, 6, 0 }, +}; + +static const struct { + int64_t bitrate; + int profile_idc; + int level_idc; +} test_bitrate[] = { + // Values where profile affects level at a given bitrate. + { 2500000, 77, 21 }, + { 2500000, 100, 20 }, + { 2500000, 244, 13 }, + { 100000000, 77, 50 }, + { 100000000, 100, 50 }, + { 100000000, 244, 41 }, + { 999999999, 77, 0 }, + { 999999999, 100, 62 }, + // Check level 1b. + { 32 * 1200, 66, 10 }, + { 32 * 1500, 100, 10 }, + { 96 * 1200, 66, 11 }, + { 96 * 1500, 100, 9 }, + { 144 * 1200, 66, 11 }, + { 144 * 1500, 100, 11 }, +}; + +static const struct { + const char *name; + int profile_idc; + int64_t bitrate; + int width; + int height; + int dpb_frames; + int level_idc; +} test_all[] = { + { "Bluray 1080p 40Mb/s", 100, 40000000, 1920, 1080, 4, 41 }, + { "Bluray 1080p 24Mb/s", 100, 24000000, 1920, 1080, 4, 40 }, + { "Bluray 720p 40Mb/s", 100, 40000000, 1280, 720, 6, 41 }, + { "Bluray 720p 24Mb/s", 100, 24000000, 1280, 720, 6, 40 }, + { "Bluray PAL 40Mb/s", 100, 40000000, 720, 576, 6, 41 }, + { "Bluray PAL 24Mb/s", 100, 24000000, 720, 576, 6, 32 }, + { "Bluray PAL 16Mb/s", 100, 16800000, 720, 576, 6, 31 }, + { "Bluray PAL 12Mb/s", 100, 12000000, 720, 576, 5, 30 }, + { "Bluray NTSC 40Mb/s", 100, 40000000, 720, 480, 6, 41 }, + { "Bluray NTSC 24Mb/s", 100, 24000000, 720, 480, 6, 32 }, + { "Bluray NTSC 16Mb/s", 100, 16800000, 720, 480, 6, 31 }, + { "Bluray NTSC 12Mb/s", 100, 12000000, 720, 480, 6, 30 }, +}; + +int main(void) +{ + const H264LevelDescriptor *level; + int i; + +#define CHECK(expected, format, ...) do { \ + if (expected ? (!level || level->level_idc != expected) \ + : !!level) { \ + av_log(NULL, AV_LOG_ERROR, "Incorrect level for " \ + format ": expected %d, got %d.\n", __VA_ARGS__, \ + expected, level ? level->level_idc : -1); \ + return 1; \ + } \ + } while (0) + + for (i = 0; i < FF_ARRAY_ELEMS(test_sizes); i++) { + level = ff_h264_guess_level(0, 0, 0, test_sizes[i].width, + test_sizes[i].height, 0); + CHECK(test_sizes[i].level_idc, "size %dx%d", + test_sizes[i].width, test_sizes[i].height); + } + + for (i = 0; i < FF_ARRAY_ELEMS(test_framerate); i++) { + level = ff_h264_guess_level(0, 0, test_framerate[i].framerate, + test_framerate[i].width, + test_framerate[i].height, 0); + CHECK(test_framerate[i].level_idc, "framerate %d, size %dx%d", + test_framerate[i].framerate, test_framerate[i].width, + test_framerate[i].height); + } + + for (i = 0; i < FF_ARRAY_ELEMS(test_dpb); i++) { + level = ff_h264_guess_level(0, 0, 0, test_dpb[i].width, + test_dpb[i].height, + test_dpb[i].dpb_size); + CHECK(test_dpb[i].level_idc, "size %dx%d dpb %d", + test_dpb[i].width, test_dpb[i].height, + test_dpb[i].dpb_size); + } + + for (i = 0; i < FF_ARRAY_ELEMS(test_bitrate); i++) { + level = ff_h264_guess_level(test_bitrate[i].profile_idc, + test_bitrate[i].bitrate, + 0, 0, 0, 0); + CHECK(test_bitrate[i].level_idc, "bitrate %"PRId64" profile %d", + test_bitrate[i].bitrate, test_bitrate[i].profile_idc); + } + + for (i = 0; i < FF_ARRAY_ELEMS(test_all); i++) { + level = ff_h264_guess_level(test_all[i].profile_idc, + test_all[i].bitrate, + 0, + test_all[i].width, + test_all[i].height, + test_all[i].dpb_frames); + CHECK(test_all[i].level_idc, "%s", test_all[i].name); + } + + return 0; +} diff --git a/libavcodec/tests/h265_levels.c b/libavcodec/tests/h265_levels.c new file mode 100644 index 000000000..66d72c63a --- /dev/null +++ b/libavcodec/tests/h265_levels.c @@ -0,0 +1,297 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/common.h" +#include "libavcodec/h265_profile_level.h" + +static const struct { + int width; + int height; + int level_idc; +} test_sizes[] = { + // First level usable at standard sizes, from H.265 table A.9. + { 176, 144, 30 }, // QCIF + { 352, 288, 60 }, // CIF + { 640, 480, 90 }, // VGA + { 720, 480, 90 }, // NTSC + { 720, 576, 90 }, // PAL + { 1024, 768, 93 }, // XGA + { 1280, 720, 93 }, // 720p + { 1280, 1024, 120 }, // SXGA + { 1920, 1080, 120 }, // 1080p + { 2048, 1080, 120 }, // 2Kx1080 + { 2048, 1536, 150 }, // 4XGA + { 3840, 2160, 150 }, // 4K + { 7680, 4320, 180 }, // 8K + + // Overly wide or tall sizes. + { 1, 512, 30 }, + { 1, 1024, 63 }, + { 1, 2048, 90 }, + { 1, 4096, 120 }, + { 1, 8192, 150 }, + { 1, 16384, 180 }, + { 1, 32768, 0 }, + { 512, 1, 30 }, + { 1024, 1, 63 }, + { 2048, 1, 90 }, + { 4096, 1, 120 }, + { 8192, 1, 150 }, + { 16384, 1, 180 }, + { 32768, 1, 0 }, + { 2800, 256, 93 }, + { 2816, 128, 120 }, + { 256, 4208, 120 }, + { 128, 4224, 150 }, + { 8432, 256, 150 }, + { 8448, 128, 180 }, + { 256, 16880, 180 }, + { 128, 16896, 0 }, +}; + +static const struct { + int width; + int height; + int dpb_size; + int level_idc; +} test_dpb[] = { + // First level usable for some DPB sizes. + + // L1: 176 * 144 = 25344 <= 36864 * 3/4 = 27648 + // L2: <= 122880 * 1/4 = 30720 + { 176, 144, 8, 30 }, + { 176, 144, 9, 60 }, + + // L2: 352 * 288 = 101376 <= 122880 + // L2.1: <= 245760 * 1/2 = 122880 + // L3: <= 552960 * 1/4 = 138240 + { 352, 288, 6, 60 }, + { 352, 288, 7, 63 }, + { 352, 288, 13, 90 }, + + // L3.1: 1280 * 720 = 921600 <= 983040 + // L4: <= 2228224 * 1/2 = 1114112 + // L5: <= 8912896 * 1/4 = 2228224 + { 1280, 720, 6, 93 }, + { 1280, 720, 12, 120 }, + { 1280, 720, 16, 150 }, + + // L5: 3840 * 2160 = 8294400 <= 8912896 + // L6: <= 35651584 * 1/4 = 8912896 + { 3840, 2160, 6, 150 }, + { 3840, 2160, 7, 180 }, + { 3840, 2160, 16, 180 }, +}; + +static const H265RawProfileTierLevel profile_main = { + // CpbNalFactor = 1100 + .general_profile_space = 0, + .general_profile_idc = 1, + .general_tier_flag = 0, + .general_profile_compatibility_flag[1] = 1, +}; + +static const H265RawProfileTierLevel profile_main_12 = { + // CpbNalFactor = 1650 + .general_profile_space = 0, + .general_profile_idc = 4, + .general_tier_flag = 0, + .general_profile_compatibility_flag[4] = 1, + .general_max_12bit_constraint_flag = 1, + .general_max_10bit_constraint_flag = 0, + .general_max_8bit_constraint_flag = 0, + .general_max_422chroma_constraint_flag = 1, + .general_max_420chroma_constraint_flag = 1, + .general_max_monochrome_constraint_flag = 0, + .general_intra_constraint_flag = 0, + .general_one_picture_only_constraint_flag = 0, + .general_lower_bit_rate_constraint_flag = 1, +}; + +static const H265RawProfileTierLevel profile_main_422_12_intra = { + // CpbNalFactor = 2200 + .general_profile_space = 0, + .general_profile_idc = 4, + .general_tier_flag = 0, + .general_profile_compatibility_flag[4] = 1, + .general_max_12bit_constraint_flag = 1, + .general_max_10bit_constraint_flag = 0, + .general_max_8bit_constraint_flag = 0, + .general_max_422chroma_constraint_flag = 1, + .general_max_420chroma_constraint_flag = 0, + .general_max_monochrome_constraint_flag = 0, + .general_intra_constraint_flag = 1, + .general_one_picture_only_constraint_flag = 0, +}; + +static const H265RawProfileTierLevel profile_ht_444_14 = { + // CpbNalFactor = 3850 + .general_profile_space = 0, + .general_profile_idc = 5, + .general_tier_flag = 0, + .general_profile_compatibility_flag[5] = 1, + .general_max_14bit_constraint_flag = 1, + .general_max_12bit_constraint_flag = 0, + .general_max_10bit_constraint_flag = 0, + .general_max_8bit_constraint_flag = 0, + .general_max_422chroma_constraint_flag = 0, + .general_max_420chroma_constraint_flag = 0, + .general_max_monochrome_constraint_flag = 0, + .general_intra_constraint_flag = 0, + .general_one_picture_only_constraint_flag = 0, + .general_lower_bit_rate_constraint_flag = 1, +}; + +static const H265RawProfileTierLevel profile_main_high_tier = { + // CpbNalFactor = 1100 + .general_profile_space = 0, + .general_profile_idc = 1, + .general_tier_flag = 1, + .general_profile_compatibility_flag[1] = 1, +}; + +static const struct { + int64_t bitrate; + const H265RawProfileTierLevel *ptl; + int level_idc; +} test_bitrate[] = { + // First level usable for some bitrates and profiles. + + // L2.1: 3000 * 1100 = 3300000 + // L3: 6000 * 1100 = 6600000 + { 4000000, &profile_main, 90 }, + // L2: 1500 * 1650 = 2475000 + // L2.1: 3000 * 1650 = 4950000 + { 4000000, &profile_main_12, 63 }, + // L1: 350 * 2200 * 2 = 1540000 + // L2: 1500 * 2200 * 2 = 6600000 + { 4000000, &profile_main_422_12_intra, 60 }, + + // L5.1: 40000 * 1100 = 44000000 + // L5.2: 60000 * 1100 = 66000000 + { 50000000, &profile_main, 156 }, + // L5: 25000 * 1650 = 41250000 + // L5.1: 40000 * 1650 = 66000000 + { 50000000, &profile_main_12, 153 }, + // L3.1: 10000 * 2200 * 2 = 44000000 + // L4: 12000 * 2200 * 2 = 52800000 + { 50000000, &profile_main_422_12_intra, 120 }, + // L2: 1500 * 3850 * 6 = 34650000 + // L2.1: 3000 * 3850 * 6 = 69300000 + { 50000000, &profile_ht_444_14, 63 }, + + // Level changes based on tier. + { 1000, &profile_main, 30 }, + { 1000, &profile_main_high_tier, 120 }, + { 40000000, &profile_main, 153 }, + { 40000000, &profile_main_high_tier, 123 }, + { 200000000, &profile_main, 186 }, + { 200000000, &profile_main_high_tier, 156 }, + + // Overflowing 32-bit integers. + // L6: 60000 * 3850 * 6 = 1386000000 + // L6.1: 120000 * 3850 * 6 = 2772000000 + // L6.2: 240000 * 3850 * 6 = 5544000000 + { INT64_C(2700000000), &profile_ht_444_14, 183 }, + { INT64_C(4200000000), &profile_ht_444_14, 186 }, + { INT64_C(5600000000), &profile_ht_444_14, 0 }, +}; + +static const struct { + int slice_segments; + int tile_rows; + int tile_cols; + int level_idc; +} test_fragments[] = { + // Slices. + { 4, 1, 1, 30 }, + { 32, 1, 1, 93 }, + { 70, 1, 1, 120 }, + { 80, 1, 1, 150 }, + { 201, 1, 1, 180 }, + { 600, 1, 1, 180 }, + { 601, 1, 1, 0 }, + + // Tiles. + { 1, 2, 1, 90 }, + { 1, 1, 2, 90 }, + { 1, 3, 3, 93 }, + { 1, 4, 2, 120 }, + { 1, 2, 4, 120 }, + { 1, 11, 10, 150 }, + { 1, 10, 11, 180 }, + { 1, 22, 20, 180 }, + { 1, 20, 22, 0 }, +}; + +int main(void) +{ + const H265ProfileDescriptor *profile; + const H265LevelDescriptor *level; + int i; + +#define CHECK(expected, format, ...) do { \ + if (expected ? (!level || level->level_idc != expected) \ + : !!level) { \ + av_log(NULL, AV_LOG_ERROR, "Incorrect level for " \ + format ": expected %d, got %d.\n", __VA_ARGS__, \ + expected, level ? level->level_idc : -1); \ + return 1; \ + } \ + } while (0) + + for (i = 0; i < FF_ARRAY_ELEMS(test_sizes); i++) { + level = ff_h265_guess_level(&profile_main, 0, + test_sizes[i].width, + test_sizes[i].height, + 0, 0, 0, 0); + CHECK(test_sizes[i].level_idc, "size %dx%d", + test_sizes[i].width, test_sizes[i].height); + } + + for (i = 0; i < FF_ARRAY_ELEMS(test_dpb); i++) { + level = ff_h265_guess_level(&profile_main, 0, + test_dpb[i].width, + test_dpb[i].height, + 0, 0, 0, test_dpb[i].dpb_size); + CHECK(test_dpb[i].level_idc, "size %dx%d dpb %d", + test_dpb[i].width, test_dpb[i].height, + test_dpb[i].dpb_size); + } + + for (i = 0; i < FF_ARRAY_ELEMS(test_bitrate); i++) { + profile = ff_h265_get_profile(test_bitrate[i].ptl); + level = ff_h265_guess_level(test_bitrate[i].ptl, + test_bitrate[i].bitrate, + 0, 0, 0, 0, 0, 0); + CHECK(test_bitrate[i].level_idc, "bitrate %"PRId64" profile %s", + test_bitrate[i].bitrate, profile->name); + } + + for (i = 0; i < FF_ARRAY_ELEMS(test_fragments); i++) { + level = ff_h265_guess_level(&profile_main, 0, 0, 0, + test_fragments[i].slice_segments, + test_fragments[i].tile_rows, + test_fragments[i].tile_cols, 0); + CHECK(test_fragments[i].level_idc, "%d slices %dx%d tiles", + test_fragments[i].slice_segments, + test_fragments[i].tile_cols, test_fragments[i].tile_rows); + } + + return 0; +} diff --git a/libavcodec/tests/imgconvert.c b/libavcodec/tests/imgconvert.c index c598d461d..aefc324bf 100644 --- a/libavcodec/tests/imgconvert.c +++ b/libavcodec/tests/imgconvert.c @@ -39,10 +39,6 @@ int main(void){ skip = 0; } av_log(NULL, AV_LOG_INFO, "pix fmt %s yuv_plan:%d avg_bpp:%d\n", desc->name, is_yuv_planar(desc), av_get_padded_bits_per_pixel(desc)); - if ((!(desc->flags & AV_PIX_FMT_FLAG_ALPHA)) != (desc->nb_components != 2 && desc->nb_components != 4)) { - av_log(NULL, AV_LOG_ERROR, "Alpha flag mismatch\n"); - err = 1; - } } return err; } diff --git a/libavcodec/tests/rangecoder.c b/libavcodec/tests/rangecoder.c index 3a8ba6759..d6cf9ec38 100644 --- a/libavcodec/tests/rangecoder.c +++ b/libavcodec/tests/rangecoder.c @@ -24,41 +24,53 @@ #include "libavcodec/rangecoder.h" -#define SIZE 10240 +#define SIZE 1240 int main(void) { RangeCoder c; uint8_t b[9 * SIZE] = {0}; uint8_t r[9 * SIZE]; - int i; + int i, p, actual_length, version; uint8_t state[10]; AVLFG prng; av_lfg_init(&prng, 1); + for (version = 0; version < 2; version++) { + for (p = 0; p< 1024; p++) { + ff_init_range_encoder(&c, b, SIZE); + ff_build_rac_states(&c, (1LL << 32) / 20, 128 + 64 + 32 + 16); - ff_init_range_encoder(&c, b, SIZE); - ff_build_rac_states(&c, (1LL << 32) / 20, 128 + 64 + 32 + 16); + memset(state, 128, sizeof(state)); - memset(state, 128, sizeof(state)); + for (i = 0; i < SIZE; i++) + r[i] = av_lfg_get(&prng) % 7; - for (i = 0; i < SIZE; i++) - r[i] = av_lfg_get(&prng) % 7; + for (i = 0; i < SIZE; i++) + put_rac(&c, state, r[i] & 1); - for (i = 0; i < SIZE; i++) - put_rac(&c, state, r[i] & 1); + actual_length = ff_rac_terminate(&c, version); - ff_rac_terminate(&c); + ff_init_range_decoder(&c, b, version ? SIZE : actual_length); - ff_init_range_decoder(&c, b, SIZE); + memset(state, 128, sizeof(state)); - memset(state, 128, sizeof(state)); + for (i = 0; i < SIZE; i++) + if ((r[i] & 1) != get_rac(&c, state)) { + av_log(NULL, AV_LOG_ERROR, "rac failure at %d pass %d version %d\n", i, p, version); + return 1; + } - for (i = 0; i < SIZE; i++) - if ((r[i] & 1) != get_rac(&c, state)) { - av_log(NULL, AV_LOG_ERROR, "rac failure at %d\n", i); - return 1; + if (ff_rac_check_termination(&c, version) < 0) { + av_log(NULL, AV_LOG_ERROR, "rac failure at termination pass %d version %d\n", p, version); + return 1; + } + if (c.bytestream - c.bytestream_start - actual_length != version) { + av_log(NULL, AV_LOG_ERROR, "rac failure at pass %d version %d\n", p, version); + return 1; + } } + } return 0; } diff --git a/libavcodec/tiff.c b/libavcodec/tiff.c index 9c13a758e..1f1a1a369 100644 --- a/libavcodec/tiff.c +++ b/libavcodec/tiff.c @@ -37,6 +37,7 @@ #include "libavutil/avstring.h" #include "libavutil/intreadwrite.h" #include "libavutil/imgutils.h" +#include "libavutil/opt.h" #include "avcodec.h" #include "bytestream.h" #include "faxcompr.h" @@ -46,11 +47,18 @@ #include "tiff.h" #include "tiff_data.h" #include "thread.h" +#include "get_bits.h" typedef struct TiffContext { + AVClass *class; AVCodecContext *avctx; GetByteContext gb; + int get_subimage; + uint16_t get_page; + int get_thumbnail; + + enum TiffType tiff_type; int width, height; unsigned int bpp, bppcount; uint32_t palette[256]; @@ -64,6 +72,14 @@ typedef struct TiffContext { int predictor; int fill_order; uint32_t res[4]; + int is_thumbnail; + + int is_bayer; + uint8_t pattern[4]; + unsigned white_level; + + uint32_t sub_ifd; + uint16_t cur_page; int strips, rps, sstype; int sot; @@ -81,6 +97,11 @@ typedef struct TiffContext { TiffGeoTag *geotags; } TiffContext; +static void tiff_set_type(TiffContext *s, enum TiffType tiff_type) { + if (s->tiff_type < tiff_type) // Prioritize higher-valued entries + s->tiff_type = tiff_type; +} + static void free_geotags(TiffContext *const s) { int i; @@ -236,7 +257,8 @@ static int add_metadata(int count, int type, }; } -static void av_always_inline horizontal_fill(unsigned int bpp, uint8_t* dst, +static void av_always_inline horizontal_fill(TiffContext *s, + unsigned int bpp, uint8_t* dst, int usePtr, const uint8_t *src, uint8_t c, int width, int offset) { @@ -267,6 +289,15 @@ static void av_always_inline horizontal_fill(unsigned int bpp, uint8_t* dst, dst[(width+offset)*2+0] = (usePtr ? src[width] : c) >> 4; } break; + case 12: { + uint16_t *dst16 = (uint16_t *)dst; + GetBitContext gb; + init_get_bits8(&gb, src, width); + for (int i = 0; i < s->width; i++) { + dst16[i] = get_bits(&gb, 12) << 4; + } + } + break; default: if (usePtr) { memcpy(dst + offset, src, width); @@ -289,6 +320,19 @@ static int deinvert_buffer(TiffContext *s, const uint8_t *src, int size) return 0; } +static void unpack_gray(TiffContext *s, AVFrame *p, + const uint8_t *src, int lnum, int width, int bpp) +{ + GetBitContext gb; + uint16_t *dst = (uint16_t *)(p->data[0] + lnum * p->linesize[0]); + + init_get_bits8(&gb, src, width); + + for (int i = 0; i < s->width; i++) { + dst[i] = get_bits(&gb, bpp); + } +} + static void unpack_yuv(TiffContext *s, AVFrame *p, const uint8_t *src, int lnum) { @@ -368,7 +412,7 @@ static int tiff_unpack_zlib(TiffContext *s, AVFrame *p, uint8_t *dst, int stride src = zbuf; for (line = 0; line < lines; line++) { if (s->bpp < 8 && s->avctx->pix_fmt == AV_PIX_FMT_PAL8) { - horizontal_fill(s->bpp, dst, 1, src, 0, width, 0); + horizontal_fill(s, s->bpp, dst, 1, src, 0, width, 0); } else { memcpy(dst, src, width); } @@ -433,7 +477,7 @@ static int tiff_unpack_lzma(TiffContext *s, AVFrame *p, uint8_t *dst, int stride src = buf; for (line = 0; line < lines; line++) { if (s->bpp < 8 && s->avctx->pix_fmt == AV_PIX_FMT_PAL8) { - horizontal_fill(s->bpp, dst, 1, src, 0, width, 0); + horizontal_fill(s, s->bpp, dst, 1, src, 0, width, 0); } else { memcpy(dst, src, width); } @@ -476,7 +520,7 @@ static int tiff_unpack_fax(TiffContext *s, uint8_t *dst, int stride, s->compr, s->fax_opts); if (s->bpp < 8 && s->avctx->pix_fmt == AV_PIX_FMT_PAL8) for (line = 0; line < lines; line++) { - horizontal_fill(s->bpp, dst, 1, dst, 0, width, 0); + horizontal_fill(s, s->bpp, dst, 1, dst, 0, width, 0); dst += stride; } return ret; @@ -516,6 +560,18 @@ static int tiff_unpack_strip(TiffContext *s, AVFrame *p, uint8_t *dst, int strid av_assert0(width <= bytes_per_row); av_assert0(s->bpp == 24); } + if (s->is_bayer) { + width = (s->bpp * s->width + 7) >> 3; + } + if (p->format == AV_PIX_FMT_GRAY12) { + av_fast_padded_malloc(&s->yuv_line, &s->yuv_line_size, width); + if (s->yuv_line == NULL) { + av_log(s->avctx, AV_LOG_ERROR, "Not enough memory\n"); + return AVERROR(ENOMEM); + } + dst = s->yuv_line; + stride = 0; + } if (s->compr == TIFF_DEFLATE || s->compr == TIFF_ADOBE_DEFLATE) { #if CONFIG_ZLIB @@ -559,10 +615,12 @@ static int tiff_unpack_strip(TiffContext *s, AVFrame *p, uint8_t *dst, int strid return AVERROR_INVALIDDATA; } if (s->bpp < 8 && s->avctx->pix_fmt == AV_PIX_FMT_PAL8) - horizontal_fill(s->bpp, dst, 1, dst, 0, width, 0); + horizontal_fill(s, s->bpp, dst, 1, dst, 0, width, 0); if (is_yuv) { unpack_yuv(s, p, dst, strip_start + line); line += s->subsampling[1] - 1; + } else if (p->format == AV_PIX_FMT_GRAY12) { + unpack_gray(s, p, dst, strip_start + line, width, s->bpp); } dst += stride; } @@ -595,7 +653,7 @@ static int tiff_unpack_strip(TiffContext *s, AVFrame *p, uint8_t *dst, int strid return AVERROR_INVALIDDATA; if (!s->fill_order) { - horizontal_fill(s->bpp * (s->avctx->pix_fmt == AV_PIX_FMT_PAL8), + horizontal_fill(s, s->bpp * (s->avctx->pix_fmt == AV_PIX_FMT_PAL8 || s->is_bayer), dst, 1, src, 0, width, 0); } else { int i; @@ -619,7 +677,7 @@ static int tiff_unpack_strip(TiffContext *s, AVFrame *p, uint8_t *dst, int strid "Copy went out of bounds\n"); return AVERROR_INVALIDDATA; } - horizontal_fill(s->bpp * (s->avctx->pix_fmt == AV_PIX_FMT_PAL8), + horizontal_fill(s, s->bpp * (s->avctx->pix_fmt == AV_PIX_FMT_PAL8), dst, 1, src, 0, code, pixels); src += code; pixels += code; @@ -631,7 +689,7 @@ static int tiff_unpack_strip(TiffContext *s, AVFrame *p, uint8_t *dst, int strid return AVERROR_INVALIDDATA; } c = *src++; - horizontal_fill(s->bpp * (s->avctx->pix_fmt == AV_PIX_FMT_PAL8), + horizontal_fill(s, s->bpp * (s->avctx->pix_fmt == AV_PIX_FMT_PAL8), dst, 0, NULL, c, code, pixels); pixels += code; } @@ -646,6 +704,8 @@ static int tiff_unpack_strip(TiffContext *s, AVFrame *p, uint8_t *dst, int strid if (is_yuv) { unpack_yuv(s, p, dst, strip_start + line); line += s->subsampling[1] - 1; + } else if (p->format == AV_PIX_FMT_GRAY12) { + unpack_gray(s, p, dst, strip_start + line, width, s->bpp); } dst += stride; } @@ -665,7 +725,7 @@ static int init_image(TiffContext *s, ThreadFrame *frame) return AVERROR_INVALIDDATA; } - switch (s->planar * 1000 + s->bpp * 10 + s->bppcount) { + switch (s->planar * 1000 + s->bpp * 10 + s->bppcount + s->is_bayer * 10000) { case 11: if (!s->palette_is_set) { s->avctx->pix_fmt = AV_PIX_FMT_MONOBLACK; @@ -681,6 +741,69 @@ static int init_image(TiffContext *s, ThreadFrame *frame) case 81: s->avctx->pix_fmt = s->palette_is_set ? AV_PIX_FMT_PAL8 : AV_PIX_FMT_GRAY8; break; + case 121: + s->avctx->pix_fmt = AV_PIX_FMT_GRAY12; + break; + case 10081: + switch (AV_RL32(s->pattern)) { + case 0x02010100: + s->avctx->pix_fmt = AV_PIX_FMT_BAYER_RGGB8; + break; + case 0x00010102: + s->avctx->pix_fmt = AV_PIX_FMT_BAYER_BGGR8; + break; + case 0x01000201: + s->avctx->pix_fmt = AV_PIX_FMT_BAYER_GBRG8; + break; + case 0x01020001: + s->avctx->pix_fmt = AV_PIX_FMT_BAYER_GRBG8; + break; + default: + av_log(s->avctx, AV_LOG_ERROR, "Unsupported Bayer pattern: 0x%X\n", + AV_RL32(s->pattern)); + return AVERROR_PATCHWELCOME; + } + break; + case 10121: + switch (AV_RL32(s->pattern)) { + case 0x02010100: + s->avctx->pix_fmt = s->le ? AV_PIX_FMT_BAYER_RGGB16LE : AV_PIX_FMT_BAYER_RGGB16BE; + break; + case 0x00010102: + s->avctx->pix_fmt = s->le ? AV_PIX_FMT_BAYER_BGGR16LE : AV_PIX_FMT_BAYER_BGGR16BE; + break; + case 0x01000201: + s->avctx->pix_fmt = s->le ? AV_PIX_FMT_BAYER_GBRG16LE : AV_PIX_FMT_BAYER_GBRG16BE; + break; + case 0x01020001: + s->avctx->pix_fmt = s->le ? AV_PIX_FMT_BAYER_GRBG16LE : AV_PIX_FMT_BAYER_GRBG16BE; + break; + default: + av_log(s->avctx, AV_LOG_ERROR, "Unsupported Bayer pattern: 0x%X\n", + AV_RL32(s->pattern)); + return AVERROR_PATCHWELCOME; + } + break; + case 10161: + switch (AV_RL32(s->pattern)) { + case 0x02010100: + s->avctx->pix_fmt = s->le ? AV_PIX_FMT_BAYER_RGGB16LE : AV_PIX_FMT_BAYER_RGGB16BE; + break; + case 0x00010102: + s->avctx->pix_fmt = s->le ? AV_PIX_FMT_BAYER_BGGR16LE : AV_PIX_FMT_BAYER_BGGR16BE; + break; + case 0x01000201: + s->avctx->pix_fmt = s->le ? AV_PIX_FMT_BAYER_GBRG16LE : AV_PIX_FMT_BAYER_GBRG16BE; + break; + case 0x01020001: + s->avctx->pix_fmt = s->le ? AV_PIX_FMT_BAYER_GRBG16LE : AV_PIX_FMT_BAYER_GRBG16BE; + break; + default: + av_log(s->avctx, AV_LOG_ERROR, "Unsupported Bayer pattern: 0x%X\n", + AV_RL32(s->pattern)); + return AVERROR_PATCHWELCOME; + } + break; case 243: if (s->photometric == TIFF_PHOTOMETRIC_YCBCR) { if (s->subsampling[0] == 1 && s->subsampling[1] == 1) { @@ -712,7 +835,16 @@ static int init_image(TiffContext *s, ThreadFrame *frame) s->avctx->pix_fmt = s->le ? AV_PIX_FMT_YA16LE : AV_PIX_FMT_YA16BE; break; case 324: - s->avctx->pix_fmt = AV_PIX_FMT_RGBA; + s->avctx->pix_fmt = s->photometric == TIFF_PHOTOMETRIC_SEPARATED ? AV_PIX_FMT_RGB0 : AV_PIX_FMT_RGBA; + break; + case 405: + if (s->photometric == TIFF_PHOTOMETRIC_SEPARATED) + s->avctx->pix_fmt = AV_PIX_FMT_RGBA; + else { + av_log(s->avctx, AV_LOG_ERROR, + "bpp=40 without PHOTOMETRIC_SEPARATED is unsupported\n"); + return AVERROR_PATCHWELCOME; + } break; case 483: s->avctx->pix_fmt = s->le ? AV_PIX_FMT_RGB48LE : AV_PIX_FMT_RGB48BE; @@ -824,6 +956,8 @@ static int tiff_decode_tag(TiffContext *s, AVFrame *frame) } switch (tag) { + case TIFF_SUBFILE: + s->is_thumbnail = (value != 0); case TIFF_WIDTH: s->width = value; break; @@ -831,7 +965,7 @@ static int tiff_decode_tag(TiffContext *s, AVFrame *frame) s->height = value; break; case TIFF_BPP: - if (count > 4U) { + if (count > 5U) { av_log(s->avctx, AV_LOG_ERROR, "This format is not supported (bpp=%d, %d components)\n", value, count); @@ -862,7 +996,7 @@ static int tiff_decode_tag(TiffContext *s, AVFrame *frame) "Samples per pixel requires a single value, many provided\n"); return AVERROR_INVALIDDATA; } - if (value > 4U) { + if (value > 5U) { av_log(s->avctx, AV_LOG_ERROR, "Samples per pixel %d is too large\n", value); return AVERROR_INVALIDDATA; @@ -961,21 +1095,44 @@ static int tiff_decode_tag(TiffContext *s, AVFrame *frame) case TIFF_PREDICTOR: s->predictor = value; break; + case TIFF_SUB_IFDS: + if (count == 1) + s->sub_ifd = value; + else if (count > 1) + s->sub_ifd = ff_tget(&s->gb, TIFF_LONG, s->le); /** Only get the first SubIFD */ + break; + case DNG_WHITE_LEVEL: + s->white_level = value; + break; + case TIFF_CFA_PATTERN_DIM: + if (count != 2 || (ff_tget(&s->gb, type, s->le) != 2 && + ff_tget(&s->gb, type, s->le) != 2)) { + av_log(s->avctx, AV_LOG_ERROR, "CFA Pattern dimensions are not 2x2\n"); + return AVERROR_INVALIDDATA; + } + break; + case TIFF_CFA_PATTERN: + s->is_bayer = 1; + s->pattern[0] = ff_tget(&s->gb, type, s->le); + s->pattern[1] = ff_tget(&s->gb, type, s->le); + s->pattern[2] = ff_tget(&s->gb, type, s->le); + s->pattern[3] = ff_tget(&s->gb, type, s->le); + break; case TIFF_PHOTOMETRIC: switch (value) { case TIFF_PHOTOMETRIC_WHITE_IS_ZERO: case TIFF_PHOTOMETRIC_BLACK_IS_ZERO: case TIFF_PHOTOMETRIC_RGB: case TIFF_PHOTOMETRIC_PALETTE: + case TIFF_PHOTOMETRIC_SEPARATED: case TIFF_PHOTOMETRIC_YCBCR: + case TIFF_PHOTOMETRIC_CFA: s->photometric = value; break; case TIFF_PHOTOMETRIC_ALPHA_MASK: - case TIFF_PHOTOMETRIC_SEPARATED: case TIFF_PHOTOMETRIC_CIE_LAB: case TIFF_PHOTOMETRIC_ICC_LAB: case TIFF_PHOTOMETRIC_ITU_LAB: - case TIFF_PHOTOMETRIC_CFA: case TIFF_PHOTOMETRIC_LOG_L: case TIFF_PHOTOMETRIC_LOG_LUV: case TIFF_PHOTOMETRIC_LINEAR_RAW: @@ -1185,14 +1342,41 @@ static int tiff_decode_tag(TiffContext *s, AVFrame *frame) break; case TIFF_PAGE_NUMBER: ADD_METADATA(count, "page_number", " / "); + // need to seek back to re-read the page number + bytestream2_seek(&s->gb, -count * sizeof(uint16_t), SEEK_CUR); + // read the page number + s->cur_page = ff_tget(&s->gb, TIFF_SHORT, s->le); + // get back to where we were before the previous seek + bytestream2_seek(&s->gb, count * sizeof(uint16_t) - sizeof(uint16_t), SEEK_CUR); break; case TIFF_SOFTWARE_NAME: ADD_METADATA(count, "software", NULL); break; + case DNG_VERSION: + if (count == 4) { + unsigned int ver[4]; + ver[0] = ff_tget(&s->gb, type, s->le); + ver[1] = ff_tget(&s->gb, type, s->le); + ver[2] = ff_tget(&s->gb, type, s->le); + ver[3] = ff_tget(&s->gb, type, s->le); + + av_log(s->avctx, AV_LOG_DEBUG, "DNG file, version %u.%u.%u.%u\n", + ver[0], ver[1], ver[2], ver[3]); + + tiff_set_type(s, TIFF_TYPE_DNG); + } + break; + case CINEMADNG_TIME_CODES: + case CINEMADNG_FRAME_RATE: + case CINEMADNG_T_STOP: + case CINEMADNG_REEL_NAME: + case CINEMADNG_CAMERA_LABEL: + tiff_set_type(s, TIFF_TYPE_CINEMADNG); + break; default: if (s->avctx->err_recognition & AV_EF_EXPLODE) { av_log(s->avctx, AV_LOG_ERROR, - "Unknown or unsupported tag %d/0X%0X\n", + "Unknown or unsupported tag %d/0x%0X\n", tag, tag); return AVERROR_INVALIDDATA; } @@ -1215,13 +1399,14 @@ static int decode_frame(AVCodecContext *avctx, TiffContext *const s = avctx->priv_data; AVFrame *const p = data; ThreadFrame frame = { .f = data }; - unsigned off; + unsigned off, last_off; int le, ret, plane, planes; int i, j, entries, stride; unsigned soff, ssize; uint8_t *dst; GetByteContext stripsizes; GetByteContext stripdata; + int retry_for_subifd, retry_for_page; bytestream2_init(&s->gb, avpkt->data, avpkt->size); @@ -1235,10 +1420,16 @@ static int decode_frame(AVCodecContext *avctx, } s->le = le; // TIFF_BPP is not a required tag and defaults to 1 +again: + s->is_thumbnail = 0; s->bppcount = s->bpp = 1; s->photometric = TIFF_PHOTOMETRIC_NONE; s->compr = TIFF_RAW; s->fill_order = 0; + s->white_level = 0; + s->is_bayer = 0; + s->cur_page = 0; + s->tiff_type = TIFF_TYPE_TIFF; free_geotags(s); // Reset these offsets so we can tell if they were set this frame @@ -1253,6 +1444,42 @@ static int decode_frame(AVCodecContext *avctx, return ret; } + if (s->get_thumbnail && !s->is_thumbnail) { + av_log(avctx, AV_LOG_INFO, "No embedded thumbnail present\n"); + return AVERROR_EOF; + } + + /** whether we should process this IFD's SubIFD */ + retry_for_subifd = s->sub_ifd && (s->get_subimage || (!s->get_thumbnail && s->is_thumbnail)); + /** whether we should process this multi-page IFD's next page */ + retry_for_page = s->get_page && s->cur_page + 1 < s->get_page; // get_page is 1-indexed + + last_off = off; + if (retry_for_page) { + // set offset to the next IFD + off = ff_tget_long(&s->gb, le); + } else if (retry_for_subifd) { + // set offset to the SubIFD + off = s->sub_ifd; + } + + if (retry_for_subifd || retry_for_page) { + if (!off) { + av_log(avctx, AV_LOG_ERROR, "Requested entry not found\n"); + return AVERROR_INVALIDDATA; + } + if (off <= last_off) { + avpriv_request_sample(s->avctx, "non increasing IFD offset\n"); + return AVERROR_INVALIDDATA; + } + if (off >= UINT_MAX - 14 || avpkt->size < off + 14) { + av_log(avctx, AV_LOG_ERROR, "IFD offset is greater than image size\n"); + return AVERROR_INVALIDDATA; + } + s->sub_ifd = 0; + goto again; + } + for (i = 0; igeotag_count; i++) { const char *keyname = get_geokey_name(s->geotags[i].key); if (!keyname) { @@ -1303,8 +1530,19 @@ static int decode_frame(AVCodecContext *avctx, planes = s->planar ? s->bppcount : 1; for (plane = 0; plane < planes; plane++) { + uint8_t *five_planes = NULL; + int remaining = avpkt->size; + int decoded_height; stride = p->linesize[plane]; dst = p->data[plane]; + if (s->photometric == TIFF_PHOTOMETRIC_SEPARATED && + s->avctx->pix_fmt == AV_PIX_FMT_RGBA) { + stride = stride * 5 / 4; + five_planes = + dst = av_malloc(stride * s->height); + if (!dst) + return AVERROR(ENOMEM); + } for (i = 0; i < s->height; i += s->rps) { if (i) dst += s->rps * stride; @@ -1318,23 +1556,29 @@ static int decode_frame(AVCodecContext *avctx, else soff = s->stripoff; - if (soff > avpkt->size || ssize > avpkt->size - soff) { + if (soff > avpkt->size || ssize > avpkt->size - soff || ssize > remaining) { av_log(avctx, AV_LOG_ERROR, "Invalid strip size/offset\n"); + av_freep(&five_planes); return AVERROR_INVALIDDATA; } + remaining -= ssize; if ((ret = tiff_unpack_strip(s, p, dst, stride, avpkt->data + soff, ssize, i, FFMIN(s->rps, s->height - i))) < 0) { - if (avctx->err_recognition & AV_EF_EXPLODE) + if (avctx->err_recognition & AV_EF_EXPLODE) { + av_freep(&five_planes); return ret; + } break; } } + decoded_height = FFMIN(i, s->height); + if (s->predictor == 2) { if (s->photometric == TIFF_PHOTOMETRIC_YCBCR) { av_log(s->avctx, AV_LOG_ERROR, "predictor == 2 with YUV is unsupported"); return AVERROR_PATCHWELCOME; } - dst = p->data[plane]; + dst = five_planes ? five_planes : p->data[plane]; soff = s->bpp >> 3; if (s->planar) soff = FFMAX(soff / s->bppcount, 1); @@ -1345,7 +1589,7 @@ static int decode_frame(AVCodecContext *avctx, s->avctx->pix_fmt == AV_PIX_FMT_YA16LE || s->avctx->pix_fmt == AV_PIX_FMT_GBRP16LE || s->avctx->pix_fmt == AV_PIX_FMT_GBRAP16LE) { - for (i = 0; i < s->height; i++) { + for (i = 0; i < decoded_height; i++) { for (j = soff; j < ssize; j += 2) AV_WL16(dst + j, AV_RL16(dst + j) + AV_RL16(dst + j - soff)); dst += stride; @@ -1356,13 +1600,13 @@ static int decode_frame(AVCodecContext *avctx, s->avctx->pix_fmt == AV_PIX_FMT_YA16BE || s->avctx->pix_fmt == AV_PIX_FMT_GBRP16BE || s->avctx->pix_fmt == AV_PIX_FMT_GBRAP16BE) { - for (i = 0; i < s->height; i++) { + for (i = 0; i < decoded_height; i++) { for (j = soff; j < ssize; j += 2) AV_WB16(dst + j, AV_RB16(dst + j) + AV_RB16(dst + j - soff)); dst += stride; } } else { - for (i = 0; i < s->height; i++) { + for (i = 0; i < decoded_height; i++) { for (j = soff; j < ssize; j++) dst[j] += dst[j - soff]; dst += stride; @@ -1379,6 +1623,44 @@ static int decode_frame(AVCodecContext *avctx, dst += stride; } } + + if (s->photometric == TIFF_PHOTOMETRIC_SEPARATED && + (s->avctx->pix_fmt == AV_PIX_FMT_RGB0 || s->avctx->pix_fmt == AV_PIX_FMT_RGBA)) { + int x = s->avctx->pix_fmt == AV_PIX_FMT_RGB0 ? 4 : 5; + uint8_t *src = five_planes ? five_planes : p->data[plane]; + dst = p->data[plane]; + for (i = 0; i < s->height; i++) { + for (j = 0; j < s->width; j++) { + int k = 255 - src[x * j + 3]; + int r = (255 - src[x * j ]) * k; + int g = (255 - src[x * j + 1]) * k; + int b = (255 - src[x * j + 2]) * k; + dst[4 * j ] = r * 257 >> 16; + dst[4 * j + 1] = g * 257 >> 16; + dst[4 * j + 2] = b * 257 >> 16; + dst[4 * j + 3] = s->avctx->pix_fmt == AV_PIX_FMT_RGBA ? src[x * j + 4] : 255; + } + src += stride; + dst += p->linesize[plane]; + } + av_freep(&five_planes); + } else if (s->photometric == TIFF_PHOTOMETRIC_SEPARATED && + s->avctx->pix_fmt == AV_PIX_FMT_RGBA64BE) { + dst = p->data[plane]; + for (i = 0; i < s->height; i++) { + for (j = 0; j < s->width; j++) { + uint64_t k = 65535 - AV_RB16(dst + 8 * j + 6); + uint64_t r = (65535 - AV_RB16(dst + 8 * j )) * k; + uint64_t g = (65535 - AV_RB16(dst + 8 * j + 2)) * k; + uint64_t b = (65535 - AV_RB16(dst + 8 * j + 4)) * k; + AV_WB16(dst + 8 * j , r * 65537 >> 32); + AV_WB16(dst + 8 * j + 2, g * 65537 >> 32); + AV_WB16(dst + 8 * j + 4, b * 65537 >> 32); + AV_WB16(dst + 8 * j + 6, 65535); + } + dst += p->linesize[plane]; + } + } } if (s->planar && s->bppcount > 2) { @@ -1388,6 +1670,15 @@ static int decode_frame(AVCodecContext *avctx, FFSWAP(int, p->linesize[0], p->linesize[1]); } + if (s->is_bayer && s->white_level && s->bpp == 16) { + uint16_t *dst = (uint16_t *)p->data[0]; + for (i = 0; i < s->height; i++) { + for (j = 0; j < s->width; j++) + dst[j] = FFMIN((dst[j] / (float)s->white_level) * 65535, 65535); + dst += stride / 2; + } + } + *got_frame = 1; return avpkt->size; @@ -1403,6 +1694,8 @@ static av_cold int tiff_init(AVCodecContext *avctx) s->subsampling[1] = 1; s->avctx = avctx; ff_lzw_decode_open(&s->lzw); + if (!s->lzw) + return AVERROR(ENOMEM); ff_ccitt_unpack_init(); return 0; @@ -1417,11 +1710,28 @@ static av_cold int tiff_end(AVCodecContext *avctx) ff_lzw_decode_close(&s->lzw); av_freep(&s->deinvert_buf); s->deinvert_buf_size = 0; + av_freep(&s->yuv_line); + s->yuv_line_size = 0; av_freep(&s->fax_buffer); s->fax_buffer_size = 0; return 0; } +#define OFFSET(x) offsetof(TiffContext, x) +static const AVOption tiff_options[] = { + { "subimage", "decode subimage instead if available", OFFSET(get_subimage), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, AV_OPT_FLAG_DECODING_PARAM | AV_OPT_FLAG_VIDEO_PARAM }, + { "thumbnail", "decode embedded thumbnail subimage instead if available", OFFSET(get_thumbnail), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, AV_OPT_FLAG_DECODING_PARAM | AV_OPT_FLAG_VIDEO_PARAM }, + { "page", "page number of multi-page image to decode (starting from 1)", OFFSET(get_page), AV_OPT_TYPE_INT, {.i64=0}, 0, UINT16_MAX, AV_OPT_FLAG_DECODING_PARAM | AV_OPT_FLAG_VIDEO_PARAM }, + { NULL }, +}; + +static const AVClass tiff_decoder_class = { + .class_name = "TIFF decoder", + .item_name = av_default_item_name, + .option = tiff_options, + .version = LIBAVUTIL_VERSION_INT, +}; + AVCodec ff_tiff_decoder = { .name = "tiff", .long_name = NULL_IF_CONFIG_SMALL("TIFF image"), @@ -1433,4 +1743,5 @@ AVCodec ff_tiff_decoder = { .decode = decode_frame, .init_thread_copy = ONLY_IF_THREADS_ENABLED(tiff_init), .capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_FRAME_THREADS, + .priv_class = &tiff_decoder_class, }; diff --git a/libavcodec/tiff.h b/libavcodec/tiff.h index 3f692afa0..81913c6b1 100644 --- a/libavcodec/tiff.h +++ b/libavcodec/tiff.h @@ -20,7 +20,7 @@ /** * @file - * TIFF tables + * TIFF constants & data structures * * For more information about the TIFF format, check the official docs at: * http://partners.adobe.com/public/developer/tiff/index.html @@ -33,7 +33,17 @@ #include #include "tiff_common.h" -/** abridged list of TIFF tags */ +/** TIFF types in ascenting priority (last in the list is highest) */ +enum TiffType { + /** TIFF image based on the TIFF 6.0 or TIFF/EP (ISO 12234-2) specifications */ + TIFF_TYPE_TIFF, + /** Digital Negative (DNG) image */ + TIFF_TYPE_DNG, + /** Digital Negative (DNG) image part of an CinemaDNG image sequence */ + TIFF_TYPE_CINEMADNG, +}; + +/** abridged list of TIFF and TIFF/EP tags */ enum TiffTags { TIFF_SUBFILE = 0xfe, TIFF_WIDTH = 0x100, @@ -70,21 +80,40 @@ enum TiffTags { TIFF_TILE_LENGTH = 0x143, TIFF_TILE_OFFSETS = 0x144, TIFF_TILE_BYTE_COUNTS = 0x145, + TIFF_SUB_IFDS = 0x14A, TIFF_EXTRASAMPLES = 0x152, TIFF_YCBCR_COEFFICIENTS = 0x211, TIFF_YCBCR_SUBSAMPLING = 0x212, TIFF_YCBCR_POSITIONING = 0x213, TIFF_REFERENCE_BW = 0x214, + TIFF_CFA_PATTERN_DIM = 0x828D, + TIFF_CFA_PATTERN = 0x828E, TIFF_COPYRIGHT = 0x8298, TIFF_MODEL_TIEPOINT = 0x8482, TIFF_MODEL_PIXEL_SCALE = 0x830E, TIFF_MODEL_TRANSFORMATION= 0x8480, TIFF_GEO_KEY_DIRECTORY = 0x87AF, TIFF_GEO_DOUBLE_PARAMS = 0x87B0, - TIFF_GEO_ASCII_PARAMS = 0x87B1 + TIFF_GEO_ASCII_PARAMS = 0x87B1, }; -/** list of TIFF compression types */ +/** abridged list of DNG tags */ +enum DngTags { + DNG_VERSION = 0xC612, + DNG_BACKWARD_VERSION = 0xC613, + DNG_WHITE_LEVEL = 0xC61D, +}; + +/** list of CinemaDNG tags */ +enum CinemaDngTags { + CINEMADNG_TIME_CODES = 0xC763, + CINEMADNG_FRAME_RATE = 0xC764, + CINEMADNG_T_STOP = 0xC772, + CINEMADNG_REEL_NAME = 0xC789, + CINEMADNG_CAMERA_LABEL = 0xC7A1, +}; + +/** list of TIFF, TIFF/EP and DNG compression types */ enum TiffCompr { TIFF_RAW = 1, TIFF_CCITT_RLE, @@ -147,6 +176,7 @@ enum TiffGeoTagKey { TIFF_VERTICAL_UNITS_GEOKEY = 4099 }; +/** list of TIFF, TIFF/AP and DNG PhotometricInterpretation (TIFF_PHOTOMETRIC) values */ enum TiffPhotometric { TIFF_PHOTOMETRIC_NONE = -1, TIFF_PHOTOMETRIC_WHITE_IS_ZERO, /* mono or grayscale, 0 is white */ @@ -159,7 +189,7 @@ enum TiffPhotometric { TIFF_PHOTOMETRIC_CIE_LAB = 8, /* 1976 CIE L*a*b* */ TIFF_PHOTOMETRIC_ICC_LAB, /* ICC L*a*b* */ TIFF_PHOTOMETRIC_ITU_LAB, /* ITU L*a*b* */ - TIFF_PHOTOMETRIC_CFA = 32803, /* Color Filter Array (DNG) */ + TIFF_PHOTOMETRIC_CFA = 32803, /* Color Filter Array (TIFF/AP and DNG) */ TIFF_PHOTOMETRIC_LOG_L = 32844, /* CIE Log2(L) */ TIFF_PHOTOMETRIC_LOG_LUV, /* CIE Log L*u*v* */ TIFF_PHOTOMETRIC_LINEAR_RAW = 34892, /* Linear Raw (DNG) */ diff --git a/libavcodec/trace_headers_bsf.c b/libavcodec/trace_headers_bsf.c index 94a3ef72a..3ec78fe82 100644 --- a/libavcodec/trace_headers_bsf.c +++ b/libavcodec/trace_headers_bsf.c @@ -28,6 +28,7 @@ typedef struct TraceHeadersContext { CodedBitstreamContext *cbc; + CodedBitstreamFragment fragment; } TraceHeadersContext; @@ -44,33 +45,30 @@ static int trace_headers_init(AVBSFContext *bsf) ctx->cbc->trace_level = AV_LOG_INFO; if (bsf->par_in->extradata) { - CodedBitstreamFragment ps; + CodedBitstreamFragment *frag = &ctx->fragment; av_log(bsf, AV_LOG_INFO, "Extradata\n"); - err = ff_cbs_read_extradata(ctx->cbc, &ps, bsf->par_in); - if (err < 0) { - av_log(bsf, AV_LOG_ERROR, "Failed to read extradata.\n"); - return err; - } + err = ff_cbs_read_extradata(ctx->cbc, frag, bsf->par_in); - ff_cbs_fragment_uninit(ctx->cbc, &ps); + ff_cbs_fragment_reset(ctx->cbc, frag); } - return 0; + return err; } static void trace_headers_close(AVBSFContext *bsf) { TraceHeadersContext *ctx = bsf->priv_data; + ff_cbs_fragment_free(ctx->cbc, &ctx->fragment); ff_cbs_close(&ctx->cbc); } static int trace_headers(AVBSFContext *bsf, AVPacket *pkt) { TraceHeadersContext *ctx = bsf->priv_data; - CodedBitstreamFragment au; + CodedBitstreamFragment *frag = &ctx->fragment; char tmp[256] = { 0 }; int err; @@ -96,15 +94,13 @@ static int trace_headers(AVBSFContext *bsf, AVPacket *pkt) av_log(bsf, AV_LOG_INFO, "Packet: %d bytes%s.\n", pkt->size, tmp); - err = ff_cbs_read_packet(ctx->cbc, &au, pkt); - if (err < 0) { + err = ff_cbs_read_packet(ctx->cbc, frag, pkt); + + ff_cbs_fragment_reset(ctx->cbc, frag); + + if (err < 0) av_packet_unref(pkt); - return err; - } - - ff_cbs_fragment_uninit(ctx->cbc, &au); - - return 0; + return err; } const AVBitStreamFilter ff_trace_headers_bsf = { diff --git a/libavcodec/truehd_core_bsf.c b/libavcodec/truehd_core_bsf.c new file mode 100644 index 000000000..dbd05b34c --- /dev/null +++ b/libavcodec/truehd_core_bsf.c @@ -0,0 +1,184 @@ +/* + * Copyright (c) 2018 Paul B Mahol + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "avcodec.h" +#include "bsf.h" +#include "get_bits.h" +#include "mlp_parse.h" +#include "mlp.h" + +typedef struct AccessUnit { + uint8_t bits[4]; + uint16_t offset; + uint16_t optional; +} AccessUnit; + +typedef struct TrueHDCoreContext { + const AVClass *class; + + MLPHeaderInfo hdr; +} TrueHDCoreContext; + +static int truehd_core_filter(AVBSFContext *ctx, AVPacket *pkt) +{ + TrueHDCoreContext *s = ctx->priv_data; + GetBitContext gbc; + AccessUnit units[MAX_SUBSTREAMS]; + int ret, i, last_offset = 0; + int in_size, out_size; + int have_header = 0; + int substream_bytes = 0; + int end; + + ret = ff_bsf_get_packet_ref(ctx, pkt); + if (ret < 0) + return ret; + + if (pkt->size < 4) { + ret = AVERROR_INVALIDDATA; + goto fail; + } + + in_size = (AV_RB16(pkt->data) & 0xFFF) * 2; + if (in_size < 4 || in_size > pkt->size) { + ret = AVERROR_INVALIDDATA; + goto fail; + } + + ret = init_get_bits8(&gbc, pkt->data + 4, pkt->size - 4); + if (ret < 0) + goto fail; + + if (show_bits_long(&gbc, 32) == 0xf8726fba) { + if ((ret = ff_mlp_read_major_sync(ctx, &s->hdr, &gbc)) < 0) + goto fail; + have_header = 1; + } + + if (s->hdr.num_substreams > MAX_SUBSTREAMS) { + ret = AVERROR_INVALIDDATA; + goto fail; + } + + for (i = 0; i < s->hdr.num_substreams; i++) { + for (int j = 0; j < 4; j++) + units[i].bits[j] = get_bits1(&gbc); + + units[i].offset = get_bits(&gbc, 12); + if (i < 3) { + last_offset = units[i].offset * 2; + substream_bytes += 2; + } + + if (units[i].bits[0]) { + units[i].optional = get_bits(&gbc, 16); + if (i < 3) + substream_bytes += 2; + } + } + end = get_bits_count(&gbc) >> 3; + + out_size = end + 4 + last_offset; + if (out_size < in_size) { + int bpos = 0, reduce = end - have_header * 28 - substream_bytes; + uint16_t parity_nibble, dts = AV_RB16(pkt->data + 2); + uint16_t auheader; + uint8_t header[28]; + + av_assert1(reduce >= 0 && reduce % 2 == 0); + + if (have_header) { + memcpy(header, pkt->data + 4, 28); + header[16] = (header[16] & 0x0c) | (FFMIN(s->hdr.num_substreams, 3) << 4); + header[17] &= 0x7f; + header[25] &= 0xfe; + AV_WL16(header + 26, ff_mlp_checksum16(header, 26)); + } + + pkt->data += reduce; + out_size -= reduce; + pkt->size = out_size; + + ret = av_packet_make_writable(pkt); + if (ret < 0) + goto fail; + + AV_WB16(pkt->data + 2, dts); + parity_nibble = dts; + parity_nibble ^= out_size / 2; + + for (i = 0; i < FFMIN(s->hdr.num_substreams, 3); i++) { + uint16_t substr_hdr = 0; + + substr_hdr |= (units[i].bits[0] << 15); + substr_hdr |= (units[i].bits[1] << 14); + substr_hdr |= (units[i].bits[2] << 13); + substr_hdr |= (units[i].bits[3] << 12); + substr_hdr |= units[i].offset; + + AV_WB16(pkt->data + have_header * 28 + 4 + bpos, substr_hdr); + + parity_nibble ^= substr_hdr; + bpos += 2; + + if (units[i].bits[0]) { + AV_WB16(pkt->data + have_header * 28 + 4 + bpos, units[i].optional); + + parity_nibble ^= units[i].optional; + bpos += 2; + } + } + + parity_nibble ^= parity_nibble >> 8; + parity_nibble ^= parity_nibble >> 4; + parity_nibble &= 0xF; + + auheader = (parity_nibble ^ 0xF) << 12; + auheader |= (out_size / 2) & 0x0fff; + AV_WB16(pkt->data, auheader); + + if (have_header) + memcpy(pkt->data + 4, header, 28); + } + +fail: + if (ret < 0) + av_packet_unref(pkt); + + return ret; +} + +static void truehd_core_flush(AVBSFContext *ctx) +{ + TrueHDCoreContext *s = ctx->priv_data; + memset(&s->hdr, 0, sizeof(s->hdr)); +} + +static const enum AVCodecID codec_ids[] = { + AV_CODEC_ID_TRUEHD, AV_CODEC_ID_NONE, +}; + +const AVBitStreamFilter ff_truehd_core_bsf = { + .name = "truehd_core", + .priv_data_size = sizeof(TrueHDCoreContext), + .filter = truehd_core_filter, + .flush = truehd_core_flush, + .codec_ids = codec_ids, +}; diff --git a/libavcodec/truemotion2.c b/libavcodec/truemotion2.c index bc3f16827..27c876fd7 100644 --- a/libavcodec/truemotion2.c +++ b/libavcodec/truemotion2.c @@ -112,9 +112,13 @@ typedef struct TM2Huff { int *lens; ///< codelengths } TM2Huff; +/** + * + * @returns the length of the longest code or an AVERROR code + */ static int tm2_read_tree(TM2Context *ctx, uint32_t prefix, int length, TM2Huff *huff) { - int ret; + int ret, ret2; if (length > huff->max_bits) { av_log(ctx->avctx, AV_LOG_ERROR, "Tree exceeded its given depth (%i)\n", huff->max_bits); @@ -133,14 +137,14 @@ static int tm2_read_tree(TM2Context *ctx, uint32_t prefix, int length, TM2Huff * huff->bits[huff->num] = prefix; huff->lens[huff->num] = length; huff->num++; - return 0; + return length; } else { /* non-terminal node */ - if ((ret = tm2_read_tree(ctx, prefix << 1, length + 1, huff)) < 0) - return ret; + if ((ret2 = tm2_read_tree(ctx, prefix << 1, length + 1, huff)) < 0) + return ret2; if ((ret = tm2_read_tree(ctx, (prefix << 1) | 1, length + 1, huff)) < 0) return ret; } - return 0; + return FFMAX(ret, ret2); } static int tm2_build_huff_table(TM2Context *ctx, TM2Codes *code) @@ -183,6 +187,11 @@ static int tm2_build_huff_table(TM2Context *ctx, TM2Codes *code) res = tm2_read_tree(ctx, 0, 0, &huff); + if (res >= 0 && res != huff.max_bits) { + av_log(ctx->avctx, AV_LOG_ERROR, "Got less bits than expected: %i of %i\n", + res, huff.max_bits); + res = AVERROR_INVALIDDATA; + } if (huff.num != huff.max_num) { av_log(ctx->avctx, AV_LOG_ERROR, "Got less codes than expected: %i of %i\n", huff.num, huff.max_num); @@ -377,6 +386,10 @@ static int tm2_read_stream(TM2Context *ctx, const uint8_t *buf, int stream_id, i } } } else { + if (len < 0) { + ret = AVERROR_INVALIDDATA; + goto end; + } for (i = 0; i < toks; i++) { ctx->tokens[stream_id][i] = codes.recode[0]; if (stream_id <= TM2_MOT && ctx->tokens[stream_id][i] >= TM2_DELTAS) { @@ -606,7 +619,7 @@ static inline void tm2_null_res_block(TM2Context *ctx, AVFrame *pic, int bx, int ct = ctx->D[0] + ctx->D[1] + ctx->D[2] + ctx->D[3]; if (bx > 0) - left = last[-1] - ct; + left = last[-1] - (unsigned)ct; else left = 0; @@ -617,7 +630,7 @@ static inline void tm2_null_res_block(TM2Context *ctx, AVFrame *pic, int bx, int last[2] = right - (diff >> 2); last[3] = right; { - int tp = left; + unsigned tp = left; ctx->D[0] = (tp + (ct >> 2)) - left; left += ctx->D[0]; @@ -668,14 +681,14 @@ static inline void tm2_still_block(TM2Context *ctx, AVFrame *pic, int bx, int by static inline void tm2_update_block(TM2Context *ctx, AVFrame *pic, int bx, int by) { int i, j; - int d; + unsigned d; TM2_INIT_POINTERS_2(); /* update chroma */ for (j = 0; j < 2; j++) { for (i = 0; i < 2; i++) { - U[i] = Uo[i] + GET_TOK(ctx, TM2_UPD); - V[i] = Vo[i] + GET_TOK(ctx, TM2_UPD); + U[i] = Uo[i] + (unsigned)GET_TOK(ctx, TM2_UPD); + V[i] = Vo[i] + (unsigned)GET_TOK(ctx, TM2_UPD); } U += Ustride; V += Vstride; @@ -688,15 +701,15 @@ static inline void tm2_update_block(TM2Context *ctx, AVFrame *pic, int bx, int b TM2_RECALC_BLOCK(V, Vstride, (clast + 2), (ctx->CD + 2)); /* update deltas */ - ctx->D[0] = Yo[3] - last[3]; - ctx->D[1] = Yo[3 + oYstride] - Yo[3]; - ctx->D[2] = Yo[3 + oYstride * 2] - Yo[3 + oYstride]; - ctx->D[3] = Yo[3 + oYstride * 3] - Yo[3 + oYstride * 2]; + ctx->D[0] = (unsigned)Yo[3] - last[3]; + ctx->D[1] = (unsigned)Yo[3 + oYstride] - Yo[3]; + ctx->D[2] = (unsigned)Yo[3 + oYstride * 2] - Yo[3 + oYstride]; + ctx->D[3] = (unsigned)Yo[3 + oYstride * 3] - Yo[3 + oYstride * 2]; for (j = 0; j < 4; j++) { d = last[3]; for (i = 0; i < 4; i++) { - Y[i] = Yo[i] + GET_TOK(ctx, TM2_UPD); + Y[i] = Yo[i] + (unsigned)GET_TOK(ctx, TM2_UPD); last[i] = Y[i]; } ctx->D[j] = last[3] - d; @@ -751,10 +764,10 @@ static inline void tm2_motion_block(TM2Context *ctx, AVFrame *pic, int bx, int b } /* calculate deltas */ Y -= Ystride * 4; - ctx->D[0] = Y[3] - last[3]; - ctx->D[1] = Y[3 + Ystride] - Y[3]; - ctx->D[2] = Y[3 + Ystride * 2] - Y[3 + Ystride]; - ctx->D[3] = Y[3 + Ystride * 3] - Y[3 + Ystride * 2]; + ctx->D[0] = (unsigned)Y[3] - last[3]; + ctx->D[1] = (unsigned)Y[3 + Ystride] - Y[3]; + ctx->D[2] = (unsigned)Y[3 + Ystride * 2] - Y[3 + Ystride]; + ctx->D[3] = (unsigned)Y[3 + Ystride * 3] - Y[3 + Ystride * 2]; for (i = 0; i < 4; i++) last[i] = Y[i + Ystride * 3]; } @@ -824,7 +837,7 @@ static int tm2_decode_blocks(TM2Context *ctx, AVFrame *p) dst = p->data[0]; for (j = 0; j < h; j++) { for (i = 0; i < w; i++) { - int y = Y[i], u = U[i >> 1], v = V[i >> 1]; + unsigned y = Y[i], u = U[i >> 1], v = V[i >> 1]; dst[3*i+0] = av_clip_uint8(y + v); dst[3*i+1] = av_clip_uint8(y); dst[3*i+2] = av_clip_uint8(y + u); diff --git a/libavcodec/tscc.c b/libavcodec/tscc.c index cb86b584c..fc1ec4de0 100644 --- a/libavcodec/tscc.c +++ b/libavcodec/tscc.c @@ -69,9 +69,19 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, CamtasiaContext * const c = avctx->priv_data; AVFrame *frame = c->frame; int ret; + int palette_has_changed = 0; - if ((ret = ff_reget_buffer(avctx, frame)) < 0) - return ret; + if (c->avctx->pix_fmt == AV_PIX_FMT_PAL8) { + int size; + const uint8_t *pal = av_packet_get_side_data(avpkt, AV_PKT_DATA_PALETTE, &size); + + if (pal && size == AVPALETTE_SIZE) { + palette_has_changed = 1; + memcpy(c->pal, pal, AVPALETTE_SIZE); + } else if (pal) { + av_log(avctx, AV_LOG_ERROR, "Palette size %d is wrong\n", size); + } + } ret = inflateReset(&c->zstream); if (ret != Z_OK) { @@ -84,11 +94,17 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, c->zstream.avail_out = c->decomp_size; ret = inflate(&c->zstream, Z_FINISH); // Z_DATA_ERROR means empty picture + if (ret == Z_DATA_ERROR && !palette_has_changed) { + return buf_size; + } + if ((ret != Z_OK) && (ret != Z_STREAM_END) && (ret != Z_DATA_ERROR)) { av_log(avctx, AV_LOG_ERROR, "Inflate error: %d\n", ret); return AVERROR_UNKNOWN; } + if ((ret = ff_reget_buffer(avctx, frame)) < 0) + return ret; if (ret != Z_DATA_ERROR) { bytestream2_init(&c->gb, c->decomp_buf, @@ -98,15 +114,7 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, /* make the palette available on the way out */ if (c->avctx->pix_fmt == AV_PIX_FMT_PAL8) { - int size; - const uint8_t *pal = av_packet_get_side_data(avpkt, AV_PKT_DATA_PALETTE, &size); - - if (pal && size == AVPALETTE_SIZE) { - frame->palette_has_changed = 1; - memcpy(c->pal, pal, AVPALETTE_SIZE); - } else if (pal) { - av_log(avctx, AV_LOG_ERROR, "Palette size %d is wrong\n", size); - } + frame->palette_has_changed = palette_has_changed; memcpy(frame->data[1], c->pal, AVPALETTE_SIZE); } @@ -161,6 +169,8 @@ static av_cold int decode_init(AVCodecContext *avctx) } c->frame = av_frame_alloc(); + if (!c->frame) + return AVERROR(ENOMEM); return 0; } @@ -187,4 +197,5 @@ AVCodec ff_tscc_decoder = { .close = decode_end, .decode = decode_frame, .capabilities = AV_CODEC_CAP_DR1, + .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; diff --git a/libavcodec/tta.c b/libavcodec/tta.c index 8f097b3bc..304f3a81d 100644 --- a/libavcodec/tta.c +++ b/libavcodec/tta.c @@ -163,7 +163,7 @@ static av_cold int tta_decode_init(AVCodecContext * avctx) s->data_length = get_bits_long(&gb, 32); skip_bits_long(&gb, 32); // CRC32 of header - if (s->channels == 0) { + if (s->channels == 0 || s->channels > 16) { av_log(avctx, AV_LOG_ERROR, "Invalid number of channels\n"); return AVERROR_INVALIDDATA; } else if (avctx->sample_rate == 0) { @@ -227,7 +227,7 @@ static int tta_decode_frame(AVCodecContext *avctx, void *data, GetBitContext gb; int i, ret; int cur_chan = 0, framelen = s->frame_length; - int32_t *p; + uint32_t *p; if (avctx->err_recognition & AV_EF_CRCCHECK) { if (buf_size < 4 || @@ -261,7 +261,7 @@ static int tta_decode_frame(AVCodecContext *avctx, void *data, } i = 0; - for (p = s->decode_buffer; p < s->decode_buffer + (framelen * s->channels); p++) { + for (p = s->decode_buffer; (int32_t*)p < s->decode_buffer + (framelen * s->channels); p++) { int32_t *predictor = &s->ch_ctx[cur_chan].predictor; TTAFilter *filter = &s->ch_ctx[cur_chan].filter; TTARice *rice = &s->ch_ctx[cur_chan].rice; @@ -334,7 +334,7 @@ static int tta_decode_frame(AVCodecContext *avctx, void *data, // decorrelate in case of multiple channels if (s->channels > 1) { int32_t *r = p - 1; - for (*p += *r / 2; r > p - s->channels; r--) + for (*p += *r / 2; r > (int32_t*)p - s->channels; r--) *r = *(r + 1) - *r; } cur_chan = 0; @@ -358,13 +358,13 @@ static int tta_decode_frame(AVCodecContext *avctx, void *data, switch (s->bps) { case 1: { uint8_t *samples = (uint8_t *)frame->data[0]; - for (p = s->decode_buffer; p < s->decode_buffer + (framelen * s->channels); p++) + for (p = s->decode_buffer; (int32_t*)p < s->decode_buffer + (framelen * s->channels); p++) *samples++ = *p + 0x80; break; } case 2: { int16_t *samples = (int16_t *)frame->data[0]; - for (p = s->decode_buffer; p < s->decode_buffer + (framelen * s->channels); p++) + for (p = s->decode_buffer; (int32_t*)p < s->decode_buffer + (framelen * s->channels); p++) *samples++ = *p; break; } @@ -372,7 +372,7 @@ static int tta_decode_frame(AVCodecContext *avctx, void *data, // shift samples for 24-bit sample format int32_t *samples = (int32_t *)frame->data[0]; for (i = 0; i < framelen * s->channels; i++) - *samples++ <<= 8; + *samples++ *= 256; // reset decode buffer s->decode_buffer = NULL; break; diff --git a/libavcodec/ulti.c b/libavcodec/ulti.c index 9e4c088b1..9318af064 100644 --- a/libavcodec/ulti.c +++ b/libavcodec/ulti.c @@ -62,7 +62,8 @@ static av_cold int ulti_decode_init(AVCodecContext *avctx) return 0; } -static av_cold int ulti_decode_end(AVCodecContext *avctx){ +static av_cold int ulti_decode_end(AVCodecContext *avctx) +{ UltimotionDecodeContext *s = avctx->priv_data; av_frame_free(&s->frame); diff --git a/libavcodec/utils.c b/libavcodec/utils.c index 59d41ccbb..a6a646636 100644 --- a/libavcodec/utils.c +++ b/libavcodec/utils.c @@ -214,6 +214,8 @@ void avcodec_align_dimensions2(AVCodecContext *s, int *width, int *height, case AV_PIX_FMT_YUVA422P9BE: case AV_PIX_FMT_YUVA422P10LE: case AV_PIX_FMT_YUVA422P10BE: + case AV_PIX_FMT_YUVA422P12LE: + case AV_PIX_FMT_YUVA422P12BE: case AV_PIX_FMT_YUVA422P16LE: case AV_PIX_FMT_YUVA422P16BE: case AV_PIX_FMT_YUV440P10LE: @@ -234,6 +236,8 @@ void avcodec_align_dimensions2(AVCodecContext *s, int *width, int *height, case AV_PIX_FMT_YUVA444P9BE: case AV_PIX_FMT_YUVA444P10LE: case AV_PIX_FMT_YUVA444P10BE: + case AV_PIX_FMT_YUVA444P12LE: + case AV_PIX_FMT_YUVA444P12BE: case AV_PIX_FMT_YUVA444P16LE: case AV_PIX_FMT_YUVA444P16BE: case AV_PIX_FMT_GBRP9LE: @@ -538,6 +542,7 @@ int attribute_align_arg ff_codec_open2_recursive(AVCodecContext *avctx, const AV int attribute_align_arg avcodec_open2(AVCodecContext *avctx, const AVCodec *codec, AVDictionary **options) { int ret = 0; + int codec_init_ok = 0; AVDictionary *tmp = NULL; const AVPixFmtDescriptor *pixdesc; @@ -674,6 +679,7 @@ int attribute_align_arg avcodec_open2(AVCodecContext *avctx, const AVCodec *code av_freep(&avctx->subtitle_header); if (avctx->channels > FF_SANE_NB_CHANNELS) { + av_log(avctx, AV_LOG_ERROR, "Too many channels: %d\n", avctx->channels); ret = AVERROR(EINVAL); goto free_and_end; } @@ -726,6 +732,12 @@ int attribute_align_arg avcodec_open2(AVCodecContext *avctx, const AVCodec *code goto free_and_end; } + if (av_codec_is_decoder(avctx->codec)) { + ret = ff_decode_bsfs_init(avctx); + if (ret < 0) + goto free_and_end; + } + if (HAVE_THREADS && !(avctx->internal->frame_thread_encoder && (avctx->active_thread_type&FF_THREAD_FRAME))) { ret = ff_thread_init(avctx); @@ -924,6 +936,7 @@ FF_ENABLE_DEPRECATION_WARNINGS if (ret < 0) { goto free_and_end; } + codec_init_ok = 1; } ret=0; @@ -951,6 +964,10 @@ FF_ENABLE_DEPRECATION_WARNINGS ret = AVERROR(EINVAL); goto free_and_end; } + if (avctx->bits_per_coded_sample < 0) { + ret = AVERROR(EINVAL); + goto free_and_end; + } if (avctx->sub_charenc) { if (avctx->codec_type != AVMEDIA_TYPE_SUBTITLE) { av_log(avctx, AV_LOG_ERROR, "Character encoding is only " @@ -1007,8 +1024,9 @@ end: return ret; free_and_end: - if (avctx->codec && - (avctx->codec->caps_internal & FF_CODEC_CAP_INIT_CLEANUP)) + if (avctx->codec && avctx->codec->close && + (codec_init_ok || + (avctx->codec->caps_internal & FF_CODEC_CAP_INIT_CLEANUP))) avctx->codec->close(avctx); if (codec->priv_class && codec->priv_data_size) @@ -1023,6 +1041,7 @@ FF_ENABLE_DEPRECATION_WARNINGS av_dict_free(&tmp); av_freep(&avctx->priv_data); + av_freep(&avctx->subtitle_header); if (avctx->internal) { av_frame_free(&avctx->internal->to_free); av_frame_free(&avctx->internal->compat_decode_frame); @@ -1031,6 +1050,7 @@ FF_ENABLE_DEPRECATION_WARNINGS av_packet_free(&avctx->internal->last_pkt_props); av_packet_free(&avctx->internal->ds.in_pkt); + ff_decode_bsfs_uninit(avctx); av_freep(&avctx->internal->pool); } @@ -1389,10 +1409,8 @@ const char *avcodec_profile_name(enum AVCodecID codec_id, int profile) unsigned avcodec_version(void) { -// av_assert0(AV_CODEC_ID_V410==164); av_assert0(AV_CODEC_ID_PCM_S8_PLANAR==65563); av_assert0(AV_CODEC_ID_ADPCM_G722==69660); -// av_assert0(AV_CODEC_ID_BMV_AUDIO==86071); av_assert0(AV_CODEC_ID_SRT==94216); av_assert0(LIBAVCODEC_VERSION_MICRO >= 100); @@ -1430,6 +1448,7 @@ int av_get_exact_bits_per_sample(enum AVCodecID codec_id) case AV_CODEC_ID_DSD_MSBF_PLANAR: case AV_CODEC_ID_PCM_ALAW: case AV_CODEC_ID_PCM_MULAW: + case AV_CODEC_ID_PCM_VIDC: case AV_CODEC_ID_PCM_S8: case AV_CODEC_ID_PCM_S8_PLANAR: case AV_CODEC_ID_PCM_U8: @@ -1536,6 +1555,7 @@ static int get_audio_frame_duration(enum AVCodecID id, int sr, int ch, int ba, case AV_CODEC_ID_GSM_MS: return 320; case AV_CODEC_ID_MP1: return 384; case AV_CODEC_ID_ATRAC1: return 512; + case AV_CODEC_ID_ATRAC9: case AV_CODEC_ID_ATRAC3: return 1024 * framecount; case AV_CODEC_ID_ATRAC3P: return 2048; case AV_CODEC_ID_MP2: @@ -1585,8 +1605,6 @@ static int get_audio_frame_duration(enum AVCodecID id, int sr, int ch, int ba, return 256 * (frame_bytes / 64); if (id == AV_CODEC_ID_RA_144) return 160 * (frame_bytes / 20); - if (id == AV_CODEC_ID_G723_1) - return 240 * (frame_bytes / 24); if (bps > 0) { /* calc from frame_bytes and bits_per_coded_sample */ @@ -2195,3 +2213,22 @@ int64_t ff_guess_coded_bitrate(AVCodecContext *avctx) return bitrate; } + +int ff_int_from_list_or_default(void *ctx, const char * val_name, int val, + const int * array_valid_values, int default_value) +{ + int i = 0, ref_val; + + while (1) { + ref_val = array_valid_values[i]; + if (ref_val == INT_MAX) + break; + if (val == ref_val) + return val; + i++; + } + /* val is not a valid value */ + av_log(ctx, AV_LOG_DEBUG, + "%s %d are not supported. Set to default value : %d\n", val_name, val, default_value); + return default_value; +} diff --git a/libavcodec/utvideodec.c b/libavcodec/utvideodec.c index 82cb038cc..d5af9d53a 100644 --- a/libavcodec/utvideodec.c +++ b/libavcodec/utvideodec.c @@ -27,6 +27,7 @@ #include #include +#define CACHED_BITSTREAM_READER !ARCH_X86_32 #define UNCHECKED_BITSTREAM_READER 1 #include "libavutil/intreadwrite.h" @@ -257,11 +258,11 @@ static int decode_plane(UtvideoContext *c, int plane_no, GetBitContext cbit, pbit; uint8_t *dest, *p; - ret = init_get_bits8(&cbit, c->control_stream[plane_no][slice], c->control_stream_size[plane_no][slice]); + ret = init_get_bits8_le(&cbit, c->control_stream[plane_no][slice], c->control_stream_size[plane_no][slice]); if (ret < 0) return ret; - ret = init_get_bits8(&pbit, c->packed_stream[plane_no][slice], c->packed_stream_size[plane_no][slice]); + ret = init_get_bits8_le(&pbit, c->packed_stream[plane_no][slice], c->packed_stream_size[plane_no][slice]); if (ret < 0) return ret; diff --git a/libavcodec/v210dec.c b/libavcodec/v210dec.c index 99199ddc1..5a33d8c08 100644 --- a/libavcodec/v210dec.c +++ b/libavcodec/v210dec.c @@ -27,6 +27,7 @@ #include "libavutil/bswap.h" #include "libavutil/internal.h" #include "libavutil/mem.h" +#include "libavutil/intreadwrite.h" #define READ_PIXELS(a, b, c) \ do { \ @@ -49,6 +50,13 @@ static void v210_planar_unpack_c(const uint32_t *src, uint16_t *y, uint16_t *u, } } +av_cold void ff_v210dec_init(V210DecContext *s) +{ + s->unpack_frame = v210_planar_unpack_c; + if (ARCH_X86) + ff_v210_x86_init(s); +} + static av_cold int decode_init(AVCodecContext *avctx) { V210DecContext *s = avctx->priv_data; @@ -56,10 +64,8 @@ static av_cold int decode_init(AVCodecContext *avctx) avctx->pix_fmt = AV_PIX_FMT_YUV422P10; avctx->bits_per_raw_sample = 10; - s->unpack_frame = v210_planar_unpack_c; - - if (HAVE_MMX) - ff_v210_x86_init(s); + s->aligned_input = 0; + ff_v210dec_init(s); return 0; } @@ -92,12 +98,16 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, return AVERROR_INVALIDDATA; } } + if ( avctx->codec_tag == MKTAG('C', '2', '1', '0') + && avpkt->size > 64 + && AV_RN32(psrc) == AV_RN32("INFO") + && avpkt->size - 64 >= stride * avctx->height) + psrc += 64; - aligned_input = !((uintptr_t)psrc & 0xf) && !(stride & 0xf); + aligned_input = !((uintptr_t)psrc & 0x1f) && !(stride & 0x1f); if (aligned_input != s->aligned_input) { s->aligned_input = aligned_input; - if (HAVE_MMX) - ff_v210_x86_init(s); + ff_v210dec_init(s); } if ((ret = ff_get_buffer(avctx, pic, 0)) < 0) @@ -113,7 +123,7 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, const uint32_t *src = (const uint32_t*)psrc; uint32_t val; - w = (avctx->width / 6) * 6; + w = (avctx->width / 12) * 12; s->unpack_frame(src, y, u, v, w); y += w; @@ -121,6 +131,14 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, v += w >> 1; src += (w << 1) / 3; + if (w < avctx->width - 5) { + READ_PIXELS(u, y, v); + READ_PIXELS(y, u, y); + READ_PIXELS(v, y, u); + READ_PIXELS(y, v, y); + w += 6; + } + if (w < avctx->width - 1) { READ_PIXELS(u, y, v); diff --git a/libavcodec/v210dec.h b/libavcodec/v210dec.h index 533afc435..cfdb29da0 100644 --- a/libavcodec/v210dec.h +++ b/libavcodec/v210dec.h @@ -31,6 +31,7 @@ typedef struct { void (*unpack_frame)(const uint32_t *src, uint16_t *y, uint16_t *u, uint16_t *v, int width); } V210DecContext; +void ff_v210dec_init(V210DecContext *s); void ff_v210_x86_init(V210DecContext *s); #endif /* AVCODEC_V210DEC_H */ diff --git a/libavcodec/v210enc.c b/libavcodec/v210enc.c index a6afbbfc4..b024806d0 100644 --- a/libavcodec/v210enc.c +++ b/libavcodec/v210enc.c @@ -123,6 +123,7 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt, int aligned_width = ((avctx->width + 47) / 48) * 48; int stride = aligned_width * 8 / 3; int line_padding = stride - ((avctx->width * 8 + 11) / 12) * 4; + AVFrameSideData *side_data; int h, w, ret; uint8_t *dst; @@ -233,6 +234,22 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt, } } + side_data = av_frame_get_side_data(pic, AV_FRAME_DATA_A53_CC); + if (side_data && side_data->size) { + uint8_t *buf = av_packet_new_side_data(pkt, AV_PKT_DATA_A53_CC, side_data->size); + if (!buf) + return AVERROR(ENOMEM); + memcpy(buf, side_data->data, side_data->size); + } + + side_data = av_frame_get_side_data(pic, AV_FRAME_DATA_AFD); + if (side_data && side_data->size) { + uint8_t *buf = av_packet_new_side_data(pkt, AV_PKT_DATA_AFD, side_data->size); + if (!buf) + return AVERROR(ENOMEM); + memcpy(buf, side_data->data, side_data->size); + } + pkt->flags |= AV_PKT_FLAG_KEY; *got_packet = 1; return 0; diff --git a/libavcodec/v4l2_buffers.h b/libavcodec/v4l2_buffers.h index dc5cc9e26..7a57caf94 100644 --- a/libavcodec/v4l2_buffers.h +++ b/libavcodec/v4l2_buffers.h @@ -72,7 +72,7 @@ typedef struct V4L2Buffer { * @param[in] buf The V4L2Buffer to get the information from * * @returns 0 in case of success, AVERROR(EINVAL) if the number of planes is incorrect, - * AVERROR(ENOMEM) if the AVBufferRef cant be created. + * AVERROR(ENOMEM) if the AVBufferRef can't be created. */ int ff_v4l2_buffer_buf_to_avframe(AVFrame *frame, V4L2Buffer *buf); @@ -83,7 +83,7 @@ int ff_v4l2_buffer_buf_to_avframe(AVFrame *frame, V4L2Buffer *buf); * @param[in] buf The V4L2Buffer to get the information from * * @returns 0 in case of success, AVERROR(EINVAL) if the number of planes is incorrect, - * AVERROR(ENOMEM) if the AVBufferRef cant be created. + * AVERROR(ENOMEM) if the AVBufferRef can't be created. * */ int ff_v4l2_buffer_buf_to_avpkt(AVPacket *pkt, V4L2Buffer *buf); diff --git a/libavcodec/v4l2_m2m_dec.c b/libavcodec/v4l2_m2m_dec.c index bca45be14..d0601f0e2 100644 --- a/libavcodec/v4l2_m2m_dec.c +++ b/libavcodec/v4l2_m2m_dec.c @@ -149,11 +149,14 @@ static int v4l2_receive_frame(AVCodecContext *avctx, AVFrame *frame) if (avpkt.size) { ret = v4l2_try_start(avctx); - if (ret) + if (ret) { + av_packet_unref(&avpkt); return 0; + } } dequeue: + av_packet_unref(&avpkt); return ff_v4l2_context_dequeue_frame(capture, frame); } @@ -185,7 +188,11 @@ static av_cold int v4l2_decode_init(AVCodecContext *avctx) ret = ff_v4l2_m2m_codec_init(avctx); if (ret) { + V4L2m2mPriv *priv = avctx->priv_data; av_log(avctx, AV_LOG_ERROR, "can't configure decoder\n"); + s->self_ref = NULL; + av_buffer_unref(&priv->context_ref); + return ret; } @@ -221,7 +228,8 @@ AVCodec ff_ ## NAME ## _v4l2m2m_decoder = { \ .receive_frame = v4l2_receive_frame,\ .close = ff_v4l2_m2m_codec_end,\ .bsfs = bsf_name, \ - .capabilities = AV_CODEC_CAP_HARDWARE | AV_CODEC_CAP_DELAY, \ + .capabilities = AV_CODEC_CAP_HARDWARE | AV_CODEC_CAP_DELAY | \ + AV_CODEC_CAP_AVOID_PROBING, \ .wrapper_name = "v4l2m2m", \ }; diff --git a/libavcodec/v4l2_m2m_enc.c b/libavcodec/v4l2_m2m_enc.c index 4c9ea1fd9..636e1a96d 100644 --- a/libavcodec/v4l2_m2m_enc.c +++ b/libavcodec/v4l2_m2m_enc.c @@ -48,7 +48,7 @@ static inline void v4l2_set_timeperframe(V4L2m2mContext *s, unsigned int num, un static inline void v4l2_set_ext_ctrl(V4L2m2mContext *s, unsigned int id, signed int value, const char *name) { - struct v4l2_ext_controls ctrls = { 0 }; + struct v4l2_ext_controls ctrls = { { 0 } }; struct v4l2_ext_control ctrl = { 0 }; /* set ctrls */ @@ -68,7 +68,7 @@ static inline void v4l2_set_ext_ctrl(V4L2m2mContext *s, unsigned int id, signed static inline int v4l2_get_ext_ctrl(V4L2m2mContext *s, unsigned int id, signed int *value, const char *name) { - struct v4l2_ext_controls ctrls = { 0 }; + struct v4l2_ext_controls ctrls = { { 0 } }; struct v4l2_ext_control ctrl = { 0 }; int ret; diff --git a/libavcodec/vaapi_decode.c b/libavcodec/vaapi_decode.c index d0a6b5817..69512e1d4 100644 --- a/libavcodec/vaapi_decode.c +++ b/libavcodec/vaapi_decode.c @@ -200,12 +200,8 @@ int ff_vaapi_decode_issue(AVCodecContext *avctx, AV_VAAPI_DRIVER_QUIRK_RENDER_PARAM_BUFFERS) ff_vaapi_decode_destroy_buffers(avctx, pic); - pic->nb_param_buffers = 0; - pic->nb_slices = 0; - pic->slices_allocated = 0; - av_freep(&pic->slice_buffers); - - return 0; + err = 0; + goto exit; fail_with_picture: vas = vaEndPicture(ctx->hwctx->display, ctx->va_context); @@ -216,6 +212,12 @@ fail_with_picture: fail: ff_vaapi_decode_destroy_buffers(avctx, pic); fail_at_end: +exit: + pic->nb_param_buffers = 0; + pic->nb_slices = 0; + pic->slices_allocated = 0; + av_freep(&pic->slice_buffers); + return err; } @@ -389,9 +391,7 @@ static const struct { MAP(VC1, VC1_MAIN, VC1Main ), MAP(VC1, VC1_COMPLEX, VC1Advanced ), MAP(VC1, VC1_ADVANCED, VC1Advanced ), -#if VA_CHECK_VERSION(0, 35, 0) MAP(VP8, UNKNOWN, VP8Version0_3 ), -#endif #if VA_CHECK_VERSION(0, 38, 0) MAP(VP9, VP9_0, VP9Profile0 ), #endif diff --git a/libavcodec/vaapi_encode.c b/libavcodec/vaapi_encode.c index 36c85a381..dd2a24de0 100644 --- a/libavcodec/vaapi_encode.c +++ b/libavcodec/vaapi_encode.c @@ -103,6 +103,29 @@ static int vaapi_encode_make_param_buffer(AVCodecContext *avctx, return 0; } +static int vaapi_encode_make_misc_param_buffer(AVCodecContext *avctx, + VAAPIEncodePicture *pic, + int type, + const void *data, size_t len) +{ + // Construct the buffer on the stack - 1KB is much larger than any + // current misc parameter buffer type (the largest is EncQuality at + // 224 bytes). + uint8_t buffer[1024]; + VAEncMiscParameterBuffer header = { + .type = type, + }; + size_t buffer_size = sizeof(header) + len; + av_assert0(buffer_size <= sizeof(buffer)); + + memcpy(buffer, &header, sizeof(header)); + memcpy(buffer + sizeof(header), data, len); + + return vaapi_encode_make_param_buffer(avctx, pic, + VAEncMiscParameterBufferType, + buffer, buffer_size); +} + static int vaapi_encode_wait(AVCodecContext *avctx, VAAPIEncodePicture *pic) { @@ -158,16 +181,10 @@ static int vaapi_encode_issue(AVCodecContext *avctx, av_log(avctx, AV_LOG_DEBUG, ".\n"); } - av_assert0(pic->input_available && !pic->encode_issued); + av_assert0(!pic->encode_issued); for (i = 0; i < pic->nb_refs; i++) { av_assert0(pic->refs[i]); - // If we are serialised then the references must have already - // completed. If not, they must have been issued but need not - // have completed yet. - if (ctx->issue_mode == ISSUE_MODE_SERIALISE_EVERYTHING) - av_assert0(pic->refs[i]->encode_complete); - else - av_assert0(pic->refs[i]->encode_issued); + av_assert0(pic->refs[i]->encode_issued); } av_log(avctx, AV_LOG_DEBUG, "Input surface is %#x.\n", pic->input_surface); @@ -207,19 +224,6 @@ static int vaapi_encode_issue(AVCodecContext *avctx, pic->nb_param_buffers = 0; - if (pic->encode_order == 0) { - // Global parameter buffers are set on the first picture only. - - for (i = 0; i < ctx->nb_global_params; i++) { - err = vaapi_encode_make_param_buffer(avctx, pic, - VAEncMiscParameterBufferType, - (char*)ctx->global_params[i], - ctx->global_params_size[i]); - if (err < 0) - goto fail; - } - } - if (pic->type == PICTURE_TYPE_IDR && ctx->codec->init_sequence_params) { err = vaapi_encode_make_param_buffer(avctx, pic, VAEncSequenceParameterBufferType, @@ -229,6 +233,17 @@ static int vaapi_encode_issue(AVCodecContext *avctx, goto fail; } + if (pic->type == PICTURE_TYPE_IDR) { + for (i = 0; i < ctx->nb_global_params; i++) { + err = vaapi_encode_make_misc_param_buffer(avctx, pic, + ctx->global_params_type[i], + ctx->global_params[i], + ctx->global_params_size[i]); + if (err < 0) + goto fail; + } + } + if (ctx->codec->init_picture_params) { err = ctx->codec->init_picture_params(avctx, pic); if (err < 0) { @@ -321,16 +336,60 @@ static int vaapi_encode_issue(AVCodecContext *avctx, } } + if (pic->nb_slices == 0) + pic->nb_slices = ctx->nb_slices; if (pic->nb_slices > 0) { + int rounding; + pic->slices = av_mallocz_array(pic->nb_slices, sizeof(*pic->slices)); if (!pic->slices) { err = AVERROR(ENOMEM); goto fail; } + + for (i = 0; i < pic->nb_slices; i++) + pic->slices[i].row_size = ctx->slice_size; + + rounding = ctx->slice_block_rows - ctx->nb_slices * ctx->slice_size; + if (rounding > 0) { + // Place rounding error at top and bottom of frame. + av_assert0(rounding < pic->nb_slices); + // Some Intel drivers contain a bug where the encoder will fail + // if the last slice is smaller than the one before it. Since + // that's straightforward to avoid here, just do so. + if (rounding <= 2) { + for (i = 0; i < rounding; i++) + ++pic->slices[i].row_size; + } else { + for (i = 0; i < (rounding + 1) / 2; i++) + ++pic->slices[pic->nb_slices - i - 1].row_size; + for (i = 0; i < rounding / 2; i++) + ++pic->slices[i].row_size; + } + } else if (rounding < 0) { + // Remove rounding error from last slice only. + av_assert0(rounding < ctx->slice_size); + pic->slices[pic->nb_slices - 1].row_size += rounding; + } } for (i = 0; i < pic->nb_slices; i++) { slice = &pic->slices[i]; slice->index = i; + if (i == 0) { + slice->row_start = 0; + slice->block_start = 0; + } else { + const VAAPIEncodeSlice *prev = &pic->slices[i - 1]; + slice->row_start = prev->row_start + prev->row_size; + slice->block_start = prev->block_start + prev->block_size; + } + slice->block_size = slice->row_size * ctx->slice_block_cols; + + av_log(avctx, AV_LOG_DEBUG, "Slice %d: %d-%d (%d rows), " + "%d-%d (%d blocks).\n", i, slice->row_start, + slice->row_start + slice->row_size - 1, slice->row_size, + slice->block_start, slice->block_start + slice->block_size - 1, + slice->block_size); if (ctx->codec->slice_params_size > 0) { slice->codec_slice_params = av_mallocz(ctx->codec->slice_params_size); @@ -424,10 +483,7 @@ static int vaapi_encode_issue(AVCodecContext *avctx, pic->encode_issued = 1; - if (ctx->issue_mode == ISSUE_MODE_SERIALISE_EVERYTHING) - return vaapi_encode_wait(avctx, pic); - else - return 0; + return 0; fail_with_picture: vaEndPicture(ctx->hwctx->display, ctx->va_context); @@ -528,14 +584,23 @@ static int vaapi_encode_discard(AVCodecContext *avctx, return 0; } -static VAAPIEncodePicture *vaapi_encode_alloc(void) +static VAAPIEncodePicture *vaapi_encode_alloc(AVCodecContext *avctx) { + VAAPIEncodeContext *ctx = avctx->priv_data; VAAPIEncodePicture *pic; pic = av_mallocz(sizeof(*pic)); if (!pic) return NULL; + if (ctx->codec->picture_priv_data_size > 0) { + pic->priv_data = av_mallocz(ctx->codec->picture_priv_data_size); + if (!pic->priv_data) { + av_freep(&pic); + return NULL; + } + } + pic->input_surface = VA_INVALID_ID; pic->recon_surface = VA_INVALID_ID; pic->output_buffer = VA_INVALID_ID; @@ -575,315 +640,349 @@ static int vaapi_encode_free(AVCodecContext *avctx, return 0; } -static int vaapi_encode_step(AVCodecContext *avctx, - VAAPIEncodePicture *target) +static void vaapi_encode_add_ref(AVCodecContext *avctx, + VAAPIEncodePicture *pic, + VAAPIEncodePicture *target, + int is_ref, int in_dpb, int prev) { - VAAPIEncodeContext *ctx = avctx->priv_data; - VAAPIEncodePicture *pic; - int i, err; + int refs = 0; - if (ctx->issue_mode == ISSUE_MODE_SERIALISE_EVERYTHING || - ctx->issue_mode == ISSUE_MODE_MINIMISE_LATENCY) { - // These two modes are equivalent, except that we wait for - // immediate completion on each operation if serialised. - - if (!target) { - // No target, nothing to do yet. - return 0; - } - - if (target->encode_complete) { - // Already done. - return 0; - } - - pic = target; - for (i = 0; i < pic->nb_refs; i++) { - if (!pic->refs[i]->encode_complete) { - err = vaapi_encode_step(avctx, pic->refs[i]); - if (err < 0) - return err; - } - } - - err = vaapi_encode_issue(avctx, pic); - if (err < 0) - return err; - - } else if (ctx->issue_mode == ISSUE_MODE_MAXIMISE_THROUGHPUT) { - int activity; - - // Run through the list of all available pictures repeatedly - // and issue the first one found which has all dependencies - // available (including previously-issued but not necessarily - // completed pictures). - do { - activity = 0; - for (pic = ctx->pic_start; pic; pic = pic->next) { - if (!pic->input_available || pic->encode_issued) - continue; - for (i = 0; i < pic->nb_refs; i++) { - if (!pic->refs[i]->encode_issued) - break; - } - if (i < pic->nb_refs) - continue; - err = vaapi_encode_issue(avctx, pic); - if (err < 0) - return err; - activity = 1; - // Start again from the beginning of the list, - // because issuing this picture may have satisfied - // forward dependencies of earlier ones. - break; - } - } while(activity); - - // If we had a defined target for this step then it will - // always have been issued by now. - if (target) { - av_assert0(target->encode_issued && "broken dependencies?"); - } - - } else { - av_assert0(0); + if (is_ref) { + av_assert0(pic != target); + av_assert0(pic->nb_refs < MAX_PICTURE_REFERENCES); + pic->refs[pic->nb_refs++] = target; + ++refs; } - return 0; + if (in_dpb) { + av_assert0(pic->nb_dpb_pics < MAX_DPB_SIZE); + pic->dpb[pic->nb_dpb_pics++] = target; + ++refs; + } + + if (prev) { + av_assert0(!pic->prev); + pic->prev = target; + ++refs; + } + + target->ref_count[0] += refs; + target->ref_count[1] += refs; } -static int vaapi_encode_get_next(AVCodecContext *avctx, - VAAPIEncodePicture **pic_out) +static void vaapi_encode_remove_refs(AVCodecContext *avctx, + VAAPIEncodePicture *pic, + int level) { - VAAPIEncodeContext *ctx = avctx->priv_data; - VAAPIEncodePicture *start, *end, *pic; int i; - for (pic = ctx->pic_start; pic; pic = pic->next) { - if (pic->next) - av_assert0(pic->display_order + 1 == pic->next->display_order); - if (pic->display_order == ctx->input_order) { - *pic_out = pic; - return 0; - } + if (pic->ref_removed[level]) + return; + + for (i = 0; i < pic->nb_refs; i++) { + av_assert0(pic->refs[i]); + --pic->refs[i]->ref_count[level]; + av_assert0(pic->refs[i]->ref_count[level] >= 0); } - pic = vaapi_encode_alloc(); - if (!pic) - return AVERROR(ENOMEM); - - if (ctx->input_order == 0 || ctx->force_idr || - ctx->gop_counter >= avctx->gop_size) { - pic->type = PICTURE_TYPE_IDR; - ctx->force_idr = 0; - ctx->gop_counter = 1; - ctx->p_counter = 0; - } else if (ctx->p_counter >= ctx->p_per_i) { - pic->type = PICTURE_TYPE_I; - ++ctx->gop_counter; - ctx->p_counter = 0; - } else { - pic->type = PICTURE_TYPE_P; - pic->refs[0] = ctx->pic_end; - pic->nb_refs = 1; - ++ctx->gop_counter; - ++ctx->p_counter; - } - start = end = pic; - - if (pic->type != PICTURE_TYPE_IDR) { - // If that was not an IDR frame, add B-frames display-before and - // encode-after it, but not exceeding the GOP size. - - for (i = 0; i < ctx->b_per_p && - ctx->gop_counter < avctx->gop_size; i++) { - pic = vaapi_encode_alloc(); - if (!pic) - goto fail; - - pic->type = PICTURE_TYPE_B; - pic->refs[0] = ctx->pic_end; - pic->refs[1] = end; - pic->nb_refs = 2; - - pic->next = start; - pic->display_order = ctx->input_order + ctx->b_per_p - i - 1; - pic->encode_order = pic->display_order + 1; - start = pic; - - ++ctx->gop_counter; - } + for (i = 0; i < pic->nb_dpb_pics; i++) { + av_assert0(pic->dpb[i]); + --pic->dpb[i]->ref_count[level]; + av_assert0(pic->dpb[i]->ref_count[level] >= 0); } - if (ctx->input_order == 0) { - pic->display_order = 0; - pic->encode_order = 0; - - ctx->pic_start = ctx->pic_end = pic; - - } else { - for (i = 0, pic = start; pic; i++, pic = pic->next) { - pic->display_order = ctx->input_order + i; - if (end->type == PICTURE_TYPE_IDR) - pic->encode_order = ctx->input_order + i; - else if (pic == end) - pic->encode_order = ctx->input_order; - else - pic->encode_order = ctx->input_order + i + 1; - } - - av_assert0(ctx->pic_end); - ctx->pic_end->next = start; - ctx->pic_end = end; + av_assert0(pic->prev || pic->type == PICTURE_TYPE_IDR); + if (pic->prev) { + --pic->prev->ref_count[level]; + av_assert0(pic->prev->ref_count[level] >= 0); } - *pic_out = start; - av_log(avctx, AV_LOG_DEBUG, "Pictures:"); - for (pic = ctx->pic_start; pic; pic = pic->next) { - av_log(avctx, AV_LOG_DEBUG, " %s (%"PRId64"/%"PRId64")", - picture_type_name[pic->type], - pic->display_order, pic->encode_order); - } - av_log(avctx, AV_LOG_DEBUG, "\n"); - - return 0; - -fail: - while (start) { - pic = start->next; - vaapi_encode_free(avctx, start); - start = pic; - } - return AVERROR(ENOMEM); + pic->ref_removed[level] = 1; } -static int vaapi_encode_truncate_gop(AVCodecContext *avctx) +static void vaapi_encode_set_b_pictures(AVCodecContext *avctx, + VAAPIEncodePicture *start, + VAAPIEncodePicture *end, + VAAPIEncodePicture *prev, + int current_depth, + VAAPIEncodePicture **last) { VAAPIEncodeContext *ctx = avctx->priv_data; - VAAPIEncodePicture *pic, *last_pic, *next; + VAAPIEncodePicture *pic, *next, *ref; + int i, len; - // Find the last picture we actually have input for. + av_assert0(start && end && start != end && start->next != end); + + // If we are at the maximum depth then encode all pictures as + // non-referenced B-pictures. Also do this if there is exactly one + // picture left, since there will be nothing to reference it. + if (current_depth == ctx->max_b_depth || start->next->next == end) { + for (pic = start->next; pic; pic = pic->next) { + if (pic == end) + break; + pic->type = PICTURE_TYPE_B; + pic->b_depth = current_depth; + + vaapi_encode_add_ref(avctx, pic, start, 1, 1, 0); + vaapi_encode_add_ref(avctx, pic, end, 1, 1, 0); + vaapi_encode_add_ref(avctx, pic, prev, 0, 0, 1); + + for (ref = end->refs[1]; ref; ref = ref->refs[1]) + vaapi_encode_add_ref(avctx, pic, ref, 0, 1, 0); + } + *last = prev; + + } else { + // Split the current list at the midpoint with a referenced + // B-picture, then descend into each side separately. + len = 0; + for (pic = start->next; pic != end; pic = pic->next) + ++len; + for (pic = start->next, i = 1; 2 * i < len; pic = pic->next, i++); + + pic->type = PICTURE_TYPE_B; + pic->b_depth = current_depth; + + pic->is_reference = 1; + + vaapi_encode_add_ref(avctx, pic, pic, 0, 1, 0); + vaapi_encode_add_ref(avctx, pic, start, 1, 1, 0); + vaapi_encode_add_ref(avctx, pic, end, 1, 1, 0); + vaapi_encode_add_ref(avctx, pic, prev, 0, 0, 1); + + for (ref = end->refs[1]; ref; ref = ref->refs[1]) + vaapi_encode_add_ref(avctx, pic, ref, 0, 1, 0); + + if (i > 1) + vaapi_encode_set_b_pictures(avctx, start, pic, pic, + current_depth + 1, &next); + else + next = pic; + + vaapi_encode_set_b_pictures(avctx, pic, end, next, + current_depth + 1, last); + } +} + +static int vaapi_encode_pick_next(AVCodecContext *avctx, + VAAPIEncodePicture **pic_out) +{ + VAAPIEncodeContext *ctx = avctx->priv_data; + VAAPIEncodePicture *pic = NULL, *next, *start; + int i, b_counter, closed_gop_end; + + // If there are any B-frames already queued, the next one to encode + // is the earliest not-yet-issued frame for which all references are + // available. for (pic = ctx->pic_start; pic; pic = pic->next) { - if (!pic->input_available) + if (pic->encode_issued) + continue; + if (pic->type != PICTURE_TYPE_B) + continue; + for (i = 0; i < pic->nb_refs; i++) { + if (!pic->refs[i]->encode_issued) + break; + } + if (i == pic->nb_refs) break; - last_pic = pic; } if (pic) { - av_assert0(last_pic); + av_log(avctx, AV_LOG_DEBUG, "Pick B-picture at depth %d to " + "encode next.\n", pic->b_depth); + *pic_out = pic; + return 0; + } - if (last_pic->type == PICTURE_TYPE_B) { - // Some fixing up is required. Change the type of this - // picture to P, then modify preceding B references which - // point beyond it to point at it instead. + // Find the B-per-Pth available picture to become the next picture + // on the top layer. + start = NULL; + b_counter = 0; + closed_gop_end = ctx->closed_gop || + ctx->idr_counter == ctx->gop_per_idr; + for (pic = ctx->pic_start; pic; pic = next) { + next = pic->next; + if (pic->encode_issued) { + start = pic; + continue; + } + // If the next available picture is force-IDR, encode it to start + // a new GOP immediately. + if (pic->force_idr) + break; + if (b_counter == ctx->b_per_p) + break; + // If this picture ends a closed GOP or starts a new GOP then it + // needs to be in the top layer. + if (ctx->gop_counter + b_counter + closed_gop_end >= ctx->gop_size) + break; + // If the picture after this one is force-IDR, we need to encode + // this one in the top layer. + if (next && next->force_idr) + break; + ++b_counter; + } - last_pic->type = PICTURE_TYPE_P; - last_pic->encode_order = last_pic->refs[1]->encode_order; + // At the end of the stream the last picture must be in the top layer. + if (!pic && ctx->end_of_stream) { + --b_counter; + pic = ctx->pic_end; + if (pic->encode_issued) + return AVERROR_EOF; + } - for (pic = ctx->pic_start; pic != last_pic; pic = pic->next) { - if (pic->type == PICTURE_TYPE_B && - pic->refs[1] == last_pic->refs[1]) - pic->refs[1] = last_pic; - } + if (!pic) { + av_log(avctx, AV_LOG_DEBUG, "Pick nothing to encode next - " + "need more input for reference pictures.\n"); + return AVERROR(EAGAIN); + } + if (ctx->input_order <= ctx->decode_delay && !ctx->end_of_stream) { + av_log(avctx, AV_LOG_DEBUG, "Pick nothing to encode next - " + "need more input for timestamps.\n"); + return AVERROR(EAGAIN); + } - last_pic->nb_refs = 1; - last_pic->refs[1] = NULL; + if (pic->force_idr) { + av_log(avctx, AV_LOG_DEBUG, "Pick forced IDR-picture to " + "encode next.\n"); + pic->type = PICTURE_TYPE_IDR; + ctx->idr_counter = 1; + ctx->gop_counter = 1; + + } else if (ctx->gop_counter + b_counter >= ctx->gop_size) { + if (ctx->idr_counter == ctx->gop_per_idr) { + av_log(avctx, AV_LOG_DEBUG, "Pick new-GOP IDR-picture to " + "encode next.\n"); + pic->type = PICTURE_TYPE_IDR; + ctx->idr_counter = 1; } else { - // We can use the current structure (no references point - // beyond the end), but there are unused pics to discard. + av_log(avctx, AV_LOG_DEBUG, "Pick new-GOP I-picture to " + "encode next.\n"); + pic->type = PICTURE_TYPE_I; + ++ctx->idr_counter; } - - // Discard all following pics, they will never be used. - for (pic = last_pic->next; pic; pic = next) { - next = pic->next; - vaapi_encode_free(avctx, pic); - } - - last_pic->next = NULL; - ctx->pic_end = last_pic; + ctx->gop_counter = 1; } else { - // Input is available for all pictures, so we don't need to - // mangle anything. + if (ctx->gop_counter + b_counter + closed_gop_end == ctx->gop_size) { + av_log(avctx, AV_LOG_DEBUG, "Pick group-end P-picture to " + "encode next.\n"); + } else { + av_log(avctx, AV_LOG_DEBUG, "Pick normal P-picture to " + "encode next.\n"); + } + pic->type = PICTURE_TYPE_P; + av_assert0(start); + ctx->gop_counter += 1 + b_counter; } + pic->is_reference = 1; + *pic_out = pic; - av_log(avctx, AV_LOG_DEBUG, "Pictures ending truncated GOP:"); - for (pic = ctx->pic_start; pic; pic = pic->next) { - av_log(avctx, AV_LOG_DEBUG, " %s (%"PRId64"/%"PRId64")", - picture_type_name[pic->type], - pic->display_order, pic->encode_order); + vaapi_encode_add_ref(avctx, pic, pic, 0, 1, 0); + if (pic->type != PICTURE_TYPE_IDR) { + vaapi_encode_add_ref(avctx, pic, start, + pic->type == PICTURE_TYPE_P, + b_counter > 0, 0); + vaapi_encode_add_ref(avctx, pic, ctx->next_prev, 0, 0, 1); } - av_log(avctx, AV_LOG_DEBUG, "\n"); + if (ctx->next_prev) + --ctx->next_prev->ref_count[0]; + if (b_counter > 0) { + vaapi_encode_set_b_pictures(avctx, start, pic, pic, 1, + &ctx->next_prev); + } else { + ctx->next_prev = pic; + } + ++ctx->next_prev->ref_count[0]; return 0; } static int vaapi_encode_clear_old(AVCodecContext *avctx) { VAAPIEncodeContext *ctx = avctx->priv_data; - VAAPIEncodePicture *pic, *old; - int i; + VAAPIEncodePicture *pic, *prev, *next; - while (ctx->pic_start != ctx->pic_end) { - old = ctx->pic_start; - if (old->encode_order > ctx->output_order) - break; + av_assert0(ctx->pic_start); - for (pic = old->next; pic; pic = pic->next) { - if (pic->encode_complete) - continue; - for (i = 0; i < pic->nb_refs; i++) { - if (pic->refs[i] == old) { - // We still need this picture because it's referred to - // directly by a later one, so it and all following - // pictures have to stay. - return 0; - } - } + // Remove direct references once each picture is complete. + for (pic = ctx->pic_start; pic; pic = pic->next) { + if (pic->encode_complete && pic->next) + vaapi_encode_remove_refs(avctx, pic, 0); + } + + // Remove indirect references once a picture has no direct references. + for (pic = ctx->pic_start; pic; pic = pic->next) { + if (pic->encode_complete && pic->ref_count[0] == 0) + vaapi_encode_remove_refs(avctx, pic, 1); + } + + // Clear out all complete pictures with no remaining references. + prev = NULL; + for (pic = ctx->pic_start; pic; pic = next) { + next = pic->next; + if (pic->encode_complete && pic->ref_count[1] == 0) { + av_assert0(pic->ref_removed[0] && pic->ref_removed[1]); + if (prev) + prev->next = next; + else + ctx->pic_start = next; + vaapi_encode_free(avctx, pic); + } else { + prev = pic; } - - pic = ctx->pic_start; - ctx->pic_start = pic->next; - vaapi_encode_free(avctx, pic); } return 0; } -int ff_vaapi_encode2(AVCodecContext *avctx, AVPacket *pkt, - const AVFrame *input_image, int *got_packet) +static int vaapi_encode_check_frame(AVCodecContext *avctx, + const AVFrame *frame) +{ + VAAPIEncodeContext *ctx = avctx->priv_data; + + if ((frame->crop_top || frame->crop_bottom || + frame->crop_left || frame->crop_right) && !ctx->crop_warned) { + av_log(avctx, AV_LOG_WARNING, "Cropping information on input " + "frames ignored due to lack of API support.\n"); + ctx->crop_warned = 1; + } + + return 0; +} + +int ff_vaapi_encode_send_frame(AVCodecContext *avctx, const AVFrame *frame) { VAAPIEncodeContext *ctx = avctx->priv_data; VAAPIEncodePicture *pic; int err; - if (input_image) { - av_log(avctx, AV_LOG_DEBUG, "Encode frame: %ux%u (%"PRId64").\n", - input_image->width, input_image->height, input_image->pts); + if (frame) { + av_log(avctx, AV_LOG_DEBUG, "Input frame: %ux%u (%"PRId64").\n", + frame->width, frame->height, frame->pts); - if (input_image->pict_type == AV_PICTURE_TYPE_I) { - err = vaapi_encode_truncate_gop(avctx); - if (err < 0) - goto fail; - ctx->force_idr = 1; - } - - err = vaapi_encode_get_next(avctx, &pic); - if (err) { - av_log(avctx, AV_LOG_ERROR, "Input setup failed: %d.\n", err); + err = vaapi_encode_check_frame(avctx, frame); + if (err < 0) return err; - } + + pic = vaapi_encode_alloc(avctx); + if (!pic) + return AVERROR(ENOMEM); pic->input_image = av_frame_alloc(); if (!pic->input_image) { err = AVERROR(ENOMEM); goto fail; } - err = av_frame_ref(pic->input_image, input_image); + err = av_frame_ref(pic->input_image, frame); if (err < 0) goto fail; - pic->input_surface = (VASurfaceID)(uintptr_t)input_image->data[3]; - pic->pts = input_image->pts; + + if (ctx->input_order == 0) + pic->force_idr = 1; + + pic->input_surface = (VASurfaceID)(uintptr_t)frame->data[3]; + pic->pts = frame->pts; if (ctx->input_order == 0) ctx->first_pts = pic->pts; @@ -892,310 +991,662 @@ int ff_vaapi_encode2(AVCodecContext *avctx, AVPacket *pkt, if (ctx->output_delay > 0) ctx->ts_ring[ctx->input_order % (3 * ctx->output_delay)] = pic->pts; - pic->input_available = 1; + pic->display_order = ctx->input_order; + ++ctx->input_order; - } else { - if (!ctx->end_of_stream) { - err = vaapi_encode_truncate_gop(avctx); - if (err < 0) - goto fail; - ctx->end_of_stream = 1; - } - } - - ++ctx->input_order; - ++ctx->output_order; - av_assert0(ctx->output_order + ctx->output_delay + 1 == ctx->input_order); - - for (pic = ctx->pic_start; pic; pic = pic->next) - if (pic->encode_order == ctx->output_order) - break; - - // pic can be null here if we don't have a specific target in this - // iteration. We might still issue encodes if things can be overlapped, - // even though we don't intend to output anything. - - err = vaapi_encode_step(avctx, pic); - if (err < 0) { - av_log(avctx, AV_LOG_ERROR, "Encode failed: %d.\n", err); - goto fail; - } - - if (!pic) { - *got_packet = 0; - } else { - err = vaapi_encode_output(avctx, pic, pkt); - if (err < 0) { - av_log(avctx, AV_LOG_ERROR, "Output failed: %d.\n", err); - goto fail; - } - - if (ctx->output_delay == 0) { - pkt->dts = pkt->pts; - } else if (ctx->output_order < ctx->decode_delay) { - if (ctx->ts_ring[ctx->output_order] < INT64_MIN + ctx->dts_pts_diff) - pkt->dts = INT64_MIN; - else - pkt->dts = ctx->ts_ring[ctx->output_order] - ctx->dts_pts_diff; + if (ctx->pic_start) { + ctx->pic_end->next = pic; + ctx->pic_end = pic; } else { - pkt->dts = ctx->ts_ring[(ctx->output_order - ctx->decode_delay) % - (3 * ctx->output_delay)]; + ctx->pic_start = pic; + ctx->pic_end = pic; } - *got_packet = 1; - } + } else { + ctx->end_of_stream = 1; - err = vaapi_encode_clear_old(avctx); - if (err < 0) { - av_log(avctx, AV_LOG_ERROR, "List clearing failed: %d.\n", err); - goto fail; + // Fix timestamps if we hit end-of-stream before the initial decode + // delay has elapsed. + if (ctx->input_order < ctx->decode_delay) + ctx->dts_pts_diff = ctx->pic_end->pts - ctx->first_pts; } return 0; fail: - // Unclear what to clean up on failure. There are probably some things we - // could do usefully clean up here, but for now just leave them for uninit() - // to do instead. return err; } -static av_cold int vaapi_encode_config_attributes(AVCodecContext *avctx) +int ff_vaapi_encode_receive_packet(AVCodecContext *avctx, AVPacket *pkt) { VAAPIEncodeContext *ctx = avctx->priv_data; + VAAPIEncodePicture *pic; + int err; + + if (!ctx->pic_start) { + if (ctx->end_of_stream) + return AVERROR_EOF; + else + return AVERROR(EAGAIN); + } + + pic = NULL; + err = vaapi_encode_pick_next(avctx, &pic); + if (err < 0) + return err; + av_assert0(pic); + + pic->encode_order = ctx->encode_order++; + + err = vaapi_encode_issue(avctx, pic); + if (err < 0) { + av_log(avctx, AV_LOG_ERROR, "Encode failed: %d.\n", err); + return err; + } + + err = vaapi_encode_output(avctx, pic, pkt); + if (err < 0) { + av_log(avctx, AV_LOG_ERROR, "Output failed: %d.\n", err); + return err; + } + + if (ctx->output_delay == 0) { + pkt->dts = pkt->pts; + } else if (pic->encode_order < ctx->decode_delay) { + if (ctx->ts_ring[pic->encode_order] < INT64_MIN + ctx->dts_pts_diff) + pkt->dts = INT64_MIN; + else + pkt->dts = ctx->ts_ring[pic->encode_order] - ctx->dts_pts_diff; + } else { + pkt->dts = ctx->ts_ring[(pic->encode_order - ctx->decode_delay) % + (3 * ctx->output_delay)]; + } + av_log(avctx, AV_LOG_DEBUG, "Output packet: pts %"PRId64" dts %"PRId64".\n", + pkt->pts, pkt->dts); + + ctx->output_order = pic->encode_order; + vaapi_encode_clear_old(avctx); + + return 0; +} + + +static av_cold void vaapi_encode_add_global_param(AVCodecContext *avctx, int type, + void *buffer, size_t size) +{ + VAAPIEncodeContext *ctx = avctx->priv_data; + + av_assert0(ctx->nb_global_params < MAX_GLOBAL_PARAMS); + + ctx->global_params_type[ctx->nb_global_params] = type; + ctx->global_params [ctx->nb_global_params] = buffer; + ctx->global_params_size[ctx->nb_global_params] = size; + + ++ctx->nb_global_params; +} + +typedef struct VAAPIEncodeRTFormat { + const char *name; + unsigned int value; + int depth; + int nb_components; + int log2_chroma_w; + int log2_chroma_h; +} VAAPIEncodeRTFormat; + +static const VAAPIEncodeRTFormat vaapi_encode_rt_formats[] = { + { "YUV400", VA_RT_FORMAT_YUV400, 8, 1, }, + { "YUV420", VA_RT_FORMAT_YUV420, 8, 3, 1, 1 }, + { "YUV422", VA_RT_FORMAT_YUV422, 8, 3, 1, 0 }, + { "YUV444", VA_RT_FORMAT_YUV444, 8, 3, 0, 0 }, + { "YUV411", VA_RT_FORMAT_YUV411, 8, 3, 2, 0 }, +#if VA_CHECK_VERSION(0, 38, 1) + { "YUV420_10", VA_RT_FORMAT_YUV420_10BPP, 10, 3, 1, 1 }, +#endif +}; + +static const VAEntrypoint vaapi_encode_entrypoints_normal[] = { + VAEntrypointEncSlice, + VAEntrypointEncPicture, +#if VA_CHECK_VERSION(0, 39, 2) + VAEntrypointEncSliceLP, +#endif + 0 +}; +#if VA_CHECK_VERSION(0, 39, 2) +static const VAEntrypoint vaapi_encode_entrypoints_low_power[] = { + VAEntrypointEncSliceLP, + 0 +}; +#endif + +static av_cold int vaapi_encode_profile_entrypoint(AVCodecContext *avctx) +{ + VAAPIEncodeContext *ctx = avctx->priv_data; + VAProfile *va_profiles = NULL; + VAEntrypoint *va_entrypoints = NULL; VAStatus vas; - int i, n, err; - VAProfile *profiles = NULL; - VAEntrypoint *entrypoints = NULL; - VAConfigAttrib attr[] = { - { VAConfigAttribRTFormat }, - { VAConfigAttribRateControl }, - { VAConfigAttribEncMaxRefFrames }, - { VAConfigAttribEncPackedHeaders }, - }; + const VAEntrypoint *usable_entrypoints; + const VAAPIEncodeProfile *profile; + const AVPixFmtDescriptor *desc; + VAConfigAttrib rt_format_attr; + const VAAPIEncodeRTFormat *rt_format; + const char *profile_string, *entrypoint_string; + int i, j, n, depth, err; + + + if (ctx->low_power) { +#if VA_CHECK_VERSION(0, 39, 2) + usable_entrypoints = vaapi_encode_entrypoints_low_power; +#else + av_log(avctx, AV_LOG_ERROR, "Low-power encoding is not " + "supported with this VAAPI version.\n"); + return AVERROR(EINVAL); +#endif + } else { + usable_entrypoints = vaapi_encode_entrypoints_normal; + } + + desc = av_pix_fmt_desc_get(ctx->input_frames->sw_format); + if (!desc) { + av_log(avctx, AV_LOG_ERROR, "Invalid input pixfmt (%d).\n", + ctx->input_frames->sw_format); + return AVERROR(EINVAL); + } + depth = desc->comp[0].depth; + for (i = 1; i < desc->nb_components; i++) { + if (desc->comp[i].depth != depth) { + av_log(avctx, AV_LOG_ERROR, "Invalid input pixfmt (%s).\n", + desc->name); + return AVERROR(EINVAL); + } + } + av_log(avctx, AV_LOG_VERBOSE, "Input surface format is %s.\n", + desc->name); n = vaMaxNumProfiles(ctx->hwctx->display); - profiles = av_malloc_array(n, sizeof(VAProfile)); - if (!profiles) { + va_profiles = av_malloc_array(n, sizeof(VAProfile)); + if (!va_profiles) { err = AVERROR(ENOMEM); goto fail; } - vas = vaQueryConfigProfiles(ctx->hwctx->display, profiles, &n); + vas = vaQueryConfigProfiles(ctx->hwctx->display, va_profiles, &n); if (vas != VA_STATUS_SUCCESS) { - av_log(ctx, AV_LOG_ERROR, "Failed to query profiles: %d (%s).\n", + av_log(avctx, AV_LOG_ERROR, "Failed to query profiles: %d (%s).\n", vas, vaErrorStr(vas)); - err = AVERROR(ENOSYS); + err = AVERROR_EXTERNAL; goto fail; } - for (i = 0; i < n; i++) { - if (profiles[i] == ctx->va_profile) - break; + + av_assert0(ctx->codec->profiles); + for (i = 0; (ctx->codec->profiles[i].av_profile != + FF_PROFILE_UNKNOWN); i++) { + profile = &ctx->codec->profiles[i]; + if (depth != profile->depth || + desc->nb_components != profile->nb_components) + continue; + if (desc->nb_components > 1 && + (desc->log2_chroma_w != profile->log2_chroma_w || + desc->log2_chroma_h != profile->log2_chroma_h)) + continue; + if (avctx->profile != profile->av_profile && + avctx->profile != FF_PROFILE_UNKNOWN) + continue; + +#if VA_CHECK_VERSION(1, 0, 0) + profile_string = vaProfileStr(profile->va_profile); +#else + profile_string = "(no profile names)"; +#endif + + for (j = 0; j < n; j++) { + if (va_profiles[j] == profile->va_profile) + break; + } + if (j >= n) { + av_log(avctx, AV_LOG_VERBOSE, "Compatible profile %s (%d) " + "is not supported by driver.\n", profile_string, + profile->va_profile); + continue; + } + + ctx->profile = profile; + break; } - if (i >= n) { - av_log(ctx, AV_LOG_ERROR, "Encoding profile not found (%d).\n", - ctx->va_profile); + if (!ctx->profile) { + av_log(avctx, AV_LOG_ERROR, "No usable encoding profile found.\n"); err = AVERROR(ENOSYS); goto fail; } + avctx->profile = profile->av_profile; + ctx->va_profile = profile->va_profile; + av_log(avctx, AV_LOG_VERBOSE, "Using VAAPI profile %s (%d).\n", + profile_string, ctx->va_profile); + n = vaMaxNumEntrypoints(ctx->hwctx->display); - entrypoints = av_malloc_array(n, sizeof(VAEntrypoint)); - if (!entrypoints) { + va_entrypoints = av_malloc_array(n, sizeof(VAEntrypoint)); + if (!va_entrypoints) { err = AVERROR(ENOMEM); goto fail; } vas = vaQueryConfigEntrypoints(ctx->hwctx->display, ctx->va_profile, - entrypoints, &n); + va_entrypoints, &n); if (vas != VA_STATUS_SUCCESS) { - av_log(ctx, AV_LOG_ERROR, "Failed to query entrypoints for " - "profile %u: %d (%s).\n", ctx->va_profile, - vas, vaErrorStr(vas)); - err = AVERROR(ENOSYS); + av_log(avctx, AV_LOG_ERROR, "Failed to query entrypoints for " + "profile %s (%d): %d (%s).\n", profile_string, + ctx->va_profile, vas, vaErrorStr(vas)); + err = AVERROR_EXTERNAL; goto fail; } + for (i = 0; i < n; i++) { - if (entrypoints[i] == ctx->va_entrypoint) + for (j = 0; usable_entrypoints[j]; j++) { + if (va_entrypoints[i] == usable_entrypoints[j]) + break; + } + if (usable_entrypoints[j]) break; } if (i >= n) { - av_log(ctx, AV_LOG_ERROR, "Encoding entrypoint not found " - "(%d / %d).\n", ctx->va_profile, ctx->va_entrypoint); + av_log(avctx, AV_LOG_ERROR, "No usable encoding entrypoint found " + "for profile %s (%d).\n", profile_string, ctx->va_profile); err = AVERROR(ENOSYS); goto fail; } - vas = vaGetConfigAttributes(ctx->hwctx->display, - ctx->va_profile, ctx->va_entrypoint, - attr, FF_ARRAY_ELEMS(attr)); - if (vas != VA_STATUS_SUCCESS) { - av_log(avctx, AV_LOG_ERROR, "Failed to fetch config " - "attributes: %d (%s).\n", vas, vaErrorStr(vas)); - return AVERROR(EINVAL); + ctx->va_entrypoint = va_entrypoints[i]; +#if VA_CHECK_VERSION(1, 0, 0) + entrypoint_string = vaEntrypointStr(ctx->va_entrypoint); +#else + entrypoint_string = "(no entrypoint names)"; +#endif + av_log(avctx, AV_LOG_VERBOSE, "Using VAAPI entrypoint %s (%d).\n", + entrypoint_string, ctx->va_entrypoint); + + for (i = 0; i < FF_ARRAY_ELEMS(vaapi_encode_rt_formats); i++) { + rt_format = &vaapi_encode_rt_formats[i]; + if (rt_format->depth == depth && + rt_format->nb_components == profile->nb_components && + rt_format->log2_chroma_w == profile->log2_chroma_w && + rt_format->log2_chroma_h == profile->log2_chroma_h) + break; + } + if (i >= FF_ARRAY_ELEMS(vaapi_encode_rt_formats)) { + av_log(avctx, AV_LOG_ERROR, "No usable render target format " + "found for profile %s (%d) entrypoint %s (%d).\n", + profile_string, ctx->va_profile, + entrypoint_string, ctx->va_entrypoint); + err = AVERROR(ENOSYS); + goto fail; } - for (i = 0; i < FF_ARRAY_ELEMS(attr); i++) { - if (attr[i].value == VA_ATTRIB_NOT_SUPPORTED) { - // Unfortunately we have to treat this as "don't know" and hope - // for the best, because the Intel MJPEG encoder returns this - // for all the interesting attributes. - av_log(avctx, AV_LOG_DEBUG, "Attribute (%d) is not supported.\n", - attr[i].type); - continue; - } - switch (attr[i].type) { - case VAConfigAttribRTFormat: - if (!(ctx->va_rt_format & attr[i].value)) { - av_log(avctx, AV_LOG_ERROR, "Surface RT format %#x " - "is not supported (mask %#x).\n", - ctx->va_rt_format, attr[i].value); - err = AVERROR(EINVAL); - goto fail; - } - ctx->config_attributes[ctx->nb_config_attributes++] = - (VAConfigAttrib) { - .type = VAConfigAttribRTFormat, - .value = ctx->va_rt_format, - }; - break; - case VAConfigAttribRateControl: - // Hack for backward compatibility: CBR was the only - // usable RC mode for a long time, so old drivers will - // only have it. Normal default options may now choose - // VBR and then fail, however, so override it here with - // CBR if that is the only supported mode. - if (ctx->va_rc_mode == VA_RC_VBR && - !(attr[i].value & VA_RC_VBR) && - (attr[i].value & VA_RC_CBR)) { - av_log(avctx, AV_LOG_WARNING, "VBR rate control is " - "not supported with this driver version; " - "using CBR instead.\n"); - ctx->va_rc_mode = VA_RC_CBR; - } - if (!(ctx->va_rc_mode & attr[i].value)) { - av_log(avctx, AV_LOG_ERROR, "Rate control mode %#x " - "is not supported (mask: %#x).\n", - ctx->va_rc_mode, attr[i].value); - err = AVERROR(EINVAL); - goto fail; - } - ctx->config_attributes[ctx->nb_config_attributes++] = - (VAConfigAttrib) { - .type = VAConfigAttribRateControl, - .value = ctx->va_rc_mode, - }; - break; - case VAConfigAttribEncMaxRefFrames: - { - unsigned int ref_l0 = attr[i].value & 0xffff; - unsigned int ref_l1 = (attr[i].value >> 16) & 0xffff; + rt_format_attr = (VAConfigAttrib) { VAConfigAttribRTFormat }; + vas = vaGetConfigAttributes(ctx->hwctx->display, + ctx->va_profile, ctx->va_entrypoint, + &rt_format_attr, 1); + if (vas != VA_STATUS_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to query RT format " + "config attribute: %d (%s).\n", vas, vaErrorStr(vas)); + err = AVERROR_EXTERNAL; + goto fail; + } - if (avctx->gop_size > 1 && ref_l0 < 1) { - av_log(avctx, AV_LOG_ERROR, "P frames are not " - "supported (%#x).\n", attr[i].value); - err = AVERROR(EINVAL); - goto fail; - } - if (avctx->max_b_frames > 0 && ref_l1 < 1) { - av_log(avctx, AV_LOG_WARNING, "B frames are not " - "supported (%#x) by the underlying driver.\n", - attr[i].value); - avctx->max_b_frames = 0; - } - } - break; - case VAConfigAttribEncPackedHeaders: - if (ctx->va_packed_headers & ~attr[i].value) { - // This isn't fatal, but packed headers are always - // preferable because they are under our control. - // When absent, the driver is generating them and some - // features may not work (e.g. VUI or SEI in H.264). - av_log(avctx, AV_LOG_WARNING, "Warning: some packed " - "headers are not supported (want %#x, got %#x).\n", - ctx->va_packed_headers, attr[i].value); - ctx->va_packed_headers &= attr[i].value; - } - ctx->config_attributes[ctx->nb_config_attributes++] = - (VAConfigAttrib) { - .type = VAConfigAttribEncPackedHeaders, - .value = ctx->va_packed_headers, - }; - break; - default: - av_assert0(0 && "Unexpected config attribute."); - } + if (rt_format_attr.value == VA_ATTRIB_NOT_SUPPORTED) { + av_log(avctx, AV_LOG_VERBOSE, "RT format config attribute not " + "supported by driver: assuming surface RT format %s " + "is valid.\n", rt_format->name); + } else if (!(rt_format_attr.value & rt_format->value)) { + av_log(avctx, AV_LOG_ERROR, "Surface RT format %s not supported " + "by driver for encoding profile %s (%d) entrypoint %s (%d).\n", + rt_format->name, profile_string, ctx->va_profile, + entrypoint_string, ctx->va_entrypoint); + err = AVERROR(ENOSYS); + goto fail; + } else { + av_log(avctx, AV_LOG_VERBOSE, "Using VAAPI render target " + "format %s (%#x).\n", rt_format->name, rt_format->value); + ctx->config_attributes[ctx->nb_config_attributes++] = + (VAConfigAttrib) { + .type = VAConfigAttribRTFormat, + .value = rt_format->value, + }; } err = 0; fail: - av_freep(&profiles); - av_freep(&entrypoints); + av_freep(&va_profiles); + av_freep(&va_entrypoints); return err; } +static const VAAPIEncodeRCMode vaapi_encode_rc_modes[] = { + // Bitrate Quality + // | Maxrate | HRD/VBV + { 0 }, // | | | | + { RC_MODE_CQP, "CQP", 1, VA_RC_CQP, 0, 0, 1, 0 }, + { RC_MODE_CBR, "CBR", 1, VA_RC_CBR, 1, 0, 0, 1 }, + { RC_MODE_VBR, "VBR", 1, VA_RC_VBR, 1, 1, 0, 1 }, +#if VA_CHECK_VERSION(1, 1, 0) + { RC_MODE_ICQ, "ICQ", 1, VA_RC_ICQ, 0, 0, 1, 0 }, +#else + { RC_MODE_ICQ, "ICQ", 0 }, +#endif +#if VA_CHECK_VERSION(1, 3, 0) + { RC_MODE_QVBR, "QVBR", 1, VA_RC_QVBR, 1, 1, 1, 1 }, + { RC_MODE_AVBR, "AVBR", 0, VA_RC_AVBR, 1, 0, 0, 0 }, +#else + { RC_MODE_QVBR, "QVBR", 0 }, + { RC_MODE_AVBR, "AVBR", 0 }, +#endif +}; + static av_cold int vaapi_encode_init_rate_control(AVCodecContext *avctx) { VAAPIEncodeContext *ctx = avctx->priv_data; - int rc_bits_per_second; - int rc_target_percentage; - int rc_window_size; - int hrd_buffer_size; - int hrd_initial_buffer_fullness; + uint32_t supported_va_rc_modes; + const VAAPIEncodeRCMode *rc_mode; + int64_t rc_bits_per_second; + int rc_target_percentage; + int rc_window_size; + int rc_quality; + int64_t hrd_buffer_size; + int64_t hrd_initial_buffer_fullness; int fr_num, fr_den; + VAConfigAttrib rc_attr = { VAConfigAttribRateControl }; + VAStatus vas; + char supported_rc_modes_string[64]; - if (avctx->bit_rate > INT32_MAX) { - av_log(avctx, AV_LOG_ERROR, "Target bitrate of 2^31 bps or " - "higher is not supported.\n"); + vas = vaGetConfigAttributes(ctx->hwctx->display, + ctx->va_profile, ctx->va_entrypoint, + &rc_attr, 1); + if (vas != VA_STATUS_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to query rate control " + "config attribute: %d (%s).\n", vas, vaErrorStr(vas)); + return AVERROR_EXTERNAL; + } + if (rc_attr.value == VA_ATTRIB_NOT_SUPPORTED) { + av_log(avctx, AV_LOG_VERBOSE, "Driver does not report any " + "supported rate control modes: assuming CQP only.\n"); + supported_va_rc_modes = VA_RC_CQP; + strcpy(supported_rc_modes_string, "unknown"); + } else { + char *str = supported_rc_modes_string; + size_t len = sizeof(supported_rc_modes_string); + int i, first = 1, res; + + supported_va_rc_modes = rc_attr.value; + for (i = 0; i < FF_ARRAY_ELEMS(vaapi_encode_rc_modes); i++) { + rc_mode = &vaapi_encode_rc_modes[i]; + if (supported_va_rc_modes & rc_mode->va_mode) { + res = snprintf(str, len, "%s%s", + first ? "" : ", ", rc_mode->name); + first = 0; + if (res < 0) { + *str = 0; + break; + } + len -= res; + str += res; + if (len == 0) + break; + } + } + + av_log(avctx, AV_LOG_DEBUG, "Driver supports RC modes %s.\n", + supported_rc_modes_string); + } + + // Rate control mode selection: + // * If the user has set a mode explicitly with the rc_mode option, + // use it and fail if it is not available. + // * If an explicit QP option has been set, use CQP. + // * If the codec is CQ-only, use CQP. + // * If the QSCALE avcodec option is set, use CQP. + // * If bitrate and quality are both set, try QVBR. + // * If quality is set, try ICQ, then CQP. + // * If bitrate and maxrate are set and have the same value, try CBR. + // * If a bitrate is set, try AVBR, then VBR, then CBR. + // * If no bitrate is set, try ICQ, then CQP. + +#define TRY_RC_MODE(mode, fail) do { \ + rc_mode = &vaapi_encode_rc_modes[mode]; \ + if (!(rc_mode->va_mode & supported_va_rc_modes)) { \ + if (fail) { \ + av_log(avctx, AV_LOG_ERROR, "Driver does not support %s " \ + "RC mode (supported modes: %s).\n", rc_mode->name, \ + supported_rc_modes_string); \ + return AVERROR(EINVAL); \ + } \ + av_log(avctx, AV_LOG_DEBUG, "Driver does not support %s " \ + "RC mode.\n", rc_mode->name); \ + rc_mode = NULL; \ + } else { \ + goto rc_mode_found; \ + } \ + } while (0) + + if (ctx->explicit_rc_mode) + TRY_RC_MODE(ctx->explicit_rc_mode, 1); + + if (ctx->explicit_qp) + TRY_RC_MODE(RC_MODE_CQP, 1); + + if (ctx->codec->flags & FLAG_CONSTANT_QUALITY_ONLY) + TRY_RC_MODE(RC_MODE_CQP, 1); + + if (avctx->flags & AV_CODEC_FLAG_QSCALE) + TRY_RC_MODE(RC_MODE_CQP, 1); + + if (avctx->bit_rate > 0 && avctx->global_quality > 0) + TRY_RC_MODE(RC_MODE_QVBR, 0); + + if (avctx->global_quality > 0) { + TRY_RC_MODE(RC_MODE_ICQ, 0); + TRY_RC_MODE(RC_MODE_CQP, 0); + } + + if (avctx->bit_rate > 0 && avctx->rc_max_rate == avctx->bit_rate) + TRY_RC_MODE(RC_MODE_CBR, 0); + + if (avctx->bit_rate > 0) { + TRY_RC_MODE(RC_MODE_AVBR, 0); + TRY_RC_MODE(RC_MODE_VBR, 0); + TRY_RC_MODE(RC_MODE_CBR, 0); + } else { + TRY_RC_MODE(RC_MODE_ICQ, 0); + TRY_RC_MODE(RC_MODE_CQP, 0); + } + + av_log(avctx, AV_LOG_ERROR, "Driver does not support any " + "RC mode compatible with selected options " + "(supported modes: %s).\n", supported_rc_modes_string); + return AVERROR(EINVAL); + +rc_mode_found: + if (rc_mode->bitrate) { + if (avctx->bit_rate <= 0) { + av_log(avctx, AV_LOG_ERROR, "Bitrate must be set for %s " + "RC mode.\n", rc_mode->name); + return AVERROR(EINVAL); + } + + if (rc_mode->mode == RC_MODE_AVBR) { + // For maximum confusion AVBR is hacked into the existing API + // by overloading some of the fields with completely different + // meanings. + + // Target percentage does not apply in AVBR mode. + rc_bits_per_second = avctx->bit_rate; + + // Accuracy tolerance range for meeting the specified target + // bitrate. It's very unclear how this is actually intended + // to work - since we do want to get the specified bitrate, + // set the accuracy to 100% for now. + rc_target_percentage = 100; + + // Convergence period in frames. The GOP size reflects the + // user's intended block size for cutting, so reusing that + // as the convergence period seems a reasonable default. + rc_window_size = avctx->gop_size > 0 ? avctx->gop_size : 60; + + } else if (rc_mode->maxrate) { + if (avctx->rc_max_rate > 0) { + if (avctx->rc_max_rate < avctx->bit_rate) { + av_log(avctx, AV_LOG_ERROR, "Invalid bitrate settings: " + "bitrate (%"PRId64") must not be greater than " + "maxrate (%"PRId64").\n", avctx->bit_rate, + avctx->rc_max_rate); + return AVERROR(EINVAL); + } + rc_bits_per_second = avctx->rc_max_rate; + rc_target_percentage = (avctx->bit_rate * 100) / + avctx->rc_max_rate; + } else { + // We only have a target bitrate, but this mode requires + // that a maximum rate be supplied as well. Since the + // user does not want this to be a constraint, arbitrarily + // pick a maximum rate of double the target rate. + rc_bits_per_second = 2 * avctx->bit_rate; + rc_target_percentage = 50; + } + } else { + if (avctx->rc_max_rate > avctx->bit_rate) { + av_log(avctx, AV_LOG_WARNING, "Max bitrate is ignored " + "in %s RC mode.\n", rc_mode->name); + } + rc_bits_per_second = avctx->bit_rate; + rc_target_percentage = 100; + } + } else { + rc_bits_per_second = 0; + rc_target_percentage = 100; + } + + if (rc_mode->quality) { + if (ctx->explicit_qp) { + rc_quality = ctx->explicit_qp; + } else if (avctx->global_quality > 0) { + rc_quality = avctx->global_quality; + } else { + rc_quality = ctx->codec->default_quality; + av_log(avctx, AV_LOG_WARNING, "No quality level set; " + "using default (%d).\n", rc_quality); + } + } else { + rc_quality = 0; + } + + if (rc_mode->hrd) { + if (avctx->rc_buffer_size) + hrd_buffer_size = avctx->rc_buffer_size; + else if (avctx->rc_max_rate > 0) + hrd_buffer_size = avctx->rc_max_rate; + else + hrd_buffer_size = avctx->bit_rate; + if (avctx->rc_initial_buffer_occupancy) { + if (avctx->rc_initial_buffer_occupancy > hrd_buffer_size) { + av_log(avctx, AV_LOG_ERROR, "Invalid RC buffer settings: " + "must have initial buffer size (%d) <= " + "buffer size (%"PRId64").\n", + avctx->rc_initial_buffer_occupancy, hrd_buffer_size); + return AVERROR(EINVAL); + } + hrd_initial_buffer_fullness = avctx->rc_initial_buffer_occupancy; + } else { + hrd_initial_buffer_fullness = hrd_buffer_size * 3 / 4; + } + + rc_window_size = (hrd_buffer_size * 1000) / rc_bits_per_second; + } else { + if (avctx->rc_buffer_size || avctx->rc_initial_buffer_occupancy) { + av_log(avctx, AV_LOG_WARNING, "Buffering settings are ignored " + "in %s RC mode.\n", rc_mode->name); + } + + hrd_buffer_size = 0; + hrd_initial_buffer_fullness = 0; + + if (rc_mode->mode != RC_MODE_AVBR) { + // Already set (with completely different meaning) for AVBR. + rc_window_size = 1000; + } + } + + if (rc_bits_per_second > UINT32_MAX || + hrd_buffer_size > UINT32_MAX || + hrd_initial_buffer_fullness > UINT32_MAX) { + av_log(avctx, AV_LOG_ERROR, "RC parameters of 2^32 or " + "greater are not supported by VAAPI.\n"); return AVERROR(EINVAL); } - if (avctx->rc_buffer_size) - hrd_buffer_size = avctx->rc_buffer_size; - else - hrd_buffer_size = avctx->bit_rate; - if (avctx->rc_initial_buffer_occupancy) - hrd_initial_buffer_fullness = avctx->rc_initial_buffer_occupancy; - else - hrd_initial_buffer_fullness = hrd_buffer_size * 3 / 4; + ctx->rc_mode = rc_mode; + ctx->rc_quality = rc_quality; + ctx->va_rc_mode = rc_mode->va_mode; + ctx->va_bit_rate = rc_bits_per_second; - if (ctx->va_rc_mode == VA_RC_CBR) { - rc_bits_per_second = avctx->bit_rate; - rc_target_percentage = 100; - rc_window_size = 1000; + av_log(avctx, AV_LOG_VERBOSE, "RC mode: %s.\n", rc_mode->name); + if (rc_attr.value == VA_ATTRIB_NOT_SUPPORTED) { + // This driver does not want the RC mode attribute to be set. } else { - if (avctx->rc_max_rate < avctx->bit_rate) { - // Max rate is unset or invalid, just use the normal bitrate. - rc_bits_per_second = avctx->bit_rate; - rc_target_percentage = 100; - } else { - rc_bits_per_second = avctx->rc_max_rate; - rc_target_percentage = (avctx->bit_rate * 100) / rc_bits_per_second; - } - rc_window_size = (hrd_buffer_size * 1000) / avctx->bit_rate; + ctx->config_attributes[ctx->nb_config_attributes++] = + (VAConfigAttrib) { + .type = VAConfigAttribRateControl, + .value = ctx->va_rc_mode, + }; } - ctx->rc_params.misc.type = VAEncMiscParameterTypeRateControl; - ctx->rc_params.rc = (VAEncMiscParameterRateControl) { - .bits_per_second = rc_bits_per_second, - .target_percentage = rc_target_percentage, - .window_size = rc_window_size, - .initial_qp = 0, - .min_qp = (avctx->qmin > 0 ? avctx->qmin : 0), - .basic_unit_size = 0, - }; - ctx->global_params[ctx->nb_global_params] = - &ctx->rc_params.misc; - ctx->global_params_size[ctx->nb_global_params++] = - sizeof(ctx->rc_params); + if (rc_mode->quality) + av_log(avctx, AV_LOG_VERBOSE, "RC quality: %d.\n", rc_quality); - ctx->hrd_params.misc.type = VAEncMiscParameterTypeHRD; - ctx->hrd_params.hrd = (VAEncMiscParameterHRD) { - .initial_buffer_fullness = hrd_initial_buffer_fullness, - .buffer_size = hrd_buffer_size, - }; - ctx->global_params[ctx->nb_global_params] = - &ctx->hrd_params.misc; - ctx->global_params_size[ctx->nb_global_params++] = - sizeof(ctx->hrd_params); + if (rc_mode->va_mode != VA_RC_CQP) { + if (rc_mode->mode == RC_MODE_AVBR) { + av_log(avctx, AV_LOG_VERBOSE, "RC target: %"PRId64" bps " + "converging in %d frames with %d%% accuracy.\n", + rc_bits_per_second, rc_window_size, + rc_target_percentage); + } else if (rc_mode->bitrate) { + av_log(avctx, AV_LOG_VERBOSE, "RC target: %d%% of " + "%"PRId64" bps over %d ms.\n", rc_target_percentage, + rc_bits_per_second, rc_window_size); + } + + ctx->rc_params = (VAEncMiscParameterRateControl) { + .bits_per_second = rc_bits_per_second, + .target_percentage = rc_target_percentage, + .window_size = rc_window_size, + .initial_qp = 0, + .min_qp = (avctx->qmin > 0 ? avctx->qmin : 0), + .basic_unit_size = 0, +#if VA_CHECK_VERSION(1, 1, 0) + .ICQ_quality_factor = av_clip(rc_quality, 1, 51), + .max_qp = (avctx->qmax > 0 ? avctx->qmax : 0), +#endif +#if VA_CHECK_VERSION(1, 3, 0) + .quality_factor = rc_quality, +#endif + }; + vaapi_encode_add_global_param(avctx, + VAEncMiscParameterTypeRateControl, + &ctx->rc_params, + sizeof(ctx->rc_params)); + } + + if (rc_mode->hrd) { + av_log(avctx, AV_LOG_VERBOSE, "RC buffer: %"PRId64" bits, " + "initial fullness %"PRId64" bits.\n", + hrd_buffer_size, hrd_initial_buffer_fullness); + + ctx->hrd_params = (VAEncMiscParameterHRD) { + .initial_buffer_fullness = hrd_initial_buffer_fullness, + .buffer_size = hrd_buffer_size, + }; + vaapi_encode_add_global_param(avctx, + VAEncMiscParameterTypeHRD, + &ctx->hrd_params, + sizeof(ctx->hrd_params)); + } if (avctx->framerate.num > 0 && avctx->framerate.den > 0) av_reduce(&fr_num, &fr_den, @@ -1204,14 +1655,288 @@ static av_cold int vaapi_encode_init_rate_control(AVCodecContext *avctx) av_reduce(&fr_num, &fr_den, avctx->time_base.den, avctx->time_base.num, 65535); - ctx->fr_params.misc.type = VAEncMiscParameterTypeFrameRate; - ctx->fr_params.fr.framerate = (unsigned int)fr_den << 16 | fr_num; + av_log(avctx, AV_LOG_VERBOSE, "RC framerate: %d/%d (%.2f fps).\n", + fr_num, fr_den, (double)fr_num / fr_den); + ctx->fr_params = (VAEncMiscParameterFrameRate) { + .framerate = (unsigned int)fr_den << 16 | fr_num, + }; #if VA_CHECK_VERSION(0, 40, 0) - ctx->global_params[ctx->nb_global_params] = - &ctx->fr_params.misc; - ctx->global_params_size[ctx->nb_global_params++] = - sizeof(ctx->fr_params); + vaapi_encode_add_global_param(avctx, + VAEncMiscParameterTypeFrameRate, + &ctx->fr_params, + sizeof(ctx->fr_params)); +#endif + + return 0; +} + +static av_cold int vaapi_encode_init_gop_structure(AVCodecContext *avctx) +{ + VAAPIEncodeContext *ctx = avctx->priv_data; + VAStatus vas; + VAConfigAttrib attr = { VAConfigAttribEncMaxRefFrames }; + uint32_t ref_l0, ref_l1; + + vas = vaGetConfigAttributes(ctx->hwctx->display, + ctx->va_profile, + ctx->va_entrypoint, + &attr, 1); + if (vas != VA_STATUS_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to query reference frames " + "attribute: %d (%s).\n", vas, vaErrorStr(vas)); + return AVERROR_EXTERNAL; + } + + if (attr.value == VA_ATTRIB_NOT_SUPPORTED) { + ref_l0 = ref_l1 = 0; + } else { + ref_l0 = attr.value & 0xffff; + ref_l1 = attr.value >> 16 & 0xffff; + } + + if (ctx->codec->flags & FLAG_INTRA_ONLY || + avctx->gop_size <= 1) { + av_log(avctx, AV_LOG_VERBOSE, "Using intra frames only.\n"); + ctx->gop_size = 1; + } else if (ref_l0 < 1) { + av_log(avctx, AV_LOG_ERROR, "Driver does not support any " + "reference frames.\n"); + return AVERROR(EINVAL); + } else if (!(ctx->codec->flags & FLAG_B_PICTURES) || + ref_l1 < 1 || avctx->max_b_frames < 1) { + av_log(avctx, AV_LOG_VERBOSE, "Using intra and P-frames " + "(supported references: %d / %d).\n", ref_l0, ref_l1); + ctx->gop_size = avctx->gop_size; + ctx->p_per_i = INT_MAX; + ctx->b_per_p = 0; + } else { + av_log(avctx, AV_LOG_VERBOSE, "Using intra, P- and B-frames " + "(supported references: %d / %d).\n", ref_l0, ref_l1); + ctx->gop_size = avctx->gop_size; + ctx->p_per_i = INT_MAX; + ctx->b_per_p = avctx->max_b_frames; + if (ctx->codec->flags & FLAG_B_PICTURE_REFERENCES) { + ctx->max_b_depth = FFMIN(ctx->desired_b_depth, + av_log2(ctx->b_per_p) + 1); + } else { + ctx->max_b_depth = 1; + } + } + + if (ctx->codec->flags & FLAG_NON_IDR_KEY_PICTURES) { + ctx->closed_gop = !!(avctx->flags & AV_CODEC_FLAG_CLOSED_GOP); + ctx->gop_per_idr = ctx->idr_interval + 1; + } else { + ctx->closed_gop = 1; + ctx->gop_per_idr = 1; + } + + return 0; +} + +static av_cold int vaapi_encode_init_slice_structure(AVCodecContext *avctx) +{ + VAAPIEncodeContext *ctx = avctx->priv_data; + VAConfigAttrib attr[2] = { { VAConfigAttribEncMaxSlices }, + { VAConfigAttribEncSliceStructure } }; + VAStatus vas; + uint32_t max_slices, slice_structure; + int req_slices; + + if (!(ctx->codec->flags & FLAG_SLICE_CONTROL)) { + if (avctx->slices > 0) { + av_log(avctx, AV_LOG_WARNING, "Multiple slices were requested " + "but this codec does not support controlling slices.\n"); + } + return 0; + } + + ctx->slice_block_rows = (avctx->height + ctx->slice_block_height - 1) / + ctx->slice_block_height; + ctx->slice_block_cols = (avctx->width + ctx->slice_block_width - 1) / + ctx->slice_block_width; + + if (avctx->slices <= 1) { + ctx->nb_slices = 1; + ctx->slice_size = ctx->slice_block_rows; + return 0; + } + + vas = vaGetConfigAttributes(ctx->hwctx->display, + ctx->va_profile, + ctx->va_entrypoint, + attr, FF_ARRAY_ELEMS(attr)); + if (vas != VA_STATUS_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to query slice " + "attributes: %d (%s).\n", vas, vaErrorStr(vas)); + return AVERROR_EXTERNAL; + } + max_slices = attr[0].value; + slice_structure = attr[1].value; + if (max_slices == VA_ATTRIB_NOT_SUPPORTED || + slice_structure == VA_ATTRIB_NOT_SUPPORTED) { + av_log(avctx, AV_LOG_ERROR, "Driver does not support encoding " + "pictures as multiple slices.\n."); + return AVERROR(EINVAL); + } + + // For fixed-size slices currently we only support whole rows, making + // rectangular slices. This could be extended to arbitrary runs of + // blocks, but since slices tend to be a conformance requirement and + // most cases (such as broadcast or bluray) want rectangular slices + // only it would need to be gated behind another option. + if (avctx->slices > ctx->slice_block_rows) { + av_log(avctx, AV_LOG_WARNING, "Not enough rows to use " + "configured number of slices (%d < %d); using " + "maximum.\n", ctx->slice_block_rows, avctx->slices); + req_slices = ctx->slice_block_rows; + } else { + req_slices = avctx->slices; + } + if (slice_structure & VA_ENC_SLICE_STRUCTURE_ARBITRARY_ROWS || + slice_structure & VA_ENC_SLICE_STRUCTURE_ARBITRARY_MACROBLOCKS) { + ctx->nb_slices = req_slices; + ctx->slice_size = ctx->slice_block_rows / ctx->nb_slices; + } else if (slice_structure & VA_ENC_SLICE_STRUCTURE_POWER_OF_TWO_ROWS) { + int k; + for (k = 1;; k *= 2) { + if (2 * k * (req_slices - 1) + 1 >= ctx->slice_block_rows) + break; + } + ctx->nb_slices = (ctx->slice_block_rows + k - 1) / k; + ctx->slice_size = k; +#if VA_CHECK_VERSION(1, 0, 0) + } else if (slice_structure & VA_ENC_SLICE_STRUCTURE_EQUAL_ROWS) { + ctx->nb_slices = ctx->slice_block_rows; + ctx->slice_size = 1; +#endif + } else { + av_log(avctx, AV_LOG_ERROR, "Driver does not support any usable " + "slice structure modes (%#x).\n", slice_structure); + return AVERROR(EINVAL); + } + + if (ctx->nb_slices > avctx->slices) { + av_log(avctx, AV_LOG_WARNING, "Slice count rounded up to " + "%d (from %d) due to driver constraints on slice " + "structure.\n", ctx->nb_slices, avctx->slices); + } + if (ctx->nb_slices > max_slices) { + av_log(avctx, AV_LOG_ERROR, "Driver does not support " + "encoding with %d slices (max %"PRIu32").\n", + ctx->nb_slices, max_slices); + return AVERROR(EINVAL); + } + + av_log(avctx, AV_LOG_VERBOSE, "Encoding pictures with %d slices " + "(default size %d block rows).\n", + ctx->nb_slices, ctx->slice_size); + return 0; +} + +static av_cold int vaapi_encode_init_packed_headers(AVCodecContext *avctx) +{ + VAAPIEncodeContext *ctx = avctx->priv_data; + VAStatus vas; + VAConfigAttrib attr = { VAConfigAttribEncPackedHeaders }; + + vas = vaGetConfigAttributes(ctx->hwctx->display, + ctx->va_profile, + ctx->va_entrypoint, + &attr, 1); + if (vas != VA_STATUS_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to query packed headers " + "attribute: %d (%s).\n", vas, vaErrorStr(vas)); + return AVERROR_EXTERNAL; + } + + if (attr.value == VA_ATTRIB_NOT_SUPPORTED) { + if (ctx->desired_packed_headers) { + av_log(avctx, AV_LOG_WARNING, "Driver does not support any " + "packed headers (wanted %#x).\n", + ctx->desired_packed_headers); + } else { + av_log(avctx, AV_LOG_VERBOSE, "Driver does not support any " + "packed headers (none wanted).\n"); + } + ctx->va_packed_headers = 0; + } else { + if (ctx->desired_packed_headers & ~attr.value) { + av_log(avctx, AV_LOG_WARNING, "Driver does not support some " + "wanted packed headers (wanted %#x, found %#x).\n", + ctx->desired_packed_headers, attr.value); + } else { + av_log(avctx, AV_LOG_VERBOSE, "All wanted packed headers " + "available (wanted %#x, found %#x).\n", + ctx->desired_packed_headers, attr.value); + } + ctx->va_packed_headers = ctx->desired_packed_headers & attr.value; + } + + if (ctx->va_packed_headers) { + ctx->config_attributes[ctx->nb_config_attributes++] = + (VAConfigAttrib) { + .type = VAConfigAttribEncPackedHeaders, + .value = ctx->va_packed_headers, + }; + } + + if ( (ctx->desired_packed_headers & VA_ENC_PACKED_HEADER_SEQUENCE) && + !(ctx->va_packed_headers & VA_ENC_PACKED_HEADER_SEQUENCE) && + (avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER)) { + av_log(avctx, AV_LOG_WARNING, "Driver does not support packed " + "sequence headers, but a global header is requested.\n"); + av_log(avctx, AV_LOG_WARNING, "No global header will be written: " + "this may result in a stream which is not usable for some " + "purposes (e.g. not muxable to some containers).\n"); + } + + return 0; +} + +static av_cold int vaapi_encode_init_quality(AVCodecContext *avctx) +{ +#if VA_CHECK_VERSION(0, 36, 0) + VAAPIEncodeContext *ctx = avctx->priv_data; + VAStatus vas; + VAConfigAttrib attr = { VAConfigAttribEncQualityRange }; + int quality = avctx->compression_level; + + vas = vaGetConfigAttributes(ctx->hwctx->display, + ctx->va_profile, + ctx->va_entrypoint, + &attr, 1); + if (vas != VA_STATUS_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to query quality " + "config attribute: %d (%s).\n", vas, vaErrorStr(vas)); + return AVERROR_EXTERNAL; + } + + if (attr.value == VA_ATTRIB_NOT_SUPPORTED) { + if (quality != 0) { + av_log(avctx, AV_LOG_WARNING, "Quality attribute is not " + "supported: will use default quality level.\n"); + } + } else { + if (quality > attr.value) { + av_log(avctx, AV_LOG_WARNING, "Invalid quality level: " + "valid range is 0-%d, using %d.\n", + attr.value, attr.value); + quality = attr.value; + } + + ctx->quality_params = (VAEncMiscParameterBufferQualityLevel) { + .quality_level = quality, + }; + vaapi_encode_add_global_param(avctx, + VAEncMiscParameterTypeQualityLevel, + &ctx->quality_params, + sizeof(ctx->quality_params)); + } +#else + av_log(avctx, AV_LOG_WARNING, "The encode quality option is " + "not supported with this VAAPI version.\n"); #endif return 0; @@ -1341,9 +2066,6 @@ static av_cold int vaapi_encode_create_recon_frames(AVCodecContext *avctx) ctx->recon_frames->sw_format = recon_format; ctx->recon_frames->width = ctx->surface_width; ctx->recon_frames->height = ctx->surface_height; - // At most three IDR/I/P frames and two runs of B frames can be in - // flight at any one time. - ctx->recon_frames->initial_pool_size = 3 + 2 * avctx->max_b_frames; err = av_hwframe_ctx_init(ctx->recon_frames_ref); if (err < 0) { @@ -1372,17 +2094,9 @@ av_cold int ff_vaapi_encode_init(AVCodecContext *avctx) return AVERROR(EINVAL); } - ctx->codec_options = ctx->codec_options_data; - ctx->va_config = VA_INVALID_ID; ctx->va_context = VA_INVALID_ID; - ctx->priv_data = av_mallocz(ctx->codec->priv_data_size); - if (!ctx->priv_data) { - err = AVERROR(ENOMEM); - goto fail; - } - ctx->input_frames_ref = av_buffer_ref(avctx->hw_frames_ctx); if (!ctx->input_frames_ref) { err = AVERROR(ENOMEM); @@ -1398,10 +2112,32 @@ av_cold int ff_vaapi_encode_init(AVCodecContext *avctx) ctx->device = (AVHWDeviceContext*)ctx->device_ref->data; ctx->hwctx = ctx->device->hwctx; - err = vaapi_encode_config_attributes(avctx); + err = vaapi_encode_profile_entrypoint(avctx); if (err < 0) goto fail; + err = vaapi_encode_init_rate_control(avctx); + if (err < 0) + goto fail; + + err = vaapi_encode_init_gop_structure(avctx); + if (err < 0) + goto fail; + + err = vaapi_encode_init_slice_structure(avctx); + if (err < 0) + goto fail; + + err = vaapi_encode_init_packed_headers(avctx); + if (err < 0) + goto fail; + + if (avctx->compression_level >= 0) { + err = vaapi_encode_init_quality(avctx); + if (err < 0) + goto fail; + } + vas = vaCreateConfig(ctx->hwctx->display, ctx->va_profile, ctx->va_entrypoint, ctx->config_attributes, ctx->nb_config_attributes, @@ -1439,61 +2175,14 @@ av_cold int ff_vaapi_encode_init(AVCodecContext *avctx) goto fail; } - if (ctx->va_rc_mode & ~VA_RC_CQP) { - err = vaapi_encode_init_rate_control(avctx); - if (err < 0) - goto fail; - } - if (ctx->codec->configure) { err = ctx->codec->configure(avctx); if (err < 0) goto fail; } - if (avctx->compression_level >= 0) { -#if VA_CHECK_VERSION(0, 36, 0) - VAConfigAttrib attr = { VAConfigAttribEncQualityRange }; - - vas = vaGetConfigAttributes(ctx->hwctx->display, - ctx->va_profile, - ctx->va_entrypoint, - &attr, 1); - if (vas != VA_STATUS_SUCCESS) { - av_log(avctx, AV_LOG_WARNING, "Failed to query quality " - "attribute: will use default compression level.\n"); - } else { - if (avctx->compression_level > attr.value) { - av_log(avctx, AV_LOG_WARNING, "Invalid compression " - "level: valid range is 0-%d, using %d.\n", - attr.value, attr.value); - avctx->compression_level = attr.value; - } - - ctx->quality_params.misc.type = - VAEncMiscParameterTypeQualityLevel; - ctx->quality_params.quality.quality_level = - avctx->compression_level; - - ctx->global_params[ctx->nb_global_params] = - &ctx->quality_params.misc; - ctx->global_params_size[ctx->nb_global_params++] = - sizeof(ctx->quality_params); - } -#else - av_log(avctx, AV_LOG_WARNING, "The encode compression level " - "option is not supported with this VAAPI version.\n"); -#endif - } - - ctx->input_order = 0; - ctx->output_delay = avctx->max_b_frames; - ctx->decode_delay = 1; - ctx->output_order = - ctx->output_delay - 1; - - // Currently we never generate I frames, only IDR. - ctx->p_per_i = INT_MAX; - ctx->b_per_p = avctx->max_b_frames; + ctx->output_delay = ctx->b_per_p; + ctx->decode_delay = ctx->max_b_depth; if (ctx->codec->sequence_params_size > 0) { ctx->codec_sequence_params = @@ -1521,12 +2210,9 @@ av_cold int ff_vaapi_encode_init(AVCodecContext *avctx) } } - // This should be configurable somehow. (Needs testing on a machine - // where it actually overlaps properly, though.) - ctx->issue_mode = ISSUE_MODE_MAXIMISE_THROUGHPUT; - if (ctx->va_packed_headers & VA_ENC_PACKED_HEADER_SEQUENCE && - ctx->codec->write_sequence_header) { + ctx->codec->write_sequence_header && + avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER) { char data[MAX_PARAM_BUFFER_SIZE]; size_t bit_len = 8 * sizeof(data); @@ -1583,7 +2269,5 @@ av_cold int ff_vaapi_encode_close(AVCodecContext *avctx) av_buffer_unref(&ctx->input_frames_ref); av_buffer_unref(&ctx->device_ref); - av_freep(&ctx->priv_data); - return 0; } diff --git a/libavcodec/vaapi_encode.h b/libavcodec/vaapi_encode.h index bcb9d5737..eeec06036 100644 --- a/libavcodec/vaapi_encode.h +++ b/libavcodec/vaapi_encode.h @@ -23,6 +23,10 @@ #include +#if VA_CHECK_VERSION(1, 0, 0) +#include +#endif + #include "libavutil/hwcontext.h" #include "libavutil/hwcontext_vaapi.h" @@ -34,6 +38,7 @@ struct VAAPIEncodePicture; enum { MAX_CONFIG_ATTRIBUTES = 4, MAX_GLOBAL_PARAMS = 4, + MAX_DPB_SIZE = 16, MAX_PICTURE_REFERENCES = 2, MAX_REORDER_DELAY = 16, MAX_PARAM_BUFFER_SIZE = 1024, @@ -48,6 +53,10 @@ enum { typedef struct VAAPIEncodeSlice { int index; + int row_start; + int row_size; + int block_start; + int block_size; void *priv_data; void *codec_slice_params; } VAAPIEncodeSlice; @@ -58,9 +67,10 @@ typedef struct VAAPIEncodePicture { int64_t display_order; int64_t encode_order; int64_t pts; + int force_idr; int type; - int input_available; + int b_depth; int encode_issued; int encode_complete; @@ -79,30 +89,103 @@ typedef struct VAAPIEncodePicture { void *priv_data; void *codec_picture_params; - int nb_refs; + // Whether this picture is a reference picture. + int is_reference; + + // The contents of the DPB after this picture has been decoded. + // This will contain the picture itself if it is a reference picture, + // but not if it isn't. + int nb_dpb_pics; + struct VAAPIEncodePicture *dpb[MAX_DPB_SIZE]; + // The reference pictures used in decoding this picture. If they are + // used by later pictures they will also appear in the DPB. + int nb_refs; struct VAAPIEncodePicture *refs[MAX_PICTURE_REFERENCES]; + // The previous reference picture in encode order. Must be in at least + // one of the reference list and DPB list. + struct VAAPIEncodePicture *prev; + // Reference count for other pictures referring to this one through + // the above pointers, directly from incomplete pictures and indirectly + // through completed pictures. + int ref_count[2]; + int ref_removed[2]; int nb_slices; VAAPIEncodeSlice *slices; } VAAPIEncodePicture; +typedef struct VAAPIEncodeProfile { + // lavc profile value (FF_PROFILE_*). + int av_profile; + // Supported bit depth. + int depth; + // Number of components. + int nb_components; + // Chroma subsampling in width dimension. + int log2_chroma_w; + // Chroma subsampling in height dimension. + int log2_chroma_h; + // VAAPI profile value. + VAProfile va_profile; +} VAAPIEncodeProfile; + +enum { + RC_MODE_AUTO, + RC_MODE_CQP, + RC_MODE_CBR, + RC_MODE_VBR, + RC_MODE_ICQ, + RC_MODE_QVBR, + RC_MODE_AVBR, + RC_MODE_MAX = RC_MODE_AVBR, +}; + +typedef struct VAAPIEncodeRCMode { + // Mode from above enum (RC_MODE_*). + int mode; + // Name. + const char *name; + // Supported in the compile-time VAAPI version. + int supported; + // VA mode value (VA_RC_*). + uint32_t va_mode; + // Uses bitrate parameters. + int bitrate; + // Supports maxrate distinct from bitrate. + int maxrate; + // Uses quality value. + int quality; + // Supports HRD/VBV parameters. + int hrd; +} VAAPIEncodeRCMode; + typedef struct VAAPIEncodeContext { const AVClass *class; // Codec-specific hooks. const struct VAAPIEncodeType *codec; - // Encoding profile (VAProfileXXX). - VAProfile va_profile; - // Encoding entrypoint (usually VAEntryointEncSlice). - VAEntrypoint va_entrypoint; - // Surface colour/sampling format (usually VA_RT_FORMAT_YUV420). - unsigned int va_rt_format; - // Rate control mode. - unsigned int va_rc_mode; - // Supported packed headers (initially the desired set, modified - // later to what is actually supported). - unsigned int va_packed_headers; + // Global options. + + // Use low power encoding mode. + int low_power; + + // Number of I frames between IDR frames. + int idr_interval; + + // Desired B frame reference depth. + int desired_b_depth; + + // Explicitly set RC mode (otherwise attempt to pick from + // available modes). + int explicit_rc_mode; + + // Explicitly-set QP, for use with the "qp" options. + // (Forces CQP mode when set, overriding everything else.) + int explicit_qp; + + // Desired packed headers. + unsigned int desired_packed_headers; // The required size of surfaces. This is probably the input // size (AVCodecContext.width|height) aligned up to whatever @@ -110,11 +193,32 @@ typedef struct VAAPIEncodeContext { int surface_width; int surface_height; + // The block size for slice calculations. + int slice_block_width; + int slice_block_height; + // Everything above this point must be set before calling // ff_vaapi_encode_init(). - // Codec-specific state. - void *priv_data; + // Chosen encoding profile details. + const VAAPIEncodeProfile *profile; + + // Chosen rate control mode details. + const VAAPIEncodeRCMode *rc_mode; + // RC quality level - meaning depends on codec and RC mode. + // In CQP mode this sets the fixed quantiser value. + int rc_quality; + + // Encoding profile (VAProfile*). + VAProfile va_profile; + // Encoding entrypoint (VAEntryoint*). + VAEntrypoint va_entrypoint; + // Rate control mode. + unsigned int va_rc_mode; + // Bitrate for codec-specific encoder parameters. + unsigned int va_bit_rate; + // Packed headers which will actually be sent. + unsigned int va_packed_headers; // Configuration attributes to use when creating va_config. VAConfigAttrib config_attributes[MAX_CONFIG_ATTRIBUTES]; @@ -140,28 +244,17 @@ typedef struct VAAPIEncodeContext { // Global parameters which will be applied at the start of the // sequence (includes rate control parameters below). - VAEncMiscParameterBuffer *global_params[MAX_GLOBAL_PARAMS]; + int global_params_type[MAX_GLOBAL_PARAMS]; + const void *global_params [MAX_GLOBAL_PARAMS]; size_t global_params_size[MAX_GLOBAL_PARAMS]; int nb_global_params; // Rate control parameters. - struct { - VAEncMiscParameterBuffer misc; - VAEncMiscParameterRateControl rc; - } rc_params; - struct { - VAEncMiscParameterBuffer misc; - VAEncMiscParameterHRD hrd; - } hrd_params; - struct { - VAEncMiscParameterBuffer misc; - VAEncMiscParameterFrameRate fr; - } fr_params; + VAEncMiscParameterRateControl rc_params; + VAEncMiscParameterHRD hrd_params; + VAEncMiscParameterFrameRate fr_params; #if VA_CHECK_VERSION(0, 36, 0) - struct { - VAEncMiscParameterBuffer misc; - VAEncMiscParameterBufferQualityLevel quality; - } quality_params; + VAEncMiscParameterBufferQualityLevel quality_params; #endif // Per-sequence parameter structure (VAEncSequenceParameterBuffer*). @@ -173,55 +266,86 @@ typedef struct VAAPIEncodeContext { // Current encoding window, in display (input) order. VAAPIEncodePicture *pic_start, *pic_end; + // The next picture to use as the previous reference picture in + // encoding order. + VAAPIEncodePicture *next_prev; // Next input order index (display order). int64_t input_order; // Number of frames that output is behind input. int64_t output_delay; + // Next encode order index. + int64_t encode_order; // Number of frames decode output will need to be delayed. int64_t decode_delay; - // Next output order index (encode order). + // Next output order index (in encode order). int64_t output_order; - enum { - // All encode operations are done independently (synchronise - // immediately after every operation). - ISSUE_MODE_SERIALISE_EVERYTHING = 0, - // Overlap as many operations as possible. - ISSUE_MODE_MAXIMISE_THROUGHPUT, - // Overlap operations only when satisfying parallel dependencies. - ISSUE_MODE_MINIMISE_LATENCY, - } issue_mode; - // Timestamp handling. int64_t first_pts; int64_t dts_pts_diff; int64_t ts_ring[MAX_REORDER_DELAY * 3]; + // Slice structure. + int slice_block_rows; + int slice_block_cols; + int nb_slices; + int slice_size; + // Frame type decision. + int gop_size; + int closed_gop; + int gop_per_idr; int p_per_i; + int max_b_depth; int b_per_p; int force_idr; + int idr_counter; int gop_counter; - int p_counter; int end_of_stream; - // Codec-local options are allocated to follow this structure in - // memory (in the AVCodec definition, set priv_data_size to - // sizeof(VAAPIEncodeContext) + sizeof(VAAPIEncodeFooOptions)). - void *codec_options; - char codec_options_data[0]; + // The encoder does not support cropping information, so warn about + // it the first time we encounter any nonzero crop fields. + int crop_warned; } VAAPIEncodeContext; +enum { + // Codec supports controlling the subdivision of pictures into slices. + FLAG_SLICE_CONTROL = 1 << 0, + // Codec only supports constant quality (no rate control). + FLAG_CONSTANT_QUALITY_ONLY = 1 << 1, + // Codec is intra-only. + FLAG_INTRA_ONLY = 1 << 2, + // Codec supports B-pictures. + FLAG_B_PICTURES = 1 << 3, + // Codec supports referencing B-pictures. + FLAG_B_PICTURE_REFERENCES = 1 << 4, + // Codec supports non-IDR key pictures (that is, key pictures do + // not necessarily empty the DPB). + FLAG_NON_IDR_KEY_PICTURES = 1 << 5, +}; typedef struct VAAPIEncodeType { - size_t priv_data_size; + // List of supported profiles and corresponding VAAPI profiles. + // (Must end with FF_PROFILE_UNKNOWN.) + const VAAPIEncodeProfile *profiles; + + // Codec feature flags. + int flags; + + // Default quality for this codec - used as quantiser or RC quality + // factor depending on RC mode. + int default_quality; // Perform any extra codec-specific configuration after the // codec context is initialised (set up the private data and // add any necessary global parameters). int (*configure)(AVCodecContext *avctx); + // The size of any private data structure associated with each + // picture (can be zero if not required). + size_t picture_priv_data_size; + // The size of the parameter structures: // sizeof(VAEnc{type}ParameterBuffer{codec}). size_t sequence_params_size; @@ -274,10 +398,44 @@ typedef struct VAAPIEncodeType { } VAAPIEncodeType; -int ff_vaapi_encode2(AVCodecContext *avctx, AVPacket *pkt, - const AVFrame *input_image, int *got_packet); +int ff_vaapi_encode_send_frame(AVCodecContext *avctx, const AVFrame *frame); +int ff_vaapi_encode_receive_packet(AVCodecContext *avctx, AVPacket *pkt); int ff_vaapi_encode_init(AVCodecContext *avctx); int ff_vaapi_encode_close(AVCodecContext *avctx); + +#define VAAPI_ENCODE_COMMON_OPTIONS \ + { "low_power", \ + "Use low-power encoding mode (only available on some platforms; " \ + "may not support all encoding features)", \ + OFFSET(common.low_power), AV_OPT_TYPE_BOOL, \ + { .i64 = 0 }, 0, 1, FLAGS }, \ + { "idr_interval", \ + "Distance (in I-frames) between IDR frames", \ + OFFSET(common.idr_interval), AV_OPT_TYPE_INT, \ + { .i64 = 0 }, 0, INT_MAX, FLAGS }, \ + { "b_depth", \ + "Maximum B-frame reference depth", \ + OFFSET(common.desired_b_depth), AV_OPT_TYPE_INT, \ + { .i64 = 1 }, 1, INT_MAX, FLAGS } + +#define VAAPI_ENCODE_RC_MODE(name, desc) \ + { #name, desc, 0, AV_OPT_TYPE_CONST, { .i64 = RC_MODE_ ## name }, \ + 0, 0, FLAGS, "rc_mode" } +#define VAAPI_ENCODE_RC_OPTIONS \ + { "rc_mode",\ + "Set rate control mode", \ + OFFSET(common.explicit_rc_mode), AV_OPT_TYPE_INT, \ + { .i64 = RC_MODE_AUTO }, RC_MODE_AUTO, RC_MODE_MAX, FLAGS, "rc_mode" }, \ + { "auto", "Choose mode automatically based on other parameters", \ + 0, AV_OPT_TYPE_CONST, { .i64 = RC_MODE_AUTO }, 0, 0, FLAGS, "rc_mode" }, \ + VAAPI_ENCODE_RC_MODE(CQP, "Constant-quality"), \ + VAAPI_ENCODE_RC_MODE(CBR, "Constant-bitrate"), \ + VAAPI_ENCODE_RC_MODE(VBR, "Variable-bitrate"), \ + VAAPI_ENCODE_RC_MODE(ICQ, "Intelligent constant-quality"), \ + VAAPI_ENCODE_RC_MODE(QVBR, "Quality-defined variable-bitrate"), \ + VAAPI_ENCODE_RC_MODE(AVBR, "Average variable-bitrate") + + #endif /* AVCODEC_VAAPI_ENCODE_H */ diff --git a/libavcodec/vaapi_encode_h264.c b/libavcodec/vaapi_encode_h264.c index 56ad217b4..d1427112e 100644 --- a/libavcodec/vaapi_encode_h264.c +++ b/libavcodec/vaapi_encode_h264.c @@ -30,6 +30,7 @@ #include "cbs.h" #include "cbs_h264.h" #include "h264.h" +#include "h264_levels.h" #include "h264_sei.h" #include "internal.h" #include "vaapi_encode.h" @@ -46,7 +47,33 @@ static const uint8_t vaapi_encode_h264_sei_identifier_uuid[16] = { 0x96, 0x75, 0x19, 0xd4, 0x1f, 0xea, 0xa9, 0x4d, }; +typedef struct VAAPIEncodeH264Picture { + int frame_num; + int pic_order_cnt; + + int64_t last_idr_frame; + uint16_t idr_pic_id; + + int primary_pic_type; + int slice_type; + + int cpb_delay; + int dpb_delay; +} VAAPIEncodeH264Picture; + typedef struct VAAPIEncodeH264Context { + VAAPIEncodeContext common; + + // User options. + int qp; + int quality; + int coder; + int aud; + int sei; + int profile; + int level; + + // Derived settings. int mb_width; int mb_height; @@ -54,56 +81,35 @@ typedef struct VAAPIEncodeH264Context { int fixed_qp_p; int fixed_qp_b; - H264RawAUD aud; - H264RawSPS sps; - H264RawPPS pps; - H264RawSEI sei; - H264RawSlice slice; - - H264RawSEIBufferingPeriod buffering_period; - H264RawSEIPicTiming pic_timing; - H264RawSEIRecoveryPoint recovery_point; - H264RawSEIUserDataUnregistered identifier; - char *identifier_string; - - int frame_num; - int pic_order_cnt; - int next_frame_num; - int64_t last_idr_frame; - int64_t idr_pic_count; - - int primary_pic_type; - int slice_type; - - int cpb_delay; - int dpb_delay; + int dpb_frames; + // Writer structures. CodedBitstreamContext *cbc; CodedBitstreamFragment current_access_unit; + + H264RawAUD raw_aud; + H264RawSPS raw_sps; + H264RawPPS raw_pps; + H264RawSEI raw_sei; + H264RawSlice raw_slice; + + H264RawSEIBufferingPeriod sei_buffering_period; + H264RawSEIPicTiming sei_pic_timing; + H264RawSEIRecoveryPoint sei_recovery_point; + H264RawSEIUserDataUnregistered sei_identifier; + char *sei_identifier_string; + int aud_needed; int sei_needed; int sei_cbr_workaround_needed; } VAAPIEncodeH264Context; -typedef struct VAAPIEncodeH264Options { - int qp; - int quality; - int low_power; - // Entropy encoder type. - int coder; - int aud; - int sei; - int profile; - int level; -} VAAPIEncodeH264Options; - static int vaapi_encode_h264_write_access_unit(AVCodecContext *avctx, char *data, size_t *data_len, CodedBitstreamFragment *au) { - VAAPIEncodeContext *ctx = avctx->priv_data; - VAAPIEncodeH264Context *priv = ctx->priv_data; + VAAPIEncodeH264Context *priv = avctx->priv_data; int err; err = ff_cbs_write_fragment_data(priv->cbc, au); @@ -129,8 +135,7 @@ static int vaapi_encode_h264_add_nal(AVCodecContext *avctx, CodedBitstreamFragment *au, void *nal_unit) { - VAAPIEncodeContext *ctx = avctx->priv_data; - VAAPIEncodeH264Context *priv = ctx->priv_data; + VAAPIEncodeH264Context *priv = avctx->priv_data; H264RawNALUnitHeader *header = nal_unit; int err; @@ -148,29 +153,28 @@ static int vaapi_encode_h264_add_nal(AVCodecContext *avctx, static int vaapi_encode_h264_write_sequence_header(AVCodecContext *avctx, char *data, size_t *data_len) { - VAAPIEncodeContext *ctx = avctx->priv_data; - VAAPIEncodeH264Context *priv = ctx->priv_data; + VAAPIEncodeH264Context *priv = avctx->priv_data; CodedBitstreamFragment *au = &priv->current_access_unit; int err; if (priv->aud_needed) { - err = vaapi_encode_h264_add_nal(avctx, au, &priv->aud); + err = vaapi_encode_h264_add_nal(avctx, au, &priv->raw_aud); if (err < 0) goto fail; priv->aud_needed = 0; } - err = vaapi_encode_h264_add_nal(avctx, au, &priv->sps); + err = vaapi_encode_h264_add_nal(avctx, au, &priv->raw_sps); if (err < 0) goto fail; - err = vaapi_encode_h264_add_nal(avctx, au, &priv->pps); + err = vaapi_encode_h264_add_nal(avctx, au, &priv->raw_pps); if (err < 0) goto fail; err = vaapi_encode_h264_write_access_unit(avctx, data, data_len, au); fail: - ff_cbs_fragment_uninit(priv->cbc, au); + ff_cbs_fragment_reset(priv->cbc, au); return err; } @@ -179,25 +183,24 @@ static int vaapi_encode_h264_write_slice_header(AVCodecContext *avctx, VAAPIEncodeSlice *slice, char *data, size_t *data_len) { - VAAPIEncodeContext *ctx = avctx->priv_data; - VAAPIEncodeH264Context *priv = ctx->priv_data; + VAAPIEncodeH264Context *priv = avctx->priv_data; CodedBitstreamFragment *au = &priv->current_access_unit; int err; if (priv->aud_needed) { - err = vaapi_encode_h264_add_nal(avctx, au, &priv->aud); + err = vaapi_encode_h264_add_nal(avctx, au, &priv->raw_aud); if (err < 0) goto fail; priv->aud_needed = 0; } - err = vaapi_encode_h264_add_nal(avctx, au, &priv->slice); + err = vaapi_encode_h264_add_nal(avctx, au, &priv->raw_slice); if (err < 0) goto fail; err = vaapi_encode_h264_write_access_unit(avctx, data, data_len, au); fail: - ff_cbs_fragment_uninit(priv->cbc, au); + ff_cbs_fragment_reset(priv->cbc, au); return err; } @@ -206,49 +209,53 @@ static int vaapi_encode_h264_write_extra_header(AVCodecContext *avctx, int index, int *type, char *data, size_t *data_len) { - VAAPIEncodeContext *ctx = avctx->priv_data; - VAAPIEncodeH264Context *priv = ctx->priv_data; - VAAPIEncodeH264Options *opt = ctx->codec_options; + VAAPIEncodeH264Context *priv = avctx->priv_data; CodedBitstreamFragment *au = &priv->current_access_unit; int err, i; if (priv->sei_needed) { + H264RawSEI *sei = &priv->raw_sei; + if (priv->aud_needed) { - err = vaapi_encode_h264_add_nal(avctx, au, &priv->aud); + err = vaapi_encode_h264_add_nal(avctx, au, &priv->raw_aud); if (err < 0) goto fail; priv->aud_needed = 0; } - memset(&priv->sei, 0, sizeof(priv->sei)); - priv->sei.nal_unit_header.nal_unit_type = H264_NAL_SEI; + *sei = (H264RawSEI) { + .nal_unit_header = { + .nal_unit_type = H264_NAL_SEI, + }, + }; i = 0; - if (pic->encode_order == 0 && opt->sei & SEI_IDENTIFIER) { - priv->sei.payload[i].payload_type = H264_SEI_TYPE_USER_DATA_UNREGISTERED; - priv->sei.payload[i].payload.user_data_unregistered = priv->identifier; + + if (priv->sei_needed & SEI_IDENTIFIER) { + sei->payload[i].payload_type = H264_SEI_TYPE_USER_DATA_UNREGISTERED; + sei->payload[i].payload.user_data_unregistered = priv->sei_identifier; ++i; } - if (opt->sei & SEI_TIMING) { + if (priv->sei_needed & SEI_TIMING) { if (pic->type == PICTURE_TYPE_IDR) { - priv->sei.payload[i].payload_type = H264_SEI_TYPE_BUFFERING_PERIOD; - priv->sei.payload[i].payload.buffering_period = priv->buffering_period; + sei->payload[i].payload_type = H264_SEI_TYPE_BUFFERING_PERIOD; + sei->payload[i].payload.buffering_period = priv->sei_buffering_period; ++i; } - priv->sei.payload[i].payload_type = H264_SEI_TYPE_PIC_TIMING; - priv->sei.payload[i].payload.pic_timing = priv->pic_timing; + sei->payload[i].payload_type = H264_SEI_TYPE_PIC_TIMING; + sei->payload[i].payload.pic_timing = priv->sei_pic_timing; ++i; } - if (opt->sei & SEI_RECOVERY_POINT && pic->type == PICTURE_TYPE_I) { - priv->sei.payload[i].payload_type = H264_SEI_TYPE_RECOVERY_POINT; - priv->sei.payload[i].payload.recovery_point = priv->recovery_point; + if (priv->sei_needed & SEI_RECOVERY_POINT) { + sei->payload[i].payload_type = H264_SEI_TYPE_RECOVERY_POINT; + sei->payload[i].payload.recovery_point = priv->sei_recovery_point; ++i; } - priv->sei.payload_count = i; - av_assert0(priv->sei.payload_count > 0); + sei->payload_count = i; + av_assert0(sei->payload_count > 0); - err = vaapi_encode_h264_add_nal(avctx, au, &priv->sei); + err = vaapi_encode_h264_add_nal(avctx, au, sei); if (err < 0) goto fail; priv->sei_needed = 0; @@ -257,7 +264,7 @@ static int vaapi_encode_h264_write_extra_header(AVCodecContext *avctx, if (err < 0) goto fail; - ff_cbs_fragment_uninit(priv->cbc, au); + ff_cbs_fragment_reset(priv->cbc, au); *type = VAEncPackedHeaderRawData; return 0; @@ -279,23 +286,19 @@ static int vaapi_encode_h264_write_extra_header(AVCodecContext *avctx, } fail: - ff_cbs_fragment_uninit(priv->cbc, au); + ff_cbs_fragment_reset(priv->cbc, au); return err; } static int vaapi_encode_h264_init_sequence_params(AVCodecContext *avctx) { VAAPIEncodeContext *ctx = avctx->priv_data; - VAAPIEncodeH264Context *priv = ctx->priv_data; - VAAPIEncodeH264Options *opt = ctx->codec_options; - H264RawSPS *sps = &priv->sps; - H264RawPPS *pps = &priv->pps; + VAAPIEncodeH264Context *priv = avctx->priv_data; + H264RawSPS *sps = &priv->raw_sps; + H264RawPPS *pps = &priv->raw_pps; VAEncSequenceParameterBufferH264 *vseq = ctx->codec_sequence_params; VAEncPictureParameterBufferH264 *vpic = ctx->codec_picture_params; - memset(&priv->current_access_unit, 0, - sizeof(priv->current_access_unit)); - memset(sps, 0, sizeof(*sps)); memset(pps, 0, sizeof(*pps)); @@ -303,24 +306,62 @@ static int vaapi_encode_h264_init_sequence_params(AVCodecContext *avctx) sps->nal_unit_header.nal_unit_type = H264_NAL_SPS; sps->profile_idc = avctx->profile & 0xff; - sps->constraint_set1_flag = - !!(avctx->profile & FF_PROFILE_H264_CONSTRAINED); - sps->constraint_set3_flag = - !!(avctx->profile & FF_PROFILE_H264_INTRA); - sps->level_idc = avctx->level; + if (avctx->profile == FF_PROFILE_H264_CONSTRAINED_BASELINE || + avctx->profile == FF_PROFILE_H264_MAIN) + sps->constraint_set1_flag = 1; + + if (avctx->profile == FF_PROFILE_H264_HIGH) + sps->constraint_set3_flag = ctx->gop_size == 1; + + if (avctx->profile == FF_PROFILE_H264_MAIN || + avctx->profile == FF_PROFILE_H264_HIGH) { + sps->constraint_set4_flag = 1; + sps->constraint_set5_flag = ctx->b_per_p == 0; + } + + if (ctx->gop_size == 1) + priv->dpb_frames = 0; + else + priv->dpb_frames = 1 + ctx->max_b_depth; + + if (avctx->level != FF_LEVEL_UNKNOWN) { + sps->level_idc = avctx->level; + } else { + const H264LevelDescriptor *level; + int framerate; + + if (avctx->framerate.num > 0 && avctx->framerate.den > 0) + framerate = avctx->framerate.num / avctx->framerate.den; + else + framerate = 0; + + level = ff_h264_guess_level(sps->profile_idc, + avctx->bit_rate, + framerate, + priv->mb_width * 16, + priv->mb_height * 16, + priv->dpb_frames); + if (level) { + av_log(avctx, AV_LOG_VERBOSE, "Using level %s.\n", level->name); + if (level->constraint_set3_flag) + sps->constraint_set3_flag = 1; + sps->level_idc = level->level_idc; + } else { + av_log(avctx, AV_LOG_WARNING, "Stream will not conform " + "to any level: using level 6.2.\n"); + sps->level_idc = 62; + } + } sps->seq_parameter_set_id = 0; sps->chroma_format_idc = 1; sps->log2_max_frame_num_minus4 = 4; sps->pic_order_cnt_type = 0; - sps->log2_max_pic_order_cnt_lsb_minus4 = - av_clip(av_log2(ctx->b_per_p + 1) - 2, 0, 12); + sps->log2_max_pic_order_cnt_lsb_minus4 = 4; - sps->max_num_ref_frames = - (avctx->profile & FF_PROFILE_H264_INTRA) ? 0 : - 1 + (ctx->b_per_p > 0); + sps->max_num_ref_frames = priv->dpb_frames; sps->pic_width_in_mbs_minus1 = priv->mb_width - 1; sps->pic_height_in_map_units_minus1 = priv->mb_height - 1; @@ -353,18 +394,20 @@ static int vaapi_encode_h264_init_sequence_params(AVCodecContext *avctx) { 80, 33 }, { 18, 11 }, { 15, 11 }, { 64, 33 }, { 160, 99 }, { 4, 3 }, { 3, 2 }, { 2, 1 }, }; - int i; + int num, den, i; + av_reduce(&num, &den, avctx->sample_aspect_ratio.num, + avctx->sample_aspect_ratio.den, 65535); for (i = 0; i < FF_ARRAY_ELEMS(sar_idc); i++) { - if (avctx->sample_aspect_ratio.num == sar_idc[i].num && - avctx->sample_aspect_ratio.den == sar_idc[i].den) { + if (num == sar_idc[i].num && + den == sar_idc[i].den) { sps->vui.aspect_ratio_idc = i; break; } } if (i >= FF_ARRAY_ELEMS(sar_idc)) { sps->vui.aspect_ratio_idc = 255; - sps->vui.sar_width = avctx->sample_aspect_ratio.num; - sps->vui.sar_height = avctx->sample_aspect_ratio.den; + sps->vui.sar_width = num; + sps->vui.sar_height = den; } sps->vui.aspect_ratio_info_present_flag = 1; } @@ -412,8 +455,9 @@ static int vaapi_encode_h264_init_sequence_params(AVCodecContext *avctx) sps->vui.fixed_frame_rate_flag = 0; } - if (opt->sei & SEI_TIMING) { + if (priv->sei & SEI_TIMING) { H264RawHRD *hrd = &sps->vui.nal_hrd_parameters; + H264RawSEIBufferingPeriod *bp = &priv->sei_buffering_period; sps->vui.nal_hrd_parameters_present_flag = 1; @@ -422,14 +466,14 @@ static int vaapi_encode_h264_init_sequence_params(AVCodecContext *avctx) // Try to scale these to a sensible range so that the // golomb encode of the value is not overlong. hrd->bit_rate_scale = - av_clip_uintp2(av_log2(avctx->bit_rate) - 15 - 6, 4); + av_clip_uintp2(av_log2(ctx->va_bit_rate) - 15 - 6, 4); hrd->bit_rate_value_minus1[0] = - (avctx->bit_rate >> hrd->bit_rate_scale + 6) - 1; + (ctx->va_bit_rate >> hrd->bit_rate_scale + 6) - 1; hrd->cpb_size_scale = - av_clip_uintp2(av_log2(ctx->hrd_params.hrd.buffer_size) - 15 - 4, 4); + av_clip_uintp2(av_log2(ctx->hrd_params.buffer_size) - 15 - 4, 4); hrd->cpb_size_value_minus1[0] = - (ctx->hrd_params.hrd.buffer_size >> hrd->cpb_size_scale + 4) - 1; + (ctx->hrd_params.buffer_size >> hrd->cpb_size_scale + 4) - 1; // CBR mode as defined for the HRD cannot be achieved without filler // data, so this flag cannot be set even with VAAPI CBR modes. @@ -440,13 +484,13 @@ static int vaapi_encode_h264_init_sequence_params(AVCodecContext *avctx) hrd->dpb_output_delay_length_minus1 = 7; hrd->time_offset_length = 0; - priv->buffering_period.seq_parameter_set_id = sps->seq_parameter_set_id; + bp->seq_parameter_set_id = sps->seq_parameter_set_id; // This calculation can easily overflow 32 bits. - priv->buffering_period.nal.initial_cpb_removal_delay[0] = 90000 * - (uint64_t)ctx->hrd_params.hrd.initial_buffer_fullness / - ctx->hrd_params.hrd.buffer_size; - priv->buffering_period.nal.initial_cpb_removal_delay_offset[0] = 0; + bp->nal.initial_cpb_removal_delay[0] = 90000 * + (uint64_t)ctx->hrd_params.initial_buffer_fullness / + ctx->hrd_params.buffer_size; + bp->nal.initial_cpb_removal_delay_offset[0] = 0; } else { sps->vui.nal_hrd_parameters_present_flag = 0; sps->vui.low_delay_hrd_flag = 1 - sps->vui.fixed_frame_rate_flag; @@ -454,10 +498,10 @@ static int vaapi_encode_h264_init_sequence_params(AVCodecContext *avctx) sps->vui.bitstream_restriction_flag = 1; sps->vui.motion_vectors_over_pic_boundaries_flag = 1; - sps->vui.log2_max_mv_length_horizontal = 16; - sps->vui.log2_max_mv_length_vertical = 16; - sps->vui.max_num_reorder_frames = (ctx->b_per_p > 0); - sps->vui.max_dec_frame_buffering = sps->max_num_ref_frames; + sps->vui.log2_max_mv_length_horizontal = 15; + sps->vui.log2_max_mv_length_vertical = 15; + sps->vui.max_num_reorder_frames = ctx->max_b_depth; + sps->vui.max_dec_frame_buffering = ctx->max_b_depth + 1; pps->nal_unit_header.nal_ref_idc = 3; pps->nal_unit_header.nal_unit_type = H264_NAL_PPS; @@ -469,7 +513,7 @@ static int vaapi_encode_h264_init_sequence_params(AVCodecContext *avctx) !(sps->profile_idc == FF_PROFILE_H264_BASELINE || sps->profile_idc == FF_PROFILE_H264_EXTENDED || sps->profile_idc == FF_PROFILE_H264_CAVLC_444); - if (!opt->coder && pps->entropy_coding_mode_flag) + if (!priv->coder && pps->entropy_coding_mode_flag) pps->entropy_coding_mode_flag = 0; pps->num_ref_idx_l0_default_active_minus1 = 0; @@ -490,11 +534,11 @@ static int vaapi_encode_h264_init_sequence_params(AVCodecContext *avctx) *vseq = (VAEncSequenceParameterBufferH264) { .seq_parameter_set_id = sps->seq_parameter_set_id, .level_idc = sps->level_idc, - .intra_period = avctx->gop_size, - .intra_idr_period = avctx->gop_size, + .intra_period = ctx->gop_size, + .intra_idr_period = ctx->gop_size, .ip_period = ctx->b_per_p + 1, - .bits_per_second = avctx->bit_rate, + .bits_per_second = ctx->va_bit_rate, .max_num_ref_frames = sps->max_num_ref_frames, .picture_width_in_mbs = sps->pic_width_in_mbs_minus1 + 1, .picture_height_in_mbs = sps->pic_height_in_map_units_minus1 + 1, @@ -577,102 +621,106 @@ static int vaapi_encode_h264_init_picture_params(AVCodecContext *avctx, VAAPIEncodePicture *pic) { VAAPIEncodeContext *ctx = avctx->priv_data; - VAAPIEncodeH264Context *priv = ctx->priv_data; - VAAPIEncodeH264Options *opt = ctx->codec_options; - H264RawSPS *sps = &priv->sps; + VAAPIEncodeH264Context *priv = avctx->priv_data; + VAAPIEncodeH264Picture *hpic = pic->priv_data; + VAAPIEncodePicture *prev = pic->prev; + VAAPIEncodeH264Picture *hprev = prev ? prev->priv_data : NULL; VAEncPictureParameterBufferH264 *vpic = pic->codec_picture_params; int i; - memset(&priv->current_access_unit, 0, - sizeof(priv->current_access_unit)); - if (pic->type == PICTURE_TYPE_IDR) { av_assert0(pic->display_order == pic->encode_order); - priv->frame_num = 0; - priv->next_frame_num = 1; - priv->cpb_delay = 0; - priv->last_idr_frame = pic->display_order; - ++priv->idr_pic_count; - priv->slice_type = 7; - priv->primary_pic_type = 0; + hpic->frame_num = 0; + hpic->last_idr_frame = pic->display_order; + hpic->idr_pic_id = hprev ? hprev->idr_pic_id + 1 : 0; + + hpic->primary_pic_type = 0; + hpic->slice_type = 7; } else { - priv->frame_num = priv->next_frame_num; + av_assert0(prev); - if (pic->type != PICTURE_TYPE_B) { - // Reference picture, so frame_num advances. - priv->next_frame_num = (priv->frame_num + 1) & - ((1 << (4 + sps->log2_max_frame_num_minus4)) - 1); - } - ++priv->cpb_delay; + hpic->frame_num = hprev->frame_num + prev->is_reference; + + hpic->last_idr_frame = hprev->last_idr_frame; + hpic->idr_pic_id = hprev->idr_pic_id; if (pic->type == PICTURE_TYPE_I) { - priv->slice_type = 7; - priv->primary_pic_type = 0; + hpic->slice_type = 7; + hpic->primary_pic_type = 0; } else if (pic->type == PICTURE_TYPE_P) { - priv->slice_type = 5; - priv->primary_pic_type = 1; + hpic->slice_type = 5; + hpic->primary_pic_type = 1; } else { - priv->slice_type = 6; - priv->primary_pic_type = 2; + hpic->slice_type = 6; + hpic->primary_pic_type = 2; } } - priv->pic_order_cnt = pic->display_order - priv->last_idr_frame; - priv->dpb_delay = pic->display_order - pic->encode_order + 1; + hpic->pic_order_cnt = pic->display_order - hpic->last_idr_frame; + hpic->dpb_delay = pic->display_order - pic->encode_order + ctx->max_b_depth; + hpic->cpb_delay = pic->encode_order - hpic->last_idr_frame; - if (opt->aud) { + if (priv->aud) { priv->aud_needed = 1; - priv->aud.nal_unit_header.nal_unit_type = H264_NAL_AUD; - priv->aud.primary_pic_type = priv->primary_pic_type; + priv->raw_aud = (H264RawAUD) { + .nal_unit_header = { + .nal_unit_type = H264_NAL_AUD, + }, + .primary_pic_type = hpic->primary_pic_type, + }; } else { priv->aud_needed = 0; } - if (opt->sei & SEI_IDENTIFIER && pic->encode_order == 0) - priv->sei_needed = 1; + priv->sei_needed = 0; + + if (priv->sei & SEI_IDENTIFIER && pic->encode_order == 0) + priv->sei_needed |= SEI_IDENTIFIER; #if !CONFIG_VAAPI_1 if (ctx->va_rc_mode == VA_RC_CBR) priv->sei_cbr_workaround_needed = 1; #endif - if (opt->sei & SEI_TIMING) { - memset(&priv->pic_timing, 0, sizeof(priv->pic_timing)); + if (priv->sei & SEI_TIMING) { + priv->sei_pic_timing = (H264RawSEIPicTiming) { + .cpb_removal_delay = 2 * hpic->cpb_delay, + .dpb_output_delay = 2 * hpic->dpb_delay, + }; - priv->pic_timing.cpb_removal_delay = 2 * priv->cpb_delay; - priv->pic_timing.dpb_output_delay = 2 * priv->dpb_delay; - - priv->sei_needed = 1; + priv->sei_needed |= SEI_TIMING; } - if (opt->sei & SEI_RECOVERY_POINT && pic->type == PICTURE_TYPE_I) { - priv->recovery_point.recovery_frame_cnt = 0; - priv->recovery_point.exact_match_flag = 1; - priv->recovery_point.broken_link_flag = ctx->b_per_p > 0; + if (priv->sei & SEI_RECOVERY_POINT && pic->type == PICTURE_TYPE_I) { + priv->sei_recovery_point = (H264RawSEIRecoveryPoint) { + .recovery_frame_cnt = 0, + .exact_match_flag = 1, + .broken_link_flag = ctx->b_per_p > 0, + }; - priv->sei_needed = 1; + priv->sei_needed |= SEI_RECOVERY_POINT; } vpic->CurrPic = (VAPictureH264) { .picture_id = pic->recon_surface, - .frame_idx = priv->frame_num, + .frame_idx = hpic->frame_num, .flags = 0, - .TopFieldOrderCnt = priv->pic_order_cnt, - .BottomFieldOrderCnt = priv->pic_order_cnt, + .TopFieldOrderCnt = hpic->pic_order_cnt, + .BottomFieldOrderCnt = hpic->pic_order_cnt, }; for (i = 0; i < pic->nb_refs; i++) { - VAAPIEncodePicture *ref = pic->refs[i]; - unsigned int frame_num = (ref->encode_order - priv->last_idr_frame) & - ((1 << (4 + sps->log2_max_frame_num_minus4)) - 1); - unsigned int pic_order_cnt = ref->display_order - priv->last_idr_frame; + VAAPIEncodePicture *ref = pic->refs[i]; + VAAPIEncodeH264Picture *href; av_assert0(ref && ref->encode_order < pic->encode_order); + href = ref->priv_data; + vpic->ReferenceFrames[i] = (VAPictureH264) { .picture_id = ref->recon_surface, - .frame_idx = frame_num, + .frame_idx = href->frame_num, .flags = VA_PICTURE_H264_SHORT_TERM_REFERENCE, - .TopFieldOrderCnt = pic_order_cnt, - .BottomFieldOrderCnt = pic_order_cnt, + .TopFieldOrderCnt = href->pic_order_cnt, + .BottomFieldOrderCnt = href->pic_order_cnt, }; } for (; i < FF_ARRAY_ELEMS(vpic->ReferenceFrames); i++) { @@ -684,47 +732,142 @@ static int vaapi_encode_h264_init_picture_params(AVCodecContext *avctx, vpic->coded_buf = pic->output_buffer; - vpic->frame_num = priv->frame_num; + vpic->frame_num = hpic->frame_num; vpic->pic_fields.bits.idr_pic_flag = (pic->type == PICTURE_TYPE_IDR); vpic->pic_fields.bits.reference_pic_flag = (pic->type != PICTURE_TYPE_B); - pic->nb_slices = 1; - return 0; } +static void vaapi_encode_h264_default_ref_pic_list(AVCodecContext *avctx, + VAAPIEncodePicture *pic, + VAAPIEncodePicture **rpl0, + VAAPIEncodePicture **rpl1, + int *rpl_size) +{ + VAAPIEncodePicture *prev; + VAAPIEncodeH264Picture *hp, *hn, *hc; + int i, j, n = 0; + + prev = pic->prev; + av_assert0(prev); + hp = pic->priv_data; + + for (i = 0; i < pic->prev->nb_dpb_pics; i++) { + hn = prev->dpb[i]->priv_data; + av_assert0(hn->frame_num < hp->frame_num); + + if (pic->type == PICTURE_TYPE_P) { + for (j = n; j > 0; j--) { + hc = rpl0[j - 1]->priv_data; + av_assert0(hc->frame_num != hn->frame_num); + if (hc->frame_num > hn->frame_num) + break; + rpl0[j] = rpl0[j - 1]; + } + rpl0[j] = prev->dpb[i]; + + } else if (pic->type == PICTURE_TYPE_B) { + for (j = n; j > 0; j--) { + hc = rpl0[j - 1]->priv_data; + av_assert0(hc->pic_order_cnt != hp->pic_order_cnt); + if (hc->pic_order_cnt < hp->pic_order_cnt) { + if (hn->pic_order_cnt > hp->pic_order_cnt || + hn->pic_order_cnt < hc->pic_order_cnt) + break; + } else { + if (hn->pic_order_cnt > hc->pic_order_cnt) + break; + } + rpl0[j] = rpl0[j - 1]; + } + rpl0[j] = prev->dpb[i]; + + for (j = n; j > 0; j--) { + hc = rpl1[j - 1]->priv_data; + av_assert0(hc->pic_order_cnt != hp->pic_order_cnt); + if (hc->pic_order_cnt > hp->pic_order_cnt) { + if (hn->pic_order_cnt < hp->pic_order_cnt || + hn->pic_order_cnt > hc->pic_order_cnt) + break; + } else { + if (hn->pic_order_cnt < hc->pic_order_cnt) + break; + } + rpl1[j] = rpl1[j - 1]; + } + rpl1[j] = prev->dpb[i]; + } + + ++n; + } + + if (pic->type == PICTURE_TYPE_B) { + for (i = 0; i < n; i++) { + if (rpl0[i] != rpl1[i]) + break; + } + if (i == n) + FFSWAP(VAAPIEncodePicture*, rpl1[0], rpl1[1]); + } + + if (pic->type == PICTURE_TYPE_P || + pic->type == PICTURE_TYPE_B) { + av_log(avctx, AV_LOG_DEBUG, "Default RefPicList0 for fn=%d/poc=%d:", + hp->frame_num, hp->pic_order_cnt); + for (i = 0; i < n; i++) { + hn = rpl0[i]->priv_data; + av_log(avctx, AV_LOG_DEBUG, " fn=%d/poc=%d", + hn->frame_num, hn->pic_order_cnt); + } + av_log(avctx, AV_LOG_DEBUG, "\n"); + } + if (pic->type == PICTURE_TYPE_B) { + av_log(avctx, AV_LOG_DEBUG, "Default RefPicList1 for fn=%d/poc=%d:", + hp->frame_num, hp->pic_order_cnt); + for (i = 0; i < n; i++) { + hn = rpl1[i]->priv_data; + av_log(avctx, AV_LOG_DEBUG, " fn=%d/poc=%d", + hn->frame_num, hn->pic_order_cnt); + } + av_log(avctx, AV_LOG_DEBUG, "\n"); + } + + *rpl_size = n; +} + static int vaapi_encode_h264_init_slice_params(AVCodecContext *avctx, VAAPIEncodePicture *pic, VAAPIEncodeSlice *slice) { - VAAPIEncodeContext *ctx = avctx->priv_data; - VAAPIEncodeH264Context *priv = ctx->priv_data; - H264RawSPS *sps = &priv->sps; - H264RawPPS *pps = &priv->pps; - H264RawSliceHeader *sh = &priv->slice.header; + VAAPIEncodeH264Context *priv = avctx->priv_data; + VAAPIEncodeH264Picture *hpic = pic->priv_data; + VAAPIEncodePicture *prev = pic->prev; + H264RawSPS *sps = &priv->raw_sps; + H264RawPPS *pps = &priv->raw_pps; + H264RawSliceHeader *sh = &priv->raw_slice.header; VAEncPictureParameterBufferH264 *vpic = pic->codec_picture_params; VAEncSliceParameterBufferH264 *vslice = slice->codec_slice_params; - int i; + int i, j; if (pic->type == PICTURE_TYPE_IDR) { sh->nal_unit_header.nal_unit_type = H264_NAL_IDR_SLICE; sh->nal_unit_header.nal_ref_idc = 3; } else { sh->nal_unit_header.nal_unit_type = H264_NAL_SLICE; - sh->nal_unit_header.nal_ref_idc = pic->type != PICTURE_TYPE_B; + sh->nal_unit_header.nal_ref_idc = pic->is_reference; } - // Only one slice per frame. - sh->first_mb_in_slice = 0; - sh->slice_type = priv->slice_type; + sh->first_mb_in_slice = slice->block_start; + sh->slice_type = hpic->slice_type; sh->pic_parameter_set_id = pps->pic_parameter_set_id; - sh->frame_num = priv->frame_num; - sh->idr_pic_id = priv->idr_pic_count; - - sh->pic_order_cnt_lsb = priv->pic_order_cnt & + sh->frame_num = hpic->frame_num & + ((1 << (4 + sps->log2_max_frame_num_minus4)) - 1); + sh->idr_pic_id = hpic->idr_pic_id; + sh->pic_order_cnt_lsb = hpic->pic_order_cnt & ((1 << (4 + sps->log2_max_pic_order_cnt_lsb_minus4)) - 1); sh->direct_spatial_mv_pred_flag = 1; @@ -736,9 +879,149 @@ static int vaapi_encode_h264_init_slice_params(AVCodecContext *avctx, else sh->slice_qp_delta = priv->fixed_qp_idr - (pps->pic_init_qp_minus26 + 26); + if (pic->is_reference && pic->type != PICTURE_TYPE_IDR) { + VAAPIEncodePicture *discard_list[MAX_DPB_SIZE]; + int discard = 0, keep = 0; - vslice->macroblock_address = sh->first_mb_in_slice; - vslice->num_macroblocks = priv->mb_width * priv->mb_height; + // Discard everything which is in the DPB of the previous frame but + // not in the DPB of this one. + for (i = 0; i < prev->nb_dpb_pics; i++) { + for (j = 0; j < pic->nb_dpb_pics; j++) { + if (prev->dpb[i] == pic->dpb[j]) + break; + } + if (j == pic->nb_dpb_pics) { + discard_list[discard] = prev->dpb[i]; + ++discard; + } else { + ++keep; + } + } + av_assert0(keep <= priv->dpb_frames); + + if (discard == 0) { + sh->adaptive_ref_pic_marking_mode_flag = 0; + } else { + sh->adaptive_ref_pic_marking_mode_flag = 1; + for (i = 0; i < discard; i++) { + VAAPIEncodeH264Picture *old = discard_list[i]->priv_data; + av_assert0(old->frame_num < hpic->frame_num); + sh->mmco[i].memory_management_control_operation = 1; + sh->mmco[i].difference_of_pic_nums_minus1 = + hpic->frame_num - old->frame_num - 1; + } + sh->mmco[i].memory_management_control_operation = 0; + } + } + + // If the intended references are not the first entries of RefPicListN + // by default, use ref-pic-list-modification to move them there. + if (pic->type == PICTURE_TYPE_P || pic->type == PICTURE_TYPE_B) { + VAAPIEncodePicture *def_l0[MAX_DPB_SIZE], *def_l1[MAX_DPB_SIZE]; + VAAPIEncodeH264Picture *href; + int n; + + vaapi_encode_h264_default_ref_pic_list(avctx, pic, + def_l0, def_l1, &n); + + if (pic->type == PICTURE_TYPE_P) { + int need_rplm = 0; + for (i = 0; i < pic->nb_refs; i++) { + av_assert0(pic->refs[i]); + if (pic->refs[i] != def_l0[i]) + need_rplm = 1; + } + + sh->ref_pic_list_modification_flag_l0 = need_rplm; + if (need_rplm) { + int pic_num = hpic->frame_num; + for (i = 0; i < pic->nb_refs; i++) { + href = pic->refs[i]->priv_data; + av_assert0(href->frame_num != pic_num); + if (href->frame_num < pic_num) { + sh->rplm_l0[i].modification_of_pic_nums_idc = 0; + sh->rplm_l0[i].abs_diff_pic_num_minus1 = + pic_num - href->frame_num - 1; + } else { + sh->rplm_l0[i].modification_of_pic_nums_idc = 1; + sh->rplm_l0[i].abs_diff_pic_num_minus1 = + href->frame_num - pic_num - 1; + } + pic_num = href->frame_num; + } + sh->rplm_l0[i].modification_of_pic_nums_idc = 3; + } + + } else { + int need_rplm_l0 = 0, need_rplm_l1 = 0; + int n0 = 0, n1 = 0; + for (i = 0; i < pic->nb_refs; i++) { + av_assert0(pic->refs[i]); + href = pic->refs[i]->priv_data; + av_assert0(href->pic_order_cnt != hpic->pic_order_cnt); + if (href->pic_order_cnt < hpic->pic_order_cnt) { + if (pic->refs[i] != def_l0[n0]) + need_rplm_l0 = 1; + ++n0; + } else { + if (pic->refs[i] != def_l1[n1]) + need_rplm_l1 = 1; + ++n1; + } + } + + sh->ref_pic_list_modification_flag_l0 = need_rplm_l0; + if (need_rplm_l0) { + int pic_num = hpic->frame_num; + for (i = j = 0; i < pic->nb_refs; i++) { + href = pic->refs[i]->priv_data; + if (href->pic_order_cnt > hpic->pic_order_cnt) + continue; + av_assert0(href->frame_num != pic_num); + if (href->frame_num < pic_num) { + sh->rplm_l0[j].modification_of_pic_nums_idc = 0; + sh->rplm_l0[j].abs_diff_pic_num_minus1 = + pic_num - href->frame_num - 1; + } else { + sh->rplm_l0[j].modification_of_pic_nums_idc = 1; + sh->rplm_l0[j].abs_diff_pic_num_minus1 = + href->frame_num - pic_num - 1; + } + pic_num = href->frame_num; + ++j; + } + av_assert0(j == n0); + sh->rplm_l0[j].modification_of_pic_nums_idc = 3; + } + + sh->ref_pic_list_modification_flag_l1 = need_rplm_l1; + if (need_rplm_l1) { + int pic_num = hpic->frame_num; + for (i = j = 0; i < pic->nb_refs; i++) { + href = pic->refs[i]->priv_data; + if (href->pic_order_cnt < hpic->pic_order_cnt) + continue; + av_assert0(href->frame_num != pic_num); + if (href->frame_num < pic_num) { + sh->rplm_l1[j].modification_of_pic_nums_idc = 0; + sh->rplm_l1[j].abs_diff_pic_num_minus1 = + pic_num - href->frame_num - 1; + } else { + sh->rplm_l1[j].modification_of_pic_nums_idc = 1; + sh->rplm_l1[j].abs_diff_pic_num_minus1 = + href->frame_num - pic_num - 1; + } + pic_num = href->frame_num; + ++j; + } + av_assert0(j == n1); + sh->rplm_l1[j].modification_of_pic_nums_idc = 3; + } + } + } + + vslice->macroblock_address = slice->block_start; + vslice->num_macroblocks = slice->block_size; vslice->macroblock_info = VA_INVALID_ID; @@ -778,8 +1061,7 @@ static int vaapi_encode_h264_init_slice_params(AVCodecContext *avctx, static av_cold int vaapi_encode_h264_configure(AVCodecContext *avctx) { VAAPIEncodeContext *ctx = avctx->priv_data; - VAAPIEncodeH264Context *priv = ctx->priv_data; - VAAPIEncodeH264Options *opt = ctx->codec_options; + VAAPIEncodeH264Context *priv = avctx->priv_data; int err; err = ff_cbs_init(&priv->cbc, AV_CODEC_ID_H264, avctx); @@ -790,51 +1072,45 @@ static av_cold int vaapi_encode_h264_configure(AVCodecContext *avctx) priv->mb_height = FFALIGN(avctx->height, 16) / 16; if (ctx->va_rc_mode == VA_RC_CQP) { - priv->fixed_qp_p = opt->qp; + priv->fixed_qp_p = av_clip(ctx->rc_quality, 1, 51); if (avctx->i_quant_factor > 0.0) - priv->fixed_qp_idr = (int)((priv->fixed_qp_p * avctx->i_quant_factor + - avctx->i_quant_offset) + 0.5); + priv->fixed_qp_idr = + av_clip((avctx->i_quant_factor * priv->fixed_qp_p + + avctx->i_quant_offset) + 0.5, 1, 51); else priv->fixed_qp_idr = priv->fixed_qp_p; if (avctx->b_quant_factor > 0.0) - priv->fixed_qp_b = (int)((priv->fixed_qp_p * avctx->b_quant_factor + - avctx->b_quant_offset) + 0.5); + priv->fixed_qp_b = + av_clip((avctx->b_quant_factor * priv->fixed_qp_p + + avctx->b_quant_offset) + 0.5, 1, 51); else priv->fixed_qp_b = priv->fixed_qp_p; - opt->sei &= ~SEI_TIMING; - av_log(avctx, AV_LOG_DEBUG, "Using fixed QP = " "%d / %d / %d for IDR- / P- / B-frames.\n", priv->fixed_qp_idr, priv->fixed_qp_p, priv->fixed_qp_b); - } else if (ctx->va_rc_mode == VA_RC_CBR || - ctx->va_rc_mode == VA_RC_VBR) { + } else { // These still need to be set for pic_init_qp/slice_qp_delta. priv->fixed_qp_idr = 26; priv->fixed_qp_p = 26; priv->fixed_qp_b = 26; - - av_log(avctx, AV_LOG_DEBUG, "Using %s-bitrate = %"PRId64" bps.\n", - ctx->va_rc_mode == VA_RC_CBR ? "constant" : "variable", - avctx->bit_rate); - - } else { - av_assert0(0 && "Invalid RC mode."); } - if (avctx->compression_level == FF_COMPRESSION_DEFAULT) - avctx->compression_level = opt->quality; + if (!ctx->rc_mode->hrd) { + // Timing SEI requires a mode respecting HRD parameters. + priv->sei &= ~SEI_TIMING; + } - if (opt->sei & SEI_IDENTIFIER) { + if (priv->sei & SEI_IDENTIFIER) { const char *lavc = LIBAVCODEC_IDENT; const char *vaapi = VA_VERSION_S; const char *driver; int len; - memcpy(priv->identifier.uuid_iso_iec_11578, + memcpy(priv->sei_identifier.uuid_iso_iec_11578, vaapi_encode_h264_sei_identifier_uuid, - sizeof(priv->identifier.uuid_iso_iec_11578)); + sizeof(priv->sei_identifier.uuid_iso_iec_11578)); driver = vaQueryVendorString(ctx->hwctx->display); if (!driver) @@ -842,26 +1118,43 @@ static av_cold int vaapi_encode_h264_configure(AVCodecContext *avctx) len = snprintf(NULL, 0, "%s / VAAPI %s / %s", lavc, vaapi, driver); if (len >= 0) { - priv->identifier_string = av_malloc(len + 1); - if (!priv->identifier_string) + priv->sei_identifier_string = av_malloc(len + 1); + if (!priv->sei_identifier_string) return AVERROR(ENOMEM); - snprintf(priv->identifier_string, len + 1, + snprintf(priv->sei_identifier_string, len + 1, "%s / VAAPI %s / %s", lavc, vaapi, driver); - priv->identifier.data = priv->identifier_string; - priv->identifier.data_length = len + 1; + priv->sei_identifier.data = priv->sei_identifier_string; + priv->sei_identifier.data_length = len + 1; } } return 0; } +static const VAAPIEncodeProfile vaapi_encode_h264_profiles[] = { + { FF_PROFILE_H264_HIGH, 8, 3, 1, 1, VAProfileH264High }, + { FF_PROFILE_H264_MAIN, 8, 3, 1, 1, VAProfileH264Main }, + { FF_PROFILE_H264_CONSTRAINED_BASELINE, + 8, 3, 1, 1, VAProfileH264ConstrainedBaseline }, + { FF_PROFILE_UNKNOWN } +}; + static const VAAPIEncodeType vaapi_encode_type_h264 = { - .priv_data_size = sizeof(VAAPIEncodeH264Context), + .profiles = vaapi_encode_h264_profiles, + + .flags = FLAG_SLICE_CONTROL | + FLAG_B_PICTURES | + FLAG_B_PICTURE_REFERENCES | + FLAG_NON_IDR_KEY_PICTURES, + + .default_quality = 20, .configure = &vaapi_encode_h264_configure, + .picture_priv_data_size = sizeof(VAAPIEncodeH264Picture), + .sequence_params_size = sizeof(VAEncSequenceParameterBufferH264), .init_sequence_params = &vaapi_encode_h264_init_sequence_params, @@ -882,41 +1175,29 @@ static const VAAPIEncodeType vaapi_encode_type_h264 = { static av_cold int vaapi_encode_h264_init(AVCodecContext *avctx) { - VAAPIEncodeContext *ctx = avctx->priv_data; - VAAPIEncodeH264Options *opt = - (VAAPIEncodeH264Options*)ctx->codec_options_data; + VAAPIEncodeContext *ctx = avctx->priv_data; + VAAPIEncodeH264Context *priv = avctx->priv_data; ctx->codec = &vaapi_encode_type_h264; if (avctx->profile == FF_PROFILE_UNKNOWN) - avctx->profile = opt->profile; + avctx->profile = priv->profile; if (avctx->level == FF_LEVEL_UNKNOWN) - avctx->level = opt->level; + avctx->level = priv->level; + if (avctx->compression_level == FF_COMPRESSION_DEFAULT) + avctx->compression_level = priv->quality; + // Reject unsupported profiles. switch (avctx->profile) { case FF_PROFILE_H264_BASELINE: av_log(avctx, AV_LOG_WARNING, "H.264 baseline profile is not " "supported, using constrained baseline profile instead.\n"); avctx->profile = FF_PROFILE_H264_CONSTRAINED_BASELINE; - case FF_PROFILE_H264_CONSTRAINED_BASELINE: - ctx->va_profile = VAProfileH264ConstrainedBaseline; - if (avctx->max_b_frames != 0) { - avctx->max_b_frames = 0; - av_log(avctx, AV_LOG_WARNING, "H.264 constrained baseline profile " - "doesn't support encoding with B frames, disabling them.\n"); - } - break; - case FF_PROFILE_H264_MAIN: - ctx->va_profile = VAProfileH264Main; break; case FF_PROFILE_H264_EXTENDED: av_log(avctx, AV_LOG_ERROR, "H.264 extended profile " "is not supported.\n"); return AVERROR_PATCHWELCOME; - case FF_PROFILE_UNKNOWN: - case FF_PROFILE_H264_HIGH: - ctx->va_profile = VAProfileH264High; - break; case FF_PROFILE_H264_HIGH_10: case FF_PROFILE_H264_HIGH_10_INTRA: av_log(avctx, AV_LOG_ERROR, "H.264 10-bit profiles " @@ -931,35 +1212,15 @@ static av_cold int vaapi_encode_h264_init(AVCodecContext *avctx) av_log(avctx, AV_LOG_ERROR, "H.264 non-4:2:0 profiles " "are not supported.\n"); return AVERROR_PATCHWELCOME; - default: - av_log(avctx, AV_LOG_ERROR, "Unknown H.264 profile %d.\n", - avctx->profile); - return AVERROR(EINVAL); - } - if (opt->low_power) { -#if VA_CHECK_VERSION(0, 39, 2) - ctx->va_entrypoint = VAEntrypointEncSliceLP; -#else - av_log(avctx, AV_LOG_ERROR, "Low-power encoding is not " - "supported with this VAAPI version.\n"); - return AVERROR(EINVAL); -#endif - } else { - ctx->va_entrypoint = VAEntrypointEncSlice; } - // Only 8-bit encode is supported. - ctx->va_rt_format = VA_RT_FORMAT_YUV420; + if (avctx->level != FF_LEVEL_UNKNOWN && avctx->level & ~0xff) { + av_log(avctx, AV_LOG_ERROR, "Invalid level %d: must fit " + "in 8-bit unsigned integer.\n", avctx->level); + return AVERROR(EINVAL); + } - if (avctx->bit_rate > 0) { - if (avctx->rc_max_rate == avctx->bit_rate) - ctx->va_rc_mode = VA_RC_CBR; - else - ctx->va_rc_mode = VA_RC_VBR; - } else - ctx->va_rc_mode = VA_RC_CQP; - - ctx->va_packed_headers = + ctx->desired_packed_headers = VA_ENC_PACKED_HEADER_SEQUENCE | // SPS and PPS. VA_ENC_PACKED_HEADER_SLICE | // Slice headers. VA_ENC_PACKED_HEADER_MISC; // SEI. @@ -967,33 +1228,35 @@ static av_cold int vaapi_encode_h264_init(AVCodecContext *avctx) ctx->surface_width = FFALIGN(avctx->width, 16); ctx->surface_height = FFALIGN(avctx->height, 16); + ctx->slice_block_height = ctx->slice_block_width = 16; + + if (priv->qp > 0) + ctx->explicit_qp = priv->qp; + return ff_vaapi_encode_init(avctx); } static av_cold int vaapi_encode_h264_close(AVCodecContext *avctx) { - VAAPIEncodeContext *ctx = avctx->priv_data; - VAAPIEncodeH264Context *priv = ctx->priv_data; + VAAPIEncodeH264Context *priv = avctx->priv_data; - if (priv) { - ff_cbs_close(&priv->cbc); - av_freep(&priv->identifier_string); - } + ff_cbs_fragment_free(priv->cbc, &priv->current_access_unit); + ff_cbs_close(&priv->cbc); + av_freep(&priv->sei_identifier_string); return ff_vaapi_encode_close(avctx); } -#define OFFSET(x) (offsetof(VAAPIEncodeContext, codec_options_data) + \ - offsetof(VAAPIEncodeH264Options, x)) +#define OFFSET(x) offsetof(VAAPIEncodeH264Context, x) #define FLAGS (AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM) static const AVOption vaapi_encode_h264_options[] = { + VAAPI_ENCODE_COMMON_OPTIONS, + VAAPI_ENCODE_RC_OPTIONS, + { "qp", "Constant QP (for P-frames; scaled by qfactor/qoffset for I/B)", - OFFSET(qp), AV_OPT_TYPE_INT, { .i64 = 20 }, 0, 52, FLAGS }, + OFFSET(qp), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 52, FLAGS }, { "quality", "Set encode quality (trades off against speed, higher is faster)", - OFFSET(quality), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 8, FLAGS }, - { "low_power", "Use low-power encoding mode (experimental: only supported " - "on some platforms, does not support all features)", - OFFSET(low_power), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, FLAGS }, + OFFSET(quality), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, FLAGS }, { "coder", "Entropy coder type", OFFSET(coder), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, 1, FLAGS, "coder" }, { "cavlc", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 0 }, INT_MIN, INT_MAX, FLAGS, "coder" }, @@ -1002,7 +1265,7 @@ static const AVOption vaapi_encode_h264_options[] = { { "ac", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 1 }, INT_MIN, INT_MAX, FLAGS, "coder" }, { "aud", "Include AUD", - OFFSET(aud), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, FLAGS }, + OFFSET(aud), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, FLAGS }, { "sei", "Set SEI to include", OFFSET(sei), AV_OPT_TYPE_FLAGS, @@ -1020,7 +1283,7 @@ static const AVOption vaapi_encode_h264_options[] = { { "profile", "Set profile (profile_idc and constraint_set*_flag)", OFFSET(profile), AV_OPT_TYPE_INT, - { .i64 = FF_PROFILE_H264_HIGH }, 0x0000, 0xffff, FLAGS, "profile" }, + { .i64 = FF_PROFILE_UNKNOWN }, FF_PROFILE_UNKNOWN, 0xffff, FLAGS, "profile" }, #define PROFILE(name, value) name, NULL, 0, AV_OPT_TYPE_CONST, \ { .i64 = value }, 0, 0, FLAGS, "profile" @@ -1031,7 +1294,7 @@ static const AVOption vaapi_encode_h264_options[] = { { "level", "Set level (level_idc)", OFFSET(level), AV_OPT_TYPE_INT, - { .i64 = 51 }, 0x00, 0xff, FLAGS, "level" }, + { .i64 = FF_LEVEL_UNKNOWN }, FF_LEVEL_UNKNOWN, 0xff, FLAGS, "level" }, #define LEVEL(name, value) name, NULL, 0, AV_OPT_TYPE_CONST, \ { .i64 = value }, 0, 0, FLAGS, "level" @@ -1067,7 +1330,8 @@ static const AVCodecDefault vaapi_encode_h264_defaults[] = { { "i_qoffset", "0" }, { "b_qfactor", "6/5" }, { "b_qoffset", "0" }, - { "qmin", "0" }, + { "qmin", "-1" }, + { "qmax", "-1" }, { NULL }, }; @@ -1083,10 +1347,10 @@ AVCodec ff_h264_vaapi_encoder = { .long_name = NULL_IF_CONFIG_SMALL("H.264/AVC (VAAPI)"), .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_H264, - .priv_data_size = (sizeof(VAAPIEncodeContext) + - sizeof(VAAPIEncodeH264Options)), + .priv_data_size = sizeof(VAAPIEncodeH264Context), .init = &vaapi_encode_h264_init, - .encode2 = &ff_vaapi_encode2, + .send_frame = &ff_vaapi_encode_send_frame, + .receive_packet = &ff_vaapi_encode_receive_packet, .close = &vaapi_encode_h264_close, .priv_class = &vaapi_encode_h264_class, .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HARDWARE, diff --git a/libavcodec/vaapi_encode_h265.c b/libavcodec/vaapi_encode_h265.c index 5203c6871..758bd40a3 100644 --- a/libavcodec/vaapi_encode_h265.c +++ b/libavcodec/vaapi_encode_h265.c @@ -23,57 +23,74 @@ #include "libavutil/avassert.h" #include "libavutil/common.h" +#include "libavutil/pixdesc.h" #include "libavutil/opt.h" +#include "libavutil/mastering_display_metadata.h" #include "avcodec.h" #include "cbs.h" #include "cbs_h265.h" +#include "h265_profile_level.h" #include "hevc.h" +#include "hevc_sei.h" #include "internal.h" #include "put_bits.h" #include "vaapi_encode.h" +enum { + SEI_MASTERING_DISPLAY = 0x08, + SEI_CONTENT_LIGHT_LEVEL = 0x10, +}; -typedef struct VAAPIEncodeH265Context { - unsigned int ctu_width; - unsigned int ctu_height; - - int fixed_qp_idr; - int fixed_qp_p; - int fixed_qp_b; - - H265RawAUD aud; - H265RawVPS vps; - H265RawSPS sps; - H265RawPPS pps; - H265RawSlice slice; +typedef struct VAAPIEncodeH265Picture { + int pic_order_cnt; int64_t last_idr_frame; - int pic_order_cnt; int slice_nal_unit; int slice_type; int pic_type; +} VAAPIEncodeH265Picture; + +typedef struct VAAPIEncodeH265Context { + VAAPIEncodeContext common; + + // User options. + int qp; + int aud; + int profile; + int tier; + int level; + int sei; + + // Derived settings. + int fixed_qp_idr; + int fixed_qp_p; + int fixed_qp_b; + + // Writer structures. + H265RawAUD raw_aud; + H265RawVPS raw_vps; + H265RawSPS raw_sps; + H265RawPPS raw_pps; + H265RawSEI raw_sei; + H265RawSlice raw_slice; + + H265RawSEIMasteringDisplayColourVolume sei_mastering_display; + H265RawSEIContentLightLevelInfo sei_content_light_level; CodedBitstreamContext *cbc; CodedBitstreamFragment current_access_unit; int aud_needed; + int sei_needed; } VAAPIEncodeH265Context; -typedef struct VAAPIEncodeH265Options { - int qp; - int aud; - int profile; - int level; -} VAAPIEncodeH265Options; - static int vaapi_encode_h265_write_access_unit(AVCodecContext *avctx, char *data, size_t *data_len, CodedBitstreamFragment *au) { - VAAPIEncodeContext *ctx = avctx->priv_data; - VAAPIEncodeH265Context *priv = ctx->priv_data; + VAAPIEncodeH265Context *priv = avctx->priv_data; int err; err = ff_cbs_write_fragment_data(priv->cbc, au); @@ -99,8 +116,7 @@ static int vaapi_encode_h265_add_nal(AVCodecContext *avctx, CodedBitstreamFragment *au, void *nal_unit) { - VAAPIEncodeContext *ctx = avctx->priv_data; - VAAPIEncodeH265Context *priv = ctx->priv_data; + VAAPIEncodeH265Context *priv = avctx->priv_data; H265RawNALUnitHeader *header = nal_unit; int err; @@ -118,33 +134,32 @@ static int vaapi_encode_h265_add_nal(AVCodecContext *avctx, static int vaapi_encode_h265_write_sequence_header(AVCodecContext *avctx, char *data, size_t *data_len) { - VAAPIEncodeContext *ctx = avctx->priv_data; - VAAPIEncodeH265Context *priv = ctx->priv_data; + VAAPIEncodeH265Context *priv = avctx->priv_data; CodedBitstreamFragment *au = &priv->current_access_unit; int err; if (priv->aud_needed) { - err = vaapi_encode_h265_add_nal(avctx, au, &priv->aud); + err = vaapi_encode_h265_add_nal(avctx, au, &priv->raw_aud); if (err < 0) goto fail; priv->aud_needed = 0; } - err = vaapi_encode_h265_add_nal(avctx, au, &priv->vps); + err = vaapi_encode_h265_add_nal(avctx, au, &priv->raw_vps); if (err < 0) goto fail; - err = vaapi_encode_h265_add_nal(avctx, au, &priv->sps); + err = vaapi_encode_h265_add_nal(avctx, au, &priv->raw_sps); if (err < 0) goto fail; - err = vaapi_encode_h265_add_nal(avctx, au, &priv->pps); + err = vaapi_encode_h265_add_nal(avctx, au, &priv->raw_pps); if (err < 0) goto fail; err = vaapi_encode_h265_write_access_unit(avctx, data, data_len, au); fail: - ff_cbs_fragment_uninit(priv->cbc, au); + ff_cbs_fragment_reset(priv->cbc, au); return err; } @@ -153,48 +168,133 @@ static int vaapi_encode_h265_write_slice_header(AVCodecContext *avctx, VAAPIEncodeSlice *slice, char *data, size_t *data_len) { - VAAPIEncodeContext *ctx = avctx->priv_data; - VAAPIEncodeH265Context *priv = ctx->priv_data; + VAAPIEncodeH265Context *priv = avctx->priv_data; CodedBitstreamFragment *au = &priv->current_access_unit; int err; if (priv->aud_needed) { - err = vaapi_encode_h265_add_nal(avctx, au, &priv->aud); + err = vaapi_encode_h265_add_nal(avctx, au, &priv->raw_aud); if (err < 0) goto fail; priv->aud_needed = 0; } - err = vaapi_encode_h265_add_nal(avctx, au, &priv->slice); + err = vaapi_encode_h265_add_nal(avctx, au, &priv->raw_slice); if (err < 0) goto fail; err = vaapi_encode_h265_write_access_unit(avctx, data, data_len, au); fail: - ff_cbs_fragment_uninit(priv->cbc, au); + ff_cbs_fragment_reset(priv->cbc, au); + return err; +} + +static int vaapi_encode_h265_write_extra_header(AVCodecContext *avctx, + VAAPIEncodePicture *pic, + int index, int *type, + char *data, size_t *data_len) +{ + VAAPIEncodeH265Context *priv = avctx->priv_data; + CodedBitstreamFragment *au = &priv->current_access_unit; + int err, i; + + if (priv->sei_needed) { + H265RawSEI *sei = &priv->raw_sei; + + if (priv->aud_needed) { + err = vaapi_encode_h265_add_nal(avctx, au, &priv->aud); + if (err < 0) + goto fail; + priv->aud_needed = 0; + } + + *sei = (H265RawSEI) { + .nal_unit_header = { + .nal_unit_type = HEVC_NAL_SEI_PREFIX, + .nuh_layer_id = 0, + .nuh_temporal_id_plus1 = 1, + }, + }; + + i = 0; + + if (priv->sei_needed & SEI_MASTERING_DISPLAY) { + sei->payload[i].payload_type = HEVC_SEI_TYPE_MASTERING_DISPLAY_INFO; + sei->payload[i].payload.mastering_display = priv->sei_mastering_display; + ++i; + } + + if (priv->sei_needed & SEI_CONTENT_LIGHT_LEVEL) { + sei->payload[i].payload_type = HEVC_SEI_TYPE_CONTENT_LIGHT_LEVEL_INFO; + sei->payload[i].payload.content_light_level = priv->sei_content_light_level; + ++i; + } + + sei->payload_count = i; + av_assert0(sei->payload_count > 0); + + err = vaapi_encode_h265_add_nal(avctx, au, sei); + if (err < 0) + goto fail; + priv->sei_needed = 0; + + err = vaapi_encode_h265_write_access_unit(avctx, data, data_len, au); + if (err < 0) + goto fail; + + ff_cbs_fragment_reset(priv->cbc, au); + + *type = VAEncPackedHeaderRawData; + return 0; + } else { + return AVERROR_EOF; + } + +fail: + ff_cbs_fragment_reset(priv->cbc, au); return err; } static int vaapi_encode_h265_init_sequence_params(AVCodecContext *avctx) { VAAPIEncodeContext *ctx = avctx->priv_data; - VAAPIEncodeH265Context *priv = ctx->priv_data; - H265RawVPS *vps = &priv->vps; - H265RawSPS *sps = &priv->sps; - H265RawPPS *pps = &priv->pps; + VAAPIEncodeH265Context *priv = avctx->priv_data; + H265RawVPS *vps = &priv->raw_vps; + H265RawSPS *sps = &priv->raw_sps; + H265RawPPS *pps = &priv->raw_pps; + H265RawProfileTierLevel *ptl = &vps->profile_tier_level; H265RawVUI *vui = &sps->vui; VAEncSequenceParameterBufferHEVC *vseq = ctx->codec_sequence_params; VAEncPictureParameterBufferHEVC *vpic = ctx->codec_picture_params; + const AVPixFmtDescriptor *desc; + int chroma_format, bit_depth; int i; - memset(&priv->current_access_unit, 0, - sizeof(priv->current_access_unit)); - memset(vps, 0, sizeof(*vps)); memset(sps, 0, sizeof(*sps)); memset(pps, 0, sizeof(*pps)); + desc = av_pix_fmt_desc_get(priv->common.input_frames->sw_format); + av_assert0(desc); + if (desc->nb_components == 1) { + chroma_format = 0; + } else { + if (desc->log2_chroma_w == 1 && desc->log2_chroma_h == 1) { + chroma_format = 1; + } else if (desc->log2_chroma_w == 1 && desc->log2_chroma_h == 0) { + chroma_format = 2; + } else if (desc->log2_chroma_w == 0 && desc->log2_chroma_h == 0) { + chroma_format = 3; + } else { + av_log(avctx, AV_LOG_ERROR, "Chroma format of input pixel format " + "%s is not supported.\n", desc->name); + return AVERROR(EINVAL); + } + } + bit_depth = desc->comp[0].depth; + + // VPS vps->nal_unit_header = (H265RawNALUnitHeader) { @@ -211,23 +311,57 @@ static int vaapi_encode_h265_init_sequence_params(AVCodecContext *avctx) vps->vps_max_sub_layers_minus1 = 0; vps->vps_temporal_id_nesting_flag = 1; - vps->profile_tier_level = (H265RawProfileTierLevel) { - .general_profile_space = 0, - .general_profile_idc = avctx->profile, - .general_tier_flag = 0, + ptl->general_profile_space = 0; + ptl->general_profile_idc = avctx->profile; + ptl->general_tier_flag = priv->tier; - .general_progressive_source_flag = 1, - .general_interlaced_source_flag = 0, - .general_non_packed_constraint_flag = 1, - .general_frame_only_constraint_flag = 1, + if (chroma_format == 1) { + ptl->general_profile_compatibility_flag[1] = bit_depth == 8; + ptl->general_profile_compatibility_flag[2] = bit_depth <= 10; + } + ptl->general_profile_compatibility_flag[4] = 1; - .general_level_idc = avctx->level, - }; - vps->profile_tier_level.general_profile_compatibility_flag[avctx->profile & 31] = 1; + ptl->general_progressive_source_flag = 1; + ptl->general_interlaced_source_flag = 0; + ptl->general_non_packed_constraint_flag = 1; + ptl->general_frame_only_constraint_flag = 1; + + ptl->general_max_12bit_constraint_flag = bit_depth <= 12; + ptl->general_max_10bit_constraint_flag = bit_depth <= 10; + ptl->general_max_8bit_constraint_flag = bit_depth == 8; + + ptl->general_max_422chroma_constraint_flag = chroma_format <= 2; + ptl->general_max_420chroma_constraint_flag = chroma_format <= 1; + ptl->general_max_monochrome_constraint_flag = chroma_format == 0; + + ptl->general_intra_constraint_flag = ctx->gop_size == 1; + + ptl->general_lower_bit_rate_constraint_flag = 1; + + if (avctx->level != FF_LEVEL_UNKNOWN) { + ptl->general_level_idc = avctx->level; + } else { + const H265LevelDescriptor *level; + + level = ff_h265_guess_level(ptl, avctx->bit_rate, + ctx->surface_width, ctx->surface_height, + ctx->nb_slices, 1, 1, + (ctx->b_per_p > 0) + 1); + if (level) { + av_log(avctx, AV_LOG_VERBOSE, "Using level %s.\n", level->name); + ptl->general_level_idc = level->level_idc; + } else { + av_log(avctx, AV_LOG_VERBOSE, "Stream will not conform to " + "any normal level; using level 8.5.\n"); + ptl->general_level_idc = 255; + // The tier flag must be set in level 8.5. + ptl->general_tier_flag = 1; + } + } vps->vps_sub_layer_ordering_info_present_flag = 0; - vps->vps_max_dec_pic_buffering_minus1[0] = (ctx->b_per_p > 0) + 1; - vps->vps_max_num_reorder_pics[0] = (ctx->b_per_p > 0); + vps->vps_max_dec_pic_buffering_minus1[0] = ctx->max_b_depth + 1; + vps->vps_max_num_reorder_pics[0] = ctx->max_b_depth; vps->vps_max_latency_increase_plus1[0] = 0; vps->vps_max_layer_id = 0; @@ -265,7 +399,7 @@ static int vaapi_encode_h265_init_sequence_params(AVCodecContext *avctx) sps->sps_seq_parameter_set_id = 0; - sps->chroma_format_idc = 1; // YUV 4:2:0. + sps->chroma_format_idc = chroma_format; sps->separate_colour_plane_flag = 0; sps->pic_width_in_luma_samples = ctx->surface_width; @@ -284,9 +418,8 @@ static int vaapi_encode_h265_init_sequence_params(AVCodecContext *avctx) sps->conformance_window_flag = 0; } - sps->bit_depth_luma_minus8 = - avctx->profile == FF_PROFILE_HEVC_MAIN_10 ? 2 : 0; - sps->bit_depth_chroma_minus8 = sps->bit_depth_luma_minus8; + sps->bit_depth_luma_minus8 = bit_depth - 8; + sps->bit_depth_chroma_minus8 = bit_depth - 8; sps->log2_max_pic_order_cnt_lsb_minus4 = 8; @@ -338,18 +471,20 @@ static int vaapi_encode_h265_init_sequence_params(AVCodecContext *avctx) { 80, 33 }, { 18, 11 }, { 15, 11 }, { 64, 33 }, { 160, 99 }, { 4, 3 }, { 3, 2 }, { 2, 1 }, }; - int i; + int num, den, i; + av_reduce(&num, &den, avctx->sample_aspect_ratio.num, + avctx->sample_aspect_ratio.den, 65535); for (i = 0; i < FF_ARRAY_ELEMS(sar_idc); i++) { - if (avctx->sample_aspect_ratio.num == sar_idc[i].num && - avctx->sample_aspect_ratio.den == sar_idc[i].den) { + if (num == sar_idc[i].num && + den == sar_idc[i].den) { vui->aspect_ratio_idc = i; break; } } if (i >= FF_ARRAY_ELEMS(sar_idc)) { vui->aspect_ratio_idc = 255; - vui->sar_width = avctx->sample_aspect_ratio.num; - vui->sar_height = avctx->sample_aspect_ratio.den; + vui->sar_width = num; + vui->sar_height = den; } vui->aspect_ratio_info_present_flag = 1; } @@ -431,10 +566,10 @@ static int vaapi_encode_h265_init_sequence_params(AVCodecContext *avctx) .general_level_idc = vps->profile_tier_level.general_level_idc, .general_tier_flag = vps->profile_tier_level.general_tier_flag, - .intra_period = avctx->gop_size, - .intra_idr_period = avctx->gop_size, + .intra_period = ctx->gop_size, + .intra_idr_period = ctx->gop_size, .ip_period = ctx->b_per_p + 1, - .bits_per_second = avctx->bit_rate, + .bits_per_second = ctx->va_bit_rate, .pic_width_in_luma_samples = sps->pic_width_in_luma_samples, .pic_height_in_luma_samples = sps->pic_height_in_luma_samples, @@ -538,68 +673,156 @@ static int vaapi_encode_h265_init_picture_params(AVCodecContext *avctx, VAAPIEncodePicture *pic) { VAAPIEncodeContext *ctx = avctx->priv_data; - VAAPIEncodeH265Context *priv = ctx->priv_data; - VAAPIEncodeH265Options *opt = ctx->codec_options; + VAAPIEncodeH265Context *priv = avctx->priv_data; + VAAPIEncodeH265Picture *hpic = pic->priv_data; + VAAPIEncodePicture *prev = pic->prev; + VAAPIEncodeH265Picture *hprev = prev ? prev->priv_data : NULL; VAEncPictureParameterBufferHEVC *vpic = pic->codec_picture_params; int i; if (pic->type == PICTURE_TYPE_IDR) { av_assert0(pic->display_order == pic->encode_order); - priv->last_idr_frame = pic->display_order; + hpic->last_idr_frame = pic->display_order; - priv->slice_nal_unit = HEVC_NAL_IDR_W_RADL; - priv->slice_type = HEVC_SLICE_I; - priv->pic_type = 0; + hpic->slice_nal_unit = HEVC_NAL_IDR_W_RADL; + hpic->slice_type = HEVC_SLICE_I; + hpic->pic_type = 0; } else { - av_assert0(pic->encode_order > priv->last_idr_frame); + av_assert0(prev); + hpic->last_idr_frame = hprev->last_idr_frame; if (pic->type == PICTURE_TYPE_I) { - priv->slice_nal_unit = HEVC_NAL_CRA_NUT; - priv->slice_type = HEVC_SLICE_I; - priv->pic_type = 0; + hpic->slice_nal_unit = HEVC_NAL_CRA_NUT; + hpic->slice_type = HEVC_SLICE_I; + hpic->pic_type = 0; } else if (pic->type == PICTURE_TYPE_P) { av_assert0(pic->refs[0]); - priv->slice_nal_unit = HEVC_NAL_TRAIL_R; - priv->slice_type = HEVC_SLICE_P; - priv->pic_type = 1; + hpic->slice_nal_unit = HEVC_NAL_TRAIL_R; + hpic->slice_type = HEVC_SLICE_P; + hpic->pic_type = 1; } else { + VAAPIEncodePicture *irap_ref; av_assert0(pic->refs[0] && pic->refs[1]); - if (pic->refs[1]->type == PICTURE_TYPE_I) - priv->slice_nal_unit = HEVC_NAL_RASL_N; - else - priv->slice_nal_unit = HEVC_NAL_TRAIL_N; - priv->slice_type = HEVC_SLICE_B; - priv->pic_type = 2; + for (irap_ref = pic; irap_ref; irap_ref = irap_ref->refs[1]) { + if (irap_ref->type == PICTURE_TYPE_I) + break; + } + if (pic->b_depth == ctx->max_b_depth) { + hpic->slice_nal_unit = irap_ref ? HEVC_NAL_RASL_N + : HEVC_NAL_TRAIL_N; + } else { + hpic->slice_nal_unit = irap_ref ? HEVC_NAL_RASL_R + : HEVC_NAL_TRAIL_R; + } + hpic->slice_type = HEVC_SLICE_B; + hpic->pic_type = 2; } } - priv->pic_order_cnt = pic->display_order - priv->last_idr_frame; + hpic->pic_order_cnt = pic->display_order - hpic->last_idr_frame; - if (opt->aud) { + if (priv->aud) { priv->aud_needed = 1; - priv->aud.nal_unit_header = (H265RawNALUnitHeader) { - .nal_unit_type = HEVC_NAL_AUD, - .nuh_layer_id = 0, - .nuh_temporal_id_plus1 = 1, + priv->raw_aud = (H265RawAUD) { + .nal_unit_header = { + .nal_unit_type = HEVC_NAL_AUD, + .nuh_layer_id = 0, + .nuh_temporal_id_plus1 = 1, + }, + .pic_type = hpic->pic_type, }; - priv->aud.pic_type = priv->pic_type; } else { priv->aud_needed = 0; } + priv->sei_needed = 0; + + // Only look for the metadata on I/IDR frame on the output. We + // may force an IDR frame on the output where the medadata gets + // changed on the input frame. + if ((priv->sei & SEI_MASTERING_DISPLAY) && + (pic->type == PICTURE_TYPE_I || pic->type == PICTURE_TYPE_IDR)) { + AVFrameSideData *sd = + av_frame_get_side_data(pic->input_image, + AV_FRAME_DATA_MASTERING_DISPLAY_METADATA); + + if (sd) { + AVMasteringDisplayMetadata *mdm = + (AVMasteringDisplayMetadata *)sd->data; + + // SEI is needed when both the primaries and luminance are set + if (mdm->has_primaries && mdm->has_luminance) { + H265RawSEIMasteringDisplayColourVolume *mdcv = + &priv->sei_mastering_display; + const int mapping[3] = {1, 2, 0}; + const int chroma_den = 50000; + const int luma_den = 10000; + + for (i = 0; i < 3; i++) { + const int j = mapping[i]; + mdcv->display_primaries_x[i] = + FFMIN(lrint(chroma_den * + av_q2d(mdm->display_primaries[j][0])), + chroma_den); + mdcv->display_primaries_y[i] = + FFMIN(lrint(chroma_den * + av_q2d(mdm->display_primaries[j][1])), + chroma_den); + } + + mdcv->white_point_x = + FFMIN(lrint(chroma_den * av_q2d(mdm->white_point[0])), + chroma_den); + mdcv->white_point_y = + FFMIN(lrint(chroma_den * av_q2d(mdm->white_point[1])), + chroma_den); + + mdcv->max_display_mastering_luminance = + lrint(luma_den * av_q2d(mdm->max_luminance)); + mdcv->min_display_mastering_luminance = + FFMIN(lrint(luma_den * av_q2d(mdm->min_luminance)), + mdcv->max_display_mastering_luminance); + + priv->sei_needed |= SEI_MASTERING_DISPLAY; + } + } + } + + if ((priv->sei & SEI_CONTENT_LIGHT_LEVEL) && + (pic->type == PICTURE_TYPE_I || pic->type == PICTURE_TYPE_IDR)) { + AVFrameSideData *sd = + av_frame_get_side_data(pic->input_image, + AV_FRAME_DATA_CONTENT_LIGHT_LEVEL); + + if (sd) { + AVContentLightMetadata *clm = + (AVContentLightMetadata *)sd->data; + H265RawSEIContentLightLevelInfo *clli = + &priv->sei_content_light_level; + + clli->max_content_light_level = FFMIN(clm->MaxCLL, 65535); + clli->max_pic_average_light_level = FFMIN(clm->MaxFALL, 65535); + + priv->sei_needed |= SEI_CONTENT_LIGHT_LEVEL; + } + } + vpic->decoded_curr_pic = (VAPictureHEVC) { .picture_id = pic->recon_surface, - .pic_order_cnt = priv->pic_order_cnt, + .pic_order_cnt = hpic->pic_order_cnt, .flags = 0, }; for (i = 0; i < pic->nb_refs; i++) { - VAAPIEncodePicture *ref = pic->refs[i]; + VAAPIEncodePicture *ref = pic->refs[i]; + VAAPIEncodeH265Picture *href; + av_assert0(ref && ref->encode_order < pic->encode_order); + href = ref->priv_data; vpic->reference_frames[i] = (VAPictureHEVC) { .picture_id = ref->recon_surface, - .pic_order_cnt = ref->display_order - priv->last_idr_frame, + .pic_order_cnt = href->pic_order_cnt, .flags = (ref->display_order < pic->display_order ? VA_PICTURE_HEVC_RPS_ST_CURR_BEFORE : 0) | (ref->display_order > pic->display_order ? @@ -615,7 +838,7 @@ static int vaapi_encode_h265_init_picture_params(AVCodecContext *avctx, vpic->coded_buf = pic->output_buffer; - vpic->nal_unit_type = priv->slice_nal_unit; + vpic->nal_unit_type = hpic->slice_nal_unit; switch (pic->type) { case PICTURE_TYPE_IDR: @@ -642,8 +865,6 @@ static int vaapi_encode_h265_init_picture_params(AVCodecContext *avctx, av_assert0(0 && "invalid picture type"); } - pic->nb_slices = 1; - return 0; } @@ -651,87 +872,105 @@ static int vaapi_encode_h265_init_slice_params(AVCodecContext *avctx, VAAPIEncodePicture *pic, VAAPIEncodeSlice *slice) { - VAAPIEncodeContext *ctx = avctx->priv_data; - VAAPIEncodeH265Context *priv = ctx->priv_data; - const H265RawSPS *sps = &priv->sps; - const H265RawPPS *pps = &priv->pps; - H265RawSliceHeader *sh = &priv->slice.header; + VAAPIEncodeH265Context *priv = avctx->priv_data; + VAAPIEncodeH265Picture *hpic = pic->priv_data; + const H265RawSPS *sps = &priv->raw_sps; + const H265RawPPS *pps = &priv->raw_pps; + H265RawSliceHeader *sh = &priv->raw_slice.header; VAEncPictureParameterBufferHEVC *vpic = pic->codec_picture_params; VAEncSliceParameterBufferHEVC *vslice = slice->codec_slice_params; int i; sh->nal_unit_header = (H265RawNALUnitHeader) { - .nal_unit_type = priv->slice_nal_unit, + .nal_unit_type = hpic->slice_nal_unit, .nuh_layer_id = 0, .nuh_temporal_id_plus1 = 1, }; sh->slice_pic_parameter_set_id = pps->pps_pic_parameter_set_id; - // Currently we only support one slice per frame. - sh->first_slice_segment_in_pic_flag = 1; - sh->slice_segment_address = 0; + sh->first_slice_segment_in_pic_flag = slice->index == 0; + sh->slice_segment_address = slice->block_start; - sh->slice_type = priv->slice_type; + sh->slice_type = hpic->slice_type; - sh->slice_pic_order_cnt_lsb = priv->pic_order_cnt & + sh->slice_pic_order_cnt_lsb = hpic->pic_order_cnt & (1 << (sps->log2_max_pic_order_cnt_lsb_minus4 + 4)) - 1; if (pic->type != PICTURE_TYPE_IDR) { H265RawSTRefPicSet *rps; - VAAPIEncodePicture *st; - int used; + const VAAPIEncodeH265Picture *strp; + int rps_poc[MAX_DPB_SIZE]; + int rps_used[MAX_DPB_SIZE]; + int i, j, poc, rps_pics; sh->short_term_ref_pic_set_sps_flag = 0; rps = &sh->short_term_ref_pic_set; memset(rps, 0, sizeof(*rps)); - for (st = ctx->pic_start; st; st = st->next) { - if (st->encode_order >= pic->encode_order) { - // Not yet in DPB. + rps_pics = 0; + for (i = 0; i < pic->nb_refs; i++) { + strp = pic->refs[i]->priv_data; + rps_poc[rps_pics] = strp->pic_order_cnt; + rps_used[rps_pics] = 1; + ++rps_pics; + } + for (i = 0; i < pic->nb_dpb_pics; i++) { + if (pic->dpb[i] == pic) continue; + for (j = 0; j < pic->nb_refs; j++) { + if (pic->dpb[i] == pic->refs[j]) + break; } - used = 0; - for (i = 0; i < pic->nb_refs; i++) { - if (pic->refs[i] == st) - used = 1; - } - if (!used) { - // Usually each picture always uses all of the others in the - // DPB as references. The one case we have to treat here is - // a non-IDR IRAP picture, which may need to hold unused - // references across itself to be used for the decoding of - // following RASL pictures. This looks for such an RASL - // picture, and keeps the reference if there is one. - VAAPIEncodePicture *rp; - for (rp = ctx->pic_start; rp; rp = rp->next) { - if (rp->encode_order < pic->encode_order) - continue; - if (rp->type != PICTURE_TYPE_B) - continue; - if (rp->refs[0] == st && rp->refs[1] == pic) - break; - } - if (!rp) - continue; - } - // This only works for one instance of each (delta_poc_sN_minus1 - // is relative to the previous frame in the list, not relative to - // the current frame directly). - if (st->display_order < pic->display_order) { - rps->delta_poc_s0_minus1[rps->num_negative_pics] = - pic->display_order - st->display_order - 1; - rps->used_by_curr_pic_s0_flag[rps->num_negative_pics] = used; - ++rps->num_negative_pics; - } else { - rps->delta_poc_s1_minus1[rps->num_positive_pics] = - st->display_order - pic->display_order - 1; - rps->used_by_curr_pic_s1_flag[rps->num_positive_pics] = used; - ++rps->num_positive_pics; + if (j < pic->nb_refs) + continue; + strp = pic->dpb[i]->priv_data; + rps_poc[rps_pics] = strp->pic_order_cnt; + rps_used[rps_pics] = 0; + ++rps_pics; + } + + for (i = 1; i < rps_pics; i++) { + for (j = i; j > 0; j--) { + if (rps_poc[j] > rps_poc[j - 1]) + break; + av_assert0(rps_poc[j] != rps_poc[j - 1]); + FFSWAP(int, rps_poc[j], rps_poc[j - 1]); + FFSWAP(int, rps_used[j], rps_used[j - 1]); } } + av_log(avctx, AV_LOG_DEBUG, "RPS for POC %d:", + hpic->pic_order_cnt); + for (i = 0; i < rps_pics; i++) { + av_log(avctx, AV_LOG_DEBUG, " (%d,%d)", + rps_poc[i], rps_used[i]); + } + av_log(avctx, AV_LOG_DEBUG, "\n"); + + for (i = 0; i < rps_pics; i++) { + av_assert0(rps_poc[i] != hpic->pic_order_cnt); + if (rps_poc[i] > hpic->pic_order_cnt) + break; + } + + rps->num_negative_pics = i; + poc = hpic->pic_order_cnt; + for (j = i - 1; j >= 0; j--) { + rps->delta_poc_s0_minus1[i - 1 - j] = poc - rps_poc[j] - 1; + rps->used_by_curr_pic_s0_flag[i - 1 - j] = rps_used[j]; + poc = rps_poc[j]; + } + + rps->num_positive_pics = rps_pics - i; + poc = hpic->pic_order_cnt; + for (j = i; j < rps_pics; j++) { + rps->delta_poc_s1_minus1[j - i] = rps_poc[j] - poc - 1; + rps->used_by_curr_pic_s1_flag[j - i] = rps_used[j]; + poc = rps_poc[j]; + } + sh->num_long_term_sps = 0; sh->num_long_term_pics = 0; @@ -760,7 +999,7 @@ static int vaapi_encode_h265_init_slice_params(AVCodecContext *avctx, *vslice = (VAEncSliceParameterBufferHEVC) { .slice_segment_address = sh->slice_segment_address, - .num_ctu_in_slice = priv->ctu_width * priv->ctu_height, + .num_ctu_in_slice = slice->block_size, .slice_type = sh->slice_type, .slice_pic_parameter_set_id = sh->slice_pic_parameter_set_id, @@ -781,7 +1020,7 @@ static int vaapi_encode_h265_init_slice_params(AVCodecContext *avctx, .slice_tc_offset_div2 = sh->slice_tc_offset_div2, .slice_fields.bits = { - .last_slice_of_pic_flag = 1, + .last_slice_of_pic_flag = slice->index == pic->nb_slices - 1, .dependent_slice_segment_flag = sh->dependent_slice_segment_flag, .colour_plane_id = sh->colour_plane_id, .slice_temporal_mvp_enabled_flag = @@ -826,31 +1065,29 @@ static int vaapi_encode_h265_init_slice_params(AVCodecContext *avctx, static av_cold int vaapi_encode_h265_configure(AVCodecContext *avctx) { VAAPIEncodeContext *ctx = avctx->priv_data; - VAAPIEncodeH265Context *priv = ctx->priv_data; - VAAPIEncodeH265Options *opt = ctx->codec_options; + VAAPIEncodeH265Context *priv = avctx->priv_data; int err; err = ff_cbs_init(&priv->cbc, AV_CODEC_ID_HEVC, avctx); if (err < 0) return err; - priv->ctu_width = FFALIGN(ctx->surface_width, 32) / 32; - priv->ctu_height = FFALIGN(ctx->surface_height, 32) / 32; - - av_log(avctx, AV_LOG_VERBOSE, "Input %ux%u -> Surface %ux%u -> CTU %ux%u.\n", - avctx->width, avctx->height, ctx->surface_width, - ctx->surface_height, priv->ctu_width, priv->ctu_height); - if (ctx->va_rc_mode == VA_RC_CQP) { - priv->fixed_qp_p = opt->qp; + // Note that VAAPI only supports positive QP values - the range is + // therefore always bounded below by 1, even in 10-bit mode where + // it should go down to -12. + + priv->fixed_qp_p = av_clip(ctx->rc_quality, 1, 51); if (avctx->i_quant_factor > 0.0) - priv->fixed_qp_idr = (int)((priv->fixed_qp_p * avctx->i_quant_factor + - avctx->i_quant_offset) + 0.5); + priv->fixed_qp_idr = + av_clip((avctx->i_quant_factor * priv->fixed_qp_p + + avctx->i_quant_offset) + 0.5, 1, 51); else priv->fixed_qp_idr = priv->fixed_qp_p; if (avctx->b_quant_factor > 0.0) - priv->fixed_qp_b = (int)((priv->fixed_qp_p * avctx->b_quant_factor + - avctx->b_quant_offset) + 0.5); + priv->fixed_qp_b = + av_clip((avctx->b_quant_factor * priv->fixed_qp_p + + avctx->b_quant_offset) + 0.5, 1, 51); else priv->fixed_qp_b = priv->fixed_qp_p; @@ -858,29 +1095,40 @@ static av_cold int vaapi_encode_h265_configure(AVCodecContext *avctx) "%d / %d / %d for IDR- / P- / B-frames.\n", priv->fixed_qp_idr, priv->fixed_qp_p, priv->fixed_qp_b); - } else if (ctx->va_rc_mode == VA_RC_CBR || - ctx->va_rc_mode == VA_RC_VBR) { - // These still need to be set for pic_init_qp/slice_qp_delta. + } else { + // These still need to be set for init_qp/slice_qp_delta. priv->fixed_qp_idr = 30; priv->fixed_qp_p = 30; priv->fixed_qp_b = 30; - - av_log(avctx, AV_LOG_DEBUG, "Using %s-bitrate = %"PRId64" bps.\n", - ctx->va_rc_mode == VA_RC_CBR ? "constant" : "variable", - avctx->bit_rate); - - } else { - av_assert0(0 && "Invalid RC mode."); } return 0; } +static const VAAPIEncodeProfile vaapi_encode_h265_profiles[] = { + { FF_PROFILE_HEVC_MAIN, 8, 3, 1, 1, VAProfileHEVCMain }, + { FF_PROFILE_HEVC_REXT, 8, 3, 1, 1, VAProfileHEVCMain }, +#if VA_CHECK_VERSION(0, 37, 0) + { FF_PROFILE_HEVC_MAIN_10, 10, 3, 1, 1, VAProfileHEVCMain10 }, + { FF_PROFILE_HEVC_REXT, 10, 3, 1, 1, VAProfileHEVCMain10 }, +#endif + { FF_PROFILE_UNKNOWN } +}; + static const VAAPIEncodeType vaapi_encode_type_h265 = { - .priv_data_size = sizeof(VAAPIEncodeH265Context), + .profiles = vaapi_encode_h265_profiles, + + .flags = FLAG_SLICE_CONTROL | + FLAG_B_PICTURES | + FLAG_B_PICTURE_REFERENCES | + FLAG_NON_IDR_KEY_PICTURES, + + .default_quality = 25, .configure = &vaapi_encode_h265_configure, + .picture_priv_data_size = sizeof(VAAPIEncodeH265Picture), + .sequence_params_size = sizeof(VAEncSequenceParameterBufferHEVC), .init_sequence_params = &vaapi_encode_h265_init_sequence_params, @@ -895,96 +1143,89 @@ static const VAAPIEncodeType vaapi_encode_type_h265 = { .slice_header_type = VAEncPackedHeaderHEVC_Slice, .write_slice_header = &vaapi_encode_h265_write_slice_header, + + .write_extra_header = &vaapi_encode_h265_write_extra_header, }; static av_cold int vaapi_encode_h265_init(AVCodecContext *avctx) { - VAAPIEncodeContext *ctx = avctx->priv_data; - VAAPIEncodeH265Options *opt = - (VAAPIEncodeH265Options*)ctx->codec_options_data; + VAAPIEncodeContext *ctx = avctx->priv_data; + VAAPIEncodeH265Context *priv = avctx->priv_data; ctx->codec = &vaapi_encode_type_h265; if (avctx->profile == FF_PROFILE_UNKNOWN) - avctx->profile = opt->profile; + avctx->profile = priv->profile; if (avctx->level == FF_LEVEL_UNKNOWN) - avctx->level = opt->level; + avctx->level = priv->level; - switch (avctx->profile) { - case FF_PROFILE_HEVC_MAIN: - case FF_PROFILE_UNKNOWN: - ctx->va_profile = VAProfileHEVCMain; - ctx->va_rt_format = VA_RT_FORMAT_YUV420; - break; - case FF_PROFILE_HEVC_MAIN_10: -#ifdef VA_RT_FORMAT_YUV420_10BPP - ctx->va_profile = VAProfileHEVCMain10; - ctx->va_rt_format = VA_RT_FORMAT_YUV420_10BPP; - break; -#else - av_log(avctx, AV_LOG_ERROR, "10-bit encoding is not " - "supported with this VAAPI version.\n"); - return AVERROR(ENOSYS); -#endif - default: - av_log(avctx, AV_LOG_ERROR, "Unknown H.265 profile %d.\n", - avctx->profile); + if (avctx->level != FF_LEVEL_UNKNOWN && avctx->level & ~0xff) { + av_log(avctx, AV_LOG_ERROR, "Invalid level %d: must fit " + "in 8-bit unsigned integer.\n", avctx->level); return AVERROR(EINVAL); } - ctx->va_entrypoint = VAEntrypointEncSlice; - if (avctx->bit_rate > 0) { - if (avctx->rc_max_rate == avctx->bit_rate) - ctx->va_rc_mode = VA_RC_CBR; - else - ctx->va_rc_mode = VA_RC_VBR; - } else - ctx->va_rc_mode = VA_RC_CQP; - - ctx->va_packed_headers = + ctx->desired_packed_headers = VA_ENC_PACKED_HEADER_SEQUENCE | // VPS, SPS and PPS. - VA_ENC_PACKED_HEADER_SLICE; // Slice headers. + VA_ENC_PACKED_HEADER_SLICE | // Slice headers. + VA_ENC_PACKED_HEADER_MISC; // SEI ctx->surface_width = FFALIGN(avctx->width, 16); ctx->surface_height = FFALIGN(avctx->height, 16); + // CTU size is currently hard-coded to 32. + ctx->slice_block_width = ctx->slice_block_height = 32; + + if (priv->qp > 0) + ctx->explicit_qp = priv->qp; + return ff_vaapi_encode_init(avctx); } static av_cold int vaapi_encode_h265_close(AVCodecContext *avctx) { - VAAPIEncodeContext *ctx = avctx->priv_data; - VAAPIEncodeH265Context *priv = ctx->priv_data; + VAAPIEncodeH265Context *priv = avctx->priv_data; - if (priv) - ff_cbs_close(&priv->cbc); + ff_cbs_fragment_free(priv->cbc, &priv->current_access_unit); + ff_cbs_close(&priv->cbc); return ff_vaapi_encode_close(avctx); } -#define OFFSET(x) (offsetof(VAAPIEncodeContext, codec_options_data) + \ - offsetof(VAAPIEncodeH265Options, x)) +#define OFFSET(x) offsetof(VAAPIEncodeH265Context, x) #define FLAGS (AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM) static const AVOption vaapi_encode_h265_options[] = { + VAAPI_ENCODE_COMMON_OPTIONS, + VAAPI_ENCODE_RC_OPTIONS, + { "qp", "Constant QP (for P-frames; scaled by qfactor/qoffset for I/B)", - OFFSET(qp), AV_OPT_TYPE_INT, { .i64 = 25 }, 0, 52, FLAGS }, + OFFSET(qp), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 52, FLAGS }, { "aud", "Include AUD", - OFFSET(aud), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, FLAGS }, + OFFSET(aud), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, FLAGS }, { "profile", "Set profile (general_profile_idc)", OFFSET(profile), AV_OPT_TYPE_INT, - { .i64 = FF_PROFILE_HEVC_MAIN }, 0x00, 0xff, FLAGS, "profile" }, + { .i64 = FF_PROFILE_UNKNOWN }, FF_PROFILE_UNKNOWN, 0xff, FLAGS, "profile" }, #define PROFILE(name, value) name, NULL, 0, AV_OPT_TYPE_CONST, \ { .i64 = value }, 0, 0, FLAGS, "profile" { PROFILE("main", FF_PROFILE_HEVC_MAIN) }, { PROFILE("main10", FF_PROFILE_HEVC_MAIN_10) }, + { PROFILE("rext", FF_PROFILE_HEVC_REXT) }, #undef PROFILE + { "tier", "Set tier (general_tier_flag)", + OFFSET(tier), AV_OPT_TYPE_INT, + { .i64 = 0 }, 0, 1, FLAGS, "tier" }, + { "main", NULL, 0, AV_OPT_TYPE_CONST, + { .i64 = 0 }, 0, 0, FLAGS, "tier" }, + { "high", NULL, 0, AV_OPT_TYPE_CONST, + { .i64 = 1 }, 0, 0, FLAGS, "tier" }, + { "level", "Set level (general_level_idc)", OFFSET(level), AV_OPT_TYPE_INT, - { .i64 = 153 }, 0x00, 0xff, FLAGS, "level" }, + { .i64 = FF_LEVEL_UNKNOWN }, FF_LEVEL_UNKNOWN, 0xff, FLAGS, "level" }, #define LEVEL(name, value) name, NULL, 0, AV_OPT_TYPE_CONST, \ { .i64 = value }, 0, 0, FLAGS, "level" @@ -1003,6 +1244,17 @@ static const AVOption vaapi_encode_h265_options[] = { { LEVEL("6.2", 186) }, #undef LEVEL + { "sei", "Set SEI to include", + OFFSET(sei), AV_OPT_TYPE_FLAGS, + { .i64 = SEI_MASTERING_DISPLAY | SEI_CONTENT_LIGHT_LEVEL }, + 0, INT_MAX, FLAGS, "sei" }, + { "hdr", + "Include HDR metadata for mastering display colour volume " + "and content light level information", + 0, AV_OPT_TYPE_CONST, + { .i64 = SEI_MASTERING_DISPLAY | SEI_CONTENT_LIGHT_LEVEL }, + INT_MIN, INT_MAX, FLAGS, "sei" }, + { NULL }, }; @@ -1014,6 +1266,8 @@ static const AVCodecDefault vaapi_encode_h265_defaults[] = { { "i_qoffset", "0" }, { "b_qfactor", "6/5" }, { "b_qoffset", "0" }, + { "qmin", "-1" }, + { "qmax", "-1" }, { NULL }, }; @@ -1029,10 +1283,10 @@ AVCodec ff_hevc_vaapi_encoder = { .long_name = NULL_IF_CONFIG_SMALL("H.265/HEVC (VAAPI)"), .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_HEVC, - .priv_data_size = (sizeof(VAAPIEncodeContext) + - sizeof(VAAPIEncodeH265Options)), + .priv_data_size = sizeof(VAAPIEncodeH265Context), .init = &vaapi_encode_h265_init, - .encode2 = &ff_vaapi_encode2, + .send_frame = &ff_vaapi_encode_send_frame, + .receive_packet = &ff_vaapi_encode_receive_packet, .close = &vaapi_encode_h265_close, .priv_class = &vaapi_encode_h265_class, .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HARDWARE, diff --git a/libavcodec/vaapi_encode_mjpeg.c b/libavcodec/vaapi_encode_mjpeg.c index c949e8964..bd029cc90 100644 --- a/libavcodec/vaapi_encode_mjpeg.c +++ b/libavcodec/vaapi_encode_mjpeg.c @@ -23,9 +23,12 @@ #include "libavutil/common.h" #include "libavutil/internal.h" #include "libavutil/opt.h" -#include "libavutil/pixfmt.h" +#include "libavutil/pixdesc.h" #include "avcodec.h" +#include "bytestream.h" +#include "cbs.h" +#include "cbs_jpeg.h" #include "internal.h" #include "jpegtables.h" #include "mjpeg.h" @@ -56,185 +59,91 @@ static const unsigned char vaapi_encode_mjpeg_quant_chrominance[64] = { }; typedef struct VAAPIEncodeMJPEGContext { + VAAPIEncodeContext common; + + // User options. + int jfif; + int huffman; + + // Derived settings. int quality; - int component_subsample_h[3]; - int component_subsample_v[3]; + uint8_t jfif_data[14]; - VAQMatrixBufferJPEG quant_tables; - VAHuffmanTableBufferJPEGBaseline huffman_tables; + // Writer structures. + JPEGRawFrameHeader frame_header; + JPEGRawScan scan; + JPEGRawApplicationData jfif_header; + JPEGRawQuantisationTableSpecification quant_tables; + JPEGRawHuffmanTableSpecification huffman_tables; + + CodedBitstreamContext *cbc; + CodedBitstreamFragment current_fragment; } VAAPIEncodeMJPEGContext; -static av_cold void vaapi_encode_mjpeg_copy_huffman(unsigned char *dst_lengths, - unsigned char *dst_values, - const unsigned char *src_lengths, - const unsigned char *src_values) -{ - int i, mt; - - ++src_lengths; - - mt = 0; - for (i = 0; i < 16; i++) - mt += (dst_lengths[i] = src_lengths[i]); - - for (i = 0; i < mt; i++) - dst_values[i] = src_values[i]; -} - -static av_cold void vaapi_encode_mjpeg_init_tables(AVCodecContext *avctx) -{ - VAAPIEncodeContext *ctx = avctx->priv_data; - VAAPIEncodeMJPEGContext *priv = ctx->priv_data; - VAQMatrixBufferJPEG *quant = &priv->quant_tables; - VAHuffmanTableBufferJPEGBaseline *huff = &priv->huffman_tables; - int i; - - quant->load_lum_quantiser_matrix = 1; - quant->load_chroma_quantiser_matrix = 1; - - for (i = 0; i < 64; i++) { - quant->lum_quantiser_matrix[i] = - vaapi_encode_mjpeg_quant_luminance[i]; - quant->chroma_quantiser_matrix[i] = - vaapi_encode_mjpeg_quant_chrominance[i]; - } - - huff->load_huffman_table[0] = 1; - vaapi_encode_mjpeg_copy_huffman(huff->huffman_table[0].num_dc_codes, - huff->huffman_table[0].dc_values, - avpriv_mjpeg_bits_dc_luminance, - avpriv_mjpeg_val_dc); - vaapi_encode_mjpeg_copy_huffman(huff->huffman_table[0].num_ac_codes, - huff->huffman_table[0].ac_values, - avpriv_mjpeg_bits_ac_luminance, - avpriv_mjpeg_val_ac_luminance); - memset(huff->huffman_table[0].pad, 0, sizeof(huff->huffman_table[0].pad)); - - huff->load_huffman_table[1] = 1; - vaapi_encode_mjpeg_copy_huffman(huff->huffman_table[1].num_dc_codes, - huff->huffman_table[1].dc_values, - avpriv_mjpeg_bits_dc_chrominance, - avpriv_mjpeg_val_dc); - vaapi_encode_mjpeg_copy_huffman(huff->huffman_table[1].num_ac_codes, - huff->huffman_table[1].ac_values, - avpriv_mjpeg_bits_ac_chrominance, - avpriv_mjpeg_val_ac_chrominance); - memset(huff->huffman_table[1].pad, 0, sizeof(huff->huffman_table[1].pad)); -} - -static void vaapi_encode_mjpeg_write_marker(PutBitContext *pbc, int marker) -{ - put_bits(pbc, 8, 0xff); - put_bits(pbc, 8, marker); -} - static int vaapi_encode_mjpeg_write_image_header(AVCodecContext *avctx, VAAPIEncodePicture *pic, VAAPIEncodeSlice *slice, char *data, size_t *data_len) { - VAAPIEncodeContext *ctx = avctx->priv_data; - VAEncPictureParameterBufferJPEG *vpic = pic->codec_picture_params; - VAEncSliceParameterBufferJPEG *vslice = slice->codec_slice_params; - VAAPIEncodeMJPEGContext *priv = ctx->priv_data; - PutBitContext pbc; - int t, i, quant_scale; + VAAPIEncodeMJPEGContext *priv = avctx->priv_data; + CodedBitstreamFragment *frag = &priv->current_fragment; + int err; - init_put_bits(&pbc, data, *data_len); - - vaapi_encode_mjpeg_write_marker(&pbc, SOI); - - // Quantisation table coefficients are scaled for quality by the driver, - // so we also need to do it ourselves here so that headers match. - if (priv->quality < 50) - quant_scale = 5000 / priv->quality; - else - quant_scale = 200 - 2 * priv->quality; - - for (t = 0; t < 2; t++) { - int q; - - vaapi_encode_mjpeg_write_marker(&pbc, DQT); - - put_bits(&pbc, 16, 3 + 64); // Lq - put_bits(&pbc, 4, 0); // Pq - put_bits(&pbc, 4, t); // Tq - - for (i = 0; i < 64; i++) { - q = i[t ? priv->quant_tables.chroma_quantiser_matrix - : priv->quant_tables.lum_quantiser_matrix]; - q = (q * quant_scale) / 100; - if (q < 1) q = 1; - if (q > 255) q = 255; - put_bits(&pbc, 8, q); - } + if (priv->jfif) { + err = ff_cbs_insert_unit_content(priv->cbc, frag, -1, + JPEG_MARKER_APPN + 0, + &priv->jfif_header, NULL); + if (err < 0) + goto fail; } - vaapi_encode_mjpeg_write_marker(&pbc, SOF0); + err = ff_cbs_insert_unit_content(priv->cbc, frag, -1, + JPEG_MARKER_DQT, + &priv->quant_tables, NULL); + if (err < 0) + goto fail; - put_bits(&pbc, 16, 8 + 3 * vpic->num_components); // Lf - put_bits(&pbc, 8, vpic->sample_bit_depth); // P - put_bits(&pbc, 16, vpic->picture_height); // Y - put_bits(&pbc, 16, vpic->picture_width); // X - put_bits(&pbc, 8, vpic->num_components); // Nf + err = ff_cbs_insert_unit_content(priv->cbc, frag, -1, + JPEG_MARKER_SOF0, + &priv->frame_header, NULL); + if (err < 0) + goto fail; - for (i = 0; i < vpic->num_components; i++) { - put_bits(&pbc, 8, vpic->component_id[i]); // Ci - put_bits(&pbc, 4, priv->component_subsample_h[i]); // Hi - put_bits(&pbc, 4, priv->component_subsample_v[i]); // Vi - put_bits(&pbc, 8, vpic->quantiser_table_selector[i]); // Tqi + if (priv->huffman) { + err = ff_cbs_insert_unit_content(priv->cbc, frag, -1, + JPEG_MARKER_DHT, + &priv->huffman_tables, NULL); + if (err < 0) + goto fail; } - for (t = 0; t < 4; t++) { - int mt; - unsigned char *lengths, *values; + err = ff_cbs_insert_unit_content(priv->cbc, frag, -1, + JPEG_MARKER_SOS, + &priv->scan, NULL); + if (err < 0) + goto fail; - vaapi_encode_mjpeg_write_marker(&pbc, DHT); - - if ((t & 1) == 0) { - lengths = priv->huffman_tables.huffman_table[t / 2].num_dc_codes; - values = priv->huffman_tables.huffman_table[t / 2].dc_values; - } else { - lengths = priv->huffman_tables.huffman_table[t / 2].num_ac_codes; - values = priv->huffman_tables.huffman_table[t / 2].ac_values; - } - - mt = 0; - for (i = 0; i < 16; i++) - mt += lengths[i]; - - put_bits(&pbc, 16, 2 + 17 + mt); // Lh - put_bits(&pbc, 4, t & 1); // Tc - put_bits(&pbc, 4, t / 2); // Th - - for (i = 0; i < 16; i++) - put_bits(&pbc, 8, lengths[i]); - for (i = 0; i < mt; i++) - put_bits(&pbc, 8, values[i]); + err = ff_cbs_write_fragment_data(priv->cbc, frag); + if (err < 0) { + av_log(avctx, AV_LOG_ERROR, "Failed to write image header.\n"); + goto fail; } - vaapi_encode_mjpeg_write_marker(&pbc, SOS); - - av_assert0(vpic->num_components == vslice->num_components); - - put_bits(&pbc, 16, 6 + 2 * vslice->num_components); // Ls - put_bits(&pbc, 8, vslice->num_components); // Ns - - for (i = 0; i < vslice->num_components; i++) { - put_bits(&pbc, 8, vslice->components[i].component_selector); // Csj - put_bits(&pbc, 4, vslice->components[i].dc_table_selector); // Tdj - put_bits(&pbc, 4, vslice->components[i].ac_table_selector); // Taj + if (*data_len < 8 * frag->data_size) { + av_log(avctx, AV_LOG_ERROR, "Image header too large: " + "%zu < %zu.\n", *data_len, 8 * frag->data_size); + err = AVERROR(ENOSPC); + goto fail; } - put_bits(&pbc, 8, 0); // Ss - put_bits(&pbc, 8, 63); // Se - put_bits(&pbc, 4, 0); // Ah - put_bits(&pbc, 4, 0); // Al + // Remove the EOI at the end of the fragment. + memcpy(data, frag->data, frag->data_size - 2); + *data_len = 8 * (frag->data_size - 2); - *data_len = put_bits_count(&pbc); - flush_put_bits(&pbc); - - return 0; + err = 0; +fail: + ff_cbs_fragment_reset(priv->cbc, frag); + return err; } static int vaapi_encode_mjpeg_write_extra_buffer(AVCodecContext *avctx, @@ -242,24 +151,67 @@ static int vaapi_encode_mjpeg_write_extra_buffer(AVCodecContext *avctx, int index, int *type, char *data, size_t *data_len) { - VAAPIEncodeContext *ctx = avctx->priv_data; - VAAPIEncodeMJPEGContext *priv = ctx->priv_data; + VAAPIEncodeMJPEGContext *priv = avctx->priv_data; + int t, i, k; if (index == 0) { // Write quantisation tables. - if (*data_len < sizeof(priv->quant_tables)) - return AVERROR(EINVAL); - *type = VAQMatrixBufferType; - memcpy(data, &priv->quant_tables, - *data_len = sizeof(priv->quant_tables)); + JPEGRawFrameHeader *fh = &priv->frame_header; + JPEGRawQuantisationTableSpecification *dqt = &priv->quant_tables; + VAQMatrixBufferJPEG *quant; + + if (*data_len < sizeof(*quant)) + return AVERROR(ENOSPC); + *type = VAQMatrixBufferType; + *data_len = sizeof(*quant); + + quant = (VAQMatrixBufferJPEG*)data; + memset(quant, 0, sizeof(*quant)); + + quant->load_lum_quantiser_matrix = 1; + for (i = 0; i < 64; i++) + quant->lum_quantiser_matrix[i] = dqt->table[fh->Tq[0]].Q[i]; + + if (fh->Nf > 1) { + quant->load_chroma_quantiser_matrix = 1; + for (i = 0; i < 64; i++) + quant->chroma_quantiser_matrix[i] = + dqt->table[fh->Tq[1]].Q[i]; + } } else if (index == 1) { // Write huffman tables. - if (*data_len < sizeof(priv->huffman_tables)) - return AVERROR(EINVAL); - *type = VAHuffmanTableBufferType; - memcpy(data, &priv->huffman_tables, - *data_len = sizeof(priv->huffman_tables)); + JPEGRawScanHeader *sh = &priv->scan.header; + JPEGRawHuffmanTableSpecification *dht = &priv->huffman_tables; + VAHuffmanTableBufferJPEGBaseline *huff; + + if (*data_len < sizeof(*huff)) + return AVERROR(ENOSPC); + *type = VAHuffmanTableBufferType; + *data_len = sizeof(*huff); + + huff = (VAHuffmanTableBufferJPEGBaseline*)data; + memset(huff, 0, sizeof(*huff)); + + for (t = 0; t < 1 + (sh->Ns > 1); t++) { + const JPEGRawHuffmanTable *ht; + + huff->load_huffman_table[t] = 1; + + ht = &dht->table[2 * t]; + for (i = k = 0; i < 16; i++) + k += (huff->huffman_table[t].num_dc_codes[i] = ht->L[i]); + av_assert0(k <= sizeof(huff->huffman_table[t].dc_values)); + for (i = 0; i < k; i++) + huff->huffman_table[t].dc_values[i] = ht->V[i]; + + ht = &dht->table[2 * t + 1]; + for (i = k = 0; i < 16; i++) + k += (huff->huffman_table[t].num_ac_codes[i] = ht->L[i]); + av_assert0(k <= sizeof(huff->huffman_table[t].ac_values)); + for (i = 0; i < k; i++) + huff->huffman_table[t].ac_values[i] = ht->V[i]; + } } else { return AVERROR_EOF; @@ -270,43 +222,189 @@ static int vaapi_encode_mjpeg_write_extra_buffer(AVCodecContext *avctx, static int vaapi_encode_mjpeg_init_picture_params(AVCodecContext *avctx, VAAPIEncodePicture *pic) { - VAAPIEncodeContext *ctx = avctx->priv_data; + VAAPIEncodeMJPEGContext *priv = avctx->priv_data; + JPEGRawFrameHeader *fh = &priv->frame_header; + JPEGRawScanHeader *sh = &priv->scan.header; VAEncPictureParameterBufferJPEG *vpic = pic->codec_picture_params; - VAAPIEncodeMJPEGContext *priv = ctx->priv_data; + const AVPixFmtDescriptor *desc; + const uint8_t components_rgb[3] = { 'R', 'G', 'B' }; + const uint8_t components_yuv[3] = { 1, 2, 3 }; + const uint8_t *components; + int t, i, quant_scale, len; - vpic->reconstructed_picture = pic->recon_surface; - vpic->coded_buf = pic->output_buffer; + av_assert0(pic->type == PICTURE_TYPE_IDR); - vpic->picture_width = avctx->width; - vpic->picture_height = avctx->height; + desc = av_pix_fmt_desc_get(priv->common.input_frames->sw_format); + av_assert0(desc); + if (desc->flags & AV_PIX_FMT_FLAG_RGB) + components = components_rgb; + else + components = components_yuv; - vpic->pic_flags.bits.profile = 0; - vpic->pic_flags.bits.progressive = 0; - vpic->pic_flags.bits.huffman = 1; - vpic->pic_flags.bits.interleaved = 0; - vpic->pic_flags.bits.differential = 0; + // Frame header. - vpic->sample_bit_depth = 8; - vpic->num_scan = 1; + fh->P = 8; + fh->Y = avctx->height; + fh->X = avctx->width; + fh->Nf = desc->nb_components; - vpic->num_components = 3; + for (i = 0; i < fh->Nf; i++) { + fh->C[i] = components[i]; + fh->H[i] = 1 + (i == 0 ? desc->log2_chroma_w : 0); + fh->V[i] = 1 + (i == 0 ? desc->log2_chroma_h : 0); - vpic->component_id[0] = 1; - vpic->component_id[1] = 2; - vpic->component_id[2] = 3; + fh->Tq[i] = !!i; + } - priv->component_subsample_h[0] = 2; - priv->component_subsample_v[0] = 2; - priv->component_subsample_h[1] = 1; - priv->component_subsample_v[1] = 1; - priv->component_subsample_h[2] = 1; - priv->component_subsample_v[2] = 1; + fh->Lf = 8 + 3 * fh->Nf; - vpic->quantiser_table_selector[0] = 0; - vpic->quantiser_table_selector[1] = 1; - vpic->quantiser_table_selector[2] = 1; + // JFIF header. + if (priv->jfif) { + JPEGRawApplicationData *app = &priv->jfif_header; + AVRational sar = pic->input_image->sample_aspect_ratio; + int sar_w, sar_h; + PutByteContext pbc; - vpic->quality = priv->quality; + bytestream2_init_writer(&pbc, priv->jfif_data, + sizeof(priv->jfif_data)); + + bytestream2_put_buffer(&pbc, "JFIF", 5); + bytestream2_put_be16(&pbc, 0x0102); + bytestream2_put_byte(&pbc, 0); + + av_reduce(&sar_w, &sar_h, sar.num, sar.den, 65535); + if (sar_w && sar_h) { + bytestream2_put_be16(&pbc, sar_w); + bytestream2_put_be16(&pbc, sar_h); + } else { + bytestream2_put_be16(&pbc, 1); + bytestream2_put_be16(&pbc, 1); + } + + bytestream2_put_byte(&pbc, 0); + bytestream2_put_byte(&pbc, 0); + + av_assert0(bytestream2_get_bytes_left_p(&pbc) == 0); + + app->Lp = 2 + sizeof(priv->jfif_data); + app->Ap = priv->jfif_data; + app->Ap_ref = NULL; + } + + // Quantisation tables. + + if (priv->quality < 50) + quant_scale = 5000 / priv->quality; + else + quant_scale = 200 - 2 * priv->quality; + + len = 2; + + for (t = 0; t < 1 + (fh->Nf > 1); t++) { + JPEGRawQuantisationTable *quant = &priv->quant_tables.table[t]; + const uint8_t *data = t == 0 ? + vaapi_encode_mjpeg_quant_luminance : + vaapi_encode_mjpeg_quant_chrominance; + + quant->Pq = 0; + quant->Tq = t; + for (i = 0; i < 64; i++) + quant->Q[i] = av_clip(data[i] * quant_scale / 100, 1, 255); + + len += 65; + } + + priv->quant_tables.Lq = len; + + // Huffman tables. + + len = 2; + + for (t = 0; t < 2 + 2 * (fh->Nf > 1); t++) { + JPEGRawHuffmanTable *huff = &priv->huffman_tables.table[t]; + const uint8_t *lengths, *values; + int k; + + switch (t) { + case 0: + lengths = avpriv_mjpeg_bits_dc_luminance + 1; + values = avpriv_mjpeg_val_dc; + break; + case 1: + lengths = avpriv_mjpeg_bits_ac_luminance + 1; + values = avpriv_mjpeg_val_ac_luminance; + break; + case 2: + lengths = avpriv_mjpeg_bits_dc_chrominance + 1; + values = avpriv_mjpeg_val_dc; + break; + case 3: + lengths = avpriv_mjpeg_bits_ac_chrominance + 1; + values = avpriv_mjpeg_val_ac_chrominance; + break; + } + + huff->Tc = t % 2; + huff->Th = t / 2; + + for (i = k = 0; i < 16; i++) + k += (huff->L[i] = lengths[i]); + + for (i = 0; i < k; i++) + huff->V[i] = values[i]; + + len += 17 + k; + } + + priv->huffman_tables.Lh = len; + + // Scan header. + + sh->Ns = fh->Nf; + + for (i = 0; i < fh->Nf; i++) { + sh->Cs[i] = fh->C[i]; + sh->Td[i] = i > 0; + sh->Ta[i] = i > 0; + } + + sh->Ss = 0; + sh->Se = 63; + sh->Ah = 0; + sh->Al = 0; + + sh->Ls = 6 + 2 * sh->Ns; + + + *vpic = (VAEncPictureParameterBufferJPEG) { + .reconstructed_picture = pic->recon_surface, + .coded_buf = pic->output_buffer, + + .picture_width = fh->X, + .picture_height = fh->Y, + + .pic_flags.bits = { + .profile = 0, + .progressive = 0, + .huffman = 1, + .interleaved = 0, + .differential = 0, + }, + + .sample_bit_depth = fh->P, + .num_scan = 1, + .num_components = fh->Nf, + + // The driver modifies the provided quantisation tables according + // to this quality value; the middle value of 50 makes that the + // identity so that they are used unchanged. + .quality = 50, + }; + + for (i = 0; i < fh->Nf; i++) { + vpic->component_id[i] = fh->C[i]; + vpic->quantiser_table_selector[i] = fh->Tq[i]; + } pic->nb_slices = 1; @@ -317,17 +415,20 @@ static int vaapi_encode_mjpeg_init_slice_params(AVCodecContext *avctx, VAAPIEncodePicture *pic, VAAPIEncodeSlice *slice) { - VAEncPictureParameterBufferJPEG *vpic = pic->codec_picture_params; + VAAPIEncodeMJPEGContext *priv = avctx->priv_data; + JPEGRawScanHeader *sh = &priv->scan.header; VAEncSliceParameterBufferJPEG *vslice = slice->codec_slice_params; int i; - vslice->restart_interval = 0; + *vslice = (VAEncSliceParameterBufferJPEG) { + .restart_interval = 0, + .num_components = sh->Ns, + }; - vslice->num_components = vpic->num_components; - for (i = 0; i < vslice->num_components; i++) { - vslice->components[i].component_selector = i + 1; - vslice->components[i].dc_table_selector = (i > 0); - vslice->components[i].ac_table_selector = (i > 0); + for (i = 0; i < sh->Ns; i++) { + vslice->components[i].component_selector = sh->Cs[i]; + vslice->components[i].dc_table_selector = sh->Td[i]; + vslice->components[i].ac_table_selector = sh->Ta[i]; } return 0; @@ -336,9 +437,10 @@ static int vaapi_encode_mjpeg_init_slice_params(AVCodecContext *avctx, static av_cold int vaapi_encode_mjpeg_configure(AVCodecContext *avctx) { VAAPIEncodeContext *ctx = avctx->priv_data; - VAAPIEncodeMJPEGContext *priv = ctx->priv_data; + VAAPIEncodeMJPEGContext *priv = avctx->priv_data; + int err; - priv->quality = avctx->global_quality; + priv->quality = ctx->rc_quality; if (priv->quality < 1 || priv->quality > 100) { av_log(avctx, AV_LOG_ERROR, "Invalid quality value %d " "(must be 1-100).\n", priv->quality); @@ -356,16 +458,35 @@ static av_cold int vaapi_encode_mjpeg_configure(AVCodecContext *avctx) ctx->va_packed_headers |= VA_ENC_PACKED_HEADER_SLICE; } - vaapi_encode_mjpeg_init_tables(avctx); + err = ff_cbs_init(&priv->cbc, AV_CODEC_ID_MJPEG, avctx); + if (err < 0) + return err; return 0; } +static const VAAPIEncodeProfile vaapi_encode_mjpeg_profiles[] = { + { FF_PROFILE_MJPEG_HUFFMAN_BASELINE_DCT, + 8, 1, 0, 0, VAProfileJPEGBaseline }, + { FF_PROFILE_MJPEG_HUFFMAN_BASELINE_DCT, + 8, 3, 1, 1, VAProfileJPEGBaseline }, + { FF_PROFILE_MJPEG_HUFFMAN_BASELINE_DCT, + 8, 3, 1, 0, VAProfileJPEGBaseline }, + { FF_PROFILE_MJPEG_HUFFMAN_BASELINE_DCT, + 8, 3, 0, 0, VAProfileJPEGBaseline }, + { FF_PROFILE_UNKNOWN } +}; + static const VAAPIEncodeType vaapi_encode_type_mjpeg = { - .priv_data_size = sizeof(VAAPIEncodeMJPEGContext), + .profiles = vaapi_encode_mjpeg_profiles, + + .flags = FLAG_CONSTANT_QUALITY_ONLY | + FLAG_INTRA_ONLY, .configure = &vaapi_encode_mjpeg_configure, + .default_quality = 80, + .picture_params_size = sizeof(VAEncPictureParameterBufferJPEG), .init_picture_params = &vaapi_encode_mjpeg_init_picture_params, @@ -384,15 +505,8 @@ static av_cold int vaapi_encode_mjpeg_init(AVCodecContext *avctx) ctx->codec = &vaapi_encode_type_mjpeg; - ctx->va_profile = VAProfileJPEGBaseline; - ctx->va_entrypoint = VAEntrypointEncPicture; - - ctx->va_rt_format = VA_RT_FORMAT_YUV420; - - ctx->va_rc_mode = VA_RC_CQP; - // The JPEG image header - see note above. - ctx->va_packed_headers = + ctx->desired_packed_headers = VA_ENC_PACKED_HEADER_RAW_DATA; ctx->surface_width = FFALIGN(avctx->width, 8); @@ -401,14 +515,40 @@ static av_cold int vaapi_encode_mjpeg_init(AVCodecContext *avctx) return ff_vaapi_encode_init(avctx); } +static av_cold int vaapi_encode_mjpeg_close(AVCodecContext *avctx) +{ + VAAPIEncodeMJPEGContext *priv = avctx->priv_data; + + ff_cbs_fragment_free(priv->cbc, &priv->current_fragment); + ff_cbs_close(&priv->cbc); + + return ff_vaapi_encode_close(avctx); +} + +#define OFFSET(x) offsetof(VAAPIEncodeMJPEGContext, x) +#define FLAGS (AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM) +static const AVOption vaapi_encode_mjpeg_options[] = { + VAAPI_ENCODE_COMMON_OPTIONS, + + { "jfif", "Include JFIF header", + OFFSET(jfif), AV_OPT_TYPE_BOOL, + { .i64 = 0 }, 0, 1, FLAGS }, + { "huffman", "Include huffman tables", + OFFSET(huffman), AV_OPT_TYPE_BOOL, + { .i64 = 1 }, 0, 1, FLAGS }, + + { NULL }, +}; + static const AVCodecDefault vaapi_encode_mjpeg_defaults[] = { - { "global_quality", "80" }, + { "b", "0" }, { NULL }, }; static const AVClass vaapi_encode_mjpeg_class = { .class_name = "mjpeg_vaapi", .item_name = av_default_item_name, + .option = vaapi_encode_mjpeg_options, .version = LIBAVUTIL_VERSION_INT, }; @@ -417,12 +557,14 @@ AVCodec ff_mjpeg_vaapi_encoder = { .long_name = NULL_IF_CONFIG_SMALL("MJPEG (VAAPI)"), .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_MJPEG, - .priv_data_size = sizeof(VAAPIEncodeContext), + .priv_data_size = sizeof(VAAPIEncodeMJPEGContext), .init = &vaapi_encode_mjpeg_init, - .encode2 = &ff_vaapi_encode2, - .close = &ff_vaapi_encode_close, + .send_frame = &ff_vaapi_encode_send_frame, + .receive_packet = &ff_vaapi_encode_receive_packet, + .close = &vaapi_encode_mjpeg_close, .priv_class = &vaapi_encode_mjpeg_class, - .capabilities = AV_CODEC_CAP_HARDWARE, + .capabilities = AV_CODEC_CAP_HARDWARE | + AV_CODEC_CAP_INTRA_ONLY, .defaults = vaapi_encode_mjpeg_defaults, .pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_VAAPI, diff --git a/libavcodec/vaapi_encode_mpeg2.c b/libavcodec/vaapi_encode_mpeg2.c index 42df77ea4..fb1ef71fd 100644 --- a/libavcodec/vaapi_encode_mpeg2.c +++ b/libavcodec/vaapi_encode_mpeg2.c @@ -28,22 +28,17 @@ #include "vaapi_encode.h" typedef struct VAAPIEncodeMPEG2Context { - int mb_width; - int mb_height; + VAAPIEncodeContext common; + // User options. + int profile; + int level; + + // Derived settings. int quant_i; int quant_p; int quant_b; - MPEG2RawSequenceHeader sequence_header; - MPEG2RawExtensionData sequence_extension; - MPEG2RawExtensionData sequence_display_extension; - MPEG2RawGroupOfPicturesHeader gop_header; - MPEG2RawPictureHeader picture_header; - MPEG2RawExtensionData picture_coding_extension; - - int64_t last_i_frame; - unsigned int bit_rate; unsigned int vbv_buffer_size; @@ -52,6 +47,17 @@ typedef struct VAAPIEncodeMPEG2Context { unsigned int f_code_horizontal; unsigned int f_code_vertical; + // Stream state. + int64_t last_i_frame; + + // Writer structures. + MPEG2RawSequenceHeader sequence_header; + MPEG2RawExtensionData sequence_extension; + MPEG2RawExtensionData sequence_display_extension; + MPEG2RawGroupOfPicturesHeader gop_header; + MPEG2RawPictureHeader picture_header; + MPEG2RawExtensionData picture_coding_extension; + CodedBitstreamContext *cbc; CodedBitstreamFragment current_fragment; } VAAPIEncodeMPEG2Context; @@ -61,8 +67,7 @@ static int vaapi_encode_mpeg2_write_fragment(AVCodecContext *avctx, char *data, size_t *data_len, CodedBitstreamFragment *frag) { - VAAPIEncodeContext *ctx = avctx->priv_data; - VAAPIEncodeMPEG2Context *priv = ctx->priv_data; + VAAPIEncodeMPEG2Context *priv = avctx->priv_data; int err; err = ff_cbs_write_fragment_data(priv->cbc, frag); @@ -88,8 +93,7 @@ static int vaapi_encode_mpeg2_add_header(AVCodecContext *avctx, CodedBitstreamFragment *frag, int type, void *header) { - VAAPIEncodeContext *ctx = avctx->priv_data; - VAAPIEncodeMPEG2Context *priv = ctx->priv_data; + VAAPIEncodeMPEG2Context *priv = avctx->priv_data; int err; err = ff_cbs_insert_unit_content(priv->cbc, frag, -1, type, header, NULL); @@ -105,8 +109,7 @@ static int vaapi_encode_mpeg2_add_header(AVCodecContext *avctx, static int vaapi_encode_mpeg2_write_sequence_header(AVCodecContext *avctx, char *data, size_t *data_len) { - VAAPIEncodeContext *ctx = avctx->priv_data; - VAAPIEncodeMPEG2Context *priv = ctx->priv_data; + VAAPIEncodeMPEG2Context *priv = avctx->priv_data; CodedBitstreamFragment *frag = &priv->current_fragment; int err; @@ -132,7 +135,7 @@ static int vaapi_encode_mpeg2_write_sequence_header(AVCodecContext *avctx, err = vaapi_encode_mpeg2_write_fragment(avctx, data, data_len, frag); fail: - ff_cbs_fragment_uninit(priv->cbc, frag); + ff_cbs_fragment_reset(priv->cbc, frag); return 0; } @@ -140,8 +143,7 @@ static int vaapi_encode_mpeg2_write_picture_header(AVCodecContext *avctx, VAAPIEncodePicture *pic, char *data, size_t *data_len) { - VAAPIEncodeContext *ctx = avctx->priv_data; - VAAPIEncodeMPEG2Context *priv = ctx->priv_data; + VAAPIEncodeMPEG2Context *priv = avctx->priv_data; CodedBitstreamFragment *frag = &priv->current_fragment; int err; @@ -157,14 +159,14 @@ static int vaapi_encode_mpeg2_write_picture_header(AVCodecContext *avctx, err = vaapi_encode_mpeg2_write_fragment(avctx, data, data_len, frag); fail: - ff_cbs_fragment_uninit(priv->cbc, frag); + ff_cbs_fragment_reset(priv->cbc, frag); return 0; } static int vaapi_encode_mpeg2_init_sequence_params(AVCodecContext *avctx) { VAAPIEncodeContext *ctx = avctx->priv_data; - VAAPIEncodeMPEG2Context *priv = ctx->priv_data; + VAAPIEncodeMPEG2Context *priv = avctx->priv_data; MPEG2RawSequenceHeader *sh = &priv->sequence_header; MPEG2RawSequenceExtension *se = &priv->sequence_extension.data.sequence; MPEG2RawSequenceDisplayExtension *sde = &priv->sequence_display_extension.data.sequence_display; @@ -183,8 +185,8 @@ static int vaapi_encode_mpeg2_init_sequence_params(AVCodecContext *avctx) memset(pce, 0, sizeof(*pce)); - if (avctx->bit_rate > 0) { - priv->bit_rate = (avctx->bit_rate + 399) / 400; + if (ctx->va_bit_rate > 0) { + priv->bit_rate = (ctx->va_bit_rate + 399) / 400; } else { // Unknown (not a bitrate-targetting mode), so just use the // highest value. @@ -311,7 +313,8 @@ static int vaapi_encode_mpeg2_init_sequence_params(AVCodecContext *avctx) goph->group_start_code = MPEG2_START_GROUP; - goph->time_code = 0; + // Marker bit in the middle of time_code. + goph->time_code = 1 << 12; goph->closed_gop = 1; goph->broken_link = 0; @@ -350,13 +353,13 @@ static int vaapi_encode_mpeg2_init_sequence_params(AVCodecContext *avctx) *vseq = (VAEncSequenceParameterBufferMPEG2) { - .intra_period = avctx->gop_size, + .intra_period = ctx->gop_size, .ip_period = ctx->b_per_p + 1, .picture_width = avctx->width, .picture_height = avctx->height, - .bits_per_second = avctx->bit_rate, + .bits_per_second = ctx->va_bit_rate, .frame_rate = av_q2d(priv->frame_rate), .aspect_ratio_information = sh->aspect_ratio_information, .vbv_buffer_size = priv->vbv_buffer_size, @@ -416,8 +419,7 @@ static int vaapi_encode_mpeg2_init_sequence_params(AVCodecContext *avctx) static int vaapi_encode_mpeg2_init_picture_params(AVCodecContext *avctx, VAAPIEncodePicture *pic) { - VAAPIEncodeContext *ctx = avctx->priv_data; - VAAPIEncodeMPEG2Context *priv = ctx->priv_data; + VAAPIEncodeMPEG2Context *priv = avctx->priv_data; MPEG2RawPictureHeader *ph = &priv->picture_header; MPEG2RawPictureCodingExtension *pce = &priv->picture_coding_extension.data.picture_coding; VAEncPictureParameterBufferMPEG2 *vpic = pic->codec_picture_params; @@ -473,8 +475,6 @@ static int vaapi_encode_mpeg2_init_picture_params(AVCodecContext *avctx, vpic->f_code[1][0] = pce->f_code[1][0]; vpic->f_code[1][1] = pce->f_code[1][1]; - pic->nb_slices = priv->mb_height; - return 0; } @@ -482,13 +482,12 @@ static int vaapi_encode_mpeg2_init_slice_params(AVCodecContext *avctx, VAAPIEncodePicture *pic, VAAPIEncodeSlice *slice) { - VAAPIEncodeContext *ctx = avctx->priv_data; + VAAPIEncodeMPEG2Context *priv = avctx->priv_data; VAEncSliceParameterBufferMPEG2 *vslice = slice->codec_slice_params; - VAAPIEncodeMPEG2Context *priv = ctx->priv_data; int qp; - vslice->macroblock_address = priv->mb_width * slice->index; - vslice->num_macroblocks = priv->mb_width; + vslice->macroblock_address = slice->block_start; + vslice->num_macroblocks = slice->block_size; switch (pic->type) { case PICTURE_TYPE_IDR: @@ -515,30 +514,25 @@ static int vaapi_encode_mpeg2_init_slice_params(AVCodecContext *avctx, static av_cold int vaapi_encode_mpeg2_configure(AVCodecContext *avctx) { VAAPIEncodeContext *ctx = avctx->priv_data; - VAAPIEncodeMPEG2Context *priv = ctx->priv_data; + VAAPIEncodeMPEG2Context *priv = avctx->priv_data; int err; err = ff_cbs_init(&priv->cbc, AV_CODEC_ID_MPEG2VIDEO, avctx); if (err < 0) return err; - priv->mb_width = FFALIGN(avctx->width, 16) / 16; - priv->mb_height = FFALIGN(avctx->height, 16) / 16; - if (ctx->va_rc_mode == VA_RC_CQP) { - priv->quant_p = av_clip(avctx->global_quality, 1, 31); + priv->quant_p = av_clip(ctx->rc_quality, 1, 31); if (avctx->i_quant_factor > 0.0) - priv->quant_i = av_clip((avctx->global_quality * - avctx->i_quant_factor + - avctx->i_quant_offset) + 0.5, - 1, 31); + priv->quant_i = + av_clip((avctx->i_quant_factor * priv->quant_p + + avctx->i_quant_offset) + 0.5, 1, 31); else priv->quant_i = priv->quant_p; if (avctx->b_quant_factor > 0.0) - priv->quant_b = av_clip((avctx->global_quality * - avctx->b_quant_factor + - avctx->b_quant_offset) + 0.5, - 1, 31); + priv->quant_b = + av_clip((avctx->b_quant_factor * priv->quant_p + + avctx->b_quant_offset) + 0.5, 1, 31); else priv->quant_b = priv->quant_p; @@ -547,17 +541,35 @@ static av_cold int vaapi_encode_mpeg2_configure(AVCodecContext *avctx) priv->quant_i, priv->quant_p, priv->quant_b); } else { - av_assert0(0 && "Invalid RC mode."); + priv->quant_i = 16; + priv->quant_p = 16; + priv->quant_b = 16; } + ctx->slice_block_rows = FFALIGN(avctx->height, 16) / 16; + ctx->slice_block_cols = FFALIGN(avctx->width, 16) / 16; + + ctx->nb_slices = ctx->slice_block_rows; + ctx->slice_size = 1; + return 0; } +static const VAAPIEncodeProfile vaapi_encode_mpeg2_profiles[] = { + { FF_PROFILE_MPEG2_MAIN, 8, 3, 1, 1, VAProfileMPEG2Main }, + { FF_PROFILE_MPEG2_SIMPLE, 8, 3, 1, 1, VAProfileMPEG2Simple }, + { FF_PROFILE_UNKNOWN } +}; + static const VAAPIEncodeType vaapi_encode_type_mpeg2 = { - .priv_data_size = sizeof(VAAPIEncodeMPEG2Context), + .profiles = vaapi_encode_mpeg2_profiles, + + .flags = FLAG_B_PICTURES, .configure = &vaapi_encode_mpeg2_configure, + .default_quality = 10, + .sequence_params_size = sizeof(VAEncSequenceParameterBufferMPEG2), .init_sequence_params = &vaapi_encode_mpeg2_init_sequence_params, @@ -576,35 +588,18 @@ static const VAAPIEncodeType vaapi_encode_type_mpeg2 = { static av_cold int vaapi_encode_mpeg2_init(AVCodecContext *avctx) { - VAAPIEncodeContext *ctx = avctx->priv_data; + VAAPIEncodeContext *ctx = avctx->priv_data; + VAAPIEncodeMPEG2Context *priv = avctx->priv_data; ctx->codec = &vaapi_encode_type_mpeg2; - switch (avctx->profile) { - case FF_PROFILE_MPEG2_SIMPLE: - ctx->va_profile = VAProfileMPEG2Simple; - break; - case FF_PROFILE_MPEG2_MAIN: - ctx->va_profile = VAProfileMPEG2Main; - break; - case FF_PROFILE_MPEG2_422: - av_log(avctx, AV_LOG_ERROR, "MPEG-2 4:2:2 profile " - "is not supported.\n"); - return AVERROR_PATCHWELCOME; - case FF_PROFILE_MPEG2_HIGH: - av_log(avctx, AV_LOG_ERROR, "MPEG-2 high profile " - "is not supported.\n"); - return AVERROR_PATCHWELCOME; - case FF_PROFILE_MPEG2_SS: - case FF_PROFILE_MPEG2_SNR_SCALABLE: - av_log(avctx, AV_LOG_ERROR, "MPEG-2 scalable profiles " - "are not supported.\n"); - return AVERROR_PATCHWELCOME; - default: - av_log(avctx, AV_LOG_ERROR, "Unknown MPEG-2 profile %d.\n", - avctx->profile); - return AVERROR(EINVAL); - } + if (avctx->profile == FF_PROFILE_UNKNOWN) + avctx->profile = priv->profile; + if (avctx->level == FF_LEVEL_UNKNOWN) + avctx->level = priv->level; + + // Reject unknown levels (these are required to set f_code for + // motion vector encoding). switch (avctx->level) { case 4: // High case 6: // High 1440 @@ -623,12 +618,8 @@ static av_cold int vaapi_encode_mpeg2_init(AVCodecContext *avctx) return AVERROR(EINVAL); } - ctx->va_entrypoint = VAEntrypointEncSlice; - ctx->va_rt_format = VA_RT_FORMAT_YUV420; - ctx->va_rc_mode = VA_RC_CQP; - - ctx->va_packed_headers = VA_ENC_PACKED_HEADER_SEQUENCE | - VA_ENC_PACKED_HEADER_PICTURE; + ctx->desired_packed_headers = VA_ENC_PACKED_HEADER_SEQUENCE | + VA_ENC_PACKED_HEADER_PICTURE; ctx->surface_width = FFALIGN(avctx->width, 16); ctx->surface_height = FFALIGN(avctx->height, 16); @@ -638,37 +629,76 @@ static av_cold int vaapi_encode_mpeg2_init(AVCodecContext *avctx) static av_cold int vaapi_encode_mpeg2_close(AVCodecContext *avctx) { - VAAPIEncodeContext *ctx = avctx->priv_data; - VAAPIEncodeMPEG2Context *priv = ctx->priv_data; + VAAPIEncodeMPEG2Context *priv = avctx->priv_data; - if (priv) - ff_cbs_close(&priv->cbc); + ff_cbs_fragment_free(priv->cbc, &priv->current_fragment); + ff_cbs_close(&priv->cbc); return ff_vaapi_encode_close(avctx); } +#define OFFSET(x) offsetof(VAAPIEncodeMPEG2Context, x) +#define FLAGS (AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM) +static const AVOption vaapi_encode_mpeg2_options[] = { + VAAPI_ENCODE_COMMON_OPTIONS, + VAAPI_ENCODE_RC_OPTIONS, + + { "profile", "Set profile (in profile_and_level_indication)", + OFFSET(profile), AV_OPT_TYPE_INT, + { .i64 = FF_PROFILE_UNKNOWN }, FF_PROFILE_UNKNOWN, 7, FLAGS, "profile" }, + +#define PROFILE(name, value) name, NULL, 0, AV_OPT_TYPE_CONST, \ + { .i64 = value }, 0, 0, FLAGS, "profile" + { PROFILE("simple", FF_PROFILE_MPEG2_SIMPLE) }, + { PROFILE("main", FF_PROFILE_MPEG2_MAIN) }, +#undef PROFILE + + { "level", "Set level (in profile_and_level_indication)", + OFFSET(level), AV_OPT_TYPE_INT, + { .i64 = 4 }, 0, 15, FLAGS, "level" }, + +#define LEVEL(name, value) name, NULL, 0, AV_OPT_TYPE_CONST, \ + { .i64 = value }, 0, 0, FLAGS, "level" + { LEVEL("low", 10) }, + { LEVEL("main", 8) }, + { LEVEL("high_1440", 6) }, + { LEVEL("high", 4) }, +#undef LEVEL + + { NULL }, +}; + static const AVCodecDefault vaapi_encode_mpeg2_defaults[] = { - { "profile", "4" }, - { "level", "4" }, + { "b", "0" }, { "bf", "1" }, { "g", "120" }, { "i_qfactor", "1" }, { "i_qoffset", "0" }, { "b_qfactor", "6/5" }, { "b_qoffset", "0" }, - { "global_quality", "10" }, + { "qmin", "-1" }, + { "qmax", "-1" }, { NULL }, }; +static const AVClass vaapi_encode_mpeg2_class = { + .class_name = "mpeg2_vaapi", + .item_name = av_default_item_name, + .option = vaapi_encode_mpeg2_options, + .version = LIBAVUTIL_VERSION_INT, +}; + AVCodec ff_mpeg2_vaapi_encoder = { .name = "mpeg2_vaapi", .long_name = NULL_IF_CONFIG_SMALL("MPEG-2 (VAAPI)"), .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_MPEG2VIDEO, - .priv_data_size = sizeof(VAAPIEncodeContext), + .priv_data_size = sizeof(VAAPIEncodeMPEG2Context), .init = &vaapi_encode_mpeg2_init, - .encode2 = &ff_vaapi_encode2, + .send_frame = &ff_vaapi_encode_send_frame, + .receive_packet = &ff_vaapi_encode_receive_packet, .close = &vaapi_encode_mpeg2_close, + .priv_class = &vaapi_encode_mpeg2_class, .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HARDWARE, .defaults = vaapi_encode_mpeg2_defaults, .pix_fmts = (const enum AVPixelFormat[]) { diff --git a/libavcodec/vaapi_encode_vp8.c b/libavcodec/vaapi_encode_vp8.c index b4c5521d1..ddbe4c907 100644 --- a/libavcodec/vaapi_encode_vp8.c +++ b/libavcodec/vaapi_encode_vp8.c @@ -32,15 +32,17 @@ typedef struct VAAPIEncodeVP8Context { + VAAPIEncodeContext common; + + // User options. + int loop_filter_level; + int loop_filter_sharpness; + + // Derived settings. int q_index_i; int q_index_p; } VAAPIEncodeVP8Context; -typedef struct VAAPIEncodeVP8Options { - int loop_filter_level; - int loop_filter_sharpness; -} VAAPIEncodeVP8Options; - #define vseq_var(name) vseq->name, name #define vseq_field(name) vseq->seq_fields.bits.name, name @@ -63,8 +65,8 @@ static int vaapi_encode_vp8_init_sequence_params(AVCodecContext *avctx) vseq->kf_auto = 0; if (!(ctx->va_rc_mode & VA_RC_CQP)) { - vseq->bits_per_second = avctx->bit_rate; - vseq->intra_period = avctx->gop_size; + vseq->bits_per_second = ctx->va_bit_rate; + vseq->intra_period = ctx->gop_size; } return 0; @@ -73,9 +75,8 @@ static int vaapi_encode_vp8_init_sequence_params(AVCodecContext *avctx) static int vaapi_encode_vp8_init_picture_params(AVCodecContext *avctx, VAAPIEncodePicture *pic) { - VAAPIEncodeContext *ctx = avctx->priv_data; + VAAPIEncodeVP8Context *priv = avctx->priv_data; VAEncPictureParameterBufferVP8 *vpic = pic->codec_picture_params; - VAAPIEncodeVP8Options *opt = ctx->codec_options; int i; vpic->reconstructed_frame = pic->recon_surface; @@ -116,8 +117,8 @@ static int vaapi_encode_vp8_init_picture_params(AVCodecContext *avctx, vpic->pic_flags.bits.version = 0; vpic->pic_flags.bits.loop_filter_type = 0; for (i = 0; i < 4; i++) - vpic->loop_filter_level[i] = opt->loop_filter_level; - vpic->sharpness_level = opt->loop_filter_sharpness; + vpic->loop_filter_level[i] = priv->loop_filter_level; + vpic->sharpness_level = priv->loop_filter_sharpness; vpic->clamp_qindex_low = 0; vpic->clamp_qindex_high = 127; @@ -130,8 +131,7 @@ static int vaapi_encode_vp8_write_quant_table(AVCodecContext *avctx, int index, int *type, char *data, size_t *data_len) { - VAAPIEncodeContext *ctx = avctx->priv_data; - VAAPIEncodeVP8Context *priv = ctx->priv_data; + VAAPIEncodeVP8Context *priv = avctx->priv_data; VAQMatrixBufferVP8 quant; int i, q; @@ -143,6 +143,8 @@ static int vaapi_encode_vp8_write_quant_table(AVCodecContext *avctx, *type = VAQMatrixBufferType; *data_len = sizeof(quant); + memset(&quant, 0, sizeof(quant)); + if (pic->type == PICTURE_TYPE_P) q = priv->q_index_p; else @@ -160,24 +162,31 @@ static int vaapi_encode_vp8_write_quant_table(AVCodecContext *avctx, static av_cold int vaapi_encode_vp8_configure(AVCodecContext *avctx) { VAAPIEncodeContext *ctx = avctx->priv_data; - VAAPIEncodeVP8Context *priv = ctx->priv_data; + VAAPIEncodeVP8Context *priv = avctx->priv_data; - priv->q_index_p = av_clip(avctx->global_quality, 0, VP8_MAX_QUANT); + priv->q_index_p = av_clip(ctx->rc_quality, 0, VP8_MAX_QUANT); if (avctx->i_quant_factor > 0.0) - priv->q_index_i = av_clip((avctx->global_quality * - avctx->i_quant_factor + - avctx->i_quant_offset) + 0.5, - 0, VP8_MAX_QUANT); + priv->q_index_i = + av_clip((avctx->i_quant_factor * priv->q_index_p + + avctx->i_quant_offset) + 0.5, + 0, VP8_MAX_QUANT); else priv->q_index_i = priv->q_index_p; return 0; } +static const VAAPIEncodeProfile vaapi_encode_vp8_profiles[] = { + { 0 /* VP8 has no profiles */, 8, 3, 1, 1, VAProfileVP8Version0_3 }, + { FF_PROFILE_UNKNOWN } +}; + static const VAAPIEncodeType vaapi_encode_type_vp8 = { + .profiles = vaapi_encode_vp8_profiles, + .configure = &vaapi_encode_vp8_configure, - .priv_data_size = sizeof(VAAPIEncodeVP8Context), + .default_quality = 40, .sequence_params_size = sizeof(VAEncSequenceParameterBufferVP8), .init_sequence_params = &vaapi_encode_vp8_init_sequence_params, @@ -192,30 +201,12 @@ static av_cold int vaapi_encode_vp8_init(AVCodecContext *avctx) { VAAPIEncodeContext *ctx = avctx->priv_data; - if (avctx->max_b_frames > 0) { - av_log(avctx, AV_LOG_ERROR, "B-frames are not supported.\n"); - return AVERROR_PATCHWELCOME; - } - ctx->codec = &vaapi_encode_type_vp8; - ctx->va_profile = VAProfileVP8Version0_3; - ctx->va_entrypoint = VAEntrypointEncSlice; - ctx->va_rt_format = VA_RT_FORMAT_YUV420; - - if (avctx->flags & AV_CODEC_FLAG_QSCALE) { - ctx->va_rc_mode = VA_RC_CQP; - } else if (avctx->bit_rate > 0) { - if (avctx->rc_max_rate == avctx->bit_rate) - ctx->va_rc_mode = VA_RC_CBR; - else - ctx->va_rc_mode = VA_RC_VBR; - } else { - ctx->va_rc_mode = VA_RC_CQP; - } - - // Packed headers are not currently supported. - ctx->va_packed_headers = 0; + // No packed headers are currently desired. VP8 has no metadata + // which would be useful to write, and no existing driver supports + // adding them anyway. + ctx->desired_packed_headers = 0; ctx->surface_width = FFALIGN(avctx->width, 16); ctx->surface_height = FFALIGN(avctx->height, 16); @@ -223,10 +214,12 @@ static av_cold int vaapi_encode_vp8_init(AVCodecContext *avctx) return ff_vaapi_encode_init(avctx); } -#define OFFSET(x) (offsetof(VAAPIEncodeContext, codec_options_data) + \ - offsetof(VAAPIEncodeVP8Options, x)) +#define OFFSET(x) offsetof(VAAPIEncodeVP8Context, x) #define FLAGS (AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM) static const AVOption vaapi_encode_vp8_options[] = { + VAAPI_ENCODE_COMMON_OPTIONS, + VAAPI_ENCODE_RC_OPTIONS, + { "loop_filter_level", "Loop filter level", OFFSET(loop_filter_level), AV_OPT_TYPE_INT, { .i64 = 16 }, 0, 63, FLAGS }, { "loop_filter_sharpness", "Loop filter sharpness", @@ -238,7 +231,8 @@ static const AVCodecDefault vaapi_encode_vp8_defaults[] = { { "b", "0" }, { "bf", "0" }, { "g", "120" }, - { "global_quality", "40" }, + { "qmin", "-1" }, + { "qmax", "-1" }, { NULL }, }; @@ -254,10 +248,10 @@ AVCodec ff_vp8_vaapi_encoder = { .long_name = NULL_IF_CONFIG_SMALL("VP8 (VAAPI)"), .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_VP8, - .priv_data_size = (sizeof(VAAPIEncodeContext) + - sizeof(VAAPIEncodeVP8Options)), + .priv_data_size = sizeof(VAAPIEncodeVP8Context), .init = &vaapi_encode_vp8_init, - .encode2 = &ff_vaapi_encode2, + .send_frame = &ff_vaapi_encode_send_frame, + .receive_packet = &ff_vaapi_encode_receive_packet, .close = &ff_vaapi_encode_close, .priv_class = &vaapi_encode_vp8_class, .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HARDWARE, diff --git a/libavcodec/vaapi_encode_vp9.c b/libavcodec/vaapi_encode_vp9.c index 9108699ac..f89fd0d07 100644 --- a/libavcodec/vaapi_encode_vp9.c +++ b/libavcodec/vaapi_encode_vp9.c @@ -32,28 +32,23 @@ #define VP9_MAX_QUANT 255 +typedef struct VAAPIEncodeVP9Picture { + int slot; +} VAAPIEncodeVP9Picture; + typedef struct VAAPIEncodeVP9Context { + VAAPIEncodeContext common; + + // User options. + int loop_filter_level; + int loop_filter_sharpness; + + // Derived settings. int q_idx_idr; int q_idx_p; int q_idx_b; - - // Reference direction for B-like frames: - // 0 - most recent P/IDR frame is last. - // 1 - most recent P frame is golden. - int last_ref_dir; } VAAPIEncodeVP9Context; -typedef struct VAAPIEncodeVP9Options { - int loop_filter_level; - int loop_filter_sharpness; -} VAAPIEncodeVP9Options; - - -#define vseq_var(name) vseq->name, name -#define vseq_field(name) vseq->seq_fields.bits.name, name -#define vpic_var(name) vpic->name, name -#define vpic_field(name) vpic->pic_fields.bits.name, name - static int vaapi_encode_vp9_init_sequence_params(AVCodecContext *avctx) { @@ -67,8 +62,8 @@ static int vaapi_encode_vp9_init_sequence_params(AVCodecContext *avctx) vseq->kf_auto = 0; if (!(ctx->va_rc_mode & VA_RC_CQP)) { - vseq->bits_per_second = avctx->bit_rate; - vseq->intra_period = avctx->gop_size; + vseq->bits_per_second = ctx->va_bit_rate; + vseq->intra_period = ctx->gop_size; } vpic->frame_width_src = avctx->width; @@ -83,9 +78,9 @@ static int vaapi_encode_vp9_init_picture_params(AVCodecContext *avctx, VAAPIEncodePicture *pic) { VAAPIEncodeContext *ctx = avctx->priv_data; + VAAPIEncodeVP9Context *priv = avctx->priv_data; + VAAPIEncodeVP9Picture *hpic = pic->priv_data; VAEncPictureParameterBufferVP9 *vpic = pic->codec_picture_params; - VAAPIEncodeVP9Context *priv = ctx->priv_data; - VAAPIEncodeVP9Options *opt = ctx->codec_options; int i; vpic->reconstructed_frame = pic->recon_surface; @@ -95,65 +90,71 @@ static int vaapi_encode_vp9_init_picture_params(AVCodecContext *avctx, case PICTURE_TYPE_IDR: av_assert0(pic->nb_refs == 0); vpic->ref_flags.bits.force_kf = 1; - vpic->refresh_frame_flags = 0x01; - priv->last_ref_dir = 0; + vpic->refresh_frame_flags = 0xff; + hpic->slot = 0; break; case PICTURE_TYPE_P: av_assert0(pic->nb_refs == 1); - if (avctx->max_b_frames > 0) { - if (priv->last_ref_dir) { - vpic->ref_flags.bits.ref_frame_ctrl_l0 = 2; - vpic->ref_flags.bits.ref_gf_idx = 1; - vpic->ref_flags.bits.ref_gf_sign_bias = 1; - vpic->refresh_frame_flags = 0x01; + { + VAAPIEncodeVP9Picture *href = pic->refs[0]->priv_data; + av_assert0(href->slot == 0 || href->slot == 1); + + if (ctx->max_b_depth > 0) { + hpic->slot = !href->slot; + vpic->refresh_frame_flags = 1 << hpic->slot | 0xfc; } else { - vpic->ref_flags.bits.ref_frame_ctrl_l0 = 1; - vpic->ref_flags.bits.ref_last_idx = 0; - vpic->ref_flags.bits.ref_last_sign_bias = 1; - vpic->refresh_frame_flags = 0x02; + hpic->slot = 0; + vpic->refresh_frame_flags = 0xff; } - } else { vpic->ref_flags.bits.ref_frame_ctrl_l0 = 1; - vpic->ref_flags.bits.ref_last_idx = 0; + vpic->ref_flags.bits.ref_last_idx = href->slot; vpic->ref_flags.bits.ref_last_sign_bias = 1; - vpic->refresh_frame_flags = 0x01; } break; case PICTURE_TYPE_B: av_assert0(pic->nb_refs == 2); - if (priv->last_ref_dir) { + { + VAAPIEncodeVP9Picture *href0 = pic->refs[0]->priv_data, + *href1 = pic->refs[1]->priv_data; + av_assert0(href0->slot < pic->b_depth + 1 && + href1->slot < pic->b_depth + 1); + + if (pic->b_depth == ctx->max_b_depth) { + // Unreferenced frame. + vpic->refresh_frame_flags = 0x00; + hpic->slot = 8; + } else { + vpic->refresh_frame_flags = 0xfe << pic->b_depth & 0xff; + hpic->slot = 1 + pic->b_depth; + } vpic->ref_flags.bits.ref_frame_ctrl_l0 = 1; vpic->ref_flags.bits.ref_frame_ctrl_l1 = 2; - vpic->ref_flags.bits.ref_last_idx = 0; + vpic->ref_flags.bits.ref_last_idx = href0->slot; vpic->ref_flags.bits.ref_last_sign_bias = 1; - vpic->ref_flags.bits.ref_gf_idx = 1; + vpic->ref_flags.bits.ref_gf_idx = href1->slot; vpic->ref_flags.bits.ref_gf_sign_bias = 0; - } else { - vpic->ref_flags.bits.ref_frame_ctrl_l0 = 2; - vpic->ref_flags.bits.ref_frame_ctrl_l1 = 1; - vpic->ref_flags.bits.ref_last_idx = 0; - vpic->ref_flags.bits.ref_last_sign_bias = 0; - vpic->ref_flags.bits.ref_gf_idx = 1; - vpic->ref_flags.bits.ref_gf_sign_bias = 1; } - vpic->refresh_frame_flags = 0x00; break; default: av_assert0(0 && "invalid picture type"); } + if (vpic->refresh_frame_flags == 0x00) { + av_log(avctx, AV_LOG_DEBUG, "Pic %"PRId64" not stored.\n", + pic->display_order); + } else { + av_log(avctx, AV_LOG_DEBUG, "Pic %"PRId64" stored in slot %d.\n", + pic->display_order, hpic->slot); + } for (i = 0; i < FF_ARRAY_ELEMS(vpic->reference_frames); i++) vpic->reference_frames[i] = VA_INVALID_SURFACE; - if (pic->type == PICTURE_TYPE_P) { - av_assert0(pic->refs[0]); - vpic->reference_frames[priv->last_ref_dir] = - pic->refs[0]->recon_surface; - } else if (pic->type == PICTURE_TYPE_B) { - av_assert0(pic->refs[0] && pic->refs[1]); - vpic->reference_frames[!priv->last_ref_dir] = - pic->refs[0]->recon_surface; - vpic->reference_frames[priv->last_ref_dir] = - pic->refs[1]->recon_surface; + + for (i = 0; i < pic->nb_refs; i++) { + VAAPIEncodePicture *ref_pic = pic->refs[i]; + int slot; + slot = ((VAAPIEncodeVP9Picture*)ref_pic->priv_data)->slot; + av_assert0(vpic->reference_frames[slot] == VA_INVALID_SURFACE); + vpic->reference_frames[slot] = ref_pic->recon_surface; } vpic->pic_flags.bits.frame_type = (pic->type != PICTURE_TYPE_IDR); @@ -169,11 +170,8 @@ static int vaapi_encode_vp9_init_picture_params(AVCodecContext *avctx, vpic->chroma_ac_qindex_delta = 0; vpic->chroma_dc_qindex_delta = 0; - vpic->filter_level = opt->loop_filter_level; - vpic->sharpness_level = opt->loop_filter_sharpness; - - if (avctx->max_b_frames > 0 && pic->type == PICTURE_TYPE_P) - priv->last_ref_dir = !priv->last_ref_dir; + vpic->filter_level = priv->loop_filter_level; + vpic->sharpness_level = priv->loop_filter_sharpness; return 0; } @@ -181,31 +179,49 @@ static int vaapi_encode_vp9_init_picture_params(AVCodecContext *avctx, static av_cold int vaapi_encode_vp9_configure(AVCodecContext *avctx) { VAAPIEncodeContext *ctx = avctx->priv_data; - VAAPIEncodeVP9Context *priv = ctx->priv_data; + VAAPIEncodeVP9Context *priv = avctx->priv_data; - priv->q_idx_p = av_clip(avctx->global_quality, 0, VP9_MAX_QUANT); - if (avctx->i_quant_factor > 0.0) - priv->q_idx_idr = av_clip((avctx->global_quality * - avctx->i_quant_factor + - avctx->i_quant_offset) + 0.5, - 0, VP9_MAX_QUANT); - else - priv->q_idx_idr = priv->q_idx_p; - if (avctx->b_quant_factor > 0.0) - priv->q_idx_b = av_clip((avctx->global_quality * - avctx->b_quant_factor + - avctx->b_quant_offset) + 0.5, - 0, VP9_MAX_QUANT); - else - priv->q_idx_b = priv->q_idx_p; + if (ctx->rc_mode->quality) { + priv->q_idx_p = av_clip(ctx->rc_quality, 0, VP9_MAX_QUANT); + if (avctx->i_quant_factor > 0.0) + priv->q_idx_idr = + av_clip((avctx->i_quant_factor * priv->q_idx_p + + avctx->i_quant_offset) + 0.5, + 0, VP9_MAX_QUANT); + else + priv->q_idx_idr = priv->q_idx_p; + if (avctx->b_quant_factor > 0.0) + priv->q_idx_b = + av_clip((avctx->b_quant_factor * priv->q_idx_p + + avctx->b_quant_offset) + 0.5, + 0, VP9_MAX_QUANT); + else + priv->q_idx_b = priv->q_idx_p; + } else { + // Arbitrary value. + priv->q_idx_idr = priv->q_idx_p = priv->q_idx_b = 100; + } return 0; } -static const VAAPIEncodeType vaapi_encode_type_vp9 = { - .configure = &vaapi_encode_vp9_configure, +static const VAAPIEncodeProfile vaapi_encode_vp9_profiles[] = { + { FF_PROFILE_VP9_0, 8, 3, 1, 1, VAProfileVP9Profile0 }, + { FF_PROFILE_VP9_2, 10, 3, 1, 1, VAProfileVP9Profile2 }, + { FF_PROFILE_UNKNOWN } +}; - .priv_data_size = sizeof(VAAPIEncodeVP9Context), +static const VAAPIEncodeType vaapi_encode_type_vp9 = { + .profiles = vaapi_encode_vp9_profiles, + + .flags = FLAG_B_PICTURES | + FLAG_B_PICTURE_REFERENCES, + + .default_quality = 100, + + .picture_priv_data_size = sizeof(VAAPIEncodeVP9Picture), + + .configure = &vaapi_encode_vp9_configure, .sequence_params_size = sizeof(VAEncSequenceParameterBufferVP9), .init_sequence_params = &vaapi_encode_vp9_init_sequence_params, @@ -220,44 +236,10 @@ static av_cold int vaapi_encode_vp9_init(AVCodecContext *avctx) ctx->codec = &vaapi_encode_type_vp9; - switch (avctx->profile) { - case FF_PROFILE_VP9_0: - case FF_PROFILE_UNKNOWN: - ctx->va_profile = VAProfileVP9Profile0; - ctx->va_rt_format = VA_RT_FORMAT_YUV420; - break; - case FF_PROFILE_VP9_1: - av_log(avctx, AV_LOG_ERROR, "VP9 profile 1 is not " - "supported.\n"); - return AVERROR_PATCHWELCOME; - case FF_PROFILE_VP9_2: - ctx->va_profile = VAProfileVP9Profile2; - ctx->va_rt_format = VA_RT_FORMAT_YUV420_10BPP; - break; - case FF_PROFILE_VP9_3: - av_log(avctx, AV_LOG_ERROR, "VP9 profile 3 is not " - "supported.\n"); - return AVERROR_PATCHWELCOME; - default: - av_log(avctx, AV_LOG_ERROR, "Unknown VP9 profile %d.\n", - avctx->profile); - return AVERROR(EINVAL); - } - ctx->va_entrypoint = VAEntrypointEncSlice; - - if (avctx->flags & AV_CODEC_FLAG_QSCALE) { - ctx->va_rc_mode = VA_RC_CQP; - } else if (avctx->bit_rate > 0) { - if (avctx->bit_rate == avctx->rc_max_rate) - ctx->va_rc_mode = VA_RC_CBR; - else - ctx->va_rc_mode = VA_RC_VBR; - } else { - ctx->va_rc_mode = VA_RC_CQP; - } - - // Packed headers are not currently supported. - ctx->va_packed_headers = 0; + // No packed headers are currently desired. They could be written, + // but there isn't any reason to do so - the one usable driver (i965) + // can write its own headers and there is no metadata to include. + ctx->desired_packed_headers = 0; // Surfaces must be aligned to superblock boundaries. ctx->surface_width = FFALIGN(avctx->width, 64); @@ -266,10 +248,12 @@ static av_cold int vaapi_encode_vp9_init(AVCodecContext *avctx) return ff_vaapi_encode_init(avctx); } -#define OFFSET(x) (offsetof(VAAPIEncodeContext, codec_options_data) + \ - offsetof(VAAPIEncodeVP9Options, x)) +#define OFFSET(x) offsetof(VAAPIEncodeVP9Context, x) #define FLAGS (AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM) static const AVOption vaapi_encode_vp9_options[] = { + VAAPI_ENCODE_COMMON_OPTIONS, + VAAPI_ENCODE_RC_OPTIONS, + { "loop_filter_level", "Loop filter level", OFFSET(loop_filter_level), AV_OPT_TYPE_INT, { .i64 = 16 }, 0, 63, FLAGS }, { "loop_filter_sharpness", "Loop filter sharpness", @@ -278,11 +262,11 @@ static const AVOption vaapi_encode_vp9_options[] = { }; static const AVCodecDefault vaapi_encode_vp9_defaults[] = { - { "profile", "0" }, { "b", "0" }, { "bf", "0" }, { "g", "250" }, - { "global_quality", "100" }, + { "qmin", "-1" }, + { "qmax", "-1" }, { NULL }, }; @@ -298,10 +282,10 @@ AVCodec ff_vp9_vaapi_encoder = { .long_name = NULL_IF_CONFIG_SMALL("VP9 (VAAPI)"), .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_VP9, - .priv_data_size = (sizeof(VAAPIEncodeContext) + - sizeof(VAAPIEncodeVP9Options)), + .priv_data_size = sizeof(VAAPIEncodeVP9Context), .init = &vaapi_encode_vp9_init, - .encode2 = &ff_vaapi_encode2, + .send_frame = &ff_vaapi_encode_send_frame, + .receive_packet = &ff_vaapi_encode_receive_packet, .close = &ff_vaapi_encode_close, .priv_class = &vaapi_encode_vp9_class, .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HARDWARE, diff --git a/libavcodec/vaapi_h264.c b/libavcodec/vaapi_h264.c index 5854587a2..dd2a65716 100644 --- a/libavcodec/vaapi_h264.c +++ b/libavcodec/vaapi_h264.c @@ -256,9 +256,6 @@ static int vaapi_h264_start_frame(AVCodecContext *avctx, .log2_max_pic_order_cnt_lsb_minus4 = sps->log2_max_poc_lsb - 4, .delta_pic_order_always_zero_flag = sps->delta_pic_order_always_zero_flag, }, - .num_slice_groups_minus1 = pps->slice_group_count - 1, - .slice_group_map_type = pps->mb_slice_group_map_type, - .slice_group_change_rate_minus1 = 0, /* FMO is not implemented */ .pic_init_qp_minus26 = pps->init_qp - 26, .pic_init_qs_minus26 = pps->init_qs - 26, .chroma_qp_index_offset = pps->chroma_qp_index_offset[0], diff --git a/libavcodec/vaapi_hevc.c b/libavcodec/vaapi_hevc.c index 19aabcdb5..c69d63d8e 100644 --- a/libavcodec/vaapi_hevc.c +++ b/libavcodec/vaapi_hevc.c @@ -122,8 +122,6 @@ static int vaapi_hevc_start_frame(AVCodecContext *avctx, pic->pic.output_surface = ff_vaapi_get_surface_id(h->ref->frame); pic->pic_param = (VAPictureParameterBufferHEVC) { - .pic_fields.value = 0, - .slice_parsing_fields.value = 0, .pic_width_in_luma_samples = sps->width, .pic_height_in_luma_samples = sps->height, .log2_min_luma_coding_block_size_minus3 = sps->log2_min_cb_size - 3, diff --git a/libavcodec/vaapi_vc1.c b/libavcodec/vaapi_vc1.c index 74ba78314..921ca6391 100644 --- a/libavcodec/vaapi_vc1.c +++ b/libavcodec/vaapi_vc1.c @@ -138,8 +138,9 @@ static int vc1_get_FPTYPE(const VC1Context *v) /** Reconstruct bitstream MVMODE (7.1.1.32) */ static inline VAMvModeVC1 vc1_get_MVMODE(const VC1Context *v) { - if ((v->s.pict_type == AV_PICTURE_TYPE_P && !v->p_frame_skipped) || - (v->s.pict_type == AV_PICTURE_TYPE_B && !v->bi_type)) + if ((v->fcm == PROGRESSIVE || v->fcm == ILACE_FIELD) && + ((v->s.pict_type == AV_PICTURE_TYPE_P && !v->p_frame_skipped) || + (v->s.pict_type == AV_PICTURE_TYPE_B && !v->bi_type))) return get_VAMvModeVC1(v->mv_mode); return 0; } @@ -147,7 +148,8 @@ static inline VAMvModeVC1 vc1_get_MVMODE(const VC1Context *v) /** Reconstruct bitstream MVMODE2 (7.1.1.33) */ static inline VAMvModeVC1 vc1_get_MVMODE2(const VC1Context *v) { - if ((v->s.pict_type == AV_PICTURE_TYPE_P && !v->p_frame_skipped) && + if ((v->fcm == PROGRESSIVE || v->fcm == ILACE_FIELD) && + (v->s.pict_type == AV_PICTURE_TYPE_P && !v->p_frame_skipped) && v->mv_mode == MV_PMODE_INTENSITY_COMP) return get_VAMvModeVC1(v->mv_mode2); return 0; @@ -465,6 +467,7 @@ static int vaapi_vc1_decode_slice(AVCodecContext *avctx, const uint8_t *buffer, const MpegEncContext *s = &v->s; VAAPIDecodePicture *pic = s->current_picture_ptr->hwaccel_picture_private; VASliceParameterBufferVC1 slice_param; + int mb_height; int err; /* Current bit buffer is beyond any marker for VC-1, so skip it */ @@ -473,12 +476,17 @@ static int vaapi_vc1_decode_slice(AVCodecContext *avctx, const uint8_t *buffer, size -= 4; } + if (v->fcm == ILACE_FIELD) + mb_height = avctx->coded_height + 31 >> 5; + else + mb_height = avctx->coded_height + 15 >> 4; + slice_param = (VASliceParameterBufferVC1) { .slice_data_size = size, .slice_data_offset = 0, .slice_data_flag = VA_SLICE_DATA_FLAG_ALL, .macroblock_offset = get_bits_count(&s->gb), - .slice_vertical_position = s->mb_y, + .slice_vertical_position = s->mb_y % mb_height, }; err = ff_vaapi_decode_make_slice_buffer(avctx, pic, diff --git a/libavcodec/vb.c b/libavcodec/vb.c index c6dd6fb45..d9c6b93a7 100644 --- a/libavcodec/vb.c +++ b/libavcodec/vb.c @@ -199,6 +199,9 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, uint32_t size; int offset = 0; + if (avpkt->size < 2) + return AVERROR_INVALIDDATA; + bytestream2_init(&c->stream, avpkt->data, avpkt->size); if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) diff --git a/libavcodec/vc1.c b/libavcodec/vc1.c index e7625070f..e102b931d 100644 --- a/libavcodec/vc1.c +++ b/libavcodec/vc1.c @@ -379,11 +379,6 @@ int ff_vc1_decode_sequence_header(AVCodecContext *avctx, VC1Context *v, GetBitCo } else { v->res_rtm_flag = get_bits1(gb); //reserved } - if (!v->res_rtm_flag) { - av_log(avctx, AV_LOG_ERROR, - "Old WMV3 version detected, some frames may be decoded incorrectly\n"); - //return -1; - } //TODO: figure out what they mean (always 0x402F) if (!v->res_fasttx) skip_bits(gb, 16); @@ -991,6 +986,7 @@ int ff_vc1_parse_frame_header_adv(VC1Context *v, GetBitContext* gb) v->pquantizer = 1; break; } + v->dquantfrm = 0; if (v->postprocflag) v->postproc = get_bits(gb, 2); @@ -1009,7 +1005,8 @@ int ff_vc1_parse_frame_header_adv(VC1Context *v, GetBitContext* gb) return -1; av_log(v->s.avctx, AV_LOG_DEBUG, "FIELDTX plane encoding: " "Imode: %i, Invert: %i\n", status>>1, status&1); - } + } else + v->fieldtx_is_raw = 0; status = bitplane_decoding(v->acpred_plane, &v->acpred_is_raw, v); if (status < 0) return -1; @@ -1055,6 +1052,8 @@ int ff_vc1_parse_frame_header_adv(VC1Context *v, GetBitContext* gb) v->last_use_ic = 1; } status = bitplane_decoding(v->s.mbskip_table, &v->skip_is_raw, v); + if (status < 0) + return -1; av_log(v->s.avctx, AV_LOG_DEBUG, "SKIPMB plane encoding: " "Imode: %i, Invert: %i\n", status>>1, status&1); v->mbmodetab = get_bits(gb, 2); @@ -1224,7 +1223,7 @@ int ff_vc1_parse_frame_header_adv(VC1Context *v, GetBitContext* gb) v->mv_mode = ff_vc1_mv_pmode_table2[lowquant][mvmode]; v->qs_last = v->s.quarter_sample; v->s.quarter_sample = (v->mv_mode == MV_PMODE_1MV || v->mv_mode == MV_PMODE_MIXED_MV); - v->s.mspel = !(v->mv_mode == MV_PMODE_1MV_HPEL_BILIN || v->mv_mode == MV_PMODE_1MV_HPEL); + v->s.mspel = (v->mv_mode != MV_PMODE_1MV_HPEL_BILIN); status = bitplane_decoding(v->forward_mb_plane, &v->fmb_is_raw, v); if (status < 0) return -1; diff --git a/libavcodec/vc1.h b/libavcodec/vc1.h index 8fc0729cb..69f6ca9e4 100644 --- a/libavcodec/vc1.h +++ b/libavcodec/vc1.h @@ -422,10 +422,12 @@ void ff_vc1_init_transposed_scantables(VC1Context *v); int ff_vc1_decode_end(AVCodecContext *avctx); void ff_vc1_decode_blocks(VC1Context *v); -void ff_vc1_loop_filter_iblk(VC1Context *v, int pq); -void ff_vc1_loop_filter_iblk_delayed(VC1Context *v, int pq); -void ff_vc1_smooth_overlap_filter_iblk(VC1Context *v); -void ff_vc1_apply_p_loop_filter(VC1Context *v); +void ff_vc1_i_overlap_filter(VC1Context *v); +void ff_vc1_p_overlap_filter(VC1Context *v); +void ff_vc1_i_loop_filter(VC1Context *v); +void ff_vc1_p_loop_filter(VC1Context *v); +void ff_vc1_p_intfr_loop_filter(VC1Context *v); +void ff_vc1_b_intfi_loop_filter(VC1Context *v); void ff_vc1_mc_1mv(VC1Context *v, int dir); void ff_vc1_mc_4mv_luma(VC1Context *v, int n, int dir, int avg); diff --git a/libavcodec/vc1_block.c b/libavcodec/vc1_block.c index b06ee9fce..514206f6d 100644 --- a/libavcodec/vc1_block.c +++ b/libavcodec/vc1_block.c @@ -45,6 +45,9 @@ static const uint8_t offset_table[2][9] = { { 0, 1, 3, 7, 15, 31, 63, 127, 255 }, }; +// mapping table for internal block representation +static const int block_map[6] = {0, 2, 1, 3, 4, 5}; + /***********************************************************************/ /** * @name VC-1 Bitplane decoding @@ -66,76 +69,97 @@ static inline void init_block_index(VC1Context *v) /** @} */ //Bitplane group -static void vc1_put_signed_blocks_clamped(VC1Context *v) +static void vc1_put_blocks_clamped(VC1Context *v, int put_signed) { MpegEncContext *s = &v->s; - int topleft_mb_pos, top_mb_pos; - int stride_y, fieldtx = 0; - int v_dist; + uint8_t *dest; + int block_count = CONFIG_GRAY && (s->avctx->flags & AV_CODEC_FLAG_GRAY) ? 4 : 6; + int fieldtx = 0; + int i; - /* The put pixels loop is always one MB row behind the decoding loop, - * because we can only put pixels when overlap filtering is done, and - * for filtering of the bottom edge of a MB, we need the next MB row - * present as well. - * Within the row, the put pixels loop is also one MB col behind the - * decoding loop. The reason for this is again, because for filtering - * of the right MB edge, we need the next MB present. */ - if (!s->first_slice_line) { + /* The put pixels loop is one MB row and one MB column behind the decoding + * loop because we can only put pixels when overlap filtering is done. For + * interlaced frame pictures, however, the put pixels loop is only one + * column behind the decoding loop as interlaced frame pictures only need + * horizontal overlap filtering. */ + if (!s->first_slice_line && v->fcm != ILACE_FRAME) { if (s->mb_x) { - topleft_mb_pos = (s->mb_y - 1) * s->mb_stride + s->mb_x - 1; - if (v->fcm == ILACE_FRAME) - fieldtx = v->fieldtx_plane[topleft_mb_pos]; - stride_y = s->linesize << fieldtx; - v_dist = (16 - fieldtx) >> (fieldtx == 0); - s->idsp.put_signed_pixels_clamped(v->block[v->topleft_blk_idx][0], - s->dest[0] - 16 * s->linesize - 16, - stride_y); - s->idsp.put_signed_pixels_clamped(v->block[v->topleft_blk_idx][1], - s->dest[0] - 16 * s->linesize - 8, - stride_y); - s->idsp.put_signed_pixels_clamped(v->block[v->topleft_blk_idx][2], - s->dest[0] - v_dist * s->linesize - 16, - stride_y); - s->idsp.put_signed_pixels_clamped(v->block[v->topleft_blk_idx][3], - s->dest[0] - v_dist * s->linesize - 8, - stride_y); - if (!CONFIG_GRAY || !(s->avctx->flags & AV_CODEC_FLAG_GRAY)) { - s->idsp.put_signed_pixels_clamped(v->block[v->topleft_blk_idx][4], - s->dest[1] - 8 * s->uvlinesize - 8, - s->uvlinesize); - s->idsp.put_signed_pixels_clamped(v->block[v->topleft_blk_idx][5], - s->dest[2] - 8 * s->uvlinesize - 8, - s->uvlinesize); + for (i = 0; i < block_count; i++) { + if (i > 3 ? v->mb_type[0][s->block_index[i] - s->block_wrap[i] - 1] : + v->mb_type[0][s->block_index[i] - 2 * s->block_wrap[i] - 2]) { + dest = s->dest[0] + ((i & 2) - 4) * 4 * s->linesize + ((i & 1) - 2) * 8; + if (put_signed) + s->idsp.put_signed_pixels_clamped(v->block[v->topleft_blk_idx][block_map[i]], + i > 3 ? s->dest[i - 3] - 8 * s->uvlinesize - 8 : dest, + i > 3 ? s->uvlinesize : s->linesize); + else + s->idsp.put_pixels_clamped(v->block[v->topleft_blk_idx][block_map[i]], + i > 3 ? s->dest[i - 3] - 8 * s->uvlinesize - 8 : dest, + i > 3 ? s->uvlinesize : s->linesize); + } } } - if (s->mb_x == s->mb_width - 1) { - top_mb_pos = (s->mb_y - 1) * s->mb_stride + s->mb_x; - if (v->fcm == ILACE_FRAME) - fieldtx = v->fieldtx_plane[top_mb_pos]; - stride_y = s->linesize << fieldtx; - v_dist = fieldtx ? 15 : 8; - s->idsp.put_signed_pixels_clamped(v->block[v->top_blk_idx][0], - s->dest[0] - 16 * s->linesize, - stride_y); - s->idsp.put_signed_pixels_clamped(v->block[v->top_blk_idx][1], - s->dest[0] - 16 * s->linesize + 8, - stride_y); - s->idsp.put_signed_pixels_clamped(v->block[v->top_blk_idx][2], - s->dest[0] - v_dist * s->linesize, - stride_y); - s->idsp.put_signed_pixels_clamped(v->block[v->top_blk_idx][3], - s->dest[0] - v_dist * s->linesize + 8, - stride_y); - if (!CONFIG_GRAY || !(s->avctx->flags & AV_CODEC_FLAG_GRAY)) { - s->idsp.put_signed_pixels_clamped(v->block[v->top_blk_idx][4], - s->dest[1] - 8 * s->uvlinesize, - s->uvlinesize); - s->idsp.put_signed_pixels_clamped(v->block[v->top_blk_idx][5], - s->dest[2] - 8 * s->uvlinesize, - s->uvlinesize); + if (s->mb_x == v->end_mb_x - 1) { + for (i = 0; i < block_count; i++) { + if (i > 3 ? v->mb_type[0][s->block_index[i] - s->block_wrap[i]] : + v->mb_type[0][s->block_index[i] - 2 * s->block_wrap[i]]) { + dest = s->dest[0] + ((i & 2) - 4) * 4 * s->linesize + (i & 1) * 8; + if (put_signed) + s->idsp.put_signed_pixels_clamped(v->block[v->top_blk_idx][block_map[i]], + i > 3 ? s->dest[i - 3] - 8 * s->uvlinesize : dest, + i > 3 ? s->uvlinesize : s->linesize); + else + s->idsp.put_pixels_clamped(v->block[v->top_blk_idx][block_map[i]], + i > 3 ? s->dest[i - 3] - 8 * s->uvlinesize : dest, + i > 3 ? s->uvlinesize : s->linesize); + } } } } + if (s->mb_y == s->end_mb_y - 1 || v->fcm == ILACE_FRAME) { + if (s->mb_x) { + if (v->fcm == ILACE_FRAME) + fieldtx = v->fieldtx_plane[s->mb_y * s->mb_stride + s->mb_x - 1]; + for (i = 0; i < block_count; i++) { + if (i > 3 ? v->mb_type[0][s->block_index[i] - 1] : + v->mb_type[0][s->block_index[i] - 2]) { + if (fieldtx) + dest = s->dest[0] + ((i & 2) >> 1) * s->linesize + ((i & 1) - 2) * 8; + else + dest = s->dest[0] + (i & 2) * 4 * s->linesize + ((i & 1) - 2) * 8; + if (put_signed) + s->idsp.put_signed_pixels_clamped(v->block[v->left_blk_idx][block_map[i]], + i > 3 ? s->dest[i - 3] - 8 : dest, + i > 3 ? s->uvlinesize : s->linesize << fieldtx); + else + s->idsp.put_pixels_clamped(v->block[v->left_blk_idx][block_map[i]], + i > 3 ? s->dest[i - 3] - 8 : dest, + i > 3 ? s->uvlinesize : s->linesize << fieldtx); + } + } + } + if (s->mb_x == v->end_mb_x - 1) { + if (v->fcm == ILACE_FRAME) + fieldtx = v->fieldtx_plane[s->mb_y * s->mb_stride + s->mb_x]; + for (i = 0; i < block_count; i++) { + if (v->mb_type[0][s->block_index[i]]) { + if (fieldtx) + dest = s->dest[0] + ((i & 2) >> 1) * s->linesize + (i & 1) * 8; + else + dest = s->dest[0] + (i & 2) * 4 * s->linesize + (i & 1) * 8; + if (put_signed) + s->idsp.put_signed_pixels_clamped(v->block[v->cur_blk_idx][block_map[i]], + i > 3 ? s->dest[i - 3] : dest, + i > 3 ? s->uvlinesize : s->linesize << fieldtx); + else + s->idsp.put_pixels_clamped(v->block[v->cur_blk_idx][block_map[i]], + i > 3 ? s->dest[i - 3] : dest, + i > 3 ? s->uvlinesize : s->linesize << fieldtx); + } + } + } + } +} #define inc_blk_idx(idx) do { \ idx++; \ @@ -143,12 +167,6 @@ static void vc1_put_signed_blocks_clamped(VC1Context *v) idx = 0; \ } while (0) - inc_blk_idx(v->topleft_blk_idx); - inc_blk_idx(v->top_blk_idx); - inc_blk_idx(v->left_blk_idx); - inc_blk_idx(v->cur_blk_idx); -} - /***********************************************************************/ /** * @name VC-1 Block-level functions @@ -165,13 +183,13 @@ static void vc1_put_signed_blocks_clamped(VC1Context *v) int edges = 0; \ if (v->dqprofile == DQPROFILE_ALL_MBS) { \ if (v->dqbilevel) { \ - mquant = (get_bits1(gb)) ? v->altpq : v->pq; \ + mquant = (get_bits1(gb)) ? -v->altpq : v->pq; \ } else { \ mqdiff = get_bits(gb, 3); \ if (mqdiff != 7) \ - mquant = v->pq + mqdiff; \ + mquant = -v->pq - mqdiff; \ else \ - mquant = get_bits(gb, 5); \ + mquant = -get_bits(gb, 5); \ } \ } \ if (v->dqprofile == DQPROFILE_SINGLE_EDGE) \ @@ -181,14 +199,15 @@ static void vc1_put_signed_blocks_clamped(VC1Context *v) else if (v->dqprofile == DQPROFILE_FOUR_EDGES) \ edges = 15; \ if ((edges&1) && !s->mb_x) \ - mquant = v->altpq; \ - if ((edges&2) && s->first_slice_line) \ - mquant = v->altpq; \ + mquant = -v->altpq; \ + if ((edges&2) && !s->mb_y) \ + mquant = -v->altpq; \ if ((edges&4) && s->mb_x == (s->mb_width - 1)) \ - mquant = v->altpq; \ - if ((edges&8) && s->mb_y == (s->mb_height - 1)) \ - mquant = v->altpq; \ - if (!mquant || mquant > 31) { \ + mquant = -v->altpq; \ + if ((edges&8) && \ + s->mb_y == ((s->mb_height >> v->field_mode) - 1)) \ + mquant = -v->altpq; \ + if (!mquant || mquant > 31 || mquant < -31) { \ av_log(v->s.avctx, AV_LOG_ERROR, \ "Overriding invalid mquant %d\n", mquant); \ mquant = 1; \ @@ -393,7 +412,7 @@ static inline int ff_vc1_pred_dc(MpegEncContext *s, int overlap, int pq, int n, int dqscale_index; /* scale predictors if needed */ - q1 = s->current_picture.qscale_table[mb_pos]; + q1 = FFABS(s->current_picture.qscale_table[mb_pos]); dqscale_index = s->y_dc_scale_table[q1] - 1; if (dqscale_index < 0) return 0; @@ -409,14 +428,14 @@ static inline int ff_vc1_pred_dc(MpegEncContext *s, int overlap, int pq, int n, a = dc_val[ - wrap]; if (c_avail && (n != 1 && n != 3)) { - q2 = s->current_picture.qscale_table[mb_pos - 1]; + q2 = FFABS(s->current_picture.qscale_table[mb_pos - 1]); if (q2 && q2 != q1) - c = (c * s->y_dc_scale_table[q2] * ff_vc1_dqscale[dqscale_index] + 0x20000) >> 18; + c = (int)((unsigned)c * s->y_dc_scale_table[q2] * ff_vc1_dqscale[dqscale_index] + 0x20000) >> 18; } if (a_avail && (n != 2 && n != 3)) { - q2 = s->current_picture.qscale_table[mb_pos - s->mb_stride]; + q2 = FFABS(s->current_picture.qscale_table[mb_pos - s->mb_stride]); if (q2 && q2 != q1) - a = (a * s->y_dc_scale_table[q2] * ff_vc1_dqscale[dqscale_index] + 0x20000) >> 18; + a = (int)((unsigned)a * s->y_dc_scale_table[q2] * ff_vc1_dqscale[dqscale_index] + 0x20000) >> 18; } if (a_avail && c_avail && (n != 3)) { int off = mb_pos; @@ -424,9 +443,9 @@ static inline int ff_vc1_pred_dc(MpegEncContext *s, int overlap, int pq, int n, off--; if (n != 2) off -= s->mb_stride; - q2 = s->current_picture.qscale_table[off]; + q2 = FFABS(s->current_picture.qscale_table[off]); if (q2 && q2 != q1) - b = (b * s->y_dc_scale_table[q2] * ff_vc1_dqscale[dqscale_index] + 0x20000) >> 18; + b = (int)((unsigned)b * s->y_dc_scale_table[q2] * ff_vc1_dqscale[dqscale_index] + 0x20000) >> 18; } if (c_avail && (!a_avail || abs(a - b) <= abs(b - c))) { @@ -489,13 +508,15 @@ static inline int vc1_coded_block_pred(MpegEncContext * s, int n, * @param codingset set of VLC to decode data * @see 8.1.3.4 */ -static void vc1_decode_ac_coeff(VC1Context *v, int *last, int *skip, +static int vc1_decode_ac_coeff(VC1Context *v, int *last, int *skip, int *value, int codingset) { GetBitContext *gb = &v->s.gb; int index, run, level, lst, sign; index = get_vlc2(gb, ff_vc1_ac_coeff_table[codingset].table, AC_VLC_BITS, 3); + if (index < 0) + return index; if (index != ff_vc1_ac_sizes[codingset] - 1) { run = vc1_index_decode_table[codingset][index][0]; level = vc1_index_decode_table[codingset][index][1]; @@ -505,6 +526,8 @@ static void vc1_decode_ac_coeff(VC1Context *v, int *last, int *skip, int escape = decode210(gb); if (escape != 2) { index = get_vlc2(gb, ff_vc1_ac_coeff_table[codingset].table, AC_VLC_BITS, 3); + if (index >= ff_vc1_ac_sizes[codingset] - 1U) + return AVERROR_INVALIDDATA; run = vc1_index_decode_table[codingset][index][0]; level = vc1_index_decode_table[codingset][index][1]; lst = index >= vc1_last_decode_table[codingset]; @@ -541,6 +564,8 @@ static void vc1_decode_ac_coeff(VC1Context *v, int *last, int *skip, *last = lst; *skip = run; *value = (level ^ -sign) + sign; + + return 0; } /** Decode intra block in intra frames - should be faster than decode_intra_block @@ -620,7 +645,9 @@ static int vc1_decode_i_block(VC1Context *v, int16_t block[64], int n, zz_table = v->zz_8x8[1]; while (!last) { - vc1_decode_ac_coeff(v, &last, &skip, &value, codingset); + int ret = vc1_decode_ac_coeff(v, &last, &skip, &value, codingset); + if (ret < 0) + return ret; i += skip; if (i > 63) break; @@ -705,6 +732,7 @@ static int vc1_decode_i_block_adv(VC1Context *v, int16_t block[64], int n, int scale; int q1, q2 = 0; int mb_pos = s->mb_x + s->mb_y * s->mb_stride; + int quant = FFABS(mquant); /* Get DC differential */ if (n < 4) { @@ -717,7 +745,7 @@ static int vc1_decode_i_block_adv(VC1Context *v, int16_t block[64], int n, return -1; } if (dcdiff) { - const int m = (mquant == 1 || mquant == 2) ? 3 - mquant : 0; + const int m = (quant == 1 || quant == 2) ? 3 - quant : 0; if (dcdiff == 119 /* ESC index value */) { dcdiff = get_bits(gb, 8 + m); } else { @@ -729,7 +757,7 @@ static int vc1_decode_i_block_adv(VC1Context *v, int16_t block[64], int n, } /* Prediction */ - dcdiff += ff_vc1_pred_dc(&v->s, v->overlap, mquant, n, v->a_avail, v->c_avail, &dc_val, &dc_pred_dir); + dcdiff += ff_vc1_pred_dc(&v->s, v->overlap, quant, n, v->a_avail, v->c_avail, &dc_val, &dc_pred_dir); *dc_val = dcdiff; /* Store the quantized DC coeff, used for prediction */ @@ -743,7 +771,7 @@ static int vc1_decode_i_block_adv(VC1Context *v, int16_t block[64], int n, if (!a_avail && !c_avail) use_pred = 0; - scale = mquant * 2 + ((mquant == v->pq) ? v->halfpq : 0); + scale = quant * 2 + ((mquant < 0) ? 0 : v->halfpq); ac_val = s->ac_val[0][s->block_index[n]]; ac_val2 = ac_val; @@ -792,7 +820,9 @@ static int vc1_decode_i_block_adv(VC1Context *v, int16_t block[64], int n, } while (!last) { - vc1_decode_ac_coeff(v, &last, &skip, &value, codingset); + int ret = vc1_decode_ac_coeff(v, &last, &skip, &value, codingset); + if (ret < 0) + return ret; i += skip; if (i > 63) break; @@ -809,11 +839,12 @@ static int vc1_decode_i_block_adv(VC1Context *v, int16_t block[64], int n, ac_val += 8; } /* scale predictors if needed*/ + q1 = FFABS(q1) * 2 + ((q1 < 0) ? 0 : v->halfpq) - 1; + if (q1 < 1) + return AVERROR_INVALIDDATA; + if (q2) + q2 = FFABS(q2) * 2 + ((q2 < 0) ? 0 : v->halfpq) - 1; if (q2 && q1 != q2) { - q1 = q1 * 2 + ((q1 == v->pq) ? v->halfpq : 0) - 1; - if (q1 < 1) - return AVERROR_INVALIDDATA; - q2 = q2 * 2 + ((q2 == v->pq) ? v->halfpq : 0) - 1; for (k = 1; k < 8; k++) block[k << sh] += (ac_val[k] * q2 * ff_vc1_dqscale[q1 - 1] + 0x20000) >> 18; } else { @@ -832,7 +863,7 @@ static int vc1_decode_i_block_adv(VC1Context *v, int16_t block[64], int n, if (block[k]) { block[k] *= scale; if (!v->pquantizer) - block[k] += (block[k] < 0) ? -mquant : mquant; + block[k] += (block[k] < 0) ? -quant : quant; } } else { // no AC coeffs @@ -851,18 +882,19 @@ static int vc1_decode_i_block_adv(VC1Context *v, int16_t block[64], int n, ac_val2 += 8; } memcpy(ac_val2, ac_val, 8 * 2); + q1 = FFABS(q1) * 2 + ((q1 < 0) ? 0 : v->halfpq) - 1; + if (q1 < 1) + return AVERROR_INVALIDDATA; + if (q2) + q2 = FFABS(q2) * 2 + ((q2 < 0) ? 0 : v->halfpq) - 1; if (q2 && q1 != q2) { - q1 = q1 * 2 + ((q1 == v->pq) ? v->halfpq : 0) - 1; - q2 = q2 * 2 + ((q2 == v->pq) ? v->halfpq : 0) - 1; - if (q1 < 1) - return AVERROR_INVALIDDATA; for (k = 1; k < 8; k++) ac_val2[k] = (ac_val2[k] * q2 * ff_vc1_dqscale[q1 - 1] + 0x20000) >> 18; } for (k = 1; k < 8; k++) { block[k << sh] = ac_val2[k] * scale; if (!v->pquantizer && block[k << sh]) - block[k << sh] += (block[k << sh] < 0) ? -mquant : mquant; + block[k << sh] += (block[k << sh] < 0) ? -quant : quant; } } } @@ -895,15 +927,16 @@ static int vc1_decode_intra_block(VC1Context *v, int16_t block[64], int n, int use_pred = s->ac_pred; int scale; int q1, q2 = 0; + int quant = FFABS(mquant); s->bdsp.clear_block(block); /* XXX: Guard against dumb values of mquant */ - mquant = av_clip_uintp2(mquant, 5); + quant = av_clip_uintp2(quant, 5); /* Set DC scale - y and c use the same */ - s->y_dc_scale = s->y_dc_scale_table[mquant]; - s->c_dc_scale = s->c_dc_scale_table[mquant]; + s->y_dc_scale = s->y_dc_scale_table[quant]; + s->c_dc_scale = s->c_dc_scale_table[quant]; /* Get DC differential */ if (n < 4) { @@ -916,7 +949,7 @@ static int vc1_decode_intra_block(VC1Context *v, int16_t block[64], int n, return -1; } if (dcdiff) { - const int m = (mquant == 1 || mquant == 2) ? 3 - mquant : 0; + const int m = (quant == 1 || quant == 2) ? 3 - quant : 0; if (dcdiff == 119 /* ESC index value */) { dcdiff = get_bits(gb, 8 + m); } else { @@ -928,7 +961,7 @@ static int vc1_decode_intra_block(VC1Context *v, int16_t block[64], int n, } /* Prediction */ - dcdiff += ff_vc1_pred_dc(&v->s, v->overlap, mquant, n, a_avail, c_avail, &dc_val, &dc_pred_dir); + dcdiff += ff_vc1_pred_dc(&v->s, v->overlap, quant, n, a_avail, c_avail, &dc_val, &dc_pred_dir); *dc_val = dcdiff; /* Store the quantized DC coeff, used for prediction */ @@ -949,7 +982,7 @@ static int vc1_decode_intra_block(VC1Context *v, int16_t block[64], int n, ac_val = s->ac_val[0][s->block_index[n]]; ac_val2 = ac_val; - scale = mquant * 2 + v->halfpq; + scale = quant * 2 + ((mquant < 0) ? 0 : v->halfpq); if (dc_pred_dir) //left ac_val -= 16; @@ -972,7 +1005,9 @@ static int vc1_decode_intra_block(VC1Context *v, int16_t block[64], int n, int k; while (!last) { - vc1_decode_ac_coeff(v, &last, &skip, &value, codingset); + int ret = vc1_decode_ac_coeff(v, &last, &skip, &value, codingset); + if (ret < 0) + return ret; i += skip; if (i > 63) break; @@ -993,12 +1028,12 @@ static int vc1_decode_intra_block(VC1Context *v, int16_t block[64], int n, /* apply AC prediction if needed */ if (use_pred) { /* scale predictors if needed*/ + q1 = FFABS(q1) * 2 + ((q1 < 0) ? 0 : v->halfpq) - 1; + if (q1 < 1) + return AVERROR_INVALIDDATA; + if (q2) + q2 = FFABS(q2) * 2 + ((q2 < 0) ? 0 : v->halfpq) - 1; if (q2 && q1 != q2) { - q1 = q1 * 2 + ((q1 == v->pq) ? v->halfpq : 0) - 1; - q2 = q2 * 2 + ((q2 == v->pq) ? v->halfpq : 0) - 1; - - if (q1 < 1) - return AVERROR_INVALIDDATA; if (dc_pred_dir) { // left for (k = 1; k < 8; k++) block[k << v->left_blk_sh] += (ac_val[k] * q2 * ff_vc1_dqscale[q1 - 1] + 0x20000) >> 18; @@ -1027,7 +1062,7 @@ static int vc1_decode_intra_block(VC1Context *v, int16_t block[64], int n, if (block[k]) { block[k] *= scale; if (!v->pquantizer) - block[k] += (block[k] < 0) ? -mquant : mquant; + block[k] += (block[k] < 0) ? -quant : quant; } if (use_pred) i = 63; @@ -1038,11 +1073,12 @@ static int vc1_decode_intra_block(VC1Context *v, int16_t block[64], int n, if (dc_pred_dir) { // left if (use_pred) { memcpy(ac_val2, ac_val, 8 * 2); + q1 = FFABS(q1) * 2 + ((q1 < 0) ? 0 : v->halfpq) - 1; + if (q1 < 1) + return AVERROR_INVALIDDATA; + if (q2) + q2 = FFABS(q2) * 2 + ((q2 < 0) ? 0 : v->halfpq) - 1; if (q2 && q1 != q2) { - q1 = q1 * 2 + ((q1 == v->pq) ? v->halfpq : 0) - 1; - q2 = q2 * 2 + ((q2 == v->pq) ? v->halfpq : 0) - 1; - if (q1 < 1) - return AVERROR_INVALIDDATA; for (k = 1; k < 8; k++) ac_val2[k] = (ac_val2[k] * q2 * ff_vc1_dqscale[q1 - 1] + 0x20000) >> 18; } @@ -1050,11 +1086,12 @@ static int vc1_decode_intra_block(VC1Context *v, int16_t block[64], int n, } else { // top if (use_pred) { memcpy(ac_val2 + 8, ac_val + 8, 8 * 2); + q1 = FFABS(q1) * 2 + ((q1 < 0) ? 0 : v->halfpq) - 1; + if (q1 < 1) + return AVERROR_INVALIDDATA; + if (q2) + q2 = FFABS(q2) * 2 + ((q2 < 0) ? 0 : v->halfpq) - 1; if (q2 && q1 != q2) { - q1 = q1 * 2 + ((q1 == v->pq) ? v->halfpq : 0) - 1; - q2 = q2 * 2 + ((q2 == v->pq) ? v->halfpq : 0) - 1; - if (q1 < 1) - return AVERROR_INVALIDDATA; for (k = 1; k < 8; k++) ac_val2[k + 8] = (ac_val2[k + 8] * q2 * ff_vc1_dqscale[q1 - 1] + 0x20000) >> 18; } @@ -1067,13 +1104,13 @@ static int vc1_decode_intra_block(VC1Context *v, int16_t block[64], int n, for (k = 1; k < 8; k++) { block[k << v->left_blk_sh] = ac_val2[k] * scale; if (!v->pquantizer && block[k << v->left_blk_sh]) - block[k << v->left_blk_sh] += (block[k << v->left_blk_sh] < 0) ? -mquant : mquant; + block[k << v->left_blk_sh] += (block[k << v->left_blk_sh] < 0) ? -quant : quant; } } else { // top for (k = 1; k < 8; k++) { block[k << v->top_blk_sh] = ac_val2[k + 8] * scale; if (!v->pquantizer && block[k << v->top_blk_sh]) - block[k << v->top_blk_sh] += (block[k << v->top_blk_sh] < 0) ? -mquant : mquant; + block[k << v->top_blk_sh] += (block[k << v->top_blk_sh] < 0) ? -quant : quant; } } i = 63; @@ -1098,6 +1135,7 @@ static int vc1_decode_p_block(VC1Context *v, int16_t block[64], int n, int scale, off, idx, last, skip, value; int ttblk = ttmb & 7; int pat = 0; + int quant = FFABS(mquant); s->bdsp.clear_block(block); @@ -1118,7 +1156,7 @@ static int vc1_decode_p_block(VC1Context *v, int16_t block[64], int n, if (ttblk == TT_4X8_RIGHT || ttblk == TT_4X8_LEFT) ttblk = TT_4X8; } - scale = 2 * mquant + ((v->pq == mquant) ? v->halfpq : 0); + scale = quant * 2 + ((mquant < 0) ? 0 : v->halfpq); // convert transforms like 8X4_TOP to generic TT and SUBBLKPAT if (ttblk == TT_8X4_TOP || ttblk == TT_8X4_BOTTOM) { @@ -1135,7 +1173,9 @@ static int vc1_decode_p_block(VC1Context *v, int16_t block[64], int n, i = 0; last = 0; while (!last) { - vc1_decode_ac_coeff(v, &last, &skip, &value, v->codingset2); + int ret = vc1_decode_ac_coeff(v, &last, &skip, &value, v->codingset2); + if (ret < 0) + return ret; i += skip; if (i > 63) break; @@ -1145,7 +1185,7 @@ static int vc1_decode_p_block(VC1Context *v, int16_t block[64], int n, idx = v->zzi_8x8[i++]; block[idx] = value * scale; if (!v->pquantizer) - block[idx] += (block[idx] < 0) ? -mquant : mquant; + block[idx] += (block[idx] < 0) ? -quant : quant; } if (!skip_block) { if (i == 1) @@ -1163,7 +1203,9 @@ static int vc1_decode_p_block(VC1Context *v, int16_t block[64], int n, i = 0; off = (j & 1) * 4 + (j & 2) * 16; while (!last) { - vc1_decode_ac_coeff(v, &last, &skip, &value, v->codingset2); + int ret = vc1_decode_ac_coeff(v, &last, &skip, &value, v->codingset2); + if (ret < 0) + return ret; i += skip; if (i > 15) break; @@ -1173,7 +1215,7 @@ static int vc1_decode_p_block(VC1Context *v, int16_t block[64], int n, idx = ff_vc1_adv_interlaced_4x4_zz[i++]; block[idx + off] = value * scale; if (!v->pquantizer) - block[idx + off] += (block[idx + off] < 0) ? -mquant : mquant; + block[idx + off] += (block[idx + off] < 0) ? -quant : quant; } if (!(subblkpat & (1 << (3 - j))) && !skip_block) { if (i == 1) @@ -1190,7 +1232,9 @@ static int vc1_decode_p_block(VC1Context *v, int16_t block[64], int n, i = 0; off = j * 32; while (!last) { - vc1_decode_ac_coeff(v, &last, &skip, &value, v->codingset2); + int ret = vc1_decode_ac_coeff(v, &last, &skip, &value, v->codingset2); + if (ret < 0) + return ret; i += skip; if (i > 31) break; @@ -1200,7 +1244,7 @@ static int vc1_decode_p_block(VC1Context *v, int16_t block[64], int n, idx = ff_vc1_adv_interlaced_8x4_zz[i++] + off; block[idx] = value * scale; if (!v->pquantizer) - block[idx] += (block[idx] < 0) ? -mquant : mquant; + block[idx] += (block[idx] < 0) ? -quant : quant; } if (!(subblkpat & (1 << (1 - j))) && !skip_block) { if (i == 1) @@ -1217,7 +1261,9 @@ static int vc1_decode_p_block(VC1Context *v, int16_t block[64], int n, i = 0; off = j * 4; while (!last) { - vc1_decode_ac_coeff(v, &last, &skip, &value, v->codingset2); + int ret = vc1_decode_ac_coeff(v, &last, &skip, &value, v->codingset2); + if (ret < 0) + return ret; i += skip; if (i > 31) break; @@ -1227,7 +1273,7 @@ static int vc1_decode_p_block(VC1Context *v, int16_t block[64], int n, idx = ff_vc1_adv_interlaced_4x8_zz[i++] + off; block[idx] = value * scale; if (!v->pquantizer) - block[idx] += (block[idx] < 0) ? -mquant : mquant; + block[idx] += (block[idx] < 0) ? -quant : quant; } if (!(subblkpat & (1 << (1 - j))) && !skip_block) { if (i == 1) @@ -1325,30 +1371,22 @@ static int vc1_decode_p_mb(VC1Context *v) if (i == 1 || i == 3 || s->mb_x) v->c_avail = v->mb_type[0][s->block_index[i] - 1]; - vc1_decode_intra_block(v, s->block[i], i, val, mquant, + vc1_decode_intra_block(v, v->block[v->cur_blk_idx][block_map[i]], i, val, mquant, (i & 4) ? v->codingset2 : v->codingset); if (CONFIG_GRAY && (i > 3) && (s->avctx->flags & AV_CODEC_FLAG_GRAY)) continue; - v->vc1dsp.vc1_inv_trans_8x8(s->block[i]); + v->vc1dsp.vc1_inv_trans_8x8(v->block[v->cur_blk_idx][block_map[i]]); if (v->rangeredfrm) for (j = 0; j < 64; j++) - s->block[i][j] <<= 1; - s->idsp.put_signed_pixels_clamped(s->block[i], - s->dest[dst_idx] + off, - i & 4 ? s->uvlinesize - : s->linesize); - if (v->pq >= 9 && v->overlap) { - if (v->c_avail) - v->vc1dsp.vc1_h_overlap(s->dest[dst_idx] + off, i & 4 ? s->uvlinesize : s->linesize); - if (v->a_avail) - v->vc1dsp.vc1_v_overlap(s->dest[dst_idx] + off, i & 4 ? s->uvlinesize : s->linesize); - } + v->block[v->cur_blk_idx][block_map[i]][j] *= 2; block_cbp |= 0xF << (i << 2); block_intra |= 1 << i; } else if (val) { - pat = vc1_decode_p_block(v, s->block[i], i, mquant, ttmb, first_block, + pat = vc1_decode_p_block(v, v->block[v->cur_blk_idx][block_map[i]], i, mquant, ttmb, first_block, s->dest[dst_idx] + off, (i & 4) ? s->uvlinesize : s->linesize, CONFIG_GRAY && (i & 4) && (s->avctx->flags & AV_CODEC_FLAG_GRAY), &block_tt); + if (pat < 0) + return pat; block_cbp |= pat << (i << 2); if (!v->ttmbf && ttmb < 8) ttmb = -1; @@ -1436,32 +1474,24 @@ static int vc1_decode_p_mb(VC1Context *v) if (i == 1 || i == 3 || s->mb_x) v->c_avail = v->mb_type[0][s->block_index[i] - 1]; - vc1_decode_intra_block(v, s->block[i], i, is_coded[i], mquant, + vc1_decode_intra_block(v, v->block[v->cur_blk_idx][block_map[i]], i, is_coded[i], mquant, (i & 4) ? v->codingset2 : v->codingset); if (CONFIG_GRAY && (i > 3) && (s->avctx->flags & AV_CODEC_FLAG_GRAY)) continue; - v->vc1dsp.vc1_inv_trans_8x8(s->block[i]); + v->vc1dsp.vc1_inv_trans_8x8(v->block[v->cur_blk_idx][block_map[i]]); if (v->rangeredfrm) for (j = 0; j < 64; j++) - s->block[i][j] <<= 1; - s->idsp.put_signed_pixels_clamped(s->block[i], - s->dest[dst_idx] + off, - (i & 4) ? s->uvlinesize - : s->linesize); - if (v->pq >= 9 && v->overlap) { - if (v->c_avail) - v->vc1dsp.vc1_h_overlap(s->dest[dst_idx] + off, i & 4 ? s->uvlinesize : s->linesize); - if (v->a_avail) - v->vc1dsp.vc1_v_overlap(s->dest[dst_idx] + off, i & 4 ? s->uvlinesize : s->linesize); - } + v->block[v->cur_blk_idx][block_map[i]][j] <<= 1; block_cbp |= 0xF << (i << 2); block_intra |= 1 << i; } else if (is_coded[i]) { - pat = vc1_decode_p_block(v, s->block[i], i, mquant, ttmb, + pat = vc1_decode_p_block(v, v->block[v->cur_blk_idx][block_map[i]], i, mquant, ttmb, first_block, s->dest[dst_idx] + off, (i & 4) ? s->uvlinesize : s->linesize, CONFIG_GRAY && (i & 4) && (s->avctx->flags & AV_CODEC_FLAG_GRAY), &block_tt); + if (pat < 0) + return pat; block_cbp |= pat << (i << 2); if (!v->ttmbf && ttmb < 8) ttmb = -1; @@ -1484,6 +1514,10 @@ static int vc1_decode_p_mb(VC1Context *v) } } end: + if (v->overlap && v->pq >= 9) + ff_vc1_p_overlap_filter(v); + vc1_put_blocks_clamped(v, 1); + v->cbp[s->mb_x] = block_cbp; v->ttblk[s->mb_x] = block_tt; v->is_intra[s->mb_x] = block_intra; @@ -1511,7 +1545,7 @@ static int vc1_decode_p_mb_intfr(VC1Context *v) int skipped, fourmv = 0, twomv = 0; int block_cbp = 0, pat, block_tt = 0; int idx_mbmode = 0, mvbp; - int stride_y, fieldtx; + int fieldtx; mquant = v->pq; /* Lossy initialization */ @@ -1570,8 +1604,8 @@ static int vc1_decode_p_mb_intfr(VC1Context *v) GET_MQUANT(); s->current_picture.qscale_table[mb_pos] = mquant; /* Set DC scale - y and c use the same (not sure if necessary here) */ - s->y_dc_scale = s->y_dc_scale_table[mquant]; - s->c_dc_scale = s->c_dc_scale_table[mquant]; + s->y_dc_scale = s->y_dc_scale_table[FFABS(mquant)]; + s->c_dc_scale = s->c_dc_scale_table[FFABS(mquant)]; dst_idx = 0; for (i = 0; i < 6; i++) { v->a_avail = v->c_avail = 0; @@ -1584,22 +1618,16 @@ static int vc1_decode_p_mb_intfr(VC1Context *v) if (i == 1 || i == 3 || s->mb_x) v->c_avail = v->mb_type[0][s->block_index[i] - 1]; - vc1_decode_intra_block(v, s->block[i], i, val, mquant, + vc1_decode_intra_block(v, v->block[v->cur_blk_idx][block_map[i]], i, val, mquant, (i & 4) ? v->codingset2 : v->codingset); if (CONFIG_GRAY && (i > 3) && (s->avctx->flags & AV_CODEC_FLAG_GRAY)) continue; - v->vc1dsp.vc1_inv_trans_8x8(s->block[i]); - if (i < 4) { - stride_y = s->linesize << fieldtx; + v->vc1dsp.vc1_inv_trans_8x8(v->block[v->cur_blk_idx][block_map[i]]); + if (i < 4) off = (fieldtx) ? ((i & 1) * 8) + ((i & 2) >> 1) * s->linesize : (i & 1) * 8 + 4 * (i & 2) * s->linesize; - } else { - stride_y = s->uvlinesize; + else off = 0; - } - s->idsp.put_signed_pixels_clamped(s->block[i], - s->dest[dst_idx] + off, - stride_y); - //TODO: loop filter + block_cbp |= 0xf << (i << 2); } } else { // inter MB @@ -1670,10 +1698,12 @@ static int vc1_decode_p_mb_intfr(VC1Context *v) else off = (i & 4) ? 0 : ((i & 1) * 8 + ((i > 1) * s->linesize)); if (val) { - pat = vc1_decode_p_block(v, s->block[i], i, mquant, ttmb, + pat = vc1_decode_p_block(v, v->block[v->cur_blk_idx][block_map[i]], i, mquant, ttmb, first_block, s->dest[dst_idx] + off, (i & 4) ? s->uvlinesize : (s->linesize << fieldtx), CONFIG_GRAY && (i & 4) && (s->avctx->flags & AV_CODEC_FLAG_GRAY), &block_tt); + if (pat < 0) + return pat; block_cbp |= pat << (i << 2); if (!v->ttmbf && ttmb < 8) ttmb = -1; @@ -1695,9 +1725,15 @@ static int vc1_decode_p_mb_intfr(VC1Context *v) v->blk_mv_type[s->block_index[3]] = 0; ff_vc1_pred_mv_intfr(v, 0, 0, 0, 1, v->range_x, v->range_y, v->mb_type[0], 0); ff_vc1_mc_1mv(v, 0); + v->fieldtx_plane[mb_pos] = 0; } - if (s->mb_x == s->mb_width - 1) - memmove(v->is_intra_base, v->is_intra, sizeof(v->is_intra_base[0])*s->mb_stride); + if (v->overlap && v->pq >= 9) + ff_vc1_p_overlap_filter(v); + vc1_put_blocks_clamped(v, 1); + + v->cbp[s->mb_x] = block_cbp; + v->ttblk[s->mb_x] = block_tt; + return 0; } @@ -1732,8 +1768,8 @@ static int vc1_decode_p_mb_intfi(VC1Context *v) GET_MQUANT(); s->current_picture.qscale_table[mb_pos] = mquant; /* Set DC scale - y and c use the same (not sure if necessary here) */ - s->y_dc_scale = s->y_dc_scale_table[mquant]; - s->c_dc_scale = s->c_dc_scale_table[mquant]; + s->y_dc_scale = s->y_dc_scale_table[FFABS(mquant)]; + s->c_dc_scale = s->c_dc_scale_table[FFABS(mquant)]; v->s.ac_pred = v->acpred_plane[mb_pos] = get_bits1(gb); mb_has_coeffs = idx_mbmode & 1; if (mb_has_coeffs) @@ -1750,17 +1786,13 @@ static int vc1_decode_p_mb_intfi(VC1Context *v) if (i == 1 || i == 3 || s->mb_x) v->c_avail = v->mb_type[0][s->block_index[i] - 1]; - vc1_decode_intra_block(v, s->block[i], i, val, mquant, + vc1_decode_intra_block(v, v->block[v->cur_blk_idx][block_map[i]], i, val, mquant, (i & 4) ? v->codingset2 : v->codingset); if (CONFIG_GRAY && (i > 3) && (s->avctx->flags & AV_CODEC_FLAG_GRAY)) continue; - v->vc1dsp.vc1_inv_trans_8x8(s->block[i]); + v->vc1dsp.vc1_inv_trans_8x8(v->block[v->cur_blk_idx][block_map[i]]); off = (i & 4) ? 0 : ((i & 1) * 8 + (i & 2) * 4 * s->linesize); - s->idsp.put_signed_pixels_clamped(s->block[i], - s->dest[dst_idx] + off, - (i & 4) ? s->uvlinesize - : s->linesize); - // TODO: loop filter + block_cbp |= 0xf << (i << 2); } } else { s->mb_intra = v->is_intra[s->mb_x] = 0; @@ -1803,11 +1835,13 @@ static int vc1_decode_p_mb_intfi(VC1Context *v) val = ((cbp >> (5 - i)) & 1); off = (i & 4) ? 0 : (i & 1) * 8 + (i & 2) * 4 * s->linesize; if (val) { - pat = vc1_decode_p_block(v, s->block[i], i, mquant, ttmb, + pat = vc1_decode_p_block(v, v->block[v->cur_blk_idx][block_map[i]], i, mquant, ttmb, first_block, s->dest[dst_idx] + off, (i & 4) ? s->uvlinesize : s->linesize, CONFIG_GRAY && (i & 4) && (s->avctx->flags & AV_CODEC_FLAG_GRAY), &block_tt); + if (pat < 0) + return pat; block_cbp |= pat << (i << 2); if (!v->ttmbf && ttmb < 8) ttmb = -1; @@ -1815,14 +1849,19 @@ static int vc1_decode_p_mb_intfi(VC1Context *v) } } } - if (s->mb_x == s->mb_width - 1) - memmove(v->is_intra_base, v->is_intra, sizeof(v->is_intra_base[0]) * s->mb_stride); + if (v->overlap && v->pq >= 9) + ff_vc1_p_overlap_filter(v); + vc1_put_blocks_clamped(v, 1); + + v->cbp[s->mb_x] = block_cbp; + v->ttblk[s->mb_x] = block_tt; + return 0; } /** Decode one B-frame MB (in Main profile) */ -static void vc1_decode_b_mb(VC1Context *v) +static int vc1_decode_b_mb(VC1Context *v) { MpegEncContext *s = &v->s; GetBitContext *gb = &s->gb; @@ -1888,7 +1927,7 @@ static void vc1_decode_b_mb(VC1Context *v) bmvtype = BMV_TYPE_INTERPOLATED; ff_vc1_pred_b_mv(v, dmv_x, dmv_y, direct, bmvtype); vc1_b_mc(v, dmv_x, dmv_y, direct, bmvtype); - return; + return 0; } if (direct) { cbp = get_vlc2(&v->s.gb, v->cbpcy_vlc->table, VC1_CBPCY_P_VLC_BITS, 2); @@ -1905,7 +1944,7 @@ static void vc1_decode_b_mb(VC1Context *v) /* no coded blocks - effectively skipped */ ff_vc1_pred_b_mv(v, dmv_x, dmv_y, direct, bmvtype); vc1_b_mc(v, dmv_x, dmv_y, direct, bmvtype); - return; + return 0; } if (s->mb_intra && !mb_has_coeffs) { GET_MQUANT(); @@ -1920,7 +1959,7 @@ static void vc1_decode_b_mb(VC1Context *v) /* interpolated skipped block */ ff_vc1_pred_b_mv(v, dmv_x, dmv_y, direct, bmvtype); vc1_b_mc(v, dmv_x, dmv_y, direct, bmvtype); - return; + return 0; } } ff_vc1_pred_b_mv(v, dmv_x, dmv_y, direct, bmvtype); @@ -1964,20 +2003,23 @@ static void vc1_decode_b_mb(VC1Context *v) i & 4 ? s->uvlinesize : s->linesize); } else if (val) { - vc1_decode_p_block(v, s->block[i], i, mquant, ttmb, - first_block, s->dest[dst_idx] + off, - (i & 4) ? s->uvlinesize : s->linesize, - CONFIG_GRAY && (i & 4) && (s->avctx->flags & AV_CODEC_FLAG_GRAY), NULL); + int pat = vc1_decode_p_block(v, s->block[i], i, mquant, ttmb, + first_block, s->dest[dst_idx] + off, + (i & 4) ? s->uvlinesize : s->linesize, + CONFIG_GRAY && (i & 4) && (s->avctx->flags & AV_CODEC_FLAG_GRAY), NULL); + if (pat < 0) + return pat; if (!v->ttmbf && ttmb < 8) ttmb = -1; first_block = 0; } } + return 0; } /** Decode one B-frame MB (in interlaced field B picture) */ -static void vc1_decode_b_mb_intfi(VC1Context *v) +static int vc1_decode_b_mb_intfi(VC1Context *v) { MpegEncContext *s = &v->s; GetBitContext *gb = &s->gb; @@ -1993,6 +2035,7 @@ static void vc1_decode_b_mb_intfi(VC1Context *v) int fwd; int dmv_x[2], dmv_y[2], pred_flag[2]; int bmvtype = BMV_TYPE_BACKWARD; + int block_cbp = 0, pat, block_tt = 0; int idx_mbmode; mquant = v->pq; /* Lossy initialization */ @@ -2008,8 +2051,8 @@ static void vc1_decode_b_mb_intfi(VC1Context *v) GET_MQUANT(); s->current_picture.qscale_table[mb_pos] = mquant; /* Set DC scale - y and c use the same (not sure if necessary here) */ - s->y_dc_scale = s->y_dc_scale_table[mquant]; - s->c_dc_scale = s->c_dc_scale_table[mquant]; + s->y_dc_scale = s->y_dc_scale_table[FFABS(mquant)]; + s->c_dc_scale = s->c_dc_scale_table[FFABS(mquant)]; v->s.ac_pred = v->acpred_plane[mb_pos] = get_bits1(gb); mb_has_coeffs = idx_mbmode & 1; if (mb_has_coeffs) @@ -2039,7 +2082,6 @@ static void vc1_decode_b_mb_intfi(VC1Context *v) s->dest[dst_idx] + off, (i & 4) ? s->uvlinesize : s->linesize); - // TODO: yet to perform loop filter } } else { s->mb_intra = v->is_intra[s->mb_x] = 0; @@ -2082,7 +2124,7 @@ static void vc1_decode_b_mb_intfi(VC1Context *v) dmv_x[1] = dmv_y[1] = pred_flag[0] = 0; if (!s->next_picture_ptr->field_picture) { av_log(s->avctx, AV_LOG_ERROR, "Mixed field/frame direct mode not supported\n"); - return; + return AVERROR_INVALIDDATA; } } ff_vc1_pred_b_mv_intfi(v, 0, dmv_x, dmv_y, 1, pred_flag); @@ -2123,16 +2165,23 @@ static void vc1_decode_b_mb_intfi(VC1Context *v) val = ((cbp >> (5 - i)) & 1); off = (i & 4) ? 0 : (i & 1) * 8 + (i & 2) * 4 * s->linesize; if (val) { - vc1_decode_p_block(v, s->block[i], i, mquant, ttmb, - first_block, s->dest[dst_idx] + off, - (i & 4) ? s->uvlinesize : s->linesize, - CONFIG_GRAY && (i & 4) && (s->avctx->flags & AV_CODEC_FLAG_GRAY), NULL); + pat = vc1_decode_p_block(v, s->block[i], i, mquant, ttmb, + first_block, s->dest[dst_idx] + off, + (i & 4) ? s->uvlinesize : s->linesize, + CONFIG_GRAY && (i & 4) && (s->avctx->flags & AV_CODEC_FLAG_GRAY), &block_tt); + if (pat < 0) + return pat; + block_cbp |= pat << (i << 2); if (!v->ttmbf && ttmb < 8) ttmb = -1; first_block = 0; } } } + v->cbp[s->mb_x] = block_cbp; + v->ttblk[s->mb_x] = block_tt; + + return 0; } /** Decode one B-frame MB (in interlaced frame B picture) @@ -2182,41 +2231,6 @@ static int vc1_decode_b_mb_intfr(VC1Context *v) } } - if (v->dmb_is_raw) - direct = get_bits1(gb); - else - direct = v->direct_mb_plane[mb_pos]; - - if (direct) { - if (s->next_picture_ptr->field_picture) - av_log(s->avctx, AV_LOG_WARNING, "Mixed frame/field direct mode not supported\n"); - s->mv[0][0][0] = s->current_picture.motion_val[0][s->block_index[0]][0] = scale_mv(s->next_picture.motion_val[1][s->block_index[0]][0], v->bfraction, 0, s->quarter_sample); - s->mv[0][0][1] = s->current_picture.motion_val[0][s->block_index[0]][1] = scale_mv(s->next_picture.motion_val[1][s->block_index[0]][1], v->bfraction, 0, s->quarter_sample); - s->mv[1][0][0] = s->current_picture.motion_val[1][s->block_index[0]][0] = scale_mv(s->next_picture.motion_val[1][s->block_index[0]][0], v->bfraction, 1, s->quarter_sample); - s->mv[1][0][1] = s->current_picture.motion_val[1][s->block_index[0]][1] = scale_mv(s->next_picture.motion_val[1][s->block_index[0]][1], v->bfraction, 1, s->quarter_sample); - - if (twomv) { - s->mv[0][2][0] = s->current_picture.motion_val[0][s->block_index[2]][0] = scale_mv(s->next_picture.motion_val[1][s->block_index[2]][0], v->bfraction, 0, s->quarter_sample); - s->mv[0][2][1] = s->current_picture.motion_val[0][s->block_index[2]][1] = scale_mv(s->next_picture.motion_val[1][s->block_index[2]][1], v->bfraction, 0, s->quarter_sample); - s->mv[1][2][0] = s->current_picture.motion_val[1][s->block_index[2]][0] = scale_mv(s->next_picture.motion_val[1][s->block_index[2]][0], v->bfraction, 1, s->quarter_sample); - s->mv[1][2][1] = s->current_picture.motion_val[1][s->block_index[2]][1] = scale_mv(s->next_picture.motion_val[1][s->block_index[2]][1], v->bfraction, 1, s->quarter_sample); - - for (i = 1; i < 4; i += 2) { - s->mv[0][i][0] = s->current_picture.motion_val[0][s->block_index[i]][0] = s->mv[0][i-1][0]; - s->mv[0][i][1] = s->current_picture.motion_val[0][s->block_index[i]][1] = s->mv[0][i-1][1]; - s->mv[1][i][0] = s->current_picture.motion_val[1][s->block_index[i]][0] = s->mv[1][i-1][0]; - s->mv[1][i][1] = s->current_picture.motion_val[1][s->block_index[i]][1] = s->mv[1][i-1][1]; - } - } else { - for (i = 1; i < 4; i++) { - s->mv[0][i][0] = s->current_picture.motion_val[0][s->block_index[i]][0] = s->mv[0][0][0]; - s->mv[0][i][1] = s->current_picture.motion_val[0][s->block_index[i]][1] = s->mv[0][0][1]; - s->mv[1][i][0] = s->current_picture.motion_val[1][s->block_index[i]][0] = s->mv[1][0][0]; - s->mv[1][i][1] = s->current_picture.motion_val[1][s->block_index[i]][1] = s->mv[1][0][1]; - } - } - } - if (ff_vc1_mbmode_intfrp[0][idx_mbmode][0] == MV_PMODE_INTFR_INTRA) { // intra MB for (i = 0; i < 4; i++) { s->mv[0][i][0] = s->current_picture.motion_val[0][s->block_index[i]][0] = 0; @@ -2235,8 +2249,8 @@ static int vc1_decode_b_mb_intfr(VC1Context *v) GET_MQUANT(); s->current_picture.qscale_table[mb_pos] = mquant; /* Set DC scale - y and c use the same (not sure if necessary here) */ - s->y_dc_scale = s->y_dc_scale_table[mquant]; - s->c_dc_scale = s->c_dc_scale_table[mquant]; + s->y_dc_scale = s->y_dc_scale_table[FFABS(mquant)]; + s->c_dc_scale = s->c_dc_scale_table[FFABS(mquant)]; dst_idx = 0; for (i = 0; i < 6; i++) { v->a_avail = v->c_avail = 0; @@ -2267,6 +2281,42 @@ static int vc1_decode_b_mb_intfr(VC1Context *v) } } else { s->mb_intra = v->is_intra[s->mb_x] = 0; + + if (v->dmb_is_raw) + direct = get_bits1(gb); + else + direct = v->direct_mb_plane[mb_pos]; + + if (direct) { + if (s->next_picture_ptr->field_picture) + av_log(s->avctx, AV_LOG_WARNING, "Mixed frame/field direct mode not supported\n"); + s->mv[0][0][0] = s->current_picture.motion_val[0][s->block_index[0]][0] = scale_mv(s->next_picture.motion_val[1][s->block_index[0]][0], v->bfraction, 0, s->quarter_sample); + s->mv[0][0][1] = s->current_picture.motion_val[0][s->block_index[0]][1] = scale_mv(s->next_picture.motion_val[1][s->block_index[0]][1], v->bfraction, 0, s->quarter_sample); + s->mv[1][0][0] = s->current_picture.motion_val[1][s->block_index[0]][0] = scale_mv(s->next_picture.motion_val[1][s->block_index[0]][0], v->bfraction, 1, s->quarter_sample); + s->mv[1][0][1] = s->current_picture.motion_val[1][s->block_index[0]][1] = scale_mv(s->next_picture.motion_val[1][s->block_index[0]][1], v->bfraction, 1, s->quarter_sample); + + if (twomv) { + s->mv[0][2][0] = s->current_picture.motion_val[0][s->block_index[2]][0] = scale_mv(s->next_picture.motion_val[1][s->block_index[2]][0], v->bfraction, 0, s->quarter_sample); + s->mv[0][2][1] = s->current_picture.motion_val[0][s->block_index[2]][1] = scale_mv(s->next_picture.motion_val[1][s->block_index[2]][1], v->bfraction, 0, s->quarter_sample); + s->mv[1][2][0] = s->current_picture.motion_val[1][s->block_index[2]][0] = scale_mv(s->next_picture.motion_val[1][s->block_index[2]][0], v->bfraction, 1, s->quarter_sample); + s->mv[1][2][1] = s->current_picture.motion_val[1][s->block_index[2]][1] = scale_mv(s->next_picture.motion_val[1][s->block_index[2]][1], v->bfraction, 1, s->quarter_sample); + + for (i = 1; i < 4; i += 2) { + s->mv[0][i][0] = s->current_picture.motion_val[0][s->block_index[i]][0] = s->mv[0][i-1][0]; + s->mv[0][i][1] = s->current_picture.motion_val[0][s->block_index[i]][1] = s->mv[0][i-1][1]; + s->mv[1][i][0] = s->current_picture.motion_val[1][s->block_index[i]][0] = s->mv[1][i-1][0]; + s->mv[1][i][1] = s->current_picture.motion_val[1][s->block_index[i]][1] = s->mv[1][i-1][1]; + } + } else { + for (i = 1; i < 4; i++) { + s->mv[0][i][0] = s->current_picture.motion_val[0][s->block_index[i]][0] = s->mv[0][0][0]; + s->mv[0][i][1] = s->current_picture.motion_val[0][s->block_index[i]][1] = s->mv[0][0][1]; + s->mv[1][i][0] = s->current_picture.motion_val[1][s->block_index[i]][0] = s->mv[1][0][0]; + s->mv[1][i][1] = s->current_picture.motion_val[1][s->block_index[i]][1] = s->mv[1][0][1]; + } + } + } + if (!direct) { if (skipped || !s->mb_intra) { bmvtype = decode012(gb); @@ -2418,6 +2468,8 @@ static int vc1_decode_b_mb_intfr(VC1Context *v) first_block, s->dest[dst_idx] + off, (i & 4) ? s->uvlinesize : (s->linesize << fieldtx), CONFIG_GRAY && (i & 4) && (s->avctx->flags & AV_CODEC_FLAG_GRAY), &block_tt); + if (pat < 0) + return pat; block_cbp |= pat << (i << 2); if (!v->ttmbf && ttmb < 8) ttmb = -1; @@ -2473,12 +2525,12 @@ static int vc1_decode_b_mb_intfr(VC1Context *v) if (direct || bmvtype == BMV_TYPE_INTERPOLATED) { ff_vc1_interp_mc(v); } + v->fieldtx_plane[mb_pos] = 0; } } - if (s->mb_x == s->mb_width - 1) - memmove(v->is_intra_base, v->is_intra, sizeof(v->is_intra_base[0]) * s->mb_stride); v->cbp[s->mb_x] = block_cbp; v->ttblk[s->mb_x] = block_tt; + return 0; } @@ -2525,30 +2577,27 @@ static void vc1_decode_i_blocks(VC1Context *v) s->mb_x = s->mb_y = 0; s->mb_intra = 1; s->first_slice_line = 1; - for (s->mb_y = 0; s->mb_y < s->end_mb_y; s->mb_y++) { + for (s->mb_y = s->start_mb_y; s->mb_y < s->end_mb_y; s->mb_y++) { s->mb_x = 0; init_block_index(v); for (; s->mb_x < v->end_mb_x; s->mb_x++) { - uint8_t *dst[6]; ff_update_block_index(s); - dst[0] = s->dest[0]; - dst[1] = dst[0] + 8; - dst[2] = s->dest[0] + s->linesize * 8; - dst[3] = dst[2] + 8; - dst[4] = s->dest[1]; - dst[5] = s->dest[2]; - s->bdsp.clear_blocks(s->block[0]); + s->bdsp.clear_blocks(v->block[v->cur_blk_idx][0]); mb_pos = s->mb_x + s->mb_y * s->mb_width; s->current_picture.mb_type[mb_pos] = MB_TYPE_INTRA; s->current_picture.qscale_table[mb_pos] = v->pq; - s->current_picture.motion_val[1][s->block_index[0]][0] = 0; - s->current_picture.motion_val[1][s->block_index[0]][1] = 0; + for (int i = 0; i < 4; i++) { + s->current_picture.motion_val[1][s->block_index[i]][0] = 0; + s->current_picture.motion_val[1][s->block_index[i]][1] = 0; + } // do actual MB decoding and displaying cbp = get_vlc2(&v->s.gb, ff_msmp4_mb_i_vlc.table, MB_INTRA_VLC_BITS, 2); v->s.ac_pred = get_bits1(&v->s.gb); for (k = 0; k < 6; k++) { + v->mb_type[0][s->block_index[k]] = 1; + val = ((cbp >> (5 - k)) & 1); if (k < 4) { @@ -2558,52 +2607,30 @@ static void vc1_decode_i_blocks(VC1Context *v) } cbp |= val << (5 - k); - vc1_decode_i_block(v, s->block[k], k, val, (k < 4) ? v->codingset : v->codingset2); + vc1_decode_i_block(v, v->block[v->cur_blk_idx][block_map[k]], k, val, (k < 4) ? v->codingset : v->codingset2); if (CONFIG_GRAY && k > 3 && (s->avctx->flags & AV_CODEC_FLAG_GRAY)) continue; - v->vc1dsp.vc1_inv_trans_8x8(s->block[k]); - if (v->pq >= 9 && v->overlap) { - if (v->rangeredfrm) - for (j = 0; j < 64; j++) - s->block[k][j] <<= 1; - s->idsp.put_signed_pixels_clamped(s->block[k], dst[k], - k & 4 ? s->uvlinesize - : s->linesize); - } else { - if (v->rangeredfrm) - for (j = 0; j < 64; j++) - s->block[k][j] = (s->block[k][j] - 64) << 1; - s->idsp.put_pixels_clamped(s->block[k], dst[k], - k & 4 ? s->uvlinesize - : s->linesize); - } + v->vc1dsp.vc1_inv_trans_8x8(v->block[v->cur_blk_idx][block_map[k]]); } - if (v->pq >= 9 && v->overlap) { - if (s->mb_x) { - v->vc1dsp.vc1_h_overlap(s->dest[0], s->linesize); - v->vc1dsp.vc1_h_overlap(s->dest[0] + 8 * s->linesize, s->linesize); - if (!CONFIG_GRAY || !(s->avctx->flags & AV_CODEC_FLAG_GRAY)) { - v->vc1dsp.vc1_h_overlap(s->dest[1], s->uvlinesize); - v->vc1dsp.vc1_h_overlap(s->dest[2], s->uvlinesize); - } - } - v->vc1dsp.vc1_h_overlap(s->dest[0] + 8, s->linesize); - v->vc1dsp.vc1_h_overlap(s->dest[0] + 8 * s->linesize + 8, s->linesize); - if (!s->first_slice_line) { - v->vc1dsp.vc1_v_overlap(s->dest[0], s->linesize); - v->vc1dsp.vc1_v_overlap(s->dest[0] + 8, s->linesize); - if (!CONFIG_GRAY || !(s->avctx->flags & AV_CODEC_FLAG_GRAY)) { - v->vc1dsp.vc1_v_overlap(s->dest[1], s->uvlinesize); - v->vc1dsp.vc1_v_overlap(s->dest[2], s->uvlinesize); - } - } - v->vc1dsp.vc1_v_overlap(s->dest[0] + 8 * s->linesize, s->linesize); - v->vc1dsp.vc1_v_overlap(s->dest[0] + 8 * s->linesize + 8, s->linesize); + if (v->overlap && v->pq >= 9) { + ff_vc1_i_overlap_filter(v); + if (v->rangeredfrm) + for (k = 0; k < 6; k++) + for (j = 0; j < 64; j++) + v->block[v->cur_blk_idx][block_map[k]][j] *= 2; + vc1_put_blocks_clamped(v, 1); + } else { + if (v->rangeredfrm) + for (k = 0; k < 6; k++) + for (j = 0; j < 64; j++) + v->block[v->cur_blk_idx][block_map[k]][j] = (v->block[v->cur_blk_idx][block_map[k]][j] - 64) * 2; + vc1_put_blocks_clamped(v, 0); } + if (v->s.loop_filter) - ff_vc1_loop_filter_iblk(v, v->pq); + ff_vc1_i_loop_filter(v); if (get_bits_count(&s->gb) > v->bits) { ff_er_add_slice(&s->er, 0, 0, s->mb_x, s->mb_y, ER_MB_ERROR); @@ -2611,6 +2638,11 @@ static void vc1_decode_i_blocks(VC1Context *v) get_bits_count(&s->gb), v->bits); return; } + + v->topleft_blk_idx = (v->topleft_blk_idx + 1) % (v->end_mb_x + 2); + v->top_blk_idx = (v->top_blk_idx + 1) % (v->end_mb_x + 2); + v->left_blk_idx = (v->left_blk_idx + 1) % (v->end_mb_x + 2); + v->cur_blk_idx = (v->cur_blk_idx + 1) % (v->end_mb_x + 2); } if (!v->s.loop_filter) ff_mpeg_draw_horiz_band(s, s->mb_y * 16, 16); @@ -2636,7 +2668,7 @@ static void vc1_decode_i_blocks_adv(VC1Context *v) int cbp, val; uint8_t *coded_val; int mb_pos; - int mquant = v->pq; + int mquant; int mqdiff; GetBitContext *gb = &s->gb; @@ -2680,13 +2712,15 @@ static void vc1_decode_i_blocks_adv(VC1Context *v) s->mb_x = 0; init_block_index(v); for (;s->mb_x < s->mb_width; s->mb_x++) { - int16_t (*block)[64] = v->block[v->cur_blk_idx]; + mquant = v->pq; ff_update_block_index(s); - s->bdsp.clear_blocks(block[0]); + s->bdsp.clear_blocks(v->block[v->cur_blk_idx][0]); mb_pos = s->mb_x + s->mb_y * s->mb_stride; s->current_picture.mb_type[mb_pos + v->mb_off] = MB_TYPE_INTRA; - s->current_picture.motion_val[1][s->block_index[0] + v->blocks_off][0] = 0; - s->current_picture.motion_val[1][s->block_index[0] + v->blocks_off][1] = 0; + for (int i = 0; i < 4; i++) { + s->current_picture.motion_val[1][s->block_index[i] + v->blocks_off][0] = 0; + s->current_picture.motion_val[1][s->block_index[i] + v->blocks_off][1] = 0; + } // do actual MB decoding and displaying if (v->fieldtx_is_raw) @@ -2704,10 +2738,12 @@ static void vc1_decode_i_blocks_adv(VC1Context *v) s->current_picture.qscale_table[mb_pos] = mquant; /* Set DC scale - y and c use the same */ - s->y_dc_scale = s->y_dc_scale_table[mquant]; - s->c_dc_scale = s->c_dc_scale_table[mquant]; + s->y_dc_scale = s->y_dc_scale_table[FFABS(mquant)]; + s->c_dc_scale = s->c_dc_scale_table[FFABS(mquant)]; for (k = 0; k < 6; k++) { + v->mb_type[0][s->block_index[k]] = 1; + val = ((cbp >> (5 - k)) & 1); if (k < 4) { @@ -2720,18 +2756,19 @@ static void vc1_decode_i_blocks_adv(VC1Context *v) v->a_avail = !s->first_slice_line || (k == 2 || k == 3); v->c_avail = !!s->mb_x || (k == 1 || k == 3); - vc1_decode_i_block_adv(v, block[k], k, val, + vc1_decode_i_block_adv(v, v->block[v->cur_blk_idx][block_map[k]], k, val, (k < 4) ? v->codingset : v->codingset2, mquant); if (CONFIG_GRAY && k > 3 && (s->avctx->flags & AV_CODEC_FLAG_GRAY)) continue; - v->vc1dsp.vc1_inv_trans_8x8(block[k]); + v->vc1dsp.vc1_inv_trans_8x8(v->block[v->cur_blk_idx][block_map[k]]); } - ff_vc1_smooth_overlap_filter_iblk(v); - vc1_put_signed_blocks_clamped(v); + if (v->overlap && (v->pq >= 9 || v->condover != CONDOVER_NONE)) + ff_vc1_i_overlap_filter(v); + vc1_put_blocks_clamped(v, 1); if (v->s.loop_filter) - ff_vc1_loop_filter_iblk_delayed(v, v->pq); + ff_vc1_i_loop_filter(v); if (get_bits_count(&s->gb) > v->bits) { // TODO: may need modification to handle slice coding @@ -2740,6 +2777,10 @@ static void vc1_decode_i_blocks_adv(VC1Context *v) get_bits_count(&s->gb), v->bits); return; } + inc_blk_idx(v->topleft_blk_idx); + inc_blk_idx(v->top_blk_idx); + inc_blk_idx(v->left_blk_idx); + inc_blk_idx(v->cur_blk_idx); } if (!v->s.loop_filter) ff_mpeg_draw_horiz_band(s, s->mb_y * 16, 16); @@ -2748,15 +2789,6 @@ static void vc1_decode_i_blocks_adv(VC1Context *v) s->first_slice_line = 0; } - /* raw bottom MB row */ - s->mb_x = 0; - init_block_index(v); - for (; s->mb_x < s->mb_width; s->mb_x++) { - ff_update_block_index(s); - vc1_put_signed_blocks_clamped(v); - if (v->s.loop_filter) - ff_vc1_loop_filter_iblk_delayed(v, v->pq); - } if (v->s.loop_filter) ff_mpeg_draw_horiz_band(s, (s->end_mb_y - 1) * 16, 16); ff_er_add_slice(&s->er, 0, s->start_mb_y << v->field_mode, s->mb_width - 1, @@ -2793,23 +2825,28 @@ static void vc1_decode_p_blocks(VC1Context *v) break; } - apply_loop_filter = s->loop_filter && !(s->avctx->skip_loop_filter >= AVDISCARD_NONKEY) && - v->fcm == PROGRESSIVE; + apply_loop_filter = s->loop_filter && !(s->avctx->skip_loop_filter >= AVDISCARD_NONKEY); s->first_slice_line = 1; - memset(v->cbp_base, 0, sizeof(v->cbp_base[0])*2*s->mb_stride); + memset(v->cbp_base, 0, sizeof(v->cbp_base[0]) * 3 * s->mb_stride); for (s->mb_y = s->start_mb_y; s->mb_y < s->end_mb_y; s->mb_y++) { s->mb_x = 0; init_block_index(v); for (; s->mb_x < s->mb_width; s->mb_x++) { ff_update_block_index(s); - if (v->fcm == ILACE_FIELD) + if (v->fcm == ILACE_FIELD) { vc1_decode_p_mb_intfi(v); - else if (v->fcm == ILACE_FRAME) + if (apply_loop_filter) + ff_vc1_p_loop_filter(v); + } else if (v->fcm == ILACE_FRAME) { vc1_decode_p_mb_intfr(v); - else vc1_decode_p_mb(v); - if (s->mb_y != s->start_mb_y && apply_loop_filter) - ff_vc1_apply_p_loop_filter(v); + if (apply_loop_filter) + ff_vc1_p_intfr_loop_filter(v); + } else { + vc1_decode_p_mb(v); + if (apply_loop_filter) + ff_vc1_p_loop_filter(v); + } if (get_bits_count(&s->gb) > v->bits || get_bits_count(&s->gb) < 0) { // TODO: may need modification to handle slice coding ff_er_add_slice(&s->er, 0, s->start_mb_y, s->mb_x, s->mb_y, ER_MB_ERROR); @@ -2817,23 +2854,27 @@ static void vc1_decode_p_blocks(VC1Context *v) get_bits_count(&s->gb), v->bits, s->mb_x, s->mb_y); return; } + inc_blk_idx(v->topleft_blk_idx); + inc_blk_idx(v->top_blk_idx); + inc_blk_idx(v->left_blk_idx); + inc_blk_idx(v->cur_blk_idx); } - memmove(v->cbp_base, v->cbp, sizeof(v->cbp_base[0]) * s->mb_stride); - memmove(v->ttblk_base, v->ttblk, sizeof(v->ttblk_base[0]) * s->mb_stride); - memmove(v->is_intra_base, v->is_intra, sizeof(v->is_intra_base[0]) * s->mb_stride); - memmove(v->luma_mv_base, v->luma_mv, sizeof(v->luma_mv_base[0]) * s->mb_stride); + memmove(v->cbp_base, + v->cbp - s->mb_stride, + sizeof(v->cbp_base[0]) * 2 * s->mb_stride); + memmove(v->ttblk_base, + v->ttblk - s->mb_stride, + sizeof(v->ttblk_base[0]) * 2 * s->mb_stride); + memmove(v->is_intra_base, + v->is_intra - s->mb_stride, + sizeof(v->is_intra_base[0]) * 2 * s->mb_stride); + memmove(v->luma_mv_base, + v->luma_mv - s->mb_stride, + sizeof(v->luma_mv_base[0]) * 2 * s->mb_stride); if (s->mb_y != s->start_mb_y) ff_mpeg_draw_horiz_band(s, (s->mb_y - 1) * 16, 16); s->first_slice_line = 0; } - if (apply_loop_filter) { - s->mb_x = 0; - init_block_index(v); - for (; s->mb_x < s->mb_width; s->mb_x++) { - ff_update_block_index(s); - ff_vc1_apply_p_loop_filter(v); - } - } if (s->end_mb_y >= s->start_mb_y) ff_mpeg_draw_horiz_band(s, (s->end_mb_y - 1) * 16, 16); ff_er_add_slice(&s->er, 0, s->start_mb_y << v->field_mode, s->mb_width - 1, @@ -2876,12 +2917,19 @@ static void vc1_decode_b_blocks(VC1Context *v) for (; s->mb_x < s->mb_width; s->mb_x++) { ff_update_block_index(s); - if (v->fcm == ILACE_FIELD) + if (v->fcm == ILACE_FIELD) { vc1_decode_b_mb_intfi(v); - else if (v->fcm == ILACE_FRAME) + if (v->s.loop_filter) + ff_vc1_b_intfi_loop_filter(v); + } else if (v->fcm == ILACE_FRAME) { vc1_decode_b_mb_intfr(v); - else + if (v->s.loop_filter) + ff_vc1_p_intfr_loop_filter(v); + } else { vc1_decode_b_mb(v); + if (v->s.loop_filter) + ff_vc1_i_loop_filter(v); + } if (get_bits_count(&s->gb) > v->bits || get_bits_count(&s->gb) < 0) { // TODO: may need modification to handle slice coding ff_er_add_slice(&s->er, 0, s->start_mb_y, s->mb_x, s->mb_y, ER_MB_ERROR); @@ -2889,9 +2937,16 @@ static void vc1_decode_b_blocks(VC1Context *v) get_bits_count(&s->gb), v->bits, s->mb_x, s->mb_y); return; } - if (v->s.loop_filter) - ff_vc1_loop_filter_iblk(v, v->pq); } + memmove(v->cbp_base, + v->cbp - s->mb_stride, + sizeof(v->cbp_base[0]) * 2 * s->mb_stride); + memmove(v->ttblk_base, + v->ttblk - s->mb_stride, + sizeof(v->ttblk_base[0]) * 2 * s->mb_stride); + memmove(v->is_intra_base, + v->is_intra - s->mb_stride, + sizeof(v->is_intra_base[0]) * 2 * s->mb_stride); if (!v->s.loop_filter) ff_mpeg_draw_horiz_band(s, s->mb_y * 16, 16); else if (s->mb_y) diff --git a/libavcodec/vc1_loopfilter.c b/libavcodec/vc1_loopfilter.c index 025776bac..0f990ccce 100644 --- a/libavcodec/vc1_loopfilter.c +++ b/libavcodec/vc1_loopfilter.c @@ -31,329 +31,1211 @@ #include "vc1.h" #include "vc1dsp.h" -void ff_vc1_loop_filter_iblk(VC1Context *v, int pq) +static av_always_inline void vc1_h_overlap_filter(VC1Context *v, int16_t (*left_block)[64], + int16_t (*right_block)[64], int left_fieldtx, + int right_fieldtx, int block_num) { - MpegEncContext *s = &v->s; - int j; - if (!s->first_slice_line) { - v->vc1dsp.vc1_v_loop_filter16(s->dest[0], s->linesize, pq); - if (s->mb_x) - v->vc1dsp.vc1_h_loop_filter16(s->dest[0] - 16 * s->linesize, s->linesize, pq); - v->vc1dsp.vc1_h_loop_filter16(s->dest[0] - 16 * s->linesize + 8, s->linesize, pq); - if (!CONFIG_GRAY || !(s->avctx->flags & AV_CODEC_FLAG_GRAY)) - for (j = 0; j < 2; j++) { - v->vc1dsp.vc1_v_loop_filter8(s->dest[j + 1], s->uvlinesize, pq); - if (s->mb_x) - v->vc1dsp.vc1_h_loop_filter8(s->dest[j + 1] - 8 * s->uvlinesize, s->uvlinesize, pq); - } - } - v->vc1dsp.vc1_v_loop_filter16(s->dest[0] + 8 * s->linesize, s->linesize, pq); + switch (block_num) { + case 0: + v->vc1dsp.vc1_h_s_overlap(left_block[2], + right_block[0], + left_fieldtx ^ right_fieldtx ? 16 - 8 * left_fieldtx : 8, + left_fieldtx ^ right_fieldtx ? 16 - 8 * right_fieldtx : 8, + left_fieldtx || right_fieldtx ? 0 : 1); + break; - if (s->mb_y == s->end_mb_y - 1) { - if (s->mb_x) { - v->vc1dsp.vc1_h_loop_filter16(s->dest[0], s->linesize, pq); - if (!CONFIG_GRAY || !(s->avctx->flags & AV_CODEC_FLAG_GRAY)) { - v->vc1dsp.vc1_h_loop_filter8(s->dest[1], s->uvlinesize, pq); - v->vc1dsp.vc1_h_loop_filter8(s->dest[2], s->uvlinesize, pq); - } - } - v->vc1dsp.vc1_h_loop_filter16(s->dest[0] + 8, s->linesize, pq); + case 1: + v->vc1dsp.vc1_h_s_overlap(right_block[0], + right_block[2], + 8, + 8, + right_fieldtx ? 0 : 1); + break; + + case 2: + v->vc1dsp.vc1_h_s_overlap(!left_fieldtx && right_fieldtx ? left_block[2] + 8 : left_block[3], + left_fieldtx && !right_fieldtx ? right_block[0] + 8 : right_block[1], + left_fieldtx ^ right_fieldtx ? 16 - 8 * left_fieldtx : 8, + left_fieldtx ^ right_fieldtx ? 16 - 8 * right_fieldtx : 8, + left_fieldtx || right_fieldtx ? 2 : 1); + break; + + case 3: + v->vc1dsp.vc1_h_s_overlap(right_block[1], + right_block[3], + 8, + 8, + right_fieldtx ? 2 : 1); + break; + + case 4: + case 5: + v->vc1dsp.vc1_h_s_overlap(left_block[block_num], right_block[block_num], 8, 8, 1); + break; } } -void ff_vc1_loop_filter_iblk_delayed(VC1Context *v, int pq) +static av_always_inline void vc1_v_overlap_filter(VC1Context *v, int16_t (*top_block)[64], + int16_t (*bottom_block)[64], int block_num) { - MpegEncContext *s = &v->s; - int j; + switch (block_num) { + case 0: + v->vc1dsp.vc1_v_s_overlap(top_block[1], bottom_block[0]); + break; - /* The loopfilter runs 1 row and 1 column behind the overlap filter, which - * means it runs two rows/cols behind the decoding loop. */ - if (!s->first_slice_line) { - if (s->mb_x) { - if (s->mb_y >= s->start_mb_y + 2) { - v->vc1dsp.vc1_v_loop_filter16(s->dest[0] - 16 * s->linesize - 16, s->linesize, pq); + case 1: + v->vc1dsp.vc1_v_s_overlap(top_block[3], bottom_block[2]); + break; - if (s->mb_x >= 2) - v->vc1dsp.vc1_h_loop_filter16(s->dest[0] - 32 * s->linesize - 16, s->linesize, pq); - v->vc1dsp.vc1_h_loop_filter16(s->dest[0] - 32 * s->linesize - 8, s->linesize, pq); - if (!CONFIG_GRAY || !(s->avctx->flags & AV_CODEC_FLAG_GRAY)) - for (j = 0; j < 2; j++) { - v->vc1dsp.vc1_v_loop_filter8(s->dest[j + 1] - 8 * s->uvlinesize - 8, s->uvlinesize, pq); - if (s->mb_x >= 2) { - v->vc1dsp.vc1_h_loop_filter8(s->dest[j + 1] - 16 * s->uvlinesize - 8, s->uvlinesize, pq); - } - } - } - v->vc1dsp.vc1_v_loop_filter16(s->dest[0] - 8 * s->linesize - 16, s->linesize, pq); - } + case 2: + v->vc1dsp.vc1_v_s_overlap(bottom_block[0], bottom_block[1]); + break; - if (s->mb_x == s->mb_width - 1) { - if (s->mb_y >= s->start_mb_y + 2) { - v->vc1dsp.vc1_v_loop_filter16(s->dest[0] - 16 * s->linesize, s->linesize, pq); + case 3: + v->vc1dsp.vc1_v_s_overlap(bottom_block[2], bottom_block[3]); + break; - if (s->mb_x) - v->vc1dsp.vc1_h_loop_filter16(s->dest[0] - 32 * s->linesize, s->linesize, pq); - v->vc1dsp.vc1_h_loop_filter16(s->dest[0] - 32 * s->linesize + 8, s->linesize, pq); - if (!CONFIG_GRAY || !(s->avctx->flags & AV_CODEC_FLAG_GRAY)) - for (j = 0; j < 2; j++) { - v->vc1dsp.vc1_v_loop_filter8(s->dest[j + 1] - 8 * s->uvlinesize, s->uvlinesize, pq); - if (s->mb_x >= 2) { - v->vc1dsp.vc1_h_loop_filter8(s->dest[j + 1] - 16 * s->uvlinesize, s->uvlinesize, pq); - } - } - } - v->vc1dsp.vc1_v_loop_filter16(s->dest[0] - 8 * s->linesize, s->linesize, pq); - } - - if (s->mb_y == s->end_mb_y) { - if (s->mb_x) { - if (s->mb_x >= 2) - v->vc1dsp.vc1_h_loop_filter16(s->dest[0] - 16 * s->linesize - 16, s->linesize, pq); - v->vc1dsp.vc1_h_loop_filter16(s->dest[0] - 16 * s->linesize - 8, s->linesize, pq); - if (s->mb_x >= 2 && (!CONFIG_GRAY || !(s->avctx->flags & AV_CODEC_FLAG_GRAY))) { - for (j = 0; j < 2; j++) { - v->vc1dsp.vc1_h_loop_filter8(s->dest[j + 1] - 8 * s->uvlinesize - 8, s->uvlinesize, pq); - } - } - } - - if (s->mb_x == s->mb_width - 1) { - if (s->mb_x) - v->vc1dsp.vc1_h_loop_filter16(s->dest[0] - 16 * s->linesize, s->linesize, pq); - v->vc1dsp.vc1_h_loop_filter16(s->dest[0] - 16 * s->linesize + 8, s->linesize, pq); - if (s->mb_x && (!CONFIG_GRAY || !(s->avctx->flags & AV_CODEC_FLAG_GRAY))) { - for (j = 0; j < 2; j++) { - v->vc1dsp.vc1_h_loop_filter8(s->dest[j + 1] - 8 * s->uvlinesize, s->uvlinesize, pq); - } - } - } - } + case 4: + case 5: + v->vc1dsp.vc1_v_s_overlap(top_block[block_num], bottom_block[block_num]); + break; } } -void ff_vc1_smooth_overlap_filter_iblk(VC1Context *v) +void ff_vc1_i_overlap_filter(VC1Context *v) { MpegEncContext *s = &v->s; - int mb_pos; + int16_t (*topleft_blk)[64], (*top_blk)[64], (*left_blk)[64], (*cur_blk)[64]; + int block_count = CONFIG_GRAY && (s->avctx->flags & AV_CODEC_FLAG_GRAY) ? 4 : 6; + int mb_pos = s->mb_x + s->mb_y * s->mb_stride; + int i; - if (v->condover == CONDOVER_NONE) - return; - - mb_pos = s->mb_x + s->mb_y * s->mb_stride; + topleft_blk = v->block[v->topleft_blk_idx]; + top_blk = v->block[v->top_blk_idx]; + left_blk = v->block[v->left_blk_idx]; + cur_blk = v->block[v->cur_blk_idx]; /* Within a MB, the horizontal overlap always runs before the vertical. - * To accomplish that, we run the H on left and internal borders of the - * currently decoded MB. Then, we wait for the next overlap iteration - * to do H overlap on the right edge of this MB, before moving over and - * running the V overlap. Therefore, the V overlap makes us trail by one - * MB col and the H overlap filter makes us trail by one MB row. This - * is reflected in the time at which we run the put_pixels loop. */ - if (v->condover == CONDOVER_ALL || v->pq >= 9 || v->over_flags_plane[mb_pos]) { - if (s->mb_x && (v->condover == CONDOVER_ALL || v->pq >= 9 || - v->over_flags_plane[mb_pos - 1])) { - v->vc1dsp.vc1_h_s_overlap(v->block[v->left_blk_idx][1], - v->block[v->cur_blk_idx][0]); - v->vc1dsp.vc1_h_s_overlap(v->block[v->left_blk_idx][3], - v->block[v->cur_blk_idx][2]); - if (!CONFIG_GRAY || !(s->avctx->flags & AV_CODEC_FLAG_GRAY)) { - v->vc1dsp.vc1_h_s_overlap(v->block[v->left_blk_idx][4], - v->block[v->cur_blk_idx][4]); - v->vc1dsp.vc1_h_s_overlap(v->block[v->left_blk_idx][5], - v->block[v->cur_blk_idx][5]); - } - } - v->vc1dsp.vc1_h_s_overlap(v->block[v->cur_blk_idx][0], - v->block[v->cur_blk_idx][1]); - v->vc1dsp.vc1_h_s_overlap(v->block[v->cur_blk_idx][2], - v->block[v->cur_blk_idx][3]); + * To accomplish that, we run the H on the left and internal vertical + * borders of the currently decoded MB. Then, we wait for the next overlap + * iteration to do H overlap on the right edge of this MB, before moving + * over and running the V overlap on the top and internal horizontal + * borders. Therefore, the H overlap trails by one MB col and the + * V overlap trails by one MB row. This is reflected in the time at which + * we run the put_pixels loop, i.e. delayed by one row and one column. */ + for (i = 0; i < block_count; i++) { + if (s->mb_x == 0 && (i & 5) != 1) + continue; - if (s->mb_x == s->mb_width - 1) { - if (!s->first_slice_line && (v->condover == CONDOVER_ALL || v->pq >= 9 || - v->over_flags_plane[mb_pos - s->mb_stride])) { - v->vc1dsp.vc1_v_s_overlap(v->block[v->top_blk_idx][2], - v->block[v->cur_blk_idx][0]); - v->vc1dsp.vc1_v_s_overlap(v->block[v->top_blk_idx][3], - v->block[v->cur_blk_idx][1]); - if (!CONFIG_GRAY || !(s->avctx->flags & AV_CODEC_FLAG_GRAY)) { - v->vc1dsp.vc1_v_s_overlap(v->block[v->top_blk_idx][4], - v->block[v->cur_blk_idx][4]); - v->vc1dsp.vc1_v_s_overlap(v->block[v->top_blk_idx][5], - v->block[v->cur_blk_idx][5]); - } - } - v->vc1dsp.vc1_v_s_overlap(v->block[v->cur_blk_idx][0], - v->block[v->cur_blk_idx][2]); - v->vc1dsp.vc1_v_s_overlap(v->block[v->cur_blk_idx][1], - v->block[v->cur_blk_idx][3]); - } + if (v->pq >= 9 || (v->profile == PROFILE_ADVANCED && + (v->condover == CONDOVER_ALL || + (v->over_flags_plane[mb_pos] && + ((i & 5) == 1 || v->over_flags_plane[mb_pos - 1]))))) + vc1_h_overlap_filter(v, + s->mb_x ? left_blk : cur_blk, cur_blk, + v->fcm == ILACE_FRAME && s->mb_x && v->fieldtx_plane[mb_pos - 1], + v->fcm == ILACE_FRAME && v->fieldtx_plane[mb_pos], + i); } - if (s->mb_x && (v->condover == CONDOVER_ALL || v->over_flags_plane[mb_pos - 1])) { - if (!s->first_slice_line && (v->condover == CONDOVER_ALL || v->pq >= 9 || - v->over_flags_plane[mb_pos - s->mb_stride - 1])) { - v->vc1dsp.vc1_v_s_overlap(v->block[v->topleft_blk_idx][2], - v->block[v->left_blk_idx][0]); - v->vc1dsp.vc1_v_s_overlap(v->block[v->topleft_blk_idx][3], - v->block[v->left_blk_idx][1]); - if (!CONFIG_GRAY || !(s->avctx->flags & AV_CODEC_FLAG_GRAY)) { - v->vc1dsp.vc1_v_s_overlap(v->block[v->topleft_blk_idx][4], - v->block[v->left_blk_idx][4]); - v->vc1dsp.vc1_v_s_overlap(v->block[v->topleft_blk_idx][5], - v->block[v->left_blk_idx][5]); - } + + if (v->fcm != ILACE_FRAME) + for (i = 0; i < block_count; i++) { + if (s->first_slice_line && !(i & 2)) + continue; + + if (s->mb_x && + (v->pq >= 9 || (v->profile == PROFILE_ADVANCED && + (v->condover == CONDOVER_ALL || + (v->over_flags_plane[mb_pos - 1] && + ((i & 2) || v->over_flags_plane[mb_pos - 1 - s->mb_stride])))))) + vc1_v_overlap_filter(v, s->first_slice_line ? left_blk : topleft_blk, left_blk, i); + if (s->mb_x == s->mb_width - 1 && + (v->pq >= 9 || (v->profile == PROFILE_ADVANCED && + (v->condover == CONDOVER_ALL || + (v->over_flags_plane[mb_pos] && + ((i & 2) || v->over_flags_plane[mb_pos - s->mb_stride])))))) + vc1_v_overlap_filter(v, s->first_slice_line ? cur_blk : top_blk, cur_blk, i); } - v->vc1dsp.vc1_v_s_overlap(v->block[v->left_blk_idx][0], - v->block[v->left_blk_idx][2]); - v->vc1dsp.vc1_v_s_overlap(v->block[v->left_blk_idx][1], - v->block[v->left_blk_idx][3]); - } } -static av_always_inline void vc1_apply_p_v_loop_filter(VC1Context *v, int block_num) -{ - MpegEncContext *s = &v->s; - int mb_cbp = v->cbp[s->mb_x - s->mb_stride], - block_cbp = mb_cbp >> (block_num * 4), bottom_cbp, - mb_is_intra = v->is_intra[s->mb_x - s->mb_stride], - block_is_intra = mb_is_intra >> block_num, bottom_is_intra; - int idx, linesize = block_num > 3 ? s->uvlinesize : s->linesize, ttblk; - uint8_t *dst; - - if (block_num > 3) { - dst = s->dest[block_num - 3]; - } else { - dst = s->dest[0] + (block_num & 1) * 8 + ((block_num & 2) * 4 - 8) * linesize; - } - if (s->mb_y != s->end_mb_y || block_num < 2) { - int16_t (*mv)[2]; - int mv_stride; - - if (block_num > 3) { - bottom_cbp = v->cbp[s->mb_x] >> (block_num * 4); - bottom_is_intra = v->is_intra[s->mb_x] >> block_num; - mv = &v->luma_mv[s->mb_x - s->mb_stride]; - mv_stride = s->mb_stride; - } else { - bottom_cbp = (block_num < 2) ? (mb_cbp >> ((block_num + 2) * 4)) - : (v->cbp[s->mb_x] >> ((block_num - 2) * 4)); - bottom_is_intra = (block_num < 2) ? (mb_is_intra >> (block_num + 2)) - : (v->is_intra[s->mb_x] >> (block_num - 2)); - mv_stride = s->b8_stride; - mv = &s->current_picture.motion_val[0][s->block_index[block_num] - 2 * mv_stride]; - } - - if (bottom_is_intra & 1 || block_is_intra & 1 || - mv[0][0] != mv[mv_stride][0] || mv[0][1] != mv[mv_stride][1]) { - v->vc1dsp.vc1_v_loop_filter8(dst, linesize, v->pq); - } else { - idx = ((bottom_cbp >> 2) | block_cbp) & 3; - if (idx == 3) { - v->vc1dsp.vc1_v_loop_filter8(dst, linesize, v->pq); - } else if (idx) { - if (idx == 1) - v->vc1dsp.vc1_v_loop_filter4(dst + 4, linesize, v->pq); - else - v->vc1dsp.vc1_v_loop_filter4(dst, linesize, v->pq); - } - } - } - - dst -= 4 * linesize; - ttblk = (v->ttblk[s->mb_x - s->mb_stride] >> (block_num * 4)) & 0xF; - if (ttblk == TT_4X4 || ttblk == TT_8X4) { - idx = (block_cbp | (block_cbp >> 2)) & 3; - if (idx == 3) { - v->vc1dsp.vc1_v_loop_filter8(dst, linesize, v->pq); - } else if (idx) { - if (idx == 1) - v->vc1dsp.vc1_v_loop_filter4(dst + 4, linesize, v->pq); - else - v->vc1dsp.vc1_v_loop_filter4(dst, linesize, v->pq); - } - } -} - -static av_always_inline void vc1_apply_p_h_loop_filter(VC1Context *v, int block_num) -{ - MpegEncContext *s = &v->s; - int mb_cbp = v->cbp[s->mb_x - 1 - s->mb_stride], - block_cbp = mb_cbp >> (block_num * 4), right_cbp, - mb_is_intra = v->is_intra[s->mb_x - 1 - s->mb_stride], - block_is_intra = mb_is_intra >> block_num, right_is_intra; - int idx, linesize = block_num > 3 ? s->uvlinesize : s->linesize, ttblk; - uint8_t *dst; - - if (block_num > 3) { - dst = s->dest[block_num - 3] - 8 * linesize; - } else { - dst = s->dest[0] + (block_num & 1) * 8 + ((block_num & 2) * 4 - 16) * linesize - 8; - } - - if (s->mb_x != s->mb_width || !(block_num & 5)) { - int16_t (*mv)[2]; - - if (block_num > 3) { - right_cbp = v->cbp[s->mb_x - s->mb_stride] >> (block_num * 4); - right_is_intra = v->is_intra[s->mb_x - s->mb_stride] >> block_num; - mv = &v->luma_mv[s->mb_x - s->mb_stride - 1]; - } else { - right_cbp = (block_num & 1) ? (v->cbp[s->mb_x - s->mb_stride] >> ((block_num - 1) * 4)) - : (mb_cbp >> ((block_num + 1) * 4)); - right_is_intra = (block_num & 1) ? (v->is_intra[s->mb_x - s->mb_stride] >> (block_num - 1)) - : (mb_is_intra >> (block_num + 1)); - mv = &s->current_picture.motion_val[0][s->block_index[block_num] - s->b8_stride * 2 - 2]; - } - if (block_is_intra & 1 || right_is_intra & 1 || mv[0][0] != mv[1][0] || mv[0][1] != mv[1][1]) { - v->vc1dsp.vc1_h_loop_filter8(dst, linesize, v->pq); - } else { - idx = ((right_cbp >> 1) | block_cbp) & 5; // FIXME check - if (idx == 5) { - v->vc1dsp.vc1_h_loop_filter8(dst, linesize, v->pq); - } else if (idx) { - if (idx == 1) - v->vc1dsp.vc1_h_loop_filter4(dst + 4 * linesize, linesize, v->pq); - else - v->vc1dsp.vc1_h_loop_filter4(dst, linesize, v->pq); - } - } - } - - dst -= 4; - ttblk = (v->ttblk[s->mb_x - s->mb_stride - 1] >> (block_num * 4)) & 0xf; - if (ttblk == TT_4X4 || ttblk == TT_4X8) { - idx = (block_cbp | (block_cbp >> 1)) & 5; - if (idx == 5) { - v->vc1dsp.vc1_h_loop_filter8(dst, linesize, v->pq); - } else if (idx) { - if (idx == 1) - v->vc1dsp.vc1_h_loop_filter4(dst + linesize * 4, linesize, v->pq); - else - v->vc1dsp.vc1_h_loop_filter4(dst, linesize, v->pq); - } - } -} - -void ff_vc1_apply_p_loop_filter(VC1Context *v) +void ff_vc1_p_overlap_filter(VC1Context *v) { MpegEncContext *s = &v->s; - int i; + int16_t (*topleft_blk)[64], (*top_blk)[64], (*left_blk)[64], (*cur_blk)[64]; int block_count = CONFIG_GRAY && (s->avctx->flags & AV_CODEC_FLAG_GRAY) ? 4 : 6; + int mb_pos = s->mb_x + s->mb_y * s->mb_stride; + int i; + + topleft_blk = v->block[v->topleft_blk_idx]; + top_blk = v->block[v->top_blk_idx]; + left_blk = v->block[v->left_blk_idx]; + cur_blk = v->block[v->cur_blk_idx]; for (i = 0; i < block_count; i++) { - vc1_apply_p_v_loop_filter(v, i); + if (s->mb_x == 0 && (i & 5) != 1) + continue; + + if (v->mb_type[0][s->block_index[i]] && v->mb_type[0][s->block_index[i] - 1]) + vc1_h_overlap_filter(v, + s->mb_x ? left_blk : cur_blk, cur_blk, + v->fcm == ILACE_FRAME && s->mb_x && v->fieldtx_plane[mb_pos - 1], + v->fcm == ILACE_FRAME && v->fieldtx_plane[mb_pos], + i); } - /* V always precedes H, therefore we run H one MB before V; - * at the end of a row, we catch up to complete the row */ - if (s->mb_x) { + if (v->fcm != ILACE_FRAME) for (i = 0; i < block_count; i++) { - vc1_apply_p_h_loop_filter(v, i); + if (s->first_slice_line && !(i & 2)) + continue; + + if (s->mb_x && v->mb_type[0][s->block_index[i] - 2 + (i > 3)] && + v->mb_type[0][s->block_index[i] - s->block_wrap[i] - 2 + (i > 3)]) + vc1_v_overlap_filter(v, s->first_slice_line ? left_blk : topleft_blk, left_blk, i); + if (s->mb_x == s->mb_width - 1) + if (v->mb_type[0][s->block_index[i]] && + v->mb_type[0][s->block_index[i] - s->block_wrap[i]]) + vc1_v_overlap_filter(v, s->first_slice_line ? cur_blk : top_blk, cur_blk, i); } - if (s->mb_x == s->mb_width - 1) { - s->mb_x++; - ff_update_block_index(s); - for (i = 0; i < block_count; i++) { - vc1_apply_p_h_loop_filter(v, i); +} + +#define LEFT_EDGE (1 << 0) +#define RIGHT_EDGE (1 << 1) +#define TOP_EDGE (1 << 2) +#define BOTTOM_EDGE (1 << 3) + +static av_always_inline void vc1_i_h_loop_filter(VC1Context *v, uint8_t *dest, + uint32_t flags, int block_num) +{ + MpegEncContext *s = &v->s; + int pq = v->pq; + uint8_t *dst; + + if (block_num & 2) + return; + + if (!(flags & LEFT_EDGE) || (block_num & 5) == 1) { + if (block_num > 3) + dst = dest; + else + dst = dest + (block_num & 2) * 4 * s->linesize + (block_num & 1) * 8; + + if (v->fcm == ILACE_FRAME) + if (block_num > 3) { + v->vc1dsp.vc1_h_loop_filter4(dst, 2 * s->uvlinesize, pq); + v->vc1dsp.vc1_h_loop_filter4(dst + s->uvlinesize, 2 * s->uvlinesize, pq); + } else { + v->vc1dsp.vc1_h_loop_filter8(dst, 2 * s->linesize, pq); + v->vc1dsp.vc1_h_loop_filter8(dst + s->linesize, 2 * s->linesize, pq); } + else + if (block_num > 3) + v->vc1dsp.vc1_h_loop_filter8(dst, s->uvlinesize, pq); + else + v->vc1dsp.vc1_h_loop_filter16(dst, s->linesize, pq); + } +} + +static av_always_inline void vc1_i_v_loop_filter(VC1Context *v, uint8_t *dest, + uint32_t flags, uint8_t fieldtx, + int block_num) +{ + MpegEncContext *s = &v->s; + int pq = v->pq; + uint8_t *dst; + + if ((block_num & 5) == 1) + return; + + if (!(flags & TOP_EDGE) || block_num & 2) { + if (block_num > 3) + dst = dest; + else + dst = dest + (block_num & 2) * 4 * s->linesize + (block_num & 1) * 8; + + if (v->fcm == ILACE_FRAME) { + if (block_num > 3) { + v->vc1dsp.vc1_v_loop_filter8(dst, 2 * s->uvlinesize, pq); + v->vc1dsp.vc1_v_loop_filter8(dst + s->uvlinesize, 2 * s->uvlinesize, pq); + } else if (block_num < 2 || !fieldtx) { + v->vc1dsp.vc1_v_loop_filter16(dst, 2 * s->linesize, pq); + v->vc1dsp.vc1_v_loop_filter16(dst + s->linesize, 2 * s->linesize, pq); + } + } else + if (block_num > 3) + v->vc1dsp.vc1_v_loop_filter8(dst, s->uvlinesize, pq); + else + v->vc1dsp.vc1_v_loop_filter16(dst, s->linesize, pq); + } +} + +void ff_vc1_i_loop_filter(VC1Context *v) +{ + MpegEncContext *s = &v->s; + int block_count = CONFIG_GRAY && (s->avctx->flags & AV_CODEC_FLAG_GRAY) ? 4 : 6; + int mb_pos = s->mb_x + s->mb_y * s->mb_stride; + uint8_t *dest, fieldtx; + uint32_t flags = 0; + int i; + + /* Within a MB, the vertical loop filter always runs before the horizontal. + * To accomplish that, we run the V loop filter on top and internal + * horizontal borders of the last overlap filtered MB. Then, we wait for + * the loop filter iteration on the next row to do V loop filter on the + * bottom edge of this MB, before moving over and running the H loop + * filter on the left and internal vertical borders. Therefore, the loop + * filter trails by one row and one column relative to the overlap filter + * and two rows and two columns relative to the decoding loop. */ + if (!s->first_slice_line) { + dest = s->dest[0] - 16 * s->linesize - 16; + flags = s->mb_y == s->start_mb_y + 1 ? TOP_EDGE : 0; + if (s->mb_x) { + fieldtx = v->fieldtx_plane[mb_pos - s->mb_stride - 1]; + for (i = 0; i < block_count; i++) + vc1_i_v_loop_filter(v, i > 3 ? s->dest[i - 3] - 8 * s->uvlinesize - 8 : dest, flags, fieldtx, i); + } + if (s->mb_x == v->end_mb_x - 1) { + dest += 16; + fieldtx = v->fieldtx_plane[mb_pos - s->mb_stride]; + for (i = 0; i < block_count; i++) + vc1_i_v_loop_filter(v, i > 3 ? s->dest[i - 3] - 8 * s->uvlinesize : dest, flags, fieldtx, i); + } + } + if (s->mb_y == s->end_mb_y - 1) { + dest = s->dest[0] - 16; + flags = s->first_slice_line ? TOP_EDGE | BOTTOM_EDGE : BOTTOM_EDGE; + if (s->mb_x) { + fieldtx = v->fieldtx_plane[mb_pos - 1]; + for (i = 0; i < block_count; i++) + vc1_i_v_loop_filter(v, i > 3 ? s->dest[i - 3] - 8 : dest, flags, fieldtx, i); + } + if (s->mb_x == v->end_mb_x - 1) { + dest += 16; + fieldtx = v->fieldtx_plane[mb_pos]; + for (i = 0; i < block_count; i++) + vc1_i_v_loop_filter(v, i > 3 ? s->dest[i - 3] : dest, flags, fieldtx, i); + } + } + + if (s->mb_y >= s->start_mb_y + 2) { + dest = s->dest[0] - 32 * s->linesize - 16; + if (s->mb_x) { + flags = s->mb_x == 1 ? LEFT_EDGE : 0; + for (i = 0; i < block_count; i++) + vc1_i_h_loop_filter(v, i > 3 ? s->dest[i - 3] - 16 * s->uvlinesize - 8 : dest, flags, i); + } + if (s->mb_x == v->end_mb_x - 1) { + dest += 16; + flags = s->mb_x == 0 ? LEFT_EDGE | RIGHT_EDGE : RIGHT_EDGE; + for (i = 0; i < block_count; i++) + vc1_i_h_loop_filter(v, i > 3 ? s->dest[i - 3] - 16 * s->uvlinesize : dest, flags, i); + } + } + if (s->mb_y == s->end_mb_y - 1) { + if (s->mb_y >= s->start_mb_y + 1) { + dest = s->dest[0] - 16 * s->linesize - 16; + if (s->mb_x) { + flags = s->mb_x == 1 ? LEFT_EDGE : 0; + for (i = 0; i < block_count; i++) + vc1_i_h_loop_filter(v, i > 3 ? s->dest[i - 3] - 8 * s->uvlinesize - 8 : dest, flags, i); + } + if (s->mb_x == v->end_mb_x - 1) { + flags = s->mb_x == 0 ? LEFT_EDGE | RIGHT_EDGE : RIGHT_EDGE; + dest += 16; + for (i = 0; i < block_count; i++) + vc1_i_h_loop_filter(v, i > 3 ? s->dest[i - 3] - 8 * s->uvlinesize : dest, flags, i); + } + } + dest = s->dest[0] - 16; + if (s->mb_x) { + flags = s->mb_x == 1 ? LEFT_EDGE : 0; + for (i = 0; i < block_count; i++) + vc1_i_h_loop_filter(v, i > 3 ? s->dest[i - 3] - 8 : dest, flags, i); + } + if (s->mb_x == v->end_mb_x - 1) { + dest += 16; + flags = s->mb_x == 0 ? LEFT_EDGE | RIGHT_EDGE : RIGHT_EDGE; + for (i = 0; i < block_count; i++) + vc1_i_h_loop_filter(v, i > 3 ? s->dest[i - 3] : dest, flags, i); + } + } +} + +static av_always_inline void vc1_p_h_loop_filter(VC1Context *v, uint8_t *dest, uint32_t *cbp, + uint8_t *is_intra, int16_t (*mv)[2], uint8_t *mv_f, + int *ttblk, uint32_t flags, int block_num) +{ + MpegEncContext *s = &v->s; + int pq = v->pq; + uint32_t left_cbp = cbp[0] >> (block_num * 4), right_cbp; + uint8_t left_is_intra, right_is_intra; + int tt; + int idx, linesize = block_num > 3 ? s->uvlinesize : s->linesize; + uint8_t *dst; + + if (block_num > 3) + dst = dest; + else + dst = dest + (block_num & 2) * 4 * s->linesize + (block_num & 1) * 8; + + if (!(flags & RIGHT_EDGE) || !(block_num & 5)) { + left_is_intra = is_intra[0] & (1 << block_num); + + if (block_num > 3) { + right_is_intra = is_intra[1] & (1 << block_num); + right_cbp = cbp[1] >> (block_num * 4); + } else if (block_num & 1) { + right_is_intra = is_intra[1] & (1 << block_num - 1); + right_cbp = cbp[1] >> ((block_num - 1) * 4); + } else { + right_is_intra = is_intra[0] & (1 << block_num + 1); + right_cbp = cbp[0] >> ((block_num + 1) * 4); + } + + if (left_is_intra || right_is_intra || + mv[0][0] != mv[1][0] || mv[0][1] != mv[1][1] || + (v->fcm == ILACE_FIELD && mv_f[0] != mv_f[1])) + v->vc1dsp.vc1_h_loop_filter8(dst + 8, linesize, pq); + else { + idx = (left_cbp | (right_cbp >> 1)) & 5; + if (idx & 1) + v->vc1dsp.vc1_h_loop_filter4(dst + 4 * linesize + 8, linesize, pq); + if (idx & 4) + v->vc1dsp.vc1_h_loop_filter4(dst + 8, linesize, pq); + } + } + + tt = ttblk[0] >> (block_num * 4) & 0xf; + if (tt == TT_4X4 || tt == TT_4X8) { + if (left_cbp & 3) + v->vc1dsp.vc1_h_loop_filter4(dst + 4 * linesize + 4, linesize, pq); + if (left_cbp & 12) + v->vc1dsp.vc1_h_loop_filter4(dst + 4, linesize, pq); + } +} + +static av_always_inline void vc1_p_v_loop_filter(VC1Context *v, uint8_t *dest, uint32_t *cbp, + uint8_t *is_intra, int16_t (*mv)[2], uint8_t *mv_f, + int *ttblk, uint32_t flags, int block_num) +{ + MpegEncContext *s = &v->s; + int pq = v->pq; + uint32_t top_cbp = cbp[0] >> (block_num * 4), bottom_cbp; + uint8_t top_is_intra, bottom_is_intra; + int tt; + int idx, linesize = block_num > 3 ? s->uvlinesize : s->linesize; + uint8_t *dst; + + if (block_num > 3) + dst = dest; + else + dst = dest + (block_num & 2) * 4 * s->linesize + (block_num & 1) * 8; + + if(!(flags & BOTTOM_EDGE) || block_num < 2) { + top_is_intra = is_intra[0] & (1 << block_num); + + if (block_num > 3) { + bottom_is_intra = is_intra[s->mb_stride] & (1 << block_num); + bottom_cbp = cbp[s->mb_stride] >> (block_num * 4); + } else if (block_num < 2) { + bottom_is_intra = is_intra[0] & (1 << block_num + 2); + bottom_cbp = cbp[0] >> ((block_num + 2) * 4); + } else { + bottom_is_intra = is_intra[s->mb_stride] & (1 << block_num - 2); + bottom_cbp = cbp[s->mb_stride] >> ((block_num - 2) * 4); + } + + if (top_is_intra || bottom_is_intra || + mv[0][0] != mv[block_num > 3 ? s->mb_stride : s->b8_stride][0] || + mv[0][1] != mv[block_num > 3 ? s->mb_stride : s->b8_stride][1] || + (v->fcm == ILACE_FIELD && mv_f[0] != mv_f[block_num > 3 ? s->mb_stride : s->b8_stride])) + v->vc1dsp.vc1_v_loop_filter8(dst + 8 * linesize, linesize, pq); + else { + idx = (top_cbp | (bottom_cbp >> 2)) & 3; + if (idx & 1) + v->vc1dsp.vc1_v_loop_filter4(dst + 8 * linesize + 4, linesize, pq); + if (idx & 2) + v->vc1dsp.vc1_v_loop_filter4(dst + 8 * linesize, linesize, pq); + } + } + + tt = ttblk[0] >> (block_num * 4) & 0xf; + if (tt == TT_4X4 || tt == TT_8X4) { + if (top_cbp & 5) + v->vc1dsp.vc1_v_loop_filter4(dst + 4 * linesize + 4, linesize, pq); + if (top_cbp & 10) + v->vc1dsp.vc1_v_loop_filter4(dst + 4 * linesize, linesize, pq); + } +} + +void ff_vc1_p_loop_filter(VC1Context *v) +{ + MpegEncContext *s = &v->s; + int block_count = CONFIG_GRAY && (s->avctx->flags & AV_CODEC_FLAG_GRAY) ? 4 : 6; + uint8_t *dest; + uint32_t *cbp; + uint8_t *is_intra; + int16_t (*uvmv)[2]; + int *ttblk; + uint32_t flags; + int i; + + /* Within a MB, the vertical loop filter always runs before the horizontal. + * To accomplish that, we run the V loop filter on all applicable + * horizontal borders of the MB above the last overlap filtered MB. Then, + * we wait for the next loop filter iteration to do H loop filter on all + * applicable vertical borders of this MB. Therefore, the loop filter + * trails by one row and one column relative to the overlap filter and two + * rows and two columns relative to the decoding loop. */ + if (s->mb_y >= s->start_mb_y + 2) { + if (s->mb_x) { + dest = s->dest[0] - 32 * s->linesize - 16; + cbp = &v->cbp[s->mb_x - 2 * s->mb_stride - 1]; + is_intra = &v->is_intra[s->mb_x - 2 * s->mb_stride - 1]; + uvmv = &v->luma_mv[s->mb_x - 2 * s->mb_stride - 1]; + ttblk = &v->ttblk[s->mb_x - 2 * s->mb_stride - 1]; + flags = s->mb_y == s->start_mb_y + 2 ? TOP_EDGE : 0; + for (i = 0; i < block_count; i++) + vc1_p_v_loop_filter(v, + i > 3 ? s->dest[i - 3] - 16 * s->uvlinesize - 8 : dest, + cbp, + is_intra, + i > 3 ? uvmv : + &s->current_picture.motion_val[0][s->block_index[i] - 4 * s->b8_stride - 2 + v->blocks_off], + i > 3 ? &v->mv_f[0][s->block_index[i] - 2 * s->mb_stride - 1 + v->mb_off] : + &v->mv_f[0][s->block_index[i] - 4 * s->b8_stride - 2 + v->blocks_off], + ttblk, + flags, + i); + } + if (s->mb_x == s->mb_width - 1) { + dest = s->dest[0] - 32 * s->linesize; + cbp = &v->cbp[s->mb_x - 2 * s->mb_stride]; + is_intra = &v->is_intra[s->mb_x - 2 * s->mb_stride]; + uvmv = &v->luma_mv[s->mb_x - 2 * s->mb_stride]; + ttblk = &v->ttblk[s->mb_x - 2 * s->mb_stride]; + flags = s->mb_y == s->start_mb_y + 2 ? TOP_EDGE : 0; + for (i = 0; i < block_count; i++) + vc1_p_v_loop_filter(v, + i > 3 ? s->dest[i - 3] - 16 * s->uvlinesize : dest, + cbp, + is_intra, + i > 3 ? uvmv : + &s->current_picture.motion_val[0][s->block_index[i] - 4 * s->b8_stride + v->blocks_off], + i > 3 ? &v->mv_f[0][s->block_index[i] - 2 * s->mb_stride + v->mb_off] : + &v->mv_f[0][s->block_index[i] - 4 * s->b8_stride + v->blocks_off], + ttblk, + flags, + i); + } + } + if (s->mb_y == s->end_mb_y - 1) { + if (s->mb_x) { + if (s->mb_y >= s->start_mb_y + 1) { + dest = s->dest[0] - 16 * s->linesize - 16; + cbp = &v->cbp[s->mb_x - s->mb_stride - 1]; + is_intra = &v->is_intra[s->mb_x - s->mb_stride - 1]; + uvmv = &v->luma_mv[s->mb_x - s->mb_stride - 1]; + ttblk = &v->ttblk[s->mb_x - s->mb_stride - 1]; + flags = s->mb_y == s->start_mb_y + 1 ? TOP_EDGE : 0; + for (i = 0; i < block_count; i++) + vc1_p_v_loop_filter(v, + i > 3 ? s->dest[i - 3] - 8 * s->uvlinesize - 8 : dest, + cbp, + is_intra, + i > 3 ? uvmv : + &s->current_picture.motion_val[0][s->block_index[i] - 2 * s->b8_stride - 2 + v->blocks_off], + i > 3 ? &v->mv_f[0][s->block_index[i] - s->mb_stride - 1 + v->mb_off] : + &v->mv_f[0][s->block_index[i] - 2 * s->b8_stride - 2 + v->blocks_off], + ttblk, + flags, + i); + } + dest = s->dest[0] - 16; + cbp = &v->cbp[s->mb_x - 1]; + is_intra = &v->is_intra[s->mb_x - 1]; + uvmv = &v->luma_mv[s->mb_x - 1]; + ttblk = &v->ttblk[s->mb_x - 1]; + flags = s->mb_y == s->start_mb_y ? TOP_EDGE | BOTTOM_EDGE : BOTTOM_EDGE; + for (i = 0; i < block_count; i++) + vc1_p_v_loop_filter(v, + i > 3 ? s->dest[i - 3] - 8 : dest, + cbp, + is_intra, + i > 3 ? uvmv : + &s->current_picture.motion_val[0][s->block_index[i] - 2 + v->blocks_off], + i > 3 ? &v->mv_f[0][s->block_index[i] - 1 + v->mb_off] : + &v->mv_f[0][s->block_index[i] - 2 + v->blocks_off], + ttblk, + flags, + i); + } + if (s->mb_x == s->mb_width - 1) { + if (s->mb_y >= s->start_mb_y + 1) { + dest = s->dest[0] - 16 * s->linesize; + cbp = &v->cbp[s->mb_x - s->mb_stride]; + is_intra = &v->is_intra[s->mb_x - s->mb_stride]; + uvmv = &v->luma_mv[s->mb_x - s->mb_stride]; + ttblk = &v->ttblk[s->mb_x - s->mb_stride]; + flags = s->mb_y == s->start_mb_y + 1 ? TOP_EDGE : 0; + for (i = 0; i < block_count; i++) + vc1_p_v_loop_filter(v, + i > 3 ? s->dest[i - 3] - 8 * s->uvlinesize : dest, + cbp, + is_intra, + i > 3 ? uvmv : + &s->current_picture.motion_val[0][s->block_index[i] - 2 * s->b8_stride + v->blocks_off], + i > 3 ? &v->mv_f[0][s->block_index[i] - s->mb_stride + v->mb_off] : + &v->mv_f[0][s->block_index[i] - 2 * s->b8_stride + v->blocks_off], + ttblk, + flags, + i); + } + dest = s->dest[0]; + cbp = &v->cbp[s->mb_x]; + is_intra = &v->is_intra[s->mb_x]; + uvmv = &v->luma_mv[s->mb_x]; + ttblk = &v->ttblk[s->mb_x]; + flags = s->mb_y == s->start_mb_y ? TOP_EDGE | BOTTOM_EDGE : BOTTOM_EDGE; + for (i = 0; i < block_count; i++) + vc1_p_v_loop_filter(v, + i > 3 ? s->dest[i - 3] : dest, + cbp, + is_intra, + i > 3 ? uvmv : + &s->current_picture.motion_val[0][s->block_index[i] + v->blocks_off], + i > 3 ? &v->mv_f[0][s->block_index[i] + v->mb_off] : + &v->mv_f[0][s->block_index[i] + v->blocks_off], + ttblk, + flags, + i); + } + } + + if (s->mb_y >= s->start_mb_y + 2) { + if (s->mb_x >= 2) { + dest = s->dest[0] - 32 * s->linesize - 32; + cbp = &v->cbp[s->mb_x - 2 * s->mb_stride - 2]; + is_intra = &v->is_intra[s->mb_x - 2 * s->mb_stride - 2]; + uvmv = &v->luma_mv[s->mb_x - 2 * s->mb_stride - 2]; + ttblk = &v->ttblk[s->mb_x - 2 * s->mb_stride - 2]; + flags = s->mb_x == 2 ? LEFT_EDGE : 0; + for (i = 0; i < block_count; i++) + vc1_p_h_loop_filter(v, + i > 3 ? s->dest[i - 3] - 16 * s->uvlinesize - 16 : dest, + cbp, + is_intra, + i > 3 ? uvmv : + &s->current_picture.motion_val[0][s->block_index[i] - 4 * s->b8_stride - 4 + v->blocks_off], + i > 3 ? &v->mv_f[0][s->block_index[i] - 2 * s->mb_stride - 2 + v->mb_off] : + &v->mv_f[0][s->block_index[i] - 4 * s->b8_stride - 4 + v->blocks_off], + ttblk, + flags, + i); + } + if (s->mb_x == s->mb_width - 1) { + if (s->mb_x >= 1) { + dest = s->dest[0] - 32 * s->linesize - 16; + cbp = &v->cbp[s->mb_x - 2 * s->mb_stride - 1]; + is_intra = &v->is_intra[s->mb_x - 2 * s->mb_stride - 1]; + uvmv = &v->luma_mv[s->mb_x - 2 * s->mb_stride - 1]; + ttblk = &v->ttblk[s->mb_x - 2 * s->mb_stride - 1]; + flags = s->mb_x == 1 ? LEFT_EDGE : 0; + for (i = 0; i < block_count; i++) + vc1_p_h_loop_filter(v, + i > 3 ? s->dest[i - 3] - 16 * s->uvlinesize - 8 : dest, + cbp, + is_intra, + i > 3 ? uvmv : + &s->current_picture.motion_val[0][s->block_index[i] - 4 * s->b8_stride - 2 + v->blocks_off], + i > 3 ? &v->mv_f[0][s->block_index[i] - 2 * s->mb_stride - 1 + v->mb_off] : + &v->mv_f[0][s->block_index[i] - 4 * s->b8_stride - 2 + v->blocks_off], + ttblk, + flags, + i); + } + dest = s->dest[0] - 32 * s->linesize; + cbp = &v->cbp[s->mb_x - 2 * s->mb_stride]; + is_intra = &v->is_intra[s->mb_x - 2 * s->mb_stride]; + uvmv = &v->luma_mv[s->mb_x - 2 * s->mb_stride]; + ttblk = &v->ttblk[s->mb_x - 2 * s->mb_stride]; + flags = s->mb_x ? RIGHT_EDGE : LEFT_EDGE | RIGHT_EDGE; + for (i = 0; i < block_count; i++) + vc1_p_h_loop_filter(v, + i > 3 ? s->dest[i - 3] - 16 * s->uvlinesize : dest, + cbp, + is_intra, + i > 3 ? uvmv : + &s->current_picture.motion_val[0][s->block_index[i] - 4 * s->b8_stride + v->blocks_off], + i > 3 ? &v->mv_f[0][s->block_index[i] - 2 * s->mb_stride + v->mb_off] : + &v->mv_f[0][s->block_index[i] - 4 * s->b8_stride + v->blocks_off], + ttblk, + flags, + i); + } + } + if (s->mb_y == s->end_mb_y - 1) { + if (s->mb_y >= s->start_mb_y + 1) { + if (s->mb_x >= 2) { + dest = s->dest[0] - 16 * s->linesize - 32; + cbp = &v->cbp[s->mb_x - s->mb_stride - 2]; + is_intra = &v->is_intra[s->mb_x - s->mb_stride - 2]; + uvmv = &v->luma_mv[s->mb_x - s->mb_stride - 2]; + ttblk = &v->ttblk[s->mb_x - s->mb_stride - 2]; + flags = s->mb_x == 2 ? LEFT_EDGE : 0; + for (i = 0; i < block_count; i++) + vc1_p_h_loop_filter(v, + i > 3 ? s->dest[i - 3] - 8 * s->uvlinesize - 16 : dest, + cbp, + is_intra, + i > 3 ? uvmv : + &s->current_picture.motion_val[0][s->block_index[i] - 2 * s->b8_stride - 4 + v->blocks_off], + i > 3 ? &v->mv_f[0][s->block_index[i] - s->mb_stride - 2 + v->mb_off] : + &v->mv_f[0][s->block_index[i] - 2 * s->b8_stride - 4 + v->blocks_off], + ttblk, + flags, + i); + } + if (s->mb_x == s->mb_width - 1) { + if (s->mb_x >= 1) { + dest = s->dest[0] - 16 * s->linesize - 16; + cbp = &v->cbp[s->mb_x - s->mb_stride - 1]; + is_intra = &v->is_intra[s->mb_x - s->mb_stride - 1]; + uvmv = &v->luma_mv[s->mb_x - s->mb_stride - 1]; + ttblk = &v->ttblk[s->mb_x - s->mb_stride - 1]; + flags = s->mb_x == 1 ? LEFT_EDGE : 0; + for (i = 0; i < block_count; i++) + vc1_p_h_loop_filter(v, + i > 3 ? s->dest[i - 3] - 8 * s->uvlinesize - 8 : dest, + cbp, + is_intra, + i > 3 ? uvmv : + &s->current_picture.motion_val[0][s->block_index[i] - 2 * s->b8_stride - 2 + v->blocks_off], + i > 3 ? &v->mv_f[0][s->block_index[i] - s->mb_stride - 1 + v->mb_off] : + &v->mv_f[0][s->block_index[i] - 2 * s->b8_stride - 2 + v->blocks_off], + ttblk, + flags, + i); + } + dest = s->dest[0] - 16 * s->linesize; + cbp = &v->cbp[s->mb_x - s->mb_stride]; + is_intra = &v->is_intra[s->mb_x - s->mb_stride]; + uvmv = &v->luma_mv[s->mb_x - s->mb_stride]; + ttblk = &v->ttblk[s->mb_x - s->mb_stride]; + flags = s->mb_x ? RIGHT_EDGE : LEFT_EDGE | RIGHT_EDGE; + for (i = 0; i < block_count; i++) + vc1_p_h_loop_filter(v, + i > 3 ? s->dest[i - 3] - 8 * s->uvlinesize : dest, + cbp, + is_intra, + i > 3 ? uvmv : + &s->current_picture.motion_val[0][s->block_index[i] - 2 * s->b8_stride + v->blocks_off], + i > 3 ? &v->mv_f[0][s->block_index[i] - s->mb_stride + v->mb_off] : + &v->mv_f[0][s->block_index[i] - 2 * s->b8_stride + v->blocks_off], + ttblk, + flags, + i); + } + } + if (s->mb_x >= 2) { + dest = s->dest[0] - 32; + cbp = &v->cbp[s->mb_x - 2]; + is_intra = &v->is_intra[s->mb_x - 2]; + uvmv = &v->luma_mv[s->mb_x - 2]; + ttblk = &v->ttblk[s->mb_x - 2]; + flags = s->mb_x == 2 ? LEFT_EDGE : 0; + for (i = 0; i < block_count; i++) + vc1_p_h_loop_filter(v, + i > 3 ? s->dest[i - 3] - 16 : dest, + cbp, + is_intra, + i > 3 ? uvmv : + &s->current_picture.motion_val[0][s->block_index[i] - 4 + v->blocks_off], + i > 3 ? &v->mv_f[0][s->block_index[i] - 2 + v->mb_off] : + &v->mv_f[0][s->block_index[i] - 4 + v->blocks_off], + ttblk, + flags, + i); + } + if (s->mb_x == s->mb_width - 1) { + if (s->mb_x >= 1) { + dest = s->dest[0] - 16; + cbp = &v->cbp[s->mb_x - 1]; + is_intra = &v->is_intra[s->mb_x - 1]; + uvmv = &v->luma_mv[s->mb_x - 1]; + ttblk = &v->ttblk[s->mb_x - 1]; + flags = s->mb_x == 1 ? LEFT_EDGE : 0; + for (i = 0; i < block_count; i++) + vc1_p_h_loop_filter(v, + i > 3 ? s->dest[i - 3] - 8 : dest, + cbp, + is_intra, + i > 3 ? uvmv : + &s->current_picture.motion_val[0][s->block_index[i] - 2 + v->blocks_off], + i > 3 ? &v->mv_f[0][s->block_index[i] - 1 + v->mb_off] : + &v->mv_f[0][s->block_index[i] - 2 + v->blocks_off], + ttblk, + flags, + i); + } + dest = s->dest[0]; + cbp = &v->cbp[s->mb_x]; + is_intra = &v->is_intra[s->mb_x]; + uvmv = &v->luma_mv[s->mb_x]; + ttblk = &v->ttblk[s->mb_x]; + flags = s->mb_x ? RIGHT_EDGE : LEFT_EDGE | RIGHT_EDGE; + for (i = 0; i < block_count; i++) + vc1_p_h_loop_filter(v, + i > 3 ? s->dest[i - 3] : dest, + cbp, + is_intra, + i > 3 ? uvmv : + &s->current_picture.motion_val[0][s->block_index[i] + v->blocks_off], + i > 3 ? &v->mv_f[0][s->block_index[i] + v->mb_off] : + &v->mv_f[0][s->block_index[i] + v->blocks_off], + ttblk, + flags, + i); + } + } +} + +static av_always_inline void vc1_p_h_intfr_loop_filter(VC1Context *v, uint8_t *dest, int *ttblk, + uint32_t flags, uint8_t fieldtx, int block_num) +{ + MpegEncContext *s = &v->s; + int pq = v->pq; + int tt; + int linesize = block_num > 3 ? s->uvlinesize : s->linesize; + uint8_t *dst; + + if (block_num > 3) + dst = dest; + else + dst = dest + (block_num & 2) * 4 * s->linesize + (block_num & 1) * 8; + + tt = ttblk[0] >> (block_num * 4) & 0xf; + if (block_num < 4) { + if (fieldtx) { + if (block_num < 2) { + if (tt == TT_4X4 || tt == TT_4X8) + v->vc1dsp.vc1_h_loop_filter8(dst + 4, 2 * linesize, pq); + if (!(flags & RIGHT_EDGE) || block_num == 0) + v->vc1dsp.vc1_h_loop_filter8(dst + 8, 2 * linesize, pq); + } else { + if (tt == TT_4X4 || tt == TT_4X8) + v->vc1dsp.vc1_h_loop_filter8(dst - 7 * linesize + 4, 2 * linesize, pq); + if (!(flags & RIGHT_EDGE) || block_num == 2) + v->vc1dsp.vc1_h_loop_filter8(dst - 7 * linesize + 8, 2 * linesize, pq); + } + } else { + if(tt == TT_4X4 || tt == TT_4X8) { + v->vc1dsp.vc1_h_loop_filter4(dst + 4, 2 * linesize, pq); + v->vc1dsp.vc1_h_loop_filter4(dst + linesize + 4, 2 * linesize, pq); + } + if (!(flags & RIGHT_EDGE) || !(block_num & 5)) { + v->vc1dsp.vc1_h_loop_filter4(dst + 8, 2 * linesize, pq); + v->vc1dsp.vc1_h_loop_filter4(dst + linesize + 8, 2 * linesize, pq); + } + } + } else { + if (tt == TT_4X4 || tt == TT_4X8) { + v->vc1dsp.vc1_h_loop_filter4(dst + 4, 2 * linesize, pq); + v->vc1dsp.vc1_h_loop_filter4(dst + linesize + 4, 2 * linesize, pq); + } + if (!(flags & RIGHT_EDGE)) { + v->vc1dsp.vc1_h_loop_filter4(dst + 8, 2 * linesize, pq); + v->vc1dsp.vc1_h_loop_filter4(dst + linesize + 8, 2 * linesize, pq); + } + } +} + +static av_always_inline void vc1_p_v_intfr_loop_filter(VC1Context *v, uint8_t *dest, int *ttblk, + uint32_t flags, uint8_t fieldtx, int block_num) +{ + MpegEncContext *s = &v->s; + int pq = v->pq; + int tt; + int linesize = block_num > 3 ? s->uvlinesize : s->linesize; + uint8_t *dst; + + if (block_num > 3) + dst = dest; + else + dst = dest + (block_num & 2) * 4 * s->linesize + (block_num & 1) * 8; + + tt = ttblk[0] >> (block_num * 4) & 0xf; + if (block_num < 4) { + if (fieldtx) { + if (block_num < 2) { + if (tt == TT_4X4 || tt == TT_8X4) + v->vc1dsp.vc1_v_loop_filter8(dst + 8 * linesize, 2 * linesize, pq); + if (!(flags & BOTTOM_EDGE)) + v->vc1dsp.vc1_v_loop_filter8(dst + 16 * linesize, 2 * linesize, pq); + } else { + if (tt == TT_4X4 || tt == TT_8X4) + v->vc1dsp.vc1_v_loop_filter8(dst + linesize, 2 * linesize, pq); + if (!(flags & BOTTOM_EDGE)) + v->vc1dsp.vc1_v_loop_filter8(dst + 9 * linesize, 2 * linesize, pq); + } + } else { + if (block_num < 2) { + if (!(flags & TOP_EDGE) && (tt == TT_4X4 || tt == TT_8X4)) { + v->vc1dsp.vc1_v_loop_filter8(dst + 4 * linesize, 2 * linesize, pq); + v->vc1dsp.vc1_v_loop_filter8(dst + 5 * linesize, 2 * linesize, pq); + } + v->vc1dsp.vc1_v_loop_filter8(dst + 8 * linesize, 2 * linesize, pq); + v->vc1dsp.vc1_v_loop_filter8(dst + 9 * linesize, 2 * linesize, pq); + } else if (!(flags & BOTTOM_EDGE)) { + if (tt == TT_4X4 || tt == TT_8X4) { + v->vc1dsp.vc1_v_loop_filter8(dst + 4 * linesize, 2 * linesize, pq); + v->vc1dsp.vc1_v_loop_filter8(dst + 5 * linesize, 2 * linesize, pq); + } + v->vc1dsp.vc1_v_loop_filter8(dst + 8 * linesize, 2 * linesize, pq); + v->vc1dsp.vc1_v_loop_filter8(dst + 9 * linesize, 2 * linesize, pq); + } + } + } else { + if (!(flags & BOTTOM_EDGE)) { + if (!(flags & TOP_EDGE) && (tt == TT_4X4 || tt == TT_8X4)) { + v->vc1dsp.vc1_v_loop_filter8(dst + 4 * linesize, 2 * linesize, pq); + v->vc1dsp.vc1_v_loop_filter8(dst + 5 * linesize, 2 * linesize, pq); + } + v->vc1dsp.vc1_v_loop_filter8(dst + 8 * linesize, 2 * linesize, pq); + v->vc1dsp.vc1_v_loop_filter8(dst + 9 * linesize, 2 * linesize, pq); + } + } +} + +void ff_vc1_p_intfr_loop_filter(VC1Context *v) +{ + MpegEncContext *s = &v->s; + int block_count = CONFIG_GRAY && (s->avctx->flags & AV_CODEC_FLAG_GRAY) ? 4 : 6; + int mb_pos = s->mb_x + s->mb_y * s->mb_stride; + uint8_t *dest; + int *ttblk; + uint32_t flags; + uint8_t fieldtx; + int i; + + /* Within a MB, the vertical loop filter always runs before the horizontal. + * To accomplish that, we run the V loop filter on all applicable + * horizontal borders of the MB above the last overlap filtered MB. Then, + * we wait for the loop filter iteration on the next row and next column to + * do H loop filter on all applicable vertical borders of this MB. + * Therefore, the loop filter trails by two rows and one column relative to + * the overlap filter and two rows and two columns relative to the decoding + * loop. */ + if (s->mb_x) { + if (s->mb_y >= s->start_mb_y + 1) { + dest = s->dest[0] - 16 * s->linesize - 16; + ttblk = &v->ttblk[s->mb_x - s->mb_stride - 1]; + flags = s->mb_y == s->start_mb_y + 1 ? TOP_EDGE : 0; + fieldtx = v->fieldtx_plane[mb_pos - s->mb_stride - 1]; + for (i = 0; i < block_count; i++) + vc1_p_v_intfr_loop_filter(v, + i > 3 ? s->dest[i - 3] - 8 * s->uvlinesize - 8 : dest, + ttblk, + flags, + fieldtx, + i); + } + } + if (s->mb_x == s->mb_width - 1) { + if (s->mb_y >= s->start_mb_y + 1) { + dest = s->dest[0] - 16 * s->linesize; + ttblk = &v->ttblk[s->mb_x - s->mb_stride]; + flags = s->mb_y == s->start_mb_y + 1 ? TOP_EDGE : 0; + fieldtx = v->fieldtx_plane[mb_pos - s->mb_stride]; + for (i = 0; i < block_count; i++) + vc1_p_v_intfr_loop_filter(v, + i > 3 ? s->dest[i - 3] - 8 * s->uvlinesize : dest, + ttblk, + flags, + fieldtx, + i); + } + } + if (s->mb_y == s->end_mb_y - 1) { + if (s->mb_x) { + dest = s->dest[0] - 16; + ttblk = &v->ttblk[s->mb_x - 1]; + flags = s->mb_y == s->start_mb_y ? TOP_EDGE | BOTTOM_EDGE : BOTTOM_EDGE; + fieldtx = v->fieldtx_plane[mb_pos - 1]; + for (i = 0; i < block_count; i++) + vc1_p_v_intfr_loop_filter(v, + i > 3 ? s->dest[i - 3] - 8 : dest, + ttblk, + flags, + fieldtx, + i); + } + if (s->mb_x == s->mb_width - 1) { + dest = s->dest[0]; + ttblk = &v->ttblk[s->mb_x]; + flags = s->mb_y == s->start_mb_y ? TOP_EDGE | BOTTOM_EDGE : BOTTOM_EDGE; + fieldtx = v->fieldtx_plane[mb_pos]; + for (i = 0; i < block_count; i++) + vc1_p_v_intfr_loop_filter(v, + i > 3 ? s->dest[i - 3] : dest, + ttblk, + flags, + fieldtx, + i); + } + } + + if (s->mb_y >= s->start_mb_y + 2) { + if (s->mb_x >= 2) { + dest = s->dest[0] - 32 * s->linesize - 32; + ttblk = &v->ttblk[s->mb_x - 2 * s->mb_stride - 2]; + flags = s->mb_x == 2 ? LEFT_EDGE : 0; + fieldtx = v->fieldtx_plane[mb_pos - 2 * s->mb_stride - 2]; + for (i = 0; i < block_count; i++) + vc1_p_h_intfr_loop_filter(v, + i > 3 ? s->dest[i - 3] - 16 * s->uvlinesize - 16 : dest, + ttblk, + flags, + fieldtx, + i); + } + if (s->mb_x == s->mb_width - 1) { + if (s->mb_x >= 1) { + dest = s->dest[0] - 32 * s->linesize - 16; + ttblk = &v->ttblk[s->mb_x - 2 * s->mb_stride - 1]; + flags = s->mb_x == 1 ? LEFT_EDGE : 0; + fieldtx = v->fieldtx_plane[mb_pos - 2 * s->mb_stride - 1]; + for (i = 0; i < block_count; i++) + vc1_p_h_intfr_loop_filter(v, + i > 3 ? s->dest[i - 3] - 16 * s->uvlinesize - 8 : dest, + ttblk, + flags, + fieldtx, + i); + } + dest = s->dest[0] - 32 * s->linesize; + ttblk = &v->ttblk[s->mb_x - 2 * s->mb_stride]; + flags = s->mb_x ? RIGHT_EDGE : LEFT_EDGE | RIGHT_EDGE; + fieldtx = v->fieldtx_plane[mb_pos - 2 * s->mb_stride]; + for (i = 0; i < block_count; i++) + vc1_p_h_intfr_loop_filter(v, + i > 3 ? s->dest[i - 3] - 16 * s->uvlinesize : dest, + ttblk, + flags, + fieldtx, + i); + } + } + if (s->mb_y == s->end_mb_y - 1) { + if (s->mb_y >= s->start_mb_y + 1) { + if (s->mb_x >= 2) { + dest = s->dest[0] - 16 * s->linesize - 32; + ttblk = &v->ttblk[s->mb_x - s->mb_stride - 2]; + flags = s->mb_x == 2 ? LEFT_EDGE : 0; + fieldtx = v->fieldtx_plane[mb_pos - s->mb_stride - 2]; + for (i = 0; i < block_count; i++) + vc1_p_h_intfr_loop_filter(v, + i > 3 ? s->dest[i - 3] - 8 * s->uvlinesize - 16 : dest, + ttblk, + flags, + fieldtx, + i); + } + if (s->mb_x == s->mb_width - 1) { + if (s->mb_x >= 1) { + dest = s->dest[0] - 16 * s->linesize - 16; + ttblk = &v->ttblk[s->mb_x - s->mb_stride - 1]; + flags = s->mb_x == 1 ? LEFT_EDGE : 0; + fieldtx = v->fieldtx_plane[mb_pos - s->mb_stride - 1]; + for (i = 0; i < block_count; i++) + vc1_p_h_intfr_loop_filter(v, + i > 3 ? s->dest[i - 3] - 8 * s->uvlinesize - 8 : dest, + ttblk, + flags, + fieldtx, + i); + } + dest = s->dest[0] - 16 * s->linesize; + ttblk = &v->ttblk[s->mb_x - s->mb_stride]; + flags = s->mb_x ? RIGHT_EDGE : LEFT_EDGE | RIGHT_EDGE; + fieldtx = v->fieldtx_plane[mb_pos - s->mb_stride]; + for (i = 0; i < block_count; i++) + vc1_p_h_intfr_loop_filter(v, + i > 3 ? s->dest[i - 3] - 8 * s->uvlinesize : dest, + ttblk, + flags, + fieldtx, + i); + } + } + if (s->mb_x >= 2) { + dest = s->dest[0] - 32; + ttblk = &v->ttblk[s->mb_x - 2]; + flags = s->mb_x == 2 ? LEFT_EDGE : 0; + fieldtx = v->fieldtx_plane[mb_pos - 2]; + for (i = 0; i < block_count; i++) + vc1_p_h_intfr_loop_filter(v, + i > 3 ? s->dest[i - 3] - 16 : dest, + ttblk, + flags, + fieldtx, + i); + } + if (s->mb_x == s->mb_width - 1) { + if (s->mb_x >= 1) { + dest = s->dest[0] - 16; + ttblk = &v->ttblk[s->mb_x - 1]; + flags = s->mb_x == 1 ? LEFT_EDGE : 0; + fieldtx = v->fieldtx_plane[mb_pos - 1]; + for (i = 0; i < block_count; i++) + vc1_p_h_intfr_loop_filter(v, + i > 3 ? s->dest[i - 3] - 8 : dest, + ttblk, + flags, + fieldtx, + i); + } + dest = s->dest[0]; + ttblk = &v->ttblk[s->mb_x]; + flags = s->mb_x ? RIGHT_EDGE : LEFT_EDGE | RIGHT_EDGE; + fieldtx = v->fieldtx_plane[mb_pos]; + for (i = 0; i < block_count; i++) + vc1_p_h_intfr_loop_filter(v, + i > 3 ? s->dest[i - 3] : dest, + ttblk, + flags, + fieldtx, + i); + } + } +} + +static av_always_inline void vc1_b_h_intfi_loop_filter(VC1Context *v, uint8_t *dest, uint32_t *cbp, + int *ttblk, uint32_t flags, int block_num) +{ + MpegEncContext *s = &v->s; + int pq = v->pq; + uint8_t *dst; + uint32_t block_cbp = cbp[0] >> (block_num * 4); + int tt; + int idx, linesize = block_num > 3 ? s->uvlinesize : s->linesize; + + if (block_num > 3) + dst = dest; + else + dst = dest + (block_num & 2) * 4 * s->linesize + (block_num & 1) * 8; + + if (!(flags & RIGHT_EDGE) || !(block_num & 5)) { + if (block_num > 3) + v->vc1dsp.vc1_h_loop_filter8(dst + 8, linesize, pq); + else + v->vc1dsp.vc1_h_loop_filter8(dst + 8, linesize, pq); + } + + tt = ttblk[0] >> (block_num * 4) & 0xf; + if (tt == TT_4X4 || tt == TT_4X8) { + idx = (block_cbp | (block_cbp >> 1)) & 5; + if (idx & 1) + v->vc1dsp.vc1_h_loop_filter4(dst + 4 * linesize + 4, linesize, pq); + if (idx & 4) + v->vc1dsp.vc1_h_loop_filter4(dst + 4, linesize, pq); + } +} + +static av_always_inline void vc1_b_v_intfi_loop_filter(VC1Context *v, uint8_t *dest, uint32_t *cbp, + int *ttblk, uint32_t flags, int block_num) +{ + MpegEncContext *s = &v->s; + int pq = v->pq; + uint8_t *dst; + uint32_t block_cbp = cbp[0] >> (block_num * 4); + int tt; + int idx, linesize = block_num > 3 ? s->uvlinesize : s->linesize; + + if (block_num > 3) + dst = dest; + else + dst = dest + (block_num & 2) * 4 * s->linesize + (block_num & 1) * 8; + + if(!(flags & BOTTOM_EDGE) || block_num < 2) + v->vc1dsp.vc1_v_loop_filter8(dst + 8 * linesize, linesize, pq); + + tt = ttblk[0] >> (block_num * 4) & 0xf; + if (tt == TT_4X4 || tt == TT_8X4) { + idx = (block_cbp | (block_cbp >> 2)) & 3; + if (idx & 1) + v->vc1dsp.vc1_v_loop_filter4(dst + 4 * linesize + 4, linesize, pq); + if (idx & 2) + v->vc1dsp.vc1_v_loop_filter4(dst + 4 * linesize, linesize, pq); + } +} + +void ff_vc1_b_intfi_loop_filter(VC1Context *v) +{ + MpegEncContext *s = &v->s; + int block_count = CONFIG_GRAY && (s->avctx->flags & AV_CODEC_FLAG_GRAY) ? 4 : 6; + uint8_t *dest; + uint32_t *cbp; + int *ttblk; + uint32_t flags = 0; + int i; + + /* Within a MB, the vertical loop filter always runs before the horizontal. + * To accomplish that, we run the V loop filter on all applicable + * horizontal borders of the MB above the currently decoded MB. Then, + * we wait for the next loop filter iteration to do H loop filter on all + * applicable vertical borders of this MB. Therefore, the loop filter + * trails by one row and one column relative to the decoding loop. */ + if (!s->first_slice_line) { + dest = s->dest[0] - 16 * s->linesize; + cbp = &v->cbp[s->mb_x - s->mb_stride]; + ttblk = &v->ttblk[s->mb_x - s->mb_stride]; + flags = s->mb_y == s->start_mb_y + 1 ? TOP_EDGE : 0; + for (i = 0; i < block_count; i++) + vc1_b_v_intfi_loop_filter(v, i > 3 ? s->dest[i - 3] - 8 * s->uvlinesize : dest, cbp, ttblk, flags, i); + } + if (s->mb_y == s->end_mb_y - 1) { + dest = s->dest[0]; + cbp = &v->cbp[s->mb_x]; + ttblk = &v->ttblk[s->mb_x]; + flags = s->first_slice_line ? TOP_EDGE | BOTTOM_EDGE : BOTTOM_EDGE; + for (i = 0; i < block_count; i++) + vc1_b_v_intfi_loop_filter(v, i > 3 ? s->dest[i - 3] : dest, cbp, ttblk, flags, i); + } + + if (!s->first_slice_line) { + dest = s->dest[0] - 16 * s->linesize - 16; + cbp = &v->cbp[s->mb_x - s->mb_stride - 1]; + ttblk = &v->ttblk[s->mb_x - s->mb_stride - 1]; + if (s->mb_x) { + flags = s->mb_x == 1 ? LEFT_EDGE : 0; + for (i = 0; i < block_count; i++) + vc1_b_h_intfi_loop_filter(v, i > 3 ? s->dest[i - 3] - 8 * s->uvlinesize - 8 : dest, cbp, ttblk, flags, i); + } + if (s->mb_x == s->mb_width - 1) { + dest += 16; + cbp++; + ttblk++; + flags = s->mb_x == 0 ? LEFT_EDGE | RIGHT_EDGE : RIGHT_EDGE; + for (i = 0; i < block_count; i++) + vc1_b_h_intfi_loop_filter(v, i > 3 ? s->dest[i - 3] - 8 * s->uvlinesize : dest, cbp, ttblk, flags, i); + } + } + if (s->mb_y == s->end_mb_y - 1) { + dest = s->dest[0] - 16; + cbp = &v->cbp[s->mb_x - 1]; + ttblk = &v->ttblk[s->mb_x - 1]; + if (s->mb_x) { + flags = s->mb_x == 1 ? LEFT_EDGE : 0; + for (i = 0; i < block_count; i++) + vc1_b_h_intfi_loop_filter(v, i > 3 ? s->dest[i - 3] - 8 : dest, cbp, ttblk, flags, i); + } + if (s->mb_x == s->mb_width - 1) { + dest += 16; + cbp++; + ttblk++; + flags = s->mb_x == 0 ? LEFT_EDGE | RIGHT_EDGE : RIGHT_EDGE; + for (i = 0; i < block_count; i++) + vc1_b_h_intfi_loop_filter(v, i > 3 ? s->dest[i - 3] : dest, cbp, ttblk, flags, i); } } } diff --git a/libavcodec/vc1_mc.c b/libavcodec/vc1_mc.c index 75c74cad8..1b8d8799b 100644 --- a/libavcodec/vc1_mc.c +++ b/libavcodec/vc1_mc.c @@ -179,12 +179,17 @@ void ff_vc1_mc_1mv(VC1Context *v, int dir) int i; uint8_t (*luty)[256], (*lutuv)[256]; int use_ic; + int interlace; + int linesize, uvlinesize; if ((!v->field_mode || (v->ref_field_type[dir] == 1 && v->cur_field_type == 1)) && !v->s.last_picture.f->data[0]) return; + linesize = s->current_picture_ptr->f->linesize[0]; + uvlinesize = s->current_picture_ptr->f->linesize[1]; + mx = s->mv[dir][0][0]; my = s->mv[dir][0][1]; @@ -220,6 +225,7 @@ void ff_vc1_mc_1mv(VC1Context *v, int dir) luty = v->curr_luty; lutuv = v->curr_lutuv; use_ic = *v->curr_use_ic; + interlace = 1; } else { srcY = s->last_picture.f->data[0]; srcU = s->last_picture.f->data[1]; @@ -227,6 +233,7 @@ void ff_vc1_mc_1mv(VC1Context *v, int dir) luty = v->last_luty; lutuv = v->last_lutuv; use_ic = v->last_use_ic; + interlace = s->last_picture.f->interlaced_frame; } } else { srcY = s->next_picture.f->data[0]; @@ -235,6 +242,7 @@ void ff_vc1_mc_1mv(VC1Context *v, int dir) luty = v->next_luty; lutuv = v->next_lutuv; use_ic = v->next_use_ic; + interlace = s->next_picture.f->interlaced_frame; } if (!srcY || !srcU) { @@ -254,9 +262,14 @@ void ff_vc1_mc_1mv(VC1Context *v, int dir) uvsrc_y = av_clip(uvsrc_y, -8, s->mb_height * 8); } else { src_x = av_clip( src_x, -17, s->avctx->coded_width); - src_y = av_clip( src_y, -18, s->avctx->coded_height + 1); uvsrc_x = av_clip(uvsrc_x, -8, s->avctx->coded_width >> 1); - uvsrc_y = av_clip(uvsrc_y, -8, s->avctx->coded_height >> 1); + if (v->fcm == ILACE_FRAME) { + src_y = av_clip(src_y, -18 + (src_y & 1), s->avctx->coded_height + (src_y & 1)); + uvsrc_y = av_clip(uvsrc_y, -8 + (uvsrc_y & 1), (s->avctx->coded_height >> 1) + (uvsrc_y & 1)); + } else { + src_y = av_clip(src_y, -18, s->avctx->coded_height + 1); + uvsrc_y = av_clip(uvsrc_y, -8, s->avctx->coded_height >> 1); + } } srcY += src_y * s->linesize + src_x; @@ -264,9 +277,9 @@ void ff_vc1_mc_1mv(VC1Context *v, int dir) srcV += uvsrc_y * s->uvlinesize + uvsrc_x; if (v->field_mode && v->ref_field_type[dir]) { - srcY += s->current_picture_ptr->f->linesize[0]; - srcU += s->current_picture_ptr->f->linesize[1]; - srcV += s->current_picture_ptr->f->linesize[2]; + srcY += linesize; + srcU += uvlinesize; + srcV += uvlinesize; } /* for grayscale we should not try to read from unknown area */ @@ -284,22 +297,106 @@ void ff_vc1_mc_1mv(VC1Context *v, int dir) const int k = 17 + s->mspel * 2; srcY -= s->mspel * (1 + s->linesize); - s->vdsp.emulated_edge_mc(s->sc.edge_emu_buffer, srcY, - s->linesize, s->linesize, - k, k, - src_x - s->mspel, src_y - s->mspel, - s->h_edge_pos, v_edge_pos); + if (interlace) { + s->vdsp.emulated_edge_mc(s->sc.edge_emu_buffer, + srcY, + linesize << 1, + linesize << 1, + k, + v->field_mode ? k : k + 1 >> 1, + src_x - s->mspel, + src_y - s->mspel >> !v->field_mode, + s->h_edge_pos, + s->v_edge_pos >> 1); + if (!v->field_mode) + s->vdsp.emulated_edge_mc(s->sc.edge_emu_buffer + linesize, + srcY + linesize, + linesize << 1, + linesize << 1, + k, + k >> 1, + src_x - s->mspel, + src_y - s->mspel + 1 >> 1, + s->h_edge_pos, + s->v_edge_pos >> 1); + } else + s->vdsp.emulated_edge_mc(s->sc.edge_emu_buffer, + srcY, + linesize, + linesize, + k, + v->field_mode ? (k << 1) - 1 : k, + src_x - s->mspel, + v->field_mode ? 2 * (src_y - s->mspel) + v->ref_field_type[dir] : + src_y - s->mspel, + s->h_edge_pos, + s->v_edge_pos); srcY = s->sc.edge_emu_buffer; - s->vdsp.emulated_edge_mc(ubuf, srcU, - s->uvlinesize, s->uvlinesize, - 8 + 1, 8 + 1, - uvsrc_x, uvsrc_y, - s->h_edge_pos >> 1, v_edge_pos >> 1); - s->vdsp.emulated_edge_mc(vbuf, srcV, - s->uvlinesize, s->uvlinesize, - 8 + 1, 8 + 1, - uvsrc_x, uvsrc_y, - s->h_edge_pos >> 1, v_edge_pos >> 1); + if (interlace) { + s->vdsp.emulated_edge_mc(ubuf, + srcU, + uvlinesize << 1, + uvlinesize << 1, + 9, + v->field_mode ? 9 : 5, + uvsrc_x, + uvsrc_y >> !v->field_mode, + s->h_edge_pos >> 1, + s->v_edge_pos >> 2); + s->vdsp.emulated_edge_mc(vbuf, + srcV, + uvlinesize << 1, + uvlinesize << 1, + 9, + v->field_mode ? 9 : 5, + uvsrc_x, + uvsrc_y >> !v->field_mode, + s->h_edge_pos >> 1, + s->v_edge_pos >> 2); + if (!v->field_mode) { + s->vdsp.emulated_edge_mc(ubuf + uvlinesize, + srcU + uvlinesize, + uvlinesize << 1, + uvlinesize << 1, + 9, + 4, + uvsrc_x, + uvsrc_y + 1 >> 1, + s->h_edge_pos >> 1, + s->v_edge_pos >> 2); + s->vdsp.emulated_edge_mc(vbuf + uvlinesize, + srcV + uvlinesize, + uvlinesize << 1, + uvlinesize << 1, + 9, + 4, + uvsrc_x, + uvsrc_y + 1 >> 1, + s->h_edge_pos >> 1, + s->v_edge_pos >> 2); + } + } else { + s->vdsp.emulated_edge_mc(ubuf, + srcU, + uvlinesize, + uvlinesize, + 9, + v->field_mode ? 17 : 9, + uvsrc_x, + v->field_mode ? 2 * uvsrc_y + v->ref_field_type[dir] : uvsrc_y, + s->h_edge_pos >> 1, + s->v_edge_pos >> 1); + s->vdsp.emulated_edge_mc(vbuf, + srcV, + uvlinesize, + uvlinesize, + 9, + v->field_mode ? 17 : 9, + uvsrc_x, + v->field_mode ? 2 * uvsrc_y + v->ref_field_type[dir] : uvsrc_y, + s->h_edge_pos >> 1, + s->v_edge_pos >> 1); + } srcU = ubuf; srcV = vbuf; /* if we deal with range reduction we need to scale source blocks */ @@ -344,6 +441,10 @@ void ff_vc1_mc_1mv(VC1Context *v, int dir) v->vc1dsp.put_no_rnd_vc1_chroma_pixels_tab[0](s->dest[1], srcU, s->uvlinesize, 8, uvmx, uvmy); v->vc1dsp.put_no_rnd_vc1_chroma_pixels_tab[0](s->dest[2], srcV, s->uvlinesize, 8, uvmx, uvmy); } + if (v->field_mode) { + v->mv_f[dir][s->block_index[4] + v->mb_off] = v->cur_field_type != v->ref_field_type[dir]; + v->mv_f[dir][s->block_index[5] + v->mb_off] = v->cur_field_type != v->ref_field_type[dir]; + } } /** Do motion compensation for 4-MV macroblock - luminance block @@ -358,12 +459,16 @@ void ff_vc1_mc_4mv_luma(VC1Context *v, int n, int dir, int avg) int v_edge_pos = s->v_edge_pos >> v->field_mode; uint8_t (*luty)[256]; int use_ic; + int interlace; + int linesize; if ((!v->field_mode || (v->ref_field_type[dir] == 1 && v->cur_field_type == 1)) && !v->s.last_picture.f->data[0]) return; + linesize = s->current_picture_ptr->f->linesize[0]; + mx = s->mv[dir][n][0]; my = s->mv[dir][n][1]; @@ -372,15 +477,18 @@ void ff_vc1_mc_4mv_luma(VC1Context *v, int n, int dir, int avg) srcY = s->current_picture.f->data[0]; luty = v->curr_luty; use_ic = *v->curr_use_ic; + interlace = 1; } else { srcY = s->last_picture.f->data[0]; luty = v->last_luty; use_ic = v->last_use_ic; + interlace = s->last_picture.f->interlaced_frame; } } else { srcY = s->next_picture.f->data[0]; luty = v->next_luty; use_ic = v->next_use_ic; + interlace = s->next_picture.f->interlaced_frame; } if (!srcY) { @@ -439,26 +547,16 @@ void ff_vc1_mc_4mv_luma(VC1Context *v, int n, int dir, int avg) src_y = av_clip(src_y, -16, s->mb_height * 16); } else { src_x = av_clip(src_x, -17, s->avctx->coded_width); - if (v->fcm == ILACE_FRAME) { - if (src_y & 1) - src_y = av_clip(src_y, -17, s->avctx->coded_height + 1); - else - src_y = av_clip(src_y, -18, s->avctx->coded_height); - } else { + if (v->fcm == ILACE_FRAME) + src_y = av_clip(src_y, -18 + (src_y & 1), s->avctx->coded_height + (src_y & 1)); + else src_y = av_clip(src_y, -18, s->avctx->coded_height + 1); - } } srcY += src_y * s->linesize + src_x; if (v->field_mode && v->ref_field_type[dir]) - srcY += s->current_picture_ptr->f->linesize[0]; + srcY += linesize; - if (fieldmv) { - if (!(src_y & 1)) - v_edge_pos--; - else - src_y -= (src_y < 4); - } if (v->rangeredfrm || use_ic || s->h_edge_pos < 13 || v_edge_pos < 23 || (unsigned)(src_x - s->mspel) > s->h_edge_pos - (mx & 3) - 8 - s->mspel * 2 @@ -467,11 +565,40 @@ void ff_vc1_mc_4mv_luma(VC1Context *v, int n, int dir, int avg) srcY -= s->mspel * (1 + (s->linesize << fieldmv)); /* check emulate edge stride and offset */ - s->vdsp.emulated_edge_mc(s->sc.edge_emu_buffer, srcY, - s->linesize, s->linesize, - k, k << fieldmv, - src_x - s->mspel, src_y - (s->mspel << fieldmv), - s->h_edge_pos, v_edge_pos); + if (interlace) { + s->vdsp.emulated_edge_mc(s->sc.edge_emu_buffer, + srcY, + linesize << 1, + linesize << 1, + k, + v->field_mode ? k : (k << fieldmv) + 1 >> 1, + src_x - s->mspel, + src_y - (s->mspel << fieldmv) >> !v->field_mode, + s->h_edge_pos, + s->v_edge_pos >> 1); + if (!v->field_mode && !fieldmv) + s->vdsp.emulated_edge_mc(s->sc.edge_emu_buffer + linesize, + srcY + linesize, + linesize << 1, + linesize << 1, + k, + k >> 1, + src_x - s->mspel, + src_y - s->mspel + 1 >> 1, + s->h_edge_pos, + s->v_edge_pos >> 1); + } else + s->vdsp.emulated_edge_mc(s->sc.edge_emu_buffer, + srcY, + linesize, + linesize, + k, + v->field_mode ? (k << 1) - 1 : k << fieldmv, + src_x - s->mspel, + v->field_mode ? 2 * (src_y - s->mspel) + v->ref_field_type[dir] : + src_y - (s->mspel << fieldmv), + s->h_edge_pos, + s->v_edge_pos); srcY = s->sc.edge_emu_buffer; /* if we deal with range reduction we need to scale source blocks */ if (v->rangeredfrm) { @@ -515,6 +642,8 @@ void ff_vc1_mc_4mv_chroma(VC1Context *v, int dir) int v_edge_pos = s->v_edge_pos >> v->field_mode; uint8_t (*lutuv)[256]; int use_ic; + int interlace; + int uvlinesize; if (!v->field_mode && !v->s.last_picture.f->data[0]) return; @@ -539,6 +668,9 @@ void ff_vc1_mc_4mv_chroma(VC1Context *v, int dir) return; s->current_picture.motion_val[1][s->block_index[0] + v->blocks_off][0] = tx; s->current_picture.motion_val[1][s->block_index[0] + v->blocks_off][1] = ty; + + uvlinesize = s->current_picture_ptr->f->linesize[1]; + uvmx = (tx + ((tx & 3) == 3)) >> 1; uvmy = (ty + ((ty & 3) == 3)) >> 1; @@ -570,17 +702,20 @@ void ff_vc1_mc_4mv_chroma(VC1Context *v, int dir) srcV = s->current_picture.f->data[2]; lutuv = v->curr_lutuv; use_ic = *v->curr_use_ic; + interlace = 1; } else { srcU = s->last_picture.f->data[1]; srcV = s->last_picture.f->data[2]; lutuv = v->last_lutuv; use_ic = v->last_use_ic; + interlace = s->last_picture.f->interlaced_frame; } } else { srcU = s->next_picture.f->data[1]; srcV = s->next_picture.f->data[2]; lutuv = v->next_lutuv; use_ic = v->next_use_ic; + interlace = s->next_picture.f->interlaced_frame; } if (!srcU) { @@ -593,8 +728,8 @@ void ff_vc1_mc_4mv_chroma(VC1Context *v, int dir) if (v->field_mode) { if (chroma_ref_type) { - srcU += s->current_picture_ptr->f->linesize[1]; - srcV += s->current_picture_ptr->f->linesize[2]; + srcU += uvlinesize; + srcV += uvlinesize; } } @@ -602,14 +737,71 @@ void ff_vc1_mc_4mv_chroma(VC1Context *v, int dir) || s->h_edge_pos < 18 || v_edge_pos < 18 || (unsigned)uvsrc_x > (s->h_edge_pos >> 1) - 9 || (unsigned)uvsrc_y > (v_edge_pos >> 1) - 9) { - s->vdsp.emulated_edge_mc(s->sc.edge_emu_buffer, srcU, - s->uvlinesize, s->uvlinesize, - 8 + 1, 8 + 1, uvsrc_x, uvsrc_y, - s->h_edge_pos >> 1, v_edge_pos >> 1); - s->vdsp.emulated_edge_mc(s->sc.edge_emu_buffer + 16, srcV, - s->uvlinesize, s->uvlinesize, - 8 + 1, 8 + 1, uvsrc_x, uvsrc_y, - s->h_edge_pos >> 1, v_edge_pos >> 1); + if (interlace) { + s->vdsp.emulated_edge_mc(s->sc.edge_emu_buffer, + srcU, + uvlinesize << 1, + uvlinesize << 1, + 9, + v->field_mode ? 9 : 5, + uvsrc_x, + uvsrc_y >> !v->field_mode, + s->h_edge_pos >> 1, + s->v_edge_pos >> 2); + s->vdsp.emulated_edge_mc(s->sc.edge_emu_buffer + 16, + srcV, + uvlinesize << 1, + uvlinesize << 1, + 9, + v->field_mode ? 9 : 5, + uvsrc_x, + uvsrc_y >> !v->field_mode, + s->h_edge_pos >> 1, + s->v_edge_pos >> 2); + if (!v->field_mode) { + s->vdsp.emulated_edge_mc(s->sc.edge_emu_buffer + uvlinesize, + srcU + uvlinesize, + uvlinesize << 1, + uvlinesize << 1, + 9, + 4, + uvsrc_x, + uvsrc_y + 1 >> 1, + s->h_edge_pos >> 1, + s->v_edge_pos >> 2); + s->vdsp.emulated_edge_mc(s->sc.edge_emu_buffer + 16 + uvlinesize, + srcV + uvlinesize, + uvlinesize << 1, + uvlinesize << 1, + 9, + 4, + uvsrc_x, + uvsrc_y + 1 >> 1, + s->h_edge_pos >> 1, + s->v_edge_pos >> 2); + } + } else { + s->vdsp.emulated_edge_mc(s->sc.edge_emu_buffer, + srcU, + uvlinesize, + uvlinesize, + 9, + v->field_mode ? 17 : 9, + uvsrc_x, + v->field_mode ? 2 * uvsrc_y + chroma_ref_type : uvsrc_y, + s->h_edge_pos >> 1, + s->v_edge_pos >> 1); + s->vdsp.emulated_edge_mc(s->sc.edge_emu_buffer + 16, + srcV, + uvlinesize, + uvlinesize, + 9, + v->field_mode ? 17 : 9, + uvsrc_x, + v->field_mode ? 2 * uvsrc_y + chroma_ref_type : uvsrc_y, + s->h_edge_pos >> 1, + s->v_edge_pos >> 1); + } srcU = s->sc.edge_emu_buffer; srcV = s->sc.edge_emu_buffer + 16; @@ -636,6 +828,10 @@ void ff_vc1_mc_4mv_chroma(VC1Context *v, int dir) v->vc1dsp.put_no_rnd_vc1_chroma_pixels_tab[0](s->dest[1], srcU, s->uvlinesize, 8, uvmx, uvmy); v->vc1dsp.put_no_rnd_vc1_chroma_pixels_tab[0](s->dest[2], srcV, s->uvlinesize, 8, uvmx, uvmy); } + if (v->field_mode) { + v->mv_f[dir][s->block_index[4] + v->mb_off] = v->cur_field_type != chroma_ref_type; + v->mv_f[dir][s->block_index[5] + v->mb_off] = v->cur_field_type != chroma_ref_type; + } } /** Do motion compensation for 4-MV interlaced frame chroma macroblock (both U and V) @@ -653,11 +849,15 @@ void ff_vc1_mc_4mv_chroma4(VC1Context *v, int dir, int dir2, int avg) int v_dist = fieldmv ? 1 : 4; // vertical offset for lower sub-blocks int v_edge_pos = s->v_edge_pos >> 1; int use_ic; + int interlace; + int uvlinesize; uint8_t (*lutuv)[256]; if (CONFIG_GRAY && s->avctx->flags & AV_CODEC_FLAG_GRAY) return; + uvlinesize = s->current_picture_ptr->f->linesize[1]; + for (i = 0; i < 4; i++) { int d = i < 2 ? dir: dir2; tx = s->mv[d][i][0]; @@ -675,17 +875,22 @@ void ff_vc1_mc_4mv_chroma4(VC1Context *v, int dir, int dir2, int avg) uvsrc_y = s->mb_y * 8 + ((i & 2) ? v_dist : 0) + (uvmy_field[i] >> 2); // FIXME: implement proper pull-back (see vc1cropmv.c, vc1CROPMV_ChromaPullBack()) uvsrc_x = av_clip(uvsrc_x, -8, s->avctx->coded_width >> 1); - uvsrc_y = av_clip(uvsrc_y, -8, s->avctx->coded_height >> 1); + if (v->fcm == ILACE_FRAME) + uvsrc_y = av_clip(uvsrc_y, -8 + (uvsrc_y & 1), (s->avctx->coded_height >> 1) + (uvsrc_y & 1)); + else + uvsrc_y = av_clip(uvsrc_y, -8, s->avctx->coded_height >> 1); if (i < 2 ? dir : dir2) { srcU = s->next_picture.f->data[1]; srcV = s->next_picture.f->data[2]; lutuv = v->next_lutuv; use_ic = v->next_use_ic; + interlace = s->next_picture.f->interlaced_frame; } else { srcU = s->last_picture.f->data[1]; srcV = s->last_picture.f->data[2]; lutuv = v->last_lutuv; use_ic = v->last_use_ic; + interlace = s->last_picture.f->interlaced_frame; } if (!srcU) return; @@ -694,24 +899,75 @@ void ff_vc1_mc_4mv_chroma4(VC1Context *v, int dir, int dir2, int avg) uvmx_field[i] = (uvmx_field[i] & 3) << 1; uvmy_field[i] = (uvmy_field[i] & 3) << 1; - if (fieldmv) { - if (!(uvsrc_y & 1)) - v_edge_pos = (s->v_edge_pos >> 1) - 1; - else - uvsrc_y -= (uvsrc_y < 2); - } if (use_ic || s->h_edge_pos < 10 || v_edge_pos < (5 << fieldmv) || (unsigned)uvsrc_x > (s->h_edge_pos >> 1) - 5 || (unsigned)uvsrc_y > v_edge_pos - (5 << fieldmv)) { - s->vdsp.emulated_edge_mc(s->sc.edge_emu_buffer, srcU, - s->uvlinesize, s->uvlinesize, - 5, (5 << fieldmv), uvsrc_x, uvsrc_y, - s->h_edge_pos >> 1, v_edge_pos); - s->vdsp.emulated_edge_mc(s->sc.edge_emu_buffer + 16, srcV, - s->uvlinesize, s->uvlinesize, - 5, (5 << fieldmv), uvsrc_x, uvsrc_y, - s->h_edge_pos >> 1, v_edge_pos); + if (interlace) { + s->vdsp.emulated_edge_mc(s->sc.edge_emu_buffer, + srcU, + uvlinesize << 1, + uvlinesize << 1, + 5, + (5 << fieldmv) + 1 >> 1, + uvsrc_x, + uvsrc_y >> 1, + s->h_edge_pos >> 1, + s->v_edge_pos >> 2); + s->vdsp.emulated_edge_mc(s->sc.edge_emu_buffer + 16, + srcV, + uvlinesize << 1, + uvlinesize << 1, + 5, + (5 << fieldmv) + 1 >> 1, + uvsrc_x, + uvsrc_y >> 1, + s->h_edge_pos >> 1, + s->v_edge_pos >> 2); + if (!fieldmv) { + s->vdsp.emulated_edge_mc(s->sc.edge_emu_buffer + uvlinesize, + srcU + uvlinesize, + uvlinesize << 1, + uvlinesize << 1, + 5, + 2, + uvsrc_x, + uvsrc_y + 1 >> 1, + s->h_edge_pos >> 1, + s->v_edge_pos >> 2); + s->vdsp.emulated_edge_mc(s->sc.edge_emu_buffer + 16 + uvlinesize, + srcV + uvlinesize, + uvlinesize << 1, + uvlinesize << 1, + 5, + 2, + uvsrc_x, + uvsrc_y + 1 >> 1, + s->h_edge_pos >> 1, + s->v_edge_pos >> 2); + } + } else { + s->vdsp.emulated_edge_mc(s->sc.edge_emu_buffer, + srcU, + uvlinesize, + uvlinesize, + 5, + 5 << fieldmv, + uvsrc_x, + uvsrc_y, + s->h_edge_pos >> 1, + s->v_edge_pos >> 1); + s->vdsp.emulated_edge_mc(s->sc.edge_emu_buffer + 16, + srcV, + uvlinesize, + uvlinesize, + 5, + 5 << fieldmv, + uvsrc_x, + uvsrc_y, + s->h_edge_pos >> 1, + s->v_edge_pos >> 1); + } srcU = s->sc.edge_emu_buffer; srcV = s->sc.edge_emu_buffer + 16; @@ -753,10 +1009,15 @@ void ff_vc1_interp_mc(VC1Context *v) int dxy, mx, my, uvmx, uvmy, src_x, src_y, uvsrc_x, uvsrc_y; int v_edge_pos = s->v_edge_pos >> v->field_mode; int use_ic = v->next_use_ic; + int interlace; + int linesize, uvlinesize; if (!v->field_mode && !v->s.next_picture.f->data[0]) return; + linesize = s->current_picture_ptr->f->linesize[0]; + uvlinesize = s->current_picture_ptr->f->linesize[1]; + mx = s->mv[1][0][0]; my = s->mv[1][0][1]; uvmx = (mx + ((mx & 3) == 3)) >> 1; @@ -773,6 +1034,8 @@ void ff_vc1_interp_mc(VC1Context *v) srcU = s->next_picture.f->data[1]; srcV = s->next_picture.f->data[2]; + interlace = s->next_picture.f->interlaced_frame; + src_x = s->mb_x * 16 + (mx >> 2); src_y = s->mb_y * 16 + (my >> 2); uvsrc_x = s->mb_x * 8 + (uvmx >> 2); @@ -785,9 +1048,14 @@ void ff_vc1_interp_mc(VC1Context *v) uvsrc_y = av_clip(uvsrc_y, -8, s->mb_height * 8); } else { src_x = av_clip( src_x, -17, s->avctx->coded_width); - src_y = av_clip( src_y, -18, s->avctx->coded_height + 1); uvsrc_x = av_clip(uvsrc_x, -8, s->avctx->coded_width >> 1); - uvsrc_y = av_clip(uvsrc_y, -8, s->avctx->coded_height >> 1); + if (v->fcm == ILACE_FRAME) { + src_y = av_clip(src_y, -18 + (src_y & 1), s->avctx->coded_height + (src_y & 1)); + uvsrc_y = av_clip(uvsrc_y, -8 + (uvsrc_y & 1), (s->avctx->coded_height >> 1) + (uvsrc_y & 1)); + } else { + src_y = av_clip(src_y, -18, s->avctx->coded_height + 1); + uvsrc_y = av_clip(uvsrc_y, -8, s->avctx->coded_height >> 1); + } } srcY += src_y * s->linesize + src_x; @@ -795,9 +1063,9 @@ void ff_vc1_interp_mc(VC1Context *v) srcV += uvsrc_y * s->uvlinesize + uvsrc_x; if (v->field_mode && v->ref_field_type[1]) { - srcY += s->current_picture_ptr->f->linesize[0]; - srcU += s->current_picture_ptr->f->linesize[1]; - srcV += s->current_picture_ptr->f->linesize[2]; + srcY += linesize; + srcU += uvlinesize; + srcV += uvlinesize; } /* for grayscale we should not try to read from unknown area */ @@ -814,22 +1082,106 @@ void ff_vc1_interp_mc(VC1Context *v) const int k = 17 + s->mspel * 2; srcY -= s->mspel * (1 + s->linesize); - s->vdsp.emulated_edge_mc(s->sc.edge_emu_buffer, srcY, - s->linesize, s->linesize, - k, k, - src_x - s->mspel, src_y - s->mspel, - s->h_edge_pos, v_edge_pos); + if (interlace) { + s->vdsp.emulated_edge_mc(s->sc.edge_emu_buffer, + srcY, + linesize << 1, + linesize << 1, + k, + v->field_mode ? k : (k + 1 >> 1), + src_x - s->mspel, + src_y - s->mspel >> !v->field_mode, + s->h_edge_pos, + s->v_edge_pos >> 1); + if (!v->field_mode) + s->vdsp.emulated_edge_mc(s->sc.edge_emu_buffer + linesize, + srcY + linesize, + linesize << 1, + linesize << 1, + k, + k >> 1, + src_x - s->mspel, + src_y - s->mspel + 1 >> 1, + s->h_edge_pos, + s->v_edge_pos >> 1); + } else + s->vdsp.emulated_edge_mc(s->sc.edge_emu_buffer, + srcY, + linesize, + linesize, + k, + v->field_mode ? (k << 1) - 1 : k, + src_x - s->mspel, + v->field_mode ? 2 * (src_y - s->mspel) + v->ref_field_type[1] : + src_y - s->mspel, + s->h_edge_pos, + s->v_edge_pos); srcY = s->sc.edge_emu_buffer; - s->vdsp.emulated_edge_mc(ubuf, srcU, - s->uvlinesize, s->uvlinesize, - 8 + 1, 8 + 1, - uvsrc_x, uvsrc_y, - s->h_edge_pos >> 1, v_edge_pos >> 1); - s->vdsp.emulated_edge_mc(vbuf, srcV, - s->uvlinesize, s->uvlinesize, - 8 + 1, 8 + 1, - uvsrc_x, uvsrc_y, - s->h_edge_pos >> 1, v_edge_pos >> 1); + if (interlace) { + s->vdsp.emulated_edge_mc(ubuf, + srcU, + uvlinesize << 1, + uvlinesize << 1, + 9, + v->field_mode ? 9 : 5, + uvsrc_x, + uvsrc_y >> !v->field_mode, + s->h_edge_pos >> 1, + s->v_edge_pos >> 2); + s->vdsp.emulated_edge_mc(vbuf, + srcV, + uvlinesize << 1, + uvlinesize << 1, + 9, + v->field_mode ? 9 : 5, + uvsrc_x, + uvsrc_y >> !v->field_mode, + s->h_edge_pos >> 1, + s->v_edge_pos >> 2); + if (!v->field_mode) { + s->vdsp.emulated_edge_mc(ubuf + uvlinesize, + srcU + uvlinesize, + uvlinesize << 1, + uvlinesize << 1, + 9, + 4, + uvsrc_x, + uvsrc_y + 1 >> 1, + s->h_edge_pos >> 1, + s->v_edge_pos >> 2); + s->vdsp.emulated_edge_mc(vbuf + uvlinesize, + srcV + uvlinesize, + uvlinesize << 1, + uvlinesize << 1, + 9, + 4, + uvsrc_x, + uvsrc_y + 1 >> 1, + s->h_edge_pos >> 1, + s->v_edge_pos >> 2); + } + } else { + s->vdsp.emulated_edge_mc(ubuf, + srcU, + uvlinesize, + uvlinesize, + 9, + v->field_mode ? 17 : 9, + uvsrc_x, + v->field_mode ? 2 * uvsrc_y + v->ref_field_type[1] : uvsrc_y, + s->h_edge_pos >> 1, + s->v_edge_pos >> 1); + s->vdsp.emulated_edge_mc(vbuf, + srcV, + uvlinesize, + uvlinesize, + 9, + v->field_mode ? 17 : 9, + uvsrc_x, + v->field_mode ? 2 * uvsrc_y + v->ref_field_type[1] : uvsrc_y, + s->h_edge_pos >> 1, + s->v_edge_pos >> 1); + } srcU = ubuf; srcV = vbuf; /* if we deal with range reduction we need to scale source blocks */ diff --git a/libavcodec/vc1_parser.c b/libavcodec/vc1_parser.c index bb54947f5..493ffde61 100644 --- a/libavcodec/vc1_parser.c +++ b/libavcodec/vc1_parser.c @@ -67,7 +67,7 @@ static void vc1_extract_header(AVCodecParserContext *s, AVCodecContext *avctx, int ret; vpc->v.s.avctx = avctx; vpc->v.parse_only = 1; - init_get_bits(&gb, buf, buf_size * 8); + init_get_bits8(&gb, buf, buf_size); switch (vpc->prev_start_code) { case VC1_CODE_SEQHDR & 0xFF: ff_vc1_decode_sequence_header(avctx, &vpc->v, &gb); diff --git a/libavcodec/vc1_pred.c b/libavcodec/vc1_pred.c index 54712f6b7..e1ad0e1d7 100644 --- a/libavcodec/vc1_pred.c +++ b/libavcodec/vc1_pred.c @@ -178,7 +178,7 @@ static av_always_inline int scaleforsame(VC1Context *v, int i, int n /* MV */, brfd = FFMIN(v->brfd, 3); scalesame = ff_vc1_b_field_mvpred_scales[0][brfd]; - n = (n * scalesame >> 8) << hpel; + n = (n * scalesame >> 8) * (1 << hpel); return n; } @@ -197,9 +197,10 @@ static av_always_inline int scaleforopp(VC1Context *v, int n /* MV */, return n; } if (v->s.pict_type != AV_PICTURE_TYPE_B) - refdist = FFMIN(v->refdist, 3); + refdist = v->refdist; else refdist = dir ? v->brfd : v->frfd; + refdist = FFMIN(refdist, 3); scaleopp = ff_vc1_field_mvpred_scales[dir ^ v->second_field][0][refdist]; n = (n * scaleopp >> 8) * (1 << hpel); @@ -254,7 +255,7 @@ void ff_vc1_pred_mv(VC1Context *v, int n, int dmv_x, int dmv_y, v->luma_mv[s->mb_x][0] = v->luma_mv[s->mb_x][1] = 0; s->current_picture.motion_val[1][xy + 1 + v->blocks_off][0] = 0; s->current_picture.motion_val[1][xy + 1 + v->blocks_off][1] = 0; - s->current_picture.motion_val[1][xy + wrap][0] = 0; + s->current_picture.motion_val[1][xy + wrap + v->blocks_off][0] = 0; s->current_picture.motion_val[1][xy + wrap + v->blocks_off][1] = 0; s->current_picture.motion_val[1][xy + wrap + 1 + v->blocks_off][0] = 0; s->current_picture.motion_val[1][xy + wrap + 1 + v->blocks_off][1] = 0; @@ -262,18 +263,23 @@ void ff_vc1_pred_mv(VC1Context *v, int n, int dmv_x, int dmv_y, return; } - C = s->current_picture.motion_val[dir][xy - 1 + v->blocks_off]; - A = s->current_picture.motion_val[dir][xy - wrap + v->blocks_off]; + a_valid = !s->first_slice_line || (n == 2 || n == 3); + b_valid = a_valid; + c_valid = s->mb_x || (n == 1 || n == 3); if (mv1) { if (v->field_mode && mixedmv_pic) off = (s->mb_x == (s->mb_width - 1)) ? -2 : 2; else off = (s->mb_x == (s->mb_width - 1)) ? -1 : 2; + b_valid = b_valid && s->mb_width > 1; } else { //in 4-MV mode different blocks have different B predictor position switch (n) { case 0: - off = (s->mb_x > 0) ? -1 : 1; + if (v->res_rtm_flag) + off = s->mb_x ? -1 : 1; + else + off = s->mb_x ? -1 : 2 * s->mb_width - wrap - 1; break; case 1: off = (s->mb_x == (s->mb_width - 1)) ? -1 : 1; @@ -284,12 +290,10 @@ void ff_vc1_pred_mv(VC1Context *v, int n, int dmv_x, int dmv_y, case 3: off = -1; } + if (v->field_mode && s->mb_width == 1) + b_valid = b_valid && c_valid; } - B = s->current_picture.motion_val[dir][xy - wrap + off + v->blocks_off]; - a_valid = !s->first_slice_line || (n == 2 || n == 3); - b_valid = a_valid && (s->mb_width > 1); - c_valid = s->mb_x || (n == 1 || n == 3); if (v->field_mode) { a_valid = a_valid && !is_intra[xy - wrap]; b_valid = b_valid && !is_intra[xy - wrap + off]; @@ -297,6 +301,7 @@ void ff_vc1_pred_mv(VC1Context *v, int n, int dmv_x, int dmv_y, } if (a_valid) { + A = s->current_picture.motion_val[dir][xy - wrap + v->blocks_off]; a_f = v->mv_f[dir][xy - wrap + v->blocks_off]; num_oppfield += a_f; num_samefield += 1 - a_f; @@ -307,6 +312,7 @@ void ff_vc1_pred_mv(VC1Context *v, int n, int dmv_x, int dmv_y, a_f = 0; } if (b_valid) { + B = s->current_picture.motion_val[dir][xy - wrap + off + v->blocks_off]; b_f = v->mv_f[dir][xy - wrap + off + v->blocks_off]; num_oppfield += b_f; num_samefield += 1 - b_f; @@ -317,6 +323,7 @@ void ff_vc1_pred_mv(VC1Context *v, int n, int dmv_x, int dmv_y, b_f = 0; } if (c_valid) { + C = s->current_picture.motion_val[dir][xy - 1 + v->blocks_off]; c_f = v->mv_f[dir][xy - 1 + v->blocks_off]; num_oppfield += c_f; num_samefield += 1 - c_f; @@ -341,6 +348,8 @@ void ff_vc1_pred_mv(VC1Context *v, int n, int dmv_x, int dmv_y, } else opposite = 0; if (opposite) { + v->mv_f[dir][xy + v->blocks_off] = 1; + v->ref_field_type[dir] = !v->cur_field_type; if (a_valid && !a_f) { field_predA[0] = scaleforopp(v, field_predA[0], 0, dir); field_predA[1] = scaleforopp(v, field_predA[1], 1, dir); @@ -353,9 +362,9 @@ void ff_vc1_pred_mv(VC1Context *v, int n, int dmv_x, int dmv_y, field_predC[0] = scaleforopp(v, field_predC[0], 0, dir); field_predC[1] = scaleforopp(v, field_predC[1], 1, dir); } - v->mv_f[dir][xy + v->blocks_off] = 1; - v->ref_field_type[dir] = !v->cur_field_type; } else { + v->mv_f[dir][xy + v->blocks_off] = 0; + v->ref_field_type[dir] = v->cur_field_type; if (a_valid && a_f) { field_predA[0] = scaleforsame(v, n, field_predA[0], 0, dir); field_predA[1] = scaleforsame(v, n, field_predA[1], 1, dir); @@ -368,8 +377,6 @@ void ff_vc1_pred_mv(VC1Context *v, int n, int dmv_x, int dmv_y, field_predC[0] = scaleforsame(v, n, field_predC[0], 0, dir); field_predC[1] = scaleforsame(v, n, field_predC[1], 1, dir); } - v->mv_f[dir][xy + v->blocks_off] = 0; - v->ref_field_type[dir] = v->cur_field_type; } if (a_valid) { diff --git a/libavcodec/vc1data.c b/libavcodec/vc1data.c index fc9ba6da1..19f1cad45 100644 --- a/libavcodec/vc1data.c +++ b/libavcodec/vc1data.c @@ -61,7 +61,7 @@ const uint8_t ff_vc1_mbmode_intfrp[2][15][4] = { { MV_PMODE_INTFR_1MV , 1, 0, 1 }, { MV_PMODE_INTFR_2MV_FIELD, 0, 0, 1 }, { MV_PMODE_INTFR_2MV_FIELD, 1, 0, 1 }, - { MV_PMODE_INTFR_2MV_FIELD, 0, 0, 0 }, + { MV_PMODE_INTFR_2MV_FIELD, 1, 0, 0 }, { MV_PMODE_INTFR_INTRA , 0, 0, 0 } }, { @@ -73,13 +73,13 @@ const uint8_t ff_vc1_mbmode_intfrp[2][15][4] = { { MV_PMODE_INTFR_1MV , 1, 0, 1 }, { MV_PMODE_INTFR_2MV_FIELD, 0, 0, 1 }, { MV_PMODE_INTFR_2MV_FIELD, 1, 0, 1 }, - { MV_PMODE_INTFR_2MV_FIELD, 0, 0, 0 }, + { MV_PMODE_INTFR_2MV_FIELD, 1, 0, 0 }, { MV_PMODE_INTFR_4MV , 0, 0, 1 }, { MV_PMODE_INTFR_4MV , 1, 0, 1 }, { MV_PMODE_INTFR_4MV , 0, 0, 0 }, { MV_PMODE_INTFR_4MV_FIELD, 0, 0, 1 }, { MV_PMODE_INTFR_4MV_FIELD, 1, 0, 1 }, - { MV_PMODE_INTFR_4MV_FIELD, 0, 0, 0 }, + { MV_PMODE_INTFR_4MV_FIELD, 1, 0, 0 }, { MV_PMODE_INTFR_INTRA , 0, 0, 0 } } }; @@ -1090,7 +1090,7 @@ const int32_t ff_vc1_dqscale[63] = { 0x1F08, 0x1E1E, 0x1D42, 0x1C72, 0x1BAD, 0x1AF3, 0x1A42, 0x199A, 0x18FA, 0x1862, 0x17D0, 0x1746, 0x16C1, 0x1643, 0x15CA, 0x1555, 0x14E6, 0x147B, 0x1414, 0x13B1, 0x1352, 0x12F7, 0x129E, 0x1249, - 0x11F7, 0x11A8, 0x115B, 0x1111, 0x10C9, 0x1084, 0x1000 + 0x11F7, 0x11A8, 0x115B, 0x1111, 0x10C9, 0x1084, 0x1041 }; /* P Interlaced field picture MV predictor scaling values (Table 114) */ diff --git a/libavcodec/vc1dec.c b/libavcodec/vc1dec.c index cbef89f25..ac3198e4f 100644 --- a/libavcodec/vc1dec.c +++ b/libavcodec/vc1dec.c @@ -340,22 +340,22 @@ av_cold int ff_vc1_decode_init_alloc_tables(VC1Context *v) v->n_allocated_blks = s->mb_width + 2; v->block = av_malloc(sizeof(*v->block) * v->n_allocated_blks); - v->cbp_base = av_malloc(sizeof(v->cbp_base[0]) * 2 * s->mb_stride); + v->cbp_base = av_malloc(sizeof(v->cbp_base[0]) * 3 * s->mb_stride); if (!v->block || !v->cbp_base) goto error; - v->cbp = v->cbp_base + s->mb_stride; - v->ttblk_base = av_malloc(sizeof(v->ttblk_base[0]) * 2 * s->mb_stride); + v->cbp = v->cbp_base + 2 * s->mb_stride; + v->ttblk_base = av_malloc(sizeof(v->ttblk_base[0]) * 3 * s->mb_stride); if (!v->ttblk_base) goto error; - v->ttblk = v->ttblk_base + s->mb_stride; - v->is_intra_base = av_mallocz(sizeof(v->is_intra_base[0]) * 2 * s->mb_stride); + v->ttblk = v->ttblk_base + 2 * s->mb_stride; + v->is_intra_base = av_mallocz(sizeof(v->is_intra_base[0]) * 3 * s->mb_stride); if (!v->is_intra_base) goto error; - v->is_intra = v->is_intra_base + s->mb_stride; - v->luma_mv_base = av_mallocz(sizeof(v->luma_mv_base[0]) * 2 * s->mb_stride); + v->is_intra = v->is_intra_base + 2 * s->mb_stride; + v->luma_mv_base = av_mallocz(sizeof(v->luma_mv_base[0]) * 3 * s->mb_stride); if (!v->luma_mv_base) goto error; - v->luma_mv = v->luma_mv_base + s->mb_stride; + v->luma_mv = v->luma_mv_base + 2 * s->mb_stride; /* allocate block type info in that way so it could be used with s->block_index[] */ v->mb_type_base = av_malloc(s->b8_stride * (mb_height * 2 + 1) + s->mb_stride * (mb_height + 1) * 2); @@ -450,6 +450,11 @@ static av_cold int vc1_decode_init(AVCodecContext *avctx) if ((ret = ff_vc1_decode_sequence_header(avctx, v, &gb)) < 0) return ret; + if (avctx->codec_id == AV_CODEC_ID_WMV3IMAGE && !v->res_sprite) { + avpriv_request_sample(avctx, "Non sprite WMV3IMAGE"); + return AVERROR_PATCHWELCOME; + } + count = avctx->extradata_size*8 - get_bits_count(&gb); if (count > 0) { av_log(avctx, AV_LOG_INFO, "Extra data: %i bits left, value: %X\n", @@ -698,9 +703,7 @@ static int vc1_decode_frame(AVCodecContext *avctx, void *data, slices[n_slices].buf); init_get_bits(&slices[n_slices].gb, slices[n_slices].buf, buf_size3 << 3); - /* assuming that the field marker is at the exact middle, - hope it's correct */ - slices[n_slices].mby_start = s->mb_height + 1 >> 1; + slices[n_slices].mby_start = avctx->coded_height + 31 >> 5; slices[n_slices].rawbuf = start; slices[n_slices].raw_size = size + 4; n_slices1 = n_slices - 1; // index of the last slice of the first field @@ -903,13 +906,41 @@ static int vc1_decode_frame(AVCodecContext *avctx, void *data, s->picture_structure = PICT_BOTTOM_FIELD - v->tff; if ((ret = avctx->hwaccel->start_frame(avctx, buf_start, buf_start_second_field - buf_start)) < 0) goto err; - if ((ret = avctx->hwaccel->decode_slice(avctx, buf_start, buf_start_second_field - buf_start)) < 0) - goto err; + + if (n_slices1 == -1) { + // no slices, decode the field as-is + if ((ret = avctx->hwaccel->decode_slice(avctx, buf_start, buf_start_second_field - buf_start)) < 0) + goto err; + } else { + if ((ret = avctx->hwaccel->decode_slice(avctx, buf_start, slices[0].rawbuf - buf_start)) < 0) + goto err; + + for (i = 0 ; i < n_slices1 + 1; i++) { + s->gb = slices[i].gb; + s->mb_y = slices[i].mby_start; + + v->pic_header_flag = get_bits1(&s->gb); + if (v->pic_header_flag) { + if (ff_vc1_parse_frame_header_adv(v, &s->gb) < 0) { + av_log(v->s.avctx, AV_LOG_ERROR, "Slice header damaged\n"); + ret = AVERROR_INVALIDDATA; + if (avctx->err_recognition & AV_EF_EXPLODE) + goto err; + continue; + } + } + + if ((ret = avctx->hwaccel->decode_slice(avctx, slices[i].rawbuf, slices[i].raw_size)) < 0) + goto err; + } + } + if ((ret = avctx->hwaccel->end_frame(avctx)) < 0) goto err; // decode second field s->gb = slices[n_slices1 + 1].gb; + s->mb_y = slices[n_slices1 + 1].mby_start; s->picture_structure = PICT_TOP_FIELD + v->tff; v->second_field = 1; v->pic_header_flag = 0; @@ -922,8 +953,35 @@ static int vc1_decode_frame(AVCodecContext *avctx, void *data, if ((ret = avctx->hwaccel->start_frame(avctx, buf_start_second_field, (buf + buf_size) - buf_start_second_field)) < 0) goto err; - if ((ret = avctx->hwaccel->decode_slice(avctx, buf_start_second_field, (buf + buf_size) - buf_start_second_field)) < 0) - goto err; + + if (n_slices - n_slices1 == 2) { + // no slices, decode the field as-is + if ((ret = avctx->hwaccel->decode_slice(avctx, buf_start_second_field, (buf + buf_size) - buf_start_second_field)) < 0) + goto err; + } else { + if ((ret = avctx->hwaccel->decode_slice(avctx, buf_start_second_field, slices[n_slices1 + 2].rawbuf - buf_start_second_field)) < 0) + goto err; + + for (i = n_slices1 + 2; i < n_slices; i++) { + s->gb = slices[i].gb; + s->mb_y = slices[i].mby_start; + + v->pic_header_flag = get_bits1(&s->gb); + if (v->pic_header_flag) { + if (ff_vc1_parse_frame_header_adv(v, &s->gb) < 0) { + av_log(v->s.avctx, AV_LOG_ERROR, "Slice header damaged\n"); + ret = AVERROR_INVALIDDATA; + if (avctx->err_recognition & AV_EF_EXPLODE) + goto err; + continue; + } + } + + if ((ret = avctx->hwaccel->decode_slice(avctx, slices[i].rawbuf, slices[i].raw_size)) < 0) + goto err; + } + } + if ((ret = avctx->hwaccel->end_frame(avctx)) < 0) goto err; } else { @@ -1029,13 +1087,15 @@ static int vc1_decode_frame(AVCodecContext *avctx, void *data, av_log(v->s.avctx, AV_LOG_ERROR, "first field slice count too large\n"); continue; } - s->end_mb_y = (i <= n_slices1 + 1) ? mb_height : FFMIN(mb_height, slices[i].mby_start % mb_height); + s->end_mb_y = (i == n_slices1 + 1) ? mb_height : FFMIN(mb_height, slices[i].mby_start % mb_height); } if (s->end_mb_y <= s->start_mb_y) { av_log(v->s.avctx, AV_LOG_ERROR, "end mb y %d %d invalid\n", s->end_mb_y, s->start_mb_y); continue; } - if (!v->p_frame_skipped && s->pict_type != AV_PICTURE_TYPE_I && !v->cbpcy_vlc) { + if (((s->pict_type == AV_PICTURE_TYPE_P && !v->p_frame_skipped) || + (s->pict_type == AV_PICTURE_TYPE_B && !v->bi_type)) && + !v->cbpcy_vlc) { av_log(v->s.avctx, AV_LOG_ERROR, "missing cbpcy_vlc\n"); continue; } diff --git a/libavcodec/vc1dsp.c b/libavcodec/vc1dsp.c index 9239a4a1f..c25a6f3ad 100644 --- a/libavcodec/vc1dsp.c +++ b/libavcodec/vc1dsp.c @@ -95,10 +95,10 @@ static void vc1_v_s_overlap_c(int16_t *top, int16_t *bottom) d1 = a - d; d2 = a - d + b - c; - top[48] = ((a << 3) - d1 + rnd1) >> 3; - top[56] = ((b << 3) - d2 + rnd2) >> 3; - bottom[0] = ((c << 3) + d2 + rnd1) >> 3; - bottom[8] = ((d << 3) + d1 + rnd2) >> 3; + top[48] = ((a * 8) - d1 + rnd1) >> 3; + top[56] = ((b * 8) - d2 + rnd2) >> 3; + bottom[0] = ((c * 8) + d2 + rnd1) >> 3; + bottom[8] = ((d * 8) + d1 + rnd2) >> 3; bottom++; top++; @@ -107,12 +107,13 @@ static void vc1_v_s_overlap_c(int16_t *top, int16_t *bottom) } } -static void vc1_h_s_overlap_c(int16_t *left, int16_t *right) +static void vc1_h_s_overlap_c(int16_t *left, int16_t *right, int left_stride, int right_stride, int flags) { int i; int a, b, c, d; int d1, d2; - int rnd1 = 4, rnd2 = 3; + int rnd1 = flags & 2 ? 3 : 4; + int rnd2 = 7 - rnd1; for (i = 0; i < 8; i++) { a = left[6]; b = left[7]; @@ -121,15 +122,17 @@ static void vc1_h_s_overlap_c(int16_t *left, int16_t *right) d1 = a - d; d2 = a - d + b - c; - left[6] = ((a << 3) - d1 + rnd1) >> 3; - left[7] = ((b << 3) - d2 + rnd2) >> 3; - right[0] = ((c << 3) + d2 + rnd1) >> 3; - right[1] = ((d << 3) + d1 + rnd2) >> 3; + left[6] = ((a * 8) - d1 + rnd1) >> 3; + left[7] = ((b * 8) - d2 + rnd2) >> 3; + right[0] = ((c * 8) + d2 + rnd1) >> 3; + right[1] = ((d * 8) + d1 + rnd2) >> 3; - right += 8; - left += 8; - rnd2 = 7 - rnd2; - rnd1 = 7 - rnd1; + right += right_stride; + left += left_stride; + if (flags & 1) { + rnd2 = 7 - rnd2; + rnd1 = 7 - rnd1; + } } } diff --git a/libavcodec/vc1dsp.h b/libavcodec/vc1dsp.h index 16b3528a7..75db62b1b 100644 --- a/libavcodec/vc1dsp.h +++ b/libavcodec/vc1dsp.h @@ -45,7 +45,7 @@ typedef struct VC1DSPContext { void (*vc1_v_overlap)(uint8_t *src, int stride); void (*vc1_h_overlap)(uint8_t *src, int stride); void (*vc1_v_s_overlap)(int16_t *top, int16_t *bottom); - void (*vc1_h_s_overlap)(int16_t *left, int16_t *right); + void (*vc1_h_s_overlap)(int16_t *left, int16_t *right, int left_stride, int right_stride, int flags); void (*vc1_v_loop_filter4)(uint8_t *src, int stride, int pq); void (*vc1_h_loop_filter4)(uint8_t *src, int stride, int pq); void (*vc1_v_loop_filter8)(uint8_t *src, int stride, int pq); diff --git a/libavcodec/vdpau.c b/libavcodec/vdpau.c index 1b2ec989c..167f06d7a 100644 --- a/libavcodec/vdpau.c +++ b/libavcodec/vdpau.c @@ -208,8 +208,12 @@ int ff_vdpau_common_init(AVCodecContext *avctx, VdpDecoderProfile profile, return vdpau_error(status); if (avctx->codec_id == AV_CODEC_ID_HEVC && strncmp(info_string, "NVIDIA ", 7) == 0 && !(avctx->hwaccel_flags & AV_HWACCEL_FLAG_ALLOW_PROFILE_MISMATCH)) { - av_log(avctx, AV_LOG_VERBOSE, "HEVC with NVIDIA VDPAU drivers is buggy, skipping.\n"); - return AVERROR(ENOTSUP); + int driver_version = 0; + sscanf(info_string, "NVIDIA VDPAU Driver Shared Library %d", &driver_version); + if (driver_version < 410) { + av_log(avctx, AV_LOG_VERBOSE, "HEVC with NVIDIA VDPAU drivers is buggy, skipping.\n"); + return AVERROR(ENOTSUP); + } } status = vdctx->get_proc_address(vdctx->device, diff --git a/libavcodec/vdpau_hevc.c b/libavcodec/vdpau_hevc.c index 421135bce..024ac6e2f 100644 --- a/libavcodec/vdpau_hevc.c +++ b/libavcodec/vdpau_hevc.c @@ -38,6 +38,9 @@ static int vdpau_hevc_start_frame(AVCodecContext *avctx, struct vdpau_picture_context *pic_ctx = pic->hwaccel_picture_private; VdpPictureInfoHEVC *info = &pic_ctx->info.hevc; +#ifdef VDP_YCBCR_FORMAT_Y_U_V_444 + VdpPictureInfoHEVC444 *info2 = &pic_ctx->info.hevc_444; +#endif const HEVCSPS *sps = h->ps.sps; const HEVCPPS *pps = h->ps.pps; @@ -355,6 +358,41 @@ static int vdpau_hevc_start_frame(AVCodecContext *avctx, } } +#ifdef VDP_YCBCR_FORMAT_Y_U_V_444 + if (sps->sps_range_extension_flag) { + info2->sps_range_extension_flag = 1; + info2->transformSkipRotationEnableFlag = sps->transform_skip_rotation_enabled_flag; + info2->transformSkipContextEnableFlag = sps->transform_skip_context_enabled_flag; + info2->implicitRdpcmEnableFlag = sps->implicit_rdpcm_enabled_flag; + info2->explicitRdpcmEnableFlag = sps->explicit_rdpcm_enabled_flag; + info2->extendedPrecisionProcessingFlag = sps->extended_precision_processing_flag; + info2->intraSmoothingDisabledFlag = sps->intra_smoothing_disabled_flag; + info2->highPrecisionOffsetsEnableFlag = sps->high_precision_offsets_enabled_flag; + info2->persistentRiceAdaptationEnableFlag = sps->persistent_rice_adaptation_enabled_flag; + info2->cabacBypassAlignmentEnableFlag = sps->cabac_bypass_alignment_enabled_flag; + } else { + info2->sps_range_extension_flag = 0; + } + if (pps->pps_range_extensions_flag) { + info2->pps_range_extension_flag = 1; + info2->log2MaxTransformSkipSize = pps->log2_max_transform_skip_block_size; + info2->crossComponentPredictionEnableFlag = pps->cross_component_prediction_enabled_flag; + info2->chromaQpAdjustmentEnableFlag = pps->chroma_qp_offset_list_enabled_flag; + info2->diffCuChromaQpAdjustmentDepth = pps->diff_cu_chroma_qp_offset_depth; + info2->chromaQpAdjustmentTableSize = pps->chroma_qp_offset_list_len_minus1 + 1; + info2->log2SaoOffsetScaleLuma = pps->log2_sao_offset_scale_luma; + info2->log2SaoOffsetScaleChroma = pps->log2_sao_offset_scale_chroma; + for (ssize_t i = 0; i < info2->chromaQpAdjustmentTableSize; i++) + { + info2->cb_qp_adjustment[i] = pps->cb_qp_offset_list[i]; + info2->cr_qp_adjustment[i] = pps->cr_qp_offset_list[i]; + } + + } else { + info2->pps_range_extension_flag = 0; + } +#endif + return ff_vdpau_common_start_frame(pic_ctx, buffer, size); } @@ -406,6 +444,9 @@ static int vdpau_hevc_init(AVCodecContext *avctx) case FF_PROFILE_HEVC_MAIN_STILL_PICTURE: profile = VDP_DECODER_PROFILE_HEVC_MAIN_STILL; break; + case FF_PROFILE_HEVC_REXT: + profile = VDP_DECODER_PROFILE_HEVC_MAIN_444; + break; default: return AVERROR(ENOTSUP); } diff --git a/libavcodec/vdpau_internal.h b/libavcodec/vdpau_internal.h index 4d63e50b1..1ee38dbc5 100644 --- a/libavcodec/vdpau_internal.h +++ b/libavcodec/vdpau_internal.h @@ -51,6 +51,9 @@ union VDPAUPictureInfo { #ifdef VDP_DECODER_PROFILE_HEVC_MAIN VdpPictureInfoHEVC hevc; #endif +#ifdef VDP_YCBCR_FORMAT_Y_U_V_444 + VdpPictureInfoHEVC444 hevc_444; +#endif }; typedef struct VDPAUHWContext { diff --git a/libavcodec/version.h b/libavcodec/version.h index 6895f1a46..3331d4730 100644 --- a/libavcodec/version.h +++ b/libavcodec/version.h @@ -28,7 +28,7 @@ #include "libavutil/version.h" #define LIBAVCODEC_VERSION_MAJOR 58 -#define LIBAVCODEC_VERSION_MINOR 18 +#define LIBAVCODEC_VERSION_MINOR 54 #define LIBAVCODEC_VERSION_MICRO 100 #define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \ @@ -132,6 +132,9 @@ #ifndef FF_API_NEXT #define FF_API_NEXT (LIBAVCODEC_VERSION_MAJOR < 59) #endif +#ifndef FF_API_UNSANITIZED_BITRATES +#define FF_API_UNSANITIZED_BITRATES (LIBAVCODEC_VERSION_MAJOR < 59) +#endif #endif /* AVCODEC_VERSION_H */ diff --git a/libavcodec/videodsp_template.c b/libavcodec/videodsp_template.c index 94c1b7188..55123a584 100644 --- a/libavcodec/videodsp_template.c +++ b/libavcodec/videodsp_template.c @@ -44,7 +44,8 @@ void FUNC(ff_emulated_edge_mc)(uint8_t *buf, const uint8_t *src, src_y = 1 - block_h; } if (src_x >= w) { - src += (w - 1 - src_x) * sizeof(pixel); + // The subtracted expression has an unsigned type and must thus not be negative + src -= (1 + src_x - w) * sizeof(pixel); src_x = w - 1; } else if (src_x <= -block_w) { src += (1 - block_w - src_x) * sizeof(pixel); diff --git a/libavcodec/videotoolbox.c b/libavcodec/videotoolbox.c index ac45e23c1..c718e82cc 100644 --- a/libavcodec/videotoolbox.c +++ b/libavcodec/videotoolbox.c @@ -26,6 +26,7 @@ #include "vt_internal.h" #include "libavutil/avutil.h" #include "libavutil/hwcontext.h" +#include "libavutil/pixdesc.h" #include "bytestream.h" #include "decode.h" #include "h264dec.h" @@ -176,26 +177,31 @@ CFDataRef ff_videotoolbox_avcc_extradata_create(AVCodecContext *avctx) CFDataRef ff_videotoolbox_hvcc_extradata_create(AVCodecContext *avctx) { HEVCContext *h = avctx->priv_data; - const HEVCVPS *vps = (const HEVCVPS *)h->ps.vps_list[0]->data; - const HEVCSPS *sps = (const HEVCSPS *)h->ps.sps_list[0]->data; - int i, num_pps = 0; + int i, num_vps = 0, num_sps = 0, num_pps = 0; + const HEVCVPS *vps = h->ps.vps; + const HEVCSPS *sps = h->ps.sps; const HEVCPPS *pps = h->ps.pps; PTLCommon ptlc = vps->ptl.general_ptl; VUI vui = sps->vui; uint8_t parallelismType; CFDataRef data = NULL; uint8_t *p; - int vt_extradata_size = 23 + 5 + vps->data_size + 5 + sps->data_size + 3; + int vt_extradata_size = 23 + 3 + 3 + 3; uint8_t *vt_extradata; - for (i = 0; i < HEVC_MAX_PPS_COUNT; i++) { - if (h->ps.pps_list[i]) { - const HEVCPPS *pps = (const HEVCPPS *)h->ps.pps_list[i]->data; - vt_extradata_size += 2 + pps->data_size; - num_pps++; - } +#define COUNT_SIZE_PS(T, t) \ + for (i = 0; i < HEVC_MAX_##T##PS_COUNT; i++) { \ + if (h->ps.t##ps_list[i]) { \ + const HEVC##T##PS *lps = (const HEVC##T##PS *)h->ps.t##ps_list[i]->data; \ + vt_extradata_size += 2 + lps->data_size; \ + num_##t##ps++; \ + } \ } + COUNT_SIZE_PS(V, v) + COUNT_SIZE_PS(S, s) + COUNT_SIZE_PS(P, p) + vt_extradata = av_malloc(vt_extradata_size); if (!vt_extradata) return NULL; @@ -286,44 +292,33 @@ CFDataRef ff_videotoolbox_hvcc_extradata_create(AVCodecContext *avctx) AV_W8(p + 22, 3); p += 23; - /* vps */ - /* - * bit(1) array_completeness; - * unsigned int(1) reserved = 0; - * unsigned int(6) NAL_unit_type; - */ - AV_W8(p, 1 << 7 | - HEVC_NAL_VPS & 0x3f); - /* unsigned int(16) numNalus; */ - AV_WB16(p + 1, 1); - /* unsigned int(16) nalUnitLength; */ - AV_WB16(p + 3, vps->data_size); - /* bit(8*nalUnitLength) nalUnit; */ - memcpy(p + 5, vps->data, vps->data_size); - p += 5 + vps->data_size; - /* sps */ - AV_W8(p, 1 << 7 | - HEVC_NAL_SPS & 0x3f); - AV_WB16(p + 1, 1); - AV_WB16(p + 3, sps->data_size); - memcpy(p + 5, sps->data, sps->data_size); - p += 5 + sps->data_size; - - /* pps */ - AV_W8(p, 1 << 7 | - HEVC_NAL_PPS & 0x3f); - AV_WB16(p + 1, num_pps); - p += 3; - for (i = 0; i < HEVC_MAX_PPS_COUNT; i++) { - if (h->ps.pps_list[i]) { - const HEVCPPS *pps = (const HEVCPPS *)h->ps.pps_list[i]->data; - AV_WB16(p, pps->data_size); - memcpy(p + 2, pps->data, pps->data_size); - p += 2 + pps->data_size; - } +#define APPEND_PS(T, t) \ + /* \ + * bit(1) array_completeness; \ + * unsigned int(1) reserved = 0; \ + * unsigned int(6) NAL_unit_type; \ + */ \ + AV_W8(p, 1 << 7 | \ + HEVC_NAL_##T##PS & 0x3f); \ + /* unsigned int(16) numNalus; */ \ + AV_WB16(p + 1, num_##t##ps); \ + p += 3; \ + for (i = 0; i < HEVC_MAX_##T##PS_COUNT; i++) { \ + if (h->ps.t##ps_list[i]) { \ + const HEVC##T##PS *lps = (const HEVC##T##PS *)h->ps.t##ps_list[i]->data; \ + /* unsigned int(16) nalUnitLength; */ \ + AV_WB16(p, lps->data_size); \ + /* bit(8*nalUnitLength) nalUnit; */ \ + memcpy(p + 2, lps->data, lps->data_size); \ + p += 2 + lps->data_size; \ + } \ } + APPEND_PS(V, v) + APPEND_PS(S, s) + APPEND_PS(P, p) + av_assert0(p - vt_extradata == vt_extradata_size); data = CFDataCreate(kCFAllocatorDefault, vt_extradata, vt_extradata_size); @@ -903,6 +898,11 @@ static int videotoolbox_common_end_frame(AVCodecContext *avctx, AVFrame *frame) AVVideotoolboxContext *videotoolbox = videotoolbox_get_context(avctx); VTContext *vtctx = avctx->internal->hwaccel_priv_data; + frame->crop_right = 0; + frame->crop_left = 0; + frame->crop_top = 0; + frame->crop_bottom = 0; + if (vtctx->reconfig_needed == true) { vtctx->reconfig_needed = false; av_log(avctx, AV_LOG_VERBOSE, "VideoToolbox decoder needs reconfig, restarting..\n"); @@ -969,6 +969,12 @@ static int videotoolbox_hevc_end_frame(AVCodecContext *avctx) HEVCContext *h = avctx->priv_data; AVFrame *frame = h->ref->frame; VTContext *vtctx = avctx->internal->hwaccel_priv_data; + + h->output_frame->crop_right = 0; + h->output_frame->crop_left = 0; + h->output_frame->crop_top = 0; + h->output_frame->crop_bottom = 0; + int ret = videotoolbox_common_end_frame(avctx, frame); vtctx->bitstream_size = 0; return ret; @@ -1015,6 +1021,19 @@ static int videotoolbox_uninit(AVCodecContext *avctx) return 0; } +static enum AVPixelFormat videotoolbox_best_pixel_format(AVCodecContext *avctx) { + const AVPixFmtDescriptor *descriptor = av_pix_fmt_desc_get(avctx->pix_fmt); + if (!descriptor) + return AV_PIX_FMT_NV12; // same as av_videotoolbox_alloc_context() + + int depth = descriptor->comp[0].depth; + if (depth > 8) { + return AV_PIX_FMT_P010; + } + + return AV_PIX_FMT_NV12; +} + static int videotoolbox_common_init(AVCodecContext *avctx) { VTContext *vtctx = avctx->internal->hwaccel_priv_data; @@ -1048,7 +1067,7 @@ static int videotoolbox_common_init(AVCodecContext *avctx) hw_frames = (AVHWFramesContext*)avctx->hw_frames_ctx->data; hw_frames->format = AV_PIX_FMT_VIDEOTOOLBOX; - hw_frames->sw_format = AV_PIX_FMT_NV12; // same as av_videotoolbox_alloc_context() + hw_frames->sw_format = videotoolbox_best_pixel_format(avctx); hw_frames->width = avctx->width; hw_frames->height = avctx->height; @@ -1092,7 +1111,7 @@ static int videotoolbox_frame_params(AVCodecContext *avctx, frames_ctx->format = AV_PIX_FMT_VIDEOTOOLBOX; frames_ctx->width = avctx->coded_width; frames_ctx->height = avctx->coded_height; - frames_ctx->sw_format = AV_PIX_FMT_NV12; + frames_ctx->sw_format = videotoolbox_best_pixel_format(avctx); return 0; } @@ -1189,18 +1208,28 @@ const AVHWAccel ff_mpeg4_videotoolbox_hwaccel = { .priv_data_size = sizeof(VTContext), }; -AVVideotoolboxContext *av_videotoolbox_alloc_context(void) +static AVVideotoolboxContext *av_videotoolbox_alloc_context_with_pix_fmt(enum AVPixelFormat pix_fmt) { AVVideotoolboxContext *ret = av_mallocz(sizeof(*ret)); if (ret) { ret->output_callback = videotoolbox_decoder_callback; - ret->cv_pix_fmt_type = kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange; + + OSType cv_pix_fmt_type = av_map_videotoolbox_format_from_pixfmt(pix_fmt); + if (cv_pix_fmt_type == 0) { + cv_pix_fmt_type = kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange; + } + ret->cv_pix_fmt_type = cv_pix_fmt_type; } return ret; } +AVVideotoolboxContext *av_videotoolbox_alloc_context(void) +{ + return av_videotoolbox_alloc_context_with_pix_fmt(AV_PIX_FMT_NONE); +} + int av_videotoolbox_default_init(AVCodecContext *avctx) { return av_videotoolbox_default_init2(avctx, NULL); @@ -1208,7 +1237,7 @@ int av_videotoolbox_default_init(AVCodecContext *avctx) int av_videotoolbox_default_init2(AVCodecContext *avctx, AVVideotoolboxContext *vtctx) { - avctx->hwaccel_context = vtctx ?: av_videotoolbox_alloc_context(); + avctx->hwaccel_context = vtctx ?: av_videotoolbox_alloc_context_with_pix_fmt(videotoolbox_best_pixel_format(avctx)); if (!avctx->hwaccel_context) return AVERROR(ENOMEM); return videotoolbox_start(avctx); diff --git a/libavcodec/videotoolboxenc.c b/libavcodec/videotoolboxenc.c index 50aba2d87..ff33c279c 100644 --- a/libavcodec/videotoolboxenc.c +++ b/libavcodec/videotoolboxenc.c @@ -39,6 +39,11 @@ enum { kCMVideoCodecType_HEVC = 'hvc1' }; #endif +#if !HAVE_KCVPIXELFORMATTYPE_420YPCBCR10BIPLANARVIDEORANGE +enum { kCVPixelFormatType_420YpCbCr10BiPlanarFullRange = 'xf20' }; +enum { kCVPixelFormatType_420YpCbCr10BiPlanarVideoRange = 'x420' }; +#endif + typedef OSStatus (*getParameterSetAtIndex)(CMFormatDescriptionRef videoDesc, size_t parameterSetIndex, const uint8_t **parameterSetPointerOut, @@ -210,6 +215,7 @@ typedef struct VTEncContext { int64_t frames_after; int64_t allow_sw; + int64_t require_sw; bool flushing; bool has_b_frames; @@ -761,6 +767,11 @@ static int get_cv_pixel_format(AVCodecContext* avctx, *av_pixel_format = range == AVCOL_RANGE_JPEG ? kCVPixelFormatType_420YpCbCr8PlanarFullRange : kCVPixelFormatType_420YpCbCr8Planar; + } else if (fmt == AV_PIX_FMT_P010LE) { + *av_pixel_format = range == AVCOL_RANGE_JPEG ? + kCVPixelFormatType_420YpCbCr10BiPlanarFullRange : + kCVPixelFormatType_420YpCbCr10BiPlanarVideoRange; + *av_pixel_format = kCVPixelFormatType_420YpCbCr10BiPlanarVideoRange; } else { return AVERROR(EINVAL); } @@ -1314,7 +1325,11 @@ static int vtenc_configure_encoder(AVCodecContext *avctx) if (!enc_info) return AVERROR(ENOMEM); #if !TARGET_OS_IPHONE - if (!vtctx->allow_sw) { + if(vtctx->require_sw) { + CFDictionarySetValue(enc_info, + compat_keys.kVTVideoEncoderSpecification_EnableHardwareAcceleratedVideoEncoder, + kCFBooleanFalse); + } else if (!vtctx->allow_sw) { CFDictionarySetValue(enc_info, compat_keys.kVTVideoEncoderSpecification_RequireHardwareAcceleratedVideoEncoder, kCFBooleanTrue); @@ -1981,6 +1996,17 @@ static int get_cv_pixel_info( strides[2] = frame ? frame->linesize[2] : (avctx->width + 1) / 2; break; + case AV_PIX_FMT_P010LE: + *plane_count = 2; + widths[0] = avctx->width; + heights[0] = avctx->height; + strides[0] = frame ? frame->linesize[0] : (avctx->width * 2 + 63) & -64; + + widths[1] = (avctx->width + 1) / 2; + heights[1] = (avctx->height + 1) / 2; + strides[1] = frame ? frame->linesize[1] : ((avctx->width + 1) / 2 + 63) & -64; + break; + default: av_log( avctx, @@ -2006,19 +2032,6 @@ static int get_cv_pixel_info( return 0; } -#if !TARGET_OS_IPHONE -//Not used on iOS - frame is always copied. -static void free_avframe( - void *release_ctx, - const void *data, - size_t size, - size_t plane_count, - const void *plane_addresses[]) -{ - AVFrame *frame = release_ctx; - av_frame_free(&frame); -} -#else //Not used on OSX - frame is never copied. static int copy_avframe_to_pixel_buffer(AVCodecContext *avctx, const AVFrame *frame, @@ -2111,7 +2124,6 @@ static int copy_avframe_to_pixel_buffer(AVCodecContext *avctx, return 0; } -#endif //!TARGET_OS_IPHONE static int create_cv_pixel_buffer(AVCodecContext *avctx, const AVFrame *frame, @@ -2124,18 +2136,8 @@ static int create_cv_pixel_buffer(AVCodecContext *avctx, size_t strides[AV_NUM_DATA_POINTERS]; int status; size_t contiguous_buf_size; -#if TARGET_OS_IPHONE CVPixelBufferPoolRef pix_buf_pool; VTEncContext* vtctx = avctx->priv_data; -#else - CFMutableDictionaryRef pix_buf_attachments = CFDictionaryCreateMutable( - kCFAllocatorDefault, - 10, - &kCFCopyStringDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); - - if (!pix_buf_attachments) return AVERROR(ENOMEM); -#endif if (avctx->pix_fmt == AV_PIX_FMT_VIDEOTOOLBOX) { av_assert0(frame->format == AV_PIX_FMT_VIDEOTOOLBOX); @@ -2175,7 +2177,6 @@ static int create_cv_pixel_buffer(AVCodecContext *avctx, return AVERROR_EXTERNAL; } -#if TARGET_OS_IPHONE pix_buf_pool = VTCompressionSessionGetPixelBufferPool(vtctx->session); if (!pix_buf_pool) { /* On iOS, the VT session is invalidated when the APP switches from @@ -2217,43 +2218,6 @@ static int create_cv_pixel_buffer(AVCodecContext *avctx, *cv_img = NULL; return status; } -#else - AVFrame *enc_frame = av_frame_alloc(); - if (!enc_frame) return AVERROR(ENOMEM); - - status = av_frame_ref(enc_frame, frame); - if (status) { - av_frame_free(&enc_frame); - return status; - } - - status = CVPixelBufferCreateWithPlanarBytes( - kCFAllocatorDefault, - enc_frame->width, - enc_frame->height, - color, - NULL, - contiguous_buf_size, - plane_count, - (void **)enc_frame->data, - widths, - heights, - strides, - free_avframe, - enc_frame, - NULL, - cv_img - ); - - add_color_attr(avctx, pix_buf_attachments); - CVBufferSetAttachments(*cv_img, pix_buf_attachments, kCVAttachmentMode_ShouldPropagate); - CFRelease(pix_buf_attachments); - - if (status) { - av_log(avctx, AV_LOG_ERROR, "Error: Could not create CVPixelBuffer: %d\n", status); - return AVERROR_EXTERNAL; - } -#endif return 0; } @@ -2405,21 +2369,11 @@ static int vtenc_populate_extradata(AVCodecContext *avctx, CFDictionaryRef pixel_buffer_info) { VTEncContext *vtctx = avctx->priv_data; - AVFrame *frame = av_frame_alloc(); - int y_size = avctx->width * avctx->height; - int chroma_size = (avctx->width / 2) * (avctx->height / 2); - CMSampleBufferRef buf = NULL; int status; - - if (!frame) - return AVERROR(ENOMEM); - - frame->buf[0] = av_buffer_alloc(y_size + 2 * chroma_size); - - if(!frame->buf[0]){ - status = AVERROR(ENOMEM); - goto pe_cleanup; - } + CVPixelBufferPoolRef pool = NULL; + CVPixelBufferRef pix_buf = NULL; + CMTime time; + CMSampleBufferRef buf = NULL; status = vtenc_create_encoder(avctx, codec_type, @@ -2431,39 +2385,36 @@ static int vtenc_populate_extradata(AVCodecContext *avctx, if (status) goto pe_cleanup; - frame->data[0] = frame->buf[0]->data; - memset(frame->data[0], 0, y_size); - - frame->data[1] = frame->buf[0]->data + y_size; - memset(frame->data[1], 128, chroma_size); - - - if (avctx->pix_fmt == AV_PIX_FMT_YUV420P) { - frame->data[2] = frame->buf[0]->data + y_size + chroma_size; - memset(frame->data[2], 128, chroma_size); + pool = VTCompressionSessionGetPixelBufferPool(vtctx->session); + if(!pool){ + av_log(avctx, AV_LOG_ERROR, "Error getting pixel buffer pool.\n"); + goto pe_cleanup; } - frame->linesize[0] = avctx->width; + status = CVPixelBufferPoolCreatePixelBuffer(NULL, + pool, + &pix_buf); - if (avctx->pix_fmt == AV_PIX_FMT_YUV420P) { - frame->linesize[1] = - frame->linesize[2] = (avctx->width + 1) / 2; - } else { - frame->linesize[1] = (avctx->width + 1) / 2; + if(status != kCVReturnSuccess){ + av_log(avctx, AV_LOG_ERROR, "Error creating frame from pool: %d\n", status); + goto pe_cleanup; } - frame->format = avctx->pix_fmt; - frame->width = avctx->width; - frame->height = avctx->height; - frame->colorspace = avctx->colorspace; - frame->color_range = avctx->color_range; - frame->color_trc = avctx->color_trc; - frame->color_primaries = avctx->color_primaries; + time = CMTimeMake(0, avctx->time_base.den); + status = VTCompressionSessionEncodeFrame(vtctx->session, + pix_buf, + time, + kCMTimeInvalid, + NULL, + NULL, + NULL); - frame->pts = 0; - status = vtenc_send_frame(avctx, vtctx, frame); if (status) { - av_log(avctx, AV_LOG_ERROR, "Error sending frame: %d\n", status); + av_log(avctx, + AV_LOG_ERROR, + "Error sending frame for extradata: %d\n", + status); + goto pe_cleanup; } @@ -2491,9 +2442,6 @@ pe_cleanup: vtctx->session = NULL; vtctx->frame_ct_out = 0; - av_frame_unref(frame); - av_frame_free(&frame); - av_assert0(status != 0 || (avctx->extradata && avctx->extradata_size > 0)); return status; @@ -2532,17 +2480,27 @@ static av_cold int vtenc_close(AVCodecContext *avctx) return 0; } -static const enum AVPixelFormat pix_fmts[] = { +static const enum AVPixelFormat avc_pix_fmts[] = { AV_PIX_FMT_VIDEOTOOLBOX, AV_PIX_FMT_NV12, AV_PIX_FMT_YUV420P, AV_PIX_FMT_NONE }; +static const enum AVPixelFormat hevc_pix_fmts[] = { + AV_PIX_FMT_VIDEOTOOLBOX, + AV_PIX_FMT_NV12, + AV_PIX_FMT_YUV420P, + AV_PIX_FMT_P010LE, + AV_PIX_FMT_NONE +}; + #define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM #define COMMON_OPTIONS \ { "allow_sw", "Allow software encoding", OFFSET(allow_sw), AV_OPT_TYPE_BOOL, \ { .i64 = 0 }, 0, 1, VE }, \ + { "require_sw", "Require software encoding", OFFSET(require_sw), AV_OPT_TYPE_BOOL, \ + { .i64 = 0 }, 0, 1, VE }, \ { "realtime", "Hint that encoding should happen in real-time if not faster (e.g. capturing from camera).", \ OFFSET(realtime), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, \ { "frames_before", "Other frames will come before the frames in this session. This helps smooth concatenation issues.", \ @@ -2594,7 +2552,7 @@ AVCodec ff_h264_videotoolbox_encoder = { .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_H264, .priv_data_size = sizeof(VTEncContext), - .pix_fmts = pix_fmts, + .pix_fmts = avc_pix_fmts, .init = vtenc_init, .encode2 = vtenc_frame, .close = vtenc_close, @@ -2626,7 +2584,7 @@ AVCodec ff_hevc_videotoolbox_encoder = { .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_HEVC, .priv_data_size = sizeof(VTEncContext), - .pix_fmts = pix_fmts, + .pix_fmts = hevc_pix_fmts, .init = vtenc_init, .encode2 = vtenc_frame, .close = vtenc_close, diff --git a/libavcodec/vmnc.c b/libavcodec/vmnc.c index 30b1414e4..e27304331 100644 --- a/libavcodec/vmnc.c +++ b/libavcodec/vmnc.c @@ -333,11 +333,15 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, uint8_t *outptr; int dx, dy, w, h, depth, enc, chunks, res, size_left, ret; + bytestream2_init(gb, buf, buf_size); + bytestream2_skip(gb, 2); + chunks = bytestream2_get_be16(gb); + if (12LL * chunks > bytestream2_get_bytes_left(gb)) + return AVERROR_INVALIDDATA; + if ((ret = ff_reget_buffer(avctx, c->pic)) < 0) return ret; - bytestream2_init(gb, buf, buf_size); - c->pic->key_frame = 0; c->pic->pict_type = AV_PICTURE_TYPE_P; @@ -369,8 +373,7 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, } } } - bytestream2_skip(gb, 2); - chunks = bytestream2_get_be16(gb); + while (chunks--) { if (bytestream2_get_bytes_left(gb) < 12) { av_log(avctx, AV_LOG_ERROR, "Premature end of data!\n"); diff --git a/libavcodec/vorbisdec.c b/libavcodec/vorbisdec.c index 00e9cd8a1..be6d1b2d2 100644 --- a/libavcodec/vorbisdec.c +++ b/libavcodec/vorbisdec.c @@ -1097,13 +1097,14 @@ static int vorbis_floor0_decode(vorbis_context *vc, { vorbis_floor0 *vf = &vfu->t0; float *lsp = vf->lsp; - unsigned amplitude, book_idx; + unsigned book_idx; + uint64_t amplitude; unsigned blockflag = vc->modes[vc->mode_number].blockflag; if (!vf->amplitude_bits) return 1; - amplitude = get_bits(&vc->gb, vf->amplitude_bits); + amplitude = get_bits64(&vc->gb, vf->amplitude_bits); if (amplitude > 0) { float last = 0; unsigned idx, lsp_len = 0; @@ -1127,8 +1128,10 @@ static int vorbis_floor0_decode(vorbis_context *vc, ff_dlog(NULL, "floor0 dec: maximum depth: %d\n", codebook.maxdepth); /* read temp vector */ vec_off = get_vlc2(&vc->gb, codebook.vlc.table, - codebook.nb_bits, codebook.maxdepth) - * codebook.dimensions; + codebook.nb_bits, codebook.maxdepth); + if (vec_off < 0) + return AVERROR_INVALIDDATA; + vec_off *= codebook.dimensions; ff_dlog(NULL, "floor0 dec: vector offset: %d\n", vec_off); /* copy each vector component and add last to it */ for (idx = 0; idx < codebook.dimensions; ++idx) @@ -1179,9 +1182,12 @@ static int vorbis_floor0_decode(vorbis_context *vc, q *= q; } + if (p + q == 0.0) + return AVERROR_INVALIDDATA; + /* calculate linear floor value */ q = exp((((amplitude*vf->amplitude_offset) / - (((1 << vf->amplitude_bits) - 1) * sqrt(p + q))) + (((1ULL << vf->amplitude_bits) - 1) * sqrt(p + q))) - vf->amplitude_offset) * .11512925f); /* fill vector */ @@ -1355,8 +1361,12 @@ static av_always_inline int setup_classifs(vorbis_context *vc, return AVERROR_INVALIDDATA; } - av_assert0(vr->classifications > 1); //needed for inverse[] - + if (vr->classifications == 1) { + for (i = partition_count + c_p_c - 1; i >= partition_count; i--) { + if (i < ptns_to_read) + vr->classifs[p + i] = 0; + } + } else { for (i = partition_count + c_p_c - 1; i >= partition_count; i--) { temp2 = (((uint64_t)temp) * inverse_class) >> 32; @@ -1364,6 +1374,7 @@ static av_always_inline int setup_classifs(vorbis_context *vc, vr->classifs[p + i] = temp - temp2 * vr->classifications; temp = temp2; } + } } p += ptns_to_read; } @@ -1431,7 +1442,7 @@ static av_always_inline int vorbis_residue_decode_internal(vorbis_context *vc, int vqbook = vr->books[vqclass][pass]; if (vqbook >= 0 && vc->codebooks[vqbook].codevectors) { - unsigned coffs; + int coffs; unsigned dim = vc->codebooks[vqbook].dimensions; unsigned step = FASTDIV(vr->partition_size << 1, dim << 1); vorbis_codebook codebook = vc->codebooks[vqbook]; @@ -1440,14 +1451,20 @@ static av_always_inline int vorbis_residue_decode_internal(vorbis_context *vc, voffs = voffset+j*vlen; for (k = 0; k < step; ++k) { - coffs = get_vlc2(gb, codebook.vlc.table, codebook.nb_bits, 3) * dim; + coffs = get_vlc2(gb, codebook.vlc.table, codebook.nb_bits, 3); + if (coffs < 0) + return coffs; + coffs *= dim; for (l = 0; l < dim; ++l) vec[voffs + k + l * step] += codebook.codevectors[coffs + l]; } } else if (vr_type == 1) { voffs = voffset + j * vlen; for (k = 0; k < step; ++k) { - coffs = get_vlc2(gb, codebook.vlc.table, codebook.nb_bits, 3) * dim; + coffs = get_vlc2(gb, codebook.vlc.table, codebook.nb_bits, 3); + if (coffs < 0) + return coffs; + coffs *= dim; for (l = 0; l < dim; ++l, ++voffs) { vec[voffs]+=codebook.codevectors[coffs+l]; @@ -1460,13 +1477,19 @@ static av_always_inline int vorbis_residue_decode_internal(vorbis_context *vc, if (dim == 2) { for (k = 0; k < step; ++k) { - coffs = get_vlc2(gb, codebook.vlc.table, codebook.nb_bits, 3) * 2; + coffs = get_vlc2(gb, codebook.vlc.table, codebook.nb_bits, 3); + if (coffs < 0) + return coffs; + coffs *= 2; vec[voffs + k ] += codebook.codevectors[coffs ]; vec[voffs + k + vlen] += codebook.codevectors[coffs + 1]; } } else if (dim == 4) { for (k = 0; k < step; ++k, voffs += 2) { - coffs = get_vlc2(gb, codebook.vlc.table, codebook.nb_bits, 3) * 4; + coffs = get_vlc2(gb, codebook.vlc.table, codebook.nb_bits, 3); + if (coffs < 0) + return coffs; + coffs *= 4; vec[voffs ] += codebook.codevectors[coffs ]; vec[voffs + 1 ] += codebook.codevectors[coffs + 2]; vec[voffs + vlen ] += codebook.codevectors[coffs + 1]; @@ -1474,7 +1497,10 @@ static av_always_inline int vorbis_residue_decode_internal(vorbis_context *vc, } } else for (k = 0; k < step; ++k) { - coffs = get_vlc2(gb, codebook.vlc.table, codebook.nb_bits, 3) * dim; + coffs = get_vlc2(gb, codebook.vlc.table, codebook.nb_bits, 3); + if (coffs < 0) + return coffs; + coffs *= dim; for (l = 0; l < dim; l += 2, voffs++) { vec[voffs ] += codebook.codevectors[coffs + l ]; vec[voffs + vlen] += codebook.codevectors[coffs + l + 1]; @@ -1487,11 +1513,14 @@ static av_always_inline int vorbis_residue_decode_internal(vorbis_context *vc, } } else if (vr_type == 2) { - unsigned voffs_div = FASTDIV(voffset << 1, ch <<1); + unsigned voffs_div = ch == 1 ? voffset : FASTDIV(voffset, ch); unsigned voffs_mod = voffset - voffs_div * ch; for (k = 0; k < step; ++k) { - coffs = get_vlc2(gb, codebook.vlc.table, codebook.nb_bits, 3) * dim; + coffs = get_vlc2(gb, codebook.vlc.table, codebook.nb_bits, 3); + if (coffs < 0) + return coffs; + coffs *= dim; for (l = 0; l < dim; ++l) { vec[voffs_div + voffs_mod * vlen] += codebook.codevectors[coffs + l]; diff --git a/libavcodec/vp3.c b/libavcodec/vp3.c index 1d8375331..a2bd2ef07 100644 --- a/libavcodec/vp3.c +++ b/libavcodec/vp3.c @@ -1,5 +1,6 @@ /* * Copyright (C) 2003-2004 The FFmpeg project + * Copyright (C) 2019 Peter Ross * * This file is part of FFmpeg. * @@ -20,7 +21,7 @@ /** * @file - * On2 VP3 Video Decoder + * On2 VP3/VP4 Video Decoder * * VP3 Video Decoder by Mike Melanson (mike at multimedia.cx) * For more information about the VP3 coding process, visit: @@ -43,6 +44,7 @@ #include "thread.h" #include "videodsp.h" #include "vp3data.h" +#include "vp4data.h" #include "vp3dsp.h" #include "xiph.h" @@ -127,6 +129,30 @@ static const uint8_t hilbert_offset[16][2] = { { 3, 1 }, { 2, 1 }, { 2, 0 }, { 3, 0 } }; +enum { + VP4_DC_INTRA = 0, + VP4_DC_INTER = 1, + VP4_DC_GOLDEN = 2, + NB_VP4_DC_TYPES, + VP4_DC_UNDEFINED = NB_VP4_DC_TYPES +}; + +static const uint8_t vp4_pred_block_type_map[8] = { + [MODE_INTER_NO_MV] = VP4_DC_INTER, + [MODE_INTRA] = VP4_DC_INTRA, + [MODE_INTER_PLUS_MV] = VP4_DC_INTER, + [MODE_INTER_LAST_MV] = VP4_DC_INTER, + [MODE_INTER_PRIOR_LAST] = VP4_DC_INTER, + [MODE_USING_GOLDEN] = VP4_DC_GOLDEN, + [MODE_GOLDEN_MV] = VP4_DC_GOLDEN, + [MODE_INTER_FOURMV] = VP4_DC_INTER, +}; + +typedef struct { + int dc; + int type; +} VP4Predictor; + #define MIN_DEQUANT_VAL 2 typedef struct Vp3DecodeContext { @@ -164,9 +190,13 @@ typedef struct Vp3DecodeContext { int v_superblock_start; unsigned char *superblock_coding; - int macroblock_count; + int macroblock_count; /* y macroblock count */ int macroblock_width; int macroblock_height; + int c_macroblock_count; + int c_macroblock_width; + int c_macroblock_height; + int yuv_macroblock_count; /* y+u+v macroblock count */ int fragment_count; int fragment_width[2]; @@ -182,7 +212,7 @@ typedef struct Vp3DecodeContext { int8_t (*motion_val[2])[2]; /* tables */ - uint16_t coded_dc_scale_factor[64]; + uint16_t coded_dc_scale_factor[2][64]; uint32_t coded_ac_scale_factor[64]; uint8_t base_matrix[384][64]; uint8_t qr_count[2][3]; @@ -223,16 +253,22 @@ typedef struct Vp3DecodeContext { * which of the fragments are coded */ int *coded_fragment_list[3]; + int *kf_coded_fragment_list; + int *nkf_coded_fragment_list; + int num_kf_coded_fragment[3]; + VLC dc_vlc[16]; VLC ac_vlc_1[16]; VLC ac_vlc_2[16]; VLC ac_vlc_3[16]; VLC ac_vlc_4[16]; - VLC superblock_run_length_vlc; - VLC fragment_run_length_vlc; + VLC superblock_run_length_vlc; /* version < 2 */ + VLC fragment_run_length_vlc; /* version < 2 */ + VLC block_pattern_vlc[2]; /* version >= 2*/ VLC mode_code_vlc; - VLC motion_vector_vlc; + VLC motion_vector_vlc; /* version < 2 */ + VLC vp4_mv_vlc[2][7]; /* version >=2 */ /* these arrays need to be on 16-byte boundaries since SSE2 operations * index into them */ @@ -259,6 +295,8 @@ typedef struct Vp3DecodeContext { uint8_t filter_limit_values[64]; DECLARE_ALIGNED(8, int, bounding_values_array)[256 + 2]; + + VP4Predictor * dc_pred_row; /* dc_pred_row[y_superblock_width * 4] */ } Vp3DecodeContext; /************************************************************************ @@ -271,10 +309,12 @@ static av_cold void free_tables(AVCodecContext *avctx) av_freep(&s->superblock_coding); av_freep(&s->all_fragments); - av_freep(&s->coded_fragment_list[0]); + av_freep(&s->nkf_coded_fragment_list); + av_freep(&s->kf_coded_fragment_list); av_freep(&s->dct_tokens_base); av_freep(&s->superblock_fragments); av_freep(&s->macroblock_coding); + av_freep(&s->dc_pred_row); av_freep(&s->motion_val[0]); av_freep(&s->motion_val[1]); } @@ -294,7 +334,7 @@ static void vp3_decode_flush(AVCodecContext *avctx) static av_cold int vp3_decode_end(AVCodecContext *avctx) { Vp3DecodeContext *s = avctx->priv_data; - int i; + int i, j; free_tables(avctx); av_freep(&s->edge_emu_buffer); @@ -323,6 +363,12 @@ static av_cold int vp3_decode_end(AVCodecContext *avctx) ff_free_vlc(&s->mode_code_vlc); ff_free_vlc(&s->motion_vector_vlc); + for (j = 0; j < 2; j++) + for (i = 0; i < 7; i++) + ff_free_vlc(&s->vp4_mv_vlc[j][i]); + + for (i = 0; i < 2; i++) + ff_free_vlc(&s->block_pattern_vlc[i]); return 0; } @@ -370,11 +416,11 @@ static int init_block_mapping(Vp3DecodeContext *s) static void init_dequantizer(Vp3DecodeContext *s, int qpi) { int ac_scale_factor = s->coded_ac_scale_factor[s->qps[qpi]]; - int dc_scale_factor = s->coded_dc_scale_factor[s->qps[qpi]]; int i, plane, inter, qri, bmi, bmj, qistart; for (inter = 0; inter < 2; inter++) { for (plane = 0; plane < 3; plane++) { + int dc_scale_factor = s->coded_dc_scale_factor[!!plane][s->qps[qpi]]; int sum = 0; for (qri = 0; qri < s->qr_count[inter][plane]; qri++) { sum += s->qr_size[inter][plane][qri]; @@ -392,9 +438,10 @@ static void init_dequantizer(Vp3DecodeContext *s, int qpi) int qmin = 8 << (inter + !i); int qscale = i ? ac_scale_factor : dc_scale_factor; - + int qbias = (1 + inter) * 3; s->qmat[qpi][inter][plane][s->idct_permutation[i]] = - av_clip((qscale * coeff) / 100 * 4, qmin, 4096); + (i == 0 || s->version < 2) ? av_clip((qscale * coeff) / 100 * 4, qmin, 4096) + : (qscale * (coeff - qbias) / 100 + qbias) * 4; } /* all DC coefficients use the same quant so as not to interfere * with DC prediction */ @@ -411,27 +458,7 @@ static void init_dequantizer(Vp3DecodeContext *s, int qpi) */ static void init_loop_filter(Vp3DecodeContext *s) { - int *bounding_values = s->bounding_values_array + 127; - int filter_limit; - int x; - int value; - - filter_limit = s->filter_limit_values[s->qps[0]]; - av_assert0(filter_limit < 128U); - - /* set up the bounding values */ - memset(s->bounding_values_array, 0, 256 * sizeof(int)); - for (x = 0; x < filter_limit; x++) { - bounding_values[-x] = -x; - bounding_values[x] = x; - } - for (x = value = filter_limit; x < 128 && value; x++, value--) { - bounding_values[ x] = value; - bounding_values[-x] = -value; - } - if (value) - bounding_values[128] = value; - bounding_values[129] = bounding_values[130] = filter_limit * 0x02020202; + ff_vp3dsp_set_bounding_values(s->bounding_values_array, s->filter_limit_values[s->qps[0]]); } /* @@ -451,6 +478,7 @@ static int unpack_superblocks(Vp3DecodeContext *s, GetBitContext *gb) int i, j; int current_fragment; int plane; + int plane0_num_coded_frags = 0; if (s->keyframe) { memset(s->superblock_coding, SB_FULLY_CODED, s->superblock_count); @@ -537,45 +565,71 @@ static int unpack_superblocks(Vp3DecodeContext *s, GetBitContext *gb) s->total_num_coded_frags = 0; memset(s->macroblock_coding, MODE_COPY, s->macroblock_count); + s->coded_fragment_list[0] = s->keyframe ? s->kf_coded_fragment_list + : s->nkf_coded_fragment_list; + for (plane = 0; plane < 3; plane++) { int sb_start = superblock_starts[plane]; int sb_end = sb_start + (plane ? s->c_superblock_count : s->y_superblock_count); int num_coded_frags = 0; - for (i = sb_start; i < sb_end && get_bits_left(gb) > 0; i++) { - /* iterate through all 16 fragments in a superblock */ - for (j = 0; j < 16; j++) { - /* if the fragment is in bounds, check its coding status */ - current_fragment = s->superblock_fragments[i * 16 + j]; - if (current_fragment != -1) { - int coded = s->superblock_coding[i]; - - if (s->superblock_coding[i] == SB_PARTIALLY_CODED) { - /* fragment may or may not be coded; this is the case - * that cares about the fragment coding runs */ - if (current_run-- == 0) { - bit ^= 1; - current_run = get_vlc2(gb, s->fragment_run_length_vlc.table, 5, 2); + if (s->keyframe) { + if (s->num_kf_coded_fragment[plane] == -1) { + for (i = sb_start; i < sb_end; i++) { + /* iterate through all 16 fragments in a superblock */ + for (j = 0; j < 16; j++) { + /* if the fragment is in bounds, check its coding status */ + current_fragment = s->superblock_fragments[i * 16 + j]; + if (current_fragment != -1) { + s->coded_fragment_list[plane][num_coded_frags++] = + current_fragment; } - coded = bit; } + } + s->num_kf_coded_fragment[plane] = num_coded_frags; + } else + num_coded_frags = s->num_kf_coded_fragment[plane]; + } else { + for (i = sb_start; i < sb_end && get_bits_left(gb) > 0; i++) { + if (get_bits_left(gb) < plane0_num_coded_frags >> 2) { + return AVERROR_INVALIDDATA; + } + /* iterate through all 16 fragments in a superblock */ + for (j = 0; j < 16; j++) { + /* if the fragment is in bounds, check its coding status */ + current_fragment = s->superblock_fragments[i * 16 + j]; + if (current_fragment != -1) { + int coded = s->superblock_coding[i]; - if (coded) { - /* default mode; actual mode will be decoded in - * the next phase */ - s->all_fragments[current_fragment].coding_method = - MODE_INTER_NO_MV; - s->coded_fragment_list[plane][num_coded_frags++] = - current_fragment; - } else { - /* not coded; copy this fragment from the prior frame */ - s->all_fragments[current_fragment].coding_method = - MODE_COPY; + if (coded == SB_PARTIALLY_CODED) { + /* fragment may or may not be coded; this is the case + * that cares about the fragment coding runs */ + if (current_run-- == 0) { + bit ^= 1; + current_run = get_vlc2(gb, s->fragment_run_length_vlc.table, 5, 2); + } + coded = bit; + } + + if (coded) { + /* default mode; actual mode will be decoded in + * the next phase */ + s->all_fragments[current_fragment].coding_method = + MODE_INTER_NO_MV; + s->coded_fragment_list[plane][num_coded_frags++] = + current_fragment; + } else { + /* not coded; copy this fragment from the prior frame */ + s->all_fragments[current_fragment].coding_method = + MODE_COPY; + } } } } } + if (!plane) + plane0_num_coded_frags = num_coded_frags; s->total_num_coded_frags += num_coded_frags; for (i = 0; i < 64; i++) s->num_coded_frags[plane][i] = num_coded_frags; @@ -586,6 +640,152 @@ static int unpack_superblocks(Vp3DecodeContext *s, GetBitContext *gb) return 0; } +#define BLOCK_X (2 * mb_x + (k & 1)) +#define BLOCK_Y (2 * mb_y + (k >> 1)) + +#if CONFIG_VP4_DECODER +/** + * @return number of blocks, or > yuv_macroblock_count on error. + * return value is always >= 1. + */ +static int vp4_get_mb_count(Vp3DecodeContext *s, GetBitContext *gb) +{ + int v = 1; + int bits; + while ((bits = show_bits(gb, 9)) == 0x1ff) { + skip_bits(gb, 9); + v += 256; + if (v > s->yuv_macroblock_count) { + av_log(s->avctx, AV_LOG_ERROR, "Invalid run length\n"); + return v; + } + } +#define body(n) { \ + skip_bits(gb, 2 + n); \ + v += (1 << n) + get_bits(gb, n); } +#define thresh(n) (0x200 - (0x80 >> n)) +#define else_if(n) else if (bits < thresh(n)) body(n) + if (bits < 0x100) { + skip_bits(gb, 1); + } else if (bits < thresh(0)) { + skip_bits(gb, 2); + v += 1; + } + else_if(1) + else_if(2) + else_if(3) + else_if(4) + else_if(5) + else_if(6) + else body(7) +#undef body +#undef thresh +#undef else_if + return v; +} + +static int vp4_get_block_pattern(Vp3DecodeContext *s, GetBitContext *gb, int *next_block_pattern_table) +{ + int v = get_vlc2(gb, s->block_pattern_vlc[*next_block_pattern_table].table, 3, 2); + if (v == -1) { + av_log(s->avctx, AV_LOG_ERROR, "Invalid block pattern\n"); + *next_block_pattern_table = 0; + return 0; + } + *next_block_pattern_table = vp4_block_pattern_table_selector[v]; + return v + 1; +} + +static int vp4_unpack_macroblocks(Vp3DecodeContext *s, GetBitContext *gb) +{ + int plane, i, j, k, fragment; + int next_block_pattern_table; + int bit, current_run, has_partial; + + memset(s->macroblock_coding, MODE_COPY, s->macroblock_count); + + if (s->keyframe) + return 0; + + has_partial = 0; + bit = get_bits1(gb); + for (i = 0; i < s->yuv_macroblock_count; i += current_run) { + if (get_bits_left(gb) <= 0) + return AVERROR_INVALIDDATA; + current_run = vp4_get_mb_count(s, gb); + if (current_run > s->yuv_macroblock_count - i) + return -1; + memset(s->superblock_coding + i, 2 * bit, current_run); + bit ^= 1; + has_partial |= bit; + } + + if (has_partial) { + if (get_bits_left(gb) <= 0) + return AVERROR_INVALIDDATA; + bit = get_bits1(gb); + current_run = vp4_get_mb_count(s, gb); + for (i = 0; i < s->yuv_macroblock_count; i++) { + if (!s->superblock_coding[i]) { + if (!current_run) { + bit ^= 1; + current_run = vp4_get_mb_count(s, gb); + } + s->superblock_coding[i] = bit; + current_run--; + } + } + if (current_run) /* handle situation when vp4_get_mb_count() fails */ + return -1; + } + + next_block_pattern_table = 0; + i = 0; + for (plane = 0; plane < 3; plane++) { + int sb_x, sb_y; + int sb_width = plane ? s->c_superblock_width : s->y_superblock_width; + int sb_height = plane ? s->c_superblock_height : s->y_superblock_height; + int mb_width = plane ? s->c_macroblock_width : s->macroblock_width; + int mb_height = plane ? s->c_macroblock_height : s->macroblock_height; + int fragment_width = s->fragment_width[!!plane]; + int fragment_height = s->fragment_height[!!plane]; + + for (sb_y = 0; sb_y < sb_height; sb_y++) { + for (sb_x = 0; sb_x < sb_width; sb_x++) { + for (j = 0; j < 4; j++) { + int mb_x = 2 * sb_x + (j >> 1); + int mb_y = 2 * sb_y + (j >> 1) ^ (j & 1); + int mb_coded, pattern, coded; + + if (mb_x >= mb_width || mb_y >= mb_height) + continue; + + mb_coded = s->superblock_coding[i++]; + + if (mb_coded == SB_FULLY_CODED) + pattern = 0xF; + else if (mb_coded == SB_PARTIALLY_CODED) + pattern = vp4_get_block_pattern(s, gb, &next_block_pattern_table); + else + pattern = 0; + + for (k = 0; k < 4; k++) { + if (BLOCK_X >= fragment_width || BLOCK_Y >= fragment_height) + continue; + fragment = s->fragment_start[plane] + BLOCK_Y * fragment_width + BLOCK_X; + coded = pattern & (8 >> k); + /* MODE_INTER_NO_MV is the default for coded fragments. + the actual method is decoded in the next phase. */ + s->all_fragments[fragment].coding_method = coded ? MODE_INTER_NO_MV : MODE_COPY; + } + } + } + } + } + return 0; +} +#endif + /* * This function unpacks all the coding mode data for individual macroblocks * from the bitstream. @@ -634,8 +834,6 @@ static int unpack_modes(Vp3DecodeContext *s, GetBitContext *gb) mb_y >= s->macroblock_height) continue; -#define BLOCK_X (2 * mb_x + (k & 1)) -#define BLOCK_Y (2 * mb_y + (k >> 1)) /* coding modes are only stored if the macroblock has * at least one luma block coded, otherwise it must be * INTER_NO_MV */ @@ -695,6 +893,12 @@ static int unpack_modes(Vp3DecodeContext *s, GetBitContext *gb) return 0; } +static int vp4_get_mv(Vp3DecodeContext *s, GetBitContext *gb, int axis, int last_motion) +{ + int v = get_vlc2(gb, s->vp4_mv_vlc[axis][vp4_mv_table_selector[FFABS(last_motion)]].table, 6, 2) - 31; + return last_motion < 0 ? -v : v; +} + /* * This function unpacks all the motion vectors for the individual * macroblocks from the bitstream. @@ -709,6 +913,8 @@ static int unpack_vectors(Vp3DecodeContext *s, GetBitContext *gb) int last_motion_y = 0; int prior_last_motion_x = 0; int prior_last_motion_y = 0; + int last_gold_motion_x = 0; + int last_gold_motion_y = 0; int current_macroblock; int current_fragment; int frag; @@ -716,8 +922,8 @@ static int unpack_vectors(Vp3DecodeContext *s, GetBitContext *gb) if (s->keyframe) return 0; - /* coding mode 0 is the VLC scheme; 1 is the fixed code scheme */ - coding_mode = get_bits1(gb); + /* coding mode 0 is the VLC scheme; 1 is the fixed code scheme; 2 is VP4 code scheme */ + coding_mode = s->version < 2 ? get_bits1(gb) : 2; /* iterate through all of the macroblocks that contain 1 or more * coded fragments */ @@ -737,15 +943,23 @@ static int unpack_vectors(Vp3DecodeContext *s, GetBitContext *gb) continue; switch (s->macroblock_coding[current_macroblock]) { - case MODE_INTER_PLUS_MV: case MODE_GOLDEN_MV: + if (coding_mode == 2) { /* VP4 */ + last_gold_motion_x = motion_x[0] = vp4_get_mv(s, gb, 0, last_gold_motion_x); + last_gold_motion_y = motion_y[0] = vp4_get_mv(s, gb, 1, last_gold_motion_y); + break; + } /* otherwise fall through */ + case MODE_INTER_PLUS_MV: /* all 6 fragments use the same motion vector */ if (coding_mode == 0) { motion_x[0] = motion_vector_table[get_vlc2(gb, s->motion_vector_vlc.table, 6, 2)]; motion_y[0] = motion_vector_table[get_vlc2(gb, s->motion_vector_vlc.table, 6, 2)]; - } else { + } else if (coding_mode == 1) { motion_x[0] = fixed_motion_vector_table[get_bits(gb, 6)]; motion_y[0] = fixed_motion_vector_table[get_bits(gb, 6)]; + } else { /* VP4 */ + motion_x[0] = vp4_get_mv(s, gb, 0, last_motion_x); + motion_y[0] = vp4_get_mv(s, gb, 1, last_motion_y); } /* vector maintenance, only on MODE_INTER_PLUS_MV */ @@ -770,9 +984,12 @@ static int unpack_vectors(Vp3DecodeContext *s, GetBitContext *gb) if (coding_mode == 0) { motion_x[k] = motion_vector_table[get_vlc2(gb, s->motion_vector_vlc.table, 6, 2)]; motion_y[k] = motion_vector_table[get_vlc2(gb, s->motion_vector_vlc.table, 6, 2)]; - } else { + } else if (coding_mode == 1) { motion_x[k] = fixed_motion_vector_table[get_bits(gb, 6)]; motion_y[k] = fixed_motion_vector_table[get_bits(gb, 6)]; + } else { /* VP4 */ + motion_x[k] = vp4_get_mv(s, gb, 0, prior_last_motion_x); + motion_y[k] = vp4_get_mv(s, gb, 1, prior_last_motion_y); } last_motion_x = motion_x[k]; last_motion_y = motion_y[k]; @@ -834,8 +1051,10 @@ static int unpack_vectors(Vp3DecodeContext *s, GetBitContext *gb) motion_y[0] = RSHIFT(motion_y[0] + motion_y[1] + motion_y[2] + motion_y[3], 2); } - motion_x[0] = (motion_x[0] >> 1) | (motion_x[0] & 1); - motion_y[0] = (motion_y[0] >> 1) | (motion_y[0] & 1); + if (s->version <= 2) { + motion_x[0] = (motion_x[0] >> 1) | (motion_x[0] & 1); + motion_y[0] = (motion_y[0] >> 1) | (motion_y[0] & 1); + } frag = mb_y * s->fragment_width[1] + mb_x; s->motion_val[1][frag][0] = motion_x[0]; s->motion_val[1][frag][1] = motion_y[0]; @@ -849,9 +1068,10 @@ static int unpack_vectors(Vp3DecodeContext *s, GetBitContext *gb) motion_x[1] = motion_x[0]; motion_y[1] = motion_y[0]; } - motion_x[0] = (motion_x[0] >> 1) | (motion_x[0] & 1); - motion_x[1] = (motion_x[1] >> 1) | (motion_x[1] & 1); - + if (s->version <= 2) { + motion_x[0] = (motion_x[0] >> 1) | (motion_x[0] & 1); + motion_x[1] = (motion_x[1] >> 1) | (motion_x[1] & 1); + } frag = 2 * mb_y * s->fragment_width[1] + mb_x; for (k = 0; k < 2; k++) { s->motion_val[1][frag][0] = motion_x[k]; @@ -919,6 +1139,30 @@ static int unpack_block_qpis(Vp3DecodeContext *s, GetBitContext *gb) return 0; } +static inline int get_eob_run(GetBitContext *gb, int token) +{ + int v = eob_run_table[token].base; + if (eob_run_table[token].bits) + v += get_bits(gb, eob_run_table[token].bits); + return v; +} + +static inline int get_coeff(GetBitContext *gb, int token, int16_t *coeff) +{ + int bits_to_get, zero_run; + + bits_to_get = coeff_get_bits[token]; + if (bits_to_get) + bits_to_get = get_bits(gb, bits_to_get); + *coeff = coeff_tables[token][bits_to_get]; + + zero_run = zero_run_base[token]; + if (zero_run_get_bits[token]) + zero_run += get_bits(gb, zero_run_get_bits[token]); + + return zero_run; +} + /* * This function is called by unpack_dct_coeffs() to extract the VLCs from * the bitstream. The VLCs encode tokens which are used to unpack DCT @@ -940,7 +1184,6 @@ static int unpack_vlcs(Vp3DecodeContext *s, GetBitContext *gb, int token; int zero_run = 0; int16_t coeff = 0; - int bits_to_get; int blocks_ended; int coeff_i = 0; int num_coeffs = s->num_coded_frags[plane][coeff_index]; @@ -976,10 +1219,7 @@ static int unpack_vlcs(Vp3DecodeContext *s, GetBitContext *gb, token = get_vlc2(gb, vlc_table, 11, 3); /* use the token to get a zero run, a coefficient, and an eob run */ if ((unsigned) token <= 6U) { - eob_run = eob_run_base[token]; - if (eob_run_get_bits[token]) - eob_run += get_bits(gb, eob_run_get_bits[token]); - + eob_run = get_eob_run(gb, token); if (!eob_run) eob_run = INT_MAX; @@ -997,14 +1237,7 @@ static int unpack_vlcs(Vp3DecodeContext *s, GetBitContext *gb, eob_run = 0; } } else if (token >= 0) { - bits_to_get = coeff_get_bits[token]; - if (bits_to_get) - bits_to_get = get_bits(gb, bits_to_get); - coeff = coeff_tables[token][bits_to_get]; - - zero_run = zero_run_base[token]; - if (zero_run_get_bits[token]) - zero_run += get_bits(gb, zero_run_get_bits[token]); + zero_run = get_coeff(gb, token, &coeff); if (zero_run) { dct_tokens[j++] = TOKEN_ZERO_RUN(coeff, zero_run); @@ -1156,6 +1389,237 @@ static int unpack_dct_coeffs(Vp3DecodeContext *s, GetBitContext *gb) return 0; } +#if CONFIG_VP4_DECODER +/** + * eob_tracker[] is instead of TOKEN_EOB(value) + * a dummy TOKEN_EOB(0) value is used to make vp3_dequant work + * + * @return < 0 on error + */ +static int vp4_unpack_vlcs(Vp3DecodeContext *s, GetBitContext *gb, + VLC *vlc_tables[64], + int plane, int eob_tracker[64], int fragment) +{ + int token; + int zero_run = 0; + int16_t coeff = 0; + int coeff_i = 0; + int eob_run; + + while (!eob_tracker[coeff_i]) { + if (get_bits_left(gb) < 1) + return AVERROR_INVALIDDATA; + + token = get_vlc2(gb, vlc_tables[coeff_i]->table, 11, 3); + + /* use the token to get a zero run, a coefficient, and an eob run */ + if ((unsigned) token <= 6U) { + eob_run = get_eob_run(gb, token); + *s->dct_tokens[plane][coeff_i]++ = TOKEN_EOB(0); + eob_tracker[coeff_i] = eob_run - 1; + return 0; + } else if (token >= 0) { + zero_run = get_coeff(gb, token, &coeff); + + if (zero_run) { + if (coeff_i + zero_run > 64) { + av_log(s->avctx, AV_LOG_DEBUG, + "Invalid zero run of %d with %d coeffs left\n", + zero_run, 64 - coeff_i); + zero_run = 64 - coeff_i; + } + *s->dct_tokens[plane][coeff_i]++ = TOKEN_ZERO_RUN(coeff, zero_run); + coeff_i += zero_run; + } else { + if (!coeff_i) + s->all_fragments[fragment].dc = coeff; + + *s->dct_tokens[plane][coeff_i]++ = TOKEN_COEFF(coeff); + } + coeff_i++; + if (coeff_i >= 64) /* > 64 occurs when there is a zero_run overflow */ + return 0; /* stop */ + } else { + av_log(s->avctx, AV_LOG_ERROR, "Invalid token %d\n", token); + return -1; + } + } + *s->dct_tokens[plane][coeff_i]++ = TOKEN_EOB(0); + eob_tracker[coeff_i]--; + return 0; +} + +static void vp4_dc_predictor_reset(VP4Predictor *p) +{ + p->dc = 0; + p->type = VP4_DC_UNDEFINED; +} + +static void vp4_dc_pred_before(const Vp3DecodeContext *s, VP4Predictor dc_pred[6][6], int sb_x) +{ + int i, j; + + for (i = 0; i < 4; i++) + dc_pred[0][i + 1] = s->dc_pred_row[sb_x * 4 + i]; + + for (j = 1; j < 5; j++) + for (i = 0; i < 4; i++) + vp4_dc_predictor_reset(&dc_pred[j][i + 1]); +} + +static void vp4_dc_pred_after(Vp3DecodeContext *s, VP4Predictor dc_pred[6][6], int sb_x) +{ + int i; + + for (i = 0; i < 4; i++) + s->dc_pred_row[sb_x * 4 + i] = dc_pred[4][i + 1]; + + for (i = 1; i < 5; i++) + dc_pred[i][0] = dc_pred[i][4]; +} + +/* note: dc_pred points to the current block */ +static int vp4_dc_pred(const Vp3DecodeContext *s, const VP4Predictor * dc_pred, const int * last_dc, int type, int plane) +{ + int count = 0; + int dc = 0; + + if (dc_pred[-6].type == type) { + dc += dc_pred[-6].dc; + count++; + } + + if (dc_pred[6].type == type) { + dc += dc_pred[6].dc; + count++; + } + + if (count != 2 && dc_pred[-1].type == type) { + dc += dc_pred[-1].dc; + count++; + } + + if (count != 2 && dc_pred[1].type == type) { + dc += dc_pred[1].dc; + count++; + } + + /* using division instead of shift to correctly handle negative values */ + return count == 2 ? dc / 2 : last_dc[type]; +} + +static void vp4_set_tokens_base(Vp3DecodeContext *s) +{ + int plane, i; + int16_t *base = s->dct_tokens_base; + for (plane = 0; plane < 3; plane++) { + for (i = 0; i < 64; i++) { + s->dct_tokens[plane][i] = base; + base += s->fragment_width[!!plane] * s->fragment_height[!!plane]; + } + } +} + +static int vp4_unpack_dct_coeffs(Vp3DecodeContext *s, GetBitContext *gb) +{ + int i, j; + int dc_y_table; + int dc_c_table; + int ac_y_table; + int ac_c_table; + VLC *tables[2][64]; + int plane, sb_y, sb_x; + int eob_tracker[64]; + VP4Predictor dc_pred[6][6]; + int last_dc[NB_VP4_DC_TYPES]; + + if (get_bits_left(gb) < 16) + return AVERROR_INVALIDDATA; + + /* fetch the DC table indexes */ + dc_y_table = get_bits(gb, 4); + dc_c_table = get_bits(gb, 4); + + ac_y_table = get_bits(gb, 4); + ac_c_table = get_bits(gb, 4); + + /* build tables of DC/AC VLC tables */ + + tables[0][0] = &s->dc_vlc[dc_y_table]; + tables[1][0] = &s->dc_vlc[dc_c_table]; + for (i = 1; i <= 5; i++) { + tables[0][i] = &s->ac_vlc_1[ac_y_table]; + tables[1][i] = &s->ac_vlc_1[ac_c_table]; + } + for (i = 6; i <= 14; i++) { + tables[0][i] = &s->ac_vlc_2[ac_y_table]; + tables[1][i] = &s->ac_vlc_2[ac_c_table]; + } + for (i = 15; i <= 27; i++) { + tables[0][i] = &s->ac_vlc_3[ac_y_table]; + tables[1][i] = &s->ac_vlc_3[ac_c_table]; + } + for (i = 28; i <= 63; i++) { + tables[0][i] = &s->ac_vlc_4[ac_y_table]; + tables[1][i] = &s->ac_vlc_4[ac_c_table]; + } + + vp4_set_tokens_base(s); + + memset(last_dc, 0, sizeof(last_dc)); + + for (plane = 0; plane < ((s->avctx->flags & AV_CODEC_FLAG_GRAY) ? 1 : 3); plane++) { + memset(eob_tracker, 0, sizeof(eob_tracker)); + + /* initialise dc prediction */ + for (i = 0; i < s->fragment_width[!!plane]; i++) + vp4_dc_predictor_reset(&s->dc_pred_row[i]); + + for (j = 0; j < 6; j++) + for (i = 0; i < 6; i++) + vp4_dc_predictor_reset(&dc_pred[j][i]); + + for (sb_y = 0; sb_y * 4 < s->fragment_height[!!plane]; sb_y++) { + for (sb_x = 0; sb_x *4 < s->fragment_width[!!plane]; sb_x++) { + vp4_dc_pred_before(s, dc_pred, sb_x); + for (j = 0; j < 16; j++) { + int hx = hilbert_offset[j][0]; + int hy = hilbert_offset[j][1]; + int x = 4 * sb_x + hx; + int y = 4 * sb_y + hy; + VP4Predictor *this_dc_pred = &dc_pred[hy + 1][hx + 1]; + int fragment, dc_block_type; + + if (x >= s->fragment_width[!!plane] || y >= s->fragment_height[!!plane]) + continue; + + fragment = s->fragment_start[plane] + y * s->fragment_width[!!plane] + x; + + if (s->all_fragments[fragment].coding_method == MODE_COPY) + continue; + + if (vp4_unpack_vlcs(s, gb, tables[!!plane], plane, eob_tracker, fragment) < 0) + return -1; + + dc_block_type = vp4_pred_block_type_map[s->all_fragments[fragment].coding_method]; + + s->all_fragments[fragment].dc += + vp4_dc_pred(s, this_dc_pred, last_dc, dc_block_type, plane); + + this_dc_pred->type = dc_block_type, + this_dc_pred->dc = last_dc[dc_block_type] = s->all_fragments[fragment].dc; + } + vp4_dc_pred_after(s, dc_pred, sb_x); + } + } + } + + vp4_set_tokens_base(s); + + return 0; +} +#endif + /* * This function reverses the DC prediction for each coded fragment in * the frame. Much of this function is adapted directly from the original @@ -1488,6 +1952,99 @@ static void await_reference_row(Vp3DecodeContext *s, Vp3Fragment *fragment, ff_thread_await_progress(ref_frame, ref_row, 0); } +#if CONFIG_VP4_DECODER +/** + * @return non-zero if temp (edge_emu_buffer) was populated + */ +static int vp4_mc_loop_filter(Vp3DecodeContext *s, int plane, int motion_x, int motion_y, int bx, int by, + uint8_t * motion_source, int stride, int src_x, int src_y, uint8_t *temp) +{ + int motion_shift = plane ? 4 : 2; + int subpel_mask = plane ? 3 : 1; + int *bounding_values = s->bounding_values_array + 127; + + int i; + int x, y; + int x2, y2; + int x_subpel, y_subpel; + int x_offset, y_offset; + + int block_width = plane ? 8 : 16; + int plane_width = s->width >> (plane && s->chroma_x_shift); + int plane_height = s->height >> (plane && s->chroma_y_shift); + +#define loop_stride 12 + uint8_t loop[12 * loop_stride]; + + /* using division instead of shift to correctly handle negative values */ + x = 8 * bx + motion_x / motion_shift; + y = 8 * by + motion_y / motion_shift; + + x_subpel = motion_x & subpel_mask; + y_subpel = motion_y & subpel_mask; + + if (x_subpel || y_subpel) { + x--; + y--; + + if (x_subpel) + x = FFMIN(x, x + FFSIGN(motion_x)); + + if (y_subpel) + y = FFMIN(y, y + FFSIGN(motion_y)); + + x2 = x + block_width; + y2 = y + block_width; + + if (x2 < 0 || x2 >= plane_width || y2 < 0 || y2 >= plane_height) + return 0; + + x_offset = (-(x + 2) & 7) + 2; + y_offset = (-(y + 2) & 7) + 2; + + if (x_offset > 8 + x_subpel && y_offset > 8 + y_subpel) + return 0; + + s->vdsp.emulated_edge_mc(loop, motion_source - stride - 1, + loop_stride, stride, + 12, 12, src_x - 1, src_y - 1, + plane_width, + plane_height); + + if (x_offset <= 8 + x_subpel) + ff_vp3dsp_h_loop_filter_12(loop + x_offset, loop_stride, bounding_values); + + if (y_offset <= 8 + y_subpel) + ff_vp3dsp_v_loop_filter_12(loop + y_offset*loop_stride, loop_stride, bounding_values); + + } else { + + x_offset = -x & 7; + y_offset = -y & 7; + + if (!x_offset && !y_offset) + return 0; + + s->vdsp.emulated_edge_mc(loop, motion_source - stride - 1, + loop_stride, stride, + 12, 12, src_x - 1, src_y - 1, + plane_width, + plane_height); + + if (x_offset) + s->vp3dsp.h_loop_filter(loop + loop_stride + x_offset + 1, loop_stride, bounding_values); + + if (y_offset) + s->vp3dsp.v_loop_filter(loop + (y_offset + 1)*loop_stride + 1, loop_stride, bounding_values); + } + + for (i = 0; i < 9; i++) + memcpy(temp + i*stride, loop + (i + 1) * loop_stride + 1, 9); + + return 1; +} +#endif + /* * Perform the final rendering for a particular slice of data. * The slice number ranges from 0..(c_superblock_height - 1). @@ -1573,8 +2130,15 @@ static void render_slice(Vp3DecodeContext *s, int slice) if ((s->all_fragments[i].coding_method > MODE_INTRA) && (s->all_fragments[i].coding_method != MODE_USING_GOLDEN)) { int src_x, src_y; + int standard_mc = 1; motion_x = motion_val[fragment][0]; motion_y = motion_val[fragment][1]; +#if CONFIG_VP4_DECODER + if (plane && s->version >= 2) { + motion_x = (motion_x >> 1) | (motion_x & 1); + motion_y = (motion_y >> 1) | (motion_y & 1); + } +#endif src_x = (motion_x >> 1) + 8 * x; src_y = (motion_y >> 1) + 8 * y; @@ -1585,9 +2149,22 @@ static void render_slice(Vp3DecodeContext *s, int slice) motion_halfpel_index |= (motion_y & 0x01) << 1; motion_source += ((motion_y >> 1) * stride); - if (src_x < 0 || src_y < 0 || +#if CONFIG_VP4_DECODER + if (s->version >= 2) { + uint8_t *temp = s->edge_emu_buffer; + if (stride < 0) + temp -= 8 * stride; + if (vp4_mc_loop_filter(s, plane, motion_val[fragment][0], motion_val[fragment][1], x, y, motion_source, stride, src_x, src_y, temp)) { + motion_source = temp; + standard_mc = 0; + } + } +#endif + + if (standard_mc && ( + src_x < 0 || src_y < 0 || src_x + 9 >= plane_width || - src_y + 9 >= plane_height) { + src_y + 9 >= plane_height)) { uint8_t *temp = s->edge_emu_buffer; if (stride < 0) temp -= 8 * stride; @@ -1653,7 +2230,7 @@ static void render_slice(Vp3DecodeContext *s, int slice) } // Filter up to the last row in the superblock row - if (!s->skip_loop_filter) + if (s->version < 2 && !s->skip_loop_filter) apply_loop_filter(s, plane, 4 * sb_y - !!sb_y, FFMIN(4 * sb_y + 3, fragment_height - 1)); } @@ -1682,10 +2259,13 @@ static av_cold int allocate_tables(AVCodecContext *avctx) y_fragment_count = s->fragment_width[0] * s->fragment_height[0]; c_fragment_count = s->fragment_width[1] * s->fragment_height[1]; - s->superblock_coding = av_mallocz(s->superblock_count); + /* superblock_coding is used by unpack_superblocks (VP3/Theora) and vp4_unpack_macroblocks (VP4) */ + s->superblock_coding = av_mallocz(FFMAX(s->superblock_count, s->yuv_macroblock_count)); s->all_fragments = av_mallocz_array(s->fragment_count, sizeof(Vp3Fragment)); - s->coded_fragment_list[0] = av_mallocz_array(s->fragment_count, sizeof(int)); + s-> kf_coded_fragment_list = av_mallocz_array(s->fragment_count, sizeof(int)); + s->nkf_coded_fragment_list = av_mallocz_array(s->fragment_count, sizeof(int)); + memset(s-> num_kf_coded_fragment, -1, sizeof(s-> num_kf_coded_fragment)); s->dct_tokens_base = av_mallocz_array(s->fragment_count, 64 * sizeof(*s->dct_tokens_base)); @@ -1696,9 +2276,13 @@ static av_cold int allocate_tables(AVCodecContext *avctx) s->superblock_fragments = av_mallocz_array(s->superblock_count, 16 * sizeof(int)); s->macroblock_coding = av_mallocz(s->macroblock_count + 1); + s->dc_pred_row = av_malloc_array(s->y_superblock_width * 4, sizeof(*s->dc_pred_row)); + if (!s->superblock_coding || !s->all_fragments || - !s->dct_tokens_base || !s->coded_fragment_list[0] || + !s->dct_tokens_base || !s->kf_coded_fragment_list || + !s->nkf_coded_fragment_list || !s->superblock_fragments || !s->macroblock_coding || + !s->dc_pred_row || !s->motion_val[0] || !s->motion_val[1]) { vp3_decode_end(avctx); return -1; @@ -1732,6 +2316,9 @@ static av_cold int vp3_decode_init(AVCodecContext *avctx) int c_width; int c_height; int y_fragment_count, c_fragment_count; +#if CONFIG_VP4_DECODER + int j; +#endif ret = init_frames(s); if (ret < 0) @@ -1739,7 +2326,9 @@ static av_cold int vp3_decode_init(AVCodecContext *avctx) avctx->internal->allocate_progress = 1; - if (avctx->codec_tag == MKTAG('V', 'P', '3', '0')) + if (avctx->codec_tag == MKTAG('V', 'P', '4', '0')) + s->version = 3; + else if (avctx->codec_tag == MKTAG('V', 'P', '3', '0')) s->version = 0; else s->version = 1; @@ -1788,6 +2377,10 @@ static av_cold int vp3_decode_init(AVCodecContext *avctx) s->macroblock_width = (s->width + 15) / 16; s->macroblock_height = (s->height + 15) / 16; s->macroblock_count = s->macroblock_width * s->macroblock_height; + s->c_macroblock_width = (c_width + 15) / 16; + s->c_macroblock_height = (c_height + 15) / 16; + s->c_macroblock_count = s->c_macroblock_width * s->c_macroblock_height; + s->yuv_macroblock_count = s->macroblock_count + 2 * s->c_macroblock_count; s->fragment_width[0] = s->width / FRAGMENT_PIXELS; s->fragment_height[0] = s->height / FRAGMENT_PIXELS; @@ -1803,12 +2396,13 @@ static av_cold int vp3_decode_init(AVCodecContext *avctx) if (!s->theora_tables) { for (i = 0; i < 64; i++) { - s->coded_dc_scale_factor[i] = vp31_dc_scale_factor[i]; - s->coded_ac_scale_factor[i] = vp31_ac_scale_factor[i]; - s->base_matrix[0][i] = vp31_intra_y_dequant[i]; - s->base_matrix[1][i] = vp31_intra_c_dequant[i]; - s->base_matrix[2][i] = vp31_inter_dequant[i]; - s->filter_limit_values[i] = vp31_filter_limit_values[i]; + s->coded_dc_scale_factor[0][i] = s->version < 2 ? vp31_dc_scale_factor[i] : vp4_y_dc_scale_factor[i]; + s->coded_dc_scale_factor[1][i] = s->version < 2 ? vp31_dc_scale_factor[i] : vp4_uv_dc_scale_factor[i]; + s->coded_ac_scale_factor[i] = s->version < 2 ? vp31_ac_scale_factor[i] : vp4_ac_scale_factor[i]; + s->base_matrix[0][i] = s->version < 2 ? vp31_intra_y_dequant[i] : vp4_generic_dequant[i]; + s->base_matrix[1][i] = s->version < 2 ? vp31_intra_c_dequant[i] : vp4_generic_dequant[i]; + s->base_matrix[2][i] = s->version < 2 ? vp31_inter_dequant[i] : vp4_generic_dequant[i]; + s->filter_limit_values[i] = s->version < 2 ? vp31_filter_limit_values[i] : vp4_filter_limit_values[i]; } for (inter = 0; inter < 2; inter++) { @@ -1821,6 +2415,7 @@ static av_cold int vp3_decode_init(AVCodecContext *avctx) } /* init VLC tables */ + if (s->version < 2) { for (i = 0; i < 16; i++) { /* DC histograms */ init_vlc(&s->dc_vlc[i], 11, 32, @@ -1847,6 +2442,36 @@ static av_cold int vp3_decode_init(AVCodecContext *avctx) &ac_bias_3[i][0][1], 4, 2, &ac_bias_3[i][0][0], 4, 2, 0); } +#if CONFIG_VP4_DECODER + } else { /* version >= 2 */ + for (i = 0; i < 16; i++) { + /* DC histograms */ + init_vlc(&s->dc_vlc[i], 11, 32, + &vp4_dc_bias[i][0][1], 4, 2, + &vp4_dc_bias[i][0][0], 4, 2, 0); + + /* group 1 AC histograms */ + init_vlc(&s->ac_vlc_1[i], 11, 32, + &vp4_ac_bias_0[i][0][1], 4, 2, + &vp4_ac_bias_0[i][0][0], 4, 2, 0); + + /* group 2 AC histograms */ + init_vlc(&s->ac_vlc_2[i], 11, 32, + &vp4_ac_bias_1[i][0][1], 4, 2, + &vp4_ac_bias_1[i][0][0], 4, 2, 0); + + /* group 3 AC histograms */ + init_vlc(&s->ac_vlc_3[i], 11, 32, + &vp4_ac_bias_2[i][0][1], 4, 2, + &vp4_ac_bias_2[i][0][0], 4, 2, 0); + + /* group 4 AC histograms */ + init_vlc(&s->ac_vlc_4[i], 11, 32, + &vp4_ac_bias_3[i][0][1], 4, 2, + &vp4_ac_bias_3[i][0][0], 4, 2, 0); + } +#endif + } } else { for (i = 0; i < 16; i++) { /* DC histograms */ @@ -1897,6 +2522,20 @@ static av_cold int vp3_decode_init(AVCodecContext *avctx) &motion_vector_vlc_table[0][1], 2, 1, &motion_vector_vlc_table[0][0], 2, 1, 0); +#if CONFIG_VP4_DECODER + for (j = 0; j < 2; j++) + for (i = 0; i < 7; i++) + init_vlc(&s->vp4_mv_vlc[j][i], 6, 63, + &vp4_mv_vlc[j][i][0][1], 4, 2, + &vp4_mv_vlc[j][i][0][0], 4, 2, 0); + + /* version >= 2 */ + for (i = 0; i < 2; i++) + init_vlc(&s->block_pattern_vlc[i], 3, 14, + &vp4_block_pattern_vlc[i][0][1], 2, 1, + &vp4_block_pattern_vlc[i][0][0], 2, 1, 0); +#endif + return allocate_tables(avctx); vlc_fail: @@ -1926,6 +2565,7 @@ fail: return ret; } +#if HAVE_THREADS static int ref_frame(Vp3DecodeContext *s, ThreadFrame *dst, ThreadFrame *src) { ff_thread_release_buffer(s->avctx, dst); @@ -1944,7 +2584,6 @@ static int ref_frames(Vp3DecodeContext *dst, Vp3DecodeContext *src) return 0; } -#if HAVE_THREADS static int vp3_update_thread_context(AVCodecContext *dst, const AVCodecContext *src) { Vp3DecodeContext *s = dst->priv_data, *s1 = src->priv_data; @@ -2120,6 +2759,29 @@ static int vp3_decode_frame(AVCodecContext *avctx, av_log(s->avctx, AV_LOG_ERROR, "Warning, unsupported keyframe coding type?!\n"); skip_bits(&gb, 2); /* reserved? */ + +#if CONFIG_VP4_DECODER + if (s->version >= 2) { + int mb_height, mb_width; + int mb_width_mul, mb_width_div, mb_height_mul, mb_height_div; + + mb_height = get_bits(&gb, 8); + mb_width = get_bits(&gb, 8); + if (mb_height != s->macroblock_height || + mb_width != s->macroblock_width) + avpriv_request_sample(s->avctx, "macroblock dimension mismatch"); + + mb_width_mul = get_bits(&gb, 5); + mb_width_div = get_bits(&gb, 3); + mb_height_mul = get_bits(&gb, 5); + mb_height_div = get_bits(&gb, 3); + if (mb_width_mul != 1 || mb_width_div != 1 || mb_height_mul != 1 || mb_height_div != 1) + avpriv_request_sample(s->avctx, "unexpected macroblock dimension multipler/divider"); + + if (get_bits(&gb, 2)) + avpriv_request_sample(s->avctx, "unknown bits"); + } +#endif } } else { if (!s->golden_frame.f->data[0]) { @@ -2141,10 +2803,19 @@ static int vp3_decode_frame(AVCodecContext *avctx, memset(s->all_fragments, 0, s->fragment_count * sizeof(Vp3Fragment)); ff_thread_finish_setup(avctx); + if (s->version < 2) { if (unpack_superblocks(s, &gb)) { av_log(s->avctx, AV_LOG_ERROR, "error in unpack_superblocks\n"); goto error; } +#if CONFIG_VP4_DECODER + } else { + if (vp4_unpack_macroblocks(s, &gb)) { + av_log(s->avctx, AV_LOG_ERROR, "error in vp4_unpack_macroblocks\n"); + goto error; + } +#endif + } if (unpack_modes(s, &gb)) { av_log(s->avctx, AV_LOG_ERROR, "error in unpack_modes\n"); goto error; @@ -2157,10 +2828,20 @@ static int vp3_decode_frame(AVCodecContext *avctx, av_log(s->avctx, AV_LOG_ERROR, "error in unpack_block_qpis\n"); goto error; } + + if (s->version < 2) { if (unpack_dct_coeffs(s, &gb)) { av_log(s->avctx, AV_LOG_ERROR, "error in unpack_dct_coeffs\n"); goto error; } +#if CONFIG_VP4_DECODER + } else { + if (vp4_unpack_dct_coeffs(s, &gb)) { + av_log(s->avctx, AV_LOG_ERROR, "error in vp4_unpack_dct_coeffs\n"); + goto error; + } +#endif + } for (i = 0; i < 3; i++) { int height = s->height >> (i && s->chroma_y_shift); @@ -2175,6 +2856,7 @@ static int vp3_decode_frame(AVCodecContext *avctx, render_slice(s, i); // filter the last row + if (s->version < 2) for (i = 0; i < 3; i++) { int row = (s->height >> (3 + (i && s->chroma_y_shift))) - 1; apply_loop_filter(s, i, row, row + 1); @@ -2251,12 +2933,15 @@ static int vp3_init_thread_copy(AVCodecContext *avctx) s->superblock_coding = NULL; s->all_fragments = NULL; s->coded_fragment_list[0] = NULL; + s-> kf_coded_fragment_list= NULL; + s->nkf_coded_fragment_list= NULL; s->dct_tokens_base = NULL; s->superblock_fragments = NULL; s->macroblock_coding = NULL; s->motion_val[0] = NULL; s->motion_val[1] = NULL; s->edge_emu_buffer = NULL; + s->dc_pred_row = NULL; return init_frames(s); } @@ -2278,6 +2963,10 @@ static int theora_decode_header(AVCodecContext *avctx, GetBitContext *gb) s->theora_header = 0; s->theora = get_bits_long(gb, 24); av_log(avctx, AV_LOG_DEBUG, "Theora bitstream version %X\n", s->theora); + if (!s->theora) { + s->theora = 1; + avpriv_request_sample(s->avctx, "theora 0"); + } /* 3.2.0 aka alpha3 has the same frame orientation as original vp3 * but previous versions have the image flipped relative to vp3 */ @@ -2405,7 +3094,8 @@ static int theora_decode_tables(AVCodecContext *avctx, GetBitContext *gb) n = 16; /* dc scale factor table */ for (i = 0; i < 64; i++) - s->coded_dc_scale_factor[i] = get_bits(gb, n); + s->coded_dc_scale_factor[0][i] = + s->coded_dc_scale_factor[1][i] = get_bits(gb, n); if (s->theora >= 0x030200) matrices = get_bits(gb, 9) + 1; @@ -2591,3 +3281,21 @@ AVCodec ff_vp3_decoder = { .init_thread_copy = ONLY_IF_THREADS_ENABLED(vp3_init_thread_copy), .update_thread_context = ONLY_IF_THREADS_ENABLED(vp3_update_thread_context), }; + +#if CONFIG_VP4_DECODER +AVCodec ff_vp4_decoder = { + .name = "vp4", + .long_name = NULL_IF_CONFIG_SMALL("On2 VP4"), + .type = AVMEDIA_TYPE_VIDEO, + .id = AV_CODEC_ID_VP4, + .priv_data_size = sizeof(Vp3DecodeContext), + .init = vp3_decode_init, + .close = vp3_decode_end, + .decode = vp3_decode_frame, + .capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DRAW_HORIZ_BAND | + AV_CODEC_CAP_FRAME_THREADS, + .flush = vp3_decode_flush, + .init_thread_copy = ONLY_IF_THREADS_ENABLED(vp3_init_thread_copy), + .update_thread_context = ONLY_IF_THREADS_ENABLED(vp3_update_thread_context), +}; +#endif diff --git a/libavcodec/vp3data.h b/libavcodec/vp3data.h index 3884bca87..d520a10c7 100644 --- a/libavcodec/vp3data.h +++ b/libavcodec/vp3data.h @@ -73,7 +73,7 @@ static const uint8_t vp31_dc_scale_factor[64] = { 20, 10, 10, 10, 10, 10, 10, 10 }; -static const uint32_t vp31_ac_scale_factor[64] = { +static const uint16_t vp31_ac_scale_factor[64] = { 500, 450, 400, 370, 340, 310, 285, 265, 245, 225, 210, 195, 185, 180, 170, 160, 150, 145, 135, 130, 125, 115, 110, 107, @@ -198,11 +198,10 @@ static const int8_t fixed_motion_vector_table[64] = { }; /* only tokens 0..6 indicate eob runs */ -static const uint8_t eob_run_base[7] = { - 1, 2, 3, 4, 8, 16, 0 -}; -static const uint8_t eob_run_get_bits[7] = { - 0, 0, 0, 2, 3, 4, 12 +static const struct { + uint8_t base, bits; +} eob_run_table[7] = { + {1, 0}, {2, 0}, {3, 0}, {4, 2}, {8, 3}, {16, 4}, {0, 12} }; static const uint8_t zero_run_base[32] = { diff --git a/libavcodec/vp3dsp.c b/libavcodec/vp3dsp.c index fdaa292d3..ac4c57441 100644 --- a/libavcodec/vp3dsp.c +++ b/libavcodec/vp3dsp.c @@ -27,6 +27,7 @@ #include "libavutil/attributes.h" #include "libavutil/common.h" #include "libavutil/intreadwrite.h" +#include "libavutil/avassert.h" #include "avcodec.h" #include "rnd_avg.h" @@ -194,6 +195,158 @@ static av_always_inline void idct(uint8_t *dst, ptrdiff_t stride, } } +static av_always_inline void idct10(uint8_t *dst, ptrdiff_t stride, + int16_t *input, int type) +{ + int16_t *ip = input; + + int A, B, C, D, Ad, Bd, Cd, Dd, E, F, G, H; + int Ed, Gd, Add, Bdd, Fd, Hd; + + int i; + + /* Inverse DCT on the rows now */ + for (i = 0; i < 4; i++) { + /* Check for non-zero values */ + if (ip[0 * 8] | ip[1 * 8] | ip[2 * 8] | ip[3 * 8]) { + A = M(xC1S7, ip[1 * 8]); + B = M(xC7S1, ip[1 * 8]); + C = M(xC3S5, ip[3 * 8]); + D = -M(xC5S3, ip[3 * 8]); + + Ad = M(xC4S4, (A - C)); + Bd = M(xC4S4, (B - D)); + + Cd = A + C; + Dd = B + D; + + E = M(xC4S4, ip[0 * 8]); + F = E; + + G = M(xC2S6, ip[2 * 8]); + H = M(xC6S2, ip[2 * 8]); + + Ed = E - G; + Gd = E + G; + + Add = F + Ad; + Bdd = Bd - H; + + Fd = F - Ad; + Hd = Bd + H; + + /* Final sequence of operations over-write original inputs */ + ip[0 * 8] = Gd + Cd; + ip[7 * 8] = Gd - Cd; + + ip[1 * 8] = Add + Hd; + ip[2 * 8] = Add - Hd; + + ip[3 * 8] = Ed + Dd; + ip[4 * 8] = Ed - Dd; + + ip[5 * 8] = Fd + Bdd; + ip[6 * 8] = Fd - Bdd; + + } + + ip += 1; + } + + ip = input; + + for (i = 0; i < 8; i++) { + /* Check for non-zero values (bitwise or faster than ||) */ + if (ip[0] | ip[1] | ip[2] | ip[3]) { + A = M(xC1S7, ip[1]); + B = M(xC7S1, ip[1]); + C = M(xC3S5, ip[3]); + D = -M(xC5S3, ip[3]); + + Ad = M(xC4S4, (A - C)); + Bd = M(xC4S4, (B - D)); + + Cd = A + C; + Dd = B + D; + + E = M(xC4S4, ip[0]); + if (type == 1) + E += 16 * 128; + F = E; + + G = M(xC2S6, ip[2]); + H = M(xC6S2, ip[2]); + + Ed = E - G; + Gd = E + G; + + Add = F + Ad; + Bdd = Bd - H; + + Fd = F - Ad; + Hd = Bd + H; + + Gd += 8; + Add += 8; + Ed += 8; + Fd += 8; + + /* Final sequence of operations over-write original inputs. */ + if (type == 1) { + dst[0 * stride] = av_clip_uint8((Gd + Cd) >> 4); + dst[7 * stride] = av_clip_uint8((Gd - Cd) >> 4); + + dst[1 * stride] = av_clip_uint8((Add + Hd) >> 4); + dst[2 * stride] = av_clip_uint8((Add - Hd) >> 4); + + dst[3 * stride] = av_clip_uint8((Ed + Dd) >> 4); + dst[4 * stride] = av_clip_uint8((Ed - Dd) >> 4); + + dst[5 * stride] = av_clip_uint8((Fd + Bdd) >> 4); + dst[6 * stride] = av_clip_uint8((Fd - Bdd) >> 4); + } else { + dst[0 * stride] = av_clip_uint8(dst[0 * stride] + ((Gd + Cd) >> 4)); + dst[7 * stride] = av_clip_uint8(dst[7 * stride] + ((Gd - Cd) >> 4)); + + dst[1 * stride] = av_clip_uint8(dst[1 * stride] + ((Add + Hd) >> 4)); + dst[2 * stride] = av_clip_uint8(dst[2 * stride] + ((Add - Hd) >> 4)); + + dst[3 * stride] = av_clip_uint8(dst[3 * stride] + ((Ed + Dd) >> 4)); + dst[4 * stride] = av_clip_uint8(dst[4 * stride] + ((Ed - Dd) >> 4)); + + dst[5 * stride] = av_clip_uint8(dst[5 * stride] + ((Fd + Bdd) >> 4)); + dst[6 * stride] = av_clip_uint8(dst[6 * stride] + ((Fd - Bdd) >> 4)); + } + } else { + if (type == 1) { + dst[0*stride] = + dst[1*stride] = + dst[2*stride] = + dst[3*stride] = + dst[4*stride] = + dst[5*stride] = + dst[6*stride] = + dst[7*stride] = 128; + } + } + + ip += 8; + dst++; + } +} + +void ff_vp3dsp_idct10_put(uint8_t *dest, ptrdiff_t stride, int16_t *block) +{ + idct10(dest, stride, block, 1); + memset(block, 0, sizeof(*block) * 64); +} + +void ff_vp3dsp_idct10_add(uint8_t *dest, ptrdiff_t stride, int16_t *block) +{ + idct10(dest, stride, block, 2); + memset(block, 0, sizeof(*block) * 64); +} + static void vp3_idct_put_c(uint8_t *dest /* align 8 */, ptrdiff_t stride, int16_t *block /* align 16 */) { @@ -227,14 +380,14 @@ static void vp3_idct_dc_add_c(uint8_t *dest /* align 8 */, ptrdiff_t stride, block[0] = 0; } -static void vp3_v_loop_filter_c(uint8_t *first_pixel, ptrdiff_t stride, - int *bounding_values) +static av_always_inline void vp3_v_loop_filter_c(uint8_t *first_pixel, ptrdiff_t stride, + int *bounding_values, int count) { unsigned char *end; int filter_value; const ptrdiff_t nstride = -stride; - for (end = first_pixel + 8; first_pixel < end; first_pixel++) { + for (end = first_pixel + count; first_pixel < end; first_pixel++) { filter_value = (first_pixel[2 * nstride] - first_pixel[stride]) + (first_pixel[0] - first_pixel[nstride]) * 3; filter_value = bounding_values[(filter_value + 4) >> 3]; @@ -244,13 +397,13 @@ static void vp3_v_loop_filter_c(uint8_t *first_pixel, ptrdiff_t stride, } } -static void vp3_h_loop_filter_c(uint8_t *first_pixel, ptrdiff_t stride, - int *bounding_values) +static av_always_inline void vp3_h_loop_filter_c(uint8_t *first_pixel, ptrdiff_t stride, + int *bounding_values, int count) { unsigned char *end; int filter_value; - for (end = first_pixel + 8 * stride; first_pixel != end; first_pixel += stride) { + for (end = first_pixel + count * stride; first_pixel != end; first_pixel += stride) { filter_value = (first_pixel[-2] - first_pixel[1]) + (first_pixel[ 0] - first_pixel[-1]) * 3; filter_value = bounding_values[(filter_value + 4) >> 3]; @@ -260,6 +413,18 @@ static void vp3_h_loop_filter_c(uint8_t *first_pixel, ptrdiff_t stride, } } +#define LOOP_FILTER(prefix, suffix, dim, count) \ +void prefix##_##dim##_loop_filter_##count##suffix(uint8_t *first_pixel, ptrdiff_t stride, \ + int *bounding_values) \ +{ \ + vp3_##dim##_loop_filter_c(first_pixel, stride, bounding_values, count); \ +} + +static LOOP_FILTER(vp3,_c, v, 8) +static LOOP_FILTER(vp3,_c, h, 8) +LOOP_FILTER(ff_vp3dsp, , v, 12) +LOOP_FILTER(ff_vp3dsp, , h, 12) + static void put_no_rnd_pixels_l2(uint8_t *dst, const uint8_t *src1, const uint8_t *src2, ptrdiff_t stride, int h) { @@ -284,8 +449,8 @@ av_cold void ff_vp3dsp_init(VP3DSPContext *c, int flags) c->idct_put = vp3_idct_put_c; c->idct_add = vp3_idct_add_c; c->idct_dc_add = vp3_idct_dc_add_c; - c->v_loop_filter = vp3_v_loop_filter_c; - c->h_loop_filter = vp3_h_loop_filter_c; + c->v_loop_filter = vp3_v_loop_filter_8_c; + c->h_loop_filter = vp3_h_loop_filter_8_c; if (ARCH_ARM) ff_vp3dsp_init_arm(c, flags); @@ -293,4 +458,37 @@ av_cold void ff_vp3dsp_init(VP3DSPContext *c, int flags) ff_vp3dsp_init_ppc(c, flags); if (ARCH_X86) ff_vp3dsp_init_x86(c, flags); + if (ARCH_MIPS) + ff_vp3dsp_init_mips(c, flags); +} + +/* + * This function initializes the loop filter boundary limits if the frame's + * quality index is different from the previous frame's. + * + * where sizeof(bounding_values_array) is 256 * sizeof(int) + * + * The filter_limit_values may not be larger than 127. + */ +void ff_vp3dsp_set_bounding_values(int * bounding_values_array, int filter_limit) +{ + int *bounding_values = bounding_values_array + 127; + int x; + int value; + + av_assert0(filter_limit < 128U); + + /* set up the bounding values */ + memset(bounding_values_array, 0, 256 * sizeof(int)); + for (x = 0; x < filter_limit; x++) { + bounding_values[-x] = -x; + bounding_values[x] = x; + } + for (x = value = filter_limit; x < 128 && value; x++, value--) { + bounding_values[ x] = value; + bounding_values[-x] = -value; + } + if (value) + bounding_values[128] = value; + bounding_values[129] = bounding_values[130] = filter_limit * 0x02020202; } diff --git a/libavcodec/vp3dsp.h b/libavcodec/vp3dsp.h index 2fdad162c..32b2cad0e 100644 --- a/libavcodec/vp3dsp.h +++ b/libavcodec/vp3dsp.h @@ -45,9 +45,18 @@ typedef struct VP3DSPContext { void (*h_loop_filter)(uint8_t *src, ptrdiff_t stride, int *bounding_values); } VP3DSPContext; +void ff_vp3dsp_v_loop_filter_12(uint8_t *first_pixel, ptrdiff_t stride, int *bounding_values); +void ff_vp3dsp_h_loop_filter_12(uint8_t *first_pixel, ptrdiff_t stride, int *bounding_values); + +void ff_vp3dsp_idct10_put(uint8_t *dest, ptrdiff_t stride, int16_t *block); +void ff_vp3dsp_idct10_add(uint8_t *dest, ptrdiff_t stride, int16_t *block); + void ff_vp3dsp_init(VP3DSPContext *c, int flags); void ff_vp3dsp_init_arm(VP3DSPContext *c, int flags); void ff_vp3dsp_init_ppc(VP3DSPContext *c, int flags); void ff_vp3dsp_init_x86(VP3DSPContext *c, int flags); +void ff_vp3dsp_init_mips(VP3DSPContext *c, int flags); + +void ff_vp3dsp_set_bounding_values(int * bound_values_array, int filter_limit); #endif /* AVCODEC_VP3DSP_H */ diff --git a/libavcodec/vp4data.h b/libavcodec/vp4data.h new file mode 100644 index 000000000..69a009eff --- /dev/null +++ b/libavcodec/vp4data.h @@ -0,0 +1,1186 @@ +/* + * Copyright (C) 2019 Peter Ross + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * VP4 video decoder + */ + +#ifndef AVCODEC_VP4DATA_H +#define AVCODEC_VP4DATA_H + +#include + +static const uint8_t vp4_generic_dequant[64] = { + 16, 17, 18, 20, 22, 24, 26, 28, + 17, 18, 20, 22, 24, 26, 28, 32, + 18, 20, 22, 24, 26, 28, 32, 36, + 20, 22, 24, 26, 28, 32, 36, 40, + 22, 24, 26, 28, 32, 36, 40, 44, + 24, 26, 28, 32, 36, 40, 44, 48, + 26, 28, 32, 36, 40, 44, 48, 52, + 28, 32, 36, 40, 44, 48, 52, 56 +}; + +static const uint8_t vp4_y_dc_scale_factor[64] = { + 180, 180, 180, 180, 180, 180, 175, 170, + 165, 160, 157, 155, 152, 150, 147, 145, + 142, 140, 137, 135, 132, 130, 127, 125, + 122, 120, 117, 115, 112, 110, 107, 105, + 102, 100, 97, 95, 92, 90, 87, 85, + 82, 80, 77, 75, 72, 70, 67, 65, + 62, 60, 57, 55, 52, 50, 47, 45, + 42, 40, 37, 35, 32, 30, 27, 25 +}; + +static const uint8_t vp4_uv_dc_scale_factor[64] = { + 150, 150, 150, 150, 150, 150, 150, 150, + 150, 150, 150, 150, 150, 150, 147, 145, + 142, 140, 137, 135, 132, 130, 127, 125, + 122, 120, 117, 115, 112, 110, 107, 105, + 102, 100, 97, 95, 92, 90, 87, 85, + 82, 80, 77, 75, 72, 70, 67, 65, + 62, 60, 57, 55, 52, 50, 47, 45, + 42, 40, 37, 35, 32, 30, 27, 25 +}; + +static const uint16_t vp4_ac_scale_factor[64] = { + 500, 475, 450, 430, 410, 390, 370, 350, + 330, 315, 300, 285, 270, 260, 250, 240, + 230, 220, 210, 200, 190, 185, 180, 170, + 160, 150, 143, 135, 128, 120, 113, 106, + 100, 94, 90, 85, 80, 75, 70, 66, + 62, 57, 52, 49, 45, 41, 38, 35, + 33, 30, 27, 24, 22, 20, 18, 16, + 14, 12, 10, 9, 7, 6, 4, 1 +}; + +static const uint8_t vp4_filter_limit_values[64] = { + 30, 25, 20, 20, 15, 15, 14, 14, + 13, 13, 12, 12, 11, 11, 10, 10, + 9, 9, 8, 8, 7, 7, 7, 7, + 6, 6, 6, 6, 5, 5, 5, 5, + 4, 4, 4, 4, 3, 3, 3, 3, + 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, + 1, 1, 1, 1, 1, 1, 1, 1 +}; + +static const uint8_t vp4_block_pattern_table_selector[14] = { + 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1 +}; + +static const uint8_t vp4_block_pattern_vlc[2][14][2] = { + { + { 0x0, 3 }, { 0xf, 4 }, { 0x9, 4 }, { 0x2, 3 }, + { 0xd, 4 }, { 0xe, 5 }, { 0xb, 4 }, { 0x1, 3 }, + { 0xf, 5 }, { 0x8, 4 }, { 0x6, 4 }, { 0xe, 4 }, + { 0xc, 4 }, { 0xa, 4 } + }, + { + { 0x7, 4 }, { 0xa, 4 }, { 0x9, 4 }, { 0xc, 4 }, + { 0x8, 4 }, { 0xd, 5 }, { 0x0, 3 }, { 0xe, 4 }, + { 0xc, 5 }, { 0xd, 4 }, { 0x1, 3 }, { 0xb, 4 }, + { 0xf, 4 }, { 0x2, 3 } + } +}; + +static const uint8_t vp4_mv_table_selector[32] = { + 0, 1, 2, 2, 3, 3, 3, 3, + 4, 4, 4, 4, 4, 4, 4, 4, + 5, 5, 5, 5, 5, 5, 5, 5, + 6, 6, 6, 6, 6, 6, 6, 6, +}; + +static const uint16_t vp4_mv_vlc[2][7][63][2] = { + { /* x-axis tables */ + { + { 0x6A, 7 }, { 0x11A, 9 }, { 0x18E, 9 }, { 0x237, 10 }, + { 0x4A, 8 }, { 0x236, 10 }, { 0x7A, 8 }, { 0xD6, 9 }, + { 0x7E, 8 }, { 0x1FD, 10 }, { 0x8C, 8 }, { 0xD7, 9 }, + { 0x87, 8 }, { 0x183, 9 }, { 0x3C, 7 }, { 0x61, 7 }, + { 0x47, 7 }, { 0x69, 8 }, { 0x40, 7 }, { 0x48, 8 }, + { 0x49, 7 }, { 0x86, 8 }, { 0x13, 6 }, { 0xD2, 8 }, + { 0x1C, 6 }, { 0x42, 7 }, { 0x25, 6 }, { 0x1B, 6 }, + { 0x13, 5 }, { 0x5, 4 }, { 0x0, 2 }, { 0x7, 3 }, + { 0x5, 3 }, { 0x1B, 5 }, { 0x19, 5 }, { 0x19, 6 }, + { 0x8, 5 }, { 0x45, 7 }, { 0x1D, 6 }, { 0xC6, 8 }, + { 0x68, 7 }, { 0x90, 8 }, { 0x41, 7 }, { 0x4B, 8 }, + { 0x31, 7 }, { 0x18F, 9 }, { 0x62, 7 }, { 0x3E, 7 }, + { 0x44, 7 }, { 0x68, 8 }, { 0x30, 7 }, { 0x182, 9 }, + { 0xC0, 8 }, { 0x1A7, 9 }, { 0x91, 8 }, { 0x92, 9 }, + { 0x7B, 8 }, { 0xFF, 9 }, { 0x1A6, 9 }, { 0x1FC, 10 }, + { 0x6A, 8 }, { 0x93, 9 }, { 0x6B, 7 } + }, + { + { 0x39, 7 }, { 0x259, 10 }, { 0x1B, 8 }, { 0x1D1, 10 }, + { 0x137, 9 }, { 0x1D0, 10 }, { 0x1A, 8 }, { 0x1B5, 10 }, + { 0x1D, 8 }, { 0x4BC, 11 }, { 0x6C, 8 }, { 0x38, 9 }, + { 0x71, 8 }, { 0x2D, 9 }, { 0x7D, 8 }, { 0x75, 8 }, + { 0x19, 7 }, { 0xE9, 9 }, { 0x37, 7 }, { 0x15, 8 }, + { 0x1E, 7 }, { 0xDB, 9 }, { 0x4C, 7 }, { 0x70, 8 }, + { 0xD, 6 }, { 0xC, 7 }, { 0x27, 6 }, { 0x4, 6 }, + { 0x2, 4 }, { 0x0, 4 }, { 0x5, 3 }, { 0x7, 3 }, + { 0x6, 3 }, { 0x2, 3 }, { 0x8, 4 }, { 0x24, 6 }, + { 0xC, 5 }, { 0x3B, 7 }, { 0x1E, 6 }, { 0x9A, 8 }, + { 0xE, 6 }, { 0x69, 8 }, { 0x4A, 7 }, { 0x12D, 9 }, + { 0x35, 7 }, { 0xF9, 9 }, { 0x18, 7 }, { 0x7F, 8 }, + { 0xF, 7 }, { 0xF8, 9 }, { 0x7E, 8 }, { 0x25F, 10 }, + { 0x68, 8 }, { 0x2C, 9 }, { 0x14, 8 }, { 0x258, 10 }, + { 0x136, 9 }, { 0x4BD, 11 }, { 0x12E, 9 }, { 0x1B4, 10 }, + { 0x17, 8 }, { 0x39, 9 }, { 0x1F, 7 } + }, + { + { 0x29, 7 }, { 0x3CB, 10 }, { 0x1F5, 9 }, { 0x263, 10 }, + { 0x1F4, 9 }, { 0x3DA, 10 }, { 0x50, 8 }, { 0x260, 10 }, + { 0x1EC, 9 }, { 0x3D3, 10 }, { 0x109, 9 }, { 0x3D2, 10 }, + { 0x51, 8 }, { 0x792, 11 }, { 0xF3, 8 }, { 0x9A, 8 }, + { 0xF7, 8 }, { 0x132, 9 }, { 0xC1, 8 }, { 0x1E8, 9 }, + { 0x2A, 7 }, { 0x85, 8 }, { 0x61, 7 }, { 0x1F7, 9 }, + { 0x78, 7 }, { 0xC7, 8 }, { 0x23, 6 }, { 0x7C, 7 }, + { 0x12, 5 }, { 0xB, 5 }, { 0xE, 4 }, { 0xD, 4 }, + { 0x0, 2 }, { 0x5, 3 }, { 0x3, 3 }, { 0x4, 4 }, + { 0x19, 5 }, { 0x20, 6 }, { 0x3F, 6 }, { 0x43, 7 }, + { 0x62, 7 }, { 0x9F, 8 }, { 0x4E, 7 }, { 0x181, 9 }, + { 0x2B, 7 }, { 0x137, 9 }, { 0xF5, 8 }, { 0x89, 8 }, + { 0xC6, 8 }, { 0x262, 10 }, { 0x88, 8 }, { 0x3C8, 10 }, + { 0x1F6, 9 }, { 0x3CA, 10 }, { 0x9E, 8 }, { 0x261, 10 }, + { 0x136, 9 }, { 0x108, 9 }, { 0x133, 9 }, { 0x793, 11 }, + { 0x180, 9 }, { 0x3DB, 10 }, { 0x45, 7 } + }, + { + { 0x1, 6 }, { 0x1C7, 9 }, { 0x67, 8 }, { 0xB5, 9 }, + { 0x66, 8 }, { 0x139, 9 }, { 0x99, 8 }, { 0xB4, 9 }, + { 0xC3, 8 }, { 0x130, 9 }, { 0x0, 7 }, { 0x131, 9 }, + { 0x9E, 8 }, { 0xB7, 9 }, { 0x2C, 7 }, { 0x1, 7 }, + { 0x28, 7 }, { 0x138, 9 }, { 0x4B, 7 }, { 0x31, 8 }, + { 0x60, 7 }, { 0x91, 8 }, { 0x3, 6 }, { 0x9D, 8 }, + { 0x17, 6 }, { 0x4D, 7 }, { 0x31, 6 }, { 0x70, 7 }, + { 0x7, 5 }, { 0x3A, 6 }, { 0x7, 4 }, { 0x2, 4 }, + { 0xB, 4 }, { 0x1, 4 }, { 0xF, 4 }, { 0x8, 4 }, + { 0xD, 4 }, { 0x4, 4 }, { 0xA, 4 }, { 0xD, 5 }, + { 0x19, 5 }, { 0x2, 6 }, { 0x3B, 6 }, { 0x4A, 7 }, + { 0x15, 6 }, { 0xC2, 8 }, { 0x18, 6 }, { 0x32, 7 }, + { 0x72, 7 }, { 0x1C6, 9 }, { 0x29, 7 }, { 0x1C5, 9 }, + { 0x49, 7 }, { 0x121, 9 }, { 0x1B, 7 }, { 0x30, 8 }, + { 0x1A, 7 }, { 0x1C4, 9 }, { 0x9F, 8 }, { 0xB6, 9 }, + { 0x19, 7 }, { 0x120, 9 }, { 0x73, 7 } + }, + { + { 0x23, 6 }, { 0x1C8, 9 }, { 0x43, 8 }, { 0x110, 9 }, + { 0xC, 7 }, { 0x153, 9 }, { 0x22, 7 }, { 0x111, 9 }, + { 0xF, 7 }, { 0x42, 8 }, { 0x23, 7 }, { 0x1C9, 9 }, + { 0x2A, 7 }, { 0x1B, 8 }, { 0x73, 7 }, { 0x45, 7 }, + { 0x6E, 7 }, { 0x89, 8 }, { 0x6C, 7 }, { 0x1A, 8 }, + { 0x6F, 7 }, { 0xB6, 8 }, { 0xB, 6 }, { 0xE5, 8 }, + { 0x25, 6 }, { 0x20, 7 }, { 0x29, 6 }, { 0x4D, 7 }, + { 0x2, 5 }, { 0x14, 6 }, { 0x1A, 5 }, { 0x17, 5 }, + { 0x1E, 5 }, { 0x27, 6 }, { 0x18, 5 }, { 0x28, 6 }, + { 0x1F, 5 }, { 0x0, 5 }, { 0x6, 4 }, { 0x10, 5 }, + { 0x7, 4 }, { 0xB, 5 }, { 0x3, 4 }, { 0x4, 5 }, + { 0x1D, 5 }, { 0x2C, 6 }, { 0x19, 5 }, { 0x2B, 6 }, + { 0x9, 5 }, { 0x55, 7 }, { 0x38, 6 }, { 0xE, 7 }, + { 0x24, 6 }, { 0xA8, 8 }, { 0xA, 6 }, { 0x99, 8 }, + { 0x5A, 7 }, { 0x98, 8 }, { 0x6D, 7 }, { 0x152, 9 }, + { 0x2B, 7 }, { 0xB7, 8 }, { 0x1, 5 } + }, + { + { 0x3D, 6 }, { 0xB1, 8 }, { 0xDD, 8 }, { 0x1F6, 9 }, + { 0xC5, 8 }, { 0x188, 9 }, { 0x37, 7 }, { 0x3F, 8 }, + { 0x1E, 7 }, { 0x189, 9 }, { 0xF, 7 }, { 0x3E, 8 }, + { 0x6A, 7 }, { 0x1F7, 9 }, { 0x61, 7 }, { 0x79, 7 }, + { 0x18, 6 }, { 0xB0, 8 }, { 0xE, 6 }, { 0xB3, 8 }, + { 0xC, 6 }, { 0xDF, 8 }, { 0x6, 6 }, { 0xDC, 8 }, + { 0x19, 6 }, { 0xDE, 8 }, { 0x27, 6 }, { 0xE, 7 }, + { 0x1A, 6 }, { 0x63, 7 }, { 0xF, 5 }, { 0xE, 5 }, + { 0x14, 5 }, { 0x7C, 7 }, { 0x36, 6 }, { 0x6B, 7 }, + { 0x3F, 6 }, { 0x60, 7 }, { 0x8, 5 }, { 0x74, 7 }, + { 0x9, 5 }, { 0x78, 7 }, { 0x12, 5 }, { 0xD, 6 }, + { 0x15, 5 }, { 0x2D, 6 }, { 0x2, 4 }, { 0x1C, 5 }, + { 0x5, 4 }, { 0x3B, 6 }, { 0x0, 4 }, { 0x34, 6 }, + { 0x19, 5 }, { 0x26, 6 }, { 0x10, 5 }, { 0x75, 7 }, + { 0x2, 5 }, { 0x36, 7 }, { 0x23, 6 }, { 0xB2, 8 }, + { 0x22, 6 }, { 0xFA, 8 }, { 0x17, 5 } + }, + { + { 0x15, 5 }, { 0xDD, 8 }, { 0x3E, 7 }, { 0x16E, 9 }, + { 0x4C, 7 }, { 0x12, 8 }, { 0x5D, 7 }, { 0xB6, 8 }, + { 0x6F, 7 }, { 0x1F1, 9 }, { 0x69, 7 }, { 0x1F0, 9 }, + { 0x1D, 7 }, { 0x16F, 9 }, { 0x2, 6 }, { 0x6B, 7 }, + { 0xC, 6 }, { 0xDC, 8 }, { 0x68, 7 }, { 0x9B, 8 }, + { 0x7D, 7 }, { 0x9A, 8 }, { 0xD, 6 }, { 0x13, 8 }, + { 0x8, 6 }, { 0xF9, 8 }, { 0x2C, 6 }, { 0x12, 7 }, + { 0x33, 6 }, { 0x4F, 7 }, { 0xD, 5 }, { 0x5, 5 }, + { 0x12, 5 }, { 0x3F, 7 }, { 0x32, 6 }, { 0x13, 7 }, + { 0x3B, 6 }, { 0x5, 6 }, { 0x2F, 6 }, { 0x5A, 7 }, + { 0x3F, 6 }, { 0x1C, 7 }, { 0x3A, 6 }, { 0x8, 7 }, + { 0x36, 6 }, { 0x5C, 7 }, { 0x10, 5 }, { 0x0, 5 }, + { 0xC, 5 }, { 0x4E, 7 }, { 0x3, 5 }, { 0x6A, 7 }, + { 0xE, 5 }, { 0x3, 6 }, { 0x14, 5 }, { 0x1E, 6 }, + { 0x1C, 5 }, { 0xF, 6 }, { 0x18, 5 }, { 0x23, 6 }, + { 0x1E, 5 }, { 0x22, 6 }, { 0x2, 3 } + } + }, + { /* y-axis tables */ + { + { 0x52, 7 }, { 0x14C, 9 }, { 0x1FA, 9 }, { 0x124, 9 }, + { 0x82, 8 }, { 0x29E, 10 }, { 0x8E, 8 }, { 0x24B, 10 }, + { 0x9C, 8 }, { 0x3F7, 10 }, { 0x86, 8 }, { 0x114, 9 }, + { 0x83, 8 }, { 0x3A5, 10 }, { 0xFA, 8 }, { 0x4F, 7 }, + { 0xFB, 8 }, { 0x13B, 9 }, { 0xFC, 8 }, { 0x172, 9 }, + { 0x44, 7 }, { 0x173, 9 }, { 0x51, 7 }, { 0x87, 8 }, + { 0x5F, 7 }, { 0xBA, 8 }, { 0x26, 6 }, { 0x5E, 7 }, + { 0x16, 5 }, { 0x15, 5 }, { 0x6, 3 }, { 0x1, 2 }, + { 0x0, 2 }, { 0x1C, 5 }, { 0x1E, 5 }, { 0x75, 7 }, + { 0x3B, 6 }, { 0xFF, 8 }, { 0x25, 6 }, { 0xBB, 8 }, + { 0x7C, 7 }, { 0x8B, 8 }, { 0x48, 7 }, { 0x171, 9 }, + { 0x42, 7 }, { 0x14E, 9 }, { 0x46, 7 }, { 0xFE, 8 }, + { 0x40, 7 }, { 0x13A, 9 }, { 0x93, 8 }, { 0x115, 9 }, + { 0x8F, 8 }, { 0x3F6, 10 }, { 0x170, 9 }, { 0x29F, 10 }, + { 0x1D1, 9 }, { 0x24A, 10 }, { 0x1D3, 9 }, { 0x3A4, 10 }, + { 0x1D0, 9 }, { 0x14D, 9 }, { 0x50, 7 } + }, + { + { 0xDE, 8 }, { 0x223, 10 }, { 0x136, 9 }, { 0x7C5, 11 }, + { 0x12F, 9 }, { 0x4A1, 11 }, { 0x3D7, 10 }, { 0x7AC, 11 }, + { 0x133, 9 }, { 0x7C4, 11 }, { 0x1B8, 9 }, { 0x222, 10 }, + { 0x96, 8 }, { 0x251, 10 }, { 0x95, 8 }, { 0x1F0, 9 }, + { 0xDA, 8 }, { 0x110, 9 }, { 0x9A, 8 }, { 0x360, 10 }, + { 0xDD, 8 }, { 0x12E, 9 }, { 0x48, 7 }, { 0x92, 8 }, + { 0x78, 7 }, { 0x98, 8 }, { 0x27, 6 }, { 0x45, 7 }, + { 0x1A, 5 }, { 0x10, 5 }, { 0x5, 3 }, { 0x0, 2 }, + { 0x1, 2 }, { 0xE, 4 }, { 0xC, 4 }, { 0x23, 6 }, + { 0x3F, 6 }, { 0xF4, 8 }, { 0x7D, 7 }, { 0x89, 8 }, + { 0x7B, 7 }, { 0x1BE, 9 }, { 0xF9, 8 }, { 0x3E3, 10 }, + { 0xF3, 8 }, { 0x127, 9 }, { 0xDB, 8 }, { 0x1EA, 9 }, + { 0xD9, 8 }, { 0x6E7, 11 }, { 0x1BF, 9 }, { 0x4A0, 11 }, + { 0x1B1, 9 }, { 0x6E6, 11 }, { 0x137, 9 }, { 0x7AD, 11 }, + { 0x126, 9 }, { 0x6C2, 11 }, { 0x132, 9 }, { 0x6C3, 11 }, + { 0x129, 9 }, { 0x372, 10 }, { 0xF2, 8 } + }, + { + { 0x16, 7 }, { 0x9C, 9 }, { 0x13C, 9 }, { 0x9E, 10 }, + { 0x12B, 9 }, { 0xBA, 10 }, { 0x181, 9 }, { 0x317, 10 }, + { 0x84, 8 }, { 0x4E, 9 }, { 0x26, 8 }, { 0x316, 10 }, + { 0x180, 9 }, { 0x5C, 9 }, { 0xC1, 8 }, { 0x2F, 8 }, + { 0x10, 7 }, { 0x45, 9 }, { 0x12, 7 }, { 0x189, 9 }, + { 0x24, 7 }, { 0x13D, 9 }, { 0x66, 7 }, { 0x23, 8 }, + { 0x67, 7 }, { 0xC6, 8 }, { 0x24, 6 }, { 0x4B, 7 }, + { 0x11, 5 }, { 0x32, 6 }, { 0xD, 4 }, { 0x0, 3 }, + { 0x7, 3 }, { 0x5, 3 }, { 0x3, 3 }, { 0x3, 4 }, + { 0x5, 4 }, { 0x20, 6 }, { 0x8, 5 }, { 0x25, 7 }, + { 0x26, 6 }, { 0x4F, 8 }, { 0x61, 7 }, { 0x2B, 8 }, + { 0x4E, 7 }, { 0x18A, 9 }, { 0x43, 7 }, { 0x9F, 8 }, + { 0x14, 7 }, { 0x254, 10 }, { 0x94, 8 }, { 0x310, 10 }, + { 0x85, 8 }, { 0x311, 10 }, { 0x2A, 8 }, { 0xBB, 10 }, + { 0x18F, 9 }, { 0x255, 10 }, { 0x9D, 9 }, { 0x9F, 10 }, + { 0x18E, 9 }, { 0x44, 9 }, { 0x26, 7 } + }, + { + { 0x61, 7 }, { 0x12A, 9 }, { 0xD, 8 }, { 0x3BD, 10 }, + { 0x89, 8 }, { 0x109, 9 }, { 0x18E, 9 }, { 0x210, 10 }, + { 0x1D3, 9 }, { 0x211, 10 }, { 0x88, 8 }, { 0x19, 9 }, + { 0x85, 8 }, { 0x18, 9 }, { 0xE8, 8 }, { 0xCE, 8 }, + { 0x40, 7 }, { 0x119, 9 }, { 0x45, 7 }, { 0x1D2, 9 }, + { 0x4B, 7 }, { 0x1DD, 9 }, { 0x62, 7 }, { 0x94, 8 }, + { 0x75, 7 }, { 0xC, 7 }, { 0x27, 6 }, { 0xD, 7 }, + { 0x2, 5 }, { 0x26, 6 }, { 0x6, 4 }, { 0x1E, 5 }, + { 0xD, 4 }, { 0x1F, 5 }, { 0x1, 3 }, { 0xA, 4 }, + { 0x2, 3 }, { 0x7, 4 }, { 0xB, 4 }, { 0x0, 5 }, + { 0x1C, 5 }, { 0x76, 7 }, { 0x32, 6 }, { 0x7, 7 }, + { 0x24, 6 }, { 0xC0, 8 }, { 0x7, 6 }, { 0x41, 7 }, + { 0x2, 6 }, { 0x18F, 9 }, { 0x47, 7 }, { 0x1DC, 9 }, + { 0x43, 7 }, { 0x12B, 9 }, { 0xCF, 8 }, { 0x118, 9 }, + { 0xC6, 8 }, { 0x3BC, 10 }, { 0x8D, 8 }, { 0x3BF, 10 }, + { 0xC1, 8 }, { 0x3BE, 10 }, { 0x66, 7 } + }, + { + { 0x7, 6 }, { 0x14D, 9 }, { 0xA0, 8 }, { 0x9E, 9 }, + { 0xCF, 8 }, { 0x39C, 10 }, { 0xA1, 8 }, { 0x39D, 10 }, + { 0xAB, 8 }, { 0x1C5, 9 }, { 0x26, 7 }, { 0x14C, 9 }, + { 0x25, 7 }, { 0x19C, 9 }, { 0x3F, 7 }, { 0xE1, 8 }, + { 0x66, 7 }, { 0x1CF, 9 }, { 0x3E, 7 }, { 0x1C4, 9 }, + { 0x72, 7 }, { 0x4E, 8 }, { 0x6, 6 }, { 0xAA, 8 }, + { 0x1C, 6 }, { 0xE6, 8 }, { 0x32, 6 }, { 0x51, 7 }, + { 0x3B, 6 }, { 0x5, 6 }, { 0x1F, 5 }, { 0x18, 5 }, + { 0x2, 4 }, { 0x3A, 6 }, { 0x0, 4 }, { 0x36, 6 }, + { 0x5, 4 }, { 0x8, 5 }, { 0x8, 4 }, { 0x16, 5 }, + { 0x9, 4 }, { 0xD, 5 }, { 0x3, 4 }, { 0x2F, 6 }, + { 0x1E, 5 }, { 0x2E, 6 }, { 0x1A, 5 }, { 0x2B, 6 }, + { 0xC, 5 }, { 0x24, 7 }, { 0x1E, 6 }, { 0xE0, 8 }, + { 0x4, 6 }, { 0xA7, 8 }, { 0x54, 7 }, { 0x1C7, 9 }, + { 0x52, 7 }, { 0x19D, 9 }, { 0x3A, 7 }, { 0x9F, 9 }, + { 0x3B, 7 }, { 0x1C6, 9 }, { 0x37, 6 } + }, + { + { 0x2A, 6 }, { 0x39, 8 }, { 0x25, 7 }, { 0x115, 9 }, + { 0x24, 7 }, { 0x1FA, 9 }, { 0x2F, 7 }, { 0x114, 9 }, + { 0x75, 7 }, { 0x38, 8 }, { 0xFC, 8 }, { 0x36, 8 }, + { 0x1E, 7 }, { 0x1FB, 9 }, { 0x7F, 7 }, { 0x68, 7 }, + { 0x16, 6 }, { 0x37, 8 }, { 0x1F, 7 }, { 0x5C, 8 }, + { 0x13, 6 }, { 0x8B, 8 }, { 0x1, 6 }, { 0xFB, 8 }, + { 0x21, 6 }, { 0x44, 7 }, { 0x2B, 6 }, { 0x6B, 7 }, + { 0x3B, 6 }, { 0xC, 6 }, { 0x1C, 5 }, { 0x19, 5 }, + { 0x1, 4 }, { 0x20, 6 }, { 0x16, 5 }, { 0x7C, 7 }, + { 0xC, 5 }, { 0x74, 7 }, { 0xA, 5 }, { 0x1C, 6 }, + { 0x12, 5 }, { 0x69, 7 }, { 0xF, 5 }, { 0x6A, 7 }, + { 0x14, 5 }, { 0x11, 6 }, { 0x1E, 5 }, { 0x17, 5 }, + { 0x2, 4 }, { 0x31, 6 }, { 0x1B, 5 }, { 0x30, 6 }, + { 0xD, 5 }, { 0x0, 6 }, { 0x1, 5 }, { 0x1D, 7 }, + { 0x23, 6 }, { 0x1A, 7 }, { 0x1D, 6 }, { 0x5D, 8 }, + { 0x10, 6 }, { 0xFA, 8 }, { 0x13, 5 } + }, + { + { 0x12, 5 }, { 0x26, 7 }, { 0x41, 7 }, { 0x22, 8 }, + { 0x1A, 7 }, { 0xA9, 8 }, { 0x4C, 7 }, { 0x1B2, 9 }, + { 0x5C, 7 }, { 0xA8, 8 }, { 0x58, 7 }, { 0x1B3, 9 }, + { 0x40, 7 }, { 0x79, 8 }, { 0xC, 6 }, { 0x55, 7 }, + { 0x1F, 6 }, { 0xD8, 8 }, { 0x76, 7 }, { 0x23, 8 }, + { 0x5F, 7 }, { 0x78, 8 }, { 0xB, 6 }, { 0x1B, 7 }, + { 0x2D, 6 }, { 0x10, 7 }, { 0x37, 6 }, { 0x6D, 7 }, + { 0x32, 6 }, { 0xA, 6 }, { 0x1A, 5 }, { 0x1E, 5 }, + { 0x1F, 5 }, { 0x2B, 6 }, { 0xD, 5 }, { 0x77, 7 }, + { 0x31, 6 }, { 0x5D, 7 }, { 0x38, 6 }, { 0x27, 7 }, + { 0xC, 5 }, { 0xE9, 8 }, { 0x33, 6 }, { 0x5E, 7 }, + { 0x30, 6 }, { 0x4D, 7 }, { 0xA, 5 }, { 0x21, 6 }, + { 0x7, 5 }, { 0x3D, 7 }, { 0x39, 6 }, { 0xE8, 8 }, + { 0xB, 5 }, { 0x59, 7 }, { 0x14, 5 }, { 0x27, 6 }, + { 0x11, 5 }, { 0x75, 7 }, { 0xE, 5 }, { 0x9, 6 }, + { 0x8, 5 }, { 0x12, 6 }, { 0x0, 3 } + } + } +}; + +static const uint16_t vp4_dc_bias[16][32][2] = { + { /* DC bias table 0 */ + { 0xC, 5 }, { 0x70, 7 }, { 0x1CA, 9 }, { 0x1CB, 9 }, + { 0x391, 10 }, { 0x1C9B, 13 }, { 0x3935, 14 }, { 0x71, 7 }, + { 0x3934, 14 }, { 0xB, 4 }, { 0xF, 4 }, { 0x19, 5 }, + { 0x2, 4 }, { 0x9, 4 }, { 0x3, 4 }, { 0x1D, 5 }, + { 0x18, 5 }, { 0x7, 4 }, { 0xD, 4 }, { 0x2, 3 }, + { 0x0, 3 }, { 0xA, 4 }, { 0x8, 4 }, { 0x1A, 6 }, + { 0x73, 7 }, { 0x6F, 8 }, { 0xE4C, 12 }, { 0x727, 11 }, + { 0x392, 10 }, { 0x390, 10 }, { 0x36, 7 }, { 0x6E, 8 } + }, + { /* DC bias table 1 */ + { 0x11, 5 }, { 0x7A, 7 }, { 0x83, 8 }, { 0x40, 7 }, + { 0x105, 9 }, { 0x413, 11 }, { 0x410, 11 }, { 0x7B, 7 }, + { 0x822, 12 }, { 0xE, 4 }, { 0x2, 3 }, { 0x2, 4 }, + { 0x6, 4 }, { 0xA, 4 }, { 0x7, 4 }, { 0x1F, 5 }, + { 0x17, 5 }, { 0x9, 4 }, { 0xD, 4 }, { 0x0, 3 }, + { 0xC, 4 }, { 0x3, 4 }, { 0x3C, 6 }, { 0x2C, 6 }, + { 0x21, 6 }, { 0x169, 9 }, { 0x412, 11 }, { 0x2D0, 10 }, + { 0x2D1, 10 }, { 0x823, 12 }, { 0x5B, 7 }, { 0xB5, 8 } + }, + { /* DC bias table 2 */ + { 0x17, 5 }, { 0x10, 6 }, { 0xB6, 8 }, { 0x22, 7 }, + { 0x16A, 9 }, { 0x2D0, 10 }, { 0xB48, 12 }, { 0x77, 7 }, + { 0x1692, 13 }, { 0x0, 3 }, { 0x3, 3 }, { 0x3, 4 }, + { 0x9, 4 }, { 0xC, 4 }, { 0x5, 4 }, { 0x2, 4 }, + { 0x1C, 5 }, { 0x8, 4 }, { 0xD, 4 }, { 0xF, 4 }, + { 0xA, 4 }, { 0x9, 5 }, { 0x23, 7 }, { 0x3A, 6 }, + { 0x2C, 6 }, { 0x16B, 9 }, { 0x5A5, 11 }, { 0x2D3, 10 }, + { 0x2D1, 10 }, { 0x1693, 13 }, { 0x76, 7 }, { 0xB7, 8 } + }, + { /* DC bias table 3 */ + { 0x1E, 5 }, { 0x13, 6 }, { 0xFB, 8 }, { 0x7C, 7 }, + { 0x46, 8 }, { 0x7D6, 11 }, { 0xFA9, 12 }, { 0x12, 6 }, + { 0x1F50, 13 }, { 0x1, 3 }, { 0x4, 3 }, { 0x5, 4 }, + { 0xA, 4 }, { 0xE, 4 }, { 0x7, 4 }, { 0x0, 4 }, + { 0x17, 5 }, { 0x6, 4 }, { 0xD, 4 }, { 0xC, 4 }, + { 0x1, 4 }, { 0x2C, 6 }, { 0x8F, 9 }, { 0x3F, 6 }, + { 0x2D, 6 }, { 0x1F4, 9 }, { 0x7D5, 11 }, { 0x8E, 9 }, + { 0x7D7, 11 }, { 0x1F51, 13 }, { 0x10, 6 }, { 0x22, 7 } + }, + { /* DC bias table 4 */ + { 0x1, 4 }, { 0x2B, 6 }, { 0x12, 7 }, { 0x55, 7 }, + { 0x27, 8 }, { 0x3B0, 10 }, { 0x762, 11 }, { 0x77, 7 }, + { 0x261, 12 }, { 0x2, 3 }, { 0x6, 3 }, { 0x7, 4 }, + { 0xB, 4 }, { 0xF, 4 }, { 0x8, 4 }, { 0x0, 4 }, + { 0x1C, 5 }, { 0x3, 4 }, { 0x9, 4 }, { 0x6, 4 }, + { 0x14, 5 }, { 0x54, 7 }, { 0x131, 11 }, { 0x5, 5 }, + { 0x3A, 6 }, { 0x1D9, 9 }, { 0x99, 10 }, { 0x4D, 9 }, + { 0x763, 11 }, { 0x260, 12 }, { 0x8, 6 }, { 0xED, 8 } + }, + { /* DC bias table 5 */ + { 0x4, 4 }, { 0x33, 6 }, { 0x60, 7 }, { 0x65, 7 }, + { 0xC2, 8 }, { 0x30D, 10 }, { 0x619, 11 }, { 0x64, 7 }, + { 0x1862, 13 }, { 0x4, 3 }, { 0x7, 3 }, { 0xA, 4 }, + { 0xB, 4 }, { 0xD, 4 }, { 0x6, 4 }, { 0x0, 4 }, + { 0xF, 5 }, { 0x3, 4 }, { 0x5, 4 }, { 0x2, 4 }, + { 0x2, 5 }, { 0x77, 8 }, { 0xC30, 12 }, { 0x3, 5 }, + { 0x31, 6 }, { 0x187, 9 }, { 0x1D9, 10 }, { 0xED, 9 }, + { 0x1D8, 10 }, { 0x1863, 13 }, { 0x1C, 6 }, { 0x3A, 7 } + }, + { /* DC bias table 6 */ + { 0x8, 4 }, { 0xA, 5 }, { 0x6A, 7 }, { 0x16, 6 }, + { 0x1E, 7 }, { 0x34E, 10 }, { 0x69F, 11 }, { 0x68, 7 }, + { 0xD28, 12 }, { 0x5, 3 }, { 0x7, 3 }, { 0x7, 4 }, + { 0xC, 4 }, { 0x0, 3 }, { 0x6, 4 }, { 0x1B, 5 }, + { 0x12, 5 }, { 0x2, 4 }, { 0x4, 4 }, { 0x13, 5 }, + { 0xE, 6 }, { 0x34B, 10 }, { 0x1A53, 13 }, { 0x6, 5 }, + { 0x17, 6 }, { 0x1A6, 9 }, { 0x69E, 11 }, { 0x1A4, 9 }, + { 0x695, 11 }, { 0x1A52, 13 }, { 0x6B, 7 }, { 0x1F, 7 } + }, + { /* DC bias table 7 */ + { 0xE, 4 }, { 0xF, 5 }, { 0x17, 6 }, { 0x25, 6 }, + { 0x9F, 8 }, { 0x138, 9 }, { 0x24B, 10 }, { 0x93, 8 }, + { 0x92A, 12 }, { 0x5, 3 }, { 0x0, 2 }, { 0x8, 4 }, + { 0xD, 4 }, { 0xF, 4 }, { 0x6, 4 }, { 0x4, 4 }, + { 0xE, 5 }, { 0x19, 5 }, { 0x18, 5 }, { 0xA, 5 }, + { 0x9E, 8 }, { 0x494, 11 }, { 0x1256, 13 }, { 0x26, 6 }, + { 0x16, 6 }, { 0x124, 9 }, { 0x4E5, 11 }, { 0x273, 10 }, + { 0x4E4, 11 }, { 0x1257, 13 }, { 0x48, 7 }, { 0x9D, 8 } + }, + { /* DC bias table 8 */ + { 0x4, 4 }, { 0x2C, 6 }, { 0x50, 7 }, { 0x1E, 7 }, + { 0x71, 9 }, { 0xE1, 10 }, { 0xE0, 10 }, { 0x1D, 7 }, + { 0x6, 6 }, { 0x7, 3 }, { 0x6, 3 }, { 0x7, 4 }, + { 0x5, 4 }, { 0x6, 4 }, { 0x15, 5 }, { 0x0, 5 }, + { 0x29, 6 }, { 0x2, 5 }, { 0x6, 5 }, { 0x1, 5 }, + { 0x23, 6 }, { 0x1F, 7 }, { 0x39, 8 }, { 0x9, 4 }, + { 0x2, 4 }, { 0x10, 5 }, { 0x7, 6 }, { 0x2D, 6 }, + { 0x2F, 6 }, { 0x2E, 6 }, { 0x22, 6 }, { 0x51, 7 } + }, + { /* DC bias table 9 */ + { 0x8, 4 }, { 0x2F, 6 }, { 0x51, 7 }, { 0x50, 7 }, + { 0x2ED, 10 }, { 0x5D9, 11 }, { 0x5D8, 11 }, { 0xBA, 8 }, + { 0x5C, 7 }, { 0x7, 3 }, { 0x6, 3 }, { 0x9, 4 }, + { 0x6, 4 }, { 0x7, 4 }, { 0x16, 5 }, { 0x5, 5 }, + { 0x2B, 6 }, { 0x6, 5 }, { 0xA, 5 }, { 0x1, 5 }, + { 0xF, 6 }, { 0x1D, 7 }, { 0x177, 9 }, { 0x4, 4 }, + { 0x1, 4 }, { 0x4, 5 }, { 0x1, 6 }, { 0x2A, 6 }, + { 0xB, 5 }, { 0x29, 6 }, { 0x0, 6 }, { 0x1C, 7 } + }, + { /* DC bias table 10 */ + { 0xA, 4 }, { 0x3C, 6 }, { 0x74, 7 }, { 0x4E, 7 }, + { 0x26D, 10 }, { 0x4D9, 11 }, { 0x4D8, 11 }, { 0x9A, 8 }, + { 0x4C, 7 }, { 0x0, 2 }, { 0x6, 3 }, { 0x8, 4 }, + { 0x7, 4 }, { 0x6, 4 }, { 0x16, 5 }, { 0x8, 5 }, + { 0x2E, 6 }, { 0xA, 5 }, { 0xB, 5 }, { 0x3D, 6 }, + { 0x24, 6 }, { 0xEB, 8 }, { 0x137, 9 }, { 0x1F, 5 }, + { 0x1C, 5 }, { 0x3B, 6 }, { 0x12, 6 }, { 0x25, 6 }, + { 0x2F, 6 }, { 0x13, 6 }, { 0x4F, 7 }, { 0xEA, 8 } + }, + { /* DC bias table 11 */ + { 0xA, 4 }, { 0xA, 5 }, { 0x3, 6 }, { 0x16, 6 }, + { 0x9, 8 }, { 0x21, 10 }, { 0x20, 10 }, { 0xB3, 8 }, + { 0x58, 7 }, { 0x7, 3 }, { 0x6, 3 }, { 0x7, 4 }, + { 0x6, 4 }, { 0x4, 4 }, { 0x13, 5 }, { 0x2, 5 }, + { 0x25, 6 }, { 0x0, 5 }, { 0x3, 5 }, { 0x2D, 6 }, + { 0x5D, 7 }, { 0xB2, 8 }, { 0x11, 9 }, { 0x8, 4 }, + { 0x2, 4 }, { 0x6, 5 }, { 0x17, 6 }, { 0x2F, 6 }, + { 0x7, 5 }, { 0x24, 6 }, { 0x5C, 7 }, { 0x5, 7 } + }, + { /* DC bias table 12 */ + { 0xB, 4 }, { 0x13, 5 }, { 0x1F, 6 }, { 0x31, 6 }, + { 0x21, 7 }, { 0x295, 10 }, { 0x528, 11 }, { 0xA4, 8 }, + { 0x3C, 7 }, { 0x0, 2 }, { 0x7, 3 }, { 0x6, 4 }, + { 0x5, 4 }, { 0x1B, 5 }, { 0x12, 5 }, { 0x32, 6 }, + { 0x1D, 6 }, { 0x2B, 6 }, { 0x30, 6 }, { 0x1C, 6 }, + { 0x3D, 7 }, { 0x14B, 9 }, { 0x529, 11 }, { 0x8, 4 }, + { 0x1A, 5 }, { 0x33, 6 }, { 0x11, 6 }, { 0x2A, 6 }, + { 0x9, 5 }, { 0x28, 6 }, { 0x53, 7 }, { 0x20, 7 } + }, + { /* DC bias table 13 */ + { 0xE, 4 }, { 0x15, 5 }, { 0x29, 6 }, { 0x3F, 6 }, + { 0x4D, 7 }, { 0x2F1, 10 }, { 0x5E0, 11 }, { 0x92, 8 }, + { 0x48, 7 }, { 0x0, 2 }, { 0x6, 3 }, { 0x6, 4 }, + { 0x5, 4 }, { 0x4, 4 }, { 0xF, 5 }, { 0x2E, 6 }, + { 0x1D, 6 }, { 0x28, 6 }, { 0x27, 6 }, { 0x5F, 7 }, + { 0xBD, 8 }, { 0x179, 9 }, { 0x5E1, 11 }, { 0x8, 4 }, + { 0x1E, 5 }, { 0x2D, 6 }, { 0x1C, 6 }, { 0x2C, 6 }, + { 0x3E, 6 }, { 0x25, 6 }, { 0x4C, 7 }, { 0x93, 8 } + }, + { /* DC bias table 14 */ + { 0xC, 4 }, { 0x17, 5 }, { 0x35, 6 }, { 0x13, 5 }, + { 0x21, 6 }, { 0xAD, 8 }, { 0x6F1, 11 }, { 0x1BD, 9 }, + { 0xD9, 8 }, { 0x0, 2 }, { 0x7, 3 }, { 0x7, 4 }, + { 0x6, 4 }, { 0x4, 4 }, { 0x11, 5 }, { 0x2A, 6 }, + { 0x6E, 7 }, { 0x25, 6 }, { 0x24, 6 }, { 0x57, 7 }, + { 0xD8, 8 }, { 0x379, 10 }, { 0x6F0, 11 }, { 0x5, 4 }, + { 0x16, 5 }, { 0x29, 6 }, { 0x6D, 7 }, { 0x28, 6 }, + { 0x34, 6 }, { 0x20, 6 }, { 0xDF, 8 }, { 0xAC, 8 } + }, + { /* DC bias table 15 */ + { 0x0, 3 }, { 0x1A, 5 }, { 0x6, 5 }, { 0x19, 5 }, + { 0x30, 6 }, { 0x5A, 7 }, { 0x18A, 9 }, { 0x2DD, 10 }, + { 0x18B, 9 }, { 0x1, 2 }, { 0x7, 3 }, { 0xA, 4 }, + { 0x9, 4 }, { 0x2, 4 }, { 0x10, 5 }, { 0x2E, 6 }, + { 0x6E, 7 }, { 0x2C, 6 }, { 0xE, 6 }, { 0x5E, 7 }, + { 0xC4, 8 }, { 0x5B9, 11 }, { 0x5B8, 11 }, { 0x11, 5 }, + { 0x36, 6 }, { 0x5F, 7 }, { 0x1E, 7 }, { 0x63, 7 }, + { 0x6F, 7 }, { 0x1F, 7 }, { 0xB6, 8 }, { 0x16F, 9 } + } +}; + +static const uint16_t vp4_ac_bias_0[16][32][2] = { + { /* AC bias group 1, table 0 */ + { 0x6, 5 }, { 0x1E, 7 }, { 0x1CC, 9 }, { 0x1CE, 9 }, + { 0x734, 11 }, { 0x1CD5, 13 }, { 0x1CD4, 13 }, { 0x18, 5 }, + { 0xE6B, 12 }, { 0x0, 3 }, { 0xF, 4 }, { 0x6, 4 }, + { 0x7, 4 }, { 0xD, 4 }, { 0x8, 4 }, { 0x2, 4 }, + { 0x19, 5 }, { 0x5, 4 }, { 0xB, 4 }, { 0xA, 4 }, + { 0x1D, 5 }, { 0x27, 6 }, { 0x1CF, 9 }, { 0x4, 4 }, + { 0x38, 6 }, { 0xE, 6 }, { 0x4C, 7 }, { 0x1F, 7 }, + { 0x4D, 7 }, { 0x39B, 10 }, { 0x12, 5 }, { 0x72, 7 } + }, + { /* AC bias group 1, table 1 */ + { 0x9, 5 }, { 0x4B, 7 }, { 0x90, 8 }, { 0x91, 8 }, + { 0x745, 11 }, { 0x1D11, 13 }, { 0x1D10, 13 }, { 0x19, 5 }, + { 0xE89, 12 }, { 0x0, 3 }, { 0xF, 4 }, { 0x8, 4 }, + { 0x7, 4 }, { 0xD, 4 }, { 0xB, 4 }, { 0x2, 4 }, + { 0x1C, 5 }, { 0x3, 4 }, { 0xA, 4 }, { 0x5, 4 }, + { 0x18, 5 }, { 0x10, 6 }, { 0x1D0, 9 }, { 0x6, 4 }, + { 0x3B, 6 }, { 0x11, 6 }, { 0x4A, 7 }, { 0x49, 7 }, + { 0xE9, 8 }, { 0x3A3, 10 }, { 0x13, 5 }, { 0x75, 7 } + }, + { /* AC bias group 1, table 2 */ + { 0x19, 5 }, { 0x74, 7 }, { 0x1D, 8 }, { 0xEA, 8 }, + { 0x73, 10 }, { 0x1CA, 12 }, { 0x396, 13 }, { 0x1C, 5 }, + { 0xE4, 11 }, { 0x2, 3 }, { 0x1, 3 }, { 0x7, 4 }, + { 0x8, 4 }, { 0xD, 4 }, { 0x9, 4 }, { 0x1F, 5 }, + { 0x18, 5 }, { 0x0, 4 }, { 0x6, 4 }, { 0x1E, 5 }, + { 0x3B, 6 }, { 0xEB, 8 }, { 0x397, 13 }, { 0xA, 4 }, + { 0x2, 5 }, { 0x2C, 6 }, { 0x5B, 7 }, { 0x5A, 7 }, + { 0xF, 7 }, { 0x38, 9 }, { 0x17, 5 }, { 0x6, 6 } + }, + { /* AC bias group 1, table 3 */ + { 0x1E, 5 }, { 0x6F, 7 }, { 0xAE, 8 }, { 0xAF, 8 }, + { 0x187, 10 }, { 0x61B, 12 }, { 0xC35, 13 }, { 0x1A, 5 }, + { 0x30C, 11 }, { 0x2, 3 }, { 0x1, 3 }, { 0x7, 4 }, + { 0x8, 4 }, { 0xE, 4 }, { 0x9, 4 }, { 0x1F, 5 }, + { 0x14, 5 }, { 0x0, 4 }, { 0x1, 4 }, { 0x19, 5 }, + { 0x2A, 6 }, { 0x60, 8 }, { 0xC34, 13 }, { 0xB, 4 }, + { 0xD, 5 }, { 0x36, 6 }, { 0x6E, 7 }, { 0x56, 7 }, + { 0x31, 7 }, { 0xC2, 9 }, { 0x18, 5 }, { 0x19, 6 } + }, + { /* AC bias group 1, table 4 */ + { 0x1, 4 }, { 0x2C, 6 }, { 0x5, 7 }, { 0x15, 7 }, + { 0x8, 8 }, { 0x97, 12 }, { 0x12D, 13 }, { 0x17, 5 }, + { 0x4A, 11 }, { 0x3, 3 }, { 0x2, 3 }, { 0x9, 4 }, + { 0xA, 4 }, { 0xE, 4 }, { 0x8, 4 }, { 0x1F, 5 }, + { 0x7, 5 }, { 0x1E, 5 }, { 0x1B, 5 }, { 0x4, 5 }, + { 0x5A, 7 }, { 0x24, 10 }, { 0x12C, 13 }, { 0xC, 4 }, + { 0x6, 5 }, { 0x0, 5 }, { 0x3, 6 }, { 0x5B, 7 }, + { 0x14, 7 }, { 0x13, 9 }, { 0x1A, 5 }, { 0xB, 6 } + }, + { /* AC bias group 1, table 5 */ + { 0x4, 4 }, { 0x0, 5 }, { 0x17, 7 }, { 0x63, 7 }, + { 0x18B, 9 }, { 0x310, 10 }, { 0xC44, 12 }, { 0x19, 5 }, + { 0x623, 11 }, { 0x4, 3 }, { 0x3, 3 }, { 0xA, 4 }, + { 0xB, 4 }, { 0xD, 4 }, { 0x3, 4 }, { 0x1C, 5 }, + { 0x3, 5 }, { 0xA, 5 }, { 0x4, 5 }, { 0x3, 6 }, + { 0x18A, 9 }, { 0x188B, 13 }, { 0x188A, 13 }, { 0xF, 4 }, + { 0xB, 5 }, { 0x2, 5 }, { 0xA, 6 }, { 0x2, 6 }, + { 0x16, 7 }, { 0x189, 9 }, { 0x1D, 5 }, { 0x30, 6 } + }, + { /* AC bias group 1, table 6 */ + { 0xD, 4 }, { 0x3, 5 }, { 0x77, 7 }, { 0xD, 6 }, + { 0x82, 8 }, { 0x20D, 10 }, { 0x830, 12 }, { 0x19, 5 }, + { 0x419, 11 }, { 0x3, 3 }, { 0x2, 3 }, { 0xA, 4 }, + { 0x9, 4 }, { 0xB, 4 }, { 0x2, 4 }, { 0x11, 5 }, + { 0x39, 6 }, { 0x2, 5 }, { 0x21, 6 }, { 0x40, 7 }, + { 0x1063, 13 }, { 0x20C5, 14 }, { 0x20C4, 14 }, { 0xF, 4 }, + { 0x18, 5 }, { 0x7, 5 }, { 0x38, 6 }, { 0xC, 6 }, + { 0x76, 7 }, { 0x107, 9 }, { 0x0, 4 }, { 0x3A, 6 } + }, + { /* AC bias group 1, table 7 */ + { 0xF, 4 }, { 0x1C, 5 }, { 0x36, 6 }, { 0x8, 5 }, + { 0x61, 7 }, { 0x91, 8 }, { 0x243, 10 }, { 0x9, 5 }, + { 0x120, 9 }, { 0x5, 3 }, { 0x3, 3 }, { 0x8, 4 }, + { 0x5, 4 }, { 0x1, 4 }, { 0x13, 5 }, { 0x31, 6 }, + { 0x76, 7 }, { 0x60, 7 }, { 0x93, 8 }, { 0x909, 12 }, + { 0x908, 12 }, { 0x90B, 12 }, { 0x90A, 12 }, { 0x1, 3 }, + { 0x1A, 5 }, { 0x19, 5 }, { 0x3A, 6 }, { 0x25, 6 }, + { 0x77, 7 }, { 0x92, 8 }, { 0x0, 4 }, { 0x37, 6 } + }, + { /* AC bias group 1, table 8 */ + { 0x1F, 5 }, { 0x79, 7 }, { 0xF1, 8 }, { 0xF0, 8 }, + { 0x11B, 10 }, { 0x469, 12 }, { 0x468, 12 }, { 0x3B, 6 }, + { 0x22, 7 }, { 0x5, 3 }, { 0x4, 3 }, { 0x7, 4 }, + { 0x5, 4 }, { 0x6, 4 }, { 0x1C, 5 }, { 0x1, 5 }, + { 0x35, 6 }, { 0x3D, 6 }, { 0x3A, 6 }, { 0x10, 6 }, + { 0x47, 8 }, { 0x8C, 9 }, { 0x235, 11 }, { 0x1, 3 }, + { 0x1, 4 }, { 0x19, 5 }, { 0x0, 5 }, { 0x30, 6 }, + { 0x9, 5 }, { 0x31, 6 }, { 0x1B, 5 }, { 0x34, 6 } + }, + { /* AC bias group 1, table 9 */ + { 0x3, 4 }, { 0x1B, 6 }, { 0xF3, 8 }, { 0xFD, 8 }, + { 0x3C9, 10 }, { 0xF20, 12 }, { 0x1E42, 13 }, { 0x3D, 6 }, + { 0xFC, 8 }, { 0x6, 3 }, { 0x4, 3 }, { 0x2, 4 }, + { 0x0, 4 }, { 0x1, 4 }, { 0x17, 5 }, { 0x3E, 6 }, + { 0x1A, 6 }, { 0x39, 6 }, { 0x2B, 6 }, { 0x78, 7 }, + { 0x1E5, 9 }, { 0x791, 11 }, { 0x1E43, 13 }, { 0x2, 3 }, + { 0x7, 4 }, { 0x1D, 5 }, { 0xC, 5 }, { 0x38, 6 }, + { 0x14, 5 }, { 0x7F, 7 }, { 0x16, 5 }, { 0x2A, 6 } + }, + { /* AC bias group 1, table 10 */ + { 0x7, 4 }, { 0x39, 6 }, { 0x51, 7 }, { 0x78, 7 }, + { 0x3CB, 10 }, { 0xF29, 12 }, { 0x1E51, 13 }, { 0x3D, 6 }, + { 0xF3, 8 }, { 0x6, 3 }, { 0x4, 3 }, { 0x2, 4 }, + { 0x0, 4 }, { 0x1, 4 }, { 0x17, 5 }, { 0x3E, 6 }, + { 0x7F, 7 }, { 0x2B, 6 }, { 0x7E, 7 }, { 0x50, 7 }, + { 0x1E4, 9 }, { 0x795, 11 }, { 0x1E50, 13 }, { 0x2, 3 }, + { 0x6, 4 }, { 0x1D, 5 }, { 0x6, 5 }, { 0x38, 6 }, + { 0x7, 5 }, { 0x29, 6 }, { 0x16, 5 }, { 0x2A, 6 } + }, + { /* AC bias group 1, table 11 */ + { 0x8, 4 }, { 0x3B, 6 }, { 0x1D, 7 }, { 0x72, 7 }, + { 0x1CC, 9 }, { 0x734, 11 }, { 0x1CD5, 13 }, { 0x3A, 6 }, + { 0x1C, 7 }, { 0x6, 3 }, { 0x5, 3 }, { 0x2, 4 }, + { 0x1, 4 }, { 0x0, 4 }, { 0x12, 5 }, { 0x3E, 6 }, + { 0x7F, 7 }, { 0x1E, 6 }, { 0x7E, 7 }, { 0xE7, 8 }, + { 0x39B, 10 }, { 0xE6B, 12 }, { 0x1CD4, 13 }, { 0x2, 3 }, + { 0x6, 4 }, { 0x1E, 5 }, { 0xE, 5 }, { 0x38, 6 }, + { 0x6, 5 }, { 0xF, 6 }, { 0x13, 5 }, { 0x1F, 6 } + }, + { /* AC bias group 1, table 12 */ + { 0xD, 4 }, { 0x3F, 6 }, { 0x73, 7 }, { 0xC, 6 }, + { 0xE4, 8 }, { 0x72B, 11 }, { 0xE54, 12 }, { 0x3A, 6 }, + { 0x1A, 7 }, { 0x5, 3 }, { 0x4, 3 }, { 0x2, 4 }, + { 0x1, 4 }, { 0x0, 4 }, { 0x7, 5 }, { 0x38, 6 }, + { 0x76, 7 }, { 0x77, 7 }, { 0x1B, 7 }, { 0x1CB, 9 }, + { 0x394, 10 }, { 0x1CAB, 13 }, { 0x1CAA, 13 }, { 0x2, 3 }, + { 0x6, 4 }, { 0x1E, 5 }, { 0xE, 5 }, { 0x3E, 6 }, + { 0x19, 5 }, { 0x1F, 6 }, { 0x18, 5 }, { 0x1E, 6 } + }, + { /* AC bias group 1, table 13 */ + { 0xE, 4 }, { 0x7, 5 }, { 0xC, 6 }, { 0x1C, 6 }, + { 0xBD, 8 }, { 0x2F3, 10 }, { 0xBC9, 12 }, { 0x1F, 6 }, + { 0xBF, 8 }, { 0x6, 3 }, { 0x4, 3 }, { 0x2, 4 }, + { 0x1, 4 }, { 0x1E, 5 }, { 0x1, 5 }, { 0xD, 6 }, + { 0x3A, 7 }, { 0x3B, 7 }, { 0xBE, 8 }, { 0x178, 9 }, + { 0x5E5, 11 }, { 0x1791, 13 }, { 0x1790, 13 }, { 0x2, 3 }, + { 0x6, 4 }, { 0x1F, 5 }, { 0x16, 5 }, { 0x0, 5 }, + { 0x15, 5 }, { 0x2E, 6 }, { 0x14, 5 }, { 0x1E, 6 } + }, + { /* AC bias group 1, table 14 */ + { 0x0, 3 }, { 0x1B, 5 }, { 0x31, 6 }, { 0x3A, 6 }, + { 0x60, 7 }, { 0x6F, 9 }, { 0x1B9, 11 }, { 0xE, 6 }, + { 0x1A, 7 }, { 0x5, 3 }, { 0x3, 3 }, { 0x2, 4 }, + { 0x1F, 5 }, { 0x1A, 5 }, { 0x39, 6 }, { 0xC, 6 }, + { 0xC3, 8 }, { 0xC2, 8 }, { 0x36, 8 }, { 0xDD, 10 }, + { 0x370, 12 }, { 0x6E3, 13 }, { 0x6E2, 13 }, { 0x2, 3 }, + { 0x8, 4 }, { 0x1E, 5 }, { 0x19, 5 }, { 0x3B, 6 }, + { 0x12, 5 }, { 0xF, 6 }, { 0x13, 5 }, { 0x38, 6 } + }, + { /* AC bias group 1, table 15 */ + { 0x2, 3 }, { 0x0, 4 }, { 0x3, 5 }, { 0x1C, 5 }, + { 0x32, 6 }, { 0x1C, 7 }, { 0x199, 9 }, { 0x4, 6 }, + { 0xCD, 8 }, { 0x4, 3 }, { 0x3, 3 }, { 0x1B, 5 }, + { 0x1A, 5 }, { 0x3D, 6 }, { 0x67, 7 }, { 0x3B, 8 }, + { 0x198, 9 }, { 0x75, 9 }, { 0xE9, 10 }, { 0x3A1, 12 }, + { 0x3A0, 12 }, { 0x3A3, 12 }, { 0x3A2, 12 }, { 0x5, 3 }, + { 0x2, 4 }, { 0x1F, 5 }, { 0x1D, 5 }, { 0x3C, 6 }, + { 0x18, 5 }, { 0xF, 6 }, { 0x6, 5 }, { 0x5, 6 } + } +}; + +static const uint16_t vp4_ac_bias_1[16][32][2] = { + { /* AC bias group 2, table 0 */ + { 0x4, 5 }, { 0xF5, 8 }, { 0x182, 9 }, { 0x60F, 11 }, + { 0x1839, 13 }, { 0x1838, 13 }, { 0x183B, 13 }, { 0x13, 5 }, + { 0xC0, 8 }, { 0x3, 3 }, { 0x2, 3 }, { 0xB, 4 }, + { 0xA, 4 }, { 0xE, 4 }, { 0x8, 4 }, { 0x1, 4 }, + { 0x12, 5 }, { 0x1F, 5 }, { 0x0, 4 }, { 0x6, 5 }, + { 0x7B, 7 }, { 0x306, 10 }, { 0x183A, 13 }, { 0xD, 4 }, + { 0x7, 5 }, { 0x31, 6 }, { 0xA, 6 }, { 0x61, 7 }, + { 0x3C, 6 }, { 0xF4, 8 }, { 0x19, 5 }, { 0xB, 6 } + }, + { /* AC bias group 2, table 1 */ + { 0xA, 5 }, { 0x1A, 7 }, { 0x1D8, 9 }, { 0x3B3, 10 }, + { 0xECA, 12 }, { 0x1D96, 13 }, { 0x3B2F, 14 }, { 0x14, 5 }, + { 0x36, 8 }, { 0x4, 3 }, { 0x3, 3 }, { 0xC, 4 }, + { 0xB, 4 }, { 0x0, 3 }, { 0x4, 4 }, { 0x1C, 5 }, + { 0x5, 5 }, { 0x15, 5 }, { 0x7, 5 }, { 0x17, 6 }, + { 0x37, 8 }, { 0x764, 11 }, { 0x3B2E, 14 }, { 0xF, 4 }, + { 0x1A, 5 }, { 0x3A, 6 }, { 0xC, 6 }, { 0x77, 7 }, + { 0x4, 5 }, { 0xED, 8 }, { 0x1B, 5 }, { 0x16, 6 } + }, + { /* AC bias group 2, table 2 */ + { 0x1A, 5 }, { 0x2D, 7 }, { 0x58, 8 }, { 0x1F4, 9 }, + { 0x7D4, 11 }, { 0x1F55, 13 }, { 0x1F54, 13 }, { 0x14, 5 }, + { 0x59, 8 }, { 0x4, 3 }, { 0x3, 3 }, { 0xB, 4 }, + { 0xC, 4 }, { 0xE, 4 }, { 0x4, 4 }, { 0x15, 5 }, + { 0x5, 5 }, { 0x7, 5 }, { 0x4, 5 }, { 0x7C, 7 }, + { 0x3EB, 10 }, { 0x1F57, 13 }, { 0x1F56, 13 }, { 0x0, 3 }, + { 0x1B, 5 }, { 0x3F, 6 }, { 0xD, 6 }, { 0xC, 6 }, + { 0xA, 5 }, { 0xFB, 8 }, { 0x1E, 5 }, { 0x17, 6 } + }, + { /* AC bias group 2, table 3 */ + { 0x0, 4 }, { 0x75, 7 }, { 0x4A, 8 }, { 0x97, 9 }, + { 0x25B, 11 }, { 0x969, 13 }, { 0x968, 13 }, { 0xB, 5 }, + { 0xE8, 8 }, { 0x5, 3 }, { 0x4, 3 }, { 0x7, 4 }, + { 0xC, 4 }, { 0xD, 4 }, { 0x1, 4 }, { 0xA, 5 }, + { 0x39, 6 }, { 0x3B, 6 }, { 0x18, 6 }, { 0xE9, 8 }, + { 0x12C, 10 }, { 0x96B, 13 }, { 0x96A, 13 }, { 0x1, 3 }, + { 0x1F, 5 }, { 0x8, 5 }, { 0x19, 6 }, { 0x13, 6 }, + { 0xD, 5 }, { 0x24, 7 }, { 0x1E, 5 }, { 0x38, 6 } + }, + { /* AC bias group 2, table 4 */ + { 0x4, 4 }, { 0x14, 6 }, { 0x6E, 8 }, { 0x57, 8 }, + { 0x159, 10 }, { 0x562, 12 }, { 0xAC7, 13 }, { 0xB, 5 }, + { 0x6F, 8 }, { 0x6, 3 }, { 0x5, 3 }, { 0x8, 4 }, + { 0x9, 4 }, { 0x7, 4 }, { 0x1E, 5 }, { 0x2, 5 }, + { 0x7, 6 }, { 0x6, 6 }, { 0x2A, 7 }, { 0xAD, 9 }, + { 0xAC6, 13 }, { 0x561, 12 }, { 0x560, 12 }, { 0x1, 3 }, + { 0x1F, 5 }, { 0xC, 5 }, { 0x39, 6 }, { 0x1A, 6 }, + { 0x0, 4 }, { 0x36, 7 }, { 0x1D, 5 }, { 0x38, 6 } + }, + { /* AC bias group 2, table 5 */ + { 0x7, 4 }, { 0x1B, 6 }, { 0xE, 7 }, { 0xD, 7 }, + { 0x3E1, 10 }, { 0x1F06, 13 }, { 0x3E0F, 14 }, { 0x2, 5 }, + { 0xF9, 8 }, { 0x5, 3 }, { 0x6, 3 }, { 0x8, 4 }, + { 0x9, 4 }, { 0x4, 4 }, { 0xC, 5 }, { 0x1A, 6 }, + { 0xF, 7 }, { 0xC, 7 }, { 0x1F1, 9 }, { 0x7C0, 11 }, + { 0x3E0E, 14 }, { 0x1F05, 13 }, { 0x1F04, 13 }, { 0x1, 3 }, + { 0x0, 4 }, { 0x1C, 5 }, { 0x3F, 6 }, { 0x3D, 6 }, + { 0x5, 4 }, { 0x7D, 7 }, { 0x1D, 5 }, { 0x3C, 6 } + }, + { /* AC bias group 2, table 6 */ + { 0xF, 4 }, { 0xA, 5 }, { 0x71, 7 }, { 0x6, 6 }, + { 0x1C2, 9 }, { 0x702, 11 }, { 0x1C0E, 13 }, { 0x2, 5 }, + { 0xE, 7 }, { 0x5, 3 }, { 0x4, 3 }, { 0x6, 4 }, + { 0x7, 4 }, { 0x1D, 5 }, { 0x17, 6 }, { 0xF, 7 }, + { 0x1C3, 9 }, { 0x1C1, 9 }, { 0x380, 10 }, { 0x381F, 14 }, + { 0x381E, 14 }, { 0x1C0D, 13 }, { 0x1C0C, 13 }, { 0x1, 3 }, + { 0x4, 4 }, { 0x18, 5 }, { 0x1, 5 }, { 0x0, 5 }, + { 0xD, 4 }, { 0x16, 6 }, { 0x19, 5 }, { 0x39, 6 } + }, + { /* AC bias group 2, table 7 */ + { 0x2, 3 }, { 0x1E, 5 }, { 0x3B, 6 }, { 0xD, 5 }, + { 0x61, 7 }, { 0x1FA, 9 }, { 0x1FB5, 13 }, { 0x31, 6 }, + { 0xFC, 8 }, { 0x4, 3 }, { 0x5, 3 }, { 0x1, 4 }, + { 0x7, 4 }, { 0x3A, 6 }, { 0x60, 7 }, { 0x3F7, 10 }, + { 0x7EC, 11 }, { 0x1FB7, 13 }, { 0x3F6C, 14 }, { 0x7EDB, 15 }, + { 0x7EDA, 15 }, { 0x3F69, 14 }, { 0x3F68, 14 }, { 0x1, 3 }, + { 0x0, 4 }, { 0x19, 5 }, { 0x3E, 6 }, { 0x39, 6 }, + { 0xD, 4 }, { 0x38, 6 }, { 0xC, 5 }, { 0x7F, 7 } + }, + { /* AC bias group 2, table 8 */ + { 0x1E, 5 }, { 0x70, 7 }, { 0x127, 9 }, { 0x126, 9 }, + { 0x492, 11 }, { 0x124D, 13 }, { 0x124C, 13 }, { 0x1, 5 }, + { 0x7F, 7 }, { 0x6, 3 }, { 0x5, 3 }, { 0x5, 4 }, + { 0x4, 4 }, { 0x1, 4 }, { 0x7, 5 }, { 0x25, 6 }, + { 0x71, 7 }, { 0x7E, 7 }, { 0x48, 7 }, { 0x125, 9 }, + { 0x248, 10 }, { 0x124F, 13 }, { 0x124E, 13 }, { 0x3, 3 }, + { 0x8, 4 }, { 0x1D, 5 }, { 0x6, 5 }, { 0x3E, 6 }, + { 0x2, 4 }, { 0x0, 5 }, { 0x13, 5 }, { 0x39, 6 } + }, + { /* AC bias group 2, table 9 */ + { 0x1, 4 }, { 0x1, 6 }, { 0xE7, 8 }, { 0x91, 8 }, + { 0x240, 10 }, { 0x120D, 13 }, { 0x120C, 13 }, { 0x3C, 6 }, + { 0x0, 6 }, { 0x6, 3 }, { 0x5, 3 }, { 0x5, 4 }, + { 0x4, 4 }, { 0x1F, 5 }, { 0x4, 5 }, { 0x25, 6 }, + { 0x72, 7 }, { 0x49, 7 }, { 0xE6, 8 }, { 0x121, 9 }, + { 0x482, 11 }, { 0x120F, 13 }, { 0x120E, 13 }, { 0x3, 3 }, + { 0x8, 4 }, { 0x1D, 5 }, { 0x5, 5 }, { 0x3D, 6 }, + { 0x3, 4 }, { 0x1, 5 }, { 0x13, 5 }, { 0x38, 6 } + }, + { /* AC bias group 2, table 10 */ + { 0x4, 4 }, { 0xF, 6 }, { 0xF4, 8 }, { 0x5B, 8 }, + { 0x2D3, 11 }, { 0xB4A, 13 }, { 0x1697, 14 }, { 0x3C, 6 }, + { 0xE, 6 }, { 0x6, 3 }, { 0x5, 3 }, { 0x2, 4 }, + { 0x1, 4 }, { 0x1D, 5 }, { 0x0, 5 }, { 0x7B, 7 }, + { 0x2C, 7 }, { 0xF5, 8 }, { 0xB5, 9 }, { 0x168, 10 }, + { 0x1696, 14 }, { 0xB49, 13 }, { 0xB48, 13 }, { 0x3, 3 }, + { 0x9, 4 }, { 0x1F, 5 }, { 0xA, 5 }, { 0x1, 5 }, + { 0x8, 4 }, { 0x6, 5 }, { 0x1C, 5 }, { 0x17, 6 } + }, + { /* AC bias group 2, table 11 */ + { 0x8, 4 }, { 0x39, 6 }, { 0x1A, 7 }, { 0x3, 7 }, + { 0xDB, 10 }, { 0x6D6, 13 }, { 0xDAF, 14 }, { 0x3C, 6 }, + { 0xC, 6 }, { 0x6, 3 }, { 0x5, 3 }, { 0x2, 4 }, + { 0x1, 4 }, { 0x1D, 5 }, { 0x3D, 6 }, { 0x0, 6 }, + { 0x2, 7 }, { 0x37, 8 }, { 0x6C, 9 }, { 0x1B4, 11 }, + { 0xDAE, 14 }, { 0x6D5, 13 }, { 0x6D4, 13 }, { 0x2, 3 }, + { 0x7, 4 }, { 0x1F, 5 }, { 0x7, 5 }, { 0x1, 5 }, + { 0x9, 4 }, { 0xD, 5 }, { 0xC, 5 }, { 0x38, 6 } + }, + { /* AC bias group 2, table 12 */ + { 0xF, 4 }, { 0x4, 5 }, { 0x2F, 7 }, { 0x2E, 7 }, + { 0x54, 9 }, { 0x555, 13 }, { 0x554, 13 }, { 0x16, 6 }, + { 0xE, 6 }, { 0x6, 3 }, { 0x5, 3 }, { 0x1, 4 }, + { 0x0, 4 }, { 0x9, 5 }, { 0xB, 6 }, { 0x14, 7 }, + { 0x57, 9 }, { 0x56, 9 }, { 0xAB, 10 }, { 0x557, 13 }, + { 0x556, 13 }, { 0x2A9, 12 }, { 0x2A8, 12 }, { 0x3, 3 }, + { 0x8, 4 }, { 0x13, 5 }, { 0xA, 5 }, { 0x8, 5 }, + { 0xE, 4 }, { 0x12, 5 }, { 0x6, 5 }, { 0xF, 6 } + }, + { /* AC bias group 2, table 13 */ + { 0x1, 3 }, { 0xE, 5 }, { 0x6, 6 }, { 0x4, 6 }, + { 0xDA, 9 }, { 0xDBE, 13 }, { 0x1B7E, 14 }, { 0x7, 6 }, + { 0x1A, 6 }, { 0x5, 3 }, { 0x4, 3 }, { 0x1C, 5 }, + { 0x1B, 5 }, { 0x3A, 6 }, { 0x37, 7 }, { 0x6C, 8 }, + { 0x1B6, 10 }, { 0x36E, 11 }, { 0xDBD, 13 }, { 0x36FF, 15 }, + { 0x36FE, 15 }, { 0x1B79, 14 }, { 0x1B78, 14 }, { 0x2, 3 }, + { 0xC, 4 }, { 0x0, 4 }, { 0xF, 5 }, { 0xC, 5 }, + { 0xF, 4 }, { 0x1A, 5 }, { 0x3B, 6 }, { 0x5, 6 } + }, + { /* AC bias group 2, table 14 */ + { 0x5, 3 }, { 0x1E, 5 }, { 0x3A, 6 }, { 0x3E, 6 }, + { 0xFC, 8 }, { 0xFD7, 12 }, { 0x3F55, 14 }, { 0x77, 7 }, + { 0x30, 6 }, { 0x3, 3 }, { 0x4, 3 }, { 0x1A, 5 }, + { 0x19, 5 }, { 0x7F, 7 }, { 0x1FB, 9 }, { 0x3F4, 10 }, + { 0xFD6, 12 }, { 0x1FA9, 13 }, { 0x3F54, 14 }, { 0x3F57, 14 }, + { 0x3F56, 14 }, { 0x3F51, 14 }, { 0x3F50, 14 }, { 0x1, 3 }, + { 0x4, 4 }, { 0x1C, 5 }, { 0xB, 5 }, { 0xA, 5 }, + { 0x0, 3 }, { 0x1B, 5 }, { 0x31, 6 }, { 0x76, 7 } + }, + { /* AC bias group 2, table 15 */ + { 0x5, 3 }, { 0xC, 4 }, { 0x1B, 5 }, { 0x8, 4 }, + { 0x38, 6 }, { 0x15, 8 }, { 0xA3, 11 }, { 0xE6, 8 }, + { 0x4, 6 }, { 0x1, 3 }, { 0x2, 3 }, { 0x12, 5 }, + { 0x3, 5 }, { 0xB, 7 }, { 0x29, 9 }, { 0xA0, 11 }, + { 0x142, 12 }, { 0x287, 13 }, { 0x286, 13 }, { 0x289, 13 }, + { 0x288, 13 }, { 0x28B, 13 }, { 0x28A, 13 }, { 0xF, 4 }, + { 0x1D, 5 }, { 0x13, 5 }, { 0x1, 5 }, { 0x0, 5 }, + { 0x3, 3 }, { 0x1A, 5 }, { 0x72, 7 }, { 0xE7, 8 } + } +}; + +static const uint16_t vp4_ac_bias_2[16][32][2] = { + { /* AC bias group 3, table 0 */ + { 0x9, 5 }, { 0x15, 7 }, { 0x28, 8 }, { 0x52, 9 }, + { 0x29A, 12 }, { 0x537, 13 }, { 0x536, 13 }, { 0xA, 5 }, + { 0x54, 7 }, { 0x4, 3 }, { 0x3, 3 }, { 0xC, 4 }, + { 0xB, 4 }, { 0xD, 4 }, { 0x3, 4 }, { 0x14, 5 }, + { 0x3A, 6 }, { 0x4, 5 }, { 0x38, 6 }, { 0x55, 7 }, + { 0xA7, 10 }, { 0x299, 12 }, { 0x298, 12 }, { 0x0, 3 }, + { 0x1E, 5 }, { 0x8, 5 }, { 0x2B, 6 }, { 0xB, 6 }, + { 0xB, 5 }, { 0x3B, 6 }, { 0x1F, 5 }, { 0x39, 6 } + }, + { /* AC bias group 3, table 1 */ + { 0x1D, 5 }, { 0x2F, 7 }, { 0x2, 8 }, { 0x7, 9 }, + { 0x19, 11 }, { 0x35, 12 }, { 0x34, 12 }, { 0x9, 5 }, + { 0x2E, 7 }, { 0x6, 3 }, { 0x5, 3 }, { 0x9, 4 }, + { 0x8, 4 }, { 0x7, 4 }, { 0x1F, 5 }, { 0x8, 5 }, + { 0x18, 6 }, { 0x19, 6 }, { 0x1, 6 }, { 0x0, 7 }, + { 0x18, 11 }, { 0x37, 12 }, { 0x36, 12 }, { 0x1, 3 }, + { 0x1, 4 }, { 0xA, 5 }, { 0x39, 6 }, { 0x16, 6 }, + { 0xD, 5 }, { 0x1, 5 }, { 0x1E, 5 }, { 0x38, 6 } + }, + { /* AC bias group 3, table 2 */ + { 0x1, 4 }, { 0x71, 7 }, { 0xE0, 8 }, { 0x1C3, 9 }, + { 0x708, 11 }, { 0x1C26, 13 }, { 0x384F, 14 }, { 0x1, 5 }, + { 0x31, 7 }, { 0x6, 3 }, { 0x5, 3 }, { 0x9, 4 }, + { 0x8, 4 }, { 0x5, 4 }, { 0xF, 5 }, { 0x39, 6 }, + { 0x77, 7 }, { 0x76, 7 }, { 0x30, 7 }, { 0x385, 10 }, + { 0x384E, 14 }, { 0x1C25, 13 }, { 0x1C24, 13 }, { 0x1, 3 }, + { 0x4, 4 }, { 0xD, 5 }, { 0x0, 5 }, { 0x19, 6 }, + { 0x1F, 5 }, { 0xE, 5 }, { 0x1E, 5 }, { 0x3A, 6 } + }, + { /* AC bias group 3, table 3 */ + { 0x6, 4 }, { 0xC, 6 }, { 0xD6, 8 }, { 0x7B, 8 }, + { 0x1E8, 10 }, { 0x7A4, 12 }, { 0xF4B, 13 }, { 0x36, 6 }, + { 0x6A, 7 }, { 0x7, 3 }, { 0x5, 3 }, { 0x8, 4 }, + { 0x9, 4 }, { 0x1, 4 }, { 0x7, 5 }, { 0xD, 6 }, + { 0x3C, 7 }, { 0xD7, 8 }, { 0xF5, 9 }, { 0x7A7, 12 }, + { 0xF4A, 13 }, { 0xF4D, 13 }, { 0xF4C, 13 }, { 0x2, 3 }, + { 0x2, 4 }, { 0xE, 5 }, { 0x37, 6 }, { 0x34, 6 }, + { 0x0, 4 }, { 0x19, 5 }, { 0x18, 5 }, { 0x1F, 6 } + }, + { /* AC bias group 3, table 4 */ + { 0xA, 4 }, { 0x27, 6 }, { 0xBF, 8 }, { 0xBE, 8 }, + { 0x224, 10 }, { 0x225D, 14 }, { 0x225C, 14 }, { 0x26, 6 }, + { 0x5E, 7 }, { 0x7, 3 }, { 0x6, 3 }, { 0x6, 4 }, + { 0x7, 4 }, { 0x16, 5 }, { 0x2E, 6 }, { 0x45, 7 }, + { 0x88, 8 }, { 0x113, 9 }, { 0x44A, 11 }, { 0x225F, 14 }, + { 0x225E, 14 }, { 0x112D, 13 }, { 0x112C, 13 }, { 0x2, 3 }, + { 0x2, 4 }, { 0x12, 5 }, { 0x3, 5 }, { 0x2, 5 }, + { 0x3, 4 }, { 0x0, 4 }, { 0x10, 5 }, { 0x23, 6 } + }, + { /* AC bias group 3, table 5 */ + { 0xF, 4 }, { 0x6, 5 }, { 0x75, 7 }, { 0x74, 7 }, + { 0xA, 9 }, { 0xBF, 13 }, { 0xB9, 13 }, { 0x22, 6 }, + { 0x3, 7 }, { 0x5, 3 }, { 0x6, 3 }, { 0x1, 4 }, + { 0x2, 4 }, { 0x7, 5 }, { 0x0, 6 }, { 0x4, 8 }, + { 0x16, 10 }, { 0x5E, 12 }, { 0xB8, 13 }, { 0xBB, 13 }, + { 0xBA, 13 }, { 0x17D, 14 }, { 0x17C, 14 }, { 0x2, 3 }, + { 0x6, 4 }, { 0x1C, 5 }, { 0x10, 5 }, { 0x3B, 6 }, + { 0x9, 4 }, { 0x7, 4 }, { 0x1, 5 }, { 0x23, 6 } + }, + { /* AC bias group 3, table 6 */ + { 0x1, 3 }, { 0x1C, 5 }, { 0x36, 6 }, { 0x3B, 6 }, + { 0xEA, 8 }, { 0x75B, 11 }, { 0x1D65, 13 }, { 0x19, 6 }, + { 0x74, 7 }, { 0x4, 3 }, { 0x5, 3 }, { 0x0, 4 }, + { 0x1, 4 }, { 0x37, 6 }, { 0x1D7, 9 }, { 0x75A, 11 }, + { 0x1D64, 13 }, { 0x1D67, 13 }, { 0x1D66, 13 }, { 0x1D61, 13 }, + { 0x1D60, 13 }, { 0x1D63, 13 }, { 0x1D62, 13 }, { 0x2, 3 }, + { 0x1F, 5 }, { 0x1A, 5 }, { 0xD, 5 }, { 0x3D, 6 }, + { 0xC, 4 }, { 0x7, 4 }, { 0x3C, 6 }, { 0x18, 6 } + }, + { /* AC bias group 3, table 7 */ + { 0x2, 3 }, { 0x1, 4 }, { 0x14, 5 }, { 0x0, 4 }, + { 0x2F, 6 }, { 0xBB, 8 }, { 0x2E4, 10 }, { 0x7D, 7 }, + { 0xBA, 8 }, { 0x3, 3 }, { 0x4, 3 }, { 0x16, 5 }, + { 0x1A, 5 }, { 0xB8, 8 }, { 0x172E, 13 }, { 0x2E5F, 14 }, + { 0x2E5E, 14 }, { 0x1729, 13 }, { 0x1728, 13 }, { 0x172B, 13 }, + { 0x172A, 13 }, { 0x172D, 13 }, { 0x172C, 13 }, { 0x1, 3 }, + { 0x1E, 5 }, { 0x15, 5 }, { 0x1B, 5 }, { 0x3F, 6 }, + { 0xC, 4 }, { 0xE, 4 }, { 0x7C, 7 }, { 0x173, 9 } + }, + { /* AC bias group 3, table 8 */ + { 0x3, 4 }, { 0x7B, 7 }, { 0x58, 8 }, { 0x1EA, 9 }, + { 0x1EB1, 13 }, { 0x1EB0, 13 }, { 0x1EB3, 13 }, { 0x13, 6 }, + { 0x12, 6 }, { 0x5, 3 }, { 0x6, 3 }, { 0x2, 4 }, + { 0x1, 4 }, { 0x13, 5 }, { 0x3C, 6 }, { 0x2D, 7 }, + { 0xF4, 8 }, { 0x59, 8 }, { 0x3D7, 10 }, { 0xF5B, 12 }, + { 0x1EB2, 13 }, { 0x1EB5, 13 }, { 0x1EB4, 13 }, { 0x3, 3 }, + { 0xE, 4 }, { 0x1F, 5 }, { 0x12, 5 }, { 0x8, 5 }, + { 0x8, 4 }, { 0x0, 4 }, { 0xA, 5 }, { 0x17, 6 } + }, + { /* AC bias group 3, table 9 */ + { 0x8, 4 }, { 0x3C, 6 }, { 0xF5, 8 }, { 0xF4, 8 }, + { 0x1EF7, 13 }, { 0x3DE9, 14 }, { 0x3DE8, 14 }, { 0x1C, 6 }, + { 0xD, 6 }, { 0x5, 3 }, { 0x6, 3 }, { 0x1, 4 }, + { 0x0, 4 }, { 0x7, 5 }, { 0xC, 6 }, { 0xF6, 8 }, + { 0x1EE, 9 }, { 0x3DF, 10 }, { 0x7BC, 11 }, { 0x3DEB, 14 }, + { 0x3DEA, 14 }, { 0x3DED, 14 }, { 0x3DEC, 14 }, { 0x2, 3 }, + { 0x9, 4 }, { 0x1F, 5 }, { 0xF, 5 }, { 0x5, 5 }, + { 0xE, 4 }, { 0x6, 4 }, { 0x4, 5 }, { 0x1D, 6 } + }, + { /* AC bias group 3, table 10 */ + { 0x9, 4 }, { 0x39, 6 }, { 0x19, 7 }, { 0x18, 7 }, + { 0x706, 11 }, { 0x383D, 14 }, { 0x383C, 14 }, { 0xD, 6 }, + { 0xF, 6 }, { 0x5, 3 }, { 0x6, 3 }, { 0x0, 4 }, + { 0x1D, 5 }, { 0x3, 5 }, { 0x71, 7 }, { 0xE1, 8 }, + { 0x1C0, 9 }, { 0x382, 10 }, { 0x1C1D, 13 }, { 0x383F, 14 }, + { 0x383E, 14 }, { 0x3839, 14 }, { 0x3838, 14 }, { 0x2, 3 }, + { 0x8, 4 }, { 0x2, 4 }, { 0xD, 5 }, { 0xC, 5 }, + { 0xF, 4 }, { 0x7, 4 }, { 0x2, 5 }, { 0xE, 6 } + }, + { /* AC bias group 3, table 11 */ + { 0x0, 3 }, { 0x6, 5 }, { 0x35, 7 }, { 0x34, 7 }, + { 0x777, 11 }, { 0x1DD4, 13 }, { 0x3BAB, 14 }, { 0xE, 6 }, + { 0xF, 6 }, { 0x5, 3 }, { 0x4, 3 }, { 0x1C, 5 }, + { 0x19, 5 }, { 0x3A, 6 }, { 0xEF, 8 }, { 0x1DC, 9 }, + { 0x776, 11 }, { 0x774, 11 }, { 0x3BAA, 14 }, { 0x3BAD, 14 }, + { 0x3BAC, 14 }, { 0x3BAF, 14 }, { 0x3BAE, 14 }, { 0x2, 3 }, + { 0x7, 4 }, { 0x2, 4 }, { 0x18, 5 }, { 0xC, 5 }, + { 0xF, 4 }, { 0xD, 4 }, { 0x1B, 6 }, { 0x76, 7 } + }, + { /* AC bias group 3, table 12 */ + { 0x2, 3 }, { 0x11, 5 }, { 0x6, 6 }, { 0x4F, 7 }, + { 0x130, 9 }, { 0x1319, 13 }, { 0x1318, 13 }, { 0x4E, 7 }, + { 0x7, 6 }, { 0x6, 3 }, { 0x5, 3 }, { 0x10, 5 }, + { 0xD, 5 }, { 0x5, 6 }, { 0x99, 8 }, { 0x262, 10 }, + { 0x98E, 12 }, { 0x131B, 13 }, { 0x131A, 13 }, { 0x263D, 14 }, + { 0x263C, 14 }, { 0x263F, 14 }, { 0x263E, 14 }, { 0x1, 3 }, + { 0x7, 4 }, { 0x0, 4 }, { 0x12, 5 }, { 0xC, 5 }, + { 0xE, 4 }, { 0xF, 4 }, { 0x4, 6 }, { 0x4D, 7 } + }, + { /* AC bias group 3, table 13 */ + { 0x3, 3 }, { 0x0, 4 }, { 0x2, 5 }, { 0x37, 6 }, + { 0x1B7, 9 }, { 0xDB5, 12 }, { 0x36DD, 14 }, { 0x6C, 7 }, + { 0x16, 6 }, { 0x5, 3 }, { 0x4, 3 }, { 0x3, 5 }, + { 0xA, 5 }, { 0x2E, 7 }, { 0x36C, 10 }, { 0xDB4, 12 }, + { 0x36DC, 14 }, { 0x36DF, 14 }, { 0x36DE, 14 }, { 0x36D9, 14 }, + { 0x36D8, 14 }, { 0x36DB, 14 }, { 0x36DA, 14 }, { 0xE, 4 }, + { 0x4, 4 }, { 0x1A, 5 }, { 0x19, 5 }, { 0x18, 5 }, + { 0xF, 4 }, { 0x1, 3 }, { 0x2F, 7 }, { 0xDA, 8 } + }, + { /* AC bias group 3, table 14 */ + { 0x6, 3 }, { 0x6, 4 }, { 0xF, 5 }, { 0x0, 4 }, + { 0x75, 7 }, { 0x3B8, 10 }, { 0x1DCA, 13 }, { 0x74, 7 }, + { 0x76, 7 }, { 0x4, 3 }, { 0x5, 3 }, { 0x3, 5 }, + { 0x2, 5 }, { 0x1DE, 9 }, { 0xEE6, 12 }, { 0x3B97, 14 }, + { 0x3B96, 14 }, { 0x3B9D, 14 }, { 0x3B9C, 14 }, { 0x3B9F, 14 }, + { 0x3B9E, 14 }, { 0x1DC9, 13 }, { 0x1DC8, 13 }, { 0x5, 4 }, + { 0x1C, 5 }, { 0x9, 5 }, { 0xE, 5 }, { 0x8, 5 }, + { 0xF, 4 }, { 0x1, 3 }, { 0x1DF, 9 }, { 0x1DD, 9 } + }, + { /* AC bias group 3, table 15 */ + { 0x4, 3 }, { 0xB, 4 }, { 0x1D, 5 }, { 0xC, 4 }, + { 0x14, 5 }, { 0xE0, 8 }, { 0x3875, 14 }, { 0x386, 10 }, + { 0x1C2, 9 }, { 0x0, 2 }, { 0x1, 2 }, { 0x71, 7 }, + { 0x72, 7 }, { 0x1C3F, 13 }, { 0x3874, 14 }, { 0x3877, 14 }, + { 0x3876, 14 }, { 0x3871, 14 }, { 0x3870, 14 }, { 0x3873, 14 }, + { 0x3872, 14 }, { 0x3879, 14 }, { 0x3878, 14 }, { 0x3C, 6 }, + { 0x73, 7 }, { 0x2A, 6 }, { 0x3D, 6 }, { 0x2B, 6 }, + { 0x1F, 5 }, { 0xD, 4 }, { 0x1C3E, 13 }, { 0x1C3D, 13 } + } +}; + +static const uint16_t vp4_ac_bias_3[16][32][2] = { + { /* AC bias group 4, table 0 */ + { 0x7, 4 }, { 0xF, 6 }, { 0xBB, 8 }, { 0xBA, 8 }, + { 0x5CF, 11 }, { 0x173A, 13 }, { 0x2E77, 14 }, { 0x29, 6 }, + { 0x172, 9 }, { 0x7, 3 }, { 0x6, 3 }, { 0x9, 4 }, + { 0x8, 4 }, { 0x1, 4 }, { 0x5, 5 }, { 0xD, 6 }, + { 0x1D, 7 }, { 0x1C, 7 }, { 0xB8, 8 }, { 0x2E6, 10 }, + { 0x2E76, 14 }, { 0x1739, 13 }, { 0x1738, 13 }, { 0x2, 3 }, + { 0x6, 4 }, { 0x16, 5 }, { 0x4, 5 }, { 0x28, 6 }, + { 0x15, 5 }, { 0xC, 6 }, { 0x0, 4 }, { 0x2F, 6 } + }, + { /* AC bias group 4, table 1 */ + { 0xB, 4 }, { 0x2, 5 }, { 0x54, 7 }, { 0x2F, 7 }, + { 0x2AC, 10 }, { 0x156B, 13 }, { 0x1568, 13 }, { 0x16, 6 }, + { 0x154, 9 }, { 0x7, 3 }, { 0x6, 3 }, { 0x4, 4 }, + { 0x3, 4 }, { 0x13, 5 }, { 0x28, 6 }, { 0x2E, 7 }, + { 0x157, 9 }, { 0x155, 9 }, { 0x55B, 11 }, { 0x2AD3, 14 }, + { 0x2AD2, 14 }, { 0x2AD5, 14 }, { 0x2AD4, 14 }, { 0x3, 3 }, + { 0x8, 4 }, { 0x0, 4 }, { 0xA, 5 }, { 0x3, 5 }, + { 0x2, 4 }, { 0x2B, 6 }, { 0x12, 5 }, { 0x29, 6 } + }, + { /* AC bias group 4, table 2 */ + { 0xF, 4 }, { 0x7, 5 }, { 0x1, 6 }, { 0x0, 6 }, + { 0x1C4, 9 }, { 0x703, 11 }, { 0xE02, 12 }, { 0x11, 6 }, + { 0xE1, 8 }, { 0x5, 3 }, { 0x6, 3 }, { 0x2, 4 }, + { 0x1, 4 }, { 0x9, 5 }, { 0x10, 6 }, { 0xE3, 8 }, + { 0x1C5, 9 }, { 0x1C1, 9 }, { 0x702, 11 }, { 0x1C07, 13 }, + { 0x1C06, 13 }, { 0xE01, 12 }, { 0xE00, 12 }, { 0x4, 3 }, + { 0x7, 4 }, { 0x1D, 5 }, { 0xD, 5 }, { 0x1, 5 }, + { 0x5, 4 }, { 0x6, 5 }, { 0xC, 5 }, { 0x39, 6 } + }, + { /* AC bias group 4, table 3 */ + { 0x1, 3 }, { 0x1C, 5 }, { 0x11, 6 }, { 0x13, 6 }, + { 0x42, 8 }, { 0x207, 11 }, { 0x815, 13 }, { 0x75, 7 }, + { 0x41, 8 }, { 0x5, 3 }, { 0x6, 3 }, { 0x0, 4 }, + { 0x1F, 5 }, { 0x3B, 6 }, { 0x74, 7 }, { 0x43, 8 }, + { 0x80, 9 }, { 0x206, 11 }, { 0x814, 13 }, { 0x817, 13 }, + { 0x816, 13 }, { 0x409, 12 }, { 0x408, 12 }, { 0x3, 3 }, + { 0x9, 4 }, { 0x1E, 5 }, { 0x11, 5 }, { 0x3, 5 }, + { 0x5, 4 }, { 0x10, 5 }, { 0x2, 5 }, { 0x12, 6 } + }, + { /* AC bias group 4, table 4 */ + { 0x1, 3 }, { 0x1F, 5 }, { 0x27, 6 }, { 0x1, 5 }, + { 0x4B, 8 }, { 0x123, 10 }, { 0x915, 13 }, { 0x0, 6 }, + { 0x49, 8 }, { 0x5, 3 }, { 0x6, 3 }, { 0x1D, 5 }, + { 0x1C, 5 }, { 0x13, 6 }, { 0x4A, 8 }, { 0x90, 9 }, + { 0x914, 13 }, { 0x917, 13 }, { 0x916, 13 }, { 0x911, 13 }, + { 0x910, 13 }, { 0x913, 13 }, { 0x912, 13 }, { 0x3, 3 }, + { 0x5, 4 }, { 0x1, 4 }, { 0x12, 5 }, { 0x8, 5 }, + { 0x8, 4 }, { 0x1E, 5 }, { 0x26, 6 }, { 0x1, 6 } + }, + { /* AC bias group 4, table 5 */ + { 0x3, 3 }, { 0x1, 4 }, { 0x3F, 6 }, { 0xB, 5 }, + { 0x4E, 7 }, { 0x132, 9 }, { 0x99A, 12 }, { 0x4F, 7 }, + { 0x98, 8 }, { 0x6, 3 }, { 0x5, 3 }, { 0x1D, 5 }, + { 0x1C, 5 }, { 0x7C, 7 }, { 0x267, 10 }, { 0x1331, 13 }, + { 0x1330, 13 }, { 0x1333, 13 }, { 0x1332, 13 }, { 0x266D, 14 }, + { 0x266C, 14 }, { 0x266F, 14 }, { 0x266E, 14 }, { 0x1, 3 }, + { 0x4, 4 }, { 0x1E, 5 }, { 0x12, 5 }, { 0xA, 5 }, + { 0x8, 4 }, { 0x0, 4 }, { 0x7D, 7 }, { 0x4D, 7 } + }, + { /* AC bias group 4, table 6 */ + { 0x2, 3 }, { 0x7, 4 }, { 0x15, 5 }, { 0x3, 4 }, + { 0x4, 5 }, { 0xA7, 8 }, { 0x536, 11 }, { 0x28, 6 }, + { 0x29A, 10 }, { 0x6, 3 }, { 0x4, 3 }, { 0x1C, 5 }, + { 0x17, 5 }, { 0xA4, 8 }, { 0x29BE, 14 }, { 0x537F, 15 }, + { 0x537E, 15 }, { 0x29B9, 14 }, { 0x29B8, 14 }, { 0x29BB, 14 }, + { 0x29BA, 14 }, { 0x29BD, 14 }, { 0x29BC, 14 }, { 0xF, 4 }, + { 0x0, 4 }, { 0x5, 5 }, { 0x16, 5 }, { 0x1D, 5 }, + { 0x6, 4 }, { 0x1, 4 }, { 0xA5, 8 }, { 0x14C, 9 } + }, + { /* AC bias group 4, table 7 */ + { 0x4, 3 }, { 0x7, 4 }, { 0x1A, 5 }, { 0xC, 4 }, + { 0x6, 4 }, { 0x29, 6 }, { 0x1BD, 9 }, { 0x1BE3, 13 }, + { 0x1BE0, 13 }, { 0x0, 2 }, { 0x7, 3 }, { 0x6E, 7 }, + { 0x1BC, 9 }, { 0x37C3, 14 }, { 0x37C2, 14 }, { 0x37CD, 14 }, + { 0x37CC, 14 }, { 0x37CF, 14 }, { 0x37CE, 14 }, { 0x37C9, 14 }, + { 0x37C8, 14 }, { 0x37CB, 14 }, { 0x37CA, 14 }, { 0x15, 5 }, + { 0x1BF, 9 }, { 0x37D, 10 }, { 0x36, 6 }, { 0x2, 3 }, + { 0xB, 4 }, { 0x28, 6 }, { 0x37C5, 14 }, { 0x37C4, 14 } + }, + { /* AC bias group 4, table 8 */ + { 0x1, 3 }, { 0x9, 5 }, { 0x3, 6 }, { 0x2, 6 }, + { 0x11F, 10 }, { 0x8E9, 13 }, { 0x8E8, 13 }, { 0x2D, 7 }, + { 0x22, 7 }, { 0x6, 3 }, { 0x7, 3 }, { 0x10, 5 }, + { 0x11, 5 }, { 0x17, 6 }, { 0x2C, 7 }, { 0x46, 8 }, + { 0x11E, 10 }, { 0x11C, 10 }, { 0x477, 12 }, { 0x8EB, 13 }, + { 0x8EA, 13 }, { 0x8ED, 13 }, { 0x8EC, 13 }, { 0x3, 3 }, + { 0xB, 4 }, { 0x1, 4 }, { 0x14, 5 }, { 0xA, 5 }, + { 0x9, 4 }, { 0x15, 5 }, { 0x0, 5 }, { 0x10, 6 } + }, + { /* AC bias group 4, table 9 */ + { 0x1, 3 }, { 0x1D, 5 }, { 0x22, 6 }, { 0x13, 6 }, + { 0x11E, 9 }, { 0x8FC, 12 }, { 0x23F5, 14 }, { 0x23, 7 }, + { 0x22, 7 }, { 0x5, 3 }, { 0x6, 3 }, { 0x10, 5 }, + { 0xB, 5 }, { 0x10, 6 }, { 0x8E, 8 }, { 0x23E, 10 }, + { 0x8FF, 12 }, { 0x11FD, 13 }, { 0x23F4, 14 }, { 0x23F7, 14 }, + { 0x23F6, 14 }, { 0x23F9, 14 }, { 0x23F8, 14 }, { 0x3, 3 }, + { 0x9, 4 }, { 0x0, 4 }, { 0x1C, 5 }, { 0xA, 5 }, + { 0xF, 4 }, { 0x1, 4 }, { 0x12, 6 }, { 0x46, 7 } + }, + { /* AC bias group 4, table 10 */ + { 0x3, 3 }, { 0x1F, 5 }, { 0x3C, 6 }, { 0x3D, 6 }, + { 0x86, 8 }, { 0x877, 12 }, { 0x10E8, 13 }, { 0x41, 7 }, + { 0x40, 7 }, { 0x5, 3 }, { 0x6, 3 }, { 0x7, 5 }, + { 0x6, 5 }, { 0x4, 6 }, { 0x10F, 9 }, { 0x21C, 10 }, + { 0x875, 12 }, { 0x21D3, 14 }, { 0x21D2, 14 }, { 0x21D9, 14 }, + { 0x21D8, 14 }, { 0x21DB, 14 }, { 0x21DA, 14 }, { 0x2, 3 }, + { 0x9, 4 }, { 0x0, 4 }, { 0x11, 5 }, { 0x3, 5 }, + { 0xE, 4 }, { 0x2, 4 }, { 0x5, 6 }, { 0x42, 7 } + }, + { /* AC bias group 4, table 11 */ + { 0x4, 3 }, { 0x1, 4 }, { 0x3D, 6 }, { 0x9, 5 }, + { 0xF3, 8 }, { 0x793, 11 }, { 0x1E45, 13 }, { 0x0, 7 }, + { 0x2, 7 }, { 0x5, 3 }, { 0x6, 3 }, { 0x8, 5 }, + { 0x1, 5 }, { 0x3, 7 }, { 0x1E5, 9 }, { 0x792, 11 }, + { 0x1E44, 13 }, { 0x1E47, 13 }, { 0x1E46, 13 }, { 0x1E41, 13 }, + { 0x1E40, 13 }, { 0x1E43, 13 }, { 0x1E42, 13 }, { 0x1, 3 }, + { 0x6, 4 }, { 0x1F, 5 }, { 0xF, 5 }, { 0xE, 5 }, + { 0xE, 4 }, { 0x5, 4 }, { 0x78, 7 }, { 0x1, 7 } + }, + { /* AC bias group 4, table 12 */ + { 0x4, 3 }, { 0x5, 4 }, { 0xE, 5 }, { 0x17, 5 }, + { 0x3E, 7 }, { 0xF0, 9 }, { 0xF1E, 13 }, { 0x7A, 8 }, + { 0x7F, 8 }, { 0x6, 3 }, { 0x7, 3 }, { 0x5, 5 }, + { 0x4, 5 }, { 0x7B, 8 }, { 0x1E2, 10 }, { 0x1E3F, 14 }, + { 0x1E3E, 14 }, { 0xF19, 13 }, { 0xF18, 13 }, { 0xF1B, 13 }, + { 0xF1A, 13 }, { 0xF1D, 13 }, { 0xF1C, 13 }, { 0x0, 3 }, + { 0x3, 4 }, { 0x16, 5 }, { 0x9, 5 }, { 0x8, 5 }, + { 0xA, 4 }, { 0x6, 4 }, { 0x7E, 8 }, { 0x79, 8 } + }, + { /* AC bias group 4, table 13 */ + { 0x5, 3 }, { 0xC, 4 }, { 0x1A, 5 }, { 0x4, 4 }, + { 0x1A, 6 }, { 0xDE, 9 }, { 0xDF4, 13 }, { 0xDD, 9 }, + { 0x6D, 8 }, { 0x0, 2 }, { 0x7, 3 }, { 0x25, 6 }, + { 0x24, 6 }, { 0xDC, 9 }, { 0xDF7, 13 }, { 0x1BEB, 14 }, + { 0x1BEA, 14 }, { 0xDF1, 13 }, { 0xDF0, 13 }, { 0xDF3, 13 }, + { 0xDF2, 13 }, { 0x1BED, 14 }, { 0x1BEC, 14 }, { 0x8, 4 }, + { 0x13, 5 }, { 0xC, 5 }, { 0x37, 6 }, { 0x36, 6 }, + { 0x5, 4 }, { 0x7, 4 }, { 0x6C, 8 }, { 0x1BF, 10 } + }, + { /* AC bias group 4, table 14 */ + { 0x5, 3 }, { 0xD, 4 }, { 0x1F, 5 }, { 0xC, 4 }, + { 0x3B, 6 }, { 0x40, 7 }, { 0x41A, 11 }, { 0x104, 9 }, + { 0x107, 9 }, { 0x1, 2 }, { 0x0, 2 }, { 0x24, 6 }, + { 0x21, 6 }, { 0x20B, 10 }, { 0x106E, 13 }, { 0x20DF, 14 }, + { 0x20DE, 14 }, { 0x1055, 13 }, { 0x1054, 13 }, { 0x1057, 13 }, + { 0x1056, 13 }, { 0x106D, 13 }, { 0x106C, 13 }, { 0x11, 5 }, + { 0x3A, 6 }, { 0x25, 6 }, { 0x38, 6 }, { 0x39, 6 }, + { 0x13, 5 }, { 0x1E, 5 }, { 0x20C, 10 }, { 0x414, 11 } + }, + { /* AC bias group 4, table 15 */ + { 0x0, 2 }, { 0x7, 4 }, { 0xD, 5 }, { 0x5, 4 }, + { 0x9, 5 }, { 0x22, 7 }, { 0xCD1, 13 }, { 0xCD0, 13 }, + { 0xCD3, 13 }, { 0x3, 2 }, { 0x2, 2 }, { 0x8D, 9 }, + { 0xCC, 9 }, { 0x66B, 12 }, { 0xCD2, 13 }, { 0x19B5, 14 }, + { 0x19B4, 14 }, { 0x19B7, 14 }, { 0x19B6, 14 }, { 0x19B1, 14 }, + { 0x19B0, 14 }, { 0x19B3, 14 }, { 0x19B2, 14 }, { 0x47, 8 }, + { 0x8C, 9 }, { 0x337, 11 }, { 0x67, 8 }, { 0x18, 6 }, + { 0x10, 6 }, { 0x32, 7 }, { 0xCD5, 13 }, { 0xCD4, 13 } + } +}; + +#endif /* AVCODEC_VP4DATA_H */ diff --git a/libavcodec/vp5.c b/libavcodec/vp5.c index cb08cec33..0fca28291 100644 --- a/libavcodec/vp5.c +++ b/libavcodec/vp5.c @@ -183,7 +183,7 @@ static int vp5_parse_coeff(VP56Context *s) int b, i, cg, idx, ctx, ctx_last; int pt = 0; /* plane type (0 for Y, 1 for U or V) */ - if (c->end <= c->buffer && c->bits >= 0) { + if (vpX_rac_is_end(c)) { av_log(s->avctx, AV_LOG_ERROR, "End of AC stream reached in vp5_parse_coeff\n"); return AVERROR_INVALIDDATA; } @@ -252,6 +252,7 @@ static int vp5_parse_coeff(VP56Context *s) for (i=coeff_idx; i<=ctx_last; i++) s->coeff_ctx[ff_vp56_b6to4[b]][i] = 5; s->above_blocks[s->above_block_idx[b]].not_null_dc = s->coeff_ctx[ff_vp56_b6to4[b]][0]; + s->idct_selector[b] = 63; } return 0; } diff --git a/libavcodec/vp56.c b/libavcodec/vp56.c index b69fe6c17..695f37e97 100644 --- a/libavcodec/vp56.c +++ b/libavcodec/vp56.c @@ -33,6 +33,8 @@ void ff_vp56_init_dequant(VP56Context *s, int quantizer) { + if (s->quantizer != quantizer) + ff_vp3dsp_set_bounding_values(s->bounding_values_array, ff_vp56_filter_threshold[quantizer]); s->quantizer = quantizer; s->dequant_dc = ff_vp56_dc_dequant[quantizer] << 2; s->dequant_ac = ff_vp56_ac_dequant[quantizer] << 2; @@ -196,12 +198,8 @@ static void vp56_decode_4mv(VP56Context *s, int row, int col) s->macroblocks[row * s->mb_width + col].mv = s->mv[3]; /* chroma vectors are average luma vectors */ - if (s->avctx->codec->id == AV_CODEC_ID_VP5) { - s->mv[4].x = s->mv[5].x = RSHIFT(mv.x,2); - s->mv[4].y = s->mv[5].y = RSHIFT(mv.y,2); - } else { - s->mv[4] = s->mv[5] = (VP56mv) {mv.x/4, mv.y/4}; - } + s->mv[4].x = s->mv[5].x = RSHIFT(mv.x,2); + s->mv[4].y = s->mv[5].y = RSHIFT(mv.y,2); } static VP56mb vp56_decode_mv(VP56Context *s, int row, int col) @@ -324,9 +322,17 @@ static void vp56_add_predictors_dc(VP56Context *s, VP56Frame ref_frame) static void vp56_deblock_filter(VP56Context *s, uint8_t *yuv, ptrdiff_t stride, int dx, int dy) { + if (s->avctx->codec->id == AV_CODEC_ID_VP5) { int t = ff_vp56_filter_threshold[s->quantizer]; if (dx) s->vp56dsp.edge_filter_hor(yuv + 10-dx , stride, t); if (dy) s->vp56dsp.edge_filter_ver(yuv + stride*(10-dy), stride, t); + } else { + int * bounding_values = s->bounding_values_array + 127; + if (dx) + ff_vp3dsp_h_loop_filter_12(yuv + 10-dx, stride, bounding_values); + if (dy) + ff_vp3dsp_v_loop_filter_12(yuv + stride*(10-dy), stride, bounding_values); + } } static void vp56_mc(VP56Context *s, int b, int plane, uint8_t *src, @@ -400,6 +406,24 @@ static void vp56_mc(VP56Context *s, int b, int plane, uint8_t *src, } } +static void vp56_idct_put(VP56Context *s, uint8_t * dest, ptrdiff_t stride, int16_t *block, int selector) +{ + if (selector > 10 || selector == 1) + s->vp3dsp.idct_put(dest, stride, block); + else + ff_vp3dsp_idct10_put(dest, stride, block); +} + +static void vp56_idct_add(VP56Context *s, uint8_t * dest, ptrdiff_t stride, int16_t *block, int selector) +{ + if (selector > 10) + s->vp3dsp.idct_add(dest, stride, block); + else if (selector > 1) + ff_vp3dsp_idct10_add(dest, stride, block); + else + s->vp3dsp.idct_dc_add(dest, stride, block); +} + static av_always_inline void vp56_render_mb(VP56Context *s, int row, int col, int is_alpha, VP56mb mb_type) { int b, ab, b_max, plane, off; @@ -420,8 +444,8 @@ static av_always_inline void vp56_render_mb(VP56Context *s, int row, int col, in case VP56_MB_INTRA: for (b=0; bvp3dsp.idct_put(frame_current->data[plane] + s->block_offset[b], - s->stride[plane], s->block_coeff[b]); + vp56_idct_put(s, frame_current->data[plane] + s->block_offset[b], + s->stride[plane], s->block_coeff[b], s->idct_selector[b]); } break; @@ -433,8 +457,8 @@ static av_always_inline void vp56_render_mb(VP56Context *s, int row, int col, in s->hdsp.put_pixels_tab[1][0](frame_current->data[plane] + off, frame_ref->data[plane] + off, s->stride[plane], 8); - s->vp3dsp.idct_add(frame_current->data[plane] + off, - s->stride[plane], s->block_coeff[b]); + vp56_idct_add(s, frame_current->data[plane] + off, + s->stride[plane], s->block_coeff[b], s->idct_selector[b]); } break; @@ -451,8 +475,8 @@ static av_always_inline void vp56_render_mb(VP56Context *s, int row, int col, in plane = ff_vp56_b2p[b+ab]; vp56_mc(s, b, plane, frame_ref->data[plane], s->stride[plane], 16*col+x_off, 16*row+y_off); - s->vp3dsp.idct_add(frame_current->data[plane] + s->block_offset[b], - s->stride[plane], s->block_coeff[b]); + vp56_idct_add(s, frame_current->data[plane] + s->block_offset[b], + s->stride[plane], s->block_coeff[b], s->idct_selector[b]); } break; } @@ -548,7 +572,7 @@ int ff_vp56_decode_frame(AVCodecContext *avctx, void *data, int *got_frame, VP56Context *s = avctx->priv_data; AVFrame *const p = s->frames[VP56_FRAME_CURRENT]; int remaining_buf_size = avpkt->size; - int av_uninit(alpha_offset); + int alpha_offset = remaining_buf_size; int i, res; int ret; @@ -561,7 +585,7 @@ int ff_vp56_decode_frame(AVCodecContext *avctx, void *data, int *got_frame, return AVERROR_INVALIDDATA; } - res = s->parse_header(s, buf, remaining_buf_size); + res = s->parse_header(s, buf, alpha_offset); if (res < 0) return res; diff --git a/libavcodec/vp56.h b/libavcodec/vp56.h index b8dda9e73..84b2f6c94 100644 --- a/libavcodec/vp56.h +++ b/libavcodec/vp56.h @@ -105,6 +105,7 @@ typedef struct VP56Macroblock { typedef struct VP56Model { uint8_t coeff_reorder[64]; /* used in vp6 only */ uint8_t coeff_index_to_pos[64]; /* used in vp6 only */ + uint8_t coeff_index_to_idct_selector[64]; /* used in vp6 only */ uint8_t vector_sig[2]; /* delta sign */ uint8_t vector_dct[2]; /* delta coding types */ uint8_t vector_pdi[2][2]; /* predefined delta init */ @@ -157,6 +158,7 @@ struct vp56_context { VP56mb mb_type; VP56Macroblock *macroblocks; DECLARE_ALIGNED(16, int16_t, block_coeff)[6][64]; + int idct_selector[6]; /* motion vectors */ VP56mv mv[6]; /* vectors for each block in MB */ @@ -170,6 +172,7 @@ struct vp56_context { int filter_mode; int max_vector_length; int sample_variance_threshold; + DECLARE_ALIGNED(8, int, bounding_values_array)[256]; uint8_t coeff_ctx[4][64]; /* used in vp5 only */ uint8_t coeff_ctx_last[4]; /* used in vp5 only */ @@ -227,6 +230,14 @@ int ff_vp56_decode_frame(AVCodecContext *avctx, void *data, int *got_frame, extern const uint8_t ff_vp56_norm_shift[256]; int ff_vp56_init_range_decoder(VP56RangeCoder *c, const uint8_t *buf, int buf_size); +/** + * vp5689 returns 1 if the end of the stream has been reached, 0 otherwise. + */ +static av_always_inline int vpX_rac_is_end(VP56RangeCoder *c) +{ + return c->end <= c->buffer && c->bits >= 0; +} + static av_always_inline unsigned int vp56_rac_renorm(VP56RangeCoder *c) { int shift = ff_vp56_norm_shift[c->high]; diff --git a/libavcodec/vp56dsp.c b/libavcodec/vp56dsp.c index 9f299dc60..e8d93d668 100644 --- a/libavcodec/vp56dsp.c +++ b/libavcodec/vp56dsp.c @@ -72,27 +72,8 @@ av_cold void ff_vp5dsp_init(VP56DSPContext *s) #endif /* CONFIG_VP5_DECODER */ #if CONFIG_VP6_DECODER -static int vp6_adjust(int v, int t) -{ - int V = v, s = v >> 31; - V ^= s; - V -= s; - if (V-t-1 >= (unsigned)(t-1)) - return v; - V = 2*t - V; - V += s; - V ^= s; - return V; -} - -VP56_EDGE_FILTER(vp6, hor, 1, stride) -VP56_EDGE_FILTER(vp6, ver, stride, 1) - av_cold void ff_vp6dsp_init(VP56DSPContext *s) { - s->edge_filter_hor = vp6_edge_filter_hor; - s->edge_filter_ver = vp6_edge_filter_ver; - s->vp6_filter_diag4 = ff_vp6_filter_diag4_c; if (ARCH_ARM) diff --git a/libavcodec/vp6.c b/libavcodec/vp6.c index 645fc5c69..e5dec19f5 100644 --- a/libavcodec/vp6.c +++ b/libavcodec/vp6.c @@ -194,6 +194,18 @@ static void vp6_coeff_order_table_init(VP56Context *s) for (pos=1; pos<64; pos++) if (s->modelp->coeff_reorder[pos] == i) s->modelp->coeff_index_to_pos[idx++] = pos; + + for (idx = 0; idx < 64; idx++) { + int max = 0; + for (i = 0; i <= idx; i++) { + int v = s->modelp->coeff_index_to_pos[i]; + if (v > max) + max = v; + } + if (s->sub_version > 6) + max++; + s->modelp->coeff_index_to_idct_selector[idx] = max; + } } static void vp6_default_models_init(VP56Context *s) @@ -446,6 +458,7 @@ static int vp6_parse_coeff_huffman(VP56Context *s) cg = FFMIN(vp6_coeff_groups[coeff_idx], 3); vlc_coeff = &s->ract_vlc[pt][ct][cg]; } + s->idct_selector[b] = model->coeff_index_to_idct_selector[FFMIN(coeff_idx, 63)]; } return 0; } @@ -460,7 +473,7 @@ static int vp6_parse_coeff(VP56Context *s) int b, i, cg, idx, ctx; int pt = 0; /* plane type (0 for Y, 1 for U or V) */ - if (c->end <= c->buffer && c->bits >= 0) { + if (vpX_rac_is_end(c)) { av_log(s->avctx, AV_LOG_ERROR, "End of AC stream reached in vp6_parse_coeff\n"); return AVERROR_INVALIDDATA; } @@ -527,6 +540,7 @@ static int vp6_parse_coeff(VP56Context *s) s->left_block[ff_vp56_b6to4[b]].not_null_dc = s->above_blocks[s->above_block_idx[b]].not_null_dc = !!s->block_coeff[b][0]; + s->idct_selector[b] = model->coeff_index_to_idct_selector[FFMIN(coeff_idx, 63)]; } return 0; } diff --git a/libavcodec/vp8.c b/libavcodec/vp8.c index 62b9f8bc2..3ddc349a4 100644 --- a/libavcodec/vp8.c +++ b/libavcodec/vp8.c @@ -492,9 +492,11 @@ static void fade(uint8_t *dst, ptrdiff_t dst_linesize, { int i, j; for (j = 0; j < height; j++) { + const uint8_t *src2 = src + j * src_linesize; + uint8_t *dst2 = dst + j * dst_linesize; for (i = 0; i < width; i++) { - uint8_t y = src[j * src_linesize + i]; - dst[j * dst_linesize + i] = av_clip_uint8(y + ((y * beta) >> 8) + alpha); + uint8_t y = src2[i]; + dst2[i] = av_clip_uint8(y + ((y * beta) >> 8) + alpha); } } } @@ -505,6 +507,9 @@ static int vp7_fade_frame(VP8Context *s, VP56RangeCoder *c) int beta = (int8_t) vp8_rac_get_uint(c, 8); int ret; + if (c->end <= c->buffer && c->bits >= 0) + return AVERROR_INVALIDDATA; + if (!s->keyframe && (alpha || beta)) { int width = s->mb_width * 16; int height = s->mb_height * 16; @@ -656,7 +661,7 @@ static int vp7_decode_frame_header(VP8Context *s, const uint8_t *buf, int buf_si s->fade_present = vp8_rac_get(c); } - if (c->end <= c->buffer && c->bits >= 0) + if (vpX_rac_is_end(c)) return AVERROR_INVALIDDATA; /* E. Fading information for previous frame */ if (s->fade_present && vp8_rac_get(c)) { @@ -2263,7 +2268,7 @@ void filter_mb_simple(VP8Context *s, uint8_t *dst, VP8FilterStrength *f, #define MARGIN (16 << 2) static av_always_inline -void vp78_decode_mv_mb_modes(AVCodecContext *avctx, VP8Frame *curframe, +int vp78_decode_mv_mb_modes(AVCodecContext *avctx, VP8Frame *curframe, VP8Frame *prev_frame, int is_vp7) { VP8Context *s = avctx->priv_data; @@ -2280,6 +2285,10 @@ void vp78_decode_mv_mb_modes(AVCodecContext *avctx, VP8Frame *curframe, s->mv_bounds.mv_min.x = -MARGIN; s->mv_bounds.mv_max.x = ((s->mb_width - 1) << 6) + MARGIN; + + if (vpX_rac_is_end(&s->c)) { + return AVERROR_INVALIDDATA; + } for (mb_x = 0; mb_x < s->mb_width; mb_x++, mb_xy++, mb++) { if (mb_y == 0) AV_WN32A((mb - s->mb_width - 1)->intra4x4_pred_mode_top, @@ -2293,18 +2302,19 @@ void vp78_decode_mv_mb_modes(AVCodecContext *avctx, VP8Frame *curframe, s->mv_bounds.mv_min.y -= 64; s->mv_bounds.mv_max.y -= 64; } + return 0; } -static void vp7_decode_mv_mb_modes(AVCodecContext *avctx, VP8Frame *cur_frame, +static int vp7_decode_mv_mb_modes(AVCodecContext *avctx, VP8Frame *cur_frame, VP8Frame *prev_frame) { - vp78_decode_mv_mb_modes(avctx, cur_frame, prev_frame, IS_VP7); + return vp78_decode_mv_mb_modes(avctx, cur_frame, prev_frame, IS_VP7); } -static void vp8_decode_mv_mb_modes(AVCodecContext *avctx, VP8Frame *cur_frame, +static int vp8_decode_mv_mb_modes(AVCodecContext *avctx, VP8Frame *cur_frame, VP8Frame *prev_frame) { - vp78_decode_mv_mb_modes(avctx, cur_frame, prev_frame, IS_VP8); + return vp78_decode_mv_mb_modes(avctx, cur_frame, prev_frame, IS_VP8); } #if HAVE_THREADS @@ -2362,7 +2372,7 @@ static av_always_inline int decode_mb_row_no_filter(AVCodecContext *avctx, void curframe->tf.f->data[2] + 8 * mb_y * s->uvlinesize }; - if (c->end <= c->buffer && c->bits >= 0) + if (vpX_rac_is_end(c)) return AVERROR_INVALIDDATA; if (mb_y == 0) @@ -2393,7 +2403,7 @@ static av_always_inline int decode_mb_row_no_filter(AVCodecContext *avctx, void td->mv_bounds.mv_max.x = ((s->mb_width - 1) << 6) + MARGIN; for (mb_x = 0; mb_x < s->mb_width; mb_x++, mb_xy++, mb++) { - if (c->end <= c->buffer && c->bits >= 0) + if (vpX_rac_is_end(c)) return AVERROR_INVALIDDATA; // Wait for previous thread to read mb_x+2, and reach mb_y-1. if (prev_td != td) { @@ -2739,9 +2749,11 @@ int vp78_decode_frame(AVCodecContext *avctx, void *data, int *got_frame, !s->segmentation.update_map) ff_thread_await_progress(&prev_frame->tf, 1, 0); if (is_vp7) - vp7_decode_mv_mb_modes(avctx, curframe, prev_frame); + ret = vp7_decode_mv_mb_modes(avctx, curframe, prev_frame); else - vp8_decode_mv_mb_modes(avctx, curframe, prev_frame); + ret = vp8_decode_mv_mb_modes(avctx, curframe, prev_frame); + if (ret < 0) + goto err; } if (avctx->active_thread_type == FF_THREAD_FRAME) diff --git a/libavcodec/vp8_parser.c b/libavcodec/vp8_parser.c index e2d91b271..7ce35e753 100644 --- a/libavcodec/vp8_parser.c +++ b/libavcodec/vp8_parser.c @@ -70,8 +70,6 @@ static int parse(AVCodecParserContext *s, s->coded_height = FFALIGN(height, 16); } - *poutbuf = buf; - *poutbuf_size = buf_size; return buf_size; } diff --git a/libavcodec/vp8dsp.c b/libavcodec/vp8dsp.c index fed5c67a9..4ff63d078 100644 --- a/libavcodec/vp8dsp.c +++ b/libavcodec/vp8dsp.c @@ -673,6 +673,8 @@ av_cold void ff_vp78dsp_init(VP8DSPContext *dsp) VP78_BILINEAR_MC_FUNC(1, 8); VP78_BILINEAR_MC_FUNC(2, 4); + if (ARCH_AARCH64) + ff_vp78dsp_init_aarch64(dsp); if (ARCH_ARM) ff_vp78dsp_init_arm(dsp); if (ARCH_PPC) @@ -733,6 +735,8 @@ av_cold void ff_vp8dsp_init(VP8DSPContext *dsp) dsp->vp8_v_loop_filter_simple = vp8_v_loop_filter_simple_c; dsp->vp8_h_loop_filter_simple = vp8_h_loop_filter_simple_c; + if (ARCH_AARCH64) + ff_vp8dsp_init_aarch64(dsp); if (ARCH_ARM) ff_vp8dsp_init_arm(dsp); if (ARCH_X86) diff --git a/libavcodec/vp8dsp.h b/libavcodec/vp8dsp.h index eaae4aed6..cfe1524b0 100644 --- a/libavcodec/vp8dsp.h +++ b/libavcodec/vp8dsp.h @@ -91,11 +91,13 @@ void ff_put_vp8_pixels4_c(uint8_t *dst, uint8_t *src, ptrdiff_t stride, void ff_vp7dsp_init(VP8DSPContext *c); void ff_vp78dsp_init(VP8DSPContext *c); +void ff_vp78dsp_init_aarch64(VP8DSPContext *c); void ff_vp78dsp_init_arm(VP8DSPContext *c); void ff_vp78dsp_init_ppc(VP8DSPContext *c); void ff_vp78dsp_init_x86(VP8DSPContext *c); void ff_vp8dsp_init(VP8DSPContext *c); +void ff_vp8dsp_init_aarch64(VP8DSPContext *c); void ff_vp8dsp_init_arm(VP8DSPContext *c); void ff_vp8dsp_init_x86(VP8DSPContext *c); void ff_vp8dsp_init_mips(VP8DSPContext *c); diff --git a/libavcodec/vp9.c b/libavcodec/vp9.c index b1178c9c0..f16462b1e 100644 --- a/libavcodec/vp9.c +++ b/libavcodec/vp9.c @@ -353,7 +353,7 @@ static av_always_inline int inv_recenter_nonneg(int v, int m) // differential forward probability updates static int update_prob(VP56RangeCoder *c, int p) { - static const int inv_map_table[255] = { + static const uint8_t inv_map_table[255] = { 7, 20, 33, 46, 59, 72, 85, 98, 111, 124, 137, 150, 163, 176, 189, 202, 215, 228, 241, 254, 1, 2, 3, 4, 5, 6, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 21, 22, 23, 24, @@ -1306,6 +1306,9 @@ static int decode_tiles(AVCodecContext *avctx, decode_sb_mem(td, row, col, lflvl_ptr, yoff2, uvoff2, BL_64X64); } else { + if (vpX_rac_is_end(td->c)) { + return AVERROR_INVALIDDATA; + } decode_sb(td, row, col, lflvl_ptr, yoff2, uvoff2, BL_64X64); } diff --git a/libavcodec/vp9_metadata_bsf.c b/libavcodec/vp9_metadata_bsf.c new file mode 100644 index 000000000..1bde1b96a --- /dev/null +++ b/libavcodec/vp9_metadata_bsf.c @@ -0,0 +1,158 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/avstring.h" +#include "libavutil/common.h" +#include "libavutil/opt.h" + +#include "bsf.h" +#include "cbs.h" +#include "cbs_vp9.h" + +typedef struct VP9MetadataContext { + const AVClass *class; + + CodedBitstreamContext *cbc; + CodedBitstreamFragment fragment; + + int color_space; + int color_range; + + int color_range_rgb_warned; +} VP9MetadataContext; + + +static int vp9_metadata_filter(AVBSFContext *bsf, AVPacket *pkt) +{ + VP9MetadataContext *ctx = bsf->priv_data; + CodedBitstreamFragment *frag = &ctx->fragment; + int err, i; + + err = ff_bsf_get_packet_ref(bsf, pkt); + if (err < 0) + return err; + + err = ff_cbs_read_packet(ctx->cbc, frag, pkt); + if (err < 0) { + av_log(bsf, AV_LOG_ERROR, "Failed to read packet.\n"); + goto fail; + } + + for (i = 0; i < frag->nb_units; i++) { + VP9RawFrame *frame = frag->units[i].content; + VP9RawFrameHeader *header = &frame->header; + + if (ctx->color_space >= 0) { + header->color_space = ctx->color_space; + } + if (ctx->color_range >= 0) { + if (ctx->color_range == 0 && + header->color_space == VP9_CS_RGB && + !ctx->color_range_rgb_warned) { + av_log(bsf, AV_LOG_WARNING, "Warning: color_range cannot " + "be set to limited in RGB streams.\n"); + ctx->color_range_rgb_warned = 1; + } else { + header->color_range = ctx->color_range; + } + } + } + + err = ff_cbs_write_packet(ctx->cbc, pkt, frag); + if (err < 0) { + av_log(bsf, AV_LOG_ERROR, "Failed to write packet.\n"); + goto fail; + } + + err = 0; +fail: + ff_cbs_fragment_reset(ctx->cbc, frag); + + if (err < 0) + av_packet_unref(pkt); + + return err; +} + +static int vp9_metadata_init(AVBSFContext *bsf) +{ + VP9MetadataContext *ctx = bsf->priv_data; + + return ff_cbs_init(&ctx->cbc, AV_CODEC_ID_VP9, bsf); +} + +static void vp9_metadata_close(AVBSFContext *bsf) +{ + VP9MetadataContext *ctx = bsf->priv_data; + + ff_cbs_fragment_free(ctx->cbc, &ctx->fragment); + ff_cbs_close(&ctx->cbc); +} + +#define OFFSET(x) offsetof(VP9MetadataContext, x) +#define FLAGS (AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_BSF_PARAM) +static const AVOption vp9_metadata_options[] = { + { "color_space", "Set colour space (section 7.2.2)", + OFFSET(color_space), AV_OPT_TYPE_INT, + { .i64 = -1 }, -1, VP9_CS_RGB, FLAGS, "cs" }, + { "unknown", "Unknown/unspecified", 0, AV_OPT_TYPE_CONST, + { .i64 = VP9_CS_UNKNOWN }, .flags = FLAGS, .unit = "cs" }, + { "bt601", "ITU-R BT.601-7", 0, AV_OPT_TYPE_CONST, + { .i64 = VP9_CS_BT_601 }, .flags = FLAGS, .unit = "cs" }, + { "bt709", "ITU-R BT.709-6", 0, AV_OPT_TYPE_CONST, + { .i64 = VP9_CS_BT_709 }, .flags = FLAGS, .unit = "cs" }, + { "smpte170", "SMPTE-170", 0, AV_OPT_TYPE_CONST, + { .i64 = VP9_CS_SMPTE_170 }, .flags = FLAGS, .unit = "cs" }, + { "smpte240", "SMPTE-240", 0, AV_OPT_TYPE_CONST, + { .i64 = VP9_CS_SMPTE_240 }, .flags = FLAGS, .unit = "cs" }, + { "bt2020", "ITU-R BT.2020-2", 0, AV_OPT_TYPE_CONST, + { .i64 = VP9_CS_BT_2020 }, .flags = FLAGS, .unit = "cs" }, + { "rgb", "sRGB / IEC 61966-2-1", 0, AV_OPT_TYPE_CONST, + { .i64 = VP9_CS_RGB }, .flags = FLAGS, .unit = "cs" }, + + { "color_range", "Set colour range (section 7.2.2)", + OFFSET(color_range), AV_OPT_TYPE_INT, + { .i64 = -1 }, -1, 1, FLAGS, "cr" }, + { "tv", "TV (limited) range", 0, AV_OPT_TYPE_CONST, + { .i64 = 0 }, .flags = FLAGS, .unit = "cr" }, + { "pc", "PC (full) range", 0, AV_OPT_TYPE_CONST, + { .i64 = 1 }, .flags = FLAGS, .unit = "cr" }, + + { NULL } +}; + +static const AVClass vp9_metadata_class = { + .class_name = "vp9_metadata_bsf", + .item_name = av_default_item_name, + .option = vp9_metadata_options, + .version = LIBAVUTIL_VERSION_INT, +}; + +static const enum AVCodecID vp9_metadata_codec_ids[] = { + AV_CODEC_ID_VP9, AV_CODEC_ID_NONE, +}; + +const AVBitStreamFilter ff_vp9_metadata_bsf = { + .name = "vp9_metadata", + .priv_data_size = sizeof(VP9MetadataContext), + .priv_class = &vp9_metadata_class, + .init = &vp9_metadata_init, + .close = &vp9_metadata_close, + .filter = &vp9_metadata_filter, + .codec_ids = vp9_metadata_codec_ids, +}; diff --git a/libavcodec/vp9_parser.c b/libavcodec/vp9_parser.c index 9531f34a3..c957a7566 100644 --- a/libavcodec/vp9_parser.c +++ b/libavcodec/vp9_parser.c @@ -36,12 +36,16 @@ static int parse(AVCodecParserContext *ctx, *out_data = data; *out_size = size; - if ((res = init_get_bits8(&gb, data, size)) < 0) + if (!size || (res = init_get_bits8(&gb, data, size)) < 0) return size; // parsers can't return errors get_bits(&gb, 2); // frame marker profile = get_bits1(&gb); profile |= get_bits1(&gb) << 1; if (profile == 3) profile += get_bits1(&gb); + if (profile > 3) + return size; + + avctx->profile = profile; if (get_bits1(&gb)) { keyframe = 0; diff --git a/libavcodec/vp9_raw_reorder_bsf.c b/libavcodec/vp9_raw_reorder_bsf.c index 01f3dad89..f19b4c719 100644 --- a/libavcodec/vp9_raw_reorder_bsf.c +++ b/libavcodec/vp9_raw_reorder_bsf.c @@ -385,6 +385,16 @@ fail: return err; } +static void vp9_raw_reorder_flush(AVBSFContext *bsf) +{ + VP9RawReorderContext *ctx = bsf->priv_data; + + for (int s = 0; s < FRAME_SLOTS; s++) + vp9_raw_reorder_clear_slot(ctx, s); + ctx->next_frame = NULL; + ctx->sequence = 0; +} + static void vp9_raw_reorder_close(AVBSFContext *bsf) { VP9RawReorderContext *ctx = bsf->priv_data; @@ -402,6 +412,7 @@ const AVBitStreamFilter ff_vp9_raw_reorder_bsf = { .name = "vp9_raw_reorder", .priv_data_size = sizeof(VP9RawReorderContext), .close = &vp9_raw_reorder_close, + .flush = &vp9_raw_reorder_flush, .filter = &vp9_raw_reorder_filter, .codec_ids = vp9_raw_reorder_codec_ids, }; diff --git a/libavcodec/vp9_superframe_bsf.c b/libavcodec/vp9_superframe_bsf.c index 52569ab09..23933d413 100644 --- a/libavcodec/vp9_superframe_bsf.c +++ b/libavcodec/vp9_superframe_bsf.c @@ -133,7 +133,7 @@ static int vp9_superframe_filter(AVBSFContext *ctx, AVPacket *out) if (uses_superframe_syntax && s->n_cache > 0) { av_log(ctx, AV_LOG_ERROR, - "Mixing of superframe syntax and naked VP9 frames not supported"); + "Mixing of superframe syntax and naked VP9 frames not supported\n"); res = AVERROR(ENOSYS); goto done; } else if ((!invisible || uses_superframe_syntax) && !s->n_cache) { @@ -142,7 +142,7 @@ static int vp9_superframe_filter(AVBSFContext *ctx, AVPacket *out) goto done; } else if (s->n_cache + 1 >= MAX_CACHE) { av_log(ctx, AV_LOG_ERROR, - "Too many invisible frames"); + "Too many invisible frames\n"); res = AVERROR_INVALIDDATA; goto done; } @@ -189,6 +189,17 @@ static int vp9_superframe_init(AVBSFContext *ctx) return 0; } +static void vp9_superframe_flush(AVBSFContext *ctx) +{ + VP9BSFContext *s = ctx->priv_data; + int n; + + // unref cached data + for (n = 0; n < s->n_cache; n++) + av_packet_unref(s->cache[n]); + s->n_cache = 0; +} + static void vp9_superframe_close(AVBSFContext *ctx) { VP9BSFContext *s = ctx->priv_data; @@ -208,6 +219,7 @@ const AVBitStreamFilter ff_vp9_superframe_bsf = { .priv_data_size = sizeof(VP9BSFContext), .filter = vp9_superframe_filter, .init = vp9_superframe_init, + .flush = vp9_superframe_flush, .close = vp9_superframe_close, .codec_ids = codec_ids, }; diff --git a/libavcodec/vp9_superframe_split_bsf.c b/libavcodec/vp9_superframe_split_bsf.c index 9c4aa33dc..13e85c3ca 100644 --- a/libavcodec/vp9_superframe_split_bsf.c +++ b/libavcodec/vp9_superframe_split_bsf.c @@ -30,7 +30,7 @@ #include "get_bits.h" typedef struct VP9SFSplitContext { - AVPacket buffer_pkt; + AVPacket *buffer_pkt; int nb_frames; int next_frame; @@ -43,13 +43,13 @@ static int vp9_superframe_split_filter(AVBSFContext *ctx, AVPacket *out) VP9SFSplitContext *s = ctx->priv_data; AVPacket *in; int i, j, ret, marker; - int is_superframe = !!s->buffer_pkt.data; + int is_superframe = !!s->buffer_pkt->data; - if (!s->buffer_pkt.data) { - ret = ff_bsf_get_packet_ref(ctx, &s->buffer_pkt); + if (!s->buffer_pkt->data) { + ret = ff_bsf_get_packet_ref(ctx, s->buffer_pkt); if (ret < 0) return ret; - in = &s->buffer_pkt; + in = s->buffer_pkt; marker = in->data[in->size - 1]; if ((marker & 0xe0) == 0xc0) { @@ -90,7 +90,7 @@ static int vp9_superframe_split_filter(AVBSFContext *ctx, AVPacket *out) GetBitContext gb; int profile, invisible = 0; - ret = av_packet_ref(out, &s->buffer_pkt); + ret = av_packet_ref(out, s->buffer_pkt); if (ret < 0) goto fail; @@ -101,7 +101,7 @@ static int vp9_superframe_split_filter(AVBSFContext *ctx, AVPacket *out) s->next_frame++; if (s->next_frame >= s->nb_frames) - av_packet_unref(&s->buffer_pkt); + av_packet_unref(s->buffer_pkt); ret = init_get_bits8(&gb, out->data, out->size); if (ret < 0) @@ -121,26 +121,45 @@ static int vp9_superframe_split_filter(AVBSFContext *ctx, AVPacket *out) out->pts = AV_NOPTS_VALUE; } else { - av_packet_move_ref(out, &s->buffer_pkt); + av_packet_move_ref(out, s->buffer_pkt); } return 0; fail: if (ret < 0) av_packet_unref(out); - av_packet_unref(&s->buffer_pkt); + av_packet_unref(s->buffer_pkt); return ret; } +static int vp9_superframe_split_init(AVBSFContext *ctx) +{ + VP9SFSplitContext *s = ctx->priv_data; + + s->buffer_pkt = av_packet_alloc(); + if (!s->buffer_pkt) + return AVERROR(ENOMEM); + + return 0; +} + +static void vp9_superframe_split_flush(AVBSFContext *ctx) +{ + VP9SFSplitContext *s = ctx->priv_data; + av_packet_unref(s->buffer_pkt); +} + static void vp9_superframe_split_uninit(AVBSFContext *ctx) { VP9SFSplitContext *s = ctx->priv_data; - av_packet_unref(&s->buffer_pkt); + av_packet_free(&s->buffer_pkt); } const AVBitStreamFilter ff_vp9_superframe_split_bsf = { .name = "vp9_superframe_split", .priv_data_size = sizeof(VP9SFSplitContext), + .init = vp9_superframe_split_init, + .flush = vp9_superframe_split_flush, .close = vp9_superframe_split_uninit, .filter = vp9_superframe_split_filter, .codec_ids = (const enum AVCodecID []){ AV_CODEC_ID_VP9, AV_CODEC_ID_NONE }, diff --git a/libavcodec/vqavideo.c b/libavcodec/vqavideo.c index 0e70be100..b9743abda 100644 --- a/libavcodec/vqavideo.c +++ b/libavcodec/vqavideo.c @@ -147,7 +147,7 @@ static av_cold int vqa_decode_init(AVCodecContext *avctx) } s->width = AV_RL16(&s->avctx->extradata[6]); s->height = AV_RL16(&s->avctx->extradata[8]); - if ((ret = av_image_check_size(s->width, s->height, 0, avctx)) < 0) { + if ((ret = ff_set_dimensions(avctx, s->width, s->height)) < 0) { s->width= s->height= 0; return ret; } diff --git a/libavcodec/wavpack.c b/libavcodec/wavpack.c index 8306ec020..d0242809f 100644 --- a/libavcodec/wavpack.c +++ b/libavcodec/wavpack.c @@ -940,13 +940,23 @@ static int wavpack_decode_block(AVCodecContext *avctx, int block_no, case 3: chmask = bytestream2_get_le32(&gb); break; + case 4: + size = bytestream2_get_byte(&gb); + chan |= (bytestream2_get_byte(&gb) & 0xF) << 8; + chan += 1; + if (avctx->channels != chan) + av_log(avctx, AV_LOG_WARNING, "%i channels signalled" + " instead of %i.\n", chan, avctx->channels); + chmask = bytestream2_get_le24(&gb); + break; case 5: size = bytestream2_get_byte(&gb); - if (avctx->channels != size) - av_log(avctx, AV_LOG_WARNING, "%i channels signalled" - " instead of %i.\n", size, avctx->channels); chan |= (bytestream2_get_byte(&gb) & 0xF) << 8; - chmask = bytestream2_get_le16(&gb); + chan += 1; + if (avctx->channels != chan) + av_log(avctx, AV_LOG_WARNING, "%i channels signalled" + " instead of %i.\n", chan, avctx->channels); + chmask = bytestream2_get_le32(&gb); break; default: av_log(avctx, AV_LOG_ERROR, "Invalid channel info size %d\n", diff --git a/libavcodec/wavpackenc.c b/libavcodec/wavpackenc.c index 979b92165..95f4b6530 100644 --- a/libavcodec/wavpackenc.c +++ b/libavcodec/wavpackenc.c @@ -637,21 +637,15 @@ static void reverse_mono_decorr(struct Decorr *dpp) } } +#define count_bits(av) ((av) ? 32 - ff_clz(av) : 0) + static uint32_t log2sample(uint32_t v, int limit, uint32_t *result) { - uint32_t dbits; + uint32_t dbits = count_bits(v); if ((v += v >> 9) < (1 << 8)) { - dbits = nbits_table[v]; *result += (dbits << 8) + wp_log2_table[(v << (9 - dbits)) & 0xff]; } else { - if (v < (1 << 16)) - dbits = nbits_table[v >> 8] + 8; - else if (v < (1 << 24)) - dbits = nbits_table[v >> 16] + 16; - else - dbits = nbits_table[v >> 24] + 24; - *result += dbits = (dbits << 8) + wp_log2_table[(v >> (dbits - 9)) & 0xff]; if (limit && dbits >= limit) @@ -1969,14 +1963,6 @@ static int wv_stereo(WavPackEncodeContext *s, return 0; } -#define count_bits(av) ( \ - (av) < (1 << 8) ? nbits_table[av] : \ - ( \ - (av) < (1 << 16) ? nbits_table[(av) >> 8] + 8 : \ - ((av) < (1 << 24) ? nbits_table[(av) >> 16] + 16 : nbits_table[(av) >> 24] + 24) \ - ) \ -) - static void encode_flush(WavPackEncodeContext *s) { WavPackWords *w = &s->w; diff --git a/libavcodec/wavpackenc.h b/libavcodec/wavpackenc.h index 9dd2a01bb..11914337c 100644 --- a/libavcodec/wavpackenc.h +++ b/libavcodec/wavpackenc.h @@ -650,15 +650,4 @@ static const uint16_t decorr_filter_sizes[] = { static const uint8_t decorr_filter_nterms[] = { 2, 5, 10, 16 }; -static const int8_t nbits_table[] = { - 0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8 -}; - #endif /* AVCODEC_WAVPACKENC_H */ diff --git a/libavcodec/wcmv.c b/libavcodec/wcmv.c new file mode 100644 index 000000000..0d60b9fe1 --- /dev/null +++ b/libavcodec/wcmv.c @@ -0,0 +1,269 @@ +/* + * WinCAM Motion Video decoder + * + * Copyright (c) 2018 Paul B Mahol + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include + +#include "libavutil/imgutils.h" + +#include "avcodec.h" +#include "bytestream.h" +#include "internal.h" + +#include + +typedef struct WCMVContext { + int bpp; + z_stream zstream; + AVFrame *prev_frame; + uint8_t block_data[65536*8]; +} WCMVContext; + +static int decode_frame(AVCodecContext *avctx, + void *data, int *got_frame, + AVPacket *avpkt) +{ + WCMVContext *s = avctx->priv_data; + AVFrame *frame = data; + int skip, blocks, zret, ret, intra = 0, bpp = s->bpp; + GetByteContext gb; + uint8_t *dst; + + ret = inflateReset(&s->zstream); + if (ret != Z_OK) { + av_log(avctx, AV_LOG_ERROR, "Inflate reset error: %d\n", ret); + return AVERROR_EXTERNAL; + } + + bytestream2_init(&gb, avpkt->data, avpkt->size); + blocks = bytestream2_get_le16(&gb); + if (!blocks) + return avpkt->size; + + if ((ret = ff_get_buffer(avctx, frame, AV_GET_BUFFER_FLAG_REF)) < 0) + return ret; + + if (blocks > 5) { + GetByteContext bgb; + int x = 0, size; + + if (blocks * 8 >= 0xFFFF) + size = bytestream2_get_le24(&gb); + else if (blocks * 8 >= 0xFF) + size = bytestream2_get_le16(&gb); + else + size = bytestream2_get_byte(&gb); + + skip = bytestream2_tell(&gb); + if (size > avpkt->size - skip) + return AVERROR_INVALIDDATA; + + s->zstream.next_in = avpkt->data + skip; + s->zstream.avail_in = size; + s->zstream.next_out = s->block_data; + s->zstream.avail_out = sizeof(s->block_data); + + zret = inflate(&s->zstream, Z_FINISH); + if (zret != Z_STREAM_END) { + av_log(avctx, AV_LOG_ERROR, + "Inflate failed with return code: %d.\n", zret); + return AVERROR_INVALIDDATA; + } + + ret = inflateReset(&s->zstream); + if (ret != Z_OK) { + av_log(avctx, AV_LOG_ERROR, "Inflate reset error: %d\n", ret); + return AVERROR_EXTERNAL; + } + + bytestream2_skip(&gb, size); + bytestream2_init(&bgb, s->block_data, blocks * 8); + + for (int i = 0; i < blocks; i++) { + int w, h; + + bytestream2_skip(&bgb, 4); + w = bytestream2_get_le16(&bgb); + h = bytestream2_get_le16(&bgb); + if (x + bpp * (int64_t)w * h > INT_MAX) + return AVERROR_INVALIDDATA; + x += bpp * w * h; + } + + if (x >= 0xFFFF) + bytestream2_skip(&gb, 3); + else if (x >= 0xFF) + bytestream2_skip(&gb, 2); + else + bytestream2_skip(&gb, 1); + + skip = bytestream2_tell(&gb); + + s->zstream.next_in = avpkt->data + skip; + s->zstream.avail_in = avpkt->size - skip; + + bytestream2_init(&gb, s->block_data, blocks * 8); + } else if (blocks) { + int x = 0; + + bytestream2_seek(&gb, 2, SEEK_SET); + + for (int i = 0; i < blocks; i++) { + int w, h; + + bytestream2_skip(&gb, 4); + w = bytestream2_get_le16(&gb); + h = bytestream2_get_le16(&gb); + if (x + bpp * (int64_t)w * h > INT_MAX) + return AVERROR_INVALIDDATA; + x += bpp * w * h; + } + + if (x >= 0xFFFF) + bytestream2_skip(&gb, 3); + else if (x >= 0xFF) + bytestream2_skip(&gb, 2); + else + bytestream2_skip(&gb, 1); + + skip = bytestream2_tell(&gb); + + s->zstream.next_in = avpkt->data + skip; + s->zstream.avail_in = avpkt->size - skip; + + bytestream2_seek(&gb, 2, SEEK_SET); + } + + if (bytestream2_get_bytes_left(&gb) < 8LL * blocks) + return AVERROR_INVALIDDATA; + + if (s->prev_frame->data[0]) { + ret = av_frame_copy(frame, s->prev_frame); + if (ret < 0) + return ret; + } else { + ptrdiff_t linesize[4] = { frame->linesize[0], 0, 0, 0 }; + av_image_fill_black(frame->data, linesize, avctx->pix_fmt, 0, + avctx->width, avctx->height); + } + + for (int block = 0; block < blocks; block++) { + int x, y, w, h; + + x = bytestream2_get_le16(&gb); + y = bytestream2_get_le16(&gb); + w = bytestream2_get_le16(&gb); + h = bytestream2_get_le16(&gb); + + if (blocks == 1 && x == 0 && y == 0 && w == avctx->width && h == avctx->height) + intra = 1; + + if (x + w > avctx->width || y + h > avctx->height) + return AVERROR_INVALIDDATA; + + if (w > avctx->width || h > avctx->height) + return AVERROR_INVALIDDATA; + + dst = frame->data[0] + (avctx->height - y - 1) * frame->linesize[0] + x * bpp; + for (int i = 0; i < h; i++) { + s->zstream.next_out = dst; + s->zstream.avail_out = w * bpp; + + zret = inflate(&s->zstream, Z_SYNC_FLUSH); + if (zret != Z_OK && zret != Z_STREAM_END) { + av_log(avctx, AV_LOG_ERROR, + "Inflate failed with return code: %d.\n", zret); + return AVERROR_INVALIDDATA; + } + + dst -= frame->linesize[0]; + } + } + + frame->key_frame = intra; + frame->pict_type = intra ? AV_PICTURE_TYPE_I : AV_PICTURE_TYPE_P; + + av_frame_unref(s->prev_frame); + if ((ret = av_frame_ref(s->prev_frame, frame)) < 0) + return ret; + + *got_frame = 1; + + return avpkt->size; +} + +static av_cold int decode_init(AVCodecContext *avctx) +{ + WCMVContext *s = avctx->priv_data; + int zret; + + switch (avctx->bits_per_coded_sample) { + case 16: avctx->pix_fmt = AV_PIX_FMT_RGB565LE; break; + case 24: avctx->pix_fmt = AV_PIX_FMT_BGR24; break; + case 32: avctx->pix_fmt = AV_PIX_FMT_BGRA; break; + default: av_log(avctx, AV_LOG_ERROR, "Unsupported bits_per_coded_sample: %d\n", + avctx->bits_per_coded_sample); + return AVERROR_PATCHWELCOME; + } + + s->bpp = avctx->bits_per_coded_sample >> 3; + + s->zstream.zalloc = Z_NULL; + s->zstream.zfree = Z_NULL; + s->zstream.opaque = Z_NULL; + zret = inflateInit(&s->zstream); + if (zret != Z_OK) { + av_log(avctx, AV_LOG_ERROR, "Inflate init error: %d\n", zret); + return AVERROR_EXTERNAL; + } + + s->prev_frame = av_frame_alloc(); + if (!s->prev_frame) + return AVERROR(ENOMEM); + + return 0; +} + +static av_cold int decode_close(AVCodecContext *avctx) +{ + WCMVContext *s = avctx->priv_data; + + av_frame_free(&s->prev_frame); + inflateEnd(&s->zstream); + + return 0; +} + +AVCodec ff_wcmv_decoder = { + .name = "wcmv", + .long_name = NULL_IF_CONFIG_SMALL("WinCAM Motion Video"), + .type = AVMEDIA_TYPE_VIDEO, + .id = AV_CODEC_ID_WCMV, + .priv_data_size = sizeof(WCMVContext), + .init = decode_init, + .close = decode_close, + .decode = decode_frame, + .capabilities = AV_CODEC_CAP_DR1, + .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE | + FF_CODEC_CAP_INIT_CLEANUP, +}; diff --git a/libavcodec/wmaprodec.c b/libavcodec/wmaprodec.c index 9439bfa77..d0fa974c8 100644 --- a/libavcodec/wmaprodec.c +++ b/libavcodec/wmaprodec.c @@ -210,6 +210,7 @@ typedef struct WMAProDecodeCtx { int subframe_offset; ///< subframe offset in the bit reservoir uint8_t packet_loss; ///< set in case of bitstream error uint8_t packet_done; ///< set when a packet is fully decoded + uint8_t eof_done; ///< set when EOF reached and extra subframe is written (XMA1/2) /* frame decode state */ uint32_t frame_num; ///< current frame number (not used for decoding) @@ -1609,7 +1610,34 @@ static int decode_packet(AVCodecContext *avctx, WMAProDecodeCtx *s, *got_frame_ptr = 0; - if (s->packet_done || s->packet_loss) { + if (!buf_size) { + AVFrame *frame = data; + int i; + + /** Must output remaining samples after stream end. WMAPRO 5.1 created + * by XWMA encoder don't though (maybe only 1/2ch streams need it). */ + s->packet_done = 0; + if (s->eof_done) + return 0; + + /** clean output buffer and copy last IMDCT samples */ + for (i = 0; i < s->nb_channels; i++) { + memset(frame->extended_data[i], 0, + s->samples_per_frame * sizeof(*s->channel[i].out)); + + memcpy(frame->extended_data[i], s->channel[i].out, + s->samples_per_frame * sizeof(*s->channel[i].out) >> 1); + } + + /* TODO: XMA should output 128 samples only (instead of 512) and WMAPRO + * maybe 768 (with 2048), XMA needs changes in multi-stream handling though. */ + + s->eof_done = 1; + s->packet_done = 1; + *got_frame_ptr = 1; + return 0; + } + else if (s->packet_done || s->packet_loss) { s->packet_done = 0; /** sanity check for the buffer length */ @@ -1922,6 +1950,7 @@ static void flush(WMAProDecodeCtx *s) sizeof(*s->channel[i].out)); s->packet_loss = 1; s->skip_packets = 0; + s->eof_done = 0; } @@ -1976,7 +2005,7 @@ AVCodec ff_xma1_decoder = { .init = xma_decode_init, .close = xma_decode_end, .decode = xma_decode_packet, - .capabilities = AV_CODEC_CAP_SUBFRAMES | AV_CODEC_CAP_DR1, + .capabilities = AV_CODEC_CAP_SUBFRAMES | AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY, .sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_NONE }, }; @@ -1991,7 +2020,7 @@ AVCodec ff_xma2_decoder = { .close = xma_decode_end, .decode = xma_decode_packet, .flush = xma_flush, - .capabilities = AV_CODEC_CAP_SUBFRAMES | AV_CODEC_CAP_DR1, + .capabilities = AV_CODEC_CAP_SUBFRAMES | AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY, .sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_NONE }, }; diff --git a/libavcodec/wmavoice.c b/libavcodec/wmavoice.c index 444e303b0..68bb65986 100644 --- a/libavcodec/wmavoice.c +++ b/libavcodec/wmavoice.c @@ -1906,7 +1906,7 @@ static int wmavoice_decode_packet(AVCodecContext *ctx, void *data, * in a single "muxer" packet, so we artificially emulate that by * capping the packet size at ctx->block_align. */ for (size = avpkt->size; size > ctx->block_align; size -= ctx->block_align); - init_get_bits(&s->gb, avpkt->data, size << 3); + init_get_bits8(&s->gb, avpkt->data, size); /* size == ctx->block_align is used to indicate whether we are dealing with * a new packet or a packet of which we already read the packet header diff --git a/libavcodec/wmv2dec.c b/libavcodec/wmv2dec.c index a99da25de..afa65478e 100644 --- a/libavcodec/wmv2dec.c +++ b/libavcodec/wmv2dec.c @@ -33,6 +33,7 @@ static int parse_mb_skip(Wmv2Context *w) { int mb_x, mb_y; + int coded_mb_count = 0; MpegEncContext *const s = &w->s; uint32_t *const mb_type = s->current_picture_ptr->mb_type; @@ -83,6 +84,14 @@ static int parse_mb_skip(Wmv2Context *w) } break; } + + for (mb_y = 0; mb_y < s->mb_height; mb_y++) + for (mb_x = 0; mb_x < s->mb_width; mb_x++) + coded_mb_count += !IS_SKIP(mb_type[mb_y * s->mb_stride + mb_x]); + + if (coded_mb_count > get_bits_left(&s->gb)) + return AVERROR_INVALIDDATA; + return 0; } @@ -141,6 +150,21 @@ int ff_wmv2_decode_picture_header(MpegEncContext *s) if (s->qscale <= 0) return AVERROR_INVALIDDATA; + if (s->pict_type != AV_PICTURE_TYPE_I && show_bits(&s->gb, 1)) { + GetBitContext gb = s->gb; + int skip_type = get_bits(&gb, 2); + int run = skip_type == SKIP_TYPE_COL ? s->mb_width : s->mb_height; + + while (run > 0) { + int block = FFMIN(run, 25); + if (get_bits(&gb, block) + 1 != 1<rl_chroma_table_index = s->rl_table_index; } + if (get_bits_left(&s->gb) < 2) + return AVERROR_INVALIDDATA; + s->dc_table_index = get_bits1(&s->gb); s->mv_table_index = get_bits1(&s->gb); diff --git a/libavcodec/x86/Makefile b/libavcodec/x86/Makefile index 2350c8bbe..194135daf 100644 --- a/libavcodec/x86/Makefile +++ b/libavcodec/x86/Makefile @@ -53,10 +53,11 @@ OBJS-$(CONFIG_CAVS_DECODER) += x86/cavsdsp.o OBJS-$(CONFIG_DCA_DECODER) += x86/dcadsp_init.o x86/synth_filter_init.o OBJS-$(CONFIG_DNXHD_ENCODER) += x86/dnxhdenc_init.o OBJS-$(CONFIG_EXR_DECODER) += x86/exrdsp_init.o -OBJS-$(CONFIG_OPUS_DECODER) += x86/opus_dsp_init.o -OBJS-$(CONFIG_OPUS_ENCODER) += x86/opus_dsp_init.o +OBJS-$(CONFIG_OPUS_DECODER) += x86/opusdsp_init.o +OBJS-$(CONFIG_OPUS_ENCODER) += x86/celt_pvq_init.o OBJS-$(CONFIG_HEVC_DECODER) += x86/hevcdsp_init.o OBJS-$(CONFIG_JPEG2000_DECODER) += x86/jpeg2000dsp_init.o +OBJS-$(CONFIG_LSCR_DECODER) += x86/pngdsp_init.o OBJS-$(CONFIG_MLP_DECODER) += x86/mlpdsp_init.o OBJS-$(CONFIG_MPEG4_DECODER) += x86/xvididct_init.o OBJS-$(CONFIG_PNG_DECODER) += x86/pngdsp_init.o @@ -127,7 +128,8 @@ X86ASM-OBJS-$(CONFIG_MDCT15) += x86/mdct15.o X86ASM-OBJS-$(CONFIG_ME_CMP) += x86/me_cmp.o X86ASM-OBJS-$(CONFIG_MPEGAUDIODSP) += x86/imdct36.o X86ASM-OBJS-$(CONFIG_MPEGVIDEOENC) += x86/mpegvideoencdsp.o -X86ASM-OBJS-$(CONFIG_OPUS_ENCODER) += x86/opus_pvq_search.o +X86ASM-OBJS-$(CONFIG_OPUS_DECODER) += x86/opusdsp.o +X86ASM-OBJS-$(CONFIG_OPUS_ENCODER) += x86/celt_pvq_search.o X86ASM-OBJS-$(CONFIG_PIXBLOCKDSP) += x86/pixblockdsp.o X86ASM-OBJS-$(CONFIG_QPELDSP) += x86/qpeldsp.o \ x86/fpel.o \ @@ -167,6 +169,7 @@ X86ASM-OBJS-$(CONFIG_HEVC_DECODER) += x86/hevc_add_res.o \ x86/hevc_sao.o \ x86/hevc_sao_10bit.o X86ASM-OBJS-$(CONFIG_JPEG2000_DECODER) += x86/jpeg2000dsp.o +X86ASM-OBJS-$(CONFIG_LSCR_DECODER) += x86/pngdsp.o X86ASM-OBJS-$(CONFIG_MLP_DECODER) += x86/mlpdsp.o X86ASM-OBJS-$(CONFIG_MPEG4_DECODER) += x86/xvididct.o X86ASM-OBJS-$(CONFIG_PNG_DECODER) += x86/pngdsp.o diff --git a/libavcodec/x86/celt_pvq_init.c b/libavcodec/x86/celt_pvq_init.c new file mode 100644 index 000000000..13724c356 --- /dev/null +++ b/libavcodec/x86/celt_pvq_init.c @@ -0,0 +1,43 @@ +/* + * Opus encoder assembly optimizations + * Copyright (C) 2017 Ivan Kalvachev + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" + +#include "libavutil/x86/cpu.h" +#include "libavcodec/opus_pvq.h" + +extern float ff_pvq_search_approx_sse2(float *X, int *y, int K, int N); +extern float ff_pvq_search_approx_sse4(float *X, int *y, int K, int N); +extern float ff_pvq_search_exact_avx (float *X, int *y, int K, int N); + +av_cold void ff_celt_pvq_init_x86(CeltPVQ *s) +{ + int cpu_flags = av_get_cpu_flags(); + + if (EXTERNAL_SSE2(cpu_flags)) + s->pvq_search = ff_pvq_search_approx_sse2; + + if (EXTERNAL_SSE4(cpu_flags)) + s->pvq_search = ff_pvq_search_approx_sse4; + + if (EXTERNAL_AVX_FAST(cpu_flags)) + s->pvq_search = ff_pvq_search_exact_avx; +} diff --git a/libavcodec/x86/celt_pvq_search.asm b/libavcodec/x86/celt_pvq_search.asm new file mode 100644 index 000000000..5c1e6d617 --- /dev/null +++ b/libavcodec/x86/celt_pvq_search.asm @@ -0,0 +1,385 @@ +;****************************************************************************** +;* SIMD optimized Opus encoder DSP function +;* +;* Copyright (C) 2017 Ivan Kalvachev +;* +;* This file is part of FFmpeg. +;* +;* FFmpeg is free software; you can redistribute it and/or +;* modify it under the terms of the GNU Lesser General Public +;* License as published by the Free Software Foundation; either +;* version 2.1 of the License, or (at your option) any later version. +;* +;* FFmpeg is distributed in the hope that it will be useful, +;* but WITHOUT ANY WARRANTY; without even the implied warranty of +;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +;* Lesser General Public License for more details. +;* +;* You should have received a copy of the GNU Lesser General Public +;* License along with FFmpeg; if not, write to the Free Software +;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +;****************************************************************************** + +%include "config.asm" +%include "libavutil/x86/x86util.asm" + +%ifdef __NASM_VER__ +%use "smartalign" +ALIGNMODE p6 +%endif + +SECTION_RODATA 64 + +const_float_abs_mask: times 8 dd 0x7fffffff +const_align_abs_edge: times 8 dd 0 + +const_float_0_5: times 8 dd 0.5 +const_float_1: times 8 dd 1.0 +const_float_sign_mask: times 8 dd 0x80000000 + +const_int32_offsets: + %rep 8 + dd $-const_int32_offsets + %endrep +SECTION .text + +; +; Setup High Register to be used +; for holding memory constants +; +; %1 - the register to be used, assmues it is >= mm8 +; %2 - name of the constant. +; +; Subsequent opcodes are going to use the constant in the form +; "addps m0, mm_const_name" and it would be turned into: +; "addps m0, [const_name]" on 32 bit arch or +; "addps m0, m8" on 64 bit arch +%macro SET_HI_REG_MM_CONSTANT 3 ; movop, reg, const_name +%if num_mmregs > 8 + %define mm_%3 %2 + %{1} %2, [%3] ; movaps m8, [const_name] +%else + %define mm_%3 [%3] +%endif +%endmacro + +; +; Set Position Independent Code +; Base address of a constant +; %1 - the register to be used, if PIC is set +; %2 - name of the constant. +; +; Subsequent opcode are going to use the base address in the form +; "movaps m0, [pic_base_constant_name+r4]" and it would be turned into +; "movaps m0, [r5 + r4]" if PIC is enabled +; "movaps m0, [constant_name + r4]" if texrel are used +%macro SET_PIC_BASE 3; reg, const_label +%ifdef PIC + %{1} %2, [%3] ; lea r5, [rip+const] + %define pic_base_%3 %2 +%else + %define pic_base_%3 %3 +%endif +%endmacro + +%macro PULSES_SEARCH 1 +; m6 Syy_norm +; m7 Sxy_norm + addps m6, mm_const_float_0_5 ; Syy_norm += 1.0/2 + pxor m1, m1 ; max_idx + xorps m3, m3 ; p_max + xor r4d, r4d +align 16 +%%distortion_search: + movd xm2, dword r4d ; movd zero extends +%ifidn %1,add + movaps m4, [tmpY + r4] ; y[i] + movaps m5, [tmpX + r4] ; X[i] + + %if USE_APPROXIMATION == 1 + xorps m0, m0 + cmpps m0, m0, m5, 4 ; m0 = (X[i] != 0.0) + %endif + + addps m4, m6 ; m4 = Syy_new = y[i] + Syy_norm + addps m5, m7 ; m5 = Sxy_new = X[i] + Sxy_norm + + %if USE_APPROXIMATION == 1 + andps m5, m0 ; if(X[i] == 0) Sxy_new = 0; Prevent aproximation error from setting pulses in array padding. + %endif + +%else + movaps m5, [tmpY + r4] ; m5 = y[i] + + xorps m0, m0 ; m0 = 0; + cmpps m0, m0, m5, 1 ; m0 = (0 p_max) + maxps m3, m5 ; m3=max(p_max,p) + ; maxps here is faster than blendvps, despite blend having lower latency. + + pand m2, m0 ; This version seems faster than sse41 pblendvb + pmaxsw m1, m2 ; SSE2 signed word, so it would work for N < 32768/4 + + add r4d, mmsize + cmp r4d, Nd + jb %%distortion_search + + por m1, mm_const_int32_offsets ; max_idx offsets per individual lane (skipped in the inner loop) + movdqa m4, m1 ; needed for the aligned y[max_idx]+=1; processing + +%if mmsize >= 32 +; Merge parallel maximums round 8 (4 vs 4) + + vextractf128 xm5, ym3, 1 ; xmm5 = ymm3[1x128] = ymm3[255..128b] + cmpps xm0, xm3, xm5, 1 ; m0 = (m3 < m5) = ( p[0x128] < p[1x128] ) + + vextracti128 xm2, ym1, 1 ; xmm2 = ymm1[1x128] = ymm1[255..128b] + BLENDVPS xm3, xm5, xm0 ; max_idx = m0 ? max_idx[1x128] : max_idx[0x128] + PBLENDVB xm1, xm2, xm0 ; p = m0 ? p[1x128] : p[0x128] +%endif + +; Merge parallel maximums round 4 (2 vs 2) + ; m3=p[3210] + movhlps xm5, xm3 ; m5=p[xx32] + cmpps xm0, xm3, xm5, 1 ; m0 = (m3 < m5) = ( p[1,0] < p[3,2] ) + + pshufd xm2, xm1, q3232 + BLENDVPS xm3, xm5, xm0 ; max_idx = m0 ? max_idx[3,2] : max_idx[1,0] + PBLENDVB xm1, xm2, xm0 ; p = m0 ? p[3,2] : p[1,0] + +; Merge parallel maximums final round (1 vs 1) + shufps xm0, xm3, xm3, q1111 ; m0 = m3[1] = p[1] + cmpss xm0, xm3, 5 ; m0 = !(m0 >= m3) = !( p[1] >= p[0] ) + + pshufd xm2, xm1, q1111 + PBLENDVB xm1, xm2, xm0 + + movd dword r4d, xm1 ; zero extends to the rest of r4q + + VBROADCASTSS m3, [tmpX + r4] + %{1}ps m7, m3 ; Sxy += X[max_idx] + + VBROADCASTSS m5, [tmpY + r4] + %{1}ps m6, m5 ; Syy += Y[max_idx] + + ; We have to update a single element in Y[i] + ; However writing 4 bytes and then doing 16 byte load in the inner loop + ; could cause a stall due to breaking write forwarding. + VPBROADCASTD m1, xm1 + pcmpeqd m1, m1, m4 ; exactly 1 element matches max_idx and this finds it + + and r4d, ~(mmsize-1) ; align address down, so the value pointed by max_idx is inside a mmsize load + movaps m5, [tmpY + r4] ; m5 = Y[y3...ym...y0] + andps m1, mm_const_float_1 ; m1 = [ 0...1.0...0] + %{1}ps m5, m1 ; m5 = Y[y3...ym...y0] +/- [0...1.0...0] + movaps [tmpY + r4], m5 ; Y[max_idx] +-= 1.0; +%endmacro + +; +; We need one more register for +; PIC relative addressing. Use this +; to count it in cglobal +; +%ifdef PIC + %define num_pic_regs 1 +%else + %define num_pic_regs 0 +%endif + +; +; Pyramid Vector Quantization Search implementation +; +; float * inX - Unaligned (SIMD) access, it will be overread, +; but extra data is masked away. +; int32 * outY - Should be aligned and padded buffer. +; It is used as temp buffer. +; uint32 K - Number of pulses to have after quantizations. +; uint32 N - Number of vector elements. Must be 0 < N < 256 +; +%macro PVQ_FAST_SEARCH 1 +cglobal pvq_search%1, 4, 5+num_pic_regs, 11, 256*4, inX, outY, K, N +%define tmpX rsp +%define tmpY outYq + + movaps m0, [const_float_abs_mask] + shl Nd, 2 ; N *= sizeof(float); also 32 bit operation zeroes the high 32 bits in 64 bit mode. + mov r4d, Nd + + neg r4d + and r4d, mmsize-1 + + SET_PIC_BASE lea, r5, const_align_abs_edge ; rip+const + movups m2, [pic_base_const_align_abs_edge + r4 - mmsize] + + add Nd, r4d ; N = align(N, mmsize) + + lea r4d, [Nd - mmsize] ; N is rounded up (aligned up) to mmsize, so r4 can't become negative here, unless N=0. + movups m1, [inXq + r4] + andps m1, m2 + movaps [tmpX + r4], m1 ; Sx = abs( X[N-1] ) + +align 16 +%%loop_abs_sum: + sub r4d, mmsize + jc %%end_loop_abs_sum + + movups m2, [inXq + r4] + andps m2, m0 + + movaps [tmpX + r4], m2 ; tmpX[i]=abs(X[i]) + addps m1, m2 ; Sx += abs(X[i]) + jmp %%loop_abs_sum + +align 16 +%%end_loop_abs_sum: + + HSUMPS m1, m2 ; m1 = Sx + + xorps m0, m0 + comiss xm0, xm1 ; + jz %%zero_input ; if (Sx==0) goto zero_input + + cvtsi2ss xm0, dword Kd ; m0 = K +%if USE_APPROXIMATION == 1 + rcpss xm1, xm1 ; m1 = approx(1/Sx) + mulss xm0, xm1 ; m0 = K*(1/Sx) +%else + divss xm0, xm1 ; b = K/Sx + ; b = K/max_x +%endif + + VBROADCASTSS m0, xm0 + + lea r4d, [Nd - mmsize] + pxor m5, m5 ; Sy ( Sum of abs( y[i]) ) + xorps m6, m6 ; Syy ( Sum of y[i]*y[i] ) + xorps m7, m7 ; Sxy ( Sum of X[i]*y[i] ) +align 16 +%%loop_guess: + movaps m1, [tmpX + r4] ; m1 = X[i] + mulps m2, m0, m1 ; m2 = res*X[i] + cvtps2dq m2, m2 ; yt = (int)lrintf( res*X[i] ) + paddd m5, m2 ; Sy += yt + cvtdq2ps m2, m2 ; yt = (float)yt + mulps m1, m2 ; m1 = X[i]*yt + movaps [tmpY + r4], m2 ; y[i] = m2 + addps m7, m1 ; Sxy += m1; + mulps m2, m2 ; m2 = yt*yt + addps m6, m2 ; Syy += m2 + + sub r4d, mmsize + jnc %%loop_guess + + HSUMPS m6, m1 ; Syy_norm + HADDD m5, m4 ; pulses + + movd dword r4d, xm5 ; zero extends to the rest of r4q + + sub Kd, r4d ; K -= pulses , also 32 bit operation zeroes high 32 bit in 64 bit mode. + jz %%finish ; K - pulses == 0 + + SET_HI_REG_MM_CONSTANT movaps, m8, const_float_0_5 + SET_HI_REG_MM_CONSTANT movaps, m9, const_float_1 + SET_HI_REG_MM_CONSTANT movdqa, m10, const_int32_offsets + ; Use Syy/2 in distortion parameter calculations. + ; Saves pre and post-caclulation to correct Y[] values. + ; Same precision, since float mantisa is normalized. + ; The SQRT approximation does differ. + HSUMPS m7, m0 ; Sxy_norm + mulps m6, mm_const_float_0_5 + + jc %%remove_pulses_loop ; K - pulses < 0 + +align 16 ; K - pulses > 0 +%%add_pulses_loop: + + PULSES_SEARCH add ; m6 Syy_norm ; m7 Sxy_norm + + sub Kd, 1 + jnz %%add_pulses_loop + + addps m6, m6 ; Syy*=2 + + jmp %%finish + +align 16 +%%remove_pulses_loop: + + PULSES_SEARCH sub ; m6 Syy_norm ; m7 Sxy_norm + + add Kd, 1 + jnz %%remove_pulses_loop + + addps m6, m6 ; Syy*=2 + +align 16 +%%finish: + lea r4d, [Nd - mmsize] + movaps m2, [const_float_sign_mask] + +align 16 +%%restore_sign_loop: + movaps m0, [tmpY + r4] ; m0 = Y[i] + movups m1, [inXq + r4] ; m1 = X[i] + andps m1, m2 ; m1 = sign(X[i]) + orps m0, m1 ; m0 = Y[i]*sign + cvtps2dq m3, m0 ; m3 = (int)m0 + movaps [outYq + r4], m3 + + sub r4d, mmsize + jnc %%restore_sign_loop +%%return: + +%if ARCH_X86_64 == 0 ; sbrdsp + movss r0m, xm6 ; return (float)Syy_norm + fld dword r0m +%else + movaps m0, m6 ; return (float)Syy_norm +%endif + + RET + +align 16 +%%zero_input: + lea r4d, [Nd - mmsize] + xorps m0, m0 +%%zero_loop: + movaps [outYq + r4], m0 + sub r4d, mmsize + jnc %%zero_loop + + movaps m6, [const_float_1] + jmp %%return +%endmacro + +; if 1, use a float op that give half precision but execute for around 3 cycles. +; On Skylake & Ryzen the division is much faster (around 11c/3), +; that makes the full precision code about 2% slower. +; Opus also does use rsqrt approximation in their intrinsics code. +%define USE_APPROXIMATION 1 + +INIT_XMM sse2 +PVQ_FAST_SEARCH _approx + +INIT_XMM sse4 +PVQ_FAST_SEARCH _approx + +%define USE_APPROXIMATION 0 + +INIT_XMM avx +PVQ_FAST_SEARCH _exact diff --git a/libavcodec/x86/h264dsp_init.c b/libavcodec/x86/h264dsp_init.c index 39f65c151..08eb7ead4 100644 --- a/libavcodec/x86/h264dsp_init.c +++ b/libavcodec/x86/h264dsp_init.c @@ -101,13 +101,13 @@ void ff_h264_loop_filter_strength_mmxext(int16_t bS[2][4][4], uint8_t nnz[40], #define LF_FUNC(DIR, TYPE, DEPTH, OPT) \ void ff_deblock_ ## DIR ## _ ## TYPE ## _ ## DEPTH ## _ ## OPT(uint8_t *pix, \ - int stride, \ + ptrdiff_t stride, \ int alpha, \ int beta, \ int8_t *tc0); #define LF_IFUNC(DIR, TYPE, DEPTH, OPT) \ void ff_deblock_ ## DIR ## _ ## TYPE ## _ ## DEPTH ## _ ## OPT(uint8_t *pix, \ - int stride, \ + ptrdiff_t stride, \ int alpha, \ int beta); diff --git a/libavcodec/x86/mdct15.asm b/libavcodec/x86/mdct15.asm index 030911253..2a2cdbd21 100644 --- a/libavcodec/x86/mdct15.asm +++ b/libavcodec/x86/mdct15.asm @@ -76,7 +76,7 @@ SECTION .text addps m%3, m%3, m0 ; Finally offset with DCs %endmacro -%macro BUTTERFLIES_DC 2 ; %1 - exptab_offset, %2 - out +%macro BUTTERFLIES_DC 1 ; %1 - exptab_offset mulps xm0, xm9, [exptabq + %1 + 16*0] mulps xm1, xm10, [exptabq + %1 + 16*1] @@ -86,10 +86,10 @@ SECTION .text addps xm0, xm1 addps xm0, xm8 - movsd [%2q], xm0 + movsd [outq], xm0 %endmacro -%macro BUTTERFLIES_AC 2 ; exptab, exptab_offset, src1, src2, src3, out (uses m0-m3) +%macro BUTTERFLIES_AC 1 ; %1 - exptab_offset mulps m0, m12, [exptabq + 64*0 + 0*mmsize + %1] mulps m1, m12, [exptabq + 64*0 + 1*mmsize + %1] mulps m2, m13, [exptabq + 64*1 + 0*mmsize + %1] @@ -104,15 +104,14 @@ SECTION .text vextractf128 xm1, m0, 1 - movlps [%2q + strideq*1], xm0 - movhps [%2q + strideq*2], xm0 - movlps [%2q + stride3q], xm1 - movhps [%2q + strideq*4], xm1 + movlps [outq + strideq*1], xm0 + movhps [outq + strideq*2], xm0 + movlps [outq + stride3q], xm1 + movhps [outq + strideq*4], xm1 %endmacro INIT_YMM avx -cglobal fft15, 4, 6, 14, out, in, exptab, stride, stride3, stride5 -%define out0q inq +cglobal fft15, 4, 5, 14, out, in, exptab, stride, stride5 shl strideq, 3 movaps xm5, [exptabq + 480 + 16*0] @@ -123,22 +122,20 @@ cglobal fft15, 4, 6, 14, out, in, exptab, stride, stride3, stride5 FFT5 8, xm9, 12 FFT5 16, xm10, 13 +%define stride3q inq lea stride3q, [strideq + strideq*2] lea stride5q, [strideq + strideq*4] - mov out0q, outq + BUTTERFLIES_DC (8*6 + 4*0)*2*4 + BUTTERFLIES_AC (8*0 + 0*0)*2*4 - BUTTERFLIES_DC (8*6 + 4*0)*2*4, out0 - lea outq, [out0q + stride5q*1] - BUTTERFLIES_DC (8*6 + 4*1)*2*4, out - lea outq, [out0q + stride5q*2] - BUTTERFLIES_DC (8*6 + 4*2)*2*4, out + add outq, stride5q + BUTTERFLIES_DC (8*6 + 4*1)*2*4 + BUTTERFLIES_AC (8*2 + 0*0)*2*4 - BUTTERFLIES_AC (8*0)*2*4, out0 - lea outq, [out0q + stride5q*1] - BUTTERFLIES_AC (8*2)*2*4, out - lea outq, [out0q + stride5q*2] - BUTTERFLIES_AC (8*4)*2*4, out + add outq, stride5q + BUTTERFLIES_DC (8*6 + 4*2)*2*4 + BUTTERFLIES_AC (8*4 + 0*0)*2*4 RET diff --git a/libavcodec/x86/mdct15_init.c b/libavcodec/x86/mdct15_init.c index 45b91b7e2..444801d9c 100644 --- a/libavcodec/x86/mdct15_init.c +++ b/libavcodec/x86/mdct15_init.c @@ -33,32 +33,35 @@ void ff_fft15_avx(FFTComplex *out, FFTComplex *in, FFTComplex *exptab, ptrdiff_t static void perm_twiddles(MDCT15Context *s) { int k; - FFTComplex exp_5point[4]; + FFTComplex tmp[30]; - FFTComplex tmp[21], tmp2[30]; - memcpy(tmp, s->exptab, sizeof(FFTComplex)*21); + /* 5-point FFT twiddles */ + s->exptab[60].re = s->exptab[60].im = s->exptab[19].re; + s->exptab[61].re = s->exptab[61].im = s->exptab[19].im; + s->exptab[62].re = s->exptab[62].im = s->exptab[20].re; + s->exptab[63].re = s->exptab[63].im = s->exptab[20].im; /* 15-point FFT twiddles */ for (k = 0; k < 5; k++) { - tmp2[6*k + 0] = tmp[k + 0]; - tmp2[6*k + 2] = tmp[k + 5]; - tmp2[6*k + 4] = tmp[k + 10]; + tmp[6*k + 0] = s->exptab[k + 0]; + tmp[6*k + 2] = s->exptab[k + 5]; + tmp[6*k + 4] = s->exptab[k + 10]; - tmp2[6*k + 1] = tmp[2 * (k + 0)]; - tmp2[6*k + 3] = tmp[2 * (k + 5)]; - tmp2[6*k + 5] = tmp[2 * k + 5 ]; + tmp[6*k + 1] = s->exptab[2 * (k + 0)]; + tmp[6*k + 3] = s->exptab[2 * (k + 5)]; + tmp[6*k + 5] = s->exptab[2 * k + 5 ]; } for (k = 0; k < 6; k++) { FFTComplex ac_exp[] = { - { tmp2[6*1 + k].re, tmp2[6*1 + k].re }, - { tmp2[6*2 + k].re, tmp2[6*2 + k].re }, - { tmp2[6*3 + k].re, tmp2[6*3 + k].re }, - { tmp2[6*4 + k].re, tmp2[6*4 + k].re }, - { tmp2[6*1 + k].im, -tmp2[6*1 + k].im }, - { tmp2[6*2 + k].im, -tmp2[6*2 + k].im }, - { tmp2[6*3 + k].im, -tmp2[6*3 + k].im }, - { tmp2[6*4 + k].im, -tmp2[6*4 + k].im }, + { tmp[6*1 + k].re, tmp[6*1 + k].re }, + { tmp[6*2 + k].re, tmp[6*2 + k].re }, + { tmp[6*3 + k].re, tmp[6*3 + k].re }, + { tmp[6*4 + k].re, tmp[6*4 + k].re }, + { tmp[6*1 + k].im, -tmp[6*1 + k].im }, + { tmp[6*2 + k].im, -tmp[6*2 + k].im }, + { tmp[6*3 + k].im, -tmp[6*3 + k].im }, + { tmp[6*4 + k].im, -tmp[6*4 + k].im }, }; memcpy(s->exptab + 8*k, ac_exp, 8*sizeof(FFTComplex)); } @@ -66,21 +69,13 @@ static void perm_twiddles(MDCT15Context *s) /* Specialcase when k = 0 */ for (k = 0; k < 3; k++) { FFTComplex dc_exp[] = { - { tmp2[2*k + 0].re, -tmp2[2*k + 0].im }, - { tmp2[2*k + 0].im, tmp2[2*k + 0].re }, - { tmp2[2*k + 1].re, -tmp2[2*k + 1].im }, - { tmp2[2*k + 1].im, tmp2[2*k + 1].re }, + { tmp[2*k + 0].re, -tmp[2*k + 0].im }, + { tmp[2*k + 0].im, tmp[2*k + 0].re }, + { tmp[2*k + 1].re, -tmp[2*k + 1].im }, + { tmp[2*k + 1].im, tmp[2*k + 1].re }, }; memcpy(s->exptab + 8*6 + 4*k, dc_exp, 4*sizeof(FFTComplex)); } - - /* 5-point FFT twiddles */ - exp_5point[0].re = exp_5point[0].im = tmp[19].re; - exp_5point[1].re = exp_5point[1].im = tmp[19].im; - exp_5point[2].re = exp_5point[2].im = tmp[20].re; - exp_5point[3].re = exp_5point[3].im = tmp[20].im; - - memcpy(s->exptab + 8*6 + 4*3, exp_5point, 4*sizeof(FFTComplex)); } av_cold void ff_mdct15_init_x86(MDCT15Context *s) diff --git a/libavcodec/x86/opusdsp.asm b/libavcodec/x86/opusdsp.asm new file mode 100644 index 000000000..f5d206a8b --- /dev/null +++ b/libavcodec/x86/opusdsp.asm @@ -0,0 +1,110 @@ +;****************************************************************************** +;* Opus SIMD functions +;* +;* This file is part of FFmpeg. +;* +;* FFmpeg is free software; you can redistribute it and/or +;* modify it under the terms of the GNU Lesser General Public +;* License as published by the Free Software Foundation; either +;* version 2.1 of the License, or (at your option) any later version. +;* +;* FFmpeg is distributed in the hope that it will be useful, +;* but WITHOUT ANY WARRANTY; without even the implied warranty of +;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +;* Lesser General Public License for more details. +;* +;* You should have received a copy of the GNU Lesser General Public +;* License along with FFmpeg; if not, write to the Free Software +;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +;****************************************************************************** + +%include "libavutil/x86/x86util.asm" + +SECTION_RODATA + + ; 0.85..^1 0.85..^2 0.85..^3 0.85..^4 +tab_st: dd 0x3f599a00, 0x3f38f671, 0x3f1d382a, 0x3f05a32f + +SECTION .text + +INIT_XMM fma3 +%if UNIX64 +cglobal opus_deemphasis, 3, 3, 8, out, in, len +%else +cglobal opus_deemphasis, 4, 4, 8, out, in, coeff, len +%endif +%if ARCH_X86_32 + VBROADCASTSS m0, coeffm +%elif WIN64 + shufps m0, m2, m2, 0 +%else + shufps m0, m0, 0 +%endif + + movaps m4, [tab_st] + VBROADCASTSS m5, m4 + shufps m6, m4, m4, q1111 + shufps m7, m4, m4, q2222 + +.loop: + movaps m1, [inq] ; x0, x1, x2, x3 + + pslldq m2, m1, 4 ; 0, x0, x1, x2 + pslldq m3, m1, 8 ; 0, 0, x0, x1 + + fmaddps m2, m2, m5, m1 ; x + c1*x[0-2] + pslldq m1, 12 ; 0, 0, 0, x0 + + fmaddps m2, m3, m6, m2 ; x + c1*x[0-2] + c2*x[0-1] + fmaddps m1, m1, m7, m2 ; x + c1*x[0-2] + c2*x[0-1] + c3*x[0] + fmaddps m0, m0, m4, m1 ; x + c1*x[0-2] + c2*x[0-1] + c3*x[0] + c*s + + movaps [outq], m0 + shufps m0, m0, q3333 ; new state + + add inq, mmsize + add outq, mmsize + sub lenq, mmsize >> 2 + jg .loop + +%if ARCH_X86_64 == 0 + movss r0m, m0 + fld dword r0m +%endif + RET + + +INIT_XMM fma3 +cglobal opus_postfilter, 4, 4, 8, data, period, gains, len + VBROADCASTSS m0, [gainsq + 0] + VBROADCASTSS m1, [gainsq + 4] + VBROADCASTSS m2, [gainsq + 8] + + lea periodq, [periodq*4 + 8] + neg periodq + + movups m3, [dataq + periodq] + mulps m3, m2 + +.loop: + movups m4, [dataq + periodq + 4] + movups m5, [dataq + periodq + 8] + movups m6, [dataq + periodq + 12] + movups m7, [dataq + periodq + 16] + + fmaddps m3, m7, m2, m3 + addps m6, m4 + + fmaddps m5, m5, m0, [dataq] + fmaddps m6, m6, m1, m3 + + addps m5, m6 + mulps m3, m7, m2 + + movaps [dataq], m5 + + add dataq, mmsize + sub lenq, mmsize >> 2 + jg .loop + + RET diff --git a/libavcodec/x86/opusdsp_init.c b/libavcodec/x86/opusdsp_init.c new file mode 100644 index 000000000..6834c4e6a --- /dev/null +++ b/libavcodec/x86/opusdsp_init.c @@ -0,0 +1,35 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" + +#include "libavutil/x86/cpu.h" +#include "libavcodec/opusdsp.h" + +void ff_opus_postfilter_fma3(float *data, int period, float *gains, int len); +float ff_opus_deemphasis_fma3(float *out, float *in, float coeff, int len); + +av_cold void ff_opus_dsp_init_x86(OpusDSP *ctx) +{ + int cpu_flags = av_get_cpu_flags(); + + if (EXTERNAL_FMA3_FAST(cpu_flags)) { + ctx->postfilter = ff_opus_postfilter_fma3; + ctx->deemphasis = ff_opus_deemphasis_fma3; + } +} diff --git a/libavcodec/x86/proresdsp_init.c b/libavcodec/x86/proresdsp_init.c index 8ca4d4d9b..bde79ab8c 100644 --- a/libavcodec/x86/proresdsp_init.c +++ b/libavcodec/x86/proresdsp_init.c @@ -35,14 +35,16 @@ av_cold void ff_proresdsp_init_x86(ProresDSPContext *dsp, AVCodecContext *avctx) #if ARCH_X86_64 int cpu_flags = av_get_cpu_flags(); - if (EXTERNAL_SSE2(cpu_flags)) { - dsp->idct_permutation_type = FF_IDCT_PERM_TRANSPOSE; - dsp->idct_put = ff_prores_idct_put_10_sse2; - } + if (avctx->bits_per_raw_sample == 10){ + if (EXTERNAL_SSE2(cpu_flags)) { + dsp->idct_permutation_type = FF_IDCT_PERM_TRANSPOSE; + dsp->idct_put = ff_prores_idct_put_10_sse2; + } - if (EXTERNAL_AVX(cpu_flags)) { - dsp->idct_permutation_type = FF_IDCT_PERM_TRANSPOSE; - dsp->idct_put = ff_prores_idct_put_10_avx; + if (EXTERNAL_AVX(cpu_flags)) { + dsp->idct_permutation_type = FF_IDCT_PERM_TRANSPOSE; + dsp->idct_put = ff_prores_idct_put_10_avx; + } } #endif /* ARCH_X86_64 */ } diff --git a/libavcodec/x86/v210-init.c b/libavcodec/x86/v210-init.c index d64dbca1a..cb9a6cbd6 100644 --- a/libavcodec/x86/v210-init.c +++ b/libavcodec/x86/v210-init.c @@ -21,9 +21,11 @@ extern void ff_v210_planar_unpack_unaligned_ssse3(const uint32_t *src, uint16_t *y, uint16_t *u, uint16_t *v, int width); extern void ff_v210_planar_unpack_unaligned_avx(const uint32_t *src, uint16_t *y, uint16_t *u, uint16_t *v, int width); +extern void ff_v210_planar_unpack_unaligned_avx2(const uint32_t *src, uint16_t *y, uint16_t *u, uint16_t *v, int width); extern void ff_v210_planar_unpack_aligned_ssse3(const uint32_t *src, uint16_t *y, uint16_t *u, uint16_t *v, int width); extern void ff_v210_planar_unpack_aligned_avx(const uint32_t *src, uint16_t *y, uint16_t *u, uint16_t *v, int width); +extern void ff_v210_planar_unpack_aligned_avx2(const uint32_t *src, uint16_t *y, uint16_t *u, uint16_t *v, int width); av_cold void ff_v210_x86_init(V210DecContext *s) { @@ -36,6 +38,9 @@ av_cold void ff_v210_x86_init(V210DecContext *s) if (HAVE_AVX_EXTERNAL && cpu_flags & AV_CPU_FLAG_AVX) s->unpack_frame = ff_v210_planar_unpack_aligned_avx; + + if (HAVE_AVX2_EXTERNAL && cpu_flags & AV_CPU_FLAG_AVX2) + s->unpack_frame = ff_v210_planar_unpack_aligned_avx2; } else { if (cpu_flags & AV_CPU_FLAG_SSSE3) @@ -43,6 +48,9 @@ av_cold void ff_v210_x86_init(V210DecContext *s) if (HAVE_AVX_EXTERNAL && cpu_flags & AV_CPU_FLAG_AVX) s->unpack_frame = ff_v210_planar_unpack_unaligned_avx; + + if (HAVE_AVX2_EXTERNAL && cpu_flags & AV_CPU_FLAG_AVX2) + s->unpack_frame = ff_v210_planar_unpack_unaligned_avx2; } #endif } diff --git a/libavcodec/x86/v210.asm b/libavcodec/x86/v210.asm index c24c765e5..3b9e0761d 100644 --- a/libavcodec/x86/v210.asm +++ b/libavcodec/x86/v210.asm @@ -22,9 +22,14 @@ %include "libavutil/x86/x86util.asm" -SECTION_RODATA +SECTION_RODATA 32 + +; for AVX2 version only +v210_luma_permute: dd 0,1,2,4,5,6,7,7 ; 32-byte alignment required +v210_chroma_shuf2: db 0,1,2,3,4,5,8,9,10,11,12,13,-1,-1,-1,-1 +v210_luma_shuf_avx2: db 0,1,4,5,6,7,8,9,12,13,14,15,-1,-1,-1,-1 +v210_chroma_shuf_avx2: db 0,1,4,5,10,11,-1,-1,2,3,8,9,12,13,-1,-1 -v210_mask: times 4 dd 0x3ff v210_mult: dw 64,4,64,4,64,4,64,4 v210_luma_shuf: db 8,9,0,1,2,3,12,13,4,5,6,7,-1,-1,-1,-1 v210_chroma_shuf: db 0,1,8,9,6,7,-1,-1,2,3,4,5,12,13,-1,-1 @@ -34,40 +39,64 @@ SECTION .text %macro v210_planar_unpack 1 ; v210_planar_unpack(const uint32_t *src, uint16_t *y, uint16_t *u, uint16_t *v, int width) -cglobal v210_planar_unpack_%1, 5, 5, 7 - movsxdifnidn r4, r4d - lea r1, [r1+2*r4] - add r2, r4 - add r3, r4 - neg r4 +cglobal v210_planar_unpack_%1, 5, 5, 6 + 2 * cpuflag(avx2), src, y, u, v, w + movsxdifnidn wq, wd + lea yq, [yq+2*wq] + add uq, wq + add vq, wq + neg wq + + VBROADCASTI128 m3, [v210_mult] + +%if cpuflag(avx2) + VBROADCASTI128 m4, [v210_luma_shuf_avx2] + VBROADCASTI128 m5, [v210_chroma_shuf_avx2] + mova m6, [v210_luma_permute] + VBROADCASTI128 m7, [v210_chroma_shuf2] +%else + VBROADCASTI128 m4, [v210_luma_shuf] + VBROADCASTI128 m5, [v210_chroma_shuf] +%endif - mova m3, [v210_mult] - mova m4, [v210_mask] - mova m5, [v210_luma_shuf] - mova m6, [v210_chroma_shuf] .loop: %ifidn %1, unaligned - movu m0, [r0] + movu m0, [srcq] ; yB v5 yA u5 y9 v4 y8 u4 y7 v3 y6 u3 y5 v2 y4 u2 y3 v1 y2 u1 y1 v0 y0 u0 %else - mova m0, [r0] + mova m0, [srcq] %endif pmullw m1, m0, m3 - psrld m0, 10 - psrlw m1, 6 ; u0 v0 y1 y2 v1 u2 y4 y5 - pand m0, m4 ; y0 __ u1 __ y3 __ v2 __ + pslld m0, 12 + psrlw m1, 6 ; yB yA u5 v4 y8 y7 v3 u3 y5 y4 u2 v1 y2 y1 v0 u0 + psrld m0, 22 ; 00 v5 00 y9 00 u4 00 y6 00 v2 00 y3 00 u1 00 y0 - shufps m2, m1, m0, 0x8d ; y1 y2 y4 y5 y0 __ y3 __ - pshufb m2, m5 ; y0 y1 y2 y3 y4 y5 __ __ - movu [r1+2*r4], m2 +%if cpuflag(avx2) + vpblendd m2, m1, m0, 0x55 ; yB yA 00 y9 y8 y7 00 y6 y5 y4 00 y3 y2 y1 00 y0 + pshufb m2, m4 ; 00 00 yB yA y9 y8 y7 y6 00 00 y5 y4 y3 y2 y1 y0 + vpermd m2, m6, m2 ; 00 00 00 00 yB yA y9 y8 y7 y6 y5 y4 y3 y2 y1 y0 + movu [yq+2*wq], m2 - shufps m1, m0, 0xd8 ; u0 v0 v1 u2 u1 __ v2 __ - pshufb m1, m6 ; u0 u1 u2 __ v0 v1 v2 __ - movq [r2+r4], m1 - movhps [r3+r4], m1 + vpblendd m1, m1, m0, 0xaa ; 00 v5 u5 v4 00 u4 v3 u3 00 v2 u2 v1 00 u1 v0 u0 + pshufb m1, m5 ; 00 v5 v4 v3 00 u5 u4 u3 00 v2 v1 v0 00 u2 u1 u0 + vpermq m1, m1, 0xd8 ; 00 v5 v4 v3 00 v2 v1 v0 00 u5 u4 u3 00 u2 u1 u0 + pshufb m1, m7 ; 00 00 v5 v4 v3 v2 v1 v0 00 00 u5 u4 u3 u2 u1 u0 - add r0, mmsize - add r4, 6 + movu [uq+wq], xm1 + vextracti128 [vq+wq], m1, 1 +%else + shufps m2, m1, m0, 0x8d ; 00 y9 00 y6 yB yA y8 y7 00 y3 00 y0 y5 y4 y2 y1 + pshufb m2, m4 ; 00 00 yB yA y9 y8 y7 y6 00 00 y5 y4 y3 y2 y1 y0 + movu [yq+2*wq], m2 + + shufps m1, m0, 0xd8 ; 00 v5 00 u4 u5 v4 v3 u3 00 v2 00 u1 u2 v1 v0 u0 + pshufb m1, m5 ; 00 v5 v4 v3 00 u5 u4 u3 00 v2 v1 v0 00 u2 u1 u0 + + movq [uq+wq], m1 + movhps [vq+wq], m1 +%endif + + add srcq, mmsize + add wq, (mmsize*3)/8 jl .loop REP_RET @@ -81,6 +110,11 @@ INIT_XMM avx v210_planar_unpack unaligned %endif +%if HAVE_AVX2_EXTERNAL +INIT_YMM avx2 +v210_planar_unpack unaligned +%endif + INIT_XMM ssse3 v210_planar_unpack aligned @@ -88,3 +122,8 @@ v210_planar_unpack aligned INIT_XMM avx v210_planar_unpack aligned %endif + +%if HAVE_AVX2_EXTERNAL +INIT_YMM avx2 +v210_planar_unpack aligned +%endif diff --git a/libavcodec/xfacedec.c b/libavcodec/xfacedec.c index d045cb6ef..ab4c0823f 100644 --- a/libavcodec/xfacedec.c +++ b/libavcodec/xfacedec.c @@ -123,7 +123,7 @@ static int xface_decode_frame(AVCodecContext *avctx, if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) return ret; - for (i = 0, k = 0; avpkt->data[i] && i < avpkt->size; i++) { + for (i = 0, k = 0; i < avpkt->size && avpkt->data[i]; i++) { c = avpkt->data[i]; /* ignore invalid digits */ diff --git a/libavcodec/xpmdec.c b/libavcodec/xpmdec.c index 03172e4aa..922dfc0f6 100644 --- a/libavcodec/xpmdec.c +++ b/libavcodec/xpmdec.c @@ -26,6 +26,10 @@ #include "avcodec.h" #include "internal.h" +#define MIN_ELEMENT ' ' +#define MAX_ELEMENT 0xfe +#define NB_ELEMENTS (MAX_ELEMENT - MIN_ELEMENT + 1) + typedef struct XPMContext { uint32_t *pixels; int pixels_size; @@ -290,10 +294,10 @@ static int ascii2index(const uint8_t *cpixel, int cpp) int n = 0, m = 1, i; for (i = 0; i < cpp; i++) { - if (*p < ' ' || *p > '~') + if (*p < MIN_ELEMENT || *p > MAX_ELEMENT) return AVERROR_INVALIDDATA; - n += (*p++ - ' ') * m; - m *= 95; + n += (*p++ - MIN_ELEMENT) * m; + m *= NB_ELEMENTS; } return n; } @@ -307,6 +311,7 @@ static int xpm_decode_frame(AVCodecContext *avctx, void *data, int ncolors, cpp, ret, i, j; int64_t size; uint32_t *dst; + int width, height; avctx->pix_fmt = AV_PIX_FMT_BGRA; @@ -328,12 +333,12 @@ static int xpm_decode_frame(AVCodecContext *avctx, void *data, ptr += mod_strcspn(ptr, "\""); if (sscanf(ptr, "\"%u %u %u %u\",", - &avctx->width, &avctx->height, &ncolors, &cpp) != 4) { + &width, &height, &ncolors, &cpp) != 4) { av_log(avctx, AV_LOG_ERROR, "missing image parameters\n"); return AVERROR_INVALIDDATA; } - if ((ret = ff_set_dimensions(avctx, avctx->width, avctx->height)) < 0) + if ((ret = ff_set_dimensions(avctx, width, height)) < 0) return ret; if ((ret = ff_get_buffer(avctx, p, 0)) < 0) @@ -346,7 +351,7 @@ static int xpm_decode_frame(AVCodecContext *avctx, void *data, size = 1; for (i = 0; i < cpp; i++) - size *= 95; + size *= NB_ELEMENTS; if (ncolors <= 0 || ncolors > size) { av_log(avctx, AV_LOG_ERROR, "invalid number of colors: %d\n", ncolors); diff --git a/libavcodec/zmbv.c b/libavcodec/zmbv.c index 6ef549dff..99e735cfd 100644 --- a/libavcodec/zmbv.c +++ b/libavcodec/zmbv.c @@ -57,6 +57,7 @@ typedef struct ZmbvContext { AVCodecContext *avctx; int bpp; + int alloc_bpp; unsigned int decomp_size; uint8_t* decomp_buf; uint8_t pal[768]; @@ -120,6 +121,8 @@ static int zmbv_decode_xor_8(ZmbvContext *c) for (j = 0; j < bh2; j++) { if (my + j < 0 || my + j >= c->height) { memset(out, 0, bw2); + } else if (mx >= 0 && mx + bw2 <= c->width){ + memcpy(out, tprev, sizeof(*out) * bw2); } else { for (i = 0; i < bw2; i++) { if (mx + i < 0 || mx + i >= c->width) @@ -192,6 +195,8 @@ static int zmbv_decode_xor_16(ZmbvContext *c) for (j = 0; j < bh2; j++) { if (my + j < 0 || my + j >= c->height) { memset(out, 0, bw2 * 2); + } else if (mx >= 0 && mx + bw2 <= c->width){ + memcpy(out, tprev, sizeof(*out) * bw2); } else { for (i = 0; i < bw2; i++) { if (mx + i < 0 || mx + i >= c->width) @@ -269,6 +274,8 @@ static int zmbv_decode_xor_24(ZmbvContext *c) for (j = 0; j < bh2; j++) { if (my + j < 0 || my + j >= c->height) { memset(out, 0, bw2 * 3); + } else if (mx >= 0 && mx + bw2 <= c->width){ + memcpy(out, tprev, 3 * bw2); } else { for (i = 0; i < bw2; i++){ if (mx + i < 0 || mx + i >= c->width) { @@ -302,7 +309,7 @@ static int zmbv_decode_xor_24(ZmbvContext *c) prev += stride * c->bh; } if (src - c->decomp_buf != c->decomp_len) - av_log(c->avctx, AV_LOG_ERROR, "Used %i of %i bytes\n", + av_log(c->avctx, AV_LOG_ERROR, "Used %"PTRDIFF_SPECIFIER" of %i bytes\n", src-c->decomp_buf, c->decomp_len); return 0; } @@ -350,6 +357,8 @@ static int zmbv_decode_xor_32(ZmbvContext *c) for (j = 0; j < bh2; j++) { if (my + j < 0 || my + j >= c->height) { memset(out, 0, bw2 * 4); + } else if (mx >= 0 && mx + bw2 <= c->width){ + memcpy(out, tprev, sizeof(*out) * bw2); } else { for (i = 0; i < bw2; i++){ if (mx + i < 0 || mx + i >= c->width) @@ -472,7 +481,7 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, AVPac c->bpp = 24; decode_intra = zmbv_decode_intra; c->decode_xor = zmbv_decode_xor_24; - avctx->pix_fmt = AV_PIX_FMT_RGB24; + avctx->pix_fmt = AV_PIX_FMT_BGR24; c->stride = c->width * 3; break; #endif //ZMBV_ENABLE_24BPP @@ -495,12 +504,17 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, AVPac return AVERROR_UNKNOWN; } - c->cur = av_realloc_f(c->cur, avctx->width * avctx->height, (c->bpp / 8)); - c->prev = av_realloc_f(c->prev, avctx->width * avctx->height, (c->bpp / 8)); + if (c->alloc_bpp < c->bpp) { + c->cur = av_realloc_f(c->cur, avctx->width * avctx->height, (c->bpp / 8)); + c->prev = av_realloc_f(c->prev, avctx->width * avctx->height, (c->bpp / 8)); + c->alloc_bpp = c->bpp; + } c->bx = (c->width + c->bw - 1) / c->bw; c->by = (c->height+ c->bh - 1) / c->bh; - if (!c->cur || !c->prev) + if (!c->cur || !c->prev) { + c->alloc_bpp = 0; return AVERROR(ENOMEM); + } memset(c->cur, 0, avctx->width * avctx->height * (c->bpp / 8)); memset(c->prev, 0, avctx->width * avctx->height * (c->bpp / 8)); c->decode_intra= decode_intra; @@ -614,12 +628,11 @@ static av_cold int decode_init(AVCodecContext *avctx) c->decomp_size = (avctx->width + 255) * 4 * (avctx->height + 64); /* Allocate decompression buffer */ - if (c->decomp_size) { - if (!(c->decomp_buf = av_mallocz(c->decomp_size))) { - av_log(avctx, AV_LOG_ERROR, - "Can't allocate decompression buffer.\n"); - return AVERROR(ENOMEM); - } + c->decomp_buf = av_mallocz(c->decomp_size); + if (!c->decomp_buf) { + av_log(avctx, AV_LOG_ERROR, + "Can't allocate decompression buffer.\n"); + return AVERROR(ENOMEM); } c->zstream.zalloc = Z_NULL; @@ -657,4 +670,5 @@ AVCodec ff_zmbv_decoder = { .close = decode_end, .decode = decode_frame, .capabilities = AV_CODEC_CAP_DR1, + .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, }; diff --git a/libavcodec/zmbvenc.c b/libavcodec/zmbvenc.c index 4d9147657..48871758e 100644 --- a/libavcodec/zmbvenc.c +++ b/libavcodec/zmbvenc.c @@ -34,34 +34,53 @@ #include +/* Frame header flags */ #define ZMBV_KEYFRAME 1 #define ZMBV_DELTAPAL 2 +/* Motion block width/height (maximum allowed value is 255) + * Note: histogram datatype in block_cmp() must be big enough to hold values + * up to (4 * ZMBV_BLOCK * ZMBV_BLOCK) + */ #define ZMBV_BLOCK 16 +/* Keyframe header format values */ +enum ZmbvFormat { + ZMBV_FMT_NONE = 0, + ZMBV_FMT_1BPP = 1, + ZMBV_FMT_2BPP = 2, + ZMBV_FMT_4BPP = 3, + ZMBV_FMT_8BPP = 4, + ZMBV_FMT_15BPP = 5, + ZMBV_FMT_16BPP = 6, + ZMBV_FMT_24BPP = 7, + ZMBV_FMT_32BPP = 8 +}; + /** * Encoder context */ typedef struct ZmbvEncContext { AVCodecContext *avctx; - int range; + int lrange, urange; uint8_t *comp_buf, *work_buf; uint8_t pal[768]; uint32_t pal2[256]; //for quick comparisons - uint8_t *prev; + uint8_t *prev, *prev_buf; int pstride; int comp_size; int keyint, curfrm; + int bypp; + enum ZmbvFormat fmt; z_stream zstream; - int score_tab[256]; + int score_tab[ZMBV_BLOCK * ZMBV_BLOCK * 4 + 1]; } ZmbvEncContext; /** Block comparing function * XXX should be optimized and moved to DSPContext - * TODO handle out of edge ME */ static inline int block_cmp(ZmbvEncContext *c, uint8_t *src, int stride, uint8_t *src2, int stride2, int bw, int bh, @@ -69,20 +88,27 @@ static inline int block_cmp(ZmbvEncContext *c, uint8_t *src, int stride, { int sum = 0; int i, j; - uint8_t histogram[256] = {0}; + uint16_t histogram[256] = {0}; + int bw_bytes = bw * c->bypp; - *xored = 0; + /* Build frequency histogram of byte values for src[] ^ src2[] */ for(j = 0; j < bh; j++){ - for(i = 0; i < bw; i++){ + for(i = 0; i < bw_bytes; i++){ int t = src[i] ^ src2[i]; histogram[t]++; - *xored |= t; } src += stride; src2 += stride2; } - for(i = 1; i < 256; i++) + /* If not all the xored values were 0, then the blocks are different */ + *xored = (histogram[0] < bw_bytes * bh); + + /* Exit early if blocks are equal */ + if (!*xored) return 0; + + /* Sum the entropy of all values */ + for(i = 0; i < 256; i++) sum += c->score_tab[histogram[i]]; return sum; @@ -94,23 +120,42 @@ static inline int block_cmp(ZmbvEncContext *c, uint8_t *src, int stride, static int zmbv_me(ZmbvEncContext *c, uint8_t *src, int sstride, uint8_t *prev, int pstride, int x, int y, int *mx, int *my, int *xored) { - int dx, dy, tx, ty, tv, bv, bw, bh; + int dx, dy, txored, tv, bv, bw, bh; + int mx0, my0; - *mx = *my = 0; + mx0 = *mx; + my0 = *my; bw = FFMIN(ZMBV_BLOCK, c->avctx->width - x); bh = FFMIN(ZMBV_BLOCK, c->avctx->height - y); + + /* Try (0,0) */ bv = block_cmp(c, src, sstride, prev, pstride, bw, bh, xored); + *mx = *my = 0; if(!bv) return 0; - for(ty = FFMAX(y - c->range, 0); ty < FFMIN(y + c->range, c->avctx->height - bh); ty++){ - for(tx = FFMAX(x - c->range, 0); tx < FFMIN(x + c->range, c->avctx->width - bw); tx++){ - if(tx == x && ty == y) continue; // we already tested this block - dx = tx - x; - dy = ty - y; - tv = block_cmp(c, src, sstride, prev + dx + dy * pstride, pstride, bw, bh, xored); + + /* Try previous block's MV (if not 0,0) */ + if (mx0 || my0){ + tv = block_cmp(c, src, sstride, prev + mx0 * c->bypp + my0 * pstride, pstride, bw, bh, &txored); + if(tv < bv){ + bv = tv; + *mx = mx0; + *my = my0; + *xored = txored; + if(!bv) return 0; + } + } + + /* Try other MVs from top-to-bottom, left-to-right */ + for(dy = -c->lrange; dy <= c->urange; dy++){ + for(dx = -c->lrange; dx <= c->urange; dx++){ + if(!dx && !dy) continue; // we already tested this block + if(dx == mx0 && dy == my0) continue; // this one too + tv = block_cmp(c, src, sstride, prev + dx * c->bypp + dy * pstride, pstride, bw, bh, &txored); if(tv < bv){ bv = tv; *mx = dx; *my = dy; + *xored = txored; if(!bv) return 0; } } @@ -141,9 +186,10 @@ FF_DISABLE_DEPRECATION_WARNINGS avctx->coded_frame->key_frame = keyframe; FF_ENABLE_DEPRECATION_WARNINGS #endif - chpal = !keyframe && memcmp(p->data[1], c->pal2, 1024); - palptr = (uint32_t*)p->data[1]; + palptr = (avctx->pix_fmt == AV_PIX_FMT_PAL8) ? (uint32_t *)p->data[1] : NULL; + chpal = !keyframe && palptr && memcmp(palptr, c->pal2, 1024); + src = p->data[0]; prev = c->prev; if(chpal){ @@ -157,25 +203,27 @@ FF_ENABLE_DEPRECATION_WARNINGS c->pal[i * 3 + 1] = tpal[1]; c->pal[i * 3 + 2] = tpal[2]; } - memcpy(c->pal2, p->data[1], 1024); + memcpy(c->pal2, palptr, 1024); } if(keyframe){ - for(i = 0; i < 256; i++){ - AV_WB24(c->pal+(i*3), palptr[i]); + if (palptr){ + for(i = 0; i < 256; i++){ + AV_WB24(c->pal+(i*3), palptr[i]); + } + memcpy(c->work_buf, c->pal, 768); + memcpy(c->pal2, palptr, 1024); + work_size = 768; } - memcpy(c->work_buf, c->pal, 768); - memcpy(c->pal2, p->data[1], 1024); - work_size = 768; for(i = 0; i < avctx->height; i++){ - memcpy(c->work_buf + work_size, src, avctx->width); + memcpy(c->work_buf + work_size, src, avctx->width * c->bypp); src += p->linesize[0]; - work_size += avctx->width; + work_size += avctx->width * c->bypp; } }else{ int x, y, bh2, bw2, xored; uint8_t *tsrc, *tprev; uint8_t *mv; - int mx, my; + int mx = 0, my = 0; bw = (avctx->width + ZMBV_BLOCK - 1) / ZMBV_BLOCK; bh = (avctx->height + ZMBV_BLOCK - 1) / ZMBV_BLOCK; @@ -188,16 +236,16 @@ FF_ENABLE_DEPRECATION_WARNINGS for(x = 0; x < avctx->width; x += ZMBV_BLOCK, mv += 2) { bw2 = FFMIN(avctx->width - x, ZMBV_BLOCK); - tsrc = src + x; - tprev = prev + x; + tsrc = src + x * c->bypp; + tprev = prev + x * c->bypp; zmbv_me(c, tsrc, p->linesize[0], tprev, c->pstride, x, y, &mx, &my, &xored); mv[0] = (mx << 1) | !!xored; mv[1] = my << 1; - tprev += mx + my * c->pstride; + tprev += mx * c->bypp + my * c->pstride; if(xored){ for(j = 0; j < bh2; j++){ - for(i = 0; i < bw2; i++) + for(i = 0; i < bw2 * c->bypp; i++) c->work_buf[work_size++] = tsrc[i] ^ tprev[i]; tsrc += p->linesize[0]; tprev += c->pstride; @@ -212,7 +260,7 @@ FF_ENABLE_DEPRECATION_WARNINGS src = p->data[0]; prev = c->prev; for(i = 0; i < avctx->height; i++){ - memcpy(prev, src, avctx->width); + memcpy(prev, src, avctx->width * c->bypp); prev += c->pstride; src += p->linesize[0]; } @@ -243,7 +291,7 @@ FF_ENABLE_DEPRECATION_WARNINGS *buf++ = 0; // hi ver *buf++ = 1; // lo ver *buf++ = 1; // comp - *buf++ = 4; // format - 8bpp + *buf++ = c->fmt; // format *buf++ = ZMBV_BLOCK; // block width *buf++ = ZMBV_BLOCK; // block height } @@ -263,7 +311,7 @@ static av_cold int encode_end(AVCodecContext *avctx) av_freep(&c->work_buf); deflateEnd(&c->zstream); - av_freep(&c->prev); + av_freep(&c->prev_buf); return 0; } @@ -277,17 +325,54 @@ static av_cold int encode_init(AVCodecContext *avctx) int zret; // Zlib return code int i; int lvl = 9; + int prev_size, prev_offset; - for(i=1; i<256; i++) - c->score_tab[i] = -i * log2(i / (double)(ZMBV_BLOCK * ZMBV_BLOCK)) * 256; + switch (avctx->pix_fmt) { + case AV_PIX_FMT_PAL8: + c->fmt = ZMBV_FMT_8BPP; + c->bypp = 1; + break; + case AV_PIX_FMT_RGB555LE: + c->fmt = ZMBV_FMT_15BPP; + c->bypp = 2; + break; + case AV_PIX_FMT_RGB565LE: + c->fmt = ZMBV_FMT_16BPP; + c->bypp = 2; + break; +#ifdef ZMBV_ENABLE_24BPP + case AV_PIX_FMT_BGR24: + c->fmt = ZMBV_FMT_24BPP; + c->bypp = 3; + break; +#endif //ZMBV_ENABLE_24BPP + case AV_PIX_FMT_BGR0: + c->fmt = ZMBV_FMT_32BPP; + c->bypp = 4; + break; + default: + av_log(avctx, AV_LOG_INFO, "unsupported pixel format\n"); + return AVERROR(EINVAL); + } + + /* Entropy-based score tables for comparing blocks. + * Suitable for blocks up to (ZMBV_BLOCK * ZMBV_BLOCK) bytes. + * Scores are nonnegative, lower is better. + */ + for(i = 1; i <= ZMBV_BLOCK * ZMBV_BLOCK * c->bypp; i++) + c->score_tab[i] = -i * log2(i / (double)(ZMBV_BLOCK * ZMBV_BLOCK * c->bypp)) * 256; c->avctx = avctx; c->curfrm = 0; c->keyint = avctx->keyint_min; - c->range = 8; - if(avctx->me_range > 0) - c->range = FFMIN(avctx->me_range, 127); + + /* Motion estimation range: maximum distance is -64..63 */ + c->lrange = c->urange = 8; + if(avctx->me_range > 0){ + c->lrange = FFMIN(avctx->me_range, 64); + c->urange = FFMIN(avctx->me_range, 63); + } if(avctx->compression_level >= 0) lvl = avctx->compression_level; @@ -298,7 +383,7 @@ static av_cold int encode_init(AVCodecContext *avctx) // Needed if zlib unused or init aborted before deflateInit memset(&c->zstream, 0, sizeof(z_stream)); - c->comp_size = avctx->width * avctx->height + 1024 + + c->comp_size = avctx->width * c->bypp * avctx->height + 1024 + ((avctx->width + ZMBV_BLOCK - 1) / ZMBV_BLOCK) * ((avctx->height + ZMBV_BLOCK - 1) / ZMBV_BLOCK) * 2 + 4; if (!(c->work_buf = av_malloc(c->comp_size))) { av_log(avctx, AV_LOG_ERROR, "Can't allocate work buffer.\n"); @@ -313,11 +398,23 @@ static av_cold int encode_init(AVCodecContext *avctx) av_log(avctx, AV_LOG_ERROR, "Can't allocate compression buffer.\n"); return AVERROR(ENOMEM); } - c->pstride = FFALIGN(avctx->width, 16); - if (!(c->prev = av_malloc(c->pstride * avctx->height))) { + + /* Allocate prev buffer - pad around the image to allow out-of-edge ME: + * - The image should be padded with `lrange` rows before and `urange` rows + * after. + * - The stride should be padded with `lrange` pixels, then rounded up to a + * multiple of 16 bytes. + * - The first row should also be padded with `lrange` pixels before, then + * aligned up to a multiple of 16 bytes. + */ + c->pstride = FFALIGN((avctx->width + c->lrange) * c->bypp, 16); + prev_size = FFALIGN(c->lrange * c->bypp, 16) + c->pstride * (c->lrange + avctx->height + c->urange); + prev_offset = FFALIGN(c->lrange, 16) + c->pstride * c->lrange; + if (!(c->prev_buf = av_mallocz(prev_size))) { av_log(avctx, AV_LOG_ERROR, "Can't allocate picture.\n"); return AVERROR(ENOMEM); } + c->prev = c->prev_buf + prev_offset; c->zstream.zalloc = Z_NULL; c->zstream.zfree = Z_NULL; @@ -340,5 +437,12 @@ AVCodec ff_zmbv_encoder = { .init = encode_init, .encode2 = encode_frame, .close = encode_end, - .pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_PAL8, AV_PIX_FMT_NONE }, + .pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_PAL8, + AV_PIX_FMT_RGB555LE, + AV_PIX_FMT_RGB565LE, +#ifdef ZMBV_ENABLE_24BPP + AV_PIX_FMT_BGR24, +#endif //ZMBV_ENABLE_24BPP + AV_PIX_FMT_BGR0, + AV_PIX_FMT_NONE }, }; diff --git a/libavdevice/Makefile b/libavdevice/Makefile index f11a6f2a8..6ea62b914 100644 --- a/libavdevice/Makefile +++ b/libavdevice/Makefile @@ -20,8 +20,6 @@ OBJS-$(CONFIG_BKTR_INDEV) += bktr.o OBJS-$(CONFIG_CACA_OUTDEV) += caca.o OBJS-$(CONFIG_DECKLINK_OUTDEV) += decklink_enc.o decklink_enc_c.o decklink_common.o OBJS-$(CONFIG_DECKLINK_INDEV) += decklink_dec.o decklink_dec_c.o decklink_common.o -OBJS-$(CONFIG_LIBNDI_NEWTEK_OUTDEV) += libndi_newtek_enc.o -OBJS-$(CONFIG_LIBNDI_NEWTEK_INDEV) += libndi_newtek_dec.o OBJS-$(CONFIG_DSHOW_INDEV) += dshow_crossbar.o dshow.o dshow_enummediatypes.o \ dshow_enumpins.o dshow_filter.o \ dshow_pin.o dshow_common.o @@ -61,8 +59,6 @@ SLIBOBJS-$(HAVE_GNU_WINDRES) += avdeviceres.o SKIPHEADERS += decklink_common.h SKIPHEADERS-$(CONFIG_DECKLINK) += decklink_enc.h decklink_dec.h \ decklink_common_c.h -SKIPHEADERS-$(CONFIG_LIBNDI_NEWTEK_INDEV) += libndi_newtek_common.h -SKIPHEADERS-$(CONFIG_LIBNDI_NEWTEK_OUTDEV) += libndi_newtek_common.h SKIPHEADERS-$(CONFIG_DSHOW_INDEV) += dshow_capture.h SKIPHEADERS-$(CONFIG_FBDEV_INDEV) += fbdev_common.h SKIPHEADERS-$(CONFIG_FBDEV_OUTDEV) += fbdev_common.h diff --git a/libavdevice/alldevices.c b/libavdevice/alldevices.c index adde749ce..863343325 100644 --- a/libavdevice/alldevices.c +++ b/libavdevice/alldevices.c @@ -32,8 +32,6 @@ extern AVInputFormat ff_bktr_demuxer; extern AVOutputFormat ff_caca_muxer; extern AVInputFormat ff_decklink_demuxer; extern AVOutputFormat ff_decklink_muxer; -extern AVInputFormat ff_libndi_newtek_demuxer; -extern AVOutputFormat ff_libndi_newtek_muxer; extern AVInputFormat ff_dshow_demuxer; extern AVInputFormat ff_fbdev_demuxer; extern AVOutputFormat ff_fbdev_muxer; diff --git a/libavdevice/alsa.c b/libavdevice/alsa.c index 1b21beb6d..117b2ea14 100644 --- a/libavdevice/alsa.c +++ b/libavdevice/alsa.c @@ -300,8 +300,10 @@ av_cold int ff_alsa_close(AVFormatContext *s1) { AlsaData *s = s1->priv_data; - snd_pcm_nonblock(s->h, 0); - snd_pcm_drain(s->h); + if (snd_pcm_stream(s->h) == SND_PCM_STREAM_PLAYBACK) { + snd_pcm_nonblock(s->h, 0); + snd_pcm_drain(s->h); + } av_freep(&s->reorder_buf); if (CONFIG_ALSA_INDEV) ff_timefilter_destroy(s->timefilter); diff --git a/libavdevice/avfoundation.m b/libavdevice/avfoundation.m index a540f6a07..08deecfee 100644 --- a/libavdevice/avfoundation.m +++ b/libavdevice/avfoundation.m @@ -35,6 +35,7 @@ #include "libavutil/internal.h" #include "libavutil/parseutils.h" #include "libavutil/time.h" +#include "libavutil/imgutils.h" #include "avdevice.h" static const int avf_time_base = 1000000; @@ -96,6 +97,8 @@ typedef struct int capture_cursor; int capture_mouse_clicks; + int capture_raw_data; + int video_is_muxed; int list_devices; int video_device_index; @@ -290,51 +293,65 @@ static int configure_video_device(AVFormatContext *s, AVCaptureDevice *video_dev NSObject *selected_range = nil; NSObject *selected_format = nil; - for (format in [video_device valueForKey:@"formats"]) { - CMFormatDescriptionRef formatDescription; - CMVideoDimensions dimensions; + // try to configure format by formats list + // might raise an exception if no format list is given + // (then fallback to default, no configuration) + @try { + for (format in [video_device valueForKey:@"formats"]) { + CMFormatDescriptionRef formatDescription; + CMVideoDimensions dimensions; - formatDescription = (CMFormatDescriptionRef) [format performSelector:@selector(formatDescription)]; - dimensions = CMVideoFormatDescriptionGetDimensions(formatDescription); + formatDescription = (CMFormatDescriptionRef) [format performSelector:@selector(formatDescription)]; + dimensions = CMVideoFormatDescriptionGetDimensions(formatDescription); - if ((ctx->width == 0 && ctx->height == 0) || - (dimensions.width == ctx->width && dimensions.height == ctx->height)) { + if ((ctx->width == 0 && ctx->height == 0) || + (dimensions.width == ctx->width && dimensions.height == ctx->height)) { - selected_format = format; + selected_format = format; - for (range in [format valueForKey:@"videoSupportedFrameRateRanges"]) { - double max_framerate; + for (range in [format valueForKey:@"videoSupportedFrameRateRanges"]) { + double max_framerate; - [[range valueForKey:@"maxFrameRate"] getValue:&max_framerate]; - if (fabs (framerate - max_framerate) < 0.01) { - selected_range = range; - break; + [[range valueForKey:@"maxFrameRate"] getValue:&max_framerate]; + if (fabs (framerate - max_framerate) < 0.01) { + selected_range = range; + break; + } } } } - } - if (!selected_format) { - av_log(s, AV_LOG_ERROR, "Selected video size (%dx%d) is not supported by the device\n", - ctx->width, ctx->height); - goto unsupported_format; - } + if (!selected_format) { + av_log(s, AV_LOG_ERROR, "Selected video size (%dx%d) is not supported by the device.\n", + ctx->width, ctx->height); + goto unsupported_format; + } - if (!selected_range) { - av_log(s, AV_LOG_ERROR, "Selected framerate (%f) is not supported by the device\n", - framerate); - goto unsupported_format; - } + if (!selected_range) { + av_log(s, AV_LOG_ERROR, "Selected framerate (%f) is not supported by the device.\n", + framerate); + if (ctx->video_is_muxed) { + av_log(s, AV_LOG_ERROR, "Falling back to default.\n"); + } else { + goto unsupported_format; + } + } - if ([video_device lockForConfiguration:NULL] == YES) { - NSValue *min_frame_duration = [selected_range valueForKey:@"minFrameDuration"]; - - [video_device setValue:selected_format forKey:@"activeFormat"]; - [video_device setValue:min_frame_duration forKey:@"activeVideoMinFrameDuration"]; - [video_device setValue:min_frame_duration forKey:@"activeVideoMaxFrameDuration"]; - } else { - av_log(s, AV_LOG_ERROR, "Could not lock device for configuration"); - return AVERROR(EINVAL); + if ([video_device lockForConfiguration:NULL] == YES) { + if (selected_format) { + [video_device setValue:selected_format forKey:@"activeFormat"]; + } + if (selected_range) { + NSValue *min_frame_duration = [selected_range valueForKey:@"minFrameDuration"]; + [video_device setValue:min_frame_duration forKey:@"activeVideoMinFrameDuration"]; + [video_device setValue:min_frame_duration forKey:@"activeVideoMaxFrameDuration"]; + } + } else { + av_log(s, AV_LOG_ERROR, "Could not lock device for configuration.\n"); + return AVERROR(EINVAL); + } + } @catch(NSException *e) { + av_log(ctx, AV_LOG_WARNING, "Configuration of video device failed, falling back to default.\n"); } return 0; @@ -467,12 +484,18 @@ static int add_video_device(AVFormatContext *s, AVCaptureDevice *video_device) } } - ctx->pixel_format = pxl_fmt_spec.ff_id; - pixel_format = [NSNumber numberWithUnsignedInt:pxl_fmt_spec.avf_id]; - capture_dict = [NSDictionary dictionaryWithObject:pixel_format - forKey:(id)kCVPixelBufferPixelFormatTypeKey]; + // set videoSettings to an empty dict for receiving raw data of muxed devices + if (ctx->capture_raw_data) { + ctx->pixel_format = pxl_fmt_spec.ff_id; + ctx->video_output.videoSettings = @{ }; + } else { + ctx->pixel_format = pxl_fmt_spec.ff_id; + pixel_format = [NSNumber numberWithUnsignedInt:pxl_fmt_spec.avf_id]; + capture_dict = [NSDictionary dictionaryWithObject:pixel_format + forKey:(id)kCVPixelBufferPixelFormatTypeKey]; - [ctx->video_output setVideoSettings:capture_dict]; + [ctx->video_output setVideoSettings:capture_dict]; + } [ctx->video_output setAlwaysDiscardsLateVideoFrames:YES]; ctx->avf_delegate = [[AVFFrameReceiver alloc] initWithContext:ctx]; @@ -539,6 +562,7 @@ static int get_video_config(AVFormatContext *s) { AVFContext *ctx = (AVFContext*)s->priv_data; CVImageBufferRef image_buffer; + CMBlockBufferRef block_buffer; CGSize image_buffer_size; AVStream* stream = avformat_new_stream(s, NULL); @@ -557,14 +581,22 @@ static int get_video_config(AVFormatContext *s) avpriv_set_pts_info(stream, 64, 1, avf_time_base); - image_buffer = CMSampleBufferGetImageBuffer(ctx->current_frame); - image_buffer_size = CVImageBufferGetEncodedSize(image_buffer); + image_buffer = CMSampleBufferGetImageBuffer(ctx->current_frame); + block_buffer = CMSampleBufferGetDataBuffer(ctx->current_frame); - stream->codecpar->codec_id = AV_CODEC_ID_RAWVIDEO; - stream->codecpar->codec_type = AVMEDIA_TYPE_VIDEO; - stream->codecpar->width = (int)image_buffer_size.width; - stream->codecpar->height = (int)image_buffer_size.height; - stream->codecpar->format = ctx->pixel_format; + if (image_buffer) { + image_buffer_size = CVImageBufferGetEncodedSize(image_buffer); + + stream->codecpar->codec_id = AV_CODEC_ID_RAWVIDEO; + stream->codecpar->codec_type = AVMEDIA_TYPE_VIDEO; + stream->codecpar->width = (int)image_buffer_size.width; + stream->codecpar->height = (int)image_buffer_size.height; + stream->codecpar->format = ctx->pixel_format; + } else { + stream->codecpar->codec_id = AV_CODEC_ID_DVVIDEO; + stream->codecpar->codec_type = AVMEDIA_TYPE_VIDEO; + stream->codecpar->format = ctx->pixel_format; + } CFRelease(ctx->current_frame); ctx->current_frame = nil; @@ -669,8 +701,9 @@ static int avf_read_header(AVFormatContext *s) AVCaptureDevice *audio_device = nil; // Find capture device NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo]; - ctx->num_video_devices = [devices count]; + NSArray *devices_muxed = [AVCaptureDevice devicesWithMediaType:AVMediaTypeMuxed]; + ctx->num_video_devices = [devices count] + [devices_muxed count]; ctx->first_pts = av_gettime(); ctx->first_audio_pts = av_gettime(); @@ -689,14 +722,18 @@ static int avf_read_header(AVFormatContext *s) const char *name = [[device localizedName] UTF8String]; index = [devices indexOfObject:device]; av_log(ctx, AV_LOG_INFO, "[%d] %s\n", index, name); - index++; + } + for (AVCaptureDevice *device in devices_muxed) { + const char *name = [[device localizedName] UTF8String]; + index = [devices count] + [devices_muxed indexOfObject:device]; + av_log(ctx, AV_LOG_INFO, "[%d] %s\n", index, name); } #if !TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070 if (num_screens > 0) { CGDirectDisplayID screens[num_screens]; CGGetActiveDisplayList(num_screens, screens, &num_screens); for (int i = 0; i < num_screens; i++) { - av_log(ctx, AV_LOG_INFO, "[%d] Capture screen %d\n", index + i, i); + av_log(ctx, AV_LOG_INFO, "[%d] Capture screen %d\n", ctx->num_video_devices + i, i); } } #endif @@ -724,7 +761,12 @@ static int avf_read_header(AVFormatContext *s) if (ctx->video_device_index >= 0) { if (ctx->video_device_index < ctx->num_video_devices) { - video_device = [devices objectAtIndex:ctx->video_device_index]; + if (ctx->video_device_index < [devices count]) { + video_device = [devices objectAtIndex:ctx->video_device_index]; + } else { + video_device = [devices_muxed objectAtIndex:(ctx->video_device_index - [devices count])]; + ctx->video_is_muxed = 1; + } } else if (ctx->video_device_index < ctx->num_video_devices + num_screens) { #if !TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070 CGDirectDisplayID screens[num_screens]; @@ -768,6 +810,14 @@ static int avf_read_header(AVFormatContext *s) break; } } + // looking for muxed inputs + for (AVCaptureDevice *device in devices_muxed) { + if (!strncmp(ctx->video_filename, [[device localizedName] UTF8String], strlen(ctx->video_filename))) { + video_device = device; + ctx->video_is_muxed = 1; + break; + } + } #if !TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070 // looking for screen inputs @@ -892,19 +942,74 @@ fail: return AVERROR(EIO); } +static int copy_cvpixelbuffer(AVFormatContext *s, + CVPixelBufferRef image_buffer, + AVPacket *pkt) +{ + AVFContext *ctx = s->priv_data; + int src_linesize[4]; + const uint8_t *src_data[4]; + int width = CVPixelBufferGetWidth(image_buffer); + int height = CVPixelBufferGetHeight(image_buffer); + int status; + + memset(src_linesize, 0, sizeof(src_linesize)); + memset(src_data, 0, sizeof(src_data)); + + status = CVPixelBufferLockBaseAddress(image_buffer, 0); + if (status != kCVReturnSuccess) { + av_log(s, AV_LOG_ERROR, "Could not lock base address: %d (%dx%d)\n", status, width, height); + return AVERROR_EXTERNAL; + } + + if (CVPixelBufferIsPlanar(image_buffer)) { + size_t plane_count = CVPixelBufferGetPlaneCount(image_buffer); + int i; + for(i = 0; i < plane_count; i++){ + src_linesize[i] = CVPixelBufferGetBytesPerRowOfPlane(image_buffer, i); + src_data[i] = CVPixelBufferGetBaseAddressOfPlane(image_buffer, i); + } + } else { + src_linesize[0] = CVPixelBufferGetBytesPerRow(image_buffer); + src_data[0] = CVPixelBufferGetBaseAddress(image_buffer); + } + + status = av_image_copy_to_buffer(pkt->data, pkt->size, + src_data, src_linesize, + ctx->pixel_format, width, height, 1); + + + + CVPixelBufferUnlockBaseAddress(image_buffer, 0); + + return status; +} + static int avf_read_packet(AVFormatContext *s, AVPacket *pkt) { AVFContext* ctx = (AVFContext*)s->priv_data; do { CVImageBufferRef image_buffer; + CMBlockBufferRef block_buffer; lock_frames(ctx); - image_buffer = CMSampleBufferGetImageBuffer(ctx->current_frame); - if (ctx->current_frame != nil) { - void *data; - if (av_new_packet(pkt, (int)CVPixelBufferGetDataSize(image_buffer)) < 0) { + int status; + int length = 0; + + image_buffer = CMSampleBufferGetImageBuffer(ctx->current_frame); + block_buffer = CMSampleBufferGetDataBuffer(ctx->current_frame); + + if (image_buffer != nil) { + length = (int)CVPixelBufferGetDataSize(image_buffer); + } else if (block_buffer != nil) { + length = (int)CMBlockBufferGetDataLength(block_buffer); + } else { + return AVERROR(EINVAL); + } + + if (av_new_packet(pkt, length) < 0) { return AVERROR(EIO); } @@ -919,14 +1024,20 @@ static int avf_read_packet(AVFormatContext *s, AVPacket *pkt) pkt->stream_index = ctx->video_stream_index; pkt->flags |= AV_PKT_FLAG_KEY; - CVPixelBufferLockBaseAddress(image_buffer, 0); - - data = CVPixelBufferGetBaseAddress(image_buffer); - memcpy(pkt->data, data, pkt->size); - - CVPixelBufferUnlockBaseAddress(image_buffer, 0); + if (image_buffer) { + status = copy_cvpixelbuffer(s, image_buffer, pkt); + } else { + status = 0; + OSStatus ret = CMBlockBufferCopyDataBytes(block_buffer, 0, pkt->size, pkt->data); + if (ret != kCMBlockBufferNoErr) { + status = AVERROR(EIO); + } + } CFRelease(ctx->current_frame); ctx->current_frame = nil; + + if (status < 0) + return status; } else if (ctx->current_audio_frame != nil) { CMBlockBufferRef block_buffer = CMSampleBufferGetDataBuffer(ctx->current_audio_frame); int block_buffer_size = CMBlockBufferGetDataLength(block_buffer); @@ -1015,16 +1126,15 @@ static int avf_close(AVFormatContext *s) } static const AVOption options[] = { - { "list_devices", "list available devices", offsetof(AVFContext, list_devices), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, AV_OPT_FLAG_DECODING_PARAM, "list_devices" }, - { "true", "", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, AV_OPT_FLAG_DECODING_PARAM, "list_devices" }, - { "false", "", 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, AV_OPT_FLAG_DECODING_PARAM, "list_devices" }, + { "list_devices", "list available devices", offsetof(AVFContext, list_devices), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, AV_OPT_FLAG_DECODING_PARAM }, { "video_device_index", "select video device by index for devices with same name (starts at 0)", offsetof(AVFContext, video_device_index), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, AV_OPT_FLAG_DECODING_PARAM }, { "audio_device_index", "select audio device by index for devices with same name (starts at 0)", offsetof(AVFContext, audio_device_index), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, AV_OPT_FLAG_DECODING_PARAM }, { "pixel_format", "set pixel format", offsetof(AVFContext, pixel_format), AV_OPT_TYPE_PIXEL_FMT, {.i64 = AV_PIX_FMT_YUV420P}, 0, INT_MAX, AV_OPT_FLAG_DECODING_PARAM}, { "framerate", "set frame rate", offsetof(AVFContext, framerate), AV_OPT_TYPE_VIDEO_RATE, {.str = "ntsc"}, 0, INT_MAX, AV_OPT_FLAG_DECODING_PARAM }, { "video_size", "set video size", offsetof(AVFContext, width), AV_OPT_TYPE_IMAGE_SIZE, {.str = NULL}, 0, 0, AV_OPT_FLAG_DECODING_PARAM }, - { "capture_cursor", "capture the screen cursor", offsetof(AVFContext, capture_cursor), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, AV_OPT_FLAG_DECODING_PARAM }, - { "capture_mouse_clicks", "capture the screen mouse clicks", offsetof(AVFContext, capture_mouse_clicks), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, AV_OPT_FLAG_DECODING_PARAM }, + { "capture_cursor", "capture the screen cursor", offsetof(AVFContext, capture_cursor), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, AV_OPT_FLAG_DECODING_PARAM }, + { "capture_mouse_clicks", "capture the screen mouse clicks", offsetof(AVFContext, capture_mouse_clicks), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, AV_OPT_FLAG_DECODING_PARAM }, + { "capture_raw_data", "capture the raw data from device connection", offsetof(AVFContext, capture_raw_data), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, AV_OPT_FLAG_DECODING_PARAM }, { NULL }, }; diff --git a/libavdevice/decklink_common.cpp b/libavdevice/decklink_common.cpp index b889033cf..659aa9be3 100644 --- a/libavdevice/decklink_common.cpp +++ b/libavdevice/decklink_common.cpp @@ -53,65 +53,49 @@ extern "C" { #include "decklink_common.h" -#ifdef _WIN32 -IDeckLinkIterator *CreateDeckLinkIteratorInstance(void) +static IDeckLinkIterator *decklink_create_iterator(AVFormatContext *avctx) { IDeckLinkIterator *iter; +#ifdef _WIN32 if (CoInitialize(NULL) < 0) { - av_log(NULL, AV_LOG_ERROR, "COM initialization failed.\n"); + av_log(avctx, AV_LOG_ERROR, "COM initialization failed.\n"); return NULL; } if (CoCreateInstance(CLSID_CDeckLinkIterator, NULL, CLSCTX_ALL, IID_IDeckLinkIterator, (void**) &iter) != S_OK) { - av_log(NULL, AV_LOG_ERROR, "DeckLink drivers not installed.\n"); - return NULL; + iter = NULL; } +#else + iter = CreateDeckLinkIteratorInstance(); +#endif + if (!iter) + av_log(avctx, AV_LOG_ERROR, "Could not create DeckLink iterator. " + "Make sure you have DeckLink drivers " BLACKMAGIC_DECKLINK_API_VERSION_STRING " or newer installed.\n"); return iter; } -#endif -#ifdef _WIN32 -static char *dup_wchar_to_utf8(wchar_t *w) +static int decklink_get_attr_string(IDeckLink *dl, BMDDeckLinkAttributeID cfg_id, const char **s) { - char *s = NULL; - int l = WideCharToMultiByte(CP_UTF8, 0, w, -1, 0, 0, 0, 0); - s = (char *) av_malloc(l); - if (s) - WideCharToMultiByte(CP_UTF8, 0, w, -1, s, l, 0, 0); - return s; -} -#define DECKLINK_STR OLECHAR * -#define DECKLINK_STRDUP dup_wchar_to_utf8 -#define DECKLINK_FREE(s) SysFreeString(s) -#elif defined(__APPLE__) -static char *dup_cfstring_to_utf8(CFStringRef w) -{ - char s[256]; - CFStringGetCString(w, s, 255, kCFStringEncodingUTF8); - return av_strdup(s); -} -#define DECKLINK_STR const __CFString * -#define DECKLINK_STRDUP dup_cfstring_to_utf8 -#define DECKLINK_FREE(s) CFRelease(s) -#else -#define DECKLINK_STR const char * -#define DECKLINK_STRDUP av_strdup -/* free() is needed for a string returned by the DeckLink SDL. */ -#define DECKLINK_FREE(s) free((void *) s) -#endif - -HRESULT ff_decklink_get_display_name(IDeckLink *This, const char **displayName) -{ - DECKLINK_STR tmpDisplayName; - HRESULT hr = This->GetDisplayName(&tmpDisplayName); - if (hr != S_OK) - return hr; - *displayName = DECKLINK_STRDUP(tmpDisplayName); - DECKLINK_FREE(tmpDisplayName); - return hr; + DECKLINK_STR tmp; + HRESULT hr; + IDeckLinkProfileAttributes *attr; + *s = NULL; + if (dl->QueryInterface(IID_IDeckLinkProfileAttributes, (void **)&attr) != S_OK) + return AVERROR_EXTERNAL; + hr = attr->GetString(cfg_id, &tmp); + attr->Release(); + if (hr == S_OK) { + *s = DECKLINK_STRDUP(tmp); + DECKLINK_FREE(tmp); + if (!*s) + return AVERROR(ENOMEM); + } else if (hr == E_FAIL) { + return AVERROR_EXTERNAL; + } + return 0; } static int decklink_select_input(AVFormatContext *avctx, BMDDeckLinkConfigurationID cfg_id) @@ -165,11 +149,28 @@ int ff_decklink_set_configs(AVFormatContext *avctx, if (ctx->duplex_mode) { DECKLINK_BOOL duplex_supported = false; +#if BLACKMAGIC_DECKLINK_API_VERSION >= 0x0b000000 + IDeckLinkProfileManager *manager = NULL; + if (ctx->dl->QueryInterface(IID_IDeckLinkProfileManager, (void **)&manager) == S_OK) + duplex_supported = true; +#else if (ctx->attr->GetFlag(BMDDeckLinkSupportsDuplexModeConfiguration, &duplex_supported) != S_OK) duplex_supported = false; +#endif if (duplex_supported) { +#if BLACKMAGIC_DECKLINK_API_VERSION >= 0x0b000000 + IDeckLinkProfile *profile = NULL; + BMDProfileID bmd_profile_id = ctx->duplex_mode == 2 ? bmdProfileOneSubDeviceFullDuplex : bmdProfileTwoSubDevicesHalfDuplex; + res = manager->GetProfile(bmd_profile_id, &profile); + if (res == S_OK) { + res = profile->SetActive(); + profile->Release(); + } + manager->Release(); +#else res = ctx->cfg->SetInt(bmdDeckLinkConfigDuplexMode, ctx->duplex_mode == 2 ? bmdDuplexModeFull : bmdDuplexModeHalf); +#endif if (res != S_OK) av_log(avctx, AV_LOG_WARNING, "Setting duplex mode failed.\n"); else @@ -187,6 +188,11 @@ int ff_decklink_set_configs(AVFormatContext *avctx, if (ret < 0) return ret; } + if (direction == DIRECTION_OUT && cctx->timing_offset != INT_MIN) { + res = ctx->cfg->SetInt(bmdDeckLinkConfigReferenceInputTimingOffset, cctx->timing_offset); + if (res != S_OK) + av_log(avctx, AV_LOG_WARNING, "Setting timing offset failed.\n"); + } return 0; } @@ -198,7 +204,11 @@ int ff_decklink_set_format(AVFormatContext *avctx, { struct decklink_cctx *cctx = (struct decklink_cctx *)avctx->priv_data; struct decklink_ctx *ctx = (struct decklink_ctx *)cctx->ctx; +#if BLACKMAGIC_DECKLINK_API_VERSION >= 0x0b000000 + DECKLINK_BOOL support; +#else BMDDisplayModeSupport support; +#endif IDeckLinkDisplayModeIterator *itermode; IDeckLinkDisplayMode *mode; int i = 1; @@ -259,19 +269,47 @@ int ff_decklink_set_format(AVFormatContext *avctx, if (ctx->bmd_mode == bmdModeUnknown) return -1; + +#if BLACKMAGIC_DECKLINK_API_VERSION >= 0x0b000000 + if (direction == DIRECTION_IN) { + if (ctx->dli->DoesSupportVideoMode(ctx->video_input, ctx->bmd_mode, (BMDPixelFormat) cctx->raw_format, + bmdSupportedVideoModeDefault, + &support) != S_OK) + return -1; + } else { + BMDDisplayMode actualMode = ctx->bmd_mode; + if (ctx->dlo->DoesSupportVideoMode(bmdVideoConnectionUnspecified, ctx->bmd_mode, ctx->raw_format, + bmdSupportedVideoModeDefault, + &actualMode, &support) != S_OK || !support || ctx->bmd_mode != actualMode) { + return -1; + } + + } + if (support) + return 0; +#else if (direction == DIRECTION_IN) { if (ctx->dli->DoesSupportVideoMode(ctx->bmd_mode, (BMDPixelFormat) cctx->raw_format, bmdVideoOutputFlagDefault, &support, NULL) != S_OK) return -1; } else { - if (ctx->dlo->DoesSupportVideoMode(ctx->bmd_mode, bmdFormat8BitYUV, - bmdVideoOutputFlagDefault, - &support, NULL) != S_OK) - return -1; + if (!ctx->supports_vanc || ctx->dlo->DoesSupportVideoMode(ctx->bmd_mode, ctx->raw_format, + bmdVideoOutputVANC, + &support, NULL) != S_OK || support != bmdDisplayModeSupported) { + /* Try without VANC enabled */ + if (ctx->dlo->DoesSupportVideoMode(ctx->bmd_mode, ctx->raw_format, + bmdVideoOutputFlagDefault, + &support, NULL) != S_OK) { + return -1; + } + ctx->supports_vanc = 0; + } + } if (support == bmdDisplayModeSupported) return 0; +#endif return -1; } @@ -285,22 +323,26 @@ int ff_decklink_list_devices(AVFormatContext *avctx, int show_inputs, int show_outputs) { IDeckLink *dl = NULL; - IDeckLinkIterator *iter = CreateDeckLinkIteratorInstance(); + IDeckLinkIterator *iter = decklink_create_iterator(avctx); int ret = 0; - if (!iter) { - av_log(avctx, AV_LOG_ERROR, "Could not create DeckLink iterator\n"); + if (!iter) return AVERROR(EIO); - } while (ret == 0 && iter->Next(&dl) == S_OK) { IDeckLinkOutput *output_config; IDeckLinkInput *input_config; - const char *displayName; + const char *display_name = NULL; + const char *unique_name = NULL; AVDeviceInfo *new_device = NULL; int add = 0; - ff_decklink_get_display_name(dl, &displayName); + ret = decklink_get_attr_string(dl, BMDDeckLinkDisplayName, &display_name); + if (ret < 0) + goto next; + ret = decklink_get_attr_string(dl, BMDDeckLinkDeviceHandle, &unique_name); + if (ret < 0) + goto next; if (show_outputs) { if (dl->QueryInterface(IID_IDeckLinkOutput, (void **)&output_config) == S_OK) { @@ -323,8 +365,8 @@ int ff_decklink_list_devices(AVFormatContext *avctx, goto next; } - new_device->device_name = av_strdup(displayName); - new_device->device_description = av_strdup(displayName); + new_device->device_name = av_strdup(unique_name ? unique_name : display_name); + new_device->device_description = av_strdup(display_name); if (!new_device->device_name || !new_device->device_description || @@ -338,7 +380,8 @@ int ff_decklink_list_devices(AVFormatContext *avctx, } next: - av_freep(&displayName); + av_freep(&display_name); + av_freep(&unique_name); dl->Release(); } iter->Release(); @@ -363,7 +406,7 @@ void ff_decklink_list_devices_legacy(AVFormatContext *avctx, av_log(avctx, AV_LOG_INFO, "Blackmagic DeckLink %s devices:\n", show_inputs ? "input" : "output"); for (int i = 0; i < device_list->nb_devices; i++) { - av_log(avctx, AV_LOG_INFO, "\t'%s'\n", device_list->devices[i]->device_name); + av_log(avctx, AV_LOG_INFO, "\t'%s'\n", device_list->devices[i]->device_description); } } avdevice_free_list_devices(&device_list); @@ -442,21 +485,23 @@ int ff_decklink_init_device(AVFormatContext *avctx, const char* name) struct decklink_cctx *cctx = (struct decklink_cctx *)avctx->priv_data; struct decklink_ctx *ctx = (struct decklink_ctx *)cctx->ctx; IDeckLink *dl = NULL; - IDeckLinkIterator *iter = CreateDeckLinkIteratorInstance(); - if (!iter) { - av_log(avctx, AV_LOG_ERROR, "Could not create DeckLink iterator\n"); + IDeckLinkIterator *iter = decklink_create_iterator(avctx); + if (!iter) return AVERROR_EXTERNAL; - } while (iter->Next(&dl) == S_OK) { - const char *displayName; - ff_decklink_get_display_name(dl, &displayName); - if (!strcmp(name, displayName)) { - av_free((void *)displayName); + const char *display_name = NULL; + const char *unique_name = NULL; + decklink_get_attr_string(dl, BMDDeckLinkDisplayName, &display_name); + decklink_get_attr_string(dl, BMDDeckLinkDeviceHandle, &unique_name); + if (display_name && !strcmp(name, display_name) || unique_name && !strcmp(name, unique_name)) { + av_free((void *)unique_name); + av_free((void *)display_name); ctx->dl = dl; break; } - av_free((void *)displayName); + av_free((void *)display_name); + av_free((void *)unique_name); dl->Release(); } iter->Release(); @@ -469,7 +514,7 @@ int ff_decklink_init_device(AVFormatContext *avctx, const char* name) return AVERROR_EXTERNAL; } - if (ctx->dl->QueryInterface(IID_IDeckLinkAttributes, (void **)&ctx->attr) != S_OK) { + if (ctx->dl->QueryInterface(IID_IDeckLinkProfileAttributes, (void **)&ctx->attr) != S_OK) { av_log(avctx, AV_LOG_ERROR, "Could not get attributes interface for '%s'\n", name); ff_decklink_cleanup(avctx); return AVERROR_EXTERNAL; diff --git a/libavdevice/decklink_common.h b/libavdevice/decklink_common.h index 57ee7d1d6..921818ba4 100644 --- a/libavdevice/decklink_common.h +++ b/libavdevice/decklink_common.h @@ -24,9 +24,16 @@ #define AVDEVICE_DECKLINK_COMMON_H #include +#if BLACKMAGIC_DECKLINK_API_VERSION < 0x0b000000 +#define IID_IDeckLinkProfileAttributes IID_IDeckLinkAttributes +#define IDeckLinkProfileAttributes IDeckLinkAttributes +#endif #include "libavutil/thread.h" #include "decklink_common_c.h" +#if CONFIG_LIBKLVANC +#include "libklvanc/vanc.h" +#endif #ifdef _WIN32 #define DECKLINK_BOOL BOOL @@ -34,6 +41,36 @@ #define DECKLINK_BOOL bool #endif +#ifdef _WIN32 +static char *dup_wchar_to_utf8(wchar_t *w) +{ + char *s = NULL; + int l = WideCharToMultiByte(CP_UTF8, 0, w, -1, 0, 0, 0, 0); + s = (char *) av_malloc(l); + if (s) + WideCharToMultiByte(CP_UTF8, 0, w, -1, s, l, 0, 0); + return s; +} +#define DECKLINK_STR OLECHAR * +#define DECKLINK_STRDUP dup_wchar_to_utf8 +#define DECKLINK_FREE(s) SysFreeString(s) +#elif defined(__APPLE__) +static char *dup_cfstring_to_utf8(CFStringRef w) +{ + char s[256]; + CFStringGetCString(w, s, 255, kCFStringEncodingUTF8); + return av_strdup(s); +} +#define DECKLINK_STR const __CFString * +#define DECKLINK_STRDUP dup_cfstring_to_utf8 +#define DECKLINK_FREE(s) CFRelease(s) +#else +#define DECKLINK_STR const char * +#define DECKLINK_STRDUP av_strdup +/* free() is needed for a string returned by the DeckLink SDL. */ +#define DECKLINK_FREE(s) free((void *) s) +#endif + class decklink_output_callback; class decklink_input_callback; @@ -54,9 +91,8 @@ struct decklink_ctx { IDeckLinkOutput *dlo; IDeckLinkInput *dli; IDeckLinkConfiguration *cfg; - IDeckLinkAttributes *attr; + IDeckLinkProfileAttributes *attr; decklink_output_callback *output_callback; - decklink_input_callback *input_callback; /* DeckLink mode information */ BMDTimeValue bmd_tb_den; @@ -64,9 +100,11 @@ struct decklink_ctx { BMDDisplayMode bmd_mode; BMDVideoConnection video_input; BMDAudioConnection audio_input; + BMDTimecodeFormat tc_format; int bmd_width; int bmd_height; int bmd_field_dominance; + int supports_vanc; /* Capture buffer queue */ AVPacketQueue queue; @@ -84,6 +122,7 @@ struct decklink_ctx { AVStream *audio_st; AVStream *video_st; AVStream *teletext_st; + uint16_t cdp_sequence_num; /* Options */ int list_devices; @@ -94,6 +133,7 @@ struct decklink_ctx { DecklinkPtsSource audio_pts_source; DecklinkPtsSource video_pts_source; int draw_bars; + BMDPixelFormat raw_format; int frames_preroll; int frames_buffer; @@ -103,6 +143,10 @@ struct decklink_ctx { int frames_buffer_available_spots; int autodetect; +#if CONFIG_LIBKLVANC + struct klvanc_context_s *vanc_ctx; +#endif + int channels; int audio_depth; }; @@ -140,7 +184,17 @@ static const BMDVideoConnection decklink_video_connection_map[] = { bmdVideoConnectionSVideo, }; -HRESULT ff_decklink_get_display_name(IDeckLink *This, const char **displayName); +static const BMDTimecodeFormat decklink_timecode_format_map[] = { + (BMDTimecodeFormat)0, + bmdTimecodeRP188VITC1, + bmdTimecodeRP188VITC2, + bmdTimecodeRP188LTC, + bmdTimecodeRP188Any, + bmdTimecodeVITC, + bmdTimecodeVITCField2, + bmdTimecodeSerial, +}; + int ff_decklink_set_configs(AVFormatContext *avctx, decklink_direction_t direction); int ff_decklink_set_format(AVFormatContext *avctx, int width, int height, int tb_num, int tb_den, enum AVFieldOrder field_order, decklink_direction_t direction = DIRECTION_OUT, int num = 0); int ff_decklink_set_format(AVFormatContext *avctx, decklink_direction_t direction, int num); diff --git a/libavdevice/decklink_common_c.h b/libavdevice/decklink_common_c.h index 08e9f9bbd..ca85ec250 100644 --- a/libavdevice/decklink_common_c.h +++ b/libavdevice/decklink_common_c.h @@ -50,11 +50,14 @@ struct decklink_cctx { DecklinkPtsSource video_pts_source; int audio_input; int video_input; + int tc_format; int draw_bars; char *format_code; int raw_format; int64_t queue_size; int copyts; + int64_t timestamp_align; + int timing_offset; }; #endif /* AVDEVICE_DECKLINK_COMMON_C_H */ diff --git a/libavdevice/decklink_dec.cpp b/libavdevice/decklink_dec.cpp index 57004d7b0..4da9122bf 100644 --- a/libavdevice/decklink_dec.cpp +++ b/libavdevice/decklink_dec.cpp @@ -21,6 +21,9 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include +using std::atomic; + /* Include internal.h first to avoid conflict between winsock.h (used by * DeckLink headers) and winsock2.h (used by libavformat) in MSVC++ builds */ extern "C" { @@ -98,6 +101,52 @@ static VANCLineNumber vanc_line_numbers[] = { {bmdModeUnknown, 0, -1, -1, -1} }; +class decklink_allocator : public IDeckLinkMemoryAllocator +{ +public: + decklink_allocator(): _refs(1) { } + virtual ~decklink_allocator() { } + + // IDeckLinkMemoryAllocator methods + virtual HRESULT STDMETHODCALLTYPE AllocateBuffer(unsigned int bufferSize, void* *allocatedBuffer) + { + void *buf = av_malloc(bufferSize + AV_INPUT_BUFFER_PADDING_SIZE); + if (!buf) + return E_OUTOFMEMORY; + *allocatedBuffer = buf; + return S_OK; + } + virtual HRESULT STDMETHODCALLTYPE ReleaseBuffer(void* buffer) + { + av_free(buffer); + return S_OK; + } + virtual HRESULT STDMETHODCALLTYPE Commit() { return S_OK; } + virtual HRESULT STDMETHODCALLTYPE Decommit() { return S_OK; } + + // IUnknown methods + virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, LPVOID *ppv) { return E_NOINTERFACE; } + virtual ULONG STDMETHODCALLTYPE AddRef(void) { return ++_refs; } + virtual ULONG STDMETHODCALLTYPE Release(void) + { + int ret = --_refs; + if (!ret) + delete this; + return ret; + } + +private: + std::atomic _refs; +}; + +extern "C" { +static void decklink_object_free(void *opaque, uint8_t *data) +{ + IUnknown *obj = (class IUnknown *)opaque; + obj->Release(); +} +} + static int get_vanc_line_idx(BMDDisplayMode mode) { unsigned int i; @@ -547,8 +596,7 @@ public: virtual HRESULT STDMETHODCALLTYPE VideoInputFrameArrived(IDeckLinkVideoInputFrame*, IDeckLinkAudioInputPacket*); private: - ULONG m_refCount; - pthread_mutex_t m_mutex; + std::atomic _refs; AVFormatContext *avctx; decklink_ctx *ctx; int no_video; @@ -556,42 +604,30 @@ private: int64_t initial_audio_pts; }; -decklink_input_callback::decklink_input_callback(AVFormatContext *_avctx) : m_refCount(0) +decklink_input_callback::decklink_input_callback(AVFormatContext *_avctx) : _refs(1) { avctx = _avctx; decklink_cctx *cctx = (struct decklink_cctx *)avctx->priv_data; ctx = (struct decklink_ctx *)cctx->ctx; no_video = 0; initial_audio_pts = initial_video_pts = AV_NOPTS_VALUE; - pthread_mutex_init(&m_mutex, NULL); } decklink_input_callback::~decklink_input_callback() { - pthread_mutex_destroy(&m_mutex); } ULONG decklink_input_callback::AddRef(void) { - pthread_mutex_lock(&m_mutex); - m_refCount++; - pthread_mutex_unlock(&m_mutex); - - return (ULONG)m_refCount; + return ++_refs; } ULONG decklink_input_callback::Release(void) { - pthread_mutex_lock(&m_mutex); - m_refCount--; - pthread_mutex_unlock(&m_mutex); - - if (m_refCount == 0) { + int ret = --_refs; + if (!ret) delete this; - return 0; - } - - return (ULONG)m_refCount; + return ret; } static int64_t get_pkt_pts(IDeckLinkVideoInputFrame *videoFrame, @@ -667,6 +703,16 @@ HRESULT decklink_input_callback::VideoInputFrameArrived( return S_OK; } + // Drop the frames till system's timestamp aligns with the configured value. + if (0 == ctx->frameCount && cctx->timestamp_align) { + AVRational remainder = av_make_q(av_gettime() % cctx->timestamp_align, 1000000); + AVRational frame_duration = av_inv_q(ctx->video_st->r_frame_rate); + if (av_cmp_q(remainder, frame_duration) > 0) { + ++ctx->dropped; + return S_OK; + } + } + ctx->frameCount++; if (ctx->audio_pts_source == PTS_SRC_WALLCLOCK || ctx->video_pts_source == PTS_SRC_WALLCLOCK) wallclock = av_gettime_relative(); @@ -716,6 +762,35 @@ HRESULT decklink_input_callback::VideoInputFrameArrived( "- Frames dropped %u\n", ctx->frameCount, ++ctx->dropped); } no_video = 0; + + // Handle Timecode (if requested) + if (ctx->tc_format) { + IDeckLinkTimecode *timecode; + if (videoFrame->GetTimecode(ctx->tc_format, &timecode) == S_OK) { + const char *tc = NULL; + DECKLINK_STR decklink_tc; + if (timecode->GetString(&decklink_tc) == S_OK) { + tc = DECKLINK_STRDUP(decklink_tc); + DECKLINK_FREE(decklink_tc); + } + timecode->Release(); + if (tc) { + AVDictionary* metadata_dict = NULL; + int metadata_len; + uint8_t* packed_metadata; + if (av_dict_set(&metadata_dict, "timecode", tc, AV_DICT_DONT_STRDUP_VAL) >= 0) { + packed_metadata = av_packet_pack_dictionary(metadata_dict, &metadata_len); + av_dict_free(&metadata_dict); + if (packed_metadata) { + if (av_packet_add_side_data(&pkt, AV_PKT_DATA_STRINGS_METADATA, packed_metadata, metadata_len) < 0) + av_freep(&packed_metadata); + } + } + } + } else { + av_log(avctx, AV_LOG_DEBUG, "Unable to find timecode.\n"); + } + } } pkt.pts = get_pkt_pts(videoFrame, audioFrame, wallclock, abs_wallclock, ctx->video_pts_source, ctx->video_st->time_base, &initial_video_pts, cctx->copyts); @@ -800,6 +875,10 @@ HRESULT decklink_input_callback::VideoInputFrameArrived( } } + pkt.buf = av_buffer_create(pkt.data, pkt.size, decklink_object_free, videoFrame, 0); + if (pkt.buf) + videoFrame->AddRef(); + if (avpacket_queue_put(&ctx->queue, &pkt) < 0) { ++ctx->dropped; } @@ -912,6 +991,8 @@ av_cold int ff_decklink_read_header(AVFormatContext *avctx) { struct decklink_cctx *cctx = (struct decklink_cctx *)avctx->priv_data; struct decklink_ctx *ctx; + class decklink_allocator *allocator; + class decklink_input_callback *input_callback; AVStream *st; HRESULT result; char fname[1024]; @@ -927,6 +1008,8 @@ av_cold int ff_decklink_read_header(AVFormatContext *avctx) ctx->teletext_lines = cctx->teletext_lines; ctx->preroll = cctx->preroll; ctx->duplex_mode = cctx->duplex_mode; + if (cctx->tc_format > 0 && (unsigned int)cctx->tc_format < FF_ARRAY_ELEMS(decklink_timecode_format_map)) + ctx->tc_format = decklink_timecode_format_map[cctx->tc_format]; if (cctx->video_input > 0 && (unsigned int)cctx->video_input < FF_ARRAY_ELEMS(decklink_video_connection_map)) ctx->video_input = decklink_video_connection_map[cctx->video_input]; if (cctx->audio_input > 0 && (unsigned int)cctx->audio_input < FF_ARRAY_ELEMS(decklink_audio_connection_map)) @@ -989,6 +1072,12 @@ av_cold int ff_decklink_read_header(AVFormatContext *avctx) goto error; } + if (ff_decklink_set_configs(avctx, DIRECTION_IN) < 0) { + av_log(avctx, AV_LOG_ERROR, "Could not set input configuration\n"); + ret = AVERROR(EIO); + goto error; + } + /* List supported formats. */ if (ctx->list_formats) { ff_decklink_list_formats(avctx, DIRECTION_IN); @@ -996,14 +1085,21 @@ av_cold int ff_decklink_read_header(AVFormatContext *avctx) goto error; } - if (ff_decklink_set_configs(avctx, DIRECTION_IN) < 0) { - av_log(avctx, AV_LOG_ERROR, "Could not set input configuration\n"); - ret = AVERROR(EIO); + input_callback = new decklink_input_callback(avctx); + ret = (ctx->dli->SetCallback(input_callback) == S_OK ? 0 : AVERROR_EXTERNAL); + input_callback->Release(); + if (ret < 0) { + av_log(avctx, AV_LOG_ERROR, "Cannot set input callback\n"); goto error; } - ctx->input_callback = new decklink_input_callback(avctx); - ctx->dli->SetCallback(ctx->input_callback); + allocator = new decklink_allocator(); + ret = (ctx->dli->SetVideoInputFrameMemoryAllocator(allocator) == S_OK ? 0 : AVERROR_EXTERNAL); + allocator->Release(); + if (ret < 0) { + av_log(avctx, AV_LOG_ERROR, "Cannot set custom memory allocator\n"); + goto error; + } if (mode_num == 0 && !cctx->format_code) { if (decklink_autodetect(cctx) < 0) { @@ -1071,14 +1167,14 @@ av_cold int ff_decklink_read_header(AVFormatContext *avctx) break; case bmdFormat8BitARGB: st->codecpar->codec_id = AV_CODEC_ID_RAWVIDEO; - st->codecpar->codec_tag = avcodec_pix_fmt_to_codec_tag((enum AVPixelFormat)st->codecpar->format); st->codecpar->format = AV_PIX_FMT_0RGB; + st->codecpar->codec_tag = avcodec_pix_fmt_to_codec_tag((enum AVPixelFormat)st->codecpar->format); st->codecpar->bit_rate = av_rescale(ctx->bmd_width * ctx->bmd_height * 32, st->time_base.den, st->time_base.num); break; case bmdFormat8BitBGRA: st->codecpar->codec_id = AV_CODEC_ID_RAWVIDEO; - st->codecpar->codec_tag = avcodec_pix_fmt_to_codec_tag((enum AVPixelFormat)st->codecpar->format); st->codecpar->format = AV_PIX_FMT_BGR0; + st->codecpar->codec_tag = avcodec_pix_fmt_to_codec_tag((enum AVPixelFormat)st->codecpar->format); st->codecpar->bit_rate = av_rescale(ctx->bmd_width * ctx->bmd_height * 32, st->time_base.den, st->time_base.num); break; case bmdFormat10BitRGB: @@ -1167,6 +1263,15 @@ int ff_decklink_read_packet(AVFormatContext *avctx, AVPacket *pkt) avpacket_queue_get(&ctx->queue, pkt, 1); + if (ctx->tc_format && !(av_dict_get(ctx->video_st->metadata, "timecode", NULL, 0))) { + int size; + const uint8_t *side_metadata = av_packet_get_side_data(pkt, AV_PKT_DATA_STRINGS_METADATA, &size); + if (side_metadata) { + if (av_packet_unpack_dictionary(side_metadata, size, &ctx->video_st->metadata) < 0) + av_log(avctx, AV_LOG_ERROR, "Unable to set timecode\n"); + } + } + return 0; } diff --git a/libavdevice/decklink_dec_c.c b/libavdevice/decklink_dec_c.c index 47018dc68..91d2839c5 100644 --- a/libavdevice/decklink_dec_c.c +++ b/libavdevice/decklink_dec_c.c @@ -48,6 +48,15 @@ static const AVOption options[] = { { "unset", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 0}, 0, 0, DEC, "duplex_mode"}, { "half", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 1}, 0, 0, DEC, "duplex_mode"}, { "full", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 2}, 0, 0, DEC, "duplex_mode"}, + { "timecode_format", "timecode format", OFFSET(tc_format), AV_OPT_TYPE_INT, { .i64 = 0}, 0, 7, DEC, "tc_format"}, + { "none", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 0}, 0, 0, DEC, "tc_format"}, + { "rp188vitc", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 1}, 0, 0, DEC, "tc_format"}, + { "rp188vitc2", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 2}, 0, 0, DEC, "tc_format"}, + { "rp188ltc", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 3}, 0, 0, DEC, "tc_format"}, + { "rp188any", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 4}, 0, 0, DEC, "tc_format"}, + { "vitc", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 5}, 0, 0, DEC, "tc_format"}, + { "vitc2", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 6}, 0, 0, DEC, "tc_format"}, + { "serial", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 7}, 0, 0, DEC, "tc_format"}, { "video_input", "video input", OFFSET(video_input), AV_OPT_TYPE_INT, { .i64 = 0}, 0, 6, DEC, "video_input"}, { "unset", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 0}, 0, 0, DEC, "video_input"}, { "sdi", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 1}, 0, 0, DEC, "video_input"}, @@ -75,6 +84,7 @@ static const AVOption options[] = { { "queue_size", "input queue buffer size", OFFSET(queue_size), AV_OPT_TYPE_INT64, { .i64 = (1024 * 1024 * 1024)}, 0, INT64_MAX, DEC }, { "audio_depth", "audio bitdepth (16 or 32)", OFFSET(audio_depth), AV_OPT_TYPE_INT, { .i64 = 16}, 16, 32, DEC }, { "decklink_copyts", "copy timestamps, do not remove the initial offset", OFFSET(copyts), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, DEC }, + { "timestamp_align", "capture start time alignment (in seconds)", OFFSET(timestamp_align), AV_OPT_TYPE_DURATION, { .i64 = 0 }, 0, INT_MAX, DEC }, { NULL }, }; diff --git a/libavdevice/decklink_enc.cpp b/libavdevice/decklink_enc.cpp index 28ab928cd..04b06aee3 100644 --- a/libavdevice/decklink_enc.cpp +++ b/libavdevice/decklink_enc.cpp @@ -38,17 +38,20 @@ extern "C" { #include "decklink_common.h" #include "decklink_enc.h" - +#if CONFIG_LIBKLVANC +#include "libklvanc/vanc.h" +#include "libklvanc/vanc-lines.h" +#include "libklvanc/pixels.h" +#endif /* DeckLink callback class declaration */ class decklink_frame : public IDeckLinkVideoFrame { public: decklink_frame(struct decklink_ctx *ctx, AVFrame *avframe, AVCodecID codec_id, int height, int width) : - _ctx(ctx), _avframe(avframe), _avpacket(NULL), _codec_id(codec_id), _height(height), _width(width), _refs(1) { } + _ctx(ctx), _avframe(avframe), _avpacket(NULL), _codec_id(codec_id), _ancillary(NULL), _height(height), _width(width), _refs(1) { } decklink_frame(struct decklink_ctx *ctx, AVPacket *avpacket, AVCodecID codec_id, int height, int width) : - _ctx(ctx), _avframe(NULL), _avpacket(avpacket), _codec_id(codec_id), _height(height), _width(width), _refs(1) { } - + _ctx(ctx), _avframe(NULL), _avpacket(avpacket), _codec_id(codec_id), _ancillary(NULL), _height(height), _width(width), _refs(1) { } virtual long STDMETHODCALLTYPE GetWidth (void) { return _width; } virtual long STDMETHODCALLTYPE GetHeight (void) { return _height; } virtual long STDMETHODCALLTYPE GetRowBytes (void) @@ -87,8 +90,24 @@ public: } virtual HRESULT STDMETHODCALLTYPE GetTimecode (BMDTimecodeFormat format, IDeckLinkTimecode **timecode) { return S_FALSE; } - virtual HRESULT STDMETHODCALLTYPE GetAncillaryData(IDeckLinkVideoFrameAncillary **ancillary) { return S_FALSE; } - + virtual HRESULT STDMETHODCALLTYPE GetAncillaryData(IDeckLinkVideoFrameAncillary **ancillary) + { + *ancillary = _ancillary; + if (_ancillary) { + _ancillary->AddRef(); + return S_OK; + } else { + return S_FALSE; + } + } + virtual HRESULT STDMETHODCALLTYPE SetAncillaryData(IDeckLinkVideoFrameAncillary *ancillary) + { + if (_ancillary) + _ancillary->Release(); + _ancillary = ancillary; + _ancillary->AddRef(); + return S_OK; + } virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, LPVOID *ppv) { return E_NOINTERFACE; } virtual ULONG STDMETHODCALLTYPE AddRef(void) { return ++_refs; } virtual ULONG STDMETHODCALLTYPE Release(void) @@ -97,6 +116,8 @@ public: if (!ret) { av_frame_free(&_avframe); av_packet_free(&_avpacket); + if (_ancillary) + _ancillary->Release(); delete this; } return ret; @@ -106,6 +127,7 @@ public: AVFrame *_avframe; AVPacket *_avpacket; AVCodecID _codec_id; + IDeckLinkVideoFrameAncillary *_ancillary; int _height; int _width; @@ -156,10 +178,13 @@ static int decklink_setup_video(AVFormatContext *avctx, AVStream *st) " Only AV_PIX_FMT_UYVY422 is supported.\n"); return -1; } + ctx->raw_format = bmdFormat8BitYUV; } else if (c->codec_id != AV_CODEC_ID_V210) { av_log(avctx, AV_LOG_ERROR, "Unsupported codec type!" " Only V210 and wrapped frame with AV_PIX_FMT_UYVY422 are supported.\n"); return -1; + } else { + ctx->raw_format = bmdFormat10BitYUV; } if (ff_decklink_set_configs(avctx, DIRECTION_OUT) < 0) { @@ -172,8 +197,11 @@ static int decklink_setup_video(AVFormatContext *avctx, AVStream *st) " Check available formats with -list_formats 1.\n"); return -1; } - if (ctx->dlo->EnableVideoOutput(ctx->bmd_mode, - bmdVideoOutputFlagDefault) != S_OK) { + if (ctx->supports_vanc && ctx->dlo->EnableVideoOutput(ctx->bmd_mode, bmdVideoOutputVANC) != S_OK) { + av_log(avctx, AV_LOG_WARNING, "Could not enable video output with VANC! Trying without...\n"); + ctx->supports_vanc = 0; + } + if (!ctx->supports_vanc && ctx->dlo->EnableVideoOutput(ctx->bmd_mode, bmdVideoOutputFlagDefault) != S_OK) { av_log(avctx, AV_LOG_ERROR, "Could not enable video output!\n"); return -1; } @@ -193,6 +221,9 @@ static int decklink_setup_video(AVFormatContext *avctx, AVStream *st) pthread_cond_init(&ctx->cond, NULL); ctx->frames_buffer_available_spots = ctx->frames_buffer; + av_log(avctx, AV_LOG_DEBUG, "output: %s, preroll: %d, frames buffer size: %d\n", + avctx->url, ctx->frames_preroll, ctx->frames_buffer); + /* The device expects the framerate to be fixed. */ avpriv_set_pts_info(st, 64, st->time_base.num, st->time_base.den); @@ -264,11 +295,139 @@ av_cold int ff_decklink_write_trailer(AVFormatContext *avctx) pthread_mutex_destroy(&ctx->mutex); pthread_cond_destroy(&ctx->cond); +#if CONFIG_LIBKLVANC + klvanc_context_destroy(ctx->vanc_ctx); +#endif + av_freep(&cctx->ctx); return 0; } +#if CONFIG_LIBKLVANC +static void construct_cc(AVFormatContext *avctx, struct decklink_ctx *ctx, + AVPacket *pkt, struct klvanc_line_set_s *vanc_lines) +{ + struct klvanc_packet_eia_708b_s *cdp; + uint16_t *cdp_words; + uint16_t len; + uint8_t cc_count; + int size, ret, i; + + const uint8_t *data = av_packet_get_side_data(pkt, AV_PKT_DATA_A53_CC, &size); + if (!data) + return; + + cc_count = size / 3; + + ret = klvanc_create_eia708_cdp(&cdp); + if (ret) + return; + + ret = klvanc_set_framerate_EIA_708B(cdp, ctx->bmd_tb_num, ctx->bmd_tb_den); + if (ret) { + av_log(avctx, AV_LOG_ERROR, "Invalid framerate specified: %lld/%lld\n", + ctx->bmd_tb_num, ctx->bmd_tb_den); + klvanc_destroy_eia708_cdp(cdp); + return; + } + + if (cc_count > KLVANC_MAX_CC_COUNT) { + av_log(avctx, AV_LOG_ERROR, "Illegal cc_count received: %d\n", cc_count); + cc_count = KLVANC_MAX_CC_COUNT; + } + + /* CC data */ + cdp->header.ccdata_present = 1; + cdp->header.caption_service_active = 1; + cdp->ccdata.cc_count = cc_count; + for (i = 0; i < cc_count; i++) { + if (data [3*i] & 0x04) + cdp->ccdata.cc[i].cc_valid = 1; + cdp->ccdata.cc[i].cc_type = data[3*i] & 0x03; + cdp->ccdata.cc[i].cc_data[0] = data[3*i+1]; + cdp->ccdata.cc[i].cc_data[1] = data[3*i+2]; + } + + klvanc_finalize_EIA_708B(cdp, ctx->cdp_sequence_num++); + ret = klvanc_convert_EIA_708B_to_words(cdp, &cdp_words, &len); + klvanc_destroy_eia708_cdp(cdp); + if (ret != 0) { + av_log(avctx, AV_LOG_ERROR, "Failed converting 708 packet to words\n"); + return; + } + + ret = klvanc_line_insert(ctx->vanc_ctx, vanc_lines, cdp_words, len, 11, 0); + free(cdp_words); + if (ret != 0) { + av_log(avctx, AV_LOG_ERROR, "VANC line insertion failed\n"); + return; + } +} + +static int decklink_construct_vanc(AVFormatContext *avctx, struct decklink_ctx *ctx, + AVPacket *pkt, decklink_frame *frame) +{ + struct klvanc_line_set_s vanc_lines = { 0 }; + int ret = 0, i; + + if (!ctx->supports_vanc) + return 0; + + construct_cc(avctx, ctx, pkt, &vanc_lines); + + IDeckLinkVideoFrameAncillary *vanc; + int result = ctx->dlo->CreateAncillaryData(bmdFormat10BitYUV, &vanc); + if (result != S_OK) { + av_log(avctx, AV_LOG_ERROR, "Failed to create vanc\n"); + ret = AVERROR(EIO); + goto done; + } + + /* Now that we've got all the VANC lines in a nice orderly manner, generate the + final VANC sections for the Decklink output */ + for (i = 0; i < vanc_lines.num_lines; i++) { + struct klvanc_line_s *line = vanc_lines.lines[i]; + int real_line; + void *buf; + + if (!line) + break; + + /* FIXME: include hack for certain Decklink cards which mis-represent + line numbers for pSF frames */ + real_line = line->line_number; + + result = vanc->GetBufferForVerticalBlankingLine(real_line, &buf); + if (result != S_OK) { + av_log(avctx, AV_LOG_ERROR, "Failed to get VANC line %d: %d", real_line, result); + continue; + } + + /* Generate the full line taking into account all VANC packets on that line */ + result = klvanc_generate_vanc_line_v210(ctx->vanc_ctx, line, (uint8_t *) buf, + ctx->bmd_width); + if (result) { + av_log(avctx, AV_LOG_ERROR, "Failed to generate VANC line\n"); + continue; + } + } + + result = frame->SetAncillaryData(vanc); + vanc->Release(); + if (result != S_OK) { + av_log(avctx, AV_LOG_ERROR, "Failed to set vanc: %d", result); + ret = AVERROR(EIO); + } + +done: + for (i = 0; i < vanc_lines.num_lines; i++) + klvanc_line_free(vanc_lines.lines[i]); + + return ret; +} +#endif + static int decklink_write_video_packet(AVFormatContext *avctx, AVPacket *pkt) { struct decklink_cctx *cctx = (struct decklink_cctx *)avctx->priv_data; @@ -303,6 +462,11 @@ static int decklink_write_video_packet(AVFormatContext *avctx, AVPacket *pkt) } frame = new decklink_frame(ctx, avpacket, st->codecpar->codec_id, ctx->bmd_height, ctx->bmd_width); + +#if CONFIG_LIBKLVANC + if (decklink_construct_vanc(avctx, ctx, pkt, frame)) + av_log(avctx, AV_LOG_ERROR, "Failed to construct VANC\n"); +#endif } if (!frame) { @@ -392,7 +556,15 @@ av_cold int ff_decklink_write_header(AVFormatContext *avctx) ctx->list_devices = cctx->list_devices; ctx->list_formats = cctx->list_formats; ctx->preroll = cctx->preroll; + ctx->duplex_mode = cctx->duplex_mode; cctx->ctx = ctx; +#if CONFIG_LIBKLVANC + if (klvanc_context_create(&ctx->vanc_ctx) < 0) { + av_log(avctx, AV_LOG_ERROR, "Cannot create VANC library context\n"); + return AVERROR(ENOMEM); + } + ctx->supports_vanc = 1; +#endif /* List available devices and exit. */ if (ctx->list_devices) { diff --git a/libavdevice/decklink_enc_c.c b/libavdevice/decklink_enc_c.c index 360535cfd..63cbd39ec 100644 --- a/libavdevice/decklink_enc_c.c +++ b/libavdevice/decklink_enc_c.c @@ -31,6 +31,12 @@ static const AVOption options[] = { { "list_devices", "list available devices" , OFFSET(list_devices), AV_OPT_TYPE_INT , { .i64 = 0 }, 0, 1, ENC }, { "list_formats", "list supported formats" , OFFSET(list_formats), AV_OPT_TYPE_INT , { .i64 = 0 }, 0, 1, ENC }, { "preroll" , "video preroll in seconds", OFFSET(preroll ), AV_OPT_TYPE_DOUBLE, { .dbl = 0.5 }, 0, 5, ENC }, + { "duplex_mode" , "duplex mode" , OFFSET(duplex_mode ), AV_OPT_TYPE_INT , { .i64 = 0 }, 0, 2, ENC, "duplex_mode"}, + { "unset" , NULL , 0 , AV_OPT_TYPE_CONST , { .i64 = 0 }, 0, 0, ENC, "duplex_mode"}, + { "half" , NULL , 0 , AV_OPT_TYPE_CONST , { .i64 = 1 }, 0, 0, ENC, "duplex_mode"}, + { "full" , NULL , 0 , AV_OPT_TYPE_CONST , { .i64 = 2 }, 0, 0, ENC, "duplex_mode"}, + { "timing_offset", "genlock timing pixel offset", OFFSET(timing_offset), AV_OPT_TYPE_INT, { .i64 = INT_MIN }, INT_MIN, INT_MAX, ENC, "timing_offset"}, + { "unset" , NULL , 0 , AV_OPT_TYPE_CONST, { .i64 = INT_MIN }, 0, 0, ENC, "timing_offset"}, { NULL }, }; diff --git a/libavdevice/dshow.c b/libavdevice/dshow.c index de910c099..d7f5bd706 100644 --- a/libavdevice/dshow.c +++ b/libavdevice/dshow.c @@ -278,12 +278,12 @@ dshow_cycle_devices(AVFormatContext *avctx, ICreateDevEnum *devenum, goto fail1; } *device_unique_name = unique_name; + unique_name = NULL; // success, loop will end now } } else { av_log(avctx, AV_LOG_INFO, " \"%s\"\n", friendly_name); av_log(avctx, AV_LOG_INFO, " Alternative name \"%s\"\n", unique_name); - av_free(unique_name); } fail1: @@ -291,7 +291,8 @@ fail1: IMalloc_Free(co_malloc, olestr); if (bind_ctx) IBindCtx_Release(bind_ctx); - av_free(friendly_name); + av_freep(&friendly_name); + av_freep(&unique_name); if (bag) IPropertyBag_Release(bag); IMoniker_Release(m); @@ -941,6 +942,8 @@ dshow_add_device(AVFormatContext *avctx, AVStream *st; int ret = AVERROR(EIO); + type.pbFormat = NULL; + st = avformat_new_stream(avctx, NULL); if (!st) { ret = AVERROR(ENOMEM); @@ -989,17 +992,22 @@ dshow_add_device(AVFormatContext *avctx, if (par->codec_id == AV_CODEC_ID_NONE) { av_log(avctx, AV_LOG_ERROR, "Unknown compression type. " "Please report type 0x%X.\n", (int) bih->biCompression); - return AVERROR_PATCHWELCOME; + ret = AVERROR_PATCHWELCOME; + goto error; } par->bits_per_coded_sample = bih->biBitCount; } else { par->codec_id = AV_CODEC_ID_RAWVIDEO; if (bih->biCompression == BI_RGB || bih->biCompression == BI_BITFIELDS) { par->bits_per_coded_sample = bih->biBitCount; - par->extradata = av_malloc(9 + AV_INPUT_BUFFER_PADDING_SIZE); - if (par->extradata) { - par->extradata_size = 9; - memcpy(par->extradata, "BottomUp", 9); + if (par->height < 0) { + par->height *= -1; + } else { + par->extradata = av_malloc(9 + AV_INPUT_BUFFER_PADDING_SIZE); + if (par->extradata) { + par->extradata_size = 9; + memcpy(par->extradata, "BottomUp", 9); + } } } } @@ -1026,6 +1034,8 @@ dshow_add_device(AVFormatContext *avctx, ret = 0; error: + if (type.pbFormat) + CoTaskMemFree(type.pbFormat); return ret; } diff --git a/libavdevice/dshow_pin.c b/libavdevice/dshow_pin.c index 664246da9..53b1c9150 100644 --- a/libavdevice/dshow_pin.c +++ b/libavdevice/dshow_pin.c @@ -249,8 +249,20 @@ libAVPin_Setup(libAVPin *this, libAVFilter *filter) return 1; } + +static void +libAVPin_Free(libAVPin *this) +{ + if (!this) + return; + av_freep(&this->imemvtbl); + if (this->type.pbFormat) { + CoTaskMemFree(this->type.pbFormat); + this->type.pbFormat = NULL; + } +} DECLARE_CREATE(libAVPin, libAVPin_Setup(this, filter), libAVFilter *filter) -DECLARE_DESTROY(libAVPin, nothing) +DECLARE_DESTROY(libAVPin, libAVPin_Free) /***************************************************************************** * libAVMemInputPin diff --git a/libavdevice/gdigrab.c b/libavdevice/gdigrab.c index ab08c1178..f4444406f 100644 --- a/libavdevice/gdigrab.c +++ b/libavdevice/gdigrab.c @@ -277,14 +277,20 @@ gdigrab_read_header(AVFormatContext *s1) } bpp = GetDeviceCaps(source_hdc, BITSPIXEL); + horzres = GetDeviceCaps(source_hdc, HORZRES); + vertres = GetDeviceCaps(source_hdc, VERTRES); + desktophorzres = GetDeviceCaps(source_hdc, DESKTOPHORZRES); + desktopvertres = GetDeviceCaps(source_hdc, DESKTOPVERTRES); + if (hwnd) { GetClientRect(hwnd, &virtual_rect); + /* window -- get the right height and width for scaling DPI */ + virtual_rect.left = virtual_rect.left * desktophorzres / horzres; + virtual_rect.right = virtual_rect.right * desktophorzres / horzres; + virtual_rect.top = virtual_rect.top * desktopvertres / vertres; + virtual_rect.bottom = virtual_rect.bottom * desktopvertres / vertres; } else { /* desktop -- get the right height and width for scaling DPI */ - horzres = GetDeviceCaps(source_hdc, HORZRES); - vertres = GetDeviceCaps(source_hdc, VERTRES); - desktophorzres = GetDeviceCaps(source_hdc, DESKTOPHORZRES); - desktopvertres = GetDeviceCaps(source_hdc, DESKTOPVERTRES); virtual_rect.left = GetSystemMetrics(SM_XVIRTUALSCREEN); virtual_rect.top = GetSystemMetrics(SM_YVIRTUALSCREEN); virtual_rect.right = (virtual_rect.left + GetSystemMetrics(SM_CXVIRTUALSCREEN)) * desktophorzres / horzres; @@ -473,25 +479,26 @@ static void paint_mouse_pointer(AVFormatContext *s1, struct gdigrab *gdigrab) goto icon_error; } - pos.x = ci.ptScreenPos.x - clip_rect.left - info.xHotspot; - pos.y = ci.ptScreenPos.y - clip_rect.top - info.yHotspot; - if (hwnd) { RECT rect; if (GetWindowRect(hwnd, &rect)) { - pos.x -= rect.left; - pos.y -= rect.top; + pos.x = ci.ptScreenPos.x - clip_rect.left - info.xHotspot - rect.left; + pos.y = ci.ptScreenPos.y - clip_rect.top - info.yHotspot - rect.top; + + //that would keep the correct location of mouse with hidpi screens + pos.x = pos.x * desktophorzres / horzres; + pos.y = pos.y * desktopvertres / vertres; } else { CURSOR_ERROR("Couldn't get window rectangle"); goto icon_error; } + } else { + //that would keep the correct location of mouse with hidpi screens + pos.x = ci.ptScreenPos.x * desktophorzres / horzres - clip_rect.left - info.xHotspot; + pos.y = ci.ptScreenPos.y * desktopvertres / vertres - clip_rect.top - info.yHotspot; } - //that would keep the correct location of mouse with hidpi screens - pos.x = pos.x * desktophorzres / horzres; - pos.y = pos.y * desktopvertres / vertres; - av_log(s1, AV_LOG_DEBUG, "Cursor pos (%li,%li) -> (%li,%li)\n", ci.ptScreenPos.x, ci.ptScreenPos.y, pos.x, pos.y); @@ -640,6 +647,7 @@ static const AVClass gdigrab_class = { .item_name = av_default_item_name, .option = options, .version = LIBAVUTIL_VERSION_INT, + .category = AV_CLASS_CATEGORY_DEVICE_VIDEO_INPUT, }; /** gdi grabber device demuxer declaration */ diff --git a/libavdevice/iec61883.c b/libavdevice/iec61883.c index dcf755392..cafafb267 100644 --- a/libavdevice/iec61883.c +++ b/libavdevice/iec61883.c @@ -23,7 +23,7 @@ * libiec61883 interface */ -#include +#include #include #include #include diff --git a/libavdevice/opengl_enc.c b/libavdevice/opengl_enc.c index 54c7e610b..fd0bb177d 100644 --- a/libavdevice/opengl_enc.c +++ b/libavdevice/opengl_enc.c @@ -25,7 +25,6 @@ #include #include #include -#include #include #include "config.h" diff --git a/libavdevice/pulse_audio_dec.c b/libavdevice/pulse_audio_dec.c index 5977fb7e9..042fe76d4 100644 --- a/libavdevice/pulse_audio_dec.c +++ b/libavdevice/pulse_audio_dec.c @@ -148,6 +148,9 @@ static av_cold int pulse_read_header(AVFormatContext *s) pd->channels }; pa_buffer_attr attr = { -1 }; + pa_channel_map cmap; + + pa_channel_map_init_extend(&cmap, pd->channels, PA_CHANNEL_MAP_WAVEEX); st = avformat_new_stream(s, NULL); @@ -202,7 +205,7 @@ static av_cold int pulse_read_header(AVFormatContext *s) pa_threaded_mainloop_wait(pd->mainloop); } - if (!(pd->stream = pa_stream_new(pd->context, pd->stream_name, &ss, NULL))) { + if (!(pd->stream = pa_stream_new(pd->context, pd->stream_name, &ss, &cmap))) { ret = AVERROR(pa_context_errno(pd->context)); goto unlock_and_fail; } diff --git a/libavdevice/sdl2.c b/libavdevice/sdl2.c index 48ed977be..d6fc74a66 100644 --- a/libavdevice/sdl2.c +++ b/libavdevice/sdl2.c @@ -40,8 +40,10 @@ typedef struct { SDL_Renderer *renderer; char *window_title; int window_width, window_height; /**< size of the window */ + int window_x, window_y; /**< position of the window */ int window_fullscreen; int window_borderless; + int enable_quit_action; SDL_Texture *texture; int texture_fmt; @@ -154,8 +156,6 @@ static int sdl2_write_trailer(AVFormatContext *s) return 0; } -#define SDL_BASE_FLAGS (SDL_SWSURFACE|SDL_WINDOW_RESIZABLE) - static int sdl2_write_header(AVFormatContext *s) { SDLContext *sdl = s->priv_data; @@ -195,8 +195,9 @@ static int sdl2_write_header(AVFormatContext *s) } /* resize texture to width and height from the codec context information */ - flags = SDL_BASE_FLAGS | (sdl->window_fullscreen ? SDL_WINDOW_FULLSCREEN : 0) | - (sdl->window_borderless ? SDL_WINDOW_BORDERLESS : 0); + flags = SDL_WINDOW_HIDDEN | + (sdl->window_fullscreen ? SDL_WINDOW_FULLSCREEN : 0) | + (sdl->window_borderless ? SDL_WINDOW_BORDERLESS : SDL_WINDOW_RESIZABLE); /* initialization */ if (!sdl->inited){ @@ -206,9 +207,7 @@ static int sdl2_write_header(AVFormatContext *s) } } - sdl->window_width = sdl->texture_rect.w = codecpar->width; - sdl->window_height = sdl->texture_rect.h = codecpar->height; - sdl->texture_rect.x = sdl->texture_rect.y = 0; + compute_texture_rect(s); if (SDL_CreateWindowAndRenderer(sdl->window_width, sdl->window_height, flags, &sdl->window, &sdl->renderer) != 0){ @@ -217,9 +216,11 @@ static int sdl2_write_header(AVFormatContext *s) } SDL_SetWindowTitle(sdl->window, sdl->window_title); + SDL_SetWindowPosition(sdl->window, sdl->window_x, sdl->window_y); + SDL_ShowWindow(sdl->window); sdl->texture = SDL_CreateTexture(sdl->renderer, sdl->texture_fmt, SDL_TEXTUREACCESS_STREAMING, - sdl->window_width, sdl->window_height); + codecpar->width, codecpar->height); if (!sdl->texture) { av_log(sdl, AV_LOG_ERROR, "Unable to set create mode: %s\n", SDL_GetError()); @@ -279,7 +280,7 @@ static int sdl2_write_packet(AVFormatContext *s, AVPacket *pkt) } } - if (quit) { + if (quit && sdl->enable_quit_action) { sdl2_write_trailer(s); return AVERROR(EIO); } @@ -338,8 +339,11 @@ static int sdl2_write_packet(AVFormatContext *s, AVPacket *pkt) static const AVOption options[] = { { "window_title", "set SDL window title", OFFSET(window_title), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, AV_OPT_FLAG_ENCODING_PARAM }, { "window_size", "set SDL window forced size", OFFSET(window_width), AV_OPT_TYPE_IMAGE_SIZE, { .str = NULL }, 0, 0, AV_OPT_FLAG_ENCODING_PARAM }, + { "window_x", "set SDL window x position", OFFSET(window_x), AV_OPT_TYPE_INT, { .i64 = SDL_WINDOWPOS_CENTERED }, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM }, + { "window_y", "set SDL window y position", OFFSET(window_y), AV_OPT_TYPE_INT, { .i64 = SDL_WINDOWPOS_CENTERED }, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM }, { "window_fullscreen", "set SDL window fullscreen", OFFSET(window_fullscreen), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, AV_OPT_FLAG_ENCODING_PARAM }, { "window_borderless", "set SDL window border off", OFFSET(window_borderless), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, AV_OPT_FLAG_ENCODING_PARAM }, + { "window_enable_quit", "set if quit action is available", OFFSET(enable_quit_action), AV_OPT_TYPE_INT, {.i64=1}, 0, 1, AV_OPT_FLAG_ENCODING_PARAM }, { NULL }, }; diff --git a/libavdevice/v4l2-common.c b/libavdevice/v4l2-common.c index 196c09b7f..b5b4448a3 100644 --- a/libavdevice/v4l2-common.c +++ b/libavdevice/v4l2-common.c @@ -34,11 +34,20 @@ const struct fmt_map ff_fmt_conversion_table[] = { { AV_PIX_FMT_RGB565BE,AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_RGB565X }, { AV_PIX_FMT_BGR24, AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_BGR24 }, { AV_PIX_FMT_RGB24, AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_RGB24 }, +#ifdef V4L2_PIX_FMT_XBGR32 + { AV_PIX_FMT_BGR0, AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_XBGR32 }, + { AV_PIX_FMT_0RGB, AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_XRGB32 }, + { AV_PIX_FMT_BGRA, AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_ABGR32 }, + { AV_PIX_FMT_ARGB, AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_ARGB32 }, +#endif { AV_PIX_FMT_BGR0, AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_BGR32 }, { AV_PIX_FMT_0RGB, AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_RGB32 }, { AV_PIX_FMT_GRAY8, AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_GREY }, #ifdef V4L2_PIX_FMT_Y16 { AV_PIX_FMT_GRAY16LE,AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_Y16 }, +#endif +#ifdef V4L2_PIX_FMT_Z16 + { AV_PIX_FMT_GRAY16LE,AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_Z16 }, #endif { AV_PIX_FMT_NV12, AV_CODEC_ID_RAWVIDEO, V4L2_PIX_FMT_NV12 }, { AV_PIX_FMT_NONE, AV_CODEC_ID_MJPEG, V4L2_PIX_FMT_MJPEG }, diff --git a/libavdevice/v4l2.c b/libavdevice/v4l2.c index 10a0ff0dd..a9a0ed324 100644 --- a/libavdevice/v4l2.c +++ b/libavdevice/v4l2.c @@ -95,7 +95,11 @@ struct video_data { int (*open_f)(const char *file, int oflag, ...); int (*close_f)(int fd); int (*dup_f)(int fd); +#ifdef __GLIBC__ int (*ioctl_f)(int fd, unsigned long int request, ...); +#else + int (*ioctl_f)(int fd, int request, ...); +#endif ssize_t (*read_f)(int fd, void *buffer, size_t n); void *(*mmap_f)(void *start, size_t length, int prot, int flags, int fd, int64_t offset); int (*munmap_f)(void *_start, size_t length); @@ -812,7 +816,7 @@ static int device_try_init(AVFormatContext *ctx, return ret; } -static int v4l2_read_probe(AVProbeData *p) +static int v4l2_read_probe(const AVProbeData *p) { if (av_strstart(p->filename, "/dev/video", NULL)) return AVPROBE_SCORE_MAX - 1; diff --git a/libavdevice/v4l2enc.c b/libavdevice/v4l2enc.c index 85200d0a3..1c36f81f9 100644 --- a/libavdevice/v4l2enc.c +++ b/libavdevice/v4l2enc.c @@ -106,7 +106,7 @@ static const AVClass v4l2_class = { }; AVOutputFormat ff_v4l2_muxer = { - .name = "v4l2", + .name = "video4linux2,v4l2", .long_name = NULL_IF_CONFIG_SMALL("Video4Linux2 output device"), .priv_data_size = sizeof(V4L2Context), .audio_codec = AV_CODEC_ID_NONE, diff --git a/libavdevice/version.h b/libavdevice/version.h index dbfbfd069..840cefad0 100644 --- a/libavdevice/version.h +++ b/libavdevice/version.h @@ -28,7 +28,7 @@ #include "libavutil/version.h" #define LIBAVDEVICE_VERSION_MAJOR 58 -#define LIBAVDEVICE_VERSION_MINOR 3 +#define LIBAVDEVICE_VERSION_MINOR 8 #define LIBAVDEVICE_VERSION_MICRO 100 #define LIBAVDEVICE_VERSION_INT AV_VERSION_INT(LIBAVDEVICE_VERSION_MAJOR, \ diff --git a/libavdevice/vfwcap.c b/libavdevice/vfwcap.c index 6a923d995..e2ab276c2 100644 --- a/libavdevice/vfwcap.c +++ b/libavdevice/vfwcap.c @@ -328,11 +328,14 @@ static int vfw_read_header(AVFormatContext *s) } if (ctx->video_size) { - ret = av_parse_video_size(&bi->bmiHeader.biWidth, &bi->bmiHeader.biHeight, ctx->video_size); + int w, h; + ret = av_parse_video_size(&w, &h, ctx->video_size); if (ret < 0) { av_log(s, AV_LOG_ERROR, "Couldn't parse video size.\n"); goto fail; } + bi->bmiHeader.biWidth = w; + bi->bmiHeader.biHeight = h; } if (0) { diff --git a/libavdevice/xcbgrab.c b/libavdevice/xcbgrab.c index 6d142abd4..b7e689343 100644 --- a/libavdevice/xcbgrab.c +++ b/libavdevice/xcbgrab.c @@ -127,7 +127,7 @@ static int xcbgrab_reposition(AVFormatContext *s, int left = x + f; int right = x + w - f; int top = y + f; - int bottom = y + h + f; + int bottom = y + h - f; if (p_x > right) { x += p_x - right; } else if (p_x < left) { diff --git a/libavfilter/Makefile b/libavfilter/Makefile index bcd5d437f..455c809b1 100644 --- a/libavfilter/Makefile +++ b/libavfilter/Makefile @@ -26,6 +26,9 @@ OBJS-$(HAVE_THREADS) += pthread.o # subsystems OBJS-$(CONFIG_QSVVPP) += qsvvpp.o +DNN-OBJS-$(CONFIG_LIBTENSORFLOW) += dnn_backend_tf.o +OBJS-$(CONFIG_DNN) += dnn_interface.o dnn_backend_native.o $(DNN-OBJS-yes) +OBJS-$(CONFIG_SCENE_SAD) += scene_sad.o # audio filters OBJS-$(CONFIG_ABENCH_FILTER) += f_bench.o @@ -33,17 +36,24 @@ OBJS-$(CONFIG_ACOMPRESSOR_FILTER) += af_sidechaincompress.o OBJS-$(CONFIG_ACONTRAST_FILTER) += af_acontrast.o OBJS-$(CONFIG_ACOPY_FILTER) += af_acopy.o OBJS-$(CONFIG_ACROSSFADE_FILTER) += af_afade.o +OBJS-$(CONFIG_ACROSSOVER_FILTER) += af_acrossover.o OBJS-$(CONFIG_ACRUSHER_FILTER) += af_acrusher.o +OBJS-$(CONFIG_ACUE_FILTER) += f_cue.o +OBJS-$(CONFIG_ADECLICK_FILTER) += af_adeclick.o +OBJS-$(CONFIG_ADECLIP_FILTER) += af_adeclick.o OBJS-$(CONFIG_ADELAY_FILTER) += af_adelay.o +OBJS-$(CONFIG_ADERIVATIVE_FILTER) += af_aderivative.o OBJS-$(CONFIG_AECHO_FILTER) += af_aecho.o OBJS-$(CONFIG_AEMPHASIS_FILTER) += af_aemphasis.o OBJS-$(CONFIG_AEVAL_FILTER) += aeval.o OBJS-$(CONFIG_AFADE_FILTER) += af_afade.o +OBJS-$(CONFIG_AFFTDN_FILTER) += af_afftdn.o OBJS-$(CONFIG_AFFTFILT_FILTER) += af_afftfilt.o OBJS-$(CONFIG_AFIR_FILTER) += af_afir.o OBJS-$(CONFIG_AFORMAT_FILTER) += af_aformat.o OBJS-$(CONFIG_AGATE_FILTER) += af_agate.o OBJS-$(CONFIG_AIIR_FILTER) += af_aiir.o +OBJS-$(CONFIG_AINTEGRAL_FILTER) += af_aderivative.o OBJS-$(CONFIG_AINTERLEAVE_FILTER) += f_interleave.o OBJS-$(CONFIG_ALIMITER_FILTER) += af_alimiter.o OBJS-$(CONFIG_ALLPASS_FILTER) += af_biquads.o @@ -51,7 +61,9 @@ OBJS-$(CONFIG_ALOOP_FILTER) += f_loop.o OBJS-$(CONFIG_AMERGE_FILTER) += af_amerge.o OBJS-$(CONFIG_AMETADATA_FILTER) += f_metadata.o OBJS-$(CONFIG_AMIX_FILTER) += af_amix.o +OBJS-$(CONFIG_AMULTIPLY_FILTER) += af_amultiply.o OBJS-$(CONFIG_ANEQUALIZER_FILTER) += af_anequalizer.o +OBJS-$(CONFIG_ANLMDN_FILTER) += af_anlmdn.o OBJS-$(CONFIG_ANULL_FILTER) += af_anull.o OBJS-$(CONFIG_APAD_FILTER) += af_apad.o OBJS-$(CONFIG_APERMS_FILTER) += f_perms.o @@ -68,7 +80,9 @@ OBJS-$(CONFIG_ASETRATE_FILTER) += af_asetrate.o OBJS-$(CONFIG_ASETTB_FILTER) += settb.o OBJS-$(CONFIG_ASHOWINFO_FILTER) += af_ashowinfo.o OBJS-$(CONFIG_ASIDEDATA_FILTER) += f_sidedata.o +OBJS-$(CONFIG_ASOFTCLIP_FILTER) += af_asoftclip.o OBJS-$(CONFIG_ASPLIT_FILTER) += split.o +OBJS-$(CONFIG_ASR_FILTER) += af_asr.o OBJS-$(CONFIG_ASTATS_FILTER) += af_astats.o OBJS-$(CONFIG_ASTREAMSELECT_FILTER) += f_streamselect.o framesync.o OBJS-$(CONFIG_ATEMPO_FILTER) += af_atempo.o @@ -87,6 +101,7 @@ OBJS-$(CONFIG_COMPENSATIONDELAY_FILTER) += af_compensationdelay.o OBJS-$(CONFIG_CROSSFEED_FILTER) += af_crossfeed.o OBJS-$(CONFIG_CRYSTALIZER_FILTER) += af_crystalizer.o OBJS-$(CONFIG_DCSHIFT_FILTER) += af_dcshift.o +OBJS-$(CONFIG_DEESSER_FILTER) += af_deesser.o OBJS-$(CONFIG_DRMETER_FILTER) += af_drmeter.o OBJS-$(CONFIG_DYNAUDNORM_FILTER) += af_dynaudnorm.o OBJS-$(CONFIG_EARWAX_FILTER) += af_earwax.o @@ -99,10 +114,12 @@ OBJS-$(CONFIG_HAAS_FILTER) += af_haas.o OBJS-$(CONFIG_HDCD_FILTER) += af_hdcd.o OBJS-$(CONFIG_HEADPHONE_FILTER) += af_headphone.o OBJS-$(CONFIG_HIGHPASS_FILTER) += af_biquads.o +OBJS-$(CONFIG_HIGHSHELF_FILTER) += af_biquads.o OBJS-$(CONFIG_JOIN_FILTER) += af_join.o OBJS-$(CONFIG_LADSPA_FILTER) += af_ladspa.o OBJS-$(CONFIG_LOUDNORM_FILTER) += af_loudnorm.o ebur128.o OBJS-$(CONFIG_LOWPASS_FILTER) += af_biquads.o +OBJS-$(CONFIG_LOWSHELF_FILTER) += af_biquads.o OBJS-$(CONFIG_LV2_FILTER) += af_lv2.o OBJS-$(CONFIG_MCOMPAND_FILTER) += af_mcompand.o OBJS-$(CONFIG_PAN_FILTER) += af_pan.o @@ -129,6 +146,7 @@ OBJS-$(CONFIG_ANOISESRC_FILTER) += asrc_anoisesrc.o OBJS-$(CONFIG_ANULLSRC_FILTER) += asrc_anullsrc.o OBJS-$(CONFIG_FLITE_FILTER) += asrc_flite.o OBJS-$(CONFIG_HILBERT_FILTER) += asrc_hilbert.o +OBJS-$(CONFIG_SINC_FILTER) += asrc_sinc.o OBJS-$(CONFIG_SINE_FILTER) += asrc_sine.o OBJS-$(CONFIG_ANULLSINK_FILTER) += asink_anullsink.o @@ -136,43 +154,56 @@ OBJS-$(CONFIG_ANULLSINK_FILTER) += asink_anullsink.o # video filters OBJS-$(CONFIG_ALPHAEXTRACT_FILTER) += vf_extractplanes.o OBJS-$(CONFIG_ALPHAMERGE_FILTER) += vf_alphamerge.o +OBJS-$(CONFIG_AMPLIFY_FILTER) += vf_amplify.o OBJS-$(CONFIG_ASS_FILTER) += vf_subtitles.o OBJS-$(CONFIG_ATADENOISE_FILTER) += vf_atadenoise.o OBJS-$(CONFIG_AVGBLUR_FILTER) += vf_avgblur.o OBJS-$(CONFIG_AVGBLUR_OPENCL_FILTER) += vf_avgblur_opencl.o opencl.o \ - opencl/avgblur.o + opencl/avgblur.o boxblur.o OBJS-$(CONFIG_BBOX_FILTER) += bbox.o vf_bbox.o OBJS-$(CONFIG_BENCH_FILTER) += f_bench.o OBJS-$(CONFIG_BITPLANENOISE_FILTER) += vf_bitplanenoise.o OBJS-$(CONFIG_BLACKDETECT_FILTER) += vf_blackdetect.o OBJS-$(CONFIG_BLACKFRAME_FILTER) += vf_blackframe.o OBJS-$(CONFIG_BLEND_FILTER) += vf_blend.o framesync.o -OBJS-$(CONFIG_BOXBLUR_FILTER) += vf_boxblur.o -OBJS-$(CONFIG_BWDIF_FILTER) += vf_bwdif.o +OBJS-$(CONFIG_BM3D_FILTER) += vf_bm3d.o +OBJS-$(CONFIG_BOXBLUR_FILTER) += vf_boxblur.o boxblur.o +OBJS-$(CONFIG_BOXBLUR_OPENCL_FILTER) += vf_avgblur_opencl.o opencl.o \ + opencl/avgblur.o boxblur.o +OBJS-$(CONFIG_BWDIF_FILTER) += vf_bwdif.o yadif_common.o +OBJS-$(CONFIG_CHROMAHOLD_FILTER) += vf_chromakey.o OBJS-$(CONFIG_CHROMAKEY_FILTER) += vf_chromakey.o +OBJS-$(CONFIG_CHROMASHIFT_FILTER) += vf_chromashift.o OBJS-$(CONFIG_CIESCOPE_FILTER) += vf_ciescope.o OBJS-$(CONFIG_CODECVIEW_FILTER) += vf_codecview.o OBJS-$(CONFIG_COLORBALANCE_FILTER) += vf_colorbalance.o OBJS-$(CONFIG_COLORCHANNELMIXER_FILTER) += vf_colorchannelmixer.o OBJS-$(CONFIG_COLORKEY_FILTER) += vf_colorkey.o +OBJS-$(CONFIG_COLORKEY_OPENCL_FILTER) += vf_colorkey_opencl.o opencl.o \ + opencl/colorkey.o +OBJS-$(CONFIG_COLORHOLD_FILTER) += vf_colorkey.o OBJS-$(CONFIG_COLORLEVELS_FILTER) += vf_colorlevels.o OBJS-$(CONFIG_COLORMATRIX_FILTER) += vf_colormatrix.o -OBJS-$(CONFIG_COLORSPACE_FILTER) += vf_colorspace.o colorspacedsp.o +OBJS-$(CONFIG_COLORSPACE_FILTER) += vf_colorspace.o colorspace.o colorspacedsp.o OBJS-$(CONFIG_CONVOLUTION_FILTER) += vf_convolution.o OBJS-$(CONFIG_CONVOLUTION_OPENCL_FILTER) += vf_convolution_opencl.o opencl.o \ - opencl/convolution.o + opencl/convolution.o OBJS-$(CONFIG_CONVOLVE_FILTER) += vf_convolve.o framesync.o OBJS-$(CONFIG_COPY_FILTER) += vf_copy.o OBJS-$(CONFIG_COREIMAGE_FILTER) += vf_coreimage.o OBJS-$(CONFIG_COVER_RECT_FILTER) += vf_cover_rect.o lavfutils.o OBJS-$(CONFIG_CROP_FILTER) += vf_crop.o OBJS-$(CONFIG_CROPDETECT_FILTER) += vf_cropdetect.o +OBJS-$(CONFIG_CUE_FILTER) += f_cue.o OBJS-$(CONFIG_CURVES_FILTER) += vf_curves.o OBJS-$(CONFIG_DATASCOPE_FILTER) += vf_datascope.o OBJS-$(CONFIG_DCTDNOIZ_FILTER) += vf_dctdnoiz.o OBJS-$(CONFIG_DEBAND_FILTER) += vf_deband.o +OBJS-$(CONFIG_DEBLOCK_FILTER) += vf_deblock.o OBJS-$(CONFIG_DECIMATE_FILTER) += vf_decimate.o +OBJS-$(CONFIG_DERAIN_FILTER) += vf_derain.o OBJS-$(CONFIG_DECONVOLVE_FILTER) += vf_convolve.o framesync.o +OBJS-$(CONFIG_DEDOT_FILTER) += vf_dedot.o OBJS-$(CONFIG_DEFLATE_FILTER) += vf_neighbor.o OBJS-$(CONFIG_DEFLICKER_FILTER) += vf_deflicker.o OBJS-$(CONFIG_DEINTERLACE_QSV_FILTER) += vf_deinterlace_qsv.o @@ -184,6 +215,8 @@ OBJS-$(CONFIG_DESHAKE_FILTER) += vf_deshake.o OBJS-$(CONFIG_DESPILL_FILTER) += vf_despill.o OBJS-$(CONFIG_DETELECINE_FILTER) += vf_detelecine.o OBJS-$(CONFIG_DILATION_FILTER) += vf_neighbor.o +OBJS-$(CONFIG_DILATION_OPENCL_FILTER) += vf_neighbor_opencl.o opencl.o \ + opencl/neighbor.o OBJS-$(CONFIG_DISPLACE_FILTER) += vf_displace.o framesync.o OBJS-$(CONFIG_DOUBLEWEAVE_FILTER) += vf_weave.o OBJS-$(CONFIG_DRAWBOX_FILTER) += vf_drawbox.o @@ -195,8 +228,11 @@ OBJS-$(CONFIG_ELBG_FILTER) += vf_elbg.o OBJS-$(CONFIG_ENTROPY_FILTER) += vf_entropy.o OBJS-$(CONFIG_EQ_FILTER) += vf_eq.o OBJS-$(CONFIG_EROSION_FILTER) += vf_neighbor.o +OBJS-$(CONFIG_EROSION_OPENCL_FILTER) += vf_neighbor_opencl.o opencl.o \ + opencl/neighbor.o OBJS-$(CONFIG_EXTRACTPLANES_FILTER) += vf_extractplanes.o OBJS-$(CONFIG_FADE_FILTER) += vf_fade.o +OBJS-$(CONFIG_FFTDNOIZ_FILTER) += vf_fftdnoiz.o OBJS-$(CONFIG_FFTFILT_FILTER) += vf_fftfilt.o OBJS-$(CONFIG_FIELD_FILTER) += vf_field.o OBJS-$(CONFIG_FIELDHINT_FILTER) += vf_fieldhint.o @@ -210,11 +246,14 @@ OBJS-$(CONFIG_FPS_FILTER) += vf_fps.o OBJS-$(CONFIG_FRAMEPACK_FILTER) += vf_framepack.o OBJS-$(CONFIG_FRAMERATE_FILTER) += vf_framerate.o OBJS-$(CONFIG_FRAMESTEP_FILTER) += vf_framestep.o +OBJS-$(CONFIG_FREEZEDETECT_FILTER) += vf_freezedetect.o OBJS-$(CONFIG_FREI0R_FILTER) += vf_frei0r.o OBJS-$(CONFIG_FSPP_FILTER) += vf_fspp.o OBJS-$(CONFIG_GBLUR_FILTER) += vf_gblur.o OBJS-$(CONFIG_GEQ_FILTER) += vf_geq.o OBJS-$(CONFIG_GRADFUN_FILTER) += vf_gradfun.o +OBJS-$(CONFIG_GRAPHMONITOR_FILTER) += f_graphmonitor.o +OBJS-$(CONFIG_GREYEDGE_FILTER) += vf_colorconstancy.o OBJS-$(CONFIG_HALDCLUT_FILTER) += vf_lut3d.o framesync.o OBJS-$(CONFIG_HFLIP_FILTER) += vf_hflip.o OBJS-$(CONFIG_HISTEQ_FILTER) += vf_histeq.o @@ -231,14 +270,17 @@ OBJS-$(CONFIG_HYSTERESIS_FILTER) += vf_hysteresis.o framesync.o OBJS-$(CONFIG_IDET_FILTER) += vf_idet.o OBJS-$(CONFIG_IL_FILTER) += vf_il.o OBJS-$(CONFIG_INFLATE_FILTER) += vf_neighbor.o -OBJS-$(CONFIG_INTERLACE_FILTER) += vf_interlace.o +OBJS-$(CONFIG_INTERLACE_FILTER) += vf_tinterlace.o OBJS-$(CONFIG_INTERLEAVE_FILTER) += f_interleave.o OBJS-$(CONFIG_KERNDEINT_FILTER) += vf_kerndeint.o +OBJS-$(CONFIG_LAGFUN_FILTER) += vf_lagfun.o OBJS-$(CONFIG_LENSCORRECTION_FILTER) += vf_lenscorrection.o +OBJS-$(CONFIG_LENSFUN_FILTER) += vf_lensfun.o OBJS-$(CONFIG_LIBVMAF_FILTER) += vf_libvmaf.o framesync.o OBJS-$(CONFIG_LIMITER_FILTER) += vf_limiter.o OBJS-$(CONFIG_LOOP_FILTER) += f_loop.o OBJS-$(CONFIG_LUMAKEY_FILTER) += vf_lumakey.o +OBJS-$(CONFIG_LUT1D_FILTER) += vf_lut3d.o OBJS-$(CONFIG_LUT_FILTER) += vf_lut.o OBJS-$(CONFIG_LUT2_FILTER) += vf_lut2.o framesync.o OBJS-$(CONFIG_LUT3D_FILTER) += vf_lut3d.o @@ -246,6 +288,7 @@ OBJS-$(CONFIG_LUTRGB_FILTER) += vf_lut.o OBJS-$(CONFIG_LUTYUV_FILTER) += vf_lut.o OBJS-$(CONFIG_MASKEDCLAMP_FILTER) += vf_maskedclamp.o framesync.o OBJS-$(CONFIG_MASKEDMERGE_FILTER) += vf_maskedmerge.o framesync.o +OBJS-$(CONFIG_MASKFUN_FILTER) += vf_maskfun.o OBJS-$(CONFIG_MCDEINT_FILTER) += vf_mcdeint.o OBJS-$(CONFIG_MERGEPLANES_FILTER) += vf_mergeplanes.o framesync.o OBJS-$(CONFIG_MESTIMATE_FILTER) += vf_mestimate.o motion_estimation.o @@ -256,6 +299,7 @@ OBJS-$(CONFIG_MIX_FILTER) += vf_mix.o OBJS-$(CONFIG_MPDECIMATE_FILTER) += vf_mpdecimate.o OBJS-$(CONFIG_NEGATE_FILTER) += vf_lut.o OBJS-$(CONFIG_NLMEANS_FILTER) += vf_nlmeans.o +OBJS-$(CONFIG_NLMEANS_OPENCL_FILTER) += vf_nlmeans_opencl.o opencl.o opencl/nlmeans.o OBJS-$(CONFIG_NNEDI_FILTER) += vf_nnedi.o OBJS-$(CONFIG_NOFORMAT_FILTER) += vf_format.o OBJS-$(CONFIG_NOISE_FILTER) += vf_noise.o @@ -281,6 +325,8 @@ OBJS-$(CONFIG_PP_FILTER) += vf_pp.o OBJS-$(CONFIG_PP7_FILTER) += vf_pp7.o OBJS-$(CONFIG_PREMULTIPLY_FILTER) += vf_premultiply.o framesync.o OBJS-$(CONFIG_PREWITT_FILTER) += vf_convolution.o +OBJS-$(CONFIG_PREWITT_OPENCL_FILTER) += vf_convolution_opencl.o opencl.o \ + opencl/convolution.o OBJS-$(CONFIG_PROCAMP_VAAPI_FILTER) += vf_procamp_vaapi.o vaapi_vpp.o OBJS-$(CONFIG_PROGRAM_OPENCL_FILTER) += vf_program_opencl.o opencl.o framesync.o OBJS-$(CONFIG_PSEUDOCOLOR_FILTER) += vf_pseudocolor.o @@ -296,7 +342,10 @@ OBJS-$(CONFIG_REMOVEGRAIN_FILTER) += vf_removegrain.o OBJS-$(CONFIG_REMOVELOGO_FILTER) += bbox.o lswsutils.o lavfutils.o vf_removelogo.o OBJS-$(CONFIG_REPEATFIELDS_FILTER) += vf_repeatfields.o OBJS-$(CONFIG_REVERSE_FILTER) += f_reverse.o +OBJS-$(CONFIG_RGBASHIFT_FILTER) += vf_chromashift.o OBJS-$(CONFIG_ROBERTS_FILTER) += vf_convolution.o +OBJS-$(CONFIG_ROBERTS_OPENCL_FILTER) += vf_convolution_opencl.o opencl.o \ + opencl/convolution.o OBJS-$(CONFIG_ROTATE_FILTER) += vf_rotate.o OBJS-$(CONFIG_SAB_FILTER) += vf_sab.o OBJS-$(CONFIG_SCALE_FILTER) += vf_scale.o scale.o @@ -310,7 +359,8 @@ OBJS-$(CONFIG_SELECTIVECOLOR_FILTER) += vf_selectivecolor.o OBJS-$(CONFIG_SENDCMD_FILTER) += f_sendcmd.o OBJS-$(CONFIG_SEPARATEFIELDS_FILTER) += vf_separatefields.o OBJS-$(CONFIG_SETDAR_FILTER) += vf_aspect.o -OBJS-$(CONFIG_SETFIELD_FILTER) += vf_setfield.o +OBJS-$(CONFIG_SETFIELD_FILTER) += vf_setparams.o +OBJS-$(CONFIG_SETPARAMS_FILTER) += vf_setparams.o OBJS-$(CONFIG_SETPTS_FILTER) += setpts.o OBJS-$(CONFIG_SETRANGE_FILTER) += vf_setparams.o OBJS-$(CONFIG_SETSAR_FILTER) += vf_aspect.o @@ -325,8 +375,11 @@ OBJS-$(CONFIG_SIGNALSTATS_FILTER) += vf_signalstats.o OBJS-$(CONFIG_SIGNATURE_FILTER) += vf_signature.o OBJS-$(CONFIG_SMARTBLUR_FILTER) += vf_smartblur.o OBJS-$(CONFIG_SOBEL_FILTER) += vf_convolution.o +OBJS-$(CONFIG_SOBEL_OPENCL_FILTER) += vf_convolution_opencl.o opencl.o \ + opencl/convolution.o OBJS-$(CONFIG_SPLIT_FILTER) += split.o OBJS-$(CONFIG_SPP_FILTER) += vf_spp.o +OBJS-$(CONFIG_SR_FILTER) += vf_sr.o OBJS-$(CONFIG_SSIM_FILTER) += vf_ssim.o framesync.o OBJS-$(CONFIG_STEREO3D_FILTER) += vf_stereo3d.o OBJS-$(CONFIG_STREAMSELECT_FILTER) += f_streamselect.o framesync.o @@ -342,8 +395,15 @@ OBJS-$(CONFIG_THUMBNAIL_CUDA_FILTER) += vf_thumbnail_cuda.o vf_thumbnail OBJS-$(CONFIG_TILE_FILTER) += vf_tile.o OBJS-$(CONFIG_TINTERLACE_FILTER) += vf_tinterlace.o OBJS-$(CONFIG_TLUT2_FILTER) += vf_lut2.o framesync.o -OBJS-$(CONFIG_TONEMAP_FILTER) += vf_tonemap.o +OBJS-$(CONFIG_TMIX_FILTER) += vf_mix.o framesync.o +OBJS-$(CONFIG_TONEMAP_FILTER) += vf_tonemap.o colorspace.o +OBJS-$(CONFIG_TONEMAP_OPENCL_FILTER) += vf_tonemap_opencl.o colorspace.o opencl.o \ + opencl/tonemap.o opencl/colorspace_common.o +OBJS-$(CONFIG_TPAD_FILTER) += vf_tpad.o OBJS-$(CONFIG_TRANSPOSE_FILTER) += vf_transpose.o +OBJS-$(CONFIG_TRANSPOSE_NPP_FILTER) += vf_transpose_npp.o +OBJS-$(CONFIG_TRANSPOSE_OPENCL_FILTER) += vf_transpose_opencl.o opencl.o opencl/transpose.o +OBJS-$(CONFIG_TRANSPOSE_VAAPI_FILTER) += vf_transpose_vaapi.o vaapi_vpp.o OBJS-$(CONFIG_TRIM_FILTER) += trim.o OBJS-$(CONFIG_UNPREMULTIPLY_FILTER) += vf_premultiply.o framesync.o OBJS-$(CONFIG_UNSHARP_FILTER) += vf_unsharp.o @@ -354,6 +414,7 @@ OBJS-$(CONFIG_VAGUEDENOISER_FILTER) += vf_vaguedenoiser.o OBJS-$(CONFIG_VECTORSCOPE_FILTER) += vf_vectorscope.o OBJS-$(CONFIG_VFLIP_FILTER) += vf_vflip.o OBJS-$(CONFIG_VFRDET_FILTER) += vf_vfrdet.o +OBJS-$(CONFIG_VIBRANCE_FILTER) += vf_vibrance.o OBJS-$(CONFIG_VIDSTABDETECT_FILTER) += vidstabutils.o vf_vidstabdetect.o OBJS-$(CONFIG_VIDSTABTRANSFORM_FILTER) += vidstabutils.o vf_vidstabtransform.o OBJS-$(CONFIG_VIGNETTE_FILTER) += vf_vignette.o @@ -364,7 +425,11 @@ OBJS-$(CONFIG_W3FDIF_FILTER) += vf_w3fdif.o OBJS-$(CONFIG_WAVEFORM_FILTER) += vf_waveform.o OBJS-$(CONFIG_WEAVE_FILTER) += vf_weave.o OBJS-$(CONFIG_XBR_FILTER) += vf_xbr.o -OBJS-$(CONFIG_YADIF_FILTER) += vf_yadif.o +OBJS-$(CONFIG_XMEDIAN_FILTER) += vf_xmedian.o framesync.o +OBJS-$(CONFIG_XSTACK_FILTER) += vf_stack.o framesync.o +OBJS-$(CONFIG_YADIF_FILTER) += vf_yadif.o yadif_common.o +OBJS-$(CONFIG_YADIF_CUDA_FILTER) += vf_yadif_cuda.o vf_yadif_cuda.ptx.o \ + yadif_common.o OBJS-$(CONFIG_ZMQ_FILTER) += f_zmq.o OBJS-$(CONFIG_ZOOMPAN_FILTER) += vf_zoompan.o OBJS-$(CONFIG_ZSCALE_FILTER) += vf_zscale.o @@ -381,6 +446,8 @@ OBJS-$(CONFIG_MANDELBROT_FILTER) += vsrc_mandelbrot.o OBJS-$(CONFIG_MPTESTSRC_FILTER) += vsrc_mptestsrc.o OBJS-$(CONFIG_NULLSRC_FILTER) += vsrc_testsrc.o OBJS-$(CONFIG_OPENCLSRC_FILTER) += vf_program_opencl.o opencl.o +OBJS-$(CONFIG_PAL75BARS_FILTER) += vsrc_testsrc.o +OBJS-$(CONFIG_PAL100BARS_FILTER) += vsrc_testsrc.o OBJS-$(CONFIG_RGBTESTSRC_FILTER) += vsrc_testsrc.o OBJS-$(CONFIG_SMPTEBARS_FILTER) += vsrc_testsrc.o OBJS-$(CONFIG_SMPTEHDBARS_FILTER) += vsrc_testsrc.o @@ -393,12 +460,14 @@ OBJS-$(CONFIG_NULLSINK_FILTER) += vsink_nullsink.o # multimedia filters OBJS-$(CONFIG_ABITSCOPE_FILTER) += avf_abitscope.o OBJS-$(CONFIG_ADRAWGRAPH_FILTER) += f_drawgraph.o +OBJS-$(CONFIG_AGRAPHMONITOR_FILTER) += f_graphmonitor.o OBJS-$(CONFIG_AHISTOGRAM_FILTER) += avf_ahistogram.o OBJS-$(CONFIG_APHASEMETER_FILTER) += avf_aphasemeter.o OBJS-$(CONFIG_AVECTORSCOPE_FILTER) += avf_avectorscope.o OBJS-$(CONFIG_CONCAT_FILTER) += avf_concat.o OBJS-$(CONFIG_SHOWCQT_FILTER) += avf_showcqt.o lswsutils.o lavfutils.o OBJS-$(CONFIG_SHOWFREQS_FILTER) += avf_showfreqs.o +OBJS-$(CONFIG_SHOWSPATIAL_FILTER) += avf_showspatial.o OBJS-$(CONFIG_SHOWSPECTRUM_FILTER) += avf_showspectrum.o OBJS-$(CONFIG_SHOWSPECTRUMPIC_FILTER) += avf_showspectrum.o OBJS-$(CONFIG_SHOWVOLUME_FILTER) += avf_showvolume.o diff --git a/libavfilter/aarch64/Makefile b/libavfilter/aarch64/Makefile new file mode 100644 index 000000000..b58daa3a3 --- /dev/null +++ b/libavfilter/aarch64/Makefile @@ -0,0 +1,3 @@ +OBJS-$(CONFIG_NLMEANS_FILTER) += aarch64/vf_nlmeans_init.o + +NEON-OBJS-$(CONFIG_NLMEANS_FILTER) += aarch64/vf_nlmeans_neon.o diff --git a/libavfilter/aarch64/vf_nlmeans_init.c b/libavfilter/aarch64/vf_nlmeans_init.c new file mode 100644 index 000000000..a1edefb14 --- /dev/null +++ b/libavfilter/aarch64/vf_nlmeans_init.c @@ -0,0 +1,33 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/aarch64/cpu.h" +#include "libavfilter/vf_nlmeans.h" + +void ff_compute_safe_ssd_integral_image_neon(uint32_t *dst, ptrdiff_t dst_linesize_32, + const uint8_t *s1, ptrdiff_t linesize1, + const uint8_t *s2, ptrdiff_t linesize2, + int w, int h); + +av_cold void ff_nlmeans_init_aarch64(NLMeansDSPContext *dsp) +{ + int cpu_flags = av_get_cpu_flags(); + + if (have_neon(cpu_flags)) + dsp->compute_safe_ssd_integral_image = ff_compute_safe_ssd_integral_image_neon; +} diff --git a/libavfilter/aarch64/vf_nlmeans_neon.S b/libavfilter/aarch64/vf_nlmeans_neon.S new file mode 100644 index 000000000..e69b0dd92 --- /dev/null +++ b/libavfilter/aarch64/vf_nlmeans_neon.S @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2018 Clément Bœsch + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/aarch64/asm.S" + +// acc_sum_store(ABCD) = {X+A, X+A+B, X+A+B+C, X+A+B+C+D} +.macro acc_sum_store x, xb + dup v24.4S, v24.S[3] // ...X -> XXXX + ext v25.16B, v26.16B, \xb, #12 // ext(0000,ABCD,12)=0ABC + add v24.4S, v24.4S, \x // XXXX+ABCD={X+A,X+B,X+C,X+D} + add v24.4S, v24.4S, v25.4S // {X+A,X+B+A,X+C+B,X+D+C} (+0ABC) + ext v25.16B, v26.16B, v25.16B, #12 // ext(0000,0ABC,12)=00AB + add v24.4S, v24.4S, v25.4S // {X+A,X+B+A,X+C+B+A,X+D+C+B} (+00AB) + ext v25.16B, v26.16B, v25.16B, #12 // ext(0000,00AB,12)=000A + add v24.4S, v24.4S, v25.4S // {X+A,X+B+A,X+C+B+A,X+D+C+B+A} (+000A) + st1 {v24.4S}, [x0], #16 // write 4x32-bit final values +.endm + +function ff_compute_safe_ssd_integral_image_neon, export=1 + movi v26.4S, #0 // used as zero for the "rotations" in acc_sum_store + sub x3, x3, w6, UXTW // s1 padding (s1_linesize - w) + sub x5, x5, w6, UXTW // s2 padding (s2_linesize - w) + sub x9, x0, w1, UXTW #2 // dst_top + sub x1, x1, w6, UXTW // dst padding (dst_linesize_32 - w) + lsl x1, x1, #2 // dst padding expressed in bytes +1: mov w10, w6 // width copy for each line + sub x0, x0, #16 // beginning of the dst line minus 4 sums + sub x8, x9, #4 // dst_top-1 + ld1 {v24.4S}, [x0], #16 // load ...X (contextual last sums) +2: ld1 {v0.16B}, [x2], #16 // s1[x + 0..15] + ld1 {v1.16B}, [x4], #16 // s2[x + 0..15] + ld1 {v16.4S,v17.4S}, [x8], #32 // dst_top[x + 0..7 - 1] + usubl v2.8H, v0.8B, v1.8B // d[x + 0..7] = s1[x + 0..7] - s2[x + 0..7] + usubl2 v3.8H, v0.16B, v1.16B // d[x + 8..15] = s1[x + 8..15] - s2[x + 8..15] + ld1 {v18.4S,v19.4S}, [x8], #32 // dst_top[x + 8..15 - 1] + smull v4.4S, v2.4H, v2.4H // d[x + 0..3]^2 + smull2 v5.4S, v2.8H, v2.8H // d[x + 4..7]^2 + ld1 {v20.4S,v21.4S}, [x9], #32 // dst_top[x + 0..7] + smull v6.4S, v3.4H, v3.4H // d[x + 8..11]^2 + smull2 v7.4S, v3.8H, v3.8H // d[x + 12..15]^2 + ld1 {v22.4S,v23.4S}, [x9], #32 // dst_top[x + 8..15] + sub v0.4S, v20.4S, v16.4S // dst_top[x + 0..3] - dst_top[x + 0..3 - 1] + sub v1.4S, v21.4S, v17.4S // dst_top[x + 4..7] - dst_top[x + 4..7 - 1] + add v0.4S, v0.4S, v4.4S // + d[x + 0..3]^2 + add v1.4S, v1.4S, v5.4S // + d[x + 4..7]^2 + sub v2.4S, v22.4S, v18.4S // dst_top[x + 8..11] - dst_top[x + 8..11 - 1] + sub v3.4S, v23.4S, v19.4S // dst_top[x + 12..15] - dst_top[x + 12..15 - 1] + add v2.4S, v2.4S, v6.4S // + d[x + 8..11]^2 + add v3.4S, v3.4S, v7.4S // + d[x + 12..15]^2 + acc_sum_store v0.4S, v0.16B // accumulate and store dst[ 0..3] + acc_sum_store v1.4S, v1.16B // accumulate and store dst[ 4..7] + acc_sum_store v2.4S, v2.16B // accumulate and store dst[ 8..11] + acc_sum_store v3.4S, v3.16B // accumulate and store dst[12..15] + subs w10, w10, #16 // width dec + b.ne 2b // loop til next line + add x2, x2, x3 // skip to next line (s1) + add x4, x4, x5 // skip to next line (s2) + add x0, x0, x1 // skip to next line (dst) + add x9, x9, x1 // skip to next line (dst_top) + subs w7, w7, #1 // height dec + b.ne 1b + ret +endfunc diff --git a/libavfilter/af_acrossover.c b/libavfilter/af_acrossover.c new file mode 100644 index 000000000..3ccc4d72f --- /dev/null +++ b/libavfilter/af_acrossover.c @@ -0,0 +1,343 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * Crossover filter + * + * Split an audio stream into several bands. + */ + +#include "libavutil/attributes.h" +#include "libavutil/avstring.h" +#include "libavutil/channel_layout.h" +#include "libavutil/eval.h" +#include "libavutil/internal.h" +#include "libavutil/opt.h" + +#include "audio.h" +#include "avfilter.h" +#include "formats.h" +#include "internal.h" + +#define MAX_SPLITS 16 +#define MAX_BANDS MAX_SPLITS + 1 + +typedef struct BiquadContext { + double a0, a1, a2; + double b1, b2; + double i1, i2; + double o1, o2; +} BiquadContext; + +typedef struct CrossoverChannel { + BiquadContext lp[MAX_BANDS][4]; + BiquadContext hp[MAX_BANDS][4]; +} CrossoverChannel; + +typedef struct AudioCrossoverContext { + const AVClass *class; + + char *splits_str; + int order; + + int filter_count; + int nb_splits; + float *splits; + + CrossoverChannel *xover; +} AudioCrossoverContext; + +#define OFFSET(x) offsetof(AudioCrossoverContext, x) +#define AF AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_FILTERING_PARAM + +static const AVOption acrossover_options[] = { + { "split", "set split frequencies", OFFSET(splits_str), AV_OPT_TYPE_STRING, {.str="500"}, 0, 0, AF }, + { "order", "set order", OFFSET(order), AV_OPT_TYPE_INT, {.i64=1}, 0, 2, AF, "m" }, + { "2nd", "2nd order", 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, AF, "m" }, + { "4th", "4th order", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, AF, "m" }, + { "8th", "8th order", 0, AV_OPT_TYPE_CONST, {.i64=2}, 0, 0, AF, "m" }, + { NULL } +}; + +AVFILTER_DEFINE_CLASS(acrossover); + +static av_cold int init(AVFilterContext *ctx) +{ + AudioCrossoverContext *s = ctx->priv; + char *p, *arg, *saveptr = NULL; + int i, ret = 0; + + s->splits = av_calloc(MAX_SPLITS, sizeof(*s->splits)); + if (!s->splits) + return AVERROR(ENOMEM); + + p = s->splits_str; + for (i = 0; i < MAX_SPLITS; i++) { + float freq; + + if (!(arg = av_strtok(p, " |", &saveptr))) + break; + + p = NULL; + + av_sscanf(arg, "%f", &freq); + if (freq <= 0) { + av_log(ctx, AV_LOG_ERROR, "Frequency %f must be positive number.\n", freq); + return AVERROR(EINVAL); + } + + if (i > 0 && freq <= s->splits[i-1]) { + av_log(ctx, AV_LOG_ERROR, "Frequency %f must be in increasing order.\n", freq); + return AVERROR(EINVAL); + } + + s->splits[i] = freq; + } + + s->nb_splits = i; + + for (i = 0; i <= s->nb_splits; i++) { + AVFilterPad pad = { 0 }; + char *name; + + pad.type = AVMEDIA_TYPE_AUDIO; + name = av_asprintf("out%d", ctx->nb_outputs); + if (!name) + return AVERROR(ENOMEM); + pad.name = name; + + if ((ret = ff_insert_outpad(ctx, i, &pad)) < 0) { + av_freep(&pad.name); + return ret; + } + } + + return ret; +} + +static void set_lp(BiquadContext *b, float fc, float q, float sr) +{ + double omega = (2.0 * M_PI * fc / sr); + double sn = sin(omega); + double cs = cos(omega); + double alpha = (sn / (2 * q)); + double inv = (1.0 / (1.0 + alpha)); + + b->a2 = b->a0 = (inv * (1.0 - cs) * 0.5); + b->a1 = b->a0 + b->a0; + b->b1 = -2. * cs * inv; + b->b2 = (1. - alpha) * inv; +} + +static void set_hp(BiquadContext *b, float fc, float q, float sr) +{ + double omega = 2 * M_PI * fc / sr; + double sn = sin(omega); + double cs = cos(omega); + double alpha = sn / (2 * q); + double inv = 1.0 / (1.0 + alpha); + + b->a0 = inv * (1. + cs) / 2.; + b->a1 = -2. * b->a0; + b->a2 = b->a0; + b->b1 = -2. * cs * inv; + b->b2 = (1. - alpha) * inv; +} + +static int config_input(AVFilterLink *inlink) +{ + AVFilterContext *ctx = inlink->dst; + AudioCrossoverContext *s = ctx->priv; + int ch, band, sample_rate = inlink->sample_rate; + double q; + + s->xover = av_calloc(inlink->channels, sizeof(*s->xover)); + if (!s->xover) + return AVERROR(ENOMEM); + + switch (s->order) { + case 0: + q = 0.5; + s->filter_count = 1; + break; + case 1: + q = M_SQRT1_2; + s->filter_count = 2; + break; + case 2: + q = 0.54; + s->filter_count = 4; + break; + } + + for (ch = 0; ch < inlink->channels; ch++) { + for (band = 0; band <= s->nb_splits; band++) { + set_lp(&s->xover[ch].lp[band][0], s->splits[band], q, sample_rate); + set_hp(&s->xover[ch].hp[band][0], s->splits[band], q, sample_rate); + + if (s->order > 1) { + set_lp(&s->xover[ch].lp[band][1], s->splits[band], 1.34, sample_rate); + set_hp(&s->xover[ch].hp[band][1], s->splits[band], 1.34, sample_rate); + set_lp(&s->xover[ch].lp[band][2], s->splits[band], q, sample_rate); + set_hp(&s->xover[ch].hp[band][2], s->splits[band], q, sample_rate); + set_lp(&s->xover[ch].lp[band][3], s->splits[band], 1.34, sample_rate); + set_hp(&s->xover[ch].hp[band][3], s->splits[band], 1.34, sample_rate); + } else { + set_lp(&s->xover[ch].lp[band][1], s->splits[band], q, sample_rate); + set_hp(&s->xover[ch].hp[band][1], s->splits[band], q, sample_rate); + } + } + } + + return 0; +} + +static int query_formats(AVFilterContext *ctx) +{ + AVFilterFormats *formats; + AVFilterChannelLayouts *layouts; + static const enum AVSampleFormat sample_fmts[] = { + AV_SAMPLE_FMT_DBLP, + AV_SAMPLE_FMT_NONE + }; + int ret; + + layouts = ff_all_channel_counts(); + if (!layouts) + return AVERROR(ENOMEM); + ret = ff_set_common_channel_layouts(ctx, layouts); + if (ret < 0) + return ret; + + formats = ff_make_format_list(sample_fmts); + if (!formats) + return AVERROR(ENOMEM); + ret = ff_set_common_formats(ctx, formats); + if (ret < 0) + return ret; + + formats = ff_all_samplerates(); + if (!formats) + return AVERROR(ENOMEM); + return ff_set_common_samplerates(ctx, formats); +} + +static double biquad_process(BiquadContext *b, double in) +{ + double out = in * b->a0 + b->i1 * b->a1 + b->i2 * b->a2 - b->o1 * b->b1 - b->o2 * b->b2; + + b->i2 = b->i1; + b->o2 = b->o1; + b->i1 = in; + b->o1 = out; + + return out; +} + +static int filter_frame(AVFilterLink *inlink, AVFrame *in) +{ + AVFilterContext *ctx = inlink->dst; + AudioCrossoverContext *s = ctx->priv; + AVFrame *frames[MAX_BANDS] = { NULL }; + int i, f, ch, band, ret = 0; + + for (i = 0; i < ctx->nb_outputs; i++) { + frames[i] = ff_get_audio_buffer(ctx->outputs[i], in->nb_samples); + + if (!frames[i]) { + ret = AVERROR(ENOMEM); + break; + } + + frames[i]->pts = in->pts; + } + + if (ret < 0) + goto fail; + + for (ch = 0; ch < inlink->channels; ch++) { + const double *src = (const double *)in->extended_data[ch]; + CrossoverChannel *xover = &s->xover[ch]; + + for (band = 0; band < ctx->nb_outputs; band++) { + double *dst = (double *)frames[band]->extended_data[ch]; + + for (i = 0; i < in->nb_samples; i++) { + dst[i] = src[i]; + + for (f = 0; f < s->filter_count; f++) { + if (band + 1 < ctx->nb_outputs) { + BiquadContext *lp = &xover->lp[band][f]; + dst[i] = biquad_process(lp, dst[i]); + } + + if (band - 1 >= 0) { + BiquadContext *hp = &xover->hp[band - 1][f]; + dst[i] = biquad_process(hp, dst[i]); + } + } + } + } + } + + for (i = 0; i < ctx->nb_outputs; i++) { + ret = ff_filter_frame(ctx->outputs[i], frames[i]); + if (ret < 0) + break; + } + +fail: + av_frame_free(&in); + + return ret; +} + +static av_cold void uninit(AVFilterContext *ctx) +{ + AudioCrossoverContext *s = ctx->priv; + int i; + + av_freep(&s->splits); + + for (i = 0; i < ctx->nb_outputs; i++) + av_freep(&ctx->output_pads[i].name); +} + +static const AVFilterPad inputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_AUDIO, + .filter_frame = filter_frame, + .config_props = config_input, + }, + { NULL } +}; + +AVFilter ff_af_acrossover = { + .name = "acrossover", + .description = NULL_IF_CONFIG_SMALL("Split audio into per-bands streams."), + .priv_size = sizeof(AudioCrossoverContext), + .priv_class = &acrossover_class, + .init = init, + .uninit = uninit, + .query_formats = query_formats, + .inputs = inputs, + .outputs = NULL, + .flags = AVFILTER_FLAG_DYNAMIC_OUTPUTS, +}; diff --git a/libavfilter/af_adeclick.c b/libavfilter/af_adeclick.c new file mode 100644 index 000000000..50eef7492 --- /dev/null +++ b/libavfilter/af_adeclick.c @@ -0,0 +1,776 @@ +/* + * Copyright (c) 2018 Paul B Mahol + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/audio_fifo.h" +#include "libavutil/opt.h" +#include "avfilter.h" +#include "audio.h" +#include "filters.h" +#include "formats.h" +#include "internal.h" + +typedef struct DeclickChannel { + double *auxiliary; + double *detection; + double *acoefficients; + double *acorrelation; + double *tmp; + double *interpolated; + double *matrix; + int matrix_size; + double *vector; + int vector_size; + double *y; + int y_size; + uint8_t *click; + int *index; + unsigned *histogram; + int histogram_size; +} DeclickChannel; + +typedef struct AudioDeclickContext { + const AVClass *class; + + double w; + double overlap; + double threshold; + double ar; + double burst; + int method; + int nb_hbins; + + int is_declip; + int ar_order; + int nb_burst_samples; + int window_size; + int hop_size; + int overlap_skip; + + AVFrame *in; + AVFrame *out; + AVFrame *buffer; + AVFrame *is; + + DeclickChannel *chan; + + int64_t pts; + int nb_channels; + uint64_t nb_samples; + uint64_t detected_errors; + int samples_left; + int eof; + + AVAudioFifo *fifo; + double *window_func_lut; + + int (*detector)(struct AudioDeclickContext *s, DeclickChannel *c, + double sigmae, double *detection, + double *acoefficients, uint8_t *click, int *index, + const double *src, double *dst); +} AudioDeclickContext; + +#define OFFSET(x) offsetof(AudioDeclickContext, x) +#define AF AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM + +static const AVOption adeclick_options[] = { + { "w", "set window size", OFFSET(w), AV_OPT_TYPE_DOUBLE, {.dbl=55}, 10, 100, AF }, + { "o", "set window overlap", OFFSET(overlap), AV_OPT_TYPE_DOUBLE, {.dbl=75}, 50, 95, AF }, + { "a", "set autoregression order", OFFSET(ar), AV_OPT_TYPE_DOUBLE, {.dbl=2}, 0, 25, AF }, + { "t", "set threshold", OFFSET(threshold), AV_OPT_TYPE_DOUBLE, {.dbl=2}, 1, 100, AF }, + { "b", "set burst fusion", OFFSET(burst), AV_OPT_TYPE_DOUBLE, {.dbl=2}, 0, 10, AF }, + { "m", "set overlap method", OFFSET(method), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, AF, "m" }, + { "a", "overlap-add", 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, AF, "m" }, + { "s", "overlap-save", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, AF, "m" }, + { NULL } +}; + +AVFILTER_DEFINE_CLASS(adeclick); + +static int query_formats(AVFilterContext *ctx) +{ + AVFilterFormats *formats = NULL; + AVFilterChannelLayouts *layouts = NULL; + static const enum AVSampleFormat sample_fmts[] = { + AV_SAMPLE_FMT_DBLP, + AV_SAMPLE_FMT_NONE + }; + int ret; + + formats = ff_make_format_list(sample_fmts); + if (!formats) + return AVERROR(ENOMEM); + ret = ff_set_common_formats(ctx, formats); + if (ret < 0) + return ret; + + layouts = ff_all_channel_counts(); + if (!layouts) + return AVERROR(ENOMEM); + + ret = ff_set_common_channel_layouts(ctx, layouts); + if (ret < 0) + return ret; + + formats = ff_all_samplerates(); + return ff_set_common_samplerates(ctx, formats); +} + +static int config_input(AVFilterLink *inlink) +{ + AVFilterContext *ctx = inlink->dst; + AudioDeclickContext *s = ctx->priv; + int i; + + s->pts = AV_NOPTS_VALUE; + s->window_size = inlink->sample_rate * s->w / 1000.; + if (s->window_size < 100) + return AVERROR(EINVAL); + s->ar_order = FFMAX(s->window_size * s->ar / 100., 1); + s->nb_burst_samples = s->window_size * s->burst / 1000.; + s->hop_size = s->window_size * (1. - (s->overlap / 100.)); + if (s->hop_size < 1) + return AVERROR(EINVAL); + + s->window_func_lut = av_calloc(s->window_size, sizeof(*s->window_func_lut)); + if (!s->window_func_lut) + return AVERROR(ENOMEM); + for (i = 0; i < s->window_size; i++) + s->window_func_lut[i] = sin(M_PI * i / s->window_size) * + (1. - (s->overlap / 100.)) * M_PI_2; + + av_frame_free(&s->in); + av_frame_free(&s->out); + av_frame_free(&s->buffer); + av_frame_free(&s->is); + s->in = ff_get_audio_buffer(inlink, s->window_size); + s->out = ff_get_audio_buffer(inlink, s->window_size); + s->buffer = ff_get_audio_buffer(inlink, s->window_size * 2); + s->is = ff_get_audio_buffer(inlink, s->window_size); + if (!s->in || !s->out || !s->buffer || !s->is) + return AVERROR(ENOMEM); + + s->fifo = av_audio_fifo_alloc(inlink->format, inlink->channels, s->window_size); + if (!s->fifo) + return AVERROR(ENOMEM); + s->overlap_skip = s->method ? (s->window_size - s->hop_size) / 2 : 0; + if (s->overlap_skip > 0) { + av_audio_fifo_write(s->fifo, (void **)s->in->extended_data, + s->overlap_skip); + } + + s->nb_channels = inlink->channels; + s->chan = av_calloc(inlink->channels, sizeof(*s->chan)); + if (!s->chan) + return AVERROR(ENOMEM); + + for (i = 0; i < inlink->channels; i++) { + DeclickChannel *c = &s->chan[i]; + + c->detection = av_calloc(s->window_size, sizeof(*c->detection)); + c->auxiliary = av_calloc(s->ar_order + 1, sizeof(*c->auxiliary)); + c->acoefficients = av_calloc(s->ar_order + 1, sizeof(*c->acoefficients)); + c->acorrelation = av_calloc(s->ar_order + 1, sizeof(*c->acorrelation)); + c->tmp = av_calloc(s->ar_order, sizeof(*c->tmp)); + c->click = av_calloc(s->window_size, sizeof(*c->click)); + c->index = av_calloc(s->window_size, sizeof(*c->index)); + c->interpolated = av_calloc(s->window_size, sizeof(*c->interpolated)); + if (!c->auxiliary || !c->acoefficients || !c->detection || !c->click || + !c->index || !c->interpolated || !c->acorrelation || !c->tmp) + return AVERROR(ENOMEM); + } + + return 0; +} + +static void autocorrelation(const double *input, int order, int size, + double *output, double scale) +{ + int i, j; + + for (i = 0; i <= order; i++) { + double value = 0.; + + for (j = i; j < size; j++) + value += input[j] * input[j - i]; + + output[i] = value * scale; + } +} + +static double autoregression(const double *samples, int ar_order, + int nb_samples, double *k, double *r, double *a) +{ + double alpha; + int i, j; + + memset(a, 0, ar_order * sizeof(*a)); + + autocorrelation(samples, ar_order, nb_samples, r, 1. / nb_samples); + + /* Levinson-Durbin algorithm */ + k[0] = a[0] = -r[1] / r[0]; + alpha = r[0] * (1. - k[0] * k[0]); + for (i = 1; i < ar_order; i++) { + double epsilon = 0.; + + for (j = 0; j < i; j++) + epsilon += a[j] * r[i - j]; + epsilon += r[i + 1]; + + k[i] = -epsilon / alpha; + alpha *= (1. - k[i] * k[i]); + for (j = i - 1; j >= 0; j--) + k[j] = a[j] + k[i] * a[i - j - 1]; + for (j = 0; j <= i; j++) + a[j] = k[j]; + } + + k[0] = 1.; + for (i = 1; i <= ar_order; i++) + k[i] = a[i - 1]; + + return sqrt(alpha); +} + +static int isfinite_array(double *samples, int nb_samples) +{ + int i; + + for (i = 0; i < nb_samples; i++) + if (!isfinite(samples[i])) + return 0; + + return 1; +} + +static int find_index(int *index, int value, int size) +{ + int i, start, end; + + if ((value < index[0]) || (value > index[size - 1])) + return 1; + + i = start = 0; + end = size - 1; + + while (start <= end) { + i = (end + start) / 2; + if (index[i] == value) + return 0; + if (value < index[i]) + end = i - 1; + if (value > index[i]) + start = i + 1; + } + + return 1; +} + +static int factorization(double *matrix, int n) +{ + int i, j, k; + + for (i = 0; i < n; i++) { + const int in = i * n; + double value; + + value = matrix[in + i]; + for (j = 0; j < i; j++) + value -= matrix[j * n + j] * matrix[in + j] * matrix[in + j]; + + if (value == 0.) { + return -1; + } + + matrix[in + i] = value; + for (j = i + 1; j < n; j++) { + const int jn = j * n; + double x; + + x = matrix[jn + i]; + for (k = 0; k < i; k++) + x -= matrix[k * n + k] * matrix[in + k] * matrix[jn + k]; + matrix[jn + i] = x / matrix[in + i]; + } + } + + return 0; +} + +static int do_interpolation(DeclickChannel *c, double *matrix, + double *vector, int n, double *out) +{ + int i, j, ret; + double *y; + + ret = factorization(matrix, n); + if (ret < 0) + return ret; + + av_fast_malloc(&c->y, &c->y_size, n * sizeof(*c->y)); + y = c->y; + if (!y) + return AVERROR(ENOMEM); + + for (i = 0; i < n; i++) { + const int in = i * n; + double value; + + value = vector[i]; + for (j = 0; j < i; j++) + value -= matrix[in + j] * y[j]; + y[i] = value; + } + + for (i = n - 1; i >= 0; i--) { + out[i] = y[i] / matrix[i * n + i]; + for (j = i + 1; j < n; j++) + out[i] -= matrix[j * n + i] * out[j]; + } + + return 0; +} + +static int interpolation(DeclickChannel *c, const double *src, int ar_order, + double *acoefficients, int *index, int nb_errors, + double *auxiliary, double *interpolated) +{ + double *vector, *matrix; + int i, j; + + av_fast_malloc(&c->matrix, &c->matrix_size, nb_errors * nb_errors * sizeof(*c->matrix)); + matrix = c->matrix; + if (!matrix) + return AVERROR(ENOMEM); + + av_fast_malloc(&c->vector, &c->vector_size, nb_errors * sizeof(*c->vector)); + vector = c->vector; + if (!vector) + return AVERROR(ENOMEM); + + autocorrelation(acoefficients, ar_order, ar_order + 1, auxiliary, 1.); + + for (i = 0; i < nb_errors; i++) { + const int im = i * nb_errors; + + for (j = i; j < nb_errors; j++) { + if (abs(index[j] - index[i]) <= ar_order) { + matrix[j * nb_errors + i] = matrix[im + j] = auxiliary[abs(index[j] - index[i])]; + } else { + matrix[j * nb_errors + i] = matrix[im + j] = 0; + } + } + } + + for (i = 0; i < nb_errors; i++) { + double value = 0.; + + for (j = -ar_order; j <= ar_order; j++) + if (find_index(index, index[i] - j, nb_errors)) + value -= src[index[i] - j] * auxiliary[abs(j)]; + + vector[i] = value; + } + + return do_interpolation(c, matrix, vector, nb_errors, interpolated); +} + +static int detect_clips(AudioDeclickContext *s, DeclickChannel *c, + double unused0, + double *unused1, double *unused2, + uint8_t *clip, int *index, + const double *src, double *dst) +{ + const double threshold = s->threshold; + double max_amplitude = 0; + unsigned *histogram; + int i, nb_clips = 0; + + av_fast_malloc(&c->histogram, &c->histogram_size, s->nb_hbins * sizeof(*c->histogram)); + if (!c->histogram) + return AVERROR(ENOMEM); + histogram = c->histogram; + memset(histogram, 0, sizeof(*histogram) * s->nb_hbins); + + for (i = 0; i < s->window_size; i++) { + const unsigned index = fmin(fabs(src[i]), 1) * (s->nb_hbins - 1); + + histogram[index]++; + dst[i] = src[i]; + clip[i] = 0; + } + + for (i = s->nb_hbins - 1; i > 1; i--) { + if (histogram[i]) { + if (histogram[i] / (double)FFMAX(histogram[i - 1], 1) > threshold) { + max_amplitude = i / (double)s->nb_hbins; + } + break; + } + } + + if (max_amplitude > 0.) { + for (i = 0; i < s->window_size; i++) { + clip[i] = fabs(src[i]) >= max_amplitude; + } + } + + memset(clip, 0, s->ar_order * sizeof(*clip)); + memset(clip + (s->window_size - s->ar_order), 0, s->ar_order * sizeof(*clip)); + + for (i = s->ar_order; i < s->window_size - s->ar_order; i++) + if (clip[i]) + index[nb_clips++] = i; + + return nb_clips; +} + +static int detect_clicks(AudioDeclickContext *s, DeclickChannel *c, + double sigmae, + double *detection, double *acoefficients, + uint8_t *click, int *index, + const double *src, double *dst) +{ + const double threshold = s->threshold; + int i, j, nb_clicks = 0, prev = -1; + + memset(detection, 0, s->window_size * sizeof(*detection)); + + for (i = s->ar_order; i < s->window_size; i++) { + for (j = 0; j <= s->ar_order; j++) { + detection[i] += acoefficients[j] * src[i - j]; + } + } + + for (i = 0; i < s->window_size; i++) { + click[i] = fabs(detection[i]) > sigmae * threshold; + dst[i] = src[i]; + } + + for (i = 0; i < s->window_size; i++) { + if (!click[i]) + continue; + + if (prev >= 0 && (i > prev + 1) && (i <= s->nb_burst_samples + prev)) + for (j = prev + 1; j < i; j++) + click[j] = 1; + prev = i; + } + + memset(click, 0, s->ar_order * sizeof(*click)); + memset(click + (s->window_size - s->ar_order), 0, s->ar_order * sizeof(*click)); + + for (i = s->ar_order; i < s->window_size - s->ar_order; i++) + if (click[i]) + index[nb_clicks++] = i; + + return nb_clicks; +} + +typedef struct ThreadData { + AVFrame *out; +} ThreadData; + +static int filter_channel(AVFilterContext *ctx, void *arg, int ch, int nb_jobs) +{ + AudioDeclickContext *s = ctx->priv; + ThreadData *td = arg; + AVFrame *out = td->out; + const double *src = (const double *)s->in->extended_data[ch]; + double *is = (double *)s->is->extended_data[ch]; + double *dst = (double *)s->out->extended_data[ch]; + double *ptr = (double *)out->extended_data[ch]; + double *buf = (double *)s->buffer->extended_data[ch]; + const double *w = s->window_func_lut; + DeclickChannel *c = &s->chan[ch]; + double sigmae; + int j, ret; + + sigmae = autoregression(src, s->ar_order, s->window_size, c->acoefficients, c->acorrelation, c->tmp); + + if (isfinite_array(c->acoefficients, s->ar_order + 1)) { + double *interpolated = c->interpolated; + int *index = c->index; + int nb_errors; + + nb_errors = s->detector(s, c, sigmae, c->detection, c->acoefficients, + c->click, index, src, dst); + if (nb_errors > 0) { + ret = interpolation(c, src, s->ar_order, c->acoefficients, index, + nb_errors, c->auxiliary, interpolated); + if (ret < 0) + return ret; + + for (j = 0; j < nb_errors; j++) { + dst[index[j]] = interpolated[j]; + is[index[j]] = 1; + } + } + } else { + memcpy(dst, src, s->window_size * sizeof(*dst)); + } + + if (s->method == 0) { + for (j = 0; j < s->window_size; j++) + buf[j] += dst[j] * w[j]; + } else { + const int skip = s->overlap_skip; + + for (j = 0; j < s->hop_size; j++) + buf[j] = dst[skip + j]; + } + for (j = 0; j < s->hop_size; j++) + ptr[j] = buf[j]; + + memmove(buf, buf + s->hop_size, (s->window_size * 2 - s->hop_size) * sizeof(*buf)); + memmove(is, is + s->hop_size, (s->window_size - s->hop_size) * sizeof(*is)); + memset(buf + s->window_size * 2 - s->hop_size, 0, s->hop_size * sizeof(*buf)); + memset(is + s->window_size - s->hop_size, 0, s->hop_size * sizeof(*is)); + + return 0; +} + +static int filter_frame(AVFilterLink *inlink) +{ + AVFilterContext *ctx = inlink->dst; + AVFilterLink *outlink = ctx->outputs[0]; + AudioDeclickContext *s = ctx->priv; + AVFrame *out = NULL; + int ret = 0, j, ch, detected_errors = 0; + ThreadData td; + + out = ff_get_audio_buffer(outlink, s->hop_size); + if (!out) + return AVERROR(ENOMEM); + + ret = av_audio_fifo_peek(s->fifo, (void **)s->in->extended_data, + s->window_size); + if (ret < 0) + goto fail; + + td.out = out; + ret = ctx->internal->execute(ctx, filter_channel, &td, NULL, inlink->channels); + if (ret < 0) + goto fail; + + for (ch = 0; ch < s->in->channels; ch++) { + double *is = (double *)s->is->extended_data[ch]; + + for (j = 0; j < s->hop_size; j++) { + if (is[j]) + detected_errors++; + } + } + + av_audio_fifo_drain(s->fifo, s->hop_size); + + if (s->samples_left > 0) + out->nb_samples = FFMIN(s->hop_size, s->samples_left); + + out->pts = s->pts; + s->pts += s->hop_size; + + s->detected_errors += detected_errors; + s->nb_samples += out->nb_samples * inlink->channels; + + ret = ff_filter_frame(outlink, out); + if (ret < 0) + goto fail; + + if (s->samples_left > 0) { + s->samples_left -= s->hop_size; + if (s->samples_left <= 0) + av_audio_fifo_drain(s->fifo, av_audio_fifo_size(s->fifo)); + } + +fail: + if (ret < 0) + av_frame_free(&out); + return ret; +} + +static int activate(AVFilterContext *ctx) +{ + AVFilterLink *inlink = ctx->inputs[0]; + AVFilterLink *outlink = ctx->outputs[0]; + AudioDeclickContext *s = ctx->priv; + AVFrame *in; + int ret, status; + int64_t pts; + + FF_FILTER_FORWARD_STATUS_BACK(outlink, inlink); + + ret = ff_inlink_consume_samples(inlink, s->window_size, s->window_size, &in); + if (ret < 0) + return ret; + if (ret > 0) { + if (s->pts == AV_NOPTS_VALUE) + s->pts = in->pts; + + ret = av_audio_fifo_write(s->fifo, (void **)in->extended_data, + in->nb_samples); + av_frame_free(&in); + if (ret < 0) + return ret; + } + + if (av_audio_fifo_size(s->fifo) >= s->window_size || + s->samples_left > 0) + return filter_frame(inlink); + + if (av_audio_fifo_size(s->fifo) >= s->window_size) { + ff_filter_set_ready(ctx, 100); + return 0; + } + + if (!s->eof && ff_inlink_acknowledge_status(inlink, &status, &pts)) { + if (status == AVERROR_EOF) { + s->eof = 1; + s->samples_left = av_audio_fifo_size(s->fifo) - s->overlap_skip; + ff_filter_set_ready(ctx, 100); + return 0; + } + } + + if (s->eof && s->samples_left <= 0) { + ff_outlink_set_status(outlink, AVERROR_EOF, s->pts); + return 0; + } + + if (!s->eof) + FF_FILTER_FORWARD_WANTED(outlink, inlink); + + return FFERROR_NOT_READY; +} + +static av_cold int init(AVFilterContext *ctx) +{ + AudioDeclickContext *s = ctx->priv; + + s->is_declip = !strcmp(ctx->filter->name, "adeclip"); + if (s->is_declip) { + s->detector = detect_clips; + } else { + s->detector = detect_clicks; + } + + return 0; +} + +static av_cold void uninit(AVFilterContext *ctx) +{ + AudioDeclickContext *s = ctx->priv; + int i; + + av_log(ctx, AV_LOG_INFO, "Detected %s in %"PRId64" of %"PRId64" samples (%g%%).\n", + s->is_declip ? "clips" : "clicks", s->detected_errors, + s->nb_samples, 100. * s->detected_errors / s->nb_samples); + + av_audio_fifo_free(s->fifo); + av_freep(&s->window_func_lut); + av_frame_free(&s->in); + av_frame_free(&s->out); + av_frame_free(&s->buffer); + av_frame_free(&s->is); + + if (s->chan) { + for (i = 0; i < s->nb_channels; i++) { + DeclickChannel *c = &s->chan[i]; + + av_freep(&c->detection); + av_freep(&c->auxiliary); + av_freep(&c->acoefficients); + av_freep(&c->acorrelation); + av_freep(&c->tmp); + av_freep(&c->click); + av_freep(&c->index); + av_freep(&c->interpolated); + av_freep(&c->matrix); + c->matrix_size = 0; + av_freep(&c->histogram); + c->histogram_size = 0; + av_freep(&c->vector); + c->vector_size = 0; + av_freep(&c->y); + c->y_size = 0; + } + } + av_freep(&s->chan); + s->nb_channels = 0; +} + +static const AVFilterPad inputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_AUDIO, + .config_props = config_input, + }, + { NULL } +}; + +static const AVFilterPad outputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_AUDIO, + }, + { NULL } +}; + +AVFilter ff_af_adeclick = { + .name = "adeclick", + .description = NULL_IF_CONFIG_SMALL("Remove impulsive noise from input audio."), + .query_formats = query_formats, + .priv_size = sizeof(AudioDeclickContext), + .priv_class = &adeclick_class, + .init = init, + .activate = activate, + .uninit = uninit, + .inputs = inputs, + .outputs = outputs, + .flags = AVFILTER_FLAG_SLICE_THREADS, +}; + +static const AVOption adeclip_options[] = { + { "w", "set window size", OFFSET(w), AV_OPT_TYPE_DOUBLE, {.dbl=55}, 10, 100, AF }, + { "o", "set window overlap", OFFSET(overlap), AV_OPT_TYPE_DOUBLE, {.dbl=75}, 50, 95, AF }, + { "a", "set autoregression order", OFFSET(ar), AV_OPT_TYPE_DOUBLE, {.dbl=8}, 0, 25, AF }, + { "t", "set threshold", OFFSET(threshold), AV_OPT_TYPE_DOUBLE, {.dbl=10}, 1, 100, AF }, + { "n", "set histogram size", OFFSET(nb_hbins), AV_OPT_TYPE_INT, {.i64=1000}, 100, 9999, AF }, + { "m", "set overlap method", OFFSET(method), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, AF, "m" }, + { "a", "overlap-add", 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, AF, "m" }, + { "s", "overlap-save", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, AF, "m" }, + { NULL } +}; + +AVFILTER_DEFINE_CLASS(adeclip); + +AVFilter ff_af_adeclip = { + .name = "adeclip", + .description = NULL_IF_CONFIG_SMALL("Remove clipping from input audio."), + .query_formats = query_formats, + .priv_size = sizeof(AudioDeclickContext), + .priv_class = &adeclip_class, + .init = init, + .activate = activate, + .uninit = uninit, + .inputs = inputs, + .outputs = outputs, + .flags = AVFILTER_FLAG_SLICE_THREADS, +}; diff --git a/libavfilter/af_adelay.c b/libavfilter/af_adelay.c index d6d81ba7d..eb9703956 100644 --- a/libavfilter/af_adelay.c +++ b/libavfilter/af_adelay.c @@ -19,10 +19,12 @@ */ #include "libavutil/avstring.h" +#include "libavutil/eval.h" #include "libavutil/opt.h" #include "libavutil/samplefmt.h" #include "avfilter.h" #include "audio.h" +#include "filters.h" #include "internal.h" typedef struct ChanDelay { @@ -38,8 +40,10 @@ typedef struct AudioDelayContext { ChanDelay *chandelay; int nb_delays; int block_align; - unsigned max_delay; + int64_t padding; + int64_t max_delay; int64_t next_pts; + int eof; void (*delay_channel)(ChanDelay *d, int nb_samples, const uint8_t *src, uint8_t *dst); @@ -137,7 +141,7 @@ static int config_input(AVFilterLink *inlink) p = s->delays; for (i = 0; i < s->nb_delays; i++) { ChanDelay *d = &s->chandelay[i]; - float delay; + float delay, div; char type = 0; int ret; @@ -146,10 +150,11 @@ static int config_input(AVFilterLink *inlink) p = NULL; - ret = sscanf(arg, "%d%c", &d->delay, &type); + ret = av_sscanf(arg, "%d%c", &d->delay, &type); if (ret != 2 || type != 'S') { - sscanf(arg, "%f", &delay); - d->delay = delay * inlink->sample_rate / 1000.0; + div = type == 's' ? 1.0 : 1000.0; + av_sscanf(arg, "%f", &delay); + d->delay = delay * inlink->sample_rate / div; } if (d->delay < 0) { @@ -158,6 +163,21 @@ static int config_input(AVFilterLink *inlink) } } + s->padding = s->chandelay[0].delay; + for (i = 1; i < s->nb_delays; i++) { + ChanDelay *d = &s->chandelay[i]; + + s->padding = FFMIN(s->padding, d->delay); + } + + if (s->padding) { + for (i = 0; i < s->nb_delays; i++) { + ChanDelay *d = &s->chandelay[i]; + + d->delay -= s->padding; + } + } + for (i = 0; i < s->nb_delays; i++) { ChanDelay *d = &s->chandelay[i]; @@ -210,21 +230,57 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame) s->delay_channel(d, frame->nb_samples, src, dst); } - s->next_pts = frame->pts + av_rescale_q(frame->nb_samples, (AVRational){1, inlink->sample_rate}, inlink->time_base); + out_frame->pts = s->next_pts; + s->next_pts += av_rescale_q(frame->nb_samples, (AVRational){1, inlink->sample_rate}, inlink->time_base); av_frame_free(&frame); return ff_filter_frame(ctx->outputs[0], out_frame); } -static int request_frame(AVFilterLink *outlink) +static int activate(AVFilterContext *ctx) { - AVFilterContext *ctx = outlink->src; + AVFilterLink *inlink = ctx->inputs[0]; + AVFilterLink *outlink = ctx->outputs[0]; AudioDelayContext *s = ctx->priv; - int ret; + AVFrame *frame = NULL; + int ret, status; + int64_t pts; - ret = ff_request_frame(ctx->inputs[0]); - if (ret == AVERROR_EOF && !ctx->is_disabled && s->max_delay) { + FF_FILTER_FORWARD_STATUS_BACK(outlink, inlink); + + if (s->padding) { + int nb_samples = FFMIN(s->padding, 2048); + + frame = ff_get_audio_buffer(outlink, nb_samples); + if (!frame) + return AVERROR(ENOMEM); + s->padding -= nb_samples; + + av_samples_set_silence(frame->extended_data, 0, + frame->nb_samples, + outlink->channels, + frame->format); + + frame->pts = s->next_pts; + if (s->next_pts != AV_NOPTS_VALUE) + s->next_pts += av_rescale_q(nb_samples, (AVRational){1, outlink->sample_rate}, outlink->time_base); + + return ff_filter_frame(outlink, frame); + } + + ret = ff_inlink_consume_frame(inlink, &frame); + if (ret < 0) + return ret; + + if (ret > 0) + return filter_frame(inlink, frame); + + if (ff_inlink_acknowledge_status(inlink, &status, &pts)) { + if (status == AVERROR_EOF) + s->eof = 1; + } + + if (s->eof && s->max_delay) { int nb_samples = FFMIN(s->max_delay, 2048); - AVFrame *frame; frame = ff_get_audio_buffer(outlink, nb_samples); if (!frame) @@ -237,22 +293,28 @@ static int request_frame(AVFilterLink *outlink) frame->format); frame->pts = s->next_pts; - if (s->next_pts != AV_NOPTS_VALUE) - s->next_pts += av_rescale_q(nb_samples, (AVRational){1, outlink->sample_rate}, outlink->time_base); - - ret = filter_frame(ctx->inputs[0], frame); + return filter_frame(inlink, frame); } - return ret; + if (s->eof && s->max_delay == 0) { + ff_outlink_set_status(outlink, AVERROR_EOF, s->next_pts); + return 0; + } + + if (!s->eof) + FF_FILTER_FORWARD_WANTED(outlink, inlink); + + return FFERROR_NOT_READY; } static av_cold void uninit(AVFilterContext *ctx) { AudioDelayContext *s = ctx->priv; - int i; - for (i = 0; i < s->nb_delays; i++) - av_freep(&s->chandelay[i].samples); + if (s->chandelay) { + for (int i = 0; i < s->nb_delays; i++) + av_freep(&s->chandelay[i].samples); + } av_freep(&s->chandelay); } @@ -261,16 +323,14 @@ static const AVFilterPad adelay_inputs[] = { .name = "default", .type = AVMEDIA_TYPE_AUDIO, .config_props = config_input, - .filter_frame = filter_frame, }, { NULL } }; static const AVFilterPad adelay_outputs[] = { { - .name = "default", - .request_frame = request_frame, - .type = AVMEDIA_TYPE_AUDIO, + .name = "default", + .type = AVMEDIA_TYPE_AUDIO, }, { NULL } }; @@ -281,6 +341,7 @@ AVFilter ff_af_adelay = { .query_formats = query_formats, .priv_size = sizeof(AudioDelayContext), .priv_class = &adelay_class, + .activate = activate, .uninit = uninit, .inputs = adelay_inputs, .outputs = adelay_outputs, diff --git a/libavfilter/af_aderivative.c b/libavfilter/af_aderivative.c new file mode 100644 index 000000000..a591515cb --- /dev/null +++ b/libavfilter/af_aderivative.c @@ -0,0 +1,207 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "audio.h" +#include "avfilter.h" +#include "internal.h" + +typedef struct ADerivativeContext { + const AVClass *class; + AVFrame *prev; + void (*filter)(void **dst, void **prv, const void **src, + int nb_samples, int channels); +} ADerivativeContext; + +static int query_formats(AVFilterContext *ctx) +{ + AVFilterFormats *formats = NULL; + AVFilterChannelLayouts *layouts = NULL; + static const enum AVSampleFormat derivative_sample_fmts[] = { + AV_SAMPLE_FMT_S16P, AV_SAMPLE_FMT_FLTP, + AV_SAMPLE_FMT_S32P, AV_SAMPLE_FMT_DBLP, + AV_SAMPLE_FMT_NONE + }; + static const enum AVSampleFormat integral_sample_fmts[] = { + AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_DBLP, + AV_SAMPLE_FMT_NONE + }; + int ret; + + formats = ff_make_format_list(strcmp(ctx->filter->name, "aintegral") ? + derivative_sample_fmts : integral_sample_fmts); + if (!formats) + return AVERROR(ENOMEM); + ret = ff_set_common_formats(ctx, formats); + if (ret < 0) + return ret; + + layouts = ff_all_channel_counts(); + if (!layouts) + return AVERROR(ENOMEM); + + ret = ff_set_common_channel_layouts(ctx, layouts); + if (ret < 0) + return ret; + + formats = ff_all_samplerates(); + return ff_set_common_samplerates(ctx, formats); +} + +#define DERIVATIVE(name, type) \ +static void aderivative_## name ##p(void **d, void **p, const void **s, \ + int nb_samples, int channels) \ +{ \ + int n, c; \ + \ + for (c = 0; c < channels; c++) { \ + const type *src = s[c]; \ + type *dst = d[c]; \ + type *prv = p[c]; \ + \ + for (n = 0; n < nb_samples; n++) { \ + const type current = src[n]; \ + \ + dst[n] = current - prv[0]; \ + prv[0] = current; \ + } \ + } \ +} + +DERIVATIVE(flt, float) +DERIVATIVE(dbl, double) +DERIVATIVE(s16, int16_t) +DERIVATIVE(s32, int32_t) + +#define INTEGRAL(name, type) \ +static void aintegral_## name ##p(void **d, void **p, const void **s, \ + int nb_samples, int channels) \ +{ \ + int n, c; \ + \ + for (c = 0; c < channels; c++) { \ + const type *src = s[c]; \ + type *dst = d[c]; \ + type *prv = p[c]; \ + \ + for (n = 0; n < nb_samples; n++) { \ + const type current = src[n]; \ + \ + dst[n] = current + prv[0]; \ + prv[0] = dst[n]; \ + } \ + } \ +} + +INTEGRAL(flt, float) +INTEGRAL(dbl, double) + +static int config_input(AVFilterLink *inlink) +{ + AVFilterContext *ctx = inlink->dst; + ADerivativeContext *s = ctx->priv; + + switch (inlink->format) { + case AV_SAMPLE_FMT_FLTP: s->filter = aderivative_fltp; break; + case AV_SAMPLE_FMT_DBLP: s->filter = aderivative_dblp; break; + case AV_SAMPLE_FMT_S32P: s->filter = aderivative_s32p; break; + case AV_SAMPLE_FMT_S16P: s->filter = aderivative_s16p; break; + } + + if (strcmp(ctx->filter->name, "aintegral")) + return 0; + + switch (inlink->format) { + case AV_SAMPLE_FMT_FLTP: s->filter = aintegral_fltp; break; + case AV_SAMPLE_FMT_DBLP: s->filter = aintegral_dblp; break; + } + + return 0; +} + +static int filter_frame(AVFilterLink *inlink, AVFrame *in) +{ + AVFilterContext *ctx = inlink->dst; + ADerivativeContext *s = ctx->priv; + AVFilterLink *outlink = ctx->outputs[0]; + AVFrame *out = ff_get_audio_buffer(outlink, in->nb_samples); + + if (!out) { + av_frame_free(&in); + return AVERROR(ENOMEM); + } + av_frame_copy_props(out, in); + + if (!s->prev) { + s->prev = ff_get_audio_buffer(inlink, 1); + if (!s->prev) { + av_frame_free(&in); + return AVERROR(ENOMEM); + } + } + + s->filter((void **)out->extended_data, (void **)s->prev->extended_data, (const void **)in->extended_data, + in->nb_samples, in->channels); + + av_frame_free(&in); + return ff_filter_frame(outlink, out); +} + +static av_cold void uninit(AVFilterContext *ctx) +{ + ADerivativeContext *s = ctx->priv; + + av_frame_free(&s->prev); +} + +static const AVFilterPad aderivative_inputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_AUDIO, + .filter_frame = filter_frame, + .config_props = config_input, + }, + { NULL } +}; + +static const AVFilterPad aderivative_outputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_AUDIO, + }, + { NULL } +}; + +AVFilter ff_af_aderivative = { + .name = "aderivative", + .description = NULL_IF_CONFIG_SMALL("Compute derivative of input audio."), + .query_formats = query_formats, + .priv_size = sizeof(ADerivativeContext), + .uninit = uninit, + .inputs = aderivative_inputs, + .outputs = aderivative_outputs, +}; + +AVFilter ff_af_aintegral = { + .name = "aintegral", + .description = NULL_IF_CONFIG_SMALL("Compute integral of input audio."), + .query_formats = query_formats, + .priv_size = sizeof(ADerivativeContext), + .uninit = uninit, + .inputs = aderivative_inputs, + .outputs = aderivative_outputs, +}; diff --git a/libavfilter/af_aecho.c b/libavfilter/af_aecho.c index b9ac18d3a..876a149df 100644 --- a/libavfilter/af_aecho.c +++ b/libavfilter/af_aecho.c @@ -78,7 +78,7 @@ static void fill_items(char *item_str, int *nb_items, float *items) char *tstr = av_strtok(p, "|", &saveptr); p = NULL; if (tstr) - new_nb_items += sscanf(tstr, "%f", &items[new_nb_items]) == 1; + new_nb_items += av_sscanf(tstr, "%f", &items[new_nb_items]) == 1; } *nb_items = new_nb_items; diff --git a/libavfilter/af_afade.c b/libavfilter/af_afade.c index 285b5b655..195fb65ab 100644 --- a/libavfilter/af_afade.c +++ b/libavfilter/af_afade.c @@ -23,10 +23,6 @@ * fade audio filter */ -#define FF_INTERNAL_FIELDS 1 -#include "framequeue.h" - -#include "libavutil/audio_fifo.h" #include "libavutil/opt.h" #include "audio.h" #include "avfilter.h" @@ -43,9 +39,7 @@ typedef struct AudioFadeContext { int64_t start_time; int overlap; int cf0_eof; - int prev_size; int crossfade_is_over; - AVAudioFifo *fifo[2]; int64_t pts; void (*fade_samples)(uint8_t **dst, uint8_t * const *src, @@ -57,7 +51,7 @@ typedef struct AudioFadeContext { int curve0, int curve1); } AudioFadeContext; -enum CurveType { TRI, QSIN, ESIN, HSIN, LOG, IPAR, QUA, CUB, SQU, CBR, PAR, EXP, IQSIN, IHSIN, DESE, DESI, NB_CURVES }; +enum CurveType { TRI, QSIN, ESIN, HSIN, LOG, IPAR, QUA, CUB, SQU, CBR, PAR, EXP, IQSIN, IHSIN, DESE, DESI, LOSI, NONE, NB_CURVES }; #define OFFSET(x) offsetof(AudioFadeContext, x) #define FLAGS AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM @@ -151,6 +145,17 @@ static double fade_gain(int curve, int64_t index, int64_t range) case DESI: gain = gain <= 0.5 ? CUBE(2 * gain) / 2: 1 - CUBE(2 * (1 - gain)) / 2; break; + case LOSI: { + const double a = 1. / (1. - 0.787) - 1; + double A = 1. / (1.0 + exp(0 -((gain-0.5) * a * 2.0))); + double B = 1. / (1.0 + exp(a)); + double C = 1. / (1.0 + exp(0-a)); + gain = (A - B) / (C - B); + } + break; + case NONE: + gain = 1.0; + break; } return gain; @@ -237,8 +242,8 @@ static const AVOption afade_options[] = { { "ns", "set number of samples for fade duration", OFFSET(nb_samples), AV_OPT_TYPE_INT64, {.i64 = 44100}, 1, INT64_MAX, FLAGS }, { "start_time", "set time to start fading", OFFSET(start_time), AV_OPT_TYPE_DURATION, {.i64 = 0. }, 0, INT64_MAX, FLAGS }, { "st", "set time to start fading", OFFSET(start_time), AV_OPT_TYPE_DURATION, {.i64 = 0. }, 0, INT64_MAX, FLAGS }, - { "duration", "set fade duration", OFFSET(duration), AV_OPT_TYPE_DURATION, {.i64 = 0. }, 0, INT32_MAX, FLAGS }, - { "d", "set fade duration", OFFSET(duration), AV_OPT_TYPE_DURATION, {.i64 = 0. }, 0, INT32_MAX, FLAGS }, + { "duration", "set fade duration", OFFSET(duration), AV_OPT_TYPE_DURATION, {.i64 = 0. }, 0, INT64_MAX, FLAGS }, + { "d", "set fade duration", OFFSET(duration), AV_OPT_TYPE_DURATION, {.i64 = 0. }, 0, INT64_MAX, FLAGS }, { "curve", "set fade curve type", OFFSET(curve), AV_OPT_TYPE_INT, {.i64 = TRI }, 0, NB_CURVES - 1, FLAGS, "curve" }, { "c", "set fade curve type", OFFSET(curve), AV_OPT_TYPE_INT, {.i64 = TRI }, 0, NB_CURVES - 1, FLAGS, "curve" }, { "tri", "linear slope", 0, AV_OPT_TYPE_CONST, {.i64 = TRI }, 0, 0, FLAGS, "curve" }, @@ -257,6 +262,8 @@ static const AVOption afade_options[] = { { "ihsin", "inverted half of sine wave", 0, AV_OPT_TYPE_CONST, {.i64 = IHSIN}, 0, 0, FLAGS, "curve" }, { "dese", "double-exponential seat", 0, AV_OPT_TYPE_CONST, {.i64 = DESE }, 0, 0, FLAGS, "curve" }, { "desi", "double-exponential sigmoid", 0, AV_OPT_TYPE_CONST, {.i64 = DESI }, 0, 0, FLAGS, "curve" }, + { "losi", "logistic sigmoid", 0, AV_OPT_TYPE_CONST, {.i64 = LOSI }, 0, 0, FLAGS, "curve" }, + { "nofade", "no fade; keep audio as-is", 0, AV_OPT_TYPE_CONST, {.i64 = NONE }, 0, 0, FLAGS, "curve" }, { NULL } }; @@ -354,8 +361,8 @@ AVFilter ff_af_afade = { static const AVOption acrossfade_options[] = { { "nb_samples", "set number of samples for cross fade duration", OFFSET(nb_samples), AV_OPT_TYPE_INT, {.i64 = 44100}, 1, INT32_MAX/10, FLAGS }, { "ns", "set number of samples for cross fade duration", OFFSET(nb_samples), AV_OPT_TYPE_INT, {.i64 = 44100}, 1, INT32_MAX/10, FLAGS }, - { "duration", "set cross fade duration", OFFSET(duration), AV_OPT_TYPE_DURATION, {.i64 = 0. }, 0, 60, FLAGS }, - { "d", "set cross fade duration", OFFSET(duration), AV_OPT_TYPE_DURATION, {.i64 = 0. }, 0, 60, FLAGS }, + { "duration", "set cross fade duration", OFFSET(duration), AV_OPT_TYPE_DURATION, {.i64 = 0. }, 0, 60000000, FLAGS }, + { "d", "set cross fade duration", OFFSET(duration), AV_OPT_TYPE_DURATION, {.i64 = 0. }, 0, 60000000, FLAGS }, { "overlap", "overlap 1st stream end with 2nd stream start", OFFSET(overlap), AV_OPT_TYPE_BOOL, {.i64 = 1 }, 0, 1, FLAGS }, { "o", "overlap 1st stream end with 2nd stream start", OFFSET(overlap), AV_OPT_TYPE_BOOL, {.i64 = 1 }, 0, 1, FLAGS }, { "curve1", "set fade curve type for 1st stream", OFFSET(curve), AV_OPT_TYPE_INT, {.i64 = TRI }, 0, NB_CURVES - 1, FLAGS, "curve" }, @@ -376,6 +383,8 @@ static const AVOption acrossfade_options[] = { { "ihsin", "inverted half of sine wave", 0, AV_OPT_TYPE_CONST, {.i64 = IHSIN}, 0, 0, FLAGS, "curve" }, { "dese", "double-exponential seat", 0, AV_OPT_TYPE_CONST, {.i64 = DESE }, 0, 0, FLAGS, "curve" }, { "desi", "double-exponential sigmoid", 0, AV_OPT_TYPE_CONST, {.i64 = DESI }, 0, 0, FLAGS, "curve" }, + { "losi", "logistic sigmoid", 0, AV_OPT_TYPE_CONST, {.i64 = LOSI }, 0, 0, FLAGS, "curve" }, + { "nofade", "no fade; keep audio as-is", 0, AV_OPT_TYPE_CONST, {.i64 = NONE }, 0, 0, FLAGS, "curve" }, { "curve2", "set fade curve type for 2nd stream", OFFSET(curve2), AV_OPT_TYPE_INT, {.i64 = TRI }, 0, NB_CURVES - 1, FLAGS, "curve" }, { "c2", "set fade curve type for 2nd stream", OFFSET(curve2), AV_OPT_TYPE_INT, {.i64 = TRI }, 0, NB_CURVES - 1, FLAGS, "curve" }, { NULL } @@ -441,6 +450,8 @@ static int activate(AVFilterContext *ctx) int ret = 0, nb_samples, status; int64_t pts; + FF_FILTER_FORWARD_STATUS_BACK_ALL(outlink, ctx); + if (s->crossfade_is_over) { ret = ff_inlink_consume_frame(ctx->inputs[1], &in); if (ret < 0) { @@ -460,8 +471,8 @@ static int activate(AVFilterContext *ctx) return ff_filter_frame(outlink, in); } - if (ff_framequeue_queued_samples(&ctx->inputs[0]->fifo) > s->nb_samples) { - nb_samples = ff_framequeue_queued_samples(&ctx->inputs[0]->fifo) - s->nb_samples; + if (ff_inlink_queued_samples(ctx->inputs[0]) > s->nb_samples) { + nb_samples = ff_inlink_queued_samples(ctx->inputs[0]) - s->nb_samples; if (nb_samples > 0) { ret = ff_inlink_consume_samples(ctx->inputs[0], nb_samples, nb_samples, &in); if (ret < 0) { @@ -472,7 +483,7 @@ static int activate(AVFilterContext *ctx) s->pts += av_rescale_q(in->nb_samples, (AVRational){ 1, outlink->sample_rate }, outlink->time_base); return ff_filter_frame(outlink, in); - } else if (ff_framequeue_queued_samples(&ctx->inputs[1]->fifo) >= s->nb_samples) { + } else if (ff_inlink_queued_samples(ctx->inputs[1]) >= s->nb_samples) { if (s->overlap) { out = ff_get_audio_buffer(outlink, s->nb_samples); if (!out) @@ -542,10 +553,10 @@ static int activate(AVFilterContext *ctx) return ff_filter_frame(outlink, out); } } else if (ff_outlink_frame_wanted(ctx->outputs[0])) { - if (!s->cf0_eof && ctx->inputs[0]->status_in) { + if (!s->cf0_eof && ff_outlink_get_status(ctx->inputs[0])) { s->cf0_eof = 1; } - if (ctx->inputs[1]->status_in) { + if (ff_outlink_get_status(ctx->inputs[1])) { ff_outlink_set_status(ctx->outputs[0], AVERROR_EOF, AV_NOPTS_VALUE); return 0; } diff --git a/libavfilter/af_afftdn.c b/libavfilter/af_afftdn.c new file mode 100644 index 000000000..9619aadbe --- /dev/null +++ b/libavfilter/af_afftdn.c @@ -0,0 +1,1452 @@ +/* + * Copyright (c) 2018 The FFmpeg Project + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include "libavutil/audio_fifo.h" +#include "libavutil/avstring.h" +#include "libavutil/channel_layout.h" +#include "libavutil/opt.h" +#include "libavcodec/avfft.h" +#include "avfilter.h" +#include "audio.h" +#include "formats.h" +#include "filters.h" + +#define C (M_LN10 * 0.1) +#define RATIO 0.98 +#define RRATIO (1.0 - RATIO) + +enum OutModes { + IN_MODE, + OUT_MODE, + NOISE_MODE, + NB_MODES +}; + +enum NoiseType { + WHITE_NOISE, + VINYL_NOISE, + SHELLAC_NOISE, + CUSTOM_NOISE, + NB_NOISE +}; + +typedef struct DeNoiseChannel { + int band_noise[15]; + double noise_band_auto_var[15]; + double noise_band_sample[15]; + double *amt; + double *band_amt; + double *band_excit; + double *gain; + double *prior; + double *prior_band_excit; + double *clean_data; + double *noisy_data; + double *out_samples; + double *spread_function; + double *abs_var; + double *rel_var; + double *min_abs_var; + FFTComplex *fft_data; + FFTContext *fft, *ifft; + + double noise_band_norm[15]; + double noise_band_avr[15]; + double noise_band_avi[15]; + double noise_band_var[15]; + + double sfm_threshold; + double sfm_alpha; + double sfm_results[3]; + int sfm_fail_flags[512]; + int sfm_fail_total; +} DeNoiseChannel; + +typedef struct AudioFFTDeNoiseContext { + const AVClass *class; + + float noise_reduction; + float noise_floor; + int noise_type; + char *band_noise_str; + float residual_floor; + int track_noise; + int track_residual; + int output_mode; + + float last_residual_floor; + float last_noise_floor; + float last_noise_reduction; + float last_noise_balance; + int64_t block_count; + + int64_t pts; + int channels; + int sample_noise; + int sample_noise_start; + int sample_noise_end; + float sample_rate; + int buffer_length; + int fft_length; + int fft_length2; + int bin_count; + int window_length; + int sample_advance; + int number_of_bands; + + int band_centre[15]; + + int *bin2band; + double *window; + double *band_alpha; + double *band_beta; + + DeNoiseChannel *dnch; + + double max_gain; + double max_var; + double gain_scale; + double window_weight; + double floor; + double sample_floor; + double auto_floor; + + int noise_band_edge[17]; + int noise_band_count; + double matrix_a[25]; + double vector_b[5]; + double matrix_b[75]; + double matrix_c[75]; + + AVAudioFifo *fifo; +} AudioFFTDeNoiseContext; + +#define OFFSET(x) offsetof(AudioFFTDeNoiseContext, x) +#define A AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM + +static const AVOption afftdn_options[] = { + { "nr", "set the noise reduction", OFFSET(noise_reduction), AV_OPT_TYPE_FLOAT, {.dbl = 12}, .01, 97, A }, + { "nf", "set the noise floor", OFFSET(noise_floor), AV_OPT_TYPE_FLOAT, {.dbl =-50}, -80,-20, A }, + { "nt", "set the noise type", OFFSET(noise_type), AV_OPT_TYPE_INT, {.i64 = WHITE_NOISE}, WHITE_NOISE, NB_NOISE-1, A, "type" }, + { "w", "white noise", 0, AV_OPT_TYPE_CONST, {.i64 = WHITE_NOISE}, 0, 0, A, "type" }, + { "v", "vinyl noise", 0, AV_OPT_TYPE_CONST, {.i64 = VINYL_NOISE}, 0, 0, A, "type" }, + { "s", "shellac noise", 0, AV_OPT_TYPE_CONST, {.i64 = SHELLAC_NOISE}, 0, 0, A, "type" }, + { "c", "custom noise", 0, AV_OPT_TYPE_CONST, {.i64 = CUSTOM_NOISE}, 0, 0, A, "type" }, + { "bn", "set the custom bands noise", OFFSET(band_noise_str), AV_OPT_TYPE_STRING, {.str = 0}, 0, 0, A }, + { "rf", "set the residual floor", OFFSET(residual_floor), AV_OPT_TYPE_FLOAT, {.dbl =-38}, -80,-20, A }, + { "tn", "track noise", OFFSET(track_noise), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, A }, + { "tr", "track residual", OFFSET(track_residual), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, A }, + { "om", "set output mode", OFFSET(output_mode), AV_OPT_TYPE_INT, {.i64 = OUT_MODE}, 0, NB_MODES-1, A, "mode" }, + { "i", "input", 0, AV_OPT_TYPE_CONST, {.i64 = IN_MODE}, 0, 0, A, "mode" }, + { "o", "output", 0, AV_OPT_TYPE_CONST, {.i64 = OUT_MODE}, 0, 0, A, "mode" }, + { "n", "noise", 0, AV_OPT_TYPE_CONST, {.i64 = NOISE_MODE}, 0, 0, A, "mode" }, + { NULL } +}; + +AVFILTER_DEFINE_CLASS(afftdn); + +static int get_band_noise(AudioFFTDeNoiseContext *s, + int band, double a, + double b, double c) +{ + double d1, d2, d3; + + d1 = a / s->band_centre[band]; + d1 = 10.0 * log(1.0 + d1 * d1) / M_LN10; + d2 = b / s->band_centre[band]; + d2 = 10.0 * log(1.0 + d2 * d2) / M_LN10; + d3 = s->band_centre[band] / c; + d3 = 10.0 * log(1.0 + d3 * d3) / M_LN10; + + return lrint(-d1 + d2 - d3); +} + +static void factor(double *array, int size) +{ + for (int i = 0; i < size - 1; i++) { + for (int j = i + 1; j < size; j++) { + double d = array[j + i * size] / array[i + i * size]; + + array[j + i * size] = d; + for (int k = i + 1; k < size; k++) { + array[j + k * size] -= d * array[i + k * size]; + } + } + } +} + +static void solve(double *matrix, double *vector, int size) +{ + for (int i = 0; i < size - 1; i++) { + for (int j = i + 1; j < size; j++) { + double d = matrix[j + i * size]; + vector[j] -= d * vector[i]; + } + } + + vector[size - 1] /= matrix[size * size - 1]; + + for (int i = size - 2; i >= 0; i--) { + double d = vector[i]; + for (int j = i + 1; j < size; j++) + d -= matrix[i + j * size] * vector[j]; + vector[i] = d / matrix[i + i * size]; + } +} + +static int process_get_band_noise(AudioFFTDeNoiseContext *s, + DeNoiseChannel *dnch, + int band) +{ + double product, sum, f; + int i = 0; + + if (band < 15) + return dnch->band_noise[band]; + + for (int j = 0; j < 5; j++) { + sum = 0.0; + for (int k = 0; k < 15; k++) + sum += s->matrix_b[i++] * dnch->band_noise[k]; + s->vector_b[j] = sum; + } + + solve(s->matrix_a, s->vector_b, 5); + f = (0.5 * s->sample_rate) / s->band_centre[14]; + f = 15.0 + log(f / 1.5) / log(1.5); + sum = 0.0; + product = 1.0; + for (int j = 0; j < 5; j++) { + sum += product * s->vector_b[j]; + product *= f; + } + + return lrint(sum); +} + +static void calculate_sfm(AudioFFTDeNoiseContext *s, + DeNoiseChannel *dnch, + int start, int end) +{ + double d1 = 0.0, d2 = 1.0; + int i = 0, j = 0; + + for (int k = start; k < end; k++) { + if (dnch->noisy_data[k] > s->sample_floor) { + j++; + d1 += dnch->noisy_data[k]; + d2 *= dnch->noisy_data[k]; + if (d2 > 1.0E100) { + d2 *= 1.0E-100; + i++; + } else if (d2 < 1.0E-100) { + d2 *= 1.0E100; + i--; + } + } + } + if (j > 1) { + d1 /= j; + dnch->sfm_results[0] = d1; + d2 = log(d2) + 230.2585 * i; + d2 /= j; + d1 = log(d1); + dnch->sfm_results[1] = d1; + dnch->sfm_results[2] = d1 - d2; + } else { + dnch->sfm_results[0] = s->auto_floor; + dnch->sfm_results[1] = dnch->sfm_threshold; + dnch->sfm_results[2] = dnch->sfm_threshold; + } +} + +static double limit_gain(double a, double b) +{ + if (a > 1.0) + return (b * a - 1.0) / (b + a - 2.0); + if (a < 1.0) + return (b * a - 2.0 * a + 1.0) / (b - a); + return 1.0; +} + +static void process_frame(AudioFFTDeNoiseContext *s, DeNoiseChannel *dnch, + FFTComplex *fft_data, + double *prior, double *prior_band_excit, int track_noise) +{ + double d1, d2, d3, gain; + int n, i1; + + d1 = fft_data[0].re * fft_data[0].re; + dnch->noisy_data[0] = d1; + d2 = d1 / dnch->abs_var[0]; + d3 = RATIO * prior[0] + RRATIO * fmax(d2 - 1.0, 0.0); + gain = d3 / (1.0 + d3); + gain *= (gain + M_PI_4 / fmax(d2, 1.0E-6)); + prior[0] = (d2 * gain); + dnch->clean_data[0] = (d1 * gain); + gain = sqrt(gain); + dnch->gain[0] = gain; + n = 0; + for (int i = 1; i < s->fft_length2; i++) { + d1 = fft_data[i].re * fft_data[i].re + fft_data[i].im * fft_data[i].im; + if (d1 > s->sample_floor) + n = i; + + dnch->noisy_data[i] = d1; + d2 = d1 / dnch->abs_var[i]; + d3 = RATIO * prior[i] + RRATIO * fmax(d2 - 1.0, 0.0); + gain = d3 / (1.0 + d3); + gain *= (gain + M_PI_4 / fmax(d2, 1.0E-6)); + prior[i] = d2 * gain; + dnch->clean_data[i] = d1 * gain; + gain = sqrt(gain); + dnch->gain[i] = gain; + } + d1 = fft_data[0].im * fft_data[0].im; + if (d1 > s->sample_floor) + n = s->fft_length2; + + dnch->noisy_data[s->fft_length2] = d1; + d2 = d1 / dnch->abs_var[s->fft_length2]; + d3 = RATIO * prior[s->fft_length2] + RRATIO * fmax(d2 - 1.0, 0.0); + gain = d3 / (1.0 + d3); + gain *= gain + M_PI_4 / fmax(d2, 1.0E-6); + prior[s->fft_length2] = d2 * gain; + dnch->clean_data[s->fft_length2] = d1 * gain; + gain = sqrt(gain); + dnch->gain[s->fft_length2] = gain; + if (n > s->fft_length2 - 2) { + n = s->bin_count; + i1 = s->noise_band_count; + } else { + i1 = 0; + for (int i = 0; i <= s->noise_band_count; i++) { + if (n > 1.1 * s->noise_band_edge[i]) { + i1 = i; + } + } + } + + if (track_noise && (i1 > s->noise_band_count / 2)) { + int j = FFMIN(n, s->noise_band_edge[i1]); + int m = 3, k; + + for (k = i1 - 1; k >= 0; k--) { + int i = s->noise_band_edge[k]; + calculate_sfm(s, dnch, i, j); + dnch->noise_band_sample[k] = dnch->sfm_results[0]; + if (dnch->sfm_results[2] + 0.013 * m * fmax(0.0, dnch->sfm_results[1] - 20.53) >= dnch->sfm_threshold) { + break; + } + j = i; + m++; + } + + if (k < i1 - 1) { + double sum = 0.0, min, max; + int i; + + for (i = i1 - 1; i > k; i--) { + min = log(dnch->noise_band_sample[i] / dnch->noise_band_auto_var[i]); + sum += min; + } + + i = i1 - k - 1; + if (i < 5) { + min = 3.0E-4 * i * i; + } else { + min = 3.0E-4 * (8 * i - 16); + } + if (i < 3) { + max = 2.0E-4 * i * i; + } else { + max = 2.0E-4 * (4 * i - 4); + } + + if (s->track_residual) { + if (s->last_noise_floor > s->last_residual_floor + 9) { + min *= 0.5; + max *= 0.75; + } else if (s->last_noise_floor > s->last_residual_floor + 6) { + min *= 0.4; + max *= 1.0; + } else if (s->last_noise_floor > s->last_residual_floor + 4) { + min *= 0.3; + max *= 1.3; + } else if (s->last_noise_floor > s->last_residual_floor + 2) { + min *= 0.2; + max *= 1.6; + } else if (s->last_noise_floor > s->last_residual_floor) { + min *= 0.1; + max *= 2.0; + } else { + min = 0.0; + max *= 2.5; + } + } + + sum = av_clipd(sum, -min, max); + sum = exp(sum); + for (int i = 0; i < 15; i++) + dnch->noise_band_auto_var[i] *= sum; + } else if (dnch->sfm_results[2] >= dnch->sfm_threshold) { + dnch->sfm_fail_flags[s->block_count & 0x1FF] = 1; + dnch->sfm_fail_total += 1; + } + } + + for (int i = 0; i < s->number_of_bands; i++) { + dnch->band_excit[i] = 0.0; + dnch->band_amt[i] = 0.0; + } + + for (int i = 0; i < s->bin_count; i++) { + dnch->band_excit[s->bin2band[i]] += dnch->clean_data[i]; + } + + for (int i = 0; i < s->number_of_bands; i++) { + dnch->band_excit[i] = fmax(dnch->band_excit[i], + s->band_alpha[i] * dnch->band_excit[i] + + s->band_beta[i] * prior_band_excit[i]); + prior_band_excit[i] = dnch->band_excit[i]; + } + + for (int j = 0, i = 0; j < s->number_of_bands; j++) { + for (int k = 0; k < s->number_of_bands; k++) { + dnch->band_amt[j] += dnch->spread_function[i++] * dnch->band_excit[k]; + } + } + + for (int i = 0; i < s->bin_count; i++) + dnch->amt[i] = dnch->band_amt[s->bin2band[i]]; + + if (dnch->amt[0] > dnch->abs_var[0]) { + dnch->gain[0] = 1.0; + } else if (dnch->amt[0] > dnch->min_abs_var[0]) { + double limit = sqrt(dnch->abs_var[0] / dnch->amt[0]); + dnch->gain[0] = limit_gain(dnch->gain[0], limit); + } else { + dnch->gain[0] = limit_gain(dnch->gain[0], s->max_gain); + } + if (dnch->amt[s->fft_length2] > dnch->abs_var[s->fft_length2]) { + dnch->gain[s->fft_length2] = 1.0; + } else if (dnch->amt[s->fft_length2] > dnch->min_abs_var[s->fft_length2]) { + double limit = sqrt(dnch->abs_var[s->fft_length2] / dnch->amt[s->fft_length2]); + dnch->gain[s->fft_length2] = limit_gain(dnch->gain[s->fft_length2], limit); + } else { + dnch->gain[s->fft_length2] = limit_gain(dnch->gain[s->fft_length2], s->max_gain); + } + + for (int i = 1; i < s->fft_length2; i++) { + if (dnch->amt[i] > dnch->abs_var[i]) { + dnch->gain[i] = 1.0; + } else if (dnch->amt[i] > dnch->min_abs_var[i]) { + double limit = sqrt(dnch->abs_var[i] / dnch->amt[i]); + dnch->gain[i] = limit_gain(dnch->gain[i], limit); + } else { + dnch->gain[i] = limit_gain(dnch->gain[i], s->max_gain); + } + } + + gain = dnch->gain[0]; + dnch->clean_data[0] = (gain * gain * dnch->noisy_data[0]); + fft_data[0].re *= gain; + gain = dnch->gain[s->fft_length2]; + dnch->clean_data[s->fft_length2] = (gain * gain * dnch->noisy_data[s->fft_length2]); + fft_data[0].im *= gain; + for (int i = 1; i < s->fft_length2; i++) { + gain = dnch->gain[i]; + dnch->clean_data[i] = (gain * gain * dnch->noisy_data[i]); + fft_data[i].re *= gain; + fft_data[i].im *= gain; + } +} + +static double freq2bark(double x) +{ + double d = x / 7500.0; + + return 13.0 * atan(7.6E-4 * x) + 3.5 * atan(d * d); +} + +static int get_band_centre(AudioFFTDeNoiseContext *s, int band) +{ + if (band == -1) + return lrint(s->band_centre[0] / 1.5); + + return s->band_centre[band]; +} + +static int get_band_edge(AudioFFTDeNoiseContext *s, int band) +{ + int i; + + if (band == 15) { + i = lrint(s->band_centre[14] * 1.224745); + } else { + i = lrint(s->band_centre[band] / 1.224745); + } + + return FFMIN(i, s->sample_rate / 2); +} + +static void set_band_parameters(AudioFFTDeNoiseContext *s, + DeNoiseChannel *dnch) +{ + double band_noise, d2, d3, d4, d5; + int i = 0, j = 0, k = 0; + + d5 = 0.0; + band_noise = process_get_band_noise(s, dnch, 0); + for (int m = j; m <= s->fft_length2; m++) { + if (m == j) { + i = j; + d5 = band_noise; + if (k == 15) { + j = s->bin_count; + } else { + j = s->fft_length * get_band_centre(s, k) / s->sample_rate; + } + d2 = j - i; + band_noise = process_get_band_noise(s, dnch, k); + k++; + } + d3 = (j - m) / d2; + d4 = (m - i) / d2; + dnch->rel_var[m] = exp((d5 * d3 + band_noise * d4) * C); + } + dnch->rel_var[s->fft_length2] = exp(band_noise * C); + + for (i = 0; i < 15; i++) + dnch->noise_band_auto_var[i] = s->max_var * exp((process_get_band_noise(s, dnch, i) - 2.0) * C); + + for (i = 0; i <= s->fft_length2; i++) { + dnch->abs_var[i] = fmax(s->max_var * dnch->rel_var[i], 1.0); + dnch->min_abs_var[i] = s->gain_scale * dnch->abs_var[i]; + } +} + +static void read_custom_noise(AudioFFTDeNoiseContext *s, int ch) +{ + DeNoiseChannel *dnch = &s->dnch[ch]; + char *p, *arg, *saveptr = NULL; + int i, ret, band_noise[15] = { 0 }; + + if (!s->band_noise_str) + return; + + p = av_strdup(s->band_noise_str); + if (!p) + return; + + for (i = 0; i < 15; i++) { + if (!(arg = av_strtok(p, "| ", &saveptr))) + break; + + p = NULL; + + ret = av_sscanf(arg, "%d", &band_noise[i]); + if (ret != 1) { + av_log(s, AV_LOG_ERROR, "Custom band noise must be integer.\n"); + break; + } + + band_noise[i] = av_clip(band_noise[i], -24, 24); + } + + av_free(p); + memcpy(dnch->band_noise, band_noise, sizeof(band_noise)); +} + +static void set_parameters(AudioFFTDeNoiseContext *s) +{ + if (s->last_noise_floor != s->noise_floor) + s->last_noise_floor = s->noise_floor; + + if (s->track_residual) + s->last_noise_floor = fmaxf(s->last_noise_floor, s->residual_floor); + + s->max_var = s->floor * exp((100.0 + s->last_noise_floor) * C); + + if (s->track_residual) { + s->last_residual_floor = s->residual_floor; + s->last_noise_reduction = fmax(s->last_noise_floor - s->last_residual_floor, 0); + s->max_gain = exp(s->last_noise_reduction * (0.5 * C)); + } else if (s->noise_reduction != s->last_noise_reduction) { + s->last_noise_reduction = s->noise_reduction; + s->last_residual_floor = av_clipf(s->last_noise_floor - s->last_noise_reduction, -80, -20); + s->max_gain = exp(s->last_noise_reduction * (0.5 * C)); + } + + s->gain_scale = 1.0 / (s->max_gain * s->max_gain); + + for (int ch = 0; ch < s->channels; ch++) { + DeNoiseChannel *dnch = &s->dnch[ch]; + + set_band_parameters(s, dnch); + } +} + +static int config_input(AVFilterLink *inlink) +{ + AVFilterContext *ctx = inlink->dst; + AudioFFTDeNoiseContext *s = ctx->priv; + double wscale, sar, sum, sdiv; + int i, j, k, m, n; + + s->dnch = av_calloc(inlink->channels, sizeof(*s->dnch)); + if (!s->dnch) + return AVERROR(ENOMEM); + + s->pts = AV_NOPTS_VALUE; + s->channels = inlink->channels; + s->sample_rate = inlink->sample_rate; + s->sample_advance = s->sample_rate / 80; + s->window_length = 3 * s->sample_advance; + s->fft_length2 = 1 << (32 - ff_clz(s->window_length)); + s->fft_length = s->fft_length2 * 2; + s->buffer_length = s->fft_length * 2; + s->bin_count = s->fft_length2 + 1; + + s->band_centre[0] = 80; + for (i = 1; i < 15; i++) { + s->band_centre[i] = lrint(1.5 * s->band_centre[i - 1] + 5.0); + if (s->band_centre[i] < 1000) { + s->band_centre[i] = 10 * (s->band_centre[i] / 10); + } else if (s->band_centre[i] < 5000) { + s->band_centre[i] = 50 * ((s->band_centre[i] + 20) / 50); + } else if (s->band_centre[i] < 15000) { + s->band_centre[i] = 100 * ((s->band_centre[i] + 45) / 100); + } else { + s->band_centre[i] = 1000 * ((s->band_centre[i] + 495) / 1000); + } + } + + for (j = 0; j < 5; j++) { + for (k = 0; k < 5; k++) { + s->matrix_a[j + k * 5] = 0.0; + for (m = 0; m < 15; m++) + s->matrix_a[j + k * 5] += pow(m, j + k); + } + } + + factor(s->matrix_a, 5); + + i = 0; + for (j = 0; j < 5; j++) + for (k = 0; k < 15; k++) + s->matrix_b[i++] = pow(k, j); + + i = 0; + for (j = 0; j < 15; j++) + for (k = 0; k < 5; k++) + s->matrix_c[i++] = pow(j, k); + + s->window = av_calloc(s->window_length, sizeof(*s->window)); + s->bin2band = av_calloc(s->bin_count, sizeof(*s->bin2band)); + if (!s->window || !s->bin2band) + return AVERROR(ENOMEM); + + sdiv = s->sample_rate / 17640.0; + for (i = 0; i <= s->fft_length2; i++) + s->bin2band[i] = lrint(sdiv * freq2bark((0.5 * i * s->sample_rate) / s->fft_length2)); + + s->number_of_bands = s->bin2band[s->fft_length2] + 1; + + s->band_alpha = av_calloc(s->number_of_bands, sizeof(*s->band_alpha)); + s->band_beta = av_calloc(s->number_of_bands, sizeof(*s->band_beta)); + if (!s->band_alpha || !s->band_beta) + return AVERROR(ENOMEM); + + for (int ch = 0; ch < inlink->channels; ch++) { + DeNoiseChannel *dnch = &s->dnch[ch]; + + switch (s->noise_type) { + case WHITE_NOISE: + for (i = 0; i < 15; i++) + dnch->band_noise[i] = 0; + break; + case VINYL_NOISE: + for (i = 0; i < 15; i++) + dnch->band_noise[i] = get_band_noise(s, i, 50.0, 500.5, 2125.0) + FFMAX(i - 7, 0); + break; + case SHELLAC_NOISE: + for (i = 0; i < 15; i++) + dnch->band_noise[i] = get_band_noise(s, i, 1.0, 500.0, 1.0E10) + FFMAX(i - 12, -5); + break; + case CUSTOM_NOISE: + read_custom_noise(s, ch); + break; + default: + return AVERROR_BUG; + } + + + dnch->sfm_threshold = 0.8; + dnch->sfm_alpha = 0.05; + for (i = 0; i < 512; i++) + dnch->sfm_fail_flags[i] = 0; + + dnch->sfm_fail_total = 0; + j = FFMAX((int)(10.0 * (1.3 - dnch->sfm_threshold)), 1); + + for (i = 0; i < 512; i += j) { + dnch->sfm_fail_flags[i] = 1; + dnch->sfm_fail_total += 1; + } + + dnch->amt = av_calloc(s->bin_count, sizeof(*dnch->amt)); + dnch->band_amt = av_calloc(s->number_of_bands, sizeof(*dnch->band_amt)); + dnch->band_excit = av_calloc(s->number_of_bands, sizeof(*dnch->band_excit)); + dnch->gain = av_calloc(s->bin_count, sizeof(*dnch->gain)); + dnch->prior = av_calloc(s->bin_count, sizeof(*dnch->prior)); + dnch->prior_band_excit = av_calloc(s->number_of_bands, sizeof(*dnch->prior_band_excit)); + dnch->clean_data = av_calloc(s->bin_count, sizeof(*dnch->clean_data)); + dnch->noisy_data = av_calloc(s->bin_count, sizeof(*dnch->noisy_data)); + dnch->out_samples = av_calloc(s->buffer_length, sizeof(*dnch->out_samples)); + dnch->abs_var = av_calloc(s->bin_count, sizeof(*dnch->abs_var)); + dnch->rel_var = av_calloc(s->bin_count, sizeof(*dnch->rel_var)); + dnch->min_abs_var = av_calloc(s->bin_count, sizeof(*dnch->min_abs_var)); + dnch->fft_data = av_calloc(s->fft_length2 + 1, sizeof(*dnch->fft_data)); + dnch->fft = av_fft_init(av_log2(s->fft_length2), 0); + dnch->ifft = av_fft_init(av_log2(s->fft_length2), 1); + dnch->spread_function = av_calloc(s->number_of_bands * s->number_of_bands, + sizeof(*dnch->spread_function)); + + if (!dnch->amt || + !dnch->band_amt || + !dnch->band_excit || + !dnch->gain || + !dnch->prior || + !dnch->prior_band_excit || + !dnch->clean_data || + !dnch->noisy_data || + !dnch->out_samples || + !dnch->fft_data || + !dnch->abs_var || + !dnch->rel_var || + !dnch->min_abs_var || + !dnch->spread_function || + !dnch->fft || + !dnch->ifft) + return AVERROR(ENOMEM); + } + + for (int ch = 0; ch < inlink->channels; ch++) { + DeNoiseChannel *dnch = &s->dnch[ch]; + double *prior_band_excit = dnch->prior_band_excit; + double *prior = dnch->prior; + double min, max; + double p1, p2; + + p1 = pow(0.1, 2.5 / sdiv); + p2 = pow(0.1, 1.0 / sdiv); + j = 0; + for (m = 0; m < s->number_of_bands; m++) { + for (n = 0; n < s->number_of_bands; n++) { + if (n < m) { + dnch->spread_function[j++] = pow(p2, m - n); + } else if (n > m) { + dnch->spread_function[j++] = pow(p1, n - m); + } else { + dnch->spread_function[j++] = 1.0; + } + } + } + + for (m = 0; m < s->number_of_bands; m++) { + dnch->band_excit[m] = 0.0; + prior_band_excit[m] = 0.0; + } + + for (m = 0; m <= s->fft_length2; m++) + dnch->band_excit[s->bin2band[m]] += 1.0; + + j = 0; + for (m = 0; m < s->number_of_bands; m++) { + for (n = 0; n < s->number_of_bands; n++) + prior_band_excit[m] += dnch->spread_function[j++] * dnch->band_excit[n]; + } + + min = pow(0.1, 2.5); + max = pow(0.1, 1.0); + for (int i = 0; i < s->number_of_bands; i++) { + if (i < lrint(12.0 * sdiv)) { + dnch->band_excit[i] = pow(0.1, 1.45 + 0.1 * i / sdiv); + } else { + dnch->band_excit[i] = pow(0.1, 2.5 - 0.2 * (i / sdiv - 14.0)); + } + dnch->band_excit[i] = av_clipd(dnch->band_excit[i], min, max); + } + + for (int i = 0; i <= s->fft_length2; i++) + prior[i] = RRATIO; + for (int i = 0; i < s->buffer_length; i++) + dnch->out_samples[i] = 0; + + j = 0; + for (int i = 0; i < s->number_of_bands; i++) + for (int k = 0; k < s->number_of_bands; k++) + dnch->spread_function[j++] *= dnch->band_excit[i] / prior_band_excit[i]; + } + + j = 0; + sar = s->sample_advance / s->sample_rate; + for (int i = 0; i <= s->fft_length2; i++) { + if ((i == s->fft_length2) || (s->bin2band[i] > j)) { + double d6 = (i - 1) * s->sample_rate / s->fft_length; + double d7 = fmin(0.008 + 2.2 / d6, 0.03); + s->band_alpha[j] = exp(-sar / d7); + s->band_beta[j] = 1.0 - s->band_alpha[j]; + j = s->bin2band[i]; + } + } + + wscale = sqrt(16.0 / (9.0 * s->fft_length)); + sum = 0.0; + for (int i = 0; i < s->window_length; i++) { + double d10 = sin(i * M_PI / s->window_length); + d10 *= wscale * d10; + s->window[i] = d10; + sum += d10 * d10; + } + + s->window_weight = 0.5 * sum; + s->floor = (1LL << 48) * exp(-23.025558369790467) * s->window_weight; + s->sample_floor = s->floor * exp(4.144600506562284); + s->auto_floor = s->floor * exp(6.907667510937141); + + set_parameters(s); + + s->noise_band_edge[0] = FFMIN(s->fft_length2, s->fft_length * get_band_edge(s, 0) / s->sample_rate); + i = 0; + for (int j = 1; j < 16; j++) { + s->noise_band_edge[j] = FFMIN(s->fft_length2, s->fft_length * get_band_edge(s, j) / s->sample_rate); + if (s->noise_band_edge[j] > lrint(1.1 * s->noise_band_edge[j - 1])) + i++; + s->noise_band_edge[16] = i; + } + s->noise_band_count = s->noise_band_edge[16]; + + s->fifo = av_audio_fifo_alloc(inlink->format, inlink->channels, s->fft_length); + if (!s->fifo) + return AVERROR(ENOMEM); + + return 0; +} + +static void preprocess(FFTComplex *in, int len) +{ + double d1, d2, d3, d4, d5, d6, d7, d8, d9, d10; + int n, i, k; + + d5 = 2.0 * M_PI / len; + d8 = sin(0.5 * d5); + d8 = -2.0 * d8 * d8; + d7 = sin(d5); + d9 = 1.0 + d8; + d6 = d7; + n = len / 2; + + for (i = 1; i < len / 4; i++) { + k = n - i; + d2 = 0.5 * (in[i].re + in[k].re); + d1 = 0.5 * (in[i].im - in[k].im); + d4 = 0.5 * (in[i].im + in[k].im); + d3 = 0.5 * (in[k].re - in[i].re); + in[i].re = d2 + d9 * d4 + d6 * d3; + in[i].im = d1 + d9 * d3 - d6 * d4; + in[k].re = d2 - d9 * d4 - d6 * d3; + in[k].im = -d1 + d9 * d3 - d6 * d4; + d10 = d9; + d9 += d9 * d8 - d6 * d7; + d6 += d6 * d8 + d10 * d7; + } + + d2 = in[0].re; + in[0].re = d2 + in[0].im; + in[0].im = d2 - in[0].im; +} + +static void postprocess(FFTComplex *in, int len) +{ + double d1, d2, d3, d4, d5, d6, d7, d8, d9, d10; + int n, i, k; + + d5 = 2.0 * M_PI / len; + d8 = sin(0.5 * d5); + d8 = -2.0 * d8 * d8; + d7 = sin(d5); + d9 = 1.0 + d8; + d6 = d7; + n = len / 2; + for (i = 1; i < len / 4; i++) { + k = n - i; + d2 = 0.5 * (in[i].re + in[k].re); + d1 = 0.5 * (in[i].im - in[k].im); + d4 = 0.5 * (in[i].re - in[k].re); + d3 = 0.5 * (in[i].im + in[k].im); + in[i].re = d2 - d9 * d3 - d6 * d4; + in[i].im = d1 + d9 * d4 - d6 * d3; + in[k].re = d2 + d9 * d3 + d6 * d4; + in[k].im = -d1 + d9 * d4 - d6 * d3; + d10 = d9; + d9 += d9 * d8 - d6 * d7; + d6 += d6 * d8 + d10 * d7; + } + d2 = in[0].re; + in[0].re = 0.5 * (d2 + in[0].im); + in[0].im = 0.5 * (d2 - in[0].im); +} + +static void init_sample_noise(DeNoiseChannel *dnch) +{ + for (int i = 0; i < 15; i++) { + dnch->noise_band_norm[i] = 0.0; + dnch->noise_band_avr[i] = 0.0; + dnch->noise_band_avi[i] = 0.0; + dnch->noise_band_var[i] = 0.0; + } +} + +static void sample_noise_block(AudioFFTDeNoiseContext *s, + DeNoiseChannel *dnch, + AVFrame *in, int ch) +{ + float *src = (float *)in->extended_data[ch]; + double mag2, var = 0.0, avr = 0.0, avi = 0.0; + int edge, j, k, n, edgemax; + + for (int i = 0; i < s->window_length; i++) { + dnch->fft_data[i].re = s->window[i] * src[i] * (1LL << 24); + dnch->fft_data[i].im = 0.0; + } + + for (int i = s->window_length; i < s->fft_length2; i++) { + dnch->fft_data[i].re = 0.0; + dnch->fft_data[i].im = 0.0; + } + + av_fft_permute(dnch->fft, dnch->fft_data); + av_fft_calc(dnch->fft, dnch->fft_data); + + preprocess(dnch->fft_data, s->fft_length); + + edge = s->noise_band_edge[0]; + j = edge; + k = 0; + n = j; + edgemax = fmin(s->fft_length2, s->noise_band_edge[15]); + dnch->fft_data[s->fft_length2].re = dnch->fft_data[0].im; + dnch->fft_data[0].im = 0.0; + dnch->fft_data[s->fft_length2].im = 0.0; + + for (int i = j; i <= edgemax; i++) { + if ((i == j) && (i < edgemax)) { + if (j > edge) { + dnch->noise_band_norm[k - 1] += j - edge; + dnch->noise_band_avr[k - 1] += avr; + dnch->noise_band_avi[k - 1] += avi; + dnch->noise_band_var[k - 1] += var; + } + k++; + edge = j; + j = s->noise_band_edge[k]; + if (k == 15) { + j++; + } + var = 0.0; + avr = 0.0; + avi = 0.0; + } + avr += dnch->fft_data[n].re; + avi += dnch->fft_data[n].im; + mag2 = dnch->fft_data[n].re * dnch->fft_data[n].re + + dnch->fft_data[n].im * dnch->fft_data[n].im; + + mag2 = fmax(mag2, s->sample_floor); + + dnch->noisy_data[i] = mag2; + var += mag2; + n++; + } + + dnch->noise_band_norm[k - 1] += j - edge; + dnch->noise_band_avr[k - 1] += avr; + dnch->noise_band_avi[k - 1] += avi; + dnch->noise_band_var[k - 1] += var; +} + +static void finish_sample_noise(AudioFFTDeNoiseContext *s, + DeNoiseChannel *dnch, + double *sample_noise) +{ + for (int i = 0; i < s->noise_band_count; i++) { + dnch->noise_band_avr[i] /= dnch->noise_band_norm[i]; + dnch->noise_band_avi[i] /= dnch->noise_band_norm[i]; + dnch->noise_band_var[i] /= dnch->noise_band_norm[i]; + dnch->noise_band_var[i] -= dnch->noise_band_avr[i] * dnch->noise_band_avr[i] + + dnch->noise_band_avi[i] * dnch->noise_band_avi[i]; + dnch->noise_band_auto_var[i] = dnch->noise_band_var[i]; + sample_noise[i] = (1.0 / C) * log(dnch->noise_band_var[i] / s->floor) - 100.0; + } + if (s->noise_band_count < 15) { + for (int i = s->noise_band_count; i < 15; i++) + sample_noise[i] = sample_noise[i - 1]; + } +} + +static void set_noise_profile(AudioFFTDeNoiseContext *s, + DeNoiseChannel *dnch, + double *sample_noise, + int new_profile) +{ + int new_band_noise[15]; + double temp[15]; + double sum = 0.0, d1; + float new_noise_floor; + int i, n; + + for (int m = 0; m < 15; m++) + temp[m] = sample_noise[m]; + + if (new_profile) { + i = 0; + for (int m = 0; m < 5; m++) { + sum = 0.0; + for (n = 0; n < 15; n++) + sum += s->matrix_b[i++] * temp[n]; + s->vector_b[m] = sum; + } + solve(s->matrix_a, s->vector_b, 5); + i = 0; + for (int m = 0; m < 15; m++) { + sum = 0.0; + for (n = 0; n < 5; n++) + sum += s->matrix_c[i++] * s->vector_b[n]; + temp[m] = sum; + } + } + + sum = 0.0; + for (int m = 0; m < 15; m++) + sum += temp[m]; + + d1 = (int)(sum / 15.0 - 0.5); + if (!new_profile) + i = lrint(temp[7] - d1); + + for (d1 -= dnch->band_noise[7] - i; d1 > -20.0; d1 -= 1.0) + ; + + for (int m = 0; m < 15; m++) + temp[m] -= d1; + + new_noise_floor = d1 + 2.5; + + if (new_profile) { + av_log(s, AV_LOG_INFO, "bn="); + for (int m = 0; m < 15; m++) { + new_band_noise[m] = lrint(temp[m]); + new_band_noise[m] = av_clip(new_band_noise[m], -24, 24); + av_log(s, AV_LOG_INFO, "%d ", new_band_noise[m]); + } + av_log(s, AV_LOG_INFO, "\n"); + memcpy(dnch->band_noise, new_band_noise, sizeof(new_band_noise)); + } + + if (s->track_noise) + s->noise_floor = new_noise_floor; +} + +typedef struct ThreadData { + AVFrame *in; +} ThreadData; + +static int filter_channel(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) +{ + AudioFFTDeNoiseContext *s = ctx->priv; + ThreadData *td = arg; + AVFrame *in = td->in; + const int start = (in->channels * jobnr) / nb_jobs; + const int end = (in->channels * (jobnr+1)) / nb_jobs; + + for (int ch = start; ch < end; ch++) { + DeNoiseChannel *dnch = &s->dnch[ch]; + const float *src = (const float *)in->extended_data[ch]; + double *dst = dnch->out_samples; + + if (s->track_noise) { + int i = s->block_count & 0x1FF; + + if (dnch->sfm_fail_flags[i]) + dnch->sfm_fail_total--; + dnch->sfm_fail_flags[i] = 0; + dnch->sfm_threshold *= 1.0 - dnch->sfm_alpha; + dnch->sfm_threshold += dnch->sfm_alpha * (0.5 + (1.0 / 640) * dnch->sfm_fail_total); + } + + for (int m = 0; m < s->window_length; m++) { + dnch->fft_data[m].re = s->window[m] * src[m] * (1LL << 24); + dnch->fft_data[m].im = 0; + } + + for (int m = s->window_length; m < s->fft_length2; m++) { + dnch->fft_data[m].re = 0; + dnch->fft_data[m].im = 0; + } + + av_fft_permute(dnch->fft, dnch->fft_data); + av_fft_calc(dnch->fft, dnch->fft_data); + + preprocess(dnch->fft_data, s->fft_length); + process_frame(s, dnch, dnch->fft_data, + dnch->prior, + dnch->prior_band_excit, + s->track_noise); + postprocess(dnch->fft_data, s->fft_length); + + av_fft_permute(dnch->ifft, dnch->fft_data); + av_fft_calc(dnch->ifft, dnch->fft_data); + + for (int m = 0; m < s->window_length; m++) + dst[m] += s->window[m] * dnch->fft_data[m].re / (1LL << 24); + } + + return 0; +} + +static void get_auto_noise_levels(AudioFFTDeNoiseContext *s, + DeNoiseChannel *dnch, + double *levels) +{ + if (s->noise_band_count > 0) { + for (int i = 0; i < s->noise_band_count; i++) { + levels[i] = (1.0 / C) * log(dnch->noise_band_auto_var[i] / s->floor) - 100.0; + } + if (s->noise_band_count < 15) { + for (int i = s->noise_band_count; i < 15; i++) + levels[i] = levels[i - 1]; + } + } else { + for (int i = 0; i < 15; i++) { + levels[i] = -100.0; + } + } +} + +static int output_frame(AVFilterLink *inlink) +{ + AVFilterContext *ctx = inlink->dst; + AVFilterLink *outlink = ctx->outputs[0]; + AudioFFTDeNoiseContext *s = ctx->priv; + AVFrame *out = NULL, *in = NULL; + ThreadData td; + int ret = 0; + + in = ff_get_audio_buffer(outlink, s->window_length); + if (!in) + return AVERROR(ENOMEM); + + ret = av_audio_fifo_peek(s->fifo, (void **)in->extended_data, s->window_length); + if (ret < 0) + goto end; + + if (s->track_noise) { + for (int ch = 0; ch < inlink->channels; ch++) { + DeNoiseChannel *dnch = &s->dnch[ch]; + double levels[15]; + + get_auto_noise_levels(s, dnch, levels); + set_noise_profile(s, dnch, levels, 0); + } + + if (s->noise_floor != s->last_noise_floor) + set_parameters(s); + } + + if (s->sample_noise_start) { + for (int ch = 0; ch < inlink->channels; ch++) { + DeNoiseChannel *dnch = &s->dnch[ch]; + + init_sample_noise(dnch); + } + s->sample_noise_start = 0; + s->sample_noise = 1; + } + + if (s->sample_noise) { + for (int ch = 0; ch < inlink->channels; ch++) { + DeNoiseChannel *dnch = &s->dnch[ch]; + + sample_noise_block(s, dnch, in, ch); + } + } + + if (s->sample_noise_end) { + for (int ch = 0; ch < inlink->channels; ch++) { + DeNoiseChannel *dnch = &s->dnch[ch]; + double sample_noise[15]; + + finish_sample_noise(s, dnch, sample_noise); + set_noise_profile(s, dnch, sample_noise, 1); + set_band_parameters(s, dnch); + } + s->sample_noise = 0; + s->sample_noise_end = 0; + } + + s->block_count++; + td.in = in; + ctx->internal->execute(ctx, filter_channel, &td, NULL, + FFMIN(outlink->channels, ff_filter_get_nb_threads(ctx))); + + out = ff_get_audio_buffer(outlink, s->sample_advance); + if (!out) { + ret = AVERROR(ENOMEM); + goto end; + } + + for (int ch = 0; ch < inlink->channels; ch++) { + DeNoiseChannel *dnch = &s->dnch[ch]; + double *src = dnch->out_samples; + float *orig = (float *)in->extended_data[ch]; + float *dst = (float *)out->extended_data[ch]; + + switch (s->output_mode) { + case IN_MODE: + for (int m = 0; m < s->sample_advance; m++) + dst[m] = orig[m]; + break; + case OUT_MODE: + for (int m = 0; m < s->sample_advance; m++) + dst[m] = src[m]; + break; + case NOISE_MODE: + for (int m = 0; m < s->sample_advance; m++) + dst[m] = orig[m] - src[m]; + break; + default: + av_frame_free(&out); + ret = AVERROR_BUG; + goto end; + } + memmove(src, src + s->sample_advance, (s->window_length - s->sample_advance) * sizeof(*src)); + memset(src + (s->window_length - s->sample_advance), 0, s->sample_advance * sizeof(*src)); + } + + av_audio_fifo_drain(s->fifo, s->sample_advance); + + out->pts = s->pts; + ret = ff_filter_frame(outlink, out); + if (ret < 0) + goto end; + s->pts += s->sample_advance; +end: + av_frame_free(&in); + + return ret; +} + +static int activate(AVFilterContext *ctx) +{ + AVFilterLink *inlink = ctx->inputs[0]; + AVFilterLink *outlink = ctx->outputs[0]; + AudioFFTDeNoiseContext *s = ctx->priv; + AVFrame *frame = NULL; + int ret; + + FF_FILTER_FORWARD_STATUS_BACK(outlink, inlink); + + ret = ff_inlink_consume_frame(inlink, &frame); + if (ret < 0) + return ret; + + if (ret > 0) { + if (s->pts == AV_NOPTS_VALUE) + s->pts = frame->pts; + + ret = av_audio_fifo_write(s->fifo, (void **)frame->extended_data, frame->nb_samples); + av_frame_free(&frame); + if (ret < 0) + return ret; + } + + if (av_audio_fifo_size(s->fifo) >= s->window_length) + return output_frame(inlink); + + FF_FILTER_FORWARD_STATUS(inlink, outlink); + if (ff_outlink_frame_wanted(outlink) && + av_audio_fifo_size(s->fifo) < s->window_length) { + ff_inlink_request_frame(inlink); + return 0; + } + + return FFERROR_NOT_READY; +} + +static av_cold void uninit(AVFilterContext *ctx) +{ + AudioFFTDeNoiseContext *s = ctx->priv; + + av_freep(&s->window); + av_freep(&s->bin2band); + av_freep(&s->band_alpha); + av_freep(&s->band_beta); + + if (s->dnch) { + for (int ch = 0; ch < s->channels; ch++) { + DeNoiseChannel *dnch = &s->dnch[ch]; + av_freep(&dnch->amt); + av_freep(&dnch->band_amt); + av_freep(&dnch->band_excit); + av_freep(&dnch->gain); + av_freep(&dnch->prior); + av_freep(&dnch->prior_band_excit); + av_freep(&dnch->clean_data); + av_freep(&dnch->noisy_data); + av_freep(&dnch->out_samples); + av_freep(&dnch->spread_function); + av_freep(&dnch->abs_var); + av_freep(&dnch->rel_var); + av_freep(&dnch->min_abs_var); + av_freep(&dnch->fft_data); + av_fft_end(dnch->fft); + dnch->fft = NULL; + av_fft_end(dnch->ifft); + dnch->ifft = NULL; + } + av_freep(&s->dnch); + } + + av_audio_fifo_free(s->fifo); +} + +static int query_formats(AVFilterContext *ctx) +{ + AVFilterFormats *formats = NULL; + AVFilterChannelLayouts *layouts = NULL; + static const enum AVSampleFormat sample_fmts[] = { + AV_SAMPLE_FMT_FLTP, + AV_SAMPLE_FMT_NONE + }; + int ret; + + formats = ff_make_format_list(sample_fmts); + if (!formats) + return AVERROR(ENOMEM); + ret = ff_set_common_formats(ctx, formats); + if (ret < 0) + return ret; + + layouts = ff_all_channel_counts(); + if (!layouts) + return AVERROR(ENOMEM); + + ret = ff_set_common_channel_layouts(ctx, layouts); + if (ret < 0) + return ret; + + formats = ff_all_samplerates(); + return ff_set_common_samplerates(ctx, formats); +} + +static int process_command(AVFilterContext *ctx, const char *cmd, const char *args, + char *res, int res_len, int flags) +{ + AudioFFTDeNoiseContext *s = ctx->priv; + int need_reset = 0; + + if (!strcmp(cmd, "sample_noise") || + !strcmp(cmd, "sn")) { + if (!strcmp(args, "start")) { + s->sample_noise_start = 1; + s->sample_noise_end = 0; + } else if (!strcmp(args, "end") || + !strcmp(args, "stop")) { + s->sample_noise_start = 0; + s->sample_noise_end = 1; + } + } else if (!strcmp(cmd, "nr") || + !strcmp(cmd, "noise_reduction")) { + float nr; + + if (av_sscanf(args, "%f", &nr) == 1) { + s->noise_reduction = av_clipf(nr, 0.01, 97); + need_reset = 1; + } + } else if (!strcmp(cmd, "nf") || + !strcmp(cmd, "noise_floor")) { + float nf; + + if (av_sscanf(args, "%f", &nf) == 1) { + s->noise_floor = av_clipf(nf, -80, -20); + need_reset = 1; + } + } else if (!strcmp(cmd, "output_mode") || + !strcmp(cmd, "om")) { + if (!strcmp(args, "i")) { + s->output_mode = IN_MODE; + } else if (!strcmp(args, "o")) { + s->output_mode = OUT_MODE; + } else if (!strcmp(args, "n")) { + s->output_mode = NOISE_MODE; + } + } + + if (need_reset) + set_parameters(s); + + return 0; +} + +static const AVFilterPad inputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_AUDIO, + .config_props = config_input, + }, + { NULL } +}; + +static const AVFilterPad outputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_AUDIO, + }, + { NULL } +}; + +AVFilter ff_af_afftdn = { + .name = "afftdn", + .description = NULL_IF_CONFIG_SMALL("Denoise audio samples using FFT."), + .query_formats = query_formats, + .priv_size = sizeof(AudioFFTDeNoiseContext), + .priv_class = &afftdn_class, + .activate = activate, + .uninit = uninit, + .inputs = inputs, + .outputs = outputs, + .process_command = process_command, + .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | + AVFILTER_FLAG_SLICE_THREADS, +}; diff --git a/libavfilter/af_afftfilt.c b/libavfilter/af_afftfilt.c index 7f28e1f77..86278ef35 100644 --- a/libavfilter/af_afftfilt.c +++ b/libavfilter/af_afftfilt.c @@ -26,16 +26,19 @@ #include "libavcodec/avfft.h" #include "libavutil/eval.h" #include "audio.h" +#include "filters.h" #include "window_func.h" typedef struct AFFTFiltContext { const AVClass *class; char *real_str; char *img_str; + int fft_size; int fft_bits; FFTContext *fft, *ifft; FFTComplex **fft_data; + FFTComplex **fft_temp; int nb_exprs; int window_size; AVExpr **real; @@ -45,59 +48,89 @@ typedef struct AFFTFiltContext { int hop_size; float overlap; AVFrame *buffer; - int start, end; + int eof; int win_func; - float win_scale; float *window_func_lut; } AFFTFiltContext; -static const char *const var_names[] = { "sr", "b", "nb", "ch", "chs", "pts", NULL }; -enum { VAR_SAMPLE_RATE, VAR_BIN, VAR_NBBINS, VAR_CHANNEL, VAR_CHANNELS, VAR_PTS, VAR_VARS_NB }; +static const char *const var_names[] = { "sr", "b", "nb", "ch", "chs", "pts", "re", "im", NULL }; +enum { VAR_SAMPLE_RATE, VAR_BIN, VAR_NBBINS, VAR_CHANNEL, VAR_CHANNELS, VAR_PTS, VAR_REAL, VAR_IMAG, VAR_VARS_NB }; #define OFFSET(x) offsetof(AFFTFiltContext, x) #define A AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM static const AVOption afftfilt_options[] = { - { "real", "set channels real expressions", OFFSET(real_str), AV_OPT_TYPE_STRING, {.str = "1" }, 0, 0, A }, - { "imag", "set channels imaginary expressions", OFFSET(img_str), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, A }, - { "win_size", "set window size", OFFSET(fft_bits), AV_OPT_TYPE_INT, {.i64=12}, 4, 17, A, "fft" }, - { "w16", 0, 0, AV_OPT_TYPE_CONST, {.i64=4}, 0, 0, A, "fft" }, - { "w32", 0, 0, AV_OPT_TYPE_CONST, {.i64=5}, 0, 0, A, "fft" }, - { "w64", 0, 0, AV_OPT_TYPE_CONST, {.i64=6}, 0, 0, A, "fft" }, - { "w128", 0, 0, AV_OPT_TYPE_CONST, {.i64=7}, 0, 0, A, "fft" }, - { "w256", 0, 0, AV_OPT_TYPE_CONST, {.i64=8}, 0, 0, A, "fft" }, - { "w512", 0, 0, AV_OPT_TYPE_CONST, {.i64=9}, 0, 0, A, "fft" }, - { "w1024", 0, 0, AV_OPT_TYPE_CONST, {.i64=10}, 0, 0, A, "fft" }, - { "w2048", 0, 0, AV_OPT_TYPE_CONST, {.i64=11}, 0, 0, A, "fft" }, - { "w4096", 0, 0, AV_OPT_TYPE_CONST, {.i64=12}, 0, 0, A, "fft" }, - { "w8192", 0, 0, AV_OPT_TYPE_CONST, {.i64=13}, 0, 0, A, "fft" }, - { "w16384", 0, 0, AV_OPT_TYPE_CONST, {.i64=14}, 0, 0, A, "fft" }, - { "w32768", 0, 0, AV_OPT_TYPE_CONST, {.i64=15}, 0, 0, A, "fft" }, - { "w65536", 0, 0, AV_OPT_TYPE_CONST, {.i64=16}, 0, 0, A, "fft" }, - { "w131072",0, 0, AV_OPT_TYPE_CONST, {.i64=17}, 0, 0, A, "fft" }, + { "real", "set channels real expressions", OFFSET(real_str), AV_OPT_TYPE_STRING, {.str = "re" }, 0, 0, A }, + { "imag", "set channels imaginary expressions", OFFSET(img_str), AV_OPT_TYPE_STRING, {.str = "im" }, 0, 0, A }, + { "win_size", "set window size", OFFSET(fft_size), AV_OPT_TYPE_INT, {.i64=4096}, 16, 131072, A }, { "win_func", "set window function", OFFSET(win_func), AV_OPT_TYPE_INT, {.i64 = WFUNC_HANNING}, 0, NB_WFUNC-1, A, "win_func" }, { "rect", "Rectangular", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_RECT}, 0, 0, A, "win_func" }, { "bartlett", "Bartlett", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_BARTLETT}, 0, 0, A, "win_func" }, { "hann", "Hann", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_HANNING}, 0, 0, A, "win_func" }, { "hanning", "Hanning", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_HANNING}, 0, 0, A, "win_func" }, { "hamming", "Hamming", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_HAMMING}, 0, 0, A, "win_func" }, + { "blackman", "Blackman", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_BLACKMAN}, 0, 0, A, "win_func" }, + { "welch", "Welch", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_WELCH}, 0, 0, A, "win_func" }, + { "flattop", "Flat-top", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_FLATTOP}, 0, 0, A, "win_func" }, + { "bharris", "Blackman-Harris", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_BHARRIS}, 0, 0, A, "win_func" }, + { "bnuttall", "Blackman-Nuttall", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_BNUTTALL}, 0, 0, A, "win_func" }, + { "bhann", "Bartlett-Hann", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_BHANN}, 0, 0, A, "win_func" }, { "sine", "Sine", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_SINE}, 0, 0, A, "win_func" }, + { "nuttall", "Nuttall", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_NUTTALL}, 0, 0, A, "win_func" }, + { "lanczos", "Lanczos", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_LANCZOS}, 0, 0, A, "win_func" }, + { "gauss", "Gauss", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_GAUSS}, 0, 0, A, "win_func" }, + { "tukey", "Tukey", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_TUKEY}, 0, 0, A, "win_func" }, + { "dolph", "Dolph-Chebyshev", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_DOLPH}, 0, 0, A, "win_func" }, + { "cauchy", "Cauchy", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_CAUCHY}, 0, 0, A, "win_func" }, + { "parzen", "Parzen", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_PARZEN}, 0, 0, A, "win_func" }, + { "poisson", "Poisson", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_POISSON}, 0, 0, A, "win_func" }, + { "bohman", "Bohman", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_BOHMAN}, 0, 0, A, "win_func" }, { "overlap", "set window overlap", OFFSET(overlap), AV_OPT_TYPE_FLOAT, {.dbl=0.75}, 0, 1, A }, { NULL }, }; AVFILTER_DEFINE_CLASS(afftfilt); +static inline double getreal(void *priv, double x, double ch) +{ + AFFTFiltContext *s = priv; + int ich, ix; + + ich = av_clip(ch, 0, s->nb_exprs - 1); + ix = av_clip(x, 0, s->window_size / 2); + + return s->fft_data[ich][ix].re; +} + +static inline double getimag(void *priv, double x, double ch) +{ + AFFTFiltContext *s = priv; + int ich, ix; + + ich = av_clip(ch, 0, s->nb_exprs - 1); + ix = av_clip(x, 0, s->window_size / 2); + + return s->fft_data[ich][ix].im; +} + +static double realf(void *priv, double x, double ch) { return getreal(priv, x, ch); } +static double imagf(void *priv, double x, double ch) { return getimag(priv, x, ch); } + +static const char *const func2_names[] = { "real", "imag", NULL }; +double (*func2[])(void *, double, double) = { realf, imagf, NULL }; + static int config_input(AVFilterLink *inlink) { AVFilterContext *ctx = inlink->dst; AFFTFiltContext *s = ctx->priv; char *saveptr = NULL; - int ret = 0, ch, i; + int ret = 0, ch; float overlap; char *args; const char *last_expr = "1"; + s->pts = AV_NOPTS_VALUE; + s->fft_bits = av_log2(s->fft_size); s->fft = av_fft_init(s->fft_bits, 0); s->ifft = av_fft_init(s->fft_bits, 1); if (!s->fft || !s->ifft) @@ -109,12 +142,22 @@ static int config_input(AVFilterLink *inlink) if (!s->fft_data) return AVERROR(ENOMEM); + s->fft_temp = av_calloc(inlink->channels, sizeof(*s->fft_temp)); + if (!s->fft_temp) + return AVERROR(ENOMEM); + for (ch = 0; ch < inlink->channels; ch++) { s->fft_data[ch] = av_calloc(s->window_size, sizeof(**s->fft_data)); if (!s->fft_data[ch]) return AVERROR(ENOMEM); } + for (ch = 0; ch < inlink->channels; ch++) { + s->fft_temp[ch] = av_calloc(s->window_size, sizeof(**s->fft_temp)); + if (!s->fft_temp[ch]) + return AVERROR(ENOMEM); + } + s->real = av_calloc(inlink->channels, sizeof(*s->real)); if (!s->real) return AVERROR(ENOMEM); @@ -131,7 +174,7 @@ static int config_input(AVFilterLink *inlink) char *arg = av_strtok(ch == 0 ? args : NULL, "|", &saveptr); ret = av_expr_parse(&s->real[ch], arg ? arg : last_expr, var_names, - NULL, NULL, NULL, NULL, 0, ctx); + NULL, NULL, func2_names, func2, 0, ctx); if (ret < 0) break; if (arg) @@ -149,7 +192,7 @@ static int config_input(AVFilterLink *inlink) char *arg = av_strtok(ch == 0 ? args : NULL, "|", &saveptr); ret = av_expr_parse(&s->imag[ch], arg ? arg : last_expr, var_names, - NULL, NULL, NULL, NULL, 0, ctx); + NULL, NULL, func2_names, func2, 0, ctx); if (ret < 0) break; if (arg) @@ -170,10 +213,6 @@ static int config_input(AVFilterLink *inlink) if (s->overlap == 1) s->overlap = overlap; - for (s->win_scale = 0, i = 0; i < s->window_size; i++) { - s->win_scale += s->window_func_lut[i] * s->window_func_lut[i]; - } - s->hop_size = s->window_size * (1 - s->overlap); if (s->hop_size <= 0) return AVERROR(EINVAL); @@ -185,142 +224,174 @@ static int config_input(AVFilterLink *inlink) return ret; } -static int filter_frame(AVFilterLink *inlink, AVFrame *frame) +static int filter_frame(AVFilterLink *inlink) { AVFilterContext *ctx = inlink->dst; AVFilterLink *outlink = ctx->outputs[0]; AFFTFiltContext *s = ctx->priv; const int window_size = s->window_size; - const float f = 1. / s->win_scale; + const float f = 1. / (s->window_size / 2); double values[VAR_VARS_NB]; AVFrame *out, *in = NULL; - int ch, n, ret, i, j, k; - int start = s->start, end = s->end; + int ch, n, ret, i; - ret = av_audio_fifo_write(s->fifo, (void **)frame->extended_data, frame->nb_samples); - av_frame_free(&frame); - if (ret < 0) - return ret; - - while (av_audio_fifo_size(s->fifo) >= window_size) { - if (!in) { - in = ff_get_audio_buffer(outlink, window_size); - if (!in) - return AVERROR(ENOMEM); - } - - ret = av_audio_fifo_peek(s->fifo, (void **)in->extended_data, window_size); - if (ret < 0) - break; - - for (ch = 0; ch < inlink->channels; ch++) { - const float *src = (float *)in->extended_data[ch]; - FFTComplex *fft_data = s->fft_data[ch]; - - for (n = 0; n < in->nb_samples; n++) { - fft_data[n].re = src[n] * s->window_func_lut[n]; - fft_data[n].im = 0; - } - - for (; n < window_size; n++) { - fft_data[n].re = 0; - fft_data[n].im = 0; - } - } - - values[VAR_PTS] = s->pts; - values[VAR_SAMPLE_RATE] = inlink->sample_rate; - values[VAR_NBBINS] = window_size / 2; - values[VAR_CHANNELS] = inlink->channels; - - for (ch = 0; ch < inlink->channels; ch++) { - FFTComplex *fft_data = s->fft_data[ch]; - float *buf = (float *)s->buffer->extended_data[ch]; - int x; - - values[VAR_CHANNEL] = ch; - - av_fft_permute(s->fft, fft_data); - av_fft_calc(s->fft, fft_data); - - for (n = 0; n < window_size / 2; n++) { - float fr, fi; - - values[VAR_BIN] = n; - - fr = av_expr_eval(s->real[ch], values, s); - fi = av_expr_eval(s->imag[ch], values, s); - - fft_data[n].re *= fr; - fft_data[n].im *= fi; - } - - for (n = window_size / 2 + 1, x = window_size / 2 - 1; n < window_size; n++, x--) { - fft_data[n].re = fft_data[x].re; - fft_data[n].im = -fft_data[x].im; - } - - av_fft_permute(s->ifft, fft_data); - av_fft_calc(s->ifft, fft_data); - - start = s->start; - end = s->end; - k = end; - for (i = 0, j = start; j < k && i < window_size; i++, j++) { - buf[j] += s->fft_data[ch][i].re * f; - } - - for (; i < window_size; i++, j++) { - buf[j] = s->fft_data[ch][i].re * f; - } - - start += s->hop_size; - end = j; - } - - s->start = start; - s->end = end; - - if (start >= window_size) { - float *dst, *buf; - - start -= window_size; - end -= window_size; - - s->start = start; - s->end = end; - - out = ff_get_audio_buffer(outlink, window_size); - if (!out) { - ret = AVERROR(ENOMEM); - break; - } - - out->pts = s->pts; - s->pts += window_size; - - for (ch = 0; ch < inlink->channels; ch++) { - dst = (float *)out->extended_data[ch]; - buf = (float *)s->buffer->extended_data[ch]; - - for (n = 0; n < window_size; n++) { - dst[n] = buf[n] * (1 - s->overlap); - } - memmove(buf, buf + window_size, window_size * 4); - } - - ret = ff_filter_frame(outlink, out); - if (ret < 0) - break; - } - - av_audio_fifo_drain(s->fifo, s->hop_size); + if (!in) { + in = ff_get_audio_buffer(outlink, window_size); + if (!in) + return AVERROR(ENOMEM); } + ret = av_audio_fifo_peek(s->fifo, (void **)in->extended_data, window_size); + if (ret < 0) + goto fail; + + for (ch = 0; ch < inlink->channels; ch++) { + const float *src = (float *)in->extended_data[ch]; + FFTComplex *fft_data = s->fft_data[ch]; + + for (n = 0; n < in->nb_samples; n++) { + fft_data[n].re = src[n] * s->window_func_lut[n]; + fft_data[n].im = 0; + } + + for (; n < window_size; n++) { + fft_data[n].re = 0; + fft_data[n].im = 0; + } + } + + values[VAR_PTS] = s->pts; + values[VAR_SAMPLE_RATE] = inlink->sample_rate; + values[VAR_NBBINS] = window_size / 2; + values[VAR_CHANNELS] = inlink->channels; + + for (ch = 0; ch < inlink->channels; ch++) { + FFTComplex *fft_data = s->fft_data[ch]; + + av_fft_permute(s->fft, fft_data); + av_fft_calc(s->fft, fft_data); + } + + for (ch = 0; ch < inlink->channels; ch++) { + FFTComplex *fft_data = s->fft_data[ch]; + FFTComplex *fft_temp = s->fft_temp[ch]; + float *buf = (float *)s->buffer->extended_data[ch]; + int x; + values[VAR_CHANNEL] = ch; + + for (n = 0; n <= window_size / 2; n++) { + float fr, fi; + + values[VAR_BIN] = n; + values[VAR_REAL] = fft_data[n].re; + values[VAR_IMAG] = fft_data[n].im; + + fr = av_expr_eval(s->real[ch], values, s); + fi = av_expr_eval(s->imag[ch], values, s); + + fft_temp[n].re = fr; + fft_temp[n].im = fi; + } + + for (n = window_size / 2 + 1, x = window_size / 2 - 1; n < window_size; n++, x--) { + fft_temp[n].re = fft_temp[x].re; + fft_temp[n].im = -fft_temp[x].im; + } + + av_fft_permute(s->ifft, fft_temp); + av_fft_calc(s->ifft, fft_temp); + + for (i = 0; i < window_size; i++) { + buf[i] += s->fft_temp[ch][i].re * f; + } + } + + out = ff_get_audio_buffer(outlink, s->hop_size); + if (!out) { + ret = AVERROR(ENOMEM); + goto fail; + } + + out->pts = s->pts; + s->pts += s->hop_size; + + for (ch = 0; ch < inlink->channels; ch++) { + float *dst = (float *)out->extended_data[ch]; + float *buf = (float *)s->buffer->extended_data[ch]; + + for (n = 0; n < s->hop_size; n++) + dst[n] = buf[n] * (1.f - s->overlap); + memmove(buf, buf + s->hop_size, window_size * 4); + } + + ret = ff_filter_frame(outlink, out); + if (ret < 0) + goto fail; + + av_audio_fifo_drain(s->fifo, s->hop_size); + +fail: av_frame_free(&in); return ret < 0 ? ret : 0; } +static int activate(AVFilterContext *ctx) +{ + AVFilterLink *inlink = ctx->inputs[0]; + AVFilterLink *outlink = ctx->outputs[0]; + AFFTFiltContext *s = ctx->priv; + AVFrame *in = NULL; + int ret = 0, status; + int64_t pts; + + FF_FILTER_FORWARD_STATUS_BACK(outlink, inlink); + + if (!s->eof && av_audio_fifo_size(s->fifo) < s->window_size) { + ret = ff_inlink_consume_frame(inlink, &in); + if (ret < 0) + return ret; + + if (ret > 0) { + ret = av_audio_fifo_write(s->fifo, (void **)in->extended_data, + in->nb_samples); + if (ret >= 0 && s->pts == AV_NOPTS_VALUE) + s->pts = in->pts; + + av_frame_free(&in); + if (ret < 0) + return ret; + } + } + + if ((av_audio_fifo_size(s->fifo) >= s->window_size) || + (av_audio_fifo_size(s->fifo) > 0 && s->eof)) { + ret = filter_frame(inlink); + if (av_audio_fifo_size(s->fifo) >= s->window_size) + ff_filter_set_ready(ctx, 100); + return ret; + } + + if (!s->eof && ff_inlink_acknowledge_status(inlink, &status, &pts)) { + if (status == AVERROR_EOF) { + s->eof = 1; + if (av_audio_fifo_size(s->fifo) >= 0) { + ff_filter_set_ready(ctx, 100); + return 0; + } + } + } + + if (s->eof && av_audio_fifo_size(s->fifo) <= 0) { + ff_outlink_set_status(outlink, AVERROR_EOF, s->pts); + return 0; + } + + if (!s->eof) + FF_FILTER_FORWARD_WANTED(outlink, inlink); + + return FFERROR_NOT_READY; +} + static int query_formats(AVFilterContext *ctx) { AVFilterFormats *formats; @@ -362,8 +433,11 @@ static av_cold void uninit(AVFilterContext *ctx) for (i = 0; i < s->nb_exprs; i++) { if (s->fft_data) av_freep(&s->fft_data[i]); + if (s->fft_temp) + av_freep(&s->fft_temp[i]); } av_freep(&s->fft_data); + av_freep(&s->fft_temp); for (i = 0; i < s->nb_exprs; i++) { av_expr_free(s->real[i]); @@ -383,7 +457,6 @@ static const AVFilterPad inputs[] = { .name = "default", .type = AVMEDIA_TYPE_AUDIO, .config_props = config_input, - .filter_frame = filter_frame, }, { NULL } }; @@ -403,6 +476,7 @@ AVFilter ff_af_afftfilt = { .priv_class = &afftfilt_class, .inputs = inputs, .outputs = outputs, + .activate = activate, .query_formats = query_formats, .uninit = uninit, }; diff --git a/libavfilter/af_afir.c b/libavfilter/af_afir.c index 668724263..31919f62e 100644 --- a/libavfilter/af_afir.c +++ b/libavfilter/af_afir.c @@ -23,14 +23,18 @@ * An arbitrary audio FIR filter */ -#include "libavutil/audio_fifo.h" +#include + #include "libavutil/common.h" #include "libavutil/float_dsp.h" +#include "libavutil/intreadwrite.h" #include "libavutil/opt.h" +#include "libavutil/xga_font_data.h" #include "libavcodec/avfft.h" #include "audio.h" #include "avfilter.h" +#include "filters.h" #include "formats.h" #include "internal.h" #include "af_afir.h" @@ -52,245 +56,474 @@ static void fcmul_add_c(float *sum, const float *t, const float *c, ptrdiff_t le sum[2 * n] += t[2 * n] * c[2 * n]; } -static int fir_channel(AVFilterContext *ctx, void *arg, int ch, int nb_jobs) +static int fir_quantum(AVFilterContext *ctx, AVFrame *out, int ch, int offset) { AudioFIRContext *s = ctx->priv; - const float *src = (const float *)s->in[0]->extended_data[ch]; - int index1 = (s->index + 1) % 3; - int index2 = (s->index + 2) % 3; - float *sum = s->sum[ch]; - AVFrame *out = arg; - float *block; - float *dst; + const float *in = (const float *)s->in[0]->extended_data[ch] + offset; + float *block, *buf, *ptr = (float *)out->extended_data[ch] + offset; + const int nb_samples = FFMIN(s->min_part_size, out->nb_samples - offset); int n, i, j; - memset(sum, 0, sizeof(*sum) * s->fft_length); - block = s->block[ch] + s->part_index * s->block_size; - memset(block, 0, sizeof(*block) * s->fft_length); + for (int segment = 0; segment < s->nb_segments; segment++) { + AudioFIRSegment *seg = &s->seg[segment]; + float *src = (float *)seg->input->extended_data[ch]; + float *dst = (float *)seg->output->extended_data[ch]; + float *sum = (float *)seg->sum->extended_data[ch]; - s->fdsp->vector_fmul_scalar(block + s->part_size, src, s->dry_gain, FFALIGN(s->nb_samples, 4)); + s->fdsp->vector_fmul_scalar(src + seg->input_offset, in, s->dry_gain, FFALIGN(nb_samples, 4)); + emms_c(); + + seg->output_offset[ch] += s->min_part_size; + if (seg->output_offset[ch] == seg->part_size) { + seg->output_offset[ch] = 0; + } else { + memmove(src, src + s->min_part_size, (seg->input_size - s->min_part_size) * sizeof(*src)); + + dst += seg->output_offset[ch]; + for (n = 0; n < nb_samples; n++) { + ptr[n] += dst[n]; + } + continue; + } + + memset(sum, 0, sizeof(*sum) * seg->fft_length); + block = (float *)seg->block->extended_data[ch] + seg->part_index[ch] * seg->block_size; + memset(block + seg->part_size, 0, sizeof(*block) * (seg->fft_length - seg->part_size)); + + memcpy(block, src, sizeof(*src) * seg->part_size); + + av_rdft_calc(seg->rdft[ch], block); + block[2 * seg->part_size] = block[1]; + block[1] = 0; + + j = seg->part_index[ch]; + + for (i = 0; i < seg->nb_partitions; i++) { + const int coffset = j * seg->coeff_size; + const float *block = (const float *)seg->block->extended_data[ch] + i * seg->block_size; + const FFTComplex *coeff = (const FFTComplex *)seg->coeff->extended_data[ch * !s->one2many] + coffset; + + s->afirdsp.fcmul_add(sum, block, (const float *)coeff, seg->part_size); + + if (j == 0) + j = seg->nb_partitions; + j--; + } + + sum[1] = sum[2 * seg->part_size]; + av_rdft_calc(seg->irdft[ch], sum); + + buf = (float *)seg->buffer->extended_data[ch]; + for (n = 0; n < seg->part_size; n++) { + buf[n] += sum[n]; + } + + memcpy(dst, buf, seg->part_size * sizeof(*dst)); + + buf = (float *)seg->buffer->extended_data[ch]; + memcpy(buf, sum + seg->part_size, seg->part_size * sizeof(*buf)); + + seg->part_index[ch] = (seg->part_index[ch] + 1) % seg->nb_partitions; + + memmove(src, src + s->min_part_size, (seg->input_size - s->min_part_size) * sizeof(*src)); + + for (n = 0; n < nb_samples; n++) { + ptr[n] += dst[n]; + } + } + + s->fdsp->vector_fmul_scalar(ptr, ptr, s->wet_gain, FFALIGN(nb_samples, 4)); emms_c(); - av_rdft_calc(s->rdft[ch], block); - block[2 * s->part_size] = block[1]; - block[1] = 0; + return 0; +} - j = s->part_index; +static int fir_channel(AVFilterContext *ctx, AVFrame *out, int ch) +{ + AudioFIRContext *s = ctx->priv; - for (i = 0; i < s->nb_partitions; i++) { - const int coffset = i * s->coeff_size; - const FFTComplex *coeff = s->coeff[ch * !s->one2many] + coffset; - - block = s->block[ch] + j * s->block_size; - s->fcmul_add(sum, block, (const float *)coeff, s->part_size); - - if (j == 0) - j = s->nb_partitions; - j--; - } - - sum[1] = sum[2 * s->part_size]; - av_rdft_calc(s->irdft[ch], sum); - - dst = (float *)s->buffer->extended_data[ch] + index1 * s->part_size; - for (n = 0; n < s->part_size; n++) { - dst[n] += sum[n]; - } - - dst = (float *)s->buffer->extended_data[ch] + index2 * s->part_size; - - memcpy(dst, sum + s->part_size, s->part_size * sizeof(*dst)); - - dst = (float *)s->buffer->extended_data[ch] + s->index * s->part_size; - - if (out) { - float *ptr = (float *)out->extended_data[ch]; - s->fdsp->vector_fmul_scalar(ptr, dst, s->wet_gain, FFALIGN(out->nb_samples, 4)); - emms_c(); + for (int offset = 0; offset < out->nb_samples; offset += s->min_part_size) { + fir_quantum(ctx, out, ch, offset); } return 0; } -static int fir_frame(AudioFIRContext *s, AVFilterLink *outlink) +static int fir_channels(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) +{ + AVFrame *out = arg; + const int start = (out->channels * jobnr) / nb_jobs; + const int end = (out->channels * (jobnr+1)) / nb_jobs; + + for (int ch = start; ch < end; ch++) { + fir_channel(ctx, out, ch); + } + + return 0; +} + +static int fir_frame(AudioFIRContext *s, AVFrame *in, AVFilterLink *outlink) { AVFilterContext *ctx = outlink->src; AVFrame *out = NULL; - int ret; - s->nb_samples = FFMIN(s->part_size, av_audio_fifo_size(s->fifo[0])); - - if (!s->want_skip) { - out = ff_get_audio_buffer(outlink, s->nb_samples); - if (!out) - return AVERROR(ENOMEM); - } - - s->in[0] = ff_get_audio_buffer(ctx->inputs[0], s->nb_samples); - if (!s->in[0]) { - av_frame_free(&out); + out = ff_get_audio_buffer(outlink, in->nb_samples); + if (!out) { + av_frame_free(&in); return AVERROR(ENOMEM); } - av_audio_fifo_peek(s->fifo[0], (void **)s->in[0]->extended_data, s->nb_samples); + if (s->pts == AV_NOPTS_VALUE) + s->pts = in->pts; + s->in[0] = in; + ctx->internal->execute(ctx, fir_channels, out, NULL, FFMIN(outlink->channels, + ff_filter_get_nb_threads(ctx))); - ctx->internal->execute(ctx, fir_channel, out, NULL, outlink->channels); + out->pts = s->pts; + if (s->pts != AV_NOPTS_VALUE) + s->pts += av_rescale_q(out->nb_samples, (AVRational){1, outlink->sample_rate}, outlink->time_base); - s->part_index = (s->part_index + 1) % s->nb_partitions; + av_frame_free(&in); + s->in[0] = NULL; - av_audio_fifo_drain(s->fifo[0], s->nb_samples); + return ff_filter_frame(outlink, out); +} - if (!s->want_skip) { - out->pts = s->pts; - if (s->pts != AV_NOPTS_VALUE) - s->pts += av_rescale_q(out->nb_samples, (AVRational){1, outlink->sample_rate}, outlink->time_base); +static void drawtext(AVFrame *pic, int x, int y, const char *txt, uint32_t color) +{ + const uint8_t *font; + int font_height; + int i; + + font = avpriv_cga_font, font_height = 8; + + for (i = 0; txt[i]; i++) { + int char_y, mask; + + uint8_t *p = pic->data[0] + y * pic->linesize[0] + (x + i * 8) * 4; + for (char_y = 0; char_y < font_height; char_y++) { + for (mask = 0x80; mask; mask >>= 1) { + if (font[txt[i] * font_height + char_y] & mask) + AV_WL32(p, color); + p += 4; + } + p += pic->linesize[0] - 8 * 4; + } + } +} + +static void draw_line(AVFrame *out, int x0, int y0, int x1, int y1, uint32_t color) +{ + int dx = FFABS(x1-x0); + int dy = FFABS(y1-y0), sy = y0 < y1 ? 1 : -1; + int err = (dx>dy ? dx : -dy) / 2, e2; + + for (;;) { + AV_WL32(out->data[0] + y0 * out->linesize[0] + x0 * 4, color); + + if (x0 == x1 && y0 == y1) + break; + + e2 = err; + + if (e2 >-dx) { + err -= dy; + x0--; + } + + if (e2 < dy) { + err += dx; + y0 += sy; + } + } +} + +static void draw_response(AVFilterContext *ctx, AVFrame *out) +{ + AudioFIRContext *s = ctx->priv; + float *mag, *phase, *delay, min = FLT_MAX, max = FLT_MIN; + float min_delay = FLT_MAX, max_delay = FLT_MIN; + int prev_ymag = -1, prev_yphase = -1, prev_ydelay = -1; + char text[32]; + int channel, i, x; + + memset(out->data[0], 0, s->h * out->linesize[0]); + + phase = av_malloc_array(s->w, sizeof(*phase)); + mag = av_malloc_array(s->w, sizeof(*mag)); + delay = av_malloc_array(s->w, sizeof(*delay)); + if (!mag || !phase || !delay) + goto end; + + channel = av_clip(s->ir_channel, 0, s->in[1]->channels - 1); + for (i = 0; i < s->w; i++) { + const float *src = (const float *)s->in[1]->extended_data[channel]; + double w = i * M_PI / (s->w - 1); + double div, real_num = 0., imag_num = 0., real = 0., imag = 0.; + + for (x = 0; x < s->nb_taps; x++) { + real += cos(-x * w) * src[x]; + imag += sin(-x * w) * src[x]; + real_num += cos(-x * w) * src[x] * x; + imag_num += sin(-x * w) * src[x] * x; + } + + mag[i] = hypot(real, imag); + phase[i] = atan2(imag, real); + div = real * real + imag * imag; + delay[i] = (real_num * real + imag_num * imag) / div; + min = fminf(min, mag[i]); + max = fmaxf(max, mag[i]); + min_delay = fminf(min_delay, delay[i]); + max_delay = fmaxf(max_delay, delay[i]); } - s->index++; - if (s->index == 3) - s->index = 0; + for (i = 0; i < s->w; i++) { + int ymag = mag[i] / max * (s->h - 1); + int ydelay = (delay[i] - min_delay) / (max_delay - min_delay) * (s->h - 1); + int yphase = (0.5 * (1. + phase[i] / M_PI)) * (s->h - 1); - av_frame_free(&s->in[0]); + ymag = s->h - 1 - av_clip(ymag, 0, s->h - 1); + yphase = s->h - 1 - av_clip(yphase, 0, s->h - 1); + ydelay = s->h - 1 - av_clip(ydelay, 0, s->h - 1); - if (s->want_skip == 1) { - s->want_skip = 0; - ret = 0; - } else { - ret = ff_filter_frame(outlink, out); + if (prev_ymag < 0) + prev_ymag = ymag; + if (prev_yphase < 0) + prev_yphase = yphase; + if (prev_ydelay < 0) + prev_ydelay = ydelay; + + draw_line(out, i, ymag, FFMAX(i - 1, 0), prev_ymag, 0xFFFF00FF); + draw_line(out, i, yphase, FFMAX(i - 1, 0), prev_yphase, 0xFF00FF00); + draw_line(out, i, ydelay, FFMAX(i - 1, 0), prev_ydelay, 0xFF00FFFF); + + prev_ymag = ymag; + prev_yphase = yphase; + prev_ydelay = ydelay; } - return ret; + if (s->w > 400 && s->h > 100) { + drawtext(out, 2, 2, "Max Magnitude:", 0xDDDDDDDD); + snprintf(text, sizeof(text), "%.2f", max); + drawtext(out, 15 * 8 + 2, 2, text, 0xDDDDDDDD); + + drawtext(out, 2, 12, "Min Magnitude:", 0xDDDDDDDD); + snprintf(text, sizeof(text), "%.2f", min); + drawtext(out, 15 * 8 + 2, 12, text, 0xDDDDDDDD); + + drawtext(out, 2, 22, "Max Delay:", 0xDDDDDDDD); + snprintf(text, sizeof(text), "%.2f", max_delay); + drawtext(out, 11 * 8 + 2, 22, text, 0xDDDDDDDD); + + drawtext(out, 2, 32, "Min Delay:", 0xDDDDDDDD); + snprintf(text, sizeof(text), "%.2f", min_delay); + drawtext(out, 11 * 8 + 2, 32, text, 0xDDDDDDDD); + } + +end: + av_free(delay); + av_free(phase); + av_free(mag); +} + +static int init_segment(AVFilterContext *ctx, AudioFIRSegment *seg, + int offset, int nb_partitions, int part_size) +{ + AudioFIRContext *s = ctx->priv; + + seg->rdft = av_calloc(ctx->inputs[0]->channels, sizeof(*seg->rdft)); + seg->irdft = av_calloc(ctx->inputs[0]->channels, sizeof(*seg->irdft)); + if (!seg->rdft || !seg->irdft) + return AVERROR(ENOMEM); + + seg->fft_length = part_size * 2 + 1; + seg->part_size = part_size; + seg->block_size = FFALIGN(seg->fft_length, 32); + seg->coeff_size = FFALIGN(seg->part_size + 1, 32); + seg->nb_partitions = nb_partitions; + seg->input_size = offset + s->min_part_size; + seg->input_offset = offset; + + seg->part_index = av_calloc(ctx->inputs[0]->channels, sizeof(*seg->part_index)); + seg->output_offset = av_calloc(ctx->inputs[0]->channels, sizeof(*seg->output_offset)); + if (!seg->part_index || !seg->output_offset) + return AVERROR(ENOMEM); + + for (int ch = 0; ch < ctx->inputs[0]->channels; ch++) { + seg->rdft[ch] = av_rdft_init(av_log2(2 * part_size), DFT_R2C); + seg->irdft[ch] = av_rdft_init(av_log2(2 * part_size), IDFT_C2R); + if (!seg->rdft[ch] || !seg->irdft[ch]) + return AVERROR(ENOMEM); + } + + seg->sum = ff_get_audio_buffer(ctx->inputs[0], seg->fft_length); + seg->block = ff_get_audio_buffer(ctx->inputs[0], seg->nb_partitions * seg->block_size); + seg->buffer = ff_get_audio_buffer(ctx->inputs[0], seg->part_size); + seg->coeff = ff_get_audio_buffer(ctx->inputs[1], seg->nb_partitions * seg->coeff_size * 2); + seg->input = ff_get_audio_buffer(ctx->inputs[0], seg->input_size); + seg->output = ff_get_audio_buffer(ctx->inputs[0], seg->part_size); + if (!seg->buffer || !seg->sum || !seg->block || !seg->coeff || !seg->input || !seg->output) + return AVERROR(ENOMEM); + + return 0; } static int convert_coeffs(AVFilterContext *ctx) { AudioFIRContext *s = ctx->priv; - int i, ch, n, N; + int left, offset = 0, part_size, max_part_size; + int ret, i, ch, n; + float power = 0; - s->nb_taps = av_audio_fifo_size(s->fifo[1]); + s->nb_taps = ff_inlink_queued_samples(ctx->inputs[1]); if (s->nb_taps <= 0) return AVERROR(EINVAL); - for (n = 4; (1 << n) < s->nb_taps; n++); - N = FFMIN(n, 16); - s->ir_length = 1 << n; - s->fft_length = (1 << (N + 1)) + 1; - s->part_size = 1 << (N - 1); - s->block_size = FFALIGN(s->fft_length, 32); - s->coeff_size = FFALIGN(s->part_size + 1, 32); - s->nb_partitions = (s->nb_taps + s->part_size - 1) / s->part_size; - s->nb_coeffs = s->ir_length + s->nb_partitions; - - for (ch = 0; ch < ctx->inputs[0]->channels; ch++) { - s->sum[ch] = av_calloc(s->fft_length, sizeof(**s->sum)); - if (!s->sum[ch]) - return AVERROR(ENOMEM); + if (s->minp > s->maxp) { + s->maxp = s->minp; } - for (ch = 0; ch < ctx->inputs[1]->channels; ch++) { - s->coeff[ch] = av_calloc(s->nb_partitions * s->coeff_size, sizeof(**s->coeff)); - if (!s->coeff[ch]) - return AVERROR(ENOMEM); + left = s->nb_taps; + part_size = 1 << av_log2(s->minp); + max_part_size = 1 << av_log2(s->maxp); + + s->min_part_size = part_size; + + for (i = 0; left > 0; i++) { + int step = part_size == max_part_size ? INT_MAX : 1 + (i == 0); + int nb_partitions = FFMIN(step, (left + part_size - 1) / part_size); + + s->nb_segments = i + 1; + ret = init_segment(ctx, &s->seg[i], offset, nb_partitions, part_size); + if (ret < 0) + return ret; + offset += nb_partitions * part_size; + left -= nb_partitions * part_size; + part_size *= 2; + part_size = FFMIN(part_size, max_part_size); } - for (ch = 0; ch < ctx->inputs[0]->channels; ch++) { - s->block[ch] = av_calloc(s->nb_partitions * s->block_size, sizeof(**s->block)); - if (!s->block[ch]) - return AVERROR(ENOMEM); - } + ret = ff_inlink_consume_samples(ctx->inputs[1], s->nb_taps, s->nb_taps, &s->in[1]); + if (ret < 0) + return ret; + if (ret == 0) + return AVERROR_BUG; - for (ch = 0; ch < ctx->inputs[0]->channels; ch++) { - s->rdft[ch] = av_rdft_init(N, DFT_R2C); - s->irdft[ch] = av_rdft_init(N, IDFT_C2R); - if (!s->rdft[ch] || !s->irdft[ch]) - return AVERROR(ENOMEM); - } + if (s->response) + draw_response(ctx, s->video); - s->in[1] = ff_get_audio_buffer(ctx->inputs[1], s->nb_taps); - if (!s->in[1]) - return AVERROR(ENOMEM); - - s->buffer = ff_get_audio_buffer(ctx->inputs[0], s->part_size * 3); - if (!s->buffer) - return AVERROR(ENOMEM); - - av_audio_fifo_read(s->fifo[1], (void **)s->in[1]->extended_data, s->nb_taps); - - if (s->again) { - float power = 0; + s->gain = 1; + switch (s->gtype) { + case -1: + /* nothing to do */ + break; + case 0: for (ch = 0; ch < ctx->inputs[1]->channels; ch++) { float *time = (float *)s->in[1]->extended_data[!s->one2many * ch]; for (i = 0; i < s->nb_taps; i++) power += FFABS(time[i]); } - - s->gain = sqrtf(1.f / (ctx->inputs[1]->channels * power)) / (sqrtf(ctx->inputs[1]->channels)); + s->gain = ctx->inputs[1]->channels / power; + break; + case 1: for (ch = 0; ch < ctx->inputs[1]->channels; ch++) { float *time = (float *)s->in[1]->extended_data[!s->one2many * ch]; - s->fdsp->vector_fmul_scalar(time, time, s->gain, FFALIGN(s->nb_taps, 4)); + for (i = 0; i < s->nb_taps; i++) + power += time[i]; } + s->gain = ctx->inputs[1]->channels / power; + break; + case 2: + for (ch = 0; ch < ctx->inputs[1]->channels; ch++) { + float *time = (float *)s->in[1]->extended_data[!s->one2many * ch]; + + for (i = 0; i < s->nb_taps; i++) + power += time[i] * time[i]; + } + s->gain = sqrtf(ch / power); + break; + default: + return AVERROR_BUG; } + s->gain = FFMIN(s->gain * s->ir_gain, 1.f); + av_log(ctx, AV_LOG_DEBUG, "power %f, gain %f\n", power, s->gain); + for (ch = 0; ch < ctx->inputs[1]->channels; ch++) { + float *time = (float *)s->in[1]->extended_data[!s->one2many * ch]; + + s->fdsp->vector_fmul_scalar(time, time, s->gain, FFALIGN(s->nb_taps, 4)); + } + + av_log(ctx, AV_LOG_DEBUG, "nb_taps: %d\n", s->nb_taps); + av_log(ctx, AV_LOG_DEBUG, "nb_segments: %d\n", s->nb_segments); + for (ch = 0; ch < ctx->inputs[1]->channels; ch++) { float *time = (float *)s->in[1]->extended_data[!s->one2many * ch]; - float *block = s->block[ch]; - FFTComplex *coeff = s->coeff[ch]; + int toffset = 0; for (i = FFMAX(1, s->length * s->nb_taps); i < s->nb_taps; i++) time[i] = 0; - for (i = 0; i < s->nb_partitions; i++) { - const float scale = 1.f / s->part_size; - const int toffset = i * s->part_size; - const int coffset = i * s->coeff_size; - const int boffset = s->part_size; - const int remaining = s->nb_taps - (i * s->part_size); - const int size = remaining >= s->part_size ? s->part_size : remaining; + av_log(ctx, AV_LOG_DEBUG, "channel: %d\n", ch); - memset(block, 0, sizeof(*block) * s->fft_length); - memcpy(block + boffset, time + toffset, size * sizeof(*block)); + for (int segment = 0; segment < s->nb_segments; segment++) { + AudioFIRSegment *seg = &s->seg[segment]; + float *block = (float *)seg->block->extended_data[ch]; + FFTComplex *coeff = (FFTComplex *)seg->coeff->extended_data[ch]; - av_rdft_calc(s->rdft[0], block); + av_log(ctx, AV_LOG_DEBUG, "segment: %d\n", segment); - coeff[coffset].re = block[0] * scale; - coeff[coffset].im = 0; - for (n = 1; n < s->part_size; n++) { - coeff[coffset + n].re = block[2 * n] * scale; - coeff[coffset + n].im = block[2 * n + 1] * scale; + for (i = 0; i < seg->nb_partitions; i++) { + const float scale = 1.f / seg->part_size; + const int coffset = i * seg->coeff_size; + const int remaining = s->nb_taps - toffset; + const int size = remaining >= seg->part_size ? seg->part_size : remaining; + + memset(block, 0, sizeof(*block) * seg->fft_length); + memcpy(block, time + toffset, size * sizeof(*block)); + + av_rdft_calc(seg->rdft[0], block); + + coeff[coffset].re = block[0] * scale; + coeff[coffset].im = 0; + for (n = 1; n < seg->part_size; n++) { + coeff[coffset + n].re = block[2 * n] * scale; + coeff[coffset + n].im = block[2 * n + 1] * scale; + } + coeff[coffset + seg->part_size].re = block[1] * scale; + coeff[coffset + seg->part_size].im = 0; + + toffset += size; } - coeff[coffset + s->part_size].re = block[1] * scale; - coeff[coffset + s->part_size].im = 0; + + av_log(ctx, AV_LOG_DEBUG, "nb_partitions: %d\n", seg->nb_partitions); + av_log(ctx, AV_LOG_DEBUG, "partition size: %d\n", seg->part_size); + av_log(ctx, AV_LOG_DEBUG, "block size: %d\n", seg->block_size); + av_log(ctx, AV_LOG_DEBUG, "fft_length: %d\n", seg->fft_length); + av_log(ctx, AV_LOG_DEBUG, "coeff_size: %d\n", seg->coeff_size); + av_log(ctx, AV_LOG_DEBUG, "input_size: %d\n", seg->input_size); + av_log(ctx, AV_LOG_DEBUG, "input_offset: %d\n", seg->input_offset); } } av_frame_free(&s->in[1]); - av_log(ctx, AV_LOG_DEBUG, "nb_taps: %d\n", s->nb_taps); - av_log(ctx, AV_LOG_DEBUG, "nb_partitions: %d\n", s->nb_partitions); - av_log(ctx, AV_LOG_DEBUG, "partition size: %d\n", s->part_size); - av_log(ctx, AV_LOG_DEBUG, "ir_length: %d\n", s->ir_length); - s->have_coeffs = 1; return 0; } -static int read_ir(AVFilterLink *link, AVFrame *frame) +static int check_ir(AVFilterLink *link, AVFrame *frame) { AVFilterContext *ctx = link->dst; AudioFIRContext *s = ctx->priv; - int nb_taps, max_nb_taps, ret; + int nb_taps, max_nb_taps; - ret = av_audio_fifo_write(s->fifo[1], (void **)frame->extended_data, - frame->nb_samples); - av_frame_free(&frame); - if (ret < 0) - return ret; - - nb_taps = av_audio_fifo_size(s->fifo[1]); - max_nb_taps = MAX_IR_DURATION * ctx->outputs[0]->sample_rate; + nb_taps = ff_inlink_queued_samples(link); + max_nb_taps = s->max_ir_len * ctx->outputs[0]->sample_rate; if (nb_taps > max_nb_taps) { av_log(ctx, AV_LOG_ERROR, "Too big number of coefficients: %d > %d.\n", nb_taps, max_nb_taps); return AVERROR(EINVAL); @@ -299,22 +532,35 @@ static int read_ir(AVFilterLink *link, AVFrame *frame) return 0; } -static int filter_frame(AVFilterLink *link, AVFrame *frame) +static int activate(AVFilterContext *ctx) { - AVFilterContext *ctx = link->dst; AudioFIRContext *s = ctx->priv; AVFilterLink *outlink = ctx->outputs[0]; - int ret; + int ret, status, available, wanted; + AVFrame *in = NULL; + int64_t pts; - ret = av_audio_fifo_write(s->fifo[0], (void **)frame->extended_data, - frame->nb_samples); - if (ret > 0 && s->pts == AV_NOPTS_VALUE) - s->pts = frame->pts; + FF_FILTER_FORWARD_STATUS_BACK_ALL(ctx->outputs[0], ctx); + if (s->response) + FF_FILTER_FORWARD_STATUS_BACK_ALL(ctx->outputs[1], ctx); + if (!s->eof_coeffs) { + AVFrame *ir = NULL; - av_frame_free(&frame); + ret = check_ir(ctx->inputs[1], ir); + if (ret < 0) + return ret; - if (ret < 0) - return ret; + if (ff_outlink_get_status(ctx->inputs[1]) == AVERROR_EOF) + s->eof_coeffs = 1; + + if (!s->eof_coeffs) { + if (ff_outlink_frame_wanted(ctx->outputs[0])) + ff_inlink_request_frame(ctx->inputs[1]); + else if (s->response && ff_outlink_frame_wanted(ctx->outputs[1])) + ff_inlink_request_frame(ctx->inputs[1]); + return 0; + } + } if (!s->have_coeffs && s->eof_coeffs) { ret = convert_coeffs(ctx); @@ -322,72 +568,97 @@ static int filter_frame(AVFilterLink *link, AVFrame *frame) return ret; } - if (s->have_coeffs) { - while (av_audio_fifo_size(s->fifo[0]) >= s->part_size) { - ret = fir_frame(s, outlink); - if (ret < 0) - return ret; - } - } - return 0; -} + available = ff_inlink_queued_samples(ctx->inputs[0]); + wanted = FFMAX(s->min_part_size, (available / s->min_part_size) * s->min_part_size); + ret = ff_inlink_consume_samples(ctx->inputs[0], wanted, wanted, &in); + if (ret > 0) + ret = fir_frame(s, in, outlink); -static int request_frame(AVFilterLink *outlink) -{ - AVFilterContext *ctx = outlink->src; - AudioFIRContext *s = ctx->priv; - int ret; - - if (!s->eof_coeffs) { - ret = ff_request_frame(ctx->inputs[1]); - if (ret == AVERROR_EOF) { - s->eof_coeffs = 1; - ret = 0; - } + if (ret < 0) return ret; - } - ret = ff_request_frame(ctx->inputs[0]); - if (ret == AVERROR_EOF && s->have_coeffs) { - if (s->need_padding) { - AVFrame *silence = ff_get_audio_buffer(outlink, s->part_size); - if (!silence) - return AVERROR(ENOMEM); - ret = av_audio_fifo_write(s->fifo[0], (void **)silence->extended_data, - silence->nb_samples); - av_frame_free(&silence); - if (ret < 0) - return ret; - s->need_padding = 0; - } + if (s->response && s->have_coeffs) { + int64_t old_pts = s->video->pts; + int64_t new_pts = av_rescale_q(s->pts, ctx->inputs[0]->time_base, ctx->outputs[1]->time_base); - while (av_audio_fifo_size(s->fifo[0]) > 0) { - ret = fir_frame(s, outlink); - if (ret < 0) - return ret; + if (ff_outlink_frame_wanted(ctx->outputs[1]) && old_pts < new_pts) { + s->video->pts = new_pts; + return ff_filter_frame(ctx->outputs[1], av_frame_clone(s->video)); } - ret = AVERROR_EOF; } - return ret; + + if (ff_inlink_queued_samples(ctx->inputs[0]) >= s->min_part_size) { + ff_filter_set_ready(ctx, 10); + return 0; + } + + if (ff_inlink_acknowledge_status(ctx->inputs[0], &status, &pts)) { + if (status == AVERROR_EOF) { + ff_outlink_set_status(ctx->outputs[0], status, pts); + if (s->response) + ff_outlink_set_status(ctx->outputs[1], status, pts); + return 0; + } + } + + if (ff_outlink_frame_wanted(ctx->outputs[0]) && + !ff_outlink_get_status(ctx->inputs[0])) { + ff_inlink_request_frame(ctx->inputs[0]); + return 0; + } + + if (s->response && + ff_outlink_frame_wanted(ctx->outputs[1]) && + !ff_outlink_get_status(ctx->inputs[0])) { + ff_inlink_request_frame(ctx->inputs[0]); + return 0; + } + + return FFERROR_NOT_READY; } static int query_formats(AVFilterContext *ctx) { + AudioFIRContext *s = ctx->priv; AVFilterFormats *formats; AVFilterChannelLayouts *layouts; static const enum AVSampleFormat sample_fmts[] = { AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_NONE }; - int ret, i; + static const enum AVPixelFormat pix_fmts[] = { + AV_PIX_FMT_RGB0, + AV_PIX_FMT_NONE + }; + int ret; + + if (s->response) { + AVFilterLink *videolink = ctx->outputs[1]; + formats = ff_make_format_list(pix_fmts); + if ((ret = ff_formats_ref(formats, &videolink->in_formats)) < 0) + return ret; + } layouts = ff_all_channel_counts(); - if ((ret = ff_channel_layouts_ref(layouts, &ctx->outputs[0]->in_channel_layouts)) < 0) - return ret; + if (!layouts) + return AVERROR(ENOMEM); - for (i = 0; i < 2; i++) { - layouts = ff_all_channel_counts(); - if ((ret = ff_channel_layouts_ref(layouts, &ctx->inputs[i]->out_channel_layouts)) < 0) + if (s->ir_format) { + ret = ff_set_common_channel_layouts(ctx, layouts); + if (ret < 0) + return ret; + } else { + AVFilterChannelLayouts *mono = NULL; + + ret = ff_add_channel_layout(&mono, AV_CH_LAYOUT_MONO); + if (ret) + return ret; + + if ((ret = ff_channel_layouts_ref(layouts, &ctx->inputs[0]->out_channel_layouts)) < 0) + return ret; + if ((ret = ff_channel_layouts_ref(layouts, &ctx->outputs[0]->in_channel_layouts)) < 0) + return ret; + if ((ret = ff_channel_layouts_ref(mono, &ctx->inputs[1]->out_channel_layouts)) < 0) return ret; } @@ -404,139 +675,175 @@ static int config_output(AVFilterLink *outlink) AVFilterContext *ctx = outlink->src; AudioFIRContext *s = ctx->priv; - if (ctx->inputs[0]->channels != ctx->inputs[1]->channels && - ctx->inputs[1]->channels != 1) { - av_log(ctx, AV_LOG_ERROR, - "Second input must have same number of channels as first input or " - "exactly 1 channel.\n"); - return AVERROR(EINVAL); - } - s->one2many = ctx->inputs[1]->channels == 1; outlink->sample_rate = ctx->inputs[0]->sample_rate; outlink->time_base = ctx->inputs[0]->time_base; outlink->channel_layout = ctx->inputs[0]->channel_layout; outlink->channels = ctx->inputs[0]->channels; - s->fifo[0] = av_audio_fifo_alloc(ctx->inputs[0]->format, ctx->inputs[0]->channels, 1024); - s->fifo[1] = av_audio_fifo_alloc(ctx->inputs[1]->format, ctx->inputs[1]->channels, 1024); - if (!s->fifo[0] || !s->fifo[1]) - return AVERROR(ENOMEM); - - s->sum = av_calloc(outlink->channels, sizeof(*s->sum)); - s->coeff = av_calloc(ctx->inputs[1]->channels, sizeof(*s->coeff)); - s->block = av_calloc(ctx->inputs[0]->channels, sizeof(*s->block)); - s->rdft = av_calloc(outlink->channels, sizeof(*s->rdft)); - s->irdft = av_calloc(outlink->channels, sizeof(*s->irdft)); - if (!s->sum || !s->coeff || !s->block || !s->rdft || !s->irdft) - return AVERROR(ENOMEM); - s->nb_channels = outlink->channels; s->nb_coef_channels = ctx->inputs[1]->channels; - s->want_skip = 1; - s->need_padding = 1; s->pts = AV_NOPTS_VALUE; return 0; } +static void uninit_segment(AVFilterContext *ctx, AudioFIRSegment *seg) +{ + AudioFIRContext *s = ctx->priv; + + if (seg->rdft) { + for (int ch = 0; ch < s->nb_channels; ch++) { + av_rdft_end(seg->rdft[ch]); + } + } + av_freep(&seg->rdft); + + if (seg->irdft) { + for (int ch = 0; ch < s->nb_channels; ch++) { + av_rdft_end(seg->irdft[ch]); + } + } + av_freep(&seg->irdft); + + av_freep(&seg->output_offset); + av_freep(&seg->part_index); + + av_frame_free(&seg->block); + av_frame_free(&seg->sum); + av_frame_free(&seg->buffer); + av_frame_free(&seg->coeff); + av_frame_free(&seg->input); + av_frame_free(&seg->output); + seg->input_size = 0; +} + static av_cold void uninit(AVFilterContext *ctx) { AudioFIRContext *s = ctx->priv; - int ch; - if (s->sum) { - for (ch = 0; ch < s->nb_channels; ch++) { - av_freep(&s->sum[ch]); - } + for (int i = 0; i < s->nb_segments; i++) { + uninit_segment(ctx, &s->seg[i]); } - av_freep(&s->sum); - - if (s->coeff) { - for (ch = 0; ch < s->nb_coef_channels; ch++) { - av_freep(&s->coeff[ch]); - } - } - av_freep(&s->coeff); - - if (s->block) { - for (ch = 0; ch < s->nb_channels; ch++) { - av_freep(&s->block[ch]); - } - } - av_freep(&s->block); - - if (s->rdft) { - for (ch = 0; ch < s->nb_channels; ch++) { - av_rdft_end(s->rdft[ch]); - } - } - av_freep(&s->rdft); - - if (s->irdft) { - for (ch = 0; ch < s->nb_channels; ch++) { - av_rdft_end(s->irdft[ch]); - } - } - av_freep(&s->irdft); - - av_frame_free(&s->in[0]); - av_frame_free(&s->in[1]); - av_frame_free(&s->buffer); - - av_audio_fifo_free(s->fifo[0]); - av_audio_fifo_free(s->fifo[1]); av_freep(&s->fdsp); + av_frame_free(&s->in[1]); + + for (int i = 0; i < ctx->nb_outputs; i++) + av_freep(&ctx->output_pads[i].name); + av_frame_free(&s->video); +} + +static int config_video(AVFilterLink *outlink) +{ + AVFilterContext *ctx = outlink->src; + AudioFIRContext *s = ctx->priv; + + outlink->sample_aspect_ratio = (AVRational){1,1}; + outlink->w = s->w; + outlink->h = s->h; + outlink->frame_rate = s->frame_rate; + outlink->time_base = av_inv_q(outlink->frame_rate); + + av_frame_free(&s->video); + s->video = ff_get_video_buffer(outlink, outlink->w, outlink->h); + if (!s->video) + return AVERROR(ENOMEM); + + return 0; +} + +void ff_afir_init(AudioFIRDSPContext *dsp) +{ + dsp->fcmul_add = fcmul_add_c; + + if (ARCH_X86) + ff_afir_init_x86(dsp); } static av_cold int init(AVFilterContext *ctx) { AudioFIRContext *s = ctx->priv; + AVFilterPad pad, vpad; + int ret; - s->fcmul_add = fcmul_add_c; + pad = (AVFilterPad){ + .name = av_strdup("default"), + .type = AVMEDIA_TYPE_AUDIO, + .config_props = config_output, + }; + + if (!pad.name) + return AVERROR(ENOMEM); + + if (s->response) { + vpad = (AVFilterPad){ + .name = av_strdup("filter_response"), + .type = AVMEDIA_TYPE_VIDEO, + .config_props = config_video, + }; + if (!vpad.name) + return AVERROR(ENOMEM); + } + + ret = ff_insert_outpad(ctx, 0, &pad); + if (ret < 0) { + av_freep(&pad.name); + return ret; + } + + if (s->response) { + ret = ff_insert_outpad(ctx, 1, &vpad); + if (ret < 0) { + av_freep(&vpad.name); + return ret; + } + } s->fdsp = avpriv_float_dsp_alloc(0); if (!s->fdsp) return AVERROR(ENOMEM); - if (ARCH_X86) - ff_afir_init_x86(s); + ff_afir_init(&s->afirdsp); return 0; } static const AVFilterPad afir_inputs[] = { { - .name = "main", - .type = AVMEDIA_TYPE_AUDIO, - .filter_frame = filter_frame, + .name = "main", + .type = AVMEDIA_TYPE_AUDIO, },{ - .name = "ir", - .type = AVMEDIA_TYPE_AUDIO, - .filter_frame = read_ir, - }, - { NULL } -}; - -static const AVFilterPad afir_outputs[] = { - { - .name = "default", - .type = AVMEDIA_TYPE_AUDIO, - .config_props = config_output, - .request_frame = request_frame, + .name = "ir", + .type = AVMEDIA_TYPE_AUDIO, }, { NULL } }; #define AF AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM +#define VF AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM #define OFFSET(x) offsetof(AudioFIRContext, x) static const AVOption afir_options[] = { - { "dry", "set dry gain", OFFSET(dry_gain), AV_OPT_TYPE_FLOAT, {.dbl=1}, 0, 1, AF }, - { "wet", "set wet gain", OFFSET(wet_gain), AV_OPT_TYPE_FLOAT, {.dbl=1}, 0, 1, AF }, - { "length", "set IR length", OFFSET(length), AV_OPT_TYPE_FLOAT, {.dbl=1}, 0, 1, AF }, - { "again", "enable auto gain", OFFSET(again), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1, AF }, + { "dry", "set dry gain", OFFSET(dry_gain), AV_OPT_TYPE_FLOAT, {.dbl=1}, 0, 10, AF }, + { "wet", "set wet gain", OFFSET(wet_gain), AV_OPT_TYPE_FLOAT, {.dbl=1}, 0, 10, AF }, + { "length", "set IR length", OFFSET(length), AV_OPT_TYPE_FLOAT, {.dbl=1}, 0, 1, AF }, + { "gtype", "set IR auto gain type",OFFSET(gtype), AV_OPT_TYPE_INT, {.i64=0}, -1, 2, AF, "gtype" }, + { "none", "without auto gain", 0, AV_OPT_TYPE_CONST, {.i64=-1}, 0, 0, AF, "gtype" }, + { "peak", "peak gain", 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, AF, "gtype" }, + { "dc", "DC gain", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, AF, "gtype" }, + { "gn", "gain to noise", 0, AV_OPT_TYPE_CONST, {.i64=2}, 0, 0, AF, "gtype" }, + { "irgain", "set IR gain", OFFSET(ir_gain), AV_OPT_TYPE_FLOAT, {.dbl=1}, 0, 1, AF }, + { "irfmt", "set IR format", OFFSET(ir_format), AV_OPT_TYPE_INT, {.i64=1}, 0, 1, AF, "irfmt" }, + { "mono", "single channel", 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, AF, "irfmt" }, + { "input", "same as input", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, AF, "irfmt" }, + { "maxir", "set max IR length", OFFSET(max_ir_len), AV_OPT_TYPE_FLOAT, {.dbl=30}, 0.1, 60, AF }, + { "response", "show IR frequency response", OFFSET(response), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, VF }, + { "channel", "set IR channel to display frequency response", OFFSET(ir_channel), AV_OPT_TYPE_INT, {.i64=0}, 0, 1024, VF }, + { "size", "set video size", OFFSET(w), AV_OPT_TYPE_IMAGE_SIZE, {.str = "hd720"}, 0, 0, VF }, + { "rate", "set video rate", OFFSET(frame_rate), AV_OPT_TYPE_VIDEO_RATE, {.str = "25"}, 0, INT32_MAX, VF }, + { "minp", "set min partition size", OFFSET(minp), AV_OPT_TYPE_INT, {.i64=8192}, 8, 32768, AF }, + { "maxp", "set max partition size", OFFSET(maxp), AV_OPT_TYPE_INT, {.i64=8192}, 8, 32768, AF }, { NULL } }; @@ -549,8 +856,9 @@ AVFilter ff_af_afir = { .priv_class = &afir_class, .query_formats = query_formats, .init = init, + .activate = activate, .uninit = uninit, .inputs = afir_inputs, - .outputs = afir_outputs, - .flags = AVFILTER_FLAG_SLICE_THREADS, + .flags = AVFILTER_FLAG_DYNAMIC_OUTPUTS | + AVFILTER_FLAG_SLICE_THREADS, }; diff --git a/libavfilter/af_afir.h b/libavfilter/af_afir.h index aaeb66536..f665c0ef8 100644 --- a/libavfilter/af_afir.h +++ b/libavfilter/af_afir.h @@ -21,7 +21,6 @@ #ifndef AVFILTER_AFIR_H #define AVFILTER_AFIR_H -#include "libavutil/audio_fifo.h" #include "libavutil/common.h" #include "libavutil/float_dsp.h" #include "libavutil/opt.h" @@ -32,7 +31,32 @@ #include "formats.h" #include "internal.h" -#define MAX_IR_DURATION 30 +typedef struct AudioFIRSegment { + int nb_partitions; + int part_size; + int block_size; + int fft_length; + int coeff_size; + int input_size; + int input_offset; + + int *output_offset; + int *part_index; + + AVFrame *sum; + AVFrame *block; + AVFrame *buffer; + AVFrame *coeff; + AVFrame *input; + AVFrame *output; + + RDFTContext **rdft, **irdft; +} AudioFIRSegment; + +typedef struct AudioFIRDSPContext { + void (*fcmul_add)(float *sum, const float *t, const float *c, + ptrdiff_t len); +} AudioFIRDSPContext; typedef struct AudioFIRContext { const AVClass *class; @@ -40,44 +64,40 @@ typedef struct AudioFIRContext { float wet_gain; float dry_gain; float length; - int again; + int gtype; + float ir_gain; + int ir_format; + float max_ir_len; + int response; + int w, h; + AVRational frame_rate; + int ir_channel; + int minp; + int maxp; float gain; int eof_coeffs; int have_coeffs; - int nb_coeffs; int nb_taps; - int part_size; - int part_index; - int coeff_size; - int block_size; - int nb_partitions; int nb_channels; - int ir_length; - int fft_length; int nb_coef_channels; int one2many; - int nb_samples; - int want_skip; - int need_padding; - RDFTContext **rdft, **irdft; - float **sum; - float **block; - FFTComplex **coeff; + AudioFIRSegment seg[1024]; + int nb_segments; - AVAudioFifo *fifo[2]; AVFrame *in[2]; - AVFrame *buffer; + AVFrame *video; + int min_part_size; int64_t pts; - int index; + AudioFIRDSPContext afirdsp; AVFloatDSPContext *fdsp; - void (*fcmul_add)(float *sum, const float *t, const float *c, - ptrdiff_t len); + } AudioFIRContext; -void ff_afir_init_x86(AudioFIRContext *s); +void ff_afir_init(AudioFIRDSPContext *s); +void ff_afir_init_x86(AudioFIRDSPContext *s); #endif /* AVFILTER_AFIR_H */ diff --git a/libavfilter/af_agate.c b/libavfilter/af_agate.c index ba96863a6..0609dc222 100644 --- a/libavfilter/af_agate.c +++ b/libavfilter/af_agate.c @@ -47,11 +47,13 @@ typedef struct AudioGateContext { double range; int link; int detection; + int mode; double thres; double knee_start; - double lin_knee_stop; double knee_stop; + double lin_knee_start; + double lin_knee_stop; double lin_slope; double attack_coeff; double release_coeff; @@ -65,6 +67,9 @@ typedef struct AudioGateContext { static const AVOption options[] = { { "level_in", "set input level", OFFSET(level_in), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0.015625, 64, A }, + { "mode", "set mode", OFFSET(mode), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, A, "mode" }, + { "downward",0, 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, A, "mode" }, + { "upward", 0, 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, A, "mode" }, { "range", "set max gain reduction", OFFSET(range), AV_OPT_TYPE_DOUBLE, {.dbl=0.06125}, 0, 1, A }, { "threshold", "set threshold", OFFSET(threshold), AV_OPT_TYPE_DOUBLE, {.dbl=0.125}, 0, 1, A }, { "ratio", "set ratio", OFFSET(ratio), AV_OPT_TYPE_DOUBLE, {.dbl=2}, 1, 9000, A }, @@ -88,7 +93,6 @@ static int agate_config_input(AVFilterLink *inlink) AudioGateContext *s = ctx->priv; double lin_threshold = s->threshold; double lin_knee_sqrt = sqrt(s->knee); - double lin_knee_start; if (s->detection) lin_threshold *= lin_threshold; @@ -96,9 +100,9 @@ static int agate_config_input(AVFilterLink *inlink) s->attack_coeff = FFMIN(1., 1. / (s->attack * inlink->sample_rate / 4000.)); s->release_coeff = FFMIN(1., 1. / (s->release * inlink->sample_rate / 4000.)); s->lin_knee_stop = lin_threshold * lin_knee_sqrt; - lin_knee_start = lin_threshold / lin_knee_sqrt; + s->lin_knee_start = lin_threshold / lin_knee_sqrt; s->thres = log(lin_threshold); - s->knee_start = log(lin_knee_start); + s->knee_start = log(s->lin_knee_start); s->knee_stop = log(s->lin_knee_stop); return 0; @@ -112,26 +116,26 @@ static int agate_config_input(AVFilterLink *inlink) static double output_gain(double lin_slope, double ratio, double thres, double knee, double knee_start, double knee_stop, - double lin_knee_stop, double range) + double range, int mode) { - if (lin_slope < lin_knee_stop) { - double slope = log(lin_slope); - double tratio = ratio; - double gain = 0.; - double delta = 0.; + double slope = log(lin_slope); + double tratio = ratio; + double gain = 0.; + double delta = 0.; - if (IS_FAKE_INFINITY(ratio)) - tratio = 1000.; - gain = (slope - thres) * tratio + thres; - delta = tratio; + if (IS_FAKE_INFINITY(ratio)) + tratio = 1000.; + gain = (slope - thres) * tratio + thres; + delta = tratio; - if (knee > 1. && slope > knee_start) { + if (mode) { + if (knee > 1. && slope < knee_stop) + gain = hermite_interpolation(slope, knee_stop, knee_start, ((knee_stop - thres) * tratio + thres), knee_start, delta, 1.); + } else { + if (knee > 1. && slope > knee_start) gain = hermite_interpolation(slope, knee_start, knee_stop, ((knee_start - thres) * tratio + thres), knee_stop, delta, 1.); - } - return FFMAX(range, exp(gain - slope)); } - - return 1.; + return FFMAX(range, exp(gain - slope)); } static void gate(AudioGateContext *s, @@ -146,6 +150,7 @@ static void gate(AudioGateContext *s, for (n = 0; n < nb_samples; n++, src += inlink->channels, dst += inlink->channels, scsrc += sclink->channels) { double abs_sample = fabs(scsrc[0] * level_sc), gain = 1.0; + int detected; if (s->link == 1) { for (c = 1; c < sclink->channels; c++) @@ -161,10 +166,16 @@ static void gate(AudioGateContext *s, abs_sample *= abs_sample; s->lin_slope += (abs_sample - s->lin_slope) * (abs_sample > s->lin_slope ? attack_coeff : release_coeff); - if (s->lin_slope > 0.0) + + if (s->mode) + detected = s->lin_slope > s->lin_knee_start; + else + detected = s->lin_slope < s->lin_knee_stop; + + if (s->lin_slope > 0.0 && detected) gain = output_gain(s->lin_slope, s->ratio, s->thres, s->knee, s->knee_start, s->knee_stop, - s->lin_knee_stop, s->range); + s->range, s->mode); for (c = 0; c < inlink->channels; c++) dst[c] = src[c] * level_in * gain * makeup; diff --git a/libavfilter/af_aiir.c b/libavfilter/af_aiir.c index 1f2a568c1..ffe2606da 100644 --- a/libavfilter/af_aiir.c +++ b/libavfilter/af_aiir.c @@ -22,7 +22,9 @@ #include "libavutil/avassert.h" #include "libavutil/avstring.h" +#include "libavutil/intreadwrite.h" #include "libavutil/opt.h" +#include "libavutil/xga_font_data.h" #include "audio.h" #include "avfilter.h" #include "internal.h" @@ -55,9 +57,16 @@ typedef struct AudioIIRContext { const AVClass *class; char *a_str, *b_str, *g_str; double dry_gain, wet_gain; + double mix; int format; int process; int precision; + int response; + int w, h; + int ir_channel; + AVRational rate; + + AVFrame *video; IIRChannel *iir; int channels; @@ -75,8 +84,20 @@ static int query_formats(AVFilterContext *ctx) AV_SAMPLE_FMT_DBLP, AV_SAMPLE_FMT_NONE }; + static const enum AVPixelFormat pix_fmts[] = { + AV_PIX_FMT_RGB0, + AV_PIX_FMT_NONE + }; int ret; + if (s->response) { + AVFilterLink *videolink = ctx->outputs[1]; + + formats = ff_make_format_list(pix_fmts); + if ((ret = ff_formats_ref(formats, &videolink->in_formats)) < 0) + return ret; + } + layouts = ff_all_channel_counts(); if (!layouts) return AVERROR(ENOMEM); @@ -104,6 +125,7 @@ static int iir_ch_## name(AVFilterContext *ctx, void *arg, int ch, int nb_jobs) AudioIIRContext *s = ctx->priv; \ const double ig = s->dry_gain; \ const double og = s->wet_gain; \ + const double mix = s->mix; \ ThreadData *td = arg; \ AVFrame *in = td->in, *out = td->out; \ const type *src = (const type *)in->extended_data[ch]; \ @@ -113,6 +135,7 @@ static int iir_ch_## name(AVFilterContext *ctx, void *arg, int ch, int nb_jobs) const int nb_b = s->iir[ch].nb_ab[1]; \ const double *a = s->iir[ch].ab[0]; \ const double *b = s->iir[ch].ab[1]; \ + const double g = s->iir[ch].g; \ int *clippings = &s->iir[ch].clippings; \ type *dst = (type *)out->extended_data[ch]; \ int n; \ @@ -131,7 +154,8 @@ static int iir_ch_## name(AVFilterContext *ctx, void *arg, int ch, int nb_jobs) sample -= a[x] * oc[x]; \ \ oc[0] = sample; \ - sample *= og; \ + sample *= og * g; \ + sample = sample * mix + ic[0] * (1. - mix); \ if (need_clipping && sample < min) { \ (*clippings)++; \ dst[n] = min; \ @@ -157,11 +181,13 @@ static int iir_ch_serial_## name(AVFilterContext *ctx, void *arg, int ch, int nb AudioIIRContext *s = ctx->priv; \ const double ig = s->dry_gain; \ const double og = s->wet_gain; \ + const double mix = s->mix; \ ThreadData *td = arg; \ AVFrame *in = td->in, *out = td->out; \ const type *src = (const type *)in->extended_data[ch]; \ type *dst = (type *)out->extended_data[ch]; \ IIRChannel *iir = &s->iir[ch]; \ + const double g = iir->g; \ int *clippings = &iir->clippings; \ int nb_biquads = (FFMAX(iir->nb_ab[0], iir->nb_ab[1]) + 1) / 2; \ int n, i; \ @@ -185,8 +211,9 @@ static int iir_ch_serial_## name(AVFilterContext *ctx, void *arg, int ch, int nb i1 = src[n]; \ o2 = o1; \ o1 = o0; \ - o0 *= og; \ + o0 *= og * g; \ \ + o0 = o0 * mix + (1. - mix) * sample; \ if (need_clipping && o0 < min) { \ (*clippings)++; \ dst[n] = min; \ @@ -394,7 +421,7 @@ static int expand(AVFilterContext *ctx, double *pz, int nb, double *coeffs) for (i = 0; i < nb + 1; i++) { if (fabs(coeffs[2 * i + 1]) > FLT_EPSILON) { - av_log(ctx, AV_LOG_ERROR, "coeff: %lf of z^%d is not real; poles/zeros are not complex conjugates.\n", + av_log(ctx, AV_LOG_ERROR, "coeff: %f of z^%d is not real; poles/zeros are not complex conjugates.\n", coeffs[2 * i + 1], i); return AVERROR(EINVAL); } @@ -573,7 +600,7 @@ static int decompose_zp2biquads(AVFilterContext *ctx, int channels) iir->biquads[current_biquad].b1 = b[2] / a[4] * (current_biquad ? 1.0 : iir->g); iir->biquads[current_biquad].b2 = b[0] / a[4] * (current_biquad ? 1.0 : iir->g); - av_log(ctx, AV_LOG_VERBOSE, "a=%lf %lf %lf:b=%lf %lf %lf\n", + av_log(ctx, AV_LOG_VERBOSE, "a=%f %f %f:b=%f %f %f\n", iir->biquads[current_biquad].a0, iir->biquads[current_biquad].a1, iir->biquads[current_biquad].a2, @@ -642,6 +669,193 @@ static void convert_pd2zp(AVFilterContext *ctx, int channels) } } +static void drawtext(AVFrame *pic, int x, int y, const char *txt, uint32_t color) +{ + const uint8_t *font; + int font_height; + int i; + + font = avpriv_cga_font, font_height = 8; + + for (i = 0; txt[i]; i++) { + int char_y, mask; + + uint8_t *p = pic->data[0] + y * pic->linesize[0] + (x + i * 8) * 4; + for (char_y = 0; char_y < font_height; char_y++) { + for (mask = 0x80; mask; mask >>= 1) { + if (font[txt[i] * font_height + char_y] & mask) + AV_WL32(p, color); + p += 4; + } + p += pic->linesize[0] - 8 * 4; + } + } +} + +static void draw_line(AVFrame *out, int x0, int y0, int x1, int y1, uint32_t color) +{ + int dx = FFABS(x1-x0); + int dy = FFABS(y1-y0), sy = y0 < y1 ? 1 : -1; + int err = (dx>dy ? dx : -dy) / 2, e2; + + for (;;) { + AV_WL32(out->data[0] + y0 * out->linesize[0] + x0 * 4, color); + + if (x0 == x1 && y0 == y1) + break; + + e2 = err; + + if (e2 >-dx) { + err -= dy; + x0--; + } + + if (e2 < dy) { + err += dx; + y0 += sy; + } + } +} + +static void draw_response(AVFilterContext *ctx, AVFrame *out) +{ + AudioIIRContext *s = ctx->priv; + float *mag, *phase, *delay, min = FLT_MAX, max = FLT_MIN; + float min_delay = FLT_MAX, max_delay = FLT_MIN; + int prev_ymag = -1, prev_yphase = -1, prev_ydelay = -1; + char text[32]; + int ch, i, x; + + memset(out->data[0], 0, s->h * out->linesize[0]); + + phase = av_malloc_array(s->w, sizeof(*phase)); + mag = av_malloc_array(s->w, sizeof(*mag)); + delay = av_malloc_array(s->w, sizeof(*delay)); + if (!mag || !phase || !delay) + goto end; + + ch = av_clip(s->ir_channel, 0, s->channels - 1); + for (i = 0; i < s->w; i++) { + const double *b = s->iir[ch].ab[0]; + const double *a = s->iir[ch].ab[1]; + double w = i * M_PI / (s->w - 1); + double realz, realp; + double imagz, imagp; + double real, imag, div; + + if (s->format == 0) { + realz = 0., realp = 0.; + imagz = 0., imagp = 0.; + for (x = 0; x < s->iir[ch].nb_ab[1]; x++) { + realz += cos(-x * w) * a[x]; + imagz += sin(-x * w) * a[x]; + } + + for (x = 0; x < s->iir[ch].nb_ab[0]; x++) { + realp += cos(-x * w) * b[x]; + imagp += sin(-x * w) * b[x]; + } + + div = realp * realp + imagp * imagp; + real = (realz * realp + imagz * imagp) / div; + imag = (imagz * realp - imagp * realz) / div; + } else { + real = 1; + imag = 0; + for (x = 0; x < s->iir[ch].nb_ab[1]; x++) { + double ore, oim, re, im; + + re = cos(w) - a[2 * x]; + im = sin(w) - a[2 * x + 1]; + + ore = real; + oim = imag; + + real = ore * re - oim * im; + imag = ore * im + oim * re; + } + + for (x = 0; x < s->iir[ch].nb_ab[0]; x++) { + double ore, oim, re, im; + + re = cos(w) - b[2 * x]; + im = sin(w) - b[2 * x + 1]; + + ore = real; + oim = imag; + div = re * re + im * im; + + real = (ore * re + oim * im) / div; + imag = (oim * re - ore * im) / div; + } + } + + mag[i] = s->iir[ch].g * hypot(real, imag); + phase[i] = atan2(imag, real); + min = fminf(min, mag[i]); + max = fmaxf(max, mag[i]); + } + + for (i = 0; i < s->w - 1; i++) { + float dw = M_PI / (s->w - 1); + + delay[i] = -(phase[i + 1] - phase[i]) / dw; + min_delay = fminf(min_delay, delay[i]); + max_delay = fmaxf(max_delay, delay[i]); + } + + delay[i] = delay[i - 1]; + + for (i = 0; i < s->w; i++) { + int ymag = mag[i] / max * (s->h - 1); + int ydelay = (delay[i] - min_delay) / (max_delay - min_delay) * (s->h - 1); + int yphase = (0.5 * (1. + phase[i] / M_PI)) * (s->h - 1); + + ymag = s->h - 1 - av_clip(ymag, 0, s->h - 1); + yphase = s->h - 1 - av_clip(yphase, 0, s->h - 1); + ydelay = s->h - 1 - av_clip(ydelay, 0, s->h - 1); + + if (prev_ymag < 0) + prev_ymag = ymag; + if (prev_yphase < 0) + prev_yphase = yphase; + if (prev_ydelay < 0) + prev_ydelay = ydelay; + + draw_line(out, i, ymag, FFMAX(i - 1, 0), prev_ymag, 0xFFFF00FF); + draw_line(out, i, yphase, FFMAX(i - 1, 0), prev_yphase, 0xFF00FF00); + draw_line(out, i, ydelay, FFMAX(i - 1, 0), prev_ydelay, 0xFF00FFFF); + + prev_ymag = ymag; + prev_yphase = yphase; + prev_ydelay = ydelay; + } + + if (s->w > 400 && s->h > 100) { + drawtext(out, 2, 2, "Max Magnitude:", 0xDDDDDDDD); + snprintf(text, sizeof(text), "%.2f", max); + drawtext(out, 15 * 8 + 2, 2, text, 0xDDDDDDDD); + + drawtext(out, 2, 12, "Min Magnitude:", 0xDDDDDDDD); + snprintf(text, sizeof(text), "%.2f", min); + drawtext(out, 15 * 8 + 2, 12, text, 0xDDDDDDDD); + + drawtext(out, 2, 22, "Max Delay:", 0xDDDDDDDD); + snprintf(text, sizeof(text), "%.2f", max_delay); + drawtext(out, 11 * 8 + 2, 22, text, 0xDDDDDDDD); + + drawtext(out, 2, 32, "Min Delay:", 0xDDDDDDDD); + snprintf(text, sizeof(text), "%.2f", min_delay); + drawtext(out, 11 * 8 + 2, 32, text, 0xDDDDDDDD); + } + +end: + av_free(delay); + av_free(phase); + av_free(mag); +} + static int config_output(AVFilterLink *outlink) { AVFilterContext *ctx = outlink->src; @@ -672,6 +886,15 @@ static int config_output(AVFilterLink *outlink) convert_pd2zp(ctx, inlink->channels); } + av_frame_free(&s->video); + if (s->response) { + s->video = ff_get_video_buffer(ctx->outputs[1], s->w, s->h); + if (!s->video) + return AVERROR(ENOMEM); + + draw_response(ctx, s->video); + } + if (s->format == 0) av_log(ctx, AV_LOG_WARNING, "tf coefficients format is not recommended for too high number of zeros/poles.\n"); @@ -693,7 +916,7 @@ static int config_output(AVFilterLink *outlink) return ret; } - for (ch = 0; ch < inlink->channels; ch++) { + for (ch = 0; s->format == 0 && ch < inlink->channels; ch++) { IIRChannel *iir = &s->iir[ch]; for (i = 1; i < iir->nb_ab[0]; i++) { @@ -722,7 +945,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) AVFilterLink *outlink = ctx->outputs[0]; ThreadData td; AVFrame *out; - int ch; + int ch, ret; if (av_frame_is_writable(in)) { out = in; @@ -749,12 +972,41 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) if (in != out) av_frame_free(&in); + if (s->response) { + AVFilterLink *outlink = ctx->outputs[1]; + int64_t old_pts = s->video->pts; + int64_t new_pts = av_rescale_q(out->pts, ctx->inputs[0]->time_base, outlink->time_base); + + if (new_pts > old_pts) { + s->video->pts = new_pts; + ret = ff_filter_frame(outlink, av_frame_clone(s->video)); + if (ret < 0) + return ret; + } + } + return ff_filter_frame(outlink, out); } +static int config_video(AVFilterLink *outlink) +{ + AVFilterContext *ctx = outlink->src; + AudioIIRContext *s = ctx->priv; + + outlink->sample_aspect_ratio = (AVRational){1,1}; + outlink->w = s->w; + outlink->h = s->h; + outlink->frame_rate = s->rate; + outlink->time_base = av_inv_q(outlink->frame_rate); + + return 0; +} + static av_cold int init(AVFilterContext *ctx) { AudioIIRContext *s = ctx->priv; + AVFilterPad pad, vpad; + int ret; if (!s->a_str || !s->b_str || !s->g_str) { av_log(ctx, AV_LOG_ERROR, "Valid coefficients are mandatory.\n"); @@ -769,6 +1021,35 @@ static av_cold int init(AVFilterContext *ctx) default: return AVERROR_BUG; } + pad = (AVFilterPad){ + .name = av_strdup("default"), + .type = AVMEDIA_TYPE_AUDIO, + .config_props = config_output, + }; + + if (!pad.name) + return AVERROR(ENOMEM); + + if (s->response) { + vpad = (AVFilterPad){ + .name = av_strdup("filter_response"), + .type = AVMEDIA_TYPE_VIDEO, + .config_props = config_video, + }; + if (!vpad.name) + return AVERROR(ENOMEM); + } + + ret = ff_insert_outpad(ctx, 0, &pad); + if (ret < 0) + return ret; + + if (s->response) { + ret = ff_insert_outpad(ctx, 1, &vpad); + if (ret < 0) + return ret; + } + return 0; } @@ -788,6 +1069,11 @@ static av_cold void uninit(AVFilterContext *ctx) } } av_freep(&s->iir); + + av_freep(&ctx->output_pads[0].name); + if (s->response) + av_freep(&ctx->output_pads[1].name); + av_frame_free(&s->video); } static const AVFilterPad inputs[] = { @@ -799,17 +1085,9 @@ static const AVFilterPad inputs[] = { { NULL } }; -static const AVFilterPad outputs[] = { - { - .name = "default", - .type = AVMEDIA_TYPE_AUDIO, - .config_props = config_output, - }, - { NULL } -}; - #define OFFSET(x) offsetof(AudioIIRContext, x) #define AF AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM +#define VF AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM static const AVOption aiir_options[] = { { "z", "set B/numerator/zeros coefficients", OFFSET(b_str), AV_OPT_TYPE_STRING, {.str="1+0i 1-0i"}, 0, 0, AF }, @@ -830,6 +1108,11 @@ static const AVOption aiir_options[] = { { "flt", "single-precision floating-point", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, AF, "precision" }, { "i32", "32-bit integers", 0, AV_OPT_TYPE_CONST, {.i64=2}, 0, 0, AF, "precision" }, { "i16", "16-bit integers", 0, AV_OPT_TYPE_CONST, {.i64=3}, 0, 0, AF, "precision" }, + { "mix", "set mix", OFFSET(mix), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 1, AF }, + { "response", "show IR frequency response", OFFSET(response), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, VF }, + { "channel", "set IR channel to display frequency response", OFFSET(ir_channel), AV_OPT_TYPE_INT, {.i64=0}, 0, 1024, VF }, + { "size", "set video size", OFFSET(w), AV_OPT_TYPE_IMAGE_SIZE, {.str = "hd720"}, 0, 0, VF }, + { "rate", "set video rate", OFFSET(rate), AV_OPT_TYPE_VIDEO_RATE, {.str = "25"}, 0, INT32_MAX, VF }, { NULL }, }; @@ -844,6 +1127,6 @@ AVFilter ff_af_aiir = { .uninit = uninit, .query_formats = query_formats, .inputs = inputs, - .outputs = outputs, - .flags = AVFILTER_FLAG_SLICE_THREADS, + .flags = AVFILTER_FLAG_DYNAMIC_OUTPUTS | + AVFILTER_FLAG_SLICE_THREADS, }; diff --git a/libavfilter/af_amerge.c b/libavfilter/af_amerge.c index 09c660ef4..567f25982 100644 --- a/libavfilter/af_amerge.c +++ b/libavfilter/af_amerge.c @@ -23,16 +23,13 @@ * Audio merging filter */ -#define FF_INTERNAL_FIELDS 1 -#include "framequeue.h" - #include "libavutil/avstring.h" #include "libavutil/bprint.h" #include "libavutil/channel_layout.h" #include "libavutil/opt.h" #include "avfilter.h" +#include "filters.h" #include "audio.h" -#include "bufferqueue.h" #include "internal.h" #define SWR_CH_MAX 64 @@ -43,10 +40,7 @@ typedef struct AMergeContext { int route[SWR_CH_MAX]; /**< channels routing, see copy_samples */ int bps; struct amerge_input { - struct FFBufQueue queue; int nb_ch; /**< number of channels for the input */ - int nb_samples; - int pos; } *in; } AMergeContext; @@ -67,8 +61,6 @@ static av_cold void uninit(AVFilterContext *ctx) int i; for (i = 0; i < s->nb_inputs; i++) { - if (s->in) - ff_bufqueue_discard_all(&s->in[i].queue); if (ctx->input_pads) av_freep(&ctx->input_pads[i].name); } @@ -171,7 +163,7 @@ static int config_output(AVFilterLink *outlink) outlink->sample_rate = ctx->inputs[0]->sample_rate; outlink->time_base = ctx->inputs[0]->time_base; - av_bprint_init(&bp, 0, 1); + av_bprint_init(&bp, 0, AV_BPRINT_SIZE_AUTOMATIC); for (i = 0; i < s->nb_inputs; i++) { av_bprintf(&bp, "%sin%d:", i ? " + " : "", i); av_bprint_channel_layout(&bp, -1, ctx->inputs[i]->channel_layout); @@ -183,21 +175,6 @@ static int config_output(AVFilterLink *outlink) return 0; } -static int request_frame(AVFilterLink *outlink) -{ - AVFilterContext *ctx = outlink->src; - AMergeContext *s = ctx->priv; - int i, ret; - - for (i = 0; i < s->nb_inputs; i++) - if (!s->in[i].nb_samples || - /* detect EOF immediately */ - (ctx->inputs[i]->status_in && !ctx->inputs[i]->status_out)) - if ((ret = ff_request_frame(ctx->inputs[i])) < 0) - return ret; - return 0; -} - /** * Copy samples from several input streams to one output stream. * @param nb_inputs number of inputs @@ -235,88 +212,101 @@ static inline void copy_samples(int nb_inputs, struct amerge_input in[], } } -static int filter_frame(AVFilterLink *inlink, AVFrame *insamples) +static void free_frames(int nb_inputs, AVFrame **input_frames) { - AVFilterContext *ctx = inlink->dst; - AMergeContext *s = ctx->priv; - AVFilterLink *const outlink = ctx->outputs[0]; - int input_number; - int nb_samples, ns, i; - AVFrame *outbuf, *inbuf[SWR_CH_MAX]; - uint8_t *ins[SWR_CH_MAX], *outs; + int i; + for (i = 0; i < nb_inputs; i++) + av_frame_free(&input_frames[i]); +} - for (input_number = 0; input_number < s->nb_inputs; input_number++) - if (inlink == ctx->inputs[input_number]) - break; - av_assert1(input_number < s->nb_inputs); - if (ff_bufqueue_is_full(&s->in[input_number].queue)) { - av_frame_free(&insamples); - return AVERROR(ENOMEM); +static int try_push_frame(AVFilterContext *ctx, int nb_samples) +{ + AMergeContext *s = ctx->priv; + AVFilterLink *outlink = ctx->outputs[0]; + int i, ret; + AVFrame *outbuf, *inbuf[SWR_CH_MAX] = { NULL }; + uint8_t *outs, *ins[SWR_CH_MAX]; + + for (i = 0; i < ctx->nb_inputs; i++) { + ret = ff_inlink_consume_samples(ctx->inputs[i], nb_samples, nb_samples, &inbuf[i]); + if (ret < 0) { + free_frames(i, inbuf); + return ret; + } + ins[i] = inbuf[i]->data[0]; } - ff_bufqueue_add(ctx, &s->in[input_number].queue, av_frame_clone(insamples)); - s->in[input_number].nb_samples += insamples->nb_samples; - av_frame_free(&insamples); - nb_samples = s->in[0].nb_samples; - for (i = 1; i < s->nb_inputs; i++) - nb_samples = FFMIN(nb_samples, s->in[i].nb_samples); - if (!nb_samples) - return 0; outbuf = ff_get_audio_buffer(ctx->outputs[0], nb_samples); - if (!outbuf) + if (!outbuf) { + free_frames(s->nb_inputs, inbuf); return AVERROR(ENOMEM); - outs = outbuf->data[0]; - for (i = 0; i < s->nb_inputs; i++) { - inbuf[i] = ff_bufqueue_peek(&s->in[i].queue, 0); - ins[i] = inbuf[i]->data[0] + - s->in[i].pos * s->in[i].nb_ch * s->bps; } - av_frame_copy_props(outbuf, inbuf[0]); - outbuf->pts = inbuf[0]->pts == AV_NOPTS_VALUE ? AV_NOPTS_VALUE : - inbuf[0]->pts + - av_rescale_q(s->in[0].pos, - av_make_q(1, ctx->inputs[0]->sample_rate), - ctx->outputs[0]->time_base); + + outs = outbuf->data[0]; + outbuf->pts = inbuf[0]->pts; outbuf->nb_samples = nb_samples; outbuf->channel_layout = outlink->channel_layout; outbuf->channels = outlink->channels; while (nb_samples) { - ns = nb_samples; - for (i = 0; i < s->nb_inputs; i++) - ns = FFMIN(ns, inbuf[i]->nb_samples - s->in[i].pos); /* Unroll the most common sample formats: speed +~350% for the loop, +~13% overall (including two common decoders) */ switch (s->bps) { case 1: - copy_samples(s->nb_inputs, s->in, s->route, ins, &outs, ns, 1); + copy_samples(s->nb_inputs, s->in, s->route, ins, &outs, nb_samples, 1); break; case 2: - copy_samples(s->nb_inputs, s->in, s->route, ins, &outs, ns, 2); + copy_samples(s->nb_inputs, s->in, s->route, ins, &outs, nb_samples, 2); break; case 4: - copy_samples(s->nb_inputs, s->in, s->route, ins, &outs, ns, 4); + copy_samples(s->nb_inputs, s->in, s->route, ins, &outs, nb_samples, 4); break; default: - copy_samples(s->nb_inputs, s->in, s->route, ins, &outs, ns, s->bps); + copy_samples(s->nb_inputs, s->in, s->route, ins, &outs, nb_samples, s->bps); break; } - nb_samples -= ns; - for (i = 0; i < s->nb_inputs; i++) { - s->in[i].nb_samples -= ns; - s->in[i].pos += ns; - if (s->in[i].pos == inbuf[i]->nb_samples) { - s->in[i].pos = 0; - av_frame_free(&inbuf[i]); - ff_bufqueue_get(&s->in[i].queue); - inbuf[i] = ff_bufqueue_peek(&s->in[i].queue, 0); - ins[i] = inbuf[i] ? inbuf[i]->data[0] : NULL; - } + nb_samples = 0; + } + + free_frames(s->nb_inputs, inbuf); + return ff_filter_frame(ctx->outputs[0], outbuf); +} + +static int activate(AVFilterContext *ctx) +{ + int i, status; + int ret, nb_samples; + int64_t pts; + + FF_FILTER_FORWARD_STATUS_BACK_ALL(ctx->outputs[0], ctx); + + nb_samples = ff_inlink_queued_samples(ctx->inputs[0]); + for (i = 1; i < ctx->nb_inputs && nb_samples > 0; i++) { + nb_samples = FFMIN(ff_inlink_queued_samples(ctx->inputs[i]), nb_samples); + } + + if (nb_samples) { + ret = try_push_frame(ctx, nb_samples); + if (ret < 0) + return ret; + } + + for (i = 0; i < ctx->nb_inputs; i++) { + if (ff_inlink_queued_samples(ctx->inputs[i])) + continue; + + if (ff_inlink_acknowledge_status(ctx->inputs[i], &status, &pts)) { + ff_outlink_set_status(ctx->outputs[0], status, pts); + return 0; + } else if (ff_outlink_frame_wanted(ctx->outputs[0])) { + ff_inlink_request_frame(ctx->inputs[i]); + return 0; } } - return ff_filter_frame(ctx->outputs[0], outbuf); + + return 0; } static av_cold int init(AVFilterContext *ctx) @@ -332,7 +322,6 @@ static av_cold int init(AVFilterContext *ctx) AVFilterPad pad = { .name = name, .type = AVMEDIA_TYPE_AUDIO, - .filter_frame = filter_frame, }; if (!name) return AVERROR(ENOMEM); @@ -349,7 +338,6 @@ static const AVFilterPad amerge_outputs[] = { .name = "default", .type = AVMEDIA_TYPE_AUDIO, .config_props = config_output, - .request_frame = request_frame, }, { NULL } }; @@ -362,6 +350,7 @@ AVFilter ff_af_amerge = { .init = init, .uninit = uninit, .query_formats = query_formats, + .activate = activate, .inputs = NULL, .outputs = amerge_outputs, .priv_class = &amerge_class, diff --git a/libavfilter/af_amix.c b/libavfilter/af_amix.c index 46f1bf63d..ec2556f92 100644 --- a/libavfilter/af_amix.c +++ b/libavfilter/af_amix.c @@ -425,6 +425,8 @@ static int activate(AVFilterContext *ctx) AVFrame *buf = NULL; int i, ret; + FF_FILTER_FORWARD_STATUS_BACK_ALL(outlink, ctx); + for (i = 0; i < s->nb_inputs; i++) { AVFilterLink *inlink = ctx->inputs[i]; diff --git a/libavfilter/af_amultiply.c b/libavfilter/af_amultiply.c new file mode 100644 index 000000000..cc032846f --- /dev/null +++ b/libavfilter/af_amultiply.c @@ -0,0 +1,218 @@ +/* + * Copyright (c) 2018 Paul B Mahol + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/avassert.h" +#include "libavutil/channel_layout.h" +#include "libavutil/common.h" +#include "libavutil/float_dsp.h" +#include "libavutil/opt.h" + +#include "audio.h" +#include "avfilter.h" +#include "formats.h" +#include "filters.h" +#include "internal.h" + +typedef struct AudioMultiplyContext { + const AVClass *class; + + AVFrame *frames[2]; + int planes; + int channels; + int samples_align; + + AVFloatDSPContext *fdsp; +} AudioMultiplyContext; + +static int query_formats(AVFilterContext *ctx) +{ + AVFilterFormats *formats; + AVFilterChannelLayouts *layouts; + static const enum AVSampleFormat sample_fmts[] = { + AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_FLTP, + AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_DBLP, + AV_SAMPLE_FMT_NONE + }; + int ret; + + layouts = ff_all_channel_counts(); + if (!layouts) + return AVERROR(ENOMEM); + ret = ff_set_common_channel_layouts(ctx, layouts); + if (ret < 0) + return ret; + + formats = ff_make_format_list(sample_fmts); + if (!formats) + return AVERROR(ENOMEM); + ret = ff_set_common_formats(ctx, formats); + if (ret < 0) + return ret; + + formats = ff_all_samplerates(); + if (!formats) + return AVERROR(ENOMEM); + return ff_set_common_samplerates(ctx, formats); +} + +static int activate(AVFilterContext *ctx) +{ + AudioMultiplyContext *s = ctx->priv; + int i, ret, status; + int nb_samples; + int64_t pts; + + FF_FILTER_FORWARD_STATUS_BACK_ALL(ctx->outputs[0], ctx); + + nb_samples = FFMIN(ff_inlink_queued_samples(ctx->inputs[0]), + ff_inlink_queued_samples(ctx->inputs[1])); + for (i = 0; i < ctx->nb_inputs && nb_samples > 0; i++) { + if (s->frames[i]) + continue; + + if (ff_inlink_check_available_samples(ctx->inputs[i], nb_samples) > 0) { + ret = ff_inlink_consume_samples(ctx->inputs[i], nb_samples, nb_samples, &s->frames[i]); + if (ret < 0) + return ret; + } + } + + if (s->frames[0] && s->frames[1]) { + AVFrame *out; + int plane_samples; + + if (av_sample_fmt_is_planar(ctx->inputs[0]->format)) + plane_samples = FFALIGN(s->frames[0]->nb_samples, s->samples_align); + else + plane_samples = FFALIGN(s->frames[0]->nb_samples * s->channels, s->samples_align); + + out = ff_get_audio_buffer(ctx->outputs[0], s->frames[0]->nb_samples); + if (!out) + return AVERROR(ENOMEM); + + out->pts = s->frames[0]->pts; + + if (av_get_packed_sample_fmt(ctx->inputs[0]->format) == AV_SAMPLE_FMT_FLT) { + for (i = 0; i < s->planes; i++) { + s->fdsp->vector_fmul((float *)out->extended_data[i], + (const float *)s->frames[0]->extended_data[i], + (const float *)s->frames[1]->extended_data[i], + plane_samples); + } + } else { + for (i = 0; i < s->planes; i++) { + s->fdsp->vector_dmul((double *)out->extended_data[i], + (const double *)s->frames[0]->extended_data[i], + (const double *)s->frames[1]->extended_data[i], + plane_samples); + } + } + emms_c(); + + av_frame_free(&s->frames[0]); + av_frame_free(&s->frames[1]); + + ret = ff_filter_frame(ctx->outputs[0], out); + if (ret < 0) + return ret; + } + + if (!nb_samples) { + for (i = 0; i < 2; i++) { + if (ff_inlink_acknowledge_status(ctx->inputs[i], &status, &pts)) { + ff_outlink_set_status(ctx->outputs[0], status, pts); + return 0; + } + } + } + + if (ff_outlink_frame_wanted(ctx->outputs[0])) { + for (i = 0; i < 2; i++) { + if (ff_inlink_queued_samples(ctx->inputs[i]) > 0) + continue; + ff_inlink_request_frame(ctx->inputs[i]); + return 0; + } + } + return 0; +} + +static int config_output(AVFilterLink *outlink) +{ + AVFilterContext *ctx = outlink->src; + AudioMultiplyContext *s = ctx->priv; + AVFilterLink *inlink = ctx->inputs[0]; + + s->channels = inlink->channels; + s->planes = av_sample_fmt_is_planar(inlink->format) ? inlink->channels : 1; + s->samples_align = 16; + + return 0; +} + +static av_cold int init(AVFilterContext *ctx) +{ + AudioMultiplyContext *s = ctx->priv; + + s->fdsp = avpriv_float_dsp_alloc(0); + if (!s->fdsp) + return AVERROR(ENOMEM); + + return 0; +} + +static av_cold void uninit(AVFilterContext *ctx) +{ + AudioMultiplyContext *s = ctx->priv; + av_freep(&s->fdsp); +} + +static const AVFilterPad inputs[] = { + { + .name = "multiply0", + .type = AVMEDIA_TYPE_AUDIO, + }, + { + .name = "multiply1", + .type = AVMEDIA_TYPE_AUDIO, + }, + { NULL } +}; + +static const AVFilterPad outputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_AUDIO, + .config_props = config_output, + }, + { NULL } +}; + +AVFilter ff_af_amultiply = { + .name = "amultiply", + .description = NULL_IF_CONFIG_SMALL("Multiply two audio streams."), + .priv_size = sizeof(AudioMultiplyContext), + .init = init, + .uninit = uninit, + .activate = activate, + .query_formats = query_formats, + .inputs = inputs, + .outputs = outputs, +}; diff --git a/libavfilter/af_anequalizer.c b/libavfilter/af_anequalizer.c index 24034602f..03d939f17 100644 --- a/libavfilter/af_anequalizer.c +++ b/libavfilter/af_anequalizer.c @@ -189,6 +189,7 @@ static av_cold int init(AVFilterContext *ctx) { AudioNEqualizerContext *s = ctx->priv; AVFilterPad pad, vpad; + int ret; pad = (AVFilterPad){ .name = av_strdup("out0"), @@ -208,10 +209,19 @@ static av_cold int init(AVFilterContext *ctx) return AVERROR(ENOMEM); } - ff_insert_outpad(ctx, 0, &pad); + ret = ff_insert_outpad(ctx, 0, &pad); + if (ret < 0) { + av_freep(&pad.name); + return ret; + } - if (s->draw_curves) - ff_insert_outpad(ctx, 1, &vpad); + if (s->draw_curves) { + ret = ff_insert_outpad(ctx, 1, &vpad); + if (ret < 0) { + av_freep(&vpad.name); + return ret; + } + } return 0; } @@ -259,9 +269,8 @@ static av_cold void uninit(AVFilterContext *ctx) { AudioNEqualizerContext *s = ctx->priv; - av_freep(&ctx->output_pads[0].name); - if (s->draw_curves) - av_freep(&ctx->output_pads[1].name); + for (int i = 0; i < ctx->nb_outputs; i++) + av_freep(&ctx->output_pads[i].name); av_frame_free(&s->video); av_freep(&s->filters); s->nb_filters = 0; diff --git a/libavfilter/af_anlmdn.c b/libavfilter/af_anlmdn.c new file mode 100644 index 000000000..b5bc94b4e --- /dev/null +++ b/libavfilter/af_anlmdn.c @@ -0,0 +1,396 @@ +/* + * Copyright (c) 2019 Paul B Mahol + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include "libavutil/avassert.h" +#include "libavutil/audio_fifo.h" +#include "libavutil/avstring.h" +#include "libavutil/opt.h" +#include "avfilter.h" +#include "audio.h" +#include "formats.h" + +#include "af_anlmdndsp.h" + +#define WEIGHT_LUT_NBITS 20 +#define WEIGHT_LUT_SIZE (1<compute_distance_ssd = compute_distance_ssd_c; + dsp->compute_cache = compute_cache_c; + + if (ARCH_X86) + ff_anlmdn_init_x86(dsp); +} + +static int config_output(AVFilterLink *outlink) +{ + AVFilterContext *ctx = outlink->src; + AudioNLMeansContext *s = ctx->priv; + int ret; + + s->K = av_rescale(s->pd, outlink->sample_rate, AV_TIME_BASE); + s->S = av_rescale(s->rd, outlink->sample_rate, AV_TIME_BASE); + + s->eof_left = -1; + s->pts = AV_NOPTS_VALUE; + s->H = s->K * 2 + 1; + s->N = s->H + (s->K + s->S) * 2; + + av_log(ctx, AV_LOG_DEBUG, "K:%d S:%d H:%d N:%d\n", s->K, s->S, s->H, s->N); + + av_frame_free(&s->in); + av_frame_free(&s->cache); + s->in = ff_get_audio_buffer(outlink, s->N); + if (!s->in) + return AVERROR(ENOMEM); + + s->cache = ff_get_audio_buffer(outlink, s->S * 2); + if (!s->cache) + return AVERROR(ENOMEM); + + s->fifo = av_audio_fifo_alloc(outlink->format, outlink->channels, s->N); + if (!s->fifo) + return AVERROR(ENOMEM); + + ret = av_audio_fifo_write(s->fifo, (void **)s->in->extended_data, s->K + s->S); + if (ret < 0) + return ret; + + s->pdiff_lut_scale = 1.f / s->m * WEIGHT_LUT_SIZE; + for (int i = 0; i < WEIGHT_LUT_SIZE; i++) { + float w = -i / s->pdiff_lut_scale; + + s->weight_lut[i] = expf(w); + } + + ff_anlmdn_init(&s->dsp); + + return 0; +} + +static int filter_channel(AVFilterContext *ctx, void *arg, int ch, int nb_jobs) +{ + AudioNLMeansContext *s = ctx->priv; + AVFrame *out = arg; + const int S = s->S; + const int K = s->K; + const int om = s->om; + const float *f = (const float *)(s->in->extended_data[ch]) + K; + float *cache = (float *)s->cache->extended_data[ch]; + const float sw = (65536.f / (4 * K + 2)) / sqrtf(s->a); + float *dst = (float *)out->extended_data[ch] + s->offset; + const float smooth = s->m; + + for (int i = S; i < s->H + S; i++) { + float P = 0.f, Q = 0.f; + int v = 0; + + if (i == S) { + for (int j = i - S; j <= i + S; j++) { + if (i == j) + continue; + cache[v++] = s->dsp.compute_distance_ssd(f + i, f + j, K); + } + } else { + s->dsp.compute_cache(cache, f, S, K, i, i - S); + s->dsp.compute_cache(cache + S, f, S, K, i, i + 1); + } + + for (int j = 0; j < 2 * S && !ctx->is_disabled; j++) { + const float distance = cache[j]; + unsigned weight_lut_idx; + float w; + + if (distance < 0.f) { + cache[j] = 0.f; + continue; + } + w = distance * sw; + if (w >= smooth) + continue; + weight_lut_idx = w * s->pdiff_lut_scale; + av_assert2(weight_lut_idx < WEIGHT_LUT_SIZE); + w = s->weight_lut[weight_lut_idx]; + P += w * f[i - S + j + (j >= S)]; + Q += w; + } + + P += f[i]; + Q += 1; + + switch (om) { + case IN_MODE: dst[i - S] = f[i]; break; + case OUT_MODE: dst[i - S] = P / Q; break; + case NOISE_MODE: dst[i - S] = f[i] - (P / Q); break; + } + } + + return 0; +} + +static int filter_frame(AVFilterLink *inlink, AVFrame *in) +{ + AVFilterContext *ctx = inlink->dst; + AVFilterLink *outlink = ctx->outputs[0]; + AudioNLMeansContext *s = ctx->priv; + AVFrame *out = NULL; + int available, wanted, ret; + + if (s->pts == AV_NOPTS_VALUE) + s->pts = in->pts; + + ret = av_audio_fifo_write(s->fifo, (void **)in->extended_data, + in->nb_samples); + av_frame_free(&in); + + s->offset = 0; + available = av_audio_fifo_size(s->fifo); + wanted = (available / s->H) * s->H; + + if (wanted >= s->H && available >= s->N) { + out = ff_get_audio_buffer(outlink, wanted); + if (!out) + return AVERROR(ENOMEM); + } + + while (available >= s->N) { + ret = av_audio_fifo_peek(s->fifo, (void **)s->in->extended_data, s->N); + if (ret < 0) + break; + + ctx->internal->execute(ctx, filter_channel, out, NULL, inlink->channels); + + av_audio_fifo_drain(s->fifo, s->H); + + s->offset += s->H; + available -= s->H; + } + + if (out) { + out->pts = s->pts; + out->nb_samples = s->offset; + if (s->eof_left >= 0) { + out->nb_samples = FFMIN(s->eof_left, s->offset); + s->eof_left -= out->nb_samples; + } + s->pts += s->offset; + + return ff_filter_frame(outlink, out); + } + + return ret; +} + +static int request_frame(AVFilterLink *outlink) +{ + AVFilterContext *ctx = outlink->src; + AudioNLMeansContext *s = ctx->priv; + int ret; + + ret = ff_request_frame(ctx->inputs[0]); + + if (ret == AVERROR_EOF && s->eof_left != 0) { + AVFrame *in; + + if (s->eof_left < 0) + s->eof_left = av_audio_fifo_size(s->fifo) - (s->S + s->K); + if (s->eof_left <= 0) + return AVERROR_EOF; + in = ff_get_audio_buffer(outlink, s->H); + if (!in) + return AVERROR(ENOMEM); + + return filter_frame(ctx->inputs[0], in); + } + + return ret; +} + +static av_cold void uninit(AVFilterContext *ctx) +{ + AudioNLMeansContext *s = ctx->priv; + + av_audio_fifo_free(s->fifo); + av_frame_free(&s->in); + av_frame_free(&s->cache); +} + +static int process_command(AVFilterContext *ctx, const char *cmd, const char *args, + char *res, int res_len, int flags) +{ + AudioNLMeansContext *s = ctx->priv; + + if (!strcmp(cmd, "s")) { + float a; + + if (av_sscanf(args, "%f", &a) == 1) + s->a = av_clipf(a, 0.00001, 10); + } else if (!strcmp(cmd, "o")) { + if (!strcmp(args, "i")) { + s->om = IN_MODE; + } else if (!strcmp(args, "o")) { + s->om = OUT_MODE; + } else if (!strcmp(args, "n")) { + s->om = NOISE_MODE; + } + } + + return 0; +} + +static const AVFilterPad inputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_AUDIO, + .filter_frame = filter_frame, + }, + { NULL } +}; + +static const AVFilterPad outputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_AUDIO, + .config_props = config_output, + .request_frame = request_frame, + }, + { NULL } +}; + +AVFilter ff_af_anlmdn = { + .name = "anlmdn", + .description = NULL_IF_CONFIG_SMALL("Reduce broadband noise from stream using Non-Local Means."), + .query_formats = query_formats, + .priv_size = sizeof(AudioNLMeansContext), + .priv_class = &anlmdn_class, + .uninit = uninit, + .inputs = inputs, + .outputs = outputs, + .process_command = process_command, + .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | + AVFILTER_FLAG_SLICE_THREADS, +}; diff --git a/libavfilter/af_anlmdndsp.h b/libavfilter/af_anlmdndsp.h new file mode 100644 index 000000000..d8f5136cd --- /dev/null +++ b/libavfilter/af_anlmdndsp.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2019 Paul B Mahol + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVFILTER_ANLMDNDSP_H +#define AVFILTER_ANLMDNDSP_H + +#include "libavutil/common.h" + +#include "audio.h" +#include "avfilter.h" +#include "formats.h" +#include "internal.h" + +typedef struct AudioNLMDNDSPContext { + float (*compute_distance_ssd)(const float *f1, const float *f2, ptrdiff_t K); + void (*compute_cache)(float *cache, const float *f, ptrdiff_t S, ptrdiff_t K, + ptrdiff_t i, ptrdiff_t jj); +} AudioNLMDNDSPContext; + +void ff_anlmdn_init(AudioNLMDNDSPContext *s); +void ff_anlmdn_init_x86(AudioNLMDNDSPContext *s); + +#endif /* AVFILTER_ANLMDNDSP_H */ diff --git a/libavfilter/af_apad.c b/libavfilter/af_apad.c index f7a4199c6..fbcf6d134 100644 --- a/libavfilter/af_apad.c +++ b/libavfilter/af_apad.c @@ -41,6 +41,8 @@ typedef struct APadContext { int packet_size; int64_t pad_len, pad_len_left; int64_t whole_len, whole_len_left; + int64_t pad_dur; + int64_t whole_dur; } APadContext; #define OFFSET(x) offsetof(APadContext, x) @@ -50,6 +52,8 @@ static const AVOption apad_options[] = { { "packet_size", "set silence packet size", OFFSET(packet_size), AV_OPT_TYPE_INT, { .i64 = 4096 }, 0, INT_MAX, A }, { "pad_len", "set number of samples of silence to add", OFFSET(pad_len), AV_OPT_TYPE_INT64, { .i64 = -1 }, -1, INT64_MAX, A }, { "whole_len", "set minimum target number of samples in the audio stream", OFFSET(whole_len), AV_OPT_TYPE_INT64, { .i64 = -1 }, -1, INT64_MAX, A }, + { "pad_dur", "set duration of silence to add", OFFSET(pad_dur), AV_OPT_TYPE_DURATION, { .i64 = 0 }, 0, INT64_MAX, A }, + { "whole_dur", "set minimum target duration in the audio stream", OFFSET(whole_dur), AV_OPT_TYPE_DURATION, { .i64 = 0 }, 0, INT64_MAX, A }, { NULL } }; @@ -64,8 +68,6 @@ static av_cold int init(AVFilterContext *ctx) av_log(ctx, AV_LOG_ERROR, "Both whole and pad length are set, this is not possible\n"); return AVERROR(EINVAL); } - s->pad_len_left = s->pad_len; - s->whole_len_left = s->whole_len; return 0; } @@ -131,6 +133,22 @@ static int request_frame(AVFilterLink *outlink) return ret; } +static int config_output(AVFilterLink *outlink) +{ + AVFilterContext *ctx = outlink->src; + APadContext *s = ctx->priv; + + if (s->pad_dur) + s->pad_len = av_rescale(s->pad_dur, outlink->sample_rate, AV_TIME_BASE); + if (s->whole_dur) + s->whole_len = av_rescale(s->whole_dur, outlink->sample_rate, AV_TIME_BASE); + + s->pad_len_left = s->pad_len; + s->whole_len_left = s->whole_len; + + return 0; +} + static const AVFilterPad apad_inputs[] = { { .name = "default", @@ -144,6 +162,7 @@ static const AVFilterPad apad_outputs[] = { { .name = "default", .request_frame = request_frame, + .config_props = config_output, .type = AVMEDIA_TYPE_AUDIO, }, { NULL } diff --git a/libavfilter/af_asetnsamples.c b/libavfilter/af_asetnsamples.c index ecb76e64d..bbc391a4f 100644 --- a/libavfilter/af_asetnsamples.c +++ b/libavfilter/af_asetnsamples.c @@ -24,20 +24,18 @@ * Filter that changes number of samples on single output operation */ -#include "libavutil/audio_fifo.h" #include "libavutil/avassert.h" #include "libavutil/channel_layout.h" #include "libavutil/opt.h" #include "avfilter.h" #include "audio.h" +#include "filters.h" #include "internal.h" #include "formats.h" typedef struct ASNSContext { const AVClass *class; int nb_out_samples; ///< how many samples to output - AVAudioFifo *fifo; ///< samples are queued here - int64_t next_out_pts; int pad; } ASNSContext; @@ -54,134 +52,68 @@ static const AVOption asetnsamples_options[] = { AVFILTER_DEFINE_CLASS(asetnsamples); -static av_cold int init(AVFilterContext *ctx) +static int activate(AVFilterContext *ctx) { - ASNSContext *asns = ctx->priv; - - asns->next_out_pts = AV_NOPTS_VALUE; - av_log(ctx, AV_LOG_VERBOSE, "nb_out_samples:%d pad:%d\n", asns->nb_out_samples, asns->pad); - - return 0; -} - -static av_cold void uninit(AVFilterContext *ctx) -{ - ASNSContext *asns = ctx->priv; - av_audio_fifo_free(asns->fifo); -} - -static int config_props_output(AVFilterLink *outlink) -{ - ASNSContext *asns = outlink->src->priv; - - asns->fifo = av_audio_fifo_alloc(outlink->format, outlink->channels, asns->nb_out_samples); - if (!asns->fifo) - return AVERROR(ENOMEM); - - return 0; -} - -static int push_samples(AVFilterLink *outlink) -{ - ASNSContext *asns = outlink->src->priv; - AVFrame *outsamples = NULL; - int ret, nb_out_samples, nb_pad_samples; - - if (asns->pad) { - nb_out_samples = av_audio_fifo_size(asns->fifo) ? asns->nb_out_samples : 0; - nb_pad_samples = nb_out_samples - FFMIN(nb_out_samples, av_audio_fifo_size(asns->fifo)); - } else { - nb_out_samples = FFMIN(asns->nb_out_samples, av_audio_fifo_size(asns->fifo)); - nb_pad_samples = 0; - } - - if (!nb_out_samples) - return 0; - - outsamples = ff_get_audio_buffer(outlink, nb_out_samples); - if (!outsamples) - return AVERROR(ENOMEM); - - av_audio_fifo_read(asns->fifo, - (void **)outsamples->extended_data, nb_out_samples); - - if (nb_pad_samples) - av_samples_set_silence(outsamples->extended_data, nb_out_samples - nb_pad_samples, - nb_pad_samples, outlink->channels, - outlink->format); - outsamples->nb_samples = nb_out_samples; - outsamples->channel_layout = outlink->channel_layout; - outsamples->sample_rate = outlink->sample_rate; - outsamples->pts = asns->next_out_pts; - - if (asns->next_out_pts != AV_NOPTS_VALUE) - asns->next_out_pts += av_rescale_q(nb_out_samples, (AVRational){1, outlink->sample_rate}, outlink->time_base); - - ret = ff_filter_frame(outlink, outsamples); - if (ret < 0) - return ret; - return nb_out_samples; -} - -static int filter_frame(AVFilterLink *inlink, AVFrame *insamples) -{ - AVFilterContext *ctx = inlink->dst; - ASNSContext *asns = ctx->priv; + AVFilterLink *inlink = ctx->inputs[0]; AVFilterLink *outlink = ctx->outputs[0]; + ASNSContext *s = ctx->priv; + AVFrame *frame = NULL, *pad_frame; int ret; - int nb_samples = insamples->nb_samples; - if (av_audio_fifo_space(asns->fifo) < nb_samples) { - av_log(ctx, AV_LOG_DEBUG, "No space for %d samples, stretching audio fifo\n", nb_samples); - ret = av_audio_fifo_realloc(asns->fifo, av_audio_fifo_size(asns->fifo) + nb_samples); - if (ret < 0) { - av_log(ctx, AV_LOG_ERROR, - "Stretching audio fifo failed, discarded %d samples\n", nb_samples); - return -1; - } - } - ret = av_audio_fifo_write(asns->fifo, (void **)insamples->extended_data, nb_samples); - if (ret > 0 && asns->next_out_pts == AV_NOPTS_VALUE) - asns->next_out_pts = insamples->pts; - av_frame_free(&insamples); + FF_FILTER_FORWARD_STATUS_BACK(outlink, inlink); + ret = ff_inlink_consume_samples(inlink, s->nb_out_samples, s->nb_out_samples, &frame); if (ret < 0) return ret; - while (av_audio_fifo_size(asns->fifo) >= asns->nb_out_samples) - push_samples(outlink); - return 0; -} + if (ret > 0) { + if (!s->pad || frame->nb_samples == s->nb_out_samples) { + ret = ff_filter_frame(outlink, frame); + if (ff_inlink_queued_samples(inlink) >= s->nb_out_samples) + ff_filter_set_ready(ctx, 100); + return ret; + } -static int request_frame(AVFilterLink *outlink) -{ - AVFilterLink *inlink = outlink->src->inputs[0]; - int ret; + pad_frame = ff_get_audio_buffer(outlink, s->nb_out_samples); + if (!pad_frame) { + av_frame_free(&frame); + return AVERROR(ENOMEM); + } - ret = ff_request_frame(inlink); - if (ret == AVERROR_EOF) { - ret = push_samples(outlink); - return ret < 0 ? ret : ret > 0 ? 0 : AVERROR_EOF; + ret = av_frame_copy_props(pad_frame, frame); + if (ret < 0) { + av_frame_free(&pad_frame); + av_frame_free(&frame); + return ret; + } + + av_samples_copy(pad_frame->extended_data, frame->extended_data, + 0, 0, frame->nb_samples, frame->channels, frame->format); + av_samples_set_silence(pad_frame->extended_data, frame->nb_samples, + s->nb_out_samples - frame->nb_samples, frame->channels, + frame->format); + av_frame_free(&frame); + return ff_filter_frame(outlink, pad_frame); } - return ret; + FF_FILTER_FORWARD_STATUS(inlink, outlink); + FF_FILTER_FORWARD_WANTED(outlink, inlink); + + return FFERROR_NOT_READY; } static const AVFilterPad asetnsamples_inputs[] = { { - .name = "default", - .type = AVMEDIA_TYPE_AUDIO, - .filter_frame = filter_frame, + .name = "default", + .type = AVMEDIA_TYPE_AUDIO, }, { NULL } }; static const AVFilterPad asetnsamples_outputs[] = { { - .name = "default", - .type = AVMEDIA_TYPE_AUDIO, - .request_frame = request_frame, - .config_props = config_props_output, + .name = "default", + .type = AVMEDIA_TYPE_AUDIO, }, { NULL } }; @@ -191,8 +123,7 @@ AVFilter ff_af_asetnsamples = { .description = NULL_IF_CONFIG_SMALL("Set the number of samples for each output audio frames."), .priv_size = sizeof(ASNSContext), .priv_class = &asetnsamples_class, - .init = init, - .uninit = uninit, .inputs = asetnsamples_inputs, .outputs = asetnsamples_outputs, + .activate = activate, }; diff --git a/libavfilter/af_asoftclip.c b/libavfilter/af_asoftclip.c new file mode 100644 index 000000000..a42b56dff --- /dev/null +++ b/libavfilter/af_asoftclip.c @@ -0,0 +1,288 @@ +/* + * Copyright (c) 2019 The FFmpeg Project + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/channel_layout.h" +#include "libavutil/opt.h" +#include "avfilter.h" +#include "audio.h" +#include "formats.h" + +enum ASoftClipTypes { + ASC_TANH, + ASC_ATAN, + ASC_CUBIC, + ASC_EXP, + ASC_ALG, + ASC_QUINTIC, + ASC_SIN, + NB_TYPES, +}; + +typedef struct ASoftClipContext { + const AVClass *class; + + int type; + double param; + + void (*filter)(struct ASoftClipContext *s, void **dst, const void **src, + int nb_samples, int channels); +} ASoftClipContext; + +#define OFFSET(x) offsetof(ASoftClipContext, x) +#define A AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM + +static const AVOption asoftclip_options[] = { + { "type", "set softclip type", OFFSET(type), AV_OPT_TYPE_INT, {.i64=0}, 0, NB_TYPES-1, A, "types" }, + { "tanh", NULL, 0, AV_OPT_TYPE_CONST, {.i64=ASC_TANH}, 0, 0, A, "types" }, + { "atan", NULL, 0, AV_OPT_TYPE_CONST, {.i64=ASC_ATAN}, 0, 0, A, "types" }, + { "cubic", NULL, 0, AV_OPT_TYPE_CONST, {.i64=ASC_CUBIC}, 0, 0, A, "types" }, + { "exp", NULL, 0, AV_OPT_TYPE_CONST, {.i64=ASC_EXP}, 0, 0, A, "types" }, + { "alg", NULL, 0, AV_OPT_TYPE_CONST, {.i64=ASC_ALG}, 0, 0, A, "types" }, + { "quintic", NULL, 0, AV_OPT_TYPE_CONST, {.i64=ASC_QUINTIC},0, 0, A, "types" }, + { "sin", NULL, 0, AV_OPT_TYPE_CONST, {.i64=ASC_SIN}, 0, 0, A, "types" }, + { "param", "set softclip parameter", OFFSET(param), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0.01, 3, A }, + { NULL } +}; + +AVFILTER_DEFINE_CLASS(asoftclip); + +static int query_formats(AVFilterContext *ctx) +{ + AVFilterFormats *formats = NULL; + AVFilterChannelLayouts *layouts = NULL; + static const enum AVSampleFormat sample_fmts[] = { + AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_FLTP, + AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_DBLP, + AV_SAMPLE_FMT_NONE + }; + int ret; + + formats = ff_make_format_list(sample_fmts); + if (!formats) + return AVERROR(ENOMEM); + ret = ff_set_common_formats(ctx, formats); + if (ret < 0) + return ret; + + layouts = ff_all_channel_counts(); + if (!layouts) + return AVERROR(ENOMEM); + + ret = ff_set_common_channel_layouts(ctx, layouts); + if (ret < 0) + return ret; + + formats = ff_all_samplerates(); + return ff_set_common_samplerates(ctx, formats); +} + +#define SQR(x) ((x) * (x)) + +static void filter_flt(ASoftClipContext *s, + void **dptr, const void **sptr, + int nb_samples, int channels) +{ + float param = s->param; + + for (int c = 0; c < channels; c++) { + const float *src = sptr[c]; + float *dst = dptr[c]; + + switch (s->type) { + case ASC_TANH: + for (int n = 0; n < nb_samples; n++) { + dst[n] = tanhf(src[n] * param); + } + break; + case ASC_ATAN: + for (int n = 0; n < nb_samples; n++) + dst[n] = 2.f / M_PI * atanf(src[n] * param); + break; + case ASC_CUBIC: + for (int n = 0; n < nb_samples; n++) { + if (FFABS(src[n]) >= 1.5f) + dst[n] = FFSIGN(src[n]); + else + dst[n] = src[n] - 0.1481f * powf(src[n], 3.f); + } + break; + case ASC_EXP: + for (int n = 0; n < nb_samples; n++) + dst[n] = 2.f / (1.f + expf(-2.f * src[n])) - 1.; + break; + case ASC_ALG: + for (int n = 0; n < nb_samples; n++) + dst[n] = src[n] / (sqrtf(param + src[n] * src[n])); + break; + case ASC_QUINTIC: + for (int n = 0; n < nb_samples; n++) { + if (FFABS(src[n]) >= 1.25) + dst[n] = FFSIGN(src[n]); + else + dst[n] = src[n] - 0.08192f * powf(src[n], 5.f); + } + break; + case ASC_SIN: + for (int n = 0; n < nb_samples; n++) { + if (FFABS(src[n]) >= M_PI_2) + dst[n] = FFSIGN(src[n]); + else + dst[n] = sinf(src[n]); + } + break; + } + } +} + +static void filter_dbl(ASoftClipContext *s, + void **dptr, const void **sptr, + int nb_samples, int channels) +{ + double param = s->param; + + for (int c = 0; c < channels; c++) { + const double *src = sptr[c]; + double *dst = dptr[c]; + + switch (s->type) { + case ASC_TANH: + for (int n = 0; n < nb_samples; n++) { + dst[n] = tanh(src[n] * param); + } + break; + case ASC_ATAN: + for (int n = 0; n < nb_samples; n++) + dst[n] = 2. / M_PI * atan(src[n] * param); + break; + case ASC_CUBIC: + for (int n = 0; n < nb_samples; n++) { + if (FFABS(src[n]) >= 1.5) + dst[n] = FFSIGN(src[n]); + else + dst[n] = src[n] - 0.1481 * pow(src[n], 3.); + } + break; + case ASC_EXP: + for (int n = 0; n < nb_samples; n++) + dst[n] = 2. / (1. + exp(-2. * src[n])) - 1.; + break; + case ASC_ALG: + for (int n = 0; n < nb_samples; n++) + dst[n] = src[n] / (sqrt(param + src[n] * src[n])); + break; + case ASC_QUINTIC: + for (int n = 0; n < nb_samples; n++) { + if (FFABS(src[n]) >= 1.25) + dst[n] = FFSIGN(src[n]); + else + dst[n] = src[n] - 0.08192 * pow(src[n], 5.); + } + break; + case ASC_SIN: + for (int n = 0; n < nb_samples; n++) { + if (FFABS(src[n]) >= M_PI_2) + dst[n] = FFSIGN(src[n]); + else + dst[n] = sin(src[n]); + } + break; + } + } +} + +static int config_input(AVFilterLink *inlink) +{ + AVFilterContext *ctx = inlink->dst; + ASoftClipContext *s = ctx->priv; + + switch (inlink->format) { + case AV_SAMPLE_FMT_FLT: + case AV_SAMPLE_FMT_FLTP: s->filter = filter_flt; break; + case AV_SAMPLE_FMT_DBL: + case AV_SAMPLE_FMT_DBLP: s->filter = filter_dbl; break; + } + + return 0; +} + +static int filter_frame(AVFilterLink *inlink, AVFrame *in) +{ + AVFilterContext *ctx = inlink->dst; + AVFilterLink *outlink = ctx->outputs[0]; + ASoftClipContext *s = ctx->priv; + int nb_samples, channels; + AVFrame *out; + + if (av_frame_is_writable(in)) { + out = in; + } else { + out = ff_get_audio_buffer(outlink, in->nb_samples); + if (!out) { + av_frame_free(&in); + return AVERROR(ENOMEM); + } + av_frame_copy_props(out, in); + } + + if (av_sample_fmt_is_planar(in->format)) { + nb_samples = in->nb_samples; + channels = in->channels; + } else { + nb_samples = in->channels * in->nb_samples; + channels = 1; + } + + s->filter(s, (void **)out->extended_data, (const void **)in->extended_data, + nb_samples, channels); + + if (out != in) + av_frame_free(&in); + + return ff_filter_frame(outlink, out); +} + +static const AVFilterPad inputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_AUDIO, + .filter_frame = filter_frame, + .config_props = config_input, + }, + { NULL } +}; + +static const AVFilterPad outputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_AUDIO, + }, + { NULL } +}; + +AVFilter ff_af_asoftclip = { + .name = "asoftclip", + .description = NULL_IF_CONFIG_SMALL("Audio Soft Clipper."), + .query_formats = query_formats, + .priv_size = sizeof(ASoftClipContext), + .priv_class = &asoftclip_class, + .inputs = inputs, + .outputs = outputs, + .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC, +}; diff --git a/libavfilter/af_asr.c b/libavfilter/af_asr.c new file mode 100644 index 000000000..0c08df135 --- /dev/null +++ b/libavfilter/af_asr.c @@ -0,0 +1,181 @@ +/* + * Copyright (c) 2019 Paul B Mahol + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include "libavutil/avassert.h" +#include "libavutil/avstring.h" +#include "libavutil/channel_layout.h" +#include "libavutil/opt.h" +#include "audio.h" +#include "avfilter.h" +#include "internal.h" + +typedef struct ASRContext { + const AVClass *class; + + int rate; + char *hmm; + char *dict; + char *lm; + char *lmctl; + char *lmname; + char *logfn; + + ps_decoder_t *ps; + cmd_ln_t *config; + + int utt_started; +} ASRContext; + +#define OFFSET(x) offsetof(ASRContext, x) +#define FLAGS AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_FILTERING_PARAM +static const AVOption asr_options[] = { + { "rate", "set sampling rate", OFFSET(rate), AV_OPT_TYPE_INT, {.i64=16000}, 0, INT_MAX, .flags = FLAGS }, + { "hmm", "set directory containing acoustic model files", OFFSET(hmm), AV_OPT_TYPE_STRING, {.str=NULL}, .flags = FLAGS }, + { "dict", "set pronunciation dictionary", OFFSET(dict), AV_OPT_TYPE_STRING, {.str=NULL}, .flags = FLAGS }, + { "lm", "set language model file", OFFSET(lm), AV_OPT_TYPE_STRING, {.str=NULL}, .flags = FLAGS }, + { "lmctl", "set language model set", OFFSET(lmctl), AV_OPT_TYPE_STRING, {.str=NULL}, .flags = FLAGS }, + { "lmname","set which language model to use", OFFSET(lmname), AV_OPT_TYPE_STRING, {.str=NULL}, .flags = FLAGS }, + { "logfn", "set output for log messages", OFFSET(logfn), AV_OPT_TYPE_STRING, {.str="/dev/null"}, .flags = FLAGS }, + { NULL } +}; + +AVFILTER_DEFINE_CLASS(asr); + +static int filter_frame(AVFilterLink *inlink, AVFrame *in) +{ + AVFilterContext *ctx = inlink->dst; + AVDictionary **metadata = &in->metadata; + ASRContext *s = ctx->priv; + int have_speech; + const char *speech; + + ps_process_raw(s->ps, (const int16_t *)in->data[0], in->nb_samples, 0, 0); + have_speech = ps_get_in_speech(s->ps); + if (have_speech && !s->utt_started) + s->utt_started = 1; + if (!have_speech && s->utt_started) { + ps_end_utt(s->ps); + speech = ps_get_hyp(s->ps, NULL); + if (speech != NULL) + av_dict_set(metadata, "lavfi.asr.text", speech, 0); + ps_start_utt(s->ps); + s->utt_started = 0; + } + + return ff_filter_frame(ctx->outputs[0], in); +} + +static int config_input(AVFilterLink *inlink) +{ + AVFilterContext *ctx = inlink->dst; + ASRContext *s = ctx->priv; + + ps_start_utt(s->ps); + + return 0; +} + +static av_cold int asr_init(AVFilterContext *ctx) +{ + ASRContext *s = ctx->priv; + const float frate = s->rate; + char *rate = av_asprintf("%f", frate); + const char *argv[] = { "-logfn", s->logfn, + "-hmm", s->hmm, + "-lm", s->lm, + "-lmctl", s->lmctl, + "-lmname", s->lmname, + "-dict", s->dict, + "-samprate", rate, + NULL }; + + s->config = cmd_ln_parse_r(NULL, ps_args(), 14, (char **)argv, 0); + av_free(rate); + if (!s->config) + return AVERROR(ENOMEM); + + ps_default_search_args(s->config); + s->ps = ps_init(s->config); + if (!s->ps) + return AVERROR(ENOMEM); + + return 0; +} + +static int query_formats(AVFilterContext *ctx) +{ + ASRContext *s = ctx->priv; + int sample_rates[] = { s->rate, -1 }; + int ret; + + AVFilterFormats *formats = NULL; + AVFilterChannelLayouts *layout = NULL; + + if ((ret = ff_add_format (&formats, AV_SAMPLE_FMT_S16 )) < 0 || + (ret = ff_set_common_formats (ctx , formats )) < 0 || + (ret = ff_add_channel_layout (&layout , AV_CH_LAYOUT_MONO )) < 0 || + (ret = ff_set_common_channel_layouts (ctx , layout )) < 0 || + (ret = ff_set_common_samplerates (ctx , ff_make_format_list(sample_rates) )) < 0) + return ret; + + return 0; +} + +static av_cold void asr_uninit(AVFilterContext *ctx) +{ + ASRContext *s = ctx->priv; + + ps_free(s->ps); + s->ps = NULL; + cmd_ln_free_r(s->config); + s->config = NULL; +} + +static const AVFilterPad asr_inputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_AUDIO, + .filter_frame = filter_frame, + .config_props = config_input, + }, + { NULL } +}; + +static const AVFilterPad asr_outputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_AUDIO, + }, + { NULL } +}; + +AVFilter ff_af_asr = { + .name = "asr", + .description = NULL_IF_CONFIG_SMALL("Automatic Speech Recognition."), + .priv_size = sizeof(ASRContext), + .priv_class = &asr_class, + .init = asr_init, + .uninit = asr_uninit, + .query_formats = query_formats, + .inputs = asr_inputs, + .outputs = asr_outputs, +}; diff --git a/libavfilter/af_astats.c b/libavfilter/af_astats.c index 2922da9f4..7707f3158 100644 --- a/libavfilter/af_astats.c +++ b/libavfilter/af_astats.c @@ -20,14 +20,44 @@ */ #include +#include #include "libavutil/opt.h" #include "audio.h" #include "avfilter.h" #include "internal.h" +#define MEASURE_ALL UINT_MAX +#define MEASURE_NONE 0 + +#define MEASURE_DC_OFFSET (1 << 0) +#define MEASURE_MIN_LEVEL (1 << 1) +#define MEASURE_MAX_LEVEL (1 << 2) +#define MEASURE_MIN_DIFFERENCE (1 << 3) +#define MEASURE_MAX_DIFFERENCE (1 << 4) +#define MEASURE_MEAN_DIFFERENCE (1 << 5) +#define MEASURE_RMS_DIFFERENCE (1 << 6) +#define MEASURE_PEAK_LEVEL (1 << 7) +#define MEASURE_RMS_LEVEL (1 << 8) +#define MEASURE_RMS_PEAK (1 << 9) +#define MEASURE_RMS_TROUGH (1 << 10) +#define MEASURE_CREST_FACTOR (1 << 11) +#define MEASURE_FLAT_FACTOR (1 << 12) +#define MEASURE_PEAK_COUNT (1 << 13) +#define MEASURE_BIT_DEPTH (1 << 14) +#define MEASURE_DYNAMIC_RANGE (1 << 15) +#define MEASURE_ZERO_CROSSINGS (1 << 16) +#define MEASURE_ZERO_CROSSINGS_RATE (1 << 17) +#define MEASURE_NUMBER_OF_SAMPLES (1 << 18) +#define MEASURE_NUMBER_OF_NANS (1 << 19) +#define MEASURE_NUMBER_OF_INFS (1 << 20) +#define MEASURE_NUMBER_OF_DENORMALS (1 << 21) + +#define MEASURE_MINMAXPEAK (MEASURE_MIN_LEVEL | MEASURE_MAX_LEVEL | MEASURE_PEAK_LEVEL) + typedef struct ChannelStats { double last; + double last_non_zero; double min_non_zero; double sigma_x, sigma_x2; double avg_sigma_x2, min_sigma_x2, max_sigma_x2; @@ -40,7 +70,11 @@ typedef struct ChannelStats { double diff1_sum_x2; uint64_t mask, imask; uint64_t min_count, max_count; + uint64_t zero_runs; uint64_t nb_samples; + uint64_t nb_nans; + uint64_t nb_infs; + uint64_t nb_denormals; } ChannelStats; typedef struct AudioStatsContext { @@ -54,6 +88,10 @@ typedef struct AudioStatsContext { int reset_count; int nb_frames; int maxbitdepth; + int measure_perchannel; + int measure_overall; + int is_float; + int is_double; } AudioStatsContext; #define OFFSET(x) offsetof(AudioStatsContext, x) @@ -63,6 +101,32 @@ static const AVOption astats_options[] = { { "length", "set the window length", OFFSET(time_constant), AV_OPT_TYPE_DOUBLE, {.dbl=.05}, .01, 10, FLAGS }, { "metadata", "inject metadata in the filtergraph", OFFSET(metadata), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS }, { "reset", "recalculate stats after this many frames", OFFSET(reset_count), AV_OPT_TYPE_INT, {.i64=0}, 0, INT_MAX, FLAGS }, + { "measure_perchannel", "only measure_perchannel these per-channel statistics", OFFSET(measure_perchannel), AV_OPT_TYPE_FLAGS, {.i64=MEASURE_ALL}, 0, UINT_MAX, FLAGS, "measure" }, + { "none" , "", 0, AV_OPT_TYPE_CONST, {.i64=MEASURE_NONE }, 0, 0, FLAGS, "measure" }, + { "all" , "", 0, AV_OPT_TYPE_CONST, {.i64=MEASURE_ALL }, 0, 0, FLAGS, "measure" }, + { "DC_offset" , "", 0, AV_OPT_TYPE_CONST, {.i64=MEASURE_DC_OFFSET }, 0, 0, FLAGS, "measure" }, + { "Min_level" , "", 0, AV_OPT_TYPE_CONST, {.i64=MEASURE_MIN_LEVEL }, 0, 0, FLAGS, "measure" }, + { "Max_level" , "", 0, AV_OPT_TYPE_CONST, {.i64=MEASURE_MAX_LEVEL }, 0, 0, FLAGS, "measure" }, + { "Min_difference" , "", 0, AV_OPT_TYPE_CONST, {.i64=MEASURE_MIN_DIFFERENCE }, 0, 0, FLAGS, "measure" }, + { "Max_difference" , "", 0, AV_OPT_TYPE_CONST, {.i64=MEASURE_MAX_DIFFERENCE }, 0, 0, FLAGS, "measure" }, + { "Mean_difference" , "", 0, AV_OPT_TYPE_CONST, {.i64=MEASURE_MEAN_DIFFERENCE }, 0, 0, FLAGS, "measure" }, + { "RMS_difference" , "", 0, AV_OPT_TYPE_CONST, {.i64=MEASURE_RMS_DIFFERENCE }, 0, 0, FLAGS, "measure" }, + { "Peak_level" , "", 0, AV_OPT_TYPE_CONST, {.i64=MEASURE_PEAK_LEVEL }, 0, 0, FLAGS, "measure" }, + { "RMS_level" , "", 0, AV_OPT_TYPE_CONST, {.i64=MEASURE_RMS_LEVEL }, 0, 0, FLAGS, "measure" }, + { "RMS_peak" , "", 0, AV_OPT_TYPE_CONST, {.i64=MEASURE_RMS_PEAK }, 0, 0, FLAGS, "measure" }, + { "RMS_trough" , "", 0, AV_OPT_TYPE_CONST, {.i64=MEASURE_RMS_TROUGH }, 0, 0, FLAGS, "measure" }, + { "Crest_factor" , "", 0, AV_OPT_TYPE_CONST, {.i64=MEASURE_CREST_FACTOR }, 0, 0, FLAGS, "measure" }, + { "Flat_factor" , "", 0, AV_OPT_TYPE_CONST, {.i64=MEASURE_FLAT_FACTOR }, 0, 0, FLAGS, "measure" }, + { "Peak_count" , "", 0, AV_OPT_TYPE_CONST, {.i64=MEASURE_PEAK_COUNT }, 0, 0, FLAGS, "measure" }, + { "Bit_depth" , "", 0, AV_OPT_TYPE_CONST, {.i64=MEASURE_BIT_DEPTH }, 0, 0, FLAGS, "measure" }, + { "Dynamic_range" , "", 0, AV_OPT_TYPE_CONST, {.i64=MEASURE_DYNAMIC_RANGE }, 0, 0, FLAGS, "measure" }, + { "Zero_crossings" , "", 0, AV_OPT_TYPE_CONST, {.i64=MEASURE_ZERO_CROSSINGS }, 0, 0, FLAGS, "measure" }, + { "Zero_crossings_rate" , "", 0, AV_OPT_TYPE_CONST, {.i64=MEASURE_ZERO_CROSSINGS_RATE }, 0, 0, FLAGS, "measure" }, + { "Number_of_samples" , "", 0, AV_OPT_TYPE_CONST, {.i64=MEASURE_NUMBER_OF_SAMPLES }, 0, 0, FLAGS, "measure" }, + { "Number_of_NaNs" , "", 0, AV_OPT_TYPE_CONST, {.i64=MEASURE_NUMBER_OF_NANS }, 0, 0, FLAGS, "measure" }, + { "Number_of_Infs" , "", 0, AV_OPT_TYPE_CONST, {.i64=MEASURE_NUMBER_OF_INFS }, 0, 0, FLAGS, "measure" }, + { "Number_of_denormals" , "", 0, AV_OPT_TYPE_CONST, {.i64=MEASURE_NUMBER_OF_DENORMALS }, 0, 0, FLAGS, "measure" }, + { "measure_overall", "only measure_perchannel these overall statistics", OFFSET(measure_overall), AV_OPT_TYPE_FLAGS, {.i64=MEASURE_ALL}, 0, UINT_MAX, FLAGS, "measure" }, { NULL } }; @@ -110,10 +174,10 @@ static void reset_stats(AudioStatsContext *s) ChannelStats *p = &s->chstats[c]; p->min = p->nmin = p->min_sigma_x2 = DBL_MAX; - p->max = p->nmax = p->max_sigma_x2 = DBL_MIN; + p->max = p->nmax = p->max_sigma_x2 =-DBL_MAX; p->min_non_zero = DBL_MAX; p->min_diff = DBL_MAX; - p->max_diff = DBL_MIN; + p->max_diff = 0; p->sigma_x = 0; p->sigma_x2 = 0; p->avg_sigma_x2 = 0; @@ -127,7 +191,12 @@ static void reset_stats(AudioStatsContext *s) p->imask = 0xFFFFFFFFFFFFFFFF; p->min_count = 0; p->max_count = 0; + p->zero_runs = 0; p->nb_samples = 0; + p->nb_nans = 0; + p->nb_infs = 0; + p->nb_denormals = 0; + p->last = NAN; } } @@ -143,6 +212,11 @@ static int config_output(AVFilterLink *outlink) s->tc_samples = 5 * s->time_constant * outlink->sample_rate + .5; s->nb_frames = 0; s->maxbitdepth = av_get_bytes_per_sample(outlink->format) * 8; + s->is_double = outlink->format == AV_SAMPLE_FMT_DBL || + outlink->format == AV_SAMPLE_FMT_DBLP; + + s->is_float = outlink->format == AV_SAMPLE_FMT_FLT || + outlink->format == AV_SAMPLE_FMT_FLTP; reset_stats(s); @@ -165,6 +239,14 @@ static void bit_depth(AudioStatsContext *s, uint64_t mask, uint64_t imask, AVRat depth->num++; } +static inline void update_minmax(AudioStatsContext *s, ChannelStats *p, double d) +{ + if (d < p->min) + p->min = d; + if (d > p->max) + p->max = d; +} + static inline void update_stat(AudioStatsContext *s, ChannelStats *p, double d, double nd, int64_t i) { if (d < p->min) { @@ -196,13 +278,20 @@ static inline void update_stat(AudioStatsContext *s, ChannelStats *p, double d, p->max_runs += p->max_run * p->max_run; } + if (d != 0) { + p->zero_runs += FFSIGN(d) != FFSIGN(p->last_non_zero); + p->last_non_zero = d; + } + p->sigma_x += nd; p->sigma_x2 += nd * nd; p->avg_sigma_x2 = p->avg_sigma_x2 * s->mult + (1.0 - s->mult) * nd * nd; - p->min_diff = FFMIN(p->min_diff, fabs(d - p->last)); - p->max_diff = FFMAX(p->max_diff, fabs(d - p->last)); - p->diff1_sum += fabs(d - p->last); - p->diff1_sum_x2 += (d - p->last) * (d - p->last); + if (!isnan(p->last)) { + p->min_diff = FFMIN(p->min_diff, fabs(d - p->last)); + p->max_diff = FFMAX(p->max_diff, fabs(d - p->last)); + p->diff1_sum += fabs(d - p->last); + p->diff1_sum_x2 += (d - p->last) * (d - p->last); + } p->last = d; p->mask |= i; p->imask &= i; @@ -214,6 +303,24 @@ static inline void update_stat(AudioStatsContext *s, ChannelStats *p, double d, p->nb_samples++; } +static inline void update_float_stat(AudioStatsContext *s, ChannelStats *p, float d) +{ + int type = fpclassify(d); + + p->nb_nans += type == FP_NAN; + p->nb_infs += type == FP_INFINITE; + p->nb_denormals += type == FP_SUBNORMAL; +} + +static inline void update_double_stat(AudioStatsContext *s, ChannelStats *p, double d) +{ + int type = fpclassify(d); + + p->nb_nans += type == FP_NAN; + p->nb_infs += type == FP_INFINITE; + p->nb_denormals += type == FP_SUBNORMAL; +} + static void set_meta(AVDictionary **metadata, int chan, const char *key, const char *fmt, double val) { @@ -233,16 +340,17 @@ static void set_meta(AVDictionary **metadata, int chan, const char *key, static void set_metadata(AudioStatsContext *s, AVDictionary **metadata) { uint64_t mask = 0, imask = 0xFFFFFFFFFFFFFFFF, min_count = 0, max_count = 0, nb_samples = 0; + uint64_t nb_nans = 0, nb_infs = 0, nb_denormals = 0; double min_runs = 0, max_runs = 0, - min = DBL_MAX, max = DBL_MIN, min_diff = DBL_MAX, max_diff = 0, - nmin = DBL_MAX, nmax = DBL_MIN, + min = DBL_MAX, max =-DBL_MAX, min_diff = DBL_MAX, max_diff = 0, + nmin = DBL_MAX, nmax =-DBL_MAX, max_sigma_x = 0, diff1_sum = 0, diff1_sum_x2 = 0, sigma_x = 0, sigma_x2 = 0, min_sigma_x2 = DBL_MAX, - max_sigma_x2 = DBL_MIN; + max_sigma_x2 =-DBL_MAX; AVRational depth; int c; @@ -271,54 +379,138 @@ static void set_metadata(AudioStatsContext *s, AVDictionary **metadata) mask |= p->mask; imask &= p->imask; nb_samples += p->nb_samples; + nb_nans += p->nb_nans; + nb_infs += p->nb_infs; + nb_denormals += p->nb_denormals; if (fabs(p->sigma_x) > fabs(max_sigma_x)) max_sigma_x = p->sigma_x; - set_meta(metadata, c + 1, "DC_offset", "%f", p->sigma_x / p->nb_samples); - set_meta(metadata, c + 1, "Min_level", "%f", p->min); - set_meta(metadata, c + 1, "Max_level", "%f", p->max); - set_meta(metadata, c + 1, "Min_difference", "%f", p->min_diff); - set_meta(metadata, c + 1, "Max_difference", "%f", p->max_diff); - set_meta(metadata, c + 1, "Mean_difference", "%f", p->diff1_sum / (p->nb_samples - 1)); - set_meta(metadata, c + 1, "RMS_difference", "%f", sqrt(p->diff1_sum_x2 / (p->nb_samples - 1))); - set_meta(metadata, c + 1, "Peak_level", "%f", LINEAR_TO_DB(FFMAX(-p->nmin, p->nmax))); - set_meta(metadata, c + 1, "RMS_level", "%f", LINEAR_TO_DB(sqrt(p->sigma_x2 / p->nb_samples))); - set_meta(metadata, c + 1, "RMS_peak", "%f", LINEAR_TO_DB(sqrt(p->max_sigma_x2))); - set_meta(metadata, c + 1, "RMS_trough", "%f", LINEAR_TO_DB(sqrt(p->min_sigma_x2))); - set_meta(metadata, c + 1, "Crest_factor", "%f", p->sigma_x2 ? FFMAX(-p->min, p->max) / sqrt(p->sigma_x2 / p->nb_samples) : 1); - set_meta(metadata, c + 1, "Flat_factor", "%f", LINEAR_TO_DB((p->min_runs + p->max_runs) / (p->min_count + p->max_count))); - set_meta(metadata, c + 1, "Peak_count", "%f", (float)(p->min_count + p->max_count)); - bit_depth(s, p->mask, p->imask, &depth); - set_meta(metadata, c + 1, "Bit_depth", "%f", depth.num); - set_meta(metadata, c + 1, "Bit_depth2", "%f", depth.den); - set_meta(metadata, c + 1, "Dynamic_range", "%f", LINEAR_TO_DB(2 * FFMAX(FFABS(p->min), FFABS(p->max))/ p->min_non_zero)); + if (s->measure_perchannel & MEASURE_DC_OFFSET) + set_meta(metadata, c + 1, "DC_offset", "%f", p->sigma_x / p->nb_samples); + if (s->measure_perchannel & MEASURE_MIN_LEVEL) + set_meta(metadata, c + 1, "Min_level", "%f", p->min); + if (s->measure_perchannel & MEASURE_MAX_LEVEL) + set_meta(metadata, c + 1, "Max_level", "%f", p->max); + if (s->measure_perchannel & MEASURE_MIN_DIFFERENCE) + set_meta(metadata, c + 1, "Min_difference", "%f", p->min_diff); + if (s->measure_perchannel & MEASURE_MAX_DIFFERENCE) + set_meta(metadata, c + 1, "Max_difference", "%f", p->max_diff); + if (s->measure_perchannel & MEASURE_MEAN_DIFFERENCE) + set_meta(metadata, c + 1, "Mean_difference", "%f", p->diff1_sum / (p->nb_samples - 1)); + if (s->measure_perchannel & MEASURE_RMS_DIFFERENCE) + set_meta(metadata, c + 1, "RMS_difference", "%f", sqrt(p->diff1_sum_x2 / (p->nb_samples - 1))); + if (s->measure_perchannel & MEASURE_PEAK_LEVEL) + set_meta(metadata, c + 1, "Peak_level", "%f", LINEAR_TO_DB(FFMAX(-p->nmin, p->nmax))); + if (s->measure_perchannel & MEASURE_RMS_LEVEL) + set_meta(metadata, c + 1, "RMS_level", "%f", LINEAR_TO_DB(sqrt(p->sigma_x2 / p->nb_samples))); + if (s->measure_perchannel & MEASURE_RMS_PEAK) + set_meta(metadata, c + 1, "RMS_peak", "%f", LINEAR_TO_DB(sqrt(p->max_sigma_x2))); + if (s->measure_perchannel & MEASURE_RMS_TROUGH) + set_meta(metadata, c + 1, "RMS_trough", "%f", LINEAR_TO_DB(sqrt(p->min_sigma_x2))); + if (s->measure_perchannel & MEASURE_CREST_FACTOR) + set_meta(metadata, c + 1, "Crest_factor", "%f", p->sigma_x2 ? FFMAX(-p->min, p->max) / sqrt(p->sigma_x2 / p->nb_samples) : 1); + if (s->measure_perchannel & MEASURE_FLAT_FACTOR) + set_meta(metadata, c + 1, "Flat_factor", "%f", LINEAR_TO_DB((p->min_runs + p->max_runs) / (p->min_count + p->max_count))); + if (s->measure_perchannel & MEASURE_PEAK_COUNT) + set_meta(metadata, c + 1, "Peak_count", "%f", (float)(p->min_count + p->max_count)); + if (s->measure_perchannel & MEASURE_BIT_DEPTH) { + bit_depth(s, p->mask, p->imask, &depth); + set_meta(metadata, c + 1, "Bit_depth", "%f", depth.num); + set_meta(metadata, c + 1, "Bit_depth2", "%f", depth.den); + } + if (s->measure_perchannel & MEASURE_DYNAMIC_RANGE) + set_meta(metadata, c + 1, "Dynamic_range", "%f", LINEAR_TO_DB(2 * FFMAX(FFABS(p->min), FFABS(p->max))/ p->min_non_zero)); + if (s->measure_perchannel & MEASURE_ZERO_CROSSINGS) + set_meta(metadata, c + 1, "Zero_crossings", "%f", p->zero_runs); + if (s->measure_perchannel & MEASURE_ZERO_CROSSINGS_RATE) + set_meta(metadata, c + 1, "Zero_crossings_rate", "%f", p->zero_runs/(double)p->nb_samples); + if ((s->is_float || s->is_double) && s->measure_perchannel & MEASURE_NUMBER_OF_NANS) + set_meta(metadata, c + 1, "Number of NaNs", "%f", p->nb_nans); + if ((s->is_float || s->is_double) && s->measure_perchannel & MEASURE_NUMBER_OF_INFS) + set_meta(metadata, c + 1, "Number of Infs", "%f", p->nb_infs); + if ((s->is_float || s->is_double) && s->measure_perchannel & MEASURE_NUMBER_OF_DENORMALS) + set_meta(metadata, c + 1, "Number of denormals", "%f", p->nb_denormals); } - set_meta(metadata, 0, "Overall.DC_offset", "%f", max_sigma_x / (nb_samples / s->nb_channels)); - set_meta(metadata, 0, "Overall.Min_level", "%f", min); - set_meta(metadata, 0, "Overall.Max_level", "%f", max); - set_meta(metadata, 0, "Overall.Min_difference", "%f", min_diff); - set_meta(metadata, 0, "Overall.Max_difference", "%f", max_diff); - set_meta(metadata, 0, "Overall.Mean_difference", "%f", diff1_sum / (nb_samples - s->nb_channels)); - set_meta(metadata, 0, "Overall.RMS_difference", "%f", sqrt(diff1_sum_x2 / (nb_samples - s->nb_channels))); - set_meta(metadata, 0, "Overall.Peak_level", "%f", LINEAR_TO_DB(FFMAX(-nmin, nmax))); - set_meta(metadata, 0, "Overall.RMS_level", "%f", LINEAR_TO_DB(sqrt(sigma_x2 / nb_samples))); - set_meta(metadata, 0, "Overall.RMS_peak", "%f", LINEAR_TO_DB(sqrt(max_sigma_x2))); - set_meta(metadata, 0, "Overall.RMS_trough", "%f", LINEAR_TO_DB(sqrt(min_sigma_x2))); - set_meta(metadata, 0, "Overall.Flat_factor", "%f", LINEAR_TO_DB((min_runs + max_runs) / (min_count + max_count))); - set_meta(metadata, 0, "Overall.Peak_count", "%f", (float)(min_count + max_count) / (double)s->nb_channels); - bit_depth(s, mask, imask, &depth); - set_meta(metadata, 0, "Overall.Bit_depth", "%f", depth.num); - set_meta(metadata, 0, "Overall.Bit_depth2", "%f", depth.den); - set_meta(metadata, 0, "Overall.Number_of_samples", "%f", nb_samples / s->nb_channels); + if (s->measure_overall & MEASURE_DC_OFFSET) + set_meta(metadata, 0, "Overall.DC_offset", "%f", max_sigma_x / (nb_samples / s->nb_channels)); + if (s->measure_overall & MEASURE_MIN_LEVEL) + set_meta(metadata, 0, "Overall.Min_level", "%f", min); + if (s->measure_overall & MEASURE_MAX_LEVEL) + set_meta(metadata, 0, "Overall.Max_level", "%f", max); + if (s->measure_overall & MEASURE_MIN_DIFFERENCE) + set_meta(metadata, 0, "Overall.Min_difference", "%f", min_diff); + if (s->measure_overall & MEASURE_MAX_DIFFERENCE) + set_meta(metadata, 0, "Overall.Max_difference", "%f", max_diff); + if (s->measure_overall & MEASURE_MEAN_DIFFERENCE) + set_meta(metadata, 0, "Overall.Mean_difference", "%f", diff1_sum / (nb_samples - s->nb_channels)); + if (s->measure_overall & MEASURE_RMS_DIFFERENCE) + set_meta(metadata, 0, "Overall.RMS_difference", "%f", sqrt(diff1_sum_x2 / (nb_samples - s->nb_channels))); + if (s->measure_overall & MEASURE_PEAK_LEVEL) + set_meta(metadata, 0, "Overall.Peak_level", "%f", LINEAR_TO_DB(FFMAX(-nmin, nmax))); + if (s->measure_overall & MEASURE_RMS_LEVEL) + set_meta(metadata, 0, "Overall.RMS_level", "%f", LINEAR_TO_DB(sqrt(sigma_x2 / nb_samples))); + if (s->measure_overall & MEASURE_RMS_PEAK) + set_meta(metadata, 0, "Overall.RMS_peak", "%f", LINEAR_TO_DB(sqrt(max_sigma_x2))); + if (s->measure_overall & MEASURE_RMS_TROUGH) + set_meta(metadata, 0, "Overall.RMS_trough", "%f", LINEAR_TO_DB(sqrt(min_sigma_x2))); + if (s->measure_overall & MEASURE_FLAT_FACTOR) + set_meta(metadata, 0, "Overall.Flat_factor", "%f", LINEAR_TO_DB((min_runs + max_runs) / (min_count + max_count))); + if (s->measure_overall & MEASURE_PEAK_COUNT) + set_meta(metadata, 0, "Overall.Peak_count", "%f", (float)(min_count + max_count) / (double)s->nb_channels); + if (s->measure_overall & MEASURE_BIT_DEPTH) { + bit_depth(s, mask, imask, &depth); + set_meta(metadata, 0, "Overall.Bit_depth", "%f", depth.num); + set_meta(metadata, 0, "Overall.Bit_depth2", "%f", depth.den); + } + if (s->measure_overall & MEASURE_NUMBER_OF_SAMPLES) + set_meta(metadata, 0, "Overall.Number_of_samples", "%f", nb_samples / s->nb_channels); + if ((s->is_float || s->is_double) && s->measure_overall & MEASURE_NUMBER_OF_NANS) + set_meta(metadata, 0, "Number of NaNs", "%f", nb_nans / (float)s->nb_channels); + if ((s->is_float || s->is_double) && s->measure_overall & MEASURE_NUMBER_OF_INFS) + set_meta(metadata, 0, "Number of Infs", "%f", nb_infs / (float)s->nb_channels); + if ((s->is_float || s->is_double) && s->measure_overall & MEASURE_NUMBER_OF_DENORMALS) + set_meta(metadata, 0, "Number of denormals", "%f", nb_denormals / (float)s->nb_channels); } +#define UPDATE_STATS_P(type, update_func, update_float, channel_func) \ + for (int c = 0; c < channels; c++) { \ + ChannelStats *p = &s->chstats[c]; \ + const type *src = (const type *)data[c]; \ + const type * const srcend = src + samples; \ + for (; src < srcend; src++) { \ + update_func; \ + update_float; \ + } \ + channel_func; \ + } + +#define UPDATE_STATS_I(type, update_func, update_float, channel_func) \ + for (int c = 0; c < channels; c++) { \ + ChannelStats *p = &s->chstats[c]; \ + const type *src = (const type *)data[0]; \ + const type * const srcend = src + samples * channels; \ + for (src += c; src < srcend; src += channels) { \ + update_func; \ + update_float; \ + } \ + channel_func; \ + } + +#define UPDATE_STATS(planar, type, sample, normalizer_suffix, int_sample) \ + if ((s->measure_overall | s->measure_perchannel) & ~MEASURE_MINMAXPEAK) { \ + UPDATE_STATS_##planar(type, update_stat(s, p, sample, sample normalizer_suffix, int_sample), s->is_float ? update_float_stat(s, p, sample) : s->is_double ? update_double_stat(s, p, sample) : (void)NULL, ); \ + } else { \ + UPDATE_STATS_##planar(type, update_minmax(s, p, sample), , p->nmin = p->min normalizer_suffix; p->nmax = p->max normalizer_suffix;); \ + } + static int filter_frame(AVFilterLink *inlink, AVFrame *buf) { AudioStatsContext *s = inlink->dst->priv; AVDictionary **metadata = &buf->metadata; const int channels = s->nb_channels; - int i, c; + const int samples = buf->nb_samples; + const uint8_t * const * const data = (const uint8_t * const *)buf->extended_data; if (s->reset_count > 0) { if (s->nb_frames >= s->reset_count) { @@ -330,89 +522,34 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *buf) switch (inlink->format) { case AV_SAMPLE_FMT_DBLP: - for (c = 0; c < channels; c++) { - ChannelStats *p = &s->chstats[c]; - const double *src = (const double *)buf->extended_data[c]; - - for (i = 0; i < buf->nb_samples; i++, src++) - update_stat(s, p, *src, *src, llrint(*src * (UINT64_C(1) << 63))); - } + UPDATE_STATS(P, double, *src, , llrint(*src * (UINT64_C(1) << 63))); break; - case AV_SAMPLE_FMT_DBL: { - const double *src = (const double *)buf->extended_data[0]; - - for (i = 0; i < buf->nb_samples; i++) { - for (c = 0; c < channels; c++, src++) - update_stat(s, &s->chstats[c], *src, *src, llrint(*src * (UINT64_C(1) << 63))); - }} + case AV_SAMPLE_FMT_DBL: + UPDATE_STATS(I, double, *src, , llrint(*src * (UINT64_C(1) << 63))); break; case AV_SAMPLE_FMT_FLTP: - for (c = 0; c < channels; c++) { - ChannelStats *p = &s->chstats[c]; - const float *src = (const float *)buf->extended_data[c]; - - for (i = 0; i < buf->nb_samples; i++, src++) - update_stat(s, p, *src, *src, llrint(*src * (UINT64_C(1) << 31))); - } + UPDATE_STATS(P, float, *src, , llrint(*src * (UINT64_C(1) << 31))); break; - case AV_SAMPLE_FMT_FLT: { - const float *src = (const float *)buf->extended_data[0]; - - for (i = 0; i < buf->nb_samples; i++) { - for (c = 0; c < channels; c++, src++) - update_stat(s, &s->chstats[c], *src, *src, llrint(*src * (UINT64_C(1) << 31))); - }} + case AV_SAMPLE_FMT_FLT: + UPDATE_STATS(I, float, *src, , llrint(*src * (UINT64_C(1) << 31))); break; case AV_SAMPLE_FMT_S64P: - for (c = 0; c < channels; c++) { - ChannelStats *p = &s->chstats[c]; - const int64_t *src = (const int64_t *)buf->extended_data[c]; - - for (i = 0; i < buf->nb_samples; i++, src++) - update_stat(s, p, *src, *src / (double)INT64_MAX, *src); - } + UPDATE_STATS(P, int64_t, *src, / (double)INT64_MAX, *src); break; - case AV_SAMPLE_FMT_S64: { - const int64_t *src = (const int64_t *)buf->extended_data[0]; - - for (i = 0; i < buf->nb_samples; i++) { - for (c = 0; c < channels; c++, src++) - update_stat(s, &s->chstats[c], *src, *src / (double)INT64_MAX, *src); - }} + case AV_SAMPLE_FMT_S64: + UPDATE_STATS(I, int64_t, *src, / (double)INT64_MAX, *src); break; case AV_SAMPLE_FMT_S32P: - for (c = 0; c < channels; c++) { - ChannelStats *p = &s->chstats[c]; - const int32_t *src = (const int32_t *)buf->extended_data[c]; - - for (i = 0; i < buf->nb_samples; i++, src++) - update_stat(s, p, *src, *src / (double)INT32_MAX, *src); - } + UPDATE_STATS(P, int32_t, *src, / (double)INT32_MAX, *src); break; - case AV_SAMPLE_FMT_S32: { - const int32_t *src = (const int32_t *)buf->extended_data[0]; - - for (i = 0; i < buf->nb_samples; i++) { - for (c = 0; c < channels; c++, src++) - update_stat(s, &s->chstats[c], *src, *src / (double)INT32_MAX, *src); - }} + case AV_SAMPLE_FMT_S32: + UPDATE_STATS(I, int32_t, *src, / (double)INT32_MAX, *src); break; case AV_SAMPLE_FMT_S16P: - for (c = 0; c < channels; c++) { - ChannelStats *p = &s->chstats[c]; - const int16_t *src = (const int16_t *)buf->extended_data[c]; - - for (i = 0; i < buf->nb_samples; i++, src++) - update_stat(s, p, *src, *src / (double)INT16_MAX, *src); - } + UPDATE_STATS(P, int16_t, *src, / (double)INT16_MAX, *src); break; - case AV_SAMPLE_FMT_S16: { - const int16_t *src = (const int16_t *)buf->extended_data[0]; - - for (i = 0; i < buf->nb_samples; i++) { - for (c = 0; c < channels; c++, src++) - update_stat(s, &s->chstats[c], *src, *src / (double)INT16_MAX, *src); - }} + case AV_SAMPLE_FMT_S16: + UPDATE_STATS(I, int16_t, *src, / (double)INT16_MAX, *src); break; } @@ -426,16 +563,17 @@ static void print_stats(AVFilterContext *ctx) { AudioStatsContext *s = ctx->priv; uint64_t mask = 0, imask = 0xFFFFFFFFFFFFFFFF, min_count = 0, max_count = 0, nb_samples = 0; + uint64_t nb_nans = 0, nb_infs = 0, nb_denormals = 0; double min_runs = 0, max_runs = 0, - min = DBL_MAX, max = DBL_MIN, min_diff = DBL_MAX, max_diff = 0, - nmin = DBL_MAX, nmax = DBL_MIN, + min = DBL_MAX, max =-DBL_MAX, min_diff = DBL_MAX, max_diff = 0, + nmin = DBL_MAX, nmax =-DBL_MAX, max_sigma_x = 0, diff1_sum_x2 = 0, diff1_sum = 0, sigma_x = 0, sigma_x2 = 0, min_sigma_x2 = DBL_MAX, - max_sigma_x2 = DBL_MIN; + max_sigma_x2 =-DBL_MAX; AVRational depth; int c; @@ -464,48 +602,100 @@ static void print_stats(AVFilterContext *ctx) mask |= p->mask; imask &= p->imask; nb_samples += p->nb_samples; + nb_nans += p->nb_nans; + nb_infs += p->nb_infs; + nb_denormals += p->nb_denormals; if (fabs(p->sigma_x) > fabs(max_sigma_x)) max_sigma_x = p->sigma_x; av_log(ctx, AV_LOG_INFO, "Channel: %d\n", c + 1); - av_log(ctx, AV_LOG_INFO, "DC offset: %f\n", p->sigma_x / p->nb_samples); - av_log(ctx, AV_LOG_INFO, "Min level: %f\n", p->min); - av_log(ctx, AV_LOG_INFO, "Max level: %f\n", p->max); - av_log(ctx, AV_LOG_INFO, "Min difference: %f\n", p->min_diff); - av_log(ctx, AV_LOG_INFO, "Max difference: %f\n", p->max_diff); - av_log(ctx, AV_LOG_INFO, "Mean difference: %f\n", p->diff1_sum / (p->nb_samples - 1)); - av_log(ctx, AV_LOG_INFO, "RMS difference: %f\n", sqrt(p->diff1_sum_x2 / (p->nb_samples - 1))); - av_log(ctx, AV_LOG_INFO, "Peak level dB: %f\n", LINEAR_TO_DB(FFMAX(-p->nmin, p->nmax))); - av_log(ctx, AV_LOG_INFO, "RMS level dB: %f\n", LINEAR_TO_DB(sqrt(p->sigma_x2 / p->nb_samples))); - av_log(ctx, AV_LOG_INFO, "RMS peak dB: %f\n", LINEAR_TO_DB(sqrt(p->max_sigma_x2))); - if (p->min_sigma_x2 != 1) - av_log(ctx, AV_LOG_INFO, "RMS trough dB: %f\n",LINEAR_TO_DB(sqrt(p->min_sigma_x2))); - av_log(ctx, AV_LOG_INFO, "Crest factor: %f\n", p->sigma_x2 ? FFMAX(-p->nmin, p->nmax) / sqrt(p->sigma_x2 / p->nb_samples) : 1); - av_log(ctx, AV_LOG_INFO, "Flat factor: %f\n", LINEAR_TO_DB((p->min_runs + p->max_runs) / (p->min_count + p->max_count))); - av_log(ctx, AV_LOG_INFO, "Peak count: %"PRId64"\n", p->min_count + p->max_count); - bit_depth(s, p->mask, p->imask, &depth); - av_log(ctx, AV_LOG_INFO, "Bit depth: %u/%u\n", depth.num, depth.den); - av_log(ctx, AV_LOG_INFO, "Dynamic range: %f\n", LINEAR_TO_DB(2 * FFMAX(FFABS(p->min), FFABS(p->max))/ p->min_non_zero)); + if (s->measure_perchannel & MEASURE_DC_OFFSET) + av_log(ctx, AV_LOG_INFO, "DC offset: %f\n", p->sigma_x / p->nb_samples); + if (s->measure_perchannel & MEASURE_MIN_LEVEL) + av_log(ctx, AV_LOG_INFO, "Min level: %f\n", p->min); + if (s->measure_perchannel & MEASURE_MAX_LEVEL) + av_log(ctx, AV_LOG_INFO, "Max level: %f\n", p->max); + if (s->measure_perchannel & MEASURE_MIN_DIFFERENCE) + av_log(ctx, AV_LOG_INFO, "Min difference: %f\n", p->min_diff); + if (s->measure_perchannel & MEASURE_MAX_DIFFERENCE) + av_log(ctx, AV_LOG_INFO, "Max difference: %f\n", p->max_diff); + if (s->measure_perchannel & MEASURE_MEAN_DIFFERENCE) + av_log(ctx, AV_LOG_INFO, "Mean difference: %f\n", p->diff1_sum / (p->nb_samples - 1)); + if (s->measure_perchannel & MEASURE_RMS_DIFFERENCE) + av_log(ctx, AV_LOG_INFO, "RMS difference: %f\n", sqrt(p->diff1_sum_x2 / (p->nb_samples - 1))); + if (s->measure_perchannel & MEASURE_PEAK_LEVEL) + av_log(ctx, AV_LOG_INFO, "Peak level dB: %f\n", LINEAR_TO_DB(FFMAX(-p->nmin, p->nmax))); + if (s->measure_perchannel & MEASURE_RMS_LEVEL) + av_log(ctx, AV_LOG_INFO, "RMS level dB: %f\n", LINEAR_TO_DB(sqrt(p->sigma_x2 / p->nb_samples))); + if (s->measure_perchannel & MEASURE_RMS_PEAK) + av_log(ctx, AV_LOG_INFO, "RMS peak dB: %f\n", LINEAR_TO_DB(sqrt(p->max_sigma_x2))); + if (s->measure_perchannel & MEASURE_RMS_TROUGH) + if (p->min_sigma_x2 != 1) + av_log(ctx, AV_LOG_INFO, "RMS trough dB: %f\n",LINEAR_TO_DB(sqrt(p->min_sigma_x2))); + if (s->measure_perchannel & MEASURE_CREST_FACTOR) + av_log(ctx, AV_LOG_INFO, "Crest factor: %f\n", p->sigma_x2 ? FFMAX(-p->nmin, p->nmax) / sqrt(p->sigma_x2 / p->nb_samples) : 1); + if (s->measure_perchannel & MEASURE_FLAT_FACTOR) + av_log(ctx, AV_LOG_INFO, "Flat factor: %f\n", LINEAR_TO_DB((p->min_runs + p->max_runs) / (p->min_count + p->max_count))); + if (s->measure_perchannel & MEASURE_PEAK_COUNT) + av_log(ctx, AV_LOG_INFO, "Peak count: %"PRId64"\n", p->min_count + p->max_count); + if (s->measure_perchannel & MEASURE_BIT_DEPTH) { + bit_depth(s, p->mask, p->imask, &depth); + av_log(ctx, AV_LOG_INFO, "Bit depth: %u/%u\n", depth.num, depth.den); + } + if (s->measure_perchannel & MEASURE_DYNAMIC_RANGE) + av_log(ctx, AV_LOG_INFO, "Dynamic range: %f\n", LINEAR_TO_DB(2 * FFMAX(FFABS(p->min), FFABS(p->max))/ p->min_non_zero)); + if (s->measure_perchannel & MEASURE_ZERO_CROSSINGS) + av_log(ctx, AV_LOG_INFO, "Zero crossings: %"PRId64"\n", p->zero_runs); + if (s->measure_perchannel & MEASURE_ZERO_CROSSINGS_RATE) + av_log(ctx, AV_LOG_INFO, "Zero crossings rate: %f\n", p->zero_runs/(double)p->nb_samples); + if ((s->is_float || s->is_double) && s->measure_perchannel & MEASURE_NUMBER_OF_NANS) + av_log(ctx, AV_LOG_INFO, "Number of NaNs: %"PRId64"\n", p->nb_nans); + if ((s->is_float || s->is_double) && s->measure_perchannel & MEASURE_NUMBER_OF_INFS) + av_log(ctx, AV_LOG_INFO, "Number of Infs: %"PRId64"\n", p->nb_infs); + if ((s->is_float || s->is_double) && s->measure_perchannel & MEASURE_NUMBER_OF_DENORMALS) + av_log(ctx, AV_LOG_INFO, "Number of denormals: %"PRId64"\n", p->nb_denormals); } av_log(ctx, AV_LOG_INFO, "Overall\n"); - av_log(ctx, AV_LOG_INFO, "DC offset: %f\n", max_sigma_x / (nb_samples / s->nb_channels)); - av_log(ctx, AV_LOG_INFO, "Min level: %f\n", min); - av_log(ctx, AV_LOG_INFO, "Max level: %f\n", max); - av_log(ctx, AV_LOG_INFO, "Min difference: %f\n", min_diff); - av_log(ctx, AV_LOG_INFO, "Max difference: %f\n", max_diff); - av_log(ctx, AV_LOG_INFO, "Mean difference: %f\n", diff1_sum / (nb_samples - s->nb_channels)); - av_log(ctx, AV_LOG_INFO, "RMS difference: %f\n", sqrt(diff1_sum_x2 / (nb_samples - s->nb_channels))); - av_log(ctx, AV_LOG_INFO, "Peak level dB: %f\n", LINEAR_TO_DB(FFMAX(-nmin, nmax))); - av_log(ctx, AV_LOG_INFO, "RMS level dB: %f\n", LINEAR_TO_DB(sqrt(sigma_x2 / nb_samples))); - av_log(ctx, AV_LOG_INFO, "RMS peak dB: %f\n", LINEAR_TO_DB(sqrt(max_sigma_x2))); - if (min_sigma_x2 != 1) - av_log(ctx, AV_LOG_INFO, "RMS trough dB: %f\n", LINEAR_TO_DB(sqrt(min_sigma_x2))); - av_log(ctx, AV_LOG_INFO, "Flat factor: %f\n", LINEAR_TO_DB((min_runs + max_runs) / (min_count + max_count))); - av_log(ctx, AV_LOG_INFO, "Peak count: %f\n", (min_count + max_count) / (double)s->nb_channels); - bit_depth(s, mask, imask, &depth); - av_log(ctx, AV_LOG_INFO, "Bit depth: %u/%u\n", depth.num, depth.den); - av_log(ctx, AV_LOG_INFO, "Number of samples: %"PRId64"\n", nb_samples / s->nb_channels); + if (s->measure_overall & MEASURE_DC_OFFSET) + av_log(ctx, AV_LOG_INFO, "DC offset: %f\n", max_sigma_x / (nb_samples / s->nb_channels)); + if (s->measure_overall & MEASURE_MIN_LEVEL) + av_log(ctx, AV_LOG_INFO, "Min level: %f\n", min); + if (s->measure_overall & MEASURE_MAX_LEVEL) + av_log(ctx, AV_LOG_INFO, "Max level: %f\n", max); + if (s->measure_overall & MEASURE_MIN_DIFFERENCE) + av_log(ctx, AV_LOG_INFO, "Min difference: %f\n", min_diff); + if (s->measure_overall & MEASURE_MAX_DIFFERENCE) + av_log(ctx, AV_LOG_INFO, "Max difference: %f\n", max_diff); + if (s->measure_overall & MEASURE_MEAN_DIFFERENCE) + av_log(ctx, AV_LOG_INFO, "Mean difference: %f\n", diff1_sum / (nb_samples - s->nb_channels)); + if (s->measure_overall & MEASURE_RMS_DIFFERENCE) + av_log(ctx, AV_LOG_INFO, "RMS difference: %f\n", sqrt(diff1_sum_x2 / (nb_samples - s->nb_channels))); + if (s->measure_overall & MEASURE_PEAK_LEVEL) + av_log(ctx, AV_LOG_INFO, "Peak level dB: %f\n", LINEAR_TO_DB(FFMAX(-nmin, nmax))); + if (s->measure_overall & MEASURE_RMS_LEVEL) + av_log(ctx, AV_LOG_INFO, "RMS level dB: %f\n", LINEAR_TO_DB(sqrt(sigma_x2 / nb_samples))); + if (s->measure_overall & MEASURE_RMS_PEAK) + av_log(ctx, AV_LOG_INFO, "RMS peak dB: %f\n", LINEAR_TO_DB(sqrt(max_sigma_x2))); + if (s->measure_overall & MEASURE_RMS_TROUGH) + if (min_sigma_x2 != 1) + av_log(ctx, AV_LOG_INFO, "RMS trough dB: %f\n", LINEAR_TO_DB(sqrt(min_sigma_x2))); + if (s->measure_overall & MEASURE_FLAT_FACTOR) + av_log(ctx, AV_LOG_INFO, "Flat factor: %f\n", LINEAR_TO_DB((min_runs + max_runs) / (min_count + max_count))); + if (s->measure_overall & MEASURE_PEAK_COUNT) + av_log(ctx, AV_LOG_INFO, "Peak count: %f\n", (min_count + max_count) / (double)s->nb_channels); + if (s->measure_overall & MEASURE_BIT_DEPTH) { + bit_depth(s, mask, imask, &depth); + av_log(ctx, AV_LOG_INFO, "Bit depth: %u/%u\n", depth.num, depth.den); + } + if (s->measure_overall & MEASURE_NUMBER_OF_SAMPLES) + av_log(ctx, AV_LOG_INFO, "Number of samples: %"PRId64"\n", nb_samples / s->nb_channels); + if ((s->is_float || s->is_double) && s->measure_overall & MEASURE_NUMBER_OF_NANS) + av_log(ctx, AV_LOG_INFO, "Number of NaNs: %f\n", nb_nans / (float)s->nb_channels); + if ((s->is_float || s->is_double) && s->measure_overall & MEASURE_NUMBER_OF_INFS) + av_log(ctx, AV_LOG_INFO, "Number of Infs: %f\n", nb_infs / (float)s->nb_channels); + if ((s->is_float || s->is_double) && s->measure_overall & MEASURE_NUMBER_OF_DENORMALS) + av_log(ctx, AV_LOG_INFO, "Number of denormals: %f\n", nb_denormals / (float)s->nb_channels); } static av_cold void uninit(AVFilterContext *ctx) diff --git a/libavfilter/af_atempo.c b/libavfilter/af_atempo.c index 8b214bccd..688dac546 100644 --- a/libavfilter/af_atempo.c +++ b/libavfilter/af_atempo.c @@ -103,6 +103,9 @@ typedef struct ATempoContext { // 1: output sample position int64_t position[2]; + // first input timestamp, all other timestamps are offset by this one + int64_t start_pts; + // sample format: enum AVSampleFormat format; @@ -149,11 +152,16 @@ typedef struct ATempoContext { uint64_t nsamples_out; } ATempoContext; +#define YAE_ATEMPO_MIN 0.5 +#define YAE_ATEMPO_MAX 100.0 + #define OFFSET(x) offsetof(ATempoContext, x) static const AVOption atempo_options[] = { { "tempo", "set tempo scale factor", - OFFSET(tempo), AV_OPT_TYPE_DOUBLE, { .dbl = 1.0 }, 0.5, 2.0, + OFFSET(tempo), AV_OPT_TYPE_DOUBLE, { .dbl = 1.0 }, + YAE_ATEMPO_MIN, + YAE_ATEMPO_MAX, AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_FILTERING_PARAM }, { NULL } }; @@ -181,6 +189,7 @@ static void yae_clear(ATempoContext *atempo) atempo->nfrag = 0; atempo->state = YAE_LOAD_FRAGMENT; + atempo->start_pts = AV_NOPTS_VALUE; atempo->position[0] = 0; atempo->position[1] = 0; @@ -331,9 +340,9 @@ static int yae_set_tempo(AVFilterContext *ctx, const char *arg_tempo) return AVERROR(EINVAL); } - if (tempo < 0.5 || tempo > 2.0) { - av_log(ctx, AV_LOG_ERROR, "Tempo value %f exceeds [0.5, 2.0] range\n", - tempo); + if (tempo < YAE_ATEMPO_MIN || tempo > YAE_ATEMPO_MAX) { + av_log(ctx, AV_LOG_ERROR, "Tempo value %f exceeds [%f, %f] range\n", + tempo, YAE_ATEMPO_MIN, YAE_ATEMPO_MAX); return AVERROR(EINVAL); } @@ -439,8 +448,8 @@ static int yae_load_data(ATempoContext *atempo, return 0; } - // samples are not expected to be skipped: - av_assert0(read_size <= atempo->ring); + // samples are not expected to be skipped, unless tempo is greater than 2: + av_assert0(read_size <= atempo->ring || atempo->tempo > 2.0); while (atempo->position[0] < stop_here && src < src_end) { int src_samples = (src_end - src) / atempo->stride; @@ -1063,7 +1072,7 @@ static int push_samples(ATempoContext *atempo, atempo->dst_buffer->nb_samples = n_out; // adjust the PTS: - atempo->dst_buffer->pts = + atempo->dst_buffer->pts = atempo->start_pts + av_rescale_q(atempo->nsamples_out, (AVRational){ 1, outlink->sample_rate }, outlink->time_base); @@ -1092,6 +1101,11 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *src_buffer) const uint8_t *src = src_buffer->data[0]; const uint8_t *src_end = src + n_in * atempo->stride; + if (atempo->start_pts == AV_NOPTS_VALUE) + atempo->start_pts = av_rescale_q(src_buffer->pts, + inlink->time_base, + outlink->time_base); + while (src < src_end) { if (!atempo->dst_buffer) { atempo->dst_buffer = ff_get_audio_buffer(outlink, n_out); diff --git a/libavfilter/af_biquads.c b/libavfilter/af_biquads.c index d5c3823e6..247a47256 100644 --- a/libavfilter/af_biquads.c +++ b/libavfilter/af_biquads.c @@ -63,6 +63,7 @@ */ #include "libavutil/avassert.h" +#include "libavutil/ffmath.h" #include "libavutil/opt.h" #include "audio.h" #include "avfilter.h" @@ -78,6 +79,8 @@ enum FilterType { allpass, highpass, lowpass, + lowshelf, + highshelf, }; enum WidthType { @@ -93,6 +96,7 @@ enum WidthType { typedef struct ChanCache { double i1, i2; double o1, o2; + int clippings; } ChanCache; typedef struct BiquadsContext { @@ -106,18 +110,19 @@ typedef struct BiquadsContext { double gain; double frequency; double width; + double mix; uint64_t channels; double a0, a1, a2; double b0, b1, b2; ChanCache *cache; - int clippings; int block_align; void (*filter)(struct BiquadsContext *s, const void *ibuf, void *obuf, int len, double *i1, double *i2, double *o1, double *o2, - double b0, double b1, double b2, double a1, double a2); + double b0, double b1, double b2, double a1, double a2, int *clippings, + int disabled); } BiquadsContext; static av_cold int init(AVFilterContext *ctx) @@ -174,7 +179,8 @@ static void biquad_## name (BiquadsContext *s, \ double *in1, double *in2, \ double *out1, double *out2, \ double b0, double b1, double b2, \ - double a1, double a2) \ + double a1, double a2, int *clippings, \ + int disabled) \ { \ const type *ibuf = input; \ type *obuf = output; \ @@ -182,6 +188,9 @@ static void biquad_## name (BiquadsContext *s, \ double i2 = *in2; \ double o1 = *out1; \ double o2 = *out2; \ + double wet = s->mix; \ + double dry = 1. - wet; \ + double out; \ int i; \ a1 = -a1; \ a2 = -a2; \ @@ -189,26 +198,32 @@ static void biquad_## name (BiquadsContext *s, \ for (i = 0; i+1 < len; i++) { \ o2 = i2 * b2 + i1 * b1 + ibuf[i] * b0 + o2 * a2 + o1 * a1; \ i2 = ibuf[i]; \ - if (need_clipping && o2 < min) { \ - s->clippings++; \ + out = o2 * wet + i2 * dry; \ + if (disabled) { \ + obuf[i] = i2; \ + } else if (need_clipping && out < min) { \ + (*clippings)++; \ obuf[i] = min; \ - } else if (need_clipping && o2 > max) { \ - s->clippings++; \ + } else if (need_clipping && out > max) { \ + (*clippings)++; \ obuf[i] = max; \ } else { \ - obuf[i] = o2; \ + obuf[i] = out; \ } \ i++; \ o1 = i1 * b2 + i2 * b1 + ibuf[i] * b0 + o1 * a2 + o2 * a1; \ i1 = ibuf[i]; \ - if (need_clipping && o1 < min) { \ - s->clippings++; \ + out = o1 * wet + i1 * dry; \ + if (disabled) { \ + obuf[i] = i1; \ + } else if (need_clipping && out < min) { \ + (*clippings)++; \ obuf[i] = min; \ - } else if (need_clipping && o1 > max) { \ - s->clippings++; \ + } else if (need_clipping && out > max) { \ + (*clippings)++; \ obuf[i] = max; \ } else { \ - obuf[i] = o1; \ + obuf[i] = out; \ } \ } \ if (i < len) { \ @@ -217,14 +232,17 @@ static void biquad_## name (BiquadsContext *s, \ i1 = ibuf[i]; \ o2 = o1; \ o1 = o0; \ - if (need_clipping && o0 < min) { \ - s->clippings++; \ + out = o0 * wet + i1 * dry; \ + if (disabled) { \ + obuf[i] = i1; \ + } else if (need_clipping && out < min) { \ + (*clippings)++; \ obuf[i] = min; \ - } else if (need_clipping && o0 > max) { \ - s->clippings++; \ + } else if (need_clipping && out > max) { \ + (*clippings)++; \ obuf[i] = max; \ } else { \ - obuf[i] = o0; \ + obuf[i] = out; \ } \ } \ *in1 = i1; \ @@ -243,9 +261,9 @@ static int config_filter(AVFilterLink *outlink, int reset) AVFilterContext *ctx = outlink->src; BiquadsContext *s = ctx->priv; AVFilterLink *inlink = ctx->inputs[0]; - double A = exp(s->gain / 40 * log(10.)); + double A = ff_exp10(s->gain / 40); double w0 = 2 * M_PI * s->frequency / inlink->sample_rate; - double alpha; + double alpha, beta; if (w0 > M_PI) { av_log(ctx, AV_LOG_ERROR, @@ -277,6 +295,8 @@ static int config_filter(AVFilterLink *outlink, int reset) av_assert0(0); } + beta = 2 * sqrt(A); + switch (s->filter_type) { case biquad: break; @@ -289,20 +309,24 @@ static int config_filter(AVFilterLink *outlink, int reset) s->b2 = 1 - alpha * A; break; case bass: - s->a0 = (A + 1) + (A - 1) * cos(w0) + 2 * sqrt(A) * alpha; + beta = sqrt((A * A + 1) - (A - 1) * (A - 1)); + case lowshelf: + s->a0 = (A + 1) + (A - 1) * cos(w0) + beta * alpha; s->a1 = -2 * ((A - 1) + (A + 1) * cos(w0)); - s->a2 = (A + 1) + (A - 1) * cos(w0) - 2 * sqrt(A) * alpha; - s->b0 = A * ((A + 1) - (A - 1) * cos(w0) + 2 * sqrt(A) * alpha); + s->a2 = (A + 1) + (A - 1) * cos(w0) - beta * alpha; + s->b0 = A * ((A + 1) - (A - 1) * cos(w0) + beta * alpha); s->b1 = 2 * A * ((A - 1) - (A + 1) * cos(w0)); - s->b2 = A * ((A + 1) - (A - 1) * cos(w0) - 2 * sqrt(A) * alpha); + s->b2 = A * ((A + 1) - (A - 1) * cos(w0) - beta * alpha); break; case treble: - s->a0 = (A + 1) - (A - 1) * cos(w0) + 2 * sqrt(A) * alpha; + beta = sqrt((A * A + 1) - (A - 1) * (A - 1)); + case highshelf: + s->a0 = (A + 1) - (A - 1) * cos(w0) + beta * alpha; s->a1 = 2 * ((A - 1) - (A + 1) * cos(w0)); - s->a2 = (A + 1) - (A - 1) * cos(w0) - 2 * sqrt(A) * alpha; - s->b0 = A * ((A + 1) + (A - 1) * cos(w0) + 2 * sqrt(A) * alpha); + s->a2 = (A + 1) - (A - 1) * cos(w0) - beta * alpha; + s->b0 = A * ((A + 1) + (A - 1) * cos(w0) + beta * alpha); s->b1 =-2 * A * ((A - 1) + (A + 1) * cos(w0)); - s->b2 = A * ((A + 1) + (A - 1) * cos(w0) - 2 * sqrt(A) * alpha); + s->b2 = A * ((A + 1) + (A - 1) * cos(w0) - beta * alpha); break; case bandpass: if (s->csg) { @@ -375,7 +399,7 @@ static int config_filter(AVFilterLink *outlink, int reset) av_assert0(0); } - av_log(ctx, AV_LOG_VERBOSE, "a=%lf %lf %lf:b=%lf %lf %lf\n", s->a0, s->a1, s->a2, s->b0, s->b1, s->b2); + av_log(ctx, AV_LOG_VERBOSE, "a=%f %f %f:b=%f %f %f\n", s->a0, s->a1, s->a2, s->b0, s->b1, s->b2); s->a1 /= s->a0; s->a2 /= s->a0; @@ -408,19 +432,50 @@ static int config_output(AVFilterLink *outlink) return config_filter(outlink, 1); } +typedef struct ThreadData { + AVFrame *in, *out; +} ThreadData; + +static int filter_channel(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) +{ + AVFilterLink *inlink = ctx->inputs[0]; + ThreadData *td = arg; + AVFrame *buf = td->in; + AVFrame *out_buf = td->out; + BiquadsContext *s = ctx->priv; + const int start = (buf->channels * jobnr) / nb_jobs; + const int end = (buf->channels * (jobnr+1)) / nb_jobs; + int ch; + + for (ch = start; ch < end; ch++) { + if (!((av_channel_layout_extract_channel(inlink->channel_layout, ch) & s->channels))) { + if (buf != out_buf) + memcpy(out_buf->extended_data[ch], buf->extended_data[ch], + buf->nb_samples * s->block_align); + continue; + } + + s->filter(s, buf->extended_data[ch], out_buf->extended_data[ch], buf->nb_samples, + &s->cache[ch].i1, &s->cache[ch].i2, &s->cache[ch].o1, &s->cache[ch].o2, + s->b0, s->b1, s->b2, s->a1, s->a2, &s->cache[ch].clippings, ctx->is_disabled); + } + + return 0; +} + static int filter_frame(AVFilterLink *inlink, AVFrame *buf) { AVFilterContext *ctx = inlink->dst; BiquadsContext *s = ctx->priv; AVFilterLink *outlink = ctx->outputs[0]; AVFrame *out_buf; - int nb_samples = buf->nb_samples; + ThreadData td; int ch; if (av_frame_is_writable(buf)) { out_buf = buf; } else { - out_buf = ff_get_audio_buffer(outlink, nb_samples); + out_buf = ff_get_audio_buffer(outlink, buf->nb_samples); if (!out_buf) { av_frame_free(&buf); return AVERROR(ENOMEM); @@ -428,22 +483,16 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *buf) av_frame_copy_props(out_buf, buf); } - for (ch = 0; ch < buf->channels; ch++) { - if (!((av_channel_layout_extract_channel(inlink->channel_layout, ch) & s->channels))) { - if (buf != out_buf) - memcpy(out_buf->extended_data[ch], buf->extended_data[ch], nb_samples * s->block_align); - continue; - } - s->filter(s, buf->extended_data[ch], - out_buf->extended_data[ch], nb_samples, - &s->cache[ch].i1, &s->cache[ch].i2, - &s->cache[ch].o1, &s->cache[ch].o2, - s->b0, s->b1, s->b2, s->a1, s->a2); - } + td.in = buf; + td.out = out_buf; + ctx->internal->execute(ctx, filter_channel, &td, NULL, FFMIN(outlink->channels, ff_filter_get_nb_threads(ctx))); - if (s->clippings > 0) - av_log(ctx, AV_LOG_WARNING, "clipping %d times. Please reduce gain.\n", s->clippings); - s->clippings = 0; + for (ch = 0; ch < outlink->channels; ch++) { + if (s->cache[ch].clippings > 0) + av_log(ctx, AV_LOG_WARNING, "Channel %d clipping %d times. Please reduce gain.\n", + ch, s->cache[ch].clippings); + s->cache[ch].clippings = 0; + } if (buf != out_buf) av_frame_free(&buf); @@ -459,6 +508,8 @@ static int process_command(AVFilterContext *ctx, const char *cmd, const char *ar if ((!strcmp(cmd, "frequency") || !strcmp(cmd, "f")) && (s->filter_type == equalizer || + s->filter_type == lowshelf || + s->filter_type == highshelf || s->filter_type == bass || s->filter_type == treble || s->filter_type == bandpass || @@ -476,6 +527,8 @@ static int process_command(AVFilterContext *ctx, const char *cmd, const char *ar s->frequency = freq; } else if ((!strcmp(cmd, "gain") || !strcmp(cmd, "g")) && (s->filter_type == equalizer || + s->filter_type == lowshelf || + s->filter_type == highshelf || s->filter_type == bass || s->filter_type == treble)) { double gain; @@ -485,9 +538,20 @@ static int process_command(AVFilterContext *ctx, const char *cmd, const char *ar return AVERROR(EINVAL); } - s->gain = gain; + s->gain = av_clipd(gain, -900, 900); + } else if (!strcmp(cmd, "mix") || !strcmp(cmd, "m")) { + double mix; + + if (sscanf(args, "%lf", &mix) != 1) { + av_log(ctx, AV_LOG_ERROR, "Invalid mix value.\n"); + return AVERROR(EINVAL); + } + + s->mix = av_clipd(mix, 0, 1); } else if ((!strcmp(cmd, "width") || !strcmp(cmd, "w")) && (s->filter_type == equalizer || + s->filter_type == lowshelf || + s->filter_type == highshelf || s->filter_type == bass || s->filter_type == treble || s->filter_type == bandpass || @@ -505,6 +569,8 @@ static int process_command(AVFilterContext *ctx, const char *cmd, const char *ar s->width = width; } else if ((!strcmp(cmd, "width_type") || !strcmp(cmd, "t")) && (s->filter_type == equalizer || + s->filter_type == lowshelf || + s->filter_type == highshelf || s->filter_type == bass || s->filter_type == treble || s->filter_type == bandpass || @@ -611,6 +677,7 @@ AVFilter ff_af_##name_ = { \ .outputs = outputs, \ .priv_class = &name_##_class, \ .process_command = process_command, \ + .flags = AVFILTER_FLAG_SLICE_THREADS | AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, \ } #if CONFIG_EQUALIZER_FILTER @@ -628,6 +695,8 @@ static const AVOption equalizer_options[] = { {"w", "set band-width", OFFSET(width), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 99999, FLAGS}, {"gain", "set gain", OFFSET(gain), AV_OPT_TYPE_DOUBLE, {.dbl=0}, -900, 900, FLAGS}, {"g", "set gain", OFFSET(gain), AV_OPT_TYPE_DOUBLE, {.dbl=0}, -900, 900, FLAGS}, + {"mix", "set mix", OFFSET(mix), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 1, FLAGS}, + {"m", "set mix", OFFSET(mix), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 1, FLAGS}, {"channels", "set channels to filter", OFFSET(channels), AV_OPT_TYPE_CHANNEL_LAYOUT, {.i64=-1}, INT64_MIN, INT64_MAX, FLAGS}, {"c", "set channels to filter", OFFSET(channels), AV_OPT_TYPE_CHANNEL_LAYOUT, {.i64=-1}, INT64_MIN, INT64_MAX, FLAGS}, {NULL} @@ -650,6 +719,8 @@ static const AVOption bass_options[] = { {"w", "set shelf transition steep", OFFSET(width), AV_OPT_TYPE_DOUBLE, {.dbl=0.5}, 0, 99999, FLAGS}, {"gain", "set gain", OFFSET(gain), AV_OPT_TYPE_DOUBLE, {.dbl=0}, -900, 900, FLAGS}, {"g", "set gain", OFFSET(gain), AV_OPT_TYPE_DOUBLE, {.dbl=0}, -900, 900, FLAGS}, + {"mix", "set mix", OFFSET(mix), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 1, FLAGS}, + {"m", "set mix", OFFSET(mix), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 1, FLAGS}, {"channels", "set channels to filter", OFFSET(channels), AV_OPT_TYPE_CHANNEL_LAYOUT, {.i64=-1}, INT64_MIN, INT64_MAX, FLAGS}, {"c", "set channels to filter", OFFSET(channels), AV_OPT_TYPE_CHANNEL_LAYOUT, {.i64=-1}, INT64_MIN, INT64_MAX, FLAGS}, {NULL} @@ -672,6 +743,8 @@ static const AVOption treble_options[] = { {"w", "set shelf transition steep", OFFSET(width), AV_OPT_TYPE_DOUBLE, {.dbl=0.5}, 0, 99999, FLAGS}, {"gain", "set gain", OFFSET(gain), AV_OPT_TYPE_DOUBLE, {.dbl=0}, -900, 900, FLAGS}, {"g", "set gain", OFFSET(gain), AV_OPT_TYPE_DOUBLE, {.dbl=0}, -900, 900, FLAGS}, + {"mix", "set mix", OFFSET(mix), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 1, FLAGS}, + {"m", "set mix", OFFSET(mix), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 1, FLAGS}, {"channels", "set channels to filter", OFFSET(channels), AV_OPT_TYPE_CHANNEL_LAYOUT, {.i64=-1}, INT64_MIN, INT64_MAX, FLAGS}, {"c", "set channels to filter", OFFSET(channels), AV_OPT_TYPE_CHANNEL_LAYOUT, {.i64=-1}, INT64_MIN, INT64_MAX, FLAGS}, {NULL} @@ -693,6 +766,8 @@ static const AVOption bandpass_options[] = { {"width", "set band-width", OFFSET(width), AV_OPT_TYPE_DOUBLE, {.dbl=0.5}, 0, 99999, FLAGS}, {"w", "set band-width", OFFSET(width), AV_OPT_TYPE_DOUBLE, {.dbl=0.5}, 0, 99999, FLAGS}, {"csg", "use constant skirt gain", OFFSET(csg), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS}, + {"mix", "set mix", OFFSET(mix), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 1, FLAGS}, + {"m", "set mix", OFFSET(mix), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 1, FLAGS}, {"channels", "set channels to filter", OFFSET(channels), AV_OPT_TYPE_CHANNEL_LAYOUT, {.i64=-1}, INT64_MIN, INT64_MAX, FLAGS}, {"c", "set channels to filter", OFFSET(channels), AV_OPT_TYPE_CHANNEL_LAYOUT, {.i64=-1}, INT64_MIN, INT64_MAX, FLAGS}, {NULL} @@ -713,6 +788,8 @@ static const AVOption bandreject_options[] = { {"k", "kHz", 0, AV_OPT_TYPE_CONST, {.i64=KHERTZ}, 0, 0, FLAGS, "width_type"}, {"width", "set band-width", OFFSET(width), AV_OPT_TYPE_DOUBLE, {.dbl=0.5}, 0, 99999, FLAGS}, {"w", "set band-width", OFFSET(width), AV_OPT_TYPE_DOUBLE, {.dbl=0.5}, 0, 99999, FLAGS}, + {"mix", "set mix", OFFSET(mix), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 1, FLAGS}, + {"m", "set mix", OFFSET(mix), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 1, FLAGS}, {"channels", "set channels to filter", OFFSET(channels), AV_OPT_TYPE_CHANNEL_LAYOUT, {.i64=-1}, INT64_MIN, INT64_MAX, FLAGS}, {"c", "set channels to filter", OFFSET(channels), AV_OPT_TYPE_CHANNEL_LAYOUT, {.i64=-1}, INT64_MIN, INT64_MAX, FLAGS}, {NULL} @@ -735,6 +812,8 @@ static const AVOption lowpass_options[] = { {"w", "set width", OFFSET(width), AV_OPT_TYPE_DOUBLE, {.dbl=0.707}, 0, 99999, FLAGS}, {"poles", "set number of poles", OFFSET(poles), AV_OPT_TYPE_INT, {.i64=2}, 1, 2, FLAGS}, {"p", "set number of poles", OFFSET(poles), AV_OPT_TYPE_INT, {.i64=2}, 1, 2, FLAGS}, + {"mix", "set mix", OFFSET(mix), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 1, FLAGS}, + {"m", "set mix", OFFSET(mix), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 1, FLAGS}, {"channels", "set channels to filter", OFFSET(channels), AV_OPT_TYPE_CHANNEL_LAYOUT, {.i64=-1}, INT64_MIN, INT64_MAX, FLAGS}, {"c", "set channels to filter", OFFSET(channels), AV_OPT_TYPE_CHANNEL_LAYOUT, {.i64=-1}, INT64_MIN, INT64_MAX, FLAGS}, {NULL} @@ -757,6 +836,8 @@ static const AVOption highpass_options[] = { {"w", "set width", OFFSET(width), AV_OPT_TYPE_DOUBLE, {.dbl=0.707}, 0, 99999, FLAGS}, {"poles", "set number of poles", OFFSET(poles), AV_OPT_TYPE_INT, {.i64=2}, 1, 2, FLAGS}, {"p", "set number of poles", OFFSET(poles), AV_OPT_TYPE_INT, {.i64=2}, 1, 2, FLAGS}, + {"mix", "set mix", OFFSET(mix), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 1, FLAGS}, + {"m", "set mix", OFFSET(mix), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 1, FLAGS}, {"channels", "set channels to filter", OFFSET(channels), AV_OPT_TYPE_CHANNEL_LAYOUT, {.i64=-1}, INT64_MIN, INT64_MAX, FLAGS}, {"c", "set channels to filter", OFFSET(channels), AV_OPT_TYPE_CHANNEL_LAYOUT, {.i64=-1}, INT64_MIN, INT64_MAX, FLAGS}, {NULL} @@ -777,6 +858,8 @@ static const AVOption allpass_options[] = { {"k", "kHz", 0, AV_OPT_TYPE_CONST, {.i64=KHERTZ}, 0, 0, FLAGS, "width_type"}, {"width", "set filter-width", OFFSET(width), AV_OPT_TYPE_DOUBLE, {.dbl=707.1}, 0, 99999, FLAGS}, {"w", "set filter-width", OFFSET(width), AV_OPT_TYPE_DOUBLE, {.dbl=707.1}, 0, 99999, FLAGS}, + {"mix", "set mix", OFFSET(mix), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 1, FLAGS}, + {"m", "set mix", OFFSET(mix), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 1, FLAGS}, {"channels", "set channels to filter", OFFSET(channels), AV_OPT_TYPE_CHANNEL_LAYOUT, {.i64=-1}, INT64_MIN, INT64_MAX, FLAGS}, {"c", "set channels to filter", OFFSET(channels), AV_OPT_TYPE_CHANNEL_LAYOUT, {.i64=-1}, INT64_MIN, INT64_MAX, FLAGS}, {NULL} @@ -784,6 +867,54 @@ static const AVOption allpass_options[] = { DEFINE_BIQUAD_FILTER(allpass, "Apply a two-pole all-pass filter."); #endif /* CONFIG_ALLPASS_FILTER */ +#if CONFIG_LOWSHELF_FILTER +static const AVOption lowshelf_options[] = { + {"frequency", "set central frequency", OFFSET(frequency), AV_OPT_TYPE_DOUBLE, {.dbl=100}, 0, 999999, FLAGS}, + {"f", "set central frequency", OFFSET(frequency), AV_OPT_TYPE_DOUBLE, {.dbl=100}, 0, 999999, FLAGS}, + {"width_type", "set filter-width type", OFFSET(width_type), AV_OPT_TYPE_INT, {.i64=QFACTOR}, HERTZ, NB_WTYPE-1, FLAGS, "width_type"}, + {"t", "set filter-width type", OFFSET(width_type), AV_OPT_TYPE_INT, {.i64=QFACTOR}, HERTZ, NB_WTYPE-1, FLAGS, "width_type"}, + {"h", "Hz", 0, AV_OPT_TYPE_CONST, {.i64=HERTZ}, 0, 0, FLAGS, "width_type"}, + {"q", "Q-Factor", 0, AV_OPT_TYPE_CONST, {.i64=QFACTOR}, 0, 0, FLAGS, "width_type"}, + {"o", "octave", 0, AV_OPT_TYPE_CONST, {.i64=OCTAVE}, 0, 0, FLAGS, "width_type"}, + {"s", "slope", 0, AV_OPT_TYPE_CONST, {.i64=SLOPE}, 0, 0, FLAGS, "width_type"}, + {"k", "kHz", 0, AV_OPT_TYPE_CONST, {.i64=KHERTZ}, 0, 0, FLAGS, "width_type"}, + {"width", "set shelf transition steep", OFFSET(width), AV_OPT_TYPE_DOUBLE, {.dbl=0.5}, 0, 99999, FLAGS}, + {"w", "set shelf transition steep", OFFSET(width), AV_OPT_TYPE_DOUBLE, {.dbl=0.5}, 0, 99999, FLAGS}, + {"gain", "set gain", OFFSET(gain), AV_OPT_TYPE_DOUBLE, {.dbl=0}, -900, 900, FLAGS}, + {"g", "set gain", OFFSET(gain), AV_OPT_TYPE_DOUBLE, {.dbl=0}, -900, 900, FLAGS}, + {"mix", "set mix", OFFSET(mix), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 1, FLAGS}, + {"m", "set mix", OFFSET(mix), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 1, FLAGS}, + {"channels", "set channels to filter", OFFSET(channels), AV_OPT_TYPE_CHANNEL_LAYOUT, {.i64=-1}, INT64_MIN, INT64_MAX, FLAGS}, + {"c", "set channels to filter", OFFSET(channels), AV_OPT_TYPE_CHANNEL_LAYOUT, {.i64=-1}, INT64_MIN, INT64_MAX, FLAGS}, + {NULL} +}; + +DEFINE_BIQUAD_FILTER(lowshelf, "Apply a low shelf filter."); +#endif /* CONFIG_LOWSHELF_FILTER */ +#if CONFIG_HIGHSHELF_FILTER +static const AVOption highshelf_options[] = { + {"frequency", "set central frequency", OFFSET(frequency), AV_OPT_TYPE_DOUBLE, {.dbl=3000}, 0, 999999, FLAGS}, + {"f", "set central frequency", OFFSET(frequency), AV_OPT_TYPE_DOUBLE, {.dbl=3000}, 0, 999999, FLAGS}, + {"width_type", "set filter-width type", OFFSET(width_type), AV_OPT_TYPE_INT, {.i64=QFACTOR}, HERTZ, NB_WTYPE-1, FLAGS, "width_type"}, + {"t", "set filter-width type", OFFSET(width_type), AV_OPT_TYPE_INT, {.i64=QFACTOR}, HERTZ, NB_WTYPE-1, FLAGS, "width_type"}, + {"h", "Hz", 0, AV_OPT_TYPE_CONST, {.i64=HERTZ}, 0, 0, FLAGS, "width_type"}, + {"q", "Q-Factor", 0, AV_OPT_TYPE_CONST, {.i64=QFACTOR}, 0, 0, FLAGS, "width_type"}, + {"o", "octave", 0, AV_OPT_TYPE_CONST, {.i64=OCTAVE}, 0, 0, FLAGS, "width_type"}, + {"s", "slope", 0, AV_OPT_TYPE_CONST, {.i64=SLOPE}, 0, 0, FLAGS, "width_type"}, + {"k", "kHz", 0, AV_OPT_TYPE_CONST, {.i64=KHERTZ}, 0, 0, FLAGS, "width_type"}, + {"width", "set shelf transition steep", OFFSET(width), AV_OPT_TYPE_DOUBLE, {.dbl=0.5}, 0, 99999, FLAGS}, + {"w", "set shelf transition steep", OFFSET(width), AV_OPT_TYPE_DOUBLE, {.dbl=0.5}, 0, 99999, FLAGS}, + {"gain", "set gain", OFFSET(gain), AV_OPT_TYPE_DOUBLE, {.dbl=0}, -900, 900, FLAGS}, + {"g", "set gain", OFFSET(gain), AV_OPT_TYPE_DOUBLE, {.dbl=0}, -900, 900, FLAGS}, + {"mix", "set mix", OFFSET(mix), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 1, FLAGS}, + {"m", "set mix", OFFSET(mix), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 1, FLAGS}, + {"channels", "set channels to filter", OFFSET(channels), AV_OPT_TYPE_CHANNEL_LAYOUT, {.i64=-1}, INT64_MIN, INT64_MAX, FLAGS}, + {"c", "set channels to filter", OFFSET(channels), AV_OPT_TYPE_CHANNEL_LAYOUT, {.i64=-1}, INT64_MIN, INT64_MAX, FLAGS}, + {NULL} +}; + +DEFINE_BIQUAD_FILTER(highshelf, "Apply a high shelf filter."); +#endif /* CONFIG_HIGHSHELF_FILTER */ #if CONFIG_BIQUAD_FILTER static const AVOption biquad_options[] = { {"a0", NULL, OFFSET(a0), AV_OPT_TYPE_DOUBLE, {.dbl=1}, INT32_MIN, INT32_MAX, FLAGS}, @@ -792,6 +923,8 @@ static const AVOption biquad_options[] = { {"b0", NULL, OFFSET(b0), AV_OPT_TYPE_DOUBLE, {.dbl=0}, INT32_MIN, INT32_MAX, FLAGS}, {"b1", NULL, OFFSET(b1), AV_OPT_TYPE_DOUBLE, {.dbl=0}, INT32_MIN, INT32_MAX, FLAGS}, {"b2", NULL, OFFSET(b2), AV_OPT_TYPE_DOUBLE, {.dbl=0}, INT32_MIN, INT32_MAX, FLAGS}, + {"mix", "set mix", OFFSET(mix), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 1, FLAGS}, + {"m", "set mix", OFFSET(mix), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 1, FLAGS}, {"channels", "set channels to filter", OFFSET(channels), AV_OPT_TYPE_CHANNEL_LAYOUT, {.i64=-1}, INT64_MIN, INT64_MAX, FLAGS}, {"c", "set channels to filter", OFFSET(channels), AV_OPT_TYPE_CHANNEL_LAYOUT, {.i64=-1}, INT64_MIN, INT64_MAX, FLAGS}, {NULL} diff --git a/libavfilter/af_crossfeed.c b/libavfilter/af_crossfeed.c index a0af28043..c819ca59a 100644 --- a/libavfilter/af_crossfeed.c +++ b/libavfilter/af_crossfeed.c @@ -17,6 +17,7 @@ */ #include "libavutil/channel_layout.h" +#include "libavutil/ffmath.h" #include "libavutil/opt.h" #include "avfilter.h" #include "audio.h" @@ -57,7 +58,7 @@ static int config_input(AVFilterLink *inlink) { AVFilterContext *ctx = inlink->dst; CrossfeedContext *s = ctx->priv; - double A = exp(s->strength * -30 / 40 * log(10.)); + double A = ff_exp10(s->strength * -30 / 40); double w0 = 2 * M_PI * (1. - s->range) * 2100 / inlink->sample_rate; double alpha; @@ -118,8 +119,13 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) s->o2 = s->o1; s->o1 = oside; - dst[0] = (mid + oside) * level_out; - dst[1] = (mid - oside) * level_out; + if (ctx->is_disabled) { + dst[0] = src[0]; + dst[1] = src[1]; + } else { + dst[0] = (mid + oside) * level_out; + dst[1] = (mid - oside) * level_out; + } } if (out != in) @@ -166,4 +172,5 @@ AVFilter ff_af_crossfeed = { .priv_class = &crossfeed_class, .inputs = inputs, .outputs = outputs, + .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, }; diff --git a/libavfilter/af_deesser.c b/libavfilter/af_deesser.c new file mode 100644 index 000000000..fad3e98f5 --- /dev/null +++ b/libavfilter/af_deesser.c @@ -0,0 +1,244 @@ +/* + * Copyright (c) 2018 Chris Johnson + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "libavutil/channel_layout.h" +#include "libavutil/opt.h" +#include "avfilter.h" +#include "audio.h" +#include "formats.h" + +typedef struct DeesserChannel { + double s1, s2, s3; + double m1, m2; + double ratioA, ratioB; + double iirSampleA, iirSampleB; + int flip; +} DeesserChannel; + +typedef struct DeesserContext { + const AVClass *class; + + double intensity; + double max; + double frequency; + int mode; + + DeesserChannel *chan; +} DeesserContext; + +enum OutModes { + IN_MODE, + OUT_MODE, + ESS_MODE, + NB_MODES +}; + +#define OFFSET(x) offsetof(DeesserContext, x) +#define A AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM + +static const AVOption deesser_options[] = { + { "i", "set intensity", OFFSET(intensity), AV_OPT_TYPE_DOUBLE, {.dbl=0.0}, 0.0, 1.0, A }, + { "m", "set max deessing", OFFSET(max), AV_OPT_TYPE_DOUBLE, {.dbl=0.5}, 0.0, 1.0, A }, + { "f", "set frequency", OFFSET(frequency), AV_OPT_TYPE_DOUBLE, {.dbl=0.5}, 0.0, 1.0, A }, + { "s", "set output mode", OFFSET(mode), AV_OPT_TYPE_INT, {.i64=OUT_MODE}, 0, NB_MODES-1, A, "mode" }, + { "i", "input", 0, AV_OPT_TYPE_CONST, {.i64=IN_MODE}, 0, 0, A, "mode" }, + { "o", "output", 0, AV_OPT_TYPE_CONST, {.i64=OUT_MODE}, 0, 0, A, "mode" }, + { "e", "ess", 0, AV_OPT_TYPE_CONST, {.i64=ESS_MODE}, 0, 0, A, "mode" }, + { NULL } +}; + +AVFILTER_DEFINE_CLASS(deesser); + +static int query_formats(AVFilterContext *ctx) +{ + AVFilterFormats *formats = NULL; + AVFilterChannelLayouts *layouts = NULL; + static const enum AVSampleFormat sample_fmts[] = { + AV_SAMPLE_FMT_DBLP, + AV_SAMPLE_FMT_NONE + }; + int ret; + + formats = ff_make_format_list(sample_fmts); + if (!formats) + return AVERROR(ENOMEM); + ret = ff_set_common_formats(ctx, formats); + if (ret < 0) + return ret; + + layouts = ff_all_channel_counts(); + if (!layouts) + return AVERROR(ENOMEM); + + ret = ff_set_common_channel_layouts(ctx, layouts); + if (ret < 0) + return ret; + + formats = ff_all_samplerates(); + return ff_set_common_samplerates(ctx, formats); +} + +static int config_input(AVFilterLink *inlink) +{ + AVFilterContext *ctx = inlink->dst; + DeesserContext *s = ctx->priv; + + s->chan = av_calloc(inlink->channels, sizeof(*s->chan)); + if (!s->chan) + return AVERROR(ENOMEM); + + for (int i = 0; i < inlink->channels; i++) { + DeesserChannel *chan = &s->chan[i]; + + chan->ratioA = chan->ratioB = 1.0; + } + + return 0; +} + +static int filter_frame(AVFilterLink *inlink, AVFrame *in) +{ + AVFilterContext *ctx = inlink->dst; + AVFilterLink *outlink = ctx->outputs[0]; + DeesserContext *s = ctx->priv; + AVFrame *out; + + if (av_frame_is_writable(in)) { + out = in; + } else { + out = ff_get_audio_buffer(outlink, in->nb_samples); + if (!out) { + av_frame_free(&in); + return AVERROR(ENOMEM); + } + av_frame_copy_props(out, in); + } + + for (int ch = 0; ch < inlink->channels; ch++) { + DeesserChannel *dec = &s->chan[ch]; + double *src = (double *)in->extended_data[ch]; + double *dst = (double *)out->extended_data[ch]; + double overallscale = inlink->sample_rate < 44100 ? 44100.0 / inlink->sample_rate : inlink->sample_rate / 44100.0; + double intensity = pow(s->intensity, 5) * (8192 / overallscale); + double maxdess = 1.0 / pow(10.0, ((s->max - 1.0) * 48.0) / 20); + double iirAmount = pow(s->frequency, 2) / overallscale; + double offset; + double sense; + double recovery; + double attackspeed; + + for (int i = 0; i < in->nb_samples; i++) { + double sample = src[i]; + + dec->s3 = dec->s2; + dec->s2 = dec->s1; + dec->s1 = sample; + dec->m1 = (dec->s1 - dec->s2) * ((dec->s1 - dec->s2) / 1.3); + dec->m2 = (dec->s2 - dec->s3) * ((dec->s1 - dec->s2) / 1.3); + sense = (dec->m1 - dec->m2) * ((dec->m1 - dec->m2) / 1.3); + attackspeed = 7.0 + sense * 1024; + + sense = 1.0 + intensity * intensity * sense; + sense = FFMIN(sense, intensity); + recovery = 1.0 + (0.01 / sense); + + offset = 1.0 - fabs(sample); + + if (dec->flip) { + dec->iirSampleA = (dec->iirSampleA * (1.0 - (offset * iirAmount))) + + (sample * (offset * iirAmount)); + if (dec->ratioA < sense) { + dec->ratioA = ((dec->ratioA * attackspeed) + sense) / (attackspeed + 1.0); + } else { + dec->ratioA = 1.0 + ((dec->ratioA - 1.0) / recovery); + } + + dec->ratioA = FFMIN(dec->ratioA, maxdess); + sample = dec->iirSampleA + ((sample - dec->iirSampleA) / dec->ratioA); + } else { + dec->iirSampleB = (dec->iirSampleB * (1.0 - (offset * iirAmount))) + + (sample * (offset * iirAmount)); + if (dec->ratioB < sense) { + dec->ratioB = ((dec->ratioB * attackspeed) + sense) / (attackspeed + 1.0); + } else { + dec->ratioB = 1.0 + ((dec->ratioB - 1.0) / recovery); + } + + dec->ratioB = FFMIN(dec->ratioB, maxdess); + sample = dec->iirSampleB + ((sample - dec->iirSampleB) / dec->ratioB); + } + + dec->flip = !dec->flip; + + if (ctx->is_disabled) + sample = src[i]; + + switch (s->mode) { + case IN_MODE: dst[i] = src[i]; break; + case OUT_MODE: dst[i] = sample; break; + case ESS_MODE: dst[i] = src[i] - sample; break; + } + } + } + + if (out != in) + av_frame_free(&in); + + return ff_filter_frame(outlink, out); +} + +static av_cold void uninit(AVFilterContext *ctx) +{ + DeesserContext *s = ctx->priv; + + av_freep(&s->chan); +} + +static const AVFilterPad inputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_AUDIO, + .filter_frame = filter_frame, + .config_props = config_input, + }, + { NULL } +}; + +static const AVFilterPad outputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_AUDIO, + }, + { NULL } +}; + +AVFilter ff_af_deesser = { + .name = "deesser", + .description = NULL_IF_CONFIG_SMALL("Apply de-essing to the audio."), + .query_formats = query_formats, + .priv_size = sizeof(DeesserContext), + .priv_class = &deesser_class, + .uninit = uninit, + .inputs = inputs, + .outputs = outputs, + .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, +}; diff --git a/libavfilter/af_dynaudnorm.c b/libavfilter/af_dynaudnorm.c index 591930426..fd430884d 100644 --- a/libavfilter/af_dynaudnorm.c +++ b/libavfilter/af_dynaudnorm.c @@ -34,6 +34,7 @@ #include "audio.h" #include "avfilter.h" +#include "filters.h" #include "internal.h" typedef struct cqueue { @@ -67,10 +68,14 @@ typedef struct DynamicAudioNormalizerContext { int channels; int delay; + int eof; + int64_t pts; cqueue **gain_history_original; cqueue **gain_history_minimum; cqueue **gain_history_smoothed; + + cqueue *is_enabled; } DynamicAudioNormalizerContext; #define OFFSET(x) offsetof(DynamicAudioNormalizerContext, x) @@ -279,6 +284,9 @@ static av_cold void uninit(AVFilterContext *ctx) av_freep(&s->gain_history_minimum); av_freep(&s->gain_history_smoothed); + cqueue_free(s->is_enabled); + s->is_enabled = NULL; + av_freep(&s->weights); ff_bufqueue_discard_all(&s->queue); @@ -292,10 +300,7 @@ static int config_input(AVFilterLink *inlink) uninit(ctx); - s->frame_len = - inlink->min_samples = - inlink->max_samples = - inlink->partial_buf_size = frame_size(inlink->sample_rate, s->frame_len_msec); + s->frame_len = frame_size(inlink->sample_rate, s->frame_len_msec); av_log(ctx, AV_LOG_DEBUG, "frame len %d\n", s->frame_len); s->fade_factors[0] = av_malloc_array(s->frame_len, sizeof(*s->fade_factors[0])); @@ -308,10 +313,11 @@ static int config_input(AVFilterLink *inlink) s->gain_history_minimum = av_calloc(inlink->channels, sizeof(*s->gain_history_minimum)); s->gain_history_smoothed = av_calloc(inlink->channels, sizeof(*s->gain_history_smoothed)); s->weights = av_malloc_array(s->filter_size, sizeof(*s->weights)); + s->is_enabled = cqueue_create(s->filter_size); if (!s->prev_amplification_factor || !s->dc_correction_value || !s->compress_threshold || !s->fade_factors[0] || !s->fade_factors[1] || !s->gain_history_original || !s->gain_history_minimum || - !s->gain_history_smoothed || !s->weights) + !s->gain_history_smoothed || !s->is_enabled || !s->weights) return AVERROR(ENOMEM); for (c = 0; c < inlink->channels; c++) { @@ -631,7 +637,7 @@ static void analyze_frame(DynamicAudioNormalizerContext *s, AVFrame *frame) } } -static void amplify_frame(DynamicAudioNormalizerContext *s, AVFrame *frame) +static void amplify_frame(DynamicAudioNormalizerContext *s, AVFrame *frame, int enabled) { int c, i; @@ -641,7 +647,7 @@ static void amplify_frame(DynamicAudioNormalizerContext *s, AVFrame *frame) cqueue_dequeue(s->gain_history_smoothed[c], ¤t_amplification_factor); - for (i = 0; i < frame->nb_samples; i++) { + for (i = 0; i < frame->nb_samples && enabled; i++) { const double amplification_factor = fade(s->prev_amplification_factor[c], current_amplification_factor, i, s->fade_factors); @@ -661,15 +667,20 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) AVFilterContext *ctx = inlink->dst; DynamicAudioNormalizerContext *s = ctx->priv; AVFilterLink *outlink = inlink->dst->outputs[0]; - int ret = 0; + int ret = 1; if (!cqueue_empty(s->gain_history_smoothed[0])) { + double is_enabled; AVFrame *out = ff_bufqueue_get(&s->queue); - amplify_frame(s, out); + cqueue_dequeue(s->is_enabled, &is_enabled); + + amplify_frame(s, out, is_enabled > 0.); ret = ff_filter_frame(outlink, out); } + av_frame_make_writable(in); + cqueue_enqueue(s->is_enabled, !ctx->is_disabled); analyze_frame(s, in); ff_bufqueue_add(ctx, &s->queue, in); @@ -701,34 +712,76 @@ static int flush_buffer(DynamicAudioNormalizerContext *s, AVFilterLink *inlink, return filter_frame(inlink, out); } -static int request_frame(AVFilterLink *outlink) +static int flush(AVFilterLink *outlink) { AVFilterContext *ctx = outlink->src; DynamicAudioNormalizerContext *s = ctx->priv; int ret = 0; - ret = ff_request_frame(ctx->inputs[0]); + if (!cqueue_empty(s->gain_history_smoothed[0])) { + ret = flush_buffer(s, ctx->inputs[0], outlink); + } else if (s->queue.available) { + AVFrame *out = ff_bufqueue_get(&s->queue); - if (ret == AVERROR_EOF && !ctx->is_disabled && s->delay) { - if (!cqueue_empty(s->gain_history_smoothed[0])) { - ret = flush_buffer(s, ctx->inputs[0], outlink); - } else if (s->queue.available) { - AVFrame *out = ff_bufqueue_get(&s->queue); - - ret = ff_filter_frame(outlink, out); - } + s->pts = out->pts; + ret = ff_filter_frame(outlink, out); + s->delay = s->queue.available; } return ret; } +static int activate(AVFilterContext *ctx) +{ + AVFilterLink *inlink = ctx->inputs[0]; + AVFilterLink *outlink = ctx->outputs[0]; + DynamicAudioNormalizerContext *s = ctx->priv; + AVFrame *in = NULL; + int ret = 0, status; + int64_t pts; + + FF_FILTER_FORWARD_STATUS_BACK(outlink, inlink); + + if (!s->eof) { + ret = ff_inlink_consume_samples(inlink, s->frame_len, s->frame_len, &in); + if (ret < 0) + return ret; + if (ret > 0) { + ret = filter_frame(inlink, in); + if (ret <= 0) + return ret; + } + + if (ff_inlink_queued_samples(inlink) >= s->frame_len) { + ff_filter_set_ready(ctx, 10); + return 0; + } + } + + if (!s->eof && ff_inlink_acknowledge_status(inlink, &status, &pts)) { + if (status == AVERROR_EOF) + s->eof = 1; + } + + if (s->eof && s->delay > 0) + return flush(outlink); + + if (s->eof && s->delay <= 0) { + ff_outlink_set_status(outlink, AVERROR_EOF, s->pts); + return 0; + } + + if (!s->eof) + FF_FILTER_FORWARD_WANTED(outlink, inlink); + + return FFERROR_NOT_READY; +} + static const AVFilterPad avfilter_af_dynaudnorm_inputs[] = { { .name = "default", .type = AVMEDIA_TYPE_AUDIO, - .filter_frame = filter_frame, .config_props = config_input, - .needs_writable = 1, }, { NULL } }; @@ -737,7 +790,6 @@ static const AVFilterPad avfilter_af_dynaudnorm_outputs[] = { { .name = "default", .type = AVMEDIA_TYPE_AUDIO, - .request_frame = request_frame, }, { NULL } }; @@ -749,7 +801,9 @@ AVFilter ff_af_dynaudnorm = { .priv_size = sizeof(DynamicAudioNormalizerContext), .init = init, .uninit = uninit, + .activate = activate, .inputs = avfilter_af_dynaudnorm_inputs, .outputs = avfilter_af_dynaudnorm_outputs, .priv_class = &dynaudnorm_class, + .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, }; diff --git a/libavfilter/af_extrastereo.c b/libavfilter/af_extrastereo.c index 13c6f4777..83eba4741 100644 --- a/libavfilter/af_extrastereo.c +++ b/libavfilter/af_extrastereo.c @@ -128,4 +128,5 @@ AVFilter ff_af_extrastereo = { .priv_class = &extrastereo_class, .inputs = inputs, .outputs = outputs, + .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC, }; diff --git a/libavfilter/af_headphone.c b/libavfilter/af_headphone.c index 791013221..10638f9e7 100644 --- a/libavfilter/af_headphone.c +++ b/libavfilter/af_headphone.c @@ -20,7 +20,6 @@ #include -#include "libavutil/audio_fifo.h" #include "libavutil/avstring.h" #include "libavutil/channel_layout.h" #include "libavutil/float_dsp.h" @@ -29,6 +28,7 @@ #include "libavcodec/avfft.h" #include "avfilter.h" +#include "filters.h" #include "internal.h" #include "audio.h" @@ -48,9 +48,9 @@ typedef struct HeadphoneContext { int have_hrirs; int eof_hrirs; - int64_t pts; int ir_len; + int air_len; int mapping[64]; @@ -73,13 +73,13 @@ typedef struct HeadphoneContext { float *data_ir[2]; float *temp_src[2]; FFTComplex *temp_fft[2]; + FFTComplex *temp_afft[2]; FFTContext *fft[2], *ifft[2]; FFTComplex *data_hrtf[2]; AVFloatDSPContext *fdsp; struct headphone_inputs { - AVAudioFifo *fifo; AVFrame *frame; int ir_len; int delay_l; @@ -159,6 +159,7 @@ typedef struct ThreadData { float **ringbuffer; float **temp_src; FFTComplex **temp_fft; + FFTComplex **temp_afft; } ThreadData; static int headphone_convolute(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) @@ -174,6 +175,7 @@ static int headphone_convolute(AVFilterContext *ctx, void *arg, int jobnr, int n float *ringbuffer = td->ringbuffer[jobnr]; float *temp_src = td->temp_src[jobnr]; const int ir_len = s->ir_len; + const int air_len = s->air_len; const float *src = (const float *)in->data[0]; float *dst = (float *)out->data[0]; const int in_channels = in->channels; @@ -202,7 +204,7 @@ static int headphone_convolute(AVFilterContext *ctx, void *arg, int jobnr, int n if (l == s->lfe_channel) { *dst += *(buffer[s->lfe_channel] + wr) * s->gain_lfe; - temp_ir += FFALIGN(ir_len, 16); + temp_ir += air_len; continue; } @@ -211,18 +213,18 @@ static int headphone_convolute(AVFilterContext *ctx, void *arg, int jobnr, int n if (read + ir_len < buffer_length) { memcpy(temp_src, bptr + read, ir_len * sizeof(*temp_src)); } else { - int len = FFMIN(ir_len - (read % ir_len), buffer_length - read); + int len = FFMIN(air_len - (read % ir_len), buffer_length - read); memcpy(temp_src, bptr + read, len * sizeof(*temp_src)); - memcpy(temp_src + len, bptr, (ir_len - len) * sizeof(*temp_src)); + memcpy(temp_src + len, bptr, (air_len - len) * sizeof(*temp_src)); } - dst[0] += s->fdsp->scalarproduct_float(temp_ir, temp_src, ir_len); - temp_ir += FFALIGN(ir_len, 16); + dst[0] += s->fdsp->scalarproduct_float(temp_ir, temp_src, FFALIGN(ir_len, 32)); + temp_ir += air_len; } - if (fabs(*dst) > 1) - *n_clippings += 1; + if (fabsf(dst[0]) > 1) + n_clippings[0]++; dst += 2; src += in_channels; @@ -251,6 +253,7 @@ static int headphone_fast_convolute(AVFilterContext *ctx, void *arg, int jobnr, const int buffer_length = s->buffer_length; const uint32_t modulo = (uint32_t)buffer_length - 1; FFTComplex *fft_in = s->temp_fft[jobnr]; + FFTComplex *fft_acc = s->temp_afft[jobnr]; FFTContext *ifft = s->ifft[jobnr]; FFTContext *fft = s->fft[jobnr]; const int n_fft = s->n_fft; @@ -262,7 +265,7 @@ static int headphone_fast_convolute(AVFilterContext *ctx, void *arg, int jobnr, dst += offset; - n_read = FFMIN(s->ir_len, in->nb_samples); + n_read = FFMIN(ir_len, in->nb_samples); for (j = 0; j < n_read; j++) { dst[2 * j] = ringbuffer[wr]; ringbuffer[wr] = 0.0; @@ -273,6 +276,8 @@ static int headphone_fast_convolute(AVFilterContext *ctx, void *arg, int jobnr, dst[2 * j] = 0; } + memset(fft_acc, 0, sizeof(FFTComplex) * n_fft); + for (i = 0; i < in_channels; i++) { if (i == s->lfe_channel) { for (j = 0; j < in->nb_samples; j++) { @@ -297,26 +302,26 @@ static int headphone_fast_convolute(AVFilterContext *ctx, void *arg, int jobnr, const float re = fft_in[j].re; const float im = fft_in[j].im; - fft_in[j].re = re * hcomplex->re - im * hcomplex->im; - fft_in[j].im = re * hcomplex->im + im * hcomplex->re; - } - - av_fft_permute(ifft, fft_in); - av_fft_calc(ifft, fft_in); - - for (j = 0; j < in->nb_samples; j++) { - dst[2 * j] += fft_in[j].re * fft_scale; - } - - for (j = 0; j < ir_len - 1; j++) { - int write_pos = (wr + j) & modulo; - - *(ringbuffer + write_pos) += fft_in[in->nb_samples + j].re * fft_scale; + fft_acc[j].re += re * hcomplex->re - im * hcomplex->im; + fft_acc[j].im += re * hcomplex->im + im * hcomplex->re; } } + av_fft_permute(ifft, fft_acc); + av_fft_calc(ifft, fft_acc); + + for (j = 0; j < in->nb_samples; j++) { + dst[2 * j] += fft_acc[j].re * fft_scale; + } + + for (j = 0; j < ir_len - 1; j++) { + int write_pos = (wr + j) & modulo; + + *(ringbuffer + write_pos) += fft_acc[in->nb_samples + j].re * fft_scale; + } + for (i = 0; i < out->nb_samples; i++) { - if (fabs(*dst) > 1) { + if (fabsf(dst[0]) > 1) { n_clippings[0]++; } @@ -328,24 +333,13 @@ static int headphone_fast_convolute(AVFilterContext *ctx, void *arg, int jobnr, return 0; } -static int read_ir(AVFilterLink *inlink, AVFrame *frame) +static int check_ir(AVFilterLink *inlink, int input_number) { AVFilterContext *ctx = inlink->dst; HeadphoneContext *s = ctx->priv; - int ir_len, max_ir_len, input_number, ret; + int ir_len, max_ir_len; - for (input_number = 0; input_number < s->nb_inputs; input_number++) - if (inlink == ctx->inputs[input_number]) - break; - - ret = av_audio_fifo_write(s->in[input_number].fifo, (void **)frame->extended_data, - frame->nb_samples); - av_frame_free(&frame); - - if (ret < 0) - return ret; - - ir_len = av_audio_fifo_size(s->in[input_number].fifo); + ir_len = ff_inlink_queued_samples(inlink); max_ir_len = 65536; if (ir_len > max_ir_len) { av_log(ctx, AV_LOG_ERROR, "Too big length of IRs: %d > %d.\n", ir_len, max_ir_len); @@ -357,27 +351,25 @@ static int read_ir(AVFilterLink *inlink, AVFrame *frame) return 0; } -static int headphone_frame(HeadphoneContext *s, AVFilterLink *outlink, int max_nb_samples) +static int headphone_frame(HeadphoneContext *s, AVFrame *in, AVFilterLink *outlink) { AVFilterContext *ctx = outlink->src; - AVFrame *in = s->in[0].frame; int n_clippings[2] = { 0 }; ThreadData td; AVFrame *out; - av_audio_fifo_read(s->in[0].fifo, (void **)in->extended_data, s->size); - out = ff_get_audio_buffer(outlink, in->nb_samples); - if (!out) + if (!out) { + av_frame_free(&in); return AVERROR(ENOMEM); - out->pts = s->pts; - if (s->pts != AV_NOPTS_VALUE) - s->pts += av_rescale_q(out->nb_samples, (AVRational){1, outlink->sample_rate}, outlink->time_base); + } + out->pts = in->pts; td.in = in; td.out = out; td.write = s->write; td.delay = s->delay; td.ir = s->data_ir; td.n_clippings = n_clippings; td.ringbuffer = s->ringbuffer; td.temp_src = s->temp_src; td.temp_fft = s->temp_fft; + td.temp_afft = s->temp_afft; if (s->type == TIME_DOMAIN) { ctx->internal->execute(ctx, headphone_convolute, &td, NULL, 2); @@ -391,7 +383,7 @@ static int headphone_frame(HeadphoneContext *s, AVFilterLink *outlink, int max_n n_clippings[0] + n_clippings[1], out->nb_samples * 2); } - out->nb_samples = max_nb_samples; + av_frame_free(&in); return ff_filter_frame(outlink, out); } @@ -412,8 +404,9 @@ static int convert_coeffs(AVFilterContext *ctx, AVFilterLink *inlink) int n_fft; int i, j, k; - s->buffer_length = 1 << (32 - ff_clz(s->ir_len)); - s->n_fft = n_fft = 1 << (32 - ff_clz(s->ir_len + s->size)); + s->air_len = 1 << (32 - ff_clz(ir_len)); + s->buffer_length = 1 << (32 - ff_clz(s->air_len)); + s->n_fft = n_fft = 1 << (32 - ff_clz(ir_len + s->size)); if (s->type == FREQUENCY_DOMAIN) { fft_in_l = av_calloc(n_fft, sizeof(*fft_in_l)); @@ -425,12 +418,12 @@ static int convert_coeffs(AVFilterContext *ctx, AVFilterLink *inlink) av_fft_end(s->fft[0]); av_fft_end(s->fft[1]); - s->fft[0] = av_fft_init(log2(s->n_fft), 0); - s->fft[1] = av_fft_init(log2(s->n_fft), 0); + s->fft[0] = av_fft_init(av_log2(s->n_fft), 0); + s->fft[1] = av_fft_init(av_log2(s->n_fft), 0); av_fft_end(s->ifft[0]); av_fft_end(s->ifft[1]); - s->ifft[0] = av_fft_init(log2(s->n_fft), 1); - s->ifft[1] = av_fft_init(log2(s->n_fft), 1); + s->ifft[0] = av_fft_init(av_log2(s->n_fft), 1); + s->ifft[1] = av_fft_init(av_log2(s->n_fft), 1); if (!s->fft[0] || !s->fft[1] || !s->ifft[0] || !s->ifft[1]) { av_log(ctx, AV_LOG_ERROR, "Unable to create FFT contexts of size %d.\n", s->n_fft); @@ -439,8 +432,8 @@ static int convert_coeffs(AVFilterContext *ctx, AVFilterLink *inlink) } } - s->data_ir[0] = av_calloc(FFALIGN(s->ir_len, 16), sizeof(float) * s->nb_irs); - s->data_ir[1] = av_calloc(FFALIGN(s->ir_len, 16), sizeof(float) * s->nb_irs); + s->data_ir[0] = av_calloc(s->air_len, sizeof(float) * s->nb_irs); + s->data_ir[1] = av_calloc(s->air_len, sizeof(float) * s->nb_irs); s->delay[0] = av_calloc(s->nb_irs, sizeof(float)); s->delay[1] = av_calloc(s->nb_irs, sizeof(float)); @@ -452,7 +445,10 @@ static int convert_coeffs(AVFilterContext *ctx, AVFilterLink *inlink) s->ringbuffer[1] = av_calloc(s->buffer_length, sizeof(float)); s->temp_fft[0] = av_calloc(s->n_fft, sizeof(FFTComplex)); s->temp_fft[1] = av_calloc(s->n_fft, sizeof(FFTComplex)); - if (!s->temp_fft[0] || !s->temp_fft[1]) { + s->temp_afft[0] = av_calloc(s->n_fft, sizeof(FFTComplex)); + s->temp_afft[1] = av_calloc(s->n_fft, sizeof(FFTComplex)); + if (!s->temp_fft[0] || !s->temp_fft[1] || + !s->temp_afft[0] || !s->temp_afft[1]) { ret = AVERROR(ENOMEM); goto fail; } @@ -464,25 +460,12 @@ static int convert_coeffs(AVFilterContext *ctx, AVFilterLink *inlink) goto fail; } - s->in[0].frame = ff_get_audio_buffer(ctx->inputs[0], s->size); - if (!s->in[0].frame) { - ret = AVERROR(ENOMEM); - goto fail; - } - for (i = 0; i < s->nb_inputs - 1; i++) { - s->in[i + 1].frame = ff_get_audio_buffer(ctx->inputs[i + 1], s->ir_len); - if (!s->in[i + 1].frame) { - ret = AVERROR(ENOMEM); - goto fail; - } - } - if (s->type == TIME_DOMAIN) { - s->temp_src[0] = av_calloc(FFALIGN(ir_len, 16), sizeof(float)); - s->temp_src[1] = av_calloc(FFALIGN(ir_len, 16), sizeof(float)); + s->temp_src[0] = av_calloc(s->air_len, sizeof(float)); + s->temp_src[1] = av_calloc(s->air_len, sizeof(float)); - data_ir_l = av_calloc(nb_irs * FFALIGN(ir_len, 16), sizeof(*data_ir_l)); - data_ir_r = av_calloc(nb_irs * FFALIGN(ir_len, 16), sizeof(*data_ir_r)); + data_ir_l = av_calloc(nb_irs * s->air_len, sizeof(*data_ir_l)); + data_ir_r = av_calloc(nb_irs * s->air_len, sizeof(*data_ir_r)); if (!data_ir_r || !data_ir_l || !s->temp_src[0] || !s->temp_src[1]) { ret = AVERROR(ENOMEM); goto fail; @@ -502,7 +485,9 @@ static int convert_coeffs(AVFilterContext *ctx, AVFilterLink *inlink) int delay_r = s->in[i + 1].delay_r; float *ptr; - av_audio_fifo_read(s->in[i + 1].fifo, (void **)s->in[i + 1].frame->extended_data, len); + ret = ff_inlink_consume_samples(ctx->inputs[i + 1], len, len, &s->in[i + 1].frame); + if (ret < 0) + goto fail; ptr = (float *)s->in[i + 1].frame->extended_data[0]; if (s->hrir_fmt == HRIR_STEREO) { @@ -522,7 +507,7 @@ static int convert_coeffs(AVFilterContext *ctx, AVFilterLink *inlink) if (idx == -1) continue; if (s->type == TIME_DOMAIN) { - offset = idx * FFALIGN(len, 16); + offset = idx * s->air_len; for (j = 0; j < len; j++) { data_ir_l[offset + j] = ptr[len * 2 - j * 2 - 2] * gain_lin; data_ir_r[offset + j] = ptr[len * 2 - j * 2 - 1] * gain_lin; @@ -565,7 +550,7 @@ static int convert_coeffs(AVFilterContext *ctx, AVFilterLink *inlink) I = idx * 2; if (s->type == TIME_DOMAIN) { - offset = idx * FFALIGN(len, 16); + offset = idx * s->air_len; for (j = 0; j < len; j++) { data_ir_l[offset + j] = ptr[len * N - j * N - N + I ] * gain_lin; data_ir_r[offset + j] = ptr[len * N - j * N - N + I + 1] * gain_lin; @@ -589,11 +574,13 @@ static int convert_coeffs(AVFilterContext *ctx, AVFilterLink *inlink) } } } + + av_frame_free(&s->in[i + 1].frame); } if (s->type == TIME_DOMAIN) { - memcpy(s->data_ir[0], data_ir_l, sizeof(float) * nb_irs * FFALIGN(ir_len, 16)); - memcpy(s->data_ir[1], data_ir_r, sizeof(float) * nb_irs * FFALIGN(ir_len, 16)); + memcpy(s->data_ir[0], data_ir_l, sizeof(float) * nb_irs * s->air_len); + memcpy(s->data_ir[1], data_ir_r, sizeof(float) * nb_irs * s->air_len); } else { s->data_hrtf[0] = av_calloc(n_fft * s->nb_irs, sizeof(FFTComplex)); s->data_hrtf[1] = av_calloc(n_fft * s->nb_irs, sizeof(FFTComplex)); @@ -612,6 +599,9 @@ static int convert_coeffs(AVFilterContext *ctx, AVFilterLink *inlink) fail: + for (i = 0; i < s->nb_inputs - 1; i++) + av_frame_free(&s->in[i + 1].frame); + av_freep(&data_ir_l); av_freep(&data_ir_r); @@ -624,22 +614,47 @@ fail: return ret; } -static int filter_frame(AVFilterLink *inlink, AVFrame *in) +static int activate(AVFilterContext *ctx) { - AVFilterContext *ctx = inlink->dst; HeadphoneContext *s = ctx->priv; + AVFilterLink *inlink = ctx->inputs[0]; AVFilterLink *outlink = ctx->outputs[0]; - int ret = 0; + AVFrame *in = NULL; + int i, ret; - ret = av_audio_fifo_write(s->in[0].fifo, (void **)in->extended_data, - in->nb_samples); - if (s->pts == AV_NOPTS_VALUE) - s->pts = in->pts; + FF_FILTER_FORWARD_STATUS_BACK_ALL(ctx->outputs[0], ctx); + if (!s->eof_hrirs) { + for (i = 1; i < s->nb_inputs; i++) { + if (s->in[i].eof) + continue; - av_frame_free(&in); + if ((ret = check_ir(ctx->inputs[i], i)) < 0) + return ret; - if (ret < 0) - return ret; + if (!s->in[i].eof) { + if (ff_outlink_get_status(ctx->inputs[i]) == AVERROR_EOF) + s->in[i].eof = 1; + } + } + + for (i = 1; i < s->nb_inputs; i++) { + if (!s->in[i].eof) + break; + } + + if (i != s->nb_inputs) { + if (ff_outlink_frame_wanted(ctx->outputs[0])) { + for (i = 1; i < s->nb_inputs; i++) { + if (!s->in[i].eof) + ff_inlink_request_frame(ctx->inputs[i]); + } + } + + return 0; + } else { + s->eof_hrirs = 1; + } + } if (!s->have_hrirs && s->eof_hrirs) { ret = convert_coeffs(ctx, inlink); @@ -647,14 +662,19 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) return ret; } - if (s->have_hrirs) { - while (av_audio_fifo_size(s->in[0].fifo) >= s->size) { - ret = headphone_frame(s, outlink, s->size); - if (ret < 0) - return ret; - } + if ((ret = ff_inlink_consume_samples(ctx->inputs[0], s->size, s->size, &in)) > 0) { + ret = headphone_frame(s, in, outlink); + if (ret < 0) + return ret; } + if (ret < 0) + return ret; + + FF_FILTER_FORWARD_STATUS(ctx->inputs[0], ctx->outputs[0]); + if (ff_outlink_frame_wanted(ctx->outputs[0])) + ff_inlink_request_frame(ctx->inputs[0]); + return 0; } @@ -733,7 +753,6 @@ static av_cold int init(AVFilterContext *ctx) .name = "in0", .type = AVMEDIA_TYPE_AUDIO, .config_props = config_input, - .filter_frame = filter_frame, }; if ((ret = ff_insert_inpad(ctx, 0, &pad)) < 0) return ret; @@ -754,7 +773,6 @@ static av_cold int init(AVFilterContext *ctx) AVFilterPad pad = { .name = name, .type = AVMEDIA_TYPE_AUDIO, - .filter_frame = read_ir, }; if (!name) return AVERROR(ENOMEM); @@ -767,7 +785,6 @@ static av_cold int init(AVFilterContext *ctx) s->fdsp = avpriv_float_dsp_alloc(0); if (!s->fdsp) return AVERROR(ENOMEM); - s->pts = AV_NOPTS_VALUE; return 0; } @@ -777,7 +794,6 @@ static int config_output(AVFilterLink *outlink) AVFilterContext *ctx = outlink->src; HeadphoneContext *s = ctx->priv; AVFilterLink *inlink = ctx->inputs[0]; - int i; if (s->hrir_fmt == HRIR_MULTI) { AVFilterLink *hrir_link = ctx->inputs[1]; @@ -788,62 +804,11 @@ static int config_output(AVFilterLink *outlink) } } - for (i = 0; i < s->nb_inputs; i++) { - s->in[i].fifo = av_audio_fifo_alloc(ctx->inputs[i]->format, ctx->inputs[i]->channels, 1024); - if (!s->in[i].fifo) - return AVERROR(ENOMEM); - } - s->gain_lfe = expf((s->gain - 3 * inlink->channels - 6 + s->lfe_gain) / 20 * M_LN10); + s->gain_lfe = expf((s->gain - 3 * inlink->channels + s->lfe_gain) / 20 * M_LN10); return 0; } -static int request_frame(AVFilterLink *outlink) -{ - AVFilterContext *ctx = outlink->src; - HeadphoneContext *s = ctx->priv; - int i, ret; - - for (i = 1; !s->eof_hrirs && i < s->nb_inputs; i++) { - if (!s->in[i].eof) { - ret = ff_request_frame(ctx->inputs[i]); - if (ret == AVERROR_EOF) { - s->in[i].eof = 1; - ret = 0; - } - return ret; - } else { - if (i == s->nb_inputs - 1) - s->eof_hrirs = 1; - } - } - - ret = ff_request_frame(ctx->inputs[0]); - if (ret == AVERROR_EOF && av_audio_fifo_size(s->in[0].fifo) > 0 && s->have_hrirs) { - int nb_samples = av_audio_fifo_size(s->in[0].fifo); - AVFrame *in = ff_get_audio_buffer(ctx->inputs[0], s->size - nb_samples); - - if (!in) - return AVERROR(ENOMEM); - - av_samples_set_silence(in->extended_data, 0, - in->nb_samples, - in->channels, - in->format); - - ret = av_audio_fifo_write(s->in[0].fifo, (void **)in->extended_data, - in->nb_samples); - av_frame_free(&in); - if (ret < 0) - return ret; - ret = headphone_frame(s, outlink, nb_samples); - - av_audio_fifo_drain(s->in[0].fifo, av_audio_fifo_size(s->in[0].fifo)); - } - - return ret; -} - static av_cold void uninit(AVFilterContext *ctx) { HeadphoneContext *s = ctx->priv; @@ -863,13 +828,13 @@ static av_cold void uninit(AVFilterContext *ctx) av_freep(&s->temp_src[1]); av_freep(&s->temp_fft[0]); av_freep(&s->temp_fft[1]); + av_freep(&s->temp_afft[0]); + av_freep(&s->temp_afft[1]); av_freep(&s->data_hrtf[0]); av_freep(&s->data_hrtf[1]); av_freep(&s->fdsp); for (i = 0; i < s->nb_inputs; i++) { - av_frame_free(&s->in[i].frame); - av_audio_fifo_free(s->in[i].fifo); if (ctx->input_pads && i) av_freep(&ctx->input_pads[i].name); } @@ -900,7 +865,6 @@ static const AVFilterPad outputs[] = { .name = "default", .type = AVMEDIA_TYPE_AUDIO, .config_props = config_output, - .request_frame = request_frame, }, { NULL } }; @@ -913,6 +877,7 @@ AVFilter ff_af_headphone = { .init = init, .uninit = uninit, .query_formats = query_formats, + .activate = activate, .inputs = NULL, .outputs = outputs, .flags = AVFILTER_FLAG_SLICE_THREADS | AVFILTER_FLAG_DYNAMIC_INPUTS, diff --git a/libavfilter/af_join.c b/libavfilter/af_join.c index 4f86e1355..930c9e48e 100644 --- a/libavfilter/af_join.c +++ b/libavfilter/af_join.c @@ -472,6 +472,8 @@ static int activate(AVFilterContext *ctx) int nb_samples = 0; int64_t pts; + FF_FILTER_FORWARD_STATUS_BACK_ALL(ctx->outputs[0], ctx); + if (!s->input_frames[0]) { ret = ff_inlink_consume_frame(ctx->inputs[0], &s->input_frames[0]); if (ret < 0) { diff --git a/libavfilter/af_ladspa.c b/libavfilter/af_ladspa.c index 3be26bc84..a8562fc07 100644 --- a/libavfilter/af_ladspa.c +++ b/libavfilter/af_ladspa.c @@ -548,8 +548,8 @@ static av_cold int init(AVFilterContext *ctx) break; p = NULL; - if (sscanf(arg, "c%d=%f", &i, &val) != 2) { - if (sscanf(arg, "%f", &val) != 1) { + if (av_sscanf(arg, "c%d=%f", &i, &val) != 2) { + if (av_sscanf(arg, "%f", &val) != 1) { av_log(ctx, AV_LOG_ERROR, "Invalid syntax.\n"); return AVERROR(EINVAL); } @@ -715,7 +715,7 @@ static int process_command(AVFilterContext *ctx, const char *cmd, const char *ar LADSPA_Data value; unsigned long port; - if (sscanf(cmd, "c%ld", &port) + sscanf(args, "%f", &value) != 2) + if (av_sscanf(cmd, "c%ld", &port) + av_sscanf(args, "%f", &value) != 2) return AVERROR(EINVAL); return set_control(ctx, port, value); diff --git a/libavfilter/af_rubberband.c b/libavfilter/af_rubberband.c index ea6f4ff2c..ef937f441 100644 --- a/libavfilter/af_rubberband.c +++ b/libavfilter/af_rubberband.c @@ -24,6 +24,7 @@ #include "audio.h" #include "avfilter.h" +#include "filters.h" #include "formats.h" #include "internal.h" @@ -36,7 +37,8 @@ typedef struct RubberBandContext { smoothing, formant, opitch, channels; int64_t nb_samples_out; int64_t nb_samples_in; - int flushed; + int64_t first_pts; + int nb_samples; } RubberBandContext; #define OFFSET(x) offsetof(RubberBandContext, x) @@ -123,7 +125,10 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) AVFrame *out; int ret = 0, nb_samples; - rubberband_process(s->rbs, (const float *const *)in->data, in->nb_samples, 0); + if (s->first_pts == AV_NOPTS_VALUE) + s->first_pts = in->pts; + + rubberband_process(s->rbs, (const float *const *)in->data, in->nb_samples, ff_outlink_get_status(inlink)); s->nb_samples_in += in->nb_samples; nb_samples = rubberband_available(s->rbs); @@ -133,7 +138,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) av_frame_free(&in); return AVERROR(ENOMEM); } - out->pts = av_rescale_q(s->nb_samples_out, + out->pts = s->first_pts + av_rescale_q(s->nb_samples_out, (AVRational){ 1, outlink->sample_rate }, outlink->time_base); nb_samples = rubberband_retrieve(s->rbs, (float *const *)out->data, nb_samples); @@ -143,7 +148,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) } av_frame_free(&in); - return ret; + return ret < 0 ? ret : nb_samples; } static int config_input(AVFilterLink *inlink) @@ -157,54 +162,38 @@ static int config_input(AVFilterLink *inlink) if (s->rbs) rubberband_delete(s->rbs); s->rbs = rubberband_new(inlink->sample_rate, inlink->channels, opts, 1. / s->tempo, s->pitch); + if (!s->rbs) + return AVERROR(ENOMEM); - inlink->partial_buf_size = - inlink->min_samples = - inlink->max_samples = rubberband_get_samples_required(s->rbs); + s->nb_samples = rubberband_get_samples_required(s->rbs); + s->first_pts = AV_NOPTS_VALUE; return 0; } -static int request_frame(AVFilterLink *outlink) +static int activate(AVFilterContext *ctx) { - AVFilterContext *ctx = outlink->src; - RubberBandContext *s = ctx->priv; AVFilterLink *inlink = ctx->inputs[0]; - int ret = 0; + AVFilterLink *outlink = ctx->outputs[0]; + RubberBandContext *s = ctx->priv; + AVFrame *in = NULL; + int ret; - ret = ff_request_frame(ctx->inputs[0]); + FF_FILTER_FORWARD_STATUS_BACK(outlink, inlink); - if (ret == AVERROR_EOF && !s->flushed) { - if (rubberband_available(s->rbs) > 0) { - AVFrame *out = ff_get_audio_buffer(inlink, 1); - int nb_samples; - - if (!out) - return AVERROR(ENOMEM); - - rubberband_process(s->rbs, (const float *const *)out->data, 1, 1); - av_frame_free(&out); - nb_samples = rubberband_available(s->rbs); - - if (nb_samples > 0) { - out = ff_get_audio_buffer(outlink, nb_samples); - if (!out) - return AVERROR(ENOMEM); - out->pts = av_rescale_q(s->nb_samples_out, - (AVRational){ 1, outlink->sample_rate }, - outlink->time_base); - nb_samples = rubberband_retrieve(s->rbs, (float *const *)out->data, nb_samples); - out->nb_samples = nb_samples; - ret = ff_filter_frame(outlink, out); - s->nb_samples_out += nb_samples; - } - } - s->flushed = 1; - av_log(ctx, AV_LOG_DEBUG, "nb_samples_in %"PRId64" nb_samples_out %"PRId64"\n", - s->nb_samples_in, s->nb_samples_out); + ret = ff_inlink_consume_samples(inlink, s->nb_samples, s->nb_samples, &in); + if (ret < 0) + return ret; + if (ret > 0) { + ret = filter_frame(inlink, in); + if (ret != 0) + return ret; } - return ret; + FF_FILTER_FORWARD_STATUS(inlink, outlink); + FF_FILTER_FORWARD_WANTED(outlink, inlink); + + return FFERROR_NOT_READY; } static int process_command(AVFilterContext *ctx, const char *cmd, const char *args, @@ -244,7 +233,6 @@ static const AVFilterPad rubberband_inputs[] = { .name = "default", .type = AVMEDIA_TYPE_AUDIO, .config_props = config_input, - .filter_frame = filter_frame, }, { NULL } }; @@ -253,7 +241,6 @@ static const AVFilterPad rubberband_outputs[] = { { .name = "default", .type = AVMEDIA_TYPE_AUDIO, - .request_frame = request_frame, }, { NULL } }; @@ -265,6 +252,7 @@ AVFilter ff_af_rubberband = { .priv_size = sizeof(RubberBandContext), .priv_class = &rubberband_class, .uninit = uninit, + .activate = activate, .inputs = rubberband_inputs, .outputs = rubberband_outputs, .process_command = process_command, diff --git a/libavfilter/af_sidechaincompress.c b/libavfilter/af_sidechaincompress.c index 888049eaf..219643acb 100644 --- a/libavfilter/af_sidechaincompress.c +++ b/libavfilter/af_sidechaincompress.c @@ -54,10 +54,14 @@ typedef struct SidechainCompressContext { double knee_start; double knee_stop; double lin_knee_start; + double lin_knee_stop; double adj_knee_start; + double adj_knee_stop; + double compressed_knee_start; double compressed_knee_stop; int link; int detection; + int mode; AVAudioFifo *fifo[2]; int64_t pts; @@ -69,6 +73,9 @@ typedef struct SidechainCompressContext { static const AVOption options[] = { { "level_in", "set input gain", OFFSET(level_in), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0.015625, 64, A|F }, + { "mode", "set mode", OFFSET(mode), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, A|F, "mode" }, + { "downward",0, 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, A|F, "mode" }, + { "upward", 0, 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, A|F, "mode" }, { "threshold", "set threshold", OFFSET(threshold), AV_OPT_TYPE_DOUBLE, {.dbl=0.125}, 0.000976563, 1, A|F }, { "ratio", "set ratio", OFFSET(ratio), AV_OPT_TYPE_DOUBLE, {.dbl=2}, 1, 20, A|F }, { "attack", "set attack", OFFSET(attack), AV_OPT_TYPE_DOUBLE, {.dbl=20}, 0.01, 2000, A|F }, @@ -97,7 +104,9 @@ AVFILTER_DEFINE_CLASS(sidechaincompress); static double output_gain(double lin_slope, double ratio, double thres, double knee, double knee_start, double knee_stop, - double compressed_knee_stop, int detection) + double compressed_knee_start, + double compressed_knee_stop, + int detection, int mode) { double slope = log(lin_slope); double gain = 0.0; @@ -114,10 +123,17 @@ static double output_gain(double lin_slope, double ratio, double thres, delta = 1.0 / ratio; } - if (knee > 1.0 && slope < knee_stop) - gain = hermite_interpolation(slope, knee_start, knee_stop, - knee_start, compressed_knee_stop, - 1.0, delta); + if (mode) { + if (knee > 1.0 && slope > knee_start) + gain = hermite_interpolation(slope, knee_stop, knee_start, + knee_stop, compressed_knee_start, + 1.0, delta); + } else { + if (knee > 1.0 && slope < knee_stop) + gain = hermite_interpolation(slope, knee_start, knee_stop, + knee_start, compressed_knee_stop, + 1.0, delta); + } return exp(gain - slope); } @@ -129,9 +145,12 @@ static int compressor_config_output(AVFilterLink *outlink) s->thres = log(s->threshold); s->lin_knee_start = s->threshold / sqrt(s->knee); + s->lin_knee_stop = s->threshold * sqrt(s->knee); s->adj_knee_start = s->lin_knee_start * s->lin_knee_start; + s->adj_knee_stop = s->lin_knee_stop * s->lin_knee_stop; s->knee_start = log(s->lin_knee_start); - s->knee_stop = log(s->threshold * sqrt(s->knee)); + s->knee_stop = log(s->lin_knee_stop); + s->compressed_knee_start = (s->knee_start - s->thres) / s->ratio + s->thres; s->compressed_knee_stop = (s->knee_stop - s->thres) / s->ratio + s->thres; s->attack_coeff = FFMIN(1., 1. / (s->attack * outlink->sample_rate / 4000.)); @@ -151,6 +170,8 @@ static void compressor(SidechainCompressContext *s, for (i = 0; i < nb_samples; i++) { double abs_sample, gain = 1.0; + double detector; + int detected; abs_sample = fabs(scsrc[0] * level_sc); @@ -169,10 +190,20 @@ static void compressor(SidechainCompressContext *s, s->lin_slope += (abs_sample - s->lin_slope) * (abs_sample > s->lin_slope ? s->attack_coeff : s->release_coeff); - if (s->lin_slope > 0.0 && s->lin_slope > (s->detection ? s->adj_knee_start : s->lin_knee_start)) + if (s->mode) { + detector = (s->detection ? s->adj_knee_stop : s->lin_knee_stop); + detected = s->lin_slope < detector; + } else { + detector = (s->detection ? s->adj_knee_start : s->lin_knee_start); + detected = s->lin_slope > detector; + } + + if (s->lin_slope > 0.0 && detected) gain = output_gain(s->lin_slope, s->ratio, s->thres, s->knee, s->knee_start, s->knee_stop, - s->compressed_knee_stop, s->detection); + s->compressed_knee_start, + s->compressed_knee_stop, + s->detection, s->mode); for (c = 0; c < inlink->channels; c++) dst[c] = src[c] * level_in * (gain * makeup * mix + (1. - mix)); diff --git a/libavfilter/af_silencedetect.c b/libavfilter/af_silencedetect.c index 6e321a5d9..3a71f3902 100644 --- a/libavfilter/af_silencedetect.c +++ b/libavfilter/af_silencedetect.c @@ -38,7 +38,7 @@ typedef struct SilenceDetectContext { double duration; ///< minimum duration of silence until notification int mono; ///< mono mode : check each channel separately (default = check when ALL channels are silent) int channels; ///< number of channels - int independant_channels; ///< number of entries in following arrays (always 1 in mono mode) + int independent_channels; ///< number of entries in following arrays (always 1 in mono mode) int64_t *nb_null_samples; ///< (array) current number of continuous zero samples int64_t *start; ///< (array) if silence is detected, this value contains the time of the first zero sample (default/unset = INT64_MIN) int64_t frame_end; ///< pts of the end of the current frame (used to compute duration of silence at EOS) @@ -57,7 +57,8 @@ static const AVOption silencedetect_options[] = { { "noise", "set noise tolerance", OFFSET(noise), AV_OPT_TYPE_DOUBLE, {.dbl=0.001}, 0, DBL_MAX, FLAGS }, { "d", "set minimum duration in seconds", OFFSET(duration), AV_OPT_TYPE_DOUBLE, {.dbl=2.}, 0, 24*60*60, FLAGS }, { "duration", "set minimum duration in seconds", OFFSET(duration), AV_OPT_TYPE_DOUBLE, {.dbl=2.}, 0, 24*60*60, FLAGS }, - { "mono", "check each channel separately", OFFSET(mono), AV_OPT_TYPE_BOOL, {.i64=0.}, 0, 1, FLAGS }, + { "mono", "check each channel separately", OFFSET(mono), AV_OPT_TYPE_BOOL, {.i64=0.}, 0, 1, FLAGS }, + { "m", "check each channel separately", OFFSET(mono), AV_OPT_TYPE_BOOL, {.i64=0.}, 0, 1, FLAGS }, { NULL } }; @@ -77,12 +78,12 @@ static av_always_inline void update(SilenceDetectContext *s, AVFrame *insamples, int is_silence, int current_sample, int64_t nb_samples_notify, AVRational time_base) { - int channel = current_sample % s->independant_channels; + int channel = current_sample % s->independent_channels; if (is_silence) { if (s->start[channel] == INT64_MIN) { s->nb_null_samples[channel]++; if (s->nb_null_samples[channel] >= nb_samples_notify) { - s->start[channel] = insamples->pts + av_rescale_q(current_sample / s->channels + 1 - nb_samples_notify * s->independant_channels / s->channels, + s->start[channel] = insamples->pts + av_rescale_q(current_sample / s->channels + 1 - nb_samples_notify * s->independent_channels / s->channels, (AVRational){ 1, s->last_sample_rate }, time_base); set_meta(insamples, s->mono ? channel + 1 : 0, "silence_start", av_ts2timestr(s->start[channel], &time_base)); @@ -141,14 +142,14 @@ static int config_input(AVFilterLink *inlink) int c; s->channels = inlink->channels; - s->independant_channels = s->mono ? s->channels : 1; - s->nb_null_samples = av_mallocz_array(sizeof(*s->nb_null_samples), s->independant_channels); + s->independent_channels = s->mono ? s->channels : 1; + s->nb_null_samples = av_mallocz_array(sizeof(*s->nb_null_samples), s->independent_channels); if (!s->nb_null_samples) return AVERROR(ENOMEM); - s->start = av_malloc_array(sizeof(*s->start), s->independant_channels); + s->start = av_malloc_array(sizeof(*s->start), s->independent_channels); if (!s->start) return AVERROR(ENOMEM); - for (c = 0; c < s->independant_channels; c++) + for (c = 0; c < s->independent_channels; c++) s->start[c] = INT64_MIN; switch (inlink->format) { @@ -178,7 +179,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *insamples) // scale number of null samples to the new sample rate if (s->last_sample_rate && s->last_sample_rate != srate) - for (c = 0; c < s->independant_channels; c++) { + for (c = 0; c < s->independent_channels; c++) { s->nb_null_samples[c] = srate * s->nb_null_samples[c] / s->last_sample_rate; } s->last_sample_rate = srate; @@ -231,7 +232,7 @@ static av_cold void uninit(AVFilterContext *ctx) SilenceDetectContext *s = ctx->priv; int c; - for (c = 0; c < s->independant_channels; c++) + for (c = 0; c < s->independent_channels; c++) if (s->start[c] > INT64_MIN) update(s, NULL, 0, c, 0, s->time_base); av_freep(&s->nb_null_samples); diff --git a/libavfilter/af_silenceremove.c b/libavfilter/af_silenceremove.c index d826a22e9..7dd8c5a1d 100644 --- a/libavfilter/af_silenceremove.c +++ b/libavfilter/af_silenceremove.c @@ -30,6 +30,16 @@ #include "avfilter.h" #include "internal.h" +enum SilenceDetect { + D_PEAK, + D_RMS, +}; + +enum ThresholdMode { + T_ANY, + T_ALL, +}; + enum SilenceMode { SILENCE_TRIM, SILENCE_TRIM_FLUSH, @@ -45,20 +55,34 @@ typedef struct SilenceRemoveContext { int start_periods; int64_t start_duration; + int64_t start_duration_opt; double start_threshold; + int64_t start_silence; + int64_t start_silence_opt; + int start_mode; int stop_periods; int64_t stop_duration; + int64_t stop_duration_opt; double stop_threshold; + int64_t stop_silence; + int64_t stop_silence_opt; + int stop_mode; double *start_holdoff; + double *start_silence_hold; size_t start_holdoff_offset; size_t start_holdoff_end; + size_t start_silence_offset; + size_t start_silence_end; int start_found_periods; double *stop_holdoff; + double *stop_silence_hold; size_t stop_holdoff_offset; size_t stop_holdoff_end; + size_t stop_silence_offset; + size_t stop_silence_end; int stop_found_periods; double window_ratio; @@ -68,7 +92,6 @@ typedef struct SilenceRemoveContext { int window_size; double sum; - int leave_silence; int restart; int64_t next_pts; @@ -78,19 +101,25 @@ typedef struct SilenceRemoveContext { } SilenceRemoveContext; #define OFFSET(x) offsetof(SilenceRemoveContext, x) -#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_AUDIO_PARAM +#define AF AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_AUDIO_PARAM + static const AVOption silenceremove_options[] = { - { "start_periods", NULL, OFFSET(start_periods), AV_OPT_TYPE_INT, {.i64=0}, 0, 9000, FLAGS }, - { "start_duration", NULL, OFFSET(start_duration), AV_OPT_TYPE_DURATION, {.i64=0}, 0, 9000, FLAGS }, - { "start_threshold", NULL, OFFSET(start_threshold), AV_OPT_TYPE_DOUBLE, {.dbl=0}, 0, DBL_MAX, FLAGS }, - { "stop_periods", NULL, OFFSET(stop_periods), AV_OPT_TYPE_INT, {.i64=0}, -9000, 9000, FLAGS }, - { "stop_duration", NULL, OFFSET(stop_duration), AV_OPT_TYPE_DURATION, {.i64=0}, 0, 9000, FLAGS }, - { "stop_threshold", NULL, OFFSET(stop_threshold), AV_OPT_TYPE_DOUBLE, {.dbl=0}, 0, DBL_MAX, FLAGS }, - { "leave_silence", NULL, OFFSET(leave_silence), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS }, - { "detection", NULL, OFFSET(detection), AV_OPT_TYPE_INT, {.i64=1}, 0, 1, FLAGS, "detection" }, - { "peak", 0, 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, FLAGS, "detection" }, - { "rms", 0, 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, FLAGS, "detection" }, - { "window", NULL, OFFSET(window_ratio), AV_OPT_TYPE_DOUBLE, {.dbl=0.02}, 0, 10, FLAGS }, + { "start_periods", NULL, OFFSET(start_periods), AV_OPT_TYPE_INT, {.i64=0}, 0, 9000, AF }, + { "start_duration", "set start duration of non-silence part", OFFSET(start_duration_opt), AV_OPT_TYPE_DURATION, {.i64=0}, 0, INT32_MAX, AF }, + { "start_threshold", "set threshold for start silence detection", OFFSET(start_threshold), AV_OPT_TYPE_DOUBLE, {.dbl=0}, 0, DBL_MAX, AF }, + { "start_silence", "set start duration of silence part to keep", OFFSET(start_silence_opt), AV_OPT_TYPE_DURATION, {.i64=0}, 0, INT32_MAX, AF }, + { "start_mode", "set which channel will trigger trimming from start", OFFSET(start_mode), AV_OPT_TYPE_INT, {.i64=T_ANY}, T_ANY, T_ALL, AF, "mode" }, + { "any", 0, 0, AV_OPT_TYPE_CONST, {.i64=T_ANY}, 0, 0, AF, "mode" }, + { "all", 0, 0, AV_OPT_TYPE_CONST, {.i64=T_ALL}, 0, 0, AF, "mode" }, + { "stop_periods", NULL, OFFSET(stop_periods), AV_OPT_TYPE_INT, {.i64=0}, -9000, 9000, AF }, + { "stop_duration", "set stop duration of non-silence part", OFFSET(stop_duration_opt), AV_OPT_TYPE_DURATION, {.i64=0}, 0, INT32_MAX, AF }, + { "stop_threshold", "set threshold for stop silence detection", OFFSET(stop_threshold), AV_OPT_TYPE_DOUBLE, {.dbl=0}, 0, DBL_MAX, AF }, + { "stop_silence", "set stop duration of silence part to keep", OFFSET(stop_silence_opt), AV_OPT_TYPE_DURATION, {.i64=0}, 0, INT32_MAX, AF }, + { "stop_mode", "set which channel will trigger trimming from end", OFFSET(stop_mode), AV_OPT_TYPE_INT, {.i64=T_ANY}, T_ANY, T_ALL, AF, "mode" }, + { "detection", "set how silence is detected", OFFSET(detection), AV_OPT_TYPE_INT, {.i64=D_RMS}, D_PEAK,D_RMS, AF, "detection" }, + { "peak", "use absolute values of samples", 0, AV_OPT_TYPE_CONST, {.i64=D_PEAK},0, 0, AF, "detection" }, + { "rms", "use squared values of samples", 0, AV_OPT_TYPE_CONST, {.i64=D_RMS}, 0, 0, AF, "detection" }, + { "window", "set duration of window in seconds", OFFSET(window_ratio), AV_OPT_TYPE_DOUBLE, {.dbl=0.02}, 0, 10, AF }, { NULL } }; @@ -150,15 +179,15 @@ static av_cold int init(AVFilterContext *ctx) } switch (s->detection) { - case 0: + case D_PEAK: s->update = update_peak; s->compute = compute_peak; break; - case 1: + case D_RMS: s->update = update_rms; s->compute = compute_rms; break; - }; + } return 0; } @@ -177,6 +206,7 @@ static int config_input(AVFilterLink *inlink) AVFilterContext *ctx = inlink->dst; SilenceRemoveContext *s = ctx->priv; + s->next_pts = AV_NOPTS_VALUE; s->window_size = FFMAX((inlink->sample_rate * s->window_ratio), 1) * inlink->channels; s->window = av_malloc_array(s->window_size, sizeof(*s->window)); if (!s->window) @@ -184,19 +214,14 @@ static int config_input(AVFilterLink *inlink) clear_window(s); - s->start_duration = av_rescale(s->start_duration, inlink->sample_rate, + s->start_duration = av_rescale(s->start_duration_opt, inlink->sample_rate, AV_TIME_BASE); - if (s->start_duration < 0) { - av_log(ctx, AV_LOG_WARNING, "start duration must be non-negative\n"); - s->start_duration = -s->start_duration; - } - - s->stop_duration = av_rescale(s->stop_duration, inlink->sample_rate, + s->start_silence = av_rescale(s->start_silence_opt, inlink->sample_rate, + AV_TIME_BASE); + s->stop_duration = av_rescale(s->stop_duration_opt, inlink->sample_rate, + AV_TIME_BASE); + s->stop_silence = av_rescale(s->stop_silence_opt, inlink->sample_rate, AV_TIME_BASE); - if (s->stop_duration < 0) { - av_log(ctx, AV_LOG_WARNING, "stop duration must be non-negative\n"); - s->stop_duration = -s->stop_duration; - } s->start_holdoff = av_malloc_array(FFMAX(s->start_duration, 1), sizeof(*s->start_holdoff) * @@ -204,6 +229,12 @@ static int config_input(AVFilterLink *inlink) if (!s->start_holdoff) return AVERROR(ENOMEM); + s->start_silence_hold = av_malloc_array(FFMAX(s->start_silence, 1), + sizeof(*s->start_silence_hold) * + inlink->channels); + if (!s->start_silence_hold) + return AVERROR(ENOMEM); + s->start_holdoff_offset = 0; s->start_holdoff_end = 0; s->start_found_periods = 0; @@ -214,6 +245,12 @@ static int config_input(AVFilterLink *inlink) if (!s->stop_holdoff) return AVERROR(ENOMEM); + s->stop_silence_hold = av_malloc_array(FFMAX(s->stop_silence, 1), + sizeof(*s->stop_silence_hold) * + inlink->channels); + if (!s->stop_silence_hold) + return AVERROR(ENOMEM); + s->stop_holdoff_offset = 0; s->stop_holdoff_end = 0; s->stop_found_periods = 0; @@ -228,8 +265,10 @@ static int config_input(AVFilterLink *inlink) static void flush(SilenceRemoveContext *s, AVFrame *out, AVFilterLink *outlink, - int *nb_samples_written, int *ret) + int *nb_samples_written, int *ret, int flush_silence) { + AVFrame *silence; + if (*nb_samples_written) { out->nb_samples = *nb_samples_written / outlink->channels; @@ -239,10 +278,43 @@ static void flush(SilenceRemoveContext *s, outlink->time_base); *ret = ff_filter_frame(outlink, out); + if (*ret < 0) + return; *nb_samples_written = 0; } else { av_frame_free(&out); } + + if (s->stop_silence_end <= 0 || !flush_silence) + return; + + silence = ff_get_audio_buffer(outlink, s->stop_silence_end / outlink->channels); + if (!silence) { + *ret = AVERROR(ENOMEM); + return; + } + + if (s->stop_silence_offset < s->stop_silence_end) { + memcpy(silence->data[0], + &s->stop_silence_hold[s->stop_silence_offset], + (s->stop_silence_end - s->stop_silence_offset) * sizeof(double)); + } + + if (s->stop_silence_offset > 0) { + memcpy(silence->data[0] + (s->stop_silence_end - s->stop_silence_offset) * sizeof(double), + &s->stop_silence_hold[0], + s->stop_silence_offset * sizeof(double)); + } + + s->stop_silence_offset = 0; + s->stop_silence_end = 0; + + silence->pts = s->next_pts; + s->next_pts += av_rescale_q(silence->nb_samples, + (AVRational){1, outlink->sample_rate}, + outlink->time_base); + + *ret = ff_filter_frame(outlink, silence); } static int filter_frame(AVFilterLink *inlink, AVFrame *in) @@ -257,27 +329,37 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) nb_samples_read = nb_samples_written = 0; + if (s->next_pts == AV_NOPTS_VALUE) + s->next_pts = in->pts; + switch (s->mode) { case SILENCE_TRIM: silence_trim: - nbs = in->nb_samples - nb_samples_read / inlink->channels; + nbs = in->nb_samples - nb_samples_read / outlink->channels; if (!nbs) break; for (i = 0; i < nbs; i++) { - threshold = 0; - for (j = 0; j < inlink->channels; j++) { - threshold |= s->compute(s, ibuf[j]) > s->start_threshold; + if (s->start_mode == T_ANY) { + threshold = 0; + for (j = 0; j < outlink->channels; j++) { + threshold |= s->compute(s, ibuf[j]) > s->start_threshold; + } + } else { + threshold = 1; + for (j = 0; j < outlink->channels; j++) { + threshold &= s->compute(s, ibuf[j]) > s->start_threshold; + } } if (threshold) { - for (j = 0; j < inlink->channels; j++) { + for (j = 0; j < outlink->channels; j++) { s->update(s, *ibuf); s->start_holdoff[s->start_holdoff_end++] = *ibuf++; } - nb_samples_read += inlink->channels; + nb_samples_read += outlink->channels; - if (s->start_holdoff_end >= s->start_duration * inlink->channels) { + if (s->start_holdoff_end >= s->start_duration * outlink->channels) { if (++s->start_found_periods >= s->start_periods) { s->mode = SILENCE_TRIM_FLUSH; goto silence_trim_flush; @@ -285,15 +367,25 @@ silence_trim: s->start_holdoff_offset = 0; s->start_holdoff_end = 0; + s->start_silence_offset = 0; + s->start_silence_end = 0; } } else { s->start_holdoff_end = 0; - for (j = 0; j < inlink->channels; j++) + for (j = 0; j < outlink->channels; j++) { s->update(s, ibuf[j]); + if (s->start_silence) { + s->start_silence_hold[s->start_silence_offset++] = ibuf[j]; + s->start_silence_end = FFMIN(s->start_silence_end + 1, outlink->channels * s->start_silence); + if (s->start_silence_offset >= outlink->channels * s->start_silence) { + s->start_silence_offset = 0; + } + } + } - ibuf += inlink->channels; - nb_samples_read += inlink->channels; + ibuf += outlink->channels; + nb_samples_read += outlink->channels; } } break; @@ -301,17 +393,32 @@ silence_trim: case SILENCE_TRIM_FLUSH: silence_trim_flush: nbs = s->start_holdoff_end - s->start_holdoff_offset; - nbs -= nbs % inlink->channels; + nbs -= nbs % outlink->channels; if (!nbs) break; - out = ff_get_audio_buffer(inlink, nbs / inlink->channels); + out = ff_get_audio_buffer(outlink, nbs / outlink->channels + s->start_silence_end / outlink->channels); if (!out) { av_frame_free(&in); return AVERROR(ENOMEM); } - memcpy(out->data[0], &s->start_holdoff[s->start_holdoff_offset], + if (s->start_silence_end > 0) { + if (s->start_silence_offset < s->start_silence_end) { + memcpy(out->data[0], + &s->start_silence_hold[s->start_silence_offset], + (s->start_silence_end - s->start_silence_offset) * sizeof(double)); + } + + if (s->start_silence_offset > 0) { + memcpy(out->data[0] + (s->start_silence_end - s->start_silence_offset) * sizeof(double), + &s->start_silence_hold[0], + s->start_silence_offset * sizeof(double)); + } + } + + memcpy(out->data[0] + s->start_silence_end * sizeof(double), + &s->start_holdoff[s->start_holdoff_offset], nbs * sizeof(double)); out->pts = s->next_pts; @@ -326,6 +433,8 @@ silence_trim_flush: if (s->start_holdoff_offset == s->start_holdoff_end) { s->start_holdoff_offset = 0; s->start_holdoff_end = 0; + s->start_silence_offset = 0; + s->start_silence_end = 0; s->mode = SILENCE_COPY; goto silence_copy; } @@ -333,11 +442,11 @@ silence_trim_flush: case SILENCE_COPY: silence_copy: - nbs = in->nb_samples - nb_samples_read / inlink->channels; + nbs = in->nb_samples - nb_samples_read / outlink->channels; if (!nbs) break; - out = ff_get_audio_buffer(inlink, nbs); + out = ff_get_audio_buffer(outlink, nbs); if (!out) { av_frame_free(&in); return AVERROR(ENOMEM); @@ -346,62 +455,75 @@ silence_copy: if (s->stop_periods) { for (i = 0; i < nbs; i++) { - threshold = 1; - for (j = 0; j < inlink->channels; j++) - threshold &= s->compute(s, ibuf[j]) > s->stop_threshold; + if (s->stop_mode == T_ANY) { + threshold = 0; + for (j = 0; j < outlink->channels; j++) { + threshold |= s->compute(s, ibuf[j]) > s->stop_threshold; + } + } else { + threshold = 1; + for (j = 0; j < outlink->channels; j++) { + threshold &= s->compute(s, ibuf[j]) > s->stop_threshold; + } + } - if (threshold && s->stop_holdoff_end && !s->leave_silence) { + if (threshold && s->stop_holdoff_end && !s->stop_silence) { s->mode = SILENCE_COPY_FLUSH; - flush(s, out, outlink, &nb_samples_written, &ret); + flush(s, out, outlink, &nb_samples_written, &ret, 0); goto silence_copy_flush; } else if (threshold) { - for (j = 0; j < inlink->channels; j++) { + for (j = 0; j < outlink->channels; j++) { s->update(s, *ibuf); *obuf++ = *ibuf++; } - nb_samples_read += inlink->channels; - nb_samples_written += inlink->channels; + nb_samples_read += outlink->channels; + nb_samples_written += outlink->channels; } else if (!threshold) { - for (j = 0; j < inlink->channels; j++) { + for (j = 0; j < outlink->channels; j++) { s->update(s, *ibuf); - if (s->leave_silence) { - *obuf++ = *ibuf; - nb_samples_written++; + if (s->stop_silence) { + s->stop_silence_hold[s->stop_silence_offset++] = *ibuf; + s->stop_silence_end = FFMIN(s->stop_silence_end + 1, outlink->channels * s->stop_silence); + if (s->stop_silence_offset >= outlink->channels * s->stop_silence) { + s->stop_silence_offset = 0; + } } s->stop_holdoff[s->stop_holdoff_end++] = *ibuf++; } - nb_samples_read += inlink->channels; + nb_samples_read += outlink->channels; - if (s->stop_holdoff_end >= s->stop_duration * inlink->channels) { + if (s->stop_holdoff_end >= s->stop_duration * outlink->channels) { if (++s->stop_found_periods >= s->stop_periods) { s->stop_holdoff_offset = 0; s->stop_holdoff_end = 0; if (!s->restart) { s->mode = SILENCE_STOP; - flush(s, out, outlink, &nb_samples_written, &ret); + flush(s, out, outlink, &nb_samples_written, &ret, 1); goto silence_stop; } else { s->stop_found_periods = 0; s->start_found_periods = 0; s->start_holdoff_offset = 0; s->start_holdoff_end = 0; + s->start_silence_offset = 0; + s->start_silence_end = 0; clear_window(s); s->mode = SILENCE_TRIM; - flush(s, out, outlink, &nb_samples_written, &ret); + flush(s, out, outlink, &nb_samples_written, &ret, 1); goto silence_trim; } } s->mode = SILENCE_COPY_FLUSH; - flush(s, out, outlink, &nb_samples_written, &ret); + flush(s, out, outlink, &nb_samples_written, &ret, 0); goto silence_copy_flush; } } } - flush(s, out, outlink, &nb_samples_written, &ret); + flush(s, out, outlink, &nb_samples_written, &ret, 0); } else { - memcpy(obuf, ibuf, sizeof(double) * nbs * inlink->channels); + memcpy(obuf, ibuf, sizeof(double) * nbs * outlink->channels); out->pts = s->next_pts; s->next_pts += av_rescale_q(out->nb_samples, @@ -415,11 +537,11 @@ silence_copy: case SILENCE_COPY_FLUSH: silence_copy_flush: nbs = s->stop_holdoff_end - s->stop_holdoff_offset; - nbs -= nbs % inlink->channels; + nbs -= nbs % outlink->channels; if (!nbs) break; - out = ff_get_audio_buffer(inlink, nbs / inlink->channels); + out = ff_get_audio_buffer(outlink, nbs / outlink->channels); if (!out) { av_frame_free(&in); return AVERROR(ENOMEM); @@ -439,6 +561,8 @@ silence_copy_flush: if (s->stop_holdoff_offset == s->stop_holdoff_end) { s->stop_holdoff_offset = 0; s->stop_holdoff_end = 0; + s->stop_silence_offset = 0; + s->stop_silence_end = 0; s->mode = SILENCE_COPY; goto silence_copy; } @@ -519,7 +643,9 @@ static av_cold void uninit(AVFilterContext *ctx) SilenceRemoveContext *s = ctx->priv; av_freep(&s->start_holdoff); + av_freep(&s->start_silence_hold); av_freep(&s->stop_holdoff); + av_freep(&s->stop_silence_hold); av_freep(&s->window); } diff --git a/libavfilter/af_sofalizer.c b/libavfilter/af_sofalizer.c index d9098d767..ccf3872e7 100644 --- a/libavfilter/af_sofalizer.c +++ b/libavfilter/af_sofalizer.c @@ -35,6 +35,7 @@ #include "libavutil/intmath.h" #include "libavutil/opt.h" #include "avfilter.h" +#include "filters.h" #include "internal.h" #include "audio.h" @@ -42,9 +43,13 @@ #define FREQUENCY_DOMAIN 1 typedef struct MySofa { /* contains data of one SOFA file */ - struct MYSOFA_EASY *easy; - int n_samples; /* length of one impulse response (IR) */ + struct MYSOFA_HRTF *hrtf; + struct MYSOFA_LOOKUP *lookup; + struct MYSOFA_NEIGHBORHOOD *neighborhood; + int ir_samples; /* length of one impulse response (IR) */ + int n_samples; /* ir_samples to next power of 2 */ float *lir, *rir; /* IRs (time-domain) */ + float *fir; int max_delay; } MySofa; @@ -77,6 +82,7 @@ typedef struct SOFAlizerContext { int buffer_length; /* is: longest IR plus max. delay in all SOFA files */ /* then choose next power of 2 */ int n_fft; /* number of samples in one FFT block */ + int nb_samples; /* netCDF variables */ int *delay[2]; /* broadband delay for each channel/IR to be convolved */ @@ -84,7 +90,8 @@ typedef struct SOFAlizerContext { float *data_ir[2]; /* IRs for all channels to be convolved */ /* (this excludes the LFE) */ float *temp_src[2]; - FFTComplex *temp_fft[2]; + FFTComplex *temp_fft[2]; /* Array to hold FFT values */ + FFTComplex *temp_afft[2]; /* Array to accumulate FFT values prior to IFFT */ /* control variables */ float gain; /* filter gain (in dB) */ @@ -92,6 +99,12 @@ typedef struct SOFAlizerContext { float elevation; /* elevation of virtual loudspeakers (in deg.) */ float radius; /* distance virtual loudspeakers to listener (in metres) */ int type; /* processing type */ + int framesize; /* size of buffer */ + int normalize; /* should all IRs be normalized upon import ? */ + int interpolate; /* should wanted IRs be interpolated from neighbors ? */ + int minphase; /* should all IRs be minphased upon import ? */ + float anglestep; /* neighbor search angle step, in agles */ + float radstep; /* neighbor search radius step, in meters */ VirtualSpeaker vspkrpos[64]; @@ -103,8 +116,16 @@ typedef struct SOFAlizerContext { static int close_sofa(struct MySofa *sofa) { - mysofa_close(sofa->easy); - sofa->easy = NULL; + if (sofa->neighborhood) + mysofa_neighborhood_free(sofa->neighborhood); + sofa->neighborhood = NULL; + if (sofa->lookup) + mysofa_lookup_free(sofa->lookup); + sofa->lookup = NULL; + if (sofa->hrtf) + mysofa_free(sofa->hrtf); + sofa->hrtf = NULL; + av_freep(&sofa->fir); return 0; } @@ -113,19 +134,51 @@ static int preload_sofa(AVFilterContext *ctx, char *filename, int *samplingrate) { struct SOFAlizerContext *s = ctx->priv; struct MYSOFA_HRTF *mysofa; + char *license; int ret; mysofa = mysofa_load(filename, &ret); + s->sofa.hrtf = mysofa; if (ret || !mysofa) { av_log(ctx, AV_LOG_ERROR, "Can't find SOFA-file '%s'\n", filename); return AVERROR(EINVAL); } + ret = mysofa_check(mysofa); + if (ret != MYSOFA_OK) { + av_log(ctx, AV_LOG_ERROR, "Selected SOFA file is invalid. Please select valid SOFA file.\n"); + return ret; + } + + if (s->normalize) + mysofa_loudness(s->sofa.hrtf); + + if (s->minphase) + mysofa_minphase(s->sofa.hrtf, 0.01f); + + mysofa_tocartesian(s->sofa.hrtf); + + s->sofa.lookup = mysofa_lookup_init(s->sofa.hrtf); + if (s->sofa.lookup == NULL) + return AVERROR(EINVAL); + + if (s->interpolate) + s->sofa.neighborhood = mysofa_neighborhood_init_withstepdefine(s->sofa.hrtf, + s->sofa.lookup, + s->anglestep, + s->radstep); + + s->sofa.fir = av_calloc(s->sofa.hrtf->N * s->sofa.hrtf->R, sizeof(*s->sofa.fir)); + if (!s->sofa.fir) + return AVERROR(ENOMEM); + if (mysofa->DataSamplingRate.elements != 1) return AVERROR(EINVAL); + av_log(ctx, AV_LOG_DEBUG, "Original IR length: %d.\n", mysofa->N); *samplingrate = mysofa->DataSamplingRate.values[0]; - s->sofa.n_samples = mysofa->N; - mysofa_free(mysofa); + license = mysofa_getAttribute(mysofa->attributes, (char *)"License"); + if (license) + av_log(ctx, AV_LOG_INFO, "SOFA license: %s\n", license); return 0; } @@ -136,7 +189,7 @@ static int parse_channel_name(char **arg, int *rchannel, char *buf) int64_t layout, layout0; /* try to parse a channel name, e.g. "FL" */ - if (sscanf(*arg, "%7[A-Z]%n", buf, &len)) { + if (av_sscanf(*arg, "%7[A-Z]%n", buf, &len)) { layout0 = layout = av_get_channel_layout(buf); /* channel_id <- first set bit in layout */ for (i = 32; i > 0; i >>= 1) { @@ -174,11 +227,11 @@ static void parse_speaker_pos(AVFilterContext *ctx, int64_t in_channel_layout) av_log(ctx, AV_LOG_WARNING, "Failed to parse \'%s\' as channel name.\n", buf); continue; } - if (sscanf(arg, "%f %f", &azim, &elev) == 2) { + if (av_sscanf(arg, "%f %f", &azim, &elev) == 2) { s->vspkrpos[out_ch_id].set = 1; s->vspkrpos[out_ch_id].azim = azim; s->vspkrpos[out_ch_id].elev = elev; - } else if (sscanf(arg, "%f", &azim) == 1) { + } else if (av_sscanf(arg, "%f", &azim) == 1) { s->vspkrpos[out_ch_id].set = 1; s->vspkrpos[out_ch_id].azim = azim; s->vspkrpos[out_ch_id].elev = 0; @@ -272,6 +325,7 @@ typedef struct ThreadData { float **ringbuffer; float **temp_src; FFTComplex **temp_fft; + FFTComplex **temp_afft; } ThreadData; static int sofalizer_convolute(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) @@ -286,9 +340,12 @@ static int sofalizer_convolute(AVFilterContext *ctx, void *arg, int jobnr, int n int *n_clippings = &td->n_clippings[jobnr]; float *ringbuffer = td->ringbuffer[jobnr]; float *temp_src = td->temp_src[jobnr]; - const int n_samples = s->sofa.n_samples; /* length of one IR */ - const float *src = (const float *)in->data[0]; /* get pointer to audio input buffer */ - float *dst = (float *)out->data[0]; /* get pointer to audio output buffer */ + const int ir_samples = s->sofa.ir_samples; /* length of one IR */ + const int n_samples = s->sofa.n_samples; + const int planar = in->format == AV_SAMPLE_FMT_FLTP; + const int mult = 1 + !planar; + const float *src = (const float *)in->extended_data[0]; /* get pointer to audio input buffer */ + float *dst = (float *)out->extended_data[jobnr * planar]; /* get pointer to audio output buffer */ const int in_channels = s->n_conv; /* number of input channels */ /* ring buffer length is: longest IR plus max. delay -> next power of 2 */ const int buffer_length = s->buffer_length; @@ -299,7 +356,9 @@ static int sofalizer_convolute(AVFilterContext *ctx, void *arg, int jobnr, int n int read; int i, l; - dst += offset; + if (!planar) + dst += offset; + for (l = 0; l < in_channels; l++) { /* get starting address of ringbuffer for each input channel */ buffer[l] = ringbuffer + l * buffer_length; @@ -309,9 +368,18 @@ static int sofalizer_convolute(AVFilterContext *ctx, void *arg, int jobnr, int n const float *temp_ir = ir; /* using same set of IRs for each sample */ dst[0] = 0; - for (l = 0; l < in_channels; l++) { - /* write current input sample to ringbuffer (for each channel) */ - buffer[l][wr] = src[l]; + if (planar) { + for (l = 0; l < in_channels; l++) { + const float *srcp = (const float *)in->extended_data[l]; + + /* write current input sample to ringbuffer (for each channel) */ + buffer[l][wr] = srcp[i]; + } + } else { + for (l = 0; l < in_channels; l++) { + /* write current input sample to ringbuffer (for each channel) */ + buffer[l][wr] = src[l]; + } } /* loop goes through all channels to be convolved */ @@ -321,36 +389,36 @@ static int sofalizer_convolute(AVFilterContext *ctx, void *arg, int jobnr, int n if (l == s->lfe_channel) { /* LFE is an input channel but requires no convolution */ /* apply gain to LFE signal and add to output buffer */ - *dst += *(buffer[s->lfe_channel] + wr) * s->gain_lfe; - temp_ir += FFALIGN(n_samples, 32); + dst[0] += *(buffer[s->lfe_channel] + wr) * s->gain_lfe; + temp_ir += n_samples; continue; } /* current read position in ringbuffer: input sample write position * - delay for l-th ch. + diff. betw. IR length and buffer length * (mod buffer length) */ - read = (wr - delay[l] - (n_samples - 1) + buffer_length) & modulo; + read = (wr - delay[l] - (ir_samples - 1) + buffer_length) & modulo; - if (read + n_samples < buffer_length) { - memmove(temp_src, bptr + read, n_samples * sizeof(*temp_src)); + if (read + ir_samples < buffer_length) { + memmove(temp_src, bptr + read, ir_samples * sizeof(*temp_src)); } else { - int len = FFMIN(n_samples - (read % n_samples), buffer_length - read); + int len = FFMIN(n_samples - (read % ir_samples), buffer_length - read); memmove(temp_src, bptr + read, len * sizeof(*temp_src)); memmove(temp_src + len, bptr, (n_samples - len) * sizeof(*temp_src)); } /* multiply signal and IR, and add up the results */ - dst[0] += s->fdsp->scalarproduct_float(temp_ir, temp_src, n_samples); - temp_ir += FFALIGN(n_samples, 32); + dst[0] += s->fdsp->scalarproduct_float(temp_ir, temp_src, FFALIGN(ir_samples, 32)); + temp_ir += n_samples; } /* clippings counter */ - if (fabs(dst[0]) > 1) - *n_clippings += 1; + if (fabsf(dst[0]) > 1) + n_clippings[0]++; /* move output buffer pointer by +2 to get to next sample of processed channel: */ - dst += 2; + dst += mult; src += in_channels; wr = (wr + 1) & modulo; /* update ringbuffer write position */ } @@ -370,15 +438,17 @@ static int sofalizer_fast_convolute(AVFilterContext *ctx, void *arg, int jobnr, FFTComplex *hrtf = s->data_hrtf[jobnr]; /* get pointers to current HRTF data */ int *n_clippings = &td->n_clippings[jobnr]; float *ringbuffer = td->ringbuffer[jobnr]; - const int n_samples = s->sofa.n_samples; /* length of one IR */ - const float *src = (const float *)in->data[0]; /* get pointer to audio input buffer */ - float *dst = (float *)out->data[0]; /* get pointer to audio output buffer */ + const int ir_samples = s->sofa.ir_samples; /* length of one IR */ + const int planar = in->format == AV_SAMPLE_FMT_FLTP; + const int mult = 1 + !planar; + float *dst = (float *)out->extended_data[jobnr * planar]; /* get pointer to audio output buffer */ const int in_channels = s->n_conv; /* number of input channels */ /* ring buffer length is: longest IR plus max. delay -> next power of 2 */ const int buffer_length = s->buffer_length; /* -1 for AND instead of MODULO (applied to powers of 2): */ const uint32_t modulo = (uint32_t)buffer_length - 1; FFTComplex *fft_in = s->temp_fft[jobnr]; /* temporary array for FFT input/output data */ + FFTComplex *fft_acc = s->temp_afft[jobnr]; FFTContext *ifft = s->ifft[jobnr]; FFTContext *fft = s->fft[jobnr]; const int n_conv = s->n_conv; @@ -389,29 +459,42 @@ static int sofalizer_fast_convolute(AVFilterContext *ctx, void *arg, int jobnr, int n_read; int i, j; - dst += offset; + if (!planar) + dst += offset; /* find minimum between number of samples and output buffer length: * (important, if one IR is longer than the output buffer) */ - n_read = FFMIN(s->sofa.n_samples, in->nb_samples); + n_read = FFMIN(ir_samples, in->nb_samples); for (j = 0; j < n_read; j++) { /* initialize output buf with saved signal from overflow buf */ - dst[2 * j] = ringbuffer[wr]; - ringbuffer[wr] = 0.0; /* re-set read samples to zero */ + dst[mult * j] = ringbuffer[wr]; + ringbuffer[wr] = 0.0f; /* re-set read samples to zero */ /* update ringbuffer read/write position */ wr = (wr + 1) & modulo; } /* initialize rest of output buffer with 0 */ for (j = n_read; j < in->nb_samples; j++) { - dst[2 * j] = 0; + dst[mult * j] = 0; } + /* fill FFT accumulation with 0 */ + memset(fft_acc, 0, sizeof(FFTComplex) * n_fft); + for (i = 0; i < n_conv; i++) { + const float *src = (const float *)in->extended_data[i * planar]; /* get pointer to audio input buffer */ + if (i == s->lfe_channel) { /* LFE */ - for (j = 0; j < in->nb_samples; j++) { - /* apply gain to LFE signal and add to output buffer */ - dst[2 * j] += src[i + j * in_channels] * s->gain_lfe; + if (in->format == AV_SAMPLE_FMT_FLT) { + for (j = 0; j < in->nb_samples; j++) { + /* apply gain to LFE signal and add to output buffer */ + dst[2 * j] += src[i + j * in_channels] * s->gain_lfe; + } + } else { + for (j = 0; j < in->nb_samples; j++) { + /* apply gain to LFE signal and add to output buffer */ + dst[j] += src[j] * s->gain_lfe; + } } continue; } @@ -423,10 +506,18 @@ static int sofalizer_fast_convolute(AVFilterContext *ctx, void *arg, int jobnr, /* fill FFT input with 0 (we want to zero-pad) */ memset(fft_in, 0, sizeof(FFTComplex) * n_fft); - for (j = 0; j < in->nb_samples; j++) { - /* prepare input for FFT */ - /* write all samples of current input channel to FFT input array */ - fft_in[j].re = src[j * in_channels + i]; + if (in->format == AV_SAMPLE_FMT_FLT) { + for (j = 0; j < in->nb_samples; j++) { + /* prepare input for FFT */ + /* write all samples of current input channel to FFT input array */ + fft_in[j].re = src[j * in_channels + i]; + } + } else { + for (j = 0; j < in->nb_samples; j++) { + /* prepare input for FFT */ + /* write all samples of current input channel to FFT input array */ + fft_in[j].re = src[j]; + } } /* transform input signal of current channel to frequency domain */ @@ -439,37 +530,34 @@ static int sofalizer_fast_convolute(AVFilterContext *ctx, void *arg, int jobnr, /* complex multiplication of input signal and HRTFs */ /* output channel (real): */ - fft_in[j].re = re * hcomplex->re - im * hcomplex->im; + fft_acc[j].re += re * hcomplex->re - im * hcomplex->im; /* output channel (imag): */ - fft_in[j].im = re * hcomplex->im + im * hcomplex->re; + fft_acc[j].im += re * hcomplex->im + im * hcomplex->re; } + } - /* transform output signal of current channel back to time domain */ - av_fft_permute(ifft, fft_in); - av_fft_calc(ifft, fft_in); + /* transform output signal of current channel back to time domain */ + av_fft_permute(ifft, fft_acc); + av_fft_calc(ifft, fft_acc); - for (j = 0; j < in->nb_samples; j++) { - /* write output signal of current channel to output buffer */ - dst[2 * j] += fft_in[j].re * fft_scale; - } + for (j = 0; j < in->nb_samples; j++) { + /* write output signal of current channel to output buffer */ + dst[mult * j] += fft_acc[j].re * fft_scale; + } - for (j = 0; j < n_samples - 1; j++) { /* overflow length is IR length - 1 */ - /* write the rest of output signal to overflow buffer */ - int write_pos = (wr + j) & modulo; + for (j = 0; j < ir_samples - 1; j++) { /* overflow length is IR length - 1 */ + /* write the rest of output signal to overflow buffer */ + int write_pos = (wr + j) & modulo; - *(ringbuffer + write_pos) += fft_in[in->nb_samples + j].re * fft_scale; - } + *(ringbuffer + write_pos) += fft_acc[in->nb_samples + j].re * fft_scale; } /* go through all samples of current output buffer: count clippings */ for (i = 0; i < out->nb_samples; i++) { /* clippings counter */ - if (fabs(*dst) > 1) { /* if current output sample > 1 */ + if (fabsf(dst[i * mult]) > 1) { /* if current output sample > 1 */ n_clippings[0]++; } - - /* move output buffer pointer by +2 to get to next sample of processed channel: */ - dst += 2; } /* remember read/write position in ringbuffer for next call */ @@ -498,10 +586,11 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) td.delay = s->delay; td.ir = s->data_ir; td.n_clippings = n_clippings; td.ringbuffer = s->ringbuffer; td.temp_src = s->temp_src; td.temp_fft = s->temp_fft; + td.temp_afft = s->temp_afft; if (s->type == TIME_DOMAIN) { ctx->internal->execute(ctx, sofalizer_convolute, &td, NULL, 2); - } else { + } else if (s->type == FREQUENCY_DOMAIN) { ctx->internal->execute(ctx, sofalizer_fast_convolute, &td, NULL, 2); } emms_c(); @@ -516,16 +605,45 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) return ff_filter_frame(outlink, out); } +static int activate(AVFilterContext *ctx) +{ + AVFilterLink *inlink = ctx->inputs[0]; + AVFilterLink *outlink = ctx->outputs[0]; + SOFAlizerContext *s = ctx->priv; + AVFrame *in; + int ret; + + FF_FILTER_FORWARD_STATUS_BACK(outlink, inlink); + + if (s->nb_samples) + ret = ff_inlink_consume_samples(inlink, s->nb_samples, s->nb_samples, &in); + else + ret = ff_inlink_consume_frame(inlink, &in); + if (ret < 0) + return ret; + if (ret > 0) + return filter_frame(inlink, in); + + FF_FILTER_FORWARD_STATUS(inlink, outlink); + FF_FILTER_FORWARD_WANTED(outlink, inlink); + + return FFERROR_NOT_READY; +} + static int query_formats(AVFilterContext *ctx) { struct SOFAlizerContext *s = ctx->priv; AVFilterFormats *formats = NULL; AVFilterChannelLayouts *layouts = NULL; int ret, sample_rates[] = { 48000, -1 }; + static const enum AVSampleFormat sample_fmts[] = { + AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_FLTP, + AV_SAMPLE_FMT_NONE + }; - ret = ff_add_format(&formats, AV_SAMPLE_FMT_FLT); - if (ret) - return ret; + formats = ff_make_format_list(sample_fmts); + if (!formats) + return AVERROR(ENOMEM); ret = ff_set_common_formats(ctx, formats); if (ret) return ret; @@ -554,10 +672,55 @@ static int query_formats(AVFilterContext *ctx) return ff_set_common_samplerates(ctx, formats); } +static int getfilter_float(AVFilterContext *ctx, float x, float y, float z, + float *left, float *right, + float *delay_left, float *delay_right) +{ + struct SOFAlizerContext *s = ctx->priv; + float c[3], delays[2]; + float *fl, *fr; + int nearest; + int *neighbors; + float *res; + + c[0] = x, c[1] = y, c[2] = z; + nearest = mysofa_lookup(s->sofa.lookup, c); + if (nearest < 0) + return AVERROR(EINVAL); + + if (s->interpolate) { + neighbors = mysofa_neighborhood(s->sofa.neighborhood, nearest); + res = mysofa_interpolate(s->sofa.hrtf, c, + nearest, neighbors, + s->sofa.fir, delays); + } else { + if (s->sofa.hrtf->DataDelay.elements > s->sofa.hrtf->R) { + delays[0] = s->sofa.hrtf->DataDelay.values[nearest * s->sofa.hrtf->R]; + delays[1] = s->sofa.hrtf->DataDelay.values[nearest * s->sofa.hrtf->R + 1]; + } else { + delays[0] = s->sofa.hrtf->DataDelay.values[0]; + delays[1] = s->sofa.hrtf->DataDelay.values[1]; + } + res = s->sofa.hrtf->DataIR.values + nearest * s->sofa.hrtf->N * s->sofa.hrtf->R; + } + + *delay_left = delays[0]; + *delay_right = delays[1]; + + fl = res; + fr = res + s->sofa.hrtf->N; + + memcpy(left, fl, sizeof(float) * s->sofa.hrtf->N); + memcpy(right, fr, sizeof(float) * s->sofa.hrtf->N); + + return 0; +} + static int load_data(AVFilterContext *ctx, int azim, int elev, float radius, int sample_rate) { struct SOFAlizerContext *s = ctx->priv; int n_samples; + int ir_samples; int n_conv = s->n_conv; /* no. channels to convolve */ int n_fft; float delay_l; /* broadband delay for each IR */ @@ -572,39 +735,46 @@ static int load_data(AVFilterContext *ctx, int azim, int elev, float radius, int float *data_ir_r = NULL; int offset = 0; /* used for faster pointer arithmetics in for-loop */ int i, j, azim_orig = azim, elev_orig = elev; - int filter_length, ret = 0; + int ret = 0; int n_current; int n_max = 0; - s->sofa.easy = mysofa_open(s->filename, sample_rate, &filter_length, &ret); - if (!s->sofa.easy || ret) { /* if an invalid SOFA file has been selected */ - av_log(ctx, AV_LOG_ERROR, "Selected SOFA file is invalid. Please select valid SOFA file.\n"); - return AVERROR_INVALIDDATA; - } + av_log(ctx, AV_LOG_DEBUG, "IR length: %d.\n", s->sofa.hrtf->N); + s->sofa.ir_samples = s->sofa.hrtf->N; + s->sofa.n_samples = 1 << (32 - ff_clz(s->sofa.ir_samples)); n_samples = s->sofa.n_samples; + ir_samples = s->sofa.ir_samples; + + if (s->type == TIME_DOMAIN) { + s->data_ir[0] = av_calloc(n_samples, sizeof(float) * s->n_conv); + s->data_ir[1] = av_calloc(n_samples, sizeof(float) * s->n_conv); + + if (!s->data_ir[0] || !s->data_ir[1]) { + ret = AVERROR(ENOMEM); + goto fail; + } + } - s->data_ir[0] = av_calloc(FFALIGN(n_samples, 32), sizeof(float) * s->n_conv); - s->data_ir[1] = av_calloc(FFALIGN(n_samples, 32), sizeof(float) * s->n_conv); s->delay[0] = av_calloc(s->n_conv, sizeof(int)); s->delay[1] = av_calloc(s->n_conv, sizeof(int)); - if (!s->data_ir[0] || !s->data_ir[1] || !s->delay[0] || !s->delay[1]) { + if (!s->delay[0] || !s->delay[1]) { ret = AVERROR(ENOMEM); goto fail; } /* get temporary IR for L and R channel */ - data_ir_l = av_calloc(n_conv * FFALIGN(n_samples, 32), sizeof(*data_ir_l)); - data_ir_r = av_calloc(n_conv * FFALIGN(n_samples, 32), sizeof(*data_ir_r)); + data_ir_l = av_calloc(n_conv * n_samples, sizeof(*data_ir_l)); + data_ir_r = av_calloc(n_conv * n_samples, sizeof(*data_ir_r)); if (!data_ir_r || !data_ir_l) { ret = AVERROR(ENOMEM); goto fail; } if (s->type == TIME_DOMAIN) { - s->temp_src[0] = av_calloc(FFALIGN(n_samples, 32), sizeof(float)); - s->temp_src[1] = av_calloc(FFALIGN(n_samples, 32), sizeof(float)); + s->temp_src[0] = av_calloc(n_samples, sizeof(float)); + s->temp_src[1] = av_calloc(n_samples, sizeof(float)); if (!s->temp_src[0] || !s->temp_src[1]) { ret = AVERROR(ENOMEM); goto fail; @@ -638,10 +808,12 @@ static int load_data(AVFilterContext *ctx, int azim, int elev, float radius, int mysofa_s2c(coordinates); /* get id of IR closest to desired position */ - mysofa_getfilter_float(s->sofa.easy, coordinates[0], coordinates[1], coordinates[2], - data_ir_l + FFALIGN(n_samples, 32) * i, - data_ir_r + FFALIGN(n_samples, 32) * i, - &delay_l, &delay_r); + ret = getfilter_float(ctx, coordinates[0], coordinates[1], coordinates[2], + data_ir_l + n_samples * i, + data_ir_r + n_samples * i, + &delay_l, &delay_r); + if (ret < 0) + goto fail; s->delay[0][i] = delay_l * sample_rate; s->delay[1][i] = delay_r * sample_rate; @@ -651,24 +823,24 @@ static int load_data(AVFilterContext *ctx, int azim, int elev, float radius, int /* get size of ringbuffer (longest IR plus max. delay) */ /* then choose next power of 2 for performance optimization */ - n_current = s->sofa.n_samples + s->sofa.max_delay; + n_current = n_samples + s->sofa.max_delay; /* length of longest IR plus max. delay */ n_max = FFMAX(n_max, n_current); /* buffer length is longest IR plus max. delay -> next power of 2 (32 - count leading zeros gives required exponent) */ s->buffer_length = 1 << (32 - ff_clz(n_max)); - s->n_fft = n_fft = 1 << (32 - ff_clz(n_max + sample_rate)); + s->n_fft = n_fft = 1 << (32 - ff_clz(n_max + s->framesize)); if (s->type == FREQUENCY_DOMAIN) { av_fft_end(s->fft[0]); av_fft_end(s->fft[1]); - s->fft[0] = av_fft_init(log2(s->n_fft), 0); - s->fft[1] = av_fft_init(log2(s->n_fft), 0); + s->fft[0] = av_fft_init(av_log2(s->n_fft), 0); + s->fft[1] = av_fft_init(av_log2(s->n_fft), 0); av_fft_end(s->ifft[0]); av_fft_end(s->ifft[1]); - s->ifft[0] = av_fft_init(log2(s->n_fft), 1); - s->ifft[1] = av_fft_init(log2(s->n_fft), 1); + s->ifft[0] = av_fft_init(av_log2(s->n_fft), 1); + s->ifft[1] = av_fft_init(av_log2(s->n_fft), 1); if (!s->fft[0] || !s->fft[1] || !s->ifft[0] || !s->ifft[1]) { av_log(ctx, AV_LOG_ERROR, "Unable to create FFT contexts of size %d.\n", s->n_fft); @@ -680,7 +852,7 @@ static int load_data(AVFilterContext *ctx, int azim, int elev, float radius, int if (s->type == TIME_DOMAIN) { s->ringbuffer[0] = av_calloc(s->buffer_length, sizeof(float) * nb_input_channels); s->ringbuffer[1] = av_calloc(s->buffer_length, sizeof(float) * nb_input_channels); - } else { + } else if (s->type == FREQUENCY_DOMAIN) { /* get temporary HRTF memory for L and R channel */ data_hrtf_l = av_malloc_array(n_fft, sizeof(*data_hrtf_l) * n_conv); data_hrtf_r = av_malloc_array(n_fft, sizeof(*data_hrtf_r) * n_conv); @@ -693,7 +865,10 @@ static int load_data(AVFilterContext *ctx, int azim, int elev, float radius, int s->ringbuffer[1] = av_calloc(s->buffer_length, sizeof(float)); s->temp_fft[0] = av_malloc_array(s->n_fft, sizeof(FFTComplex)); s->temp_fft[1] = av_malloc_array(s->n_fft, sizeof(FFTComplex)); - if (!s->temp_fft[0] || !s->temp_fft[1]) { + s->temp_afft[0] = av_malloc_array(s->n_fft, sizeof(FFTComplex)); + s->temp_afft[1] = av_malloc_array(s->n_fft, sizeof(FFTComplex)); + if (!s->temp_fft[0] || !s->temp_fft[1] || + !s->temp_afft[0] || !s->temp_afft[1]) { ret = AVERROR(ENOMEM); goto fail; } @@ -716,28 +891,28 @@ static int load_data(AVFilterContext *ctx, int azim, int elev, float radius, int for (i = 0; i < s->n_conv; i++) { float *lir, *rir; - offset = i * FFALIGN(n_samples, 32); /* no. samples already written */ + offset = i * n_samples; /* no. samples already written */ lir = data_ir_l + offset; rir = data_ir_r + offset; if (s->type == TIME_DOMAIN) { - for (j = 0; j < n_samples; j++) { + for (j = 0; j < ir_samples; j++) { /* load reversed IRs of the specified source position * sample-by-sample for left and right ear; and apply gain */ - s->data_ir[0][offset + j] = lir[n_samples - 1 - j] * gain_lin; - s->data_ir[1][offset + j] = rir[n_samples - 1 - j] * gain_lin; + s->data_ir[0][offset + j] = lir[ir_samples - 1 - j] * gain_lin; + s->data_ir[1][offset + j] = rir[ir_samples - 1 - j] * gain_lin; } - } else { + } else if (s->type == FREQUENCY_DOMAIN) { memset(fft_in_l, 0, n_fft * sizeof(*fft_in_l)); memset(fft_in_r, 0, n_fft * sizeof(*fft_in_r)); offset = i * n_fft; /* no. samples already written */ - for (j = 0; j < n_samples; j++) { + for (j = 0; j < ir_samples; j++) { /* load non-reversed IRs of the specified source position * sample-by-sample and apply gain, * L channel is loaded to real part, R channel to imag part, - * IRs ared shifted by L and R delay */ + * IRs are shifted by L and R delay */ fft_in_l[s->delay[0][i] + j].re = lir[j] * gain_lin; fft_in_r[s->delay[1][i] + j].re = rir[j] * gain_lin; } @@ -816,14 +991,11 @@ static int config_input(AVFilterLink *inlink) SOFAlizerContext *s = ctx->priv; int ret; - if (s->type == FREQUENCY_DOMAIN) { - inlink->partial_buf_size = - inlink->min_samples = - inlink->max_samples = inlink->sample_rate; - } + if (s->type == FREQUENCY_DOMAIN) + s->nb_samples = s->framesize; - /* gain -3 dB per channel, -6 dB to get LFE on a similar level */ - s->gain_lfe = expf((s->gain - 3 * inlink->channels - 6 + s->lfe_gain) / 20 * M_LN10); + /* gain -3 dB per channel */ + s->gain_lfe = expf((s->gain - 3 * inlink->channels + s->lfe_gain) / 20 * M_LN10); s->n_conv = inlink->channels; @@ -846,6 +1018,10 @@ static av_cold void uninit(AVFilterContext *ctx) av_fft_end(s->ifft[1]); av_fft_end(s->fft[0]); av_fft_end(s->fft[1]); + s->ifft[0] = NULL; + s->ifft[1] = NULL; + s->fft[0] = NULL; + s->fft[1] = NULL; av_freep(&s->delay[0]); av_freep(&s->delay[1]); av_freep(&s->data_ir[0]); @@ -856,6 +1032,8 @@ static av_cold void uninit(AVFilterContext *ctx) av_freep(&s->speaker_elev); av_freep(&s->temp_src[0]); av_freep(&s->temp_src[1]); + av_freep(&s->temp_afft[0]); + av_freep(&s->temp_afft[1]); av_freep(&s->temp_fft[0]); av_freep(&s->temp_fft[1]); av_freep(&s->data_hrtf[0]); @@ -871,12 +1049,18 @@ static const AVOption sofalizer_options[] = { { "gain", "set gain in dB", OFFSET(gain), AV_OPT_TYPE_FLOAT, {.dbl=0}, -20, 40, .flags = FLAGS }, { "rotation", "set rotation" , OFFSET(rotation), AV_OPT_TYPE_FLOAT, {.dbl=0}, -360, 360, .flags = FLAGS }, { "elevation", "set elevation", OFFSET(elevation), AV_OPT_TYPE_FLOAT, {.dbl=0}, -90, 90, .flags = FLAGS }, - { "radius", "set radius", OFFSET(radius), AV_OPT_TYPE_FLOAT, {.dbl=1}, 0, 3, .flags = FLAGS }, + { "radius", "set radius", OFFSET(radius), AV_OPT_TYPE_FLOAT, {.dbl=1}, 0, 5, .flags = FLAGS }, { "type", "set processing", OFFSET(type), AV_OPT_TYPE_INT, {.i64=1}, 0, 1, .flags = FLAGS, "type" }, { "time", "time domain", 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, .flags = FLAGS, "type" }, { "freq", "frequency domain", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, .flags = FLAGS, "type" }, { "speakers", "set speaker custom positions", OFFSET(speakers_pos), AV_OPT_TYPE_STRING, {.str=0}, 0, 0, .flags = FLAGS }, - { "lfegain", "set lfe gain", OFFSET(lfe_gain), AV_OPT_TYPE_FLOAT, {.dbl=0}, -9, 9, .flags = FLAGS }, + { "lfegain", "set lfe gain", OFFSET(lfe_gain), AV_OPT_TYPE_FLOAT, {.dbl=0}, -20,40, .flags = FLAGS }, + { "framesize", "set frame size", OFFSET(framesize), AV_OPT_TYPE_INT, {.i64=1024},1024,96000, .flags = FLAGS }, + { "normalize", "normalize IRs", OFFSET(normalize), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1, .flags = FLAGS }, + { "interpolate","interpolate IRs from neighbors", OFFSET(interpolate),AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, .flags = FLAGS }, + { "minphase", "minphase IRs", OFFSET(minphase), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, .flags = FLAGS }, + { "anglestep", "set neighbor search angle step", OFFSET(anglestep), AV_OPT_TYPE_FLOAT, {.dbl=.5}, 0.01, 10, .flags = FLAGS }, + { "radstep", "set neighbor search radius step", OFFSET(radstep), AV_OPT_TYPE_FLOAT, {.dbl=.01}, 0.01, 1, .flags = FLAGS }, { NULL } }; @@ -887,7 +1071,6 @@ static const AVFilterPad inputs[] = { .name = "default", .type = AVMEDIA_TYPE_AUDIO, .config_props = config_input, - .filter_frame = filter_frame, }, { NULL } }; @@ -906,6 +1089,7 @@ AVFilter ff_af_sofalizer = { .priv_size = sizeof(SOFAlizerContext), .priv_class = &sofalizer_class, .init = init, + .activate = activate, .uninit = uninit, .query_formats = query_formats, .inputs = inputs, diff --git a/libavfilter/af_stereowiden.c b/libavfilter/af_stereowiden.c index ef16fcec7..d23c8dba7 100644 --- a/libavfilter/af_stereowiden.c +++ b/libavfilter/af_stereowiden.c @@ -113,8 +113,13 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) if (s->cur == s->buffer + s->length) s->cur = s->buffer; - dst[0] = drymix * left - crossfeed * right - feedback * s->cur[1]; - dst[1] = drymix * right - crossfeed * left - feedback * s->cur[0]; + if (ctx->is_disabled) { + dst[0] = left; + dst[1] = right; + } else { + dst[0] = drymix * left - crossfeed * right - feedback * s->cur[1]; + dst[1] = drymix * right - crossfeed * left - feedback * s->cur[0]; + } s->cur[0] = left; s->cur[1] = right; @@ -159,4 +164,5 @@ AVFilter ff_af_stereowiden = { .uninit = uninit, .inputs = inputs, .outputs = outputs, + .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, }; diff --git a/libavfilter/af_superequalizer.c b/libavfilter/af_superequalizer.c index f38cca5c8..f11ec9e6d 100644 --- a/libavfilter/af_superequalizer.c +++ b/libavfilter/af_superequalizer.c @@ -25,6 +25,7 @@ #include "audio.h" #include "avfilter.h" +#include "filters.h" #include "internal.h" #define NBANDS 17 @@ -203,7 +204,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) dst = (float *)s->out->extended_data[ch]; src = (float *)in->extended_data[ch]; - for (i = 0; i < s->winlen; i++) + for (i = 0; i < in->nb_samples; i++) fsamples[i] = src[i]; for (; i < s->tabsize; i++) fsamples[i] = 0; @@ -240,6 +241,28 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) return ff_filter_frame(outlink, out); } +static int activate(AVFilterContext *ctx) +{ + AVFilterLink *inlink = ctx->inputs[0]; + AVFilterLink *outlink = ctx->outputs[0]; + SuperEqualizerContext *s = ctx->priv; + AVFrame *in = NULL; + int ret; + + FF_FILTER_FORWARD_STATUS_BACK(outlink, inlink); + + ret = ff_inlink_consume_samples(inlink, s->winlen, s->winlen, &in); + if (ret < 0) + return ret; + if (ret > 0) + return filter_frame(inlink, in); + + FF_FILTER_FORWARD_STATUS(inlink, outlink); + FF_FILTER_FORWARD_WANTED(outlink, inlink); + + return FFERROR_NOT_READY; +} + static av_cold int init(AVFilterContext *ctx) { SuperEqualizerContext *s = ctx->priv; @@ -277,10 +300,6 @@ static int config_input(AVFilterLink *inlink) AVFilterContext *ctx = inlink->dst; SuperEqualizerContext *s = ctx->priv; - inlink->partial_buf_size = - inlink->min_samples = - inlink->max_samples = s->winlen; - s->out = ff_get_audio_buffer(inlink, s->tabsize); if (!s->out) return AVERROR(ENOMEM); @@ -314,7 +333,6 @@ static const AVFilterPad superequalizer_inputs[] = { { .name = "default", .type = AVMEDIA_TYPE_AUDIO, - .filter_frame = filter_frame, .config_props = config_input, }, { NULL } @@ -363,6 +381,7 @@ AVFilter ff_af_superequalizer = { .priv_class = &superequalizer_class, .query_formats = query_formats, .init = init, + .activate = activate, .uninit = uninit, .inputs = superequalizer_inputs, .outputs = superequalizer_outputs, diff --git a/libavfilter/af_surround.c b/libavfilter/af_surround.c index f29afecbf..5a4eca775 100644 --- a/libavfilter/af_surround.c +++ b/libavfilter/af_surround.c @@ -18,13 +18,17 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "libavutil/avassert.h" #include "libavutil/audio_fifo.h" #include "libavutil/channel_layout.h" #include "libavutil/opt.h" #include "libavcodec/avfft.h" #include "avfilter.h" #include "audio.h" +#include "filters.h" +#include "internal.h" #include "formats.h" +#include "window_func.h" typedef struct AudioSurroundContext { const AVClass *class; @@ -36,8 +40,48 @@ typedef struct AudioSurroundContext { float level_out; float fc_in; float fc_out; + float fl_in; + float fl_out; + float fr_in; + float fr_out; + float sl_in; + float sl_out; + float sr_in; + float sr_out; + float bl_in; + float bl_out; + float br_in; + float br_out; + float bc_in; + float bc_out; float lfe_in; float lfe_out; + int lfe_mode; + float angle; + int win_size; + int win_func; + float overlap; + + float all_x; + float all_y; + + float fc_x; + float fl_x; + float fr_x; + float bl_x; + float br_x; + float sl_x; + float sr_x; + float bc_x; + + float fc_y; + float fl_y; + float fr_y; + float bl_y; + float br_y; + float sl_y; + float sr_y; + float bc_y; float *input_levels; float *output_levels; @@ -64,6 +108,7 @@ typedef struct AudioSurroundContext { float *window_func_lut; int64_t pts; + int eof; void (*filter)(AVFilterContext *ctx); void (*upmix_stereo)(AVFilterContext *ctx, @@ -173,6 +218,27 @@ static int config_input(AVFilterLink *inlink) ch = av_get_channel_layout_channel_index(inlink->channel_layout, AV_CH_FRONT_CENTER); if (ch >= 0) s->input_levels[ch] *= s->fc_in; + ch = av_get_channel_layout_channel_index(inlink->channel_layout, AV_CH_FRONT_LEFT); + if (ch >= 0) + s->input_levels[ch] *= s->fl_in; + ch = av_get_channel_layout_channel_index(inlink->channel_layout, AV_CH_FRONT_RIGHT); + if (ch >= 0) + s->input_levels[ch] *= s->fr_in; + ch = av_get_channel_layout_channel_index(inlink->channel_layout, AV_CH_SIDE_LEFT); + if (ch >= 0) + s->input_levels[ch] *= s->sl_in; + ch = av_get_channel_layout_channel_index(inlink->channel_layout, AV_CH_SIDE_RIGHT); + if (ch >= 0) + s->input_levels[ch] *= s->sr_in; + ch = av_get_channel_layout_channel_index(inlink->channel_layout, AV_CH_BACK_LEFT); + if (ch >= 0) + s->input_levels[ch] *= s->bl_in; + ch = av_get_channel_layout_channel_index(inlink->channel_layout, AV_CH_BACK_RIGHT); + if (ch >= 0) + s->input_levels[ch] *= s->br_in; + ch = av_get_channel_layout_channel_index(inlink->channel_layout, AV_CH_BACK_CENTER); + if (ch >= 0) + s->input_levels[ch] *= s->bc_in; ch = av_get_channel_layout_channel_index(inlink->channel_layout, AV_CH_LOW_FREQUENCY); if (ch >= 0) s->input_levels[ch] *= s->lfe_in; @@ -215,6 +281,27 @@ static int config_output(AVFilterLink *outlink) ch = av_get_channel_layout_channel_index(outlink->channel_layout, AV_CH_FRONT_CENTER); if (ch >= 0) s->output_levels[ch] *= s->fc_out; + ch = av_get_channel_layout_channel_index(outlink->channel_layout, AV_CH_FRONT_LEFT); + if (ch >= 0) + s->output_levels[ch] *= s->fl_out; + ch = av_get_channel_layout_channel_index(outlink->channel_layout, AV_CH_FRONT_RIGHT); + if (ch >= 0) + s->output_levels[ch] *= s->fr_out; + ch = av_get_channel_layout_channel_index(outlink->channel_layout, AV_CH_SIDE_LEFT); + if (ch >= 0) + s->output_levels[ch] *= s->sl_out; + ch = av_get_channel_layout_channel_index(outlink->channel_layout, AV_CH_SIDE_RIGHT); + if (ch >= 0) + s->output_levels[ch] *= s->sr_out; + ch = av_get_channel_layout_channel_index(outlink->channel_layout, AV_CH_BACK_LEFT); + if (ch >= 0) + s->output_levels[ch] *= s->bl_out; + ch = av_get_channel_layout_channel_index(outlink->channel_layout, AV_CH_BACK_RIGHT); + if (ch >= 0) + s->output_levels[ch] *= s->br_out; + ch = av_get_channel_layout_channel_index(outlink->channel_layout, AV_CH_BACK_CENTER); + if (ch >= 0) + s->output_levels[ch] *= s->bc_out; ch = av_get_channel_layout_channel_index(outlink->channel_layout, AV_CH_LOW_FREQUENCY); if (ch >= 0) s->output_levels[ch] *= s->lfe_out; @@ -227,19 +314,42 @@ static int config_output(AVFilterLink *outlink) return 0; } +static void stereo_transform(float *x, float *y, float angle) +{ + float reference, r, a; + + if (angle == 90.f) + return; + + reference = angle * M_PI / 180.f; + r = hypotf(*x, *y); + a = atan2f(*x, *y); + + if (fabsf(a) <= M_PI_4) + a *= reference / M_PI_2; + else + a = M_PI + 2 * (-2 * M_PI + reference) * (M_PI - fabsf(a)) * FFDIFFSIGN(a, 0) / (3 * M_PI); + + *x = av_clipf(sinf(a) * r, -1, 1); + *y = av_clipf(cosf(a) * r, -1, 1); +} + static void stereo_position(float a, float p, float *x, float *y) { - *x = av_clipf(a+FFMAX(0, sinf(p-M_PI_2))*FFDIFFSIGN(a,0), -1, 1); - *y = av_clipf(cosf(a*M_PI_2+M_PI)*cosf(M_PI_2-p/M_PI)*M_LN10+1, -1, 1); + av_assert2(a >= -1.f && a <= 1.f); + av_assert2(p >= 0.f && p <= M_PI); + *x = av_clipf(a+a*FFMAX(0, p*p-M_PI_2), -1, 1); + *y = av_clipf(cosf(a*M_PI_2+M_PI)*cosf(M_PI_2-p/M_PI)*M_LN10+1, -1, 1); } static inline void get_lfe(int output_lfe, int n, float lowcut, float highcut, - float *lfe_mag, float *mag_total) + float *lfe_mag, float *mag_total, int lfe_mode) { if (output_lfe && n < highcut) { *lfe_mag = n < lowcut ? 1.f : .5f*(1.f+cosf(M_PI*(lowcut-n)/(lowcut-highcut))); *lfe_mag *= *mag_total; - *mag_total -= *lfe_mag; + if (lfe_mode) + *mag_total -= *lfe_mag; } else { *lfe_mag = 0.f; } @@ -258,7 +368,7 @@ static void upmix_1_0(AVFilterContext *ctx, dst = (float *)s->output->extended_data[0]; - mag = sqrtf(1.f - fabsf(x)) * ((y + 1.f) * .5f) * mag_total; + mag = powf(1.f - fabsf(x), s->fc_x) * powf((y + 1.f) * .5f, s->fc_y) * mag_total; dst[2 * n ] = mag * cosf(c_phase); dst[2 * n + 1] = mag * sinf(c_phase); @@ -278,8 +388,8 @@ static void upmix_stereo(AVFilterContext *ctx, dstl = (float *)s->output->extended_data[0]; dstr = (float *)s->output->extended_data[1]; - l_mag = sqrtf(.5f * ( x + 1.f)) * ((y + 1.f) * .5f) * mag_total; - r_mag = sqrtf(.5f * (-x + 1.f)) * ((y + 1.f) * .5f) * mag_total; + l_mag = powf(.5f * ( x + 1.f), s->fl_x) * powf((y + 1.f) * .5f, s->fl_y) * mag_total; + r_mag = powf(.5f * (-x + 1.f), s->fr_x) * powf((y + 1.f) * .5f, s->fr_y) * mag_total; dstl[2 * n ] = l_mag * cosf(l_phase); dstl[2 * n + 1] = l_mag * sinf(l_phase); @@ -303,10 +413,10 @@ static void upmix_2_1(AVFilterContext *ctx, dstr = (float *)s->output->extended_data[1]; dstlfe = (float *)s->output->extended_data[2]; - get_lfe(s->output_lfe, n, s->lowcut, s->highcut, &lfe_mag, &mag_total); + get_lfe(s->output_lfe, n, s->lowcut, s->highcut, &lfe_mag, &mag_total, s->lfe_mode); - l_mag = sqrtf(.5f * ( x + 1.f)) * ((y + 1.f) * .5f) * mag_total; - r_mag = sqrtf(.5f * (-x + 1.f)) * ((y + 1.f) * .5f) * mag_total; + l_mag = powf(.5f * ( x + 1.f), s->fl_x) * powf((y + 1.f) * .5f, s->fl_y) * mag_total; + r_mag = powf(.5f * (-x + 1.f), s->fr_x) * powf((y + 1.f) * .5f, s->fr_y) * mag_total; dstl[2 * n ] = l_mag * cosf(l_phase); dstl[2 * n + 1] = l_mag * sinf(l_phase); @@ -333,9 +443,9 @@ static void upmix_3_0(AVFilterContext *ctx, dstr = (float *)s->output->extended_data[1]; dstc = (float *)s->output->extended_data[2]; - c_mag = sqrtf(1.f - fabsf(x)) * ((y + 1.f) * .5f) * mag_total; - l_mag = sqrtf(.5f * ( x + 1.f)) * ((y + 1.f) * .5f) * mag_total; - r_mag = sqrtf(.5f * (-x + 1.f)) * ((y + 1.f) * .5f) * mag_total; + c_mag = powf(1.f - fabsf(x), s->fc_x) * powf((y + 1.f) * .5f, s->fc_y) * mag_total; + l_mag = powf(.5f * ( x + 1.f), s->fl_x) * powf((y + 1.f) * .5f, s->fl_y) * mag_total; + r_mag = powf(.5f * (-x + 1.f), s->fr_x) * powf((y + 1.f) * .5f, s->fr_y) * mag_total; dstl[2 * n ] = l_mag * cosf(l_phase); dstl[2 * n + 1] = l_mag * sinf(l_phase); @@ -363,11 +473,11 @@ static void upmix_3_1(AVFilterContext *ctx, dstc = (float *)s->output->extended_data[2]; dstlfe = (float *)s->output->extended_data[3]; - get_lfe(s->output_lfe, n, s->lowcut, s->highcut, &lfe_mag, &mag_total); + get_lfe(s->output_lfe, n, s->lowcut, s->highcut, &lfe_mag, &mag_total, s->lfe_mode); - c_mag = sqrtf(1.f - fabsf(x)) * ((y + 1.f) * .5f) * mag_total; - l_mag = sqrtf(.5f * ( x + 1.f)) * ((y + 1.f) * .5f) * mag_total; - r_mag = sqrtf(.5f * (-x + 1.f)) * ((y + 1.f) * .5f) * mag_total; + c_mag = powf(1.f - fabsf(x), s->fc_x) * powf((y + 1.f) * .5f, s->fc_y) * mag_total; + l_mag = powf(.5f * ( x + 1.f), s->fl_x) * powf((y + 1.f) * .5f, s->fl_y) * mag_total; + r_mag = powf(.5f * (-x + 1.f), s->fr_x) * powf((y + 1.f) * .5f, s->fr_y) * mag_total; dstl[2 * n ] = l_mag * cosf(l_phase); dstl[2 * n + 1] = l_mag * sinf(l_phase); @@ -399,10 +509,10 @@ static void upmix_3_1_surround(AVFilterContext *ctx, dstc = (float *)s->output->extended_data[2]; dstlfe = (float *)s->output->extended_data[3]; - get_lfe(s->output_lfe, n, s->lowcut, s->highcut, &lfe_mag, &c_mag); + get_lfe(s->output_lfe, n, s->lowcut, s->highcut, &lfe_mag, &c_mag, s->lfe_mode); - l_mag = sqrtf(.5f * ( x + 1.f)) * ((y + 1.f) * .5f) * mag_total; - r_mag = sqrtf(.5f * (-x + 1.f)) * ((y + 1.f) * .5f) * mag_total; + l_mag = powf(.5f * ( x + 1.f), s->fl_x) * powf((y + 1.f) * .5f, s->fl_y) * mag_total; + r_mag = powf(.5f * (-x + 1.f), s->fr_x) * powf((y + 1.f) * .5f, s->fr_y) * mag_total; dstl[2 * n ] = l_mag * cosf(l_phase); dstl[2 * n + 1] = l_mag * sinf(l_phase); @@ -425,18 +535,18 @@ static void upmix_4_0(AVFilterContext *ctx, float x, float y, int n) { - float b_mag, l_mag, r_mag, c_mag, *dstc, *dstl, *dstr, *dstb; AudioSurroundContext *s = ctx->priv; + float b_mag, l_mag, r_mag, c_mag, *dstc, *dstl, *dstr, *dstb; dstl = (float *)s->output->extended_data[0]; dstr = (float *)s->output->extended_data[1]; dstc = (float *)s->output->extended_data[2]; dstb = (float *)s->output->extended_data[3]; - c_mag = sqrtf(1.f - fabsf(x)) * ((y + 1.f) * .5f) * mag_total; - b_mag = sqrtf(1.f - fabsf(x)) * ((1.f - y) * .5f) * mag_total; - l_mag = sqrtf(.5f * ( x + 1.f)) * ((y + 1.f) * .5f) * mag_total; - r_mag = sqrtf(.5f * (-x + 1.f)) * ((y + 1.f) * .5f) * mag_total; + c_mag = powf(1.f - fabsf(x), s->fc_x) * powf((y + 1.f) * .5f, s->fc_y) * mag_total; + b_mag = powf(1.f - fabsf(x), s->bc_x) * powf((1.f - y) * .5f, s->bc_y) * mag_total; + l_mag = powf(.5f * ( x + 1.f), s->fl_x) * powf((y + 1.f) * .5f, s->fl_y) * mag_total; + r_mag = powf(.5f * (-x + 1.f), s->fr_x) * powf((y + 1.f) * .5f, s->fr_y) * mag_total; dstl[2 * n ] = l_mag * cosf(l_phase); dstl[2 * n + 1] = l_mag * sinf(l_phase); @@ -459,8 +569,8 @@ static void upmix_4_1(AVFilterContext *ctx, float x, float y, int n) { - float lfe_mag, b_mag, l_mag, r_mag, c_mag, *dstc, *dstl, *dstr, *dstb, *dstlfe; AudioSurroundContext *s = ctx->priv; + float lfe_mag, b_mag, l_mag, r_mag, c_mag, *dstc, *dstl, *dstr, *dstb, *dstlfe; dstl = (float *)s->output->extended_data[0]; dstr = (float *)s->output->extended_data[1]; @@ -468,15 +578,15 @@ static void upmix_4_1(AVFilterContext *ctx, dstlfe = (float *)s->output->extended_data[3]; dstb = (float *)s->output->extended_data[4]; - get_lfe(s->output_lfe, n, s->lowcut, s->highcut, &lfe_mag, &mag_total); + get_lfe(s->output_lfe, n, s->lowcut, s->highcut, &lfe_mag, &mag_total, s->lfe_mode); dstlfe[2 * n ] = lfe_mag * cosf(c_phase); dstlfe[2 * n + 1] = lfe_mag * sinf(c_phase); - c_mag = sqrtf(1.f - fabsf(x)) * ((y + 1.f) * .5f) * mag_total; - b_mag = sqrtf(1.f - fabsf(x)) * ((1.f - y) * .5f) * mag_total; - l_mag = sqrtf(.5f * ( x + 1.f)) * ((y + 1.f) * .5f) * mag_total; - r_mag = sqrtf(.5f * (-x + 1.f)) * ((y + 1.f) * .5f) * mag_total; + c_mag = powf(1.f - fabsf(x), s->fc_x) * powf((y + 1.f) * .5f, s->fc_y) * mag_total; + b_mag = powf(1.f - fabsf(x), s->bc_x) * powf((1.f - y) * .5f, s->bc_y) * mag_total; + l_mag = powf(.5f * ( x + 1.f), s->fl_x) * powf((y + 1.f) * .5f, s->fl_y) * mag_total; + r_mag = powf(.5f * (-x + 1.f), s->fr_x) * powf((y + 1.f) * .5f, s->fr_y) * mag_total; dstl[2 * n ] = l_mag * cosf(l_phase); dstl[2 * n + 1] = l_mag * sinf(l_phase); @@ -499,8 +609,8 @@ static void upmix_5_0_back(AVFilterContext *ctx, float x, float y, int n) { - float l_mag, r_mag, ls_mag, rs_mag, c_mag, *dstc, *dstl, *dstr, *dstls, *dstrs; AudioSurroundContext *s = ctx->priv; + float l_mag, r_mag, ls_mag, rs_mag, c_mag, *dstc, *dstl, *dstr, *dstls, *dstrs; dstl = (float *)s->output->extended_data[0]; dstr = (float *)s->output->extended_data[1]; @@ -508,11 +618,11 @@ static void upmix_5_0_back(AVFilterContext *ctx, dstls = (float *)s->output->extended_data[3]; dstrs = (float *)s->output->extended_data[4]; - c_mag = sqrtf(1.f - fabsf(x)) * ((y + 1.f) * .5f) * mag_total; - l_mag = sqrtf(.5f * ( x + 1.f)) * ((y + 1.f) * .5f) * mag_total; - r_mag = sqrtf(.5f * (-x + 1.f)) * ((y + 1.f) * .5f) * mag_total; - ls_mag = sqrtf(.5f * ( x + 1.f)) * (1.f - ((y + 1.f) * .5f)) * mag_total; - rs_mag = sqrtf(.5f * (-x + 1.f)) * (1.f - ((y + 1.f) * .5f)) * mag_total; + c_mag = powf(1.f - fabsf(x), s->fc_x) * powf((y + 1.f) * .5f, s->fc_y) * mag_total; + l_mag = powf(.5f * ( x + 1.f), s->fl_x) * powf((y + 1.f) * .5f, s->fl_y) * mag_total; + r_mag = powf(.5f * (-x + 1.f), s->fr_x) * powf((y + 1.f) * .5f, s->fr_y) * mag_total; + ls_mag = powf(.5f * ( x + 1.f), s->bl_x) * powf(1.f - ((y + 1.f) * .5f), s->bl_y) * mag_total; + rs_mag = powf(.5f * (-x + 1.f), s->br_x) * powf(1.f - ((y + 1.f) * .5f), s->br_y) * mag_total; dstl[2 * n ] = l_mag * cosf(l_phase); dstl[2 * n + 1] = l_mag * sinf(l_phase); @@ -538,8 +648,8 @@ static void upmix_5_1_back(AVFilterContext *ctx, float x, float y, int n) { - float lfe_mag, l_mag, r_mag, ls_mag, rs_mag, c_mag, *dstc, *dstl, *dstr, *dstls, *dstrs, *dstlfe; AudioSurroundContext *s = ctx->priv; + float lfe_mag, l_mag, r_mag, ls_mag, rs_mag, c_mag, *dstc, *dstl, *dstr, *dstls, *dstrs, *dstlfe; dstl = (float *)s->output->extended_data[0]; dstr = (float *)s->output->extended_data[1]; @@ -548,13 +658,13 @@ static void upmix_5_1_back(AVFilterContext *ctx, dstls = (float *)s->output->extended_data[4]; dstrs = (float *)s->output->extended_data[5]; - get_lfe(s->output_lfe, n, s->lowcut, s->highcut, &lfe_mag, &mag_total); + get_lfe(s->output_lfe, n, s->lowcut, s->highcut, &lfe_mag, &mag_total, s->lfe_mode); - c_mag = sqrtf(1.f - fabsf(x)) * ((y + 1.f) * .5f) * mag_total; - l_mag = sqrtf(.5f * ( x + 1.f)) * ((y + 1.f) * .5f) * mag_total; - r_mag = sqrtf(.5f * (-x + 1.f)) * ((y + 1.f) * .5f) * mag_total; - ls_mag = sqrtf(.5f * ( x + 1.f)) * (1.f - ((y + 1.f) * .5f)) * mag_total; - rs_mag = sqrtf(.5f * (-x + 1.f)) * (1.f - ((y + 1.f) * .5f)) * mag_total; + c_mag = powf(1.f - fabsf(x), s->fc_x) * powf((y + 1.f) * .5f, s->fc_y) * mag_total; + l_mag = powf(.5f * ( x + 1.f), s->fl_x) * powf((y + 1.f) * .5f, s->fl_y) * mag_total; + r_mag = powf(.5f * (-x + 1.f), s->fr_x) * powf((y + 1.f) * .5f, s->fr_y) * mag_total; + ls_mag = powf(.5f * ( x + 1.f), s->bl_x) * powf(1.f - ((y + 1.f) * .5f), s->bl_y) * mag_total; + rs_mag = powf(.5f * (-x + 1.f), s->br_x) * powf(1.f - ((y + 1.f) * .5f), s->br_y) * mag_total; dstl[2 * n ] = l_mag * cosf(l_phase); dstl[2 * n + 1] = l_mag * sinf(l_phase); @@ -575,6 +685,100 @@ static void upmix_5_1_back(AVFilterContext *ctx, dstrs[2 * n + 1] = rs_mag * sinf(r_phase); } +static void upmix_6_0(AVFilterContext *ctx, + float l_phase, + float r_phase, + float c_phase, + float mag_total, + float x, float y, + int n) +{ + AudioSurroundContext *s = ctx->priv; + float l_mag, r_mag, ls_mag, rs_mag, c_mag, b_mag, *dstc, *dstb, *dstl, *dstr, *dstls, *dstrs; + + dstl = (float *)s->output->extended_data[0]; + dstr = (float *)s->output->extended_data[1]; + dstc = (float *)s->output->extended_data[2]; + dstb = (float *)s->output->extended_data[3]; + dstls = (float *)s->output->extended_data[4]; + dstrs = (float *)s->output->extended_data[5]; + + c_mag = powf(1.f - fabsf(x), s->fc_x) * powf((y + 1.f) * .5f, s->fc_y) * mag_total; + b_mag = powf(1.f - fabsf(x), s->bc_x) * powf((1.f - y) * .5f, s->bc_y) * mag_total; + l_mag = powf(.5f * ( x + 1.f), s->fl_x) * powf((y + 1.f) * .5f, s->fl_y) * mag_total; + r_mag = powf(.5f * (-x + 1.f), s->fr_x) * powf((y + 1.f) * .5f, s->fr_y) * mag_total; + ls_mag = powf(.5f * ( x + 1.f), s->bl_x) * powf(1.f - ((y + 1.f) * .5f), s->bl_y) * mag_total; + rs_mag = powf(.5f * (-x + 1.f), s->br_x) * powf(1.f - ((y + 1.f) * .5f), s->br_y) * mag_total; + + dstl[2 * n ] = l_mag * cosf(l_phase); + dstl[2 * n + 1] = l_mag * sinf(l_phase); + + dstr[2 * n ] = r_mag * cosf(r_phase); + dstr[2 * n + 1] = r_mag * sinf(r_phase); + + dstc[2 * n ] = c_mag * cosf(c_phase); + dstc[2 * n + 1] = c_mag * sinf(c_phase); + + dstls[2 * n ] = ls_mag * cosf(l_phase); + dstls[2 * n + 1] = ls_mag * sinf(l_phase); + + dstrs[2 * n ] = rs_mag * cosf(r_phase); + dstrs[2 * n + 1] = rs_mag * sinf(r_phase); + + dstb[2 * n ] = b_mag * cosf(c_phase); + dstb[2 * n + 1] = b_mag * sinf(c_phase); +} + +static void upmix_6_1(AVFilterContext *ctx, + float l_phase, + float r_phase, + float c_phase, + float mag_total, + float x, float y, + int n) +{ + AudioSurroundContext *s = ctx->priv; + float lfe_mag, l_mag, r_mag, ls_mag, rs_mag, c_mag, b_mag, *dstc, *dstb, *dstl, *dstr, *dstls, *dstrs, *dstlfe; + + dstl = (float *)s->output->extended_data[0]; + dstr = (float *)s->output->extended_data[1]; + dstc = (float *)s->output->extended_data[2]; + dstlfe = (float *)s->output->extended_data[3]; + dstb = (float *)s->output->extended_data[4]; + dstls = (float *)s->output->extended_data[5]; + dstrs = (float *)s->output->extended_data[6]; + + get_lfe(s->output_lfe, n, s->lowcut, s->highcut, &lfe_mag, &mag_total, s->lfe_mode); + + c_mag = powf(1.f - fabsf(x), s->fc_x) * powf((y + 1.f) * .5f, s->fc_y) * mag_total; + b_mag = powf(1.f - fabsf(x), s->bc_x) * powf((1.f - y) * .5f, s->bc_y) * mag_total; + l_mag = powf(.5f * ( x + 1.f), s->fl_x) * powf((y + 1.f) * .5f, s->fl_y) * mag_total; + r_mag = powf(.5f * (-x + 1.f), s->fr_x) * powf((y + 1.f) * .5f, s->fr_y) * mag_total; + ls_mag = powf(.5f * ( x + 1.f), s->bl_x) * powf(1.f - ((y + 1.f) * .5f), s->bl_y) * mag_total; + rs_mag = powf(.5f * (-x + 1.f), s->br_x) * powf(1.f - ((y + 1.f) * .5f), s->br_y) * mag_total; + + dstl[2 * n ] = l_mag * cosf(l_phase); + dstl[2 * n + 1] = l_mag * sinf(l_phase); + + dstr[2 * n ] = r_mag * cosf(r_phase); + dstr[2 * n + 1] = r_mag * sinf(r_phase); + + dstc[2 * n ] = c_mag * cosf(c_phase); + dstc[2 * n + 1] = c_mag * sinf(c_phase); + + dstlfe[2 * n ] = lfe_mag * cosf(c_phase); + dstlfe[2 * n + 1] = lfe_mag * sinf(c_phase); + + dstls[2 * n ] = ls_mag * cosf(l_phase); + dstls[2 * n + 1] = ls_mag * sinf(l_phase); + + dstrs[2 * n ] = rs_mag * cosf(r_phase); + dstrs[2 * n + 1] = rs_mag * sinf(r_phase); + + dstb[2 * n ] = b_mag * cosf(c_phase); + dstb[2 * n + 1] = b_mag * sinf(c_phase); +} + static void upmix_5_1_back_surround(AVFilterContext *ctx, float l_phase, float r_phase, @@ -595,12 +799,12 @@ static void upmix_5_1_back_surround(AVFilterContext *ctx, dstls = (float *)s->output->extended_data[4]; dstrs = (float *)s->output->extended_data[5]; - get_lfe(s->output_lfe, n, s->lowcut, s->highcut, &lfe_mag, &c_mag); + get_lfe(s->output_lfe, n, s->lowcut, s->highcut, &lfe_mag, &c_mag, s->lfe_mode); - l_mag = sqrtf(.5f * ( x + 1.f)) * ((y + 1.f) * .5f) * mag_total; - r_mag = sqrtf(.5f * (-x + 1.f)) * ((y + 1.f) * .5f) * mag_total; - ls_mag = sqrtf(.5f * ( x + 1.f)) * (1.f - ((y + 1.f) * .5f)) * mag_total; - rs_mag = sqrtf(.5f * (-x + 1.f)) * (1.f - ((y + 1.f) * .5f)) * mag_total; + l_mag = powf(.5f * ( x + 1.f), s->fl_x) * powf((y + 1.f) * .5f, s->fl_y) * mag_total; + r_mag = powf(.5f * (-x + 1.f), s->fr_x) * powf((y + 1.f) * .5f, s->fr_y) * mag_total; + ls_mag = powf(.5f * ( x + 1.f), s->bl_x) * powf(1.f - ((y + 1.f) * .5f), s->bl_y) * mag_total; + rs_mag = powf(.5f * (-x + 1.f), s->br_x) * powf(1.f - ((y + 1.f) * .5f), s->br_y) * mag_total; dstl[2 * n ] = l_mag * cosf(l_phase); dstl[2 * n + 1] = l_mag * sinf(l_phase); @@ -642,11 +846,11 @@ static void upmix_5_1_back_2_1(AVFilterContext *ctx, dstls = (float *)s->output->extended_data[4]; dstrs = (float *)s->output->extended_data[5]; - c_mag = sqrtf(1.f - fabsf(x)) * ((y + 1.f) * .5f) * mag_total; - l_mag = sqrtf(.5f * ( x + 1.f)) * ((y + 1.f) * .5f) * mag_total; - r_mag = sqrtf(.5f * (-x + 1.f)) * ((y + 1.f) * .5f) * mag_total; - ls_mag = sqrtf(.5f * ( x + 1.f)) * (1.f - ((y + 1.f) * .5f)) * mag_total; - rs_mag = sqrtf(.5f * (-x + 1.f)) * (1.f - ((y + 1.f) * .5f)) * mag_total; + c_mag = powf(1.f - fabsf(x), s->fc_x) * powf((y + 1.f) * .5f, s->fc_y) * mag_total; + l_mag = powf(.5f * ( x + 1.f), s->fl_x) * powf((y + 1.f) * .5f, s->fl_y) * mag_total; + r_mag = powf(.5f * (-x + 1.f), s->fr_x) * powf((y + 1.f) * .5f, s->fr_y) * mag_total; + ls_mag = powf(.5f * ( x + 1.f), s->bl_x) * powf(1.f - ((y + 1.f) * .5f), s->bl_y) * mag_total; + rs_mag = powf(.5f * (-x + 1.f), s->br_x) * powf(1.f - ((y + 1.f) * .5f), s->br_y) * mag_total; dstl[2 * n ] = l_mag * cosf(l_phase); dstl[2 * n + 1] = l_mag * sinf(l_phase); @@ -687,13 +891,13 @@ static void upmix_7_0(AVFilterContext *ctx, dstls = (float *)s->output->extended_data[5]; dstrs = (float *)s->output->extended_data[6]; - c_mag = sqrtf(1.f - fabsf(x)) * ((y + 1.f) * .5f) * mag_total; - l_mag = sqrtf(.5f * ( x + 1.f)) * ((y + 1.f) * .5f) * mag_total; - r_mag = sqrtf(.5f * (-x + 1.f)) * ((y + 1.f) * .5f) * mag_total; - lb_mag = sqrtf(.5f * ( x + 1.f)) * (1.f - ((y + 1.f) * .5f)) * mag_total; - rb_mag = sqrtf(.5f * (-x + 1.f)) * (1.f - ((y + 1.f) * .5f)) * mag_total; - ls_mag = sqrtf(.5f * ( x + 1.f)) * (1.f - fabsf(y)) * mag_total; - rs_mag = sqrtf(.5f * (-x + 1.f)) * (1.f - fabsf(y)) * mag_total; + c_mag = powf(1.f - fabsf(x), s->fc_x) * powf((y + 1.f) * .5f, s->fc_y) * mag_total; + l_mag = powf(.5f * ( x + 1.f), s->fl_x) * powf((y + 1.f) * .5f, s->fl_y) * mag_total; + r_mag = powf(.5f * (-x + 1.f), s->fr_x) * powf((y + 1.f) * .5f, s->fr_y) * mag_total; + lb_mag = powf(.5f * ( x + 1.f), s->bl_x) * powf(1.f - ((y + 1.f) * .5f), s->bl_y) * mag_total; + rb_mag = powf(.5f * (-x + 1.f), s->br_x) * powf(1.f - ((y + 1.f) * .5f), s->br_y) * mag_total; + ls_mag = powf(.5f * ( x + 1.f), s->sl_x) * powf(1.f - fabsf(y), s->sl_y) * mag_total; + rs_mag = powf(.5f * (-x + 1.f), s->sr_x) * powf(1.f - fabsf(y), s->sr_y) * mag_total; dstl[2 * n ] = l_mag * cosf(l_phase); dstl[2 * n + 1] = l_mag * sinf(l_phase); @@ -738,15 +942,15 @@ static void upmix_7_1(AVFilterContext *ctx, dstls = (float *)s->output->extended_data[6]; dstrs = (float *)s->output->extended_data[7]; - get_lfe(s->output_lfe, n, s->lowcut, s->highcut, &lfe_mag, &mag_total); + get_lfe(s->output_lfe, n, s->lowcut, s->highcut, &lfe_mag, &mag_total, s->lfe_mode); - c_mag = sqrtf(1.f - fabsf(x)) * ((y + 1.f) * .5f) * mag_total; - l_mag = sqrtf(.5f * ( x + 1.f)) * ((y + 1.f) * .5f) * mag_total; - r_mag = sqrtf(.5f * (-x + 1.f)) * ((y + 1.f) * .5f) * mag_total; - lb_mag = sqrtf(.5f * ( x + 1.f)) * (1.f - ((y + 1.f) * .5f)) * mag_total; - rb_mag = sqrtf(.5f * (-x + 1.f)) * (1.f - ((y + 1.f) * .5f)) * mag_total; - ls_mag = sqrtf(.5f * ( x + 1.f)) * (1.f - fabsf(y)) * mag_total; - rs_mag = sqrtf(.5f * (-x + 1.f)) * (1.f - fabsf(y)) * mag_total; + c_mag = powf(1.f - fabsf(x), s->fc_x) * powf((y + 1.f) * .5f, s->fc_y) * mag_total; + l_mag = powf(.5f * ( x + 1.f), s->fl_x) * powf((y + 1.f) * .5f, s->fl_y) * mag_total; + r_mag = powf(.5f * (-x + 1.f), s->fr_x) * powf((y + 1.f) * .5f, s->fr_y) * mag_total; + lb_mag = powf(.5f * ( x + 1.f), s->bl_x) * powf(1.f - ((y + 1.f) * .5f), s->bl_y) * mag_total; + rb_mag = powf(.5f * (-x + 1.f), s->br_x) * powf(1.f - ((y + 1.f) * .5f), s->br_y) * mag_total; + ls_mag = powf(.5f * ( x + 1.f), s->sl_x) * powf(1.f - fabsf(y), s->sl_y) * mag_total; + rs_mag = powf(.5f * (-x + 1.f), s->sr_x) * powf(1.f - fabsf(y), s->sr_y) * mag_total; dstl[2 * n ] = l_mag * cosf(l_phase); dstl[2 * n + 1] = l_mag * sinf(l_phase); @@ -799,14 +1003,14 @@ static void upmix_7_1_5_0_side(AVFilterContext *ctx, c_phase = atan2f(c_im, c_re); - get_lfe(s->output_lfe, n, s->lowcut, s->highcut, &lfe_mag, &mag_total); + get_lfe(s->output_lfe, n, s->lowcut, s->highcut, &lfe_mag, &mag_total, s->lfe_mode); - fl_mag = sqrtf(.5f * (xl + 1.f)) * ((yl + 1.f) * .5f) * mag_totall; - fr_mag = sqrtf(.5f * (xr + 1.f)) * ((yr + 1.f) * .5f) * mag_totalr; - lb_mag = sqrtf(.5f * (-xl + 1.f)) * ((yl + 1.f) * .5f) * mag_totall; - rb_mag = sqrtf(.5f * (-xr + 1.f)) * ((yr + 1.f) * .5f) * mag_totalr; - ls_mag = sqrtf(1.f - fabsf(xl)) * ((yl + 1.f) * .5f) * mag_totall; - rs_mag = sqrtf(1.f - fabsf(xr)) * ((yr + 1.f) * .5f) * mag_totalr; + fl_mag = powf(.5f * (xl + 1.f), s->fl_x) * powf((yl + 1.f) * .5f, s->fl_y) * mag_totall; + fr_mag = powf(.5f * (xr + 1.f), s->fr_x) * powf((yr + 1.f) * .5f, s->fr_y) * mag_totalr; + lb_mag = powf(.5f * (-xl + 1.f), s->bl_x) * powf((yl + 1.f) * .5f, s->bl_y) * mag_totall; + rb_mag = powf(.5f * (-xr + 1.f), s->br_x) * powf((yr + 1.f) * .5f, s->br_y) * mag_totalr; + ls_mag = powf(1.f - fabsf(xl), s->sl_x) * powf((yl + 1.f) * .5f, s->sl_y) * mag_totall; + rs_mag = powf(1.f - fabsf(xr), s->sr_x) * powf((yr + 1.f) * .5f, s->sr_y) * mag_totalr; dstl[2 * n ] = fl_mag * cosf(fl_phase); dstl[2 * n + 1] = fl_mag * sinf(fl_phase); @@ -857,12 +1061,12 @@ static void upmix_7_1_5_1(AVFilterContext *ctx, dstls = (float *)s->output->extended_data[6]; dstrs = (float *)s->output->extended_data[7]; - fl_mag = sqrtf(.5f * (xl + 1.f)) * ((yl + 1.f) * .5f) * mag_totall; - fr_mag = sqrtf(.5f * (xr + 1.f)) * ((yr + 1.f) * .5f) * mag_totalr; - lb_mag = sqrtf(.5f * (-xl + 1.f)) * ((yl + 1.f) * .5f) * mag_totall; - rb_mag = sqrtf(.5f * (-xr + 1.f)) * ((yr + 1.f) * .5f) * mag_totalr; - ls_mag = sqrtf(1.f - fabsf(xl)) * ((yl + 1.f) * .5f) * mag_totall; - rs_mag = sqrtf(1.f - fabsf(xr)) * ((yr + 1.f) * .5f) * mag_totalr; + fl_mag = powf(.5f * (xl + 1.f), s->fl_x) * powf((yl + 1.f) * .5f, s->fl_y) * mag_totall; + fr_mag = powf(.5f * (xr + 1.f), s->fr_x) * powf((yr + 1.f) * .5f, s->fr_y) * mag_totalr; + lb_mag = powf(.5f * (-xl + 1.f), s->bl_x) * powf((yl + 1.f) * .5f, s->bl_y) * mag_totall; + rb_mag = powf(.5f * (-xr + 1.f), s->br_x) * powf((yr + 1.f) * .5f, s->br_y) * mag_totalr; + ls_mag = powf(1.f - fabsf(xl), s->sl_x) * powf((yl + 1.f) * .5f, s->sl_y) * mag_totall; + rs_mag = powf(1.f - fabsf(xr), s->sr_x) * powf((yr + 1.f) * .5f, s->sr_y) * mag_totalr; dstl[2 * n ] = fl_mag * cosf(fl_phase); dstl[2 * n + 1] = fl_mag * sinf(fl_phase); @@ -907,7 +1111,8 @@ static void filter_stereo(AVFilterContext *ctx) float l_phase = atan2f(l_im, l_re); float r_phase = atan2f(r_im, r_re); float phase_dif = fabsf(l_phase - r_phase); - float mag_dif = (l_mag - r_mag) / (l_mag + r_mag); + float mag_sum = l_mag + r_mag; + float mag_dif = mag_sum < 0.000001 ? FFDIFFSIGN(l_mag, r_mag) : (l_mag - r_mag) / mag_sum; float mag_total = hypotf(l_mag, r_mag); float x, y; @@ -915,6 +1120,7 @@ static void filter_stereo(AVFilterContext *ctx) phase_dif = 2 * M_PI - phase_dif; stereo_position(mag_dif, phase_dif, &x, &y); + stereo_transform(&x, &y, s->angle); s->upmix_stereo(ctx, l_phase, r_phase, c_phase, mag_total, x, y, n); } @@ -941,7 +1147,8 @@ static void filter_surround(AVFilterContext *ctx) float l_phase = atan2f(l_im, l_re); float r_phase = atan2f(r_im, r_re); float phase_dif = fabsf(l_phase - r_phase); - float mag_dif = (l_mag - r_mag) / (l_mag + r_mag); + float mag_sum = l_mag + r_mag; + float mag_dif = mag_sum < 0.000001 ? FFDIFFSIGN(l_mag, r_mag) : (l_mag - r_mag) / mag_sum; float mag_total = hypotf(l_mag, r_mag); float x, y; @@ -949,6 +1156,7 @@ static void filter_surround(AVFilterContext *ctx) phase_dif = 2 * M_PI - phase_dif; stereo_position(mag_dif, phase_dif, &x, &y); + stereo_transform(&x, &y, s->angle); s->upmix_3_0(ctx, l_phase, r_phase, c_phase, c_mag, mag_total, x, y, n); } @@ -974,7 +1182,8 @@ static void filter_2_1(AVFilterContext *ctx) float l_phase = atan2f(l_im, l_re); float r_phase = atan2f(r_im, r_re); float phase_dif = fabsf(l_phase - r_phase); - float mag_dif = (l_mag - r_mag) / (l_mag + r_mag); + float mag_sum = l_mag + r_mag; + float mag_dif = mag_sum < 0.000001 ? FFDIFFSIGN(l_mag, r_mag) : (l_mag - r_mag) / mag_sum; float mag_total = hypotf(l_mag, r_mag); float x, y; @@ -982,6 +1191,7 @@ static void filter_2_1(AVFilterContext *ctx) phase_dif = 2 * M_PI - phase_dif; stereo_position(mag_dif, phase_dif, &x, &y); + stereo_transform(&x, &y, s->angle); s->upmix_2_1(ctx, l_phase, r_phase, c_phase, mag_total, lfe_re, lfe_im, x, y, n); } @@ -1015,8 +1225,10 @@ static void filter_5_0_side(AVFilterContext *ctx) float sr_phase = atan2f(sr_im, sr_re); float phase_difl = fabsf(fl_phase - sl_phase); float phase_difr = fabsf(fr_phase - sr_phase); - float mag_difl = (fl_mag - sl_mag) / (fl_mag + sl_mag); - float mag_difr = (fr_mag - sr_mag) / (fr_mag + sr_mag); + float magl_sum = fl_mag + sl_mag; + float magr_sum = fr_mag + sr_mag; + float mag_difl = magl_sum < 0.000001 ? FFDIFFSIGN(fl_mag, sl_mag) : (fl_mag - sl_mag) / magl_sum; + float mag_difr = magr_sum < 0.000001 ? FFDIFFSIGN(fr_mag, sr_mag) : (fr_mag - sr_mag) / magr_sum; float mag_totall = hypotf(fl_mag, sl_mag); float mag_totalr = hypotf(fr_mag, sr_mag); float bl_phase = atan2f(fl_im + sl_im, fl_re + sl_re); @@ -1072,8 +1284,10 @@ static void filter_5_1_side(AVFilterContext *ctx) float sr_phase = atan2f(sr_im, sr_re); float phase_difl = fabsf(fl_phase - sl_phase); float phase_difr = fabsf(fr_phase - sr_phase); - float mag_difl = (fl_mag - sl_mag) / (fl_mag + sl_mag); - float mag_difr = (fr_mag - sr_mag) / (fr_mag + sr_mag); + float magl_sum = fl_mag + sl_mag; + float magr_sum = fr_mag + sr_mag; + float mag_difl = magl_sum < 0.000001 ? FFDIFFSIGN(fl_mag, sl_mag) : (fl_mag - sl_mag) / magl_sum; + float mag_difr = magr_sum < 0.000001 ? FFDIFFSIGN(fr_mag, sr_mag) : (fr_mag - sr_mag) / magr_sum; float mag_totall = hypotf(fl_mag, sl_mag); float mag_totalr = hypotf(fr_mag, sr_mag); float bl_phase = atan2f(fl_im + sl_im, fl_re + sl_re); @@ -1129,8 +1343,10 @@ static void filter_5_1_back(AVFilterContext *ctx) float br_phase = atan2f(br_im, br_re); float phase_difl = fabsf(fl_phase - bl_phase); float phase_difr = fabsf(fr_phase - br_phase); - float mag_difl = (fl_mag - bl_mag) / (fl_mag + bl_mag); - float mag_difr = (fr_mag - br_mag) / (fr_mag + br_mag); + float magl_sum = fl_mag + bl_mag; + float magr_sum = fr_mag + br_mag; + float mag_difl = magl_sum < 0.000001 ? FFDIFFSIGN(fl_mag, bl_mag) : (fl_mag - bl_mag) / magl_sum; + float mag_difr = magr_sum < 0.000001 ? FFDIFFSIGN(fr_mag, br_mag) : (fr_mag - br_mag) / magr_sum; float mag_totall = hypotf(fl_mag, bl_mag); float mag_totalr = hypotf(fr_mag, br_mag); float sl_phase = atan2f(fl_im + bl_im, fl_re + bl_re); @@ -1211,6 +1427,12 @@ static int init(AVFilterContext *ctx) case AV_CH_LAYOUT_5POINT1_BACK: s->upmix_stereo = upmix_5_1_back; break; + case AV_CH_LAYOUT_6POINT0: + s->upmix_stereo = upmix_6_0; + break; + case AV_CH_LAYOUT_6POINT1: + s->upmix_stereo = upmix_6_1; + break; case AV_CH_LAYOUT_7POINT0: s->upmix_stereo = upmix_7_0; break; @@ -1281,17 +1503,27 @@ fail: return AVERROR(EINVAL); } - s->buf_size = 4096; + s->buf_size = 1 << av_log2(s->win_size); s->pts = AV_NOPTS_VALUE; s->window_func_lut = av_calloc(s->buf_size, sizeof(*s->window_func_lut)); if (!s->window_func_lut) return AVERROR(ENOMEM); + generate_window_func(s->window_func_lut, s->buf_size, s->win_func, &overlap); + if (s->overlap == 1) + s->overlap = overlap; + for (i = 0; i < s->buf_size; i++) - s->window_func_lut[i] = sqrtf(0.5 * (1 - cosf(2 * M_PI * i / s->buf_size)) / s->buf_size); - overlap = .5; - s->hop_size = s->buf_size * (1. - overlap); + s->window_func_lut[i] = sqrtf(s->window_func_lut[i] / s->buf_size); + s->hop_size = s->buf_size * (1. - s->overlap); + if (s->hop_size <= 0) + return AVERROR(EINVAL); + + if (s->all_x >= 0.f) + s->fc_x = s->fl_x = s->fr_x = s->bc_x = s->sl_x = s->sr_x = s->bl_x = s->br_x = s->all_x; + if (s->all_y >= 0.f) + s->fc_y = s->fl_y = s->fr_y = s->bc_y = s->sl_y = s->sr_y = s->bl_y = s->br_y = s->all_y; return 0; } @@ -1345,70 +1577,91 @@ static int ifft_channel(AVFilterContext *ctx, void *arg, int ch, int nb_jobs) return 0; } -static int filter_frame(AVFilterLink *inlink, AVFrame *in) +static int filter_frame(AVFilterLink *inlink) { AVFilterContext *ctx = inlink->dst; AVFilterLink *outlink = ctx->outputs[0]; AudioSurroundContext *s = ctx->priv; + AVFrame *out; int ret; - ret = av_audio_fifo_write(s->fifo, (void **)in->extended_data, - in->nb_samples); - if (ret >= 0 && s->pts == AV_NOPTS_VALUE) - s->pts = in->pts; - - av_frame_free(&in); + ret = av_audio_fifo_peek(s->fifo, (void **)s->input->extended_data, s->buf_size); if (ret < 0) return ret; - while (av_audio_fifo_size(s->fifo) >= s->buf_size) { - AVFrame *out; + ctx->internal->execute(ctx, fft_channel, NULL, NULL, inlink->channels); - ret = av_audio_fifo_peek(s->fifo, (void **)s->input->extended_data, s->buf_size); - if (ret < 0) - return ret; + s->filter(ctx); - ctx->internal->execute(ctx, fft_channel, NULL, NULL, inlink->channels); + out = ff_get_audio_buffer(outlink, s->hop_size); + if (!out) + return AVERROR(ENOMEM); - s->filter(ctx); + ctx->internal->execute(ctx, ifft_channel, out, NULL, outlink->channels); - out = ff_get_audio_buffer(outlink, s->hop_size); - if (!out) - return AVERROR(ENOMEM); + out->pts = s->pts; + if (s->pts != AV_NOPTS_VALUE) + s->pts += av_rescale_q(out->nb_samples, (AVRational){1, outlink->sample_rate}, outlink->time_base); + av_audio_fifo_drain(s->fifo, FFMIN(av_audio_fifo_size(s->fifo), s->hop_size)); - ctx->internal->execute(ctx, ifft_channel, out, NULL, outlink->channels); - - out->pts = s->pts; - if (s->pts != AV_NOPTS_VALUE) - s->pts += av_rescale_q(out->nb_samples, (AVRational){1, outlink->sample_rate}, outlink->time_base); - av_audio_fifo_drain(s->fifo, s->hop_size); - ret = ff_filter_frame(outlink, out); - if (ret < 0) - return ret; - } - - return 0; + return ff_filter_frame(outlink, out); } -static int request_frame(AVFilterLink *outlink) +static int activate(AVFilterContext *ctx) { - AVFilterContext *ctx = outlink->src; + AVFilterLink *inlink = ctx->inputs[0]; + AVFilterLink *outlink = ctx->outputs[0]; AudioSurroundContext *s = ctx->priv; - int ret = 0; + AVFrame *in = NULL; + int ret = 0, status; + int64_t pts; - ret = ff_request_frame(ctx->inputs[0]); + FF_FILTER_FORWARD_STATUS_BACK(outlink, inlink); - if (ret == AVERROR_EOF && av_audio_fifo_size(s->fifo) > 0 && av_audio_fifo_size(s->fifo) < s->buf_size) { - AVFrame *in; + if (!s->eof && av_audio_fifo_size(s->fifo) < s->buf_size) { + ret = ff_inlink_consume_frame(inlink, &in); + if (ret < 0) + return ret; - in = ff_get_audio_buffer(outlink, s->buf_size - av_audio_fifo_size(s->fifo)); - if (!in) - return AVERROR(ENOMEM); - ret = filter_frame(ctx->inputs[0], in); - av_audio_fifo_drain(s->fifo, s->buf_size); + if (ret > 0) { + ret = av_audio_fifo_write(s->fifo, (void **)in->extended_data, + in->nb_samples); + if (ret >= 0 && s->pts == AV_NOPTS_VALUE) + s->pts = in->pts; + + av_frame_free(&in); + if (ret < 0) + return ret; + } } - return ret; + if ((av_audio_fifo_size(s->fifo) >= s->buf_size) || + (av_audio_fifo_size(s->fifo) > 0 && s->eof)) { + ret = filter_frame(inlink); + if (av_audio_fifo_size(s->fifo) >= s->buf_size) + ff_filter_set_ready(ctx, 100); + return ret; + } + + if (!s->eof && ff_inlink_acknowledge_status(inlink, &status, &pts)) { + if (status == AVERROR_EOF) { + s->eof = 1; + if (av_audio_fifo_size(s->fifo) >= 0) { + ff_filter_set_ready(ctx, 100); + return 0; + } + } + } + + if (s->eof && av_audio_fifo_size(s->fifo) <= 0) { + ff_outlink_set_status(outlink, AVERROR_EOF, s->pts); + return 0; + } + + if (!s->eof) + FF_FILTER_FORWARD_WANTED(outlink, inlink); + + return FFERROR_NOT_READY; } static av_cold void uninit(AVFilterContext *ctx) @@ -1445,10 +1698,70 @@ static const AVOption surround_options[] = { { "lfe", "output LFE", OFFSET(output_lfe), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1, FLAGS }, { "lfe_low", "LFE low cut off", OFFSET(lowcutf), AV_OPT_TYPE_INT, {.i64=128}, 0, 256, FLAGS }, { "lfe_high", "LFE high cut off", OFFSET(highcutf), AV_OPT_TYPE_INT, {.i64=256}, 0, 512, FLAGS }, + { "lfe_mode", "set LFE channel mode", OFFSET(lfe_mode), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, FLAGS, "lfe_mode" }, + { "add", "just add LFE channel", 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 1, FLAGS, "lfe_mode" }, + { "sub", "substract LFE channel with others", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 1, FLAGS, "lfe_mode" }, + { "angle", "set soundfield transform angle", OFFSET(angle), AV_OPT_TYPE_FLOAT, {.dbl=90}, 0, 360, FLAGS }, { "fc_in", "set front center channel input level", OFFSET(fc_in), AV_OPT_TYPE_FLOAT, {.dbl=1}, 0, 10, FLAGS }, { "fc_out", "set front center channel output level", OFFSET(fc_out), AV_OPT_TYPE_FLOAT, {.dbl=1}, 0, 10, FLAGS }, + { "fl_in", "set front left channel input level", OFFSET(fl_in), AV_OPT_TYPE_FLOAT, {.dbl=1}, 0, 10, FLAGS }, + { "fl_out", "set front left channel output level", OFFSET(fl_out), AV_OPT_TYPE_FLOAT, {.dbl=1}, 0, 10, FLAGS }, + { "fr_in", "set front right channel input level", OFFSET(fr_in), AV_OPT_TYPE_FLOAT, {.dbl=1}, 0, 10, FLAGS }, + { "fr_out", "set front right channel output level", OFFSET(fr_out), AV_OPT_TYPE_FLOAT, {.dbl=1}, 0, 10, FLAGS }, + { "sl_in", "set side left channel input level", OFFSET(sl_in), AV_OPT_TYPE_FLOAT, {.dbl=1}, 0, 10, FLAGS }, + { "sl_out", "set side left channel output level", OFFSET(sl_out), AV_OPT_TYPE_FLOAT, {.dbl=1}, 0, 10, FLAGS }, + { "sr_in", "set side right channel input level", OFFSET(sr_in), AV_OPT_TYPE_FLOAT, {.dbl=1}, 0, 10, FLAGS }, + { "sr_out", "set side right channel output level", OFFSET(sr_out), AV_OPT_TYPE_FLOAT, {.dbl=1}, 0, 10, FLAGS }, + { "bl_in", "set back left channel input level", OFFSET(bl_in), AV_OPT_TYPE_FLOAT, {.dbl=1}, 0, 10, FLAGS }, + { "bl_out", "set back left channel output level", OFFSET(bl_out), AV_OPT_TYPE_FLOAT, {.dbl=1}, 0, 10, FLAGS }, + { "br_in", "set back right channel input level", OFFSET(br_in), AV_OPT_TYPE_FLOAT, {.dbl=1}, 0, 10, FLAGS }, + { "br_out", "set back right channel output level", OFFSET(br_out), AV_OPT_TYPE_FLOAT, {.dbl=1}, 0, 10, FLAGS }, + { "bc_in", "set back center channel input level", OFFSET(bc_in), AV_OPT_TYPE_FLOAT, {.dbl=1}, 0, 10, FLAGS }, + { "bc_out", "set back center channel output level", OFFSET(bc_out), AV_OPT_TYPE_FLOAT, {.dbl=1}, 0, 10, FLAGS }, { "lfe_in", "set lfe channel input level", OFFSET(lfe_in), AV_OPT_TYPE_FLOAT, {.dbl=1}, 0, 10, FLAGS }, { "lfe_out", "set lfe channel output level", OFFSET(lfe_out), AV_OPT_TYPE_FLOAT, {.dbl=1}, 0, 10, FLAGS }, + { "allx", "set all channel's x spread", OFFSET(all_x), AV_OPT_TYPE_FLOAT, {.dbl=-1}, -1, 15, FLAGS }, + { "ally", "set all channel's y spread", OFFSET(all_y), AV_OPT_TYPE_FLOAT, {.dbl=-1}, -1, 15, FLAGS }, + { "fcx", "set front center channel x spread", OFFSET(fc_x), AV_OPT_TYPE_FLOAT, {.dbl=1}, 0, 15, FLAGS }, + { "flx", "set front left channel x spread", OFFSET(fl_x), AV_OPT_TYPE_FLOAT, {.dbl=1}, 0, 15, FLAGS }, + { "frx", "set front right channel x spread", OFFSET(fr_x), AV_OPT_TYPE_FLOAT, {.dbl=1}, 0, 15, FLAGS }, + { "blx", "set back left channel x spread", OFFSET(bl_x), AV_OPT_TYPE_FLOAT, {.dbl=1}, 0, 15, FLAGS }, + { "brx", "set back right channel x spread", OFFSET(br_x), AV_OPT_TYPE_FLOAT, {.dbl=1}, 0, 15, FLAGS }, + { "slx", "set side left channel x spread", OFFSET(sl_x), AV_OPT_TYPE_FLOAT, {.dbl=1}, 0, 15, FLAGS }, + { "srx", "set side right channel x spread", OFFSET(sr_x), AV_OPT_TYPE_FLOAT, {.dbl=1}, 0, 15, FLAGS }, + { "bcx", "set back center channel x spread", OFFSET(bc_x), AV_OPT_TYPE_FLOAT, {.dbl=1}, 0, 15, FLAGS }, + { "fcy", "set front center channel y spread", OFFSET(fc_y), AV_OPT_TYPE_FLOAT, {.dbl=1}, 0, 15, FLAGS }, + { "fly", "set front left channel y spread", OFFSET(fl_y), AV_OPT_TYPE_FLOAT, {.dbl=1}, 0, 15, FLAGS }, + { "fry", "set front right channel y spread", OFFSET(fr_y), AV_OPT_TYPE_FLOAT, {.dbl=1}, 0, 15, FLAGS }, + { "bly", "set back left channel y spread", OFFSET(bl_y), AV_OPT_TYPE_FLOAT, {.dbl=1}, 0, 15, FLAGS }, + { "bry", "set back right channel y spread", OFFSET(br_y), AV_OPT_TYPE_FLOAT, {.dbl=1}, 0, 15, FLAGS }, + { "sly", "set side left channel y spread", OFFSET(sl_y), AV_OPT_TYPE_FLOAT, {.dbl=1}, 0, 15, FLAGS }, + { "sry", "set side right channel y spread", OFFSET(sr_y), AV_OPT_TYPE_FLOAT, {.dbl=1}, 0, 15, FLAGS }, + { "bcy", "set back center channel y spread", OFFSET(bc_y), AV_OPT_TYPE_FLOAT, {.dbl=1}, 0, 15, FLAGS }, + { "win_size", "set window size", OFFSET(win_size), AV_OPT_TYPE_INT, {.i64 = 4096}, 1024, 65536, FLAGS }, + { "win_func", "set window function", OFFSET(win_func), AV_OPT_TYPE_INT, {.i64 = WFUNC_HANNING}, 0, NB_WFUNC-1, FLAGS, "win_func" }, + { "rect", "Rectangular", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_RECT}, 0, 0, FLAGS, "win_func" }, + { "bartlett", "Bartlett", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_BARTLETT}, 0, 0, FLAGS, "win_func" }, + { "hann", "Hann", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_HANNING}, 0, 0, FLAGS, "win_func" }, + { "hanning", "Hanning", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_HANNING}, 0, 0, FLAGS, "win_func" }, + { "hamming", "Hamming", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_HAMMING}, 0, 0, FLAGS, "win_func" }, + { "blackman", "Blackman", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_BLACKMAN}, 0, 0, FLAGS, "win_func" }, + { "welch", "Welch", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_WELCH}, 0, 0, FLAGS, "win_func" }, + { "flattop", "Flat-top", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_FLATTOP}, 0, 0, FLAGS, "win_func" }, + { "bharris", "Blackman-Harris", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_BHARRIS}, 0, 0, FLAGS, "win_func" }, + { "bnuttall", "Blackman-Nuttall", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_BNUTTALL}, 0, 0, FLAGS, "win_func" }, + { "bhann", "Bartlett-Hann", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_BHANN}, 0, 0, FLAGS, "win_func" }, + { "sine", "Sine", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_SINE}, 0, 0, FLAGS, "win_func" }, + { "nuttall", "Nuttall", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_NUTTALL}, 0, 0, FLAGS, "win_func" }, + { "lanczos", "Lanczos", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_LANCZOS}, 0, 0, FLAGS, "win_func" }, + { "gauss", "Gauss", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_GAUSS}, 0, 0, FLAGS, "win_func" }, + { "tukey", "Tukey", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_TUKEY}, 0, 0, FLAGS, "win_func" }, + { "dolph", "Dolph-Chebyshev", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_DOLPH}, 0, 0, FLAGS, "win_func" }, + { "cauchy", "Cauchy", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_CAUCHY}, 0, 0, FLAGS, "win_func" }, + { "parzen", "Parzen", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_PARZEN}, 0, 0, FLAGS, "win_func" }, + { "poisson", "Poisson", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_POISSON}, 0, 0, FLAGS, "win_func" }, + { "bohman", "Bohman", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_BOHMAN}, 0, 0, FLAGS, "win_func" }, + { "overlap", "set window overlap", OFFSET(overlap), AV_OPT_TYPE_FLOAT, {.dbl=0.5}, 0, 1, FLAGS }, { NULL } }; @@ -1458,7 +1771,6 @@ static const AVFilterPad inputs[] = { { .name = "default", .type = AVMEDIA_TYPE_AUDIO, - .filter_frame = filter_frame, .config_props = config_input, }, { NULL } @@ -1468,7 +1780,6 @@ static const AVFilterPad outputs[] = { { .name = "default", .type = AVMEDIA_TYPE_AUDIO, - .request_frame = request_frame, .config_props = config_output, }, { NULL } @@ -1482,6 +1793,7 @@ AVFilter ff_af_surround = { .priv_class = &surround_class, .init = init, .uninit = uninit, + .activate = activate, .inputs = inputs, .outputs = outputs, .flags = AVFILTER_FLAG_SLICE_THREADS, diff --git a/libavfilter/allfilters.c b/libavfilter/allfilters.c index 68b299202..04a3df7d5 100644 --- a/libavfilter/allfilters.c +++ b/libavfilter/allfilters.c @@ -27,18 +27,25 @@ extern AVFilter ff_af_abench; extern AVFilter ff_af_acompressor; extern AVFilter ff_af_acontrast; extern AVFilter ff_af_acopy; +extern AVFilter ff_af_acue; extern AVFilter ff_af_acrossfade; +extern AVFilter ff_af_acrossover; extern AVFilter ff_af_acrusher; +extern AVFilter ff_af_adeclick; +extern AVFilter ff_af_adeclip; extern AVFilter ff_af_adelay; +extern AVFilter ff_af_aderivative; extern AVFilter ff_af_aecho; extern AVFilter ff_af_aemphasis; extern AVFilter ff_af_aeval; extern AVFilter ff_af_afade; +extern AVFilter ff_af_afftdn; extern AVFilter ff_af_afftfilt; extern AVFilter ff_af_afir; extern AVFilter ff_af_aformat; extern AVFilter ff_af_agate; extern AVFilter ff_af_aiir; +extern AVFilter ff_af_aintegral; extern AVFilter ff_af_ainterleave; extern AVFilter ff_af_alimiter; extern AVFilter ff_af_allpass; @@ -46,7 +53,9 @@ extern AVFilter ff_af_aloop; extern AVFilter ff_af_amerge; extern AVFilter ff_af_ametadata; extern AVFilter ff_af_amix; +extern AVFilter ff_af_amultiply; extern AVFilter ff_af_anequalizer; +extern AVFilter ff_af_anlmdn; extern AVFilter ff_af_anull; extern AVFilter ff_af_apad; extern AVFilter ff_af_aperms; @@ -63,7 +72,9 @@ extern AVFilter ff_af_asetrate; extern AVFilter ff_af_asettb; extern AVFilter ff_af_ashowinfo; extern AVFilter ff_af_asidedata; +extern AVFilter ff_af_asoftclip; extern AVFilter ff_af_asplit; +extern AVFilter ff_af_asr; extern AVFilter ff_af_astats; extern AVFilter ff_af_astreamselect; extern AVFilter ff_af_atempo; @@ -82,6 +93,7 @@ extern AVFilter ff_af_compensationdelay; extern AVFilter ff_af_crossfeed; extern AVFilter ff_af_crystalizer; extern AVFilter ff_af_dcshift; +extern AVFilter ff_af_deesser; extern AVFilter ff_af_drmeter; extern AVFilter ff_af_dynaudnorm; extern AVFilter ff_af_earwax; @@ -94,10 +106,12 @@ extern AVFilter ff_af_haas; extern AVFilter ff_af_hdcd; extern AVFilter ff_af_headphone; extern AVFilter ff_af_highpass; +extern AVFilter ff_af_highshelf; extern AVFilter ff_af_join; extern AVFilter ff_af_ladspa; extern AVFilter ff_af_loudnorm; extern AVFilter ff_af_lowpass; +extern AVFilter ff_af_lowshelf; extern AVFilter ff_af_lv2; extern AVFilter ff_af_mcompand; extern AVFilter ff_af_pan; @@ -124,12 +138,14 @@ extern AVFilter ff_asrc_anoisesrc; extern AVFilter ff_asrc_anullsrc; extern AVFilter ff_asrc_flite; extern AVFilter ff_asrc_hilbert; +extern AVFilter ff_asrc_sinc; extern AVFilter ff_asrc_sine; extern AVFilter ff_asink_anullsink; extern AVFilter ff_vf_alphaextract; extern AVFilter ff_vf_alphamerge; +extern AVFilter ff_vf_amplify; extern AVFilter ff_vf_ass; extern AVFilter ff_vf_atadenoise; extern AVFilter ff_vf_avgblur; @@ -140,14 +156,20 @@ extern AVFilter ff_vf_bitplanenoise; extern AVFilter ff_vf_blackdetect; extern AVFilter ff_vf_blackframe; extern AVFilter ff_vf_blend; +extern AVFilter ff_vf_bm3d; extern AVFilter ff_vf_boxblur; +extern AVFilter ff_vf_boxblur_opencl; extern AVFilter ff_vf_bwdif; +extern AVFilter ff_vf_chromahold; extern AVFilter ff_vf_chromakey; +extern AVFilter ff_vf_chromashift; extern AVFilter ff_vf_ciescope; extern AVFilter ff_vf_codecview; extern AVFilter ff_vf_colorbalance; extern AVFilter ff_vf_colorchannelmixer; extern AVFilter ff_vf_colorkey; +extern AVFilter ff_vf_colorkey_opencl; +extern AVFilter ff_vf_colorhold; extern AVFilter ff_vf_colorlevels; extern AVFilter ff_vf_colormatrix; extern AVFilter ff_vf_colorspace; @@ -159,12 +181,15 @@ extern AVFilter ff_vf_coreimage; extern AVFilter ff_vf_cover_rect; extern AVFilter ff_vf_crop; extern AVFilter ff_vf_cropdetect; +extern AVFilter ff_vf_cue; extern AVFilter ff_vf_curves; extern AVFilter ff_vf_datascope; extern AVFilter ff_vf_dctdnoiz; extern AVFilter ff_vf_deband; +extern AVFilter ff_vf_deblock; extern AVFilter ff_vf_decimate; extern AVFilter ff_vf_deconvolve; +extern AVFilter ff_vf_dedot; extern AVFilter ff_vf_deflate; extern AVFilter ff_vf_deflicker; extern AVFilter ff_vf_deinterlace_qsv; @@ -172,10 +197,12 @@ extern AVFilter ff_vf_deinterlace_vaapi; extern AVFilter ff_vf_dejudder; extern AVFilter ff_vf_delogo; extern AVFilter ff_vf_denoise_vaapi; +extern AVFilter ff_vf_derain; extern AVFilter ff_vf_deshake; extern AVFilter ff_vf_despill; extern AVFilter ff_vf_detelecine; extern AVFilter ff_vf_dilation; +extern AVFilter ff_vf_dilation_opencl; extern AVFilter ff_vf_displace; extern AVFilter ff_vf_doubleweave; extern AVFilter ff_vf_drawbox; @@ -187,8 +214,10 @@ extern AVFilter ff_vf_elbg; extern AVFilter ff_vf_entropy; extern AVFilter ff_vf_eq; extern AVFilter ff_vf_erosion; +extern AVFilter ff_vf_erosion_opencl; extern AVFilter ff_vf_extractplanes; extern AVFilter ff_vf_fade; +extern AVFilter ff_vf_fftdnoiz; extern AVFilter ff_vf_fftfilt; extern AVFilter ff_vf_field; extern AVFilter ff_vf_fieldhint; @@ -202,11 +231,14 @@ extern AVFilter ff_vf_fps; extern AVFilter ff_vf_framepack; extern AVFilter ff_vf_framerate; extern AVFilter ff_vf_framestep; +extern AVFilter ff_vf_freezedetect; extern AVFilter ff_vf_frei0r; extern AVFilter ff_vf_fspp; extern AVFilter ff_vf_gblur; extern AVFilter ff_vf_geq; extern AVFilter ff_vf_gradfun; +extern AVFilter ff_vf_graphmonitor; +extern AVFilter ff_vf_greyedge; extern AVFilter ff_vf_haldclut; extern AVFilter ff_vf_hflip; extern AVFilter ff_vf_histeq; @@ -226,18 +258,22 @@ extern AVFilter ff_vf_inflate; extern AVFilter ff_vf_interlace; extern AVFilter ff_vf_interleave; extern AVFilter ff_vf_kerndeint; +extern AVFilter ff_vf_lagfun; extern AVFilter ff_vf_lenscorrection; +extern AVFilter ff_vf_lensfun; extern AVFilter ff_vf_libvmaf; extern AVFilter ff_vf_limiter; extern AVFilter ff_vf_loop; extern AVFilter ff_vf_lumakey; extern AVFilter ff_vf_lut; +extern AVFilter ff_vf_lut1d; extern AVFilter ff_vf_lut2; extern AVFilter ff_vf_lut3d; extern AVFilter ff_vf_lutrgb; extern AVFilter ff_vf_lutyuv; extern AVFilter ff_vf_maskedclamp; extern AVFilter ff_vf_maskedmerge; +extern AVFilter ff_vf_maskfun; extern AVFilter ff_vf_mcdeint; extern AVFilter ff_vf_mergeplanes; extern AVFilter ff_vf_mestimate; @@ -248,6 +284,7 @@ extern AVFilter ff_vf_mix; extern AVFilter ff_vf_mpdecimate; extern AVFilter ff_vf_negate; extern AVFilter ff_vf_nlmeans; +extern AVFilter ff_vf_nlmeans_opencl; extern AVFilter ff_vf_nnedi; extern AVFilter ff_vf_noformat; extern AVFilter ff_vf_noise; @@ -272,6 +309,7 @@ extern AVFilter ff_vf_pp; extern AVFilter ff_vf_pp7; extern AVFilter ff_vf_premultiply; extern AVFilter ff_vf_prewitt; +extern AVFilter ff_vf_prewitt_opencl; extern AVFilter ff_vf_procamp_vaapi; extern AVFilter ff_vf_program_opencl; extern AVFilter ff_vf_pseudocolor; @@ -287,7 +325,9 @@ extern AVFilter ff_vf_removegrain; extern AVFilter ff_vf_removelogo; extern AVFilter ff_vf_repeatfields; extern AVFilter ff_vf_reverse; +extern AVFilter ff_vf_rgbashift; extern AVFilter ff_vf_roberts; +extern AVFilter ff_vf_roberts_opencl; extern AVFilter ff_vf_rotate; extern AVFilter ff_vf_sab; extern AVFilter ff_vf_scale; @@ -302,6 +342,7 @@ extern AVFilter ff_vf_sendcmd; extern AVFilter ff_vf_separatefields; extern AVFilter ff_vf_setdar; extern AVFilter ff_vf_setfield; +extern AVFilter ff_vf_setparams; extern AVFilter ff_vf_setpts; extern AVFilter ff_vf_setrange; extern AVFilter ff_vf_setsar; @@ -316,8 +357,10 @@ extern AVFilter ff_vf_signalstats; extern AVFilter ff_vf_signature; extern AVFilter ff_vf_smartblur; extern AVFilter ff_vf_sobel; +extern AVFilter ff_vf_sobel_opencl; extern AVFilter ff_vf_split; extern AVFilter ff_vf_spp; +extern AVFilter ff_vf_sr; extern AVFilter ff_vf_ssim; extern AVFilter ff_vf_stereo3d; extern AVFilter ff_vf_streamselect; @@ -333,8 +376,14 @@ extern AVFilter ff_vf_thumbnail_cuda; extern AVFilter ff_vf_tile; extern AVFilter ff_vf_tinterlace; extern AVFilter ff_vf_tlut2; +extern AVFilter ff_vf_tmix; extern AVFilter ff_vf_tonemap; +extern AVFilter ff_vf_tonemap_opencl; +extern AVFilter ff_vf_tpad; extern AVFilter ff_vf_transpose; +extern AVFilter ff_vf_transpose_npp; +extern AVFilter ff_vf_transpose_opencl; +extern AVFilter ff_vf_transpose_vaapi; extern AVFilter ff_vf_trim; extern AVFilter ff_vf_unpremultiply; extern AVFilter ff_vf_unsharp; @@ -344,6 +393,7 @@ extern AVFilter ff_vf_vaguedenoiser; extern AVFilter ff_vf_vectorscope; extern AVFilter ff_vf_vflip; extern AVFilter ff_vf_vfrdet; +extern AVFilter ff_vf_vibrance; extern AVFilter ff_vf_vidstabdetect; extern AVFilter ff_vf_vidstabtransform; extern AVFilter ff_vf_vignette; @@ -354,7 +404,10 @@ extern AVFilter ff_vf_w3fdif; extern AVFilter ff_vf_waveform; extern AVFilter ff_vf_weave; extern AVFilter ff_vf_xbr; +extern AVFilter ff_vf_xmedian; +extern AVFilter ff_vf_xstack; extern AVFilter ff_vf_yadif; +extern AVFilter ff_vf_yadif_cuda; extern AVFilter ff_vf_zmq; extern AVFilter ff_vf_zoompan; extern AVFilter ff_vf_zscale; @@ -371,6 +424,8 @@ extern AVFilter ff_vsrc_mandelbrot; extern AVFilter ff_vsrc_mptestsrc; extern AVFilter ff_vsrc_nullsrc; extern AVFilter ff_vsrc_openclsrc; +extern AVFilter ff_vsrc_pal75bars; +extern AVFilter ff_vsrc_pal100bars; extern AVFilter ff_vsrc_rgbtestsrc; extern AVFilter ff_vsrc_smptebars; extern AVFilter ff_vsrc_smptehdbars; @@ -383,12 +438,14 @@ extern AVFilter ff_vsink_nullsink; /* multimedia filters */ extern AVFilter ff_avf_abitscope; extern AVFilter ff_avf_adrawgraph; +extern AVFilter ff_avf_agraphmonitor; extern AVFilter ff_avf_ahistogram; extern AVFilter ff_avf_aphasemeter; extern AVFilter ff_avf_avectorscope; extern AVFilter ff_avf_concat; extern AVFilter ff_avf_showcqt; extern AVFilter ff_avf_showfreqs; +extern AVFilter ff_avf_showspatial; extern AVFilter ff_avf_showspectrum; extern AVFilter ff_avf_showspectrumpic; extern AVFilter ff_avf_showvolume; diff --git a/libavfilter/asrc_hilbert.c b/libavfilter/asrc_hilbert.c index a3a395254..a51c676c6 100644 --- a/libavfilter/asrc_hilbert.c +++ b/libavfilter/asrc_hilbert.c @@ -67,6 +67,7 @@ static const AVOption hilbert_options[] = { { "cauchy", "Cauchy", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_CAUCHY}, 0, 0, FLAGS, "win_func" }, { "parzen", "Parzen", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_PARZEN}, 0, 0, FLAGS, "win_func" }, { "poisson", "Poisson", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_POISSON}, 0, 0, FLAGS, "win_func" }, + { "bohman" , "Bohman", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_BOHMAN}, 0, 0, FLAGS, "win_func" }, {NULL} }; diff --git a/libavfilter/asrc_sinc.c b/libavfilter/asrc_sinc.c new file mode 100644 index 000000000..0135eb902 --- /dev/null +++ b/libavfilter/asrc_sinc.c @@ -0,0 +1,455 @@ +/* + * Copyright (c) 2008-2009 Rob Sykes + * Copyright (c) 2017 Paul B Mahol + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/avassert.h" +#include "libavutil/opt.h" + +#include "libavcodec/avfft.h" + +#include "audio.h" +#include "avfilter.h" +#include "internal.h" + +typedef struct SincContext { + const AVClass *class; + + int sample_rate, nb_samples; + float att, beta, phase, Fc0, Fc1, tbw0, tbw1; + int num_taps[2]; + int round; + + int n, rdft_len; + float *coeffs; + int64_t pts; + + RDFTContext *rdft, *irdft; +} SincContext; + +static int request_frame(AVFilterLink *outlink) +{ + AVFilterContext *ctx = outlink->src; + SincContext *s = ctx->priv; + const float *coeffs = s->coeffs; + AVFrame *frame = NULL; + int nb_samples; + + nb_samples = FFMIN(s->nb_samples, s->n - s->pts); + if (nb_samples <= 0) + return AVERROR_EOF; + + if (!(frame = ff_get_audio_buffer(outlink, nb_samples))) + return AVERROR(ENOMEM); + + memcpy(frame->data[0], coeffs + s->pts, nb_samples * sizeof(float)); + + frame->pts = s->pts; + s->pts += nb_samples; + + return ff_filter_frame(outlink, frame); +} + +static int query_formats(AVFilterContext *ctx) +{ + SincContext *s = ctx->priv; + static const int64_t chlayouts[] = { AV_CH_LAYOUT_MONO, -1 }; + int sample_rates[] = { s->sample_rate, -1 }; + static const enum AVSampleFormat sample_fmts[] = { AV_SAMPLE_FMT_FLT, + AV_SAMPLE_FMT_NONE }; + AVFilterFormats *formats; + AVFilterChannelLayouts *layouts; + int ret; + + formats = ff_make_format_list(sample_fmts); + if (!formats) + return AVERROR(ENOMEM); + ret = ff_set_common_formats (ctx, formats); + if (ret < 0) + return ret; + + layouts = avfilter_make_format64_list(chlayouts); + if (!layouts) + return AVERROR(ENOMEM); + ret = ff_set_common_channel_layouts(ctx, layouts); + if (ret < 0) + return ret; + + formats = ff_make_format_list(sample_rates); + if (!formats) + return AVERROR(ENOMEM); + return ff_set_common_samplerates(ctx, formats); +} + +static float bessel_I_0(float x) +{ + float term = 1, sum = 1, last_sum, x2 = x / 2; + int i = 1; + + do { + float y = x2 / i++; + + last_sum = sum; + sum += term *= y * y; + } while (sum != last_sum); + + return sum; +} + +static float *make_lpf(int num_taps, float Fc, float beta, float rho, + float scale, int dc_norm) +{ + int i, m = num_taps - 1; + float *h = av_calloc(num_taps, sizeof(*h)), sum = 0; + float mult = scale / bessel_I_0(beta), mult1 = 1.f / (.5f * m + rho); + + av_assert0(Fc >= 0 && Fc <= 1); + + for (i = 0; i <= m / 2; i++) { + float z = i - .5f * m, x = z * M_PI, y = z * mult1; + h[i] = x ? sinf(Fc * x) / x : Fc; + sum += h[i] *= bessel_I_0(beta * sqrtf(1.f - y * y)) * mult; + if (m - i != i) { + h[m - i] = h[i]; + sum += h[i]; + } + } + + for (i = 0; dc_norm && i < num_taps; i++) + h[i] *= scale / sum; + + return h; +} + +static float kaiser_beta(float att, float tr_bw) +{ + if (att >= 60.f) { + static const float coefs[][4] = { + {-6.784957e-10, 1.02856e-05, 0.1087556, -0.8988365 + .001}, + {-6.897885e-10, 1.027433e-05, 0.10876, -0.8994658 + .002}, + {-1.000683e-09, 1.030092e-05, 0.1087677, -0.9007898 + .003}, + {-3.654474e-10, 1.040631e-05, 0.1087085, -0.8977766 + .006}, + {8.106988e-09, 6.983091e-06, 0.1091387, -0.9172048 + .015}, + {9.519571e-09, 7.272678e-06, 0.1090068, -0.9140768 + .025}, + {-5.626821e-09, 1.342186e-05, 0.1083999, -0.9065452 + .05}, + {-9.965946e-08, 5.073548e-05, 0.1040967, -0.7672778 + .085}, + {1.604808e-07, -5.856462e-05, 0.1185998, -1.34824 + .1}, + {-1.511964e-07, 6.363034e-05, 0.1064627, -0.9876665 + .18}, + }; + float realm = logf(tr_bw / .0005f) / logf(2.f); + float const *c0 = coefs[av_clip((int)realm, 0, FF_ARRAY_ELEMS(coefs) - 1)]; + float const *c1 = coefs[av_clip(1 + (int)realm, 0, FF_ARRAY_ELEMS(coefs) - 1)]; + float b0 = ((c0[0] * att + c0[1]) * att + c0[2]) * att + c0[3]; + float b1 = ((c1[0] * att + c1[1]) * att + c1[2]) * att + c1[3]; + + return b0 + (b1 - b0) * (realm - (int)realm); + } + if (att > 50.f) + return .1102f * (att - 8.7f); + if (att > 20.96f) + return .58417f * powf(att - 20.96f, .4f) + .07886f * (att - 20.96f); + return 0; +} + +static void kaiser_params(float att, float Fc, float tr_bw, float *beta, int *num_taps) +{ + *beta = *beta < 0.f ? kaiser_beta(att, tr_bw * .5f / Fc): *beta; + att = att < 60.f ? (att - 7.95f) / (2.285f * M_PI * 2.f) : + ((.0007528358f-1.577737e-05 * *beta) * *beta + 0.6248022f) * *beta + .06186902f; + *num_taps = !*num_taps ? ceilf(att/tr_bw + 1) : *num_taps; +} + +static float *lpf(float Fn, float Fc, float tbw, int *num_taps, float att, float *beta, int round) +{ + int n = *num_taps; + + if ((Fc /= Fn) <= 0.f || Fc >= 1.f) { + *num_taps = 0; + return NULL; + } + + att = att ? att : 120.f; + + kaiser_params(att, Fc, (tbw ? tbw / Fn : .05f) * .5f, beta, num_taps); + + if (!n) { + n = *num_taps; + *num_taps = av_clip(n, 11, 32767); + if (round) + *num_taps = 1 + 2 * (int)((int)((*num_taps / 2) * Fc + .5f) / Fc + .5f); + } + + return make_lpf(*num_taps |= 1, Fc, *beta, 0.f, 1.f, 0); +} + +static void invert(float *h, int n) +{ + for (int i = 0; i < n; i++) + h[i] = -h[i]; + + h[(n - 1) / 2] += 1; +} + +#define PACK(h, n) h[1] = h[n] +#define UNPACK(h, n) h[n] = h[1], h[n + 1] = h[1] = 0; +#define SQR(a) ((a) * (a)) + +static float safe_log(float x) +{ + av_assert0(x >= 0); + if (x) + return logf(x); + return -26; +} + +static int fir_to_phase(SincContext *s, float **h, int *len, int *post_len, float phase) +{ + float *pi_wraps, *work, phase1 = (phase > 50.f ? 100.f - phase : phase) / 50.f; + int i, work_len, begin, end, imp_peak = 0, peak = 0; + float imp_sum = 0, peak_imp_sum = 0; + float prev_angle2 = 0, cum_2pi = 0, prev_angle1 = 0, cum_1pi = 0; + + for (i = *len, work_len = 2 * 2 * 8; i > 1; work_len <<= 1, i >>= 1); + + work = av_calloc(work_len + 2, sizeof(*work)); /* +2: (UN)PACK */ + pi_wraps = av_calloc(((work_len + 2) / 2), sizeof(*pi_wraps)); + if (!work || !pi_wraps) + return AVERROR(ENOMEM); + + memcpy(work, *h, *len * sizeof(*work)); + + av_rdft_end(s->rdft); + av_rdft_end(s->irdft); + s->rdft = s->irdft = NULL; + s->rdft = av_rdft_init(av_log2(work_len), DFT_R2C); + s->irdft = av_rdft_init(av_log2(work_len), IDFT_C2R); + if (!s->rdft || !s->irdft) + return AVERROR(ENOMEM); + + av_rdft_calc(s->rdft, work); /* Cepstral: */ + UNPACK(work, work_len); + + for (i = 0; i <= work_len; i += 2) { + float angle = atan2f(work[i + 1], work[i]); + float detect = 2 * M_PI; + float delta = angle - prev_angle2; + float adjust = detect * ((delta < -detect * .7f) - (delta > detect * .7f)); + + prev_angle2 = angle; + cum_2pi += adjust; + angle += cum_2pi; + detect = M_PI; + delta = angle - prev_angle1; + adjust = detect * ((delta < -detect * .7f) - (delta > detect * .7f)); + prev_angle1 = angle; + cum_1pi += fabsf(adjust); /* fabs for when 2pi and 1pi have combined */ + pi_wraps[i >> 1] = cum_1pi; + + work[i] = safe_log(sqrtf(SQR(work[i]) + SQR(work[i + 1]))); + work[i + 1] = 0; + } + + PACK(work, work_len); + av_rdft_calc(s->irdft, work); + + for (i = 0; i < work_len; i++) + work[i] *= 2.f / work_len; + + for (i = 1; i < work_len / 2; i++) { /* Window to reject acausal components */ + work[i] *= 2; + work[i + work_len / 2] = 0; + } + av_rdft_calc(s->rdft, work); + + for (i = 2; i < work_len; i += 2) /* Interpolate between linear & min phase */ + work[i + 1] = phase1 * i / work_len * pi_wraps[work_len >> 1] + (1 - phase1) * (work[i + 1] + pi_wraps[i >> 1]) - pi_wraps[i >> 1]; + + work[0] = exp(work[0]); + work[1] = exp(work[1]); + for (i = 2; i < work_len; i += 2) { + float x = expf(work[i]); + + work[i ] = x * cosf(work[i + 1]); + work[i + 1] = x * sinf(work[i + 1]); + } + + av_rdft_calc(s->irdft, work); + for (i = 0; i < work_len; i++) + work[i] *= 2.f / work_len; + + /* Find peak pos. */ + for (i = 0; i <= (int) (pi_wraps[work_len >> 1] / M_PI + .5f); i++) { + imp_sum += work[i]; + if (fabs(imp_sum) > fabs(peak_imp_sum)) { + peak_imp_sum = imp_sum; + peak = i; + } + if (work[i] > work[imp_peak]) /* For debug check only */ + imp_peak = i; + } + + while (peak && fabsf(work[peak - 1]) > fabsf(work[peak]) && (work[peak - 1] * work[peak] > 0)) { + peak--; + } + + if (!phase1) { + begin = 0; + } else if (phase1 == 1) { + begin = peak - *len / 2; + } else { + begin = (.997f - (2 - phase1) * .22f) * *len + .5f; + end = (.997f + (0 - phase1) * .22f) * *len + .5f; + begin = peak - (begin & ~3); + end = peak + 1 + ((end + 3) & ~3); + *len = end - begin; + *h = av_realloc_f(*h, *len, sizeof(**h)); + if (!*h) { + av_free(pi_wraps); + av_free(work); + return AVERROR(ENOMEM); + } + } + + for (i = 0; i < *len; i++) { + (*h)[i] = work[(begin + (phase > 50.f ? *len - 1 - i : i) + work_len) & (work_len - 1)]; + } + *post_len = phase > 50 ? peak - begin : begin + *len - (peak + 1); + + av_log(s, AV_LOG_DEBUG, "%d nPI=%g peak-sum@%i=%g (val@%i=%g); len=%i post=%i (%g%%)\n", + work_len, pi_wraps[work_len >> 1] / M_PI, peak, peak_imp_sum, imp_peak, + work[imp_peak], *len, *post_len, 100.f - 100.f * *post_len / (*len - 1)); + + av_free(pi_wraps); + av_free(work); + + return 0; +} + +static int config_output(AVFilterLink *outlink) +{ + AVFilterContext *ctx = outlink->src; + SincContext *s = ctx->priv; + float Fn = s->sample_rate * .5f; + float *h[2]; + int i, n, post_peak, longer; + + outlink->sample_rate = s->sample_rate; + s->pts = 0; + + if (s->Fc0 >= Fn || s->Fc1 >= Fn) { + av_log(ctx, AV_LOG_ERROR, + "filter frequency must be less than %d/2.\n", s->sample_rate); + return AVERROR(EINVAL); + } + + h[0] = lpf(Fn, s->Fc0, s->tbw0, &s->num_taps[0], s->att, &s->beta, s->round); + h[1] = lpf(Fn, s->Fc1, s->tbw1, &s->num_taps[1], s->att, &s->beta, s->round); + + if (h[0]) + invert(h[0], s->num_taps[0]); + + longer = s->num_taps[1] > s->num_taps[0]; + n = s->num_taps[longer]; + + if (h[0] && h[1]) { + for (i = 0; i < s->num_taps[!longer]; i++) + h[longer][i + (n - s->num_taps[!longer]) / 2] += h[!longer][i]; + + if (s->Fc0 < s->Fc1) + invert(h[longer], n); + + av_free(h[!longer]); + } + + if (s->phase != 50.f) { + int ret = fir_to_phase(s, &h[longer], &n, &post_peak, s->phase); + if (ret < 0) + return ret; + } else { + post_peak = n >> 1; + } + + s->n = 1 << (av_log2(n) + 1); + s->rdft_len = 1 << av_log2(n); + s->coeffs = av_calloc(s->n, sizeof(*s->coeffs)); + if (!s->coeffs) + return AVERROR(ENOMEM); + + for (i = 0; i < n; i++) + s->coeffs[i] = h[longer][i]; + av_free(h[longer]); + + av_rdft_end(s->rdft); + av_rdft_end(s->irdft); + s->rdft = s->irdft = NULL; + + return 0; +} + +static av_cold void uninit(AVFilterContext *ctx) +{ + SincContext *s = ctx->priv; + + av_freep(&s->coeffs); + av_rdft_end(s->rdft); + av_rdft_end(s->irdft); + s->rdft = s->irdft = NULL; +} + +static const AVFilterPad sinc_outputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_AUDIO, + .config_props = config_output, + .request_frame = request_frame, + }, + { NULL } +}; + +#define AF AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM +#define OFFSET(x) offsetof(SincContext, x) + +static const AVOption sinc_options[] = { + { "sample_rate", "set sample rate", OFFSET(sample_rate), AV_OPT_TYPE_INT, {.i64=44100}, 1, INT_MAX, AF }, + { "r", "set sample rate", OFFSET(sample_rate), AV_OPT_TYPE_INT, {.i64=44100}, 1, INT_MAX, AF }, + { "nb_samples", "set the number of samples per requested frame", OFFSET(nb_samples), AV_OPT_TYPE_INT, {.i64=1024}, 1, INT_MAX, AF }, + { "n", "set the number of samples per requested frame", OFFSET(nb_samples), AV_OPT_TYPE_INT, {.i64=1024}, 1, INT_MAX, AF }, + { "hp", "set high-pass filter frequency", OFFSET(Fc0), AV_OPT_TYPE_FLOAT, {.dbl=0}, 0, INT_MAX, AF }, + { "lp", "set low-pass filter frequency", OFFSET(Fc1), AV_OPT_TYPE_FLOAT, {.dbl=0}, 0, INT_MAX, AF }, + { "phase", "set filter phase response", OFFSET(phase), AV_OPT_TYPE_FLOAT, {.dbl=50}, 0, 100, AF }, + { "beta", "set kaiser window beta", OFFSET(beta), AV_OPT_TYPE_FLOAT, {.dbl=-1}, -1, 256, AF }, + { "att", "set stop-band attenuation", OFFSET(att), AV_OPT_TYPE_FLOAT, {.dbl=120}, 40, 180, AF }, + { "round", "enable rounding", OFFSET(round), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, AF }, + { "hptaps", "set number of taps for high-pass filter", OFFSET(num_taps[0]), AV_OPT_TYPE_INT, {.i64=0}, 0, 32768, AF }, + { "lptaps", "set number of taps for low-pass filter", OFFSET(num_taps[1]), AV_OPT_TYPE_INT, {.i64=0}, 0, 32768, AF }, + { NULL } +}; + +AVFILTER_DEFINE_CLASS(sinc); + +AVFilter ff_asrc_sinc = { + .name = "sinc", + .description = NULL_IF_CONFIG_SMALL("Generate a sinc kaiser-windowed low-pass, high-pass, band-pass, or band-reject FIR coefficients."), + .priv_size = sizeof(SincContext), + .priv_class = &sinc_class, + .query_formats = query_formats, + .uninit = uninit, + .inputs = NULL, + .outputs = sinc_outputs, +}; diff --git a/libavfilter/avf_abitscope.c b/libavfilter/avf_abitscope.c index 0e3eaa422..6a38521b6 100644 --- a/libavfilter/avf_abitscope.c +++ b/libavfilter/avf_abitscope.c @@ -24,6 +24,7 @@ #include "libavutil/opt.h" #include "libavutil/parseutils.h" #include "avfilter.h" +#include "filters.h" #include "formats.h" #include "audio.h" #include "video.h" @@ -36,6 +37,7 @@ typedef struct AudioBitScopeContext { char *colors; int nb_channels; + int nb_samples; int depth; uint8_t *fg; @@ -91,13 +93,10 @@ static int config_input(AVFilterLink *inlink) { AVFilterContext *ctx = inlink->dst; AudioBitScopeContext *s = ctx->priv; - int ch, nb_samples; + int ch; char *colors, *saveptr = NULL; - nb_samples = FFMAX(1024, ((double)inlink->sample_rate / av_q2d(s->frame_rate)) + 0.5); - inlink->partial_buf_size = - inlink->min_samples = - inlink->max_samples = nb_samples; + s->nb_samples = FFMAX(1, av_rescale(inlink->sample_rate, s->frame_rate.den, s->frame_rate.num)); s->nb_channels = inlink->channels; s->depth = inlink->format == AV_SAMPLE_FMT_S16P ? 16 : 32; @@ -222,12 +221,33 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *insamples) return ff_filter_frame(outlink, outpicref); } +static int activate(AVFilterContext *ctx) +{ + AVFilterLink *inlink = ctx->inputs[0]; + AVFilterLink *outlink = ctx->outputs[0]; + AudioBitScopeContext *s = ctx->priv; + AVFrame *in; + int ret; + + FF_FILTER_FORWARD_STATUS_BACK(outlink, inlink); + + ret = ff_inlink_consume_samples(inlink, s->nb_samples, s->nb_samples, &in); + if (ret < 0) + return ret; + if (ret > 0) + return filter_frame(inlink, in); + + FF_FILTER_FORWARD_STATUS(inlink, outlink); + FF_FILTER_FORWARD_WANTED(outlink, inlink); + + return FFERROR_NOT_READY; +} + static const AVFilterPad inputs[] = { { .name = "default", .type = AVMEDIA_TYPE_AUDIO, .config_props = config_input, - .filter_frame = filter_frame, }, { NULL } }; @@ -248,5 +268,6 @@ AVFilter ff_avf_abitscope = { .priv_size = sizeof(AudioBitScopeContext), .inputs = inputs, .outputs = outputs, + .activate = activate, .priv_class = &abitscope_class, }; diff --git a/libavfilter/avf_ahistogram.c b/libavfilter/avf_ahistogram.c index 587415175..a0931bfa5 100644 --- a/libavfilter/avf_ahistogram.c +++ b/libavfilter/avf_ahistogram.c @@ -22,6 +22,7 @@ #include "libavutil/opt.h" #include "libavutil/parseutils.h" #include "avfilter.h" +#include "filters.h" #include "formats.h" #include "audio.h" #include "video.h" @@ -54,6 +55,7 @@ typedef struct AudioHistogramContext { float *combine_buffer; AVFrame *in[101]; int first; + int nb_samples; } AudioHistogramContext; #define OFFSET(x) offsetof(AudioHistogramContext, x) @@ -117,13 +119,8 @@ static int config_input(AVFilterLink *inlink) { AVFilterContext *ctx = inlink->dst; AudioHistogramContext *s = ctx->priv; - int nb_samples; - - nb_samples = FFMAX(1024, ((double)inlink->sample_rate / av_q2d(s->frame_rate)) + 0.5); - inlink->partial_buf_size = - inlink->min_samples = - inlink->max_samples = nb_samples; + s->nb_samples = FFMAX(1, av_rescale(inlink->sample_rate, s->frame_rate.den, s->frame_rate.num)); s->dchannels = s->dmode == SINGLE ? 1 : inlink->channels; s->shistogram = av_calloc(s->w, s->dchannels * sizeof(*s->shistogram)); if (!s->shistogram) @@ -369,6 +366,28 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) return ff_filter_frame(outlink, av_frame_clone(s->out)); } +static int activate(AVFilterContext *ctx) +{ + AVFilterLink *inlink = ctx->inputs[0]; + AVFilterLink *outlink = ctx->outputs[0]; + AudioHistogramContext *s = ctx->priv; + AVFrame *in; + int ret; + + FF_FILTER_FORWARD_STATUS_BACK(outlink, inlink); + + ret = ff_inlink_consume_samples(inlink, s->nb_samples, s->nb_samples, &in); + if (ret < 0) + return ret; + if (ret > 0) + return filter_frame(inlink, in); + + FF_FILTER_FORWARD_STATUS(inlink, outlink); + FF_FILTER_FORWARD_WANTED(outlink, inlink); + + return FFERROR_NOT_READY; +} + static av_cold void uninit(AVFilterContext *ctx) { AudioHistogramContext *s = ctx->priv; @@ -382,17 +401,16 @@ static av_cold void uninit(AVFilterContext *ctx) av_frame_free(&s->in[i]); } -static const AVFilterPad audiovectorscope_inputs[] = { +static const AVFilterPad ahistogram_inputs[] = { { .name = "default", .type = AVMEDIA_TYPE_AUDIO, .config_props = config_input, - .filter_frame = filter_frame, }, { NULL } }; -static const AVFilterPad audiovectorscope_outputs[] = { +static const AVFilterPad ahistogram_outputs[] = { { .name = "default", .type = AVMEDIA_TYPE_VIDEO, @@ -407,7 +425,8 @@ AVFilter ff_avf_ahistogram = { .uninit = uninit, .query_formats = query_formats, .priv_size = sizeof(AudioHistogramContext), - .inputs = audiovectorscope_inputs, - .outputs = audiovectorscope_outputs, + .activate = activate, + .inputs = ahistogram_inputs, + .outputs = ahistogram_outputs, .priv_class = &ahistogram_class, }; diff --git a/libavfilter/avf_aphasemeter.c b/libavfilter/avf_aphasemeter.c index 8cdee9464..f497bc996 100644 --- a/libavfilter/avf_aphasemeter.c +++ b/libavfilter/avf_aphasemeter.c @@ -106,7 +106,7 @@ static int config_input(AVFilterLink *inlink) int nb_samples; if (s->do_video) { - nb_samples = FFMAX(1024, ((double)inlink->sample_rate / av_q2d(s->frame_rate)) + 0.5); + nb_samples = FFMAX(1, av_rescale(inlink->sample_rate, s->frame_rate.den, s->frame_rate.num)); inlink->partial_buf_size = inlink->min_samples = inlink->max_samples = nb_samples; @@ -233,6 +233,7 @@ static av_cold int init(AVFilterContext *ctx) { AudioPhaseMeterContext *s = ctx->priv; AVFilterPad pad; + int ret; pad = (AVFilterPad){ .name = av_strdup("out0"), @@ -240,7 +241,11 @@ static av_cold int init(AVFilterContext *ctx) }; if (!pad.name) return AVERROR(ENOMEM); - ff_insert_outpad(ctx, 0, &pad); + ret = ff_insert_outpad(ctx, 0, &pad); + if (ret < 0) { + av_freep(&pad.name); + return ret; + } if (s->do_video) { pad = (AVFilterPad){ @@ -250,7 +255,11 @@ static av_cold int init(AVFilterContext *ctx) }; if (!pad.name) return AVERROR(ENOMEM); - ff_insert_outpad(ctx, 1, &pad); + ret = ff_insert_outpad(ctx, 1, &pad); + if (ret < 0) { + av_freep(&pad.name); + return ret; + } } return 0; diff --git a/libavfilter/avf_avectorscope.c b/libavfilter/avf_avectorscope.c index 75e0ee5e2..0f53b36df 100644 --- a/libavfilter/avf_avectorscope.c +++ b/libavfilter/avf_avectorscope.c @@ -28,6 +28,7 @@ #include "libavutil/opt.h" #include "libavutil/parseutils.h" #include "avfilter.h" +#include "filters.h" #include "formats.h" #include "audio.h" #include "video.h" @@ -69,6 +70,7 @@ typedef struct AudioVectorScopeContext { int mirror; unsigned prev_x, prev_y; AVRational frame_rate; + int nb_samples; } AudioVectorScopeContext; #define OFFSET(x) offsetof(AudioVectorScopeContext, x) @@ -102,7 +104,7 @@ static const AVOption avectorscope_options[] = { { "cbrt", "cube root", 0, AV_OPT_TYPE_CONST, {.i64=CBRT}, 0, 0, FLAGS, "scale" }, { "log", "logarithmic", 0, AV_OPT_TYPE_CONST, {.i64=LOG}, 0, 0, FLAGS, "scale" }, { "swap", "swap x axis with y axis", OFFSET(swap), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1, FLAGS }, - { "mirror", "mirror axis", OFFSET(mirror), AV_OPT_TYPE_INT, {.i64=2}, 0, 3, FLAGS, "mirror" }, + { "mirror", "mirror axis", OFFSET(mirror), AV_OPT_TYPE_INT, {.i64=0}, 0, 3, FLAGS, "mirror" }, { "none", "no mirror", 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, FLAGS, "mirror" }, { "x", "mirror x", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, FLAGS, "mirror" }, { "y", "mirror y", 0, AV_OPT_TYPE_CONST, {.i64=2}, 0, 0, FLAGS, "mirror" }, @@ -208,12 +210,8 @@ static int config_input(AVFilterLink *inlink) { AVFilterContext *ctx = inlink->dst; AudioVectorScopeContext *s = ctx->priv; - int nb_samples; - nb_samples = FFMAX(1024, ((double)inlink->sample_rate / av_q2d(s->frame_rate)) + 0.5); - inlink->partial_buf_size = - inlink->min_samples = - inlink->max_samples = nb_samples; + s->nb_samples = FFMAX(1, av_rescale(inlink->sample_rate, s->frame_rate.den, s->frame_rate.num)); return 0; } @@ -365,6 +363,28 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *insamples) return ff_filter_frame(outlink, av_frame_clone(s->outpicref)); } +static int activate(AVFilterContext *ctx) +{ + AVFilterLink *inlink = ctx->inputs[0]; + AVFilterLink *outlink = ctx->outputs[0]; + AudioVectorScopeContext *s = ctx->priv; + AVFrame *in; + int ret; + + FF_FILTER_FORWARD_STATUS_BACK(outlink, inlink); + + ret = ff_inlink_consume_samples(inlink, s->nb_samples, s->nb_samples, &in); + if (ret < 0) + return ret; + if (ret > 0) + return filter_frame(inlink, in); + + FF_FILTER_FORWARD_STATUS(inlink, outlink); + FF_FILTER_FORWARD_WANTED(outlink, inlink); + + return FFERROR_NOT_READY; +} + static av_cold void uninit(AVFilterContext *ctx) { AudioVectorScopeContext *s = ctx->priv; @@ -377,7 +397,6 @@ static const AVFilterPad audiovectorscope_inputs[] = { .name = "default", .type = AVMEDIA_TYPE_AUDIO, .config_props = config_input, - .filter_frame = filter_frame, }, { NULL } }; @@ -397,6 +416,7 @@ AVFilter ff_avf_avectorscope = { .uninit = uninit, .query_formats = query_formats, .priv_size = sizeof(AudioVectorScopeContext), + .activate = activate, .inputs = audiovectorscope_inputs, .outputs = audiovectorscope_outputs, .priv_class = &avectorscope_class, diff --git a/libavfilter/avf_concat.c b/libavfilter/avf_concat.c index 46bd42359..1d0c2de29 100644 --- a/libavfilter/avf_concat.c +++ b/libavfilter/avf_concat.c @@ -28,8 +28,7 @@ #include "libavutil/channel_layout.h" #include "libavutil/opt.h" #include "avfilter.h" -#define FF_BUFQUEUE_SIZE 256 -#include "bufferqueue.h" +#include "filters.h" #include "internal.h" #include "video.h" #include "audio.h" @@ -48,7 +47,6 @@ typedef struct ConcatContext { int64_t pts; int64_t nb_frames; unsigned eof; - struct FFBufQueue queue; } *in; } ConcatContext; @@ -185,24 +183,6 @@ static int push_frame(AVFilterContext *ctx, unsigned in_no, AVFrame *buf) return ff_filter_frame(outlink, buf); } -static int process_frame(AVFilterLink *inlink, AVFrame *buf) -{ - AVFilterContext *ctx = inlink->dst; - ConcatContext *cat = ctx->priv; - unsigned in_no = FF_INLINK_IDX(inlink); - - if (in_no < cat->cur_idx) { - av_log(ctx, AV_LOG_ERROR, "Frame after EOF on input %s\n", - ctx->input_pads[in_no].name); - av_frame_free(&buf); - } else if (in_no >= cat->cur_idx + ctx->nb_outputs) { - ff_bufqueue_add(ctx, &cat->in[in_no].queue, buf); - } else { - return push_frame(ctx, in_no, buf); - } - return 0; -} - static AVFrame *get_video_buffer(AVFilterLink *inlink, int w, int h) { AVFilterContext *ctx = inlink->dst; @@ -221,11 +201,6 @@ static AVFrame *get_audio_buffer(AVFilterLink *inlink, int nb_samples) return ff_get_audio_buffer(outlink, nb_samples); } -static int filter_frame(AVFilterLink *inlink, AVFrame *buf) -{ - return process_frame(inlink, buf); -} - static void close_input(AVFilterContext *ctx, unsigned in_no) { ConcatContext *cat = ctx->priv; @@ -306,57 +281,10 @@ static int flush_segment(AVFilterContext *ctx) if (ret < 0) return ret; } - /* flush queued buffers */ - /* possible enhancement: flush in PTS order */ - str_max = cat->cur_idx + ctx->nb_outputs; - for (str = cat->cur_idx; str < str_max; str++) { - while (cat->in[str].queue.available) { - ret = push_frame(ctx, str, ff_bufqueue_get(&cat->in[str].queue)); - if (ret < 0) - return ret; - } - } } return 0; } -static int request_frame(AVFilterLink *outlink) -{ - AVFilterContext *ctx = outlink->src; - ConcatContext *cat = ctx->priv; - unsigned out_no = FF_OUTLINK_IDX(outlink); - unsigned in_no = out_no + cat->cur_idx; - unsigned str, str_max; - int ret; - - while (1) { - if (in_no >= ctx->nb_inputs) - return AVERROR_EOF; - if (!cat->in[in_no].eof) { - ret = ff_request_frame(ctx->inputs[in_no]); - if (ret != AVERROR_EOF) - return ret; - close_input(ctx, in_no); - } - /* cycle on all inputs to finish the segment */ - /* possible enhancement: request in PTS order */ - str_max = cat->cur_idx + ctx->nb_outputs - 1; - for (str = cat->cur_idx; cat->nb_in_active; - str = str == str_max ? cat->cur_idx : str + 1) { - if (cat->in[str].eof) - continue; - ret = ff_request_frame(ctx->inputs[str]); - if (ret != AVERROR_EOF) - return ret; - close_input(ctx, str); - } - ret = flush_segment(ctx); - if (ret < 0) - return ret; - in_no += ctx->nb_outputs; - } -} - static av_cold int init(AVFilterContext *ctx) { ConcatContext *cat = ctx->priv; @@ -371,7 +299,6 @@ static av_cold int init(AVFilterContext *ctx) .type = type, .get_video_buffer = get_video_buffer, .get_audio_buffer = get_audio_buffer, - .filter_frame = filter_frame, }; pad.name = av_asprintf("in%d:%c%d", seg, "va"[type], str); if ((ret = ff_insert_inpad(ctx, ctx->nb_inputs, &pad)) < 0) { @@ -387,7 +314,6 @@ static av_cold int init(AVFilterContext *ctx) AVFilterPad pad = { .type = type, .config_props = config_output, - .request_frame = request_frame, }; pad.name = av_asprintf("out:%c%d", "va"[type], str); if ((ret = ff_insert_outpad(ctx, ctx->nb_outputs, &pad)) < 0) { @@ -409,15 +335,88 @@ static av_cold void uninit(AVFilterContext *ctx) ConcatContext *cat = ctx->priv; unsigned i; - for (i = 0; i < ctx->nb_inputs; i++) { + for (i = 0; i < ctx->nb_inputs; i++) av_freep(&ctx->input_pads[i].name); - ff_bufqueue_discard_all(&cat->in[i].queue); - } for (i = 0; i < ctx->nb_outputs; i++) av_freep(&ctx->output_pads[i].name); av_freep(&cat->in); } +static int activate(AVFilterContext *ctx) +{ + ConcatContext *cat = ctx->priv; + AVFrame *frame; + unsigned i, j; + int ret, status; + int64_t pts; + + /* Forward status back */ + for (i = 0; i < ctx->nb_outputs; i++) { + status = ff_outlink_get_status(ctx->outputs[i]); + if (!status) + continue; + for (j = i; j < ctx->nb_inputs; j += ctx->nb_outputs) { + if (!cat->in[j].eof) { + cat->in[j].eof = 1; + ff_inlink_set_status(ctx->inputs[j], status); + return 0; + } + } + + } + + /* Forward available frames */ + if (cat->cur_idx < ctx->nb_inputs) { + for (i = 0; i < ctx->nb_outputs; i++) { + ret = ff_inlink_consume_frame(ctx->inputs[cat->cur_idx + i], &frame); + if (ret < 0) + return ret; + if (ret) { + ff_filter_set_ready(ctx, 10); + return push_frame(ctx, cat->cur_idx + i, frame); + } + } + } + + /* Forward status change */ + if (cat->cur_idx < ctx->nb_inputs) { + for (i = 0; i < ctx->nb_outputs; i++) { + ret = ff_inlink_acknowledge_status(ctx->inputs[cat->cur_idx + i], &status, &pts); + /* TODO use pts */ + if (ret > 0) { + close_input(ctx, cat->cur_idx + i); + if (cat->cur_idx + ctx->nb_outputs >= ctx->nb_inputs) { + ff_outlink_set_status(ctx->outputs[i], status, pts); + } + if (!cat->nb_in_active) { + ret = flush_segment(ctx); + if (ret < 0) + return ret; + } + ff_filter_set_ready(ctx, 10); + return 0; + } + } + } + + ret = FFERROR_NOT_READY; + for (i = 0; i < ctx->nb_outputs; i++) { + if (ff_outlink_frame_wanted(ctx->outputs[i])) { + if (cat->in[cat->cur_idx + i].eof) { + for (j = 0; j < ctx->nb_outputs; j++) + if (!cat->in[cat->cur_idx + j].eof) + ff_inlink_request_frame(ctx->inputs[cat->cur_idx + j]); + return 0; + } else { + ff_inlink_request_frame(ctx->inputs[cat->cur_idx + i]); + ret = 0; + } + } + } + + return ret; +} + static int process_command(AVFilterContext *ctx, const char *cmd, const char *args, char *res, int res_len, int flags) { @@ -437,6 +436,7 @@ AVFilter ff_avf_concat = { .init = init, .uninit = uninit, .query_formats = query_formats, + .activate = activate, .priv_size = sizeof(ConcatContext), .inputs = NULL, .outputs = NULL, diff --git a/libavfilter/avf_showfreqs.c b/libavfilter/avf_showfreqs.c index 22f28ec38..8755ac3a9 100644 --- a/libavfilter/avf_showfreqs.c +++ b/libavfilter/avf_showfreqs.c @@ -30,6 +30,7 @@ #include "libavutil/opt.h" #include "libavutil/parseutils.h" #include "audio.h" +#include "filters.h" #include "video.h" #include "avfilter.h" #include "internal.h" @@ -45,6 +46,7 @@ typedef struct ShowFreqsContext { int w, h; int mode; int cmode; + int fft_size; int fft_bits; int ascale, fscale; int avg; @@ -84,20 +86,7 @@ static const AVOption showfreqs_options[] = { { "lin", "linear", 0, AV_OPT_TYPE_CONST, {.i64=FS_LINEAR}, 0, 0, FLAGS, "fscale" }, { "log", "logarithmic", 0, AV_OPT_TYPE_CONST, {.i64=FS_LOG}, 0, 0, FLAGS, "fscale" }, { "rlog", "reverse logarithmic", 0, AV_OPT_TYPE_CONST, {.i64=FS_RLOG}, 0, 0, FLAGS, "fscale" }, - { "win_size", "set window size", OFFSET(fft_bits), AV_OPT_TYPE_INT, {.i64=11}, 4, 16, FLAGS, "fft" }, - { "w16", 0, 0, AV_OPT_TYPE_CONST, {.i64=4}, 0, 0, FLAGS, "fft" }, - { "w32", 0, 0, AV_OPT_TYPE_CONST, {.i64=5}, 0, 0, FLAGS, "fft" }, - { "w64", 0, 0, AV_OPT_TYPE_CONST, {.i64=6}, 0, 0, FLAGS, "fft" }, - { "w128", 0, 0, AV_OPT_TYPE_CONST, {.i64=7}, 0, 0, FLAGS, "fft" }, - { "w256", 0, 0, AV_OPT_TYPE_CONST, {.i64=8}, 0, 0, FLAGS, "fft" }, - { "w512", 0, 0, AV_OPT_TYPE_CONST, {.i64=9}, 0, 0, FLAGS, "fft" }, - { "w1024", 0, 0, AV_OPT_TYPE_CONST, {.i64=10}, 0, 0, FLAGS, "fft" }, - { "w2048", 0, 0, AV_OPT_TYPE_CONST, {.i64=11}, 0, 0, FLAGS, "fft" }, - { "w4096", 0, 0, AV_OPT_TYPE_CONST, {.i64=12}, 0, 0, FLAGS, "fft" }, - { "w8192", 0, 0, AV_OPT_TYPE_CONST, {.i64=13}, 0, 0, FLAGS, "fft" }, - { "w16384", 0, 0, AV_OPT_TYPE_CONST, {.i64=14}, 0, 0, FLAGS, "fft" }, - { "w32768", 0, 0, AV_OPT_TYPE_CONST, {.i64=15}, 0, 0, FLAGS, "fft" }, - { "w65536", 0, 0, AV_OPT_TYPE_CONST, {.i64=16}, 0, 0, FLAGS, "fft" }, + { "win_size", "set window size", OFFSET(fft_size), AV_OPT_TYPE_INT, {.i64=2048}, 16, 65536, FLAGS }, { "win_func", "set window function", OFFSET(win_func), AV_OPT_TYPE_INT, {.i64=WFUNC_HANNING}, 0, NB_WFUNC-1, FLAGS, "win_func" }, { "rect", "Rectangular", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_RECT}, 0, 0, FLAGS, "win_func" }, { "bartlett", "Bartlett", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_BARTLETT}, 0, 0, FLAGS, "win_func" }, @@ -118,6 +107,7 @@ static const AVOption showfreqs_options[] = { { "cauchy", "Cauchy", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_CAUCHY}, 0, 0, FLAGS, "win_func" }, { "parzen", "Parzen", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_PARZEN}, 0, 0, FLAGS, "win_func" }, { "poisson", "Poisson", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_POISSON}, 0, 0, FLAGS, "win_func" }, + { "bohman", "Bohman", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_BOHMAN} , 0, 0, FLAGS, "win_func" }, { "overlap", "set window overlap", OFFSET(overlap), AV_OPT_TYPE_FLOAT, {.dbl=1.}, 0., 1., FLAGS }, { "averaging", "set time averaging", OFFSET(avg), AV_OPT_TYPE_INT, {.i64=1}, 0, INT32_MAX, FLAGS }, { "colors", "set channels colors", OFFSET(colors), AV_OPT_TYPE_STRING, {.str = "red|green|blue|yellow|orange|lime|pink|magenta|brown" }, 0, 0, FLAGS }, @@ -178,6 +168,7 @@ static int config_output(AVFilterLink *outlink) float overlap; int i; + s->fft_bits = av_log2(s->fft_size); s->nb_freq = 1 << (s->fft_bits - 1); s->win_size = s->nb_freq << 1; av_audio_fifo_free(s->fifo); @@ -438,45 +429,66 @@ static int plot_freqs(AVFilterLink *inlink, AVFrame *in) return ff_filter_frame(outlink, out); } -static int filter_frame(AVFilterLink *inlink, AVFrame *in) +static int filter_frame(AVFilterLink *inlink) { AVFilterContext *ctx = inlink->dst; ShowFreqsContext *s = ctx->priv; AVFrame *fin = NULL; - int consumed = 0; int ret = 0; - if (s->pts == AV_NOPTS_VALUE) - s->pts = in->pts - av_audio_fifo_size(s->fifo); - - av_audio_fifo_write(s->fifo, (void **)in->extended_data, in->nb_samples); - while (av_audio_fifo_size(s->fifo) >= s->win_size) { - fin = ff_get_audio_buffer(inlink, s->win_size); - if (!fin) { - ret = AVERROR(ENOMEM); - goto fail; - } - - fin->pts = s->pts + consumed; - consumed += s->hop_size; - ret = av_audio_fifo_peek(s->fifo, (void **)fin->extended_data, s->win_size); - if (ret < 0) - goto fail; - - ret = plot_freqs(inlink, fin); - av_frame_free(&fin); - av_audio_fifo_drain(s->fifo, s->hop_size); - if (ret < 0) - goto fail; + fin = ff_get_audio_buffer(inlink, s->win_size); + if (!fin) { + ret = AVERROR(ENOMEM); + goto fail; } + fin->pts = s->pts; + s->pts += s->hop_size; + ret = av_audio_fifo_peek(s->fifo, (void **)fin->extended_data, s->win_size); + if (ret < 0) + goto fail; + + ret = plot_freqs(inlink, fin); + av_frame_free(&fin); + av_audio_fifo_drain(s->fifo, s->hop_size); + fail: - s->pts = AV_NOPTS_VALUE; av_frame_free(&fin); - av_frame_free(&in); return ret; } +static int activate(AVFilterContext *ctx) +{ + AVFilterLink *inlink = ctx->inputs[0]; + AVFilterLink *outlink = ctx->outputs[0]; + ShowFreqsContext *s = ctx->priv; + AVFrame *in = NULL; + int ret = 0; + + FF_FILTER_FORWARD_STATUS_BACK(outlink, inlink); + + if (av_audio_fifo_size(s->fifo) < s->win_size) + ret = ff_inlink_consume_samples(inlink, s->win_size, s->win_size, &in); + if (ret < 0) + return ret; + if (ret > 0) { + av_audio_fifo_write(s->fifo, (void **)in->extended_data, in->nb_samples); + if (s->pts == AV_NOPTS_VALUE) + s->pts = in->pts; + } + + if (av_audio_fifo_size(s->fifo) >= s->win_size) { + ret = filter_frame(inlink); + if (ret <= 0) + return ret; + } + + FF_FILTER_FORWARD_STATUS(inlink, outlink); + FF_FILTER_FORWARD_WANTED(outlink, inlink); + + return FFERROR_NOT_READY; +} + static av_cold void uninit(AVFilterContext *ctx) { ShowFreqsContext *s = ctx->priv; @@ -499,7 +511,6 @@ static const AVFilterPad showfreqs_inputs[] = { { .name = "default", .type = AVMEDIA_TYPE_AUDIO, - .filter_frame = filter_frame, }, { NULL } }; @@ -520,6 +531,7 @@ AVFilter ff_avf_showfreqs = { .uninit = uninit, .query_formats = query_formats, .priv_size = sizeof(ShowFreqsContext), + .activate = activate, .inputs = showfreqs_inputs, .outputs = showfreqs_outputs, .priv_class = &showfreqs_class, diff --git a/libavfilter/avf_showspatial.c b/libavfilter/avf_showspatial.c new file mode 100644 index 000000000..80109a305 --- /dev/null +++ b/libavfilter/avf_showspatial.c @@ -0,0 +1,372 @@ +/* + * Copyright (c) 2019 Paul B Mahol + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include + +#include "libavcodec/avfft.h" +#include "libavutil/audio_fifo.h" +#include "libavutil/avassert.h" +#include "libavutil/channel_layout.h" +#include "libavutil/opt.h" +#include "libavutil/parseutils.h" +#include "audio.h" +#include "video.h" +#include "avfilter.h" +#include "filters.h" +#include "internal.h" +#include "window_func.h" + +typedef struct ShowSpatialContext { + const AVClass *class; + int w, h; + AVRational frame_rate; + FFTContext *fft[2]; ///< Fast Fourier Transform context + FFTContext *ifft[2]; ///< Inverse Fast Fourier Transform context + int fft_bits; ///< number of bits (FFT window size = 1<priv; + int i; + + for (i = 0; i < 2; i++) + av_fft_end(s->fft[i]); + for (i = 0; i < 2; i++) + av_fft_end(s->ifft[i]); + for (i = 0; i < 2; i++) + av_freep(&s->fft_data[i]); + av_freep(&s->window_func_lut); + av_audio_fifo_free(s->fifo); +} + +static int query_formats(AVFilterContext *ctx) +{ + AVFilterFormats *formats = NULL; + AVFilterChannelLayouts *layout = NULL; + AVFilterLink *inlink = ctx->inputs[0]; + AVFilterLink *outlink = ctx->outputs[0]; + static const enum AVSampleFormat sample_fmts[] = { AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_NONE }; + static const enum AVPixelFormat pix_fmts[] = { AV_PIX_FMT_GBRP, AV_PIX_FMT_NONE }; + int ret; + + formats = ff_make_format_list(sample_fmts); + if ((ret = ff_formats_ref (formats, &inlink->out_formats )) < 0 || + (ret = ff_add_channel_layout (&layout, AV_CH_LAYOUT_STEREO )) < 0 || + (ret = ff_channel_layouts_ref (layout , &inlink->out_channel_layouts)) < 0) + return ret; + + formats = ff_all_samplerates(); + if ((ret = ff_formats_ref(formats, &inlink->out_samplerates)) < 0) + return ret; + + formats = ff_make_format_list(pix_fmts); + if ((ret = ff_formats_ref(formats, &outlink->in_formats)) < 0) + return ret; + + return 0; +} + +static int run_channel_fft(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) +{ + ShowSpatialContext *s = ctx->priv; + const float *window_func_lut = s->window_func_lut; + AVFrame *fin = arg; + const int ch = jobnr; + const float *p = (float *)fin->extended_data[ch]; + + for (int n = 0; n < fin->nb_samples; n++) { + s->fft_data[ch][n].re = p[n] * window_func_lut[n]; + s->fft_data[ch][n].im = 0; + } + + av_fft_permute(s->fft[ch], s->fft_data[ch]); + av_fft_calc(s->fft[ch], s->fft_data[ch]); + + return 0; +} + +static int config_output(AVFilterLink *outlink) +{ + AVFilterContext *ctx = outlink->src; + AVFilterLink *inlink = ctx->inputs[0]; + ShowSpatialContext *s = ctx->priv; + int i, fft_bits; + float overlap; + + outlink->w = s->w; + outlink->h = s->h; + outlink->sample_aspect_ratio = (AVRational){1,1}; + + s->buf_size = 1 << av_log2(s->win_size); + s->win_size = s->buf_size; + fft_bits = av_log2(s->win_size); + + /* (re-)configuration if the video output changed (or first init) */ + if (fft_bits != s->fft_bits) { + s->fft_bits = fft_bits; + + /* FFT buffers: x2 for each channel buffer. + * Note: we use free and malloc instead of a realloc-like function to + * make sure the buffer is aligned in memory for the FFT functions. */ + for (i = 0; i < 2; i++) { + av_fft_end(s->fft[i]); + av_freep(&s->fft_data[i]); + } + for (i = 0; i < 2; i++) { + s->fft[i] = av_fft_init(fft_bits, 0); + if (!s->fft[i]) { + av_log(ctx, AV_LOG_ERROR, "Unable to create FFT context. " + "The window size might be too high.\n"); + return AVERROR(EINVAL); + } + } + + for (i = 0; i < 2; i++) { + s->fft_data[i] = av_calloc(s->buf_size, sizeof(**s->fft_data)); + if (!s->fft_data[i]) + return AVERROR(ENOMEM); + } + + /* pre-calc windowing function */ + s->window_func_lut = + av_realloc_f(s->window_func_lut, s->win_size, + sizeof(*s->window_func_lut)); + if (!s->window_func_lut) + return AVERROR(ENOMEM); + generate_window_func(s->window_func_lut, s->win_size, s->win_func, &overlap); + if (s->overlap == 1) + s->overlap = overlap; + + s->hop_size = (1.f - s->overlap) * s->win_size; + if (s->hop_size < 1) { + av_log(ctx, AV_LOG_ERROR, "overlap %f too big\n", s->overlap); + return AVERROR(EINVAL); + } + } + + outlink->time_base = av_inv_q(outlink->frame_rate); + + av_audio_fifo_free(s->fifo); + s->fifo = av_audio_fifo_alloc(inlink->format, inlink->channels, s->win_size); + if (!s->fifo) + return AVERROR(ENOMEM); + return 0; +} + +#define RE(y, ch) s->fft_data[ch][y].re +#define IM(y, ch) s->fft_data[ch][y].im + +static void draw_dot(uint8_t *dst, int linesize, int value) +{ + dst[0] = value; + dst[1] = value; + dst[-1] = value; + dst[linesize] = value; + dst[-linesize] = value; +} + +static int draw_spatial(AVFilterLink *inlink, AVFrame *insamples) +{ + AVFilterContext *ctx = inlink->dst; + AVFilterLink *outlink = ctx->outputs[0]; + ShowSpatialContext *s = ctx->priv; + AVFrame *outpicref; + int h = s->h - 2; + int w = s->w - 2; + int z = s->win_size / 2; + + outpicref = ff_get_video_buffer(outlink, outlink->w, outlink->h); + if (!outpicref) + return AVERROR(ENOMEM); + + outpicref->sample_aspect_ratio = (AVRational){1,1}; + for (int i = 0; i < outlink->h; i++) { + memset(outpicref->data[0] + i * outpicref->linesize[0], 0, outlink->w); + memset(outpicref->data[1] + i * outpicref->linesize[1], 0, outlink->w); + memset(outpicref->data[2] + i * outpicref->linesize[2], 0, outlink->w); + } + + for (int j = 0; j < z; j++) { + const int idx = z - 1 - j; + float l = hypotf(RE(idx, 0), IM(idx, 0)); + float r = hypotf(RE(idx, 1), IM(idx, 1)); + float sum = l + r; + float lp = atan2f(IM(idx, 0), RE(idx, 0)); + float rp = atan2f(IM(idx, 1), RE(idx, 1)); + float diffp = ((rp - lp) / (2.f * M_PI) + 1.f) * 0.5f; + float diff = (sum < 0.000001f ? 0.f : (r - l) / sum) * 0.5f + 0.5f; + float cr = av_clipf(cbrtf(l / sum), 0, 1) * 255.f; + float cb = av_clipf(cbrtf(r / sum), 0, 1) * 255.f; + float cg; + int x, y; + + cg = diffp * 255.f; + x = av_clip(w * diff, 0, w - 2) + 1; + y = av_clip(h * diffp, 0, h - 2) + 1; + + draw_dot(outpicref->data[0] + outpicref->linesize[0] * y + x, outpicref->linesize[0], cg); + draw_dot(outpicref->data[1] + outpicref->linesize[1] * y + x, outpicref->linesize[1], cb); + draw_dot(outpicref->data[2] + outpicref->linesize[2] * y + x, outpicref->linesize[2], cr); + } + + outpicref->pts = av_rescale_q(insamples->pts, inlink->time_base, outlink->time_base); + + return ff_filter_frame(outlink, outpicref); +} + +static int spatial_activate(AVFilterContext *ctx) +{ + AVFilterLink *inlink = ctx->inputs[0]; + AVFilterLink *outlink = ctx->outputs[0]; + ShowSpatialContext *s = ctx->priv; + int ret; + + FF_FILTER_FORWARD_STATUS_BACK(outlink, inlink); + + if (av_audio_fifo_size(s->fifo) < s->win_size) { + AVFrame *frame = NULL; + + ret = ff_inlink_consume_frame(inlink, &frame); + if (ret < 0) + return ret; + if (ret > 0) { + s->pts = frame->pts; + s->consumed = 0; + + av_audio_fifo_write(s->fifo, (void **)frame->extended_data, frame->nb_samples); + av_frame_free(&frame); + } + } + + if (av_audio_fifo_size(s->fifo) >= s->win_size) { + AVFrame *fin = ff_get_audio_buffer(inlink, s->win_size); + if (!fin) + return AVERROR(ENOMEM); + + fin->pts = s->pts + s->consumed; + s->consumed += s->hop_size; + ret = av_audio_fifo_peek(s->fifo, (void **)fin->extended_data, + FFMIN(s->win_size, av_audio_fifo_size(s->fifo))); + if (ret < 0) { + av_frame_free(&fin); + return ret; + } + + av_assert0(fin->nb_samples == s->win_size); + + ctx->internal->execute(ctx, run_channel_fft, fin, NULL, 2); + + ret = draw_spatial(inlink, fin); + + av_frame_free(&fin); + av_audio_fifo_drain(s->fifo, s->hop_size); + if (ret <= 0) + return ret; + } + + FF_FILTER_FORWARD_STATUS(inlink, outlink); + if (ff_outlink_frame_wanted(outlink) && av_audio_fifo_size(s->fifo) < s->win_size) { + ff_inlink_request_frame(inlink); + return 0; + } + + if (av_audio_fifo_size(s->fifo) >= s->win_size) { + ff_filter_set_ready(ctx, 10); + return 0; + } + return FFERROR_NOT_READY; +} + +static const AVFilterPad showspatial_inputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_AUDIO, + }, + { NULL } +}; + +static const AVFilterPad showspatial_outputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + .config_props = config_output, + }, + { NULL } +}; + +AVFilter ff_avf_showspatial = { + .name = "showspatial", + .description = NULL_IF_CONFIG_SMALL("Convert input audio to a spatial video output."), + .uninit = uninit, + .query_formats = query_formats, + .priv_size = sizeof(ShowSpatialContext), + .inputs = showspatial_inputs, + .outputs = showspatial_outputs, + .activate = spatial_activate, + .priv_class = &showspatial_class, + .flags = AVFILTER_FLAG_SLICE_THREADS, +}; diff --git a/libavfilter/avf_showspectrum.c b/libavfilter/avf_showspectrum.c index 956f62f3a..f175bf1cb 100644 --- a/libavfilter/avf_showspectrum.c +++ b/libavfilter/avf_showspectrum.c @@ -34,23 +34,29 @@ #include "libavutil/avstring.h" #include "libavutil/channel_layout.h" #include "libavutil/opt.h" +#include "libavutil/parseutils.h" #include "libavutil/xga_font_data.h" #include "audio.h" #include "video.h" #include "avfilter.h" +#include "filters.h" #include "internal.h" #include "window_func.h" enum DisplayMode { COMBINED, SEPARATE, NB_MODES }; enum DataMode { D_MAGNITUDE, D_PHASE, NB_DMODES }; +enum FrequencyScale { F_LINEAR, F_LOG, NB_FSCALES }; enum DisplayScale { LINEAR, SQRT, CBRT, LOG, FOURTHRT, FIFTHRT, NB_SCALES }; -enum ColorMode { CHANNEL, INTENSITY, RAINBOW, MORELAND, NEBULAE, FIRE, FIERY, FRUIT, COOL, NB_CLMODES }; +enum ColorMode { CHANNEL, INTENSITY, RAINBOW, MORELAND, NEBULAE, FIRE, FIERY, FRUIT, COOL, MAGMA, GREEN, VIRIDIS, PLASMA, CIVIDIS, TERRAIN, NB_CLMODES }; enum SlideMode { REPLACE, SCROLL, FULLFRAME, RSCROLL, NB_SLIDES }; enum Orientation { VERTICAL, HORIZONTAL, NB_ORIENTATIONS }; typedef struct ShowSpectrumContext { const AVClass *class; int w, h; + char *rate_str; + AVRational auto_frame_rate; + AVRational frame_rate; AVFrame *outpicref; int nb_display_channels; int orientation; @@ -60,29 +66,38 @@ typedef struct ShowSpectrumContext { int mode; ///< channel display mode int color_mode; ///< display color scheme int scale; + int fscale; float saturation; ///< color saturation multiplier float rotation; ///< color rotation + int start, stop; ///< zoom mode int data; int xpos; ///< x position (current column) FFTContext **fft; ///< Fast Fourier Transform context + FFTContext **ifft; ///< Inverse Fast Fourier Transform context int fft_bits; ///< number of bits (FFT window size = 1<fft[i]); } av_freep(&s->fft); + if (s->ifft) { + for (i = 0; i < s->nb_display_channels; i++) + av_fft_end(s->ifft[i]); + } + av_freep(&s->ifft); if (s->fft_data) { for (i = 0; i < s->nb_display_channels; i++) av_freep(&s->fft_data[i]); } av_freep(&s->fft_data); + if (s->fft_scratch) { + for (i = 0; i < s->nb_display_channels; i++) + av_freep(&s->fft_scratch[i]); + } + av_freep(&s->fft_scratch); if (s->color_buffer) { for (i = 0; i < s->nb_display_channels; i++) av_freep(&s->color_buffer[i]); @@ -291,6 +374,606 @@ static int query_formats(AVFilterContext *ctx) return 0; } +static int run_channel_fft(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) +{ + ShowSpectrumContext *s = ctx->priv; + AVFilterLink *inlink = ctx->inputs[0]; + const float *window_func_lut = s->window_func_lut; + AVFrame *fin = arg; + const int ch = jobnr; + int n; + + /* fill FFT input with the number of samples available */ + const float *p = (float *)fin->extended_data[ch]; + + for (n = 0; n < s->win_size; n++) { + s->fft_data[ch][n].re = p[n] * window_func_lut[n]; + s->fft_data[ch][n].im = 0; + } + + if (s->stop) { + float theta, phi, psi, a, b, S, c; + FFTComplex *g = s->fft_data[ch]; + FFTComplex *h = s->fft_scratch[ch]; + int L = s->buf_size; + int N = s->win_size; + int M = s->win_size / 2; + + phi = 2.f * M_PI * (s->stop - s->start) / (float)inlink->sample_rate / (M - 1); + theta = 2.f * M_PI * s->start / (float)inlink->sample_rate; + + for (int n = 0; n < M; n++) { + h[n].re = cosf(n * n / 2.f * phi); + h[n].im = sinf(n * n / 2.f * phi); + } + + for (int n = M; n < L; n++) { + h[n].re = 0.f; + h[n].im = 0.f; + } + + for (int n = L - N; n < L; n++) { + h[n].re = cosf((L - n) * (L - n) / 2.f * phi); + h[n].im = sinf((L - n) * (L - n) / 2.f * phi); + } + + for (int n = 0; n < N; n++) { + g[n].re = s->fft_data[ch][n].re; + g[n].im = s->fft_data[ch][n].im; + } + + for (int n = N; n < L; n++) { + g[n].re = 0.f; + g[n].im = 0.f; + } + + for (int n = 0; n < N; n++) { + psi = n * theta + n * n / 2.f * phi; + c = cosf(psi); + S = -sinf(psi); + a = c * g[n].re - S * g[n].im; + b = S * g[n].re + c * g[n].im; + g[n].re = a; + g[n].im = b; + } + + av_fft_permute(s->fft[ch], h); + av_fft_calc(s->fft[ch], h); + + av_fft_permute(s->fft[ch], g); + av_fft_calc(s->fft[ch], g); + + for (int n = 0; n < L; n++) { + c = g[n].re; + S = g[n].im; + a = c * h[n].re - S * h[n].im; + b = S * h[n].re + c * h[n].im; + + g[n].re = a / L; + g[n].im = b / L; + } + + av_fft_permute(s->ifft[ch], g); + av_fft_calc(s->ifft[ch], g); + + for (int k = 0; k < M; k++) { + psi = k * k / 2.f * phi; + c = cosf(psi); + S = -sinf(psi); + a = c * g[k].re - S * g[k].im; + b = S * g[k].re + c * g[k].im; + s->fft_data[ch][k].re = a; + s->fft_data[ch][k].im = b; + } + } else { + /* run FFT on each samples set */ + av_fft_permute(s->fft[ch], s->fft_data[ch]); + av_fft_calc(s->fft[ch], s->fft_data[ch]); + } + + return 0; +} + +static void drawtext(AVFrame *pic, int x, int y, const char *txt, int o) +{ + const uint8_t *font; + int font_height; + int i; + + font = avpriv_cga_font, font_height = 8; + + for (i = 0; txt[i]; i++) { + int char_y, mask; + + if (o) { + for (char_y = font_height - 1; char_y >= 0; char_y--) { + uint8_t *p = pic->data[0] + (y + i * 10) * pic->linesize[0] + x; + for (mask = 0x80; mask; mask >>= 1) { + if (font[txt[i] * font_height + font_height - 1 - char_y] & mask) + p[char_y] = ~p[char_y]; + p += pic->linesize[0]; + } + } + } else { + uint8_t *p = pic->data[0] + y*pic->linesize[0] + (x + i*8); + for (char_y = 0; char_y < font_height; char_y++) { + for (mask = 0x80; mask; mask >>= 1) { + if (font[txt[i] * font_height + char_y] & mask) + *p = ~(*p); + p++; + } + p += pic->linesize[0] - 8; + } + } + } +} + +static void color_range(ShowSpectrumContext *s, int ch, + float *yf, float *uf, float *vf) +{ + switch (s->mode) { + case COMBINED: + // reduce range by channel count + *yf = 256.0f / s->nb_display_channels; + switch (s->color_mode) { + case RAINBOW: + case MORELAND: + case NEBULAE: + case FIRE: + case FIERY: + case FRUIT: + case COOL: + case GREEN: + case VIRIDIS: + case PLASMA: + case CIVIDIS: + case TERRAIN: + case MAGMA: + case INTENSITY: + *uf = *yf; + *vf = *yf; + break; + case CHANNEL: + /* adjust saturation for mixed UV coloring */ + /* this factor is correct for infinite channels, an approximation otherwise */ + *uf = *yf * M_PI; + *vf = *yf * M_PI; + break; + default: + av_assert0(0); + } + break; + case SEPARATE: + // full range + *yf = 256.0f; + *uf = 256.0f; + *vf = 256.0f; + break; + default: + av_assert0(0); + } + + if (s->color_mode == CHANNEL) { + if (s->nb_display_channels > 1) { + *uf *= 0.5f * sinf((2 * M_PI * ch) / s->nb_display_channels + M_PI * s->rotation); + *vf *= 0.5f * cosf((2 * M_PI * ch) / s->nb_display_channels + M_PI * s->rotation); + } else { + *uf *= 0.5f * sinf(M_PI * s->rotation); + *vf *= 0.5f * cosf(M_PI * s->rotation + M_PI_2); + } + } else { + *uf += *uf * sinf(M_PI * s->rotation); + *vf += *vf * cosf(M_PI * s->rotation + M_PI_2); + } + + *uf *= s->saturation; + *vf *= s->saturation; +} + +static void pick_color(ShowSpectrumContext *s, + float yf, float uf, float vf, + float a, float *out) +{ + if (s->color_mode > CHANNEL) { + const int cm = s->color_mode; + float y, u, v; + int i; + + for (i = 1; i < FF_ARRAY_ELEMS(color_table[cm]) - 1; i++) + if (color_table[cm][i].a >= a) + break; + // i now is the first item >= the color + // now we know to interpolate between item i - 1 and i + if (a <= color_table[cm][i - 1].a) { + y = color_table[cm][i - 1].y; + u = color_table[cm][i - 1].u; + v = color_table[cm][i - 1].v; + } else if (a >= color_table[cm][i].a) { + y = color_table[cm][i].y; + u = color_table[cm][i].u; + v = color_table[cm][i].v; + } else { + float start = color_table[cm][i - 1].a; + float end = color_table[cm][i].a; + float lerpfrac = (a - start) / (end - start); + y = color_table[cm][i - 1].y * (1.0f - lerpfrac) + + color_table[cm][i].y * lerpfrac; + u = color_table[cm][i - 1].u * (1.0f - lerpfrac) + + color_table[cm][i].u * lerpfrac; + v = color_table[cm][i - 1].v * (1.0f - lerpfrac) + + color_table[cm][i].v * lerpfrac; + } + + out[0] = y * yf; + out[1] = u * uf; + out[2] = v * vf; + } else { + out[0] = a * yf; + out[1] = a * uf; + out[2] = a * vf; + } +} + +static char *get_time(AVFilterContext *ctx, float seconds, int x) +{ + char *units; + + if (x == 0) + units = av_asprintf("0"); + else if (log10(seconds) > 6) + units = av_asprintf("%.2fh", seconds / (60 * 60)); + else if (log10(seconds) > 3) + units = av_asprintf("%.2fm", seconds / 60); + else + units = av_asprintf("%.2fs", seconds); + return units; +} + +static float log_scale(const float value, const float min, const float max) +{ + if (value < min) + return min; + if (value > max) + return max; + + { + const float b = logf(max / min) / (max - min); + const float a = max / expf(max * b); + + return expf(value * b) * a; + } +} + +static float get_log_hz(const int bin, const int num_bins, const float sample_rate) +{ + const float max_freq = sample_rate / 2; + const float hz_per_bin = max_freq / num_bins; + const float freq = hz_per_bin * bin; + const float scaled_freq = log_scale(freq + 1, 21, max_freq) - 1; + + return num_bins * scaled_freq / max_freq; +} + +static float inv_log_scale(const float value, const float min, const float max) +{ + if (value < min) + return min; + if (value > max) + return max; + + { + const float b = logf(max / min) / (max - min); + const float a = max / expf(max * b); + + return logf(value / a) / b; + } +} + +static float bin_pos(const int bin, const int num_bins, const float sample_rate) +{ + const float max_freq = sample_rate / 2; + const float hz_per_bin = max_freq / num_bins; + const float freq = hz_per_bin * bin; + const float scaled_freq = inv_log_scale(freq + 1, 21, max_freq) - 1; + + return num_bins * scaled_freq / max_freq; +} + +static int draw_legend(AVFilterContext *ctx, int samples) +{ + ShowSpectrumContext *s = ctx->priv; + AVFilterLink *inlink = ctx->inputs[0]; + AVFilterLink *outlink = ctx->outputs[0]; + int ch, y, x = 0, sz = s->orientation == VERTICAL ? s->w : s->h; + int multi = (s->mode == SEPARATE && s->color_mode == CHANNEL); + float spp = samples / (float)sz; + char *text; + uint8_t *dst; + char chlayout_str[128]; + + av_get_channel_layout_string(chlayout_str, sizeof(chlayout_str), inlink->channels, + inlink->channel_layout); + + text = av_asprintf("%d Hz | %s", inlink->sample_rate, chlayout_str); + + drawtext(s->outpicref, 2, outlink->h - 10, "CREATED BY LIBAVFILTER", 0); + drawtext(s->outpicref, outlink->w - 2 - strlen(text) * 10, outlink->h - 10, text, 0); + if (s->stop) { + char *text = av_asprintf("Zoom: %d Hz - %d Hz", s->start, s->stop); + drawtext(s->outpicref, outlink->w - 2 - strlen(text) * 10, 3, text, 0); + av_freep(&text); + } + + av_freep(&text); + + dst = s->outpicref->data[0] + (s->start_y - 1) * s->outpicref->linesize[0] + s->start_x - 1; + for (x = 0; x < s->w + 1; x++) + dst[x] = 200; + dst = s->outpicref->data[0] + (s->start_y + s->h) * s->outpicref->linesize[0] + s->start_x - 1; + for (x = 0; x < s->w + 1; x++) + dst[x] = 200; + for (y = 0; y < s->h + 2; y++) { + dst = s->outpicref->data[0] + (y + s->start_y - 1) * s->outpicref->linesize[0]; + dst[s->start_x - 1] = 200; + dst[s->start_x + s->w] = 200; + } + if (s->orientation == VERTICAL) { + int h = s->mode == SEPARATE ? s->h / s->nb_display_channels : s->h; + int hh = s->mode == SEPARATE ? -(s->h % s->nb_display_channels) + 1 : 1; + for (ch = 0; ch < (s->mode == SEPARATE ? s->nb_display_channels : 1); ch++) { + for (y = 0; y < h; y += 20) { + dst = s->outpicref->data[0] + (s->start_y + h * (ch + 1) - y - hh) * s->outpicref->linesize[0]; + dst[s->start_x - 2] = 200; + dst[s->start_x + s->w + 1] = 200; + } + for (y = 0; y < h; y += 40) { + dst = s->outpicref->data[0] + (s->start_y + h * (ch + 1) - y - hh) * s->outpicref->linesize[0]; + dst[s->start_x - 3] = 200; + dst[s->start_x + s->w + 2] = 200; + } + dst = s->outpicref->data[0] + (s->start_y - 2) * s->outpicref->linesize[0] + s->start_x; + for (x = 0; x < s->w; x+=40) + dst[x] = 200; + dst = s->outpicref->data[0] + (s->start_y - 3) * s->outpicref->linesize[0] + s->start_x; + for (x = 0; x < s->w; x+=80) + dst[x] = 200; + dst = s->outpicref->data[0] + (s->h + s->start_y + 1) * s->outpicref->linesize[0] + s->start_x; + for (x = 0; x < s->w; x+=40) { + dst[x] = 200; + } + dst = s->outpicref->data[0] + (s->h + s->start_y + 2) * s->outpicref->linesize[0] + s->start_x; + for (x = 0; x < s->w; x+=80) { + dst[x] = 200; + } + for (y = 0; y < h; y += 40) { + float range = s->stop ? s->stop - s->start : inlink->sample_rate / 2; + float bin = s->fscale == F_LINEAR ? y : get_log_hz(y, h, inlink->sample_rate); + float hertz = s->start + bin * range / (float)(1 << (int)ceil(log2(h))); + char *units; + + if (hertz == 0) + units = av_asprintf("DC"); + else + units = av_asprintf("%.2f", hertz); + if (!units) + return AVERROR(ENOMEM); + + drawtext(s->outpicref, s->start_x - 8 * strlen(units) - 4, h * (ch + 1) + s->start_y - y - 4 - hh, units, 0); + av_free(units); + } + } + + for (x = 0; x < s->w && s->single_pic; x+=80) { + float seconds = x * spp / inlink->sample_rate; + char *units = get_time(ctx, seconds, x); + + drawtext(s->outpicref, s->start_x + x - 4 * strlen(units), s->h + s->start_y + 6, units, 0); + drawtext(s->outpicref, s->start_x + x - 4 * strlen(units), s->start_y - 12, units, 0); + av_free(units); + } + + drawtext(s->outpicref, outlink->w / 2 - 4 * 4, outlink->h - s->start_y / 2, "TIME", 0); + drawtext(s->outpicref, s->start_x / 7, outlink->h / 2 - 14 * 4, "FREQUENCY (Hz)", 1); + } else { + int w = s->mode == SEPARATE ? s->w / s->nb_display_channels : s->w; + for (y = 0; y < s->h; y += 20) { + dst = s->outpicref->data[0] + (s->start_y + y) * s->outpicref->linesize[0]; + dst[s->start_x - 2] = 200; + dst[s->start_x + s->w + 1] = 200; + } + for (y = 0; y < s->h; y += 40) { + dst = s->outpicref->data[0] + (s->start_y + y) * s->outpicref->linesize[0]; + dst[s->start_x - 3] = 200; + dst[s->start_x + s->w + 2] = 200; + } + for (ch = 0; ch < (s->mode == SEPARATE ? s->nb_display_channels : 1); ch++) { + dst = s->outpicref->data[0] + (s->start_y - 2) * s->outpicref->linesize[0] + s->start_x + w * ch; + for (x = 0; x < w; x+=40) + dst[x] = 200; + dst = s->outpicref->data[0] + (s->start_y - 3) * s->outpicref->linesize[0] + s->start_x + w * ch; + for (x = 0; x < w; x+=80) + dst[x] = 200; + dst = s->outpicref->data[0] + (s->h + s->start_y + 1) * s->outpicref->linesize[0] + s->start_x + w * ch; + for (x = 0; x < w; x+=40) { + dst[x] = 200; + } + dst = s->outpicref->data[0] + (s->h + s->start_y + 2) * s->outpicref->linesize[0] + s->start_x + w * ch; + for (x = 0; x < w; x+=80) { + dst[x] = 200; + } + for (x = 0; x < w - 79; x += 80) { + float range = s->stop ? s->stop - s->start : inlink->sample_rate / 2; + float bin = s->fscale == F_LINEAR ? x : get_log_hz(x, w, inlink->sample_rate); + float hertz = s->start + bin * range / (float)(1 << (int)ceil(log2(w))); + char *units; + + if (hertz == 0) + units = av_asprintf("DC"); + else + units = av_asprintf("%.2f", hertz); + if (!units) + return AVERROR(ENOMEM); + + drawtext(s->outpicref, s->start_x - 4 * strlen(units) + x + w * ch, s->start_y - 12, units, 0); + drawtext(s->outpicref, s->start_x - 4 * strlen(units) + x + w * ch, s->h + s->start_y + 6, units, 0); + av_free(units); + } + } + for (y = 0; y < s->h && s->single_pic; y+=40) { + float seconds = y * spp / inlink->sample_rate; + char *units = get_time(ctx, seconds, x); + + drawtext(s->outpicref, s->start_x - 8 * strlen(units) - 4, s->start_y + y - 4, units, 0); + av_free(units); + } + drawtext(s->outpicref, s->start_x / 7, outlink->h / 2 - 4 * 4, "TIME", 1); + drawtext(s->outpicref, outlink->w / 2 - 14 * 4, outlink->h - s->start_y / 2, "FREQUENCY (Hz)", 0); + } + + for (ch = 0; ch < (multi ? s->nb_display_channels : 1); ch++) { + int h = multi ? s->h / s->nb_display_channels : s->h; + + for (y = 0; y < h; y++) { + float out[3] = { 0., 127.5, 127.5}; + int chn; + + for (chn = 0; chn < (s->mode == SEPARATE ? 1 : s->nb_display_channels); chn++) { + float yf, uf, vf; + int channel = (multi) ? s->nb_display_channels - ch - 1 : chn; + float lout[3]; + + color_range(s, channel, &yf, &uf, &vf); + pick_color(s, yf, uf, vf, y / (float)h, lout); + out[0] += lout[0]; + out[1] += lout[1]; + out[2] += lout[2]; + } + memset(s->outpicref->data[0]+(s->start_y + h * (ch + 1) - y - 1) * s->outpicref->linesize[0] + s->w + s->start_x + 20, av_clip_uint8(out[0]), 10); + memset(s->outpicref->data[1]+(s->start_y + h * (ch + 1) - y - 1) * s->outpicref->linesize[1] + s->w + s->start_x + 20, av_clip_uint8(out[1]), 10); + memset(s->outpicref->data[2]+(s->start_y + h * (ch + 1) - y - 1) * s->outpicref->linesize[2] + s->w + s->start_x + 20, av_clip_uint8(out[2]), 10); + } + + for (y = 0; ch == 0 && y < h; y += h / 10) { + float value = 120.f * log10f(1.f - y / (float)h); + char *text; + + if (value < -120) + break; + text = av_asprintf("%.0f dB", value); + if (!text) + continue; + drawtext(s->outpicref, s->w + s->start_x + 35, s->start_y + y - 5, text, 0); + av_free(text); + } + } + + return 0; +} + +static float get_value(AVFilterContext *ctx, int ch, int y) +{ + ShowSpectrumContext *s = ctx->priv; + float *magnitudes = s->magnitudes[ch]; + float *phases = s->phases[ch]; + float a; + + switch (s->data) { + case D_MAGNITUDE: + /* get magnitude */ + a = magnitudes[y]; + break; + case D_PHASE: + /* get phase */ + a = phases[y]; + break; + default: + av_assert0(0); + } + + /* apply scale */ + switch (s->scale) { + case LINEAR: + a = av_clipf(a, 0, 1); + break; + case SQRT: + a = av_clipf(sqrtf(a), 0, 1); + break; + case CBRT: + a = av_clipf(cbrtf(a), 0, 1); + break; + case FOURTHRT: + a = av_clipf(sqrtf(sqrtf(a)), 0, 1); + break; + case FIFTHRT: + a = av_clipf(powf(a, 0.20), 0, 1); + break; + case LOG: + a = 1.f + log10f(av_clipf(a, 1e-6, 1)) / 6.f; // zero = -120dBFS + break; + default: + av_assert0(0); + } + + return a; +} + +static int plot_channel_lin(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) +{ + ShowSpectrumContext *s = ctx->priv; + const int h = s->orientation == VERTICAL ? s->channel_height : s->channel_width; + const int ch = jobnr; + float yf, uf, vf; + int y; + + /* decide color range */ + color_range(s, ch, &yf, &uf, &vf); + + /* draw the channel */ + for (y = 0; y < h; y++) { + int row = (s->mode == COMBINED) ? y : ch * h + y; + float *out = &s->color_buffer[ch][3 * row]; + float a = get_value(ctx, ch, y); + + pick_color(s, yf, uf, vf, a, out); + } + + return 0; +} + +static int plot_channel_log(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) +{ + ShowSpectrumContext *s = ctx->priv; + AVFilterLink *inlink = ctx->inputs[0]; + const int h = s->orientation == VERTICAL ? s->channel_height : s->channel_width; + const int ch = jobnr; + float y, yf, uf, vf; + int yy = 0; + + /* decide color range */ + color_range(s, ch, &yf, &uf, &vf); + + /* draw the channel */ + for (y = 0; y < h && yy < h; yy++) { + float pos0 = bin_pos(yy+0, h, inlink->sample_rate); + float pos1 = bin_pos(yy+1, h, inlink->sample_rate); + float delta = pos1 - pos0; + float a0, a1; + + a0 = get_value(ctx, ch, yy+0); + a1 = get_value(ctx, ch, FFMIN(yy+1, h-1)); + for (float j = pos0; j < pos1 && y + j - pos0 < h; j++) { + float row = (s->mode == COMBINED) ? y + j - pos0 : ch * h + y + j - pos0; + float *out = &s->color_buffer[ch][3 * FFMIN(lrintf(row), h-1)]; + float lerpfrac = (j - pos0) / delta; + + pick_color(s, yf, uf, vf, lerpfrac * a1 + (1.f-lerpfrac) * a0, out); + } + y += delta; + } + + return 0; +} + static int config_output(AVFilterLink *outlink) { AVFilterContext *ctx = outlink->src; @@ -299,7 +982,17 @@ static int config_output(AVFilterLink *outlink) int i, fft_bits, h, w; float overlap; - s->pts = AV_NOPTS_VALUE; + switch (s->fscale) { + case F_LINEAR: s->plot_channel = plot_channel_lin; break; + case F_LOG: s->plot_channel = plot_channel_log; break; + default: return AVERROR_BUG; + } + + s->stop = FFMIN(s->stop, inlink->sample_rate / 2); + if (s->stop && s->stop <= s->start) { + av_log(ctx, AV_LOG_ERROR, "Stop frequency should be greater than start.\n"); + return AVERROR(EINVAL); + } if (!strcmp(ctx->filter->name, "showspectrumpic")) s->single_pic = 1; @@ -309,7 +1002,7 @@ static int config_output(AVFilterLink *outlink) outlink->sample_aspect_ratio = (AVRational){1,1}; if (s->legend) { - s->start_x = log10(inlink->sample_rate) * 25; + s->start_x = (log10(inlink->sample_rate) + 1) * 25; s->start_y = 64; outlink->w += s->start_x * 2; outlink->h += s->start_y * 2; @@ -327,7 +1020,9 @@ static int config_output(AVFilterLink *outlink) /* FFT window size (precision) according to the requested output frame width */ for (fft_bits = 1; 1 << fft_bits < 2 * w; fft_bits++); } + s->win_size = 1 << fft_bits; + s->buf_size = s->win_size << !!s->stop; if (!s->fft) { s->fft = av_calloc(inlink->channels, sizeof(*s->fft)); @@ -335,6 +1030,14 @@ static int config_output(AVFilterLink *outlink) return AVERROR(ENOMEM); } + if (s->stop) { + if (!s->ifft) { + s->ifft = av_calloc(inlink->channels, sizeof(*s->ifft)); + if (!s->ifft) + return AVERROR(ENOMEM); + } + } + /* (re-)configuration if the video output changed (or first init) */ if (fft_bits != s->fft_bits) { AVFrame *outpicref; @@ -345,6 +1048,10 @@ static int config_output(AVFilterLink *outlink) * Note: we use free and malloc instead of a realloc-like function to * make sure the buffer is aligned in memory for the FFT functions. */ for (i = 0; i < s->nb_display_channels; i++) { + if (s->stop) { + av_fft_end(s->ifft[i]); + av_freep(&s->fft_scratch[i]); + } av_fft_end(s->fft[i]); av_freep(&s->fft_data[i]); } @@ -352,7 +1059,15 @@ static int config_output(AVFilterLink *outlink) s->nb_display_channels = inlink->channels; for (i = 0; i < s->nb_display_channels; i++) { - s->fft[i] = av_fft_init(fft_bits, 0); + s->fft[i] = av_fft_init(fft_bits + !!s->stop, 0); + if (s->stop) { + s->ifft[i] = av_fft_init(fft_bits + !!s->stop, 1); + if (!s->ifft[i]) { + av_log(ctx, AV_LOG_ERROR, "Unable to create Inverse FFT context. " + "The window size might be too high.\n"); + return AVERROR(EINVAL); + } + } if (!s->fft[i]) { av_log(ctx, AV_LOG_ERROR, "Unable to create FFT context. " "The window size might be too high.\n"); @@ -391,10 +1106,17 @@ static int config_output(AVFilterLink *outlink) s->fft_data = av_calloc(s->nb_display_channels, sizeof(*s->fft_data)); if (!s->fft_data) return AVERROR(ENOMEM); + s->fft_scratch = av_calloc(s->nb_display_channels, sizeof(*s->fft_scratch)); + if (!s->fft_scratch) + return AVERROR(ENOMEM); for (i = 0; i < s->nb_display_channels; i++) { - s->fft_data[i] = av_calloc(s->win_size, sizeof(**s->fft_data)); + s->fft_data[i] = av_calloc(s->buf_size, sizeof(**s->fft_data)); if (!s->fft_data[i]) return AVERROR(ENOMEM); + + s->fft_scratch[i] = av_calloc(s->buf_size, sizeof(**s->fft_scratch)); + if (!s->fft_scratch[i]) + return AVERROR(ENOMEM); } /* pre-calc windowing function */ @@ -406,7 +1128,7 @@ static int config_output(AVFilterLink *outlink) generate_window_func(s->window_func_lut, s->win_size, s->win_func, &overlap); if (s->overlap == 1) s->overlap = overlap; - s->hop_size = (1. - s->overlap) * s->win_size; + s->hop_size = (1.f - s->overlap) * s->win_size; if (s->hop_size < 1) { av_log(ctx, AV_LOG_ERROR, "overlap %f too big\n", s->overlap); return AVERROR(EINVAL); @@ -415,7 +1137,7 @@ static int config_output(AVFilterLink *outlink) for (s->win_scale = 0, i = 0; i < s->win_size; i++) { s->win_scale += s->window_func_lut[i] * s->window_func_lut[i]; } - s->win_scale = 1. / sqrt(s->win_scale); + s->win_scale = 1.f / sqrtf(s->win_scale); /* prepare the initial picref buffer (black frame) */ av_frame_free(&s->outpicref); @@ -430,17 +1152,29 @@ static int config_output(AVFilterLink *outlink) memset(outpicref->data[2] + i * outpicref->linesize[2], 128, outlink->w); } outpicref->color_range = AVCOL_RANGE_JPEG; + + if (!s->single_pic && s->legend) + draw_legend(ctx, 0); } if ((s->orientation == VERTICAL && s->xpos >= s->w) || (s->orientation == HORIZONTAL && s->xpos >= s->h)) s->xpos = 0; - outlink->frame_rate = av_make_q(inlink->sample_rate, s->win_size * (1.-s->overlap)); + s->auto_frame_rate = av_make_q(inlink->sample_rate, s->hop_size); if (s->orientation == VERTICAL && s->sliding == FULLFRAME) - outlink->frame_rate.den *= s->w; + s->auto_frame_rate.den *= s->w; if (s->orientation == HORIZONTAL && s->sliding == FULLFRAME) - outlink->frame_rate.den *= s->h; + s->auto_frame_rate.den *= s->h; + if (!s->single_pic && strcmp(s->rate_str, "auto")) { + int ret = av_parse_video_rate(&s->frame_rate, s->rate_str); + if (ret < 0) + return ret; + } else { + s->frame_rate = s->auto_frame_rate; + } + outlink->frame_rate = s->frame_rate; + outlink->time_base = av_inv_q(outlink->frame_rate); if (s->orientation == VERTICAL) { s->combine_buffer = @@ -462,33 +1196,10 @@ static int config_output(AVFilterLink *outlink) return 0; } -static int run_channel_fft(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) -{ - ShowSpectrumContext *s = ctx->priv; - const float *window_func_lut = s->window_func_lut; - AVFrame *fin = arg; - const int ch = jobnr; - int n; - - /* fill FFT input with the number of samples available */ - const float *p = (float *)fin->extended_data[ch]; - - for (n = 0; n < s->win_size; n++) { - s->fft_data[ch][n].re = p[n] * window_func_lut[n]; - s->fft_data[ch][n].im = 0; - } - - /* run FFT on each samples set */ - av_fft_permute(s->fft[ch], s->fft_data[ch]); - av_fft_calc(s->fft[ch], s->fft_data[ch]); - - return 0; -} - #define RE(y, ch) s->fft_data[ch][y].re #define IM(y, ch) s->fft_data[ch][y].im -#define MAGNITUDE(y, ch) hypot(RE(y, ch), IM(y, ch)) -#define PHASE(y, ch) atan2(IM(y, ch), RE(y, ch)) +#define MAGNITUDE(y, ch) hypotf(RE(y, ch), IM(y, ch)) +#define PHASE(y, ch) atan2f(IM(y, ch), RE(y, ch)) static int calc_channel_magnitudes(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) { @@ -545,106 +1256,6 @@ static void scale_magnitudes(ShowSpectrumContext *s, float scale) } } -static void color_range(ShowSpectrumContext *s, int ch, - float *yf, float *uf, float *vf) -{ - switch (s->mode) { - case COMBINED: - // reduce range by channel count - *yf = 256.0f / s->nb_display_channels; - switch (s->color_mode) { - case RAINBOW: - case MORELAND: - case NEBULAE: - case FIRE: - case FIERY: - case FRUIT: - case COOL: - case INTENSITY: - *uf = *yf; - *vf = *yf; - break; - case CHANNEL: - /* adjust saturation for mixed UV coloring */ - /* this factor is correct for infinite channels, an approximation otherwise */ - *uf = *yf * M_PI; - *vf = *yf * M_PI; - break; - default: - av_assert0(0); - } - break; - case SEPARATE: - // full range - *yf = 256.0f; - *uf = 256.0f; - *vf = 256.0f; - break; - default: - av_assert0(0); - } - - if (s->color_mode == CHANNEL) { - if (s->nb_display_channels > 1) { - *uf *= 0.5 * sin((2 * M_PI * ch) / s->nb_display_channels + M_PI * s->rotation); - *vf *= 0.5 * cos((2 * M_PI * ch) / s->nb_display_channels + M_PI * s->rotation); - } else { - *uf *= 0.5 * sin(M_PI * s->rotation); - *vf *= 0.5 * cos(M_PI * s->rotation + M_PI_2); - } - } else { - *uf += *uf * sin(M_PI * s->rotation); - *vf += *vf * cos(M_PI * s->rotation + M_PI_2); - } - - *uf *= s->saturation; - *vf *= s->saturation; -} - -static void pick_color(ShowSpectrumContext *s, - float yf, float uf, float vf, - float a, float *out) -{ - if (s->color_mode > CHANNEL) { - const int cm = s->color_mode; - float y, u, v; - int i; - - for (i = 1; i < FF_ARRAY_ELEMS(color_table[cm]) - 1; i++) - if (color_table[cm][i].a >= a) - break; - // i now is the first item >= the color - // now we know to interpolate between item i - 1 and i - if (a <= color_table[cm][i - 1].a) { - y = color_table[cm][i - 1].y; - u = color_table[cm][i - 1].u; - v = color_table[cm][i - 1].v; - } else if (a >= color_table[cm][i].a) { - y = color_table[cm][i].y; - u = color_table[cm][i].u; - v = color_table[cm][i].v; - } else { - float start = color_table[cm][i - 1].a; - float end = color_table[cm][i].a; - float lerpfrac = (a - start) / (end - start); - y = color_table[cm][i - 1].y * (1.0f - lerpfrac) - + color_table[cm][i].y * lerpfrac; - u = color_table[cm][i - 1].u * (1.0f - lerpfrac) - + color_table[cm][i].u * lerpfrac; - v = color_table[cm][i - 1].v * (1.0f - lerpfrac) - + color_table[cm][i].v * lerpfrac; - } - - out[0] = y * yf; - out[1] = u * uf; - out[2] = v * vf; - } else { - out[0] = a * yf; - out[1] = a * uf; - out[2] = a * vf; - } -} - static void clear_combine_buffer(ShowSpectrumContext *s, int size) { int y; @@ -656,68 +1267,6 @@ static void clear_combine_buffer(ShowSpectrumContext *s, int size) } } -static int plot_channel(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) -{ - ShowSpectrumContext *s = ctx->priv; - const int h = s->orientation == VERTICAL ? s->channel_height : s->channel_width; - const int ch = jobnr; - float *magnitudes = s->magnitudes[ch]; - float *phases = s->phases[ch]; - float yf, uf, vf; - int y; - - /* decide color range */ - color_range(s, ch, &yf, &uf, &vf); - - /* draw the channel */ - for (y = 0; y < h; y++) { - int row = (s->mode == COMBINED) ? y : ch * h + y; - float *out = &s->color_buffer[ch][3 * row]; - float a; - - switch (s->data) { - case D_MAGNITUDE: - /* get magnitude */ - a = magnitudes[y]; - break; - case D_PHASE: - /* get phase */ - a = phases[y]; - break; - default: - av_assert0(0); - } - - /* apply scale */ - switch (s->scale) { - case LINEAR: - a = av_clipf(a, 0, 1); - break; - case SQRT: - a = av_clipf(sqrt(a), 0, 1); - break; - case CBRT: - a = av_clipf(cbrt(a), 0, 1); - break; - case FOURTHRT: - a = av_clipf(sqrt(sqrt(a)), 0, 1); - break; - case FIFTHRT: - a = av_clipf(pow(a, 0.20), 0, 1); - break; - case LOG: - a = 1 + log10(av_clipd(a, 1e-6, 1)) / 6; // zero = -120dBFS - break; - default: - av_assert0(0); - } - - pick_color(s, yf, uf, vf, a, out); - } - - return 0; -} - static int plot_spectrum_column(AVFilterLink *inlink, AVFrame *insamples) { AVFilterContext *ctx = inlink->dst; @@ -730,7 +1279,7 @@ static int plot_spectrum_column(AVFilterLink *inlink, AVFrame *insamples) /* initialize buffer for combining to black */ clear_combine_buffer(s, z); - ctx->internal->execute(ctx, plot_channel, NULL, NULL, s->nb_display_channels); + ctx->internal->execute(ctx, s->plot_channel, NULL, NULL, s->nb_display_channels); for (y = 0; y < z * 3; y++) { for (x = 0; x < s->nb_display_channels; x++) { @@ -744,8 +1293,8 @@ static int plot_spectrum_column(AVFilterLink *inlink, AVFrame *insamples) if (s->sliding == SCROLL) { for (plane = 0; plane < 3; plane++) { for (y = 0; y < s->h; y++) { - uint8_t *p = outpicref->data[plane] + - y * outpicref->linesize[plane]; + uint8_t *p = outpicref->data[plane] + s->start_x + + (y + s->start_y) * outpicref->linesize[plane]; memmove(p, p + 1, s->w - 1); } } @@ -753,8 +1302,8 @@ static int plot_spectrum_column(AVFilterLink *inlink, AVFrame *insamples) } else if (s->sliding == RSCROLL) { for (plane = 0; plane < 3; plane++) { for (y = 0; y < s->h; y++) { - uint8_t *p = outpicref->data[plane] + - y * outpicref->linesize[plane]; + uint8_t *p = outpicref->data[plane] + s->start_x + + (y + s->start_y) * outpicref->linesize[plane]; memmove(p + 1, p, s->w - 1); } } @@ -773,8 +1322,8 @@ static int plot_spectrum_column(AVFilterLink *inlink, AVFrame *insamples) if (s->sliding == SCROLL) { for (plane = 0; plane < 3; plane++) { for (y = 1; y < s->h; y++) { - memmove(outpicref->data[plane] + (y-1) * outpicref->linesize[plane], - outpicref->data[plane] + (y ) * outpicref->linesize[plane], + memmove(outpicref->data[plane] + (y-1 + s->start_y) * outpicref->linesize[plane] + s->start_x, + outpicref->data[plane] + (y + s->start_y) * outpicref->linesize[plane] + s->start_x, s->w); } } @@ -782,8 +1331,8 @@ static int plot_spectrum_column(AVFilterLink *inlink, AVFrame *insamples) } else if (s->sliding == RSCROLL) { for (plane = 0; plane < 3; plane++) { for (y = s->h - 1; y >= 1; y--) { - memmove(outpicref->data[plane] + (y ) * outpicref->linesize[plane], - outpicref->data[plane] + (y-1) * outpicref->linesize[plane], + memmove(outpicref->data[plane] + (y + s->start_y) * outpicref->linesize[plane] + s->start_x, + outpicref->data[plane] + (y-1 + s->start_y) * outpicref->linesize[plane] + s->start_x, s->w); } } @@ -800,7 +1349,7 @@ static int plot_spectrum_column(AVFilterLink *inlink, AVFrame *insamples) } if (s->sliding != FULLFRAME || s->xpos == 0) - outpicref->pts = insamples->pts; + outpicref->pts = av_rescale_q(insamples->pts, inlink->time_base, outlink->time_base); s->xpos++; if (s->orientation == VERTICAL && s->xpos >= s->w) @@ -808,71 +1357,83 @@ static int plot_spectrum_column(AVFilterLink *inlink, AVFrame *insamples) if (s->orientation == HORIZONTAL && s->xpos >= s->h) s->xpos = 0; if (!s->single_pic && (s->sliding != FULLFRAME || s->xpos == 0)) { - ret = ff_filter_frame(outlink, av_frame_clone(s->outpicref)); - if (ret < 0) - return ret; + if (s->old_pts < outpicref->pts) { + if (s->legend) { + char *units = get_time(ctx, insamples->pts /(float)inlink->sample_rate, x); + + if (s->orientation == VERTICAL) { + for (y = 0; y < 10; y++) { + memset(s->outpicref->data[0] + outlink->w / 2 - 4 * s->old_len + + (outlink->h - s->start_y / 2 - 20 + y) * s->outpicref->linesize[0], 0, 10 * s->old_len); + } + drawtext(s->outpicref, + outlink->w / 2 - 4 * strlen(units), + outlink->h - s->start_y / 2 - 20, + units, 0); + } else { + for (y = 0; y < 10 * s->old_len; y++) { + memset(s->outpicref->data[0] + s->start_x / 7 + 20 + + (outlink->h / 2 - 4 * s->old_len + y) * s->outpicref->linesize[0], 0, 10); + } + drawtext(s->outpicref, + s->start_x / 7 + 20, + outlink->h / 2 - 4 * strlen(units), + units, 1); + } + s->old_len = strlen(units); + av_free(units); + } + s->old_pts = outpicref->pts; + ret = ff_filter_frame(outlink, av_frame_clone(s->outpicref)); + if (ret < 0) + return ret; + return 0; + } } - return s->win_size; + return 1; } #if CONFIG_SHOWSPECTRUM_FILTER -static int request_frame(AVFilterLink *outlink) +static int activate(AVFilterContext *ctx) { - ShowSpectrumContext *s = outlink->src->priv; - AVFilterLink *inlink = outlink->src->inputs[0]; - unsigned i; + AVFilterLink *inlink = ctx->inputs[0]; + AVFilterLink *outlink = ctx->outputs[0]; + ShowSpectrumContext *s = ctx->priv; int ret; - ret = ff_request_frame(inlink); - if (ret == AVERROR_EOF && s->sliding == FULLFRAME && s->xpos > 0 && - s->outpicref) { - if (s->orientation == VERTICAL) { - for (i = 0; i < outlink->h; i++) { - memset(s->outpicref->data[0] + i * s->outpicref->linesize[0] + s->xpos, 0, outlink->w - s->xpos); - memset(s->outpicref->data[1] + i * s->outpicref->linesize[1] + s->xpos, 128, outlink->w - s->xpos); - memset(s->outpicref->data[2] + i * s->outpicref->linesize[2] + s->xpos, 128, outlink->w - s->xpos); - } - } else { - for (i = s->xpos; i < outlink->h; i++) { - memset(s->outpicref->data[0] + i * s->outpicref->linesize[0], 0, outlink->w); - memset(s->outpicref->data[1] + i * s->outpicref->linesize[1], 128, outlink->w); - memset(s->outpicref->data[2] + i * s->outpicref->linesize[2], 128, outlink->w); - } + FF_FILTER_FORWARD_STATUS_BACK(outlink, inlink); + + if (av_audio_fifo_size(s->fifo) < s->win_size) { + AVFrame *frame = NULL; + + ret = ff_inlink_consume_frame(inlink, &frame); + if (ret < 0) + return ret; + if (ret > 0) { + s->pts = frame->pts; + s->consumed = 0; + + av_audio_fifo_write(s->fifo, (void **)frame->extended_data, frame->nb_samples); + av_frame_free(&frame); } - ret = ff_filter_frame(outlink, s->outpicref); - s->outpicref = NULL; } - return ret; -} + if (s->outpicref && av_audio_fifo_size(s->fifo) >= s->win_size) { + AVFrame *fin = ff_get_audio_buffer(inlink, s->win_size); + if (!fin) + return AVERROR(ENOMEM); -static int filter_frame(AVFilterLink *inlink, AVFrame *insamples) -{ - AVFilterContext *ctx = inlink->dst; - ShowSpectrumContext *s = ctx->priv; - AVFrame *fin = NULL; - int ret = 0, consumed = 0; - - if (s->pts == AV_NOPTS_VALUE) - s->pts = insamples->pts - av_audio_fifo_size(s->fifo); - - av_audio_fifo_write(s->fifo, (void **)insamples->extended_data, insamples->nb_samples); - av_frame_free(&insamples); - while (av_audio_fifo_size(s->fifo) >= s->win_size) { - fin = ff_get_audio_buffer(inlink, s->win_size); - if (!fin) { - ret = AVERROR(ENOMEM); - goto fail; + fin->pts = s->pts + s->consumed; + s->consumed += s->hop_size; + ret = av_audio_fifo_peek(s->fifo, (void **)fin->extended_data, + FFMIN(s->win_size, av_audio_fifo_size(s->fifo))); + if (ret < 0) { + av_frame_free(&fin); + return ret; } - fin->pts = s->pts + consumed; - consumed += s->hop_size; - ret = av_audio_fifo_peek(s->fifo, (void **)fin->extended_data, s->win_size); - if (ret < 0) - goto fail; - av_assert0(fin->nb_samples == s->win_size); ctx->internal->execute(ctx, run_channel_fft, fin, NULL, s->nb_display_channels); @@ -884,23 +1445,56 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *insamples) ctx->internal->execute(ctx, calc_channel_phases, NULL, NULL, s->nb_display_channels); ret = plot_spectrum_column(inlink, fin); + av_frame_free(&fin); av_audio_fifo_drain(s->fifo, s->hop_size); - if (ret < 0) - goto fail; + if (ret <= 0) + return ret; } -fail: - s->pts = AV_NOPTS_VALUE; - av_frame_free(&fin); - return ret; + if (ff_outlink_get_status(inlink) == AVERROR_EOF && + s->sliding == FULLFRAME && + s->xpos > 0 && s->outpicref) { + int64_t pts; + + if (s->orientation == VERTICAL) { + for (int i = 0; i < outlink->h; i++) { + memset(s->outpicref->data[0] + i * s->outpicref->linesize[0] + s->xpos, 0, outlink->w - s->xpos); + memset(s->outpicref->data[1] + i * s->outpicref->linesize[1] + s->xpos, 128, outlink->w - s->xpos); + memset(s->outpicref->data[2] + i * s->outpicref->linesize[2] + s->xpos, 128, outlink->w - s->xpos); + } + } else { + for (int i = s->xpos; i < outlink->h; i++) { + memset(s->outpicref->data[0] + i * s->outpicref->linesize[0], 0, outlink->w); + memset(s->outpicref->data[1] + i * s->outpicref->linesize[1], 128, outlink->w); + memset(s->outpicref->data[2] + i * s->outpicref->linesize[2], 128, outlink->w); + } + } + s->outpicref->pts += s->consumed; + pts = s->outpicref->pts; + ret = ff_filter_frame(outlink, s->outpicref); + s->outpicref = NULL; + ff_outlink_set_status(outlink, AVERROR_EOF, pts); + return 0; + } + + FF_FILTER_FORWARD_STATUS(inlink, outlink); + if (ff_outlink_frame_wanted(outlink) && av_audio_fifo_size(s->fifo) < s->win_size) { + ff_inlink_request_frame(inlink); + return 0; + } + + if (av_audio_fifo_size(s->fifo) >= s->win_size) { + ff_filter_set_ready(ctx, 10); + return 0; + } + return FFERROR_NOT_READY; } static const AVFilterPad showspectrum_inputs[] = { { .name = "default", .type = AVMEDIA_TYPE_AUDIO, - .filter_frame = filter_frame, }, { NULL } }; @@ -910,7 +1504,6 @@ static const AVFilterPad showspectrum_outputs[] = { .name = "default", .type = AVMEDIA_TYPE_VIDEO, .config_props = config_output, - .request_frame = request_frame, }, { NULL } }; @@ -923,6 +1516,7 @@ AVFilter ff_avf_showspectrum = { .priv_size = sizeof(ShowSpectrumContext), .inputs = showspectrum_inputs, .outputs = showspectrum_outputs, + .activate = activate, .priv_class = &showspectrum_class, .flags = AVFILTER_FLAG_SLICE_THREADS, }; @@ -946,6 +1540,12 @@ static const AVOption showspectrumpic_options[] = { { "fiery", "fiery based coloring", 0, AV_OPT_TYPE_CONST, {.i64=FIERY}, 0, 0, FLAGS, "color" }, { "fruit", "fruit based coloring", 0, AV_OPT_TYPE_CONST, {.i64=FRUIT}, 0, 0, FLAGS, "color" }, { "cool", "cool based coloring", 0, AV_OPT_TYPE_CONST, {.i64=COOL}, 0, 0, FLAGS, "color" }, + { "magma", "magma based coloring", 0, AV_OPT_TYPE_CONST, {.i64=MAGMA}, 0, 0, FLAGS, "color" }, + { "green", "green based coloring", 0, AV_OPT_TYPE_CONST, {.i64=GREEN}, 0, 0, FLAGS, "color" }, + { "viridis", "viridis based coloring", 0, AV_OPT_TYPE_CONST, {.i64=VIRIDIS}, 0, 0, FLAGS, "color" }, + { "plasma", "plasma based coloring", 0, AV_OPT_TYPE_CONST, {.i64=PLASMA}, 0, 0, FLAGS, "color" }, + { "cividis", "cividis based coloring", 0, AV_OPT_TYPE_CONST, {.i64=CIVIDIS}, 0, 0, FLAGS, "color" }, + { "terrain", "terrain based coloring", 0, AV_OPT_TYPE_CONST, {.i64=TERRAIN}, 0, 0, FLAGS, "color" }, { "scale", "set display scale", OFFSET(scale), AV_OPT_TYPE_INT, {.i64=LOG}, 0, NB_SCALES-1, FLAGS, "scale" }, { "lin", "linear", 0, AV_OPT_TYPE_CONST, {.i64=LINEAR}, 0, 0, FLAGS, "scale" }, { "sqrt", "square root", 0, AV_OPT_TYPE_CONST, {.i64=SQRT}, 0, 0, FLAGS, "scale" }, @@ -953,6 +1553,9 @@ static const AVOption showspectrumpic_options[] = { { "log", "logarithmic", 0, AV_OPT_TYPE_CONST, {.i64=LOG}, 0, 0, FLAGS, "scale" }, { "4thrt","4th root", 0, AV_OPT_TYPE_CONST, {.i64=FOURTHRT}, 0, 0, FLAGS, "scale" }, { "5thrt","5th root", 0, AV_OPT_TYPE_CONST, {.i64=FIFTHRT}, 0, 0, FLAGS, "scale" }, + { "fscale", "set frequency scale", OFFSET(fscale), AV_OPT_TYPE_INT, {.i64=F_LINEAR}, 0, NB_FSCALES-1, FLAGS, "fscale" }, + { "lin", "linear", 0, AV_OPT_TYPE_CONST, {.i64=F_LINEAR}, 0, 0, FLAGS, "fscale" }, + { "log", "logarithmic", 0, AV_OPT_TYPE_CONST, {.i64=F_LOG}, 0, 0, FLAGS, "fscale" }, { "saturation", "color saturation multiplier", OFFSET(saturation), AV_OPT_TYPE_FLOAT, {.dbl = 1}, -10, 10, FLAGS }, { "win_func", "set window function", OFFSET(win_func), AV_OPT_TYPE_INT, {.i64 = WFUNC_HANNING}, 0, NB_WFUNC-1, FLAGS, "win_func" }, { "rect", "Rectangular", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_RECT}, 0, 0, FLAGS, "win_func" }, @@ -975,51 +1578,20 @@ static const AVOption showspectrumpic_options[] = { { "cauchy", "Cauchy", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_CAUCHY}, 0, 0, FLAGS, "win_func" }, { "parzen", "Parzen", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_PARZEN}, 0, 0, FLAGS, "win_func" }, { "poisson", "Poisson", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_POISSON}, 0, 0, FLAGS, "win_func" }, + { "bohman", "Bohman", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_BOHMAN}, 0, 0, FLAGS, "win_func" }, { "orientation", "set orientation", OFFSET(orientation), AV_OPT_TYPE_INT, {.i64=VERTICAL}, 0, NB_ORIENTATIONS-1, FLAGS, "orientation" }, { "vertical", NULL, 0, AV_OPT_TYPE_CONST, {.i64=VERTICAL}, 0, 0, FLAGS, "orientation" }, { "horizontal", NULL, 0, AV_OPT_TYPE_CONST, {.i64=HORIZONTAL}, 0, 0, FLAGS, "orientation" }, { "gain", "set scale gain", OFFSET(gain), AV_OPT_TYPE_FLOAT, {.dbl = 1}, 0, 128, FLAGS }, { "legend", "draw legend", OFFSET(legend), AV_OPT_TYPE_BOOL, {.i64 = 1}, 0, 1, FLAGS }, { "rotation", "color rotation", OFFSET(rotation), AV_OPT_TYPE_FLOAT, {.dbl = 0}, -1, 1, FLAGS }, + { "start", "start frequency", OFFSET(start), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT32_MAX, FLAGS }, + { "stop", "stop frequency", OFFSET(stop), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT32_MAX, FLAGS }, { NULL } }; AVFILTER_DEFINE_CLASS(showspectrumpic); -static void drawtext(AVFrame *pic, int x, int y, const char *txt, int o) -{ - const uint8_t *font; - int font_height; - int i; - - font = avpriv_cga_font, font_height = 8; - - for (i = 0; txt[i]; i++) { - int char_y, mask; - - if (o) { - for (char_y = font_height - 1; char_y >= 0; char_y--) { - uint8_t *p = pic->data[0] + (y + i * 10) * pic->linesize[0] + x; - for (mask = 0x80; mask; mask >>= 1) { - if (font[txt[i] * font_height + font_height - 1 - char_y] & mask) - p[char_y] = ~p[char_y]; - p += pic->linesize[0]; - } - } - } else { - uint8_t *p = pic->data[0] + y*pic->linesize[0] + (x + i*8); - for (char_y = 0; char_y < font_height; char_y++) { - for (mask = 0x80; mask; mask >>= 1) { - if (font[txt[i] * font_height + char_y] & mask) - *p = ~(*p); - p++; - } - p += pic->linesize[0] - 8; - } - } - } -} - static int showspectrumpic_request_frame(AVFilterLink *outlink) { AVFilterContext *ctx = outlink->src; @@ -1031,7 +1603,7 @@ static int showspectrumpic_request_frame(AVFilterLink *outlink) samples = av_audio_fifo_size(s->fifo); if (ret == AVERROR_EOF && s->outpicref && samples > 0) { int consumed = 0; - int y, x = 0, sz = s->orientation == VERTICAL ? s->w : s->h; + int x = 0, sz = s->orientation == VERTICAL ? s->w : s->h; int ch, spf, spb; AVFrame *fin; @@ -1067,7 +1639,7 @@ static int showspectrumpic_request_frame(AVFilterLink *outlink) if (consumed >= spb) { int h = s->orientation == VERTICAL ? s->h : s->w; - scale_magnitudes(s, 1. / (consumed / spf)); + scale_magnitudes(s, 1.f / (consumed / spf)); plot_spectrum_column(inlink, fin); consumed = 0; x++; @@ -1079,191 +1651,8 @@ static int showspectrumpic_request_frame(AVFilterLink *outlink) av_frame_free(&fin); s->outpicref->pts = 0; - if (s->legend) { - int multi = (s->mode == SEPARATE && s->color_mode == CHANNEL); - float spp = samples / (float)sz; - uint8_t *dst; - - drawtext(s->outpicref, 2, outlink->h - 10, "CREATED BY LIBAVFILTER", 0); - - dst = s->outpicref->data[0] + (s->start_y - 1) * s->outpicref->linesize[0] + s->start_x - 1; - for (x = 0; x < s->w + 1; x++) - dst[x] = 200; - dst = s->outpicref->data[0] + (s->start_y + s->h) * s->outpicref->linesize[0] + s->start_x - 1; - for (x = 0; x < s->w + 1; x++) - dst[x] = 200; - for (y = 0; y < s->h + 2; y++) { - dst = s->outpicref->data[0] + (y + s->start_y - 1) * s->outpicref->linesize[0]; - dst[s->start_x - 1] = 200; - dst[s->start_x + s->w] = 200; - } - if (s->orientation == VERTICAL) { - int h = s->mode == SEPARATE ? s->h / s->nb_display_channels : s->h; - for (ch = 0; ch < (s->mode == SEPARATE ? s->nb_display_channels : 1); ch++) { - for (y = 0; y < h; y += 20) { - dst = s->outpicref->data[0] + (s->start_y + h * (ch + 1) - y - 1) * s->outpicref->linesize[0]; - dst[s->start_x - 2] = 200; - dst[s->start_x + s->w + 1] = 200; - } - for (y = 0; y < h; y += 40) { - dst = s->outpicref->data[0] + (s->start_y + h * (ch + 1) - y - 1) * s->outpicref->linesize[0]; - dst[s->start_x - 3] = 200; - dst[s->start_x + s->w + 2] = 200; - } - dst = s->outpicref->data[0] + (s->start_y - 2) * s->outpicref->linesize[0] + s->start_x; - for (x = 0; x < s->w; x+=40) - dst[x] = 200; - dst = s->outpicref->data[0] + (s->start_y - 3) * s->outpicref->linesize[0] + s->start_x; - for (x = 0; x < s->w; x+=80) - dst[x] = 200; - dst = s->outpicref->data[0] + (s->h + s->start_y + 1) * s->outpicref->linesize[0] + s->start_x; - for (x = 0; x < s->w; x+=40) { - dst[x] = 200; - } - dst = s->outpicref->data[0] + (s->h + s->start_y + 2) * s->outpicref->linesize[0] + s->start_x; - for (x = 0; x < s->w; x+=80) { - dst[x] = 200; - } - for (y = 0; y < h; y += 40) { - float hertz = y * (inlink->sample_rate / 2) / (float)(1 << (int)ceil(log2(h))); - char *units; - - if (hertz == 0) - units = av_asprintf("DC"); - else - units = av_asprintf("%.2f", hertz); - if (!units) - return AVERROR(ENOMEM); - - drawtext(s->outpicref, s->start_x - 8 * strlen(units) - 4, h * (ch + 1) + s->start_y - y - 4, units, 0); - av_free(units); - } - } - - for (x = 0; x < s->w; x+=80) { - float seconds = x * spp / inlink->sample_rate; - char *units; - - if (x == 0) - units = av_asprintf("0"); - else if (log10(seconds) > 6) - units = av_asprintf("%.2fh", seconds / (60 * 60)); - else if (log10(seconds) > 3) - units = av_asprintf("%.2fm", seconds / 60); - else - units = av_asprintf("%.2fs", seconds); - if (!units) - return AVERROR(ENOMEM); - - drawtext(s->outpicref, s->start_x + x - 4 * strlen(units), s->h + s->start_y + 6, units, 0); - drawtext(s->outpicref, s->start_x + x - 4 * strlen(units), s->start_y - 12, units, 0); - av_free(units); - } - - drawtext(s->outpicref, outlink->w / 2 - 4 * 4, outlink->h - s->start_y / 2, "TIME", 0); - drawtext(s->outpicref, s->start_x / 7, outlink->h / 2 - 14 * 4, "FREQUENCY (Hz)", 1); - } else { - int w = s->mode == SEPARATE ? s->w / s->nb_display_channels : s->w; - for (y = 0; y < s->h; y += 20) { - dst = s->outpicref->data[0] + (s->start_y + y) * s->outpicref->linesize[0]; - dst[s->start_x - 2] = 200; - dst[s->start_x + s->w + 1] = 200; - } - for (y = 0; y < s->h; y += 40) { - dst = s->outpicref->data[0] + (s->start_y + y) * s->outpicref->linesize[0]; - dst[s->start_x - 3] = 200; - dst[s->start_x + s->w + 2] = 200; - } - for (ch = 0; ch < (s->mode == SEPARATE ? s->nb_display_channels : 1); ch++) { - dst = s->outpicref->data[0] + (s->start_y - 2) * s->outpicref->linesize[0] + s->start_x + w * ch; - for (x = 0; x < w; x+=40) - dst[x] = 200; - dst = s->outpicref->data[0] + (s->start_y - 3) * s->outpicref->linesize[0] + s->start_x + w * ch; - for (x = 0; x < w; x+=80) - dst[x] = 200; - dst = s->outpicref->data[0] + (s->h + s->start_y + 1) * s->outpicref->linesize[0] + s->start_x + w * ch; - for (x = 0; x < w; x+=40) { - dst[x] = 200; - } - dst = s->outpicref->data[0] + (s->h + s->start_y + 2) * s->outpicref->linesize[0] + s->start_x + w * ch; - for (x = 0; x < w; x+=80) { - dst[x] = 200; - } - for (x = 0; x < w; x += 80) { - float hertz = x * (inlink->sample_rate / 2) / (float)(1 << (int)ceil(log2(w))); - char *units; - - if (hertz == 0) - units = av_asprintf("DC"); - else - units = av_asprintf("%.2f", hertz); - if (!units) - return AVERROR(ENOMEM); - - drawtext(s->outpicref, s->start_x - 4 * strlen(units) + x + w * ch, s->start_y - 12, units, 0); - drawtext(s->outpicref, s->start_x - 4 * strlen(units) + x + w * ch, s->h + s->start_y + 6, units, 0); - av_free(units); - } - } - for (y = 0; y < s->h; y+=40) { - float seconds = y * spp / inlink->sample_rate; - char *units; - - if (x == 0) - units = av_asprintf("0"); - else if (log10(seconds) > 6) - units = av_asprintf("%.2fh", seconds / (60 * 60)); - else if (log10(seconds) > 3) - units = av_asprintf("%.2fm", seconds / 60); - else - units = av_asprintf("%.2fs", seconds); - if (!units) - return AVERROR(ENOMEM); - - drawtext(s->outpicref, s->start_x - 8 * strlen(units) - 4, s->start_y + y - 4, units, 0); - av_free(units); - } - drawtext(s->outpicref, s->start_x / 7, outlink->h / 2 - 4 * 4, "TIME", 1); - drawtext(s->outpicref, outlink->w / 2 - 14 * 4, outlink->h - s->start_y / 2, "FREQUENCY (Hz)", 0); - } - - for (ch = 0; ch < (multi ? s->nb_display_channels : 1); ch++) { - int h = multi ? s->h / s->nb_display_channels : s->h; - - for (y = 0; y < h; y++) { - float out[3] = { 0., 127.5, 127.5}; - int chn; - - for (chn = 0; chn < (s->mode == SEPARATE ? 1 : s->nb_display_channels); chn++) { - float yf, uf, vf; - int channel = (multi) ? s->nb_display_channels - ch - 1 : chn; - float lout[3]; - - color_range(s, channel, &yf, &uf, &vf); - pick_color(s, yf, uf, vf, y / (float)h, lout); - out[0] += lout[0]; - out[1] += lout[1]; - out[2] += lout[2]; - } - memset(s->outpicref->data[0]+(s->start_y + h * (ch + 1) - y - 1) * s->outpicref->linesize[0] + s->w + s->start_x + 20, av_clip_uint8(out[0]), 10); - memset(s->outpicref->data[1]+(s->start_y + h * (ch + 1) - y - 1) * s->outpicref->linesize[1] + s->w + s->start_x + 20, av_clip_uint8(out[1]), 10); - memset(s->outpicref->data[2]+(s->start_y + h * (ch + 1) - y - 1) * s->outpicref->linesize[2] + s->w + s->start_x + 20, av_clip_uint8(out[2]), 10); - } - - for (y = 0; ch == 0 && y < h; y += h / 10) { - float value = 120.0 * log10(1. - y / (float)h); - char *text; - - if (value < -120) - break; - text = av_asprintf("%.0f dB", value); - if (!text) - continue; - drawtext(s->outpicref, s->w + s->start_x + 35, s->start_y + y - 5, text, 0); - av_free(text); - } - } - } + if (s->legend) + draw_legend(ctx, samples); ret = ff_filter_frame(outlink, s->outpicref); s->outpicref = NULL; diff --git a/libavfilter/avf_showvolume.c b/libavfilter/avf_showvolume.c index 6b553c4eb..548d73c14 100644 --- a/libavfilter/avf_showvolume.c +++ b/libavfilter/avf_showvolume.c @@ -26,6 +26,7 @@ #include "libavutil/parseutils.h" #include "libavutil/xga_font_data.h" #include "avfilter.h" +#include "filters.h" #include "formats.h" #include "audio.h" #include "video.h" @@ -47,6 +48,7 @@ typedef struct ShowVolumeContext { float bgopacity; int mode; + int nb_samples; AVFrame *out; AVExpr *c_expr; int draw_text; @@ -162,12 +164,8 @@ static int config_input(AVFilterLink *inlink) { AVFilterContext *ctx = inlink->dst; ShowVolumeContext *s = ctx->priv; - int nb_samples; - nb_samples = FFMAX(1024, ((double)inlink->sample_rate / av_q2d(s->frame_rate)) + 0.5); - inlink->partial_buf_size = - inlink->min_samples = - inlink->max_samples = nb_samples; + s->nb_samples = FFMAX(1, av_rescale(inlink->sample_rate, s->frame_rate.den, s->frame_rate.num)); s->values = av_calloc(inlink->channels * VAR_VARS_NB, sizeof(double)); if (!s->values) return AVERROR(ENOMEM); @@ -449,6 +447,28 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *insamples) return ff_filter_frame(outlink, out); } +static int activate(AVFilterContext *ctx) +{ + AVFilterLink *inlink = ctx->inputs[0]; + AVFilterLink *outlink = ctx->outputs[0]; + ShowVolumeContext *s = ctx->priv; + AVFrame *in = NULL; + int ret; + + FF_FILTER_FORWARD_STATUS_BACK(outlink, inlink); + + ret = ff_inlink_consume_samples(inlink, s->nb_samples, s->nb_samples, &in); + if (ret < 0) + return ret; + if (ret > 0) + return filter_frame(inlink, in); + + FF_FILTER_FORWARD_STATUS(inlink, outlink); + FF_FILTER_FORWARD_WANTED(outlink, inlink); + + return FFERROR_NOT_READY; +} + static av_cold void uninit(AVFilterContext *ctx) { ShowVolumeContext *s = ctx->priv; @@ -465,7 +485,6 @@ static const AVFilterPad showvolume_inputs[] = { .name = "default", .type = AVMEDIA_TYPE_AUDIO, .config_props = config_input, - .filter_frame = filter_frame, }, { NULL } }; @@ -483,6 +502,7 @@ AVFilter ff_avf_showvolume = { .name = "showvolume", .description = NULL_IF_CONFIG_SMALL("Convert input audio volume to video output."), .init = init, + .activate = activate, .uninit = uninit, .query_formats = query_formats, .priv_size = sizeof(ShowVolumeContext), diff --git a/libavfilter/avf_showwaves.c b/libavfilter/avf_showwaves.c index bb7f4ea87..afe05fb50 100644 --- a/libavfilter/avf_showwaves.c +++ b/libavfilter/avf_showwaves.c @@ -29,6 +29,7 @@ #include "libavutil/opt.h" #include "libavutil/parseutils.h" #include "avfilter.h" +#include "filters.h" #include "formats.h" #include "audio.h" #include "video.h" @@ -416,7 +417,7 @@ static int config_output(AVFilterLink *outlink) showwaves->n = 1; if (!showwaves->n) - showwaves->n = FFMAX(1, ((double)inlink->sample_rate / (showwaves->w * av_q2d(showwaves->rate))) + 0.5); + showwaves->n = FFMAX(1, av_rescale_q(inlink->sample_rate, av_make_q(1, showwaves->w), showwaves->rate)); showwaves->buf_idx = 0; if (!(showwaves->buf_idy = av_mallocz_array(nb_channels, sizeof(*showwaves->buf_idy)))) { @@ -559,7 +560,9 @@ static int push_single_pic(AVFilterLink *outlink) AVFilterContext *ctx = outlink->src; AVFilterLink *inlink = ctx->inputs[0]; ShowWavesContext *showwaves = ctx->priv; - int64_t n = 0, max_samples = showwaves->total_samples / outlink->w; + int64_t n = 0, column_max_samples = showwaves->total_samples / outlink->w; + int64_t remaining_samples = showwaves->total_samples - (column_max_samples * outlink->w); + int64_t last_column_samples = column_max_samples + remaining_samples; AVFrame *out = showwaves->outpicref; struct frame_node *node; const int nb_channels = inlink->channels; @@ -569,12 +572,12 @@ static int push_single_pic(AVFilterLink *outlink) int col = 0; int64_t *sum = showwaves->sum; - if (max_samples == 0) { + if (column_max_samples == 0) { av_log(ctx, AV_LOG_ERROR, "Too few samples\n"); return AVERROR(EINVAL); } - av_log(ctx, AV_LOG_DEBUG, "Create frame averaging %"PRId64" samples per column\n", max_samples); + av_log(ctx, AV_LOG_DEBUG, "Create frame averaging %"PRId64" samples per column\n", column_max_samples); memset(sum, 0, nb_channels); @@ -584,11 +587,13 @@ static int push_single_pic(AVFilterLink *outlink) const int16_t *p = (const int16_t *)frame->data[0]; for (i = 0; i < frame->nb_samples; i++) { + int64_t max_samples = col == outlink->w - 1 ? last_column_samples: column_max_samples; int ch; for (ch = 0; ch < nb_channels; ch++) sum[ch] += abs(p[ch + i*nb_channels]) << 1; - if (n++ == max_samples) { + n++; + if (n == max_samples) { for (ch = 0; ch < nb_channels; ch++) { int16_t sample = sum[ch] / max_samples; uint8_t *buf = out->data[0] + col * pixstep; @@ -702,7 +707,8 @@ static int showwaves_filter_frame(AVFilterLink *inlink, AVFrame *insamples) showwaves->sample_count_mod = 0; showwaves->buf_idx++; } - if (showwaves->buf_idx == showwaves->w) + if (showwaves->buf_idx == showwaves->w || + (ff_outlink_get_status(inlink) && i == nb_samples - 1)) if ((ret = push_frame(outlink)) < 0) break; outpicref = showwaves->outpicref; @@ -713,11 +719,33 @@ end: return ret; } +static int activate(AVFilterContext *ctx) +{ + AVFilterLink *inlink = ctx->inputs[0]; + AVFilterLink *outlink = ctx->outputs[0]; + ShowWavesContext *showwaves = ctx->priv; + AVFrame *in; + const int nb_samples = showwaves->n * outlink->w; + int ret; + + FF_FILTER_FORWARD_STATUS_BACK(outlink, inlink); + + ret = ff_inlink_consume_samples(inlink, nb_samples, nb_samples, &in); + if (ret < 0) + return ret; + if (ret > 0) + return showwaves_filter_frame(inlink, in); + + FF_FILTER_FORWARD_STATUS(inlink, outlink); + FF_FILTER_FORWARD_WANTED(outlink, inlink); + + return FFERROR_NOT_READY; +} + static const AVFilterPad showwaves_inputs[] = { { .name = "default", .type = AVMEDIA_TYPE_AUDIO, - .filter_frame = showwaves_filter_frame, }, { NULL } }; @@ -727,7 +755,6 @@ static const AVFilterPad showwaves_outputs[] = { .name = "default", .type = AVMEDIA_TYPE_VIDEO, .config_props = config_output, - .request_frame = request_frame, }, { NULL } }; @@ -740,6 +767,7 @@ AVFilter ff_avf_showwaves = { .query_formats = query_formats, .priv_size = sizeof(ShowWavesContext), .inputs = showwaves_inputs, + .activate = activate, .outputs = showwaves_outputs, .priv_class = &showwaves_class, }; @@ -761,6 +789,9 @@ static const AVOption showwavespic_options[] = { { "log", "logarithmic", 0, AV_OPT_TYPE_CONST, {.i64=SCALE_LOG}, .flags=FLAGS, .unit="scale"}, { "sqrt", "square root", 0, AV_OPT_TYPE_CONST, {.i64=SCALE_SQRT}, .flags=FLAGS, .unit="scale"}, { "cbrt", "cubic root", 0, AV_OPT_TYPE_CONST, {.i64=SCALE_CBRT}, .flags=FLAGS, .unit="scale"}, + { "draw", "set draw mode", OFFSET(draw_mode), AV_OPT_TYPE_INT, {.i64 = DRAW_SCALE}, 0, DRAW_NB-1, FLAGS, .unit="draw" }, + { "scale", "scale pixel values for each drawn sample", 0, AV_OPT_TYPE_CONST, {.i64=DRAW_SCALE}, .flags=FLAGS, .unit="draw"}, + { "full", "draw every pixel for sample directly", 0, AV_OPT_TYPE_CONST, {.i64=DRAW_FULL}, .flags=FLAGS, .unit="draw"}, { NULL } }; diff --git a/libavfilter/avfilter.c b/libavfilter/avfilter.c index ed8161136..93e866b79 100644 --- a/libavfilter/avfilter.c +++ b/libavfilter/avfilter.c @@ -628,7 +628,7 @@ static const AVClass *filter_child_class_next(const AVClass *prev) static const AVOption avfilter_options[] = { { "thread_type", "Allowed thread types", OFFSET(thread_type), AV_OPT_TYPE_FLAGS, { .i64 = AVFILTER_THREAD_SLICE }, 0, INT_MAX, FLAGS, "thread_type" }, - { "slice", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AVFILTER_THREAD_SLICE }, .unit = "thread_type" }, + { "slice", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AVFILTER_THREAD_SLICE }, .flags = FLAGS, .unit = "thread_type" }, { "enable", "set enable expression", OFFSET(enable_str), AV_OPT_TYPE_STRING, {.str=NULL}, .flags = FLAGS }, { "threads", "Allowed number of threads", OFFSET(nb_threads), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, FLAGS }, @@ -1370,7 +1370,7 @@ static int ff_filter_activate_default(AVFilterContext *filter) and request_frame() to acknowledge status changes), to run once more and check if enough input was present for several frames. - Exemples of scenarios to consider: + Examples of scenarios to consider: - buffersrc: activate if frame_wanted_out to notify the application; activate when the application adds a frame to push it immediately. @@ -1396,7 +1396,7 @@ static int ff_filter_activate_default(AVFilterContext *filter) - If an input has frames in fifo and frame_wanted_out == 0, dequeue a frame and call filter_frame(). - Ratinale: filter frames as soon as possible instead of leaving them + Rationale: filter frames as soon as possible instead of leaving them queued; frame_wanted_out < 0 is not possible since the old API does not set it nor provides any similar feedback; frame_wanted_out > 0 happens when min_samples > 0 and there are not enough samples queued. @@ -1448,11 +1448,21 @@ int ff_inlink_acknowledge_status(AVFilterLink *link, int *rstatus, int64_t *rpts return 1; } +size_t ff_inlink_queued_frames(AVFilterLink *link) +{ + return ff_framequeue_queued_frames(&link->fifo); +} + int ff_inlink_check_available_frame(AVFilterLink *link) { return ff_framequeue_queued_frames(&link->fifo) > 0; } +int ff_inlink_queued_samples(AVFilterLink *link) +{ + return ff_framequeue_queued_samples(&link->fifo); +} + int ff_inlink_check_available_samples(AVFilterLink *link, unsigned min) { uint64_t samples = ff_framequeue_queued_samples(&link->fifo); @@ -1507,6 +1517,11 @@ int ff_inlink_consume_samples(AVFilterLink *link, unsigned min, unsigned max, return 1; } +AVFrame *ff_inlink_peek_frame(AVFilterLink *link, size_t idx) +{ + return ff_framequeue_peek(&link->fifo, idx); +} + int ff_inlink_make_frame_writable(AVFilterLink *link, AVFrame **rframe) { AVFrame *frame = *rframe; diff --git a/libavfilter/avfiltergraph.c b/libavfilter/avfiltergraph.c index 4cc689240..a149f8fb6 100644 --- a/libavfilter/avfiltergraph.c +++ b/libavfilter/avfiltergraph.c @@ -679,6 +679,7 @@ static int pick_format(AVFilterLink *link, AVFilterLink *ref) if (link->type == AVMEDIA_TYPE_VIDEO) { if(ref && ref->type == AVMEDIA_TYPE_VIDEO){ + //FIXME: This should check for AV_PIX_FMT_FLAG_ALPHA after PAL8 pixel format without alpha is implemented int has_alpha= av_pix_fmt_desc_get(ref->format)->nb_components % 2 == 0; enum AVPixelFormat best= AV_PIX_FMT_NONE; int i; diff --git a/libavfilter/blend.h b/libavfilter/blend.h index eb2022683..00db51838 100644 --- a/libavfilter/blend.h +++ b/libavfilter/blend.h @@ -74,7 +74,7 @@ typedef struct FilterParams { struct FilterParams *param, double *values, int starty); } FilterParams; -void ff_blend_init(FilterParams *param, int is_16bit); -void ff_blend_init_x86(FilterParams *param, int is_16bit); +void ff_blend_init(FilterParams *param, int depth); +void ff_blend_init_x86(FilterParams *param, int depth); #endif /* AVFILTER_BLEND_H */ diff --git a/libavfilter/boxblur.c b/libavfilter/boxblur.c new file mode 100644 index 000000000..4534b456d --- /dev/null +++ b/libavfilter/boxblur.c @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2002 Michael Niedermayer + * Copyright (c) 2011 Stefano Sabatini + * Copyright (c) 2018 Danil Iashchenko + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "boxblur.h" + +static const char *const var_names[] = { + "w", + "h", + "cw", + "ch", + "hsub", + "vsub", + NULL +}; + +enum var_name { + VAR_W, + VAR_H, + VAR_CW, + VAR_CH, + VAR_HSUB, + VAR_VSUB, + VARS_NB +}; + + +int ff_boxblur_eval_filter_params(AVFilterLink *inlink, + FilterParam *luma_param, + FilterParam *chroma_param, + FilterParam *alpha_param) +{ + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format); + AVFilterContext *ctx = inlink->dst; + int w = inlink->w, h = inlink->h; + int cw, ch; + double var_values[VARS_NB], res; + char *expr; + int ret; + + if (!luma_param->radius_expr) { + av_log(ctx, AV_LOG_ERROR, "Luma radius expression is not set.\n"); + return AVERROR(EINVAL); + } + + /* fill missing params */ + if (!chroma_param->radius_expr) { + chroma_param->radius_expr = av_strdup(luma_param->radius_expr); + if (!chroma_param->radius_expr) + return AVERROR(ENOMEM); + } + if (chroma_param->power < 0) + chroma_param->power = luma_param->power; + + if (!alpha_param->radius_expr) { + alpha_param->radius_expr = av_strdup(luma_param->radius_expr); + if (!alpha_param->radius_expr) + return AVERROR(ENOMEM); + } + if (alpha_param->power < 0) + alpha_param->power = luma_param->power; + + var_values[VAR_W] = inlink->w; + var_values[VAR_H] = inlink->h; + var_values[VAR_CW] = cw = w>>(desc->log2_chroma_w); + var_values[VAR_CH] = ch = h>>(desc->log2_chroma_h); + var_values[VAR_HSUB] = 1<<(desc->log2_chroma_w); + var_values[VAR_VSUB] = 1<<(desc->log2_chroma_h); + +#define EVAL_RADIUS_EXPR(comp) \ + expr = comp->radius_expr; \ + ret = av_expr_parse_and_eval(&res, expr, var_names, var_values, \ + NULL, NULL, NULL, NULL, NULL, 0, ctx); \ + comp->radius = res; \ + if (ret < 0) { \ + av_log(NULL, AV_LOG_ERROR, \ + "Error when evaluating " #comp " radius expression '%s'\n", expr); \ + return ret; \ + } + + EVAL_RADIUS_EXPR(luma_param); + EVAL_RADIUS_EXPR(chroma_param); + EVAL_RADIUS_EXPR(alpha_param); + + av_log(ctx, AV_LOG_VERBOSE, + "luma_radius:%d luma_power:%d " + "chroma_radius:%d chroma_power:%d " + "alpha_radius:%d alpha_power:%d " + "w:%d chroma_w:%d h:%d chroma_h:%d\n", + luma_param ->radius, luma_param ->power, + chroma_param->radius, chroma_param->power, + alpha_param ->radius, alpha_param ->power, + w, cw, h, ch); + + +#define CHECK_RADIUS_VAL(w_, h_, comp) \ + if (comp->radius < 0 || \ + 2*comp->radius > FFMIN(w_, h_)) { \ + av_log(ctx, AV_LOG_ERROR, \ + "Invalid " #comp " radius value %d, must be >= 0 and <= %d\n", \ + comp->radius, FFMIN(w_, h_)/2); \ + return AVERROR(EINVAL); \ + } + CHECK_RADIUS_VAL(w, h, luma_param); + CHECK_RADIUS_VAL(cw, ch, chroma_param); + CHECK_RADIUS_VAL(w, h, alpha_param); + + return 0; +} diff --git a/libavfilter/boxblur.h b/libavfilter/boxblur.h new file mode 100644 index 000000000..5694722a9 --- /dev/null +++ b/libavfilter/boxblur.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2002 Michael Niedermayer + * Copyright (c) 2011 Stefano Sabatini + * Copyright (c) 2018 Danil Iashchenko + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVFILTER_BOXBLUR_H +#define AVFILTER_BOXBLUR_H + +#include "libavutil/eval.h" +#include "libavutil/pixdesc.h" +#include "libavutil/mem.h" + +#include "avfilter.h" + +typedef struct FilterParam { + int radius; + int power; + char *radius_expr; +} FilterParam; + +#define Y 0 +#define U 1 +#define V 2 +#define A 3 + +int ff_boxblur_eval_filter_params(AVFilterLink *inlink, + FilterParam *luma_param, + FilterParam *chroma_param, + FilterParam *alpha_param); + +#endif // AVFILTER_BOXBLUR_H diff --git a/libavfilter/buffersink.c b/libavfilter/buffersink.c index 0f87b5439..f9b0b5e7d 100644 --- a/libavfilter/buffersink.c +++ b/libavfilter/buffersink.c @@ -320,7 +320,7 @@ static const AVOption buffersink_options[] = { { NULL }, }; #undef FLAGS -#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM +#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_AUDIO_PARAM static const AVOption abuffersink_options[] = { { "sample_fmts", "set the supported sample formats", OFFSET(sample_fmts), AV_OPT_TYPE_BINARY, .flags = FLAGS }, { "sample_rates", "set the supported sample rates", OFFSET(sample_rates), AV_OPT_TYPE_BINARY, .flags = FLAGS }, diff --git a/libavfilter/buffersink.h b/libavfilter/buffersink.h index 21d6bb505..3c846bb52 100644 --- a/libavfilter/buffersink.h +++ b/libavfilter/buffersink.h @@ -151,7 +151,7 @@ int av_buffersink_get_frame(AVFilterContext *ctx, AVFrame *frame); * the end of stream, when it can contain less than nb_samples. * * @return The return codes have the same meaning as for - * av_buffersink_get_samples(). + * av_buffersink_get_frame(). * * @warning do not mix this function with av_buffersink_get_frame(). Use only one or * the other with a single sink, not both. diff --git a/libavfilter/buffersrc.c b/libavfilter/buffersrc.c index cd56f8ca4..e0ff7e4dd 100644 --- a/libavfilter/buffersrc.c +++ b/libavfilter/buffersrc.c @@ -33,6 +33,7 @@ #include "libavutil/internal.h" #include "libavutil/opt.h" #include "libavutil/samplefmt.h" +#include "libavutil/timestamp.h" #include "audio.h" #include "avfilter.h" #include "buffersrc.h" @@ -67,15 +68,20 @@ typedef struct BufferSourceContext { int eof; } BufferSourceContext; -#define CHECK_VIDEO_PARAM_CHANGE(s, c, width, height, format)\ +#define CHECK_VIDEO_PARAM_CHANGE(s, c, width, height, format, pts)\ if (c->w != width || c->h != height || c->pix_fmt != format) {\ - av_log(s, AV_LOG_INFO, "Changing frame properties on the fly is not supported by all filters.\n");\ + av_log(s, AV_LOG_INFO, "filter context - w: %d h: %d fmt: %d, incoming frame - w: %d h: %d fmt: %d pts_time: %s\n",\ + c->w, c->h, c->pix_fmt, width, height, format, av_ts2timestr(pts, &s->outputs[0]->time_base));\ + av_log(s, AV_LOG_WARNING, "Changing video frame properties on the fly is not supported by all filters.\n");\ } -#define CHECK_AUDIO_PARAM_CHANGE(s, c, srate, ch_layout, ch_count, format)\ +#define CHECK_AUDIO_PARAM_CHANGE(s, c, srate, ch_layout, ch_count, format, pts)\ if (c->sample_fmt != format || c->sample_rate != srate ||\ c->channel_layout != ch_layout || c->channels != ch_count) {\ - av_log(s, AV_LOG_ERROR, "Changing frame properties on the fly is not supported.\n");\ + av_log(s, AV_LOG_INFO, "filter context - fmt: %s r: %d layout: %"PRIX64" ch: %d, incoming frame - fmt: %s r: %d layout: %"PRIX64" ch: %d pts_time: %s\n",\ + av_get_sample_fmt_name(c->sample_fmt), c->sample_rate, c->channel_layout, c->channels,\ + av_get_sample_fmt_name(format), srate, ch_layout, ch_count, av_ts2timestr(pts, &s->outputs[0]->time_base));\ + av_log(s, AV_LOG_ERROR, "Changing audio frame properties on the fly is not supported.\n");\ return AVERROR(EINVAL);\ } @@ -205,21 +211,21 @@ static int av_buffersrc_add_frame_internal(AVFilterContext *ctx, if (!(flags & AV_BUFFERSRC_FLAG_NO_CHECK_FORMAT)) { - switch (ctx->outputs[0]->type) { - case AVMEDIA_TYPE_VIDEO: - CHECK_VIDEO_PARAM_CHANGE(ctx, s, frame->width, frame->height, - frame->format); - break; - case AVMEDIA_TYPE_AUDIO: - /* For layouts unknown on input but known on link after negotiation. */ - if (!frame->channel_layout) - frame->channel_layout = s->channel_layout; - CHECK_AUDIO_PARAM_CHANGE(ctx, s, frame->sample_rate, frame->channel_layout, - frame->channels, frame->format); - break; - default: - return AVERROR(EINVAL); - } + switch (ctx->outputs[0]->type) { + case AVMEDIA_TYPE_VIDEO: + CHECK_VIDEO_PARAM_CHANGE(ctx, s, frame->width, frame->height, + frame->format, frame->pts); + break; + case AVMEDIA_TYPE_AUDIO: + /* For layouts unknown on input but known on link after negotiation. */ + if (!frame->channel_layout) + frame->channel_layout = s->channel_layout; + CHECK_AUDIO_PARAM_CHANGE(ctx, s, frame->sample_rate, frame->channel_layout, + frame->channels, frame->format, frame->pts); + break; + default: + return AVERROR(EINVAL); + } } diff --git a/libavfilter/buffersrc.h b/libavfilter/buffersrc.h index 0652113f2..08fbd18a4 100644 --- a/libavfilter/buffersrc.h +++ b/libavfilter/buffersrc.h @@ -106,7 +106,7 @@ typedef struct AVBufferSrcParameters { AVBufferRef *hw_frames_ctx; /** - * Audio only, the audio sampling rate in samples per secon. + * Audio only, the audio sampling rate in samples per second. */ int sample_rate; diff --git a/libavfilter/bwdif.h b/libavfilter/bwdif.h index 8b42c760a..889ff772e 100644 --- a/libavfilter/bwdif.h +++ b/libavfilter/bwdif.h @@ -21,36 +21,10 @@ #include "libavutil/pixdesc.h" #include "avfilter.h" - -enum BWDIFMode { - BWDIF_MODE_SEND_FRAME = 0, ///< send 1 frame for each frame - BWDIF_MODE_SEND_FIELD = 1, ///< send 1 frame for each field -}; - -enum BWDIFParity { - BWDIF_PARITY_TFF = 0, ///< top field first - BWDIF_PARITY_BFF = 1, ///< bottom field first - BWDIF_PARITY_AUTO = -1, ///< auto detection -}; - -enum BWDIFDeint { - BWDIF_DEINT_ALL = 0, ///< deinterlace all frames - BWDIF_DEINT_INTERLACED = 1, ///< only deinterlace frames marked as interlaced -}; +#include "yadif.h" typedef struct BWDIFContext { - const AVClass *class; - - int mode; ///< BWDIFMode - int parity; ///< BWDIFParity - int deint; ///< BWDIFDeint - - int frame_pending; - - AVFrame *cur; - AVFrame *next; - AVFrame *prev; - AVFrame *out; + YADIFContext yadif; void (*filter_intra)(void *dst1, void *cur1, int w, int prefs, int mrefs, int prefs3, int mrefs3, int parity, int clip_max); @@ -61,10 +35,6 @@ typedef struct BWDIFContext { void (*filter_edge)(void *dst, void *prev, void *cur, void *next, int w, int prefs, int mrefs, int prefs2, int mrefs2, int parity, int clip_max, int spat); - - const AVPixFmtDescriptor *csp; - int inter_field; - int eof; } BWDIFContext; void ff_bwdif_init_x86(BWDIFContext *bwdif); diff --git a/libavfilter/colorspace.c b/libavfilter/colorspace.c new file mode 100644 index 000000000..19616e4f1 --- /dev/null +++ b/libavfilter/colorspace.c @@ -0,0 +1,208 @@ +/* + * Copyright (c) 2016 Ronald S. Bultje + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/frame.h" +#include "libavutil/mastering_display_metadata.h" +#include "libavutil/pixdesc.h" + +#include "colorspace.h" + + +void ff_matrix_invert_3x3(const double in[3][3], double out[3][3]) +{ + double m00 = in[0][0], m01 = in[0][1], m02 = in[0][2], + m10 = in[1][0], m11 = in[1][1], m12 = in[1][2], + m20 = in[2][0], m21 = in[2][1], m22 = in[2][2]; + int i, j; + double det; + + out[0][0] = (m11 * m22 - m21 * m12); + out[0][1] = -(m01 * m22 - m21 * m02); + out[0][2] = (m01 * m12 - m11 * m02); + out[1][0] = -(m10 * m22 - m20 * m12); + out[1][1] = (m00 * m22 - m20 * m02); + out[1][2] = -(m00 * m12 - m10 * m02); + out[2][0] = (m10 * m21 - m20 * m11); + out[2][1] = -(m00 * m21 - m20 * m01); + out[2][2] = (m00 * m11 - m10 * m01); + + det = m00 * out[0][0] + m10 * out[0][1] + m20 * out[0][2]; + det = 1.0 / det; + + for (i = 0; i < 3; i++) { + for (j = 0; j < 3; j++) + out[i][j] *= det; + } +} + +void ff_matrix_mul_3x3(double dst[3][3], + const double src1[3][3], const double src2[3][3]) +{ + int m, n; + + for (m = 0; m < 3; m++) + for (n = 0; n < 3; n++) + dst[m][n] = src2[m][0] * src1[0][n] + + src2[m][1] * src1[1][n] + + src2[m][2] * src1[2][n]; +} +/* + * see e.g. http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html + */ +void ff_fill_rgb2xyz_table(const struct PrimaryCoefficients *coeffs, + const struct WhitepointCoefficients *wp, + double rgb2xyz[3][3]) +{ + double i[3][3], sr, sg, sb, zw; + + rgb2xyz[0][0] = coeffs->xr / coeffs->yr; + rgb2xyz[0][1] = coeffs->xg / coeffs->yg; + rgb2xyz[0][2] = coeffs->xb / coeffs->yb; + rgb2xyz[1][0] = rgb2xyz[1][1] = rgb2xyz[1][2] = 1.0; + rgb2xyz[2][0] = (1.0 - coeffs->xr - coeffs->yr) / coeffs->yr; + rgb2xyz[2][1] = (1.0 - coeffs->xg - coeffs->yg) / coeffs->yg; + rgb2xyz[2][2] = (1.0 - coeffs->xb - coeffs->yb) / coeffs->yb; + ff_matrix_invert_3x3(rgb2xyz, i); + zw = 1.0 - wp->xw - wp->yw; + sr = i[0][0] * wp->xw + i[0][1] * wp->yw + i[0][2] * zw; + sg = i[1][0] * wp->xw + i[1][1] * wp->yw + i[1][2] * zw; + sb = i[2][0] * wp->xw + i[2][1] * wp->yw + i[2][2] * zw; + rgb2xyz[0][0] *= sr; + rgb2xyz[0][1] *= sg; + rgb2xyz[0][2] *= sb; + rgb2xyz[1][0] *= sr; + rgb2xyz[1][1] *= sg; + rgb2xyz[1][2] *= sb; + rgb2xyz[2][0] *= sr; + rgb2xyz[2][1] *= sg; + rgb2xyz[2][2] *= sb; +} +static const double ycgco_matrix[3][3] = +{ + { 0.25, 0.5, 0.25 }, + { -0.25, 0.5, -0.25 }, + { 0.5, 0, -0.5 }, +}; + +static const double gbr_matrix[3][3] = +{ + { 0, 1, 0 }, + { 0, -0.5, 0.5 }, + { 0.5, -0.5, 0 }, +}; + +/* + * All constants explained in e.g. https://linuxtv.org/downloads/v4l-dvb-apis/ch02s06.html + * The older ones (bt470bg/m) are also explained in their respective ITU docs + * (e.g. https://www.itu.int/dms_pubrec/itu-r/rec/bt/R-REC-BT.470-5-199802-S!!PDF-E.pdf) + * whereas the newer ones can typically be copied directly from wikipedia :) + */ +static const struct LumaCoefficients luma_coefficients[AVCOL_SPC_NB] = { + [AVCOL_SPC_FCC] = { 0.30, 0.59, 0.11 }, + [AVCOL_SPC_BT470BG] = { 0.299, 0.587, 0.114 }, + [AVCOL_SPC_SMPTE170M] = { 0.299, 0.587, 0.114 }, + [AVCOL_SPC_BT709] = { 0.2126, 0.7152, 0.0722 }, + [AVCOL_SPC_SMPTE240M] = { 0.212, 0.701, 0.087 }, + [AVCOL_SPC_YCOCG] = { 0.25, 0.5, 0.25 }, + [AVCOL_SPC_RGB] = { 1, 1, 1 }, + [AVCOL_SPC_BT2020_NCL] = { 0.2627, 0.6780, 0.0593 }, + [AVCOL_SPC_BT2020_CL] = { 0.2627, 0.6780, 0.0593 }, +}; + +const struct LumaCoefficients *ff_get_luma_coefficients(enum AVColorSpace csp) +{ + const struct LumaCoefficients *coeffs; + + if (csp >= AVCOL_SPC_NB) + return NULL; + coeffs = &luma_coefficients[csp]; + if (!coeffs->cr) + return NULL; + + return coeffs; +} + +void ff_fill_rgb2yuv_table(const struct LumaCoefficients *coeffs, + double rgb2yuv[3][3]) +{ + double bscale, rscale; + + // special ycgco matrix + if (coeffs->cr == 0.25 && coeffs->cg == 0.5 && coeffs->cb == 0.25) { + memcpy(rgb2yuv, ycgco_matrix, sizeof(double) * 9); + return; + } else if (coeffs->cr == 1 && coeffs->cg == 1 && coeffs->cb == 1) { + memcpy(rgb2yuv, gbr_matrix, sizeof(double) * 9); + return; + } + + rgb2yuv[0][0] = coeffs->cr; + rgb2yuv[0][1] = coeffs->cg; + rgb2yuv[0][2] = coeffs->cb; + bscale = 0.5 / (coeffs->cb - 1.0); + rscale = 0.5 / (coeffs->cr - 1.0); + rgb2yuv[1][0] = bscale * coeffs->cr; + rgb2yuv[1][1] = bscale * coeffs->cg; + rgb2yuv[1][2] = 0.5; + rgb2yuv[2][0] = 0.5; + rgb2yuv[2][1] = rscale * coeffs->cg; + rgb2yuv[2][2] = rscale * coeffs->cb; +} + +double ff_determine_signal_peak(AVFrame *in) +{ + AVFrameSideData *sd = av_frame_get_side_data(in, AV_FRAME_DATA_CONTENT_LIGHT_LEVEL); + double peak = 0; + + if (sd) { + AVContentLightMetadata *clm = (AVContentLightMetadata *)sd->data; + peak = clm->MaxCLL / REFERENCE_WHITE; + } + + sd = av_frame_get_side_data(in, AV_FRAME_DATA_MASTERING_DISPLAY_METADATA); + if (!peak && sd) { + AVMasteringDisplayMetadata *metadata = (AVMasteringDisplayMetadata *)sd->data; + if (metadata->has_luminance) + peak = av_q2d(metadata->max_luminance) / REFERENCE_WHITE; + } + + // For untagged source, use peak of 10000 if SMPTE ST.2084 + // otherwise assume HLG with reference display peak 1000. + if (!peak) + peak = in->color_trc == AVCOL_TRC_SMPTE2084 ? 100.0f : 10.0f; + + return peak; +} + +void ff_update_hdr_metadata(AVFrame *in, double peak) +{ + AVFrameSideData *sd = av_frame_get_side_data(in, AV_FRAME_DATA_CONTENT_LIGHT_LEVEL); + + if (sd) { + AVContentLightMetadata *clm = (AVContentLightMetadata *)sd->data; + clm->MaxCLL = (unsigned)(peak * REFERENCE_WHITE); + } + + sd = av_frame_get_side_data(in, AV_FRAME_DATA_MASTERING_DISPLAY_METADATA); + if (sd) { + AVMasteringDisplayMetadata *metadata = (AVMasteringDisplayMetadata *)sd->data; + if (metadata->has_luminance) + metadata->max_luminance = av_d2q(peak * REFERENCE_WHITE, 10000); + } +} diff --git a/libavfilter/colorspace.h b/libavfilter/colorspace.h new file mode 100644 index 000000000..459a5df60 --- /dev/null +++ b/libavfilter/colorspace.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2016 Ronald S. Bultje + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVFILTER_COLORSPACE_H +#define AVFILTER_COLORSPACE_H + +#include "libavutil/common.h" +#include "libavutil/frame.h" + +#define REFERENCE_WHITE 100.0f + +struct LumaCoefficients { + double cr, cg, cb; +}; + +struct PrimaryCoefficients { + double xr, yr, xg, yg, xb, yb; +}; + +struct WhitepointCoefficients { + double xw, yw; +}; + +void ff_matrix_invert_3x3(const double in[3][3], double out[3][3]); +void ff_matrix_mul_3x3(double dst[3][3], + const double src1[3][3], const double src2[3][3]); +void ff_fill_rgb2xyz_table(const struct PrimaryCoefficients *coeffs, + const struct WhitepointCoefficients *wp, + double rgb2xyz[3][3]); + +const struct LumaCoefficients *ff_get_luma_coefficients(enum AVColorSpace csp); +void ff_fill_rgb2yuv_table(const struct LumaCoefficients *coeffs, + double rgb2yuv[3][3]); + +double ff_determine_signal_peak(AVFrame *in); +void ff_update_hdr_metadata(AVFrame *in, double peak); + +#endif diff --git a/libavfilter/dnn_backend_native.c b/libavfilter/dnn_backend_native.c new file mode 100644 index 000000000..82e900bd8 --- /dev/null +++ b/libavfilter/dnn_backend_native.c @@ -0,0 +1,389 @@ +/* + * Copyright (c) 2018 Sergey Lavrushkin + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * DNN native backend implementation. + */ + +#include "dnn_backend_native.h" +#include "libavutil/avassert.h" + +static DNNReturnType set_input_output_native(void *model, DNNInputData *input, const char *input_name, const char **output_names, uint32_t nb_output) +{ + ConvolutionalNetwork *network = (ConvolutionalNetwork *)model; + InputParams *input_params; + ConvolutionalParams *conv_params; + DepthToSpaceParams *depth_to_space_params; + int cur_width, cur_height, cur_channels; + int32_t layer; + + if (network->layers_num <= 0 || network->layers[0].type != INPUT){ + return DNN_ERROR; + } + else{ + input_params = (InputParams *)network->layers[0].params; + input_params->width = cur_width = input->width; + input_params->height = cur_height = input->height; + input_params->channels = cur_channels = input->channels; + if (input->data){ + av_freep(&input->data); + } + av_assert0(input->dt == DNN_FLOAT); + network->layers[0].output = input->data = av_malloc(cur_height * cur_width * cur_channels * sizeof(float)); + if (!network->layers[0].output){ + return DNN_ERROR; + } + } + + for (layer = 1; layer < network->layers_num; ++layer){ + switch (network->layers[layer].type){ + case CONV: + conv_params = (ConvolutionalParams *)network->layers[layer].params; + if (conv_params->input_num != cur_channels){ + return DNN_ERROR; + } + cur_channels = conv_params->output_num; + + if (conv_params->padding_method == VALID) { + int pad_size = (conv_params->kernel_size - 1) * conv_params->dilation; + cur_height -= pad_size; + cur_width -= pad_size; + } + break; + case DEPTH_TO_SPACE: + depth_to_space_params = (DepthToSpaceParams *)network->layers[layer].params; + if (cur_channels % (depth_to_space_params->block_size * depth_to_space_params->block_size) != 0){ + return DNN_ERROR; + } + cur_channels = cur_channels / (depth_to_space_params->block_size * depth_to_space_params->block_size); + cur_height *= depth_to_space_params->block_size; + cur_width *= depth_to_space_params->block_size; + break; + default: + return DNN_ERROR; + } + if (network->layers[layer].output){ + av_freep(&network->layers[layer].output); + } + + if (cur_height <= 0 || cur_width <= 0) + return DNN_ERROR; + + network->layers[layer].output = av_malloc(cur_height * cur_width * cur_channels * sizeof(float)); + if (!network->layers[layer].output){ + return DNN_ERROR; + } + } + + return DNN_SUCCESS; +} + +// Loads model and its parameters that are stored in a binary file with following structure: +// layers_num,layer_type,layer_parameterss,layer_type,layer_parameters... +// For CONV layer: activation_function, input_num, output_num, kernel_size, kernel, biases +// For DEPTH_TO_SPACE layer: block_size +DNNModel *ff_dnn_load_model_native(const char *model_filename) +{ + DNNModel *model = NULL; + ConvolutionalNetwork *network = NULL; + AVIOContext *model_file_context; + int file_size, dnn_size, kernel_size, i; + int32_t layer; + DNNLayerType layer_type; + ConvolutionalParams *conv_params; + DepthToSpaceParams *depth_to_space_params; + + model = av_malloc(sizeof(DNNModel)); + if (!model){ + return NULL; + } + + if (avio_open(&model_file_context, model_filename, AVIO_FLAG_READ) < 0){ + av_freep(&model); + return NULL; + } + file_size = avio_size(model_file_context); + + network = av_malloc(sizeof(ConvolutionalNetwork)); + if (!network){ + avio_closep(&model_file_context); + av_freep(&model); + return NULL; + } + model->model = (void *)network; + + network->layers_num = 1 + (int32_t)avio_rl32(model_file_context); + dnn_size = 4; + + network->layers = av_malloc(network->layers_num * sizeof(Layer)); + if (!network->layers){ + av_freep(&network); + avio_closep(&model_file_context); + av_freep(&model); + return NULL; + } + + for (layer = 0; layer < network->layers_num; ++layer){ + network->layers[layer].output = NULL; + network->layers[layer].params = NULL; + } + network->layers[0].type = INPUT; + network->layers[0].params = av_malloc(sizeof(InputParams)); + if (!network->layers[0].params){ + avio_closep(&model_file_context); + ff_dnn_free_model_native(&model); + return NULL; + } + + for (layer = 1; layer < network->layers_num; ++layer){ + layer_type = (int32_t)avio_rl32(model_file_context); + dnn_size += 4; + switch (layer_type){ + case CONV: + conv_params = av_malloc(sizeof(ConvolutionalParams)); + if (!conv_params){ + avio_closep(&model_file_context); + ff_dnn_free_model_native(&model); + return NULL; + } + conv_params->dilation = (int32_t)avio_rl32(model_file_context); + conv_params->padding_method = (int32_t)avio_rl32(model_file_context); + conv_params->activation = (int32_t)avio_rl32(model_file_context); + conv_params->input_num = (int32_t)avio_rl32(model_file_context); + conv_params->output_num = (int32_t)avio_rl32(model_file_context); + conv_params->kernel_size = (int32_t)avio_rl32(model_file_context); + kernel_size = conv_params->input_num * conv_params->output_num * + conv_params->kernel_size * conv_params->kernel_size; + dnn_size += 24 + (kernel_size + conv_params->output_num << 2); + if (dnn_size > file_size || conv_params->input_num <= 0 || + conv_params->output_num <= 0 || conv_params->kernel_size <= 0){ + avio_closep(&model_file_context); + ff_dnn_free_model_native(&model); + return NULL; + } + conv_params->kernel = av_malloc(kernel_size * sizeof(float)); + conv_params->biases = av_malloc(conv_params->output_num * sizeof(float)); + if (!conv_params->kernel || !conv_params->biases){ + avio_closep(&model_file_context); + ff_dnn_free_model_native(&model); + return NULL; + } + for (i = 0; i < kernel_size; ++i){ + conv_params->kernel[i] = av_int2float(avio_rl32(model_file_context)); + } + for (i = 0; i < conv_params->output_num; ++i){ + conv_params->biases[i] = av_int2float(avio_rl32(model_file_context)); + } + network->layers[layer].type = CONV; + network->layers[layer].params = conv_params; + break; + case DEPTH_TO_SPACE: + depth_to_space_params = av_malloc(sizeof(DepthToSpaceParams)); + if (!depth_to_space_params){ + avio_closep(&model_file_context); + ff_dnn_free_model_native(&model); + return NULL; + } + depth_to_space_params->block_size = (int32_t)avio_rl32(model_file_context); + dnn_size += 4; + network->layers[layer].type = DEPTH_TO_SPACE; + network->layers[layer].params = depth_to_space_params; + break; + default: + avio_closep(&model_file_context); + ff_dnn_free_model_native(&model); + return NULL; + } + } + + avio_closep(&model_file_context); + + if (dnn_size != file_size){ + ff_dnn_free_model_native(&model); + return NULL; + } + + model->set_input_output = &set_input_output_native; + + return model; +} + +#define CLAMP_TO_EDGE(x, w) ((x) < 0 ? 0 : ((x) >= (w) ? (w - 1) : (x))) + +static void convolve(const float *input, float *output, const ConvolutionalParams *conv_params, int width, int height) +{ + int radius = conv_params->kernel_size >> 1; + int src_linesize = width * conv_params->input_num; + int filter_linesize = conv_params->kernel_size * conv_params->input_num; + int filter_size = conv_params->kernel_size * filter_linesize; + int pad_size = (conv_params->padding_method == VALID) ? (conv_params->kernel_size - 1) / 2 * conv_params->dilation : 0; + + for (int y = pad_size; y < height - pad_size; ++y) { + for (int x = pad_size; x < width - pad_size; ++x) { + for (int n_filter = 0; n_filter < conv_params->output_num; ++n_filter) { + output[n_filter] = conv_params->biases[n_filter]; + + for (int ch = 0; ch < conv_params->input_num; ++ch) { + for (int kernel_y = 0; kernel_y < conv_params->kernel_size; ++kernel_y) { + for (int kernel_x = 0; kernel_x < conv_params->kernel_size; ++kernel_x) { + float input_pel; + if (conv_params->padding_method == SAME_CLAMP_TO_EDGE) { + int y_pos = CLAMP_TO_EDGE(y + (kernel_y - radius) * conv_params->dilation, height); + int x_pos = CLAMP_TO_EDGE(x + (kernel_x - radius) * conv_params->dilation, width); + input_pel = input[y_pos * src_linesize + x_pos * conv_params->input_num + ch]; + } else { + int y_pos = y + (kernel_y - radius) * conv_params->dilation; + int x_pos = x + (kernel_x - radius) * conv_params->dilation; + input_pel = (x_pos < 0 || x_pos >= width || y_pos < 0 || y_pos >= height) ? 0.0 : + input[y_pos * src_linesize + x_pos * conv_params->input_num + ch]; + } + + + output[n_filter] += input_pel * conv_params->kernel[n_filter * filter_size + kernel_y * filter_linesize + + kernel_x * conv_params->input_num + ch]; + } + } + } + switch (conv_params->activation){ + case RELU: + output[n_filter] = FFMAX(output[n_filter], 0.0); + break; + case TANH: + output[n_filter] = 2.0f / (1.0f + exp(-2.0f * output[n_filter])) - 1.0f; + break; + case SIGMOID: + output[n_filter] = 1.0f / (1.0f + exp(-output[n_filter])); + break; + case NONE: + break; + case LEAKY_RELU: + output[n_filter] = FFMAX(output[n_filter], 0.0) + 0.2 * FFMIN(output[n_filter], 0.0); + } + } + output += conv_params->output_num; + } + } +} + +static void depth_to_space(const float *input, float *output, int block_size, int width, int height, int channels) +{ + int y, x, by, bx, ch; + int new_channels = channels / (block_size * block_size); + int output_linesize = width * channels; + int by_linesize = output_linesize / block_size; + int x_linesize = new_channels * block_size; + + for (y = 0; y < height; ++y){ + for (x = 0; x < width; ++x){ + for (by = 0; by < block_size; ++by){ + for (bx = 0; bx < block_size; ++bx){ + for (ch = 0; ch < new_channels; ++ch){ + output[by * by_linesize + x * x_linesize + bx * new_channels + ch] = input[ch]; + } + input += new_channels; + } + } + } + output += output_linesize; + } +} + +DNNReturnType ff_dnn_execute_model_native(const DNNModel *model, DNNData *outputs, uint32_t nb_output) +{ + ConvolutionalNetwork *network = (ConvolutionalNetwork *)model->model; + int cur_width, cur_height, cur_channels; + int32_t layer; + InputParams *input_params; + ConvolutionalParams *conv_params; + DepthToSpaceParams *depth_to_space_params; + + if (network->layers_num <= 0 || network->layers[0].type != INPUT || !network->layers[0].output){ + return DNN_ERROR; + } + else{ + input_params = (InputParams *)network->layers[0].params; + cur_width = input_params->width; + cur_height = input_params->height; + cur_channels = input_params->channels; + } + + for (layer = 1; layer < network->layers_num; ++layer){ + if (!network->layers[layer].output){ + return DNN_ERROR; + } + switch (network->layers[layer].type){ + case CONV: + conv_params = (ConvolutionalParams *)network->layers[layer].params; + convolve(network->layers[layer - 1].output, network->layers[layer].output, conv_params, cur_width, cur_height); + cur_channels = conv_params->output_num; + if (conv_params->padding_method == VALID) { + int pad_size = (conv_params->kernel_size - 1) * conv_params->dilation; + cur_height -= pad_size; + cur_width -= pad_size; + } + break; + case DEPTH_TO_SPACE: + depth_to_space_params = (DepthToSpaceParams *)network->layers[layer].params; + depth_to_space(network->layers[layer - 1].output, network->layers[layer].output, + depth_to_space_params->block_size, cur_width, cur_height, cur_channels); + cur_height *= depth_to_space_params->block_size; + cur_width *= depth_to_space_params->block_size; + cur_channels /= depth_to_space_params->block_size * depth_to_space_params->block_size; + break; + case INPUT: + return DNN_ERROR; + } + } + + // native mode does not support multiple outputs yet + if (nb_output > 1) + return DNN_ERROR; + outputs[0].data = network->layers[network->layers_num - 1].output; + outputs[0].height = cur_height; + outputs[0].width = cur_width; + outputs[0].channels = cur_channels; + + return DNN_SUCCESS; +} + +void ff_dnn_free_model_native(DNNModel **model) +{ + ConvolutionalNetwork *network; + ConvolutionalParams *conv_params; + int32_t layer; + + if (*model) + { + network = (ConvolutionalNetwork *)(*model)->model; + for (layer = 0; layer < network->layers_num; ++layer){ + av_freep(&network->layers[layer].output); + if (network->layers[layer].type == CONV){ + conv_params = (ConvolutionalParams *)network->layers[layer].params; + av_freep(&conv_params->kernel); + av_freep(&conv_params->biases); + } + av_freep(&network->layers[layer].params); + } + av_freep(&network->layers); + av_freep(&network); + av_freep(model); + } +} diff --git a/libavfilter/dnn_backend_native.h b/libavfilter/dnn_backend_native.h new file mode 100644 index 000000000..591795573 --- /dev/null +++ b/libavfilter/dnn_backend_native.h @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2018 Sergey Lavrushkin + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * DNN inference functions interface for native backend. + */ + + +#ifndef AVFILTER_DNN_BACKEND_NATIVE_H +#define AVFILTER_DNN_BACKEND_NATIVE_H + +#include "dnn_interface.h" +#include "libavformat/avio.h" + +typedef enum {INPUT, CONV, DEPTH_TO_SPACE} DNNLayerType; + +typedef enum {RELU, TANH, SIGMOID, NONE, LEAKY_RELU} DNNActivationFunc; + +typedef enum {VALID, SAME, SAME_CLAMP_TO_EDGE} DNNConvPaddingParam; + +typedef struct Layer{ + DNNLayerType type; + float *output; + void *params; +} Layer; + +typedef struct ConvolutionalParams{ + int32_t input_num, output_num, kernel_size; + DNNActivationFunc activation; + DNNConvPaddingParam padding_method; + int32_t dilation; + float *kernel; + float *biases; +} ConvolutionalParams; + +typedef struct InputParams{ + int height, width, channels; +} InputParams; + +typedef struct DepthToSpaceParams{ + int block_size; +} DepthToSpaceParams; + +// Represents simple feed-forward convolutional network. +typedef struct ConvolutionalNetwork{ + Layer *layers; + int32_t layers_num; +} ConvolutionalNetwork; + +DNNModel *ff_dnn_load_model_native(const char *model_filename); + +DNNReturnType ff_dnn_execute_model_native(const DNNModel *model, DNNData *outputs, uint32_t nb_output); + +void ff_dnn_free_model_native(DNNModel **model); + +#endif diff --git a/libavfilter/dnn_backend_tf.c b/libavfilter/dnn_backend_tf.c new file mode 100644 index 000000000..ba959ae3a --- /dev/null +++ b/libavfilter/dnn_backend_tf.c @@ -0,0 +1,603 @@ +/* + * Copyright (c) 2018 Sergey Lavrushkin + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * DNN tensorflow backend implementation. + */ + +#include "dnn_backend_tf.h" +#include "dnn_backend_native.h" +#include "libavformat/avio.h" +#include "libavutil/avassert.h" + +#include + +typedef struct TFModel{ + TF_Graph *graph; + TF_Session *session; + TF_Status *status; + TF_Output input; + TF_Tensor *input_tensor; + TF_Output *outputs; + TF_Tensor **output_tensors; + uint32_t nb_output; +} TFModel; + +static void free_buffer(void *data, size_t length) +{ + av_freep(&data); +} + +static TF_Buffer *read_graph(const char *model_filename) +{ + TF_Buffer *graph_buf; + unsigned char *graph_data = NULL; + AVIOContext *model_file_context; + long size, bytes_read; + + if (avio_open(&model_file_context, model_filename, AVIO_FLAG_READ) < 0){ + return NULL; + } + + size = avio_size(model_file_context); + + graph_data = av_malloc(size); + if (!graph_data){ + avio_closep(&model_file_context); + return NULL; + } + bytes_read = avio_read(model_file_context, graph_data, size); + avio_closep(&model_file_context); + if (bytes_read != size){ + av_freep(&graph_data); + return NULL; + } + + graph_buf = TF_NewBuffer(); + graph_buf->data = (void *)graph_data; + graph_buf->length = size; + graph_buf->data_deallocator = free_buffer; + + return graph_buf; +} + +static TF_Tensor *allocate_input_tensor(const DNNInputData *input) +{ + TF_DataType dt; + size_t size; + int64_t input_dims[] = {1, input->height, input->width, input->channels}; + switch (input->dt) { + case DNN_FLOAT: + dt = TF_FLOAT; + size = sizeof(float); + break; + case DNN_UINT8: + dt = TF_UINT8; + size = sizeof(char); + break; + default: + av_assert0(!"should not reach here"); + } + + return TF_AllocateTensor(dt, input_dims, 4, + input_dims[1] * input_dims[2] * input_dims[3] * size); +} + +static DNNReturnType set_input_output_tf(void *model, DNNInputData *input, const char *input_name, const char **output_names, uint32_t nb_output) +{ + TFModel *tf_model = (TFModel *)model; + TF_SessionOptions *sess_opts; + const TF_Operation *init_op = TF_GraphOperationByName(tf_model->graph, "init"); + + // Input operation + tf_model->input.oper = TF_GraphOperationByName(tf_model->graph, input_name); + if (!tf_model->input.oper){ + return DNN_ERROR; + } + tf_model->input.index = 0; + if (tf_model->input_tensor){ + TF_DeleteTensor(tf_model->input_tensor); + } + tf_model->input_tensor = allocate_input_tensor(input); + if (!tf_model->input_tensor){ + return DNN_ERROR; + } + input->data = (float *)TF_TensorData(tf_model->input_tensor); + + // Output operation + if (nb_output == 0) + return DNN_ERROR; + + av_freep(&tf_model->outputs); + tf_model->outputs = av_malloc_array(nb_output, sizeof(*tf_model->outputs)); + if (!tf_model->outputs) + return DNN_ERROR; + for (int i = 0; i < nb_output; ++i) { + tf_model->outputs[i].oper = TF_GraphOperationByName(tf_model->graph, output_names[i]); + if (!tf_model->outputs[i].oper){ + av_freep(&tf_model->outputs); + return DNN_ERROR; + } + tf_model->outputs[i].index = 0; + } + + if (tf_model->output_tensors) { + for (uint32_t i = 0; i < tf_model->nb_output; ++i) { + if (tf_model->output_tensors[i]) { + TF_DeleteTensor(tf_model->output_tensors[i]); + tf_model->output_tensors[i] = NULL; + } + } + } + av_freep(&tf_model->output_tensors); + tf_model->output_tensors = av_mallocz_array(nb_output, sizeof(*tf_model->output_tensors)); + if (!tf_model->output_tensors) { + av_freep(&tf_model->outputs); + return DNN_ERROR; + } + + tf_model->nb_output = nb_output; + + if (tf_model->session){ + TF_CloseSession(tf_model->session, tf_model->status); + TF_DeleteSession(tf_model->session, tf_model->status); + } + + sess_opts = TF_NewSessionOptions(); + tf_model->session = TF_NewSession(tf_model->graph, sess_opts, tf_model->status); + TF_DeleteSessionOptions(sess_opts); + if (TF_GetCode(tf_model->status) != TF_OK) + { + return DNN_ERROR; + } + + // Run initialization operation with name "init" if it is present in graph + if (init_op){ + TF_SessionRun(tf_model->session, NULL, + NULL, NULL, 0, + NULL, NULL, 0, + &init_op, 1, NULL, tf_model->status); + if (TF_GetCode(tf_model->status) != TF_OK) + { + return DNN_ERROR; + } + } + + return DNN_SUCCESS; +} + +static DNNReturnType load_tf_model(TFModel *tf_model, const char *model_filename) +{ + TF_Buffer *graph_def; + TF_ImportGraphDefOptions *graph_opts; + + graph_def = read_graph(model_filename); + if (!graph_def){ + return DNN_ERROR; + } + tf_model->graph = TF_NewGraph(); + tf_model->status = TF_NewStatus(); + graph_opts = TF_NewImportGraphDefOptions(); + TF_GraphImportGraphDef(tf_model->graph, graph_def, graph_opts, tf_model->status); + TF_DeleteImportGraphDefOptions(graph_opts); + TF_DeleteBuffer(graph_def); + if (TF_GetCode(tf_model->status) != TF_OK){ + TF_DeleteGraph(tf_model->graph); + TF_DeleteStatus(tf_model->status); + return DNN_ERROR; + } + + return DNN_SUCCESS; +} + +#define NAME_BUFFER_SIZE 256 + +static DNNReturnType add_conv_layer(TFModel *tf_model, TF_Operation *transpose_op, TF_Operation **cur_op, + ConvolutionalParams* params, const int layer) +{ + TF_Operation *op; + TF_OperationDescription *op_desc; + TF_Output input; + int64_t strides[] = {1, 1, 1, 1}; + TF_Tensor *tensor; + int64_t dims[4]; + int dims_len; + char name_buffer[NAME_BUFFER_SIZE]; + int32_t size; + + size = params->input_num * params->output_num * params->kernel_size * params->kernel_size; + input.index = 0; + + snprintf(name_buffer, NAME_BUFFER_SIZE, "conv_kernel%d", layer); + op_desc = TF_NewOperation(tf_model->graph, "Const", name_buffer); + TF_SetAttrType(op_desc, "dtype", TF_FLOAT); + dims[0] = params->output_num; + dims[1] = params->kernel_size; + dims[2] = params->kernel_size; + dims[3] = params->input_num; + dims_len = 4; + tensor = TF_AllocateTensor(TF_FLOAT, dims, dims_len, size * sizeof(float)); + memcpy(TF_TensorData(tensor), params->kernel, size * sizeof(float)); + TF_SetAttrTensor(op_desc, "value", tensor, tf_model->status); + if (TF_GetCode(tf_model->status) != TF_OK){ + return DNN_ERROR; + } + op = TF_FinishOperation(op_desc, tf_model->status); + if (TF_GetCode(tf_model->status) != TF_OK){ + return DNN_ERROR; + } + + snprintf(name_buffer, NAME_BUFFER_SIZE, "transpose%d", layer); + op_desc = TF_NewOperation(tf_model->graph, "Transpose", name_buffer); + input.oper = op; + TF_AddInput(op_desc, input); + input.oper = transpose_op; + TF_AddInput(op_desc, input); + TF_SetAttrType(op_desc, "T", TF_FLOAT); + TF_SetAttrType(op_desc, "Tperm", TF_INT32); + op = TF_FinishOperation(op_desc, tf_model->status); + if (TF_GetCode(tf_model->status) != TF_OK){ + return DNN_ERROR; + } + + snprintf(name_buffer, NAME_BUFFER_SIZE, "conv2d%d", layer); + op_desc = TF_NewOperation(tf_model->graph, "Conv2D", name_buffer); + input.oper = *cur_op; + TF_AddInput(op_desc, input); + input.oper = op; + TF_AddInput(op_desc, input); + TF_SetAttrType(op_desc, "T", TF_FLOAT); + TF_SetAttrIntList(op_desc, "strides", strides, 4); + TF_SetAttrString(op_desc, "padding", "VALID", 5); + *cur_op = TF_FinishOperation(op_desc, tf_model->status); + if (TF_GetCode(tf_model->status) != TF_OK){ + return DNN_ERROR; + } + + snprintf(name_buffer, NAME_BUFFER_SIZE, "conv_biases%d", layer); + op_desc = TF_NewOperation(tf_model->graph, "Const", name_buffer); + TF_SetAttrType(op_desc, "dtype", TF_FLOAT); + dims[0] = params->output_num; + dims_len = 1; + tensor = TF_AllocateTensor(TF_FLOAT, dims, dims_len, params->output_num * sizeof(float)); + memcpy(TF_TensorData(tensor), params->biases, params->output_num * sizeof(float)); + TF_SetAttrTensor(op_desc, "value", tensor, tf_model->status); + if (TF_GetCode(tf_model->status) != TF_OK){ + return DNN_ERROR; + } + op = TF_FinishOperation(op_desc, tf_model->status); + if (TF_GetCode(tf_model->status) != TF_OK){ + return DNN_ERROR; + } + + snprintf(name_buffer, NAME_BUFFER_SIZE, "bias_add%d", layer); + op_desc = TF_NewOperation(tf_model->graph, "BiasAdd", name_buffer); + input.oper = *cur_op; + TF_AddInput(op_desc, input); + input.oper = op; + TF_AddInput(op_desc, input); + TF_SetAttrType(op_desc, "T", TF_FLOAT); + *cur_op = TF_FinishOperation(op_desc, tf_model->status); + if (TF_GetCode(tf_model->status) != TF_OK){ + return DNN_ERROR; + } + + snprintf(name_buffer, NAME_BUFFER_SIZE, "activation%d", layer); + switch (params->activation){ + case RELU: + op_desc = TF_NewOperation(tf_model->graph, "Relu", name_buffer); + break; + case TANH: + op_desc = TF_NewOperation(tf_model->graph, "Tanh", name_buffer); + break; + case SIGMOID: + op_desc = TF_NewOperation(tf_model->graph, "Sigmoid", name_buffer); + break; + default: + return DNN_ERROR; + } + input.oper = *cur_op; + TF_AddInput(op_desc, input); + TF_SetAttrType(op_desc, "T", TF_FLOAT); + *cur_op = TF_FinishOperation(op_desc, tf_model->status); + if (TF_GetCode(tf_model->status) != TF_OK){ + return DNN_ERROR; + } + + return DNN_SUCCESS; +} + +static DNNReturnType add_depth_to_space_layer(TFModel *tf_model, TF_Operation **cur_op, + DepthToSpaceParams *params, const int layer) +{ + TF_OperationDescription *op_desc; + TF_Output input; + char name_buffer[NAME_BUFFER_SIZE]; + + snprintf(name_buffer, NAME_BUFFER_SIZE, "depth_to_space%d", layer); + op_desc = TF_NewOperation(tf_model->graph, "DepthToSpace", name_buffer); + input.oper = *cur_op; + input.index = 0; + TF_AddInput(op_desc, input); + TF_SetAttrType(op_desc, "T", TF_FLOAT); + TF_SetAttrInt(op_desc, "block_size", params->block_size); + *cur_op = TF_FinishOperation(op_desc, tf_model->status); + if (TF_GetCode(tf_model->status) != TF_OK){ + return DNN_ERROR; + } + + return DNN_SUCCESS; +} + +static int calculate_pad(const ConvolutionalNetwork *conv_network) +{ + ConvolutionalParams *params; + int32_t layer; + int pad = 0; + + for (layer = 0; layer < conv_network->layers_num; ++layer){ + if (conv_network->layers[layer].type == CONV){ + params = (ConvolutionalParams *)conv_network->layers[layer].params; + pad += params->kernel_size >> 1; + } + } + + return pad; +} + +static DNNReturnType add_pad_op(TFModel *tf_model, TF_Operation **cur_op, const int32_t pad) +{ + TF_Operation *op; + TF_Tensor *tensor; + TF_OperationDescription *op_desc; + TF_Output input; + int32_t *pads; + int64_t pads_shape[] = {4, 2}; + + input.index = 0; + + op_desc = TF_NewOperation(tf_model->graph, "Const", "pads"); + TF_SetAttrType(op_desc, "dtype", TF_INT32); + tensor = TF_AllocateTensor(TF_INT32, pads_shape, 2, 4 * 2 * sizeof(int32_t)); + pads = (int32_t *)TF_TensorData(tensor); + pads[0] = 0; pads[1] = 0; + pads[2] = pad; pads[3] = pad; + pads[4] = pad; pads[5] = pad; + pads[6] = 0; pads[7] = 0; + TF_SetAttrTensor(op_desc, "value", tensor, tf_model->status); + if (TF_GetCode(tf_model->status) != TF_OK){ + return DNN_ERROR; + } + op = TF_FinishOperation(op_desc, tf_model->status); + if (TF_GetCode(tf_model->status) != TF_OK){ + return DNN_ERROR; + } + + op_desc = TF_NewOperation(tf_model->graph, "MirrorPad", "mirror_pad"); + input.oper = *cur_op; + TF_AddInput(op_desc, input); + input.oper = op; + TF_AddInput(op_desc, input); + TF_SetAttrType(op_desc, "T", TF_FLOAT); + TF_SetAttrType(op_desc, "Tpaddings", TF_INT32); + TF_SetAttrString(op_desc, "mode", "SYMMETRIC", 9); + *cur_op = TF_FinishOperation(op_desc, tf_model->status); + if (TF_GetCode(tf_model->status) != TF_OK){ + return DNN_ERROR; + } + + return DNN_SUCCESS; +} + +static DNNReturnType load_native_model(TFModel *tf_model, const char *model_filename) +{ + int32_t layer; + TF_OperationDescription *op_desc; + TF_Operation *op; + TF_Operation *transpose_op; + TF_Tensor *tensor; + TF_Output input; + int32_t *transpose_perm; + int64_t transpose_perm_shape[] = {4}; + int64_t input_shape[] = {1, -1, -1, -1}; + int32_t pad; + DNNReturnType layer_add_res; + DNNModel *native_model = NULL; + ConvolutionalNetwork *conv_network; + + native_model = ff_dnn_load_model_native(model_filename); + if (!native_model){ + return DNN_ERROR; + } + + conv_network = (ConvolutionalNetwork *)native_model->model; + pad = calculate_pad(conv_network); + tf_model->graph = TF_NewGraph(); + tf_model->status = TF_NewStatus(); + +#define CLEANUP_ON_ERROR(tf_model) \ + { \ + TF_DeleteGraph(tf_model->graph); \ + TF_DeleteStatus(tf_model->status); \ + return DNN_ERROR; \ + } + + op_desc = TF_NewOperation(tf_model->graph, "Placeholder", "x"); + TF_SetAttrType(op_desc, "dtype", TF_FLOAT); + TF_SetAttrShape(op_desc, "shape", input_shape, 4); + op = TF_FinishOperation(op_desc, tf_model->status); + if (TF_GetCode(tf_model->status) != TF_OK){ + CLEANUP_ON_ERROR(tf_model); + } + + if (add_pad_op(tf_model, &op, pad) != DNN_SUCCESS){ + CLEANUP_ON_ERROR(tf_model); + } + + op_desc = TF_NewOperation(tf_model->graph, "Const", "transpose_perm"); + TF_SetAttrType(op_desc, "dtype", TF_INT32); + tensor = TF_AllocateTensor(TF_INT32, transpose_perm_shape, 1, 4 * sizeof(int32_t)); + transpose_perm = (int32_t *)TF_TensorData(tensor); + transpose_perm[0] = 1; + transpose_perm[1] = 2; + transpose_perm[2] = 3; + transpose_perm[3] = 0; + TF_SetAttrTensor(op_desc, "value", tensor, tf_model->status); + if (TF_GetCode(tf_model->status) != TF_OK){ + CLEANUP_ON_ERROR(tf_model); + } + transpose_op = TF_FinishOperation(op_desc, tf_model->status); + + for (layer = 0; layer < conv_network->layers_num; ++layer){ + switch (conv_network->layers[layer].type){ + case INPUT: + layer_add_res = DNN_SUCCESS; + break; + case CONV: + layer_add_res = add_conv_layer(tf_model, transpose_op, &op, + (ConvolutionalParams *)conv_network->layers[layer].params, layer); + break; + case DEPTH_TO_SPACE: + layer_add_res = add_depth_to_space_layer(tf_model, &op, + (DepthToSpaceParams *)conv_network->layers[layer].params, layer); + break; + default: + CLEANUP_ON_ERROR(tf_model); + } + + if (layer_add_res != DNN_SUCCESS){ + CLEANUP_ON_ERROR(tf_model); + } + } + + op_desc = TF_NewOperation(tf_model->graph, "Identity", "y"); + input.oper = op; + TF_AddInput(op_desc, input); + TF_FinishOperation(op_desc, tf_model->status); + if (TF_GetCode(tf_model->status) != TF_OK){ + CLEANUP_ON_ERROR(tf_model); + } + + ff_dnn_free_model_native(&native_model); + + return DNN_SUCCESS; +} + +DNNModel *ff_dnn_load_model_tf(const char *model_filename) +{ + DNNModel *model = NULL; + TFModel *tf_model = NULL; + + model = av_malloc(sizeof(DNNModel)); + if (!model){ + return NULL; + } + + tf_model = av_mallocz(sizeof(TFModel)); + if (!tf_model){ + av_freep(&model); + return NULL; + } + + if (load_tf_model(tf_model, model_filename) != DNN_SUCCESS){ + if (load_native_model(tf_model, model_filename) != DNN_SUCCESS){ + av_freep(&tf_model); + av_freep(&model); + + return NULL; + } + } + + model->model = (void *)tf_model; + model->set_input_output = &set_input_output_tf; + + return model; +} + + + +DNNReturnType ff_dnn_execute_model_tf(const DNNModel *model, DNNData *outputs, uint32_t nb_output) +{ + TFModel *tf_model = (TFModel *)model->model; + uint32_t nb = FFMIN(nb_output, tf_model->nb_output); + if (nb == 0) + return DNN_ERROR; + + av_assert0(tf_model->output_tensors); + for (uint32_t i = 0; i < tf_model->nb_output; ++i) { + if (tf_model->output_tensors[i]) { + TF_DeleteTensor(tf_model->output_tensors[i]); + tf_model->output_tensors[i] = NULL; + } + } + + TF_SessionRun(tf_model->session, NULL, + &tf_model->input, &tf_model->input_tensor, 1, + tf_model->outputs, tf_model->output_tensors, nb, + NULL, 0, NULL, tf_model->status); + + if (TF_GetCode(tf_model->status) != TF_OK){ + return DNN_ERROR; + } + + for (uint32_t i = 0; i < nb; ++i) { + outputs[i].height = TF_Dim(tf_model->output_tensors[i], 1); + outputs[i].width = TF_Dim(tf_model->output_tensors[i], 2); + outputs[i].channels = TF_Dim(tf_model->output_tensors[i], 3); + outputs[i].data = TF_TensorData(tf_model->output_tensors[i]); + } + + return DNN_SUCCESS; +} + +void ff_dnn_free_model_tf(DNNModel **model) +{ + TFModel *tf_model; + + if (*model){ + tf_model = (TFModel *)(*model)->model; + if (tf_model->graph){ + TF_DeleteGraph(tf_model->graph); + } + if (tf_model->session){ + TF_CloseSession(tf_model->session, tf_model->status); + TF_DeleteSession(tf_model->session, tf_model->status); + } + if (tf_model->status){ + TF_DeleteStatus(tf_model->status); + } + if (tf_model->input_tensor){ + TF_DeleteTensor(tf_model->input_tensor); + } + if (tf_model->output_tensors) { + for (uint32_t i = 0; i < tf_model->nb_output; ++i) { + if (tf_model->output_tensors[i]) { + TF_DeleteTensor(tf_model->output_tensors[i]); + tf_model->output_tensors[i] = NULL; + } + } + } + av_freep(&tf_model->outputs); + av_freep(&tf_model->output_tensors); + av_freep(&tf_model); + av_freep(model); + } +} diff --git a/libavfilter/dnn_backend_tf.h b/libavfilter/dnn_backend_tf.h new file mode 100644 index 000000000..07877b120 --- /dev/null +++ b/libavfilter/dnn_backend_tf.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2018 Sergey Lavrushkin + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * DNN inference functions interface for TensorFlow backend. + */ + + +#ifndef AVFILTER_DNN_BACKEND_TF_H +#define AVFILTER_DNN_BACKEND_TF_H + +#include "dnn_interface.h" + +DNNModel *ff_dnn_load_model_tf(const char *model_filename); + +DNNReturnType ff_dnn_execute_model_tf(const DNNModel *model, DNNData *outputs, uint32_t nb_output); + +void ff_dnn_free_model_tf(DNNModel **model); + +#endif diff --git a/libavfilter/dnn_interface.c b/libavfilter/dnn_interface.c new file mode 100644 index 000000000..86fc28302 --- /dev/null +++ b/libavfilter/dnn_interface.c @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2018 Sergey Lavrushkin + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * Implements DNN module initialization with specified backend. + */ + +#include "dnn_interface.h" +#include "dnn_backend_native.h" +#include "dnn_backend_tf.h" +#include "libavutil/mem.h" + +DNNModule *ff_get_dnn_module(DNNBackendType backend_type) +{ + DNNModule *dnn_module; + + dnn_module = av_malloc(sizeof(DNNModule)); + if(!dnn_module){ + return NULL; + } + + switch(backend_type){ + case DNN_NATIVE: + dnn_module->load_model = &ff_dnn_load_model_native; + dnn_module->execute_model = &ff_dnn_execute_model_native; + dnn_module->free_model = &ff_dnn_free_model_native; + break; + case DNN_TF: + #if (CONFIG_LIBTENSORFLOW == 1) + dnn_module->load_model = &ff_dnn_load_model_tf; + dnn_module->execute_model = &ff_dnn_execute_model_tf; + dnn_module->free_model = &ff_dnn_free_model_tf; + #else + av_freep(&dnn_module); + return NULL; + #endif + break; + default: + av_log(NULL, AV_LOG_ERROR, "Module backend_type is not native or tensorflow\n"); + av_freep(&dnn_module); + return NULL; + } + + return dnn_module; +} diff --git a/libavfilter/dnn_interface.h b/libavfilter/dnn_interface.h new file mode 100644 index 000000000..c24df0e96 --- /dev/null +++ b/libavfilter/dnn_interface.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2018 Sergey Lavrushkin + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * DNN inference engine interface. + */ + +#ifndef AVFILTER_DNN_INTERFACE_H +#define AVFILTER_DNN_INTERFACE_H + +#include + +typedef enum {DNN_SUCCESS, DNN_ERROR} DNNReturnType; + +typedef enum {DNN_NATIVE, DNN_TF} DNNBackendType; + +typedef enum {DNN_FLOAT, DNN_UINT8} DNNDataType; + +typedef struct DNNInputData{ + void *data; + DNNDataType dt; + int width, height, channels; +} DNNInputData; + +typedef struct DNNData{ + float *data; + int width, height, channels; +} DNNData; + +typedef struct DNNModel{ + // Stores model that can be different for different backends. + void *model; + // Sets model input and output. + // Should be called at least once before model execution. + DNNReturnType (*set_input_output)(void *model, DNNInputData *input, const char *input_name, const char **output_names, uint32_t nb_output); +} DNNModel; + +// Stores pointers to functions for loading, executing, freeing DNN models for one of the backends. +typedef struct DNNModule{ + // Loads model and parameters from given file. Returns NULL if it is not possible. + DNNModel *(*load_model)(const char *model_filename); + // Executes model with specified input and output. Returns DNN_ERROR otherwise. + DNNReturnType (*execute_model)(const DNNModel *model, DNNData *outputs, uint32_t nb_output); + // Frees memory allocated for model. + void (*free_model)(DNNModel **model); +} DNNModule; + +// Initializes DNNModule depending on chosen backend. +DNNModule *ff_get_dnn_module(DNNBackendType backend_type); + +#endif diff --git a/libavfilter/drawutils.c b/libavfilter/drawutils.c index db8c7a622..5f4cb548f 100644 --- a/libavfilter/drawutils.c +++ b/libavfilter/drawutils.c @@ -181,6 +181,7 @@ int ff_draw_init(FFDrawContext *draw, enum AVPixelFormat format, unsigned flags) const AVComponentDescriptor *c; unsigned i, nb_planes = 0; int pixelstep[MAX_PLANES] = { 0 }; + int full_range = 0; if (!desc || !desc->name) return AVERROR(EINVAL); @@ -188,6 +189,9 @@ int ff_draw_init(FFDrawContext *draw, enum AVPixelFormat format, unsigned flags) return AVERROR(ENOSYS); if (format == AV_PIX_FMT_P010LE || format == AV_PIX_FMT_P010BE || format == AV_PIX_FMT_P016LE || format == AV_PIX_FMT_P016BE) return AVERROR(ENOSYS); + if (format == AV_PIX_FMT_YUVJ420P || format == AV_PIX_FMT_YUVJ422P || format == AV_PIX_FMT_YUVJ444P || + format == AV_PIX_FMT_YUVJ411P || format == AV_PIX_FMT_YUVJ440P) + full_range = 1; for (i = 0; i < desc->nb_components; i++) { c = &desc->comp[i]; /* for now, only 8-16 bits formats */ @@ -214,6 +218,7 @@ int ff_draw_init(FFDrawContext *draw, enum AVPixelFormat format, unsigned flags) draw->format = format; draw->nb_planes = nb_planes; draw->flags = flags; + draw->full_range = full_range; memcpy(draw->pixelstep, pixelstep, sizeof(draw->pixelstep)); draw->hsub[1] = draw->hsub[2] = draw->hsub_max = desc->log2_chroma_w; draw->vsub[1] = draw->vsub[2] = draw->vsub_max = desc->log2_chroma_h; @@ -249,9 +254,9 @@ void ff_draw_color(FFDrawContext *draw, FFDrawColor *color, const uint8_t rgba[4 } else if (draw->nb_planes >= 2) { /* assume YUV */ const AVPixFmtDescriptor *desc = draw->desc; - color->comp[desc->comp[0].plane].u8[desc->comp[0].offset] = RGB_TO_Y_CCIR(rgba[0], rgba[1], rgba[2]); - color->comp[desc->comp[1].plane].u8[desc->comp[1].offset] = RGB_TO_U_CCIR(rgba[0], rgba[1], rgba[2], 0); - color->comp[desc->comp[2].plane].u8[desc->comp[2].offset] = RGB_TO_V_CCIR(rgba[0], rgba[1], rgba[2], 0); + color->comp[desc->comp[0].plane].u8[desc->comp[0].offset] = draw->full_range ? RGB_TO_Y_JPEG(rgba[0], rgba[1], rgba[2]) : RGB_TO_Y_CCIR(rgba[0], rgba[1], rgba[2]); + color->comp[desc->comp[1].plane].u8[desc->comp[1].offset] = draw->full_range ? RGB_TO_U_JPEG(rgba[0], rgba[1], rgba[2]) : RGB_TO_U_CCIR(rgba[0], rgba[1], rgba[2], 0); + color->comp[desc->comp[2].plane].u8[desc->comp[2].offset] = draw->full_range ? RGB_TO_V_JPEG(rgba[0], rgba[1], rgba[2]) : RGB_TO_V_CCIR(rgba[0], rgba[1], rgba[2], 0); color->comp[3].u8[0] = rgba[3]; #define EXPAND(compn) \ if (desc->comp[compn].depth > 8) \ @@ -266,7 +271,8 @@ void ff_draw_color(FFDrawContext *draw, FFDrawColor *color, const uint8_t rgba[4 draw->format == AV_PIX_FMT_GRAY16LE || draw->format == AV_PIX_FMT_YA16LE || draw->format == AV_PIX_FMT_GRAY9LE || draw->format == AV_PIX_FMT_GRAY10LE || - draw->format == AV_PIX_FMT_GRAY12LE) { + draw->format == AV_PIX_FMT_GRAY12LE || + draw->format == AV_PIX_FMT_GRAY14LE) { const AVPixFmtDescriptor *desc = draw->desc; color->comp[0].u8[0] = RGB_TO_Y_CCIR(rgba[0], rgba[1], rgba[2]); EXPAND(0); diff --git a/libavfilter/drawutils.h b/libavfilter/drawutils.h index cf5363545..b999d70e5 100644 --- a/libavfilter/drawutils.h +++ b/libavfilter/drawutils.h @@ -55,6 +55,7 @@ typedef struct FFDrawContext { uint8_t vsub[MAX_PLANES]; /*< vertical subsampling */ uint8_t hsub_max; uint8_t vsub_max; + int full_range; unsigned flags; } FFDrawContext; diff --git a/libavfilter/ebur128.c b/libavfilter/ebur128.c index e11008078..c8986fb5e 100644 --- a/libavfilter/ebur128.c +++ b/libavfilter/ebur128.c @@ -368,7 +368,7 @@ EBUR128_FILTER(double, 1.0) static double ebur128_energy_to_loudness(double energy) { - return 10 * (log(energy) / log(10.0)) - 0.691; + return 10 * log10(energy) - 0.691; } static size_t find_histogram_index(double energy) diff --git a/libavfilter/f_cue.c b/libavfilter/f_cue.c new file mode 100644 index 000000000..b48dfc9d4 --- /dev/null +++ b/libavfilter/f_cue.c @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2018 Marton Balint + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with FFmpeg; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/opt.h" +#include "libavutil/time.h" +#include "avfilter.h" +#include "filters.h" +#include "internal.h" + +typedef struct CueContext { + const AVClass *class; + int64_t first_pts; + int64_t cue; + int64_t preroll; + int64_t buffer; + int status; +} CueContext; + +static int activate(AVFilterContext *ctx) +{ + AVFilterLink *inlink = ctx->inputs[0]; + AVFilterLink *outlink = ctx->outputs[0]; + CueContext *s = ctx->priv; + + FF_FILTER_FORWARD_STATUS_BACK(outlink, inlink); + + if (ff_inlink_queued_frames(inlink)) { + AVFrame *frame = ff_inlink_peek_frame(inlink, 0); + int64_t pts = av_rescale_q(frame->pts, inlink->time_base, AV_TIME_BASE_Q); + + if (!s->status) { + s->first_pts = pts; + s->status++; + } + if (s->status == 1) { + if (pts - s->first_pts < s->preroll) { + int ret = ff_inlink_consume_frame(inlink, &frame); + if (ret < 0) + return ret; + return ff_filter_frame(outlink, frame); + } + s->first_pts = pts; + s->status++; + } + if (s->status == 2) { + frame = ff_inlink_peek_frame(inlink, ff_inlink_queued_frames(inlink) - 1); + pts = av_rescale_q(frame->pts, inlink->time_base, AV_TIME_BASE_Q); + if (!(pts - s->first_pts < s->buffer && (av_gettime() - s->cue) < 0)) + s->status++; + } + if (s->status == 3) { + int64_t diff; + while ((diff = (av_gettime() - s->cue)) < 0) + av_usleep(av_clip(-diff / 2, 100, 1000000)); + s->status++; + } + if (s->status == 4) { + int ret = ff_inlink_consume_frame(inlink, &frame); + if (ret < 0) + return ret; + return ff_filter_frame(outlink, frame); + } + } + + FF_FILTER_FORWARD_STATUS(inlink, outlink); + FF_FILTER_FORWARD_WANTED(outlink, inlink); + + return FFERROR_NOT_READY; +} + +#define OFFSET(x) offsetof(CueContext, x) +#define FLAGS AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_FILTERING_PARAM +static const AVOption options[] = { + { "cue", "cue unix timestamp in microseconds", OFFSET(cue), AV_OPT_TYPE_INT64, { .i64 = 0 }, 0, INT64_MAX, FLAGS }, + { "preroll", "preroll duration in seconds", OFFSET(preroll), AV_OPT_TYPE_DURATION, { .i64 = 0 }, 0, INT64_MAX, FLAGS }, + { "buffer", "buffer duration in seconds", OFFSET(buffer), AV_OPT_TYPE_DURATION, { .i64 = 0 }, 0, INT64_MAX, FLAGS }, + { NULL } +}; + +#if CONFIG_CUE_FILTER +#define cue_options options +AVFILTER_DEFINE_CLASS(cue); + +static const AVFilterPad cue_inputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + }, + { NULL } +}; + +static const AVFilterPad cue_outputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + }, + { NULL } +}; + +AVFilter ff_vf_cue = { + .name = "cue", + .description = NULL_IF_CONFIG_SMALL("Delay filtering to match a cue."), + .priv_size = sizeof(CueContext), + .priv_class = &cue_class, + .inputs = cue_inputs, + .outputs = cue_outputs, + .activate = activate, +}; +#endif /* CONFIG_CUE_FILTER */ + +#if CONFIG_ACUE_FILTER +#define acue_options options +AVFILTER_DEFINE_CLASS(acue); + +static const AVFilterPad acue_inputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_AUDIO, + }, + { NULL } +}; + +static const AVFilterPad acue_outputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_AUDIO, + }, + { NULL } +}; + +AVFilter ff_af_acue = { + .name = "acue", + .description = NULL_IF_CONFIG_SMALL("Delay filtering to match a cue."), + .priv_size = sizeof(CueContext), + .priv_class = &acue_class, + .inputs = acue_inputs, + .outputs = acue_outputs, + .activate = activate, +}; +#endif /* CONFIG_ACUE_FILTER */ diff --git a/libavfilter/f_drawgraph.c b/libavfilter/f_drawgraph.c index 8be9b9f95..955047368 100644 --- a/libavfilter/f_drawgraph.c +++ b/libavfilter/f_drawgraph.c @@ -20,6 +20,7 @@ #include "float.h" +#include "libavutil/avstring.h" #include "libavutil/eval.h" #include "libavutil/intreadwrite.h" #include "libavutil/opt.h" @@ -43,7 +44,7 @@ typedef struct DrawGraphContext { AVFrame *out; int x; int prev_y[4]; - int first; + int first[4]; float *values[4]; int values_size[4]; int nb_values; @@ -102,7 +103,7 @@ static av_cold int init(AVFilterContext *ctx) } } - s->first = 1; + s->first[0] = s->first[1] = s->first[2] = s->first[3] = 1; if (s->slide == 4) { s->values[0] = av_fast_realloc(NULL, &s->values_size[0], 2000); @@ -215,7 +216,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) if (!e || !e->value) continue; - if (sscanf(e->value, "%f", &vf) != 1) + if (av_sscanf(e->value, "%f", &vf) != 1) continue; vf = av_clipf(vf, s->min, s->max); @@ -282,8 +283,8 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) draw_dot(fg, x, y, out); break; case 2: - if (s->first) { - s->first = 0; + if (s->first[i]) { + s->first[i] = 0; s->prev_y[i] = y; } @@ -366,8 +367,8 @@ static int request_frame(AVFilterLink *outlink) draw_dot(fg, x, y, out); break; case 2: - if (s->first) { - s->first = 0; + if (s->first[i]) { + s->first[i] = 0; s->prev_y[i] = y; } diff --git a/libavfilter/f_ebur128.c b/libavfilter/f_ebur128.c index 1e8b90fa2..f25d5f096 100644 --- a/libavfilter/f_ebur128.c +++ b/libavfilter/f_ebur128.c @@ -114,6 +114,8 @@ typedef struct EBUR128Context { int meter; ///< select a EBU mode between +9 and +18 int scale_range; ///< the range of LU values according to the meter int y_zero_lu; ///< the y value (pixel position) for 0 LU + int y_opt_max; ///< the y value (pixel position) for 1 LU + int y_opt_min; ///< the y value (pixel position) for -1 LU int *y_line_ref; ///< y reference values for drawing the LU lines in the graph and the gauge /* audio */ @@ -142,6 +144,9 @@ typedef struct EBUR128Context { int metadata; ///< whether or not to inject loudness results in frames int dual_mono; ///< whether or not to treat single channel input files as dual-mono double pan_law; ///< pan law value used to calculate dual-mono measurements + int target; ///< target level in LUFS used to set relative zero LU in visualization + int gauge_type; ///< whether gauge shows momentary or short + int scale; ///< display scale type of statistics } EBUR128Context; enum { @@ -150,6 +155,16 @@ enum { PEAK_MODE_TRUE_PEAKS = 1<<2, }; +enum { + GAUGE_TYPE_MOMENTARY = 0, + GAUGE_TYPE_SHORTTERM = 1, +}; + +enum { + SCALE_TYPE_ABSOLUTE = 0, + SCALE_TYPE_RELATIVE = 1, +}; + #define OFFSET(x) offsetof(EBUR128Context, x) #define A AV_OPT_FLAG_AUDIO_PARAM #define V AV_OPT_FLAG_VIDEO_PARAM @@ -168,28 +183,48 @@ static const AVOption ebur128_options[] = { { "true", "enable true-peak mode", 0, AV_OPT_TYPE_CONST, {.i64 = PEAK_MODE_TRUE_PEAKS}, INT_MIN, INT_MAX, A|F, "mode" }, { "dualmono", "treat mono input files as dual-mono", OFFSET(dual_mono), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, A|F }, { "panlaw", "set a specific pan law for dual-mono files", OFFSET(pan_law), AV_OPT_TYPE_DOUBLE, {.dbl = -3.01029995663978}, -10.0, 0.0, A|F }, + { "target", "set a specific target level in LUFS (-23 to 0)", OFFSET(target), AV_OPT_TYPE_INT, {.i64 = -23}, -23, 0, V|F }, + { "gauge", "set gauge display type", OFFSET(gauge_type), AV_OPT_TYPE_INT, {.i64 = 0 }, GAUGE_TYPE_MOMENTARY, GAUGE_TYPE_SHORTTERM, V|F, "gaugetype" }, + { "momentary", "display momentary value", 0, AV_OPT_TYPE_CONST, {.i64 = GAUGE_TYPE_MOMENTARY}, INT_MIN, INT_MAX, V|F, "gaugetype" }, + { "m", "display momentary value", 0, AV_OPT_TYPE_CONST, {.i64 = GAUGE_TYPE_MOMENTARY}, INT_MIN, INT_MAX, V|F, "gaugetype" }, + { "shortterm", "display short-term value", 0, AV_OPT_TYPE_CONST, {.i64 = GAUGE_TYPE_SHORTTERM}, INT_MIN, INT_MAX, V|F, "gaugetype" }, + { "s", "display short-term value", 0, AV_OPT_TYPE_CONST, {.i64 = GAUGE_TYPE_SHORTTERM}, INT_MIN, INT_MAX, V|F, "gaugetype" }, + { "scale", "sets display method for the stats", OFFSET(scale), AV_OPT_TYPE_INT, {.i64 = 0}, SCALE_TYPE_ABSOLUTE, SCALE_TYPE_RELATIVE, V|F, "scaletype" }, + { "absolute", "display absolute values (LUFS)", 0, AV_OPT_TYPE_CONST, {.i64 = SCALE_TYPE_ABSOLUTE}, INT_MIN, INT_MAX, V|F, "scaletype" }, + { "LUFS", "display absolute values (LUFS)", 0, AV_OPT_TYPE_CONST, {.i64 = SCALE_TYPE_ABSOLUTE}, INT_MIN, INT_MAX, V|F, "scaletype" }, + { "relative", "display values relative to target (LU)", 0, AV_OPT_TYPE_CONST, {.i64 = SCALE_TYPE_RELATIVE}, INT_MIN, INT_MAX, V|F, "scaletype" }, + { "LU", "display values relative to target (LU)", 0, AV_OPT_TYPE_CONST, {.i64 = SCALE_TYPE_RELATIVE}, INT_MIN, INT_MAX, V|F, "scaletype" }, { NULL }, }; AVFILTER_DEFINE_CLASS(ebur128); static const uint8_t graph_colors[] = { - 0xdd, 0x66, 0x66, // value above 0LU non reached - 0x66, 0x66, 0xdd, // value below 0LU non reached - 0x96, 0x33, 0x33, // value above 0LU reached - 0x33, 0x33, 0x96, // value below 0LU reached - 0xdd, 0x96, 0x96, // value above 0LU line non reached - 0x96, 0x96, 0xdd, // value below 0LU line non reached - 0xdd, 0x33, 0x33, // value above 0LU line reached - 0x33, 0x33, 0xdd, // value below 0LU line reached + 0xdd, 0x66, 0x66, // value above 1LU non reached below -1LU (impossible) + 0x66, 0x66, 0xdd, // value below 1LU non reached below -1LU + 0x96, 0x33, 0x33, // value above 1LU reached below -1LU (impossible) + 0x33, 0x33, 0x96, // value below 1LU reached below -1LU + 0xdd, 0x96, 0x96, // value above 1LU line non reached below -1LU (impossible) + 0x96, 0x96, 0xdd, // value below 1LU line non reached below -1LU + 0xdd, 0x33, 0x33, // value above 1LU line reached below -1LU (impossible) + 0x33, 0x33, 0xdd, // value below 1LU line reached below -1LU + 0xdd, 0x66, 0x66, // value above 1LU non reached above -1LU + 0x66, 0xdd, 0x66, // value below 1LU non reached above -1LU + 0x96, 0x33, 0x33, // value above 1LU reached above -1LU + 0x33, 0x96, 0x33, // value below 1LU reached above -1LU + 0xdd, 0x96, 0x96, // value above 1LU line non reached above -1LU + 0x96, 0xdd, 0x96, // value below 1LU line non reached above -1LU + 0xdd, 0x33, 0x33, // value above 1LU line reached above -1LU + 0x33, 0xdd, 0x33, // value below 1LU line reached above -1LU }; static const uint8_t *get_graph_color(const EBUR128Context *ebur128, int v, int y) { - const int below0 = y > ebur128->y_zero_lu; + const int above_opt_max = y > ebur128->y_opt_max; + const int below_opt_min = y < ebur128->y_opt_min; const int reached = y >= v; const int line = ebur128->y_line_ref[y] || y == ebur128->y_zero_lu; - const int colorid = 4*line + 2*reached + below0; + const int colorid = 8*below_opt_min+ 4*line + 2*reached + above_opt_max; return graph_colors + 3*colorid; } @@ -323,6 +358,8 @@ static int config_video_output(AVFilterLink *outlink) /* draw graph */ ebur128->y_zero_lu = lu_to_y(ebur128, 0); + ebur128->y_opt_max = lu_to_y(ebur128, 1); + ebur128->y_opt_min = lu_to_y(ebur128, -1); p = outpicref->data[0] + ebur128->graph.y * outpicref->linesize[0] + ebur128->graph.x * 3; for (y = 0; y < ebur128->graph.h; y++) { @@ -383,7 +420,7 @@ static int config_audio_output(AVFilterLink *outlink) for (i = 0; i < nb_channels; i++) { /* channel weighting */ - const uint16_t chl = av_channel_layout_extract_channel(outlink->channel_layout, i); + const uint64_t chl = av_channel_layout_extract_channel(outlink->channel_layout, i); if (chl & (AV_CH_LOW_FREQUENCY|AV_CH_LOW_FREQUENCY_2)) { ebur128->ch_weighting[i] = 0; } else if (chl & BACK_MASK) { @@ -459,6 +496,7 @@ static av_cold int init(AVFilterContext *ctx) { EBUR128Context *ebur128 = ctx->priv; AVFilterPad pad; + int ret; if (ebur128->loglevel != AV_LOG_INFO && ebur128->loglevel != AV_LOG_VERBOSE) { @@ -495,7 +533,11 @@ static av_cold int init(AVFilterContext *ctx) }; if (!pad.name) return AVERROR(ENOMEM); - ff_insert_outpad(ctx, 0, &pad); + ret = ff_insert_outpad(ctx, 0, &pad); + if (ret < 0) { + av_freep(&pad.name); + return ret; + } } pad = (AVFilterPad){ .name = av_asprintf("out%d", ebur128->do_video), @@ -504,7 +546,11 @@ static av_cold int init(AVFilterContext *ctx) }; if (!pad.name) return AVERROR(ENOMEM); - ff_insert_outpad(ctx, ebur128->do_video, &pad); + ret = ff_insert_outpad(ctx, ebur128->do_video, &pad); + if (ret < 0) { + av_freep(&pad.name); + return ret; + } /* summary */ av_log(ctx, AV_LOG_VERBOSE, "EBU +%d scale\n", ebur128->meter); @@ -724,15 +770,23 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *insamples) loudness_3000 -= ebur128->pan_law; } -#define LOG_FMT "M:%6.1f S:%6.1f I:%6.1f LUFS LRA:%6.1f LU" +#define LOG_FMT "TARGET:%d LUFS M:%6.1f S:%6.1f I:%6.1f %s LRA:%6.1f LU" /* push one video frame */ if (ebur128->do_video) { int x, y, ret; uint8_t *p; + double gauge_value; + int y_loudness_lu_graph, y_loudness_lu_gauge; - const int y_loudness_lu_graph = lu_to_y(ebur128, loudness_3000 + 23); - const int y_loudness_lu_gauge = lu_to_y(ebur128, loudness_400 + 23); + if (ebur128->gauge_type == GAUGE_TYPE_MOMENTARY) { + gauge_value = loudness_400 - ebur128->target; + } else { + gauge_value = loudness_3000 - ebur128->target; + } + + y_loudness_lu_graph = lu_to_y(ebur128, loudness_3000 - ebur128->target); + y_loudness_lu_gauge = lu_to_y(ebur128, gauge_value); /* draw the graph using the short-term loudness */ p = pic->data[0] + ebur128->graph.y*pic->linesize[0] + ebur128->graph.x*3; @@ -744,7 +798,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *insamples) p += pic->linesize[0]; } - /* draw the gauge using the momentary loudness */ + /* draw the gauge using either momentary or short-term loudness */ p = pic->data[0] + ebur128->gauge.y*pic->linesize[0] + ebur128->gauge.x*3; for (y = 0; y < ebur128->gauge.h; y++) { const uint8_t *c = get_graph_color(ebur128, y_loudness_lu_gauge, y); @@ -755,10 +809,17 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *insamples) } /* draw textual info */ - drawtext(pic, PAD, PAD - PAD/2, FONT16, font_colors, - LOG_FMT " ", // padding to erase trailing characters - loudness_400, loudness_3000, - ebur128->integrated_loudness, ebur128->loudness_range); + if (ebur128->scale == SCALE_TYPE_ABSOLUTE) { + drawtext(pic, PAD, PAD - PAD/2, FONT16, font_colors, + LOG_FMT " ", // padding to erase trailing characters + ebur128->target, loudness_400, loudness_3000, + ebur128->integrated_loudness, "LUFS", ebur128->loudness_range); + } else { + drawtext(pic, PAD, PAD - PAD/2, FONT16, font_colors, + LOG_FMT " ", // padding to erase trailing characters + ebur128->target, loudness_400-ebur128->target, loudness_3000-ebur128->target, + ebur128->integrated_loudness-ebur128->target, "LU", ebur128->loudness_range); + } /* set pts and push frame */ pic->pts = pts; @@ -798,10 +859,17 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *insamples) SET_META_PEAK(true, TRUE); } - av_log(ctx, ebur128->loglevel, "t: %-10s " LOG_FMT, - av_ts2timestr(pts, &outlink->time_base), - loudness_400, loudness_3000, - ebur128->integrated_loudness, ebur128->loudness_range); + if (ebur128->scale == SCALE_TYPE_ABSOLUTE) { + av_log(ctx, ebur128->loglevel, "t: %-10s " LOG_FMT, + av_ts2timestr(pts, &outlink->time_base), + ebur128->target, loudness_400, loudness_3000, + ebur128->integrated_loudness, "LUFS", ebur128->loudness_range); + } else { + av_log(ctx, ebur128->loglevel, "t: %-10s " LOG_FMT, + av_ts2timestr(pts, &outlink->time_base), + ebur128->target, loudness_400-ebur128->target, loudness_3000-ebur128->target, + ebur128->integrated_loudness-ebur128->target, "LU", ebur128->loudness_range); + } #define PRINT_PEAKS(str, sp, ptype) do { \ if (ebur128->peak_mode & PEAK_MODE_ ## ptype ## _PEAKS) { \ diff --git a/libavfilter/f_graphmonitor.c b/libavfilter/f_graphmonitor.c new file mode 100644 index 000000000..c00183536 --- /dev/null +++ b/libavfilter/f_graphmonitor.c @@ -0,0 +1,425 @@ +/* + * Copyright (c) 2018 Paul B Mahol + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "float.h" + +#include "libavutil/pixdesc.h" +#include "libavutil/eval.h" +#include "libavutil/intreadwrite.h" +#include "libavutil/opt.h" +#include "libavutil/timestamp.h" +#include "libavutil/xga_font_data.h" +#include "avfilter.h" +#include "filters.h" +#include "formats.h" +#include "internal.h" +#include "video.h" + +typedef struct GraphMonitorContext { + const AVClass *class; + + int w, h; + float opacity; + int mode; + int flags; + AVRational frame_rate; + + int64_t pts; + uint8_t white[4]; + uint8_t yellow[4]; + uint8_t red[4]; + uint8_t green[4]; + uint8_t bg[4]; +} GraphMonitorContext; + +enum { + MODE_QUEUE = 1 << 0, + MODE_FCIN = 1 << 1, + MODE_FCOUT = 1 << 2, + MODE_PTS = 1 << 3, + MODE_TIME = 1 << 4, + MODE_TB = 1 << 5, + MODE_FMT = 1 << 6, + MODE_SIZE = 1 << 7, + MODE_RATE = 1 << 8, +}; + +#define OFFSET(x) offsetof(GraphMonitorContext, x) +#define VF AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM + +static const AVOption graphmonitor_options[] = { + { "size", "set monitor size", OFFSET(w), AV_OPT_TYPE_IMAGE_SIZE, {.str="hd720"}, 0, 0, VF }, + { "s", "set monitor size", OFFSET(w), AV_OPT_TYPE_IMAGE_SIZE, {.str="hd720"}, 0, 0, VF }, + { "opacity", "set video opacity", OFFSET(opacity), AV_OPT_TYPE_FLOAT, {.dbl=.9}, 0, 1, VF }, + { "o", "set video opacity", OFFSET(opacity), AV_OPT_TYPE_FLOAT, {.dbl=.9}, 0, 1, VF }, + { "mode", "set mode", OFFSET(mode), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, VF, "mode" }, + { "m", "set mode", OFFSET(mode), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, VF, "mode" }, + { "full", NULL, 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, VF, "mode" }, + { "compact", NULL, 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, VF, "mode" }, + { "flags", "set flags", OFFSET(flags), AV_OPT_TYPE_FLAGS, {.i64=MODE_QUEUE}, 0, INT_MAX, VF, "flags" }, + { "f", "set flags", OFFSET(flags), AV_OPT_TYPE_FLAGS, {.i64=MODE_QUEUE}, 0, INT_MAX, VF, "flags" }, + { "queue", NULL, 0, AV_OPT_TYPE_CONST, {.i64=MODE_QUEUE}, 0, 0, VF, "flags" }, + { "frame_count_in", NULL, 0, AV_OPT_TYPE_CONST, {.i64=MODE_FCOUT}, 0, 0, VF, "flags" }, + { "frame_count_out", NULL, 0, AV_OPT_TYPE_CONST, {.i64=MODE_FCIN}, 0, 0, VF, "flags" }, + { "pts", NULL, 0, AV_OPT_TYPE_CONST, {.i64=MODE_PTS}, 0, 0, VF, "flags" }, + { "time", NULL, 0, AV_OPT_TYPE_CONST, {.i64=MODE_TIME}, 0, 0, VF, "flags" }, + { "timebase", NULL, 0, AV_OPT_TYPE_CONST, {.i64=MODE_TB}, 0, 0, VF, "flags" }, + { "format", NULL, 0, AV_OPT_TYPE_CONST, {.i64=MODE_FMT}, 0, 0, VF, "flags" }, + { "size", NULL, 0, AV_OPT_TYPE_CONST, {.i64=MODE_SIZE}, 0, 0, VF, "flags" }, + { "rate", NULL, 0, AV_OPT_TYPE_CONST, {.i64=MODE_RATE}, 0, 0, VF, "flags" }, + { "rate", "set video rate", OFFSET(frame_rate), AV_OPT_TYPE_VIDEO_RATE, {.str = "25"}, 0, INT_MAX, VF }, + { "r", "set video rate", OFFSET(frame_rate), AV_OPT_TYPE_VIDEO_RATE, {.str = "25"}, 0, INT_MAX, VF }, + { NULL } +}; + +static int query_formats(AVFilterContext *ctx) +{ + AVFilterLink *outlink = ctx->outputs[0]; + static const enum AVPixelFormat pix_fmts[] = { + AV_PIX_FMT_RGBA, + AV_PIX_FMT_NONE + }; + int ret; + + AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts); + if ((ret = ff_formats_ref(fmts_list, &outlink->in_formats)) < 0) + return ret; + + return 0; +} + +static void clear_image(GraphMonitorContext *s, AVFrame *out, AVFilterLink *outlink) +{ + int bg = AV_RN32(s->bg); + + for (int i = 0; i < out->height; i++) + for (int j = 0; j < out->width; j++) + AV_WN32(out->data[0] + i * out->linesize[0] + j * 4, bg); +} + +static void drawtext(AVFrame *pic, int x, int y, const char *txt, uint8_t *color) +{ + const uint8_t *font; + int font_height; + int i; + + font = avpriv_cga_font, font_height = 8; + + if (y + 8 >= pic->height || + x + strlen(txt) * 8 >= pic->width) + return; + + for (i = 0; txt[i]; i++) { + int char_y, mask; + + uint8_t *p = pic->data[0] + y*pic->linesize[0] + (x + i*8)*4; + for (char_y = 0; char_y < font_height; char_y++) { + for (mask = 0x80; mask; mask >>= 1) { + if (font[txt[i] * font_height + char_y] & mask) { + p[0] = color[0]; + p[1] = color[1]; + p[2] = color[2]; + } + p += 4; + } + p += pic->linesize[0] - 8 * 4; + } + } +} + +static int filter_have_queued(AVFilterContext *filter) +{ + for (int j = 0; j < filter->nb_inputs; j++) { + AVFilterLink *l = filter->inputs[j]; + size_t frames = ff_inlink_queued_frames(l); + + if (frames) + return 1; + } + + for (int j = 0; j < filter->nb_outputs; j++) { + AVFilterLink *l = filter->outputs[j]; + size_t frames = ff_inlink_queued_frames(l); + + if (frames) + return 1; + } + + return 0; +} + +static void draw_items(AVFilterContext *ctx, AVFrame *out, + int xpos, int ypos, + AVFilterLink *l, + size_t frames) +{ + GraphMonitorContext *s = ctx->priv; + char buffer[1024] = { 0 }; + + if (s->flags & MODE_FMT) { + if (l->type == AVMEDIA_TYPE_VIDEO) { + snprintf(buffer, sizeof(buffer)-1, " | format: %s", + av_get_pix_fmt_name(l->format)); + } else if (l->type == AVMEDIA_TYPE_AUDIO) { + snprintf(buffer, sizeof(buffer)-1, " | format: %s", + av_get_sample_fmt_name(l->format)); + } + drawtext(out, xpos, ypos, buffer, s->white); + xpos += strlen(buffer) * 8; + } + if (s->flags & MODE_SIZE) { + if (l->type == AVMEDIA_TYPE_VIDEO) { + snprintf(buffer, sizeof(buffer)-1, " | size: %dx%d", l->w, l->h); + } else if (l->type == AVMEDIA_TYPE_AUDIO) { + snprintf(buffer, sizeof(buffer)-1, " | channels: %d", l->channels); + } + drawtext(out, xpos, ypos, buffer, s->white); + xpos += strlen(buffer) * 8; + } + if (s->flags & MODE_RATE) { + if (l->type == AVMEDIA_TYPE_VIDEO) { + snprintf(buffer, sizeof(buffer)-1, " | fps: %d/%d", l->frame_rate.num, l->frame_rate.den); + } else if (l->type == AVMEDIA_TYPE_AUDIO) { + snprintf(buffer, sizeof(buffer)-1, " | samplerate: %d", l->sample_rate); + } + drawtext(out, xpos, ypos, buffer, s->white); + xpos += strlen(buffer) * 8; + } + if (s->flags & MODE_TB) { + snprintf(buffer, sizeof(buffer)-1, " | tb: %d/%d", l->time_base.num, l->time_base.den); + drawtext(out, xpos, ypos, buffer, s->white); + xpos += strlen(buffer) * 8; + } + if (s->flags & MODE_QUEUE) { + snprintf(buffer, sizeof(buffer)-1, " | queue: "); + drawtext(out, xpos, ypos, buffer, s->white); + xpos += strlen(buffer) * 8; + snprintf(buffer, sizeof(buffer)-1, "%"SIZE_SPECIFIER, frames); + drawtext(out, xpos, ypos, buffer, frames > 0 ? frames >= 10 ? frames >= 50 ? s->red : s->yellow : s->green : s->white); + xpos += strlen(buffer) * 8; + } + if (s->flags & MODE_FCIN) { + snprintf(buffer, sizeof(buffer)-1, " | in: %"PRId64, l->frame_count_in); + drawtext(out, xpos, ypos, buffer, s->white); + xpos += strlen(buffer) * 8; + } + if (s->flags & MODE_FCOUT) { + snprintf(buffer, sizeof(buffer)-1, " | out: %"PRId64, l->frame_count_out); + drawtext(out, xpos, ypos, buffer, s->white); + xpos += strlen(buffer) * 8; + } + if (s->flags & MODE_PTS) { + snprintf(buffer, sizeof(buffer)-1, " | pts: %s", av_ts2str(l->current_pts_us)); + drawtext(out, xpos, ypos, buffer, s->white); + xpos += strlen(buffer) * 8; + } + if (s->flags & MODE_TIME) { + snprintf(buffer, sizeof(buffer)-1, " | time: %s", av_ts2timestr(l->current_pts_us, &AV_TIME_BASE_Q)); + drawtext(out, xpos, ypos, buffer, s->white); + xpos += strlen(buffer) * 8; + } +} + +static int create_frame(AVFilterContext *ctx, int64_t pts) +{ + GraphMonitorContext *s = ctx->priv; + AVFilterLink *outlink = ctx->outputs[0]; + AVFrame *out; + int xpos, ypos = 0; + + out = ff_get_video_buffer(outlink, outlink->w, outlink->h); + if (!out) + return AVERROR(ENOMEM); + + clear_image(s, out, outlink); + + for (int i = 0; i < ctx->graph->nb_filters; i++) { + AVFilterContext *filter = ctx->graph->filters[i]; + char buffer[1024] = { 0 }; + + if (s->mode && !filter_have_queued(filter)) + continue; + + xpos = 0; + drawtext(out, xpos, ypos, filter->name, s->white); + xpos += strlen(filter->name) * 8 + 10; + drawtext(out, xpos, ypos, filter->filter->name, s->white); + ypos += 10; + for (int j = 0; j < filter->nb_inputs; j++) { + AVFilterLink *l = filter->inputs[j]; + size_t frames = ff_inlink_queued_frames(l); + + if (s->mode && !frames) + continue; + + xpos = 10; + snprintf(buffer, sizeof(buffer)-1, "in%d: ", j); + drawtext(out, xpos, ypos, buffer, s->white); + xpos += strlen(buffer) * 8; + drawtext(out, xpos, ypos, l->src->name, s->white); + xpos += strlen(l->src->name) * 8 + 10; + draw_items(ctx, out, xpos, ypos, l, frames); + ypos += 10; + } + + ypos += 2; + for (int j = 0; j < filter->nb_outputs; j++) { + AVFilterLink *l = filter->outputs[j]; + size_t frames = ff_inlink_queued_frames(l); + + if (s->mode && !frames) + continue; + + xpos = 10; + snprintf(buffer, sizeof(buffer)-1, "out%d: ", j); + drawtext(out, xpos, ypos, buffer, s->white); + xpos += strlen(buffer) * 8; + drawtext(out, xpos, ypos, l->dst->name, s->white); + xpos += strlen(l->dst->name) * 8 + 10; + draw_items(ctx, out, xpos, ypos, l, frames); + ypos += 10; + } + ypos += 5; + } + + out->pts = pts; + s->pts = pts; + return ff_filter_frame(outlink, out); +} + +static int activate(AVFilterContext *ctx) +{ + GraphMonitorContext *s = ctx->priv; + AVFilterLink *inlink = ctx->inputs[0]; + AVFilterLink *outlink = ctx->outputs[0]; + int64_t pts = AV_NOPTS_VALUE; + + FF_FILTER_FORWARD_STATUS_BACK(outlink, inlink); + + if (ff_inlink_queued_frames(inlink)) { + AVFrame *frame = NULL; + int ret; + + ret = ff_inlink_consume_frame(inlink, &frame); + if (ret < 0) + return ret; + if (ret > 0) { + pts = frame->pts; + av_frame_free(&frame); + } + } + + if (pts != AV_NOPTS_VALUE) { + pts = av_rescale_q(pts, inlink->time_base, outlink->time_base); + if (s->pts < pts && ff_outlink_frame_wanted(outlink)) + return create_frame(ctx, pts); + } + + FF_FILTER_FORWARD_STATUS(inlink, outlink); + FF_FILTER_FORWARD_WANTED(outlink, inlink); + + return FFERROR_NOT_READY; +} + +static int config_output(AVFilterLink *outlink) +{ + GraphMonitorContext *s = outlink->src->priv; + + s->bg[3] = 255 * s->opacity; + s->white[0] = s->white[1] = s->white[2] = 255; + s->yellow[0] = s->yellow[1] = 255; + s->red[0] = 255; + s->green[1] = 255; + outlink->w = s->w; + outlink->h = s->h; + outlink->sample_aspect_ratio = (AVRational){1,1}; + outlink->frame_rate = s->frame_rate; + outlink->time_base = av_inv_q(s->frame_rate); + + return 0; +} + +#if CONFIG_GRAPHMONITOR_FILTER + +AVFILTER_DEFINE_CLASS(graphmonitor); + +static const AVFilterPad graphmonitor_inputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + }, + { NULL } +}; + +static const AVFilterPad graphmonitor_outputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + .config_props = config_output, + }, + { NULL } +}; + +AVFilter ff_vf_graphmonitor = { + .name = "graphmonitor", + .description = NULL_IF_CONFIG_SMALL("Show various filtergraph stats."), + .priv_size = sizeof(GraphMonitorContext), + .priv_class = &graphmonitor_class, + .query_formats = query_formats, + .activate = activate, + .inputs = graphmonitor_inputs, + .outputs = graphmonitor_outputs, +}; + +#endif // CONFIG_GRAPHMONITOR_FILTER + +#if CONFIG_AGRAPHMONITOR_FILTER + +#define agraphmonitor_options graphmonitor_options +AVFILTER_DEFINE_CLASS(agraphmonitor); + +static const AVFilterPad agraphmonitor_inputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_AUDIO, + }, + { NULL } +}; + +static const AVFilterPad agraphmonitor_outputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + .config_props = config_output, + }, + { NULL } +}; + +AVFilter ff_avf_agraphmonitor = { + .name = "agraphmonitor", + .description = NULL_IF_CONFIG_SMALL("Show various filtergraph stats."), + .priv_size = sizeof(GraphMonitorContext), + .priv_class = &agraphmonitor_class, + .query_formats = query_formats, + .activate = activate, + .inputs = agraphmonitor_inputs, + .outputs = agraphmonitor_outputs, +}; +#endif // CONFIG_AGRAPHMONITOR_FILTER diff --git a/libavfilter/f_interleave.c b/libavfilter/f_interleave.c index d8a73b52e..06f4cda79 100644 --- a/libavfilter/f_interleave.c +++ b/libavfilter/f_interleave.c @@ -27,12 +27,9 @@ #include "libavutil/avstring.h" #include "libavutil/opt.h" -#define FF_INTERNAL_FIELDS 1 -#include "framequeue.h" - #include "avfilter.h" -#include "bufferqueue.h" #include "formats.h" +#include "filters.h" #include "internal.h" #include "audio.h" #include "video.h" @@ -40,7 +37,7 @@ typedef struct InterleaveContext { const AVClass *class; int nb_inputs; - struct FFBufQueue *queues; + int64_t pts; } InterleaveContext; #define OFFSET(x) offsetof(InterleaveContext, x) @@ -52,58 +49,78 @@ static const AVOption filt_name##_options[] = { \ { NULL } \ } -inline static int push_frame(AVFilterContext *ctx) +static int activate(AVFilterContext *ctx) { + AVFilterLink *outlink = ctx->outputs[0]; InterleaveContext *s = ctx->priv; - AVFrame *frame; - int i, queue_idx = -1; - int64_t pts_min = INT64_MAX; + int64_t q_pts, pts = INT64_MAX; + int i, nb_eofs = 0, input_idx = -1; + + FF_FILTER_FORWARD_STATUS_BACK_ALL(outlink, ctx); - /* look for oldest frame */ for (i = 0; i < ctx->nb_inputs; i++) { - struct FFBufQueue *q = &s->queues[i]; + if (!ff_outlink_get_status(ctx->inputs[i]) && + !ff_inlink_queued_frames(ctx->inputs[i])) + break; + } - if (!q->available && !ctx->inputs[i]->status_out) - return 0; - if (q->available) { - frame = ff_bufqueue_peek(q, 0); - if (frame->pts < pts_min) { - pts_min = frame->pts; - queue_idx = i; + if (i == ctx->nb_inputs) { + for (i = 0; i < ctx->nb_inputs; i++) { + AVFrame *frame; + + if (ff_outlink_get_status(ctx->inputs[i])) + continue; + + frame = ff_inlink_peek_frame(ctx->inputs[i], 0); + if (frame->pts == AV_NOPTS_VALUE) { + int ret; + + av_log(ctx, AV_LOG_WARNING, + "NOPTS value for input frame cannot be accepted, frame discarded\n"); + ret = ff_inlink_consume_frame(ctx->inputs[i], &frame); + if (ret < 0) + return ret; + av_frame_free(&frame); + return AVERROR_INVALIDDATA; } + + q_pts = av_rescale_q(frame->pts, ctx->inputs[i]->time_base, AV_TIME_BASE_Q); + if (q_pts < pts) { + pts = q_pts; + input_idx = i; + } + } + + if (input_idx >= 0) { + AVFrame *frame; + int ret; + + ret = ff_inlink_consume_frame(ctx->inputs[input_idx], &frame); + if (ret < 0) + return ret; + + frame->pts = s->pts = pts; + return ff_filter_frame(outlink, frame); } } - /* all inputs are closed */ - if (queue_idx < 0) - return AVERROR_EOF; - - frame = ff_bufqueue_get(&s->queues[queue_idx]); - av_log(ctx, AV_LOG_DEBUG, "queue:%d -> frame time:%f\n", - queue_idx, frame->pts * av_q2d(AV_TIME_BASE_Q)); - return ff_filter_frame(ctx->outputs[0], frame); -} - -static int filter_frame(AVFilterLink *inlink, AVFrame *frame) -{ - AVFilterContext *ctx = inlink->dst; - InterleaveContext *s = ctx->priv; - unsigned in_no = FF_INLINK_IDX(inlink); - - if (frame->pts == AV_NOPTS_VALUE) { - av_log(ctx, AV_LOG_WARNING, - "NOPTS value for input frame cannot be accepted, frame discarded\n"); - av_frame_free(&frame); - return AVERROR_INVALIDDATA; + for (i = 0; i < ctx->nb_inputs; i++) { + if (ff_inlink_queued_frames(ctx->inputs[i])) + continue; + if (ff_outlink_frame_wanted(outlink) && + !ff_outlink_get_status(ctx->inputs[i])) { + ff_inlink_request_frame(ctx->inputs[i]); + return 0; + } + nb_eofs++; } - /* queue frame */ - frame->pts = av_rescale_q(frame->pts, inlink->time_base, AV_TIME_BASE_Q); - av_log(ctx, AV_LOG_DEBUG, "frame pts:%f -> queue idx:%d available:%d\n", - frame->pts * av_q2d(AV_TIME_BASE_Q), in_no, s->queues[in_no].available); - ff_bufqueue_add(ctx, &s->queues[in_no], frame); + if (nb_eofs == ctx->nb_inputs) { + ff_outlink_set_status(outlink, AVERROR_EOF, s->pts); + return 0; + } - return push_frame(ctx); + return FFERROR_NOT_READY; } static av_cold int init(AVFilterContext *ctx) @@ -112,10 +129,6 @@ static av_cold int init(AVFilterContext *ctx) const AVFilterPad *outpad = &ctx->filter->outputs[0]; int i, ret; - s->queues = av_calloc(s->nb_inputs, sizeof(s->queues[0])); - if (!s->queues) - return AVERROR(ENOMEM); - for (i = 0; i < s->nb_inputs; i++) { AVFilterPad inpad = { 0 }; @@ -123,7 +136,6 @@ static av_cold int init(AVFilterContext *ctx) if (!inpad.name) return AVERROR(ENOMEM); inpad.type = outpad->type; - inpad.filter_frame = filter_frame; switch (outpad->type) { case AVMEDIA_TYPE_VIDEO: @@ -144,14 +156,8 @@ static av_cold int init(AVFilterContext *ctx) static av_cold void uninit(AVFilterContext *ctx) { - InterleaveContext *s = ctx->priv; - int i; - - for (i = 0; i < ctx->nb_inputs; i++) { - ff_bufqueue_discard_all(&s->queues[i]); - av_freep(&s->queues[i]); + for (int i = 0; i < ctx->nb_inputs; i++) av_freep(&ctx->input_pads[i].name); - } } static int config_output(AVFilterLink *outlink) @@ -190,23 +196,6 @@ static int config_output(AVFilterLink *outlink) return 0; } -static int request_frame(AVFilterLink *outlink) -{ - AVFilterContext *ctx = outlink->src; - InterleaveContext *s = ctx->priv; - int i, ret; - - for (i = 0; i < ctx->nb_inputs; i++) { - if (!s->queues[i].available && !ctx->inputs[i]->status_out) { - ret = ff_request_frame(ctx->inputs[i]); - if (ret != AVERROR_EOF) - return ret; - } - } - - return push_frame(ctx); -} - #if CONFIG_INTERLEAVE_FILTER DEFINE_OPTIONS(interleave, AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM); @@ -217,7 +206,6 @@ static const AVFilterPad interleave_outputs[] = { .name = "default", .type = AVMEDIA_TYPE_VIDEO, .config_props = config_output, - .request_frame = request_frame, }, { NULL } }; @@ -228,6 +216,7 @@ AVFilter ff_vf_interleave = { .priv_size = sizeof(InterleaveContext), .init = init, .uninit = uninit, + .activate = activate, .outputs = interleave_outputs, .priv_class = &interleave_class, .flags = AVFILTER_FLAG_DYNAMIC_INPUTS, @@ -245,7 +234,6 @@ static const AVFilterPad ainterleave_outputs[] = { .name = "default", .type = AVMEDIA_TYPE_AUDIO, .config_props = config_output, - .request_frame = request_frame, }, { NULL } }; @@ -256,6 +244,7 @@ AVFilter ff_af_ainterleave = { .priv_size = sizeof(InterleaveContext), .init = init, .uninit = uninit, + .activate = activate, .outputs = ainterleave_outputs, .priv_class = &ainterleave_class, .flags = AVFILTER_FLAG_DYNAMIC_INPUTS, diff --git a/libavfilter/f_loop.c b/libavfilter/f_loop.c index 255fe643d..5ec44d9da 100644 --- a/libavfilter/f_loop.c +++ b/libavfilter/f_loop.c @@ -25,6 +25,7 @@ #include "libavutil/opt.h" #include "avfilter.h" #include "audio.h" +#include "filters.h" #include "formats.h" #include "internal.h" #include "video.h" @@ -44,6 +45,7 @@ typedef struct LoopContext { int64_t ignored_samples; int loop; + int eof; int64_t size; int64_t start; int64_t pts; @@ -53,6 +55,15 @@ typedef struct LoopContext { #define VFLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM #define OFFSET(x) offsetof(LoopContext, x) +static void check_size(AVFilterContext *ctx) +{ + LoopContext *s = ctx->priv; + + if (!s->size) + av_log(ctx, AV_LOG_WARNING, "Number of %s to loop is not set!\n", + ctx->input_pads[0].type == AVMEDIA_TYPE_VIDEO ? "frames" : "samples"); +} + #if CONFIG_ALOOP_FILTER static int aconfig_input(AVFilterLink *inlink) @@ -65,6 +76,8 @@ static int aconfig_input(AVFilterLink *inlink) if (!s->fifo || !s->left) return AVERROR(ENOMEM); + check_size(ctx); + return 0; } @@ -248,6 +261,8 @@ static av_cold int init(AVFilterContext *ctx) if (!s->frames) return AVERROR(ENOMEM); + check_size(ctx); + return 0; } @@ -267,7 +282,7 @@ static int push_frame(AVFilterContext *ctx) { AVFilterLink *outlink = ctx->outputs[0]; LoopContext *s = ctx->priv; - int64_t pts; + int64_t pts, duration; int ret; AVFrame *out = av_frame_clone(s->frames[s->current_frame]); @@ -275,7 +290,11 @@ static int push_frame(AVFilterContext *ctx) if (!out) return AVERROR(ENOMEM); out->pts += s->duration - s->start_pts; - pts = out->pts + out->pkt_duration; + if (out->pkt_duration) + duration = out->pkt_duration; + else + duration = av_rescale_q(1, av_inv_q(outlink->frame_rate), outlink->time_base); + pts = out->pts + duration; ret = ff_filter_frame(outlink, out); s->current_frame++; @@ -295,6 +314,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame) AVFilterContext *ctx = inlink->dst; AVFilterLink *outlink = ctx->outputs[0]; LoopContext *s = ctx->priv; + int64_t duration; int ret = 0; if (inlink->frame_count_out >= s->start && s->size > 0 && s->loop != 0) { @@ -307,7 +327,11 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame) return AVERROR(ENOMEM); } s->nb_frames++; - s->duration = frame->pts + frame->pkt_duration; + if (frame->pkt_duration) + duration = frame->pkt_duration; + else + duration = av_rescale_q(1, av_inv_q(outlink->frame_rate), outlink->time_base); + s->duration = frame->pts + duration; ret = ff_filter_frame(outlink, frame); } else { av_frame_free(&frame); @@ -321,25 +345,46 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame) return ret; } -static int request_frame(AVFilterLink *outlink) +static int activate(AVFilterContext *ctx) { - AVFilterContext *ctx = outlink->src; + AVFilterLink *inlink = ctx->inputs[0]; + AVFilterLink *outlink = ctx->outputs[0]; LoopContext *s = ctx->priv; - int ret = 0; + AVFrame *frame = NULL; + int ret, status; + int64_t pts; - if ((!s->size) || + FF_FILTER_FORWARD_STATUS_BACK(outlink, inlink); + + if (!s->eof && (s->nb_frames < s->size || !s->loop || !s->size)) { + ret = ff_inlink_consume_frame(inlink, &frame); + if (ret < 0) + return ret; + if (ret > 0) + return filter_frame(inlink, frame); + } + + if (!s->eof && ff_inlink_acknowledge_status(inlink, &status, &pts)) { + if (status == AVERROR_EOF) { + s->size = s->nb_frames; + s->eof = 1; + } + } + + if (s->eof && (!s->loop || !s->size)) { + ff_outlink_set_status(outlink, AVERROR_EOF, s->duration); + return 0; + } + + if (!s->eof && (!s->size || (s->nb_frames < s->size) || - (s->nb_frames >= s->size && s->loop == 0)) { - ret = ff_request_frame(ctx->inputs[0]); - } else { - ret = push_frame(ctx); + (s->nb_frames >= s->size && s->loop == 0))) { + FF_FILTER_FORWARD_WANTED(outlink, inlink); + } else if (s->loop && s->nb_frames == s->size) { + return push_frame(ctx); } - if (ret == AVERROR_EOF && s->nb_frames > 0 && s->loop != 0) { - ret = push_frame(ctx); - } - - return ret; + return FFERROR_NOT_READY; } static const AVOption loop_options[] = { @@ -353,18 +398,16 @@ AVFILTER_DEFINE_CLASS(loop); static const AVFilterPad inputs[] = { { - .name = "default", - .type = AVMEDIA_TYPE_VIDEO, - .filter_frame = filter_frame, + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, }, { NULL } }; static const AVFilterPad outputs[] = { { - .name = "default", - .type = AVMEDIA_TYPE_VIDEO, - .request_frame = request_frame, + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, }, { NULL } }; @@ -376,6 +419,7 @@ AVFilter ff_vf_loop = { .priv_class = &loop_class, .init = init, .uninit = uninit, + .activate = activate, .inputs = inputs, .outputs = outputs, }; diff --git a/libavfilter/f_realtime.c b/libavfilter/f_realtime.c index 171c16aaa..6fd3559da 100644 --- a/libavfilter/f_realtime.c +++ b/libavfilter/f_realtime.c @@ -22,11 +22,13 @@ #include "libavutil/time.h" #include "avfilter.h" #include "internal.h" +#include typedef struct RealtimeContext { const AVClass *class; int64_t delta; int64_t limit; + double speed; unsigned inited; } RealtimeContext; @@ -36,7 +38,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame) RealtimeContext *s = ctx->priv; if (frame->pts != AV_NOPTS_VALUE) { - int64_t pts = av_rescale_q(frame->pts, inlink->time_base, AV_TIME_BASE_Q); + int64_t pts = av_rescale_q(frame->pts, inlink->time_base, AV_TIME_BASE_Q) / s->speed; int64_t now = av_gettime_relative(); int64_t sleep = pts - now + s->delta; if (!s->inited) { @@ -44,7 +46,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame) sleep = 0; s->delta = now - pts; } - if (sleep > s->limit || sleep < -s->limit) { + if (FFABS(sleep) > s->limit / s->speed) { av_log(ctx, AV_LOG_WARNING, "time discontinuity detected: %"PRIi64" us, resetting\n", sleep); @@ -65,6 +67,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame) #define FLAGS AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_FILTERING_PARAM static const AVOption options[] = { { "limit", "sleep time limit", OFFSET(limit), AV_OPT_TYPE_DURATION, { .i64 = 2000000 }, 0, INT64_MAX, FLAGS }, + { "speed", "speed factor", OFFSET(speed), AV_OPT_TYPE_DOUBLE, { .dbl = 1.0 }, DBL_MIN, DBL_MAX, FLAGS }, { NULL } }; diff --git a/libavfilter/f_reverse.c b/libavfilter/f_reverse.c index 5bf71b38e..5f2792707 100644 --- a/libavfilter/f_reverse.c +++ b/libavfilter/f_reverse.c @@ -154,7 +154,7 @@ static int query_formats(AVFilterContext *ctx) if (ret < 0) return ret; - ret = ff_set_common_formats(ctx, ff_planar_sample_fmts()); + ret = ff_set_common_formats(ctx, ff_all_formats(AVMEDIA_TYPE_AUDIO)); if (ret < 0) return ret; @@ -164,11 +164,92 @@ static int query_formats(AVFilterContext *ctx) return ff_set_common_samplerates(ctx, formats); } +static void reverse_samples_planar(AVFrame *out) +{ + for (int p = 0; p < out->channels; p++) { + switch (out->format) { + case AV_SAMPLE_FMT_U8P: { + uint8_t *dst = (uint8_t *)out->extended_data[p]; + for (int i = 0, j = out->nb_samples - 1; i < j; i++, j--) + FFSWAP(uint8_t, dst[i], dst[j]); + } + break; + case AV_SAMPLE_FMT_S16P: { + int16_t *dst = (int16_t *)out->extended_data[p]; + for (int i = 0, j = out->nb_samples - 1; i < j; i++, j--) + FFSWAP(int16_t, dst[i], dst[j]); + } + break; + case AV_SAMPLE_FMT_S32P: { + int32_t *dst = (int32_t *)out->extended_data[p]; + for (int i = 0, j = out->nb_samples - 1; i < j; i++, j--) + FFSWAP(int32_t, dst[i], dst[j]); + } + break; + case AV_SAMPLE_FMT_FLTP: { + float *dst = (float *)out->extended_data[p]; + for (int i = 0, j = out->nb_samples - 1; i < j; i++, j--) + FFSWAP(float, dst[i], dst[j]); + } + break; + case AV_SAMPLE_FMT_DBLP: { + double *dst = (double *)out->extended_data[p]; + for (int i = 0, j = out->nb_samples - 1; i < j; i++, j--) + FFSWAP(double, dst[i], dst[j]); + } + break; + } + } +} + +static void reverse_samples_packed(AVFrame *out) +{ + const int channels = out->channels; + + switch (out->format) { + case AV_SAMPLE_FMT_U8: { + uint8_t *dst = (uint8_t *)out->extended_data[0]; + for (int i = 0, j = out->nb_samples - 1; i < j; i++, j--) + for (int p = 0; p < channels; p++) + FFSWAP(uint8_t, dst[i * channels + p], dst[j * channels + p]); + } + break; + case AV_SAMPLE_FMT_S16: { + int16_t *dst = (int16_t *)out->extended_data[0]; + for (int i = 0, j = out->nb_samples - 1; i < j; i++, j--) + for (int p = 0; p < channels; p++) + FFSWAP(int16_t, dst[i * channels + p], dst[j * channels + p]); + } + break; + case AV_SAMPLE_FMT_S32: { + int32_t *dst = (int32_t *)out->extended_data[0]; + for (int i = 0, j = out->nb_samples - 1; i < j; i++, j--) + for (int p = 0; p < channels; p++) + FFSWAP(int32_t, dst[i * channels + p], dst[j * channels + p]); + } + break; + case AV_SAMPLE_FMT_FLT: { + float *dst = (float *)out->extended_data[0]; + for (int i = 0, j = out->nb_samples - 1; i < j; i++, j--) + for (int p = 0; p < channels; p++) + FFSWAP(float, dst[i * channels + p], dst[j * channels + p]); + } + break; + case AV_SAMPLE_FMT_DBL: { + double *dst = (double *)out->extended_data[0]; + for (int i = 0, j = out->nb_samples - 1; i < j; i++, j--) + for (int p = 0; p < channels; p++) + FFSWAP(double, dst[i * channels + p], dst[j * channels + p]); + } + break; + } +} + static int areverse_request_frame(AVFilterLink *outlink) { AVFilterContext *ctx = outlink->src; ReverseContext *s = ctx->priv; - int ret, p, i, j; + int ret; ret = ff_request_frame(ctx->inputs[0]); @@ -176,41 +257,10 @@ static int areverse_request_frame(AVFilterLink *outlink) AVFrame *out = s->frames[s->nb_frames - 1]; out->pts = s->pts[s->flush_idx++]; - for (p = 0; p < outlink->channels; p++) { - switch (outlink->format) { - case AV_SAMPLE_FMT_U8P: { - uint8_t *dst = (uint8_t *)out->extended_data[p]; - for (i = 0, j = out->nb_samples - 1; i < j; i++, j--) - FFSWAP(uint8_t, dst[i], dst[j]); - } - break; - case AV_SAMPLE_FMT_S16P: { - int16_t *dst = (int16_t *)out->extended_data[p]; - for (i = 0, j = out->nb_samples - 1; i < j; i++, j--) - FFSWAP(int16_t, dst[i], dst[j]); - } - break; - case AV_SAMPLE_FMT_S32P: { - int32_t *dst = (int32_t *)out->extended_data[p]; - for (i = 0, j = out->nb_samples - 1; i < j; i++, j--) - FFSWAP(int32_t, dst[i], dst[j]); - } - break; - case AV_SAMPLE_FMT_FLTP: { - float *dst = (float *)out->extended_data[p]; - for (i = 0, j = out->nb_samples - 1; i < j; i++, j--) - FFSWAP(float, dst[i], dst[j]); - } - break; - case AV_SAMPLE_FMT_DBLP: { - double *dst = (double *)out->extended_data[p]; - for (i = 0, j = out->nb_samples - 1; i < j; i++, j--) - FFSWAP(double, dst[i], dst[j]); - } - break; - } - } - + if (av_sample_fmt_is_planar(out->format)) + reverse_samples_planar(out); + else + reverse_samples_packed(out); ret = ff_filter_frame(outlink, out); s->nb_frames--; } diff --git a/libavfilter/f_select.c b/libavfilter/f_select.c index b1b2cbc21..113237575 100644 --- a/libavfilter/f_select.c +++ b/libavfilter/f_select.c @@ -28,12 +28,12 @@ #include "libavutil/fifo.h" #include "libavutil/internal.h" #include "libavutil/opt.h" -#include "libavutil/pixelutils.h" #include "avfilter.h" #include "audio.h" #include "formats.h" #include "internal.h" #include "video.h" +#include "scene_sad.h" static const char *const var_names[] = { "TB", ///< timebase @@ -145,7 +145,7 @@ typedef struct SelectContext { AVExpr *expr; double var_values[VAR_VARS_NB]; int do_scene_detect; ///< 1 if the expression requires scene detection variables, 0 otherwise - av_pixelutils_sad_fn sad; ///< Sum of the absolute difference function (scene detect only) + ff_scene_sad_fn sad; ///< Sum of the absolute difference function (scene detect only) double prev_mafd; ///< previous MAFD (scene detect only) AVFrame *prev_picref; ///< previous frame (scene detect only) double select; @@ -241,8 +241,8 @@ static int config_input(AVFilterLink *inlink) select->var_values[VAR_SAMPLE_RATE] = inlink->type == AVMEDIA_TYPE_AUDIO ? inlink->sample_rate : NAN; - if (select->do_scene_detect) { - select->sad = av_pixelutils_get_sad_fn(3, 3, 2, select); // 8x8 both sources aligned + if (CONFIG_SELECT_FILTER && select->do_scene_detect) { + select->sad = ff_scene_sad_get_fn(8); if (!select->sad) return AVERROR(EINVAL); } @@ -258,24 +258,12 @@ static double get_scene_score(AVFilterContext *ctx, AVFrame *frame) if (prev_picref && frame->height == prev_picref->height && frame->width == prev_picref->width) { - int x, y, nb_sad = 0; - int64_t sad = 0; + uint64_t sad; double mafd, diff; - uint8_t *p1 = frame->data[0]; - uint8_t *p2 = prev_picref->data[0]; - const int p1_linesize = frame->linesize[0]; - const int p2_linesize = prev_picref->linesize[0]; - for (y = 0; y < frame->height - 7; y += 8) { - for (x = 0; x < frame->width*3 - 7; x += 8) { - sad += select->sad(p1 + x, p1_linesize, p2 + x, p2_linesize); - nb_sad += 8 * 8; - } - p1 += 8 * p1_linesize; - p2 += 8 * p2_linesize; - } + select->sad(prev_picref->data[0], prev_picref->linesize[0], frame->data[0], frame->linesize[0], frame->width * 3, frame->height, &sad); emms_c(); - mafd = nb_sad ? (double)sad / nb_sad : 0; + mafd = (double)sad / (frame->width * 3 * frame->height); diff = fabs(mafd - select->prev_mafd); ret = av_clipf(FFMIN(mafd, diff) / 100., 0, 1); select->prev_mafd = mafd; @@ -430,29 +418,6 @@ static av_cold void uninit(AVFilterContext *ctx) } } -static int query_formats(AVFilterContext *ctx) -{ - SelectContext *select = ctx->priv; - - if (!select->do_scene_detect) { - return ff_default_query_formats(ctx); - } else { - int ret; - static const enum AVPixelFormat pix_fmts[] = { - AV_PIX_FMT_RGB24, AV_PIX_FMT_BGR24, - AV_PIX_FMT_NONE - }; - AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts); - - if (!fmts_list) - return AVERROR(ENOMEM); - ret = ff_set_common_formats(ctx, fmts_list); - if (ret < 0) - return ret; - } - return 0; -} - #if CONFIG_ASELECT_FILTER DEFINE_OPTIONS(aselect, AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM); @@ -498,6 +463,29 @@ AVFilter ff_af_aselect = { #if CONFIG_SELECT_FILTER +static int query_formats(AVFilterContext *ctx) +{ + SelectContext *select = ctx->priv; + + if (!select->do_scene_detect) { + return ff_default_query_formats(ctx); + } else { + int ret; + static const enum AVPixelFormat pix_fmts[] = { + AV_PIX_FMT_RGB24, AV_PIX_FMT_BGR24, + AV_PIX_FMT_NONE + }; + AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts); + + if (!fmts_list) + return AVERROR(ENOMEM); + ret = ff_set_common_formats(ctx, fmts_list); + if (ret < 0) + return ret; + } + return 0; +} + DEFINE_OPTIONS(select, AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM); AVFILTER_DEFINE_CLASS(select); diff --git a/libavfilter/f_sidedata.c b/libavfilter/f_sidedata.c index 45d246b73..381da5a05 100644 --- a/libavfilter/f_sidedata.c +++ b/libavfilter/f_sidedata.c @@ -43,6 +43,7 @@ typedef struct SideDataContext { } SideDataContext; #define OFFSET(x) offsetof(SideDataContext, x) +#if FF_API_FRAME_QP #define DEFINE_OPTIONS(filt_name, FLAGS) \ static const AVOption filt_name##_options[] = { \ { "mode", "set a mode of operation", OFFSET(mode), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, SIDEDATA_NB-1, FLAGS, "mode" }, \ @@ -62,8 +63,45 @@ static const AVOption filt_name##_options[] = { \ { "AUDIO_SERVICE_TYPE", "", 0, AV_OPT_TYPE_CONST, {.i64 = AV_FRAME_DATA_AUDIO_SERVICE_TYPE }, 0, 0, FLAGS, "type" }, \ { "MASTERING_DISPLAY_METADATA", "", 0, AV_OPT_TYPE_CONST, {.i64 = AV_FRAME_DATA_MASTERING_DISPLAY_METADATA }, 0, 0, FLAGS, "type" }, \ { "GOP_TIMECODE", "", 0, AV_OPT_TYPE_CONST, {.i64 = AV_FRAME_DATA_GOP_TIMECODE }, 0, 0, FLAGS, "type" }, \ + { "SPHERICAL", "", 0, AV_OPT_TYPE_CONST, {.i64 = AV_FRAME_DATA_SPHERICAL }, 0, 0, FLAGS, "type" }, \ + { "CONTENT_LIGHT_LEVEL", "", 0, AV_OPT_TYPE_CONST, {.i64 = AV_FRAME_DATA_CONTENT_LIGHT_LEVEL }, 0, 0, FLAGS, "type" }, \ + { "ICC_PROFILE", "", 0, AV_OPT_TYPE_CONST, {.i64 = AV_FRAME_DATA_ICC_PROFILE }, 0, 0, FLAGS, "type" }, \ + { "QP_TABLE_PROPERTIES", "", 0, AV_OPT_TYPE_CONST, {.i64 = AV_FRAME_DATA_QP_TABLE_PROPERTIES }, 0, 0, FLAGS, "type" }, \ + { "QP_TABLE_DATA", "", 0, AV_OPT_TYPE_CONST, {.i64 = AV_FRAME_DATA_QP_TABLE_DATA }, 0, 0, FLAGS, "type" }, \ + { "S12M_TIMECOD", "", 0, AV_OPT_TYPE_CONST, {.i64 = AV_FRAME_DATA_S12M_TIMECODE }, 0, 0, FLAGS, "type" }, \ + { "DYNAMIC_HDR_PLUS", "", 0, AV_OPT_TYPE_CONST, {.i64 = AV_FRAME_DATA_DYNAMIC_HDR_PLUS }, 0, 0, FLAGS, "type" }, \ + { "REGIONS_OF_INTEREST", "", 0, AV_OPT_TYPE_CONST, {.i64 = AV_FRAME_DATA_REGIONS_OF_INTEREST }, 0, 0, FLAGS, "type" }, \ { NULL } \ } +#else +#define DEFINE_OPTIONS(filt_name, FLAGS) \ +static const AVOption filt_name##_options[] = { \ + { "mode", "set a mode of operation", OFFSET(mode), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, SIDEDATA_NB-1, FLAGS, "mode" }, \ + { "select", "select frame", 0, AV_OPT_TYPE_CONST, {.i64 = SIDEDATA_SELECT }, 0, 0, FLAGS, "mode" }, \ + { "delete", "delete side data", 0, AV_OPT_TYPE_CONST, {.i64 = SIDEDATA_DELETE }, 0, 0, FLAGS, "mode" }, \ + { "type", "set side data type", OFFSET(type), AV_OPT_TYPE_INT, {.i64 = -1 }, -1, INT_MAX, FLAGS, "type" }, \ + { "PANSCAN", "", 0, AV_OPT_TYPE_CONST, {.i64 = AV_FRAME_DATA_PANSCAN }, 0, 0, FLAGS, "type" }, \ + { "A53_CC", "", 0, AV_OPT_TYPE_CONST, {.i64 = AV_FRAME_DATA_A53_CC }, 0, 0, FLAGS, "type" }, \ + { "STEREO3D", "", 0, AV_OPT_TYPE_CONST, {.i64 = AV_FRAME_DATA_STEREO3D }, 0, 0, FLAGS, "type" }, \ + { "MATRIXENCODING", "", 0, AV_OPT_TYPE_CONST, {.i64 = AV_FRAME_DATA_MATRIXENCODING }, 0, 0, FLAGS, "type" }, \ + { "DOWNMIX_INFO", "", 0, AV_OPT_TYPE_CONST, {.i64 = AV_FRAME_DATA_DOWNMIX_INFO }, 0, 0, FLAGS, "type" }, \ + { "REPLAYGAIN", "", 0, AV_OPT_TYPE_CONST, {.i64 = AV_FRAME_DATA_REPLAYGAIN }, 0, 0, FLAGS, "type" }, \ + { "DISPLAYMATRIX", "", 0, AV_OPT_TYPE_CONST, {.i64 = AV_FRAME_DATA_DISPLAYMATRIX }, 0, 0, FLAGS, "type" }, \ + { "AFD", "", 0, AV_OPT_TYPE_CONST, {.i64 = AV_FRAME_DATA_AFD }, 0, 0, FLAGS, "type" }, \ + { "MOTION_VECTORS", "", 0, AV_OPT_TYPE_CONST, {.i64 = AV_FRAME_DATA_MOTION_VECTORS }, 0, 0, FLAGS, "type" }, \ + { "SKIP_SAMPLES", "", 0, AV_OPT_TYPE_CONST, {.i64 = AV_FRAME_DATA_SKIP_SAMPLES }, 0, 0, FLAGS, "type" }, \ + { "AUDIO_SERVICE_TYPE", "", 0, AV_OPT_TYPE_CONST, {.i64 = AV_FRAME_DATA_AUDIO_SERVICE_TYPE }, 0, 0, FLAGS, "type" }, \ + { "MASTERING_DISPLAY_METADATA", "", 0, AV_OPT_TYPE_CONST, {.i64 = AV_FRAME_DATA_MASTERING_DISPLAY_METADATA }, 0, 0, FLAGS, "type" }, \ + { "GOP_TIMECODE", "", 0, AV_OPT_TYPE_CONST, {.i64 = AV_FRAME_DATA_GOP_TIMECODE }, 0, 0, FLAGS, "type" }, \ + { "SPHERICAL", "", 0, AV_OPT_TYPE_CONST, {.i64 = AV_FRAME_DATA_SPHERICAL }, 0, 0, FLAGS, "type" }, \ + { "CONTENT_LIGHT_LEVEL", "", 0, AV_OPT_TYPE_CONST, {.i64 = AV_FRAME_DATA_CONTENT_LIGHT_LEVEL }, 0, 0, FLAGS, "type" }, \ + { "ICC_PROFILE", "", 0, AV_OPT_TYPE_CONST, {.i64 = AV_FRAME_DATA_ICC_PROFILE }, 0, 0, FLAGS, "type" }, \ + { "S12M_TIMECOD", "", 0, AV_OPT_TYPE_CONST, {.i64 = AV_FRAME_DATA_S12M_TIMECODE }, 0, 0, FLAGS, "type" }, \ + { "DYNAMIC_HDR_PLUS", "", 0, AV_OPT_TYPE_CONST, {.i64 = AV_FRAME_DATA_DYNAMIC_HDR_PLUS }, 0, 0, FLAGS, "type" }, \ + { "REGIONS_OF_INTEREST", "", 0, AV_OPT_TYPE_CONST, {.i64 = AV_FRAME_DATA_REGIONS_OF_INTEREST }, 0, 0, FLAGS, "type" }, \ + { NULL } \ +} +#endif static av_cold int init(AVFilterContext *ctx) { diff --git a/libavfilter/filters.h b/libavfilter/filters.h index 4e2652ebe..115775540 100644 --- a/libavfilter/filters.h +++ b/libavfilter/filters.h @@ -60,12 +60,25 @@ int ff_inlink_process_commands(AVFilterLink *link, const AVFrame *frame); */ int ff_inlink_evaluate_timeline_at_frame(AVFilterLink *link, const AVFrame *frame); +/** + * Get the number of frames available on the link. + * @return the number of frames available in the link fifo. + */ +size_t ff_inlink_queued_frames(AVFilterLink *link); + /** * Test if a frame is available on the link. * @return >0 if a frame is available */ int ff_inlink_check_available_frame(AVFilterLink *link); + +/*** + * Get the number of samples available on the link. + * @return the numer of samples available on the link. + */ +int ff_inlink_queued_samples(AVFilterLink *link); + /** * Test if enough samples are available on the link. * @return >0 if enough samples are available @@ -102,6 +115,13 @@ int ff_inlink_consume_frame(AVFilterLink *link, AVFrame **rframe); int ff_inlink_consume_samples(AVFilterLink *link, unsigned min, unsigned max, AVFrame **rframe); +/** + * Access a frame in the link fifo without consuming it. + * The first frame is numbered 0; the designated frame must exist. + * @return the frame at idx position in the link fifo. + */ +AVFrame *ff_inlink_peek_frame(AVFilterLink *link, size_t idx); + /** * Make sure a frame is writable. * This is similar to av_frame_make_writable() except it uses the link's diff --git a/libavfilter/framerate.h b/libavfilter/framerate.h index a42d5af68..8048dfa36 100644 --- a/libavfilter/framerate.h +++ b/libavfilter/framerate.h @@ -19,7 +19,7 @@ #ifndef AVFILTER_FRAMERATE_H #define AVFILTER_FRAMERATE_H -#include "libavutil/pixelutils.h" +#include "scene_sad.h" #include "avfilter.h" #define BLEND_FUNC_PARAMS const uint8_t *src1, ptrdiff_t src1_linesize, \ @@ -48,7 +48,7 @@ typedef struct FrameRateContext { AVRational srce_time_base; ///< timebase of source AVRational dest_time_base; ///< timebase of destination - av_pixelutils_sad_fn sad; ///< Sum of the absolute difference function (scene detect only) + ff_scene_sad_fn sad; ///< Sum of the absolute difference function (scene detect only) double prev_mafd; ///< previous MAFD (scene detect only) int blend_factor_max; diff --git a/libavfilter/framesync.c b/libavfilter/framesync.c index da12c58a6..bc95f7d90 100644 --- a/libavfilter/framesync.c +++ b/libavfilter/framesync.c @@ -61,7 +61,7 @@ enum { static int consume_from_fifos(FFFrameSync *fs); -const AVClass *framesync_get_class(void) +const AVClass *ff_framesync_get_class(void) { return &framesync_class; } @@ -127,16 +127,16 @@ int ff_framesync_configure(FFFrameSync *fs) fs->opt_shortest = 1; fs->opt_eof_action = EOF_ACTION_ENDALL; } - if (fs->opt_shortest) { - for (i = 0; i < fs->nb_in; i++) - fs->in[i].after = EXT_STOP; - } if (!fs->opt_repeatlast) { for (i = 1; i < fs->nb_in; i++) { fs->in[i].after = EXT_NULL; fs->in[i].sync = 0; } } + if (fs->opt_shortest) { + for (i = 0; i < fs->nb_in; i++) + fs->in[i].after = EXT_STOP; + } if (!fs->time_base.num) { for (i = 0; i < fs->nb_in; i++) { diff --git a/libavfilter/framesync.h b/libavfilter/framesync.h index abf3bf552..37743cccb 100644 --- a/libavfilter/framesync.h +++ b/libavfilter/framesync.h @@ -211,7 +211,7 @@ typedef struct FFFrameSync { /** * Get the class for the framesync object. */ -const AVClass *framesync_get_class(void); +const AVClass *ff_framesync_get_class(void); /** * Pre-initialize a frame sync structure. @@ -304,11 +304,11 @@ static int name##_framesync_preinit(AVFilterContext *ctx) { \ return 0; \ } \ static const AVClass *name##_child_class_next(const AVClass *prev) { \ - return prev ? NULL : framesync_get_class(); \ + return prev ? NULL : ff_framesync_get_class(); \ } \ static void *name##_child_next(void *obj, void *prev) { \ context *s = obj; \ - s->fs.class = framesync_get_class(); /* FIXME */ \ + s->fs.class = ff_framesync_get_class(); /* FIXME */ \ return prev ? NULL : &s->field; \ } \ static const AVClass name##_class = { \ diff --git a/libavfilter/gblur.h b/libavfilter/gblur.h new file mode 100644 index 000000000..87129801d --- /dev/null +++ b/libavfilter/gblur.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2011 Pascal Getreuer + * Copyright (c) 2016 Paul B Mahol + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef AVFILTER_GBLUR_H +#define AVFILTER_GBLUR_H +#include "avfilter.h" + +typedef struct GBlurContext { + const AVClass *class; + + float sigma; + float sigmaV; + int steps; + int planes; + + int depth; + int planewidth[4]; + int planeheight[4]; + float *buffer; + float boundaryscale; + float boundaryscaleV; + float postscale; + float postscaleV; + float nu; + float nuV; + int nb_planes; + void (*horiz_slice)(float *buffer, int width, int height, int steps, float nu, float bscale); +} GBlurContext; +void ff_gblur_init(GBlurContext *s); +void ff_gblur_init_x86(GBlurContext *s); +#endif diff --git a/libavfilter/graphdump.c b/libavfilter/graphdump.c index 73777191d..8bc7b162d 100644 --- a/libavfilter/graphdump.c +++ b/libavfilter/graphdump.c @@ -156,7 +156,7 @@ char *avfilter_graph_dump(AVFilterGraph *graph, const char *options) AVBPrint buf; char *dump; - av_bprint_init(&buf, 0, 0); + av_bprint_init(&buf, 0, AV_BPRINT_SIZE_COUNT_ONLY); avfilter_graph_dump_to_buf(&buf, graph); av_bprint_init(&buf, buf.len + 1, buf.len + 1); avfilter_graph_dump_to_buf(&buf, graph); diff --git a/libavfilter/opencl.c b/libavfilter/opencl.c index ae6166738..95f0bfc60 100644 --- a/libavfilter/opencl.c +++ b/libavfilter/opencl.c @@ -19,12 +19,9 @@ #include #include -#include "libavutil/hwcontext.h" -#include "libavutil/hwcontext_opencl.h" #include "libavutil/mem.h" #include "libavutil/pixdesc.h" -#include "avfilter.h" #include "formats.h" #include "opencl.h" @@ -340,3 +337,16 @@ int ff_opencl_filter_work_size_from_image(AVFilterContext *avctx, return 0; } + +void ff_opencl_print_const_matrix_3x3(AVBPrint *buf, const char *name_str, + double mat[3][3]) +{ + int i, j; + av_bprintf(buf, "__constant float %s[9] = {\n", name_str); + for (i = 0; i < 3; i++) { + for (j = 0; j < 3; j++) + av_bprintf(buf, " %.5ff,", mat[i][j]); + av_bprintf(buf, "\n"); + } + av_bprintf(buf, "};\n"); +} diff --git a/libavfilter/opencl.h b/libavfilter/opencl.h index c0a451978..973b6d82d 100644 --- a/libavfilter/opencl.h +++ b/libavfilter/opencl.h @@ -25,6 +25,7 @@ // it was introduced in OpenCL 2.0. #define CL_USE_DEPRECATED_OPENCL_1_2_APIS +#include "libavutil/bprint.h" #include "libavutil/buffer.h" #include "libavutil/hwcontext.h" #include "libavutil/hwcontext_opencl.h" @@ -46,6 +47,71 @@ typedef struct OpenCLFilterContext { int output_height; } OpenCLFilterContext; + +/** + * set argument to specific Kernel. + * This macro relies on usage of local label "fail" and variables: + * avctx, cle and err. + */ +#define CL_SET_KERNEL_ARG(kernel, arg_num, type, arg) \ + cle = clSetKernelArg(kernel, arg_num, sizeof(type), arg); \ + if (cle != CL_SUCCESS) { \ + av_log(avctx, AV_LOG_ERROR, "Failed to set kernel " \ + "argument %d: error %d.\n", arg_num, cle); \ + err = AVERROR(EIO); \ + goto fail; \ + } + +/** + * A helper macro to handle OpenCL errors. It will assign errcode to + * variable err, log error msg, and jump to fail label on error. + */ +#define CL_FAIL_ON_ERROR(errcode, ...) do { \ + if (cle != CL_SUCCESS) { \ + av_log(avctx, AV_LOG_ERROR, __VA_ARGS__); \ + err = errcode; \ + goto fail; \ + } \ + } while(0) +/** + * release an OpenCL Kernel + */ +#define CL_RELEASE_KERNEL(k) \ +do { \ + if (k) { \ + cle = clReleaseKernel(k); \ + if (cle != CL_SUCCESS) \ + av_log(avctx, AV_LOG_ERROR, "Failed to release " \ + "OpenCL kernel: %d.\n", cle); \ + } \ +} while(0) + +/** + * release an OpenCL Memory Object + */ +#define CL_RELEASE_MEMORY(m) \ +do { \ + if (m) { \ + cle = clReleaseMemObject(m); \ + if (cle != CL_SUCCESS) \ + av_log(avctx, AV_LOG_ERROR, "Failed to release " \ + "OpenCL memory: %d.\n", cle); \ + } \ +} while(0) + +/** + * release an OpenCL Command Queue + */ +#define CL_RELEASE_QUEUE(q) \ +do { \ + if (q) { \ + cle = clReleaseCommandQueue(q); \ + if (cle != CL_SUCCESS) \ + av_log(avctx, AV_LOG_ERROR, "Failed to release " \ + "OpenCL command queue: %d.\n", cle); \ + } \ +} while(0) + /** * Return that all inputs and outputs support only AV_PIX_FMT_OPENCL. */ @@ -97,5 +163,12 @@ int ff_opencl_filter_work_size_from_image(AVFilterContext *avctx, size_t *work_size, AVFrame *frame, int plane, int block_alignment); +/** + * Print a 3x3 matrix into a buffer as __constant array, which could + * be included in an OpenCL program. +*/ + +void ff_opencl_print_const_matrix_3x3(AVBPrint *buf, const char *name_str, + double mat[3][3]); #endif /* AVFILTER_OPENCL_H */ diff --git a/libavfilter/opencl/colorkey.cl b/libavfilter/opencl/colorkey.cl new file mode 100644 index 000000000..6d71f1716 --- /dev/null +++ b/libavfilter/opencl/colorkey.cl @@ -0,0 +1,49 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +const sampler_t sampler = CLK_NORMALIZED_COORDS_FALSE | + CLK_FILTER_NEAREST; + +__kernel void colorkey_blend( + __read_only image2d_t src, + __write_only image2d_t dst, + float4 colorkey_rgba, + float similarity, + float blend +) { + int2 loc = (int2)(get_global_id(0), get_global_id(1)); + float4 pixel = read_imagef(src, sampler, loc); + float diff = distance(pixel.xyz, colorkey_rgba.xyz); + + pixel.s3 = clamp((diff - similarity) / blend, 0.0f, 1.0f); + write_imagef(dst, loc, pixel); +} + +__kernel void colorkey( + __read_only image2d_t src, + __write_only image2d_t dst, + float4 colorkey_rgba, + float similarity +) { + int2 loc = (int2)(get_global_id(0), get_global_id(1)); + float4 pixel = read_imagef(src, sampler, loc); + float diff = distance(pixel.xyz, colorkey_rgba.xyz); + + pixel.s3 = (diff > similarity) ? 1.0f : 0.0f; + write_imagef(dst, loc, pixel); +} diff --git a/libavfilter/opencl/colorspace_common.cl b/libavfilter/opencl/colorspace_common.cl new file mode 100644 index 000000000..ac911f03e --- /dev/null +++ b/libavfilter/opencl/colorspace_common.cl @@ -0,0 +1,205 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#define ST2084_MAX_LUMINANCE 10000.0f +#define REFERENCE_WHITE 100.0f + +#if chroma_loc == 1 + #define chroma_sample(a,b,c,d) (((a) + (c)) * 0.5f) +#elif chroma_loc == 3 + #define chroma_sample(a,b,c,d) (a) +#elif chroma_loc == 4 + #define chroma_sample(a,b,c,d) (((a) + (b)) * 0.5f) +#elif chroma_loc == 5 + #define chroma_sample(a,b,c,d) (c) +#elif chroma_loc == 6 + #define chroma_sample(a,b,c,d) (((c) + (d)) * 0.5f) +#else + #define chroma_sample(a,b,c,d) (((a) + (b) + (c) + (d)) * 0.25f) +#endif + +constant const float ST2084_M1 = 0.1593017578125f; +constant const float ST2084_M2 = 78.84375f; +constant const float ST2084_C1 = 0.8359375f; +constant const float ST2084_C2 = 18.8515625f; +constant const float ST2084_C3 = 18.6875f; + +float get_luma_dst(float3 c) { + return luma_dst.x * c.x + luma_dst.y * c.y + luma_dst.z * c.z; +} + +float get_luma_src(float3 c) { + return luma_src.x * c.x + luma_src.y * c.y + luma_src.z * c.z; +} + +float3 get_chroma_sample(float3 a, float3 b, float3 c, float3 d) { + return chroma_sample(a, b, c, d); +} + +float eotf_st2084(float x) { + float p = powr(x, 1.0f / ST2084_M2); + float a = max(p -ST2084_C1, 0.0f); + float b = max(ST2084_C2 - ST2084_C3 * p, 1e-6f); + float c = powr(a / b, 1.0f / ST2084_M1); + return x > 0.0f ? c * ST2084_MAX_LUMINANCE / REFERENCE_WHITE : 0.0f; +} + +__constant const float HLG_A = 0.17883277f; +__constant const float HLG_B = 0.28466892f; +__constant const float HLG_C = 0.55991073f; + +// linearizer for HLG +float inverse_oetf_hlg(float x) { + float a = 4.0f * x * x; + float b = exp((x - HLG_C) / HLG_A) + HLG_B; + return x < 0.5f ? a : b; +} + +// delinearizer for HLG +float oetf_hlg(float x) { + float a = 0.5f * sqrt(x); + float b = HLG_A * log(x - HLG_B) + HLG_C; + return x <= 1.0f ? a : b; +} + +float3 ootf_hlg(float3 c, float peak) { + float luma = get_luma_src(c); + float gamma = 1.2f + 0.42f * log10(peak * REFERENCE_WHITE / 1000.0f); + gamma = max(1.0f, gamma); + float factor = peak * powr(luma, gamma - 1.0f) / powr(12.0f, gamma); + return c * factor; +} + +float3 inverse_ootf_hlg(float3 c, float peak) { + float gamma = 1.2f + 0.42f * log10(peak * REFERENCE_WHITE / 1000.0f); + c *= powr(12.0f, gamma) / peak; + c /= powr(get_luma_dst(c), (gamma - 1.0f) / gamma); + return c; +} + +float inverse_eotf_bt1886(float c) { + return c < 0.0f ? 0.0f : powr(c, 1.0f / 2.4f); +} + +float oetf_bt709(float c) { + c = c < 0.0f ? 0.0f : c; + float r1 = 4.5f * c; + float r2 = 1.099f * powr(c, 0.45f) - 0.099f; + return c < 0.018f ? r1 : r2; +} +float inverse_oetf_bt709(float c) { + float r1 = c / 4.5f; + float r2 = powr((c + 0.099f) / 1.099f, 1.0f / 0.45f); + return c < 0.081f ? r1 : r2; +} + +float3 yuv2rgb(float y, float u, float v) { +#ifdef FULL_RANGE_IN + u -= 0.5f; v -= 0.5f; +#else + y = (y * 255.0f - 16.0f) / 219.0f; + u = (u * 255.0f - 128.0f) / 224.0f; + v = (v * 255.0f - 128.0f) / 224.0f; +#endif + float r = y * rgb_matrix[0] + u * rgb_matrix[1] + v * rgb_matrix[2]; + float g = y * rgb_matrix[3] + u * rgb_matrix[4] + v * rgb_matrix[5]; + float b = y * rgb_matrix[6] + u * rgb_matrix[7] + v * rgb_matrix[8]; + return (float3)(r, g, b); +} + +float3 yuv2lrgb(float3 yuv) { + float3 rgb = yuv2rgb(yuv.x, yuv.y, yuv.z); +#ifdef linearize + float r = linearize(rgb.x); + float g = linearize(rgb.y); + float b = linearize(rgb.z); + return (float3)(r, g, b); +#else + return rgb; +#endif +} + +float3 rgb2yuv(float r, float g, float b) { + float y = r*yuv_matrix[0] + g*yuv_matrix[1] + b*yuv_matrix[2]; + float u = r*yuv_matrix[3] + g*yuv_matrix[4] + b*yuv_matrix[5]; + float v = r*yuv_matrix[6] + g*yuv_matrix[7] + b*yuv_matrix[8]; +#ifdef FULL_RANGE_OUT + u += 0.5f; v += 0.5f; +#else + y = (219.0f * y + 16.0f) / 255.0f; + u = (224.0f * u + 128.0f) / 255.0f; + v = (224.0f * v + 128.0f) / 255.0f; +#endif + return (float3)(y, u, v); +} + +float rgb2y(float r, float g, float b) { + float y = r*yuv_matrix[0] + g*yuv_matrix[1] + b*yuv_matrix[2]; + y = (219.0f * y + 16.0f) / 255.0f; + return y; +} + +float3 lrgb2yuv(float3 c) { +#ifdef delinearize + float r = delinearize(c.x); + float g = delinearize(c.y); + float b = delinearize(c.z); + return rgb2yuv(r, g, b); +#else + return rgb2yuv(c.x, c.y, c.z); +#endif +} + +float lrgb2y(float3 c) { +#ifdef delinearize + float r = delinearize(c.x); + float g = delinearize(c.y); + float b = delinearize(c.z); + return rgb2y(r, g, b); +#else + return rgb2y(c.x, c.y, c.z); +#endif +} + +float3 lrgb2lrgb(float3 c) { +#ifdef RGB2RGB_PASSTHROUGH + return c; +#else + float r = c.x, g = c.y, b = c.z; + float rr = rgb2rgb[0] * r + rgb2rgb[1] * g + rgb2rgb[2] * b; + float gg = rgb2rgb[3] * r + rgb2rgb[4] * g + rgb2rgb[5] * b; + float bb = rgb2rgb[6] * r + rgb2rgb[7] * g + rgb2rgb[8] * b; + return (float3)(rr, gg, bb); +#endif +} + +float3 ootf(float3 c, float peak) { +#ifdef ootf_impl + return ootf_impl(c, peak); +#else + return c; +#endif +} + +float3 inverse_ootf(float3 c, float peak) { +#ifdef inverse_ootf_impl + return inverse_ootf_impl(c, peak); +#else + return c; +#endif +} diff --git a/libavfilter/opencl/convolution.cl b/libavfilter/opencl/convolution.cl index 03ef4eff1..815c77927 100644 --- a/libavfilter/opencl/convolution.cl +++ b/libavfilter/opencl/convolution.cl @@ -43,3 +43,85 @@ __kernel void convolution_global(__write_only image2d_t dst, float4 dstPix = convPix * div + bias; write_imagef(dst, loc, dstPix); } + + +__kernel void sobel_global(__write_only image2d_t dst, + __read_only image2d_t src, + float div, + float bias) +{ + const sampler_t sampler = (CLK_NORMALIZED_COORDS_FALSE | + CLK_ADDRESS_CLAMP_TO_EDGE | + CLK_FILTER_NEAREST); + + int2 loc = (int2)(get_global_id(0), get_global_id(1)); + + float4 sum1 = read_imagef(src, sampler, loc + (int2)(-1,-1)) * -1 + + read_imagef(src, sampler, loc + (int2)( 0,-1)) * -2 + + read_imagef(src, sampler, loc + (int2)( 1,-1)) * -1 + + read_imagef(src, sampler, loc + (int2)(-1, 1)) * 1 + + read_imagef(src, sampler, loc + (int2)( 0, 1)) * 2 + + read_imagef(src, sampler, loc + (int2)( 1, 1)) * 1; + + float4 sum2 = read_imagef(src, sampler, loc + (int2)(-1,-1)) * -1 + + read_imagef(src, sampler, loc + (int2)(-1, 0)) * -2 + + read_imagef(src, sampler, loc + (int2)(-1, 1)) * -1 + + read_imagef(src, sampler, loc + (int2)( 1,-1)) * 1 + + read_imagef(src, sampler, loc + (int2)( 1, 0)) * 2 + + read_imagef(src, sampler, loc + (int2)( 1, 1)) * 1; + + float4 dstPix = hypot(sum1, sum2) * div + bias; + write_imagef(dst, loc, dstPix); +} + +__kernel void prewitt_global(__write_only image2d_t dst, + __read_only image2d_t src, + float div, + float bias) +{ + const sampler_t sampler = (CLK_NORMALIZED_COORDS_FALSE | + CLK_ADDRESS_CLAMP_TO_EDGE | + CLK_FILTER_NEAREST); + + int2 loc = (int2)(get_global_id(0), get_global_id(1)); + + float4 sum1 = read_imagef(src, sampler, loc + (int2)(-1,-1)) * 1 + + read_imagef(src, sampler, loc + (int2)( 0,-1)) * 1 + + read_imagef(src, sampler, loc + (int2)( 1,-1)) * 1 + + read_imagef(src, sampler, loc + (int2)(-1, 1)) * -1 + + read_imagef(src, sampler, loc + (int2)( 0, 1)) * -1 + + read_imagef(src, sampler, loc + (int2)( 1, 1)) * -1; + + float4 sum2 = read_imagef(src, sampler, loc + (int2)(-1,-1)) * 1 + + read_imagef(src, sampler, loc + (int2)(-1, 0)) * 1 + + read_imagef(src, sampler, loc + (int2)(-1, 1)) * 1 + + read_imagef(src, sampler, loc + (int2)( 1,-1)) * -1 + + read_imagef(src, sampler, loc + (int2)( 1, 0)) * -1 + + read_imagef(src, sampler, loc + (int2)( 1, 1)) * -1; + + float4 dstPix = hypot(sum1, sum2) * div + bias; + write_imagef(dst, loc, dstPix); +} + +__kernel void roberts_global(__write_only image2d_t dst, + __read_only image2d_t src, + float div, + float bias) +{ + const sampler_t sampler = (CLK_NORMALIZED_COORDS_FALSE | + CLK_ADDRESS_CLAMP_TO_EDGE | + CLK_FILTER_NEAREST); + + int2 loc = (int2)(get_global_id(0), get_global_id(1)); + + float4 sum1 = read_imagef(src, sampler, loc + (int2)(-1,-1)) * 1 + + read_imagef(src, sampler, loc + (int2)( 0,-1)) * -1; + + + float4 sum2 = read_imagef(src, sampler, loc + (int2)(-1, 0)) * -1 + + read_imagef(src, sampler, loc + (int2)( 0, 0)) * 1; + + + float4 dstPix = hypot(sum1, sum2) * div + bias; + write_imagef(dst, loc, dstPix); +} diff --git a/libavfilter/opencl/neighbor.cl b/libavfilter/opencl/neighbor.cl new file mode 100644 index 000000000..e619af315 --- /dev/null +++ b/libavfilter/opencl/neighbor.cl @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2018 Danil Iashchenko + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +__kernel void erosion_global(__write_only image2d_t dst, + __read_only image2d_t src, + float threshold, + __constant int *coord) +{ + const sampler_t sampler = (CLK_NORMALIZED_COORDS_FALSE | + CLK_ADDRESS_CLAMP_TO_EDGE | + CLK_FILTER_NEAREST); + + int2 loc = (int2)(get_global_id(0), get_global_id(1)); + + float4 px = read_imagef(src, sampler, loc); + float limit = px.x - threshold; + if (limit < 0) { + limit = 0; + } + + for (int i = -1; i <= 1; i++) { + for (int j = -1; j <= 1; j++) { + if (coord[(j + 1) * 3 + (i + 1)] == 1) { + float4 cur = read_imagef(src, sampler, loc + (int2)(i, j)); + if (cur.x < px.x) { + px = cur; + } + } + } + } + if (limit > px.x) { + px = (float4)(limit); + } + write_imagef(dst, loc, px); +} + + +__kernel void dilation_global(__write_only image2d_t dst, + __read_only image2d_t src, + float threshold, + __constant int *coord) +{ + const sampler_t sampler = (CLK_NORMALIZED_COORDS_FALSE | + CLK_ADDRESS_CLAMP_TO_EDGE | + CLK_FILTER_NEAREST); + + int2 loc = (int2)(get_global_id(0), get_global_id(1)); + + float4 px = read_imagef(src, sampler, loc); + float limit = px.x + threshold; + if (limit > 1) { + limit = 1; + } + + for (int i = -1; i <= 1; i++) { + for (int j = -1; j <= 1; j++) { + if (coord[(j + 1) * 3 + (i + 1)] == 1) { + float4 cur = read_imagef(src, sampler, loc + (int2)(i, j)); + if (cur.x > px.x) { + px = cur; + } + } + } + } + if (limit < px.x) { + px = (float4)(limit); + } + write_imagef(dst, loc, px); +} diff --git a/libavfilter/opencl/nlmeans.cl b/libavfilter/opencl/nlmeans.cl new file mode 100644 index 000000000..72bd681fd --- /dev/null +++ b/libavfilter/opencl/nlmeans.cl @@ -0,0 +1,115 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +const sampler_t sampler = (CLK_NORMALIZED_COORDS_FALSE | + CLK_ADDRESS_CLAMP_TO_EDGE | + CLK_FILTER_NEAREST); + +kernel void horiz_sum(__global uint4 *integral_img, + __read_only image2d_t src, + int width, + int height, + int4 dx, + int4 dy) +{ + + int y = get_global_id(0); + int work_size = get_global_size(0); + + uint4 sum = (uint4)(0); + float4 s2; + for (int i = 0; i < width; i++) { + float s1 = read_imagef(src, sampler, (int2)(i, y)).x; + s2.x = read_imagef(src, sampler, (int2)(i + dx.x, y + dy.x)).x; + s2.y = read_imagef(src, sampler, (int2)(i + dx.y, y + dy.y)).x; + s2.z = read_imagef(src, sampler, (int2)(i + dx.z, y + dy.z)).x; + s2.w = read_imagef(src, sampler, (int2)(i + dx.w, y + dy.w)).x; + sum += convert_uint4((s1 - s2) * (s1 - s2) * 255 * 255); + integral_img[y * width + i] = sum; + } +} + +kernel void vert_sum(__global uint4 *integral_img, + __global int *overflow, + int width, + int height) +{ + int x = get_global_id(0); + uint4 sum = 0; + for (int i = 0; i < height; i++) { + if (any((uint4)UINT_MAX - integral_img[i * width + x] < sum)) + atomic_inc(overflow); + integral_img[i * width + x] += sum; + sum = integral_img[i * width + x]; + } +} + +kernel void weight_accum(global float *sum, global float *weight, + global uint4 *integral_img, __read_only image2d_t src, + int width, int height, int p, float h, + int4 dx, int4 dy) +{ + // w(x) = integral_img(x-p, y-p) + + // integral_img(x+p, y+p) - + // integral_img(x+p, y-p) - + // integral_img(x-p, y+p) + // total_sum[x] += w(x, y) * src(x + dx, y + dy) + // total_weight += w(x, y) + + int x = get_global_id(0); + int y = get_global_id(1); + int4 xoff = x + dx; + int4 yoff = y + dy; + uint4 a = 0, b = 0, c = 0, d = 0; + uint4 src_pix = 0; + + // out-of-bounding-box? + int oobb = (x - p) < 0 || (y - p) < 0 || (y + p) >= height || (x + p) >= width; + + src_pix.x = (int)(255 * read_imagef(src, sampler, (int2)(xoff.x, yoff.x)).x); + src_pix.y = (int)(255 * read_imagef(src, sampler, (int2)(xoff.y, yoff.y)).x); + src_pix.z = (int)(255 * read_imagef(src, sampler, (int2)(xoff.z, yoff.z)).x); + src_pix.w = (int)(255 * read_imagef(src, sampler, (int2)(xoff.w, yoff.w)).x); + if (!oobb) { + a = integral_img[(y - p) * width + x - p]; + b = integral_img[(y + p) * width + x - p]; + c = integral_img[(y - p) * width + x + p]; + d = integral_img[(y + p) * width + x + p]; + } + + float4 patch_diff = convert_float4(d + a - c - b); + float4 w = native_exp(-patch_diff / (h * h)); + float w_sum = w.x + w.y + w.z + w.w; + weight[y * width + x] += w_sum; + sum[y * width + x] += dot(w, convert_float4(src_pix)); +} + +kernel void average(__write_only image2d_t dst, + __read_only image2d_t src, + global float *sum, global float *weight) { + int x = get_global_id(0); + int y = get_global_id(1); + int2 dim = get_image_dim(dst); + + float w = weight[y * dim.x + x]; + float s = sum[y * dim.x + x]; + float src_pix = read_imagef(src, sampler, (int2)(x, y)).x; + float r = (s + src_pix * 255) / (1.0f + w) / 255.0f; + if (x < dim.x && y < dim.y) + write_imagef(dst, (int2)(x, y), (float4)(r, 0.0f, 0.0f, 1.0f)); +} diff --git a/libavfilter/opencl/tonemap.cl b/libavfilter/opencl/tonemap.cl new file mode 100644 index 000000000..9448ba455 --- /dev/null +++ b/libavfilter/opencl/tonemap.cl @@ -0,0 +1,272 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#define REFERENCE_WHITE 100.0f +extern float3 lrgb2yuv(float3); +extern float lrgb2y(float3); +extern float3 yuv2lrgb(float3); +extern float3 lrgb2lrgb(float3); +extern float get_luma_src(float3); +extern float get_luma_dst(float3); +extern float3 ootf(float3 c, float peak); +extern float3 inverse_ootf(float3 c, float peak); +extern float3 get_chroma_sample(float3, float3, float3, float3); + +struct detection_result { + float peak; + float average; +}; + +float hable_f(float in) { + float a = 0.15f, b = 0.50f, c = 0.10f, d = 0.20f, e = 0.02f, f = 0.30f; + return (in * (in * a + b * c) + d * e) / (in * (in * a + b) + d * f) - e / f; +} + +float direct(float s, float peak) { + return s; +} + +float linear(float s, float peak) { + return s * tone_param / peak; +} + +float gamma(float s, float peak) { + float p = s > 0.05f ? s /peak : 0.05f / peak; + float v = powr(p, 1.0f / tone_param); + return s > 0.05f ? v : (s * v /0.05f); +} + +float clip(float s, float peak) { + return clamp(s * tone_param, 0.0f, 1.0f); +} + +float reinhard(float s, float peak) { + return s / (s + tone_param) * (peak + tone_param) / peak; +} + +float hable(float s, float peak) { + return hable_f(s)/hable_f(peak); +} + +float mobius(float s, float peak) { + float j = tone_param; + float a, b; + + if (s <= j) + return s; + + a = -j * j * (peak - 1.0f) / (j * j - 2.0f * j + peak); + b = (j * j - 2.0f * j * peak + peak) / max(peak - 1.0f, 1e-6f); + + return (b * b + 2.0f * b * j + j * j) / (b - a) * (s + a) / (s + b); +} + +// detect peak/average signal of a frame, the algorithm was ported from: +// libplacebo (https://github.com/haasn/libplacebo) +struct detection_result +detect_peak_avg(global uint *util_buf, __local uint *sum_wg, + float signal, float peak) { +// layout of the util buffer +// +// Name: : Size (units of 4-bytes) +// average buffer : detection_frames + 1 +// peak buffer : detection_frames + 1 +// workgroup counter : 1 +// total of peak : 1 +// total of average : 1 +// frame index : 1 +// frame number : 1 + global uint *avg_buf = util_buf; + global uint *peak_buf = avg_buf + DETECTION_FRAMES + 1; + global uint *counter_wg_p = peak_buf + DETECTION_FRAMES + 1; + global uint *max_total_p = counter_wg_p + 1; + global uint *avg_total_p = max_total_p + 1; + global uint *frame_idx_p = avg_total_p + 1; + global uint *scene_frame_num_p = frame_idx_p + 1; + + uint frame_idx = *frame_idx_p; + uint scene_frame_num = *scene_frame_num_p; + + size_t lidx = get_local_id(0); + size_t lidy = get_local_id(1); + size_t lsizex = get_local_size(0); + size_t lsizey = get_local_size(1); + uint num_wg = get_num_groups(0) * get_num_groups(1); + size_t group_idx = get_group_id(0); + size_t group_idy = get_group_id(1); + struct detection_result r = {peak, sdr_avg}; + if (lidx == 0 && lidy == 0) + *sum_wg = 0; + barrier(CLK_LOCAL_MEM_FENCE); + + // update workgroup sum + atomic_add(sum_wg, (uint)(signal * REFERENCE_WHITE)); + barrier(CLK_LOCAL_MEM_FENCE); + + // update frame peak/avg using work-group-average. + if (lidx == 0 && lidy == 0) { + uint avg_wg = *sum_wg / (lsizex * lsizey); + atomic_max(&peak_buf[frame_idx], avg_wg); + atomic_add(&avg_buf[frame_idx], avg_wg); + } + + if (scene_frame_num > 0) { + float peak = (float)*max_total_p / (REFERENCE_WHITE * scene_frame_num); + float avg = (float)*avg_total_p / (REFERENCE_WHITE * scene_frame_num); + r.peak = max(1.0f, peak); + r.average = max(0.25f, avg); + } + + if (lidx == 0 && lidy == 0 && atomic_add(counter_wg_p, 1) == num_wg - 1) { + *counter_wg_p = 0; + avg_buf[frame_idx] /= num_wg; + + if (scene_threshold > 0.0f) { + uint cur_max = peak_buf[frame_idx]; + uint cur_avg = avg_buf[frame_idx]; + int diff = (int)(scene_frame_num * cur_avg) - (int)*avg_total_p; + + if (abs(diff) > scene_frame_num * scene_threshold * REFERENCE_WHITE) { + for (uint i = 0; i < DETECTION_FRAMES + 1; i++) + avg_buf[i] = 0; + for (uint i = 0; i < DETECTION_FRAMES + 1; i++) + peak_buf[i] = 0; + *avg_total_p = *max_total_p = 0; + *scene_frame_num_p = 0; + avg_buf[frame_idx] = cur_avg; + peak_buf[frame_idx] = cur_max; + } + } + uint next = (frame_idx + 1) % (DETECTION_FRAMES + 1); + // add current frame, subtract next frame + *max_total_p += peak_buf[frame_idx] - peak_buf[next]; + *avg_total_p += avg_buf[frame_idx] - avg_buf[next]; + // reset next frame + peak_buf[next] = avg_buf[next] = 0; + *frame_idx_p = next; + *scene_frame_num_p = min(*scene_frame_num_p + 1, + (uint)DETECTION_FRAMES); + } + return r; +} + +float3 map_one_pixel_rgb(float3 rgb, float peak, float average) { + float sig = max(max(rgb.x, max(rgb.y, rgb.z)), 1e-6f); + + // Rescale the variables in order to bring it into a representation where + // 1.0 represents the dst_peak. This is because all of the tone mapping + // algorithms are defined in such a way that they map to the range [0.0, 1.0]. + if (target_peak > 1.0f) { + sig *= 1.0f / target_peak; + peak *= 1.0f / target_peak; + } + + float sig_old = sig; + + // Scale the signal to compensate for differences in the average brightness + float slope = min(1.0f, sdr_avg / average); + sig *= slope; + peak *= slope; + + // Desaturate the color using a coefficient dependent on the signal level + if (desat_param > 0.0f) { + float luma = get_luma_dst(rgb); + float coeff = max(sig - 0.18f, 1e-6f) / max(sig, 1e-6f); + coeff = native_powr(coeff, 10.0f / desat_param); + rgb = mix(rgb, (float3)luma, (float3)coeff); + sig = mix(sig, luma * slope, coeff); + } + + sig = TONE_FUNC(sig, peak); + + sig = min(sig, 1.0f); + rgb *= (sig/sig_old); + return rgb; +} +// map from source space YUV to destination space RGB +float3 map_to_dst_space_from_yuv(float3 yuv, float peak) { + float3 c = yuv2lrgb(yuv); + c = ootf(c, peak); + c = lrgb2lrgb(c); + return c; +} + +__kernel void tonemap(__write_only image2d_t dst1, + __read_only image2d_t src1, + __write_only image2d_t dst2, + __read_only image2d_t src2, + global uint *util_buf, + float peak + ) +{ + __local uint sum_wg; + const sampler_t sampler = (CLK_NORMALIZED_COORDS_FALSE | + CLK_ADDRESS_CLAMP_TO_EDGE | + CLK_FILTER_NEAREST); + int xi = get_global_id(0); + int yi = get_global_id(1); + // each work item process four pixels + int x = 2 * xi; + int y = 2 * yi; + + float y0 = read_imagef(src1, sampler, (int2)(x, y)).x; + float y1 = read_imagef(src1, sampler, (int2)(x + 1, y)).x; + float y2 = read_imagef(src1, sampler, (int2)(x, y + 1)).x; + float y3 = read_imagef(src1, sampler, (int2)(x + 1, y + 1)).x; + float2 uv = read_imagef(src2, sampler, (int2)(xi, yi)).xy; + + float3 c0 = map_to_dst_space_from_yuv((float3)(y0, uv.x, uv.y), peak); + float3 c1 = map_to_dst_space_from_yuv((float3)(y1, uv.x, uv.y), peak); + float3 c2 = map_to_dst_space_from_yuv((float3)(y2, uv.x, uv.y), peak); + float3 c3 = map_to_dst_space_from_yuv((float3)(y3, uv.x, uv.y), peak); + + float sig0 = max(c0.x, max(c0.y, c0.z)); + float sig1 = max(c1.x, max(c1.y, c1.z)); + float sig2 = max(c2.x, max(c2.y, c2.z)); + float sig3 = max(c3.x, max(c3.y, c3.z)); + float sig = max(sig0, max(sig1, max(sig2, sig3))); + + struct detection_result r = detect_peak_avg(util_buf, &sum_wg, sig, peak); + + float3 c0_old = c0, c1_old = c1, c2_old = c2; + c0 = map_one_pixel_rgb(c0, r.peak, r.average); + c1 = map_one_pixel_rgb(c1, r.peak, r.average); + c2 = map_one_pixel_rgb(c2, r.peak, r.average); + c3 = map_one_pixel_rgb(c3, r.peak, r.average); + + c0 = inverse_ootf(c0, target_peak); + c1 = inverse_ootf(c1, target_peak); + c2 = inverse_ootf(c2, target_peak); + c3 = inverse_ootf(c3, target_peak); + + y0 = lrgb2y(c0); + y1 = lrgb2y(c1); + y2 = lrgb2y(c2); + y3 = lrgb2y(c3); + float3 chroma_c = get_chroma_sample(c0, c1, c2, c3); + float3 chroma = lrgb2yuv(chroma_c); + + if (xi < get_image_width(dst2) && yi < get_image_height(dst2)) { + write_imagef(dst1, (int2)(x, y), (float4)(y0, 0.0f, 0.0f, 1.0f)); + write_imagef(dst1, (int2)(x+1, y), (float4)(y1, 0.0f, 0.0f, 1.0f)); + write_imagef(dst1, (int2)(x, y+1), (float4)(y2, 0.0f, 0.0f, 1.0f)); + write_imagef(dst1, (int2)(x+1, y+1), (float4)(y3, 0.0f, 0.0f, 1.0f)); + write_imagef(dst2, (int2)(xi, yi), + (float4)(chroma.y, chroma.z, 0.0f, 1.0f)); + } +} diff --git a/libavfilter/opencl/transpose.cl b/libavfilter/opencl/transpose.cl new file mode 100644 index 000000000..e6388aba8 --- /dev/null +++ b/libavfilter/opencl/transpose.cl @@ -0,0 +1,35 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +kernel void transpose(__write_only image2d_t dst, + __read_only image2d_t src, + int dir) { + const sampler_t sampler = (CLK_NORMALIZED_COORDS_FALSE | + CLK_ADDRESS_CLAMP_TO_EDGE | + CLK_FILTER_NEAREST); + + int2 size = get_image_dim(dst); + int x = get_global_id(0); + int y = get_global_id(1); + + int xin = (dir & 2) ? (size.y - 1 - y) : y; + int yin = (dir & 1) ? (size.x - 1 - x) : x; + float4 data = read_imagef(src, sampler, (int2)(xin, yin)); + + if (x < size.x && y < size.y) + write_imagef(dst, (int2)(x, y), data); +} diff --git a/libavfilter/opencl_source.h b/libavfilter/opencl_source.h index 4bb996924..1a6cd7ca7 100644 --- a/libavfilter/opencl_source.h +++ b/libavfilter/opencl_source.h @@ -20,8 +20,14 @@ #define AVFILTER_OPENCL_SOURCE_H extern const char *ff_opencl_source_avgblur; +extern const char *ff_opencl_source_colorkey; +extern const char *ff_opencl_source_colorspace_common; extern const char *ff_opencl_source_convolution; +extern const char *ff_opencl_source_neighbor; +extern const char *ff_opencl_source_nlmeans; extern const char *ff_opencl_source_overlay; +extern const char *ff_opencl_source_tonemap; +extern const char *ff_opencl_source_transpose; extern const char *ff_opencl_source_unsharp; #endif /* AVFILTER_OPENCL_SOURCE_H */ diff --git a/libavfilter/qsvvpp.c b/libavfilter/qsvvpp.c index 2c0129562..8d5ff2eb6 100644 --- a/libavfilter/qsvvpp.c +++ b/libavfilter/qsvvpp.c @@ -142,7 +142,7 @@ static int pix_fmt_to_mfx_fourcc(int format) return MFX_FOURCC_NV12; case AV_PIX_FMT_YUYV422: return MFX_FOURCC_YUY2; - case AV_PIX_FMT_RGB32: + case AV_PIX_FMT_BGRA: return MFX_FOURCC_RGB4; } @@ -153,6 +153,7 @@ static int map_frame_to_surface(AVFrame *frame, mfxFrameSurface1 *surface) { switch (frame->format) { case AV_PIX_FMT_NV12: + case AV_PIX_FMT_P010: surface->Data.Y = frame->data[0]; surface->Data.UV = frame->data[1]; break; @@ -316,7 +317,6 @@ static QSVFrame *submit_frame(QSVVPPContext *s, AVFilterLink *inlink, AVFrame *p } av_frame_copy_props(qsv_frame->frame, picref); - av_frame_free(&picref); } else qsv_frame->frame = av_frame_clone(picref); @@ -461,6 +461,8 @@ static int init_vpp_session(AVFilterContext *avctx, QSVVPPContext *s) out_frames_ctx->height = FFALIGN(outlink->h, 32); out_frames_ctx->sw_format = s->out_sw_format; out_frames_ctx->initial_pool_size = 64; + if (avctx->extra_hw_frames > 0) + out_frames_ctx->initial_pool_size += avctx->extra_hw_frames; out_frames_hwctx->frame_type = s->out_mem_mode; ret = av_hwframe_ctx_init(out_frames_ref); @@ -503,6 +505,11 @@ static int init_vpp_session(AVFilterContext *avctx, QSVVPPContext *s) } } + if (ret != MFX_ERR_NONE) { + av_log(avctx, AV_LOG_ERROR, "Error getting the session handle\n"); + return AVERROR_UNKNOWN; + } + /* create a "slave" session with those same properties, to be used for vpp */ ret = MFXInit(impl, &ver, &s->session); if (ret != MFX_ERR_NONE) { diff --git a/libavfilter/qsvvpp.h b/libavfilter/qsvvpp.h index ff02b64c4..c2bcce754 100644 --- a/libavfilter/qsvvpp.h +++ b/libavfilter/qsvvpp.h @@ -36,8 +36,8 @@ MFX_VERSION_MAJOR == (MAJOR) && MFX_VERSION_MINOR >= (MINOR)) #define QSV_RUNTIME_VERSION_ATLEAST(MFX_VERSION, MAJOR, MINOR) \ - (MFX_VERSION.Major > (MAJOR)) || \ - (MFX_VERSION.Major == (MAJOR) && MFX_VERSION.Minor >= (MINOR)) + ((MFX_VERSION.Major > (MAJOR)) || \ + (MFX_VERSION.Major == (MAJOR) && MFX_VERSION.Minor >= (MINOR))) typedef struct QSVVPPContext QSVVPPContext; diff --git a/libavfilter/scene_sad.c b/libavfilter/scene_sad.c new file mode 100644 index 000000000..73d3eacbf --- /dev/null +++ b/libavfilter/scene_sad.c @@ -0,0 +1,72 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * Scene SAD functions + */ + +#include "scene_sad.h" + +void ff_scene_sad16_c(SCENE_SAD_PARAMS) +{ + uint64_t sad = 0; + const uint16_t *src1w = (const uint16_t *)src1; + const uint16_t *src2w = (const uint16_t *)src2; + int x, y; + + stride1 /= 2; + stride2 /= 2; + + for (y = 0; y < height; y++) { + for (x = 0; x < width; x++) + sad += FFABS(src1w[x] - src2w[x]); + src1w += stride1; + src2w += stride2; + } + *sum = sad; +} + +void ff_scene_sad_c(SCENE_SAD_PARAMS) +{ + uint64_t sad = 0; + int x, y; + + for (y = 0; y < height; y++) { + for (x = 0; x < width; x++) + sad += FFABS(src1[x] - src2[x]); + src1 += stride1; + src2 += stride2; + } + *sum = sad; +} + +ff_scene_sad_fn ff_scene_sad_get_fn(int depth) +{ + ff_scene_sad_fn sad = NULL; + if (ARCH_X86) + sad = ff_scene_sad_get_fn_x86(depth); + if (!sad) { + if (depth == 8) + sad = ff_scene_sad_c; + if (depth == 16) + sad = ff_scene_sad16_c; + } + return sad; +} + diff --git a/libavfilter/scene_sad.h b/libavfilter/scene_sad.h new file mode 100644 index 000000000..173a051f2 --- /dev/null +++ b/libavfilter/scene_sad.h @@ -0,0 +1,44 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * Scene SAD functions + */ + +#ifndef AVFILTER_SCENE_SAD_H +#define AVFILTER_SCENE_SAD_H + +#include "avfilter.h" + +#define SCENE_SAD_PARAMS const uint8_t *src1, ptrdiff_t stride1, \ + const uint8_t *src2, ptrdiff_t stride2, \ + ptrdiff_t width, ptrdiff_t height, \ + uint64_t *sum + +typedef void (*ff_scene_sad_fn)(SCENE_SAD_PARAMS); + +void ff_scene_sad_c(SCENE_SAD_PARAMS); + +void ff_scene_sad16_c(SCENE_SAD_PARAMS); + +ff_scene_sad_fn ff_scene_sad_get_fn_x86(int depth); + +ff_scene_sad_fn ff_scene_sad_get_fn(int depth); + +#endif /* AVFILTER_SCENE_SAD_H */ diff --git a/libavfilter/setpts.c b/libavfilter/setpts.c index 4505498bf..800ba6a83 100644 --- a/libavfilter/setpts.c +++ b/libavfilter/setpts.c @@ -57,6 +57,7 @@ static const char *const var_names[] = { "RTCSTART", ///< wallclock (RTC) time at the start of the movie in micro seconds "S", // Number of samples in the current frame "SR", // Audio sample rate + "FR", ///< defined only for constant frame-rate video NULL }; @@ -81,6 +82,7 @@ enum var_name { VAR_RTCSTART, VAR_S, VAR_SR, + VAR_FR, VAR_VARS_NB }; @@ -127,7 +129,8 @@ static int config_input(AVFilterLink *inlink) setpts->var_values[VAR_SAMPLE_RATE] = setpts->type == AVMEDIA_TYPE_AUDIO ? inlink->sample_rate : NAN; - setpts->var_values[VAR_FRAME_RATE] = inlink->frame_rate.num && + setpts->var_values[VAR_FRAME_RATE] = + setpts->var_values[VAR_FR] = inlink->frame_rate.num && inlink->frame_rate.den ? av_q2d(inlink->frame_rate) : NAN; diff --git a/libavfilter/split.c b/libavfilter/split.c index 8b260a9ba..89af360cb 100644 --- a/libavfilter/split.c +++ b/libavfilter/split.c @@ -30,11 +30,9 @@ #include "libavutil/mem.h" #include "libavutil/opt.h" -#define FF_INTERNAL_FIELDS 1 -#include "framequeue.h" - #include "avfilter.h" #include "audio.h" +#include "filters.h" #include "formats.h" #include "internal.h" #include "video.h" @@ -84,7 +82,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame) for (i = 0; i < ctx->nb_outputs; i++) { AVFrame *buf_out; - if (ctx->outputs[i]->status_in) + if (ff_outlink_get_status(ctx->outputs[i])) continue; buf_out = av_frame_clone(frame); if (!buf_out) { diff --git a/libavfilter/tests/filtfmts.c b/libavfilter/tests/filtfmts.c index a958621f1..317df86c5 100644 --- a/libavfilter/tests/filtfmts.c +++ b/libavfilter/tests/filtfmts.c @@ -138,9 +138,9 @@ int main(int argc, char **argv) } if (filter->query_formats) - filter->query_formats(filter_ctx); + ret = filter->query_formats(filter_ctx); else - ff_default_query_formats(filter_ctx); + ret = ff_default_query_formats(filter_ctx); print_formats(filter_ctx); diff --git a/libavfilter/tests/integral.c b/libavfilter/tests/integral.c index 049fefae8..03b1e7736 100644 --- a/libavfilter/tests/integral.c +++ b/libavfilter/tests/integral.c @@ -33,8 +33,11 @@ static void display_integral(const uint32_t *ii, int w, int h, int lz_32) int main(void) { int ret = 0, xoff, yoff; + uint32_t *ii_start; + uint32_t *ii_start2; + NLMeansDSPContext dsp = {0}; - // arbitrary test source of size 6x4 and linesize=8 + // arbitrary test source of size 6x5 and linesize=8 const int w = 6, h = 5, lz = 8; static const uint8_t src[] = { 0xb0, 0x71, 0xfb, 0xd8, 0x01, 0xd9, /***/ 0x01, 0x02, @@ -54,17 +57,19 @@ int main(void) uint32_t *ii = av_mallocz_array(ii_h + 1, ii_lz_32 * sizeof(*ii)); uint32_t *ii2 = av_mallocz_array(ii_h + 1, ii_lz_32 * sizeof(*ii2)); - uint32_t *ii_start = ii + ii_lz_32 + 1; // skip top 0-line and left 0-column - uint32_t *ii_start2 = ii2 + ii_lz_32 + 1; // skip top 0-line and left 0-column - if (!ii || !ii2) return -1; + ii_start = ii + ii_lz_32 + 1; // skip top 0-line and left 0-column + ii_start2 = ii2 + ii_lz_32 + 1; // skip top 0-line and left 0-column + + ff_nlmeans_init(&dsp); + for (yoff = -e; yoff <= e; yoff++) { for (xoff = -e; xoff <= e; xoff++) { printf("xoff=%d yoff=%d\n", xoff, yoff); - compute_ssd_integral_image(ii_start, ii_lz_32, + compute_ssd_integral_image(&dsp, ii_start, ii_lz_32, src, lz, xoff, yoff, e, w, h); display_integral(ii_start, ii_w, ii_h, ii_lz_32); diff --git a/libavfilter/tinterlace.h b/libavfilter/tinterlace.h index b5c39aac5..5bcb9a583 100644 --- a/libavfilter/tinterlace.h +++ b/libavfilter/tinterlace.h @@ -34,8 +34,8 @@ #include "avfilter.h" #define TINTERLACE_FLAG_VLPF 01 -#define TINTERLACE_FLAG_EXACT_TB 2 -#define TINTERLACE_FLAG_CVLPF 4 +#define TINTERLACE_FLAG_CVLPF 2 +#define TINTERLACE_FLAG_EXACT_TB 4 enum TInterlaceMode { MODE_MERGE = 0, @@ -49,6 +49,11 @@ enum TInterlaceMode { MODE_NB, }; +enum InterlaceScanMode { + MODE_TFF = 0, + MODE_BFF, +}; + typedef struct TInterlaceContext { const AVClass *class; int mode; ///< TInterlaceMode, interlace mode selected diff --git a/libavfilter/transpose.h b/libavfilter/transpose.h new file mode 100644 index 000000000..aa262b948 --- /dev/null +++ b/libavfilter/transpose.h @@ -0,0 +1,37 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +#ifndef AVFILTER_TRANSPOSE_H +#define AVFILTER_TRANSPOSE_H + +enum PassthroughType { + TRANSPOSE_PT_TYPE_NONE, + TRANSPOSE_PT_TYPE_LANDSCAPE, + TRANSPOSE_PT_TYPE_PORTRAIT, +}; + +enum TransposeDir { + TRANSPOSE_CCLOCK_FLIP, + TRANSPOSE_CLOCK, + TRANSPOSE_CCLOCK, + TRANSPOSE_CLOCK_FLIP, + TRANSPOSE_REVERSAL, // rotate by half-turn + TRANSPOSE_HFLIP, + TRANSPOSE_VFLIP, +}; + +#endif diff --git a/libavfilter/unsharp.h b/libavfilter/unsharp.h index caff986fc..a60b30f31 100644 --- a/libavfilter/unsharp.h +++ b/libavfilter/unsharp.h @@ -37,7 +37,8 @@ typedef struct UnsharpFilterParam { int steps_y; ///< vertical step count int scalebits; ///< bits to shift pixel int32_t halfscale; ///< amount to add to pixel - uint32_t *sc[MAX_MATRIX_SIZE - 1]; ///< finite state machine storage + uint32_t *sr; ///< finite state machine storage within a row + uint32_t **sc; ///< finite state machine storage across rows } UnsharpFilterParam; typedef struct UnsharpContext { @@ -47,6 +48,7 @@ typedef struct UnsharpContext { UnsharpFilterParam luma; ///< luma parameters (width, height, amount) UnsharpFilterParam chroma; ///< chroma parameters (width, height, amount) int hsub, vsub; + int nb_threads; int opencl; int (* apply_unsharp)(AVFilterContext *ctx, AVFrame *in, AVFrame *out); } UnsharpContext; diff --git a/libavfilter/vaapi_vpp.c b/libavfilter/vaapi_vpp.c index c5bbc3b85..b5b245c8a 100644 --- a/libavfilter/vaapi_vpp.c +++ b/libavfilter/vaapi_vpp.c @@ -234,18 +234,330 @@ fail: return err; } -int ff_vaapi_vpp_colour_standard(enum AVColorSpace av_cs) +typedef struct VAAPIColourProperties { + VAProcColorStandardType va_color_standard; + + enum AVColorPrimaries color_primaries; + enum AVColorTransferCharacteristic color_trc; + enum AVColorSpace colorspace; + + uint8_t va_chroma_sample_location; + uint8_t va_color_range; + + enum AVColorRange color_range; + enum AVChromaLocation chroma_sample_location; +} VAAPIColourProperties; + +static const VAAPIColourProperties vaapi_colour_standard_map[] = { + { VAProcColorStandardBT601, 5, 6, 5 }, + { VAProcColorStandardBT601, 6, 6, 6 }, + { VAProcColorStandardBT709, 1, 1, 1 }, + { VAProcColorStandardBT470M, 4, 4, 4 }, + { VAProcColorStandardBT470BG, 5, 5, 5 }, + { VAProcColorStandardSMPTE170M, 6, 6, 6 }, + { VAProcColorStandardSMPTE240M, 7, 7, 7 }, + { VAProcColorStandardGenericFilm, 8, 1, 1 }, +#if VA_CHECK_VERSION(1, 1, 0) + { VAProcColorStandardSRGB, 1, 13, 0 }, + { VAProcColorStandardXVYCC601, 1, 11, 5 }, + { VAProcColorStandardXVYCC709, 1, 11, 1 }, + { VAProcColorStandardBT2020, 9, 14, 9 }, +#endif +}; + +static void vaapi_vpp_fill_colour_standard(VAAPIColourProperties *props, + VAProcColorStandardType *vacs, + int nb_vacs) { - switch(av_cs) { -#define CS(av, va) case AVCOL_SPC_ ## av: return VAProcColorStandard ## va; - CS(BT709, BT709); - CS(BT470BG, BT601); - CS(SMPTE170M, SMPTE170M); - CS(SMPTE240M, SMPTE240M); -#undef CS - default: - return VAProcColorStandardNone; + const VAAPIColourProperties *t; + int i, j, score, best_score, worst_score; + VAProcColorStandardType best_standard; + +#if VA_CHECK_VERSION(1, 3, 0) + // If the driver supports explicit use of the standard values then just + // use them and avoid doing any mapping. (The driver may not support + // some particular code point, but it still has enough information to + // make a better fallback choice than we do in that case.) + for (i = 0; i < nb_vacs; i++) { + if (vacs[i] == VAProcColorStandardExplicit) { + props->va_color_standard = VAProcColorStandardExplicit; + return; + } } +#endif + + // Give scores to the possible options and choose the lowest one. + // An exact match will score zero and therefore always be chosen, as + // will a partial match where all unmatched elements are explicitly + // unspecified. If no options match at all then just pass "none" to + // the driver and let it make its own choice. + best_standard = VAProcColorStandardNone; + best_score = -1; + worst_score = 4 * (props->colorspace != AVCOL_SPC_UNSPECIFIED && + props->colorspace != AVCOL_SPC_RGB) + + 2 * (props->color_trc != AVCOL_TRC_UNSPECIFIED) + + (props->color_primaries != AVCOL_PRI_UNSPECIFIED); + + if (worst_score == 0) { + // No properties are specified, so we aren't going to be able to + // make a useful choice. + props->va_color_standard = VAProcColorStandardNone; + return; + } + + for (i = 0; i < nb_vacs; i++) { + for (j = 0; j < FF_ARRAY_ELEMS(vaapi_colour_standard_map); j++) { + t = &vaapi_colour_standard_map[j]; + if (t->va_color_standard != vacs[i]) + continue; + + score = 0; + if (props->colorspace != AVCOL_SPC_UNSPECIFIED && + props->colorspace != AVCOL_SPC_RGB) + score += 4 * (props->colorspace != t->colorspace); + if (props->color_trc != AVCOL_TRC_UNSPECIFIED) + score += 2 * (props->color_trc != t->color_trc); + if (props->color_primaries != AVCOL_PRI_UNSPECIFIED) + score += (props->color_primaries != t->color_primaries); + + // Only include choices which matched something. + if (score < worst_score && + (best_score == -1 || score < best_score)) { + best_score = score; + best_standard = t->va_color_standard; + } + } + } + props->va_color_standard = best_standard; +} + +static void vaapi_vpp_fill_chroma_sample_location(VAAPIColourProperties *props) +{ +#if VA_CHECK_VERSION(1, 1, 0) + static const struct { + enum AVChromaLocation av; + uint8_t va; + } csl_map[] = { + { AVCHROMA_LOC_UNSPECIFIED, VA_CHROMA_SITING_UNKNOWN }, + { AVCHROMA_LOC_LEFT, VA_CHROMA_SITING_VERTICAL_CENTER | + VA_CHROMA_SITING_HORIZONTAL_LEFT }, + { AVCHROMA_LOC_CENTER, VA_CHROMA_SITING_VERTICAL_CENTER | + VA_CHROMA_SITING_HORIZONTAL_CENTER }, + { AVCHROMA_LOC_TOPLEFT, VA_CHROMA_SITING_VERTICAL_TOP | + VA_CHROMA_SITING_HORIZONTAL_LEFT }, + { AVCHROMA_LOC_TOP, VA_CHROMA_SITING_VERTICAL_TOP | + VA_CHROMA_SITING_HORIZONTAL_CENTER }, + { AVCHROMA_LOC_BOTTOMLEFT, VA_CHROMA_SITING_VERTICAL_BOTTOM | + VA_CHROMA_SITING_HORIZONTAL_LEFT }, + { AVCHROMA_LOC_BOTTOM, VA_CHROMA_SITING_VERTICAL_BOTTOM | + VA_CHROMA_SITING_HORIZONTAL_CENTER }, + }; + int i; + + for (i = 0; i < FF_ARRAY_ELEMS(csl_map); i++) { + if (props->chroma_sample_location == csl_map[i].av) { + props->va_chroma_sample_location = csl_map[i].va; + return; + } + } + props->va_chroma_sample_location = VA_CHROMA_SITING_UNKNOWN; +#else + props->va_chroma_sample_location = 0; +#endif +} + +static void vaapi_vpp_fill_colour_range(VAAPIColourProperties *props) +{ +#if VA_CHECK_VERSION(1, 1, 0) + switch (props->color_range) { + case AVCOL_RANGE_MPEG: + props->va_color_range = VA_SOURCE_RANGE_REDUCED; + break; + case AVCOL_RANGE_JPEG: + props->va_color_range = VA_SOURCE_RANGE_FULL; + break; + case AVCOL_RANGE_UNSPECIFIED: + default: + props->va_color_range = VA_SOURCE_RANGE_UNKNOWN; + } +#else + props->va_color_range = 0; +#endif +} + +static void vaapi_vpp_fill_colour_properties(AVFilterContext *avctx, + VAAPIColourProperties *props, + VAProcColorStandardType *vacs, + int nb_vacs) +{ + vaapi_vpp_fill_colour_standard(props, vacs, nb_vacs); + vaapi_vpp_fill_chroma_sample_location(props); + vaapi_vpp_fill_colour_range(props); + + av_log(avctx, AV_LOG_DEBUG, "Mapped colour properties %s %s/%s/%s %s " + "to VA standard %d chroma siting %#x range %#x.\n", + av_color_range_name(props->color_range), + av_color_space_name(props->colorspace), + av_color_primaries_name(props->color_primaries), + av_color_transfer_name(props->color_trc), + av_chroma_location_name(props->chroma_sample_location), + props->va_color_standard, + props->va_chroma_sample_location, props->va_color_range); +} + +static int vaapi_vpp_frame_is_rgb(const AVFrame *frame) +{ + const AVHWFramesContext *hwfc; + const AVPixFmtDescriptor *desc; + av_assert0(frame->format == AV_PIX_FMT_VAAPI && + frame->hw_frames_ctx); + hwfc = (const AVHWFramesContext*)frame->hw_frames_ctx->data; + desc = av_pix_fmt_desc_get(hwfc->sw_format); + av_assert0(desc); + return !!(desc->flags & AV_PIX_FMT_FLAG_RGB); +} + +static int vaapi_vpp_colour_properties(AVFilterContext *avctx, + VAProcPipelineParameterBuffer *params, + const AVFrame *input_frame, + AVFrame *output_frame) +{ + VAAPIVPPContext *ctx = avctx->priv; + VAAPIColourProperties input_props, output_props; + VAProcPipelineCaps caps; + VAStatus vas; + + vas = vaQueryVideoProcPipelineCaps(ctx->hwctx->display, ctx->va_context, + ctx->filter_buffers, ctx->nb_filter_buffers, + &caps); + if (vas != VA_STATUS_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to query capabilities for " + "colour standard support: %d (%s).\n", vas, vaErrorStr(vas)); + return AVERROR_EXTERNAL; + } + + input_props = (VAAPIColourProperties) { + .colorspace = vaapi_vpp_frame_is_rgb(input_frame) + ? AVCOL_SPC_RGB : input_frame->colorspace, + .color_primaries = input_frame->color_primaries, + .color_trc = input_frame->color_trc, + .color_range = input_frame->color_range, + .chroma_sample_location = input_frame->chroma_location, + }; + + vaapi_vpp_fill_colour_properties(avctx, &input_props, + caps.input_color_standards, + caps.num_input_color_standards); + + output_props = (VAAPIColourProperties) { + .colorspace = vaapi_vpp_frame_is_rgb(output_frame) + ? AVCOL_SPC_RGB : output_frame->colorspace, + .color_primaries = output_frame->color_primaries, + .color_trc = output_frame->color_trc, + .color_range = output_frame->color_range, + .chroma_sample_location = output_frame->chroma_location, + }; + vaapi_vpp_fill_colour_properties(avctx, &output_props, + caps.output_color_standards, + caps.num_output_color_standards); + + // If the properties weren't filled completely in the output frame and + // we chose a fixed standard then fill the known values in here. +#if VA_CHECK_VERSION(1, 3, 0) + if (output_props.va_color_standard != VAProcColorStandardExplicit) +#endif + { + const VAAPIColourProperties *output_standard = NULL; + int i; + + for (i = 0; i < FF_ARRAY_ELEMS(vaapi_colour_standard_map); i++) { + if (output_props.va_color_standard == + vaapi_colour_standard_map[i].va_color_standard) { + output_standard = &vaapi_colour_standard_map[i]; + break; + } + } + if (output_standard) { + output_frame->colorspace = vaapi_vpp_frame_is_rgb(output_frame) + ? AVCOL_SPC_RGB : output_standard->colorspace; + output_frame->color_primaries = output_standard->color_primaries; + output_frame->color_trc = output_standard->color_trc; + } + } + + params->surface_color_standard = input_props.va_color_standard; + params->output_color_standard = output_props.va_color_standard; + +#if VA_CHECK_VERSION(1, 1, 0) + params->input_color_properties = (VAProcColorProperties) { + .chroma_sample_location = input_props.va_chroma_sample_location, + .color_range = input_props.va_color_range, +#if VA_CHECK_VERSION(1, 3, 0) + .colour_primaries = input_props.color_primaries, + .transfer_characteristics = input_props.color_trc, + .matrix_coefficients = input_props.colorspace, +#endif + }; + params->output_color_properties = (VAProcColorProperties) { + .chroma_sample_location = output_props.va_chroma_sample_location, + .color_range = output_props.va_color_range, +#if VA_CHECK_VERSION(1, 3, 0) + .colour_primaries = output_props.color_primaries, + .transfer_characteristics = output_props.color_trc, + .matrix_coefficients = output_props.colorspace, +#endif + }; +#endif + + return 0; +} + +int ff_vaapi_vpp_init_params(AVFilterContext *avctx, + VAProcPipelineParameterBuffer *params, + const AVFrame *input_frame, + AVFrame *output_frame) +{ + VAAPIVPPContext *ctx = avctx->priv; + VASurfaceID input_surface; + int err; + + ctx->input_region = (VARectangle) { + .x = input_frame->crop_left, + .y = input_frame->crop_top, + .width = input_frame->width - + (input_frame->crop_left + input_frame->crop_right), + .height = input_frame->height - + (input_frame->crop_top + input_frame->crop_bottom), + }; + output_frame->crop_top = 0; + output_frame->crop_bottom = 0; + output_frame->crop_left = 0; + output_frame->crop_right = 0; + + input_surface = (VASurfaceID)(uintptr_t)input_frame->data[3], + + *params = (VAProcPipelineParameterBuffer) { + .surface = input_surface, + .surface_region = &ctx->input_region, + .output_region = NULL, + .output_background_color = VAAPI_VPP_BACKGROUND_BLACK, + .pipeline_flags = 0, + .filter_flags = VA_FRAME_PICTURE, + + // Filter and reference data filled by the filter itself. + +#if VA_CHECK_VERSION(1, 1, 0) + .rotation_state = VA_ROTATION_NONE, + .mirror_state = VA_MIRROR_NONE, +#endif + }; + + err = vaapi_vpp_colour_properties(avctx, params, + input_frame, output_frame); + if (err < 0) + return err; + + return 0; } int ff_vaapi_vpp_make_param_buffers(AVFilterContext *avctx, @@ -279,12 +591,15 @@ int ff_vaapi_vpp_make_param_buffers(AVFilterContext *avctx, int ff_vaapi_vpp_render_picture(AVFilterContext *avctx, VAProcPipelineParameterBuffer *params, - VASurfaceID output_surface) + AVFrame *output_frame) { + VAAPIVPPContext *ctx = avctx->priv; + VASurfaceID output_surface; VABufferID params_id; VAStatus vas; - int err = 0; - VAAPIVPPContext *ctx = avctx->priv; + int err; + + output_surface = (VASurfaceID)(uintptr_t)output_frame->data[3]; vas = vaBeginPicture(ctx->hwctx->display, ctx->va_context, output_surface); diff --git a/libavfilter/vaapi_vpp.h b/libavfilter/vaapi_vpp.h index 0bc31018d..c3da91717 100644 --- a/libavfilter/vaapi_vpp.h +++ b/libavfilter/vaapi_vpp.h @@ -27,6 +27,9 @@ #include "avfilter.h" +// ARGB black, for VAProcPipelineParameterBuffer.output_background_color. +#define VAAPI_VPP_BACKGROUND_BLACK 0xff000000 + typedef struct VAAPIVPPContext { const AVClass *class; @@ -39,6 +42,7 @@ typedef struct VAAPIVPPContext { AVBufferRef *input_frames_ref; AVHWFramesContext *input_frames; + VARectangle input_region; enum AVPixelFormat output_format; int output_width; // computed width @@ -64,7 +68,10 @@ int ff_vaapi_vpp_config_input(AVFilterLink *inlink); int ff_vaapi_vpp_config_output(AVFilterLink *outlink); -int ff_vaapi_vpp_colour_standard(enum AVColorSpace av_cs); +int ff_vaapi_vpp_init_params(AVFilterContext *avctx, + VAProcPipelineParameterBuffer *params, + const AVFrame *input_frame, + AVFrame *output_frame); int ff_vaapi_vpp_make_param_buffers(AVFilterContext *avctx, int type, @@ -74,6 +81,6 @@ int ff_vaapi_vpp_make_param_buffers(AVFilterContext *avctx, int ff_vaapi_vpp_render_picture(AVFilterContext *avctx, VAProcPipelineParameterBuffer *params, - VASurfaceID output_surface); + AVFrame *output_frame); #endif /* AVFILTER_VAAPI_VPP_H */ diff --git a/libavfilter/version.h b/libavfilter/version.h index 87468df53..cc5b23b70 100644 --- a/libavfilter/version.h +++ b/libavfilter/version.h @@ -30,9 +30,10 @@ #include "libavutil/version.h" #define LIBAVFILTER_VERSION_MAJOR 7 -#define LIBAVFILTER_VERSION_MINOR 16 +#define LIBAVFILTER_VERSION_MINOR 57 #define LIBAVFILTER_VERSION_MICRO 100 + #define LIBAVFILTER_VERSION_INT AV_VERSION_INT(LIBAVFILTER_VERSION_MAJOR, \ LIBAVFILTER_VERSION_MINOR, \ LIBAVFILTER_VERSION_MICRO) diff --git a/libavfilter/vf_alphamerge.c b/libavfilter/vf_alphamerge.c index 45fa340fc..c5602b622 100644 --- a/libavfilter/vf_alphamerge.c +++ b/libavfilter/vf_alphamerge.c @@ -28,9 +28,9 @@ #include "libavutil/imgutils.h" #include "libavutil/pixfmt.h" #include "avfilter.h" -#include "bufferqueue.h" #include "drawutils.h" #include "formats.h" +#include "filters.h" #include "internal.h" #include "video.h" @@ -39,17 +39,10 @@ enum { Y, U, V, A }; typedef struct AlphaMergeContext { int is_packed_rgb; uint8_t rgba_map[4]; - struct FFBufQueue queue_main; - struct FFBufQueue queue_alpha; + AVFrame *main_frame; + AVFrame *alpha_frame; } AlphaMergeContext; -static av_cold void uninit(AVFilterContext *ctx) -{ - AlphaMergeContext *merge = ctx->priv; - ff_bufqueue_discard_all(&merge->queue_main); - ff_bufqueue_discard_all(&merge->queue_alpha); -} - static int query_formats(AVFilterContext *ctx) { static const enum AVPixelFormat main_fmts[] = { @@ -140,44 +133,52 @@ static void draw_frame(AVFilterContext *ctx, } } -static int filter_frame(AVFilterLink *inlink, AVFrame *buf) +static int activate(AVFilterContext *ctx) { - AVFilterContext *ctx = inlink->dst; - AlphaMergeContext *merge = ctx->priv; + AVFilterLink *outlink = ctx->outputs[0]; + AlphaMergeContext *s = ctx->priv; + int ret; - int ret = 0; - int is_alpha = (inlink == ctx->inputs[1]); - struct FFBufQueue *queue = - (is_alpha ? &merge->queue_alpha : &merge->queue_main); - ff_bufqueue_add(ctx, queue, buf); + FF_FILTER_FORWARD_STATUS_BACK_ALL(outlink, ctx); - do { - AVFrame *main_buf, *alpha_buf; + if (!s->main_frame) { + ret = ff_inlink_consume_frame(ctx->inputs[0], &s->main_frame); + if (ret < 0) + return ret; + } - if (!ff_bufqueue_peek(&merge->queue_main, 0) || - !ff_bufqueue_peek(&merge->queue_alpha, 0)) break; + if (!s->alpha_frame) { + ret = ff_inlink_consume_frame(ctx->inputs[1], &s->alpha_frame); + if (ret < 0) + return ret; + } - main_buf = ff_bufqueue_get(&merge->queue_main); - alpha_buf = ff_bufqueue_get(&merge->queue_alpha); - - draw_frame(ctx, main_buf, alpha_buf); - ret = ff_filter_frame(ctx->outputs[0], main_buf); - av_frame_free(&alpha_buf); - } while (ret >= 0); - return ret; -} - -static int request_frame(AVFilterLink *outlink) -{ - AVFilterContext *ctx = outlink->src; - AlphaMergeContext *merge = ctx->priv; - int in, ret; - - in = ff_bufqueue_peek(&merge->queue_main, 0) ? 1 : 0; - ret = ff_request_frame(ctx->inputs[in]); - if (ret < 0) + if (s->main_frame && s->alpha_frame) { + draw_frame(ctx, s->main_frame, s->alpha_frame); + ret = ff_filter_frame(outlink, s->main_frame); + av_frame_free(&s->alpha_frame); + s->main_frame = NULL; return ret; - return 0; + } + + FF_FILTER_FORWARD_STATUS(ctx->inputs[0], outlink); + FF_FILTER_FORWARD_STATUS(ctx->inputs[1], outlink); + + if (ff_outlink_frame_wanted(ctx->outputs[0]) && + !ff_outlink_get_status(ctx->inputs[0]) && + !s->main_frame) { + ff_inlink_request_frame(ctx->inputs[0]); + return 0; + } + + if (ff_outlink_frame_wanted(ctx->outputs[0]) && + !ff_outlink_get_status(ctx->inputs[1]) && + !s->alpha_frame) { + ff_inlink_request_frame(ctx->inputs[1]); + return 0; + } + + return FFERROR_NOT_READY; } static const AVFilterPad alphamerge_inputs[] = { @@ -185,12 +186,10 @@ static const AVFilterPad alphamerge_inputs[] = { .name = "main", .type = AVMEDIA_TYPE_VIDEO, .config_props = config_input_main, - .filter_frame = filter_frame, .needs_writable = 1, },{ .name = "alpha", .type = AVMEDIA_TYPE_VIDEO, - .filter_frame = filter_frame, }, { NULL } }; @@ -200,7 +199,6 @@ static const AVFilterPad alphamerge_outputs[] = { .name = "default", .type = AVMEDIA_TYPE_VIDEO, .config_props = config_output, - .request_frame = request_frame, }, { NULL } }; @@ -209,9 +207,9 @@ AVFilter ff_vf_alphamerge = { .name = "alphamerge", .description = NULL_IF_CONFIG_SMALL("Copy the luma value of the second " "input into the alpha channel of the first input."), - .uninit = uninit, .priv_size = sizeof(AlphaMergeContext), .query_formats = query_formats, .inputs = alphamerge_inputs, .outputs = alphamerge_outputs, + .activate = activate, }; diff --git a/libavfilter/vf_amplify.c b/libavfilter/vf_amplify.c new file mode 100644 index 000000000..48dcb93a6 --- /dev/null +++ b/libavfilter/vf_amplify.c @@ -0,0 +1,314 @@ +/* + * Copyright (c) 2018 Paul B Mahol + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/imgutils.h" +#include "libavutil/intreadwrite.h" +#include "libavutil/opt.h" +#include "libavutil/pixdesc.h" + +#include "avfilter.h" +#include "formats.h" +#include "internal.h" +#include "video.h" + +typedef struct AmplifyContext { + const AVClass *class; + const AVPixFmtDescriptor *desc; + int radius; + float factor; + float threshold; + float tolerance; + int planes; + + int llimit; + int hlimit; + int nb_inputs; + int nb_frames; + + int depth; + int nb_planes; + int linesize[4]; + int height[4]; + + AVFrame **frames; +} AmplifyContext; + +static int query_formats(AVFilterContext *ctx) +{ + static const enum AVPixelFormat pixel_fmts[] = { + AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY9, + AV_PIX_FMT_GRAY10, AV_PIX_FMT_GRAY12, AV_PIX_FMT_GRAY14, + AV_PIX_FMT_GRAY16, + AV_PIX_FMT_YUV410P, AV_PIX_FMT_YUV411P, + AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV422P, + AV_PIX_FMT_YUV440P, AV_PIX_FMT_YUV444P, + AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUVJ422P, + AV_PIX_FMT_YUVJ440P, AV_PIX_FMT_YUVJ444P, + AV_PIX_FMT_YUVJ411P, + AV_PIX_FMT_YUV420P9, AV_PIX_FMT_YUV422P9, AV_PIX_FMT_YUV444P9, + AV_PIX_FMT_YUV420P10, AV_PIX_FMT_YUV422P10, AV_PIX_FMT_YUV444P10, + AV_PIX_FMT_YUV440P10, + AV_PIX_FMT_YUV444P12, AV_PIX_FMT_YUV422P12, AV_PIX_FMT_YUV420P12, + AV_PIX_FMT_YUV440P12, + AV_PIX_FMT_YUV444P14, AV_PIX_FMT_YUV422P14, AV_PIX_FMT_YUV420P14, + AV_PIX_FMT_YUV420P16, AV_PIX_FMT_YUV422P16, AV_PIX_FMT_YUV444P16, + AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRP9, AV_PIX_FMT_GBRP10, + AV_PIX_FMT_GBRP12, AV_PIX_FMT_GBRP14, AV_PIX_FMT_GBRP16, + AV_PIX_FMT_NONE + }; + AVFilterFormats *formats = ff_make_format_list(pixel_fmts); + if (!formats) + return AVERROR(ENOMEM); + return ff_set_common_formats(ctx, formats); +} + +static av_cold int init(AVFilterContext *ctx) +{ + AmplifyContext *s = ctx->priv; + + s->nb_inputs = s->radius * 2 + 1; + + s->frames = av_calloc(s->nb_inputs, sizeof(*s->frames)); + if (!s->frames) + return AVERROR(ENOMEM); + + return 0; +} + +typedef struct ThreadData { + AVFrame **in, *out; +} ThreadData; + +static int amplify_frame(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) +{ + AmplifyContext *s = ctx->priv; + ThreadData *td = arg; + AVFrame **in = td->in; + AVFrame *out = td->out; + const int radius = s->radius; + const int nb_inputs = s->nb_inputs; + const float threshold = s->threshold; + const float tolerance = s->tolerance; + const float factor = s->factor; + const int llimit = s->llimit; + const int hlimit = s->hlimit; + const int depth = s->depth; + int i, p, x, y; + + if (s->depth <= 8) { + for (p = 0; p < s->nb_planes; p++) { + const int slice_start = (s->height[p] * jobnr) / nb_jobs; + const int slice_end = (s->height[p] * (jobnr+1)) / nb_jobs; + uint8_t *dst = out->data[p] + slice_start * out->linesize[p]; + + if (!((1 << p) & s->planes)) { + av_image_copy_plane(dst, out->linesize[p], + in[radius]->data[p] + slice_start * in[radius]->linesize[p], + in[radius]->linesize[p], + s->linesize[p], slice_end - slice_start); + continue; + } + + for (y = slice_start; y < slice_end; y++) { + for (x = 0; x < s->linesize[p]; x++) { + int src = in[radius]->data[p][y * in[radius]->linesize[p] + x]; + float diff, avg; + int sum = 0; + + for (i = 0; i < nb_inputs; i++) { + sum += in[i]->data[p][y * in[i]->linesize[p] + x]; + } + + avg = sum / (float)nb_inputs; + diff = src - avg; + if (fabsf(diff) < threshold && fabsf(diff) > tolerance) { + int amp; + if (diff < 0) { + amp = -FFMIN(FFABS(diff * factor), llimit); + } else { + amp = FFMIN(FFABS(diff * factor), hlimit); + } + dst[x] = av_clip_uint8(src + amp); + } else { + dst[x] = src; + } + } + + dst += out->linesize[p]; + } + } + } else { + for (p = 0; p < s->nb_planes; p++) { + const int slice_start = (s->height[p] * jobnr) / nb_jobs; + const int slice_end = (s->height[p] * (jobnr+1)) / nb_jobs; + uint16_t *dst = (uint16_t *)(out->data[p] + slice_start * out->linesize[p]); + + if (!((1 << p) & s->planes)) { + av_image_copy_plane((uint8_t *)dst, out->linesize[p], + in[radius]->data[p] + slice_start * in[radius]->linesize[p], + in[radius]->linesize[p], + s->linesize[p], slice_end - slice_start); + continue; + } + + for (y = slice_start; y < slice_end; y++) { + for (x = 0; x < s->linesize[p] / 2; x++) { + int src = AV_RN16(in[radius]->data[p] + y * in[radius]->linesize[p] + x * 2); + float diff, avg; + int sum = 0; + + for (i = 0; i < nb_inputs; i++) { + sum += AV_RN16(in[i]->data[p] + y * in[i]->linesize[p] + x * 2); + } + + avg = sum / (float)nb_inputs; + diff = src - avg; + + if (fabsf(diff) < threshold && fabsf(diff) > tolerance) { + int amp; + if (diff < 0) { + amp = -FFMIN(FFABS(diff * factor), llimit); + } else { + amp = FFMIN(FFABS(diff * factor), hlimit); + } + dst[x] = av_clip_uintp2_c(src + amp, depth); + } else { + dst[x] = src; + } + } + + dst += out->linesize[p] / 2; + } + } + } + + return 0; +} + +static int config_output(AVFilterLink *outlink) +{ + AVFilterContext *ctx = outlink->src; + AmplifyContext *s = ctx->priv; + AVFilterLink *inlink = ctx->inputs[0]; + int ret; + + s->desc = av_pix_fmt_desc_get(outlink->format); + if (!s->desc) + return AVERROR_BUG; + s->nb_planes = av_pix_fmt_count_planes(outlink->format); + s->depth = s->desc->comp[0].depth; + + if ((ret = av_image_fill_linesizes(s->linesize, inlink->format, inlink->w)) < 0) + return ret; + + s->height[1] = s->height[2] = AV_CEIL_RSHIFT(inlink->h, s->desc->log2_chroma_h); + s->height[0] = s->height[3] = inlink->h; + + return 0; +} + +static av_cold void uninit(AVFilterContext *ctx) +{ + AmplifyContext *s = ctx->priv; + int i; + + if (s->frames) { + for (i = 0; i < s->nb_frames; i++) + av_frame_free(&s->frames[i]); + } + av_freep(&s->frames); +} + +static int filter_frame(AVFilterLink *inlink, AVFrame *in) +{ + AVFilterContext *ctx = inlink->dst; + AVFilterLink *outlink = ctx->outputs[0]; + AmplifyContext *s = ctx->priv; + ThreadData td; + AVFrame *out; + + if (s->nb_frames < s->nb_inputs) { + s->frames[s->nb_frames] = in; + s->nb_frames++; + return 0; + } else { + av_frame_free(&s->frames[0]); + memmove(&s->frames[0], &s->frames[1], sizeof(*s->frames) * (s->nb_inputs - 1)); + s->frames[s->nb_inputs - 1] = in; + } + + out = ff_get_video_buffer(outlink, outlink->w, outlink->h); + if (!out) + return AVERROR(ENOMEM); + out->pts = s->frames[0]->pts; + + td.out = out; + td.in = s->frames; + ctx->internal->execute(ctx, amplify_frame, &td, NULL, FFMIN(s->height[1], ff_filter_get_nb_threads(ctx))); + + return ff_filter_frame(outlink, out); +} + +#define OFFSET(x) offsetof(AmplifyContext, x) +#define FLAGS AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_FILTERING_PARAM + +static const AVOption amplify_options[] = { + { "radius", "set radius", OFFSET(radius), AV_OPT_TYPE_INT, {.i64=2}, 1, 63, .flags = FLAGS }, + { "factor", "set factor", OFFSET(factor), AV_OPT_TYPE_FLOAT, {.dbl=2}, 0, UINT16_MAX, .flags = FLAGS }, + { "threshold", "set threshold", OFFSET(threshold), AV_OPT_TYPE_FLOAT, {.dbl=10}, 0, UINT16_MAX, .flags = FLAGS }, + { "tolerance", "set tolerance", OFFSET(tolerance), AV_OPT_TYPE_FLOAT, {.dbl=0}, 0, UINT16_MAX, .flags = FLAGS }, + { "low", "set low limit for amplification", OFFSET(llimit), AV_OPT_TYPE_INT, {.i64=UINT16_MAX}, 0, UINT16_MAX, .flags = FLAGS }, + { "high", "set high limit for amplification", OFFSET(hlimit), AV_OPT_TYPE_INT, {.i64=UINT16_MAX}, 0, UINT16_MAX, .flags = FLAGS }, + { "planes", "set what planes to filter", OFFSET(planes), AV_OPT_TYPE_FLAGS, {.i64=7}, 0, 15, FLAGS }, + { NULL }, +}; + +static const AVFilterPad inputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + .filter_frame = filter_frame, + }, + { NULL } +}; + +static const AVFilterPad outputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + .config_props = config_output, + }, + { NULL } +}; + +AVFILTER_DEFINE_CLASS(amplify); + +AVFilter ff_vf_amplify = { + .name = "amplify", + .description = NULL_IF_CONFIG_SMALL("Amplify changes between successive video frames."), + .priv_size = sizeof(AmplifyContext), + .priv_class = &lify_class, + .query_formats = query_formats, + .outputs = outputs, + .inputs = inputs, + .init = init, + .uninit = uninit, + .flags = AVFILTER_FLAG_SLICE_THREADS, +}; diff --git a/libavfilter/vf_atadenoise.c b/libavfilter/vf_atadenoise.c index 03b772c67..b7d958b83 100644 --- a/libavfilter/vf_atadenoise.c +++ b/libavfilter/vf_atadenoise.c @@ -83,6 +83,7 @@ static int query_formats(AVFilterContext *ctx) AV_PIX_FMT_GRAY9, AV_PIX_FMT_GRAY10, AV_PIX_FMT_GRAY12, + AV_PIX_FMT_GRAY14, AV_PIX_FMT_GRAY16, AV_PIX_FMT_YUV410P, AV_PIX_FMT_YUV411P, AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV422P, @@ -112,8 +113,8 @@ static av_cold int init(AVFilterContext *ctx) ATADenoiseContext *s = ctx->priv; if (!(s->size & 1)) { - av_log(ctx, AV_LOG_ERROR, "size %d is invalid. Must be an odd value.\n", s->size); - return AVERROR(EINVAL); + av_log(ctx, AV_LOG_WARNING, "size %d is invalid. Must be an odd value, setting it to %d.\n", s->size, s->size|1); + s->size |= 1; } s->mid = s->size / 2 + 1; diff --git a/libavfilter/vf_avgblur.c b/libavfilter/vf_avgblur.c index afd4a6ab7..c7b88427f 100644 --- a/libavfilter/vf_avgblur.c +++ b/libavfilter/vf_avgblur.c @@ -242,7 +242,7 @@ static int query_formats(AVFilterContext *ctx) AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRP9, AV_PIX_FMT_GBRP10, AV_PIX_FMT_GBRP12, AV_PIX_FMT_GBRP14, AV_PIX_FMT_GBRP16, AV_PIX_FMT_GBRAP, AV_PIX_FMT_GBRAP10, AV_PIX_FMT_GBRAP12, AV_PIX_FMT_GBRAP16, - AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY9, AV_PIX_FMT_GRAY10, AV_PIX_FMT_GRAY12, AV_PIX_FMT_GRAY16, + AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY9, AV_PIX_FMT_GRAY10, AV_PIX_FMT_GRAY12, AV_PIX_FMT_GRAY14, AV_PIX_FMT_GRAY16, AV_PIX_FMT_NONE }; diff --git a/libavfilter/vf_avgblur_opencl.c b/libavfilter/vf_avgblur_opencl.c index 48cebb588..f0e5f01e0 100644 --- a/libavfilter/vf_avgblur_opencl.c +++ b/libavfilter/vf_avgblur_opencl.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2018 Dylan Fernando + * Copyright (c) 2018 Danil Iashchenko * * This file is part of FFmpeg. * @@ -20,16 +21,14 @@ #include "libavutil/common.h" #include "libavutil/imgutils.h" -#include "libavutil/mem.h" #include "libavutil/opt.h" -#include "libavutil/pixdesc.h" #include "avfilter.h" #include "internal.h" #include "opencl.h" #include "opencl_source.h" #include "video.h" - +#include "boxblur.h" typedef struct AverageBlurOpenCLContext { OpenCLFilterContext ocf; @@ -39,10 +38,16 @@ typedef struct AverageBlurOpenCLContext { cl_kernel kernel_vert; cl_command_queue command_queue; - int radius; + int radiusH; int radiusV; int planes; + FilterParam luma_param; + FilterParam chroma_param; + FilterParam alpha_param; + int radius[4]; + int power[4]; + } AverageBlurOpenCLContext; @@ -59,30 +64,16 @@ static int avgblur_opencl_init(AVFilterContext *avctx) ctx->command_queue = clCreateCommandQueue(ctx->ocf.hwctx->context, ctx->ocf.hwctx->device_id, 0, &cle); - if (!ctx->command_queue) { - av_log(avctx, AV_LOG_ERROR, "Failed to create OpenCL " - "command queue: %d.\n", cle); - err = AVERROR(EIO); - goto fail; - } + CL_FAIL_ON_ERROR(AVERROR(EIO), "Failed to create OpenCL " + "command queue %d.\n", cle); ctx->kernel_horiz = clCreateKernel(ctx->ocf.program,"avgblur_horiz", &cle); - if (!ctx->kernel_horiz) { - av_log(avctx, AV_LOG_ERROR, "Failed to create kernel: %d.\n", cle); - err = AVERROR(EIO); - goto fail; - } + CL_FAIL_ON_ERROR(AVERROR(EIO), "Failed to create horizontal " + "kernel %d.\n", cle); ctx->kernel_vert = clCreateKernel(ctx->ocf.program,"avgblur_vert", &cle); - if (!ctx->kernel_vert) { - av_log(avctx, AV_LOG_ERROR, "Failed to create kernel: %d.\n", cle); - err = AVERROR(EIO); - goto fail; - } - - if (ctx->radiusV <= 0) { - ctx->radiusV = ctx->radius; - } + CL_FAIL_ON_ERROR(AVERROR(EIO), "Failed to create vertical " + "kernel %d.\n", cle); ctx->initialised = 1; return 0; @@ -97,6 +88,60 @@ fail: return err; } + +static int avgblur_opencl_make_filter_params(AVFilterLink *inlink) +{ + AVFilterContext *ctx = inlink->dst; + AverageBlurOpenCLContext *s = ctx->priv; + int i; + + if (s->radiusV <= 0) { + s->radiusV = s->radiusH; + } + + for (i = 0; i < 4; i++) { + s->power[i] = 1; + } + return 0; +} + + +static int boxblur_opencl_make_filter_params(AVFilterLink *inlink) +{ + AVFilterContext *ctx = inlink->dst; + AverageBlurOpenCLContext *s = ctx->priv; + int err, i; + + err = ff_boxblur_eval_filter_params(inlink, + &s->luma_param, + &s->chroma_param, + &s->alpha_param); + + if (err != 0) { + av_log(ctx, AV_LOG_ERROR, "Failed to evaluate " + "filter params: %d.\n", err); + return err; + } + + s->radius[Y] = s->luma_param.radius; + s->radius[U] = s->radius[V] = s->chroma_param.radius; + s->radius[A] = s->alpha_param.radius; + + s->power[Y] = s->luma_param.power; + s->power[U] = s->power[V] = s->chroma_param.power; + s->power[A] = s->alpha_param.power; + + for (i = 0; i < 4; i++) { + if (s->power[i] == 0) { + s->power[i] = 1; + s->radius[i] = 0; + } + } + + return 0; +} + + static int avgblur_opencl_filter_frame(AVFilterLink *inlink, AVFrame *input) { AVFilterContext *avctx = inlink->dst; @@ -107,7 +152,7 @@ static int avgblur_opencl_filter_frame(AVFilterLink *inlink, AVFrame *input) cl_int cle; size_t global_work[2]; cl_mem src, dst, inter; - int err, p, radius_x, radius_y; + int err, p, radius_x, radius_y, i; av_log(ctx, AV_LOG_DEBUG, "Filter input: %s, %ux%u (%"PRId64").\n", av_get_pix_fmt_name(input->format), @@ -121,6 +166,16 @@ static int avgblur_opencl_filter_frame(AVFilterLink *inlink, AVFrame *input) if (err < 0) goto fail; + if (!strcmp(avctx->filter->name, "avgblur_opencl")) { + err = avgblur_opencl_make_filter_params(inlink); + if (err < 0) + goto fail; + } else if (!strcmp(avctx->filter->name, "boxblur_opencl")) { + err = boxblur_opencl_make_filter_params(inlink); + if (err < 0) + goto fail; + } + } output = ff_get_video_buffer(outlink, outlink->w, outlink->h); @@ -128,7 +183,6 @@ static int avgblur_opencl_filter_frame(AVFilterLink *inlink, AVFrame *input) err = AVERROR(ENOMEM); goto fail; } - intermediate = ff_get_video_buffer(outlink, outlink->w, outlink->h); if (!intermediate) { err = AVERROR(ENOMEM); @@ -137,13 +191,13 @@ static int avgblur_opencl_filter_frame(AVFilterLink *inlink, AVFrame *input) for (p = 0; p < FF_ARRAY_ELEMS(output->data); p++) { src = (cl_mem) input->data[p]; - dst = (cl_mem)output->data[p]; - inter = (cl_mem) intermediate->data[p]; + dst = (cl_mem) output->data[p]; + inter = (cl_mem)intermediate->data[p]; if (!dst) break; - radius_x = ctx->radius; + radius_x = ctx->radiusH; radius_y = ctx->radiusV; if (!(ctx->planes & (1 << p))) { @@ -151,97 +205,52 @@ static int avgblur_opencl_filter_frame(AVFilterLink *inlink, AVFrame *input) radius_y = 0; } - cle = clSetKernelArg(ctx->kernel_horiz, 0, sizeof(cl_mem), &inter); - if (cle != CL_SUCCESS) { - av_log(avctx, AV_LOG_ERROR, "Failed to set kernel " - "destination image argument: %d.\n", cle); - err = AVERROR_UNKNOWN; - goto fail; - } - cle = clSetKernelArg(ctx->kernel_horiz, 1, sizeof(cl_mem), &src); - if (cle != CL_SUCCESS) { - av_log(avctx, AV_LOG_ERROR, "Failed to set kernel " - "source image argument: %d.\n", cle); - err = AVERROR_UNKNOWN; - goto fail; - } - cle = clSetKernelArg(ctx->kernel_horiz, 2, sizeof(cl_int), &radius_x); - if (cle != CL_SUCCESS) { - av_log(avctx, AV_LOG_ERROR, "Failed to set kernel " - "sizeX argument: %d.\n", cle); - err = AVERROR_UNKNOWN; - goto fail; - } + for (i = 0; i < ctx->power[p]; i++) { + CL_SET_KERNEL_ARG(ctx->kernel_horiz, 0, cl_mem, &inter); + CL_SET_KERNEL_ARG(ctx->kernel_horiz, 1, cl_mem, i == 0 ? &src : &dst); + if (!strcmp(avctx->filter->name, "avgblur_opencl")) { + CL_SET_KERNEL_ARG(ctx->kernel_horiz, 2, cl_int, &radius_x); + } else if (!strcmp(avctx->filter->name, "boxblur_opencl")) { + CL_SET_KERNEL_ARG(ctx->kernel_horiz, 2, cl_int, &ctx->radius[p]); + } - err = ff_opencl_filter_work_size_from_image(avctx, global_work, - intermediate, p, 0); - if (err < 0) - goto fail; + err = ff_opencl_filter_work_size_from_image(avctx, global_work, + i == 0 ? intermediate : output, p, 0); + if (err < 0) + goto fail; - av_log(avctx, AV_LOG_DEBUG, "Run kernel on plane %d " - "(%"SIZE_SPECIFIER"x%"SIZE_SPECIFIER").\n", - p, global_work[0], global_work[1]); + av_log(avctx, AV_LOG_DEBUG, "Run kernel on plane %d " + "(%"SIZE_SPECIFIER"x%"SIZE_SPECIFIER").\n", + p, global_work[0], global_work[1]); - cle = clEnqueueNDRangeKernel(ctx->command_queue, ctx->kernel_horiz, 2, NULL, - global_work, NULL, - 0, NULL, NULL); - if (cle != CL_SUCCESS) { - av_log(avctx, AV_LOG_ERROR, "Failed to enqueue kernel: %d.\n", - cle); - err = AVERROR(EIO); - goto fail; + cle = clEnqueueNDRangeKernel(ctx->command_queue, ctx->kernel_horiz, 2, NULL, + global_work, NULL, + 0, NULL, NULL); + CL_FAIL_ON_ERROR(AVERROR(EIO), "Failed to enqueue horizontal " + "kernel: %d.\n", cle); + + err = ff_opencl_filter_work_size_from_image(avctx, global_work, + i == 0 ? output : intermediate, p, 0); + + CL_SET_KERNEL_ARG(ctx->kernel_vert, 0, cl_mem, &dst); + CL_SET_KERNEL_ARG(ctx->kernel_vert, 1, cl_mem, &inter); + + if (!strcmp(avctx->filter->name, "avgblur_opencl")) { + CL_SET_KERNEL_ARG(ctx->kernel_vert, 2, cl_int, &radius_y); + } else if (!strcmp(avctx->filter->name, "boxblur_opencl")) { + CL_SET_KERNEL_ARG(ctx->kernel_vert, 2, cl_int, &ctx->radius[p]); + } + + cle = clEnqueueNDRangeKernel(ctx->command_queue, ctx->kernel_vert, 2, NULL, + global_work, NULL, + 0, NULL, NULL); + CL_FAIL_ON_ERROR(AVERROR(EIO), "Failed to enqueue vertical " + "kernel: %d.\n", cle); } - - cle = clSetKernelArg(ctx->kernel_vert, 0, sizeof(cl_mem), &dst); - if (cle != CL_SUCCESS) { - av_log(avctx, AV_LOG_ERROR, "Failed to set kernel " - "destination image argument: %d.\n", cle); - err = AVERROR_UNKNOWN; - goto fail; - } - cle = clSetKernelArg(ctx->kernel_vert, 1, sizeof(cl_mem), &inter); - if (cle != CL_SUCCESS) { - av_log(avctx, AV_LOG_ERROR, "Failed to set kernel " - "source image argument: %d.\n", cle); - err = AVERROR_UNKNOWN; - goto fail; - } - cle = clSetKernelArg(ctx->kernel_vert, 2, sizeof(cl_int), &radius_y); - if (cle != CL_SUCCESS) { - av_log(avctx, AV_LOG_ERROR, "Failed to set kernel " - "sizeY argument: %d.\n", cle); - err = AVERROR_UNKNOWN; - goto fail; - } - - err = ff_opencl_filter_work_size_from_image(avctx, global_work, - output, p, 0); - if (err < 0) - goto fail; - - av_log(avctx, AV_LOG_DEBUG, "Run kernel on plane %d " - "(%"SIZE_SPECIFIER"x%"SIZE_SPECIFIER").\n", - p, global_work[0], global_work[1]); - - cle = clEnqueueNDRangeKernel(ctx->command_queue, ctx->kernel_vert, 2, NULL, - global_work, NULL, - 0, NULL, NULL); - if (cle != CL_SUCCESS) { - av_log(avctx, AV_LOG_ERROR, "Failed to enqueue kernel: %d.\n", - cle); - err = AVERROR(EIO); - goto fail; - } - } cle = clFinish(ctx->command_queue); - if (cle != CL_SUCCESS) { - av_log(avctx, AV_LOG_ERROR, "Failed to finish command queue: %d.\n", - cle); - err = AVERROR(EIO); - goto fail; - } + CL_FAIL_ON_ERROR(AVERROR(EIO), "Failed to finish command queue: %d.\n", cle); err = av_frame_copy_props(output, input); if (err < 0) @@ -264,12 +273,12 @@ fail: return err; } + static av_cold void avgblur_opencl_uninit(AVFilterContext *avctx) { AverageBlurOpenCLContext *ctx = avctx->priv; cl_int cle; - if (ctx->kernel_horiz) { cle = clReleaseKernel(ctx->kernel_horiz); if (cle != CL_SUCCESS) @@ -294,16 +303,6 @@ static av_cold void avgblur_opencl_uninit(AVFilterContext *avctx) ff_opencl_filter_uninit(avctx); } -#define OFFSET(x) offsetof(AverageBlurOpenCLContext, x) -#define FLAGS (AV_OPT_FLAG_FILTERING_PARAM | AV_OPT_FLAG_VIDEO_PARAM) -static const AVOption avgblur_opencl_options[] = { - { "sizeX", "set horizontal size", OFFSET(radius), AV_OPT_TYPE_INT, {.i64=1}, 1, 1024, FLAGS }, - { "planes", "set planes to filter", OFFSET(planes), AV_OPT_TYPE_INT, {.i64=0xF}, 0, 0xF, FLAGS }, - { "sizeY", "set vertical size", OFFSET(radiusV), AV_OPT_TYPE_INT, {.i64=0}, 0, 1024, FLAGS }, - { NULL } -}; - -AVFILTER_DEFINE_CLASS(avgblur_opencl); static const AVFilterPad avgblur_opencl_inputs[] = { { @@ -315,6 +314,7 @@ static const AVFilterPad avgblur_opencl_inputs[] = { { NULL } }; + static const AVFilterPad avgblur_opencl_outputs[] = { { .name = "default", @@ -324,6 +324,22 @@ static const AVFilterPad avgblur_opencl_outputs[] = { { NULL } }; + +#define OFFSET(x) offsetof(AverageBlurOpenCLContext, x) +#define FLAGS (AV_OPT_FLAG_FILTERING_PARAM | AV_OPT_FLAG_VIDEO_PARAM) + +#if CONFIG_AVGBLUR_OPENCL_FILTER + +static const AVOption avgblur_opencl_options[] = { + { "sizeX", "set horizontal size", OFFSET(radiusH), AV_OPT_TYPE_INT, {.i64=1}, 1, 1024, FLAGS }, + { "planes", "set planes to filter", OFFSET(planes), AV_OPT_TYPE_INT, {.i64=0xF}, 0, 0xF, FLAGS }, + { "sizeY", "set vertical size", OFFSET(radiusV), AV_OPT_TYPE_INT, {.i64=0}, 0, 1024, FLAGS }, + { NULL } +}; + +AVFILTER_DEFINE_CLASS(avgblur_opencl); + + AVFilter ff_vf_avgblur_opencl = { .name = "avgblur_opencl", .description = NULL_IF_CONFIG_SMALL("Apply average blur filter"), @@ -336,3 +352,44 @@ AVFilter ff_vf_avgblur_opencl = { .outputs = avgblur_opencl_outputs, .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE, }; + +#endif /* CONFIG_AVGBLUR_OPENCL_FILTER */ + + +#if CONFIG_BOXBLUR_OPENCL_FILTER + +static const AVOption boxblur_opencl_options[] = { + { "luma_radius", "Radius of the luma blurring box", OFFSET(luma_param.radius_expr), AV_OPT_TYPE_STRING, {.str="2"}, .flags = FLAGS }, + { "lr", "Radius of the luma blurring box", OFFSET(luma_param.radius_expr), AV_OPT_TYPE_STRING, {.str="2"}, .flags = FLAGS }, + { "luma_power", "How many times should the boxblur be applied to luma", OFFSET(luma_param.power), AV_OPT_TYPE_INT, {.i64=2}, 0, INT_MAX, .flags = FLAGS }, + { "lp", "How many times should the boxblur be applied to luma", OFFSET(luma_param.power), AV_OPT_TYPE_INT, {.i64=2}, 0, INT_MAX, .flags = FLAGS }, + + { "chroma_radius", "Radius of the chroma blurring box", OFFSET(chroma_param.radius_expr), AV_OPT_TYPE_STRING, {.str=NULL}, .flags = FLAGS }, + { "cr", "Radius of the chroma blurring box", OFFSET(chroma_param.radius_expr), AV_OPT_TYPE_STRING, {.str=NULL}, .flags = FLAGS }, + { "chroma_power", "How many times should the boxblur be applied to chroma", OFFSET(chroma_param.power), AV_OPT_TYPE_INT, {.i64=-1}, -1, INT_MAX, .flags = FLAGS }, + { "cp", "How many times should the boxblur be applied to chroma", OFFSET(chroma_param.power), AV_OPT_TYPE_INT, {.i64=-1}, -1, INT_MAX, .flags = FLAGS }, + + { "alpha_radius", "Radius of the alpha blurring box", OFFSET(alpha_param.radius_expr), AV_OPT_TYPE_STRING, {.str=NULL}, .flags = FLAGS }, + { "ar", "Radius of the alpha blurring box", OFFSET(alpha_param.radius_expr), AV_OPT_TYPE_STRING, {.str=NULL}, .flags = FLAGS }, + { "alpha_power", "How many times should the boxblur be applied to alpha", OFFSET(alpha_param.power), AV_OPT_TYPE_INT, {.i64=-1}, -1, INT_MAX, .flags = FLAGS }, + { "ap", "How many times should the boxblur be applied to alpha", OFFSET(alpha_param.power), AV_OPT_TYPE_INT, {.i64=-1}, -1, INT_MAX, .flags = FLAGS }, + + { NULL } +}; + +AVFILTER_DEFINE_CLASS(boxblur_opencl); + +AVFilter ff_vf_boxblur_opencl = { + .name = "boxblur_opencl", + .description = NULL_IF_CONFIG_SMALL("Apply boxblur filter to input video"), + .priv_size = sizeof(AverageBlurOpenCLContext), + .priv_class = &boxblur_opencl_class, + .init = &ff_opencl_filter_init, + .uninit = &avgblur_opencl_uninit, + .query_formats = &ff_opencl_filter_query_formats, + .inputs = avgblur_opencl_inputs, + .outputs = avgblur_opencl_outputs, + .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE, +}; + +#endif /* CONFIG_BOXBLUR_OPENCL_FILTER */ diff --git a/libavfilter/vf_bitplanenoise.c b/libavfilter/vf_bitplanenoise.c index dd6864bc5..4ec3a2257 100644 --- a/libavfilter/vf_bitplanenoise.c +++ b/libavfilter/vf_bitplanenoise.c @@ -63,7 +63,7 @@ static int query_formats(AVFilterContext *ctx) AV_PIX_FMT_YUV444P16, AV_PIX_FMT_YUV422P16, AV_PIX_FMT_YUV420P16, AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRP9, AV_PIX_FMT_GBRP10, AV_PIX_FMT_GBRP12, AV_PIX_FMT_GBRP14, AV_PIX_FMT_GBRP16, - AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY9, AV_PIX_FMT_GRAY10, AV_PIX_FMT_GRAY12, AV_PIX_FMT_GRAY16, + AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY9, AV_PIX_FMT_GRAY10, AV_PIX_FMT_GRAY12, AV_PIX_FMT_GRAY14, AV_PIX_FMT_GRAY16, AV_PIX_FMT_NONE }; diff --git a/libavfilter/vf_blend.c b/libavfilter/vf_blend.c index 70c37c75d..d6036c10e 100644 --- a/libavfilter/vf_blend.c +++ b/libavfilter/vf_blend.c @@ -23,7 +23,6 @@ #include "libavutil/opt.h" #include "libavutil/pixfmt.h" #include "avfilter.h" -#include "bufferqueue.h" #include "formats.h" #include "framesync.h" #include "internal.h" @@ -42,6 +41,7 @@ typedef struct BlendContext { enum BlendMode all_mode; double all_opacity; + int depth; FilterParams params[4]; int tblend; AVFrame *prev_frame; /* only used with tblend */ @@ -121,19 +121,22 @@ static const AVOption blend_options[] = { FRAMESYNC_DEFINE_CLASS(blend, BlendContext, fs); -#define COPY(src) \ -static void blend_copy ## src(const uint8_t *top, ptrdiff_t top_linesize, \ +#define COPY(src, depth) \ +static void blend_copy ## src##_##depth(const uint8_t *top, ptrdiff_t top_linesize, \ const uint8_t *bottom, ptrdiff_t bottom_linesize,\ uint8_t *dst, ptrdiff_t dst_linesize, \ ptrdiff_t width, ptrdiff_t height, \ FilterParams *param, double *values, int starty) \ { \ av_image_copy_plane(dst, dst_linesize, src, src ## _linesize, \ - width, height); \ + width * depth / 8, height); \ } -COPY(top) -COPY(bottom) +COPY(top, 8) +COPY(bottom, 8) + +COPY(top, 16) +COPY(bottom, 16) #undef COPY @@ -201,15 +204,15 @@ static void blend_## name##_8bit(const uint8_t *top, ptrdiff_t top_linesize, } \ } -#define DEFINE_BLEND16(name, expr) \ -static void blend_## name##_16bit(const uint8_t *_top, ptrdiff_t top_linesize, \ +#define DEFINE_BLEND16(name, expr, depth) \ +static void blend_## name##_##depth##bit(const uint8_t *_top, ptrdiff_t top_linesize,\ const uint8_t *_bottom, ptrdiff_t bottom_linesize, \ uint8_t *_dst, ptrdiff_t dst_linesize, \ ptrdiff_t width, ptrdiff_t height, \ FilterParams *param, double *values, int starty) \ { \ - const uint16_t *top = (uint16_t*)_top; \ - const uint16_t *bottom = (uint16_t*)_bottom; \ + const uint16_t *top = (const uint16_t*)_top; \ + const uint16_t *bottom = (const uint16_t*)_bottom; \ uint16_t *dst = (uint16_t*)_dst; \ double opacity = param->opacity; \ int i, j; \ @@ -278,38 +281,167 @@ DEFINE_BLEND8(linearlight,av_clip_uint8((B < 128) ? B + 2 * A - 255 : B + 2 * (A #define BURN(a, b) (((a) == 0) ? (a) : FFMAX(0, 65535 - ((65535 - (b)) << 16) / (a))) #define DODGE(a, b) (((a) == 65535) ? (a) : FFMIN(65535, (((b) << 16) / (65535 - (a))))) -DEFINE_BLEND16(addition, FFMIN(65535, A + B)) -DEFINE_BLEND16(grainmerge, av_clip_uint16(A + B - 32768)) -DEFINE_BLEND16(average, (A + B) / 2) -DEFINE_BLEND16(subtract, FFMAX(0, A - B)) -DEFINE_BLEND16(multiply, MULTIPLY(1, A, B)) -DEFINE_BLEND16(multiply128, av_clip_uint16((A - 32768) * B / 8192. + 32768)) -DEFINE_BLEND16(negation, 65535 - FFABS(65535 - A - B)) -DEFINE_BLEND16(extremity, FFABS(65535 - A - B)) -DEFINE_BLEND16(difference, FFABS(A - B)) -DEFINE_BLEND16(grainextract, av_clip_uint16(32768 + A - B)) -DEFINE_BLEND16(screen, SCREEN(1, A, B)) -DEFINE_BLEND16(overlay, (A < 32768) ? MULTIPLY(2, A, B) : SCREEN(2, A, B)) -DEFINE_BLEND16(hardlight, (B < 32768) ? MULTIPLY(2, B, A) : SCREEN(2, B, A)) -DEFINE_BLEND16(hardmix, (A < (65535 - B)) ? 0: 65535) -DEFINE_BLEND16(heat, (A == 0) ? 0 : 65535 - FFMIN(((65535 - B) * (65535 - B)) / A, 65535)) -DEFINE_BLEND16(freeze, (B == 0) ? 0 : 65535 - FFMIN(((65535 - A) * (65535 - A)) / B, 65535)) -DEFINE_BLEND16(darken, FFMIN(A, B)) -DEFINE_BLEND16(lighten, FFMAX(A, B)) -DEFINE_BLEND16(divide, av_clip_uint16(B == 0 ? 65535 : 65535 * A / B)) -DEFINE_BLEND16(dodge, DODGE(A, B)) -DEFINE_BLEND16(burn, BURN(A, B)) -DEFINE_BLEND16(softlight, (A > 32767) ? B + (65535 - B) * (A - 32767.5) / 32767.5 * (0.5 - fabs(B - 32767.5) / 65535): B - B * ((32767.5 - A) / 32767.5) * (0.5 - fabs(B - 32767.5)/65535)) -DEFINE_BLEND16(exclusion, A + B - 2 * A * B / 65535) -DEFINE_BLEND16(pinlight, (B < 32768) ? FFMIN(A, 2 * B) : FFMAX(A, 2 * (B - 32768))) -DEFINE_BLEND16(phoenix, FFMIN(A, B) - FFMAX(A, B) + 65535) -DEFINE_BLEND16(reflect, (B == 65535) ? B : FFMIN(65535, (A * A / (65535 - B)))) -DEFINE_BLEND16(glow, (A == 65535) ? A : FFMIN(65535, (B * B / (65535 - A)))) -DEFINE_BLEND16(and, A & B) -DEFINE_BLEND16(or, A | B) -DEFINE_BLEND16(xor, A ^ B) -DEFINE_BLEND16(vividlight, (A < 32768) ? BURN(2 * A, B) : DODGE(2 * (A - 32768), B)) -DEFINE_BLEND16(linearlight,av_clip_uint16((B < 32768) ? B + 2 * A - 65535 : B + 2 * (A - 32768))) +DEFINE_BLEND16(addition, FFMIN(65535, A + B), 16) +DEFINE_BLEND16(grainmerge, av_clip_uint16(A + B - 32768), 16) +DEFINE_BLEND16(average, (A + B) / 2, 16) +DEFINE_BLEND16(subtract, FFMAX(0, A - B), 16) +DEFINE_BLEND16(multiply, MULTIPLY(1, A, B), 16) +DEFINE_BLEND16(multiply128, av_clip_uint16((A - 32768) * B / 8192. + 32768), 16) +DEFINE_BLEND16(negation, 65535 - FFABS(65535 - A - B), 16) +DEFINE_BLEND16(extremity, FFABS(65535 - A - B), 16) +DEFINE_BLEND16(difference, FFABS(A - B), 16) +DEFINE_BLEND16(grainextract, av_clip_uint16(32768 + A - B), 16) +DEFINE_BLEND16(screen, SCREEN(1, A, B), 16) +DEFINE_BLEND16(overlay, (A < 32768) ? MULTIPLY(2, A, B) : SCREEN(2, A, B), 16) +DEFINE_BLEND16(hardlight, (B < 32768) ? MULTIPLY(2, B, A) : SCREEN(2, B, A), 16) +DEFINE_BLEND16(hardmix, (A < (65535 - B)) ? 0: 65535, 16) +DEFINE_BLEND16(heat, (A == 0) ? 0 : 65535 - FFMIN(((65535 - B) * (65535 - B)) / A, 65535), 16) +DEFINE_BLEND16(freeze, (B == 0) ? 0 : 65535 - FFMIN(((65535 - A) * (65535 - A)) / B, 65535), 16) +DEFINE_BLEND16(darken, FFMIN(A, B), 16) +DEFINE_BLEND16(lighten, FFMAX(A, B), 16) +DEFINE_BLEND16(divide, av_clip_uint16(B == 0 ? 65535 : 65535 * A / B), 16) +DEFINE_BLEND16(dodge, DODGE(A, B), 16) +DEFINE_BLEND16(burn, BURN(A, B), 16) +DEFINE_BLEND16(softlight, (A > 32767) ? B + (65535 - B) * (A - 32767.5) / 32767.5 * (0.5 - fabs(B - 32767.5) / 65535): B - B * ((32767.5 - A) / 32767.5) * (0.5 - fabs(B - 32767.5)/65535), 16) +DEFINE_BLEND16(exclusion, A + B - 2 * A * B / 65535, 16) +DEFINE_BLEND16(pinlight, (B < 32768) ? FFMIN(A, 2 * B) : FFMAX(A, 2 * (B - 32768)), 16) +DEFINE_BLEND16(phoenix, FFMIN(A, B) - FFMAX(A, B) + 65535, 16) +DEFINE_BLEND16(reflect, (B == 65535) ? B : FFMIN(65535, (A * A / (65535 - B))), 16) +DEFINE_BLEND16(glow, (A == 65535) ? A : FFMIN(65535, (B * B / (65535 - A))), 16) +DEFINE_BLEND16(and, A & B, 16) +DEFINE_BLEND16(or, A | B, 16) +DEFINE_BLEND16(xor, A ^ B, 16) +DEFINE_BLEND16(vividlight, (A < 32768) ? BURN(2 * A, B) : DODGE(2 * (A - 32768), B), 16) +DEFINE_BLEND16(linearlight,av_clip_uint16((B < 32768) ? B + 2 * A - 65535 : B + 2 * (A - 32768)), 16) + +#undef MULTIPLY +#undef SCREEN +#undef BURN +#undef DODGE + +#define MULTIPLY(x, a, b) ((x) * (((a) * (b)) / 1023)) +#define SCREEN(x, a, b) (1023 - (x) * ((1023 - (a)) * (1023 - (b)) / 1023)) +#define BURN(a, b) (((a) == 0) ? (a) : FFMAX(0, 1023 - ((1023 - (b)) << 10) / (a))) +#define DODGE(a, b) (((a) == 1023) ? (a) : FFMIN(1023, (((b) << 10) / (1023 - (a))))) + +DEFINE_BLEND16(addition, FFMIN(1023, A + B), 10) +DEFINE_BLEND16(grainmerge, (int)av_clip_uintp2(A + B - 512, 10), 10) +DEFINE_BLEND16(average, (A + B) / 2, 10) +DEFINE_BLEND16(subtract, FFMAX(0, A - B), 10) +DEFINE_BLEND16(multiply, MULTIPLY(1, A, B), 10) +DEFINE_BLEND16(multiply128, (int)av_clip_uintp2((A - 512) * B / 128. + 512, 10), 10) +DEFINE_BLEND16(negation, 1023 - FFABS(1023 - A - B), 10) +DEFINE_BLEND16(extremity, FFABS(1023 - A - B), 10) +DEFINE_BLEND16(difference, FFABS(A - B), 10) +DEFINE_BLEND16(grainextract, (int)av_clip_uintp2(512 + A - B, 10), 10) +DEFINE_BLEND16(screen, SCREEN(1, A, B), 10) +DEFINE_BLEND16(overlay, (A < 512) ? MULTIPLY(2, A, B) : SCREEN(2, A, B), 10) +DEFINE_BLEND16(hardlight, (B < 512) ? MULTIPLY(2, B, A) : SCREEN(2, B, A), 10) +DEFINE_BLEND16(hardmix, (A < (1023 - B)) ? 0: 1023, 10) +DEFINE_BLEND16(heat, (A == 0) ? 0 : 1023 - FFMIN(((1023 - B) * (1023 - B)) / A, 1023), 10) +DEFINE_BLEND16(freeze, (B == 0) ? 0 : 1023 - FFMIN(((1023 - A) * (1023 - A)) / B, 1023), 10) +DEFINE_BLEND16(darken, FFMIN(A, B), 10) +DEFINE_BLEND16(lighten, FFMAX(A, B), 10) +DEFINE_BLEND16(divide, (int)av_clip_uintp2(B == 0 ? 1023 : 1023 * A / B, 10), 10) +DEFINE_BLEND16(dodge, DODGE(A, B), 10) +DEFINE_BLEND16(burn, BURN(A, B), 10) +DEFINE_BLEND16(softlight, (A > 511) ? B + (1023 - B) * (A - 511.5) / 511.5 * (0.5 - fabs(B - 511.5) / 1023): B - B * ((511.5 - A) / 511.5) * (0.5 - fabs(B - 511.5)/1023), 10) +DEFINE_BLEND16(exclusion, A + B - 2 * A * B / 1023, 10) +DEFINE_BLEND16(pinlight, (B < 512) ? FFMIN(A, 2 * B) : FFMAX(A, 2 * (B - 512)), 10) +DEFINE_BLEND16(phoenix, FFMIN(A, B) - FFMAX(A, B) + 1023, 10) +DEFINE_BLEND16(reflect, (B == 1023) ? B : FFMIN(1023, (A * A / (1023 - B))), 10) +DEFINE_BLEND16(glow, (A == 1023) ? A : FFMIN(1023, (B * B / (1023 - A))), 10) +DEFINE_BLEND16(and, A & B, 10) +DEFINE_BLEND16(or, A | B, 10) +DEFINE_BLEND16(xor, A ^ B, 10) +DEFINE_BLEND16(vividlight, (A < 512) ? BURN(2 * A, B) : DODGE(2 * (A - 512), B), 10) +DEFINE_BLEND16(linearlight,(int)av_clip_uintp2((B < 512) ? B + 2 * A - 1023 : B + 2 * (A - 512), 10), 10) + +#undef MULTIPLY +#undef SCREEN +#undef BURN +#undef DODGE + +#define MULTIPLY(x, a, b) ((x) * (((a) * (b)) / 4095)) +#define SCREEN(x, a, b) (4095 - (x) * ((4095 - (a)) * (4095 - (b)) / 4095)) +#define BURN(a, b) (((a) == 0) ? (a) : FFMAX(0, 4095 - ((4095 - (b)) << 12) / (a))) +#define DODGE(a, b) (((a) == 4095) ? (a) : FFMIN(4095, (((b) << 12) / (4095 - (a))))) + +DEFINE_BLEND16(addition, FFMIN(4095, A + B), 12) +DEFINE_BLEND16(grainmerge, (int)av_clip_uintp2(A + B - 2048, 12), 12) +DEFINE_BLEND16(average, (A + B) / 2, 12) +DEFINE_BLEND16(subtract, FFMAX(0, A - B), 12) +DEFINE_BLEND16(multiply, MULTIPLY(1, A, B), 12) +DEFINE_BLEND16(multiply128, (int)av_clip_uintp2((A - 2048) * B / 512. + 2048, 12), 12) +DEFINE_BLEND16(negation, 4095 - FFABS(4095 - A - B), 12) +DEFINE_BLEND16(extremity, FFABS(4095 - A - B), 12) +DEFINE_BLEND16(difference, FFABS(A - B), 12) +DEFINE_BLEND16(grainextract, (int)av_clip_uintp2(2048 + A - B, 12), 12) +DEFINE_BLEND16(screen, SCREEN(1, A, B), 12) +DEFINE_BLEND16(overlay, (A < 2048) ? MULTIPLY(2, A, B) : SCREEN(2, A, B), 12) +DEFINE_BLEND16(hardlight, (B < 2048) ? MULTIPLY(2, B, A) : SCREEN(2, B, A), 12) +DEFINE_BLEND16(hardmix, (A < (4095 - B)) ? 0: 4095, 12) +DEFINE_BLEND16(heat, (A == 0) ? 0 : 4095 - FFMIN(((4095 - B) * (4095 - B)) / A, 4095), 12) +DEFINE_BLEND16(freeze, (B == 0) ? 0 : 4095 - FFMIN(((4095 - A) * (4095 - A)) / B, 4095), 12) +DEFINE_BLEND16(darken, FFMIN(A, B), 12) +DEFINE_BLEND16(lighten, FFMAX(A, B), 12) +DEFINE_BLEND16(divide, (int)av_clip_uintp2(B == 0 ? 4095 : 4095 * A / B, 12), 12) +DEFINE_BLEND16(dodge, DODGE(A, B), 12) +DEFINE_BLEND16(burn, BURN(A, B), 12) +DEFINE_BLEND16(softlight, (A > 2047) ? B + (4095 - B) * (A - 2047.5) / 2047.5 * (0.5 - fabs(B - 2047.5) / 4095): B - B * ((2047.5 - A) / 2047.5) * (0.5 - fabs(B - 2047.5)/4095), 12) +DEFINE_BLEND16(exclusion, A + B - 2 * A * B / 4095, 12) +DEFINE_BLEND16(pinlight, (B < 2048) ? FFMIN(A, 2 * B) : FFMAX(A, 2 * (B - 2048)), 12) +DEFINE_BLEND16(phoenix, FFMIN(A, B) - FFMAX(A, B) + 4095, 12) +DEFINE_BLEND16(reflect, (B == 4095) ? B : FFMIN(4095, (A * A / (4095 - B))), 12) +DEFINE_BLEND16(glow, (A == 4095) ? A : FFMIN(4095, (B * B / (4095 - A))), 12) +DEFINE_BLEND16(and, A & B, 12) +DEFINE_BLEND16(or, A | B, 12) +DEFINE_BLEND16(xor, A ^ B, 12) +DEFINE_BLEND16(vividlight, (A < 2048) ? BURN(2 * A, B) : DODGE(2 * (A - 2048), B), 12) +DEFINE_BLEND16(linearlight,(int)av_clip_uintp2((B < 2048) ? B + 2 * A - 4095 : B + 2 * (A - 2048), 12), 12) + +#undef MULTIPLY +#undef SCREEN +#undef BURN +#undef DODGE + +#define MULTIPLY(x, a, b) ((x) * (((a) * (b)) / 511)) +#define SCREEN(x, a, b) (511 - (x) * ((511 - (a)) * (511 - (b)) / 511)) +#define BURN(a, b) (((a) == 0) ? (a) : FFMAX(0, 511 - ((511 - (b)) << 9) / (a))) +#define DODGE(a, b) (((a) == 511) ? (a) : FFMIN(511, (((b) << 9) / (511 - (a))))) + +DEFINE_BLEND16(addition, FFMIN(511, A + B), 9) +DEFINE_BLEND16(grainmerge, (int)av_clip_uintp2(A + B - 256, 9), 9) +DEFINE_BLEND16(average, (A + B) / 2, 9) +DEFINE_BLEND16(subtract, FFMAX(0, A - B), 9) +DEFINE_BLEND16(multiply, MULTIPLY(1, A, B), 9) +DEFINE_BLEND16(multiply128, (int)av_clip_uintp2((A - 256) * B / 64. + 256, 9), 9) +DEFINE_BLEND16(negation, 511 - FFABS(511 - A - B), 9) +DEFINE_BLEND16(extremity, FFABS(511 - A - B), 9) +DEFINE_BLEND16(difference, FFABS(A - B), 9) +DEFINE_BLEND16(grainextract, (int)av_clip_uintp2(256 + A - B, 9), 9) +DEFINE_BLEND16(screen, SCREEN(1, A, B), 9) +DEFINE_BLEND16(overlay, (A < 256) ? MULTIPLY(2, A, B) : SCREEN(2, A, B), 9) +DEFINE_BLEND16(hardlight, (B < 256) ? MULTIPLY(2, B, A) : SCREEN(2, B, A), 9) +DEFINE_BLEND16(hardmix, (A < (511 - B)) ? 0: 511, 9) +DEFINE_BLEND16(heat, (A == 0) ? 0 : 511 - FFMIN(((511 - B) * (511 - B)) / A, 511), 9) +DEFINE_BLEND16(freeze, (B == 0) ? 0 : 511 - FFMIN(((511 - A) * (511 - A)) / B, 511), 9) +DEFINE_BLEND16(darken, FFMIN(A, B), 9) +DEFINE_BLEND16(lighten, FFMAX(A, B), 9) +DEFINE_BLEND16(divide, (int)av_clip_uintp2(B == 0 ? 511 : 511 * A / B, 9), 9) +DEFINE_BLEND16(dodge, DODGE(A, B), 9) +DEFINE_BLEND16(burn, BURN(A, B), 9) +DEFINE_BLEND16(softlight, (A > 511) ? B + (511 - B) * (A - 511.5) / 511.5 * (0.5 - fabs(B - 511.5) / 511): B - B * ((511.5 - A) / 511.5) * (0.5 - fabs(B - 511.5)/511), 9) +DEFINE_BLEND16(exclusion, A + B - 2 * A * B / 511, 9) +DEFINE_BLEND16(pinlight, (B < 256) ? FFMIN(A, 2 * B) : FFMAX(A, 2 * (B - 256)), 9) +DEFINE_BLEND16(phoenix, FFMIN(A, B) - FFMAX(A, B) + 511, 9) +DEFINE_BLEND16(reflect, (B == 511) ? B : FFMIN(511, (A * A / (511 - B))), 9) +DEFINE_BLEND16(glow, (A == 511) ? A : FFMIN(511, (B * B / (511 - A))), 9) +DEFINE_BLEND16(and, A & B, 9) +DEFINE_BLEND16(or, A | B, 9) +DEFINE_BLEND16(xor, A ^ B, 9) +DEFINE_BLEND16(vividlight, (A < 256) ? BURN(2 * A, B) : DODGE(2 * (A - 256), B), 9) +DEFINE_BLEND16(linearlight,(int)av_clip_uintp2((B < 256) ? B + 2 * A - 511 : B + 2 * (A - 256), 9), 9) #define DEFINE_BLEND_EXPR(type, name, div) \ static void blend_expr_## name(const uint8_t *_top, ptrdiff_t top_linesize, \ @@ -437,6 +569,13 @@ static int query_formats(AVFilterContext *ctx) AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_YUVJ440P, AV_PIX_FMT_YUVJ422P,AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUVJ411P, AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUV440P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV411P, AV_PIX_FMT_YUV410P, AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRAP, AV_PIX_FMT_GRAY8, + AV_PIX_FMT_YUV420P9, AV_PIX_FMT_YUV422P9, AV_PIX_FMT_YUV444P9, + AV_PIX_FMT_YUVA420P9, AV_PIX_FMT_YUVA422P9, AV_PIX_FMT_YUVA444P9, AV_PIX_FMT_GBRP9, + AV_PIX_FMT_YUV420P10, AV_PIX_FMT_YUV422P10, AV_PIX_FMT_YUV444P10, AV_PIX_FMT_YUV440P10, + AV_PIX_FMT_YUVA420P10, AV_PIX_FMT_YUVA422P10, AV_PIX_FMT_YUVA444P10, + AV_PIX_FMT_GBRP10, AV_PIX_FMT_GBRAP10, AV_PIX_FMT_GRAY10, + AV_PIX_FMT_YUV420P12, AV_PIX_FMT_YUV422P12, AV_PIX_FMT_YUV444P12, AV_PIX_FMT_YUV440P12, + AV_PIX_FMT_GBRP12, AV_PIX_FMT_GBRAP12, AV_PIX_FMT_GRAY12, AV_PIX_FMT_YUV420P16, AV_PIX_FMT_YUV422P16, AV_PIX_FMT_YUV444P16, AV_PIX_FMT_YUVA420P16, AV_PIX_FMT_YUVA422P16, AV_PIX_FMT_YUVA444P16, AV_PIX_FMT_GBRP16, AV_PIX_FMT_GBRAP16, AV_PIX_FMT_GRAY16, @@ -461,52 +600,82 @@ static av_cold void uninit(AVFilterContext *ctx) av_expr_free(s->params[i].e); } -void ff_blend_init(FilterParams *param, int is_16bit) +#define DEFINE_INIT_BLEND_FUNC(depth, nbits) \ +static av_cold void init_blend_func_##depth##_##nbits##bit(FilterParams *param) \ +{ \ + switch (param->mode) { \ + case BLEND_ADDITION: param->blend = blend_addition_##depth##bit; break; \ + case BLEND_GRAINMERGE: param->blend = blend_grainmerge_##depth##bit; break; \ + case BLEND_AND: param->blend = blend_and_##depth##bit; break; \ + case BLEND_AVERAGE: param->blend = blend_average_##depth##bit; break; \ + case BLEND_BURN: param->blend = blend_burn_##depth##bit; break; \ + case BLEND_DARKEN: param->blend = blend_darken_##depth##bit; break; \ + case BLEND_DIFFERENCE: param->blend = blend_difference_##depth##bit; break; \ + case BLEND_GRAINEXTRACT: param->blend = blend_grainextract_##depth##bit; break; \ + case BLEND_DIVIDE: param->blend = blend_divide_##depth##bit; break; \ + case BLEND_DODGE: param->blend = blend_dodge_##depth##bit; break; \ + case BLEND_EXCLUSION: param->blend = blend_exclusion_##depth##bit; break; \ + case BLEND_EXTREMITY: param->blend = blend_extremity_##depth##bit; break; \ + case BLEND_FREEZE: param->blend = blend_freeze_##depth##bit; break; \ + case BLEND_GLOW: param->blend = blend_glow_##depth##bit; break; \ + case BLEND_HARDLIGHT: param->blend = blend_hardlight_##depth##bit; break; \ + case BLEND_HARDMIX: param->blend = blend_hardmix_##depth##bit; break; \ + case BLEND_HEAT: param->blend = blend_heat_##depth##bit; break; \ + case BLEND_LIGHTEN: param->blend = blend_lighten_##depth##bit; break; \ + case BLEND_LINEARLIGHT:param->blend = blend_linearlight_##depth##bit;break; \ + case BLEND_MULTIPLY: param->blend = blend_multiply_##depth##bit; break; \ + case BLEND_MULTIPLY128:param->blend = blend_multiply128_##depth##bit;break; \ + case BLEND_NEGATION: param->blend = blend_negation_##depth##bit; break; \ + case BLEND_NORMAL: param->blend = blend_normal_##nbits##bit; break; \ + case BLEND_OR: param->blend = blend_or_##depth##bit; break; \ + case BLEND_OVERLAY: param->blend = blend_overlay_##depth##bit; break; \ + case BLEND_PHOENIX: param->blend = blend_phoenix_##depth##bit; break; \ + case BLEND_PINLIGHT: param->blend = blend_pinlight_##depth##bit; break; \ + case BLEND_REFLECT: param->blend = blend_reflect_##depth##bit; break; \ + case BLEND_SCREEN: param->blend = blend_screen_##depth##bit; break; \ + case BLEND_SOFTLIGHT: param->blend = blend_softlight_##depth##bit; break; \ + case BLEND_SUBTRACT: param->blend = blend_subtract_##depth##bit; break; \ + case BLEND_VIVIDLIGHT: param->blend = blend_vividlight_##depth##bit; break; \ + case BLEND_XOR: param->blend = blend_xor_##depth##bit; break; \ + } \ +} +DEFINE_INIT_BLEND_FUNC(8, 8); +DEFINE_INIT_BLEND_FUNC(9, 16); +DEFINE_INIT_BLEND_FUNC(10, 16); +DEFINE_INIT_BLEND_FUNC(12, 16); +DEFINE_INIT_BLEND_FUNC(16, 16); + +void ff_blend_init(FilterParams *param, int depth) { - switch (param->mode) { - case BLEND_ADDITION: param->blend = is_16bit ? blend_addition_16bit : blend_addition_8bit; break; - case BLEND_GRAINMERGE: param->blend = is_16bit ? blend_grainmerge_16bit : blend_grainmerge_8bit; break; - case BLEND_AND: param->blend = is_16bit ? blend_and_16bit : blend_and_8bit; break; - case BLEND_AVERAGE: param->blend = is_16bit ? blend_average_16bit : blend_average_8bit; break; - case BLEND_BURN: param->blend = is_16bit ? blend_burn_16bit : blend_burn_8bit; break; - case BLEND_DARKEN: param->blend = is_16bit ? blend_darken_16bit : blend_darken_8bit; break; - case BLEND_DIFFERENCE: param->blend = is_16bit ? blend_difference_16bit : blend_difference_8bit; break; - case BLEND_GRAINEXTRACT: param->blend = is_16bit ? blend_grainextract_16bit: blend_grainextract_8bit; break; - case BLEND_DIVIDE: param->blend = is_16bit ? blend_divide_16bit : blend_divide_8bit; break; - case BLEND_DODGE: param->blend = is_16bit ? blend_dodge_16bit : blend_dodge_8bit; break; - case BLEND_EXCLUSION: param->blend = is_16bit ? blend_exclusion_16bit : blend_exclusion_8bit; break; - case BLEND_EXTREMITY: param->blend = is_16bit ? blend_extremity_16bit : blend_extremity_8bit; break; - case BLEND_FREEZE: param->blend = is_16bit ? blend_freeze_16bit : blend_freeze_8bit; break; - case BLEND_GLOW: param->blend = is_16bit ? blend_glow_16bit : blend_glow_8bit; break; - case BLEND_HARDLIGHT: param->blend = is_16bit ? blend_hardlight_16bit : blend_hardlight_8bit; break; - case BLEND_HARDMIX: param->blend = is_16bit ? blend_hardmix_16bit : blend_hardmix_8bit; break; - case BLEND_HEAT: param->blend = is_16bit ? blend_heat_16bit : blend_heat_8bit; break; - case BLEND_LIGHTEN: param->blend = is_16bit ? blend_lighten_16bit : blend_lighten_8bit; break; - case BLEND_LINEARLIGHT:param->blend = is_16bit ? blend_linearlight_16bit: blend_linearlight_8bit;break; - case BLEND_MULTIPLY: param->blend = is_16bit ? blend_multiply_16bit : blend_multiply_8bit; break; - case BLEND_MULTIPLY128:param->blend = is_16bit ? blend_multiply128_16bit: blend_multiply128_8bit;break; - case BLEND_NEGATION: param->blend = is_16bit ? blend_negation_16bit : blend_negation_8bit; break; - case BLEND_NORMAL: param->blend = param->opacity == 1 ? blend_copytop : - param->opacity == 0 ? blend_copybottom : - is_16bit ? blend_normal_16bit : blend_normal_8bit; break; - case BLEND_OR: param->blend = is_16bit ? blend_or_16bit : blend_or_8bit; break; - case BLEND_OVERLAY: param->blend = is_16bit ? blend_overlay_16bit : blend_overlay_8bit; break; - case BLEND_PHOENIX: param->blend = is_16bit ? blend_phoenix_16bit : blend_phoenix_8bit; break; - case BLEND_PINLIGHT: param->blend = is_16bit ? blend_pinlight_16bit : blend_pinlight_8bit; break; - case BLEND_REFLECT: param->blend = is_16bit ? blend_reflect_16bit : blend_reflect_8bit; break; - case BLEND_SCREEN: param->blend = is_16bit ? blend_screen_16bit : blend_screen_8bit; break; - case BLEND_SOFTLIGHT: param->blend = is_16bit ? blend_softlight_16bit : blend_softlight_8bit; break; - case BLEND_SUBTRACT: param->blend = is_16bit ? blend_subtract_16bit : blend_subtract_8bit; break; - case BLEND_VIVIDLIGHT: param->blend = is_16bit ? blend_vividlight_16bit : blend_vividlight_8bit; break; - case BLEND_XOR: param->blend = is_16bit ? blend_xor_16bit : blend_xor_8bit; break; + switch (depth) { + case 8: + init_blend_func_8_8bit(param); + break; + case 9: + init_blend_func_9_16bit(param); + break; + case 10: + init_blend_func_10_16bit(param); + break; + case 12: + init_blend_func_12_16bit(param); + break; + case 16: + init_blend_func_16_16bit(param); + break; } if (param->opacity == 0 && param->mode != BLEND_NORMAL) { - param->blend = blend_copytop; + param->blend = depth > 8 ? blend_copytop_16 : blend_copytop_8; + } else if (param->mode == BLEND_NORMAL) { + if (param->opacity == 1) + param->blend = depth > 8 ? blend_copytop_16 : blend_copytop_8; + else if (param->opacity == 0) + param->blend = depth > 8 ? blend_copybottom_16 : blend_copybottom_8; } if (ARCH_X86) - ff_blend_init_x86(param, is_16bit); + ff_blend_init_x86(param, depth); } static int config_output(AVFilterLink *outlink) @@ -515,7 +684,7 @@ static int config_output(AVFilterLink *outlink) AVFilterLink *toplink = ctx->inputs[TOP]; BlendContext *s = ctx->priv; const AVPixFmtDescriptor *pix_desc = av_pix_fmt_desc_get(toplink->format); - int ret, plane, is_16bit; + int ret, plane; if (!s->tblend) { AVFilterLink *bottomlink = ctx->inputs[BOTTOM]; @@ -543,7 +712,7 @@ static int config_output(AVFilterLink *outlink) s->hsub = pix_desc->log2_chroma_w; s->vsub = pix_desc->log2_chroma_h; - is_16bit = pix_desc->comp[0].depth == 16; + s->depth = pix_desc->comp[0].depth; s->nb_planes = av_pix_fmt_count_planes(toplink->format); if (!s->tblend) @@ -558,7 +727,7 @@ static int config_output(AVFilterLink *outlink) if (s->all_opacity < 1) param->opacity = s->all_opacity; - ff_blend_init(param, is_16bit); + ff_blend_init(param, s->depth); if (s->all_expr && !param->expr_str) { param->expr_str = av_strdup(s->all_expr); @@ -570,11 +739,17 @@ static int config_output(AVFilterLink *outlink) NULL, NULL, NULL, NULL, 0, ctx); if (ret < 0) return ret; - param->blend = is_16bit? blend_expr_16bit : blend_expr_8bit; + param->blend = s->depth > 8 ? blend_expr_16bit : blend_expr_8bit; } } - return s->tblend ? 0 : ff_framesync_configure(&s->fs); + if (s->tblend) + return 0; + + ret = ff_framesync_configure(&s->fs); + outlink->time_base = s->fs.time_base; + + return ret; } #if CONFIG_BLEND_FILTER @@ -626,11 +801,17 @@ AVFilter ff_vf_blend = { static int tblend_filter_frame(AVFilterLink *inlink, AVFrame *frame) { - BlendContext *s = inlink->dst->priv; - AVFilterLink *outlink = inlink->dst->outputs[0]; + AVFilterContext *ctx = inlink->dst; + BlendContext *s = ctx->priv; + AVFilterLink *outlink = ctx->outputs[0]; if (s->prev_frame) { - AVFrame *out = blend_frame(inlink->dst, frame, s->prev_frame); + AVFrame *out; + + if (ctx->is_disabled) + out = av_frame_clone(frame); + else + out = blend_frame(ctx, frame, s->prev_frame); av_frame_free(&s->prev_frame); s->prev_frame = frame; return ff_filter_frame(outlink, out); @@ -674,7 +855,7 @@ AVFilter ff_vf_tblend = { .uninit = uninit, .inputs = tblend_inputs, .outputs = tblend_outputs, - .flags = AVFILTER_FLAG_SLICE_THREADS, + .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | AVFILTER_FLAG_SLICE_THREADS, }; #endif diff --git a/libavfilter/vf_bm3d.c b/libavfilter/vf_bm3d.c new file mode 100644 index 000000000..75c356728 --- /dev/null +++ b/libavfilter/vf_bm3d.c @@ -0,0 +1,1077 @@ +/* + * Copyright (c) 2015-2016 mawen1250 + * Copyright (c) 2018 Paul B Mahol + * + * This file is part of FFmpeg. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/** + * @todo + * - non-power of 2 DCT + * - opponent color space + * - temporal support + */ + +#include + +#include "libavutil/avassert.h" +#include "libavutil/imgutils.h" +#include "libavutil/opt.h" +#include "libavutil/pixdesc.h" +#include "libavcodec/avfft.h" +#include "avfilter.h" +#include "filters.h" +#include "formats.h" +#include "framesync.h" +#include "internal.h" +#include "video.h" + +#define MAX_NB_THREADS 32 + +enum FilterModes { + BASIC, + FINAL, + NB_MODES, +}; + +typedef struct ThreadData { + const uint8_t *src; + int src_linesize; + const uint8_t *ref; + int ref_linesize; + int plane; +} ThreadData; + +typedef struct PosCode { + int x, y; +} PosCode; + +typedef struct PosPairCode { + double score; + int x, y; +} PosPairCode; + +typedef struct SliceContext { + DCTContext *gdctf, *gdcti; + DCTContext *dctf, *dcti; + FFTSample *bufferh; + FFTSample *bufferv; + FFTSample *bufferz; + FFTSample *buffer; + FFTSample *rbufferh; + FFTSample *rbufferv; + FFTSample *rbufferz; + FFTSample *rbuffer; + float *num, *den; + PosPairCode match_blocks[256]; + int nb_match_blocks; + PosCode *search_positions; +} SliceContext; + +typedef struct BM3DContext { + const AVClass *class; + + float sigma; + int block_size; + int block_step; + int group_size; + int bm_range; + int bm_step; + float th_mse; + float hard_threshold; + int mode; + int ref; + int planes; + + int depth; + int max; + int nb_planes; + int planewidth[4]; + int planeheight[4]; + int group_bits; + int pgroup_size; + + SliceContext slices[MAX_NB_THREADS]; + + FFFrameSync fs; + int nb_threads; + + void (*get_block_row)(const uint8_t *srcp, int src_linesize, + int y, int x, int block_size, float *dst); + double (*do_block_ssd)(struct BM3DContext *s, PosCode *pos, + const uint8_t *src, int src_stride, + int r_y, int r_x); + void (*do_output)(struct BM3DContext *s, uint8_t *dst, int dst_linesize, + int plane, int nb_jobs); + void (*block_filtering)(struct BM3DContext *s, + const uint8_t *src, int src_linesize, + const uint8_t *ref, int ref_linesize, + int y, int x, int plane, int jobnr); +} BM3DContext; + +#define OFFSET(x) offsetof(BM3DContext, x) +#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM +static const AVOption bm3d_options[] = { + { "sigma", "set denoising strength", + OFFSET(sigma), AV_OPT_TYPE_FLOAT, {.dbl=1}, 0, 99999.9, FLAGS }, + { "block", "set log2(size) of local patch", + OFFSET(block_size), AV_OPT_TYPE_INT, {.i64=4}, 4, 6, FLAGS }, + { "bstep", "set sliding step for processing blocks", + OFFSET(block_step), AV_OPT_TYPE_INT, {.i64=4}, 1, 64, FLAGS }, + { "group", "set maximal number of similar blocks", + OFFSET(group_size), AV_OPT_TYPE_INT, {.i64=1}, 1, 256, FLAGS }, + { "range", "set block matching range", + OFFSET(bm_range), AV_OPT_TYPE_INT, {.i64=9}, 1, INT32_MAX, FLAGS }, + { "mstep", "set step for block matching", + OFFSET(bm_step), AV_OPT_TYPE_INT, {.i64=1}, 1, 64, FLAGS }, + { "thmse", "set threshold of mean square error for block matching", + OFFSET(th_mse), AV_OPT_TYPE_FLOAT, {.dbl=0}, 0, INT32_MAX, FLAGS }, + { "hdthr", "set hard threshold for 3D transfer domain", + OFFSET(hard_threshold), AV_OPT_TYPE_FLOAT, {.dbl=2.7}, 0, INT32_MAX, FLAGS }, + { "estim", "set filtering estimation mode", + OFFSET(mode), AV_OPT_TYPE_INT, {.i64=BASIC}, 0, NB_MODES-1, FLAGS, "mode" }, + { "basic", "basic estimate", + 0, AV_OPT_TYPE_CONST, {.i64=BASIC}, 0, 0, FLAGS, "mode" }, + { "final", "final estimate", + 0, AV_OPT_TYPE_CONST, {.i64=FINAL}, 0, 0, FLAGS, "mode" }, + { "ref", "have reference stream", + OFFSET(ref), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, FLAGS }, + { "planes", "set planes to filter", + OFFSET(planes), AV_OPT_TYPE_INT, {.i64=7}, 0, 15, FLAGS }, + { NULL } +}; + +AVFILTER_DEFINE_CLASS(bm3d); + +static int query_formats(AVFilterContext *ctx) +{ + static const enum AVPixelFormat pix_fmts[] = { + AV_PIX_FMT_GRAY8, + AV_PIX_FMT_GRAY9, AV_PIX_FMT_GRAY10, + AV_PIX_FMT_GRAY12, AV_PIX_FMT_GRAY16, + AV_PIX_FMT_YUV410P, AV_PIX_FMT_YUV411P, + AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV422P, + AV_PIX_FMT_YUV440P, AV_PIX_FMT_YUV444P, + AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUVJ422P, + AV_PIX_FMT_YUVJ440P, AV_PIX_FMT_YUVJ444P, + AV_PIX_FMT_YUVJ411P, + AV_PIX_FMT_YUV420P9, AV_PIX_FMT_YUV422P9, AV_PIX_FMT_YUV444P9, + AV_PIX_FMT_YUV420P10, AV_PIX_FMT_YUV422P10, AV_PIX_FMT_YUV444P10, + AV_PIX_FMT_YUV440P10, + AV_PIX_FMT_YUV444P12, AV_PIX_FMT_YUV422P12, AV_PIX_FMT_YUV420P12, + AV_PIX_FMT_YUV440P12, + AV_PIX_FMT_YUV444P14, AV_PIX_FMT_YUV422P14, AV_PIX_FMT_YUV420P14, + AV_PIX_FMT_YUV420P16, AV_PIX_FMT_YUV422P16, AV_PIX_FMT_YUV444P16, + AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRP9, AV_PIX_FMT_GBRP10, + AV_PIX_FMT_GBRP12, AV_PIX_FMT_GBRP14, AV_PIX_FMT_GBRP16, + AV_PIX_FMT_NONE + }; + + AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts); + if (!fmts_list) + return AVERROR(ENOMEM); + return ff_set_common_formats(ctx, fmts_list); +} + +static int do_search_boundary(int pos, int plane_boundary, int search_range, int search_step) +{ + int search_boundary; + + search_range = search_range / search_step * search_step; + + if (pos == plane_boundary) { + search_boundary = plane_boundary; + } else if (pos > plane_boundary) { + search_boundary = pos - search_range; + + while (search_boundary < plane_boundary) { + search_boundary += search_step; + } + } else { + search_boundary = pos + search_range; + + while (search_boundary > plane_boundary) { + search_boundary -= search_step; + } + } + + return search_boundary; +} + +static int search_boundary(int plane_boundary, int search_range, int search_step, int vertical, int y, int x) +{ + return do_search_boundary(vertical ? y : x, plane_boundary, search_range, search_step); +} + +static int cmp_scores(const void *a, const void *b) +{ + const struct PosPairCode *pair1 = a; + const struct PosPairCode *pair2 = b; + return FFDIFFSIGN(pair1->score, pair2->score); +} + +static double do_block_ssd(BM3DContext *s, PosCode *pos, const uint8_t *src, int src_stride, int r_y, int r_x) +{ + const uint8_t *srcp = src + pos->y * src_stride + pos->x; + const uint8_t *refp = src + r_y * src_stride + r_x; + const int block_size = s->block_size; + double dist = 0.; + int x, y; + + for (y = 0; y < block_size; y++) { + for (x = 0; x < block_size; x++) { + double temp = refp[x] - srcp[x]; + dist += temp * temp; + } + + srcp += src_stride; + refp += src_stride; + } + + return dist; +} + +static double do_block_ssd16(BM3DContext *s, PosCode *pos, const uint8_t *src, int src_stride, int r_y, int r_x) +{ + const uint16_t *srcp = (uint16_t *)src + pos->y * src_stride / 2 + pos->x; + const uint16_t *refp = (uint16_t *)src + r_y * src_stride / 2 + r_x; + const int block_size = s->block_size; + double dist = 0.; + int x, y; + + for (y = 0; y < block_size; y++) { + for (x = 0; x < block_size; x++) { + double temp = refp[x] - srcp[x]; + dist += temp * temp; + } + + srcp += src_stride / 2; + refp += src_stride / 2; + } + + return dist; +} + +static void do_block_matching_multi(BM3DContext *s, const uint8_t *src, int src_stride, int src_range, + const PosCode *search_pos, int search_size, float th_mse, + int r_y, int r_x, int plane, int jobnr) +{ + SliceContext *sc = &s->slices[jobnr]; + double MSE2SSE = s->group_size * s->block_size * s->block_size * src_range * src_range / (s->max * s->max); + double distMul = 1. / MSE2SSE; + double th_sse = th_mse * MSE2SSE; + int i, index = sc->nb_match_blocks; + + for (i = 0; i < search_size; i++) { + PosCode pos = search_pos[i]; + double dist; + + dist = s->do_block_ssd(s, &pos, src, src_stride, r_y, r_x); + + // Only match similar blocks but not identical blocks + if (dist <= th_sse && dist != 0) { + const double score = dist * distMul; + + if (index >= s->group_size && score >= sc->match_blocks[index - 1].score) { + continue; + } + + if (index >= s->group_size) + index = s->group_size - 1; + + sc->match_blocks[index].score = score; + sc->match_blocks[index].y = pos.y; + sc->match_blocks[index].x = pos.x; + index++; + qsort(sc->match_blocks, index, sizeof(PosPairCode), cmp_scores); + } + } + + sc->nb_match_blocks = index; +} + +static void block_matching_multi(BM3DContext *s, const uint8_t *ref, int ref_linesize, int y, int x, + int exclude_cur_pos, int plane, int jobnr) +{ + SliceContext *sc = &s->slices[jobnr]; + const int width = s->planewidth[plane]; + const int height = s->planeheight[plane]; + const int block_size = s->block_size; + const int step = s->bm_step; + const int range = s->bm_range / step * step; + int l = search_boundary(0, range, step, 0, y, x); + int r = search_boundary(width - block_size, range, step, 0, y, x); + int t = search_boundary(0, range, step, 1, y, x); + int b = search_boundary(height - block_size, range, step, 1, y, x); + int j, i, index = 0; + + for (j = t; j <= b; j += step) { + for (i = l; i <= r; i += step) { + PosCode pos; + + if (exclude_cur_pos > 0 && j == y && i == x) { + continue; + } + + pos.y = j; + pos.x = i; + sc->search_positions[index++] = pos; + } + } + + if (exclude_cur_pos == 1) { + sc->match_blocks[0].score = 0; + sc->match_blocks[0].y = y; + sc->match_blocks[0].x = x; + sc->nb_match_blocks = 1; + } + + do_block_matching_multi(s, ref, ref_linesize, s->bm_range, + sc->search_positions, index, s->th_mse, y, x, plane, jobnr); +} + +static void block_matching(BM3DContext *s, const uint8_t *ref, int ref_linesize, + int j, int i, int plane, int jobnr) +{ + SliceContext *sc = &s->slices[jobnr]; + + if (s->group_size == 1 || s->th_mse <= 0.f) { + sc->match_blocks[0].score = 1; + sc->match_blocks[0].x = i; + sc->match_blocks[0].y = j; + sc->nb_match_blocks = 1; + return; + } + + sc->nb_match_blocks = 0; + block_matching_multi(s, ref, ref_linesize, j, i, 1, plane, jobnr); +} + +static void get_block_row(const uint8_t *srcp, int src_linesize, + int y, int x, int block_size, float *dst) +{ + const uint8_t *src = srcp + y * src_linesize + x; + int j; + + for (j = 0; j < block_size; j++) { + dst[j] = src[j]; + } +} + +static void get_block_row16(const uint8_t *srcp, int src_linesize, + int y, int x, int block_size, float *dst) +{ + const uint16_t *src = (uint16_t *)srcp + y * src_linesize / 2 + x; + int j; + + for (j = 0; j < block_size; j++) { + dst[j] = src[j]; + } +} + +static void basic_block_filtering(BM3DContext *s, const uint8_t *src, int src_linesize, + const uint8_t *ref, int ref_linesize, + int y, int x, int plane, int jobnr) +{ + SliceContext *sc = &s->slices[jobnr]; + const int buffer_linesize = s->block_size * s->block_size; + const int nb_match_blocks = sc->nb_match_blocks; + const int block_size = s->block_size; + const int width = s->planewidth[plane]; + const int pgroup_size = s->pgroup_size; + const int group_size = s->group_size; + float *buffer = sc->buffer; + float *bufferh = sc->bufferh; + float *bufferv = sc->bufferv; + float *bufferz = sc->bufferz; + float threshold[4]; + float den_weight, num_weight; + int retained = 0; + int i, j, k; + + for (k = 0; k < nb_match_blocks; k++) { + const int y = sc->match_blocks[k].y; + const int x = sc->match_blocks[k].x; + + for (i = 0; i < block_size; i++) { + s->get_block_row(src, src_linesize, y + i, x, block_size, bufferh + block_size * i); + av_dct_calc(sc->dctf, bufferh + block_size * i); + } + + for (i = 0; i < block_size; i++) { + for (j = 0; j < block_size; j++) { + bufferv[i * block_size + j] = bufferh[j * block_size + i]; + } + av_dct_calc(sc->dctf, bufferv + i * block_size); + } + + for (i = 0; i < block_size; i++) { + memcpy(buffer + k * buffer_linesize + i * block_size, + bufferv + i * block_size, block_size * 4); + } + } + + for (i = 0; i < block_size; i++) { + for (j = 0; j < block_size; j++) { + for (k = 0; k < nb_match_blocks; k++) + bufferz[k] = buffer[buffer_linesize * k + i * block_size + j]; + if (group_size > 1) + av_dct_calc(sc->gdctf, bufferz); + bufferz += pgroup_size; + } + } + + threshold[0] = s->hard_threshold * s->sigma; + threshold[1] = threshold[0] * sqrtf(2.f); + threshold[2] = threshold[0] * 2.f; + threshold[3] = threshold[0] * sqrtf(8.f); + bufferz = sc->bufferz; + + for (i = 0; i < block_size; i++) { + for (j = 0; j < block_size; j++) { + for (k = 0; k < nb_match_blocks; k++) { + const float thresh = threshold[(j == 0) + (i == 0) + (k == 0)]; + + if (bufferz[k] > thresh || bufferz[k] < -thresh) { + retained++; + } else { + bufferz[k] = 0; + } + } + bufferz += pgroup_size; + } + } + + bufferz = sc->bufferz; + buffer = sc->buffer; + for (i = 0; i < block_size; i++) { + for (j = 0; j < block_size; j++) { + if (group_size > 1) + av_dct_calc(sc->gdcti, bufferz); + for (k = 0; k < nb_match_blocks; k++) { + buffer[buffer_linesize * k + i * block_size + j] = bufferz[k]; + } + bufferz += pgroup_size; + } + } + + den_weight = retained < 1 ? 1.f : 1.f / retained; + num_weight = den_weight; + + buffer = sc->buffer; + for (k = 0; k < nb_match_blocks; k++) { + float *num = sc->num + y * width + x; + float *den = sc->den + y * width + x; + + for (i = 0; i < block_size; i++) { + memcpy(bufferv + i * block_size, + buffer + k * buffer_linesize + i * block_size, + block_size * 4); + } + + for (i = 0; i < block_size; i++) { + av_dct_calc(sc->dcti, bufferv + block_size * i); + for (j = 0; j < block_size; j++) { + bufferh[j * block_size + i] = bufferv[i * block_size + j]; + } + } + + for (i = 0; i < block_size; i++) { + av_dct_calc(sc->dcti, bufferh + block_size * i); + for (j = 0; j < block_size; j++) { + num[j] += bufferh[i * block_size + j] * num_weight; + den[j] += den_weight; + } + num += width; + den += width; + } + } +} + +static void final_block_filtering(BM3DContext *s, const uint8_t *src, int src_linesize, + const uint8_t *ref, int ref_linesize, + int y, int x, int plane, int jobnr) +{ + SliceContext *sc = &s->slices[jobnr]; + const int buffer_linesize = s->block_size * s->block_size; + const int nb_match_blocks = sc->nb_match_blocks; + const int block_size = s->block_size; + const int width = s->planewidth[plane]; + const int pgroup_size = s->pgroup_size; + const int group_size = s->group_size; + const float sigma_sqr = s->sigma * s->sigma; + float *buffer = sc->buffer; + float *bufferh = sc->bufferh; + float *bufferv = sc->bufferv; + float *bufferz = sc->bufferz; + float *rbuffer = sc->rbuffer; + float *rbufferh = sc->rbufferh; + float *rbufferv = sc->rbufferv; + float *rbufferz = sc->rbufferz; + float den_weight, num_weight; + float l2_wiener = 0; + int i, j, k; + + for (k = 0; k < nb_match_blocks; k++) { + const int y = sc->match_blocks[k].y; + const int x = sc->match_blocks[k].x; + + for (i = 0; i < block_size; i++) { + s->get_block_row(src, src_linesize, y + i, x, block_size, bufferh + block_size * i); + s->get_block_row(ref, ref_linesize, y + i, x, block_size, rbufferh + block_size * i); + av_dct_calc(sc->dctf, bufferh + block_size * i); + av_dct_calc(sc->dctf, rbufferh + block_size * i); + } + + for (i = 0; i < block_size; i++) { + for (j = 0; j < block_size; j++) { + bufferv[i * block_size + j] = bufferh[j * block_size + i]; + rbufferv[i * block_size + j] = rbufferh[j * block_size + i]; + } + av_dct_calc(sc->dctf, bufferv + i * block_size); + av_dct_calc(sc->dctf, rbufferv + i * block_size); + } + + for (i = 0; i < block_size; i++) { + memcpy(buffer + k * buffer_linesize + i * block_size, + bufferv + i * block_size, block_size * 4); + memcpy(rbuffer + k * buffer_linesize + i * block_size, + rbufferv + i * block_size, block_size * 4); + } + } + + for (i = 0; i < block_size; i++) { + for (j = 0; j < block_size; j++) { + for (k = 0; k < nb_match_blocks; k++) { + bufferz[k] = buffer[buffer_linesize * k + i * block_size + j]; + rbufferz[k] = rbuffer[buffer_linesize * k + i * block_size + j]; + } + if (group_size > 1) { + av_dct_calc(sc->gdctf, bufferz); + av_dct_calc(sc->gdctf, rbufferz); + } + bufferz += pgroup_size; + rbufferz += pgroup_size; + } + } + + bufferz = sc->bufferz; + rbufferz = sc->rbufferz; + + for (i = 0; i < block_size; i++) { + for (j = 0; j < block_size; j++) { + for (k = 0; k < nb_match_blocks; k++) { + const float ref_sqr = rbufferz[k] * rbufferz[k]; + float wiener_coef = ref_sqr / (ref_sqr + sigma_sqr); + + if (isnan(wiener_coef)) + wiener_coef = 1; + bufferz[k] *= wiener_coef; + l2_wiener += wiener_coef * wiener_coef; + } + bufferz += pgroup_size; + rbufferz += pgroup_size; + } + } + + bufferz = sc->bufferz; + buffer = sc->buffer; + for (i = 0; i < block_size; i++) { + for (j = 0; j < block_size; j++) { + if (group_size > 1) + av_dct_calc(sc->gdcti, bufferz); + for (k = 0; k < nb_match_blocks; k++) { + buffer[buffer_linesize * k + i * block_size + j] = bufferz[k]; + } + bufferz += pgroup_size; + } + } + + l2_wiener = FFMAX(l2_wiener, 1e-15f); + den_weight = 1.f / l2_wiener; + num_weight = den_weight; + + for (k = 0; k < nb_match_blocks; k++) { + float *num = sc->num + y * width + x; + float *den = sc->den + y * width + x; + + for (i = 0; i < block_size; i++) { + memcpy(bufferv + i * block_size, + buffer + k * buffer_linesize + i * block_size, + block_size * 4); + } + + for (i = 0; i < block_size; i++) { + av_dct_calc(sc->dcti, bufferv + block_size * i); + for (j = 0; j < block_size; j++) { + bufferh[j * block_size + i] = bufferv[i * block_size + j]; + } + } + + for (i = 0; i < block_size; i++) { + av_dct_calc(sc->dcti, bufferh + block_size * i); + for (j = 0; j < block_size; j++) { + num[j] += bufferh[i * block_size + j] * num_weight; + den[j] += den_weight; + } + num += width; + den += width; + } + } +} + +static void do_output(BM3DContext *s, uint8_t *dst, int dst_linesize, + int plane, int nb_jobs) +{ + const int height = s->planeheight[plane]; + const int width = s->planewidth[plane]; + int i, j, k; + + for (i = 0; i < height; i++) { + for (j = 0; j < width; j++) { + uint8_t *dstp = dst + i * dst_linesize; + float sum_den = 0.f; + float sum_num = 0.f; + + for (k = 0; k < nb_jobs; k++) { + SliceContext *sc = &s->slices[k]; + float num = sc->num[i * width + j]; + float den = sc->den[i * width + j]; + + sum_num += num; + sum_den += den; + } + + dstp[j] = av_clip_uint8(sum_num / sum_den); + } + } +} + +static void do_output16(BM3DContext *s, uint8_t *dst, int dst_linesize, + int plane, int nb_jobs) +{ + const int height = s->planeheight[plane]; + const int width = s->planewidth[plane]; + const int depth = s->depth; + int i, j, k; + + for (i = 0; i < height; i++) { + for (j = 0; j < width; j++) { + uint16_t *dstp = (uint16_t *)dst + i * dst_linesize / 2; + float sum_den = 0.f; + float sum_num = 0.f; + + for (k = 0; k < nb_jobs; k++) { + SliceContext *sc = &s->slices[k]; + float num = sc->num[i * width + j]; + float den = sc->den[i * width + j]; + + sum_num += num; + sum_den += den; + } + + dstp[j] = av_clip_uintp2_c(sum_num / sum_den, depth); + } + } +} + +static int filter_slice(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) +{ + BM3DContext *s = ctx->priv; + SliceContext *sc = &s->slices[jobnr]; + const int block_step = s->block_step; + ThreadData *td = arg; + const uint8_t *src = td->src; + const uint8_t *ref = td->ref; + const int src_linesize = td->src_linesize; + const int ref_linesize = td->ref_linesize; + const int plane = td->plane; + const int width = s->planewidth[plane]; + const int height = s->planeheight[plane]; + const int block_pos_bottom = height - s->block_size; + const int block_pos_right = width - s->block_size; + const int slice_start = (((height + block_step - 1) / block_step) * jobnr / nb_jobs) * block_step; + const int slice_end = (jobnr == nb_jobs - 1) ? block_pos_bottom + block_step : + (((height + block_step - 1) / block_step) * (jobnr + 1) / nb_jobs) * block_step; + int i, j; + + memset(sc->num, 0, width * height * sizeof(FFTSample)); + memset(sc->den, 0, width * height * sizeof(FFTSample)); + + for (j = slice_start; j < slice_end; j += block_step) { + if (j > block_pos_bottom) { + j = block_pos_bottom; + } + + for (i = 0; i < block_pos_right + block_step; i += block_step) { + if (i > block_pos_right) { + i = block_pos_right; + } + + block_matching(s, ref, ref_linesize, j, i, plane, jobnr); + + s->block_filtering(s, src, src_linesize, + ref, ref_linesize, j, i, plane, jobnr); + } + } + + return 0; +} + +static int filter_frame(AVFilterContext *ctx, AVFrame **out, AVFrame *in, AVFrame *ref) +{ + BM3DContext *s = ctx->priv; + AVFilterLink *outlink = ctx->outputs[0]; + int p; + + *out = ff_get_video_buffer(outlink, outlink->w, outlink->h); + if (!*out) + return AVERROR(ENOMEM); + av_frame_copy_props(*out, in); + + for (p = 0; p < s->nb_planes; p++) { + const int nb_jobs = FFMIN(s->nb_threads, s->planeheight[p] / s->block_step); + ThreadData td; + + if (!((1 << p) & s->planes) || ctx->is_disabled) { + av_image_copy_plane((*out)->data[p], (*out)->linesize[p], + in->data[p], in->linesize[p], + s->planewidth[p], s->planeheight[p]); + continue; + } + + td.src = in->data[p]; + td.src_linesize = in->linesize[p]; + td.ref = ref->data[p]; + td.ref_linesize = ref->linesize[p]; + td.plane = p; + ctx->internal->execute(ctx, filter_slice, &td, NULL, nb_jobs); + + s->do_output(s, (*out)->data[p], (*out)->linesize[p], p, nb_jobs); + } + + return 0; +} + +#define SQR(x) ((x) * (x)) + +static int config_input(AVFilterLink *inlink) +{ + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format); + AVFilterContext *ctx = inlink->dst; + BM3DContext *s = ctx->priv; + int i, group_bits; + + s->nb_threads = FFMIN(ff_filter_get_nb_threads(ctx), MAX_NB_THREADS); + s->nb_planes = av_pix_fmt_count_planes(inlink->format); + s->depth = desc->comp[0].depth; + s->max = (1 << s->depth) - 1; + s->planeheight[1] = s->planeheight[2] = AV_CEIL_RSHIFT(inlink->h, desc->log2_chroma_h); + s->planeheight[0] = s->planeheight[3] = inlink->h; + s->planewidth[1] = s->planewidth[2] = AV_CEIL_RSHIFT(inlink->w, desc->log2_chroma_w); + s->planewidth[0] = s->planewidth[3] = inlink->w; + + for (group_bits = 4; 1 << group_bits < s->group_size; group_bits++); + s->group_bits = group_bits; + s->pgroup_size = 1 << group_bits; + + for (i = 0; i < s->nb_threads; i++) { + SliceContext *sc = &s->slices[i]; + + sc->num = av_calloc(s->planewidth[0] * s->planeheight[0], sizeof(FFTSample)); + sc->den = av_calloc(s->planewidth[0] * s->planeheight[0], sizeof(FFTSample)); + if (!sc->num || !sc->den) + return AVERROR(ENOMEM); + + sc->dctf = av_dct_init(av_log2(s->block_size), DCT_II); + sc->dcti = av_dct_init(av_log2(s->block_size), DCT_III); + if (!sc->dctf || !sc->dcti) + return AVERROR(ENOMEM); + + if (s->group_bits > 1) { + sc->gdctf = av_dct_init(s->group_bits, DCT_II); + sc->gdcti = av_dct_init(s->group_bits, DCT_III); + if (!sc->gdctf || !sc->gdcti) + return AVERROR(ENOMEM); + } + + sc->buffer = av_calloc(s->block_size * s->block_size * s->pgroup_size, sizeof(*sc->buffer)); + sc->bufferz = av_calloc(s->block_size * s->block_size * s->pgroup_size, sizeof(*sc->bufferz)); + sc->bufferh = av_calloc(s->block_size * s->block_size, sizeof(*sc->bufferh)); + sc->bufferv = av_calloc(s->block_size * s->block_size, sizeof(*sc->bufferv)); + if (!sc->bufferh || !sc->bufferv || !sc->buffer || !sc->bufferz) + return AVERROR(ENOMEM); + + if (s->mode == FINAL) { + sc->rbuffer = av_calloc(s->block_size * s->block_size * s->pgroup_size, sizeof(*sc->rbuffer)); + sc->rbufferz = av_calloc(s->block_size * s->block_size * s->pgroup_size, sizeof(*sc->rbufferz)); + sc->rbufferh = av_calloc(s->block_size * s->block_size, sizeof(*sc->rbufferh)); + sc->rbufferv = av_calloc(s->block_size * s->block_size, sizeof(*sc->rbufferv)); + if (!sc->rbufferh || !sc->rbufferv || !sc->rbuffer || !sc->rbufferz) + return AVERROR(ENOMEM); + } + + sc->search_positions = av_calloc(SQR(2 * s->bm_range / s->bm_step + 1), sizeof(*sc->search_positions)); + if (!sc->search_positions) + return AVERROR(ENOMEM); + } + + s->do_output = do_output; + s->do_block_ssd = do_block_ssd; + s->get_block_row = get_block_row; + + if (s->depth > 8) { + s->do_output = do_output16; + s->do_block_ssd = do_block_ssd16; + s->get_block_row = get_block_row16; + } + + return 0; +} + +static int activate(AVFilterContext *ctx) +{ + BM3DContext *s = ctx->priv; + + if (!s->ref) { + AVFrame *frame = NULL; + AVFrame *out = NULL; + int ret, status; + int64_t pts; + + if ((ret = ff_inlink_consume_frame(ctx->inputs[0], &frame)) > 0) { + ret = filter_frame(ctx, &out, frame, frame); + av_frame_free(&frame); + if (ret < 0) + return ret; + ret = ff_filter_frame(ctx->outputs[0], out); + } + if (ret < 0) { + return ret; + } else if (ff_inlink_acknowledge_status(ctx->inputs[0], &status, &pts)) { + ff_outlink_set_status(ctx->outputs[0], status, pts); + return 0; + } else { + if (ff_outlink_frame_wanted(ctx->outputs[0])) + ff_inlink_request_frame(ctx->inputs[0]); + return 0; + } + } else { + return ff_framesync_activate(&s->fs); + } +} + +static int process_frame(FFFrameSync *fs) +{ + AVFilterContext *ctx = fs->parent; + BM3DContext *s = fs->opaque; + AVFilterLink *outlink = ctx->outputs[0]; + AVFrame *out = NULL, *src, *ref; + int ret; + + if ((ret = ff_framesync_get_frame(&s->fs, 0, &src, 0)) < 0 || + (ret = ff_framesync_get_frame(&s->fs, 1, &ref, 0)) < 0) + return ret; + + if ((ret = filter_frame(ctx, &out, src, ref)) < 0) + return ret; + + out->pts = av_rescale_q(src->pts, s->fs.time_base, outlink->time_base); + + return ff_filter_frame(outlink, out); +} + +static av_cold int init(AVFilterContext *ctx) +{ + BM3DContext *s = ctx->priv; + AVFilterPad pad = { 0 }; + int ret; + + if (s->mode == BASIC) { + if (s->th_mse == 0.f) + s->th_mse = 400.f + s->sigma * 80.f; + s->block_filtering = basic_block_filtering; + } else if (s->mode == FINAL) { + if (!s->ref) { + av_log(ctx, AV_LOG_WARNING, "Reference stream is mandatory in final estimation mode.\n"); + s->ref = 1; + } + if (s->th_mse == 0.f) + s->th_mse = 200.f + s->sigma * 10.f; + + s->block_filtering = final_block_filtering; + } else { + return AVERROR_BUG; + } + + s->block_size = 1 << s->block_size; + + if (s->block_step > s->block_size) { + av_log(ctx, AV_LOG_WARNING, "bstep: %d can't be bigger than block size. Changing to %d.\n", + s->block_step, s->block_size); + s->block_step = s->block_size; + } + if (s->bm_step > s->bm_range) { + av_log(ctx, AV_LOG_WARNING, "mstep: %d can't be bigger than block matching range. Changing to %d.\n", + s->bm_step, s->bm_range); + s->bm_step = s->bm_range; + } + + pad.type = AVMEDIA_TYPE_VIDEO; + pad.name = av_strdup("source"); + pad.config_props = config_input; + if (!pad.name) + return AVERROR(ENOMEM); + + if ((ret = ff_insert_inpad(ctx, 0, &pad)) < 0) { + av_freep(&pad.name); + return ret; + } + + if (s->ref) { + pad.type = AVMEDIA_TYPE_VIDEO; + pad.name = av_strdup("reference"); + pad.config_props = NULL; + if (!pad.name) + return AVERROR(ENOMEM); + + if ((ret = ff_insert_inpad(ctx, 1, &pad)) < 0) { + av_freep(&pad.name); + return ret; + } + } + + return 0; +} + +static int config_output(AVFilterLink *outlink) +{ + AVFilterContext *ctx = outlink->src; + BM3DContext *s = ctx->priv; + AVFilterLink *src = ctx->inputs[0]; + AVFilterLink *ref; + FFFrameSyncIn *in; + int ret; + + if (s->ref) { + ref = ctx->inputs[1]; + + if (src->format != ref->format) { + av_log(ctx, AV_LOG_ERROR, "inputs must be of same pixel format\n"); + return AVERROR(EINVAL); + } + if (src->w != ref->w || + src->h != ref->h) { + av_log(ctx, AV_LOG_ERROR, "First input link %s parameters " + "(size %dx%d) do not match the corresponding " + "second input link %s parameters (%dx%d) ", + ctx->input_pads[0].name, src->w, src->h, + ctx->input_pads[1].name, ref->w, ref->h); + return AVERROR(EINVAL); + } + } + + outlink->w = src->w; + outlink->h = src->h; + outlink->time_base = src->time_base; + outlink->sample_aspect_ratio = src->sample_aspect_ratio; + outlink->frame_rate = src->frame_rate; + + if (!s->ref) + return 0; + + if ((ret = ff_framesync_init(&s->fs, ctx, 2)) < 0) + return ret; + + in = s->fs.in; + in[0].time_base = src->time_base; + in[1].time_base = ref->time_base; + in[0].sync = 1; + in[0].before = EXT_STOP; + in[0].after = EXT_STOP; + in[1].sync = 1; + in[1].before = EXT_STOP; + in[1].after = EXT_STOP; + s->fs.opaque = s; + s->fs.on_event = process_frame; + + return ff_framesync_configure(&s->fs); +} + +static av_cold void uninit(AVFilterContext *ctx) +{ + BM3DContext *s = ctx->priv; + int i; + + for (i = 0; i < ctx->nb_inputs; i++) + av_freep(&ctx->input_pads[i].name); + + if (s->ref) + ff_framesync_uninit(&s->fs); + + for (i = 0; i < s->nb_threads; i++) { + SliceContext *sc = &s->slices[i]; + + av_freep(&sc->num); + av_freep(&sc->den); + + av_dct_end(sc->gdctf); + av_dct_end(sc->gdcti); + av_dct_end(sc->dctf); + av_dct_end(sc->dcti); + + av_freep(&sc->buffer); + av_freep(&sc->bufferh); + av_freep(&sc->bufferv); + av_freep(&sc->bufferz); + av_freep(&sc->rbuffer); + av_freep(&sc->rbufferh); + av_freep(&sc->rbufferv); + av_freep(&sc->rbufferz); + + av_freep(&sc->search_positions); + } +} + +static const AVFilterPad bm3d_outputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + .config_props = config_output, + }, + { NULL } +}; + +AVFilter ff_vf_bm3d = { + .name = "bm3d", + .description = NULL_IF_CONFIG_SMALL("Block-Matching 3D denoiser."), + .priv_size = sizeof(BM3DContext), + .init = init, + .uninit = uninit, + .activate = activate, + .query_formats = query_formats, + .inputs = NULL, + .outputs = bm3d_outputs, + .priv_class = &bm3d_class, + .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | + AVFILTER_FLAG_DYNAMIC_INPUTS | + AVFILTER_FLAG_SLICE_THREADS, +}; diff --git a/libavfilter/vf_boxblur.c b/libavfilter/vf_boxblur.c index 8e4398684..bde74084f 100644 --- a/libavfilter/vf_boxblur.c +++ b/libavfilter/vf_boxblur.c @@ -27,39 +27,13 @@ #include "libavutil/avstring.h" #include "libavutil/common.h" -#include "libavutil/eval.h" #include "libavutil/opt.h" -#include "libavutil/pixdesc.h" #include "avfilter.h" #include "formats.h" #include "internal.h" #include "video.h" +#include "boxblur.h" -static const char *const var_names[] = { - "w", - "h", - "cw", - "ch", - "hsub", - "vsub", - NULL -}; - -enum var_name { - VAR_W, - VAR_H, - VAR_CW, - VAR_CH, - VAR_HSUB, - VAR_VSUB, - VARS_NB -}; - -typedef struct FilterParam { - int radius; - int power; - char *radius_expr; -} FilterParam; typedef struct BoxBlurContext { const AVClass *class; @@ -73,40 +47,6 @@ typedef struct BoxBlurContext { uint8_t *temp[2]; ///< temporary buffer used in blur_power() } BoxBlurContext; -#define Y 0 -#define U 1 -#define V 2 -#define A 3 - -static av_cold int init(AVFilterContext *ctx) -{ - BoxBlurContext *s = ctx->priv; - - if (!s->luma_param.radius_expr) { - av_log(ctx, AV_LOG_ERROR, "Luma radius expression is not set.\n"); - return AVERROR(EINVAL); - } - - /* fill missing params */ - if (!s->chroma_param.radius_expr) { - s->chroma_param.radius_expr = av_strdup(s->luma_param.radius_expr); - if (!s->chroma_param.radius_expr) - return AVERROR(ENOMEM); - } - if (s->chroma_param.power < 0) - s->chroma_param.power = s->luma_param.power; - - if (!s->alpha_param.radius_expr) { - s->alpha_param.radius_expr = av_strdup(s->luma_param.radius_expr); - if (!s->alpha_param.radius_expr) - return AVERROR(ENOMEM); - } - if (s->alpha_param.power < 0) - s->alpha_param.power = s->luma_param.power; - - return 0; -} - static av_cold void uninit(AVFilterContext *ctx) { BoxBlurContext *s = ctx->priv; @@ -138,9 +78,6 @@ static int config_input(AVFilterLink *inlink) AVFilterContext *ctx = inlink->dst; BoxBlurContext *s = ctx->priv; int w = inlink->w, h = inlink->h; - int cw, ch; - double var_values[VARS_NB], res; - char *expr; int ret; if (!(s->temp[0] = av_malloc(2*FFMAX(w, h))) || @@ -150,48 +87,16 @@ static int config_input(AVFilterLink *inlink) s->hsub = desc->log2_chroma_w; s->vsub = desc->log2_chroma_h; - var_values[VAR_W] = inlink->w; - var_values[VAR_H] = inlink->h; - var_values[VAR_CW] = cw = w>>s->hsub; - var_values[VAR_CH] = ch = h>>s->vsub; - var_values[VAR_HSUB] = 1<hsub; - var_values[VAR_VSUB] = 1<vsub; + ret = ff_boxblur_eval_filter_params(inlink, + &s->luma_param, + &s->chroma_param, + &s->alpha_param); -#define EVAL_RADIUS_EXPR(comp) \ - expr = s->comp##_param.radius_expr; \ - ret = av_expr_parse_and_eval(&res, expr, var_names, var_values, \ - NULL, NULL, NULL, NULL, NULL, 0, ctx); \ - s->comp##_param.radius = res; \ - if (ret < 0) { \ - av_log(NULL, AV_LOG_ERROR, \ - "Error when evaluating " #comp " radius expression '%s'\n", expr); \ - return ret; \ + if (ret != 0) { + av_log(ctx, AV_LOG_ERROR, "Failed to evaluate " + "filter params: %d.\n", ret); + return ret; } - EVAL_RADIUS_EXPR(luma); - EVAL_RADIUS_EXPR(chroma); - EVAL_RADIUS_EXPR(alpha); - - av_log(ctx, AV_LOG_VERBOSE, - "luma_radius:%d luma_power:%d " - "chroma_radius:%d chroma_power:%d " - "alpha_radius:%d alpha_power:%d " - "w:%d chroma_w:%d h:%d chroma_h:%d\n", - s->luma_param .radius, s->luma_param .power, - s->chroma_param.radius, s->chroma_param.power, - s->alpha_param .radius, s->alpha_param .power, - w, cw, h, ch); - -#define CHECK_RADIUS_VAL(w_, h_, comp) \ - if (s->comp##_param.radius < 0 || \ - 2*s->comp##_param.radius > FFMIN(w_, h_)) { \ - av_log(ctx, AV_LOG_ERROR, \ - "Invalid " #comp " radius value %d, must be >= 0 and <= %d\n", \ - s->comp##_param.radius, FFMIN(w_, h_)/2); \ - return AVERROR(EINVAL); \ - } - CHECK_RADIUS_VAL(w, h, luma); - CHECK_RADIUS_VAL(cw, ch, chroma); - CHECK_RADIUS_VAL(w, h, alpha); s->radius[Y] = s->luma_param.radius; s->radius[U] = s->radius[V] = s->chroma_param.radius; @@ -404,7 +309,6 @@ AVFilter ff_vf_boxblur = { .description = NULL_IF_CONFIG_SMALL("Blur the input."), .priv_size = sizeof(BoxBlurContext), .priv_class = &boxblur_class, - .init = init, .uninit = uninit, .query_formats = query_formats, .inputs = avfilter_vf_boxblur_inputs, diff --git a/libavfilter/vf_bwdif.c b/libavfilter/vf_bwdif.c index b69198361..37165584c 100644 --- a/libavfilter/vf_bwdif.c +++ b/libavfilter/vf_bwdif.c @@ -216,10 +216,11 @@ static void filter_edge_16bit(void *dst1, void *prev1, void *cur1, void *next1, static int filter_slice(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) { BWDIFContext *s = ctx->priv; + YADIFContext *yadif = &s->yadif; ThreadData *td = arg; - int linesize = s->cur->linesize[td->plane]; - int clip_max = (1 << (s->csp->comp[td->plane].depth)) - 1; - int df = (s->csp->comp[td->plane].depth + 7) / 8; + int linesize = yadif->cur->linesize[td->plane]; + int clip_max = (1 << (yadif->csp->comp[td->plane].depth)) - 1; + int df = (yadif->csp->comp[td->plane].depth + 7) / 8; int refs = linesize / df; int slice_start = (td->h * jobnr ) / nb_jobs; int slice_end = (td->h * (jobnr+1)) / nb_jobs; @@ -227,11 +228,11 @@ static int filter_slice(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) for (y = slice_start; y < slice_end; y++) { if ((y ^ td->parity) & 1) { - uint8_t *prev = &s->prev->data[td->plane][y * linesize]; - uint8_t *cur = &s->cur ->data[td->plane][y * linesize]; - uint8_t *next = &s->next->data[td->plane][y * linesize]; + uint8_t *prev = &yadif->prev->data[td->plane][y * linesize]; + uint8_t *cur = &yadif->cur ->data[td->plane][y * linesize]; + uint8_t *next = &yadif->next->data[td->plane][y * linesize]; uint8_t *dst = &td->frame->data[td->plane][y * td->frame->linesize[td->plane]]; - if (!s->inter_field) { + if (yadif->current_field == YADIF_FIELD_END) { s->filter_intra(dst, cur, td->w, (y + df) < td->h ? refs : -refs, y > (df - 1) ? -refs : refs, (y + 3*df) < td->h ? 3 * refs : -refs, @@ -252,7 +253,7 @@ static int filter_slice(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) } } else { memcpy(&td->frame->data[td->plane][y * td->frame->linesize[td->plane]], - &s->cur->data[td->plane][y * linesize], td->w * df); + &yadif->cur->data[td->plane][y * linesize], td->w * df); } } return 0; @@ -262,16 +263,17 @@ static void filter(AVFilterContext *ctx, AVFrame *dstpic, int parity, int tff) { BWDIFContext *bwdif = ctx->priv; + YADIFContext *yadif = &bwdif->yadif; ThreadData td = { .frame = dstpic, .parity = parity, .tff = tff }; int i; - for (i = 0; i < bwdif->csp->nb_components; i++) { + for (i = 0; i < yadif->csp->nb_components; i++) { int w = dstpic->width; int h = dstpic->height; if (i == 1 || i == 2) { - w = AV_CEIL_RSHIFT(w, bwdif->csp->log2_chroma_w); - h = AV_CEIL_RSHIFT(h, bwdif->csp->log2_chroma_h); + w = AV_CEIL_RSHIFT(w, yadif->csp->log2_chroma_w); + h = AV_CEIL_RSHIFT(h, yadif->csp->log2_chroma_h); } td.w = w; @@ -280,186 +282,21 @@ static void filter(AVFilterContext *ctx, AVFrame *dstpic, ctx->internal->execute(ctx, filter_slice, &td, NULL, FFMIN(h, ff_filter_get_nb_threads(ctx))); } - if (!bwdif->inter_field) { - bwdif->inter_field = 1; + if (yadif->current_field == YADIF_FIELD_END) { + yadif->current_field = YADIF_FIELD_NORMAL; } emms_c(); } -static int return_frame(AVFilterContext *ctx, int is_second) -{ - BWDIFContext *bwdif = ctx->priv; - AVFilterLink *link = ctx->outputs[0]; - int tff, ret; - - if (bwdif->parity == -1) { - tff = bwdif->cur->interlaced_frame ? - bwdif->cur->top_field_first : 1; - } else { - tff = bwdif->parity ^ 1; - } - - if (is_second) { - bwdif->out = ff_get_video_buffer(link, link->w, link->h); - if (!bwdif->out) - return AVERROR(ENOMEM); - - av_frame_copy_props(bwdif->out, bwdif->cur); - bwdif->out->interlaced_frame = 0; - if (bwdif->inter_field < 0) - bwdif->inter_field = 0; - } - - filter(ctx, bwdif->out, tff ^ !is_second, tff); - - if (is_second) { - int64_t cur_pts = bwdif->cur->pts; - int64_t next_pts = bwdif->next->pts; - - if (next_pts != AV_NOPTS_VALUE && cur_pts != AV_NOPTS_VALUE) { - bwdif->out->pts = cur_pts + next_pts; - } else { - bwdif->out->pts = AV_NOPTS_VALUE; - } - } - ret = ff_filter_frame(ctx->outputs[0], bwdif->out); - - bwdif->frame_pending = (bwdif->mode&1) && !is_second; - return ret; -} - -static int checkstride(BWDIFContext *bwdif, const AVFrame *a, const AVFrame *b) -{ - int i; - for (i = 0; i < bwdif->csp->nb_components; i++) - if (a->linesize[i] != b->linesize[i]) - return 1; - return 0; -} - -static void fixstride(AVFilterLink *link, AVFrame *f) -{ - AVFrame *dst = ff_default_get_video_buffer(link, f->width, f->height); - if(!dst) - return; - av_frame_copy_props(dst, f); - av_image_copy(dst->data, dst->linesize, - (const uint8_t **)f->data, f->linesize, - dst->format, dst->width, dst->height); - av_frame_unref(f); - av_frame_move_ref(f, dst); - av_frame_free(&dst); -} - -static int filter_frame(AVFilterLink *link, AVFrame *frame) -{ - AVFilterContext *ctx = link->dst; - BWDIFContext *bwdif = ctx->priv; - - av_assert0(frame); - - if (bwdif->frame_pending) - return_frame(ctx, 1); - - if (bwdif->prev) - av_frame_free(&bwdif->prev); - bwdif->prev = bwdif->cur; - bwdif->cur = bwdif->next; - bwdif->next = frame; - - if (!bwdif->cur) { - bwdif->cur = av_frame_clone(bwdif->next); - if (!bwdif->cur) - return AVERROR(ENOMEM); - bwdif->inter_field = 0; - } - - if (checkstride(bwdif, bwdif->next, bwdif->cur)) { - av_log(ctx, AV_LOG_VERBOSE, "Reallocating frame due to differing stride\n"); - fixstride(link, bwdif->next); - } - if (checkstride(bwdif, bwdif->next, bwdif->cur)) - fixstride(link, bwdif->cur); - if (bwdif->prev && checkstride(bwdif, bwdif->next, bwdif->prev)) - fixstride(link, bwdif->prev); - if (checkstride(bwdif, bwdif->next, bwdif->cur) || (bwdif->prev && checkstride(bwdif, bwdif->next, bwdif->prev))) { - av_log(ctx, AV_LOG_ERROR, "Failed to reallocate frame\n"); - return -1; - } - - if (!bwdif->prev) - return 0; - - if ((bwdif->deint && !bwdif->cur->interlaced_frame) || - ctx->is_disabled || - (bwdif->deint && !bwdif->prev->interlaced_frame && bwdif->prev->repeat_pict) || - (bwdif->deint && !bwdif->next->interlaced_frame && bwdif->next->repeat_pict) - ) { - bwdif->out = av_frame_clone(bwdif->cur); - if (!bwdif->out) - return AVERROR(ENOMEM); - - av_frame_free(&bwdif->prev); - if (bwdif->out->pts != AV_NOPTS_VALUE) - bwdif->out->pts *= 2; - return ff_filter_frame(ctx->outputs[0], bwdif->out); - } - - bwdif->out = ff_get_video_buffer(ctx->outputs[0], link->w, link->h); - if (!bwdif->out) - return AVERROR(ENOMEM); - - av_frame_copy_props(bwdif->out, bwdif->cur); - bwdif->out->interlaced_frame = 0; - - if (bwdif->out->pts != AV_NOPTS_VALUE) - bwdif->out->pts *= 2; - - return return_frame(ctx, 0); -} - -static int request_frame(AVFilterLink *link) -{ - AVFilterContext *ctx = link->src; - BWDIFContext *bwdif = ctx->priv; - int ret; - - if (bwdif->frame_pending) { - return_frame(ctx, 1); - return 0; - } - - if (bwdif->eof) - return AVERROR_EOF; - - ret = ff_request_frame(link->src->inputs[0]); - - if (ret == AVERROR_EOF && bwdif->cur) { - AVFrame *next = av_frame_clone(bwdif->next); - - if (!next) - return AVERROR(ENOMEM); - - bwdif->inter_field = -1; - next->pts = bwdif->next->pts * 2 - bwdif->cur->pts; - - filter_frame(link->src->inputs[0], next); - bwdif->eof = 1; - } else if (ret < 0) { - return ret; - } - - return 0; -} - static av_cold void uninit(AVFilterContext *ctx) { BWDIFContext *bwdif = ctx->priv; + YADIFContext *yadif = &bwdif->yadif; - av_frame_free(&bwdif->prev); - av_frame_free(&bwdif->cur ); - av_frame_free(&bwdif->next); + av_frame_free(&yadif->prev); + av_frame_free(&yadif->cur ); + av_frame_free(&yadif->next); } static int query_formats(AVFilterContext *ctx) @@ -496,13 +333,14 @@ static int config_props(AVFilterLink *link) { AVFilterContext *ctx = link->src; BWDIFContext *s = link->src->priv; + YADIFContext *yadif = &s->yadif; link->time_base.num = link->src->inputs[0]->time_base.num; link->time_base.den = link->src->inputs[0]->time_base.den * 2; link->w = link->src->inputs[0]->w; link->h = link->src->inputs[0]->h; - if(s->mode&1) + if(yadif->mode&1) link->frame_rate = av_mul_q(link->src->inputs[0]->frame_rate, (AVRational){2,1}); if (link->w < 3 || link->h < 3) { @@ -510,8 +348,9 @@ static int config_props(AVFilterLink *link) return AVERROR(EINVAL); } - s->csp = av_pix_fmt_desc_get(link->format); - if (s->csp->comp[0].depth > 8) { + yadif->csp = av_pix_fmt_desc_get(link->format); + yadif->filter = filter; + if (yadif->csp->comp[0].depth > 8) { s->filter_intra = filter_intra_16bit; s->filter_line = filter_line_c_16bit; s->filter_edge = filter_edge_16bit; @@ -528,24 +367,24 @@ static int config_props(AVFilterLink *link) } -#define OFFSET(x) offsetof(BWDIFContext, x) +#define OFFSET(x) offsetof(YADIFContext, x) #define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM #define CONST(name, help, val, unit) { name, help, 0, AV_OPT_TYPE_CONST, {.i64=val}, INT_MIN, INT_MAX, FLAGS, unit } static const AVOption bwdif_options[] = { - { "mode", "specify the interlacing mode", OFFSET(mode), AV_OPT_TYPE_INT, {.i64=BWDIF_MODE_SEND_FIELD}, 0, 1, FLAGS, "mode"}, - CONST("send_frame", "send one frame for each frame", BWDIF_MODE_SEND_FRAME, "mode"), - CONST("send_field", "send one frame for each field", BWDIF_MODE_SEND_FIELD, "mode"), + { "mode", "specify the interlacing mode", OFFSET(mode), AV_OPT_TYPE_INT, {.i64=YADIF_MODE_SEND_FIELD}, 0, 1, FLAGS, "mode"}, + CONST("send_frame", "send one frame for each frame", YADIF_MODE_SEND_FRAME, "mode"), + CONST("send_field", "send one frame for each field", YADIF_MODE_SEND_FIELD, "mode"), - { "parity", "specify the assumed picture field parity", OFFSET(parity), AV_OPT_TYPE_INT, {.i64=BWDIF_PARITY_AUTO}, -1, 1, FLAGS, "parity" }, - CONST("tff", "assume top field first", BWDIF_PARITY_TFF, "parity"), - CONST("bff", "assume bottom field first", BWDIF_PARITY_BFF, "parity"), - CONST("auto", "auto detect parity", BWDIF_PARITY_AUTO, "parity"), + { "parity", "specify the assumed picture field parity", OFFSET(parity), AV_OPT_TYPE_INT, {.i64=YADIF_PARITY_AUTO}, -1, 1, FLAGS, "parity" }, + CONST("tff", "assume top field first", YADIF_PARITY_TFF, "parity"), + CONST("bff", "assume bottom field first", YADIF_PARITY_BFF, "parity"), + CONST("auto", "auto detect parity", YADIF_PARITY_AUTO, "parity"), - { "deint", "specify which frames to deinterlace", OFFSET(deint), AV_OPT_TYPE_INT, {.i64=BWDIF_DEINT_ALL}, 0, 1, FLAGS, "deint" }, - CONST("all", "deinterlace all frames", BWDIF_DEINT_ALL, "deint"), - CONST("interlaced", "only deinterlace frames marked as interlaced", BWDIF_DEINT_INTERLACED, "deint"), + { "deint", "specify which frames to deinterlace", OFFSET(deint), AV_OPT_TYPE_INT, {.i64=YADIF_DEINT_ALL}, 0, 1, FLAGS, "deint" }, + CONST("all", "deinterlace all frames", YADIF_DEINT_ALL, "deint"), + CONST("interlaced", "only deinterlace frames marked as interlaced", YADIF_DEINT_INTERLACED, "deint"), { NULL } }; @@ -556,7 +395,7 @@ static const AVFilterPad avfilter_vf_bwdif_inputs[] = { { .name = "default", .type = AVMEDIA_TYPE_VIDEO, - .filter_frame = filter_frame, + .filter_frame = ff_yadif_filter_frame, }, { NULL } }; @@ -565,7 +404,7 @@ static const AVFilterPad avfilter_vf_bwdif_outputs[] = { { .name = "default", .type = AVMEDIA_TYPE_VIDEO, - .request_frame = request_frame, + .request_frame = ff_yadif_request_frame, .config_props = config_props, }, { NULL } diff --git a/libavfilter/vf_chromakey.c b/libavfilter/vf_chromakey.c index 88414783b..76a5e2056 100644 --- a/libavfilter/vf_chromakey.c +++ b/libavfilter/vf_chromakey.c @@ -38,6 +38,9 @@ typedef struct ChromakeyContext { int hsub_log2; int vsub_log2; + + int (*do_slice)(AVFilterContext *ctx, void *arg, + int jobnr, int nb_jobs); } ChromakeyContext; static uint8_t do_chromakey_pixel(ChromakeyContext *ctx, uint8_t u[9], uint8_t v[9]) @@ -103,12 +106,50 @@ static int do_chromakey_slice(AVFilterContext *avctx, void *arg, int jobnr, int return 0; } +static int do_chromahold_slice(AVFilterContext *avctx, void *arg, int jobnr, int nb_jobs) +{ + ChromakeyContext *ctx = avctx->priv; + AVFrame *frame = arg; + const int slice_start = ((frame->height >> ctx->vsub_log2) * jobnr) / nb_jobs; + const int slice_end = ((frame->height >> ctx->vsub_log2) * (jobnr + 1)) / nb_jobs; + + int x, y, alpha; + + for (y = slice_start; y < slice_end; ++y) { + for (x = 0; x < frame->width >> ctx->hsub_log2; ++x) { + int u = frame->data[1][frame->linesize[1] * y + x]; + int v = frame->data[2][frame->linesize[2] * y + x]; + double diff; + int du, dv; + + du = u - ctx->chromakey_uv[0]; + dv = v - ctx->chromakey_uv[1]; + + diff = sqrt((du * du + dv * dv) / (255.0 * 255.0)); + + alpha = diff > ctx->similarity; + if (ctx->blend > 0.0001) { + double f = 1. - av_clipd((diff - ctx->similarity) / ctx->blend, 0.0, 1.0); + + frame->data[1][frame->linesize[1] * y + x] = 128 + (u - 128) * f; + frame->data[2][frame->linesize[2] * y + x] = 128 + (v - 128) * f; + } else if (alpha) { + frame->data[1][frame->linesize[1] * y + x] = 128; + frame->data[2][frame->linesize[2] * y + x] = 128; + } + } + } + + return 0; +} + static int filter_frame(AVFilterLink *link, AVFrame *frame) { AVFilterContext *avctx = link->dst; + ChromakeyContext *ctx = avctx->priv; int res; - if (res = avctx->internal->execute(avctx, do_chromakey_slice, frame, NULL, FFMIN(frame->height, ff_filter_get_nb_threads(avctx)))) + if (res = avctx->internal->execute(avctx, ctx->do_slice, frame, NULL, FFMIN(frame->height, ff_filter_get_nb_threads(avctx)))) return res; return ff_filter_frame(avctx->outputs[0], frame); @@ -130,6 +171,12 @@ static av_cold int initialize_chromakey(AVFilterContext *avctx) ctx->chromakey_uv[1] = RGB_TO_V(ctx->chromakey_rgba); } + if (!strcmp(avctx->filter->name, "chromakey")) { + ctx->do_slice = do_chromakey_slice; + } else { + ctx->do_slice = do_chromahold_slice; + } + return 0; } @@ -142,9 +189,19 @@ static av_cold int query_formats(AVFilterContext *avctx) AV_PIX_FMT_NONE }; + static const enum AVPixelFormat hold_pixel_fmts[] = { + AV_PIX_FMT_YUV420P, + AV_PIX_FMT_YUV422P, + AV_PIX_FMT_YUV444P, + AV_PIX_FMT_YUVA420P, + AV_PIX_FMT_YUVA422P, + AV_PIX_FMT_YUVA444P, + AV_PIX_FMT_NONE + }; + AVFilterFormats *formats = NULL; - formats = ff_make_format_list(pixel_fmts); + formats = ff_make_format_list(!strcmp(avctx->filter->name, "chromahold") ? hold_pixel_fmts : pixel_fmts); if (!formats) return AVERROR(ENOMEM); @@ -206,3 +263,44 @@ AVFilter ff_vf_chromakey = { .outputs = chromakey_outputs, .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS, }; + +static const AVOption chromahold_options[] = { + { "color", "set the chromahold key color", OFFSET(chromakey_rgba), AV_OPT_TYPE_COLOR, { .str = "black" }, CHAR_MIN, CHAR_MAX, FLAGS }, + { "similarity", "set the chromahold similarity value", OFFSET(similarity), AV_OPT_TYPE_FLOAT, { .dbl = 0.01 }, 0.01, 1.0, FLAGS }, + { "blend", "set the chromahold blend value", OFFSET(blend), AV_OPT_TYPE_FLOAT, { .dbl = 0.0 }, 0.0, 1.0, FLAGS }, + { "yuv", "color parameter is in yuv instead of rgb", OFFSET(is_yuv), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, FLAGS }, + { NULL } +}; + +static const AVFilterPad chromahold_inputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + .needs_writable = 1, + .filter_frame = filter_frame, + .config_props = config_input, + }, + { NULL } +}; + +static const AVFilterPad chromahold_outputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + }, + { NULL } +}; + +AVFILTER_DEFINE_CLASS(chromahold); + +AVFilter ff_vf_chromahold = { + .name = "chromahold", + .description = NULL_IF_CONFIG_SMALL("Turns a certain color range into gray."), + .priv_size = sizeof(ChromakeyContext), + .priv_class = &chromahold_class, + .init = initialize_chromakey, + .query_formats = query_formats, + .inputs = chromahold_inputs, + .outputs = chromahold_outputs, + .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS, +}; diff --git a/libavfilter/vf_chromashift.c b/libavfilter/vf_chromashift.c new file mode 100644 index 000000000..f4ac28ad1 --- /dev/null +++ b/libavfilter/vf_chromashift.c @@ -0,0 +1,474 @@ +/* + * Copyright (c) 2018 Paul B Mahol + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/avstring.h" +#include "libavutil/eval.h" +#include "libavutil/imgutils.h" +#include "libavutil/intreadwrite.h" +#include "libavutil/opt.h" +#include "libavutil/pixdesc.h" + +#include "avfilter.h" +#include "formats.h" +#include "internal.h" +#include "framesync.h" +#include "video.h" + +typedef struct ChromaShiftContext { + const AVClass *class; + int cbh, cbv; + int crh, crv; + int rh, rv; + int gh, gv; + int bh, bv; + int ah, av; + int edge; + + int nb_planes; + int depth; + int height[4]; + int width[4]; + int linesize[4]; + + AVFrame *in; + + int is_rgbashift; + int (*filter_slice)(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs); +} ChromaShiftContext; + +static int query_formats(AVFilterContext *ctx) +{ + static const enum AVPixelFormat yuv_pix_fmts[] = { + AV_PIX_FMT_YUVA444P, AV_PIX_FMT_YUVA422P, AV_PIX_FMT_YUVA420P, + AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_YUVJ440P, AV_PIX_FMT_YUVJ422P,AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUVJ411P, + AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUV440P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV411P, AV_PIX_FMT_YUV410P, + AV_PIX_FMT_YUV420P9, AV_PIX_FMT_YUV422P9, AV_PIX_FMT_YUV444P9, + AV_PIX_FMT_YUV420P10, AV_PIX_FMT_YUV422P10, AV_PIX_FMT_YUV444P10, AV_PIX_FMT_YUV440P10, + AV_PIX_FMT_YUVA420P10, AV_PIX_FMT_YUVA422P10, AV_PIX_FMT_YUVA444P10, + AV_PIX_FMT_YUV420P12, AV_PIX_FMT_YUV422P12, AV_PIX_FMT_YUV444P12, AV_PIX_FMT_YUV440P12, + AV_PIX_FMT_YUV444P14, AV_PIX_FMT_YUV422P14, AV_PIX_FMT_YUV420P14, + AV_PIX_FMT_YUV420P16, AV_PIX_FMT_YUV422P16, AV_PIX_FMT_YUV444P16, + AV_PIX_FMT_YUVA420P16, AV_PIX_FMT_YUVA422P16, AV_PIX_FMT_YUVA444P16, + AV_PIX_FMT_NONE + }; + static const enum AVPixelFormat rgb_pix_fmts[] = { + AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRAP, AV_PIX_FMT_GBRP9, + AV_PIX_FMT_GBRP10, AV_PIX_FMT_GBRP12, + AV_PIX_FMT_GBRP14, AV_PIX_FMT_GBRP16, + AV_PIX_FMT_GBRAP10, AV_PIX_FMT_GBRAP12, AV_PIX_FMT_GBRAP16, + AV_PIX_FMT_NONE + }; + const enum AVPixelFormat *pix_fmts; + AVFilterFormats *fmts_list; + + if (!strcmp(ctx->filter->name, "rgbashift")) + pix_fmts = rgb_pix_fmts; + else + pix_fmts = yuv_pix_fmts; + + fmts_list = ff_make_format_list(pix_fmts); + if (!fmts_list) + return AVERROR(ENOMEM); + return ff_set_common_formats(ctx, fmts_list); +} + +#define DEFINE_SMEAR(depth, type, div) \ +static int smear_slice ## depth(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) \ +{ \ + ChromaShiftContext *s = ctx->priv; \ + AVFrame *in = s->in; \ + AVFrame *out = arg; \ + const int sulinesize = in->linesize[1] / div; \ + const int svlinesize = in->linesize[2] / div; \ + const int ulinesize = out->linesize[1] / div; \ + const int vlinesize = out->linesize[2] / div; \ + const int cbh = s->cbh; \ + const int cbv = s->cbv; \ + const int crh = s->crh; \ + const int crv = s->crv; \ + const int h = s->height[1]; \ + const int w = s->width[1]; \ + const int slice_start = (h * jobnr) / nb_jobs; \ + const int slice_end = (h * (jobnr+1)) / nb_jobs; \ + const type *su = (const type *)in->data[1]; \ + const type *sv = (const type *)in->data[2]; \ + type *du = (type *)out->data[1] + slice_start * ulinesize; \ + type *dv = (type *)out->data[2] + slice_start * vlinesize; \ + \ + for (int y = slice_start; y < slice_end; y++) { \ + const int duy = av_clip(y - cbv, 0, h-1) * sulinesize; \ + const int dvy = av_clip(y - crv, 0, h-1) * svlinesize; \ + \ + for (int x = 0; x < w; x++) { \ + du[x] = su[av_clip(x - cbh, 0, w - 1) + duy]; \ + dv[x] = sv[av_clip(x - crh, 0, w - 1) + dvy]; \ + } \ + \ + du += ulinesize; \ + dv += vlinesize; \ + } \ + \ + return 0; \ +} + +DEFINE_SMEAR(8, uint8_t, 1) +DEFINE_SMEAR(16, uint16_t, 2) + +#define DEFINE_WRAP(depth, type, div) \ +static int wrap_slice ## depth(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) \ +{ \ + ChromaShiftContext *s = ctx->priv; \ + AVFrame *in = s->in; \ + AVFrame *out = arg; \ + const int sulinesize = in->linesize[1] / div; \ + const int svlinesize = in->linesize[2] / div; \ + const int ulinesize = out->linesize[1] / div; \ + const int vlinesize = out->linesize[2] / div; \ + const int cbh = s->cbh; \ + const int cbv = s->cbv; \ + const int crh = s->crh; \ + const int crv = s->crv; \ + const int h = s->height[1]; \ + const int w = s->width[1]; \ + const int slice_start = (h * jobnr) / nb_jobs; \ + const int slice_end = (h * (jobnr+1)) / nb_jobs; \ + const type *su = (const type *)in->data[1]; \ + const type *sv = (const type *)in->data[2]; \ + type *du = (type *)out->data[1] + slice_start * ulinesize; \ + type *dv = (type *)out->data[2] + slice_start * vlinesize; \ + \ + for (int y = slice_start; y < slice_end; y++) { \ + int uy = (y - cbv) % h; \ + int vy = (y - crv) % h; \ + \ + if (uy < 0) \ + uy += h; \ + if (vy < 0) \ + vy += h; \ + \ + for (int x = 0; x < w; x++) { \ + int ux = (x - cbh) % w; \ + int vx = (x - crh) % w; \ + \ + if (ux < 0) \ + ux += w; \ + if (vx < 0) \ + vx += w; \ + \ + du[x] = su[ux + uy * sulinesize]; \ + dv[x] = sv[vx + vy * svlinesize]; \ + } \ + \ + du += ulinesize; \ + dv += vlinesize; \ + } \ + \ + return 0; \ +} + +DEFINE_WRAP(8, uint8_t, 1) +DEFINE_WRAP(16, uint16_t, 2) + +#define DEFINE_RGBASMEAR(depth, type, div) \ +static int rgbasmear_slice ## depth(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) \ +{ \ + ChromaShiftContext *s = ctx->priv; \ + AVFrame *in = s->in; \ + AVFrame *out = arg; \ + const int srlinesize = in->linesize[2] / div; \ + const int sglinesize = in->linesize[0] / div; \ + const int sblinesize = in->linesize[1] / div; \ + const int salinesize = in->linesize[3] / div; \ + const int rlinesize = out->linesize[2] / div; \ + const int glinesize = out->linesize[0] / div; \ + const int blinesize = out->linesize[1] / div; \ + const int alinesize = out->linesize[3] / div; \ + const int rh = s->rh; \ + const int rv = s->rv; \ + const int gh = s->gh; \ + const int gv = s->gv; \ + const int bh = s->bh; \ + const int bv = s->bv; \ + const int ah = s->ah; \ + const int av = s->av; \ + const int h = s->height[1]; \ + const int w = s->width[1]; \ + const int slice_start = (h * jobnr) / nb_jobs; \ + const int slice_end = (h * (jobnr+1)) / nb_jobs; \ + const type *sr = (const type *)in->data[2]; \ + const type *sg = (const type *)in->data[0]; \ + const type *sb = (const type *)in->data[1]; \ + const type *sa = (const type *)in->data[3]; \ + type *dr = (type *)out->data[2] + slice_start * rlinesize; \ + type *dg = (type *)out->data[0] + slice_start * glinesize; \ + type *db = (type *)out->data[1] + slice_start * blinesize; \ + type *da = (type *)out->data[3] + slice_start * alinesize; \ + \ + for (int y = slice_start; y < slice_end; y++) { \ + const int ry = av_clip(y - rv, 0, h-1) * srlinesize; \ + const int gy = av_clip(y - gv, 0, h-1) * sglinesize; \ + const int by = av_clip(y - bv, 0, h-1) * sblinesize; \ + int ay; \ + \ + for (int x = 0; x < w; x++) { \ + dr[x] = sr[av_clip(x - rh, 0, w - 1) + ry]; \ + dg[x] = sg[av_clip(x - gh, 0, w - 1) + gy]; \ + db[x] = sb[av_clip(x - bh, 0, w - 1) + by]; \ + } \ + \ + dr += rlinesize; \ + dg += glinesize; \ + db += blinesize; \ + \ + if (s->nb_planes < 4) \ + continue; \ + ay = av_clip(y - av, 0, h-1) * salinesize; \ + for (int x = 0; x < w; x++) { \ + da[x] = sa[av_clip(x - ah, 0, w - 1) + ay]; \ + } \ + \ + da += alinesize; \ + } \ + \ + return 0; \ +} + +DEFINE_RGBASMEAR(8, uint8_t, 1) +DEFINE_RGBASMEAR(16, uint16_t, 2) + +#define DEFINE_RGBAWRAP(depth, type, div) \ +static int rgbawrap_slice ## depth(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) \ +{ \ + ChromaShiftContext *s = ctx->priv; \ + AVFrame *in = s->in; \ + AVFrame *out = arg; \ + const int srlinesize = in->linesize[2] / div; \ + const int sglinesize = in->linesize[0] / div; \ + const int sblinesize = in->linesize[1] / div; \ + const int salinesize = in->linesize[3] / div; \ + const int rlinesize = out->linesize[2] / div; \ + const int glinesize = out->linesize[0] / div; \ + const int blinesize = out->linesize[1] / div; \ + const int alinesize = out->linesize[3] / div; \ + const int rh = s->rh; \ + const int rv = s->rv; \ + const int gh = s->gh; \ + const int gv = s->gv; \ + const int bh = s->bh; \ + const int bv = s->bv; \ + const int ah = s->ah; \ + const int av = s->av; \ + const int h = s->height[1]; \ + const int w = s->width[1]; \ + const int slice_start = (h * jobnr) / nb_jobs; \ + const int slice_end = (h * (jobnr+1)) / nb_jobs; \ + const type *sr = (const type *)in->data[2]; \ + const type *sg = (const type *)in->data[0]; \ + const type *sb = (const type *)in->data[1]; \ + const type *sa = (const type *)in->data[3]; \ + type *dr = (type *)out->data[2] + slice_start * rlinesize; \ + type *dg = (type *)out->data[0] + slice_start * glinesize; \ + type *db = (type *)out->data[1] + slice_start * blinesize; \ + type *da = (type *)out->data[3] + slice_start * alinesize; \ + \ + for (int y = slice_start; y < slice_end; y++) { \ + int ry = (y - rv) % h; \ + int gy = (y - gv) % h; \ + int by = (y - bv) % h; \ + \ + if (ry < 0) \ + ry += h; \ + if (gy < 0) \ + gy += h; \ + if (by < 0) \ + by += h; \ + \ + for (int x = 0; x < w; x++) { \ + int rx = (x - rh) % w; \ + int gx = (x - gh) % w; \ + int bx = (x - bh) % w; \ + \ + if (rx < 0) \ + rx += w; \ + if (gx < 0) \ + gx += w; \ + if (bx < 0) \ + bx += w; \ + dr[x] = sr[rx + ry * srlinesize]; \ + dg[x] = sg[gx + gy * sglinesize]; \ + db[x] = sb[bx + by * sblinesize]; \ + } \ + \ + dr += rlinesize; \ + dg += glinesize; \ + db += blinesize; \ + \ + if (s->nb_planes < 4) \ + continue; \ + for (int x = 0; x < w; x++) { \ + int ax = (x - ah) % w; \ + int ay = (x - av) % h; \ + \ + if (ax < 0) \ + ax += w; \ + if (ay < 0) \ + ay += h; \ + da[x] = sa[ax + ay * salinesize]; \ + } \ + \ + da += alinesize; \ + } \ + \ + return 0; \ +} + +DEFINE_RGBAWRAP(8, uint8_t, 1) +DEFINE_RGBAWRAP(16, uint16_t, 2) + +static int filter_frame(AVFilterLink *inlink, AVFrame *in) +{ + AVFilterContext *ctx = inlink->dst; + AVFilterLink *outlink = ctx->outputs[0]; + ChromaShiftContext *s = ctx->priv; + AVFrame *out; + + out = ff_get_video_buffer(outlink, outlink->w, outlink->h); + if (!out) { + av_frame_free(&in); + return AVERROR(ENOMEM); + } + av_frame_copy_props(out, in); + + s->in = in; + if (!s->is_rgbashift) { + av_image_copy_plane(out->data[0], + out->linesize[0], + in->data[0], in->linesize[0], + s->linesize[0], s->height[0]); + } + ctx->internal->execute(ctx, s->filter_slice, out, NULL, + FFMIN3(s->height[1], + s->height[2], + ff_filter_get_nb_threads(ctx))); + s->in = NULL; + av_frame_free(&in); + return ff_filter_frame(outlink, out); +} + +static int config_input(AVFilterLink *inlink) +{ + AVFilterContext *ctx = inlink->dst; + ChromaShiftContext *s = ctx->priv; + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format); + + s->is_rgbashift = !strcmp(ctx->filter->name, "rgbashift"); + s->depth = desc->comp[0].depth; + s->nb_planes = desc->nb_components; + if (s->is_rgbashift) { + if (s->edge) + s->filter_slice = s->depth > 8 ? rgbawrap_slice16 : rgbawrap_slice8; + else + s->filter_slice = s->depth > 8 ? rgbasmear_slice16 : rgbasmear_slice8; + } else { + if (s->edge) + s->filter_slice = s->depth > 8 ? wrap_slice16 : wrap_slice8; + else + s->filter_slice = s->depth > 8 ? smear_slice16 : smear_slice8; + } + s->height[1] = s->height[2] = AV_CEIL_RSHIFT(inlink->h, desc->log2_chroma_h); + s->height[0] = s->height[3] = inlink->h; + s->width[1] = s->width[2] = AV_CEIL_RSHIFT(inlink->w, desc->log2_chroma_w); + s->width[0] = s->width[3] = inlink->w; + + return av_image_fill_linesizes(s->linesize, inlink->format, inlink->w); +} + +#define OFFSET(x) offsetof(ChromaShiftContext, x) +#define VF AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_FILTERING_PARAM + +static const AVOption chromashift_options[] = { + { "cbh", "shift chroma-blue horizontally", OFFSET(cbh), AV_OPT_TYPE_INT, {.i64=0}, -255, 255, .flags = VF }, + { "cbv", "shift chroma-blue vertically", OFFSET(cbv), AV_OPT_TYPE_INT, {.i64=0}, -255, 255, .flags = VF }, + { "crh", "shift chroma-red horizontally", OFFSET(crh), AV_OPT_TYPE_INT, {.i64=0}, -255, 255, .flags = VF }, + { "crv", "shift chroma-red vertically", OFFSET(crv), AV_OPT_TYPE_INT, {.i64=0}, -255, 255, .flags = VF }, + { "edge", "set edge operation", OFFSET(edge), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, .flags = VF, "edge" }, + { "smear", 0, 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, .flags = VF, "edge" }, + { "wrap", 0, 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, .flags = VF, "edge" }, + { NULL }, +}; + +static const AVFilterPad inputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + .filter_frame = filter_frame, + .config_props = config_input, + }, + { NULL } +}; + +static const AVFilterPad outputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + }, + { NULL } +}; + +AVFILTER_DEFINE_CLASS(chromashift); + +AVFilter ff_vf_chromashift = { + .name = "chromashift", + .description = NULL_IF_CONFIG_SMALL("Shift chroma."), + .priv_size = sizeof(ChromaShiftContext), + .priv_class = &chromashift_class, + .query_formats = query_formats, + .outputs = outputs, + .inputs = inputs, + .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS, +}; + +static const AVOption rgbashift_options[] = { + { "rh", "shift red horizontally", OFFSET(rh), AV_OPT_TYPE_INT, {.i64=0}, -255, 255, .flags = VF }, + { "rv", "shift red vertically", OFFSET(rv), AV_OPT_TYPE_INT, {.i64=0}, -255, 255, .flags = VF }, + { "gh", "shift green horizontally", OFFSET(gh), AV_OPT_TYPE_INT, {.i64=0}, -255, 255, .flags = VF }, + { "gv", "shift green vertically", OFFSET(gv), AV_OPT_TYPE_INT, {.i64=0}, -255, 255, .flags = VF }, + { "bh", "shift blue horizontally", OFFSET(bh), AV_OPT_TYPE_INT, {.i64=0}, -255, 255, .flags = VF }, + { "bv", "shift blue vertically", OFFSET(bv), AV_OPT_TYPE_INT, {.i64=0}, -255, 255, .flags = VF }, + { "ah", "shift alpha horizontally", OFFSET(ah), AV_OPT_TYPE_INT, {.i64=0}, -255, 255, .flags = VF }, + { "av", "shift alpha vertically", OFFSET(av), AV_OPT_TYPE_INT, {.i64=0}, -255, 255, .flags = VF }, + { "edge", "set edge operation", OFFSET(edge), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, .flags = VF, "edge" }, + { "smear", 0, 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, .flags = VF, "edge" }, + { "wrap", 0, 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, .flags = VF, "edge" }, + { NULL }, +}; + +AVFILTER_DEFINE_CLASS(rgbashift); + +AVFilter ff_vf_rgbashift = { + .name = "rgbashift", + .description = NULL_IF_CONFIG_SMALL("Shift RGBA."), + .priv_size = sizeof(ChromaShiftContext), + .priv_class = &rgbashift_class, + .query_formats = query_formats, + .outputs = outputs, + .inputs = inputs, + .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS, +}; diff --git a/libavfilter/vf_colorbalance.c b/libavfilter/vf_colorbalance.c index f9965248f..fd003fdc2 100644 --- a/libavfilter/vf_colorbalance.c +++ b/libavfilter/vf_colorbalance.c @@ -31,6 +31,10 @@ #define B 2 #define A 3 +typedef struct ThreadData { + AVFrame *in, *out; +} ThreadData; + typedef struct Range { double shadows; double midtones; @@ -43,10 +47,12 @@ typedef struct ColorBalanceContext { Range magenta_green; Range yellow_blue; - uint8_t lut[3][256]; + uint16_t lut[3][65536]; uint8_t rgba_map[4]; int step; + + int (*apply_lut)(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs); } ColorBalanceContext; #define OFFSET(x) offsetof(ColorBalanceContext, x) @@ -74,6 +80,14 @@ static int query_formats(AVFilterContext *ctx) AV_PIX_FMT_ABGR, AV_PIX_FMT_ARGB, AV_PIX_FMT_0BGR, AV_PIX_FMT_0RGB, AV_PIX_FMT_RGB0, AV_PIX_FMT_BGR0, + AV_PIX_FMT_RGB48, AV_PIX_FMT_BGR48, + AV_PIX_FMT_RGBA64, AV_PIX_FMT_BGRA64, + AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRAP, + AV_PIX_FMT_GBRP9, + AV_PIX_FMT_GBRP10, AV_PIX_FMT_GBRAP10, + AV_PIX_FMT_GBRP12, AV_PIX_FMT_GBRAP12, + AV_PIX_FMT_GBRP14, + AV_PIX_FMT_GBRP16, AV_PIX_FMT_GBRAP16, AV_PIX_FMT_NONE }; AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts); @@ -82,46 +96,218 @@ static int query_formats(AVFilterContext *ctx) return ff_set_common_formats(ctx, fmts_list); } +static int apply_lut8_p(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) +{ + ColorBalanceContext *s = ctx->priv; + ThreadData *td = arg; + AVFrame *in = td->in; + AVFrame *out = td->out; + const int slice_start = (out->height * jobnr) / nb_jobs; + const int slice_end = (out->height * (jobnr+1)) / nb_jobs; + const uint8_t *srcg = in->data[0] + slice_start * in->linesize[0]; + const uint8_t *srcb = in->data[1] + slice_start * in->linesize[1]; + const uint8_t *srcr = in->data[2] + slice_start * in->linesize[2]; + const uint8_t *srca = in->data[3] + slice_start * in->linesize[3]; + uint8_t *dstg = out->data[0] + slice_start * out->linesize[0]; + uint8_t *dstb = out->data[1] + slice_start * out->linesize[1]; + uint8_t *dstr = out->data[2] + slice_start * out->linesize[2]; + uint8_t *dsta = out->data[3] + slice_start * out->linesize[3]; + int i, j; + + for (i = slice_start; i < slice_end; i++) { + for (j = 0; j < out->width; j++) { + dstg[j] = s->lut[G][srcg[j]]; + dstb[j] = s->lut[B][srcb[j]]; + dstr[j] = s->lut[R][srcr[j]]; + if (in != out && out->linesize[3]) + dsta[j] = srca[j]; + } + + srcg += in->linesize[0]; + srcb += in->linesize[1]; + srcr += in->linesize[2]; + srca += in->linesize[3]; + dstg += out->linesize[0]; + dstb += out->linesize[1]; + dstr += out->linesize[2]; + dsta += out->linesize[3]; + } + + return 0; +} + +static int apply_lut16_p(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) +{ + ColorBalanceContext *s = ctx->priv; + ThreadData *td = arg; + AVFrame *in = td->in; + AVFrame *out = td->out; + const int slice_start = (out->height * jobnr) / nb_jobs; + const int slice_end = (out->height * (jobnr+1)) / nb_jobs; + const uint16_t *srcg = (const uint16_t *)in->data[0] + slice_start * in->linesize[0] / 2; + const uint16_t *srcb = (const uint16_t *)in->data[1] + slice_start * in->linesize[1] / 2; + const uint16_t *srcr = (const uint16_t *)in->data[2] + slice_start * in->linesize[2] / 2; + const uint16_t *srca = (const uint16_t *)in->data[3] + slice_start * in->linesize[3] / 2; + uint16_t *dstg = (uint16_t *)out->data[0] + slice_start * out->linesize[0] / 2; + uint16_t *dstb = (uint16_t *)out->data[1] + slice_start * out->linesize[1] / 2; + uint16_t *dstr = (uint16_t *)out->data[2] + slice_start * out->linesize[2] / 2; + uint16_t *dsta = (uint16_t *)out->data[3] + slice_start * out->linesize[3] / 2; + int i, j; + + for (i = slice_start; i < slice_end; i++) { + for (j = 0; j < out->width; j++) { + dstg[j] = s->lut[G][srcg[j]]; + dstb[j] = s->lut[B][srcb[j]]; + dstr[j] = s->lut[R][srcr[j]]; + if (in != out && out->linesize[3]) + dsta[j] = srca[j]; + } + + srcg += in->linesize[0] / 2; + srcb += in->linesize[1] / 2; + srcr += in->linesize[2] / 2; + srca += in->linesize[3] / 2; + dstg += out->linesize[0] / 2; + dstb += out->linesize[1] / 2; + dstr += out->linesize[2] / 2; + dsta += out->linesize[3] / 2; + } + + return 0; +} + +static int apply_lut8(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) +{ + ColorBalanceContext *s = ctx->priv; + ThreadData *td = arg; + AVFrame *in = td->in; + AVFrame *out = td->out; + AVFilterLink *outlink = ctx->outputs[0]; + const int slice_start = (out->height * jobnr) / nb_jobs; + const int slice_end = (out->height * (jobnr+1)) / nb_jobs; + const uint8_t *srcrow = in->data[0] + slice_start * in->linesize[0]; + const uint8_t roffset = s->rgba_map[R]; + const uint8_t goffset = s->rgba_map[G]; + const uint8_t boffset = s->rgba_map[B]; + const uint8_t aoffset = s->rgba_map[A]; + const int step = s->step; + uint8_t *dstrow; + int i, j; + + dstrow = out->data[0] + slice_start * out->linesize[0]; + for (i = slice_start; i < slice_end; i++) { + const uint8_t *src = srcrow; + uint8_t *dst = dstrow; + + for (j = 0; j < outlink->w * step; j += step) { + dst[j + roffset] = s->lut[R][src[j + roffset]]; + dst[j + goffset] = s->lut[G][src[j + goffset]]; + dst[j + boffset] = s->lut[B][src[j + boffset]]; + if (in != out && step == 4) + dst[j + aoffset] = src[j + aoffset]; + } + + srcrow += in->linesize[0]; + dstrow += out->linesize[0]; + } + + return 0; +} + +static int apply_lut16(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) +{ + ColorBalanceContext *s = ctx->priv; + ThreadData *td = arg; + AVFrame *in = td->in; + AVFrame *out = td->out; + AVFilterLink *outlink = ctx->outputs[0]; + const int slice_start = (out->height * jobnr) / nb_jobs; + const int slice_end = (out->height * (jobnr+1)) / nb_jobs; + const uint16_t *srcrow = (const uint16_t *)in->data[0] + slice_start * in->linesize[0] / 2; + const uint8_t roffset = s->rgba_map[R]; + const uint8_t goffset = s->rgba_map[G]; + const uint8_t boffset = s->rgba_map[B]; + const uint8_t aoffset = s->rgba_map[A]; + const int step = s->step / 2; + uint16_t *dstrow; + int i, j; + + dstrow = (uint16_t *)out->data[0] + slice_start * out->linesize[0] / 2; + for (i = slice_start; i < slice_end; i++) { + const uint16_t *src = srcrow; + uint16_t *dst = dstrow; + + for (j = 0; j < outlink->w * step; j += step) { + dst[j + roffset] = s->lut[R][src[j + roffset]]; + dst[j + goffset] = s->lut[G][src[j + goffset]]; + dst[j + boffset] = s->lut[B][src[j + boffset]]; + if (in != out && step == 4) + dst[j + aoffset] = src[j + aoffset]; + } + + srcrow += in->linesize[0] / 2; + dstrow += out->linesize[0] / 2; + } + + return 0; +} + static int config_output(AVFilterLink *outlink) { AVFilterContext *ctx = outlink->src; ColorBalanceContext *s = ctx->priv; const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(outlink->format); + const int depth = desc->comp[0].depth; + const int max = 1 << depth; + const int planar = av_pix_fmt_count_planes(outlink->format) > 1; double *shadows, *midtones, *highlights, *buffer; int i, r, g, b; - buffer = av_malloc(256 * 3 * sizeof(*buffer)); + if (max == 256 && planar) { + s->apply_lut = apply_lut8_p; + } else if (planar) { + s->apply_lut = apply_lut16_p; + } else if (max == 256) { + s->apply_lut = apply_lut8; + } else { + s->apply_lut = apply_lut16; + } + + buffer = av_malloc(max * 3 * sizeof(*buffer)); if (!buffer) return AVERROR(ENOMEM); - shadows = buffer + 256 * 0; - midtones = buffer + 256 * 1; - highlights = buffer + 256 * 2; + shadows = buffer + max * 0; + midtones = buffer + max * 1; + highlights = buffer + max * 2; - for (i = 0; i < 256; i++) { - double low = av_clipd((i - 85.0) / -64.0 + 0.5, 0, 1) * 178.5; - double mid = av_clipd((i - 85.0) / 64.0 + 0.5, 0, 1) * - av_clipd((i + 85.0 - 255.0) / -64.0 + 0.5, 0, 1) * 178.5; + for (i = 0; i < max; i++) { + const double L = 0.333 * (max - 1); + const double M = 0.7 * (max - 1); + const double H = 1 * (max - 1); + double low = av_clipd((i - L) / (-max * 0.25) + 0.5, 0, 1) * M; + double mid = av_clipd((i - L) / ( max * 0.25) + 0.5, 0, 1) * + av_clipd((i + L - H) / (-max * 0.25) + 0.5, 0, 1) * M; shadows[i] = low; midtones[i] = mid; - highlights[255 - i] = low; + highlights[max - i - 1] = low; } - for (i = 0; i < 256; i++) { + for (i = 0; i < max; i++) { r = g = b = i; - r = av_clip_uint8(r + s->cyan_red.shadows * shadows[r]); - r = av_clip_uint8(r + s->cyan_red.midtones * midtones[r]); - r = av_clip_uint8(r + s->cyan_red.highlights * highlights[r]); + r = av_clip_uintp2_c(r + s->cyan_red.shadows * shadows[r], depth); + r = av_clip_uintp2_c(r + s->cyan_red.midtones * midtones[r], depth); + r = av_clip_uintp2_c(r + s->cyan_red.highlights * highlights[r], depth); - g = av_clip_uint8(g + s->magenta_green.shadows * shadows[g]); - g = av_clip_uint8(g + s->magenta_green.midtones * midtones[g]); - g = av_clip_uint8(g + s->magenta_green.highlights * highlights[g]); + g = av_clip_uintp2_c(g + s->magenta_green.shadows * shadows[g], depth); + g = av_clip_uintp2_c(g + s->magenta_green.midtones * midtones[g], depth); + g = av_clip_uintp2_c(g + s->magenta_green.highlights * highlights[g], depth); - b = av_clip_uint8(b + s->yellow_blue.shadows * shadows[b]); - b = av_clip_uint8(b + s->yellow_blue.midtones * midtones[b]); - b = av_clip_uint8(b + s->yellow_blue.highlights * highlights[b]); + b = av_clip_uintp2_c(b + s->yellow_blue.shadows * shadows[b], depth); + b = av_clip_uintp2_c(b + s->yellow_blue.midtones * midtones[b], depth); + b = av_clip_uintp2_c(b + s->yellow_blue.highlights * highlights[b], depth); s->lut[R][i] = r; s->lut[G][i] = g; @@ -141,15 +327,8 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) AVFilterContext *ctx = inlink->dst; ColorBalanceContext *s = ctx->priv; AVFilterLink *outlink = ctx->outputs[0]; - const uint8_t roffset = s->rgba_map[R]; - const uint8_t goffset = s->rgba_map[G]; - const uint8_t boffset = s->rgba_map[B]; - const uint8_t aoffset = s->rgba_map[A]; - const int step = s->step; - const uint8_t *srcrow = in->data[0]; - uint8_t *dstrow; + ThreadData td; AVFrame *out; - int i, j; if (av_frame_is_writable(in)) { out = in; @@ -162,26 +341,13 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) av_frame_copy_props(out, in); } - dstrow = out->data[0]; - for (i = 0; i < outlink->h; i++) { - const uint8_t *src = srcrow; - uint8_t *dst = dstrow; - - for (j = 0; j < outlink->w * step; j += step) { - dst[j + roffset] = s->lut[R][src[j + roffset]]; - dst[j + goffset] = s->lut[G][src[j + goffset]]; - dst[j + boffset] = s->lut[B][src[j + boffset]]; - if (in != out && step == 4) - dst[j + aoffset] = src[j + aoffset]; - } - - srcrow += in->linesize[0]; - dstrow += out->linesize[0]; - } + td.in = in; + td.out = out; + ctx->internal->execute(ctx, s->apply_lut, &td, NULL, FFMIN(outlink->h, ff_filter_get_nb_threads(ctx))); if (in != out) av_frame_free(&in); - return ff_filter_frame(ctx->outputs[0], out); + return ff_filter_frame(outlink, out); } static const AVFilterPad colorbalance_inputs[] = { @@ -210,5 +376,5 @@ AVFilter ff_vf_colorbalance = { .query_formats = query_formats, .inputs = colorbalance_inputs, .outputs = colorbalance_outputs, - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC, + .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS, }; diff --git a/libavfilter/vf_colorchannelmixer.c b/libavfilter/vf_colorchannelmixer.c index 2e068fa79..3a9cd37b7 100644 --- a/libavfilter/vf_colorchannelmixer.c +++ b/libavfilter/vf_colorchannelmixer.c @@ -19,6 +19,7 @@ */ #include "libavutil/opt.h" +#include "libavutil/pixdesc.h" #include "avfilter.h" #include "drawutils.h" #include "formats.h" @@ -30,6 +31,10 @@ #define B 2 #define A 3 +typedef struct ThreadData { + AVFrame *in, *out; +} ThreadData; + typedef struct ColorChannelMixerContext { const AVClass *class; double rr, rg, rb, ra; @@ -42,6 +47,8 @@ typedef struct ColorChannelMixerContext { int *buffer; uint8_t rgba_map[4]; + + int (*filter_slice)(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs); } ColorChannelMixerContext; #define OFFSET(x) offsetof(ColorChannelMixerContext, x) @@ -78,6 +85,12 @@ static int query_formats(AVFilterContext *ctx) AV_PIX_FMT_RGB0, AV_PIX_FMT_BGR0, AV_PIX_FMT_RGB48, AV_PIX_FMT_BGR48, AV_PIX_FMT_RGBA64, AV_PIX_FMT_BGRA64, + AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRAP, + AV_PIX_FMT_GBRP9, + AV_PIX_FMT_GBRP10, AV_PIX_FMT_GBRAP10, + AV_PIX_FMT_GBRP12, AV_PIX_FMT_GBRAP12, + AV_PIX_FMT_GBRP14, + AV_PIX_FMT_GBRP16, AV_PIX_FMT_GBRAP16, AV_PIX_FMT_NONE }; @@ -87,25 +100,319 @@ static int query_formats(AVFilterContext *ctx) return ff_set_common_formats(ctx, fmts_list); } +static av_always_inline int filter_slice_rgba_planar(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs, + int have_alpha) +{ + ColorChannelMixerContext *s = ctx->priv; + ThreadData *td = arg; + AVFrame *in = td->in; + AVFrame *out = td->out; + const int slice_start = (out->height * jobnr) / nb_jobs; + const int slice_end = (out->height * (jobnr+1)) / nb_jobs; + const uint8_t *srcg = in->data[0] + slice_start * in->linesize[0]; + const uint8_t *srcb = in->data[1] + slice_start * in->linesize[1]; + const uint8_t *srcr = in->data[2] + slice_start * in->linesize[2]; + const uint8_t *srca = in->data[3] + slice_start * in->linesize[3]; + uint8_t *dstg = out->data[0] + slice_start * out->linesize[0]; + uint8_t *dstb = out->data[1] + slice_start * out->linesize[1]; + uint8_t *dstr = out->data[2] + slice_start * out->linesize[2]; + uint8_t *dsta = out->data[3] + slice_start * out->linesize[3]; + int i, j; + + for (i = slice_start; i < slice_end; i++) { + for (j = 0; j < out->width; j++) { + const uint8_t rin = srcr[j]; + const uint8_t gin = srcg[j]; + const uint8_t bin = srcb[j]; + const uint8_t ain = srca[j]; + + dstr[j] = av_clip_uint8(s->lut[R][R][rin] + + s->lut[R][G][gin] + + s->lut[R][B][bin] + + (have_alpha == 1 ? s->lut[R][A][ain] : 0)); + dstg[j] = av_clip_uint8(s->lut[G][R][rin] + + s->lut[G][G][gin] + + s->lut[G][B][bin] + + (have_alpha == 1 ? s->lut[G][A][ain] : 0)); + dstb[j] = av_clip_uint8(s->lut[B][R][rin] + + s->lut[B][G][gin] + + s->lut[B][B][bin] + + (have_alpha == 1 ? s->lut[B][A][ain] : 0)); + if (have_alpha == 1) { + dsta[j] = av_clip_uint8(s->lut[A][R][rin] + + s->lut[A][G][gin] + + s->lut[A][B][bin] + + s->lut[A][A][ain]); + } + } + + srcg += in->linesize[0]; + srcb += in->linesize[1]; + srcr += in->linesize[2]; + srca += in->linesize[3]; + dstg += out->linesize[0]; + dstb += out->linesize[1]; + dstr += out->linesize[2]; + dsta += out->linesize[3]; + } + + return 0; +} + +static av_always_inline int filter_slice_rgba16_planar(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs, + int have_alpha, int depth) +{ + ColorChannelMixerContext *s = ctx->priv; + ThreadData *td = arg; + AVFrame *in = td->in; + AVFrame *out = td->out; + const int slice_start = (out->height * jobnr) / nb_jobs; + const int slice_end = (out->height * (jobnr+1)) / nb_jobs; + const uint16_t *srcg = (const uint16_t *)(in->data[0] + slice_start * in->linesize[0]); + const uint16_t *srcb = (const uint16_t *)(in->data[1] + slice_start * in->linesize[1]); + const uint16_t *srcr = (const uint16_t *)(in->data[2] + slice_start * in->linesize[2]); + const uint16_t *srca = (const uint16_t *)(in->data[3] + slice_start * in->linesize[3]); + uint16_t *dstg = (uint16_t *)(out->data[0] + slice_start * out->linesize[0]); + uint16_t *dstb = (uint16_t *)(out->data[1] + slice_start * out->linesize[1]); + uint16_t *dstr = (uint16_t *)(out->data[2] + slice_start * out->linesize[2]); + uint16_t *dsta = (uint16_t *)(out->data[3] + slice_start * out->linesize[3]); + int i, j; + + for (i = slice_start; i < slice_end; i++) { + for (j = 0; j < out->width; j++) { + const uint16_t rin = srcr[j]; + const uint16_t gin = srcg[j]; + const uint16_t bin = srcb[j]; + const uint16_t ain = srca[j]; + + dstr[j] = av_clip_uintp2(s->lut[R][R][rin] + + s->lut[R][G][gin] + + s->lut[R][B][bin] + + (have_alpha == 1 ? s->lut[R][A][ain] : 0), depth); + dstg[j] = av_clip_uintp2(s->lut[G][R][rin] + + s->lut[G][G][gin] + + s->lut[G][B][bin] + + (have_alpha == 1 ? s->lut[G][A][ain] : 0), depth); + dstb[j] = av_clip_uintp2(s->lut[B][R][rin] + + s->lut[B][G][gin] + + s->lut[B][B][bin] + + (have_alpha == 1 ? s->lut[B][A][ain] : 0), depth); + if (have_alpha == 1) { + dsta[j] = av_clip_uintp2(s->lut[A][R][rin] + + s->lut[A][G][gin] + + s->lut[A][B][bin] + + s->lut[A][A][ain], depth); + } + } + + srcg += in->linesize[0] / 2; + srcb += in->linesize[1] / 2; + srcr += in->linesize[2] / 2; + srca += in->linesize[3] / 2; + dstg += out->linesize[0] / 2; + dstb += out->linesize[1] / 2; + dstr += out->linesize[2] / 2; + dsta += out->linesize[3] / 2; + } + + return 0; +} + +static int filter_slice_gbrp(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) +{ + return filter_slice_rgba_planar(ctx, arg, jobnr, nb_jobs, 0); +} + +static int filter_slice_gbrap(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) +{ + return filter_slice_rgba_planar(ctx, arg, jobnr, nb_jobs, 1); +} + +static int filter_slice_gbrp9(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) +{ + return filter_slice_rgba16_planar(ctx, arg, jobnr, nb_jobs, 0, 9); +} + +static int filter_slice_gbrp10(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) +{ + return filter_slice_rgba16_planar(ctx, arg, jobnr, nb_jobs, 0, 10); +} + +static int filter_slice_gbrap10(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) +{ + return filter_slice_rgba16_planar(ctx, arg, jobnr, nb_jobs, 1, 10); +} + +static int filter_slice_gbrp12(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) +{ + return filter_slice_rgba16_planar(ctx, arg, jobnr, nb_jobs, 0, 12); +} + +static int filter_slice_gbrap12(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) +{ + return filter_slice_rgba16_planar(ctx, arg, jobnr, nb_jobs, 1, 12); +} + +static int filter_slice_gbrp14(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) +{ + return filter_slice_rgba16_planar(ctx, arg, jobnr, nb_jobs, 0, 14); +} + +static int filter_slice_gbrp16(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) +{ + return filter_slice_rgba16_planar(ctx, arg, jobnr, nb_jobs, 0, 16); +} + +static int filter_slice_gbrap16(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) +{ + return filter_slice_rgba16_planar(ctx, arg, jobnr, nb_jobs, 1, 16); +} + +static av_always_inline int filter_slice_rgba_packed(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs, + int have_alpha, int step) +{ + ColorChannelMixerContext *s = ctx->priv; + ThreadData *td = arg; + AVFrame *in = td->in; + AVFrame *out = td->out; + const int slice_start = (out->height * jobnr) / nb_jobs; + const int slice_end = (out->height * (jobnr+1)) / nb_jobs; + const uint8_t roffset = s->rgba_map[R]; + const uint8_t goffset = s->rgba_map[G]; + const uint8_t boffset = s->rgba_map[B]; + const uint8_t aoffset = s->rgba_map[A]; + const uint8_t *srcrow = in->data[0] + slice_start * in->linesize[0]; + uint8_t *dstrow = out->data[0] + slice_start * out->linesize[0]; + int i, j; + + for (i = slice_start; i < slice_end; i++) { + const uint8_t *src = srcrow; + uint8_t *dst = dstrow; + + for (j = 0; j < out->width * step; j += step) { + const uint8_t rin = src[j + roffset]; + const uint8_t gin = src[j + goffset]; + const uint8_t bin = src[j + boffset]; + const uint8_t ain = src[j + aoffset]; + + dst[j + roffset] = av_clip_uint8(s->lut[R][R][rin] + + s->lut[R][G][gin] + + s->lut[R][B][bin] + + (have_alpha == 1 ? s->lut[R][A][ain] : 0)); + dst[j + goffset] = av_clip_uint8(s->lut[G][R][rin] + + s->lut[G][G][gin] + + s->lut[G][B][bin] + + (have_alpha == 1 ? s->lut[G][A][ain] : 0)); + dst[j + boffset] = av_clip_uint8(s->lut[B][R][rin] + + s->lut[B][G][gin] + + s->lut[B][B][bin] + + (have_alpha == 1 ? s->lut[B][A][ain] : 0)); + if (have_alpha == 1) { + dst[j + aoffset] = av_clip_uint8(s->lut[A][R][rin] + + s->lut[A][G][gin] + + s->lut[A][B][bin] + + s->lut[A][A][ain]); + } else if (have_alpha == -1 && in != out) + dst[j + aoffset] = 0; + } + + srcrow += in->linesize[0]; + dstrow += out->linesize[0]; + } + + return 0; +} + +static av_always_inline int filter_slice_rgba16_packed(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs, + int have_alpha, int step) +{ + ColorChannelMixerContext *s = ctx->priv; + ThreadData *td = arg; + AVFrame *in = td->in; + AVFrame *out = td->out; + const int slice_start = (out->height * jobnr) / nb_jobs; + const int slice_end = (out->height * (jobnr+1)) / nb_jobs; + const uint8_t roffset = s->rgba_map[R]; + const uint8_t goffset = s->rgba_map[G]; + const uint8_t boffset = s->rgba_map[B]; + const uint8_t aoffset = s->rgba_map[A]; + const uint8_t *srcrow = in->data[0] + slice_start * in->linesize[0]; + uint8_t *dstrow = out->data[0] + slice_start * out->linesize[0]; + int i, j; + + for (i = slice_start; i < slice_end; i++) { + const uint16_t *src = (const uint16_t *)srcrow; + uint16_t *dst = (uint16_t *)dstrow; + + for (j = 0; j < out->width * step; j += step) { + const uint16_t rin = src[j + roffset]; + const uint16_t gin = src[j + goffset]; + const uint16_t bin = src[j + boffset]; + const uint16_t ain = src[j + aoffset]; + + dst[j + roffset] = av_clip_uint16(s->lut[R][R][rin] + + s->lut[R][G][gin] + + s->lut[R][B][bin] + + (have_alpha == 1 ? s->lut[R][A][ain] : 0)); + dst[j + goffset] = av_clip_uint16(s->lut[G][R][rin] + + s->lut[G][G][gin] + + s->lut[G][B][bin] + + (have_alpha == 1 ? s->lut[G][A][ain] : 0)); + dst[j + boffset] = av_clip_uint16(s->lut[B][R][rin] + + s->lut[B][G][gin] + + s->lut[B][B][bin] + + (have_alpha == 1 ? s->lut[B][A][ain] : 0)); + if (have_alpha == 1) { + dst[j + aoffset] = av_clip_uint16(s->lut[A][R][rin] + + s->lut[A][G][gin] + + s->lut[A][B][bin] + + s->lut[A][A][ain]); + } + } + + srcrow += in->linesize[0]; + dstrow += out->linesize[0]; + } + + return 0; +} + +static int filter_slice_rgba64(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) +{ + return filter_slice_rgba16_packed(ctx, arg, jobnr, nb_jobs, 1, 4); +} + +static int filter_slice_rgb48(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) +{ + return filter_slice_rgba16_packed(ctx, arg, jobnr, nb_jobs, 0, 3); +} + +static int filter_slice_rgba(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) +{ + return filter_slice_rgba_packed(ctx, arg, jobnr, nb_jobs, 1, 4); +} + +static int filter_slice_rgb24(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) +{ + return filter_slice_rgba_packed(ctx, arg, jobnr, nb_jobs, 0, 3); +} + +static int filter_slice_rgb0(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) +{ + return filter_slice_rgba_packed(ctx, arg, jobnr, nb_jobs, -1, 4); +} + static int config_output(AVFilterLink *outlink) { AVFilterContext *ctx = outlink->src; ColorChannelMixerContext *s = ctx->priv; + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(outlink->format); + const int depth = desc->comp[0].depth; int i, j, size, *buffer; ff_fill_rgba_map(s->rgba_map, outlink->format); - switch (outlink->format) { - case AV_PIX_FMT_RGB48: - case AV_PIX_FMT_BGR48: - case AV_PIX_FMT_RGBA64: - case AV_PIX_FMT_BGRA64: - size = 65536; - break; - default: - size = 256; - } - + size = 1 << depth; s->buffer = buffer = av_malloc(16 * size * sizeof(*s->buffer)); if (!s->buffer) return AVERROR(ENOMEM); @@ -136,6 +443,63 @@ static int config_output(AVFilterLink *outlink) s->lut[A][A][i] = lrint(i * s->aa); } + switch (outlink->format) { + case AV_PIX_FMT_BGR24: + case AV_PIX_FMT_RGB24: + s->filter_slice = filter_slice_rgb24; + break; + case AV_PIX_FMT_0BGR: + case AV_PIX_FMT_0RGB: + case AV_PIX_FMT_BGR0: + case AV_PIX_FMT_RGB0: + s->filter_slice = filter_slice_rgb0; + break; + case AV_PIX_FMT_ABGR: + case AV_PIX_FMT_ARGB: + case AV_PIX_FMT_BGRA: + case AV_PIX_FMT_RGBA: + s->filter_slice = filter_slice_rgba; + break; + case AV_PIX_FMT_BGR48: + case AV_PIX_FMT_RGB48: + s->filter_slice = filter_slice_rgb48; + break; + case AV_PIX_FMT_BGRA64: + case AV_PIX_FMT_RGBA64: + s->filter_slice = filter_slice_rgba64; + break; + case AV_PIX_FMT_GBRP: + s->filter_slice = filter_slice_gbrp; + break; + case AV_PIX_FMT_GBRAP: + s->filter_slice = filter_slice_gbrap; + break; + case AV_PIX_FMT_GBRP9: + s->filter_slice = filter_slice_gbrp9; + break; + case AV_PIX_FMT_GBRP10: + s->filter_slice = filter_slice_gbrp10; + break; + case AV_PIX_FMT_GBRAP10: + s->filter_slice = filter_slice_gbrap10; + break; + case AV_PIX_FMT_GBRP12: + s->filter_slice = filter_slice_gbrp12; + break; + case AV_PIX_FMT_GBRAP12: + s->filter_slice = filter_slice_gbrap12; + break; + case AV_PIX_FMT_GBRP14: + s->filter_slice = filter_slice_gbrp14; + break; + case AV_PIX_FMT_GBRP16: + s->filter_slice = filter_slice_gbrp16; + break; + case AV_PIX_FMT_GBRAP16: + s->filter_slice = filter_slice_gbrap16; + break; + } + return 0; } @@ -144,14 +508,8 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) AVFilterContext *ctx = inlink->dst; ColorChannelMixerContext *s = ctx->priv; AVFilterLink *outlink = ctx->outputs[0]; - const uint8_t roffset = s->rgba_map[R]; - const uint8_t goffset = s->rgba_map[G]; - const uint8_t boffset = s->rgba_map[B]; - const uint8_t aoffset = s->rgba_map[A]; - const uint8_t *srcrow = in->data[0]; - uint8_t *dstrow; + ThreadData td; AVFrame *out; - int i, j; if (av_frame_is_writable(in)) { out = in; @@ -164,164 +522,13 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) av_frame_copy_props(out, in); } - dstrow = out->data[0]; - switch (outlink->format) { - case AV_PIX_FMT_BGR24: - case AV_PIX_FMT_RGB24: - for (i = 0; i < outlink->h; i++) { - const uint8_t *src = srcrow; - uint8_t *dst = dstrow; - - for (j = 0; j < outlink->w * 3; j += 3) { - const uint8_t rin = src[j + roffset]; - const uint8_t gin = src[j + goffset]; - const uint8_t bin = src[j + boffset]; - - dst[j + roffset] = av_clip_uint8(s->lut[R][R][rin] + - s->lut[R][G][gin] + - s->lut[R][B][bin]); - dst[j + goffset] = av_clip_uint8(s->lut[G][R][rin] + - s->lut[G][G][gin] + - s->lut[G][B][bin]); - dst[j + boffset] = av_clip_uint8(s->lut[B][R][rin] + - s->lut[B][G][gin] + - s->lut[B][B][bin]); - } - - srcrow += in->linesize[0]; - dstrow += out->linesize[0]; - } - break; - case AV_PIX_FMT_0BGR: - case AV_PIX_FMT_0RGB: - case AV_PIX_FMT_BGR0: - case AV_PIX_FMT_RGB0: - for (i = 0; i < outlink->h; i++) { - const uint8_t *src = srcrow; - uint8_t *dst = dstrow; - - for (j = 0; j < outlink->w * 4; j += 4) { - const uint8_t rin = src[j + roffset]; - const uint8_t gin = src[j + goffset]; - const uint8_t bin = src[j + boffset]; - - dst[j + roffset] = av_clip_uint8(s->lut[R][R][rin] + - s->lut[R][G][gin] + - s->lut[R][B][bin]); - dst[j + goffset] = av_clip_uint8(s->lut[G][R][rin] + - s->lut[G][G][gin] + - s->lut[G][B][bin]); - dst[j + boffset] = av_clip_uint8(s->lut[B][R][rin] + - s->lut[B][G][gin] + - s->lut[B][B][bin]); - if (in != out) - dst[j + aoffset] = 0; - } - - srcrow += in->linesize[0]; - dstrow += out->linesize[0]; - } - break; - case AV_PIX_FMT_ABGR: - case AV_PIX_FMT_ARGB: - case AV_PIX_FMT_BGRA: - case AV_PIX_FMT_RGBA: - for (i = 0; i < outlink->h; i++) { - const uint8_t *src = srcrow; - uint8_t *dst = dstrow; - - for (j = 0; j < outlink->w * 4; j += 4) { - const uint8_t rin = src[j + roffset]; - const uint8_t gin = src[j + goffset]; - const uint8_t bin = src[j + boffset]; - const uint8_t ain = src[j + aoffset]; - - dst[j + roffset] = av_clip_uint8(s->lut[R][R][rin] + - s->lut[R][G][gin] + - s->lut[R][B][bin] + - s->lut[R][A][ain]); - dst[j + goffset] = av_clip_uint8(s->lut[G][R][rin] + - s->lut[G][G][gin] + - s->lut[G][B][bin] + - s->lut[G][A][ain]); - dst[j + boffset] = av_clip_uint8(s->lut[B][R][rin] + - s->lut[B][G][gin] + - s->lut[B][B][bin] + - s->lut[B][A][ain]); - dst[j + aoffset] = av_clip_uint8(s->lut[A][R][rin] + - s->lut[A][G][gin] + - s->lut[A][B][bin] + - s->lut[A][A][ain]); - } - - srcrow += in->linesize[0]; - dstrow += out->linesize[0]; - } - break; - case AV_PIX_FMT_BGR48: - case AV_PIX_FMT_RGB48: - for (i = 0; i < outlink->h; i++) { - const uint16_t *src = (const uint16_t *)srcrow; - uint16_t *dst = (uint16_t *)dstrow; - - for (j = 0; j < outlink->w * 3; j += 3) { - const uint16_t rin = src[j + roffset]; - const uint16_t gin = src[j + goffset]; - const uint16_t bin = src[j + boffset]; - - dst[j + roffset] = av_clip_uint16(s->lut[R][R][rin] + - s->lut[R][G][gin] + - s->lut[R][B][bin]); - dst[j + goffset] = av_clip_uint16(s->lut[G][R][rin] + - s->lut[G][G][gin] + - s->lut[G][B][bin]); - dst[j + boffset] = av_clip_uint16(s->lut[B][R][rin] + - s->lut[B][G][gin] + - s->lut[B][B][bin]); - } - - srcrow += in->linesize[0]; - dstrow += out->linesize[0]; - } - break; - case AV_PIX_FMT_BGRA64: - case AV_PIX_FMT_RGBA64: - for (i = 0; i < outlink->h; i++) { - const uint16_t *src = (const uint16_t *)srcrow; - uint16_t *dst = (uint16_t *)dstrow; - - for (j = 0; j < outlink->w * 4; j += 4) { - const uint16_t rin = src[j + roffset]; - const uint16_t gin = src[j + goffset]; - const uint16_t bin = src[j + boffset]; - const uint16_t ain = src[j + aoffset]; - - dst[j + roffset] = av_clip_uint16(s->lut[R][R][rin] + - s->lut[R][G][gin] + - s->lut[R][B][bin] + - s->lut[R][A][ain]); - dst[j + goffset] = av_clip_uint16(s->lut[G][R][rin] + - s->lut[G][G][gin] + - s->lut[G][B][bin] + - s->lut[G][A][ain]); - dst[j + boffset] = av_clip_uint16(s->lut[B][R][rin] + - s->lut[B][G][gin] + - s->lut[B][B][bin] + - s->lut[B][A][ain]); - dst[j + aoffset] = av_clip_uint16(s->lut[A][R][rin] + - s->lut[A][G][gin] + - s->lut[A][B][bin] + - s->lut[A][A][ain]); - } - - srcrow += in->linesize[0]; - dstrow += out->linesize[0]; - } - } + td.in = in; + td.out = out; + ctx->internal->execute(ctx, s->filter_slice, &td, NULL, FFMIN(outlink->h, ff_filter_get_nb_threads(ctx))); if (in != out) av_frame_free(&in); - return ff_filter_frame(ctx->outputs[0], out); + return ff_filter_frame(outlink, out); } static av_cold void uninit(AVFilterContext *ctx) @@ -358,5 +565,5 @@ AVFilter ff_vf_colorchannelmixer = { .query_formats = query_formats, .inputs = colorchannelmixer_inputs, .outputs = colorchannelmixer_outputs, - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC, + .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS, }; diff --git a/libavfilter/vf_colorconstancy.c b/libavfilter/vf_colorconstancy.c new file mode 100644 index 000000000..e3bb39e51 --- /dev/null +++ b/libavfilter/vf_colorconstancy.c @@ -0,0 +1,758 @@ +/* + * Copyright (c) 2018 Mina Sami + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * Color Constancy filter + * + * @see http://colorconstancy.com/ + * + * @cite + * J. van de Weijer, Th. Gevers, A. Gijsenij "Edge-Based Color Constancy". + */ + +#include "libavutil/imgutils.h" +#include "libavutil/opt.h" +#include "libavutil/pixdesc.h" + +#include "avfilter.h" +#include "formats.h" +#include "internal.h" +#include "video.h" + +#include + +#define GREY_EDGE "greyedge" + +#define SQRT3 1.73205080757 + +#define NUM_PLANES 3 +#define MAX_DIFF_ORD 2 +#define MAX_META_DATA 4 +#define MAX_DATA 4 + +#define INDEX_TEMP 0 +#define INDEX_DX 1 +#define INDEX_DY 2 +#define INDEX_DXY 3 +#define INDEX_NORM INDEX_DX +#define INDEX_SRC 0 +#define INDEX_DST 1 +#define INDEX_ORD 2 +#define INDEX_DIR 3 +#define DIR_X 0 +#define DIR_Y 1 + +/** + * Used for passing data between threads. + */ +typedef struct ThreadData { + AVFrame *in, *out; + int meta_data[MAX_META_DATA]; + double *data[MAX_DATA][NUM_PLANES]; +} ThreadData; + +/** + * Common struct for all algorithms contexts. + */ +typedef struct ColorConstancyContext { + const AVClass *class; + + int difford; + int minknorm; /**< @minknorm = 0 : getMax instead */ + double sigma; + + int nb_threads; + int planeheight[4]; + int planewidth[4]; + + int filtersize; + double *gauss[MAX_DIFF_ORD+1]; + + double white[NUM_PLANES]; +} ColorConstancyContext; + +#define OFFSET(x) offsetof(ColorConstancyContext, x) +#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM + +#define GINDX(s, i) ( (i) - ((s) >> 2) ) + +/** + * Sets gauss filters used for calculating gauss derivatives. Filter size + * depends on sigma which is a user option hence we calculate these + * filters each time. Also each higher order depends on lower ones. Sigma + * can be zero only at difford = 0, then we only convert data to double + * instead. + * + * @param ctx the filter context. + * + * @return 0 in case of success, a negative value corresponding to an + * AVERROR code in case of failure. + */ +static int set_gauss(AVFilterContext *ctx) +{ + ColorConstancyContext *s = ctx->priv; + int filtersize = s->filtersize; + int difford = s->difford; + double sigma = s->sigma; + double sum1, sum2; + int i; + + for (i = 0; i <= difford; ++i) { + s->gauss[i] = av_mallocz_array(filtersize, sizeof(*s->gauss[i])); + if (!s->gauss[i]) { + for (; i >= 0; --i) { + av_freep(&s->gauss[i]); + } + av_log(ctx, AV_LOG_ERROR, "Out of memory while allocating gauss buffers.\n"); + return AVERROR(ENOMEM); + } + } + + // Order 0 + av_log(ctx, AV_LOG_TRACE, "Setting 0-d gauss with filtersize = %d.\n", filtersize); + sum1 = 0.0; + if (!sigma) { + s->gauss[0][0] = 1; // Copying data to double instead of convolution + } else { + for (i = 0; i < filtersize; ++i) { + s->gauss[0][i] = exp(- pow(GINDX(filtersize, i), 2.) / (2 * sigma * sigma)) / ( sqrt(2 * M_PI) * sigma ); + sum1 += s->gauss[0][i]; + } + for (i = 0; i < filtersize; ++i) { + s->gauss[0][i] /= sum1; + } + } + // Order 1 + if (difford > 0) { + av_log(ctx, AV_LOG_TRACE, "Setting 1-d gauss with filtersize = %d.\n", filtersize); + sum1 = 0.0; + for (i = 0; i < filtersize; ++i) { + s->gauss[1][i] = - (GINDX(filtersize, i) / pow(sigma, 2)) * s->gauss[0][i]; + sum1 += s->gauss[1][i] * GINDX(filtersize, i); + } + + for (i = 0; i < filtersize; ++i) { + s->gauss[1][i] /= sum1; + } + + // Order 2 + if (difford > 1) { + av_log(ctx, AV_LOG_TRACE, "Setting 2-d gauss with filtersize = %d.\n", filtersize); + sum1 = 0.0; + for (i = 0; i < filtersize; ++i) { + s->gauss[2][i] = ( pow(GINDX(filtersize, i), 2) / pow(sigma, 4) - 1/pow(sigma, 2) ) + * s->gauss[0][i]; + sum1 += s->gauss[2][i]; + } + + sum2 = 0.0; + for (i = 0; i < filtersize; ++i) { + s->gauss[2][i] -= sum1 / (filtersize); + sum2 += (0.5 * GINDX(filtersize, i) * GINDX(filtersize, i) * s->gauss[2][i]); + } + for (i = 0; i < filtersize ; ++i) { + s->gauss[2][i] /= sum2; + } + } + } + return 0; +} + +/** + * Frees up buffers used by grey edge for storing derivatives final + * and intermidiate results. Number of buffers and number of planes + * for last buffer are given so it can be safely called at allocation + * failure instances. + * + * @param td holds the buffers. + * @param nb_buff number of buffers to be freed. + * @param nb_planes number of planes for last buffer to be freed. + */ +static void cleanup_derivative_buffers(ThreadData *td, int nb_buff, int nb_planes) +{ + int b, p; + + for (b = 0; b < nb_buff; ++b) { + for (p = 0; p < NUM_PLANES; ++p) { + av_freep(&td->data[b][p]); + } + } + // Final buffer may not be fully allocated at fail cases + for (p = 0; p < nb_planes; ++p) { + av_freep(&td->data[b][p]); + } +} + +/** + * Allocates buffers used by grey edge for storing derivatives final + * and intermidiate results. + * + * @param ctx the filter context. + * @param td holds the buffers. + * + * @return 0 in case of success, a negative value corresponding to an + * AVERROR code in case of failure. + */ +static int setup_derivative_buffers(AVFilterContext* ctx, ThreadData *td) +{ + ColorConstancyContext *s = ctx->priv; + int nb_buff = s->difford + 1; + int b, p; + + av_log(ctx, AV_LOG_TRACE, "Allocating %d buffer(s) for grey edge.\n", nb_buff); + for (b = 0; b <= nb_buff; ++b) { // We need difford + 1 buffers + for (p = 0; p < NUM_PLANES; ++p) { + td->data[b][p] = av_mallocz_array(s->planeheight[p] * s->planewidth[p], sizeof(*td->data[b][p])); + if (!td->data[b][p]) { + cleanup_derivative_buffers(td, b + 1, p); + av_log(ctx, AV_LOG_ERROR, "Out of memory while allocating derivatives buffers.\n"); + return AVERROR(ENOMEM); + } + } + } + return 0; +} + +#define CLAMP(x, mx) av_clip((x), 0, (mx-1)) +#define INDX2D(r, c, w) ( (r) * (w) + (c) ) +#define GAUSS(s, sr, sc, sls, sh, sw, g) ( (s)[ INDX2D(CLAMP((sr), (sh)), CLAMP((sc), (sw)), (sls)) ] * (g) ) + +/** + * Slice calculation of gaussian derivatives. Applies 1-D gaussian derivative filter + * either horizontally or vertically according to meta data given in thread data. + * When convoluting horizontally source is always the in frame withing thread data + * while when convoluting vertically source is a buffer. + * + * @param ctx the filter context. + * @param arg data to be passed between threads. + * @param jobnr current job nubmer. + * @param nb_jobs total number of jobs. + * + * @return 0. + */ +static int slice_get_derivative(AVFilterContext* ctx, void* arg, int jobnr, int nb_jobs) +{ + ColorConstancyContext *s = ctx->priv; + ThreadData *td = arg; + AVFrame *in = td->in; + const int ord = td->meta_data[INDEX_ORD]; + const int dir = td->meta_data[INDEX_DIR]; + const int src_index = td->meta_data[INDEX_SRC]; + const int dst_index = td->meta_data[INDEX_DST]; + const int filtersize = s->filtersize; + const double *gauss = s->gauss[ord]; + int plane; + + for (plane = 0; plane < NUM_PLANES; ++plane) { + const int height = s->planeheight[plane]; + const int width = s->planewidth[plane]; + const int in_linesize = in->linesize[plane]; + double *dst = td->data[dst_index][plane]; + int slice_start, slice_end; + int r, c, g; + + if (dir == DIR_X) { + /** Applying gauss horizontally along each row */ + const uint8_t *src = in->data[plane]; + slice_start = (height * jobnr ) / nb_jobs; + slice_end = (height * (jobnr + 1)) / nb_jobs; + + for (r = slice_start; r < slice_end; ++r) { + for (c = 0; c < width; ++c) { + dst[INDX2D(r, c, width)] = 0; + for (g = 0; g < filtersize; ++g) { + dst[INDX2D(r, c, width)] += GAUSS(src, r, c + GINDX(filtersize, g), + in_linesize, height, width, gauss[GINDX(filtersize, g)]); + } + } + } + } else { + /** Applying gauss vertically along each column */ + const double *src = td->data[src_index][plane]; + slice_start = (width * jobnr ) / nb_jobs; + slice_end = (width * (jobnr + 1)) / nb_jobs; + + for (c = slice_start; c < slice_end; ++c) { + for (r = 0; r < height; ++r) { + dst[INDX2D(r, c, width)] = 0; + for (g = 0; g < filtersize; ++g) { + dst[INDX2D(r, c, width)] += GAUSS(src, r + GINDX(filtersize, g), c, + width, height, width, gauss[GINDX(filtersize, g)]); + } + } + } + } + + } + return 0; +} + +/** + * Slice Frobius normalization of gaussian derivatives. Only called for difford values of + * 1 or 2. + * + * @param ctx the filter context. + * @param arg data to be passed between threads. + * @param jobnr current job nubmer. + * @param nb_jobs total number of jobs. + * + * @return 0. + */ +static int slice_normalize(AVFilterContext* ctx, void* arg, int jobnr, int nb_jobs) +{ + ColorConstancyContext *s = ctx->priv; + ThreadData *td = arg; + const int difford = s->difford; + int plane; + + for (plane = 0; plane < NUM_PLANES; ++plane) { + const int height = s->planeheight[plane]; + const int width = s->planewidth[plane]; + const int64_t numpixels = width * (int64_t)height; + const int slice_start = (numpixels * jobnr ) / nb_jobs; + const int slice_end = (numpixels * (jobnr+1)) / nb_jobs; + const double *dx = td->data[INDEX_DX][plane]; + const double *dy = td->data[INDEX_DY][plane]; + double *norm = td->data[INDEX_NORM][plane]; + int i; + + if (difford == 1) { + for (i = slice_start; i < slice_end; ++i) { + norm[i] = sqrt( pow(dx[i], 2) + pow(dy[i], 2)); + } + } else { + const double *dxy = td->data[INDEX_DXY][plane]; + for (i = slice_start; i < slice_end; ++i) { + norm[i] = sqrt( pow(dx[i], 2) + 4 * pow(dxy[i], 2) + pow(dy[i], 2) ); + } + } + } + + return 0; +} + +/** + * Utility function for setting up differentiation data/metadata. + * + * @param ctx the filter context. + * @param td to be used for passing data between threads. + * @param ord ord of differentiation. + * @param dir direction of differentiation. + * @param src index of source used for differentiation. + * @param dst index destination used for saving differentiation result. + * @param dim maximum dimension in current direction. + * @param nb_threads number of threads to use. + */ +static void av_always_inline +get_deriv(AVFilterContext *ctx, ThreadData *td, int ord, int dir, + int src, int dst, int dim, int nb_threads) { + td->meta_data[INDEX_ORD] = ord; + td->meta_data[INDEX_DIR] = dir; + td->meta_data[INDEX_SRC] = src; + td->meta_data[INDEX_DST] = dst; + ctx->internal->execute(ctx, slice_get_derivative, td, NULL, FFMIN(dim, nb_threads)); +} + +/** + * Main control function for calculating gaussian derivatives. + * + * @param ctx the filter context. + * @param td holds the buffers used for storing results. + * + * @return 0 in case of success, a negative value corresponding to an + * AVERROR code in case of failure. + */ +static int get_derivative(AVFilterContext *ctx, ThreadData *td) +{ + ColorConstancyContext *s = ctx->priv; + int nb_threads = s->nb_threads; + int height = s->planeheight[1]; + int width = s->planewidth[1]; + + switch(s->difford) { + case 0: + if (!s->sigma) { // Only copy once + get_deriv(ctx, td, 0, DIR_X, 0 , INDEX_NORM, height, nb_threads); + } else { + get_deriv(ctx, td, 0, DIR_X, 0, INDEX_TEMP, height, nb_threads); + get_deriv(ctx, td, 0, DIR_Y, INDEX_TEMP, INDEX_NORM, width , nb_threads); + // save to INDEX_NORM because this will not be normalied and + // end gry edge filter expects result to be found in INDEX_NORM + } + return 0; + + case 1: + get_deriv(ctx, td, 1, DIR_X, 0, INDEX_TEMP, height, nb_threads); + get_deriv(ctx, td, 0, DIR_Y, INDEX_TEMP, INDEX_DX, width , nb_threads); + + get_deriv(ctx, td, 0, DIR_X, 0, INDEX_TEMP, height, nb_threads); + get_deriv(ctx, td, 1, DIR_Y, INDEX_TEMP, INDEX_DY, width , nb_threads); + return 0; + + case 2: + get_deriv(ctx, td, 2, DIR_X, 0, INDEX_TEMP, height, nb_threads); + get_deriv(ctx, td, 0, DIR_Y, INDEX_TEMP, INDEX_DX, width , nb_threads); + + get_deriv(ctx, td, 0, DIR_X, 0, INDEX_TEMP, height, nb_threads); + get_deriv(ctx, td, 2, DIR_Y, INDEX_TEMP, INDEX_DY, width , nb_threads); + + get_deriv(ctx, td, 1, DIR_X, 0, INDEX_TEMP, height, nb_threads); + get_deriv(ctx, td, 1, DIR_Y, INDEX_TEMP, INDEX_DXY, width , nb_threads); + return 0; + + default: + av_log(ctx, AV_LOG_ERROR, "Unsupported difford value: %d.\n", s->difford); + return AVERROR(EINVAL); + } + +} + +/** + * Slice function for grey edge algorithm that does partial summing/maximizing + * of gaussian derivatives. + * + * @param ctx the filter context. + * @param arg data to be passed between threads. + * @param jobnr current job nubmer. + * @param nb_jobs total number of jobs. + * + * @return 0. + */ +static int filter_slice_grey_edge(AVFilterContext* ctx, void* arg, int jobnr, int nb_jobs) +{ + ColorConstancyContext *s = ctx->priv; + ThreadData *td = arg; + AVFrame *in = td->in; + int minknorm = s->minknorm; + const uint8_t thresh = 255; + int plane; + + for (plane = 0; plane < NUM_PLANES; ++plane) { + const int height = s->planeheight[plane]; + const int width = s->planewidth[plane]; + const int in_linesize = in->linesize[plane]; + const int slice_start = (height * jobnr) / nb_jobs; + const int slice_end = (height * (jobnr+1)) / nb_jobs; + const uint8_t *img_data = in->data[plane]; + const double *src = td->data[INDEX_NORM][plane]; + double *dst = td->data[INDEX_DST][plane]; + int r, c; + + dst[jobnr] = 0; + if (!minknorm) { + for (r = slice_start; r < slice_end; ++r) { + for (c = 0; c < width; ++c) { + dst[jobnr] = FFMAX( dst[jobnr], fabs(src[INDX2D(r, c, width)]) + * (img_data[INDX2D(r, c, in_linesize)] < thresh) ); + } + } + } else { + for (r = slice_start; r < slice_end; ++r) { + for (c = 0; c < width; ++c) { + dst[jobnr] += ( pow( fabs(src[INDX2D(r, c, width)] / 255.), minknorm) + * (img_data[INDX2D(r, c, in_linesize)] < thresh) ); + } + } + } + } + return 0; +} + +/** + * Main control function for grey edge algorithm. + * + * @param ctx the filter context. + * @param in frame to perfrom grey edge on. + * + * @return 0 in case of success, a negative value corresponding to an + * AVERROR code in case of failure. + */ +static int filter_grey_edge(AVFilterContext *ctx, AVFrame *in) +{ + ColorConstancyContext *s = ctx->priv; + ThreadData td; + int minknorm = s->minknorm; + int difford = s->difford; + double *white = s->white; + int nb_jobs = FFMIN3(s->planeheight[1], s->planewidth[1], s->nb_threads); + int plane, job, ret; + + td.in = in; + ret = setup_derivative_buffers(ctx, &td); + if (ret) { + return ret; + } + get_derivative(ctx, &td); + if (difford > 0) { + ctx->internal->execute(ctx, slice_normalize, &td, NULL, nb_jobs); + } + + ctx->internal->execute(ctx, filter_slice_grey_edge, &td, NULL, nb_jobs); + if (!minknorm) { + for (plane = 0; plane < NUM_PLANES; ++plane) { + white[plane] = 0; // All values are absolute + for (job = 0; job < nb_jobs; ++job) { + white[plane] = FFMAX(white[plane] , td.data[INDEX_DST][plane][job]); + } + } + } else { + for (plane = 0; plane < NUM_PLANES; ++plane) { + white[plane] = 0; + for (job = 0; job < nb_jobs; ++job) { + white[plane] += td.data[INDEX_DST][plane][job]; + } + white[plane] = pow(white[plane], 1./minknorm); + } + } + + cleanup_derivative_buffers(&td, difford + 1, NUM_PLANES); + return 0; +} + +/** + * Normalizes estimated illumination since only illumination vector + * direction is required for color constancy. + * + * @param light the estimated illumination to be normalized in place + */ +static void normalize_light(double *light) +{ + double abs_val = pow( pow(light[0], 2.0) + pow(light[1], 2.0) + pow(light[2], 2.0), 0.5); + int plane; + + // TODO: check if setting to 1.0 when estimated = 0.0 is the best thing to do + + if (!abs_val) { + for (plane = 0; plane < NUM_PLANES; ++plane) { + light[plane] = 1.0; + } + } else { + for (plane = 0; plane < NUM_PLANES; ++plane) { + light[plane] = (light[plane] / abs_val); + if (!light[plane]) { // to avoid division by zero when correcting + light[plane] = 1.0; + } + } + } +} + +/** + * Redirects to corresponding algorithm estimation function and performs normalization + * after estimation. + * + * @param ctx the filter context. + * @param in frame to perfrom estimation on. + * + * @return 0 in case of success, a negative value corresponding to an + * AVERROR code in case of failure. + */ +static int illumination_estimation(AVFilterContext *ctx, AVFrame *in) +{ + ColorConstancyContext *s = ctx->priv; + int ret; + + ret = filter_grey_edge(ctx, in); + + av_log(ctx, AV_LOG_DEBUG, "Estimated illumination= %f %f %f\n", + s->white[0], s->white[1], s->white[2]); + normalize_light(s->white); + av_log(ctx, AV_LOG_DEBUG, "Estimated illumination after normalization= %f %f %f\n", + s->white[0], s->white[1], s->white[2]); + + return ret; +} + +/** + * Performs simple correction via diagonal transformation model. + * + * @param ctx the filter context. + * @param arg data to be passed between threads. + * @param jobnr current job nubmer. + * @param nb_jobs total number of jobs. + * + * @return 0. + */ +static int diagonal_transformation(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) +{ + ColorConstancyContext *s = ctx->priv; + ThreadData *td = arg; + AVFrame *in = td->in; + AVFrame *out = td->out; + int plane; + + for (plane = 0; plane < NUM_PLANES; ++plane) { + const int height = s->planeheight[plane]; + const int width = s->planewidth[plane]; + const int64_t numpixels = width * (int64_t)height; + const int slice_start = (numpixels * jobnr) / nb_jobs; + const int slice_end = (numpixels * (jobnr+1)) / nb_jobs; + const uint8_t *src = in->data[plane]; + uint8_t *dst = out->data[plane]; + double temp; + unsigned i; + + for (i = slice_start; i < slice_end; ++i) { + temp = src[i] / (s->white[plane] * SQRT3); + dst[i] = av_clip_uint8((int)(temp + 0.5)); + } + } + return 0; +} + +/** + * Main control function for correcting scene illumination based on + * estimated illumination. + * + * @param ctx the filter context. + * @param in holds frame to correct + * @param out holds corrected frame + */ +static void chromatic_adaptation(AVFilterContext *ctx, AVFrame *in, AVFrame *out) +{ + ColorConstancyContext *s = ctx->priv; + ThreadData td; + int nb_jobs = FFMIN3(s->planeheight[1], s->planewidth[1], s->nb_threads); + + td.in = in; + td.out = out; + ctx->internal->execute(ctx, diagonal_transformation, &td, NULL, nb_jobs); +} + +static int query_formats(AVFilterContext *ctx) +{ + static const enum AVPixelFormat pix_fmts[] = { + // TODO: support more formats + // FIXME: error when saving to .jpg + AV_PIX_FMT_GBRP, + AV_PIX_FMT_NONE + }; + + return ff_set_common_formats(ctx, ff_make_format_list(pix_fmts)); +} + +static int config_props(AVFilterLink *inlink) +{ + AVFilterContext *ctx = inlink->dst; + ColorConstancyContext *s = ctx->priv; + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format); + const double break_off_sigma = 3.0; + double sigma = s->sigma; + int ret; + + if (!floor(break_off_sigma * sigma + 0.5) && s->difford) { + av_log(ctx, AV_LOG_ERROR, "floor(%f * sigma) must be > 0 when difford > 0.\n", break_off_sigma); + return AVERROR(EINVAL); + } + + s->filtersize = 2 * floor(break_off_sigma * sigma + 0.5) + 1; + if (ret=set_gauss(ctx)) { + return ret; + } + + s->nb_threads = ff_filter_get_nb_threads(ctx); + s->planewidth[1] = s->planewidth[2] = AV_CEIL_RSHIFT(inlink->w, desc->log2_chroma_w); + s->planewidth[0] = s->planewidth[3] = inlink->w; + s->planeheight[1] = s->planeheight[2] = AV_CEIL_RSHIFT(inlink->h, desc->log2_chroma_h); + s->planeheight[0] = s->planeheight[3] = inlink->h; + + return 0; +} + +static int filter_frame(AVFilterLink *inlink, AVFrame *in) +{ + AVFilterContext *ctx = inlink->dst; + AVFilterLink *outlink = ctx->outputs[0]; + AVFrame *out; + int ret; + + ret = illumination_estimation(ctx, in); + if (ret) { + return ret; + } + + if (av_frame_is_writable(in)) { + out = in; + } else { + out = ff_get_video_buffer(outlink, outlink->w, outlink->h); + if (!out) { + av_log(ctx, AV_LOG_ERROR, "Out of memory while allocating output video buffer.\n"); + return AVERROR(ENOMEM); + } + av_frame_copy_props(out, in); + } + chromatic_adaptation(ctx, in, out); + + return ff_filter_frame(outlink, out); +} + +static av_cold void uninit(AVFilterContext *ctx) +{ + ColorConstancyContext *s = ctx->priv; + int difford = s->difford; + int i; + + for (i = 0; i <= difford; ++i) { + av_freep(&s->gauss[i]); + } +} + +static const AVFilterPad colorconstancy_inputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + .config_props = config_props, + .filter_frame = filter_frame, + }, + { NULL } +}; + +static const AVFilterPad colorconstancy_outputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + }, + { NULL } +}; + +#if CONFIG_GREYEDGE_FILTER + +static const AVOption greyedge_options[] = { + { "difford", "set differentiation order", OFFSET(difford), AV_OPT_TYPE_INT, {.i64=1}, 0, 2, FLAGS }, + { "minknorm", "set Minkowski norm", OFFSET(minknorm), AV_OPT_TYPE_INT, {.i64=1}, 0, 20, FLAGS }, + { "sigma", "set sigma", OFFSET(sigma), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0.0, 1024.0, FLAGS }, + { NULL } +}; + +AVFILTER_DEFINE_CLASS(greyedge); + +AVFilter ff_vf_greyedge = { + .name = GREY_EDGE, + .description = NULL_IF_CONFIG_SMALL("Estimates scene illumination by grey edge assumption."), + .priv_size = sizeof(ColorConstancyContext), + .priv_class = &greyedge_class, + .query_formats = query_formats, + .uninit = uninit, + .inputs = colorconstancy_inputs, + .outputs = colorconstancy_outputs, + .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS, +}; + +#endif /* CONFIG_GREY_EDGE_FILTER */ diff --git a/libavfilter/vf_colorkey.c b/libavfilter/vf_colorkey.c index 3d65e59d4..4e37c7f0c 100644 --- a/libavfilter/vf_colorkey.c +++ b/libavfilter/vf_colorkey.c @@ -34,6 +34,9 @@ typedef struct ColorkeyContext { uint8_t colorkey_rgba[4]; float similarity; float blend; + + int (*do_slice)(AVFilterContext *ctx, void *arg, + int jobnr, int nb_jobs); } ColorkeyContext; static uint8_t do_colorkey_pixel(ColorkeyContext *ctx, uint8_t r, uint8_t g, uint8_t b) @@ -77,15 +80,65 @@ static int do_colorkey_slice(AVFilterContext *avctx, void *arg, int jobnr, int n return 0; } +static int do_colorhold_slice(AVFilterContext *avctx, void *arg, int jobnr, int nb_jobs) +{ + AVFrame *frame = arg; + + const int slice_start = (frame->height * jobnr) / nb_jobs; + const int slice_end = (frame->height * (jobnr + 1)) / nb_jobs; + + ColorkeyContext *ctx = avctx->priv; + + int x, y; + + for (y = slice_start; y < slice_end; ++y) { + for (x = 0; x < frame->width; ++x) { + int o, t, r, g, b; + + o = frame->linesize[0] * y + x * 4; + r = frame->data[0][o + ctx->co[0]]; + g = frame->data[0][o + ctx->co[1]]; + b = frame->data[0][o + ctx->co[2]]; + + t = do_colorkey_pixel(ctx, r, g, b); + + if (t > 0) { + int a = (r + g + b) / 3; + int rt = 255 - t; + + frame->data[0][o + ctx->co[0]] = (a * t + r * rt + 127) >> 8; + frame->data[0][o + ctx->co[1]] = (a * t + g * rt + 127) >> 8; + frame->data[0][o + ctx->co[2]] = (a * t + b * rt + 127) >> 8; + } + } + } + + return 0; +} + +static av_cold int init_filter(AVFilterContext *avctx) +{ + ColorkeyContext *ctx = avctx->priv; + + if (!strcmp(avctx->filter->name, "colorkey")) { + ctx->do_slice = do_colorkey_slice; + } else { + ctx->do_slice = do_colorhold_slice; + } + + return 0; +} + static int filter_frame(AVFilterLink *link, AVFrame *frame) { AVFilterContext *avctx = link->dst; + ColorkeyContext *ctx = avctx->priv; int res; if (res = av_frame_make_writable(frame)) return res; - if (res = avctx->internal->execute(avctx, do_colorkey_slice, frame, NULL, FFMIN(frame->height, ff_filter_get_nb_threads(avctx)))) + if (res = avctx->internal->execute(avctx, ctx->do_slice, frame, NULL, FFMIN(frame->height, ff_filter_get_nb_threads(avctx)))) return res; return ff_filter_frame(avctx->outputs[0], frame); @@ -148,6 +201,8 @@ static const AVFilterPad colorkey_outputs[] = { #define OFFSET(x) offsetof(ColorkeyContext, x) #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM +#if CONFIG_COLORKEY_FILTER + static const AVOption colorkey_options[] = { { "color", "set the colorkey key color", OFFSET(colorkey_rgba), AV_OPT_TYPE_COLOR, { .str = "black" }, CHAR_MIN, CHAR_MAX, FLAGS }, { "similarity", "set the colorkey similarity value", OFFSET(similarity), AV_OPT_TYPE_FLOAT, { .dbl = 0.01 }, 0.01, 1.0, FLAGS }, @@ -163,7 +218,34 @@ AVFilter ff_vf_colorkey = { .priv_size = sizeof(ColorkeyContext), .priv_class = &colorkey_class, .query_formats = query_formats, + .init = init_filter, .inputs = colorkey_inputs, .outputs = colorkey_outputs, .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS, }; + +#endif /* CONFIG_COLORKEY_FILTER */ +#if CONFIG_COLORHOLD_FILTER + +static const AVOption colorhold_options[] = { + { "color", "set the colorhold key color", OFFSET(colorkey_rgba), AV_OPT_TYPE_COLOR, { .str = "black" }, CHAR_MIN, CHAR_MAX, FLAGS }, + { "similarity", "set the colorhold similarity value", OFFSET(similarity), AV_OPT_TYPE_FLOAT, { .dbl = 0.01 }, 0.01, 1.0, FLAGS }, + { "blend", "set the colorhold blend value", OFFSET(blend), AV_OPT_TYPE_FLOAT, { .dbl = 0.0 }, 0.0, 1.0, FLAGS }, + { NULL } +}; + +AVFILTER_DEFINE_CLASS(colorhold); + +AVFilter ff_vf_colorhold = { + .name = "colorhold", + .description = NULL_IF_CONFIG_SMALL("Turns a certain color range into gray. Operates on RGB colors."), + .priv_size = sizeof(ColorkeyContext), + .priv_class = &colorhold_class, + .query_formats = query_formats, + .init = init_filter, + .inputs = colorkey_inputs, + .outputs = colorkey_outputs, + .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS, +}; + +#endif /* CONFIG_COLORHOLD_FILTER */ diff --git a/libavfilter/vf_colorkey_opencl.c b/libavfilter/vf_colorkey_opencl.c new file mode 100644 index 000000000..46a0454fb --- /dev/null +++ b/libavfilter/vf_colorkey_opencl.c @@ -0,0 +1,244 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/opt.h" +#include "libavutil/imgutils.h" +#include "avfilter.h" +#include "formats.h" +#include "internal.h" +#include "opencl.h" +#include "opencl_source.h" +#include "video.h" + +typedef struct ColorkeyOpenCLContext { + OpenCLFilterContext ocf; + // Whether or not the above `OpenCLFilterContext` has been initialized + int initialized; + + cl_command_queue command_queue; + cl_kernel kernel_colorkey; + + // The color we are supposed to replace with transparency + uint8_t colorkey_rgba[4]; + // Stored as a normalized float for passing to the OpenCL kernel + cl_float4 colorkey_rgba_float; + // Similarity percentage compared to `colorkey_rgba`, ranging from `0.01` to `1.0` + // where `0.01` matches only the key color and `1.0` matches all colors + float similarity; + // Blending percentage where `0.0` results in fully transparent pixels, `1.0` results + // in fully opaque pixels, and numbers in between result in transparency that varies + // based on the similarity to the key color + float blend; +} ColorkeyOpenCLContext; + +static int colorkey_opencl_init(AVFilterContext *avctx) +{ + ColorkeyOpenCLContext *ctx = avctx->priv; + cl_int cle; + int err; + + err = ff_opencl_filter_load_program(avctx, &ff_opencl_source_colorkey, 1); + if (err < 0) + goto fail; + + ctx->command_queue = clCreateCommandQueue( + ctx->ocf.hwctx->context, + ctx->ocf.hwctx->device_id, + 0, + &cle + ); + + CL_FAIL_ON_ERROR(AVERROR(EIO), "Failed to create OpenCL command queue %d.\n", cle); + + if (ctx->blend > 0.0001) { + ctx->kernel_colorkey = clCreateKernel(ctx->ocf.program, "colorkey_blend", &cle); + CL_FAIL_ON_ERROR(AVERROR(EIO), "Failed to create colorkey_blend kernel: %d.\n", cle); + } else { + ctx->kernel_colorkey = clCreateKernel(ctx->ocf.program, "colorkey", &cle); + CL_FAIL_ON_ERROR(AVERROR(EIO), "Failed to create colorkey kernel: %d.\n", cle); + } + + for (int i = 0; i < 4; ++i) { + ctx->colorkey_rgba_float.s[i] = (float)ctx->colorkey_rgba[i] / 255.0; + } + + ctx->initialized = 1; + return 0; + +fail: + if (ctx->command_queue) + clReleaseCommandQueue(ctx->command_queue); + if (ctx->kernel_colorkey) + clReleaseKernel(ctx->kernel_colorkey); + return err; +} + +static int filter_frame(AVFilterLink *link, AVFrame *input_frame) +{ + AVFilterContext *avctx = link->dst; + AVFilterLink *outlink = avctx->outputs[0]; + ColorkeyOpenCLContext *colorkey_ctx = avctx->priv; + AVFrame *output_frame = NULL; + int err; + cl_int cle; + size_t global_work[2]; + cl_mem src, dst; + + if (!input_frame->hw_frames_ctx) + return AVERROR(EINVAL); + + if (!colorkey_ctx->initialized) { + AVHWFramesContext *input_frames_ctx = + (AVHWFramesContext*)input_frame->hw_frames_ctx->data; + int fmt = input_frames_ctx->sw_format; + + // Make sure the input is a format we support + if (fmt != AV_PIX_FMT_ARGB && + fmt != AV_PIX_FMT_RGBA && + fmt != AV_PIX_FMT_ABGR && + fmt != AV_PIX_FMT_BGRA + ) { + av_log(avctx, AV_LOG_ERROR, "unsupported (non-RGB) format in colorkey_opencl.\n"); + err = AVERROR(ENOSYS); + goto fail; + } + + err = colorkey_opencl_init(avctx); + if (err < 0) + goto fail; + } + + // This filter only operates on RGB data and we know that will be on the first plane + src = (cl_mem)input_frame->data[0]; + output_frame = ff_get_video_buffer(outlink, outlink->w, outlink->h); + if (!output_frame) { + err = AVERROR(ENOMEM); + goto fail; + } + dst = (cl_mem)output_frame->data[0]; + + CL_SET_KERNEL_ARG(colorkey_ctx->kernel_colorkey, 0, cl_mem, &src); + CL_SET_KERNEL_ARG(colorkey_ctx->kernel_colorkey, 1, cl_mem, &dst); + CL_SET_KERNEL_ARG(colorkey_ctx->kernel_colorkey, 2, cl_float4, &colorkey_ctx->colorkey_rgba_float); + CL_SET_KERNEL_ARG(colorkey_ctx->kernel_colorkey, 3, float, &colorkey_ctx->similarity); + if (colorkey_ctx->blend > 0.0001) { + CL_SET_KERNEL_ARG(colorkey_ctx->kernel_colorkey, 4, float, &colorkey_ctx->blend); + } + + err = ff_opencl_filter_work_size_from_image(avctx, global_work, input_frame, 0, 0); + if (err < 0) + goto fail; + + cle = clEnqueueNDRangeKernel( + colorkey_ctx->command_queue, + colorkey_ctx->kernel_colorkey, + 2, + NULL, + global_work, + NULL, + 0, + NULL, + NULL + ); + + CL_FAIL_ON_ERROR(AVERROR(EIO), "Failed to enqueue colorkey kernel: %d.\n", cle); + + // Run queued kernel + cle = clFinish(colorkey_ctx->command_queue); + CL_FAIL_ON_ERROR(AVERROR(EIO), "Failed to finish command queue: %d.\n", cle); + + err = av_frame_copy_props(output_frame, input_frame); + if (err < 0) + goto fail; + + av_frame_free(&input_frame); + + return ff_filter_frame(outlink, output_frame); + +fail: + clFinish(colorkey_ctx->command_queue); + av_frame_free(&input_frame); + av_frame_free(&output_frame); + return err; +} + +static av_cold void colorkey_opencl_uninit(AVFilterContext *avctx) +{ + ColorkeyOpenCLContext *ctx = avctx->priv; + cl_int cle; + + if (ctx->kernel_colorkey) { + cle = clReleaseKernel(ctx->kernel_colorkey); + if (cle != CL_SUCCESS) + av_log(avctx, AV_LOG_ERROR, "Failed to release " + "kernel: %d.\n", cle); + } + + if (ctx->command_queue) { + cle = clReleaseCommandQueue(ctx->command_queue); + if (cle != CL_SUCCESS) + av_log(avctx, AV_LOG_ERROR, "Failed to release " + "command queue: %d.\n", cle); + } + + ff_opencl_filter_uninit(avctx); +} + +static const AVFilterPad colorkey_opencl_inputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + .filter_frame = filter_frame, + .config_props = &ff_opencl_filter_config_input, + }, + { NULL } +}; + +static const AVFilterPad colorkey_opencl_outputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + .config_props = &ff_opencl_filter_config_output, + }, + { NULL } +}; + +#define OFFSET(x) offsetof(ColorkeyOpenCLContext, x) +#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM + +static const AVOption colorkey_opencl_options[] = { + { "color", "set the colorkey key color", OFFSET(colorkey_rgba), AV_OPT_TYPE_COLOR, { .str = "black" }, CHAR_MIN, CHAR_MAX, FLAGS }, + { "similarity", "set the colorkey similarity value", OFFSET(similarity), AV_OPT_TYPE_FLOAT, { .dbl = 0.01 }, 0.01, 1.0, FLAGS }, + { "blend", "set the colorkey key blend value", OFFSET(blend), AV_OPT_TYPE_FLOAT, { .dbl = 0.0 }, 0.0, 1.0, FLAGS }, + { NULL } +}; + +AVFILTER_DEFINE_CLASS(colorkey_opencl); + +AVFilter ff_vf_colorkey_opencl = { + .name = "colorkey_opencl", + .description = NULL_IF_CONFIG_SMALL("Turns a certain color into transparency. Operates on RGB colors."), + .priv_size = sizeof(ColorkeyOpenCLContext), + .priv_class = &colorkey_opencl_class, + .init = &ff_opencl_filter_init, + .uninit = &colorkey_opencl_uninit, + .query_formats = &ff_opencl_filter_query_formats, + .inputs = colorkey_opencl_inputs, + .outputs = colorkey_opencl_outputs, + .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE +}; diff --git a/libavfilter/vf_colorlevels.c b/libavfilter/vf_colorlevels.c index 5385a5e75..fadb39e00 100644 --- a/libavfilter/vf_colorlevels.c +++ b/libavfilter/vf_colorlevels.c @@ -105,6 +105,68 @@ static int config_input(AVFilterLink *inlink) return 0; } +struct thread_data { + const uint8_t *srcrow; + uint8_t *dstrow; + int dst_linesize; + int src_linesize; + + double coeff; + uint8_t offset; + + int h; + + int imin; + int omin; +}; + +#define LOAD_COMMON\ + ColorLevelsContext *s = ctx->priv;\ + const struct thread_data *td = arg;\ +\ + int process_h = td->h;\ + const int slice_start = (process_h * jobnr ) / nb_jobs;\ + const int slice_end = (process_h * (jobnr+1)) / nb_jobs;\ + int x, y;\ + const uint8_t *srcrow = td->srcrow;\ + uint8_t *dstrow = td->dstrow;\ + const int step = s->step;\ + const uint8_t offset = td->offset;\ +\ + int imin = td->imin;\ + int omin = td->omin;\ + double coeff = td->coeff;\ + +static int colorlevel_slice_8(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) +{ + LOAD_COMMON + + for (y = slice_start; y < slice_end; y++) { + const uint8_t *src = srcrow + y * td->src_linesize; + uint8_t *dst = dstrow + y * td->dst_linesize; + + for (x = 0; x < s->linesize; x += step) + dst[x + offset] = av_clip_uint8((src[x + offset] - imin) * coeff + omin); + } + + return 0; +} + +static int colorlevel_slice_16(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) +{ + LOAD_COMMON + + for (y = slice_start; y < slice_end; y++) { + const uint16_t *src = (const uint16_t *)(srcrow + y * td->src_linesize); + uint16_t *dst = (uint16_t *)(dstrow + y * td->dst_linesize); + + for (x = 0; x < s->linesize; x += step) + dst[x + offset] = av_clip_uint16((src[x + offset] - imin) * coeff + omin); + } + + return 0; +} + static int filter_frame(AVFilterLink *inlink, AVFrame *in) { AVFilterContext *ctx = inlink->dst; @@ -137,6 +199,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) int omin = lrint(r->out_min * UINT8_MAX); int omax = lrint(r->out_max * UINT8_MAX); double coeff; + struct thread_data td; if (imin < 0) { imin = UINT8_MAX; @@ -162,15 +225,19 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) srcrow = in->data[0]; coeff = (omax - omin) / (double)(imax - imin); - for (y = 0; y < inlink->h; y++) { - const uint8_t *src = srcrow; - uint8_t *dst = dstrow; - for (x = 0; x < s->linesize; x += step) - dst[x + offset] = av_clip_uint8((src[x + offset] - imin) * coeff + omin); - dstrow += out->linesize[0]; - srcrow += in->linesize[0]; - } + td.srcrow = srcrow; + td.dstrow = dstrow; + td.dst_linesize = out->linesize[0]; + td.src_linesize = in->linesize[0]; + td.coeff = coeff; + td.offset = offset; + td.h = inlink->h; + td.imin = imin; + td.omin = omin; + + ctx->internal->execute(ctx, colorlevel_slice_8, &td, NULL, + FFMIN(inlink->h, ff_filter_get_nb_threads(ctx))); } break; case 2: @@ -184,6 +251,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) int omin = lrint(r->out_min * UINT16_MAX); int omax = lrint(r->out_max * UINT16_MAX); double coeff; + struct thread_data td; if (imin < 0) { imin = UINT16_MAX; @@ -209,15 +277,19 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) srcrow = in->data[0]; coeff = (omax - omin) / (double)(imax - imin); - for (y = 0; y < inlink->h; y++) { - const uint16_t *src = (const uint16_t*)srcrow; - uint16_t *dst = (uint16_t *)dstrow; - for (x = 0; x < s->linesize; x += step) - dst[x + offset] = av_clip_uint16((src[x + offset] - imin) * coeff + omin); - dstrow += out->linesize[0]; - srcrow += in->linesize[0]; - } + td.srcrow = srcrow; + td.dstrow = dstrow; + td.dst_linesize = out->linesize[0]; + td.src_linesize = in->linesize[0]; + td.coeff = coeff; + td.offset = offset; + td.h = inlink->h; + td.imin = imin; + td.omin = omin; + + ctx->internal->execute(ctx, colorlevel_slice_16, &td, NULL, + FFMIN(inlink->h, ff_filter_get_nb_threads(ctx))); } } @@ -252,5 +324,5 @@ AVFilter ff_vf_colorlevels = { .query_formats = query_formats, .inputs = colorlevels_inputs, .outputs = colorlevels_outputs, - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC, + .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS, }; diff --git a/libavfilter/vf_colorspace.c b/libavfilter/vf_colorspace.c index 71ea08a20..df6efffb3 100644 --- a/libavfilter/vf_colorspace.c +++ b/libavfilter/vf_colorspace.c @@ -33,6 +33,7 @@ #include "formats.h" #include "internal.h" #include "video.h" +#include "colorspace.h" enum DitherMode { DITHER_NONE, @@ -110,21 +111,13 @@ static const enum AVColorSpace default_csp[CS_NB + 1] = { struct ColorPrimaries { enum Whitepoint wp; - double xr, yr, xg, yg, xb, yb; + struct PrimaryCoefficients coeff; }; struct TransferCharacteristics { double alpha, beta, gamma, delta; }; -struct LumaCoefficients { - double cr, cg, cb; -}; - -struct WhitepointCoefficients { - double xw, yw; -}; - typedef struct ColorSpaceContext { const AVClass *class; @@ -177,78 +170,6 @@ typedef struct ColorSpaceContext { // FIXME dithering if bitdepth goes down? // FIXME bitexact for fate integration? -static const double ycgco_matrix[3][3] = -{ - { 0.25, 0.5, 0.25 }, - { -0.25, 0.5, -0.25 }, - { 0.5, 0, -0.5 }, -}; - -static const double gbr_matrix[3][3] = -{ - { 0, 1, 0 }, - { 0, -0.5, 0.5 }, - { 0.5, -0.5, 0 }, -}; - -/* - * All constants explained in e.g. https://linuxtv.org/downloads/v4l-dvb-apis/ch02s06.html - * The older ones (bt470bg/m) are also explained in their respective ITU docs - * (e.g. https://www.itu.int/dms_pubrec/itu-r/rec/bt/R-REC-BT.470-5-199802-S!!PDF-E.pdf) - * whereas the newer ones can typically be copied directly from wikipedia :) - */ -static const struct LumaCoefficients luma_coefficients[AVCOL_SPC_NB] = { - [AVCOL_SPC_FCC] = { 0.30, 0.59, 0.11 }, - [AVCOL_SPC_BT470BG] = { 0.299, 0.587, 0.114 }, - [AVCOL_SPC_SMPTE170M] = { 0.299, 0.587, 0.114 }, - [AVCOL_SPC_BT709] = { 0.2126, 0.7152, 0.0722 }, - [AVCOL_SPC_SMPTE240M] = { 0.212, 0.701, 0.087 }, - [AVCOL_SPC_YCOCG] = { 0.25, 0.5, 0.25 }, - [AVCOL_SPC_RGB] = { 1, 1, 1 }, - [AVCOL_SPC_BT2020_NCL] = { 0.2627, 0.6780, 0.0593 }, - [AVCOL_SPC_BT2020_CL] = { 0.2627, 0.6780, 0.0593 }, -}; - -static const struct LumaCoefficients *get_luma_coefficients(enum AVColorSpace csp) -{ - const struct LumaCoefficients *coeffs; - - if (csp >= AVCOL_SPC_NB) - return NULL; - coeffs = &luma_coefficients[csp]; - if (!coeffs->cr) - return NULL; - - return coeffs; -} - -static void fill_rgb2yuv_table(const struct LumaCoefficients *coeffs, - double rgb2yuv[3][3]) -{ - double bscale, rscale; - - // special ycgco matrix - if (coeffs->cr == 0.25 && coeffs->cg == 0.5 && coeffs->cb == 0.25) { - memcpy(rgb2yuv, ycgco_matrix, sizeof(double) * 9); - return; - } else if (coeffs->cr == 1 && coeffs->cg == 1 && coeffs->cb == 1) { - memcpy(rgb2yuv, gbr_matrix, sizeof(double) * 9); - return; - } - - rgb2yuv[0][0] = coeffs->cr; - rgb2yuv[0][1] = coeffs->cg; - rgb2yuv[0][2] = coeffs->cb; - bscale = 0.5 / (coeffs->cb - 1.0); - rscale = 0.5 / (coeffs->cr - 1.0); - rgb2yuv[1][0] = bscale * coeffs->cr; - rgb2yuv[1][1] = bscale * coeffs->cg; - rgb2yuv[1][2] = 0.5; - rgb2yuv[2][0] = 0.5; - rgb2yuv[2][1] = rscale * coeffs->cg; - rgb2yuv[2][2] = rscale * coeffs->cb; -} - // FIXME I'm pretty sure gamma22/28 also have a linear toe slope, but I can't // find any actual tables that document their real values... // See http://www.13thmonkey.org/~boris/gammacorrection/ first graph why it matters @@ -286,57 +207,30 @@ static const struct WhitepointCoefficients whitepoint_coefficients[WP_NB] = { }; static const struct ColorPrimaries color_primaries[AVCOL_PRI_NB] = { - [AVCOL_PRI_BT709] = { WP_D65, 0.640, 0.330, 0.300, 0.600, 0.150, 0.060 }, - [AVCOL_PRI_BT470M] = { WP_C, 0.670, 0.330, 0.210, 0.710, 0.140, 0.080 }, - [AVCOL_PRI_BT470BG] = { WP_D65, 0.640, 0.330, 0.290, 0.600, 0.150, 0.060,}, - [AVCOL_PRI_SMPTE170M] = { WP_D65, 0.630, 0.340, 0.310, 0.595, 0.155, 0.070 }, - [AVCOL_PRI_SMPTE240M] = { WP_D65, 0.630, 0.340, 0.310, 0.595, 0.155, 0.070 }, - [AVCOL_PRI_SMPTE428] = { WP_E, 0.735, 0.265, 0.274, 0.718, 0.167, 0.009 }, - [AVCOL_PRI_SMPTE431] = { WP_DCI, 0.680, 0.320, 0.265, 0.690, 0.150, 0.060 }, - [AVCOL_PRI_SMPTE432] = { WP_D65, 0.680, 0.320, 0.265, 0.690, 0.150, 0.060 }, - [AVCOL_PRI_FILM] = { WP_C, 0.681, 0.319, 0.243, 0.692, 0.145, 0.049 }, - [AVCOL_PRI_BT2020] = { WP_D65, 0.708, 0.292, 0.170, 0.797, 0.131, 0.046 }, - [AVCOL_PRI_JEDEC_P22] = { WP_D65, 0.630, 0.340, 0.295, 0.605, 0.155, 0.077 }, + [AVCOL_PRI_BT709] = { WP_D65, { 0.640, 0.330, 0.300, 0.600, 0.150, 0.060 } }, + [AVCOL_PRI_BT470M] = { WP_C, { 0.670, 0.330, 0.210, 0.710, 0.140, 0.080 } }, + [AVCOL_PRI_BT470BG] = { WP_D65, { 0.640, 0.330, 0.290, 0.600, 0.150, 0.060 } }, + [AVCOL_PRI_SMPTE170M] = { WP_D65, { 0.630, 0.340, 0.310, 0.595, 0.155, 0.070 } }, + [AVCOL_PRI_SMPTE240M] = { WP_D65, { 0.630, 0.340, 0.310, 0.595, 0.155, 0.070 } }, + [AVCOL_PRI_SMPTE428] = { WP_E, { 0.735, 0.265, 0.274, 0.718, 0.167, 0.009 } }, + [AVCOL_PRI_SMPTE431] = { WP_DCI, { 0.680, 0.320, 0.265, 0.690, 0.150, 0.060 } }, + [AVCOL_PRI_SMPTE432] = { WP_D65, { 0.680, 0.320, 0.265, 0.690, 0.150, 0.060 } }, + [AVCOL_PRI_FILM] = { WP_C, { 0.681, 0.319, 0.243, 0.692, 0.145, 0.049 } }, + [AVCOL_PRI_BT2020] = { WP_D65, { 0.708, 0.292, 0.170, 0.797, 0.131, 0.046 } }, + [AVCOL_PRI_JEDEC_P22] = { WP_D65, { 0.630, 0.340, 0.295, 0.605, 0.155, 0.077 } }, }; static const struct ColorPrimaries *get_color_primaries(enum AVColorPrimaries prm) { - const struct ColorPrimaries *coeffs; + const struct ColorPrimaries *p; if (prm >= AVCOL_PRI_NB) return NULL; - coeffs = &color_primaries[prm]; - if (!coeffs->xr) + p = &color_primaries[prm]; + if (!p->coeff.xr) return NULL; - return coeffs; -} - -static void invert_matrix3x3(const double in[3][3], double out[3][3]) -{ - double m00 = in[0][0], m01 = in[0][1], m02 = in[0][2], - m10 = in[1][0], m11 = in[1][1], m12 = in[1][2], - m20 = in[2][0], m21 = in[2][1], m22 = in[2][2]; - int i, j; - double det; - - out[0][0] = (m11 * m22 - m21 * m12); - out[0][1] = -(m01 * m22 - m21 * m02); - out[0][2] = (m01 * m12 - m11 * m02); - out[1][0] = -(m10 * m22 - m20 * m12); - out[1][1] = (m00 * m22 - m20 * m02); - out[1][2] = -(m00 * m12 - m10 * m02); - out[2][0] = (m10 * m21 - m20 * m11); - out[2][1] = -(m00 * m21 - m20 * m01); - out[2][2] = (m00 * m11 - m10 * m01); - - det = m00 * out[0][0] + m10 * out[0][1] + m20 * out[0][2]; - det = 1.0 / det; - - for (i = 0; i < 3; i++) { - for (j = 0; j < 3; j++) - out[i][j] *= det; - } + return p; } static int fill_gamma_table(ColorSpaceContext *s) @@ -366,9 +260,9 @@ static int fill_gamma_table(ColorSpaceContext *s) s->delin_lut[n] = av_clip_int16(lrint(d * 28672.0)); // linearize - if (v <= -in_beta) { + if (v <= -in_beta * in_delta) { l = -pow((1.0 - in_alpha - v) * in_ialpha, in_igamma); - } else if (v < in_beta) { + } else if (v < in_beta * in_delta) { l = v * in_idelta; } else { l = pow((v + in_alpha - 1.0) * in_ialpha, in_igamma); @@ -379,49 +273,6 @@ static int fill_gamma_table(ColorSpaceContext *s) return 0; } -/* - * see e.g. http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html - */ -static void fill_rgb2xyz_table(const struct ColorPrimaries *coeffs, - double rgb2xyz[3][3]) -{ - const struct WhitepointCoefficients *wp = &whitepoint_coefficients[coeffs->wp]; - double i[3][3], sr, sg, sb, zw; - - rgb2xyz[0][0] = coeffs->xr / coeffs->yr; - rgb2xyz[0][1] = coeffs->xg / coeffs->yg; - rgb2xyz[0][2] = coeffs->xb / coeffs->yb; - rgb2xyz[1][0] = rgb2xyz[1][1] = rgb2xyz[1][2] = 1.0; - rgb2xyz[2][0] = (1.0 - coeffs->xr - coeffs->yr) / coeffs->yr; - rgb2xyz[2][1] = (1.0 - coeffs->xg - coeffs->yg) / coeffs->yg; - rgb2xyz[2][2] = (1.0 - coeffs->xb - coeffs->yb) / coeffs->yb; - invert_matrix3x3(rgb2xyz, i); - zw = 1.0 - wp->xw - wp->yw; - sr = i[0][0] * wp->xw + i[0][1] * wp->yw + i[0][2] * zw; - sg = i[1][0] * wp->xw + i[1][1] * wp->yw + i[1][2] * zw; - sb = i[2][0] * wp->xw + i[2][1] * wp->yw + i[2][2] * zw; - rgb2xyz[0][0] *= sr; - rgb2xyz[0][1] *= sg; - rgb2xyz[0][2] *= sb; - rgb2xyz[1][0] *= sr; - rgb2xyz[1][1] *= sg; - rgb2xyz[1][2] *= sb; - rgb2xyz[2][0] *= sr; - rgb2xyz[2][1] *= sg; - rgb2xyz[2][2] *= sb; -} - -static void mul3x3(double dst[3][3], const double src1[3][3], const double src2[3][3]) -{ - int m, n; - - for (m = 0; m < 3; m++) - for (n = 0; n < 3; n++) - dst[m][n] = src2[m][0] * src1[0][n] + - src2[m][1] * src1[1][n] + - src2[m][2] * src1[2][n]; -} - /* * See http://www.brucelindbloom.com/index.html?Eqn_ChromAdapt.html * This function uses the Bradford mechanism. @@ -448,7 +299,7 @@ static void fill_whitepoint_conv_table(double out[3][3], enum WhitepointAdaptati double mai[3][3], fac[3][3], tmp[3][3]; double rs, gs, bs, rd, gd, bd; - invert_matrix3x3(ma, mai); + ff_matrix_invert_3x3(ma, mai); rs = ma[0][0] * wp_src->xw + ma[0][1] * wp_src->yw + ma[0][2] * zw_src; gs = ma[1][0] * wp_src->xw + ma[1][1] * wp_src->yw + ma[1][2] * zw_src; bs = ma[2][0] * wp_src->xw + ma[2][1] * wp_src->yw + ma[2][2] * zw_src; @@ -459,8 +310,8 @@ static void fill_whitepoint_conv_table(double out[3][3], enum WhitepointAdaptati fac[1][1] = gd / gs; fac[2][2] = bd / bs; fac[0][1] = fac[0][2] = fac[1][0] = fac[1][2] = fac[2][0] = fac[2][1] = 0.0; - mul3x3(tmp, ma, fac); - mul3x3(out, tmp, mai); + ff_matrix_mul_3x3(tmp, ma, fac); + ff_matrix_mul_3x3(out, tmp, mai); } static void apply_lut(int16_t *buf[3], ptrdiff_t stride, @@ -517,7 +368,7 @@ static int convert(AVFilterContext *ctx, void *data, int job_nr, int n_jobs) s->yuv2yuv(out_data, td->out_linesize, in_data, td->in_linesize, w, h, s->yuv2yuv_coeffs, s->yuv_offset); } else { - // FIXME maybe (for caching effciency) do pipeline per-line instead of + // FIXME maybe (for caching efficiency) do pipeline per-line instead of // full buffer per function? (Or, since yuv2rgb requires 2 lines: per // 2 lines, for yuv420.) /* @@ -661,20 +512,23 @@ static int create_filtergraph(AVFilterContext *ctx, sizeof(*s->in_primaries)); if (!s->lrgb2lrgb_passthrough) { double rgb2xyz[3][3], xyz2rgb[3][3], rgb2rgb[3][3]; + const struct WhitepointCoefficients *wp_out, *wp_in; - fill_rgb2xyz_table(s->out_primaries, rgb2xyz); - invert_matrix3x3(rgb2xyz, xyz2rgb); - fill_rgb2xyz_table(s->in_primaries, rgb2xyz); + wp_out = &whitepoint_coefficients[s->out_primaries->wp]; + wp_in = &whitepoint_coefficients[s->in_primaries->wp]; + ff_fill_rgb2xyz_table(&s->out_primaries->coeff, wp_out, rgb2xyz); + ff_matrix_invert_3x3(rgb2xyz, xyz2rgb); + ff_fill_rgb2xyz_table(&s->in_primaries->coeff, wp_in, rgb2xyz); if (s->out_primaries->wp != s->in_primaries->wp && s->wp_adapt != WP_ADAPT_IDENTITY) { double wpconv[3][3], tmp[3][3]; fill_whitepoint_conv_table(wpconv, s->wp_adapt, s->in_primaries->wp, s->out_primaries->wp); - mul3x3(tmp, rgb2xyz, wpconv); - mul3x3(rgb2rgb, tmp, xyz2rgb); + ff_matrix_mul_3x3(tmp, rgb2xyz, wpconv); + ff_matrix_mul_3x3(rgb2rgb, tmp, xyz2rgb); } else { - mul3x3(rgb2rgb, rgb2xyz, xyz2rgb); + ff_matrix_mul_3x3(rgb2rgb, rgb2xyz, xyz2rgb); } for (m = 0; m < 3; m++) for (n = 0; n < 3; n++) { @@ -743,7 +597,7 @@ static int create_filtergraph(AVFilterContext *ctx, s->in_rng = in->color_range; if (s->user_irng != AVCOL_RANGE_UNSPECIFIED) s->in_rng = s->user_irng; - s->in_lumacoef = get_luma_coefficients(s->in_csp); + s->in_lumacoef = ff_get_luma_coefficients(s->in_csp); if (!s->in_lumacoef) { av_log(ctx, AV_LOG_ERROR, "Unsupported input colorspace %d (%s)\n", @@ -756,7 +610,7 @@ static int create_filtergraph(AVFilterContext *ctx, if (!s->out_lumacoef) { s->out_csp = out->colorspace; s->out_rng = out->color_range; - s->out_lumacoef = get_luma_coefficients(s->out_csp); + s->out_lumacoef = ff_get_luma_coefficients(s->out_csp); if (!s->out_lumacoef) { if (s->out_csp == AVCOL_SPC_UNSPECIFIED) { if (s->user_all == CS_UNSPECIFIED) { @@ -798,8 +652,8 @@ static int create_filtergraph(AVFilterContext *ctx, } for (n = 0; n < 8; n++) s->yuv_offset[0][n] = off; - fill_rgb2yuv_table(s->in_lumacoef, rgb2yuv); - invert_matrix3x3(rgb2yuv, yuv2rgb); + ff_fill_rgb2yuv_table(s->in_lumacoef, rgb2yuv); + ff_matrix_invert_3x3(rgb2yuv, yuv2rgb); bits = 1 << (in_desc->comp[0].depth - 1); for (n = 0; n < 3; n++) { for (in_rng = s->in_y_rng, m = 0; m < 3; m++, in_rng = s->in_uv_rng) { @@ -831,7 +685,7 @@ static int create_filtergraph(AVFilterContext *ctx, } for (n = 0; n < 8; n++) s->yuv_offset[1][n] = off; - fill_rgb2yuv_table(s->out_lumacoef, rgb2yuv); + ff_fill_rgb2yuv_table(s->out_lumacoef, rgb2yuv); bits = 1 << (29 - out_desc->comp[0].depth); for (out_rng = s->out_y_rng, n = 0; n < 3; n++, out_rng = s->out_uv_rng) { for (m = 0; m < 3; m++) { @@ -855,7 +709,7 @@ static int create_filtergraph(AVFilterContext *ctx, double yuv2yuv[3][3]; int in_rng, out_rng; - mul3x3(yuv2yuv, yuv2rgb, rgb2yuv); + ff_matrix_mul_3x3(yuv2yuv, yuv2rgb, rgb2yuv); for (out_rng = s->out_y_rng, m = 0; m < 3; m++, out_rng = s->out_uv_rng) { for (in_rng = s->in_y_rng, n = 0; n < 3; n++, in_rng = s->in_uv_rng) { s->yuv2yuv_coeffs[m][n][0] = diff --git a/libavfilter/vf_convolution.c b/libavfilter/vf_convolution.c index ce09e338c..1305569c8 100644 --- a/libavfilter/vf_convolution.c +++ b/libavfilter/vf_convolution.c @@ -21,6 +21,7 @@ #include "libavutil/avstring.h" #include "libavutil/imgutils.h" +#include "libavutil/intreadwrite.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "avfilter.h" @@ -28,22 +29,28 @@ #include "internal.h" #include "video.h" +enum MatrixMode { + MATRIX_SQUARE, + MATRIX_ROW, + MATRIX_COLUMN, + MATRIX_NBMODES, +}; + typedef struct ConvolutionContext { const AVClass *class; char *matrix_str[4]; float rdiv[4]; float bias[4]; + int mode[4]; float scale; float delta; int planes; int size[4]; int depth; + int max; int bpc; - int bstride; - uint8_t *buffer; - uint8_t **bptrs; int nb_planes; int nb_threads; int planewidth[4]; @@ -52,7 +59,12 @@ typedef struct ConvolutionContext { int matrix_length[4]; int copy[4]; - int (*filter[4])(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs); + void (*setup[4])(int radius, const uint8_t *c[], const uint8_t *src, int stride, + int x, int width, int y, int height, int bpc); + void (*filter[4])(uint8_t *dst, int width, + float rdiv, float bias, const int *const matrix, + const uint8_t *c[], int peak, int radius, + int dstride, int stride); } ConvolutionContext; #define OFFSET(x) offsetof(ConvolutionContext, x) @@ -63,14 +75,21 @@ static const AVOption convolution_options[] = { { "1m", "set matrix for 2nd plane", OFFSET(matrix_str[1]), AV_OPT_TYPE_STRING, {.str="0 0 0 0 1 0 0 0 0"}, 0, 0, FLAGS }, { "2m", "set matrix for 3rd plane", OFFSET(matrix_str[2]), AV_OPT_TYPE_STRING, {.str="0 0 0 0 1 0 0 0 0"}, 0, 0, FLAGS }, { "3m", "set matrix for 4th plane", OFFSET(matrix_str[3]), AV_OPT_TYPE_STRING, {.str="0 0 0 0 1 0 0 0 0"}, 0, 0, FLAGS }, - { "0rdiv", "set rdiv for 1st plane", OFFSET(rdiv[0]), AV_OPT_TYPE_FLOAT, {.dbl=1.0}, 0.0, INT_MAX, FLAGS}, - { "1rdiv", "set rdiv for 2nd plane", OFFSET(rdiv[1]), AV_OPT_TYPE_FLOAT, {.dbl=1.0}, 0.0, INT_MAX, FLAGS}, - { "2rdiv", "set rdiv for 3rd plane", OFFSET(rdiv[2]), AV_OPT_TYPE_FLOAT, {.dbl=1.0}, 0.0, INT_MAX, FLAGS}, - { "3rdiv", "set rdiv for 4th plane", OFFSET(rdiv[3]), AV_OPT_TYPE_FLOAT, {.dbl=1.0}, 0.0, INT_MAX, FLAGS}, + { "0rdiv", "set rdiv for 1st plane", OFFSET(rdiv[0]), AV_OPT_TYPE_FLOAT, {.dbl=0.0}, 0.0, INT_MAX, FLAGS}, + { "1rdiv", "set rdiv for 2nd plane", OFFSET(rdiv[1]), AV_OPT_TYPE_FLOAT, {.dbl=0.0}, 0.0, INT_MAX, FLAGS}, + { "2rdiv", "set rdiv for 3rd plane", OFFSET(rdiv[2]), AV_OPT_TYPE_FLOAT, {.dbl=0.0}, 0.0, INT_MAX, FLAGS}, + { "3rdiv", "set rdiv for 4th plane", OFFSET(rdiv[3]), AV_OPT_TYPE_FLOAT, {.dbl=0.0}, 0.0, INT_MAX, FLAGS}, { "0bias", "set bias for 1st plane", OFFSET(bias[0]), AV_OPT_TYPE_FLOAT, {.dbl=0.0}, 0.0, INT_MAX, FLAGS}, { "1bias", "set bias for 2nd plane", OFFSET(bias[1]), AV_OPT_TYPE_FLOAT, {.dbl=0.0}, 0.0, INT_MAX, FLAGS}, { "2bias", "set bias for 3rd plane", OFFSET(bias[2]), AV_OPT_TYPE_FLOAT, {.dbl=0.0}, 0.0, INT_MAX, FLAGS}, { "3bias", "set bias for 4th plane", OFFSET(bias[3]), AV_OPT_TYPE_FLOAT, {.dbl=0.0}, 0.0, INT_MAX, FLAGS}, + { "0mode", "set matrix mode for 1st plane", OFFSET(mode[0]), AV_OPT_TYPE_INT, {.i64=MATRIX_SQUARE}, 0, MATRIX_NBMODES-1, FLAGS, "mode" }, + { "1mode", "set matrix mode for 2nd plane", OFFSET(mode[1]), AV_OPT_TYPE_INT, {.i64=MATRIX_SQUARE}, 0, MATRIX_NBMODES-1, FLAGS, "mode" }, + { "2mode", "set matrix mode for 3rd plane", OFFSET(mode[2]), AV_OPT_TYPE_INT, {.i64=MATRIX_SQUARE}, 0, MATRIX_NBMODES-1, FLAGS, "mode" }, + { "3mode", "set matrix mode for 4th plane", OFFSET(mode[3]), AV_OPT_TYPE_INT, {.i64=MATRIX_SQUARE}, 0, MATRIX_NBMODES-1, FLAGS, "mode" }, + { "square", "square matrix", 0, AV_OPT_TYPE_CONST, {.i64=MATRIX_SQUARE}, 0, 0, FLAGS, "mode" }, + { "row", "single row matrix", 0, AV_OPT_TYPE_CONST, {.i64=MATRIX_ROW} , 0, 0, FLAGS, "mode" }, + { "column", "single column matrix", 0, AV_OPT_TYPE_CONST, {.i64=MATRIX_COLUMN}, 0, 0, FLAGS, "mode" }, { NULL } }; @@ -113,750 +132,460 @@ static int query_formats(AVFilterContext *ctx) AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRP9, AV_PIX_FMT_GBRP10, AV_PIX_FMT_GBRP12, AV_PIX_FMT_GBRP14, AV_PIX_FMT_GBRP16, AV_PIX_FMT_GBRAP, AV_PIX_FMT_GBRAP10, AV_PIX_FMT_GBRAP12, AV_PIX_FMT_GBRAP16, - AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY9, AV_PIX_FMT_GRAY10, AV_PIX_FMT_GRAY12, AV_PIX_FMT_GRAY16, + AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY9, AV_PIX_FMT_GRAY10, AV_PIX_FMT_GRAY12, AV_PIX_FMT_GRAY14, AV_PIX_FMT_GRAY16, AV_PIX_FMT_NONE }; return ff_set_common_formats(ctx, ff_make_format_list(pix_fmts)); } -static inline void line_copy8(uint8_t *line, const uint8_t *srcp, int width, int mergin) -{ - int i; - - memcpy(line, srcp, width); - - for (i = mergin; i > 0; i--) { - line[-i] = line[i]; - line[width - 1 + i] = line[width - 1 - i]; - } -} - -static inline void line_copy16(uint16_t *line, const uint16_t *srcp, int width, int mergin) -{ - int i; - - memcpy(line, srcp, width * 2); - - for (i = mergin; i > 0; i--) { - line[-i] = line[i]; - line[width - 1 + i] = line[width - 1 - i]; - } -} - typedef struct ThreadData { AVFrame *in, *out; - int plane; } ThreadData; -static int filter16_prewitt(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) +static void filter16_prewitt(uint8_t *dstp, int width, + float scale, float delta, const int *const matrix, + const uint8_t *c[], int peak, int radius, + int dstride, int stride) { - ConvolutionContext *s = ctx->priv; - ThreadData *td = arg; - AVFrame *in = td->in; - AVFrame *out = td->out; - const int plane = td->plane; - const int peak = (1 << s->depth) - 1; - const int stride = in->linesize[plane] / 2; - const int bstride = s->bstride; - const int height = s->planeheight[plane]; - const int width = s->planewidth[plane]; - const int slice_start = (height * jobnr) / nb_jobs; - const int slice_end = (height * (jobnr+1)) / nb_jobs; - const uint16_t *src = (const uint16_t *)in->data[plane] + slice_start * stride; - uint16_t *dst = (uint16_t *)out->data[plane] + slice_start * (out->linesize[plane] / 2); - const float scale = s->scale; - const float delta = s->delta; - uint16_t *p0 = (uint16_t *)s->bptrs[jobnr] + 16; - uint16_t *p1 = p0 + bstride; - uint16_t *p2 = p1 + bstride; - uint16_t *orig = p0, *end = p2; - int y, x; + uint16_t *dst = (uint16_t *)dstp; + int x; - line_copy16(p0, src + stride * (slice_start == 0 ? 1 : -1), width, 1); - line_copy16(p1, src, width, 1); + for (x = 0; x < width; x++) { + int suma = AV_RN16A(&c[0][2 * x]) * -1 + AV_RN16A(&c[1][2 * x]) * -1 + AV_RN16A(&c[2][2 * x]) * -1 + + AV_RN16A(&c[6][2 * x]) * 1 + AV_RN16A(&c[7][2 * x]) * 1 + AV_RN16A(&c[8][2 * x]) * 1; + int sumb = AV_RN16A(&c[0][2 * x]) * -1 + AV_RN16A(&c[2][2 * x]) * 1 + AV_RN16A(&c[3][2 * x]) * -1 + + AV_RN16A(&c[5][2 * x]) * 1 + AV_RN16A(&c[6][2 * x]) * -1 + AV_RN16A(&c[8][2 * x]) * 1; - for (y = slice_start; y < slice_end; y++) { - src += stride * (y < height - 1 ? 1 : -1); - line_copy16(p2, src, width, 1); - - for (x = 0; x < width; x++) { - int suma = p0[x - 1] * -1 + - p0[x] * -1 + - p0[x + 1] * -1 + - p2[x - 1] * 1 + - p2[x] * 1 + - p2[x + 1] * 1; - int sumb = p0[x - 1] * -1 + - p0[x + 1] * 1 + - p1[x - 1] * -1 + - p1[x + 1] * 1 + - p2[x - 1] * -1 + - p2[x + 1] * 1; - - dst[x] = av_clip(sqrt(suma*suma + sumb*sumb) * scale + delta, 0, peak); - } - - p0 = p1; - p1 = p2; - p2 = (p2 == end) ? orig: p2 + bstride; - dst += out->linesize[plane] / 2; + dst[x] = av_clip(sqrtf(suma*suma + sumb*sumb) * scale + delta, 0, peak); } - - return 0; } -static int filter16_roberts(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) +static void filter16_roberts(uint8_t *dstp, int width, + float scale, float delta, const int *const matrix, + const uint8_t *c[], int peak, int radius, + int dstride, int stride) { - ConvolutionContext *s = ctx->priv; - ThreadData *td = arg; - AVFrame *in = td->in; - AVFrame *out = td->out; - const int plane = td->plane; - const int peak = (1 << s->depth) - 1; - const int stride = in->linesize[plane] / 2; - const int bstride = s->bstride; - const int height = s->planeheight[plane]; - const int width = s->planewidth[plane]; - const int slice_start = (height * jobnr) / nb_jobs; - const int slice_end = (height * (jobnr+1)) / nb_jobs; - const uint16_t *src = (const uint16_t *)in->data[plane] + slice_start * stride; - uint16_t *dst = (uint16_t *)out->data[plane] + slice_start * (out->linesize[plane] / 2); - const float scale = s->scale; - const float delta = s->delta; - uint16_t *p0 = (uint16_t *)s->bptrs[jobnr] + 16; - uint16_t *p1 = p0 + bstride; - uint16_t *p2 = p1 + bstride; - uint16_t *orig = p0, *end = p2; - int y, x; + uint16_t *dst = (uint16_t *)dstp; + int x; - line_copy16(p0, src + stride * (slice_start == 0 ? 1 : -1), width, 1); - line_copy16(p1, src, width, 1); + for (x = 0; x < width; x++) { + int suma = AV_RN16A(&c[0][2 * x]) * 1 + AV_RN16A(&c[1][2 * x]) * -1; + int sumb = AV_RN16A(&c[4][2 * x]) * 1 + AV_RN16A(&c[3][2 * x]) * -1; - for (y = slice_start; y < slice_end; y++) { - src += stride * (y < height - 1 ? 1 : -1); - line_copy16(p2, src, width, 1); - - for (x = 0; x < width; x++) { - int suma = p0[x - 1] * 1 + - p1[x ] * -1; - int sumb = p0[x ] * 1 + - p1[x - 1] * -1; - - dst[x] = av_clip(sqrt(suma*suma + sumb*sumb) * scale + delta, 0, peak); - } - - p0 = p1; - p1 = p2; - p2 = (p2 == end) ? orig: p2 + bstride; - dst += out->linesize[plane] / 2; + dst[x] = av_clip(sqrtf(suma*suma + sumb*sumb) * scale + delta, 0, peak); } - - return 0; } -static int filter16_sobel(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) +static void filter16_sobel(uint8_t *dstp, int width, + float scale, float delta, const int *const matrix, + const uint8_t *c[], int peak, int radius, + int dstride, int stride) { - ConvolutionContext *s = ctx->priv; - ThreadData *td = arg; - AVFrame *in = td->in; - AVFrame *out = td->out; - const int plane = td->plane; - const int peak = (1 << s->depth) - 1; - const int stride = in->linesize[plane] / 2; - const int bstride = s->bstride; - const int height = s->planeheight[plane]; - const int width = s->planewidth[plane]; - const int slice_start = (height * jobnr) / nb_jobs; - const int slice_end = (height * (jobnr+1)) / nb_jobs; - const uint16_t *src = (const uint16_t *)in->data[plane] + slice_start * stride; - uint16_t *dst = (uint16_t *)out->data[plane] + slice_start * (out->linesize[plane] / 2); - const float scale = s->scale; - const float delta = s->delta; - uint16_t *p0 = (uint16_t *)s->bptrs[jobnr] + 16; - uint16_t *p1 = p0 + bstride; - uint16_t *p2 = p1 + bstride; - uint16_t *orig = p0, *end = p2; - int y, x; + uint16_t *dst = (uint16_t *)dstp; + int x; - line_copy16(p0, src + stride * (slice_start == 0 ? 1 : -1), width, 1); - line_copy16(p1, src, width, 1); + for (x = 0; x < width; x++) { + int suma = AV_RN16A(&c[0][2 * x]) * -1 + AV_RN16A(&c[1][2 * x]) * -2 + AV_RN16A(&c[2][2 * x]) * -1 + + AV_RN16A(&c[6][2 * x]) * 1 + AV_RN16A(&c[7][2 * x]) * 2 + AV_RN16A(&c[8][2 * x]) * 1; + int sumb = AV_RN16A(&c[0][2 * x]) * -1 + AV_RN16A(&c[2][2 * x]) * 1 + AV_RN16A(&c[3][2 * x]) * -2 + + AV_RN16A(&c[5][2 * x]) * 2 + AV_RN16A(&c[6][2 * x]) * -1 + AV_RN16A(&c[8][2 * x]) * 1; - for (y = slice_start; y < slice_end; y++) { - src += stride * (y < height - 1 ? 1 : -1); - line_copy16(p2, src, width, 1); - - for (x = 0; x < width; x++) { - int suma = p0[x - 1] * -1 + - p0[x] * -2 + - p0[x + 1] * -1 + - p2[x - 1] * 1 + - p2[x] * 2 + - p2[x + 1] * 1; - int sumb = p0[x - 1] * -1 + - p0[x + 1] * 1 + - p1[x - 1] * -2 + - p1[x + 1] * 2 + - p2[x - 1] * -1 + - p2[x + 1] * 1; - - dst[x] = av_clip(sqrt(suma*suma + sumb*sumb) * scale + delta, 0, peak); - } - - p0 = p1; - p1 = p2; - p2 = (p2 == end) ? orig: p2 + bstride; - dst += out->linesize[plane] / 2; + dst[x] = av_clip(sqrtf(suma*suma + sumb*sumb) * scale + delta, 0, peak); } - - return 0; } -static int filter_prewitt(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) +static void filter_prewitt(uint8_t *dst, int width, + float scale, float delta, const int *const matrix, + const uint8_t *c[], int peak, int radius, + int dstride, int stride) { - ConvolutionContext *s = ctx->priv; - ThreadData *td = arg; - AVFrame *in = td->in; - AVFrame *out = td->out; - const int plane = td->plane; - const int stride = in->linesize[plane]; - const int bstride = s->bstride; - const int height = s->planeheight[plane]; - const int width = s->planewidth[plane]; - const int slice_start = (height * jobnr) / nb_jobs; - const int slice_end = (height * (jobnr+1)) / nb_jobs; - const uint8_t *src = in->data[plane] + slice_start * stride; - uint8_t *dst = out->data[plane] + slice_start * out->linesize[plane]; - const float scale = s->scale; - const float delta = s->delta; - uint8_t *p0 = s->bptrs[jobnr] + 16; - uint8_t *p1 = p0 + bstride; - uint8_t *p2 = p1 + bstride; - uint8_t *orig = p0, *end = p2; - int y, x; + const uint8_t *c0 = c[0], *c1 = c[1], *c2 = c[2]; + const uint8_t *c3 = c[3], *c5 = c[5]; + const uint8_t *c6 = c[6], *c7 = c[7], *c8 = c[8]; + int x; - line_copy8(p0, src + stride * (slice_start == 0 ? 1 : -1), width, 1); - line_copy8(p1, src, width, 1); + for (x = 0; x < width; x++) { + int suma = c0[x] * -1 + c1[x] * -1 + c2[x] * -1 + + c6[x] * 1 + c7[x] * 1 + c8[x] * 1; + int sumb = c0[x] * -1 + c2[x] * 1 + c3[x] * -1 + + c5[x] * 1 + c6[x] * -1 + c8[x] * 1; - for (y = slice_start; y < slice_end; y++) { - src += stride * (y < height - 1 ? 1 : -1); - line_copy8(p2, src, width, 1); - - for (x = 0; x < width; x++) { - int suma = p0[x - 1] * -1 + - p0[x] * -1 + - p0[x + 1] * -1 + - p2[x - 1] * 1 + - p2[x] * 1 + - p2[x + 1] * 1; - int sumb = p0[x - 1] * -1 + - p0[x + 1] * 1 + - p1[x - 1] * -1 + - p1[x + 1] * 1 + - p2[x - 1] * -1 + - p2[x + 1] * 1; - - dst[x] = av_clip_uint8(sqrt(suma*suma + sumb*sumb) * scale + delta); - } - - p0 = p1; - p1 = p2; - p2 = (p2 == end) ? orig: p2 + bstride; - dst += out->linesize[plane]; + dst[x] = av_clip_uint8(sqrtf(suma*suma + sumb*sumb) * scale + delta); } - - return 0; } -static int filter_roberts(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) +static void filter_roberts(uint8_t *dst, int width, + float scale, float delta, const int *const matrix, + const uint8_t *c[], int peak, int radius, + int dstride, int stride) { - ConvolutionContext *s = ctx->priv; - ThreadData *td = arg; - AVFrame *in = td->in; - AVFrame *out = td->out; - const int plane = td->plane; - const int stride = in->linesize[plane]; - const int bstride = s->bstride; - const int height = s->planeheight[plane]; - const int width = s->planewidth[plane]; - const int slice_start = (height * jobnr) / nb_jobs; - const int slice_end = (height * (jobnr+1)) / nb_jobs; - const uint8_t *src = in->data[plane] + slice_start * stride; - uint8_t *dst = out->data[plane] + slice_start * out->linesize[plane]; - const float scale = s->scale; - const float delta = s->delta; - uint8_t *p0 = s->bptrs[jobnr] + 16; - uint8_t *p1 = p0 + bstride; - uint8_t *p2 = p1 + bstride; - uint8_t *orig = p0, *end = p2; - int y, x; + int x; - line_copy8(p0, src + stride * (slice_start == 0 ? 1 : -1), width, 1); - line_copy8(p1, src, width, 1); + for (x = 0; x < width; x++) { + int suma = c[0][x] * 1 + c[1][x] * -1; + int sumb = c[4][x] * 1 + c[3][x] * -1; - for (y = slice_start; y < slice_end; y++) { - src += stride * (y < height - 1 ? 1 : -1); - line_copy8(p2, src, width, 1); - - for (x = 0; x < width; x++) { - int suma = p0[x - 1] * 1 + - p1[x ] * -1; - int sumb = p0[x ] * 1 + - p1[x - 1] * -1; - - dst[x] = av_clip_uint8(sqrt(suma*suma + sumb*sumb) * scale + delta); - } - - p0 = p1; - p1 = p2; - p2 = (p2 == end) ? orig: p2 + bstride; - dst += out->linesize[plane]; + dst[x] = av_clip_uint8(sqrtf(suma*suma + sumb*sumb) * scale + delta); } - - return 0; } -static int filter_sobel(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) +static void filter_sobel(uint8_t *dst, int width, + float scale, float delta, const int *const matrix, + const uint8_t *c[], int peak, int radius, + int dstride, int stride) { - ConvolutionContext *s = ctx->priv; - ThreadData *td = arg; - AVFrame *in = td->in; - AVFrame *out = td->out; - const int plane = td->plane; - const int stride = in->linesize[plane]; - const int bstride = s->bstride; - const int height = s->planeheight[plane]; - const int width = s->planewidth[plane]; - const int slice_start = (height * jobnr) / nb_jobs; - const int slice_end = (height * (jobnr+1)) / nb_jobs; - const uint8_t *src = in->data[plane] + slice_start * stride; - uint8_t *dst = out->data[plane] + slice_start * out->linesize[plane]; - const float scale = s->scale; - const float delta = s->delta; - uint8_t *p0 = s->bptrs[jobnr] + 16; - uint8_t *p1 = p0 + bstride; - uint8_t *p2 = p1 + bstride; - uint8_t *orig = p0, *end = p2; - int y, x; + const uint8_t *c0 = c[0], *c1 = c[1], *c2 = c[2]; + const uint8_t *c3 = c[3], *c5 = c[5]; + const uint8_t *c6 = c[6], *c7 = c[7], *c8 = c[8]; + int x; - line_copy8(p0, src + stride * (slice_start == 0 ? 1 : -1), width, 1); - line_copy8(p1, src, width, 1); + for (x = 0; x < width; x++) { + int suma = c0[x] * -1 + c1[x] * -2 + c2[x] * -1 + + c6[x] * 1 + c7[x] * 2 + c8[x] * 1; + int sumb = c0[x] * -1 + c2[x] * 1 + c3[x] * -2 + + c5[x] * 2 + c6[x] * -1 + c8[x] * 1; - for (y = slice_start; y < slice_end; y++) { - src += stride * (y < height - 1 ? 1 : -1); - line_copy8(p2, src, width, 1); - - for (x = 0; x < width; x++) { - int suma = p0[x - 1] * -1 + - p0[x] * -2 + - p0[x + 1] * -1 + - p2[x - 1] * 1 + - p2[x] * 2 + - p2[x + 1] * 1; - int sumb = p0[x - 1] * -1 + - p0[x + 1] * 1 + - p1[x - 1] * -2 + - p1[x + 1] * 2 + - p2[x - 1] * -1 + - p2[x + 1] * 1; - - dst[x] = av_clip_uint8(sqrt(suma*suma + sumb*sumb) * scale + delta); - } - - p0 = p1; - p1 = p2; - p2 = (p2 == end) ? orig: p2 + bstride; - dst += out->linesize[plane]; + dst[x] = av_clip_uint8(sqrtf(suma*suma + sumb*sumb) * scale + delta); } - - return 0; } -static int filter16_3x3(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) +static void filter16_3x3(uint8_t *dstp, int width, + float rdiv, float bias, const int *const matrix, + const uint8_t *c[], int peak, int radius, + int dstride, int stride) { - ConvolutionContext *s = ctx->priv; - ThreadData *td = arg; - AVFrame *in = td->in; - AVFrame *out = td->out; - const int plane = td->plane; - const int peak = (1 << s->depth) - 1; - const int stride = in->linesize[plane] / 2; - const int bstride = s->bstride; - const int height = s->planeheight[plane]; - const int width = s->planewidth[plane]; - const int slice_start = (height * jobnr) / nb_jobs; - const int slice_end = (height * (jobnr+1)) / nb_jobs; - const uint16_t *src = (const uint16_t *)in->data[plane] + slice_start * stride; - uint16_t *dst = (uint16_t *)out->data[plane] + slice_start * (out->linesize[plane] / 2); - uint16_t *p0 = (uint16_t *)s->bptrs[jobnr] + 16; - uint16_t *p1 = p0 + bstride; - uint16_t *p2 = p1 + bstride; - uint16_t *orig = p0, *end = p2; - const int *matrix = s->matrix[plane]; - const float rdiv = s->rdiv[plane]; - const float bias = s->bias[plane]; - int y, x; + uint16_t *dst = (uint16_t *)dstp; + int x; - line_copy16(p0, src + stride * (slice_start == 0 ? 1 : -1), width, 1); - line_copy16(p1, src, width, 1); - - for (y = slice_start; y < slice_end; y++) { - src += stride * (y < height - 1 ? 1 : -1); - line_copy16(p2, src, width, 1); - - for (x = 0; x < width; x++) { - int sum = p0[x - 1] * matrix[0] + - p0[x] * matrix[1] + - p0[x + 1] * matrix[2] + - p1[x - 1] * matrix[3] + - p1[x] * matrix[4] + - p1[x + 1] * matrix[5] + - p2[x - 1] * matrix[6] + - p2[x] * matrix[7] + - p2[x + 1] * matrix[8]; - sum = (int)(sum * rdiv + bias + 0.5f); - dst[x] = av_clip(sum, 0, peak); - } - - p0 = p1; - p1 = p2; - p2 = (p2 == end) ? orig: p2 + bstride; - dst += out->linesize[plane] / 2; + for (x = 0; x < width; x++) { + int sum = AV_RN16A(&c[0][2 * x]) * matrix[0] + + AV_RN16A(&c[1][2 * x]) * matrix[1] + + AV_RN16A(&c[2][2 * x]) * matrix[2] + + AV_RN16A(&c[3][2 * x]) * matrix[3] + + AV_RN16A(&c[4][2 * x]) * matrix[4] + + AV_RN16A(&c[5][2 * x]) * matrix[5] + + AV_RN16A(&c[6][2 * x]) * matrix[6] + + AV_RN16A(&c[7][2 * x]) * matrix[7] + + AV_RN16A(&c[8][2 * x]) * matrix[8]; + sum = (int)(sum * rdiv + bias + 0.5f); + dst[x] = av_clip(sum, 0, peak); } - - return 0; } -static int filter16_5x5(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) +static void filter16_5x5(uint8_t *dstp, int width, + float rdiv, float bias, const int *const matrix, + const uint8_t *c[], int peak, int radius, + int dstride, int stride) +{ + uint16_t *dst = (uint16_t *)dstp; + int x; + + for (x = 0; x < width; x++) { + int i, sum = 0; + + for (i = 0; i < 25; i++) + sum += AV_RN16A(&c[i][2 * x]) * matrix[i]; + + sum = (int)(sum * rdiv + bias + 0.5f); + dst[x] = av_clip(sum, 0, peak); + } +} + +static void filter16_7x7(uint8_t *dstp, int width, + float rdiv, float bias, const int *const matrix, + const uint8_t *c[], int peak, int radius, + int dstride, int stride) +{ + uint16_t *dst = (uint16_t *)dstp; + int x; + + for (x = 0; x < width; x++) { + int i, sum = 0; + + for (i = 0; i < 49; i++) + sum += AV_RN16A(&c[i][2 * x]) * matrix[i]; + + sum = (int)(sum * rdiv + bias + 0.5f); + dst[x] = av_clip(sum, 0, peak); + } +} + +static void filter16_row(uint8_t *dstp, int width, + float rdiv, float bias, const int *const matrix, + const uint8_t *c[], int peak, int radius, + int dstride, int stride) +{ + uint16_t *dst = (uint16_t *)dstp; + int x; + + for (x = 0; x < width; x++) { + int i, sum = 0; + + for (i = 0; i < 2 * radius + 1; i++) + sum += AV_RN16A(&c[i][2 * x]) * matrix[i]; + + sum = (int)(sum * rdiv + bias + 0.5f); + dst[x] = av_clip(sum, 0, peak); + } +} + +static void filter16_column(uint8_t *dstp, int height, + float rdiv, float bias, const int *const matrix, + const uint8_t *c[], int peak, int radius, + int dstride, int stride) +{ + uint16_t *dst = (uint16_t *)dstp; + int y; + + for (y = 0; y < height; y++) { + int i, sum = 0; + + for (i = 0; i < 2 * radius + 1; i++) + sum += AV_RN16A(&c[i][0 + y * stride]) * matrix[i]; + + sum = (int)(sum * rdiv + bias + 0.5f); + dst[0] = av_clip(sum, 0, peak); + dst += dstride / 2; + } +} + +static void filter_7x7(uint8_t *dst, int width, + float rdiv, float bias, const int *const matrix, + const uint8_t *c[], int peak, int radius, + int dstride, int stride) +{ + int x; + + for (x = 0; x < width; x++) { + int i, sum = 0; + + for (i = 0; i < 49; i++) + sum += c[i][x] * matrix[i]; + + sum = (int)(sum * rdiv + bias + 0.5f); + dst[x] = av_clip_uint8(sum); + } +} + +static void filter_5x5(uint8_t *dst, int width, + float rdiv, float bias, const int *const matrix, + const uint8_t *c[], int peak, int radius, + int dstride, int stride) +{ + int x; + + for (x = 0; x < width; x++) { + int i, sum = 0; + + for (i = 0; i < 25; i++) + sum += c[i][x] * matrix[i]; + + sum = (int)(sum * rdiv + bias + 0.5f); + dst[x] = av_clip_uint8(sum); + } +} + +static void filter_3x3(uint8_t *dst, int width, + float rdiv, float bias, const int *const matrix, + const uint8_t *c[], int peak, int radius, + int dstride, int stride) +{ + const uint8_t *c0 = c[0], *c1 = c[1], *c2 = c[2]; + const uint8_t *c3 = c[3], *c4 = c[4], *c5 = c[5]; + const uint8_t *c6 = c[6], *c7 = c[7], *c8 = c[8]; + int x; + + for (x = 0; x < width; x++) { + int sum = c0[x] * matrix[0] + c1[x] * matrix[1] + c2[x] * matrix[2] + + c3[x] * matrix[3] + c4[x] * matrix[4] + c5[x] * matrix[5] + + c6[x] * matrix[6] + c7[x] * matrix[7] + c8[x] * matrix[8]; + sum = (int)(sum * rdiv + bias + 0.5f); + dst[x] = av_clip_uint8(sum); + } +} + +static void filter_row(uint8_t *dst, int width, + float rdiv, float bias, const int *const matrix, + const uint8_t *c[], int peak, int radius, + int dstride, int stride) +{ + int x; + + for (x = 0; x < width; x++) { + int i, sum = 0; + + for (i = 0; i < 2 * radius + 1; i++) + sum += c[i][x] * matrix[i]; + + sum = (int)(sum * rdiv + bias + 0.5f); + dst[x] = av_clip_uint8(sum); + } +} + +static void filter_column(uint8_t *dst, int height, + float rdiv, float bias, const int *const matrix, + const uint8_t *c[], int peak, int radius, + int dstride, int stride) +{ + int y; + + for (y = 0; y < height; y++) { + int i, sum = 0; + + for (i = 0; i < 2 * radius + 1; i++) + sum += c[i][0 + y * stride] * matrix[i]; + + sum = (int)(sum * rdiv + bias + 0.5f); + dst[0] = av_clip_uint8(sum); + dst += dstride; + } +} + +static void setup_3x3(int radius, const uint8_t *c[], const uint8_t *src, int stride, + int x, int w, int y, int h, int bpc) +{ + int i; + + for (i = 0; i < 9; i++) { + int xoff = FFABS(x + ((i % 3) - 1)); + int yoff = FFABS(y + (i / 3) - 1); + + xoff = xoff >= w ? 2 * w - 1 - xoff : xoff; + yoff = yoff >= h ? 2 * h - 1 - yoff : yoff; + + c[i] = src + xoff * bpc + yoff * stride; + } +} + +static void setup_5x5(int radius, const uint8_t *c[], const uint8_t *src, int stride, + int x, int w, int y, int h, int bpc) +{ + int i; + + for (i = 0; i < 25; i++) { + int xoff = FFABS(x + ((i % 5) - 2)); + int yoff = FFABS(y + (i / 5) - 2); + + xoff = xoff >= w ? 2 * w - 1 - xoff : xoff; + yoff = yoff >= h ? 2 * h - 1 - yoff : yoff; + + c[i] = src + xoff * bpc + yoff * stride; + } +} + +static void setup_7x7(int radius, const uint8_t *c[], const uint8_t *src, int stride, + int x, int w, int y, int h, int bpc) +{ + int i; + + for (i = 0; i < 49; i++) { + int xoff = FFABS(x + ((i % 7) - 3)); + int yoff = FFABS(y + (i / 7) - 3); + + xoff = xoff >= w ? 2 * w - 1 - xoff : xoff; + yoff = yoff >= h ? 2 * h - 1 - yoff : yoff; + + c[i] = src + xoff * bpc + yoff * stride; + } +} + +static void setup_row(int radius, const uint8_t *c[], const uint8_t *src, int stride, + int x, int w, int y, int h, int bpc) +{ + int i; + + for (i = 0; i < radius * 2 + 1; i++) { + int xoff = FFABS(x + i - radius); + + xoff = xoff >= w ? 2 * w - 1 - xoff : xoff; + + c[i] = src + xoff * bpc + y * stride; + } +} + +static void setup_column(int radius, const uint8_t *c[], const uint8_t *src, int stride, + int x, int w, int y, int h, int bpc) +{ + int i; + + for (i = 0; i < radius * 2 + 1; i++) { + int xoff = FFABS(x + i - radius); + + xoff = xoff >= h ? 2 * h - 1 - xoff : xoff; + + c[i] = src + y * bpc + xoff * stride; + } +} + +static int filter_slice(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) { ConvolutionContext *s = ctx->priv; ThreadData *td = arg; AVFrame *in = td->in; AVFrame *out = td->out; - const int plane = td->plane; - const int peak = (1 << s->depth) - 1; - const int stride = in->linesize[plane] / 2; - const int bstride = s->bstride; - const int height = s->planeheight[plane]; - const int width = s->planewidth[plane]; - const int slice_start = (height * jobnr) / nb_jobs; - const int slice_end = (height * (jobnr+1)) / nb_jobs; - const uint16_t *src = (const uint16_t *)in->data[plane] + slice_start * stride; - uint16_t *dst = (uint16_t *)out->data[plane] + slice_start * (out->linesize[plane] / 2); - uint16_t *p0 = (uint16_t *)s->bptrs[jobnr] + 16; - uint16_t *p1 = p0 + bstride; - uint16_t *p2 = p1 + bstride; - uint16_t *p3 = p2 + bstride; - uint16_t *p4 = p3 + bstride; - uint16_t *orig = p0, *end = p4; - const int *matrix = s->matrix[plane]; - float rdiv = s->rdiv[plane]; - float bias = s->bias[plane]; - int y, x, i; + int plane; - line_copy16(p0, src + 2 * stride * (slice_start < 2 ? 1 : -1), width, 2); - line_copy16(p1, src + stride * (slice_start == 0 ? 1 : -1), width, 2); - line_copy16(p2, src, width, 2); - src += stride; - line_copy16(p3, src, width, 2); + for (plane = 0; plane < s->nb_planes; plane++) { + const int mode = s->mode[plane]; + const int bpc = s->bpc; + const int radius = s->size[plane] / 2; + const int height = s->planeheight[plane]; + const int width = s->planewidth[plane]; + const int stride = in->linesize[plane]; + const int dstride = out->linesize[plane]; + const int sizeh = mode == MATRIX_COLUMN ? width : height; + const int sizew = mode == MATRIX_COLUMN ? height : width; + const int slice_start = (sizeh * jobnr) / nb_jobs; + const int slice_end = (sizeh * (jobnr+1)) / nb_jobs; + const float rdiv = s->rdiv[plane]; + const float bias = s->bias[plane]; + const uint8_t *src = in->data[plane]; + const int dst_pos = slice_start * (mode == MATRIX_COLUMN ? bpc : dstride); + uint8_t *dst = out->data[plane] + dst_pos; + const int *matrix = s->matrix[plane]; + const uint8_t *c[49]; + int y, x; - for (y = slice_start; y < slice_end; y++) { - uint16_t *array[] = { - p0 - 2, p0 - 1, p0, p0 + 1, p0 + 2, - p1 - 2, p1 - 1, p1, p1 + 1, p1 + 2, - p2 - 2, p2 - 1, p2, p2 + 1, p2 + 2, - p3 - 2, p3 - 1, p3, p3 + 1, p3 + 2, - p4 - 2, p4 - 1, p4, p4 + 1, p4 + 2 - }; + if (s->copy[plane]) { + if (mode == MATRIX_COLUMN) + av_image_copy_plane(dst, dstride, src + slice_start * bpc, stride, + (slice_end - slice_start) * bpc, height); + else + av_image_copy_plane(dst, dstride, src + slice_start * stride, stride, + width * bpc, slice_end - slice_start); + continue; + } - src += stride * (y < height - 2 ? 1 : -1); - line_copy16(p4, src, width, 2); + for (y = slice_start; y < slice_end; y++) { + const int xoff = mode == MATRIX_COLUMN ? (y - slice_start) * bpc : radius * bpc; + const int yoff = mode == MATRIX_COLUMN ? radius * stride : 0; - for (x = 0; x < width; x++) { - int sum = 0; + for (x = 0; x < radius; x++) { + const int xoff = mode == MATRIX_COLUMN ? (y - slice_start) * bpc : x * bpc; + const int yoff = mode == MATRIX_COLUMN ? x * stride : 0; - for (i = 0; i < 25; i++) { - sum += *(array[i] + x) * matrix[i]; + s->setup[plane](radius, c, src, stride, x, width, y, height, bpc); + s->filter[plane](dst + yoff + xoff, 1, rdiv, + bias, matrix, c, s->max, radius, + dstride, stride); } - sum = (int)(sum * rdiv + bias + 0.5f); - dst[x] = av_clip(sum, 0, peak); - } + s->setup[plane](radius, c, src, stride, radius, width, y, height, bpc); + s->filter[plane](dst + yoff + xoff, sizew - 2 * radius, + rdiv, bias, matrix, c, s->max, radius, + dstride, stride); + for (x = sizew - radius; x < sizew; x++) { + const int xoff = mode == MATRIX_COLUMN ? (y - slice_start) * bpc : x * bpc; + const int yoff = mode == MATRIX_COLUMN ? x * stride : 0; - p0 = p1; - p1 = p2; - p2 = p3; - p3 = p4; - p4 = (p4 == end) ? orig: p4 + bstride; - dst += out->linesize[plane] / 2; - } - - return 0; -} - -static int filter16_7x7(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) -{ - ConvolutionContext *s = ctx->priv; - ThreadData *td = arg; - AVFrame *in = td->in; - AVFrame *out = td->out; - const int plane = td->plane; - const int peak = (1 << s->depth) - 1; - const int stride = in->linesize[plane] / 2; - const int bstride = s->bstride; - const int height = s->planeheight[plane]; - const int width = s->planewidth[plane]; - const int slice_start = (height * jobnr) / nb_jobs; - const int slice_end = (height * (jobnr+1)) / nb_jobs; - const uint16_t *src = (const uint16_t *)in->data[plane] + slice_start * stride; - uint16_t *dst = (uint16_t *)out->data[plane] + slice_start * (out->linesize[plane] / 2); - uint16_t *p0 = (uint16_t *)s->bptrs[jobnr] + 32; - uint16_t *p1 = p0 + bstride; - uint16_t *p2 = p1 + bstride; - uint16_t *p3 = p2 + bstride; - uint16_t *p4 = p3 + bstride; - uint16_t *p5 = p4 + bstride; - uint16_t *p6 = p5 + bstride; - uint16_t *orig = p0, *end = p6; - const int *matrix = s->matrix[plane]; - float rdiv = s->rdiv[plane]; - float bias = s->bias[plane]; - int y, x, i; - - line_copy16(p0, src + 3 * stride * (slice_start < 3 ? 1 : -1), width, 3); - line_copy16(p1, src + 2 * stride * (slice_start < 2 ? 1 : -1), width, 3); - line_copy16(p2, src + stride * (slice_start == 0 ? 1 : -1), width, 3); - line_copy16(p3, src, width, 3); - src += stride; - line_copy16(p4, src, width, 3); - src += stride; - line_copy16(p5, src, width, 3); - - for (y = slice_start; y < slice_end; y++) { - uint16_t *array[] = { - p0 - 3, p0 - 2, p0 - 1, p0, p0 + 1, p0 + 2, p0 + 3, - p1 - 3, p1 - 2, p1 - 1, p1, p1 + 1, p1 + 2, p1 + 3, - p2 - 3, p2 - 2, p2 - 1, p2, p2 + 1, p2 + 2, p2 + 3, - p3 - 3, p3 - 2, p3 - 1, p3, p3 + 1, p3 + 2, p3 + 3, - p4 - 3, p4 - 2, p4 - 1, p4, p4 + 1, p4 + 2, p4 + 3, - p5 - 3, p5 - 2, p5 - 1, p5, p5 + 1, p5 + 2, p5 + 3, - p6 - 3, p6 - 2, p6 - 1, p6, p6 + 1, p6 + 2, p6 + 3, - }; - - src += stride * (y < height - 3 ? 1 : -1); - line_copy16(p6, src, width, 3); - - for (x = 0; x < width; x++) { - int sum = 0; - - for (i = 0; i < 25; i++) { - sum += *(array[i] + x) * matrix[i]; + s->setup[plane](radius, c, src, stride, x, width, y, height, bpc); + s->filter[plane](dst + yoff + xoff, 1, rdiv, + bias, matrix, c, s->max, radius, + dstride, stride); } - sum = (int)(sum * rdiv + bias + 0.5f); - dst[x] = av_clip(sum, 0, peak); + if (mode != MATRIX_COLUMN) + dst += dstride; } - - p0 = p1; - p1 = p2; - p2 = p3; - p3 = p4; - p4 = p5; - p5 = p6; - p6 = (p6 == end) ? orig: p6 + bstride; - dst += out->linesize[plane] / 2; - } - - return 0; -} - -static int filter_3x3(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) -{ - ConvolutionContext *s = ctx->priv; - ThreadData *td = arg; - AVFrame *in = td->in; - AVFrame *out = td->out; - const int plane = td->plane; - const int stride = in->linesize[plane]; - const int bstride = s->bstride; - const int height = s->planeheight[plane]; - const int width = s->planewidth[plane]; - const int slice_start = (height * jobnr) / nb_jobs; - const int slice_end = (height * (jobnr+1)) / nb_jobs; - const uint8_t *src = in->data[plane] + slice_start * stride; - uint8_t *dst = out->data[plane] + slice_start * out->linesize[plane]; - uint8_t *p0 = s->bptrs[jobnr] + 16; - uint8_t *p1 = p0 + bstride; - uint8_t *p2 = p1 + bstride; - uint8_t *orig = p0, *end = p2; - const int *matrix = s->matrix[plane]; - const float rdiv = s->rdiv[plane]; - const float bias = s->bias[plane]; - int y, x; - - line_copy8(p0, src + stride * (slice_start == 0 ? 1 : -1), width, 1); - line_copy8(p1, src, width, 1); - - for (y = slice_start; y < slice_end; y++) { - src += stride * (y < height - 1 ? 1 : -1); - line_copy8(p2, src, width, 1); - - for (x = 0; x < width; x++) { - int sum = p0[x - 1] * matrix[0] + - p0[x] * matrix[1] + - p0[x + 1] * matrix[2] + - p1[x - 1] * matrix[3] + - p1[x] * matrix[4] + - p1[x + 1] * matrix[5] + - p2[x - 1] * matrix[6] + - p2[x] * matrix[7] + - p2[x + 1] * matrix[8]; - sum = (int)(sum * rdiv + bias + 0.5f); - dst[x] = av_clip_uint8(sum); - } - - p0 = p1; - p1 = p2; - p2 = (p2 == end) ? orig: p2 + bstride; - dst += out->linesize[plane]; - } - - return 0; -} - -static int filter_5x5(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) -{ - ConvolutionContext *s = ctx->priv; - ThreadData *td = arg; - AVFrame *in = td->in; - AVFrame *out = td->out; - const int plane = td->plane; - const int stride = in->linesize[plane]; - const int bstride = s->bstride; - const int height = s->planeheight[plane]; - const int width = s->planewidth[plane]; - const int slice_start = (height * jobnr) / nb_jobs; - const int slice_end = (height * (jobnr+1)) / nb_jobs; - const uint8_t *src = in->data[plane] + slice_start * stride; - uint8_t *dst = out->data[plane] + slice_start * out->linesize[plane]; - uint8_t *p0 = s->bptrs[jobnr] + 16; - uint8_t *p1 = p0 + bstride; - uint8_t *p2 = p1 + bstride; - uint8_t *p3 = p2 + bstride; - uint8_t *p4 = p3 + bstride; - uint8_t *orig = p0, *end = p4; - const int *matrix = s->matrix[plane]; - float rdiv = s->rdiv[plane]; - float bias = s->bias[plane]; - int y, x, i; - - line_copy8(p0, src + 2 * stride * (slice_start < 2 ? 1 : -1), width, 2); - line_copy8(p1, src + stride * (slice_start == 0 ? 1 : -1), width, 2); - line_copy8(p2, src, width, 2); - src += stride; - line_copy8(p3, src, width, 2); - - - for (y = slice_start; y < slice_end; y++) { - uint8_t *array[] = { - p0 - 2, p0 - 1, p0, p0 + 1, p0 + 2, - p1 - 2, p1 - 1, p1, p1 + 1, p1 + 2, - p2 - 2, p2 - 1, p2, p2 + 1, p2 + 2, - p3 - 2, p3 - 1, p3, p3 + 1, p3 + 2, - p4 - 2, p4 - 1, p4, p4 + 1, p4 + 2 - }; - - src += stride * (y < height - 2 ? 1 : -1); - line_copy8(p4, src, width, 2); - - for (x = 0; x < width; x++) { - int sum = 0; - - for (i = 0; i < 25; i++) { - sum += *(array[i] + x) * matrix[i]; - } - sum = (int)(sum * rdiv + bias + 0.5f); - dst[x] = av_clip_uint8(sum); - } - - p0 = p1; - p1 = p2; - p2 = p3; - p3 = p4; - p4 = (p4 == end) ? orig: p4 + bstride; - dst += out->linesize[plane]; - } - - return 0; -} - -static int filter_7x7(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) -{ - ConvolutionContext *s = ctx->priv; - ThreadData *td = arg; - AVFrame *in = td->in; - AVFrame *out = td->out; - const int plane = td->plane; - const int stride = in->linesize[plane]; - const int bstride = s->bstride; - const int height = s->planeheight[plane]; - const int width = s->planewidth[plane]; - const int slice_start = (height * jobnr) / nb_jobs; - const int slice_end = (height * (jobnr+1)) / nb_jobs; - const uint8_t *src = in->data[plane] + slice_start * stride; - uint8_t *dst = out->data[plane] + slice_start * out->linesize[plane]; - uint8_t *p0 = s->bptrs[jobnr] + 32; - uint8_t *p1 = p0 + bstride; - uint8_t *p2 = p1 + bstride; - uint8_t *p3 = p2 + bstride; - uint8_t *p4 = p3 + bstride; - uint8_t *p5 = p4 + bstride; - uint8_t *p6 = p5 + bstride; - uint8_t *orig = p0, *end = p6; - const int *matrix = s->matrix[plane]; - float rdiv = s->rdiv[plane]; - float bias = s->bias[plane]; - int y, x, i; - - line_copy8(p0, src + 3 * stride * (slice_start < 3 ? 1 : -1), width, 3); - line_copy8(p1, src + 2 * stride * (slice_start < 2 ? 1 : -1), width, 3); - line_copy8(p2, src + stride * (slice_start == 0 ? 1 : -1), width, 3); - line_copy8(p3, src, width, 3); - src += stride; - line_copy8(p4, src, width, 3); - src += stride; - line_copy8(p5, src, width, 3); - - for (y = slice_start; y < slice_end; y++) { - uint8_t *array[] = { - p0 - 3, p0 - 2, p0 - 1, p0, p0 + 1, p0 + 2, p0 + 3, - p1 - 3, p1 - 2, p1 - 1, p1, p1 + 1, p1 + 2, p1 + 3, - p2 - 3, p2 - 2, p2 - 1, p2, p2 + 1, p2 + 2, p2 + 3, - p3 - 3, p3 - 2, p3 - 1, p3, p3 + 1, p3 + 2, p3 + 3, - p4 - 3, p4 - 2, p4 - 1, p4, p4 + 1, p4 + 2, p4 + 3, - p5 - 3, p5 - 2, p5 - 1, p5, p5 + 1, p5 + 2, p5 + 3, - p6 - 3, p6 - 2, p6 - 1, p6, p6 + 1, p6 + 2, p6 + 3, - }; - - src += stride * (y < height - 3 ? 1 : -1); - line_copy8(p6, src, width, 3); - - for (x = 0; x < width; x++) { - int sum = 0; - - for (i = 0; i < 49; i++) { - sum += *(array[i] + x) * matrix[i]; - } - sum = (int)(sum * rdiv + bias + 0.5f); - dst[x] = av_clip_uint8(sum); - } - - p0 = p1; - p1 = p2; - p2 = p3; - p3 = p4; - p4 = p5; - p5 = p6; - p6 = (p6 == end) ? orig: p6 + bstride; - dst += out->linesize[plane]; } return 0; @@ -870,6 +599,7 @@ static int config_input(AVFilterLink *inlink) int p; s->depth = desc->comp[0].depth; + s->max = (1 << s->depth) - 1; s->planewidth[1] = s->planewidth[2] = AV_CEIL_RSHIFT(inlink->w, desc->log2_chroma_w); s->planewidth[0] = s->planewidth[3] = inlink->w; @@ -878,24 +608,16 @@ static int config_input(AVFilterLink *inlink) s->nb_planes = av_pix_fmt_count_planes(inlink->format); s->nb_threads = ff_filter_get_nb_threads(ctx); - s->bptrs = av_calloc(s->nb_threads, sizeof(*s->bptrs)); - if (!s->bptrs) - return AVERROR(ENOMEM); - - s->bstride = s->planewidth[0] + 64; s->bpc = (s->depth + 7) / 8; - s->buffer = av_malloc_array(7 * s->bstride * s->nb_threads, s->bpc); - if (!s->buffer) - return AVERROR(ENOMEM); - - for (p = 0; p < s->nb_threads; p++) { - s->bptrs[p] = s->buffer + 7 * s->bstride * s->bpc * p; - } if (!strcmp(ctx->filter->name, "convolution")) { if (s->depth > 8) { for (p = 0; p < s->nb_planes; p++) { - if (s->size[p] == 3) + if (s->mode[p] == MATRIX_ROW) + s->filter[p] = filter16_row; + else if (s->mode[p] == MATRIX_COLUMN) + s->filter[p] = filter16_column; + else if (s->size[p] == 3) s->filter[p] = filter16_3x3; else if (s->size[p] == 5) s->filter[p] = filter16_5x5; @@ -926,7 +648,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) ConvolutionContext *s = ctx->priv; AVFilterLink *outlink = ctx->outputs[0]; AVFrame *out; - int plane; + ThreadData td; out = ff_get_video_buffer(outlink, outlink->w, outlink->h); if (!out) { @@ -935,22 +657,9 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) } av_frame_copy_props(out, in); - for (plane = 0; plane < s->nb_planes; plane++) { - ThreadData td; - - if (s->copy[plane]) { - av_image_copy_plane(out->data[plane], out->linesize[plane], - in->data[plane], in->linesize[plane], - s->planewidth[plane] * s->bpc, - s->planeheight[plane]); - continue; - } - - td.in = in; - td.out = out; - td.plane = plane; - ctx->internal->execute(ctx, s->filter[plane], &td, NULL, FFMIN(s->planeheight[plane], s->nb_threads)); - } + td.in = in; + td.out = out; + ctx->internal->execute(ctx, filter_slice, &td, NULL, FFMIN3(s->planeheight[1], s->planewidth[1], s->nb_threads)); av_frame_free(&in); return ff_filter_frame(outlink, out); @@ -965,6 +674,7 @@ static av_cold int init(AVFilterContext *ctx) for (i = 0; i < 4; i++) { int *matrix = (int *)s->matrix[i]; char *p, *arg, *saveptr = NULL; + float sum = 0; p = s->matrix_str[i]; while (s->matrix_length[i] < 49) { @@ -973,31 +683,52 @@ static av_cold int init(AVFilterContext *ctx) p = NULL; sscanf(arg, "%d", &matrix[s->matrix_length[i]]); + sum += matrix[s->matrix_length[i]]; s->matrix_length[i]++; } - if (s->matrix_length[i] == 9) { + if (!(s->matrix_length[i] & 1)) { + av_log(ctx, AV_LOG_ERROR, "number of matrix elements must be odd\n"); + return AVERROR(EINVAL); + } + if (s->mode[i] == MATRIX_ROW) { + s->filter[i] = filter_row; + s->setup[i] = setup_row; + s->size[i] = s->matrix_length[i]; + } else if (s->mode[i] == MATRIX_COLUMN) { + s->filter[i] = filter_column; + s->setup[i] = setup_column; + s->size[i] = s->matrix_length[i]; + } else if (s->matrix_length[i] == 9) { s->size[i] = 3; if (!memcmp(matrix, same3x3, sizeof(same3x3))) s->copy[i] = 1; else s->filter[i] = filter_3x3; + s->setup[i] = setup_3x3; } else if (s->matrix_length[i] == 25) { s->size[i] = 5; if (!memcmp(matrix, same5x5, sizeof(same5x5))) s->copy[i] = 1; else s->filter[i] = filter_5x5; + s->setup[i] = setup_5x5; } else if (s->matrix_length[i] == 49) { s->size[i] = 7; if (!memcmp(matrix, same7x7, sizeof(same7x7))) s->copy[i] = 1; else s->filter[i] = filter_7x7; + s->setup[i] = setup_7x7; } else { return AVERROR(EINVAL); } + if (sum == 0) + sum = 1; + if (s->rdiv[i] == 0) + s->rdiv[i] = 1. / sum; + if (s->copy[i] && (s->rdiv[i] != 1. || s->bias[i] != 0.)) s->copy[i] = 0; } @@ -1007,6 +738,10 @@ static av_cold int init(AVFilterContext *ctx) s->filter[i] = filter_prewitt; else s->copy[i] = 1; + s->size[i] = 3; + s->setup[i] = setup_3x3; + s->rdiv[i] = s->scale; + s->bias[i] = s->delta; } } else if (!strcmp(ctx->filter->name, "roberts")) { for (i = 0; i < 4; i++) { @@ -1014,6 +749,10 @@ static av_cold int init(AVFilterContext *ctx) s->filter[i] = filter_roberts; else s->copy[i] = 1; + s->size[i] = 3; + s->setup[i] = setup_3x3; + s->rdiv[i] = s->scale; + s->bias[i] = s->delta; } } else if (!strcmp(ctx->filter->name, "sobel")) { for (i = 0; i < 4; i++) { @@ -1021,20 +760,16 @@ static av_cold int init(AVFilterContext *ctx) s->filter[i] = filter_sobel; else s->copy[i] = 1; + s->size[i] = 3; + s->setup[i] = setup_3x3; + s->rdiv[i] = s->scale; + s->bias[i] = s->delta; } } return 0; } -static av_cold void uninit(AVFilterContext *ctx) -{ - ConvolutionContext *s = ctx->priv; - - av_freep(&s->bptrs); - av_freep(&s->buffer); -} - static const AVFilterPad convolution_inputs[] = { { .name = "default", @@ -1061,7 +796,6 @@ AVFilter ff_vf_convolution = { .priv_size = sizeof(ConvolutionContext), .priv_class = &convolution_class, .init = init, - .uninit = uninit, .query_formats = query_formats, .inputs = convolution_inputs, .outputs = convolution_outputs, @@ -1087,7 +821,6 @@ AVFilter ff_vf_prewitt = { .priv_size = sizeof(ConvolutionContext), .priv_class = &prewitt_class, .init = init, - .uninit = uninit, .query_formats = query_formats, .inputs = convolution_inputs, .outputs = convolution_outputs, @@ -1113,7 +846,6 @@ AVFilter ff_vf_sobel = { .priv_size = sizeof(ConvolutionContext), .priv_class = &sobel_class, .init = init, - .uninit = uninit, .query_formats = query_formats, .inputs = convolution_inputs, .outputs = convolution_outputs, @@ -1139,7 +871,6 @@ AVFilter ff_vf_roberts = { .priv_size = sizeof(ConvolutionContext), .priv_class = &roberts_class, .init = init, - .uninit = uninit, .query_formats = query_formats, .inputs = convolution_inputs, .outputs = convolution_outputs, diff --git a/libavfilter/vf_convolution_opencl.c b/libavfilter/vf_convolution_opencl.c index 2df51e053..00246b2e4 100644 --- a/libavfilter/vf_convolution_opencl.c +++ b/libavfilter/vf_convolution_opencl.c @@ -47,12 +47,16 @@ typedef struct ConvolutionOpenCLContext { cl_float rdivs[4]; cl_float biases[4]; -} ConvolutionOpenCLContext; + cl_int planes; + cl_float scale; + cl_float delta; +} ConvolutionOpenCLContext; static int convolution_opencl_init(AVFilterContext *avctx) { ConvolutionOpenCLContext *ctx = avctx->priv; + const char *kernel_name; cl_int cle; int err; @@ -63,19 +67,21 @@ static int convolution_opencl_init(AVFilterContext *avctx) ctx->command_queue = clCreateCommandQueue(ctx->ocf.hwctx->context, ctx->ocf.hwctx->device_id, 0, &cle); - if (!ctx->command_queue) { - av_log(avctx, AV_LOG_ERROR, "Failed to create OpenCL " - "command queue: %d.\n", cle); - err = AVERROR(EIO); - goto fail; - } + CL_FAIL_ON_ERROR(AVERROR(EIO), "Failed to create OpenCL " + "command queue %d.\n", cle); - ctx->kernel = clCreateKernel(ctx->ocf.program, "convolution_global", &cle); - if (!ctx->kernel) { - av_log(avctx, AV_LOG_ERROR, "Failed to create kernel: %d.\n", cle); - err = AVERROR(EIO); - goto fail; + if (!strcmp(avctx->filter->name, "convolution_opencl")) { + kernel_name = "convolution_global"; + } else if (!strcmp(avctx->filter->name, "sobel_opencl")) { + kernel_name = "sobel_global"; + } else if (!strcmp(avctx->filter->name, "prewitt_opencl")){ + kernel_name = "prewitt_global"; + } else if (!strcmp(avctx->filter->name, "roberts_opencl")){ + kernel_name = "roberts_global"; } + ctx->kernel = clCreateKernel(ctx->ocf.program, kernel_name, &cle); + CL_FAIL_ON_ERROR(AVERROR(EIO), "Failed to create " + "kernel %d.\n", cle); ctx->initialised = 1; return 0; @@ -173,6 +179,8 @@ static int convolution_opencl_filter_frame(AVFilterLink *inlink, AVFrame *input) size_t global_work[2]; cl_mem src, dst; int err, p; + size_t origin[3] = {0, 0, 0}; + size_t region[3] = {0, 0, 1}; av_log(ctx, AV_LOG_DEBUG, "Filter input: %s, %ux%u (%"PRId64").\n", av_get_pix_fmt_name(input->format), @@ -186,9 +194,14 @@ static int convolution_opencl_filter_frame(AVFilterLink *inlink, AVFrame *input) if (err < 0) goto fail; - err = convolution_opencl_make_filter_params(avctx); - if (err < 0) - goto fail; + if (!strcmp(avctx->filter->name, "convolution_opencl")) { + err = convolution_opencl_make_filter_params(avctx); + if (err < 0) + goto fail; + } else { + ctx->delta /= 255.0; + } + } output = ff_get_video_buffer(outlink, outlink->w, outlink->h); @@ -204,70 +217,62 @@ static int convolution_opencl_filter_frame(AVFilterLink *inlink, AVFrame *input) if (!dst) break; - cle = clSetKernelArg(ctx->kernel, 0, sizeof(cl_mem), &dst); - if (cle != CL_SUCCESS) { - av_log(avctx, AV_LOG_ERROR, "Failed to set kernel " - "destination image argument: %d.\n", cle); - goto fail; - } - cle = clSetKernelArg(ctx->kernel, 1, sizeof(cl_mem), &src); - if (cle != CL_SUCCESS) { - av_log(avctx, AV_LOG_ERROR, "Failed to set kernel " - "source image argument: %d.\n", cle); - goto fail; - } - cle = clSetKernelArg(ctx->kernel, 2, sizeof(cl_int), &ctx->dims[p]); - if (cle != CL_SUCCESS) { - av_log(avctx, AV_LOG_ERROR, "Failed to set kernel " - "matrix size argument: %d.\n", cle); - goto fail; - } - cle = clSetKernelArg(ctx->kernel, 3, sizeof(cl_mem), &ctx->matrix[p]); - if (cle != CL_SUCCESS) { - av_log(avctx, AV_LOG_ERROR, "Failed to set kernel " - "matrix argument: %d.\n", cle); - goto fail; - } - cle = clSetKernelArg(ctx->kernel, 4, sizeof(cl_float), &ctx->rdivs[p]); - if (cle != CL_SUCCESS) { - av_log(avctx, AV_LOG_ERROR, "Failed to set kernel " - "rdiv argument: %d.\n", cle); - goto fail; - } - cle = clSetKernelArg(ctx->kernel, 5, sizeof(cl_float), &ctx->biases[p]); - if (cle != CL_SUCCESS) { - av_log(avctx, AV_LOG_ERROR, "Failed to set kernel " - "bias argument: %d.\n", cle); - goto fail; - } + if (!strcmp(avctx->filter->name, "convolution_opencl")) { + CL_SET_KERNEL_ARG(ctx->kernel, 0, cl_mem, &dst); + CL_SET_KERNEL_ARG(ctx->kernel, 1, cl_mem, &src); + CL_SET_KERNEL_ARG(ctx->kernel, 2, cl_int, &ctx->dims[p]); + CL_SET_KERNEL_ARG(ctx->kernel, 3, cl_mem, &ctx->matrix[p]); + CL_SET_KERNEL_ARG(ctx->kernel, 4, cl_float, &ctx->rdivs[p]); + CL_SET_KERNEL_ARG(ctx->kernel, 5, cl_float, &ctx->biases[p]); + err = ff_opencl_filter_work_size_from_image(avctx, global_work, output, p, 0); + if (err < 0) + goto fail; - err = ff_opencl_filter_work_size_from_image(avctx, global_work, output, p, 0); - if (err < 0) - goto fail; + av_log(avctx, AV_LOG_DEBUG, "Run kernel on plane %d " + "(%"SIZE_SPECIFIER"x%"SIZE_SPECIFIER").\n", + p, global_work[0], global_work[1]); - av_log(avctx, AV_LOG_DEBUG, "Run kernel on plane %d " - "(%"SIZE_SPECIFIER"x%"SIZE_SPECIFIER").\n", - p, global_work[0], global_work[1]); + cle = clEnqueueNDRangeKernel(ctx->command_queue, ctx->kernel, 2, NULL, + global_work, NULL, + 0, NULL, NULL); + CL_FAIL_ON_ERROR(AVERROR(EIO), "Failed to enqueue " + "kernel: %d.\n", cle); + } else { + if (!(ctx->planes & (1 << p))) { + err = ff_opencl_filter_work_size_from_image(avctx, region, output, p, 0); + if (err < 0) + goto fail; - cle = clEnqueueNDRangeKernel(ctx->command_queue, ctx->kernel, 2, NULL, - global_work, NULL, - 0, NULL, NULL); - if (cle != CL_SUCCESS) { - av_log(avctx, AV_LOG_ERROR, "Failed to enqueue kernel: %d.\n", - cle); - err = AVERROR(EIO); - goto fail; + cle = clEnqueueCopyImage(ctx->command_queue, src, dst, + origin, origin, region, 0, NULL, NULL); + CL_FAIL_ON_ERROR(AVERROR(EIO), "Failed to copy plane %d: %d.\n", + p, cle); + } else { + CL_SET_KERNEL_ARG(ctx->kernel, 0, cl_mem, &dst); + CL_SET_KERNEL_ARG(ctx->kernel, 1, cl_mem, &src); + CL_SET_KERNEL_ARG(ctx->kernel, 2, cl_float, &ctx->scale); + CL_SET_KERNEL_ARG(ctx->kernel, 3, cl_float, &ctx->delta); + + err = ff_opencl_filter_work_size_from_image(avctx, global_work, output, p, 0); + if (err < 0) + goto fail; + + av_log(avctx, AV_LOG_DEBUG, "Run kernel on plane %d " + "(%"SIZE_SPECIFIER"x%"SIZE_SPECIFIER").\n", + p, global_work[0], global_work[1]); + + cle = clEnqueueNDRangeKernel(ctx->command_queue, ctx->kernel, 2, NULL, + global_work, NULL, + 0, NULL, NULL); + CL_FAIL_ON_ERROR(AVERROR(EIO), "Failed to enqueue " + "kernel: %d.\n", cle); + } } } cle = clFinish(ctx->command_queue); - if (cle != CL_SUCCESS) { - av_log(avctx, AV_LOG_ERROR, "Failed to finish command queue: %d.\n", - cle); - err = AVERROR(EIO); - goto fail; - } + CL_FAIL_ON_ERROR(AVERROR(EIO), "Failed to finish command queue: %d.\n", cle); err = av_frame_copy_props(output, input); if (err < 0) @@ -315,26 +320,6 @@ static av_cold void convolution_opencl_uninit(AVFilterContext *avctx) ff_opencl_filter_uninit(avctx); } -#define OFFSET(x) offsetof(ConvolutionOpenCLContext, x) -#define FLAGS (AV_OPT_FLAG_FILTERING_PARAM | AV_OPT_FLAG_VIDEO_PARAM) -static const AVOption convolution_opencl_options[] = { - { "0m", "set matrix for 2nd plane", OFFSET(matrix_str[0]), AV_OPT_TYPE_STRING, {.str="0 0 0 0 1 0 0 0 0"}, 0, 0, FLAGS }, - { "1m", "set matrix for 2nd plane", OFFSET(matrix_str[1]), AV_OPT_TYPE_STRING, {.str="0 0 0 0 1 0 0 0 0"}, 0, 0, FLAGS }, - { "2m", "set matrix for 3rd plane", OFFSET(matrix_str[2]), AV_OPT_TYPE_STRING, {.str="0 0 0 0 1 0 0 0 0"}, 0, 0, FLAGS }, - { "3m", "set matrix for 4th plane", OFFSET(matrix_str[3]), AV_OPT_TYPE_STRING, {.str="0 0 0 0 1 0 0 0 0"}, 0, 0, FLAGS }, - { "0rdiv", "set rdiv for 1nd plane", OFFSET(rdivs[0]), AV_OPT_TYPE_FLOAT, {.dbl=1.0}, 0.0, INT_MAX, FLAGS}, - { "1rdiv", "set rdiv for 2nd plane", OFFSET(rdivs[1]), AV_OPT_TYPE_FLOAT, {.dbl=1.0}, 0.0, INT_MAX, FLAGS}, - { "2rdiv", "set rdiv for 3rd plane", OFFSET(rdivs[2]), AV_OPT_TYPE_FLOAT, {.dbl=1.0}, 0.0, INT_MAX, FLAGS}, - { "3rdiv", "set rdiv for 4th plane", OFFSET(rdivs[3]), AV_OPT_TYPE_FLOAT, {.dbl=1.0}, 0.0, INT_MAX, FLAGS}, - { "0bias", "set bias for 1st plane", OFFSET(biases[0]), AV_OPT_TYPE_FLOAT, {.dbl=0.0}, 0.0, INT_MAX, FLAGS}, - { "1bias", "set bias for 2nd plane", OFFSET(biases[1]), AV_OPT_TYPE_FLOAT, {.dbl=0.0}, 0.0, INT_MAX, FLAGS}, - { "2bias", "set bias for 3rd plane", OFFSET(biases[2]), AV_OPT_TYPE_FLOAT, {.dbl=0.0}, 0.0, INT_MAX, FLAGS}, - { "3bias", "set bias for 4th plane", OFFSET(biases[3]), AV_OPT_TYPE_FLOAT, {.dbl=0.0}, 0.0, INT_MAX, FLAGS}, - { NULL } -}; - -AVFILTER_DEFINE_CLASS(convolution_opencl); - static const AVFilterPad convolution_opencl_inputs[] = { { .name = "default", @@ -354,6 +339,29 @@ static const AVFilterPad convolution_opencl_outputs[] = { { NULL } }; +#define OFFSET(x) offsetof(ConvolutionOpenCLContext, x) +#define FLAGS (AV_OPT_FLAG_FILTERING_PARAM | AV_OPT_FLAG_VIDEO_PARAM) + +#if CONFIG_CONVOLUTION_OPENCL_FILTER + +static const AVOption convolution_opencl_options[] = { + { "0m", "set matrix for 2nd plane", OFFSET(matrix_str[0]), AV_OPT_TYPE_STRING, {.str="0 0 0 0 1 0 0 0 0"}, 0, 0, FLAGS }, + { "1m", "set matrix for 2nd plane", OFFSET(matrix_str[1]), AV_OPT_TYPE_STRING, {.str="0 0 0 0 1 0 0 0 0"}, 0, 0, FLAGS }, + { "2m", "set matrix for 3rd plane", OFFSET(matrix_str[2]), AV_OPT_TYPE_STRING, {.str="0 0 0 0 1 0 0 0 0"}, 0, 0, FLAGS }, + { "3m", "set matrix for 4th plane", OFFSET(matrix_str[3]), AV_OPT_TYPE_STRING, {.str="0 0 0 0 1 0 0 0 0"}, 0, 0, FLAGS }, + { "0rdiv", "set rdiv for 1nd plane", OFFSET(rdivs[0]), AV_OPT_TYPE_FLOAT, {.dbl=1.0}, 0.0, INT_MAX, FLAGS}, + { "1rdiv", "set rdiv for 2nd plane", OFFSET(rdivs[1]), AV_OPT_TYPE_FLOAT, {.dbl=1.0}, 0.0, INT_MAX, FLAGS}, + { "2rdiv", "set rdiv for 3rd plane", OFFSET(rdivs[2]), AV_OPT_TYPE_FLOAT, {.dbl=1.0}, 0.0, INT_MAX, FLAGS}, + { "3rdiv", "set rdiv for 4th plane", OFFSET(rdivs[3]), AV_OPT_TYPE_FLOAT, {.dbl=1.0}, 0.0, INT_MAX, FLAGS}, + { "0bias", "set bias for 1st plane", OFFSET(biases[0]), AV_OPT_TYPE_FLOAT, {.dbl=0.0}, 0.0, INT_MAX, FLAGS}, + { "1bias", "set bias for 2nd plane", OFFSET(biases[1]), AV_OPT_TYPE_FLOAT, {.dbl=0.0}, 0.0, INT_MAX, FLAGS}, + { "2bias", "set bias for 3rd plane", OFFSET(biases[2]), AV_OPT_TYPE_FLOAT, {.dbl=0.0}, 0.0, INT_MAX, FLAGS}, + { "3bias", "set bias for 4th plane", OFFSET(biases[3]), AV_OPT_TYPE_FLOAT, {.dbl=0.0}, 0.0, INT_MAX, FLAGS}, + { NULL } +}; + +AVFILTER_DEFINE_CLASS(convolution_opencl); + AVFilter ff_vf_convolution_opencl = { .name = "convolution_opencl", .description = NULL_IF_CONFIG_SMALL("Apply convolution mask to input video"), @@ -366,3 +374,83 @@ AVFilter ff_vf_convolution_opencl = { .outputs = convolution_opencl_outputs, .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE, }; + +#endif /* CONFIG_CONVOLUTION_OPENCL_FILTER */ + +#if CONFIG_SOBEL_OPENCL_FILTER + +static const AVOption sobel_opencl_options[] = { + { "planes", "set planes to filter", OFFSET(planes), AV_OPT_TYPE_INT, {.i64=15}, 0, 15, FLAGS}, + { "scale", "set scale", OFFSET(scale), AV_OPT_TYPE_FLOAT, {.dbl=1.0}, 0.0, 65535, FLAGS}, + { "delta", "set delta", OFFSET(delta), AV_OPT_TYPE_FLOAT, {.dbl=0}, -65535, 65535, FLAGS}, + { NULL } +}; + +AVFILTER_DEFINE_CLASS(sobel_opencl); + +AVFilter ff_vf_sobel_opencl = { + .name = "sobel_opencl", + .description = NULL_IF_CONFIG_SMALL("Apply sobel operator"), + .priv_size = sizeof(ConvolutionOpenCLContext), + .priv_class = &sobel_opencl_class, + .init = &ff_opencl_filter_init, + .uninit = &convolution_opencl_uninit, + .query_formats = &ff_opencl_filter_query_formats, + .inputs = convolution_opencl_inputs, + .outputs = convolution_opencl_outputs, + .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE, +}; + +#endif /* CONFIG_SOBEL_OPENCL_FILTER */ + +#if CONFIG_PREWITT_OPENCL_FILTER + +static const AVOption prewitt_opencl_options[] = { + { "planes", "set planes to filter", OFFSET(planes), AV_OPT_TYPE_INT, {.i64=15}, 0, 15, FLAGS}, + { "scale", "set scale", OFFSET(scale), AV_OPT_TYPE_FLOAT, {.dbl=1.0}, 0.0, 65535, FLAGS}, + { "delta", "set delta", OFFSET(delta), AV_OPT_TYPE_FLOAT, {.dbl=0}, -65535, 65535, FLAGS}, + { NULL } +}; + +AVFILTER_DEFINE_CLASS(prewitt_opencl); + +AVFilter ff_vf_prewitt_opencl = { + .name = "prewitt_opencl", + .description = NULL_IF_CONFIG_SMALL("Apply prewitt operator"), + .priv_size = sizeof(ConvolutionOpenCLContext), + .priv_class = &prewitt_opencl_class, + .init = &ff_opencl_filter_init, + .uninit = &convolution_opencl_uninit, + .query_formats = &ff_opencl_filter_query_formats, + .inputs = convolution_opencl_inputs, + .outputs = convolution_opencl_outputs, + .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE, +}; + +#endif /* CONFIG_PREWITT_OPENCL_FILTER */ + +#if CONFIG_ROBERTS_OPENCL_FILTER + +static const AVOption roberts_opencl_options[] = { + { "planes", "set planes to filter", OFFSET(planes), AV_OPT_TYPE_INT, {.i64=15}, 0, 15, FLAGS}, + { "scale", "set scale", OFFSET(scale), AV_OPT_TYPE_FLOAT, {.dbl=1.0}, 0.0, 65535, FLAGS}, + { "delta", "set delta", OFFSET(delta), AV_OPT_TYPE_FLOAT, {.dbl=0}, -65535, 65535, FLAGS}, + { NULL } +}; + +AVFILTER_DEFINE_CLASS(roberts_opencl); + +AVFilter ff_vf_roberts_opencl = { + .name = "roberts_opencl", + .description = NULL_IF_CONFIG_SMALL("Apply roberts operator"), + .priv_size = sizeof(ConvolutionOpenCLContext), + .priv_class = &roberts_opencl_class, + .init = &ff_opencl_filter_init, + .uninit = &convolution_opencl_uninit, + .query_formats = &ff_opencl_filter_query_formats, + .inputs = convolution_opencl_inputs, + .outputs = convolution_opencl_outputs, + .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE, +}; + +#endif /* CONFIG_ROBERTS_OPENCL_FILTER */ diff --git a/libavfilter/vf_convolve.c b/libavfilter/vf_convolve.c index 982eda1cb..024eb6848 100644 --- a/libavfilter/vf_convolve.c +++ b/libavfilter/vf_convolve.c @@ -91,7 +91,7 @@ static int query_formats(AVFilterContext *ctx) AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRP9, AV_PIX_FMT_GBRP10, AV_PIX_FMT_GBRP12, AV_PIX_FMT_GBRP14, AV_PIX_FMT_GBRP16, AV_PIX_FMT_GBRAP, AV_PIX_FMT_GBRAP10, AV_PIX_FMT_GBRAP12, AV_PIX_FMT_GBRAP16, - AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY9, AV_PIX_FMT_GRAY10, AV_PIX_FMT_GRAY12, AV_PIX_FMT_GRAY16, + AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY9, AV_PIX_FMT_GRAY10, AV_PIX_FMT_GRAY12, AV_PIX_FMT_GRAY14, AV_PIX_FMT_GRAY16, AV_PIX_FMT_NONE }; diff --git a/libavfilter/vf_cover_rect.c b/libavfilter/vf_cover_rect.c index f7f61038e..898debf09 100644 --- a/libavfilter/vf_cover_rect.c +++ b/libavfilter/vf_cover_rect.c @@ -152,7 +152,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) } if (!xendptr || *xendptr || !yendptr || *yendptr || - !wendptr || *wendptr || !hendptr || !hendptr + !wendptr || *wendptr || !hendptr || *hendptr ) { return ff_filter_frame(ctx->outputs[0], in); } @@ -198,6 +198,7 @@ static av_cold void uninit(AVFilterContext *ctx) if (cover->cover_frame) av_freep(&cover->cover_frame->data[0]); + av_frame_free(&cover->cover_frame); } static av_cold int init(AVFilterContext *ctx) diff --git a/libavfilter/vf_crop.c b/libavfilter/vf_crop.c index 84be4c7d0..9fca7a730 100644 --- a/libavfilter/vf_crop.c +++ b/libavfilter/vf_crop.c @@ -98,9 +98,17 @@ static int query_formats(AVFilterContext *ctx) for (fmt = 0; av_pix_fmt_desc_get(fmt); fmt++) { const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(fmt); - if (!(desc->flags & (AV_PIX_FMT_FLAG_HWACCEL | AV_PIX_FMT_FLAG_BITSTREAM)) && - !((desc->log2_chroma_w || desc->log2_chroma_h) && !(desc->flags & AV_PIX_FMT_FLAG_PLANAR)) && - (ret = ff_add_format(&formats, fmt)) < 0) + if (desc->flags & AV_PIX_FMT_FLAG_BITSTREAM) + continue; + if (!(desc->flags & AV_PIX_FMT_FLAG_HWACCEL)) { + // Not usable if there is any subsampling but the format is + // not planar (e.g. YUYV422). + if ((desc->log2_chroma_w || desc->log2_chroma_h) && + !(desc->flags & AV_PIX_FMT_FLAG_PLANAR)) + continue; + } + ret = ff_add_format(&formats, fmt); + if (ret < 0) return ret; } @@ -157,8 +165,14 @@ static int config_input(AVFilterLink *link) s->var_values[VAR_POS] = NAN; av_image_fill_max_pixsteps(s->max_step, NULL, pix_desc); - s->hsub = pix_desc->log2_chroma_w; - s->vsub = pix_desc->log2_chroma_h; + + if (pix_desc->flags & AV_PIX_FMT_FLAG_HWACCEL) { + s->hsub = 1; + s->vsub = 1; + } else { + s->hsub = pix_desc->log2_chroma_w; + s->vsub = pix_desc->log2_chroma_h; + } if ((ret = av_expr_parse_and_eval(&res, (expr = s->w_expr), var_names, s->var_values, @@ -237,9 +251,15 @@ fail_expr: static int config_output(AVFilterLink *link) { CropContext *s = link->src->priv; + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(link->format); - link->w = s->w; - link->h = s->h; + if (desc->flags & AV_PIX_FMT_FLAG_HWACCEL) { + // Hardware frames adjust the cropping regions rather than + // changing the frame size. + } else { + link->w = s->w; + link->h = s->h; + } link->sample_aspect_ratio = s->out_sar; return 0; @@ -252,9 +272,6 @@ static int filter_frame(AVFilterLink *link, AVFrame *frame) const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(link->format); int i; - frame->width = s->w; - frame->height = s->h; - s->var_values[VAR_N] = link->frame_count_out; s->var_values[VAR_T] = frame->pts == AV_NOPTS_VALUE ? NAN : frame->pts * av_q2d(link->time_base); @@ -285,22 +302,32 @@ static int filter_frame(AVFilterLink *link, AVFrame *frame) (int)s->var_values[VAR_N], s->var_values[VAR_T], s->var_values[VAR_POS], s->x, s->y, s->x+s->w, s->y+s->h); - frame->data[0] += s->y * frame->linesize[0]; - frame->data[0] += s->x * s->max_step[0]; + if (desc->flags & AV_PIX_FMT_FLAG_HWACCEL) { + frame->crop_top += s->y; + frame->crop_left += s->x; + frame->crop_bottom = frame->height - frame->crop_top - frame->crop_bottom - s->h; + frame->crop_right = frame->width - frame->crop_left - frame->crop_right - s->w; + } else { + frame->width = s->w; + frame->height = s->h; - if (!(desc->flags & AV_PIX_FMT_FLAG_PAL || desc->flags & FF_PSEUDOPAL)) { - for (i = 1; i < 3; i ++) { - if (frame->data[i]) { - frame->data[i] += (s->y >> s->vsub) * frame->linesize[i]; - frame->data[i] += (s->x * s->max_step[i]) >> s->hsub; + frame->data[0] += s->y * frame->linesize[0]; + frame->data[0] += s->x * s->max_step[0]; + + if (!(desc->flags & AV_PIX_FMT_FLAG_PAL || desc->flags & FF_PSEUDOPAL)) { + for (i = 1; i < 3; i ++) { + if (frame->data[i]) { + frame->data[i] += (s->y >> s->vsub) * frame->linesize[i]; + frame->data[i] += (s->x * s->max_step[i]) >> s->hsub; + } } } - } - /* alpha plane */ - if (frame->data[3]) { - frame->data[3] += s->y * frame->linesize[3]; - frame->data[3] += s->x * s->max_step[3]; + /* alpha plane */ + if (frame->data[3]) { + frame->data[3] += s->y * frame->linesize[3]; + frame->data[3] += s->x * s->max_step[3]; + } } return ff_filter_frame(link->dst->outputs[0], frame); diff --git a/libavfilter/vf_curves.c b/libavfilter/vf_curves.c index 19ab78915..883cc1c90 100644 --- a/libavfilter/vf_curves.c +++ b/libavfilter/vf_curves.c @@ -70,6 +70,9 @@ typedef struct CurvesContext { int step; char *plot_filename; int is_16bit; + int depth; + + int (*filter_slice)(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs); } CurvesContext; typedef struct ThreadData { @@ -209,7 +212,7 @@ static int get_nb_points(const struct keypoint *d) * @see http://people.math.sfu.ca/~stockie/teaching/macm316/notes/splines.pdf */ -#define CLIP(v) (nbits == 8 ? av_clip_uint8(v) : av_clip_uint16(v)) +#define CLIP(v) (nbits == 8 ? av_clip_uint8(v) : av_clip_uintp2_c(v, nbits)) static inline int interpolate(void *log_ctx, uint16_t *y, const struct keypoint *points, int nbits) @@ -341,6 +344,10 @@ static int interpolate##nbits(void *log_ctx, uint16_t *y, \ } DECLARE_INTERPOLATE_FUNC(8) +DECLARE_INTERPOLATE_FUNC(9) +DECLARE_INTERPOLATE_FUNC(10) +DECLARE_INTERPOLATE_FUNC(12) +DECLARE_INTERPOLATE_FUNC(14) DECLARE_INTERPOLATE_FUNC(16) static int parse_psfile(AVFilterContext *ctx, const char *fname) @@ -512,6 +519,12 @@ static int query_formats(AVFilterContext *ctx) AV_PIX_FMT_RGB0, AV_PIX_FMT_BGR0, AV_PIX_FMT_RGB48, AV_PIX_FMT_BGR48, AV_PIX_FMT_RGBA64, AV_PIX_FMT_BGRA64, + AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRAP, + AV_PIX_FMT_GBRP9, + AV_PIX_FMT_GBRP10, AV_PIX_FMT_GBRAP10, + AV_PIX_FMT_GBRP12, AV_PIX_FMT_GBRAP12, + AV_PIX_FMT_GBRP14, + AV_PIX_FMT_GBRP16, AV_PIX_FMT_GBRAP16, AV_PIX_FMT_NONE }; AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts); @@ -520,66 +533,7 @@ static int query_formats(AVFilterContext *ctx) return ff_set_common_formats(ctx, fmts_list); } -static int config_input(AVFilterLink *inlink) -{ - int i, j, ret; - AVFilterContext *ctx = inlink->dst; - CurvesContext *curves = ctx->priv; - const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format); - char **pts = curves->comp_points_str; - struct keypoint *comp_points[NB_COMP + 1] = {0}; - - ff_fill_rgba_map(curves->rgba_map, inlink->format); - curves->is_16bit = desc->comp[0].depth > 8; - curves->lut_size = curves->is_16bit ? 1<<16 : 1<<8; - curves->step = av_get_padded_bits_per_pixel(desc) >> (3 + curves->is_16bit); - - for (i = 0; i < NB_COMP + 1; i++) { - curves->graph[i] = av_mallocz_array(curves->lut_size, sizeof(*curves->graph[0])); - if (!curves->graph[i]) - return AVERROR(ENOMEM); - ret = parse_points_str(ctx, comp_points + i, curves->comp_points_str[i], curves->lut_size); - if (ret < 0) - return ret; - if (curves->is_16bit) ret = interpolate16(ctx, curves->graph[i], comp_points[i]); - else ret = interpolate8(ctx, curves->graph[i], comp_points[i]); - if (ret < 0) - return ret; - } - - if (pts[NB_COMP]) { - for (i = 0; i < NB_COMP; i++) - for (j = 0; j < curves->lut_size; j++) - curves->graph[i][j] = curves->graph[NB_COMP][curves->graph[i][j]]; - } - - if (av_log_get_level() >= AV_LOG_VERBOSE) { - for (i = 0; i < NB_COMP; i++) { - const struct keypoint *point = comp_points[i]; - av_log(ctx, AV_LOG_VERBOSE, "#%d points:", i); - while (point) { - av_log(ctx, AV_LOG_VERBOSE, " (%f;%f)", point->x, point->y); - point = point->next; - } - } - } - - if (curves->plot_filename) - dump_curves(curves->plot_filename, curves->graph, comp_points, curves->lut_size); - - for (i = 0; i < NB_COMP + 1; i++) { - struct keypoint *point = comp_points[i]; - while (point) { - struct keypoint *next = point->next; - av_free(point); - point = next; - } - } - - return 0; -} - -static int filter_slice(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) +static int filter_slice_packed(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) { int x, y; const CurvesContext *curves = ctx->priv; @@ -627,9 +581,143 @@ static int filter_slice(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) return 0; } +static int filter_slice_planar(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) +{ + int x, y; + const CurvesContext *curves = ctx->priv; + const ThreadData *td = arg; + const AVFrame *in = td->in; + const AVFrame *out = td->out; + const int direct = out == in; + const int step = curves->step; + const uint8_t r = curves->rgba_map[R]; + const uint8_t g = curves->rgba_map[G]; + const uint8_t b = curves->rgba_map[B]; + const uint8_t a = curves->rgba_map[A]; + const int slice_start = (in->height * jobnr ) / nb_jobs; + const int slice_end = (in->height * (jobnr+1)) / nb_jobs; + + if (curves->is_16bit) { + for (y = slice_start; y < slice_end; y++) { + uint16_t *dstrp = ( uint16_t *)(out->data[r] + y * out->linesize[r]); + uint16_t *dstgp = ( uint16_t *)(out->data[g] + y * out->linesize[g]); + uint16_t *dstbp = ( uint16_t *)(out->data[b] + y * out->linesize[b]); + uint16_t *dstap = ( uint16_t *)(out->data[a] + y * out->linesize[a]); + const uint16_t *srcrp = (const uint16_t *)(in ->data[r] + y * in->linesize[r]); + const uint16_t *srcgp = (const uint16_t *)(in ->data[g] + y * in->linesize[g]); + const uint16_t *srcbp = (const uint16_t *)(in ->data[b] + y * in->linesize[b]); + const uint16_t *srcap = (const uint16_t *)(in ->data[a] + y * in->linesize[a]); + + for (x = 0; x < in->width; x++) { + dstrp[x] = curves->graph[R][srcrp[x]]; + dstgp[x] = curves->graph[G][srcgp[x]]; + dstbp[x] = curves->graph[B][srcbp[x]]; + if (!direct && step == 4) + dstap[x] = srcap[x]; + } + } + } else { + uint8_t *dstr = out->data[r] + slice_start * out->linesize[r]; + uint8_t *dstg = out->data[g] + slice_start * out->linesize[g]; + uint8_t *dstb = out->data[b] + slice_start * out->linesize[b]; + uint8_t *dsta = out->data[a] + slice_start * out->linesize[a]; + const uint8_t *srcr = in->data[r] + slice_start * in->linesize[r]; + const uint8_t *srcg = in->data[g] + slice_start * in->linesize[g]; + const uint8_t *srcb = in->data[b] + slice_start * in->linesize[b]; + const uint8_t *srca = in->data[a] + slice_start * in->linesize[a]; + + for (y = slice_start; y < slice_end; y++) { + for (x = 0; x < in->width; x++) { + dstr[x] = curves->graph[R][srcr[x]]; + dstg[x] = curves->graph[G][srcg[x]]; + dstb[x] = curves->graph[B][srcb[x]]; + if (!direct && step == 4) + dsta[x] = srca[x]; + } + dstr += out->linesize[r]; + dstg += out->linesize[g]; + dstb += out->linesize[b]; + dsta += out->linesize[a]; + srcr += in ->linesize[r]; + srcg += in ->linesize[g]; + srcb += in ->linesize[b]; + srca += in ->linesize[a]; + } + } + return 0; +} + +static int config_input(AVFilterLink *inlink) +{ + int i, j, ret; + AVFilterContext *ctx = inlink->dst; + CurvesContext *curves = ctx->priv; + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format); + char **pts = curves->comp_points_str; + struct keypoint *comp_points[NB_COMP + 1] = {0}; + + ff_fill_rgba_map(curves->rgba_map, inlink->format); + curves->is_16bit = desc->comp[0].depth > 8; + curves->depth = desc->comp[0].depth; + curves->lut_size = 1 << curves->depth; + curves->step = av_get_padded_bits_per_pixel(desc) >> (3 + curves->is_16bit); + curves->filter_slice = desc->flags & AV_PIX_FMT_FLAG_PLANAR ? filter_slice_planar : filter_slice_packed; + + for (i = 0; i < NB_COMP + 1; i++) { + curves->graph[i] = av_mallocz_array(curves->lut_size, sizeof(*curves->graph[0])); + if (!curves->graph[i]) + return AVERROR(ENOMEM); + ret = parse_points_str(ctx, comp_points + i, curves->comp_points_str[i], curves->lut_size); + if (ret < 0) + return ret; + switch (curves->depth) { + case 8: ret = interpolate8 (ctx, curves->graph[i], comp_points[i]); break; + case 9: ret = interpolate9 (ctx, curves->graph[i], comp_points[i]); break; + case 10: ret = interpolate10(ctx, curves->graph[i], comp_points[i]); break; + case 12: ret = interpolate12(ctx, curves->graph[i], comp_points[i]); break; + case 14: ret = interpolate14(ctx, curves->graph[i], comp_points[i]); break; + case 16: ret = interpolate16(ctx, curves->graph[i], comp_points[i]); break; + } + if (ret < 0) + return ret; + } + + if (pts[NB_COMP]) { + for (i = 0; i < NB_COMP; i++) + for (j = 0; j < curves->lut_size; j++) + curves->graph[i][j] = curves->graph[NB_COMP][curves->graph[i][j]]; + } + + if (av_log_get_level() >= AV_LOG_VERBOSE) { + for (i = 0; i < NB_COMP; i++) { + const struct keypoint *point = comp_points[i]; + av_log(ctx, AV_LOG_VERBOSE, "#%d points:", i); + while (point) { + av_log(ctx, AV_LOG_VERBOSE, " (%f;%f)", point->x, point->y); + point = point->next; + } + } + } + + if (curves->plot_filename) + dump_curves(curves->plot_filename, curves->graph, comp_points, curves->lut_size); + + for (i = 0; i < NB_COMP + 1; i++) { + struct keypoint *point = comp_points[i]; + while (point) { + struct keypoint *next = point->next; + av_free(point); + point = next; + } + } + + return 0; +} + static int filter_frame(AVFilterLink *inlink, AVFrame *in) { AVFilterContext *ctx = inlink->dst; + CurvesContext *curves = ctx->priv; AVFilterLink *outlink = ctx->outputs[0]; AVFrame *out; ThreadData td; @@ -647,7 +735,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) td.in = in; td.out = out; - ctx->internal->execute(ctx, filter_slice, &td, NULL, FFMIN(outlink->h, ff_filter_get_nb_threads(ctx))); + ctx->internal->execute(ctx, curves->filter_slice, &td, NULL, FFMIN(outlink->h, ff_filter_get_nb_threads(ctx))); if (out != in) av_frame_free(&in); diff --git a/libavfilter/vf_datascope.c b/libavfilter/vf_datascope.c index 467663556..c9039a60f 100644 --- a/libavfilter/vf_datascope.c +++ b/libavfilter/vf_datascope.c @@ -506,7 +506,7 @@ static int pixscope_config_input(AVFilterLink *inlink) } s->ww = 300; - s->wh = 300 * 1.6180; + s->wh = 300 * 1.6; s->x = s->xpos * (inlink->w - 1); s->y = s->ypos * (inlink->h - 1); if (s->x + s->w >= inlink->w || s->y + s->h >= inlink->h) { @@ -802,8 +802,8 @@ static void draw_trace8(OscilloscopeContext *s, AVFrame *frame) if ((1 << c) & s->components) { int x = i * s->width / s->nb_values; int px = (i - 1) * s->width / s->nb_values; - int py = s->height - s->values[i-1].p[c] * s->height / 256; - int y = s->height - s->values[i].p[c] * s->height / 256; + int py = s->height - s->values[i-1].p[s->rgba_map[c]] * s->height / 256; + int y = s->height - s->values[i].p[s->rgba_map[c]] * s->height / 256; draw_line(&s->draw, s->ox + x, s->oy + y, s->ox + px, s->oy + py, frame, s->colors[c]); } @@ -821,8 +821,8 @@ static void draw_trace16(OscilloscopeContext *s, AVFrame *frame) if ((1 << c) & s->components) { int x = i * s->width / s->nb_values; int px = (i - 1) * s->width / s->nb_values; - int py = s->height - s->values[i-1].p[c] * s->height / s->max; - int y = s->height - s->values[i].p[c] * s->height / s->max; + int py = s->height - s->values[i-1].p[s->rgba_map[c]] * s->height / s->max; + int y = s->height - s->values[i].p[s->rgba_map[c]] * s->height / s->max; draw_line(&s->draw, s->ox + x, s->oy + y, s->ox + px, s->oy + py, frame, s->colors[c]); } @@ -996,9 +996,9 @@ static int oscilloscope_filter_frame(AVFilterLink *inlink, AVFrame *frame) for (i = 0; i < s->nb_values; i++) { for (c = 0; c < s->nb_comps; c++) { if ((1 << c) & s->components) { - max[c] = FFMAX(max[c], s->values[i].p[c]); - min[c] = FFMIN(min[c], s->values[i].p[c]); - average[c] += s->values[i].p[c]; + max[c] = FFMAX(max[c], s->values[i].p[s->rgba_map[c]]); + min[c] = FFMIN(min[c], s->values[i].p[s->rgba_map[c]]); + average[c] += s->values[i].p[s->rgba_map[c]]; } } } @@ -1013,7 +1013,7 @@ static int oscilloscope_filter_frame(AVFilterLink *inlink, AVFrame *frame) const char yuva[4] = { 'Y', 'U', 'V', 'A' }; char text[128]; - snprintf(text, sizeof(text), "%c avg:%.1f min:%d max:%d\n", s->is_rgb ? rgba[c] : yuva[c], average[s->rgba_map[c]], min[s->rgba_map[c]], max[s->rgba_map[c]]); + snprintf(text, sizeof(text), "%c avg:%.1f min:%d max:%d\n", s->is_rgb ? rgba[c] : yuva[c], average[c], min[c], max[c]); draw_text(&s->draw, frame, &s->white, s->ox + 2 + 280 * i++, s->oy + s->height + 4, text, 0); } } diff --git a/libavfilter/vf_deblock.c b/libavfilter/vf_deblock.c new file mode 100644 index 000000000..62e3248d4 --- /dev/null +++ b/libavfilter/vf_deblock.c @@ -0,0 +1,414 @@ +/* + * Copyright (c) 2018 Paul B Mahol + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * Based on paper: A Simple and Efficient Deblocking Algorithm for Low Bit-Rate Video Coding. + */ + +#include "libavutil/imgutils.h" +#include "libavutil/opt.h" +#include "libavutil/pixdesc.h" + +#include "avfilter.h" +#include "formats.h" +#include "internal.h" +#include "video.h" + +enum FilterType { WEAK, STRONG, NB_FILTER }; + +typedef struct DeblockContext { + const AVClass *class; + const AVPixFmtDescriptor *desc; + int filter; + int block; + int planes; + float alpha; + float beta; + float gamma; + float delta; + + int ath; + int bth; + int gth; + int dth; + int max; + int depth; + int bpc; + int nb_planes; + int planewidth[4]; + int planeheight[4]; + + void (*deblockh)(uint8_t *dst, ptrdiff_t dst_linesize, int block, + int ath, int bth, int gth, int dth, int max); + void (*deblockv)(uint8_t *dst, ptrdiff_t dst_linesize, int block, + int ath, int bth, int gth, int dth, int max); +} DeblockContext; + +static int query_formats(AVFilterContext *ctx) +{ + static const enum AVPixelFormat pixel_fmts[] = { + AV_PIX_FMT_YUVA444P, AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUV440P, + AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_YUVJ440P, + AV_PIX_FMT_YUVA422P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUVA420P, AV_PIX_FMT_YUV420P, + AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUVJ420P, + AV_PIX_FMT_YUVJ411P, AV_PIX_FMT_YUV411P, AV_PIX_FMT_YUV410P, + AV_PIX_FMT_YUV420P9, AV_PIX_FMT_YUV422P9, AV_PIX_FMT_YUV444P9, + AV_PIX_FMT_YUV420P10, AV_PIX_FMT_YUV422P10, AV_PIX_FMT_YUV444P10, + AV_PIX_FMT_YUV420P12, AV_PIX_FMT_YUV422P12, AV_PIX_FMT_YUV444P12, AV_PIX_FMT_YUV440P12, + AV_PIX_FMT_YUV420P14, AV_PIX_FMT_YUV422P14, AV_PIX_FMT_YUV444P14, + AV_PIX_FMT_YUV420P16, AV_PIX_FMT_YUV422P16, AV_PIX_FMT_YUV444P16, + AV_PIX_FMT_YUVA420P9, AV_PIX_FMT_YUVA422P9, AV_PIX_FMT_YUVA444P9, + AV_PIX_FMT_YUVA420P10, AV_PIX_FMT_YUVA422P10, AV_PIX_FMT_YUVA444P10, + AV_PIX_FMT_YUVA420P16, AV_PIX_FMT_YUVA422P16, AV_PIX_FMT_YUVA444P16, + AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRP9, AV_PIX_FMT_GBRP10, + AV_PIX_FMT_GBRP12, AV_PIX_FMT_GBRP14, AV_PIX_FMT_GBRP16, + AV_PIX_FMT_GBRAP, AV_PIX_FMT_GBRAP10, AV_PIX_FMT_GBRAP12, AV_PIX_FMT_GBRAP16, + AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY9, AV_PIX_FMT_GRAY10, AV_PIX_FMT_GRAY12, AV_PIX_FMT_GRAY14, AV_PIX_FMT_GRAY16, + AV_PIX_FMT_NONE + }; + AVFilterFormats *formats = ff_make_format_list(pixel_fmts); + if (!formats) + return AVERROR(ENOMEM); + return ff_set_common_formats(ctx, formats); +} + +#define WEAK_HFILTER(name, type, ldiv) \ +static void deblockh##name##_weak(uint8_t *dstp, ptrdiff_t dst_linesize, int block, \ + int ath, int bth, int gth, int dth, int max) \ +{ \ + type *dst; \ + int x; \ + \ + dst = (type *)dstp; \ + dst_linesize /= ldiv; \ + \ + for (x = 0; x < block; x++) { \ + int delta = dst[x] - dst[x - dst_linesize]; \ + int A, B, C, D, a, b, c, d; \ + \ + if (FFABS(delta) >= ath || \ + FFABS(dst[x - 1 * dst_linesize] - dst[x - 2 * dst_linesize]) >= bth || \ + FFABS(dst[x + 0 * dst_linesize] - dst[x + 1 * dst_linesize]) >= gth) \ + continue; \ + \ + A = dst[x - 2 * dst_linesize]; \ + B = dst[x - 1 * dst_linesize]; \ + C = dst[x + 0 * dst_linesize]; \ + D = dst[x + 1 * dst_linesize]; \ + \ + a = A + delta / 8; \ + b = B + delta / 2; \ + c = C - delta / 2; \ + d = D - delta / 8; \ + \ + dst[x - 2 * dst_linesize] = av_clip(a, 0, max); \ + dst[x - 1 * dst_linesize] = av_clip(b, 0, max); \ + dst[x + 0 * dst_linesize] = av_clip(c, 0, max); \ + dst[x + 1 * dst_linesize] = av_clip(d, 0, max); \ + } \ +} + +WEAK_HFILTER(8, uint8_t, 1) +WEAK_HFILTER(16, uint16_t, 2) + +#define WEAK_VFILTER(name, type, ldiv) \ +static void deblockv##name##_weak(uint8_t *dstp, ptrdiff_t dst_linesize, int block, \ + int ath, int bth, int gth, int dth, int max) \ +{ \ + type *dst; \ + int y; \ + \ + dst = (type *)dstp; \ + dst_linesize /= ldiv; \ + \ + for (y = 0; y < block; y++) { \ + int delta = dst[0] - dst[-1]; \ + int A, B, C, D, a, b, c, d; \ + \ + if (FFABS(delta) >= ath || \ + FFABS(dst[-1] - dst[-2]) >= bth || \ + FFABS(dst[0] - dst[1]) >= gth) \ + continue; \ + \ + A = dst[-2]; \ + B = dst[-1]; \ + C = dst[+0]; \ + D = dst[+1]; \ + \ + a = A + delta / 8; \ + b = B + delta / 2; \ + c = C - delta / 2; \ + d = D - delta / 8; \ + \ + dst[-2] = av_clip(a, 0, max); \ + dst[-1] = av_clip(b, 0, max); \ + dst[+0] = av_clip(c, 0, max); \ + dst[+1] = av_clip(d, 0, max); \ + \ + dst += dst_linesize; \ + } \ +} + +WEAK_VFILTER(8, uint8_t, 1) +WEAK_VFILTER(16, uint16_t, 2) + +#define STRONG_HFILTER(name, type, ldiv) \ +static void deblockh##name##_strong(uint8_t *dstp, ptrdiff_t dst_linesize, int block,\ + int ath, int bth, int gth, int dth, int max) \ +{ \ + type *dst; \ + int x; \ + \ + dst = (type *)dstp; \ + dst_linesize /= ldiv; \ + \ + for (x = 0; x < block; x++) { \ + int A, B, C, D, E, F, a, b, c, d, e, f; \ + int delta = dst[x] - dst[x - dst_linesize]; \ + \ + if (FFABS(delta) >= ath || \ + FFABS(dst[x - 1 * dst_linesize] - dst[x - 2 * dst_linesize]) >= bth || \ + FFABS(dst[x + 1 * dst_linesize] - dst[x + 2 * dst_linesize]) >= gth || \ + FFABS(dst[x + 0 * dst_linesize] - dst[x + 1 * dst_linesize]) >= dth) \ + continue; \ + \ + A = dst[x - 3 * dst_linesize]; \ + B = dst[x - 2 * dst_linesize]; \ + C = dst[x - 1 * dst_linesize]; \ + D = dst[x + 0 * dst_linesize]; \ + E = dst[x + 1 * dst_linesize]; \ + F = dst[x + 2 * dst_linesize]; \ + \ + a = A + delta / 8; \ + b = B + delta / 4; \ + c = C + delta / 2; \ + d = D - delta / 2; \ + e = E - delta / 4; \ + f = F - delta / 8; \ + \ + dst[x - 3 * dst_linesize] = av_clip(a, 0, max); \ + dst[x - 2 * dst_linesize] = av_clip(b, 0, max); \ + dst[x - 1 * dst_linesize] = av_clip(c, 0, max); \ + dst[x + 0 * dst_linesize] = av_clip(d, 0, max); \ + dst[x + 1 * dst_linesize] = av_clip(e, 0, max); \ + dst[x + 2 * dst_linesize] = av_clip(f, 0, max); \ + } \ +} + +STRONG_HFILTER(8, uint8_t, 1) +STRONG_HFILTER(16, uint16_t, 2) + +#define STRONG_VFILTER(name, type, ldiv) \ +static void deblockv##name##_strong(uint8_t *dstp, ptrdiff_t dst_linesize, int block,\ + int ath, int bth, int gth, int dth, int max) \ +{ \ + type *dst; \ + int y; \ + \ + dst = (type *)dstp; \ + dst_linesize /= ldiv; \ + \ + for (y = 0; y < block; y++) { \ + int A, B, C, D, E, F, a, b, c, d, e, f; \ + int delta = dst[0] - dst[-1]; \ + \ + if (FFABS(delta) >= ath || \ + FFABS(dst[-1] - dst[-2]) >= bth || \ + FFABS(dst[+1] - dst[+2]) >= gth || \ + FFABS(dst[+0] - dst[+1]) >= dth) \ + continue; \ + \ + A = dst[-3]; \ + B = dst[-2]; \ + C = dst[-1]; \ + D = dst[+0]; \ + E = dst[+1]; \ + F = dst[+2]; \ + \ + a = A + delta / 8; \ + b = B + delta / 4; \ + c = C + delta / 2; \ + d = D - delta / 2; \ + e = E - delta / 4; \ + f = F - delta / 8; \ + \ + dst[-3] = av_clip(a, 0, max); \ + dst[-2] = av_clip(b, 0, max); \ + dst[-1] = av_clip(c, 0, max); \ + dst[+0] = av_clip(d, 0, max); \ + dst[+1] = av_clip(e, 0, max); \ + dst[+2] = av_clip(f, 0, max); \ + \ + dst += dst_linesize; \ + } \ +} + +STRONG_VFILTER(8, uint8_t, 1) +STRONG_VFILTER(16, uint16_t, 2) + +static int config_output(AVFilterLink *outlink) +{ + AVFilterContext *ctx = outlink->src; + DeblockContext *s = ctx->priv; + AVFilterLink *inlink = ctx->inputs[0]; + + s->desc = av_pix_fmt_desc_get(outlink->format); + if (!s->desc) + return AVERROR_BUG; + s->nb_planes = av_pix_fmt_count_planes(outlink->format); + s->depth = s->desc->comp[0].depth; + s->bpc = (s->depth + 7) / 8; + s->max = (1 << s->depth) - 1; + s->ath = s->alpha * s->max; + s->bth = s->beta * s->max; + s->gth = s->gamma * s->max; + s->dth = s->delta * s->max; + + if (s->depth <= 8 && s->filter == WEAK) { + s->deblockh = deblockh8_weak; + s->deblockv = deblockv8_weak; + } else if (s->depth >= 8 && s->filter == WEAK) { + s->deblockh = deblockh16_weak; + s->deblockv = deblockv16_weak; + } + if (s->depth <= 8 && s->filter == STRONG) { + s->deblockh = deblockh8_strong; + s->deblockv = deblockv8_strong; + } else if (s->depth >= 8 && s->filter == STRONG) { + s->deblockh = deblockh16_strong; + s->deblockv = deblockv16_strong; + } + + s->planewidth[1] = s->planewidth[2] = AV_CEIL_RSHIFT(inlink->w, s->desc->log2_chroma_w); + s->planewidth[0] = s->planewidth[3] = inlink->w; + + s->planeheight[1] = s->planeheight[2] = AV_CEIL_RSHIFT(inlink->h, s->desc->log2_chroma_h); + s->planeheight[0] = s->planeheight[3] = inlink->h; + + return 0; +} + +static int filter_frame(AVFilterLink *inlink, AVFrame *in) +{ + AVFilterContext *ctx = inlink->dst; + AVFilterLink *outlink = ctx->outputs[0]; + DeblockContext *s = ctx->priv; + const int block = s->block; + AVFrame *out; + int plane, x, y; + + if (av_frame_is_writable(in)) { + out = in; + } else { + out = ff_get_video_buffer(outlink, outlink->w, outlink->h); + if (!out) { + av_frame_free(&in); + return AVERROR(ENOMEM); + } + av_frame_copy_props(out, in); + } + + for (plane = 0; plane < s->nb_planes; plane++) { + const int width = s->planewidth[plane]; + const int height = s->planeheight[plane]; + const uint8_t *src = (const uint8_t *)in->data[plane]; + uint8_t *dst = (uint8_t *)out->data[plane]; + + if (in != out) + av_image_copy_plane(dst, out->linesize[plane], + src, in->linesize[plane], + width * s->bpc, height); + + if (!((1 << plane) & s->planes)) + continue; + + for (x = block; x < width; x += block) + s->deblockv(dst + x * s->bpc, out->linesize[plane], + FFMIN(block, height), s->ath, s->bth, s->gth, s->dth, s->max); + + for (y = block; y < height; y += block) { + dst += out->linesize[plane] * block; + + s->deblockh(dst, out->linesize[plane], + FFMIN(block, width), + s->ath, s->bth, s->gth, s->dth, s->max); + + for (x = block; x < width; x += block) { + s->deblockh(dst + x * s->bpc, out->linesize[plane], + FFMIN(block, width - x), + s->ath, s->bth, s->gth, s->dth, s->max); + s->deblockv(dst + x * s->bpc, out->linesize[plane], + FFMIN(block, height - y), + s->ath, s->bth, s->gth, s->dth, s->max); + } + } + } + + if (in != out) + av_frame_free(&in); + return ff_filter_frame(outlink, out); +} + +#define OFFSET(x) offsetof(DeblockContext, x) +#define FLAGS AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_FILTERING_PARAM + +static const AVOption deblock_options[] = { + { "filter", "set type of filter", OFFSET(filter), AV_OPT_TYPE_INT, {.i64=STRONG},0, 1, FLAGS, "filter" }, + { "weak", 0, 0, AV_OPT_TYPE_CONST, {.i64=WEAK}, 0, 0, FLAGS, "filter" }, + { "strong", 0, 0, AV_OPT_TYPE_CONST, {.i64=STRONG},0, 0, FLAGS, "filter" }, + { "block", "set size of block", OFFSET(block), AV_OPT_TYPE_INT, {.i64=8}, 4, 512, FLAGS }, + { "alpha", "set 1st detection threshold", OFFSET(alpha), AV_OPT_TYPE_FLOAT, {.dbl=.098}, 0, 1, FLAGS }, + { "beta", "set 2nd detection threshold", OFFSET(beta), AV_OPT_TYPE_FLOAT, {.dbl=.05}, 0, 1, FLAGS }, + { "gamma", "set 3rd detection threshold", OFFSET(gamma), AV_OPT_TYPE_FLOAT, {.dbl=.05}, 0, 1, FLAGS }, + { "delta", "set 4th detection threshold", OFFSET(delta), AV_OPT_TYPE_FLOAT, {.dbl=.05}, 0, 1, FLAGS }, + { "planes", "set planes to filter", OFFSET(planes), AV_OPT_TYPE_INT, {.i64=15}, 0, 15, FLAGS }, + { NULL }, +}; + +static const AVFilterPad inputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + .filter_frame = filter_frame, + }, + { NULL } +}; + +static const AVFilterPad outputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + .config_props = config_output, + }, + { NULL } +}; + +AVFILTER_DEFINE_CLASS(deblock); + +AVFilter ff_vf_deblock = { + .name = "deblock", + .description = NULL_IF_CONFIG_SMALL("Deblock video."), + .priv_size = sizeof(DeblockContext), + .priv_class = &deblock_class, + .query_formats = query_formats, + .inputs = inputs, + .outputs = outputs, + .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC, +}; diff --git a/libavfilter/vf_dedot.c b/libavfilter/vf_dedot.c new file mode 100644 index 000000000..bb0f9e5ac --- /dev/null +++ b/libavfilter/vf_dedot.c @@ -0,0 +1,409 @@ +/* + * Copyright (c) 2018 Paul B Mahol + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/imgutils.h" +#include "libavutil/opt.h" +#include "libavutil/pixdesc.h" + +#include "avfilter.h" +#include "filters.h" +#include "formats.h" +#include "internal.h" +#include "video.h" + +typedef struct DedotContext { + const AVClass *class; + int m; + float lt; + float tl; + float tc; + float ct; + + const AVPixFmtDescriptor *desc; + int depth; + int max; + int luma2d; + int lumaT; + int chromaT1; + int chromaT2; + + int eof; + int eof_frames; + int nb_planes; + int planewidth[4]; + int planeheight[4]; + + AVFrame *frames[5]; + + int (*dedotcrawl)(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs); + int (*derainbow)(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs); +} DedotContext; + +static int query_formats(AVFilterContext *ctx) +{ + static const enum AVPixelFormat pixel_fmts[] = { + AV_PIX_FMT_YUVA444P, AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUV440P, + AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_YUVJ440P, + AV_PIX_FMT_YUVA422P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUVA420P, AV_PIX_FMT_YUV420P, + AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUVJ420P, + AV_PIX_FMT_YUVJ411P, AV_PIX_FMT_YUV411P, AV_PIX_FMT_YUV410P, + AV_PIX_FMT_YUV420P9, AV_PIX_FMT_YUV422P9, AV_PIX_FMT_YUV444P9, + AV_PIX_FMT_YUV420P10, AV_PIX_FMT_YUV422P10, AV_PIX_FMT_YUV444P10, + AV_PIX_FMT_YUV420P12, AV_PIX_FMT_YUV422P12, AV_PIX_FMT_YUV444P12, AV_PIX_FMT_YUV440P12, + AV_PIX_FMT_YUV420P14, AV_PIX_FMT_YUV422P14, AV_PIX_FMT_YUV444P14, + AV_PIX_FMT_YUV420P16, AV_PIX_FMT_YUV422P16, AV_PIX_FMT_YUV444P16, + AV_PIX_FMT_YUVA420P9, AV_PIX_FMT_YUVA422P9, AV_PIX_FMT_YUVA444P9, + AV_PIX_FMT_YUVA420P10, AV_PIX_FMT_YUVA422P10, AV_PIX_FMT_YUVA444P10, + AV_PIX_FMT_YUVA420P16, AV_PIX_FMT_YUVA422P16, AV_PIX_FMT_YUVA444P16, + AV_PIX_FMT_NONE + }; + AVFilterFormats *formats = ff_make_format_list(pixel_fmts); + if (!formats) + return AVERROR(ENOMEM); + return ff_set_common_formats(ctx, formats); +} + +#define DEFINE_DEDOTCRAWL(name, type, div) \ +static int dedotcrawl##name(AVFilterContext *ctx, void *arg, \ + int jobnr, int nb_jobs) \ +{ \ + DedotContext *s = ctx->priv; \ + AVFrame *out = arg; \ + int src_linesize = s->frames[2]->linesize[0] / div; \ + int dst_linesize = out->linesize[0] / div; \ + int p0_linesize = s->frames[0]->linesize[0] / div; \ + int p1_linesize = s->frames[1]->linesize[0] / div; \ + int p3_linesize = s->frames[3]->linesize[0] / div; \ + int p4_linesize = s->frames[4]->linesize[0] / div; \ + const int h = s->planeheight[0]; \ + int slice_start = (h * jobnr) / nb_jobs; \ + int slice_end = (h * (jobnr+1)) / nb_jobs; \ + type *p0 = (type *)s->frames[0]->data[0]; \ + type *p1 = (type *)s->frames[1]->data[0]; \ + type *p3 = (type *)s->frames[3]->data[0]; \ + type *p4 = (type *)s->frames[4]->data[0]; \ + type *src = (type *)s->frames[2]->data[0]; \ + type *dst = (type *)out->data[0]; \ + const int luma2d = s->luma2d; \ + const int lumaT = s->lumaT; \ + \ + if (!slice_start) { \ + slice_start++; \ + } \ + p0 += p0_linesize * slice_start; \ + p1 += p1_linesize * slice_start; \ + p3 += p3_linesize * slice_start; \ + p4 += p4_linesize * slice_start; \ + src += src_linesize * slice_start; \ + dst += dst_linesize * slice_start; \ + if (slice_end == h) { \ + slice_end--; \ + } \ + for (int y = slice_start; y < slice_end; y++) { \ + for (int x = 1; x < s->planewidth[0] - 1; x++) { \ + int above = src[x - src_linesize]; \ + int bellow = src[x + src_linesize]; \ + int cur = src[x]; \ + int left = src[x - 1]; \ + int right = src[x + 1]; \ + \ + if (FFABS(above + bellow - 2 * cur) <= luma2d && \ + FFABS(left + right - 2 * cur) <= luma2d) \ + continue; \ + \ + if (FFABS(cur - p0[x]) <= lumaT && \ + FFABS(cur - p4[x]) <= lumaT && \ + FFABS(p1[x] - p3[x]) <= lumaT) { \ + int diff1 = FFABS(cur - p1[x]); \ + int diff2 = FFABS(cur - p3[x]); \ + \ + if (diff1 < diff2) \ + dst[x] = (src[x] + p1[x] + 1) >> 1; \ + else \ + dst[x] = (src[x] + p3[x] + 1) >> 1; \ + } \ + } \ + \ + dst += dst_linesize; \ + src += src_linesize; \ + p0 += p0_linesize; \ + p1 += p1_linesize; \ + p3 += p3_linesize; \ + p4 += p4_linesize; \ + } \ + return 0; \ +} + +DEFINE_DEDOTCRAWL(8, uint8_t, 1) +DEFINE_DEDOTCRAWL(16, uint16_t, 2) + +typedef struct ThreadData { + AVFrame *out; + int plane; +} ThreadData; + +#define DEFINE_DERAINBOW(name, type, div) \ +static int derainbow##name(AVFilterContext *ctx, void *arg, \ + int jobnr, int nb_jobs) \ +{ \ + DedotContext *s = ctx->priv; \ + ThreadData *td = arg; \ + AVFrame *out = td->out; \ + const int plane = td->plane; \ + const int h = s->planeheight[plane]; \ + int slice_start = (h * jobnr) / nb_jobs; \ + int slice_end = (h * (jobnr+1)) / nb_jobs; \ + int src_linesize = s->frames[2]->linesize[plane] / div; \ + int dst_linesize = out->linesize[plane] / div; \ + int p0_linesize = s->frames[0]->linesize[plane] / div; \ + int p1_linesize = s->frames[1]->linesize[plane] / div; \ + int p3_linesize = s->frames[3]->linesize[plane] / div; \ + int p4_linesize = s->frames[4]->linesize[plane] / div; \ + type *p0 = (type *)s->frames[0]->data[plane]; \ + type *p1 = (type *)s->frames[1]->data[plane]; \ + type *p3 = (type *)s->frames[3]->data[plane]; \ + type *p4 = (type *)s->frames[4]->data[plane]; \ + type *src = (type *)s->frames[2]->data[plane]; \ + type *dst = (type *)out->data[plane]; \ + const int chromaT1 = s->chromaT1; \ + const int chromaT2 = s->chromaT2; \ + \ + p0 += slice_start * p0_linesize; \ + p1 += slice_start * p1_linesize; \ + p3 += slice_start * p3_linesize; \ + p4 += slice_start * p4_linesize; \ + src += slice_start * src_linesize; \ + dst += slice_start * dst_linesize; \ + for (int y = slice_start; y < slice_end; y++) { \ + for (int x = 0; x < s->planewidth[plane]; x++) { \ + int cur = src[x]; \ + \ + if (FFABS(cur - p0[x]) <= chromaT1 && \ + FFABS(cur - p4[x]) <= chromaT1 && \ + FFABS(p1[x] - p3[x]) <= chromaT1 && \ + FFABS(cur - p1[x]) > chromaT2 && \ + FFABS(cur - p3[x]) > chromaT2) { \ + int diff1 = FFABS(cur - p1[x]); \ + int diff2 = FFABS(cur - p3[x]); \ + \ + if (diff1 < diff2) \ + dst[x] = (src[x] + p1[x] + 1) >> 1; \ + else \ + dst[x] = (src[x] + p3[x] + 1) >> 1; \ + } \ + } \ + \ + dst += dst_linesize; \ + src += src_linesize; \ + p0 += p0_linesize; \ + p1 += p1_linesize; \ + p3 += p3_linesize; \ + p4 += p4_linesize; \ + } \ + return 0; \ +} + +DEFINE_DERAINBOW(8, uint8_t, 1) +DEFINE_DERAINBOW(16, uint16_t, 2) + +static int config_output(AVFilterLink *outlink) +{ + AVFilterContext *ctx = outlink->src; + DedotContext *s = ctx->priv; + AVFilterLink *inlink = ctx->inputs[0]; + + s->desc = av_pix_fmt_desc_get(outlink->format); + if (!s->desc) + return AVERROR_BUG; + s->nb_planes = av_pix_fmt_count_planes(outlink->format); + s->depth = s->desc->comp[0].depth; + s->max = (1 << s->depth) - 1; + s->luma2d = s->lt * s->max; + s->lumaT = s->tl * s->max; + s->chromaT1 = s->tc * s->max; + s->chromaT2 = s->ct * s->max; + + s->planewidth[1] = s->planewidth[2] = AV_CEIL_RSHIFT(inlink->w, s->desc->log2_chroma_w); + s->planewidth[0] = s->planewidth[3] = inlink->w; + + s->planeheight[1] = s->planeheight[2] = AV_CEIL_RSHIFT(inlink->h, s->desc->log2_chroma_h); + s->planeheight[0] = s->planeheight[3] = inlink->h; + + if (s->depth <= 8) { + s->dedotcrawl = dedotcrawl8; + s->derainbow = derainbow8; + } else { + s->dedotcrawl = dedotcrawl16; + s->derainbow = derainbow16; + } + + return 0; +} + +static int activate(AVFilterContext *ctx) +{ + AVFilterLink *inlink = ctx->inputs[0]; + AVFilterLink *outlink = ctx->outputs[0]; + DedotContext *s = ctx->priv; + AVFrame *frame = NULL; + int64_t pts; + int status; + int ret = 0; + + FF_FILTER_FORWARD_STATUS_BACK(outlink, inlink); + + if (s->eof == 0) { + ret = ff_inlink_consume_frame(inlink, &frame); + if (ret < 0) + return ret; + } + if (frame || s->eof_frames > 0) { + AVFrame *out = NULL; + + if (frame) { + for (int i = 2; i < 5; i++) { + if (!s->frames[i]) + s->frames[i] = av_frame_clone(frame); + } + av_frame_free(&frame); + } else { + s->eof_frames--; + s->frames[4] = av_frame_clone(s->frames[3]); + } + + if (s->frames[0] && + s->frames[1] && + s->frames[2] && + s->frames[3] && + s->frames[4]) { + out = av_frame_clone(s->frames[2]); + if (out && !ctx->is_disabled) { + ret = av_frame_make_writable(out); + if (ret >= 0) { + if (s->m & 1) + ctx->internal->execute(ctx, s->dedotcrawl, out, NULL, + FFMIN(s->planeheight[0], + ff_filter_get_nb_threads(ctx))); + if (s->m & 2) { + ThreadData td; + td.out = out; td.plane = 1; + ctx->internal->execute(ctx, s->derainbow, &td, NULL, + FFMIN(s->planeheight[1], + ff_filter_get_nb_threads(ctx))); + td.plane = 2; + ctx->internal->execute(ctx, s->derainbow, &td, NULL, + FFMIN(s->planeheight[2], + ff_filter_get_nb_threads(ctx))); + } + } + } else if (!out) { + ret = AVERROR(ENOMEM); + } + } + + av_frame_free(&s->frames[0]); + s->frames[0] = s->frames[1]; + s->frames[1] = s->frames[2]; + s->frames[2] = s->frames[3]; + s->frames[3] = s->frames[4]; + s->frames[4] = NULL; + + if (ret < 0) + return ret; + if (out) + return ff_filter_frame(outlink, out); + } + + if (s->eof) { + if (s->eof_frames <= 0) { + ff_outlink_set_status(outlink, AVERROR_EOF, s->frames[2]->pts); + } else { + ff_filter_set_ready(ctx, 10); + } + return 0; + } + + if (!s->eof && ff_inlink_acknowledge_status(inlink, &status, &pts)) { + if (status == AVERROR_EOF) { + s->eof = 1; + s->eof_frames = 2; + ff_filter_set_ready(ctx, 10); + return 0; + } + } + + FF_FILTER_FORWARD_WANTED(outlink, inlink); + + return FFERROR_NOT_READY; +} + +static av_cold void uninit(AVFilterContext *ctx) +{ + DedotContext *s = ctx->priv; + + for (int i = 0; i < 5; i++) + av_frame_free(&s->frames[i]); +} + +#define OFFSET(x) offsetof(DedotContext, x) +#define FLAGS AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_FILTERING_PARAM + +static const AVOption dedot_options[] = { + { "m", "set filtering mode", OFFSET( m), AV_OPT_TYPE_FLAGS, {.i64=3}, 0, 3, FLAGS, "m" }, + { "dotcrawl", 0, 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, FLAGS, "m" }, + { "rainbows", 0, 0, AV_OPT_TYPE_CONST, {.i64=2}, 0, 0, FLAGS, "m" }, + { "lt", "set spatial luma threshold", OFFSET(lt), AV_OPT_TYPE_FLOAT, {.dbl=.079}, 0, 1, FLAGS }, + { "tl", "set tolerance for temporal luma", OFFSET(tl), AV_OPT_TYPE_FLOAT, {.dbl=.079}, 0, 1, FLAGS }, + { "tc", "set tolerance for chroma temporal variation", OFFSET(tc), AV_OPT_TYPE_FLOAT, {.dbl=.058}, 0, 1, FLAGS }, + { "ct", "set temporal chroma threshold", OFFSET(ct), AV_OPT_TYPE_FLOAT, {.dbl=.019}, 0, 1, FLAGS }, + { NULL }, +}; + +static const AVFilterPad inputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + }, + { NULL } +}; + +static const AVFilterPad outputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + .config_props = config_output, + }, + { NULL } +}; + +AVFILTER_DEFINE_CLASS(dedot); + +AVFilter ff_vf_dedot = { + .name = "dedot", + .description = NULL_IF_CONFIG_SMALL("Reduce cross-luminance and cross-color."), + .priv_size = sizeof(DedotContext), + .priv_class = &dedot_class, + .query_formats = query_formats, + .activate = activate, + .uninit = uninit, + .inputs = inputs, + .outputs = outputs, + .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | AVFILTER_FLAG_SLICE_THREADS, +}; diff --git a/libavfilter/vf_deflicker.c b/libavfilter/vf_deflicker.c index 863a3508c..b038b977f 100644 --- a/libavfilter/vf_deflicker.c +++ b/libavfilter/vf_deflicker.c @@ -95,7 +95,7 @@ static int query_formats(AVFilterContext *ctx) { static const enum AVPixelFormat pixel_fmts[] = { AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY9, AV_PIX_FMT_GRAY10, - AV_PIX_FMT_GRAY12, AV_PIX_FMT_GRAY16, + AV_PIX_FMT_GRAY12, AV_PIX_FMT_GRAY14, AV_PIX_FMT_GRAY16, AV_PIX_FMT_YUV410P, AV_PIX_FMT_YUV411P, AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV440P, AV_PIX_FMT_YUV444P, diff --git a/libavfilter/vf_deinterlace_qsv.c b/libavfilter/vf_deinterlace_qsv.c index c9e76c605..80217c841 100644 --- a/libavfilter/vf_deinterlace_qsv.c +++ b/libavfilter/vf_deinterlace_qsv.c @@ -83,7 +83,7 @@ typedef struct QSVDeintContext { int mode; } QSVDeintContext; -static void qsvdeint_uninit(AVFilterContext *ctx) +static av_cold void qsvdeint_uninit(AVFilterContext *ctx) { QSVDeintContext *s = ctx->priv; QSVFrame *cur; @@ -202,6 +202,11 @@ static int init_out_session(AVFilterContext *ctx) } } + if (err != MFX_ERR_NONE) { + av_log(ctx, AV_LOG_ERROR, "Error getting the session handle\n"); + return AVERROR_UNKNOWN; + } + /* create a "slave" session with those same properties, to be used for * actual deinterlacing */ err = MFXInit(impl, &ver, &s->session); @@ -414,9 +419,11 @@ static int submit_frame(AVFilterContext *ctx, AVFrame *frame, qf->surface.Info.PicStruct = !qf->frame->interlaced_frame ? MFX_PICSTRUCT_PROGRESSIVE : (qf->frame->top_field_first ? MFX_PICSTRUCT_FIELD_TFF : MFX_PICSTRUCT_FIELD_BFF); - if (qf->frame->repeat_pict == 1) + if (qf->frame->repeat_pict == 1) { qf->surface.Info.PicStruct |= MFX_PICSTRUCT_FIELD_REPEATED; - else if (qf->frame->repeat_pict == 2) + qf->surface.Info.PicStruct |= qf->frame->top_field_first ? MFX_PICSTRUCT_FIELD_TFF : + MFX_PICSTRUCT_FIELD_BFF; + } else if (qf->frame->repeat_pict == 2) qf->surface.Info.PicStruct |= MFX_PICSTRUCT_FRAME_DOUBLING; else if (qf->frame->repeat_pict == 4) qf->surface.Info.PicStruct |= MFX_PICSTRUCT_FRAME_TRIPLING; diff --git a/libavfilter/vf_deinterlace_vaapi.c b/libavfilter/vf_deinterlace_vaapi.c index f7a262d0c..72d034981 100644 --- a/libavfilter/vf_deinterlace_vaapi.c +++ b/libavfilter/vf_deinterlace_vaapi.c @@ -113,6 +113,7 @@ static int deint_vaapi_build_filter_params(AVFilterContext *avctx) av_log(avctx, AV_LOG_ERROR, "Deinterlacing mode %d (%s) is " "not supported.\n", ctx->mode, deint_vaapi_mode_name(ctx->mode)); + return AVERROR(EINVAL); } } @@ -180,12 +181,11 @@ static int deint_vaapi_filter_frame(AVFilterLink *inlink, AVFrame *input_frame) VAAPIVPPContext *vpp_ctx = avctx->priv; DeintVAAPIContext *ctx = avctx->priv; AVFrame *output_frame = NULL; - VASurfaceID input_surface, output_surface; + VASurfaceID input_surface; VASurfaceID backward_references[MAX_REFERENCES]; VASurfaceID forward_references[MAX_REFERENCES]; VAProcPipelineParameterBuffer params; VAProcFilterParameterBufferDeinterlacing *filter_params; - VARectangle input_region; VAStatus vas; void *filter_params_addr = NULL; int err, i, field, current_frame_index; @@ -237,30 +237,14 @@ static int deint_vaapi_filter_frame(AVFilterLink *inlink, AVFrame *input_frame) goto fail; } - output_surface = (VASurfaceID)(uintptr_t)output_frame->data[3]; - av_log(avctx, AV_LOG_DEBUG, "Using surface %#x for " - "deinterlace output.\n", output_surface); + err = av_frame_copy_props(output_frame, input_frame); + if (err < 0) + return err; - memset(¶ms, 0, sizeof(params)); - - input_region = (VARectangle) { - .x = 0, - .y = 0, - .width = input_frame->width, - .height = input_frame->height, - }; - - params.surface = input_surface; - params.surface_region = &input_region; - params.surface_color_standard = - ff_vaapi_vpp_colour_standard(input_frame->colorspace); - - params.output_region = NULL; - params.output_background_color = 0xff000000; - params.output_color_standard = params.surface_color_standard; - - params.pipeline_flags = 0; - params.filter_flags = VA_FRAME_PICTURE; + err = ff_vaapi_vpp_init_params(avctx, ¶ms, + input_frame, output_frame); + if (err < 0) + goto fail; if (!ctx->auto_enable || input_frame->interlaced_frame) { vas = vaMapBuffer(vpp_ctx->hwctx->display, vpp_ctx->filter_buffers[0], @@ -300,11 +284,7 @@ static int deint_vaapi_filter_frame(AVFilterLink *inlink, AVFrame *input_frame) params.num_filters = 0; } - err = ff_vaapi_vpp_render_picture(avctx, ¶ms, output_surface); - if (err < 0) - goto fail; - - err = av_frame_copy_props(output_frame, input_frame); + err = ff_vaapi_vpp_render_picture(avctx, ¶ms, output_frame); if (err < 0) goto fail; diff --git a/libavfilter/vf_derain.c b/libavfilter/vf_derain.c new file mode 100644 index 000000000..c380b4012 --- /dev/null +++ b/libavfilter/vf_derain.c @@ -0,0 +1,212 @@ +/* + * Copyright (c) 2019 Xuewei Meng + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * Filter implementing image derain filter using deep convolutional networks. + * http://openaccess.thecvf.com/content_ECCV_2018/html/Xia_Li_Recurrent_Squeeze-and-Excitation_Context_ECCV_2018_paper.html + */ + +#include "libavformat/avio.h" +#include "libavutil/opt.h" +#include "avfilter.h" +#include "dnn_interface.h" +#include "formats.h" +#include "internal.h" + +typedef struct DRContext { + const AVClass *class; + + char *model_filename; + DNNBackendType backend_type; + DNNModule *dnn_module; + DNNModel *model; + DNNInputData input; + DNNData output; +} DRContext; + +#define CLIP(x, min, max) (x < min ? min : (x > max ? max : x)) +#define OFFSET(x) offsetof(DRContext, x) +#define FLAGS AV_OPT_FLAG_FILTERING_PARAM | AV_OPT_FLAG_VIDEO_PARAM +static const AVOption derain_options[] = { + { "dnn_backend", "DNN backend", OFFSET(backend_type), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, FLAGS, "backend" }, + { "native", "native backend flag", 0, AV_OPT_TYPE_CONST, { .i64 = 0 }, 0, 0, FLAGS, "backend" }, +#if (CONFIG_LIBTENSORFLOW == 1) + { "tensorflow", "tensorflow backend flag", 0, AV_OPT_TYPE_CONST, { .i64 = 1 }, 0, 0, FLAGS, "backend" }, +#endif + { "model", "path to model file", OFFSET(model_filename), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, FLAGS }, + { NULL } +}; + +AVFILTER_DEFINE_CLASS(derain); + +static int query_formats(AVFilterContext *ctx) +{ + AVFilterFormats *formats; + const enum AVPixelFormat pixel_fmts[] = { + AV_PIX_FMT_RGB24, + AV_PIX_FMT_NONE + }; + + formats = ff_make_format_list(pixel_fmts); + + return ff_set_common_formats(ctx, formats); +} + +static int config_inputs(AVFilterLink *inlink) +{ + AVFilterContext *ctx = inlink->dst; + DRContext *dr_context = ctx->priv; + const char *model_output_name = "y"; + DNNReturnType result; + + dr_context->input.width = inlink->w; + dr_context->input.height = inlink->h; + dr_context->input.channels = 3; + + result = (dr_context->model->set_input_output)(dr_context->model->model, &dr_context->input, "x", &model_output_name, 1); + if (result != DNN_SUCCESS) { + av_log(ctx, AV_LOG_ERROR, "could not set input and output for the model\n"); + return AVERROR(EIO); + } + + return 0; +} + +static int filter_frame(AVFilterLink *inlink, AVFrame *in) +{ + AVFilterContext *ctx = inlink->dst; + AVFilterLink *outlink = ctx->outputs[0]; + DRContext *dr_context = ctx->priv; + DNNReturnType dnn_result; + int pad_size; + + AVFrame *out = ff_get_video_buffer(outlink, outlink->w, outlink->h); + if (!out) { + av_log(ctx, AV_LOG_ERROR, "could not allocate memory for output frame\n"); + av_frame_free(&in); + return AVERROR(ENOMEM); + } + + av_frame_copy_props(out, in); + + for (int i = 0; i < in->height; i++){ + for(int j = 0; j < in->width * 3; j++){ + int k = i * in->linesize[0] + j; + int t = i * in->width * 3 + j; + ((float *)dr_context->input.data)[t] = in->data[0][k] / 255.0; + } + } + + dnn_result = (dr_context->dnn_module->execute_model)(dr_context->model, &dr_context->output, 1); + if (dnn_result != DNN_SUCCESS){ + av_log(ctx, AV_LOG_ERROR, "failed to execute model\n"); + return AVERROR(EIO); + } + + out->height = dr_context->output.height; + out->width = dr_context->output.width; + outlink->h = dr_context->output.height; + outlink->w = dr_context->output.width; + pad_size = (in->height - out->height) >> 1; + + for (int i = 0; i < out->height; i++){ + for(int j = 0; j < out->width * 3; j++){ + int k = i * out->linesize[0] + j; + int t = i * out->width * 3 + j; + + int t_in = (i + pad_size) * in->width * 3 + j + pad_size * 3; + out->data[0][k] = CLIP((int)((((float *)dr_context->input.data)[t_in] - dr_context->output.data[t]) * 255), 0, 255); + } + } + + av_frame_free(&in); + + return ff_filter_frame(outlink, out); +} + +static av_cold int init(AVFilterContext *ctx) +{ + DRContext *dr_context = ctx->priv; + + dr_context->input.dt = DNN_FLOAT; + dr_context->dnn_module = ff_get_dnn_module(dr_context->backend_type); + if (!dr_context->dnn_module) { + av_log(ctx, AV_LOG_ERROR, "could not create DNN module for requested backend\n"); + return AVERROR(ENOMEM); + } + if (!dr_context->model_filename) { + av_log(ctx, AV_LOG_ERROR, "model file for network is not specified\n"); + return AVERROR(EINVAL); + } + if (!dr_context->dnn_module->load_model) { + av_log(ctx, AV_LOG_ERROR, "load_model for network is not specified\n"); + return AVERROR(EINVAL); + } + + dr_context->model = (dr_context->dnn_module->load_model)(dr_context->model_filename); + if (!dr_context->model) { + av_log(ctx, AV_LOG_ERROR, "could not load DNN model\n"); + return AVERROR(EINVAL); + } + + return 0; +} + +static av_cold void uninit(AVFilterContext *ctx) +{ + DRContext *dr_context = ctx->priv; + + if (dr_context->dnn_module) { + (dr_context->dnn_module->free_model)(&dr_context->model); + av_freep(&dr_context->dnn_module); + } +} + +static const AVFilterPad derain_inputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + .config_props = config_inputs, + .filter_frame = filter_frame, + }, + { NULL } +}; + +static const AVFilterPad derain_outputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + }, + { NULL } +}; + +AVFilter ff_vf_derain = { + .name = "derain", + .description = NULL_IF_CONFIG_SMALL("Apply derain filter to the input."), + .priv_size = sizeof(DRContext), + .init = init, + .uninit = uninit, + .query_formats = query_formats, + .inputs = derain_inputs, + .outputs = derain_outputs, + .priv_class = &derain_class, + .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC, +}; diff --git a/libavfilter/vf_deshake.c b/libavfilter/vf_deshake.c index 55ce5e18a..c8480e74d 100644 --- a/libavfilter/vf_deshake.c +++ b/libavfilter/vf_deshake.c @@ -196,7 +196,7 @@ static int block_contrast(uint8_t *src, int x, int y, int stride, int blocksize) for (i = 0; i <= blocksize * 2; i++) { // We use a width of 16 here to match the sad function for (j = 0; j <= 15; j++) { - pos = (y - i) * stride + (x - j); + pos = (y + i) * stride + (x + j); if (src[pos] < lowest) lowest = src[pos]; else if (src[pos] > highest) { diff --git a/libavfilter/vf_detelecine.c b/libavfilter/vf_detelecine.c index 0d1e2f2ff..0199214c3 100644 --- a/libavfilter/vf_detelecine.c +++ b/libavfilter/vf_detelecine.c @@ -206,6 +206,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *inpicref) if (s->nskip_fields >= 2) { s->nskip_fields -= 2; + av_frame_free(&inpicref); return 0; } else if (s->nskip_fields >= 1) { for (i = 0; i < s->nb_planes; i++) { @@ -216,6 +217,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *inpicref) } s->occupied = 1; s->nskip_fields--; + av_frame_free(&inpicref); return 0; } diff --git a/libavfilter/vf_displace.c b/libavfilter/vf_displace.c index 768af6def..e4c033061 100644 --- a/libavfilter/vf_displace.c +++ b/libavfilter/vf_displace.c @@ -265,7 +265,7 @@ static int process_frame(FFFrameSync *fs) s->displace(s, in, xpic, ypic, out); } - out->pts = av_rescale_q(in->pts, s->fs.time_base, outlink->time_base); + out->pts = av_rescale_q(s->fs.pts, s->fs.time_base, outlink->time_base); return ff_filter_frame(outlink, out); } @@ -332,7 +332,6 @@ static int config_output(AVFilterLink *outlink) outlink->w = srclink->w; outlink->h = srclink->h; - outlink->time_base = srclink->time_base; outlink->sample_aspect_ratio = srclink->sample_aspect_ratio; outlink->frame_rate = srclink->frame_rate; @@ -356,7 +355,10 @@ static int config_output(AVFilterLink *outlink) s->fs.opaque = s; s->fs.on_event = process_frame; - return ff_framesync_configure(&s->fs); + ret = ff_framesync_configure(&s->fs); + outlink->time_base = s->fs.time_base; + + return ret; } static int activate(AVFilterContext *ctx) diff --git a/libavfilter/vf_drawtext.c b/libavfilter/vf_drawtext.c index e8905a40d..8f4badbdb 100644 --- a/libavfilter/vf_drawtext.c +++ b/libavfilter/vf_drawtext.c @@ -88,6 +88,9 @@ static const char *const var_names[] = { "x", "y", "pict_type", + "pkt_pos", + "pkt_duration", + "pkt_size", NULL }; @@ -125,6 +128,9 @@ enum var_name { VAR_X, VAR_Y, VAR_PICT_TYPE, + VAR_PKT_POS, + VAR_PKT_DURATION, + VAR_PKT_SIZE, VAR_VARS_NB }; @@ -862,20 +868,49 @@ static int config_input(AVFilterLink *inlink) static int command(AVFilterContext *ctx, const char *cmd, const char *arg, char *res, int res_len, int flags) { - DrawTextContext *s = ctx->priv; + DrawTextContext *old = ctx->priv; + DrawTextContext *new = NULL; + int ret; if (!strcmp(cmd, "reinit")) { - int ret; - uninit(ctx); - s->reinit = 1; - if ((ret = av_set_options_string(ctx, arg, "=", ":")) < 0) - return ret; - if ((ret = init(ctx)) < 0) - return ret; - return config_input(ctx->inputs[0]); - } + new = av_mallocz(sizeof(DrawTextContext)); + if (!new) + return AVERROR(ENOMEM); - return AVERROR(ENOSYS); + new->class = &drawtext_class; + ret = av_opt_copy(new, old); + if (ret < 0) + goto fail; + + ctx->priv = new; + ret = av_set_options_string(ctx, arg, "=", ":"); + if (ret < 0) { + ctx->priv = old; + goto fail; + } + + ret = init(ctx); + if (ret < 0) { + uninit(ctx); + ctx->priv = old; + goto fail; + } + + new->reinit = 1; + + ctx->priv = old; + uninit(ctx); + av_freep(&old); + + ctx->priv = new; + return config_input(ctx->inputs[0]); + } else + return AVERROR(ENOSYS); + +fail: + av_log(ctx, AV_LOG_ERROR, "Failed to process command. Continuing with existing parameters.\n"); + av_freep(&new); + return ret; } static int func_pict_type(AVFilterContext *ctx, AVBPrint *bp, @@ -916,6 +951,14 @@ static int func_pts(AVFilterContext *ctx, AVBPrint *bp, sign = '-'; ms = -ms; } + if (argc >= 3) { + if (!strcmp(argv[2], "24HH")) { + ms %= 24 * 60 * 60 * 1000; + } else { + av_log(ctx, AV_LOG_ERROR, "Invalid argument '%s'\n", argv[2]); + return AVERROR(EINVAL); + } + } av_bprintf(bp, "%c%02d:%02d:%02d.%03d", sign, (int)(ms / (60 * 60 * 1000)), (int)(ms / (60 * 1000)) % 60, @@ -1399,8 +1442,8 @@ static int draw_text(AVFilterContext *ctx, AVFrame *frame, update_color_with_alpha(s, &bordercolor, s->bordercolor); update_color_with_alpha(s, &boxcolor , s->boxcolor ); - box_w = FFMIN(width - 1 , max_text_line_w); - box_h = FFMIN(height - 1, y + s->max_glyph_h); + box_w = max_text_line_w; + box_h = y + s->max_glyph_h; if (s->fix_bounds) { @@ -1479,6 +1522,9 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame) NAN : frame->pts * av_q2d(inlink->time_base); s->var_values[VAR_PICT_TYPE] = frame->pict_type; + s->var_values[VAR_PKT_POS] = frame->pkt_pos; + s->var_values[VAR_PKT_DURATION] = frame->pkt_duration * av_q2d(inlink->time_base); + s->var_values[VAR_PKT_SIZE] = frame->pkt_size; s->metadata = frame->metadata; draw_text(ctx, frame, frame->width, frame->height); diff --git a/libavfilter/vf_edgedetect.c b/libavfilter/vf_edgedetect.c index 173f9fe16..a0ddcbbf5 100644 --- a/libavfilter/vf_edgedetect.c +++ b/libavfilter/vf_edgedetect.c @@ -26,15 +26,25 @@ */ #include "libavutil/avassert.h" +#include "libavutil/imgutils.h" #include "libavutil/opt.h" #include "avfilter.h" #include "formats.h" #include "internal.h" #include "video.h" +#define PLANE_R 0x4 +#define PLANE_G 0x1 +#define PLANE_B 0x2 +#define PLANE_Y 0x1 +#define PLANE_U 0x2 +#define PLANE_V 0x4 +#define PLANE_A 0x8 + enum FilterMode { MODE_WIRES, MODE_COLORMIX, + MODE_CANNY, NB_MODE }; @@ -42,11 +52,13 @@ struct plane_info { uint8_t *tmpbuf; uint16_t *gradients; char *directions; + int width, height; }; typedef struct EdgeDetectContext { const AVClass *class; struct plane_info planes[3]; + int filter_planes; int nb_planes; double low, high; uint8_t low_u8, high_u8; @@ -61,6 +73,14 @@ static const AVOption edgedetect_options[] = { { "mode", "set mode", OFFSET(mode), AV_OPT_TYPE_INT, {.i64=MODE_WIRES}, 0, NB_MODE-1, FLAGS, "mode" }, { "wires", "white/gray wires on black", 0, AV_OPT_TYPE_CONST, {.i64=MODE_WIRES}, INT_MIN, INT_MAX, FLAGS, "mode" }, { "colormix", "mix colors", 0, AV_OPT_TYPE_CONST, {.i64=MODE_COLORMIX}, INT_MIN, INT_MAX, FLAGS, "mode" }, + { "canny", "detect edges on planes", 0, AV_OPT_TYPE_CONST, {.i64=MODE_CANNY}, INT_MIN, INT_MAX, FLAGS, "mode" }, + { "planes", "set planes to filter", OFFSET(filter_planes), AV_OPT_TYPE_FLAGS, {.i64=7}, 1, 0x7, FLAGS, "flags" }, + { "y", "filter luma plane", 0, AV_OPT_TYPE_CONST, {.i64=PLANE_Y}, 0, 0, FLAGS, "flags" }, + { "u", "filter u plane", 0, AV_OPT_TYPE_CONST, {.i64=PLANE_U}, 0, 0, FLAGS, "flags" }, + { "v", "filter v plane", 0, AV_OPT_TYPE_CONST, {.i64=PLANE_V}, 0, 0, FLAGS, "flags" }, + { "r", "filter red plane", 0, AV_OPT_TYPE_CONST, {.i64=PLANE_R}, 0, 0, FLAGS, "flags" }, + { "g", "filter green plane", 0, AV_OPT_TYPE_CONST, {.i64=PLANE_G}, 0, 0, FLAGS, "flags" }, + { "b", "filter blue plane", 0, AV_OPT_TYPE_CONST, {.i64=PLANE_B}, 0, 0, FLAGS, "flags" }, { NULL } }; @@ -79,6 +99,7 @@ static int query_formats(AVFilterContext *ctx) { const EdgeDetectContext *edgedetect = ctx->priv; static const enum AVPixelFormat wires_pix_fmts[] = {AV_PIX_FMT_GRAY8, AV_PIX_FMT_NONE}; + static const enum AVPixelFormat canny_pix_fmts[] = {AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV444P, AV_PIX_FMT_GBRP, AV_PIX_FMT_GRAY8, AV_PIX_FMT_NONE}; static const enum AVPixelFormat colormix_pix_fmts[] = {AV_PIX_FMT_GBRP, AV_PIX_FMT_GRAY8, AV_PIX_FMT_NONE}; AVFilterFormats *fmts_list; const enum AVPixelFormat *pix_fmts = NULL; @@ -87,6 +108,8 @@ static int query_formats(AVFilterContext *ctx) pix_fmts = wires_pix_fmts; } else if (edgedetect->mode == MODE_COLORMIX) { pix_fmts = colormix_pix_fmts; + } else if (edgedetect->mode == MODE_CANNY) { + pix_fmts = canny_pix_fmts; } else { av_assert0(0); } @@ -101,14 +124,19 @@ static int config_props(AVFilterLink *inlink) int p; AVFilterContext *ctx = inlink->dst; EdgeDetectContext *edgedetect = ctx->priv; + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format); edgedetect->nb_planes = inlink->format == AV_PIX_FMT_GRAY8 ? 1 : 3; for (p = 0; p < edgedetect->nb_planes; p++) { struct plane_info *plane = &edgedetect->planes[p]; + int vsub = p ? desc->log2_chroma_h : 0; + int hsub = p ? desc->log2_chroma_w : 0; - plane->tmpbuf = av_malloc(inlink->w * inlink->h); - plane->gradients = av_calloc(inlink->w * inlink->h, sizeof(*plane->gradients)); - plane->directions = av_malloc(inlink->w * inlink->h); + plane->width = AV_CEIL_RSHIFT(inlink->w, hsub); + plane->height = AV_CEIL_RSHIFT(inlink->h, vsub); + plane->tmpbuf = av_malloc(plane->width * plane->height); + plane->gradients = av_calloc(plane->width * plane->height, sizeof(*plane->gradients)); + plane->directions = av_malloc(plane->width * plane->height); if (!plane->tmpbuf || !plane->gradients || !plane->directions) return AVERROR(ENOMEM); } @@ -316,34 +344,44 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) uint8_t *tmpbuf = plane->tmpbuf; uint16_t *gradients = plane->gradients; int8_t *directions = plane->directions; + const int width = plane->width; + const int height = plane->height; + + if (!((1 << p) & edgedetect->filter_planes)) { + if (!direct) + av_image_copy_plane(out->data[p], out->linesize[p], + in->data[p], in->linesize[p], + width, height); + continue; + } /* gaussian filter to reduce noise */ - gaussian_blur(ctx, inlink->w, inlink->h, - tmpbuf, inlink->w, + gaussian_blur(ctx, width, height, + tmpbuf, width, in->data[p], in->linesize[p]); /* compute the 16-bits gradients and directions for the next step */ - sobel(inlink->w, inlink->h, - gradients, inlink->w, - directions,inlink->w, - tmpbuf, inlink->w); + sobel(width, height, + gradients, width, + directions,width, + tmpbuf, width); /* non_maximum_suppression() will actually keep & clip what's necessary and * ignore the rest, so we need a clean output buffer */ - memset(tmpbuf, 0, inlink->w * inlink->h); - non_maximum_suppression(inlink->w, inlink->h, - tmpbuf, inlink->w, - directions,inlink->w, - gradients, inlink->w); + memset(tmpbuf, 0, width * height); + non_maximum_suppression(width, height, + tmpbuf, width, + directions,width, + gradients, width); /* keep high values, or low values surrounded by high values */ double_threshold(edgedetect->low_u8, edgedetect->high_u8, - inlink->w, inlink->h, + width, height, out->data[p], out->linesize[p], - tmpbuf, inlink->w); + tmpbuf, width); if (edgedetect->mode == MODE_COLORMIX) { - color_mix(inlink->w, inlink->h, + color_mix(width, height, out->data[p], out->linesize[p], in->data[p], in->linesize[p]); } diff --git a/libavfilter/vf_entropy.c b/libavfilter/vf_entropy.c index e6002ce27..c7361c84a 100644 --- a/libavfilter/vf_entropy.c +++ b/libavfilter/vf_entropy.c @@ -69,7 +69,7 @@ static int query_formats(AVFilterContext *ctx) AV_PIX_FMT_YUV444P16, AV_PIX_FMT_YUV422P16, AV_PIX_FMT_YUV420P16, AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRP9, AV_PIX_FMT_GBRP10, AV_PIX_FMT_GBRP12, AV_PIX_FMT_GBRP14, AV_PIX_FMT_GBRP16, - AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY9, AV_PIX_FMT_GRAY10, AV_PIX_FMT_GRAY12, AV_PIX_FMT_GRAY16, + AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY9, AV_PIX_FMT_GRAY10, AV_PIX_FMT_GRAY12, AV_PIX_FMT_GRAY14, AV_PIX_FMT_GRAY16, AV_PIX_FMT_NONE }; diff --git a/libavfilter/vf_extractplanes.c b/libavfilter/vf_extractplanes.c index fc676a25f..739c2420c 100644 --- a/libavfilter/vf_extractplanes.c +++ b/libavfilter/vf_extractplanes.c @@ -23,11 +23,9 @@ #include "libavutil/opt.h" #include "libavutil/pixdesc.h" -#define FF_INTERNAL_FIELDS 1 -#include "libavfilter/framequeue.h" - #include "avfilter.h" #include "drawutils.h" +#include "filters.h" #include "internal.h" #define PLANE_R 0x01 @@ -64,98 +62,69 @@ static const AVOption extractplanes_options[] = { AVFILTER_DEFINE_CLASS(extractplanes); +#define EIGHTBIT_FORMATS \ + AV_PIX_FMT_YUV410P, \ + AV_PIX_FMT_YUV411P, \ + AV_PIX_FMT_YUV440P, \ + AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUVA420P, \ + AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUVA422P, \ + AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUVJ422P, \ + AV_PIX_FMT_YUVJ440P, AV_PIX_FMT_YUVJ444P, \ + AV_PIX_FMT_YUVJ411P, \ + AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUVA444P, \ + AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY8A, \ + AV_PIX_FMT_RGB24, AV_PIX_FMT_BGR24, \ + AV_PIX_FMT_RGBA, AV_PIX_FMT_BGRA, \ + AV_PIX_FMT_ARGB, AV_PIX_FMT_ABGR, \ + AV_PIX_FMT_RGB0, AV_PIX_FMT_BGR0, \ + AV_PIX_FMT_0RGB, AV_PIX_FMT_0BGR, \ + AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRAP + +#define HIGHDEPTH_FORMATS(suf) \ + AV_PIX_FMT_YA16##suf, AV_PIX_FMT_GRAY16##suf, \ + AV_PIX_FMT_YUV420P16##suf, AV_PIX_FMT_YUVA420P16##suf, \ + AV_PIX_FMT_YUV422P16##suf, AV_PIX_FMT_YUVA422P16##suf, \ + AV_PIX_FMT_YUV444P16##suf, AV_PIX_FMT_YUVA444P16##suf, \ + AV_PIX_FMT_RGB48##suf, AV_PIX_FMT_BGR48##suf, \ + AV_PIX_FMT_RGBA64##suf, AV_PIX_FMT_BGRA64##suf, \ + AV_PIX_FMT_GBRP16##suf, AV_PIX_FMT_GBRAP16##suf, \ + AV_PIX_FMT_YUV420P10##suf, \ + AV_PIX_FMT_YUV422P10##suf, \ + AV_PIX_FMT_YUV444P10##suf, \ + AV_PIX_FMT_YUV440P10##suf, \ + AV_PIX_FMT_YUVA420P10##suf, \ + AV_PIX_FMT_YUVA422P10##suf, \ + AV_PIX_FMT_YUVA444P10##suf, \ + AV_PIX_FMT_YUV420P12##suf, \ + AV_PIX_FMT_YUV422P12##suf, \ + AV_PIX_FMT_YUV444P12##suf, \ + AV_PIX_FMT_YUV440P12##suf, \ + AV_PIX_FMT_YUVA422P12##suf, \ + AV_PIX_FMT_YUVA444P12##suf, \ + AV_PIX_FMT_GBRP10##suf, AV_PIX_FMT_GBRAP10##suf, \ + AV_PIX_FMT_GBRP12##suf, AV_PIX_FMT_GBRAP12##suf, \ + AV_PIX_FMT_YUV420P9##suf, \ + AV_PIX_FMT_YUV422P9##suf, \ + AV_PIX_FMT_YUV444P9##suf, \ + AV_PIX_FMT_YUVA420P9##suf, \ + AV_PIX_FMT_YUVA422P9##suf, \ + AV_PIX_FMT_YUVA444P9##suf, \ + AV_PIX_FMT_GBRP9##suf, \ + AV_PIX_FMT_GBRP14##suf, \ + AV_PIX_FMT_YUV420P14##suf, \ + AV_PIX_FMT_YUV422P14##suf, \ + AV_PIX_FMT_YUV444P14##suf + static int query_formats(AVFilterContext *ctx) { static const enum AVPixelFormat in_pixfmts_le[] = { - AV_PIX_FMT_YUV410P, - AV_PIX_FMT_YUV411P, - AV_PIX_FMT_YUV440P, - AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUVA420P, - AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUVA422P, - AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUVJ422P, - AV_PIX_FMT_YUVJ440P, AV_PIX_FMT_YUVJ444P, - AV_PIX_FMT_YUVJ411P, - AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUVA444P, - AV_PIX_FMT_YUV420P16LE, AV_PIX_FMT_YUVA420P16LE, - AV_PIX_FMT_YUV422P16LE, AV_PIX_FMT_YUVA422P16LE, - AV_PIX_FMT_YUV444P16LE, AV_PIX_FMT_YUVA444P16LE, - AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY8A, - AV_PIX_FMT_YA16LE, AV_PIX_FMT_GRAY16LE, - AV_PIX_FMT_RGB24, AV_PIX_FMT_BGR24, - AV_PIX_FMT_RGBA, AV_PIX_FMT_BGRA, - AV_PIX_FMT_ARGB, AV_PIX_FMT_ABGR, - AV_PIX_FMT_RGB0, AV_PIX_FMT_BGR0, - AV_PIX_FMT_0RGB, AV_PIX_FMT_0BGR, - AV_PIX_FMT_RGB48LE, AV_PIX_FMT_BGR48LE, - AV_PIX_FMT_RGBA64LE, AV_PIX_FMT_BGRA64LE, - AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRAP, - AV_PIX_FMT_GBRP16LE, AV_PIX_FMT_GBRAP16LE, - AV_PIX_FMT_YUV420P10LE, - AV_PIX_FMT_YUV422P10LE, - AV_PIX_FMT_YUV444P10LE, - AV_PIX_FMT_YUV440P10LE, - AV_PIX_FMT_YUVA420P10LE, - AV_PIX_FMT_YUVA422P10LE, - AV_PIX_FMT_YUVA444P10LE, - AV_PIX_FMT_YUV420P12LE, - AV_PIX_FMT_YUV422P12LE, - AV_PIX_FMT_YUV444P12LE, - AV_PIX_FMT_YUV440P12LE, - AV_PIX_FMT_GBRP10LE, AV_PIX_FMT_GBRAP10LE, - AV_PIX_FMT_GBRP12LE, AV_PIX_FMT_GBRAP12LE, - AV_PIX_FMT_YUV420P9LE, - AV_PIX_FMT_YUV422P9LE, - AV_PIX_FMT_YUV444P9LE, - AV_PIX_FMT_YUVA420P9LE, - AV_PIX_FMT_YUVA422P9LE, - AV_PIX_FMT_YUVA444P9LE, - AV_PIX_FMT_GBRP9LE, + EIGHTBIT_FORMATS, + HIGHDEPTH_FORMATS(LE), AV_PIX_FMT_NONE, }; static const enum AVPixelFormat in_pixfmts_be[] = { - AV_PIX_FMT_YUV410P, - AV_PIX_FMT_YUV411P, - AV_PIX_FMT_YUV440P, - AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUVA420P, - AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUVA422P, - AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUVJ422P, - AV_PIX_FMT_YUVJ440P, AV_PIX_FMT_YUVJ444P, - AV_PIX_FMT_YUVJ411P, - AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUVA444P, - AV_PIX_FMT_YUV420P16BE, AV_PIX_FMT_YUVA420P16BE, - AV_PIX_FMT_YUV422P16BE, AV_PIX_FMT_YUVA422P16BE, - AV_PIX_FMT_YUV444P16BE, AV_PIX_FMT_YUVA444P16BE, - AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY8A, - AV_PIX_FMT_YA16BE, AV_PIX_FMT_GRAY16BE, - AV_PIX_FMT_RGB24, AV_PIX_FMT_BGR24, - AV_PIX_FMT_RGBA, AV_PIX_FMT_BGRA, - AV_PIX_FMT_ARGB, AV_PIX_FMT_ABGR, - AV_PIX_FMT_RGB0, AV_PIX_FMT_BGR0, - AV_PIX_FMT_0RGB, AV_PIX_FMT_0BGR, - AV_PIX_FMT_RGB48BE, AV_PIX_FMT_BGR48BE, - AV_PIX_FMT_RGBA64BE, AV_PIX_FMT_BGRA64BE, - AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRAP, - AV_PIX_FMT_GBRP16BE, AV_PIX_FMT_GBRAP16BE, - AV_PIX_FMT_YUV420P10BE, - AV_PIX_FMT_YUV422P10BE, - AV_PIX_FMT_YUV444P10BE, - AV_PIX_FMT_YUV440P10BE, - AV_PIX_FMT_YUVA420P10BE, - AV_PIX_FMT_YUVA422P10BE, - AV_PIX_FMT_YUVA444P10BE, - AV_PIX_FMT_YUV420P12BE, - AV_PIX_FMT_YUV422P12BE, - AV_PIX_FMT_YUV444P12BE, - AV_PIX_FMT_YUV440P12BE, - AV_PIX_FMT_GBRP10BE, AV_PIX_FMT_GBRAP10BE, - AV_PIX_FMT_GBRP12BE, AV_PIX_FMT_GBRAP12BE, - AV_PIX_FMT_YUV420P9BE, - AV_PIX_FMT_YUV422P9BE, - AV_PIX_FMT_YUV444P9BE, - AV_PIX_FMT_YUVA420P9BE, - AV_PIX_FMT_YUVA422P9BE, - AV_PIX_FMT_YUVA444P9BE, - AV_PIX_FMT_GBRP9BE, + EIGHTBIT_FORMATS, + HIGHDEPTH_FORMATS(BE), AV_PIX_FMT_NONE, }; static const enum AVPixelFormat out8_pixfmts[] = { AV_PIX_FMT_GRAY8, AV_PIX_FMT_NONE }; @@ -165,6 +134,8 @@ static int query_formats(AVFilterContext *ctx) static const enum AVPixelFormat out10be_pixfmts[] = { AV_PIX_FMT_GRAY10BE, AV_PIX_FMT_NONE }; static const enum AVPixelFormat out12le_pixfmts[] = { AV_PIX_FMT_GRAY12LE, AV_PIX_FMT_NONE }; static const enum AVPixelFormat out12be_pixfmts[] = { AV_PIX_FMT_GRAY12BE, AV_PIX_FMT_NONE }; + static const enum AVPixelFormat out14le_pixfmts[] = { AV_PIX_FMT_GRAY14LE, AV_PIX_FMT_NONE }; + static const enum AVPixelFormat out14be_pixfmts[] = { AV_PIX_FMT_GRAY14BE, AV_PIX_FMT_NONE }; static const enum AVPixelFormat out16le_pixfmts[] = { AV_PIX_FMT_GRAY16LE, AV_PIX_FMT_NONE }; static const enum AVPixelFormat out16be_pixfmts[] = { AV_PIX_FMT_GRAY16BE, AV_PIX_FMT_NONE }; const enum AVPixelFormat *out_pixfmts, *in_pixfmts; @@ -212,6 +183,10 @@ static int query_formats(AVFilterContext *ctx) out_pixfmts = out12le_pixfmts; else if (be && depth == 12) out_pixfmts = out12be_pixfmts; + else if (!be && depth == 14) + out_pixfmts = out14le_pixfmts; + else if (be && depth == 14) + out_pixfmts = out14be_pixfmts; else if (be) out_pixfmts = out16be_pixfmts; else @@ -307,7 +282,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame) const int idx = s->map[i]; AVFrame *out; - if (outlink->status_in) + if (ff_outlink_get_status(outlink)) continue; out = ff_get_video_buffer(outlink, outlink->w, outlink->h); diff --git a/libavfilter/vf_fade.c b/libavfilter/vf_fade.c index c30c41db0..17eca109b 100644 --- a/libavfilter/vf_fade.c +++ b/libavfilter/vf_fade.c @@ -386,13 +386,13 @@ static const AVOption fade_options[] = { OFFSET(nb_frames), AV_OPT_TYPE_INT, { .i64 = 25 }, 0, INT_MAX, FLAGS }, { "alpha", "fade alpha if it is available on the input", OFFSET(alpha), AV_OPT_TYPE_BOOL, {.i64 = 0 }, 0, 1, FLAGS }, { "start_time", "Number of seconds of the beginning of the effect.", - OFFSET(start_time), AV_OPT_TYPE_DURATION, {.i64 = 0. }, 0, INT32_MAX, FLAGS }, + OFFSET(start_time), AV_OPT_TYPE_DURATION, {.i64 = 0. }, 0, INT64_MAX, FLAGS }, { "st", "Number of seconds of the beginning of the effect.", - OFFSET(start_time), AV_OPT_TYPE_DURATION, {.i64 = 0. }, 0, INT32_MAX, FLAGS }, + OFFSET(start_time), AV_OPT_TYPE_DURATION, {.i64 = 0. }, 0, INT64_MAX, FLAGS }, { "duration", "Duration of the effect in seconds.", - OFFSET(duration), AV_OPT_TYPE_DURATION, {.i64 = 0. }, 0, INT32_MAX, FLAGS }, + OFFSET(duration), AV_OPT_TYPE_DURATION, {.i64 = 0. }, 0, INT64_MAX, FLAGS }, { "d", "Duration of the effect in seconds.", - OFFSET(duration), AV_OPT_TYPE_DURATION, {.i64 = 0. }, 0, INT32_MAX, FLAGS }, + OFFSET(duration), AV_OPT_TYPE_DURATION, {.i64 = 0. }, 0, INT64_MAX, FLAGS }, { "color", "set color", OFFSET(color_rgba), AV_OPT_TYPE_COLOR, {.str = "black"}, CHAR_MIN, CHAR_MAX, FLAGS }, { "c", "set color", OFFSET(color_rgba), AV_OPT_TYPE_COLOR, {.str = "black"}, CHAR_MIN, CHAR_MAX, FLAGS }, { NULL } diff --git a/libavfilter/vf_fftdnoiz.c b/libavfilter/vf_fftdnoiz.c new file mode 100644 index 000000000..7ee7dbc19 --- /dev/null +++ b/libavfilter/vf_fftdnoiz.c @@ -0,0 +1,694 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include "libavutil/avassert.h" +#include "libavutil/common.h" +#include "libavutil/imgutils.h" +#include "libavutil/opt.h" +#include "libavutil/pixdesc.h" +#include "internal.h" +#include "libavcodec/avfft.h" + +enum BufferTypes { + CURRENT, + PREV, + NEXT, + BSIZE +}; + +typedef struct PlaneContext { + int planewidth, planeheight; + int nox, noy; + int b; + int o; + float n; + + float *buffer[BSIZE]; + FFTComplex *hdata, *vdata; + int data_linesize; + int buffer_linesize; + + FFTContext *fft, *ifft; +} PlaneContext; + +typedef struct FFTdnoizContext { + const AVClass *class; + + float sigma; + float amount; + int block_bits; + float overlap; + int nb_prev; + int nb_next; + int planesf; + + AVFrame *prev, *cur, *next; + + int depth; + int nb_planes; + PlaneContext planes[4]; + + void (*import_row)(FFTComplex *dst, uint8_t *src, int rw); + void (*export_row)(FFTComplex *src, uint8_t *dst, int rw, float scale, int depth); +} FFTdnoizContext; + +#define OFFSET(x) offsetof(FFTdnoizContext, x) +#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM +static const AVOption fftdnoiz_options[] = { + { "sigma", "set denoise strength", + OFFSET(sigma), AV_OPT_TYPE_FLOAT, {.dbl=1}, 0, 30, .flags = FLAGS }, + { "amount", "set amount of denoising", + OFFSET(amount), AV_OPT_TYPE_FLOAT, {.dbl=1}, 0.01, 1, .flags = FLAGS }, + { "block", "set block log2(size)", + OFFSET(block_bits), AV_OPT_TYPE_INT, {.i64=4}, 3, 6, .flags = FLAGS }, + { "overlap", "set block overlap", + OFFSET(overlap), AV_OPT_TYPE_FLOAT, {.dbl=0.5}, 0.2, 0.8, .flags = FLAGS }, + { "prev", "set number of previous frames for temporal denoising", + OFFSET(nb_prev), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, .flags = FLAGS }, + { "next", "set number of next frames for temporal denoising", + OFFSET(nb_next), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, .flags = FLAGS }, + { "planes", "set planes to filter", + OFFSET(planesf), AV_OPT_TYPE_INT, {.i64=7}, 0, 15, .flags = FLAGS }, + { NULL } +}; + +AVFILTER_DEFINE_CLASS(fftdnoiz); + +static av_cold int init(AVFilterContext *ctx) +{ + FFTdnoizContext *s = ctx->priv; + int i; + + for (i = 0; i < 4; i++) { + PlaneContext *p = &s->planes[i]; + + p->fft = av_fft_init(s->block_bits, 0); + p->ifft = av_fft_init(s->block_bits, 1); + if (!p->fft || !p->ifft) + return AVERROR(ENOMEM); + } + + return 0; +} + +static int query_formats(AVFilterContext *ctx) +{ + static const enum AVPixelFormat pix_fmts[] = { + AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY9, + AV_PIX_FMT_GRAY10, AV_PIX_FMT_GRAY12, + AV_PIX_FMT_GRAY14, AV_PIX_FMT_GRAY16, + AV_PIX_FMT_YUV410P, AV_PIX_FMT_YUV411P, + AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV422P, + AV_PIX_FMT_YUV440P, AV_PIX_FMT_YUV444P, + AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUVJ422P, + AV_PIX_FMT_YUVJ440P, AV_PIX_FMT_YUVJ444P, + AV_PIX_FMT_YUVJ411P, + AV_PIX_FMT_YUV420P9, AV_PIX_FMT_YUV422P9, AV_PIX_FMT_YUV444P9, + AV_PIX_FMT_YUV420P10, AV_PIX_FMT_YUV422P10, AV_PIX_FMT_YUV444P10, + AV_PIX_FMT_YUV440P10, + AV_PIX_FMT_YUV444P12, AV_PIX_FMT_YUV422P12, AV_PIX_FMT_YUV420P12, + AV_PIX_FMT_YUV440P12, + AV_PIX_FMT_YUV444P14, AV_PIX_FMT_YUV422P14, AV_PIX_FMT_YUV420P14, + AV_PIX_FMT_YUV420P16, AV_PIX_FMT_YUV422P16, AV_PIX_FMT_YUV444P16, + AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRP9, AV_PIX_FMT_GBRP10, + AV_PIX_FMT_GBRP12, AV_PIX_FMT_GBRP14, AV_PIX_FMT_GBRP16, + AV_PIX_FMT_NONE + }; + AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts); + if (!fmts_list) + return AVERROR(ENOMEM); + return ff_set_common_formats(ctx, fmts_list); +} + +typedef struct ThreadData { + float *src, *dst; +} ThreadData; + +static void import_row8(FFTComplex *dst, uint8_t *src, int rw) +{ + int j; + + for (j = 0; j < rw; j++) { + dst[j].re = src[j]; + dst[j].im = 0; + } +} + +static void export_row8(FFTComplex *src, uint8_t *dst, int rw, float scale, int depth) +{ + int j; + + for (j = 0; j < rw; j++) + dst[j] = av_clip_uint8(src[j].re * scale); +} + +static void import_row16(FFTComplex *dst, uint8_t *srcp, int rw) +{ + uint16_t *src = (uint16_t *)srcp; + int j; + + for (j = 0; j < rw; j++) { + dst[j].re = src[j]; + dst[j].im = 0; + } +} + +static void export_row16(FFTComplex *src, uint8_t *dstp, int rw, float scale, int depth) +{ + uint16_t *dst = (uint16_t *)dstp; + int j; + + for (j = 0; j < rw; j++) + dst[j] = av_clip_uintp2_c(src[j].re * scale, depth); +} + +static int config_input(AVFilterLink *inlink) +{ + AVFilterContext *ctx = inlink->dst; + const AVPixFmtDescriptor *desc; + FFTdnoizContext *s = ctx->priv; + int i; + + desc = av_pix_fmt_desc_get(inlink->format); + s->depth = desc->comp[0].depth; + + if (s->depth <= 8) { + s->import_row = import_row8; + s->export_row = export_row8; + } else { + s->import_row = import_row16; + s->export_row = export_row16; + s->sigma *= 1 << (s->depth - 8) * (1 + s->nb_prev + s->nb_next); + } + + s->planes[1].planewidth = s->planes[2].planewidth = AV_CEIL_RSHIFT(inlink->w, desc->log2_chroma_w); + s->planes[0].planewidth = s->planes[3].planewidth = inlink->w; + s->planes[1].planeheight = s->planes[2].planeheight = AV_CEIL_RSHIFT(inlink->h, desc->log2_chroma_h); + s->planes[0].planeheight = s->planes[3].planeheight = inlink->h; + + s->nb_planes = av_pix_fmt_count_planes(inlink->format); + + for (i = 0; i < s->nb_planes; i++) { + PlaneContext *p = &s->planes[i]; + int size; + + p->b = 1 << s->block_bits; + p->n = 1.f / (p->b * p->b); + p->o = p->b * s->overlap; + size = p->b - p->o; + p->nox = (p->planewidth + (size - 1)) / size; + p->noy = (p->planeheight + (size - 1)) / size; + + av_log(ctx, AV_LOG_DEBUG, "nox:%d noy:%d size:%d\n", p->nox, p->noy, size); + + p->buffer_linesize = p->b * p->nox * sizeof(FFTComplex); + p->buffer[CURRENT] = av_calloc(p->b * p->noy, p->buffer_linesize); + if (!p->buffer[CURRENT]) + return AVERROR(ENOMEM); + if (s->nb_prev > 0) { + p->buffer[PREV] = av_calloc(p->b * p->noy, p->buffer_linesize); + if (!p->buffer[PREV]) + return AVERROR(ENOMEM); + } + if (s->nb_next > 0) { + p->buffer[NEXT] = av_calloc(p->b * p->noy, p->buffer_linesize); + if (!p->buffer[NEXT]) + return AVERROR(ENOMEM); + } + p->data_linesize = 2 * p->b * sizeof(float); + p->hdata = av_calloc(p->b, p->data_linesize); + p->vdata = av_calloc(p->b, p->data_linesize); + if (!p->hdata || !p->vdata) + return AVERROR(ENOMEM); + } + + return 0; +} + +static void import_plane(FFTdnoizContext *s, + uint8_t *srcp, int src_linesize, + float *buffer, int buffer_linesize, int plane) +{ + PlaneContext *p = &s->planes[plane]; + const int width = p->planewidth; + const int height = p->planeheight; + const int block = p->b; + const int overlap = p->o; + const int size = block - overlap; + const int nox = p->nox; + const int noy = p->noy; + const int bpp = (s->depth + 7) / 8; + const int data_linesize = p->data_linesize / sizeof(FFTComplex); + FFTComplex *hdata = p->hdata; + FFTComplex *vdata = p->vdata; + int x, y, i, j; + + buffer_linesize /= sizeof(float); + for (y = 0; y < noy; y++) { + for (x = 0; x < nox; x++) { + const int rh = FFMIN(block, height - y * size); + const int rw = FFMIN(block, width - x * size); + uint8_t *src = srcp + src_linesize * y * size + x * size * bpp; + float *bdst = buffer + buffer_linesize * y * block + x * block * 2; + FFTComplex *ssrc, *dst = hdata; + + for (i = 0; i < rh; i++) { + s->import_row(dst, src, rw); + for (j = rw; j < block; j++) { + dst[j].re = dst[block - j - 1].re; + dst[j].im = 0; + } + av_fft_permute(p->fft, dst); + av_fft_calc(p->fft, dst); + + src += src_linesize; + dst += data_linesize; + } + + dst = hdata; + for (; i < block; i++) { + for (j = 0; j < block; j++) { + dst[j].re = dst[(block - i - 1) * data_linesize + j].re; + dst[j].im = dst[(block - i - 1) * data_linesize + j].im; + } + } + + ssrc = hdata; + dst = vdata; + for (i = 0; i < block; i++) { + for (j = 0; j < block; j++) + dst[j] = ssrc[j * data_linesize + i]; + av_fft_permute(p->fft, dst); + av_fft_calc(p->fft, dst); + memcpy(bdst, dst, block * sizeof(FFTComplex)); + + dst += data_linesize; + bdst += buffer_linesize; + } + } + } +} + +static void export_plane(FFTdnoizContext *s, + uint8_t *dstp, int dst_linesize, + float *buffer, int buffer_linesize, int plane) +{ + PlaneContext *p = &s->planes[plane]; + const int depth = s->depth; + const int bpp = (depth + 7) / 8; + const int width = p->planewidth; + const int height = p->planeheight; + const int block = p->b; + const int overlap = p->o; + const int hoverlap = overlap / 2; + const int size = block - overlap; + const int nox = p->nox; + const int noy = p->noy; + const int data_linesize = p->data_linesize / sizeof(FFTComplex); + const float scale = 1.f / (block * block); + FFTComplex *hdata = p->hdata; + FFTComplex *vdata = p->vdata; + int x, y, i, j; + + buffer_linesize /= sizeof(float); + for (y = 0; y < noy; y++) { + for (x = 0; x < nox; x++) { + const int woff = x == 0 ? 0 : hoverlap; + const int hoff = y == 0 ? 0 : hoverlap; + const int rw = x == 0 ? block : FFMIN(size, width - x * size - woff); + const int rh = y == 0 ? block : FFMIN(size, height - y * size - hoff); + float *bsrc = buffer + buffer_linesize * y * block + x * block * 2; + uint8_t *dst = dstp + dst_linesize * (y * size + hoff) + (x * size + woff) * bpp; + FFTComplex *hdst, *ddst = vdata; + + hdst = hdata; + for (i = 0; i < block; i++) { + memcpy(ddst, bsrc, block * sizeof(FFTComplex)); + av_fft_permute(p->ifft, ddst); + av_fft_calc(p->ifft, ddst); + for (j = 0; j < block; j++) { + hdst[j * data_linesize + i] = ddst[j]; + } + + ddst += data_linesize; + bsrc += buffer_linesize; + } + + hdst = hdata + hoff * data_linesize; + for (i = 0; i < rh; i++) { + av_fft_permute(p->ifft, hdst); + av_fft_calc(p->ifft, hdst); + s->export_row(hdst + woff, dst, rw, scale, depth); + + hdst += data_linesize; + dst += dst_linesize; + } + } + } +} + +static void filter_plane3d2(FFTdnoizContext *s, int plane, float *pbuffer, float *nbuffer) +{ + PlaneContext *p = &s->planes[plane]; + const int block = p->b; + const int nox = p->nox; + const int noy = p->noy; + const int buffer_linesize = p->buffer_linesize / sizeof(float); + const float sigma = s->sigma * s->sigma * block * block; + const float limit = 1.f - s->amount; + float *cbuffer = p->buffer[CURRENT]; + const float cfactor = sqrtf(3.f) * 0.5f; + const float scale = 1.f / 3.f; + int y, x, i, j; + + for (y = 0; y < noy; y++) { + for (x = 0; x < nox; x++) { + float *cbuff = cbuffer + buffer_linesize * y * block + x * block * 2; + float *pbuff = pbuffer + buffer_linesize * y * block + x * block * 2; + float *nbuff = nbuffer + buffer_linesize * y * block + x * block * 2; + + for (i = 0; i < block; i++) { + for (j = 0; j < block; j++) { + float sumr, sumi, difr, difi, mpr, mpi, mnr, mni; + float factor, power, sumpnr, sumpni; + + sumpnr = pbuff[2 * j ] + nbuff[2 * j ]; + sumpni = pbuff[2 * j + 1] + nbuff[2 * j + 1]; + sumr = cbuff[2 * j ] + sumpnr; + sumi = cbuff[2 * j + 1] + sumpni; + difr = cfactor * (nbuff[2 * j ] - pbuff[2 * j ]); + difi = cfactor * (pbuff[2 * j + 1] - nbuff[2 * j + 1]); + mpr = cbuff[2 * j ] - 0.5f * sumpnr + difi; + mnr = mpr - difi - difi; + mpi = cbuff[2 * j + 1] - 0.5f * sumpni + difr; + mni = mpi - difr - difr; + power = sumr * sumr + sumi * sumi + 1e-15f; + factor = FFMAX((power - sigma) / power, limit); + sumr *= factor; + sumi *= factor; + power = mpr * mpr + mpi * mpi + 1e-15f; + factor = FFMAX((power - sigma) / power, limit); + mpr *= factor; + mpi *= factor; + power = mnr * mnr + mni * mni + 1e-15f; + factor = FFMAX((power - sigma) / power, limit); + mnr *= factor; + mni *= factor; + cbuff[2 * j ] = (sumr + mpr + mnr) * scale; + cbuff[2 * j + 1] = (sumi + mpi + mni) * scale; + + } + + cbuff += buffer_linesize; + pbuff += buffer_linesize; + nbuff += buffer_linesize; + } + } + } +} + +static void filter_plane3d1(FFTdnoizContext *s, int plane, float *pbuffer) +{ + PlaneContext *p = &s->planes[plane]; + const int block = p->b; + const int nox = p->nox; + const int noy = p->noy; + const int buffer_linesize = p->buffer_linesize / sizeof(float); + const float sigma = s->sigma * s->sigma * block * block; + const float limit = 1.f - s->amount; + float *cbuffer = p->buffer[CURRENT]; + int y, x, i, j; + + for (y = 0; y < noy; y++) { + for (x = 0; x < nox; x++) { + float *cbuff = cbuffer + buffer_linesize * y * block + x * block * 2; + float *pbuff = pbuffer + buffer_linesize * y * block + x * block * 2; + + for (i = 0; i < block; i++) { + for (j = 0; j < block; j++) { + float factor, power, re, im, pre, pim; + float sumr, sumi, difr, difi; + + re = cbuff[j * 2 ]; + pre = pbuff[j * 2 ]; + im = cbuff[j * 2 + 1]; + pim = pbuff[j * 2 + 1]; + + sumr = re + pre; + sumi = im + pim; + difr = re - pre; + difi = im - pim; + + power = sumr * sumr + sumi * sumi + 1e-15f; + factor = FFMAX(limit, (power - sigma) / power); + sumr *= factor; + sumi *= factor; + power = difr * difr + difi * difi + 1e-15f; + factor = FFMAX(limit, (power - sigma) / power); + difr *= factor; + difi *= factor; + + cbuff[j * 2 ] = (sumr + difr) * 0.5f; + cbuff[j * 2 + 1] = (sumi + difi) * 0.5f; + } + + cbuff += buffer_linesize; + pbuff += buffer_linesize; + } + } + } +} + +static void filter_plane2d(FFTdnoizContext *s, int plane) +{ + PlaneContext *p = &s->planes[plane]; + const int block = p->b; + const int nox = p->nox; + const int noy = p->noy; + const int buffer_linesize = p->buffer_linesize / 4; + const float sigma = s->sigma * s->sigma * block * block; + const float limit = 1.f - s->amount; + float *buffer = p->buffer[CURRENT]; + int y, x, i, j; + + for (y = 0; y < noy; y++) { + for (x = 0; x < nox; x++) { + float *buff = buffer + buffer_linesize * y * block + x * block * 2; + + for (i = 0; i < block; i++) { + for (j = 0; j < block; j++) { + float factor, power, re, im; + + re = buff[j * 2 ]; + im = buff[j * 2 + 1]; + power = re * re + im * im + 1e-15f; + factor = FFMAX(limit, (power - sigma) / power); + buff[j * 2 ] *= factor; + buff[j * 2 + 1] *= factor; + } + + buff += buffer_linesize; + } + } + } +} + +static int filter_frame(AVFilterLink *inlink, AVFrame *in) +{ + AVFilterContext *ctx = inlink->dst; + FFTdnoizContext *s = ctx->priv; + AVFilterLink *outlink = ctx->outputs[0]; + int direct, plane; + AVFrame *out; + + if (s->nb_next > 0 && s->nb_prev > 0) { + av_frame_free(&s->prev); + s->prev = s->cur; + s->cur = s->next; + s->next = in; + + if (!s->prev && s->cur) { + s->prev = av_frame_clone(s->cur); + if (!s->prev) + return AVERROR(ENOMEM); + } + if (!s->cur) + return 0; + } else if (s->nb_next > 0) { + av_frame_free(&s->cur); + s->cur = s->next; + s->next = in; + + if (!s->cur) + return 0; + } else if (s->nb_prev > 0) { + av_frame_free(&s->prev); + s->prev = s->cur; + s->cur = in; + + if (!s->prev) + s->prev = av_frame_clone(s->cur); + if (!s->prev) + return AVERROR(ENOMEM); + } else { + s->cur = in; + } + + if (av_frame_is_writable(in) && s->nb_next == 0 && s->nb_prev == 0) { + direct = 1; + out = in; + } else { + direct = 0; + out = ff_get_video_buffer(outlink, outlink->w, outlink->h); + if (!out) + return AVERROR(ENOMEM); + av_frame_copy_props(out, s->cur); + } + + for (plane = 0; plane < s->nb_planes; plane++) { + PlaneContext *p = &s->planes[plane]; + + if (!((1 << plane) & s->planesf) || ctx->is_disabled) { + if (!direct) + av_image_copy_plane(out->data[plane], out->linesize[plane], + s->cur->data[plane], s->cur->linesize[plane], + p->planewidth, p->planeheight); + continue; + } + + if (s->next) { + import_plane(s, s->next->data[plane], s->next->linesize[plane], + p->buffer[NEXT], p->buffer_linesize, plane); + } + + if (s->prev) { + import_plane(s, s->prev->data[plane], s->prev->linesize[plane], + p->buffer[PREV], p->buffer_linesize, plane); + } + + import_plane(s, s->cur->data[plane], s->cur->linesize[plane], + p->buffer[CURRENT], p->buffer_linesize, plane); + + if (s->next && s->prev) { + filter_plane3d2(s, plane, p->buffer[PREV], p->buffer[NEXT]); + } else if (s->next) { + filter_plane3d1(s, plane, p->buffer[NEXT]); + } else if (s->prev) { + filter_plane3d1(s, plane, p->buffer[PREV]); + } else { + filter_plane2d(s, plane); + } + + export_plane(s, out->data[plane], out->linesize[plane], + p->buffer[CURRENT], p->buffer_linesize, plane); + } + + if (s->nb_next == 0 && s->nb_prev == 0) { + if (direct) { + s->cur = NULL; + } else { + av_frame_free(&s->cur); + } + } + return ff_filter_frame(outlink, out); +} + +static int request_frame(AVFilterLink *outlink) +{ + AVFilterContext *ctx = outlink->src; + FFTdnoizContext *s = ctx->priv; + int ret = 0; + + ret = ff_request_frame(ctx->inputs[0]); + + if (ret == AVERROR_EOF && (s->nb_next > 0)) { + AVFrame *buf; + + if (s->next && s->nb_next > 0) + buf = av_frame_clone(s->next); + else if (s->cur) + buf = av_frame_clone(s->cur); + else + buf = av_frame_clone(s->prev); + if (!buf) + return AVERROR(ENOMEM); + + ret = filter_frame(ctx->inputs[0], buf); + if (ret < 0) + return ret; + ret = AVERROR_EOF; + } + + return ret; +} + +static av_cold void uninit(AVFilterContext *ctx) +{ + FFTdnoizContext *s = ctx->priv; + int i; + + for (i = 0; i < 4; i++) { + PlaneContext *p = &s->planes[i]; + + av_freep(&p->hdata); + av_freep(&p->vdata); + av_freep(&p->buffer[PREV]); + av_freep(&p->buffer[CURRENT]); + av_freep(&p->buffer[NEXT]); + av_fft_end(p->fft); + av_fft_end(p->ifft); + } + + av_frame_free(&s->prev); + av_frame_free(&s->cur); + av_frame_free(&s->next); +} + +static const AVFilterPad fftdnoiz_inputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + .filter_frame = filter_frame, + .config_props = config_input, + }, + { NULL } +}; + +static const AVFilterPad fftdnoiz_outputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + .request_frame = request_frame, + }, + { NULL } +}; + +AVFilter ff_vf_fftdnoiz = { + .name = "fftdnoiz", + .description = NULL_IF_CONFIG_SMALL("Denoise frames using 3D FFT."), + .priv_size = sizeof(FFTdnoizContext), + .init = init, + .uninit = uninit, + .query_formats = query_formats, + .inputs = fftdnoiz_inputs, + .outputs = fftdnoiz_outputs, + .priv_class = &fftdnoiz_class, + .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, +}; diff --git a/libavfilter/vf_fieldmatch.c b/libavfilter/vf_fieldmatch.c index 3694f26d3..5a73eb43b 100644 --- a/libavfilter/vf_fieldmatch.c +++ b/libavfilter/vf_fieldmatch.c @@ -37,6 +37,7 @@ #include "libavutil/opt.h" #include "libavutil/timestamp.h" #include "avfilter.h" +#include "filters.h" #include "internal.h" #define INPUT_MAIN 0 @@ -79,6 +80,7 @@ typedef struct FieldMatchContext { AVFrame *prv2, *src2, *nxt2; ///< sliding window of the optional second stream int got_frame[2]; ///< frame request flag for each input stream int hsub, vsub; ///< chroma subsampling values + int bpc; ///< bytes per component uint32_t eof; ///< bitmask for end of stream int64_t lastscdiff; int64_t lastn; @@ -503,9 +505,9 @@ static int compare_fields(FieldMatchContext *fm, int match1, int match2, int fie int prvf_linesize, nxtf_linesize; const int width = get_width (fm, src, plane); const int height = get_height(fm, src, plane); - const int y0a = fm->y0 >> (plane != 0); - const int y1a = fm->y1 >> (plane != 0); - const int startx = (plane == 0 ? 8 : 4); + const int y0a = fm->y0 >> (plane ? fm->vsub : 0); + const int y1a = fm->y1 >> (plane ? fm->vsub : 0); + const int startx = (plane == 0 ? 8 : 8 >> fm->hsub); const int stopx = width - startx; const uint8_t *srcpf, *srcf, *srcnf; const uint8_t *prvpf, *prvnf, *nxtpf, *nxtnf; @@ -613,7 +615,7 @@ static void copy_fields(const FieldMatchContext *fm, AVFrame *dst, const int nb_copy_fields = (plane_h >> 1) + (field ? 0 : (plane_h & 1)); av_image_copy_plane(dst->data[plane] + field*dst->linesize[plane], dst->linesize[plane] << 1, src->data[plane] + field*src->linesize[plane], src->linesize[plane] << 1, - get_width(fm, src, plane), nb_copy_fields); + get_width(fm, src, plane) * fm->bpc, nb_copy_fields); } } @@ -697,9 +699,11 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) av_assert0(prv && src && nxt); \ } while (0) if (FF_INLINK_IDX(inlink) == INPUT_MAIN) { + av_assert0(fm->got_frame[INPUT_MAIN] == 0); SLIDING_FRAME_WINDOW(fm->prv, fm->src, fm->nxt); fm->got_frame[INPUT_MAIN] = 1; } else { + av_assert0(fm->got_frame[INPUT_CLEANSRC] == 0); SLIDING_FRAME_WINDOW(fm->prv2, fm->src2, fm->nxt2); fm->got_frame[INPUT_CLEANSRC] = 1; } @@ -818,50 +822,99 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) return ff_filter_frame(outlink, dst); } -static int request_inlink(AVFilterContext *ctx, int lid) +static int activate(AVFilterContext *ctx) { - int ret = 0; FieldMatchContext *fm = ctx->priv; + AVFrame *frame = NULL; + int ret = 0, status; + int64_t pts; - if (!fm->got_frame[lid]) { - AVFilterLink *inlink = ctx->inputs[lid]; - ret = ff_request_frame(inlink); - if (ret == AVERROR_EOF) { // flushing - fm->eof |= 1 << lid; - ret = filter_frame(inlink, NULL); - } + if ((fm->got_frame[INPUT_MAIN] == 0) && + (ret = ff_inlink_consume_frame(ctx->inputs[INPUT_MAIN], &frame)) > 0) { + ret = filter_frame(ctx->inputs[INPUT_MAIN], frame); + if (ret < 0) + return ret; } - return ret; -} - -static int request_frame(AVFilterLink *outlink) -{ - int ret; - AVFilterContext *ctx = outlink->src; - FieldMatchContext *fm = ctx->priv; - const uint32_t eof_mask = 1<ppsrc<eof & eof_mask) == eof_mask) // flush done? - return AVERROR_EOF; - if ((ret = request_inlink(ctx, INPUT_MAIN)) < 0) + if (ret < 0) return ret; - if (fm->ppsrc && (ret = request_inlink(ctx, INPUT_CLEANSRC)) < 0) + if (fm->ppsrc && + (fm->got_frame[INPUT_CLEANSRC] == 0) && + (ret = ff_inlink_consume_frame(ctx->inputs[INPUT_CLEANSRC], &frame)) > 0) { + ret = filter_frame(ctx->inputs[INPUT_CLEANSRC], frame); + if (ret < 0) + return ret; + } + if (ret < 0) { return ret; - return 0; + } else if (ff_inlink_acknowledge_status(ctx->inputs[INPUT_MAIN], &status, &pts)) { + if (status == AVERROR_EOF) { // flushing + fm->eof |= 1 << INPUT_MAIN; + ret = filter_frame(ctx->inputs[INPUT_MAIN], NULL); + } + ff_outlink_set_status(ctx->outputs[0], status, pts); + return ret; + } else if (fm->ppsrc && ff_inlink_acknowledge_status(ctx->inputs[INPUT_CLEANSRC], &status, &pts)) { + if (status == AVERROR_EOF) { // flushing + fm->eof |= 1 << INPUT_CLEANSRC; + ret = filter_frame(ctx->inputs[INPUT_CLEANSRC], NULL); + } + ff_outlink_set_status(ctx->outputs[0], status, pts); + return ret; + } else { + if (ff_outlink_frame_wanted(ctx->outputs[0])) { + if (fm->got_frame[INPUT_MAIN] == 0) + ff_inlink_request_frame(ctx->inputs[INPUT_MAIN]); + if (fm->ppsrc && (fm->got_frame[INPUT_CLEANSRC] == 0)) + ff_inlink_request_frame(ctx->inputs[INPUT_CLEANSRC]); + } + return 0; + } } static int query_formats(AVFilterContext *ctx) { - // TODO: second input source can support >8bit depth + FieldMatchContext *fm = ctx->priv; + static const enum AVPixelFormat pix_fmts[] = { AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV411P, AV_PIX_FMT_YUV410P, AV_PIX_FMT_NONE }; + static const enum AVPixelFormat unproc_pix_fmts[] = { + AV_PIX_FMT_YUV410P, AV_PIX_FMT_YUV411P, + AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV422P, + AV_PIX_FMT_YUV440P, AV_PIX_FMT_YUV444P, + AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUVJ422P, + AV_PIX_FMT_YUVJ440P, AV_PIX_FMT_YUVJ444P, + AV_PIX_FMT_YUVJ411P, + AV_PIX_FMT_YUV420P9, AV_PIX_FMT_YUV422P9, AV_PIX_FMT_YUV444P9, + AV_PIX_FMT_YUV420P10, AV_PIX_FMT_YUV422P10, AV_PIX_FMT_YUV444P10, + AV_PIX_FMT_YUV440P10, + AV_PIX_FMT_YUV444P12, AV_PIX_FMT_YUV422P12, AV_PIX_FMT_YUV420P12, + AV_PIX_FMT_YUV440P12, + AV_PIX_FMT_YUV444P14, AV_PIX_FMT_YUV422P14, AV_PIX_FMT_YUV420P14, + AV_PIX_FMT_YUV420P16, AV_PIX_FMT_YUV422P16, AV_PIX_FMT_YUV444P16, + AV_PIX_FMT_NONE + }; + int ret; + AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts); if (!fmts_list) return AVERROR(ENOMEM); - return ff_set_common_formats(ctx, fmts_list); + if (!fm->ppsrc) { + return ff_set_common_formats(ctx, fmts_list); + } + + if ((ret = ff_formats_ref(fmts_list, &ctx->inputs[INPUT_MAIN]->out_formats)) < 0) + return ret; + fmts_list = ff_make_format_list(unproc_pix_fmts); + if (!fmts_list) + return AVERROR(ENOMEM); + if ((ret = ff_formats_ref(fmts_list, &ctx->outputs[0]->in_formats)) < 0) + return ret; + if ((ret = ff_formats_ref(fmts_list, &ctx->inputs[INPUT_CLEANSRC]->out_formats)) < 0) + return ret; + return 0; } static int config_input(AVFilterLink *inlink) @@ -901,7 +954,6 @@ static av_cold int fieldmatch_init(AVFilterContext *ctx) AVFilterPad pad = { .name = av_strdup("main"), .type = AVMEDIA_TYPE_VIDEO, - .filter_frame = filter_frame, .config_props = config_input, }; int ret; @@ -947,7 +999,12 @@ static av_cold void fieldmatch_uninit(AVFilterContext *ctx) av_frame_free(&fm->prv); if (fm->nxt != fm->src) av_frame_free(&fm->nxt); + if (fm->prv2 != fm->src2) + av_frame_free(&fm->prv2); + if (fm->nxt2 != fm->src2) + av_frame_free(&fm->nxt2); av_frame_free(&fm->src); + av_frame_free(&fm->src2); av_freep(&fm->map_data[0]); av_freep(&fm->cmask_data[0]); av_freep(&fm->tbuffer); @@ -959,10 +1016,12 @@ static av_cold void fieldmatch_uninit(AVFilterContext *ctx) static int config_output(AVFilterLink *outlink) { AVFilterContext *ctx = outlink->src; - const FieldMatchContext *fm = ctx->priv; + FieldMatchContext *fm = ctx->priv; const AVFilterLink *inlink = ctx->inputs[fm->ppsrc ? INPUT_CLEANSRC : INPUT_MAIN]; + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format); + fm->bpc = (desc->comp[0].depth + 7) / 8; outlink->time_base = inlink->time_base; outlink->sample_aspect_ratio = inlink->sample_aspect_ratio; outlink->frame_rate = inlink->frame_rate; @@ -975,7 +1034,6 @@ static const AVFilterPad fieldmatch_outputs[] = { { .name = "default", .type = AVMEDIA_TYPE_VIDEO, - .request_frame = request_frame, .config_props = config_output, }, { NULL } @@ -987,6 +1045,7 @@ AVFilter ff_vf_fieldmatch = { .query_formats = query_formats, .priv_size = sizeof(FieldMatchContext), .init = fieldmatch_init, + .activate = activate, .uninit = fieldmatch_uninit, .inputs = NULL, .outputs = fieldmatch_outputs, diff --git a/libavfilter/vf_fillborders.c b/libavfilter/vf_fillborders.c index df883bc62..134458702 100644 --- a/libavfilter/vf_fillborders.c +++ b/libavfilter/vf_fillborders.c @@ -73,7 +73,7 @@ static int query_formats(AVFilterContext *ctx) AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRP9, AV_PIX_FMT_GBRP10, AV_PIX_FMT_GBRP12, AV_PIX_FMT_GBRP14, AV_PIX_FMT_GBRP16, AV_PIX_FMT_GBRAP, AV_PIX_FMT_GBRAP10, AV_PIX_FMT_GBRAP12, AV_PIX_FMT_GBRAP16, - AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY9, AV_PIX_FMT_GRAY10, AV_PIX_FMT_GRAY12, AV_PIX_FMT_GRAY16, + AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY9, AV_PIX_FMT_GRAY10, AV_PIX_FMT_GRAY12, AV_PIX_FMT_GRAY14, AV_PIX_FMT_GRAY16, AV_PIX_FMT_NONE }; AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts); diff --git a/libavfilter/vf_fps.c b/libavfilter/vf_fps.c index 9167a00a1..6b99f20d2 100644 --- a/libavfilter/vf_fps.c +++ b/libavfilter/vf_fps.c @@ -249,6 +249,8 @@ static int write_frame(AVFilterContext *ctx, FPSContext *s, AVFilterLink *outlin frame = av_frame_clone(s->frames[0]); if (!frame) return AVERROR(ENOMEM); + // Make sure Closed Captions will not be duplicated + av_frame_remove_side_data(s->frames[0], AV_FRAME_DATA_A53_CC); frame->pts = s->next_pts++; av_log(ctx, AV_LOG_DEBUG, "Writing frame with pts %"PRId64" to pts %"PRId64"\n", diff --git a/libavfilter/vf_framerate.c b/libavfilter/vf_framerate.c index 3e2615be5..06e463e4d 100644 --- a/libavfilter/vf_framerate.c +++ b/libavfilter/vf_framerate.c @@ -33,12 +33,13 @@ #include "libavutil/internal.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" -#include "libavutil/pixelutils.h" #include "avfilter.h" #include "internal.h" #include "video.h" +#include "filters.h" #include "framerate.h" +#include "scene_sad.h" #define OFFSET(x) offsetof(FrameRateContext, x) #define V AV_OPT_FLAG_VIDEO_PARAM @@ -61,52 +62,6 @@ static const AVOption framerate_options[] = { AVFILTER_DEFINE_CLASS(framerate); -static av_always_inline int64_t sad_8x8_16(const uint16_t *src1, ptrdiff_t stride1, - const uint16_t *src2, ptrdiff_t stride2) -{ - int sum = 0; - int x, y; - - for (y = 0; y < 8; y++) { - for (x = 0; x < 8; x++) - sum += FFABS(src1[x] - src2[x]); - src1 += stride1; - src2 += stride2; - } - return sum; -} - -static int64_t scene_sad16(FrameRateContext *s, const uint16_t *p1, int p1_linesize, const uint16_t* p2, int p2_linesize, const int width, const int height) -{ - int64_t sad; - int x, y; - for (sad = y = 0; y < height - 7; y += 8) { - for (x = 0; x < width - 7; x += 8) { - sad += sad_8x8_16(p1 + y * p1_linesize + x, - p1_linesize, - p2 + y * p2_linesize + x, - p2_linesize); - } - } - return sad; -} - -static int64_t scene_sad8(FrameRateContext *s, uint8_t *p1, int p1_linesize, uint8_t* p2, int p2_linesize, const int width, const int height) -{ - int64_t sad; - int x, y; - for (sad = y = 0; y < height - 7; y += 8) { - for (x = 0; x < width - 7; x += 8) { - sad += s->sad(p1 + y * p1_linesize + x, - p1_linesize, - p2 + y * p2_linesize + x, - p2_linesize); - } - } - emms_c(); - return sad; -} - static double get_scene_score(AVFilterContext *ctx, AVFrame *crnt, AVFrame *next) { FrameRateContext *s = ctx->priv; @@ -116,16 +71,13 @@ static double get_scene_score(AVFilterContext *ctx, AVFrame *crnt, AVFrame *next if (crnt->height == next->height && crnt->width == next->width) { - int64_t sad; + uint64_t sad; double mafd, diff; ff_dlog(ctx, "get_scene_score() process\n"); - if (s->bitdepth == 8) - sad = scene_sad8(s, crnt->data[0], crnt->linesize[0], next->data[0], next->linesize[0], crnt->width, crnt->height); - else - sad = scene_sad16(s, (const uint16_t*)crnt->data[0], crnt->linesize[0] / 2, (const uint16_t*)next->data[0], next->linesize[0] / 2, crnt->width, crnt->height); - - mafd = (double)sad * 100.0 / FFMAX(1, (crnt->height & ~7) * (crnt->width & ~7)) / (1 << s->bitdepth); + s->sad(crnt->data[0], crnt->linesize[0], next->data[0], next->linesize[0], crnt->width, crnt->height, &sad); + emms_c(); + mafd = (double)sad * 100.0 / (crnt->width * crnt->height) / (1 << s->bitdepth); diff = fabs(mafd - s->prev_mafd); ret = av_clipf(FFMIN(mafd, diff), 0, 100.0); s->prev_mafd = mafd; @@ -349,7 +301,7 @@ static int config_input(AVFilterLink *inlink) s->bitdepth = pix_desc->comp[0].depth; s->vsub = pix_desc->log2_chroma_h; - s->sad = av_pixelutils_get_sad_fn(3, 3, 2, s); // 8x8 both sources aligned + s->sad = ff_scene_sad_get_fn(s->bitdepth == 8 ? 8 : 16); if (!s->sad) return AVERROR(EINVAL); @@ -360,53 +312,81 @@ static int config_input(AVFilterLink *inlink) return 0; } -static int filter_frame(AVFilterLink *inlink, AVFrame *inpicref) +static int activate(AVFilterContext *ctx) { - int ret; - AVFilterContext *ctx = inlink->dst; + int ret, status; + AVFilterLink *inlink = ctx->inputs[0]; + AVFilterLink *outlink = ctx->outputs[0]; FrameRateContext *s = ctx->priv; + AVFrame *inpicref; int64_t pts; - if (inpicref->interlaced_frame) - av_log(ctx, AV_LOG_WARNING, "Interlaced frame found - the output will not be correct.\n"); + FF_FILTER_FORWARD_STATUS_BACK(outlink, inlink); - if (inpicref->pts == AV_NOPTS_VALUE) { - av_log(ctx, AV_LOG_WARNING, "Ignoring frame without PTS.\n"); - return 0; +retry: + ret = process_work_frame(ctx); + if (ret < 0) + return ret; + else if (ret == 1) + return ff_filter_frame(outlink, s->work); + + ret = ff_inlink_consume_frame(inlink, &inpicref); + if (ret < 0) + return ret; + + if (inpicref) { + if (inpicref->interlaced_frame) + av_log(ctx, AV_LOG_WARNING, "Interlaced frame found - the output will not be correct.\n"); + + if (inpicref->pts == AV_NOPTS_VALUE) { + av_log(ctx, AV_LOG_WARNING, "Ignoring frame without PTS.\n"); + av_frame_free(&inpicref); + } } - pts = av_rescale_q(inpicref->pts, s->srce_time_base, s->dest_time_base); - if (s->f1 && pts == s->pts1) { - av_log(ctx, AV_LOG_WARNING, "Ignoring frame with same PTS.\n"); - return 0; + if (inpicref) { + pts = av_rescale_q(inpicref->pts, s->srce_time_base, s->dest_time_base); + + if (s->f1 && pts == s->pts1) { + av_log(ctx, AV_LOG_WARNING, "Ignoring frame with same PTS.\n"); + av_frame_free(&inpicref); + } } - av_frame_free(&s->f0); - s->f0 = s->f1; - s->pts0 = s->pts1; - s->f1 = inpicref; - s->pts1 = pts; - s->delta = s->pts1 - s->pts0; - s->score = -1.0; - - if (s->delta < 0) { - av_log(ctx, AV_LOG_WARNING, "PTS discontinuity.\n"); - s->start_pts = s->pts1; - s->n = 0; + if (inpicref) { av_frame_free(&s->f0); + s->f0 = s->f1; + s->pts0 = s->pts1; + s->f1 = inpicref; + s->pts1 = pts; + s->delta = s->pts1 - s->pts0; + s->score = -1.0; + + if (s->delta < 0) { + av_log(ctx, AV_LOG_WARNING, "PTS discontinuity.\n"); + s->start_pts = s->pts1; + s->n = 0; + av_frame_free(&s->f0); + } + + if (s->start_pts == AV_NOPTS_VALUE) + s->start_pts = s->pts1; + + goto retry; } - if (s->start_pts == AV_NOPTS_VALUE) - s->start_pts = s->pts1; + if (ff_inlink_acknowledge_status(inlink, &status, &pts)) { + if (!s->flush) { + s->flush = 1; + goto retry; + } + ff_outlink_set_status(outlink, status, pts); + return 0; + } - do { - ret = process_work_frame(ctx); - if (ret <= 0) - return ret; - ret = ff_filter_frame(ctx->outputs[0], s->work); - } while (ret >= 0); + FF_FILTER_FORWARD_WANTED(outlink, inlink); - return ret; + return FFERROR_NOT_READY; } static int config_output(AVFilterLink *outlink) @@ -454,33 +434,11 @@ static int config_output(AVFilterLink *outlink) return 0; } -static int request_frame(AVFilterLink *outlink) -{ - AVFilterContext *ctx = outlink->src; - FrameRateContext *s = ctx->priv; - int ret; - - ff_dlog(ctx, "request_frame()\n"); - - ret = ff_request_frame(ctx->inputs[0]); - if (ret == AVERROR_EOF && s->f1 && !s->flush) { - s->flush = 1; - ret = process_work_frame(ctx); - if (ret < 0) - return ret; - ret = ret ? ff_filter_frame(ctx->outputs[0], s->work) : AVERROR_EOF; - } - - ff_dlog(ctx, "request_frame() source's request_frame() returned:%d\n", ret); - return ret; -} - static const AVFilterPad framerate_inputs[] = { { .name = "default", .type = AVMEDIA_TYPE_VIDEO, .config_props = config_input, - .filter_frame = filter_frame, }, { NULL } }; @@ -489,7 +447,6 @@ static const AVFilterPad framerate_outputs[] = { { .name = "default", .type = AVMEDIA_TYPE_VIDEO, - .request_frame = request_frame, .config_props = config_output, }, { NULL } @@ -506,4 +463,5 @@ AVFilter ff_vf_framerate = { .inputs = framerate_inputs, .outputs = framerate_outputs, .flags = AVFILTER_FLAG_SLICE_THREADS, + .activate = activate, }; diff --git a/libavfilter/vf_freezedetect.c b/libavfilter/vf_freezedetect.c new file mode 100644 index 000000000..cc086afee --- /dev/null +++ b/libavfilter/vf_freezedetect.c @@ -0,0 +1,235 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * video freeze detection filter + */ + +#include "libavutil/avassert.h" +#include "libavutil/imgutils.h" +#include "libavutil/opt.h" +#include "libavutil/pixdesc.h" +#include "libavutil/timestamp.h" + +#include "avfilter.h" +#include "filters.h" +#include "scene_sad.h" + +typedef struct FreezeDetectContext { + const AVClass *class; + + ptrdiff_t width[4]; + ptrdiff_t height[4]; + ff_scene_sad_fn sad; + int bitdepth; + AVFrame *reference_frame; + int64_t n; + int64_t reference_n; + int frozen; + + double noise; + int64_t duration; ///< minimum duration of frozen frame until notification +} FreezeDetectContext; + +#define OFFSET(x) offsetof(FreezeDetectContext, x) +#define V AV_OPT_FLAG_VIDEO_PARAM +#define F AV_OPT_FLAG_FILTERING_PARAM + +static const AVOption freezedetect_options[] = { + { "n", "set noise tolerance", OFFSET(noise), AV_OPT_TYPE_DOUBLE, {.dbl=0.001}, 0, 1.0, V|F }, + { "noise", "set noise tolerance", OFFSET(noise), AV_OPT_TYPE_DOUBLE, {.dbl=0.001}, 0, 1.0, V|F }, + { "d", "set minimum duration in seconds", OFFSET(duration), AV_OPT_TYPE_DURATION, {.i64=2000000}, 0, INT64_MAX, V|F }, + { "duration", "set minimum duration in seconds", OFFSET(duration), AV_OPT_TYPE_DURATION, {.i64=2000000}, 0, INT64_MAX, V|F }, + + {NULL} +}; + +AVFILTER_DEFINE_CLASS(freezedetect); + +static int query_formats(AVFilterContext *ctx) +{ + static const enum AVPixelFormat pix_fmts[] = { + AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUYV422, AV_PIX_FMT_RGB24, + AV_PIX_FMT_BGR24, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV444P, + AV_PIX_FMT_YUV410P, AV_PIX_FMT_YUV411P, AV_PIX_FMT_GRAY8, + AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUVJ444P, + AV_PIX_FMT_UYVY422, AV_PIX_FMT_NV12, AV_PIX_FMT_NV21, AV_PIX_FMT_ARGB, + AV_PIX_FMT_RGBA, AV_PIX_FMT_ABGR, AV_PIX_FMT_BGRA, AV_PIX_FMT_GRAY16, + AV_PIX_FMT_YUV440P, AV_PIX_FMT_YUVJ440P, AV_PIX_FMT_YUVA420P, + AV_PIX_FMT_YUV420P16, AV_PIX_FMT_YUV422P16, AV_PIX_FMT_YUV444P16, + AV_PIX_FMT_YA8, AV_PIX_FMT_YUV420P9, AV_PIX_FMT_YUV420P10, + AV_PIX_FMT_YUV422P10, AV_PIX_FMT_YUV444P9, AV_PIX_FMT_YUV444P10, + AV_PIX_FMT_YUV422P9, AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRP9, + AV_PIX_FMT_GBRP10, AV_PIX_FMT_GBRP16, AV_PIX_FMT_YUVA422P, + AV_PIX_FMT_YUVA444P, AV_PIX_FMT_YUVA420P9, AV_PIX_FMT_YUVA422P9, + AV_PIX_FMT_YUVA444P9, AV_PIX_FMT_YUVA420P10, AV_PIX_FMT_YUVA422P10, + AV_PIX_FMT_YUVA444P10, AV_PIX_FMT_YUVA420P16, AV_PIX_FMT_YUVA422P16, + AV_PIX_FMT_YUVA444P16, AV_PIX_FMT_NV16, AV_PIX_FMT_YVYU422, + AV_PIX_FMT_GBRAP, AV_PIX_FMT_GBRAP16, AV_PIX_FMT_YUV420P12, + AV_PIX_FMT_YUV420P14, AV_PIX_FMT_YUV422P12, AV_PIX_FMT_YUV422P14, + AV_PIX_FMT_YUV444P12, AV_PIX_FMT_YUV444P14, AV_PIX_FMT_GBRP12, + AV_PIX_FMT_GBRP14, AV_PIX_FMT_YUVJ411P, AV_PIX_FMT_YUV440P10, + AV_PIX_FMT_YUV440P12, AV_PIX_FMT_GBRAP12, AV_PIX_FMT_GBRAP10, + AV_PIX_FMT_GRAY12, AV_PIX_FMT_GRAY10, AV_PIX_FMT_GRAY9, + AV_PIX_FMT_GRAY14, + AV_PIX_FMT_NONE + }; + + AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts); + if (!fmts_list) + return AVERROR(ENOMEM); + return ff_set_common_formats(ctx, fmts_list); +} + +static int config_input(AVFilterLink *inlink) +{ + AVFilterContext *ctx = inlink->dst; + FreezeDetectContext *s = ctx->priv; + const AVPixFmtDescriptor *pix_desc = av_pix_fmt_desc_get(inlink->format); + + s->bitdepth = pix_desc->comp[0].depth; + + for (int plane = 0; plane < 4; plane++) { + ptrdiff_t line_size = av_image_get_linesize(inlink->format, inlink->w, plane); + s->width[plane] = line_size >> (s->bitdepth > 8); + s->height[plane] = inlink->h >> ((plane == 1 || plane == 2) ? pix_desc->log2_chroma_h : 0); + } + + s->sad = ff_scene_sad_get_fn(s->bitdepth == 8 ? 8 : 16); + if (!s->sad) + return AVERROR(EINVAL); + + return 0; +} + +static av_cold void uninit(AVFilterContext *ctx) +{ + FreezeDetectContext *s = ctx->priv; + av_frame_free(&s->reference_frame); +} + +static int is_frozen(FreezeDetectContext *s, AVFrame *reference, AVFrame *frame) +{ + uint64_t sad = 0; + uint64_t count = 0; + double mafd; + for (int plane = 0; plane < 4; plane++) { + if (s->width[plane]) { + uint64_t plane_sad; + s->sad(frame->data[plane], frame->linesize[plane], + reference->data[plane], reference->linesize[plane], + s->width[plane], s->height[plane], &plane_sad); + sad += plane_sad; + count += s->width[plane] * s->height[plane]; + } + } + emms_c(); + mafd = (double)sad / count / (1ULL << s->bitdepth); + return (mafd <= s->noise); +} + +static int set_meta(FreezeDetectContext *s, AVFrame *frame, const char *key, const char *value) +{ + av_log(s, AV_LOG_INFO, "%s: %s\n", key, value); + return av_dict_set(&frame->metadata, key, value, 0); +} + +static int activate(AVFilterContext *ctx) +{ + int ret; + AVFilterLink *inlink = ctx->inputs[0]; + AVFilterLink *outlink = ctx->outputs[0]; + FreezeDetectContext *s = ctx->priv; + AVFrame *frame; + + FF_FILTER_FORWARD_STATUS_BACK(outlink, inlink); + + ret = ff_inlink_consume_frame(inlink, &frame); + if (ret < 0) + return ret; + + if (frame) { + int frozen = 0; + s->n++; + + if (s->reference_frame) { + int64_t duration; + if (s->reference_frame->pts == AV_NOPTS_VALUE || frame->pts == AV_NOPTS_VALUE || frame->pts < s->reference_frame->pts) // Discontinuity? + duration = inlink->frame_rate.num > 0 ? av_rescale_q(s->n - s->reference_n, av_inv_q(inlink->frame_rate), AV_TIME_BASE_Q) : 0; + else + duration = av_rescale_q(frame->pts - s->reference_frame->pts, inlink->time_base, AV_TIME_BASE_Q); + + frozen = is_frozen(s, s->reference_frame, frame); + if (duration >= s->duration) { + if (!s->frozen) + set_meta(s, frame, "lavfi.freezedetect.freeze_start", av_ts2timestr(s->reference_frame->pts, &inlink->time_base)); + if (!frozen) { + set_meta(s, frame, "lavfi.freezedetect.freeze_duration", av_ts2timestr(duration, &AV_TIME_BASE_Q)); + set_meta(s, frame, "lavfi.freezedetect.freeze_end", av_ts2timestr(frame->pts, &inlink->time_base)); + } + s->frozen = frozen; + } + } + + if (!frozen) { + av_frame_free(&s->reference_frame); + s->reference_frame = av_frame_clone(frame); + s->reference_n = s->n; + if (!s->reference_frame) { + av_frame_free(&frame); + return AVERROR(ENOMEM); + } + } + return ff_filter_frame(outlink, frame); + } + + FF_FILTER_FORWARD_STATUS(inlink, outlink); + FF_FILTER_FORWARD_WANTED(outlink, inlink); + + return FFERROR_NOT_READY; +} + +static const AVFilterPad freezedetect_inputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + .config_props = config_input, + }, + { NULL } +}; + +static const AVFilterPad freezedetect_outputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + }, + { NULL } +}; + +AVFilter ff_vf_freezedetect = { + .name = "freezedetect", + .description = NULL_IF_CONFIG_SMALL("Detects frozen video input."), + .priv_size = sizeof(FreezeDetectContext), + .priv_class = &freezedetect_class, + .uninit = uninit, + .query_formats = query_formats, + .inputs = freezedetect_inputs, + .outputs = freezedetect_outputs, + .activate = activate, +}; diff --git a/libavfilter/vf_frei0r.c b/libavfilter/vf_frei0r.c index 8aeac0851..5d3840599 100644 --- a/libavfilter/vf_frei0r.c +++ b/libavfilter/vf_frei0r.c @@ -93,6 +93,7 @@ static int set_param(AVFilterContext *ctx, f0r_param_info_t info, int index, cha double d; f0r_param_color_t col; f0r_param_position_t pos; + f0r_param_string str; } val; char *tail; uint8_t rgba[4]; @@ -124,6 +125,10 @@ static int set_param(AVFilterContext *ctx, f0r_param_info_t info, int index, cha if (sscanf(param, "%lf/%lf", &val.pos.x, &val.pos.y) != 2) goto fail; break; + + case F0R_PARAM_STRING: + val.str = param; + break; } s->set_param_value(s->instance, &val, index); diff --git a/libavfilter/vf_fspp.h b/libavfilter/vf_fspp.h index 74a34473b..73d8c7c77 100644 --- a/libavfilter/vf_fspp.h +++ b/libavfilter/vf_fspp.h @@ -31,9 +31,7 @@ #define DCTSIZE 8 #define DCTSIZE_S "8" -#define FIX(x,s) ((int) ((x) * (1 << s) + 0.5) & 0xffff) -#define C64(x) ((uint64_t)((x) | (x) << 16)) <<32 | (uint64_t)(x) | (uint64_t)(x) << 16 -#define FIX64(x,s) C64(FIX(x,s)) +#define FIX(x,s) ((x) * (1 << s) + 0.5) #define MULTIPLY16H(x,k) (((x) * (k)) >> 16) #define THRESHOLD(r,x,t) \ diff --git a/libavfilter/vf_gblur.c b/libavfilter/vf_gblur.c index fd901e20d..e71b33da8 100644 --- a/libavfilter/vf_gblur.c +++ b/libavfilter/vf_gblur.c @@ -30,30 +30,10 @@ #include "libavutil/pixdesc.h" #include "avfilter.h" #include "formats.h" +#include "gblur.h" #include "internal.h" #include "video.h" -typedef struct GBlurContext { - const AVClass *class; - - float sigma; - float sigmaV; - int steps; - int planes; - - int depth; - int planewidth[4]; - int planeheight[4]; - float *buffer; - float boundaryscale; - float boundaryscaleV; - float postscale; - float postscaleV; - float nu; - float nuV; - int nb_planes; -} GBlurContext; - #define OFFSET(x) offsetof(GBlurContext, x) #define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM @@ -72,6 +52,28 @@ typedef struct ThreadData { int width; } ThreadData; +static void horiz_slice_c(float *buffer, int width, int height, int steps, + float nu, float bscale) +{ + int step, x, y; + float *ptr; + for (y = 0; y < height; y++) { + for (step = 0; step < steps; step++) { + ptr = buffer + width * y; + ptr[0] *= bscale; + + /* Filter rightwards */ + for (x = 1; x < width; x++) + ptr[x] += nu * ptr[x - 1]; + ptr[x = width - 1] *= bscale; + + /* Filter leftwards */ + for (; x > 0; x--) + ptr[x - 1] += nu * ptr[x]; + } + } +} + static int filter_horizontally(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) { GBlurContext *s = ctx->priv; @@ -84,30 +86,47 @@ static int filter_horizontally(AVFilterContext *ctx, void *arg, int jobnr, int n const int steps = s->steps; const float nu = s->nu; float *buffer = s->buffer; - int y, x, step; - float *ptr; - - /* Filter horizontally along each row */ - for (y = slice_start; y < slice_end; y++) { - for (step = 0; step < steps; step++) { - ptr = buffer + width * y; - ptr[0] *= boundaryscale; - - /* Filter rightwards */ - for (x = 1; x < width; x++) - ptr[x] += nu * ptr[x - 1]; - - ptr[x = width - 1] *= boundaryscale; - - /* Filter leftwards */ - for (; x > 0; x--) - ptr[x - 1] += nu * ptr[x]; - } - } + s->horiz_slice(buffer + width * slice_start, width, slice_end - slice_start, + steps, nu, boundaryscale); + emms_c(); return 0; } +static void do_vertical_columns(float *buffer, int width, int height, + int column_begin, int column_end, int steps, + float nu, float boundaryscale, int column_step) +{ + const int numpixels = width * height; + int i, x, k, step; + float *ptr; + for (x = column_begin; x < column_end;) { + for (step = 0; step < steps; step++) { + ptr = buffer + x; + for (k = 0; k < column_step; k++) { + ptr[k] *= boundaryscale; + } + /* Filter downwards */ + for (i = width; i < numpixels; i += width) { + for (k = 0; k < column_step; k++) { + ptr[i + k] += nu * ptr[i - width + k]; + } + } + i = numpixels - width; + + for (k = 0; k < column_step; k++) + ptr[i + k] *= boundaryscale; + + /* Filter upwards */ + for (; i > 0; i -= width) { + for (k = 0; k < column_step; k++) + ptr[i - width + k] += nu * ptr[i + k]; + } + } + x += column_step; + } +} + static int filter_vertically(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) { GBlurContext *s = ctx->priv; @@ -117,31 +136,19 @@ static int filter_vertically(AVFilterContext *ctx, void *arg, int jobnr, int nb_ const int slice_start = (width * jobnr ) / nb_jobs; const int slice_end = (width * (jobnr+1)) / nb_jobs; const float boundaryscale = s->boundaryscaleV; - const int numpixels = width * height; const int steps = s->steps; const float nu = s->nuV; float *buffer = s->buffer; - int i, x, step; - float *ptr; + int aligned_end; - /* Filter vertically along each column */ - for (x = slice_start; x < slice_end; x++) { - for (step = 0; step < steps; step++) { - ptr = buffer + x; - ptr[0] *= boundaryscale; - - /* Filter downwards */ - for (i = width; i < numpixels; i += width) - ptr[i] += nu * ptr[i - width]; - - ptr[i = numpixels - width] *= boundaryscale; - - /* Filter upwards */ - for (; i > 0; i -= width) - ptr[i - width] += nu * ptr[i]; - } - } + aligned_end = slice_start + (((slice_end - slice_start) >> 3) << 3); + /* Filter vertically along columns (process 8 columns in each step) */ + do_vertical_columns(buffer, width, height, slice_start, aligned_end, + steps, nu, boundaryscale, 8); + /* Filter un-aligned columns one by one */ + do_vertical_columns(buffer, width, height, aligned_end, slice_end, + steps, nu, boundaryscale, 1); return 0; } @@ -202,13 +209,20 @@ static int query_formats(AVFilterContext *ctx) AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRP9, AV_PIX_FMT_GBRP10, AV_PIX_FMT_GBRP12, AV_PIX_FMT_GBRP14, AV_PIX_FMT_GBRP16, AV_PIX_FMT_GBRAP, AV_PIX_FMT_GBRAP10, AV_PIX_FMT_GBRAP12, AV_PIX_FMT_GBRAP16, - AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY9, AV_PIX_FMT_GRAY10, AV_PIX_FMT_GRAY12, AV_PIX_FMT_GRAY16, + AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY9, AV_PIX_FMT_GRAY10, AV_PIX_FMT_GRAY12, AV_PIX_FMT_GRAY14, AV_PIX_FMT_GRAY16, AV_PIX_FMT_NONE }; return ff_set_common_formats(ctx, ff_make_format_list(pix_fmts)); } +void ff_gblur_init(GBlurContext *s) +{ + s->horiz_slice = horiz_slice_c; + if (ARCH_X86_64) + ff_gblur_init_x86(s); +} + static int config_input(AVFilterLink *inlink) { const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format); @@ -229,6 +243,7 @@ static int config_input(AVFilterLink *inlink) if (s->sigmaV < 0) { s->sigmaV = s->sigma; } + ff_gblur_init(s); return 0; } diff --git a/libavfilter/vf_geq.c b/libavfilter/vf_geq.c index 2aa1259c9..91eb9685f 100644 --- a/libavfilter/vf_geq.c +++ b/libavfilter/vf_geq.c @@ -191,9 +191,9 @@ static int geq_query_formats(AVFilterContext *ctx) AV_PIX_FMT_YUV444P10, AV_PIX_FMT_YUV422P10, AV_PIX_FMT_YUV420P10, AV_PIX_FMT_YUV440P10, AV_PIX_FMT_YUVA444P10, AV_PIX_FMT_YUVA422P10, AV_PIX_FMT_YUVA420P10, - AV_PIX_FMT_GRAY10, + AV_PIX_FMT_GRAY9, AV_PIX_FMT_GRAY10, AV_PIX_FMT_YUV444P12, AV_PIX_FMT_YUV422P12, AV_PIX_FMT_YUV420P12, - AV_PIX_FMT_GRAY12, + AV_PIX_FMT_GRAY12, AV_PIX_FMT_GRAY14, AV_PIX_FMT_YUV444P14, AV_PIX_FMT_YUV422P14, AV_PIX_FMT_YUV420P14, AV_PIX_FMT_YUV444P16, AV_PIX_FMT_YUV422P16, AV_PIX_FMT_YUV420P16, AV_PIX_FMT_YUVA444P16, AV_PIX_FMT_YUVA422P16, AV_PIX_FMT_YUVA420P16, diff --git a/libavfilter/vf_hue.c b/libavfilter/vf_hue.c index 45a5a1a92..323333b33 100644 --- a/libavfilter/vf_hue.c +++ b/libavfilter/vf_hue.c @@ -80,6 +80,9 @@ typedef struct HueContext { uint8_t lut_l[256]; uint8_t lut_u[256][256]; uint8_t lut_v[256][256]; + uint16_t lut_l16[65536]; + uint16_t lut_u10[1024][1024]; + uint16_t lut_v10[1024][1024]; } HueContext; #define OFFSET(x) offsetof(HueContext, x) @@ -117,6 +120,9 @@ static inline void create_luma_lut(HueContext *h) for (i = 0; i < 256; i++) { h->lut_l[i] = av_clip_uint8(i + b * 25.5); } + for (i = 0; i < 65536; i++) { + h->lut_l16[i] = av_clip_uintp2(i + b * 102.4, 10); + } } static inline void create_chrominance_lut(HueContext *h, const int32_t c, @@ -148,6 +154,25 @@ static inline void create_chrominance_lut(HueContext *h, const int32_t c, h->lut_v[i][j] = av_clip_uint8(new_v); } } + for (i = 0; i < 1024; i++) { + for (j = 0; j < 1024; j++) { + u = i - 512; + v = j - 512; + /* + * Apply the rotation of the vector : (c * u) - (s * v) + * (s * u) + (c * v) + * De-normalize the components (without forgetting to scale 512 + * by << 16) + * Finally scale back the result by >> 16 + */ + new_u = ((c * u) - (s * v) + (1 << 15) + (512 << 16)) >> 16; + new_v = ((s * u) + (c * v) + (1 << 15) + (512 << 16)) >> 16; + + /* Prevent a potential overflow */ + h->lut_u10[i][j] = av_clip_uintp2(new_u, 10); + h->lut_v10[i][j] = av_clip_uintp2(new_v, 10); + } + } } static int set_expr(AVExpr **pexpr_ptr, char **expr_ptr, @@ -231,6 +256,11 @@ static int query_formats(AVFilterContext *ctx) AV_PIX_FMT_YUV410P, AV_PIX_FMT_YUV440P, AV_PIX_FMT_YUVA444P, AV_PIX_FMT_YUVA422P, AV_PIX_FMT_YUVA420P, + AV_PIX_FMT_YUV444P10, AV_PIX_FMT_YUV422P10, + AV_PIX_FMT_YUV420P10, + AV_PIX_FMT_YUV440P10, + AV_PIX_FMT_YUVA444P10, AV_PIX_FMT_YUVA422P10, + AV_PIX_FMT_YUVA420P10, AV_PIX_FMT_NONE }; AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts); @@ -271,6 +301,22 @@ static void apply_luma_lut(HueContext *s, } } +static void apply_luma_lut10(HueContext *s, + uint16_t *ldst, const int dst_linesize, + uint16_t *lsrc, const int src_linesize, + int w, int h) +{ + int i; + + while (h--) { + for (i = 0; i < w; i++) + ldst[i] = s->lut_l16[lsrc[i]]; + + lsrc += src_linesize; + ldst += dst_linesize; + } +} + static void apply_lut(HueContext *s, uint8_t *udst, uint8_t *vdst, const int dst_linesize, uint8_t *usrc, uint8_t *vsrc, const int src_linesize, @@ -294,6 +340,29 @@ static void apply_lut(HueContext *s, } } +static void apply_lut10(HueContext *s, + uint16_t *udst, uint16_t *vdst, const int dst_linesize, + uint16_t *usrc, uint16_t *vsrc, const int src_linesize, + int w, int h) +{ + int i; + + while (h--) { + for (i = 0; i < w; i++) { + const int u = av_clip_uintp2(usrc[i], 10); + const int v = av_clip_uintp2(vsrc[i], 10); + + udst[i] = s->lut_u10[u][v]; + vdst[i] = s->lut_v10[u][v]; + } + + usrc += src_linesize; + vsrc += src_linesize; + udst += dst_linesize; + vdst += dst_linesize; + } +} + #define TS2D(ts) ((ts) == AV_NOPTS_VALUE ? NAN : (double)(ts)) #define TS2T(ts, tb) ((ts) == AV_NOPTS_VALUE ? NAN : (double)(ts) * av_q2d(tb)) @@ -305,6 +374,8 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *inpic) const int32_t old_hue_sin = hue->hue_sin, old_hue_cos = hue->hue_cos; const float old_brightness = hue->brightness; int direct = 0; + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format); + const int bps = desc->comp[0].depth > 8 ? 2 : 1; if (av_frame_is_writable(inpic)) { direct = 1; @@ -367,21 +438,31 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *inpic) if (!direct) { if (!hue->brightness) av_image_copy_plane(outpic->data[0], outpic->linesize[0], - inpic->data[0], inpic->linesize[0], - inlink->w, inlink->h); + inpic->data[0], inpic->linesize[0], + inlink->w * bps, inlink->h); if (inpic->data[3]) av_image_copy_plane(outpic->data[3], outpic->linesize[3], - inpic->data[3], inpic->linesize[3], - inlink->w, inlink->h); + inpic->data[3], inpic->linesize[3], + inlink->w * bps, inlink->h); } - apply_lut(hue, outpic->data[1], outpic->data[2], outpic->linesize[1], - inpic->data[1], inpic->data[2], inpic->linesize[1], - AV_CEIL_RSHIFT(inlink->w, hue->hsub), - AV_CEIL_RSHIFT(inlink->h, hue->vsub)); - if (hue->brightness) - apply_luma_lut(hue, outpic->data[0], outpic->linesize[0], - inpic->data[0], inpic->linesize[0], inlink->w, inlink->h); + if (bps > 1) { + apply_lut10(hue, (uint16_t*)outpic->data[1], (uint16_t*)outpic->data[2], outpic->linesize[1]/2, + (uint16_t*) inpic->data[1], (uint16_t*) inpic->data[2], inpic->linesize[1]/2, + AV_CEIL_RSHIFT(inlink->w, hue->hsub), + AV_CEIL_RSHIFT(inlink->h, hue->vsub)); + if (hue->brightness) + apply_luma_lut10(hue, (uint16_t*)outpic->data[0], outpic->linesize[0]/2, + (uint16_t*) inpic->data[0], inpic->linesize[0]/2, inlink->w, inlink->h); + } else { + apply_lut(hue, outpic->data[1], outpic->data[2], outpic->linesize[1], + inpic->data[1], inpic->data[2], inpic->linesize[1], + AV_CEIL_RSHIFT(inlink->w, hue->hsub), + AV_CEIL_RSHIFT(inlink->h, hue->vsub)); + if (hue->brightness) + apply_luma_lut(hue, outpic->data[0], outpic->linesize[0], + inpic->data[0], inpic->linesize[0], inlink->w, inlink->h); + } if (!direct) av_frame_free(&inpic); diff --git a/libavfilter/vf_hwupload_cuda.c b/libavfilter/vf_hwupload_cuda.c index 063f0285c..4d83e6c8f 100644 --- a/libavfilter/vf_hwupload_cuda.c +++ b/libavfilter/vf_hwupload_cuda.c @@ -59,6 +59,7 @@ static int cudaupload_query_formats(AVFilterContext *ctx) static const enum AVPixelFormat input_pix_fmts[] = { AV_PIX_FMT_NV12, AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV444P, AV_PIX_FMT_P010, AV_PIX_FMT_P016, AV_PIX_FMT_YUV444P16, + AV_PIX_FMT_0RGB32, AV_PIX_FMT_0BGR32, AV_PIX_FMT_NONE, }; static const enum AVPixelFormat output_pix_fmts[] = { diff --git a/libavfilter/vf_hysteresis.c b/libavfilter/vf_hysteresis.c index 551b33f33..48e9179f4 100644 --- a/libavfilter/vf_hysteresis.c +++ b/libavfilter/vf_hysteresis.c @@ -77,7 +77,7 @@ static int query_formats(AVFilterContext *ctx) AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRP9, AV_PIX_FMT_GBRP10, AV_PIX_FMT_GBRP12, AV_PIX_FMT_GBRP14, AV_PIX_FMT_GBRP16, AV_PIX_FMT_GBRAP, AV_PIX_FMT_GBRAP10, AV_PIX_FMT_GBRAP12, AV_PIX_FMT_GBRAP16, - AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY9, AV_PIX_FMT_GRAY10, AV_PIX_FMT_GRAY12, AV_PIX_FMT_GRAY16, + AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY9, AV_PIX_FMT_GRAY10, AV_PIX_FMT_GRAY12, AV_PIX_FMT_GRAY14, AV_PIX_FMT_GRAY16, AV_PIX_FMT_NONE }; @@ -311,7 +311,6 @@ static int config_output(AVFilterLink *outlink) outlink->w = base->w; outlink->h = base->h; - outlink->time_base = base->time_base; outlink->sample_aspect_ratio = base->sample_aspect_ratio; outlink->frame_rate = base->frame_rate; @@ -330,7 +329,10 @@ static int config_output(AVFilterLink *outlink) s->fs.opaque = s; s->fs.on_event = process_frame; - return ff_framesync_configure(&s->fs); + ret = ff_framesync_configure(&s->fs); + outlink->time_base = s->fs.time_base; + + return ret; } static int activate(AVFilterContext *ctx) diff --git a/libavfilter/vf_lagfun.c b/libavfilter/vf_lagfun.c new file mode 100644 index 000000000..329c7465e --- /dev/null +++ b/libavfilter/vf_lagfun.c @@ -0,0 +1,252 @@ +/* + * Copyright (c) 2019 Paul B Mahol + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/imgutils.h" +#include "libavutil/intreadwrite.h" +#include "libavutil/opt.h" +#include "libavutil/pixdesc.h" + +#include "avfilter.h" +#include "formats.h" +#include "internal.h" +#include "video.h" + +typedef struct LagfunContext { + const AVClass *class; + const AVPixFmtDescriptor *desc; + float decay; + int planes; + + int depth; + int nb_planes; + int linesize[4]; + int height[4]; + + AVFrame *old; + + int (*lagfun)(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs); +} LagfunContext; + +static int query_formats(AVFilterContext *ctx) +{ + static const enum AVPixelFormat pixel_fmts[] = { + AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY9, + AV_PIX_FMT_GRAY10, AV_PIX_FMT_GRAY12, AV_PIX_FMT_GRAY14, + AV_PIX_FMT_GRAY16, + AV_PIX_FMT_YUV410P, AV_PIX_FMT_YUV411P, + AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV422P, + AV_PIX_FMT_YUV440P, AV_PIX_FMT_YUV444P, + AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUVJ422P, + AV_PIX_FMT_YUVJ440P, AV_PIX_FMT_YUVJ444P, + AV_PIX_FMT_YUVJ411P, + AV_PIX_FMT_YUV420P9, AV_PIX_FMT_YUV422P9, AV_PIX_FMT_YUV444P9, + AV_PIX_FMT_YUV420P10, AV_PIX_FMT_YUV422P10, AV_PIX_FMT_YUV444P10, + AV_PIX_FMT_YUV440P10, + AV_PIX_FMT_YUV444P12, AV_PIX_FMT_YUV422P12, AV_PIX_FMT_YUV420P12, + AV_PIX_FMT_YUV440P12, + AV_PIX_FMT_YUV444P14, AV_PIX_FMT_YUV422P14, AV_PIX_FMT_YUV420P14, + AV_PIX_FMT_YUV420P16, AV_PIX_FMT_YUV422P16, AV_PIX_FMT_YUV444P16, + AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRP9, AV_PIX_FMT_GBRP10, + AV_PIX_FMT_GBRP12, AV_PIX_FMT_GBRP14, AV_PIX_FMT_GBRP16, + AV_PIX_FMT_NONE + }; + AVFilterFormats *formats = ff_make_format_list(pixel_fmts); + if (!formats) + return AVERROR(ENOMEM); + return ff_set_common_formats(ctx, formats); +} + +typedef struct ThreadData { + AVFrame *in, *out, *old; +} ThreadData; + +static int lagfun_frame8(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) +{ + LagfunContext *s = ctx->priv; + const float decay = s->decay; + ThreadData *td = arg; + AVFrame *in = td->in; + AVFrame *out = td->out; + AVFrame *old = td->old; + + for (int p = 0; p < s->nb_planes; p++) { + const int slice_start = (s->height[p] * jobnr) / nb_jobs; + const int slice_end = (s->height[p] * (jobnr+1)) / nb_jobs; + const uint8_t *src = in->data[p] + slice_start * in->linesize[p]; + const uint8_t *osrc = old->data[p] + slice_start * old->linesize[p]; + uint8_t *dst = out->data[p] + slice_start * out->linesize[p]; + + if (!((1 << p) & s->planes)) { + av_image_copy_plane(dst, out->linesize[p], + src, in->linesize[p], + s->linesize[p], slice_end - slice_start); + continue; + } + + for (int y = slice_start; y < slice_end; y++) { + for (int x = 0; x < s->linesize[p]; x++) + dst[x] = FFMAX(src[x], osrc[x] * decay); + + src += in->linesize[p]; + osrc += old->linesize[p]; + dst += out->linesize[p]; + } + } + + return 0; +} + +static int lagfun_frame16(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) +{ + LagfunContext *s = ctx->priv; + const float decay = s->decay; + ThreadData *td = arg; + AVFrame *in = td->in; + AVFrame *out = td->out; + AVFrame *old = td->old; + + for (int p = 0; p < s->nb_planes; p++) { + const int slice_start = (s->height[p] * jobnr) / nb_jobs; + const int slice_end = (s->height[p] * (jobnr+1)) / nb_jobs; + const uint16_t *src = (const uint16_t *)in->data[p] + slice_start * in->linesize[p] / 2; + const uint16_t *osrc = (const uint16_t *)old->data[p] + slice_start * old->linesize[p] / 2; + uint16_t *dst = (uint16_t *)out->data[p] + slice_start * out->linesize[p] / 2; + + if (!((1 << p) & s->planes)) { + av_image_copy_plane((uint8_t *)dst, out->linesize[p], + (uint8_t *)src, in->linesize[p], + s->linesize[p], slice_end - slice_start); + continue; + } + + for (int y = slice_start; y < slice_end; y++) { + for (int x = 0; x < s->linesize[p]; x++) + dst[x] = FFMAX(src[x], osrc[x] * decay); + + src += in->linesize[p] / 2; + osrc += old->linesize[p] / 2; + dst += out->linesize[p] / 2; + } + } + + return 0; +} + +static int config_output(AVFilterLink *outlink) +{ + AVFilterContext *ctx = outlink->src; + LagfunContext *s = ctx->priv; + AVFilterLink *inlink = ctx->inputs[0]; + int ret; + + s->desc = av_pix_fmt_desc_get(outlink->format); + if (!s->desc) + return AVERROR_BUG; + s->nb_planes = av_pix_fmt_count_planes(outlink->format); + s->depth = s->desc->comp[0].depth; + s->lagfun = s->depth <= 8 ? lagfun_frame8 : lagfun_frame16; + + if ((ret = av_image_fill_linesizes(s->linesize, inlink->format, inlink->w)) < 0) + return ret; + + s->height[1] = s->height[2] = AV_CEIL_RSHIFT(inlink->h, s->desc->log2_chroma_h); + s->height[0] = s->height[3] = inlink->h; + + return 0; +} + +static int filter_frame(AVFilterLink *inlink, AVFrame *in) +{ + AVFilterContext *ctx = inlink->dst; + AVFilterLink *outlink = ctx->outputs[0]; + LagfunContext *s = ctx->priv; + ThreadData td; + AVFrame *out; + + if (!s->old) { + s->old = av_frame_clone(in); + return ff_filter_frame(outlink, in); + } + + out = ff_get_video_buffer(outlink, outlink->w, outlink->h); + if (!out) { + av_frame_free(&in); + return AVERROR(ENOMEM); + } + out->pts = in->pts; + + td.out = out; + td.in = in; + td.old = s->old; + ctx->internal->execute(ctx, s->lagfun, &td, NULL, FFMIN(s->height[1], ff_filter_get_nb_threads(ctx))); + + av_frame_free(&s->old); + av_frame_free(&in); + s->old = av_frame_clone(out); + return ff_filter_frame(outlink, out); +} + +static av_cold void uninit(AVFilterContext *ctx) +{ + LagfunContext *s = ctx->priv; + + av_frame_free(&s->old); +} + +#define OFFSET(x) offsetof(LagfunContext, x) +#define FLAGS AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_FILTERING_PARAM + +static const AVOption lagfun_options[] = { + { "decay", "set decay", OFFSET(decay), AV_OPT_TYPE_FLOAT, {.dbl=.95}, 0, 1, FLAGS }, + { "planes", "set what planes to filter", OFFSET(planes), AV_OPT_TYPE_FLAGS, {.i64=15}, 0, 15, FLAGS }, + { NULL }, +}; + +static const AVFilterPad inputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + .filter_frame = filter_frame, + }, + { NULL } +}; + +static const AVFilterPad outputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + .config_props = config_output, + }, + { NULL } +}; + +AVFILTER_DEFINE_CLASS(lagfun); + +AVFilter ff_vf_lagfun = { + .name = "lagfun", + .description = NULL_IF_CONFIG_SMALL("Slowly update darker pixels."), + .priv_size = sizeof(LagfunContext), + .priv_class = &lagfun_class, + .query_formats = query_formats, + .uninit = uninit, + .outputs = outputs, + .inputs = inputs, + .flags = AVFILTER_FLAG_SLICE_THREADS, +}; diff --git a/libavfilter/vf_lensfun.c b/libavfilter/vf_lensfun.c new file mode 100644 index 000000000..089121ed0 --- /dev/null +++ b/libavfilter/vf_lensfun.c @@ -0,0 +1,548 @@ +/* + * Copyright (C) 2007 by Andrew Zabolotny (author of lensfun, from which this filter derives from) + * Copyright (C) 2018 Stephen Seo + * + * This file is part of FFmpeg. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 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. If not, see . + */ + +/** + * @file + * Lensfun filter, applies lens correction with parameters from the lensfun database + * + * @see https://lensfun.sourceforge.net/ + */ + +#include +#include + +#include "libavutil/avassert.h" +#include "libavutil/imgutils.h" +#include "libavutil/opt.h" +#include "libswscale/swscale.h" +#include "avfilter.h" +#include "formats.h" +#include "internal.h" +#include "video.h" + +#include + +#define LANCZOS_RESOLUTION 256 + +enum Mode { + VIGNETTING = 0x1, + GEOMETRY_DISTORTION = 0x2, + SUBPIXEL_DISTORTION = 0x4 +}; + +enum InterpolationType { + NEAREST, + LINEAR, + LANCZOS +}; + +typedef struct VignettingThreadData { + int width, height; + uint8_t *data_in; + int linesize_in; + int pixel_composition; + lfModifier *modifier; +} VignettingThreadData; + +typedef struct DistortionCorrectionThreadData { + int width, height; + const float *distortion_coords; + const uint8_t *data_in; + uint8_t *data_out; + int linesize_in, linesize_out; + const float *interpolation; + int mode; + int interpolation_type; +} DistortionCorrectionThreadData; + +typedef struct LensfunContext { + const AVClass *class; + const char *make, *model, *lens_model; + int mode; + float focal_length; + float aperture; + float focus_distance; + float scale; + int target_geometry; + int reverse; + int interpolation_type; + + float *distortion_coords; + float *interpolation; + + lfLens *lens; + lfCamera *camera; + lfModifier *modifier; +} LensfunContext; + +#define OFFSET(x) offsetof(LensfunContext, x) +#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM +static const AVOption lensfun_options[] = { + { "make", "set camera maker", OFFSET(make), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 0, FLAGS }, + { "model", "set camera model", OFFSET(model), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 0, FLAGS }, + { "lens_model", "set lens model", OFFSET(lens_model), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 0, FLAGS }, + { "mode", "set mode", OFFSET(mode), AV_OPT_TYPE_INT, {.i64=GEOMETRY_DISTORTION}, 0, VIGNETTING | GEOMETRY_DISTORTION | SUBPIXEL_DISTORTION, FLAGS, "mode" }, + { "vignetting", "fix lens vignetting", 0, AV_OPT_TYPE_CONST, {.i64=VIGNETTING}, 0, 0, FLAGS, "mode" }, + { "geometry", "correct geometry distortion", 0, AV_OPT_TYPE_CONST, {.i64=GEOMETRY_DISTORTION}, 0, 0, FLAGS, "mode" }, + { "subpixel", "fix chromatic aberrations", 0, AV_OPT_TYPE_CONST, {.i64=SUBPIXEL_DISTORTION}, 0, 0, FLAGS, "mode" }, + { "vig_geo", "fix lens vignetting and correct geometry distortion", 0, AV_OPT_TYPE_CONST, {.i64=VIGNETTING | GEOMETRY_DISTORTION}, 0, 0, FLAGS, "mode" }, + { "vig_subpixel", "fix lens vignetting and chromatic aberrations", 0, AV_OPT_TYPE_CONST, {.i64=VIGNETTING | SUBPIXEL_DISTORTION}, 0, 0, FLAGS, "mode" }, + { "distortion", "correct geometry distortion and chromatic aberrations", 0, AV_OPT_TYPE_CONST, {.i64=GEOMETRY_DISTORTION | SUBPIXEL_DISTORTION}, 0, 0, FLAGS, "mode" }, + { "all", NULL, 0, AV_OPT_TYPE_CONST, {.i64=VIGNETTING | GEOMETRY_DISTORTION | SUBPIXEL_DISTORTION}, 0, 0, FLAGS, "mode" }, + { "focal_length", "focal length of video (zoom; constant for the duration of the use of this filter)", OFFSET(focal_length), AV_OPT_TYPE_FLOAT, {.dbl=18}, 0.0, DBL_MAX, FLAGS }, + { "aperture", "aperture (constant for the duration of the use of this filter)", OFFSET(aperture), AV_OPT_TYPE_FLOAT, {.dbl=3.5}, 0.0, DBL_MAX, FLAGS }, + { "focus_distance", "focus distance (constant for the duration of the use of this filter)", OFFSET(focus_distance), AV_OPT_TYPE_FLOAT, {.dbl=1000.0f}, 0.0, DBL_MAX, FLAGS }, + { "scale", "scale factor applied after corrections (0.0 means automatic scaling)", OFFSET(scale), AV_OPT_TYPE_FLOAT, {.dbl=0.0}, 0.0, DBL_MAX, FLAGS }, + { "target_geometry", "target geometry of the lens correction (only when geometry correction is enabled)", OFFSET(target_geometry), AV_OPT_TYPE_INT, {.i64=LF_RECTILINEAR}, 0, INT_MAX, FLAGS, "lens_geometry" }, + { "rectilinear", "rectilinear lens (default)", 0, AV_OPT_TYPE_CONST, {.i64=LF_RECTILINEAR}, 0, 0, FLAGS, "lens_geometry" }, + { "fisheye", "fisheye lens", 0, AV_OPT_TYPE_CONST, {.i64=LF_FISHEYE}, 0, 0, FLAGS, "lens_geometry" }, + { "panoramic", "panoramic (cylindrical)", 0, AV_OPT_TYPE_CONST, {.i64=LF_PANORAMIC}, 0, 0, FLAGS, "lens_geometry" }, + { "equirectangular", "equirectangular", 0, AV_OPT_TYPE_CONST, {.i64=LF_EQUIRECTANGULAR}, 0, 0, FLAGS, "lens_geometry" }, + { "fisheye_orthographic", "orthographic fisheye", 0, AV_OPT_TYPE_CONST, {.i64=LF_FISHEYE_ORTHOGRAPHIC}, 0, 0, FLAGS, "lens_geometry" }, + { "fisheye_stereographic", "stereographic fisheye", 0, AV_OPT_TYPE_CONST, {.i64=LF_FISHEYE_STEREOGRAPHIC}, 0, 0, FLAGS, "lens_geometry" }, + { "fisheye_equisolid", "equisolid fisheye", 0, AV_OPT_TYPE_CONST, {.i64=LF_FISHEYE_EQUISOLID}, 0, 0, FLAGS, "lens_geometry" }, + { "fisheye_thoby", "fisheye as measured by thoby", 0, AV_OPT_TYPE_CONST, {.i64=LF_FISHEYE_THOBY}, 0, 0, FLAGS, "lens_geometry" }, + { "reverse", "Does reverse correction (regular image to lens distorted)", OFFSET(reverse), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS }, + { "interpolation", "Type of interpolation", OFFSET(interpolation_type), AV_OPT_TYPE_INT, {.i64=LINEAR}, 0, LANCZOS, FLAGS, "interpolation" }, + { "nearest", NULL, 0, AV_OPT_TYPE_CONST, {.i64=NEAREST}, 0, 0, FLAGS, "interpolation" }, + { "linear", NULL, 0, AV_OPT_TYPE_CONST, {.i64=LINEAR}, 0, 0, FLAGS, "interpolation" }, + { "lanczos", NULL, 0, AV_OPT_TYPE_CONST, {.i64=LANCZOS}, 0, 0, FLAGS, "interpolation" }, + { NULL } +}; + +AVFILTER_DEFINE_CLASS(lensfun); + +static av_cold int init(AVFilterContext *ctx) +{ + LensfunContext *lensfun = ctx->priv; + lfDatabase *db; + const lfCamera **cameras; + const lfLens **lenses; + + if (!lensfun->make) { + av_log(ctx, AV_LOG_FATAL, "Option \"make\" not specified\n"); + return AVERROR(EINVAL); + } else if (!lensfun->model) { + av_log(ctx, AV_LOG_FATAL, "Option \"model\" not specified\n"); + return AVERROR(EINVAL); + } else if (!lensfun->lens_model) { + av_log(ctx, AV_LOG_FATAL, "Option \"lens_model\" not specified\n"); + return AVERROR(EINVAL); + } + + lensfun->lens = lf_lens_new(); + lensfun->camera = lf_camera_new(); + + db = lf_db_new(); + if (lf_db_load(db) != LF_NO_ERROR) { + lf_db_destroy(db); + av_log(ctx, AV_LOG_FATAL, "Failed to load lensfun database\n"); + return AVERROR_INVALIDDATA; + } + + cameras = lf_db_find_cameras(db, lensfun->make, lensfun->model); + if (cameras && *cameras) { + lf_camera_copy(lensfun->camera, *cameras); + av_log(ctx, AV_LOG_INFO, "Using camera %s\n", lensfun->camera->Model); + } else { + lf_free(cameras); + lf_db_destroy(db); + av_log(ctx, AV_LOG_FATAL, "Failed to find camera in lensfun database\n"); + return AVERROR_INVALIDDATA; + } + lf_free(cameras); + + lenses = lf_db_find_lenses_hd(db, lensfun->camera, NULL, lensfun->lens_model, 0); + if (lenses && *lenses) { + lf_lens_copy(lensfun->lens, *lenses); + av_log(ctx, AV_LOG_INFO, "Using lens %s\n", lensfun->lens->Model); + } else { + lf_free(lenses); + lf_db_destroy(db); + av_log(ctx, AV_LOG_FATAL, "Failed to find lens in lensfun database\n"); + return AVERROR_INVALIDDATA; + } + lf_free(lenses); + + lf_db_destroy(db); + return 0; +} + +static int query_formats(AVFilterContext *ctx) +{ + // Some of the functions provided by lensfun require pixels in RGB format + static const enum AVPixelFormat fmts[] = {AV_PIX_FMT_RGB24, AV_PIX_FMT_NONE}; + AVFilterFormats *fmts_list = ff_make_format_list(fmts); + return ff_set_common_formats(ctx, fmts_list); +} + +static float lanczos_kernel(float x) +{ + if (x == 0.0f) { + return 1.0f; + } else if (x > -2.0f && x < 2.0f) { + return (2.0f * sin(M_PI * x) * sin(M_PI / 2.0f * x)) / (M_PI * M_PI * x * x); + } else { + return 0.0f; + } +} + +static int config_props(AVFilterLink *inlink) +{ + AVFilterContext *ctx = inlink->dst; + LensfunContext *lensfun = ctx->priv; + int index; + float a; + int lensfun_mode = 0; + + if (!lensfun->modifier) { + if (lensfun->camera && lensfun->lens) { + lensfun->modifier = lf_modifier_new(lensfun->lens, + lensfun->camera->CropFactor, + inlink->w, + inlink->h); + if (lensfun->mode & VIGNETTING) + lensfun_mode |= LF_MODIFY_VIGNETTING; + if (lensfun->mode & GEOMETRY_DISTORTION) + lensfun_mode |= LF_MODIFY_DISTORTION | LF_MODIFY_GEOMETRY | LF_MODIFY_SCALE; + if (lensfun->mode & SUBPIXEL_DISTORTION) + lensfun_mode |= LF_MODIFY_TCA; + lf_modifier_initialize(lensfun->modifier, + lensfun->lens, + LF_PF_U8, + lensfun->focal_length, + lensfun->aperture, + lensfun->focus_distance, + lensfun->scale, + lensfun->target_geometry, + lensfun_mode, + lensfun->reverse); + } else { + // lensfun->camera and lensfun->lens should have been initialized + return AVERROR_BUG; + } + } + + if (!lensfun->distortion_coords) { + if (lensfun->mode & SUBPIXEL_DISTORTION) { + lensfun->distortion_coords = av_malloc_array(inlink->w * inlink->h, sizeof(float) * 2 * 3); + if (!lensfun->distortion_coords) + return AVERROR(ENOMEM); + if (lensfun->mode & GEOMETRY_DISTORTION) { + // apply both geometry and subpixel distortion + lf_modifier_apply_subpixel_geometry_distortion(lensfun->modifier, + 0, 0, + inlink->w, inlink->h, + lensfun->distortion_coords); + } else { + // apply only subpixel distortion + lf_modifier_apply_subpixel_distortion(lensfun->modifier, + 0, 0, + inlink->w, inlink->h, + lensfun->distortion_coords); + } + } else if (lensfun->mode & GEOMETRY_DISTORTION) { + lensfun->distortion_coords = av_malloc_array(inlink->w * inlink->h, sizeof(float) * 2); + if (!lensfun->distortion_coords) + return AVERROR(ENOMEM); + // apply only geometry distortion + lf_modifier_apply_geometry_distortion(lensfun->modifier, + 0, 0, + inlink->w, inlink->h, + lensfun->distortion_coords); + } + } + + if (!lensfun->interpolation) + if (lensfun->interpolation_type == LANCZOS) { + lensfun->interpolation = av_malloc_array(LANCZOS_RESOLUTION, sizeof(float) * 4); + if (!lensfun->interpolation) + return AVERROR(ENOMEM); + for (index = 0; index < 4 * LANCZOS_RESOLUTION; ++index) { + if (index == 0) { + lensfun->interpolation[index] = 1.0f; + } else { + a = sqrtf((float)index / LANCZOS_RESOLUTION); + lensfun->interpolation[index] = lanczos_kernel(a); + } + } + } + + return 0; +} + +static int vignetting_filter_slice(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) +{ + const VignettingThreadData *thread_data = arg; + const int slice_start = thread_data->height * jobnr / nb_jobs; + const int slice_end = thread_data->height * (jobnr + 1) / nb_jobs; + + lf_modifier_apply_color_modification(thread_data->modifier, + thread_data->data_in + slice_start * thread_data->linesize_in, + 0, + slice_start, + thread_data->width, + slice_end - slice_start, + thread_data->pixel_composition, + thread_data->linesize_in); + + return 0; +} + +static float square(float x) +{ + return x * x; +} + +static int distortion_correction_filter_slice(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) +{ + const DistortionCorrectionThreadData *thread_data = arg; + const int slice_start = thread_data->height * jobnr / nb_jobs; + const int slice_end = thread_data->height * (jobnr + 1) / nb_jobs; + + int x, y, i, j, rgb_index; + float interpolated, new_x, new_y, d, norm; + int new_x_int, new_y_int; + for (y = slice_start; y < slice_end; ++y) + for (x = 0; x < thread_data->width; ++x) + for (rgb_index = 0; rgb_index < 3; ++rgb_index) { + if (thread_data->mode & SUBPIXEL_DISTORTION) { + // subpixel (and possibly geometry) distortion correction was applied, correct distortion + switch(thread_data->interpolation_type) { + case NEAREST: + new_x_int = thread_data->distortion_coords[x * 2 * 3 + y * thread_data->width * 2 * 3 + rgb_index * 2] + 0.5f; + new_y_int = thread_data->distortion_coords[x * 2 * 3 + y * thread_data->width * 2 * 3 + rgb_index * 2 + 1] + 0.5f; + if (new_x_int < 0 || new_x_int >= thread_data->width || new_y_int < 0 || new_y_int >= thread_data->height) { + thread_data->data_out[x * 3 + rgb_index + y * thread_data->linesize_out] = 0; + } else { + thread_data->data_out[x * 3 + rgb_index + y * thread_data->linesize_out] = thread_data->data_in[new_x_int * 3 + rgb_index + new_y_int * thread_data->linesize_in]; + } + break; + case LINEAR: + interpolated = 0.0f; + new_x = thread_data->distortion_coords[x * 2 * 3 + y * thread_data->width * 2 * 3 + rgb_index * 2]; + new_x_int = new_x; + new_y = thread_data->distortion_coords[x * 2 * 3 + y * thread_data->width * 2 * 3 + rgb_index * 2 + 1]; + new_y_int = new_y; + if (new_x_int < 0 || new_x_int + 1 >= thread_data->width || new_y_int < 0 || new_y_int + 1 >= thread_data->height) { + thread_data->data_out[x * 3 + rgb_index + y * thread_data->linesize_out] = 0; + } else { + thread_data->data_out[x * 3 + rgb_index + y * thread_data->linesize_out] = + thread_data->data_in[ new_x_int * 3 + rgb_index + new_y_int * thread_data->linesize_in] * (new_x_int + 1 - new_x) * (new_y_int + 1 - new_y) + + thread_data->data_in[(new_x_int + 1) * 3 + rgb_index + new_y_int * thread_data->linesize_in] * (new_x - new_x_int) * (new_y_int + 1 - new_y) + + thread_data->data_in[ new_x_int * 3 + rgb_index + (new_y_int + 1) * thread_data->linesize_in] * (new_x_int + 1 - new_x) * (new_y - new_y_int) + + thread_data->data_in[(new_x_int + 1) * 3 + rgb_index + (new_y_int + 1) * thread_data->linesize_in] * (new_x - new_x_int) * (new_y - new_y_int); + } + break; + case LANCZOS: + interpolated = 0.0f; + norm = 0.0f; + new_x = thread_data->distortion_coords[x * 2 * 3 + y * thread_data->width * 2 * 3 + rgb_index * 2]; + new_x_int = new_x; + new_y = thread_data->distortion_coords[x * 2 * 3 + y * thread_data->width * 2 * 3 + rgb_index * 2 + 1]; + new_y_int = new_y; + for (j = 0; j < 4; ++j) + for (i = 0; i < 4; ++i) { + if (new_x_int + i - 2 < 0 || new_x_int + i - 2 >= thread_data->width || new_y_int + j - 2 < 0 || new_y_int + j - 2 >= thread_data->height) + continue; + d = square(new_x - (new_x_int + i - 2)) * square(new_y - (new_y_int + j - 2)); + if (d >= 4.0f) + continue; + d = thread_data->interpolation[(int)(d * LANCZOS_RESOLUTION)]; + norm += d; + interpolated += thread_data->data_in[(new_x_int + i - 2) * 3 + rgb_index + (new_y_int + j - 2) * thread_data->linesize_in] * d; + } + if (norm == 0.0f) { + thread_data->data_out[x * 3 + rgb_index + y * thread_data->linesize_out] = 0; + } else { + interpolated /= norm; + thread_data->data_out[x * 3 + rgb_index + y * thread_data->linesize_out] = interpolated < 0.0f ? 0.0f : interpolated > 255.0f ? 255.0f : interpolated; + } + break; + } + } else if (thread_data->mode & GEOMETRY_DISTORTION) { + // geometry distortion correction was applied, correct distortion + switch(thread_data->interpolation_type) { + case NEAREST: + new_x_int = thread_data->distortion_coords[x * 2 + y * thread_data->width * 2] + 0.5f; + new_y_int = thread_data->distortion_coords[x * 2 + y * thread_data->width * 2 + 1] + 0.5f; + if (new_x_int < 0 || new_x_int >= thread_data->width || new_y_int < 0 || new_y_int >= thread_data->height) { + thread_data->data_out[x * 3 + rgb_index + y * thread_data->linesize_out] = 0; + } else { + thread_data->data_out[x * 3 + rgb_index + y * thread_data->linesize_out] = thread_data->data_in[new_x_int * 3 + rgb_index + new_y_int * thread_data->linesize_in]; + } + break; + case LINEAR: + interpolated = 0.0f; + new_x = thread_data->distortion_coords[x * 2 + y * thread_data->width * 2]; + new_x_int = new_x; + new_y = thread_data->distortion_coords[x * 2 + y * thread_data->width * 2 + 1]; + new_y_int = new_y; + if (new_x_int < 0 || new_x_int + 1 >= thread_data->width || new_y_int < 0 || new_y_int + 1 >= thread_data->height) { + thread_data->data_out[x * 3 + rgb_index + y * thread_data->linesize_out] = 0; + } else { + thread_data->data_out[x * 3 + rgb_index + y * thread_data->linesize_out] = + thread_data->data_in[ new_x_int * 3 + rgb_index + new_y_int * thread_data->linesize_in] * (new_x_int + 1 - new_x) * (new_y_int + 1 - new_y) + + thread_data->data_in[(new_x_int + 1) * 3 + rgb_index + new_y_int * thread_data->linesize_in] * (new_x - new_x_int) * (new_y_int + 1 - new_y) + + thread_data->data_in[ new_x_int * 3 + rgb_index + (new_y_int + 1) * thread_data->linesize_in] * (new_x_int + 1 - new_x) * (new_y - new_y_int) + + thread_data->data_in[(new_x_int + 1) * 3 + rgb_index + (new_y_int + 1) * thread_data->linesize_in] * (new_x - new_x_int) * (new_y - new_y_int); + } + break; + case LANCZOS: + interpolated = 0.0f; + norm = 0.0f; + new_x = thread_data->distortion_coords[x * 2 + y * thread_data->width * 2]; + new_x_int = new_x; + new_y = thread_data->distortion_coords[x * 2 + 1 + y * thread_data->width * 2]; + new_y_int = new_y; + for (j = 0; j < 4; ++j) + for (i = 0; i < 4; ++i) { + if (new_x_int + i - 2 < 0 || new_x_int + i - 2 >= thread_data->width || new_y_int + j - 2 < 0 || new_y_int + j - 2 >= thread_data->height) + continue; + d = square(new_x - (new_x_int + i - 2)) * square(new_y - (new_y_int + j - 2)); + if (d >= 4.0f) + continue; + d = thread_data->interpolation[(int)(d * LANCZOS_RESOLUTION)]; + norm += d; + interpolated += thread_data->data_in[(new_x_int + i - 2) * 3 + rgb_index + (new_y_int + j - 2) * thread_data->linesize_in] * d; + } + if (norm == 0.0f) { + thread_data->data_out[x * 3 + rgb_index + y * thread_data->linesize_out] = 0; + } else { + interpolated /= norm; + thread_data->data_out[x * 3 + rgb_index + y * thread_data->linesize_out] = interpolated < 0.0f ? 0.0f : interpolated > 255.0f ? 255.0f : interpolated; + } + break; + } + } else { + // no distortion correction was applied + thread_data->data_out[x * 3 + rgb_index + y * thread_data->linesize_out] = thread_data->data_in[x * 3 + rgb_index + y * thread_data->linesize_in]; + } + } + + return 0; +} + +static int filter_frame(AVFilterLink *inlink, AVFrame *in) +{ + AVFilterContext *ctx = inlink->dst; + LensfunContext *lensfun = ctx->priv; + AVFilterLink *outlink = ctx->outputs[0]; + AVFrame *out; + VignettingThreadData vignetting_thread_data; + DistortionCorrectionThreadData distortion_correction_thread_data; + + if (lensfun->mode & VIGNETTING) { + av_frame_make_writable(in); + + vignetting_thread_data = (VignettingThreadData) { + .width = inlink->w, + .height = inlink->h, + .data_in = in->data[0], + .linesize_in = in->linesize[0], + .pixel_composition = LF_CR_3(RED, GREEN, BLUE), + .modifier = lensfun->modifier + }; + + ctx->internal->execute(ctx, + vignetting_filter_slice, + &vignetting_thread_data, + NULL, + FFMIN(outlink->h, ff_filter_get_nb_threads(ctx))); + } + + if (lensfun->mode & (GEOMETRY_DISTORTION | SUBPIXEL_DISTORTION)) { + out = ff_get_video_buffer(outlink, outlink->w, outlink->h); + if (!out) { + av_frame_free(&in); + return AVERROR(ENOMEM); + } + av_frame_copy_props(out, in); + + distortion_correction_thread_data = (DistortionCorrectionThreadData) { + .width = inlink->w, + .height = inlink->h, + .distortion_coords = lensfun->distortion_coords, + .data_in = in->data[0], + .data_out = out->data[0], + .linesize_in = in->linesize[0], + .linesize_out = out->linesize[0], + .interpolation = lensfun->interpolation, + .mode = lensfun->mode, + .interpolation_type = lensfun->interpolation_type + }; + + ctx->internal->execute(ctx, + distortion_correction_filter_slice, + &distortion_correction_thread_data, + NULL, + FFMIN(outlink->h, ff_filter_get_nb_threads(ctx))); + + av_frame_free(&in); + return ff_filter_frame(outlink, out); + } else { + return ff_filter_frame(outlink, in); + } +} + +static av_cold void uninit(AVFilterContext *ctx) +{ + LensfunContext *lensfun = ctx->priv; + + if (lensfun->camera) + lf_camera_destroy(lensfun->camera); + if (lensfun->lens) + lf_lens_destroy(lensfun->lens); + if (lensfun->modifier) + lf_modifier_destroy(lensfun->modifier); + av_freep(&lensfun->distortion_coords); + av_freep(&lensfun->interpolation); +} + +static const AVFilterPad lensfun_inputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + .config_props = config_props, + .filter_frame = filter_frame, + }, + { NULL } +}; + +static const AVFilterPad lensfun_outputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + }, + { NULL } +}; + +AVFilter ff_vf_lensfun = { + .name = "lensfun", + .description = NULL_IF_CONFIG_SMALL("Apply correction to an image based on info derived from the lensfun database."), + .priv_size = sizeof(LensfunContext), + .init = init, + .uninit = uninit, + .query_formats = query_formats, + .inputs = lensfun_inputs, + .outputs = lensfun_outputs, + .priv_class = &lensfun_class, + .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS, +}; diff --git a/libavfilter/vf_libvmaf.c b/libavfilter/vf_libvmaf.c index 42c6b66b6..249e50c72 100644 --- a/libavfilter/vf_libvmaf.c +++ b/libavfilter/vf_libvmaf.c @@ -43,6 +43,7 @@ typedef struct LIBVMAFContext { int width; int height; double vmaf_score; + int vmaf_thread_created; pthread_t vmaf_thread; pthread_mutex_t lock; pthread_cond_t cond; @@ -61,6 +62,9 @@ typedef struct LIBVMAFContext { int ssim; int ms_ssim; char *pool; + int n_threads; + int n_subsample; + int enable_conf_interval; int error; } LIBVMAFContext; @@ -77,6 +81,9 @@ static const AVOption libvmaf_options[] = { {"ssim", "Enables computing ssim along with vmaf.", OFFSET(ssim), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS}, {"ms_ssim", "Enables computing ms-ssim along with vmaf.", OFFSET(ms_ssim), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS}, {"pool", "Set the pool method to be used for computing vmaf.", OFFSET(pool), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 1, FLAGS}, + {"n_threads", "Set number of threads to be used when computing vmaf.", OFFSET(n_threads), AV_OPT_TYPE_INT, {.i64=0}, 0, UINT_MAX, FLAGS}, + {"n_subsample", "Set interval for frame subsampling used when computing vmaf.", OFFSET(n_subsample), AV_OPT_TYPE_INT, {.i64=1}, 1, UINT_MAX, FLAGS}, + {"enable_conf_interval", "Enables confidence interval.", OFFSET(enable_conf_interval), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS}, { NULL } }; @@ -165,7 +172,8 @@ static void compute_vmaf_score(LIBVMAFContext *s) read_frame, s, s->model_path, s->log_path, s->log_fmt, 0, 0, s->enable_transform, s->phone_model, s->psnr, s->ssim, - s->ms_ssim, s->pool); + s->ms_ssim, s->pool, + s->n_threads, s->n_subsample, s->enable_conf_interval); } static void *call_vmaf(void *ctx) @@ -228,6 +236,7 @@ static av_cold int init(AVFilterContext *ctx) s->gmain = av_frame_alloc(); s->error = 0; + s->vmaf_thread_created = 0; pthread_mutex_init(&s->lock, NULL); pthread_cond_init (&s->cond, NULL); @@ -275,6 +284,7 @@ static int config_input_ref(AVFilterLink *inlink) av_log(ctx, AV_LOG_ERROR, "Thread creation failed.\n"); return AVERROR(EINVAL); } + s->vmaf_thread_created = 1; return 0; } @@ -317,7 +327,11 @@ static av_cold void uninit(AVFilterContext *ctx) pthread_cond_signal(&s->cond); pthread_mutex_unlock(&s->lock); - pthread_join(s->vmaf_thread, NULL); + if (s->vmaf_thread_created) + { + pthread_join(s->vmaf_thread, NULL); + s->vmaf_thread_created = 0; + } av_frame_free(&s->gref); av_frame_free(&s->gmain); diff --git a/libavfilter/vf_limiter.c b/libavfilter/vf_limiter.c index 9c62b1188..6f340069d 100644 --- a/libavfilter/vf_limiter.c +++ b/libavfilter/vf_limiter.c @@ -18,7 +18,6 @@ #include "libavutil/attributes.h" #include "libavutil/common.h" -#include "libavutil/eval.h" #include "libavutil/imgutils.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" @@ -28,6 +27,11 @@ #include "limiter.h" #include "video.h" +typedef struct ThreadData { + AVFrame *in; + AVFrame *out; +} ThreadData; + typedef struct LimiterContext { const AVClass *class; int min; @@ -81,7 +85,7 @@ static int query_formats(AVFilterContext *ctx) AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRP9, AV_PIX_FMT_GBRP10, AV_PIX_FMT_GBRP12, AV_PIX_FMT_GBRP14, AV_PIX_FMT_GBRP16, AV_PIX_FMT_GBRAP, AV_PIX_FMT_GBRAP10, AV_PIX_FMT_GBRAP12, AV_PIX_FMT_GBRAP16, - AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY9, AV_PIX_FMT_GRAY10, AV_PIX_FMT_GRAY12, AV_PIX_FMT_GRAY16, + AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY9, AV_PIX_FMT_GRAY10, AV_PIX_FMT_GRAY12, AV_PIX_FMT_GRAY14, AV_PIX_FMT_GRAY16, AV_PIX_FMT_NONE }; @@ -133,13 +137,14 @@ static int config_props(AVFilterLink *inlink) AVFilterContext *ctx = inlink->dst; LimiterContext *s = ctx->priv; const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format); - int vsub, hsub, ret; + int depth, vsub, hsub, ret; s->nb_planes = av_pix_fmt_count_planes(inlink->format); if ((ret = av_image_fill_linesizes(s->linesize, inlink->format, inlink->w)) < 0) return ret; + depth = desc->comp[0].depth; hsub = desc->log2_chroma_w; vsub = desc->log2_chroma_h; s->height[1] = s->height[2] = AV_CEIL_RSHIFT(inlink->h, vsub); @@ -147,10 +152,11 @@ static int config_props(AVFilterLink *inlink) s->width[1] = s->width[2] = AV_CEIL_RSHIFT(inlink->w, hsub); s->width[0] = s->width[3] = inlink->w; - if (desc->comp[0].depth == 8) { + s->max = FFMIN(s->max, (1 << depth) - 1); + s->min = FFMIN(s->min, (1 << depth) - 1); + + if (depth == 8) { s->dsp.limiter = limiter8; - s->max = FFMIN(s->max, 255); - s->min = FFMIN(s->min, 255); } else { s->dsp.limiter = limiter16; } @@ -161,13 +167,46 @@ static int config_props(AVFilterLink *inlink) return 0; } +static int filter_slice(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) +{ + LimiterContext *s = ctx->priv; + ThreadData *td = arg; + AVFrame *in = td->in; + AVFrame *out = td->out; + int p; + + for (p = 0; p < s->nb_planes; p++) { + const int h = s->height[p]; + const int slice_start = (h * jobnr) / nb_jobs; + const int slice_end = (h * (jobnr+1)) / nb_jobs; + + if (!((1 << p) & s->planes)) { + if (out != in) + av_image_copy_plane(out->data[p] + slice_start * out->linesize[p], + out->linesize[p], + in->data[p] + slice_start * in->linesize[p], + in->linesize[p], + s->linesize[p], slice_end - slice_start); + continue; + } + + s->dsp.limiter(in->data[p] + slice_start * in->linesize[p], + out->data[p] + slice_start * out->linesize[p], + in->linesize[p], out->linesize[p], + s->width[p], slice_end - slice_start, + s->min, s->max); + } + + return 0; +} + static int filter_frame(AVFilterLink *inlink, AVFrame *in) { AVFilterContext *ctx = inlink->dst; LimiterContext *s = ctx->priv; AVFilterLink *outlink = ctx->outputs[0]; + ThreadData td; AVFrame *out; - int p; if (av_frame_is_writable(in)) { out = in; @@ -180,20 +219,10 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) av_frame_copy_props(out, in); } - for (p = 0; p < s->nb_planes; p++) { - if (!((1 << p) & s->planes)) { - if (out != in) - av_image_copy_plane(out->data[p], out->linesize[p], in->data[p], in->linesize[p], - s->linesize[p], s->height[p]); - continue; - } - - s->dsp.limiter(in->data[p], out->data[p], - in->linesize[p], out->linesize[p], - s->width[p], s->height[p], - s->min, s->max); - } - + td.out = out; + td.in = in; + ctx->internal->execute(ctx, filter_slice, &td, NULL, + FFMIN(s->height[2], ff_filter_get_nb_threads(ctx))); if (out != in) av_frame_free(&in); @@ -227,5 +256,5 @@ AVFilter ff_vf_limiter = { .query_formats = query_formats, .inputs = inputs, .outputs = outputs, - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC, + .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS, }; diff --git a/libavfilter/vf_lut.c b/libavfilter/vf_lut.c index 26f2945c8..1fdc5e181 100644 --- a/libavfilter/vf_lut.c +++ b/libavfilter/vf_lut.c @@ -137,7 +137,7 @@ static av_cold void uninit(AVFilterContext *ctx) #define GRAY_FORMATS \ AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY9LE, AV_PIX_FMT_GRAY10LE, \ - AV_PIX_FMT_GRAY12LE, AV_PIX_FMT_GRAY16LE + AV_PIX_FMT_GRAY12LE, AV_PIX_FMT_GRAY14LE, AV_PIX_FMT_GRAY16LE static const enum AVPixelFormat yuv_pix_fmts[] = { YUV_FORMATS, AV_PIX_FMT_NONE }; static const enum AVPixelFormat rgb_pix_fmts[] = { RGB_FORMATS, AV_PIX_FMT_NONE }; @@ -337,13 +337,194 @@ static int config_props(AVFilterLink *inlink) return 0; } +struct thread_data { + AVFrame *in; + AVFrame *out; + + int w; + int h; +}; + +#define LOAD_PACKED_COMMON\ + LutContext *s = ctx->priv;\ + const struct thread_data *td = arg;\ +\ + int i, j;\ + const int w = td->w;\ + const int h = td->h;\ + AVFrame *in = td->in;\ + AVFrame *out = td->out;\ + const uint16_t (*tab)[256*256] = (const uint16_t (*)[256*256])s->lut;\ + const int step = s->step;\ +\ + const int slice_start = (h * jobnr ) / nb_jobs;\ + const int slice_end = (h * (jobnr+1)) / nb_jobs;\ + +/* packed, 16-bit */ +static int lut_packed_16bits(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) +{ + LOAD_PACKED_COMMON + + uint16_t *inrow, *outrow, *inrow0, *outrow0; + const int in_linesize = in->linesize[0] / 2; + const int out_linesize = out->linesize[0] / 2; + inrow0 = (uint16_t *)in ->data[0]; + outrow0 = (uint16_t *)out->data[0]; + + for (i = slice_start; i < slice_end; i++) { + inrow = inrow0 + i * in_linesize; + outrow = outrow0 + i * out_linesize; + for (j = 0; j < w; j++) { + + switch (step) { +#if HAVE_BIGENDIAN + case 4: outrow[3] = av_bswap16(tab[3][av_bswap16(inrow[3])]); // Fall-through + case 3: outrow[2] = av_bswap16(tab[2][av_bswap16(inrow[2])]); // Fall-through + case 2: outrow[1] = av_bswap16(tab[1][av_bswap16(inrow[1])]); // Fall-through + default: outrow[0] = av_bswap16(tab[0][av_bswap16(inrow[0])]); +#else + case 4: outrow[3] = tab[3][inrow[3]]; // Fall-through + case 3: outrow[2] = tab[2][inrow[2]]; // Fall-through + case 2: outrow[1] = tab[1][inrow[1]]; // Fall-through + default: outrow[0] = tab[0][inrow[0]]; +#endif + } + outrow += step; + inrow += step; + } + } + + return 0; +} + +/* packed, 8-bit */ +static int lut_packed_8bits(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) +{ + LOAD_PACKED_COMMON + + uint8_t *inrow, *outrow, *inrow0, *outrow0; + const int in_linesize = in->linesize[0]; + const int out_linesize = out->linesize[0]; + inrow0 = in ->data[0]; + outrow0 = out->data[0]; + + for (i = slice_start; i < slice_end; i++) { + inrow = inrow0 + i * in_linesize; + outrow = outrow0 + i * out_linesize; + for (j = 0; j < w; j++) { + switch (step) { + case 4: outrow[3] = tab[3][inrow[3]]; // Fall-through + case 3: outrow[2] = tab[2][inrow[2]]; // Fall-through + case 2: outrow[1] = tab[1][inrow[1]]; // Fall-through + default: outrow[0] = tab[0][inrow[0]]; + } + outrow += step; + inrow += step; + } + } + + return 0; +} + +#define LOAD_PLANAR_COMMON\ + LutContext *s = ctx->priv;\ + const struct thread_data *td = arg;\ + int i, j, plane;\ + AVFrame *in = td->in;\ + AVFrame *out = td->out;\ + +#define PLANAR_COMMON\ + int vsub = plane == 1 || plane == 2 ? s->vsub : 0;\ + int hsub = plane == 1 || plane == 2 ? s->hsub : 0;\ + int h = AV_CEIL_RSHIFT(td->h, vsub);\ + int w = AV_CEIL_RSHIFT(td->w, hsub);\ + const uint16_t *tab = s->lut[plane];\ +\ + const int slice_start = (h * jobnr ) / nb_jobs;\ + const int slice_end = (h * (jobnr+1)) / nb_jobs;\ + +/* planar >8 bit depth */ +static int lut_planar_16bits(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) +{ + LOAD_PLANAR_COMMON + + uint16_t *inrow, *outrow; + + for (plane = 0; plane < 4 && in->data[plane] && in->linesize[plane]; plane++) { + PLANAR_COMMON + + const int in_linesize = in->linesize[plane] / 2; + const int out_linesize = out->linesize[plane] / 2; + + inrow = (uint16_t *)in ->data[plane] + slice_start * in_linesize; + outrow = (uint16_t *)out->data[plane] + slice_start * out_linesize; + + for (i = slice_start; i < slice_end; i++) { + for (j = 0; j < w; j++) { +#if HAVE_BIGENDIAN + outrow[j] = av_bswap16(tab[av_bswap16(inrow[j])]); +#else + outrow[j] = tab[inrow[j]]; +#endif + } + inrow += in_linesize; + outrow += out_linesize; + } + } + + return 0; +} + +/* planar 8bit depth */ +static int lut_planar_8bits(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) +{ + LOAD_PLANAR_COMMON + + uint8_t *inrow, *outrow; + + for (plane = 0; plane < 4 && in->data[plane] && in->linesize[plane]; plane++) { + PLANAR_COMMON + + const int in_linesize = in->linesize[plane]; + const int out_linesize = out->linesize[plane]; + + inrow = in ->data[plane] + slice_start * in_linesize; + outrow = out->data[plane] + slice_start * out_linesize; + + for (i = slice_start; i < slice_end; i++) { + for (j = 0; j < w; j++) + outrow[j] = tab[inrow[j]]; + inrow += in_linesize; + outrow += out_linesize; + } + } + + return 0; +} + +#define PACKED_THREAD_DATA\ + struct thread_data td = {\ + .in = in,\ + .out = out,\ + .w = inlink->w,\ + .h = in->height,\ + };\ + +#define PLANAR_THREAD_DATA\ + struct thread_data td = {\ + .in = in,\ + .out = out,\ + .w = inlink->w,\ + .h = inlink->h,\ + };\ + static int filter_frame(AVFilterLink *inlink, AVFrame *in) { AVFilterContext *ctx = inlink->dst; LutContext *s = ctx->priv; AVFilterLink *outlink = ctx->outputs[0]; AVFrame *out; - int i, j, plane, direct = 0; + int direct = 0; if (av_frame_is_writable(in)) { direct = 1; @@ -359,121 +540,24 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) if (s->is_rgb && s->is_16bit && !s->is_planar) { /* packed, 16-bit */ - uint16_t *inrow, *outrow, *inrow0, *outrow0; - const int w = inlink->w; - const int h = in->height; - const uint16_t (*tab)[256*256] = (const uint16_t (*)[256*256])s->lut; - const int in_linesize = in->linesize[0] / 2; - const int out_linesize = out->linesize[0] / 2; - const int step = s->step; - - inrow0 = (uint16_t*) in ->data[0]; - outrow0 = (uint16_t*) out->data[0]; - - for (i = 0; i < h; i ++) { - inrow = inrow0; - outrow = outrow0; - for (j = 0; j < w; j++) { - - switch (step) { -#if HAVE_BIGENDIAN - case 4: outrow[3] = av_bswap16(tab[3][av_bswap16(inrow[3])]); // Fall-through - case 3: outrow[2] = av_bswap16(tab[2][av_bswap16(inrow[2])]); // Fall-through - case 2: outrow[1] = av_bswap16(tab[1][av_bswap16(inrow[1])]); // Fall-through - default: outrow[0] = av_bswap16(tab[0][av_bswap16(inrow[0])]); -#else - case 4: outrow[3] = tab[3][inrow[3]]; // Fall-through - case 3: outrow[2] = tab[2][inrow[2]]; // Fall-through - case 2: outrow[1] = tab[1][inrow[1]]; // Fall-through - default: outrow[0] = tab[0][inrow[0]]; -#endif - } - outrow += step; - inrow += step; - } - inrow0 += in_linesize; - outrow0 += out_linesize; - } + PACKED_THREAD_DATA + ctx->internal->execute(ctx, lut_packed_16bits, &td, NULL, + FFMIN(in->height, ff_filter_get_nb_threads(ctx))); } else if (s->is_rgb && !s->is_planar) { - /* packed */ - uint8_t *inrow, *outrow, *inrow0, *outrow0; - const int w = inlink->w; - const int h = in->height; - const uint16_t (*tab)[256*256] = (const uint16_t (*)[256*256])s->lut; - const int in_linesize = in->linesize[0]; - const int out_linesize = out->linesize[0]; - const int step = s->step; - - inrow0 = in ->data[0]; - outrow0 = out->data[0]; - - for (i = 0; i < h; i ++) { - inrow = inrow0; - outrow = outrow0; - for (j = 0; j < w; j++) { - switch (step) { - case 4: outrow[3] = tab[3][inrow[3]]; // Fall-through - case 3: outrow[2] = tab[2][inrow[2]]; // Fall-through - case 2: outrow[1] = tab[1][inrow[1]]; // Fall-through - default: outrow[0] = tab[0][inrow[0]]; - } - outrow += step; - inrow += step; - } - inrow0 += in_linesize; - outrow0 += out_linesize; - } + /* packed 8 bits */ + PACKED_THREAD_DATA + ctx->internal->execute(ctx, lut_packed_8bits, &td, NULL, + FFMIN(in->height, ff_filter_get_nb_threads(ctx))); } else if (s->is_16bit) { - // planar >8 bit depth - uint16_t *inrow, *outrow; - - for (plane = 0; plane < 4 && in->data[plane] && in->linesize[plane]; plane++) { - int vsub = plane == 1 || plane == 2 ? s->vsub : 0; - int hsub = plane == 1 || plane == 2 ? s->hsub : 0; - int h = AV_CEIL_RSHIFT(inlink->h, vsub); - int w = AV_CEIL_RSHIFT(inlink->w, hsub); - const uint16_t *tab = s->lut[plane]; - const int in_linesize = in->linesize[plane] / 2; - const int out_linesize = out->linesize[plane] / 2; - - inrow = (uint16_t *)in ->data[plane]; - outrow = (uint16_t *)out->data[plane]; - - for (i = 0; i < h; i++) { - for (j = 0; j < w; j++) { -#if HAVE_BIGENDIAN - outrow[j] = av_bswap16(tab[av_bswap16(inrow[j])]); -#else - outrow[j] = tab[inrow[j]]; -#endif - } - inrow += in_linesize; - outrow += out_linesize; - } - } + /* planar >8 bit depth */ + PLANAR_THREAD_DATA + ctx->internal->execute(ctx, lut_planar_16bits, &td, NULL, + FFMIN(in->height, ff_filter_get_nb_threads(ctx))); } else { /* planar 8bit depth */ - uint8_t *inrow, *outrow; - - for (plane = 0; plane < 4 && in->data[plane] && in->linesize[plane]; plane++) { - int vsub = plane == 1 || plane == 2 ? s->vsub : 0; - int hsub = plane == 1 || plane == 2 ? s->hsub : 0; - int h = AV_CEIL_RSHIFT(inlink->h, vsub); - int w = AV_CEIL_RSHIFT(inlink->w, hsub); - const uint16_t *tab = s->lut[plane]; - const int in_linesize = in->linesize[plane]; - const int out_linesize = out->linesize[plane]; - - inrow = in ->data[plane]; - outrow = out->data[plane]; - - for (i = 0; i < h; i++) { - for (j = 0; j < w; j++) - outrow[j] = tab[inrow[j]]; - inrow += in_linesize; - outrow += out_linesize; - } - } + PLANAR_THREAD_DATA + ctx->internal->execute(ctx, lut_planar_8bits, &td, NULL, + FFMIN(in->height, ff_filter_get_nb_threads(ctx))); } if (!direct) @@ -508,7 +592,7 @@ static const AVFilterPad outputs[] = { .query_formats = query_formats, \ .inputs = inputs, \ .outputs = outputs, \ - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC, \ + .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS, \ } #if CONFIG_LUT_FILTER diff --git a/libavfilter/vf_lut2.c b/libavfilter/vf_lut2.c index 1385cba9b..721de7d21 100644 --- a/libavfilter/vf_lut2.c +++ b/libavfilter/vf_lut2.c @@ -54,21 +54,29 @@ typedef struct LUT2Context { const AVClass *class; FFFrameSync fs; + int odepth; char *comp_expr_str[4]; AVExpr *comp_expr[4]; double var_values[VAR_VARS_NB]; uint16_t *lut[4]; ///< lookup table for each component int width[4], height[4]; + int widthx[4], heightx[4]; + int widthy[4], heighty[4]; + int nb_planesx; + int nb_planesy; int nb_planes; int depth, depthx, depthy; int tlut2; AVFrame *prev_frame; /* only used with tlut2 */ - void (*lut2)(struct LUT2Context *s, AVFrame *dst, AVFrame *srcx, AVFrame *srcy); - + int (*lut2)(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs); } LUT2Context; +typedef struct ThreadData { + AVFrame *out, *srcx, *srcy; +} ThreadData; + #define OFFSET(x) offsetof(LUT2Context, x) #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM @@ -77,6 +85,7 @@ static const AVOption options[] = { { "c1", "set component #1 expression", OFFSET(comp_expr_str[1]), AV_OPT_TYPE_STRING, { .str = "x" }, .flags = FLAGS }, { "c2", "set component #2 expression", OFFSET(comp_expr_str[2]), AV_OPT_TYPE_STRING, { .str = "x" }, .flags = FLAGS }, { "c3", "set component #3 expression", OFFSET(comp_expr_str[3]), AV_OPT_TYPE_STRING, { .str = "x" }, .flags = FLAGS }, + { "d", "set output depth", OFFSET(odepth), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 16, .flags = FLAGS }, { NULL } }; @@ -96,27 +105,93 @@ static av_cold void uninit(AVFilterContext *ctx) } } +#define BIT8_FMTS \ + AV_PIX_FMT_YUVA444P, AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUV440P, \ + AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_YUVJ440P, \ + AV_PIX_FMT_YUVA422P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUVA420P, AV_PIX_FMT_YUV420P, \ + AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUVJ420P, \ + AV_PIX_FMT_YUVJ411P, AV_PIX_FMT_YUV411P, AV_PIX_FMT_YUV410P, \ + AV_PIX_FMT_GRAY8, AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRAP, + +#define BIT9_FMTS \ + AV_PIX_FMT_GBRP9, AV_PIX_FMT_GRAY9, \ + AV_PIX_FMT_YUV420P9, AV_PIX_FMT_YUV422P9, AV_PIX_FMT_YUV444P9, \ + AV_PIX_FMT_YUVA420P9, AV_PIX_FMT_YUVA422P9, AV_PIX_FMT_YUVA444P9, + +#define BIT10_FMTS \ + AV_PIX_FMT_GRAY10, AV_PIX_FMT_GBRP10, AV_PIX_FMT_GBRAP10, \ + AV_PIX_FMT_YUV420P10, AV_PIX_FMT_YUV422P10, AV_PIX_FMT_YUV444P10, \ + AV_PIX_FMT_YUVA420P10, AV_PIX_FMT_YUVA422P10, AV_PIX_FMT_YUVA444P10, + +#define BIT12_FMTS \ + AV_PIX_FMT_YUV420P12, AV_PIX_FMT_YUV422P12, AV_PIX_FMT_YUV444P12, AV_PIX_FMT_YUV440P12, \ + AV_PIX_FMT_GRAY12, AV_PIX_FMT_GBRAP12, AV_PIX_FMT_GBRP12, + +#define BIT14_FMTS \ + AV_PIX_FMT_YUV420P14, AV_PIX_FMT_YUV422P14, AV_PIX_FMT_YUV444P14, \ + AV_PIX_FMT_GRAY12, AV_PIX_FMT_GBRP14, + +#define BIT16_FMTS \ + AV_PIX_FMT_YUV420P16, AV_PIX_FMT_YUV422P16, AV_PIX_FMT_YUV444P16, \ + AV_PIX_FMT_YUVA420P16, AV_PIX_FMT_YUVA422P16, AV_PIX_FMT_YUVA444P16, \ + AV_PIX_FMT_GBRP16, AV_PIX_FMT_GBRAP16, AV_PIX_FMT_GRAY16, + static int query_formats(AVFilterContext *ctx) { - static const enum AVPixelFormat pix_fmts[] = { - AV_PIX_FMT_YUVA444P, AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUV440P, - AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_YUVJ440P, - AV_PIX_FMT_YUVA422P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUVA420P, AV_PIX_FMT_YUV420P, - AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUVJ420P, - AV_PIX_FMT_YUVJ411P, AV_PIX_FMT_YUV411P, AV_PIX_FMT_YUV410P, - AV_PIX_FMT_YUV420P9, AV_PIX_FMT_YUV422P9, AV_PIX_FMT_YUV444P9, - AV_PIX_FMT_YUV420P10, AV_PIX_FMT_YUV422P10, AV_PIX_FMT_YUV444P10, - AV_PIX_FMT_YUV420P12, AV_PIX_FMT_YUV422P12, AV_PIX_FMT_YUV444P12, AV_PIX_FMT_YUV440P12, - AV_PIX_FMT_YUVA420P9, AV_PIX_FMT_YUVA422P9, AV_PIX_FMT_YUVA444P9, - AV_PIX_FMT_YUVA420P10, AV_PIX_FMT_YUVA422P10, AV_PIX_FMT_YUVA444P10, - AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRP9, AV_PIX_FMT_GBRP10, - AV_PIX_FMT_GBRP12, - AV_PIX_FMT_GBRAP, AV_PIX_FMT_GBRAP10, AV_PIX_FMT_GBRAP12, - AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY9, AV_PIX_FMT_GRAY10, AV_PIX_FMT_GRAY12, + LUT2Context *s = ctx->priv; + static const enum AVPixelFormat all_pix_fmts[] = { + BIT8_FMTS + BIT9_FMTS + BIT10_FMTS + BIT12_FMTS AV_PIX_FMT_NONE }; + static const enum AVPixelFormat bit8_pix_fmts[] = { + BIT8_FMTS + AV_PIX_FMT_NONE + }; + static const enum AVPixelFormat bit9_pix_fmts[] = { + BIT9_FMTS + AV_PIX_FMT_NONE + }; + static const enum AVPixelFormat bit10_pix_fmts[] = { + BIT10_FMTS + AV_PIX_FMT_NONE + }; + static const enum AVPixelFormat bit12_pix_fmts[] = { + BIT12_FMTS + AV_PIX_FMT_NONE + }; + static const enum AVPixelFormat bit14_pix_fmts[] = { + BIT14_FMTS + AV_PIX_FMT_NONE + }; + static const enum AVPixelFormat bit16_pix_fmts[] = { + BIT16_FMTS + AV_PIX_FMT_NONE + }; + const enum AVPixelFormat *pix_fmts; + int ret; - return ff_set_common_formats(ctx, ff_make_format_list(pix_fmts)); + if (s->tlut2 || !s->odepth) + return ff_set_common_formats(ctx, ff_make_format_list(all_pix_fmts)); + + ret = ff_formats_ref(ff_make_format_list(all_pix_fmts), &ctx->inputs[0]->out_formats); + if (ret < 0) + return ret; + + switch (s->odepth) { + case 8: pix_fmts = bit8_pix_fmts; break; + case 9: pix_fmts = bit9_pix_fmts; break; + case 10: pix_fmts = bit10_pix_fmts; break; + case 12: pix_fmts = bit12_pix_fmts; break; + case 14: pix_fmts = bit14_pix_fmts; break; + case 16: pix_fmts = bit16_pix_fmts; break; + default: av_log(ctx, AV_LOG_ERROR, "Unsupported output bit depth %d.\n", s->odepth); + return AVERROR(EINVAL); + } + + return ff_formats_ref(ff_make_format_list(pix_fmts), &ctx->outputs[0]->in_formats); } static int config_inputx(AVFilterLink *inlink) @@ -127,11 +202,11 @@ static int config_inputx(AVFilterLink *inlink) int hsub = desc->log2_chroma_w; int vsub = desc->log2_chroma_h; - s->nb_planes = av_pix_fmt_count_planes(inlink->format); - s->height[1] = s->height[2] = AV_CEIL_RSHIFT(inlink->h, vsub); - s->height[0] = s->height[3] = inlink->h; - s->width[1] = s->width[2] = AV_CEIL_RSHIFT(inlink->w, hsub); - s->width[0] = s->width[3] = inlink->w; + s->nb_planesx = av_pix_fmt_count_planes(inlink->format); + s->heightx[1] = s->heightx[2] = AV_CEIL_RSHIFT(inlink->h, vsub); + s->heightx[0] = s->heightx[3] = inlink->h; + s->widthx[1] = s->widthx[2] = AV_CEIL_RSHIFT(inlink->w, hsub); + s->widthx[0] = s->widthx[3] = inlink->w; s->var_values[VAR_W] = inlink->w; s->var_values[VAR_H] = inlink->h; @@ -151,62 +226,66 @@ static int config_inputy(AVFilterLink *inlink) AVFilterContext *ctx = inlink->dst; LUT2Context *s = ctx->priv; const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format); + int hsub = desc->log2_chroma_w; + int vsub = desc->log2_chroma_h; + s->nb_planesy = av_pix_fmt_count_planes(inlink->format); s->depthy = desc->comp[0].depth; s->var_values[VAR_BITDEPTHY] = s->depthy; + s->heighty[1] = s->heighty[2] = AV_CEIL_RSHIFT(inlink->h, vsub); + s->heighty[0] = s->heighty[3] = inlink->h; + s->widthy[1] = s->widthy[2] = AV_CEIL_RSHIFT(inlink->w, hsub); + s->widthy[0] = s->widthy[3] = inlink->w; return 0; } -static void lut2_8bit(struct LUT2Context *s, AVFrame *out, AVFrame *srcx, AVFrame *srcy) -{ - int p, y, x; - - for (p = 0; p < s->nb_planes; p++) { - const uint16_t *lut = s->lut[p]; - const uint8_t *srcxx, *srcyy; - uint8_t *dst; - - dst = out->data[p]; - srcxx = srcx->data[p]; - srcyy = srcy->data[p]; - - for (y = 0; y < s->height[p]; y++) { - for (x = 0; x < s->width[p]; x++) { - dst[x] = lut[(srcyy[x] << s->depthx) | srcxx[x]]; - } - - dst += out->linesize[p]; - srcxx += srcx->linesize[p]; - srcyy += srcy->linesize[p]; - } - } +#define DEFINE_LUT2(zname, xname, yname, ztype, xtype, ytype, zdiv, xdiv, ydiv) \ +static int lut2_##zname##_##xname##_##yname(AVFilterContext *ctx, \ + void *arg, \ + int jobnr, int nb_jobs) \ +{ \ + LUT2Context *s = ctx->priv; \ + ThreadData *td = arg; \ + AVFrame *out = td->out; \ + AVFrame *srcx = td->srcx; \ + AVFrame *srcy = td->srcy; \ + const int odepth = s->odepth; \ + int p, y, x; \ + \ + for (p = 0; p < s->nb_planes; p++) { \ + const int slice_start = (s->heightx[p] * jobnr) / nb_jobs; \ + const int slice_end = (s->heightx[p] * (jobnr+1)) / nb_jobs; \ + const uint16_t *lut = s->lut[p]; \ + const xtype *srcxx; \ + const ytype *srcyy; \ + ztype *dst; \ + \ + dst = (ztype *)(out->data[p] + slice_start * out->linesize[p]); \ + srcxx = (const xtype *)(srcx->data[p] + slice_start * srcx->linesize[p]);\ + srcyy = (const ytype *)(srcy->data[p] + slice_start * srcy->linesize[p]);\ + \ + for (y = slice_start; y < slice_end; y++) { \ + for (x = 0; x < s->widthx[p]; x++) { \ + dst[x] = av_clip_uintp2_c(lut[(srcyy[x] << s->depthx) | srcxx[x]], odepth); \ + } \ + \ + dst += out->linesize[p] / zdiv; \ + srcxx += srcx->linesize[p] / xdiv; \ + srcyy += srcy->linesize[p] / ydiv; \ + } \ + } \ + return 0; \ } -static void lut2_16bit(struct LUT2Context *s, AVFrame *out, AVFrame *srcx, AVFrame *srcy) -{ - int p, y, x; - - for (p = 0; p < s->nb_planes; p++) { - const uint16_t *lut = s->lut[p]; - const uint16_t *srcxx, *srcyy; - uint16_t *dst; - - dst = (uint16_t *)out->data[p]; - srcxx = (uint16_t *)srcx->data[p]; - srcyy = (uint16_t *)srcy->data[p]; - - for (y = 0; y < s->height[p]; y++) { - for (x = 0; x < s->width[p]; x++) { - dst[x] = lut[(srcyy[x] << s->depthx) | srcxx[x]]; - } - - dst += out->linesize[p] / 2; - srcxx += srcx->linesize[p] / 2; - srcyy += srcy->linesize[p] / 2; - } - } -} +DEFINE_LUT2(8, 8, 8, uint8_t, uint8_t, uint8_t, 1, 1, 1) +DEFINE_LUT2(8, 8, 16, uint8_t, uint8_t, uint16_t, 1, 1, 2) +DEFINE_LUT2(8, 16, 8, uint8_t, uint16_t, uint8_t, 1, 2, 1) +DEFINE_LUT2(8, 16, 16, uint8_t, uint16_t, uint16_t, 1, 2, 2) +DEFINE_LUT2(16, 8, 8, uint16_t, uint8_t, uint8_t, 2, 1, 1) +DEFINE_LUT2(16, 8, 16, uint16_t, uint8_t, uint16_t, 2, 1, 2) +DEFINE_LUT2(16, 16, 8, uint16_t, uint16_t, uint8_t, 2, 2, 1) +DEFINE_LUT2(16, 16, 16, uint16_t, uint16_t, uint16_t, 2, 2, 2) static int process_frame(FFFrameSync *fs) { @@ -225,12 +304,17 @@ static int process_frame(FFFrameSync *fs) if (!out) return AVERROR(ENOMEM); } else { + ThreadData td; + out = ff_get_video_buffer(outlink, outlink->w, outlink->h); if (!out) return AVERROR(ENOMEM); av_frame_copy_props(out, srcx); - s->lut2(s, out, srcx, srcy); + td.out = out; + td.srcx = srcx; + td.srcy = srcy; + ctx->internal->execute(ctx, s->lut2, &td, NULL, FFMIN(s->heightx[1], ff_filter_get_nb_threads(ctx))); } out->pts = av_rescale_q(s->fs.pts, s->fs.time_base, outlink->time_base); @@ -245,8 +329,27 @@ static int config_output(AVFilterLink *outlink) int p, ret; s->depth = s->depthx + s->depthy; + s->nb_planes = s->nb_planesx; - s->lut2 = s->depth > 16 ? lut2_16bit : lut2_8bit; + s->lut2 = s->depth > 16 ? lut2_16_16_16 : lut2_8_8_8; + if (s->odepth) { + if (s->depthx == 8 && s->depthy == 8 && s->odepth > 8) + s->lut2 = lut2_16_8_8; + if (s->depthx > 8 && s->depthy == 8 && s->odepth > 8) + s->lut2 = lut2_16_16_8; + if (s->depthx == 8 && s->depthy > 8 && s->odepth > 8) + s->lut2 = lut2_16_8_16; + if (s->depthx == 8 && s->depthy == 8 && s->odepth == 8) + s->lut2 = lut2_8_8_8; + if (s->depthx > 8 && s->depthy == 8 && s->odepth == 8) + s->lut2 = lut2_8_16_8; + if (s->depthx == 8 && s->depthy > 8 && s->odepth == 8) + s->lut2 = lut2_8_8_16; + if (s->depthx > 8 && s->depthy > 8 && s->odepth == 8) + s->lut2 = lut2_8_16_16; + } else { + s->odepth = s->depthx; + } for (p = 0; p < s->nb_planes; p++) { s->lut[p] = av_malloc_array(1 << s->depth, sizeof(uint16_t)); @@ -271,7 +374,7 @@ static int config_output(AVFilterLink *outlink) } /* compute the lut */ - for (y = 0; y < (1 << s->depthx); y++) { + for (y = 0; y < (1 << s->depthy); y++) { s->var_values[VAR_Y] = y; for (x = 0; x < (1 << s->depthx); x++) { s->var_values[VAR_X] = x; @@ -298,12 +401,28 @@ static int lut2_config_output(AVFilterLink *outlink) AVFilterLink *srcx = ctx->inputs[0]; AVFilterLink *srcy = ctx->inputs[1]; FFFrameSyncIn *in; + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(outlink->format); + int hsub = desc->log2_chroma_w; + int vsub = desc->log2_chroma_h; int ret; - if (srcx->format != srcy->format) { + outlink->w = srcx->w; + outlink->h = srcx->h; + outlink->time_base = srcx->time_base; + outlink->sample_aspect_ratio = srcx->sample_aspect_ratio; + outlink->frame_rate = srcx->frame_rate; + + s->nb_planes = av_pix_fmt_count_planes(outlink->format); + s->height[1] = s->height[2] = AV_CEIL_RSHIFT(outlink->h, vsub); + s->height[0] = s->height[3] = outlink->h; + s->width[1] = s->width[2] = AV_CEIL_RSHIFT(outlink->w, hsub); + s->width[0] = s->width[3] = outlink->w; + + if (!s->odepth && srcx->format != srcy->format) { av_log(ctx, AV_LOG_ERROR, "inputs must be of same pixel format\n"); return AVERROR(EINVAL); } + if (srcx->w != srcy->w || srcx->h != srcy->h) { av_log(ctx, AV_LOG_ERROR, "First input link %s parameters " "(size %dx%d) do not match the corresponding " @@ -314,11 +433,61 @@ static int lut2_config_output(AVFilterLink *outlink) return AVERROR(EINVAL); } - outlink->w = srcx->w; - outlink->h = srcx->h; - outlink->time_base = srcx->time_base; - outlink->sample_aspect_ratio = srcx->sample_aspect_ratio; - outlink->frame_rate = srcx->frame_rate; + if (s->nb_planesx != s->nb_planesy) { + av_log(ctx, AV_LOG_ERROR, "First input link %s number of planes " + "(%d) do not match the corresponding " + "second input link %s number of planes (%d)\n", + ctx->input_pads[0].name, s->nb_planesx, + ctx->input_pads[1].name, s->nb_planesy); + return AVERROR(EINVAL); + } + + if (s->nb_planesx != s->nb_planes) { + av_log(ctx, AV_LOG_ERROR, "First input link %s number of planes " + "(%d) do not match the corresponding " + "output link %s number of planes (%d)\n", + ctx->input_pads[0].name, s->nb_planesx, + ctx->output_pads[0].name, s->nb_planes); + return AVERROR(EINVAL); + } + + if (s->widthx[1] != s->widthy[1] || s->heightx[1] != s->heighty[1]) { + av_log(ctx, AV_LOG_ERROR, "First input link %s 2nd plane " + "(size %dx%d) do not match the corresponding " + "second input link %s 2nd plane (size %dx%d)\n", + ctx->input_pads[0].name, s->widthx[1], s->heightx[1], + ctx->input_pads[1].name, + s->widthy[1], s->heighty[1]); + return AVERROR(EINVAL); + } + + if (s->widthx[2] != s->widthy[2] || s->heightx[2] != s->heighty[2]) { + av_log(ctx, AV_LOG_ERROR, "First input link %s 3rd plane " + "(size %dx%d) do not match the corresponding " + "second input link %s 3rd plane (size %dx%d)\n", + ctx->input_pads[0].name, s->widthx[2], s->heightx[2], + ctx->input_pads[1].name, + s->widthy[2], s->heighty[2]); + return AVERROR(EINVAL); + } + + if (s->widthx[1] != s->width[1] || s->heightx[1] != s->height[1]) { + av_log(ctx, AV_LOG_ERROR, "First input link %s 2nd plane " + "(size %dx%d) do not match the corresponding " + "output link %s 2nd plane (size %dx%d)\n", + ctx->input_pads[0].name, s->widthx[1], s->heightx[1], + ctx->output_pads[0].name, s->width[1], s->height[1]); + return AVERROR(EINVAL); + } + + if (s->widthx[2] != s->width[2] || s->heightx[2] != s->height[2]) { + av_log(ctx, AV_LOG_ERROR, "First input link %s 3rd plane " + "(size %dx%d) do not match the corresponding " + "output link %s 3rd plane (size %dx%d)\n", + ctx->input_pads[0].name, s->widthx[2], s->heightx[2], + ctx->output_pads[0].name, s->width[2], s->height[2]); + return AVERROR(EINVAL); + } if ((ret = ff_framesync_init(&s->fs, ctx, 2)) < 0) return ret; @@ -338,7 +507,10 @@ static int lut2_config_output(AVFilterLink *outlink) if ((ret = config_output(outlink)) < 0) return ret; - return ff_framesync_configure(&s->fs); + ret = ff_framesync_configure(&s->fs); + outlink->time_base = s->fs.time_base; + + return ret; } static int activate(AVFilterContext *ctx) @@ -385,7 +557,8 @@ AVFilter ff_vf_lut2 = { .activate = activate, .inputs = inputs, .outputs = outputs, - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, + .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | + AVFILTER_FLAG_SLICE_THREADS, }; #if CONFIG_TLUT2_FILTER @@ -401,18 +574,32 @@ static av_cold int init(AVFilterContext *ctx) static int tlut2_filter_frame(AVFilterLink *inlink, AVFrame *frame) { - LUT2Context *s = inlink->dst->priv; - AVFilterLink *outlink = inlink->dst->outputs[0]; + AVFilterContext *ctx = inlink->dst; + LUT2Context *s = ctx->priv; + AVFilterLink *outlink = ctx->outputs[0]; if (s->prev_frame) { - AVFrame *out = ff_get_video_buffer(outlink, outlink->w, outlink->h); - if (!out) { - av_frame_free(&s->prev_frame); - s->prev_frame = frame; - return AVERROR(ENOMEM); + AVFrame *out; + + if (ctx->is_disabled) { + out = av_frame_clone(frame); + } else { + ThreadData td; + + out = ff_get_video_buffer(outlink, outlink->w, outlink->h); + if (!out) { + av_frame_free(&s->prev_frame); + s->prev_frame = frame; + return AVERROR(ENOMEM); + } + + av_frame_copy_props(out, frame); + + td.out = out; + td.srcx = frame; + td.srcy = s->prev_frame; + ctx->internal->execute(ctx, s->lut2, &td, NULL, FFMIN(s->heightx[1], ff_filter_get_nb_threads(ctx))); } - av_frame_copy_props(out, frame); - s->lut2(s, out, frame, s->prev_frame); av_frame_free(&s->prev_frame); s->prev_frame = frame; return ff_filter_frame(outlink, out); @@ -421,7 +608,13 @@ static int tlut2_filter_frame(AVFilterLink *inlink, AVFrame *frame) return 0; } -#define tlut2_options options +static const AVOption tlut2_options[] = { + { "c0", "set component #0 expression", OFFSET(comp_expr_str[0]), AV_OPT_TYPE_STRING, { .str = "x" }, .flags = FLAGS }, + { "c1", "set component #1 expression", OFFSET(comp_expr_str[1]), AV_OPT_TYPE_STRING, { .str = "x" }, .flags = FLAGS }, + { "c2", "set component #2 expression", OFFSET(comp_expr_str[2]), AV_OPT_TYPE_STRING, { .str = "x" }, .flags = FLAGS }, + { "c3", "set component #3 expression", OFFSET(comp_expr_str[3]), AV_OPT_TYPE_STRING, { .str = "x" }, .flags = FLAGS }, + { NULL } +}; AVFILTER_DEFINE_CLASS(tlut2); @@ -454,6 +647,8 @@ AVFilter ff_vf_tlut2 = { .uninit = uninit, .inputs = tlut2_inputs, .outputs = tlut2_outputs, + .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | + AVFILTER_FLAG_SLICE_THREADS, }; #endif diff --git a/libavfilter/vf_lut3d.c b/libavfilter/vf_lut3d.c index c9b72249a..a525039ba 100644 --- a/libavfilter/vf_lut3d.c +++ b/libavfilter/vf_lut3d.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2013 Clément Bœsch + * Copyright (c) 2018 Paul B Mahol * * This file is part of FFmpeg. * @@ -54,7 +55,7 @@ struct rgbvec { /* 3D LUT don't often go up to level 32, but it is common to have a Hald CLUT * of 512x512 (64x64x64) */ -#define MAX_LEVEL 64 +#define MAX_LEVEL 128 typedef struct LUT3DContext { const AVClass *class; @@ -63,12 +64,14 @@ typedef struct LUT3DContext { uint8_t rgba_map[4]; int step; avfilter_action_func *interp; + struct rgbvec scale; struct rgbvec lut[MAX_LEVEL][MAX_LEVEL][MAX_LEVEL]; int lutsize; #if CONFIG_HALDCLUT_FILTER uint8_t clut_rgba_map[4]; int clut_step; - int clut_is16bit; + int clut_bits; + int clut_planar; int clut_width; FFFrameSync fs; #endif @@ -198,6 +201,85 @@ static inline struct rgbvec interp_tetrahedral(const LUT3DContext *lut3d, return c; } +#define DEFINE_INTERP_FUNC_PLANAR(name, nbits, depth) \ +static int interp_##nbits##_##name##_p##depth(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) \ +{ \ + int x, y; \ + const LUT3DContext *lut3d = ctx->priv; \ + const ThreadData *td = arg; \ + const AVFrame *in = td->in; \ + const AVFrame *out = td->out; \ + const int direct = out == in; \ + const int slice_start = (in->height * jobnr ) / nb_jobs; \ + const int slice_end = (in->height * (jobnr+1)) / nb_jobs; \ + uint8_t *grow = out->data[0] + slice_start * out->linesize[0]; \ + uint8_t *brow = out->data[1] + slice_start * out->linesize[1]; \ + uint8_t *rrow = out->data[2] + slice_start * out->linesize[2]; \ + uint8_t *arow = out->data[3] + slice_start * out->linesize[3]; \ + const uint8_t *srcgrow = in->data[0] + slice_start * in->linesize[0]; \ + const uint8_t *srcbrow = in->data[1] + slice_start * in->linesize[1]; \ + const uint8_t *srcrrow = in->data[2] + slice_start * in->linesize[2]; \ + const uint8_t *srcarow = in->data[3] + slice_start * in->linesize[3]; \ + const float scale_r = (lut3d->scale.r / ((1<lutsize - 1); \ + const float scale_g = (lut3d->scale.g / ((1<lutsize - 1); \ + const float scale_b = (lut3d->scale.b / ((1<lutsize - 1); \ + \ + for (y = slice_start; y < slice_end; y++) { \ + uint##nbits##_t *dstg = (uint##nbits##_t *)grow; \ + uint##nbits##_t *dstb = (uint##nbits##_t *)brow; \ + uint##nbits##_t *dstr = (uint##nbits##_t *)rrow; \ + uint##nbits##_t *dsta = (uint##nbits##_t *)arow; \ + const uint##nbits##_t *srcg = (const uint##nbits##_t *)srcgrow; \ + const uint##nbits##_t *srcb = (const uint##nbits##_t *)srcbrow; \ + const uint##nbits##_t *srcr = (const uint##nbits##_t *)srcrrow; \ + const uint##nbits##_t *srca = (const uint##nbits##_t *)srcarow; \ + for (x = 0; x < in->width; x++) { \ + const struct rgbvec scaled_rgb = {srcr[x] * scale_r, \ + srcg[x] * scale_g, \ + srcb[x] * scale_b}; \ + struct rgbvec vec = interp_##name(lut3d, &scaled_rgb); \ + dstr[x] = av_clip_uintp2(vec.r * (float)((1<linesize[3]) \ + dsta[x] = srca[x]; \ + } \ + grow += out->linesize[0]; \ + brow += out->linesize[1]; \ + rrow += out->linesize[2]; \ + arow += out->linesize[3]; \ + srcgrow += in->linesize[0]; \ + srcbrow += in->linesize[1]; \ + srcrrow += in->linesize[2]; \ + srcarow += in->linesize[3]; \ + } \ + return 0; \ +} + +DEFINE_INTERP_FUNC_PLANAR(nearest, 8, 8) +DEFINE_INTERP_FUNC_PLANAR(trilinear, 8, 8) +DEFINE_INTERP_FUNC_PLANAR(tetrahedral, 8, 8) + +DEFINE_INTERP_FUNC_PLANAR(nearest, 16, 9) +DEFINE_INTERP_FUNC_PLANAR(trilinear, 16, 9) +DEFINE_INTERP_FUNC_PLANAR(tetrahedral, 16, 9) + +DEFINE_INTERP_FUNC_PLANAR(nearest, 16, 10) +DEFINE_INTERP_FUNC_PLANAR(trilinear, 16, 10) +DEFINE_INTERP_FUNC_PLANAR(tetrahedral, 16, 10) + +DEFINE_INTERP_FUNC_PLANAR(nearest, 16, 12) +DEFINE_INTERP_FUNC_PLANAR(trilinear, 16, 12) +DEFINE_INTERP_FUNC_PLANAR(tetrahedral, 16, 12) + +DEFINE_INTERP_FUNC_PLANAR(nearest, 16, 14) +DEFINE_INTERP_FUNC_PLANAR(trilinear, 16, 14) +DEFINE_INTERP_FUNC_PLANAR(tetrahedral, 16, 14) + +DEFINE_INTERP_FUNC_PLANAR(nearest, 16, 16) +DEFINE_INTERP_FUNC_PLANAR(trilinear, 16, 16) +DEFINE_INTERP_FUNC_PLANAR(tetrahedral, 16, 16) + #define DEFINE_INTERP_FUNC(name, nbits) \ static int interp_##nbits##_##name(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) \ { \ @@ -216,15 +298,17 @@ static int interp_##nbits##_##name(AVFilterContext *ctx, void *arg, int jobnr, i const int slice_end = (in->height * (jobnr+1)) / nb_jobs; \ uint8_t *dstrow = out->data[0] + slice_start * out->linesize[0]; \ const uint8_t *srcrow = in ->data[0] + slice_start * in ->linesize[0]; \ - const float scale = (1. / ((1<lutsize - 1); \ + const float scale_r = (lut3d->scale.r / ((1<lutsize - 1); \ + const float scale_g = (lut3d->scale.g / ((1<lutsize - 1); \ + const float scale_b = (lut3d->scale.b / ((1<lutsize - 1); \ \ for (y = slice_start; y < slice_end; y++) { \ uint##nbits##_t *dst = (uint##nbits##_t *)dstrow; \ const uint##nbits##_t *src = (const uint##nbits##_t *)srcrow; \ for (x = 0; x < in->width * step; x += step) { \ - const struct rgbvec scaled_rgb = {src[x + r] * scale, \ - src[x + g] * scale, \ - src[x + b] * scale}; \ + const struct rgbvec scaled_rgb = {src[x + r] * scale_r, \ + src[x + g] * scale_g, \ + src[x + b] * scale_b}; \ struct rgbvec vec = interp_##name(lut3d, &scaled_rgb); \ dst[x + r] = av_clip_uint##nbits(vec.r * (float)((1<lut[k][j][i]; if (k != 0 || j != 0 || i != 0) NEXT_LINE(skip_line(line)); - if (sscanf(line, "%f %f %f", &vec->r, &vec->g, &vec->b) != 3) + if (av_sscanf(line, "%f %f %f", &vec->r, &vec->g, &vec->b) != 3) return AVERROR_INVALIDDATA; } } @@ -305,7 +389,7 @@ static int parse_cube(AVFilterContext *ctx, FILE *f) float max[3] = {1.0, 1.0, 1.0}; while (fgets(line, sizeof(line), f)) { - if (!strncmp(line, "LUT_3D_SIZE ", 12)) { + if (!strncmp(line, "LUT_3D_SIZE", 11)) { int i, j, k; const int size = strtol(line + 12, NULL, 0); @@ -328,23 +412,27 @@ try_again: else if (!strncmp(line + 7, "MAX ", 4)) vals = max; if (!vals) return AVERROR_INVALIDDATA; - sscanf(line + 11, "%f %f %f", vals, vals + 1, vals + 2); + av_sscanf(line + 11, "%f %f %f", vals, vals + 1, vals + 2); av_log(ctx, AV_LOG_DEBUG, "min: %f %f %f | max: %f %f %f\n", min[0], min[1], min[2], max[0], max[1], max[2]); goto try_again; + } else if (!strncmp(line, "TITLE", 5)) { + goto try_again; } } while (skip_line(line)); - if (sscanf(line, "%f %f %f", &vec->r, &vec->g, &vec->b) != 3) + if (av_sscanf(line, "%f %f %f", &vec->r, &vec->g, &vec->b) != 3) return AVERROR_INVALIDDATA; - vec->r *= max[0] - min[0]; - vec->g *= max[1] - min[1]; - vec->b *= max[2] - min[2]; } } } break; } } + + lut3d->scale.r = av_clipf(1. / (max[0] - min[0]), 0.f, 1.f); + lut3d->scale.g = av_clipf(1. / (max[1] - min[1]), 0.f, 1.f); + lut3d->scale.b = av_clipf(1. / (max[2] - min[2]), 0.f, 1.f); + return 0; } @@ -367,7 +455,7 @@ static int parse_3dl(AVFilterContext *ctx, FILE *f) struct rgbvec *vec = &lut3d->lut[k][j][i]; NEXT_LINE(skip_line(line)); - if (sscanf(line, "%d %d %d", &r, &g, &b) != 3) + if (av_sscanf(line, "%d %d %d", &r, &g, &b) != 3) return AVERROR_INVALIDDATA; vec->r = r / scale; vec->g = g / scale; @@ -431,7 +519,7 @@ static int parse_m3d(AVFilterContext *ctx, FILE *f) float val[3]; NEXT_LINE(0); - if (sscanf(line, "%f %f %f", val, val + 1, val + 2) != 3) + if (av_sscanf(line, "%f %f %f", val, val + 1, val + 2) != 3) return AVERROR_INVALIDDATA; vec->r = val[rgb_map[0]] * scale; vec->g = val[rgb_map[1]] * scale; @@ -442,6 +530,100 @@ static int parse_m3d(AVFilterContext *ctx, FILE *f) return 0; } +static int parse_cinespace(AVFilterContext *ctx, FILE *f) +{ + LUT3DContext *lut3d = ctx->priv; + char line[MAX_LINE_SIZE]; + float in_min[3] = {0.0, 0.0, 0.0}; + float in_max[3] = {1.0, 1.0, 1.0}; + float out_min[3] = {0.0, 0.0, 0.0}; + float out_max[3] = {1.0, 1.0, 1.0}; + int inside_metadata = 0, size; + + NEXT_LINE(skip_line(line)); + if (strncmp(line, "CSPLUTV100", 10)) { + av_log(ctx, AV_LOG_ERROR, "Not cineSpace LUT format\n"); + return AVERROR(EINVAL); + } + + NEXT_LINE(skip_line(line)); + if (strncmp(line, "3D", 2)) { + av_log(ctx, AV_LOG_ERROR, "Not 3D LUT format\n"); + return AVERROR(EINVAL); + } + + while (1) { + NEXT_LINE(skip_line(line)); + + if (!strncmp(line, "BEGIN METADATA", 14)) { + inside_metadata = 1; + continue; + } + if (!strncmp(line, "END METADATA", 12)) { + inside_metadata = 0; + continue; + } + if (inside_metadata == 0) { + int size_r, size_g, size_b; + + for (int i = 0; i < 3; i++) { + int npoints = strtol(line, NULL, 0); + + if (npoints != 2) { + av_log(ctx, AV_LOG_ERROR, "Unsupported number of pre-lut points.\n"); + return AVERROR_PATCHWELCOME; + } + + NEXT_LINE(skip_line(line)); + if (av_sscanf(line, "%f %f", &in_min[i], &in_max[i]) != 2) + return AVERROR_INVALIDDATA; + NEXT_LINE(skip_line(line)); + if (av_sscanf(line, "%f %f", &out_min[i], &out_max[i]) != 2) + return AVERROR_INVALIDDATA; + NEXT_LINE(skip_line(line)); + } + + if (av_sscanf(line, "%d %d %d", &size_r, &size_g, &size_b) != 3) + return AVERROR(EINVAL); + if (size_r != size_g || size_r != size_b) { + av_log(ctx, AV_LOG_ERROR, "Unsupported size combination: %dx%dx%d.\n", size_r, size_g, size_b); + return AVERROR_PATCHWELCOME; + } + + size = size_r; + if (size < 2 || size > MAX_LEVEL) { + av_log(ctx, AV_LOG_ERROR, "Too large or invalid 3D LUT size\n"); + return AVERROR(EINVAL); + } + + lut3d->lutsize = size; + + for (int k = 0; k < size; k++) { + for (int j = 0; j < size; j++) { + for (int i = 0; i < size; i++) { + struct rgbvec *vec = &lut3d->lut[i][j][k]; + if (k != 0 || j != 0 || i != 0) + NEXT_LINE(skip_line(line)); + if (av_sscanf(line, "%f %f %f", &vec->r, &vec->g, &vec->b) != 3) + return AVERROR_INVALIDDATA; + vec->r *= out_max[0] - out_min[0]; + vec->g *= out_max[1] - out_min[1]; + vec->b *= out_max[2] - out_min[2]; + } + } + } + + break; + } + } + + lut3d->scale.r = av_clipf(1. / (in_max[0] - in_min[0]), 0.f, 1.f); + lut3d->scale.g = av_clipf(1. / (in_max[1] - in_min[1]), 0.f, 1.f); + lut3d->scale.b = av_clipf(1. / (in_max[2] - in_min[2]), 0.f, 1.f); + + return 0; +} + static void set_identity_matrix(LUT3DContext *lut3d, int size) { int i, j, k; @@ -470,6 +652,12 @@ static int query_formats(AVFilterContext *ctx) AV_PIX_FMT_RGB0, AV_PIX_FMT_BGR0, AV_PIX_FMT_RGB48, AV_PIX_FMT_BGR48, AV_PIX_FMT_RGBA64, AV_PIX_FMT_BGRA64, + AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRAP, + AV_PIX_FMT_GBRP9, + AV_PIX_FMT_GBRP10, AV_PIX_FMT_GBRAP10, + AV_PIX_FMT_GBRP12, AV_PIX_FMT_GBRAP12, + AV_PIX_FMT_GBRP14, + AV_PIX_FMT_GBRP16, AV_PIX_FMT_GBRAP16, AV_PIX_FMT_NONE }; AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts); @@ -480,24 +668,49 @@ static int query_formats(AVFilterContext *ctx) static int config_input(AVFilterLink *inlink) { - int is16bit = 0; + int depth, is16bit = 0, planar = 0; LUT3DContext *lut3d = inlink->dst->priv; const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format); + depth = desc->comp[0].depth; + switch (inlink->format) { case AV_PIX_FMT_RGB48: case AV_PIX_FMT_BGR48: case AV_PIX_FMT_RGBA64: case AV_PIX_FMT_BGRA64: is16bit = 1; + break; + case AV_PIX_FMT_GBRP9: + case AV_PIX_FMT_GBRP10: + case AV_PIX_FMT_GBRP12: + case AV_PIX_FMT_GBRP14: + case AV_PIX_FMT_GBRP16: + case AV_PIX_FMT_GBRAP10: + case AV_PIX_FMT_GBRAP12: + case AV_PIX_FMT_GBRAP16: + is16bit = 1; + case AV_PIX_FMT_GBRP: + case AV_PIX_FMT_GBRAP: + planar = 1; + break; } ff_fill_rgba_map(lut3d->rgba_map, inlink->format); lut3d->step = av_get_padded_bits_per_pixel(desc) >> (3 + is16bit); -#define SET_FUNC(name) do { \ - if (is16bit) lut3d->interp = interp_16_##name; \ - else lut3d->interp = interp_8_##name; \ +#define SET_FUNC(name) do { \ + if (planar) { \ + switch (depth) { \ + case 8: lut3d->interp = interp_8_##name##_p8; break; \ + case 9: lut3d->interp = interp_16_##name##_p9; break; \ + case 10: lut3d->interp = interp_16_##name##_p10; break; \ + case 12: lut3d->interp = interp_16_##name##_p12; break; \ + case 14: lut3d->interp = interp_16_##name##_p14; break; \ + case 16: lut3d->interp = interp_16_##name##_p16; break; \ + } \ + } else if (is16bit) { lut3d->interp = interp_16_##name; \ + } else { lut3d->interp = interp_8_##name; } \ } while (0) switch (lut3d->interpolation) { @@ -564,6 +777,8 @@ static av_cold int lut3d_init(AVFilterContext *ctx) const char *ext; LUT3DContext *lut3d = ctx->priv; + lut3d->scale.r = lut3d->scale.g = lut3d->scale.b = 1.f; + if (!lut3d->file) { set_identity_matrix(lut3d, 32); return 0; @@ -592,6 +807,8 @@ static av_cold int lut3d_init(AVFilterContext *ctx) ret = parse_cube(ctx, f); } else if (!av_strcasecmp(ext, "m3d")) { ret = parse_m3d(ctx, f); + } else if (!av_strcasecmp(ext, "csp")) { + ret = parse_cinespace(ctx, f); } else { av_log(ctx, AV_LOG_ERROR, "Unrecognized '.%s' file type\n", ext); ret = AVERROR(EINVAL); @@ -640,7 +857,7 @@ AVFilter ff_vf_lut3d = { #if CONFIG_HALDCLUT_FILTER -static void update_clut(LUT3DContext *lut3d, const AVFrame *frame) +static void update_clut_packed(LUT3DContext *lut3d, const AVFrame *frame) { const uint8_t *data = frame->data[0]; const int linesize = frame->linesize[0]; @@ -670,10 +887,57 @@ static void update_clut(LUT3DContext *lut3d, const AVFrame *frame) } \ } while (0) - if (!lut3d->clut_is16bit) LOAD_CLUT(8); - else LOAD_CLUT(16); + switch (lut3d->clut_bits) { + case 8: LOAD_CLUT(8); break; + case 16: LOAD_CLUT(16); break; + } } +static void update_clut_planar(LUT3DContext *lut3d, const AVFrame *frame) +{ + const uint8_t *datag = frame->data[0]; + const uint8_t *datab = frame->data[1]; + const uint8_t *datar = frame->data[2]; + const int glinesize = frame->linesize[0]; + const int blinesize = frame->linesize[1]; + const int rlinesize = frame->linesize[2]; + const int w = lut3d->clut_width; + const int level = lut3d->lutsize; + +#define LOAD_CLUT_PLANAR(nbits, depth) do { \ + int i, j, k, x = 0, y = 0; \ + \ + for (k = 0; k < level; k++) { \ + for (j = 0; j < level; j++) { \ + for (i = 0; i < level; i++) { \ + const uint##nbits##_t *gsrc = (const uint##nbits##_t *) \ + (datag + y*glinesize); \ + const uint##nbits##_t *bsrc = (const uint##nbits##_t *) \ + (datab + y*blinesize); \ + const uint##nbits##_t *rsrc = (const uint##nbits##_t *) \ + (datar + y*rlinesize); \ + struct rgbvec *vec = &lut3d->lut[i][j][k]; \ + vec->r = gsrc[x] / (float)((1<<(depth)) - 1); \ + vec->g = bsrc[x] / (float)((1<<(depth)) - 1); \ + vec->b = rsrc[x] / (float)((1<<(depth)) - 1); \ + if (++x == w) { \ + x = 0; \ + y++; \ + } \ + } \ + } \ + } \ +} while (0) + + switch (lut3d->clut_bits) { + case 8: LOAD_CLUT_PLANAR(8, 8); break; + case 9: LOAD_CLUT_PLANAR(16, 9); break; + case 10: LOAD_CLUT_PLANAR(16, 10); break; + case 12: LOAD_CLUT_PLANAR(16, 12); break; + case 14: LOAD_CLUT_PLANAR(16, 14); break; + case 16: LOAD_CLUT_PLANAR(16, 16); break; + } +} static int config_output(AVFilterLink *outlink) { @@ -707,14 +971,8 @@ static int config_clut(AVFilterLink *inlink) av_assert0(desc); - lut3d->clut_is16bit = 0; - switch (inlink->format) { - case AV_PIX_FMT_RGB48: - case AV_PIX_FMT_BGR48: - case AV_PIX_FMT_RGBA64: - case AV_PIX_FMT_BGRA64: - lut3d->clut_is16bit = 1; - } + lut3d->clut_bits = desc->comp[0].depth; + lut3d->clut_planar = av_pix_fmt_count_planes(inlink->format) > 1; lut3d->clut_step = av_get_padded_bits_per_pixel(desc) >> 3; ff_fill_rgba_map(lut3d->clut_rgba_map, inlink->format); @@ -751,6 +1009,7 @@ static int config_clut(AVFilterLink *inlink) static int update_apply_clut(FFFrameSync *fs) { AVFilterContext *ctx = fs->parent; + LUT3DContext *lut3d = ctx->priv; AVFilterLink *inlink = ctx->inputs[0]; AVFrame *master, *second, *out; int ret; @@ -760,7 +1019,10 @@ static int update_apply_clut(FFFrameSync *fs) return ret; if (!second) return ff_filter_frame(ctx->outputs[0], master); - update_clut(ctx->priv, second); + if (lut3d->clut_planar) + update_clut_planar(ctx->priv, second); + else + update_clut_packed(ctx->priv, second); out = apply_lut(inlink, master); return ff_filter_frame(ctx->outputs[0], out); } @@ -768,6 +1030,7 @@ static int update_apply_clut(FFFrameSync *fs) static av_cold int haldclut_init(AVFilterContext *ctx) { LUT3DContext *lut3d = ctx->priv; + lut3d->scale.r = lut3d->scale.g = lut3d->scale.b = 1.f; lut3d->fs.on_event = update_apply_clut; return 0; } @@ -821,3 +1084,599 @@ AVFilter ff_vf_haldclut = { .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | AVFILTER_FLAG_SLICE_THREADS, }; #endif + +#if CONFIG_LUT1D_FILTER + +enum interp_1d_mode { + INTERPOLATE_1D_NEAREST, + INTERPOLATE_1D_LINEAR, + INTERPOLATE_1D_CUBIC, + INTERPOLATE_1D_COSINE, + INTERPOLATE_1D_SPLINE, + NB_INTERP_1D_MODE +}; + +#define MAX_1D_LEVEL 65536 + +typedef struct LUT1DContext { + const AVClass *class; + char *file; + int interpolation; ///lutsize = size; + for (i = 0; i < size; i++) { + lut1d->lut[0][i] = i * c; + lut1d->lut[1][i] = i * c; + lut1d->lut[2][i] = i * c; + } +} + +static int parse_cinespace_1d(AVFilterContext *ctx, FILE *f) +{ + LUT1DContext *lut1d = ctx->priv; + char line[MAX_LINE_SIZE]; + float in_min[3] = {0.0, 0.0, 0.0}; + float in_max[3] = {1.0, 1.0, 1.0}; + float out_min[3] = {0.0, 0.0, 0.0}; + float out_max[3] = {1.0, 1.0, 1.0}; + int inside_metadata = 0, size; + + NEXT_LINE(skip_line(line)); + if (strncmp(line, "CSPLUTV100", 10)) { + av_log(ctx, AV_LOG_ERROR, "Not cineSpace LUT format\n"); + return AVERROR(EINVAL); + } + + NEXT_LINE(skip_line(line)); + if (strncmp(line, "1D", 2)) { + av_log(ctx, AV_LOG_ERROR, "Not 1D LUT format\n"); + return AVERROR(EINVAL); + } + + while (1) { + NEXT_LINE(skip_line(line)); + + if (!strncmp(line, "BEGIN METADATA", 14)) { + inside_metadata = 1; + continue; + } + if (!strncmp(line, "END METADATA", 12)) { + inside_metadata = 0; + continue; + } + if (inside_metadata == 0) { + for (int i = 0; i < 3; i++) { + int npoints = strtol(line, NULL, 0); + + if (npoints != 2) { + av_log(ctx, AV_LOG_ERROR, "Unsupported number of pre-lut points.\n"); + return AVERROR_PATCHWELCOME; + } + + NEXT_LINE(skip_line(line)); + if (av_sscanf(line, "%f %f", &in_min[i], &in_max[i]) != 2) + return AVERROR_INVALIDDATA; + NEXT_LINE(skip_line(line)); + if (av_sscanf(line, "%f %f", &out_min[i], &out_max[i]) != 2) + return AVERROR_INVALIDDATA; + NEXT_LINE(skip_line(line)); + } + + size = strtol(line, NULL, 0); + + if (size < 2 || size > MAX_1D_LEVEL) { + av_log(ctx, AV_LOG_ERROR, "Too large or invalid 1D LUT size\n"); + return AVERROR(EINVAL); + } + + lut1d->lutsize = size; + + for (int i = 0; i < size; i++) { + NEXT_LINE(skip_line(line)); + if (av_sscanf(line, "%f %f %f", &lut1d->lut[0][i], &lut1d->lut[1][i], &lut1d->lut[2][i]) != 3) + return AVERROR_INVALIDDATA; + lut1d->lut[0][i] *= out_max[0] - out_min[0]; + lut1d->lut[1][i] *= out_max[1] - out_min[1]; + lut1d->lut[2][i] *= out_max[2] - out_min[2]; + } + + break; + } + } + + lut1d->scale.r = av_clipf(1. / (in_max[0] - in_min[0]), 0.f, 1.f); + lut1d->scale.g = av_clipf(1. / (in_max[1] - in_min[1]), 0.f, 1.f); + lut1d->scale.b = av_clipf(1. / (in_max[2] - in_min[2]), 0.f, 1.f); + + return 0; +} + +static int parse_cube_1d(AVFilterContext *ctx, FILE *f) +{ + LUT1DContext *lut1d = ctx->priv; + char line[MAX_LINE_SIZE]; + float min[3] = {0.0, 0.0, 0.0}; + float max[3] = {1.0, 1.0, 1.0}; + + while (fgets(line, sizeof(line), f)) { + if (!strncmp(line, "LUT_1D_SIZE", 11)) { + const int size = strtol(line + 12, NULL, 0); + int i; + + if (size < 2 || size > MAX_1D_LEVEL) { + av_log(ctx, AV_LOG_ERROR, "Too large or invalid 1D LUT size\n"); + return AVERROR(EINVAL); + } + lut1d->lutsize = size; + for (i = 0; i < size; i++) { + do { +try_again: + NEXT_LINE(0); + if (!strncmp(line, "DOMAIN_", 7)) { + float *vals = NULL; + if (!strncmp(line + 7, "MIN ", 4)) vals = min; + else if (!strncmp(line + 7, "MAX ", 4)) vals = max; + if (!vals) + return AVERROR_INVALIDDATA; + av_sscanf(line + 11, "%f %f %f", vals, vals + 1, vals + 2); + av_log(ctx, AV_LOG_DEBUG, "min: %f %f %f | max: %f %f %f\n", + min[0], min[1], min[2], max[0], max[1], max[2]); + goto try_again; + } else if (!strncmp(line, "LUT_1D_INPUT_RANGE ", 19)) { + av_sscanf(line + 19, "%f %f", min, max); + min[1] = min[2] = min[0]; + max[1] = max[2] = max[0]; + goto try_again; + } else if (!strncmp(line, "TITLE", 5)) { + goto try_again; + } + } while (skip_line(line)); + if (av_sscanf(line, "%f %f %f", &lut1d->lut[0][i], &lut1d->lut[1][i], &lut1d->lut[2][i]) != 3) + return AVERROR_INVALIDDATA; + } + break; + } + } + + lut1d->scale.r = av_clipf(1. / (max[0] - min[0]), 0.f, 1.f); + lut1d->scale.g = av_clipf(1. / (max[1] - min[1]), 0.f, 1.f); + lut1d->scale.b = av_clipf(1. / (max[2] - min[2]), 0.f, 1.f); + + return 0; +} + +static const AVOption lut1d_options[] = { + { "file", "set 1D LUT file name", OFFSET(file), AV_OPT_TYPE_STRING, {.str=NULL}, .flags = FLAGS }, + { "interp", "select interpolation mode", OFFSET(interpolation), AV_OPT_TYPE_INT, {.i64=INTERPOLATE_1D_LINEAR}, 0, NB_INTERP_1D_MODE-1, FLAGS, "interp_mode" }, + { "nearest", "use values from the nearest defined points", 0, AV_OPT_TYPE_CONST, {.i64=INTERPOLATE_1D_NEAREST}, INT_MIN, INT_MAX, FLAGS, "interp_mode" }, + { "linear", "use values from the linear interpolation", 0, AV_OPT_TYPE_CONST, {.i64=INTERPOLATE_1D_LINEAR}, INT_MIN, INT_MAX, FLAGS, "interp_mode" }, + { "cosine", "use values from the cosine interpolation", 0, AV_OPT_TYPE_CONST, {.i64=INTERPOLATE_1D_COSINE}, INT_MIN, INT_MAX, FLAGS, "interp_mode" }, + { "cubic", "use values from the cubic interpolation", 0, AV_OPT_TYPE_CONST, {.i64=INTERPOLATE_1D_CUBIC}, INT_MIN, INT_MAX, FLAGS, "interp_mode" }, + { "spline", "use values from the spline interpolation", 0, AV_OPT_TYPE_CONST, {.i64=INTERPOLATE_1D_SPLINE}, INT_MIN, INT_MAX, FLAGS, "interp_mode" }, + { NULL } +}; + +AVFILTER_DEFINE_CLASS(lut1d); + +static inline float interp_1d_nearest(const LUT1DContext *lut1d, + int idx, const float s) +{ + return lut1d->lut[idx][NEAR(s)]; +} + +#define NEXT1D(x) (FFMIN((int)(x) + 1, lut1d->lutsize - 1)) + +static inline float interp_1d_linear(const LUT1DContext *lut1d, + int idx, const float s) +{ + const int prev = PREV(s); + const int next = NEXT1D(s); + const float d = s - prev; + const float p = lut1d->lut[idx][prev]; + const float n = lut1d->lut[idx][next]; + + return lerpf(p, n, d); +} + +static inline float interp_1d_cosine(const LUT1DContext *lut1d, + int idx, const float s) +{ + const int prev = PREV(s); + const int next = NEXT1D(s); + const float d = s - prev; + const float p = lut1d->lut[idx][prev]; + const float n = lut1d->lut[idx][next]; + const float m = (1.f - cosf(d * M_PI)) * .5f; + + return lerpf(p, n, m); +} + +static inline float interp_1d_cubic(const LUT1DContext *lut1d, + int idx, const float s) +{ + const int prev = PREV(s); + const int next = NEXT1D(s); + const float mu = s - prev; + float a0, a1, a2, a3, mu2; + + float y0 = lut1d->lut[idx][FFMAX(prev - 1, 0)]; + float y1 = lut1d->lut[idx][prev]; + float y2 = lut1d->lut[idx][next]; + float y3 = lut1d->lut[idx][FFMIN(next + 1, lut1d->lutsize - 1)]; + + + mu2 = mu * mu; + a0 = y3 - y2 - y0 + y1; + a1 = y0 - y1 - a0; + a2 = y2 - y0; + a3 = y1; + + return a0 * mu * mu2 + a1 * mu2 + a2 * mu + a3; +} + +static inline float interp_1d_spline(const LUT1DContext *lut1d, + int idx, const float s) +{ + const int prev = PREV(s); + const int next = NEXT1D(s); + const float x = s - prev; + float c0, c1, c2, c3; + + float y0 = lut1d->lut[idx][FFMAX(prev - 1, 0)]; + float y1 = lut1d->lut[idx][prev]; + float y2 = lut1d->lut[idx][next]; + float y3 = lut1d->lut[idx][FFMIN(next + 1, lut1d->lutsize - 1)]; + + c0 = y1; + c1 = .5f * (y2 - y0); + c2 = y0 - 2.5f * y1 + 2.f * y2 - .5f * y3; + c3 = .5f * (y3 - y0) + 1.5f * (y1 - y2); + + return ((c3 * x + c2) * x + c1) * x + c0; +} + +#define DEFINE_INTERP_FUNC_PLANAR_1D(name, nbits, depth) \ +static int interp_1d_##nbits##_##name##_p##depth(AVFilterContext *ctx, \ + void *arg, int jobnr, \ + int nb_jobs) \ +{ \ + int x, y; \ + const LUT1DContext *lut1d = ctx->priv; \ + const ThreadData *td = arg; \ + const AVFrame *in = td->in; \ + const AVFrame *out = td->out; \ + const int direct = out == in; \ + const int slice_start = (in->height * jobnr ) / nb_jobs; \ + const int slice_end = (in->height * (jobnr+1)) / nb_jobs; \ + uint8_t *grow = out->data[0] + slice_start * out->linesize[0]; \ + uint8_t *brow = out->data[1] + slice_start * out->linesize[1]; \ + uint8_t *rrow = out->data[2] + slice_start * out->linesize[2]; \ + uint8_t *arow = out->data[3] + slice_start * out->linesize[3]; \ + const uint8_t *srcgrow = in->data[0] + slice_start * in->linesize[0]; \ + const uint8_t *srcbrow = in->data[1] + slice_start * in->linesize[1]; \ + const uint8_t *srcrrow = in->data[2] + slice_start * in->linesize[2]; \ + const uint8_t *srcarow = in->data[3] + slice_start * in->linesize[3]; \ + const float factor = (1 << depth) - 1; \ + const float scale_r = (lut1d->scale.r / factor) * (lut1d->lutsize - 1); \ + const float scale_g = (lut1d->scale.g / factor) * (lut1d->lutsize - 1); \ + const float scale_b = (lut1d->scale.b / factor) * (lut1d->lutsize - 1); \ + \ + for (y = slice_start; y < slice_end; y++) { \ + uint##nbits##_t *dstg = (uint##nbits##_t *)grow; \ + uint##nbits##_t *dstb = (uint##nbits##_t *)brow; \ + uint##nbits##_t *dstr = (uint##nbits##_t *)rrow; \ + uint##nbits##_t *dsta = (uint##nbits##_t *)arow; \ + const uint##nbits##_t *srcg = (const uint##nbits##_t *)srcgrow; \ + const uint##nbits##_t *srcb = (const uint##nbits##_t *)srcbrow; \ + const uint##nbits##_t *srcr = (const uint##nbits##_t *)srcrrow; \ + const uint##nbits##_t *srca = (const uint##nbits##_t *)srcarow; \ + for (x = 0; x < in->width; x++) { \ + float r = srcr[x] * scale_r; \ + float g = srcg[x] * scale_g; \ + float b = srcb[x] * scale_b; \ + r = interp_1d_##name(lut1d, 0, r); \ + g = interp_1d_##name(lut1d, 1, g); \ + b = interp_1d_##name(lut1d, 2, b); \ + dstr[x] = av_clip_uintp2(r * factor, depth); \ + dstg[x] = av_clip_uintp2(g * factor, depth); \ + dstb[x] = av_clip_uintp2(b * factor, depth); \ + if (!direct && in->linesize[3]) \ + dsta[x] = srca[x]; \ + } \ + grow += out->linesize[0]; \ + brow += out->linesize[1]; \ + rrow += out->linesize[2]; \ + arow += out->linesize[3]; \ + srcgrow += in->linesize[0]; \ + srcbrow += in->linesize[1]; \ + srcrrow += in->linesize[2]; \ + srcarow += in->linesize[3]; \ + } \ + return 0; \ +} + +DEFINE_INTERP_FUNC_PLANAR_1D(nearest, 8, 8) +DEFINE_INTERP_FUNC_PLANAR_1D(linear, 8, 8) +DEFINE_INTERP_FUNC_PLANAR_1D(cosine, 8, 8) +DEFINE_INTERP_FUNC_PLANAR_1D(cubic, 8, 8) +DEFINE_INTERP_FUNC_PLANAR_1D(spline, 8, 8) + +DEFINE_INTERP_FUNC_PLANAR_1D(nearest, 16, 9) +DEFINE_INTERP_FUNC_PLANAR_1D(linear, 16, 9) +DEFINE_INTERP_FUNC_PLANAR_1D(cosine, 16, 9) +DEFINE_INTERP_FUNC_PLANAR_1D(cubic, 16, 9) +DEFINE_INTERP_FUNC_PLANAR_1D(spline, 16, 9) + +DEFINE_INTERP_FUNC_PLANAR_1D(nearest, 16, 10) +DEFINE_INTERP_FUNC_PLANAR_1D(linear, 16, 10) +DEFINE_INTERP_FUNC_PLANAR_1D(cosine, 16, 10) +DEFINE_INTERP_FUNC_PLANAR_1D(cubic, 16, 10) +DEFINE_INTERP_FUNC_PLANAR_1D(spline, 16, 10) + +DEFINE_INTERP_FUNC_PLANAR_1D(nearest, 16, 12) +DEFINE_INTERP_FUNC_PLANAR_1D(linear, 16, 12) +DEFINE_INTERP_FUNC_PLANAR_1D(cosine, 16, 12) +DEFINE_INTERP_FUNC_PLANAR_1D(cubic, 16, 12) +DEFINE_INTERP_FUNC_PLANAR_1D(spline, 16, 12) + +DEFINE_INTERP_FUNC_PLANAR_1D(nearest, 16, 14) +DEFINE_INTERP_FUNC_PLANAR_1D(linear, 16, 14) +DEFINE_INTERP_FUNC_PLANAR_1D(cosine, 16, 14) +DEFINE_INTERP_FUNC_PLANAR_1D(cubic, 16, 14) +DEFINE_INTERP_FUNC_PLANAR_1D(spline, 16, 14) + +DEFINE_INTERP_FUNC_PLANAR_1D(nearest, 16, 16) +DEFINE_INTERP_FUNC_PLANAR_1D(linear, 16, 16) +DEFINE_INTERP_FUNC_PLANAR_1D(cosine, 16, 16) +DEFINE_INTERP_FUNC_PLANAR_1D(cubic, 16, 16) +DEFINE_INTERP_FUNC_PLANAR_1D(spline, 16, 16) + +#define DEFINE_INTERP_FUNC_1D(name, nbits) \ +static int interp_1d_##nbits##_##name(AVFilterContext *ctx, void *arg, \ + int jobnr, int nb_jobs) \ +{ \ + int x, y; \ + const LUT1DContext *lut1d = ctx->priv; \ + const ThreadData *td = arg; \ + const AVFrame *in = td->in; \ + const AVFrame *out = td->out; \ + const int direct = out == in; \ + const int step = lut1d->step; \ + const uint8_t r = lut1d->rgba_map[R]; \ + const uint8_t g = lut1d->rgba_map[G]; \ + const uint8_t b = lut1d->rgba_map[B]; \ + const uint8_t a = lut1d->rgba_map[A]; \ + const int slice_start = (in->height * jobnr ) / nb_jobs; \ + const int slice_end = (in->height * (jobnr+1)) / nb_jobs; \ + uint8_t *dstrow = out->data[0] + slice_start * out->linesize[0]; \ + const uint8_t *srcrow = in ->data[0] + slice_start * in ->linesize[0]; \ + const float factor = (1 << nbits) - 1; \ + const float scale_r = (lut1d->scale.r / factor) * (lut1d->lutsize - 1); \ + const float scale_g = (lut1d->scale.g / factor) * (lut1d->lutsize - 1); \ + const float scale_b = (lut1d->scale.b / factor) * (lut1d->lutsize - 1); \ + \ + for (y = slice_start; y < slice_end; y++) { \ + uint##nbits##_t *dst = (uint##nbits##_t *)dstrow; \ + const uint##nbits##_t *src = (const uint##nbits##_t *)srcrow; \ + for (x = 0; x < in->width * step; x += step) { \ + float rr = src[x + r] * scale_r; \ + float gg = src[x + g] * scale_g; \ + float bb = src[x + b] * scale_b; \ + rr = interp_1d_##name(lut1d, 0, rr); \ + gg = interp_1d_##name(lut1d, 1, gg); \ + bb = interp_1d_##name(lut1d, 2, bb); \ + dst[x + r] = av_clip_uint##nbits(rr * factor); \ + dst[x + g] = av_clip_uint##nbits(gg * factor); \ + dst[x + b] = av_clip_uint##nbits(bb * factor); \ + if (!direct && step == 4) \ + dst[x + a] = src[x + a]; \ + } \ + dstrow += out->linesize[0]; \ + srcrow += in ->linesize[0]; \ + } \ + return 0; \ +} + +DEFINE_INTERP_FUNC_1D(nearest, 8) +DEFINE_INTERP_FUNC_1D(linear, 8) +DEFINE_INTERP_FUNC_1D(cosine, 8) +DEFINE_INTERP_FUNC_1D(cubic, 8) +DEFINE_INTERP_FUNC_1D(spline, 8) + +DEFINE_INTERP_FUNC_1D(nearest, 16) +DEFINE_INTERP_FUNC_1D(linear, 16) +DEFINE_INTERP_FUNC_1D(cosine, 16) +DEFINE_INTERP_FUNC_1D(cubic, 16) +DEFINE_INTERP_FUNC_1D(spline, 16) + +static int config_input_1d(AVFilterLink *inlink) +{ + int depth, is16bit = 0, planar = 0; + LUT1DContext *lut1d = inlink->dst->priv; + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format); + + depth = desc->comp[0].depth; + + switch (inlink->format) { + case AV_PIX_FMT_RGB48: + case AV_PIX_FMT_BGR48: + case AV_PIX_FMT_RGBA64: + case AV_PIX_FMT_BGRA64: + is16bit = 1; + break; + case AV_PIX_FMT_GBRP9: + case AV_PIX_FMT_GBRP10: + case AV_PIX_FMT_GBRP12: + case AV_PIX_FMT_GBRP14: + case AV_PIX_FMT_GBRP16: + case AV_PIX_FMT_GBRAP10: + case AV_PIX_FMT_GBRAP12: + case AV_PIX_FMT_GBRAP16: + is16bit = 1; + case AV_PIX_FMT_GBRP: + case AV_PIX_FMT_GBRAP: + planar = 1; + break; + } + + ff_fill_rgba_map(lut1d->rgba_map, inlink->format); + lut1d->step = av_get_padded_bits_per_pixel(desc) >> (3 + is16bit); + +#define SET_FUNC_1D(name) do { \ + if (planar) { \ + switch (depth) { \ + case 8: lut1d->interp = interp_1d_8_##name##_p8; break; \ + case 9: lut1d->interp = interp_1d_16_##name##_p9; break; \ + case 10: lut1d->interp = interp_1d_16_##name##_p10; break; \ + case 12: lut1d->interp = interp_1d_16_##name##_p12; break; \ + case 14: lut1d->interp = interp_1d_16_##name##_p14; break; \ + case 16: lut1d->interp = interp_1d_16_##name##_p16; break; \ + } \ + } else if (is16bit) { lut1d->interp = interp_1d_16_##name; \ + } else { lut1d->interp = interp_1d_8_##name; } \ +} while (0) + + switch (lut1d->interpolation) { + case INTERPOLATE_1D_NEAREST: SET_FUNC_1D(nearest); break; + case INTERPOLATE_1D_LINEAR: SET_FUNC_1D(linear); break; + case INTERPOLATE_1D_COSINE: SET_FUNC_1D(cosine); break; + case INTERPOLATE_1D_CUBIC: SET_FUNC_1D(cubic); break; + case INTERPOLATE_1D_SPLINE: SET_FUNC_1D(spline); break; + default: + av_assert0(0); + } + + return 0; +} + +static av_cold int lut1d_init(AVFilterContext *ctx) +{ + int ret; + FILE *f; + const char *ext; + LUT1DContext *lut1d = ctx->priv; + + lut1d->scale.r = lut1d->scale.g = lut1d->scale.b = 1.f; + + if (!lut1d->file) { + set_identity_matrix_1d(lut1d, 32); + return 0; + } + + f = fopen(lut1d->file, "r"); + if (!f) { + ret = AVERROR(errno); + av_log(ctx, AV_LOG_ERROR, "%s: %s\n", lut1d->file, av_err2str(ret)); + return ret; + } + + ext = strrchr(lut1d->file, '.'); + if (!ext) { + av_log(ctx, AV_LOG_ERROR, "Unable to guess the format from the extension\n"); + ret = AVERROR_INVALIDDATA; + goto end; + } + ext++; + + if (!av_strcasecmp(ext, "cube") || !av_strcasecmp(ext, "1dlut")) { + ret = parse_cube_1d(ctx, f); + } else if (!av_strcasecmp(ext, "csp")) { + ret = parse_cinespace_1d(ctx, f); + } else { + av_log(ctx, AV_LOG_ERROR, "Unrecognized '.%s' file type\n", ext); + ret = AVERROR(EINVAL); + } + + if (!ret && !lut1d->lutsize) { + av_log(ctx, AV_LOG_ERROR, "1D LUT is empty\n"); + ret = AVERROR_INVALIDDATA; + } + +end: + fclose(f); + return ret; +} + +static AVFrame *apply_1d_lut(AVFilterLink *inlink, AVFrame *in) +{ + AVFilterContext *ctx = inlink->dst; + LUT1DContext *lut1d = ctx->priv; + AVFilterLink *outlink = inlink->dst->outputs[0]; + AVFrame *out; + ThreadData td; + + if (av_frame_is_writable(in)) { + out = in; + } else { + out = ff_get_video_buffer(outlink, outlink->w, outlink->h); + if (!out) { + av_frame_free(&in); + return NULL; + } + av_frame_copy_props(out, in); + } + + td.in = in; + td.out = out; + ctx->internal->execute(ctx, lut1d->interp, &td, NULL, FFMIN(outlink->h, ff_filter_get_nb_threads(ctx))); + + if (out != in) + av_frame_free(&in); + + return out; +} + +static int filter_frame_1d(AVFilterLink *inlink, AVFrame *in) +{ + AVFilterLink *outlink = inlink->dst->outputs[0]; + AVFrame *out = apply_1d_lut(inlink, in); + if (!out) + return AVERROR(ENOMEM); + return ff_filter_frame(outlink, out); +} + +static const AVFilterPad lut1d_inputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + .filter_frame = filter_frame_1d, + .config_props = config_input_1d, + }, + { NULL } +}; + +static const AVFilterPad lut1d_outputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + }, + { NULL } +}; + +AVFilter ff_vf_lut1d = { + .name = "lut1d", + .description = NULL_IF_CONFIG_SMALL("Adjust colors using a 1D LUT."), + .priv_size = sizeof(LUT1DContext), + .init = lut1d_init, + .query_formats = query_formats, + .inputs = lut1d_inputs, + .outputs = lut1d_outputs, + .priv_class = &lut1d_class, + .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS, +}; +#endif diff --git a/libavfilter/vf_maskedclamp.c b/libavfilter/vf_maskedclamp.c index 9812e0853..16444e9de 100644 --- a/libavfilter/vf_maskedclamp.c +++ b/libavfilter/vf_maskedclamp.c @@ -30,6 +30,10 @@ #define OFFSET(x) offsetof(MaskedClampContext, x) #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM +typedef struct ThreadData { + AVFrame *b, *o, *m, *d; +} ThreadData; + typedef struct MaskedClampContext { const AVClass *class; @@ -43,11 +47,7 @@ typedef struct MaskedClampContext { int depth; FFFrameSync fs; - void (*maskedclamp)(const uint8_t *bsrc, const uint8_t *osrc, - const uint8_t *msrc, uint8_t *dst, - ptrdiff_t blinesize, ptrdiff_t darklinesize, - ptrdiff_t brightlinesize, ptrdiff_t destlinesize, - int w, int h, int undershoot, int overshoot); + int (*maskedclamp)(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs); } MaskedClampContext; static const AVOption maskedclamp_options[] = { @@ -78,7 +78,7 @@ static int query_formats(AVFilterContext *ctx) AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRP9, AV_PIX_FMT_GBRP10, AV_PIX_FMT_GBRP12, AV_PIX_FMT_GBRP14, AV_PIX_FMT_GBRP16, AV_PIX_FMT_GBRAP, AV_PIX_FMT_GBRAP10, AV_PIX_FMT_GBRAP12, AV_PIX_FMT_GBRAP16, - AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY9, AV_PIX_FMT_GRAY10, AV_PIX_FMT_GRAY12, AV_PIX_FMT_GRAY16, + AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY9, AV_PIX_FMT_GRAY10, AV_PIX_FMT_GRAY12, AV_PIX_FMT_GRAY14, AV_PIX_FMT_GRAY16, AV_PIX_FMT_NONE }; @@ -103,92 +103,122 @@ static int process_frame(FFFrameSync *fs) if (!out) return AVERROR(ENOMEM); } else { - int p; + ThreadData td; out = ff_get_video_buffer(outlink, outlink->w, outlink->h); if (!out) return AVERROR(ENOMEM); av_frame_copy_props(out, base); - for (p = 0; p < s->nb_planes; p++) { - if (!((1 << p) & s->planes)) { - av_image_copy_plane(out->data[p], out->linesize[p], base->data[p], base->linesize[p], - s->linesize[p], s->height[p]); - continue; - } + td.b = base; + td.o = dark; + td.m = bright; + td.d = out; - s->maskedclamp(base->data[p], dark->data[p], - bright->data[p], out->data[p], - base->linesize[p], dark->linesize[p], - bright->linesize[p], out->linesize[p], - s->width[p], s->height[p], - s->undershoot, s->overshoot); - } + ctx->internal->execute(ctx, s->maskedclamp, &td, NULL, FFMIN(s->height[0], + ff_filter_get_nb_threads(ctx))); } out->pts = av_rescale_q(s->fs.pts, s->fs.time_base, outlink->time_base); return ff_filter_frame(outlink, out); } -static void maskedclamp8(const uint8_t *bsrc, const uint8_t *darksrc, - const uint8_t *brightsrc, uint8_t *dst, - ptrdiff_t blinesize, ptrdiff_t darklinesize, - ptrdiff_t brightlinesize, ptrdiff_t dlinesize, - int w, int h, - int undershoot, int overshoot) +static int maskedclamp8(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) { - int x, y; + MaskedClampContext *s = ctx->priv; + ThreadData *td = arg; + int p; - for (y = 0; y < h; y++) { - for (x = 0; x < w; x++) { - if (bsrc[x] < darksrc[x] - undershoot) - dst[x] = darksrc[x] - undershoot; - else if (bsrc[x] > brightsrc[x] + overshoot) - dst[x] = brightsrc[x] + overshoot; - else - dst[x] = bsrc[x]; + for (p = 0; p < s->nb_planes; p++) { + const ptrdiff_t blinesize = td->b->linesize[p]; + const ptrdiff_t brightlinesize = td->m->linesize[p]; + const ptrdiff_t darklinesize = td->o->linesize[p]; + const ptrdiff_t dlinesize = td->d->linesize[p]; + const int w = s->width[p]; + const int h = s->height[p]; + const int slice_start = (h * jobnr) / nb_jobs; + const int slice_end = (h * (jobnr+1)) / nb_jobs; + const uint8_t *bsrc = td->b->data[p] + slice_start * blinesize; + const uint8_t *darksrc = td->o->data[p] + slice_start * darklinesize; + const uint8_t *brightsrc = td->m->data[p] + slice_start * brightlinesize; + uint8_t *dst = td->d->data[p] + slice_start * dlinesize; + const int undershoot = s->undershoot; + const int overshoot = s->overshoot; + int x, y; + + if (!((1 << p) & s->planes)) { + av_image_copy_plane(dst, dlinesize, bsrc, blinesize, + s->linesize[p], slice_end - slice_start); + continue; } - dst += dlinesize; - bsrc += blinesize; - darksrc += darklinesize; - brightsrc += brightlinesize; + for (y = slice_start; y < slice_end; y++) { + for (x = 0; x < w; x++) { + if (bsrc[x] < darksrc[x] - undershoot) + dst[x] = darksrc[x] - undershoot; + else if (bsrc[x] > brightsrc[x] + overshoot) + dst[x] = brightsrc[x] + overshoot; + else + dst[x] = bsrc[x]; + } + + dst += dlinesize; + bsrc += blinesize; + darksrc += darklinesize; + brightsrc += brightlinesize; + } } + + return 0; } -static void maskedclamp16(const uint8_t *bbsrc, const uint8_t *oosrc, - const uint8_t *mmsrc, uint8_t *ddst, - ptrdiff_t blinesize, ptrdiff_t darklinesize, - ptrdiff_t brightlinesize, ptrdiff_t dlinesize, - int w, int h, - int undershoot, int overshoot) +static int maskedclamp16(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) { - const uint16_t *bsrc = (const uint16_t *)bbsrc; - const uint16_t *darksrc = (const uint16_t *)oosrc; - const uint16_t *brightsrc = (const uint16_t *)mmsrc; - uint16_t *dst = (uint16_t *)ddst; - int x, y; + MaskedClampContext *s = ctx->priv; + ThreadData *td = arg; + int p; - dlinesize /= 2; - blinesize /= 2; - darklinesize /= 2; - brightlinesize /= 2; + for (p = 0; p < s->nb_planes; p++) { + const ptrdiff_t blinesize = td->b->linesize[p] / 2; + const ptrdiff_t brightlinesize = td->m->linesize[p] / 2; + const ptrdiff_t darklinesize = td->o->linesize[p] / 2; + const ptrdiff_t dlinesize = td->d->linesize[p] / 2; + const int w = s->width[p]; + const int h = s->height[p]; + const int slice_start = (h * jobnr) / nb_jobs; + const int slice_end = (h * (jobnr+1)) / nb_jobs; + const uint16_t *bsrc = (const uint16_t *)td->b->data[p] + slice_start * blinesize; + const uint16_t *darksrc = (const uint16_t *)td->o->data[p] + slice_start * darklinesize; + const uint16_t *brightsrc = (const uint16_t *)td->m->data[p] + slice_start * brightlinesize; + uint16_t *dst = (uint16_t *)td->d->data[p] + slice_start * dlinesize; + const int undershoot = s->undershoot; + const int overshoot = s->overshoot; + int x, y; - for (y = 0; y < h; y++) { - for (x = 0; x < w; x++) { - if (bsrc[x] < darksrc[x] - undershoot) - dst[x] = darksrc[x] - undershoot; - else if (bsrc[x] > brightsrc[x] + overshoot) - dst[x] = brightsrc[x] + overshoot; - else - dst[x] = bsrc[x]; + if (!((1 << p) & s->planes)) { + av_image_copy_plane((uint8_t *)dst, dlinesize, (const uint8_t *)bsrc, blinesize, + s->linesize[p], slice_end - slice_start); + continue; } - dst += dlinesize; - bsrc += blinesize; - darksrc += darklinesize; - brightsrc += brightlinesize; + for (y = slice_start; y < slice_end; y++) { + for (x = 0; x < w; x++) { + if (bsrc[x] < darksrc[x] - undershoot) + dst[x] = darksrc[x] - undershoot; + else if (bsrc[x] > brightsrc[x] + overshoot) + dst[x] = brightsrc[x] + overshoot; + else + dst[x] = bsrc[x]; + } + + dst += dlinesize; + bsrc += blinesize; + darksrc += darklinesize; + brightsrc += brightlinesize; + } } + + return 0; } static int config_input(AVFilterLink *inlink) @@ -249,7 +279,6 @@ static int config_output(AVFilterLink *outlink) outlink->w = base->w; outlink->h = base->h; - outlink->time_base = base->time_base; outlink->sample_aspect_ratio = base->sample_aspect_ratio; outlink->frame_rate = base->frame_rate; @@ -272,7 +301,10 @@ static int config_output(AVFilterLink *outlink) s->fs.opaque = s; s->fs.on_event = process_frame; - return ff_framesync_configure(&s->fs); + ret = ff_framesync_configure(&s->fs); + outlink->time_base = s->fs.time_base; + + return ret; } static int activate(AVFilterContext *ctx) @@ -324,5 +356,5 @@ AVFilter ff_vf_maskedclamp = { .inputs = maskedclamp_inputs, .outputs = maskedclamp_outputs, .priv_class = &maskedclamp_class, - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, + .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | AVFILTER_FLAG_SLICE_THREADS, }; diff --git a/libavfilter/vf_maskedmerge.c b/libavfilter/vf_maskedmerge.c index 86559abda..0c531935e 100644 --- a/libavfilter/vf_maskedmerge.c +++ b/libavfilter/vf_maskedmerge.c @@ -56,19 +56,62 @@ static int query_formats(AVFilterContext *ctx) AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRP9, AV_PIX_FMT_GBRP10, AV_PIX_FMT_GBRP12, AV_PIX_FMT_GBRP14, AV_PIX_FMT_GBRP16, AV_PIX_FMT_GBRAP, AV_PIX_FMT_GBRAP10, AV_PIX_FMT_GBRAP12, AV_PIX_FMT_GBRAP16, - AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY9, AV_PIX_FMT_GRAY10, AV_PIX_FMT_GRAY12, AV_PIX_FMT_GRAY16, + AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY9, AV_PIX_FMT_GRAY10, AV_PIX_FMT_GRAY12, AV_PIX_FMT_GRAY14, AV_PIX_FMT_GRAY16, AV_PIX_FMT_NONE }; return ff_set_common_formats(ctx, ff_make_format_list(pix_fmts)); } +typedef struct ThreadData { + AVFrame *base, *overlay, *mask; + AVFrame *out; +} ThreadData; + +static int filter_slice(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) +{ + MaskedMergeContext *s = ctx->priv; + ThreadData *td = arg; + AVFrame *base = td->base; + AVFrame *overlay = td->overlay; + AVFrame *mask = td->mask; + AVFrame *out = td->out; + int p; + + for (p = 0; p < s->nb_planes; p++) { + const int h = s->height[p]; + const int slice_start = (h * jobnr) / nb_jobs; + const int slice_end = (h * (jobnr+1)) / nb_jobs; + + if (!((1 << p) & s->planes)) { + av_image_copy_plane(out->data[p] + slice_start * out->linesize[p], + out->linesize[p], + base->data[p] + slice_start * base->linesize[p], + base->linesize[p], + s->linesize[p], slice_end - slice_start); + continue; + } + + s->maskedmerge(base->data[p] + slice_start * base->linesize[p], + overlay->data[p] + slice_start * overlay->linesize[p], + mask->data[p] + slice_start * mask->linesize[p], + out->data[p] + slice_start * out->linesize[p], + base->linesize[p], overlay->linesize[p], + mask->linesize[p], out->linesize[p], + s->width[p], slice_end - slice_start, + s->half, s->depth); + } + + return 0; +} + static int process_frame(FFFrameSync *fs) { AVFilterContext *ctx = fs->parent; MaskedMergeContext *s = fs->opaque; AVFilterLink *outlink = ctx->outputs[0]; AVFrame *out, *base, *overlay, *mask; + ThreadData td; int ret; if ((ret = ff_framesync_get_frame(&s->fs, 0, &base, 0)) < 0 || @@ -81,29 +124,19 @@ static int process_frame(FFFrameSync *fs) if (!out) return AVERROR(ENOMEM); } else { - int p; - out = ff_get_video_buffer(outlink, outlink->w, outlink->h); if (!out) return AVERROR(ENOMEM); av_frame_copy_props(out, base); - for (p = 0; p < s->nb_planes; p++) { - if (!((1 << p) & s->planes)) { - av_image_copy_plane(out->data[p], out->linesize[p], base->data[p], base->linesize[p], - s->linesize[p], s->height[p]); - continue; - } - - s->maskedmerge(base->data[p], overlay->data[p], - mask->data[p], out->data[p], - base->linesize[p], overlay->linesize[p], - mask->linesize[p], out->linesize[p], - s->width[p], s->height[p], - s->half, s->depth); - } + td.out = out; + td.base = base; + td.overlay = overlay; + td.mask = mask; + ctx->internal->execute(ctx, filter_slice, &td, NULL, + FFMIN(s->height[2], ff_filter_get_nb_threads(ctx))); } - out->pts = av_rescale_q(base->pts, s->fs.time_base, outlink->time_base); + out->pts = av_rescale_q(s->fs.pts, s->fs.time_base, outlink->time_base); return ff_filter_frame(outlink, out); } @@ -213,7 +246,6 @@ static int config_output(AVFilterLink *outlink) outlink->w = base->w; outlink->h = base->h; - outlink->time_base = base->time_base; outlink->sample_aspect_ratio = base->sample_aspect_ratio; outlink->frame_rate = base->frame_rate; @@ -239,7 +271,10 @@ static int config_output(AVFilterLink *outlink) s->fs.opaque = s; s->fs.on_event = process_frame; - return ff_framesync_configure(&s->fs); + ret = ff_framesync_configure(&s->fs); + outlink->time_base = s->fs.time_base; + + return ret; } static int activate(AVFilterContext *ctx) @@ -291,5 +326,5 @@ AVFilter ff_vf_maskedmerge = { .inputs = maskedmerge_inputs, .outputs = maskedmerge_outputs, .priv_class = &maskedmerge_class, - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, + .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | AVFILTER_FLAG_SLICE_THREADS, }; diff --git a/libavfilter/vf_maskfun.c b/libavfilter/vf_maskfun.c new file mode 100644 index 000000000..a8c6466d2 --- /dev/null +++ b/libavfilter/vf_maskfun.c @@ -0,0 +1,279 @@ +/* + * Copyright (c) 2018 Paul B Mahol + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/imgutils.h" +#include "libavutil/pixdesc.h" +#include "libavutil/opt.h" +#include "avfilter.h" +#include "formats.h" +#include "internal.h" +#include "video.h" + +typedef struct MaskFunContext { + const AVClass *class; + + int low, high; + int planes; + int fill; + int sum; + + int linesize[4]; + int width[4], height[4]; + int nb_planes; + int depth; + int max; + uint64_t max_sum; + + AVFrame *empty; + int (*getsum)(AVFilterContext *ctx, AVFrame *out); + int (*maskfun)(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs); +} MaskFunContext; + +#define OFFSET(x) offsetof(MaskFunContext, x) +#define VF AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM + +static const AVOption maskfun_options[] = { + { "low", "set low threshold", OFFSET(low), AV_OPT_TYPE_INT, {.i64=10}, 0, UINT16_MAX, VF }, + { "high", "set high threshold", OFFSET(high), AV_OPT_TYPE_INT, {.i64=10}, 0, UINT16_MAX, VF }, + { "planes", "set planes", OFFSET(planes), AV_OPT_TYPE_INT, {.i64=0xF}, 0, 0xF, VF }, + { "fill", "set fill value", OFFSET(fill), AV_OPT_TYPE_INT, {.i64=0}, 0, UINT16_MAX, VF }, + { "sum", "set sum value", OFFSET(sum), AV_OPT_TYPE_INT, {.i64=10}, 0, UINT16_MAX, VF }, + { NULL } +}; + +AVFILTER_DEFINE_CLASS(maskfun); + +static int query_formats(AVFilterContext *ctx) +{ + static const enum AVPixelFormat pix_fmts[] = { + AV_PIX_FMT_YUVA444P, AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUV440P, + AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_YUVJ440P, + AV_PIX_FMT_YUVA422P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUVA420P, AV_PIX_FMT_YUV420P, + AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUVJ420P, + AV_PIX_FMT_YUVJ411P, AV_PIX_FMT_YUV411P, AV_PIX_FMT_YUV410P, + AV_PIX_FMT_YUV420P9, AV_PIX_FMT_YUV422P9, AV_PIX_FMT_YUV444P9, + AV_PIX_FMT_YUV420P10, AV_PIX_FMT_YUV422P10, AV_PIX_FMT_YUV444P10, + AV_PIX_FMT_YUV420P12, AV_PIX_FMT_YUV422P12, AV_PIX_FMT_YUV444P12, AV_PIX_FMT_YUV440P12, + AV_PIX_FMT_YUV420P14, AV_PIX_FMT_YUV422P14, AV_PIX_FMT_YUV444P14, + AV_PIX_FMT_YUV420P16, AV_PIX_FMT_YUV422P16, AV_PIX_FMT_YUV444P16, + AV_PIX_FMT_YUVA420P9, AV_PIX_FMT_YUVA422P9, AV_PIX_FMT_YUVA444P9, + AV_PIX_FMT_YUVA420P10, AV_PIX_FMT_YUVA422P10, AV_PIX_FMT_YUVA444P10, + AV_PIX_FMT_YUVA420P16, AV_PIX_FMT_YUVA422P16, AV_PIX_FMT_YUVA444P16, + AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRP9, AV_PIX_FMT_GBRP10, + AV_PIX_FMT_GBRP12, AV_PIX_FMT_GBRP14, AV_PIX_FMT_GBRP16, + AV_PIX_FMT_GBRAP, AV_PIX_FMT_GBRAP10, AV_PIX_FMT_GBRAP12, AV_PIX_FMT_GBRAP16, + AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY9, AV_PIX_FMT_GRAY10, AV_PIX_FMT_GRAY12, AV_PIX_FMT_GRAY14, AV_PIX_FMT_GRAY16, + AV_PIX_FMT_NONE + }; + + return ff_set_common_formats(ctx, ff_make_format_list(pix_fmts)); +} + +static int filter_frame(AVFilterLink *inlink, AVFrame *frame) +{ + AVFilterContext *ctx = inlink->dst; + MaskFunContext *s = ctx->priv; + AVFilterLink *outlink = ctx->outputs[0]; + + if (s->getsum(ctx, frame)) { + AVFrame *out = av_frame_clone(s->empty); + + if (!out) { + av_frame_free(&frame); + return AVERROR(ENOMEM); + } + out->pts = frame->pts; + av_frame_free(&frame); + + return ff_filter_frame(outlink, out); + } + + ctx->internal->execute(ctx, s->maskfun, frame, NULL, + FFMIN(s->height[1], ff_filter_get_nb_threads(ctx))); + + return ff_filter_frame(outlink, frame); +} + +#define GETSUM(name, type, div) \ +static int getsum##name(AVFilterContext *ctx, AVFrame *out) \ +{ \ + MaskFunContext *s = ctx->priv; \ + uint64_t sum = 0; \ + int p; \ + \ + for (p = 0; p < s->nb_planes; p++) { \ + const int linesize = out->linesize[p] / div; \ + const int w = s->width[p]; \ + const int h = s->height[p]; \ + type *dst = (type *)out->data[p]; \ + \ + if (!((1 << p) & s->planes)) \ + continue; \ + \ + for (int y = 0; y < h; y++) { \ + for (int x = 0; x < w; x++) \ + sum += dst[x]; \ + if (sum >= s->max_sum) \ + return 1; \ + dst += linesize; \ + } \ + } \ + \ + return 0; \ +} + +GETSUM(8, uint8_t, 1) +GETSUM(16, uint16_t, 2) + +#define MASKFUN(name, type, div) \ +static int maskfun##name(AVFilterContext *ctx, void *arg, \ + int jobnr, int nb_jobs) \ +{ \ + MaskFunContext *s = ctx->priv; \ + AVFrame *out = arg; \ + const int low = s->low; \ + const int high = s->high; \ + const int max = s->max; \ + int p; \ + \ + for (p = 0; p < s->nb_planes; p++) { \ + const int linesize = out->linesize[p] / div; \ + const int w = s->width[p]; \ + const int h = s->height[p]; \ + const int slice_start = (h * jobnr) / nb_jobs; \ + const int slice_end = (h * (jobnr+1)) / nb_jobs; \ + type *dst = (type *)out->data[p] + slice_start * linesize; \ + \ + if (!((1 << p) & s->planes)) \ + continue; \ + \ + for (int y = slice_start; y < slice_end; y++) { \ + for (int x = 0; x < w; x++) { \ + if (dst[x] <= low) \ + dst[x] = 0; \ + else if (dst[x] > high) \ + dst[x] = max; \ + } \ + \ + dst += linesize; \ + } \ + } \ + \ + return 0; \ +} + +MASKFUN(8, uint8_t, 1) +MASKFUN(16, uint16_t, 2) + +static int config_input(AVFilterLink *inlink) +{ + AVFilterContext *ctx = inlink->dst; + MaskFunContext *s = ctx->priv; + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format); + int vsub, hsub, ret; + + s->nb_planes = av_pix_fmt_count_planes(inlink->format); + + if ((ret = av_image_fill_linesizes(s->linesize, inlink->format, inlink->w)) < 0) + return ret; + + hsub = desc->log2_chroma_w; + vsub = desc->log2_chroma_h; + s->height[1] = s->height[2] = AV_CEIL_RSHIFT(inlink->h, vsub); + s->height[0] = s->height[3] = inlink->h; + s->width[1] = s->width[2] = AV_CEIL_RSHIFT(inlink->w, hsub); + s->width[0] = s->width[3] = inlink->w; + + s->depth = desc->comp[0].depth; + s->max = (1 << s->depth) - 1; + s->fill = FFMIN(s->fill, s->max); + + if (s->depth == 8) { + s->maskfun = maskfun8; + s->getsum = getsum8; + } else { + s->maskfun = maskfun16; + s->getsum = getsum16; + } + + s->empty = ff_get_video_buffer(inlink, inlink->w, inlink->h); + if (!s->empty) + return AVERROR(ENOMEM); + + if (s->depth == 8) { + for (int p = 0; p < s->nb_planes; p++) { + uint8_t *dst = s->empty->data[p]; + + for (int y = 0; y < s->height[p]; y++) { + memset(dst, s->fill, s->width[p]); + dst += s->empty->linesize[p]; + } + } + } else { + for (int p = 0; p < s->nb_planes; p++) { + uint16_t *dst = (uint16_t *)s->empty->data[p]; + + for (int y = 0; y < s->height[p]; y++) { + for (int x = 0; x < s->width[p]; x++) + dst[x] = s->fill; + dst += s->empty->linesize[p] / 2; + } + } + } + + s->max_sum = 0; + for (int p = 0; p < s->nb_planes; p++) { + if (!((1 << p) & s->planes)) + continue; + s->max_sum += (uint64_t)s->sum * s->width[p] * s->height[p]; + } + + return 0; +} + +static const AVFilterPad maskfun_inputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + .filter_frame = filter_frame, + .config_props = config_input, + .needs_writable = 1, + }, + { NULL } +}; + +static const AVFilterPad maskfun_outputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + }, + { NULL } +}; + +AVFilter ff_vf_maskfun = { + .name = "maskfun", + .description = NULL_IF_CONFIG_SMALL("Create Mask."), + .priv_size = sizeof(MaskFunContext), + .query_formats = query_formats, + .inputs = maskfun_inputs, + .outputs = maskfun_outputs, + .priv_class = &maskfun_class, + .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS, +}; diff --git a/libavfilter/vf_midequalizer.c b/libavfilter/vf_midequalizer.c index c03814a24..38d2193b2 100644 --- a/libavfilter/vf_midequalizer.c +++ b/libavfilter/vf_midequalizer.c @@ -66,7 +66,7 @@ static int query_formats(AVFilterContext *ctx) AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUVJ411P, AV_PIX_FMT_YUV411P, AV_PIX_FMT_YUV410P, AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRAP, - AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY9, AV_PIX_FMT_GRAY10, AV_PIX_FMT_GRAY12, + AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY9, AV_PIX_FMT_GRAY10, AV_PIX_FMT_GRAY12, AV_PIX_FMT_GRAY14, AV_PIX_FMT_YUV420P9, AV_PIX_FMT_YUV422P9, AV_PIX_FMT_YUV444P9, AV_PIX_FMT_YUV420P10, AV_PIX_FMT_YUV422P10, AV_PIX_FMT_YUV444P10, AV_PIX_FMT_YUV420P12, AV_PIX_FMT_YUV422P12, AV_PIX_FMT_YUV444P12, @@ -122,7 +122,7 @@ static int process_frame(FFFrameSync *fs) s->cchange, s->histogram_size); } } - out->pts = av_rescale_q(in0->pts, s->fs.time_base, outlink->time_base); + out->pts = av_rescale_q(s->fs.pts, s->fs.time_base, outlink->time_base); return ff_filter_frame(outlink, out); } @@ -307,7 +307,6 @@ static int config_output(AVFilterLink *outlink) outlink->w = in0->w; outlink->h = in0->h; - outlink->time_base = in0->time_base; outlink->sample_aspect_ratio = in0->sample_aspect_ratio; outlink->frame_rate = in0->frame_rate; @@ -326,7 +325,10 @@ static int config_output(AVFilterLink *outlink) s->fs.opaque = s; s->fs.on_event = process_frame; - return ff_framesync_configure(&s->fs); + ret = ff_framesync_configure(&s->fs); + outlink->time_base = s->fs.time_base; + + return ret; } static int activate(AVFilterContext *ctx) diff --git a/libavfilter/vf_minterpolate.c b/libavfilter/vf_minterpolate.c index d53431593..b0bb238ad 100644 --- a/libavfilter/vf_minterpolate.c +++ b/libavfilter/vf_minterpolate.c @@ -26,11 +26,11 @@ #include "libavutil/motion_vector.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" -#include "libavutil/pixelutils.h" #include "avfilter.h" #include "formats.h" #include "internal.h" #include "video.h" +#include "scene_sad.h" #define ME_MODE_BIDIR 0 #define ME_MODE_BILAT 1 @@ -188,7 +188,7 @@ typedef struct MIContext { int scd_method; int scene_changed; - av_pixelutils_sad_fn sad; + ff_scene_sad_fn sad; double prev_mafd; double scd_threshold; @@ -383,7 +383,7 @@ static int config_input(AVFilterLink *inlink) } if (mi_ctx->scd_method == SCD_METHOD_FDIFF) { - mi_ctx->sad = av_pixelutils_get_sad_fn(3, 3, 2, mi_ctx); + mi_ctx->sad = ff_scene_sad_get_fn(8); if (!mi_ctx->sad) return AVERROR(EINVAL); } @@ -826,19 +826,15 @@ static int inject_frame(AVFilterLink *inlink, AVFrame *avf_in) static int detect_scene_change(MIContext *mi_ctx) { AVMotionEstContext *me_ctx = &mi_ctx->me_ctx; - int x, y; - int linesize = me_ctx->linesize; uint8_t *p1 = mi_ctx->frames[1].avf->data[0]; + ptrdiff_t linesize1 = mi_ctx->frames[1].avf->linesize[0]; uint8_t *p2 = mi_ctx->frames[2].avf->data[0]; + ptrdiff_t linesize2 = mi_ctx->frames[2].avf->linesize[0]; if (mi_ctx->scd_method == SCD_METHOD_FDIFF) { double ret = 0, mafd, diff; - int64_t sad; - - for (sad = y = 0; y < me_ctx->height; y += 8) - for (x = 0; x < linesize; x += 8) - sad += mi_ctx->sad(p1 + x + y * linesize, linesize, p2 + x + y * linesize, linesize); - + uint64_t sad; + mi_ctx->sad(p1, linesize1, p2, linesize2, me_ctx->width, me_ctx->height, &sad); emms_c(); mafd = (double) sad / (me_ctx->height * me_ctx->width * 3); diff = fabs(mafd - mi_ctx->prev_mafd); @@ -1122,8 +1118,8 @@ static void interpolate(AVFilterLink *inlink, AVFrame *avf_out) for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { avf_out->data[plane][x + y * avf_out->linesize[plane]] = - alpha * mi_ctx->frames[2].avf->data[plane][x + y * mi_ctx->frames[2].avf->linesize[plane]] + - ((ALPHA_MAX - alpha) * mi_ctx->frames[1].avf->data[plane][x + y * mi_ctx->frames[1].avf->linesize[plane]] + 512) >> 10; + (alpha * mi_ctx->frames[2].avf->data[plane][x + y * mi_ctx->frames[2].avf->linesize[plane]] + + (ALPHA_MAX - alpha) * mi_ctx->frames[1].avf->data[plane][x + y * mi_ctx->frames[1].avf->linesize[plane]] + 512) >> 10; } } } diff --git a/libavfilter/vf_misc_vaapi.c b/libavfilter/vf_misc_vaapi.c index 30b808a99..54516d7e3 100644 --- a/libavfilter/vf_misc_vaapi.c +++ b/libavfilter/vf_misc_vaapi.c @@ -84,10 +84,9 @@ static int denoise_vaapi_build_filter_params(AVFilterContext *avctx) denoise.value = map(ctx->denoise, DENOISE_MIN, DENOISE_MAX, caps.range.min_value, caps.range.max_value); - ff_vaapi_vpp_make_param_buffers(avctx, VAProcFilterParameterBufferType, - &denoise, sizeof(denoise), 1); - - return 0; + return ff_vaapi_vpp_make_param_buffers(avctx, + VAProcFilterParameterBufferType, + &denoise, sizeof(denoise), 1); } static int sharpness_vaapi_build_filter_params(AVFilterContext *avctx) @@ -116,11 +115,9 @@ static int sharpness_vaapi_build_filter_params(AVFilterContext *avctx) SHARPNESS_MIN, SHARPNESS_MAX, caps.range.min_value, caps.range.max_value); - ff_vaapi_vpp_make_param_buffers(avctx, - VAProcFilterParameterBufferType, - &sharpness, sizeof(sharpness), 1); - - return 0; + return ff_vaapi_vpp_make_param_buffers(avctx, + VAProcFilterParameterBufferType, + &sharpness, sizeof(sharpness), 1); } static int misc_vaapi_filter_frame(AVFilterLink *inlink, AVFrame *input_frame) @@ -129,9 +126,6 @@ static int misc_vaapi_filter_frame(AVFilterLink *inlink, AVFrame *input_frame) AVFilterLink *outlink = avctx->outputs[0]; VAAPIVPPContext *vpp_ctx = avctx->priv; AVFrame *output_frame = NULL; - VASurfaceID input_surface, output_surface; - VARectangle input_region; - VAProcPipelineParameterBuffer params; int err; @@ -142,10 +136,6 @@ static int misc_vaapi_filter_frame(AVFilterLink *inlink, AVFrame *input_frame) if (vpp_ctx->va_context == VA_INVALID_ID) return AVERROR(EINVAL); - input_surface = (VASurfaceID)(uintptr_t)input_frame->data[3]; - av_log(avctx, AV_LOG_DEBUG, "Using surface %#x for misc vpp input.\n", - input_surface); - output_frame = ff_get_video_buffer(outlink, vpp_ctx->output_width, vpp_ctx->output_height); if (!output_frame) { @@ -153,40 +143,24 @@ static int misc_vaapi_filter_frame(AVFilterLink *inlink, AVFrame *input_frame) goto fail; } - output_surface = (VASurfaceID)(uintptr_t)output_frame->data[3]; - av_log(avctx, AV_LOG_DEBUG, "Using surface %#x for misc vpp output.\n", - output_surface); - memset(¶ms, 0, sizeof(params)); - input_region = (VARectangle) { - .x = 0, - .y = 0, - .width = input_frame->width, - .height = input_frame->height, - }; + err = av_frame_copy_props(output_frame, input_frame); + if (err < 0) + return err; + + err = ff_vaapi_vpp_init_params(avctx, ¶ms, + input_frame, output_frame); + if (err < 0) + goto fail; if (vpp_ctx->nb_filter_buffers) { params.filters = &vpp_ctx->filter_buffers[0]; params.num_filters = vpp_ctx->nb_filter_buffers; } - params.surface = input_surface; - params.surface_region = &input_region; - params.surface_color_standard = - ff_vaapi_vpp_colour_standard(input_frame->colorspace); - params.output_region = NULL; - params.output_background_color = 0xff000000; - params.output_color_standard = params.surface_color_standard; - - params.pipeline_flags = 0; - params.filter_flags = VA_FRAME_PICTURE; - - err = ff_vaapi_vpp_render_picture(avctx, ¶ms, output_surface); + err = ff_vaapi_vpp_render_picture(avctx, ¶ms, output_frame); if (err < 0) goto fail; - err = av_frame_copy_props(output_frame, input_frame); - if (err < 0) - goto fail; av_frame_free(&input_frame); av_log(avctx, AV_LOG_DEBUG, "Filter output: %s, %ux%u (%"PRId64").\n", diff --git a/libavfilter/vf_mix.c b/libavfilter/vf_mix.c index 261ab066e..b5a282ad4 100644 --- a/libavfilter/vf_mix.c +++ b/libavfilter/vf_mix.c @@ -37,9 +37,14 @@ typedef struct MixContext { int nb_inputs; int duration; float *weights; + float scale; float wfactor; + int tmix; + int nb_frames; + int depth; + int max; int nb_planes; int linesize[4]; int height[4]; @@ -69,7 +74,9 @@ static av_cold int init(AVFilterContext *ctx) { MixContext *s = ctx->priv; char *p, *arg, *saveptr = NULL; - int i, ret; + int i, ret, last = 0; + + s->tmix = !strcmp(ctx->filter->name, "tmix"); s->frames = av_calloc(s->nb_inputs, sizeof(*s->frames)); if (!s->frames) @@ -79,17 +86,19 @@ static av_cold int init(AVFilterContext *ctx) if (!s->weights) return AVERROR(ENOMEM); - for (i = 0; i < s->nb_inputs; i++) { - AVFilterPad pad = { 0 }; + if (!s->tmix) { + for (i = 0; i < s->nb_inputs; i++) { + AVFilterPad pad = { 0 }; - pad.type = AVMEDIA_TYPE_VIDEO; - pad.name = av_asprintf("input%d", i); - if (!pad.name) - return AVERROR(ENOMEM); + pad.type = AVMEDIA_TYPE_VIDEO; + pad.name = av_asprintf("input%d", i); + if (!pad.name) + return AVERROR(ENOMEM); - if ((ret = ff_insert_inpad(ctx, i, &pad)) < 0) { - av_freep(&pad.name); - return ret; + if ((ret = ff_insert_inpad(ctx, i, &pad)) < 0) { + av_freep(&pad.name); + return ret; + } } } @@ -99,10 +108,80 @@ static av_cold int init(AVFilterContext *ctx) break; p = NULL; - sscanf(arg, "%f", &s->weights[i]); + av_sscanf(arg, "%f", &s->weights[i]); + s->wfactor += s->weights[i]; + last = i; + } + for (; i < s->nb_inputs; i++) { + s->weights[i] = s->weights[last]; s->wfactor += s->weights[i]; } - s->wfactor = 1 / s->wfactor; + if (s->scale == 0) { + s->wfactor = 1 / s->wfactor; + } else { + s->wfactor = s->scale; + } + + return 0; +} + +typedef struct ThreadData { + AVFrame **in, *out; +} ThreadData; + +static int mix_frames(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) +{ + MixContext *s = ctx->priv; + ThreadData *td = arg; + AVFrame **in = td->in; + AVFrame *out = td->out; + int i, p, x, y; + + if (s->depth <= 8) { + for (p = 0; p < s->nb_planes; p++) { + const int slice_start = (s->height[p] * jobnr) / nb_jobs; + const int slice_end = (s->height[p] * (jobnr+1)) / nb_jobs; + uint8_t *dst = out->data[p] + slice_start * out->linesize[p]; + + for (y = slice_start; y < slice_end; y++) { + for (x = 0; x < s->linesize[p]; x++) { + int val = 0; + + for (i = 0; i < s->nb_inputs; i++) { + uint8_t src = in[i]->data[p][y * in[i]->linesize[p] + x]; + + val += src * s->weights[i]; + } + + dst[x] = av_clip_uint8(val * s->wfactor); + } + + dst += out->linesize[p]; + } + } + } else { + for (p = 0; p < s->nb_planes; p++) { + const int slice_start = (s->height[p] * jobnr) / nb_jobs; + const int slice_end = (s->height[p] * (jobnr+1)) / nb_jobs; + uint16_t *dst = (uint16_t *)(out->data[p] + slice_start * out->linesize[p]); + + for (y = slice_start; y < slice_end; y++) { + for (x = 0; x < s->linesize[p] / 2; x++) { + int val = 0; + + for (i = 0; i < s->nb_inputs; i++) { + uint16_t src = AV_RN16(in[i]->data[p] + y * in[i]->linesize[p] + x * 2); + + val += src * s->weights[i]; + } + + dst[x] = av_clip(val * s->wfactor, 0, s->max); + } + + dst += out->linesize[p] / 2; + } + } + } return 0; } @@ -114,7 +193,8 @@ static int process_frame(FFFrameSync *fs) MixContext *s = fs->opaque; AVFrame **in = s->frames; AVFrame *out; - int i, p, ret, x, y; + ThreadData td; + int i, ret; for (i = 0; i < s->nb_inputs; i++) { if ((ret = ff_framesync_get_frame(&s->fs, i, &in[i], 0)) < 0) @@ -126,47 +206,9 @@ static int process_frame(FFFrameSync *fs) return AVERROR(ENOMEM); out->pts = av_rescale_q(s->fs.pts, s->fs.time_base, outlink->time_base); - if (s->depth <= 8) { - for (p = 0; p < s->nb_planes; p++) { - uint8_t *dst = out->data[p]; - - for (y = 0; y < s->height[p]; y++) { - for (x = 0; x < s->linesize[p]; x++) { - int val = 0; - - for (i = 0; i < s->nb_inputs; i++) { - uint8_t src = in[i]->data[p][y * s->linesize[p] + x]; - - val += src * s->weights[i]; - } - - dst[x] = val * s->wfactor; - } - - dst += out->linesize[p]; - } - } - } else { - for (p = 0; p < s->nb_planes; p++) { - uint16_t *dst = (uint16_t *)out->data[p]; - - for (y = 0; y < s->height[p]; y++) { - for (x = 0; x < s->linesize[p]; x++) { - int val = 0; - - for (i = 0; i < s->nb_inputs; i++) { - uint16_t src = AV_RN16(in[i]->data[p] + y * s->linesize[p] + x * 2); - - val += src * s->weights[i]; - } - - dst[x] = val * s->wfactor; - } - - dst += out->linesize[p] / 2; - } - } - } + td.in = in; + td.out = out; + ctx->internal->execute(ctx, mix_frames, &td, NULL, FFMIN(s->height[0], ff_filter_get_nb_threads(ctx))); return ff_filter_frame(outlink, out); } @@ -175,18 +217,20 @@ static int config_output(AVFilterLink *outlink) { AVFilterContext *ctx = outlink->src; MixContext *s = ctx->priv; - AVRational time_base = ctx->inputs[0]->time_base; AVRational frame_rate = ctx->inputs[0]->frame_rate; + AVRational sar = ctx->inputs[0]->sample_aspect_ratio; AVFilterLink *inlink = ctx->inputs[0]; int height = ctx->inputs[0]->h; int width = ctx->inputs[0]->w; FFFrameSyncIn *in; int i, ret; - for (i = 1; i < s->nb_inputs; i++) { - if (ctx->inputs[i]->h != height || ctx->inputs[i]->w != width) { - av_log(ctx, AV_LOG_ERROR, "Input %d size (%dx%d) does not match input %d size (%dx%d).\n", i, ctx->inputs[i]->w, ctx->inputs[i]->h, 0, width, height); - return AVERROR(EINVAL); + if (!s->tmix) { + for (i = 1; i < s->nb_inputs; i++) { + if (ctx->inputs[i]->h != height || ctx->inputs[i]->w != width) { + av_log(ctx, AV_LOG_ERROR, "Input %d size (%dx%d) does not match input %d size (%dx%d).\n", i, ctx->inputs[i]->w, ctx->inputs[i]->h, 0, width, height); + return AVERROR(EINVAL); + } } } @@ -195,11 +239,21 @@ static int config_output(AVFilterLink *outlink) return AVERROR_BUG; s->nb_planes = av_pix_fmt_count_planes(outlink->format); s->depth = s->desc->comp[0].depth; + s->max = (1 << s->depth) - 1; + + if ((ret = av_image_fill_linesizes(s->linesize, inlink->format, inlink->w)) < 0) + return ret; + + s->height[1] = s->height[2] = AV_CEIL_RSHIFT(inlink->h, s->desc->log2_chroma_h); + s->height[0] = s->height[3] = inlink->h; + + if (s->tmix) + return 0; outlink->w = width; outlink->h = height; - outlink->time_base = time_base; outlink->frame_rate = frame_rate; + outlink->sample_aspect_ratio = sar; if ((ret = ff_framesync_init(&s->fs, ctx, s->nb_inputs)) < 0) return ret; @@ -208,12 +262,6 @@ static int config_output(AVFilterLink *outlink) s->fs.opaque = s; s->fs.on_event = process_frame; - if ((ret = av_image_fill_linesizes(s->linesize, inlink->format, inlink->w)) < 0) - return ret; - - s->height[1] = s->height[2] = AV_CEIL_RSHIFT(inlink->h, s->desc->log2_chroma_h); - s->height[0] = s->height[3] = inlink->h; - for (i = 0; i < s->nb_inputs; i++) { AVFilterLink *inlink = ctx->inputs[i]; @@ -223,7 +271,10 @@ static int config_output(AVFilterLink *outlink) in[i].after = (s->duration == 1 || (s->duration == 2 && i == 0)) ? EXT_STOP : EXT_INFINITY; } - return ff_framesync_configure(&s->fs); + ret = ff_framesync_configure(&s->fs); + outlink->time_base = s->fs.time_base; + + return ret; } static av_cold void uninit(AVFilterContext *ctx) @@ -232,11 +283,16 @@ static av_cold void uninit(AVFilterContext *ctx) int i; ff_framesync_uninit(&s->fs); - av_freep(&s->frames); av_freep(&s->weights); - for (i = 0; i < ctx->nb_inputs; i++) - av_freep(&ctx->input_pads[i].name); + if (!s->tmix) { + for (i = 0; i < ctx->nb_inputs; i++) + av_freep(&ctx->input_pads[i].name); + } else { + for (i = 0; i < s->nb_frames; i++) + av_frame_free(&s->frames[i]); + } + av_freep(&s->frames); } static int activate(AVFilterContext *ctx) @@ -251,6 +307,7 @@ static int activate(AVFilterContext *ctx) static const AVOption mix_options[] = { { "inputs", "set number of inputs", OFFSET(nb_inputs), AV_OPT_TYPE_INT, {.i64=2}, 2, INT_MAX, .flags = FLAGS }, { "weights", "set weight for each input", OFFSET(weights_str), AV_OPT_TYPE_STRING, {.str="1 1"}, 0, 0, .flags = FLAGS }, + { "scale", "set scale", OFFSET(scale), AV_OPT_TYPE_FLOAT, {.dbl=0}, 0, INT16_MAX, .flags = FLAGS }, { "duration", "how to determine end of stream", OFFSET(duration), AV_OPT_TYPE_INT, {.i64=0}, 0, 2, .flags = FLAGS, "duration" }, { "longest", "Duration of longest input", 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, FLAGS, "duration" }, { "shortest", "Duration of shortest input", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, FLAGS, "duration" }, @@ -267,6 +324,7 @@ static const AVFilterPad outputs[] = { { NULL } }; +#if CONFIG_MIX_FILTER AVFILTER_DEFINE_CLASS(mix); AVFilter ff_vf_mix = { @@ -279,5 +337,82 @@ AVFilter ff_vf_mix = { .init = init, .uninit = uninit, .activate = activate, - .flags = AVFILTER_FLAG_DYNAMIC_INPUTS, + .flags = AVFILTER_FLAG_DYNAMIC_INPUTS | AVFILTER_FLAG_SLICE_THREADS, }; + +#endif /* CONFIG_MIX_FILTER */ + +#if CONFIG_TMIX_FILTER +static int tmix_filter_frame(AVFilterLink *inlink, AVFrame *in) +{ + AVFilterContext *ctx = inlink->dst; + AVFilterLink *outlink = ctx->outputs[0]; + MixContext *s = ctx->priv; + ThreadData td; + AVFrame *out; + + if (s->nb_inputs == 1) + return ff_filter_frame(outlink, in); + + if (s->nb_frames < s->nb_inputs) { + s->frames[s->nb_frames] = in; + s->nb_frames++; + if (s->nb_frames < s->nb_inputs) + return 0; + } else { + av_frame_free(&s->frames[0]); + memmove(&s->frames[0], &s->frames[1], sizeof(*s->frames) * (s->nb_inputs - 1)); + s->frames[s->nb_inputs - 1] = in; + } + + if (ctx->is_disabled) { + out = av_frame_clone(s->frames[0]); + if (!out) + return AVERROR(ENOMEM); + return ff_filter_frame(outlink, out); + } + + out = ff_get_video_buffer(outlink, outlink->w, outlink->h); + if (!out) + return AVERROR(ENOMEM); + out->pts = s->frames[0]->pts; + + td.out = out; + td.in = s->frames; + ctx->internal->execute(ctx, mix_frames, &td, NULL, FFMIN(s->height[0], ff_filter_get_nb_threads(ctx))); + + return ff_filter_frame(outlink, out); +} + +static const AVOption tmix_options[] = { + { "frames", "set number of successive frames to mix", OFFSET(nb_inputs), AV_OPT_TYPE_INT, {.i64=3}, 1, 128, .flags = FLAGS }, + { "weights", "set weight for each frame", OFFSET(weights_str), AV_OPT_TYPE_STRING, {.str="1 1 1"}, 0, 0, .flags = FLAGS }, + { "scale", "set scale", OFFSET(scale), AV_OPT_TYPE_FLOAT, {.dbl=0}, 0, INT16_MAX, .flags = FLAGS }, + { NULL }, +}; + +static const AVFilterPad inputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + .filter_frame = tmix_filter_frame, + }, + { NULL } +}; + +AVFILTER_DEFINE_CLASS(tmix); + +AVFilter ff_vf_tmix = { + .name = "tmix", + .description = NULL_IF_CONFIG_SMALL("Mix successive video frames."), + .priv_size = sizeof(MixContext), + .priv_class = &tmix_class, + .query_formats = query_formats, + .outputs = outputs, + .inputs = inputs, + .init = init, + .uninit = uninit, + .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | AVFILTER_FLAG_SLICE_THREADS, +}; + +#endif /* CONFIG_TMIX_FILTER */ diff --git a/libavfilter/vf_neighbor.c b/libavfilter/vf_neighbor.c index de4a12f04..e50d4b4ed 100644 --- a/libavfilter/vf_neighbor.c +++ b/libavfilter/vf_neighbor.c @@ -20,6 +20,7 @@ */ #include "libavutil/imgutils.h" +#include "libavutil/intreadwrite.h" #include "libavutil/pixdesc.h" #include "libavutil/opt.h" #include "avfilter.h" @@ -27,6 +28,10 @@ #include "internal.h" #include "video.h" +typedef struct ThreadData { + AVFrame *in, *out; +} ThreadData; + typedef struct NContext { const AVClass *class; int planeheight[4]; @@ -34,45 +39,45 @@ typedef struct NContext { int nb_planes; int threshold[4]; int coordinates; - uint8_t *buffer; + + int depth; + int max; + int bpc; void (*filter)(uint8_t *dst, const uint8_t *p1, int width, - int threshold, const uint8_t *coordinates[], int coord); + int threshold, const uint8_t *coordinates[], int coord, + int maxc); } NContext; static int query_formats(AVFilterContext *ctx) { static const enum AVPixelFormat pix_fmts[] = { - AV_PIX_FMT_YUVA444P, AV_PIX_FMT_YUVA422P, AV_PIX_FMT_YUVA420P, - AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_YUVJ440P, AV_PIX_FMT_YUVJ422P,AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUVJ411P, - AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUV440P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV411P, AV_PIX_FMT_YUV410P, - AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRAP, AV_PIX_FMT_GRAY8, AV_PIX_FMT_NONE + AV_PIX_FMT_YUVA444P, AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUV440P, + AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_YUVJ440P, + AV_PIX_FMT_YUVA422P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUVA420P, AV_PIX_FMT_YUV420P, + AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUVJ420P, + AV_PIX_FMT_YUVJ411P, AV_PIX_FMT_YUV411P, AV_PIX_FMT_YUV410P, + AV_PIX_FMT_YUV420P9, AV_PIX_FMT_YUV422P9, AV_PIX_FMT_YUV444P9, + AV_PIX_FMT_YUV420P10, AV_PIX_FMT_YUV422P10, AV_PIX_FMT_YUV444P10, + AV_PIX_FMT_YUV420P12, AV_PIX_FMT_YUV422P12, AV_PIX_FMT_YUV444P12, AV_PIX_FMT_YUV440P12, + AV_PIX_FMT_YUV420P14, AV_PIX_FMT_YUV422P14, AV_PIX_FMT_YUV444P14, + AV_PIX_FMT_YUV420P16, AV_PIX_FMT_YUV422P16, AV_PIX_FMT_YUV444P16, + AV_PIX_FMT_YUVA420P9, AV_PIX_FMT_YUVA422P9, AV_PIX_FMT_YUVA444P9, + AV_PIX_FMT_YUVA420P10, AV_PIX_FMT_YUVA422P10, AV_PIX_FMT_YUVA444P10, + AV_PIX_FMT_YUVA420P16, AV_PIX_FMT_YUVA422P16, AV_PIX_FMT_YUVA444P16, + AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRP9, AV_PIX_FMT_GBRP10, + AV_PIX_FMT_GBRP12, AV_PIX_FMT_GBRP14, AV_PIX_FMT_GBRP16, + AV_PIX_FMT_GBRAP, AV_PIX_FMT_GBRAP10, AV_PIX_FMT_GBRAP12, AV_PIX_FMT_GBRAP16, + AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY9, AV_PIX_FMT_GRAY10, AV_PIX_FMT_GRAY12, AV_PIX_FMT_GRAY14, AV_PIX_FMT_GRAY16, + AV_PIX_FMT_NONE }; return ff_set_common_formats(ctx, ff_make_format_list(pix_fmts)); } -static av_cold void uninit(AVFilterContext *ctx) -{ - NContext *s = ctx->priv; - - av_freep(&s->buffer); -} - -static inline void line_copy8(uint8_t *line, const uint8_t *srcp, int width, int mergin) -{ - int i; - - memcpy(line, srcp, width); - - for (i = mergin; i > 0; i--) { - line[-i] = line[i]; - line[width - 1 + i] = line[width - 1 - i]; - } -} - static void erosion(uint8_t *dst, const uint8_t *p1, int width, - int threshold, const uint8_t *coordinates[], int coord) + int threshold, const uint8_t *coordinates[], int coord, + int maxc) { int x, i; @@ -91,8 +96,31 @@ static void erosion(uint8_t *dst, const uint8_t *p1, int width, } } +static void erosion16(uint8_t *dstp, const uint8_t *p1, int width, + int threshold, const uint8_t *coordinates[], int coord, + int maxc) +{ + uint16_t *dst = (uint16_t *)dstp; + int x, i; + + for (x = 0; x < width; x++) { + int min = AV_RN16A(&p1[2 * x]); + int limit = FFMAX(min - threshold, 0); + + for (i = 0; i < 8; i++) { + if (coord & (1 << i)) { + min = FFMIN(min, AV_RN16A(coordinates[i] + x * 2)); + } + min = FFMAX(min, limit); + } + + dst[x] = min; + } +} + static void dilation(uint8_t *dst, const uint8_t *p1, int width, - int threshold, const uint8_t *coordinates[], int coord) + int threshold, const uint8_t *coordinates[], int coord, + int maxc) { int x, i; @@ -111,8 +139,31 @@ static void dilation(uint8_t *dst, const uint8_t *p1, int width, } } +static void dilation16(uint8_t *dstp, const uint8_t *p1, int width, + int threshold, const uint8_t *coordinates[], int coord, + int maxc) +{ + uint16_t *dst = (uint16_t *)dstp; + int x, i; + + for (x = 0; x < width; x++) { + int max = AV_RN16A(&p1[x * 2]); + int limit = FFMIN(max + threshold, maxc); + + for (i = 0; i < 8; i++) { + if (coord & (1 << i)) { + max = FFMAX(max, AV_RN16A(coordinates[i] + x * 2)); + } + max = FFMIN(max, limit); + } + + dst[x] = max; + } +} + static void deflate(uint8_t *dst, const uint8_t *p1, int width, - int threshold, const uint8_t *coordinates[], int coord) + int threshold, const uint8_t *coordinates[], int coord, + int maxc) { int x, i; @@ -126,8 +177,26 @@ static void deflate(uint8_t *dst, const uint8_t *p1, int width, } } +static void deflate16(uint8_t *dstp, const uint8_t *p1, int width, + int threshold, const uint8_t *coordinates[], int coord, + int maxc) +{ + uint16_t *dst = (uint16_t *)dstp; + int x, i; + + for (x = 0; x < width; x++) { + int sum = 0; + int limit = FFMAX(AV_RN16A(&p1[2 * x]) - threshold, 0); + + for (i = 0; i < 8; sum += AV_RN16A(coordinates[i++] + x * 2)); + + dst[x] = FFMAX(FFMIN(sum / 8, AV_RN16A(&p1[2 * x])), limit); + } +} + static void inflate(uint8_t *dst, const uint8_t *p1, int width, - int threshold, const uint8_t *coordinates[], int coord) + int threshold, const uint8_t *coordinates[], int coord, + int maxc) { int x, i; @@ -141,32 +210,100 @@ static void inflate(uint8_t *dst, const uint8_t *p1, int width, } } +static void inflate16(uint8_t *dstp, const uint8_t *p1, int width, + int threshold, const uint8_t *coordinates[], int coord, + int maxc) +{ + uint16_t *dst = (uint16_t *)dstp; + int x, i; + + for (x = 0; x < width; x++) { + int sum = 0; + int limit = FFMIN(AV_RN16A(&p1[2 * x]) + threshold, maxc); + + for (i = 0; i < 8; sum += AV_RN16A(coordinates[i++] + x * 2)); + + dst[x] = FFMIN(FFMAX(sum / 8, AV_RN16A(&p1[x * 2])), limit); + } +} + static int config_input(AVFilterLink *inlink) { AVFilterContext *ctx = inlink->dst; NContext *s = ctx->priv; const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format); - int ret; - if ((ret = av_image_fill_linesizes(s->planewidth, inlink->format, inlink->w)) < 0) - return ret; + s->depth = desc->comp[0].depth; + s->max = (1 << s->depth) - 1; + s->bpc = (s->depth + 7) / 8; + s->planewidth[1] = s->planewidth[2] = AV_CEIL_RSHIFT(inlink->w, desc->log2_chroma_w); + s->planewidth[0] = s->planewidth[3] = inlink->w; s->planeheight[1] = s->planeheight[2] = AV_CEIL_RSHIFT(inlink->h, desc->log2_chroma_h); s->planeheight[0] = s->planeheight[3] = inlink->h; s->nb_planes = av_pix_fmt_count_planes(inlink->format); - s->buffer = av_malloc(3 * (s->planewidth[0] + 32)); - if (!s->buffer) - return AVERROR(ENOMEM); if (!strcmp(ctx->filter->name, "erosion")) - s->filter = erosion; + s->filter = s->depth > 8 ? erosion16 : erosion; else if (!strcmp(ctx->filter->name, "dilation")) - s->filter = dilation; + s->filter = s->depth > 8 ? dilation16 : dilation; else if (!strcmp(ctx->filter->name, "deflate")) - s->filter = deflate; + s->filter = s->depth > 8 ? deflate16 : deflate; else if (!strcmp(ctx->filter->name, "inflate")) - s->filter = inflate; + s->filter = s->depth > 8 ? inflate16 : inflate; + + return 0; +} + +static int filter_slice(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) +{ + NContext *s = ctx->priv; + ThreadData *td = arg; + AVFrame *out = td->out; + AVFrame *in = td->in; + int plane, y; + + for (plane = 0; plane < s->nb_planes; plane++) { + const int bpc = s->bpc; + const int threshold = s->threshold[plane]; + const int stride = in->linesize[plane]; + const int dstride = out->linesize[plane]; + const int height = s->planeheight[plane]; + const int width = s->planewidth[plane]; + const int slice_start = (height * jobnr) / nb_jobs; + const int slice_end = (height * (jobnr+1)) / nb_jobs; + const uint8_t *src = (const uint8_t *)in->data[plane] + slice_start * stride; + uint8_t *dst = out->data[plane] + slice_start * dstride; + + if (!threshold) { + av_image_copy_plane(dst, dstride, src, stride, width * bpc, slice_end - slice_start); + continue; + } + + for (y = slice_start; y < slice_end; y++) { + const int nh = y > 0; + const int ph = y < height - 1; + const uint8_t *coordinates[] = { src - nh * stride, src + 1 * bpc - nh * stride, src + 2 * bpc - nh * stride, + src, src + 2 * bpc, + src + ph * stride, src + 1 * bpc + ph * stride, src + 2 * bpc + ph * stride}; + + const uint8_t *coordinateslb[] = { src + 1 * bpc - nh * stride, src - nh * stride, src + 1 * bpc - nh * stride, + src + 1 * bpc, src + 1 * bpc, + src + 1 * bpc + ph * stride, src + ph * stride, src + 1 * bpc + ph * stride}; + + const uint8_t *coordinatesrb[] = { src + (width - 2) * bpc - nh * stride, src + (width - 1) * bpc - nh * stride, src + (width - 2) * bpc - nh * stride, + src + (width - 2) * bpc, src + (width - 2) * bpc, + src + (width - 2) * bpc + ph * stride, src + (width - 1) * bpc + ph * stride, src + (width - 2) * bpc + ph * stride}; + + s->filter(dst, src, 1, threshold, coordinateslb, s->coordinates, s->max); + s->filter(dst + 1 * bpc, src + 1 * bpc, width - 2, threshold, coordinates, s->coordinates, s->max); + s->filter(dst + (width - 1) * bpc, src + (width - 1) * bpc, 1, threshold, coordinatesrb, s->coordinates, s->max); + + src += stride; + dst += dstride; + } + } return 0; } @@ -176,8 +313,8 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) AVFilterContext *ctx = inlink->dst; AVFilterLink *outlink = ctx->outputs[0]; NContext *s = ctx->priv; + ThreadData td; AVFrame *out; - int plane, y; out = ff_get_video_buffer(outlink, outlink->w, outlink->h); if (!out) { @@ -186,43 +323,9 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) } av_frame_copy_props(out, in); - for (plane = 0; plane < s->nb_planes; plane++) { - const int threshold = s->threshold[plane]; - - if (threshold) { - const uint8_t *src = in->data[plane]; - uint8_t *dst = out->data[plane]; - int stride = in->linesize[plane]; - int height = s->planeheight[plane]; - int width = s->planewidth[plane]; - uint8_t *p0 = s->buffer + 16; - uint8_t *p1 = p0 + s->planewidth[0]; - uint8_t *p2 = p1 + s->planewidth[0]; - uint8_t *orig = p0, *end = p2; - - line_copy8(p0, src + stride, width, 1); - line_copy8(p1, src, width, 1); - - for (y = 0; y < height; y++) { - const uint8_t *coordinates[] = { p0 - 1, p0, p0 + 1, - p1 - 1, p1 + 1, - p2 - 1, p2, p2 + 1}; - src += stride * (y < height - 1 ? 1 : -1); - line_copy8(p2, src, width, 1); - - s->filter(dst, p1, width, threshold, coordinates, s->coordinates); - - p0 = p1; - p1 = p2; - p2 = (p2 == end) ? orig: p2 + s->planewidth[0]; - dst += out->linesize[plane]; - } - } else { - av_image_copy_plane(out->data[plane], out->linesize[plane], - in->data[plane], in->linesize[plane], - s->planewidth[plane], s->planeheight[plane]); - } - } + td.in = in; + td.out = out; + ctx->internal->execute(ctx, filter_slice, &td, NULL, FFMIN(s->planeheight[1], ff_filter_get_nb_threads(ctx))); av_frame_free(&in); return ff_filter_frame(outlink, out); @@ -257,11 +360,11 @@ AVFilter ff_vf_##name_ = { \ .description = NULL_IF_CONFIG_SMALL(description_), \ .priv_size = sizeof(NContext), \ .priv_class = &name_##_class, \ - .uninit = uninit, \ .query_formats = query_formats, \ .inputs = neighbor_inputs, \ .outputs = neighbor_outputs, \ - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC, \ + .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC| \ + AVFILTER_FLAG_SLICE_THREADS, \ } #if CONFIG_EROSION_FILTER diff --git a/libavfilter/vf_neighbor_opencl.c b/libavfilter/vf_neighbor_opencl.c new file mode 100644 index 000000000..fb40132d9 --- /dev/null +++ b/libavfilter/vf_neighbor_opencl.c @@ -0,0 +1,318 @@ +/* + * Copyright (c) 2018 Danil Iashchenko + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/common.h" +#include "libavutil/imgutils.h" +#include "libavutil/mem.h" +#include "libavutil/opt.h" +#include "libavutil/pixdesc.h" +#include "libavutil/avstring.h" + + +#include "avfilter.h" +#include "internal.h" +#include "opencl.h" +#include "opencl_source.h" +#include "video.h" + +typedef struct NeighborOpenCLContext { + OpenCLFilterContext ocf; + + int initialised; + cl_kernel kernel; + cl_command_queue command_queue; + + char *matrix_str[4]; + + cl_float threshold[4]; + cl_int coordinates; + cl_mem coord; + +} NeighborOpenCLContext; + +static int neighbor_opencl_init(AVFilterContext *avctx) +{ + NeighborOpenCLContext *ctx = avctx->priv; + const char *kernel_name; + cl_int cle; + int err; + + err = ff_opencl_filter_load_program(avctx, &ff_opencl_source_neighbor, 1); + if (err < 0) + goto fail; + + ctx->command_queue = clCreateCommandQueue(ctx->ocf.hwctx->context, + ctx->ocf.hwctx->device_id, + 0, &cle); + CL_FAIL_ON_ERROR(AVERROR(EIO), "Failed to create OpenCL " + "command queue %d.\n", cle); + + if (!strcmp(avctx->filter->name, "erosion_opencl")){ + kernel_name = "erosion_global"; + } else if (!strcmp(avctx->filter->name, "dilation_opencl")){ + kernel_name = "dilation_global"; + } + ctx->kernel = clCreateKernel(ctx->ocf.program, kernel_name, &cle); + CL_FAIL_ON_ERROR(AVERROR(EIO), "Failed to create " + "kernel %d.\n", cle); + + ctx->initialised = 1; + return 0; + +fail: + if (ctx->command_queue) + clReleaseCommandQueue(ctx->command_queue); + if (ctx->kernel) + clReleaseKernel(ctx->kernel); + return err; +} + +static int neighbor_opencl_make_filter_params(AVFilterContext *avctx) +{ + NeighborOpenCLContext *ctx = avctx->priv; + cl_int matrix[9]; + cl_mem buffer; + cl_int cle; + int i; + + for (i = 0; i < 4; i++) { + ctx->threshold[i] /= 255.0; + } + + matrix[4] = 0; + for (i = 0; i < 8; i++) { + if (ctx->coordinates & (1 << i)) { + matrix[i > 3 ? i + 1: i] = 1; + } + } + buffer = clCreateBuffer(ctx->ocf.hwctx->context, + CL_MEM_READ_ONLY | + CL_MEM_COPY_HOST_PTR | + CL_MEM_HOST_NO_ACCESS, + 9 * sizeof(cl_int), matrix, &cle); + if (!buffer) { + av_log(avctx, AV_LOG_ERROR, "Failed to create matrix buffer: " + "%d.\n", cle); + return AVERROR(EIO); + } + ctx->coord = buffer; + + return 0; +} + + +static int neighbor_opencl_filter_frame(AVFilterLink *inlink, AVFrame *input) +{ + AVFilterContext *avctx = inlink->dst; + AVFilterLink *outlink = avctx->outputs[0]; + NeighborOpenCLContext *ctx = avctx->priv; + AVFrame *output = NULL; + cl_int cle; + size_t global_work[2]; + cl_mem src, dst; + int err, p; + size_t origin[3] = {0, 0, 0}; + size_t region[3] = {0, 0, 1}; + + av_log(ctx, AV_LOG_DEBUG, "Filter input: %s, %ux%u (%"PRId64").\n", + av_get_pix_fmt_name(input->format), + input->width, input->height, input->pts); + + if (!input->hw_frames_ctx) + return AVERROR(EINVAL); + + if (!ctx->initialised) { + err = neighbor_opencl_init(avctx); + if (err < 0) + goto fail; + + err = neighbor_opencl_make_filter_params(avctx); + if (err < 0) + goto fail; + + } + + output = ff_get_video_buffer(outlink, outlink->w, outlink->h); + if (!output) { + err = AVERROR(ENOMEM); + goto fail; + } + + for (p = 0; p < FF_ARRAY_ELEMS(output->data); p++) { + src = (cl_mem) input->data[p]; + dst = (cl_mem)output->data[p]; + + if (!dst) + break; + + if (ctx->threshold[p] == 0) { + err = ff_opencl_filter_work_size_from_image(avctx, region, output, p, 0); + if (err < 0) + goto fail; + + cle = clEnqueueCopyImage(ctx->command_queue, src, dst, + origin, origin, region, 0, NULL, NULL); + CL_FAIL_ON_ERROR(AVERROR(EIO), "Failed to copy plane %d: %d.\n", + p, cle); + } else { + CL_SET_KERNEL_ARG(ctx->kernel, 0, cl_mem, &dst); + CL_SET_KERNEL_ARG(ctx->kernel, 1, cl_mem, &src); + CL_SET_KERNEL_ARG(ctx->kernel, 2, cl_float, &ctx->threshold[p]); + CL_SET_KERNEL_ARG(ctx->kernel, 3, cl_mem, &ctx->coord); + + err = ff_opencl_filter_work_size_from_image(avctx, global_work, output, p, 0); + if (err < 0) + goto fail; + + av_log(avctx, AV_LOG_DEBUG, "Run kernel on plane %d " + "(%"SIZE_SPECIFIER"x%"SIZE_SPECIFIER").\n", + p, global_work[0], global_work[1]); + + cle = clEnqueueNDRangeKernel(ctx->command_queue, ctx->kernel, 2, NULL, + global_work, NULL, + 0, NULL, NULL); + CL_FAIL_ON_ERROR(AVERROR(EIO), "Failed to enqueue " + "kernel: %d.\n", cle); + } + } + + cle = clFinish(ctx->command_queue); + CL_FAIL_ON_ERROR(AVERROR(EIO), "Failed to finish command queue: %d.\n", cle); + + err = av_frame_copy_props(output, input); + if (err < 0) + goto fail; + + av_frame_free(&input); + + av_log(ctx, AV_LOG_DEBUG, "Filter output: %s, %ux%u (%"PRId64").\n", + av_get_pix_fmt_name(output->format), + output->width, output->height, output->pts); + + return ff_filter_frame(outlink, output); + +fail: + clFinish(ctx->command_queue); + av_frame_free(&input); + av_frame_free(&output); + return err; +} + +static av_cold void neighbor_opencl_uninit(AVFilterContext *avctx) +{ + NeighborOpenCLContext *ctx = avctx->priv; + cl_int cle; + + clReleaseMemObject(ctx->coord); + + if (ctx->kernel) { + cle = clReleaseKernel(ctx->kernel); + if (cle != CL_SUCCESS) + av_log(avctx, AV_LOG_ERROR, "Failed to release " + "kernel: %d.\n", cle); + } + + if (ctx->command_queue) { + cle = clReleaseCommandQueue(ctx->command_queue); + if (cle != CL_SUCCESS) + av_log(avctx, AV_LOG_ERROR, "Failed to release " + "command queue: %d.\n", cle); + } + + ff_opencl_filter_uninit(avctx); +} + +static const AVFilterPad neighbor_opencl_inputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + .filter_frame = &neighbor_opencl_filter_frame, + .config_props = &ff_opencl_filter_config_input, + }, + { NULL } +}; + +static const AVFilterPad neighbor_opencl_outputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + .config_props = &ff_opencl_filter_config_output, + }, + { NULL } +}; + +#define OFFSET(x) offsetof(NeighborOpenCLContext, x) +#define FLAGS (AV_OPT_FLAG_FILTERING_PARAM | AV_OPT_FLAG_VIDEO_PARAM) + +#if CONFIG_EROSION_OPENCL_FILTER + +static const AVOption erosion_opencl_options[] = { + { "threshold0", "set threshold for 1st plane", OFFSET(threshold[0]), AV_OPT_TYPE_FLOAT, {.dbl=65535.0}, 0.0, 65535, FLAGS }, + { "threshold1", "set threshold for 2nd plane", OFFSET(threshold[1]), AV_OPT_TYPE_FLOAT, {.dbl=65535.0}, 0.0, 65535, FLAGS }, + { "threshold2", "set threshold for 3rd plane", OFFSET(threshold[2]), AV_OPT_TYPE_FLOAT, {.dbl=65535.0}, 0.0, 65535, FLAGS }, + { "threshold3", "set threshold for 4th plane", OFFSET(threshold[3]), AV_OPT_TYPE_FLOAT, {.dbl=65535.0}, 0.0, 65535, FLAGS }, + { "coordinates", "set coordinates", OFFSET(coordinates), AV_OPT_TYPE_INT, {.i64=255}, 0, 255, FLAGS }, + { NULL } +}; + +AVFILTER_DEFINE_CLASS(erosion_opencl); + +AVFilter ff_vf_erosion_opencl = { + .name = "erosion_opencl", + .description = NULL_IF_CONFIG_SMALL("Apply erosion effect"), + .priv_size = sizeof(NeighborOpenCLContext), + .priv_class = &erosion_opencl_class, + .init = &ff_opencl_filter_init, + .uninit = &neighbor_opencl_uninit, + .query_formats = &ff_opencl_filter_query_formats, + .inputs = neighbor_opencl_inputs, + .outputs = neighbor_opencl_outputs, + .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE, +}; + +#endif /* CONFIG_EROSION_OPENCL_FILTER */ + +#if CONFIG_DILATION_OPENCL_FILTER + +static const AVOption dilation_opencl_options[] = { + { "threshold0", "set threshold for 1st plane", OFFSET(threshold[0]), AV_OPT_TYPE_FLOAT, {.dbl=65535.0}, 0.0, 65535, FLAGS }, + { "threshold1", "set threshold for 2nd plane", OFFSET(threshold[1]), AV_OPT_TYPE_FLOAT, {.dbl=65535.0}, 0.0, 65535, FLAGS }, + { "threshold2", "set threshold for 3rd plane", OFFSET(threshold[2]), AV_OPT_TYPE_FLOAT, {.dbl=65535.0}, 0.0, 65535, FLAGS }, + { "threshold3", "set threshold for 4th plane", OFFSET(threshold[3]), AV_OPT_TYPE_FLOAT, {.dbl=65535.0}, 0.0, 65535, FLAGS }, + { "coordinates", "set coordinates", OFFSET(coordinates), AV_OPT_TYPE_INT, {.i64=255}, 0, 255, FLAGS }, + { NULL } +}; + +AVFILTER_DEFINE_CLASS(dilation_opencl); + +AVFilter ff_vf_dilation_opencl = { + .name = "dilation_opencl", + .description = NULL_IF_CONFIG_SMALL("Apply dilation effect"), + .priv_size = sizeof(NeighborOpenCLContext), + .priv_class = &dilation_opencl_class, + .init = &ff_opencl_filter_init, + .uninit = &neighbor_opencl_uninit, + .query_formats = &ff_opencl_filter_query_formats, + .inputs = neighbor_opencl_inputs, + .outputs = neighbor_opencl_outputs, + .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE, +}; + +#endif /* CONFIG_DILATION_OPENCL_FILTER */ diff --git a/libavfilter/vf_nlmeans.c b/libavfilter/vf_nlmeans.c index e4952e187..dcb5a0395 100644 --- a/libavfilter/vf_nlmeans.c +++ b/libavfilter/vf_nlmeans.c @@ -20,8 +20,6 @@ /** * @todo - * - SIMD for compute_safe_ssd_integral_image - * - SIMD for final weighted averaging * - better automatic defaults? see "Parameters" @ http://www.ipol.im/pub/art/2011/bcm_nlm/ * - temporal support (probably doesn't need any displacement according to * "Denoising image sequences does not require motion estimation") @@ -37,16 +35,14 @@ #include "avfilter.h" #include "formats.h" #include "internal.h" +#include "vf_nlmeans.h" #include "video.h" struct weighted_avg { - double total_weight; - double sum; + float total_weight; + float sum; }; -#define WEIGHT_LUT_NBITS 9 -#define WEIGHT_LUT_SIZE (1<= 16 && h >= 1); for (y = 0; y < h; y++) { - uint32_t acc = dst[-1] - dst[-dst_linesize_32 - 1]; + for (x = 0; x < w; x += 4) { + const int d0 = s1[x ] - s2[x ]; + const int d1 = s1[x + 1] - s2[x + 1]; + const int d2 = s1[x + 2] - s2[x + 2]; + const int d3 = s1[x + 3] - s2[x + 3]; - for (x = 0; x < w; x++) { - const int d = s1[x] - s2[x]; - acc += d * d; - dst[x] = dst[-dst_linesize_32 + x] + acc; + dst[x ] = dst_top[x ] - dst_top[x - 1] + d0*d0; + dst[x + 1] = dst_top[x + 1] - dst_top[x ] + d1*d1; + dst[x + 2] = dst_top[x + 2] - dst_top[x + 1] + d2*d2; + dst[x + 3] = dst_top[x + 3] - dst_top[x + 2] + d3*d3; + + dst[x ] += dst[x - 1]; + dst[x + 1] += dst[x ]; + dst[x + 2] += dst[x + 1]; + dst[x + 3] += dst[x + 2]; } s1 += linesize1; s2 += linesize2; dst += dst_linesize_32; + dst_top += dst_linesize_32; } } @@ -195,9 +163,9 @@ static void compute_safe_ssd_integral_image_c(uint32_t *dst, int dst_linesize_32 * @param w width to compute * @param h height to compute */ -static inline void compute_unsafe_ssd_integral_image(uint32_t *dst, int dst_linesize_32, +static inline void compute_unsafe_ssd_integral_image(uint32_t *dst, ptrdiff_t dst_linesize_32, int startx, int starty, - const uint8_t *src, int linesize, + const uint8_t *src, ptrdiff_t linesize, int offx, int offy, int r, int sw, int sh, int w, int h) { @@ -237,8 +205,9 @@ static inline void compute_unsafe_ssd_integral_image(uint32_t *dst, int dst_line * @param h source height * @param e research padding edge */ -static void compute_ssd_integral_image(uint32_t *ii, int ii_linesize_32, - const uint8_t *src, int linesize, int offx, int offy, +static void compute_ssd_integral_image(const NLMeansDSPContext *dsp, + uint32_t *ii, ptrdiff_t ii_linesize_32, + const uint8_t *src, ptrdiff_t linesize, int offx, int offy, int e, int w, int h) { // ii has a surrounding padding of thickness "e" @@ -257,9 +226,16 @@ static void compute_ssd_integral_image(uint32_t *ii, int ii_linesize_32, // to compare the 2 sources pixels const int startx_safe = FFMAX(s1x, s2x); const int starty_safe = FFMAX(s1y, s2y); - const int endx_safe = FFMIN(s1x + w, s2x + w); + const int u_endx_safe = FFMIN(s1x + w, s2x + w); // unaligned const int endy_safe = FFMIN(s1y + h, s2y + h); + // deduce the safe area width and height + const int safe_pw = (u_endx_safe - startx_safe) & ~0xf; + const int safe_ph = endy_safe - starty_safe; + + // adjusted end x position of the safe area after width of the safe area gets aligned + const int endx_safe = startx_safe + safe_pw; + // top part where only one of s1 and s2 is still readable, or none at all compute_unsafe_ssd_integral_image(ii, ii_linesize_32, 0, 0, @@ -273,24 +249,25 @@ static void compute_ssd_integral_image(uint32_t *ii, int ii_linesize_32, 0, starty_safe, src, linesize, offx, offy, e, w, h, - startx_safe, endy_safe - starty_safe); + startx_safe, safe_ph); // main and safe part of the integral av_assert1(startx_safe - s1x >= 0); av_assert1(startx_safe - s1x < w); av_assert1(starty_safe - s1y >= 0); av_assert1(starty_safe - s1y < h); av_assert1(startx_safe - s2x >= 0); av_assert1(startx_safe - s2x < w); av_assert1(starty_safe - s2y >= 0); av_assert1(starty_safe - s2y < h); - compute_safe_ssd_integral_image_c(ii + starty_safe*ii_linesize_32 + startx_safe, ii_linesize_32, - src + (starty_safe - s1y) * linesize + (startx_safe - s1x), linesize, - src + (starty_safe - s2y) * linesize + (startx_safe - s2x), linesize, - endx_safe - startx_safe, endy_safe - starty_safe); + if (safe_pw && safe_ph) + dsp->compute_safe_ssd_integral_image(ii + starty_safe*ii_linesize_32 + startx_safe, ii_linesize_32, + src + (starty_safe - s1y) * linesize + (startx_safe - s1x), linesize, + src + (starty_safe - s2y) * linesize + (startx_safe - s2x), linesize, + safe_pw, safe_ph); // right part of the integral compute_unsafe_ssd_integral_image(ii, ii_linesize_32, endx_safe, starty_safe, src, linesize, offx, offy, e, w, h, - ii_w - endx_safe, endy_safe - starty_safe); + ii_w - endx_safe, safe_ph); // bottom part where only one of s1 and s2 is still readable, or none at all compute_unsafe_ssd_integral_image(ii, ii_linesize_32, @@ -308,8 +285,8 @@ static int config_input(AVFilterLink *inlink) const int e = FFMAX(s->research_hsize, s->research_hsize_uv) + FFMAX(s->patch_hsize, s->patch_hsize_uv); - s->chroma_w = FF_CEIL_RSHIFT(inlink->w, desc->log2_chroma_w); - s->chroma_h = FF_CEIL_RSHIFT(inlink->h, desc->log2_chroma_h); + s->chroma_w = AV_CEIL_RSHIFT(inlink->w, desc->log2_chroma_w); + s->chroma_h = AV_CEIL_RSHIFT(inlink->h, desc->log2_chroma_h); s->nb_planes = av_pix_fmt_count_planes(inlink->format); /* Allocate the integral image with extra edges of thickness "e" @@ -356,7 +333,7 @@ static int config_input(AVFilterLink *inlink) struct thread_data { const uint8_t *src; - int src_linesize; + ptrdiff_t src_linesize; int startx, starty; int endx, endy; const uint32_t *ii_start; @@ -368,34 +345,92 @@ static int nlmeans_slice(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs int x, y; NLMeansContext *s = ctx->priv; const struct thread_data *td = arg; - const uint8_t *src = td->src; - const int src_linesize = td->src_linesize; + const ptrdiff_t src_linesize = td->src_linesize; const int process_h = td->endy - td->starty; const int slice_start = (process_h * jobnr ) / nb_jobs; const int slice_end = (process_h * (jobnr+1)) / nb_jobs; const int starty = td->starty + slice_start; const int endy = td->starty + slice_end; + const int p = td->p; + const uint32_t *ii = td->ii_start + (starty - p - 1) * s->ii_lz_32 - p - 1; + const int dist_b = 2*p + 1; + const int dist_d = dist_b * s->ii_lz_32; + const int dist_e = dist_d + dist_b; for (y = starty; y < endy; y++) { + const uint8_t *src = td->src + y*src_linesize; + struct weighted_avg *wa = s->wa + y*s->wa_linesize; for (x = td->startx; x < td->endx; x++) { - const int patch_diff_sq = get_integral_patch_value(td->ii_start, s->ii_lz_32, x, y, td->p); + /* + * M is a discrete map where every entry contains the sum of all the entries + * in the rectangle from the top-left origin of M to its coordinate. In the + * following schema, "i" contains the sum of the whole map: + * + * M = +----------+-----------------+----+ + * | | | | + * | | | | + * | a| b| c| + * +----------+-----------------+----+ + * | | | | + * | | | | + * | | X | | + * | | | | + * | d| e| f| + * +----------+-----------------+----+ + * | | | | + * | g| h| i| + * +----------+-----------------+----+ + * + * The sum of the X box can be calculated with: + * X = e-d-b+a + * + * See https://en.wikipedia.org/wiki/Summed_area_table + * + * The compute*_ssd functions compute the integral image M where every entry + * contains the sum of the squared difference of every corresponding pixels of + * two input planes of the same size as M. + */ + const uint32_t a = ii[x]; + const uint32_t b = ii[x + dist_b]; + const uint32_t d = ii[x + dist_d]; + const uint32_t e = ii[x + dist_e]; + const uint32_t patch_diff_sq = e - d - b + a; + if (patch_diff_sq < s->max_meaningful_diff) { - struct weighted_avg *wa = &s->wa[y*s->wa_linesize + x]; - const int weight_lut_idx = patch_diff_sq * s->pdiff_lut_scale; - const double weight = s->weight_lut[weight_lut_idx]; // exp(-patch_diff_sq * s->pdiff_scale) - wa->total_weight += weight; - wa->sum += weight * src[y*src_linesize + x]; + const float weight = s->weight_lut[patch_diff_sq]; // exp(-patch_diff_sq * s->pdiff_scale) + wa[x].total_weight += weight; + wa[x].sum += weight * src[x]; } } + ii += s->ii_lz_32; } return 0; } -static int nlmeans_plane(AVFilterContext *ctx, int w, int h, int p, int r, - uint8_t *dst, int dst_linesize, - const uint8_t *src, int src_linesize) +static void weight_averages(uint8_t *dst, ptrdiff_t dst_linesize, + const uint8_t *src, ptrdiff_t src_linesize, + struct weighted_avg *wa, ptrdiff_t wa_linesize, + int w, int h) { int x, y; + + for (y = 0; y < h; y++) { + for (x = 0; x < w; x++) { + // Also weight the centered pixel + wa[x].total_weight += 1.f; + wa[x].sum += 1.f * src[x]; + dst[x] = av_clip_uint8(wa[x].sum / wa[x].total_weight); + } + dst += dst_linesize; + src += src_linesize; + wa += wa_linesize; + } +} + +static int nlmeans_plane(AVFilterContext *ctx, int w, int h, int p, int r, + uint8_t *dst, ptrdiff_t dst_linesize, + const uint8_t *src, ptrdiff_t src_linesize) +{ int offx, offy; NLMeansContext *s = ctx->priv; /* patches center points cover the whole research window so the patches @@ -420,7 +455,7 @@ static int nlmeans_plane(AVFilterContext *ctx, int w, int h, int p, int r, .p = p, }; - compute_ssd_integral_image(s->ii, s->ii_lz_32, + compute_ssd_integral_image(&s->dsp, s->ii, s->ii_lz_32, src, src_linesize, offx, offy, e, w, h); ctx->internal->execute(ctx, nlmeans_slice, &td, NULL, @@ -428,17 +463,10 @@ static int nlmeans_plane(AVFilterContext *ctx, int w, int h, int p, int r, } } } - for (y = 0; y < h; y++) { - for (x = 0; x < w; x++) { - struct weighted_avg *wa = &s->wa[y*s->wa_linesize + x]; - // Also weight the centered pixel - wa->total_weight += 1.0; - wa->sum += 1.0 * src[y*src_linesize + x]; + weight_averages(dst, dst_linesize, src, src_linesize, + s->wa, s->wa_linesize, w, h); - dst[y*dst_linesize + x] = av_clip_uint8(wa->sum / wa->total_weight); - } - } return 0; } @@ -478,6 +506,14 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) } \ } while (0) +void ff_nlmeans_init(NLMeansDSPContext *dsp) +{ + dsp->compute_safe_ssd_integral_image = compute_safe_ssd_integral_image_c; + + if (ARCH_AARCH64) + ff_nlmeans_init_aarch64(dsp); +} + static av_cold int init(AVFilterContext *ctx) { int i; @@ -485,11 +521,12 @@ static av_cold int init(AVFilterContext *ctx) const double h = s->sigma * 10.; s->pdiff_scale = 1. / (h * h); - s->max_meaningful_diff = -log(1/255.) / s->pdiff_scale; - s->pdiff_lut_scale = 1./s->max_meaningful_diff * WEIGHT_LUT_SIZE; - av_assert0((s->max_meaningful_diff - 1) * s->pdiff_lut_scale < FF_ARRAY_ELEMS(s->weight_lut)); - for (i = 0; i < WEIGHT_LUT_SIZE; i++) - s->weight_lut[i] = exp(-i / s->pdiff_lut_scale * s->pdiff_scale); + s->max_meaningful_diff = log(255.) / s->pdiff_scale; + s->weight_lut = av_calloc(s->max_meaningful_diff, sizeof(*s->weight_lut)); + if (!s->weight_lut) + return AVERROR(ENOMEM); + for (i = 0; i < s->max_meaningful_diff; i++) + s->weight_lut[i] = exp(-i * s->pdiff_scale); CHECK_ODD_FIELD(research_size, "Luma research window"); CHECK_ODD_FIELD(patch_size, "Luma patch"); @@ -509,12 +546,15 @@ static av_cold int init(AVFilterContext *ctx) s->research_size, s->research_size, s->research_size_uv, s->research_size_uv, s->patch_size, s->patch_size, s->patch_size_uv, s->patch_size_uv); + ff_nlmeans_init(&s->dsp); + return 0; } static av_cold void uninit(AVFilterContext *ctx) { NLMeansContext *s = ctx->priv; + av_freep(&s->weight_lut); av_freep(&s->ii_orig); av_freep(&s->wa); } diff --git a/libavfilter/vf_nlmeans.h b/libavfilter/vf_nlmeans.h new file mode 100644 index 000000000..0a9aab292 --- /dev/null +++ b/libavfilter/vf_nlmeans.h @@ -0,0 +1,35 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVFILTER_NLMEANS_H +#define AVFILTER_NLMEANS_H + +#include +#include + +typedef struct NLMeansDSPContext { + void (*compute_safe_ssd_integral_image)(uint32_t *dst, ptrdiff_t dst_linesize_32, + const uint8_t *s1, ptrdiff_t linesize1, + const uint8_t *s2, ptrdiff_t linesize2, + int w, int h); +} NLMeansDSPContext; + +void ff_nlmeans_init(NLMeansDSPContext *dsp); +void ff_nlmeans_init_aarch64(NLMeansDSPContext *dsp); + +#endif /* AVFILTER_NLMEANS_H */ diff --git a/libavfilter/vf_nlmeans_opencl.c b/libavfilter/vf_nlmeans_opencl.c new file mode 100644 index 000000000..e57b5e087 --- /dev/null +++ b/libavfilter/vf_nlmeans_opencl.c @@ -0,0 +1,443 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include + +#include "libavutil/avassert.h" +#include "libavutil/common.h" +#include "libavutil/imgutils.h" +#include "libavutil/mem.h" +#include "libavutil/opt.h" +#include "libavutil/pixdesc.h" + +#include "avfilter.h" +#include "internal.h" +#include "opencl.h" +#include "opencl_source.h" +#include "video.h" + +// TODO: +// the integral image may overflow 32bit, consider using 64bit + +static const enum AVPixelFormat supported_formats[] = { + AV_PIX_FMT_YUV420P, + AV_PIX_FMT_YUV444P, + AV_PIX_FMT_GBRP, +}; + +static int is_format_supported(enum AVPixelFormat fmt) +{ + int i; + + for (i = 0; i < FF_ARRAY_ELEMS(supported_formats); i++) + if (supported_formats[i] == fmt) + return 1; + return 0; +} + +typedef struct NLMeansOpenCLContext { + OpenCLFilterContext ocf; + int initialised; + cl_kernel vert_kernel; + cl_kernel horiz_kernel; + cl_kernel accum_kernel; + cl_kernel average_kernel; + cl_mem integral_img; + cl_mem weight; + cl_mem sum; + cl_mem overflow; // overflow in integral image? + double sigma; + float h; + int chroma_w; + int chroma_h; + int patch_size; + int patch_size_uv; + int research_size; + int research_size_uv; + cl_command_queue command_queue; +} NLMeansOpenCLContext; + +static int nlmeans_opencl_init(AVFilterContext *avctx, int width, int height) +{ + NLMeansOpenCLContext *ctx = avctx->priv; + cl_int cle; + int err; + int weight_buf_size = width * height * sizeof(float); + + ctx->h = ctx->sigma * 10; + if (!(ctx->research_size & 1)) { + ctx->research_size |= 1; + av_log(avctx, AV_LOG_WARNING, + "research_size should be odd, set to %d", + ctx->research_size); + } + + if (!(ctx->patch_size & 1)) { + ctx->patch_size |= 1; + av_log(avctx, AV_LOG_WARNING, + "patch_size should be odd, set to %d", + ctx->patch_size); + } + + if (!ctx->research_size_uv) + ctx->research_size_uv = ctx->research_size; + if (!ctx->patch_size_uv) + ctx->patch_size_uv = ctx->patch_size; + + err = ff_opencl_filter_load_program(avctx, &ff_opencl_source_nlmeans, 1); + if (err < 0) + goto fail; + + ctx->command_queue = clCreateCommandQueue(ctx->ocf.hwctx->context, + ctx->ocf.hwctx->device_id, + 0, &cle); + CL_FAIL_ON_ERROR(AVERROR(EIO), "Failed to create OpenCL " + "command queue %d.\n", cle); + + ctx->vert_kernel = clCreateKernel(ctx->ocf.program, + "vert_sum", &cle); + CL_FAIL_ON_ERROR(AVERROR(EIO), "Failed to create " + "vert_sum kernel %d.\n", cle); + + ctx->horiz_kernel = clCreateKernel(ctx->ocf.program, + "horiz_sum", &cle); + CL_FAIL_ON_ERROR(AVERROR(EIO), "Failed to create " + "horiz_sum kernel %d.\n", cle); + + ctx->accum_kernel = clCreateKernel(ctx->ocf.program, + "weight_accum", &cle); + CL_FAIL_ON_ERROR(AVERROR(EIO), "Failed to create " + "accum kernel %d.\n", cle); + + ctx->average_kernel = clCreateKernel(ctx->ocf.program, + "average", &cle); + CL_FAIL_ON_ERROR(AVERROR(EIO), "Failed to create " + "average kernel %d.\n", cle); + + ctx->integral_img = clCreateBuffer(ctx->ocf.hwctx->context, 0, + 4 * width * height * sizeof(cl_int), + NULL, &cle); + CL_FAIL_ON_ERROR(AVERROR(EIO), "Failed to create " + "integral image %d.\n", cle); + + ctx->weight = clCreateBuffer(ctx->ocf.hwctx->context, 0, + weight_buf_size, NULL, &cle); + CL_FAIL_ON_ERROR(AVERROR(EIO), "Failed to create " + "weight buffer %d.\n", cle); + + ctx->sum = clCreateBuffer(ctx->ocf.hwctx->context, 0, + weight_buf_size, NULL, &cle); + CL_FAIL_ON_ERROR(AVERROR(EIO), "Failed to create " + "sum buffer %d.\n", cle); + + ctx->overflow = clCreateBuffer(ctx->ocf.hwctx->context, 0, + sizeof(cl_int), NULL, &cle); + CL_FAIL_ON_ERROR(AVERROR(EIO), "Failed to create " + "overflow buffer %d.\n", cle); + + ctx->initialised = 1; + return 0; + +fail: + CL_RELEASE_KERNEL(ctx->vert_kernel); + CL_RELEASE_KERNEL(ctx->horiz_kernel); + CL_RELEASE_KERNEL(ctx->accum_kernel); + CL_RELEASE_KERNEL(ctx->average_kernel); + + CL_RELEASE_MEMORY(ctx->integral_img); + CL_RELEASE_MEMORY(ctx->weight); + CL_RELEASE_MEMORY(ctx->sum); + CL_RELEASE_MEMORY(ctx->overflow); + + CL_RELEASE_QUEUE(ctx->command_queue); + return err; +} + +static int nlmeans_plane(AVFilterContext *avctx, cl_mem dst, cl_mem src, + cl_int width, cl_int height, cl_int p, cl_int r) +{ + NLMeansOpenCLContext *ctx = avctx->priv; + const float zero = 0.0f; + const size_t worksize1[] = {height}; + const size_t worksize2[] = {width}; + const size_t worksize3[2] = {width, height}; + int i, dx, dy, err = 0, weight_buf_size; + cl_int cle; + int nb_pixel, *tmp = NULL, idx = 0; + cl_int *dxdy = NULL; + + weight_buf_size = width * height * sizeof(float); + cle = clEnqueueFillBuffer(ctx->command_queue, ctx->weight, + &zero, sizeof(float), 0, weight_buf_size, + 0, NULL, NULL); + CL_FAIL_ON_ERROR(AVERROR(EIO), "Failed to fill weight buffer: %d.\n", + cle); + cle = clEnqueueFillBuffer(ctx->command_queue, ctx->sum, + &zero, sizeof(float), 0, weight_buf_size, + 0, NULL, NULL); + CL_FAIL_ON_ERROR(AVERROR(EIO), "Failed to fill sum buffer: %d.\n", + cle); + + nb_pixel = (2 * r + 1) * (2 * r + 1) - 1; + dxdy = av_malloc(nb_pixel * 2 * sizeof(cl_int)); + tmp = av_malloc(nb_pixel * 2 * sizeof(int)); + + if (!dxdy || !tmp) + goto fail; + + for (dx = -r; dx <= r; dx++) { + for (dy = -r; dy <= r; dy++) { + if (dx || dy) { + tmp[idx++] = dx; + tmp[idx++] = dy; + } + } + } + // repack dx/dy seperately, as we want to do four pairs of dx/dy in a batch + for (i = 0; i < nb_pixel / 4; i++) { + dxdy[i * 8] = tmp[i * 8]; // dx0 + dxdy[i * 8 + 1] = tmp[i * 8 + 2]; // dx1 + dxdy[i * 8 + 2] = tmp[i * 8 + 4]; // dx2 + dxdy[i * 8 + 3] = tmp[i * 8 + 6]; // dx3 + dxdy[i * 8 + 4] = tmp[i * 8 + 1]; // dy0 + dxdy[i * 8 + 5] = tmp[i * 8 + 3]; // dy1 + dxdy[i * 8 + 6] = tmp[i * 8 + 5]; // dy2 + dxdy[i * 8 + 7] = tmp[i * 8 + 7]; // dy3 + } + av_freep(&tmp); + + for (i = 0; i < nb_pixel / 4; i++) { + cl_int *dx_cur = dxdy + 8 * i; + cl_int *dy_cur = dxdy + 8 * i + 4; + + // horizontal pass + // integral(x,y) = sum([u(v,y) - u(v+dx,y+dy)]^2) for v in [0, x] + CL_SET_KERNEL_ARG(ctx->horiz_kernel, 0, cl_mem, &ctx->integral_img); + CL_SET_KERNEL_ARG(ctx->horiz_kernel, 1, cl_mem, &src); + CL_SET_KERNEL_ARG(ctx->horiz_kernel, 2, cl_int, &width); + CL_SET_KERNEL_ARG(ctx->horiz_kernel, 3, cl_int, &height); + CL_SET_KERNEL_ARG(ctx->horiz_kernel, 4, cl_int4, dx_cur); + CL_SET_KERNEL_ARG(ctx->horiz_kernel, 5, cl_int4, dy_cur); + cle = clEnqueueNDRangeKernel(ctx->command_queue, ctx->horiz_kernel, 1, + NULL, worksize1, NULL, 0, NULL, NULL); + CL_FAIL_ON_ERROR(AVERROR(EIO), "Failed to enqueue horiz_kernel: %d.\n", + cle); + // vertical pass + // integral(x, y) = sum(integral(x, v)) for v in [0, y] + CL_SET_KERNEL_ARG(ctx->vert_kernel, 0, cl_mem, &ctx->integral_img); + CL_SET_KERNEL_ARG(ctx->vert_kernel, 1, cl_mem, &ctx->overflow); + CL_SET_KERNEL_ARG(ctx->vert_kernel, 2, cl_int, &width); + CL_SET_KERNEL_ARG(ctx->vert_kernel, 3, cl_int, &height); + cle = clEnqueueNDRangeKernel(ctx->command_queue, ctx->vert_kernel, + 1, NULL, worksize2, NULL, 0, NULL, NULL); + CL_FAIL_ON_ERROR(AVERROR(EIO), "Failed to enqueue vert_kernel: %d.\n", + cle); + + // accumulate weights + CL_SET_KERNEL_ARG(ctx->accum_kernel, 0, cl_mem, &ctx->sum); + CL_SET_KERNEL_ARG(ctx->accum_kernel, 1, cl_mem, &ctx->weight); + CL_SET_KERNEL_ARG(ctx->accum_kernel, 2, cl_mem, &ctx->integral_img); + CL_SET_KERNEL_ARG(ctx->accum_kernel, 3, cl_mem, &src); + CL_SET_KERNEL_ARG(ctx->accum_kernel, 4, cl_int, &width); + CL_SET_KERNEL_ARG(ctx->accum_kernel, 5, cl_int, &height); + CL_SET_KERNEL_ARG(ctx->accum_kernel, 6, cl_int, &p); + CL_SET_KERNEL_ARG(ctx->accum_kernel, 7, cl_float, &ctx->h); + CL_SET_KERNEL_ARG(ctx->accum_kernel, 8, cl_int4, dx_cur); + CL_SET_KERNEL_ARG(ctx->accum_kernel, 9, cl_int4, dy_cur); + cle = clEnqueueNDRangeKernel(ctx->command_queue, ctx->accum_kernel, + 2, NULL, worksize3, NULL, 0, NULL, NULL); + CL_FAIL_ON_ERROR(AVERROR(EIO), "Failed to enqueue kernel: %d.\n", cle); + } + av_freep(&dxdy); + + // average + CL_SET_KERNEL_ARG(ctx->average_kernel, 0, cl_mem, &dst); + CL_SET_KERNEL_ARG(ctx->average_kernel, 1, cl_mem, &src); + CL_SET_KERNEL_ARG(ctx->average_kernel, 2, cl_mem, &ctx->sum); + CL_SET_KERNEL_ARG(ctx->average_kernel, 3, cl_mem, &ctx->weight); + cle = clEnqueueNDRangeKernel(ctx->command_queue, ctx->average_kernel, 2, + NULL, worksize3, NULL, 0, NULL, NULL); + CL_FAIL_ON_ERROR(AVERROR(EIO), "Failed to enqueue average kernel: %d.\n", + cle); + cle = clFlush(ctx->command_queue); + CL_FAIL_ON_ERROR(AVERROR(EIO), "Failed to flush command queue: %d.\n", cle); +fail: + if (tmp) + av_freep(&tmp); + if (dxdy) + av_freep(&dxdy); + return err; +} + +static int nlmeans_opencl_filter_frame(AVFilterLink *inlink, AVFrame *input) +{ + AVFilterContext *avctx = inlink->dst; + AVFilterLink *outlink = avctx->outputs[0]; + NLMeansOpenCLContext *ctx = avctx->priv; + AVFrame *output = NULL; + AVHWFramesContext *input_frames_ctx; + const AVPixFmtDescriptor *desc; + enum AVPixelFormat in_format; + cl_mem src, dst; + const cl_int zero = 0; + int w, h, err, cle, overflow, p, patch, research; + + av_log(ctx, AV_LOG_DEBUG, "Filter input: %s, %ux%u (%"PRId64").\n", + av_get_pix_fmt_name(input->format), + input->width, input->height, input->pts); + + if (!input->hw_frames_ctx) + return AVERROR(EINVAL); + input_frames_ctx = (AVHWFramesContext*)input->hw_frames_ctx->data; + in_format = input_frames_ctx->sw_format; + + output = ff_get_video_buffer(outlink, outlink->w, outlink->h); + if (!output) { + err = AVERROR(ENOMEM); + goto fail; + } + + err = av_frame_copy_props(output, input); + if (err < 0) + goto fail; + + if (!ctx->initialised) { + desc = av_pix_fmt_desc_get(in_format); + if (!is_format_supported(in_format)) { + err = AVERROR(EINVAL); + av_log(avctx, AV_LOG_ERROR, "input format %s not supported\n", + av_get_pix_fmt_name(in_format)); + goto fail; + } + ctx->chroma_w = AV_CEIL_RSHIFT(inlink->w, desc->log2_chroma_w); + ctx->chroma_h = AV_CEIL_RSHIFT(inlink->h, desc->log2_chroma_h); + + err = nlmeans_opencl_init(avctx, inlink->w, inlink->h); + if (err < 0) + goto fail; + } + + cle = clEnqueueWriteBuffer(ctx->command_queue, ctx->overflow, CL_FALSE, + 0, sizeof(cl_int), &zero, 0, NULL, NULL); + CL_FAIL_ON_ERROR(AVERROR(EIO), "Failed to initialize overflow" + "detection buffer %d.\n", cle); + + for (p = 0; p < FF_ARRAY_ELEMS(output->data); p++) { + src = (cl_mem) input->data[p]; + dst = (cl_mem) output->data[p]; + + if (!dst) + break; + av_assert0(src); + w = p ? ctx->chroma_w : inlink->w; + h = p ? ctx->chroma_h : inlink->h; + patch = (p ? ctx->patch_size_uv : ctx->patch_size) / 2; + research = (p ? ctx->research_size_uv : ctx->research_size) / 2; + err = nlmeans_plane(avctx, dst, src, w, h, patch, research); + if (err < 0) + goto fail; + } + // overflow occurred? + cle = clEnqueueReadBuffer(ctx->command_queue, ctx->overflow, CL_FALSE, + 0, sizeof(cl_int), &overflow, 0, NULL, NULL); + CL_FAIL_ON_ERROR(AVERROR(EIO), "Failed to read overflow: %d.\n", cle); + + cle = clFinish(ctx->command_queue); + CL_FAIL_ON_ERROR(AVERROR(EIO), "Failed to finish kernel: %d.\n", cle); + + if (overflow > 0) + av_log(avctx, AV_LOG_ERROR, "integral image overflow %d\n", overflow); + + av_frame_free(&input); + + av_log(ctx, AV_LOG_DEBUG, "Filter output: %s, %ux%u (%"PRId64").\n", + av_get_pix_fmt_name(output->format), + output->width, output->height, output->pts); + + return ff_filter_frame(outlink, output); + +fail: + clFinish(ctx->command_queue); + av_frame_free(&input); + av_frame_free(&output); + return err; +} + +static av_cold void nlmeans_opencl_uninit(AVFilterContext *avctx) +{ + NLMeansOpenCLContext *ctx = avctx->priv; + cl_int cle; + + CL_RELEASE_KERNEL(ctx->vert_kernel); + CL_RELEASE_KERNEL(ctx->horiz_kernel); + CL_RELEASE_KERNEL(ctx->accum_kernel); + CL_RELEASE_KERNEL(ctx->average_kernel); + + CL_RELEASE_MEMORY(ctx->integral_img); + CL_RELEASE_MEMORY(ctx->weight); + CL_RELEASE_MEMORY(ctx->sum); + CL_RELEASE_MEMORY(ctx->overflow); + + CL_RELEASE_QUEUE(ctx->command_queue); + + ff_opencl_filter_uninit(avctx); +} + +#define OFFSET(x) offsetof(NLMeansOpenCLContext, x) +#define FLAGS (AV_OPT_FLAG_FILTERING_PARAM | AV_OPT_FLAG_VIDEO_PARAM) +static const AVOption nlmeans_opencl_options[] = { + { "s", "denoising strength", OFFSET(sigma), AV_OPT_TYPE_DOUBLE, { .dbl = 1.0 }, 1.0, 30.0, FLAGS }, + { "p", "patch size", OFFSET(patch_size), AV_OPT_TYPE_INT, { .i64 = 2*3+1 }, 0, 99, FLAGS }, + { "pc", "patch size for chroma planes", OFFSET(patch_size_uv), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 99, FLAGS }, + { "r", "research window", OFFSET(research_size), AV_OPT_TYPE_INT, { .i64 = 7*2+1 }, 0, 99, FLAGS }, + { "rc", "research window for chroma planes", OFFSET(research_size_uv), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 99, FLAGS }, + { NULL } +}; + +AVFILTER_DEFINE_CLASS(nlmeans_opencl); + +static const AVFilterPad nlmeans_opencl_inputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + .filter_frame = &nlmeans_opencl_filter_frame, + .config_props = &ff_opencl_filter_config_input, + }, + { NULL } +}; + +static const AVFilterPad nlmeans_opencl_outputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + .config_props = &ff_opencl_filter_config_output, + }, + { NULL } +}; + +AVFilter ff_vf_nlmeans_opencl = { + .name = "nlmeans_opencl", + .description = NULL_IF_CONFIG_SMALL("Non-local means denoiser through OpenCL"), + .priv_size = sizeof(NLMeansOpenCLContext), + .priv_class = &nlmeans_opencl_class, + .init = &ff_opencl_filter_init, + .uninit = &nlmeans_opencl_uninit, + .query_formats = &ff_opencl_filter_query_formats, + .inputs = nlmeans_opencl_inputs, + .outputs = nlmeans_opencl_outputs, + .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE, +}; diff --git a/libavfilter/vf_normalize.c b/libavfilter/vf_normalize.c index 5c1fe98c6..48eea59e6 100644 --- a/libavfilter/vf_normalize.c +++ b/libavfilter/vf_normalize.c @@ -76,6 +76,7 @@ #include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "avfilter.h" +#include "drawutils.h" #include "formats.h" #include "internal.h" #include "video.h" @@ -90,8 +91,9 @@ typedef struct NormalizeContext { float independence; float strength; - int co[4]; // Offsets to R,G,B,A bytes respectively in each pixel + uint8_t co[4]; // Offsets to R,G,B,A bytes respectively in each pixel int num_components; // Number of components in the pixel format + int step; int history_len; // Number of frames to average; based on smoothing factor int frame_num; // Increments on each frame, starting from 0. @@ -147,8 +149,8 @@ static void normalize(NormalizeContext *s, AVFrame *in, AVFrame *out) min[c].in = FFMIN(min[c].in, inp[s->co[c]]); max[c].in = FFMAX(max[c].in, inp[s->co[c]]); } - inp += s->num_components; - outp += s->num_components; + inp += s->step; + outp += s->step; } } @@ -237,8 +239,8 @@ static void normalize(NormalizeContext *s, AVFrame *in, AVFrame *out) if (s->num_components == 4) // Copy alpha as-is. outp[s->co[3]] = inp[s->co[3]]; - inp += s->num_components; - outp += s->num_components; + inp += s->step; + outp += s->step; } } @@ -286,9 +288,9 @@ static int config_input(AVFilterLink *inlink) const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format); int c; - for (c = 0; c < 4; ++c) - s->co[c] = desc->comp[c].offset; + ff_fill_rgba_map(s->co, inlink->format); s->num_components = desc->nb_components; + s->step = av_get_padded_bits_per_pixel(desc) >> 3; // Convert smoothing value to history_len (a count of frames to average, // must be at least 1). Currently this is a direct assignment, but the // smoothing value was originally envisaged as a number of seconds. In @@ -383,4 +385,5 @@ AVFilter ff_vf_normalize = { .query_formats = query_formats, .inputs = inputs, .outputs = outputs, + .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, }; diff --git a/libavfilter/vf_ocr.c b/libavfilter/vf_ocr.c index abfff4943..d5f76059b 100644 --- a/libavfilter/vf_ocr.c +++ b/libavfilter/vf_ocr.c @@ -100,11 +100,21 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) AVFilterLink *outlink = ctx->outputs[0]; OCRContext *s = ctx->priv; char *result; + int *confs; result = TessBaseAPIRect(s->tess, in->data[0], 1, in->linesize[0], 0, 0, in->width, in->height); + confs = TessBaseAPIAllWordConfidences(s->tess); av_dict_set(metadata, "lavfi.ocr.text", result, 0); + for (int i = 0; confs[i] != -1; i++) { + char number[256]; + + snprintf(number, sizeof(number), "%d ", confs[i]); + av_dict_set(metadata, "lavfi.ocr.confidence", number, AV_DICT_APPEND); + } + TessDeleteText(result); + TessDeleteIntArray(confs); return ff_filter_frame(outlink, in); } diff --git a/libavfilter/vf_overlay.c b/libavfilter/vf_overlay.c index c6a6ac82f..0a8f089c0 100644 --- a/libavfilter/vf_overlay.c +++ b/libavfilter/vf_overlay.c @@ -39,6 +39,11 @@ #include "drawutils.h" #include "framesync.h" #include "video.h" +#include "vf_overlay.h" + +typedef struct ThreadData { + AVFrame *dst, *src; +} ThreadData; static const char *const var_names[] = { "main_w", "W", ///< width of the main video @@ -55,21 +60,6 @@ static const char *const var_names[] = { NULL }; -enum var_name { - VAR_MAIN_W, VAR_MW, - VAR_MAIN_H, VAR_MH, - VAR_OVERLAY_W, VAR_OW, - VAR_OVERLAY_H, VAR_OH, - VAR_HSUB, - VAR_VSUB, - VAR_X, - VAR_Y, - VAR_N, - VAR_POS, - VAR_T, - VAR_VARS_NB -}; - #define MAIN 0 #define OVERLAY 1 @@ -88,45 +78,6 @@ enum EvalMode { EVAL_MODE_NB }; -enum OverlayFormat { - OVERLAY_FORMAT_YUV420, - OVERLAY_FORMAT_YUV422, - OVERLAY_FORMAT_YUV444, - OVERLAY_FORMAT_RGB, - OVERLAY_FORMAT_GBRP, - OVERLAY_FORMAT_AUTO, - OVERLAY_FORMAT_NB -}; - -typedef struct OverlayContext { - const AVClass *class; - int x, y; ///< position of overlaid picture - - uint8_t main_is_packed_rgb; - uint8_t main_rgba_map[4]; - uint8_t main_has_alpha; - uint8_t overlay_is_packed_rgb; - uint8_t overlay_rgba_map[4]; - uint8_t overlay_has_alpha; - int format; ///< OverlayFormat - int alpha_format; - int eval_mode; ///< EvalMode - - FFFrameSync fs; - - int main_pix_step[4]; ///< steps per pixel for each plane of the main output - int overlay_pix_step[4]; ///< steps per pixel for each plane of the overlay - int hsub, vsub; ///< chroma subsampling values - const AVPixFmtDescriptor *main_desc; ///< format descriptor for main input - - double var_values[VAR_VARS_NB]; - char *x_expr, *y_expr; - - AVExpr *x_pexpr, *y_pexpr; - - void (*blend_image)(AVFilterContext *ctx, AVFrame *dst, const AVFrame *src, int x, int y); -} OverlayContext; - static av_cold void uninit(AVFilterContext *ctx) { OverlayContext *s = ctx->priv; @@ -403,10 +354,10 @@ static int config_output(AVFilterLink *outlink) * Blend image in src to destination buffer dst at position (x, y). */ -static av_always_inline void blend_image_packed_rgb(AVFilterContext *ctx, +static av_always_inline void blend_slice_packed_rgb(AVFilterContext *ctx, AVFrame *dst, const AVFrame *src, int main_has_alpha, int x, int y, - int is_straight) + int is_straight, int jobnr, int nb_jobs) { OverlayContext *s = ctx->priv; int i, imax, j, jmax; @@ -425,13 +376,19 @@ static av_always_inline void blend_image_packed_rgb(AVFilterContext *ctx, const int sb = s->overlay_rgba_map[B]; const int sa = s->overlay_rgba_map[A]; const int sstep = s->overlay_pix_step[0]; + int slice_start, slice_end; uint8_t *S, *sp, *d, *dp; i = FFMAX(-y, 0); - sp = src->data[0] + i * src->linesize[0]; - dp = dst->data[0] + (y+i) * dst->linesize[0]; + imax = FFMIN3(-y + dst_h, FFMIN(src_h, dst_h), y + src_h); - for (imax = FFMIN(-y + dst_h, src_h); i < imax; i++) { + slice_start = i + (imax * jobnr) / nb_jobs; + slice_end = i + (imax * (jobnr+1)) / nb_jobs; + + sp = src->data[0] + (slice_start) * src->linesize[0]; + dp = dst->data[0] + (y + slice_start) * dst->linesize[0]; + + for (i = slice_start; i < slice_end; i++) { j = FFMAX(-x, 0); S = sp + j * sstep; d = dp + (x+j) * dstep; @@ -495,8 +452,11 @@ static av_always_inline void blend_plane(AVFilterContext *ctx, int dst_offset, int dst_step, int straight, - int yuv) + int yuv, + int jobnr, + int nb_jobs) { + OverlayContext *octx = ctx->priv; int src_wp = AV_CEIL_RSHIFT(src_w, hsub); int src_hp = AV_CEIL_RSHIFT(src_h, vsub); int dst_wp = AV_CEIL_RSHIFT(dst_w, hsub); @@ -505,23 +465,39 @@ static av_always_inline void blend_plane(AVFilterContext *ctx, int xp = x>>hsub; uint8_t *s, *sp, *d, *dp, *dap, *a, *da, *ap; int jmax, j, k, kmax; + int slice_start, slice_end; j = FFMAX(-yp, 0); - sp = src->data[i] + j * src->linesize[i]; - dp = dst->data[dst_plane] - + (yp+j) * dst->linesize[dst_plane] - + dst_offset; - ap = src->data[3] + (j<linesize[3]; - dap = dst->data[3] + ((yp+j) << vsub) * dst->linesize[3]; + jmax = FFMIN3(-yp + dst_hp, FFMIN(src_hp, dst_hp), yp + src_hp); - for (jmax = FFMIN(-yp + dst_hp, src_hp); j < jmax; j++) { + slice_start = j + (jmax * jobnr) / nb_jobs; + slice_end = j + (jmax * (jobnr+1)) / nb_jobs; + + sp = src->data[i] + (slice_start) * src->linesize[i]; + dp = dst->data[dst_plane] + + (yp + slice_start) * dst->linesize[dst_plane] + + dst_offset; + ap = src->data[3] + (slice_start << vsub) * src->linesize[3]; + dap = dst->data[3] + ((yp + slice_start) << vsub) * dst->linesize[3]; + + for (j = slice_start; j < slice_end; j++) { k = FFMAX(-xp, 0); d = dp + (xp+k) * dst_step; s = sp + k; a = ap + (k<blend_row[i]) { + int c = octx->blend_row[i](d, da, s, a, kmax - k, src->linesize[3]); + + s += c; + d += dst_step * c; + da += (1 << hsub) * c; + a += (1 << hsub) * c; + k += c; + } + for (; k < kmax; k++) { int alpha_v, alpha_h, alpha; // average alpha for color components, improve quality @@ -577,17 +553,23 @@ static av_always_inline void blend_plane(AVFilterContext *ctx, static inline void alpha_composite(const AVFrame *src, const AVFrame *dst, int src_w, int src_h, int dst_w, int dst_h, - int x, int y) + int x, int y, + int jobnr, int nb_jobs) { uint8_t alpha; ///< the amount of overlay to blend on to main uint8_t *s, *sa, *d, *da; int i, imax, j, jmax; + int slice_start, slice_end; + + imax = FFMIN(-y + dst_h, src_h); + slice_start = (imax * jobnr) / nb_jobs; + slice_end = ((imax * (jobnr+1)) / nb_jobs); i = FFMAX(-y, 0); - sa = src->data[3] + i * src->linesize[3]; - da = dst->data[3] + (y+i) * dst->linesize[3]; + sa = src->data[3] + (i + slice_start) * src->linesize[3]; + da = dst->data[3] + (y + i + slice_start) * dst->linesize[3]; - for (imax = FFMIN(-y + dst_h, src_h); i < imax; i++) { + for (i = i + slice_start; i < slice_end; i++) { j = FFMAX(-x, 0); s = sa + j; d = da + x+j; @@ -616,12 +598,13 @@ static inline void alpha_composite(const AVFrame *src, const AVFrame *dst, } } -static av_always_inline void blend_image_yuv(AVFilterContext *ctx, +static av_always_inline void blend_slice_yuv(AVFilterContext *ctx, AVFrame *dst, const AVFrame *src, int hsub, int vsub, int main_has_alpha, int x, int y, - int is_straight) + int is_straight, + int jobnr, int nb_jobs) { OverlayContext *s = ctx->priv; const int src_w = src->width; @@ -630,22 +613,27 @@ static av_always_inline void blend_image_yuv(AVFilterContext *ctx, const int dst_h = dst->height; blend_plane(ctx, dst, src, src_w, src_h, dst_w, dst_h, 0, 0, 0, x, y, main_has_alpha, - s->main_desc->comp[0].plane, s->main_desc->comp[0].offset, s->main_desc->comp[0].step, is_straight, 1); + s->main_desc->comp[0].plane, s->main_desc->comp[0].offset, s->main_desc->comp[0].step, is_straight, 1, + jobnr, nb_jobs); blend_plane(ctx, dst, src, src_w, src_h, dst_w, dst_h, 1, hsub, vsub, x, y, main_has_alpha, - s->main_desc->comp[1].plane, s->main_desc->comp[1].offset, s->main_desc->comp[1].step, is_straight, 1); + s->main_desc->comp[1].plane, s->main_desc->comp[1].offset, s->main_desc->comp[1].step, is_straight, 1, + jobnr, nb_jobs); blend_plane(ctx, dst, src, src_w, src_h, dst_w, dst_h, 2, hsub, vsub, x, y, main_has_alpha, - s->main_desc->comp[2].plane, s->main_desc->comp[2].offset, s->main_desc->comp[2].step, is_straight, 1); + s->main_desc->comp[2].plane, s->main_desc->comp[2].offset, s->main_desc->comp[2].step, is_straight, 1, + jobnr, nb_jobs); if (main_has_alpha) - alpha_composite(src, dst, src_w, src_h, dst_w, dst_h, x, y); + alpha_composite(src, dst, src_w, src_h, dst_w, dst_h, x, y, jobnr, nb_jobs); } -static av_always_inline void blend_image_planar_rgb(AVFilterContext *ctx, +static av_always_inline void blend_slice_planar_rgb(AVFilterContext *ctx, AVFrame *dst, const AVFrame *src, int hsub, int vsub, int main_has_alpha, int x, int y, - int is_straight) + int is_straight, + int jobnr, + int nb_jobs) { OverlayContext *s = ctx->priv; const int src_w = src->width; @@ -654,114 +642,177 @@ static av_always_inline void blend_image_planar_rgb(AVFilterContext *ctx, const int dst_h = dst->height; blend_plane(ctx, dst, src, src_w, src_h, dst_w, dst_h, 0, 0, 0, x, y, main_has_alpha, - s->main_desc->comp[1].plane, s->main_desc->comp[1].offset, s->main_desc->comp[1].step, is_straight, 0); + s->main_desc->comp[1].plane, s->main_desc->comp[1].offset, s->main_desc->comp[1].step, is_straight, 0, + jobnr, nb_jobs); blend_plane(ctx, dst, src, src_w, src_h, dst_w, dst_h, 1, hsub, vsub, x, y, main_has_alpha, - s->main_desc->comp[2].plane, s->main_desc->comp[2].offset, s->main_desc->comp[2].step, is_straight, 0); + s->main_desc->comp[2].plane, s->main_desc->comp[2].offset, s->main_desc->comp[2].step, is_straight, 0, + jobnr, nb_jobs); blend_plane(ctx, dst, src, src_w, src_h, dst_w, dst_h, 2, hsub, vsub, x, y, main_has_alpha, - s->main_desc->comp[0].plane, s->main_desc->comp[0].offset, s->main_desc->comp[0].step, is_straight, 0); + s->main_desc->comp[0].plane, s->main_desc->comp[0].offset, s->main_desc->comp[0].step, is_straight, 0, + jobnr, nb_jobs); if (main_has_alpha) - alpha_composite(src, dst, src_w, src_h, dst_w, dst_h, x, y); + alpha_composite(src, dst, src_w, src_h, dst_w, dst_h, x, y, jobnr, nb_jobs); } -static void blend_image_yuv420(AVFilterContext *ctx, AVFrame *dst, const AVFrame *src, int x, int y) +static int blend_slice_yuv420(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) { - blend_image_yuv(ctx, dst, src, 1, 1, 0, x, y, 1); + OverlayContext *s = ctx->priv; + ThreadData *td = arg; + blend_slice_yuv(ctx, td->dst, td->src, 1, 1, 0, s->x, s->y, 1, jobnr, nb_jobs); + return 0; } -static void blend_image_yuva420(AVFilterContext *ctx, AVFrame *dst, const AVFrame *src, int x, int y) +static int blend_slice_yuva420(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) { - blend_image_yuv(ctx, dst, src, 1, 1, 1, x, y, 1); + OverlayContext *s = ctx->priv; + ThreadData *td = arg; + blend_slice_yuv(ctx, td->dst, td->src, 1, 1, 1, s->x, s->y, 1, jobnr, nb_jobs); + return 0; } -static void blend_image_yuv422(AVFilterContext *ctx, AVFrame *dst, const AVFrame *src, int x, int y) +static int blend_slice_yuv422(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) { - blend_image_yuv(ctx, dst, src, 1, 0, 0, x, y, 1); + OverlayContext *s = ctx->priv; + ThreadData *td = arg; + blend_slice_yuv(ctx, td->dst, td->src, 1, 0, 0, s->x, s->y, 1, jobnr, nb_jobs); + return 0; } -static void blend_image_yuva422(AVFilterContext *ctx, AVFrame *dst, const AVFrame *src, int x, int y) +static int blend_slice_yuva422(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) { - blend_image_yuv(ctx, dst, src, 1, 0, 1, x, y, 1); + OverlayContext *s = ctx->priv; + ThreadData *td = arg; + blend_slice_yuv(ctx, td->dst, td->src, 1, 0, 1, s->x, s->y, 1, jobnr, nb_jobs); + return 0; } -static void blend_image_yuv444(AVFilterContext *ctx, AVFrame *dst, const AVFrame *src, int x, int y) +static int blend_slice_yuv444(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) { - blend_image_yuv(ctx, dst, src, 0, 0, 0, x, y, 1); + OverlayContext *s = ctx->priv; + ThreadData *td = arg; + blend_slice_yuv(ctx, td->dst, td->src, 0, 0, 0, s->x, s->y, 1, jobnr, nb_jobs); + return 0; } -static void blend_image_yuva444(AVFilterContext *ctx, AVFrame *dst, const AVFrame *src, int x, int y) +static int blend_slice_yuva444(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) { - blend_image_yuv(ctx, dst, src, 0, 0, 1, x, y, 1); + OverlayContext *s = ctx->priv; + ThreadData *td = arg; + blend_slice_yuv(ctx, td->dst, td->src, 0, 0, 1, s->x, s->y, 1, jobnr, nb_jobs); + return 0; } -static void blend_image_gbrp(AVFilterContext *ctx, AVFrame *dst, const AVFrame *src, int x, int y) +static int blend_slice_gbrp(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) { - blend_image_planar_rgb(ctx, dst, src, 0, 0, 0, x, y, 1); + OverlayContext *s = ctx->priv; + ThreadData *td = arg; + blend_slice_planar_rgb(ctx, td->dst, td->src, 0, 0, 0, s->x, s->y, 1, jobnr, nb_jobs); + return 0; } -static void blend_image_gbrap(AVFilterContext *ctx, AVFrame *dst, const AVFrame *src, int x, int y) +static int blend_slice_gbrap(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) { - blend_image_planar_rgb(ctx, dst, src, 0, 0, 1, x, y, 1); + OverlayContext *s = ctx->priv; + ThreadData *td = arg; + blend_slice_planar_rgb(ctx, td->dst, td->src, 0, 0, 1, s->x, s->y, 1, jobnr, nb_jobs); + return 0; } -static void blend_image_yuv420_pm(AVFilterContext *ctx, AVFrame *dst, const AVFrame *src, int x, int y) +static int blend_slice_yuv420_pm(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) { - blend_image_yuv(ctx, dst, src, 1, 1, 0, x, y, 0); + OverlayContext *s = ctx->priv; + ThreadData *td = arg; + blend_slice_yuv(ctx, td->dst, td->src, 1, 1, 0, s->x, s->y, 0, jobnr, nb_jobs); + return 0; } -static void blend_image_yuva420_pm(AVFilterContext *ctx, AVFrame *dst, const AVFrame *src, int x, int y) +static int blend_slice_yuva420_pm(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) { - blend_image_yuv(ctx, dst, src, 1, 1, 1, x, y, 0); + OverlayContext *s = ctx->priv; + ThreadData *td = arg; + blend_slice_yuv(ctx, td->dst, td->src, 1, 1, 1, s->x, s->y, 0, jobnr, nb_jobs); + return 0; } -static void blend_image_yuv422_pm(AVFilterContext *ctx, AVFrame *dst, const AVFrame *src, int x, int y) +static int blend_slice_yuv422_pm(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) { - blend_image_yuv(ctx, dst, src, 1, 0, 0, x, y, 0); + OverlayContext *s = ctx->priv; + ThreadData *td = arg; + blend_slice_yuv(ctx, td->dst, td->src, 1, 0, 0, s->x, s->y, 0, jobnr, nb_jobs); + return 0; } -static void blend_image_yuva422_pm(AVFilterContext *ctx, AVFrame *dst, const AVFrame *src, int x, int y) +static int blend_slice_yuva422_pm(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) { - blend_image_yuv(ctx, dst, src, 1, 0, 1, x, y, 0); + OverlayContext *s = ctx->priv; + ThreadData *td = arg; + blend_slice_yuv(ctx, td->dst, td->src, 1, 0, 1, s->x, s->y, 0, jobnr, nb_jobs); + return 0; } -static void blend_image_yuv444_pm(AVFilterContext *ctx, AVFrame *dst, const AVFrame *src, int x, int y) +static int blend_slice_yuv444_pm(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) { - blend_image_yuv(ctx, dst, src, 0, 0, 0, x, y, 0); + OverlayContext *s = ctx->priv; + ThreadData *td = arg; + blend_slice_yuv(ctx, td->dst, td->src, 0, 0, 0, s->x, s->y, 0, jobnr, nb_jobs); + return 0; } -static void blend_image_yuva444_pm(AVFilterContext *ctx, AVFrame *dst, const AVFrame *src, int x, int y) +static int blend_slice_yuva444_pm(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) { - blend_image_yuv(ctx, dst, src, 0, 0, 1, x, y, 0); + OverlayContext *s = ctx->priv; + ThreadData *td = arg; + blend_slice_yuv(ctx, td->dst, td->src, 0, 0, 1, s->x, s->y, 0, jobnr, nb_jobs); + return 0; } -static void blend_image_gbrp_pm(AVFilterContext *ctx, AVFrame *dst, const AVFrame *src, int x, int y) +static int blend_slice_gbrp_pm(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) { - blend_image_planar_rgb(ctx, dst, src, 0, 0, 0, x, y, 0); + OverlayContext *s = ctx->priv; + ThreadData *td = arg; + blend_slice_planar_rgb(ctx, td->dst, td->src, 0, 0, 0, s->x, s->y, 0, jobnr, nb_jobs); + return 0; } -static void blend_image_gbrap_pm(AVFilterContext *ctx, AVFrame *dst, const AVFrame *src, int x, int y) +static int blend_slice_gbrap_pm(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) { - blend_image_planar_rgb(ctx, dst, src, 0, 0, 1, x, y, 0); + OverlayContext *s = ctx->priv; + ThreadData *td = arg; + blend_slice_planar_rgb(ctx, td->dst, td->src, 0, 0, 1, s->x, s->y, 0, jobnr, nb_jobs); + return 0; } -static void blend_image_rgb(AVFilterContext *ctx, AVFrame *dst, const AVFrame *src, int x, int y) +static int blend_slice_rgb(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) { - blend_image_packed_rgb(ctx, dst, src, 0, x, y, 1); + OverlayContext *s = ctx->priv; + ThreadData *td = arg; + blend_slice_packed_rgb(ctx, td->dst, td->src, 0, s->x, s->y, 1, jobnr, nb_jobs); + return 0; } -static void blend_image_rgba(AVFilterContext *ctx, AVFrame *dst, const AVFrame *src, int x, int y) +static int blend_slice_rgba(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) { - blend_image_packed_rgb(ctx, dst, src, 1, x, y, 1); + OverlayContext *s = ctx->priv; + ThreadData *td = arg; + blend_slice_packed_rgb(ctx, td->dst, td->src, 1, s->x, s->y, 1, jobnr, nb_jobs); + return 0; } -static void blend_image_rgb_pm(AVFilterContext *ctx, AVFrame *dst, const AVFrame *src, int x, int y) +static int blend_slice_rgb_pm(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) { - blend_image_packed_rgb(ctx, dst, src, 0, x, y, 0); + OverlayContext *s = ctx->priv; + ThreadData *td = arg; + blend_slice_packed_rgb(ctx, td->dst, td->src, 0, s->x, s->y, 0, jobnr, nb_jobs); + return 0; } -static void blend_image_rgba_pm(AVFilterContext *ctx, AVFrame *dst, const AVFrame *src, int x, int y) +static int blend_slice_rgba_pm(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) { - blend_image_packed_rgb(ctx, dst, src, 1, x, y, 0); + OverlayContext *s = ctx->priv; + ThreadData *td = arg; + blend_slice_packed_rgb(ctx, td->dst, td->src, 1, s->x, s->y, 0, jobnr, nb_jobs); + return 0; } static int config_input_main(AVFilterLink *inlink) @@ -781,39 +832,39 @@ static int config_input_main(AVFilterLink *inlink) s->main_has_alpha = ff_fmt_is_in(inlink->format, alpha_pix_fmts); switch (s->format) { case OVERLAY_FORMAT_YUV420: - s->blend_image = s->main_has_alpha ? blend_image_yuva420 : blend_image_yuv420; + s->blend_slice = s->main_has_alpha ? blend_slice_yuva420 : blend_slice_yuv420; break; case OVERLAY_FORMAT_YUV422: - s->blend_image = s->main_has_alpha ? blend_image_yuva422 : blend_image_yuv422; + s->blend_slice = s->main_has_alpha ? blend_slice_yuva422 : blend_slice_yuv422; break; case OVERLAY_FORMAT_YUV444: - s->blend_image = s->main_has_alpha ? blend_image_yuva444 : blend_image_yuv444; + s->blend_slice = s->main_has_alpha ? blend_slice_yuva444 : blend_slice_yuv444; break; case OVERLAY_FORMAT_RGB: - s->blend_image = s->main_has_alpha ? blend_image_rgba : blend_image_rgb; + s->blend_slice = s->main_has_alpha ? blend_slice_rgba : blend_slice_rgb; break; case OVERLAY_FORMAT_GBRP: - s->blend_image = s->main_has_alpha ? blend_image_gbrap : blend_image_gbrp; + s->blend_slice = s->main_has_alpha ? blend_slice_gbrap : blend_slice_gbrp; break; case OVERLAY_FORMAT_AUTO: switch (inlink->format) { case AV_PIX_FMT_YUVA420P: - s->blend_image = blend_image_yuva420; + s->blend_slice = blend_slice_yuva420; break; case AV_PIX_FMT_YUVA422P: - s->blend_image = blend_image_yuva422; + s->blend_slice = blend_slice_yuva422; break; case AV_PIX_FMT_YUVA444P: - s->blend_image = blend_image_yuva444; + s->blend_slice = blend_slice_yuva444; break; case AV_PIX_FMT_ARGB: case AV_PIX_FMT_RGBA: case AV_PIX_FMT_BGRA: case AV_PIX_FMT_ABGR: - s->blend_image = blend_image_rgba; + s->blend_slice = blend_slice_rgba; break; case AV_PIX_FMT_GBRAP: - s->blend_image = blend_image_gbrap; + s->blend_slice = blend_slice_gbrap; break; default: av_assert0(0); @@ -823,43 +874,43 @@ static int config_input_main(AVFilterLink *inlink) } if (!s->alpha_format) - return 0; + goto end; switch (s->format) { case OVERLAY_FORMAT_YUV420: - s->blend_image = s->main_has_alpha ? blend_image_yuva420_pm : blend_image_yuv420_pm; + s->blend_slice = s->main_has_alpha ? blend_slice_yuva420_pm : blend_slice_yuv420_pm; break; case OVERLAY_FORMAT_YUV422: - s->blend_image = s->main_has_alpha ? blend_image_yuva422_pm : blend_image_yuv422_pm; + s->blend_slice = s->main_has_alpha ? blend_slice_yuva422_pm : blend_slice_yuv422_pm; break; case OVERLAY_FORMAT_YUV444: - s->blend_image = s->main_has_alpha ? blend_image_yuva444_pm : blend_image_yuv444_pm; + s->blend_slice = s->main_has_alpha ? blend_slice_yuva444_pm : blend_slice_yuv444_pm; break; case OVERLAY_FORMAT_RGB: - s->blend_image = s->main_has_alpha ? blend_image_rgba_pm : blend_image_rgb_pm; + s->blend_slice = s->main_has_alpha ? blend_slice_rgba_pm : blend_slice_rgb_pm; break; case OVERLAY_FORMAT_GBRP: - s->blend_image = s->main_has_alpha ? blend_image_gbrap_pm : blend_image_gbrp_pm; + s->blend_slice = s->main_has_alpha ? blend_slice_gbrap_pm : blend_slice_gbrp_pm; break; case OVERLAY_FORMAT_AUTO: switch (inlink->format) { case AV_PIX_FMT_YUVA420P: - s->blend_image = blend_image_yuva420_pm; + s->blend_slice = blend_slice_yuva420_pm; break; case AV_PIX_FMT_YUVA422P: - s->blend_image = blend_image_yuva422_pm; + s->blend_slice = blend_slice_yuva422_pm; break; case AV_PIX_FMT_YUVA444P: - s->blend_image = blend_image_yuva444_pm; + s->blend_slice = blend_slice_yuva444_pm; break; case AV_PIX_FMT_ARGB: case AV_PIX_FMT_RGBA: case AV_PIX_FMT_BGRA: case AV_PIX_FMT_ABGR: - s->blend_image = blend_image_rgba_pm; + s->blend_slice = blend_slice_rgba_pm; break; case AV_PIX_FMT_GBRAP: - s->blend_image = blend_image_gbrap_pm; + s->blend_slice = blend_slice_gbrap_pm; break; default: av_assert0(0); @@ -867,6 +918,12 @@ static int config_input_main(AVFilterLink *inlink) } break; } + +end: + if (ARCH_X86) + ff_overlay_init_x86(s, s->format, inlink->format, + s->alpha_format, s->main_has_alpha); + return 0; } @@ -904,9 +961,15 @@ static int do_blend(FFFrameSync *fs) s->var_values[VAR_Y], s->y); } - if (s->x < mainpic->width && s->x + second->width >= 0 || - s->y < mainpic->height && s->y + second->height >= 0) - s->blend_image(ctx, mainpic, second, s->x, s->y); + if (s->x < mainpic->width && s->x + second->width >= 0 && + s->y < mainpic->height && s->y + second->height >= 0) { + ThreadData td; + + td.dst = mainpic; + td.src = second; + ctx->internal->execute(ctx, s->blend_slice, &td, NULL, FFMIN(FFMAX(1, FFMIN3(s->y + second->height, FFMIN(second->height, mainpic->height), mainpic->height - s->y)), + ff_filter_get_nb_threads(ctx))); + } return ff_filter_frame(ctx->outputs[0], mainpic); } @@ -992,5 +1055,6 @@ AVFilter ff_vf_overlay = { .process_command = process_command, .inputs = avfilter_vf_overlay_inputs, .outputs = avfilter_vf_overlay_outputs, - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, + .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | + AVFILTER_FLAG_SLICE_THREADS, }; diff --git a/libavfilter/vf_overlay.h b/libavfilter/vf_overlay.h new file mode 100644 index 000000000..98b06eaac --- /dev/null +++ b/libavfilter/vf_overlay.h @@ -0,0 +1,86 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVFILTER_OVERLAY_H +#define AVFILTER_OVERLAY_H + +#include "libavutil/eval.h" +#include "libavutil/pixdesc.h" +#include "framesync.h" +#include "avfilter.h" + +enum var_name { + VAR_MAIN_W, VAR_MW, + VAR_MAIN_H, VAR_MH, + VAR_OVERLAY_W, VAR_OW, + VAR_OVERLAY_H, VAR_OH, + VAR_HSUB, + VAR_VSUB, + VAR_X, + VAR_Y, + VAR_N, + VAR_POS, + VAR_T, + VAR_VARS_NB +}; + +enum OverlayFormat { + OVERLAY_FORMAT_YUV420, + OVERLAY_FORMAT_YUV422, + OVERLAY_FORMAT_YUV444, + OVERLAY_FORMAT_RGB, + OVERLAY_FORMAT_GBRP, + OVERLAY_FORMAT_AUTO, + OVERLAY_FORMAT_NB +}; + +typedef struct OverlayContext { + const AVClass *class; + int x, y; ///< position of overlaid picture + + uint8_t main_is_packed_rgb; + uint8_t main_rgba_map[4]; + uint8_t main_has_alpha; + uint8_t overlay_is_packed_rgb; + uint8_t overlay_rgba_map[4]; + uint8_t overlay_has_alpha; + int format; ///< OverlayFormat + int alpha_format; + int eval_mode; ///< EvalMode + + FFFrameSync fs; + + int main_pix_step[4]; ///< steps per pixel for each plane of the main output + int overlay_pix_step[4]; ///< steps per pixel for each plane of the overlay + int hsub, vsub; ///< chroma subsampling values + const AVPixFmtDescriptor *main_desc; ///< format descriptor for main input + + double var_values[VAR_VARS_NB]; + char *x_expr, *y_expr; + + AVExpr *x_pexpr, *y_pexpr; + + int (*blend_row[4])(uint8_t *d, uint8_t *da, uint8_t *s, uint8_t *a, int w, + ptrdiff_t alinesize); + int (*blend_slice)(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs); +} OverlayContext; + +void ff_overlay_init_x86(OverlayContext *s, int format, int pix_format, + int alpha_format, int main_has_alpha); + +#endif /* AVFILTER_OVERLAY_H */ diff --git a/libavfilter/vf_overlay_opencl.c b/libavfilter/vf_overlay_opencl.c index b43050df5..e9c853203 100644 --- a/libavfilter/vf_overlay_opencl.c +++ b/libavfilter/vf_overlay_opencl.c @@ -100,19 +100,11 @@ static int overlay_opencl_load(AVFilterContext *avctx, ctx->command_queue = clCreateCommandQueue(ctx->ocf.hwctx->context, ctx->ocf.hwctx->device_id, 0, &cle); - if (!ctx->command_queue) { - av_log(avctx, AV_LOG_ERROR, "Failed to create OpenCL " - "command queue: %d.\n", cle); - err = AVERROR(EIO); - goto fail; - } + CL_FAIL_ON_ERROR(AVERROR(EIO), "Failed to create OpenCL " + "command queue %d.\n", cle); ctx->kernel = clCreateKernel(ctx->ocf.program, kernel, &cle); - if (!ctx->kernel) { - av_log(avctx, AV_LOG_ERROR, "Failed to create kernel: %d.\n", cle); - err = AVERROR(EIO); - goto fail; - } + CL_FAIL_ON_ERROR(AVERROR(EIO), "Failed to create kernel %d.\n", cle); ctx->initialised = 1; return 0; @@ -167,47 +159,39 @@ static int overlay_opencl_blend(FFFrameSync *fs) kernel_arg = 0; mem = (cl_mem)output->data[plane]; - cle = clSetKernelArg(ctx->kernel, kernel_arg++, sizeof(cl_mem), &mem); - if (cle != CL_SUCCESS) - goto fail_kernel_arg; + CL_SET_KERNEL_ARG(ctx->kernel, kernel_arg, cl_mem, &mem); + kernel_arg++; mem = (cl_mem)input_main->data[plane]; - cle = clSetKernelArg(ctx->kernel, kernel_arg++, sizeof(cl_mem), &mem); - if (cle != CL_SUCCESS) - goto fail_kernel_arg; + CL_SET_KERNEL_ARG(ctx->kernel, kernel_arg, cl_mem, &mem); + kernel_arg++; mem = (cl_mem)input_overlay->data[plane]; - cle = clSetKernelArg(ctx->kernel, kernel_arg++, sizeof(cl_mem), &mem); - if (cle != CL_SUCCESS) - goto fail_kernel_arg; + CL_SET_KERNEL_ARG(ctx->kernel, kernel_arg, cl_mem, &mem); + kernel_arg++; if (ctx->alpha_separate) { mem = (cl_mem)input_overlay->data[ctx->nb_planes]; - cle = clSetKernelArg(ctx->kernel, kernel_arg++, sizeof(cl_mem), &mem); - if (cle != CL_SUCCESS) - goto fail_kernel_arg; + CL_SET_KERNEL_ARG(ctx->kernel, kernel_arg, cl_mem, &mem); + kernel_arg++; } x = ctx->x_position / (plane == 0 ? 1 : ctx->x_subsample); y = ctx->y_position / (plane == 0 ? 1 : ctx->y_subsample); - cle = clSetKernelArg(ctx->kernel, kernel_arg++, sizeof(cl_int), &x); - if (cle != CL_SUCCESS) - goto fail_kernel_arg; - cle = clSetKernelArg(ctx->kernel, kernel_arg++, sizeof(cl_int), &y); - if (cle != CL_SUCCESS) - goto fail_kernel_arg; + CL_SET_KERNEL_ARG(ctx->kernel, kernel_arg, cl_int, &x); + kernel_arg++; + CL_SET_KERNEL_ARG(ctx->kernel, kernel_arg, cl_int, &y); + kernel_arg++; if (ctx->alpha_separate) { cl_int alpha_adj_x = plane == 0 ? 1 : ctx->x_subsample; cl_int alpha_adj_y = plane == 0 ? 1 : ctx->y_subsample; - cle = clSetKernelArg(ctx->kernel, kernel_arg++, sizeof(cl_int), &alpha_adj_x); - if (cle != CL_SUCCESS) - goto fail_kernel_arg; - cle = clSetKernelArg(ctx->kernel, kernel_arg++, sizeof(cl_int), &alpha_adj_y); - if (cle != CL_SUCCESS) - goto fail_kernel_arg; + CL_SET_KERNEL_ARG(ctx->kernel, kernel_arg, cl_int, &alpha_adj_x); + kernel_arg++; + CL_SET_KERNEL_ARG(ctx->kernel, kernel_arg, cl_int, &alpha_adj_y); + kernel_arg++; } err = ff_opencl_filter_work_size_from_image(avctx, global_work, @@ -217,21 +201,12 @@ static int overlay_opencl_blend(FFFrameSync *fs) cle = clEnqueueNDRangeKernel(ctx->command_queue, ctx->kernel, 2, NULL, global_work, NULL, 0, NULL, NULL); - if (cle != CL_SUCCESS) { - av_log(avctx, AV_LOG_ERROR, "Failed to enqueue " - "overlay kernel for plane %d: %d.\n", cle, plane); - err = AVERROR(EIO); - goto fail; - } + CL_FAIL_ON_ERROR(AVERROR(EIO), "Failed to enqueue overlay kernel " + "for plane %d: %d.\n", plane, cle); } cle = clFinish(ctx->command_queue); - if (cle != CL_SUCCESS) { - av_log(avctx, AV_LOG_ERROR, "Failed to finish " - "command queue: %d.\n", cle); - err = AVERROR(EIO); - goto fail; - } + CL_FAIL_ON_ERROR(AVERROR(EIO), "Failed to finish command queue: %d.\n", cle); err = av_frame_copy_props(output, input_main); @@ -241,10 +216,6 @@ static int overlay_opencl_blend(FFFrameSync *fs) return ff_filter_frame(outlink, output); -fail_kernel_arg: - av_log(avctx, AV_LOG_ERROR, "Failed to set kernel arg %d: %d.\n", - kernel_arg, cle); - err = AVERROR(EIO); fail: av_frame_free(&output); return err; diff --git a/libavfilter/vf_overlay_qsv.c b/libavfilter/vf_overlay_qsv.c index 20871786e..2a4dc5cb5 100644 --- a/libavfilter/vf_overlay_qsv.c +++ b/libavfilter/vf_overlay_qsv.c @@ -160,7 +160,7 @@ release: static int have_alpha_planar(AVFilterLink *link) { - enum AVPixelFormat pix_fmt; + enum AVPixelFormat pix_fmt = link->format; const AVPixFmtDescriptor *desc; AVHWFramesContext *fctx; @@ -345,7 +345,7 @@ static int overlay_qsv_init(AVFilterContext *ctx) return 0; } -static void overlay_qsv_uninit(AVFilterContext *ctx) +static av_cold void overlay_qsv_uninit(AVFilterContext *ctx) { QSVOverlayContext *vpp = ctx->priv; diff --git a/libavfilter/vf_palettegen.c b/libavfilter/vf_palettegen.c index 5ff73e6b2..44323782d 100644 --- a/libavfilter/vf_palettegen.c +++ b/libavfilter/vf_palettegen.c @@ -245,7 +245,7 @@ static void write_palette(AVFilterContext *ctx, AVFrame *out) av_log(ctx, AV_LOG_WARNING, "Dupped color: %08"PRIX32"\n", pal[x]); last_color = pal[x]; } else { - pal[x] = 0xff000000; // pad with black + pal[x] = last_color; // pad with last color } } pal += pal_linesize; diff --git a/libavfilter/vf_paletteuse.c b/libavfilter/vf_paletteuse.c index 604a8af29..ed128813d 100644 --- a/libavfilter/vf_paletteuse.c +++ b/libavfilter/vf_paletteuse.c @@ -119,7 +119,7 @@ static const AVOption paletteuse_options[] = { { "diff_mode", "set frame difference mode", OFFSET(diff_mode), AV_OPT_TYPE_INT, {.i64=DIFF_MODE_NONE}, 0, NB_DIFF_MODE-1, FLAGS, "diff_mode" }, { "rectangle", "process smallest different rectangle", 0, AV_OPT_TYPE_CONST, {.i64=DIFF_MODE_RECTANGLE}, INT_MIN, INT_MAX, FLAGS, "diff_mode" }, { "new", "take new palette for each output frame", OFFSET(new), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS }, - { "alpha_threshold", "set the alpha threshold for transparency", OFFSET(trans_thresh), AV_OPT_TYPE_INT, {.i64=128}, 0, 255 }, + { "alpha_threshold", "set the alpha threshold for transparency", OFFSET(trans_thresh), AV_OPT_TYPE_INT, {.i64=128}, 0, 255, FLAGS }, /* following are the debug options, not part of the official API */ { "debug_kdtree", "save Graphviz graph of the kdtree in specified file", OFFSET(dot_filename), AV_OPT_TYPE_STRING, {.str=NULL}, CHAR_MIN, CHAR_MAX, FLAGS }, @@ -814,7 +814,7 @@ static void set_processing_window(enum diff_mode diff_mode, int width = cur_src->width; int height = cur_src->height; - if (prv_src && diff_mode == DIFF_MODE_RECTANGLE) { + if (prv_src->data[0] && diff_mode == DIFF_MODE_RECTANGLE) { int y; int x_end = cur_src->width - 1, y_end = cur_src->height - 1; @@ -911,11 +911,10 @@ static int apply_palette(AVFilterLink *inlink, AVFrame *in, AVFrame **outf) set_processing_window(s->diff_mode, s->last_in, in, s->last_out, out, &x, &y, &w, &h); - av_frame_free(&s->last_in); - av_frame_free(&s->last_out); - s->last_in = av_frame_clone(in); - s->last_out = av_frame_clone(out); - if (!s->last_in || !s->last_out || + av_frame_unref(s->last_in); + av_frame_unref(s->last_out); + if (av_frame_ref(s->last_in, in) < 0 || + av_frame_ref(s->last_out, out) < 0 || av_frame_make_writable(s->last_in) < 0) { av_frame_free(&in); av_frame_free(&out); @@ -1086,6 +1085,14 @@ static av_cold int init(AVFilterContext *ctx) { PaletteUseContext *s = ctx->priv; + s->last_in = av_frame_alloc(); + s->last_out = av_frame_alloc(); + if (!s->last_in || !s->last_out) { + av_frame_free(&s->last_in); + av_frame_free(&s->last_out); + return AVERROR(ENOMEM); + } + s->set_frame = set_frame_lut[s->color_search_method][s->dither]; if (s->dither == DITHERING_BAYER) { diff --git a/libavfilter/vf_pixdesctest.c b/libavfilter/vf_pixdesctest.c index 2d0749e20..680d1a772 100644 --- a/libavfilter/vf_pixdesctest.c +++ b/libavfilter/vf_pixdesctest.c @@ -31,7 +31,7 @@ typedef struct PixdescTestContext { const AVPixFmtDescriptor *pix_desc; - uint16_t *line; + uint32_t *line; } PixdescTestContext; static av_cold void uninit(AVFilterContext *ctx) @@ -89,17 +89,17 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) const int h1 = c == 1 || c == 2 ? ch : h; for (i = 0; i < h1; i++) { - av_read_image_line(priv->line, + av_read_image_line2(priv->line, (void*)in->data, in->linesize, priv->pix_desc, - 0, i, c, w1, 0); + 0, i, c, w1, 0, 4); - av_write_image_line(priv->line, + av_write_image_line2(priv->line, out->data, out->linesize, priv->pix_desc, - 0, i, c, w1); + 0, i, c, w1, 4); } } diff --git a/libavfilter/vf_premultiply.c b/libavfilter/vf_premultiply.c index 4f250df3f..a9404b4eb 100644 --- a/libavfilter/vf_premultiply.c +++ b/libavfilter/vf_premultiply.c @@ -28,6 +28,10 @@ #include "internal.h" #include "video.h" +typedef struct ThreadData { + AVFrame *m, *a, *d; +} ThreadData; + typedef struct PreMultiplyContext { const AVClass *class; int width[4], height[4]; @@ -70,7 +74,7 @@ static int query_formats(AVFilterContext *ctx) AV_PIX_FMT_YUV444P16, AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRP9, AV_PIX_FMT_GBRP10, AV_PIX_FMT_GBRP12, AV_PIX_FMT_GBRP14, AV_PIX_FMT_GBRP16, - AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY9, AV_PIX_FMT_GRAY10, AV_PIX_FMT_GRAY12, AV_PIX_FMT_GRAY16, + AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY9, AV_PIX_FMT_GRAY10, AV_PIX_FMT_GRAY12, AV_PIX_FMT_GRAY14, AV_PIX_FMT_GRAY16, AV_PIX_FMT_NONE }; @@ -361,6 +365,41 @@ static void unpremultiply16offset(const uint8_t *mmsrc, const uint8_t *aasrc, } } +static int premultiply_slice(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) +{ + PreMultiplyContext *s = ctx->priv; + ThreadData *td = arg; + AVFrame *out = td->d; + AVFrame *alpha = td->a; + AVFrame *base = td->m; + int p; + + for (p = 0; p < s->nb_planes; p++) { + const int slice_start = (s->height[p] * jobnr) / nb_jobs; + const int slice_end = (s->height[p] * (jobnr+1)) / nb_jobs; + + if (!((1 << p) & s->planes) || p == 3) { + av_image_copy_plane(out->data[p] + slice_start * out->linesize[p], + out->linesize[p], + base->data[p] + slice_start * base->linesize[p], + base->linesize[p], + s->linesize[p], slice_end - slice_start); + continue; + } + + s->premultiply[p](base->data[p] + slice_start * base->linesize[p], + s->inplace ? alpha->data[3] + slice_start * alpha->linesize[3] : + alpha->data[0] + slice_start * alpha->linesize[0], + out->data[p] + slice_start * out->linesize[p], + base->linesize[p], s->inplace ? alpha->linesize[3] : alpha->linesize[0], + out->linesize[p], + s->width[p], slice_end - slice_start, + s->half, s->inverse ? s->max : s->depth, s->offset); + } + + return 0; +} + static int filter_frame(AVFilterContext *ctx, AVFrame **out, AVFrame *base, AVFrame *alpha) { @@ -372,7 +411,8 @@ static int filter_frame(AVFilterContext *ctx, if (!*out) return AVERROR(ENOMEM); } else { - int p, full, limited; + ThreadData td; + int full, limited; *out = ff_get_video_buffer(outlink, outlink->w, outlink->h); if (!*out) @@ -424,6 +464,7 @@ static int filter_frame(AVFilterContext *ctx, case AV_PIX_FMT_GRAY9: case AV_PIX_FMT_GRAY10: case AV_PIX_FMT_GRAY12: + case AV_PIX_FMT_GRAY14: case AV_PIX_FMT_GRAY16: s->premultiply[0] = limited ? unpremultiply16offset : unpremultiply16; break; @@ -470,26 +511,18 @@ static int filter_frame(AVFilterContext *ctx, case AV_PIX_FMT_GRAY9: case AV_PIX_FMT_GRAY10: case AV_PIX_FMT_GRAY12: + case AV_PIX_FMT_GRAY14: case AV_PIX_FMT_GRAY16: s->premultiply[0] = limited ? premultiply16offset : premultiply16; break; } } - for (p = 0; p < s->nb_planes; p++) { - if (!((1 << p) & s->planes) || p == 3) { - av_image_copy_plane((*out)->data[p], (*out)->linesize[p], base->data[p], base->linesize[p], - s->linesize[p], s->height[p]); - continue; - } - - s->premultiply[p](base->data[p], s->inplace ? alpha->data[3] : alpha->data[0], - (*out)->data[p], - base->linesize[p], s->inplace ? alpha->linesize[3] : alpha->linesize[0], - (*out)->linesize[p], - s->width[p], s->height[p], - s->half, s->inverse ? s->max : s->depth, s->offset); - } + td.d = *out; + td.a = alpha; + td.m = base; + ctx->internal->execute(ctx, premultiply_slice, &td, NULL, FFMIN(s->height[0], + ff_filter_get_nb_threads(ctx))); } return 0; @@ -695,7 +728,8 @@ AVFilter ff_vf_premultiply = { .outputs = premultiply_outputs, .priv_class = &premultiply_class, .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | - AVFILTER_FLAG_DYNAMIC_INPUTS, + AVFILTER_FLAG_DYNAMIC_INPUTS | + AVFILTER_FLAG_SLICE_THREADS, }; #endif /* CONFIG_PREMULTIPLY_FILTER */ @@ -717,7 +751,8 @@ AVFilter ff_vf_unpremultiply = { .outputs = premultiply_outputs, .priv_class = &unpremultiply_class, .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | - AVFILTER_FLAG_DYNAMIC_INPUTS, + AVFILTER_FLAG_DYNAMIC_INPUTS | + AVFILTER_FLAG_SLICE_THREADS, }; #endif /* CONFIG_UNPREMULTIPLY_FILTER */ diff --git a/libavfilter/vf_procamp_vaapi.c b/libavfilter/vf_procamp_vaapi.c index 10eccbe97..c3e9866f2 100644 --- a/libavfilter/vf_procamp_vaapi.c +++ b/libavfilter/vf_procamp_vaapi.c @@ -131,9 +131,7 @@ static int procamp_vaapi_filter_frame(AVFilterLink *inlink, AVFrame *input_frame AVFilterLink *outlink = avctx->outputs[0]; VAAPIVPPContext *vpp_ctx = avctx->priv; AVFrame *output_frame = NULL; - VASurfaceID input_surface, output_surface; VAProcPipelineParameterBuffer params; - VARectangle input_region; int err; av_log(avctx, AV_LOG_DEBUG, "Filter input: %s, %ux%u (%"PRId64").\n", @@ -143,10 +141,6 @@ static int procamp_vaapi_filter_frame(AVFilterLink *inlink, AVFrame *input_frame if (vpp_ctx->va_context == VA_INVALID_ID) return AVERROR(EINVAL); - input_surface = (VASurfaceID)(uintptr_t)input_frame->data[3]; - av_log(avctx, AV_LOG_DEBUG, "Using surface %#x for procamp input.\n", - input_surface); - output_frame = ff_get_video_buffer(outlink, vpp_ctx->output_width, vpp_ctx->output_height); if (!output_frame) { @@ -154,39 +148,22 @@ static int procamp_vaapi_filter_frame(AVFilterLink *inlink, AVFrame *input_frame goto fail; } - output_surface = (VASurfaceID)(uintptr_t)output_frame->data[3]; - av_log(avctx, AV_LOG_DEBUG, "Using surface %#x for procamp output.\n", - output_surface); - memset(¶ms, 0, sizeof(params)); - input_region = (VARectangle) { - .x = 0, - .y = 0, - .width = input_frame->width, - .height = input_frame->height, - }; + err = av_frame_copy_props(output_frame, input_frame); + if (err < 0) + return err; - params.surface = input_surface; - params.surface_region = &input_region; - params.surface_color_standard = - ff_vaapi_vpp_colour_standard(input_frame->colorspace); - - params.output_region = NULL; - params.output_background_color = 0xff000000; - params.output_color_standard = params.surface_color_standard; - - params.pipeline_flags = 0; - params.filter_flags = VA_FRAME_PICTURE; + err = ff_vaapi_vpp_init_params(avctx, ¶ms, + input_frame, output_frame); + if (err < 0) + goto fail; params.filters = &vpp_ctx->filter_buffers[0]; params.num_filters = 1; - err = ff_vaapi_vpp_render_picture(avctx, ¶ms, output_surface); + err = ff_vaapi_vpp_render_picture(avctx, ¶ms, output_frame); if (err < 0) goto fail; - err = av_frame_copy_props(output_frame, input_frame); - if (err < 0) - goto fail; av_frame_free(&input_frame); av_log(avctx, AV_LOG_DEBUG, "Filter output: %s, %ux%u (%"PRId64").\n", diff --git a/libavfilter/vf_program_opencl.c b/libavfilter/vf_program_opencl.c index a0027923f..ec25e931f 100644 --- a/libavfilter/vf_program_opencl.c +++ b/libavfilter/vf_program_opencl.c @@ -144,25 +144,16 @@ static int program_opencl_run(AVFilterContext *avctx) goto fail; av_log(avctx, AV_LOG_DEBUG, "Run kernel on plane %d " - "(%zux%zu).\n", plane, global_work[0], global_work[1]); + "(%"SIZE_SPECIFIER"x%"SIZE_SPECIFIER").\n", + plane, global_work[0], global_work[1]); cle = clEnqueueNDRangeKernel(ctx->command_queue, ctx->kernel, 2, NULL, global_work, NULL, 0, NULL, NULL); - if (cle != CL_SUCCESS) { - av_log(avctx, AV_LOG_ERROR, "Failed to enqueue kernel: %d.\n", - cle); - err = AVERROR(EIO); - goto fail; - } + CL_FAIL_ON_ERROR(AVERROR(EIO), "Failed to enqueue kernel: %d.\n", cle); } cle = clFinish(ctx->command_queue); - if (cle != CL_SUCCESS) { - av_log(avctx, AV_LOG_ERROR, "Failed to finish command queue: %d.\n", - cle); - err = AVERROR(EIO); - goto fail; - } + CL_FAIL_ON_ERROR(AVERROR(EIO), "Failed to finish command queue: %d.\n", cle); if (ctx->nb_inputs > 0) { err = av_frame_copy_props(output, ctx->frames[0]); diff --git a/libavfilter/vf_pseudocolor.c b/libavfilter/vf_pseudocolor.c index 2e7a3a95f..e48b69c08 100644 --- a/libavfilter/vf_pseudocolor.c +++ b/libavfilter/vf_pseudocolor.c @@ -94,7 +94,7 @@ static const AVOption pseudocolor_options[] = { }; static const enum AVPixelFormat pix_fmts[] = { - AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY9, AV_PIX_FMT_GRAY10, AV_PIX_FMT_GRAY12, AV_PIX_FMT_GRAY16, + AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY9, AV_PIX_FMT_GRAY10, AV_PIX_FMT_GRAY12, AV_PIX_FMT_GRAY14, AV_PIX_FMT_GRAY16, AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUVA420P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUVA422P, AV_PIX_FMT_YUV444P, AV_PIX_FMT_GBRP, @@ -545,6 +545,7 @@ static int config_input(AVFilterLink *inlink) case AV_PIX_FMT_GRAY9: case AV_PIX_FMT_GRAY10: case AV_PIX_FMT_GRAY12: + case AV_PIX_FMT_GRAY14: case AV_PIX_FMT_GRAY16: s->filter[0] = s->filter[1] = s->filter[2] = s->filter[3] = pseudocolor_filter_16; break; diff --git a/libavfilter/vf_psnr.c b/libavfilter/vf_psnr.c index 153d694b7..0675a17c5 100644 --- a/libavfilter/vf_psnr.c +++ b/libavfilter/vf_psnr.c @@ -260,7 +260,7 @@ static av_cold int init(AVFilterContext *ctx) static int query_formats(AVFilterContext *ctx) { static const enum AVPixelFormat pix_fmts[] = { - AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY9, AV_PIX_FMT_GRAY10, AV_PIX_FMT_GRAY12, AV_PIX_FMT_GRAY16, + AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY9, AV_PIX_FMT_GRAY10, AV_PIX_FMT_GRAY12, AV_PIX_FMT_GRAY14, AV_PIX_FMT_GRAY16, #define PF_NOALPHA(suf) AV_PIX_FMT_YUV420##suf, AV_PIX_FMT_YUV422##suf, AV_PIX_FMT_YUV444##suf #define PF_ALPHA(suf) AV_PIX_FMT_YUVA420##suf, AV_PIX_FMT_YUVA422##suf, AV_PIX_FMT_YUVA444##suf #define PF(suf) PF_NOALPHA(suf), PF_ALPHA(suf) diff --git a/libavfilter/vf_readeia608.c b/libavfilter/vf_readeia608.c index bc3abe7c4..27a0c5832 100644 --- a/libavfilter/vf_readeia608.c +++ b/libavfilter/vf_readeia608.c @@ -51,6 +51,8 @@ typedef struct ReadEIA608Context { int black; float mpd, mhd, msd, mac, spw, bhd, wth, bth; int chp; + int lp; + uint8_t *temp; } ReadEIA608Context; #define OFFSET(x) offsetof(ReadEIA608Context, x) @@ -68,6 +70,7 @@ static const AVOption readeia608_options[] = { { "th_w", "set white color threshold", OFFSET(wth), AV_OPT_TYPE_FLOAT, {.dbl=.35}, 0.1, 1, FLAGS }, { "th_b", "set black color threshold", OFFSET(bth), AV_OPT_TYPE_FLOAT, {.dbl=.15}, 0, 0.5, FLAGS }, { "chp", "check and apply parity bit", OFFSET(chp), AV_OPT_TYPE_BOOL, {.i64= 0}, 0, 1, FLAGS }, + { "lp", "lowpass line prior to processing", OFFSET(lp), AV_OPT_TYPE_BOOL, {.i64= 0}, 0, 1, FLAGS }, { NULL } }; @@ -114,6 +117,9 @@ static int config_input(AVFilterLink *inlink) s->max_start_diff = s->msd * ((1 << depth) - 1); s->white = s->wth * ((1 << depth) - 1); s->black = s->bth * ((1 << depth) - 1); + s->temp = av_calloc(inlink->w, sizeof(*s->temp)); + if (!s->temp) + return AVERROR(ENOMEM); return 0; } @@ -132,6 +138,25 @@ static void extract_line(AVFilterContext *ctx, AVFilterLink *inlink, AVFrame *in int s1, s2, s3, parity; src = &in->data[0][line * in->linesize[0]]; + + if (s->lp) { + uint8_t *dst = s->temp; + int w = inlink->w - 1; + + for (i = 0; i < inlink->w; i++) { + int a = FFMAX(i - 3, 0); + int b = FFMAX(i - 2, 0); + int c = FFMAX(i - 1, 0); + int d = FFMIN(i + 3, w); + int e = FFMIN(i + 2, w); + int f = FFMIN(i + 1, w); + + dst[i] = (src[a] + src[b] + src[c] + src[i] + src[d] + src[e] + src[f] + 6) / 7; + } + + src = s->temp; + } + for (i = 0; i < sync_width; i++) { max = FFMAX(max, src[i]); min = FFMIN(min, src[i]); @@ -163,14 +188,18 @@ static void extract_line(AVFilterContext *ctx, AVFilterLink *inlink, AVFrame *in last = Y; } - if (peaks != 7) + if (peaks != 7) { + av_log(ctx, AV_LOG_DEBUG, "peaks: %d != 7\n", peaks); return; + } for (i = 1; i < 7; i++) max_peak_diff = FFMAX(max_peak_diff, FFABS(clock[i][0] - clock[i-1][0])); - if (max_peak_diff > s->max_peak_diff) + if (max_peak_diff > s->max_peak_diff) { + av_log(ctx, AV_LOG_DEBUG, "mhd: %d > %d\n", max_peak_diff, s->max_peak_diff); return; + } max = 0; min = INT_MAX; for (i = 1; i < 7; i++) { @@ -179,15 +208,19 @@ static void extract_line(AVFilterContext *ctx, AVFilterLink *inlink, AVFrame *in } range = max - min; - if (range > s->max_period_diff) + if (range > s->max_period_diff) { + av_log(ctx, AV_LOG_DEBUG, "mpd: %d > %d\n", range, s->max_period_diff); return; + } s1 = src[sync_width + width_per_bit * 0 + width_per_bit / 2]; s2 = src[sync_width + width_per_bit * 1 + width_per_bit / 2]; s3 = src[sync_width + width_per_bit * 2 + width_per_bit / 2]; - if (FFABS(s1 - s2) > s->max_start_diff || s1 > s->black || s2 > s->black || s3 < s->white) + if (FFABS(s1 - s2) > s->max_start_diff || s1 > s->black || s2 > s->black || s3 < s->white) { + av_log(ctx, AV_LOG_DEBUG, "msd: %d > %d\n", FFABS(s1 - s2), s->max_start_diff); return; + } for (ch = 0; ch < 2; ch++) { for (parity = 0, i = 0; i < 8; i++) { @@ -238,6 +271,13 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) return ff_filter_frame(outlink, in); } +static av_cold void uninit(AVFilterContext *ctx) +{ + ReadEIA608Context *s = ctx->priv; + + av_freep(&s->temp); +} + static const AVFilterPad readeia608_inputs[] = { { .name = "default", @@ -264,5 +304,6 @@ AVFilter ff_vf_readeia608 = { .query_formats = query_formats, .inputs = readeia608_inputs, .outputs = readeia608_outputs, + .uninit = uninit, .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC, }; diff --git a/libavfilter/vf_remap.c b/libavfilter/vf_remap.c index d24284703..b1c3e4324 100644 --- a/libavfilter/vf_remap.c +++ b/libavfilter/vf_remap.c @@ -47,27 +47,39 @@ typedef struct RemapContext { const AVClass *class; + int format; + int nb_planes; int nb_components; int step; + FFFrameSync fs; - void (*remap)(struct RemapContext *s, const AVFrame *in, - const AVFrame *xin, const AVFrame *yin, - AVFrame *out); + int (*remap_slice)(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs); } RemapContext; #define OFFSET(x) offsetof(RemapContext, x) #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM static const AVOption remap_options[] = { + { "format", "set output format", OFFSET(format), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, FLAGS, "format" }, + { "color", "", 0, AV_OPT_TYPE_CONST, {.i64=0}, .flags = FLAGS, .unit = "format" }, + { "gray", "", 0, AV_OPT_TYPE_CONST, {.i64=1}, .flags = FLAGS, .unit = "format" }, { NULL } }; AVFILTER_DEFINE_CLASS(remap); +typedef struct ThreadData { + AVFrame *in, *xin, *yin, *out; + int nb_planes; + int nb_components; + int step; +} ThreadData; + static int query_formats(AVFilterContext *ctx) { + RemapContext *s = ctx->priv; static const enum AVPixelFormat pix_fmts[] = { AV_PIX_FMT_YUVA444P, AV_PIX_FMT_YUV444P, @@ -83,9 +95,12 @@ static int query_formats(AVFilterContext *ctx) AV_PIX_FMT_GBRAP10, AV_PIX_FMT_GBRAP12, AV_PIX_FMT_GBRAP16, AV_PIX_FMT_RGB48, AV_PIX_FMT_BGR48, AV_PIX_FMT_RGBA64, AV_PIX_FMT_BGRA64, + AV_PIX_FMT_NONE + }; + static const enum AVPixelFormat gray_pix_fmts[] = { AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY9, AV_PIX_FMT_GRAY10, AV_PIX_FMT_GRAY12, - AV_PIX_FMT_GRAY16, + AV_PIX_FMT_GRAY14, AV_PIX_FMT_GRAY16, AV_PIX_FMT_NONE }; static const enum AVPixelFormat map_fmts[] = { @@ -95,7 +110,7 @@ static int query_formats(AVFilterContext *ctx) AVFilterFormats *pix_formats = NULL, *map_formats = NULL; int ret; - if (!(pix_formats = ff_make_format_list(pix_fmts)) || + if (!(pix_formats = ff_make_format_list(s->format ? gray_pix_fmts : pix_fmts)) || !(map_formats = ff_make_format_list(map_fmts))) { ret = AVERROR(ENOMEM); goto fail; @@ -121,67 +136,48 @@ fail: * pixels are copied from source to target using : * Target_frame[y][x] = Source_frame[ ymap[y][x] ][ [xmap[y][x] ]; */ -static void remap_planar(RemapContext *s, const AVFrame *in, - const AVFrame *xin, const AVFrame *yin, - AVFrame *out) -{ - const int xlinesize = xin->linesize[0] / 2; - const int ylinesize = yin->linesize[0] / 2; - int x , y, plane; - - for (plane = 0; plane < s->nb_planes ; plane++) { - uint8_t *dst = out->data[plane]; - const int dlinesize = out->linesize[plane]; - const uint8_t *src = in->data[plane]; - const int slinesize = in->linesize[plane]; - const uint16_t *xmap = (const uint16_t *)xin->data[0]; - const uint16_t *ymap = (const uint16_t *)yin->data[0]; - - for (y = 0; y < out->height; y++) { - for (x = 0; x < out->width; x++) { - if (ymap[x] < in->height && xmap[x] < in->width) { - dst[x] = src[ymap[x] * slinesize + xmap[x]]; - } else { - dst[x] = 0; - } - } - dst += dlinesize; - xmap += xlinesize; - ymap += ylinesize; - } - } +#define DEFINE_REMAP_PLANAR_FUNC(name, bits, div) \ +static int remap_planar##bits##_##name##_slice(AVFilterContext *ctx, void *arg, \ + int jobnr, int nb_jobs) \ +{ \ + const ThreadData *td = (ThreadData*)arg; \ + const AVFrame *in = td->in; \ + const AVFrame *xin = td->xin; \ + const AVFrame *yin = td->yin; \ + const AVFrame *out = td->out; \ + const int slice_start = (out->height * jobnr ) / nb_jobs; \ + const int slice_end = (out->height * (jobnr+1)) / nb_jobs; \ + const int xlinesize = xin->linesize[0] / 2; \ + const int ylinesize = yin->linesize[0] / 2; \ + int x , y, plane; \ + \ + for (plane = 0; plane < td->nb_planes ; plane++) { \ + const int dlinesize = out->linesize[plane] / div; \ + const uint##bits##_t *src = (const uint##bits##_t *)in->data[plane]; \ + uint##bits##_t *dst = (uint##bits##_t *)out->data[plane] + slice_start * dlinesize; \ + const int slinesize = in->linesize[plane] / div; \ + const uint16_t *xmap = (const uint16_t *)xin->data[0] + slice_start * xlinesize; \ + const uint16_t *ymap = (const uint16_t *)yin->data[0] + slice_start * ylinesize; \ + \ + for (y = slice_start; y < slice_end; y++) { \ + for (x = 0; x < out->width; x++) { \ + if (ymap[x] < in->height && xmap[x] < in->width) { \ + dst[x] = src[ymap[x] * slinesize + xmap[x]]; \ + } else { \ + dst[x] = 0; \ + } \ + } \ + dst += dlinesize; \ + xmap += xlinesize; \ + ymap += ylinesize; \ + } \ + } \ + \ + return 0; \ } -static void remap_planar16(RemapContext *s, const AVFrame *in, - const AVFrame *xin, const AVFrame *yin, - AVFrame *out) -{ - const int xlinesize = xin->linesize[0] / 2; - const int ylinesize = yin->linesize[0] / 2; - int x , y, plane; - - for (plane = 0; plane < s->nb_planes ; plane++) { - uint16_t *dst = (uint16_t *)out->data[plane]; - const int dlinesize = out->linesize[plane] / 2; - const uint16_t *src = (const uint16_t *)in->data[plane]; - const int slinesize = in->linesize[plane] / 2; - const uint16_t *xmap = (const uint16_t *)xin->data[0]; - const uint16_t *ymap = (const uint16_t *)yin->data[0]; - - for (y = 0; y < out->height; y++) { - for (x = 0; x < out->width; x++) { - if (ymap[x] < in->height && xmap[x] < in->width) { - dst[x] = src[ymap[x] * slinesize + xmap[x]]; - } else { - dst[x] = 0; - } - } - dst += dlinesize; - xmap += xlinesize; - ymap += ylinesize; - } - } -} +DEFINE_REMAP_PLANAR_FUNC(nearest, 8, 1) +DEFINE_REMAP_PLANAR_FUNC(nearest, 16, 2) /** * remap_packed algorithm expects pixels with both padded bits (step) and @@ -189,67 +185,48 @@ static void remap_planar16(RemapContext *s, const AVFrame *in, * pixels are copied from source to target using : * Target_frame[y][x] = Source_frame[ ymap[y][x] ][ [xmap[y][x] ]; */ -static void remap_packed(RemapContext *s, const AVFrame *in, - const AVFrame *xin, const AVFrame *yin, - AVFrame *out) -{ - uint8_t *dst = out->data[0]; - const uint8_t *src = in->data[0]; - const int dlinesize = out->linesize[0]; - const int slinesize = in->linesize[0]; - const int xlinesize = xin->linesize[0] / 2; - const int ylinesize = yin->linesize[0] / 2; - const uint16_t *xmap = (const uint16_t *)xin->data[0]; - const uint16_t *ymap = (const uint16_t *)yin->data[0]; - const int step = s->step; - int c, x, y; - - for (y = 0; y < out->height; y++) { - for (x = 0; x < out->width; x++) { - for (c = 0; c < s->nb_components; c++) { - if (ymap[x] < in->height && xmap[x] < in->width) { - dst[x * step + c] = src[ymap[x] * slinesize + xmap[x] * step + c]; - } else { - dst[x * step + c] = 0; - } - } - } - dst += dlinesize; - xmap += xlinesize; - ymap += ylinesize; - } +#define DEFINE_REMAP_PACKED_FUNC(name, bits, div) \ +static int remap_packed##bits##_##name##_slice(AVFilterContext *ctx, void *arg, \ + int jobnr, int nb_jobs) \ +{ \ + const ThreadData *td = (ThreadData*)arg; \ + const AVFrame *in = td->in; \ + const AVFrame *xin = td->xin; \ + const AVFrame *yin = td->yin; \ + const AVFrame *out = td->out; \ + const int slice_start = (out->height * jobnr ) / nb_jobs; \ + const int slice_end = (out->height * (jobnr+1)) / nb_jobs; \ + const int dlinesize = out->linesize[0] / div; \ + const int slinesize = in->linesize[0] / div; \ + const int xlinesize = xin->linesize[0] / 2; \ + const int ylinesize = yin->linesize[0] / 2; \ + const uint##bits##_t *src = (const uint##bits##_t *)in->data[0]; \ + uint##bits##_t *dst = (uint##bits##_t *)out->data[0] + slice_start * dlinesize; \ + const uint16_t *xmap = (const uint16_t *)xin->data[0] + slice_start * xlinesize; \ + const uint16_t *ymap = (const uint16_t *)yin->data[0] + slice_start * ylinesize; \ + const int step = td->step / div; \ + int c, x, y; \ + \ + for (y = slice_start; y < slice_end; y++) { \ + for (x = 0; x < out->width; x++) { \ + for (c = 0; c < td->nb_components; c++) { \ + if (ymap[x] < in->height && xmap[x] < in->width) { \ + dst[x * step + c] = src[ymap[x] * slinesize + xmap[x] * step + c]; \ + } else { \ + dst[x * step + c] = 0; \ + } \ + } \ + } \ + dst += dlinesize; \ + xmap += xlinesize; \ + ymap += ylinesize; \ + } \ + \ + return 0; \ } -static void remap_packed16(RemapContext *s, const AVFrame *in, - const AVFrame *xin, const AVFrame *yin, - AVFrame *out) -{ - uint16_t *dst = (uint16_t *)out->data[0]; - const uint16_t *src = (const uint16_t *)in->data[0]; - const int dlinesize = out->linesize[0] / 2; - const int slinesize = in->linesize[0] / 2; - const int xlinesize = xin->linesize[0] / 2; - const int ylinesize = yin->linesize[0] / 2; - const uint16_t *xmap = (const uint16_t *)xin->data[0]; - const uint16_t *ymap = (const uint16_t *)yin->data[0]; - const int step = s->step / 2; - int c, x, y; - - for (y = 0; y < out->height; y++) { - for (x = 0; x < out->width; x++) { - for (c = 0; c < s->nb_components; c++) { - if (ymap[x] < in->height && xmap[x] < in->width) { - dst[x * step + c] = src[ymap[x] * slinesize + xmap[x] * step + c]; - } else { - dst[x * step + c] = 0; - } - } - } - dst += dlinesize; - xmap += xlinesize; - ymap += ylinesize; - } -} +DEFINE_REMAP_PACKED_FUNC(nearest, 8, 1) +DEFINE_REMAP_PACKED_FUNC(nearest, 16, 2) static int config_input(AVFilterLink *inlink) { @@ -262,15 +239,15 @@ static int config_input(AVFilterLink *inlink) if (desc->comp[0].depth == 8) { if (s->nb_planes > 1 || s->nb_components == 1) { - s->remap = remap_planar; + s->remap_slice = remap_planar8_nearest_slice; } else { - s->remap = remap_packed; + s->remap_slice = remap_packed8_nearest_slice; } } else { if (s->nb_planes > 1 || s->nb_components == 1) { - s->remap = remap_planar16; + s->remap_slice = remap_planar16_nearest_slice; } else { - s->remap = remap_packed16; + s->remap_slice = remap_packed16_nearest_slice; } } @@ -296,14 +273,23 @@ static int process_frame(FFFrameSync *fs) if (!out) return AVERROR(ENOMEM); } else { + ThreadData td; + out = ff_get_video_buffer(outlink, outlink->w, outlink->h); if (!out) return AVERROR(ENOMEM); av_frame_copy_props(out, in); - s->remap(s, in, xpic, ypic, out); + td.in = in; + td.xin = xpic; + td.yin = ypic; + td.out = out; + td.nb_planes = s->nb_planes; + td.nb_components = s->nb_components; + td.step = s->step; + ctx->internal->execute(ctx, s->remap_slice, &td, NULL, FFMIN(outlink->h, ff_filter_get_nb_threads(ctx))); } - out->pts = av_rescale_q(in->pts, s->fs.time_base, outlink->time_base); + out->pts = av_rescale_q(s->fs.pts, s->fs.time_base, outlink->time_base); return ff_filter_frame(outlink, out); } @@ -329,7 +315,6 @@ static int config_output(AVFilterLink *outlink) outlink->w = xlink->w; outlink->h = xlink->h; - outlink->time_base = srclink->time_base; outlink->sample_aspect_ratio = srclink->sample_aspect_ratio; outlink->frame_rate = srclink->frame_rate; @@ -353,7 +338,10 @@ static int config_output(AVFilterLink *outlink) s->fs.opaque = s; s->fs.on_event = process_frame; - return ff_framesync_configure(&s->fs); + ret = ff_framesync_configure(&s->fs); + outlink->time_base = s->fs.time_base; + + return ret; } static int activate(AVFilterContext *ctx) @@ -362,7 +350,6 @@ static int activate(AVFilterContext *ctx) return ff_framesync_activate(&s->fs); } - static av_cold void uninit(AVFilterContext *ctx) { RemapContext *s = ctx->priv; @@ -406,5 +393,5 @@ AVFilter ff_vf_remap = { .inputs = remap_inputs, .outputs = remap_outputs, .priv_class = &remap_class, - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC, + .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS, }; diff --git a/libavfilter/vf_scale.c b/libavfilter/vf_scale.c index f741419e7..7aebf56ad 100644 --- a/libavfilter/vf_scale.c +++ b/libavfilter/vf_scale.c @@ -572,8 +572,16 @@ static const AVOption scale_options[] = { { "interl", "set interlacing", OFFSET(interlaced), AV_OPT_TYPE_BOOL, {.i64 = 0 }, -1, 1, FLAGS }, { "size", "set video size", OFFSET(size_str), AV_OPT_TYPE_STRING, {.str = NULL}, 0, FLAGS }, { "s", "set video size", OFFSET(size_str), AV_OPT_TYPE_STRING, {.str = NULL}, 0, FLAGS }, - { "in_color_matrix", "set input YCbCr type", OFFSET(in_color_matrix), AV_OPT_TYPE_STRING, { .str = "auto" }, .flags = FLAGS }, - { "out_color_matrix", "set output YCbCr type", OFFSET(out_color_matrix), AV_OPT_TYPE_STRING, { .str = NULL }, .flags = FLAGS }, + { "in_color_matrix", "set input YCbCr type", OFFSET(in_color_matrix), AV_OPT_TYPE_STRING, { .str = "auto" }, .flags = FLAGS, "color" }, + { "out_color_matrix", "set output YCbCr type", OFFSET(out_color_matrix), AV_OPT_TYPE_STRING, { .str = NULL }, .flags = FLAGS, "color"}, + { "auto", NULL, 0, AV_OPT_TYPE_CONST, { .str = "auto" }, 0, 0, FLAGS, "color" }, + { "bt601", NULL, 0, AV_OPT_TYPE_CONST, { .str = "bt601" }, 0, 0, FLAGS, "color" }, + { "bt470", NULL, 0, AV_OPT_TYPE_CONST, { .str = "bt470" }, 0, 0, FLAGS, "color" }, + { "smpte170m", NULL, 0, AV_OPT_TYPE_CONST, { .str = "smpte170m" }, 0, 0, FLAGS, "color" }, + { "bt709", NULL, 0, AV_OPT_TYPE_CONST, { .str = "bt709" }, 0, 0, FLAGS, "color" }, + { "fcc", NULL, 0, AV_OPT_TYPE_CONST, { .str = "fcc" }, 0, 0, FLAGS, "color" }, + { "smpte240m", NULL, 0, AV_OPT_TYPE_CONST, { .str = "smpte240m" }, 0, 0, FLAGS, "color" }, + { "bt2020", NULL, 0, AV_OPT_TYPE_CONST, { .str = "bt2020" }, 0, 0, FLAGS, "color" }, { "in_range", "set input color range", OFFSET( in_range), AV_OPT_TYPE_INT, {.i64 = AVCOL_RANGE_UNSPECIFIED }, 0, 2, FLAGS, "range" }, { "out_range", "set output color range", OFFSET(out_range), AV_OPT_TYPE_INT, {.i64 = AVCOL_RANGE_UNSPECIFIED }, 0, 2, FLAGS, "range" }, { "auto", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_RANGE_UNSPECIFIED }, 0, 0, FLAGS, "range" }, diff --git a/libavfilter/vf_scale_cuda.c b/libavfilter/vf_scale_cuda.c index 23ac27a7d..0a73ea142 100644 --- a/libavfilter/vf_scale_cuda.c +++ b/libavfilter/vf_scale_cuda.c @@ -20,7 +20,6 @@ * DEALINGS IN THE SOFTWARE. */ -#include #include #include @@ -28,6 +27,7 @@ #include "libavutil/common.h" #include "libavutil/hwcontext.h" #include "libavutil/hwcontext_cuda_internal.h" +#include "libavutil/cuda_check.h" #include "libavutil/internal.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" @@ -43,7 +43,8 @@ static const enum AVPixelFormat supported_formats[] = { AV_PIX_FMT_NV12, AV_PIX_FMT_YUV444P, AV_PIX_FMT_P010, - AV_PIX_FMT_P016 + AV_PIX_FMT_P016, + AV_PIX_FMT_YUV444P16, }; #define DIV_UP(a, b) ( ((a) + (b) - 1) / (b) ) @@ -52,8 +53,13 @@ static const enum AVPixelFormat supported_formats[] = { #define BLOCKX 32 #define BLOCKY 16 +#define CHECK_CU(x) FF_CUDA_CHECK_DL(ctx, s->hwctx->internal->cuda_dl, x) + typedef struct CUDAScaleContext { const AVClass *class; + + AVCUDADeviceContext *hwctx; + enum AVPixelFormat in_fmt; enum AVPixelFormat out_fmt; @@ -77,7 +83,6 @@ typedef struct CUDAScaleContext { char *h_expr; ///< height expression string CUcontext cu_ctx; - CUevent cu_event; CUmodule cu_module; CUfunction cu_func_uchar; CUfunction cu_func_uchar2; @@ -85,12 +90,7 @@ typedef struct CUDAScaleContext { CUfunction cu_func_ushort; CUfunction cu_func_ushort2; CUfunction cu_func_ushort4; - CUtexref cu_tex_uchar; - CUtexref cu_tex_uchar2; - CUtexref cu_tex_uchar4; - CUtexref cu_tex_ushort; - CUtexref cu_tex_ushort2; - CUtexref cu_tex_ushort4; + CUstream cu_stream; CUdeviceptr srcBuffer; CUdeviceptr dstBuffer; @@ -255,55 +255,49 @@ static av_cold int cudascale_config_props(AVFilterLink *outlink) AVHWFramesContext *frames_ctx = (AVHWFramesContext*)inlink->hw_frames_ctx->data; AVCUDADeviceContext *device_hwctx = frames_ctx->device_ctx->hwctx; CUcontext dummy, cuda_ctx = device_hwctx->cuda_ctx; - CUresult err; + CudaFunctions *cu = device_hwctx->internal->cuda_dl; int w, h; int ret; extern char vf_scale_cuda_ptx[]; - err = cuCtxPushCurrent(cuda_ctx); - if (err != CUDA_SUCCESS) { - av_log(ctx, AV_LOG_ERROR, "Error pushing cuda context\n"); - ret = AVERROR_UNKNOWN; + s->hwctx = device_hwctx; + s->cu_stream = s->hwctx->stream; + + ret = CHECK_CU(cu->cuCtxPushCurrent(cuda_ctx)); + if (ret < 0) goto fail; - } - err = cuModuleLoadData(&s->cu_module, vf_scale_cuda_ptx); - if (err != CUDA_SUCCESS) { - av_log(ctx, AV_LOG_ERROR, "Error loading module data\n"); - ret = AVERROR_UNKNOWN; + ret = CHECK_CU(cu->cuModuleLoadData(&s->cu_module, vf_scale_cuda_ptx)); + if (ret < 0) goto fail; - } - cuModuleGetFunction(&s->cu_func_uchar, s->cu_module, "Subsample_Bilinear_uchar"); - cuModuleGetFunction(&s->cu_func_uchar2, s->cu_module, "Subsample_Bilinear_uchar2"); - cuModuleGetFunction(&s->cu_func_uchar4, s->cu_module, "Subsample_Bilinear_uchar4"); - cuModuleGetFunction(&s->cu_func_ushort, s->cu_module, "Subsample_Bilinear_ushort"); - cuModuleGetFunction(&s->cu_func_ushort2, s->cu_module, "Subsample_Bilinear_ushort2"); - cuModuleGetFunction(&s->cu_func_ushort4, s->cu_module, "Subsample_Bilinear_ushort4"); + CHECK_CU(cu->cuModuleGetFunction(&s->cu_func_uchar, s->cu_module, "Subsample_Bilinear_uchar")); + if (ret < 0) + goto fail; - cuModuleGetTexRef(&s->cu_tex_uchar, s->cu_module, "uchar_tex"); - cuModuleGetTexRef(&s->cu_tex_uchar2, s->cu_module, "uchar2_tex"); - cuModuleGetTexRef(&s->cu_tex_uchar4, s->cu_module, "uchar4_tex"); - cuModuleGetTexRef(&s->cu_tex_ushort, s->cu_module, "ushort_tex"); - cuModuleGetTexRef(&s->cu_tex_ushort2, s->cu_module, "ushort2_tex"); - cuModuleGetTexRef(&s->cu_tex_ushort4, s->cu_module, "ushort4_tex"); + CHECK_CU(cu->cuModuleGetFunction(&s->cu_func_uchar2, s->cu_module, "Subsample_Bilinear_uchar2")); + if (ret < 0) + goto fail; - cuTexRefSetFlags(s->cu_tex_uchar, CU_TRSF_READ_AS_INTEGER); - cuTexRefSetFlags(s->cu_tex_uchar2, CU_TRSF_READ_AS_INTEGER); - cuTexRefSetFlags(s->cu_tex_uchar4, CU_TRSF_READ_AS_INTEGER); - cuTexRefSetFlags(s->cu_tex_ushort, CU_TRSF_READ_AS_INTEGER); - cuTexRefSetFlags(s->cu_tex_ushort2, CU_TRSF_READ_AS_INTEGER); - cuTexRefSetFlags(s->cu_tex_ushort4, CU_TRSF_READ_AS_INTEGER); + CHECK_CU(cu->cuModuleGetFunction(&s->cu_func_uchar4, s->cu_module, "Subsample_Bilinear_uchar4")); + if (ret < 0) + goto fail; - cuTexRefSetFilterMode(s->cu_tex_uchar, CU_TR_FILTER_MODE_LINEAR); - cuTexRefSetFilterMode(s->cu_tex_uchar2, CU_TR_FILTER_MODE_LINEAR); - cuTexRefSetFilterMode(s->cu_tex_uchar4, CU_TR_FILTER_MODE_LINEAR); - cuTexRefSetFilterMode(s->cu_tex_ushort, CU_TR_FILTER_MODE_LINEAR); - cuTexRefSetFilterMode(s->cu_tex_ushort2, CU_TR_FILTER_MODE_LINEAR); - cuTexRefSetFilterMode(s->cu_tex_ushort4, CU_TR_FILTER_MODE_LINEAR); + CHECK_CU(cu->cuModuleGetFunction(&s->cu_func_ushort, s->cu_module, "Subsample_Bilinear_ushort")); + if (ret < 0) + goto fail; - cuCtxPopCurrent(&dummy); + CHECK_CU(cu->cuModuleGetFunction(&s->cu_func_ushort2, s->cu_module, "Subsample_Bilinear_ushort2")); + if (ret < 0) + goto fail; + + CHECK_CU(cu->cuModuleGetFunction(&s->cu_func_ushort4, s->cu_module, "Subsample_Bilinear_ushort4")); + if (ret < 0) + goto fail; + + + CHECK_CU(cu->cuCtxPopCurrent(&dummy)); if ((ret = ff_scale_eval_dimensions(s, s->w_expr, s->h_expr, @@ -339,29 +333,48 @@ fail: return ret; } -static int call_resize_kernel(CUDAScaleContext *s, CUfunction func, CUtexref tex, int channels, +static int call_resize_kernel(AVFilterContext *ctx, CUfunction func, int channels, uint8_t *src_dptr, int src_width, int src_height, int src_pitch, uint8_t *dst_dptr, int dst_width, int dst_height, int dst_pitch, int pixel_size) { - CUdeviceptr src_devptr = (CUdeviceptr)src_dptr; + CUDAScaleContext *s = ctx->priv; + CudaFunctions *cu = s->hwctx->internal->cuda_dl; CUdeviceptr dst_devptr = (CUdeviceptr)dst_dptr; - void *args_uchar[] = { &dst_devptr, &dst_width, &dst_height, &dst_pitch, &src_width, &src_height }; - CUDA_ARRAY_DESCRIPTOR desc; + CUtexObject tex = 0; + void *args_uchar[] = { &tex, &dst_devptr, &dst_width, &dst_height, &dst_pitch, &src_width, &src_height }; + int ret; - desc.Width = src_width; - desc.Height = src_height; - desc.NumChannels = channels; - if (pixel_size == 1) { - desc.Format = CU_AD_FORMAT_UNSIGNED_INT8; - } else { - desc.Format = CU_AD_FORMAT_UNSIGNED_INT16; - } + CUDA_TEXTURE_DESC tex_desc = { + .filterMode = CU_TR_FILTER_MODE_LINEAR, + .flags = CU_TRSF_READ_AS_INTEGER, + }; - cuTexRefSetAddress2D_v3(tex, &desc, src_devptr, src_pitch * pixel_size); - cuLaunchKernel(func, DIV_UP(dst_width, BLOCKX), DIV_UP(dst_height, BLOCKY), 1, BLOCKX, BLOCKY, 1, 0, 0, args_uchar, NULL); + CUDA_RESOURCE_DESC res_desc = { + .resType = CU_RESOURCE_TYPE_PITCH2D, + .res.pitch2D.format = pixel_size == 1 ? + CU_AD_FORMAT_UNSIGNED_INT8 : + CU_AD_FORMAT_UNSIGNED_INT16, + .res.pitch2D.numChannels = channels, + .res.pitch2D.width = src_width, + .res.pitch2D.height = src_height, + .res.pitch2D.pitchInBytes = src_pitch * pixel_size, + .res.pitch2D.devPtr = (CUdeviceptr)src_dptr, + }; - return 0; + ret = CHECK_CU(cu->cuTexObjectCreate(&tex, &res_desc, &tex_desc, NULL)); + if (ret < 0) + goto exit; + + ret = CHECK_CU(cu->cuLaunchKernel(func, + DIV_UP(dst_width, BLOCKX), DIV_UP(dst_height, BLOCKY), 1, + BLOCKX, BLOCKY, 1, 0, s->cu_stream, args_uchar, NULL)); + +exit: + if (tex) + CHECK_CU(cu->cuTexObjectDestroy(tex)); + + return ret; } static int scalecuda_resize(AVFilterContext *ctx, @@ -372,61 +385,75 @@ static int scalecuda_resize(AVFilterContext *ctx, switch (in_frames_ctx->sw_format) { case AV_PIX_FMT_YUV420P: - call_resize_kernel(s, s->cu_func_uchar, s->cu_tex_uchar, 1, + call_resize_kernel(ctx, s->cu_func_uchar, 1, in->data[0], in->width, in->height, in->linesize[0], out->data[0], out->width, out->height, out->linesize[0], 1); - call_resize_kernel(s, s->cu_func_uchar, s->cu_tex_uchar, 1, - in->data[0]+in->linesize[0]*in->height, in->width/2, in->height/2, in->linesize[0]/2, - out->data[0]+out->linesize[0]*out->height, out->width/2, out->height/2, out->linesize[0]/2, + call_resize_kernel(ctx, s->cu_func_uchar, 1, + in->data[1], in->width/2, in->height/2, in->linesize[0]/2, + out->data[1], out->width/2, out->height/2, out->linesize[0]/2, 1); - call_resize_kernel(s, s->cu_func_uchar, s->cu_tex_uchar, 1, - in->data[0]+ ALIGN_UP((in->linesize[0]*in->height*5)/4, s->tex_alignment), in->width/2, in->height/2, in->linesize[0]/2, - out->data[0]+(out->linesize[0]*out->height*5)/4, out->width/2, out->height/2, out->linesize[0]/2, + call_resize_kernel(ctx, s->cu_func_uchar, 1, + in->data[2], in->width/2, in->height/2, in->linesize[0]/2, + out->data[2], out->width/2, out->height/2, out->linesize[0]/2, 1); break; case AV_PIX_FMT_YUV444P: - call_resize_kernel(s, s->cu_func_uchar, s->cu_tex_uchar, 1, + call_resize_kernel(ctx, s->cu_func_uchar, 1, in->data[0], in->width, in->height, in->linesize[0], out->data[0], out->width, out->height, out->linesize[0], 1); - call_resize_kernel(s, s->cu_func_uchar, s->cu_tex_uchar, 1, - in->data[0]+in->linesize[0]*in->height, in->width, in->height, in->linesize[0], - out->data[0]+out->linesize[0]*out->height, out->width, out->height, out->linesize[0], + call_resize_kernel(ctx, s->cu_func_uchar, 1, + in->data[1], in->width, in->height, in->linesize[0], + out->data[1], out->width, out->height, out->linesize[0], 1); - call_resize_kernel(s, s->cu_func_uchar, s->cu_tex_uchar, 1, - in->data[0]+in->linesize[0]*in->height*2, in->width, in->height, in->linesize[0], - out->data[0]+out->linesize[0]*out->height*2, out->width, out->height, out->linesize[0], + call_resize_kernel(ctx, s->cu_func_uchar, 1, + in->data[2], in->width, in->height, in->linesize[0], + out->data[2], out->width, out->height, out->linesize[0], 1); break; - case AV_PIX_FMT_NV12: - call_resize_kernel(s, s->cu_func_uchar, s->cu_tex_uchar, 1, - in->data[0], in->width, in->height, in->linesize[0], - out->data[0], out->width, out->height, out->linesize[0], - 1); - call_resize_kernel(s, s->cu_func_uchar2, s->cu_tex_uchar2, 2, - in->data[1], in->width/2, in->height/2, in->linesize[1], - out->data[0] + out->linesize[0] * ((out->height + 31) & ~0x1f), out->width/2, out->height/2, out->linesize[1]/2, - 1); - break; - case AV_PIX_FMT_P010LE: - call_resize_kernel(s, s->cu_func_ushort, s->cu_tex_ushort, 1, - in->data[0], in->width, in->height, in->linesize[0]/2, - out->data[0], out->width, out->height, out->linesize[0]/2, - 2); - call_resize_kernel(s, s->cu_func_ushort2, s->cu_tex_ushort2, 2, - in->data[1], in->width / 2, in->height / 2, in->linesize[1]/2, - out->data[0] + out->linesize[0] * ((out->height + 31) & ~0x1f), out->width / 2, out->height / 2, out->linesize[1] / 4, - 2); - break; - case AV_PIX_FMT_P016LE: - call_resize_kernel(s, s->cu_func_ushort, s->cu_tex_ushort, 1, + case AV_PIX_FMT_YUV444P16: + call_resize_kernel(ctx, s->cu_func_ushort, 1, in->data[0], in->width, in->height, in->linesize[0] / 2, out->data[0], out->width, out->height, out->linesize[0] / 2, 2); - call_resize_kernel(s, s->cu_func_ushort2, s->cu_tex_ushort2, 2, + call_resize_kernel(ctx, s->cu_func_ushort, 1, + in->data[1], in->width, in->height, in->linesize[1] / 2, + out->data[1], out->width, out->height, out->linesize[1] / 2, + 2); + call_resize_kernel(ctx, s->cu_func_ushort, 1, + in->data[2], in->width, in->height, in->linesize[2] / 2, + out->data[2], out->width, out->height, out->linesize[2] / 2, + 2); + break; + case AV_PIX_FMT_NV12: + call_resize_kernel(ctx, s->cu_func_uchar, 1, + in->data[0], in->width, in->height, in->linesize[0], + out->data[0], out->width, out->height, out->linesize[0], + 1); + call_resize_kernel(ctx, s->cu_func_uchar2, 2, + in->data[1], in->width/2, in->height/2, in->linesize[1], + out->data[1], out->width/2, out->height/2, out->linesize[1]/2, + 1); + break; + case AV_PIX_FMT_P010LE: + call_resize_kernel(ctx, s->cu_func_ushort, 1, + in->data[0], in->width, in->height, in->linesize[0]/2, + out->data[0], out->width, out->height, out->linesize[0]/2, + 2); + call_resize_kernel(ctx, s->cu_func_ushort2, 2, + in->data[1], in->width / 2, in->height / 2, in->linesize[1]/2, + out->data[1], out->width / 2, out->height / 2, out->linesize[1] / 4, + 2); + break; + case AV_PIX_FMT_P016LE: + call_resize_kernel(ctx, s->cu_func_ushort, 1, + in->data[0], in->width, in->height, in->linesize[0] / 2, + out->data[0], out->width, out->height, out->linesize[0] / 2, + 2); + call_resize_kernel(ctx, s->cu_func_ushort2, 2, in->data[1], in->width / 2, in->height / 2, in->linesize[1] / 2, - out->data[0] + out->linesize[0] * ((out->height + 31) & ~0x1f), out->width / 2, out->height / 2, out->linesize[1] / 4, + out->data[1], out->width / 2, out->height / 2, out->linesize[1] / 4, 2); break; default: @@ -454,6 +481,9 @@ static int cudascale_scale(AVFilterContext *ctx, AVFrame *out, AVFrame *in) av_frame_move_ref(out, s->frame); av_frame_move_ref(s->frame, s->tmp_frame); + s->frame->width = s->planes_out[0].width; + s->frame->height = s->planes_out[0].height; + ret = av_frame_copy_props(out, in); if (ret < 0) return ret; @@ -463,14 +493,12 @@ static int cudascale_scale(AVFilterContext *ctx, AVFrame *out, AVFrame *in) static int cudascale_filter_frame(AVFilterLink *link, AVFrame *in) { - AVFilterContext *ctx = link->dst; - CUDAScaleContext *s = ctx->priv; - AVFilterLink *outlink = ctx->outputs[0]; - AVHWFramesContext *frames_ctx = (AVHWFramesContext*)s->frames_ctx->data; - AVCUDADeviceContext *device_hwctx = frames_ctx->device_ctx->hwctx; + AVFilterContext *ctx = link->dst; + CUDAScaleContext *s = ctx->priv; + AVFilterLink *outlink = ctx->outputs[0]; + CudaFunctions *cu = s->hwctx->internal->cuda_dl; AVFrame *out = NULL; - CUresult err; CUcontext dummy; int ret = 0; @@ -480,15 +508,13 @@ static int cudascale_filter_frame(AVFilterLink *link, AVFrame *in) goto fail; } - err = cuCtxPushCurrent(device_hwctx->cuda_ctx); - if (err != CUDA_SUCCESS) { - ret = AVERROR_UNKNOWN; + ret = CHECK_CU(cu->cuCtxPushCurrent(s->hwctx->cuda_ctx)); + if (ret < 0) goto fail; - } ret = cudascale_scale(ctx, out, in); - cuCtxPopCurrent(&dummy); + CHECK_CU(cu->cuCtxPopCurrent(&dummy)); if (ret < 0) goto fail; diff --git a/libavfilter/vf_scale_cuda.cu b/libavfilter/vf_scale_cuda.cu index 5f5ec8198..3f3f40546 100644 --- a/libavfilter/vf_scale_cuda.cu +++ b/libavfilter/vf_scale_cuda.cu @@ -22,14 +22,8 @@ extern "C" { -texture uchar_tex; -texture uchar2_tex; -texture uchar4_tex; -texture ushort_tex; -texture ushort2_tex; -texture ushort4_tex; - -__global__ void Subsample_Bilinear_uchar(unsigned char *dst, +__global__ void Subsample_Bilinear_uchar(cudaTextureObject_t uchar_tex, + unsigned char *dst, int dst_width, int dst_height, int dst_pitch, int src_width, int src_height) { @@ -48,15 +42,16 @@ __global__ void Subsample_Bilinear_uchar(unsigned char *dst, // Convert weights to two bilinear weights -> {wh,1.0,wh} -> {wh,0.5,0} + {0,0.5,wh} float dx = wh / (0.5f + wh); float dy = wv / (0.5f + wv); - int y0 = tex2D(uchar_tex, xi-dx, yi-dy); - int y1 = tex2D(uchar_tex, xi+dx, yi-dy); - int y2 = tex2D(uchar_tex, xi-dx, yi+dy); - int y3 = tex2D(uchar_tex, xi+dx, yi+dy); + int y0 = tex2D(uchar_tex, xi-dx, yi-dy); + int y1 = tex2D(uchar_tex, xi+dx, yi-dy); + int y2 = tex2D(uchar_tex, xi-dx, yi+dy); + int y3 = tex2D(uchar_tex, xi+dx, yi+dy); dst[yo*dst_pitch+xo] = (unsigned char)((y0+y1+y2+y3+2) >> 2); } } -__global__ void Subsample_Bilinear_uchar2(uchar2 *dst, +__global__ void Subsample_Bilinear_uchar2(cudaTextureObject_t uchar2_tex, + uchar2 *dst, int dst_width, int dst_height, int dst_pitch2, int src_width, int src_height) { @@ -75,10 +70,10 @@ __global__ void Subsample_Bilinear_uchar2(uchar2 *dst, // Convert weights to two bilinear weights -> {wh,1.0,wh} -> {wh,0.5,0} + {0,0.5,wh} float dx = wh / (0.5f + wh); float dy = wv / (0.5f + wv); - uchar2 c0 = tex2D(uchar2_tex, xi-dx, yi-dy); - uchar2 c1 = tex2D(uchar2_tex, xi+dx, yi-dy); - uchar2 c2 = tex2D(uchar2_tex, xi-dx, yi+dy); - uchar2 c3 = tex2D(uchar2_tex, xi+dx, yi+dy); + uchar2 c0 = tex2D(uchar2_tex, xi-dx, yi-dy); + uchar2 c1 = tex2D(uchar2_tex, xi+dx, yi-dy); + uchar2 c2 = tex2D(uchar2_tex, xi-dx, yi+dy); + uchar2 c3 = tex2D(uchar2_tex, xi+dx, yi+dy); int2 uv; uv.x = ((int)c0.x+(int)c1.x+(int)c2.x+(int)c3.x+2) >> 2; uv.y = ((int)c0.y+(int)c1.y+(int)c2.y+(int)c3.y+2) >> 2; @@ -86,7 +81,8 @@ __global__ void Subsample_Bilinear_uchar2(uchar2 *dst, } } -__global__ void Subsample_Bilinear_uchar4(uchar4 *dst, +__global__ void Subsample_Bilinear_uchar4(cudaTextureObject_t uchar4_tex, + uchar4 *dst, int dst_width, int dst_height, int dst_pitch, int src_width, int src_height) { @@ -105,10 +101,10 @@ __global__ void Subsample_Bilinear_uchar4(uchar4 *dst, // Convert weights to two bilinear weights -> {wh,1.0,wh} -> {wh,0.5,0} + {0,0.5,wh} float dx = wh / (0.5f + wh); float dy = wv / (0.5f + wv); - uchar4 c0 = tex2D(uchar4_tex, xi-dx, yi-dy); - uchar4 c1 = tex2D(uchar4_tex, xi+dx, yi-dy); - uchar4 c2 = tex2D(uchar4_tex, xi-dx, yi+dy); - uchar4 c3 = tex2D(uchar4_tex, xi+dx, yi+dy); + uchar4 c0 = tex2D(uchar4_tex, xi-dx, yi-dy); + uchar4 c1 = tex2D(uchar4_tex, xi+dx, yi-dy); + uchar4 c2 = tex2D(uchar4_tex, xi-dx, yi+dy); + uchar4 c3 = tex2D(uchar4_tex, xi+dx, yi+dy); int4 res; res.x = ((int)c0.x+(int)c1.x+(int)c2.x+(int)c3.x+2) >> 2; res.y = ((int)c0.y+(int)c1.y+(int)c2.y+(int)c3.y+2) >> 2; @@ -119,7 +115,8 @@ __global__ void Subsample_Bilinear_uchar4(uchar4 *dst, } } -__global__ void Subsample_Bilinear_ushort(unsigned short *dst, +__global__ void Subsample_Bilinear_ushort(cudaTextureObject_t ushort_tex, + unsigned short *dst, int dst_width, int dst_height, int dst_pitch, int src_width, int src_height) { @@ -138,15 +135,16 @@ __global__ void Subsample_Bilinear_ushort(unsigned short *dst, // Convert weights to two bilinear weights -> {wh,1.0,wh} -> {wh,0.5,0} + {0,0.5,wh} float dx = wh / (0.5f + wh); float dy = wv / (0.5f + wv); - int y0 = tex2D(ushort_tex, xi-dx, yi-dy); - int y1 = tex2D(ushort_tex, xi+dx, yi-dy); - int y2 = tex2D(ushort_tex, xi-dx, yi+dy); - int y3 = tex2D(ushort_tex, xi+dx, yi+dy); + int y0 = tex2D(ushort_tex, xi-dx, yi-dy); + int y1 = tex2D(ushort_tex, xi+dx, yi-dy); + int y2 = tex2D(ushort_tex, xi-dx, yi+dy); + int y3 = tex2D(ushort_tex, xi+dx, yi+dy); dst[yo*dst_pitch+xo] = (unsigned short)((y0+y1+y2+y3+2) >> 2); } } -__global__ void Subsample_Bilinear_ushort2(ushort2 *dst, +__global__ void Subsample_Bilinear_ushort2(cudaTextureObject_t ushort2_tex, + ushort2 *dst, int dst_width, int dst_height, int dst_pitch2, int src_width, int src_height) { @@ -165,10 +163,10 @@ __global__ void Subsample_Bilinear_ushort2(ushort2 *dst, // Convert weights to two bilinear weights -> {wh,1.0,wh} -> {wh,0.5,0} + {0,0.5,wh} float dx = wh / (0.5f + wh); float dy = wv / (0.5f + wv); - ushort2 c0 = tex2D(ushort2_tex, xi-dx, yi-dy); - ushort2 c1 = tex2D(ushort2_tex, xi+dx, yi-dy); - ushort2 c2 = tex2D(ushort2_tex, xi-dx, yi+dy); - ushort2 c3 = tex2D(ushort2_tex, xi+dx, yi+dy); + ushort2 c0 = tex2D(ushort2_tex, xi-dx, yi-dy); + ushort2 c1 = tex2D(ushort2_tex, xi+dx, yi-dy); + ushort2 c2 = tex2D(ushort2_tex, xi-dx, yi+dy); + ushort2 c3 = tex2D(ushort2_tex, xi+dx, yi+dy); int2 uv; uv.x = ((int)c0.x+(int)c1.x+(int)c2.x+(int)c3.x+2) >> 2; uv.y = ((int)c0.y+(int)c1.y+(int)c2.y+(int)c3.y+2) >> 2; @@ -176,7 +174,8 @@ __global__ void Subsample_Bilinear_ushort2(ushort2 *dst, } } -__global__ void Subsample_Bilinear_ushort4(ushort4 *dst, +__global__ void Subsample_Bilinear_ushort4(cudaTextureObject_t ushort4_tex, + ushort4 *dst, int dst_width, int dst_height, int dst_pitch, int src_width, int src_height) { @@ -195,10 +194,10 @@ __global__ void Subsample_Bilinear_ushort4(ushort4 *dst, // Convert weights to two bilinear weights -> {wh,1.0,wh} -> {wh,0.5,0} + {0,0.5,wh} float dx = wh / (0.5f + wh); float dy = wv / (0.5f + wv); - ushort4 c0 = tex2D(ushort4_tex, xi-dx, yi-dy); - ushort4 c1 = tex2D(ushort4_tex, xi+dx, yi-dy); - ushort4 c2 = tex2D(ushort4_tex, xi-dx, yi+dy); - ushort4 c3 = tex2D(ushort4_tex, xi+dx, yi+dy); + ushort4 c0 = tex2D(ushort4_tex, xi-dx, yi-dy); + ushort4 c1 = tex2D(ushort4_tex, xi+dx, yi-dy); + ushort4 c2 = tex2D(ushort4_tex, xi-dx, yi+dy); + ushort4 c3 = tex2D(ushort4_tex, xi+dx, yi+dy); int4 res; res.x = ((int)c0.x+(int)c1.x+(int)c2.x+(int)c3.x+2) >> 2; res.y = ((int)c0.y+(int)c1.y+(int)c2.y+(int)c3.y+2) >> 2; diff --git a/libavfilter/vf_scale_npp.c b/libavfilter/vf_scale_npp.c index 8a277ce8e..a3e085764 100644 --- a/libavfilter/vf_scale_npp.c +++ b/libavfilter/vf_scale_npp.c @@ -29,6 +29,7 @@ #include "libavutil/common.h" #include "libavutil/hwcontext.h" #include "libavutil/hwcontext_cuda_internal.h" +#include "libavutil/cuda_check.h" #include "libavutil/internal.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" @@ -39,6 +40,8 @@ #include "scale.h" #include "video.h" +#define CHECK_CU(x) FF_CUDA_CHECK_DL(ctx, device_hwctx->internal->cuda_dl, x) + static const enum AVPixelFormat supported_formats[] = { AV_PIX_FMT_YUV420P, AV_PIX_FMT_NV12, @@ -498,7 +501,6 @@ static int nppscale_filter_frame(AVFilterLink *link, AVFrame *in) AVCUDADeviceContext *device_hwctx = frames_ctx->device_ctx->hwctx; AVFrame *out = NULL; - CUresult err; CUcontext dummy; int ret = 0; @@ -511,15 +513,13 @@ static int nppscale_filter_frame(AVFilterLink *link, AVFrame *in) goto fail; } - err = device_hwctx->internal->cuda_dl->cuCtxPushCurrent(device_hwctx->cuda_ctx); - if (err != CUDA_SUCCESS) { - ret = AVERROR_UNKNOWN; + ret = CHECK_CU(device_hwctx->internal->cuda_dl->cuCtxPushCurrent(device_hwctx->cuda_ctx)); + if (ret < 0) goto fail; - } ret = nppscale_scale(ctx, out, in); - device_hwctx->internal->cuda_dl->cuCtxPopCurrent(&dummy); + CHECK_CU(device_hwctx->internal->cuda_dl->cuCtxPopCurrent(&dummy)); if (ret < 0) goto fail; diff --git a/libavfilter/vf_scale_qsv.c b/libavfilter/vf_scale_qsv.c index d1189942d..499534e30 100644 --- a/libavfilter/vf_scale_qsv.c +++ b/libavfilter/vf_scale_qsv.c @@ -69,6 +69,8 @@ enum var_name { VARS_NB }; +#define QSV_HAVE_SCALING_CONFIG QSV_VERSION_ATLEAST(1, 19) + typedef struct QSVScaleContext { const AVClass *class; @@ -88,7 +90,14 @@ typedef struct QSVScaleContext { int nb_surface_ptrs_out; mfxExtOpaqueSurfaceAlloc opaque_alloc; - mfxExtBuffer *ext_buffers[1]; + +#if QSV_HAVE_SCALING_CONFIG + mfxExtVPPScaling scale_conf; +#endif + int mode; + + mfxExtBuffer *ext_buffers[1 + QSV_HAVE_SCALING_CONFIG]; + int num_ext_buf; int shift_width, shift_height; @@ -109,7 +118,7 @@ typedef struct QSVScaleContext { char *format_str; } QSVScaleContext; -static int qsvscale_init(AVFilterContext *ctx) +static av_cold int qsvscale_init(AVFilterContext *ctx) { QSVScaleContext *s = ctx->priv; @@ -126,7 +135,7 @@ static int qsvscale_init(AVFilterContext *ctx) return 0; } -static void qsvscale_uninit(AVFilterContext *ctx) +static av_cold void qsvscale_uninit(AVFilterContext *ctx) { QSVScaleContext *s = ctx->priv; @@ -285,6 +294,8 @@ static int init_out_session(AVFilterContext *ctx) mfxStatus err; int i; + s->num_ext_buf = 0; + /* extract the properties of the "master" session given to us */ err = MFXQueryIMPL(device_hwctx->session, &impl); if (err == MFX_ERR_NONE) @@ -302,6 +313,11 @@ static int init_out_session(AVFilterContext *ctx) } } + if (err != MFX_ERR_NONE) { + av_log(ctx, AV_LOG_ERROR, "Error getting the session handle\n"); + return AVERROR_UNKNOWN; + } + /* create a "slave" session with those same properties, to be used for * actual scaling */ err = MFXInit(impl, &ver, &s->session); @@ -352,10 +368,7 @@ static int init_out_session(AVFilterContext *ctx) s->opaque_alloc.Header.BufferId = MFX_EXTBUFF_OPAQUE_SURFACE_ALLOCATION; s->opaque_alloc.Header.BufferSz = sizeof(s->opaque_alloc); - s->ext_buffers[0] = (mfxExtBuffer*)&s->opaque_alloc; - - par.ExtParam = s->ext_buffers; - par.NumExtParam = FF_ARRAY_ELEMS(s->ext_buffers); + s->ext_buffers[s->num_ext_buf++] = (mfxExtBuffer*)&s->opaque_alloc; par.IOPattern = MFX_IOPATTERN_IN_OPAQUE_MEMORY | MFX_IOPATTERN_OUT_OPAQUE_MEMORY; } else { @@ -391,6 +404,18 @@ static int init_out_session(AVFilterContext *ctx) par.IOPattern = MFX_IOPATTERN_IN_VIDEO_MEMORY | MFX_IOPATTERN_OUT_VIDEO_MEMORY; } +#if QSV_HAVE_SCALING_CONFIG + memset(&s->scale_conf, 0, sizeof(mfxExtVPPScaling)); + s->scale_conf.Header.BufferId = MFX_EXTBUFF_VPP_SCALING; + s->scale_conf.Header.BufferSz = sizeof(mfxExtVPPScaling); + s->scale_conf.ScalingMode = s->mode; + s->ext_buffers[s->num_ext_buf++] = (mfxExtBuffer*)&s->scale_conf; + av_log(ctx, AV_LOG_VERBOSE, "Scaling mode: %"PRIu16"\n", s->mode); +#endif + + par.ExtParam = s->ext_buffers; + par.NumExtParam = s->num_ext_buf; + par.AsyncDepth = 1; // TODO async par.vpp.In = in_frames_hwctx->surfaces[0].Info; @@ -590,6 +615,16 @@ static const AVOption options[] = { { "h", "Output video height", OFFSET(h_expr), AV_OPT_TYPE_STRING, { .str = "ih" }, .flags = FLAGS }, { "format", "Output pixel format", OFFSET(format_str), AV_OPT_TYPE_STRING, { .str = "same" }, .flags = FLAGS }, +#if QSV_HAVE_SCALING_CONFIG + { "mode", "set scaling mode", OFFSET(mode), AV_OPT_TYPE_INT, { .i64 = MFX_SCALING_MODE_DEFAULT}, MFX_SCALING_MODE_DEFAULT, MFX_SCALING_MODE_QUALITY, FLAGS, "mode"}, + { "low_power", "low power mode", 0, AV_OPT_TYPE_CONST, { .i64 = MFX_SCALING_MODE_LOWPOWER}, INT_MIN, INT_MAX, FLAGS, "mode"}, + { "hq", "high quality mode", 0, AV_OPT_TYPE_CONST, { .i64 = MFX_SCALING_MODE_QUALITY}, INT_MIN, INT_MAX, FLAGS, "mode"}, +#else + { "mode", "(not supported)", OFFSET(mode), AV_OPT_TYPE_INT, { .i64 = 0}, 0, INT_MAX, FLAGS, "mode"}, + { "low_power", "", 0, AV_OPT_TYPE_CONST, { .i64 = 1}, 0, 0, FLAGS, "mode"}, + { "hq", "", 0, AV_OPT_TYPE_CONST, { .i64 = 2}, 0, 0, FLAGS, "mode"}, +#endif + { NULL }, }; diff --git a/libavfilter/vf_scale_vaapi.c b/libavfilter/vf_scale_vaapi.c index d6529d523..c32395ac0 100644 --- a/libavfilter/vf_scale_vaapi.c +++ b/libavfilter/vf_scale_vaapi.c @@ -35,10 +35,38 @@ typedef struct ScaleVAAPIContext { char *output_format_string; + int mode; + char *w_expr; // width expression string char *h_expr; // height expression string + + char *colour_primaries_string; + char *colour_transfer_string; + char *colour_matrix_string; + int colour_range; + char *chroma_location_string; + + enum AVColorPrimaries colour_primaries; + enum AVColorTransferCharacteristic colour_transfer; + enum AVColorSpace colour_matrix; + enum AVChromaLocation chroma_location; } ScaleVAAPIContext; +static const char *scale_vaapi_mode_name(int mode) +{ + switch (mode) { +#define D(name) case VA_FILTER_SCALING_ ## name: return #name + D(DEFAULT); + D(FAST); + D(HQ); + D(NL_ANAMORPHIC); +#undef D + default: + return "Invalid"; + } +} + + static int scale_vaapi_config_output(AVFilterLink *outlink) { AVFilterLink *inlink = outlink->src->inputs[0]; @@ -70,10 +98,9 @@ static int scale_vaapi_filter_frame(AVFilterLink *inlink, AVFrame *input_frame) AVFilterContext *avctx = inlink->dst; AVFilterLink *outlink = avctx->outputs[0]; VAAPIVPPContext *vpp_ctx = avctx->priv; + ScaleVAAPIContext *ctx = avctx->priv; AVFrame *output_frame = NULL; - VASurfaceID input_surface, output_surface; VAProcPipelineParameterBuffer params; - VARectangle input_region; int err; av_log(avctx, AV_LOG_DEBUG, "Filter input: %s, %ux%u (%"PRId64").\n", @@ -83,10 +110,6 @@ static int scale_vaapi_filter_frame(AVFilterLink *inlink, AVFrame *input_frame) if (vpp_ctx->va_context == VA_INVALID_ID) return AVERROR(EINVAL); - input_surface = (VASurfaceID)(uintptr_t)input_frame->data[3]; - av_log(avctx, AV_LOG_DEBUG, "Using surface %#x for scale input.\n", - input_surface); - output_frame = ff_get_video_buffer(outlink, vpp_ctx->output_width, vpp_ctx->output_height); if (!output_frame) { @@ -94,46 +117,38 @@ static int scale_vaapi_filter_frame(AVFilterLink *inlink, AVFrame *input_frame) goto fail; } - output_surface = (VASurfaceID)(uintptr_t)output_frame->data[3]; - av_log(avctx, AV_LOG_DEBUG, "Using surface %#x for scale output.\n", - output_surface); + err = av_frame_copy_props(output_frame, input_frame); + if (err < 0) + return err; - memset(¶ms, 0, sizeof(params)); + if (ctx->colour_primaries != AVCOL_PRI_UNSPECIFIED) + output_frame->color_primaries = ctx->colour_primaries; + if (ctx->colour_transfer != AVCOL_TRC_UNSPECIFIED) + output_frame->color_trc = ctx->colour_transfer; + if (ctx->colour_matrix != AVCOL_SPC_UNSPECIFIED) + output_frame->colorspace = ctx->colour_matrix; + if (ctx->colour_range != AVCOL_RANGE_UNSPECIFIED) + output_frame->color_range = ctx->colour_range; + if (ctx->chroma_location != AVCHROMA_LOC_UNSPECIFIED) + output_frame->chroma_location = ctx->chroma_location; - input_region = (VARectangle) { - .x = input_frame->crop_left, - .y = input_frame->crop_top, - .width = input_frame->width - - (input_frame->crop_left + input_frame->crop_right), - .height = input_frame->height - - (input_frame->crop_top + input_frame->crop_bottom), - }; - - params.surface = input_surface; - params.surface_region = &input_region; - params.surface_color_standard = - ff_vaapi_vpp_colour_standard(input_frame->colorspace); - - params.output_region = 0; - params.output_background_color = 0xff000000; - params.output_color_standard = params.surface_color_standard; - - params.pipeline_flags = 0; - params.filter_flags = VA_FILTER_SCALING_HQ; - - err = ff_vaapi_vpp_render_picture(avctx, ¶ms, output_surface); + err = ff_vaapi_vpp_init_params(avctx, ¶ms, + input_frame, output_frame); if (err < 0) goto fail; - err = av_frame_copy_props(output_frame, input_frame); + params.filter_flags |= ctx->mode; + + err = ff_vaapi_vpp_render_picture(avctx, ¶ms, output_frame); if (err < 0) goto fail; av_frame_free(&input_frame); - av_log(avctx, AV_LOG_DEBUG, "Filter output: %s, %ux%u (%"PRId64").\n", + av_log(avctx, AV_LOG_DEBUG, "Filter output: %s, %ux%u (%"PRId64"), mode: %s.\n", av_get_pix_fmt_name(output_frame->format), - output_frame->width, output_frame->height, output_frame->pts); + output_frame->width, output_frame->height, output_frame->pts, + scale_vaapi_mode_name(ctx->mode)); return ff_filter_frame(outlink, output_frame); @@ -162,6 +177,24 @@ static av_cold int scale_vaapi_init(AVFilterContext *avctx) vpp_ctx->output_format = AV_PIX_FMT_NONE; } +#define STRING_OPTION(var_name, func_name, default_value) do { \ + if (ctx->var_name ## _string) { \ + int var = av_ ## func_name ## _from_name(ctx->var_name ## _string); \ + if (var < 0) { \ + av_log(avctx, AV_LOG_ERROR, "Invalid %s.\n", #var_name); \ + return AVERROR(EINVAL); \ + } \ + ctx->var_name = var; \ + } else { \ + ctx->var_name = default_value; \ + } \ + } while (0) + + STRING_OPTION(colour_primaries, color_primaries, AVCOL_PRI_UNSPECIFIED); + STRING_OPTION(colour_transfer, color_transfer, AVCOL_TRC_UNSPECIFIED); + STRING_OPTION(colour_matrix, color_space, AVCOL_SPC_UNSPECIFIED); + STRING_OPTION(chroma_location, chroma_location, AVCHROMA_LOC_UNSPECIFIED); + return 0; } @@ -174,6 +207,47 @@ static const AVOption scale_vaapi_options[] = { OFFSET(h_expr), AV_OPT_TYPE_STRING, {.str = "ih"}, .flags = FLAGS }, { "format", "Output video format (software format of hardware frames)", OFFSET(output_format_string), AV_OPT_TYPE_STRING, .flags = FLAGS }, + { "mode", "Scaling mode", + OFFSET(mode), AV_OPT_TYPE_INT, { .i64 = VA_FILTER_SCALING_HQ }, + 0, VA_FILTER_SCALING_NL_ANAMORPHIC, FLAGS, "mode" }, + { "default", "Use the default (depend on the driver) scaling algorithm", + 0, AV_OPT_TYPE_CONST, { .i64 = VA_FILTER_SCALING_DEFAULT }, 0, 0, FLAGS, "mode" }, + { "fast", "Use fast scaling algorithm", + 0, AV_OPT_TYPE_CONST, { .i64 = VA_FILTER_SCALING_FAST }, 0, 0, FLAGS, "mode" }, + { "hq", "Use high quality scaling algorithm", + 0, AV_OPT_TYPE_CONST, { .i64 = VA_FILTER_SCALING_HQ }, 0, 0, FLAGS, "mode" }, + { "nl_anamorphic", "Use nolinear anamorphic scaling algorithm", + 0, AV_OPT_TYPE_CONST, { .i64 = VA_FILTER_SCALING_NL_ANAMORPHIC }, 0, 0, FLAGS, "mode" }, + + // These colour properties match the ones of the same name in vf_scale. + { "out_color_matrix", "Output colour matrix coefficient set", + OFFSET(colour_matrix_string), AV_OPT_TYPE_STRING, { .str = NULL }, .flags = FLAGS }, + { "out_range", "Output colour range", + OFFSET(colour_range), AV_OPT_TYPE_INT, { .i64 = AVCOL_RANGE_UNSPECIFIED }, + AVCOL_RANGE_UNSPECIFIED, AVCOL_RANGE_JPEG, FLAGS, "range" }, + { "full", "Full range", + 0, AV_OPT_TYPE_CONST, { .i64 = AVCOL_RANGE_JPEG }, 0, 0, FLAGS, "range" }, + { "limited", "Limited range", + 0, AV_OPT_TYPE_CONST, { .i64 = AVCOL_RANGE_MPEG }, 0, 0, FLAGS, "range" }, + { "jpeg", "Full range", + 0, AV_OPT_TYPE_CONST, { .i64 = AVCOL_RANGE_JPEG }, 0, 0, FLAGS, "range" }, + { "mpeg", "Limited range", + 0, AV_OPT_TYPE_CONST, { .i64 = AVCOL_RANGE_MPEG }, 0, 0, FLAGS, "range" }, + { "tv", "Limited range", + 0, AV_OPT_TYPE_CONST, { .i64 = AVCOL_RANGE_MPEG }, 0, 0, FLAGS, "range" }, + { "pc", "Full range", + 0, AV_OPT_TYPE_CONST, { .i64 = AVCOL_RANGE_JPEG }, 0, 0, FLAGS, "range" }, + // These colour properties are new here. + { "out_color_primaries", "Output colour primaries", + OFFSET(colour_primaries_string), AV_OPT_TYPE_STRING, + { .str = NULL }, .flags = FLAGS }, + { "out_color_transfer", "Output colour transfer characteristics", + OFFSET(colour_transfer_string), AV_OPT_TYPE_STRING, + { .str = NULL }, .flags = FLAGS }, + { "out_chroma_location", "Output chroma sample location", + OFFSET(chroma_location_string), AV_OPT_TYPE_STRING, + { .str = NULL }, .flags = FLAGS }, + { NULL }, }; diff --git a/libavfilter/vf_selectivecolor.c b/libavfilter/vf_selectivecolor.c index c4d51bb70..b99f31bef 100644 --- a/libavfilter/vf_selectivecolor.c +++ b/libavfilter/vf_selectivecolor.c @@ -344,7 +344,7 @@ static inline int selective_color_##nbits(AVFilterContext *ctx, ThreadData *td, const int max_color = FFMAX3(r, g, b); \ const int is_white = (r > 1<<(nbits-1) && g > 1<<(nbits-1) && b > 1<<(nbits-1)); \ const int is_neutral = (r || g || b) && \ - r != (1<src; SeparateFieldsContext *s = ctx->priv; - int ret; + int ret = 0; - ret = ff_request_frame(ctx->inputs[0]); - if (ret == AVERROR_EOF && s->second) { - s->second->pts *= 2; + if (s->second) { + *out_pts = s->second->pts += pts; extract_field(s->second, s->nb_planes, s->second->top_field_first); ret = ff_filter_frame(outlink, s->second); - s->second = 0; + s->second = NULL; } return ret; } +static int activate(AVFilterContext *ctx) +{ + AVFilterLink *inlink = ctx->inputs[0]; + AVFilterLink *outlink = ctx->outputs[0]; + AVFrame *in; + int64_t pts; + int ret, status; + + FF_FILTER_FORWARD_STATUS_BACK(outlink, inlink); + + ret = ff_inlink_consume_frame(inlink, &in); + if (ret < 0) + return ret; + if (ret > 0) + return filter_frame(inlink, in); + + if (ff_inlink_acknowledge_status(inlink, &status, &pts)) { + if (status == AVERROR_EOF) { + int64_t out_pts = pts; + + ret = flush_frame(outlink, pts, &out_pts); + ff_outlink_set_status(outlink, status, out_pts); + return ret; + } + } + + FF_FILTER_FORWARD_WANTED(outlink, inlink); + + return FFERROR_NOT_READY; +} + static av_cold void uninit(AVFilterContext *ctx) { SeparateFieldsContext *s = ctx->priv; @@ -129,7 +160,6 @@ static const AVFilterPad separatefields_inputs[] = { { .name = "default", .type = AVMEDIA_TYPE_VIDEO, - .filter_frame = filter_frame, }, { NULL } }; @@ -139,7 +169,6 @@ static const AVFilterPad separatefields_outputs[] = { .name = "default", .type = AVMEDIA_TYPE_VIDEO, .config_props = config_props_output, - .request_frame = request_frame, }, { NULL } }; @@ -148,6 +177,7 @@ AVFilter ff_vf_separatefields = { .name = "separatefields", .description = NULL_IF_CONFIG_SMALL("Split input video frames into fields."), .priv_size = sizeof(SeparateFieldsContext), + .activate = activate, .uninit = uninit, .inputs = separatefields_inputs, .outputs = separatefields_outputs, diff --git a/libavfilter/vf_setparams.c b/libavfilter/vf_setparams.c index 8427f98ba..fe298e5a0 100644 --- a/libavfilter/vf_setparams.c +++ b/libavfilter/vf_setparams.c @@ -1,4 +1,6 @@ /* + * Copyright (c) 2012 Stefano Sabatini + * * This file is part of FFmpeg. * * FFmpeg is free software; you can redistribute it and/or @@ -22,15 +24,32 @@ #include "internal.h" #include "video.h" +enum SetFieldMode { + MODE_AUTO = -1, + MODE_BFF, + MODE_TFF, + MODE_PROG, +}; + typedef struct SetParamsContext { const AVClass *class; + int field_mode; int color_range; + int color_primaries; + int color_trc; + int colorspace; } SetParamsContext; #define OFFSET(x) offsetof(SetParamsContext, x) #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM -static const AVOption setrange_options[] = { +static const AVOption setparams_options[] = { + {"field_mode", "select interlace mode", OFFSET(field_mode), AV_OPT_TYPE_INT, {.i64=MODE_AUTO}, -1, MODE_PROG, FLAGS, "mode"}, + {"auto", "keep the same input field", 0, AV_OPT_TYPE_CONST, {.i64=MODE_AUTO}, INT_MIN, INT_MAX, FLAGS, "mode"}, + {"bff", "mark as bottom-field-first", 0, AV_OPT_TYPE_CONST, {.i64=MODE_BFF}, INT_MIN, INT_MAX, FLAGS, "mode"}, + {"tff", "mark as top-field-first", 0, AV_OPT_TYPE_CONST, {.i64=MODE_TFF}, INT_MIN, INT_MAX, FLAGS, "mode"}, + {"prog", "mark as progressive", 0, AV_OPT_TYPE_CONST, {.i64=MODE_PROG}, INT_MIN, INT_MAX, FLAGS, "mode"}, + {"range", "select color range", OFFSET(color_range), AV_OPT_TYPE_INT, {.i64=-1},-1, AVCOL_RANGE_NB-1, FLAGS, "range"}, {"auto", "keep the same color range", 0, AV_OPT_TYPE_CONST, {.i64=-1}, 0, 0, FLAGS, "range"}, {"unspecified", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_RANGE_UNSPECIFIED}, 0, 0, FLAGS, "range"}, @@ -41,18 +60,87 @@ static const AVOption setrange_options[] = { {"full", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_RANGE_JPEG}, 0, 0, FLAGS, "range"}, {"pc", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_RANGE_JPEG}, 0, 0, FLAGS, "range"}, {"jpeg", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_RANGE_JPEG}, 0, 0, FLAGS, "range"}, + + {"color_primaries", "select color primaries", OFFSET(color_primaries), AV_OPT_TYPE_INT, {.i64=-1}, -1, AVCOL_PRI_NB-1, FLAGS, "color_primaries"}, + {"auto", "keep the same color primaries", 0, AV_OPT_TYPE_CONST, {.i64=-1}, INT_MIN, INT_MAX, FLAGS, "color_primaries"}, + {"bt709", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_PRI_BT709}, INT_MIN, INT_MAX, FLAGS, "color_primaries"}, + {"unknown", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_PRI_UNSPECIFIED}, INT_MIN, INT_MAX, FLAGS, "color_primaries"}, + {"bt470m", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_PRI_BT470M}, INT_MIN, INT_MAX, FLAGS, "color_primaries"}, + {"bt470bg", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_PRI_BT470BG}, INT_MIN, INT_MAX, FLAGS, "color_primaries"}, + {"smpte170m", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_PRI_SMPTE170M}, INT_MIN, INT_MAX, FLAGS, "color_primaries"}, + {"smpte240m", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_PRI_SMPTE240M}, INT_MIN, INT_MAX, FLAGS, "color_primaries"}, + {"film", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_PRI_FILM}, INT_MIN, INT_MAX, FLAGS, "color_primaries"}, + {"bt2020", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_PRI_BT2020}, INT_MIN, INT_MAX, FLAGS, "color_primaries"}, + {"smpte428", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_PRI_SMPTE428}, INT_MIN, INT_MAX, FLAGS, "color_primaries"}, + {"smpte431", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_PRI_SMPTE431}, INT_MIN, INT_MAX, FLAGS, "color_primaries"}, + {"smpte432", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_PRI_SMPTE432}, INT_MIN, INT_MAX, FLAGS, "color_primaries"}, + {"jedec-p22", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_PRI_JEDEC_P22}, INT_MIN, INT_MAX, FLAGS, "color_primaries"}, + + {"color_trc", "select color transfer", OFFSET(color_trc), AV_OPT_TYPE_INT, {.i64=-1}, -1, AVCOL_TRC_NB-1, FLAGS, "color_trc"}, + {"auto", "keep the same color transfer", 0, AV_OPT_TYPE_CONST, {.i64=-1}, INT_MIN, INT_MAX, FLAGS, "color_trc"}, + {"bt709", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_BT709}, INT_MIN, INT_MAX, FLAGS, "color_trc"}, + {"unknown", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_UNSPECIFIED}, INT_MIN, INT_MAX, FLAGS, "color_trc"}, + {"bt470m", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_GAMMA22}, INT_MIN, INT_MAX, FLAGS, "color_trc"}, + {"bt470bg", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_GAMMA28}, INT_MIN, INT_MAX, FLAGS, "color_trc"}, + {"smpte170m", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_SMPTE170M}, INT_MIN, INT_MAX, FLAGS, "color_trc"}, + {"smpte240m", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_SMPTE240M}, INT_MIN, INT_MAX, FLAGS, "color_trc"}, + {"linear", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_LINEAR}, INT_MIN, INT_MAX, FLAGS, "color_trc"}, + {"log100", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_LOG}, INT_MIN, INT_MAX, FLAGS, "color_trc"}, + {"log316", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_LOG_SQRT}, INT_MIN, INT_MAX, FLAGS, "color_trc"}, + {"iec61966-2-4", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_IEC61966_2_4}, INT_MIN, INT_MAX, FLAGS, "color_trc"}, + {"bt1361e", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_BT1361_ECG}, INT_MIN, INT_MAX, FLAGS, "color_trc"}, + {"iec61966-2-1", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_IEC61966_2_1}, INT_MIN, INT_MAX, FLAGS, "color_trc"}, + {"bt2020-10", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_BT2020_10}, INT_MIN, INT_MAX, FLAGS, "color_trc"}, + {"bt2020-12", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_BT2020_12}, INT_MIN, INT_MAX, FLAGS, "color_trc"}, + {"smpte2084", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_SMPTE2084}, INT_MIN, INT_MAX, FLAGS, "color_trc"}, + {"smpte428", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_SMPTE428}, INT_MIN, INT_MAX, FLAGS, "color_trc"}, + {"arib-std-b67", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_TRC_ARIB_STD_B67}, INT_MIN, INT_MAX, FLAGS, "color_trc"}, + + {"colorspace", "select colorspace", OFFSET(colorspace), AV_OPT_TYPE_INT, {.i64=-1}, -1, AVCOL_SPC_NB-1, FLAGS, "colorspace"}, + {"auto", "keep the same colorspace", 0, AV_OPT_TYPE_CONST, {.i64=-1}, INT_MIN, INT_MAX, FLAGS, "colorspace"}, + {"gbr", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_SPC_RGB}, INT_MIN, INT_MAX, FLAGS, "colorspace"}, + {"bt709", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_SPC_BT709}, INT_MIN, INT_MAX, FLAGS, "colorspace"}, + {"unknown", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_SPC_UNSPECIFIED}, INT_MIN, INT_MAX, FLAGS, "colorspace"}, + {"fcc", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_SPC_FCC}, INT_MIN, INT_MAX, FLAGS, "colorspace"}, + {"bt470bg", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_SPC_BT470BG}, INT_MIN, INT_MAX, FLAGS, "colorspace"}, + {"smpte170m", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_SPC_SMPTE170M}, INT_MIN, INT_MAX, FLAGS, "colorspace"}, + {"smpte240m", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_SPC_SMPTE240M}, INT_MIN, INT_MAX, FLAGS, "colorspace"}, + {"ycgco", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_SPC_YCGCO}, INT_MIN, INT_MAX, FLAGS, "colorspace"}, + {"bt2020nc", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_SPC_BT2020_NCL}, INT_MIN, INT_MAX, FLAGS, "colorspace"}, + {"bt2020c", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_SPC_BT2020_CL}, INT_MIN, INT_MAX, FLAGS, "colorspace"}, + {"smpte2085", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_SPC_SMPTE2085}, INT_MIN, INT_MAX, FLAGS, "colorspace"}, + {"chroma-derived-nc", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_SPC_CHROMA_DERIVED_NCL},INT_MIN, INT_MAX, FLAGS, "colorspace"}, + {"chroma-derived-c", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_SPC_CHROMA_DERIVED_CL}, INT_MIN, INT_MAX, FLAGS, "colorspace"}, + {"ictcp", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_SPC_ICTCP}, INT_MIN, INT_MAX, FLAGS, "colorspace"}, {NULL} }; -AVFILTER_DEFINE_CLASS(setrange); +AVFILTER_DEFINE_CLASS(setparams); static int filter_frame(AVFilterLink *inlink, AVFrame *frame) { AVFilterContext *ctx = inlink->dst; SetParamsContext *s = ctx->priv; + /* set field */ + if (s->field_mode == MODE_PROG) { + frame->interlaced_frame = 0; + } else if (s->field_mode != MODE_AUTO) { + frame->interlaced_frame = 1; + frame->top_field_first = s->field_mode; + } + + /* set range */ if (s->color_range >= 0) frame->color_range = s->color_range; + + /* set color prim, trc, space */ + if (s->color_primaries >= 0) + frame->color_primaries = s->color_primaries; + if (s->color_trc >= 0) + frame->color_trc = s->color_trc; + if (s->colorspace >= 0) + frame->colorspace = s->colorspace; return ff_filter_frame(ctx->outputs[0], frame); } @@ -73,11 +161,85 @@ static const AVFilterPad outputs[] = { { NULL } }; +AVFilter ff_vf_setparams = { + .name = "setparams", + .description = NULL_IF_CONFIG_SMALL("Force field, or color property for the output video frame."), + .priv_size = sizeof(SetParamsContext), + .priv_class = &setparams_class, + .inputs = inputs, + .outputs = outputs, +}; + +#if CONFIG_SETRANGE_FILTER + +static const AVOption setrange_options[] = { + {"range", "select color range", OFFSET(color_range), AV_OPT_TYPE_INT, {.i64=-1},-1, AVCOL_RANGE_NB-1, FLAGS, "range"}, + {"auto", "keep the same color range", 0, AV_OPT_TYPE_CONST, {.i64=-1}, 0, 0, FLAGS, "range"}, + {"unspecified", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_RANGE_UNSPECIFIED}, 0, 0, FLAGS, "range"}, + {"unknown", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_RANGE_UNSPECIFIED}, 0, 0, FLAGS, "range"}, + {"limited", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_RANGE_MPEG}, 0, 0, FLAGS, "range"}, + {"tv", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_RANGE_MPEG}, 0, 0, FLAGS, "range"}, + {"mpeg", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_RANGE_MPEG}, 0, 0, FLAGS, "range"}, + {"full", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_RANGE_JPEG}, 0, 0, FLAGS, "range"}, + {"pc", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_RANGE_JPEG}, 0, 0, FLAGS, "range"}, + {"jpeg", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_RANGE_JPEG}, 0, 0, FLAGS, "range"}, + {NULL} +}; + +AVFILTER_DEFINE_CLASS(setrange); + +static av_cold int init_setrange(AVFilterContext *ctx) +{ + SetParamsContext *s = ctx->priv; + + s->field_mode = MODE_AUTO;/* set field mode to auto */ + s->color_primaries = -1; + s->color_trc = -1; + s->colorspace = -1; + return 0; +} + AVFilter ff_vf_setrange = { .name = "setrange", .description = NULL_IF_CONFIG_SMALL("Force color range for the output video frame."), .priv_size = sizeof(SetParamsContext), + .init = init_setrange, .priv_class = &setrange_class, .inputs = inputs, .outputs = outputs, }; +#endif /* CONFIG_SETRANGE_FILTER */ + +#if CONFIG_SETFIELD_FILTER +static const AVOption setfield_options[] = { + {"mode", "select interlace mode", OFFSET(field_mode), AV_OPT_TYPE_INT, {.i64=MODE_AUTO}, -1, MODE_PROG, FLAGS, "mode"}, + {"auto", "keep the same input field", 0, AV_OPT_TYPE_CONST, {.i64=MODE_AUTO}, INT_MIN, INT_MAX, FLAGS, "mode"}, + {"bff", "mark as bottom-field-first", 0, AV_OPT_TYPE_CONST, {.i64=MODE_BFF}, INT_MIN, INT_MAX, FLAGS, "mode"}, + {"tff", "mark as top-field-first", 0, AV_OPT_TYPE_CONST, {.i64=MODE_TFF}, INT_MIN, INT_MAX, FLAGS, "mode"}, + {"prog", "mark as progressive", 0, AV_OPT_TYPE_CONST, {.i64=MODE_PROG}, INT_MIN, INT_MAX, FLAGS, "mode"}, + {NULL} +}; + +AVFILTER_DEFINE_CLASS(setfield); + +static av_cold int init_setfield(AVFilterContext *ctx) +{ + SetParamsContext *s = ctx->priv; + + s->color_range = -1;/* set range mode to auto */ + s->color_primaries = -1; + s->color_trc = -1; + s->colorspace = -1; + return 0; +} + +AVFilter ff_vf_setfield = { + .name = "setfield", + .description = NULL_IF_CONFIG_SMALL("Force field for the output video frame."), + .priv_size = sizeof(SetParamsContext), + .init = init_setfield, + .priv_class = &setfield_class, + .inputs = inputs, + .outputs = outputs, +}; +#endif /* CONFIG_SETFIELD_FILTER */ diff --git a/libavfilter/vf_showinfo.c b/libavfilter/vf_showinfo.c index d1d1415c0..f6f8f4977 100644 --- a/libavfilter/vf_showinfo.c +++ b/libavfilter/vf_showinfo.c @@ -28,15 +28,32 @@ #include "libavutil/display.h" #include "libavutil/imgutils.h" #include "libavutil/internal.h" +#include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "libavutil/spherical.h" #include "libavutil/stereo3d.h" #include "libavutil/timestamp.h" +#include "libavutil/timecode.h" #include "avfilter.h" #include "internal.h" #include "video.h" +typedef struct ShowInfoContext { + const AVClass *class; + int calculate_checksums; +} ShowInfoContext; + +#define OFFSET(x) offsetof(ShowInfoContext, x) +#define VF AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM + +static const AVOption showinfo_options[] = { + { "checksum", "calculate checksums", OFFSET(calculate_checksums), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1, VF }, + { NULL } +}; + +AVFILTER_DEFINE_CLASS(showinfo); + static void dump_spherical(AVFilterContext *ctx, AVFrame *frame, AVFrameSideData *sd) { AVSphericalMapping *spherical = (AVSphericalMapping *)sd->data; @@ -94,6 +111,61 @@ static void dump_stereo3d(AVFilterContext *ctx, AVFrameSideData *sd) av_log(ctx, AV_LOG_INFO, " (inverted)"); } +static void dump_roi(AVFilterContext *ctx, AVFrameSideData *sd) +{ + int nb_rois; + const AVRegionOfInterest *roi; + uint32_t roi_size; + + roi = (const AVRegionOfInterest *)sd->data; + roi_size = roi->self_size; + if (!roi_size || sd->size % roi_size != 0) { + av_log(ctx, AV_LOG_ERROR, "Invalid AVRegionOfInterest.self_size.\n"); + return; + } + nb_rois = sd->size / roi_size; + + av_log(ctx, AV_LOG_INFO, "Regions Of Interest(RoI) information: "); + for (int i = 0; i < nb_rois; i++) { + roi = (const AVRegionOfInterest *)(sd->data + roi_size * i); + av_log(ctx, AV_LOG_INFO, "index: %d, region: (%d, %d)/(%d, %d), qp offset: %d/%d.\n", + i, roi->left, roi->top, roi->right, roi->bottom, roi->qoffset.num, roi->qoffset.den); + } +} + +static void dump_color_property(AVFilterContext *ctx, AVFrame *frame) +{ + const char *color_range_str = av_color_range_name(frame->color_range); + const char *colorspace_str = av_color_space_name(frame->colorspace); + const char *color_primaries_str = av_color_primaries_name(frame->color_primaries); + const char *color_trc_str = av_color_transfer_name(frame->color_trc); + + if (!color_range_str || frame->color_range == AVCOL_RANGE_UNSPECIFIED) { + av_log(ctx, AV_LOG_INFO, "color_range:unknown"); + } else { + av_log(ctx, AV_LOG_INFO, "color_range:%s", color_range_str); + } + + if (!colorspace_str || frame->colorspace == AVCOL_SPC_UNSPECIFIED) { + av_log(ctx, AV_LOG_INFO, " color_space:unknown"); + } else { + av_log(ctx, AV_LOG_INFO, " color_space:%s", colorspace_str); + } + + if (!color_primaries_str || frame->color_primaries == AVCOL_PRI_UNSPECIFIED) { + av_log(ctx, AV_LOG_INFO, " color_primaries:unknown"); + } else { + av_log(ctx, AV_LOG_INFO, " color_primaries:%s", color_primaries_str); + } + + if (!color_trc_str || frame->color_trc == AVCOL_TRC_UNSPECIFIED) { + av_log(ctx, AV_LOG_INFO, " color_trc:unknown"); + } else { + av_log(ctx, AV_LOG_INFO, " color_trc:%s", color_trc_str); + } + av_log(ctx, AV_LOG_INFO, "\n"); +} + static void update_sample_stats(const uint8_t *src, int len, int64_t *sum, int64_t *sum2) { int i; @@ -107,13 +179,14 @@ static void update_sample_stats(const uint8_t *src, int len, int64_t *sum, int64 static int filter_frame(AVFilterLink *inlink, AVFrame *frame) { AVFilterContext *ctx = inlink->dst; + ShowInfoContext *s = ctx->priv; const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format); uint32_t plane_checksum[4] = {0}, checksum = 0; int64_t sum[4] = {0}, sum2[4] = {0}; int32_t pixelcount[4] = {0}; int i, plane, vsub = desc->log2_chroma_h; - for (plane = 0; plane < 4 && frame->data[plane] && frame->linesize[plane]; plane++) { + for (plane = 0; plane < 4 && s->calculate_checksums && frame->data[plane] && frame->linesize[plane]; plane++) { uint8_t *data = frame->data[plane]; int h = plane == 1 || plane == 2 ? AV_CEIL_RSHIFT(inlink->h, vsub) : inlink->h; int linesize = av_image_get_linesize(frame->format, frame->width, plane); @@ -133,8 +206,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame) av_log(ctx, AV_LOG_INFO, "n:%4"PRId64" pts:%7s pts_time:%-7s pos:%9"PRId64" " - "fmt:%s sar:%d/%d s:%dx%d i:%c iskey:%d type:%c " - "checksum:%08"PRIX32" plane_checksum:[%08"PRIX32, + "fmt:%s sar:%d/%d s:%dx%d i:%c iskey:%d type:%c ", inlink->frame_count_out, av_ts2str(frame->pts), av_ts2timestr(frame->pts, &inlink->time_base), frame->pkt_pos, desc->name, @@ -143,19 +215,25 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame) !frame->interlaced_frame ? 'P' : /* Progressive */ frame->top_field_first ? 'T' : 'B', /* Top / Bottom */ frame->key_frame, - av_get_picture_type_char(frame->pict_type), - checksum, plane_checksum[0]); + av_get_picture_type_char(frame->pict_type)); - for (plane = 1; plane < 4 && frame->data[plane] && frame->linesize[plane]; plane++) - av_log(ctx, AV_LOG_INFO, " %08"PRIX32, plane_checksum[plane]); - av_log(ctx, AV_LOG_INFO, "] mean:["); - for (plane = 0; plane < 4 && frame->data[plane] && frame->linesize[plane]; plane++) - av_log(ctx, AV_LOG_INFO, "%"PRId64" ", (sum[plane] + pixelcount[plane]/2) / pixelcount[plane]); - av_log(ctx, AV_LOG_INFO, "\b] stdev:["); - for (plane = 0; plane < 4 && frame->data[plane] && frame->linesize[plane]; plane++) - av_log(ctx, AV_LOG_INFO, "%3.1f ", - sqrt((sum2[plane] - sum[plane]*(double)sum[plane]/pixelcount[plane])/pixelcount[plane])); - av_log(ctx, AV_LOG_INFO, "\b]\n"); + if (s->calculate_checksums) { + av_log(ctx, AV_LOG_INFO, + "checksum:%08"PRIX32" plane_checksum:[%08"PRIX32, + checksum, plane_checksum[0]); + + for (plane = 1; plane < 4 && frame->data[plane] && frame->linesize[plane]; plane++) + av_log(ctx, AV_LOG_INFO, " %08"PRIX32, plane_checksum[plane]); + av_log(ctx, AV_LOG_INFO, "] mean:["); + for (plane = 0; plane < 4 && frame->data[plane] && frame->linesize[plane]; plane++) + av_log(ctx, AV_LOG_INFO, "%"PRId64" ", (sum[plane] + pixelcount[plane]/2) / pixelcount[plane]); + av_log(ctx, AV_LOG_INFO, "\b] stdev:["); + for (plane = 0; plane < 4 && frame->data[plane] && frame->linesize[plane]; plane++) + av_log(ctx, AV_LOG_INFO, "%3.1f ", + sqrt((sum2[plane] - sum[plane]*(double)sum[plane]/pixelcount[plane])/pixelcount[plane])); + av_log(ctx, AV_LOG_INFO, "\b]"); + } + av_log(ctx, AV_LOG_INFO, "\n"); for (i = 0; i < frame->nb_side_data; i++) { AVFrameSideData *sd = frame->side_data[i]; @@ -174,6 +252,15 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame) case AV_FRAME_DATA_STEREO3D: dump_stereo3d(ctx, sd); break; + case AV_FRAME_DATA_S12M_TIMECODE: { + uint32_t *tc = (uint32_t*)sd->data; + for (int j = 1; j <= tc[0]; j++) { + char tcbuf[AV_TIMECODE_STR_SIZE]; + av_timecode_make_smpte_tc_string(tcbuf, tc[j], 0); + av_log(ctx, AV_LOG_INFO, "timecode - %s%s", tcbuf, j != tc[0] ? ", " : ""); + } + break; + } case AV_FRAME_DATA_DISPLAYMATRIX: av_log(ctx, AV_LOG_INFO, "displaymatrix: rotation of %.2f degrees", av_display_rotation_get((int32_t *)sd->data)); @@ -181,6 +268,9 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame) case AV_FRAME_DATA_AFD: av_log(ctx, AV_LOG_INFO, "afd: value of %"PRIu8, sd->data[0]); break; + case AV_FRAME_DATA_REGIONS_OF_INTEREST: + dump_roi(ctx, sd); + break; default: av_log(ctx, AV_LOG_WARNING, "unknown side data type %d (%d bytes)", sd->type, sd->size); @@ -190,6 +280,8 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame) av_log(ctx, AV_LOG_INFO, "\n"); } + dump_color_property(ctx, frame); + return ff_filter_frame(inlink->dst->outputs[0], frame); } @@ -240,4 +332,6 @@ AVFilter ff_vf_showinfo = { .description = NULL_IF_CONFIG_SMALL("Show textual information for each video frame."), .inputs = avfilter_vf_showinfo_inputs, .outputs = avfilter_vf_showinfo_outputs, + .priv_size = sizeof(ShowInfoContext), + .priv_class = &showinfo_class, }; diff --git a/libavfilter/vf_shuffleplanes.c b/libavfilter/vf_shuffleplanes.c index 32d2d585f..5d1302db0 100644 --- a/libavfilter/vf_shuffleplanes.c +++ b/libavfilter/vf_shuffleplanes.c @@ -158,10 +158,9 @@ static const AVFilterPad shuffleplanes_outputs[] = { AVFilter ff_vf_shuffleplanes = { .name = "shuffleplanes", .description = NULL_IF_CONFIG_SMALL("Shuffle video planes."), - .priv_size = sizeof(ShufflePlanesContext), .priv_class = &shuffleplanes_class, - .inputs = shuffleplanes_inputs, .outputs = shuffleplanes_outputs, + .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC, }; diff --git a/libavfilter/vf_signalstats.c b/libavfilter/vf_signalstats.c index 298881bc7..2b8c0de4c 100644 --- a/libavfilter/vf_signalstats.c +++ b/libavfilter/vf_signalstats.c @@ -830,7 +830,7 @@ static int filter_frame16(AVFilterLink *link, AVFrame *in) masky |= yuv; histy[yuv]++; - dify += abs(yuv - AV_RN16(prev->data[0] + pw + i * 2)); + dify += abs(yuv - (int)AV_RN16(prev->data[0] + pw + i * 2)); } w += in->linesize[0]; pw += prev->linesize[0]; @@ -848,9 +848,9 @@ static int filter_frame16(AVFilterLink *link, AVFrame *in) masku |= yuvu; maskv |= yuvv; histu[yuvu]++; - difu += abs(yuvu - AV_RN16(prev->data[1] + cpw + i * 2)); + difu += abs(yuvu - (int)AV_RN16(prev->data[1] + cpw + i * 2)); histv[yuvv]++; - difv += abs(yuvv - AV_RN16(prev->data[2] + cpw + i * 2)); + difv += abs(yuvv - (int)AV_RN16(prev->data[2] + cpw + i * 2)); histsat[p_sat[i]]++; histhue[((int16_t*)p_hue)[i]]++; diff --git a/libavfilter/vf_sr.c b/libavfilter/vf_sr.c new file mode 100644 index 000000000..0433246e2 --- /dev/null +++ b/libavfilter/vf_sr.c @@ -0,0 +1,321 @@ +/* + * Copyright (c) 2018 Sergey Lavrushkin + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * Filter implementing image super-resolution using deep convolutional networks. + * https://arxiv.org/abs/1501.00092 + * https://arxiv.org/abs/1609.05158 + */ + +#include "avfilter.h" +#include "formats.h" +#include "internal.h" +#include "libavutil/opt.h" +#include "libavutil/pixdesc.h" +#include "libavformat/avio.h" +#include "libswscale/swscale.h" +#include "dnn_interface.h" + +typedef struct SRContext { + const AVClass *class; + + char *model_filename; + DNNBackendType backend_type; + DNNModule *dnn_module; + DNNModel *model; + DNNInputData input; + DNNData output; + int scale_factor; + struct SwsContext *sws_contexts[3]; + int sws_slice_h, sws_input_linesize, sws_output_linesize; +} SRContext; + +#define OFFSET(x) offsetof(SRContext, x) +#define FLAGS AV_OPT_FLAG_FILTERING_PARAM | AV_OPT_FLAG_VIDEO_PARAM +static const AVOption sr_options[] = { + { "dnn_backend", "DNN backend used for model execution", OFFSET(backend_type), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, FLAGS, "backend" }, + { "native", "native backend flag", 0, AV_OPT_TYPE_CONST, { .i64 = 0 }, 0, 0, FLAGS, "backend" }, +#if (CONFIG_LIBTENSORFLOW == 1) + { "tensorflow", "tensorflow backend flag", 0, AV_OPT_TYPE_CONST, { .i64 = 1 }, 0, 0, FLAGS, "backend" }, +#endif + { "scale_factor", "scale factor for SRCNN model", OFFSET(scale_factor), AV_OPT_TYPE_INT, { .i64 = 2 }, 2, 4, FLAGS }, + { "model", "path to model file specifying network architecture and its parameters", OFFSET(model_filename), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 0, FLAGS }, + { NULL } +}; + +AVFILTER_DEFINE_CLASS(sr); + +static av_cold int init(AVFilterContext *context) +{ + SRContext *sr_context = context->priv; + + sr_context->dnn_module = ff_get_dnn_module(sr_context->backend_type); + if (!sr_context->dnn_module){ + av_log(context, AV_LOG_ERROR, "could not create DNN module for requested backend\n"); + return AVERROR(ENOMEM); + } + + if (!sr_context->model_filename){ + av_log(context, AV_LOG_ERROR, "model file for network was not specified\n"); + return AVERROR(EIO); + } + if (!sr_context->dnn_module->load_model) { + av_log(context, AV_LOG_ERROR, "load_model for network was not specified\n"); + return AVERROR(EIO); + } + sr_context->model = (sr_context->dnn_module->load_model)(sr_context->model_filename); + if (!sr_context->model){ + av_log(context, AV_LOG_ERROR, "could not load DNN model\n"); + return AVERROR(EIO); + } + + sr_context->input.dt = DNN_FLOAT; + sr_context->sws_contexts[0] = NULL; + sr_context->sws_contexts[1] = NULL; + sr_context->sws_contexts[2] = NULL; + + return 0; +} + +static int query_formats(AVFilterContext *context) +{ + const enum AVPixelFormat pixel_formats[] = {AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV444P, + AV_PIX_FMT_YUV410P, AV_PIX_FMT_YUV411P, AV_PIX_FMT_GRAY8, + AV_PIX_FMT_NONE}; + AVFilterFormats *formats_list; + + formats_list = ff_make_format_list(pixel_formats); + if (!formats_list){ + av_log(context, AV_LOG_ERROR, "could not create formats list\n"); + return AVERROR(ENOMEM); + } + + return ff_set_common_formats(context, formats_list); +} + +static int config_props(AVFilterLink *inlink) +{ + AVFilterContext *context = inlink->dst; + SRContext *sr_context = context->priv; + AVFilterLink *outlink = context->outputs[0]; + DNNReturnType result; + int sws_src_h, sws_src_w, sws_dst_h, sws_dst_w; + const char *model_output_name = "y"; + + sr_context->input.width = inlink->w * sr_context->scale_factor; + sr_context->input.height = inlink->h * sr_context->scale_factor; + sr_context->input.channels = 1; + + result = (sr_context->model->set_input_output)(sr_context->model->model, &sr_context->input, "x", &model_output_name, 1); + if (result != DNN_SUCCESS){ + av_log(context, AV_LOG_ERROR, "could not set input and output for the model\n"); + return AVERROR(EIO); + } + + result = (sr_context->dnn_module->execute_model)(sr_context->model, &sr_context->output, 1); + if (result != DNN_SUCCESS){ + av_log(context, AV_LOG_ERROR, "failed to execute loaded model\n"); + return AVERROR(EIO); + } + + if (sr_context->input.height != sr_context->output.height || sr_context->input.width != sr_context->output.width){ + sr_context->input.width = inlink->w; + sr_context->input.height = inlink->h; + result = (sr_context->model->set_input_output)(sr_context->model->model, &sr_context->input, "x", &model_output_name, 1); + if (result != DNN_SUCCESS){ + av_log(context, AV_LOG_ERROR, "could not set input and output for the model\n"); + return AVERROR(EIO); + } + result = (sr_context->dnn_module->execute_model)(sr_context->model, &sr_context->output, 1); + if (result != DNN_SUCCESS){ + av_log(context, AV_LOG_ERROR, "failed to execute loaded model\n"); + return AVERROR(EIO); + } + sr_context->scale_factor = 0; + } + outlink->h = sr_context->output.height; + outlink->w = sr_context->output.width; + sr_context->sws_contexts[1] = sws_getContext(sr_context->input.width, sr_context->input.height, AV_PIX_FMT_GRAY8, + sr_context->input.width, sr_context->input.height, AV_PIX_FMT_GRAYF32, + 0, NULL, NULL, NULL); + sr_context->sws_input_linesize = sr_context->input.width << 2; + sr_context->sws_contexts[2] = sws_getContext(sr_context->output.width, sr_context->output.height, AV_PIX_FMT_GRAYF32, + sr_context->output.width, sr_context->output.height, AV_PIX_FMT_GRAY8, + 0, NULL, NULL, NULL); + sr_context->sws_output_linesize = sr_context->output.width << 2; + if (!sr_context->sws_contexts[1] || !sr_context->sws_contexts[2]){ + av_log(context, AV_LOG_ERROR, "could not create SwsContext for conversions\n"); + return AVERROR(ENOMEM); + } + if (sr_context->scale_factor){ + sr_context->sws_contexts[0] = sws_getContext(inlink->w, inlink->h, inlink->format, + outlink->w, outlink->h, outlink->format, + SWS_BICUBIC, NULL, NULL, NULL); + if (!sr_context->sws_contexts[0]){ + av_log(context, AV_LOG_ERROR, "could not create SwsContext for scaling\n"); + return AVERROR(ENOMEM); + } + sr_context->sws_slice_h = inlink->h; + } else { + if (inlink->format != AV_PIX_FMT_GRAY8){ + sws_src_h = sr_context->input.height; + sws_src_w = sr_context->input.width; + sws_dst_h = sr_context->output.height; + sws_dst_w = sr_context->output.width; + + switch (inlink->format){ + case AV_PIX_FMT_YUV420P: + sws_src_h = AV_CEIL_RSHIFT(sws_src_h, 1); + sws_src_w = AV_CEIL_RSHIFT(sws_src_w, 1); + sws_dst_h = AV_CEIL_RSHIFT(sws_dst_h, 1); + sws_dst_w = AV_CEIL_RSHIFT(sws_dst_w, 1); + break; + case AV_PIX_FMT_YUV422P: + sws_src_w = AV_CEIL_RSHIFT(sws_src_w, 1); + sws_dst_w = AV_CEIL_RSHIFT(sws_dst_w, 1); + break; + case AV_PIX_FMT_YUV444P: + break; + case AV_PIX_FMT_YUV410P: + sws_src_h = AV_CEIL_RSHIFT(sws_src_h, 2); + sws_src_w = AV_CEIL_RSHIFT(sws_src_w, 2); + sws_dst_h = AV_CEIL_RSHIFT(sws_dst_h, 2); + sws_dst_w = AV_CEIL_RSHIFT(sws_dst_w, 2); + break; + case AV_PIX_FMT_YUV411P: + sws_src_w = AV_CEIL_RSHIFT(sws_src_w, 2); + sws_dst_w = AV_CEIL_RSHIFT(sws_dst_w, 2); + break; + default: + av_log(context, AV_LOG_ERROR, + "could not create SwsContext for scaling for given input pixel format: %s\n", + av_get_pix_fmt_name(inlink->format)); + return AVERROR(EIO); + } + sr_context->sws_contexts[0] = sws_getContext(sws_src_w, sws_src_h, AV_PIX_FMT_GRAY8, + sws_dst_w, sws_dst_h, AV_PIX_FMT_GRAY8, + SWS_BICUBIC, NULL, NULL, NULL); + if (!sr_context->sws_contexts[0]){ + av_log(context, AV_LOG_ERROR, "could not create SwsContext for scaling\n"); + return AVERROR(ENOMEM); + } + sr_context->sws_slice_h = sws_src_h; + } + } + + return 0; +} + +static int filter_frame(AVFilterLink *inlink, AVFrame *in) +{ + AVFilterContext *context = inlink->dst; + SRContext *sr_context = context->priv; + AVFilterLink *outlink = context->outputs[0]; + AVFrame *out = ff_get_video_buffer(outlink, outlink->w, outlink->h); + DNNReturnType dnn_result; + + if (!out){ + av_log(context, AV_LOG_ERROR, "could not allocate memory for output frame\n"); + av_frame_free(&in); + return AVERROR(ENOMEM); + } + av_frame_copy_props(out, in); + out->height = sr_context->output.height; + out->width = sr_context->output.width; + if (sr_context->scale_factor){ + sws_scale(sr_context->sws_contexts[0], (const uint8_t **)in->data, in->linesize, + 0, sr_context->sws_slice_h, out->data, out->linesize); + + sws_scale(sr_context->sws_contexts[1], (const uint8_t **)out->data, out->linesize, + 0, out->height, (uint8_t * const*)(&sr_context->input.data), + (const int [4]){sr_context->sws_input_linesize, 0, 0, 0}); + } else { + if (sr_context->sws_contexts[0]){ + sws_scale(sr_context->sws_contexts[0], (const uint8_t **)(in->data + 1), in->linesize + 1, + 0, sr_context->sws_slice_h, out->data + 1, out->linesize + 1); + sws_scale(sr_context->sws_contexts[0], (const uint8_t **)(in->data + 2), in->linesize + 2, + 0, sr_context->sws_slice_h, out->data + 2, out->linesize + 2); + } + + sws_scale(sr_context->sws_contexts[1], (const uint8_t **)in->data, in->linesize, + 0, in->height, (uint8_t * const*)(&sr_context->input.data), + (const int [4]){sr_context->sws_input_linesize, 0, 0, 0}); + } + av_frame_free(&in); + + dnn_result = (sr_context->dnn_module->execute_model)(sr_context->model, &sr_context->output, 1); + if (dnn_result != DNN_SUCCESS){ + av_log(context, AV_LOG_ERROR, "failed to execute loaded model\n"); + return AVERROR(EIO); + } + + sws_scale(sr_context->sws_contexts[2], (const uint8_t *[4]){(const uint8_t *)sr_context->output.data, 0, 0, 0}, + (const int[4]){sr_context->sws_output_linesize, 0, 0, 0}, + 0, out->height, (uint8_t * const*)out->data, out->linesize); + + return ff_filter_frame(outlink, out); +} + +static av_cold void uninit(AVFilterContext *context) +{ + int i; + SRContext *sr_context = context->priv; + + if (sr_context->dnn_module){ + (sr_context->dnn_module->free_model)(&sr_context->model); + av_freep(&sr_context->dnn_module); + } + + for (i = 0; i < 3; ++i){ + sws_freeContext(sr_context->sws_contexts[i]); + } +} + +static const AVFilterPad sr_inputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + .config_props = config_props, + .filter_frame = filter_frame, + }, + { NULL } +}; + +static const AVFilterPad sr_outputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + }, + { NULL } +}; + +AVFilter ff_vf_sr = { + .name = "sr", + .description = NULL_IF_CONFIG_SMALL("Apply DNN-based image super resolution to the input."), + .priv_size = sizeof(SRContext), + .init = init, + .uninit = uninit, + .query_formats = query_formats, + .inputs = sr_inputs, + .outputs = sr_outputs, + .priv_class = &sr_class, + .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC, +}; diff --git a/libavfilter/vf_ssim.c b/libavfilter/vf_ssim.c index 4dcdc0548..4c957f41a 100644 --- a/libavfilter/vf_ssim.c +++ b/libavfilter/vf_ssim.c @@ -359,7 +359,7 @@ static int query_formats(AVFilterContext *ctx) { static const enum AVPixelFormat pix_fmts[] = { AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY9, AV_PIX_FMT_GRAY10, - AV_PIX_FMT_GRAY12, AV_PIX_FMT_GRAY16, + AV_PIX_FMT_GRAY12, AV_PIX_FMT_GRAY14, AV_PIX_FMT_GRAY16, AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUV440P, AV_PIX_FMT_YUV411P, AV_PIX_FMT_YUV410P, AV_PIX_FMT_YUVJ411P, AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUVJ422P, diff --git a/libavfilter/vf_stack.c b/libavfilter/vf_stack.c index b2b8c6804..4d254e001 100644 --- a/libavfilter/vf_stack.c +++ b/libavfilter/vf_stack.c @@ -29,14 +29,23 @@ #include "framesync.h" #include "video.h" +typedef struct StackItem { + int x[4], y[4]; + int linesize[4]; + int height[4]; +} StackItem; + typedef struct StackContext { const AVClass *class; const AVPixFmtDescriptor *desc; int nb_inputs; + char *layout; int shortest; int is_vertical; + int is_horizontal; int nb_planes; + StackItem *items; AVFrame **frames; FFFrameSync fs; } StackContext; @@ -66,10 +75,30 @@ static av_cold int init(AVFilterContext *ctx) if (!strcmp(ctx->filter->name, "vstack")) s->is_vertical = 1; + if (!strcmp(ctx->filter->name, "hstack")) + s->is_horizontal = 1; + s->frames = av_calloc(s->nb_inputs, sizeof(*s->frames)); if (!s->frames) return AVERROR(ENOMEM); + if (!strcmp(ctx->filter->name, "xstack")) { + if (!s->layout) { + if (s->nb_inputs == 2) { + s->layout = av_strdup("0_0|w0_0"); + if (!s->layout) + return AVERROR(ENOMEM); + } else { + av_log(ctx, AV_LOG_ERROR, "No layout specified.\n"); + return AVERROR(EINVAL); + } + } + + s->items = av_calloc(s->nb_inputs, sizeof(*s->items)); + if (!s->items) + return AVERROR(ENOMEM); + } + for (i = 0; i < s->nb_inputs; i++) { AVFilterPad pad = { 0 }; @@ -112,13 +141,15 @@ static int process_frame(FFFrameSync *fs) int linesize[4]; int height[4]; - if ((ret = av_image_fill_linesizes(linesize, inlink->format, inlink->w)) < 0) { - av_frame_free(&out); - return ret; - } + if (s->is_horizontal || s->is_vertical) { + if ((ret = av_image_fill_linesizes(linesize, inlink->format, inlink->w)) < 0) { + av_frame_free(&out); + return ret; + } - height[1] = height[2] = AV_CEIL_RSHIFT(inlink->h, s->desc->log2_chroma_h); - height[0] = height[3] = inlink->h; + height[1] = height[2] = AV_CEIL_RSHIFT(inlink->h, s->desc->log2_chroma_h); + height[0] = height[3] = inlink->h; + } for (p = 0; p < s->nb_planes; p++) { if (s->is_vertical) { @@ -128,13 +159,21 @@ static int process_frame(FFFrameSync *fs) in[i]->linesize[p], linesize[p], height[p]); offset[p] += height[p]; - } else { + } else if (s->is_horizontal) { av_image_copy_plane(out->data[p] + offset[p], out->linesize[p], in[i]->data[p], in[i]->linesize[p], linesize[p], height[p]); offset[p] += linesize[p]; + } else { + StackItem *item = &s->items[i]; + + av_image_copy_plane(out->data[p] + out->linesize[p] * item->y[p] + item->x[p], + out->linesize[p], + in[i]->data[p], + in[i]->linesize[p], + item->linesize[p], item->height[p]); } } } @@ -146,7 +185,6 @@ static int config_output(AVFilterLink *outlink) { AVFilterContext *ctx = outlink->src; StackContext *s = ctx->priv; - AVRational time_base = ctx->inputs[0]->time_base; AVRational frame_rate = ctx->inputs[0]->frame_rate; AVRational sar = ctx->inputs[0]->sample_aspect_ratio; int height = ctx->inputs[0]->h; @@ -154,6 +192,10 @@ static int config_output(AVFilterLink *outlink) FFFrameSyncIn *in; int i, ret; + s->desc = av_pix_fmt_desc_get(outlink->format); + if (!s->desc) + return AVERROR_BUG; + if (s->is_vertical) { for (i = 1; i < s->nb_inputs; i++) { if (ctx->inputs[i]->w != width) { @@ -162,7 +204,7 @@ static int config_output(AVFilterLink *outlink) } height += ctx->inputs[i]->h; } - } else { + } else if (s->is_horizontal) { for (i = 1; i < s->nb_inputs; i++) { if (ctx->inputs[i]->h != height) { av_log(ctx, AV_LOG_ERROR, "Input %d height %d does not match input %d height %d.\n", i, ctx->inputs[i]->h, 0, height); @@ -170,16 +212,85 @@ static int config_output(AVFilterLink *outlink) } width += ctx->inputs[i]->w; } + } else { + char *arg, *p = s->layout, *saveptr = NULL; + char *arg2, *p2, *saveptr2 = NULL; + char *arg3, *p3, *saveptr3 = NULL; + int inw, inh, size; + + for (i = 0; i < s->nb_inputs; i++) { + AVFilterLink *inlink = ctx->inputs[i]; + StackItem *item = &s->items[i]; + + if (!(arg = av_strtok(p, "|", &saveptr))) + return AVERROR(EINVAL); + + p = NULL; + + if ((ret = av_image_fill_linesizes(item->linesize, inlink->format, inlink->w)) < 0) { + return ret; + } + + item->height[1] = item->height[2] = AV_CEIL_RSHIFT(inlink->h, s->desc->log2_chroma_h); + item->height[0] = item->height[3] = inlink->h; + + p2 = arg; + inw = inh = 0; + + for (int j = 0; j < 2; j++) { + if (!(arg2 = av_strtok(p2, "_", &saveptr2))) + return AVERROR(EINVAL); + + p2 = NULL; + p3 = arg2; + while ((arg3 = av_strtok(p3, "+", &saveptr3))) { + p3 = NULL; + if (sscanf(arg3, "w%d", &size) == 1) { + if (size == i || size < 0 || size >= s->nb_inputs) + return AVERROR(EINVAL); + + if (!j) + inw += ctx->inputs[size]->w; + else + inh += ctx->inputs[size]->w; + } else if (sscanf(arg3, "h%d", &size) == 1) { + if (size == i || size < 0 || size >= s->nb_inputs) + return AVERROR(EINVAL); + + if (!j) + inw += ctx->inputs[size]->h; + else + inh += ctx->inputs[size]->h; + } else if (sscanf(arg3, "%d", &size) == 1) { + if (size < 0) + return AVERROR(EINVAL); + + if (!j) + inw += size; + else + inh += size; + } else { + return AVERROR(EINVAL); + } + } + } + + if ((ret = av_image_fill_linesizes(item->x, inlink->format, inw)) < 0) { + return ret; + } + + item->y[1] = item->y[2] = AV_CEIL_RSHIFT(inh, s->desc->log2_chroma_h); + item->y[0] = item->y[3] = inh; + + width = FFMAX(width, inlink->w + inw); + height = FFMAX(height, inlink->h + inh); + } } - s->desc = av_pix_fmt_desc_get(outlink->format); - if (!s->desc) - return AVERROR_BUG; s->nb_planes = av_pix_fmt_count_planes(outlink->format); outlink->w = width; outlink->h = height; - outlink->time_base = time_base; outlink->frame_rate = frame_rate; outlink->sample_aspect_ratio = sar; @@ -199,7 +310,10 @@ static int config_output(AVFilterLink *outlink) in[i].after = s->shortest ? EXT_STOP : EXT_INFINITY; } - return ff_framesync_configure(&s->fs); + ret = ff_framesync_configure(&s->fs); + outlink->time_base = s->fs.time_base; + + return ret; } static av_cold void uninit(AVFilterContext *ctx) @@ -209,6 +323,7 @@ static av_cold void uninit(AVFilterContext *ctx) ff_framesync_uninit(&s->fs); av_freep(&s->frames); + av_freep(&s->items); for (i = 0; i < ctx->nb_inputs; i++) av_freep(&ctx->input_pads[i].name); @@ -276,3 +391,29 @@ AVFilter ff_vf_vstack = { }; #endif /* CONFIG_VSTACK_FILTER */ + +#if CONFIG_XSTACK_FILTER + +static const AVOption xstack_options[] = { + { "inputs", "set number of inputs", OFFSET(nb_inputs), AV_OPT_TYPE_INT, {.i64=2}, 2, INT_MAX, .flags = FLAGS }, + { "layout", "set custom layout", OFFSET(layout), AV_OPT_TYPE_STRING, {.str=NULL}, 0, 0, .flags = FLAGS }, + { "shortest", "force termination when the shortest input terminates", OFFSET(shortest), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, .flags = FLAGS }, + { NULL }, +}; + +AVFILTER_DEFINE_CLASS(xstack); + +AVFilter ff_vf_xstack = { + .name = "xstack", + .description = NULL_IF_CONFIG_SMALL("Stack video inputs into custom layout."), + .priv_size = sizeof(StackContext), + .priv_class = &xstack_class, + .query_formats = query_formats, + .outputs = outputs, + .init = init, + .uninit = uninit, + .activate = activate, + .flags = AVFILTER_FLAG_DYNAMIC_INPUTS, +}; + +#endif /* CONFIG_XSTACK_FILTER */ diff --git a/libavfilter/vf_swaprect.c b/libavfilter/vf_swaprect.c index f96f89781..f1fab1e36 100644 --- a/libavfilter/vf_swaprect.c +++ b/libavfilter/vf_swaprect.c @@ -151,32 +151,32 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) x2[0] = av_clip(x2[0], 0, inlink->w - 1); y2[0] = av_clip(y2[0], 0, inlink->w - 1); - ah[1] = ah[2] = FF_CEIL_RSHIFT(h, s->desc->log2_chroma_h); + ah[1] = ah[2] = AV_CEIL_RSHIFT(h, s->desc->log2_chroma_h); ah[0] = ah[3] = h; - aw[1] = aw[2] = FF_CEIL_RSHIFT(w, s->desc->log2_chroma_w); + aw[1] = aw[2] = AV_CEIL_RSHIFT(w, s->desc->log2_chroma_w); aw[0] = aw[3] = w; w = FFMIN3(w, inlink->w - x1[0], inlink->w - x2[0]); h = FFMIN3(h, inlink->h - y1[0], inlink->h - y2[0]); - ph[1] = ph[2] = FF_CEIL_RSHIFT(h, s->desc->log2_chroma_h); + ph[1] = ph[2] = AV_CEIL_RSHIFT(h, s->desc->log2_chroma_h); ph[0] = ph[3] = h; - pw[1] = pw[2] = FF_CEIL_RSHIFT(w, s->desc->log2_chroma_w); + pw[1] = pw[2] = AV_CEIL_RSHIFT(w, s->desc->log2_chroma_w); pw[0] = pw[3] = w; - lh[1] = lh[2] = FF_CEIL_RSHIFT(inlink->h, s->desc->log2_chroma_h); + lh[1] = lh[2] = AV_CEIL_RSHIFT(inlink->h, s->desc->log2_chroma_h); lh[0] = lh[3] = inlink->h; - lw[1] = lw[2] = FF_CEIL_RSHIFT(inlink->w, s->desc->log2_chroma_w); + lw[1] = lw[2] = AV_CEIL_RSHIFT(inlink->w, s->desc->log2_chroma_w); lw[0] = lw[3] = inlink->w; - x1[1] = x1[2] = FF_CEIL_RSHIFT(x1[0], s->desc->log2_chroma_w); + x1[1] = x1[2] = AV_CEIL_RSHIFT(x1[0], s->desc->log2_chroma_w); x1[0] = x1[3] = x1[0]; - y1[1] = y1[2] = FF_CEIL_RSHIFT(y1[0], s->desc->log2_chroma_h); + y1[1] = y1[2] = AV_CEIL_RSHIFT(y1[0], s->desc->log2_chroma_h); y1[0] = y1[3] = y1[0]; - x2[1] = x2[2] = FF_CEIL_RSHIFT(x2[0], s->desc->log2_chroma_w); + x2[1] = x2[2] = AV_CEIL_RSHIFT(x2[0], s->desc->log2_chroma_w); x2[0] = x2[3] = x2[0]; - y2[1] = y2[2] = FF_CEIL_RSHIFT(y2[0], s->desc->log2_chroma_h); + y2[1] = y2[2] = AV_CEIL_RSHIFT(y2[0], s->desc->log2_chroma_h); y2[0] = y2[3] = y2[0]; for (p = 0; p < s->nb_planes; p++) { diff --git a/libavfilter/vf_threshold.c b/libavfilter/vf_threshold.c index 58b5d1483..ee29c88ef 100644 --- a/libavfilter/vf_threshold.c +++ b/libavfilter/vf_threshold.c @@ -61,19 +61,66 @@ static int query_formats(AVFilterContext *ctx) AV_PIX_FMT_GBRP12, AV_PIX_FMT_GBRP14, AV_PIX_FMT_GBRP16, AV_PIX_FMT_GBRAP, AV_PIX_FMT_GBRAP10, AV_PIX_FMT_GBRAP12 , AV_PIX_FMT_GBRAP16, AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY9, AV_PIX_FMT_GRAY10, - AV_PIX_FMT_GRAY12, AV_PIX_FMT_GRAY16, + AV_PIX_FMT_GRAY12, AV_PIX_FMT_GRAY14, AV_PIX_FMT_GRAY16, AV_PIX_FMT_NONE }; return ff_set_common_formats(ctx, ff_make_format_list(pix_fmts)); } +typedef struct ThreadData { + AVFrame *in; + AVFrame *threshold; + AVFrame *min; + AVFrame *max; + AVFrame *out; +} ThreadData; + +static int filter_slice(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) +{ + ThresholdContext *s = ctx->priv; + ThreadData *td = arg; + AVFrame *min = td->min; + AVFrame *max = td->max; + AVFrame *threshold = td->threshold; + AVFrame *in = td->in; + AVFrame *out = td->out; + + for (int p = 0; p < s->nb_planes; p++) { + const int h = s->height[p]; + const int slice_start = (h * jobnr) / nb_jobs; + const int slice_end = (h * (jobnr+1)) / nb_jobs; + + if (!(s->planes & (1 << p))) { + av_image_copy_plane(out->data[p] + slice_start * out->linesize[p], + out->linesize[p], + in->data[p] + slice_start * in->linesize[p], + in->linesize[p], + s->width[p] * s->bpc, + slice_end - slice_start); + continue; + } + s->threshold(in->data[p] + slice_start * in->linesize[p], + threshold->data[p] + slice_start * threshold->linesize[p], + min->data[p] + slice_start * min->linesize[p], + max->data[p] + slice_start * max->linesize[p], + out->data[p] + slice_start * out->linesize[p], + in->linesize[p], threshold->linesize[p], + min->linesize[p], max->linesize[p], + out->linesize[p], + s->width[p], slice_end - slice_start); + } + + return 0; +} + static int process_frame(FFFrameSync *fs) { AVFilterContext *ctx = fs->parent; ThresholdContext *s = fs->opaque; AVFilterLink *outlink = ctx->outputs[0]; AVFrame *out, *in, *threshold, *min, *max; + ThreadData td; int ret; if ((ret = ff_framesync_get_frame(&s->fs, 0, &in, 0)) < 0 || @@ -87,29 +134,18 @@ static int process_frame(FFFrameSync *fs) if (!out) return AVERROR(ENOMEM); } else { - int p; - out = ff_get_video_buffer(outlink, outlink->w, outlink->h); if (!out) return AVERROR(ENOMEM); av_frame_copy_props(out, in); - for (p = 0; p < s->nb_planes; p++) { - if (!(s->planes & (1 << p))) { - av_image_copy_plane(out->data[p], out->linesize[p], - in->data[p], in->linesize[p], - s->width[p] * s->bpc, - s->height[p]); - continue; - } - s->threshold(in->data[p], threshold->data[p], - min->data[p], max->data[p], - out->data[p], - in->linesize[p], threshold->linesize[p], - min->linesize[p], max->linesize[p], - out->linesize[p], - s->width[p], s->height[p]); - } + td.out = out; + td.in = in; + td.threshold = threshold; + td.min = min; + td.max = max; + ctx->internal->execute(ctx, filter_slice, &td, NULL, + FFMIN(s->height[2], ff_filter_get_nb_threads(ctx))); } out->pts = av_rescale_q(s->fs.pts, s->fs.time_base, outlink->time_base); @@ -241,7 +277,6 @@ static int config_output(AVFilterLink *outlink) outlink->w = base->w; outlink->h = base->h; - outlink->time_base = base->time_base; outlink->sample_aspect_ratio = base->sample_aspect_ratio; outlink->frame_rate = base->frame_rate; @@ -268,7 +303,10 @@ static int config_output(AVFilterLink *outlink) s->fs.opaque = s; s->fs.on_event = process_frame; - return ff_framesync_configure(&s->fs); + ret = ff_framesync_configure(&s->fs); + outlink->time_base = s->fs.time_base; + + return ret; } static int activate(AVFilterContext *ctx) @@ -324,5 +362,5 @@ AVFilter ff_vf_threshold = { .activate = activate, .inputs = inputs, .outputs = outputs, - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, + .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | AVFILTER_FLAG_SLICE_THREADS, }; diff --git a/libavfilter/vf_thumbnail_cuda.c b/libavfilter/vf_thumbnail_cuda.c index 09377ca7f..0c0681564 100644 --- a/libavfilter/vf_thumbnail_cuda.c +++ b/libavfilter/vf_thumbnail_cuda.c @@ -20,16 +20,17 @@ * DEALINGS IN THE SOFTWARE. */ -#include - #include "libavutil/hwcontext.h" #include "libavutil/hwcontext_cuda_internal.h" +#include "libavutil/cuda_check.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "avfilter.h" #include "internal.h" +#define CHECK_CU(x) FF_CUDA_CHECK_DL(ctx, s->hwctx->internal->cuda_dl, x) + #define HIST_SIZE (3*256) #define DIV_UP(a, b) ( ((a) + (b) - 1) / (b) ) #define BLOCKX 32 @@ -57,6 +58,7 @@ typedef struct ThumbnailCudaContext { AVRational tb; ///< copy of the input timebase to ease access AVBufferRef *hw_frames_ctx; + AVCUDADeviceContext *hwctx; CUmodule cu_module; @@ -64,12 +66,10 @@ typedef struct ThumbnailCudaContext { CUfunction cu_func_uchar2; CUfunction cu_func_ushort; CUfunction cu_func_ushort2; - CUtexref cu_tex_uchar; - CUtexref cu_tex_uchar2; - CUtexref cu_tex_ushort; - CUtexref cu_tex_ushort2; + CUstream cu_stream; CUdeviceptr data; + } ThumbnailCudaContext; #define OFFSET(x) offsetof(ThumbnailCudaContext, x) @@ -154,27 +154,44 @@ static AVFrame *get_best_frame(AVFilterContext *ctx) return picref; } -static int thumbnail_kernel(ThumbnailCudaContext *s, CUfunction func, CUtexref tex, int channels, +static int thumbnail_kernel(AVFilterContext *ctx, CUfunction func, int channels, int *histogram, uint8_t *src_dptr, int src_width, int src_height, int src_pitch, int pixel_size) { - CUdeviceptr src_devptr = (CUdeviceptr)src_dptr; - void *args[] = { &histogram, &src_width, &src_height }; - CUDA_ARRAY_DESCRIPTOR desc; + int ret; + ThumbnailCudaContext *s = ctx->priv; + CudaFunctions *cu = s->hwctx->internal->cuda_dl; + CUtexObject tex = 0; + void *args[] = { &tex, &histogram, &src_width, &src_height }; - desc.Width = src_width; - desc.Height = src_height; - desc.NumChannels = channels; - if (pixel_size == 1) { - desc.Format = CU_AD_FORMAT_UNSIGNED_INT8; - } - else { - desc.Format = CU_AD_FORMAT_UNSIGNED_INT16; - } + CUDA_TEXTURE_DESC tex_desc = { + .filterMode = CU_TR_FILTER_MODE_LINEAR, + .flags = CU_TRSF_READ_AS_INTEGER, + }; - cuTexRefSetAddress2D_v3(tex, &desc, src_devptr, src_pitch); - cuLaunchKernel(func, DIV_UP(src_width, BLOCKX), DIV_UP(src_height, BLOCKY), 1, BLOCKX, BLOCKY, 1, 0, 0, args, NULL); + CUDA_RESOURCE_DESC res_desc = { + .resType = CU_RESOURCE_TYPE_PITCH2D, + .res.pitch2D.format = pixel_size == 1 ? + CU_AD_FORMAT_UNSIGNED_INT8 : + CU_AD_FORMAT_UNSIGNED_INT16, + .res.pitch2D.numChannels = channels, + .res.pitch2D.width = src_width, + .res.pitch2D.height = src_height, + .res.pitch2D.pitchInBytes = src_pitch, + .res.pitch2D.devPtr = (CUdeviceptr)src_dptr, + }; - return 0; + ret = CHECK_CU(cu->cuTexObjectCreate(&tex, &res_desc, &tex_desc, NULL)); + if (ret < 0) + goto exit; + + ret = CHECK_CU(cu->cuLaunchKernel(func, + DIV_UP(src_width, BLOCKX), DIV_UP(src_height, BLOCKY), 1, + BLOCKX, BLOCKY, 1, 0, s->cu_stream, args, NULL)); +exit: + if (tex) + CHECK_CU(cu->cuTexObjectDestroy(tex)); + + return ret; } static int thumbnail(AVFilterContext *ctx, int *histogram, AVFrame *in) @@ -184,40 +201,40 @@ static int thumbnail(AVFilterContext *ctx, int *histogram, AVFrame *in) switch (in_frames_ctx->sw_format) { case AV_PIX_FMT_NV12: - thumbnail_kernel(s, s->cu_func_uchar, s->cu_tex_uchar, 1, + thumbnail_kernel(ctx, s->cu_func_uchar, 1, histogram, in->data[0], in->width, in->height, in->linesize[0], 1); - thumbnail_kernel(s, s->cu_func_uchar2, s->cu_tex_uchar2, 2, + thumbnail_kernel(ctx, s->cu_func_uchar2, 2, histogram + 256, in->data[1], in->width / 2, in->height / 2, in->linesize[1], 1); break; case AV_PIX_FMT_YUV420P: - thumbnail_kernel(s, s->cu_func_uchar, s->cu_tex_uchar, 1, + thumbnail_kernel(ctx, s->cu_func_uchar, 1, histogram, in->data[0], in->width, in->height, in->linesize[0], 1); - thumbnail_kernel(s, s->cu_func_uchar, s->cu_tex_uchar, 1, + thumbnail_kernel(ctx, s->cu_func_uchar, 1, histogram + 256, in->data[1], in->width / 2, in->height / 2, in->linesize[1], 1); - thumbnail_kernel(s, s->cu_func_uchar, s->cu_tex_uchar, 1, + thumbnail_kernel(ctx, s->cu_func_uchar, 1, histogram + 512, in->data[2], in->width / 2, in->height / 2, in->linesize[2], 1); break; case AV_PIX_FMT_YUV444P: - thumbnail_kernel(s, s->cu_func_uchar, s->cu_tex_uchar, 1, + thumbnail_kernel(ctx, s->cu_func_uchar, 1, histogram, in->data[0], in->width, in->height, in->linesize[0], 1); - thumbnail_kernel(s, s->cu_func_uchar, s->cu_tex_uchar, 1, + thumbnail_kernel(ctx, s->cu_func_uchar, 1, histogram + 256, in->data[1], in->width, in->height, in->linesize[1], 1); - thumbnail_kernel(s, s->cu_func_uchar, s->cu_tex_uchar, 1, + thumbnail_kernel(ctx, s->cu_func_uchar, 1, histogram + 512, in->data[2], in->width, in->height, in->linesize[2], 1); break; case AV_PIX_FMT_P010LE: case AV_PIX_FMT_P016LE: - thumbnail_kernel(s, s->cu_func_ushort, s->cu_tex_ushort, 1, + thumbnail_kernel(ctx, s->cu_func_ushort, 1, histogram, in->data[0], in->width, in->height, in->linesize[0], 2); - thumbnail_kernel(s, s->cu_func_ushort2, s->cu_tex_ushort2, 2, + thumbnail_kernel(ctx, s->cu_func_ushort2, 2, histogram + 256, in->data[1], in->width / 2, in->height / 2, in->linesize[1], 2); break; case AV_PIX_FMT_YUV444P16: - thumbnail_kernel(s, s->cu_func_ushort2, s->cu_tex_uchar, 1, + thumbnail_kernel(ctx, s->cu_func_ushort2, 1, histogram, in->data[0], in->width, in->height, in->linesize[0], 2); - thumbnail_kernel(s, s->cu_func_ushort2, s->cu_tex_uchar, 1, + thumbnail_kernel(ctx, s->cu_func_ushort2, 1, histogram + 256, in->data[1], in->width, in->height, in->linesize[1], 2); - thumbnail_kernel(s, s->cu_func_ushort2, s->cu_tex_uchar, 1, + thumbnail_kernel(ctx, s->cu_func_ushort2, 1, histogram + 512, in->data[2], in->width, in->height, in->linesize[2], 2); break; default: @@ -231,11 +248,10 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame) { AVFilterContext *ctx = inlink->dst; ThumbnailCudaContext *s = ctx->priv; + CudaFunctions *cu = s->hwctx->internal->cuda_dl; AVFilterLink *outlink = ctx->outputs[0]; int *hist = s->frames[s->n].histogram; AVHWFramesContext *hw_frames_ctx = (AVHWFramesContext*)s->hw_frames_ctx->data; - AVCUDADeviceContext *device_hwctx = hw_frames_ctx->device_ctx->hwctx; - CUresult err; CUcontext dummy; CUDA_MEMCPY2D cpy = { 0 }; int ret = 0; @@ -243,11 +259,11 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame) // keep a reference of each frame s->frames[s->n].buf = frame; - err = cuCtxPushCurrent(device_hwctx->cuda_ctx); - if (err != CUDA_SUCCESS) - return AVERROR_UNKNOWN; + ret = CHECK_CU(cu->cuCtxPushCurrent(s->hwctx->cuda_ctx)); + if (ret < 0) + return ret; - cuMemsetD8(s->data, 0, HIST_SIZE * sizeof(int)); + CHECK_CU(cu->cuMemsetD8Async(s->data, 0, HIST_SIZE * sizeof(int), s->cu_stream)); thumbnail(ctx, (int*)s->data, frame); @@ -260,11 +276,9 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame) cpy.WidthInBytes = HIST_SIZE * sizeof(int); cpy.Height = 1; - err = cuMemcpy2D(&cpy); - if (err != CUDA_SUCCESS) { - av_log(ctx, AV_LOG_ERROR, "Error transferring the data from the CUDA frame\n"); - return AVERROR_UNKNOWN; - } + ret = CHECK_CU(cu->cuMemcpy2DAsync(&cpy, s->cu_stream)); + if (ret < 0) + return ret; if (hw_frames_ctx->sw_format == AV_PIX_FMT_NV12 || hw_frames_ctx->sw_format == AV_PIX_FMT_YUV420P || hw_frames_ctx->sw_format == AV_PIX_FMT_P010LE || hw_frames_ctx->sw_format == AV_PIX_FMT_P016LE) @@ -274,7 +288,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame) hist[i] = 4 * hist[i]; } - cuCtxPopCurrent(&dummy); + CHECK_CU(cu->cuCtxPopCurrent(&dummy)); if (ret < 0) return ret; @@ -290,14 +304,15 @@ static av_cold void uninit(AVFilterContext *ctx) { int i; ThumbnailCudaContext *s = ctx->priv; + CudaFunctions *cu = s->hwctx->internal->cuda_dl; if (s->data) { - cuMemFree(s->data); + CHECK_CU(cu->cuMemFree(s->data)); s->data = 0; } if (s->cu_module) { - cuModuleUnload(s->cu_module); + CHECK_CU(cu->cuModuleUnload(s->cu_module)); s->cu_module = NULL; } @@ -340,49 +355,43 @@ static int config_props(AVFilterLink *inlink) AVHWFramesContext *hw_frames_ctx = (AVHWFramesContext*)inlink->hw_frames_ctx->data; AVCUDADeviceContext *device_hwctx = hw_frames_ctx->device_ctx->hwctx; CUcontext dummy, cuda_ctx = device_hwctx->cuda_ctx; - CUresult err; + CudaFunctions *cu = device_hwctx->internal->cuda_dl; + int ret; extern char vf_thumbnail_cuda_ptx[]; - err = cuCtxPushCurrent(cuda_ctx); - if (err != CUDA_SUCCESS) { - av_log(ctx, AV_LOG_ERROR, "Error pushing cuda context\n"); - return AVERROR_UNKNOWN; - } + s->hwctx = device_hwctx; + s->cu_stream = s->hwctx->stream; - err = cuModuleLoadData(&s->cu_module, vf_thumbnail_cuda_ptx); - if (err != CUDA_SUCCESS) { - av_log(ctx, AV_LOG_ERROR, "Error loading module data\n"); - return AVERROR_UNKNOWN; - } + ret = CHECK_CU(cu->cuCtxPushCurrent(cuda_ctx)); + if (ret < 0) + return ret; - cuModuleGetFunction(&s->cu_func_uchar, s->cu_module, "Thumbnail_uchar"); - cuModuleGetFunction(&s->cu_func_uchar2, s->cu_module, "Thumbnail_uchar2"); - cuModuleGetFunction(&s->cu_func_ushort, s->cu_module, "Thumbnail_ushort"); - cuModuleGetFunction(&s->cu_func_ushort2, s->cu_module, "Thumbnail_ushort2"); + ret = CHECK_CU(cu->cuModuleLoadData(&s->cu_module, vf_thumbnail_cuda_ptx)); + if (ret < 0) + return ret; - cuModuleGetTexRef(&s->cu_tex_uchar, s->cu_module, "uchar_tex"); - cuModuleGetTexRef(&s->cu_tex_uchar2, s->cu_module, "uchar2_tex"); - cuModuleGetTexRef(&s->cu_tex_ushort, s->cu_module, "ushort_tex"); - cuModuleGetTexRef(&s->cu_tex_ushort2, s->cu_module, "ushort2_tex"); + ret = CHECK_CU(cu->cuModuleGetFunction(&s->cu_func_uchar, s->cu_module, "Thumbnail_uchar")); + if (ret < 0) + return ret; - cuTexRefSetFlags(s->cu_tex_uchar, CU_TRSF_READ_AS_INTEGER); - cuTexRefSetFlags(s->cu_tex_uchar2, CU_TRSF_READ_AS_INTEGER); - cuTexRefSetFlags(s->cu_tex_ushort, CU_TRSF_READ_AS_INTEGER); - cuTexRefSetFlags(s->cu_tex_ushort2, CU_TRSF_READ_AS_INTEGER); + ret = CHECK_CU(cu->cuModuleGetFunction(&s->cu_func_uchar2, s->cu_module, "Thumbnail_uchar2")); + if (ret < 0) + return ret; - cuTexRefSetFilterMode(s->cu_tex_uchar, CU_TR_FILTER_MODE_LINEAR); - cuTexRefSetFilterMode(s->cu_tex_uchar2, CU_TR_FILTER_MODE_LINEAR); - cuTexRefSetFilterMode(s->cu_tex_ushort, CU_TR_FILTER_MODE_LINEAR); - cuTexRefSetFilterMode(s->cu_tex_ushort2, CU_TR_FILTER_MODE_LINEAR); + ret = CHECK_CU(cu->cuModuleGetFunction(&s->cu_func_ushort, s->cu_module, "Thumbnail_ushort")); + if (ret < 0) + return ret; - err = cuMemAlloc(&s->data, HIST_SIZE * sizeof(int)); - if (err != CUDA_SUCCESS) { - av_log(ctx, AV_LOG_ERROR, "Error allocating cuda memory\n"); - return AVERROR_UNKNOWN; - } + ret = CHECK_CU(cu->cuModuleGetFunction(&s->cu_func_ushort2, s->cu_module, "Thumbnail_ushort2")); + if (ret < 0) + return ret; - cuCtxPopCurrent(&dummy); + ret = CHECK_CU(cu->cuMemAlloc(&s->data, HIST_SIZE * sizeof(int))); + if (ret < 0) + return ret; + + CHECK_CU(cu->cuCtxPopCurrent(&dummy)); s->hw_frames_ctx = ctx->inputs[0]->hw_frames_ctx; diff --git a/libavfilter/vf_thumbnail_cuda.cu b/libavfilter/vf_thumbnail_cuda.cu index 98fad4303..d4d4d791f 100644 --- a/libavfilter/vf_thumbnail_cuda.cu +++ b/libavfilter/vf_thumbnail_cuda.cu @@ -22,57 +22,56 @@ extern "C" { -texture uchar_tex; -texture uchar2_tex; -texture ushort_tex; -texture ushort2_tex; - -__global__ void Thumbnail_uchar(int *histogram, int src_width, int src_height) +__global__ void Thumbnail_uchar(cudaTextureObject_t uchar_tex, + int *histogram, int src_width, int src_height) { int x = blockIdx.x * blockDim.x + threadIdx.x; int y = blockIdx.y * blockDim.y + threadIdx.y; if (y < src_height && x < src_width) { - unsigned char pixel = tex2D(uchar_tex, x, y); + unsigned char pixel = tex2D(uchar_tex, x, y); atomicAdd(&histogram[pixel], 1); } } -__global__ void Thumbnail_uchar2(int *histogram, int src_width, int src_height) +__global__ void Thumbnail_uchar2(cudaTextureObject_t uchar2_tex, + int *histogram, int src_width, int src_height) { int x = blockIdx.x * blockDim.x + threadIdx.x; int y = blockIdx.y * blockDim.y + threadIdx.y; if (y < src_height && x < src_width) { - uchar2 pixel = tex2D(uchar2_tex, x, y); + uchar2 pixel = tex2D(uchar2_tex, x, y); atomicAdd(&histogram[pixel.x], 1); atomicAdd(&histogram[256 + pixel.y], 1); } } -__global__ void Thumbnail_ushort(int *histogram, int src_width, int src_height) +__global__ void Thumbnail_ushort(cudaTextureObject_t ushort_tex, + int *histogram, int src_width, int src_height) { int x = blockIdx.x * blockDim.x + threadIdx.x; int y = blockIdx.y * blockDim.y + threadIdx.y; if (y < src_height && x < src_width) { - unsigned short pixel = (tex2D(ushort_tex, x, y) + 128) >> 8; + unsigned short pixel = (tex2D(ushort_tex, x, y) + 128) >> 8; atomicAdd(&histogram[pixel], 1); } } -__global__ void Thumbnail_ushort2(int *histogram, int src_width, int src_height) +__global__ void Thumbnail_ushort2(cudaTextureObject_t ushort2_tex, + int *histogram, int src_width, int src_height) { int x = blockIdx.x * blockDim.x + threadIdx.x; int y = blockIdx.y * blockDim.y + threadIdx.y; if (y < src_height && x < src_width) { - ushort2 pixel = tex2D(ushort2_tex, x, y); + ushort2 pixel = tex2D(ushort2_tex, x, y); atomicAdd(&histogram[(pixel.x + 128) >> 8], 1); - atomicAdd(&histogram[256 + (pixel.y + 128) >> 8], 1); + atomicAdd(&histogram[256 + ((pixel.y + 128) >> 8)], 1); } } diff --git a/libavfilter/vf_tinterlace.c b/libavfilter/vf_tinterlace.c index f13791d25..fc5d11e05 100644 --- a/libavfilter/vf_tinterlace.c +++ b/libavfilter/vf_tinterlace.c @@ -59,6 +59,20 @@ static const AVOption tinterlace_options[] = { AVFILTER_DEFINE_CLASS(tinterlace); +static const AVOption interlace_options[] = { + { "scan", "scanning mode", OFFSET(mode), AV_OPT_TYPE_INT, {.i64 = MODE_TFF}, 0, 1, FLAGS, "mode"}, + { "tff", "top field first", 0, AV_OPT_TYPE_CONST, {.i64 = MODE_TFF}, INT_MIN, INT_MAX, FLAGS, .unit = "mode"}, + { "bff", "bottom field first", 0, AV_OPT_TYPE_CONST, {.i64 = MODE_BFF}, INT_MIN, INT_MAX, FLAGS, .unit = "mode"}, + { "lowpass", "set vertical low-pass filter", OFFSET(flags), AV_OPT_TYPE_FLAGS, {.i64 = TINTERLACE_FLAG_VLPF}, 0, 2, FLAGS, "flags" }, + { "off", "disable vertical low-pass filter", 0, AV_OPT_TYPE_CONST, {.i64 = 0}, INT_MIN, INT_MAX, FLAGS, "flags" }, + { "linear", "linear vertical low-pass filter", 0, AV_OPT_TYPE_CONST, {.i64 = TINTERLACE_FLAG_VLPF}, INT_MIN, INT_MAX, FLAGS, "flags" }, + { "complex", "complex vertical low-pass filter", 0, AV_OPT_TYPE_CONST, {.i64 = TINTERLACE_FLAG_CVLPF},INT_MIN, INT_MAX, FLAGS, "flags" }, + + { NULL } +}; + +AVFILTER_DEFINE_CLASS(interlace); + #define FULL_SCALE_YUVJ_FORMATS \ AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_YUVJ440P @@ -497,6 +511,16 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *picref) return ret; } +static int init_interlace(AVFilterContext *ctx) +{ + TInterlaceContext *tinterlace = ctx->priv; + + if (tinterlace->mode <= MODE_BFF) + tinterlace->mode += MODE_INTERLEAVE_TOP; + + return 0; +} + static const AVFilterPad tinterlace_inputs[] = { { .name = "default", @@ -525,3 +549,16 @@ AVFilter ff_vf_tinterlace = { .outputs = tinterlace_outputs, .priv_class = &tinterlace_class, }; + + +AVFilter ff_vf_interlace = { + .name = "interlace", + .description = NULL_IF_CONFIG_SMALL("Convert progressive video into interlaced."), + .priv_size = sizeof(TInterlaceContext), + .init = init_interlace, + .uninit = uninit, + .query_formats = query_formats, + .inputs = tinterlace_inputs, + .outputs = tinterlace_outputs, + .priv_class = &interlace_class, +}; diff --git a/libavfilter/vf_tonemap.c b/libavfilter/vf_tonemap.c index 10308bdb1..d1728c851 100644 --- a/libavfilter/vf_tonemap.c +++ b/libavfilter/vf_tonemap.c @@ -30,17 +30,15 @@ #include "libavutil/imgutils.h" #include "libavutil/internal.h" #include "libavutil/intreadwrite.h" -#include "libavutil/mastering_display_metadata.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "avfilter.h" +#include "colorspace.h" #include "formats.h" #include "internal.h" #include "video.h" -#define REFERENCE_WHITE 100.0f - enum TonemapAlgorithm { TONEMAP_NONE, TONEMAP_LINEAR, @@ -52,11 +50,6 @@ enum TonemapAlgorithm { TONEMAP_MAX, }; -typedef struct LumaCoefficients { - double cr, cg, cb; -} LumaCoefficients; - - static const struct LumaCoefficients luma_coefficients[AVCOL_SPC_NB] = { [AVCOL_SPC_FCC] = { 0.30, 0.59, 0.11 }, [AVCOL_SPC_BT470BG] = { 0.299, 0.587, 0.114 }, @@ -75,7 +68,7 @@ typedef struct TonemapContext { double desat; double peak; - const LumaCoefficients *coeffs; + const struct LumaCoefficients *coeffs; } TonemapContext; static const enum AVPixelFormat pix_fmts[] = { @@ -114,31 +107,6 @@ static av_cold int init(AVFilterContext *ctx) return 0; } -static double determine_signal_peak(AVFrame *in) -{ - AVFrameSideData *sd = av_frame_get_side_data(in, AV_FRAME_DATA_CONTENT_LIGHT_LEVEL); - double peak = 0; - - if (sd) { - AVContentLightMetadata *clm = (AVContentLightMetadata *)sd->data; - peak = clm->MaxCLL / REFERENCE_WHITE; - } - - sd = av_frame_get_side_data(in, AV_FRAME_DATA_MASTERING_DISPLAY_METADATA); - if (!peak && sd) { - AVMasteringDisplayMetadata *metadata = (AVMasteringDisplayMetadata *)sd->data; - if (metadata->has_luminance) - peak = av_q2d(metadata->max_luminance) / REFERENCE_WHITE; - } - - /* smpte2084 needs the side data above to work correctly - * if missing, assume that the original transfer was arib-std-b67 */ - if (!peak) - peak = 12; - - return peak; -} - static float hable(float in) { float a = 0.15f, b = 0.50f, c = 0.10f, d = 0.20f, e = 0.02f, f = 0.30f; @@ -223,10 +191,36 @@ static void tonemap(TonemapContext *s, AVFrame *out, const AVFrame *in, *b_out *= sig / sig_orig; } +typedef struct ThreadData { + AVFrame *in, *out; + const AVPixFmtDescriptor *desc; + double peak; +} ThreadData; + +static int tonemap_slice(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) +{ + TonemapContext *s = ctx->priv; + ThreadData *td = arg; + AVFrame *in = td->in; + AVFrame *out = td->out; + const AVPixFmtDescriptor *desc = td->desc; + const int slice_start = (in->height * jobnr) / nb_jobs; + const int slice_end = (in->height * (jobnr+1)) / nb_jobs; + double peak = td->peak; + + for (int y = slice_start; y < slice_end; y++) + for (int x = 0; x < out->width; x++) + tonemap(s, out, in, desc, x, y, peak); + + return 0; +} + static int filter_frame(AVFilterLink *link, AVFrame *in) { - TonemapContext *s = link->dst->priv; - AVFilterLink *outlink = link->dst->outputs[0]; + AVFilterContext *ctx = link->dst; + TonemapContext *s = ctx->priv; + AVFilterLink *outlink = ctx->outputs[0]; + ThreadData td; AVFrame *out; const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(link->format); const AVPixFmtDescriptor *odesc = av_pix_fmt_desc_get(outlink->format); @@ -260,7 +254,7 @@ static int filter_frame(AVFilterLink *link, AVFrame *in) /* read peak from side data if not passed in */ if (!peak) { - peak = determine_signal_peak(in); + peak = ff_determine_signal_peak(in); av_log(s, AV_LOG_DEBUG, "Computed signal peak: %f\n", peak); } @@ -277,9 +271,11 @@ static int filter_frame(AVFilterLink *link, AVFrame *in) } /* do the tone map */ - for (y = 0; y < out->height; y++) - for (x = 0; x < out->width; x++) - tonemap(s, out, in, desc, x, y, peak); + td.out = out; + td.in = in; + td.desc = desc; + td.peak = peak; + ctx->internal->execute(ctx, tonemap_slice, &td, NULL, FFMIN(in->height, ff_filter_get_nb_threads(ctx))); /* copy/generate alpha if needed */ if (desc->flags & AV_PIX_FMT_FLAG_ALPHA && odesc->flags & AV_PIX_FMT_FLAG_ALPHA) { @@ -297,6 +293,8 @@ static int filter_frame(AVFilterLink *link, AVFrame *in) av_frame_free(&in); + ff_update_hdr_metadata(out, peak); + return ff_filter_frame(outlink, out); } @@ -317,13 +315,7 @@ static const AVOption tonemap_options[] = { { NULL } }; -static const AVClass tonemap_class = { - .class_name = "tonemap", - .item_name = av_default_item_name, - .option = tonemap_options, - .version = LIBAVUTIL_VERSION_INT, - .category = AV_CLASS_CATEGORY_FILTER, -}; +AVFILTER_DEFINE_CLASS(tonemap); static const AVFilterPad tonemap_inputs[] = { { @@ -351,4 +343,5 @@ AVFilter ff_vf_tonemap = { .priv_class = &tonemap_class, .inputs = tonemap_inputs, .outputs = tonemap_outputs, + .flags = AVFILTER_FLAG_SLICE_THREADS, }; diff --git a/libavfilter/vf_tonemap_opencl.c b/libavfilter/vf_tonemap_opencl.c new file mode 100644 index 000000000..315ead49d --- /dev/null +++ b/libavfilter/vf_tonemap_opencl.c @@ -0,0 +1,554 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include + +#include "libavutil/avassert.h" +#include "libavutil/common.h" +#include "libavutil/imgutils.h" +#include "libavutil/mem.h" +#include "libavutil/opt.h" +#include "libavutil/pixdesc.h" + +#include "avfilter.h" +#include "internal.h" +#include "opencl.h" +#include "opencl_source.h" +#include "video.h" +#include "colorspace.h" + +// TODO: +// - separate peak-detection from tone-mapping kernel to solve +// one-frame-delay issue. +// - more format support + +#define DETECTION_FRAMES 63 + +enum TonemapAlgorithm { + TONEMAP_NONE, + TONEMAP_LINEAR, + TONEMAP_GAMMA, + TONEMAP_CLIP, + TONEMAP_REINHARD, + TONEMAP_HABLE, + TONEMAP_MOBIUS, + TONEMAP_MAX, +}; + +typedef struct TonemapOpenCLContext { + OpenCLFilterContext ocf; + + enum AVColorSpace colorspace, colorspace_in, colorspace_out; + enum AVColorTransferCharacteristic trc, trc_in, trc_out; + enum AVColorPrimaries primaries, primaries_in, primaries_out; + enum AVColorRange range, range_in, range_out; + enum AVChromaLocation chroma_loc; + + enum TonemapAlgorithm tonemap; + enum AVPixelFormat format; + double peak; + double param; + double desat_param; + double target_peak; + double scene_threshold; + int initialised; + cl_kernel kernel; + cl_command_queue command_queue; + cl_mem util_mem; +} TonemapOpenCLContext; + +static const char *linearize_funcs[AVCOL_TRC_NB] = { + [AVCOL_TRC_SMPTE2084] = "eotf_st2084", + [AVCOL_TRC_ARIB_STD_B67] = "inverse_oetf_hlg", +}; + +static const char *delinearize_funcs[AVCOL_TRC_NB] = { + [AVCOL_TRC_BT709] = "inverse_eotf_bt1886", + [AVCOL_TRC_BT2020_10] = "inverse_eotf_bt1886", +}; + +static const struct PrimaryCoefficients primaries_table[AVCOL_PRI_NB] = { + [AVCOL_PRI_BT709] = { 0.640, 0.330, 0.300, 0.600, 0.150, 0.060 }, + [AVCOL_PRI_BT2020] = { 0.708, 0.292, 0.170, 0.797, 0.131, 0.046 }, +}; + +static const struct WhitepointCoefficients whitepoint_table[AVCOL_PRI_NB] = { + [AVCOL_PRI_BT709] = { 0.3127, 0.3290 }, + [AVCOL_PRI_BT2020] = { 0.3127, 0.3290 }, +}; + +static const char *tonemap_func[TONEMAP_MAX] = { + [TONEMAP_NONE] = "direct", + [TONEMAP_LINEAR] = "linear", + [TONEMAP_GAMMA] = "gamma", + [TONEMAP_CLIP] = "clip", + [TONEMAP_REINHARD] = "reinhard", + [TONEMAP_HABLE] = "hable", + [TONEMAP_MOBIUS] = "mobius", +}; + +static void get_rgb2rgb_matrix(enum AVColorPrimaries in, enum AVColorPrimaries out, + double rgb2rgb[3][3]) { + double rgb2xyz[3][3], xyz2rgb[3][3]; + + ff_fill_rgb2xyz_table(&primaries_table[out], &whitepoint_table[out], rgb2xyz); + ff_matrix_invert_3x3(rgb2xyz, xyz2rgb); + ff_fill_rgb2xyz_table(&primaries_table[in], &whitepoint_table[in], rgb2xyz); + ff_matrix_mul_3x3(rgb2rgb, rgb2xyz, xyz2rgb); +} + +#define OPENCL_SOURCE_NB 3 +// Average light level for SDR signals. This is equal to a signal level of 0.5 +// under a typical presentation gamma of about 2.0. +static const float sdr_avg = 0.25f; + +static int tonemap_opencl_init(AVFilterContext *avctx) +{ + TonemapOpenCLContext *ctx = avctx->priv; + int rgb2rgb_passthrough = 1; + double rgb2rgb[3][3], rgb2yuv[3][3], yuv2rgb[3][3]; + const struct LumaCoefficients *luma_src, *luma_dst; + cl_int cle; + int err; + AVBPrint header; + const char *opencl_sources[OPENCL_SOURCE_NB]; + + av_bprint_init(&header, 1024, AV_BPRINT_SIZE_AUTOMATIC); + + switch(ctx->tonemap) { + case TONEMAP_GAMMA: + if (isnan(ctx->param)) + ctx->param = 1.8f; + break; + case TONEMAP_REINHARD: + if (!isnan(ctx->param)) + ctx->param = (1.0f - ctx->param) / ctx->param; + break; + case TONEMAP_MOBIUS: + if (isnan(ctx->param)) + ctx->param = 0.3f; + break; + } + + if (isnan(ctx->param)) + ctx->param = 1.0f; + + // SDR peak is 1.0f + ctx->target_peak = 1.0f; + av_log(ctx, AV_LOG_DEBUG, "tone mapping transfer from %s to %s\n", + av_color_transfer_name(ctx->trc_in), + av_color_transfer_name(ctx->trc_out)); + av_log(ctx, AV_LOG_DEBUG, "mapping colorspace from %s to %s\n", + av_color_space_name(ctx->colorspace_in), + av_color_space_name(ctx->colorspace_out)); + av_log(ctx, AV_LOG_DEBUG, "mapping primaries from %s to %s\n", + av_color_primaries_name(ctx->primaries_in), + av_color_primaries_name(ctx->primaries_out)); + av_log(ctx, AV_LOG_DEBUG, "mapping range from %s to %s\n", + av_color_range_name(ctx->range_in), + av_color_range_name(ctx->range_out)); + // checking valid value just because of limited implementaion + // please remove when more functionalities are implemented + av_assert0(ctx->trc_out == AVCOL_TRC_BT709 || + ctx->trc_out == AVCOL_TRC_BT2020_10); + av_assert0(ctx->trc_in == AVCOL_TRC_SMPTE2084|| + ctx->trc_in == AVCOL_TRC_ARIB_STD_B67); + av_assert0(ctx->colorspace_in == AVCOL_SPC_BT2020_NCL || + ctx->colorspace_in == AVCOL_SPC_BT709); + av_assert0(ctx->primaries_in == AVCOL_PRI_BT2020 || + ctx->primaries_in == AVCOL_PRI_BT709); + + av_bprintf(&header, "__constant const float tone_param = %.4ff;\n", + ctx->param); + av_bprintf(&header, "__constant const float desat_param = %.4ff;\n", + ctx->desat_param); + av_bprintf(&header, "__constant const float target_peak = %.4ff;\n", + ctx->target_peak); + av_bprintf(&header, "__constant const float sdr_avg = %.4ff;\n", sdr_avg); + av_bprintf(&header, "__constant const float scene_threshold = %.4ff;\n", + ctx->scene_threshold); + av_bprintf(&header, "#define TONE_FUNC %s\n", tonemap_func[ctx->tonemap]); + av_bprintf(&header, "#define DETECTION_FRAMES %d\n", DETECTION_FRAMES); + + if (ctx->primaries_out != ctx->primaries_in) { + get_rgb2rgb_matrix(ctx->primaries_in, ctx->primaries_out, rgb2rgb); + rgb2rgb_passthrough = 0; + } + if (ctx->range_in == AVCOL_RANGE_JPEG) + av_bprintf(&header, "#define FULL_RANGE_IN\n"); + + if (ctx->range_out == AVCOL_RANGE_JPEG) + av_bprintf(&header, "#define FULL_RANGE_OUT\n"); + + av_bprintf(&header, "#define chroma_loc %d\n", (int)ctx->chroma_loc); + + if (rgb2rgb_passthrough) + av_bprintf(&header, "#define RGB2RGB_PASSTHROUGH\n"); + else + ff_opencl_print_const_matrix_3x3(&header, "rgb2rgb", rgb2rgb); + + + luma_src = ff_get_luma_coefficients(ctx->colorspace_in); + if (!luma_src) { + err = AVERROR(EINVAL); + av_log(avctx, AV_LOG_ERROR, "unsupported input colorspace %d (%s)\n", + ctx->colorspace_in, av_color_space_name(ctx->colorspace_in)); + goto fail; + } + + luma_dst = ff_get_luma_coefficients(ctx->colorspace_out); + if (!luma_dst) { + err = AVERROR(EINVAL); + av_log(avctx, AV_LOG_ERROR, "unsupported output colorspace %d (%s)\n", + ctx->colorspace_out, av_color_space_name(ctx->colorspace_out)); + goto fail; + } + + ff_fill_rgb2yuv_table(luma_dst, rgb2yuv); + ff_opencl_print_const_matrix_3x3(&header, "yuv_matrix", rgb2yuv); + + ff_fill_rgb2yuv_table(luma_src, rgb2yuv); + ff_matrix_invert_3x3(rgb2yuv, yuv2rgb); + ff_opencl_print_const_matrix_3x3(&header, "rgb_matrix", yuv2rgb); + + av_bprintf(&header, "constant float3 luma_src = {%.4ff, %.4ff, %.4ff};\n", + luma_src->cr, luma_src->cg, luma_src->cb); + av_bprintf(&header, "constant float3 luma_dst = {%.4ff, %.4ff, %.4ff};\n", + luma_dst->cr, luma_dst->cg, luma_dst->cb); + + av_bprintf(&header, "#define linearize %s\n", linearize_funcs[ctx->trc_in]); + av_bprintf(&header, "#define delinearize %s\n", + delinearize_funcs[ctx->trc_out]); + + if (ctx->trc_in == AVCOL_TRC_ARIB_STD_B67) + av_bprintf(&header, "#define ootf_impl ootf_hlg\n"); + + if (ctx->trc_out == AVCOL_TRC_ARIB_STD_B67) + av_bprintf(&header, "#define inverse_ootf_impl inverse_ootf_hlg\n"); + + av_log(avctx, AV_LOG_DEBUG, "Generated OpenCL header:\n%s\n", header.str); + opencl_sources[0] = header.str; + opencl_sources[1] = ff_opencl_source_tonemap; + opencl_sources[2] = ff_opencl_source_colorspace_common; + err = ff_opencl_filter_load_program(avctx, opencl_sources, OPENCL_SOURCE_NB); + + av_bprint_finalize(&header, NULL); + if (err < 0) + goto fail; + + ctx->command_queue = clCreateCommandQueue(ctx->ocf.hwctx->context, + ctx->ocf.hwctx->device_id, + 0, &cle); + CL_FAIL_ON_ERROR(AVERROR(EIO), "Failed to create OpenCL " + "command queue %d.\n", cle); + + ctx->kernel = clCreateKernel(ctx->ocf.program, "tonemap", &cle); + CL_FAIL_ON_ERROR(AVERROR(EIO), "Failed to create kernel %d.\n", cle); + + ctx->util_mem = + clCreateBuffer(ctx->ocf.hwctx->context, 0, + (2 * DETECTION_FRAMES + 7) * sizeof(unsigned), + NULL, &cle); + CL_FAIL_ON_ERROR(AVERROR(EIO), "Failed to create util buffer: %d.\n", cle); + + ctx->initialised = 1; + return 0; + +fail: + av_bprint_finalize(&header, NULL); + if (ctx->util_mem) + clReleaseMemObject(ctx->util_mem); + if (ctx->command_queue) + clReleaseCommandQueue(ctx->command_queue); + if (ctx->kernel) + clReleaseKernel(ctx->kernel); + return err; +} + +static int tonemap_opencl_config_output(AVFilterLink *outlink) +{ + AVFilterContext *avctx = outlink->src; + TonemapOpenCLContext *s = avctx->priv; + int ret; + if (s->format == AV_PIX_FMT_NONE) + av_log(avctx, AV_LOG_WARNING, "format not set, use default format NV12\n"); + else { + if (s->format != AV_PIX_FMT_P010 && + s->format != AV_PIX_FMT_NV12) { + av_log(avctx, AV_LOG_ERROR, "unsupported output format," + "only p010/nv12 supported now\n"); + return AVERROR(EINVAL); + } + } + + s->ocf.output_format = s->format == AV_PIX_FMT_NONE ? AV_PIX_FMT_NV12 : s->format; + ret = ff_opencl_filter_config_output(outlink); + if (ret < 0) + return ret; + + return 0; +} + +static int launch_kernel(AVFilterContext *avctx, cl_kernel kernel, + AVFrame *output, AVFrame *input, float peak) { + TonemapOpenCLContext *ctx = avctx->priv; + int err = AVERROR(ENOSYS); + size_t global_work[2]; + size_t local_work[2]; + cl_int cle; + + CL_SET_KERNEL_ARG(kernel, 0, cl_mem, &output->data[0]); + CL_SET_KERNEL_ARG(kernel, 1, cl_mem, &input->data[0]); + CL_SET_KERNEL_ARG(kernel, 2, cl_mem, &output->data[1]); + CL_SET_KERNEL_ARG(kernel, 3, cl_mem, &input->data[1]); + CL_SET_KERNEL_ARG(kernel, 4, cl_mem, &ctx->util_mem); + CL_SET_KERNEL_ARG(kernel, 5, cl_float, &peak); + + local_work[0] = 16; + local_work[1] = 16; + // Note the work size based on uv plane, as we process a 2x2 quad in one workitem + err = ff_opencl_filter_work_size_from_image(avctx, global_work, output, + 1, 16); + if (err < 0) + return err; + + cle = clEnqueueNDRangeKernel(ctx->command_queue, kernel, 2, NULL, + global_work, local_work, + 0, NULL, NULL); + CL_FAIL_ON_ERROR(AVERROR(EIO), "Failed to enqueue kernel: %d.\n", cle); + return 0; +fail: + return err; +} + +static int tonemap_opencl_filter_frame(AVFilterLink *inlink, AVFrame *input) +{ + AVFilterContext *avctx = inlink->dst; + AVFilterLink *outlink = avctx->outputs[0]; + TonemapOpenCLContext *ctx = avctx->priv; + AVFrame *output = NULL; + cl_int cle; + int err; + double peak = ctx->peak; + + AVHWFramesContext *input_frames_ctx = + (AVHWFramesContext*)input->hw_frames_ctx->data; + + av_log(ctx, AV_LOG_DEBUG, "Filter input: %s, %ux%u (%"PRId64").\n", + av_get_pix_fmt_name(input->format), + input->width, input->height, input->pts); + + if (!input->hw_frames_ctx) + return AVERROR(EINVAL); + + output = ff_get_video_buffer(outlink, outlink->w, outlink->h); + if (!output) { + err = AVERROR(ENOMEM); + goto fail; + } + + err = av_frame_copy_props(output, input); + if (err < 0) + goto fail; + + if (!peak) + peak = ff_determine_signal_peak(input); + + if (ctx->trc != -1) + output->color_trc = ctx->trc; + if (ctx->primaries != -1) + output->color_primaries = ctx->primaries; + if (ctx->colorspace != -1) + output->colorspace = ctx->colorspace; + if (ctx->range != -1) + output->color_range = ctx->range; + + ctx->trc_in = input->color_trc; + ctx->trc_out = output->color_trc; + ctx->colorspace_in = input->colorspace; + ctx->colorspace_out = output->colorspace; + ctx->primaries_in = input->color_primaries; + ctx->primaries_out = output->color_primaries; + ctx->range_in = input->color_range; + ctx->range_out = output->color_range; + ctx->chroma_loc = output->chroma_location; + + if (!ctx->initialised) { + if (!(input->color_trc == AVCOL_TRC_SMPTE2084 || + input->color_trc == AVCOL_TRC_ARIB_STD_B67)) { + av_log(ctx, AV_LOG_ERROR, "unsupported transfer function characteristic.\n"); + err = AVERROR(ENOSYS); + goto fail; + } + + if (input_frames_ctx->sw_format != AV_PIX_FMT_P010) { + av_log(ctx, AV_LOG_ERROR, "unsupported format in tonemap_opencl.\n"); + err = AVERROR(ENOSYS); + goto fail; + } + + err = tonemap_opencl_init(avctx); + if (err < 0) + goto fail; + } + + switch(input_frames_ctx->sw_format) { + case AV_PIX_FMT_P010: + err = launch_kernel(avctx, ctx->kernel, output, input, peak); + if (err < 0) goto fail; + break; + default: + err = AVERROR(ENOSYS); + goto fail; + } + + cle = clFinish(ctx->command_queue); + CL_FAIL_ON_ERROR(AVERROR(EIO), "Failed to finish command queue: %d.\n", cle); + + av_frame_free(&input); + + ff_update_hdr_metadata(output, ctx->target_peak); + + av_log(ctx, AV_LOG_DEBUG, "Tone-mapping output: %s, %ux%u (%"PRId64").\n", + av_get_pix_fmt_name(output->format), + output->width, output->height, output->pts); +#ifndef NDEBUG + { + uint32_t *ptr, *max_total_p, *avg_total_p, *frame_number_p; + float peak_detected, avg_detected; + unsigned map_size = (2 * DETECTION_FRAMES + 7) * sizeof(unsigned); + ptr = (void *)clEnqueueMapBuffer(ctx->command_queue, ctx->util_mem, + CL_TRUE, CL_MAP_READ, 0, map_size, + 0, NULL, NULL, &cle); + // For the layout of the util buffer, refer tonemap.cl + if (ptr) { + max_total_p = ptr + 2 * (DETECTION_FRAMES + 1) + 1; + avg_total_p = max_total_p + 1; + frame_number_p = avg_total_p + 2; + peak_detected = (float)*max_total_p / (REFERENCE_WHITE * (*frame_number_p)); + avg_detected = (float)*avg_total_p / (REFERENCE_WHITE * (*frame_number_p)); + av_log(ctx, AV_LOG_DEBUG, "peak %f, avg %f will be used for next frame\n", + peak_detected, avg_detected); + clEnqueueUnmapMemObject(ctx->command_queue, ctx->util_mem, ptr, 0, + NULL, NULL); + } + } +#endif + + return ff_filter_frame(outlink, output); + +fail: + clFinish(ctx->command_queue); + av_frame_free(&input); + av_frame_free(&output); + return err; +} + +static av_cold void tonemap_opencl_uninit(AVFilterContext *avctx) +{ + TonemapOpenCLContext *ctx = avctx->priv; + cl_int cle; + + if (ctx->util_mem) + clReleaseMemObject(ctx->util_mem); + if (ctx->kernel) { + cle = clReleaseKernel(ctx->kernel); + if (cle != CL_SUCCESS) + av_log(avctx, AV_LOG_ERROR, "Failed to release " + "kernel: %d.\n", cle); + } + + if (ctx->command_queue) { + cle = clReleaseCommandQueue(ctx->command_queue); + if (cle != CL_SUCCESS) + av_log(avctx, AV_LOG_ERROR, "Failed to release " + "command queue: %d.\n", cle); + } + + ff_opencl_filter_uninit(avctx); +} + +#define OFFSET(x) offsetof(TonemapOpenCLContext, x) +#define FLAGS (AV_OPT_FLAG_FILTERING_PARAM | AV_OPT_FLAG_VIDEO_PARAM) +static const AVOption tonemap_opencl_options[] = { + { "tonemap", "tonemap algorithm selection", OFFSET(tonemap), AV_OPT_TYPE_INT, {.i64 = TONEMAP_NONE}, TONEMAP_NONE, TONEMAP_MAX - 1, FLAGS, "tonemap" }, + { "none", 0, 0, AV_OPT_TYPE_CONST, {.i64 = TONEMAP_NONE}, 0, 0, FLAGS, "tonemap" }, + { "linear", 0, 0, AV_OPT_TYPE_CONST, {.i64 = TONEMAP_LINEAR}, 0, 0, FLAGS, "tonemap" }, + { "gamma", 0, 0, AV_OPT_TYPE_CONST, {.i64 = TONEMAP_GAMMA}, 0, 0, FLAGS, "tonemap" }, + { "clip", 0, 0, AV_OPT_TYPE_CONST, {.i64 = TONEMAP_CLIP}, 0, 0, FLAGS, "tonemap" }, + { "reinhard", 0, 0, AV_OPT_TYPE_CONST, {.i64 = TONEMAP_REINHARD}, 0, 0, FLAGS, "tonemap" }, + { "hable", 0, 0, AV_OPT_TYPE_CONST, {.i64 = TONEMAP_HABLE}, 0, 0, FLAGS, "tonemap" }, + { "mobius", 0, 0, AV_OPT_TYPE_CONST, {.i64 = TONEMAP_MOBIUS}, 0, 0, FLAGS, "tonemap" }, + { "transfer", "set transfer characteristic", OFFSET(trc), AV_OPT_TYPE_INT, {.i64 = AVCOL_TRC_BT709}, -1, INT_MAX, FLAGS, "transfer" }, + { "t", "set transfer characteristic", OFFSET(trc), AV_OPT_TYPE_INT, {.i64 = AVCOL_TRC_BT709}, -1, INT_MAX, FLAGS, "transfer" }, + { "bt709", 0, 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_TRC_BT709}, 0, 0, FLAGS, "transfer" }, + { "bt2020", 0, 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_TRC_BT2020_10}, 0, 0, FLAGS, "transfer" }, + { "matrix", "set colorspace matrix", OFFSET(colorspace), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, FLAGS, "matrix" }, + { "m", "set colorspace matrix", OFFSET(colorspace), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, FLAGS, "matrix" }, + { "bt709", 0, 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_SPC_BT709}, 0, 0, FLAGS, "matrix" }, + { "bt2020", 0, 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_SPC_BT2020_NCL}, 0, 0, FLAGS, "matrix" }, + { "primaries", "set color primaries", OFFSET(primaries), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, FLAGS, "primaries" }, + { "p", "set color primaries", OFFSET(primaries), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, FLAGS, "primaries" }, + { "bt709", 0, 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_PRI_BT709}, 0, 0, FLAGS, "primaries" }, + { "bt2020", 0, 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_PRI_BT2020}, 0, 0, FLAGS, "primaries" }, + { "range", "set color range", OFFSET(range), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, FLAGS, "range" }, + { "r", "set color range", OFFSET(range), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, FLAGS, "range" }, + { "tv", 0, 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_RANGE_MPEG}, 0, 0, FLAGS, "range" }, + { "pc", 0, 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_RANGE_JPEG}, 0, 0, FLAGS, "range" }, + { "limited", 0, 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_RANGE_MPEG}, 0, 0, FLAGS, "range" }, + { "full", 0, 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_RANGE_JPEG}, 0, 0, FLAGS, "range" }, + { "format", "output pixel format", OFFSET(format), AV_OPT_TYPE_PIXEL_FMT, {.i64 = AV_PIX_FMT_NONE}, AV_PIX_FMT_NONE, INT_MAX, FLAGS, "fmt" }, + { "peak", "signal peak override", OFFSET(peak), AV_OPT_TYPE_DOUBLE, {.dbl = 0}, 0, DBL_MAX, FLAGS }, + { "param", "tonemap parameter", OFFSET(param), AV_OPT_TYPE_DOUBLE, {.dbl = NAN}, DBL_MIN, DBL_MAX, FLAGS }, + { "desat", "desaturation parameter", OFFSET(desat_param), AV_OPT_TYPE_DOUBLE, {.dbl = 0.5}, 0, DBL_MAX, FLAGS }, + { "threshold", "scene detection threshold", OFFSET(scene_threshold), AV_OPT_TYPE_DOUBLE, {.dbl = 0.2}, 0, DBL_MAX, FLAGS }, + { NULL } +}; + +AVFILTER_DEFINE_CLASS(tonemap_opencl); + +static const AVFilterPad tonemap_opencl_inputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + .filter_frame = &tonemap_opencl_filter_frame, + .config_props = &ff_opencl_filter_config_input, + }, + { NULL } +}; + +static const AVFilterPad tonemap_opencl_outputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + .config_props = &tonemap_opencl_config_output, + }, + { NULL } +}; + +AVFilter ff_vf_tonemap_opencl = { + .name = "tonemap_opencl", + .description = NULL_IF_CONFIG_SMALL("perform HDR to SDR conversion with tonemapping"), + .priv_size = sizeof(TonemapOpenCLContext), + .priv_class = &tonemap_opencl_class, + .init = &ff_opencl_filter_init, + .uninit = &tonemap_opencl_uninit, + .query_formats = &ff_opencl_filter_query_formats, + .inputs = tonemap_opencl_inputs, + .outputs = tonemap_opencl_outputs, + .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE, +}; diff --git a/libavfilter/vf_tpad.c b/libavfilter/vf_tpad.c new file mode 100644 index 000000000..86e063090 --- /dev/null +++ b/libavfilter/vf_tpad.c @@ -0,0 +1,218 @@ +/* + * Copyright (c) 2018 Paul B Mahol + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/avassert.h" +#include "libavutil/channel_layout.h" +#include "libavutil/opt.h" +#include "avfilter.h" +#include "audio.h" +#include "filters.h" +#include "internal.h" +#include "formats.h" +#include "drawutils.h" + +typedef struct TPadContext { + const AVClass *class; + int pad_start; + int pad_stop; + int start_mode; + int stop_mode; + int64_t start_duration; + int64_t stop_duration; + uint8_t rgba_color[4]; ///< color for the padding area + + FFDrawContext draw; + FFDrawColor color; + int64_t pts; + int eof; + AVFrame *cache_start; + AVFrame *cache_stop; +} TPadContext; + +#define OFFSET(x) offsetof(TPadContext, x) +#define VF AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM + +static const AVOption tpad_options[] = { + { "start", "set the number of frames to delay input", OFFSET(pad_start), AV_OPT_TYPE_INT, {.i64=0}, 0, INT_MAX, VF }, + { "stop", "set the number of frames to add after input finished", OFFSET(pad_stop), AV_OPT_TYPE_INT, {.i64=0}, -1, INT_MAX, VF }, + { "start_mode", "set the mode of added frames to start", OFFSET(start_mode), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, VF, "mode" }, + { "add", "add solid-color frames", 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, VF, "mode" }, + { "clone", "clone first/last frame", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, VF, "mode" }, + { "stop_mode", "set the mode of added frames to end", OFFSET(stop_mode), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, VF, "mode" }, + { "start_duration", "set the duration to delay input", OFFSET(start_duration), AV_OPT_TYPE_DURATION, {.i64=0}, 0, INT64_MAX, VF }, + { "stop_duration", "set the duration to pad input", OFFSET(stop_duration), AV_OPT_TYPE_DURATION, {.i64=0}, 0, INT64_MAX, VF }, + { "color", "set the color of the added frames", OFFSET(rgba_color), AV_OPT_TYPE_COLOR, {.str="black"}, 0, 0, VF }, + { NULL } +}; + +AVFILTER_DEFINE_CLASS(tpad); + +static int query_formats(AVFilterContext *ctx) +{ + return ff_set_common_formats(ctx, ff_draw_supported_pixel_formats(0)); +} + +static int activate(AVFilterContext *ctx) +{ + AVFilterLink *inlink = ctx->inputs[0]; + AVFilterLink *outlink = ctx->outputs[0]; + TPadContext *s = ctx->priv; + AVFrame *frame = NULL; + int ret, status; + int64_t pts; + + FF_FILTER_FORWARD_STATUS_BACK(outlink, inlink); + + if (s->start_mode == 0 && s->pad_start > 0 && ff_outlink_frame_wanted(outlink)) { + frame = ff_get_video_buffer(outlink, outlink->w, outlink->h); + if (!frame) + return AVERROR(ENOMEM); + ff_fill_rectangle(&s->draw, &s->color, + frame->data, frame->linesize, + 0, 0, frame->width, frame->height); + frame->pts = s->pts; + s->pts += av_rescale_q(1, av_inv_q(outlink->frame_rate), outlink->time_base); + s->pad_start--; + return ff_filter_frame(outlink, frame); + } + + if (s->start_mode == 1 && s->pad_start > 0) { + if (!s->cache_start && ff_inlink_queued_frames(inlink)) { + s->cache_start = ff_inlink_peek_frame(inlink, 0); + } else if (!s->cache_start) { + FF_FILTER_FORWARD_WANTED(outlink, inlink); + } + frame = av_frame_clone(s->cache_start); + if (!frame) + return AVERROR(ENOMEM); + frame->pts = s->pts; + s->pts += av_rescale_q(1, av_inv_q(outlink->frame_rate), outlink->time_base); + s->pad_start--; + if (s->pad_start == 0) + s->cache_start = NULL; + return ff_filter_frame(outlink, frame); + } + + if (!s->eof && !s->pad_start) { + ret = ff_inlink_consume_frame(inlink, &frame); + if (ret < 0) + return ret; + if (ret > 0) { + if (s->stop_mode == 1 && s->pad_stop != 0) { + av_frame_free(&s->cache_stop); + s->cache_stop = av_frame_clone(frame); + } + frame->pts += s->pts; + return ff_filter_frame(outlink, frame); + } + } + + if (!s->eof && ff_inlink_acknowledge_status(inlink, &status, &pts)) { + if (status == AVERROR_EOF) { + if (!s->pad_stop) { + ff_outlink_set_status(outlink, status, pts); + return 0; + } + s->eof = 1; + s->pts += pts; + } + } + + if (s->eof) { + if (!s->pad_stop) { + ff_outlink_set_status(outlink, AVERROR_EOF, s->pts); + return 0; + } + if (s->stop_mode == 0) { + frame = ff_get_video_buffer(outlink, outlink->w, outlink->h); + if (!frame) + return AVERROR(ENOMEM); + ff_fill_rectangle(&s->draw, &s->color, + frame->data, frame->linesize, + 0, 0, frame->width, frame->height); + } else if (s->stop_mode == 1) { + frame = av_frame_clone(s->cache_stop); + if (!frame) + return AVERROR(ENOMEM); + } + frame->pts = s->pts; + s->pts += av_rescale_q(1, av_inv_q(outlink->frame_rate), outlink->time_base); + if (s->pad_stop > 0) + s->pad_stop--; + return ff_filter_frame(outlink, frame); + } + + if (!s->pad_start) + FF_FILTER_FORWARD_WANTED(outlink, inlink); + + return FFERROR_NOT_READY; +} + +static int config_input(AVFilterLink *inlink) +{ + AVFilterContext *ctx = inlink->dst; + TPadContext *s = ctx->priv; + + ff_draw_init(&s->draw, inlink->format, 0); + ff_draw_color(&s->draw, &s->color, s->rgba_color); + + if (s->start_duration) + s->pad_start = av_rescale_q(s->start_duration, inlink->frame_rate, av_inv_q(AV_TIME_BASE_Q)); + if (s->stop_duration) + s->pad_stop = av_rescale_q(s->stop_duration, inlink->frame_rate, av_inv_q(AV_TIME_BASE_Q)); + + return 0; +} + +static void uninit(AVFilterContext *ctx) +{ + TPadContext *s = ctx->priv; + + av_frame_free(&s->cache_stop); +} + +static const AVFilterPad tpad_inputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + .config_props = config_input, + }, + { NULL } +}; + +static const AVFilterPad tpad_outputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + }, + { NULL } +}; + +AVFilter ff_vf_tpad = { + .name = "tpad", + .description = NULL_IF_CONFIG_SMALL("Temporarily pad video frames."), + .priv_size = sizeof(TPadContext), + .priv_class = &tpad_class, + .query_formats = query_formats, + .activate = activate, + .uninit = uninit, + .inputs = tpad_inputs, + .outputs = tpad_outputs, +}; diff --git a/libavfilter/vf_transpose.c b/libavfilter/vf_transpose.c index 74a4bbcf5..dd54947bd 100644 --- a/libavfilter/vf_transpose.c +++ b/libavfilter/vf_transpose.c @@ -38,19 +38,7 @@ #include "formats.h" #include "internal.h" #include "video.h" - -typedef enum { - TRANSPOSE_PT_TYPE_NONE, - TRANSPOSE_PT_TYPE_LANDSCAPE, - TRANSPOSE_PT_TYPE_PORTRAIT, -} PassthroughType; - -enum TransposeDir { - TRANSPOSE_CCLOCK_FLIP, - TRANSPOSE_CLOCK, - TRANSPOSE_CCLOCK, - TRANSPOSE_CLOCK_FLIP, -}; +#include "transpose.h" typedef struct TransVtable { void (*transpose_8x8)(uint8_t *src, ptrdiff_t src_linesize, diff --git a/libavfilter/vf_transpose_npp.c b/libavfilter/vf_transpose_npp.c new file mode 100644 index 000000000..3ea031667 --- /dev/null +++ b/libavfilter/vf_transpose_npp.c @@ -0,0 +1,487 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include + +#include "libavutil/common.h" +#include "libavutil/hwcontext.h" +#include "libavutil/hwcontext_cuda_internal.h" +#include "libavutil/cuda_check.h" +#include "libavutil/internal.h" +#include "libavutil/opt.h" +#include "libavutil/pixdesc.h" + +#include "avfilter.h" +#include "formats.h" +#include "internal.h" +#include "video.h" + +#define CHECK_CU(x) FF_CUDA_CHECK_DL(ctx, device_hwctx->internal->cuda_dl, x) + +static const enum AVPixelFormat supported_formats[] = { + AV_PIX_FMT_YUV420P, + AV_PIX_FMT_YUV444P +}; + +enum TransposeStage { + STAGE_ROTATE, + STAGE_TRANSPOSE, + STAGE_NB +}; + +enum Transpose { + NPP_TRANSPOSE_CCLOCK_FLIP = 0, + NPP_TRANSPOSE_CLOCK = 1, + NPP_TRANSPOSE_CCLOCK = 2, + NPP_TRANSPOSE_CLOCK_FLIP = 3 +}; + +enum Passthrough { + NPP_TRANSPOSE_PT_TYPE_NONE = 0, + NPP_TRANSPOSE_PT_TYPE_LANDSCAPE, + NPP_TRANSPOSE_PT_TYPE_PORTRAIT +}; + +typedef struct NPPTransposeStageContext { + int stage_needed; + enum AVPixelFormat in_fmt; + enum AVPixelFormat out_fmt; + struct { + int width; + int height; + } planes_in[3], planes_out[3]; + AVBufferRef *frames_ctx; + AVFrame *frame; +} NPPTransposeStageContext; + +typedef struct NPPTransposeContext { + const AVClass *class; + NPPTransposeStageContext stages[STAGE_NB]; + AVFrame *tmp_frame; + + int passthrough; ///< PassthroughType, landscape passthrough mode enabled + int dir; ///< TransposeDir +} NPPTransposeContext; + +static int npptranspose_init(AVFilterContext *ctx) +{ + NPPTransposeContext *s = ctx->priv; + int i; + + for (i = 0; i < FF_ARRAY_ELEMS(s->stages); i++) { + s->stages[i].frame = av_frame_alloc(); + if (!s->stages[i].frame) + return AVERROR(ENOMEM); + } + + s->tmp_frame = av_frame_alloc(); + if (!s->tmp_frame) + return AVERROR(ENOMEM); + + return 0; +} + +static void npptranspose_uninit(AVFilterContext *ctx) +{ + NPPTransposeContext *s = ctx->priv; + int i; + + for (i = 0; i < FF_ARRAY_ELEMS(s->stages); i++) { + av_frame_free(&s->stages[i].frame); + av_buffer_unref(&s->stages[i].frames_ctx); + } + + av_frame_free(&s->tmp_frame); +} + +static int npptranspose_query_formats(AVFilterContext *ctx) +{ + static const enum AVPixelFormat pixel_formats[] = { + AV_PIX_FMT_CUDA, AV_PIX_FMT_NONE, + }; + + AVFilterFormats *pix_fmts = ff_make_format_list(pixel_formats); + return ff_set_common_formats(ctx, pix_fmts); +} + +static int init_stage(NPPTransposeStageContext *stage, AVBufferRef *device_ctx) +{ + AVBufferRef *out_ref = NULL; + AVHWFramesContext *out_ctx; + int in_sw, in_sh, out_sw, out_sh; + int ret, i; + + av_pix_fmt_get_chroma_sub_sample(stage->in_fmt, &in_sw, &in_sh); + av_pix_fmt_get_chroma_sub_sample(stage->out_fmt, &out_sw, &out_sh); + + if (!stage->planes_out[0].width) { + stage->planes_out[0].width = stage->planes_in[0].width; + stage->planes_out[0].height = stage->planes_in[0].height; + } + + for (i = 1; i < FF_ARRAY_ELEMS(stage->planes_in); i++) { + stage->planes_in[i].width = stage->planes_in[0].width >> in_sw; + stage->planes_in[i].height = stage->planes_in[0].height >> in_sh; + stage->planes_out[i].width = stage->planes_out[0].width >> out_sw; + stage->planes_out[i].height = stage->planes_out[0].height >> out_sh; + } + + out_ref = av_hwframe_ctx_alloc(device_ctx); + if (!out_ref) + return AVERROR(ENOMEM); + out_ctx = (AVHWFramesContext*)out_ref->data; + + out_ctx->format = AV_PIX_FMT_CUDA; + out_ctx->sw_format = stage->out_fmt; + out_ctx->width = FFALIGN(stage->planes_out[0].width, 32); + out_ctx->height = FFALIGN(stage->planes_out[0].height, 32); + + ret = av_hwframe_ctx_init(out_ref); + if (ret < 0) + goto fail; + + av_frame_unref(stage->frame); + ret = av_hwframe_get_buffer(out_ref, stage->frame, 0); + if (ret < 0) + goto fail; + + stage->frame->width = stage->planes_out[0].width; + stage->frame->height = stage->planes_out[0].height; + av_buffer_unref(&stage->frames_ctx); + stage->frames_ctx = out_ref; + + return 0; + +fail: + av_buffer_unref(&out_ref); + return ret; +} + +static int format_is_supported(enum AVPixelFormat fmt) +{ + int i; + + for (i = 0; i < FF_ARRAY_ELEMS(supported_formats); i++) + if (supported_formats[i] == fmt) + return 1; + + return 0; +} + +static int init_processing_chain(AVFilterContext *ctx, int in_width, int in_height, + int out_width, int out_height) +{ + NPPTransposeContext *s = ctx->priv; + AVHWFramesContext *in_frames_ctx; + enum AVPixelFormat format; + int i, ret, last_stage = -1; + int rot_width = out_width, rot_height = out_height; + + /* check that we have a hw context */ + if (!ctx->inputs[0]->hw_frames_ctx) { + av_log(ctx, AV_LOG_ERROR, "No hw context provided on input\n"); + return AVERROR(EINVAL); + } + + in_frames_ctx = (AVHWFramesContext*)ctx->inputs[0]->hw_frames_ctx->data; + format = in_frames_ctx->sw_format; + + if (!format_is_supported(format)) { + av_log(ctx, AV_LOG_ERROR, "Unsupported input format: %s\n", + av_get_pix_fmt_name(format)); + return AVERROR(ENOSYS); + } + + if (s->dir != NPP_TRANSPOSE_CCLOCK_FLIP) { + s->stages[STAGE_ROTATE].stage_needed = 1; + } + + if (s->dir == NPP_TRANSPOSE_CCLOCK_FLIP || s->dir == NPP_TRANSPOSE_CLOCK_FLIP) { + s->stages[STAGE_TRANSPOSE].stage_needed = 1; + + /* Rotating by 180° in case of clock_flip, or not at all for cclock_flip, so width/height unchanged by rotation */ + rot_width = in_width; + rot_height = in_height; + } + + s->stages[STAGE_ROTATE].in_fmt = format; + s->stages[STAGE_ROTATE].out_fmt = format; + s->stages[STAGE_ROTATE].planes_in[0].width = in_width; + s->stages[STAGE_ROTATE].planes_in[0].height = in_height; + s->stages[STAGE_ROTATE].planes_out[0].width = rot_width; + s->stages[STAGE_ROTATE].planes_out[0].height = rot_height; + s->stages[STAGE_TRANSPOSE].in_fmt = format; + s->stages[STAGE_TRANSPOSE].out_fmt = format; + s->stages[STAGE_TRANSPOSE].planes_in[0].width = rot_width; + s->stages[STAGE_TRANSPOSE].planes_in[0].height = rot_height; + s->stages[STAGE_TRANSPOSE].planes_out[0].width = out_width; + s->stages[STAGE_TRANSPOSE].planes_out[0].height = out_height; + + /* init the hardware contexts */ + for (i = 0; i < FF_ARRAY_ELEMS(s->stages); i++) { + if (!s->stages[i].stage_needed) + continue; + ret = init_stage(&s->stages[i], in_frames_ctx->device_ref); + if (ret < 0) + return ret; + last_stage = i; + } + + if (last_stage >= 0) { + ctx->outputs[0]->hw_frames_ctx = av_buffer_ref(s->stages[last_stage].frames_ctx); + } else { + ctx->outputs[0]->hw_frames_ctx = av_buffer_ref(ctx->inputs[0]->hw_frames_ctx); + s->passthrough = 1; + } + + if (!ctx->outputs[0]->hw_frames_ctx) + return AVERROR(ENOMEM); + + return 0; +} + +static int npptranspose_config_props(AVFilterLink *outlink) +{ + AVFilterContext *ctx = outlink->src; + AVFilterLink *inlink = ctx->inputs[0]; + NPPTransposeContext *s = ctx->priv; + int ret; + + if ((inlink->w >= inlink->h && s->passthrough == NPP_TRANSPOSE_PT_TYPE_LANDSCAPE) || + (inlink->w <= inlink->h && s->passthrough == NPP_TRANSPOSE_PT_TYPE_PORTRAIT)) + { + if (inlink->hw_frames_ctx) { + outlink->hw_frames_ctx = av_buffer_ref(inlink->hw_frames_ctx); + if (!outlink->hw_frames_ctx) + return AVERROR(ENOMEM); + } + + av_log(ctx, AV_LOG_VERBOSE, + "w:%d h:%d -> w:%d h:%d (passthrough mode)\n", + inlink->w, inlink->h, inlink->w, inlink->h); + return 0; + } else { + s->passthrough = NPP_TRANSPOSE_PT_TYPE_NONE; + } + + outlink->w = inlink->h; + outlink->h = inlink->w; + outlink->sample_aspect_ratio = (AVRational){inlink->sample_aspect_ratio.den, inlink->sample_aspect_ratio.num}; + + ret = init_processing_chain(ctx, inlink->w, inlink->h, outlink->w, outlink->h); + if (ret < 0) + return ret; + + av_log(ctx, AV_LOG_VERBOSE, "w:%d h:%d -transpose-> w:%d h:%d\n", + inlink->w, inlink->h, outlink->w, outlink->h); + + return 0; +} + +static int npptranspose_rotate(AVFilterContext *ctx, NPPTransposeStageContext *stage, + AVFrame *out, AVFrame *in) +{ + NPPTransposeContext *s = ctx->priv; + NppStatus err; + int i; + + for (i = 0; i < FF_ARRAY_ELEMS(stage->planes_in) && i < FF_ARRAY_ELEMS(in->data) && in->data[i]; i++) { + int iw = stage->planes_in[i].width; + int ih = stage->planes_in[i].height; + int ow = stage->planes_out[i].width; + int oh = stage->planes_out[i].height; + + // nppRotate uses 0,0 as the rotation point + // need to shift the image accordingly after rotation + // need to substract 1 to get the correct coordinates + double angle = s->dir == NPP_TRANSPOSE_CLOCK ? -90.0 : s->dir == NPP_TRANSPOSE_CCLOCK ? 90.0 : 180.0; + int shiftw = (s->dir == NPP_TRANSPOSE_CLOCK || s->dir == NPP_TRANSPOSE_CLOCK_FLIP) ? ow - 1 : 0; + int shifth = (s->dir == NPP_TRANSPOSE_CCLOCK || s->dir == NPP_TRANSPOSE_CLOCK_FLIP) ? oh - 1 : 0; + + err = nppiRotate_8u_C1R(in->data[i], (NppiSize){ iw, ih }, + in->linesize[i], (NppiRect){ 0, 0, iw, ih }, + out->data[i], out->linesize[i], + (NppiRect){ 0, 0, ow, oh }, + angle, shiftw, shifth, NPPI_INTER_NN); + if (err != NPP_SUCCESS) { + av_log(ctx, AV_LOG_ERROR, "NPP rotate error: %d\n", err); + return AVERROR_UNKNOWN; + } + } + + return 0; +} + +static int npptranspose_transpose(AVFilterContext *ctx, NPPTransposeStageContext *stage, + AVFrame *out, AVFrame *in) +{ + NppStatus err; + int i; + + for (i = 0; i < FF_ARRAY_ELEMS(stage->planes_in) && i < FF_ARRAY_ELEMS(in->data) && in->data[i]; i++) { + int iw = stage->planes_in[i].width; + int ih = stage->planes_in[i].height; + + err = nppiTranspose_8u_C1R(in->data[i], in->linesize[i], + out->data[i], out->linesize[i], + (NppiSize){ iw, ih }); + if (err != NPP_SUCCESS) { + av_log(ctx, AV_LOG_ERROR, "NPP transpose error: %d\n", err); + return AVERROR_UNKNOWN; + } + } + + return 0; +} + +static int (*const npptranspose_process[])(AVFilterContext *ctx, NPPTransposeStageContext *stage, + AVFrame *out, AVFrame *in) = { + [STAGE_ROTATE] = npptranspose_rotate, + [STAGE_TRANSPOSE] = npptranspose_transpose +}; + +static int npptranspose_filter(AVFilterContext *ctx, AVFrame *out, AVFrame *in) +{ + NPPTransposeContext *s = ctx->priv; + AVFrame *src = in; + int i, ret, last_stage = -1; + + for (i = 0; i < FF_ARRAY_ELEMS(s->stages); i++) { + if (!s->stages[i].stage_needed) + continue; + + ret = npptranspose_process[i](ctx, &s->stages[i], s->stages[i].frame, src); + if (ret < 0) + return ret; + + src = s->stages[i].frame; + last_stage = i; + } + + if (last_stage < 0) + return AVERROR_BUG; + + ret = av_hwframe_get_buffer(src->hw_frames_ctx, s->tmp_frame, 0); + if (ret < 0) + return ret; + + av_frame_move_ref(out, src); + av_frame_move_ref(src, s->tmp_frame); + + ret = av_frame_copy_props(out, in); + if (ret < 0) + return ret; + + return 0; +} + +static int npptranspose_filter_frame(AVFilterLink *link, AVFrame *in) +{ + AVFilterContext *ctx = link->dst; + NPPTransposeContext *s = ctx->priv; + AVFilterLink *outlink = ctx->outputs[0]; + AVHWFramesContext *frames_ctx = (AVHWFramesContext*)outlink->hw_frames_ctx->data; + AVCUDADeviceContext *device_hwctx = frames_ctx->device_ctx->hwctx; + AVFrame *out = NULL; + CUcontext dummy; + int ret = 0; + + if (s->passthrough) + return ff_filter_frame(outlink, in); + + out = av_frame_alloc(); + if (!out) { + ret = AVERROR(ENOMEM); + goto fail; + } + + ret = CHECK_CU(device_hwctx->internal->cuda_dl->cuCtxPushCurrent(device_hwctx->cuda_ctx)); + if (ret < 0) + goto fail; + + ret = npptranspose_filter(ctx, out, in); + + CHECK_CU(device_hwctx->internal->cuda_dl->cuCtxPopCurrent(&dummy)); + if (ret < 0) + goto fail; + + av_frame_free(&in); + + return ff_filter_frame(outlink, out); + +fail: + av_frame_free(&in); + av_frame_free(&out); + return ret; +} + +#define OFFSET(x) offsetof(NPPTransposeContext, x) +#define FLAGS (AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM) + +static const AVOption options[] = { + { "dir", "set transpose direction", OFFSET(dir), AV_OPT_TYPE_INT, { .i64 = NPP_TRANSPOSE_CCLOCK_FLIP }, 0, 3, FLAGS, "dir" }, + { "cclock_flip", "rotate counter-clockwise with vertical flip", 0, AV_OPT_TYPE_CONST, { .i64 = NPP_TRANSPOSE_CCLOCK_FLIP }, 0, 0, FLAGS, "dir" }, + { "clock", "rotate clockwise", 0, AV_OPT_TYPE_CONST, { .i64 = NPP_TRANSPOSE_CLOCK }, 0, 0, FLAGS, "dir" }, + { "cclock", "rotate counter-clockwise", 0, AV_OPT_TYPE_CONST, { .i64 = NPP_TRANSPOSE_CCLOCK }, 0, 0, FLAGS, "dir" }, + { "clock_flip", "rotate clockwise with vertical flip", 0, AV_OPT_TYPE_CONST, { .i64 = NPP_TRANSPOSE_CLOCK_FLIP }, 0, 0, FLAGS, "dir" }, + { "passthrough", "do not apply transposition if the input matches the specified geometry", OFFSET(passthrough), AV_OPT_TYPE_INT, { .i64 = NPP_TRANSPOSE_PT_TYPE_NONE }, 0, 2, FLAGS, "passthrough" }, + { "none", "always apply transposition", 0, AV_OPT_TYPE_CONST, { .i64 = NPP_TRANSPOSE_PT_TYPE_NONE }, 0, 0, FLAGS, "passthrough" }, + { "landscape", "preserve landscape geometry", 0, AV_OPT_TYPE_CONST, { .i64 = NPP_TRANSPOSE_PT_TYPE_LANDSCAPE }, 0, 0, FLAGS, "passthrough" }, + { "portrait", "preserve portrait geometry", 0, AV_OPT_TYPE_CONST, { .i64 = NPP_TRANSPOSE_PT_TYPE_PORTRAIT }, 0, 0, FLAGS, "passthrough" }, + { NULL }, +}; + +static const AVClass npptranspose_class = { + .class_name = "npptranspose", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; + +static const AVFilterPad npptranspose_inputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + .filter_frame = npptranspose_filter_frame, + }, + { NULL } +}; + +static const AVFilterPad npptranspose_outputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + .config_props = npptranspose_config_props, + }, + { NULL } +}; + +AVFilter ff_vf_transpose_npp = { + .name = "transpose_npp", + .description = NULL_IF_CONFIG_SMALL("NVIDIA Performance Primitives video transpose"), + .init = npptranspose_init, + .uninit = npptranspose_uninit, + .query_formats = npptranspose_query_formats, + .priv_size = sizeof(NPPTransposeContext), + .priv_class = &npptranspose_class, + .inputs = npptranspose_inputs, + .outputs = npptranspose_outputs, + .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE, +}; diff --git a/libavfilter/vf_transpose_opencl.c b/libavfilter/vf_transpose_opencl.c new file mode 100644 index 000000000..dd678e91c --- /dev/null +++ b/libavfilter/vf_transpose_opencl.c @@ -0,0 +1,288 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include + +#include "libavutil/avassert.h" +#include "libavutil/common.h" +#include "libavutil/imgutils.h" +#include "libavutil/mem.h" +#include "libavutil/opt.h" +#include "libavutil/pixdesc.h" + +#include "avfilter.h" +#include "internal.h" +#include "opencl.h" +#include "opencl_source.h" +#include "video.h" +#include "transpose.h" + +typedef struct TransposeOpenCLContext { + OpenCLFilterContext ocf; + int initialised; + int passthrough; ///< PassthroughType, landscape passthrough mode enabled + int dir; ///< TransposeDir + cl_kernel kernel; + cl_command_queue command_queue; +} TransposeOpenCLContext; + +static int transpose_opencl_init(AVFilterContext *avctx) +{ + TransposeOpenCLContext *ctx = avctx->priv; + cl_int cle; + int err; + + err = ff_opencl_filter_load_program(avctx, &ff_opencl_source_transpose, 1); + if (err < 0) + goto fail; + + ctx->command_queue = clCreateCommandQueue(ctx->ocf.hwctx->context, + ctx->ocf.hwctx->device_id, + 0, &cle); + CL_FAIL_ON_ERROR(AVERROR(EIO), "Failed to create OpenCL " + "command queue %d.\n", cle); + + ctx->kernel = clCreateKernel(ctx->ocf.program, "transpose", &cle); + CL_FAIL_ON_ERROR(AVERROR(EIO), "Failed to create kernel %d.\n", cle); + + + ctx->initialised = 1; + return 0; + +fail: + if (ctx->command_queue) + clReleaseCommandQueue(ctx->command_queue); + if (ctx->kernel) + clReleaseKernel(ctx->kernel); + return err; +} + +static int transpose_opencl_config_output(AVFilterLink *outlink) +{ + AVFilterContext *avctx = outlink->src; + TransposeOpenCLContext *s = avctx->priv; + AVFilterLink *inlink = avctx->inputs[0]; + const AVPixFmtDescriptor *desc_in = av_pix_fmt_desc_get(inlink->format); + int ret; + + if ((inlink->w >= inlink->h && + s->passthrough == TRANSPOSE_PT_TYPE_LANDSCAPE) || + (inlink->w <= inlink->h && + s->passthrough == TRANSPOSE_PT_TYPE_PORTRAIT)) { + if (inlink->hw_frames_ctx) { + outlink->hw_frames_ctx = av_buffer_ref(inlink->hw_frames_ctx); + if (!outlink->hw_frames_ctx) + return AVERROR(ENOMEM); + } + av_log(avctx, AV_LOG_VERBOSE, + "w:%d h:%d -> w:%d h:%d (passthrough mode)\n", + inlink->w, inlink->h, inlink->w, inlink->h); + + return 0; + } else { + s->passthrough = TRANSPOSE_PT_TYPE_NONE; + } + + if (desc_in->log2_chroma_w != desc_in->log2_chroma_h) { + av_log(avctx, AV_LOG_ERROR, "Input format %s not supported.\n", + desc_in->name); + return AVERROR(EINVAL); + } + + s->ocf.output_width = inlink->h; + s->ocf.output_height = inlink->w; + ret = ff_opencl_filter_config_output(outlink); + if (ret < 0) + return ret; + + if (inlink->sample_aspect_ratio.num) + outlink->sample_aspect_ratio = av_div_q((AVRational) { 1, 1 }, + inlink->sample_aspect_ratio); + else + outlink->sample_aspect_ratio = inlink->sample_aspect_ratio; + + av_log(avctx, AV_LOG_VERBOSE, + "w:%d h:%d dir:%d -> w:%d h:%d rotation:%s vflip:%d\n", + inlink->w, inlink->h, s->dir, outlink->w, outlink->h, + s->dir == 1 || s->dir == 3 ? "clockwise" : "counterclockwise", + s->dir == 0 || s->dir == 3); + return 0; +} + +static AVFrame *get_video_buffer(AVFilterLink *inlink, int w, int h) +{ + TransposeOpenCLContext *s = inlink->dst->priv; + + return s->passthrough ? + ff_null_get_video_buffer (inlink, w, h) : + ff_default_get_video_buffer(inlink, w, h); +} + +static int transpose_opencl_filter_frame(AVFilterLink *inlink, AVFrame *input) +{ + AVFilterContext *avctx = inlink->dst; + AVFilterLink *outlink = avctx->outputs[0]; + TransposeOpenCLContext *ctx = avctx->priv; + AVFrame *output = NULL; + size_t global_work[2]; + cl_mem src, dst; + cl_int cle; + int err, p; + + av_log(ctx, AV_LOG_DEBUG, "Filter input: %s, %ux%u (%"PRId64").\n", + av_get_pix_fmt_name(input->format), + input->width, input->height, input->pts); + + if (!input->hw_frames_ctx) + return AVERROR(EINVAL); + + if (ctx->passthrough) + return ff_filter_frame(outlink, input); + + output = ff_get_video_buffer(outlink, outlink->w, outlink->h); + if (!output) { + err = AVERROR(ENOMEM); + goto fail; + } + + err = av_frame_copy_props(output, input); + if (err < 0) + goto fail; + + if (input->sample_aspect_ratio.num == 0) { + output->sample_aspect_ratio = input->sample_aspect_ratio; + } else { + output->sample_aspect_ratio.num = input->sample_aspect_ratio.den; + output->sample_aspect_ratio.den = input->sample_aspect_ratio.num; + } + + if (!ctx->initialised) { + err = transpose_opencl_init(avctx); + if (err < 0) + goto fail; + } + + for (p = 0; p < FF_ARRAY_ELEMS(output->data); p++) { + src = (cl_mem) input->data[p]; + dst = (cl_mem) output->data[p]; + + if (!dst) + break; + CL_SET_KERNEL_ARG(ctx->kernel, 0, cl_mem, &dst); + CL_SET_KERNEL_ARG(ctx->kernel, 1, cl_mem, &src); + CL_SET_KERNEL_ARG(ctx->kernel, 2, cl_int, &ctx->dir); + + err = ff_opencl_filter_work_size_from_image(avctx, global_work, output, + p, 16); + + cle = clEnqueueNDRangeKernel(ctx->command_queue, ctx->kernel, 2, NULL, + global_work, NULL, + 0, NULL, NULL); + CL_FAIL_ON_ERROR(AVERROR(EIO), "Failed to enqueue kernel: %d.\n", cle); + } + cle = clFinish(ctx->command_queue); + CL_FAIL_ON_ERROR(AVERROR(EIO), "Failed to finish command queue: %d.\n", cle); + + av_frame_free(&input); + + av_log(ctx, AV_LOG_DEBUG, "Filter output: %s, %ux%u (%"PRId64").\n", + av_get_pix_fmt_name(output->format), + output->width, output->height, output->pts); + + return ff_filter_frame(outlink, output); + +fail: + clFinish(ctx->command_queue); + av_frame_free(&input); + av_frame_free(&output); + return err; +} + +static av_cold void transpose_opencl_uninit(AVFilterContext *avctx) +{ + TransposeOpenCLContext *ctx = avctx->priv; + cl_int cle; + + if (ctx->kernel) { + cle = clReleaseKernel(ctx->kernel); + if (cle != CL_SUCCESS) + av_log(avctx, AV_LOG_ERROR, "Failed to release " + "kernel: %d.\n", cle); + } + + if (ctx->command_queue) { + cle = clReleaseCommandQueue(ctx->command_queue); + if (cle != CL_SUCCESS) + av_log(avctx, AV_LOG_ERROR, "Failed to release " + "command queue: %d.\n", cle); + } + + ff_opencl_filter_uninit(avctx); +} + +#define OFFSET(x) offsetof(TransposeOpenCLContext, x) +#define FLAGS (AV_OPT_FLAG_FILTERING_PARAM | AV_OPT_FLAG_VIDEO_PARAM) +static const AVOption transpose_opencl_options[] = { + { "dir", "set transpose direction", OFFSET(dir), AV_OPT_TYPE_INT, { .i64 = TRANSPOSE_CCLOCK_FLIP }, 0, 3, FLAGS, "dir" }, + { "cclock_flip", "rotate counter-clockwise with vertical flip", 0, AV_OPT_TYPE_CONST, { .i64 = TRANSPOSE_CCLOCK_FLIP }, .flags=FLAGS, .unit = "dir" }, + { "clock", "rotate clockwise", 0, AV_OPT_TYPE_CONST, { .i64 = TRANSPOSE_CLOCK }, .flags=FLAGS, .unit = "dir" }, + { "cclock", "rotate counter-clockwise", 0, AV_OPT_TYPE_CONST, { .i64 = TRANSPOSE_CCLOCK }, .flags=FLAGS, .unit = "dir" }, + { "clock_flip", "rotate clockwise with vertical flip", 0, AV_OPT_TYPE_CONST, { .i64 = TRANSPOSE_CLOCK_FLIP }, .flags=FLAGS, .unit = "dir" }, + + { "passthrough", "do not apply transposition if the input matches the specified geometry", + OFFSET(passthrough), AV_OPT_TYPE_INT, {.i64=TRANSPOSE_PT_TYPE_NONE}, 0, INT_MAX, FLAGS, "passthrough" }, + { "none", "always apply transposition", 0, AV_OPT_TYPE_CONST, {.i64=TRANSPOSE_PT_TYPE_NONE}, INT_MIN, INT_MAX, FLAGS, "passthrough" }, + { "portrait", "preserve portrait geometry", 0, AV_OPT_TYPE_CONST, {.i64=TRANSPOSE_PT_TYPE_PORTRAIT}, INT_MIN, INT_MAX, FLAGS, "passthrough" }, + { "landscape", "preserve landscape geometry", 0, AV_OPT_TYPE_CONST, {.i64=TRANSPOSE_PT_TYPE_LANDSCAPE}, INT_MIN, INT_MAX, FLAGS, "passthrough" }, + + { NULL } +}; + +AVFILTER_DEFINE_CLASS(transpose_opencl); + +static const AVFilterPad transpose_opencl_inputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + .get_video_buffer = get_video_buffer, + .filter_frame = &transpose_opencl_filter_frame, + .config_props = &ff_opencl_filter_config_input, + }, + { NULL } +}; + +static const AVFilterPad transpose_opencl_outputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + .config_props = &transpose_opencl_config_output, + }, + { NULL } +}; + +AVFilter ff_vf_transpose_opencl = { + .name = "transpose_opencl", + .description = NULL_IF_CONFIG_SMALL("Transpose input video"), + .priv_size = sizeof(TransposeOpenCLContext), + .priv_class = &transpose_opencl_class, + .init = &ff_opencl_filter_init, + .uninit = &transpose_opencl_uninit, + .query_formats = &ff_opencl_filter_query_formats, + .inputs = transpose_opencl_inputs, + .outputs = transpose_opencl_outputs, + .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE, +}; diff --git a/libavfilter/vf_transpose_vaapi.c b/libavfilter/vf_transpose_vaapi.c new file mode 100644 index 000000000..69dbdd701 --- /dev/null +++ b/libavfilter/vf_transpose_vaapi.c @@ -0,0 +1,288 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include + +#include "libavutil/avassert.h" +#include "libavutil/mem.h" +#include "libavutil/opt.h" +#include "libavutil/pixdesc.h" + +#include "avfilter.h" +#include "formats.h" +#include "internal.h" +#include "transpose.h" +#include "vaapi_vpp.h" + +typedef struct TransposeVAAPIContext { + VAAPIVPPContext vpp_ctx; // must be the first field + int passthrough; // PassthroughType, landscape passthrough mode enabled + int dir; // TransposeDir + + int rotation_state; + int mirror_state; +} TransposeVAAPIContext; + +static int transpose_vaapi_build_filter_params(AVFilterContext *avctx) +{ + VAAPIVPPContext *vpp_ctx = avctx->priv; + TransposeVAAPIContext *ctx = avctx->priv; + VAStatus vas; + int support_flag; + VAProcPipelineCaps pipeline_caps; + + memset(&pipeline_caps, 0, sizeof(pipeline_caps)); + vas = vaQueryVideoProcPipelineCaps(vpp_ctx->hwctx->display, + vpp_ctx->va_context, + NULL, 0, + &pipeline_caps); + if (vas != VA_STATUS_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to query pipeline " + "caps: %d (%s).\n", vas, vaErrorStr(vas)); + return AVERROR(EIO); + } + + if (!pipeline_caps.rotation_flags) { + av_log(avctx, AV_LOG_ERROR, "VAAPI driver doesn't support transpose\n"); + return AVERROR(EINVAL); + } + + switch (ctx->dir) { + case TRANSPOSE_CCLOCK_FLIP: + ctx->rotation_state = VA_ROTATION_270; + ctx->mirror_state = VA_MIRROR_VERTICAL; + break; + case TRANSPOSE_CLOCK: + ctx->rotation_state = VA_ROTATION_90; + ctx->mirror_state = VA_MIRROR_NONE; + break; + case TRANSPOSE_CCLOCK: + ctx->rotation_state = VA_ROTATION_270; + ctx->mirror_state = VA_MIRROR_NONE; + break; + case TRANSPOSE_CLOCK_FLIP: + ctx->rotation_state = VA_ROTATION_90; + ctx->mirror_state = VA_MIRROR_VERTICAL; + break; + case TRANSPOSE_REVERSAL: + ctx->rotation_state = VA_ROTATION_180; + ctx->mirror_state = VA_MIRROR_NONE; + break; + case TRANSPOSE_HFLIP: + ctx->rotation_state = VA_ROTATION_NONE; + ctx->mirror_state = VA_MIRROR_HORIZONTAL; + break; + case TRANSPOSE_VFLIP: + ctx->rotation_state = VA_ROTATION_NONE; + ctx->mirror_state = VA_MIRROR_VERTICAL; + break; + default: + av_log(avctx, AV_LOG_ERROR, "Failed to set direction to %d\n", ctx->dir); + return AVERROR(EINVAL); + } + + if (VA_ROTATION_NONE != ctx->rotation_state) { + support_flag = pipeline_caps.rotation_flags & (1 << ctx->rotation_state); + if (!support_flag) { + av_log(avctx, AV_LOG_ERROR, "VAAPI driver doesn't support rotation %d\n", + ctx->rotation_state); + return AVERROR(EINVAL); + } + } + + if (VA_MIRROR_NONE != ctx->mirror_state) { + support_flag = pipeline_caps.mirror_flags & ctx->mirror_state; + if (!support_flag) { + av_log(avctx, AV_LOG_ERROR, "VAAPI driver doesn't support mirror %d\n", + ctx->mirror_state); + return AVERROR(EINVAL); + } + } + + return 0; +} + +static int transpose_vaapi_filter_frame(AVFilterLink *inlink, AVFrame *input_frame) +{ + AVFilterContext *avctx = inlink->dst; + AVFilterLink *outlink = avctx->outputs[0]; + VAAPIVPPContext *vpp_ctx = avctx->priv; + TransposeVAAPIContext *ctx = avctx->priv; + AVFrame *output_frame = NULL; + VAProcPipelineParameterBuffer params; + int err; + + if (ctx->passthrough) + return ff_filter_frame(outlink, input_frame); + + av_log(avctx, AV_LOG_DEBUG, "Filter input: %s, %ux%u (%"PRId64").\n", + av_get_pix_fmt_name(input_frame->format), + input_frame->width, input_frame->height, input_frame->pts); + + if (vpp_ctx->va_context == VA_INVALID_ID) + return AVERROR(EINVAL); + + output_frame = ff_get_video_buffer(outlink, vpp_ctx->output_width, + vpp_ctx->output_height); + if (!output_frame) { + err = AVERROR(ENOMEM); + goto fail; + } + + err = av_frame_copy_props(output_frame, input_frame); + if (err < 0) + return err; + + err = ff_vaapi_vpp_init_params(avctx, ¶ms, + input_frame, output_frame); + if (err < 0) + goto fail; + + params.rotation_state = ctx->rotation_state; + params.mirror_state = ctx->mirror_state; + + err = ff_vaapi_vpp_render_picture(avctx, ¶ms, output_frame); + if (err < 0) + goto fail; + + av_frame_free(&input_frame); + + av_log(avctx, AV_LOG_DEBUG, "Filter output: %s, %ux%u (%"PRId64").\n", + av_get_pix_fmt_name(output_frame->format), + output_frame->width, output_frame->height, output_frame->pts); + + return ff_filter_frame(outlink, output_frame); + +fail: + av_frame_free(&input_frame); + av_frame_free(&output_frame); + return err; +} + +static av_cold int transpose_vaapi_init(AVFilterContext *avctx) +{ + VAAPIVPPContext *vpp_ctx = avctx->priv; + + ff_vaapi_vpp_ctx_init(avctx); + vpp_ctx->pipeline_uninit = ff_vaapi_vpp_pipeline_uninit; + vpp_ctx->build_filter_params = transpose_vaapi_build_filter_params; + vpp_ctx->output_format = AV_PIX_FMT_NONE; + + return 0; +} + +static int transpose_vaapi_vpp_config_output(AVFilterLink *outlink) +{ + AVFilterContext *avctx = outlink->src; + VAAPIVPPContext *vpp_ctx = avctx->priv; + TransposeVAAPIContext *ctx = avctx->priv; + AVFilterLink *inlink = avctx->inputs[0]; + + if ((inlink->w >= inlink->h && ctx->passthrough == TRANSPOSE_PT_TYPE_LANDSCAPE) || + (inlink->w <= inlink->h && ctx->passthrough == TRANSPOSE_PT_TYPE_PORTRAIT)) { + outlink->hw_frames_ctx = av_buffer_ref(inlink->hw_frames_ctx); + if (!outlink->hw_frames_ctx) + return AVERROR(ENOMEM); + av_log(avctx, AV_LOG_VERBOSE, + "w:%d h:%d -> w:%d h:%d (passthrough mode)\n", + inlink->w, inlink->h, inlink->w, inlink->h); + return 0; + } + + ctx->passthrough = TRANSPOSE_PT_TYPE_NONE; + + switch (ctx->dir) { + case TRANSPOSE_CCLOCK_FLIP: + case TRANSPOSE_CCLOCK: + case TRANSPOSE_CLOCK: + case TRANSPOSE_CLOCK_FLIP: + vpp_ctx->output_width = avctx->inputs[0]->h; + vpp_ctx->output_height = avctx->inputs[0]->w; + av_log(avctx, AV_LOG_DEBUG, "swap width and height for clock/cclock rotation\n"); + break; + default: + break; + } + + return ff_vaapi_vpp_config_output(outlink); +} + +static AVFrame *get_video_buffer(AVFilterLink *inlink, int w, int h) +{ + TransposeVAAPIContext *ctx = inlink->dst->priv; + + return ctx->passthrough ? + ff_null_get_video_buffer(inlink, w, h) : + ff_default_get_video_buffer(inlink, w, h); +} + +#define OFFSET(x) offsetof(TransposeVAAPIContext, x) +#define FLAGS (AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_FILTERING_PARAM) +static const AVOption transpose_vaapi_options[] = { + { "dir", "set transpose direction", OFFSET(dir), AV_OPT_TYPE_INT, { .i64 = TRANSPOSE_CCLOCK_FLIP }, 0, 6, FLAGS, "dir" }, + { "cclock_flip", "rotate counter-clockwise with vertical flip", 0, AV_OPT_TYPE_CONST, { .i64 = TRANSPOSE_CCLOCK_FLIP }, .flags=FLAGS, .unit = "dir" }, + { "clock", "rotate clockwise", 0, AV_OPT_TYPE_CONST, { .i64 = TRANSPOSE_CLOCK }, .flags=FLAGS, .unit = "dir" }, + { "cclock", "rotate counter-clockwise", 0, AV_OPT_TYPE_CONST, { .i64 = TRANSPOSE_CCLOCK }, .flags=FLAGS, .unit = "dir" }, + { "clock_flip", "rotate clockwise with vertical flip", 0, AV_OPT_TYPE_CONST, { .i64 = TRANSPOSE_CLOCK_FLIP }, .flags=FLAGS, .unit = "dir" }, + { "reversal", "rotate by half-turn", 0, AV_OPT_TYPE_CONST, { .i64 = TRANSPOSE_REVERSAL }, .flags=FLAGS, .unit = "dir" }, + { "hflip", "flip horizontally", 0, AV_OPT_TYPE_CONST, { .i64 = TRANSPOSE_HFLIP }, .flags=FLAGS, .unit = "dir" }, + { "vflip", "flip vertically", 0, AV_OPT_TYPE_CONST, { .i64 = TRANSPOSE_VFLIP }, .flags=FLAGS, .unit = "dir" }, + + { "passthrough", "do not apply transposition if the input matches the specified geometry", + OFFSET(passthrough), AV_OPT_TYPE_INT, {.i64=TRANSPOSE_PT_TYPE_NONE}, 0, INT_MAX, FLAGS, "passthrough" }, + { "none", "always apply transposition", 0, AV_OPT_TYPE_CONST, {.i64=TRANSPOSE_PT_TYPE_NONE}, INT_MIN, INT_MAX, FLAGS, "passthrough" }, + { "portrait", "preserve portrait geometry", 0, AV_OPT_TYPE_CONST, {.i64=TRANSPOSE_PT_TYPE_PORTRAIT}, INT_MIN, INT_MAX, FLAGS, "passthrough" }, + { "landscape", "preserve landscape geometry", 0, AV_OPT_TYPE_CONST, {.i64=TRANSPOSE_PT_TYPE_LANDSCAPE}, INT_MIN, INT_MAX, FLAGS, "passthrough" }, + + { NULL } +}; + + +AVFILTER_DEFINE_CLASS(transpose_vaapi); + +static const AVFilterPad transpose_vaapi_inputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + .filter_frame = &transpose_vaapi_filter_frame, + .get_video_buffer = get_video_buffer, + .config_props = &ff_vaapi_vpp_config_input, + }, + { NULL } +}; + +static const AVFilterPad transpose_vaapi_outputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + .config_props = &transpose_vaapi_vpp_config_output, + }, + { NULL } +}; + +AVFilter ff_vf_transpose_vaapi = { + .name = "transpose_vaapi", + .description = NULL_IF_CONFIG_SMALL("VAAPI VPP for transpose"), + .priv_size = sizeof(TransposeVAAPIContext), + .init = &transpose_vaapi_init, + .uninit = &ff_vaapi_vpp_ctx_uninit, + .query_formats = &ff_vaapi_vpp_query_formats, + .inputs = transpose_vaapi_inputs, + .outputs = transpose_vaapi_outputs, + .priv_class = &transpose_vaapi_class, + .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE, +}; diff --git a/libavfilter/vf_unsharp.c b/libavfilter/vf_unsharp.c index 41ccc5694..af05833a5 100644 --- a/libavfilter/vf_unsharp.c +++ b/libavfilter/vf_unsharp.c @@ -47,15 +47,22 @@ #include "libavutil/pixdesc.h" #include "unsharp.h" -static void apply_unsharp( uint8_t *dst, int dst_stride, - const uint8_t *src, int src_stride, - int width, int height, UnsharpFilterParam *fp) -{ - uint32_t **sc = fp->sc; - uint32_t sr[MAX_MATRIX_SIZE - 1], tmp1, tmp2; +typedef struct TheadData { + UnsharpFilterParam *fp; + uint8_t *dst; + const uint8_t *src; + int dst_stride; + int src_stride; + int width; + int height; +} ThreadData; - int32_t res; - int x, y, z; +static int unsharp_slice(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) +{ + ThreadData *td = arg; + UnsharpFilterParam *fp = td->fp; + uint32_t **sc = fp->sc; + uint32_t *sr = fp->sr; const uint8_t *src2 = NULL; //silence a warning const int amount = fp->amount; const int steps_x = fp->steps_x; @@ -63,30 +70,54 @@ static void apply_unsharp( uint8_t *dst, int dst_stride, const int scalebits = fp->scalebits; const int32_t halfscale = fp->halfscale; + uint8_t *dst = td->dst; + const uint8_t *src = td->src; + const int dst_stride = td->dst_stride; + const int src_stride = td->src_stride; + const int width = td->width; + const int height = td->height; + const int sc_offset = jobnr * 2 * steps_y; + const int sr_offset = jobnr * (MAX_MATRIX_SIZE - 1); + const int slice_start = (height * jobnr) / nb_jobs; + const int slice_end = (height * (jobnr+1)) / nb_jobs; + + int32_t res; + int x, y, z; + uint32_t tmp1, tmp2; + if (!amount) { - av_image_copy_plane(dst, dst_stride, src, src_stride, width, height); - return; + av_image_copy_plane(dst + slice_start * dst_stride, dst_stride, + src + slice_start * src_stride, src_stride, + width, slice_end - slice_start); + return 0; } for (y = 0; y < 2 * steps_y; y++) - memset(sc[y], 0, sizeof(sc[y][0]) * (width + 2 * steps_x)); + memset(sc[sc_offset + y], 0, sizeof(sc[y][0]) * (width + 2 * steps_x)); - for (y = -steps_y; y < height + steps_y; y++) { + // if this is not the first tile, we start from (slice_start - steps_y), + // so we can get smooth result at slice boundary + if (slice_start > steps_y) { + src += (slice_start - steps_y) * src_stride; + dst += (slice_start - steps_y) * dst_stride; + } + + for (y = -steps_y + slice_start; y < steps_y + slice_end; y++) { if (y < height) src2 = src; - memset(sr, 0, sizeof(sr[0]) * (2 * steps_x - 1)); + memset(sr + sr_offset, 0, sizeof(sr[0]) * (2 * steps_x - 1)); for (x = -steps_x; x < width + steps_x; x++) { tmp1 = x <= 0 ? src2[0] : x >= width ? src2[width-1] : src2[x]; for (z = 0; z < steps_x * 2; z += 2) { - tmp2 = sr[z + 0] + tmp1; sr[z + 0] = tmp1; - tmp1 = sr[z + 1] + tmp2; sr[z + 1] = tmp2; + tmp2 = sr[sr_offset + z + 0] + tmp1; sr[sr_offset + z + 0] = tmp1; + tmp1 = sr[sr_offset + z + 1] + tmp2; sr[sr_offset + z + 1] = tmp2; } for (z = 0; z < steps_y * 2; z += 2) { - tmp2 = sc[z + 0][x + steps_x] + tmp1; sc[z + 0][x + steps_x] = tmp1; - tmp1 = sc[z + 1][x + steps_x] + tmp2; sc[z + 1][x + steps_x] = tmp2; + tmp2 = sc[sc_offset + z + 0][x + steps_x] + tmp1; sc[sc_offset + z + 0][x + steps_x] = tmp1; + tmp1 = sc[sc_offset + z + 1][x + steps_x] + tmp2; sc[sc_offset + z + 1][x + steps_x] = tmp2; } - if (x >= steps_x && y >= steps_y) { + if (x >= steps_x && y >= (steps_y + slice_start)) { const uint8_t *srx = src - steps_y * src_stride + x - steps_x; uint8_t *dsx = dst - steps_y * dst_stride + x - steps_x; @@ -99,6 +130,7 @@ static void apply_unsharp( uint8_t *dst, int dst_stride, src += src_stride; } } + return 0; } static int apply_unsharp_c(AVFilterContext *ctx, AVFrame *in, AVFrame *out) @@ -107,6 +139,8 @@ static int apply_unsharp_c(AVFilterContext *ctx, AVFrame *in, AVFrame *out) UnsharpContext *s = ctx->priv; int i, plane_w[3], plane_h[3]; UnsharpFilterParam *fp[3]; + ThreadData td; + plane_w[0] = inlink->w; plane_w[1] = plane_w[2] = AV_CEIL_RSHIFT(inlink->w, s->hsub); plane_h[0] = inlink->h; @@ -114,7 +148,14 @@ static int apply_unsharp_c(AVFilterContext *ctx, AVFrame *in, AVFrame *out) fp[0] = &s->luma; fp[1] = fp[2] = &s->chroma; for (i = 0; i < 3; i++) { - apply_unsharp(out->data[i], out->linesize[i], in->data[i], in->linesize[i], plane_w[i], plane_h[i], fp[i]); + td.fp = fp[i]; + td.dst = out->data[i]; + td.src = in->data[i]; + td.width = plane_w[i]; + td.height = plane_h[i]; + td.dst_stride = out->linesize[i]; + td.src_stride = in->linesize[i]; + ctx->internal->execute(ctx, unsharp_slice, &td, NULL, FFMIN(plane_h[i], s->nb_threads)); } return 0; } @@ -163,6 +204,7 @@ static int query_formats(AVFilterContext *ctx) static int init_filter_param(AVFilterContext *ctx, UnsharpFilterParam *fp, const char *effect_type, int width) { int z; + UnsharpContext *s = ctx->priv; const char *effect = fp->amount == 0 ? "none" : fp->amount < 0 ? "blur" : "sharpen"; if (!(fp->msize_x & fp->msize_y & 1)) { @@ -175,7 +217,12 @@ static int init_filter_param(AVFilterContext *ctx, UnsharpFilterParam *fp, const av_log(ctx, AV_LOG_VERBOSE, "effect:%s type:%s msize_x:%d msize_y:%d amount:%0.2f\n", effect, effect_type, fp->msize_x, fp->msize_y, fp->amount / 65535.0); - for (z = 0; z < 2 * fp->steps_y; z++) + fp->sr = av_malloc_array((MAX_MATRIX_SIZE - 1) * s->nb_threads, sizeof(uint32_t)); + fp->sc = av_malloc_array(2 * fp->steps_y * s->nb_threads, sizeof(uint32_t **)); + if (!fp->sr || !fp->sc) + return AVERROR(ENOMEM); + + for (z = 0; z < 2 * fp->steps_y * s->nb_threads; z++) if (!(fp->sc[z] = av_malloc_array(width + 2 * fp->steps_x, sizeof(*(fp->sc[z]))))) return AVERROR(ENOMEM); @@ -192,6 +239,11 @@ static int config_props(AVFilterLink *link) s->hsub = desc->log2_chroma_w; s->vsub = desc->log2_chroma_h; + // ensure (height / nb_threads) > 4 * steps_y, + // so that we don't have too much overlap between two threads + s->nb_threads = FFMIN(ff_filter_get_nb_threads(link->dst), + link->h / (4 * s->luma.steps_y)); + ret = init_filter_param(link->dst, &s->luma, "luma", link->w); if (ret < 0) return ret; @@ -202,20 +254,22 @@ static int config_props(AVFilterLink *link) return 0; } -static void free_filter_param(UnsharpFilterParam *fp) +static void free_filter_param(UnsharpFilterParam *fp, int nb_threads) { int z; - for (z = 0; z < 2 * fp->steps_y; z++) + for (z = 0; z < 2 * fp->steps_y * nb_threads; z++) av_freep(&fp->sc[z]); + av_freep(&fp->sc); + av_freep(&fp->sr); } static av_cold void uninit(AVFilterContext *ctx) { UnsharpContext *s = ctx->priv; - free_filter_param(&s->luma); - free_filter_param(&s->chroma); + free_filter_param(&s->luma, s->nb_threads); + free_filter_param(&s->chroma, s->nb_threads); } static int filter_frame(AVFilterLink *link, AVFrame *in) @@ -294,5 +348,5 @@ AVFilter ff_vf_unsharp = { .query_formats = query_formats, .inputs = avfilter_vf_unsharp_inputs, .outputs = avfilter_vf_unsharp_outputs, - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC, + .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS, }; diff --git a/libavfilter/vf_unsharp_opencl.c b/libavfilter/vf_unsharp_opencl.c index 19c91857c..d76d1b173 100644 --- a/libavfilter/vf_unsharp_opencl.c +++ b/libavfilter/vf_unsharp_opencl.c @@ -76,12 +76,8 @@ static int unsharp_opencl_init(AVFilterContext *avctx) ctx->command_queue = clCreateCommandQueue(ctx->ocf.hwctx->context, ctx->ocf.hwctx->device_id, 0, &cle); - if (!ctx->command_queue) { - av_log(avctx, AV_LOG_ERROR, "Failed to create OpenCL " - "command queue: %d.\n", cle); - err = AVERROR(EIO); - goto fail; - } + CL_FAIL_ON_ERROR(AVERROR(EIO), "Failed to create OpenCL " + "command queue %d.\n", cle); // Use global kernel if mask size will be too big for the local store.. ctx->global = (ctx->luma_size_x > 17.0f || @@ -92,11 +88,7 @@ static int unsharp_opencl_init(AVFilterContext *avctx) ctx->kernel = clCreateKernel(ctx->ocf.program, ctx->global ? "unsharp_global" : "unsharp_local", &cle); - if (!ctx->kernel) { - av_log(avctx, AV_LOG_ERROR, "Failed to create kernel: %d.\n", cle); - err = AVERROR(EIO); - goto fail; - } + CL_FAIL_ON_ERROR(AVERROR(EIO), "Failed to create kernel %d.\n", cle); ctx->initialised = 1; return 0; @@ -176,12 +168,8 @@ static int unsharp_opencl_make_filter_params(AVFilterContext *avctx) CL_MEM_COPY_HOST_PTR | CL_MEM_HOST_NO_ACCESS, matrix_bytes, matrix, &cle); - if (!buffer) { - av_log(avctx, AV_LOG_ERROR, "Failed to create matrix buffer: " - "%d.\n", cle); - err = AVERROR(EIO); - goto fail; - } + CL_FAIL_ON_ERROR(AVERROR(EIO), "Failed to create matrix buffer: " + "%d.\n", cle); ctx->plane[p].matrix = buffer; } else { buffer = clCreateBuffer(ctx->ocf.hwctx->context, @@ -190,12 +178,8 @@ static int unsharp_opencl_make_filter_params(AVFilterContext *avctx) CL_MEM_HOST_NO_ACCESS, sizeof(ctx->plane[p].blur_x), ctx->plane[p].blur_x, &cle); - if (!buffer) { - av_log(avctx, AV_LOG_ERROR, "Failed to create x-coef buffer: " - "%d.\n", cle); - err = AVERROR(EIO); - goto fail; - } + CL_FAIL_ON_ERROR(AVERROR(EIO), "Failed to create x-coef buffer: " + "%d.\n", cle); ctx->plane[p].coef_x = buffer; buffer = clCreateBuffer(ctx->ocf.hwctx->context, @@ -204,12 +188,8 @@ static int unsharp_opencl_make_filter_params(AVFilterContext *avctx) CL_MEM_HOST_NO_ACCESS, sizeof(ctx->plane[p].blur_y), ctx->plane[p].blur_y, &cle); - if (!buffer) { - av_log(avctx, AV_LOG_ERROR, "Failed to create y-coef buffer: " - "%d.\n", cle); - err = AVERROR(EIO); - goto fail; - } + CL_FAIL_ON_ERROR(AVERROR(EIO), "Failed to create y-coef buffer: " + "%d.\n", cle); ctx->plane[p].coef_y = buffer; } @@ -268,56 +248,17 @@ static int unsharp_opencl_filter_frame(AVFilterLink *inlink, AVFrame *input) if (!dst) break; - cle = clSetKernelArg(ctx->kernel, 0, sizeof(cl_mem), &dst); - if (cle != CL_SUCCESS) { - av_log(avctx, AV_LOG_ERROR, "Failed to set kernel " - "destination image argument: %d.\n", cle); - goto fail; - } - cle = clSetKernelArg(ctx->kernel, 1, sizeof(cl_mem), &src); - if (cle != CL_SUCCESS) { - av_log(avctx, AV_LOG_ERROR, "Failed to set kernel " - "source image argument: %d.\n", cle); - goto fail; - } - cle = clSetKernelArg(ctx->kernel, 2, sizeof(cl_int), &ctx->plane[p].size_x); - if (cle != CL_SUCCESS) { - av_log(avctx, AV_LOG_ERROR, "Failed to set kernel " - "matrix size argument: %d.\n", cle); - goto fail; - } - cle = clSetKernelArg(ctx->kernel, 3, sizeof(cl_int), &ctx->plane[p].size_y); - if (cle != CL_SUCCESS) { - av_log(avctx, AV_LOG_ERROR, "Failed to set kernel " - "matrix size argument: %d.\n", cle); - goto fail; - } - cle = clSetKernelArg(ctx->kernel, 4, sizeof(cl_float), &ctx->plane[p].amount); - if (cle != CL_SUCCESS) { - av_log(avctx, AV_LOG_ERROR, "Failed to set kernel " - "amount argument: %d.\n", cle); - goto fail; - } + CL_SET_KERNEL_ARG(ctx->kernel, 0, cl_mem, &dst); + CL_SET_KERNEL_ARG(ctx->kernel, 1, cl_mem, &src); + CL_SET_KERNEL_ARG(ctx->kernel, 2, cl_int, &ctx->plane[p].size_x); + CL_SET_KERNEL_ARG(ctx->kernel, 3, cl_int, &ctx->plane[p].size_y); + CL_SET_KERNEL_ARG(ctx->kernel, 4, cl_float, &ctx->plane[p].amount); + if (ctx->global) { - cle = clSetKernelArg(ctx->kernel, 5, sizeof(cl_mem), &ctx->plane[p].matrix); - if (cle != CL_SUCCESS) { - av_log(avctx, AV_LOG_ERROR, "Failed to set kernel " - "matrix argument: %d.\n", cle); - goto fail; - } + CL_SET_KERNEL_ARG(ctx->kernel, 5, cl_mem, &ctx->plane[p].matrix); } else { - cle = clSetKernelArg(ctx->kernel, 5, sizeof(cl_mem), &ctx->plane[p].coef_x); - if (cle != CL_SUCCESS) { - av_log(avctx, AV_LOG_ERROR, "Failed to set kernel " - "x-coef argument: %d.\n", cle); - goto fail; - } - cle = clSetKernelArg(ctx->kernel, 6, sizeof(cl_mem), &ctx->plane[p].coef_y); - if (cle != CL_SUCCESS) { - av_log(avctx, AV_LOG_ERROR, "Failed to set kernel " - "y-coef argument: %d.\n", cle); - goto fail; - } + CL_SET_KERNEL_ARG(ctx->kernel, 5, cl_mem, &ctx->plane[p].coef_x); + CL_SET_KERNEL_ARG(ctx->kernel, 6, cl_mem, &ctx->plane[p].coef_y); } err = ff_opencl_filter_work_size_from_image(avctx, global_work, output, p, @@ -335,21 +276,11 @@ static int unsharp_opencl_filter_frame(AVFilterLink *inlink, AVFrame *input) cle = clEnqueueNDRangeKernel(ctx->command_queue, ctx->kernel, 2, NULL, global_work, ctx->global ? NULL : local_work, 0, NULL, NULL); - if (cle != CL_SUCCESS) { - av_log(avctx, AV_LOG_ERROR, "Failed to enqueue kernel: %d.\n", - cle); - err = AVERROR(EIO); - goto fail; - } + CL_FAIL_ON_ERROR(AVERROR(EIO), "Failed to enqueue kernel: %d.\n", cle); } cle = clFinish(ctx->command_queue); - if (cle != CL_SUCCESS) { - av_log(avctx, AV_LOG_ERROR, "Failed to finish command queue: %d.\n", - cle); - err = AVERROR(EIO); - goto fail; - } + CL_FAIL_ON_ERROR(AVERROR(EIO), "Failed to finish command queue: %d.\n", cle); err = av_frame_copy_props(output, input); if (err < 0) diff --git a/libavfilter/vf_vibrance.c b/libavfilter/vf_vibrance.c new file mode 100644 index 000000000..aac61c0f1 --- /dev/null +++ b/libavfilter/vf_vibrance.c @@ -0,0 +1,252 @@ +/* + * Copyright (c) 2018 Paul B Mahol + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/opt.h" +#include "libavutil/imgutils.h" +#include "avfilter.h" +#include "formats.h" +#include "internal.h" +#include "video.h" + +typedef struct VibranceContext { + const AVClass *class; + + float intensity; + float balance[3]; + float lcoeffs[3]; + int alternate; + + int depth; + + int (*do_slice)(AVFilterContext *s, void *arg, + int jobnr, int nb_jobs); +} VibranceContext; + +static inline float lerpf(float v0, float v1, float f) +{ + return v0 + (v1 - v0) * f; +} + +static int vibrance_slice8(AVFilterContext *avctx, void *arg, int jobnr, int nb_jobs) +{ + VibranceContext *s = avctx->priv; + AVFrame *frame = arg; + const int width = frame->width; + const int height = frame->height; + const float scale = 1.f / 255.f; + const float gc = s->lcoeffs[0]; + const float bc = s->lcoeffs[1]; + const float rc = s->lcoeffs[2]; + const float intensity = s->intensity; + const float alternate = s->alternate ? 1.f : -1.f; + const float gintensity = intensity * s->balance[0]; + const float bintensity = intensity * s->balance[1]; + const float rintensity = intensity * s->balance[2]; + const float sgintensity = alternate * FFSIGN(gintensity); + const float sbintensity = alternate * FFSIGN(bintensity); + const float srintensity = alternate * FFSIGN(rintensity); + const int slice_start = (height * jobnr) / nb_jobs; + const int slice_end = (height * (jobnr + 1)) / nb_jobs; + const int glinesize = frame->linesize[0]; + const int blinesize = frame->linesize[1]; + const int rlinesize = frame->linesize[2]; + uint8_t *gptr = frame->data[0] + slice_start * glinesize; + uint8_t *bptr = frame->data[1] + slice_start * blinesize; + uint8_t *rptr = frame->data[2] + slice_start * rlinesize; + + for (int y = slice_start; y < slice_end; y++) { + for (int x = 0; x < width; x++) { + float g = gptr[x] * scale; + float b = bptr[x] * scale; + float r = rptr[x] * scale; + float max_color = FFMAX3(r, g, b); + float min_color = FFMIN3(r, g, b); + float color_saturation = max_color - min_color; + float luma = g * gc + r * rc + b * bc; + const float cg = 1.f + gintensity * (1.f - sgintensity * color_saturation); + const float cb = 1.f + bintensity * (1.f - sbintensity * color_saturation); + const float cr = 1.f + rintensity * (1.f - srintensity * color_saturation); + + g = lerpf(luma, g, cg); + b = lerpf(luma, b, cb); + r = lerpf(luma, r, cr); + + gptr[x] = av_clip_uint8(g * 255.f); + bptr[x] = av_clip_uint8(b * 255.f); + rptr[x] = av_clip_uint8(r * 255.f); + } + + gptr += glinesize; + bptr += blinesize; + rptr += rlinesize; + } + + return 0; +} + +static int vibrance_slice16(AVFilterContext *avctx, void *arg, int jobnr, int nb_jobs) +{ + VibranceContext *s = avctx->priv; + AVFrame *frame = arg; + const int depth = s->depth; + const float max = (1 << depth) - 1; + const float scale = 1.f / max; + const float gc = s->lcoeffs[0]; + const float bc = s->lcoeffs[1]; + const float rc = s->lcoeffs[2]; + const int width = frame->width; + const int height = frame->height; + const float intensity = s->intensity; + const float alternate = s->alternate ? 1.f : -1.f; + const float gintensity = intensity * s->balance[0]; + const float bintensity = intensity * s->balance[1]; + const float rintensity = intensity * s->balance[2]; + const float sgintensity = alternate * FFSIGN(gintensity); + const float sbintensity = alternate * FFSIGN(bintensity); + const float srintensity = alternate * FFSIGN(rintensity); + const int slice_start = (height * jobnr) / nb_jobs; + const int slice_end = (height * (jobnr + 1)) / nb_jobs; + const int glinesize = frame->linesize[0] / 2; + const int blinesize = frame->linesize[1] / 2; + const int rlinesize = frame->linesize[2] / 2; + uint16_t *gptr = (uint16_t *)frame->data[0] + slice_start * glinesize; + uint16_t *bptr = (uint16_t *)frame->data[1] + slice_start * blinesize; + uint16_t *rptr = (uint16_t *)frame->data[2] + slice_start * rlinesize; + + for (int y = slice_start; y < slice_end; y++) { + for (int x = 0; x < width; x++) { + float g = gptr[x] * scale; + float b = bptr[x] * scale; + float r = rptr[x] * scale; + float max_color = FFMAX3(r, g, b); + float min_color = FFMIN3(r, g, b); + float color_saturation = max_color - min_color; + float luma = g * gc + r * rc + b * bc; + const float cg = 1.f + gintensity * (1.f - sgintensity * color_saturation); + const float cb = 1.f + bintensity * (1.f - sbintensity * color_saturation); + const float cr = 1.f + rintensity * (1.f - srintensity * color_saturation); + + g = lerpf(luma, g, cg); + b = lerpf(luma, b, cb); + r = lerpf(luma, r, cr); + + gptr[x] = av_clip_uintp2_c(g * max, depth); + bptr[x] = av_clip_uintp2_c(b * max, depth); + rptr[x] = av_clip_uintp2_c(r * max, depth); + } + + gptr += glinesize; + bptr += blinesize; + rptr += rlinesize; + } + + return 0; +} + +static int filter_frame(AVFilterLink *link, AVFrame *frame) +{ + AVFilterContext *avctx = link->dst; + VibranceContext *s = avctx->priv; + int res; + + if (res = avctx->internal->execute(avctx, s->do_slice, frame, NULL, + FFMIN(frame->height, ff_filter_get_nb_threads(avctx)))) + return res; + + return ff_filter_frame(avctx->outputs[0], frame); +} + +static av_cold int query_formats(AVFilterContext *avctx) +{ + static const enum AVPixelFormat pixel_fmts[] = { + AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRAP, + AV_PIX_FMT_GBRP9, AV_PIX_FMT_GBRP10, AV_PIX_FMT_GBRP12, + AV_PIX_FMT_GBRP14, AV_PIX_FMT_GBRP16, + AV_PIX_FMT_GBRAP10, AV_PIX_FMT_GBRAP12, AV_PIX_FMT_GBRAP16, + AV_PIX_FMT_NONE + }; + + AVFilterFormats *formats = NULL; + + formats = ff_make_format_list(pixel_fmts); + if (!formats) + return AVERROR(ENOMEM); + + return ff_set_common_formats(avctx, formats); +} + +static av_cold int config_input(AVFilterLink *inlink) +{ + AVFilterContext *avctx = inlink->dst; + VibranceContext *s = avctx->priv; + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format); + + s->depth = desc->comp[0].depth; + s->do_slice = s->depth <= 8 ? vibrance_slice8 : vibrance_slice16; + + return 0; +} + +static const AVFilterPad vibrance_inputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + .needs_writable = 1, + .filter_frame = filter_frame, + .config_props = config_input, + }, + { NULL } +}; + +static const AVFilterPad vibrance_outputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + }, + { NULL } +}; + +#define OFFSET(x) offsetof(VibranceContext, x) +#define VF AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM + +static const AVOption vibrance_options[] = { + { "intensity", "set the intensity value", OFFSET(intensity), AV_OPT_TYPE_FLOAT, {.dbl=0}, -2, 2, VF }, + { "rbal", "set the red balance value", OFFSET(balance[2]), AV_OPT_TYPE_FLOAT, {.dbl=1}, -10, 10, VF }, + { "gbal", "set the green balance value", OFFSET(balance[0]), AV_OPT_TYPE_FLOAT, {.dbl=1}, -10, 10, VF }, + { "bbal", "set the blue balance value", OFFSET(balance[1]), AV_OPT_TYPE_FLOAT, {.dbl=1}, -10, 10, VF }, + { "rlum", "set the red luma coefficient", OFFSET(lcoeffs[2]), AV_OPT_TYPE_FLOAT, {.dbl=0.072186}, 0, 1, VF }, + { "glum", "set the green luma coefficient", OFFSET(lcoeffs[0]), AV_OPT_TYPE_FLOAT, {.dbl=0.715158}, 0, 1, VF }, + { "blum", "set the blue luma coefficient", OFFSET(lcoeffs[1]), AV_OPT_TYPE_FLOAT, {.dbl=0.212656}, 0, 1, VF }, + { "alternate", "use alternate colors", OFFSET(alternate), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, VF }, + { NULL } +}; + +AVFILTER_DEFINE_CLASS(vibrance); + +AVFilter ff_vf_vibrance = { + .name = "vibrance", + .description = NULL_IF_CONFIG_SMALL("Boost or alter saturation."), + .priv_size = sizeof(VibranceContext), + .priv_class = &vibrance_class, + .query_formats = query_formats, + .inputs = vibrance_inputs, + .outputs = vibrance_outputs, + .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS, +}; diff --git a/libavfilter/vf_vmafmotion.c b/libavfilter/vf_vmafmotion.c index 9bcc4ff16..5c2a97453 100644 --- a/libavfilter/vf_vmafmotion.c +++ b/libavfilter/vf_vmafmotion.c @@ -27,7 +27,6 @@ #include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "avfilter.h" -#include "drawutils.h" #include "formats.h" #include "internal.h" #include "vmaf_motion.h" diff --git a/libavfilter/vf_vpp_qsv.c b/libavfilter/vf_vpp_qsv.c index 41a9f3896..915cf748c 100644 --- a/libavfilter/vf_vpp_qsv.c +++ b/libavfilter/vf_vpp_qsv.c @@ -57,6 +57,10 @@ typedef struct VPPContext{ int out_width; int out_height; + /** + * Output sw format. AV_PIX_FMT_NONE for no conversion. + */ + enum AVPixelFormat out_format; AVRational framerate; /* target framerate */ int use_frc; /* use framerate conversion */ @@ -79,6 +83,7 @@ typedef struct VPPContext{ char *cx, *cy, *cw, *ch; char *ow, *oh; + char *output_format_str; } VPPContext; static const AVOption options[] = { @@ -104,6 +109,8 @@ static const AVOption options[] = { { "width", "Output video width", OFFSET(ow), AV_OPT_TYPE_STRING, { .str="cw" }, 0, 255, .flags = FLAGS }, { "h", "Output video height", OFFSET(oh), AV_OPT_TYPE_STRING, { .str="w*ch/cw" }, 0, 255, .flags = FLAGS }, { "height", "Output video height", OFFSET(oh), AV_OPT_TYPE_STRING, { .str="w*ch/cw" }, 0, 255, .flags = FLAGS }, + { "format", "Output pixel format", OFFSET(output_format_str), AV_OPT_TYPE_STRING, { .str = "same" }, .flags = FLAGS }, + { NULL } }; @@ -207,6 +214,23 @@ release: return ret; } +static av_cold int vpp_init(AVFilterContext *ctx) +{ + VPPContext *vpp = ctx->priv; + + if (!strcmp(vpp->output_format_str, "same")) { + vpp->out_format = AV_PIX_FMT_NONE; + } else { + vpp->out_format = av_get_pix_fmt(vpp->output_format_str); + if (vpp->out_format == AV_PIX_FMT_NONE) { + av_log(ctx, AV_LOG_ERROR, "Unrecognized output pixel format: %s\n", vpp->output_format_str); + return AVERROR(EINVAL); + } + } + + return 0; +} + static int config_input(AVFilterLink *inlink) { AVFilterContext *ctx = inlink->dst; @@ -251,6 +275,7 @@ static int config_output(AVFilterLink *outlink) QSVVPPCrop crop = { 0 }; mfxExtBuffer *ext_buf[ENH_FILTERS_COUNT]; AVFilterLink *inlink = ctx->inputs[0]; + enum AVPixelFormat in_format; outlink->w = vpp->out_width; outlink->h = vpp->out_height; @@ -258,10 +283,19 @@ static int config_output(AVFilterLink *outlink) outlink->time_base = av_inv_q(vpp->framerate); param.filter_frame = NULL; - param.out_sw_format = AV_PIX_FMT_NV12; param.num_ext_buf = 0; param.ext_buf = ext_buf; + if (inlink->format == AV_PIX_FMT_QSV) { + if (!inlink->hw_frames_ctx || !inlink->hw_frames_ctx->data) + return AVERROR(EINVAL); + else + in_format = ((AVHWFramesContext*)inlink->hw_frames_ctx->data)->sw_format; + } else + in_format = inlink->format; + + param.out_sw_format = (vpp->out_format == AV_PIX_FMT_NONE) ? in_format : vpp->out_format; + if (vpp->use_crop) { crop.in_idx = 0; crop.x = vpp->crop_x; @@ -367,6 +401,7 @@ static int query_formats(AVFilterContext *ctx) }; static const enum AVPixelFormat out_pix_fmts[] = { AV_PIX_FMT_NV12, + AV_PIX_FMT_P010, AV_PIX_FMT_QSV, AV_PIX_FMT_NONE }; @@ -421,6 +456,7 @@ AVFilter ff_vf_vpp_qsv = { .description = NULL_IF_CONFIG_SMALL("Quick Sync Video VPP."), .priv_size = sizeof(VPPContext), .query_formats = query_formats, + .init = vpp_init, .uninit = vpp_uninit, .inputs = vpp_inputs, .outputs = vpp_outputs, diff --git a/libavfilter/vf_waveform.c b/libavfilter/vf_waveform.c index 428147c60..803362840 100644 --- a/libavfilter/vf_waveform.c +++ b/libavfilter/vf_waveform.c @@ -29,6 +29,14 @@ #include "internal.h" #include "video.h" +typedef struct ThreadData { + AVFrame *in; + AVFrame *out; + int component; + int offset_y; + int offset_x; +} ThreadData; + enum FilterType { LOWPASS, FLAT, @@ -94,11 +102,10 @@ typedef struct WaveformContext { int shift_w[4], shift_h[4]; GraticuleLines *glines; int nb_glines; - void (*waveform)(struct WaveformContext *s, - AVFrame *in, AVFrame *out, - int component, int intensity, - int offset_y, int offset_x, - int column, int mirror); + int rgb; + + int (*waveform_slice)(AVFilterContext *ctx, void *arg, + int jobnr, int nb_jobs); void (*graticulef)(struct WaveformContext *s, AVFrame *out); const AVPixFmtDescriptor *desc; const AVPixFmtDescriptor *odesc; @@ -644,7 +651,8 @@ static av_always_inline void lowpass16(WaveformContext *s, AVFrame *in, AVFrame *out, int component, int intensity, int offset_y, int offset_x, - int column, int mirror) + int column, int mirror, + int jobnr, int nb_jobs) { const int plane = s->desc->comp[component].plane; const int shift_w = s->shift_w[component]; @@ -656,22 +664,26 @@ static av_always_inline void lowpass16(WaveformContext *s, const int max = limit - intensity; const int src_h = AV_CEIL_RSHIFT(in->height, shift_h); const int src_w = AV_CEIL_RSHIFT(in->width, shift_w); - const uint16_t *src_data = (const uint16_t *)in->data[plane]; - uint16_t *dst_data = (uint16_t *)out->data[plane] + offset_y * dst_linesize + offset_x; + const int sliceh_start = !column ? (src_h * jobnr) / nb_jobs : 0; + const int sliceh_end = !column ? (src_h * (jobnr+1)) / nb_jobs : src_h; + const int slicew_start = column ? (src_w * jobnr) / nb_jobs : 0; + const int slicew_end = column ? (src_w * (jobnr+1)) / nb_jobs : src_w; + const int step = column ? 1 << shift_w : 1 << shift_h; + const uint16_t *src_data = (const uint16_t *)in->data[plane] + sliceh_start * src_linesize; + uint16_t *dst_data = (uint16_t *)out->data[plane] + (offset_y + sliceh_start * step) * dst_linesize + offset_x; uint16_t * const dst_bottom_line = dst_data + dst_linesize * (s->size - 1); uint16_t * const dst_line = (mirror ? dst_bottom_line : dst_data); - const int step = column ? 1 << shift_w : 1 << shift_h; const uint16_t *p; int y; if (!column && mirror) dst_data += s->size; - for (y = 0; y < src_h; y++) { - const uint16_t *src_data_end = src_data + src_w; - uint16_t *dst = dst_line; + for (y = sliceh_start; y < sliceh_end; y++) { + const uint16_t *src_data_end = src_data + slicew_end; + uint16_t *dst = dst_line + slicew_start * step; - for (p = src_data; p < src_data_end; p++) { + for (p = src_data + slicew_start; p < src_data_end; p++) { uint16_t *target; int i = 0, v = FFMIN(*p, limit); @@ -695,19 +707,26 @@ static av_always_inline void lowpass16(WaveformContext *s, src_data += src_linesize; dst_data += dst_linesize * step; } - - envelope16(s, out, plane, plane, column ? offset_x : offset_y); } -#define LOWPASS16_FUNC(name, column, mirror) \ -static void lowpass16_##name(WaveformContext *s, \ - AVFrame *in, AVFrame *out, \ - int component, int intensity, \ - int offset_y, int offset_x, \ - int unused1, int unused2) \ -{ \ - lowpass16(s, in, out, component, intensity, \ - offset_y, offset_x, column, mirror); \ +#define LOWPASS16_FUNC(name, column, mirror) \ +static int lowpass16_##name(AVFilterContext *ctx, \ + void *arg, int jobnr, \ + int nb_jobs) \ +{ \ + WaveformContext *s = ctx->priv; \ + ThreadData *td = arg; \ + AVFrame *in = td->in; \ + AVFrame *out = td->out; \ + int component = td->component; \ + int offset_y = td->offset_y; \ + int offset_x = td->offset_x; \ + \ + lowpass16(s, in, out, component, s->intensity, \ + offset_y, offset_x, column, mirror, \ + jobnr, nb_jobs); \ + \ + return 0; \ } LOWPASS16_FUNC(column_mirror, 1, 1) @@ -719,7 +738,8 @@ static av_always_inline void lowpass(WaveformContext *s, AVFrame *in, AVFrame *out, int component, int intensity, int offset_y, int offset_x, - int column, int mirror) + int column, int mirror, + int jobnr, int nb_jobs) { const int plane = s->desc->comp[component].plane; const int shift_w = s->shift_w[component]; @@ -730,22 +750,26 @@ static av_always_inline void lowpass(WaveformContext *s, const int max = 255 - intensity; const int src_h = AV_CEIL_RSHIFT(in->height, shift_h); const int src_w = AV_CEIL_RSHIFT(in->width, shift_w); - const uint8_t *src_data = in->data[plane]; - uint8_t *dst_data = out->data[plane] + offset_y * dst_linesize + offset_x; + const int sliceh_start = !column ? (src_h * jobnr) / nb_jobs : 0; + const int sliceh_end = !column ? (src_h * (jobnr+1)) / nb_jobs : src_h; + const int slicew_start = column ? (src_w * jobnr) / nb_jobs : 0; + const int slicew_end = column ? (src_w * (jobnr+1)) / nb_jobs : src_w; + const int step = column ? 1 << shift_w : 1 << shift_h; + const uint8_t *src_data = in->data[plane] + sliceh_start * src_linesize; + uint8_t *dst_data = out->data[plane] + (offset_y + sliceh_start * step) * dst_linesize + offset_x; uint8_t * const dst_bottom_line = dst_data + dst_linesize * (s->size - 1); uint8_t * const dst_line = (mirror ? dst_bottom_line : dst_data); - const int step = column ? 1 << shift_w : 1 << shift_h; const uint8_t *p; int y; if (!column && mirror) dst_data += s->size; - for (y = 0; y < src_h; y++) { - const uint8_t *src_data_end = src_data + src_w; - uint8_t *dst = dst_line; + for (y = sliceh_start; y < sliceh_end; y++) { + const uint8_t *src_data_end = src_data + slicew_end; + uint8_t *dst = dst_line + slicew_start * step; - for (p = src_data; p < src_data_end; p++) { + for (p = src_data + slicew_start; p < src_data_end; p++) { uint8_t *target; if (column) { target = dst + dst_signed_linesize * *p; @@ -766,14 +790,13 @@ static av_always_inline void lowpass(WaveformContext *s, } if (column && step > 1) { - const int dst_w = s->display == PARADE ? out->width / s->acomp : out->width; const int dst_h = 256; uint8_t *dst; int x, z; dst = out->data[plane] + offset_y * dst_linesize + offset_x; for (y = 0; y < dst_h; y++) { - for (x = 0; x < dst_w; x+=step) { + for (x = slicew_start * step; x < slicew_end * step; x+=step) { for (z = 1; z < step; z++) { dst[x + z] = dst[x]; } @@ -781,31 +804,37 @@ static av_always_inline void lowpass(WaveformContext *s, dst += dst_linesize; } } else if (step > 1) { - const int dst_h = s->display == PARADE ? out->height / s->acomp : out->height; const int dst_w = 256; uint8_t *dst; int z; - dst = out->data[plane] + offset_y * dst_linesize + offset_x; - for (y = 0; y < dst_h; y+=step) { + dst = out->data[plane] + (offset_y + sliceh_start * step) * dst_linesize + offset_x; + for (y = sliceh_start * step; y < sliceh_end * step; y+=step) { for (z = 1; z < step; z++) memcpy(dst + dst_linesize * z, dst, dst_w); dst += dst_linesize * step; } } - - envelope(s, out, plane, plane, column ? offset_x : offset_y); } -#define LOWPASS_FUNC(name, column, mirror) \ -static void lowpass_##name(WaveformContext *s, \ - AVFrame *in, AVFrame *out, \ - int component, int intensity, \ - int offset_y, int offset_x, \ - int unused1, int unused2) \ -{ \ - lowpass(s, in, out, component, intensity, \ - offset_y, offset_x, column, mirror); \ +#define LOWPASS_FUNC(name, column, mirror) \ +static int lowpass_##name(AVFilterContext *ctx, \ + void *arg, int jobnr, \ + int nb_jobs) \ +{ \ + WaveformContext *s = ctx->priv; \ + ThreadData *td = arg; \ + AVFrame *in = td->in; \ + AVFrame *out = td->out; \ + int component = td->component; \ + int offset_y = td->offset_y; \ + int offset_x = td->offset_x; \ + \ + lowpass(s, in, out, component, s->intensity, \ + offset_y, offset_x, column, mirror, \ + jobnr, nb_jobs); \ + \ + return 0; \ } LOWPASS_FUNC(column_mirror, 1, 1) @@ -817,7 +846,8 @@ static av_always_inline void flat16(WaveformContext *s, AVFrame *in, AVFrame *out, int component, int intensity, int offset_y, int offset_x, - int column, int mirror) + int column, int mirror, + int jobnr, int nb_jobs) { const int plane = s->desc->comp[component].plane; const int c0_linesize = in->linesize[ plane + 0 ] / 2; @@ -836,13 +866,17 @@ static av_always_inline void flat16(WaveformContext *s, const int mid = s->max / 2; const int src_h = in->height; const int src_w = in->width; + const int sliceh_start = !column ? (src_h * jobnr) / nb_jobs : 0; + const int sliceh_end = !column ? (src_h * (jobnr+1)) / nb_jobs : src_h; + const int slicew_start = column ? (src_w * jobnr) / nb_jobs : 0; + const int slicew_end = column ? (src_w * (jobnr+1)) / nb_jobs : src_w; int x, y; if (column) { const int d0_signed_linesize = d0_linesize * (mirror == 1 ? -1 : 1); const int d1_signed_linesize = d1_linesize * (mirror == 1 ? -1 : 1); - for (x = 0; x < src_w; x++) { + for (x = slicew_start; x < slicew_end; x++) { const uint16_t *c0_data = (uint16_t *)in->data[plane + 0]; const uint16_t *c1_data = (uint16_t *)in->data[(plane + 1) % s->ncomp]; const uint16_t *c2_data = (uint16_t *)in->data[(plane + 2) % s->ncomp]; @@ -876,18 +910,18 @@ static av_always_inline void flat16(WaveformContext *s, } } } else { - const uint16_t *c0_data = (uint16_t *)in->data[plane]; - const uint16_t *c1_data = (uint16_t *)in->data[(plane + 1) % s->ncomp]; - const uint16_t *c2_data = (uint16_t *)in->data[(plane + 2) % s->ncomp]; - uint16_t *d0_data = (uint16_t *)(out->data[plane]) + offset_y * d0_linesize + offset_x; - uint16_t *d1_data = (uint16_t *)(out->data[(plane + 1) % s->ncomp]) + offset_y * d1_linesize + offset_x; + const uint16_t *c0_data = (uint16_t *)(in->data[plane]) + (sliceh_start >> c0_shift_h) * c0_linesize; + const uint16_t *c1_data = (uint16_t *)(in->data[(plane + 1) % s->ncomp]) + (sliceh_start >> c1_shift_h) * c1_linesize; + const uint16_t *c2_data = (uint16_t *)(in->data[(plane + 2) % s->ncomp]) + (sliceh_start >> c2_shift_h) * c2_linesize; + uint16_t *d0_data = (uint16_t *)(out->data[plane]) + (offset_y + sliceh_start) * d0_linesize + offset_x; + uint16_t *d1_data = (uint16_t *)(out->data[(plane + 1) % s->ncomp]) + (offset_y + sliceh_start) * d1_linesize + offset_x; if (mirror) { d0_data += s->size - 1; d1_data += s->size - 1; } - for (y = 0; y < src_h; y++) { + for (y = sliceh_start; y < sliceh_end; y++) { for (x = 0; x < src_w; x++) { const int c0 = FFMIN(c0_data[x >> c0_shift_w], limit) + s->max; const int c1 = FFMIN(FFABS(c1_data[x >> c1_shift_w] - mid) + FFABS(c2_data[x >> c2_shift_w] - mid), limit); @@ -920,16 +954,39 @@ static av_always_inline void flat16(WaveformContext *s, d1_data += d1_linesize; } } - - envelope16(s, out, plane, plane, column ? offset_x : offset_y); - envelope16(s, out, plane, (plane + 1) % s->ncomp, column ? offset_x : offset_y); } +#define FLAT16_FUNC(name, column, mirror) \ +static int flat16_##name(AVFilterContext *ctx, \ + void *arg, int jobnr, \ + int nb_jobs) \ +{ \ + WaveformContext *s = ctx->priv; \ + ThreadData *td = arg; \ + AVFrame *in = td->in; \ + AVFrame *out = td->out; \ + int component = td->component; \ + int offset_y = td->offset_y; \ + int offset_x = td->offset_x; \ + \ + flat16(s, in, out, component, s->intensity, \ + offset_y, offset_x, column, mirror, \ + jobnr, nb_jobs); \ + \ + return 0; \ +} + +FLAT16_FUNC(column_mirror, 1, 1) +FLAT16_FUNC(column, 1, 0) +FLAT16_FUNC(row_mirror, 0, 1) +FLAT16_FUNC(row, 0, 0) + static av_always_inline void flat(WaveformContext *s, AVFrame *in, AVFrame *out, int component, int intensity, int offset_y, int offset_x, - int column, int mirror) + int column, int mirror, + int jobnr, int nb_jobs) { const int plane = s->desc->comp[component].plane; const int c0_linesize = in->linesize[ plane + 0 ]; @@ -946,13 +1003,17 @@ static av_always_inline void flat(WaveformContext *s, const int max = 255 - intensity; const int src_h = in->height; const int src_w = in->width; + const int sliceh_start = !column ? (src_h * jobnr) / nb_jobs : 0; + const int sliceh_end = !column ? (src_h * (jobnr+1)) / nb_jobs : src_h; + const int slicew_start = column ? (src_w * jobnr) / nb_jobs : 0; + const int slicew_end = column ? (src_w * (jobnr+1)) / nb_jobs : src_w; int x, y; if (column) { const int d0_signed_linesize = d0_linesize * (mirror == 1 ? -1 : 1); const int d1_signed_linesize = d1_linesize * (mirror == 1 ? -1 : 1); - for (x = 0; x < src_w; x++) { + for (x = slicew_start; x < slicew_end; x++) { const uint8_t *c0_data = in->data[plane + 0]; const uint8_t *c1_data = in->data[(plane + 1) % s->ncomp]; const uint8_t *c2_data = in->data[(plane + 2) % s->ncomp]; @@ -986,20 +1047,20 @@ static av_always_inline void flat(WaveformContext *s, } } } else { - const uint8_t *c0_data = in->data[plane]; - const uint8_t *c1_data = in->data[(plane + 1) % s->ncomp]; - const uint8_t *c2_data = in->data[(plane + 2) % s->ncomp]; - uint8_t *d0_data = out->data[plane] + offset_y * d0_linesize + offset_x; - uint8_t *d1_data = out->data[(plane + 1) % s->ncomp] + offset_y * d1_linesize + offset_x; + const uint8_t *c0_data = in->data[plane] + (sliceh_start >> c0_shift_h) * c0_linesize; + const uint8_t *c1_data = in->data[(plane + 1) % s->ncomp] + (sliceh_start >> c1_shift_h) * c1_linesize; + const uint8_t *c2_data = in->data[(plane + 2) % s->ncomp] + (sliceh_start >> c2_shift_h) * c2_linesize; + uint8_t *d0_data = out->data[plane] + (offset_y + sliceh_start) * d0_linesize + offset_x; + uint8_t *d1_data = out->data[(plane + 1) % s->ncomp] + (offset_y + sliceh_start) * d1_linesize + offset_x; if (mirror) { d0_data += s->size - 1; d1_data += s->size - 1; } - for (y = 0; y < src_h; y++) { + for (y = sliceh_start; y < sliceh_end; y++) { for (x = 0; x < src_w; x++) { - int c0 = c0_data[x >> c0_shift_w] + 256; + const int c0 = c0_data[x >> c0_shift_w] + 256; const int c1 = FFABS(c1_data[x >> c1_shift_w] - 128) + FFABS(c2_data[x >> c2_shift_w] - 128); uint8_t *target; @@ -1030,18 +1091,46 @@ static av_always_inline void flat(WaveformContext *s, d1_data += d1_linesize; } } - - envelope(s, out, plane, plane, column ? offset_x : offset_y); - envelope(s, out, plane, (plane + 1) % s->ncomp, column ? offset_x : offset_y); } +#define FLAT_FUNC(name, column, mirror) \ +static int flat_##name(AVFilterContext *ctx, \ + void *arg, int jobnr, \ + int nb_jobs) \ +{ \ + WaveformContext *s = ctx->priv; \ + ThreadData *td = arg; \ + AVFrame *in = td->in; \ + AVFrame *out = td->out; \ + int component = td->component; \ + int offset_y = td->offset_y; \ + int offset_x = td->offset_x; \ + \ + flat(s, in, out, component, s->intensity, \ + offset_y, offset_x, column, mirror, \ + jobnr, nb_jobs); \ + \ + return 0; \ +} + +FLAT_FUNC(column_mirror, 1, 1) +FLAT_FUNC(column, 1, 0) +FLAT_FUNC(row_mirror, 0, 1) +FLAT_FUNC(row, 0, 0) + #define AFLAT16(name, update_cr, column, mirror) \ -static av_always_inline void name (WaveformContext *s, \ - AVFrame *in, AVFrame *out, \ - int component, int intensity, \ - int offset_y, int offset_x, \ - int unused1, int unused2) \ +static int name(AVFilterContext *ctx, \ + void *arg, int jobnr, \ + int nb_jobs) \ { \ + WaveformContext *s = ctx->priv; \ + ThreadData *td = arg; \ + AVFrame *in = td->in; \ + AVFrame *out = td->out; \ + int component = td->component; \ + int offset_y = td->offset_y; \ + int offset_x = td->offset_x; \ + const int intensity = s->intensity; \ const int plane = s->desc->comp[component].plane; \ const int c0_linesize = in->linesize[ plane + 0 ] / 2; \ const int c1_linesize = in->linesize[(plane + 1) % s->ncomp] / 2; \ @@ -1060,6 +1149,10 @@ static av_always_inline void name (WaveformContext *s, const int mid = s->max / 2; \ const int src_h = in->height; \ const int src_w = in->width; \ + const int sliceh_start = !column ? (src_h * jobnr) / nb_jobs : 0; \ + const int sliceh_end = !column ? (src_h * (jobnr+1)) / nb_jobs : src_h; \ + const int slicew_start = column ? (src_w * jobnr) / nb_jobs : 0; \ + const int slicew_end = column ? (src_w * (jobnr+1)) / nb_jobs : src_w; \ int x, y; \ \ if (column) { \ @@ -1067,7 +1160,7 @@ static av_always_inline void name (WaveformContext *s, const int d1_signed_linesize = d1_linesize * (mirror == 1 ? -1 : 1); \ const int d2_signed_linesize = d2_linesize * (mirror == 1 ? -1 : 1); \ \ - for (x = 0; x < src_w; x++) { \ + for (x = slicew_start; x < slicew_end; x++) { \ const uint16_t *c0_data = (uint16_t *)in->data[plane + 0]; \ const uint16_t *c1_data = (uint16_t *)in->data[(plane + 1) % s->ncomp]; \ const uint16_t *c2_data = (uint16_t *)in->data[(plane + 2) % s->ncomp]; \ @@ -1108,12 +1201,12 @@ static av_always_inline void name (WaveformContext *s, } \ } \ } else { \ - const uint16_t *c0_data = (uint16_t *)in->data[plane]; \ - const uint16_t *c1_data = (uint16_t *)in->data[(plane + 1) % s->ncomp]; \ - const uint16_t *c2_data = (uint16_t *)in->data[(plane + 2) % s->ncomp]; \ - uint16_t *d0_data = (uint16_t *)out->data[plane] + offset_y * d0_linesize + offset_x; \ - uint16_t *d1_data = (uint16_t *)out->data[(plane + 1) % s->ncomp] + offset_y * d1_linesize + offset_x; \ - uint16_t *d2_data = (uint16_t *)out->data[(plane + 2) % s->ncomp] + offset_y * d2_linesize + offset_x; \ + const uint16_t *c0_data = (uint16_t *)in->data[plane] + (sliceh_start >> c0_shift_h) * c0_linesize; \ + const uint16_t *c1_data = (uint16_t *)in->data[(plane + 1) % s->ncomp] + (sliceh_start >> c1_shift_h) * c1_linesize; \ + const uint16_t *c2_data = (uint16_t *)in->data[(plane + 2) % s->ncomp] + (sliceh_start >> c2_shift_h) * c2_linesize; \ + uint16_t *d0_data = (uint16_t *)out->data[plane] + (offset_y + sliceh_start) * d0_linesize + offset_x; \ + uint16_t *d1_data = (uint16_t *)out->data[(plane + 1) % s->ncomp] + (offset_y + sliceh_start) * d1_linesize + offset_x; \ + uint16_t *d2_data = (uint16_t *)out->data[(plane + 2) % s->ncomp] + (offset_y + sliceh_start) * d2_linesize + offset_x; \ \ if (mirror) { \ d0_data += s->size - 1; \ @@ -1121,7 +1214,7 @@ static av_always_inline void name (WaveformContext *s, d2_data += s->size - 1; \ } \ \ - for (y = 0; y < src_h; y++) { \ + for (y = sliceh_start; y < sliceh_end; y++) { \ for (x = 0; x < src_w; x++) { \ const int c0 = FFMIN(c0_data[x >> c0_shift_w], limit) + mid; \ const int c1 = FFMIN(c1_data[x >> c1_shift_w], limit) - mid; \ @@ -1156,19 +1249,28 @@ static av_always_inline void name (WaveformContext *s, d2_data += d2_linesize; \ } \ } \ - \ - envelope16(s, out, plane, (plane + 0) % s->ncomp, column ? offset_x : offset_y); \ - envelope16(s, out, plane, (plane + 1) % s->ncomp, column ? offset_x : offset_y); \ - envelope16(s, out, plane, (plane + 2) % s->ncomp, column ? offset_x : offset_y); \ + return 0; \ } #define AFLAT(name, update_cr, column, mirror) \ -static av_always_inline void name(WaveformContext *s, \ - AVFrame *in, AVFrame *out, \ - int component, int intensity, \ - int offset_y, int offset_x, \ - int unused1, int unused2) \ +static int name(AVFilterContext *ctx, \ + void *arg, int jobnr, \ + int nb_jobs) \ { \ + WaveformContext *s = ctx->priv; \ + ThreadData *td = arg; \ + AVFrame *in = td->in; \ + AVFrame *out = td->out; \ + int component = td->component; \ + int offset_y = td->offset_y; \ + int offset_x = td->offset_x; \ + const int src_h = in->height; \ + const int src_w = in->width; \ + const int sliceh_start = !column ? (src_h * jobnr) / nb_jobs : 0; \ + const int sliceh_end = !column ? (src_h * (jobnr+1)) / nb_jobs : src_h; \ + const int slicew_start = column ? (src_w * jobnr) / nb_jobs : 0; \ + const int slicew_end = column ? (src_w * (jobnr+1)) / nb_jobs : src_w; \ + const int intensity = s->intensity; \ const int plane = s->desc->comp[component].plane; \ const int c0_linesize = in->linesize[ plane + 0 ]; \ const int c1_linesize = in->linesize[(plane + 1) % s->ncomp]; \ @@ -1183,8 +1285,6 @@ static av_always_inline void name(WaveformContext *s, const int d1_linesize = out->linesize[(plane + 1) % s->ncomp]; \ const int d2_linesize = out->linesize[(plane + 2) % s->ncomp]; \ const int max = 255 - intensity; \ - const int src_h = in->height; \ - const int src_w = in->width; \ int x, y; \ \ if (column) { \ @@ -1192,7 +1292,7 @@ static av_always_inline void name(WaveformContext *s, const int d1_signed_linesize = d1_linesize * (mirror == 1 ? -1 : 1); \ const int d2_signed_linesize = d2_linesize * (mirror == 1 ? -1 : 1); \ \ - for (x = 0; x < src_w; x++) { \ + for (x = slicew_start; x < slicew_end; x++) { \ const uint8_t *c0_data = in->data[plane + 0]; \ const uint8_t *c1_data = in->data[(plane + 1) % s->ncomp]; \ const uint8_t *c2_data = in->data[(plane + 2) % s->ncomp]; \ @@ -1233,12 +1333,12 @@ static av_always_inline void name(WaveformContext *s, } \ } \ } else { \ - const uint8_t *c0_data = in->data[plane]; \ - const uint8_t *c1_data = in->data[(plane + 1) % s->ncomp]; \ - const uint8_t *c2_data = in->data[(plane + 2) % s->ncomp]; \ - uint8_t *d0_data = out->data[plane] + offset_y * d0_linesize + offset_x; \ - uint8_t *d1_data = out->data[(plane + 1) % s->ncomp] + offset_y * d1_linesize + offset_x; \ - uint8_t *d2_data = out->data[(plane + 2) % s->ncomp] + offset_y * d2_linesize + offset_x; \ + const uint8_t *c0_data = in->data[plane] + (sliceh_start >> c0_shift_h) * c0_linesize; \ + const uint8_t *c1_data = in->data[(plane + 1) % s->ncomp] + (sliceh_start >> c1_shift_h) * c1_linesize; \ + const uint8_t *c2_data = in->data[(plane + 2) % s->ncomp] + (sliceh_start >> c2_shift_h) * c2_linesize; \ + uint8_t *d0_data = out->data[plane] + (offset_y + sliceh_start) * d0_linesize + offset_x; \ + uint8_t *d1_data = out->data[(plane + 1) % s->ncomp] + (offset_y + sliceh_start) * d1_linesize + offset_x; \ + uint8_t *d2_data = out->data[(plane + 2) % s->ncomp] + (offset_y + sliceh_start) * d2_linesize + offset_x; \ \ if (mirror) { \ d0_data += s->size - 1; \ @@ -1246,7 +1346,7 @@ static av_always_inline void name(WaveformContext *s, d2_data += s->size - 1; \ } \ \ - for (y = 0; y < src_h; y++) { \ + for (y = sliceh_start; y < sliceh_end; y++) { \ for (x = 0; x < src_w; x++) { \ const int c0 = c0_data[x >> c0_shift_w] + 128; \ const int c1 = c1_data[x >> c1_shift_w] - 128; \ @@ -1281,10 +1381,7 @@ static av_always_inline void name(WaveformContext *s, d2_data += d2_linesize; \ } \ } \ - \ - envelope(s, out, plane, (plane + 0) % s->ncomp, column ? offset_x : offset_y); \ - envelope(s, out, plane, (plane + 1) % s->ncomp, column ? offset_x : offset_y); \ - envelope(s, out, plane, (plane + 2) % s->ncomp, column ? offset_x : offset_y); \ + return 0; \ } AFLAT16(aflat16_row, update16, 0, 0) @@ -1309,7 +1406,8 @@ static av_always_inline void chroma16(WaveformContext *s, AVFrame *in, AVFrame *out, int component, int intensity, int offset_y, int offset_x, - int column, int mirror) + int column, int mirror, + int jobnr, int nb_jobs) { const int plane = s->desc->comp[component].plane; const int c0_linesize = in->linesize[(plane + 1) % s->ncomp] / 2; @@ -1324,12 +1422,16 @@ static av_always_inline void chroma16(WaveformContext *s, const int c1_shift_h = s->shift_h[(component + 2) % s->ncomp]; const int src_h = in->height; const int src_w = in->width; + const int sliceh_start = !column ? (src_h * jobnr) / nb_jobs : 0; + const int sliceh_end = !column ? (src_h * (jobnr+1)) / nb_jobs : src_h; + const int slicew_start = column ? (src_w * jobnr) / nb_jobs : 0; + const int slicew_end = column ? (src_w * (jobnr+1)) / nb_jobs : src_w; int x, y; if (column) { const int dst_signed_linesize = dst_linesize * (mirror == 1 ? -1 : 1); - for (x = 0; x < src_w; x++) { + for (x = slicew_start; x < slicew_end; x++) { const uint16_t *c0_data = (uint16_t *)in->data[(plane + 1) % s->ncomp]; const uint16_t *c1_data = (uint16_t *)in->data[(plane + 2) % s->ncomp]; uint16_t *dst_data = (uint16_t *)out->data[plane] + offset_y * dst_linesize + offset_x; @@ -1352,13 +1454,13 @@ static av_always_inline void chroma16(WaveformContext *s, } } } else { - const uint16_t *c0_data = (uint16_t *)in->data[(plane + 1) % s->ncomp]; - const uint16_t *c1_data = (uint16_t *)in->data[(plane + 2) % s->ncomp]; - uint16_t *dst_data = (uint16_t *)out->data[plane] + offset_y * dst_linesize + offset_x; + const uint16_t *c0_data = (uint16_t *)in->data[(plane + 1) % s->ncomp] + (sliceh_start >> c0_shift_h) * c0_linesize; + const uint16_t *c1_data = (uint16_t *)in->data[(plane + 2) % s->ncomp] + (sliceh_start >> c1_shift_h) * c1_linesize; + uint16_t *dst_data = (uint16_t *)out->data[plane] + (offset_y + sliceh_start) * dst_linesize + offset_x; if (mirror) dst_data += s->size - 1; - for (y = 0; y < src_h; y++) { + for (y = sliceh_start; y < sliceh_end; y++) { for (x = 0; x < src_w; x++) { const int sum = FFMIN(FFABS(c0_data[x >> c0_shift_w] - mid) + FFABS(c1_data[x >> c1_shift_w] - mid - 1), limit); uint16_t *target; @@ -1379,17 +1481,47 @@ static av_always_inline void chroma16(WaveformContext *s, dst_data += dst_linesize; } } - - envelope16(s, out, plane, plane, column ? offset_x : offset_y); } +#define CHROMA16_FUNC(name, column, mirror) \ +static int chroma16_##name(AVFilterContext *ctx, \ + void *arg, int jobnr, \ + int nb_jobs) \ +{ \ + WaveformContext *s = ctx->priv; \ + ThreadData *td = arg; \ + AVFrame *in = td->in; \ + AVFrame *out = td->out; \ + int component = td->component; \ + int offset_y = td->offset_y; \ + int offset_x = td->offset_x; \ + \ + chroma16(s, in, out, component, s->intensity,\ + offset_y, offset_x, column, mirror, \ + jobnr, nb_jobs); \ + \ + return 0; \ +} + +CHROMA16_FUNC(column_mirror, 1, 1) +CHROMA16_FUNC(column, 1, 0) +CHROMA16_FUNC(row_mirror, 0, 1) +CHROMA16_FUNC(row, 0, 0) + static av_always_inline void chroma(WaveformContext *s, AVFrame *in, AVFrame *out, int component, int intensity, int offset_y, int offset_x, - int column, int mirror) + int column, int mirror, + int jobnr, int nb_jobs) { const int plane = s->desc->comp[component].plane; + const int src_h = in->height; + const int src_w = in->width; + const int sliceh_start = !column ? (src_h * jobnr) / nb_jobs : 0; + const int sliceh_end = !column ? (src_h * (jobnr+1)) / nb_jobs : src_h; + const int slicew_start = column ? (src_w * jobnr) / nb_jobs : 0; + const int slicew_end = column ? (src_w * (jobnr+1)) / nb_jobs : src_w; const int c0_linesize = in->linesize[(plane + 1) % s->ncomp]; const int c1_linesize = in->linesize[(plane + 2) % s->ncomp]; const int dst_linesize = out->linesize[plane]; @@ -1398,14 +1530,12 @@ static av_always_inline void chroma(WaveformContext *s, const int c1_shift_w = s->shift_w[(component + 2) % s->ncomp]; const int c0_shift_h = s->shift_h[(component + 1) % s->ncomp]; const int c1_shift_h = s->shift_h[(component + 2) % s->ncomp]; - const int src_h = in->height; - const int src_w = in->width; int x, y; if (column) { const int dst_signed_linesize = dst_linesize * (mirror == 1 ? -1 : 1); - for (x = 0; x < src_w; x++) { + for (x = slicew_start; x < slicew_end; x++) { const uint8_t *c0_data = in->data[(plane + 1) % s->ncomp]; const uint8_t *c1_data = in->data[(plane + 2) % s->ncomp]; uint8_t *dst_data = out->data[plane] + offset_y * dst_linesize + offset_x; @@ -1428,13 +1558,13 @@ static av_always_inline void chroma(WaveformContext *s, } } } else { - const uint8_t *c0_data = in->data[(plane + 1) % s->ncomp]; - const uint8_t *c1_data = in->data[(plane + 2) % s->ncomp]; - uint8_t *dst_data = out->data[plane] + offset_y * dst_linesize + offset_x; + const uint8_t *c0_data = in->data[(plane + 1) % s->ncomp] + (sliceh_start >> c0_shift_h) * c0_linesize; + const uint8_t *c1_data = in->data[(plane + 2) % s->ncomp] + (sliceh_start >> c1_shift_h) * c1_linesize; + uint8_t *dst_data = out->data[plane] + (offset_y + sliceh_start) * dst_linesize + offset_x; if (mirror) dst_data += s->size - 1; - for (y = 0; y < src_h; y++) { + for (y = sliceh_start; y < sliceh_end; y++) { for (x = 0; x < src_w; x++) { const int sum = FFABS(c0_data[x >> c0_shift_w] - 128) + FFABS(c1_data[x >> c1_shift_w] - 127); uint8_t *target; @@ -1455,35 +1585,63 @@ static av_always_inline void chroma(WaveformContext *s, dst_data += dst_linesize; } } - - envelope(s, out, plane, plane, column ? offset_x : offset_y); } +#define CHROMA_FUNC(name, column, mirror) \ +static int chroma_##name(AVFilterContext *ctx, \ + void *arg, int jobnr, \ + int nb_jobs) \ +{ \ + WaveformContext *s = ctx->priv; \ + ThreadData *td = arg; \ + AVFrame *in = td->in; \ + AVFrame *out = td->out; \ + int component = td->component; \ + int offset_y = td->offset_y; \ + int offset_x = td->offset_x; \ + \ + chroma(s, in, out, component, s->intensity, \ + offset_y, offset_x, column, mirror, \ + jobnr, nb_jobs); \ + \ + return 0; \ +} + +CHROMA_FUNC(column_mirror, 1, 1) +CHROMA_FUNC(column, 1, 0) +CHROMA_FUNC(row_mirror, 0, 1) +CHROMA_FUNC(row, 0, 0) + static av_always_inline void color16(WaveformContext *s, AVFrame *in, AVFrame *out, int component, int intensity, int offset_y, int offset_x, - int column, int mirror) + int column, int mirror, + int jobnr, int nb_jobs) { const int plane = s->desc->comp[component].plane; const int limit = s->max - 1; - const uint16_t *c0_data = (const uint16_t *)in->data[plane + 0]; - const uint16_t *c1_data = (const uint16_t *)in->data[(plane + 1) % s->ncomp]; - const uint16_t *c2_data = (const uint16_t *)in->data[(plane + 2) % s->ncomp]; + const int src_h = in->height; + const int src_w = in->width; + const int sliceh_start = !column ? (src_h * jobnr) / nb_jobs : 0; + const int sliceh_end = !column ? (src_h * (jobnr+1)) / nb_jobs : src_h; + const int slicew_start = column ? (src_w * jobnr) / nb_jobs : 0; + const int slicew_end = column ? (src_w * (jobnr+1)) / nb_jobs : src_w; const int c0_linesize = in->linesize[ plane + 0 ] / 2; const int c1_linesize = in->linesize[(plane + 1) % s->ncomp] / 2; const int c2_linesize = in->linesize[(plane + 2) % s->ncomp] / 2; + const int c0_shift_h = s->shift_h[ component + 0 ]; + const int c1_shift_h = s->shift_h[(component + 1) % s->ncomp]; + const int c2_shift_h = s->shift_h[(component + 2) % s->ncomp]; + const uint16_t *c0_data = (const uint16_t *)in->data[plane + 0] + (sliceh_start >> c0_shift_h) * c0_linesize; + const uint16_t *c1_data = (const uint16_t *)in->data[(plane + 1) % s->ncomp] + (sliceh_start >> c1_shift_h) * c1_linesize; + const uint16_t *c2_data = (const uint16_t *)in->data[(plane + 2) % s->ncomp] + (sliceh_start >> c2_shift_h) * c2_linesize; const int d0_linesize = out->linesize[ plane + 0 ] / 2; const int d1_linesize = out->linesize[(plane + 1) % s->ncomp] / 2; const int d2_linesize = out->linesize[(plane + 2) % s->ncomp] / 2; const int c0_shift_w = s->shift_w[ component + 0 ]; const int c1_shift_w = s->shift_w[(component + 1) % s->ncomp]; const int c2_shift_w = s->shift_w[(component + 2) % s->ncomp]; - const int c0_shift_h = s->shift_h[ component + 0 ]; - const int c1_shift_h = s->shift_h[(component + 1) % s->ncomp]; - const int c2_shift_h = s->shift_h[(component + 2) % s->ncomp]; - const int src_h = in->height; - const int src_w = in->width; int x, y; if (column) { @@ -1501,7 +1659,7 @@ static av_always_inline void color16(WaveformContext *s, uint16_t * const d2 = (mirror ? d2_bottom_line : d2_data); for (y = 0; y < src_h; y++) { - for (x = 0; x < src_w; x++) { + for (x = slicew_start; x < slicew_end; x++) { const int c0 = FFMIN(c0_data[x >> c0_shift_w], limit); const int c1 = c1_data[x >> c1_shift_w]; const int c2 = c2_data[x >> c2_shift_w]; @@ -1522,9 +1680,9 @@ static av_always_inline void color16(WaveformContext *s, d2_data += d2_linesize; } } else { - uint16_t *d0_data = (uint16_t *)out->data[plane] + offset_y * d0_linesize + offset_x; - uint16_t *d1_data = (uint16_t *)out->data[(plane + 1) % s->ncomp] + offset_y * d1_linesize + offset_x; - uint16_t *d2_data = (uint16_t *)out->data[(plane + 2) % s->ncomp] + offset_y * d2_linesize + offset_x; + uint16_t *d0_data = (uint16_t *)out->data[plane] + (offset_y + sliceh_start) * d0_linesize + offset_x; + uint16_t *d1_data = (uint16_t *)out->data[(plane + 1) % s->ncomp] + (offset_y + sliceh_start) * d1_linesize + offset_x; + uint16_t *d2_data = (uint16_t *)out->data[(plane + 2) % s->ncomp] + (offset_y + sliceh_start) * d2_linesize + offset_x; if (mirror) { d0_data += s->size - 1; @@ -1532,7 +1690,7 @@ static av_always_inline void color16(WaveformContext *s, d2_data += s->size - 1; } - for (y = 0; y < src_h; y++) { + for (y = sliceh_start; y < sliceh_end; y++) { for (x = 0; x < src_w; x++) { const int c0 = FFMIN(c0_data[x >> c0_shift_w], limit); const int c1 = c1_data[x >> c1_shift_w]; @@ -1560,37 +1718,65 @@ static av_always_inline void color16(WaveformContext *s, d2_data += d2_linesize; } } - - envelope16(s, out, plane, plane, column ? offset_x : offset_y); } +#define COLOR16_FUNC(name, column, mirror) \ +static int color16_##name(AVFilterContext *ctx, \ + void *arg, int jobnr, \ + int nb_jobs) \ +{ \ + WaveformContext *s = ctx->priv; \ + ThreadData *td = arg; \ + AVFrame *in = td->in; \ + AVFrame *out = td->out; \ + int component = td->component; \ + int offset_y = td->offset_y; \ + int offset_x = td->offset_x; \ + \ + color16(s, in, out, component, s->intensity, \ + offset_y, offset_x, column, mirror, \ + jobnr, nb_jobs); \ + \ + return 0; \ +} + +COLOR16_FUNC(column_mirror, 1, 1) +COLOR16_FUNC(column, 1, 0) +COLOR16_FUNC(row_mirror, 0, 1) +COLOR16_FUNC(row, 0, 0) + static av_always_inline void color(WaveformContext *s, AVFrame *in, AVFrame *out, int component, int intensity, int offset_y, int offset_x, - int column, int mirror) + int column, int mirror, + int jobnr, int nb_jobs) { const int plane = s->desc->comp[component].plane; - const uint8_t *c0_data = in->data[plane + 0]; - const uint8_t *c1_data = in->data[(plane + 1) % s->ncomp]; - const uint8_t *c2_data = in->data[(plane + 2) % s->ncomp]; + const int src_h = in->height; + const int src_w = in->width; + const int sliceh_start = !column ? (src_h * jobnr) / nb_jobs : 0; + const int sliceh_end = !column ? (src_h * (jobnr+1)) / nb_jobs : src_h; + const int slicew_start = column ? (src_w * jobnr) / nb_jobs : 0; + const int slicew_end = column ? (src_w * (jobnr+1)) / nb_jobs : src_w; const int c0_linesize = in->linesize[ plane + 0 ]; const int c1_linesize = in->linesize[(plane + 1) % s->ncomp]; const int c2_linesize = in->linesize[(plane + 2) % s->ncomp]; + const int c0_shift_h = s->shift_h[ component + 0 ]; + const int c1_shift_h = s->shift_h[(component + 1) % s->ncomp]; + const int c2_shift_h = s->shift_h[(component + 2) % s->ncomp]; + const uint8_t *c0_data = in->data[plane] + (sliceh_start >> c0_shift_h) * c0_linesize; + const uint8_t *c1_data = in->data[(plane + 1) % s->ncomp] + (sliceh_start >> c1_shift_h) * c1_linesize; + const uint8_t *c2_data = in->data[(plane + 2) % s->ncomp] + (sliceh_start >> c2_shift_h) * c2_linesize; const int d0_linesize = out->linesize[ plane + 0 ]; const int d1_linesize = out->linesize[(plane + 1) % s->ncomp]; const int d2_linesize = out->linesize[(plane + 2) % s->ncomp]; const int c0_shift_w = s->shift_w[ component + 0 ]; const int c1_shift_w = s->shift_w[(component + 1) % s->ncomp]; const int c2_shift_w = s->shift_w[(component + 2) % s->ncomp]; - const int c0_shift_h = s->shift_h[ component + 0 ]; - const int c1_shift_h = s->shift_h[(component + 1) % s->ncomp]; - const int c2_shift_h = s->shift_h[(component + 2) % s->ncomp]; - const int src_h = in->height; - const int src_w = in->width; int x, y; - if (s->mode) { + if (column) { const int d0_signed_linesize = d0_linesize * (mirror == 1 ? -1 : 1); const int d1_signed_linesize = d1_linesize * (mirror == 1 ? -1 : 1); const int d2_signed_linesize = d2_linesize * (mirror == 1 ? -1 : 1); @@ -1605,7 +1791,7 @@ static av_always_inline void color(WaveformContext *s, uint8_t * const d2 = (mirror ? d2_bottom_line : d2_data); for (y = 0; y < src_h; y++) { - for (x = 0; x < src_w; x++) { + for (x = slicew_start; x < slicew_end; x++) { const int c0 = c0_data[x >> c0_shift_w]; const int c1 = c1_data[x >> c1_shift_w]; const int c2 = c2_data[x >> c2_shift_w]; @@ -1626,9 +1812,9 @@ static av_always_inline void color(WaveformContext *s, d2_data += d2_linesize; } } else { - uint8_t *d0_data = out->data[plane] + offset_y * d0_linesize + offset_x; - uint8_t *d1_data = out->data[(plane + 1) % s->ncomp] + offset_y * d1_linesize + offset_x; - uint8_t *d2_data = out->data[(plane + 2) % s->ncomp] + offset_y * d2_linesize + offset_x; + uint8_t *d0_data = out->data[plane] + (offset_y + sliceh_start) * d0_linesize + offset_x; + uint8_t *d1_data = out->data[(plane + 1) % s->ncomp] + (offset_y + sliceh_start) * d1_linesize + offset_x; + uint8_t *d2_data = out->data[(plane + 2) % s->ncomp] + (offset_y + sliceh_start) * d2_linesize + offset_x; if (mirror) { d0_data += s->size - 1; @@ -1636,7 +1822,7 @@ static av_always_inline void color(WaveformContext *s, d2_data += s->size - 1; } - for (y = 0; y < src_h; y++) { + for (y = sliceh_start; y < sliceh_end; y++) { for (x = 0; x < src_w; x++) { const int c0 = c0_data[x >> c0_shift_w]; const int c1 = c1_data[x >> c1_shift_w]; @@ -1664,39 +1850,67 @@ static av_always_inline void color(WaveformContext *s, d2_data += d2_linesize; } } - - envelope(s, out, plane, plane, column ? offset_x : offset_y); } +#define COLOR_FUNC(name, column, mirror) \ +static int color_##name(AVFilterContext *ctx, \ + void *arg, int jobnr, \ + int nb_jobs) \ +{ \ + WaveformContext *s = ctx->priv; \ + ThreadData *td = arg; \ + AVFrame *in = td->in; \ + AVFrame *out = td->out; \ + int component = td->component; \ + int offset_y = td->offset_y; \ + int offset_x = td->offset_x; \ + \ + color(s, in, out, component, s->intensity, \ + offset_y, offset_x, column, mirror, \ + jobnr, nb_jobs); \ + \ + return 0; \ +} + +COLOR_FUNC(column_mirror, 1, 1) +COLOR_FUNC(column, 1, 0) +COLOR_FUNC(row_mirror, 0, 1) +COLOR_FUNC(row, 0, 0) + static av_always_inline void acolor16(WaveformContext *s, AVFrame *in, AVFrame *out, int component, int intensity, int offset_y, int offset_x, - int column, int mirror) + int column, int mirror, + int jobnr, int nb_jobs) { const int plane = s->desc->comp[component].plane; const int limit = s->max - 1; const int max = limit - intensity; - const uint16_t *c0_data = (const uint16_t *)in->data[plane + 0]; - const uint16_t *c1_data = (const uint16_t *)in->data[(plane + 1) % s->ncomp]; - const uint16_t *c2_data = (const uint16_t *)in->data[(plane + 2) % s->ncomp]; + const int src_h = in->height; + const int src_w = in->width; + const int sliceh_start = !column ? (src_h * jobnr) / nb_jobs : 0; + const int sliceh_end = !column ? (src_h * (jobnr+1)) / nb_jobs : src_h; + const int slicew_start = column ? (src_w * jobnr) / nb_jobs : 0; + const int slicew_end = column ? (src_w * (jobnr+1)) / nb_jobs : src_w; + const int c0_shift_h = s->shift_h[ component + 0 ]; + const int c1_shift_h = s->shift_h[(component + 1) % s->ncomp]; + const int c2_shift_h = s->shift_h[(component + 2) % s->ncomp]; const int c0_linesize = in->linesize[ plane + 0 ] / 2; const int c1_linesize = in->linesize[(plane + 1) % s->ncomp] / 2; const int c2_linesize = in->linesize[(plane + 2) % s->ncomp] / 2; + const uint16_t *c0_data = (const uint16_t *)in->data[plane + 0] + (sliceh_start >> c0_shift_h) * c0_linesize; + const uint16_t *c1_data = (const uint16_t *)in->data[(plane + 1) % s->ncomp] + (sliceh_start >> c1_shift_h) * c1_linesize; + const uint16_t *c2_data = (const uint16_t *)in->data[(plane + 2) % s->ncomp] + (sliceh_start >> c2_shift_h) * c2_linesize; const int d0_linesize = out->linesize[ plane + 0 ] / 2; const int d1_linesize = out->linesize[(plane + 1) % s->ncomp] / 2; const int d2_linesize = out->linesize[(plane + 2) % s->ncomp] / 2; const int c0_shift_w = s->shift_w[ component + 0 ]; const int c1_shift_w = s->shift_w[(component + 1) % s->ncomp]; const int c2_shift_w = s->shift_w[(component + 2) % s->ncomp]; - const int c0_shift_h = s->shift_h[ component + 0 ]; - const int c1_shift_h = s->shift_h[(component + 1) % s->ncomp]; - const int c2_shift_h = s->shift_h[(component + 2) % s->ncomp]; - const int src_h = in->height; - const int src_w = in->width; int x, y; - if (s->mode) { + if (column) { const int d0_signed_linesize = d0_linesize * (mirror == 1 ? -1 : 1); const int d1_signed_linesize = d1_linesize * (mirror == 1 ? -1 : 1); const int d2_signed_linesize = d2_linesize * (mirror == 1 ? -1 : 1); @@ -1711,7 +1925,7 @@ static av_always_inline void acolor16(WaveformContext *s, uint16_t * const d2 = (mirror ? d2_bottom_line : d2_data); for (y = 0; y < src_h; y++) { - for (x = 0; x < src_w; x++) { + for (x = slicew_start; x < slicew_end; x++) { const int c0 = FFMIN(c0_data[x >> c0_shift_w], limit); const int c1 = c1_data[x >> c1_shift_w]; const int c2 = c2_data[x >> c2_shift_w]; @@ -1732,9 +1946,9 @@ static av_always_inline void acolor16(WaveformContext *s, d2_data += d2_linesize; } } else { - uint16_t *d0_data = (uint16_t *)out->data[plane] + offset_y * d0_linesize + offset_x; - uint16_t *d1_data = (uint16_t *)out->data[(plane + 1) % s->ncomp] + offset_y * d1_linesize + offset_x; - uint16_t *d2_data = (uint16_t *)out->data[(plane + 2) % s->ncomp] + offset_y * d2_linesize + offset_x; + uint16_t *d0_data = (uint16_t *)out->data[plane] + (offset_y + sliceh_start) * d0_linesize + offset_x; + uint16_t *d1_data = (uint16_t *)out->data[(plane + 1) % s->ncomp] + (offset_y + sliceh_start) * d1_linesize + offset_x; + uint16_t *d2_data = (uint16_t *)out->data[(plane + 2) % s->ncomp] + (offset_y + sliceh_start) * d2_linesize + offset_x; if (mirror) { d0_data += s->size - 1; @@ -1742,7 +1956,7 @@ static av_always_inline void acolor16(WaveformContext *s, d2_data += s->size - 1; } - for (y = 0; y < src_h; y++) { + for (y = sliceh_start; y < sliceh_end; y++) { for (x = 0; x < src_w; x++) { const int c0 = FFMIN(c0_data[x >> c0_shift_w], limit); const int c1 = c1_data[x >> c1_shift_w]; @@ -1770,38 +1984,66 @@ static av_always_inline void acolor16(WaveformContext *s, d2_data += d2_linesize; } } - - envelope16(s, out, plane, plane, column ? offset_x : offset_y); } +#define ACOLOR16_FUNC(name, column, mirror) \ +static int acolor16_##name(AVFilterContext *ctx, \ + void *arg, int jobnr, \ + int nb_jobs) \ +{ \ + WaveformContext *s = ctx->priv; \ + ThreadData *td = arg; \ + AVFrame *in = td->in; \ + AVFrame *out = td->out; \ + int component = td->component; \ + int offset_y = td->offset_y; \ + int offset_x = td->offset_x; \ + \ + acolor16(s, in, out, component, s->intensity,\ + offset_y, offset_x, column, mirror, \ + jobnr, nb_jobs); \ + \ + return 0; \ +} + +ACOLOR16_FUNC(column_mirror, 1, 1) +ACOLOR16_FUNC(column, 1, 0) +ACOLOR16_FUNC(row_mirror, 0, 1) +ACOLOR16_FUNC(row, 0, 0) + static av_always_inline void acolor(WaveformContext *s, AVFrame *in, AVFrame *out, int component, int intensity, int offset_y, int offset_x, - int column, int mirror) + int column, int mirror, + int jobnr, int nb_jobs) { const int plane = s->desc->comp[component].plane; - const uint8_t *c0_data = in->data[plane + 0]; - const uint8_t *c1_data = in->data[(plane + 1) % s->ncomp]; - const uint8_t *c2_data = in->data[(plane + 2) % s->ncomp]; - const int c0_linesize = in->linesize[ plane + 0 ]; - const int c1_linesize = in->linesize[(plane + 1) % s->ncomp]; - const int c2_linesize = in->linesize[(plane + 2) % s->ncomp]; - const int d0_linesize = out->linesize[ plane + 0 ]; - const int d1_linesize = out->linesize[(plane + 1) % s->ncomp]; - const int d2_linesize = out->linesize[(plane + 2) % s->ncomp]; + const int src_h = in->height; + const int src_w = in->width; + const int sliceh_start = !column ? (src_h * jobnr) / nb_jobs : 0; + const int sliceh_end = !column ? (src_h * (jobnr+1)) / nb_jobs : src_h; + const int slicew_start = column ? (src_w * jobnr) / nb_jobs : 0; + const int slicew_end = column ? (src_w * (jobnr+1)) / nb_jobs : src_w; const int c0_shift_w = s->shift_w[ component + 0 ]; const int c1_shift_w = s->shift_w[(component + 1) % s->ncomp]; const int c2_shift_w = s->shift_w[(component + 2) % s->ncomp]; const int c0_shift_h = s->shift_h[ component + 0 ]; const int c1_shift_h = s->shift_h[(component + 1) % s->ncomp]; const int c2_shift_h = s->shift_h[(component + 2) % s->ncomp]; + const int c0_linesize = in->linesize[ plane + 0 ]; + const int c1_linesize = in->linesize[(plane + 1) % s->ncomp]; + const int c2_linesize = in->linesize[(plane + 2) % s->ncomp]; + const uint8_t *c0_data = in->data[plane + 0] + (sliceh_start >> c0_shift_h) * c0_linesize; + const uint8_t *c1_data = in->data[(plane + 1) % s->ncomp] + (sliceh_start >> c1_shift_h) * c1_linesize; + const uint8_t *c2_data = in->data[(plane + 2) % s->ncomp] + (sliceh_start >> c2_shift_h) * c2_linesize; + const int d0_linesize = out->linesize[ plane + 0 ]; + const int d1_linesize = out->linesize[(plane + 1) % s->ncomp]; + const int d2_linesize = out->linesize[(plane + 2) % s->ncomp]; const int max = 255 - intensity; - const int src_h = in->height; - const int src_w = in->width; int x, y; - if (s->mode) { + if (column) { const int d0_signed_linesize = d0_linesize * (mirror == 1 ? -1 : 1); const int d1_signed_linesize = d1_linesize * (mirror == 1 ? -1 : 1); const int d2_signed_linesize = d2_linesize * (mirror == 1 ? -1 : 1); @@ -1816,7 +2058,7 @@ static av_always_inline void acolor(WaveformContext *s, uint8_t * const d2 = (mirror ? d2_bottom_line : d2_data); for (y = 0; y < src_h; y++) { - for (x = 0; x < src_w; x++) { + for (x = slicew_start; x < slicew_end; x++) { const int c0 = c0_data[x >> c0_shift_w]; const int c1 = c1_data[x >> c1_shift_w]; const int c2 = c2_data[x >> c2_shift_w]; @@ -1837,9 +2079,9 @@ static av_always_inline void acolor(WaveformContext *s, d2_data += d2_linesize; } } else { - uint8_t *d0_data = out->data[plane] + offset_y * d0_linesize + offset_x; - uint8_t *d1_data = out->data[(plane + 1) % s->ncomp] + offset_y * d1_linesize + offset_x; - uint8_t *d2_data = out->data[(plane + 2) % s->ncomp] + offset_y * d2_linesize + offset_x; + uint8_t *d0_data = out->data[plane] + (offset_y + sliceh_start) * d0_linesize + offset_x; + uint8_t *d1_data = out->data[(plane + 1) % s->ncomp] + (offset_y + sliceh_start) * d1_linesize + offset_x; + uint8_t *d2_data = out->data[(plane + 2) % s->ncomp] + (offset_y + sliceh_start) * d2_linesize + offset_x; if (mirror) { d0_data += s->size - 1; @@ -1847,7 +2089,7 @@ static av_always_inline void acolor(WaveformContext *s, d2_data += s->size - 1; } - for (y = 0; y < src_h; y++) { + for (y = sliceh_start; y < sliceh_end; y++) { for (x = 0; x < src_w; x++) { const int c0 = c0_data[x >> c0_shift_w]; const int c1 = c1_data[x >> c1_shift_w]; @@ -1875,10 +2117,33 @@ static av_always_inline void acolor(WaveformContext *s, d2_data += d2_linesize; } } - - envelope(s, out, plane, plane, column ? offset_x : offset_y); } +#define ACOLOR_FUNC(name, column, mirror) \ +static int acolor_##name(AVFilterContext *ctx, \ + void *arg, int jobnr, \ + int nb_jobs) \ +{ \ + WaveformContext *s = ctx->priv; \ + ThreadData *td = arg; \ + AVFrame *in = td->in; \ + AVFrame *out = td->out; \ + int component = td->component; \ + int offset_y = td->offset_y; \ + int offset_x = td->offset_x; \ + \ + acolor(s, in, out, component, s->intensity, \ + offset_y, offset_x, column, mirror, \ + jobnr, nb_jobs); \ + \ + return 0; \ +} + +ACOLOR_FUNC(column_mirror, 1, 1) +ACOLOR_FUNC(column, 1, 0) +ACOLOR_FUNC(row_mirror, 0, 1) +ACOLOR_FUNC(row, 0, 0) + static const uint8_t black_yuva_color[4] = { 0, 127, 127, 255 }; static const uint8_t black_gbrp_color[4] = { 0, 0, 0, 255 }; @@ -2346,17 +2611,18 @@ static void graticule_row(WaveformContext *s, AVFrame *out) const float o1 = s->opacity; const float o2 = 1. - o1; const int height = s->display == PARADE ? out->height / s->acomp : out->height; - int k = 0, c, p, l, offset_x = 0, offset_y = 0; + int C, k = 0, c, p, l, offset_x = 0, offset_y = 0; for (c = 0; c < s->ncomp; c++) { if (!((1 << c) & s->pcomp) || (!s->display && k > 0)) continue; k++; + C = s->rgb ? 0 : c; for (p = 0; p < s->ncomp; p++) { const int v = s->grat_yuva_color[p]; for (l = 0; l < s->nb_glines; l++) { - const uint16_t pos = s->glines[l].line[c].pos; + const uint16_t pos = s->glines[l].line[C].pos; int x = offset_x + (s->mirror ? s->size - 1 - pos : pos); uint8_t *dst = out->data[p] + offset_y * out->linesize[p] + x; @@ -2365,8 +2631,8 @@ static void graticule_row(WaveformContext *s, AVFrame *out) } for (l = 0; l < s->nb_glines && (s->flags & 1); l++) { - const char *name = s->glines[l].line[c].name; - const uint16_t pos = s->glines[l].line[c].pos; + const char *name = s->glines[l].line[C].name; + const uint16_t pos = s->glines[l].line[C].pos; int x = offset_x + (s->mirror ? s->size - 1 - pos : pos) - 10; if (x < 0) @@ -2387,17 +2653,18 @@ static void graticule16_row(WaveformContext *s, AVFrame *out) const float o2 = 1. - o1; const int mult = s->max / 256; const int height = s->display == PARADE ? out->height / s->acomp : out->height; - int k = 0, c, p, l, offset_x = 0, offset_y = 0; + int C, k = 0, c, p, l, offset_x = 0, offset_y = 0; for (c = 0; c < s->ncomp; c++) { if (!((1 << c) & s->pcomp) || (!s->display && k > 0)) continue; k++; + C = s->rgb ? 0 : c; for (p = 0; p < s->ncomp; p++) { const int v = s->grat_yuva_color[p] * mult; for (l = 0; l < s->nb_glines ; l++) { - const uint16_t pos = s->glines[l].line[c].pos; + const uint16_t pos = s->glines[l].line[C].pos; int x = offset_x + (s->mirror ? s->size - 1 - pos : pos); uint16_t *dst = (uint16_t *)(out->data[p] + offset_y * out->linesize[p]) + x; @@ -2406,8 +2673,8 @@ static void graticule16_row(WaveformContext *s, AVFrame *out) } for (l = 0; l < s->nb_glines && (s->flags & 1); l++) { - const char *name = s->glines[l].line[c].name; - const uint16_t pos = s->glines[l].line[c].pos; + const char *name = s->glines[l].line[C].name; + const uint16_t pos = s->glines[l].line[C].pos; int x = offset_x + (s->mirror ? s->size - 1 - pos : pos) - 10; if (x < 0) @@ -2427,17 +2694,18 @@ static void graticule_column(WaveformContext *s, AVFrame *out) const float o1 = s->opacity; const float o2 = 1. - o1; const int width = s->display == PARADE ? out->width / s->acomp : out->width; - int k = 0, c, p, l, offset_y = 0, offset_x = 0; + int C, k = 0, c, p, l, offset_y = 0, offset_x = 0; for (c = 0; c < s->ncomp; c++) { if ((!((1 << c) & s->pcomp) || (!s->display && k > 0))) continue; k++; + C = s->rgb ? 0 : c; for (p = 0; p < s->ncomp; p++) { const int v = s->grat_yuva_color[p]; for (l = 0; l < s->nb_glines ; l++) { - const uint16_t pos = s->glines[l].line[c].pos; + const uint16_t pos = s->glines[l].line[C].pos; int y = offset_y + (s->mirror ? s->size - 1 - pos : pos); uint8_t *dst = out->data[p] + y * out->linesize[p] + offset_x; @@ -2446,8 +2714,8 @@ static void graticule_column(WaveformContext *s, AVFrame *out) } for (l = 0; l < s->nb_glines && (s->flags & 1); l++) { - const char *name = s->glines[l].line[c].name; - const uint16_t pos = s->glines[l].line[c].pos; + const char *name = s->glines[l].line[C].name; + const uint16_t pos = s->glines[l].line[C].pos; int y = offset_y + (s->mirror ? s->size - 1 - pos : pos) - 10; if (y < 0) @@ -2468,17 +2736,18 @@ static void graticule16_column(WaveformContext *s, AVFrame *out) const float o2 = 1. - o1; const int mult = s->max / 256; const int width = s->display == PARADE ? out->width / s->acomp : out->width; - int k = 0, c, p, l, offset_x = 0, offset_y = 0; + int C, k = 0, c, p, l, offset_x = 0, offset_y = 0; for (c = 0; c < s->ncomp; c++) { if ((!((1 << c) & s->pcomp) || (!s->display && k > 0))) continue; k++; + C = s->rgb ? 0 : c; for (p = 0; p < s->ncomp; p++) { const int v = s->grat_yuva_color[p] * mult; for (l = 0; l < s->nb_glines ; l++) { - const uint16_t pos = s->glines[l].line[c].pos; + const uint16_t pos = s->glines[l].line[C].pos; int y = offset_y + (s->mirror ? s->size - 1 - pos : pos); uint16_t *dst = (uint16_t *)(out->data[p] + y * out->linesize[p]) + offset_x; @@ -2487,8 +2756,8 @@ static void graticule16_column(WaveformContext *s, AVFrame *out) } for (l = 0; l < s->nb_glines && (s->flags & 1); l++) { - const char *name = s->glines[l].line[c].name; - const uint16_t pos = s->glines[l].line[c].pos; + const char *name = s->glines[l].line[C].name; + const uint16_t pos = s->glines[l].line[C].pos; int y = offset_y + (s->mirror ? s->size - 1 - pos: pos) - 10; if (y < 0) @@ -2529,62 +2798,62 @@ static int config_input(AVFilterLink *inlink) switch (s->filter | ((s->bits > 8) << 4) | (s->mode << 8) | (s->mirror << 12)) { - case 0x1100: s->waveform = lowpass_column_mirror; break; - case 0x1000: s->waveform = lowpass_row_mirror; break; - case 0x0100: s->waveform = lowpass_column; break; - case 0x0000: s->waveform = lowpass_row; break; - case 0x1110: s->waveform = lowpass16_column_mirror; break; - case 0x1010: s->waveform = lowpass16_row_mirror; break; - case 0x0110: s->waveform = lowpass16_column; break; - case 0x0010: s->waveform = lowpass16_row; break; - case 0x1101: - case 0x1001: - case 0x0101: - case 0x0001: s->waveform = flat; break; - case 0x1111: - case 0x1011: - case 0x0111: - case 0x0011: s->waveform = flat16; break; - case 0x1102: s->waveform = aflat_column_mirror; break; - case 0x1002: s->waveform = aflat_row_mirror; break; - case 0x0102: s->waveform = aflat_column; break; - case 0x0002: s->waveform = aflat_row; break; - case 0x1112: s->waveform = aflat16_column_mirror; break; - case 0x1012: s->waveform = aflat16_row_mirror; break; - case 0x0112: s->waveform = aflat16_column; break; - case 0x0012: s->waveform = aflat16_row; break; - case 0x1103: - case 0x1003: - case 0x0103: - case 0x0003: s->waveform = chroma; break; - case 0x1113: - case 0x1013: - case 0x0113: - case 0x0013: s->waveform = chroma16; break; - case 0x1104: - case 0x1004: - case 0x0104: - case 0x0004: s->waveform = color; break; - case 0x1114: - case 0x1014: - case 0x0114: - case 0x0014: s->waveform = color16; break; - case 0x1105: - case 0x1005: - case 0x0105: - case 0x0005: s->waveform = acolor; break; - case 0x1115: - case 0x1015: - case 0x0115: - case 0x0015: s->waveform = acolor16; break; - case 0x1106: s->waveform = xflat_column_mirror; break; - case 0x1006: s->waveform = xflat_row_mirror; break; - case 0x0106: s->waveform = xflat_column; break; - case 0x0006: s->waveform = xflat_row; break; - case 0x1116: s->waveform = xflat16_column_mirror; break; - case 0x1016: s->waveform = xflat16_row_mirror; break; - case 0x0116: s->waveform = xflat16_column; break; - case 0x0016: s->waveform = xflat16_row; break; + case 0x1100: s->waveform_slice = lowpass_column_mirror; break; + case 0x1000: s->waveform_slice = lowpass_row_mirror; break; + case 0x0100: s->waveform_slice = lowpass_column; break; + case 0x0000: s->waveform_slice = lowpass_row; break; + case 0x1110: s->waveform_slice = lowpass16_column_mirror; break; + case 0x1010: s->waveform_slice = lowpass16_row_mirror; break; + case 0x0110: s->waveform_slice = lowpass16_column; break; + case 0x0010: s->waveform_slice = lowpass16_row; break; + case 0x1101: s->waveform_slice = flat_column_mirror; break; + case 0x1001: s->waveform_slice = flat_row_mirror; break; + case 0x0101: s->waveform_slice = flat_column; break; + case 0x0001: s->waveform_slice = flat_row; break; + case 0x1111: s->waveform_slice = flat16_column_mirror; break; + case 0x1011: s->waveform_slice = flat16_row_mirror; break; + case 0x0111: s->waveform_slice = flat16_column; break; + case 0x0011: s->waveform_slice = flat16_row; break; + case 0x1102: s->waveform_slice = aflat_column_mirror; break; + case 0x1002: s->waveform_slice = aflat_row_mirror; break; + case 0x0102: s->waveform_slice = aflat_column; break; + case 0x0002: s->waveform_slice = aflat_row; break; + case 0x1112: s->waveform_slice = aflat16_column_mirror; break; + case 0x1012: s->waveform_slice = aflat16_row_mirror; break; + case 0x0112: s->waveform_slice = aflat16_column; break; + case 0x0012: s->waveform_slice = aflat16_row; break; + case 0x1103: s->waveform_slice = chroma_column_mirror; break; + case 0x1003: s->waveform_slice = chroma_row_mirror; break; + case 0x0103: s->waveform_slice = chroma_column; break; + case 0x0003: s->waveform_slice = chroma_row; break; + case 0x1113: s->waveform_slice = chroma16_column_mirror; break; + case 0x1013: s->waveform_slice = chroma16_row_mirror; break; + case 0x0113: s->waveform_slice = chroma16_column; break; + case 0x0013: s->waveform_slice = chroma16_row; break; + case 0x1104: s->waveform_slice = color_column_mirror; break; + case 0x1004: s->waveform_slice = color_row_mirror; break; + case 0x0104: s->waveform_slice = color_column; break; + case 0x0004: s->waveform_slice = color_row; break; + case 0x1114: s->waveform_slice = color16_column_mirror; break; + case 0x1014: s->waveform_slice = color16_row_mirror; break; + case 0x0114: s->waveform_slice = color16_column; break; + case 0x0014: s->waveform_slice = color16_row; break; + case 0x1105: s->waveform_slice = acolor_column_mirror; break; + case 0x1005: s->waveform_slice = acolor_row_mirror; break; + case 0x0105: s->waveform_slice = acolor_column; break; + case 0x0005: s->waveform_slice = acolor_row; break; + case 0x1115: s->waveform_slice = acolor16_column_mirror; break; + case 0x1015: s->waveform_slice = acolor16_row_mirror; break; + case 0x0115: s->waveform_slice = acolor16_column; break; + case 0x0015: s->waveform_slice = acolor16_row; break; + case 0x1106: s->waveform_slice = xflat_column_mirror; break; + case 0x1006: s->waveform_slice = xflat_row_mirror; break; + case 0x0106: s->waveform_slice = xflat_column; break; + case 0x0006: s->waveform_slice = xflat_row; break; + case 0x1116: s->waveform_slice = xflat16_column_mirror; break; + case 0x1016: s->waveform_slice = xflat16_row_mirror; break; + case 0x0116: s->waveform_slice = xflat16_column; break; + case 0x0016: s->waveform_slice = xflat16_row; break; } s->grat_yuva_color[0] = 255; @@ -2732,8 +3001,8 @@ static int config_input(AVFilterLink *inlink) case AV_PIX_FMT_GBRP9: case AV_PIX_FMT_GBRP10: case AV_PIX_FMT_GBRP12: + s->rgb = 1; memcpy(s->bg_color, black_gbrp_color, sizeof(s->bg_color)); - s->graticulef = graticule_none; break; default: memcpy(s->bg_color, black_yuva_color, sizeof(s->bg_color)); @@ -2756,6 +3025,9 @@ static int config_output(AVFilterLink *outlink) comp++; } s->acomp = comp; + if (s->acomp == 0) + return AVERROR(EINVAL); + s->odesc = av_pix_fmt_desc_get(outlink->format); s->dcomp = s->odesc->nb_components; @@ -2839,6 +3111,8 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) for (k = 0, i = 0; k < s->ncomp; k++) { if ((1 << k) & s->pcomp) { + const int plane = s->desc->comp[k].plane; + ThreadData td; int offset_y; int offset_x; @@ -2849,7 +3123,45 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) offset_y = s->mode ? i++ * s->size * !!s->display : 0; offset_x = s->mode ? 0 : i++ * s->size * !!s->display; } - s->waveform(s, in, out, k, s->intensity, offset_y, offset_x, s->mode, s->mirror); + + td.in = in; + td.out = out; + td.component = k; + td.offset_y = offset_y; + td.offset_x = offset_x; + ctx->internal->execute(ctx, s->waveform_slice, &td, NULL, ff_filter_get_nb_threads(ctx)); + switch (s->filter) { + case ACOLOR: + case CHROMA: + case COLOR: + case LOWPASS: + if (s->bits <= 8) + envelope(s, out, plane, plane, s->mode ? offset_x : offset_y); + else + envelope16(s, out, plane, plane, s->mode ? offset_x : offset_y); + break; + case FLAT: + if (s->bits <= 8) { + envelope(s, out, plane, plane, s->mode ? offset_x : offset_y); + envelope(s, out, plane, (plane + 1) % s->ncomp, s->mode ? offset_x : offset_y); + } else { + envelope16(s, out, plane, plane, s->mode ? offset_x : offset_y); + envelope16(s, out, plane, (plane + 1) % s->ncomp, s->mode ? offset_x : offset_y); + } + break; + case AFLAT: + case XFLAT: + if (s->bits <= 8) { + envelope(s, out, plane, (plane + 0) % s->ncomp, s->mode ? offset_x : offset_y); + envelope(s, out, plane, (plane + 1) % s->ncomp, s->mode ? offset_x : offset_y); + envelope(s, out, plane, (plane + 2) % s->ncomp, s->mode ? offset_x : offset_y); + } else { + envelope16(s, out, plane, (plane + 0) % s->ncomp, s->mode ? offset_x : offset_y); + envelope16(s, out, plane, (plane + 1) % s->ncomp, s->mode ? offset_x : offset_y); + envelope16(s, out, plane, (plane + 2) % s->ncomp, s->mode ? offset_x : offset_y); + } + break; + } } } s->graticulef(s, out); @@ -2893,4 +3205,5 @@ AVFilter ff_vf_waveform = { .uninit = uninit, .inputs = inputs, .outputs = outputs, + .flags = AVFILTER_FLAG_SLICE_THREADS, }; diff --git a/libavfilter/vf_weave.c b/libavfilter/vf_weave.c index 037f5d1cf..663d79f51 100644 --- a/libavfilter/vf_weave.c +++ b/libavfilter/vf_weave.c @@ -84,6 +84,8 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) AVFilterLink *outlink = ctx->outputs[0]; AVFrame *out; int i; + int weave; + int field1, field2; if (!s->prev) { s->prev = in; @@ -98,26 +100,18 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) } av_frame_copy_props(out, in); + weave = (s->double_weave && !(inlink->frame_count_out & 1)); + field1 = weave ? s->first_field : (!s->first_field); + field2 = weave ? (!s->first_field) : s->first_field; for (i = 0; i < s->nb_planes; i++) { - if (s->double_weave && !(inlink->frame_count_out & 1)) { - av_image_copy_plane(out->data[i] + out->linesize[i] * s->first_field, - out->linesize[i] * 2, - in->data[i], in->linesize[i], - s->linesize[i], s->planeheight[i]); - av_image_copy_plane(out->data[i] + out->linesize[i] * !s->first_field, - out->linesize[i] * 2, - s->prev->data[i], s->prev->linesize[i], - s->linesize[i], s->planeheight[i]); - } else { - av_image_copy_plane(out->data[i] + out->linesize[i] * !s->first_field, - out->linesize[i] * 2, - in->data[i], in->linesize[i], - s->linesize[i], s->planeheight[i]); - av_image_copy_plane(out->data[i] + out->linesize[i] * s->first_field, - out->linesize[i] * 2, - s->prev->data[i], s->prev->linesize[i], - s->linesize[i], s->planeheight[i]); - } + av_image_copy_plane(out->data[i] + out->linesize[i] * field1, + out->linesize[i] * 2, + in->data[i], in->linesize[i], + s->linesize[i], s->planeheight[i]); + av_image_copy_plane(out->data[i] + out->linesize[i] * field2, + out->linesize[i] * 2, + s->prev->data[i], s->prev->linesize[i], + s->linesize[i], s->planeheight[i]); } out->pts = s->double_weave ? s->prev->pts : in->pts / 2; diff --git a/libavfilter/vf_xbr.c b/libavfilter/vf_xbr.c index 78094e028..2c71871d2 100644 --- a/libavfilter/vf_xbr.c +++ b/libavfilter/vf_xbr.c @@ -24,7 +24,7 @@ * XBR Filter is used for depixelization of image. * This is based on Hyllian's xBR shader. * - * @see http://www.libretro.com/forums/viewtopic.php?f=6&t=134 + * @see https://forums.libretro.com/t/xbr-algorithm-tutorial/123 * @see https://github.com/yoyofr/iFBA/blob/master/fba_src/src/intf/video/scalers/xbr.cpp */ diff --git a/libavfilter/vf_xmedian.c b/libavfilter/vf_xmedian.c new file mode 100644 index 000000000..672b3a7e7 --- /dev/null +++ b/libavfilter/vf_xmedian.c @@ -0,0 +1,351 @@ +/* + * Copyright (c) 2019 Paul B Mahol + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/avstring.h" +#include "libavutil/imgutils.h" +#include "libavutil/intreadwrite.h" +#include "libavutil/opt.h" +#include "libavutil/pixdesc.h" +#include "libavutil/qsort.h" + +#include "avfilter.h" +#include "formats.h" +#include "internal.h" +#include "framesync.h" +#include "video.h" + +typedef struct XMedianContext { + const AVClass *class; + const AVPixFmtDescriptor *desc; + int nb_inputs; + int planes; + + int radius; + int depth; + int max; + int nb_planes; + int linesize[4]; + int width[4]; + int height[4]; + + AVFrame **frames; + FFFrameSync fs; + + int (*median_frames)(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs); +} XMedianContext; + +static int query_formats(AVFilterContext *ctx) +{ + static const enum AVPixelFormat pixel_fmts[] = { + AV_PIX_FMT_GRAY8, + AV_PIX_FMT_GRAY9, + AV_PIX_FMT_GRAY10, + AV_PIX_FMT_GRAY12, + AV_PIX_FMT_GRAY14, + AV_PIX_FMT_GRAY16, + AV_PIX_FMT_YUV410P, AV_PIX_FMT_YUV411P, + AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV422P, + AV_PIX_FMT_YUV440P, AV_PIX_FMT_YUV444P, + AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUVJ422P, + AV_PIX_FMT_YUVJ440P, AV_PIX_FMT_YUVJ444P, + AV_PIX_FMT_YUVJ411P, + AV_PIX_FMT_YUV420P9, AV_PIX_FMT_YUV422P9, AV_PIX_FMT_YUV444P9, + AV_PIX_FMT_YUV420P10, AV_PIX_FMT_YUV422P10, AV_PIX_FMT_YUV444P10, + AV_PIX_FMT_YUV440P10, + AV_PIX_FMT_YUV444P12, AV_PIX_FMT_YUV422P12, AV_PIX_FMT_YUV420P12, + AV_PIX_FMT_YUV440P12, + AV_PIX_FMT_YUV444P14, AV_PIX_FMT_YUV422P14, AV_PIX_FMT_YUV420P14, + AV_PIX_FMT_YUV420P16, AV_PIX_FMT_YUV422P16, AV_PIX_FMT_YUV444P16, + AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRP9, AV_PIX_FMT_GBRP10, + AV_PIX_FMT_GBRP12, AV_PIX_FMT_GBRP14, AV_PIX_FMT_GBRP16, + AV_PIX_FMT_NONE + }; + AVFilterFormats *formats = ff_make_format_list(pixel_fmts); + if (!formats) + return AVERROR(ENOMEM); + return ff_set_common_formats(ctx, formats); +} + +static av_cold int init(AVFilterContext *ctx) +{ + XMedianContext *s = ctx->priv; + int ret; + + s->radius = s->nb_inputs / 2; + s->frames = av_calloc(s->nb_inputs, sizeof(*s->frames)); + if (!s->frames) + return AVERROR(ENOMEM); + + for (int i = 0; i < s->nb_inputs; i++) { + AVFilterPad pad = { 0 }; + + pad.type = AVMEDIA_TYPE_VIDEO; + pad.name = av_asprintf("input%d", i); + if (!pad.name) + return AVERROR(ENOMEM); + + if ((ret = ff_insert_inpad(ctx, i, &pad)) < 0) { + av_freep(&pad.name); + return ret; + } + } + + return 0; +} + +typedef struct ThreadData { + AVFrame **in, *out; +} ThreadData; + +static int comparei(const void *p1, const void *p2) +{ + int left = *(const int *)p1; + int right = *(const int *)p2; + return FFDIFFSIGN(left, right); +} + +static int median_frames16(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) +{ + XMedianContext *s = ctx->priv; + ThreadData *td = arg; + AVFrame **in = td->in; + AVFrame *out = td->out; + const int nb_inputs = s->nb_inputs; + const int radius = s->radius; + int values[256]; + + for (int p = 0; p < s->nb_planes; p++) { + const int slice_start = (s->height[p] * jobnr) / nb_jobs; + const int slice_end = (s->height[p] * (jobnr+1)) / nb_jobs; + uint16_t *dst = (uint16_t *)(out->data[p] + slice_start * out->linesize[p]); + + if (!((1 << p) & s->planes)) { + av_image_copy_plane((uint8_t *)dst, out->linesize[p], + in[0]->data[p] + slice_start * in[radius]->linesize[p], + in[0]->linesize[p], + s->linesize[p], slice_end - slice_start); + continue; + } + + for (int y = slice_start; y < slice_end; y++) { + for (int x = 0; x < s->width[p]; x++) { + for (int i = 0; i < nb_inputs; i++) { + const uint16_t *src = (const uint16_t *)(in[i]->data[p] + y * in[i]->linesize[p]); + values[i] = src[x]; + } + + AV_QSORT(values, nb_inputs, int, comparei); + if (radius & 1) + dst[x] = values[radius]; + else + dst[x] = (values[radius] + values[radius - 1]) >> 1; + } + + dst += out->linesize[p] / 2; + } + } + + return 0; +} + +static int median_frames8(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) +{ + XMedianContext *s = ctx->priv; + ThreadData *td = arg; + AVFrame **in = td->in; + AVFrame *out = td->out; + const int nb_inputs = s->nb_inputs; + const int radius = s->radius; + int values[256]; + + for (int p = 0; p < s->nb_planes; p++) { + const int slice_start = (s->height[p] * jobnr) / nb_jobs; + const int slice_end = (s->height[p] * (jobnr+1)) / nb_jobs; + uint8_t *dst = out->data[p] + slice_start * out->linesize[p]; + + if (!((1 << p) & s->planes)) { + av_image_copy_plane(dst, out->linesize[p], + in[0]->data[p] + slice_start * in[0]->linesize[p], + in[0]->linesize[p], + s->linesize[p], slice_end - slice_start); + continue; + } + + for (int y = slice_start; y < slice_end; y++) { + for (int x = 0; x < s->width[p]; x++) { + for (int i = 0; i < nb_inputs; i++) + values[i] = in[i]->data[p][y * in[i]->linesize[p] + x]; + + AV_QSORT(values, nb_inputs, int, comparei); + if (radius & 1) + dst[x] = values[radius]; + else + dst[x] = (values[radius] + values[radius - 1]) >> 1; + } + + dst += out->linesize[p]; + } + } + + return 0; +} + +static int process_frame(FFFrameSync *fs) +{ + AVFilterContext *ctx = fs->parent; + AVFilterLink *outlink = ctx->outputs[0]; + XMedianContext *s = fs->opaque; + AVFrame **in = s->frames; + AVFrame *out; + ThreadData td; + int i, ret; + + for (i = 0; i < s->nb_inputs; i++) { + if ((ret = ff_framesync_get_frame(&s->fs, i, &in[i], 0)) < 0) + return ret; + } + + out = ff_get_video_buffer(outlink, outlink->w, outlink->h); + if (!out) + return AVERROR(ENOMEM); + out->pts = av_rescale_q(s->fs.pts, s->fs.time_base, outlink->time_base); + + td.in = in; + td.out = out; + ctx->internal->execute(ctx, s->median_frames, &td, NULL, FFMIN(s->height[1], ff_filter_get_nb_threads(ctx))); + + return ff_filter_frame(outlink, out); +} + +static int config_output(AVFilterLink *outlink) +{ + AVFilterContext *ctx = outlink->src; + XMedianContext *s = ctx->priv; + AVRational frame_rate = ctx->inputs[0]->frame_rate; + AVRational sar = ctx->inputs[0]->sample_aspect_ratio; + AVFilterLink *inlink = ctx->inputs[0]; + int height = ctx->inputs[0]->h; + int width = ctx->inputs[0]->w; + FFFrameSyncIn *in; + int i, ret; + + for (int i = 1; i < s->nb_inputs; i++) { + if (ctx->inputs[i]->h != height || ctx->inputs[i]->w != width) { + av_log(ctx, AV_LOG_ERROR, "Input %d size (%dx%d) does not match input %d size (%dx%d).\n", i, ctx->inputs[i]->w, ctx->inputs[i]->h, 0, width, height); + return AVERROR(EINVAL); + } + } + + s->desc = av_pix_fmt_desc_get(outlink->format); + if (!s->desc) + return AVERROR_BUG; + s->nb_planes = av_pix_fmt_count_planes(outlink->format); + s->depth = s->desc->comp[0].depth; + s->max = (1 << s->depth) - 1; + + if (s->depth <= 8) + s->median_frames = median_frames8; + else + s->median_frames = median_frames16; + + if ((ret = av_image_fill_linesizes(s->linesize, inlink->format, inlink->w)) < 0) + return ret; + + s->width[1] = s->width[2] = AV_CEIL_RSHIFT(inlink->w, s->desc->log2_chroma_w); + s->width[0] = s->width[3] = inlink->w; + s->height[1] = s->height[2] = AV_CEIL_RSHIFT(inlink->h, s->desc->log2_chroma_h); + s->height[0] = s->height[3] = inlink->h; + + outlink->w = width; + outlink->h = height; + outlink->frame_rate = frame_rate; + outlink->sample_aspect_ratio = sar; + + if ((ret = ff_framesync_init(&s->fs, ctx, s->nb_inputs)) < 0) + return ret; + + in = s->fs.in; + s->fs.opaque = s; + s->fs.on_event = process_frame; + + for (i = 0; i < s->nb_inputs; i++) { + AVFilterLink *inlink = ctx->inputs[i]; + + in[i].time_base = inlink->time_base; + in[i].sync = 1; + in[i].before = EXT_STOP; + in[i].after = EXT_STOP; + } + + ret = ff_framesync_configure(&s->fs); + outlink->time_base = s->fs.time_base; + + return ret; +} + +static av_cold void uninit(AVFilterContext *ctx) +{ + XMedianContext *s = ctx->priv; + + ff_framesync_uninit(&s->fs); + av_freep(&s->frames); + + for (int i = 0; i < ctx->nb_inputs; i++) + av_freep(&ctx->input_pads[i].name); +} + +static int activate(AVFilterContext *ctx) +{ + XMedianContext *s = ctx->priv; + return ff_framesync_activate(&s->fs); +} + +#define OFFSET(x) offsetof(XMedianContext, x) +#define FLAGS AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_FILTERING_PARAM + +static const AVOption xmedian_options[] = { + { "inputs", "set number of inputs", OFFSET(nb_inputs), AV_OPT_TYPE_INT, {.i64=3}, 3, 255, .flags = FLAGS }, + { "planes", "set planes to filter", OFFSET(planes), AV_OPT_TYPE_INT, {.i64=15}, 0, 15, .flags = FLAGS }, + { NULL }, +}; + +static const AVFilterPad outputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + .config_props = config_output, + }, + { NULL } +}; + +AVFILTER_DEFINE_CLASS(xmedian); + +AVFilter ff_vf_xmedian = { + .name = "xmedian", + .description = NULL_IF_CONFIG_SMALL("Pick median pixels from several video inputs."), + .priv_size = sizeof(XMedianContext), + .priv_class = &xmedian_class, + .query_formats = query_formats, + .outputs = outputs, + .init = init, + .uninit = uninit, + .activate = activate, + .flags = AVFILTER_FLAG_DYNAMIC_INPUTS | AVFILTER_FLAG_SLICE_THREADS, +}; diff --git a/libavfilter/vf_yadif.c b/libavfilter/vf_yadif.c index f58d8ac2b..310792493 100644 --- a/libavfilter/vf_yadif.c +++ b/libavfilter/vf_yadif.c @@ -22,7 +22,6 @@ #include "libavutil/avassert.h" #include "libavutil/cpu.h" #include "libavutil/common.h" -#include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "libavutil/imgutils.h" #include "avfilter.h" @@ -254,166 +253,6 @@ static void filter(AVFilterContext *ctx, AVFrame *dstpic, emms_c(); } -static int return_frame(AVFilterContext *ctx, int is_second) -{ - YADIFContext *yadif = ctx->priv; - AVFilterLink *link = ctx->outputs[0]; - int tff, ret; - - if (yadif->parity == -1) { - tff = yadif->cur->interlaced_frame ? - yadif->cur->top_field_first : 1; - } else { - tff = yadif->parity ^ 1; - } - - if (is_second) { - yadif->out = ff_get_video_buffer(link, link->w, link->h); - if (!yadif->out) - return AVERROR(ENOMEM); - - av_frame_copy_props(yadif->out, yadif->cur); - yadif->out->interlaced_frame = 0; - } - - filter(ctx, yadif->out, tff ^ !is_second, tff); - - if (is_second) { - int64_t cur_pts = yadif->cur->pts; - int64_t next_pts = yadif->next->pts; - - if (next_pts != AV_NOPTS_VALUE && cur_pts != AV_NOPTS_VALUE) { - yadif->out->pts = cur_pts + next_pts; - } else { - yadif->out->pts = AV_NOPTS_VALUE; - } - } - ret = ff_filter_frame(ctx->outputs[0], yadif->out); - - yadif->frame_pending = (yadif->mode&1) && !is_second; - return ret; -} - -static int checkstride(YADIFContext *yadif, const AVFrame *a, const AVFrame *b) -{ - int i; - for (i = 0; i < yadif->csp->nb_components; i++) - if (a->linesize[i] != b->linesize[i]) - return 1; - return 0; -} - -static void fixstride(AVFilterLink *link, AVFrame *f) -{ - AVFrame *dst = ff_default_get_video_buffer(link, f->width, f->height); - if(!dst) - return; - av_frame_copy_props(dst, f); - av_image_copy(dst->data, dst->linesize, - (const uint8_t **)f->data, f->linesize, - dst->format, dst->width, dst->height); - av_frame_unref(f); - av_frame_move_ref(f, dst); - av_frame_free(&dst); -} - -static int filter_frame(AVFilterLink *link, AVFrame *frame) -{ - AVFilterContext *ctx = link->dst; - YADIFContext *yadif = ctx->priv; - - av_assert0(frame); - - if (yadif->frame_pending) - return_frame(ctx, 1); - - if (yadif->prev) - av_frame_free(&yadif->prev); - yadif->prev = yadif->cur; - yadif->cur = yadif->next; - yadif->next = frame; - - if (!yadif->cur && - !(yadif->cur = av_frame_clone(yadif->next))) - return AVERROR(ENOMEM); - - if (checkstride(yadif, yadif->next, yadif->cur)) { - av_log(ctx, AV_LOG_VERBOSE, "Reallocating frame due to differing stride\n"); - fixstride(link, yadif->next); - } - if (checkstride(yadif, yadif->next, yadif->cur)) - fixstride(link, yadif->cur); - if (yadif->prev && checkstride(yadif, yadif->next, yadif->prev)) - fixstride(link, yadif->prev); - if (checkstride(yadif, yadif->next, yadif->cur) || (yadif->prev && checkstride(yadif, yadif->next, yadif->prev))) { - av_log(ctx, AV_LOG_ERROR, "Failed to reallocate frame\n"); - return -1; - } - - if (!yadif->prev) - return 0; - - if ((yadif->deint && !yadif->cur->interlaced_frame) || - ctx->is_disabled || - (yadif->deint && !yadif->prev->interlaced_frame && yadif->prev->repeat_pict) || - (yadif->deint && !yadif->next->interlaced_frame && yadif->next->repeat_pict) - ) { - yadif->out = av_frame_clone(yadif->cur); - if (!yadif->out) - return AVERROR(ENOMEM); - - av_frame_free(&yadif->prev); - if (yadif->out->pts != AV_NOPTS_VALUE) - yadif->out->pts *= 2; - return ff_filter_frame(ctx->outputs[0], yadif->out); - } - - yadif->out = ff_get_video_buffer(ctx->outputs[0], link->w, link->h); - if (!yadif->out) - return AVERROR(ENOMEM); - - av_frame_copy_props(yadif->out, yadif->cur); - yadif->out->interlaced_frame = 0; - - if (yadif->out->pts != AV_NOPTS_VALUE) - yadif->out->pts *= 2; - - return return_frame(ctx, 0); -} - -static int request_frame(AVFilterLink *link) -{ - AVFilterContext *ctx = link->src; - YADIFContext *yadif = ctx->priv; - int ret; - - if (yadif->frame_pending) { - return_frame(ctx, 1); - return 0; - } - - if (yadif->eof) - return AVERROR_EOF; - - ret = ff_request_frame(ctx->inputs[0]); - - if (ret == AVERROR_EOF && yadif->cur) { - AVFrame *next = av_frame_clone(yadif->next); - - if (!next) - return AVERROR(ENOMEM); - - next->pts = yadif->next->pts * 2 - yadif->cur->pts; - - filter_frame(ctx->inputs[0], next); - yadif->eof = 1; - } else if (ret < 0) { - return ret; - } - - return 0; -} - static av_cold void uninit(AVFilterContext *ctx) { YADIFContext *yadif = ctx->priv; @@ -492,6 +331,7 @@ static int config_props(AVFilterLink *link) } s->csp = av_pix_fmt_desc_get(link->format); + s->filter = filter; if (s->csp->comp[0].depth > 8) { s->filter_line = filter_line_c_16bit; s->filter_edges = filter_edges_16bit; @@ -507,37 +347,19 @@ static int config_props(AVFilterLink *link) } -#define OFFSET(x) offsetof(YADIFContext, x) -#define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM - -#define CONST(name, help, val, unit) { name, help, 0, AV_OPT_TYPE_CONST, {.i64=val}, INT_MIN, INT_MAX, FLAGS, unit } - -static const AVOption yadif_options[] = { - { "mode", "specify the interlacing mode", OFFSET(mode), AV_OPT_TYPE_INT, {.i64=YADIF_MODE_SEND_FRAME}, 0, 3, FLAGS, "mode"}, - CONST("send_frame", "send one frame for each frame", YADIF_MODE_SEND_FRAME, "mode"), - CONST("send_field", "send one frame for each field", YADIF_MODE_SEND_FIELD, "mode"), - CONST("send_frame_nospatial", "send one frame for each frame, but skip spatial interlacing check", YADIF_MODE_SEND_FRAME_NOSPATIAL, "mode"), - CONST("send_field_nospatial", "send one frame for each field, but skip spatial interlacing check", YADIF_MODE_SEND_FIELD_NOSPATIAL, "mode"), - - { "parity", "specify the assumed picture field parity", OFFSET(parity), AV_OPT_TYPE_INT, {.i64=YADIF_PARITY_AUTO}, -1, 1, FLAGS, "parity" }, - CONST("tff", "assume top field first", YADIF_PARITY_TFF, "parity"), - CONST("bff", "assume bottom field first", YADIF_PARITY_BFF, "parity"), - CONST("auto", "auto detect parity", YADIF_PARITY_AUTO, "parity"), - - { "deint", "specify which frames to deinterlace", OFFSET(deint), AV_OPT_TYPE_INT, {.i64=YADIF_DEINT_ALL}, 0, 1, FLAGS, "deint" }, - CONST("all", "deinterlace all frames", YADIF_DEINT_ALL, "deint"), - CONST("interlaced", "only deinterlace frames marked as interlaced", YADIF_DEINT_INTERLACED, "deint"), - - { NULL } +static const AVClass yadif_class = { + .class_name = "yadif", + .item_name = av_default_item_name, + .option = ff_yadif_options, + .version = LIBAVUTIL_VERSION_INT, + .category = AV_CLASS_CATEGORY_FILTER, }; -AVFILTER_DEFINE_CLASS(yadif); - static const AVFilterPad avfilter_vf_yadif_inputs[] = { { .name = "default", .type = AVMEDIA_TYPE_VIDEO, - .filter_frame = filter_frame, + .filter_frame = ff_yadif_filter_frame, }, { NULL } }; @@ -546,7 +368,7 @@ static const AVFilterPad avfilter_vf_yadif_outputs[] = { { .name = "default", .type = AVMEDIA_TYPE_VIDEO, - .request_frame = request_frame, + .request_frame = ff_yadif_request_frame, .config_props = config_props, }, { NULL } diff --git a/libavfilter/vf_yadif_cuda.c b/libavfilter/vf_yadif_cuda.c new file mode 100644 index 000000000..c9eb1a229 --- /dev/null +++ b/libavfilter/vf_yadif_cuda.c @@ -0,0 +1,387 @@ +/* + * Copyright (C) 2018 Philip Langdale + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/avassert.h" +#include "libavutil/hwcontext_cuda_internal.h" +#include "libavutil/cuda_check.h" +#include "internal.h" +#include "yadif.h" + +extern char vf_yadif_cuda_ptx[]; + +typedef struct DeintCUDAContext { + YADIFContext yadif; + + AVCUDADeviceContext *hwctx; + AVBufferRef *device_ref; + AVBufferRef *input_frames_ref; + AVHWFramesContext *input_frames; + + CUcontext cu_ctx; + CUstream stream; + CUmodule cu_module; + CUfunction cu_func_uchar; + CUfunction cu_func_uchar2; + CUfunction cu_func_ushort; + CUfunction cu_func_ushort2; +} DeintCUDAContext; + +#define DIV_UP(a, b) ( ((a) + (b) - 1) / (b) ) +#define ALIGN_UP(a, b) (((a) + (b) - 1) & ~((b) - 1)) +#define BLOCKX 32 +#define BLOCKY 16 + +#define CHECK_CU(x) FF_CUDA_CHECK_DL(ctx, s->hwctx->internal->cuda_dl, x) + +static CUresult call_kernel(AVFilterContext *ctx, CUfunction func, + CUdeviceptr prev, CUdeviceptr cur, CUdeviceptr next, + CUarray_format format, int channels, + int src_width, // Width is pixels per channel + int src_height, // Height is pixels per channel + int src_pitch, // Pitch is bytes + CUdeviceptr dst, + int dst_width, // Width is pixels per channel + int dst_height, // Height is pixels per channel + int dst_pitch, // Pitch is pixels per channel + int parity, int tff) +{ + DeintCUDAContext *s = ctx->priv; + CudaFunctions *cu = s->hwctx->internal->cuda_dl; + CUtexObject tex_prev = 0, tex_cur = 0, tex_next = 0; + int ret; + int skip_spatial_check = s->yadif.mode&2; + + void *args[] = { &dst, &tex_prev, &tex_cur, &tex_next, + &dst_width, &dst_height, &dst_pitch, + &src_width, &src_height, &parity, &tff, + &skip_spatial_check }; + + CUDA_TEXTURE_DESC tex_desc = { + .filterMode = CU_TR_FILTER_MODE_POINT, + .flags = CU_TRSF_READ_AS_INTEGER, + }; + + CUDA_RESOURCE_DESC res_desc = { + .resType = CU_RESOURCE_TYPE_PITCH2D, + .res.pitch2D.format = format, + .res.pitch2D.numChannels = channels, + .res.pitch2D.width = src_width, + .res.pitch2D.height = src_height, + .res.pitch2D.pitchInBytes = src_pitch, + }; + + res_desc.res.pitch2D.devPtr = (CUdeviceptr)prev; + ret = CHECK_CU(cu->cuTexObjectCreate(&tex_prev, &res_desc, &tex_desc, NULL)); + if (ret < 0) + goto exit; + + res_desc.res.pitch2D.devPtr = (CUdeviceptr)cur; + ret = CHECK_CU(cu->cuTexObjectCreate(&tex_cur, &res_desc, &tex_desc, NULL)); + if (ret < 0) + goto exit; + + res_desc.res.pitch2D.devPtr = (CUdeviceptr)next; + ret = CHECK_CU(cu->cuTexObjectCreate(&tex_next, &res_desc, &tex_desc, NULL)); + if (ret < 0) + goto exit; + + ret = CHECK_CU(cu->cuLaunchKernel(func, + DIV_UP(dst_width, BLOCKX), DIV_UP(dst_height, BLOCKY), 1, + BLOCKX, BLOCKY, 1, + 0, s->stream, args, NULL)); + +exit: + if (tex_prev) + CHECK_CU(cu->cuTexObjectDestroy(tex_prev)); + if (tex_cur) + CHECK_CU(cu->cuTexObjectDestroy(tex_cur)); + if (tex_next) + CHECK_CU(cu->cuTexObjectDestroy(tex_next)); + + return ret; +} + +static void filter(AVFilterContext *ctx, AVFrame *dst, + int parity, int tff) +{ + DeintCUDAContext *s = ctx->priv; + YADIFContext *y = &s->yadif; + CudaFunctions *cu = s->hwctx->internal->cuda_dl; + CUcontext dummy; + int i, ret; + + ret = CHECK_CU(cu->cuCtxPushCurrent(s->cu_ctx)); + if (ret < 0) + return; + + for (i = 0; i < y->csp->nb_components; i++) { + CUfunction func; + CUarray_format format; + int pixel_size, channels; + const AVComponentDescriptor *comp = &y->csp->comp[i]; + + if (comp->plane < i) { + // We process planes as a whole, so don't reprocess + // them for additional components + continue; + } + + pixel_size = (comp->depth + comp->shift) / 8; + channels = comp->step / pixel_size; + if (pixel_size > 2 || channels > 2) { + av_log(ctx, AV_LOG_ERROR, "Unsupported pixel format: %s\n", y->csp->name); + goto exit; + } + switch (pixel_size) { + case 1: + func = channels == 1 ? s->cu_func_uchar : s->cu_func_uchar2; + format = CU_AD_FORMAT_UNSIGNED_INT8; + break; + case 2: + func = channels == 1 ? s->cu_func_ushort : s->cu_func_ushort2; + format = CU_AD_FORMAT_UNSIGNED_INT16; + break; + default: + av_log(ctx, AV_LOG_ERROR, "Unsupported pixel format: %s\n", y->csp->name); + goto exit; + } + av_log(ctx, AV_LOG_TRACE, + "Deinterlacing plane %d: pixel_size: %d channels: %d\n", + comp->plane, pixel_size, channels); + call_kernel(ctx, func, + (CUdeviceptr)y->prev->data[i], + (CUdeviceptr)y->cur->data[i], + (CUdeviceptr)y->next->data[i], + format, channels, + AV_CEIL_RSHIFT(y->cur->width, i ? y->csp->log2_chroma_w : 0), + AV_CEIL_RSHIFT(y->cur->height, i ? y->csp->log2_chroma_h : 0), + y->cur->linesize[i], + (CUdeviceptr)dst->data[i], + AV_CEIL_RSHIFT(dst->width, i ? y->csp->log2_chroma_w : 0), + AV_CEIL_RSHIFT(dst->height, i ? y->csp->log2_chroma_h : 0), + dst->linesize[i] / comp->step, + parity, tff); + } + +exit: + CHECK_CU(cu->cuCtxPopCurrent(&dummy)); + return; +} + +static av_cold void deint_cuda_uninit(AVFilterContext *ctx) +{ + CUcontext dummy; + DeintCUDAContext *s = ctx->priv; + YADIFContext *y = &s->yadif; + + if (s->hwctx && s->cu_module) { + CudaFunctions *cu = s->hwctx->internal->cuda_dl; + CHECK_CU(cu->cuCtxPushCurrent(s->cu_ctx)); + CHECK_CU(cu->cuModuleUnload(s->cu_module)); + CHECK_CU(cu->cuCtxPopCurrent(&dummy)); + } + + av_frame_free(&y->prev); + av_frame_free(&y->cur); + av_frame_free(&y->next); + + av_buffer_unref(&s->device_ref); + s->hwctx = NULL; + av_buffer_unref(&s->input_frames_ref); + s->input_frames = NULL; +} + +static int deint_cuda_query_formats(AVFilterContext *ctx) +{ + enum AVPixelFormat pix_fmts[] = { + AV_PIX_FMT_CUDA, AV_PIX_FMT_NONE, + }; + int ret; + + if ((ret = ff_formats_ref(ff_make_format_list(pix_fmts), + &ctx->inputs[0]->out_formats)) < 0) + return ret; + if ((ret = ff_formats_ref(ff_make_format_list(pix_fmts), + &ctx->outputs[0]->in_formats)) < 0) + return ret; + + return 0; +} + +static int config_input(AVFilterLink *inlink) +{ + AVFilterContext *ctx = inlink->dst; + DeintCUDAContext *s = ctx->priv; + + if (!inlink->hw_frames_ctx) { + av_log(ctx, AV_LOG_ERROR, "A hardware frames reference is " + "required to associate the processing device.\n"); + return AVERROR(EINVAL); + } + + s->input_frames_ref = av_buffer_ref(inlink->hw_frames_ctx); + if (!s->input_frames_ref) { + av_log(ctx, AV_LOG_ERROR, "A input frames reference create " + "failed.\n"); + return AVERROR(ENOMEM); + } + s->input_frames = (AVHWFramesContext*)s->input_frames_ref->data; + + return 0; +} + +static int config_output(AVFilterLink *link) +{ + AVHWFramesContext *output_frames; + AVFilterContext *ctx = link->src; + DeintCUDAContext *s = ctx->priv; + YADIFContext *y = &s->yadif; + CudaFunctions *cu; + int ret = 0; + CUcontext dummy; + + av_assert0(s->input_frames); + s->device_ref = av_buffer_ref(s->input_frames->device_ref); + if (!s->device_ref) { + av_log(ctx, AV_LOG_ERROR, "A device reference create " + "failed.\n"); + return AVERROR(ENOMEM); + } + s->hwctx = ((AVHWDeviceContext*)s->device_ref->data)->hwctx; + s->cu_ctx = s->hwctx->cuda_ctx; + s->stream = s->hwctx->stream; + cu = s->hwctx->internal->cuda_dl; + + link->hw_frames_ctx = av_hwframe_ctx_alloc(s->device_ref); + if (!link->hw_frames_ctx) { + av_log(ctx, AV_LOG_ERROR, "Failed to create HW frame context " + "for output.\n"); + ret = AVERROR(ENOMEM); + goto exit; + } + + output_frames = (AVHWFramesContext*)link->hw_frames_ctx->data; + + output_frames->format = AV_PIX_FMT_CUDA; + output_frames->sw_format = s->input_frames->sw_format; + output_frames->width = ctx->inputs[0]->w; + output_frames->height = ctx->inputs[0]->h; + + output_frames->initial_pool_size = 4; + + ret = ff_filter_init_hw_frames(ctx, link, 10); + if (ret < 0) + goto exit; + + ret = av_hwframe_ctx_init(link->hw_frames_ctx); + if (ret < 0) { + av_log(ctx, AV_LOG_ERROR, "Failed to initialise CUDA frame " + "context for output: %d\n", ret); + goto exit; + } + + link->time_base.num = ctx->inputs[0]->time_base.num; + link->time_base.den = ctx->inputs[0]->time_base.den * 2; + link->w = ctx->inputs[0]->w; + link->h = ctx->inputs[0]->h; + + if(y->mode & 1) + link->frame_rate = av_mul_q(ctx->inputs[0]->frame_rate, + (AVRational){2, 1}); + + if (link->w < 3 || link->h < 3) { + av_log(ctx, AV_LOG_ERROR, "Video of less than 3 columns or lines is not supported\n"); + ret = AVERROR(EINVAL); + goto exit; + } + + y->csp = av_pix_fmt_desc_get(output_frames->sw_format); + y->filter = filter; + + ret = CHECK_CU(cu->cuCtxPushCurrent(s->cu_ctx)); + if (ret < 0) + goto exit; + + ret = CHECK_CU(cu->cuModuleLoadData(&s->cu_module, vf_yadif_cuda_ptx)); + if (ret < 0) + goto exit; + + ret = CHECK_CU(cu->cuModuleGetFunction(&s->cu_func_uchar, s->cu_module, "yadif_uchar")); + if (ret < 0) + goto exit; + + ret = CHECK_CU(cu->cuModuleGetFunction(&s->cu_func_uchar2, s->cu_module, "yadif_uchar2")); + if (ret < 0) + goto exit; + + ret = CHECK_CU(cu->cuModuleGetFunction(&s->cu_func_ushort, s->cu_module, "yadif_ushort")); + if (ret < 0) + goto exit; + + ret = CHECK_CU(cu->cuModuleGetFunction(&s->cu_func_ushort2, s->cu_module, "yadif_ushort2")); + if (ret < 0) + goto exit; + +exit: + CHECK_CU(cu->cuCtxPopCurrent(&dummy)); + + return ret; +} + +static const AVClass yadif_cuda_class = { + .class_name = "yadif_cuda", + .item_name = av_default_item_name, + .option = ff_yadif_options, + .version = LIBAVUTIL_VERSION_INT, + .category = AV_CLASS_CATEGORY_FILTER, +}; + +static const AVFilterPad deint_cuda_inputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + .filter_frame = ff_yadif_filter_frame, + .config_props = config_input, + }, + { NULL } +}; + +static const AVFilterPad deint_cuda_outputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + .request_frame = ff_yadif_request_frame, + .config_props = config_output, + }, + { NULL } +}; + +AVFilter ff_vf_yadif_cuda = { + .name = "yadif_cuda", + .description = NULL_IF_CONFIG_SMALL("Deinterlace CUDA frames"), + .priv_size = sizeof(DeintCUDAContext), + .priv_class = &yadif_cuda_class, + .uninit = deint_cuda_uninit, + .query_formats = deint_cuda_query_formats, + .inputs = deint_cuda_inputs, + .outputs = deint_cuda_outputs, + .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, + .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE, +}; diff --git a/libavfilter/vf_yadif_cuda.cu b/libavfilter/vf_yadif_cuda.cu new file mode 100644 index 000000000..12e7e4a44 --- /dev/null +++ b/libavfilter/vf_yadif_cuda.cu @@ -0,0 +1,299 @@ +/* + * Copyright (C) 2018 Philip Langdale + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +template +__inline__ __device__ T spatial_predictor(T a, T b, T c, T d, T e, T f, T g, + T h, T i, T j, T k, T l, T m, T n) +{ + int spatial_pred = (d + k)/2; + int spatial_score = abs(c - j) + abs(d - k) + abs(e - l); + + int score = abs(b - k) + abs(c - l) + abs(d - m); + if (score < spatial_score) { + spatial_pred = (c + l)/2; + spatial_score = score; + score = abs(a - l) + abs(b - m) + abs(c - n); + if (score < spatial_score) { + spatial_pred = (b + m)/2; + spatial_score = score; + } + } + score = abs(d - i) + abs(e - j) + abs(f - k); + if (score < spatial_score) { + spatial_pred = (e + j)/2; + spatial_score = score; + score = abs(e - h) + abs(f - i) + abs(g - j); + if (score < spatial_score) { + spatial_pred = (f + i)/2; + spatial_score = score; + } + } + return spatial_pred; +} + +__inline__ __device__ int max3(int a, int b, int c) +{ + int x = max(a, b); + return max(x, c); +} + +__inline__ __device__ int min3(int a, int b, int c) +{ + int x = min(a, b); + return min(x, c); +} + +template +__inline__ __device__ T temporal_predictor(T A, T B, T C, T D, T E, T F, + T G, T H, T I, T J, T K, T L, + T spatial_pred, bool skip_check) +{ + int p0 = (C + H) / 2; + int p1 = F; + int p2 = (D + I) / 2; + int p3 = G; + int p4 = (E + J) / 2; + + int tdiff0 = abs(D - I); + int tdiff1 = (abs(A - F) + abs(B - G)) / 2; + int tdiff2 = (abs(K - F) + abs(G - L)) / 2; + + int diff = max3(tdiff0, tdiff1, tdiff2); + + if (!skip_check) { + int maxi = max3(p2 - p3, p2 - p1, min(p0 - p1, p4 - p3)); + int mini = min3(p2 - p3, p2 - p1, max(p0 - p1, p4 - p3)); + diff = max3(diff, mini, -maxi); + } + + if (spatial_pred > p2 + diff) { + spatial_pred = p2 + diff; + } + if (spatial_pred < p2 - diff) { + spatial_pred = p2 - diff; + } + + return spatial_pred; +} + +template +__inline__ __device__ void yadif_single(T *dst, + cudaTextureObject_t prev, + cudaTextureObject_t cur, + cudaTextureObject_t next, + int dst_width, int dst_height, int dst_pitch, + int src_width, int src_height, + int parity, int tff, bool skip_spatial_check) +{ + // Identify location + int xo = blockIdx.x * blockDim.x + threadIdx.x; + int yo = blockIdx.y * blockDim.y + threadIdx.y; + + if (xo >= dst_width || yo >= dst_height) { + return; + } + + // Don't modify the primary field + if (yo % 2 == parity) { + dst[yo*dst_pitch+xo] = tex2D(cur, xo, yo); + return; + } + + // Calculate spatial prediction + T a = tex2D(cur, xo - 3, yo - 1); + T b = tex2D(cur, xo - 2, yo - 1); + T c = tex2D(cur, xo - 1, yo - 1); + T d = tex2D(cur, xo - 0, yo - 1); + T e = tex2D(cur, xo + 1, yo - 1); + T f = tex2D(cur, xo + 2, yo - 1); + T g = tex2D(cur, xo + 3, yo - 1); + + T h = tex2D(cur, xo - 3, yo + 1); + T i = tex2D(cur, xo - 2, yo + 1); + T j = tex2D(cur, xo - 1, yo + 1); + T k = tex2D(cur, xo - 0, yo + 1); + T l = tex2D(cur, xo + 1, yo + 1); + T m = tex2D(cur, xo + 2, yo + 1); + T n = tex2D(cur, xo + 3, yo + 1); + + T spatial_pred = + spatial_predictor(a, b, c, d, e, f, g, h, i, j, k, l, m, n); + + // Calculate temporal prediction + int is_second_field = !(parity ^ tff); + + cudaTextureObject_t prev2 = prev; + cudaTextureObject_t prev1 = is_second_field ? cur : prev; + cudaTextureObject_t next1 = is_second_field ? next : cur; + cudaTextureObject_t next2 = next; + + T A = tex2D(prev2, xo, yo - 1); + T B = tex2D(prev2, xo, yo + 1); + T C = tex2D(prev1, xo, yo - 2); + T D = tex2D(prev1, xo, yo + 0); + T E = tex2D(prev1, xo, yo + 2); + T F = tex2D(cur, xo, yo - 1); + T G = tex2D(cur, xo, yo + 1); + T H = tex2D(next1, xo, yo - 2); + T I = tex2D(next1, xo, yo + 0); + T J = tex2D(next1, xo, yo + 2); + T K = tex2D(next2, xo, yo - 1); + T L = tex2D(next2, xo, yo + 1); + + spatial_pred = temporal_predictor(A, B, C, D, E, F, G, H, I, J, K, L, + spatial_pred, skip_spatial_check); + + dst[yo*dst_pitch+xo] = spatial_pred; +} + +template +__inline__ __device__ void yadif_double(T *dst, + cudaTextureObject_t prev, + cudaTextureObject_t cur, + cudaTextureObject_t next, + int dst_width, int dst_height, int dst_pitch, + int src_width, int src_height, + int parity, int tff, bool skip_spatial_check) +{ + int xo = blockIdx.x * blockDim.x + threadIdx.x; + int yo = blockIdx.y * blockDim.y + threadIdx.y; + + if (xo >= dst_width || yo >= dst_height) { + return; + } + + if (yo % 2 == parity) { + // Don't modify the primary field + dst[yo*dst_pitch+xo] = tex2D(cur, xo, yo); + return; + } + + T a = tex2D(cur, xo - 3, yo - 1); + T b = tex2D(cur, xo - 2, yo - 1); + T c = tex2D(cur, xo - 1, yo - 1); + T d = tex2D(cur, xo - 0, yo - 1); + T e = tex2D(cur, xo + 1, yo - 1); + T f = tex2D(cur, xo + 2, yo - 1); + T g = tex2D(cur, xo + 3, yo - 1); + + T h = tex2D(cur, xo - 3, yo + 1); + T i = tex2D(cur, xo - 2, yo + 1); + T j = tex2D(cur, xo - 1, yo + 1); + T k = tex2D(cur, xo - 0, yo + 1); + T l = tex2D(cur, xo + 1, yo + 1); + T m = tex2D(cur, xo + 2, yo + 1); + T n = tex2D(cur, xo + 3, yo + 1); + + T spatial_pred; + spatial_pred.x = + spatial_predictor(a.x, b.x, c.x, d.x, e.x, f.x, g.x, h.x, i.x, j.x, k.x, l.x, m.x, n.x); + spatial_pred.y = + spatial_predictor(a.y, b.y, c.y, d.y, e.y, f.y, g.y, h.y, i.y, j.y, k.y, l.y, m.y, n.y); + + // Calculate temporal prediction + int is_second_field = !(parity ^ tff); + + cudaTextureObject_t prev2 = prev; + cudaTextureObject_t prev1 = is_second_field ? cur : prev; + cudaTextureObject_t next1 = is_second_field ? next : cur; + cudaTextureObject_t next2 = next; + + T A = tex2D(prev2, xo, yo - 1); + T B = tex2D(prev2, xo, yo + 1); + T C = tex2D(prev1, xo, yo - 2); + T D = tex2D(prev1, xo, yo + 0); + T E = tex2D(prev1, xo, yo + 2); + T F = tex2D(cur, xo, yo - 1); + T G = tex2D(cur, xo, yo + 1); + T H = tex2D(next1, xo, yo - 2); + T I = tex2D(next1, xo, yo + 0); + T J = tex2D(next1, xo, yo + 2); + T K = tex2D(next2, xo, yo - 1); + T L = tex2D(next2, xo, yo + 1); + + spatial_pred.x = + temporal_predictor(A.x, B.x, C.x, D.x, E.x, F.x, G.x, H.x, I.x, J.x, K.x, L.x, + spatial_pred.x, skip_spatial_check); + spatial_pred.y = + temporal_predictor(A.y, B.y, C.y, D.y, E.y, F.y, G.y, H.y, I.y, J.y, K.y, L.y, + spatial_pred.y, skip_spatial_check); + + dst[yo*dst_pitch+xo] = spatial_pred; +} + +extern "C" { + +__global__ void yadif_uchar(unsigned char *dst, + cudaTextureObject_t prev, + cudaTextureObject_t cur, + cudaTextureObject_t next, + int dst_width, int dst_height, int dst_pitch, + int src_width, int src_height, + int parity, int tff, bool skip_spatial_check) +{ + yadif_single(dst, prev, cur, next, + dst_width, dst_height, dst_pitch, + src_width, src_height, + parity, tff, skip_spatial_check); +} + +__global__ void yadif_ushort(unsigned short *dst, + cudaTextureObject_t prev, + cudaTextureObject_t cur, + cudaTextureObject_t next, + int dst_width, int dst_height, int dst_pitch, + int src_width, int src_height, + int parity, int tff, bool skip_spatial_check) +{ + yadif_single(dst, prev, cur, next, + dst_width, dst_height, dst_pitch, + src_width, src_height, + parity, tff, skip_spatial_check); +} + +__global__ void yadif_uchar2(uchar2 *dst, + cudaTextureObject_t prev, + cudaTextureObject_t cur, + cudaTextureObject_t next, + int dst_width, int dst_height, int dst_pitch, + int src_width, int src_height, + int parity, int tff, bool skip_spatial_check) +{ + yadif_double(dst, prev, cur, next, + dst_width, dst_height, dst_pitch, + src_width, src_height, + parity, tff, skip_spatial_check); +} + +__global__ void yadif_ushort2(ushort2 *dst, + cudaTextureObject_t prev, + cudaTextureObject_t cur, + cudaTextureObject_t next, + int dst_width, int dst_height, int dst_pitch, + int src_width, int src_height, + int parity, int tff, bool skip_spatial_check) +{ + yadif_double(dst, prev, cur, next, + dst_width, dst_height, dst_pitch, + src_width, src_height, + parity, tff, skip_spatial_check); +} + +} /* extern "C" */ diff --git a/libavfilter/vf_zoompan.c b/libavfilter/vf_zoompan.c index 0635171b5..dea10d513 100644 --- a/libavfilter/vf_zoompan.c +++ b/libavfilter/vf_zoompan.c @@ -167,7 +167,7 @@ static int output_single_frame(AVFilterContext *ctx, AVFrame *in, double *var_va var_values[VAR_PDURATION] = s->prev_nb_frames; var_values[VAR_TIME] = pts * av_q2d(outlink->time_base); var_values[VAR_FRAME] = i; - var_values[VAR_ON] = outlink->frame_count_in + 1; + var_values[VAR_ON] = outlink->frame_count_in; *zoom = av_expr_eval(s->zoom_expr, var_values, NULL); @@ -274,8 +274,8 @@ static int activate(AVFilterContext *ctx) s->var_values[VAR_IN_H] = s->var_values[VAR_IH] = s->in->height; s->var_values[VAR_OUT_W] = s->var_values[VAR_OW] = s->w; s->var_values[VAR_OUT_H] = s->var_values[VAR_OH] = s->h; - s->var_values[VAR_IN] = inlink->frame_count_out + 1; - s->var_values[VAR_ON] = outlink->frame_count_in + 1; + s->var_values[VAR_IN] = inlink->frame_count_out - 1; + s->var_values[VAR_ON] = outlink->frame_count_in; s->var_values[VAR_PX] = s->x; s->var_values[VAR_PY] = s->y; s->var_values[VAR_X] = 0; diff --git a/libavfilter/vf_zscale.c b/libavfilter/vf_zscale.c index 6e1d36cb4..f0309272f 100644 --- a/libavfilter/vf_zscale.c +++ b/libavfilter/vf_zscale.c @@ -859,13 +859,7 @@ static const AVOption zscale_options[] = { { NULL } }; -static const AVClass zscale_class = { - .class_name = "zscale", - .item_name = av_default_item_name, - .option = zscale_options, - .version = LIBAVUTIL_VERSION_INT, - .category = AV_CLASS_CATEGORY_FILTER, -}; +AVFILTER_DEFINE_CLASS(zscale); static const AVFilterPad avfilter_vf_zscale_inputs[] = { { diff --git a/libavfilter/vsrc_testsrc.c b/libavfilter/vsrc_testsrc.c index a790974d1..f06714807 100644 --- a/libavfilter/vsrc_testsrc.c +++ b/libavfilter/vsrc_testsrc.c @@ -1252,7 +1252,7 @@ AVFilter ff_vsrc_yuvtestsrc = { #endif /* CONFIG_YUVTESTSRC_FILTER */ -#if CONFIG_SMPTEBARS_FILTER || CONFIG_SMPTEHDBARS_FILTER +#if CONFIG_PAL75BARS_FILTER || CONFIG_PAL100BARS_FILTER || CONFIG_SMPTEBARS_FILTER || CONFIG_SMPTEHDBARS_FILTER static const uint8_t rainbow[7][4] = { { 180, 128, 128, 255 }, /* 75% white */ @@ -1264,6 +1264,16 @@ static const uint8_t rainbow[7][4] = { { 35, 212, 114, 255 }, /* 75% blue */ }; +static const uint8_t rainbow100[7][4] = { + { 235, 128, 128, 255 }, /* 100% white */ + { 210, 16, 146, 255 }, /* 100% yellow */ + { 170, 166, 16, 255 }, /* 100% cyan */ + { 145, 54, 34, 255 }, /* 100% green */ + { 106, 202, 222, 255 }, /* 100% magenta */ + { 81, 90, 240, 255 }, /* 100% red */ + { 41, 240, 110, 255 }, /* 100% blue */ +}; + static const uint8_t rainbowhd[7][4] = { { 180, 128, 128, 255 }, /* 75% white */ { 168, 44, 136, 255 }, /* 75% yellow */ @@ -1371,6 +1381,100 @@ static const AVFilterPad smptebars_outputs[] = { { NULL } }; +#if CONFIG_PAL75BARS_FILTER + +#define pal75bars_options options +AVFILTER_DEFINE_CLASS(pal75bars); + +static void pal75bars_fill_picture(AVFilterContext *ctx, AVFrame *picref) +{ + TestSourceContext *test = ctx->priv; + int r_w, i, x = 0; + const AVPixFmtDescriptor *pixdesc = av_pix_fmt_desc_get(picref->format); + + picref->color_range = AVCOL_RANGE_MPEG; + picref->colorspace = AVCOL_SPC_BT470BG; + + r_w = FFALIGN((test->w + 7) / 8, 1 << pixdesc->log2_chroma_w); + + draw_bar(test, white, x, 0, r_w, test->h, picref); + x += r_w; + for (i = 1; i < 7; i++) { + draw_bar(test, rainbow[i], x, 0, r_w, test->h, picref); + x += r_w; + } + draw_bar(test, black0, x, 0, r_w, test->h, picref); +} + +static av_cold int pal75bars_init(AVFilterContext *ctx) +{ + TestSourceContext *test = ctx->priv; + + test->fill_picture_fn = pal75bars_fill_picture; + test->draw_once = 1; + return init(ctx); +} + +AVFilter ff_vsrc_pal75bars = { + .name = "pal75bars", + .description = NULL_IF_CONFIG_SMALL("Generate PAL 75% color bars."), + .priv_size = sizeof(TestSourceContext), + .priv_class = &pal75bars_class, + .init = pal75bars_init, + .uninit = uninit, + .query_formats = smptebars_query_formats, + .inputs = NULL, + .outputs = smptebars_outputs, +}; + +#endif /* CONFIG_PAL75BARS_FILTER */ + +#if CONFIG_PAL100BARS_FILTER + +#define pal100bars_options options +AVFILTER_DEFINE_CLASS(pal100bars); + +static void pal100bars_fill_picture(AVFilterContext *ctx, AVFrame *picref) +{ + TestSourceContext *test = ctx->priv; + int r_w, i, x = 0; + const AVPixFmtDescriptor *pixdesc = av_pix_fmt_desc_get(picref->format); + + picref->color_range = AVCOL_RANGE_MPEG; + picref->colorspace = AVCOL_SPC_BT470BG; + + r_w = FFALIGN((test->w + 7) / 8, 1 << pixdesc->log2_chroma_w); + + for (i = 0; i < 7; i++) { + draw_bar(test, rainbow100[i], x, 0, r_w, test->h, picref); + x += r_w; + } + draw_bar(test, black0, x, 0, r_w, test->h, picref); +} + +static av_cold int pal100bars_init(AVFilterContext *ctx) +{ + TestSourceContext *test = ctx->priv; + + test->fill_picture_fn = pal100bars_fill_picture; + test->draw_once = 1; + return init(ctx); +} + +AVFilter ff_vsrc_pal100bars = { + .name = "pal100bars", + .description = NULL_IF_CONFIG_SMALL("Generate PAL 100% color bars."), + .priv_size = sizeof(TestSourceContext), + .priv_class = &pal100bars_class, + .init = pal100bars_init, + .uninit = uninit, + .query_formats = smptebars_query_formats, + .inputs = NULL, + .outputs = smptebars_outputs, +}; + +#endif /* CONFIG_PAL100BARS_FILTER */ + #if CONFIG_SMPTEBARS_FILTER #define smptebars_options options diff --git a/libavfilter/window_func.h b/libavfilter/window_func.h index a94482c93..1de8f1fbd 100644 --- a/libavfilter/window_func.h +++ b/libavfilter/window_func.h @@ -30,6 +30,7 @@ enum WindowFunc { WFUNC_RECT, WFUNC_HANNING, WFUNC_HAMMING, WFUNC_BLACKMAN, WFUNC_BHARRIS, WFUNC_BNUTTALL, WFUNC_SINE, WFUNC_NUTTALL, WFUNC_BHANN, WFUNC_LANCZOS, WFUNC_GAUSS, WFUNC_TUKEY, WFUNC_DOLPH, WFUNC_CAUCHY, WFUNC_PARZEN, WFUNC_POISSON, + WFUNC_BOHMAN, NB_WFUNC }; static inline void generate_window_func(float *lut, int N, int win_func, @@ -182,6 +183,14 @@ static inline void generate_window_func(float *lut, int N, int win_func, } *overlap = 0.75; break; + case WFUNC_BOHMAN: + for (n = 0; n < N; n++) { + double x = 2 * ((n / (double)(N - 1))) - 1.; + + lut[n] = (1 - fabs(x)) * cos(M_PI*fabs(x)) + 1./M_PI*sin(M_PI*fabs(x)); + } + *overlap = 0.75; + break; default: av_assert0(0); } diff --git a/libavfilter/x86/Makefile b/libavfilter/x86/Makefile index 4d4c5e503..6b0361bed 100644 --- a/libavfilter/x86/Makefile +++ b/libavfilter/x86/Makefile @@ -1,18 +1,23 @@ +OBJS-$(CONFIG_SCENE_SAD) += x86/scene_sad_init.o + OBJS-$(CONFIG_AFIR_FILTER) += x86/af_afir_init.o +OBJS-$(CONFIG_ANLMDN_FILTER) += x86/af_anlmdn_init.o OBJS-$(CONFIG_BLEND_FILTER) += x86/vf_blend_init.o OBJS-$(CONFIG_BWDIF_FILTER) += x86/vf_bwdif_init.o OBJS-$(CONFIG_COLORSPACE_FILTER) += x86/colorspacedsp_init.o OBJS-$(CONFIG_EQ_FILTER) += x86/vf_eq.o OBJS-$(CONFIG_FSPP_FILTER) += x86/vf_fspp_init.o +OBJS-$(CONFIG_GBLUR_FILTER) += x86/vf_gblur_init.o OBJS-$(CONFIG_GRADFUN_FILTER) += x86/vf_gradfun_init.o OBJS-$(CONFIG_FRAMERATE_FILTER) += x86/vf_framerate_init.o OBJS-$(CONFIG_HFLIP_FILTER) += x86/vf_hflip_init.o OBJS-$(CONFIG_HQDN3D_FILTER) += x86/vf_hqdn3d_init.o OBJS-$(CONFIG_IDET_FILTER) += x86/vf_idet_init.o -OBJS-$(CONFIG_INTERLACE_FILTER) += x86/vf_interlace_init.o +OBJS-$(CONFIG_INTERLACE_FILTER) += x86/vf_tinterlace_init.o OBJS-$(CONFIG_LIMITER_FILTER) += x86/vf_limiter_init.o OBJS-$(CONFIG_MASKEDMERGE_FILTER) += x86/vf_maskedmerge_init.o OBJS-$(CONFIG_NOISE_FILTER) += x86/vf_noise.o +OBJS-$(CONFIG_OVERLAY_FILTER) += x86/vf_overlay_init.o OBJS-$(CONFIG_PP7_FILTER) += x86/vf_pp7_init.o OBJS-$(CONFIG_PSNR_FILTER) += x86/vf_psnr_init.o OBJS-$(CONFIG_PULLUP_FILTER) += x86/vf_pullup_init.o @@ -28,12 +33,16 @@ OBJS-$(CONFIG_VOLUME_FILTER) += x86/af_volume_init.o OBJS-$(CONFIG_W3FDIF_FILTER) += x86/vf_w3fdif_init.o OBJS-$(CONFIG_YADIF_FILTER) += x86/vf_yadif_init.o +X86ASM-OBJS-$(CONFIG_SCENE_SAD) += x86/scene_sad.o + X86ASM-OBJS-$(CONFIG_AFIR_FILTER) += x86/af_afir.o +X86ASM-OBJS-$(CONFIG_ANLMDN_FILTER) += x86/af_anlmdn.o X86ASM-OBJS-$(CONFIG_BLEND_FILTER) += x86/vf_blend.o X86ASM-OBJS-$(CONFIG_BWDIF_FILTER) += x86/vf_bwdif.o X86ASM-OBJS-$(CONFIG_COLORSPACE_FILTER) += x86/colorspacedsp.o X86ASM-OBJS-$(CONFIG_FRAMERATE_FILTER) += x86/vf_framerate.o X86ASM-OBJS-$(CONFIG_FSPP_FILTER) += x86/vf_fspp.o +X86ASM-OBJS-$(CONFIG_GBLUR_FILTER) += x86/vf_gblur.o X86ASM-OBJS-$(CONFIG_GRADFUN_FILTER) += x86/vf_gradfun.o X86ASM-OBJS-$(CONFIG_HFLIP_FILTER) += x86/vf_hflip.o X86ASM-OBJS-$(CONFIG_HQDN3D_FILTER) += x86/vf_hqdn3d.o @@ -41,6 +50,7 @@ X86ASM-OBJS-$(CONFIG_IDET_FILTER) += x86/vf_idet.o X86ASM-OBJS-$(CONFIG_INTERLACE_FILTER) += x86/vf_interlace.o X86ASM-OBJS-$(CONFIG_LIMITER_FILTER) += x86/vf_limiter.o X86ASM-OBJS-$(CONFIG_MASKEDMERGE_FILTER) += x86/vf_maskedmerge.o +X86ASM-OBJS-$(CONFIG_OVERLAY_FILTER) += x86/vf_overlay.o X86ASM-OBJS-$(CONFIG_PP7_FILTER) += x86/vf_pp7.o X86ASM-OBJS-$(CONFIG_PSNR_FILTER) += x86/vf_psnr.o X86ASM-OBJS-$(CONFIG_PULLUP_FILTER) += x86/vf_pullup.o diff --git a/libavfilter/x86/af_afir.asm b/libavfilter/x86/af_afir.asm index 849d85e70..2cc09709a 100644 --- a/libavfilter/x86/af_afir.asm +++ b/libavfilter/x86/af_afir.asm @@ -27,10 +27,9 @@ SECTION .text ; void ff_fcmul_add(float *sum, const float *t, const float *c, int len) ;------------------------------------------------------------------------------ -INIT_XMM sse3 +%macro FCMUL_ADD 0 cglobal fcmul_add, 4,4,6, sum, t, c, len shl lend, 3 - add lend, mmsize*2 add tq, lenq add cq, lenq add sumq, lenq @@ -41,20 +40,30 @@ ALIGN 16 movsldup m3, [tq + lenq+mmsize] movaps m1, [cq + lenq] movaps m4, [cq + lenq+mmsize] - mulps m0, m1 - mulps m3, m4 - shufps m1, m1, 0xb1 - shufps m4, m4, 0xb1 + mulps m0, m0, m1 + mulps m3, m3, m4 + shufps m1, m1, m1, 0xb1 + shufps m4, m4, m4, 0xb1 movshdup m2, [tq + lenq] movshdup m5, [tq + lenq+mmsize] - mulps m2, m1 - mulps m5, m4 - addsubps m0, m2 - addsubps m3, m5 - addps m0, [sumq + lenq] - addps m3, [sumq + lenq+mmsize] + mulps m2, m2, m1 + mulps m5, m5, m4 + addsubps m0, m0, m2 + addsubps m3, m3, m5 + addps m0, m0, [sumq + lenq] + addps m3, m3, [sumq + lenq+mmsize] movaps [sumq + lenq], m0 movaps [sumq + lenq+mmsize], m3 add lenq, mmsize*2 jl .loop - REP_RET + movss xm0, [tq + lenq] + mulss xm0, [cq + lenq] + addss xm0, [sumq + lenq] + movss [sumq + lenq], xm0 + RET +%endmacro + +INIT_XMM sse3 +FCMUL_ADD +INIT_YMM avx +FCMUL_ADD diff --git a/libavfilter/x86/af_afir_init.c b/libavfilter/x86/af_afir_init.c index 6a652b9b8..c37212c38 100644 --- a/libavfilter/x86/af_afir_init.c +++ b/libavfilter/x86/af_afir_init.c @@ -24,12 +24,17 @@ void ff_fcmul_add_sse3(float *sum, const float *t, const float *c, ptrdiff_t len); +void ff_fcmul_add_avx(float *sum, const float *t, const float *c, + ptrdiff_t len); -av_cold void ff_afir_init_x86(AudioFIRContext *s) +av_cold void ff_afir_init_x86(AudioFIRDSPContext *s) { int cpu_flags = av_get_cpu_flags(); if (EXTERNAL_SSE3(cpu_flags)) { s->fcmul_add = ff_fcmul_add_sse3; } + if (EXTERNAL_AVX_FAST(cpu_flags)) { + s->fcmul_add = ff_fcmul_add_avx; + } } diff --git a/libavfilter/x86/af_anlmdn.asm b/libavfilter/x86/af_anlmdn.asm new file mode 100644 index 000000000..7986cf443 --- /dev/null +++ b/libavfilter/x86/af_anlmdn.asm @@ -0,0 +1,80 @@ +;***************************************************************************** +;* x86-optimized functions for anlmdn filter +;* Copyright (c) 2017 Paul B Mahol +;* +;* This file is part of FFmpeg. +;* +;* FFmpeg is free software; you can redistribute it and/or +;* modify it under the terms of the GNU Lesser General Public +;* License as published by the Free Software Foundation; either +;* version 2.1 of the License, or (at your option) any later version. +;* +;* FFmpeg is distributed in the hope that it will be useful, +;* but WITHOUT ANY WARRANTY; without even the implied warranty of +;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +;* Lesser General Public License for more details. +;* +;* You should have received a copy of the GNU Lesser General Public +;* License along with FFmpeg; if not, write to the Free Software +;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +;****************************************************************************** + +%include "libavutil/x86/x86util.asm" + +SECTION .text + +;------------------------------------------------------------------------------ +; float ff_compute_distance_ssd(float *f1, const float *f2, ptrdiff_t len) +;------------------------------------------------------------------------------ + +INIT_XMM sse +cglobal compute_distance_ssd, 3,5,3, f1, f2, len, r, x + mov xq, lenq + shl xq, 2 + neg xq + add f1q, xq + add f2q, xq + xor xq, xq + shl lenq, 1 + add lenq, 1 + shl lenq, 2 + mov rq, lenq + and rq, mmsize - 1 + xorps m0, m0 + cmp lenq, mmsize + jl .loop1 + sub lenq, rq +ALIGN 16 + .loop0: + movups m1, [f1q + xq] + movups m2, [f2q + xq] + subps m1, m2 + mulps m1, m1 + addps m0, m1 + add xq, mmsize + cmp xq, lenq + jl .loop0 + + movhlps xmm1, xmm0 + addps xmm0, xmm1 + movss xmm1, xmm0 + shufps xmm0, xmm0, 1 + addss xmm0, xmm1 + + cmp rq, 0 + je .end + add lenq, rq + .loop1: + movss xm1, [f1q + xq] + subss xm1, [f2q + xq] + mulss xm1, xm1 + addss xm0, xm1 + add xq, 4 + cmp xq, lenq + jl .loop1 + .end: +%if ARCH_X86_64 == 0 + movss r0m, xm0 + fld dword r0m +%endif + RET diff --git a/libavfilter/x86/af_anlmdn_init.c b/libavfilter/x86/af_anlmdn_init.c new file mode 100644 index 000000000..30eff6f64 --- /dev/null +++ b/libavfilter/x86/af_anlmdn_init.c @@ -0,0 +1,35 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" +#include "libavutil/attributes.h" +#include "libavutil/cpu.h" +#include "libavutil/x86/cpu.h" +#include "libavfilter/af_anlmdndsp.h" + +float ff_compute_distance_ssd_sse(const float *f1, const float *f2, + ptrdiff_t len); + +av_cold void ff_anlmdn_init_x86(AudioNLMDNDSPContext *s) +{ + int cpu_flags = av_get_cpu_flags(); + + if (EXTERNAL_SSE(cpu_flags)) { + s->compute_distance_ssd = ff_compute_distance_ssd_sse; + } +} diff --git a/libavfilter/x86/scene_sad.asm b/libavfilter/x86/scene_sad.asm new file mode 100644 index 000000000..d38d71ccc --- /dev/null +++ b/libavfilter/x86/scene_sad.asm @@ -0,0 +1,74 @@ +;***************************************************************************** +;* x86-optimized functions for scene SAD +;* +;* Copyright (C) 2018 Marton Balint +;* +;* Based on vf_blend.asm, Copyright (C) 2015 Paul B Mahol +;* +;* This file is part of FFmpeg. +;* +;* FFmpeg is free software; you can redistribute it and/or +;* modify it under the terms of the GNU Lesser General Public +;* License as published by the Free Software Foundation; either +;* version 2.1 of the License, or (at your option) any later version. +;* +;* FFmpeg is distributed in the hope that it will be useful, +;* but WITHOUT ANY WARRANTY; without even the implied warranty of +;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +;* Lesser General Public License for more details. +;* +;* You should have received a copy of the GNU Lesser General Public +;* License along with FFmpeg; if not, write to the Free Software +;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +;****************************************************************************** + +%include "libavutil/x86/x86util.asm" + +SECTION .text + + +%macro SAD_INIT 0 +cglobal scene_sad, 6, 7, 2, src1, stride1, src2, stride2, width, end, x + add src1q, widthq + add src2q, widthq + neg widthq + pxor m1, m1 +%endmacro + + +%macro SAD_LOOP 0 +.nextrow: + mov xq, widthq + + .loop: + movu m0, [src1q + xq] + psadbw m0, [src2q + xq] + paddq m1, m0 + add xq, mmsize + jl .loop + add src1q, stride1q + add src2q, stride2q + sub endd, 1 + jg .nextrow + + mov r0q, r6mp + movu [r0q], m1 ; sum +REP_RET +%endmacro + + +%macro SAD_FRAMES 0 + SAD_INIT + SAD_LOOP +%endmacro + + +INIT_XMM sse2 +SAD_FRAMES + +%if HAVE_AVX2_EXTERNAL + +INIT_YMM avx2 +SAD_FRAMES + +%endif diff --git a/libavfilter/x86/scene_sad_init.c b/libavfilter/x86/scene_sad_init.c new file mode 100644 index 000000000..f8104dcb4 --- /dev/null +++ b/libavfilter/x86/scene_sad_init.c @@ -0,0 +1,60 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/cpu.h" +#include "libavutil/x86/cpu.h" +#include "libavfilter/scene_sad.h" + +#define SCENE_SAD_FUNC(FUNC_NAME, ASM_FUNC_NAME, MMSIZE) \ +void ASM_FUNC_NAME(SCENE_SAD_PARAMS); \ + \ +static void FUNC_NAME(SCENE_SAD_PARAMS) { \ + uint64_t sad[MMSIZE / 8] = {0}; \ + ptrdiff_t awidth = width & ~(MMSIZE - 1); \ + *sum = 0; \ + ASM_FUNC_NAME(src1, stride1, src2, stride2, awidth, height, sad); \ + for (int i = 0; i < MMSIZE / 8; i++) \ + *sum += sad[i]; \ + ff_scene_sad_c(src1 + awidth, stride1, \ + src2 + awidth, stride2, \ + width - awidth, height, sad); \ + *sum += sad[0]; \ +} + +#if HAVE_X86ASM +SCENE_SAD_FUNC(scene_sad_sse2, ff_scene_sad_sse2, 16); +#if HAVE_AVX2_EXTERNAL +SCENE_SAD_FUNC(scene_sad_avx2, ff_scene_sad_avx2, 32); +#endif +#endif + +ff_scene_sad_fn ff_scene_sad_get_fn_x86(int depth) +{ +#if HAVE_X86ASM + int cpu_flags = av_get_cpu_flags(); + if (depth == 8) { +#if HAVE_AVX2_EXTERNAL + if (EXTERNAL_AVX2_FAST(cpu_flags)) + return scene_sad_avx2; +#endif + if (EXTERNAL_SSE2(cpu_flags)) + return scene_sad_sse2; + } +#endif + return NULL; +} diff --git a/libavfilter/x86/vf_blend_init.c b/libavfilter/x86/vf_blend_init.c index acf28559f..84bc55cc8 100644 --- a/libavfilter/x86/vf_blend_init.c +++ b/libavfilter/x86/vf_blend_init.c @@ -100,11 +100,11 @@ BLEND_FUNC(xor_16, sse2) BLEND_FUNC(xor_16, avx2) #endif /* ARCH_X86_64 */ -av_cold void ff_blend_init_x86(FilterParams *param, int is_16bit) +av_cold void ff_blend_init_x86(FilterParams *param, int depth) { int cpu_flags = av_get_cpu_flags(); - if (!is_16bit) { + if (depth == 8) { if (EXTERNAL_SSE2(cpu_flags) && param->opacity == 1) { switch (param->mode) { case BLEND_ADDITION: param->blend = ff_blend_addition_sse2; break; @@ -156,7 +156,7 @@ av_cold void ff_blend_init_x86(FilterParams *param, int is_16bit) case BLEND_NEGATION: param->blend = ff_blend_negation_avx2; break; } } - } else { /* is_16_bit */ + } else if (depth == 16) { #if ARCH_X86_64 if (EXTERNAL_SSE2(cpu_flags) && param->opacity == 1) { switch (param->mode) { diff --git a/libavfilter/x86/vf_bwdif_init.c b/libavfilter/x86/vf_bwdif_init.c index 1cb8438e5..b1e70b3bc 100644 --- a/libavfilter/x86/vf_bwdif_init.c +++ b/libavfilter/x86/vf_bwdif_init.c @@ -53,8 +53,9 @@ void ff_bwdif_filter_line_12bit_ssse3(void *dst, void *prev, void *cur, void *ne av_cold void ff_bwdif_init_x86(BWDIFContext *bwdif) { + YADIFContext *yadif = &bwdif->yadif; int cpu_flags = av_get_cpu_flags(); - int bit_depth = (!bwdif->csp) ? 8 : bwdif->csp->comp[0].depth; + int bit_depth = (!yadif->csp) ? 8 : yadif->csp->comp[0].depth; if (bit_depth <= 8) { #if ARCH_X86_32 diff --git a/libavfilter/x86/vf_gblur.asm b/libavfilter/x86/vf_gblur.asm new file mode 100644 index 000000000..762c953c8 --- /dev/null +++ b/libavfilter/x86/vf_gblur.asm @@ -0,0 +1,185 @@ +;***************************************************************************** +;* x86-optimized functions for gblur filter +;* +;* This file is part of FFmpeg. +;* +;* FFmpeg is free software; you can redistribute it and/or +;* modify it under the terms of the GNU Lesser General Public +;* License as published by the Free Software Foundation; either +;* version 2.1 of the License, or (at your option) any later version. +;* +;* FFmpeg is distributed in the hope that it will be useful, +;* but WITHOUT ANY WARRANTY; without even the implied warranty of +;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +;* Lesser General Public License for more details. +;* +;* You should have received a copy of the GNU Lesser General Public +;* License along with FFmpeg; if not, write to the Free Software +;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +;****************************************************************************** + +%include "libavutil/x86/x86util.asm" + +SECTION .text + +; void ff_horiz_slice_sse4(float *ptr, int width, int height, int steps, +; float nu, float bscale) + +%macro HORIZ_SLICE 0 +%if UNIX64 +cglobal horiz_slice, 4, 9, 9, ptr, width, height, steps, x, y, step, stride, remain +%else +cglobal horiz_slice, 4, 9, 9, ptr, width, height, steps, nu, bscale, x, y, step, stride, remain +%endif +%if WIN64 + movss m0, num + movss m1, bscalem + DEFINE_ARGS ptr, width, height, steps, x, y, step, stride, remain +%endif + movsxdifnidn widthq, widthd + + mulss m2, m0, m0 ; nu ^ 2 + mulss m3, m2, m0 ; nu ^ 3 + mulss m4, m3, m0 ; nu ^ 4 + xor xq, xq + xor yd, yd + mov strideq, widthq + ; stride = width * 4 + shl strideq, 2 + ; w = w - ((w - 1) & 3) + mov remainq, widthq + sub remainq, 1 + and remainq, 3 + sub widthq, remainq + + shufps m0, m0, 0 + shufps m2, m2, 0 + shufps m3, m3, 0 + shufps m4, m4, 0 + +.loop_y: + xor stepd, stepd + + .loop_step: + ; p0 *= bscale + mulss m5, m1, [ptrq + xq * 4] + movss [ptrq + xq * 4], m5 + inc xq + ; filter rightwards + ; Here we are vectorizing the c version by 4 + ; for (x = 1; x < width; x++) + ; ptr[x] += nu * ptr[x - 1]; + ; let p0 stands for ptr[x-1], the data from last loop + ; and [p1,p2,p3,p4] be the vector data for this loop. + ; Unrolling the loop, we get: + ; p1' = p1 + p0*nu + ; p2' = p2 + p1*nu + p0*nu^2 + ; p3' = p3 + p2*nu + p1*nu^2 + p0*nu^3 + ; p4' = p4 + p3*nu + p2*nu^2 + p1*nu^3 + p0*nu^4 + ; so we can do it in simd: + ; [p1',p2',p3',p4'] = [p1,p2,p3,p4] + [p0,p1,p2,p3]*nu + + ; [0,p0,p1,p2]*nu^2 + [0,0,p0,p1]*nu^3 + + ; [0,0,0,p0]*nu^4 + + .loop_x: + movu m6, [ptrq + xq * 4] ; s = [p1,p2,p3,p4] + pslldq m7, m6, 4 ; [0, p1,p2,p3] + movss m7, m5 ; [p0,p1,p2,p3] + FMULADD_PS m6, m7, m0, m6, m8 ; s += [p0,p1,p2,p3] * nu + pslldq m7, 4 ; [0,p0,p1,p2] + FMULADD_PS m6, m7, m2, m6, m8 ; s += [0,p0,p1,p2] * nu^2 + pslldq m7, 4 + FMULADD_PS m6, m7, m3, m6, m8 ; s += [0,0,p0,p1] * nu^3 + pslldq m7, 4 + FMULADD_PS m6, m7, m4, m6, m8 ; s += [0,0,0,p0] * nu^4 + movu [ptrq + xq * 4], m6 + shufps m5, m6, m6, q3333 + add xq, 4 + cmp xq, widthq + jl .loop_x + + add widthq, remainq + cmp xq, widthq + je .end_scalar + + .loop_scalar: + ; ptr[x] += nu * ptr[x-1] + movss m5, [ptrq + 4*xq - 4] + mulss m5, m0 + addss m5, [ptrq + 4*xq] + movss [ptrq + 4*xq], m5 + inc xq + cmp xq, widthq + jl .loop_scalar + .end_scalar: + ; ptr[width - 1] *= bscale + dec xq + mulss m5, m1, [ptrq + 4*xq] + movss [ptrq + 4*xq], m5 + shufps m5, m5, 0 + + ; filter leftwards + ; for (; x > 0; x--) + ; ptr[x - 1] += nu * ptr[x]; + ; The idea here is basically the same as filter rightwards. + ; But we need to take care as the data layout is different. + ; Let p0 stands for the ptr[x], which is the data from last loop. + ; The way we do it in simd as below: + ; [p-4', p-3', p-2', p-1'] = [p-4, p-3, p-2, p-1] + ; + [p-3, p-2, p-1, p0] * nu + ; + [p-2, p-1, p0, 0] * nu^2 + ; + [p-1, p0, 0, 0] * nu^3 + ; + [p0, 0, 0, 0] * nu^4 + .loop_x_back: + sub xq, 4 + movu m6, [ptrq + xq * 4] ; s = [p-4, p-3, p-2, p-1] + psrldq m7, m6, 4 ; [p-3, p-2, p-1, 0 ] + blendps m7, m5, 0x8 ; [p-3, p-2, p-1, p0 ] + FMULADD_PS m6, m7, m0, m6, m8 ; s+= [p-3, p-2, p-1, p0 ] * nu + psrldq m7, 4 ; + FMULADD_PS m6, m7, m2, m6, m8 ; s+= [p-2, p-1, p0, 0] * nu^2 + psrldq m7, 4 + FMULADD_PS m6, m7, m3, m6, m8 ; s+= [p-1, p0, 0, 0] * nu^3 + psrldq m7, 4 + FMULADD_PS m6, m7, m4, m6, m8 ; s+= [p0, 0, 0, 0] * nu^4 + movu [ptrq + xq * 4], m6 + shufps m5, m6, m6, 0 ; m5 = [p-4', p-4', p-4', p-4'] + cmp xq, remainq + jg .loop_x_back + + cmp xq, 0 + je .end_scalar_back + + .loop_scalar_back: + ; ptr[x-1] += nu * ptr[x] + movss m5, [ptrq + 4*xq] + mulss m5, m0 + addss m5, [ptrq + 4*xq - 4] + movss [ptrq + 4*xq - 4], m5 + dec xq + cmp xq, 0 + jg .loop_scalar_back + .end_scalar_back: + + ; reset aligned width for next line + sub widthq, remainq + + inc stepd + cmp stepd, stepsd + jl .loop_step + + add ptrq, strideq + inc yd + cmp yd, heightd + jl .loop_y + + RET +%endmacro + +%if ARCH_X86_64 +INIT_XMM sse4 +HORIZ_SLICE + +INIT_XMM avx2 +HORIZ_SLICE +%endif diff --git a/libavfilter/x86/vf_gblur_init.c b/libavfilter/x86/vf_gblur_init.c new file mode 100644 index 000000000..e63e59fe2 --- /dev/null +++ b/libavfilter/x86/vf_gblur_init.c @@ -0,0 +1,40 @@ +/* + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" + +#include "libavutil/attributes.h" +#include "libavutil/cpu.h" +#include "libavutil/x86/cpu.h" +#include "libavfilter/gblur.h" + +void ff_horiz_slice_sse4(float *ptr, int width, int height, int steps, float nu, float bscale); +void ff_horiz_slice_avx2(float *ptr, int width, int height, int steps, float nu, float bscale); + +av_cold void ff_gblur_init_x86(GBlurContext *s) +{ +#if ARCH_X86_64 + int cpu_flags = av_get_cpu_flags(); + + if (EXTERNAL_SSE4(cpu_flags)) + s->horiz_slice = ff_horiz_slice_sse4; + if (EXTERNAL_AVX2(cpu_flags)) + s->horiz_slice = ff_horiz_slice_avx2; +#endif +} diff --git a/libavfilter/x86/vf_overlay.asm b/libavfilter/x86/vf_overlay.asm new file mode 100644 index 000000000..14ec60ca3 --- /dev/null +++ b/libavfilter/x86/vf_overlay.asm @@ -0,0 +1,144 @@ +;***************************************************************************** +;* x86-optimized functions for overlay filter +;* +;* Copyright (C) 2018 Paul B Mahol +;* Copyright (C) 2018 Henrik Gramner +;* +;* This file is part of FFmpeg. +;* +;* FFmpeg is free software; you can redistribute it and/or +;* modify it under the terms of the GNU Lesser General Public +;* License as published by the Free Software Foundation; either +;* version 2.1 of the License, or (at your option) any later version. +;* +;* FFmpeg is distributed in the hope that it will be useful, +;* but WITHOUT ANY WARRANTY; without even the implied warranty of +;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +;* Lesser General Public License for more details. +;* +;* You should have received a copy of the GNU Lesser General Public +;* License along with FFmpeg; if not, write to the Free Software +;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +;***************************************************************************** + +%include "libavutil/x86/x86util.asm" + +SECTION_RODATA + +pb_1: times 16 db 1 +pw_128: times 8 dw 128 +pw_255: times 8 dw 255 +pw_257: times 8 dw 257 + +SECTION .text + +INIT_XMM sse4 +cglobal overlay_row_44, 5, 7, 6, 0, d, da, s, a, w, r, x + xor xq, xq + movsxdifnidn wq, wd + mov rq, wq + and rq, mmsize/2 - 1 + cmp wq, mmsize/2 + jl .end + sub wq, rq + mova m3, [pw_255] + mova m4, [pw_128] + mova m5, [pw_257] + .loop: + pmovzxbw m0, [sq+xq] + pmovzxbw m2, [aq+xq] + pmovzxbw m1, [dq+xq] + pmullw m0, m2 + pxor m2, m3 + pmullw m1, m2 + paddw m0, m4 + paddw m0, m1 + pmulhuw m0, m5 + packuswb m0, m0 + movq [dq+xq], m0 + add xq, mmsize/2 + cmp xq, wq + jl .loop + + .end: + mov eax, xd + RET + +INIT_XMM sse4 +cglobal overlay_row_22, 5, 7, 6, 0, d, da, s, a, w, r, x + xor xq, xq + movsxdifnidn wq, wd + sub wq, 1 + mov rq, wq + and rq, mmsize/2 - 1 + cmp wq, mmsize/2 + jl .end + sub wq, rq + mova m3, [pw_255] + mova m4, [pw_128] + mova m5, [pw_257] + .loop: + pmovzxbw m0, [sq+xq] + movu m1, [aq+2*xq] + pandn m2, m3, m1 + psllw m1, 8 + pavgw m2, m1 + pavgw m2, m1 + psrlw m2, 8 + pmovzxbw m1, [dq+xq] + pmullw m0, m2 + pxor m2, m3 + pmullw m1, m2 + paddw m0, m4 + paddw m0, m1 + pmulhuw m0, m5 + packuswb m0, m0 + movq [dq+xq], m0 + add xq, mmsize/2 + cmp xq, wq + jl .loop + + .end: + mov eax, xd + RET + +INIT_XMM sse4 +cglobal overlay_row_20, 6, 7, 7, 0, d, da, s, a, w, r, x + mov daq, aq + add daq, rmp + xor xq, xq + movsxdifnidn wq, wd + sub wq, 1 + mov rq, wq + and rq, mmsize/2 - 1 + cmp wq, mmsize/2 + jl .end + sub wq, rq + mova m3, [pw_255] + mova m4, [pw_128] + mova m5, [pw_257] + mova m6, [pb_1] + .loop: + pmovzxbw m0, [sq+xq] + movu m2, [aq+2*xq] + movu m1, [daq+2*xq] + pmaddubsw m2, m6 + pmaddubsw m1, m6 + paddw m2, m1 + psrlw m2, 2 + pmovzxbw m1, [dq+xq] + pmullw m0, m2 + pxor m2, m3 + pmullw m1, m2 + paddw m0, m4 + paddw m0, m1 + pmulhuw m0, m5 + packuswb m0, m0 + movq [dq+xq], m0 + add xq, mmsize/2 + cmp xq, wq + jl .loop + + .end: + mov eax, xd + RET diff --git a/libavfilter/x86/vf_overlay_init.c b/libavfilter/x86/vf_overlay_init.c new file mode 100644 index 000000000..d4218b18f --- /dev/null +++ b/libavfilter/x86/vf_overlay_init.c @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2018 Paul B Mahol + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/attributes.h" +#include "libavutil/cpu.h" +#include "libavutil/x86/cpu.h" +#include "libavfilter/vf_overlay.h" + +int ff_overlay_row_44_sse4(uint8_t *d, uint8_t *da, uint8_t *s, uint8_t *a, + int w, ptrdiff_t alinesize); + +int ff_overlay_row_20_sse4(uint8_t *d, uint8_t *da, uint8_t *s, uint8_t *a, + int w, ptrdiff_t alinesize); + +int ff_overlay_row_22_sse4(uint8_t *d, uint8_t *da, uint8_t *s, uint8_t *a, + int w, ptrdiff_t alinesize); + +av_cold void ff_overlay_init_x86(OverlayContext *s, int format, int pix_format, + int alpha_format, int main_has_alpha) +{ + int cpu_flags = av_get_cpu_flags(); + + if (EXTERNAL_SSE4(cpu_flags) && + (format == OVERLAY_FORMAT_YUV444 || + format == OVERLAY_FORMAT_GBRP) && + alpha_format == 0 && main_has_alpha == 0) { + s->blend_row[0] = ff_overlay_row_44_sse4; + s->blend_row[1] = ff_overlay_row_44_sse4; + s->blend_row[2] = ff_overlay_row_44_sse4; + } + + if (EXTERNAL_SSE4(cpu_flags) && + (pix_format == AV_PIX_FMT_YUV420P) && + (format == OVERLAY_FORMAT_YUV420) && + alpha_format == 0 && main_has_alpha == 0) { + s->blend_row[0] = ff_overlay_row_44_sse4; + s->blend_row[1] = ff_overlay_row_20_sse4; + s->blend_row[2] = ff_overlay_row_20_sse4; + } + + if (EXTERNAL_SSE4(cpu_flags) && + (format == OVERLAY_FORMAT_YUV422) && + alpha_format == 0 && main_has_alpha == 0) { + s->blend_row[0] = ff_overlay_row_44_sse4; + s->blend_row[1] = ff_overlay_row_22_sse4; + s->blend_row[2] = ff_overlay_row_22_sse4; + } +} diff --git a/libavfilter/yadif.h b/libavfilter/yadif.h index d23d1380d..c928911b3 100644 --- a/libavfilter/yadif.h +++ b/libavfilter/yadif.h @@ -19,6 +19,7 @@ #ifndef AVFILTER_YADIF_H #define AVFILTER_YADIF_H +#include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "avfilter.h" @@ -40,6 +41,12 @@ enum YADIFDeint { YADIF_DEINT_INTERLACED = 1, ///< only deinterlace frames marked as interlaced }; +enum YADIFCurrentField { + YADIF_FIELD_BACK_END = -1, ///< The last frame in a sequence + YADIF_FIELD_END = 0, ///< The first or last field in a sequence + YADIF_FIELD_NORMAL = 1, ///< A normal field in the middle of a sequence +}; + typedef struct YADIFContext { const AVClass *class; @@ -54,6 +61,8 @@ typedef struct YADIFContext { AVFrame *prev; AVFrame *out; + void (*filter)(AVFilterContext *ctx, AVFrame *dstpic, int parity, int tff); + /** * Required alignment for filter_line */ @@ -67,8 +76,22 @@ typedef struct YADIFContext { int eof; uint8_t *temp_line; int temp_line_size; + + /* + * An algorithm that treats first and/or last fields in a sequence + * differently can use this to detect those cases. It is the algorithm's + * responsibility to set the value to YADIF_FIELD_NORMAL after processing + * the first field. + */ + int current_field; ///< YADIFCurrentField } YADIFContext; void ff_yadif_init_x86(YADIFContext *yadif); +int ff_yadif_filter_frame(AVFilterLink *link, AVFrame *frame); + +int ff_yadif_request_frame(AVFilterLink *link); + +extern const AVOption ff_yadif_options[]; + #endif /* AVFILTER_YADIF_H */ diff --git a/libavfilter/yadif_common.c b/libavfilter/yadif_common.c new file mode 100644 index 000000000..a10cf7a17 --- /dev/null +++ b/libavfilter/yadif_common.c @@ -0,0 +1,215 @@ +/* + * Copyright (C) 2006-2011 Michael Niedermayer + * 2010 James Darnley + + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/avassert.h" +#include "libavutil/imgutils.h" +#include "internal.h" +#include "yadif.h" + +static int return_frame(AVFilterContext *ctx, int is_second) +{ + YADIFContext *yadif = ctx->priv; + AVFilterLink *link = ctx->outputs[0]; + int tff, ret; + + if (yadif->parity == -1) { + tff = yadif->cur->interlaced_frame ? + yadif->cur->top_field_first : 1; + } else { + tff = yadif->parity ^ 1; + } + + if (is_second) { + yadif->out = ff_get_video_buffer(link, link->w, link->h); + if (!yadif->out) + return AVERROR(ENOMEM); + + av_frame_copy_props(yadif->out, yadif->cur); + yadif->out->interlaced_frame = 0; + if (yadif->current_field == YADIF_FIELD_BACK_END) + yadif->current_field = YADIF_FIELD_END; + } + + yadif->filter(ctx, yadif->out, tff ^ !is_second, tff); + + if (is_second) { + int64_t cur_pts = yadif->cur->pts; + int64_t next_pts = yadif->next->pts; + + if (next_pts != AV_NOPTS_VALUE && cur_pts != AV_NOPTS_VALUE) { + yadif->out->pts = cur_pts + next_pts; + } else { + yadif->out->pts = AV_NOPTS_VALUE; + } + } + ret = ff_filter_frame(ctx->outputs[0], yadif->out); + + yadif->frame_pending = (yadif->mode&1) && !is_second; + return ret; +} + +static int checkstride(YADIFContext *yadif, const AVFrame *a, const AVFrame *b) +{ + int i; + for (i = 0; i < yadif->csp->nb_components; i++) + if (a->linesize[i] != b->linesize[i]) + return 1; + return 0; +} + +static void fixstride(AVFilterLink *link, AVFrame *f) +{ + AVFrame *dst = ff_default_get_video_buffer(link, f->width, f->height); + if(!dst) + return; + av_frame_copy_props(dst, f); + av_image_copy(dst->data, dst->linesize, + (const uint8_t **)f->data, f->linesize, + dst->format, dst->width, dst->height); + av_frame_unref(f); + av_frame_move_ref(f, dst); + av_frame_free(&dst); +} + +int ff_yadif_filter_frame(AVFilterLink *link, AVFrame *frame) +{ + AVFilterContext *ctx = link->dst; + YADIFContext *yadif = ctx->priv; + + av_assert0(frame); + + if (yadif->frame_pending) + return_frame(ctx, 1); + + if (yadif->prev) + av_frame_free(&yadif->prev); + yadif->prev = yadif->cur; + yadif->cur = yadif->next; + yadif->next = frame; + + if (!yadif->cur) { + yadif->cur = av_frame_clone(yadif->next); + if (!yadif->cur) + return AVERROR(ENOMEM); + yadif->current_field = YADIF_FIELD_END; + } + + if (checkstride(yadif, yadif->next, yadif->cur)) { + av_log(ctx, AV_LOG_VERBOSE, "Reallocating frame due to differing stride\n"); + fixstride(link, yadif->next); + } + if (checkstride(yadif, yadif->next, yadif->cur)) + fixstride(link, yadif->cur); + if (yadif->prev && checkstride(yadif, yadif->next, yadif->prev)) + fixstride(link, yadif->prev); + if (checkstride(yadif, yadif->next, yadif->cur) || (yadif->prev && checkstride(yadif, yadif->next, yadif->prev))) { + av_log(ctx, AV_LOG_ERROR, "Failed to reallocate frame\n"); + return -1; + } + + if (!yadif->prev) + return 0; + + if ((yadif->deint && !yadif->cur->interlaced_frame) || + ctx->is_disabled || + (yadif->deint && !yadif->prev->interlaced_frame && yadif->prev->repeat_pict) || + (yadif->deint && !yadif->next->interlaced_frame && yadif->next->repeat_pict) + ) { + yadif->out = av_frame_clone(yadif->cur); + if (!yadif->out) + return AVERROR(ENOMEM); + + av_frame_free(&yadif->prev); + if (yadif->out->pts != AV_NOPTS_VALUE) + yadif->out->pts *= 2; + return ff_filter_frame(ctx->outputs[0], yadif->out); + } + + yadif->out = ff_get_video_buffer(ctx->outputs[0], link->w, link->h); + if (!yadif->out) + return AVERROR(ENOMEM); + + av_frame_copy_props(yadif->out, yadif->cur); + yadif->out->interlaced_frame = 0; + + if (yadif->out->pts != AV_NOPTS_VALUE) + yadif->out->pts *= 2; + + return return_frame(ctx, 0); +} + +int ff_yadif_request_frame(AVFilterLink *link) +{ + AVFilterContext *ctx = link->src; + YADIFContext *yadif = ctx->priv; + int ret; + + if (yadif->frame_pending) { + return_frame(ctx, 1); + return 0; + } + + if (yadif->eof) + return AVERROR_EOF; + + ret = ff_request_frame(ctx->inputs[0]); + + if (ret == AVERROR_EOF && yadif->cur) { + AVFrame *next = av_frame_clone(yadif->next); + + if (!next) + return AVERROR(ENOMEM); + + yadif->current_field = YADIF_FIELD_BACK_END; + next->pts = yadif->next->pts * 2 - yadif->cur->pts; + + ff_yadif_filter_frame(ctx->inputs[0], next); + yadif->eof = 1; + } else if (ret < 0) { + return ret; + } + + return 0; +} + +#define OFFSET(x) offsetof(YADIFContext, x) +#define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM + +#define CONST(name, help, val, unit) { name, help, 0, AV_OPT_TYPE_CONST, {.i64=val}, INT_MIN, INT_MAX, FLAGS, unit } + +const AVOption ff_yadif_options[] = { + { "mode", "specify the interlacing mode", OFFSET(mode), AV_OPT_TYPE_INT, {.i64=YADIF_MODE_SEND_FRAME}, 0, 3, FLAGS, "mode"}, + CONST("send_frame", "send one frame for each frame", YADIF_MODE_SEND_FRAME, "mode"), + CONST("send_field", "send one frame for each field", YADIF_MODE_SEND_FIELD, "mode"), + CONST("send_frame_nospatial", "send one frame for each frame, but skip spatial interlacing check", YADIF_MODE_SEND_FRAME_NOSPATIAL, "mode"), + CONST("send_field_nospatial", "send one frame for each field, but skip spatial interlacing check", YADIF_MODE_SEND_FIELD_NOSPATIAL, "mode"), + + { "parity", "specify the assumed picture field parity", OFFSET(parity), AV_OPT_TYPE_INT, {.i64=YADIF_PARITY_AUTO}, -1, 1, FLAGS, "parity" }, + CONST("tff", "assume top field first", YADIF_PARITY_TFF, "parity"), + CONST("bff", "assume bottom field first", YADIF_PARITY_BFF, "parity"), + CONST("auto", "auto detect parity", YADIF_PARITY_AUTO, "parity"), + + { "deint", "specify which frames to deinterlace", OFFSET(deint), AV_OPT_TYPE_INT, {.i64=YADIF_DEINT_ALL}, 0, 1, FLAGS, "deint" }, + CONST("all", "deinterlace all frames", YADIF_DEINT_ALL, "deint"), + CONST("interlaced", "only deinterlace frames marked as interlaced", YADIF_DEINT_INTERLACED, "deint"), + + { NULL } +}; diff --git a/libavformat/3dostr.c b/libavformat/3dostr.c index 3668e5f61..6c49f7589 100644 --- a/libavformat/3dostr.c +++ b/libavformat/3dostr.c @@ -22,7 +22,7 @@ #include "avformat.h" #include "internal.h" -static int threedostr_probe(AVProbeData *p) +static int threedostr_probe(const AVProbeData *p) { if (memcmp(p->buf, "CTRL", 4) && memcmp(p->buf, "SHDR", 4) && diff --git a/libavformat/4xm.c b/libavformat/4xm.c index ead6d2b42..a984fc9fd 100644 --- a/libavformat/4xm.c +++ b/libavformat/4xm.c @@ -81,7 +81,7 @@ typedef struct FourxmDemuxContext { AVRational fps; } FourxmDemuxContext; -static int fourxm_probe(AVProbeData *p) +static int fourxm_probe(const AVProbeData *p) { if ((AV_RL32(&p->buf[0]) != RIFF_TAG) || (AV_RL32(&p->buf[8]) != FOURXMV_TAG)) diff --git a/libavformat/Makefile b/libavformat/Makefile index 3eeca5091..a434b005a 100644 --- a/libavformat/Makefile +++ b/libavformat/Makefile @@ -115,6 +115,8 @@ OBJS-$(CONFIG_AVI_MUXER) += avienc.o mpegtsenc.o avlanguage.o ra OBJS-$(CONFIG_AVM2_MUXER) += swfenc.o swf.o OBJS-$(CONFIG_AVR_DEMUXER) += avr.o pcm.o OBJS-$(CONFIG_AVS_DEMUXER) += avs.o voc_packet.o vocdec.o voc.o +OBJS-$(CONFIG_AVS2_DEMUXER) += davs2.o rawdec.o +OBJS-$(CONFIG_AVS2_MUXER) += rawenc.o OBJS-$(CONFIG_BETHSOFTVID_DEMUXER) += bethsoftvid.o OBJS-$(CONFIG_BFI_DEMUXER) += bfi.o OBJS-$(CONFIG_BINK_DEMUXER) += bink.o @@ -147,6 +149,7 @@ OBJS-$(CONFIG_DAUD_DEMUXER) += dauddec.o OBJS-$(CONFIG_DAUD_MUXER) += daudenc.o OBJS-$(CONFIG_DCSTR_DEMUXER) += dcstr.o OBJS-$(CONFIG_DFA_DEMUXER) += dfa.o +OBJS-$(CONFIG_DHAV_DEMUXER) += dhav.o OBJS-$(CONFIG_DIRAC_DEMUXER) += diracdec.o rawdec.o OBJS-$(CONFIG_DIRAC_MUXER) += rawenc.o OBJS-$(CONFIG_DNXHD_DEMUXER) += dnxhddec.o rawdec.o @@ -159,8 +162,8 @@ OBJS-$(CONFIG_DTS_DEMUXER) += dtsdec.o rawdec.o OBJS-$(CONFIG_DTS_MUXER) += rawenc.o OBJS-$(CONFIG_DV_DEMUXER) += dv.o OBJS-$(CONFIG_DV_MUXER) += dvenc.o -OBJS-$(CONFIG_DVBSUB_DEMUXER) += dvbsub.o -OBJS-$(CONFIG_DVBTXT_DEMUXER) += dvbtxt.o +OBJS-$(CONFIG_DVBSUB_DEMUXER) += dvbsub.o rawdec.o +OBJS-$(CONFIG_DVBTXT_DEMUXER) += dvbtxt.o rawdec.o OBJS-$(CONFIG_DXA_DEMUXER) += dxa.o OBJS-$(CONFIG_EA_CDATA_DEMUXER) += eacdata.o OBJS-$(CONFIG_EA_DEMUXER) += electronicarts.o @@ -216,6 +219,7 @@ OBJS-$(CONFIG_H263_MUXER) += rawenc.o OBJS-$(CONFIG_H264_DEMUXER) += h264dec.o rawdec.o OBJS-$(CONFIG_H264_MUXER) += rawenc.o OBJS-$(CONFIG_HASH_MUXER) += hashenc.o +OBJS-$(CONFIG_HCOM_DEMUXER) += hcom.o OBJS-$(CONFIG_HDS_MUXER) += hdsenc.o OBJS-$(CONFIG_HEVC_DEMUXER) += hevcdec.o rawdec.o OBJS-$(CONFIG_HEVC_MUXER) += rawenc.o @@ -227,6 +231,7 @@ OBJS-$(CONFIG_ICO_MUXER) += icoenc.o OBJS-$(CONFIG_IDCIN_DEMUXER) += idcin.o OBJS-$(CONFIG_IDF_DEMUXER) += bintext.o sauce.o OBJS-$(CONFIG_IFF_DEMUXER) += iff.o +OBJS-$(CONFIG_IFV_DEMUXER) += ifv.o OBJS-$(CONFIG_ILBC_DEMUXER) += ilbc.o OBJS-$(CONFIG_ILBC_MUXER) += ilbc.o OBJS-$(CONFIG_IMAGE2_DEMUXER) += img2dec.o img2.o @@ -239,6 +244,7 @@ OBJS-$(CONFIG_IMAGE_BMP_PIPE_DEMUXER) += img2dec.o img2.o OBJS-$(CONFIG_IMAGE_DDS_PIPE_DEMUXER) += img2dec.o img2.o OBJS-$(CONFIG_IMAGE_DPX_PIPE_DEMUXER) += img2dec.o img2.o OBJS-$(CONFIG_IMAGE_EXR_PIPE_DEMUXER) += img2dec.o img2.o +OBJS-$(CONFIG_IMAGE_GIF_PIPE_DEMUXER) += img2dec.o img2.o OBJS-$(CONFIG_IMAGE_J2K_PIPE_DEMUXER) += img2dec.o img2.o OBJS-$(CONFIG_IMAGE_JPEG_PIPE_DEMUXER) += img2dec.o img2.o OBJS-$(CONFIG_IMAGE_JPEGLS_PIPE_DEMUXER) += img2dec.o img2.o @@ -258,6 +264,7 @@ OBJS-$(CONFIG_IMAGE_SUNRAST_PIPE_DEMUXER) += img2dec.o img2.o OBJS-$(CONFIG_IMAGE_TIFF_PIPE_DEMUXER) += img2dec.o img2.o OBJS-$(CONFIG_IMAGE_WEBP_PIPE_DEMUXER) += img2dec.o img2.o OBJS-$(CONFIG_IMAGE_XPM_PIPE_DEMUXER) += img2dec.o img2.o +OBJS-$(CONFIG_IMAGE_XWD_PIPE_DEMUXER) += img2dec.o img2.o OBJS-$(CONFIG_INGENIENT_DEMUXER) += ingenientdec.o rawdec.o OBJS-$(CONFIG_IPMOVIE_DEMUXER) += ipmovie.o OBJS-$(CONFIG_IRCAM_DEMUXER) += ircamdec.o ircam.o pcm.o @@ -270,6 +277,7 @@ OBJS-$(CONFIG_IVR_DEMUXER) += rmdec.o rm.o rmsipr.o OBJS-$(CONFIG_JACOSUB_DEMUXER) += jacosubdec.o subtitles.o OBJS-$(CONFIG_JACOSUB_MUXER) += jacosubenc.o rawenc.o OBJS-$(CONFIG_JV_DEMUXER) += jvdec.o +OBJS-$(CONFIG_KUX_DEMUXER) += flvdec.o OBJS-$(CONFIG_LATM_MUXER) += latmenc.o rawenc.o OBJS-$(CONFIG_LMLM4_DEMUXER) += lmlm4.o OBJS-$(CONFIG_LOAS_DEMUXER) += loasdec.o rawdec.o @@ -284,7 +292,7 @@ OBJS-$(CONFIG_MATROSKA_DEMUXER) += matroskadec.o matroska.o \ oggparsevorbis.o vorbiscomment.o \ flac_picture.o replaygain.o OBJS-$(CONFIG_MATROSKA_MUXER) += matroskaenc.o matroska.o \ - avc.o hevc.o \ + av1.o avc.o hevc.o \ flacenc_header.o avlanguage.o vorbiscomment.o wv.o \ webmdashenc.o webm_chunk.o OBJS-$(CONFIG_MD5_MUXER) += hashenc.o @@ -301,7 +309,7 @@ OBJS-$(CONFIG_MM_DEMUXER) += mm.o OBJS-$(CONFIG_MMF_DEMUXER) += mmf.o OBJS-$(CONFIG_MMF_MUXER) += mmf.o rawenc.o OBJS-$(CONFIG_MOV_DEMUXER) += mov.o mov_chan.o mov_esds.o replaygain.o -OBJS-$(CONFIG_MOV_MUXER) += movenc.o avc.o hevc.o vpcc.o \ +OBJS-$(CONFIG_MOV_MUXER) += movenc.o av1.o avc.o hevc.o vpcc.o \ movenchint.o mov_chan.o rtp.o \ movenccenc.o rawutils.o OBJS-$(CONFIG_MP2_MUXER) += rawenc.o @@ -332,7 +340,7 @@ OBJS-$(CONFIG_MUSX_DEMUXER) += musx.o OBJS-$(CONFIG_MV_DEMUXER) += mvdec.o OBJS-$(CONFIG_MVI_DEMUXER) += mvi.o OBJS-$(CONFIG_MXF_DEMUXER) += mxfdec.o mxf.o -OBJS-$(CONFIG_MXF_MUXER) += mxfenc.o mxf.o audiointerleave.o +OBJS-$(CONFIG_MXF_MUXER) += mxfenc.o mxf.o audiointerleave.o avc.o OBJS-$(CONFIG_MXG_DEMUXER) += mxg.o OBJS-$(CONFIG_NC_DEMUXER) += ncdec.o OBJS-$(CONFIG_NISTSPHERE_DEMUXER) += nistspheredec.o pcm.o @@ -408,6 +416,8 @@ OBJS-$(CONFIG_PCM_U32LE_DEMUXER) += pcmdec.o pcm.o OBJS-$(CONFIG_PCM_U32LE_MUXER) += pcmenc.o rawenc.o OBJS-$(CONFIG_PCM_U8_DEMUXER) += pcmdec.o pcm.o OBJS-$(CONFIG_PCM_U8_MUXER) += pcmenc.o rawenc.o +OBJS-$(CONFIG_PCM_VIDC_DEMUXER) += pcmdec.o pcm.o +OBJS-$(CONFIG_PCM_VIDC_MUXER) += pcmenc.o rawenc.o OBJS-$(CONFIG_PJS_DEMUXER) += pjsdec.o subtitles.o OBJS-$(CONFIG_PMP_DEMUXER) += pmpdec.o OBJS-$(CONFIG_PVA_DEMUXER) += pva.o @@ -464,6 +474,7 @@ OBJS-$(CONFIG_SDX_DEMUXER) += sdxdec.o OBJS-$(CONFIG_SEGAFILM_DEMUXER) += segafilm.o OBJS-$(CONFIG_SEGAFILM_MUXER) += segafilmenc.o OBJS-$(CONFIG_SEGMENT_MUXER) += segment.o +OBJS-$(CONFIG_SER_DEMUXER) += serdec.o OBJS-$(CONFIG_SHORTEN_DEMUXER) += shortendec.o rawdec.o OBJS-$(CONFIG_SIFF_DEMUXER) += siff.o OBJS-$(CONFIG_SINGLEJPEG_MUXER) += rawenc.o @@ -514,6 +525,7 @@ OBJS-$(CONFIG_VC1_DEMUXER) += rawdec.o vc1dec.o OBJS-$(CONFIG_VC1_MUXER) += rawenc.o OBJS-$(CONFIG_VC1T_DEMUXER) += vc1test.o OBJS-$(CONFIG_VC1T_MUXER) += vc1testenc.o +OBJS-$(CONFIG_VIVIDAS_DEMUXER) += vividas.o OBJS-$(CONFIG_VIVO_DEMUXER) += vivo.o OBJS-$(CONFIG_VMD_DEMUXER) += sierravmd.o OBJS-$(CONFIG_VOBSUB_DEMUXER) += subtitles.o # mpeg demuxer is in the dependencies @@ -528,7 +540,7 @@ OBJS-$(CONFIG_WAV_DEMUXER) += wavdec.o pcm.o OBJS-$(CONFIG_WAV_MUXER) += wavenc.o OBJS-$(CONFIG_WC3_DEMUXER) += wc3movie.o OBJS-$(CONFIG_WEBM_MUXER) += matroskaenc.o matroska.o \ - avc.o hevc.o \ + av1.o avc.o hevc.o \ flacenc_header.o avlanguage.o \ wv.o vorbiscomment.o \ webmdashenc.o webm_chunk.o @@ -556,20 +568,13 @@ OBJS-$(CONFIG_YOP_DEMUXER) += yop.o OBJS-$(CONFIG_YUV4MPEGPIPE_DEMUXER) += yuv4mpegdec.o OBJS-$(CONFIG_YUV4MPEGPIPE_MUXER) += yuv4mpegenc.o -# external libraries +# external library muxers/demuxers OBJS-$(CONFIG_AVISYNTH_DEMUXER) += avisynth.o OBJS-$(CONFIG_CHROMAPRINT_MUXER) += chromaprint.o OBJS-$(CONFIG_LIBGME_DEMUXER) += libgme.o OBJS-$(CONFIG_LIBMODPLUG_DEMUXER) += libmodplug.o OBJS-$(CONFIG_LIBOPENMPT_DEMUXER) += libopenmpt.o -OBJS-$(CONFIG_LIBRTMP_PROTOCOL) += librtmp.o -OBJS-$(CONFIG_LIBRTMPE_PROTOCOL) += librtmp.o -OBJS-$(CONFIG_LIBRTMPS_PROTOCOL) += librtmp.o -OBJS-$(CONFIG_LIBRTMPT_PROTOCOL) += librtmp.o -OBJS-$(CONFIG_LIBRTMPTE_PROTOCOL) += librtmp.o -OBJS-$(CONFIG_LIBSRT_PROTOCOL) += libsrt.o -OBJS-$(CONFIG_LIBSSH_PROTOCOL) += libssh.o -OBJS-$(CONFIG_LIBSMBCLIENT_PROTOCOL) += libsmbclient.o +OBJS-$(CONFIG_VAPOURSYNTH_DEMUXER) += vapoursynth.o # protocols I/O OBJS-$(CONFIG_ASYNC_PROTOCOL) += async.o @@ -600,7 +605,7 @@ OBJS-$(CONFIG_RTMPS_PROTOCOL) += rtmpproto.o rtmpdigest.o rtmppkt.o OBJS-$(CONFIG_RTMPT_PROTOCOL) += rtmpproto.o rtmpdigest.o rtmppkt.o OBJS-$(CONFIG_RTMPTE_PROTOCOL) += rtmpproto.o rtmpdigest.o rtmppkt.o OBJS-$(CONFIG_RTMPTS_PROTOCOL) += rtmpproto.o rtmpdigest.o rtmppkt.o -OBJS-$(CONFIG_RTP_PROTOCOL) += rtpproto.o +OBJS-$(CONFIG_RTP_PROTOCOL) += rtpproto.o ip.o OBJS-$(CONFIG_SCTP_PROTOCOL) += sctp.o OBJS-$(CONFIG_SRTP_PROTOCOL) += srtpproto.o srtp.o OBJS-$(CONFIG_SUBFILE_PROTOCOL) += subfile.o @@ -608,14 +613,25 @@ OBJS-$(CONFIG_TEE_PROTOCOL) += teeproto.o tee_common.o OBJS-$(CONFIG_TCP_PROTOCOL) += tcp.o TLS-OBJS-$(CONFIG_GNUTLS) += tls_gnutls.o TLS-OBJS-$(CONFIG_LIBTLS) += tls_libtls.o +TLS-OBJS-$(CONFIG_MBEDTLS) += tls_mbedtls.o TLS-OBJS-$(CONFIG_OPENSSL) += tls_openssl.o TLS-OBJS-$(CONFIG_SECURETRANSPORT) += tls_securetransport.o TLS-OBJS-$(CONFIG_SCHANNEL) += tls_schannel.o OBJS-$(CONFIG_TLS_PROTOCOL) += tls.o $(TLS-OBJS-yes) -OBJS-$(CONFIG_UDP_PROTOCOL) += udp.o -OBJS-$(CONFIG_UDPLITE_PROTOCOL) += udp.o +OBJS-$(CONFIG_UDP_PROTOCOL) += udp.o ip.o +OBJS-$(CONFIG_UDPLITE_PROTOCOL) += udp.o ip.o OBJS-$(CONFIG_UNIX_PROTOCOL) += unix.o +# external library protocols +OBJS-$(CONFIG_LIBRTMP_PROTOCOL) += librtmp.o +OBJS-$(CONFIG_LIBRTMPE_PROTOCOL) += librtmp.o +OBJS-$(CONFIG_LIBRTMPS_PROTOCOL) += librtmp.o +OBJS-$(CONFIG_LIBRTMPT_PROTOCOL) += librtmp.o +OBJS-$(CONFIG_LIBRTMPTE_PROTOCOL) += librtmp.o +OBJS-$(CONFIG_LIBSMBCLIENT_PROTOCOL) += libsmbclient.o +OBJS-$(CONFIG_LIBSRT_PROTOCOL) += libsrt.o +OBJS-$(CONFIG_LIBSSH_PROTOCOL) += libssh.o + # libavdevice dependencies OBJS-$(CONFIG_IEC61883_INDEV) += dv.o diff --git a/libavformat/aacdec.c b/libavformat/aacdec.c index 685458b91..00ca2319c 100644 --- a/libavformat/aacdec.c +++ b/libavformat/aacdec.c @@ -20,6 +20,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "libavutil/avassert.h" #include "libavutil/intreadwrite.h" #include "avformat.h" #include "avio_internal.h" @@ -30,7 +31,7 @@ #define ADTS_HEADER_SIZE 7 -static int adts_aac_probe(AVProbeData *p) +static int adts_aac_probe(const AVProbeData *p) { int max_frames = 0, first_frames = 0; int fsize, frames; @@ -79,10 +80,31 @@ static int adts_aac_probe(AVProbeData *p) return 0; } +static int adts_aac_resync(AVFormatContext *s) +{ + uint16_t state; + + // skip data until an ADTS frame is found + state = avio_r8(s->pb); + while (!avio_feof(s->pb) && avio_tell(s->pb) < s->probesize) { + state = (state << 8) | avio_r8(s->pb); + if ((state >> 4) != 0xFFF) + continue; + avio_seek(s->pb, -2, SEEK_CUR); + break; + } + if (s->pb->eof_reached) + return AVERROR_EOF; + if ((state >> 4) != 0xFFF) + return AVERROR_INVALIDDATA; + + return 0; +} + static int adts_aac_read_header(AVFormatContext *s) { AVStream *st; - uint16_t state; + int ret; st = avformat_new_stream(s, NULL); if (!st) @@ -100,17 +122,9 @@ static int adts_aac_read_header(AVFormatContext *s) avio_seek(s->pb, cur, SEEK_SET); } - // skip data until the first ADTS frame is found - state = avio_r8(s->pb); - while (!avio_feof(s->pb) && avio_tell(s->pb) < s->probesize) { - state = (state << 8) | avio_r8(s->pb); - if ((state >> 4) != 0xFFF) - continue; - avio_seek(s->pb, -2, SEEK_CUR); - break; - } - if ((state >> 4) != 0xFFF) - return AVERROR_INVALIDDATA; + ret = adts_aac_resync(s); + if (ret < 0) + return ret; // LCM of all possible ADTS sample rates avpriv_set_pts_info(st, 64, 1, 28224000); @@ -154,17 +168,8 @@ static int adts_aac_read_packet(AVFormatContext *s, AVPacket *pkt) { int ret, fsize; - // Parse all the ID3 headers between frames - while (1) { - ret = av_get_packet(s->pb, pkt, FFMAX(ID3v2_HEADER_SIZE, ADTS_HEADER_SIZE)); - if (ret >= ID3v2_HEADER_SIZE && ff_id3v2_match(pkt->data, ID3v2_DEFAULT_MAGIC)) { - if ((ret = handle_id3(s, pkt)) >= 0) { - continue; - } - } - break; - } - +retry: + ret = av_get_packet(s->pb, pkt, ADTS_HEADER_SIZE); if (ret < 0) return ret; @@ -174,8 +179,24 @@ static int adts_aac_read_packet(AVFormatContext *s, AVPacket *pkt) } if ((AV_RB16(pkt->data) >> 4) != 0xfff) { - av_packet_unref(pkt); - return AVERROR_INVALIDDATA; + // Parse all the ID3 headers between frames + int append = ID3v2_HEADER_SIZE - ADTS_HEADER_SIZE; + + av_assert2(append > 0); + ret = av_append_packet(s->pb, pkt, append); + if (ret != append) { + av_packet_unref(pkt); + return AVERROR(EIO); + } + if (!ff_id3v2_match(pkt->data, ID3v2_DEFAULT_MAGIC)) { + av_packet_unref(pkt); + ret = adts_aac_resync(s); + } else + ret = handle_id3(s, pkt); + if (ret < 0) + return ret; + + goto retry; } fsize = (AV_RB32(pkt->data + 3) >> 13) & 0x1FFF; diff --git a/libavformat/aadec.c b/libavformat/aadec.c index 8d39b1d9b..b9dd51ebf 100644 --- a/libavformat/aadec.c +++ b/libavformat/aadec.c @@ -35,6 +35,9 @@ #define MAX_TOC_ENTRIES 16 #define MAX_DICTIONARY_ENTRIES 128 #define TEA_BLOCK_SIZE 8 +#define CHAPTER_HEADER_SIZE 8 +#define TIMEPREC 1000 +#define MP3_FRAME_SIZE 104 typedef struct AADemuxContext { AVClass *class; @@ -46,6 +49,9 @@ typedef struct AADemuxContext { struct AVTEA *tea_ctx; uint8_t file_key[16]; int64_t current_chapter_size; + int64_t content_start; + int64_t content_end; + int seek_offset; } AADemuxContext; static int get_second_size(char *codec_name) @@ -69,7 +75,7 @@ static int aa_read_header(AVFormatContext *s) uint32_t nkey, nval, toc_size, npairs, header_seed = 0, start; char key[128], val[128], codec_name[64] = {0}; uint8_t output[24], dst[8], src[8]; - int64_t largest_size = -1, current_size = -1; + int64_t largest_size = -1, current_size = -1, chapter_pos; struct toc_entry { uint32_t offset; uint32_t size; @@ -79,6 +85,7 @@ static int aa_read_header(AVFormatContext *s) AADemuxContext *c = s->priv_data; AVIOContext *pb = s->pb; AVStream *st; + int ret; /* parse .aa header */ avio_skip(pb, 4); // file size @@ -112,8 +119,12 @@ static int aa_read_header(AVFormatContext *s) header_seed = atoi(val); } else if (!strcmp(key, "HeaderKey")) { // this looks like "1234567890 1234567890 1234567890 1234567890" av_log(s, AV_LOG_DEBUG, "HeaderKey is <%s>\n", val); - sscanf(val, "%"SCNu32"%"SCNu32"%"SCNu32"%"SCNu32, + + ret = sscanf(val, "%"SCNu32"%"SCNu32"%"SCNu32"%"SCNu32, &header_key_part[0], &header_key_part[1], &header_key_part[2], &header_key_part[3]); + if (ret != 4) + return AVERROR_INVALIDDATA; + for (idx = 0; idx < 4; idx++) { AV_WB32(&header_key[idx * 4], header_key_part[idx]); // convert each part to BE! } @@ -172,19 +183,24 @@ static int aa_read_header(AVFormatContext *s) st->codecpar->codec_id = AV_CODEC_ID_MP3; st->codecpar->sample_rate = 22050; st->need_parsing = AVSTREAM_PARSE_FULL_RAW; - st->start_time = 0; + avpriv_set_pts_info(st, 64, 8, 32000 * TIMEPREC); + // encoded audio frame is MP3_FRAME_SIZE bytes (+1 with padding, unlikely) } else if (!strcmp(codec_name, "acelp85")) { st->codecpar->codec_id = AV_CODEC_ID_SIPR; st->codecpar->block_align = 19; st->codecpar->channels = 1; st->codecpar->sample_rate = 8500; + st->codecpar->bit_rate = 8500; st->need_parsing = AVSTREAM_PARSE_FULL_RAW; + avpriv_set_pts_info(st, 64, 8, 8500 * TIMEPREC); } else if (!strcmp(codec_name, "acelp16")) { st->codecpar->codec_id = AV_CODEC_ID_SIPR; st->codecpar->block_align = 20; st->codecpar->channels = 1; st->codecpar->sample_rate = 16000; + st->codecpar->bit_rate = 16000; st->need_parsing = AVSTREAM_PARSE_FULL_RAW; + avpriv_set_pts_info(st, 64, 8, 16000 * TIMEPREC); } /* determine, and jump to audio start offset */ @@ -197,7 +213,30 @@ static int aa_read_header(AVFormatContext *s) } start = TOC[largest_idx].offset; avio_seek(pb, start, SEEK_SET); + + // extract chapter positions. since all formats have constant bit rate, use it + // as time base in bytes/s, for easy stream position <-> timestamp conversion + st->start_time = 0; + c->content_start = start; + c->content_end = start + largest_size; + + while ((chapter_pos = avio_tell(pb)) >= 0 && chapter_pos < c->content_end) { + int chapter_idx = s->nb_chapters; + uint32_t chapter_size = avio_rb32(pb); + if (chapter_size == 0) break; + chapter_pos -= start + CHAPTER_HEADER_SIZE * chapter_idx; + avio_skip(pb, 4 + chapter_size); + if (!avpriv_new_chapter(s, chapter_idx, st->time_base, + chapter_pos * TIMEPREC, (chapter_pos + chapter_size) * TIMEPREC, NULL)) + return AVERROR(ENOMEM); + } + + st->duration = (largest_size - CHAPTER_HEADER_SIZE * s->nb_chapters) * TIMEPREC; + + ff_update_cur_dts(s, st, 0); + avio_seek(pb, start, SEEK_SET); c->current_chapter_size = 0; + c->seek_offset = 0; return 0; } @@ -213,6 +252,12 @@ static int aa_read_packet(AVFormatContext *s, AVPacket *pkt) int written = 0; int ret; AADemuxContext *c = s->priv_data; + uint64_t pos = avio_tell(s->pb); + + // are we at the end of the audio content? + if (pos >= c->content_end) { + return AVERROR_EOF; + } // are we at the start of a chapter? if (c->current_chapter_size == 0) { @@ -223,6 +268,7 @@ static int aa_read_packet(AVFormatContext *s, AVPacket *pkt) av_log(s, AV_LOG_DEBUG, "Chapter %d (%" PRId64 " bytes)\n", c->chapter_idx, c->current_chapter_size); c->chapter_idx = c->chapter_idx + 1; avio_skip(s->pb, 4); // data start offset + pos += 8; c->current_codec_second_size = c->codec_second_size; } @@ -234,7 +280,9 @@ static int aa_read_packet(AVFormatContext *s, AVPacket *pkt) // decrypt c->current_codec_second_size bytes blocks = c->current_codec_second_size / TEA_BLOCK_SIZE; for (i = 0; i < blocks; i++) { - avio_read(s->pb, src, TEA_BLOCK_SIZE); + ret = avio_read(s->pb, src, TEA_BLOCK_SIZE); + if (ret != TEA_BLOCK_SIZE) + return (ret < 0) ? ret : AVERROR_EOF; av_tea_init(c->tea_ctx, c->file_key, 16); av_tea_crypt(c->tea_ctx, dst, src, 1, NULL, 1); memcpy(buf + written, dst, TEA_BLOCK_SIZE); @@ -242,7 +290,9 @@ static int aa_read_packet(AVFormatContext *s, AVPacket *pkt) } trailing_bytes = c->current_codec_second_size % TEA_BLOCK_SIZE; if (trailing_bytes != 0) { // trailing bytes are left unencrypted! - avio_read(s->pb, src, trailing_bytes); + ret = avio_read(s->pb, src, trailing_bytes); + if (ret != trailing_bytes) + return (ret < 0) ? ret : AVERROR_EOF; memcpy(buf + written, src, trailing_bytes); written = written + trailing_bytes; } @@ -252,15 +302,70 @@ static int aa_read_packet(AVFormatContext *s, AVPacket *pkt) if (c->current_chapter_size <= 0) c->current_chapter_size = 0; - ret = av_new_packet(pkt, written); + if (c->seek_offset > written) + c->seek_offset = 0; // ignore wrong estimate + + ret = av_new_packet(pkt, written - c->seek_offset); if (ret < 0) return ret; - memcpy(pkt->data, buf, written); + memcpy(pkt->data, buf + c->seek_offset, written - c->seek_offset); + pkt->pos = pos; + c->seek_offset = 0; return 0; } -static int aa_probe(AVProbeData *p) +static int aa_read_seek(AVFormatContext *s, + int stream_index, int64_t timestamp, int flags) +{ + AADemuxContext *c = s->priv_data; + AVChapter *ch; + int64_t chapter_pos, chapter_start, chapter_size; + int chapter_idx = 0; + + // find chapter containing seek timestamp + if (timestamp < 0) + timestamp = 0; + + while (chapter_idx < s->nb_chapters && timestamp >= s->chapters[chapter_idx]->end) { + ++chapter_idx; + } + + if (chapter_idx >= s->nb_chapters) { + chapter_idx = s->nb_chapters - 1; + if (chapter_idx < 0) return -1; // there is no chapter. + timestamp = s->chapters[chapter_idx]->end; + } + + ch = s->chapters[chapter_idx]; + + // sync by clamping timestamp to nearest valid block position in its chapter + chapter_size = ch->end / TIMEPREC - ch->start / TIMEPREC; + chapter_pos = av_rescale_rnd((timestamp - ch->start) / TIMEPREC, + 1, c->codec_second_size, + (flags & AVSEEK_FLAG_BACKWARD) ? AV_ROUND_DOWN : AV_ROUND_UP) + * c->codec_second_size; + if (chapter_pos >= chapter_size) + chapter_pos = chapter_size; + chapter_start = c->content_start + (ch->start / TIMEPREC) + CHAPTER_HEADER_SIZE * (1 + chapter_idx); + + // reinit read state + avio_seek(s->pb, chapter_start + chapter_pos, SEEK_SET); + c->current_codec_second_size = c->codec_second_size; + c->current_chapter_size = chapter_size - chapter_pos; + c->chapter_idx = 1 + chapter_idx; + + // for unaligned frames, estimate offset of first frame in block (assume no padding) + if (s->streams[0]->codecpar->codec_id == AV_CODEC_ID_MP3) { + c->seek_offset = (MP3_FRAME_SIZE - chapter_pos % MP3_FRAME_SIZE) % MP3_FRAME_SIZE; + } + + ff_update_cur_dts(s, s->streams[0], ch->start + (chapter_pos + c->seek_offset) * TIMEPREC); + + return 1; +} + +static int aa_probe(const AVProbeData *p) { uint8_t *buf = p->buf; @@ -305,6 +410,7 @@ AVInputFormat ff_aa_demuxer = { .read_probe = aa_probe, .read_header = aa_read_header, .read_packet = aa_read_packet, + .read_seek = aa_read_seek, .read_close = aa_read_close, - .flags = AVFMT_GENERIC_INDEX, + .flags = AVFMT_NO_BYTE_SEEK | AVFMT_NOGENSEARCH, }; diff --git a/libavformat/ac3dec.c b/libavformat/ac3dec.c index 6f423ff7e..1f8793938 100644 --- a/libavformat/ac3dec.c +++ b/libavformat/ac3dec.c @@ -25,7 +25,7 @@ #include "avformat.h" #include "rawdec.h" -static int ac3_eac3_probe(AVProbeData *p, enum AVCodecID expected_codec_id) +static int ac3_eac3_probe(const AVProbeData *p, enum AVCodecID expected_codec_id) { int max_frames, first_frames = 0, frames; const uint8_t *buf, *buf2, *end; @@ -47,7 +47,7 @@ static int ac3_eac3_probe(AVProbeData *p, enum AVCodecID expected_codec_id) uint16_t frame_size; int i, ret; - if(!memcmp(buf2, "\x1\x10\0\0\0\0\0\0", 8)) { + if(!memcmp(buf2, "\x1\x10", 2)) { if (buf2 + 16 > end) break; buf2+=16; @@ -97,11 +97,12 @@ static int ac3_eac3_probe(AVProbeData *p, enum AVCodecID expected_codec_id) } #if CONFIG_AC3_DEMUXER -static int ac3_probe(AVProbeData *p) +static int ac3_probe(const AVProbeData *p) { return ac3_eac3_probe(p, AV_CODEC_ID_AC3); } +FF_RAW_DEMUXER_CLASS(ac3) AVInputFormat ff_ac3_demuxer = { .name = "ac3", .long_name = NULL_IF_CONFIG_SMALL("raw AC-3"), @@ -111,15 +112,18 @@ AVInputFormat ff_ac3_demuxer = { .flags= AVFMT_GENERIC_INDEX, .extensions = "ac3", .raw_codec_id = AV_CODEC_ID_AC3, + .priv_data_size = sizeof(FFRawDemuxerContext), + .priv_class = &ac3_demuxer_class, }; #endif #if CONFIG_EAC3_DEMUXER -static int eac3_probe(AVProbeData *p) +static int eac3_probe(const AVProbeData *p) { return ac3_eac3_probe(p, AV_CODEC_ID_EAC3); } +FF_RAW_DEMUXER_CLASS(eac3) AVInputFormat ff_eac3_demuxer = { .name = "eac3", .long_name = NULL_IF_CONFIG_SMALL("raw E-AC-3"), @@ -129,5 +133,7 @@ AVInputFormat ff_eac3_demuxer = { .flags = AVFMT_GENERIC_INDEX, .extensions = "eac3", .raw_codec_id = AV_CODEC_ID_EAC3, + .priv_data_size = sizeof(FFRawDemuxerContext), + .priv_class = &eac3_demuxer_class, }; #endif diff --git a/libavformat/acm.c b/libavformat/acm.c index 08dd9282f..5e03cf8bf 100644 --- a/libavformat/acm.c +++ b/libavformat/acm.c @@ -24,7 +24,7 @@ #include "rawdec.h" #include "internal.h" -static int acm_probe(AVProbeData *p) +static int acm_probe(const AVProbeData *p) { if (AV_RB32(p->buf) != 0x97280301) return 0; @@ -44,12 +44,9 @@ static int acm_read_header(AVFormatContext *s) st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO; st->codecpar->codec_id = AV_CODEC_ID_INTERPLAY_ACM; - ff_alloc_extradata(st->codecpar, 14); - if (!st->codecpar->extradata) - return AVERROR(ENOMEM); - ret = avio_read(s->pb, st->codecpar->extradata, 14); - if (ret < 10) - return ret < 0 ? ret : AVERROR_EOF; + ret = ff_get_extradata(s, st->codecpar, s->pb, 14); + if (ret < 0) + return ret; st->codecpar->channels = AV_RL16(st->codecpar->extradata + 8); st->codecpar->sample_rate = AV_RL16(st->codecpar->extradata + 10); @@ -63,6 +60,7 @@ static int acm_read_header(AVFormatContext *s) return 0; } +FF_RAW_DEMUXER_CLASS(acm) AVInputFormat ff_acm_demuxer = { .name = "acm", .long_name = NULL_IF_CONFIG_SMALL("Interplay ACM"), @@ -72,4 +70,6 @@ AVInputFormat ff_acm_demuxer = { .flags = AVFMT_NOBINSEARCH | AVFMT_NOGENSEARCH | AVFMT_NO_BYTE_SEEK | AVFMT_NOTIMESTAMPS, .extensions = "acm", .raw_codec_id = AV_CODEC_ID_INTERPLAY_ACM, + .priv_data_size = sizeof(FFRawDemuxerContext), + .priv_class = &acm_demuxer_class, }; diff --git a/libavformat/act.c b/libavformat/act.c index fe6741178..26425ca1b 100644 --- a/libavformat/act.c +++ b/libavformat/act.c @@ -33,7 +33,7 @@ typedef struct{ char second_packet; ///< 1 - if temporary buffer contains valid (second) G.729 packet } ACTContext; -static int probe(AVProbeData *p) +static int probe(const AVProbeData *p) { int i; diff --git a/libavformat/adp.c b/libavformat/adp.c index 3914857ad..56f302acf 100644 --- a/libavformat/adp.c +++ b/libavformat/adp.c @@ -24,7 +24,7 @@ #include "avformat.h" #include "internal.h" -static int adp_probe(AVProbeData *p) +static int adp_probe(const AVProbeData *p) { int i, changes = 0; uint8_t last = 0; diff --git a/libavformat/ads.c b/libavformat/ads.c index 73ea7c7d5..f25141b3c 100644 --- a/libavformat/ads.c +++ b/libavformat/ads.c @@ -23,7 +23,7 @@ #include "avformat.h" #include "internal.h" -static int ads_probe(AVProbeData *p) +static int ads_probe(const AVProbeData *p) { if (memcmp(p->buf, "SShd", 4) || memcmp(p->buf+32, "SSbd", 4)) diff --git a/libavformat/adxdec.c b/libavformat/adxdec.c index a271e2afa..1038a0d67 100644 --- a/libavformat/adxdec.c +++ b/libavformat/adxdec.c @@ -34,7 +34,7 @@ typedef struct ADXDemuxerContext { int header_size; } ADXDemuxerContext; -static int adx_probe(AVProbeData *p) +static int adx_probe(const AVProbeData *p) { int offset; if (AV_RB16(p->buf) != 0x8000) diff --git a/libavformat/aea.c b/libavformat/aea.c index f7954956c..bdeed6425 100644 --- a/libavformat/aea.c +++ b/libavformat/aea.c @@ -27,7 +27,7 @@ #define AT1_SU_SIZE 212 -static int aea_read_probe(AVProbeData *p) +static int aea_read_probe(const AVProbeData *p) { if (p->buf_size <= 2048+212) return 0; diff --git a/libavformat/aiffdec.c b/libavformat/aiffdec.c index 7c701e0c7..fcedb0a80 100644 --- a/libavformat/aiffdec.c +++ b/libavformat/aiffdec.c @@ -189,7 +189,7 @@ static int get_aiff_header(AVFormatContext *s, int size, return num_frames; } -static int aiff_probe(AVProbeData *p) +static int aiff_probe(const AVProbeData *p) { /* check file header */ if (p->buf[0] == 'F' && p->buf[1] == 'O' && diff --git a/libavformat/aixdec.c b/libavformat/aixdec.c index cad8a1e11..b536bc4b0 100644 --- a/libavformat/aixdec.c +++ b/libavformat/aixdec.c @@ -23,7 +23,7 @@ #include "avformat.h" #include "internal.h" -static int aix_probe(AVProbeData *p) +static int aix_probe(const AVProbeData *p) { if (AV_RL32(p->buf) != MKTAG('A','I','X','F') || AV_RB32(p->buf + 8) != 0x01000014 || diff --git a/libavformat/allformats.c b/libavformat/allformats.c index d582778b3..cd0083480 100644 --- a/libavformat/allformats.c +++ b/libavformat/allformats.c @@ -76,6 +76,8 @@ extern AVInputFormat ff_avisynth_demuxer; extern AVOutputFormat ff_avm2_muxer; extern AVInputFormat ff_avr_demuxer; extern AVInputFormat ff_avs_demuxer; +extern AVInputFormat ff_avs2_demuxer; +extern AVOutputFormat ff_avs2_muxer; extern AVInputFormat ff_bethsoftvid_demuxer; extern AVInputFormat ff_bfi_demuxer; extern AVInputFormat ff_bintext_demuxer; @@ -108,6 +110,7 @@ extern AVInputFormat ff_daud_demuxer; extern AVOutputFormat ff_daud_muxer; extern AVInputFormat ff_dcstr_demuxer; extern AVInputFormat ff_dfa_demuxer; +extern AVInputFormat ff_dhav_demuxer; extern AVInputFormat ff_dirac_demuxer; extern AVOutputFormat ff_dirac_muxer; extern AVInputFormat ff_dnxhd_demuxer; @@ -173,6 +176,7 @@ extern AVOutputFormat ff_h263_muxer; extern AVInputFormat ff_h264_demuxer; extern AVOutputFormat ff_h264_muxer; extern AVOutputFormat ff_hash_muxer; +extern AVInputFormat ff_hcom_demuxer; extern AVOutputFormat ff_hds_muxer; extern AVInputFormat ff_hevc_demuxer; extern AVOutputFormat ff_hevc_muxer; @@ -184,6 +188,7 @@ extern AVOutputFormat ff_ico_muxer; extern AVInputFormat ff_idcin_demuxer; extern AVInputFormat ff_idf_demuxer; extern AVInputFormat ff_iff_demuxer; +extern AVInputFormat ff_ifv_demuxer; extern AVInputFormat ff_ilbc_demuxer; extern AVOutputFormat ff_ilbc_muxer; extern AVInputFormat ff_image2_demuxer; @@ -206,6 +211,7 @@ extern AVInputFormat ff_ivr_demuxer; extern AVInputFormat ff_jacosub_demuxer; extern AVOutputFormat ff_jacosub_muxer; extern AVInputFormat ff_jv_demuxer; +extern AVInputFormat ff_kux_demuxer; extern AVOutputFormat ff_latm_muxer; extern AVInputFormat ff_lmlm4_demuxer; extern AVInputFormat ff_loas_demuxer; @@ -287,6 +293,8 @@ extern AVInputFormat ff_pcm_alaw_demuxer; extern AVOutputFormat ff_pcm_alaw_muxer; extern AVInputFormat ff_pcm_mulaw_demuxer; extern AVOutputFormat ff_pcm_mulaw_muxer; +extern AVInputFormat ff_pcm_vidc_demuxer; +extern AVOutputFormat ff_pcm_vidc_muxer; extern AVInputFormat ff_pcm_f64be_demuxer; extern AVOutputFormat ff_pcm_f64be_muxer; extern AVInputFormat ff_pcm_f64le_demuxer; @@ -365,6 +373,7 @@ extern AVInputFormat ff_segafilm_demuxer; extern AVOutputFormat ff_segafilm_muxer; extern AVOutputFormat ff_segment_muxer; extern AVOutputFormat ff_stream_segment_muxer; +extern AVInputFormat ff_ser_demuxer; extern AVInputFormat ff_shorten_demuxer; extern AVInputFormat ff_siff_demuxer; extern AVOutputFormat ff_singlejpeg_muxer; @@ -416,6 +425,7 @@ extern AVInputFormat ff_vc1_demuxer; extern AVOutputFormat ff_vc1_muxer; extern AVInputFormat ff_vc1t_demuxer; extern AVOutputFormat ff_vc1t_muxer; +extern AVInputFormat ff_vividas_demuxer; extern AVInputFormat ff_vivo_demuxer; extern AVInputFormat ff_vmd_demuxer; extern AVInputFormat ff_vobsub_demuxer; @@ -457,6 +467,7 @@ extern AVInputFormat ff_image_bmp_pipe_demuxer; extern AVInputFormat ff_image_dds_pipe_demuxer; extern AVInputFormat ff_image_dpx_pipe_demuxer; extern AVInputFormat ff_image_exr_pipe_demuxer; +extern AVInputFormat ff_image_gif_pipe_demuxer; extern AVInputFormat ff_image_j2k_pipe_demuxer; extern AVInputFormat ff_image_jpeg_pipe_demuxer; extern AVInputFormat ff_image_jpegls_pipe_demuxer; @@ -476,12 +487,14 @@ extern AVInputFormat ff_image_sunrast_pipe_demuxer; extern AVInputFormat ff_image_tiff_pipe_demuxer; extern AVInputFormat ff_image_webp_pipe_demuxer; extern AVInputFormat ff_image_xpm_pipe_demuxer; +extern AVInputFormat ff_image_xwd_pipe_demuxer; /* external libraries */ extern AVOutputFormat ff_chromaprint_muxer; extern AVInputFormat ff_libgme_demuxer; extern AVInputFormat ff_libmodplug_demuxer; extern AVInputFormat ff_libopenmpt_demuxer; +extern AVInputFormat ff_vapoursynth_demuxer; #include "libavformat/muxer_list.c" #include "libavformat/demuxer_list.c" @@ -572,7 +585,11 @@ AVInputFormat *av_iformat_next(const AVInputFormat *f) ff_thread_once(&av_format_next_init, av_format_init_next); if (f) +#if FF_API_AVIOFORMAT return f->next; +#else + return (AVInputFormat *) f->next; +#endif else { void *opaque = NULL; return (AVInputFormat *)av_demuxer_iterate(&opaque); @@ -584,7 +601,11 @@ AVOutputFormat *av_oformat_next(const AVOutputFormat *f) ff_thread_once(&av_format_next_init, av_format_init_next); if (f) +#if FF_API_AVIOFORMAT return f->next; +#else + return (AVOutputFormat *) f->next; +#endif else { void *opaque = NULL; return (AVOutputFormat *)av_muxer_iterate(&opaque); diff --git a/libavformat/amr.c b/libavformat/amr.c index f954803d4..42840a50a 100644 --- a/libavformat/amr.c +++ b/libavformat/amr.c @@ -71,7 +71,7 @@ static int amr_write_packet(AVFormatContext *s, AVPacket *pkt) } #endif /* CONFIG_AMR_MUXER */ -static int amr_probe(AVProbeData *p) +static int amr_probe(const AVProbeData *p) { // Only check for "#!AMR" which could be amr-wb, amr-nb. // This will also trigger multichannel files: "#!AMR_MC1.0\n" and @@ -176,7 +176,7 @@ AVInputFormat ff_amr_demuxer = { #endif #if CONFIG_AMRNB_DEMUXER -static int amrnb_probe(AVProbeData *p) +static int amrnb_probe(const AVProbeData *p) { int mode, i = 0, valid = 0, invalid = 0; const uint8_t *b = p->buf; @@ -184,12 +184,11 @@ static int amrnb_probe(AVProbeData *p) while (i < p->buf_size) { mode = b[i] >> 3 & 0x0F; if (mode < 9 && (b[i] & 0x4) == 0x4) { - int last = mode; + int last = b[i]; int size = amrnb_packed_size[mode]; while (size--) { if (b[++i] != last) break; - last = b[i]; } if (size > 0) { valid++; @@ -201,7 +200,7 @@ static int amrnb_probe(AVProbeData *p) i++; } } - if (valid > 100 && valid > invalid) + if (valid > 100 && valid >> 4 > invalid) return AVPROBE_SCORE_EXTENSION / 2 + 1; return 0; } @@ -233,7 +232,7 @@ AVInputFormat ff_amrnb_demuxer = { #endif #if CONFIG_AMRWB_DEMUXER -static int amrwb_probe(AVProbeData *p) +static int amrwb_probe(const AVProbeData *p) { int mode, i = 0, valid = 0, invalid = 0; const uint8_t *b = p->buf; @@ -241,12 +240,11 @@ static int amrwb_probe(AVProbeData *p) while (i < p->buf_size) { mode = b[i] >> 3 & 0x0F; if (mode < 10 && (b[i] & 0x4) == 0x4) { - int last = mode; + int last = b[i]; int size = amrwb_packed_size[mode]; while (size--) { if (b[++i] != last) break; - last = b[i]; } if (size > 0) { valid++; @@ -258,8 +256,8 @@ static int amrwb_probe(AVProbeData *p) i++; } } - if (valid > 100 && valid > invalid) - return AVPROBE_SCORE_EXTENSION / 2 - 1; + if (valid > 100 && valid >> 4 > invalid) + return AVPROBE_SCORE_EXTENSION / 2 + 1; return 0; } diff --git a/libavformat/anm.c b/libavformat/anm.c index b31757ab0..9af3a4179 100644 --- a/libavformat/anm.c +++ b/libavformat/anm.c @@ -47,7 +47,7 @@ typedef struct AnmDemuxContext { #define LPF_TAG MKTAG('L','P','F',' ') #define ANIM_TAG MKTAG('A','N','I','M') -static int probe(AVProbeData *p) +static int probe(const AVProbeData *p) { /* verify tags and video dimensions */ if (AV_RL32(&p->buf[0]) == LPF_TAG && @@ -132,12 +132,7 @@ static int read_header(AVFormatContext *s) avio_skip(pb, 58); /* color cycling and palette data */ - st->codecpar->extradata_size = 16*8 + 4*256; - st->codecpar->extradata = av_mallocz(st->codecpar->extradata_size + AV_INPUT_BUFFER_PADDING_SIZE); - if (!st->codecpar->extradata) { - return AVERROR(ENOMEM); - } - ret = avio_read(pb, st->codecpar->extradata, st->codecpar->extradata_size); + ret = ff_get_extradata(s, st->codecpar, s->pb, 16*8 + 4*256); if (ret < 0) return ret; diff --git a/libavformat/apc.c b/libavformat/apc.c index b180a50c9..835d1b0f6 100644 --- a/libavformat/apc.c +++ b/libavformat/apc.c @@ -25,7 +25,7 @@ #include "avformat.h" #include "internal.h" -static int apc_probe(AVProbeData *p) +static int apc_probe(const AVProbeData *p) { if (!strncmp(p->buf, "CRYO_APC", 8)) return AVPROBE_SCORE_MAX; diff --git a/libavformat/ape.c b/libavformat/ape.c index c06db7848..977e6f3d1 100644 --- a/libavformat/ape.c +++ b/libavformat/ape.c @@ -83,7 +83,7 @@ typedef struct APEContext { uint8_t *bittable; } APEContext; -static int ape_probe(AVProbeData * p) +static int ape_probe(const AVProbeData * p) { int version = AV_RL16(p->buf+4); if (AV_RL32(p->buf) != MKTAG('M', 'A', 'C', ' ')) diff --git a/libavformat/apetag.c b/libavformat/apetag.c index cdc602e1a..8cb3f4a23 100644 --- a/libavformat/apetag.c +++ b/libavformat/apetag.c @@ -29,7 +29,7 @@ #include "apetag.h" #include "internal.h" -#define APE_TAG_FLAG_CONTAINS_HEADER (1 << 31) +#define APE_TAG_FLAG_CONTAINS_HEADER (1U << 31) #define APE_TAG_FLAG_LACKS_FOOTER (1 << 30) #define APE_TAG_FLAG_IS_HEADER (1 << 29) #define APE_TAG_FLAG_IS_BINARY (1 << 1) diff --git a/libavformat/apngdec.c b/libavformat/apngdec.c index ffff03710..c8db9c6e1 100644 --- a/libavformat/apngdec.c +++ b/libavformat/apngdec.c @@ -44,7 +44,6 @@ typedef struct APNGDemuxContext { int max_fps; int default_fps; - int64_t pkt_pts; int pkt_duration; int is_key_frame; @@ -67,7 +66,7 @@ typedef struct APNGDemuxContext { * ... * IDAT */ -static int apng_probe(AVProbeData *p) +static int apng_probe(const AVProbeData *p) { GetByteContext gb; int state = 0; @@ -343,6 +342,10 @@ static int apng_read_packet(AVFormatContext *s, AVPacket *pkt) len = avio_rb32(pb); tag = avio_rl32(pb); + + if (avio_feof(pb)) + return AVERROR_EOF; + switch (tag) { case MKTAG('f', 'c', 'T', 'L'): if (len != 26) @@ -390,9 +393,8 @@ static int apng_read_packet(AVFormatContext *s, AVPacket *pkt) if (ctx->is_key_frame) pkt->flags |= AV_PKT_FLAG_KEY; - pkt->pts = ctx->pkt_pts; + pkt->pts = pkt->dts = AV_NOPTS_VALUE; pkt->duration = ctx->pkt_duration; - ctx->pkt_pts += ctx->pkt_duration; return ret; case MKTAG('I', 'E', 'N', 'D'): ctx->cur_loop++; diff --git a/libavformat/aqtitledec.c b/libavformat/aqtitledec.c index f0e840b0f..8cc82a8f3 100644 --- a/libavformat/aqtitledec.c +++ b/libavformat/aqtitledec.c @@ -37,7 +37,7 @@ typedef struct { AVRational frame_rate; } AQTitleContext; -static int aqt_probe(AVProbeData *p) +static int aqt_probe(const AVProbeData *p) { int frame; const char *ptr = p->buf; diff --git a/libavformat/asf.h b/libavformat/asf.h index 1a5b33840..a30d3bb23 100644 --- a/libavformat/asf.h +++ b/libavformat/asf.h @@ -166,6 +166,4 @@ extern const AVMetadataConv ff_asf_metadata_conv[]; #define ASF_PL_FLAG_KEY_FRAME 0x80 //1000 0000 -extern AVInputFormat ff_asf_demuxer; - #endif /* AVFORMAT_ASF_H */ diff --git a/libavformat/asfdec_f.c b/libavformat/asfdec_f.c index 64a0b9d7f..57dc3b09b 100644 --- a/libavformat/asfdec_f.c +++ b/libavformat/asfdec_f.c @@ -186,7 +186,7 @@ static void print_guid(ff_asf_guid *g) #define print_guid(g) while(0) #endif -static int asf_probe(AVProbeData *pd) +static int asf_probe(const AVProbeData *pd) { /* check file header */ if (!ff_guidcmp(pd->buf, &ff_asf_header)) diff --git a/libavformat/asfdec_o.c b/libavformat/asfdec_o.c index b4b269836..8e7f044ce 100644 --- a/libavformat/asfdec_o.c +++ b/libavformat/asfdec_o.c @@ -147,7 +147,7 @@ typedef struct ASFContext { static int detect_unknown_subobject(AVFormatContext *s, int64_t offset, int64_t size); static const GUIDParseTable *find_guid(ff_asf_guid guid); -static int asf_probe(AVProbeData *pd) +static int asf_probe(const AVProbeData *pd) { /* check file header */ if (!ff_guidcmp(pd->buf, &ff_asf_header)) diff --git a/libavformat/assdec.c b/libavformat/assdec.c index d89c14e5b..f66b29667 100644 --- a/libavformat/assdec.c +++ b/libavformat/assdec.c @@ -33,7 +33,7 @@ typedef struct ASSContext { unsigned readorder; } ASSContext; -static int ass_probe(AVProbeData *p) +static int ass_probe(const AVProbeData *p) { char buf[13]; FFTextReader tr; diff --git a/libavformat/astdec.c b/libavformat/astdec.c index 4ba08c218..9d2174f70 100644 --- a/libavformat/astdec.c +++ b/libavformat/astdec.c @@ -25,7 +25,7 @@ #include "internal.h" #include "ast.h" -static int ast_probe(AVProbeData *p) +static int ast_probe(const AVProbeData *p) { if (AV_RL32(p->buf) != MKTAG('S','T','R','M')) return 0; diff --git a/libavformat/async.c b/libavformat/async.c index 54dbd2312..4e295b5e1 100644 --- a/libavformat/async.c +++ b/libavformat/async.c @@ -142,7 +142,7 @@ static int ring_size_of_read_back(RingBuffer *ring) static int ring_drain(RingBuffer *ring, int offset) { av_assert2(offset >= -ring_size_of_read_back(ring)); - av_assert2(offset <= -ring_size(ring)); + av_assert2(offset <= ring_size(ring)); ring->read_pos += offset; return 0; } diff --git a/libavformat/au.c b/libavformat/au.c index 520824fc1..cb48e67fe 100644 --- a/libavformat/au.c +++ b/libavformat/au.c @@ -57,7 +57,7 @@ static const AVCodecTag codec_au_tags[] = { #if CONFIG_AU_DEMUXER -static int au_probe(AVProbeData *p) +static int au_probe(const AVProbeData *p) { if (p->buf[0] == '.' && p->buf[1] == 's' && p->buf[2] == 'n' && p->buf[3] == 'd') @@ -140,7 +140,7 @@ static int au_read_header(AVFormatContext *s) unsigned int tag; AVIOContext *pb = s->pb; unsigned int id, channels, rate; - int bps; + int bps, ba = 0; enum AVCodecID codec; AVStream *st; @@ -178,6 +178,7 @@ static int au_read_header(AVFormatContext *s) } else { const uint8_t bpcss[] = {4, 0, 3, 5}; av_assert0(id >= 23 && id < 23 + 4); + ba = bpcss[id - 23]; bps = bpcss[id - 23]; } } else if (!bps) { @@ -205,7 +206,7 @@ static int au_read_header(AVFormatContext *s) st->codecpar->sample_rate = rate; st->codecpar->bits_per_coded_sample = bps; st->codecpar->bit_rate = channels * rate * bps; - st->codecpar->block_align = FFMAX(bps * st->codecpar->channels / 8, 1); + st->codecpar->block_align = ba ? ba : FFMAX(bps * st->codecpar->channels / 8, 1); if (data_size != AU_UNKNOWN_SIZE) st->duration = (((int64_t)data_size)<<3) / (st->codecpar->channels * (int64_t)bps); diff --git a/libavformat/audiointerleave.c b/libavformat/audiointerleave.c index 6d4954bef..dea5d9982 100644 --- a/libavformat/audiointerleave.c +++ b/libavformat/audiointerleave.c @@ -81,15 +81,19 @@ static int interleave_new_audio_packet(AVFormatContext *s, AVPacket *pkt, AVStream *st = s->streams[stream_index]; AudioInterleaveContext *aic = st->priv_data; int ret; - int size = FFMIN(av_fifo_size(aic->fifo), *aic->samples * aic->sample_size); + int frame_size = *aic->samples * aic->sample_size; + int size = FFMIN(av_fifo_size(aic->fifo), frame_size); if (!size || (!flush && size == av_fifo_size(aic->fifo))) return 0; - ret = av_new_packet(pkt, size); + ret = av_new_packet(pkt, frame_size); if (ret < 0) return ret; av_fifo_generic_read(aic->fifo, pkt->data, size, NULL); + if (size < pkt->size) + memset(pkt->data + size, 0, pkt->size - size); + pkt->dts = pkt->pts = aic->dts; pkt->duration = av_rescale_q(*aic->samples, st->time_base, aic->time_base); pkt->stream_index = stream_index; @@ -99,7 +103,7 @@ static int interleave_new_audio_packet(AVFormatContext *s, AVPacket *pkt, if (!*aic->samples) aic->samples = aic->samples_per_frame; - return size; + return pkt->size; } int ff_audio_rechunk_interleave(AVFormatContext *s, AVPacket *out, AVPacket *pkt, int flush, diff --git a/libavformat/av1.c b/libavformat/av1.c new file mode 100644 index 000000000..b36c5e44b --- /dev/null +++ b/libavformat/av1.c @@ -0,0 +1,414 @@ +/* + * AV1 helper functions for muxers + * Copyright (c) 2018 James Almer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/mem.h" +#include "libavcodec/av1.h" +#include "libavcodec/av1_parse.h" +#include "libavcodec/profiles.h" +#include "libavcodec/put_bits.h" +#include "av1.h" +#include "avio.h" + +int ff_av1_filter_obus(AVIOContext *pb, const uint8_t *buf, int size) +{ + const uint8_t *end = buf + size; + int64_t obu_size; + int start_pos, type, temporal_id, spatial_id; + + size = 0; + while (buf < end) { + int len = parse_obu_header(buf, end - buf, &obu_size, &start_pos, + &type, &temporal_id, &spatial_id); + if (len < 0) + return len; + + switch (type) { + case AV1_OBU_TEMPORAL_DELIMITER: + case AV1_OBU_REDUNDANT_FRAME_HEADER: + case AV1_OBU_TILE_LIST: + case AV1_OBU_PADDING: + break; + default: + avio_write(pb, buf, len); + size += len; + break; + } + buf += len; + } + + return size; +} + +int ff_av1_filter_obus_buf(const uint8_t *buf, uint8_t **out, int *size) +{ + AVIOContext *pb; + int ret; + + ret = avio_open_dyn_buf(&pb); + if (ret < 0) + return ret; + + ret = ff_av1_filter_obus(pb, buf, *size); + if (ret < 0) + return ret; + + av_freep(out); + *size = avio_close_dyn_buf(pb, out); + + return ret; +} + +static inline void uvlc(GetBitContext *gb) +{ + int leading_zeros = 0; + + while (get_bits_left(gb)) { + if (get_bits1(gb)) + break; + leading_zeros++; + } + + if (leading_zeros >= 32) + return; + + skip_bits_long(gb, leading_zeros); +} + +static int parse_color_config(AV1SequenceParameters *seq_params, GetBitContext *gb) +{ + int twelve_bit = 0; + int high_bitdepth = get_bits1(gb); + if (seq_params->profile == FF_PROFILE_AV1_PROFESSIONAL && high_bitdepth) + twelve_bit = get_bits1(gb); + + seq_params->bitdepth = 8 + (high_bitdepth * 2) + (twelve_bit * 2); + + if (seq_params->profile == FF_PROFILE_AV1_HIGH) + seq_params->monochrome = 0; + else + seq_params->monochrome = get_bits1(gb); + + seq_params->color_description_present_flag = get_bits1(gb); + if (seq_params->color_description_present_flag) { + seq_params->color_primaries = get_bits(gb, 8); + seq_params->transfer_characteristics = get_bits(gb, 8); + seq_params->matrix_coefficients = get_bits(gb, 8); + } else { + seq_params->color_primaries = AVCOL_PRI_UNSPECIFIED; + seq_params->transfer_characteristics = AVCOL_TRC_UNSPECIFIED; + seq_params->matrix_coefficients = AVCOL_SPC_UNSPECIFIED; + } + + if (seq_params->monochrome) { + seq_params->color_range = get_bits1(gb); + seq_params->chroma_subsampling_x = 1; + seq_params->chroma_subsampling_y = 1; + seq_params->chroma_sample_position = 0; + return 0; + } else if (seq_params->color_primaries == AVCOL_PRI_BT709 && + seq_params->transfer_characteristics == AVCOL_TRC_IEC61966_2_1 && + seq_params->matrix_coefficients == AVCOL_SPC_RGB) { + seq_params->chroma_subsampling_x = 0; + seq_params->chroma_subsampling_y = 0; + } else { + seq_params->color_range = get_bits1(gb); + + if (seq_params->profile == FF_PROFILE_AV1_MAIN) { + seq_params->chroma_subsampling_x = 1; + seq_params->chroma_subsampling_y = 1; + } else if (seq_params->profile == FF_PROFILE_AV1_HIGH) { + seq_params->chroma_subsampling_x = 0; + seq_params->chroma_subsampling_y = 0; + } else { + if (twelve_bit) { + seq_params->chroma_subsampling_x = get_bits1(gb); + if (seq_params->chroma_subsampling_x) + seq_params->chroma_subsampling_y = get_bits1(gb); + else + seq_params->chroma_subsampling_y = 0; + } else { + seq_params->chroma_subsampling_x = 1; + seq_params->chroma_subsampling_y = 0; + } + } + if (seq_params->chroma_subsampling_x && seq_params->chroma_subsampling_y) + seq_params->chroma_sample_position = get_bits(gb, 2); + } + + skip_bits1(gb); // separate_uv_delta_q + + return 0; +} + +static int parse_sequence_header(AV1SequenceParameters *seq_params, const uint8_t *buf, int size) +{ + GetBitContext gb; + int reduced_still_picture_header; + int frame_width_bits_minus_1, frame_height_bits_minus_1; + int size_bits, ret; + + size_bits = get_obu_bit_length(buf, size, AV1_OBU_SEQUENCE_HEADER); + if (size_bits < 0) + return size_bits; + + ret = init_get_bits(&gb, buf, size_bits); + if (ret < 0) + return ret; + + memset(seq_params, 0, sizeof(*seq_params)); + + seq_params->profile = get_bits(&gb, 3); + + skip_bits1(&gb); // still_picture + reduced_still_picture_header = get_bits1(&gb); + + if (reduced_still_picture_header) { + seq_params->level = get_bits(&gb, 5); + seq_params->tier = 0; + } else { + int initial_display_delay_present_flag, operating_points_cnt_minus_1; + int decoder_model_info_present_flag, buffer_delay_length_minus_1; + + if (get_bits1(&gb)) { // timing_info_present_flag + skip_bits_long(&gb, 32); // num_units_in_display_tick + skip_bits_long(&gb, 32); // time_scale + + if (get_bits1(&gb)) // equal_picture_interval + uvlc(&gb); // num_ticks_per_picture_minus_1 + + decoder_model_info_present_flag = get_bits1(&gb); + if (decoder_model_info_present_flag) { + buffer_delay_length_minus_1 = get_bits(&gb, 5); + skip_bits_long(&gb, 32); // num_units_in_decoding_tick + skip_bits(&gb, 10); // buffer_removal_time_length_minus_1 (5) + // frame_presentation_time_length_minus_1 (5) + } + } else + decoder_model_info_present_flag = 0; + + initial_display_delay_present_flag = get_bits1(&gb); + + operating_points_cnt_minus_1 = get_bits(&gb, 5); + for (int i = 0; i <= operating_points_cnt_minus_1; i++) { + int seq_level_idx, seq_tier; + + skip_bits(&gb, 12); // operating_point_idc + seq_level_idx = get_bits(&gb, 5); + + if (seq_level_idx > 7) + seq_tier = get_bits1(&gb); + else + seq_tier = 0; + + if (decoder_model_info_present_flag) { + if (get_bits1(&gb)) { // decoder_model_present_for_this_op + skip_bits_long(&gb, buffer_delay_length_minus_1 + 1); // decoder_buffer_delay + skip_bits_long(&gb, buffer_delay_length_minus_1 + 1); // encoder_buffer_delay + skip_bits1(&gb); // low_delay_mode_flag + } + } + + if (initial_display_delay_present_flag) { + if (get_bits1(&gb)) // initial_display_delay_present_for_this_op + skip_bits(&gb, 4); // initial_display_delay_minus_1 + } + + if (i == 0) { + seq_params->level = seq_level_idx; + seq_params->tier = seq_tier; + } + } + } + + frame_width_bits_minus_1 = get_bits(&gb, 4); + frame_height_bits_minus_1 = get_bits(&gb, 4); + + skip_bits(&gb, frame_width_bits_minus_1 + 1); // max_frame_width_minus_1 + skip_bits(&gb, frame_height_bits_minus_1 + 1); // max_frame_height_minus_1 + + if (!reduced_still_picture_header) { + if (get_bits1(&gb)) // frame_id_numbers_present_flag + skip_bits(&gb, 7); // delta_frame_id_length_minus_2 (4), additional_frame_id_length_minus_1 (3) + } + + skip_bits(&gb, 3); // use_128x128_superblock (1), enable_filter_intra (1), enable_intra_edge_filter (1) + + if (!reduced_still_picture_header) { + int enable_order_hint, seq_force_screen_content_tools; + + skip_bits(&gb, 4); // enable_intraintra_compound (1), enable_masked_compound (1) + // enable_warped_motion (1), enable_dual_filter (1) + + enable_order_hint = get_bits1(&gb); + if (enable_order_hint) + skip_bits(&gb, 2); // enable_jnt_comp (1), enable_ref_frame_mvs (1) + + if (get_bits1(&gb)) // seq_choose_screen_content_tools + seq_force_screen_content_tools = 2; + else + seq_force_screen_content_tools = get_bits1(&gb); + + if (seq_force_screen_content_tools) { + if (!get_bits1(&gb)) // seq_choose_integer_mv + skip_bits1(&gb); // seq_force_integer_mv + } + + if (enable_order_hint) + skip_bits(&gb, 3); // order_hint_bits_minus_1 + } + + skip_bits(&gb, 3); // enable_superres (1), enable_cdef (1), enable_restoration (1) + + parse_color_config(seq_params, &gb); + + skip_bits1(&gb); // film_grain_params_present + + if (get_bits_left(&gb)) + return AVERROR_INVALIDDATA; + + return 0; +} + +int ff_av1_parse_seq_header(AV1SequenceParameters *seq, const uint8_t *buf, int size) +{ + int64_t obu_size; + int start_pos, type, temporal_id, spatial_id; + + if (size <= 0) + return AVERROR_INVALIDDATA; + + while (size > 0) { + int len = parse_obu_header(buf, size, &obu_size, &start_pos, + &type, &temporal_id, &spatial_id); + if (len < 0) + return len; + + switch (type) { + case AV1_OBU_SEQUENCE_HEADER: + if (!obu_size) + return AVERROR_INVALIDDATA; + + return parse_sequence_header(seq, buf + start_pos, obu_size); + default: + break; + } + size -= len; + buf += len; + } + + return AVERROR_INVALIDDATA; +} + +int ff_isom_write_av1c(AVIOContext *pb, const uint8_t *buf, int size) +{ + AVIOContext *seq_pb = NULL, *meta_pb = NULL; + AV1SequenceParameters seq_params; + PutBitContext pbc; + uint8_t header[4]; + uint8_t *seq = NULL, *meta = NULL; + int64_t obu_size; + int start_pos, type, temporal_id, spatial_id; + int ret, nb_seq = 0, seq_size, meta_size; + + if (size <= 0) + return AVERROR_INVALIDDATA; + + ret = avio_open_dyn_buf(&seq_pb); + if (ret < 0) + return ret; + ret = avio_open_dyn_buf(&meta_pb); + if (ret < 0) + goto fail; + + while (size > 0) { + int len = parse_obu_header(buf, size, &obu_size, &start_pos, + &type, &temporal_id, &spatial_id); + if (len < 0) { + ret = len; + goto fail; + } + + switch (type) { + case AV1_OBU_SEQUENCE_HEADER: + nb_seq++; + if (!obu_size || nb_seq > 1) { + ret = AVERROR_INVALIDDATA; + goto fail; + } + ret = parse_sequence_header(&seq_params, buf + start_pos, obu_size); + if (ret < 0) + goto fail; + + avio_write(seq_pb, buf, len); + break; + case AV1_OBU_METADATA: + if (!obu_size) { + ret = AVERROR_INVALIDDATA; + goto fail; + } + avio_write(meta_pb, buf, len); + break; + default: + break; + } + size -= len; + buf += len; + } + + seq_size = avio_close_dyn_buf(seq_pb, &seq); + if (!seq_size) { + ret = AVERROR_INVALIDDATA; + goto fail; + } + + init_put_bits(&pbc, header, sizeof(header)); + + put_bits(&pbc, 1, 1); // marker + put_bits(&pbc, 7, 1); // version + put_bits(&pbc, 3, seq_params.profile); + put_bits(&pbc, 5, seq_params.level); + put_bits(&pbc, 1, seq_params.tier); + put_bits(&pbc, 1, seq_params.bitdepth > 8); + put_bits(&pbc, 1, seq_params.bitdepth == 12); + put_bits(&pbc, 1, seq_params.monochrome); + put_bits(&pbc, 1, seq_params.chroma_subsampling_x); + put_bits(&pbc, 1, seq_params.chroma_subsampling_y); + put_bits(&pbc, 2, seq_params.chroma_sample_position); + put_bits(&pbc, 8, 0); // padding + flush_put_bits(&pbc); + + avio_write(pb, header, sizeof(header)); + avio_write(pb, seq, seq_size); + + meta_size = avio_close_dyn_buf(meta_pb, &meta); + if (meta_size) + avio_write(pb, meta, meta_size); + +fail: + if (!seq) + avio_close_dyn_buf(seq_pb, &seq); + if (!meta) + avio_close_dyn_buf(meta_pb, &meta); + av_free(seq); + av_free(meta); + + return ret; +} diff --git a/libavformat/av1.h b/libavformat/av1.h new file mode 100644 index 000000000..441b6c989 --- /dev/null +++ b/libavformat/av1.h @@ -0,0 +1,98 @@ +/* + * AV1 helper functions for muxers + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVFORMAT_AV1_H +#define AVFORMAT_AV1_H + +#include + +#include "avio.h" + +typedef struct AV1SequenceParameters { + uint8_t profile; + uint8_t level; + uint8_t tier; + uint8_t bitdepth; + uint8_t monochrome; + uint8_t chroma_subsampling_x; + uint8_t chroma_subsampling_y; + uint8_t chroma_sample_position; + uint8_t color_description_present_flag; + uint8_t color_primaries; + uint8_t transfer_characteristics; + uint8_t matrix_coefficients; + uint8_t color_range; +} AV1SequenceParameters; + +/** + * Filter out AV1 OBUs not meant to be present in ISOBMFF sample data and write + * the resulting bitstream to the provided AVIOContext. + * + * @param pb pointer to the AVIOContext where the filtered bitstream shall be + * written + * @param buf input data buffer + * @param size size of the input data buffer + * + * @return the amount of bytes written in case of success, a negative AVERROR + * code in case of failure + */ +int ff_av1_filter_obus(AVIOContext *pb, const uint8_t *buf, int size); + +/** + * Filter out AV1 OBUs not meant to be present in ISOBMFF sample data and write + * the resulting bitstream to a newly allocated data buffer. + * + * @param pb pointer to the AVIOContext where the filtered bitstream shall be + * written + * @param buf input data buffer + * @param out pointer to pointer that will hold the allocated data buffer + * @param size size of the input data buffer. The size of the resulting output + data buffer will be written here + * + * @return the amount of bytes written in case of success, a negative AVERROR + * code in case of failure. On failure, out and size are unchanged + */ +int ff_av1_filter_obus_buf(const uint8_t *buf, uint8_t **out, int *size); + +/** + * Parses a Sequence Header from the the provided buffer. + * + * @param seq pointer to the AV1SequenceParameters where the parsed values will + * be written + * @param buf input data buffer + * @param size size in bytes of the input data buffer + * + * @return >= 0 in case of success, a negative AVERROR code in case of failure + */ +int ff_av1_parse_seq_header(AV1SequenceParameters *seq, const uint8_t *buf, int size); + +/** + * Writes AV1 extradata (Sequence Header and Metadata OBUs) to the provided + * AVIOContext. + * + * @param pb pointer to the AVIOContext where the hvcC shall be written + * @param buf input data buffer + * @param size size in bytes of the input data buffer + * + * @return >= 0 in case of success, a negative AVERROR code in case of failure + */ +int ff_isom_write_av1c(AVIOContext *pb, const uint8_t *buf, int size); + +#endif /* AVFORMAT_AV1_H */ diff --git a/libavformat/avc.c b/libavformat/avc.c index ec50033a0..a041e8435 100644 --- a/libavformat/avc.c +++ b/libavformat/avc.c @@ -21,6 +21,7 @@ #include "libavutil/intreadwrite.h" #include "libavcodec/h264.h" +#include "libavcodec/get_bits.h" #include "avformat.h" #include "avio.h" #include "avc.h" @@ -241,3 +242,188 @@ const uint8_t *ff_avc_mp4_find_startcode(const uint8_t *start, return start + res; } + +uint8_t *ff_nal_unit_extract_rbsp(const uint8_t *src, uint32_t src_len, + uint32_t *dst_len, int header_len) +{ + uint8_t *dst; + uint32_t i, len; + + dst = av_malloc(src_len + AV_INPUT_BUFFER_PADDING_SIZE); + if (!dst) + return NULL; + + /* NAL unit header */ + i = len = 0; + while (i < header_len && i < src_len) + dst[len++] = src[i++]; + + while (i + 2 < src_len) + if (!src[i] && !src[i + 1] && src[i + 2] == 3) { + dst[len++] = src[i++]; + dst[len++] = src[i++]; + i++; // remove emulation_prevention_three_byte + } else + dst[len++] = src[i++]; + + while (i < src_len) + dst[len++] = src[i++]; + + memset(dst + len, 0, AV_INPUT_BUFFER_PADDING_SIZE); + + *dst_len = len; + return dst; +} + +static const AVRational avc_sample_aspect_ratio[17] = { + { 0, 1 }, + { 1, 1 }, + { 12, 11 }, + { 10, 11 }, + { 16, 11 }, + { 40, 33 }, + { 24, 11 }, + { 20, 11 }, + { 32, 11 }, + { 80, 33 }, + { 18, 11 }, + { 15, 11 }, + { 64, 33 }, + { 160, 99 }, + { 4, 3 }, + { 3, 2 }, + { 2, 1 }, +}; + +static inline int get_ue_golomb(GetBitContext *gb) { + int i; + for (i = 0; i < 32 && !get_bits1(gb); i++) + ; + return get_bitsz(gb, i) + (1 << i) - 1; +} + +static inline int get_se_golomb(GetBitContext *gb) { + int v = get_ue_golomb(gb) + 1; + int sign = -(v & 1); + return ((v >> 1) ^ sign) - sign; +} + +H264SequenceParameterSet *ff_avc_decode_sps(const uint8_t *buf, int buf_size) +{ + int i, j, ret, rbsp_size, aspect_ratio_idc, pic_order_cnt_type; + int num_ref_frames_in_pic_order_cnt_cycle; + int delta_scale, lastScale = 8, nextScale = 8; + int sizeOfScalingList; + H264SequenceParameterSet *sps = NULL; + GetBitContext gb; + uint8_t *rbsp_buf; + + rbsp_buf = ff_nal_unit_extract_rbsp(buf, buf_size, &rbsp_size, 0); + if (!rbsp_buf) + return NULL; + + ret = init_get_bits8(&gb, rbsp_buf, rbsp_size); + if (ret < 0) + goto end; + + sps = av_mallocz(sizeof(*sps)); + if (!sps) + goto end; + + sps->profile_idc = get_bits(&gb, 8); + sps->constraint_set_flags |= get_bits1(&gb) << 0; // constraint_set0_flag + sps->constraint_set_flags |= get_bits1(&gb) << 1; // constraint_set1_flag + sps->constraint_set_flags |= get_bits1(&gb) << 2; // constraint_set2_flag + sps->constraint_set_flags |= get_bits1(&gb) << 3; // constraint_set3_flag + sps->constraint_set_flags |= get_bits1(&gb) << 4; // constraint_set4_flag + sps->constraint_set_flags |= get_bits1(&gb) << 5; // constraint_set5_flag + skip_bits(&gb, 2); // reserved_zero_2bits + sps->level_idc = get_bits(&gb, 8); + sps->id = get_ue_golomb(&gb); + + if (sps->profile_idc == 100 || sps->profile_idc == 110 || + sps->profile_idc == 122 || sps->profile_idc == 244 || sps->profile_idc == 44 || + sps->profile_idc == 83 || sps->profile_idc == 86 || sps->profile_idc == 118 || + sps->profile_idc == 128 || sps->profile_idc == 138 || sps->profile_idc == 139 || + sps->profile_idc == 134) { + sps->chroma_format_idc = get_ue_golomb(&gb); // chroma_format_idc + if (sps->chroma_format_idc == 3) { + skip_bits1(&gb); // separate_colour_plane_flag + } + sps->bit_depth_luma = get_ue_golomb(&gb) + 8; + get_ue_golomb(&gb); // bit_depth_chroma_minus8 + skip_bits1(&gb); // qpprime_y_zero_transform_bypass_flag + if (get_bits1(&gb)) { // seq_scaling_matrix_present_flag + for (i = 0; i < ((sps->chroma_format_idc != 3) ? 8 : 12); i++) { + if (!get_bits1(&gb)) // seq_scaling_list_present_flag + continue; + lastScale = 8; + nextScale = 8; + sizeOfScalingList = i < 6 ? 16 : 64; + for (j = 0; j < sizeOfScalingList; j++) { + if (nextScale != 0) { + delta_scale = get_se_golomb(&gb); + nextScale = (lastScale + delta_scale) & 0xff; + } + lastScale = nextScale == 0 ? lastScale : nextScale; + } + } + } + } else { + sps->chroma_format_idc = 1; + sps->bit_depth_luma = 8; + } + + get_ue_golomb(&gb); // log2_max_frame_num_minus4 + pic_order_cnt_type = get_ue_golomb(&gb); + + if (pic_order_cnt_type == 0) { + get_ue_golomb(&gb); // log2_max_pic_order_cnt_lsb_minus4 + } else if (pic_order_cnt_type == 1) { + skip_bits1(&gb); // delta_pic_order_always_zero + get_se_golomb(&gb); // offset_for_non_ref_pic + get_se_golomb(&gb); // offset_for_top_to_bottom_field + num_ref_frames_in_pic_order_cnt_cycle = get_ue_golomb(&gb); + for (i = 0; i < num_ref_frames_in_pic_order_cnt_cycle; i++) + get_se_golomb(&gb); // offset_for_ref_frame + } + + get_ue_golomb(&gb); // max_num_ref_frames + skip_bits1(&gb); // gaps_in_frame_num_value_allowed_flag + get_ue_golomb(&gb); // pic_width_in_mbs_minus1 + get_ue_golomb(&gb); // pic_height_in_map_units_minus1 + + sps->frame_mbs_only_flag = get_bits1(&gb); + if (!sps->frame_mbs_only_flag) + skip_bits1(&gb); // mb_adaptive_frame_field_flag + + skip_bits1(&gb); // direct_8x8_inference_flag + + if (get_bits1(&gb)) { // frame_cropping_flag + get_ue_golomb(&gb); // frame_crop_left_offset + get_ue_golomb(&gb); // frame_crop_right_offset + get_ue_golomb(&gb); // frame_crop_top_offset + get_ue_golomb(&gb); // frame_crop_bottom_offset + } + + if (get_bits1(&gb)) { // vui_parameters_present_flag + if (get_bits1(&gb)) { // aspect_ratio_info_present_flag + aspect_ratio_idc = get_bits(&gb, 8); + if (aspect_ratio_idc == 0xff) { + sps->sar.num = get_bits(&gb, 16); + sps->sar.den = get_bits(&gb, 16); + } else if (aspect_ratio_idc < FF_ARRAY_ELEMS(avc_sample_aspect_ratio)) { + sps->sar = avc_sample_aspect_ratio[aspect_ratio_idc]; + } + } + } + + if (!sps->sar.den) { + sps->sar.num = 1; + sps->sar.den = 1; + } + + end: + av_free(rbsp_buf); + return sps; +} diff --git a/libavformat/avc.h b/libavformat/avc.h index c5e80ff65..a79bf9b2d 100644 --- a/libavformat/avc.h +++ b/libavformat/avc.h @@ -33,5 +33,20 @@ int ff_avc_write_annexb_extradata(const uint8_t *in, uint8_t **buf, int *size); const uint8_t *ff_avc_mp4_find_startcode(const uint8_t *start, const uint8_t *end, int nal_length_size); +uint8_t *ff_nal_unit_extract_rbsp(const uint8_t *src, uint32_t src_len, + uint32_t *dst_len, int header_len); + +typedef struct { + uint8_t id; + uint8_t profile_idc; + uint8_t level_idc; + uint8_t constraint_set_flags; + uint8_t chroma_format_idc; + uint8_t bit_depth_luma; + uint8_t frame_mbs_only_flag; + AVRational sar; +} H264SequenceParameterSet; + +H264SequenceParameterSet *ff_avc_decode_sps(const uint8_t *src, int src_len); #endif /* AVFORMAT_AVC_H */ diff --git a/libavformat/avformat.h b/libavformat/avformat.h index a2fe7c6bb..6eb329f13 100644 --- a/libavformat/avformat.h +++ b/libavformat/avformat.h @@ -36,17 +36,15 @@ * into component streams, and the reverse process of muxing - writing supplied * data in a specified container format. It also has an @ref lavf_io * "I/O module" which supports a number of protocols for accessing the data (e.g. - * file, tcp, http and others). Before using lavf, you need to call - * av_register_all() to register all compiled muxers, demuxers and protocols. + * file, tcp, http and others). * Unless you are absolutely sure you won't use libavformat's network * capabilities, you should also call avformat_network_init(). * * A supported input format is described by an AVInputFormat struct, conversely * an output format is described by AVOutputFormat. You can iterate over all - * registered input/output formats using the av_iformat_next() / - * av_oformat_next() functions. The protocols layer is not part of the public - * API, so you can only get the names of supported protocols with the - * avio_enum_protocols() function. + * input/output formats using the av_demuxer_iterate / av_muxer_iterate() functions. + * The protocols layer is not part of the public API, so you can only get the names + * of supported protocols with the avio_enum_protocols() function. * * Main lavf structure used for both muxing and demuxing is AVFormatContext, * which exports all information about the file being read or written. As with @@ -177,8 +175,8 @@ * Otherwise, if AVPacket.buf is NULL, the packet data is backed by a * static storage somewhere inside the demuxer and the packet is only valid * until the next av_read_frame() call or closing the file. If the caller - * requires a longer lifetime, av_dup_packet() will make an av_malloc()ed copy - * of it. + * requires a longer lifetime, av_packet_make_refcounted() will ensure that + * the data is reference counted, copying the data if necessary. * In both cases, the packet must be freed with av_packet_unref() when it is no * longer needed. * @@ -532,7 +530,16 @@ typedef struct AVOutputFormat { * New public fields should be added right above. ***************************************************************** */ - struct AVOutputFormat *next; + /** + * The ff_const59 define is not part of the public API and will + * be removed without further warning. + */ +#if FF_API_AVIOFORMAT +#define ff_const59 +#else +#define ff_const59 const +#endif + ff_const59 struct AVOutputFormat *next; /** * size of private data so that it can be allocated in the wrapper */ @@ -646,7 +653,7 @@ typedef struct AVInputFormat { /** * Can use flags: AVFMT_NOFILE, AVFMT_NEEDNUMBER, AVFMT_SHOW_IDS, - * AVFMT_GENERIC_INDEX, AVFMT_TS_DISCONT, AVFMT_NOBINSEARCH, + * AVFMT_NOTIMESTAMPS, AVFMT_GENERIC_INDEX, AVFMT_TS_DISCONT, AVFMT_NOBINSEARCH, * AVFMT_NOGENSEARCH, AVFMT_NO_BYTE_SEEK, AVFMT_SEEK_TO_PTS. */ int flags; @@ -676,7 +683,7 @@ typedef struct AVInputFormat { * New public fields should be added right above. ***************************************************************** */ - struct AVInputFormat *next; + ff_const59 struct AVInputFormat *next; /** * Raw demuxers store their codec ID here. @@ -693,7 +700,7 @@ typedef struct AVInputFormat { * The buffer provided is guaranteed to be AVPROBE_PADDING_SIZE bytes * big so you do not have to check for that unless you need more. */ - int (*read_probe)(AVProbeData *); + int (*read_probe)(const AVProbeData *); /** * Read the format header and initialize the AVFormatContext @@ -846,6 +853,7 @@ typedef struct AVStreamInternal AVStreamInternal; #define AV_DISPOSITION_DESCRIPTIONS 0x20000 #define AV_DISPOSITION_METADATA 0x40000 #define AV_DISPOSITION_DEPENDENT 0x80000 ///< dependent audio stream (mix_type=0 in mpegts) +#define AV_DISPOSITION_STILL_IMAGE 0x100000 ///< still images in video stream (still_picture_flag=1 in mpegts) /** * Options for behavior on timestamp wrap detection. @@ -1102,6 +1110,13 @@ typedef struct AVStream { */ int stream_identifier; + /** + * Details of the MPEG-TS program which created this stream. + */ + int program_num; + int pmt_version; + int pmt_stream_idx; + int64_t interleaver_chunk_size; int64_t interleaver_chunk_duration; @@ -1259,6 +1274,7 @@ typedef struct AVProgram { int program_num; int pmt_pid; int pcr_pid; + int pmt_version; /***************************************************************** * All fields below this line are not part of the public API. They @@ -1337,14 +1353,14 @@ typedef struct AVFormatContext { * * Demuxing only, set by avformat_open_input(). */ - struct AVInputFormat *iformat; + ff_const59 struct AVInputFormat *iformat; /** * The output container format. * * Muxing only, must be set by the caller before avformat_write_header(). */ - struct AVOutputFormat *oformat; + ff_const59 struct AVOutputFormat *oformat; /** * Format private data. This is an AVOptions-enabled struct @@ -1474,7 +1490,9 @@ typedef struct AVFormatContext { * This flag is mainly intended for testing. */ #define AVFMT_FLAG_BITEXACT 0x0400 -#define AVFMT_FLAG_MP4A_LATM 0x8000 ///< Enable RTP MP4A-LATM payload +#if FF_API_LAVF_MP4A_LATM +#define AVFMT_FLAG_MP4A_LATM 0x8000 ///< Deprecated, does nothing. +#endif #define AVFMT_FLAG_SORT_DTS 0x10000 ///< try to interleave outputted packets by dts (using this flag can slow demuxing down) #define AVFMT_FLAG_PRIV_OPT 0x20000 ///< Enable use of private options by delaying codec open (this could be made default once all code is converted) #if FF_API_LAVF_KEEPSIDE_FLAG @@ -1926,6 +1944,13 @@ typedef struct AVFormatContext { * - decoding: set by user */ int max_streams; + + /** + * Skip duration calcuation in estimate_timings_from_pts. + * - encoding: unused + * - decoding: set by user + */ + int skip_estimate_duration_from_pts; } AVFormatContext; #if FF_API_FORMAT_GET_SET @@ -2193,7 +2218,7 @@ AVProgram *av_new_program(AVFormatContext *s, int id); * @return >= 0 in case of success, a negative AVERROR code in case of * failure */ -int avformat_alloc_output_context2(AVFormatContext **ctx, AVOutputFormat *oformat, +int avformat_alloc_output_context2(AVFormatContext **ctx, ff_const59 AVOutputFormat *oformat, const char *format_name, const char *filename); /** @@ -2204,7 +2229,7 @@ int avformat_alloc_output_context2(AVFormatContext **ctx, AVOutputFormat *oforma /** * Find AVInputFormat based on the short name of the input format. */ -AVInputFormat *av_find_input_format(const char *short_name); +ff_const59 AVInputFormat *av_find_input_format(const char *short_name); /** * Guess the file format. @@ -2213,7 +2238,7 @@ AVInputFormat *av_find_input_format(const char *short_name); * @param is_opened Whether the file is already opened; determines whether * demuxers with or without AVFMT_NOFILE are probed. */ -AVInputFormat *av_probe_input_format(AVProbeData *pd, int is_opened); +ff_const59 AVInputFormat *av_probe_input_format(ff_const59 AVProbeData *pd, int is_opened); /** * Guess the file format. @@ -2227,7 +2252,7 @@ AVInputFormat *av_probe_input_format(AVProbeData *pd, int is_opened); * If the score is <= AVPROBE_SCORE_MAX / 4 it is recommended * to retry with a larger probe buffer. */ -AVInputFormat *av_probe_input_format2(AVProbeData *pd, int is_opened, int *score_max); +ff_const59 AVInputFormat *av_probe_input_format2(ff_const59 AVProbeData *pd, int is_opened, int *score_max); /** * Guess the file format. @@ -2236,7 +2261,7 @@ AVInputFormat *av_probe_input_format2(AVProbeData *pd, int is_opened, int *score * demuxers with or without AVFMT_NOFILE are probed. * @param score_ret The score of the best detection. */ -AVInputFormat *av_probe_input_format3(AVProbeData *pd, int is_opened, int *score_ret); +ff_const59 AVInputFormat *av_probe_input_format3(ff_const59 AVProbeData *pd, int is_opened, int *score_ret); /** * Probe a bytestream to determine the input format. Each time a probe returns @@ -2254,14 +2279,14 @@ AVInputFormat *av_probe_input_format3(AVProbeData *pd, int is_opened, int *score * the maximal score is AVPROBE_SCORE_MAX * AVERROR code otherwise */ -int av_probe_input_buffer2(AVIOContext *pb, AVInputFormat **fmt, +int av_probe_input_buffer2(AVIOContext *pb, ff_const59 AVInputFormat **fmt, const char *url, void *logctx, unsigned int offset, unsigned int max_probe_size); /** * Like av_probe_input_buffer2() but returns 0 on success */ -int av_probe_input_buffer(AVIOContext *pb, AVInputFormat **fmt, +int av_probe_input_buffer(AVIOContext *pb, ff_const59 AVInputFormat **fmt, const char *url, void *logctx, unsigned int offset, unsigned int max_probe_size); @@ -2284,7 +2309,7 @@ int av_probe_input_buffer(AVIOContext *pb, AVInputFormat **fmt, * * @note If you want to use custom IO, preallocate the format context and set its pb field. */ -int avformat_open_input(AVFormatContext **ps, const char *url, AVInputFormat *fmt, AVDictionary **options); +int avformat_open_input(AVFormatContext **ps, const char *url, ff_const59 AVInputFormat *fmt, AVDictionary **options); attribute_deprecated int av_demuxer_open(AVFormatContext *ic); @@ -2669,14 +2694,14 @@ int av_write_trailer(AVFormatContext *s); * @param mime_type if non-NULL checks if mime_type matches with the * MIME type of the registered formats */ -AVOutputFormat *av_guess_format(const char *short_name, +ff_const59 AVOutputFormat *av_guess_format(const char *short_name, const char *filename, const char *mime_type); /** * Guess the codec ID based upon muxer and filename. */ -enum AVCodecID av_guess_codec(AVOutputFormat *fmt, const char *short_name, +enum AVCodecID av_guess_codec(ff_const59 AVOutputFormat *fmt, const char *short_name, const char *filename, const char *mime_type, enum AVMediaType type); diff --git a/libavformat/avidec.c b/libavformat/avidec.c index bafe1dc8d..df78925d5 100644 --- a/libavformat/avidec.c +++ b/libavformat/avidec.c @@ -456,7 +456,7 @@ static int calculate_bitrate(AVFormatContext *s) continue; duration = st->index_entries[j-1].timestamp - st->index_entries[0].timestamp; bitrate = av_rescale(8*len, st->time_base.den, duration * st->time_base.num); - if (bitrate <= INT_MAX && bitrate > 0) { + if (bitrate > 0) { st->codecpar->bit_rate = bitrate; } } @@ -815,6 +815,9 @@ FF_ENABLE_DEPRECATION_WARNINGS "mov tag found in avi (fourcc %s)\n", av_fourcc2str(tag1)); } + if (!st->codecpar->codec_id) + st->codecpar->codec_id = ff_codec_get_id(ff_codec_bmp_tags_unofficial, tag1); + /* This is needed to get the pict type which is necessary * for generating correct pts. */ st->need_parsing = AVSTREAM_PARSE_HEADERS; @@ -1068,7 +1071,7 @@ static int read_gab2_sub(AVFormatContext *s, AVStream *st, AVPacket *pkt) uint8_t desc[256]; int score = AVPROBE_SCORE_EXTENSION, ret; AVIStream *ast = st->priv_data; - AVInputFormat *sub_demuxer; + ff_const59 AVInputFormat *sub_demuxer; AVRational time_base; int size; AVIOContext *pb = avio_alloc_context(pkt->data + 7, @@ -1231,6 +1234,11 @@ start_sync: goto start_sync; } + if (d[2] == 'w' && d[3] == 'c' && n < s->nb_streams) { + avio_skip(pb, 16 * 3 + 8); + goto start_sync; + } + if (avi->dv_demux && n != 0) continue; @@ -1915,7 +1923,7 @@ static int avi_read_close(AVFormatContext *s) return 0; } -static int avi_probe(AVProbeData *p) +static int avi_probe(const AVProbeData *p) { int i; diff --git a/libavformat/avio.c b/libavformat/avio.c index 63e82872f..663789ec0 100644 --- a/libavformat/avio.c +++ b/libavformat/avio.c @@ -663,8 +663,7 @@ int ffurl_shutdown(URLContext *h, int flags) int ff_check_interrupt(AVIOInterruptCB *cb) { - int ret; - if (cb && cb->callback && (ret = cb->callback(cb->opaque))) - return ret; + if (cb && cb->callback) + return cb->callback(cb->opaque); return 0; } diff --git a/libavformat/avio.h b/libavformat/avio.h index 75912ce6b..dcb8dcdf9 100644 --- a/libavformat/avio.h +++ b/libavformat/avio.h @@ -236,7 +236,7 @@ typedef struct AVIOContext { int (*write_packet)(void *opaque, uint8_t *buf, int buf_size); int64_t (*seek)(void *opaque, int64_t offset, int whence); int64_t pos; /**< position in the file of the current buffer */ - int eof_reached; /**< true if eof reached */ + int eof_reached; /**< true if was unable to read due to error or eof */ int write_flag; /**< true if open for writing */ int max_packet_size; unsigned long checksum; @@ -566,8 +566,8 @@ static av_always_inline int64_t avio_tell(AVIOContext *s) int64_t avio_size(AVIOContext *s); /** - * feof() equivalent for AVIOContext. - * @return non zero if and only if end of file + * Similar to feof() but also returns nonzero on read errors. + * @return non zero if and only if at end of file or a read error happened when reading. */ int avio_feof(AVIOContext *s); diff --git a/libavformat/aviobuf.c b/libavformat/aviobuf.c index e752d0e1a..2d011027c 100644 --- a/libavformat/aviobuf.c +++ b/libavformat/aviobuf.c @@ -570,7 +570,7 @@ static void fill_buffer(AVIOContext *s) } /* make buffer smaller in case it ended up large after probing */ - if (s->read_packet && s->orig_buffer_size && s->buffer_size > s->orig_buffer_size) { + if (s->read_packet && s->orig_buffer_size && s->buffer_size > s->orig_buffer_size && len >= s->orig_buffer_size) { if (dst == s->buffer && s->buf_ptr != dst) { int ret = ffio_set_buf_size(s, s->orig_buffer_size); if (ret < 0) @@ -578,7 +578,6 @@ static void fill_buffer(AVIOContext *s) s->checksum_ptr = dst = s->buffer; } - av_assert0(len >= s->orig_buffer_size); len = s->orig_buffer_size; } @@ -1181,12 +1180,6 @@ int avio_open2(AVIOContext **s, const char *filename, int flags, return ffio_open_whitelist(s, filename, flags, int_cb, options, NULL, NULL); } -int ffio_open2_wrapper(struct AVFormatContext *s, AVIOContext **pb, const char *url, int flags, - const AVIOInterruptCB *int_cb, AVDictionary **options) -{ - return ffio_open_whitelist(pb, url, flags, int_cb, options, s->protocol_whitelist, s->protocol_blacklist); -} - int avio_close(AVIOContext *s) { AVIOInternal *internal; @@ -1202,9 +1195,9 @@ int avio_close(AVIOContext *s) av_freep(&s->opaque); av_freep(&s->buffer); if (s->write_flag) - av_log(s, AV_LOG_DEBUG, "Statistics: %d seeks, %d writeouts\n", s->seek_count, s->writeout_count); + av_log(s, AV_LOG_VERBOSE, "Statistics: %d seeks, %d writeouts\n", s->seek_count, s->writeout_count); else - av_log(s, AV_LOG_DEBUG, "Statistics: %"PRId64" bytes read, %d seeks\n", s->bytes_read, s->seek_count); + av_log(s, AV_LOG_VERBOSE, "Statistics: %"PRId64" bytes read, %d seeks\n", s->bytes_read, s->seek_count); av_opt_free(s); avio_context_free(&s); diff --git a/libavformat/avisynth.c b/libavformat/avisynth.c index 250a48932..5dfe94ae0 100644 --- a/libavformat/avisynth.c +++ b/libavformat/avisynth.c @@ -123,7 +123,8 @@ static av_cold int avisynth_load_library(void) return AVERROR_UNKNOWN; #define LOAD_AVS_FUNC(name, continue_on_fail) \ - avs_library.name = dlsym(avs_library.library, #name); \ + avs_library.name = (name ## _func) \ + dlsym(avs_library.library, #name); \ if (!continue_on_fail && !avs_library.name) \ goto fail; @@ -323,6 +324,10 @@ static int avisynth_create_stream_video(AVFormatContext *s, AVStream *st) st->codecpar->format = AV_PIX_FMT_YUVA420P10; planar = 4; break; + case AVS_CS_YUVA422P12: + st->codecpar->format = AV_PIX_FMT_YUVA422P12; + planar = 4; + break; case AVS_CS_YUVA444P16: st->codecpar->format = AV_PIX_FMT_YUVA444P16; planar = 4; @@ -356,6 +361,11 @@ static int avisynth_create_stream_video(AVFormatContext *s, AVStream *st) st->codecpar->format = AV_PIX_FMT_GBRP16; planar = 3; break; + /* Single precision floating point Planar RGB (AviSynth+) */ + case AVS_CS_RGBPS: + st->codecpar->format = AV_PIX_FMT_GBRPF32; + planar = 3; + break; /* Planar RGB pix_fmts with Alpha (AviSynth+) */ case AVS_CS_RGBAP: st->codecpar->format = AV_PIX_FMT_GBRAP; @@ -373,11 +383,33 @@ static int avisynth_create_stream_video(AVFormatContext *s, AVStream *st) st->codecpar->format = AV_PIX_FMT_GBRAP16; planar = 5; break; - /* GRAY16 (AviSynth+) */ + /* Single precision floating point Planar RGB with Alpha (AviSynth+) */ + case AVS_CS_RGBAPS: + st->codecpar->format = AV_PIX_FMT_GBRAPF32; + planar = 5; + break; + /* 10~16-bit gray pix_fmts (AviSynth+) */ + case AVS_CS_Y10: + st->codecpar->format = AV_PIX_FMT_GRAY10; + planar = 2; + break; + case AVS_CS_Y12: + st->codecpar->format = AV_PIX_FMT_GRAY12; + planar = 2; + break; + case AVS_CS_Y14: + st->codecpar->format = AV_PIX_FMT_GRAY14; + planar = 2; + break; case AVS_CS_Y16: st->codecpar->format = AV_PIX_FMT_GRAY16; planar = 2; break; + /* Single precision floating point gray (AviSynth+) */ + case AVS_CS_Y32: + st->codecpar->format = AV_PIX_FMT_GRAYF32; + planar = 2; + break; /* pix_fmts added in AviSynth 2.6 */ case AVS_CS_YV24: st->codecpar->format = AV_PIX_FMT_YUV444P; diff --git a/libavformat/avr.c b/libavformat/avr.c index 294160e02..c4ce70142 100644 --- a/libavformat/avr.c +++ b/libavformat/avr.c @@ -24,7 +24,7 @@ #include "internal.h" #include "pcm.h" -static int avr_probe(AVProbeData *p) +static int avr_probe(const AVProbeData *p) { if (AV_RL32(p->buf) != MKTAG('2', 'B', 'I', 'T')) return 0; diff --git a/libavformat/avs.c b/libavformat/avs.c index 763ba63f6..47fa41017 100644 --- a/libavformat/avs.c +++ b/libavformat/avs.c @@ -19,6 +19,12 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +/** + * @file + * Argonaut Games' Creature Shock demuxer + * @see http://wiki.multimedia.cx/index.php?title=AVS + */ + #include "avformat.h" #include "voc.h" @@ -44,7 +50,7 @@ typedef enum avs_block_type { AVS_GAME_DATA = 0x04, } AvsBlockType; -static int avs_probe(AVProbeData * p) +static int avs_probe(const AVProbeData * p) { const uint8_t *d; @@ -225,7 +231,7 @@ static int avs_read_close(AVFormatContext * s) AVInputFormat ff_avs_demuxer = { .name = "avs", - .long_name = NULL_IF_CONFIG_SMALL("AVS"), + .long_name = NULL_IF_CONFIG_SMALL("Argonaut Games Creature Shock"), .priv_data_size = sizeof(AvsFormat), .read_probe = avs_probe, .read_header = avs_read_header, diff --git a/libavformat/bethsoftvid.c b/libavformat/bethsoftvid.c index f516806d9..4aefb04f1 100644 --- a/libavformat/bethsoftvid.c +++ b/libavformat/bethsoftvid.c @@ -55,7 +55,7 @@ typedef struct BVID_DemuxContext } BVID_DemuxContext; -static int vid_probe(AVProbeData *p) +static int vid_probe(const AVProbeData *p) { // little-endian VID tag, file starts with "VID\0" if (AV_RL32(p->buf) != MKTAG('V', 'I', 'D', 0)) diff --git a/libavformat/bfi.c b/libavformat/bfi.c index 6c98e33ab..29e2cf8cf 100644 --- a/libavformat/bfi.c +++ b/libavformat/bfi.c @@ -39,7 +39,7 @@ typedef struct BFIContext { int avflag; } BFIContext; -static int bfi_probe(AVProbeData * p) +static int bfi_probe(const AVProbeData * p) { /* Check file header */ if (AV_RL32(p->buf) == MKTAG('B', 'F', '&', 'I')) @@ -54,7 +54,7 @@ static int bfi_read_header(AVFormatContext * s) AVIOContext *pb = s->pb; AVStream *vstream; AVStream *astream; - int fps, chunk_header; + int ret, fps, chunk_header; /* Initialize the video codec... */ vstream = avformat_new_stream(s, NULL); @@ -80,12 +80,9 @@ static int bfi_read_header(AVFormatContext * s) /*Load the palette to extradata */ avio_skip(pb, 8); - vstream->codecpar->extradata = av_malloc(768); - if (!vstream->codecpar->extradata) - return AVERROR(ENOMEM); - vstream->codecpar->extradata_size = 768; - avio_read(pb, vstream->codecpar->extradata, - vstream->codecpar->extradata_size); + ret = ff_get_extradata(s, vstream->codecpar, pb, 768); + if (ret < 0) + return ret; astream->codecpar->sample_rate = avio_rl32(pb); if (astream->codecpar->sample_rate <= 0) { diff --git a/libavformat/bink.c b/libavformat/bink.c index 8a05082fc..631b8c4d7 100644 --- a/libavformat/bink.c +++ b/libavformat/bink.c @@ -59,7 +59,7 @@ typedef struct BinkDemuxContext { int smush_size; } BinkDemuxContext; -static int probe(AVProbeData *p) +static int probe(const AVProbeData *p) { const uint8_t *b = p->buf; int smush = AV_RN32(p->buf) == AV_RN32("SMUS"); @@ -92,6 +92,8 @@ static int read_header(AVFormatContext *s) uint16_t flags; int keyframe; int ret; + uint32_t signature; + uint8_t revision; vst = avformat_new_stream(s, NULL); if (!vst) @@ -160,14 +162,14 @@ static int read_header(AVFormatContext *s) return AVERROR(EIO); } + signature = (vst->codecpar->codec_tag & 0xFFFFFF); + revision = ((vst->codecpar->codec_tag >> 24) % 0xFF); + + if ((signature == AV_RL32("BIK") && (revision == 'k')) || + (signature == AV_RL32("KB2") && (revision == 'i' || revision == 'j' || revision == 'k'))) + avio_skip(pb, 4); /* unknown new field */ + if (bink->num_audio_tracks) { - uint32_t signature = (vst->codecpar->codec_tag & 0xFFFFFF); - uint8_t revision = ((vst->codecpar->codec_tag >> 24) % 0xFF); - - if ((signature == AV_RL32("BIK") && (revision == 0x6b)) || /* k */ - (signature == AV_RL32("KB2") && (revision == 0x69 || revision == 0x6a || revision == 0x6b))) /* i,j,k */ - avio_skip(pb, 4); /* unknown new field */ - avio_skip(pb, 4 * bink->num_audio_tracks); /* max decoded size */ for (i = 0; i < bink->num_audio_tracks; i++) { diff --git a/libavformat/bintext.c b/libavformat/bintext.c index 0b499d955..d4921749a 100644 --- a/libavformat/bintext.c +++ b/libavformat/bintext.c @@ -126,7 +126,7 @@ static void predict_width(AVCodecParameters *par, uint64_t fsize, int got_width) par->width = fsize > 4000 ? (160<<3) : (80<<3); } -static int bin_probe(AVProbeData *p) +static int bin_probe(const AVProbeData *p) { const uint8_t *d = p->buf; int magic = 0, sauce = 0; @@ -204,7 +204,7 @@ static int bintext_read_header(AVFormatContext *s) #endif /* CONFIG_BINTEXT_DEMUXER */ #if CONFIG_XBIN_DEMUXER -static int xbin_probe(AVProbeData *p) +static int xbin_probe(const AVProbeData *p) { const uint8_t *d = p->buf; @@ -302,7 +302,7 @@ static const uint8_t idf_magic[] = { 0x04, 0x31, 0x2e, 0x34, 0x00, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x15, 0x00 }; -static int idf_probe(AVProbeData *p) +static int idf_probe(const AVProbeData *p) { if (p->buf_size < sizeof(idf_magic)) return 0; diff --git a/libavformat/bit.c b/libavformat/bit.c index 76aae2d4a..0aacfc7c3 100644 --- a/libavformat/bit.c +++ b/libavformat/bit.c @@ -30,7 +30,7 @@ #define BIT_1 0x81 #if CONFIG_BIT_DEMUXER -static int probe(AVProbeData *p) +static int probe(const AVProbeData *p) { int i = 0, j, valid = 0; diff --git a/libavformat/boadec.c b/libavformat/boadec.c index 730e9573d..495090c48 100644 --- a/libavformat/boadec.c +++ b/libavformat/boadec.c @@ -24,7 +24,7 @@ #include "avformat.h" #include "internal.h" -static int probe(AVProbeData *p) +static int probe(const AVProbeData *p) { if (p->buf_size < 2096) return 0; diff --git a/libavformat/brstm.c b/libavformat/brstm.c index 87690e3f7..e8a1eaa02 100644 --- a/libavformat/brstm.c +++ b/libavformat/brstm.c @@ -38,7 +38,7 @@ typedef struct BRSTMDemuxContext { int little_endian; } BRSTMDemuxContext; -static int probe(AVProbeData *p) +static int probe(const AVProbeData *p) { if (AV_RL32(p->buf) == MKTAG('R','S','T','M') && (AV_RL16(p->buf + 4) == 0xFFFE || @@ -47,7 +47,7 @@ static int probe(AVProbeData *p) return 0; } -static int probe_bfstm(AVProbeData *p) +static int probe_bfstm(const AVProbeData *p) { if ((AV_RL32(p->buf) == MKTAG('F','S','T','M') || AV_RL32(p->buf) == MKTAG('C','S','T','M')) && diff --git a/libavformat/c93.c b/libavformat/c93.c index b1a245a3c..8aa80b5e0 100644 --- a/libavformat/c93.c +++ b/libavformat/c93.c @@ -43,7 +43,7 @@ typedef struct C93DemuxContext { AVStream *audio; } C93DemuxContext; -static int probe(AVProbeData *p) +static int probe(const AVProbeData *p) { int i; int index = 1; diff --git a/libavformat/cache.c b/libavformat/cache.c index 66bbbf54c..3425be935 100644 --- a/libavformat/cache.c +++ b/libavformat/cache.c @@ -54,6 +54,7 @@ typedef struct CacheEntry { typedef struct Context { AVClass *class; int fd; + char *filename; struct AVTreeNode *root; int64_t logical_pos; int64_t cache_pos; @@ -72,6 +73,7 @@ static int cmp(const void *key, const void *node) static int cache_open(URLContext *h, const char *arg, int flags, AVDictionary **options) { + int ret; char *buffername; Context *c= h->priv_data; @@ -83,8 +85,12 @@ static int cache_open(URLContext *h, const char *arg, int flags, AVDictionary ** return c->fd; } - unlink(buffername); - av_freep(&buffername); + ret = unlink(buffername); + + if (ret >= 0) + av_freep(&buffername); + else + c->filename = buffername; return ffurl_open_whitelist(&c->inner, arg, flags, &h->interrupt_callback, options, h->protocol_whitelist, h->protocol_blacklist, h); @@ -292,11 +298,18 @@ static int enu_free(void *opaque, void *elem) static int cache_close(URLContext *h) { Context *c= h->priv_data; + int ret; av_log(h, AV_LOG_INFO, "Statistics, cache hits:%"PRId64" cache misses:%"PRId64"\n", c->cache_hit, c->cache_miss); close(c->fd); + if (c->filename) { + ret = unlink(c->filename); + if (ret < 0) + av_log(h, AV_LOG_ERROR, "Could not delete %s.\n", c->filename); + av_freep(&c->filename); + } ffurl_close(c->inner); av_tree_enumerate(c->root, NULL, NULL, enu_free); av_tree_destroy(c->root); diff --git a/libavformat/cafdec.c b/libavformat/cafdec.c index 7652d9e23..86228595c 100644 --- a/libavformat/cafdec.c +++ b/libavformat/cafdec.c @@ -48,7 +48,7 @@ typedef struct CafContext { int64_t data_size; ///< raw data size, in bytes } CafContext; -static int probe(AVProbeData *p) +static int probe(const AVProbeData *p) { if (AV_RB32(p->buf) == MKBETAG('c','a','f','f') && AV_RB16(&p->buf[4]) == 1) return AVPROBE_SCORE_MAX; @@ -310,6 +310,8 @@ static int read_header(AVFormatContext *s) "skipping CAF chunk: %08"PRIX32" (%s), size %"PRId64"\n", tag, av_fourcc2str(av_bswap32(tag)), size); case MKBETAG('f','r','e','e'): + if (size < 0 && found_data) + goto found_data; if (size < 0) return AVERROR_INVALIDDATA; break; @@ -325,6 +327,7 @@ static int read_header(AVFormatContext *s) if (!found_data) return AVERROR_INVALIDDATA; +found_data: if (caf->bytes_per_packet > 0 && caf->frames_per_packet > 0) { if (caf->data_size > 0) st->nb_frames = (caf->data_size / caf->bytes_per_packet) * caf->frames_per_packet; diff --git a/libavformat/cavsvideodec.c b/libavformat/cavsvideodec.c index b4da58e34..8900b9759 100644 --- a/libavformat/cavsvideodec.c +++ b/libavformat/cavsvideodec.c @@ -30,7 +30,7 @@ #define CAVS_VIDEO_EDIT_CODE 0x000001b7 #define CAVS_PROFILE_JIZHUN 0x20 -static int cavsvideo_probe(AVProbeData *p) +static int cavsvideo_probe(const AVProbeData *p) { uint32_t code= -1; int pic=0, seq=0, slice_pos = 0; diff --git a/libavformat/cdxl.c b/libavformat/cdxl.c index 94a063c81..9aacaddb4 100644 --- a/libavformat/cdxl.c +++ b/libavformat/cdxl.c @@ -40,7 +40,7 @@ typedef struct CDXLDemuxContext { int64_t filesize; } CDXLDemuxContext; -static int cdxl_read_probe(AVProbeData *p) +static int cdxl_read_probe(const AVProbeData *p) { int score = AVPROBE_SCORE_EXTENSION + 10; diff --git a/libavformat/cinedec.c b/libavformat/cinedec.c index de34fb963..d27ebbba7 100644 --- a/libavformat/cinedec.c +++ b/libavformat/cinedec.c @@ -56,7 +56,7 @@ enum { #define CFA_BLGRAY 0x20000000U #define CFA_BRGRAY 0x10000000U -static int cine_read_probe(AVProbeData *p) +static int cine_read_probe(const AVProbeData *p) { int HeaderSize; if (p->buf[0] == 'C' && p->buf[1] == 'I' && // Type diff --git a/libavformat/codec2.c b/libavformat/codec2.c index 28dbbd817..0d7c48858 100644 --- a/libavformat/codec2.c +++ b/libavformat/codec2.c @@ -43,7 +43,7 @@ typedef struct { int frames_per_packet; } Codec2Context; -static int codec2_probe(AVProbeData *p) +static int codec2_probe(const AVProbeData *p) { //must start wih C0 DE C2 if (AV_RB24(p->buf) != AVPRIV_CODEC2_MAGIC) { diff --git a/libavformat/concatdec.c b/libavformat/concatdec.c index bbe13136f..b80294efb 100644 --- a/libavformat/concatdec.c +++ b/libavformat/concatdec.c @@ -45,6 +45,7 @@ typedef struct { int64_t file_start_time; int64_t file_inpoint; int64_t duration; + int64_t user_duration; int64_t next_dts; ConcatStream *streams; int64_t inpoint; @@ -67,7 +68,7 @@ typedef struct { int segment_time_metadata; } ConcatContext; -static int concat_probe(AVProbeData *probe) +static int concat_probe(const AVProbeData *probe) { return memcmp(probe->buf, "ffconcat version 1.0", 20) ? 0 : AVPROBE_SCORE_MAX; @@ -154,6 +155,7 @@ static int add_file(AVFormatContext *avf, char *filename, ConcatFile **rfile, file->next_dts = AV_NOPTS_VALUE; file->inpoint = AV_NOPTS_VALUE; file->outpoint = AV_NOPTS_VALUE; + file->user_duration = AV_NOPTS_VALUE; return 0; @@ -314,6 +316,19 @@ static int match_streams(AVFormatContext *avf) return 0; } +static int64_t get_best_effort_duration(ConcatFile *file, AVFormatContext *avf) +{ + if (file->user_duration != AV_NOPTS_VALUE) + return file->user_duration; + if (file->outpoint != AV_NOPTS_VALUE) + return file->outpoint - file->file_inpoint; + if (avf->duration > 0) + return avf->duration - (file->file_inpoint - file->file_start_time); + if (file->next_dts != AV_NOPTS_VALUE) + return file->next_dts - file->file_inpoint; + return AV_NOPTS_VALUE; +} + static int open_file(AVFormatContext *avf, unsigned fileno) { ConcatContext *cat = avf->priv_data; @@ -340,14 +355,12 @@ static int open_file(AVFormatContext *avf, unsigned fileno) return ret; } cat->cur_file = file; - if (file->start_time == AV_NOPTS_VALUE) - file->start_time = !fileno ? 0 : - cat->files[fileno - 1].start_time + - cat->files[fileno - 1].duration; + file->start_time = !fileno ? 0 : + cat->files[fileno - 1].start_time + + cat->files[fileno - 1].duration; file->file_start_time = (cat->avf->start_time == AV_NOPTS_VALUE) ? 0 : cat->avf->start_time; file->file_inpoint = (file->inpoint == AV_NOPTS_VALUE) ? file->file_start_time : file->inpoint; - if (file->duration == AV_NOPTS_VALUE && file->outpoint != AV_NOPTS_VALUE) - file->duration = file->outpoint - file->file_inpoint; + file->duration = get_best_effort_duration(file, cat->avf); if (cat->segment_time_metadata) { av_dict_set_int(&file->metadata, "lavf.concatdec.start_time", file->start_time, 0); @@ -425,7 +438,7 @@ static int concat_read_header(AVFormatContext *avf) goto fail; } if (!strcmp(keyword, "duration")) - file->duration = dur; + file->user_duration = dur; else if (!strcmp(keyword, "inpoint")) file->inpoint = dur; else if (!strcmp(keyword, "outpoint")) @@ -484,12 +497,13 @@ static int concat_read_header(AVFormatContext *avf) cat->files[i].start_time = time; else time = cat->files[i].start_time; - if (cat->files[i].duration == AV_NOPTS_VALUE) { + if (cat->files[i].user_duration == AV_NOPTS_VALUE) { if (cat->files[i].inpoint == AV_NOPTS_VALUE || cat->files[i].outpoint == AV_NOPTS_VALUE) break; - cat->files[i].duration = cat->files[i].outpoint - cat->files[i].inpoint; + cat->files[i].user_duration = cat->files[i].outpoint - cat->files[i].inpoint; } - time += cat->files[i].duration; + cat->files[i].duration = cat->files[i].user_duration; + time += cat->files[i].user_duration; } if (i == cat->nb_files) { avf->duration = time; @@ -514,14 +528,7 @@ static int open_next_file(AVFormatContext *avf) ConcatContext *cat = avf->priv_data; unsigned fileno = cat->cur_file - cat->files; - if (cat->cur_file->duration == AV_NOPTS_VALUE) { - if (cat->avf->duration > 0 || cat->cur_file->next_dts == AV_NOPTS_VALUE) { - cat->cur_file->duration = cat->avf->duration; - } else { - cat->cur_file->duration = cat->cur_file->next_dts; - } - cat->cur_file->duration -= (cat->cur_file->file_inpoint - cat->cur_file->file_start_time); - } + cat->cur_file->duration = get_best_effort_duration(cat->cur_file, cat->avf); if (++fileno >= cat->nb_files) { cat->eof = 1; @@ -692,6 +699,13 @@ static int real_seek(AVFormatContext *avf, int stream, left = 0; right = cat->nb_files; + + /* Always support seek to start */ + if (ts <= 0) + right = 1; + else if (!cat->seekable) + return AVERROR(ESPIPE); /* XXX: can we use it? */ + while (right - left > 1) { int mid = (left + right) / 2; if (ts < cat->files[mid].start_time) @@ -728,8 +742,6 @@ static int concat_seek(AVFormatContext *avf, int stream, AVFormatContext *cur_avf_saved = cat->avf; int ret; - if (!cat->seekable) - return AVERROR(ESPIPE); /* XXX: can we use it? */ if (flags & (AVSEEK_FLAG_BYTE | AVSEEK_FLAG_FRAME)) return AVERROR(ENOSYS); cat->avf = NULL; diff --git a/libavformat/dashdec.c b/libavformat/dashdec.c index a51154699..f82a750d6 100644 --- a/libavformat/dashdec.c +++ b/libavformat/dashdec.c @@ -122,16 +122,32 @@ struct representation { typedef struct DASHContext { const AVClass *class; char *base_url; + char *adaptionset_contenttype_val; + char *adaptionset_par_val; + char *adaptionset_lang_val; + char *adaptionset_minbw_val; + char *adaptionset_maxbw_val; + char *adaptionset_minwidth_val; + char *adaptionset_maxwidth_val; + char *adaptionset_minheight_val; + char *adaptionset_maxheight_val; + char *adaptionset_minframerate_val; + char *adaptionset_maxframerate_val; + char *adaptionset_segmentalignment_val; + char *adaptionset_bitstreamswitching_val; int n_videos; struct representation **videos; int n_audios; struct representation **audios; + int n_subtitles; + struct representation **subtitles; /* MediaPresentationDescription Attribute */ uint64_t media_presentation_duration; uint64_t suggested_presentation_delay; uint64_t availability_start_time; + uint64_t availability_end_time; uint64_t publish_time; uint64_t minimum_update_period; uint64_t time_shift_buffer_depth; @@ -143,12 +159,14 @@ typedef struct DASHContext { int is_live; AVIOInterruptCB *interrupt_callback; - char *user_agent; ///< holds HTTP user agent set as an AVOption to the HTTP protocol context - char *cookies; ///< holds HTTP cookie values set in either the initial response or as an AVOption to the HTTP protocol context - char *headers; ///< holds HTTP headers set as an AVOption to the HTTP protocol context char *allowed_extensions; AVDictionary *avio_opts; int max_url_size; + + /* Flags for init section*/ + int is_init_section_common_video; + int is_init_section_common_audio; + } DASHContext; static int ishttp(char *url) @@ -257,6 +275,12 @@ static int64_t get_segment_start_time_based_on_timeline(struct representation *p goto finish; start_time += pls->timelines[i]->duration; + + if (pls->timelines[i]->repeat == -1) { + start_time = pls->timelines[i]->duration * cur_seq_no; + goto finish; + } + for (j = 0; j < pls->timelines[i]->repeat; j++) { num++; if (num == cur_seq_no) @@ -372,22 +396,15 @@ static void free_audio_list(DASHContext *c) c->n_audios = 0; } -static void set_httpheader_options(DASHContext *c, AVDictionary **opts) +static void free_subtitle_list(DASHContext *c) { - // broker prior HTTP options that should be consistent across requests - av_dict_set(opts, "user-agent", c->user_agent, 0); - av_dict_set(opts, "cookies", c->cookies, 0); - av_dict_set(opts, "headers", c->headers, 0); - if (c->is_live) { - av_dict_set(opts, "seekable", "0", 0); + int i; + for (i = 0; i < c->n_subtitles; i++) { + struct representation *pls = c->subtitles[i]; + free_representation(pls); } -} -static void update_options(char **dest, const char *name, void *src) -{ - av_freep(dest); - av_opt_get(src, name, AV_OPT_SEARCH_CHILDREN, (uint8_t**)dest); - if (*dest) - av_freep(dest); + av_freep(&c->subtitles); + c->n_subtitles = 0; } static int open_url(AVFormatContext *s, AVIOContext **pb, const char *url, @@ -416,9 +433,9 @@ static int open_url(AVFormatContext *s, AVIOContext **pb, const char *url, if (av_strstart(proto_name, "file", NULL)) { if (strcmp(c->allowed_extensions, "ALL") && !av_match_ext(url, c->allowed_extensions)) { av_log(s, AV_LOG_ERROR, - "Filename extension of \'%s\' is not a common multimedia extension, blocked for security reasons.\n" - "If you wish to override this adjust allowed_extensions, you can set it to \'ALL\' to allow all\n", - url); + "Filename extension of \'%s\' is not a common multimedia extension, blocked for security reasons.\n" + "If you wish to override this adjust allowed_extensions, you can set it to \'ALL\' to allow all\n", + url); return AVERROR_INVALIDDATA; } } else if (av_strstart(proto_name, "http", NULL)) { @@ -443,11 +460,9 @@ static int open_url(AVFormatContext *s, AVIOContext **pb, const char *url, av_opt_get(*pb, "cookies", AV_OPT_SEARCH_CHILDREN, (uint8_t**)&new_cookies); if (new_cookies) { - av_free(c->cookies); - c->cookies = new_cookies; + av_dict_set(&opts, "cookies", new_cookies, AV_DICT_DONT_STRDUP_VAL); } - av_dict_set(&opts, "cookies", c->cookies, 0); } av_dict_free(&tmp); @@ -491,7 +506,7 @@ static char *get_content_url(xmlNodePtr *baseurl_nodes, } if (val) - av_strlcat(tmp_str, (const char*)val, max_url_size); + ff_make_absolute_url(tmp_str, max_url_size, tmp_str, val); if (rep_id_val) { url = av_strireplace(tmp_str, "$RepresentationID$", (const char*)rep_id_val); @@ -563,6 +578,8 @@ static enum AVMediaType get_content_type(xmlNodePtr node) type = AVMEDIA_TYPE_VIDEO; } else if (av_stristr((const char *)val, "audio")) { type = AVMEDIA_TYPE_AUDIO; + } else if (av_stristr((const char *)val, "text")) { + type = AVMEDIA_TYPE_SUBTITLE; } xmlFree(val); } @@ -692,8 +709,8 @@ static int parse_manifest_segmenttimeline(AVFormatContext *s, struct representat return 0; } -static int resolve_content_path(AVFormatContext *s, const char *url, int *max_url_size, xmlNodePtr *baseurl_nodes, int n_baseurl_nodes) { - +static int resolve_content_path(AVFormatContext *s, const char *url, int *max_url_size, xmlNodePtr *baseurl_nodes, int n_baseurl_nodes) +{ char *tmp_str = NULL; char *path = NULL; char *mpdName = NULL; @@ -701,7 +718,7 @@ static int resolve_content_path(AVFormatContext *s, const char *url, int *max_ur char *baseurl = NULL; char *root_url = NULL; char *text = NULL; - + char *tmp = NULL; int isRootHttp = 0; char token ='/'; int start = 0; @@ -730,9 +747,11 @@ static int resolve_content_path(AVFormatContext *s, const char *url, int *max_ur goto end; } av_strlcpy(text, url, strlen(url)+1); - while (mpdName = av_strtok(text, "/", &text)) { + tmp = text; + while (mpdName = av_strtok(tmp, "/", &tmp)) { size = strlen(mpdName); } + av_free(text); path = av_mallocz(tmp_max_url_size); tmp_str = av_mallocz(tmp_max_url_size); @@ -746,9 +765,12 @@ static int resolve_content_path(AVFormatContext *s, const char *url, int *max_ur if (!(node = baseurl_nodes[rootId])) { continue; } - if (ishttp(xmlNodeGetContent(node))) { + text = xmlNodeGetContent(node); + if (ishttp(text)) { + xmlFree(text); break; } + xmlFree(text); } node = baseurl_nodes[rootId]; @@ -791,6 +813,7 @@ end: } av_free(path); av_free(tmp_str); + xmlFree(baseurl); return updated; } @@ -809,6 +832,7 @@ static int parse_manifest_representation(AVFormatContext *s, const char *url, xmlNodePtr adaptionset_supplementalproperty_node) { int32_t ret = 0; + int32_t subtitle_rep_idx = 0; int32_t audio_rep_idx = 0; int32_t video_rep_idx = 0; DASHContext *c = s->priv_data; @@ -817,7 +841,7 @@ static int parse_manifest_representation(AVFormatContext *s, const char *url, xmlNodePtr representation_segmenttemplate_node = NULL; xmlNodePtr representation_baseurl_node = NULL; xmlNodePtr representation_segmentlist_node = NULL; - xmlNodePtr segmentlists_tab[2]; + xmlNodePtr segmentlists_tab[3]; xmlNodePtr fragment_timeline_node = NULL; xmlNodePtr fragment_templates_tab[5]; char *duration_val = NULL; @@ -845,7 +869,7 @@ static int parse_manifest_representation(AVFormatContext *s, const char *url, type = get_content_type(adaptionset_node); if (type == AVMEDIA_TYPE_UNKNOWN) { av_log(s, AV_LOG_VERBOSE, "Parsing '%s' - skipp not supported representation type\n", url); - } else if (type == AVMEDIA_TYPE_VIDEO || type == AVMEDIA_TYPE_AUDIO) { + } else if (type == AVMEDIA_TYPE_VIDEO || type == AVMEDIA_TYPE_AUDIO || type == AVMEDIA_TYPE_SUBTITLE) { // convert selected representation to our internal struct rep = av_mallocz(sizeof(struct representation)); if (!rep) { @@ -910,18 +934,22 @@ static int parse_manifest_representation(AVFormatContext *s, const char *url, if (presentation_timeoffset_val) { rep->presentation_timeoffset = (int64_t) strtoll(presentation_timeoffset_val, NULL, 10); + av_log(s, AV_LOG_TRACE, "rep->presentation_timeoffset = [%"PRId64"]\n", rep->presentation_timeoffset); xmlFree(presentation_timeoffset_val); } if (duration_val) { rep->fragment_duration = (int64_t) strtoll(duration_val, NULL, 10); + av_log(s, AV_LOG_TRACE, "rep->fragment_duration = [%"PRId64"]\n", rep->fragment_duration); xmlFree(duration_val); } if (timescale_val) { rep->fragment_timescale = (int64_t) strtoll(timescale_val, NULL, 10); + av_log(s, AV_LOG_TRACE, "rep->fragment_timescale = [%"PRId64"]\n", rep->fragment_timescale); xmlFree(timescale_val); } if (startnumber_val) { rep->first_seq_no = (int64_t) strtoll(startnumber_val, NULL, 10); + av_log(s, AV_LOG_TRACE, "rep->first_seq_no = [%"PRId64"]\n", rep->first_seq_no); xmlFree(startnumber_val); } if (adaptionset_supplementalproperty_node) { @@ -933,7 +961,7 @@ static int parse_manifest_representation(AVFormatContext *s, const char *url, rep->last_seq_no =(int64_t) strtoll(val, NULL, 10) - 1; xmlFree(val); } - } + } } fragment_timeline_node = find_child_node_by_name(representation_segmenttemplate_node, "SegmentTimeline"); @@ -974,15 +1002,18 @@ static int parse_manifest_representation(AVFormatContext *s, const char *url, xmlNodePtr fragmenturl_node = NULL; segmentlists_tab[0] = representation_segmentlist_node; segmentlists_tab[1] = adaptionset_segmentlist_node; + segmentlists_tab[2] = period_segmentlist_node; - duration_val = get_val_from_nodes_tab(segmentlists_tab, 2, "duration"); - timescale_val = get_val_from_nodes_tab(segmentlists_tab, 2, "timescale"); + duration_val = get_val_from_nodes_tab(segmentlists_tab, 3, "duration"); + timescale_val = get_val_from_nodes_tab(segmentlists_tab, 3, "timescale"); if (duration_val) { rep->fragment_duration = (int64_t) strtoll(duration_val, NULL, 10); + av_log(s, AV_LOG_TRACE, "rep->fragment_duration = [%"PRId64"]\n", rep->fragment_duration); xmlFree(duration_val); } if (timescale_val) { rep->fragment_timescale = (int64_t) strtoll(timescale_val, NULL, 10); + av_log(s, AV_LOG_TRACE, "rep->fragment_timescale = [%"PRId64"]\n", rep->fragment_timescale); xmlFree(timescale_val); } fragmenturl_node = xmlFirstElementChild(representation_segmentlist_node); @@ -1033,18 +1064,29 @@ static int parse_manifest_representation(AVFormatContext *s, const char *url, av_log(s, AV_LOG_VERBOSE, "Ignoring invalid frame rate '%s'\n", rep_framerate_val); } - if (type == AVMEDIA_TYPE_VIDEO) { - rep->rep_idx = video_rep_idx; - dynarray_add(&c->videos, &c->n_videos, rep); - } else { - rep->rep_idx = audio_rep_idx; - dynarray_add(&c->audios, &c->n_audios, rep); + switch (type) { + case AVMEDIA_TYPE_VIDEO: + rep->rep_idx = video_rep_idx; + dynarray_add(&c->videos, &c->n_videos, rep); + break; + case AVMEDIA_TYPE_AUDIO: + rep->rep_idx = audio_rep_idx; + dynarray_add(&c->audios, &c->n_audios, rep); + break; + case AVMEDIA_TYPE_SUBTITLE: + rep->rep_idx = subtitle_rep_idx; + dynarray_add(&c->subtitles, &c->n_subtitles, rep); + break; + default: + av_log(s, AV_LOG_WARNING, "Unsupported the stream type %d\n", type); + break; } } } video_rep_idx += type == AVMEDIA_TYPE_VIDEO; audio_rep_idx += type == AVMEDIA_TYPE_AUDIO; + subtitle_rep_idx += type == AVMEDIA_TYPE_SUBTITLE; end: if (rep_id_val) @@ -1065,12 +1107,26 @@ static int parse_manifest_adaptationset(AVFormatContext *s, const char *url, xmlNodePtr period_segmentlist_node) { int ret = 0; + DASHContext *c = s->priv_data; xmlNodePtr fragment_template_node = NULL; xmlNodePtr content_component_node = NULL; xmlNodePtr adaptionset_baseurl_node = NULL; xmlNodePtr adaptionset_segmentlist_node = NULL; xmlNodePtr adaptionset_supplementalproperty_node = NULL; xmlNodePtr node = NULL; + c->adaptionset_contenttype_val = xmlGetProp(adaptionset_node, "contentType"); + c->adaptionset_par_val = xmlGetProp(adaptionset_node, "par"); + c->adaptionset_lang_val = xmlGetProp(adaptionset_node, "lang"); + c->adaptionset_minbw_val = xmlGetProp(adaptionset_node, "minBandwidth"); + c->adaptionset_maxbw_val = xmlGetProp(adaptionset_node, "maxBandwidth"); + c->adaptionset_minwidth_val = xmlGetProp(adaptionset_node, "minWidth"); + c->adaptionset_maxwidth_val = xmlGetProp(adaptionset_node, "maxWidth"); + c->adaptionset_minheight_val = xmlGetProp(adaptionset_node, "minHeight"); + c->adaptionset_maxheight_val = xmlGetProp(adaptionset_node, "maxHeight"); + c->adaptionset_minframerate_val = xmlGetProp(adaptionset_node, "minFrameRate"); + c->adaptionset_maxframerate_val = xmlGetProp(adaptionset_node, "maxFrameRate"); + c->adaptionset_segmentalignment_val = xmlGetProp(adaptionset_node, "segmentAlignment"); + c->adaptionset_bitstreamswitching_val = xmlGetProp(adaptionset_node, "bitstreamSwitching"); node = xmlFirstElementChild(adaptionset_node); while (node) { @@ -1105,6 +1161,34 @@ static int parse_manifest_adaptationset(AVFormatContext *s, const char *url, return 0; } +static int parse_programinformation(AVFormatContext *s, xmlNodePtr node) +{ + xmlChar *val = NULL; + + node = xmlFirstElementChild(node); + while (node) { + if (!av_strcasecmp(node->name, "Title")) { + val = xmlNodeGetContent(node); + if (val) { + av_dict_set(&s->metadata, "Title", val, 0); + } + } else if (!av_strcasecmp(node->name, "Source")) { + val = xmlNodeGetContent(node); + if (val) { + av_dict_set(&s->metadata, "Source", val, 0); + } + } else if (!av_strcasecmp(node->name, "Copyright")) { + val = xmlNodeGetContent(node); + if (val) { + av_dict_set(&s->metadata, "Copyright", val, 0); + } + } + node = xmlNextElementSibling(node); + xmlFree(val); + } + return 0; +} + static int parse_manifest(AVFormatContext *s, const char *url, AVIOContext *in) { DASHContext *c = s->priv_data; @@ -1118,6 +1202,7 @@ static int parse_manifest(AVFormatContext *s, const char *url, AVIOContext *in) xmlNodePtr root_element = NULL; xmlNodePtr node = NULL; xmlNodePtr period_node = NULL; + xmlNodePtr tmp_node = NULL; xmlNodePtr mpd_baseurl_node = NULL; xmlNodePtr period_baseurl_node = NULL; xmlNodePtr period_segmenttemplate_node = NULL; @@ -1131,7 +1216,7 @@ static int parse_manifest(AVFormatContext *s, const char *url, AVIOContext *in) if (!in) { close_in = 1; - set_httpheader_options(c, &opts); + av_dict_copy(&opts, c->avio_opts, 0); ret = avio_open2(&in, url, AVIO_FLAG_READ, c->interrupt_callback, &opts); av_dict_free(&opts); if (ret < 0) @@ -1162,7 +1247,7 @@ static int parse_manifest(AVFormatContext *s, const char *url, AVIOContext *in) } else { LIBXML_TEST_VERSION - doc = xmlReadMemory(buffer, filesize, c->base_url, NULL, 0); + doc = xmlReadMemory(buffer, filesize, c->base_url, NULL, 0); root_element = xmlDocGetRootElement(doc); node = root_element; @@ -1195,25 +1280,37 @@ static int parse_manifest(AVFormatContext *s, const char *url, AVIOContext *in) if (!av_strcasecmp(attr->name, (const char *)"availabilityStartTime")) { c->availability_start_time = get_utc_date_time_insec(s, (const char *)val); + av_log(s, AV_LOG_TRACE, "c->availability_start_time = [%"PRId64"]\n", c->availability_start_time); + } else if (!av_strcasecmp(attr->name, (const char *)"availabilityEndTime")) { + c->availability_end_time = get_utc_date_time_insec(s, (const char *)val); + av_log(s, AV_LOG_TRACE, "c->availability_end_time = [%"PRId64"]\n", c->availability_end_time); } else if (!av_strcasecmp(attr->name, (const char *)"publishTime")) { c->publish_time = get_utc_date_time_insec(s, (const char *)val); + av_log(s, AV_LOG_TRACE, "c->publish_time = [%"PRId64"]\n", c->publish_time); } else if (!av_strcasecmp(attr->name, (const char *)"minimumUpdatePeriod")) { c->minimum_update_period = get_duration_insec(s, (const char *)val); + av_log(s, AV_LOG_TRACE, "c->minimum_update_period = [%"PRId64"]\n", c->minimum_update_period); } else if (!av_strcasecmp(attr->name, (const char *)"timeShiftBufferDepth")) { c->time_shift_buffer_depth = get_duration_insec(s, (const char *)val); + av_log(s, AV_LOG_TRACE, "c->time_shift_buffer_depth = [%"PRId64"]\n", c->time_shift_buffer_depth); } else if (!av_strcasecmp(attr->name, (const char *)"minBufferTime")) { c->min_buffer_time = get_duration_insec(s, (const char *)val); + av_log(s, AV_LOG_TRACE, "c->min_buffer_time = [%"PRId64"]\n", c->min_buffer_time); } else if (!av_strcasecmp(attr->name, (const char *)"suggestedPresentationDelay")) { c->suggested_presentation_delay = get_duration_insec(s, (const char *)val); + av_log(s, AV_LOG_TRACE, "c->suggested_presentation_delay = [%"PRId64"]\n", c->suggested_presentation_delay); } else if (!av_strcasecmp(attr->name, (const char *)"mediaPresentationDuration")) { c->media_presentation_duration = get_duration_insec(s, (const char *)val); + av_log(s, AV_LOG_TRACE, "c->media_presentation_duration = [%"PRId64"]\n", c->media_presentation_duration); } attr = attr->next; xmlFree(val); } - mpd_baseurl_node = find_child_node_by_name(node, "BaseURL"); - if (!mpd_baseurl_node) { + tmp_node = find_child_node_by_name(node, "BaseURL"); + if (tmp_node) { + mpd_baseurl_node = xmlCopyNode(tmp_node,1); + } else { mpd_baseurl_node = xmlNewNode(NULL, "BaseURL"); } @@ -1241,6 +1338,8 @@ static int parse_manifest(AVFormatContext *s, const char *url, AVIOContext *in) if (c->period_start > 0) c->media_presentation_duration = c->period_duration; } + } else if (!av_strcasecmp(node->name, "ProgramInformation")) { + parse_programinformation(s, node); } node = xmlNextElementSibling(node); } @@ -1267,6 +1366,7 @@ cleanup: /*free the document */ xmlFreeDoc(doc); xmlCleanupParser(); + xmlFreeNode(mpd_baseurl_node); } av_free(new_url); @@ -1285,8 +1385,10 @@ static int64_t calc_cur_seg_no(AVFormatContext *s, struct representation *pls) if (c->is_live) { if (pls->n_fragments) { + av_log(s, AV_LOG_TRACE, "in n_fragments mode\n"); num = pls->first_seq_no; } else if (pls->n_timelines) { + av_log(s, AV_LOG_TRACE, "in n_timelines mode\n"); start_time_offset = get_segment_start_time_based_on_timeline(pls, 0xFFFFFFFF) - 60 * pls->fragment_timescale; // 60 seconds before end num = calc_next_seg_no_from_timelines(pls, start_time_offset); if (num == -1) @@ -1294,10 +1396,15 @@ static int64_t calc_cur_seg_no(AVFormatContext *s, struct representation *pls) else num += pls->first_seq_no; } else if (pls->fragment_duration){ + av_log(s, AV_LOG_TRACE, "in fragment_duration mode fragment_timescale = %"PRId64", presentation_timeoffset = %"PRId64"\n", pls->fragment_timescale, pls->presentation_timeoffset); if (pls->presentation_timeoffset) { - num = pls->presentation_timeoffset * pls->fragment_timescale / pls->fragment_duration; + num = pls->first_seq_no + (((get_current_time_in_sec() - c->availability_start_time) * pls->fragment_timescale)-pls->presentation_timeoffset) / pls->fragment_duration - c->min_buffer_time; } else if (c->publish_time > 0 && !c->availability_start_time) { - num = pls->first_seq_no + (((c->publish_time - c->availability_start_time) - c->suggested_presentation_delay) * pls->fragment_timescale) / pls->fragment_duration; + if (c->min_buffer_time) { + num = pls->first_seq_no + (((c->publish_time + pls->fragment_duration) - c->suggested_presentation_delay) * pls->fragment_timescale) / pls->fragment_duration - c->min_buffer_time; + } else { + num = pls->first_seq_no + (((c->publish_time - c->time_shift_buffer_depth + pls->fragment_duration) - c->suggested_presentation_delay) * pls->fragment_timescale) / pls->fragment_duration; + } } else { num = pls->first_seq_no + (((get_current_time_in_sec() - c->availability_start_time) - c->suggested_presentation_delay) * pls->fragment_timescale) / pls->fragment_duration; } @@ -1314,6 +1421,7 @@ static int64_t calc_min_seg_no(AVFormatContext *s, struct representation *pls) int64_t num = 0; if (c->is_live && pls->fragment_duration) { + av_log(s, AV_LOG_TRACE, "in live mode\n"); num = pls->first_seq_no + (((get_current_time_in_sec() - c->availability_start_time) - c->time_shift_buffer_depth) * pls->fragment_timescale) / pls->fragment_duration; } else { num = pls->first_seq_no; @@ -1331,7 +1439,12 @@ static int64_t calc_max_seg_no(struct representation *pls, DASHContext *c) int i = 0; num = pls->first_seq_no + pls->n_timelines - 1; for (i = 0; i < pls->n_timelines; i++) { - num += pls->timelines[i]->repeat; + if (pls->timelines[i]->repeat == -1) { + int length_of_each_segment = pls->timelines[i]->duration / pls->fragment_timescale; + num = c->period_duration / length_of_each_segment; + } else { + num += pls->timelines[i]->repeat; + } } } else if (c->is_live && pls->fragment_duration) { num = pls->first_seq_no + (((get_current_time_in_sec() - c->availability_start_time)) * pls->fragment_timescale) / pls->fragment_duration; @@ -1376,15 +1489,15 @@ static void move_segments(struct representation *rep_src, struct representation static int refresh_manifest(AVFormatContext *s) { - int ret = 0, i; DASHContext *c = s->priv_data; - // save current context int n_videos = c->n_videos; struct representation **videos = c->videos; int n_audios = c->n_audios; struct representation **audios = c->audios; + int n_subtitles = c->n_subtitles; + struct representation **subtitles = c->subtitles; char *base_url = c->base_url; c->base_url = NULL; @@ -1392,20 +1505,28 @@ static int refresh_manifest(AVFormatContext *s) c->videos = NULL; c->n_audios = 0; c->audios = NULL; - ret = parse_manifest(s, s->filename, NULL); + c->n_subtitles = 0; + c->subtitles = NULL; + ret = parse_manifest(s, s->url, NULL); if (ret) goto finish; if (c->n_videos != n_videos) { av_log(c, AV_LOG_ERROR, - "new manifest has mismatched no. of video representations, %d -> %d\n", - n_videos, c->n_videos); + "new manifest has mismatched no. of video representations, %d -> %d\n", + n_videos, c->n_videos); return AVERROR_INVALIDDATA; } if (c->n_audios != n_audios) { av_log(c, AV_LOG_ERROR, - "new manifest has mismatched no. of audio representations, %d -> %d\n", - n_audios, c->n_audios); + "new manifest has mismatched no. of audio representations, %d -> %d\n", + n_audios, c->n_audios); + return AVERROR_INVALIDDATA; + } + if (c->n_subtitles != n_subtitles) { + av_log(c, AV_LOG_ERROR, + "new manifest has mismatched no. of subtitles representations, %d -> %d\n", + n_subtitles, c->n_subtitles); return AVERROR_INVALIDDATA; } @@ -1448,10 +1569,16 @@ finish: av_free(base_url); else c->base_url = base_url; + + if (c->subtitles) + free_subtitle_list(c); if (c->audios) free_audio_list(c); if (c->videos) free_video_list(c); + + c->n_subtitles = n_subtitles; + c->subtitles = subtitles; c->n_audios = n_audios; c->audios = audios; c->n_videos = n_videos; @@ -1534,14 +1661,8 @@ static struct fragment *get_current_fragment(struct representation *pls) return seg; } -enum ReadFromURLMode { - READ_NORMAL, - READ_COMPLETE, -}; - static int read_from_url(struct representation *pls, struct fragment *seg, - uint8_t *buf, int buf_size, - enum ReadFromURLMode mode) + uint8_t *buf, int buf_size) { int ret; @@ -1549,14 +1670,7 @@ static int read_from_url(struct representation *pls, struct fragment *seg, if (seg->size >= 0) buf_size = FFMIN(buf_size, pls->cur_seg_size - pls->cur_seg_offset); - if (mode == READ_COMPLETE) { - ret = avio_read(pls->input, buf, buf_size); - if (ret < buf_size) { - av_log(pls->parent, AV_LOG_WARNING, "Could not read complete fragment.\n"); - } - } else { - ret = avio_read(pls->input, buf, buf_size); - } + ret = avio_read(pls->input, buf, buf_size); if (ret > 0) pls->cur_seg_offset += ret; @@ -1571,9 +1685,10 @@ static int open_input(DASHContext *c, struct representation *pls, struct fragmen url = av_mallocz(c->max_url_size); if (!url) { + ret = AVERROR(ENOMEM); goto cleanup; } - set_httpheader_options(c, &opts); + if (seg->size >= 0) { /* try to restrict the HTTP request to the part we want * (if this is in fact a HTTP request) */ @@ -1585,9 +1700,6 @@ static int open_input(DASHContext *c, struct representation *pls, struct fragmen av_log(pls->parent, AV_LOG_VERBOSE, "DASH request for url '%s', offset %"PRId64", playlist %d\n", url, seg->url_offset, pls->rep_idx); ret = open_url(pls->parent, &pls->input, url, c->avio_opts, opts, NULL); - if (ret < 0) { - goto cleanup; - } cleanup: av_free(url); @@ -1632,7 +1744,7 @@ static int update_init_section(struct representation *pls) av_fast_malloc(&pls->init_sec_buf, &pls->init_sec_buf_size, sec_size); ret = read_from_url(pls, pls->init_section, pls->init_sec_buf, - pls->init_sec_buf_size, READ_COMPLETE); + pls->init_sec_buf_size); ff_format_io_close(pls->parent, &pls->input); if (ret < 0) @@ -1677,8 +1789,8 @@ restart: ret = open_input(c, v, v->cur_seg); if (ret < 0) { if (ff_check_interrupt(c->interrupt_callback)) { - goto end; ret = AVERROR_EXIT; + goto end; } av_log(v->parent, AV_LOG_WARNING, "Failed to open fragment of playlist %d\n", v->rep_idx); v->cur_seq_no++; @@ -1703,7 +1815,7 @@ restart: ret = AVERROR_EOF; goto end; } - ret = read_from_url(v, v->cur_seg, buf, buf_size, READ_NORMAL); + ret = read_from_url(v, v->cur_seg, buf, buf_size); if (ret > 0) goto end; @@ -1720,7 +1832,9 @@ end: static int save_avio_options(AVFormatContext *s) { DASHContext *c = s->priv_data; - const char *opts[] = { "headers", "user_agent", "user-agent", "cookies", NULL }, **opt = opts; + const char *opts[] = { + "headers", "user_agent", "cookies", "http_proxy", "referer", "rw_timeout", NULL }; + const char **opt = opts; uint8_t *buf = NULL; int ret = 0; @@ -1748,7 +1862,7 @@ static int nested_io_open(AVFormatContext *s, AVIOContext **pb, const char *url, av_log(s, AV_LOG_ERROR, "A DASH playlist item '%s' referred to an external file '%s'. " "Opening this file was forbidden for security reasons\n", - s->filename, url); + s->url, url); return AVERROR(EPERM); } @@ -1765,7 +1879,7 @@ static void close_demux_for_component(struct representation *pls) static int reopen_demux_for_component(AVFormatContext *s, struct representation *pls) { DASHContext *c = s->priv_data; - AVInputFormat *in_fmt = NULL; + ff_const59 AVInputFormat *in_fmt = NULL; AVDictionary *in_fmt_opts = NULL; uint8_t *avio_ctx_buffer = NULL; int ret = 0, i; @@ -1773,6 +1887,12 @@ static int reopen_demux_for_component(AVFormatContext *s, struct representation if (pls->ctx) { close_demux_for_component(pls); } + + if (ff_check_interrupt(&s->interrupt_callback)) { + ret = AVERROR_EXIT; + goto fail; + } + if (!(pls->ctx = avformat_alloc_context())) { ret = AVERROR(ENOMEM); goto fail; @@ -1821,7 +1941,6 @@ static int reopen_demux_for_component(AVFormatContext *s, struct representation pls->ctx->streams[i]->r_frame_rate = pls->framerate; } #endif - ret = avformat_find_stream_info(pls->ctx, NULL); if (ret < 0) goto fail; @@ -1855,7 +1974,7 @@ static int open_demux_for_component(AVFormatContext *s, struct representation *p goto fail; } st->id = i; - avcodec_parameters_copy(st->codecpar, pls->ctx->streams[i]->codecpar); + avcodec_parameters_copy(st->codecpar, ist->codecpar); avpriv_set_pts_info(st, ist->pts_wrap_bits, ist->time_base.num, ist->time_base.den); } @@ -1864,50 +1983,120 @@ fail: return ret; } +static int is_common_init_section_exist(struct representation **pls, int n_pls) +{ + struct fragment *first_init_section = pls[0]->init_section; + char *url =NULL; + int64_t url_offset = -1; + int64_t size = -1; + int i = 0; + + if (first_init_section == NULL || n_pls == 0) + return 0; + + url = first_init_section->url; + url_offset = first_init_section->url_offset; + size = pls[0]->init_section->size; + for (i=0;iinit_section->url,url) || pls[i]->init_section->url_offset != url_offset || pls[i]->init_section->size != size) { + return 0; + } + } + return 1; +} + +static int copy_init_section(struct representation *rep_dest, struct representation *rep_src) +{ + rep_dest->init_sec_buf = av_mallocz(rep_src->init_sec_buf_size); + if (!rep_dest->init_sec_buf) { + av_log(rep_dest->ctx, AV_LOG_WARNING, "Cannot alloc memory for init_sec_buf\n"); + return AVERROR(ENOMEM); + } + memcpy(rep_dest->init_sec_buf, rep_src->init_sec_buf, rep_src->init_sec_data_len); + rep_dest->init_sec_buf_size = rep_src->init_sec_buf_size; + rep_dest->init_sec_data_len = rep_src->init_sec_data_len; + rep_dest->cur_timestamp = rep_src->cur_timestamp; + + return 0; +} + + static int dash_read_header(AVFormatContext *s) { - void *u = (s->flags & AVFMT_FLAG_CUSTOM_IO) ? NULL : s->pb; DASHContext *c = s->priv_data; + struct representation *rep; int ret = 0; int stream_index = 0; int i; c->interrupt_callback = &s->interrupt_callback; - // if the URL context is good, read important options we must broker later - if (u) { - update_options(&c->user_agent, "user-agent", u); - update_options(&c->cookies, "cookies", u); - update_options(&c->headers, "headers", u); - } - - if ((ret = parse_manifest(s, s->filename, s->pb)) < 0) - goto fail; if ((ret = save_avio_options(s)) < 0) goto fail; + if ((ret = parse_manifest(s, s->url, s->pb)) < 0) + goto fail; + /* If this isn't a live stream, fill the total duration of the * stream. */ if (!c->is_live) { s->duration = (int64_t) c->media_presentation_duration * AV_TIME_BASE; + } else { + av_dict_set(&c->avio_opts, "seekable", "0", 0); } + if(c->n_videos) + c->is_init_section_common_video = is_common_init_section_exist(c->videos, c->n_videos); + /* Open the demuxer for video and audio components if available */ for (i = 0; i < c->n_videos; i++) { - struct representation *cur_video = c->videos[i]; - ret = open_demux_for_component(s, cur_video); + rep = c->videos[i]; + if (i > 0 && c->is_init_section_common_video) { + ret = copy_init_section(rep, c->videos[0]); + if (ret < 0) + goto fail; + } + ret = open_demux_for_component(s, rep); + if (ret) goto fail; - cur_video->stream_index = stream_index; + rep->stream_index = stream_index; ++stream_index; } + if(c->n_audios) + c->is_init_section_common_audio = is_common_init_section_exist(c->audios, c->n_audios); + for (i = 0; i < c->n_audios; i++) { - struct representation *cur_audio = c->audios[i]; - ret = open_demux_for_component(s, cur_audio); + rep = c->audios[i]; + if (i > 0 && c->is_init_section_common_audio) { + ret = copy_init_section(rep, c->audios[0]); + if (ret < 0) + goto fail; + } + ret = open_demux_for_component(s, rep); + if (ret) goto fail; - cur_audio->stream_index = stream_index; + rep->stream_index = stream_index; + ++stream_index; + } + + if (c->n_subtitles) + c->is_init_section_common_audio = is_common_init_section_exist(c->subtitles, c->n_subtitles); + + for (i = 0; i < c->n_subtitles; i++) { + rep = c->subtitles[i]; + if (i > 0 && c->is_init_section_common_audio) { + ret = copy_init_section(rep, c->subtitles[0]); + if (ret < 0) + goto fail; + } + ret = open_demux_for_component(s, rep); + + if (ret) + goto fail; + rep->stream_index = stream_index; ++stream_index; } @@ -1925,24 +2114,29 @@ static int dash_read_header(AVFormatContext *s) } for (i = 0; i < c->n_videos; i++) { - struct representation *pls = c->videos[i]; - - av_program_add_stream_index(s, 0, pls->stream_index); - pls->assoc_stream = s->streams[pls->stream_index]; - if (pls->bandwidth > 0) - av_dict_set_int(&pls->assoc_stream->metadata, "variant_bitrate", pls->bandwidth, 0); - if (pls->id[0]) - av_dict_set(&pls->assoc_stream->metadata, "id", pls->id, 0); - } + rep = c->videos[i]; + av_program_add_stream_index(s, 0, rep->stream_index); + rep->assoc_stream = s->streams[rep->stream_index]; + if (rep->bandwidth > 0) + av_dict_set_int(&rep->assoc_stream->metadata, "variant_bitrate", rep->bandwidth, 0); + if (rep->id[0]) + av_dict_set(&rep->assoc_stream->metadata, "id", rep->id, 0); + } for (i = 0; i < c->n_audios; i++) { - struct representation *pls = c->audios[i]; - - av_program_add_stream_index(s, 0, pls->stream_index); - pls->assoc_stream = s->streams[pls->stream_index]; - if (pls->bandwidth > 0) - av_dict_set_int(&pls->assoc_stream->metadata, "variant_bitrate", pls->bandwidth, 0); - if (pls->id[0]) - av_dict_set(&pls->assoc_stream->metadata, "id", pls->id, 0); + rep = c->audios[i]; + av_program_add_stream_index(s, 0, rep->stream_index); + rep->assoc_stream = s->streams[rep->stream_index]; + if (rep->bandwidth > 0) + av_dict_set_int(&rep->assoc_stream->metadata, "variant_bitrate", rep->bandwidth, 0); + if (rep->id[0]) + av_dict_set(&rep->assoc_stream->metadata, "id", rep->id, 0); + } + for (i = 0; i < c->n_subtitles; i++) { + rep = c->subtitles[i]; + av_program_add_stream_index(s, 0, rep->stream_index); + rep->assoc_stream = s->streams[rep->stream_index]; + if (rep->id[0]) + av_dict_set(&rep->assoc_stream->metadata, "id", rep->id, 0); } } @@ -1957,8 +2151,8 @@ static void recheck_discard_flags(AVFormatContext *s, struct representation **p, for (i = 0; i < n; i++) { struct representation *pls = p[i]; - int needed = !pls->assoc_stream || pls->assoc_stream->discard < AVDISCARD_ALL; + if (needed && !pls->ctx) { pls->cur_seg_offset = 0; pls->init_sec_buf_read_offset = 0; @@ -1983,26 +2177,38 @@ static int dash_read_packet(AVFormatContext *s, AVPacket *pkt) int ret = 0, i; int64_t mints = 0; struct representation *cur = NULL; + struct representation *rep = NULL; recheck_discard_flags(s, c->videos, c->n_videos); recheck_discard_flags(s, c->audios, c->n_audios); + recheck_discard_flags(s, c->subtitles, c->n_subtitles); for (i = 0; i < c->n_videos; i++) { - struct representation *pls = c->videos[i]; - if (!pls->ctx) + rep = c->videos[i]; + if (!rep->ctx) continue; - if (!cur || pls->cur_timestamp < mints) { - cur = pls; - mints = pls->cur_timestamp; + if (!cur || rep->cur_timestamp < mints) { + cur = rep; + mints = rep->cur_timestamp; } } for (i = 0; i < c->n_audios; i++) { - struct representation *pls = c->audios[i]; - if (!pls->ctx) + rep = c->audios[i]; + if (!rep->ctx) continue; - if (!cur || pls->cur_timestamp < mints) { - cur = pls; - mints = pls->cur_timestamp; + if (!cur || rep->cur_timestamp < mints) { + cur = rep; + mints = rep->cur_timestamp; + } + } + + for (i = 0; i < c->n_subtitles; i++) { + rep = c->subtitles[i]; + if (!rep->ctx) + continue; + if (!cur || rep->cur_timestamp < mints) { + cur = rep; + mints = rep->cur_timestamp; } } @@ -2034,9 +2240,6 @@ static int dash_close(AVFormatContext *s) DASHContext *c = s->priv_data; free_audio_list(c); free_video_list(c); - - av_freep(&c->cookies); - av_freep(&c->user_agent); av_dict_free(&c->avio_opts); av_freep(&c->base_url); return 0; @@ -2050,7 +2253,7 @@ static int dash_seek(AVFormatContext *s, struct representation *pls, int64_t see int64_t duration = 0; av_log(pls->parent, AV_LOG_VERBOSE, "DASH seek pos[%"PRId64"ms], playlist %d%s\n", - seek_pos_msec, pls->rep_idx, dry_run ? " (dry)" : ""); + seek_pos_msec, pls->rep_idx, dry_run ? " (dry)" : ""); // single fragment mode if (pls->n_fragments == 1) { @@ -2127,11 +2330,15 @@ static int dash_read_seek(AVFormatContext *s, int stream_index, int64_t timestam if (!ret) ret = dash_seek(s, c->audios[i], seek_pos_msec, flags, !c->audios[i]->ctx); } + for (i = 0; i < c->n_subtitles; i++) { + if (!ret) + ret = dash_seek(s, c->subtitles[i], seek_pos_msec, flags, !c->subtitles[i]->ctx); + } return ret; } -static int dash_probe(AVProbeData *p) +static int dash_probe(const AVProbeData *p) { if (!av_stristr(p->buf, "priv_data; int http_base_proto = filename ? ff_is_http_proto(filename) : 0; + if (!*pb) + return; + if (!http_base_proto || !c->http_persistent) { ff_format_io_close(s, pb); #if CONFIG_HTTP_PROTOCOL @@ -164,8 +211,105 @@ static void dashenc_io_close(AVFormatContext *s, AVIOContext **pb, char *filenam } } +static const char *get_format_str(SegmentType segment_type) { + int i; + for (i = 0; i < SEGMENT_TYPE_NB; i++) + if (formats[i].segment_type == segment_type) + return formats[i].str; + return NULL; +} + +static const char *get_extension_str(SegmentType type, int single_file) +{ + switch (type) { + + case SEGMENT_TYPE_MP4: return single_file ? "mp4" : "m4s"; + case SEGMENT_TYPE_WEBM: return "webm"; + default: return NULL; + } +} + +static int handle_io_open_error(AVFormatContext *s, int err, char *url) { + DASHContext *c = s->priv_data; + char errbuf[AV_ERROR_MAX_STRING_SIZE]; + av_strerror(err, errbuf, sizeof(errbuf)); + av_log(s, c->ignore_io_errors ? AV_LOG_WARNING : AV_LOG_ERROR, + "Unable to open %s for writing: %s\n", url, errbuf); + return c->ignore_io_errors ? 0 : err; +} + +static inline SegmentType select_segment_type(SegmentType segment_type, enum AVCodecID codec_id) +{ + if (segment_type == SEGMENT_TYPE_AUTO) { + if (codec_id == AV_CODEC_ID_OPUS || codec_id == AV_CODEC_ID_VORBIS || + codec_id == AV_CODEC_ID_VP8 || codec_id == AV_CODEC_ID_VP9) { + segment_type = SEGMENT_TYPE_WEBM; + } else { + segment_type = SEGMENT_TYPE_MP4; + } + } + + return segment_type; +} + +static int init_segment_types(AVFormatContext *s) +{ + DASHContext *c = s->priv_data; + int has_mp4_streams = 0; + for (int i = 0; i < s->nb_streams; ++i) { + OutputStream *os = &c->streams[i]; + SegmentType segment_type = select_segment_type( + c->segment_type_option, s->streams[i]->codecpar->codec_id); + os->segment_type = segment_type; + os->format_name = get_format_str(segment_type); + if (!os->format_name) { + av_log(s, AV_LOG_ERROR, "Could not select DASH segment type for stream %d\n", i); + return AVERROR_MUXER_NOT_FOUND; + } + os->extension_name = get_extension_str(segment_type, c->single_file); + if (!os->extension_name) { + av_log(s, AV_LOG_ERROR, "Could not get extension type for stream %d\n", i); + return AVERROR_MUXER_NOT_FOUND; + } + + has_mp4_streams |= segment_type == SEGMENT_TYPE_MP4; + } + + if (c->hls_playlist && !has_mp4_streams) { + av_log(s, AV_LOG_WARNING, "No mp4 streams, disabling HLS manifest generation\n"); + c->hls_playlist = 0; + } + + return 0; +} + +static int check_file_extension(const char *filename, const char *extension) { + char *dot; + if (!filename || !extension) + return -1; + dot = strrchr(filename, '.'); + if (dot && !strcmp(dot + 1, extension)) + return 0; + return -1; +} + +static void set_vp9_codec_str(AVFormatContext *s, AVCodecParameters *par, + AVRational *frame_rate, char *str, int size) { + VPCC vpcc; + int ret = ff_isom_get_vpcc_features(s, par, frame_rate, &vpcc); + if (ret == 0) { + av_strlcatf(str, size, "vp09.%02d.%02d.%02d", + vpcc.profile, vpcc.level, vpcc.bitdepth); + } else { + // Default to just vp9 in case of error while finding out profile or level + av_log(s, AV_LOG_WARNING, "Could not find VP9 profile and/or level\n"); + av_strlcpy(str, "vp9", size); + } + return; +} + static void set_codec_str(AVFormatContext *s, AVCodecParameters *par, - char *str, int size) + AVRational *frame_rate, char *str, int size) { const AVCodecTag *tags[2] = { NULL, NULL }; uint32_t tag; @@ -174,7 +318,11 @@ static void set_codec_str(AVFormatContext *s, AVCodecParameters *par, // common Webm codecs are not part of RFC 6381 for (i = 0; codecs[i].id; i++) if (codecs[i].id == par->codec_id) { - av_strlcpy(str, codecs[i].str, size); + if (codecs[i].id == AV_CODEC_ID_VP9) { + set_vp9_codec_str(s, par, frame_rate, str, size); + } else { + av_strlcpy(str, codecs[i].str, size); + } return; } @@ -186,7 +334,9 @@ static void set_codec_str(AVFormatContext *s, AVCodecParameters *par, else return; - tag = av_codec_get_tag(tags, par->codec_id); + tag = par->codec_tag; + if (!tag) + tag = av_codec_get_tag(tags, par->codec_id); if (!tag) return; if (size < 5) @@ -236,10 +386,25 @@ static void set_codec_str(AVFormatContext *s, AVCodecParameters *par, av_strlcatf(str, size, ".%02x%02x%02x", extradata[1], extradata[2], extradata[3]); av_free(tmpbuf); + } else if (!strcmp(str, "av01")) { + AV1SequenceParameters seq; + if (!par->extradata_size) + return; + if (ff_av1_parse_seq_header(&seq, par->extradata, par->extradata_size) < 0) + return; + + av_strlcatf(str, size, ".%01u.%02u%s.%02u", + seq.profile, seq.level, seq.tier ? "H" : "M", seq.bitdepth); + if (seq.color_description_present_flag) + av_strlcatf(str, size, ".%01u.%01u%01u%01u.%02u.%02u.%02u.%01u", + seq.monochrome, + seq.chroma_subsampling_x, seq.chroma_subsampling_y, seq.chroma_sample_position, + seq.color_primaries, seq.transfer_characteristics, seq.matrix_coefficients, + seq.color_range); } } -static int flush_dynbuf(OutputStream *os, int *range_length) +static int flush_dynbuf(DASHContext *c, OutputStream *os, int *range_length) { uint8_t *buffer; @@ -251,15 +416,21 @@ static int flush_dynbuf(OutputStream *os, int *range_length) av_write_frame(os->ctx, NULL); avio_flush(os->ctx->pb); - // write out to file - *range_length = avio_close_dyn_buf(os->ctx->pb, &buffer); - os->ctx->pb = NULL; - avio_write(os->out, buffer + os->written_len, *range_length - os->written_len); - os->written_len = 0; - av_free(buffer); + if (!c->single_file) { + // write out to file + *range_length = avio_close_dyn_buf(os->ctx->pb, &buffer); + os->ctx->pb = NULL; + if (os->out) + avio_write(os->out, buffer + os->written_len, *range_length - os->written_len); + os->written_len = 0; + av_free(buffer); - // re-open buffer - return avio_open_dyn_buf(&os->ctx->pb); + // re-open buffer + return avio_open_dyn_buf(&os->ctx->pb); + } else { + *range_length = avio_tell(os->ctx->pb) - os->pos; + return 0; + } } static void set_http_options(AVDictionary **options, DASHContext *c) @@ -282,18 +453,112 @@ static void get_hls_playlist_name(char *playlist_name, int string_size, snprintf(playlist_name, string_size, "media_%d.m3u8", id); } +static void get_start_index_number(OutputStream *os, DASHContext *c, + int *start_index, int *start_number) { + *start_index = 0; + *start_number = 1; + if (c->window_size) { + *start_index = FFMAX(os->nb_segments - c->window_size, 0); + *start_number = FFMAX(os->segment_index - c->window_size, 1); + } +} + +static void write_hls_media_playlist(OutputStream *os, AVFormatContext *s, + int representation_id, int final, + char *prefetch_url) { + DASHContext *c = s->priv_data; + int timescale = os->ctx->streams[0]->time_base.den; + char temp_filename_hls[1024]; + char filename_hls[1024]; + AVDictionary *http_opts = NULL; + int target_duration = 0; + int ret = 0; + const char *proto = avio_find_protocol_name(c->dirname); + int use_rename = proto && !strcmp(proto, "file"); + int i, start_index, start_number; + double prog_date_time = 0; + + get_start_index_number(os, c, &start_index, &start_number); + + if (!c->hls_playlist || start_index >= os->nb_segments || + os->segment_type != SEGMENT_TYPE_MP4) + return; + + get_hls_playlist_name(filename_hls, sizeof(filename_hls), + c->dirname, representation_id); + + snprintf(temp_filename_hls, sizeof(temp_filename_hls), use_rename ? "%s.tmp" : "%s", filename_hls); + + set_http_options(&http_opts, c); + ret = dashenc_io_open(s, &c->m3u8_out, temp_filename_hls, &http_opts); + av_dict_free(&http_opts); + if (ret < 0) { + handle_io_open_error(s, ret, temp_filename_hls); + return; + } + for (i = start_index; i < os->nb_segments; i++) { + Segment *seg = os->segments[i]; + double duration = (double) seg->duration / timescale; + if (target_duration <= duration) + target_duration = lrint(duration); + } + + ff_hls_write_playlist_header(c->m3u8_out, 6, -1, target_duration, + start_number, PLAYLIST_TYPE_NONE, 0); + + ff_hls_write_init_file(c->m3u8_out, os->initfile, c->single_file, + os->init_range_length, os->init_start_pos); + + for (i = start_index; i < os->nb_segments; i++) { + Segment *seg = os->segments[i]; + + if (prog_date_time == 0) { + if (os->nb_segments == 1) + prog_date_time = c->start_time_s; + else + prog_date_time = seg->prog_date_time; + } + seg->prog_date_time = prog_date_time; + + ret = ff_hls_write_file_entry(c->m3u8_out, 0, c->single_file, + (double) seg->duration / timescale, 0, + seg->range_length, seg->start_pos, NULL, + c->single_file ? os->initfile : seg->file, + &prog_date_time, 0, 0, 0); + if (ret < 0) { + av_log(os->ctx, AV_LOG_WARNING, "ff_hls_write_file_entry get error\n"); + } + } + + if (prefetch_url) + avio_printf(c->m3u8_out, "#EXT-X-PREFETCH:%s\n", prefetch_url); + + if (final) + ff_hls_write_end_list(c->m3u8_out); + + dashenc_io_close(s, &c->m3u8_out, temp_filename_hls); + + if (use_rename) + if (avpriv_io_move(temp_filename_hls, filename_hls) < 0) { + av_log(os->ctx, AV_LOG_WARNING, "renaming file %s to %s failed\n\n", temp_filename_hls, filename_hls); + } +} + static int flush_init_segment(AVFormatContext *s, OutputStream *os) { DASHContext *c = s->priv_data; int ret, range_length; - ret = flush_dynbuf(os, &range_length); + ret = flush_dynbuf(c, os, &range_length); if (ret < 0) return ret; os->pos = os->init_range_length = range_length; - if (!c->single_file) - ff_format_io_close(s, &os->out); + if (!c->single_file) { + char filename[1024]; + snprintf(filename, sizeof(filename), "%s%s", c->dirname, os->initfile); + dashenc_io_close(s, &os->out, filename); + } return 0; } @@ -313,16 +578,21 @@ static void dash_free(AVFormatContext *s) return; for (i = 0; i < s->nb_streams; i++) { OutputStream *os = &c->streams[i]; - if (os->ctx && os->ctx_inited) - av_write_trailer(os->ctx); - if (os->ctx && os->ctx->pb) - ffio_free_dyn_buf(&os->ctx->pb); + if (os->ctx && os->ctx->pb) { + if (!c->single_file) + ffio_free_dyn_buf(&os->ctx->pb); + else + avio_close(os->ctx->pb); + } ff_format_io_close(s, &os->out); if (os->ctx) avformat_free_context(os->ctx); for (j = 0; j < os->nb_segments; j++) av_free(os->segments[j]); av_free(os->segments); + av_freep(&os->single_file_name); + av_freep(&os->init_seg_name); + av_freep(&os->media_seg_name); } av_freep(&c->streams); @@ -334,18 +604,19 @@ static void output_segment_list(OutputStream *os, AVIOContext *out, AVFormatCont int representation_id, int final) { DASHContext *c = s->priv_data; - int i, start_index = 0, start_number = 1; - if (c->window_size) { - start_index = FFMAX(os->nb_segments - c->window_size, 0); - start_number = FFMAX(os->segment_index - c->window_size, 1); - } + int i, start_index, start_number; + get_start_index_number(os, c, &start_index, &start_number); if (c->use_template) { int timescale = c->use_timeline ? os->ctx->streams[0]->time_base.den : AV_TIME_BASE; avio_printf(out, "\t\t\t\tuse_timeline) - avio_printf(out, "duration=\"%"PRId64"\" ", c->last_duration); - avio_printf(out, "initialization=\"%s\" media=\"%s\" startNumber=\"%d\">\n", c->init_seg_name, c->media_seg_name, c->use_timeline ? start_number : 1); + if (!c->use_timeline) { + avio_printf(out, "duration=\"%"PRId64"\" ", c->seg_duration); + if (c->streaming && os->availability_time_offset) + avio_printf(out, "availabilityTimeOffset=\"%.3f\" ", + os->availability_time_offset); + } + avio_printf(out, "initialization=\"%s\" media=\"%s\" startNumber=\"%d\">\n", os->init_seg_name, os->media_seg_name, c->use_timeline ? start_number : 1); if (c->use_timeline) { int64_t cur_time = 0; avio_printf(out, "\t\t\t\t\t\n"); @@ -357,7 +628,7 @@ static void output_segment_list(OutputStream *os, AVIOContext *out, AVFormatCont cur_time = seg->time; avio_printf(out, "t=\"%"PRId64"\" ", seg->time); } - avio_printf(out, "d=\"%d\" ", seg->duration); + avio_printf(out, "d=\"%"PRId64"\" ", seg->duration); while (i + repeat + 1 < os->nb_segments && os->segments[i + repeat + 1]->duration == seg->duration && os->segments[i + repeat + 1]->time == os->segments[i + repeat]->time + os->segments[i + repeat]->duration) @@ -392,59 +663,8 @@ static void output_segment_list(OutputStream *os, AVIOContext *out, AVFormatCont } avio_printf(out, "\t\t\t\t\n"); } - if (c->hls_playlist && start_index < os->nb_segments) - { - int timescale = os->ctx->streams[0]->time_base.den; - char temp_filename_hls[1024]; - char filename_hls[1024]; - AVDictionary *http_opts = NULL; - int target_duration = 0; - int ret = 0; - const char *proto = avio_find_protocol_name(c->dirname); - int use_rename = proto && !strcmp(proto, "file"); - - get_hls_playlist_name(filename_hls, sizeof(filename_hls), - c->dirname, representation_id); - - snprintf(temp_filename_hls, sizeof(temp_filename_hls), use_rename ? "%s.tmp" : "%s", filename_hls); - - set_http_options(&http_opts, c); - dashenc_io_open(s, &c->m3u8_out, temp_filename_hls, &http_opts); - av_dict_free(&http_opts); - for (i = start_index; i < os->nb_segments; i++) { - Segment *seg = os->segments[i]; - double duration = (double) seg->duration / timescale; - if (target_duration <= duration) - target_duration = lrint(duration); - } - - ff_hls_write_playlist_header(c->m3u8_out, 6, -1, target_duration, - start_number, PLAYLIST_TYPE_NONE); - - ff_hls_write_init_file(c->m3u8_out, os->initfile, c->single_file, - os->init_range_length, os->init_start_pos); - - for (i = start_index; i < os->nb_segments; i++) { - Segment *seg = os->segments[i]; - ret = ff_hls_write_file_entry(c->m3u8_out, 0, c->single_file, - (double) seg->duration / timescale, 0, - seg->range_length, seg->start_pos, NULL, - c->single_file ? os->initfile : seg->file, - NULL); - if (ret < 0) { - av_log(os->ctx, AV_LOG_WARNING, "ff_hls_write_file_entry get error\n"); - } - } - - if (final) - ff_hls_write_end_list(c->m3u8_out); - - dashenc_io_close(s, &c->m3u8_out, temp_filename_hls); - - if (use_rename) - if (avpriv_io_move(temp_filename_hls, filename_hls) < 0) { - av_log(os->ctx, AV_LOG_WARNING, "renaming file %s to %s failed\n\n", temp_filename_hls, filename_hls); - } + if (!c->lhls || final) { + write_hls_media_playlist(os, s, representation_id, final, NULL); } } @@ -507,12 +727,20 @@ static void write_time(AVIOContext *out, int64_t time) static void format_date_now(char *buf, int size) { - time_t t = time(NULL); struct tm *ptm, tmbuf; - ptm = gmtime_r(&t, &tmbuf); + int64_t time_us = av_gettime(); + int64_t time_ms = time_us / 1000; + const time_t time_s = time_ms / 1000; + int millisec = time_ms - (time_s * 1000); + ptm = gmtime_r(&time_s, &tmbuf); if (ptm) { - if (!strftime(buf, size, "%Y-%m-%dT%H:%M:%SZ", ptm)) + int len; + if (!strftime(buf, size, "%Y-%m-%dT%H:%M:%S", ptm)) { buf[0] = '\0'; + return; + } + len = strlen(buf); + snprintf(buf + len, size - len, ".%03dZ", millisec); } } @@ -539,20 +767,25 @@ static int write_adaptation_set(AVFormatContext *s, AVIOContext *out, int as_ind for (i = 0; i < s->nb_streams; i++) { OutputStream *os = &c->streams[i]; + char bandwidth_str[64] = {'\0'}; if (os->as_idx - 1 != as_index) continue; + if (os->bit_rate > 0) + snprintf(bandwidth_str, sizeof(bandwidth_str), " bandwidth=\"%d\"", + os->bit_rate); + if (as->media_type == AVMEDIA_TYPE_VIDEO) { AVStream *st = s->streams[i]; avio_printf(out, "\t\t\tformat_name, os->codec_str, os->bandwidth_str, s->streams[i]->codecpar->width, s->streams[i]->codecpar->height); + i, os->format_name, os->codec_str, bandwidth_str, s->streams[i]->codecpar->width, s->streams[i]->codecpar->height); if (st->avg_frame_rate.num) avio_printf(out, " frameRate=\"%d/%d\"", st->avg_frame_rate.num, st->avg_frame_rate.den); avio_printf(out, ">\n"); } else { avio_printf(out, "\t\t\t\n", - i, os->format_name, os->codec_str, os->bandwidth_str, s->streams[i]->codecpar->sample_rate); + i, os->format_name, os->codec_str, bandwidth_str, s->streams[i]->codecpar->sample_rate); avio_printf(out, "\t\t\t\t\n", s->streams[i]->codecpar->channels); } @@ -716,12 +949,11 @@ static int write_manifest(AVFormatContext *s, int final) snprintf(temp_filename, sizeof(temp_filename), use_rename ? "%s.tmp" : "%s", s->url); set_http_options(&opts, c); ret = dashenc_io_open(s, &c->mpd_out, temp_filename, &opts); + av_dict_free(&opts); if (ret < 0) { - av_log(s, AV_LOG_ERROR, "Unable to open %s for writing\n", temp_filename); - return ret; + return handle_io_open_error(s, ret, temp_filename); } out = c->mpd_out; - av_dict_free(&opts); avio_printf(out, "\n"); avio_printf(out, "last_duration / AV_TIME_BASE); - if (!c->availability_start_time[0] && s->nb_streams > 0 && c->streams[0].nb_segments > 0) { - format_date_now(c->availability_start_time, sizeof(c->availability_start_time)); - } if (c->availability_start_time[0]) avio_printf(out, "\tavailabilityStartTime=\"%s\"\n", c->availability_start_time); format_date_now(now_str, sizeof(now_str)); @@ -794,54 +1023,83 @@ static int write_manifest(AVFormatContext *s, int final) return ret; } - if (c->hls_playlist && !c->master_playlist_created) { + if (c->hls_playlist) { char filename_hls[1024]; const char *audio_group = "A1"; + char audio_codec_str[128] = "\0"; int is_default = 1; int max_audio_bitrate = 0; + // Publish master playlist only the configured rate + if (c->master_playlist_created && (!c->master_publish_rate || + c->streams[0].segment_index % c->master_publish_rate)) + return 0; + if (*c->dirname) - snprintf(filename_hls, sizeof(filename_hls), "%s/master.m3u8", c->dirname); + snprintf(filename_hls, sizeof(filename_hls), "%smaster.m3u8", c->dirname); else snprintf(filename_hls, sizeof(filename_hls), "master.m3u8"); snprintf(temp_filename, sizeof(temp_filename), use_rename ? "%s.tmp" : "%s", filename_hls); set_http_options(&opts, c); - ret = avio_open2(&out, temp_filename, AVIO_FLAG_WRITE, NULL, &opts); - if (ret < 0) { - av_log(s, AV_LOG_ERROR, "Unable to open %s for writing\n", temp_filename); - return ret; - } + ret = dashenc_io_open(s, &c->m3u8_out, temp_filename, &opts); av_dict_free(&opts); + if (ret < 0) { + return handle_io_open_error(s, ret, temp_filename); + } - ff_hls_write_playlist_version(out, 6); + ff_hls_write_playlist_version(c->m3u8_out, 7); for (i = 0; i < s->nb_streams; i++) { char playlist_file[64]; AVStream *st = s->streams[i]; + OutputStream *os = &c->streams[i]; if (st->codecpar->codec_type != AVMEDIA_TYPE_AUDIO) continue; + if (os->segment_type != SEGMENT_TYPE_MP4) + continue; get_hls_playlist_name(playlist_file, sizeof(playlist_file), NULL, i); - ff_hls_write_audio_rendition(out, (char *)audio_group, - playlist_file, i, is_default); - max_audio_bitrate = FFMAX(st->codecpar->bit_rate, max_audio_bitrate); + ff_hls_write_audio_rendition(c->m3u8_out, (char *)audio_group, + playlist_file, NULL, i, is_default); + max_audio_bitrate = FFMAX(st->codecpar->bit_rate + + os->muxer_overhead, max_audio_bitrate); + if (!av_strnstr(audio_codec_str, os->codec_str, sizeof(audio_codec_str))) { + if (strlen(audio_codec_str)) + av_strlcat(audio_codec_str, ",", sizeof(audio_codec_str)); + av_strlcat(audio_codec_str, os->codec_str, sizeof(audio_codec_str)); + } is_default = 0; } for (i = 0; i < s->nb_streams; i++) { char playlist_file[64]; + char codec_str[128]; AVStream *st = s->streams[i]; + OutputStream *os = &c->streams[i]; char *agroup = NULL; - int stream_bitrate = st->codecpar->bit_rate; - if ((st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) && max_audio_bitrate) { + char *codec_str_ptr = NULL; + int stream_bitrate = st->codecpar->bit_rate + os->muxer_overhead; + if (st->codecpar->codec_type != AVMEDIA_TYPE_VIDEO) + continue; + if (os->segment_type != SEGMENT_TYPE_MP4) + continue; + av_strlcpy(codec_str, os->codec_str, sizeof(codec_str)); + if (max_audio_bitrate) { agroup = (char *)audio_group; stream_bitrate += max_audio_bitrate; + av_strlcat(codec_str, ",", sizeof(codec_str)); + av_strlcat(codec_str, audio_codec_str, sizeof(codec_str)); + } + if (st->codecpar->codec_id != AV_CODEC_ID_HEVC) { + codec_str_ptr = codec_str; } get_hls_playlist_name(playlist_file, sizeof(playlist_file), NULL, i); - ff_hls_write_stream_info(st, out, stream_bitrate, playlist_file, agroup, NULL, NULL); + ff_hls_write_stream_info(st, c->m3u8_out, stream_bitrate, + playlist_file, agroup, + codec_str_ptr, NULL); } - avio_close(out); + dashenc_io_close(s, &c->m3u8_out, temp_filename); if (use_rename) if ((ret = avpriv_io_move(temp_filename, filename_hls)) < 0) return ret; @@ -866,11 +1124,44 @@ static int dash_init(AVFormatContext *s) char *ptr; char basename[1024]; + c->nr_of_streams_to_flush = 0; if (c->single_file_name) c->single_file = 1; if (c->single_file) c->use_template = 0; +#if FF_API_DASH_MIN_SEG_DURATION + if (c->min_seg_duration != 5000000) { + av_log(s, AV_LOG_WARNING, "The min_seg_duration option is deprecated and will be removed. Please use the -seg_duration\n"); + c->seg_duration = c->min_seg_duration; + } +#endif + if (c->lhls && s->strict_std_compliance > FF_COMPLIANCE_EXPERIMENTAL) { + av_log(s, AV_LOG_ERROR, + "LHLS is experimental, Please set -strict experimental in order to enable it.\n"); + return AVERROR_EXPERIMENTAL; + } + + if (c->lhls && !c->streaming) { + av_log(s, AV_LOG_WARNING, "LHLS option will be ignored as streaming is not enabled\n"); + c->lhls = 0; + } + + if (c->lhls && !c->hls_playlist) { + av_log(s, AV_LOG_WARNING, "LHLS option will be ignored as hls_playlist is not enabled\n"); + c->lhls = 0; + } + + if (c->global_sidx && !c->single_file) { + av_log(s, AV_LOG_WARNING, "Global SIDX option will be ignored as single_file is not enabled\n"); + c->global_sidx = 0; + } + + if (c->global_sidx && c->streaming) { + av_log(s, AV_LOG_WARNING, "Global SIDX option will be ignored as streaming is enabled\n"); + c->global_sidx = 0; + } + av_strlcpy(c->dirname, s->url, sizeof(c->dirname)); ptr = strrchr(c->dirname, '/'); if (ptr) { @@ -892,6 +1183,9 @@ static int dash_init(AVFormatContext *s) if ((ret = parse_adaptation_sets(s)) < 0) return ret; + if ((ret = init_segment_types(s)) < 0) + return ret; + for (i = 0; i < s->nb_streams; i++) { OutputStream *os = &c->streams[i]; AdaptationSet *as = &c->as[os->as_idx - 1]; @@ -901,10 +1195,7 @@ static int dash_init(AVFormatContext *s) char filename[1024]; os->bit_rate = s->streams[i]->codecpar->bit_rate; - if (os->bit_rate) { - snprintf(os->bandwidth_str, sizeof(os->bandwidth_str), - " bandwidth=\"%d\"", os->bit_rate); - } else { + if (!os->bit_rate) { int level = s->strict_std_compliance >= FF_COMPLIANCE_STRICT ? AV_LOG_ERROR : AV_LOG_WARNING; av_log(s, level, "No bit rate set for stream %d\n", i); @@ -920,25 +1211,47 @@ static int dash_init(AVFormatContext *s) if (!ctx) return AVERROR(ENOMEM); - // choose muxer based on codec: webm for VP8/9 and opus, mp4 otherwise - // note: os->format_name is also used as part of the mimetype of the - // representation, e.g. video/ - if (s->streams[i]->codecpar->codec_id == AV_CODEC_ID_VP8 || - s->streams[i]->codecpar->codec_id == AV_CODEC_ID_VP9 || - s->streams[i]->codecpar->codec_id == AV_CODEC_ID_OPUS || - s->streams[i]->codecpar->codec_id == AV_CODEC_ID_VORBIS) { - snprintf(os->format_name, sizeof(os->format_name), "webm"); - } else { - snprintf(os->format_name, sizeof(os->format_name), "mp4"); + if (c->init_seg_name) { + os->init_seg_name = av_strireplace(c->init_seg_name, "$ext$", os->extension_name); + if (!os->init_seg_name) + return AVERROR(ENOMEM); } + if (c->media_seg_name) { + os->media_seg_name = av_strireplace(c->media_seg_name, "$ext$", os->extension_name); + if (!os->media_seg_name) + return AVERROR(ENOMEM); + } + if (c->single_file_name) { + os->single_file_name = av_strireplace(c->single_file_name, "$ext$", os->extension_name); + if (!os->single_file_name) + return AVERROR(ENOMEM); + } + + if (os->segment_type == SEGMENT_TYPE_WEBM) { + if ((!c->single_file && check_file_extension(os->init_seg_name, os->format_name) != 0) || + (!c->single_file && check_file_extension(os->media_seg_name, os->format_name) != 0) || + (c->single_file && check_file_extension(os->single_file_name, os->format_name) != 0)) { + av_log(s, AV_LOG_WARNING, + "One or many segment file names doesn't end with .webm. " + "Override -init_seg_name and/or -media_seg_name and/or " + "-single_file_name to end with the extension .webm\n"); + } + if (c->streaming) { + // Streaming not supported as matroskaenc buffers internally before writing the output + av_log(s, AV_LOG_WARNING, "One or more streams in WebM output format. Streaming option will be ignored\n"); + c->streaming = 0; + } + } + ctx->oformat = av_guess_format(os->format_name, NULL, NULL); if (!ctx->oformat) return AVERROR_MUXER_NOT_FOUND; os->ctx = ctx; - ctx->interrupt_callback = s->interrupt_callback; - ctx->opaque = s->opaque; - ctx->io_close = s->io_close; - ctx->io_open = s->io_open; + ctx->interrupt_callback = s->interrupt_callback; + ctx->opaque = s->opaque; + ctx->io_close = s->io_close; + ctx->io_open = s->io_open; + ctx->strict_std_compliance = s->strict_std_compliance; if (!(st = avformat_new_stream(ctx, NULL))) return AVERROR(ENOMEM); @@ -949,42 +1262,60 @@ static int dash_init(AVFormatContext *s) ctx->avoid_negative_ts = s->avoid_negative_ts; ctx->flags = s->flags; - if ((ret = avio_open_dyn_buf(&ctx->pb)) < 0) - return ret; - if (c->single_file) { - if (c->single_file_name) - ff_dash_fill_tmpl_params(os->initfile, sizeof(os->initfile), c->single_file_name, i, 0, os->bit_rate, 0); + if (os->single_file_name) + ff_dash_fill_tmpl_params(os->initfile, sizeof(os->initfile), os->single_file_name, i, 0, os->bit_rate, 0); else - snprintf(os->initfile, sizeof(os->initfile), "%s-stream%d.m4s", basename, i); + snprintf(os->initfile, sizeof(os->initfile), "%s-stream%d.%s", basename, i, os->format_name); } else { - ff_dash_fill_tmpl_params(os->initfile, sizeof(os->initfile), c->init_seg_name, i, 0, os->bit_rate, 0); + ff_dash_fill_tmpl_params(os->initfile, sizeof(os->initfile), os->init_seg_name, i, 0, os->bit_rate, 0); } snprintf(filename, sizeof(filename), "%s%s", c->dirname, os->initfile); set_http_options(&opts, c); - ret = s->io_open(s, &os->out, filename, AVIO_FLAG_WRITE, &opts); + if (!c->single_file) { + if ((ret = avio_open_dyn_buf(&ctx->pb)) < 0) + return ret; + ret = s->io_open(s, &os->out, filename, AVIO_FLAG_WRITE, &opts); + } else { + ctx->url = av_strdup(filename); + ret = avio_open2(&ctx->pb, filename, AVIO_FLAG_WRITE, NULL, &opts); + } + av_dict_free(&opts); if (ret < 0) return ret; - av_dict_free(&opts); os->init_start_pos = 0; - if (!strcmp(os->format_name, "mp4")) { + if (c->format_options_str) { + ret = av_dict_parse_string(&opts, c->format_options_str, "=", ":", 0); + if (ret < 0) + return ret; + } + + if (os->segment_type == SEGMENT_TYPE_MP4) { if (c->streaming) - av_dict_set(&opts, "movflags", "frag_every_frame+dash+delay_moov", 0); - else - av_dict_set(&opts, "movflags", "frag_custom+dash+delay_moov", 0); + // frag_every_frame : Allows lower latency streaming + // skip_sidx : Reduce bitrate overhead + // skip_trailer : Avoids growing memory usage with time + av_dict_set(&opts, "movflags", "frag_every_frame+dash+delay_moov+skip_sidx+skip_trailer", 0); + else { + if (c->global_sidx) + av_dict_set(&opts, "movflags", "frag_custom+dash+delay_moov+global_sidx+skip_trailer", 0); + else + av_dict_set(&opts, "movflags", "frag_custom+dash+delay_moov+skip_trailer", 0); + } } else { - av_dict_set_int(&opts, "cluster_time_limit", c->min_seg_duration / 1000, 0); + av_dict_set_int(&opts, "cluster_time_limit", c->seg_duration / 1000, 0); av_dict_set_int(&opts, "cluster_size_limit", 5 * 1024 * 1024, 0); // set a large cluster size limit av_dict_set_int(&opts, "dash", 1, 0); av_dict_set_int(&opts, "dash_track_number", i + 1, 0); av_dict_set_int(&opts, "live", 1, 0); } - if ((ret = avformat_init_output(ctx, &opts)) < 0) + ret = avformat_init_output(ctx, &opts); + av_dict_free(&opts); + if (ret < 0) return ret; os->ctx_inited = 1; avio_flush(ctx->pb); - av_dict_free(&opts); av_log(s, AV_LOG_VERBOSE, "Representation %d init segment will be written to: %s\n", i, filename); @@ -1006,17 +1337,24 @@ static int dash_init(AVFormatContext *s) c->has_video = 1; } - set_codec_str(s, st->codecpar, os->codec_str, sizeof(os->codec_str)); + set_codec_str(s, st->codecpar, &st->avg_frame_rate, os->codec_str, + sizeof(os->codec_str)); os->first_pts = AV_NOPTS_VALUE; os->max_pts = AV_NOPTS_VALUE; os->last_dts = AV_NOPTS_VALUE; os->segment_index = 1; + + if (s->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) + c->nr_of_streams_to_flush++; } - if (!c->has_video && c->min_seg_duration <= 0) { - av_log(s, AV_LOG_WARNING, "no video stream and no min seg duration set\n"); + if (!c->has_video && c->seg_duration <= 0) { + av_log(s, AV_LOG_WARNING, "no video stream and no seg duration set\n"); return AVERROR(EINVAL); } + + c->nr_of_streams_flushed = 0; + return 0; } @@ -1028,23 +1366,21 @@ static int dash_write_header(AVFormatContext *s) OutputStream *os = &c->streams[i]; if ((ret = avformat_write_header(os->ctx, NULL)) < 0) return ret; + // Flush init segment // Only for WebM segment, since for mp4 delay_moov is set and // the init segment is thus flushed after the first packets. - if (strcmp(os->format_name, "mp4") && + if (os->segment_type == SEGMENT_TYPE_WEBM && (ret = flush_init_segment(s, os)) < 0) return ret; } - ret = write_manifest(s, 0); - if (!ret) - av_log(s, AV_LOG_VERBOSE, "Manifest written to: %s\n", s->url); return ret; } static int add_segment(OutputStream *os, const char *file, - int64_t time, int duration, + int64_t time, int64_t duration, int64_t start_pos, int64_t range_length, - int64_t index_length) + int64_t index_length, int next_exp_index) { int err; Segment *seg; @@ -1072,6 +1408,12 @@ static int add_segment(OutputStream *os, const char *file, seg->index_length = index_length; os->segments[os->nb_segments++] = seg; os->segment_index++; + //correcting the segment index if it has fallen behind the expected value + if (os->segment_index < next_exp_index) { + av_log(NULL, AV_LOG_WARNING, "Correcting the segment index after file %s: current=%d corrected=%d\n", + file, os->segment_index, next_exp_index); + os->segment_index = next_exp_index; + } return 0; } @@ -1109,24 +1451,26 @@ static void find_index_range(AVFormatContext *s, const char *full_path, } static int update_stream_extradata(AVFormatContext *s, OutputStream *os, - AVCodecParameters *par) + AVPacket *pkt, AVRational *frame_rate) { + AVCodecParameters *par = os->ctx->streams[0]->codecpar; uint8_t *extradata; + int ret, extradata_size; - if (os->ctx->streams[0]->codecpar->extradata_size || !par->extradata_size) + if (par->extradata_size) return 0; - extradata = av_malloc(par->extradata_size); + extradata = av_packet_get_side_data(pkt, AV_PKT_DATA_NEW_EXTRADATA, &extradata_size); + if (!extradata_size) + return 0; - if (!extradata) - return AVERROR(ENOMEM); + ret = ff_alloc_extradata(par, extradata_size); + if (ret < 0) + return ret; - memcpy(extradata, par->extradata, par->extradata_size); + memcpy(par->extradata, extradata, extradata_size); - os->ctx->streams[0]->codecpar->extradata = extradata; - os->ctx->streams[0]->codecpar->extradata_size = par->extradata_size; - - set_codec_str(s, par, os->codec_str, sizeof(os->codec_str)); + set_codec_str(s, par, frame_rate, os->codec_str, sizeof(os->codec_str)); return 0; } @@ -1147,12 +1491,58 @@ static void dashenc_delete_file(AVFormatContext *s, char *filename) { } av_dict_free(&http_opts); - dashenc_io_close(s, &out, filename); - } else if (unlink(filename) < 0) { - av_log(s, AV_LOG_ERROR, "failed to delete %s: %s\n", filename, strerror(errno)); + ff_format_io_close(s, &out); + } else { + int res = avpriv_io_delete(filename); + if (res < 0) { + char errbuf[AV_ERROR_MAX_STRING_SIZE]; + av_strerror(res, errbuf, sizeof(errbuf)); + av_log(s, (res == AVERROR(ENOENT) ? AV_LOG_WARNING : AV_LOG_ERROR), "failed to delete %s: %s\n", filename, errbuf); + } } } +static int dashenc_delete_segment_file(AVFormatContext *s, const char* file) +{ + DASHContext *c = s->priv_data; + size_t dirname_len, file_len; + char filename[1024]; + + dirname_len = strlen(c->dirname); + if (dirname_len >= sizeof(filename)) { + av_log(s, AV_LOG_WARNING, "Cannot delete segments as the directory path is too long: %"PRIu64" characters: %s\n", + (uint64_t)dirname_len, c->dirname); + return AVERROR(ENAMETOOLONG); + } + + memcpy(filename, c->dirname, dirname_len); + + file_len = strlen(file); + if ((dirname_len + file_len) >= sizeof(filename)) { + av_log(s, AV_LOG_WARNING, "Cannot delete segments as the path is too long: %"PRIu64" characters: %s%s\n", + (uint64_t)(dirname_len + file_len), c->dirname, file); + return AVERROR(ENAMETOOLONG); + } + + memcpy(filename + dirname_len, file, file_len + 1); // include the terminating zero + dashenc_delete_file(s, filename); + + return 0; +} + +static inline void dashenc_delete_media_segments(AVFormatContext *s, OutputStream *os, int remove_count) +{ + for (int i = 0; i < remove_count; ++i) { + dashenc_delete_segment_file(s, os->segments[i]->file); + + // Delete the segment regardless of whether the file was successfully deleted + av_free(os->segments[i]); + } + + os->nb_segments -= remove_count; + memmove(os->segments, os->segments + remove_count, os->nb_segments * sizeof(*os->segments)); +} + static int dash_flush(AVFormatContext *s, int final, int stream) { DASHContext *c = s->priv_data; @@ -1161,10 +1551,22 @@ static int dash_flush(AVFormatContext *s, int final, int stream) const char *proto = avio_find_protocol_name(s->url); int use_rename = proto && !strcmp(proto, "file"); - int cur_flush_segment_index = 0; - if (stream >= 0) + int cur_flush_segment_index = 0, next_exp_index = -1; + if (stream >= 0) { cur_flush_segment_index = c->streams[stream].segment_index; + //finding the next segment's expected index, based on the current pts value + if (c->use_template && !c->use_timeline && c->index_correction && + c->streams[stream].last_pts != AV_NOPTS_VALUE && + c->streams[stream].first_pts != AV_NOPTS_VALUE) { + int64_t pts_diff = av_rescale_q(c->streams[stream].last_pts - + c->streams[stream].first_pts, + s->streams[stream]->time_base, + AV_TIME_BASE_Q); + next_exp_index = (pts_diff / c->seg_duration) + 1; + } + } + for (i = 0; i < s->nb_streams; i++) { OutputStream *os = &c->streams[i]; AVStream *st = s->streams[i]; @@ -1186,13 +1588,13 @@ static int dash_flush(AVFormatContext *s, int final, int stream) } if (!c->single_file) { - if (!strcmp(os->format_name, "mp4") && !os->written_len) + if (os->segment_type == SEGMENT_TYPE_MP4 && !os->written_len) write_styp(os->ctx->pb); } else { snprintf(os->full_path, sizeof(os->full_path), "%s%s", c->dirname, os->initfile); } - ret = flush_dynbuf(os, &range_length); + ret = flush_dynbuf(c, os, &range_length); if (ret < 0) break; os->packets_written = 0; @@ -1209,45 +1611,69 @@ static int dash_flush(AVFormatContext *s, int final, int stream) } } + if (!os->muxer_overhead) + os->muxer_overhead = ((int64_t) (range_length - os->total_pkt_size) * + 8 * AV_TIME_BASE) / + av_rescale_q(os->max_pts - os->start_pts, + st->time_base, AV_TIME_BASE_Q); + os->total_pkt_size = 0; + if (!os->bit_rate) { // calculate average bitrate of first segment int64_t bitrate = (int64_t) range_length * 8 * AV_TIME_BASE / av_rescale_q(os->max_pts - os->start_pts, st->time_base, AV_TIME_BASE_Q); - if (bitrate >= 0) { + if (bitrate >= 0) os->bit_rate = bitrate; - snprintf(os->bandwidth_str, sizeof(os->bandwidth_str), - " bandwidth=\"%d\"", os->bit_rate); - } } - add_segment(os, os->filename, os->start_pts, os->max_pts - os->start_pts, os->pos, range_length, index_length); + add_segment(os, os->filename, os->start_pts, os->max_pts - os->start_pts, os->pos, range_length, index_length, next_exp_index); av_log(s, AV_LOG_VERBOSE, "Representation %d media segment %d written to: %s\n", i, os->segment_index, os->full_path); os->pos += range_length; } - if (c->window_size || (final && c->remove_at_exit)) { + if (c->window_size) { for (i = 0; i < s->nb_streams; i++) { OutputStream *os = &c->streams[i]; - int j; - int remove = os->nb_segments - c->window_size - c->extra_window_size; - if (final && c->remove_at_exit) - remove = os->nb_segments; - if (remove > 0) { - for (j = 0; j < remove; j++) { - char filename[1024]; - snprintf(filename, sizeof(filename), "%s%s", c->dirname, os->segments[j]->file); - dashenc_delete_file(s, filename); - av_free(os->segments[j]); - } - os->nb_segments -= remove; - memmove(os->segments, os->segments + remove, os->nb_segments * sizeof(*os->segments)); - } + int remove_count = os->nb_segments - c->window_size - c->extra_window_size; + if (remove_count > 0) + dashenc_delete_media_segments(s, os, remove_count); } } - if (ret >= 0) + if (final) { + for (i = 0; i < s->nb_streams; i++) { + OutputStream *os = &c->streams[i]; + if (os->ctx && os->ctx_inited) { + int64_t file_size = avio_tell(os->ctx->pb); + av_write_trailer(os->ctx); + if (c->global_sidx) { + int j, start_index, start_number; + int64_t sidx_size = avio_tell(os->ctx->pb) - file_size; + get_start_index_number(os, c, &start_index, &start_number); + if (start_index >= os->nb_segments || + os->segment_type != SEGMENT_TYPE_MP4) + continue; + os->init_range_length += sidx_size; + for (j = start_index; j < os->nb_segments; j++) { + Segment *seg = os->segments[j]; + seg->start_pos += sidx_size; + } + } + + } + } + } + if (ret >= 0) { + if (c->has_video && !final) { + c->nr_of_streams_flushed++; + if (c->nr_of_streams_flushed != c->nr_of_streams_to_flush) + return ret; + + c->nr_of_streams_flushed = 0; + } ret = write_manifest(s, final); + } return ret; } @@ -1256,9 +1682,10 @@ static int dash_write_packet(AVFormatContext *s, AVPacket *pkt) DASHContext *c = s->priv_data; AVStream *st = s->streams[pkt->stream_index]; OutputStream *os = &c->streams[pkt->stream_index]; + int64_t seg_end_duration, elapsed_duration; int ret; - ret = update_stream_extradata(s, os, st->codecpar); + ret = update_stream_extradata(s, os, pkt, &st->avg_frame_rate); if (ret < 0) return ret; @@ -1282,11 +1709,34 @@ static int dash_write_packet(AVFormatContext *s, AVPacket *pkt) if (os->first_pts == AV_NOPTS_VALUE) os->first_pts = pkt->pts; + os->last_pts = pkt->pts; + + if (!c->availability_start_time[0]) { + int64_t start_time_us = av_gettime(); + c->start_time_s = start_time_us / 1000000; + format_date_now(c->availability_start_time, + sizeof(c->availability_start_time)); + } + + if (!os->availability_time_offset && pkt->duration) { + int64_t frame_duration = av_rescale_q(pkt->duration, st->time_base, + AV_TIME_BASE_Q); + os->availability_time_offset = ((double) c->seg_duration - + frame_duration) / AV_TIME_BASE; + } + + if (c->use_template && !c->use_timeline) { + elapsed_duration = pkt->pts - os->first_pts; + seg_end_duration = (int64_t) os->segment_index * c->seg_duration; + } else { + elapsed_duration = pkt->pts - os->start_pts; + seg_end_duration = c->seg_duration; + } if ((!c->has_video || st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) && pkt->flags & AV_PKT_FLAG_KEY && os->packets_written && - av_compare_ts(pkt->pts - os->start_pts, st->time_base, - c->min_seg_duration, AV_TIME_BASE_Q) >= 0) { + av_compare_ts(elapsed_duration, st->time_base, + seg_end_duration, AV_TIME_BASE_Q) >= 0) { int64_t prev_duration = c->last_duration; c->last_duration = av_rescale_q(pkt->pts - os->start_pts, @@ -1323,6 +1773,7 @@ static int dash_write_packet(AVFormatContext *s, AVPacket *pkt) else os->max_pts = FFMAX(os->max_pts, pkt->pts + pkt->duration); os->packets_written++; + os->total_pkt_size += pkt->size; if ((ret = ff_write_chained(os->ctx, 0, pkt, s, 0)) < 0) return ret; @@ -1336,7 +1787,7 @@ static int dash_write_packet(AVFormatContext *s, AVPacket *pkt) int use_rename = proto && !strcmp(proto, "file"); os->filename[0] = os->full_path[0] = os->temp_path[0] = '\0'; ff_dash_fill_tmpl_params(os->filename, sizeof(os->filename), - c->media_seg_name, pkt->stream_index, + os->media_seg_name, pkt->stream_index, os->segment_index, os->bit_rate, os->start_pts); snprintf(os->full_path, sizeof(os->full_path), "%s%s", c->dirname, os->filename); @@ -1344,22 +1795,29 @@ static int dash_write_packet(AVFormatContext *s, AVPacket *pkt) use_rename ? "%s.tmp" : "%s", os->full_path); set_http_options(&opts, c); ret = dashenc_io_open(s, &os->out, os->temp_path, &opts); - if (ret < 0) - return ret; av_dict_free(&opts); + if (ret < 0) { + return handle_io_open_error(s, ret, os->temp_path); + } + if (c->lhls) { + char *prefetch_url = use_rename ? NULL : os->filename; + write_hls_media_playlist(os, s, pkt->stream_index, 0, prefetch_url); + } } //write out the data immediately in streaming mode - if (c->streaming && !strcmp(os->format_name, "mp4")) { + if (c->streaming && os->segment_type == SEGMENT_TYPE_MP4) { int len = 0; uint8_t *buf = NULL; if (!os->written_len) write_styp(os->ctx->pb); avio_flush(os->ctx->pb); len = avio_get_dyn_buf (os->ctx->pb, &buf); - avio_write(os->out, buf + os->written_len, len - os->written_len); + if (os->out) { + avio_write(os->out, buf + os->written_len, len - os->written_len); + avio_flush(os->out); + } os->written_len = len; - avio_flush(os->out); } return ret; @@ -1368,6 +1826,7 @@ static int dash_write_packet(AVFormatContext *s, AVPacket *pkt) static int dash_write_trailer(AVFormatContext *s) { DASHContext *c = s->priv_data; + int i; if (s->nb_streams > 0) { OutputStream *os = &c->streams[0]; @@ -1384,14 +1843,23 @@ static int dash_write_trailer(AVFormatContext *s) dash_flush(s, 1, -1); if (c->remove_at_exit) { - char filename[1024]; - int i; - for (i = 0; i < s->nb_streams; i++) { + for (i = 0; i < s->nb_streams; ++i) { OutputStream *os = &c->streams[i]; - snprintf(filename, sizeof(filename), "%s%s", c->dirname, os->initfile); - dashenc_delete_file(s, filename); + dashenc_delete_media_segments(s, os, os->nb_segments); + dashenc_delete_segment_file(s, os->initfile); + if (c->hls_playlist && os->segment_type == SEGMENT_TYPE_MP4) { + char filename[1024]; + get_hls_playlist_name(filename, sizeof(filename), c->dirname, i); + dashenc_delete_file(s, filename); + } } dashenc_delete_file(s, s->url); + + if (c->hls_playlist && c->master_playlist_created) { + char filename[1024]; + snprintf(filename, sizeof(filename), "%smaster.m3u8", c->dirname); + dashenc_delete_file(s, filename); + } } return 0; @@ -1426,14 +1894,17 @@ static const AVOption options[] = { { "adaptation_sets", "Adaptation sets. Syntax: id=0,streams=0,1,2 id=1,streams=3,4 and so on", OFFSET(adaptation_sets), AV_OPT_TYPE_STRING, { 0 }, 0, 0, AV_OPT_FLAG_ENCODING_PARAM }, { "window_size", "number of segments kept in the manifest", OFFSET(window_size), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, E }, { "extra_window_size", "number of segments kept outside of the manifest before removing from disk", OFFSET(extra_window_size), AV_OPT_TYPE_INT, { .i64 = 5 }, 0, INT_MAX, E }, - { "min_seg_duration", "minimum segment duration (in microseconds)", OFFSET(min_seg_duration), AV_OPT_TYPE_INT, { .i64 = 5000000 }, 0, INT_MAX, E }, +#if FF_API_DASH_MIN_SEG_DURATION + { "min_seg_duration", "minimum segment duration (in microseconds) (will be deprecated)", OFFSET(min_seg_duration), AV_OPT_TYPE_INT, { .i64 = 5000000 }, 0, INT_MAX, E }, +#endif + { "seg_duration", "segment duration (in seconds, fractional value can be set)", OFFSET(seg_duration), AV_OPT_TYPE_DURATION, { .i64 = 5000000 }, 0, INT_MAX, E }, { "remove_at_exit", "remove all segments when finished", OFFSET(remove_at_exit), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, E }, { "use_template", "Use SegmentTemplate instead of SegmentList", OFFSET(use_template), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, E }, { "use_timeline", "Use SegmentTimeline in SegmentTemplate", OFFSET(use_timeline), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, E }, { "single_file", "Store all segments in one file, accessed using byte ranges", OFFSET(single_file), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, E }, { "single_file_name", "DASH-templated name to be used for baseURL. Implies storing all segments in one file, accessed using byte ranges", OFFSET(single_file_name), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, E }, - { "init_seg_name", "DASH-templated name to used for the initialization segment", OFFSET(init_seg_name), AV_OPT_TYPE_STRING, {.str = "init-stream$RepresentationID$.m4s"}, 0, 0, E }, - { "media_seg_name", "DASH-templated name to used for the media segments", OFFSET(media_seg_name), AV_OPT_TYPE_STRING, {.str = "chunk-stream$RepresentationID$-$Number%05d$.m4s"}, 0, 0, E }, + { "init_seg_name", "DASH-templated name to used for the initialization segment", OFFSET(init_seg_name), AV_OPT_TYPE_STRING, {.str = "init-stream$RepresentationID$.$ext$"}, 0, 0, E }, + { "media_seg_name", "DASH-templated name to used for the media segments", OFFSET(media_seg_name), AV_OPT_TYPE_STRING, {.str = "chunk-stream$RepresentationID$-$Number%05d$.$ext$"}, 0, 0, E }, { "utc_timing_url", "URL of the page that will return the UTC timestamp in ISO format", OFFSET(utc_timing_url), AV_OPT_TYPE_STRING, { 0 }, 0, 0, E }, { "method", "set the HTTP method", OFFSET(method), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E }, { "http_user_agent", "override User-Agent field in HTTP header", OFFSET(user_agent), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E}, @@ -1441,6 +1912,16 @@ static const AVOption options[] = { { "hls_playlist", "Generate HLS playlist files(master.m3u8, media_%d.m3u8)", OFFSET(hls_playlist), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, E }, { "streaming", "Enable/Disable streaming mode of output. Each frame will be moof fragment", OFFSET(streaming), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, E }, { "timeout", "set timeout for socket I/O operations", OFFSET(timeout), AV_OPT_TYPE_DURATION, { .i64 = -1 }, -1, INT_MAX, .flags = E }, + { "index_correction", "Enable/Disable segment index correction logic", OFFSET(index_correction), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, E }, + { "format_options","set list of options for the container format (mp4/webm) used for dash", OFFSET(format_options_str), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E}, + { "global_sidx", "Write global SIDX atom. Applicable only for single file, mp4 output, non-streaming mode", OFFSET(global_sidx), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, E }, + { "dash_segment_type", "set dash segment files type", OFFSET(segment_type_option), AV_OPT_TYPE_INT, {.i64 = SEGMENT_TYPE_AUTO }, 0, SEGMENT_TYPE_NB - 1, E, "segment_type"}, + { "auto", "select segment file format based on codec", 0, AV_OPT_TYPE_CONST, {.i64 = SEGMENT_TYPE_AUTO }, 0, UINT_MAX, E, "segment_type"}, + { "mp4", "make segment file in ISOBMFF format", 0, AV_OPT_TYPE_CONST, {.i64 = SEGMENT_TYPE_MP4 }, 0, UINT_MAX, E, "segment_type"}, + { "webm", "make segment file in WebM format", 0, AV_OPT_TYPE_CONST, {.i64 = SEGMENT_TYPE_WEBM }, 0, UINT_MAX, E, "segment_type"}, + { "ignore_io_errors", "Ignore IO errors during open and write. Useful for long-duration runs with network output", OFFSET(ignore_io_errors), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, E }, + { "lhls", "Enable Low-latency HLS(Experimental). Adds #EXT-X-PREFETCH tag with current segment's URI", OFFSET(lhls), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, E }, + { "master_m3u8_publish_rate", "Publish master playlist every after this many segment intervals", OFFSET(master_publish_rate), AV_OPT_TYPE_INT, {.i64 = 0}, 0, UINT_MAX, E}, { NULL }, }; diff --git a/libavformat/davs2.c b/libavformat/davs2.c new file mode 100644 index 000000000..59f41fd49 --- /dev/null +++ b/libavformat/davs2.c @@ -0,0 +1,71 @@ +/* + * AVS2 video stream probe. + * + * Copyright (C) 2018 Huiwen Ren, + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "avformat.h" +#include "rawdec.h" +#include "libavcodec/internal.h" +#include "libavutil/intreadwrite.h" + +#define ISSQH(x) ((x) == 0xB0 ) +#define ISEND(x) ((x) == 0xB1 ) +#define ISPIC(x) ((x) == 0xB3 || (x) == 0xB6) +#define ISUNIT(x) ( ISSQH(x) || ISEND(x) || (x) == 0xB2 || ISPIC(x) || (x) == 0xB5 || (x) == 0xB7 ) +#define ISAVS2(x) ((x) == 0x20 || (x) == 0x22 || (x) == 0x30 || (x) == 0x32 ) + +static int avs2_probe(const AVProbeData *p) +{ + uint32_t code= -1, hds=0, pic=0, seq=0; + uint8_t state=0; + const uint8_t *ptr = p->buf, *end = p->buf + p->buf_size, *sqb=0; + if (AV_RB32(p->buf) != 0x1B0){ + return 0; + } + + while (ptr < end) { + ptr = avpriv_find_start_code(ptr, end, &code); + state = code & 0xFF; + if ((code & 0xffffff00) == 0x100) { + if (ISUNIT(state)) { + if (sqb && !hds) { + hds = ptr - sqb; + } + if (ISSQH(state)) { + if (!ISAVS2(*ptr)) + return 0; + sqb = ptr; + seq++; + } else if (ISPIC(state)) { + pic++; + } else if (ISEND(state)) { + break; + } + } + } + } + if (seq && hds >= 21 && pic){ + return AVPROBE_SCORE_EXTENSION + 2; // more than cavs + } + + return 0; +} + +FF_DEF_RAWVIDEO_DEMUXER(avs2, "raw AVS2-P2/IEEE1857.4", avs2_probe, "avs,avs2", AV_CODEC_ID_AVS2) diff --git a/libavformat/dcstr.c b/libavformat/dcstr.c index 6035dd433..9041a8653 100644 --- a/libavformat/dcstr.c +++ b/libavformat/dcstr.c @@ -22,7 +22,7 @@ #include "avformat.h" #include "internal.h" -static int dcstr_probe(AVProbeData *p) +static int dcstr_probe(const AVProbeData *p) { if (p->buf_size < 224 || memcmp(p->buf + 213, "Sega Stream", 11)) return 0; diff --git a/libavformat/dfa.c b/libavformat/dfa.c index 9858ee794..a5ecfd9b1 100644 --- a/libavformat/dfa.c +++ b/libavformat/dfa.c @@ -25,7 +25,7 @@ #include "avformat.h" #include "internal.h" -static int dfa_probe(AVProbeData *p) +static int dfa_probe(const AVProbeData *p) { if (p->buf_size < 4 || AV_RL32(p->buf) != MKTAG('D', 'F', 'I', 'A')) return 0; diff --git a/libavformat/dhav.c b/libavformat/dhav.c new file mode 100644 index 000000000..e6f61eeb6 --- /dev/null +++ b/libavformat/dhav.c @@ -0,0 +1,384 @@ +/* + * DHAV demuxer + * + * Copyright (c) 2018 Paul B Mahol + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/parseutils.h" +#include "avio_internal.h" +#include "avformat.h" +#include "internal.h" + +typedef struct DHAVContext { + unsigned type; + unsigned subtype; + unsigned channel; + unsigned frame_subnumber; + unsigned frame_number; + unsigned date; + unsigned timestamp; + int width, height; + int video_codec; + int frame_rate; + int audio_channels; + int audio_codec; + int sample_rate; + + int video_stream_index; + int audio_stream_index; +} DHAVContext; + +typedef struct DHAVStream { + int64_t last_timestamp; + int64_t pts; +} DHAVStream; + +static int dhav_probe(const AVProbeData *p) +{ + if (!memcmp(p->buf, "DAHUA", 5)) + return AVPROBE_SCORE_MAX; + + if (memcmp(p->buf, "DHAV", 4)) + return 0; + + if (p->buf[4] == 0xf0 || + p->buf[4] == 0xf1 || + p->buf[4] == 0xfc || + p->buf[4] == 0xfd) + return AVPROBE_SCORE_MAX; + return 0; +} + +static int dhav_read_header(AVFormatContext *s) +{ + DHAVContext *dhav = s->priv_data; + uint8_t signature[5]; + + ffio_ensure_seekback(s->pb, 5); + avio_read(s->pb, signature, sizeof(signature)); + if (!memcmp(signature, "DAHUA", 5)) + avio_skip(s->pb, 0x400 - 5); + else + avio_seek(s->pb, -5, SEEK_CUR); + + s->ctx_flags |= AVFMTCTX_NOHEADER; + dhav->video_stream_index = -1; + dhav->audio_stream_index = -1; + + return 0; +} + +static int64_t get_pts(AVFormatContext *s, DHAVStream *st) +{ + DHAVContext *dhav = s->priv_data; + /* + int year, month, day, hour, min, sec; + struct tm timeinfo; + + sec = dhav->date & 0x3F; + min = (dhav->date >> 6) & 0x3F; + hour = (dhav->date >> 12) & 0x1F; + day = (dhav->date >> 17) & 0x1F; + month = (dhav->date >> 22) & 0x0F; + year = ((dhav->date >> 26) & 0x3F) + 2000; + + timeinfo.tm_year = year - 1900; + timeinfo.tm_mon = month - 1; + timeinfo.tm_mday = day; + timeinfo.tm_hour = hour; + timeinfo.tm_min = min; + timeinfo.tm_sec = sec;*/ + + if (st->last_timestamp == AV_NOPTS_VALUE) { + st->last_timestamp = dhav->timestamp; + } + + if (st->last_timestamp <= dhav->timestamp) { + st->pts += dhav->timestamp - st->last_timestamp; + } else { + st->pts += 65535 + dhav->timestamp - st->last_timestamp; + } + + st->last_timestamp = dhav->timestamp; + + return st->pts; +} + +static const uint32_t sample_rates[] = { + 8000, 4000, 8000, 11025, 16000, + 20000, 22050, 32000, 44100, 48000, + 96000, 192000, 64000, +}; + +static int parse_ext(AVFormatContext *s, int length) +{ + DHAVContext *dhav = s->priv_data; + int index; + + while (length > 0) { + int type = avio_r8(s->pb); + + switch (type) { + case 0x80: + avio_skip(s->pb, 1); + dhav->width = 8 * avio_r8(s->pb); + dhav->height = 8 * avio_r8(s->pb); + length -= 4; + break; + case 0x81: + avio_skip(s->pb, 1); + dhav->video_codec = avio_r8(s->pb); + dhav->frame_rate = avio_r8(s->pb); + length -= 4; + break; + case 0x82: + avio_skip(s->pb, 3); + dhav->width = avio_rl16(s->pb); + dhav->height = avio_rl16(s->pb); + length -= 8; + break; + case 0x83: + dhav->audio_channels = avio_r8(s->pb); + dhav->audio_codec = avio_r8(s->pb); + index = avio_r8(s->pb); + if (index < FF_ARRAY_ELEMS(sample_rates)) { + dhav->sample_rate = sample_rates[index]; + } else { + dhav->sample_rate = 8000; + } + length -= 4; + break; + case 0x88: + avio_skip(s->pb, 7); + length -= 8; + break; + case 0x8c: + avio_skip(s->pb, 1); + dhav->audio_channels = avio_r8(s->pb); + dhav->audio_codec = avio_r8(s->pb); + index = avio_r8(s->pb); + if (index < FF_ARRAY_ELEMS(sample_rates)) { + dhav->sample_rate = sample_rates[index]; + } else { + dhav->sample_rate = 8000; + } + avio_skip(s->pb, 3); + length -= 8; + break; + case 0x91: + case 0x92: + case 0x93: + case 0x95: + case 0x9a: + case 0x9b: // sample aspect ratio + case 0xb3: + avio_skip(s->pb, 7); + length -= 8; + break; + case 0x84: + case 0x85: + case 0x8b: + case 0x94: + case 0x96: + case 0xa0: + case 0xb2: + case 0xb4: + avio_skip(s->pb, 3); + length -= 4; + break; + default: + av_log(s, AV_LOG_INFO, "Unknown type: %X, skipping rest of header.\n", type); + avio_skip(s->pb, length - 1); + length = 0; + } + } + + return 0; +} + +static int read_chunk(AVFormatContext *s) +{ + DHAVContext *dhav = s->priv_data; + unsigned frame_length, ext_length; + int64_t start, end; + int ret; + + start = avio_tell(s->pb); + + if (avio_feof(s->pb)) + return AVERROR_EOF; + + if (avio_rl32(s->pb) != MKTAG('D','H','A','V')) + return AVERROR_INVALIDDATA; + + dhav->type = avio_r8(s->pb); + dhav->subtype = avio_r8(s->pb); + dhav->channel = avio_r8(s->pb); + dhav->frame_subnumber = avio_r8(s->pb); + dhav->frame_number = avio_rl32(s->pb); + frame_length = avio_rl32(s->pb); + + if (frame_length < 24) + return AVERROR_INVALIDDATA; + if (dhav->type == 0xf1) { + avio_skip(s->pb, frame_length - 16); + return 0; + } + + dhav->date = avio_rl32(s->pb); + dhav->timestamp = avio_rl16(s->pb); + ext_length = avio_r8(s->pb); + avio_skip(s->pb, 1); // checksum + + ret = parse_ext(s, ext_length); + if (ret < 0) + return ret; + + end = avio_tell(s->pb); + + return frame_length - 8 - (end - start); +} + +static int dhav_read_packet(AVFormatContext *s, AVPacket *pkt) +{ + DHAVContext *dhav = s->priv_data; + int64_t start; + int ret; + + start = avio_tell(s->pb); + + while ((ret = read_chunk(s)) == 0) + ; + + if (ret < 0) + return ret; + + if (dhav->type == 0xfd && dhav->video_stream_index == -1) { + AVStream *st = avformat_new_stream(s, NULL); + DHAVStream *dst; + + if (!st) + return AVERROR(ENOMEM); + + st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO; + switch (dhav->video_codec) { + case 0x1: st->codecpar->codec_id = AV_CODEC_ID_MPEG4; break; + case 0x3: st->codecpar->codec_id = AV_CODEC_ID_MJPEG; break; + case 0x2: + case 0x4: + case 0x8: st->codecpar->codec_id = AV_CODEC_ID_H264; break; + case 0xc: st->codecpar->codec_id = AV_CODEC_ID_HEVC; break; + default: avpriv_request_sample(s, "Unknown video codec %X\n", dhav->video_codec); + } + st->codecpar->width = dhav->width; + st->codecpar->height = dhav->height; + st->avg_frame_rate.num = dhav->frame_rate; + st->avg_frame_rate.den = 1; + st->priv_data = dst = av_mallocz(sizeof(DHAVStream)); + if (!st->priv_data) + return AVERROR(ENOMEM); + dst->last_timestamp = AV_NOPTS_VALUE; + dhav->video_stream_index = st->index; + + avpriv_set_pts_info(st, 64, 1, 1000); + } else if (dhav->type == 0xf0 && dhav->audio_stream_index == -1) { + AVStream *st = avformat_new_stream(s, NULL); + DHAVStream *dst; + + if (!st) + return AVERROR(ENOMEM); + + st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO; + switch (dhav->audio_codec) { + case 0x07: st->codecpar->codec_id = AV_CODEC_ID_PCM_S8; break; + case 0x0c: st->codecpar->codec_id = AV_CODEC_ID_PCM_S16LE; break; + case 0x10: st->codecpar->codec_id = AV_CODEC_ID_PCM_S16LE; break; + case 0x0a: st->codecpar->codec_id = AV_CODEC_ID_PCM_MULAW; break; + case 0x16: st->codecpar->codec_id = AV_CODEC_ID_PCM_MULAW; break; + case 0x0e: st->codecpar->codec_id = AV_CODEC_ID_PCM_ALAW; break; + case 0x1a: st->codecpar->codec_id = AV_CODEC_ID_AAC; break; + case 0x1f: st->codecpar->codec_id = AV_CODEC_ID_MP2; break; + case 0x21: st->codecpar->codec_id = AV_CODEC_ID_MP3; break; + case 0x0d: st->codecpar->codec_id = AV_CODEC_ID_ADPCM_MS; break; + default: avpriv_request_sample(s, "Unknown audio codec %X\n", dhav->audio_codec); + } + st->codecpar->channels = dhav->audio_channels; + st->codecpar->sample_rate = dhav->sample_rate; + st->priv_data = dst = av_mallocz(sizeof(DHAVStream)); + if (!st->priv_data) + return AVERROR(ENOMEM); + dst->last_timestamp = AV_NOPTS_VALUE; + dhav->audio_stream_index = st->index; + + avpriv_set_pts_info(st, 64, 1, 1000); + } + + ret = av_get_packet(s->pb, pkt, ret); + if (ret < 0) + return ret; + pkt->stream_index = dhav->type == 0xf0 ? dhav->audio_stream_index : dhav->video_stream_index; + if (dhav->type != 0xfc) + pkt->flags |= AV_PKT_FLAG_KEY; + if (pkt->stream_index >= 0) + pkt->pts = get_pts(s, s->streams[pkt->stream_index]->priv_data); + pkt->duration = 1; + pkt->pos = start; + if (avio_rl32(s->pb) != MKTAG('d','h','a','v')) + return AVERROR_INVALIDDATA; + avio_skip(s->pb, 4); + + return ret; +} + +static int dhav_read_seek(AVFormatContext *s, int stream_index, + int64_t timestamp, int flags) +{ + AVStream *st = s->streams[stream_index]; + int index = av_index_search_timestamp(st, timestamp, flags); + int64_t pts; + + if (index < 0) + return -1; + if (avio_seek(s->pb, st->index_entries[index].pos, SEEK_SET) < 0) + return -1; + + pts = st->index_entries[index].timestamp; + + for (int n = 0; n < s->nb_streams; n++) { + AVStream *st = s->streams[n]; + DHAVStream *dst = st->priv_data; + + dst->pts = pts; + dst->last_timestamp = AV_NOPTS_VALUE; + } + + return 0; +} + +AVInputFormat ff_dhav_demuxer = { + .name = "dhav", + .long_name = NULL_IF_CONFIG_SMALL("Video DAV"), + .priv_data_size = sizeof(DHAVContext), + .read_probe = dhav_probe, + .read_header = dhav_read_header, + .read_packet = dhav_read_packet, + .read_seek = dhav_read_seek, + .extensions = "dav", + .flags = AVFMT_GENERIC_INDEX | AVFMT_NO_BYTE_SEEK, +}; diff --git a/libavformat/diracdec.c b/libavformat/diracdec.c index e061ba5e8..d9294a122 100644 --- a/libavformat/diracdec.c +++ b/libavformat/diracdec.c @@ -23,7 +23,7 @@ #include "avformat.h" #include "rawdec.h" -static int dirac_probe(AVProbeData *p) +static int dirac_probe(const AVProbeData *p) { unsigned size; if (AV_RL32(p->buf) != MKTAG('B', 'B', 'C', 'D')) diff --git a/libavformat/dnxhddec.c b/libavformat/dnxhddec.c index 0ad51b597..2d1d9fb49 100644 --- a/libavformat/dnxhddec.c +++ b/libavformat/dnxhddec.c @@ -25,7 +25,7 @@ #include "rawdec.h" #include "libavcodec/dnxhddata.h" -static int dnxhd_probe(AVProbeData *p) +static int dnxhd_probe(const AVProbeData *p) { int w, h, compression_id; if (p->buf_size < 0x2c) diff --git a/libavformat/dsfdec.c b/libavformat/dsfdec.c index 5e06fd63a..afb24634b 100644 --- a/libavformat/dsfdec.c +++ b/libavformat/dsfdec.c @@ -30,7 +30,7 @@ typedef struct { uint64_t data_size; } DSFContext; -static int dsf_probe(AVProbeData *p) +static int dsf_probe(const AVProbeData *p) { if (p->buf_size < 12 || memcmp(p->buf, "DSD ", 4) || AV_RL64(p->buf + 4) != 28) return 0; diff --git a/libavformat/dsicin.c b/libavformat/dsicin.c index bd4f3ad03..244622ee3 100644 --- a/libavformat/dsicin.c +++ b/libavformat/dsicin.c @@ -60,7 +60,7 @@ typedef struct CinDemuxContext { } CinDemuxContext; -static int cin_probe(AVProbeData *p) +static int cin_probe(const AVProbeData *p) { /* header starts with this special marker */ if (AV_RL32(&p->buf[0]) != 0x55AA0000) diff --git a/libavformat/dss.c b/libavformat/dss.c index 083eb4ad4..e5b0be9de 100644 --- a/libavformat/dss.c +++ b/libavformat/dss.c @@ -58,7 +58,7 @@ typedef struct DSSDemuxContext { int dss_header_size; } DSSDemuxContext; -static int dss_probe(AVProbeData *p) +static int dss_probe(const AVProbeData *p) { if ( AV_RL32(p->buf) != MKTAG(0x2, 'd', 's', 's') && AV_RL32(p->buf) != MKTAG(0x3, 'd', 's', 's')) diff --git a/libavformat/dtsdec.c b/libavformat/dtsdec.c index a3e52cd59..ab59a56df 100644 --- a/libavformat/dtsdec.c +++ b/libavformat/dtsdec.c @@ -29,7 +29,7 @@ #include "avformat.h" #include "rawdec.h" -static int dts_probe(AVProbeData *p) +static int dts_probe(const AVProbeData *p) { const uint8_t *buf, *bufp; uint32_t state = -1; @@ -127,6 +127,7 @@ static int dts_probe(AVProbeData *p) return 0; } +FF_RAW_DEMUXER_CLASS(dts) AVInputFormat ff_dts_demuxer = { .name = "dts", .long_name = NULL_IF_CONFIG_SMALL("raw DTS"), @@ -136,4 +137,5 @@ AVInputFormat ff_dts_demuxer = { .flags = AVFMT_GENERIC_INDEX, .extensions = "dts", .raw_codec_id = AV_CODEC_ID_DTS, -}; + .priv_data_size = sizeof(FFRawDemuxerContext), + .priv_class = &dts_demuxer_class,}; diff --git a/libavformat/dtshddec.c b/libavformat/dtshddec.c index 1bd403c84..b1eb7ffb2 100644 --- a/libavformat/dtshddec.c +++ b/libavformat/dtshddec.c @@ -43,7 +43,7 @@ typedef struct DTSHDDemuxContext { uint64_t data_end; } DTSHDDemuxContext; -static int dtshd_probe(AVProbeData *p) +static int dtshd_probe(const AVProbeData *p) { if (AV_RB64(p->buf) == DTSHDHDR) return AVPROBE_SCORE_MAX; diff --git a/libavformat/dump.c b/libavformat/dump.c index 942e62a58..1c4465607 100644 --- a/libavformat/dump.c +++ b/libavformat/dump.c @@ -293,7 +293,7 @@ static void dump_audioservicetype(void *ctx, AVPacketSideData *sd) av_log(ctx, AV_LOG_INFO, "dialogue"); break; case AV_AUDIO_SERVICE_TYPE_COMMENTARY: - av_log(ctx, AV_LOG_INFO, "comentary"); + av_log(ctx, AV_LOG_INFO, "commentary"); break; case AV_AUDIO_SERVICE_TYPE_EMERGENCY: av_log(ctx, AV_LOG_INFO, "emergency"); @@ -547,10 +547,20 @@ static void dump_stream_format(AVFormatContext *ic, int i, av_log(NULL, AV_LOG_INFO, " (visual impaired)"); if (st->disposition & AV_DISPOSITION_CLEAN_EFFECTS) av_log(NULL, AV_LOG_INFO, " (clean effects)"); + if (st->disposition & AV_DISPOSITION_ATTACHED_PIC) + av_log(NULL, AV_LOG_INFO, " (attached pic)"); + if (st->disposition & AV_DISPOSITION_TIMED_THUMBNAILS) + av_log(NULL, AV_LOG_INFO, " (timed thumbnails)"); + if (st->disposition & AV_DISPOSITION_CAPTIONS) + av_log(NULL, AV_LOG_INFO, " (captions)"); if (st->disposition & AV_DISPOSITION_DESCRIPTIONS) av_log(NULL, AV_LOG_INFO, " (descriptions)"); + if (st->disposition & AV_DISPOSITION_METADATA) + av_log(NULL, AV_LOG_INFO, " (metadata)"); if (st->disposition & AV_DISPOSITION_DEPENDENT) av_log(NULL, AV_LOG_INFO, " (dependent)"); + if (st->disposition & AV_DISPOSITION_STILL_IMAGE) + av_log(NULL, AV_LOG_INFO, " (still image)"); av_log(NULL, AV_LOG_INFO, "\n"); dump_metadata(NULL, st->metadata, " "); diff --git a/libavformat/dv.c b/libavformat/dv.c index 06de04485..eb44e0acb 100644 --- a/libavformat/dv.c +++ b/libavformat/dv.c @@ -587,7 +587,7 @@ static int dv_read_close(AVFormatContext *s) return 0; } -static int dv_probe(AVProbeData *p) +static int dv_probe(const AVProbeData *p) { unsigned marker_pos = 0; int i; diff --git a/libavformat/dvbsub.c b/libavformat/dvbsub.c index 3d2f704c4..ba5d56a86 100644 --- a/libavformat/dvbsub.c +++ b/libavformat/dvbsub.c @@ -25,7 +25,7 @@ #include "rawdec.h" -static int dvbsub_probe(AVProbeData *p) +static int dvbsub_probe(const AVProbeData *p) { int i, j, k; const uint8_t *end = p->buf + p->buf_size; diff --git a/libavformat/dvbtxt.c b/libavformat/dvbtxt.c index 682873834..354d0948f 100644 --- a/libavformat/dvbtxt.c +++ b/libavformat/dvbtxt.c @@ -24,7 +24,7 @@ #include "avformat.h" #include "rawdec.h" -static int dvbtxt_probe(AVProbeData *p) +static int dvbtxt_probe(const AVProbeData *p) { const uint8_t *end = p->buf + p->buf_size; const uint8_t *buf; diff --git a/libavformat/dxa.c b/libavformat/dxa.c index 50193907b..298cda05d 100644 --- a/libavformat/dxa.c +++ b/libavformat/dxa.c @@ -37,7 +37,7 @@ typedef struct DXAContext { int readvid; }DXAContext; -static int dxa_probe(AVProbeData *p) +static int dxa_probe(const AVProbeData *p) { int w, h; if (p->buf_size < 15) diff --git a/libavformat/eacdata.c b/libavformat/eacdata.c index 97eb66e36..b05d5c88b 100644 --- a/libavformat/eacdata.c +++ b/libavformat/eacdata.c @@ -36,7 +36,7 @@ typedef struct CdataDemuxContext { unsigned int audio_pts; } CdataDemuxContext; -static int cdata_probe(AVProbeData *p) +static int cdata_probe(const AVProbeData *p) { const uint8_t *b = p->buf; diff --git a/libavformat/electronicarts.c b/libavformat/electronicarts.c index bfd3fed3a..6dbc3e350 100644 --- a/libavformat/electronicarts.c +++ b/libavformat/electronicarts.c @@ -458,7 +458,7 @@ static int process_ea_header(AVFormatContext *s) return 1; } -static int ea_probe(AVProbeData *p) +static int ea_probe(const AVProbeData *p) { unsigned big_endian, size; diff --git a/libavformat/epafdec.c b/libavformat/epafdec.c index 0cd9627a4..16239ee4a 100644 --- a/libavformat/epafdec.c +++ b/libavformat/epafdec.c @@ -25,7 +25,7 @@ #include "internal.h" #include "pcm.h" -static int epaf_probe(AVProbeData *p) +static int epaf_probe(const AVProbeData *p) { if (((AV_RL32(p->buf) == MKTAG('f','a','p',' ') && AV_RL32(p->buf + 8) == 1) || diff --git a/libavformat/ffmetadec.c b/libavformat/ffmetadec.c index 3290b3b7b..45c92f1ff 100644 --- a/libavformat/ffmetadec.c +++ b/libavformat/ffmetadec.c @@ -19,19 +19,62 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "libavutil/bprint.h" #include "libavutil/mathematics.h" #include "avformat.h" #include "ffmeta.h" #include "internal.h" #include "libavutil/dict.h" -static int probe(AVProbeData *p) +static int probe(const AVProbeData *p) { if(!memcmp(p->buf, ID_STRING, strlen(ID_STRING))) return AVPROBE_SCORE_MAX; return 0; } +static int64_t read_line_to_bprint_escaped(AVIOContext *s, AVBPrint *bp) +{ + int len, end; + int64_t read = 0; + char tmp[1024]; + char c; + char prev = ' '; + + do { + len = 0; + do { + c = avio_r8(s); + end = prev != '\\' && (c == '\r' || c == '\n' || c == '\0'); + if (!end) + tmp[len++] = c; + prev = c; + } while (!end && len < sizeof(tmp)); + av_bprint_append_data(bp, tmp, len); + read += len; + } while (!end); + + if (c == '\r' && avio_r8(s) != '\n' && !avio_feof(s)) + avio_skip(s, -1); + + if (!c && s->error) + return s->error; + + if (!c && !read && avio_feof(s)) + return AVERROR_EOF; + + return read; +} + +static void get_bprint_line(AVIOContext *s, AVBPrint *bp) +{ + + do { + av_bprint_clear(bp); + read_line_to_bprint_escaped(s, bp); + } while (!avio_feof(s) && (bp->str[0] == ';' || bp->str[0] == '#' || bp->str[0] == 0)); +} + static void get_line(AVIOContext *s, uint8_t *buf, int size) { do { @@ -128,12 +171,14 @@ static int read_tag(const uint8_t *line, AVDictionary **m) static int read_header(AVFormatContext *s) { AVDictionary **m = &s->metadata; - uint8_t line[1024]; + AVBPrint bp; + + av_bprint_init(&bp, 0, AV_BPRINT_SIZE_UNLIMITED); while(!avio_feof(s->pb)) { - get_line(s->pb, line, sizeof(line)); + get_bprint_line(s->pb, &bp); - if (!memcmp(line, ID_STREAM, strlen(ID_STREAM))) { + if (!memcmp(bp.str, ID_STREAM, strlen(ID_STREAM))) { AVStream *st = avformat_new_stream(s, NULL); if (!st) @@ -143,7 +188,7 @@ static int read_header(AVFormatContext *s) st->codecpar->codec_id = AV_CODEC_ID_FFMETADATA; m = &st->metadata; - } else if (!memcmp(line, ID_CHAPTER, strlen(ID_CHAPTER))) { + } else if (!memcmp(bp.str, ID_CHAPTER, strlen(ID_CHAPTER))) { AVChapter *ch = read_chapter(s); if (!ch) @@ -151,9 +196,11 @@ static int read_header(AVFormatContext *s) m = &ch->metadata; } else - read_tag(line, m); + read_tag(bp.str, m); } + av_bprint_finalize(&bp, NULL); + s->start_time = 0; if (s->nb_chapters) s->duration = av_rescale_q(s->chapters[s->nb_chapters - 1]->end, diff --git a/libavformat/fifo.c b/libavformat/fifo.c index 145e2e266..b403ba717 100644 --- a/libavformat/fifo.c +++ b/libavformat/fifo.c @@ -442,7 +442,7 @@ static void *fifo_consumer_thread(void *data) return NULL; } -static int fifo_mux_init(AVFormatContext *avf, AVOutputFormat *oformat, +static int fifo_mux_init(AVFormatContext *avf, ff_const59 AVOutputFormat *oformat, const char *filename) { FifoContext *fifo = avf->priv_data; @@ -481,7 +481,7 @@ static int fifo_mux_init(AVFormatContext *avf, AVOutputFormat *oformat, static int fifo_init(AVFormatContext *avf) { FifoContext *fifo = avf->priv_data; - AVOutputFormat *oformat; + ff_const59 AVOutputFormat *oformat; int ret = 0; if (fifo->recovery_wait_streamtime && !fifo->drop_pkts_on_overflow) { diff --git a/libavformat/file.c b/libavformat/file.c index 1d321c420..08c7f8e6d 100644 --- a/libavformat/file.c +++ b/libavformat/file.c @@ -73,6 +73,7 @@ typedef struct FileContext { int trunc; int blocksize; int follow; + int seekable; #if HAVE_DIRENT_H DIR *dir; #endif @@ -82,6 +83,7 @@ static const AVOption file_options[] = { { "truncate", "truncate existing files on write", offsetof(FileContext, trunc), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, AV_OPT_FLAG_ENCODING_PARAM }, { "blocksize", "set I/O operation maximum block size", offsetof(FileContext, blocksize), AV_OPT_TYPE_INT, { .i64 = INT_MAX }, 1, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM }, { "follow", "Follow a file as it is being written", offsetof(FileContext, follow), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, AV_OPT_FLAG_DECODING_PARAM }, + { "seekable", "Sets if the file is seekable", offsetof(FileContext, seekable), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 0, AV_OPT_FLAG_DECODING_PARAM | AV_OPT_FLAG_ENCODING_PARAM }, { NULL } }; @@ -173,7 +175,11 @@ static int file_delete(URLContext *h) av_strstart(filename, "file:", &filename); ret = rmdir(filename); - if (ret < 0 && errno == ENOTDIR) + if (ret < 0 && (errno == ENOTDIR +# ifdef _WIN32 + || errno == EINVAL +# endif + )) ret = unlink(filename); if (ret < 0) return AVERROR(errno); @@ -234,6 +240,9 @@ static int file_open(URLContext *h, const char *filename, int flags) if (!h->is_streamed && flags & AVIO_FLAG_WRITE) h->min_packet_size = h->max_packet_size = 262144; + if (c->seekable >= 0) + h->is_streamed = !c->seekable; + return 0; } diff --git a/libavformat/fitsdec.c b/libavformat/fitsdec.c index 4b288b390..c7d1edec6 100644 --- a/libavformat/fitsdec.c +++ b/libavformat/fitsdec.c @@ -39,7 +39,7 @@ typedef struct FITSContext { int64_t pts; } FITSContext; -static int fits_probe(AVProbeData *p) +static int fits_probe(const AVProbeData *p) { const uint8_t *b = p->buf; if (!memcmp(b, "SIMPLE = T", 30)) diff --git a/libavformat/flac_picture.c b/libavformat/flac_picture.c index 38982b960..8317ab2fa 100644 --- a/libavformat/flac_picture.c +++ b/libavformat/flac_picture.c @@ -20,6 +20,8 @@ */ #include "libavutil/avassert.h" +#include "libavutil/intreadwrite.h" +#include "libavcodec/png.h" #include "avformat.h" #include "flac_picture.h" #include "id3v2.h" @@ -119,6 +121,9 @@ int ff_flac_parse_picture(AVFormatContext *s, uint8_t *buf, int buf_size) goto fail; } + if (AV_RB64(data->data) == PNGSIG) + id = AV_CODEC_ID_PNG; + st = avformat_new_stream(s, NULL); if (!st) { RETURN_ERROR(AVERROR(ENOMEM)); diff --git a/libavformat/flacdec.c b/libavformat/flacdec.c index a03237804..8394e4748 100644 --- a/libavformat/flacdec.c +++ b/libavformat/flacdec.c @@ -31,6 +31,8 @@ #define SEEKPOINT_SIZE 18 typedef struct FLACDecContext { + AVClass *class; + int raw_packet_size; int found_seektable; } FLACDecContext; @@ -211,7 +213,7 @@ fail: return ret; } -static int raw_flac_probe(AVProbeData *p) +static int raw_flac_probe(const AVProbeData *p) { if ((p->buf[2] & 0xF0) == 0) // blocksize code invalid return 0; @@ -227,7 +229,7 @@ static int raw_flac_probe(AVProbeData *p) return AVPROBE_SCORE_EXTENSION / 4 + 1; } -static int flac_probe(AVProbeData *p) +static int flac_probe(const AVProbeData *p) { if ((AV_RB16(p->buf) & 0xFFFE) == 0xFFF8) return raw_flac_probe(p); @@ -327,6 +329,7 @@ static int flac_seek(AVFormatContext *s, int stream_index, int64_t timestamp, in return -1; } +FF_RAW_DEMUXER_CLASS(flac) AVInputFormat ff_flac_demuxer = { .name = "flac", .long_name = NULL_IF_CONFIG_SMALL("raw FLAC"), @@ -339,4 +342,5 @@ AVInputFormat ff_flac_demuxer = { .extensions = "flac", .raw_codec_id = AV_CODEC_ID_FLAC, .priv_data_size = sizeof(FLACDecContext), + .priv_class = &flac_demuxer_class, }; diff --git a/libavformat/flacenc.c b/libavformat/flacenc.c index 617bccdc8..a07260f42 100644 --- a/libavformat/flacenc.c +++ b/libavformat/flacenc.c @@ -65,7 +65,7 @@ static int flac_write_block_comment(AVIOContext *pb, AVDictionary **m, ff_metadata_conv(m, ff_vorbiscomment_metadata_conv, NULL); - len = ff_vorbiscomment_length(*m, vendor); + len = ff_vorbiscomment_length(*m, vendor, NULL, 0); if (len >= ((1<<24) - 4)) return AVERROR(EINVAL); p0 = av_malloc(len+4); @@ -75,7 +75,7 @@ static int flac_write_block_comment(AVIOContext *pb, AVDictionary **m, bytestream_put_byte(&p, last_block ? 0x84 : 0x04); bytestream_put_be24(&p, len); - ff_vorbiscomment_write(&p, m, vendor); + ff_vorbiscomment_write(&p, m, vendor, NULL, 0); avio_write(pb, p0, len+4); av_freep(&p0); diff --git a/libavformat/flic.c b/libavformat/flic.c index 7c62cb423..d7844ce04 100644 --- a/libavformat/flic.c +++ b/libavformat/flic.c @@ -57,7 +57,7 @@ typedef struct FlicDemuxContext { int frame_number; } FlicDemuxContext; -static int flic_probe(AVProbeData *p) +static int flic_probe(const AVProbeData *p) { int magic_number; diff --git a/libavformat/flv.h b/libavformat/flv.h index df5ce3d17..3571b9027 100644 --- a/libavformat/flv.h +++ b/libavformat/flv.h @@ -65,6 +65,7 @@ enum FlvTagType { enum { FLV_STREAM_TYPE_VIDEO, FLV_STREAM_TYPE_AUDIO, + FLV_STREAM_TYPE_SUBTITLE, FLV_STREAM_TYPE_DATA, FLV_STREAM_TYPE_NB, }; diff --git a/libavformat/flvdec.c b/libavformat/flvdec.c index 34c3e08ba..b531a39ad 100644 --- a/libavformat/flvdec.c +++ b/libavformat/flvdec.c @@ -30,6 +30,7 @@ #include "libavutil/opt.h" #include "libavutil/intfloat.h" #include "libavutil/mathematics.h" +#include "libavutil/time_internal.h" #include "libavcodec/bytestream.h" #include "libavcodec/mpeg4audio.h" #include "avformat.h" @@ -44,6 +45,8 @@ typedef struct FLVContext { const AVClass *class; ///< Class for private options. int trust_metadata; ///< configure streams according onMetaData + int trust_datasize; ///< trust data size of FLVTag + int dump_full_metadata; ///< Dump full metadata of the onMetadata int wrong_dts; ///< wrong dts due to negative cts uint8_t *new_extradata[FLV_STREAM_TYPE_NB]; int new_extradata_size[FLV_STREAM_TYPE_NB]; @@ -70,9 +73,18 @@ typedef struct FLVContext { int64_t *keyframe_filepositions; int missing_streams; AVRational framerate; + int64_t last_ts; + int64_t time_offset; + int64_t time_pos; } FLVContext; -static int probe(AVProbeData *p, int live) +/* AMF date type */ +typedef struct amf_date { + double milliseconds; + int16_t timezone; +} amf_date; + +static int probe(const AVProbeData *p, int live) { const uint8_t *d = p->buf; unsigned offset = AV_RB32(d + 5); @@ -91,16 +103,30 @@ static int probe(AVProbeData *p, int live) return 0; } -static int flv_probe(AVProbeData *p) +static int flv_probe(const AVProbeData *p) { return probe(p, 0); } -static int live_flv_probe(AVProbeData *p) +static int live_flv_probe(const AVProbeData *p) { return probe(p, 1); } +static int kux_probe(const AVProbeData *p) +{ + const uint8_t *d = p->buf; + + if (d[0] == 'K' && + d[1] == 'D' && + d[2] == 'K' && + d[3] == 0 && + d[4] == 0) { + return AVPROBE_SCORE_EXTENSION + 1; + } + return 0; +} + static void add_keyframes_index(AVFormatContext *s) { FLVContext *flv = s->priv_data; @@ -141,7 +167,9 @@ static AVStream *create_stream(AVFormatContext *s, int codec_type) st->codecpar->codec_type = codec_type; if (s->nb_streams>=3 ||( s->nb_streams==2 && s->streams[0]->codecpar->codec_type != AVMEDIA_TYPE_SUBTITLE - && s->streams[1]->codecpar->codec_type != AVMEDIA_TYPE_SUBTITLE)) + && s->streams[1]->codecpar->codec_type != AVMEDIA_TYPE_SUBTITLE + && s->streams[0]->codecpar->codec_type != AVMEDIA_TYPE_DATA + && s->streams[1]->codecpar->codec_type != AVMEDIA_TYPE_DATA)) s->ctx_flags &= ~AVFMTCTX_NOHEADER; if (codec_type == AVMEDIA_TYPE_AUDIO) { st->codecpar->bit_rate = flv->audio_bit_rate; @@ -379,7 +407,7 @@ static int parse_keyframes_index(AVFormatContext *s, AVIOContext *ioc, int64_t m int64_t initial_pos = avio_tell(ioc); if (flv->keyframe_count > 0) { - av_log(s, AV_LOG_DEBUG, "keyframes have been paresed\n"); + av_log(s, AV_LOG_DEBUG, "keyframes have been parsed\n"); return 0; } av_assert0(!flv->keyframe_times); @@ -464,6 +492,7 @@ static int amf_parse_object(AVFormatContext *s, AVStream *astream, AMFDataType amf_type; char str_val[1024]; double num_val; + amf_date date; num_val = 0; ioc = s->pb; @@ -535,7 +564,9 @@ static int amf_parse_object(AVFormatContext *s, AVStream *astream, } break; case AMF_DATA_TYPE_DATE: - avio_skip(ioc, 8 + 2); // timestamp (double) and UTC offset (int16) + // timestamp (double) and UTC offset (int16) + date.milliseconds = av_int2double(avio_rb64(ioc)); + date.timezone = avio_rb16(ioc); break; default: // unsupported type, we couldn't skip av_log(s, AV_LOG_ERROR, "unsupported amf type %d\n", amf_type); @@ -611,7 +642,7 @@ static int amf_parse_object(AVFormatContext *s, AVStream *astream, (!vpar && !strcmp(key, "videocodecid")))) s->ctx_flags &= ~AVFMTCTX_NOHEADER; //If there is either audio/video missing, codecid will be an empty object - if (!strcmp(key, "duration") || + if ((!strcmp(key, "duration") || !strcmp(key, "filesize") || !strcmp(key, "width") || !strcmp(key, "height") || @@ -623,7 +654,7 @@ static int amf_parse_object(AVFormatContext *s, AVStream *astream, !strcmp(key, "audiosamplesize") || !strcmp(key, "stereo") || !strcmp(key, "audiocodecid") || - !strcmp(key, "datastream")) + !strcmp(key, "datastream")) && !flv->dump_full_metadata) return 0; s->event_flags |= AVFMT_EVENT_FLAG_METADATA_UPDATED; @@ -634,8 +665,18 @@ static int amf_parse_object(AVFormatContext *s, AVStream *astream, } else if (amf_type == AMF_DATA_TYPE_NUMBER) { snprintf(str_val, sizeof(str_val), "%.f", num_val); av_dict_set(&s->metadata, key, str_val, 0); - } else if (amf_type == AMF_DATA_TYPE_STRING) + } else if (amf_type == AMF_DATA_TYPE_STRING) { av_dict_set(&s->metadata, key, str_val, 0); + } else if (amf_type == AMF_DATA_TYPE_DATE) { + time_t time; + struct tm t; + char datestr[128]; + time = date.milliseconds / 1000; // to seconds + localtime_r(&time, &t); + strftime(datestr, sizeof(datestr), "%a, %d %b %Y %H:%M:%S %z", &t); + + av_dict_set(&s->metadata, key, datestr, 0); + } } return 0; @@ -654,8 +695,6 @@ static int flv_read_metabody(AVFormatContext *s, int64_t next_pos) AVStream av_unused *dstream; AVIOContext *ioc; int i; - // only needs to hold the string "onMetaData". - // Anything longer is something we don't want. char buffer[32]; astream = NULL; @@ -713,6 +752,10 @@ static int flv_read_header(AVFormatContext *s) int offset; int pre_tag_size = 0; + /* Actual FLV data at 0xe40000 in KUX file */ + if(!strcmp(s->iformat->name, "kux")) + avio_skip(s->pb, 0xe40000); + avio_skip(s->pb, 4); flags = avio_r8(s->pb); @@ -753,6 +796,9 @@ static int flv_read_close(AVFormatContext *s) static int flv_get_extradata(AVFormatContext *s, AVStream *st, int size) { + if (!size) + return 0; + av_freep(&st->codecpar->extradata); if (ff_get_extradata(s, st->codecpar, s->pb, size) < 0) return AVERROR(ENOMEM); @@ -763,6 +809,9 @@ static int flv_get_extradata(AVFormatContext *s, AVStream *st, int size) static int flv_queue_extradata(FLVContext *flv, AVIOContext *pb, int stream, int size) { + if (!size) + return 0; + av_free(flv->new_extradata[stream]); flv->new_extradata[stream] = av_mallocz(size + AV_INPUT_BUFFER_PADDING_SIZE); @@ -909,6 +958,18 @@ static int resync(AVFormatContext *s) flv->resync_buffer[j ] = flv->resync_buffer[j1] = avio_r8(s->pb); + if (i >= 8 && pos) { + uint8_t *d = flv->resync_buffer + j1 - 8; + if (d[0] == 'F' && + d[1] == 'L' && + d[2] == 'V' && + d[3] < 5 && d[5] == 0) { + av_log(s, AV_LOG_WARNING, "Concatenated FLV detected, might fail to demux, decode and seek %"PRId64"\n", flv->last_ts); + flv->time_offset = flv->last_ts + 1; + flv->time_pos = avio_tell(s->pb); + } + } + if (i > 22) { unsigned lsize2 = AV_RB32(flv->resync_buffer + j1 - 4); if (lsize2 >= 11 && lsize2 + 8LL < FFMIN(i, RESYNC_BUFFER_SIZE)) { @@ -943,135 +1004,144 @@ static int flv_read_packet(AVFormatContext *s, AVPacket *pkt) retry: /* pkt size is repeated at end. skip it */ - pos = avio_tell(s->pb); - type = (avio_r8(s->pb) & 0x1F); - orig_size = - size = avio_rb24(s->pb); - flv->sum_flv_tag_size += size + 11; - dts = avio_rb24(s->pb); - dts |= (unsigned)avio_r8(s->pb) << 24; - av_log(s, AV_LOG_TRACE, "type:%d, size:%d, last:%d, dts:%"PRId64" pos:%"PRId64"\n", type, size, last, dts, avio_tell(s->pb)); - if (avio_feof(s->pb)) - return AVERROR_EOF; - avio_skip(s->pb, 3); /* stream id, always 0 */ - flags = 0; + pos = avio_tell(s->pb); + type = (avio_r8(s->pb) & 0x1F); + orig_size = + size = avio_rb24(s->pb); + flv->sum_flv_tag_size += size + 11; + dts = avio_rb24(s->pb); + dts |= (unsigned)avio_r8(s->pb) << 24; + av_log(s, AV_LOG_TRACE, "type:%d, size:%d, last:%d, dts:%"PRId64" pos:%"PRId64"\n", type, size, last, dts, avio_tell(s->pb)); + if (avio_feof(s->pb)) + return AVERROR_EOF; + avio_skip(s->pb, 3); /* stream id, always 0 */ + flags = 0; - if (flv->validate_next < flv->validate_count) { - int64_t validate_pos = flv->validate_index[flv->validate_next].pos; - if (pos == validate_pos) { - if (FFABS(dts - flv->validate_index[flv->validate_next].dts) <= - VALIDATE_INDEX_TS_THRESH) { - flv->validate_next++; - } else { - clear_index_entries(s, validate_pos); - flv->validate_count = 0; - } - } else if (pos > validate_pos) { + if (flv->validate_next < flv->validate_count) { + int64_t validate_pos = flv->validate_index[flv->validate_next].pos; + if (pos == validate_pos) { + if (FFABS(dts - flv->validate_index[flv->validate_next].dts) <= + VALIDATE_INDEX_TS_THRESH) { + flv->validate_next++; + } else { clear_index_entries(s, validate_pos); flv->validate_count = 0; } + } else if (pos > validate_pos) { + clear_index_entries(s, validate_pos); + flv->validate_count = 0; } + } - if (size == 0) { - ret = FFERROR_REDO; - goto leave; - } + if (size == 0) { + ret = FFERROR_REDO; + goto leave; + } - next = size + avio_tell(s->pb); + next = size + avio_tell(s->pb); - if (type == FLV_TAG_TYPE_AUDIO) { - stream_type = FLV_STREAM_TYPE_AUDIO; - flags = avio_r8(s->pb); - size--; - } else if (type == FLV_TAG_TYPE_VIDEO) { - stream_type = FLV_STREAM_TYPE_VIDEO; - flags = avio_r8(s->pb); - size--; - if ((flags & FLV_VIDEO_FRAMETYPE_MASK) == FLV_FRAME_VIDEO_INFO_CMD) - goto skip; - } else if (type == FLV_TAG_TYPE_META) { - stream_type=FLV_STREAM_TYPE_DATA; - if (size > 13 + 1 + 4) { // Header-type metadata stuff - int type; - meta_pos = avio_tell(s->pb); - type = flv_read_metabody(s, next); - if (type == 0 && dts == 0 || type < 0 || type == TYPE_UNKNOWN) { - if (type < 0 && flv->validate_count && - flv->validate_index[0].pos > next && - flv->validate_index[0].pos - 4 < next - ) { - av_log(s, AV_LOG_WARNING, "Adjusting next position due to index mismatch\n"); - next = flv->validate_index[0].pos - 4; - } - goto skip; - } else if (type == TYPE_ONTEXTDATA) { - avpriv_request_sample(s, "OnTextData packet"); - return flv_data_packet(s, pkt, dts, next); - } else if (type == TYPE_ONCAPTION) { - return flv_data_packet(s, pkt, dts, next); + if (type == FLV_TAG_TYPE_AUDIO) { + stream_type = FLV_STREAM_TYPE_AUDIO; + flags = avio_r8(s->pb); + size--; + } else if (type == FLV_TAG_TYPE_VIDEO) { + stream_type = FLV_STREAM_TYPE_VIDEO; + flags = avio_r8(s->pb); + size--; + if ((flags & FLV_VIDEO_FRAMETYPE_MASK) == FLV_FRAME_VIDEO_INFO_CMD) + goto skip; + } else if (type == FLV_TAG_TYPE_META) { + stream_type=FLV_STREAM_TYPE_SUBTITLE; + if (size > 13 + 1 + 4) { // Header-type metadata stuff + int type; + meta_pos = avio_tell(s->pb); + type = flv_read_metabody(s, next); + if (type == 0 && dts == 0 || type < 0) { + if (type < 0 && flv->validate_count && + flv->validate_index[0].pos > next && + flv->validate_index[0].pos - 4 < next + ) { + av_log(s, AV_LOG_WARNING, "Adjusting next position due to index mismatch\n"); + next = flv->validate_index[0].pos - 4; } - avio_seek(s->pb, meta_pos, SEEK_SET); + goto skip; + } else if (type == TYPE_ONTEXTDATA) { + avpriv_request_sample(s, "OnTextData packet"); + return flv_data_packet(s, pkt, dts, next); + } else if (type == TYPE_ONCAPTION) { + return flv_data_packet(s, pkt, dts, next); + } else if (type == TYPE_UNKNOWN) { + stream_type = FLV_STREAM_TYPE_DATA; } - } else { - av_log(s, AV_LOG_DEBUG, - "Skipping flv packet: type %d, size %d, flags %d.\n", - type, size, flags); + avio_seek(s->pb, meta_pos, SEEK_SET); + } + } else { + av_log(s, AV_LOG_DEBUG, + "Skipping flv packet: type %d, size %d, flags %d.\n", + type, size, flags); skip: - if (avio_seek(s->pb, next, SEEK_SET) != next) { - // This can happen if flv_read_metabody above read past - // next, on a non-seekable input, and the preceding data has - // been flushed out from the IO buffer. - av_log(s, AV_LOG_ERROR, "Unable to seek to the next packet\n"); - return AVERROR_INVALIDDATA; - } - ret = FFERROR_REDO; - goto leave; + if (avio_seek(s->pb, next, SEEK_SET) != next) { + // This can happen if flv_read_metabody above read past + // next, on a non-seekable input, and the preceding data has + // been flushed out from the IO buffer. + av_log(s, AV_LOG_ERROR, "Unable to seek to the next packet\n"); + return AVERROR_INVALIDDATA; } + ret = FFERROR_REDO; + goto leave; + } - /* skip empty data packets */ - if (!size) { - ret = FFERROR_REDO; - goto leave; + /* skip empty data packets */ + if (!size) { + ret = FFERROR_REDO; + goto leave; + } + + /* now find stream */ + for (i = 0; i < s->nb_streams; i++) { + st = s->streams[i]; + if (stream_type == FLV_STREAM_TYPE_AUDIO) { + if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && + (s->audio_codec_id || flv_same_audio_codec(st->codecpar, flags))) + break; + } else if (stream_type == FLV_STREAM_TYPE_VIDEO) { + if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && + (s->video_codec_id || flv_same_video_codec(st->codecpar, flags))) + break; + } else if (stream_type == FLV_STREAM_TYPE_SUBTITLE) { + if (st->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE) + break; + } else if (stream_type == FLV_STREAM_TYPE_DATA) { + if (st->codecpar->codec_type == AVMEDIA_TYPE_DATA) + break; } + } + if (i == s->nb_streams) { + static const enum AVMediaType stream_types[] = {AVMEDIA_TYPE_VIDEO, AVMEDIA_TYPE_AUDIO, AVMEDIA_TYPE_SUBTITLE, AVMEDIA_TYPE_DATA}; + st = create_stream(s, stream_types[stream_type]); + if (!st) + return AVERROR(ENOMEM); - /* now find stream */ - for (i = 0; i < s->nb_streams; i++) { - st = s->streams[i]; - if (stream_type == FLV_STREAM_TYPE_AUDIO) { - if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && - (s->audio_codec_id || flv_same_audio_codec(st->codecpar, flags))) - break; - } else if (stream_type == FLV_STREAM_TYPE_VIDEO) { - if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && - (s->video_codec_id || flv_same_video_codec(st->codecpar, flags))) - break; - } else if (stream_type == FLV_STREAM_TYPE_DATA) { - if (st->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE) - break; - } - } - if (i == s->nb_streams) { - static const enum AVMediaType stream_types[] = {AVMEDIA_TYPE_VIDEO, AVMEDIA_TYPE_AUDIO, AVMEDIA_TYPE_SUBTITLE}; - st = create_stream(s, stream_types[stream_type]); - if (!st) - return AVERROR(ENOMEM); + } + av_log(s, AV_LOG_TRACE, "%d %X %d \n", stream_type, flags, st->discard); - } - av_log(s, AV_LOG_TRACE, "%d %X %d \n", stream_type, flags, st->discard); + if (flv->time_pos <= pos) { + dts += flv->time_offset; + } - if ((s->pb->seekable & AVIO_SEEKABLE_NORMAL) && - ((flags & FLV_VIDEO_FRAMETYPE_MASK) == FLV_FRAME_KEY || - stream_type == FLV_STREAM_TYPE_AUDIO)) - av_add_index_entry(st, pos, dts, size, 0, AVINDEX_KEYFRAME); + if ((s->pb->seekable & AVIO_SEEKABLE_NORMAL) && + ((flags & FLV_VIDEO_FRAMETYPE_MASK) == FLV_FRAME_KEY || + stream_type == FLV_STREAM_TYPE_AUDIO)) + av_add_index_entry(st, pos, dts, size, 0, AVINDEX_KEYFRAME); - if ( (st->discard >= AVDISCARD_NONKEY && !((flags & FLV_VIDEO_FRAMETYPE_MASK) == FLV_FRAME_KEY || (stream_type == FLV_STREAM_TYPE_AUDIO))) - ||(st->discard >= AVDISCARD_BIDIR && ((flags & FLV_VIDEO_FRAMETYPE_MASK) == FLV_FRAME_DISP_INTER && (stream_type == FLV_STREAM_TYPE_VIDEO))) - || st->discard >= AVDISCARD_ALL - ) { - avio_seek(s->pb, next, SEEK_SET); - ret = FFERROR_REDO; - goto leave; - } + if ( (st->discard >= AVDISCARD_NONKEY && !((flags & FLV_VIDEO_FRAMETYPE_MASK) == FLV_FRAME_KEY || (stream_type == FLV_STREAM_TYPE_AUDIO))) + ||(st->discard >= AVDISCARD_BIDIR && ((flags & FLV_VIDEO_FRAMETYPE_MASK) == FLV_FRAME_DISP_INTER && (stream_type == FLV_STREAM_TYPE_VIDEO))) + || st->discard >= AVDISCARD_ALL + ) { + avio_seek(s->pb, next, SEEK_SET); + ret = FFERROR_REDO; + goto leave; + } // if not streamed and no duration from metadata then seek to end to find // the duration from the timestamps @@ -1145,8 +1215,10 @@ retry_duration: if (ret < 0) return ret; size -= ret; - } else if (stream_type == FLV_STREAM_TYPE_DATA) { + } else if (stream_type == FLV_STREAM_TYPE_SUBTITLE) { st->codecpar->codec_id = AV_CODEC_ID_TEXT; + } else if (stream_type == FLV_STREAM_TYPE_DATA) { + st->codecpar->codec_id = AV_CODEC_ID_NONE; // Opaque AMF data } if (st->codecpar->codec_id == AV_CODEC_ID_AAC || @@ -1247,23 +1319,30 @@ retry_duration: if ( stream_type == FLV_STREAM_TYPE_AUDIO || ((flags & FLV_VIDEO_FRAMETYPE_MASK) == FLV_FRAME_KEY) || + stream_type == FLV_STREAM_TYPE_SUBTITLE || stream_type == FLV_STREAM_TYPE_DATA) pkt->flags |= AV_PKT_FLAG_KEY; leave: last = avio_rb32(s->pb); - if (last != orig_size + 11 && last != orig_size + 10 && - !avio_feof(s->pb) && - (last != orig_size || !last) && last != flv->sum_flv_tag_size && - !flv->broken_sizes) { - av_log(s, AV_LOG_ERROR, "Packet mismatch %d %d %d\n", last, orig_size + 11, flv->sum_flv_tag_size); - avio_seek(s->pb, pos + 1, SEEK_SET); - ret = resync(s); - av_packet_unref(pkt); - if (ret >= 0) { - goto retry; + if (!flv->trust_datasize) { + if (last != orig_size + 11 && last != orig_size + 10 && + !avio_feof(s->pb) && + (last != orig_size || !last) && last != flv->sum_flv_tag_size && + !flv->broken_sizes) { + av_log(s, AV_LOG_ERROR, "Packet mismatch %d %d %d\n", last, orig_size + 11, flv->sum_flv_tag_size); + avio_seek(s->pb, pos + 1, SEEK_SET); + ret = resync(s); + av_packet_unref(pkt); + if (ret >= 0) { + goto retry; + } } } + + if (ret >= 0) + flv->last_ts = pkt->dts; + return ret; } @@ -1279,6 +1358,8 @@ static int flv_read_seek(AVFormatContext *s, int stream_index, #define VD AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_DECODING_PARAM static const AVOption options[] = { { "flv_metadata", "Allocate streams according to the onMetaData array", OFFSET(trust_metadata), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VD }, + { "flv_full_metadata", "Dump full metadata of the onMetadata", OFFSET(dump_full_metadata), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VD }, + { "flv_ignore_prevtag", "Ignore the Size of previous tag", OFFSET(trust_datasize), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VD }, { "missing_streams", "", OFFSET(missing_streams), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 0xFF, VD | AV_OPT_FLAG_EXPORT | AV_OPT_FLAG_READONLY }, { NULL } }; @@ -1323,3 +1404,23 @@ AVInputFormat ff_live_flv_demuxer = { .priv_class = &live_flv_class, .flags = AVFMT_TS_DISCONT }; + +static const AVClass kux_class = { + .class_name = "kuxdec", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; + +AVInputFormat ff_kux_demuxer = { + .name = "kux", + .long_name = NULL_IF_CONFIG_SMALL("KUX (YouKu)"), + .priv_data_size = sizeof(FLVContext), + .read_probe = kux_probe, + .read_header = flv_read_header, + .read_packet = flv_read_packet, + .read_seek = flv_read_seek, + .read_close = flv_read_close, + .extensions = "kux", + .priv_class = &kux_class, +}; diff --git a/libavformat/flvenc.c b/libavformat/flvenc.c index 1f503679e..fb1dede7a 100644 --- a/libavformat/flvenc.c +++ b/libavformat/flvenc.c @@ -230,12 +230,17 @@ static void put_amf_string(AVIOContext *pb, const char *str) avio_write(pb, str, len); } +// FLV timestamps are 32 bits signed, RTMP timestamps should be 32-bit unsigned +static void put_timestamp(AVIOContext *pb, int64_t ts) { + avio_wb24(pb, ts & 0xFFFFFF); + avio_w8(pb, (ts >> 24) & 0x7F); +} + static void put_avc_eos_tag(AVIOContext *pb, unsigned ts) { avio_w8(pb, FLV_TAG_TYPE_VIDEO); avio_wb24(pb, 5); /* Tag Data Size */ - avio_wb24(pb, ts); /* lower 24 bits of timestamp in ms */ - avio_w8(pb, (ts >> 24) & 0x7F); /* MSB of ts in ms */ + put_timestamp(pb, ts); avio_wb24(pb, 0); /* StreamId = 0 */ avio_w8(pb, 23); /* ub[4] FrameType = 1, ub[4] CodecId = 7 */ avio_w8(pb, 2); /* AVC end of sequence */ @@ -480,7 +485,7 @@ static int unsupported_codec(AVFormatContext *s, return AVERROR(ENOSYS); } -static void flv_write_codec_header(AVFormatContext* s, AVCodecParameters* par) { +static void flv_write_codec_header(AVFormatContext* s, AVCodecParameters* par, int64_t ts) { int64_t data_size; AVIOContext *pb = s->pb; FLVContext *flv = s->priv_data; @@ -492,8 +497,7 @@ static void flv_write_codec_header(AVFormatContext* s, AVCodecParameters* par) { par->codec_type == AVMEDIA_TYPE_VIDEO ? FLV_TAG_TYPE_VIDEO : FLV_TAG_TYPE_AUDIO); avio_wb24(pb, 0); // size patched later - avio_wb24(pb, 0); // ts - avio_w8(pb, 0); // ts ext + put_timestamp(pb, ts); avio_wb24(pb, 0); // streamid pos = avio_tell(pb); if (par->codec_id == AV_CODEC_ID_AAC) { @@ -649,11 +653,9 @@ end: return ret; } - -static int flv_write_header(AVFormatContext *s) +static int flv_init(struct AVFormatContext *s) { int i; - AVIOContext *pb = s->pb; FLVContext *flv = s->priv_data; for (i = 0; i < s->nb_streams; i++) { @@ -732,6 +734,15 @@ static int flv_write_header(AVFormatContext *s) flv->delay = AV_NOPTS_VALUE; + return 0; +} + +static int flv_write_header(AVFormatContext *s) +{ + int i; + AVIOContext *pb = s->pb; + FLVContext *flv = s->priv_data; + avio_write(pb, "FLV", 3); avio_w8(pb, 1); avio_w8(pb, FLV_HEADER_FLAG_HASAUDIO * !!flv->audio_par + @@ -756,7 +767,7 @@ static int flv_write_header(AVFormatContext *s) } for (i = 0; i < s->nb_streams; i++) { - flv_write_codec_header(s, s->streams[i]->codecpar); + flv_write_codec_header(s, s->streams[i]->codecpar, 0); } flv->datastart_offset = avio_tell(pb); @@ -905,7 +916,7 @@ static int flv_write_packet(AVFormatContext *s, AVPacket *pkt) } memcpy(par->extradata, side, side_size); par->extradata_size = side_size; - flv_write_codec_header(s, par); + flv_write_codec_header(s, par, pkt->dts); } } @@ -983,8 +994,7 @@ static int flv_write_packet(AVFormatContext *s, AVPacket *pkt) } avio_wb24(pb, size + flags_size); - avio_wb24(pb, ts & 0xFFFFFF); - avio_w8(pb, (ts >> 24) & 0x7F); // timestamps are 32 bits _signed_ + put_timestamp(pb, ts); avio_wb24(pb, flv->reserved); if (par->codec_type == AVMEDIA_TYPE_DATA || @@ -1071,6 +1081,18 @@ static int flv_write_packet(AVFormatContext *s, AVPacket *pkt) return pb->error; } +static int flv_check_bitstream(struct AVFormatContext *s, const AVPacket *pkt) +{ + int ret = 1; + AVStream *st = s->streams[pkt->stream_index]; + + if (st->codecpar->codec_id == AV_CODEC_ID_AAC) { + if (pkt->size > 2 && (AV_RB16(pkt->data) & 0xfff0) == 0xfff0) + ret = ff_stream_add_bitstream_filter(st, "aac_adtstoasc", NULL); + } + return ret; +} + static const AVOption options[] = { { "flvflags", "FLV muxer flags", offsetof(FLVContext, flags), AV_OPT_TYPE_FLAGS, {.i64 = 0}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "flvflags" }, { "aac_seq_header_detect", "Put AAC sequence header based on stream data", 0, AV_OPT_TYPE_CONST, {.i64 = FLV_AAC_SEQ_HEADER_DETECT}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "flvflags" }, @@ -1096,9 +1118,11 @@ AVOutputFormat ff_flv_muxer = { .priv_data_size = sizeof(FLVContext), .audio_codec = CONFIG_LIBMP3LAME ? AV_CODEC_ID_MP3 : AV_CODEC_ID_ADPCM_SWF, .video_codec = AV_CODEC_ID_FLV1, + .init = flv_init, .write_header = flv_write_header, .write_packet = flv_write_packet, .write_trailer = flv_write_trailer, + .check_bitstream= flv_check_bitstream, .codec_tag = (const AVCodecTag* const []) { flv_video_codec_ids, flv_audio_codec_ids, 0 }, diff --git a/libavformat/format.c b/libavformat/format.c index 1c66afb7e..c47490c8e 100644 --- a/libavformat/format.c +++ b/libavformat/format.c @@ -48,7 +48,7 @@ int av_match_ext(const char *filename, const char *extensions) return 0; } -AVOutputFormat *av_guess_format(const char *short_name, const char *filename, +ff_const59 AVOutputFormat *av_guess_format(const char *short_name, const char *filename, const char *mime_type) { const AVOutputFormat *fmt = NULL; @@ -84,12 +84,12 @@ AVOutputFormat *av_guess_format(const char *short_name, const char *filename, return fmt_found; } -enum AVCodecID av_guess_codec(AVOutputFormat *fmt, const char *short_name, +enum AVCodecID av_guess_codec(ff_const59 AVOutputFormat *fmt, const char *short_name, const char *filename, const char *mime_type, enum AVMediaType type) { if (av_match_name("segment", fmt->name) || av_match_name("ssegment", fmt->name)) { - AVOutputFormat *fmt2 = av_guess_format(NULL, filename, NULL); + ff_const59 AVOutputFormat *fmt2 = av_guess_format(NULL, filename, NULL); if (fmt2) fmt = fmt2; } @@ -115,7 +115,7 @@ enum AVCodecID av_guess_codec(AVOutputFormat *fmt, const char *short_name, return AV_CODEC_ID_NONE; } -AVInputFormat *av_find_input_format(const char *short_name) +ff_const59 AVInputFormat *av_find_input_format(const char *short_name) { const AVInputFormat *fmt = NULL; void *i = 0; @@ -125,12 +125,12 @@ AVInputFormat *av_find_input_format(const char *short_name) return NULL; } -AVInputFormat *av_probe_input_format3(AVProbeData *pd, int is_opened, +ff_const59 AVInputFormat *av_probe_input_format3(ff_const59 AVProbeData *pd, int is_opened, int *score_ret) { AVProbeData lpd = *pd; const AVInputFormat *fmt1 = NULL; - AVInputFormat *fmt = NULL; + ff_const59 AVInputFormat *fmt = NULL; int score, score_max = 0; void *i = 0; const static uint8_t zerobuffer[AVPROBE_PADDING_SIZE]; @@ -202,10 +202,10 @@ AVInputFormat *av_probe_input_format3(AVProbeData *pd, int is_opened, return fmt; } -AVInputFormat *av_probe_input_format2(AVProbeData *pd, int is_opened, int *score_max) +ff_const59 AVInputFormat *av_probe_input_format2(ff_const59 AVProbeData *pd, int is_opened, int *score_max) { int score_ret; - AVInputFormat *fmt = av_probe_input_format3(pd, is_opened, &score_ret); + ff_const59 AVInputFormat *fmt = av_probe_input_format3(pd, is_opened, &score_ret); if (score_ret > *score_max) { *score_max = score_ret; return fmt; @@ -213,13 +213,13 @@ AVInputFormat *av_probe_input_format2(AVProbeData *pd, int is_opened, int *score return NULL; } -AVInputFormat *av_probe_input_format(AVProbeData *pd, int is_opened) +ff_const59 AVInputFormat *av_probe_input_format(ff_const59 AVProbeData *pd, int is_opened) { int score = 0; return av_probe_input_format2(pd, is_opened, &score); } -int av_probe_input_buffer2(AVIOContext *pb, AVInputFormat **fmt, +int av_probe_input_buffer2(AVIOContext *pb, ff_const59 AVInputFormat **fmt, const char *filename, void *logctx, unsigned int offset, unsigned int max_probe_size) { @@ -250,14 +250,6 @@ int av_probe_input_buffer2(AVIOContext *pb, AVInputFormat **fmt, *semi = '\0'; } } -#if 0 - if (!*fmt && pb->av_class && av_opt_get(pb, "mime_type", AV_OPT_SEARCH_CHILDREN, &mime_type) >= 0 && mime_type) { - if (!av_strcasecmp(mime_type, "audio/aacp")) { - *fmt = av_find_input_format("aac"); - } - av_freep(&mime_type); - } -#endif for (probe_size = PROBE_BUF_MIN; probe_size <= max_probe_size && !*fmt; probe_size = FFMIN(probe_size << 1, @@ -317,7 +309,7 @@ fail: return ret < 0 ? ret : score; } -int av_probe_input_buffer(AVIOContext *pb, AVInputFormat **fmt, +int av_probe_input_buffer(AVIOContext *pb, ff_const59 AVInputFormat **fmt, const char *filename, void *logctx, unsigned int offset, unsigned int max_probe_size) { diff --git a/libavformat/frmdec.c b/libavformat/frmdec.c index 2f6b72642..9a962f37f 100644 --- a/libavformat/frmdec.c +++ b/libavformat/frmdec.c @@ -42,7 +42,7 @@ typedef struct { int count; } FrmContext; -static int frm_read_probe(AVProbeData *p) +static int frm_read_probe(const AVProbeData *p) { if (p->buf_size > 8 && p->buf[0] == 'F' && p->buf[1] == 'R' && p->buf[2] == 'M' && diff --git a/libavformat/fsb.c b/libavformat/fsb.c index 4f59576e3..faad6b16f 100644 --- a/libavformat/fsb.c +++ b/libavformat/fsb.c @@ -25,7 +25,7 @@ #include "avio.h" #include "internal.h" -static int fsb_probe(AVProbeData *p) +static int fsb_probe(const AVProbeData *p) { if (memcmp(p->buf, "FSB", 3) || p->buf[3] - '0' < 1 || p->buf[3] - '0' > 5) return 0; diff --git a/libavformat/ftp.c b/libavformat/ftp.c index ba64abb42..3adc04ee1 100644 --- a/libavformat/ftp.c +++ b/libavformat/ftp.c @@ -489,8 +489,6 @@ static int ftp_list_nlst(FTPContext *s) return 0; } -static int ftp_has_feature(FTPContext *s, const char *feature_name); - static int ftp_list(FTPContext *s) { int ret; @@ -515,7 +513,7 @@ static int ftp_features(FTPContext *s) static const char *feat_command = "FEAT\r\n"; static const char *enable_utf8_command = "OPTS UTF8 ON\r\n"; static const int feat_codes[] = {211, 0}; - static const int opts_codes[] = {200, 451, 0}; + static const int opts_codes[] = {200, 202, 451, 0}; av_freep(&s->features); if (ftp_send_command(s, feat_command, feat_codes, &s->features) != 211) { @@ -523,7 +521,8 @@ static int ftp_features(FTPContext *s) } if (ftp_has_feature(s, "UTF8")) { - if (ftp_send_command(s, enable_utf8_command, opts_codes, NULL) == 200) + int ret = ftp_send_command(s, enable_utf8_command, opts_codes, NULL); + if (ret == 200 || ret == 202) s->utf8 = 1; } diff --git a/libavformat/g722.c b/libavformat/g722.c index 2feec0121..fe8c4ae7b 100644 --- a/libavformat/g722.c +++ b/libavformat/g722.c @@ -46,6 +46,7 @@ static int g722_read_header(AVFormatContext *s) return 0; } +FF_RAW_DEMUXER_CLASS(g722) AVInputFormat ff_g722_demuxer = { .name = "g722", .long_name = NULL_IF_CONFIG_SMALL("raw G.722"), @@ -54,4 +55,5 @@ AVInputFormat ff_g722_demuxer = { .flags = AVFMT_GENERIC_INDEX, .extensions = "g722,722", .raw_codec_id = AV_CODEC_ID_ADPCM_G722, -}; + .priv_data_size = sizeof(FFRawDemuxerContext), + .priv_class = &g722_demuxer_class,}; diff --git a/libavformat/gdv.c b/libavformat/gdv.c index 3ead38389..b698497a6 100644 --- a/libavformat/gdv.c +++ b/libavformat/gdv.c @@ -34,7 +34,7 @@ typedef struct GDVContext { unsigned pal[256]; } GDVContext; -static int gdv_read_probe(AVProbeData *p) +static int gdv_read_probe(const AVProbeData *p) { if (AV_RL32(p->buf) == 0x29111994) return AVPROBE_SCORE_MAX; diff --git a/libavformat/genh.c b/libavformat/genh.c index dd4e76d3d..61adf4996 100644 --- a/libavformat/genh.c +++ b/libavformat/genh.c @@ -29,7 +29,7 @@ typedef struct GENHDemuxContext { unsigned interleave_size; } GENHDemuxContext; -static int genh_probe(AVProbeData *p) +static int genh_probe(const AVProbeData *p) { if (AV_RL32(p->buf) != MKTAG('G','E','N','H')) return 0; diff --git a/libavformat/gif.c b/libavformat/gif.c index 01d98a27b..e125d386b 100644 --- a/libavformat/gif.c +++ b/libavformat/gif.c @@ -27,94 +27,21 @@ #include "libavutil/imgutils.h" #include "libavutil/log.h" #include "libavutil/opt.h" - -/* XXX: random value that shouldn't be taken into effect if there is no - * transparent color in the palette (the transparency bit will be set to 0) */ -#define DEFAULT_TRANSPARENCY_INDEX 0x1f - -static int get_palette_transparency_index(const uint32_t *palette) -{ - int transparent_color_index = -1; - unsigned i, smallest_alpha = 0xff; - - if (!palette) - return -1; - - for (i = 0; i < AVPALETTE_COUNT; i++) { - const uint32_t v = palette[i]; - if (v >> 24 < smallest_alpha) { - smallest_alpha = v >> 24; - transparent_color_index = i; - } - } - return smallest_alpha < 128 ? transparent_color_index : -1; -} - -static int gif_image_write_header(AVIOContext *pb, AVStream *st, - int loop_count, uint32_t *palette) -{ - int i; - int64_t aspect = 0; - const AVRational sar = st->sample_aspect_ratio; - - if (sar.num > 0 && sar.den > 0) { - aspect = sar.num * 64LL / sar.den - 15; - if (aspect < 0 || aspect > 255) - aspect = 0; - } - - avio_write(pb, "GIF", 3); - avio_write(pb, "89a", 3); - avio_wl16(pb, st->codecpar->width); - avio_wl16(pb, st->codecpar->height); - - if (palette) { - const int bcid = get_palette_transparency_index(palette); - - avio_w8(pb, 0xf7); /* flags: global clut, 256 entries */ - avio_w8(pb, bcid < 0 ? DEFAULT_TRANSPARENCY_INDEX : bcid); /* background color index */ - avio_w8(pb, aspect); - for (i = 0; i < 256; i++) { - const uint32_t v = palette[i] & 0xffffff; - avio_wb24(pb, v); - } - } else { - avio_w8(pb, 0); /* flags */ - avio_w8(pb, 0); /* background color index */ - avio_w8(pb, aspect); - } - - - if (loop_count >= 0 ) { - /* "NETSCAPE EXTENSION" for looped animation GIF */ - avio_w8(pb, 0x21); /* GIF Extension code */ - avio_w8(pb, 0xff); /* Application Extension Label */ - avio_w8(pb, 0x0b); /* Length of Application Block */ - avio_write(pb, "NETSCAPE2.0", sizeof("NETSCAPE2.0") - 1); - avio_w8(pb, 0x03); /* Length of Data Sub-Block */ - avio_w8(pb, 0x01); - avio_wl16(pb, (uint16_t)loop_count); - avio_w8(pb, 0x00); /* Data Sub-block Terminator */ - } - - avio_flush(pb); - return 0; -} +#include "libavcodec/bytestream.h" +#include "libavcodec/gif.h" typedef struct GIFContext { AVClass *class; int loop; int last_delay; - AVPacket *prev_pkt; int duration; + int64_t last_pos; + int have_end; + AVPacket *prev_pkt; } GIFContext; static int gif_write_header(AVFormatContext *s) { - GIFContext *gif = s->priv_data; - AVCodecParameters *video_par; - uint32_t palette[AVPALETTE_COUNT]; - if (s->nb_streams != 1 || s->streams[0]->codecpar->codec_type != AVMEDIA_TYPE_VIDEO || s->streams[0]->codecpar->codec_id != AV_CODEC_ID_GIF) { @@ -123,92 +50,123 @@ static int gif_write_header(AVFormatContext *s) return AVERROR(EINVAL); } - video_par = s->streams[0]->codecpar; - avpriv_set_pts_info(s->streams[0], 64, 1, 100); - if (avpriv_set_systematic_pal2(palette, video_par->format) < 0) { - av_assert0(video_par->format == AV_PIX_FMT_PAL8); - /* delay header writing: we wait for the first palette to put it - * globally */ - } else { - gif_image_write_header(s->pb, s->streams[0], gif->loop, palette); + + return 0; +} + +static int gif_parse_packet(AVFormatContext *s, uint8_t *data, int size) +{ + GetByteContext gb; + int x; + + bytestream2_init(&gb, data, size); + + while (bytestream2_get_bytes_left(&gb) > 0) { + x = bytestream2_get_byte(&gb); + if (x != GIF_EXTENSION_INTRODUCER) + return 0; + + x = bytestream2_get_byte(&gb); + while (x != GIF_GCE_EXT_LABEL && bytestream2_get_bytes_left(&gb) > 0) { + int block_size = bytestream2_get_byte(&gb); + if (!block_size) + break; + bytestream2_skip(&gb, block_size); + } + + if (x == GIF_GCE_EXT_LABEL) + return bytestream2_tell(&gb) + 2; } return 0; } -static int flush_packet(AVFormatContext *s, AVPacket *new) +static int gif_get_delay(GIFContext *gif, AVPacket *prev, AVPacket *new) { - GIFContext *gif = s->priv_data; - int size, bcid; - AVIOContext *pb = s->pb; - const uint32_t *palette; - AVPacket *pkt = gif->prev_pkt; - - if (!pkt) - return 0; - - /* Mark one colour as transparent if the input palette contains at least - * one colour that is more than 50% transparent. */ - palette = (uint32_t*)av_packet_get_side_data(pkt, AV_PKT_DATA_PALETTE, &size); - if (palette && size != AVPALETTE_SIZE) { - av_log(s, AV_LOG_ERROR, "Invalid palette extradata\n"); - return AVERROR_INVALIDDATA; - } - bcid = get_palette_transparency_index(palette); - if (new && new->pts != AV_NOPTS_VALUE) - gif->duration = av_clip_uint16(new->pts - gif->prev_pkt->pts); + gif->duration = av_clip_uint16(new->pts - prev->pts); else if (!new && gif->last_delay >= 0) gif->duration = gif->last_delay; - /* graphic control extension block */ - avio_w8(pb, 0x21); - avio_w8(pb, 0xf9); - avio_w8(pb, 0x04); /* block size */ - avio_w8(pb, 1<<2 | (bcid >= 0)); - avio_wl16(pb, gif->duration); - avio_w8(pb, bcid < 0 ? DEFAULT_TRANSPARENCY_INDEX : bcid); - avio_w8(pb, 0x00); - - avio_write(pb, pkt->data, pkt->size); - - av_packet_unref(gif->prev_pkt); - if (new) - av_packet_ref(gif->prev_pkt, new); - - return 0; + return gif->duration; } -static int gif_write_packet(AVFormatContext *s, AVPacket *pkt) +static int gif_write_packet(AVFormatContext *s, AVPacket *new_pkt) { GIFContext *gif = s->priv_data; - AVStream *video_st = s->streams[0]; + AVIOContext *pb = s->pb; + AVPacket *pkt = gif->prev_pkt; if (!gif->prev_pkt) { gif->prev_pkt = av_packet_alloc(); if (!gif->prev_pkt) return AVERROR(ENOMEM); + return av_packet_ref(gif->prev_pkt, new_pkt); + } - /* Write the first palette as global palette */ - if (video_st->codecpar->format == AV_PIX_FMT_PAL8) { - int size; - void *palette = av_packet_get_side_data(pkt, AV_PKT_DATA_PALETTE, &size); + gif->last_pos = avio_tell(pb); + if (pkt->size > 0) + gif->have_end = pkt->data[pkt->size - 1] == GIF_TRAILER; - if (!palette) { - av_log(s, AV_LOG_ERROR, "PAL8 packet is missing palette in extradata\n"); - return AVERROR_INVALIDDATA; - } - if (size != AVPALETTE_SIZE) { - av_log(s, AV_LOG_ERROR, "Invalid palette extradata\n"); - return AVERROR_INVALIDDATA; - } - gif_image_write_header(s->pb, video_st, gif->loop, palette); + if (!gif->last_pos) { + int delay_pos; + int off = 13; + + if (pkt->size < 13) + return AVERROR(EINVAL); + + if (pkt->data[10] & 0x80) + off += 3 * (1 << ((pkt->data[10] & 0x07) + 1)); + + if (pkt->size < off + 2) + return AVERROR(EINVAL); + + avio_write(pb, pkt->data, off); + + if (pkt->data[off] == GIF_EXTENSION_INTRODUCER && pkt->data[off + 1] == 0xff) + off += 19; + + if (pkt->size <= off) + return AVERROR(EINVAL); + + /* "NETSCAPE EXTENSION" for looped animation GIF */ + if (gif->loop >= 0) { + avio_w8(pb, GIF_EXTENSION_INTRODUCER); /* GIF Extension code */ + avio_w8(pb, GIF_APP_EXT_LABEL); /* Application Extension Label */ + avio_w8(pb, 0x0b); /* Length of Application Block */ + avio_write(pb, "NETSCAPE2.0", sizeof("NETSCAPE2.0") - 1); + avio_w8(pb, 0x03); /* Length of Data Sub-Block */ + avio_w8(pb, 0x01); + avio_wl16(pb, (uint16_t)gif->loop); + avio_w8(pb, 0x00); /* Data Sub-block Terminator */ } - return av_packet_ref(gif->prev_pkt, pkt); + delay_pos = gif_parse_packet(s, pkt->data + off, pkt->size - off); + if (delay_pos > 0 && delay_pos < pkt->size - off - 2) { + avio_write(pb, pkt->data + off, delay_pos); + avio_wl16(pb, gif_get_delay(gif, pkt, new_pkt)); + avio_write(pb, pkt->data + off + delay_pos + 2, pkt->size - off - delay_pos - 2); + } else { + avio_write(pb, pkt->data + off, pkt->size - off); + } + } else { + int delay_pos = gif_parse_packet(s, pkt->data, pkt->size); + + if (delay_pos > 0 && delay_pos < pkt->size - 2) { + avio_write(pb, pkt->data, delay_pos); + avio_wl16(pb, gif_get_delay(gif, pkt, new_pkt)); + avio_write(pb, pkt->data + delay_pos + 2, pkt->size - delay_pos - 2); + } else { + avio_write(pb, pkt->data, pkt->size); + } } - return flush_packet(s, pkt); + + av_packet_unref(gif->prev_pkt); + if (new_pkt) + return av_packet_ref(gif->prev_pkt, new_pkt); + + return 0; } static int gif_write_trailer(AVFormatContext *s) @@ -216,9 +174,14 @@ static int gif_write_trailer(AVFormatContext *s) GIFContext *gif = s->priv_data; AVIOContext *pb = s->pb; - flush_packet(s, NULL); - av_freep(&gif->prev_pkt); - avio_w8(pb, 0x3b); + if (!gif->prev_pkt) + return AVERROR(EINVAL); + + gif_write_packet(s, NULL); + + if (!gif->have_end) + avio_w8(pb, GIF_TRAILER); + av_packet_free(&gif->prev_pkt); return 0; } @@ -242,7 +205,7 @@ static const AVClass gif_muxer_class = { AVOutputFormat ff_gif_muxer = { .name = "gif", - .long_name = NULL_IF_CONFIG_SMALL("GIF Animation"), + .long_name = NULL_IF_CONFIG_SMALL("CompuServe Graphics Interchange Format (GIF)"), .mime_type = "image/gif", .extensions = "gif", .priv_data_size = sizeof(GIFContext), diff --git a/libavformat/gifdec.c b/libavformat/gifdec.c index 8993ca615..a31644c2a 100644 --- a/libavformat/gifdec.c +++ b/libavformat/gifdec.c @@ -25,6 +25,7 @@ */ #include "avformat.h" +#include "libavutil/bprint.h" #include "libavutil/intreadwrite.h" #include "libavutil/opt.h" #include "internal.h" @@ -68,7 +69,7 @@ typedef struct GIFDemuxContext { */ #define GIF_MIN_DELAY 2 -static int gif_probe(AVProbeData *p) +static int gif_probe(const AVProbeData *p) { /* check magick */ if (memcmp(p->buf, gif87a_sig, 6) && memcmp(p->buf, gif89a_sig, 6)) @@ -94,42 +95,6 @@ static int resync(AVIOContext *pb) return 0; } -static int gif_read_header(AVFormatContext *s) -{ - GIFDemuxContext *gdc = s->priv_data; - AVIOContext *pb = s->pb; - AVStream *st; - int width, height, ret; - - if ((ret = resync(pb)) < 0) - return ret; - - gdc->delay = gdc->default_delay; - width = avio_rl16(pb); - height = avio_rl16(pb); - - if (width == 0 || height == 0) - return AVERROR_INVALIDDATA; - - st = avformat_new_stream(s, NULL); - if (!st) - return AVERROR(ENOMEM); - - /* GIF format operates with time in "hundredths of second", - * therefore timebase is 1/100 */ - avpriv_set_pts_info(st, 64, 1, 100); - st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO; - st->codecpar->codec_id = AV_CODEC_ID_GIF; - st->codecpar->width = width; - st->codecpar->height = height; - - /* jump to start because gif decoder needs header data too */ - if (avio_seek(pb, 0, SEEK_SET) != 0) - return AVERROR(EIO); - - return 0; -} - static int gif_skip_subblocks(AVIOContext *pb) { int sb_size, ret = 0; @@ -142,6 +107,104 @@ static int gif_skip_subblocks(AVIOContext *pb) return ret; } +static int gif_read_header(AVFormatContext *s) +{ + GIFDemuxContext *gdc = s->priv_data; + AVIOContext *pb = s->pb; + AVStream *st; + int type, width, height, ret, n, flags; + int64_t nb_frames = 0, duration = 0; + + if ((ret = resync(pb)) < 0) + return ret; + + gdc->delay = gdc->default_delay; + width = avio_rl16(pb); + height = avio_rl16(pb); + flags = avio_r8(pb); + avio_skip(pb, 1); + n = avio_r8(pb); + + if (width == 0 || height == 0) + return AVERROR_INVALIDDATA; + + st = avformat_new_stream(s, NULL); + if (!st) + return AVERROR(ENOMEM); + + if (flags & 0x80) + avio_skip(pb, 3 * (1 << ((flags & 0x07) + 1))); + + while ((type = avio_r8(pb)) != GIF_TRAILER) { + if (avio_feof(pb)) + break; + if (type == GIF_EXTENSION_INTRODUCER) { + int subtype = avio_r8(pb); + if (subtype == GIF_COM_EXT_LABEL) { + AVBPrint bp; + int block_size; + + av_bprint_init(&bp, 0, -1); + while ((block_size = avio_r8(pb)) != 0) { + avio_read_to_bprint(pb, &bp, block_size); + } + av_dict_set(&s->metadata, "comment", bp.str, 0); + av_bprint_finalize(&bp, NULL); + } else if (subtype == GIF_GCE_EXT_LABEL) { + int block_size = avio_r8(pb); + + if (block_size == 4) { + int delay; + + avio_skip(pb, 1); + delay = avio_rl16(pb); + if (delay < gdc->min_delay) + delay = gdc->default_delay; + delay = FFMIN(delay, gdc->max_delay); + duration += delay; + avio_skip(pb, 1); + } else { + avio_skip(pb, block_size); + } + gif_skip_subblocks(pb); + } else { + gif_skip_subblocks(pb); + } + } else if (type == GIF_IMAGE_SEPARATOR) { + avio_skip(pb, 8); + flags = avio_r8(pb); + if (flags & 0x80) + avio_skip(pb, 3 * (1 << ((flags & 0x07) + 1))); + avio_skip(pb, 1); + gif_skip_subblocks(pb); + nb_frames++; + } else { + break; + } + } + + /* GIF format operates with time in "hundredths of second", + * therefore timebase is 1/100 */ + avpriv_set_pts_info(st, 64, 1, 100); + st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO; + st->codecpar->codec_id = AV_CODEC_ID_GIF; + st->codecpar->width = width; + st->codecpar->height = height; + st->start_time = 0; + st->duration = duration; + st->nb_frames = nb_frames; + if (n) { + st->codecpar->sample_aspect_ratio.num = n + 15; + st->codecpar->sample_aspect_ratio.den = 64; + } + + /* jump to start because gif decoder needs header data too */ + if (avio_seek(pb, 0, SEEK_SET) != 0) + return AVERROR(EIO); + + return 0; +} + static int gif_read_ext(AVFormatContext *s) { GIFDemuxContext *gdc = s->priv_data; diff --git a/libavformat/gsmdec.c b/libavformat/gsmdec.c index 1627106a2..1044cde31 100644 --- a/libavformat/gsmdec.c +++ b/libavformat/gsmdec.c @@ -34,7 +34,7 @@ typedef struct GSMDemuxerContext { int sample_rate; } GSMDemuxerContext; -static int gsm_probe(AVProbeData *p) +static int gsm_probe(const AVProbeData *p) { int valid = 0, invalid = 0; uint8_t *b = p->buf; diff --git a/libavformat/gxf.c b/libavformat/gxf.c index 399f745bc..49364b720 100644 --- a/libavformat/gxf.c +++ b/libavformat/gxf.c @@ -86,7 +86,7 @@ static int parse_packet_header(AVIOContext *pb, GXFPktType *type, int *length) { /** * @brief check if file starts with a PKT_MAP header */ -static int gxf_probe(AVProbeData *p) { +static int gxf_probe(const AVProbeData *p) { static const uint8_t startcode[] = {0, 0, 0, 0, 1, 0xbc}; // start with map packet static const uint8_t endcode[] = {0, 0, 0, 0, 0xe1, 0xe2}; if (!memcmp(p->buf, startcode, sizeof(startcode)) && diff --git a/libavformat/h261dec.c b/libavformat/h261dec.c index a1d682128..b5161ff57 100644 --- a/libavformat/h261dec.c +++ b/libavformat/h261dec.c @@ -23,7 +23,7 @@ #include "avformat.h" #include "rawdec.h" -static int h261_probe(AVProbeData *p) +static int h261_probe(const AVProbeData *p) { int i; int valid_psc=0; diff --git a/libavformat/h263dec.c b/libavformat/h263dec.c index 145fb8590..0736158bf 100644 --- a/libavformat/h263dec.c +++ b/libavformat/h263dec.c @@ -22,7 +22,7 @@ #include "avformat.h" #include "rawdec.h" -static int h263_probe(AVProbeData *p) +static int h263_probe(const AVProbeData *p) { uint64_t code= -1; int i; diff --git a/libavformat/h264dec.c b/libavformat/h264dec.c index 85d7163c9..199e87fbf 100644 --- a/libavformat/h264dec.c +++ b/libavformat/h264dec.c @@ -28,7 +28,7 @@ #define MAX_SPS_COUNT 32 #define MAX_PPS_COUNT 256 -static int h264_probe(AVProbeData *p) +static int h264_probe(const AVProbeData *p) { uint32_t code = -1; int sps = 0, pps = 0, idr = 0, res = 0, sli = 0; diff --git a/libavformat/hashenc.c b/libavformat/hashenc.c index a66db4ae7..06fc085d1 100644 --- a/libavformat/hashenc.c +++ b/libavformat/hashenc.c @@ -88,7 +88,7 @@ static int hash_write_trailer(struct AVFormatContext *s) #if CONFIG_HASH_MUXER static const AVClass hashenc_class = { - .class_name = "hash encoder class", + .class_name = "hash muxer", .item_name = av_default_item_name, .option = hash_options, .version = LIBAVUTIL_VERSION_INT, @@ -111,7 +111,7 @@ AVOutputFormat ff_hash_muxer = { #if CONFIG_MD5_MUXER static const AVClass md5enc_class = { - .class_name = "MD5 encoder class", + .class_name = "MD5 muxer", .item_name = av_default_item_name, .option = md5_options, .version = LIBAVUTIL_VERSION_INT, @@ -217,7 +217,7 @@ static int framehash_write_trailer(struct AVFormatContext *s) #if CONFIG_FRAMEHASH_MUXER static const AVClass framehash_class = { - .class_name = "frame hash encoder class", + .class_name = "frame hash muxer", .item_name = av_default_item_name, .option = hash_options, .version = LIBAVUTIL_VERSION_INT, @@ -240,7 +240,7 @@ AVOutputFormat ff_framehash_muxer = { #if CONFIG_FRAMEMD5_MUXER static const AVClass framemd5_class = { - .class_name = "frame hash encoder class", + .class_name = "frame MD5 muxer", .item_name = av_default_item_name, .option = md5_options, .version = LIBAVUTIL_VERSION_INT, diff --git a/libavformat/hcom.c b/libavformat/hcom.c new file mode 100644 index 000000000..0d1736b62 --- /dev/null +++ b/libavformat/hcom.c @@ -0,0 +1,91 @@ +/* + * HCOM demuxer + * Copyright (c) 2019 Paul B Mahol + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/intreadwrite.h" +#include "libavcodec/internal.h" +#include "avformat.h" +#include "internal.h" +#include "pcm.h" + +static int hcom_probe(const AVProbeData *p) +{ + if (p->buf_size < 132) + return 0; + if (!memcmp(p->buf+65, "FSSD", 4) && + !memcmp(p->buf+128, "HCOM", 4)) + return AVPROBE_SCORE_MAX; + return 0; +} + +static int hcom_read_header(AVFormatContext *s) +{ + AVStream *st; + unsigned data_size, rsrc_size, huffcount; + unsigned compresstype, divisor; + unsigned dict_entries; + int ret; + + avio_skip(s->pb, 83); + data_size = avio_rb32(s->pb); + rsrc_size = avio_rb32(s->pb); + avio_skip(s->pb, 128-91+4); + huffcount = avio_rb32(s->pb); + avio_skip(s->pb, 4); + compresstype = avio_rb32(s->pb); + if (compresstype > 1) + return AVERROR_INVALIDDATA; + divisor = avio_rb32(s->pb); + if (divisor == 0 || divisor > 4) + return AVERROR_INVALIDDATA; + dict_entries = avio_rb16(s->pb); + + st = avformat_new_stream(s, NULL); + if (!st) + return AVERROR(ENOMEM); + + st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO; + st->codecpar->channels = 1; + st->codecpar->sample_rate = 22050 / divisor; + st->codecpar->codec_id = AV_CODEC_ID_HCOM; + st->codecpar->bits_per_coded_sample = 8; + st->codecpar->block_align = 4; + + ret = ff_alloc_extradata(st->codecpar, dict_entries * 4 + 7); + if (ret < 0) + return ret; + AV_WB16(st->codecpar->extradata, dict_entries); + AV_WB32(st->codecpar->extradata + 2, compresstype); + avio_read(s->pb, st->codecpar->extradata + 6, dict_entries * 4); + avio_skip(s->pb, 1); + st->codecpar->extradata[dict_entries * 4 + 6] = avio_r8(s->pb); + + avpriv_set_pts_info(st, 64, 1, st->codecpar->sample_rate); + + return 0; +} + +AVInputFormat ff_hcom_demuxer = { + .name = "hcom", + .long_name = NULL_IF_CONFIG_SMALL("Macintosh HCOM"), + .read_probe = hcom_probe, + .read_header = hcom_read_header, + .read_packet = ff_pcm_read_packet, +}; diff --git a/libavformat/hdsenc.c b/libavformat/hdsenc.c index d82aee17b..026530ac3 100644 --- a/libavformat/hdsenc.c +++ b/libavformat/hdsenc.c @@ -315,7 +315,7 @@ static int hds_write_header(AVFormatContext *s) { HDSContext *c = s->priv_data; int ret = 0, i; - AVOutputFormat *oformat; + ff_const59 AVOutputFormat *oformat; if (mkdir(s->url, 0777) == -1 && errno != EEXIST) { ret = AVERROR(errno); diff --git a/libavformat/hevc.c b/libavformat/hevc.c index 3628d5a02..c7c4be344 100644 --- a/libavformat/hevc.c +++ b/libavformat/hevc.c @@ -643,40 +643,6 @@ static int hvcc_parse_pps(GetBitContext *gb, return 0; } -static uint8_t *nal_unit_extract_rbsp(const uint8_t *src, uint32_t src_len, - uint32_t *dst_len) -{ - uint8_t *dst; - uint32_t i, len; - - dst = av_malloc(src_len + AV_INPUT_BUFFER_PADDING_SIZE); - if (!dst) - return NULL; - - /* NAL unit header (2 bytes) */ - i = len = 0; - while (i < 2 && i < src_len) - dst[len++] = src[i++]; - - while (i + 2 < src_len) - if (!src[i] && !src[i + 1] && src[i + 2] == 3) { - dst[len++] = src[i++]; - dst[len++] = src[i++]; - i++; // remove emulation_prevention_three_byte - } else - dst[len++] = src[i++]; - - while (i < src_len) - dst[len++] = src[i++]; - - memset(dst + len, 0, AV_INPUT_BUFFER_PADDING_SIZE); - - *dst_len = len; - return dst; -} - - - static void nal_unit_parse_header(GetBitContext *gb, uint8_t *nal_type) { skip_bits1(gb); // forbidden_zero_bit @@ -753,7 +719,7 @@ static int hvcc_add_nal_unit(uint8_t *nal_buf, uint32_t nal_size, uint8_t *rbsp_buf; uint32_t rbsp_size; - rbsp_buf = nal_unit_extract_rbsp(nal_buf, nal_size, &rbsp_size); + rbsp_buf = ff_nal_unit_extract_rbsp(nal_buf, nal_size, &rbsp_size, 2); if (!rbsp_buf) { ret = AVERROR(ENOMEM); goto end; diff --git a/libavformat/hevcdec.c b/libavformat/hevcdec.c index aaab0ffa2..255f03bc4 100644 --- a/libavformat/hevcdec.c +++ b/libavformat/hevcdec.c @@ -24,7 +24,7 @@ #include "avformat.h" #include "rawdec.h" -static int hevc_probe(AVProbeData *p) +static int hevc_probe(const AVProbeData *p) { uint32_t code = -1; int vps = 0, sps = 0, pps = 0, irap = 0; diff --git a/libavformat/hls.c b/libavformat/hls.c index 1257cd101..8c12fcef7 100644 --- a/libavformat/hls.c +++ b/libavformat/hls.c @@ -202,13 +202,7 @@ typedef struct HLSContext { int64_t first_timestamp; int64_t cur_timestamp; AVIOInterruptCB *interrupt_callback; - char *referer; ///< holds HTTP referer set as an AVOption to the HTTP protocol context - char *user_agent; ///< holds HTTP user agent set as an AVOption to the HTTP protocol context - char *cookies; ///< holds HTTP cookie values set in either the initial response or as an AVOption to the HTTP protocol context - char *headers; ///< holds HTTP headers set as an AVOption to the HTTP protocol context - char *http_proxy; ///< holds the address of the HTTP proxy server AVDictionary *avio_opts; - int strict_std_compliance; char *allowed_extensions; int max_reload; int http_persistent; @@ -216,14 +210,19 @@ typedef struct HLSContext { AVIOContext *playlist_pb; } HLSContext; -static void free_segment_list(struct playlist *pls) +static void free_segment_dynarray(struct segment **segments, int n_segments) { int i; - for (i = 0; i < pls->n_segments; i++) { - av_freep(&pls->segments[i]->key); - av_freep(&pls->segments[i]->url); - av_freep(&pls->segments[i]); + for (i = 0; i < n_segments; i++) { + av_freep(&segments[i]->key); + av_freep(&segments[i]->url); + av_freep(&segments[i]); } +} + +static void free_segment_list(struct playlist *pls) +{ + free_segment_dynarray(pls->segments, pls->n_segments); av_freep(&pls->segments); pls->n_segments = 0; } @@ -267,10 +266,6 @@ static void free_playlist_list(HLSContext *c) av_free(pls); } av_freep(&c->playlists); - av_freep(&c->cookies); - av_freep(&c->user_agent); - av_freep(&c->headers); - av_freep(&c->http_proxy); c->n_playlists = 0; } @@ -296,7 +291,7 @@ static void free_rendition_list(HLSContext *c) } /* - * Used to reset a statically allocated AVPacket to a clean slate, + * Used to reset a statically allocated AVPacket to a clean state, * containing no data. */ static void reset_packet(AVPacket *pkt) @@ -481,17 +476,23 @@ static struct rendition *new_rendition(HLSContext *c, struct rendition_info *inf * AVC SEI RBSP anyway */ return NULL; - if (type == AVMEDIA_TYPE_UNKNOWN) + if (type == AVMEDIA_TYPE_UNKNOWN) { + av_log(c, AV_LOG_WARNING, "Can't support the type: %s\n", info->type); return NULL; + } /* URI is mandatory for subtitles as per spec */ - if (type == AVMEDIA_TYPE_SUBTITLE && !info->uri[0]) + if (type == AVMEDIA_TYPE_SUBTITLE && !info->uri[0]) { + av_log(c, AV_LOG_ERROR, "The URI tag is REQUIRED for subtitle.\n"); return NULL; + } /* TODO: handle subtitles (each segment has to parsed separately) */ - if (c->strict_std_compliance > FF_COMPLIANCE_EXPERIMENTAL) - if (type == AVMEDIA_TYPE_SUBTITLE) + if (c->ctx->strict_std_compliance > FF_COMPLIANCE_EXPERIMENTAL) + if (type == AVMEDIA_TYPE_SUBTITLE) { + av_log(c, AV_LOG_WARNING, "Can't support the subtitle(uri: %s)\n", info->uri); return NULL; + } rend = av_mallocz(sizeof(struct rendition)); if (!rend) @@ -593,14 +594,6 @@ static int ensure_playlist(HLSContext *c, struct playlist **pls, const char *url return 0; } -static void update_options(char **dest, const char *name, void *src) -{ - av_freep(dest); - av_opt_get(src, name, AV_OPT_SEARCH_CHILDREN, (uint8_t**)dest); - if (*dest && !strlen(*dest)) - av_freep(dest); -} - static int open_url_keepalive(AVFormatContext *s, AVIOContext **pb, const char *url) { @@ -670,7 +663,7 @@ static int open_url(AVFormatContext *s, AVIOContext **pb, const char *url, } else if (ret < 0) { if (ret != AVERROR_EOF) av_log(s, AV_LOG_WARNING, - "keepalive request failed for '%s', retrying with new connection: %s\n", + "keepalive request failed for '%s' when opening url, retrying with new connection: %s\n", url, av_err2str(ret)); ret = s->io_open(s, pb, url, AVIO_FLAG_READ, &tmp); } @@ -684,12 +677,8 @@ static int open_url(AVFormatContext *s, AVIOContext **pb, const char *url, if (!(s->flags & AVFMT_FLAG_CUSTOM_IO)) av_opt_get(*pb, "cookies", AV_OPT_SEARCH_CHILDREN, (uint8_t**)&new_cookies); - if (new_cookies) { - av_free(c->cookies); - c->cookies = new_cookies; - } - - av_dict_set(&opts, "cookies", c->cookies, 0); + if (new_cookies) + av_dict_set(&opts, "cookies", new_cookies, AV_DICT_DONT_STRDUP_VAL); } av_dict_free(&tmp); @@ -719,6 +708,9 @@ static int parse_playlist(HLSContext *c, const char *url, char tmp_str[MAX_URL_SIZE]; struct segment *cur_init_section = NULL; int is_http = av_strstart(url, "http", NULL); + struct segment **prev_segments = NULL; + int prev_n_segments = 0; + int prev_start_seq_no = -1; if (is_http && !in && c->http_persistent && c->playlist_pb) { in = c->playlist_pb; @@ -728,7 +720,7 @@ static int parse_playlist(HLSContext *c, const char *url, } else if (ret < 0) { if (ret != AVERROR_EOF) av_log(c->ctx, AV_LOG_WARNING, - "keepalive request failed for '%s', retrying with new connection: %s\n", + "keepalive request failed for '%s' when parsing playlist, retrying with new connection: %s\n", url, av_err2str(ret)); in = NULL; } @@ -736,14 +728,7 @@ static int parse_playlist(HLSContext *c, const char *url, if (!in) { AVDictionary *opts = NULL; - /* Some HLS servers don't like being sent the range header */ - av_dict_set(&opts, "seekable", "0", 0); - - // broker prior HTTP options that should be consistent across requests - av_dict_set(&opts, "user_agent", c->user_agent, 0); - av_dict_set(&opts, "cookies", c->cookies, 0); - av_dict_set(&opts, "headers", c->headers, 0); - av_dict_set(&opts, "http_proxy", c->http_proxy, 0); + av_dict_copy(&opts, c->avio_opts, 0); if (c->http_persistent) av_dict_set(&opts, "multiple_requests", "1", 0); @@ -769,7 +754,12 @@ static int parse_playlist(HLSContext *c, const char *url, } if (pls) { - free_segment_list(pls); + prev_start_seq_no = pls->start_seq_no; + prev_segments = pls->segments; + prev_n_segments = pls->n_segments; + pls->segments = NULL; + pls->n_segments = 0; + pls->finished = 0; pls->type = PLS_TYPE_UNSPECIFIED; } @@ -826,6 +816,27 @@ static int parse_playlist(HLSContext *c, const char *url, ff_parse_key_value(ptr, (ff_parse_key_val_cb) handle_init_section_args, &info); cur_init_section = new_init_section(pls, &info, url); + cur_init_section->key_type = key_type; + if (has_iv) { + memcpy(cur_init_section->iv, iv, sizeof(iv)); + } else { + int seq = pls->start_seq_no + pls->n_segments; + memset(cur_init_section->iv, 0, sizeof(cur_init_section->iv)); + AV_WB32(cur_init_section->iv + 12, seq); + } + + if (key_type != KEY_NONE) { + ff_make_absolute_url(tmp_str, sizeof(tmp_str), url, key); + cur_init_section->key = av_strdup(tmp_str); + if (!cur_init_section->key) { + av_free(cur_init_section); + ret = AVERROR(ENOMEM); + goto fail; + } + } else { + cur_init_section->key = NULL; + } + } else if (av_strstart(line, "#EXT-X-ENDLIST", &ptr)) { if (pls) pls->finished = 1; @@ -838,6 +849,7 @@ static int parse_playlist(HLSContext *c, const char *url, if (ptr) seg_offset = strtoll(ptr+1, NULL, 10); } else if (av_strstart(line, "#", NULL)) { + av_log(c->ctx, AV_LOG_INFO, "Skip ('%s')\n", line); continue; } else if (line[0]) { if (is_variant) { @@ -909,6 +921,24 @@ static int parse_playlist(HLSContext *c, const char *url, } } } + if (prev_segments) { + if (pls->start_seq_no > prev_start_seq_no && c->first_timestamp != AV_NOPTS_VALUE) { + int64_t prev_timestamp = c->first_timestamp; + int i, diff = pls->start_seq_no - prev_start_seq_no; + for (i = 0; i < prev_n_segments && i < diff; i++) { + c->first_timestamp += prev_segments[i]->duration; + } + av_log(c->ctx, AV_LOG_DEBUG, "Media sequence change (%d -> %d)" + " reflected in first_timestamp: %"PRId64" -> %"PRId64"\n", + prev_start_seq_no, pls->start_seq_no, + prev_timestamp, c->first_timestamp); + } else if (pls->start_seq_no < prev_start_seq_no) { + av_log(c->ctx, AV_LOG_WARNING, "Media sequence changed unexpectedly: %d -> %d\n", + prev_start_seq_no, pls->start_seq_no); + } + free_segment_dynarray(prev_segments, prev_n_segments); + av_freep(&prev_segments); + } if (pls) pls->last_load_time = av_gettime_relative(); @@ -937,14 +967,8 @@ static struct segment *next_segment(struct playlist *pls) return pls->segments[n]; } -enum ReadFromURLMode { - READ_NORMAL, - READ_COMPLETE, -}; - static int read_from_url(struct playlist *pls, struct segment *seg, - uint8_t *buf, int buf_size, - enum ReadFromURLMode mode) + uint8_t *buf, int buf_size) { int ret; @@ -952,13 +976,7 @@ static int read_from_url(struct playlist *pls, struct segment *seg, if (seg->size >= 0) buf_size = FFMIN(buf_size, seg->size - pls->cur_seg_offset); - if (mode == READ_COMPLETE) { - ret = avio_read(pls->input, buf, buf_size); - if (ret != buf_size) - av_log(NULL, AV_LOG_ERROR, "Could not read complete segment.\n"); - } else - ret = avio_read(pls->input, buf, buf_size); - + ret = avio_read(pls->input, buf, buf_size); if (ret > 0) pls->cur_seg_offset += ret; @@ -1077,7 +1095,7 @@ static void intercept_id3(struct playlist *pls, uint8_t *buf, while (1) { /* see if we can retrieve enough data for ID3 header */ if (*len < ID3v2_HEADER_SIZE && buf_size >= ID3v2_HEADER_SIZE) { - bytes = read_from_url(pls, seg, buf + *len, ID3v2_HEADER_SIZE - *len, READ_COMPLETE); + bytes = read_from_url(pls, seg, buf + *len, ID3v2_HEADER_SIZE - *len); if (bytes > 0) { if (bytes == ID3v2_HEADER_SIZE - *len) @@ -1129,7 +1147,7 @@ static void intercept_id3(struct playlist *pls, uint8_t *buf, if (remaining > 0) { /* read the rest of the tag in */ - if (read_from_url(pls, seg, pls->id3_buf + id3_buf_pos, remaining, READ_COMPLETE) != remaining) + if (read_from_url(pls, seg, pls->id3_buf + id3_buf_pos, remaining) != remaining) break; id3_buf_pos += remaining; av_log(pls->ctx, AV_LOG_DEBUG, "Stripped additional %d HLS ID3 bytes\n", remaining); @@ -1143,7 +1161,7 @@ static void intercept_id3(struct playlist *pls, uint8_t *buf, /* re-fill buffer for the caller unless EOF */ if (*len >= 0 && (fill_buf || *len == 0)) { - bytes = read_from_url(pls, seg, buf + *len, buf_size - *len, READ_NORMAL); + bytes = read_from_url(pls, seg, buf + *len, buf_size - *len); /* ignore error if we already had some data */ if (bytes >= 0) @@ -1169,14 +1187,6 @@ static int open_input(HLSContext *c, struct playlist *pls, struct segment *seg, int ret; int is_http = 0; - // broker prior HTTP options that should be consistent across requests - av_dict_set(&opts, "user_agent", c->user_agent, 0); - av_dict_set(&opts, "referer", c->referer, 0); - av_dict_set(&opts, "cookies", c->cookies, 0); - av_dict_set(&opts, "headers", c->headers, 0); - av_dict_set(&opts, "http_proxy", c->http_proxy, 0); - av_dict_set(&opts, "seekable", "0", 0); - if (c->http_persistent) av_dict_set(&opts, "multiple_requests", "1", 0); @@ -1193,19 +1203,18 @@ static int open_input(HLSContext *c, struct playlist *pls, struct segment *seg, if (seg->key_type == KEY_NONE) { ret = open_url(pls->parent, in, seg->url, c->avio_opts, opts, &is_http); } else if (seg->key_type == KEY_AES_128) { - AVDictionary *opts2 = NULL; char iv[33], key[33], url[MAX_URL_SIZE]; if (strcmp(seg->key, pls->key_url)) { AVIOContext *pb = NULL; if (open_url(pls->parent, &pb, seg->key, c->avio_opts, opts, NULL) == 0) { ret = avio_read(pb, pls->key, sizeof(pls->key)); if (ret != sizeof(pls->key)) { - av_log(NULL, AV_LOG_ERROR, "Unable to read key file %s\n", + av_log(pls->parent, AV_LOG_ERROR, "Unable to read key file %s\n", seg->key); } ff_format_io_close(pls->parent, &pb); } else { - av_log(NULL, AV_LOG_ERROR, "Unable to open key file %s\n", + av_log(pls->parent, AV_LOG_ERROR, "Unable to open key file %s\n", seg->key); } av_strlcpy(pls->key_url, seg->key, sizeof(pls->key_url)); @@ -1218,14 +1227,10 @@ static int open_input(HLSContext *c, struct playlist *pls, struct segment *seg, else snprintf(url, sizeof(url), "crypto:%s", seg->url); - av_dict_copy(&opts2, c->avio_opts, 0); - av_dict_set(&opts2, "key", key, 0); - av_dict_set(&opts2, "iv", iv, 0); - - ret = open_url(pls->parent, in, url, opts2, opts, &is_http); - - av_dict_free(&opts2); + av_dict_set(&opts, "key", key, 0); + av_dict_set(&opts, "iv", iv, 0); + ret = open_url(pls->parent, in, url, c->avio_opts, opts, &is_http); if (ret < 0) { goto cleanup; } @@ -1303,7 +1308,7 @@ static int update_init_section(struct playlist *pls, struct segment *seg) av_fast_malloc(&pls->init_sec_buf, &pls->init_sec_buf_size, sec_size); ret = read_from_url(pls, seg->init_section, pls->init_sec_buf, - pls->init_sec_buf_size, READ_COMPLETE); + pls->init_sec_buf_size); ff_format_io_close(pls->parent, &pls->input); if (ret < 0) @@ -1394,8 +1399,8 @@ restart: v->needed = playlist_needed(v); if (!v->needed) { - av_log(v->parent, AV_LOG_INFO, "No longer receiving playlist %d\n", - v->index); + av_log(v->parent, AV_LOG_INFO, "No longer receiving playlist %d ('%s')\n", + v->index, v->url); return AVERROR_EOF; } @@ -1421,7 +1426,7 @@ reload: reload_interval = v->target_duration / 2; } if (v->cur_seq_no < v->start_seq_no) { - av_log(NULL, AV_LOG_WARNING, + av_log(v->parent, AV_LOG_WARNING, "skipping %d segments ahead, expired from playlists\n", v->start_seq_no - v->cur_seq_no); v->cur_seq_no = v->start_seq_no; @@ -1469,7 +1474,7 @@ reload: uint8_t *http_version_opt = NULL; int r = av_opt_get(v->input, "http_version", AV_OPT_SEARCH_CHILDREN, &http_version_opt); if (r >= 0) { - c->http_multiple = strncmp((const char *)http_version_opt, "1.1", 3) == 0; + c->http_multiple = (!strncmp((const char *)http_version_opt, "1.1", 3) || !strncmp((const char *)http_version_opt, "2.0", 3)); av_freep(&http_version_opt); } } @@ -1498,7 +1503,7 @@ reload: } seg = current_segment(v); - ret = read_from_url(v, seg, buf, buf_size, READ_NORMAL); + ret = read_from_url(v, seg, buf, buf_size); if (ret > 0) { if (just_opened && v->is_id3_timestamped != 0) { /* Intercept ID3 tags here, elementary audio streams are required @@ -1646,7 +1651,7 @@ static int save_avio_options(AVFormatContext *s) { HLSContext *c = s->priv_data; static const char * const opts[] = { - "headers", "http_proxy", "user_agent", "user-agent", "cookies", "referer", NULL }; + "headers", "http_proxy", "user_agent", "cookies", "referer", "rw_timeout", NULL }; const char * const * opt = opts; uint8_t *buf; int ret = 0; @@ -1781,44 +1786,28 @@ static int hls_close(AVFormatContext *s) static int hls_read_header(AVFormatContext *s) { - void *u = (s->flags & AVFMT_FLAG_CUSTOM_IO) ? NULL : s->pb; HLSContext *c = s->priv_data; int ret = 0, i; int highest_cur_seq_no = 0; c->ctx = s; c->interrupt_callback = &s->interrupt_callback; - c->strict_std_compliance = s->strict_std_compliance; c->first_packet = 1; c->first_timestamp = AV_NOPTS_VALUE; c->cur_timestamp = AV_NOPTS_VALUE; - if (u) { - // get the previous user agent & set back to null if string size is zero - update_options(&c->user_agent, "user_agent", u); - - // get the previous cookies & set back to null if string size is zero - update_options(&c->cookies, "cookies", u); - - // get the previous headers & set back to null if string size is zero - update_options(&c->headers, "headers", u); - - // get the previous http proxt & set back to null if string size is zero - update_options(&c->http_proxy, "http_proxy", u); - } - - if ((ret = parse_playlist(c, s->url, NULL, s->pb)) < 0) - goto fail; - if ((ret = save_avio_options(s)) < 0) goto fail; /* Some HLS servers don't like being sent the range header */ av_dict_set(&c->avio_opts, "seekable", "0", 0); + if ((ret = parse_playlist(c, s->url, NULL, s->pb)) < 0) + goto fail; + if (c->n_variants == 0) { - av_log(NULL, AV_LOG_WARNING, "Empty playlist\n"); + av_log(s, AV_LOG_WARNING, "Empty playlist\n"); ret = AVERROR_EOF; goto fail; } @@ -1833,7 +1822,7 @@ static int hls_read_header(AVFormatContext *s) } if (c->variants[0]->playlists[0]->n_segments == 0) { - av_log(NULL, AV_LOG_WARNING, "Empty playlist\n"); + av_log(s, AV_LOG_WARNING, "Empty segment\n"); ret = AVERROR_EOF; goto fail; } @@ -1884,7 +1873,7 @@ static int hls_read_header(AVFormatContext *s) /* Open the demuxer for each playlist */ for (i = 0; i < c->n_playlists; i++) { struct playlist *pls = c->playlists[i]; - AVInputFormat *in_fmt = NULL; + ff_const59 AVInputFormat *in_fmt = NULL; if (!(pls->ctx = avformat_alloc_context())) { ret = AVERROR(ENOMEM); @@ -1960,7 +1949,7 @@ static int hls_read_header(AVFormatContext *s) * but for other streams we can rely on our user calling avformat_find_stream_info() * on us if they want to. */ - if (pls->is_id3_timestamped) { + if (pls->is_id3_timestamped || (pls->n_renditions > 0 && pls->renditions[0]->type == AVMEDIA_TYPE_AUDIO)) { ret = avformat_find_stream_info(pls->ctx, NULL); if (ret < 0) goto fail; @@ -2301,7 +2290,7 @@ static int hls_read_seek(AVFormatContext *s, int stream_index, return 0; } -static int hls_probe(AVProbeData *p) +static int hls_probe(const AVProbeData *p) { /* Require #EXTM3U at the start, and either one of the ones below * somewhere for a proper match. */ @@ -2334,14 +2323,14 @@ static const AVOption hls_options[] = { }; static const AVClass hls_class = { - .class_name = "hls,applehttp", + .class_name = "hls demuxer", .item_name = av_default_item_name, .option = hls_options, .version = LIBAVUTIL_VERSION_INT, }; AVInputFormat ff_hls_demuxer = { - .name = "hls,applehttp", + .name = "hls", .long_name = NULL_IF_CONFIG_SMALL("Apple HTTP Live Streaming"), .priv_class = &hls_class, .priv_data_size = sizeof(HLSContext), diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c index c27a66ea7..2ade6723f 100644 --- a/libavformat/hlsenc.c +++ b/libavformat/hlsenc.c @@ -64,17 +64,19 @@ typedef enum { } CodecAttributeStatus; #define KEYSIZE 16 -#define LINE_BUFFER_SIZE 1024 +#define LINE_BUFFER_SIZE MAX_URL_SIZE #define HLS_MICROSECOND_UNIT 1000000 #define POSTFIX_PATTERN "_%d" typedef struct HLSSegment { - char filename[1024]; - char sub_filename[1024]; + char filename[MAX_URL_SIZE]; + char sub_filename[MAX_URL_SIZE]; double duration; /* in seconds */ int discont; int64_t pos; int64_t size; + int64_t keyframe_pos; + int64_t keyframe_size; unsigned var_stream_idx; char key_uri[LINE_BUFFER_SIZE + 1]; @@ -99,6 +101,7 @@ typedef enum HLSFlags { HLS_TEMP_FILE = (1 << 11), HLS_PERIODIC_REKEY = (1 << 12), HLS_INDEPENDENT_SEGMENTS = (1 << 13), + HLS_I_FRAMES_ONLY = (1 << 14), } HLSFlags; typedef enum { @@ -110,8 +113,8 @@ typedef struct VariantStream { unsigned var_stream_idx; unsigned number; int64_t sequence; - AVOutputFormat *oformat; - AVOutputFormat *vtt_oformat; + ff_const59 AVOutputFormat *oformat; + ff_const59 AVOutputFormat *vtt_oformat; AVIOContext *out; int packets_written; int init_range_length; @@ -125,6 +128,9 @@ typedef struct VariantStream { double dpp; // duration per packet int64_t start_pts; int64_t end_pts; + int64_t video_lastpos; + int64_t video_keyframe_pos; + int64_t video_keyframe_size; double duration; // last segment duration computed so far, in seconds int64_t start_pos; // last segment starting position int64_t size; // last segment size @@ -143,20 +149,22 @@ typedef struct VariantStream { char *m3u8_name; double initial_prog_date_time; - char current_segment_final_filename_fmt[1024]; // when renaming segments + char current_segment_final_filename_fmt[MAX_URL_SIZE]; // when renaming segments char *fmp4_init_filename; char *base_output_dirname; - int fmp4_init_mode; AVStream **streams; char codec_attr[128]; CodecAttributeStatus attr_status; unsigned int nb_streams; int m3u8_created; /* status of media play-list creation */ + int is_default; /* default status of audio group */ + char *language; /* audio lauguage name */ char *agroup; /* audio group name */ char *ccgroup; /* closed caption group name */ char *baseurl; + char *varname; // variant name } VariantStream; typedef struct ClosedCaptionsStream { @@ -228,41 +236,12 @@ typedef struct HLSContext { AVIOContext *m3u8_out; AVIOContext *sub_m3u8_out; int64_t timeout; + int ignore_io_errors; + char *headers; + int has_default_key; /* has DEFAULT field of var_stream_map */ + int has_video_m3u8; /* has video stream m3u8 list */ } HLSContext; -static int mkdir_p(const char *path) { - int ret = 0; - char *temp = av_strdup(path); - char *pos = temp; - char tmp_ch = '\0'; - - if (!path || !temp) { - return -1; - } - - if (!strncmp(temp, "/", 1) || !strncmp(temp, "\\", 1)) { - pos++; - } else if (!strncmp(temp, "./", 2) || !strncmp(temp, ".\\", 2)) { - pos += 2; - } - - for ( ; *pos != '\0'; ++pos) { - if (*pos == '/' || *pos == '\\') { - tmp_ch = *pos; - *pos = '\0'; - ret = mkdir(temp, 0755); - *pos = tmp_ch; - } - } - - if ((*(pos - 1) != '/') || (*(pos - 1) != '\\')) { - ret = mkdir(temp, 0755); - } - - av_free(temp); - return ret; -} - static int hlsenc_io_open(AVFormatContext *s, AVIOContext **pb, char *filename, AVDictionary **options) { HLSContext *hls = s->priv_data; @@ -275,6 +254,9 @@ static int hlsenc_io_open(AVFormatContext *s, AVIOContext **pb, char *filename, URLContext *http_url_context = ffio_geturlcontext(*pb); av_assert0(http_url_context); err = ff_http_do_new_request(http_url_context, filename); + if (err < 0) + ff_format_io_close(s, pb); + #endif } return err; @@ -283,6 +265,8 @@ static int hlsenc_io_open(AVFormatContext *s, AVIOContext **pb, char *filename, static void hlsenc_io_close(AVFormatContext *s, AVIOContext **pb, char *filename) { HLSContext *hls = s->priv_data; int http_base_proto = filename ? ff_is_http_proto(filename) : 0; + if (!*pb) + return; if (!http_base_proto || !hls->http_persistent || hls->key_info_file || hls->encrypt) { ff_format_io_close(s, pb); #if CONFIG_HTTP_PROTOCOL @@ -311,6 +295,8 @@ static void set_http_options(AVFormatContext *s, AVDictionary **options, HLSCont av_dict_set_int(options, "multiple_requests", 1, 0); if (c->timeout >= 0) av_dict_set_int(options, "timeout", c->timeout, 0); + if (c->headers) + av_dict_set(options, "headers", c->headers, 0); } static void write_codec_attr(AVStream *st, VariantStream *vs) { @@ -358,6 +344,47 @@ fail: return; } +static int replace_str_data_in_filename(char **s, const char *filename, char placeholder, const char *datastring) +{ + const char *p; + char *new_filename; + char c; + int addchar_count; + int found_count = 0; + AVBPrint buf; + + av_bprint_init(&buf, 0, AV_BPRINT_SIZE_UNLIMITED); + + p = filename; + for (;;) { + c = *p; + if (c == '\0') + break; + if (c == '%' && *(p+1) == '%') // %% + addchar_count = 2; + else if (c == '%' && *(p+1) == placeholder) { + av_bprintf(&buf, "%s", datastring); + p += 2; + addchar_count = 0; + found_count ++; + } else + addchar_count = 1; + + if (addchar_count > 0) { + av_bprint_append_data(&buf, p, addchar_count); + p += addchar_count; + } + } + if (!av_bprint_is_complete(&buf)) { + av_bprint_finalize(&buf, NULL); + return -1; + } + if (av_bprint_finalize(&buf, &new_filename) < 0 || !new_filename) + return -1; + *s = new_filename; + return found_count; +} + static int replace_int_data_in_filename(char **s, const char *filename, char placeholder, int64_t number) { const char *p; @@ -449,6 +476,7 @@ static int hls_delete_old_segments(AVFormatContext *s, HLSContext *hls, int segment_cnt = 0; char *dirname = NULL, *p, *sub_path; char *path = NULL; + char *vtt_dirname = NULL; AVDictionary *options = NULL; AVIOContext *out = NULL; const char *proto = NULL; @@ -491,20 +519,27 @@ static int hls_delete_old_segments(AVFormatContext *s, HLSContext *hls, } - while (segment) { + /* if %v is present in the file's directory + * all segment belongs to the same variant, so do it only once before the loop*/ + if (dirname && av_stristr(dirname, "%v")) { char * r_dirname = dirname; - - /* if %v is present in the file's directory */ - if (av_stristr(dirname, "%v")) { - + if (!vs->varname) { if (replace_int_data_in_filename(&r_dirname, dirname, 'v', segment->var_stream_idx) < 1) { ret = AVERROR(EINVAL); goto fail; } - av_free(dirname); - dirname = r_dirname; + } else { + if (replace_str_data_in_filename(&r_dirname, dirname, 'v', vs->varname) < 1) { + ret = AVERROR(EINVAL); + goto fail; + } } + av_free(dirname); + dirname = r_dirname; + } + + while (segment) { av_log(hls, AV_LOG_DEBUG, "deleting old segment %s\n", segment->filename); path_size = (hls->use_localtime_mkdir ? 0 : strlen(dirname)) + strlen(segment->filename) + 1; @@ -524,8 +559,11 @@ static int hls_delete_old_segments(AVFormatContext *s, HLSContext *hls, proto = avio_find_protocol_name(s->url); if (hls->method || (proto && !av_strcasecmp(proto, "http"))) { av_dict_set(&options, "method", "DELETE", 0); - if ((ret = vs->avf->io_open(vs->avf, &out, path, AVIO_FLAG_WRITE, &options)) < 0) + if ((ret = vs->avf->io_open(vs->avf, &out, path, AVIO_FLAG_WRITE, &options)) < 0) { + if (hls->ignore_io_errors) + ret = 0; goto fail; + } ff_format_io_close(vs->avf, &out); } else if (unlink(path) < 0) { av_log(hls, AV_LOG_ERROR, "failed to delete old segment %s: %s\n", @@ -533,23 +571,32 @@ static int hls_delete_old_segments(AVFormatContext *s, HLSContext *hls, } if ((segment->sub_filename[0] != '\0')) { - sub_path_size = strlen(segment->sub_filename) + 1 + (dirname ? strlen(dirname) : 0); + vtt_dirname = av_strdup(vs->vtt_avf->url); + if (!vtt_dirname) { + ret = AVERROR(ENOMEM); + goto fail; + } + p = (char *)av_basename(vtt_dirname); + *p = '\0'; + sub_path_size = strlen(segment->sub_filename) + 1 + strlen(vtt_dirname); sub_path = av_malloc(sub_path_size); if (!sub_path) { ret = AVERROR(ENOMEM); goto fail; } - av_strlcpy(sub_path, dirname, sub_path_size); + av_strlcpy(sub_path, vtt_dirname, sub_path_size); av_strlcat(sub_path, segment->sub_filename, sub_path_size); if (hls->method || (proto && !av_strcasecmp(proto, "http"))) { av_dict_set(&options, "method", "DELETE", 0); - if ((ret = vs->avf->io_open(vs->avf, &out, sub_path, AVIO_FLAG_WRITE, &options)) < 0) { + if ((ret = vs->vtt_avf->io_open(vs->vtt_avf, &out, sub_path, AVIO_FLAG_WRITE, &options)) < 0) { + if (hls->ignore_io_errors) + ret = 0; av_free(sub_path); goto fail; } - ff_format_io_close(vs->avf, &out); + ff_format_io_close(vs->vtt_avf, &out); } else if (unlink(sub_path) < 0) { av_log(hls, AV_LOG_ERROR, "failed to delete old segment %s: %s\n", sub_path, strerror(errno)); @@ -565,6 +612,7 @@ static int hls_delete_old_segments(AVFormatContext *s, HLSContext *hls, fail: av_free(path); av_free(dirname); + av_free(vtt_dirname); return ret; } @@ -766,9 +814,12 @@ static int hls_mux_init(AVFormatContext *s, VariantStream *vs) vs->packets_written = 1; vs->start_pos = 0; vs->new_start = 1; - vs->fmp4_init_mode = 0; if (hls->segment_type == SEGMENT_TYPE_FMP4) { + if (hls->http_persistent > 0) { + //TODO: Support fragment fmp4 for http persistent in HLS muxer. + av_log(s, AV_LOG_WARNING, "http persistent mode is currently unsupported for fragment mp4 in the HLS muxer.\n"); + } if (hls->max_seg_size > 0) { av_log(s, AV_LOG_WARNING, "Multi-file byterange mode is currently unsupported in the HLS muxer.\n"); return AVERROR_PATCHWELCOME; @@ -776,7 +827,6 @@ static int hls_mux_init(AVFormatContext *s, VariantStream *vs) vs->packets_written = 0; vs->init_range_length = 0; - vs->fmp4_init_mode = !byterange_mode; set_http_options(s, &options, hls); if ((ret = avio_open_dyn_buf(&oc->pb)) < 0) return ret; @@ -803,7 +853,7 @@ static int hls_mux_init(AVFormatContext *s, VariantStream *vs) av_dict_copy(&options, hls->format_options, 0); av_dict_set(&options, "fflags", "-autobsf", 0); - av_dict_set(&options, "movflags", "frag_custom+dash+delay_moov", 0); + av_dict_set(&options, "movflags", "+frag_custom+dash+delay_moov", AV_DICT_APPEND); ret = avformat_init_output(oc, &options); if (ret < 0) return ret; @@ -877,17 +927,17 @@ static int sls_flag_check_duration_size_index(HLSContext *hls) if (hls->flags & HLS_SECOND_LEVEL_SEGMENT_DURATION) { av_log(hls, AV_LOG_ERROR, - "second_level_segment_duration hls_flag requires use_localtime to be true\n"); + "second_level_segment_duration hls_flag requires strftime to be true\n"); ret = AVERROR(EINVAL); } if (hls->flags & HLS_SECOND_LEVEL_SEGMENT_SIZE) { av_log(hls, AV_LOG_ERROR, - "second_level_segment_size hls_flag requires use_localtime to be true\n"); + "second_level_segment_size hls_flag requires strfime to be true\n"); ret = AVERROR(EINVAL); } if (hls->flags & HLS_SECOND_LEVEL_SEGMENT_INDEX) { av_log(hls, AV_LOG_ERROR, - "second_level_segment_index hls_flag requires use_localtime to be true\n"); + "second_level_segment_index hls_flag requires strftime to be true\n"); ret = AVERROR(EINVAL); } @@ -1006,6 +1056,8 @@ static int hls_append_segment(struct AVFormatContext *s, HLSContext *hls, en->duration = duration; en->pos = pos; en->size = size; + en->keyframe_pos = vs->video_keyframe_pos; + en->keyframe_size = vs->video_keyframe_size; en->next = NULL; en->discont = 0; @@ -1063,7 +1115,7 @@ static int parse_playlist(AVFormatContext *s, const char *url, VariantStream *vs AVIOContext *in; int ret = 0, is_segment = 0; int64_t new_start_pos; - char line[1024]; + char line[MAX_URL_SIZE]; const char *ptr; const char *end; @@ -1215,8 +1267,12 @@ static int create_master_playlist(AVFormatContext *s, AVDictionary *options = NULL; unsigned int i, j; int m3u8_name_size, ret, bandwidth; - char *m3u8_rel_name, *ccgroup; + char *m3u8_rel_name = NULL, *ccgroup; ClosedCaptionsStream *ccs; + const char *proto = avio_find_protocol_name(hls->master_m3u8_url); + int is_file_proto = proto && !strcmp(proto, "file"); + int use_temp_file = is_file_proto && ((hls->flags & HLS_TEMP_FILE) || hls->master_publish_rate); + char temp_filename[MAX_URL_SIZE]; input_vs->m3u8_created = 1; if (!hls->master_m3u8_created) { @@ -1232,12 +1288,12 @@ static int create_master_playlist(AVFormatContext *s, } set_http_options(s, &options, hls); - - ret = hlsenc_io_open(s, &hls->m3u8_out, hls->master_m3u8_url, &options); + snprintf(temp_filename, sizeof(temp_filename), use_temp_file ? "%s.tmp" : "%s", hls->master_m3u8_url); + ret = hlsenc_io_open(s, &hls->m3u8_out, temp_filename, &options); av_dict_free(&options); if (ret < 0) { av_log(NULL, AV_LOG_ERROR, "Failed to open master play list file '%s'\n", - hls->master_m3u8_url); + temp_filename); goto fail; } @@ -1274,7 +1330,7 @@ static int create_master_playlist(AVFormatContext *s, goto fail; } - ff_hls_write_audio_rendition(hls->m3u8_out, vs->agroup, m3u8_rel_name, 0, 1); + ff_hls_write_audio_rendition(hls->m3u8_out, vs->agroup, m3u8_rel_name, vs->language, i, hls->has_default_key ? vs->is_default : 1); av_freep(&m3u8_rel_name); } @@ -1352,8 +1408,15 @@ static int create_master_playlist(AVFormatContext *s, vs->ccgroup); } - ff_hls_write_stream_info(vid_st, hls->m3u8_out, bandwidth, m3u8_rel_name, - aud_st ? vs->agroup : NULL, vs->codec_attr, ccgroup); + if (!hls->has_default_key || !hls->has_video_m3u8) { + ff_hls_write_stream_info(vid_st, hls->m3u8_out, bandwidth, m3u8_rel_name, + aud_st ? vs->agroup : NULL, vs->codec_attr, ccgroup); + } else { + if (vid_st) { + ff_hls_write_stream_info(vid_st, hls->m3u8_out, bandwidth, m3u8_rel_name, + aud_st ? vs->agroup : NULL, vs->codec_attr, ccgroup); + } + } av_freep(&m3u8_rel_name); } @@ -1361,7 +1424,10 @@ fail: if(ret >=0) hls->master_m3u8_created = 1; av_freep(&m3u8_rel_name); - hlsenc_io_close(s, &hls->m3u8_out, hls->master_m3u8_url); + hlsenc_io_close(s, &hls->m3u8_out, temp_filename); + if (use_temp_file) + ff_rename(temp_filename, hls->master_m3u8_url, s); + return ret; } @@ -1369,12 +1435,15 @@ static int hls_window(AVFormatContext *s, int last, VariantStream *vs) { HLSContext *hls = s->priv_data; HLSSegment *en; + AVFormatContext *oc = vs->avf; int target_duration = 0; int ret = 0; - char temp_filename[1024]; + char temp_filename[MAX_URL_SIZE]; + char temp_vtt_filename[MAX_URL_SIZE]; int64_t sequence = FFMAX(hls->start_sequence, vs->sequence - vs->nb_entries); - const char *proto = avio_find_protocol_name(s->url); - int use_rename = proto && !strcmp(proto, "file"); + const char *proto = avio_find_protocol_name(vs->m3u8_name); + int is_file_proto = proto && !strcmp(proto, "file"); + int use_temp_file = is_file_proto && ((hls->flags & HLS_TEMP_FILE) || !(hls->pl_type == PLAYLIST_TYPE_VOD)); static unsigned warned_non_file; char *key_uri = NULL; char *iv_string = NULL; @@ -1397,13 +1466,16 @@ static int hls_window(AVFormatContext *s, int last, VariantStream *vs) hls->version = 7; } - if (!use_rename && !warned_non_file++) + if (!is_file_proto && (hls->flags & HLS_TEMP_FILE) && !warned_non_file++) av_log(s, AV_LOG_ERROR, "Cannot use rename on non file protocol, this may lead to races and temporary partial files\n"); set_http_options(s, &options, hls); - snprintf(temp_filename, sizeof(temp_filename), use_rename ? "%s.tmp" : "%s", vs->m3u8_name); - if ((ret = hlsenc_io_open(s, &hls->m3u8_out, temp_filename, &options)) < 0) + snprintf(temp_filename, sizeof(temp_filename), use_temp_file ? "%s.tmp" : "%s", vs->m3u8_name); + if ((ret = hlsenc_io_open(s, (byterange_mode || hls->segment_type == SEGMENT_TYPE_FMP4) ? &hls->m3u8_out : &oc->pb, temp_filename, &options)) < 0) { + if (hls->ignore_io_errors) + ret = 0; goto fail; + } for (en = vs->segments; en; en = en->next) { if (target_duration <= en->duration) @@ -1411,53 +1483,57 @@ static int hls_window(AVFormatContext *s, int last, VariantStream *vs) } vs->discontinuity_set = 0; - ff_hls_write_playlist_header(hls->m3u8_out, hls->version, hls->allowcache, - target_duration, sequence, hls->pl_type); + ff_hls_write_playlist_header((byterange_mode || hls->segment_type == SEGMENT_TYPE_FMP4) ? hls->m3u8_out : oc->pb, hls->version, hls->allowcache, + target_duration, sequence, hls->pl_type, hls->flags & HLS_I_FRAMES_ONLY); if((hls->flags & HLS_DISCONT_START) && sequence==hls->start_sequence && vs->discontinuity_set==0 ){ - avio_printf(hls->m3u8_out, "#EXT-X-DISCONTINUITY\n"); + avio_printf((byterange_mode || hls->segment_type == SEGMENT_TYPE_FMP4) ? hls->m3u8_out : oc->pb, "#EXT-X-DISCONTINUITY\n"); vs->discontinuity_set = 1; } if (vs->has_video && (hls->flags & HLS_INDEPENDENT_SEGMENTS)) { - avio_printf(hls->m3u8_out, "#EXT-X-INDEPENDENT-SEGMENTS\n"); + avio_printf((byterange_mode || hls->segment_type == SEGMENT_TYPE_FMP4) ? hls->m3u8_out : oc->pb, "#EXT-X-INDEPENDENT-SEGMENTS\n"); } for (en = vs->segments; en; en = en->next) { if ((hls->encrypt || hls->key_info_file) && (!key_uri || strcmp(en->key_uri, key_uri) || av_strcasecmp(en->iv_string, iv_string))) { - avio_printf(hls->m3u8_out, "#EXT-X-KEY:METHOD=AES-128,URI=\"%s\"", en->key_uri); + avio_printf((byterange_mode || hls->segment_type == SEGMENT_TYPE_FMP4) ? hls->m3u8_out : oc->pb, "#EXT-X-KEY:METHOD=AES-128,URI=\"%s\"", en->key_uri); if (*en->iv_string) - avio_printf(hls->m3u8_out, ",IV=0x%s", en->iv_string); - avio_printf(hls->m3u8_out, "\n"); + avio_printf((byterange_mode || hls->segment_type == SEGMENT_TYPE_FMP4) ? hls->m3u8_out : oc->pb, ",IV=0x%s", en->iv_string); + avio_printf((byterange_mode || hls->segment_type == SEGMENT_TYPE_FMP4) ? hls->m3u8_out : oc->pb, "\n"); key_uri = en->key_uri; iv_string = en->iv_string; } if ((hls->segment_type == SEGMENT_TYPE_FMP4) && (en == vs->segments)) { - ff_hls_write_init_file(hls->m3u8_out, (hls->flags & HLS_SINGLE_FILE) ? en->filename : vs->fmp4_init_filename, + ff_hls_write_init_file((byterange_mode || hls->segment_type == SEGMENT_TYPE_FMP4) ? hls->m3u8_out : oc->pb, (hls->flags & HLS_SINGLE_FILE) ? en->filename : vs->fmp4_init_filename, hls->flags & HLS_SINGLE_FILE, vs->init_range_length, 0); } - ret = ff_hls_write_file_entry(hls->m3u8_out, en->discont, byterange_mode, + ret = ff_hls_write_file_entry((byterange_mode || hls->segment_type == SEGMENT_TYPE_FMP4) ? hls->m3u8_out : oc->pb, en->discont, byterange_mode, en->duration, hls->flags & HLS_ROUND_DURATIONS, en->size, en->pos, vs->baseurl, - en->filename, prog_date_time_p); + en->filename, prog_date_time_p, en->keyframe_size, en->keyframe_pos, hls->flags & HLS_I_FRAMES_ONLY); if (ret < 0) { av_log(s, AV_LOG_WARNING, "ff_hls_write_file_entry get error\n"); } } if (last && (hls->flags & HLS_OMIT_ENDLIST)==0) - ff_hls_write_end_list(hls->m3u8_out); + ff_hls_write_end_list((byterange_mode || hls->segment_type == SEGMENT_TYPE_FMP4) ? hls->m3u8_out : oc->pb); - if( vs->vtt_m3u8_name ) { - if ((ret = hlsenc_io_open(s, &hls->sub_m3u8_out, vs->vtt_m3u8_name, &options)) < 0) + if (vs->vtt_m3u8_name) { + snprintf(temp_vtt_filename, sizeof(temp_vtt_filename), use_temp_file ? "%s.tmp" : "%s", vs->vtt_m3u8_name); + if ((ret = hlsenc_io_open(s, &hls->sub_m3u8_out, temp_vtt_filename, &options)) < 0) { + if (hls->ignore_io_errors) + ret = 0; goto fail; + } ff_hls_write_playlist_header(hls->sub_m3u8_out, hls->version, hls->allowcache, - target_duration, sequence, PLAYLIST_TYPE_NONE); + target_duration, sequence, PLAYLIST_TYPE_NONE, 0); for (en = vs->segments; en; en = en->next) { ret = ff_hls_write_file_entry(hls->sub_m3u8_out, 0, byterange_mode, en->duration, 0, en->size, en->pos, - vs->baseurl, en->sub_filename, NULL); + vs->baseurl, en->sub_filename, NULL, 0, 0, 0); if (ret < 0) { av_log(s, AV_LOG_WARNING, "ff_hls_write_file_entry get error\n"); } @@ -1470,11 +1546,13 @@ static int hls_window(AVFormatContext *s, int last, VariantStream *vs) fail: av_dict_free(&options); - hlsenc_io_close(s, &hls->m3u8_out, temp_filename); + hlsenc_io_close(s, (byterange_mode || hls->segment_type == SEGMENT_TYPE_FMP4) ? &hls->m3u8_out : &oc->pb, temp_filename); hlsenc_io_close(s, &hls->sub_m3u8_out, vs->vtt_m3u8_name); - if (ret >= 0 && use_rename) + if (use_temp_file) { ff_rename(temp_filename, vs->m3u8_name, s); - + if (vs->vtt_m3u8_name) + ff_rename(temp_vtt_filename, vs->vtt_m3u8_name, s); + } if (ret >= 0 && hls->master_pl_name) if (create_master_playlist(s, vs) < 0) av_log(s, AV_LOG_WARNING, "Master playlist creation failed\n"); @@ -1488,6 +1566,8 @@ static int hls_start(AVFormatContext *s, VariantStream *vs) AVFormatContext *oc = vs->avf; AVFormatContext *vtt_oc = vs->vtt_avf; AVDictionary *options = NULL; + const char *proto = NULL; + int use_temp_file = 0; char *filename, iv_string[KEYSIZE*2 + 1]; int err = 0; @@ -1511,7 +1591,7 @@ static int hls_start(AVFormatContext *s, VariantStream *vs) vs->basename, 'd', vs->sequence) < 1) { #endif av_free(filename); - av_log(oc, AV_LOG_ERROR, "Invalid segment filename template '%s', you can try to use -use_localtime 1 with it\n", vs->basename); + av_log(oc, AV_LOG_ERROR, "Invalid segment filename template '%s', you can try to use -strftime 1 with it\n", vs->basename); return AVERROR(EINVAL); } ff_format_set_url(oc, filename); @@ -1519,7 +1599,7 @@ static int hls_start(AVFormatContext *s, VariantStream *vs) if (c->use_localtime) { time_t now0; struct tm *tm, tmpbuf; - int bufsize = strlen(vs->basename) + 1024; + int bufsize = strlen(vs->basename) + MAX_URL_SIZE; char *buf = av_mallocz(bufsize); if (!buf) return AVERROR(ENOMEM); @@ -1527,7 +1607,7 @@ static int hls_start(AVFormatContext *s, VariantStream *vs) tm = localtime_r(&now0, &tmpbuf); ff_format_set_url(oc, buf); if (!strftime(oc->url, bufsize, vs->basename, tm)) { - av_log(oc, AV_LOG_ERROR, "Could not get segment filename with use_localtime\n"); + av_log(oc, AV_LOG_ERROR, "Could not get segment filename with strftime\n"); return AVERROR(EINVAL); } @@ -1543,7 +1623,7 @@ static int hls_start(AVFormatContext *s, VariantStream *vs) return AVERROR(ENOMEM); } dir = av_dirname(fn_copy); - if (mkdir_p(dir) == -1 && errno != EEXIST) { + if (ff_mkdir_p(dir) == -1 && errno != EEXIST) { av_log(oc, AV_LOG_ERROR, "Could not create directory %s with use_localtime_mkdir\n", dir); av_free(fn_copy); return AVERROR(errno); @@ -1559,7 +1639,7 @@ static int hls_start(AVFormatContext *s, VariantStream *vs) vs->basename, 'd', vs->sequence) < 1) { #endif av_free(filename); - av_log(oc, AV_LOG_ERROR, "Invalid segment filename template '%s' you can try to use -use_localtime 1 with it\n", vs->basename); + av_log(oc, AV_LOG_ERROR, "Invalid segment filename template '%s' you can try to use -strftime 1 with it\n", vs->basename); return AVERROR(EINVAL); } ff_format_set_url(oc, filename); @@ -1583,7 +1663,10 @@ static int hls_start(AVFormatContext *s, VariantStream *vs) set_http_options(s, &options, c); - if (c->flags & HLS_TEMP_FILE) { + proto = avio_find_protocol_name(oc->url); + use_temp_file = proto && !strcmp(proto, "file") && (c->flags & HLS_TEMP_FILE); + + if (use_temp_file) { char *new_name = av_asprintf("%s.tmp", oc->url); if (!new_name) return AVERROR(ENOMEM); @@ -1631,13 +1714,19 @@ static int hls_start(AVFormatContext *s, VariantStream *vs) if (err < 0) return err; } else if (c->segment_type != SEGMENT_TYPE_FMP4) { - if ((err = hlsenc_io_open(s, &oc->pb, oc->url, &options)) < 0) + if ((err = hlsenc_io_open(s, &oc->pb, oc->url, &options)) < 0) { + if (c->ignore_io_errors) + err = 0; goto fail; + } } if (vs->vtt_basename) { set_http_options(s, &options, c); - if ((err = hlsenc_io_open(s, &vtt_oc->pb, vtt_oc->url, &options)) < 0) + if ((err = hlsenc_io_open(s, &vtt_oc->pb, vtt_oc->url, &options)) < 0) { + if (c->ignore_io_errors) + err = 0; goto fail; + } } av_dict_free(&options); @@ -1723,15 +1812,15 @@ static int validate_name(int nb_vs, const char *fn) subdir_name = av_dirname(fn_dup); if (nb_vs > 1 && !av_stristr(filename, "%v") && !av_stristr(subdir_name, "%v")) { - av_log(NULL, AV_LOG_ERROR, "More than 1 variant streams are present, %%v is expected in the filename %s\n", - fn); + av_log(NULL, AV_LOG_ERROR, "More than 1 variant streams are present, %%v is expected " + "either in the filename or in the sub-directory name of file %s\n", fn); ret = AVERROR(EINVAL); goto fail; } if (av_stristr(filename, "%v") && av_stristr(subdir_name, "%v")) { - av_log(NULL, AV_LOG_ERROR, "%%v is expected either in filename or in the sub-directory name of file %s\n", - fn); + av_log(NULL, AV_LOG_ERROR, "%%v is expected either in the filename or " + "in the sub-directory name of file %s, but only in one of them\n", fn); ret = AVERROR(EINVAL); goto fail; } @@ -1741,40 +1830,48 @@ fail: return ret; } -static int format_name(char *buf, int buf_len, int index) +static int format_name(const char *buf, char **s, int index, const char *varname) { const char *proto, *dir; - char *orig_buf_dup = NULL, *mod_buf = NULL, *mod_buf_dup = NULL; + char *orig_buf_dup = NULL, *mod_buf_dup = NULL; int ret = 0; - if (!av_stristr(buf, "%v")) - return ret; - orig_buf_dup = av_strdup(buf); if (!orig_buf_dup) { ret = AVERROR(ENOMEM); goto fail; } - if (replace_int_data_in_filename(&mod_buf, orig_buf_dup, 'v', index) < 1) { - ret = AVERROR(EINVAL); - goto fail; + if (!av_stristr(buf, "%v")) { + *s = orig_buf_dup; + return ret; + } + + if (!varname) { + if (replace_int_data_in_filename(s, orig_buf_dup, 'v', index) < 1) { + ret = AVERROR(EINVAL); + goto fail; + } + } else { + if (replace_str_data_in_filename(s, orig_buf_dup, 'v', varname) < 1) { + ret = AVERROR(EINVAL); + goto fail; + } } - av_strlcpy(buf, mod_buf, buf_len); proto = avio_find_protocol_name(orig_buf_dup); dir = av_dirname(orig_buf_dup); /* if %v is present in the file's directory, create sub-directory */ if (av_stristr(dir, "%v") && proto && !strcmp(proto, "file")) { - mod_buf_dup = av_strdup(buf); + mod_buf_dup = av_strdup(*s); if (!mod_buf_dup) { ret = AVERROR(ENOMEM); goto fail; } dir = av_dirname(mod_buf_dup); - if (mkdir_p(dir) == -1 && errno != EEXIST) { + if (ff_mkdir_p(dir) == -1 && errno != EEXIST) { ret = AVERROR(errno); goto fail; } @@ -1783,7 +1880,6 @@ static int format_name(char *buf, int buf_len, int index) fail: av_freep(&orig_buf_dup); av_freep(&mod_buf_dup); - av_freep(&mod_buf); return ret; } @@ -1809,7 +1905,7 @@ static int parse_variant_stream_mapstring(AVFormatContext *s) { HLSContext *hls = s->priv_data; VariantStream *vs; - int stream_index; + int stream_index, i, j; enum AVMediaType codec_type; int nb_varstreams, nb_streams; char *p, *q, *saveptr1, *saveptr2, *varstr, *keyval; @@ -1818,7 +1914,7 @@ static int parse_variant_stream_mapstring(AVFormatContext *s) /** * Expected format for var_stream_map string is as below: * "a:0,v:0 a:1,v:1" - * "a:0,agroup:a0 a:1,agroup:a1 v:0,agroup:a0 v:1,agroup:a1" + * "a:0,agroup:a0,default:1,language:ENG a:1,agroup:a1,default:0 v:0,agroup:a0 v:1,agroup:a1" * This string specifies how to group the audio, video and subtitle streams * into different variant streams. The variant stream groups are separated * by space. @@ -1849,6 +1945,7 @@ static int parse_variant_stream_mapstring(AVFormatContext *s) if (nb_varstreams < hls->nb_varstreams) { vs = &(hls->var_streams[nb_varstreams]); vs->var_stream_idx = nb_varstreams; + vs->is_default = 0; nb_varstreams++; } else return AVERROR(EINVAL); @@ -1867,8 +1964,22 @@ static int parse_variant_stream_mapstring(AVFormatContext *s) nb_streams = 0; while (keyval = av_strtok(varstr, ",", &saveptr2)) { varstr = NULL; - - if (av_strstart(keyval, "agroup:", &val)) { + if (av_strstart(keyval, "language:", &val)) { + vs->language = av_strdup(val); + if (!vs->language) + return AVERROR(ENOMEM); + continue; + } else if (av_strstart(keyval, "default:", &val)) { + vs->is_default = (!av_strncasecmp(val, "YES", strlen("YES")) || + (!av_strncasecmp(val, "1", strlen("1")))); + hls->has_default_key = 1; + continue; + } else if (av_strstart(keyval, "name:", &val)) { + vs->varname = av_strdup(val); + if (!vs->varname) + return AVERROR(ENOMEM); + continue; + } else if (av_strstart(keyval, "agroup:", &val)) { vs->agroup = av_strdup(val); if (!vs->agroup) return AVERROR(ENOMEM); @@ -1880,6 +1991,7 @@ static int parse_variant_stream_mapstring(AVFormatContext *s) continue; } else if (av_strstart(keyval, "v:", &val)) { codec_type = AVMEDIA_TYPE_VIDEO; + hls->has_video_m3u8 = 1; } else if (av_strstart(keyval, "a:", &val)) { codec_type = AVMEDIA_TYPE_AUDIO; } else if (av_strstart(keyval, "s:", &val)) { @@ -1895,6 +2007,23 @@ static int parse_variant_stream_mapstring(AVFormatContext *s) atoi(val)); if (stream_index >= 0 && nb_streams < vs->nb_streams) { + for(i = 0; nb_streams > 0 && i < nb_streams; i++) { + if (vs->streams[i] == s->streams[stream_index]) { + av_log(s, AV_LOG_ERROR, "Same elementary stream found more than once inside " + "variant definition #%d\n", nb_varstreams - 1); + return AVERROR(EINVAL); + } + } + for(j = 0; nb_varstreams > 1 && j < nb_varstreams - 1; j++) { + for(i = 0; i < hls->var_streams[j].nb_streams; i++) { + if (hls->var_streams[j].streams[i] == s->streams[stream_index]) { + av_log(s, AV_LOG_ERROR, "Same elementary stream found more than once " + "in two different variant definitions #%d and #%d\n", + j, nb_varstreams - 1); + return AVERROR(EINVAL); + } + } + } vs->streams[nb_streams++] = s->streams[stream_index]; } else { av_log(s, AV_LOG_ERROR, "Unable to map stream at %s\n", keyval); @@ -2076,21 +2205,14 @@ static int hls_write_header(AVFormatContext *s) { HLSContext *hls = s->priv_data; int ret, i, j; - AVDictionary *options = NULL; VariantStream *vs = NULL; for (i = 0; i < hls->nb_varstreams; i++) { vs = &hls->var_streams[i]; - av_dict_copy(&options, hls->format_options, 0); - ret = avformat_write_header(vs->avf, &options); - if (av_dict_count(options)) { - av_log(s, AV_LOG_ERROR, "Some of provided format options in '%s' are not recognized\n", hls->format_options_str); - ret = AVERROR(EINVAL); - av_dict_free(&options); - goto fail; - } - av_dict_free(&options); + ret = avformat_write_header(vs->avf, NULL); + if (ret < 0) + return ret; //av_assert0(s->nb_streams == hls->avf->nb_streams); for (j = 0; j < vs->nb_streams; j++) { AVStream *inner_st; @@ -2130,7 +2252,6 @@ static int hls_write_header(AVFormatContext *s) } } } -fail: return ret; } @@ -2145,8 +2266,12 @@ static int hls_write_packet(AVFormatContext *s, AVPacket *pkt) int ret = 0, can_split = 1, i, j; int stream_index = 0; int range_length = 0; + const char *proto = NULL; + int use_temp_file = 0; uint8_t *buffer = NULL; VariantStream *vs = NULL; + AVDictionary *options = NULL; + char *old_filename = NULL; for (i = 0; i < hls->nb_varstreams; i++) { vs = &hls->var_streams[i]; @@ -2177,7 +2302,7 @@ static int hls_write_packet(AVFormatContext *s, AVPacket *pkt) if (vs->sequence - vs->nb_entries > hls->start_sequence && hls->init_time > 0) { /* reset end_pts, hls->recording_time at end of the init hls list */ int init_list_dur = hls->init_time * vs->nb_entries * AV_TIME_BASE; - int after_init_list_dur = (vs->sequence - vs->nb_entries ) * hls->time * AV_TIME_BASE; + int after_init_list_dur = (vs->sequence - hls->start_sequence - vs->nb_entries ) * (hls->time * AV_TIME_BASE); hls->recording_time = hls->time * AV_TIME_BASE; end_pts = init_list_dur + after_init_list_dur ; } @@ -2186,7 +2311,7 @@ static int hls_write_packet(AVFormatContext *s, AVPacket *pkt) vs->start_pts = pkt->pts; } - if (vs->has_video) { + if (vs->has_video) { can_split = st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && ((pkt->flags & AV_PKT_FLAG_KEY) || (hls->flags & HLS_SPLIT_BY_TIME)); is_ref_pkt = (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) && (pkt->stream_index == vs->reference_stream_index); @@ -2216,13 +2341,14 @@ static int hls_write_packet(AVFormatContext *s, AVPacket *pkt) if (vs->packets_written && can_split && av_compare_ts(pkt->pts - vs->start_pts, st->time_base, end_pts, AV_TIME_BASE_Q) >= 0) { int64_t new_start_pos; - char *old_filename = NULL; int byterange_mode = (hls->flags & HLS_SINGLE_FILE) || (hls->max_seg_size > 0); av_write_frame(vs->avf, NULL); /* Flush any buffered data */ new_start_pos = avio_tell(vs->avf->pb); + if (hls->segment_type != SEGMENT_TYPE_FMP4) { + avio_flush(oc->pb); vs->size = new_start_pos - vs->start_pos; } else { vs->size = new_start_pos; @@ -2233,6 +2359,7 @@ static int hls_write_packet(AVFormatContext *s, AVPacket *pkt) avio_flush(oc->pb); range_length = avio_close_dyn_buf(oc->pb, &buffer); avio_write(vs->out, buffer, range_length); + av_free(buffer); vs->init_range_length = range_length; avio_open_dyn_buf(&oc->pb); vs->packets_written = 0; @@ -2252,31 +2379,33 @@ static int hls_write_packet(AVFormatContext *s, AVPacket *pkt) hlsenc_io_close(s, &vs->vtt_avf->pb, vs->vtt_avf->url); } } - if ((hls->flags & HLS_TEMP_FILE) && oc->url[0]) { + + if (oc->url[0]) { + proto = avio_find_protocol_name(oc->url); + use_temp_file = proto && !strcmp(proto, "file") && (hls->flags & HLS_TEMP_FILE); + } + + // look to rename the asset name + if (use_temp_file) { if (!(hls->flags & HLS_SINGLE_FILE) || (hls->max_seg_size <= 0)) if ((vs->avf->oformat->priv_class && vs->avf->priv_data) && hls->segment_type != SEGMENT_TYPE_FMP4) av_opt_set(vs->avf->priv_data, "mpegts_flags", "resend_headers", 0); - hls_rename_temp_file(s, oc); - } - - if (vs->fmp4_init_mode) { - vs->number--; } if (hls->segment_type == SEGMENT_TYPE_FMP4) { if (hls->flags & HLS_SINGLE_FILE) { ret = flush_dynbuf(vs, &range_length); if (ret < 0) { - av_free(old_filename); return ret; } vs->size = range_length; } else { - ret = hlsenc_io_open(s, &vs->out, vs->avf->url, NULL); + set_http_options(s, &options, hls); + ret = hlsenc_io_open(s, &vs->out, vs->avf->url, &options); if (ret < 0) { - av_log(s, AV_LOG_ERROR, "Failed to open file '%s'\n", - vs->avf->url); - return ret; + av_log(s, hls->ignore_io_errors ? AV_LOG_WARNING : AV_LOG_ERROR, + "Failed to open file '%s'\n", vs->avf->url); + return hls->ignore_io_errors ? 0 : ret; } write_styp(vs->out); ret = flush_dynbuf(vs, &range_length); @@ -2287,6 +2416,10 @@ static int hls_write_packet(AVFormatContext *s, AVPacket *pkt) } } + if (use_temp_file && !(hls->flags & HLS_SINGLE_FILE)) { + hls_rename_temp_file(s, oc); + } + old_filename = av_strdup(vs->avf->url); if (!old_filename) { return AVERROR(ENOMEM); @@ -2307,8 +2440,13 @@ static int hls_write_packet(AVFormatContext *s, AVPacket *pkt) } else { vs->start_pos += vs->size; } + // if we're building a VOD playlist, skip writing the manifest multiple times, and just wait until the end + if (hls->pl_type != PLAYLIST_TYPE_VOD) { + if ((ret = hls_window(s, 0, vs)) < 0) { + return ret; + } + } - vs->fmp4_init_mode = 0; if (hls->flags & HLS_SINGLE_FILE) { vs->number++; } else if (hls->max_seg_size > 0) { @@ -2332,24 +2470,63 @@ static int hls_write_packet(AVFormatContext *s, AVPacket *pkt) return ret; } - if (!vs->fmp4_init_mode || byterange_mode) - if ((ret = hls_window(s, 0, vs)) < 0) { - return ret; - } } vs->packets_written++; - ret = ff_write_chained(oc, stream_index, pkt, s, 0); + if (oc->pb) { + ret = ff_write_chained(oc, stream_index, pkt, s, 0); + if ((st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) && (pkt->flags & AV_PKT_FLAG_KEY)) { + vs->video_keyframe_size = avio_tell(oc->pb) - vs->video_lastpos; + vs->video_keyframe_pos = vs->start_pos; + } else { + vs->video_lastpos = avio_tell(oc->pb); + } + + if (hls->ignore_io_errors) + ret = 0; + } return ret; } +static void hls_free_variant_streams(struct HLSContext *hls) +{ + int i = 0; + AVFormatContext *vtt_oc = NULL; + VariantStream *vs = NULL; + + for (i = 0; i < hls->nb_varstreams; i++) { + vs = &hls->var_streams[i]; + vtt_oc = vs->vtt_avf; + + av_freep(&vs->basename); + av_freep(&vs->base_output_dirname); + av_freep(&vs->fmp4_init_filename); + if (vtt_oc) { + av_freep(&vs->vtt_basename); + av_freep(&vs->vtt_m3u8_name); + } + + hls_free_segments(vs->segments); + hls_free_segments(vs->old_segments); + av_freep(&vs->m3u8_name); + av_freep(&vs->streams); + av_freep(&vs->agroup); + av_freep(&vs->language); + av_freep(&vs->ccgroup); + av_freep(&vs->baseurl); + av_freep(&vs->varname); + } +} + static int hls_write_trailer(struct AVFormatContext *s) { HLSContext *hls = s->priv_data; AVFormatContext *oc = NULL; AVFormatContext *vtt_oc = NULL; char *old_filename = NULL; + const char *proto = NULL; + int use_temp_file = 0; int i; int ret = 0; VariantStream *vs = NULL; @@ -2360,12 +2537,32 @@ static int hls_write_trailer(struct AVFormatContext *s) oc = vs->avf; vtt_oc = vs->vtt_avf; old_filename = av_strdup(vs->avf->url); + use_temp_file = 0; if (!old_filename) { return AVERROR(ENOMEM); } if ( hls->segment_type == SEGMENT_TYPE_FMP4) { int range_length = 0; + if (!vs->init_range_length) { + uint8_t *buffer = NULL; + int range_length, byterange_mode; + av_write_frame(vs->avf, NULL); /* Flush any buffered data */ + avio_flush(oc->pb); + + range_length = avio_close_dyn_buf(oc->pb, &buffer); + avio_write(vs->out, buffer, range_length); + av_free(buffer); + vs->init_range_length = range_length; + avio_open_dyn_buf(&oc->pb); + vs->packets_written = 0; + vs->start_pos = range_length; + byterange_mode = (hls->flags & HLS_SINGLE_FILE) || (hls->max_seg_size > 0); + if (!byterange_mode) { + ff_format_io_close(s, &vs->out); + hlsenc_io_close(s, &vs->out, vs->base_output_dirname); + } + } if (!(hls->flags & HLS_SINGLE_FILE)) { ret = hlsenc_io_open(s, &vs->out, vs->avf->url, NULL); if (ret < 0) { @@ -2378,21 +2575,26 @@ static int hls_write_trailer(struct AVFormatContext *s) if (ret < 0) { goto failed; } + vs->size = range_length; ff_format_io_close(s, &vs->out); } failed: av_write_trailer(oc); + + if (oc->url[0]) { + proto = avio_find_protocol_name(oc->url); + use_temp_file = proto && !strcmp(proto, "file") && (hls->flags & HLS_TEMP_FILE); + } + if (oc->pb) { if (hls->segment_type != SEGMENT_TYPE_FMP4) { vs->size = avio_tell(vs->avf->pb) - vs->start_pos; - } else { - vs->size = avio_tell(vs->avf->pb); + hlsenc_io_close(s, &vs->avf->pb, vs->avf->url); } - if (hls->segment_type != SEGMENT_TYPE_FMP4) - ff_format_io_close(s, &oc->pb); - if ((hls->flags & HLS_TEMP_FILE) && oc->url[0]) { + // rename that segment from .tmp to the real one + if (use_temp_file && !(hls->flags & HLS_SINGLE_FILE)) { hls_rename_temp_file(s, oc); av_free(old_filename); old_filename = av_strdup(vs->avf->url); @@ -2413,31 +2615,17 @@ failed: av_write_trailer(vtt_oc); vs->size = avio_tell(vs->vtt_avf->pb) - vs->start_pos; ff_format_io_close(s, &vtt_oc->pb); + avformat_free_context(vtt_oc); } - av_freep(&vs->basename); - av_freep(&vs->base_output_dirname); + hls_window(s, 1, vs); avformat_free_context(oc); vs->avf = NULL; - hls_window(s, 1, vs); - - av_freep(&vs->fmp4_init_filename); - if (vtt_oc) { - av_freep(&vs->vtt_basename); - av_freep(&vs->vtt_m3u8_name); - avformat_free_context(vtt_oc); - } - - hls_free_segments(vs->segments); - hls_free_segments(vs->old_segments); av_free(old_filename); - av_freep(&vs->m3u8_name); - av_freep(&vs->streams); - av_freep(&vs->agroup); - av_freep(&vs->ccgroup); - av_freep(&vs->baseurl); } + hls_free_variant_streams(hls); + for (i = 0; i < hls->nb_ccstreams; i++) { ClosedCaptionsStream *ccs = &hls->cc_streams[i]; av_freep(&ccs->ccgroup); @@ -2470,6 +2658,8 @@ static int hls_init(AVFormatContext *s) int vtt_basename_size = 0; int fmp4_init_filename_len = strlen(hls->fmp4_init_filename) + 1; + hls->has_default_key = 0; + hls->has_video_m3u8 = 0; ret = update_variant_stream_info(s); if (ret < 0) { av_log(s, AV_LOG_ERROR, "Variant stream info update failed with status %x\n", @@ -2538,12 +2728,7 @@ static int hls_init(AVFormatContext *s) for (i = 0; i < hls->nb_varstreams; i++) { vs = &hls->var_streams[i]; - vs->m3u8_name = av_strdup(s->url); - if (!vs->m3u8_name ) { - ret = AVERROR(ENOMEM); - goto fail; - } - ret = format_name(vs->m3u8_name, strlen(s->url) + 1, i); + ret = format_name(s->url, &vs->m3u8_name, i, vs->varname); if (ret < 0) goto fail; @@ -2604,17 +2789,10 @@ static int hls_init(AVFormatContext *s) } } if (hls->segment_filename) { - basename_size = strlen(hls->segment_filename) + 1; - vs->basename = av_malloc(basename_size); - if (!vs->basename) { - ret = AVERROR(ENOMEM); - goto fail; - } - - av_strlcpy(vs->basename, hls->segment_filename, basename_size); - ret = format_name(vs->basename, basename_size, i); + ret = format_name(hls->segment_filename, &vs->basename, i, vs->varname); if (ret < 0) goto fail; + basename_size = strlen(vs->basename) + 1; } else { if (hls->flags & HLS_SINGLE_FILE) { if (hls->segment_type == SEGMENT_TYPE_FMP4) { @@ -2666,7 +2844,12 @@ static int hls_init(AVFormatContext *s) av_strlcpy(vs->fmp4_init_filename, hls->fmp4_init_filename, fmp4_init_filename_len); if (hls->nb_varstreams > 1) { - ret = append_postfix(vs->fmp4_init_filename, fmp4_init_filename_len, i); + if (av_stristr(vs->fmp4_init_filename, "%v")) { + av_freep(&vs->fmp4_init_filename); + format_name(hls->fmp4_init_filename, &vs->fmp4_init_filename, i, vs->varname); + } else { + ret = append_postfix(vs->fmp4_init_filename, fmp4_init_filename_len, i); + } if (ret < 0) goto fail; } @@ -2727,8 +2910,8 @@ static int hls_init(AVFormatContext *s) *p = '\0'; if ( hls->subtitle_filename ) { - strcpy(vs->vtt_m3u8_name, hls->subtitle_filename); - ret = format_name(vs->vtt_m3u8_name, vtt_basename_size, i); + av_freep(&vs->vtt_m3u8_name); + ret = format_name(hls->subtitle_filename, &vs->vtt_m3u8_name, i, vs->varname); if (ret < 0) goto fail; } else { @@ -2775,9 +2958,11 @@ fail: av_freep(&vs->m3u8_name); av_freep(&vs->vtt_m3u8_name); av_freep(&vs->streams); + av_freep(&vs->language); av_freep(&vs->agroup); av_freep(&vs->ccgroup); av_freep(&vs->baseurl); + av_freep(&vs->varname); if (vs->avf) avformat_free_context(vs->avf); if (vs->vtt_avf) @@ -2826,7 +3011,7 @@ static const AVOption options[] = { {"hls_fmp4_init_filename", "set fragment mp4 file init filename", OFFSET(fmp4_init_filename), AV_OPT_TYPE_STRING, {.str = "init.mp4"}, 0, 0, E}, {"hls_flags", "set flags affecting HLS playlist and media file generation", OFFSET(flags), AV_OPT_TYPE_FLAGS, {.i64 = 0 }, 0, UINT_MAX, E, "flags"}, {"single_file", "generate a single media file indexed with byte ranges", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_SINGLE_FILE }, 0, UINT_MAX, E, "flags"}, - {"temp_file", "write segment to temporary file and rename when complete", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_TEMP_FILE }, 0, UINT_MAX, E, "flags"}, + {"temp_file", "write segment and playlist to temporary file and rename when complete", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_TEMP_FILE }, 0, UINT_MAX, E, "flags"}, {"delete_segments", "delete segment files that are no longer part of the playlist", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_DELETE_SEGMENTS }, 0, UINT_MAX, E, "flags"}, {"round_durations", "round durations in m3u8 to whole numbers", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_ROUND_DURATIONS }, 0, UINT_MAX, E, "flags"}, {"discont_start", "start the playlist with a discontinuity tag", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_DISCONT_START }, 0, UINT_MAX, E, "flags"}, @@ -2839,8 +3024,15 @@ static const AVOption options[] = { {"second_level_segment_size", "include segment size in segment filenames when use_localtime", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_SECOND_LEVEL_SEGMENT_SIZE }, 0, UINT_MAX, E, "flags"}, {"periodic_rekey", "reload keyinfo file periodically for re-keying", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_PERIODIC_REKEY }, 0, UINT_MAX, E, "flags"}, {"independent_segments", "add EXT-X-INDEPENDENT-SEGMENTS, whenever applicable", 0, AV_OPT_TYPE_CONST, { .i64 = HLS_INDEPENDENT_SEGMENTS }, 0, UINT_MAX, E, "flags"}, - {"use_localtime", "set filename expansion with strftime at segment creation", OFFSET(use_localtime), AV_OPT_TYPE_BOOL, {.i64 = 0 }, 0, 1, E }, - {"use_localtime_mkdir", "create last directory component in strftime-generated filename", OFFSET(use_localtime_mkdir), AV_OPT_TYPE_BOOL, {.i64 = 0 }, 0, 1, E }, + {"iframes_only", "add EXT-X-I-FRAMES-ONLY, whenever applicable", 0, AV_OPT_TYPE_CONST, { .i64 = HLS_I_FRAMES_ONLY }, 0, UINT_MAX, E, "flags"}, +#if FF_API_HLS_USE_LOCALTIME + {"use_localtime", "set filename expansion with strftime at segment creation(will be deprecated )", OFFSET(use_localtime), AV_OPT_TYPE_BOOL, {.i64 = 0 }, 0, 1, E }, +#endif + {"strftime", "set filename expansion with strftime at segment creation", OFFSET(use_localtime), AV_OPT_TYPE_BOOL, {.i64 = 0 }, 0, 1, E }, +#if FF_API_HLS_USE_LOCALTIME + {"use_localtime_mkdir", "create last directory component in strftime-generated filename(will be deprecated)", OFFSET(use_localtime_mkdir), AV_OPT_TYPE_BOOL, {.i64 = 0 }, 0, 1, E }, +#endif + {"strftime_mkdir", "create last directory component in strftime-generated filename", OFFSET(use_localtime_mkdir), AV_OPT_TYPE_BOOL, {.i64 = 0 }, 0, 1, E }, {"hls_playlist_type", "set the HLS playlist type", OFFSET(pl_type), AV_OPT_TYPE_INT, {.i64 = PLAYLIST_TYPE_NONE }, 0, PLAYLIST_TYPE_NB-1, E, "pl_type" }, {"event", "EVENT playlist", 0, AV_OPT_TYPE_CONST, {.i64 = PLAYLIST_TYPE_EVENT }, INT_MIN, INT_MAX, E, "pl_type" }, {"vod", "VOD playlist", 0, AV_OPT_TYPE_CONST, {.i64 = PLAYLIST_TYPE_VOD }, INT_MIN, INT_MAX, E, "pl_type" }, @@ -2856,6 +3048,8 @@ static const AVOption options[] = { {"master_pl_publish_rate", "Publish master play list every after this many segment intervals", OFFSET(master_publish_rate), AV_OPT_TYPE_INT, {.i64 = 0}, 0, UINT_MAX, E}, {"http_persistent", "Use persistent HTTP connections", OFFSET(http_persistent), AV_OPT_TYPE_BOOL, {.i64 = 0 }, 0, 1, E }, {"timeout", "set timeout for socket I/O operations", OFFSET(timeout), AV_OPT_TYPE_DURATION, { .i64 = -1 }, -1, INT_MAX, .flags = E }, + {"ignore_io_errors", "Ignore IO errors for stable long-duration runs with network output", OFFSET(ignore_io_errors), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, E }, + {"headers", "set custom HTTP headers, can override built in default headers", OFFSET(headers), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, E }, { NULL }, }; @@ -2875,7 +3069,7 @@ AVOutputFormat ff_hls_muxer = { .audio_codec = AV_CODEC_ID_AAC, .video_codec = AV_CODEC_ID_H264, .subtitle_codec = AV_CODEC_ID_WEBVTT, - .flags = AVFMT_NOFILE | AVFMT_GLOBALHEADER | AVFMT_ALLOW_FLUSH, + .flags = AVFMT_NOFILE | AVFMT_GLOBALHEADER | AVFMT_ALLOW_FLUSH | AVFMT_NODIMENSIONS, .init = hls_init, .write_header = hls_write_header, .write_packet = hls_write_packet, diff --git a/libavformat/hlsplaylist.c b/libavformat/hlsplaylist.c index efcbff000..e8b566789 100644 --- a/libavformat/hlsplaylist.c +++ b/libavformat/hlsplaylist.c @@ -36,13 +36,16 @@ void ff_hls_write_playlist_version(AVIOContext *out, int version) { } void ff_hls_write_audio_rendition(AVIOContext *out, char *agroup, - char *filename, int name_id, int is_default) { + char *filename, char *language, int name_id, int is_default) { if (!out || !agroup || !filename) return; avio_printf(out, "#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID=\"group_%s\"", agroup); - avio_printf(out, ",NAME=\"audio_%d\",DEFAULT=%s,URI=\"%s\"\n", name_id, - is_default ? "YES" : "NO", filename); + avio_printf(out, ",NAME=\"audio_%d\",DEFAULT=%s,", name_id, is_default ? "YES" : "NO"); + if (language) { + avio_printf(out, "LANGUAGE=\"%s\",", language); + } + avio_printf(out, "URI=\"%s\"\n", filename); } void ff_hls_write_stream_info(AVStream *st, AVIOContext *out, @@ -73,7 +76,7 @@ void ff_hls_write_stream_info(AVStream *st, AVIOContext *out, void ff_hls_write_playlist_header(AVIOContext *out, int version, int allowcache, int target_duration, int64_t sequence, - uint32_t playlist_type) { + uint32_t playlist_type, int iframe_mode) { if (!out) return; ff_hls_write_playlist_version(out, version); @@ -89,6 +92,9 @@ void ff_hls_write_playlist_header(AVIOContext *out, int version, int allowcache, } else if (playlist_type == PLAYLIST_TYPE_VOD) { avio_printf(out, "#EXT-X-PLAYLIST-TYPE:VOD\n"); } + if (iframe_mode) { + avio_printf(out, "#EXT-X-I-FRAMES-ONLY\n"); + } } void ff_hls_write_init_file(AVIOContext *out, char *filename, @@ -105,7 +111,8 @@ int ff_hls_write_file_entry(AVIOContext *out, int insert_discont, double duration, int round_duration, int64_t size, int64_t pos, //Used only if HLS_SINGLE_FILE flag is set char *baseurl, //Ignored if NULL - char *filename, double *prog_date_time) { + char *filename, double *prog_date_time, + int64_t video_keyframe_size, int64_t video_keyframe_pos, int iframe_mode) { if (!out || !filename) return AVERROR(EINVAL); @@ -117,7 +124,8 @@ int ff_hls_write_file_entry(AVIOContext *out, int insert_discont, else avio_printf(out, "#EXTINF:%f,\n", duration); if (byterange_mode) - avio_printf(out, "#EXT-X-BYTERANGE:%"PRId64"@%"PRId64"\n", size, pos); + avio_printf(out, "#EXT-X-BYTERANGE:%"PRId64"@%"PRId64"\n", iframe_mode ? video_keyframe_size : size, + iframe_mode ? video_keyframe_pos : pos); if (prog_date_time) { time_t tt, wrongsecs; diff --git a/libavformat/hlsplaylist.h b/libavformat/hlsplaylist.h index 5054b01c8..8d2d83b66 100644 --- a/libavformat/hlsplaylist.h +++ b/libavformat/hlsplaylist.h @@ -38,13 +38,13 @@ typedef enum { void ff_hls_write_playlist_version(AVIOContext *out, int version); void ff_hls_write_audio_rendition(AVIOContext *out, char *agroup, - char *filename, int name_id, int is_default); + char *filename, char *language, int name_id, int is_default); void ff_hls_write_stream_info(AVStream *st, AVIOContext *out, int bandwidth, char *filename, char *agroup, char *codecs, char *ccgroup); void ff_hls_write_playlist_header(AVIOContext *out, int version, int allowcache, int target_duration, int64_t sequence, - uint32_t playlist_type); + uint32_t playlist_type, int iframe_mode); void ff_hls_write_init_file(AVIOContext *out, char *filename, int byterange_mode, int64_t size, int64_t pos); int ff_hls_write_file_entry(AVIOContext *out, int insert_discont, @@ -52,7 +52,8 @@ int ff_hls_write_file_entry(AVIOContext *out, int insert_discont, double duration, int round_duration, int64_t size, int64_t pos, //Used only if HLS_SINGLE_FILE flag is set char *baseurl, //Ignored if NULL - char *filename, double *prog_date_time); + char *filename, double *prog_date_time, + int64_t video_keyframe_size, int64_t video_keyframe_pos, int iframe_mode); void ff_hls_write_end_list (AVIOContext *out); #endif /* AVFORMAT_HLSPLAYLIST_H_ */ diff --git a/libavformat/hlsproto.c b/libavformat/hlsproto.c index e7ef2d88e..e5673e5e0 100644 --- a/libavformat/hlsproto.c +++ b/libavformat/hlsproto.c @@ -295,7 +295,7 @@ retry: } goto retry; } - url = s->segments[s->cur_seq_no - s->start_seq_no]->url, + url = s->segments[s->cur_seq_no - s->start_seq_no]->url; av_log(h, AV_LOG_DEBUG, "opening %s\n", url); ret = ffurl_open_whitelist(&s->seg_hd, url, AVIO_FLAG_READ, &h->interrupt_callback, NULL, diff --git a/libavformat/hnm.c b/libavformat/hnm.c index 24d4e808a..40ef5c06e 100644 --- a/libavformat/hnm.c +++ b/libavformat/hnm.c @@ -52,7 +52,7 @@ typedef struct Hnm4DemuxContext { AVPacket vpkt; } Hnm4DemuxContext; -static int hnm_probe(AVProbeData *p) +static int hnm_probe(const AVProbeData *p) { if (p->buf_size < 4) return 0; diff --git a/libavformat/http.c b/libavformat/http.c index 954eee3ba..579debcd3 100644 --- a/libavformat/http.c +++ b/libavformat/http.c @@ -113,6 +113,7 @@ typedef struct HTTPContext { uint8_t *inflate_buffer; #endif /* CONFIG_ZLIB */ AVDictionary *chained_options; + /* -1 = try to send if applicable, 0 = always disabled, 1 = always enabled */ int send_expect_100; char *method; int reconnect; @@ -141,7 +142,7 @@ static const AVOption options[] = { { "user_agent", "override User-Agent header", OFFSET(user_agent), AV_OPT_TYPE_STRING, { .str = DEFAULT_USER_AGENT }, 0, 0, D }, { "referer", "override referer header", OFFSET(referer), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, D }, #if FF_API_HTTP_USER_AGENT - { "user-agent", "override User-Agent header", OFFSET(user_agent_deprecated), AV_OPT_TYPE_STRING, { .str = DEFAULT_USER_AGENT }, 0, 0, D }, + { "user-agent", "use the \"user_agent\" option instead", OFFSET(user_agent_deprecated), AV_OPT_TYPE_STRING, { .str = DEFAULT_USER_AGENT }, 0, 0, D|AV_OPT_FLAG_DEPRECATED }, #endif { "multiple_requests", "use persistent connections", OFFSET(multiple_requests), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, D | E }, { "post_data", "set custom HTTP post data", OFFSET(post_data), AV_OPT_TYPE_BINARY, .flags = D | E }, @@ -155,7 +156,7 @@ static const AVOption options[] = { { "auth_type", "HTTP authentication type", OFFSET(auth_state.auth_type), AV_OPT_TYPE_INT, { .i64 = HTTP_AUTH_NONE }, HTTP_AUTH_NONE, HTTP_AUTH_BASIC, D | E, "auth_type"}, { "none", "No auth method set, autodetect", 0, AV_OPT_TYPE_CONST, { .i64 = HTTP_AUTH_NONE }, 0, 0, D | E, "auth_type"}, { "basic", "HTTP basic authentication", 0, AV_OPT_TYPE_CONST, { .i64 = HTTP_AUTH_BASIC }, 0, 0, D | E, "auth_type"}, - { "send_expect_100", "Force sending an Expect: 100-continue header for POST", OFFSET(send_expect_100), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, E }, + { "send_expect_100", "Force sending an Expect: 100-continue header for POST", OFFSET(send_expect_100), AV_OPT_TYPE_BOOL, { .i64 = -1 }, -1, 1, E }, { "location", "The actual location of the data received", OFFSET(location), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, D | E }, { "offset", "initial byte offset", OFFSET(off), AV_OPT_TYPE_INT64, { .i64 = 0 }, 0, INT64_MAX, D }, { "end_offset", "try to limit the request to bytes preceding this offset", OFFSET(end_off), AV_OPT_TYPE_INT64, { .i64 = 0 }, 0, INT64_MAX, D }, @@ -541,7 +542,7 @@ static int http_open(URLContext *h, const char *uri, int flags, int len = strlen(s->headers); if (len < 2 || strcmp("\r\n", s->headers + len - 2)) { av_log(h, AV_LOG_WARNING, - "No trailing CRLF found in HTTP header.\n"); + "No trailing CRLF found in HTTP header. Adding it.\n"); ret = av_reallocp(&s->headers, len + 3); if (ret < 0) return ret; @@ -1019,7 +1020,8 @@ static int process_line(URLContext *h, char *line, int line_count, /** * Create a string containing cookie values for use as a HTTP cookie header * field value for a particular path and domain from the cookie values stored in - * the HTTP protocol context. The cookie string is stored in *cookies. + * the HTTP protocol context. The cookie string is stored in *cookies, and may + * be NULL if there are no valid cookies. * * @return a negative value if an error condition occurred, 0 otherwise */ @@ -1029,15 +1031,20 @@ static int get_cookies(HTTPContext *s, char **cookies, const char *path, // cookie strings will look like Set-Cookie header field values. Multiple // Set-Cookie fields will result in multiple values delimited by a newline int ret = 0; - char *cookie, *set_cookies = av_strdup(s->cookies), *next = set_cookies; - - if (!set_cookies) return AVERROR(EINVAL); + char *cookie, *set_cookies, *next; // destroy any cookies in the dictionary. av_dict_free(&s->cookie_dict); + if (!s->cookies) + return 0; + + next = set_cookies = av_strdup(s->cookies); + if (!next) + return AVERROR(ENOMEM); + *cookies = NULL; - while ((cookie = av_strtok(next, "\n", &next))) { + while ((cookie = av_strtok(next, "\n", &next)) && !ret) { AVDictionary *cookie_params = NULL; AVDictionaryEntry *cookie_entry, *e; @@ -1047,23 +1054,19 @@ static int get_cookies(HTTPContext *s, char **cookies, const char *path, // continue on to the next cookie if this one cannot be parsed if (parse_set_cookie(cookie, &cookie_params)) - continue; + goto skip_cookie; // if the cookie has no value, skip it cookie_entry = av_dict_get(cookie_params, "", NULL, AV_DICT_IGNORE_SUFFIX); - if (!cookie_entry || !cookie_entry->value) { - av_dict_free(&cookie_params); - continue; - } + if (!cookie_entry || !cookie_entry->value) + goto skip_cookie; // if the cookie has expired, don't add it if ((e = av_dict_get(cookie_params, "expires", NULL, 0)) && e->value) { struct tm tm_buf = {0}; if (!parse_set_cookie_expiry_time(e->value, &tm_buf)) { - if (av_timegm(&tm_buf) < av_gettime() / 1000000) { - av_dict_free(&cookie_params); - continue; - } + if (av_timegm(&tm_buf) < av_gettime() / 1000000) + goto skip_cookie; } } @@ -1071,42 +1074,32 @@ static int get_cookies(HTTPContext *s, char **cookies, const char *path, if ((e = av_dict_get(cookie_params, "domain", NULL, 0)) && e->value) { // find the offset comparison is on the min domain (b.com, not a.b.com) int domain_offset = strlen(domain) - strlen(e->value); - if (domain_offset < 0) { - av_dict_free(&cookie_params); - continue; - } + if (domain_offset < 0) + goto skip_cookie; // match the cookie domain - if (av_strcasecmp(&domain[domain_offset], e->value)) { - av_dict_free(&cookie_params); - continue; - } + if (av_strcasecmp(&domain[domain_offset], e->value)) + goto skip_cookie; } // ensure this cookie matches the path e = av_dict_get(cookie_params, "path", NULL, 0); - if (!e || av_strncasecmp(path, e->value, strlen(e->value))) { - av_dict_free(&cookie_params); - continue; - } + if (!e || av_strncasecmp(path, e->value, strlen(e->value))) + goto skip_cookie; // cookie parameters match, so copy the value if (!*cookies) { - if (!(*cookies = av_asprintf("%s=%s", cookie_entry->key, cookie_entry->value))) { - ret = AVERROR(ENOMEM); - break; - } + *cookies = av_asprintf("%s=%s", cookie_entry->key, cookie_entry->value); } else { char *tmp = *cookies; - size_t str_size = strlen(cookie_entry->key) + strlen(cookie_entry->value) + strlen(*cookies) + 4; - if (!(*cookies = av_malloc(str_size))) { - ret = AVERROR(ENOMEM); - av_free(tmp); - break; - } - snprintf(*cookies, str_size, "%s; %s=%s", tmp, cookie_entry->key, cookie_entry->value); + *cookies = av_asprintf("%s; %s=%s", tmp, cookie_entry->key, cookie_entry->value); av_free(tmp); } + if (!*cookies) + ret = AVERROR(ENOMEM); + + skip_cookie: + av_dict_free(&cookie_params); } av_free(set_cookies); @@ -1187,21 +1180,25 @@ static int http_connect(URLContext *h, const char *path, const char *local_path, local_path, method); proxyauthstr = ff_http_auth_create_response(&s->proxy_auth_state, proxyauth, local_path, method); - if (post && !s->post_data) { - send_expect_100 = s->send_expect_100; - /* The user has supplied authentication but we don't know the auth type, - * send Expect: 100-continue to get the 401 response including the - * WWW-Authenticate header, or an 100 continue if no auth actually - * is needed. */ - if (auth && *auth && - s->auth_state.auth_type == HTTP_AUTH_NONE && - s->http_code != 401) - send_expect_100 = 1; + + if (post && !s->post_data) { + if (s->send_expect_100 != -1) { + send_expect_100 = s->send_expect_100; + } else { + send_expect_100 = 0; + /* The user has supplied authentication but we don't know the auth type, + * send Expect: 100-continue to get the 401 response including the + * WWW-Authenticate header, or an 100 continue if no auth actually + * is needed. */ + if (auth && *auth && + s->auth_state.auth_type == HTTP_AUTH_NONE && + s->http_code != 401) + send_expect_100 = 1; + } } #if FF_API_HTTP_USER_AGENT if (strcmp(s->user_agent_deprecated, DEFAULT_USER_AGENT)) { - av_log(s, AV_LOG_WARNING, "the user-agent option is deprecated, please use user_agent option\n"); s->user_agent = av_strdup(s->user_agent_deprecated); } #endif @@ -1513,12 +1510,13 @@ static int http_read_stream_all(URLContext *h, uint8_t *buf, int size) return pos; } -static void update_metadata(HTTPContext *s, char *data) +static void update_metadata(URLContext *h, char *data) { char *key; char *val; char *end; char *next = data; + HTTPContext *s = h->priv_data; while (*next) { key = next; @@ -1534,6 +1532,7 @@ static void update_metadata(HTTPContext *s, char *data) val += 2; av_dict_set(&s->metadata, key, val, 0); + av_log(h, AV_LOG_VERBOSE, "Metadata update for %s: %s\n", key, val); next = end + 2; } @@ -1568,7 +1567,7 @@ static int store_icy(URLContext *h, int size) data[len + 1] = 0; if ((ret = av_opt_set(s, "icy_metadata_packet", data, 0)) < 0) return ret; - update_metadata(s, data); + update_metadata(h, data); } s->icy_data_read = 0; remaining = s->icy_metaint; @@ -1631,6 +1630,18 @@ static int http_shutdown(URLContext *h, int flags) ((flags & AVIO_FLAG_READ) && s->chunked_post && s->listen)) { ret = ffurl_write(s->hd, footer, sizeof(footer) - 1); ret = ret > 0 ? 0 : ret; + /* flush the receive buffer when it is write only mode */ + if (!(flags & AVIO_FLAG_READ)) { + char buf[1024]; + int read_ret; + s->hd->flags |= AVIO_FLAG_NONBLOCK; + read_ret = ffurl_read(s->hd, buf, sizeof(buf)); + s->hd->flags &= ~AVIO_FLAG_NONBLOCK; + if (read_ret < 0 && read_ret != AVERROR(EAGAIN)) { + av_log(h, AV_LOG_ERROR, "URL read error: %s\n", av_err2str(read_ret)); + ret = read_ret; + } + } s->end_chunked_post = 1; } @@ -1647,7 +1658,7 @@ static int http_close(URLContext *h) av_freep(&s->inflate_buffer); #endif /* CONFIG_ZLIB */ - if (!s->end_chunked_post) + if (s->hd && !s->end_chunked_post) /* Close the write direction by sending the end of chunked encoding. */ ret = http_shutdown(h, h->flags); @@ -1688,6 +1699,13 @@ static int64_t http_seek_internal(URLContext *h, int64_t off, int whence, int fo if (s->off && h->is_streamed) return AVERROR(ENOSYS); + /* do not try to make a new connection if seeking past the end of the file */ + if (s->end_off || s->filesize != UINT64_MAX) { + uint64_t end_pos = s->end_off ? s->end_off : s->filesize; + if (s->off >= end_pos) + return s->off; + } + /* we save the old context in case the seek fails */ old_buf_size = s->buf_end - s->buf_ptr; memcpy(old_buf, s->buf_ptr, old_buf_size); diff --git a/libavformat/icecast.c b/libavformat/icecast.c index 02e3e3878..d2198b78e 100644 --- a/libavformat/icecast.c +++ b/libavformat/icecast.c @@ -96,7 +96,7 @@ static int icecast_open(URLContext *h, const char *uri, int flags) if (flags & AVIO_FLAG_READ) return AVERROR(ENOSYS); - av_bprint_init(&bp, 0, 1); + av_bprint_init(&bp, 0, AV_BPRINT_SIZE_AUTOMATIC); // Build header strings cat_header(&bp, "Ice-Name", s->name); @@ -115,7 +115,7 @@ static int icecast_open(URLContext *h, const char *uri, int flags) av_dict_set(&opt_dict, "auth_type", "basic", 0); av_dict_set(&opt_dict, "headers", headers, 0); av_dict_set(&opt_dict, "chunked_post", "0", 0); - av_dict_set(&opt_dict, "send_expect_100", s->legacy_icecast ? "0" : "1", 0); + av_dict_set(&opt_dict, "send_expect_100", s->legacy_icecast ? "-1" : "1", 0); if (NOT_EMPTY(s->content_type)) av_dict_set(&opt_dict, "content_type", s->content_type, 0); else diff --git a/libavformat/icodec.c b/libavformat/icodec.c index f33fa1195..98684e5e7 100644 --- a/libavformat/icodec.c +++ b/libavformat/icodec.c @@ -43,7 +43,7 @@ typedef struct { IcoImage * images; } IcoDemuxContext; -static int probe(AVProbeData *p) +static int probe(const AVProbeData *p) { unsigned i, frames, checked = 0; @@ -96,8 +96,10 @@ static int read_header(AVFormatContext *s) break; st = avformat_new_stream(s, NULL); - if (!st) + if (!st) { + av_freep(&ico->images); return AVERROR(ENOMEM); + } st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO; st->codecpar->width = avio_r8(pb); @@ -111,6 +113,7 @@ static int read_header(AVFormatContext *s) ico->images[i].size = avio_rl32(pb); if (ico->images[i].size <= 0) { av_log(s, AV_LOG_ERROR, "Invalid image size %d\n", ico->images[i].size); + av_freep(&ico->images); return AVERROR_INVALIDDATA; } ico->images[i].offset = avio_rl32(pb); @@ -126,8 +129,10 @@ static int read_header(AVFormatContext *s) st->codecpar->height = 0; break; case 40: - if (ico->images[i].size < 40) + if (ico->images[i].size < 40) { + av_freep(&ico->images); return AVERROR_INVALIDDATA; + } st->codecpar->codec_id = AV_CODEC_ID_BMP; tmp = avio_rl32(pb); if (tmp) @@ -138,6 +143,7 @@ static int read_header(AVFormatContext *s) break; default: avpriv_request_sample(s, "codec %d", codec); + av_freep(&ico->images); return AVERROR_INVALIDDATA; } } diff --git a/libavformat/id3v2.c b/libavformat/id3v2.c index 5fe055b59..b43ab1745 100644 --- a/libavformat/id3v2.c +++ b/libavformat/id3v2.c @@ -36,6 +36,7 @@ #include "libavutil/bprint.h" #include "libavutil/dict.h" #include "libavutil/intreadwrite.h" +#include "libavcodec/png.h" #include "avio_internal.h" #include "internal.h" #include "id3v1.h" @@ -1158,7 +1159,7 @@ int ff_id3v2_parse_apic(AVFormatContext *s, ID3v2ExtraMeta **extra_meta) st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO; st->codecpar->codec_id = apic->id; - if (AV_RB64(apic->buf->data) == 0x89504e470d0a1a0a) + if (AV_RB64(apic->buf->data) == PNGSIG) st->codecpar->codec_id = AV_CODEC_ID_PNG; if (apic->description[0]) diff --git a/libavformat/id3v2enc.c b/libavformat/id3v2enc.c index ffe358f01..c13b93a7d 100644 --- a/libavformat/id3v2enc.c +++ b/libavformat/id3v2enc.c @@ -255,6 +255,42 @@ static int write_metadata(AVIOContext *pb, AVDictionary **metadata, return 0; } +static int write_ctoc(AVFormatContext *s, ID3v2EncContext *id3, int enc) +{ + uint8_t *dyn_buf = NULL; + AVIOContext *dyn_bc = NULL; + char name[123]; + int len, ret; + + if (s->nb_chapters == 0) + return 0; + + if ((ret = avio_open_dyn_buf(&dyn_bc)) < 0) + goto fail; + + id3->len += avio_put_str(dyn_bc, "toc"); + avio_w8(dyn_bc, 0x03); + avio_w8(dyn_bc, s->nb_chapters); + for (int i = 0; i < s->nb_chapters; i++) { + snprintf(name, 122, "ch%d", i); + id3->len += avio_put_str(dyn_bc, name); + } + len = avio_close_dyn_buf(dyn_bc, &dyn_buf); + id3->len += 16 + ID3v2_HEADER_SIZE; + + avio_wb32(s->pb, MKBETAG('C', 'T', 'O', 'C')); + avio_wb32(s->pb, len); + avio_wb16(s->pb, 0); + avio_write(s->pb, dyn_buf, len); + +fail: + if (dyn_bc && !dyn_buf) + avio_close_dyn_buf(dyn_bc, &dyn_buf); + av_freep(&dyn_buf); + + return ret; +} + static int write_chapter(AVFormatContext *s, ID3v2EncContext *id3, int id, int enc) { const AVRational time_base = {1, 1000}; @@ -306,6 +342,9 @@ int ff_id3v2_write_metadata(AVFormatContext *s, ID3v2EncContext *id3) if ((ret = write_metadata(s->pb, &s->metadata, id3, enc)) < 0) return ret; + if ((ret = write_ctoc(s, id3, enc)) < 0) + return ret; + for (i = 0; i < s->nb_chapters; i++) { if ((ret = write_chapter(s, id3, i, enc)) < 0) return ret; diff --git a/libavformat/idcin.c b/libavformat/idcin.c index cf69102b2..0b1058171 100644 --- a/libavformat/idcin.c +++ b/libavformat/idcin.c @@ -91,7 +91,7 @@ typedef struct IdcinDemuxContext { int64_t first_pkt_pos; } IdcinDemuxContext; -static int idcin_probe(AVProbeData *p) +static int idcin_probe(const AVProbeData *p) { unsigned int number, sample_rate; unsigned int w, h; diff --git a/libavformat/idroqdec.c b/libavformat/idroqdec.c index 8fd67a681..1db4cce6f 100644 --- a/libavformat/idroqdec.c +++ b/libavformat/idroqdec.c @@ -59,7 +59,7 @@ typedef struct RoqDemuxContext { } RoqDemuxContext; -static int roq_probe(AVProbeData *p) +static int roq_probe(const AVProbeData *p) { if ((AV_RL16(&p->buf[0]) != RoQ_MAGIC_NUMBER) || (AV_RL32(&p->buf[2]) != 0xFFFFFFFF)) diff --git a/libavformat/iff.c b/libavformat/iff.c index 4cf17f6e1..f4d806b7b 100644 --- a/libavformat/iff.c +++ b/libavformat/iff.c @@ -142,7 +142,7 @@ static int get_metadata(AVFormatContext *s, return 0; } -static int iff_probe(AVProbeData *p) +static int iff_probe(const AVProbeData *p) { const uint8_t *d = p->buf; diff --git a/libavformat/ifv.c b/libavformat/ifv.c new file mode 100644 index 000000000..f95e9b0e5 --- /dev/null +++ b/libavformat/ifv.c @@ -0,0 +1,309 @@ +/* + * IFV demuxer + * + * Copyright (c) 2019 Swaraj Hota + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "avformat.h" +#include "internal.h" +#include "avio_internal.h" + +typedef struct IFVContext { + uint32_t next_video_index; + uint32_t next_audio_index; + uint32_t total_vframes; + uint32_t total_aframes; + + int width, height; + int is_audio_present; + int sample_rate; + + int video_stream_index; + int audio_stream_index; +} IFVContext; + +static int ifv_probe(const AVProbeData *p) +{ + static const uint8_t ifv_magic[] = {0x11, 0xd2, 0xd3, 0xab, 0xba, 0xa9, + 0xcf, 0x11, 0x8e, 0xe6, 0x00, 0xc0, 0x0c, 0x20, 0x53, 0x65, 0x44}; + + if (!memcmp(p->buf, ifv_magic, sizeof(ifv_magic))) + return AVPROBE_SCORE_MAX; + + return 0; +} + +static int read_index(AVFormatContext *s, + enum AVMediaType frame_type, + uint32_t start_index) +{ + IFVContext *ifv = s->priv_data; + AVStream *st; + int64_t pos, size, timestamp; + uint32_t end_index, i; + int ret; + + if (frame_type == AVMEDIA_TYPE_VIDEO) { + end_index = ifv->total_vframes; + st = s->streams[ifv->video_stream_index]; + } else { + end_index = ifv->total_aframes; + st = s->streams[ifv->audio_stream_index]; + } + + for (i = start_index; i < end_index; i++) { + if (avio_feof(s->pb)) + return AVERROR_EOF; + pos = avio_rl32(s->pb); + size = avio_rl32(s->pb); + + avio_skip(s->pb, 8); + timestamp = avio_rl32(s->pb); + + ret = av_add_index_entry(st, pos, timestamp, size, 0, 0); + if (ret < 0) + return ret; + + avio_skip(s->pb, frame_type == AVMEDIA_TYPE_VIDEO ? 8: 4); + } + + return 0; +} + +static int parse_header(AVFormatContext *s) +{ + IFVContext *ifv = s->priv_data; + uint32_t aud_magic; + uint32_t vid_magic; + + avio_skip(s->pb, 0x34); + avpriv_dict_set_timestamp(&s->metadata, "creation_time", avio_rl32(s->pb) * 1000000LL); + avio_skip(s->pb, 0x24); + + ifv->width = avio_rl16(s->pb); + ifv->height = avio_rl16(s->pb); + + avio_skip(s->pb, 0x8); + vid_magic = avio_rl32(s->pb); + + if (vid_magic != MKTAG('H','2','6','4')) + avpriv_request_sample(s, "Unknown video codec %x", vid_magic); + + avio_skip(s->pb, 0x2c); + ifv->sample_rate = avio_rl32(s->pb); + aud_magic = avio_rl32(s->pb); + + if (aud_magic == MKTAG('G','R','A','W')) { + ifv->is_audio_present = 1; + } else if (aud_magic == MKTAG('P','C','M','U')) { + ifv->is_audio_present = 0; + } else { + avpriv_request_sample(s, "Unknown audio codec %x", aud_magic); + } + + avio_skip(s->pb, 0x44); + ifv->total_vframes = avio_rl32(s->pb); + ifv->total_aframes = avio_rl32(s->pb); + + return 0; +} + +static int ifv_read_header(AVFormatContext *s) +{ + IFVContext *ifv = s->priv_data; + AVStream *st; + int ret; + + ret = parse_header(s); + if (ret < 0) + return ret; + + st = avformat_new_stream(s, NULL); + if (!st) + return AVERROR(ENOMEM); + + st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO; + st->codecpar->codec_id = AV_CODEC_ID_H264; + st->codecpar->width = ifv->width; + st->codecpar->height = ifv->height; + st->start_time = 0; + ifv->video_stream_index = st->index; + + avpriv_set_pts_info(st, 32, 1, 1000); + + if (ifv->is_audio_present) { + st = avformat_new_stream(s, NULL); + if (!st) + return AVERROR(ENOMEM); + + st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO; + st->codecpar->codec_id = AV_CODEC_ID_PCM_S16LE; + st->codecpar->channels = 1; + st->codecpar->channel_layout = AV_CH_LAYOUT_MONO; + st->codecpar->sample_rate = ifv->sample_rate; + ifv->audio_stream_index = st->index; + + avpriv_set_pts_info(st, 32, 1, 1000); + } + + /*read video index*/ + avio_seek(s->pb, 0xf8, SEEK_SET); + + ret = read_index(s, AVMEDIA_TYPE_VIDEO, 0); + if (ret < 0) + return ret; + + if (ifv->is_audio_present) { + /*read audio index*/ + avio_seek(s->pb, 0x14918, SEEK_SET); + + ret = read_index(s, AVMEDIA_TYPE_AUDIO, 0); + if (ret < 0) + return ret; + } + + ifv->next_video_index = 0; + ifv->next_audio_index = 0; + + return 0; +} + +static int ifv_read_packet(AVFormatContext *s, AVPacket *pkt) +{ + IFVContext *ifv = s->priv_data; + AVStream *st; + AVIndexEntry *ev, *ea, *e_next; + int ret; + + ev = ea = e_next = NULL; + + if (ifv->next_video_index < ifv->total_vframes) { + st = s->streams[ifv->video_stream_index]; + if (ifv->next_video_index < st->nb_index_entries) + e_next = ev = &st->index_entries[ifv->next_video_index]; + } + + if (ifv->is_audio_present && + ifv->next_audio_index < ifv->total_aframes) { + st = s->streams[ifv->audio_stream_index]; + if (ifv->next_audio_index < st->nb_index_entries) { + ea = &st->index_entries[ifv->next_audio_index]; + if (!ev || ea->timestamp < ev->timestamp) + e_next = ea; + } + } + + if (!ev) { + if (ifv->is_audio_present && !ea) { + /*read new video and audio indexes*/ + + ifv->next_video_index = ifv->total_vframes; + ifv->next_audio_index = ifv->total_aframes; + + avio_skip(s->pb, 0x1c); + ifv->total_vframes += avio_rl32(s->pb); + ifv->total_aframes += avio_rl32(s->pb); + avio_skip(s->pb, 0xc); + + if (avio_feof(s->pb)) + return AVERROR_EOF; + + ret = read_index(s, AVMEDIA_TYPE_VIDEO, ifv->next_video_index); + if (ret < 0) + return ret; + + ret = read_index(s, AVMEDIA_TYPE_AUDIO, ifv->next_audio_index); + if (ret < 0) + return ret; + + return 0; + + } else if (!ifv->is_audio_present) { + /*read new video index*/ + + ifv->next_video_index = ifv->total_vframes; + + avio_skip(s->pb, 0x1c); + ifv->total_vframes += avio_rl32(s->pb); + avio_skip(s->pb, 0x10); + + if (avio_feof(s->pb)) + return AVERROR_EOF; + + ret = read_index(s, AVMEDIA_TYPE_VIDEO, ifv->next_video_index); + if (ret < 0) + return ret; + + return 0; + } + } + + if (!e_next) return AVERROR_EOF; + + avio_seek(s->pb, e_next->pos, SEEK_SET); + ret = av_get_packet(s->pb, pkt, e_next->size); + if (ret < 0) + return ret; + + if (e_next == ev) { + ifv->next_video_index++; + pkt->stream_index = ifv->video_stream_index; + } else { + ifv->next_audio_index++; + pkt->stream_index = ifv->audio_stream_index; + } + + pkt->pts = e_next->timestamp; + pkt->pos = e_next->pos; + + return 0; +} + +static int ifv_read_seek(AVFormatContext *s, int stream_index, int64_t ts, int flags) +{ + IFVContext *ifv = s->priv_data; + + for (unsigned i = 0; i < s->nb_streams; i++) { + int index = av_index_search_timestamp(s->streams[i], ts, AVSEEK_FLAG_ANY); + if (index < 0) { + ifv->next_video_index = ifv->total_vframes - 1; + ifv->next_audio_index = ifv->total_aframes - 1; + return 0; + } + + if (i == ifv->video_stream_index) { + ifv->next_video_index = index; + } else { + ifv->next_audio_index = index; + } + } + + return 0; +} + +AVInputFormat ff_ifv_demuxer = { + .name = "ifv", + .long_name = NULL_IF_CONFIG_SMALL("IFV CCTV DVR"), + .priv_data_size = sizeof(IFVContext), + .extensions = "ifv", + .read_probe = ifv_probe, + .read_header = ifv_read_header, + .read_packet = ifv_read_packet, + .read_seek = ifv_read_seek, +}; diff --git a/libavformat/ilbc.c b/libavformat/ilbc.c index 50e3c3cc7..ba11953b5 100644 --- a/libavformat/ilbc.c +++ b/libavformat/ilbc.c @@ -59,7 +59,7 @@ static int ilbc_write_packet(AVFormatContext *s, AVPacket *pkt) return 0; } -static int ilbc_probe(AVProbeData *p) +static int ilbc_probe(const AVProbeData *p) { // Only check for "#!iLBC" which matches both formats if (!memcmp(p->buf, mode20_header, 6)) diff --git a/libavformat/img2.c b/libavformat/img2.c index 8432cc095..16bc9d2ab 100644 --- a/libavformat/img2.c +++ b/libavformat/img2.c @@ -51,6 +51,7 @@ const IdStrMap ff_img_tags[] = { { AV_CODEC_ID_TARGA, "tga" }, { AV_CODEC_ID_TIFF, "tiff" }, { AV_CODEC_ID_TIFF, "tif" }, + { AV_CODEC_ID_TIFF, "dng" }, { AV_CODEC_ID_SGI, "sgi" }, { AV_CODEC_ID_PTX, "ptx" }, { AV_CODEC_ID_PCX, "pcx" }, diff --git a/libavformat/img2_alias_pix.c b/libavformat/img2_alias_pix.c index c2650ad1b..2fa3b28e7 100644 --- a/libavformat/img2_alias_pix.c +++ b/libavformat/img2_alias_pix.c @@ -22,7 +22,7 @@ #include "img2.h" #include "libavcodec/bytestream.h" -static int alias_pix_read_probe(AVProbeData *p) +static int alias_pix_read_probe(const AVProbeData *p) { const uint8_t *b = p->buf; const uint8_t *end = b + p->buf_size; diff --git a/libavformat/img2_brender_pix.c b/libavformat/img2_brender_pix.c index ae6b3dd71..b8ac3d2ab 100644 --- a/libavformat/img2_brender_pix.c +++ b/libavformat/img2_brender_pix.c @@ -22,7 +22,7 @@ #include "img2.h" #include "libavutil/intreadwrite.h" -static int brender_read_probe(AVProbeData *p) +static int brender_read_probe(const AVProbeData *p) { static const uint8_t brender_magic[16] = { 0,0,0,0x12,0,0,0,8,0,0,0,2,0,0,0,2 diff --git a/libavformat/img2dec.c b/libavformat/img2dec.c index ffbc9a66d..f8b4a655a 100644 --- a/libavformat/img2dec.c +++ b/libavformat/img2dec.c @@ -29,11 +29,13 @@ #include "libavutil/pixdesc.h" #include "libavutil/parseutils.h" #include "libavutil/intreadwrite.h" +#include "libavcodec/gif.h" #include "avformat.h" #include "avio_internal.h" #include "internal.h" #include "img2.h" #include "libavcodec/mjpeg.h" +#include "libavcodec/xwd.h" #include "subtitles.h" #if HAVE_GLOB @@ -158,7 +160,7 @@ fail: return -1; } -static int img_read_probe(AVProbeData *p) +static int img_read_probe(const AVProbeData *p) { if (p->filename && ff_guess_image2_codec(p->filename)) { if (av_filename_number_test(p->filename)) @@ -354,6 +356,7 @@ int ff_img_read_header(AVFormatContext *s1) } if (s1->flags & AVFMT_FLAG_CUSTOM_IO) { avio_seek(s1->pb, 0, SEEK_SET); + av_freep(&probe_buffer); } else ffio_rewind_with_probe_data(s1->pb, &probe_buffer, probe_buffer_size); } @@ -422,7 +425,7 @@ int ff_img_read_packet(AVFormatContext *s1, AVPacket *pkt) if (par->codec_id == AV_CODEC_ID_NONE) { AVProbeData pd = { 0 }; - AVInputFormat *ifmt; + const AVInputFormat *ifmt; uint8_t header[PROBE_BUF_MIN + AVPROBE_PADDING_SIZE]; int ret; int score = 0; @@ -562,29 +565,29 @@ static int img_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp #define OFFSET(x) offsetof(VideoDemuxData, x) #define DEC AV_OPT_FLAG_DECODING_PARAM -const AVOption ff_img_options[] = { - { "framerate", "set the video framerate", OFFSET(framerate), AV_OPT_TYPE_VIDEO_RATE, {.str = "25"}, 0, INT_MAX, DEC }, - { "loop", "force loop over input file sequence", OFFSET(loop), AV_OPT_TYPE_BOOL, {.i64 = 0 }, 0, 1, DEC }, +#define COMMON_OPTIONS \ + { "framerate", "set the video framerate", OFFSET(framerate), AV_OPT_TYPE_VIDEO_RATE, {.str = "25"}, 0, INT_MAX, DEC }, \ + { "pixel_format", "set video pixel format", OFFSET(pixel_format), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, DEC }, \ + { "video_size", "set video size", OFFSET(width), AV_OPT_TYPE_IMAGE_SIZE, {.str = NULL}, 0, 0, DEC }, \ + { "loop", "force loop over input file sequence", OFFSET(loop), AV_OPT_TYPE_BOOL, {.i64 = 0 }, 0, 1, DEC }, \ + { NULL }, +#if CONFIG_IMAGE2_DEMUXER +const AVOption ff_img_options[] = { { "pattern_type", "set pattern type", OFFSET(pattern_type), AV_OPT_TYPE_INT, {.i64=PT_DEFAULT}, 0, INT_MAX, DEC, "pattern_type"}, { "glob_sequence","select glob/sequence pattern type", 0, AV_OPT_TYPE_CONST, {.i64=PT_GLOB_SEQUENCE}, INT_MIN, INT_MAX, DEC, "pattern_type" }, { "glob", "select glob pattern type", 0, AV_OPT_TYPE_CONST, {.i64=PT_GLOB }, INT_MIN, INT_MAX, DEC, "pattern_type" }, { "sequence", "select sequence pattern type", 0, AV_OPT_TYPE_CONST, {.i64=PT_SEQUENCE }, INT_MIN, INT_MAX, DEC, "pattern_type" }, { "none", "disable pattern matching", 0, AV_OPT_TYPE_CONST, {.i64=PT_NONE }, INT_MIN, INT_MAX, DEC, "pattern_type" }, - - { "pixel_format", "set video pixel format", OFFSET(pixel_format), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, DEC }, { "start_number", "set first number in the sequence", OFFSET(start_number), AV_OPT_TYPE_INT, {.i64 = 0 }, INT_MIN, INT_MAX, DEC }, { "start_number_range", "set range for looking at the first sequence number", OFFSET(start_number_range), AV_OPT_TYPE_INT, {.i64 = 5}, 1, INT_MAX, DEC }, - { "video_size", "set video size", OFFSET(width), AV_OPT_TYPE_IMAGE_SIZE, {.str = NULL}, 0, 0, DEC }, - { "frame_size", "force frame size in bytes", OFFSET(frame_size), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, INT_MAX, DEC }, { "ts_from_file", "set frame timestamp from file's one", OFFSET(ts_from_file), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, 2, DEC, "ts_type" }, { "none", "none", 0, AV_OPT_TYPE_CONST, {.i64 = 0 }, 0, 2, DEC, "ts_type" }, { "sec", "second precision", 0, AV_OPT_TYPE_CONST, {.i64 = 1 }, 0, 2, DEC, "ts_type" }, { "ns", "nano second precision", 0, AV_OPT_TYPE_CONST, {.i64 = 2 }, 0, 2, DEC, "ts_type" }, - { NULL }, + COMMON_OPTIONS }; -#if CONFIG_IMAGE2_DEMUXER static const AVClass img2_class = { .class_name = "image2 demuxer", .item_name = av_default_item_name, @@ -604,11 +607,17 @@ AVInputFormat ff_image2_demuxer = { .priv_class = &img2_class, }; #endif + +const AVOption ff_img2pipe_options[] = { + { "frame_size", "force frame size in bytes", OFFSET(frame_size), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, INT_MAX, DEC }, + COMMON_OPTIONS +}; + #if CONFIG_IMAGE2PIPE_DEMUXER static const AVClass img2pipe_class = { .class_name = "image2pipe demuxer", .item_name = av_default_item_name, - .option = ff_img_options, + .option = ff_img2pipe_options, .version = LIBAVUTIL_VERSION_INT, }; AVInputFormat ff_image2pipe_demuxer = { @@ -621,7 +630,7 @@ AVInputFormat ff_image2pipe_demuxer = { }; #endif -static int bmp_probe(AVProbeData *p) +static int bmp_probe(const AVProbeData *p) { const uint8_t *b = p->buf; int ihsize; @@ -639,7 +648,7 @@ static int bmp_probe(AVProbeData *p) return AVPROBE_SCORE_EXTENSION / 4; } -static int dds_probe(AVProbeData *p) +static int dds_probe(const AVProbeData *p) { const uint8_t *b = p->buf; @@ -650,7 +659,7 @@ static int dds_probe(AVProbeData *p) return 0; } -static int dpx_probe(AVProbeData *p) +static int dpx_probe(const AVProbeData *p) { const uint8_t *b = p->buf; int w, h; @@ -668,7 +677,7 @@ static int dpx_probe(AVProbeData *p) return 0; } -static int exr_probe(AVProbeData *p) +static int exr_probe(const AVProbeData *p) { const uint8_t *b = p->buf; @@ -677,7 +686,7 @@ static int exr_probe(AVProbeData *p) return 0; } -static int j2k_probe(AVProbeData *p) +static int j2k_probe(const AVProbeData *p) { const uint8_t *b = p->buf; @@ -687,7 +696,7 @@ static int j2k_probe(AVProbeData *p) return 0; } -static int jpeg_probe(AVProbeData *p) +static int jpeg_probe(const AVProbeData *p) { const uint8_t *b = p->buf; int i, state = SOI; @@ -762,7 +771,7 @@ static int jpeg_probe(AVProbeData *p) return AVPROBE_SCORE_EXTENSION / 8; } -static int jpegls_probe(AVProbeData *p) +static int jpegls_probe(const AVProbeData *p) { const uint8_t *b = p->buf; @@ -771,7 +780,7 @@ static int jpegls_probe(AVProbeData *p) return 0; } -static int pcx_probe(AVProbeData *p) +static int pcx_probe(const AVProbeData *p) { const uint8_t *b = p->buf; @@ -792,7 +801,7 @@ static int pcx_probe(AVProbeData *p) return AVPROBE_SCORE_EXTENSION + 1; } -static int qdraw_probe(AVProbeData *p) +static int qdraw_probe(const AVProbeData *p) { const uint8_t *b = p->buf; @@ -808,7 +817,7 @@ static int qdraw_probe(AVProbeData *p) return 0; } -static int pictor_probe(AVProbeData *p) +static int pictor_probe(const AVProbeData *p) { const uint8_t *b = p->buf; @@ -817,7 +826,7 @@ static int pictor_probe(AVProbeData *p) return 0; } -static int png_probe(AVProbeData *p) +static int png_probe(const AVProbeData *p) { const uint8_t *b = p->buf; @@ -826,7 +835,7 @@ static int png_probe(AVProbeData *p) return 0; } -static int psd_probe(AVProbeData *p) +static int psd_probe(const AVProbeData *p) { const uint8_t *b = p->buf; int ret = 0; @@ -854,7 +863,7 @@ static int psd_probe(AVProbeData *p) return AVPROBE_SCORE_EXTENSION + ret; } -static int sgi_probe(AVProbeData *p) +static int sgi_probe(const AVProbeData *p) { const uint8_t *b = p->buf; @@ -866,7 +875,7 @@ static int sgi_probe(AVProbeData *p) return 0; } -static int sunrast_probe(AVProbeData *p) +static int sunrast_probe(const AVProbeData *p) { const uint8_t *b = p->buf; @@ -875,7 +884,7 @@ static int sunrast_probe(AVProbeData *p) return 0; } -static int svg_probe(AVProbeData *p) +static int svg_probe(const AVProbeData *p) { const uint8_t *b = p->buf; const uint8_t *end = p->buf + p->buf_size; @@ -895,7 +904,7 @@ static int svg_probe(AVProbeData *p) return 0; } -static int tiff_probe(AVProbeData *p) +static int tiff_probe(const AVProbeData *p) { const uint8_t *b = p->buf; @@ -905,7 +914,7 @@ static int tiff_probe(AVProbeData *p) return 0; } -static int webp_probe(AVProbeData *p) +static int webp_probe(const AVProbeData *p) { const uint8_t *b = p->buf; @@ -933,39 +942,39 @@ static inline int pnm_probe(const AVProbeData *p) return 0; } -static int pbm_probe(AVProbeData *p) +static int pbm_probe(const AVProbeData *p) { return pnm_magic_check(p, 1) || pnm_magic_check(p, 4) ? pnm_probe(p) : 0; } -static inline int pgmx_probe(AVProbeData *p) +static inline int pgmx_probe(const AVProbeData *p) { return pnm_magic_check(p, 2) || pnm_magic_check(p, 5) ? pnm_probe(p) : 0; } -static int pgm_probe(AVProbeData *p) +static int pgm_probe(const AVProbeData *p) { int ret = pgmx_probe(p); return ret && !av_match_ext(p->filename, "pgmyuv") ? ret : 0; } -static int pgmyuv_probe(AVProbeData *p) // custom FFmpeg format recognized by file extension +static int pgmyuv_probe(const AVProbeData *p) // custom FFmpeg format recognized by file extension { int ret = pgmx_probe(p); return ret && av_match_ext(p->filename, "pgmyuv") ? ret : 0; } -static int ppm_probe(AVProbeData *p) +static int ppm_probe(const AVProbeData *p) { return pnm_magic_check(p, 3) || pnm_magic_check(p, 6) ? pnm_probe(p) : 0; } -static int pam_probe(AVProbeData *p) +static int pam_probe(const AVProbeData *p) { return pnm_magic_check(p, 7) ? pnm_probe(p) : 0; } -static int xpm_probe(AVProbeData *p) +static int xpm_probe(const AVProbeData *p) { const uint8_t *b = p->buf; @@ -974,11 +983,54 @@ static int xpm_probe(AVProbeData *p) return 0; } +static int xwd_probe(const AVProbeData *p) +{ + const uint8_t *b = p->buf; + unsigned width, bpp, bpad, lsize; + + if ( p->buf_size < XWD_HEADER_SIZE + || AV_RB32(b ) < XWD_HEADER_SIZE // header size + || AV_RB32(b + 4) != XWD_VERSION // version + || AV_RB32(b + 8) != XWD_Z_PIXMAP // format + || AV_RB32(b + 12) > 32 || !AV_RB32(b + 12) // depth + || AV_RB32(b + 16) == 0 // width + || AV_RB32(b + 20) == 0 // height + || AV_RB32(b + 28) > 1 // byteorder + || AV_RB32(b + 32) & ~56 || av_popcount(AV_RB32(b + 32)) != 1 // bitmap unit + || AV_RB32(b + 36) > 1 // bitorder + || AV_RB32(b + 40) & ~56 || av_popcount(AV_RB32(b + 40)) != 1 // padding + || AV_RB32(b + 44) > 32 || !AV_RB32(b + 44) // bpp + || AV_RB32(b + 68) > 256) // colours + return 0; + + width = AV_RB32(b + 16); + bpad = AV_RB32(b + 40); + bpp = AV_RB32(b + 44); + lsize = AV_RB32(b + 48); + if (lsize < FFALIGN(width * bpp, bpad) >> 3) + return 0; + + return AVPROBE_SCORE_MAX / 2 + 1; +} + +static int gif_probe(const AVProbeData *p) +{ + /* check magick */ + if (memcmp(p->buf, gif87a_sig, 6) && memcmp(p->buf, gif89a_sig, 6)) + return 0; + + /* width or height contains zero? */ + if (!AV_RL16(&p->buf[6]) || !AV_RL16(&p->buf[8])) + return 0; + + return AVPROBE_SCORE_MAX - 1; +} + #define IMAGEAUTO_DEMUXER(imgname, codecid)\ static const AVClass imgname ## _class = {\ .class_name = AV_STRINGIFY(imgname) " demuxer",\ .item_name = av_default_item_name,\ - .option = ff_img_options,\ + .option = ff_img2pipe_options,\ .version = LIBAVUTIL_VERSION_INT,\ };\ AVInputFormat ff_image_ ## imgname ## _pipe_demuxer = {\ @@ -997,6 +1049,7 @@ IMAGEAUTO_DEMUXER(bmp, AV_CODEC_ID_BMP) IMAGEAUTO_DEMUXER(dds, AV_CODEC_ID_DDS) IMAGEAUTO_DEMUXER(dpx, AV_CODEC_ID_DPX) IMAGEAUTO_DEMUXER(exr, AV_CODEC_ID_EXR) +IMAGEAUTO_DEMUXER(gif, AV_CODEC_ID_GIF) IMAGEAUTO_DEMUXER(j2k, AV_CODEC_ID_JPEG2000) IMAGEAUTO_DEMUXER(jpeg, AV_CODEC_ID_MJPEG) IMAGEAUTO_DEMUXER(jpegls, AV_CODEC_ID_JPEGLS) @@ -1016,3 +1069,4 @@ IMAGEAUTO_DEMUXER(svg, AV_CODEC_ID_SVG) IMAGEAUTO_DEMUXER(tiff, AV_CODEC_ID_TIFF) IMAGEAUTO_DEMUXER(webp, AV_CODEC_ID_WEBP) IMAGEAUTO_DEMUXER(xpm, AV_CODEC_ID_XPM) +IMAGEAUTO_DEMUXER(xwd, AV_CODEC_ID_XWD) diff --git a/libavformat/img2enc.c b/libavformat/img2enc.c index a09cc8ec5..bec4bf81d 100644 --- a/libavformat/img2enc.c +++ b/libavformat/img2enc.c @@ -110,7 +110,8 @@ static int write_packet(AVFormatContext *s, AVPacket *pkt) AV_FRAME_FILENAME_FLAGS_MULTIPLE) < 0 && img->img_number > 1) { av_log(s, AV_LOG_ERROR, - "Could not get frame filename number %d from pattern '%s' (either set update or use a pattern like %%03d within the filename pattern)\n", + "Could not get frame filename number %d from pattern '%s'. " + "Use '-frames:v 1' for a single image, or '-update' option, or use a pattern such as %%03d within the filename.\n", img->img_number, img->path); return AVERROR(EINVAL); } diff --git a/libavformat/ingenientdec.c b/libavformat/ingenientdec.c index c0ba61e81..1b437b48f 100644 --- a/libavformat/ingenientdec.c +++ b/libavformat/ingenientdec.c @@ -24,7 +24,7 @@ #include "libavutil/intreadwrite.h" // http://multimedia.cx/ingenient.txt -static int ingenient_probe(AVProbeData *p) +static int ingenient_probe(const AVProbeData *p) { if ( AV_RN32(p->buf) != AV_RN32("MJPG") || p->buf_size < 50 diff --git a/libavformat/internal.h b/libavformat/internal.h index 358268292..cf8c16579 100644 --- a/libavformat/internal.h +++ b/libavformat/internal.h @@ -211,6 +211,14 @@ do {\ struct tm *ff_brktimegm(time_t secs, struct tm *tm); +/** + * Automatically create sub-directories + * + * @param path will create sub-directories by path + * @return 0, or < 0 on error + */ +int ff_mkdir_p(const char *path); + char *ff_data_to_hex(char *buf, const uint8_t *src, int size, int lowercase); /** @@ -239,6 +247,14 @@ void ff_read_frame_flush(AVFormatContext *s); /** Get the current time since NTP epoch in microseconds. */ uint64_t ff_ntp_time(void); +/** + * Get the NTP time stamp formatted as per the RFC-5905. + * + * @param ntp_time NTP time in micro seconds (since NTP epoch) + * @return the formatted NTP time stamp + */ +uint64_t ff_get_formatted_ntp_time(uint64_t ntp_time_us); + /** * Append the media-specific SDP fragment for the media stream c * to the buffer buff. @@ -634,9 +650,6 @@ enum AVWriteUncodedFrameFlags { */ int ff_copy_whiteblacklists(AVFormatContext *dst, const AVFormatContext *src); -int ffio_open2_wrapper(struct AVFormatContext *s, AVIOContext **pb, const char *url, int flags, - const AVIOInterruptCB *int_cb, AVDictionary **options); - /** * Returned by demuxers to indicate that data was consumed but discarded * (ignored streams or junk data). The framework will re-call the demuxer. diff --git a/libavformat/ip.c b/libavformat/ip.c new file mode 100644 index 000000000..70c5529b7 --- /dev/null +++ b/libavformat/ip.c @@ -0,0 +1,159 @@ +/* + * IP common code + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with FFmpeg; if not, write to the Free Software * Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "ip.h" +#include "libavutil/avstring.h" + +static int compare_addr(const struct sockaddr_storage *a, + const struct sockaddr_storage *b) +{ + if (a->ss_family != b->ss_family) + return 1; + if (a->ss_family == AF_INET) { + return (((const struct sockaddr_in *)a)->sin_addr.s_addr != + ((const struct sockaddr_in *)b)->sin_addr.s_addr); + } + +#if HAVE_STRUCT_SOCKADDR_IN6 + if (a->ss_family == AF_INET6) { + const uint8_t *s6_addr_a = ((const struct sockaddr_in6 *)a)->sin6_addr.s6_addr; + const uint8_t *s6_addr_b = ((const struct sockaddr_in6 *)b)->sin6_addr.s6_addr; + return memcmp(s6_addr_a, s6_addr_b, 16); + } +#endif + return 1; +} + +int ff_ip_check_source_lists(struct sockaddr_storage *source_addr_ptr, IPSourceFilters *s) +{ + int i; + if (s->nb_exclude_addrs) { + for (i = 0; i < s->nb_exclude_addrs; i++) { + if (!compare_addr(source_addr_ptr, &s->exclude_addrs[i])) + return 1; + } + } + if (s->nb_include_addrs) { + for (i = 0; i < s->nb_include_addrs; i++) { + if (!compare_addr(source_addr_ptr, &s->include_addrs[i])) + return 0; + } + return 1; + } + return 0; +} + +struct addrinfo *ff_ip_resolve_host(void *log_ctx, + const char *hostname, int port, + int type, int family, int flags) +{ + struct addrinfo hints = { 0 }, *res = 0; + int error; + char sport[16]; + const char *node = 0, *service = "0"; + + if (port > 0) { + snprintf(sport, sizeof(sport), "%d", port); + service = sport; + } + if ((hostname) && (hostname[0] != '\0') && (hostname[0] != '?')) { + node = hostname; + } + hints.ai_socktype = type; + hints.ai_family = family; + hints.ai_flags = flags; + if ((error = getaddrinfo(node, service, &hints, &res))) { + res = NULL; + av_log(log_ctx, AV_LOG_ERROR, "getaddrinfo(%s, %s): %s\n", + node ? node : "unknown", + service, + gai_strerror(error)); + } + + return res; +} + + +static int ip_parse_addr_list(void *log_ctx, const char *buf, + struct sockaddr_storage **address_list_ptr, + int *address_list_size_ptr) +{ + struct addrinfo *ai = NULL; + + /* Resolve all of the IPs */ + + while (buf && buf[0]) { + char* host = av_get_token(&buf, ","); + if (!host) + return AVERROR(ENOMEM); + + ai = ff_ip_resolve_host(log_ctx, host, 0, SOCK_DGRAM, AF_UNSPEC, 0); + av_freep(&host); + + if (ai) { + struct sockaddr_storage source_addr = {0}; + memcpy(&source_addr, ai->ai_addr, ai->ai_addrlen); + freeaddrinfo(ai); + av_dynarray2_add((void **)address_list_ptr, address_list_size_ptr, sizeof(source_addr), (uint8_t *)&source_addr); + if (!*address_list_ptr) + return AVERROR(ENOMEM); + } else { + return AVERROR(EINVAL); + } + + if (*buf) + buf++; + } + + return 0; +} + +static int ip_parse_sources_and_blocks(void *log_ctx, const char *buf, IPSourceFilters *filters, int parse_include_list) +{ + int ret; + if (parse_include_list) + ret = ip_parse_addr_list(log_ctx, buf, &filters->include_addrs, &filters->nb_include_addrs); + else + ret = ip_parse_addr_list(log_ctx, buf, &filters->exclude_addrs, &filters->nb_exclude_addrs); + + if (ret >= 0 && filters->nb_include_addrs && filters->nb_exclude_addrs) { + av_log(log_ctx, AV_LOG_ERROR, "Simultaneously including and excluding sources is not supported.\n"); + return AVERROR(EINVAL); + } + return ret; +} + +int ff_ip_parse_sources(void *log_ctx, const char *buf, IPSourceFilters *filters) +{ + return ip_parse_sources_and_blocks(log_ctx, buf, filters, 1); +} + +int ff_ip_parse_blocks(void *log_ctx, const char *buf, IPSourceFilters *filters) +{ + return ip_parse_sources_and_blocks(log_ctx, buf, filters, 0); +} + +void ff_ip_reset_filters(IPSourceFilters *filters) +{ + av_freep(&filters->exclude_addrs); + av_freep(&filters->include_addrs); + filters->nb_include_addrs = 0; + filters->nb_exclude_addrs = 0; +} diff --git a/libavformat/ip.h b/libavformat/ip.h new file mode 100644 index 000000000..b76cdab91 --- /dev/null +++ b/libavformat/ip.h @@ -0,0 +1,72 @@ +/* + * IP common code + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with FFmpeg; if not, write to the Free Software * Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVFORMAT_IP_H +#define AVFORMAT_IP_H + +#include "network.h" + +/** + * Structure for storing IP (UDP) source filters or block lists. + */ +typedef struct IPSourceFilters { + int nb_include_addrs; + int nb_exclude_addrs; + struct sockaddr_storage *include_addrs; + struct sockaddr_storage *exclude_addrs; +} IPSourceFilters; + +/** + * Checks the source address against a given IP source filter. + * @return 0 if packet should be processed based on the filter, 1 if the packet + * can be dropped. + */ +int ff_ip_check_source_lists(struct sockaddr_storage *source_addr_ptr, IPSourceFilters *s); + +/** + * Resolves hostname into an addrinfo structure. + * @return addrinfo structure which should be freed by the user, NULL in case + * of error. + */ +struct addrinfo *ff_ip_resolve_host(void *log_ctx, + const char *hostname, int port, + int type, int family, int flags); + +/** + * Parses the address[,address] source list in buf and adds it to the filters + * in the IPSourceFilters structure. + * @return 0 on success, < 0 AVERROR code on error. + */ +int ff_ip_parse_sources(void *log_ctx, const char *buf, IPSourceFilters *filters); + +/** + * Parses the address[,address] source block list in buf and adds it to the + * filters in the IPSourceFilters structure. + * @return 0 on success, < 0 AVERROR code on error. + */ +int ff_ip_parse_blocks(void *log_ctx, const char *buf, IPSourceFilters *filters); + +/** + * Resets the IP filter list and frees the internal fields of an + * IPSourceFilters structure. + */ +void ff_ip_reset_filters(IPSourceFilters *filters); + +#endif /* AVFORMAT_IP_H */ diff --git a/libavformat/ipmovie.c b/libavformat/ipmovie.c index 7f5a8c62e..137c85770 100644 --- a/libavformat/ipmovie.c +++ b/libavformat/ipmovie.c @@ -614,7 +614,7 @@ static int process_ipmovie_chunk(IPMVEContext *s, AVIOContext *pb, static const char signature[] = "Interplay MVE File\x1A\0\x1A"; -static int ipmovie_probe(AVProbeData *p) +static int ipmovie_probe(const AVProbeData *p) { const uint8_t *b = p->buf; const uint8_t *b_end = p->buf + p->buf_size - sizeof(signature); diff --git a/libavformat/ircamdec.c b/libavformat/ircamdec.c index d376ffef6..17bfb4ed1 100644 --- a/libavformat/ircamdec.c +++ b/libavformat/ircamdec.c @@ -26,7 +26,7 @@ #include "pcm.h" #include "ircam.h" -static int ircam_probe(AVProbeData *p) +static int ircam_probe(const AVProbeData *p) { if ((p->buf[0] == 0x64 && p->buf[1] == 0xA3 && p->buf[3] == 0x00 && p->buf[2] >= 1 && p->buf[2] <= 4) || diff --git a/libavformat/isom.c b/libavformat/isom.c index 2792371c2..c4880878c 100644 --- a/libavformat/isom.c +++ b/libavformat/isom.c @@ -163,6 +163,8 @@ const AVCodecTag ff_codec_movvideo_tags[] = { { AV_CODEC_ID_HEVC, MKTAG('h', 'e', 'v', '1') }, /* HEVC/H.265 which indicates parameter sets may be in ES */ { AV_CODEC_ID_HEVC, MKTAG('h', 'v', 'c', '1') }, /* HEVC/H.265 which indicates parameter sets shall not be in ES */ + { AV_CODEC_ID_HEVC, MKTAG('d', 'v', 'h', 'e') }, /* HEVC-based Dolby Vision derived from hev1 */ + /* dvh1 is handled within mov.c */ { AV_CODEC_ID_H264, MKTAG('a', 'v', 'c', '1') }, /* AVC-1/H.264 */ { AV_CODEC_ID_H264, MKTAG('a', 'v', 'c', '2') }, @@ -185,9 +187,12 @@ const AVCodecTag ff_codec_movvideo_tags[] = { { AV_CODEC_ID_H264, MKTAG('r', 'v', '6', '4') }, /* X-Com Radvision */ { AV_CODEC_ID_H264, MKTAG('x', 'a', 'l', 'g') }, /* XAVC-L HD422 produced by FCP */ { AV_CODEC_ID_H264, MKTAG('a', 'v', 'l', 'g') }, /* Panasonic P2 AVC-LongG */ + { AV_CODEC_ID_H264, MKTAG('d', 'v', 'a', '1') }, /* AVC-based Dolby Vision derived from avc1 */ + { AV_CODEC_ID_H264, MKTAG('d', 'v', 'a', 'v') }, /* AVC-based Dolby Vision derived from avc3 */ { AV_CODEC_ID_VP8, MKTAG('v', 'p', '0', '8') }, /* VP8 */ { AV_CODEC_ID_VP9, MKTAG('v', 'p', '0', '9') }, /* VP9 */ + { AV_CODEC_ID_AV1, MKTAG('a', 'v', '0', '1') }, /* AV1 */ { AV_CODEC_ID_MPEG1VIDEO, MKTAG('m', '1', 'v', ' ') }, { AV_CODEC_ID_MPEG1VIDEO, MKTAG('m', '1', 'v', '1') }, /* Apple MPEG-1 Camcorder */ @@ -285,6 +290,7 @@ const AVCodecTag ff_codec_movvideo_tags[] = { { AV_CODEC_ID_MAGICYUV, MKTAG('M', '0', 'R', 'A') }, { AV_CODEC_ID_MAGICYUV, MKTAG('M', '0', 'R', 'G') }, { AV_CODEC_ID_MAGICYUV, MKTAG('M', '0', 'Y', '2') }, + { AV_CODEC_ID_MAGICYUV, MKTAG('M', '0', 'Y', '4') }, { AV_CODEC_ID_MAGICYUV, MKTAG('M', '8', 'R', 'G') }, { AV_CODEC_ID_MAGICYUV, MKTAG('M', '8', 'R', 'A') }, { AV_CODEC_ID_MAGICYUV, MKTAG('M', '8', 'G', '0') }, @@ -332,6 +338,7 @@ const AVCodecTag ff_codec_movaudio_tags[] = { { AV_CODEC_ID_MP1, MKTAG('.', 'm', 'p', '1') }, { AV_CODEC_ID_MP2, MKTAG('.', 'm', 'p', '2') }, { AV_CODEC_ID_MP3, MKTAG('.', 'm', 'p', '3') }, + { AV_CODEC_ID_MP3, MKTAG('m', 'p', '3', ' ') }, /* vlc */ { AV_CODEC_ID_MP3, 0x6D730055 }, { AV_CODEC_ID_NELLYMOSER, MKTAG('n', 'm', 'o', 's') }, /* Flash Media Server */ { AV_CODEC_ID_NELLYMOSER, MKTAG('N', 'E', 'L', 'L') }, /* Perian */ @@ -373,6 +380,11 @@ const AVCodecTag ff_codec_movsubtitle_tags[] = { { AV_CODEC_ID_NONE, 0 }, }; +const AVCodecTag ff_codec_movdata_tags[] = { + { AV_CODEC_ID_BIN_DATA, MKTAG('g', 'p', 'm', 'd') }, + { AV_CODEC_ID_NONE, 0 }, +}; + /* map numeric codes from mdhd atom to ISO 639 */ /* cf. QTFileFormat.pdf p253, qtff.pdf p205 */ /* http://developer.apple.com/documentation/mac/Text/Text-368.html */ @@ -524,6 +536,10 @@ FF_ENABLE_DEPRECATION_WARNINGS len = ff_mp4_read_descr(fc, pb, &tag); if (tag == MP4DecSpecificDescrTag) { av_log(fc, AV_LOG_TRACE, "Specific MPEG-4 header len=%d\n", len); + /* As per 14496-3:2009 9.D.2.2, No decSpecificInfo is defined + for MPEG-1 Audio or MPEG-2 Audio; MPEG-2 AAC excluded. */ + if (object_type_id == 0x69 || object_type_id == 0x6b) + return 0; if (!len || (uint64_t)len > (1<<30)) return AVERROR_INVALIDDATA; if ((ret = ff_get_extradata(fc, st->codecpar, pb, len)) < 0) diff --git a/libavformat/isom.h b/libavformat/isom.h index 0f81bef4c..69452cae8 100644 --- a/libavformat/isom.h +++ b/libavformat/isom.h @@ -27,6 +27,7 @@ #include #include +#include "libavutil/encryption_info.h" #include "libavutil/mastering_display_metadata.h" #include "libavutil/spherical.h" #include "libavutil/stereo3d.h" @@ -40,6 +41,7 @@ extern const AVCodecTag ff_mp4_obj_type[]; extern const AVCodecTag ff_codec_movvideo_tags[]; extern const AVCodecTag ff_codec_movaudio_tags[]; extern const AVCodecTag ff_codec_movsubtitle_tags[]; +extern const AVCodecTag ff_codec_movdata_tags[]; int ff_mov_iso639_to_lang(const char lang[4], int mp4); int ff_mov_lang_to_iso639(unsigned code, char to[4]); @@ -109,12 +111,26 @@ typedef struct MOVSbgp { unsigned int index; } MOVSbgp; +typedef struct MOVEncryptionIndex { + // Individual encrypted samples. If there are no elements, then the default + // settings will be used. + unsigned int nb_encrypted_samples; + AVEncryptionInfo **encrypted_samples; + + uint8_t* auxiliary_info_sizes; + size_t auxiliary_info_sample_count; + uint8_t auxiliary_info_default_size; + uint64_t* auxiliary_offsets; ///< Absolute seek position + size_t auxiliary_offsets_count; +} MOVEncryptionIndex; + typedef struct MOVFragmentStreamInfo { int id; int64_t sidx_pts; int64_t first_tfra_pts; int64_t tfdt_dts; int index_entry; + MOVEncryptionIndex *encryption_index; } MOVFragmentStreamInfo; typedef struct MOVFragmentIndexItem { @@ -203,6 +219,7 @@ typedef struct MOVStreamContext { int *extradata_size; int last_stsd_index; int stsd_count; + int stsd_version; int32_t *display_matrix; AVStereo3D *stereo3d; @@ -216,15 +233,10 @@ typedef struct MOVStreamContext { int has_sidx; // If there is an sidx entry for this stream. struct { - int use_subsamples; - uint8_t* auxiliary_info; - uint8_t* auxiliary_info_end; - uint8_t* auxiliary_info_pos; - uint8_t auxiliary_info_default_size; - uint8_t* auxiliary_info_sizes; - size_t auxiliary_info_sizes_count; - int64_t auxiliary_info_index; struct AVAESCTR* aes_ctr; + unsigned int per_sample_iv_size; // Either 0, 8, or 16. + AVEncryptionInfo *default_encrypted_sample; + MOVEncryptionIndex *encryption_index; } cenc; } MOVStreamContext; diff --git a/libavformat/iss.c b/libavformat/iss.c index 95b35dc78..6d6aec2ce 100644 --- a/libavformat/iss.c +++ b/libavformat/iss.c @@ -58,7 +58,7 @@ static void get_token(AVIOContext *s, char *buf, int maxlen) buf[i] = 0; /* Ensure null terminated, but may be truncated */ } -static int iss_probe(AVProbeData *p) +static int iss_probe(const AVProbeData *p) { if (strncmp(p->buf, ISS_SIG, ISS_SIG_LEN)) return 0; diff --git a/libavformat/iv8.c b/libavformat/iv8.c index 077d905b4..449a42234 100644 --- a/libavformat/iv8.c +++ b/libavformat/iv8.c @@ -22,7 +22,7 @@ #include "internal.h" -static int probe(AVProbeData *p) +static int probe(const AVProbeData *p) { // the single file I have starts with that, I do not know if others do, too if( p->buf[0] == 1 diff --git a/libavformat/ivfdec.c b/libavformat/ivfdec.c index 197c099bc..40ae464b7 100644 --- a/libavformat/ivfdec.c +++ b/libavformat/ivfdec.c @@ -23,7 +23,7 @@ #include "riff.h" #include "libavutil/intreadwrite.h" -static int probe(AVProbeData *p) +static int probe(const AVProbeData *p) { if (AV_RL32(p->buf) == MKTAG('D','K','I','F') && !AV_RL16(p->buf+4) && AV_RL16(p->buf+6) == 32) diff --git a/libavformat/ivfenc.c b/libavformat/ivfenc.c index af803d59e..adf72117e 100644 --- a/libavformat/ivfenc.c +++ b/libavformat/ivfenc.c @@ -46,7 +46,7 @@ static int ivf_write_header(AVFormatContext *s) avio_write(pb, "DKIF", 4); avio_wl16(pb, 0); // version avio_wl16(pb, 32); // header length - avio_wl32(pb, par->codec_tag ? par->codec_tag : + avio_wl32(pb, par->codec_id == AV_CODEC_ID_VP9 ? AV_RL32("VP90") : par->codec_id == AV_CODEC_ID_VP8 ? AV_RL32("VP80") : AV_RL32("AV01")); avio_wl16(pb, par->width); @@ -97,6 +97,8 @@ static int ivf_check_bitstream(struct AVFormatContext *s, const AVPacket *pkt) if (st->codecpar->codec_id == AV_CODEC_ID_VP9) ret = ff_stream_add_bitstream_filter(st, "vp9_superframe", NULL); + else if (st->codecpar->codec_id == AV_CODEC_ID_AV1) + ret = ff_stream_add_bitstream_filter(st, "av1_metadata", "td=insert"); return ret; } diff --git a/libavformat/jacosubdec.c b/libavformat/jacosubdec.c index 520c435cc..121c86d65 100644 --- a/libavformat/jacosubdec.c +++ b/libavformat/jacosubdec.c @@ -48,7 +48,7 @@ static int timed_line(const char *ptr) (sscanf(ptr, "@%u @%u %c", &fs, &fe, &c) == 3 && fs < fe)); } -static int jacosub_probe(AVProbeData *p) +static int jacosub_probe(const AVProbeData *p) { const char *ptr = p->buf; const char *ptr_end = p->buf + p->buf_size; @@ -107,6 +107,7 @@ static const char *read_ts(JACOsubContext *jacosub, const char *buf, unsigned hs, ms, ss, fs; // hours, minutes, seconds, frame start unsigned he, me, se, fe; // hours, minutes, seconds, frame end int ts_start, ts_end; + int64_t ts_start64, ts_end64; /* timed format */ if (sscanf(buf, "%u:%u:%u.%u %u:%u:%u.%u %n", @@ -124,10 +125,10 @@ static const char *read_ts(JACOsubContext *jacosub, const char *buf, return NULL; shift_and_ret: - ts_start = (ts_start + jacosub->shift) * 100 / jacosub->timeres; - ts_end = (ts_end + jacosub->shift) * 100 / jacosub->timeres; - *start = ts_start; - *duration = ts_start + ts_end; + ts_start64 = (ts_start + jacosub->shift) * 100LL / jacosub->timeres; + ts_end64 = (ts_end + jacosub->shift) * 100LL / jacosub->timeres; + *start = ts_start64; + *duration = ts_end64 - ts_start64; return buf + len; } diff --git a/libavformat/jvdec.c b/libavformat/jvdec.c index b2c067fb9..18c81f0de 100644 --- a/libavformat/jvdec.c +++ b/libavformat/jvdec.c @@ -52,7 +52,7 @@ typedef struct JVDemuxContext { #define MAGIC " Compression by John M Phillips Copyright (C) 1995 The Bitmap Brothers Ltd." -static int read_probe(AVProbeData *pd) +static int read_probe(const AVProbeData *pd) { if (pd->buf[0] == 'J' && pd->buf[1] == 'V' && strlen(MAGIC) + 4 <= pd->buf_size && !memcmp(pd->buf + 4, MAGIC, strlen(MAGIC))) diff --git a/libavformat/latmenc.c b/libavformat/latmenc.c index 273197bb5..8eb219f8a 100644 --- a/libavformat/latmenc.c +++ b/libavformat/latmenc.c @@ -89,6 +89,10 @@ static int latm_write_header(AVFormatContext *s) if (par->codec_id == AV_CODEC_ID_AAC_LATM) return 0; + if (par->codec_id != AV_CODEC_ID_AAC && par->codec_id != AV_CODEC_ID_MP4ALS) { + av_log(ctx, AV_LOG_ERROR, "Only AAC, LATM and ALS are supported\n"); + return AVERROR(EINVAL); + } if (par->extradata_size > 0 && latm_decode_extradata(ctx, par->extradata, par->extradata_size) < 0) diff --git a/libavformat/libgme.c b/libavformat/libgme.c index 228273dc9..e6c56c487 100644 --- a/libavformat/libgme.c +++ b/libavformat/libgme.c @@ -169,7 +169,7 @@ static int read_seek_gme(AVFormatContext *s, int stream_idx, int64_t ts, int fla return 0; } -static int probe_gme(AVProbeData *p) +static int probe_gme(const AVProbeData *p) { // Reads 4 bytes - returns "" if unknown format. if (gme_identify_header(p->buf)[0]) { diff --git a/libavformat/libmodplug.c b/libavformat/libmodplug.c index f18c610c4..314bdae3e 100644 --- a/libavformat/libmodplug.c +++ b/libavformat/libmodplug.c @@ -350,7 +350,7 @@ static int modplug_read_seek(AVFormatContext *s, int stream_idx, int64_t ts, int static const char modplug_extensions[] = "669,abc,amf,ams,dbm,dmf,dsm,far,it,mdl,med,mid,mod,mt2,mtm,okt,psm,ptm,s3m,stm,ult,umx,xm,itgz,itr,itz,mdgz,mdr,mdz,s3gz,s3r,s3z,xmgz,xmr,xmz"; -static int modplug_probe(AVProbeData *p) +static int modplug_probe(const AVProbeData *p) { if (av_match_ext(p->filename, modplug_extensions)) { if (p->buf_size < 16384) diff --git a/libavformat/libopenmpt.c b/libavformat/libopenmpt.c index a33427084..52511aba5 100644 --- a/libavformat/libopenmpt.c +++ b/libavformat/libopenmpt.c @@ -232,7 +232,7 @@ static int probe_openmpt_extension(AVProbeData *p) return 0; } -static int read_probe_openmpt(AVProbeData *p) +static int read_probe_openmpt(const AVProbeData *p) { #if OPENMPT_API_VERSION_AT_LEAST(0,3,0) int probe_result; diff --git a/libavformat/libsrt.c b/libavformat/libsrt.c index 0f9529d26..b5568089f 100644 --- a/libavformat/libsrt.c +++ b/libavformat/libsrt.c @@ -34,6 +34,16 @@ #include "os_support.h" #include "url.h" +/* This is for MPEG-TS and it's a default SRTO_PAYLOADSIZE for SRTT_LIVE (8 TS packets) */ +#ifndef SRT_LIVE_DEFAULT_PAYLOAD_SIZE +#define SRT_LIVE_DEFAULT_PAYLOAD_SIZE 1316 +#endif + +/* This is the maximum payload size for Live mode, should you have a different payload type than MPEG-TS */ +#ifndef SRT_LIVE_MAX_PAYLOAD_SIZE +#define SRT_LIVE_MAX_PAYLOAD_SIZE 1456 +#endif + enum SRTMode { SRT_MODE_CALLER = 0, SRT_MODE_LISTENER = 1, @@ -58,11 +68,22 @@ typedef struct SRTContext { int iptos; int64_t inputbw; int oheadbw; - int64_t tsbpddelay; + int64_t latency; int tlpktdrop; int nakreport; int64_t connect_timeout; + int payload_size; + int64_t rcvlatency; + int64_t peerlatency; enum SRTMode mode; + int sndbuf; + int rcvbuf; + int lossmaxttl; + int minversion; + char *streamid; + char *smoother; + int messageapi; + SRT_TRANSTYPE transtype; } SRTContext; #define D AV_OPT_FLAG_DECODING_PARAM @@ -73,6 +94,10 @@ static const AVOption libsrt_options[] = { { "listen_timeout", "Connection awaiting timeout", OFFSET(listen_timeout), AV_OPT_TYPE_INT64, { .i64 = -1 }, -1, INT64_MAX, .flags = D|E }, { "send_buffer_size", "Socket send buffer size (in bytes)", OFFSET(send_buffer_size), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, .flags = D|E }, { "recv_buffer_size", "Socket receive buffer size (in bytes)", OFFSET(recv_buffer_size), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, .flags = D|E }, + { "pkt_size", "Maximum SRT packet size", OFFSET(payload_size), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, SRT_LIVE_MAX_PAYLOAD_SIZE, .flags = D|E, "payload_size" }, + { "payload_size", "Maximum SRT packet size", OFFSET(payload_size), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, SRT_LIVE_MAX_PAYLOAD_SIZE, .flags = D|E, "payload_size" }, + { "ts_size", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = SRT_LIVE_DEFAULT_PAYLOAD_SIZE }, INT_MIN, INT_MAX, .flags = D|E, "payload_size" }, + { "max_size", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = SRT_LIVE_MAX_PAYLOAD_SIZE }, INT_MIN, INT_MAX, .flags = D|E, "payload_size" }, { "maxbw", "Maximum bandwidth (bytes per second) that the connection can use", OFFSET(maxbw), AV_OPT_TYPE_INT64, { .i64 = -1 }, -1, INT64_MAX, .flags = D|E }, { "pbkeylen", "Crypto key len in bytes {16,24,32} Default: 16 (128-bit)", OFFSET(pbkeylen), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 32, .flags = D|E }, { "passphrase", "Crypto PBKDF2 Passphrase size[0,10..64] 0:disable crypto", OFFSET(passphrase), AV_OPT_TYPE_STRING, { .str = NULL }, .flags = D|E }, @@ -82,7 +107,10 @@ static const AVOption libsrt_options[] = { { "iptos", "IP Type of Service", OFFSET(iptos), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 255, .flags = D|E }, { "inputbw", "Estimated input stream rate", OFFSET(inputbw), AV_OPT_TYPE_INT64, { .i64 = -1 }, -1, INT64_MAX, .flags = D|E }, { "oheadbw", "MaxBW ceiling based on % over input stream rate", OFFSET(oheadbw), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 100, .flags = D|E }, - { "tsbpddelay", "TsbPd receiver delay to absorb burst of missed packet retransmission", OFFSET(tsbpddelay), AV_OPT_TYPE_INT64, { .i64 = -1 }, -1, INT64_MAX, .flags = D|E }, + { "latency", "receiver delay to absorb bursts of missed packet retransmissions", OFFSET(latency), AV_OPT_TYPE_INT64, { .i64 = -1 }, -1, INT64_MAX, .flags = D|E }, + { "tsbpddelay", "deprecated, same effect as latency option", OFFSET(latency), AV_OPT_TYPE_INT64, { .i64 = -1 }, -1, INT64_MAX, .flags = D|E }, + { "rcvlatency", "receive latency", OFFSET(rcvlatency), AV_OPT_TYPE_INT64, { .i64 = -1 }, -1, INT64_MAX, .flags = D|E }, + { "peerlatency", "peer latency", OFFSET(peerlatency), AV_OPT_TYPE_INT64, { .i64 = -1 }, -1, INT64_MAX, .flags = D|E }, { "tlpktdrop", "Enable receiver pkt drop", OFFSET(tlpktdrop), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 1, .flags = D|E }, { "nakreport", "Enable receiver to send periodic NAK reports", OFFSET(nakreport), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 1, .flags = D|E }, { "connect_timeout", "Connect timeout. Caller default: 3000, rendezvous (x 10)", OFFSET(connect_timeout), AV_OPT_TYPE_INT64, { .i64 = -1 }, -1, INT64_MAX, .flags = D|E }, @@ -90,6 +118,16 @@ static const AVOption libsrt_options[] = { { "caller", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = SRT_MODE_CALLER }, INT_MIN, INT_MAX, .flags = D|E, "mode" }, { "listener", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = SRT_MODE_LISTENER }, INT_MIN, INT_MAX, .flags = D|E, "mode" }, { "rendezvous", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = SRT_MODE_RENDEZVOUS }, INT_MIN, INT_MAX, .flags = D|E, "mode" }, + { "sndbuf", "Send buffer size (in bytes)", OFFSET(sndbuf), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, .flags = D|E }, + { "rcvbuf", "Receive buffer size (in bytes)", OFFSET(rcvbuf), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, .flags = D|E }, + { "lossmaxttl", "Maximum possible packet reorder tolerance", OFFSET(lossmaxttl), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, .flags = D|E }, + { "minversion", "The minimum SRT version that is required from the peer", OFFSET(minversion), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, .flags = D|E }, + { "streamid", "A string of up to 512 characters that an Initiator can pass to a Responder", OFFSET(streamid), AV_OPT_TYPE_STRING, { .str = NULL }, .flags = D|E }, + { "smoother", "The type of Smoother used for the transmission for that socket", OFFSET(smoother), AV_OPT_TYPE_STRING, { .str = NULL }, .flags = D|E }, + { "messageapi", "Enable message API", OFFSET(messageapi), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 1, .flags = D|E }, + { "transtype", "The transmission type for the socket", OFFSET(transtype), AV_OPT_TYPE_INT, { .i64 = SRTT_INVALID }, SRTT_LIVE, SRTT_INVALID, .flags = D|E, "transtype" }, + { "live", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = SRTT_LIVE }, INT_MIN, INT_MAX, .flags = D|E, "transtype" }, + { "file", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = SRTT_FILE }, INT_MIN, INT_MAX, .flags = D|E, "transtype" }, { NULL } }; @@ -240,6 +278,15 @@ static int libsrt_setsockopt(URLContext *h, int fd, SRT_SOCKOPT optname, const c return 0; } +static int libsrt_getsockopt(URLContext *h, int fd, SRT_SOCKOPT optname, const char * optnamestr, void * optval, int * optlen) +{ + if (srt_getsockopt(fd, 0, optname, optval, optlen) < 0) { + av_log(h, AV_LOG_ERROR, "failed to get option %s on socket: %s\n", optnamestr, srt_getlasterror_str()); + return AVERROR(EIO); + } + return 0; +} + /* - The "POST" options can be altered any time on a connected socket. They MAY have also some meaning when set prior to connecting; such option is SRTO_RCVSYN, which makes connect/accept call asynchronous. @@ -262,21 +309,35 @@ static int libsrt_set_options_pre(URLContext *h, int fd) { SRTContext *s = h->priv_data; int yes = 1; - int tsbpddelay = s->tsbpddelay / 1000; + int latency = s->latency / 1000; + int rcvlatency = s->rcvlatency / 1000; + int peerlatency = s->peerlatency / 1000; int connect_timeout = s->connect_timeout; if ((s->mode == SRT_MODE_RENDEZVOUS && libsrt_setsockopt(h, fd, SRTO_RENDEZVOUS, "SRTO_RENDEZVOUS", &yes, sizeof(yes)) < 0) || + (s->transtype != SRTT_INVALID && libsrt_setsockopt(h, fd, SRTO_TRANSTYPE, "SRTO_TRANSTYPE", &s->transtype, sizeof(s->transtype)) < 0) || (s->maxbw >= 0 && libsrt_setsockopt(h, fd, SRTO_MAXBW, "SRTO_MAXBW", &s->maxbw, sizeof(s->maxbw)) < 0) || (s->pbkeylen >= 0 && libsrt_setsockopt(h, fd, SRTO_PBKEYLEN, "SRTO_PBKEYLEN", &s->pbkeylen, sizeof(s->pbkeylen)) < 0) || - (s->passphrase && libsrt_setsockopt(h, fd, SRTO_PASSPHRASE, "SRTO_PASSPHRASE", &s->passphrase, sizeof(s->passphrase)) < 0) || + (s->passphrase && libsrt_setsockopt(h, fd, SRTO_PASSPHRASE, "SRTO_PASSPHRASE", s->passphrase, strlen(s->passphrase)) < 0) || (s->mss >= 0 && libsrt_setsockopt(h, fd, SRTO_MSS, "SRTO_MMS", &s->mss, sizeof(s->mss)) < 0) || (s->ffs >= 0 && libsrt_setsockopt(h, fd, SRTO_FC, "SRTO_FC", &s->ffs, sizeof(s->ffs)) < 0) || (s->ipttl >= 0 && libsrt_setsockopt(h, fd, SRTO_IPTTL, "SRTO_UPTTL", &s->ipttl, sizeof(s->ipttl)) < 0) || (s->iptos >= 0 && libsrt_setsockopt(h, fd, SRTO_IPTOS, "SRTO_IPTOS", &s->iptos, sizeof(s->iptos)) < 0) || - (tsbpddelay >= 0 && libsrt_setsockopt(h, fd, SRTO_TSBPDDELAY, "SRTO_TSBPDELAY", &tsbpddelay, sizeof(tsbpddelay)) < 0) || + (s->latency >= 0 && libsrt_setsockopt(h, fd, SRTO_LATENCY, "SRTO_LATENCY", &latency, sizeof(latency)) < 0) || + (s->rcvlatency >= 0 && libsrt_setsockopt(h, fd, SRTO_RCVLATENCY, "SRTO_RCVLATENCY", &rcvlatency, sizeof(rcvlatency)) < 0) || + (s->peerlatency >= 0 && libsrt_setsockopt(h, fd, SRTO_PEERLATENCY, "SRTO_PEERLATENCY", &peerlatency, sizeof(peerlatency)) < 0) || (s->tlpktdrop >= 0 && libsrt_setsockopt(h, fd, SRTO_TLPKTDROP, "SRTO_TLPKDROP", &s->tlpktdrop, sizeof(s->tlpktdrop)) < 0) || (s->nakreport >= 0 && libsrt_setsockopt(h, fd, SRTO_NAKREPORT, "SRTO_NAKREPORT", &s->nakreport, sizeof(s->nakreport)) < 0) || - (connect_timeout >= 0 && libsrt_setsockopt(h, fd, SRTO_CONNTIMEO, "SRTO_CONNTIMEO", &connect_timeout, sizeof(connect_timeout)) <0 )) { + (connect_timeout >= 0 && libsrt_setsockopt(h, fd, SRTO_CONNTIMEO, "SRTO_CONNTIMEO", &connect_timeout, sizeof(connect_timeout)) <0 ) || + (s->sndbuf >= 0 && libsrt_setsockopt(h, fd, SRTO_SNDBUF, "SRTO_SNDBUF", &s->sndbuf, sizeof(s->sndbuf)) < 0) || + (s->rcvbuf >= 0 && libsrt_setsockopt(h, fd, SRTO_RCVBUF, "SRTO_RCVBUF", &s->rcvbuf, sizeof(s->rcvbuf)) < 0) || + (s->lossmaxttl >= 0 && libsrt_setsockopt(h, fd, SRTO_LOSSMAXTTL, "SRTO_LOSSMAXTTL", &s->lossmaxttl, sizeof(s->lossmaxttl)) < 0) || + (s->minversion >= 0 && libsrt_setsockopt(h, fd, SRTO_MINVERSION, "SRTO_MINVERSION", &s->minversion, sizeof(s->minversion)) < 0) || + (s->streamid && libsrt_setsockopt(h, fd, SRTO_STREAMID, "SRTO_STREAMID", s->streamid, strlen(s->streamid)) < 0) || + (s->smoother && libsrt_setsockopt(h, fd, SRTO_SMOOTHER, "SRTO_SMOOTHER", s->smoother, strlen(s->smoother)) < 0) || + (s->messageapi >= 0 && libsrt_setsockopt(h, fd, SRTO_MESSAGEAPI, "SRTO_MESSAGEAPI", &s->messageapi, sizeof(s->messageapi)) < 0) || + (s->payload_size >= 0 && libsrt_setsockopt(h, fd, SRTO_PAYLOADSIZE, "SRTO_PAYLOADSIZE", &s->payload_size, sizeof(s->payload_size)) < 0) || + ((h->flags & AVIO_FLAG_WRITE) && libsrt_setsockopt(h, fd, SRTO_SENDER, "SRTO_SENDER", &yes, sizeof(yes)) < 0)) { return AVERROR(EIO); } return 0; @@ -380,6 +441,16 @@ static int libsrt_setup(URLContext *h, const char *uri, int flags) goto fail; } + if (flags & AVIO_FLAG_WRITE) { + int packet_size = 0; + int optlen = sizeof(packet_size); + ret = libsrt_getsockopt(h, fd, SRTO_PAYLOADSIZE, "SRTO_PAYLOADSIZE", &packet_size, &optlen); + if (ret < 0) + goto fail1; + if (packet_size > 0) + h->max_packet_size = packet_size; + } + h->is_streamed = 1; s->fd = fd; @@ -442,8 +513,17 @@ static int libsrt_open(URLContext *h, const char *uri, int flags) if (av_find_info_tag(buf, sizeof(buf), "oheadbw", p)) { s->oheadbw = strtoll(buf, NULL, 10); } + if (av_find_info_tag(buf, sizeof(buf), "latency", p)) { + s->latency = strtol(buf, NULL, 10); + } if (av_find_info_tag(buf, sizeof(buf), "tsbpddelay", p)) { - s->tsbpddelay = strtol(buf, NULL, 10); + s->latency = strtol(buf, NULL, 10); + } + if (av_find_info_tag(buf, sizeof(buf), "rcvlatency", p)) { + s->rcvlatency = strtol(buf, NULL, 10); + } + if (av_find_info_tag(buf, sizeof(buf), "peerlatency", p)) { + s->peerlatency = strtol(buf, NULL, 10); } if (av_find_info_tag(buf, sizeof(buf), "tlpktdrop", p)) { s->tlpktdrop = strtol(buf, NULL, 10); @@ -454,6 +534,10 @@ static int libsrt_open(URLContext *h, const char *uri, int flags) if (av_find_info_tag(buf, sizeof(buf), "connect_timeout", p)) { s->connect_timeout = strtol(buf, NULL, 10); } + if (av_find_info_tag(buf, sizeof(buf), "payload_size", p) || + av_find_info_tag(buf, sizeof(buf), "pkt_size", p)) { + s->payload_size = strtol(buf, NULL, 10); + } if (av_find_info_tag(buf, sizeof(buf), "mode", p)) { if (!strcmp(buf, "caller")) { s->mode = SRT_MODE_CALLER; @@ -465,6 +549,38 @@ static int libsrt_open(URLContext *h, const char *uri, int flags) return AVERROR(EIO); } } + if (av_find_info_tag(buf, sizeof(buf), "sndbuf", p)) { + s->sndbuf = strtol(buf, NULL, 10); + } + if (av_find_info_tag(buf, sizeof(buf), "rcvbuf", p)) { + s->rcvbuf = strtol(buf, NULL, 10); + } + if (av_find_info_tag(buf, sizeof(buf), "lossmaxttl", p)) { + s->lossmaxttl = strtol(buf, NULL, 10); + } + if (av_find_info_tag(buf, sizeof(buf), "minversion", p)) { + s->minversion = strtol(buf, NULL, 0); + } + if (av_find_info_tag(buf, sizeof(buf), "streamid", p)) { + av_freep(&s->streamid); + s->streamid = av_strdup(buf); + } + if (av_find_info_tag(buf, sizeof(buf), "smoother", p)) { + av_freep(&s->smoother); + s->smoother = av_strdup(buf); + } + if (av_find_info_tag(buf, sizeof(buf), "messageapi", p)) { + s->messageapi = strtol(buf, NULL, 10); + } + if (av_find_info_tag(buf, sizeof(buf), "transtype", p)) { + if (!strcmp(buf, "live")) { + s->transtype = SRTT_LIVE; + } else if (!strcmp(buf, "file")) { + s->transtype = SRTT_FILE; + } else { + return AVERROR(EINVAL); + } + } } return libsrt_setup(h, uri, flags); } diff --git a/libavformat/lmlm4.c b/libavformat/lmlm4.c index d0cf8feb0..79d703a8f 100644 --- a/libavformat/lmlm4.c +++ b/libavformat/lmlm4.c @@ -35,7 +35,7 @@ #define LMLM4_MAX_PACKET_SIZE 1024 * 1024 -static int lmlm4_probe(AVProbeData *pd) +static int lmlm4_probe(const AVProbeData *pd) { const unsigned char *buf = pd->buf; unsigned int frame_type, packet_size; diff --git a/libavformat/loasdec.c b/libavformat/loasdec.c index 70440559d..e166a5928 100644 --- a/libavformat/loasdec.c +++ b/libavformat/loasdec.c @@ -27,7 +27,7 @@ #define LOAS_SYNC_WORD 0x2b7 -static int loas_probe(AVProbeData *p) +static int loas_probe(const AVProbeData *p) { int max_frames = 0, first_frames = 0; int fsize, frames; @@ -83,6 +83,7 @@ static int loas_read_header(AVFormatContext *s) return 0; } +FF_RAW_DEMUXER_CLASS(loas) AVInputFormat ff_loas_demuxer = { .name = "loas", .long_name = NULL_IF_CONFIG_SMALL("LOAS AudioSyncStream"), @@ -91,4 +92,6 @@ AVInputFormat ff_loas_demuxer = { .read_packet = ff_raw_read_partial_packet, .flags= AVFMT_GENERIC_INDEX, .raw_codec_id = AV_CODEC_ID_AAC_LATM, + .priv_data_size = sizeof(FFRawDemuxerContext), + .priv_class = &loas_demuxer_class, }; diff --git a/libavformat/lrcdec.c b/libavformat/lrcdec.c index f4e9a4efa..a9a117691 100644 --- a/libavformat/lrcdec.c +++ b/libavformat/lrcdec.c @@ -116,7 +116,7 @@ static int64_t read_line(AVBPrint *buf, AVIOContext *pb) return pos; } -static int lrc_probe(AVProbeData *p) +static int lrc_probe(const AVProbeData *p) { int64_t offset = 0; int64_t mm; diff --git a/libavformat/lvfdec.c b/libavformat/lvfdec.c index b8af25609..8b8d6f01b 100644 --- a/libavformat/lvfdec.c +++ b/libavformat/lvfdec.c @@ -23,7 +23,7 @@ #include "avformat.h" #include "riff.h" -static int lvf_probe(AVProbeData *p) +static int lvf_probe(const AVProbeData *p) { if (AV_RL32(p->buf) != MKTAG('L', 'V', 'F', 'F')) return 0; diff --git a/libavformat/lxfdec.c b/libavformat/lxfdec.c index 9b3eb6a65..434518fc5 100644 --- a/libavformat/lxfdec.c +++ b/libavformat/lxfdec.c @@ -52,7 +52,7 @@ typedef struct LXFDemuxContext { uint32_t video_format, packet_type, extended_size; } LXFDemuxContext; -static int lxf_probe(AVProbeData *p) +static int lxf_probe(const AVProbeData *p) { if (!memcmp(p->buf, LXF_IDENT, LXF_IDENT_LENGTH)) return AVPROBE_SCORE_MAX; diff --git a/libavformat/m4vdec.c b/libavformat/m4vdec.c index 220daeb77..befe4d790 100644 --- a/libavformat/m4vdec.c +++ b/libavformat/m4vdec.c @@ -30,7 +30,7 @@ #define SLICE_STARTCODE 0x1B7 #define EXT_STARTCODE 0x1B8 -static int mpeg4video_probe(AVProbeData *probe_packet) +static int mpeg4video_probe(const AVProbeData *probe_packet) { uint32_t temp_buffer = -1; int VO = 0, VOL = 0, VOP = 0, VISO = 0, res = 0; diff --git a/libavformat/matroska.c b/libavformat/matroska.c index 94ccbeced..4d18d147f 100644 --- a/libavformat/matroska.c +++ b/libavformat/matroska.c @@ -103,6 +103,22 @@ const CodecTags ff_mkv_codec_tags[]={ {"" , AV_CODEC_ID_NONE} }; +const CodecTags ff_webm_codec_tags[] = { + {"V_VP8" , AV_CODEC_ID_VP8}, + {"V_VP9" , AV_CODEC_ID_VP9}, + {"V_AV1" , AV_CODEC_ID_AV1}, + + {"A_VORBIS" , AV_CODEC_ID_VORBIS}, + {"A_OPUS" , AV_CODEC_ID_OPUS}, + + {"D_WEBVTT/SUBTITLES" , AV_CODEC_ID_WEBVTT}, + {"D_WEBVTT/CAPTIONS" , AV_CODEC_ID_WEBVTT}, + {"D_WEBVTT/DESCRIPTIONS", AV_CODEC_ID_WEBVTT}, + {"D_WEBVTT/METADATA" , AV_CODEC_ID_WEBVTT}, + + {"" , AV_CODEC_ID_NONE} +}; + const CodecMime ff_mkv_image_mime_tags[] = { {"image/gif" , AV_CODEC_ID_GIF}, {"image/jpeg" , AV_CODEC_ID_MJPEG}, diff --git a/libavformat/matroska.h b/libavformat/matroska.h index 83c824614..86968a8de 100644 --- a/libavformat/matroska.h +++ b/libavformat/matroska.h @@ -360,6 +360,7 @@ typedef struct CodecTags{ #define MATROSKA_VIDEO_STEREO_PLANE_COUNT 3 extern const CodecTags ff_mkv_codec_tags[]; +extern const CodecTags ff_webm_codec_tags[]; extern const CodecMime ff_mkv_mime_tags[]; extern const CodecMime ff_mkv_image_mime_tags[]; extern const AVMetadataConv ff_mkv_metadata_conv[]; diff --git a/libavformat/matroskadec.c b/libavformat/matroskadec.c index 37c9a1c11..8c4ff3093 100644 --- a/libavformat/matroskadec.c +++ b/libavformat/matroskadec.c @@ -68,26 +68,37 @@ #include "qtpalette.h" +#define EBML_UNKNOWN_LENGTH UINT64_MAX /* EBML unknown length, in uint64_t */ +#define NEEDS_CHECKING 2 /* Indicates that some error checks + * still need to be performed */ +#define LEVEL_ENDED 3 /* return value of ebml_parse when the + * syntax level used for parsing ended. */ +#define SKIP_THRESHOLD 1024 * 1024 /* In non-seekable mode, if more than SKIP_THRESHOLD + * of unkown, potentially damaged data is encountered, + * it is considered an error. */ +#define UNKNOWN_EQUIV 50 * 1024 /* An unknown element is considered equivalent + * to this many bytes of unknown data for the + * SKIP_THRESHOLD check. */ + typedef enum { EBML_NONE, EBML_UINT, + EBML_SINT, EBML_FLOAT, EBML_STR, EBML_UTF8, EBML_BIN, EBML_NEST, EBML_LEVEL1, - EBML_PASS, EBML_STOP, - EBML_SINT, EBML_TYPE_COUNT } EbmlType; typedef const struct EbmlSyntax { uint32_t id; EbmlType type; - int list_elem_size; - int data_offset; + size_t list_elem_size; + size_t data_offset; union { int64_t i; uint64_t u; @@ -99,6 +110,7 @@ typedef const struct EbmlSyntax { typedef struct EbmlList { int nb_elem; + unsigned int alloc_elem_size; void *elem; } EbmlList; @@ -178,7 +190,7 @@ typedef struct MatroskaTrackVideo { uint64_t display_height; uint64_t pixel_width; uint64_t pixel_height; - EbmlBin color_space; + EbmlBin color_space; uint64_t display_unit; uint64_t interlaced; uint64_t field_order; @@ -302,14 +314,25 @@ typedef struct MatroskaLevel { uint64_t length; } MatroskaLevel; +typedef struct MatroskaBlock { + uint64_t duration; + int64_t reference; + uint64_t non_simple; + EbmlBin bin; + uint64_t additional_id; + EbmlBin additional; + int64_t discard_padding; +} MatroskaBlock; + typedef struct MatroskaCluster { + MatroskaBlock block; uint64_t timecode; - EbmlList blocks; + int64_t pos; } MatroskaCluster; typedef struct MatroskaLevel1Element { - uint64_t id; - uint64_t pos; + int64_t pos; + uint32_t id; int parsed; } MatroskaLevel1Element; @@ -318,16 +341,17 @@ typedef struct MatroskaDemuxContext { AVFormatContext *ctx; /* EBML stuff */ - int num_levels; MatroskaLevel levels[EBML_MAX_DEPTH]; - int level_up; + int num_levels; uint32_t current_id; + int64_t resync_pos; + int unknown_count; uint64_t time_scale; double duration; char *title; char *muxingapp; - EbmlBin date_utc; + EbmlBin date_utc; EbmlList tracks; EbmlList attachments; EbmlList chapters; @@ -355,13 +379,8 @@ typedef struct MatroskaDemuxContext { MatroskaLevel1Element level1_elems[64]; int num_level1_elems; - int current_cluster_num_blocks; - int64_t current_cluster_pos; MatroskaCluster current_cluster; - /* File has SSA subtitles which prevent incremental cluster parsing. */ - int contains_ssa; - /* WebM DASH Manifest live flag */ int is_live; @@ -369,17 +388,20 @@ typedef struct MatroskaDemuxContext { int bandwidth; } MatroskaDemuxContext; -typedef struct MatroskaBlock { - uint64_t duration; - int64_t reference; - uint64_t non_simple; - EbmlBin bin; - uint64_t additional_id; - EbmlBin additional; - int64_t discard_padding; -} MatroskaBlock; +#define CHILD_OF(parent) { .def = { .n = parent } } -static const EbmlSyntax ebml_header[] = { +// The following forward declarations need their size because +// a tentative definition with internal linkage must not be an +// incomplete type (6.7.2 in C90, 6.9.2 in C99). +// Removing the sizes breaks MSVC. +static EbmlSyntax ebml_syntax[3], matroska_segment[9], matroska_track_video_color[15], matroska_track_video[19], + matroska_track[27], matroska_track_encoding[6], matroska_track_encodings[2], + matroska_track_combine_planes[2], matroska_track_operation[2], matroska_tracks[2], + matroska_attachments[2], matroska_chapter_entry[9], matroska_chapter[6], matroska_chapters[2], + matroska_index_entry[3], matroska_index[2], matroska_tag[3], matroska_tags[2], matroska_seekhead[2], + matroska_blockadditions[2], matroska_blockgroup[8], matroska_cluster_parsing[8]; + +static EbmlSyntax ebml_header[] = { { EBML_ID_EBMLREADVERSION, EBML_UINT, 0, offsetof(Ebml, version), { .u = EBML_VERSION } }, { EBML_ID_EBMLMAXSIZELENGTH, EBML_UINT, 0, offsetof(Ebml, max_size), { .u = 8 } }, { EBML_ID_EBMLMAXIDLENGTH, EBML_UINT, 0, offsetof(Ebml, id_length), { .u = 4 } }, @@ -387,15 +409,16 @@ static const EbmlSyntax ebml_header[] = { { EBML_ID_DOCTYPEREADVERSION, EBML_UINT, 0, offsetof(Ebml, doctype_version), { .u = 1 } }, { EBML_ID_EBMLVERSION, EBML_NONE }, { EBML_ID_DOCTYPEVERSION, EBML_NONE }, + CHILD_OF(ebml_syntax) +}; + +static EbmlSyntax ebml_syntax[] = { + { EBML_ID_HEADER, EBML_NEST, 0, 0, { .n = ebml_header } }, + { MATROSKA_ID_SEGMENT, EBML_STOP }, { 0 } }; -static const EbmlSyntax ebml_syntax[] = { - { EBML_ID_HEADER, EBML_NEST, 0, 0, { .n = ebml_header } }, - { 0 } -}; - -static const EbmlSyntax matroska_info[] = { +static EbmlSyntax matroska_info[] = { { MATROSKA_ID_TIMECODESCALE, EBML_UINT, 0, offsetof(MatroskaDemuxContext, time_scale), { .u = 1000000 } }, { MATROSKA_ID_DURATION, EBML_FLOAT, 0, offsetof(MatroskaDemuxContext, duration) }, { MATROSKA_ID_TITLE, EBML_UTF8, 0, offsetof(MatroskaDemuxContext, title) }, @@ -403,10 +426,10 @@ static const EbmlSyntax matroska_info[] = { { MATROSKA_ID_MUXINGAPP, EBML_UTF8, 0, offsetof(MatroskaDemuxContext, muxingapp) }, { MATROSKA_ID_DATEUTC, EBML_BIN, 0, offsetof(MatroskaDemuxContext, date_utc) }, { MATROSKA_ID_SEGMENTUID, EBML_NONE }, - { 0 } + CHILD_OF(matroska_segment) }; -static const EbmlSyntax matroska_mastering_meta[] = { +static EbmlSyntax matroska_mastering_meta[] = { { MATROSKA_ID_VIDEOCOLOR_RX, EBML_FLOAT, 0, offsetof(MatroskaMasteringMeta, r_x), { .f=-1 } }, { MATROSKA_ID_VIDEOCOLOR_RY, EBML_FLOAT, 0, offsetof(MatroskaMasteringMeta, r_y), { .f=-1 } }, { MATROSKA_ID_VIDEOCOLOR_GX, EBML_FLOAT, 0, offsetof(MatroskaMasteringMeta, g_x), { .f=-1 } }, @@ -417,10 +440,10 @@ static const EbmlSyntax matroska_mastering_meta[] = { { MATROSKA_ID_VIDEOCOLOR_WHITEY, EBML_FLOAT, 0, offsetof(MatroskaMasteringMeta, white_y), { .f=-1 } }, { MATROSKA_ID_VIDEOCOLOR_LUMINANCEMIN, EBML_FLOAT, 0, offsetof(MatroskaMasteringMeta, min_luminance), { .f=-1 } }, { MATROSKA_ID_VIDEOCOLOR_LUMINANCEMAX, EBML_FLOAT, 0, offsetof(MatroskaMasteringMeta, max_luminance), { .f=-1 } }, - { 0 } + CHILD_OF(matroska_track_video_color) }; -static const EbmlSyntax matroska_track_video_color[] = { +static EbmlSyntax matroska_track_video_color[] = { { MATROSKA_ID_VIDEOCOLORMATRIXCOEFF, EBML_UINT, 0, offsetof(MatroskaTrackVideoColor, matrix_coefficients), { .u = AVCOL_SPC_UNSPECIFIED } }, { MATROSKA_ID_VIDEOCOLORBITSPERCHANNEL, EBML_UINT, 0, offsetof(MatroskaTrackVideoColor, bits_per_channel), { .u=0 } }, { MATROSKA_ID_VIDEOCOLORCHROMASUBHORZ, EBML_UINT, 0, offsetof(MatroskaTrackVideoColor, chroma_sub_horz), { .u=0 } }, @@ -435,19 +458,19 @@ static const EbmlSyntax matroska_track_video_color[] = { { MATROSKA_ID_VIDEOCOLORMAXCLL, EBML_UINT, 0, offsetof(MatroskaTrackVideoColor, max_cll), { .u=0 } }, { MATROSKA_ID_VIDEOCOLORMAXFALL, EBML_UINT, 0, offsetof(MatroskaTrackVideoColor, max_fall), { .u=0 } }, { MATROSKA_ID_VIDEOCOLORMASTERINGMETA, EBML_NEST, 0, offsetof(MatroskaTrackVideoColor, mastering_meta), { .n = matroska_mastering_meta } }, - { 0 } + CHILD_OF(matroska_track_video) }; -static const EbmlSyntax matroska_track_video_projection[] = { +static EbmlSyntax matroska_track_video_projection[] = { { MATROSKA_ID_VIDEOPROJECTIONTYPE, EBML_UINT, 0, offsetof(MatroskaTrackVideoProjection, type), { .u = MATROSKA_VIDEO_PROJECTION_TYPE_RECTANGULAR } }, { MATROSKA_ID_VIDEOPROJECTIONPRIVATE, EBML_BIN, 0, offsetof(MatroskaTrackVideoProjection, private) }, { MATROSKA_ID_VIDEOPROJECTIONPOSEYAW, EBML_FLOAT, 0, offsetof(MatroskaTrackVideoProjection, yaw), { .f=0.0 } }, { MATROSKA_ID_VIDEOPROJECTIONPOSEPITCH, EBML_FLOAT, 0, offsetof(MatroskaTrackVideoProjection, pitch), { .f=0.0 } }, { MATROSKA_ID_VIDEOPROJECTIONPOSEROLL, EBML_FLOAT, 0, offsetof(MatroskaTrackVideoProjection, roll), { .f=0.0 } }, - { 0 } + CHILD_OF(matroska_track_video) }; -static const EbmlSyntax matroska_track_video[] = { +static EbmlSyntax matroska_track_video[] = { { MATROSKA_ID_VIDEOFRAMERATE, EBML_FLOAT, 0, offsetof(MatroskaTrackVideo, frame_rate) }, { MATROSKA_ID_VIDEODISPLAYWIDTH, EBML_UINT, 0, offsetof(MatroskaTrackVideo, display_width), { .u=-1 } }, { MATROSKA_ID_VIDEODISPLAYHEIGHT, EBML_UINT, 0, offsetof(MatroskaTrackVideo, display_height), { .u=-1 } }, @@ -466,24 +489,24 @@ static const EbmlSyntax matroska_track_video[] = { { MATROSKA_ID_VIDEOFIELDORDER, EBML_UINT, 0, offsetof(MatroskaTrackVideo, field_order), { .u = MATROSKA_VIDEO_FIELDORDER_UNDETERMINED } }, { MATROSKA_ID_VIDEOSTEREOMODE, EBML_UINT, 0, offsetof(MatroskaTrackVideo, stereo_mode), { .u = MATROSKA_VIDEO_STEREOMODE_TYPE_NB } }, { MATROSKA_ID_VIDEOASPECTRATIO, EBML_NONE }, - { 0 } + CHILD_OF(matroska_track) }; -static const EbmlSyntax matroska_track_audio[] = { +static EbmlSyntax matroska_track_audio[] = { { MATROSKA_ID_AUDIOSAMPLINGFREQ, EBML_FLOAT, 0, offsetof(MatroskaTrackAudio, samplerate), { .f = 8000.0 } }, { MATROSKA_ID_AUDIOOUTSAMPLINGFREQ, EBML_FLOAT, 0, offsetof(MatroskaTrackAudio, out_samplerate) }, { MATROSKA_ID_AUDIOBITDEPTH, EBML_UINT, 0, offsetof(MatroskaTrackAudio, bitdepth) }, { MATROSKA_ID_AUDIOCHANNELS, EBML_UINT, 0, offsetof(MatroskaTrackAudio, channels), { .u = 1 } }, - { 0 } + CHILD_OF(matroska_track) }; -static const EbmlSyntax matroska_track_encoding_compression[] = { +static EbmlSyntax matroska_track_encoding_compression[] = { { MATROSKA_ID_ENCODINGCOMPALGO, EBML_UINT, 0, offsetof(MatroskaTrackCompression, algo), { .u = 0 } }, { MATROSKA_ID_ENCODINGCOMPSETTINGS, EBML_BIN, 0, offsetof(MatroskaTrackCompression, settings) }, - { 0 } + CHILD_OF(matroska_track_encoding) }; -static const EbmlSyntax matroska_track_encoding_encryption[] = { +static EbmlSyntax matroska_track_encoding_encryption[] = { { MATROSKA_ID_ENCODINGENCALGO, EBML_UINT, 0, offsetof(MatroskaTrackEncryption,algo), {.u = 0} }, { MATROSKA_ID_ENCODINGENCKEYID, EBML_BIN, 0, offsetof(MatroskaTrackEncryption,key_id) }, { MATROSKA_ID_ENCODINGENCAESSETTINGS, EBML_NONE }, @@ -491,39 +514,39 @@ static const EbmlSyntax matroska_track_encoding_encryption[] = { { MATROSKA_ID_ENCODINGSIGHASHALGO, EBML_NONE }, { MATROSKA_ID_ENCODINGSIGKEYID, EBML_NONE }, { MATROSKA_ID_ENCODINGSIGNATURE, EBML_NONE }, - { 0 } + CHILD_OF(matroska_track_encoding) }; -static const EbmlSyntax matroska_track_encoding[] = { +static EbmlSyntax matroska_track_encoding[] = { { MATROSKA_ID_ENCODINGSCOPE, EBML_UINT, 0, offsetof(MatroskaTrackEncoding, scope), { .u = 1 } }, { MATROSKA_ID_ENCODINGTYPE, EBML_UINT, 0, offsetof(MatroskaTrackEncoding, type), { .u = 0 } }, { MATROSKA_ID_ENCODINGCOMPRESSION, EBML_NEST, 0, offsetof(MatroskaTrackEncoding, compression), { .n = matroska_track_encoding_compression } }, { MATROSKA_ID_ENCODINGENCRYPTION, EBML_NEST, 0, offsetof(MatroskaTrackEncoding, encryption), { .n = matroska_track_encoding_encryption } }, { MATROSKA_ID_ENCODINGORDER, EBML_NONE }, - { 0 } + CHILD_OF(matroska_track_encodings) }; -static const EbmlSyntax matroska_track_encodings[] = { +static EbmlSyntax matroska_track_encodings[] = { { MATROSKA_ID_TRACKCONTENTENCODING, EBML_NEST, sizeof(MatroskaTrackEncoding), offsetof(MatroskaTrack, encodings), { .n = matroska_track_encoding } }, - { 0 } + CHILD_OF(matroska_track) }; -static const EbmlSyntax matroska_track_plane[] = { +static EbmlSyntax matroska_track_plane[] = { { MATROSKA_ID_TRACKPLANEUID, EBML_UINT, 0, offsetof(MatroskaTrackPlane,uid) }, { MATROSKA_ID_TRACKPLANETYPE, EBML_UINT, 0, offsetof(MatroskaTrackPlane,type) }, - { 0 } + CHILD_OF(matroska_track_combine_planes) }; -static const EbmlSyntax matroska_track_combine_planes[] = { +static EbmlSyntax matroska_track_combine_planes[] = { { MATROSKA_ID_TRACKPLANE, EBML_NEST, sizeof(MatroskaTrackPlane), offsetof(MatroskaTrackOperation,combine_planes), {.n = matroska_track_plane} }, - { 0 } + CHILD_OF(matroska_track_operation) }; -static const EbmlSyntax matroska_track_operation[] = { +static EbmlSyntax matroska_track_operation[] = { { MATROSKA_ID_TRACKCOMBINEPLANES, EBML_NEST, 0, 0, {.n = matroska_track_combine_planes} }, - { 0 } + CHILD_OF(matroska_track) }; -static const EbmlSyntax matroska_track[] = { +static EbmlSyntax matroska_track[] = { { MATROSKA_ID_TRACKNUMBER, EBML_UINT, 0, offsetof(MatroskaTrack, num) }, { MATROSKA_ID_TRACKNAME, EBML_UTF8, 0, offsetof(MatroskaTrack, name) }, { MATROSKA_ID_TRACKUID, EBML_UINT, 0, offsetof(MatroskaTrack, uid) }, @@ -550,36 +573,36 @@ static const EbmlSyntax matroska_track[] = { { MATROSKA_ID_CODECDOWNLOADURL, EBML_NONE }, { MATROSKA_ID_TRACKMINCACHE, EBML_NONE }, { MATROSKA_ID_TRACKMAXCACHE, EBML_NONE }, - { 0 } + CHILD_OF(matroska_tracks) }; -static const EbmlSyntax matroska_tracks[] = { +static EbmlSyntax matroska_tracks[] = { { MATROSKA_ID_TRACKENTRY, EBML_NEST, sizeof(MatroskaTrack), offsetof(MatroskaDemuxContext, tracks), { .n = matroska_track } }, - { 0 } + CHILD_OF(matroska_segment) }; -static const EbmlSyntax matroska_attachment[] = { +static EbmlSyntax matroska_attachment[] = { { MATROSKA_ID_FILEUID, EBML_UINT, 0, offsetof(MatroskaAttachment, uid) }, { MATROSKA_ID_FILENAME, EBML_UTF8, 0, offsetof(MatroskaAttachment, filename) }, { MATROSKA_ID_FILEMIMETYPE, EBML_STR, 0, offsetof(MatroskaAttachment, mime) }, { MATROSKA_ID_FILEDATA, EBML_BIN, 0, offsetof(MatroskaAttachment, bin) }, { MATROSKA_ID_FILEDESC, EBML_NONE }, - { 0 } + CHILD_OF(matroska_attachments) }; -static const EbmlSyntax matroska_attachments[] = { +static EbmlSyntax matroska_attachments[] = { { MATROSKA_ID_ATTACHEDFILE, EBML_NEST, sizeof(MatroskaAttachment), offsetof(MatroskaDemuxContext, attachments), { .n = matroska_attachment } }, - { 0 } + CHILD_OF(matroska_segment) }; -static const EbmlSyntax matroska_chapter_display[] = { +static EbmlSyntax matroska_chapter_display[] = { { MATROSKA_ID_CHAPSTRING, EBML_UTF8, 0, offsetof(MatroskaChapter, title) }, { MATROSKA_ID_CHAPLANG, EBML_NONE }, { MATROSKA_ID_CHAPCOUNTRY, EBML_NONE }, - { 0 } + CHILD_OF(matroska_chapter_entry) }; -static const EbmlSyntax matroska_chapter_entry[] = { +static EbmlSyntax matroska_chapter_entry[] = { { MATROSKA_ID_CHAPTERTIMESTART, EBML_UINT, 0, offsetof(MatroskaChapter, start), { .u = AV_NOPTS_VALUE } }, { MATROSKA_ID_CHAPTERTIMEEND, EBML_UINT, 0, offsetof(MatroskaChapter, end), { .u = AV_NOPTS_VALUE } }, { MATROSKA_ID_CHAPTERUID, EBML_UINT, 0, offsetof(MatroskaChapter, uid) }, @@ -588,85 +611,86 @@ static const EbmlSyntax matroska_chapter_entry[] = { { MATROSKA_ID_CHAPTERFLAGENABLED, EBML_NONE }, { MATROSKA_ID_CHAPTERPHYSEQUIV, EBML_NONE }, { MATROSKA_ID_CHAPTERATOM, EBML_NONE }, - { 0 } + CHILD_OF(matroska_chapter) }; -static const EbmlSyntax matroska_chapter[] = { +static EbmlSyntax matroska_chapter[] = { { MATROSKA_ID_CHAPTERATOM, EBML_NEST, sizeof(MatroskaChapter), offsetof(MatroskaDemuxContext, chapters), { .n = matroska_chapter_entry } }, { MATROSKA_ID_EDITIONUID, EBML_NONE }, { MATROSKA_ID_EDITIONFLAGHIDDEN, EBML_NONE }, { MATROSKA_ID_EDITIONFLAGDEFAULT, EBML_NONE }, { MATROSKA_ID_EDITIONFLAGORDERED, EBML_NONE }, - { 0 } + CHILD_OF(matroska_chapters) }; -static const EbmlSyntax matroska_chapters[] = { +static EbmlSyntax matroska_chapters[] = { { MATROSKA_ID_EDITIONENTRY, EBML_NEST, 0, 0, { .n = matroska_chapter } }, - { 0 } + CHILD_OF(matroska_segment) }; -static const EbmlSyntax matroska_index_pos[] = { +static EbmlSyntax matroska_index_pos[] = { { MATROSKA_ID_CUETRACK, EBML_UINT, 0, offsetof(MatroskaIndexPos, track) }, { MATROSKA_ID_CUECLUSTERPOSITION, EBML_UINT, 0, offsetof(MatroskaIndexPos, pos) }, { MATROSKA_ID_CUERELATIVEPOSITION,EBML_NONE }, { MATROSKA_ID_CUEDURATION, EBML_NONE }, { MATROSKA_ID_CUEBLOCKNUMBER, EBML_NONE }, - { 0 } + CHILD_OF(matroska_index_entry) }; -static const EbmlSyntax matroska_index_entry[] = { +static EbmlSyntax matroska_index_entry[] = { { MATROSKA_ID_CUETIME, EBML_UINT, 0, offsetof(MatroskaIndex, time) }, { MATROSKA_ID_CUETRACKPOSITION, EBML_NEST, sizeof(MatroskaIndexPos), offsetof(MatroskaIndex, pos), { .n = matroska_index_pos } }, - { 0 } + CHILD_OF(matroska_index) }; -static const EbmlSyntax matroska_index[] = { +static EbmlSyntax matroska_index[] = { { MATROSKA_ID_POINTENTRY, EBML_NEST, sizeof(MatroskaIndex), offsetof(MatroskaDemuxContext, index), { .n = matroska_index_entry } }, - { 0 } + CHILD_OF(matroska_segment) }; -static const EbmlSyntax matroska_simpletag[] = { +static EbmlSyntax matroska_simpletag[] = { { MATROSKA_ID_TAGNAME, EBML_UTF8, 0, offsetof(MatroskaTag, name) }, { MATROSKA_ID_TAGSTRING, EBML_UTF8, 0, offsetof(MatroskaTag, string) }, { MATROSKA_ID_TAGLANG, EBML_STR, 0, offsetof(MatroskaTag, lang), { .s = "und" } }, { MATROSKA_ID_TAGDEFAULT, EBML_UINT, 0, offsetof(MatroskaTag, def) }, { MATROSKA_ID_TAGDEFAULT_BUG, EBML_UINT, 0, offsetof(MatroskaTag, def) }, { MATROSKA_ID_SIMPLETAG, EBML_NEST, sizeof(MatroskaTag), offsetof(MatroskaTag, sub), { .n = matroska_simpletag } }, - { 0 } + CHILD_OF(matroska_tag) }; -static const EbmlSyntax matroska_tagtargets[] = { +static EbmlSyntax matroska_tagtargets[] = { { MATROSKA_ID_TAGTARGETS_TYPE, EBML_STR, 0, offsetof(MatroskaTagTarget, type) }, { MATROSKA_ID_TAGTARGETS_TYPEVALUE, EBML_UINT, 0, offsetof(MatroskaTagTarget, typevalue), { .u = 50 } }, { MATROSKA_ID_TAGTARGETS_TRACKUID, EBML_UINT, 0, offsetof(MatroskaTagTarget, trackuid) }, { MATROSKA_ID_TAGTARGETS_CHAPTERUID, EBML_UINT, 0, offsetof(MatroskaTagTarget, chapteruid) }, { MATROSKA_ID_TAGTARGETS_ATTACHUID, EBML_UINT, 0, offsetof(MatroskaTagTarget, attachuid) }, - { 0 } + CHILD_OF(matroska_tag) }; -static const EbmlSyntax matroska_tag[] = { +static EbmlSyntax matroska_tag[] = { { MATROSKA_ID_SIMPLETAG, EBML_NEST, sizeof(MatroskaTag), offsetof(MatroskaTags, tag), { .n = matroska_simpletag } }, { MATROSKA_ID_TAGTARGETS, EBML_NEST, 0, offsetof(MatroskaTags, target), { .n = matroska_tagtargets } }, - { 0 } + CHILD_OF(matroska_tags) }; -static const EbmlSyntax matroska_tags[] = { +static EbmlSyntax matroska_tags[] = { { MATROSKA_ID_TAG, EBML_NEST, sizeof(MatroskaTags), offsetof(MatroskaDemuxContext, tags), { .n = matroska_tag } }, - { 0 } + CHILD_OF(matroska_segment) }; -static const EbmlSyntax matroska_seekhead_entry[] = { +static EbmlSyntax matroska_seekhead_entry[] = { { MATROSKA_ID_SEEKID, EBML_UINT, 0, offsetof(MatroskaSeekhead, id) }, { MATROSKA_ID_SEEKPOSITION, EBML_UINT, 0, offsetof(MatroskaSeekhead, pos), { .u = -1 } }, - { 0 } + CHILD_OF(matroska_seekhead) }; -static const EbmlSyntax matroska_seekhead[] = { +static EbmlSyntax matroska_seekhead[] = { { MATROSKA_ID_SEEKENTRY, EBML_NEST, sizeof(MatroskaSeekhead), offsetof(MatroskaDemuxContext, seekhead), { .n = matroska_seekhead_entry } }, - { 0 } + CHILD_OF(matroska_segment) }; -static const EbmlSyntax matroska_segment[] = { +static EbmlSyntax matroska_segment[] = { + { MATROSKA_ID_CLUSTER, EBML_STOP }, { MATROSKA_ID_INFO, EBML_LEVEL1, 0, 0, { .n = matroska_info } }, { MATROSKA_ID_TRACKS, EBML_LEVEL1, 0, 0, { .n = matroska_tracks } }, { MATROSKA_ID_ATTACHMENTS, EBML_LEVEL1, 0, 0, { .n = matroska_attachments } }, @@ -674,104 +698,94 @@ static const EbmlSyntax matroska_segment[] = { { MATROSKA_ID_CUES, EBML_LEVEL1, 0, 0, { .n = matroska_index } }, { MATROSKA_ID_TAGS, EBML_LEVEL1, 0, 0, { .n = matroska_tags } }, { MATROSKA_ID_SEEKHEAD, EBML_LEVEL1, 0, 0, { .n = matroska_seekhead } }, - { MATROSKA_ID_CLUSTER, EBML_STOP }, - { 0 } + { 0 } /* We don't want to go back to level 0, so don't add the parent. */ }; -static const EbmlSyntax matroska_segments[] = { +static EbmlSyntax matroska_segments[] = { { MATROSKA_ID_SEGMENT, EBML_NEST, 0, 0, { .n = matroska_segment } }, { 0 } }; -static const EbmlSyntax matroska_blockmore[] = { +static EbmlSyntax matroska_blockmore[] = { { MATROSKA_ID_BLOCKADDID, EBML_UINT, 0, offsetof(MatroskaBlock,additional_id) }, { MATROSKA_ID_BLOCKADDITIONAL, EBML_BIN, 0, offsetof(MatroskaBlock,additional) }, - { 0 } + CHILD_OF(matroska_blockadditions) }; -static const EbmlSyntax matroska_blockadditions[] = { +static EbmlSyntax matroska_blockadditions[] = { { MATROSKA_ID_BLOCKMORE, EBML_NEST, 0, 0, {.n = matroska_blockmore} }, - { 0 } + CHILD_OF(matroska_blockgroup) }; -static const EbmlSyntax matroska_blockgroup[] = { +static EbmlSyntax matroska_blockgroup[] = { { MATROSKA_ID_BLOCK, EBML_BIN, 0, offsetof(MatroskaBlock, bin) }, { MATROSKA_ID_BLOCKADDITIONS, EBML_NEST, 0, 0, { .n = matroska_blockadditions} }, - { MATROSKA_ID_SIMPLEBLOCK, EBML_BIN, 0, offsetof(MatroskaBlock, bin) }, { MATROSKA_ID_BLOCKDURATION, EBML_UINT, 0, offsetof(MatroskaBlock, duration) }, { MATROSKA_ID_DISCARDPADDING, EBML_SINT, 0, offsetof(MatroskaBlock, discard_padding) }, { MATROSKA_ID_BLOCKREFERENCE, EBML_SINT, 0, offsetof(MatroskaBlock, reference), { .i = INT64_MIN } }, { MATROSKA_ID_CODECSTATE, EBML_NONE }, { 1, EBML_UINT, 0, offsetof(MatroskaBlock, non_simple), { .u = 1 } }, - { 0 } + CHILD_OF(matroska_cluster_parsing) }; -static const EbmlSyntax matroska_cluster[] = { - { MATROSKA_ID_CLUSTERTIMECODE, EBML_UINT, 0, offsetof(MatroskaCluster, timecode) }, - { MATROSKA_ID_BLOCKGROUP, EBML_NEST, sizeof(MatroskaBlock), offsetof(MatroskaCluster, blocks), { .n = matroska_blockgroup } }, - { MATROSKA_ID_SIMPLEBLOCK, EBML_PASS, sizeof(MatroskaBlock), offsetof(MatroskaCluster, blocks), { .n = matroska_blockgroup } }, - { MATROSKA_ID_CLUSTERPOSITION, EBML_NONE }, - { MATROSKA_ID_CLUSTERPREVSIZE, EBML_NONE }, - { 0 } -}; - -static const EbmlSyntax matroska_clusters[] = { - { MATROSKA_ID_CLUSTER, EBML_NEST, 0, 0, { .n = matroska_cluster } }, - { MATROSKA_ID_INFO, EBML_NONE }, - { MATROSKA_ID_CUES, EBML_NONE }, - { MATROSKA_ID_TAGS, EBML_NONE }, - { MATROSKA_ID_SEEKHEAD, EBML_NONE }, - { 0 } -}; - -static const EbmlSyntax matroska_cluster_incremental_parsing[] = { - { MATROSKA_ID_CLUSTERTIMECODE, EBML_UINT, 0, offsetof(MatroskaCluster, timecode) }, - { MATROSKA_ID_BLOCKGROUP, EBML_NEST, sizeof(MatroskaBlock), offsetof(MatroskaCluster, blocks), { .n = matroska_blockgroup } }, - { MATROSKA_ID_SIMPLEBLOCK, EBML_PASS, sizeof(MatroskaBlock), offsetof(MatroskaCluster, blocks), { .n = matroska_blockgroup } }, - { MATROSKA_ID_CLUSTERPOSITION, EBML_NONE }, - { MATROSKA_ID_CLUSTERPREVSIZE, EBML_NONE }, - { MATROSKA_ID_INFO, EBML_NONE }, - { MATROSKA_ID_CUES, EBML_NONE }, - { MATROSKA_ID_TAGS, EBML_NONE }, - { MATROSKA_ID_SEEKHEAD, EBML_NONE }, - { MATROSKA_ID_CLUSTER, EBML_STOP }, - { 0 } -}; - -static const EbmlSyntax matroska_cluster_incremental[] = { +// The following array contains SimpleBlock and BlockGroup twice +// in order to reuse the other values for matroska_cluster_enter. +static EbmlSyntax matroska_cluster_parsing[] = { + { MATROSKA_ID_SIMPLEBLOCK, EBML_BIN, 0, offsetof(MatroskaBlock, bin) }, + { MATROSKA_ID_BLOCKGROUP, EBML_NEST, 0, 0, { .n = matroska_blockgroup } }, { MATROSKA_ID_CLUSTERTIMECODE, EBML_UINT, 0, offsetof(MatroskaCluster, timecode) }, - { MATROSKA_ID_BLOCKGROUP, EBML_STOP }, { MATROSKA_ID_SIMPLEBLOCK, EBML_STOP }, + { MATROSKA_ID_BLOCKGROUP, EBML_STOP }, { MATROSKA_ID_CLUSTERPOSITION, EBML_NONE }, { MATROSKA_ID_CLUSTERPREVSIZE, EBML_NONE }, - { 0 } + CHILD_OF(matroska_segment) }; -static const EbmlSyntax matroska_clusters_incremental[] = { - { MATROSKA_ID_CLUSTER, EBML_NEST, 0, 0, { .n = matroska_cluster_incremental } }, - { MATROSKA_ID_INFO, EBML_NONE }, - { MATROSKA_ID_CUES, EBML_NONE }, - { MATROSKA_ID_TAGS, EBML_NONE }, - { MATROSKA_ID_SEEKHEAD, EBML_NONE }, +static EbmlSyntax matroska_cluster_enter[] = { + { MATROSKA_ID_CLUSTER, EBML_NEST, 0, 0, { .n = &matroska_cluster_parsing[2] } }, { 0 } }; +#undef CHILD_OF static const char *const matroska_doctypes[] = { "matroska", "webm" }; static int matroska_read_close(AVFormatContext *s); +/* + * This function prepares the status for parsing of level 1 elements. + */ +static int matroska_reset_status(MatroskaDemuxContext *matroska, + uint32_t id, int64_t position) +{ + if (position >= 0) { + int64_t err = avio_seek(matroska->ctx->pb, position, SEEK_SET); + if (err < 0) + return err; + } + + matroska->current_id = id; + matroska->num_levels = 1; + matroska->unknown_count = 0; + matroska->resync_pos = avio_tell(matroska->ctx->pb); + if (id) + matroska->resync_pos -= (av_log2(id) + 7) / 8; + + return 0; +} + static int matroska_resync(MatroskaDemuxContext *matroska, int64_t last_pos) { AVIOContext *pb = matroska->ctx->pb; - int64_t ret; uint32_t id; - matroska->current_id = 0; - matroska->num_levels = 0; - /* seek to next position to resync from */ - if ((ret = avio_seek(pb, last_pos + 1, SEEK_SET)) < 0) { - matroska->done = 1; - return ret; + /* Try to seek to the last position to resync from. If this doesn't work, + * we resync from the earliest position available: The start of the buffer. */ + if (last_pos < avio_tell(pb) && avio_seek(pb, last_pos + 1, SEEK_SET) < 0) { + av_log(matroska->ctx, AV_LOG_WARNING, + "Seek to desired resync point failed. Seeking to " + "earliest point available instead.\n"); + avio_seek(pb, FFMAX(avio_tell(pb) + (pb->buffer - pb->buf_ptr), + last_pos + 1), SEEK_SET); } id = avio_rb32(pb); @@ -782,32 +796,20 @@ static int matroska_resync(MatroskaDemuxContext *matroska, int64_t last_pos) id == MATROSKA_ID_CUES || id == MATROSKA_ID_TAGS || id == MATROSKA_ID_SEEKHEAD || id == MATROSKA_ID_ATTACHMENTS || id == MATROSKA_ID_CLUSTER || id == MATROSKA_ID_CHAPTERS) { - matroska->current_id = id; + /* Prepare the context for parsing of a level 1 element. */ + matroska_reset_status(matroska, id, -1); + /* Given that we are here means that an error has occured, + * so treat the segment as unknown length in order not to + * discard valid data that happens to be beyond the designated + * end of the segment. */ + matroska->levels[0].length = EBML_UNKNOWN_LENGTH; return 0; } id = (id << 8) | avio_r8(pb); } matroska->done = 1; - return AVERROR_EOF; -} - -/* - * Return: Whether we reached the end of a level in the hierarchy or not. - */ -static int ebml_level_end(MatroskaDemuxContext *matroska) -{ - AVIOContext *pb = matroska->ctx->pb; - int64_t pos = avio_tell(pb); - - if (matroska->num_levels > 0) { - MatroskaLevel *level = &matroska->levels[matroska->num_levels - 1]; - if (pos - level->start >= level->length || matroska->current_id) { - matroska->num_levels--; - return 1; - } - } - return (matroska->is_live && matroska->ctx->pb->eof_reached) ? 1 : 0; + return pb->error ? pb->error : AVERROR_EOF; } /* @@ -819,33 +821,32 @@ static int ebml_level_end(MatroskaDemuxContext *matroska) * Returns: number of bytes read, < 0 on error */ static int ebml_read_num(MatroskaDemuxContext *matroska, AVIOContext *pb, - int max_size, uint64_t *number) + int max_size, uint64_t *number, int eof_forbidden) { - int read = 1, n = 1; - uint64_t total = 0; + int read, n = 1; + uint64_t total; + int64_t pos; - /* The first byte tells us the length in bytes - avio_r8() can normally - * return 0, but since that's not a valid first ebmlID byte, we can - * use it safely here to catch EOS. */ - if (!(total = avio_r8(pb))) { - /* we might encounter EOS here */ - if (!avio_feof(pb)) { - int64_t pos = avio_tell(pb); - av_log(matroska->ctx, AV_LOG_ERROR, - "Read error at pos. %"PRIu64" (0x%"PRIx64")\n", - pos, pos); - return pb->error ? pb->error : AVERROR(EIO); - } - return AVERROR_EOF; - } + /* The first byte tells us the length in bytes - except when it is zero. */ + total = avio_r8(pb); + if (pb->eof_reached) + goto err; /* get the length of the EBML number */ read = 8 - ff_log2_tab[total]; - if (read > max_size) { - int64_t pos = avio_tell(pb) - 1; - av_log(matroska->ctx, AV_LOG_ERROR, - "Invalid EBML number size tag 0x%02x at pos %"PRIu64" (0x%"PRIx64")\n", - (uint8_t) total, pos, pos); + + if (!total || read > max_size) { + pos = avio_tell(pb) - 1; + if (!total) { + av_log(matroska->ctx, AV_LOG_ERROR, + "0x00 at pos %"PRId64" (0x%"PRIx64") invalid as first byte " + "of an EBML number\n", pos, pos); + } else { + av_log(matroska->ctx, AV_LOG_ERROR, + "Length %d indicated by an EBML number's first byte 0x%02x " + "at pos %"PRId64" (0x%"PRIx64") exceeds max length %d.\n", + read, (uint8_t) total, pos, pos, max_size); + } return AVERROR_INVALIDDATA; } @@ -854,9 +855,29 @@ static int ebml_read_num(MatroskaDemuxContext *matroska, AVIOContext *pb, while (n++ < read) total = (total << 8) | avio_r8(pb); + if (pb->eof_reached) { + eof_forbidden = 1; + goto err; + } + *number = total; return read; + +err: + pos = avio_tell(pb); + if (pb->error) { + av_log(matroska->ctx, AV_LOG_ERROR, + "Read error at pos. %"PRIu64" (0x%"PRIx64")\n", + pos, pos); + return pb->error; + } + if (eof_forbidden) { + av_log(matroska->ctx, AV_LOG_ERROR, "File ended prematurely " + "at pos. %"PRIu64" (0x%"PRIx64")\n", pos, pos); + return AVERROR(EIO); + } + return AVERROR_EOF; } /** @@ -867,42 +888,36 @@ static int ebml_read_num(MatroskaDemuxContext *matroska, AVIOContext *pb, static int ebml_read_length(MatroskaDemuxContext *matroska, AVIOContext *pb, uint64_t *number) { - int res = ebml_read_num(matroska, pb, 8, number); + int res = ebml_read_num(matroska, pb, 8, number, 1); if (res > 0 && *number + 1 == 1ULL << (7 * res)) - *number = 0xffffffffffffffULL; + *number = EBML_UNKNOWN_LENGTH; return res; } /* * Read the next element as an unsigned int. - * 0 is success, < 0 is failure. + * Returns NEEDS_CHECKING. */ static int ebml_read_uint(AVIOContext *pb, int size, uint64_t *num) { int n = 0; - if (size > 8) - return AVERROR_INVALIDDATA; - /* big-endian ordering; build up number */ *num = 0; while (n++ < size) *num = (*num << 8) | avio_r8(pb); - return 0; + return NEEDS_CHECKING; } /* * Read the next element as a signed int. - * 0 is success, < 0 is failure. + * Returns NEEDS_CHECKING. */ static int ebml_read_sint(AVIOContext *pb, int size, int64_t *num) { int n = 1; - if (size > 8) - return AVERROR_INVALIDDATA; - if (size == 0) { *num = 0; } else { @@ -913,12 +928,12 @@ static int ebml_read_sint(AVIOContext *pb, int size, int64_t *num) *num = ((uint64_t)*num << 8) | avio_r8(pb); } - return 0; + return NEEDS_CHECKING; } /* * Read the next element as a float. - * 0 is success, < 0 is failure. + * Returns NEEDS_CHECKING or < 0 on obvious failure. */ static int ebml_read_float(AVIOContext *pb, int size, double *num) { @@ -931,24 +946,25 @@ static int ebml_read_float(AVIOContext *pb, int size, double *num) else return AVERROR_INVALIDDATA; - return 0; + return NEEDS_CHECKING; } /* * Read the next element as an ASCII string. - * 0 is success, < 0 is failure. + * 0 is success, < 0 or NEEDS_CHECKING is failure. */ static int ebml_read_ascii(AVIOContext *pb, int size, char **str) { char *res; + int ret; /* EBML strings are usually not 0-terminated, so we allocate one * byte more, read the string and NULL-terminate it ourselves. */ if (!(res = av_malloc(size + 1))) return AVERROR(ENOMEM); - if (avio_read(pb, (uint8_t *) res, size) != size) { + if ((ret = avio_read(pb, (uint8_t *) res, size)) != size) { av_free(res); - return AVERROR(EIO); + return ret < 0 ? ret : NEEDS_CHECKING; } (res)[size] = '\0'; av_free(*str); @@ -959,9 +975,10 @@ static int ebml_read_ascii(AVIOContext *pb, int size, char **str) /* * Read the next element as binary data. - * 0 is success, < 0 is failure. + * 0 is success, < 0 or NEEDS_CHECKING is failure. */ -static int ebml_read_binary(AVIOContext *pb, int length, EbmlBin *bin) +static int ebml_read_binary(AVIOContext *pb, int length, + int64_t pos, EbmlBin *bin) { int ret; @@ -972,12 +989,12 @@ static int ebml_read_binary(AVIOContext *pb, int length, EbmlBin *bin) bin->data = bin->buf->data; bin->size = length; - bin->pos = avio_tell(pb); - if (avio_read(pb, bin->data, length) != length) { + bin->pos = pos; + if ((ret = avio_read(pb, bin->data, length)) != length) { av_buffer_unref(&bin->buf); bin->data = NULL; bin->size = 0; - return AVERROR(EIO); + return ret < 0 ? ret : NEEDS_CHECKING; } return 0; @@ -988,9 +1005,9 @@ static int ebml_read_binary(AVIOContext *pb, int length, EbmlBin *bin) * are supposed to be sub-elements which can be read separately. * 0 is success, < 0 is failure. */ -static int ebml_read_master(MatroskaDemuxContext *matroska, uint64_t length) +static int ebml_read_master(MatroskaDemuxContext *matroska, + uint64_t length, int64_t pos) { - AVIOContext *pb = matroska->ctx->pb; MatroskaLevel *level; if (matroska->num_levels >= EBML_MAX_DEPTH) { @@ -1000,7 +1017,7 @@ static int ebml_read_master(MatroskaDemuxContext *matroska, uint64_t length) } level = &matroska->levels[matroska->num_levels++]; - level->start = avio_tell(pb); + level->start = pos; level->length = length; return 0; @@ -1015,7 +1032,7 @@ static int matroska_ebmlnum_uint(MatroskaDemuxContext *matroska, { AVIOContext pb; ffio_init_context(&pb, data, size, 0, NULL, NULL, NULL, NULL); - return ebml_read_num(matroska, &pb, FFMIN(size, 8), num); + return ebml_read_num(matroska, &pb, FFMIN(size, 8), num, 1); } /* @@ -1037,74 +1054,62 @@ static int matroska_ebmlnum_sint(MatroskaDemuxContext *matroska, return res; } -static int ebml_parse_elem(MatroskaDemuxContext *matroska, - EbmlSyntax *syntax, void *data); +static int ebml_parse(MatroskaDemuxContext *matroska, + EbmlSyntax *syntax, void *data); -static int ebml_parse_id(MatroskaDemuxContext *matroska, EbmlSyntax *syntax, - uint32_t id, void *data) +static EbmlSyntax *ebml_parse_id(EbmlSyntax *syntax, uint32_t id) { int i; + + // Whoever touches this should be aware of the duplication + // existing in matroska_cluster_parsing. for (i = 0; syntax[i].id; i++) if (id == syntax[i].id) break; - if (!syntax[i].id && id == MATROSKA_ID_CLUSTER && - matroska->num_levels > 0 && - matroska->levels[matroska->num_levels - 1].length == 0xffffffffffffff) - return 0; // we reached the end of an unknown size cluster - if (!syntax[i].id && id != EBML_ID_VOID && id != EBML_ID_CRC32) { - av_log(matroska->ctx, AV_LOG_DEBUG, "Unknown entry 0x%"PRIX32"\n", id); - } - return ebml_parse_elem(matroska, &syntax[i], data); -} -static int ebml_parse(MatroskaDemuxContext *matroska, EbmlSyntax *syntax, - void *data) -{ - if (!matroska->current_id) { - uint64_t id; - int res = ebml_read_num(matroska, matroska->ctx->pb, 4, &id); - if (res < 0) { - // in live mode, finish parsing if EOF is reached. - return (matroska->is_live && matroska->ctx->pb->eof_reached && - res == AVERROR_EOF) ? 1 : res; - } - matroska->current_id = id | 1 << 7 * res; - } - return ebml_parse_id(matroska, syntax, matroska->current_id, data); + return &syntax[i]; } static int ebml_parse_nest(MatroskaDemuxContext *matroska, EbmlSyntax *syntax, void *data) { - int i, res = 0; + int res; - for (i = 0; syntax[i].id; i++) - switch (syntax[i].type) { - case EBML_SINT: - *(int64_t *) ((char *) data + syntax[i].data_offset) = syntax[i].def.i; - break; - case EBML_UINT: - *(uint64_t *) ((char *) data + syntax[i].data_offset) = syntax[i].def.u; - break; - case EBML_FLOAT: - *(double *) ((char *) data + syntax[i].data_offset) = syntax[i].def.f; - break; - case EBML_STR: - case EBML_UTF8: - // the default may be NULL - if (syntax[i].def.s) { - uint8_t **dst = (uint8_t **) ((uint8_t *) data + syntax[i].data_offset); - *dst = av_strdup(syntax[i].def.s); - if (!*dst) - return AVERROR(ENOMEM); + if (data) { + for (int i = 0; syntax[i].id; i++) + switch (syntax[i].type) { + case EBML_UINT: + *(uint64_t *) ((char *) data + syntax[i].data_offset) = syntax[i].def.u; + break; + case EBML_SINT: + *(int64_t *) ((char *) data + syntax[i].data_offset) = syntax[i].def.i; + break; + case EBML_FLOAT: + *(double *) ((char *) data + syntax[i].data_offset) = syntax[i].def.f; + break; + case EBML_STR: + case EBML_UTF8: + // the default may be NULL + if (syntax[i].def.s) { + uint8_t **dst = (uint8_t **) ((uint8_t *) data + syntax[i].data_offset); + *dst = av_strdup(syntax[i].def.s); + if (!*dst) + return AVERROR(ENOMEM); + } + break; } - break; + + if (!matroska->levels[matroska->num_levels - 1].length) { + matroska->num_levels--; + return 0; } + } - while (!res && !ebml_level_end(matroska)) + do { res = ebml_parse(matroska, syntax, data); + } while (!res); - return res; + return res == LEVEL_ENDED ? 0 : res; } static int is_ebml_id_valid(uint32_t id) @@ -1155,11 +1160,14 @@ static MatroskaLevel1Element *matroska_find_level1_elem(MatroskaDemuxContext *ma return elem; } -static int ebml_parse_elem(MatroskaDemuxContext *matroska, - EbmlSyntax *syntax, void *data) +static int ebml_parse(MatroskaDemuxContext *matroska, + EbmlSyntax *syntax, void *data) { static const uint64_t max_lengths[EBML_TYPE_COUNT] = { + // Forbid unknown-length EBML_NONE elements. + [EBML_NONE] = EBML_UNKNOWN_LENGTH - 1, [EBML_UINT] = 8, + [EBML_SINT] = 8, [EBML_FLOAT] = 8, // max. 16 MB for strings [EBML_STR] = 0x1000000, @@ -1169,34 +1177,200 @@ static int ebml_parse_elem(MatroskaDemuxContext *matroska, // no limits for anything else }; AVIOContext *pb = matroska->ctx->pb; - uint32_t id = syntax->id; + uint32_t id; uint64_t length; - int res; - void *newelem; + int64_t pos = avio_tell(pb), pos_alt; + int res, update_pos = 1, level_check; MatroskaLevel1Element *level1_elem; + MatroskaLevel *level = matroska->num_levels ? &matroska->levels[matroska->num_levels - 1] : NULL; - data = (char *) data + syntax->data_offset; - if (syntax->list_elem_size) { - EbmlList *list = data; - newelem = av_realloc_array(list->elem, list->nb_elem + 1, syntax->list_elem_size); - if (!newelem) - return AVERROR(ENOMEM); - list->elem = newelem; - data = (char *) list->elem + list->nb_elem * syntax->list_elem_size; - memset(data, 0, syntax->list_elem_size); - list->nb_elem++; + if (!matroska->current_id) { + uint64_t id; + res = ebml_read_num(matroska, pb, 4, &id, 0); + if (res < 0) { + if (pb->eof_reached && res == AVERROR_EOF) { + if (matroska->is_live) + // in live mode, finish parsing if EOF is reached. + return 1; + if (level && pos == avio_tell(pb)) { + if (level->length == EBML_UNKNOWN_LENGTH) { + // Unknown-length levels automatically end at EOF. + matroska->num_levels--; + return LEVEL_ENDED; + } else { + av_log(matroska->ctx, AV_LOG_ERROR, "File ended prematurely " + "at pos. %"PRIu64" (0x%"PRIx64")\n", pos, pos); + } + } + } + return res; + } + matroska->current_id = id | 1 << 7 * res; + pos_alt = pos + res; + } else { + pos_alt = pos; + pos -= (av_log2(matroska->current_id) + 7) / 8; } - if (syntax->type != EBML_PASS && syntax->type != EBML_STOP) { + id = matroska->current_id; + + syntax = ebml_parse_id(syntax, id); + if (!syntax->id && id != EBML_ID_VOID && id != EBML_ID_CRC32) { + if (level && level->length == EBML_UNKNOWN_LENGTH) { + // Unknown-length levels end when an element from an upper level + // in the hierarchy is encountered. + while (syntax->def.n) { + syntax = ebml_parse_id(syntax->def.n, id); + if (syntax->id) { + matroska->num_levels--; + return LEVEL_ENDED; + } + }; + } + + av_log(matroska->ctx, AV_LOG_DEBUG, "Unknown entry 0x%"PRIX32" at pos. " + "%"PRId64"\n", id, pos); + update_pos = 0; /* Don't update resync_pos as an error might have happened. */ + } + + if (data) { + data = (char *) data + syntax->data_offset; + if (syntax->list_elem_size) { + EbmlList *list = data; + void *newelem; + + if ((unsigned)list->nb_elem + 1 >= UINT_MAX / syntax->list_elem_size) + return AVERROR(ENOMEM); + newelem = av_fast_realloc(list->elem, + &list->alloc_elem_size, + (list->nb_elem + 1) * syntax->list_elem_size); + if (!newelem) + return AVERROR(ENOMEM); + list->elem = newelem; + data = (char *) list->elem + list->nb_elem * syntax->list_elem_size; + memset(data, 0, syntax->list_elem_size); + list->nb_elem++; + } + } + + if (syntax->type != EBML_STOP) { matroska->current_id = 0; if ((res = ebml_read_length(matroska, pb, &length)) < 0) return res; + + pos_alt += res; + + if (matroska->num_levels > 0) { + if (length != EBML_UNKNOWN_LENGTH && + level->length != EBML_UNKNOWN_LENGTH) { + uint64_t elem_end = pos_alt + length, + level_end = level->start + level->length; + + if (elem_end < level_end) { + level_check = 0; + } else if (elem_end == level_end) { + level_check = LEVEL_ENDED; + } else { + av_log(matroska->ctx, AV_LOG_ERROR, + "Element at 0x%"PRIx64" ending at 0x%"PRIx64" exceeds " + "containing master element ending at 0x%"PRIx64"\n", + pos, elem_end, level_end); + return AVERROR_INVALIDDATA; + } + } else if (length != EBML_UNKNOWN_LENGTH) { + level_check = 0; + } else if (level->length != EBML_UNKNOWN_LENGTH) { + av_log(matroska->ctx, AV_LOG_ERROR, "Unknown-sized element " + "at 0x%"PRIx64" inside parent with finite size\n", pos); + return AVERROR_INVALIDDATA; + } else { + level_check = 0; + if (id != MATROSKA_ID_CLUSTER && (syntax->type == EBML_LEVEL1 + || syntax->type == EBML_NEST)) { + // According to the current specifications only clusters and + // segments are allowed to be unknown-length. We also accept + // other unknown-length master elements. + av_log(matroska->ctx, AV_LOG_WARNING, + "Found unknown-length element 0x%"PRIX32" other than " + "a cluster at 0x%"PRIx64". Spec-incompliant, but " + "parsing will nevertheless be attempted.\n", id, pos); + update_pos = -1; + } + } + } else + level_check = 0; + if (max_lengths[syntax->type] && length > max_lengths[syntax->type]) { - av_log(matroska->ctx, AV_LOG_ERROR, - "Invalid length 0x%"PRIx64" > 0x%"PRIx64" for syntax element %i\n", - length, max_lengths[syntax->type], syntax->type); + if (length != EBML_UNKNOWN_LENGTH) { + av_log(matroska->ctx, AV_LOG_ERROR, + "Invalid length 0x%"PRIx64" > 0x%"PRIx64" for element " + "with ID 0x%"PRIX32" at 0x%"PRIx64"\n", + length, max_lengths[syntax->type], id, pos); + } else if (syntax->type != EBML_NONE) { + av_log(matroska->ctx, AV_LOG_ERROR, + "Element with ID 0x%"PRIX32" at pos. 0x%"PRIx64" has " + "unknown length, yet the length of an element of its " + "type must be known.\n", id, pos); + } else { + av_log(matroska->ctx, AV_LOG_ERROR, + "Found unknown-length element with ID 0x%"PRIX32" at " + "pos. 0x%"PRIx64" for which no syntax for parsing is " + "available.\n", id, pos); + } return AVERROR_INVALIDDATA; } + + if (!(pb->seekable & AVIO_SEEKABLE_NORMAL)) { + // Loosing sync will likely manifest itself as encountering unknown + // elements which are not reliably distinguishable from elements + // belonging to future extensions of the format. + // We use a heuristic to detect such situations: If the current + // element is not expected at the current syntax level and there + // were only a few unknown elements in a row, then the element is + // skipped or considered defective based upon the length of the + // current element (i.e. how much would be skipped); if there were + // more than a few skipped elements in a row and skipping the current + // element would lead us more than SKIP_THRESHOLD away from the last + // known good position, then it is inferred that an error occured. + // The dependency on the number of unknown elements in a row exists + // because the distance to the last known good position is + // automatically big if the last parsed element was big. + // In both cases, each unknown element is considered equivalent to + // UNKNOWN_EQUIV of skipped bytes for the check. + // The whole check is only done for non-seekable output, because + // in this situation skipped data can't simply be rechecked later. + // This is especially important when using unkown length elements + // as the check for whether a child exceeds its containing master + // element is not effective in this situation. + if (update_pos) { + matroska->unknown_count = 0; + } else { + int64_t dist = length + UNKNOWN_EQUIV * matroska->unknown_count++; + + if (matroska->unknown_count > 3) + dist += pos_alt - matroska->resync_pos; + + if (dist > SKIP_THRESHOLD) { + av_log(matroska->ctx, AV_LOG_ERROR, + "Unknown element %"PRIX32" at pos. 0x%"PRIx64" with " + "length 0x%"PRIx64" considered as invalid data. Last " + "known good position 0x%"PRIx64", %d unknown elements" + " in a row\n", id, pos, length, matroska->resync_pos, + matroska->unknown_count); + return AVERROR_INVALIDDATA; + } + } + } + + if (update_pos > 0) { + // We have found an element that is allowed at this place + // in the hierarchy and it passed all checks, so treat the beginning + // of the element as the "last known good" position. + matroska->resync_pos = pos; + } + + if (!data && length != EBML_UNKNOWN_LENGTH) + goto skip; } switch (syntax->type) { @@ -1214,37 +1388,89 @@ static int ebml_parse_elem(MatroskaDemuxContext *matroska, res = ebml_read_ascii(pb, length, data); break; case EBML_BIN: - res = ebml_read_binary(pb, length, data); + res = ebml_read_binary(pb, length, pos_alt, data); break; case EBML_LEVEL1: case EBML_NEST: - if ((res = ebml_read_master(matroska, length)) < 0) + if ((res = ebml_read_master(matroska, length, pos_alt)) < 0) return res; if (id == MATROSKA_ID_SEGMENT) - matroska->segment_start = avio_tell(matroska->ctx->pb); + matroska->segment_start = pos_alt; if (id == MATROSKA_ID_CUES) matroska->cues_parsing_deferred = 0; if (syntax->type == EBML_LEVEL1 && (level1_elem = matroska_find_level1_elem(matroska, syntax->id))) { - if (level1_elem->parsed) + if (!level1_elem->pos) { + // Zero is not a valid position for a level 1 element. + level1_elem->pos = pos; + } else if (level1_elem->pos != pos) av_log(matroska->ctx, AV_LOG_ERROR, "Duplicate element\n"); level1_elem->parsed = 1; } - return ebml_parse_nest(matroska, syntax->def.n, data); - case EBML_PASS: - return ebml_parse_id(matroska, syntax->def.n, id, data); + if (res = ebml_parse_nest(matroska, syntax->def.n, data)) + return res; + break; case EBML_STOP: return 1; + skip: default: - if (ffio_limit(pb, length) != length) - return AVERROR(EIO); - return avio_skip(pb, length) < 0 ? AVERROR(EIO) : 0; + if (length) { + int64_t res2; + if (ffio_limit(pb, length) != length) { + // ffio_limit emits its own error message, + // so we don't have to. + return AVERROR(EIO); + } + if ((res2 = avio_skip(pb, length - 1)) >= 0) { + // avio_skip might take us past EOF. We check for this + // by skipping only length - 1 bytes, reading a byte and + // checking the error flags. This is done in order to check + // that the element has been properly skipped even when + // no filesize (that ffio_limit relies on) is available. + avio_r8(pb); + res = NEEDS_CHECKING; + } else + res = res2; + } else + res = 0; } - if (res == AVERROR_INVALIDDATA) - av_log(matroska->ctx, AV_LOG_ERROR, "Invalid element\n"); - else if (res == AVERROR(EIO)) - av_log(matroska->ctx, AV_LOG_ERROR, "Read error\n"); - return res; + if (res) { + if (res == NEEDS_CHECKING) { + if (pb->eof_reached) { + if (pb->error) + res = pb->error; + else + res = AVERROR_EOF; + } else + goto level_check; + } + + if (res == AVERROR_INVALIDDATA) + av_log(matroska->ctx, AV_LOG_ERROR, "Invalid element\n"); + else if (res == AVERROR(EIO)) + av_log(matroska->ctx, AV_LOG_ERROR, "Read error\n"); + else if (res == AVERROR_EOF) { + av_log(matroska->ctx, AV_LOG_ERROR, "File ended prematurely\n"); + res = AVERROR(EIO); + } + + return res; + } + +level_check: + if (level_check == LEVEL_ENDED && matroska->num_levels) { + level = &matroska->levels[matroska->num_levels - 1]; + pos = avio_tell(pb); + + // Given that pos >= level->start no check for + // level->length != EBML_UNKNOWN_LENGTH is necessary. + while (matroska->num_levels && pos == level->start + level->length) { + matroska->num_levels--; + level--; + } + } + + return level_check; } static void ebml_free(EbmlSyntax *syntax, void *data) @@ -1270,6 +1496,7 @@ static void ebml_free(EbmlSyntax *syntax, void *data) ebml_free(syntax[i].def.n, ptr); av_freep(&list->elem); list->nb_elem = 0; + list->alloc_elem_size = 0; } else ebml_free(syntax[i].def.n, data_off); default: @@ -1281,7 +1508,7 @@ static void ebml_free(EbmlSyntax *syntax, void *data) /* * Autodetecting... */ -static int matroska_probe(AVProbeData *p) +static int matroska_probe(const AVProbeData *p) { uint64_t total = 0; int len_mask = 0x80, size = 1, n = 1, i; @@ -1302,9 +1529,14 @@ static int matroska_probe(AVProbeData *p) while (n < size) total = (total << 8) | p->buf[4 + n++]; - /* Does the probe data contain the whole header? */ - if (p->buf_size < 4 + size + total) - return 0; + if (total + 1 == 1ULL << (7 * size)){ + /* Unknown-length header - simply parse the whole buffer. */ + total = p->buf_size - 4 - size; + } else { + /* Does the probe data contain the whole header? */ + if (p->buf_size < 4 + size + total) + return 0; + } /* The header should contain a known document type. For now, * we don't parse the whole header but simply check for the @@ -1577,18 +1809,14 @@ static void matroska_convert_tags(AVFormatContext *s) } static int matroska_parse_seekhead_entry(MatroskaDemuxContext *matroska, - uint64_t pos) + int64_t pos) { - uint32_t level_up = matroska->level_up; - uint32_t saved_id = matroska->current_id; + uint32_t saved_id = matroska->current_id; int64_t before_pos = avio_tell(matroska->ctx->pb); - MatroskaLevel level; - int64_t offset; int ret = 0; /* seek */ - offset = pos + matroska->segment_start; - if (avio_seek(matroska->ctx->pb, offset, SEEK_SET) == offset) { + if (avio_seek(matroska->ctx->pb, pos, SEEK_SET) == pos) { /* We don't want to lose our seekhead level, so we add * a dummy. This is a crude hack. */ if (matroska->num_levels == EBML_MAX_DEPTH) { @@ -1597,26 +1825,20 @@ static int matroska_parse_seekhead_entry(MatroskaDemuxContext *matroska, "cannot parse further.\n", EBML_MAX_DEPTH); ret = AVERROR_INVALIDDATA; } else { - level.start = 0; - level.length = (uint64_t) -1; - matroska->levels[matroska->num_levels] = level; + matroska->levels[matroska->num_levels] = (MatroskaLevel) { 0, EBML_UNKNOWN_LENGTH }; matroska->num_levels++; matroska->current_id = 0; ret = ebml_parse(matroska, matroska_segment, matroska); - - /* remove dummy level */ - while (matroska->num_levels) { - uint64_t length = matroska->levels[--matroska->num_levels].length; - if (length == (uint64_t) -1) - break; + if (ret == LEVEL_ENDED) { + /* This can only happen if the seek brought us beyond EOF. */ + ret = AVERROR_EOF; } } } - /* seek back */ - avio_seek(matroska->ctx->pb, before_pos, SEEK_SET); - matroska->level_up = level_up; - matroska->current_id = saved_id; + /* Seek back - notice that in all instances where this is used + * it is safe to set the level to 1. */ + matroska_reset_status(matroska, saved_id, before_pos); return ret; } @@ -1632,8 +1854,8 @@ static void matroska_execute_seekhead(MatroskaDemuxContext *matroska) for (i = 0; i < seekhead_list->nb_elem; i++) { MatroskaSeekhead *seekheads = seekhead_list->elem; - uint32_t id = seekheads[i].id; - uint64_t pos = seekheads[i].pos; + uint32_t id = seekheads[i].id; + int64_t pos = seekheads[i].pos + matroska->segment_start; MatroskaLevel1Element *elem = matroska_find_level1_elem(matroska, id); if (!elem || elem->parsed) @@ -2421,6 +2643,10 @@ static int matroska_parse_tracks(AVFormatContext *s) /* we don't need any value stored in CodecPrivate. make sure that it's not exported as extradata. */ track->codec_priv.size = 0; + } else if (codec_id == AV_CODEC_ID_AV1 && track->codec_priv.size) { + /* For now, propagate only the OBUs, if any. Once libavcodec is + updated to handle isobmff style extradata this can be removed. */ + extradata_offset = 4; } track->codec_priv.size -= extradata_offset; @@ -2574,8 +2800,6 @@ static int matroska_parse_tracks(AVFormatContext *s) } } else if (track->type == MATROSKA_TRACK_TYPE_SUBTITLE) { st->codecpar->codec_type = AVMEDIA_TYPE_SUBTITLE; - if (st->codecpar->codec_id == AV_CODEC_ID_ASS) - matroska->contains_ssa = 1; } } @@ -2633,7 +2857,7 @@ static int matroska_read_header(AVFormatContext *s) /* The next thing is a segment. */ pos = avio_tell(matroska->ctx->pb); res = ebml_parse(matroska, matroska_segments, matroska); - // try resyncing until we find a EBML_STOP type element. + // Try resyncing until we find an EBML_STOP type element. while (res != 1) { res = matroska_resync(matroska, pos); if (res < 0) @@ -2641,6 +2865,9 @@ static int matroska_read_header(AVFormatContext *s) pos = avio_tell(matroska->ctx->pb); res = ebml_parse(matroska, matroska_segment, matroska); } + /* Set data_offset as it might be needed later by seek_frame_generic. */ + if (matroska->current_id == MATROSKA_ID_CLUSTER) + s->internal->data_offset = avio_tell(matroska->ctx->pb) - 4; matroska_execute_seekhead(matroska); if (!matroska->time_scale) @@ -2682,15 +2909,19 @@ static int matroska_read_header(AVFormatContext *s) attachments[j].stream = st; if (st->codecpar->codec_id != AV_CODEC_ID_NONE) { + AVPacket *pkt = &st->attached_pic; + st->disposition |= AV_DISPOSITION_ATTACHED_PIC; st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO; - av_init_packet(&st->attached_pic); - if ((res = av_new_packet(&st->attached_pic, attachments[j].bin.size)) < 0) - return res; - memcpy(st->attached_pic.data, attachments[j].bin.data, attachments[j].bin.size); - st->attached_pic.stream_index = st->index; - st->attached_pic.flags |= AV_PKT_FLAG_KEY; + av_init_packet(pkt); + pkt->buf = av_buffer_ref(attachments[j].bin.buf); + if (!pkt->buf) + return AVERROR(ENOMEM); + pkt->data = attachments[j].bin.data; + pkt->size = attachments[j].bin.size; + pkt->stream_index = st->index; + pkt->flags |= AV_PKT_FLAG_KEY; } else { st->codecpar->codec_type = AVMEDIA_TYPE_ATTACHMENT; if (ff_alloc_extradata(st->codecpar, attachments[j].bin.size)) @@ -2781,7 +3012,7 @@ static int matroska_parse_laces(MatroskaDemuxContext *matroska, uint8_t **buf, if (!type) { *laces = 1; - *lace_buf = av_mallocz(sizeof(int)); + *lace_buf = av_malloc(sizeof(**lace_buf)); if (!*lace_buf) return AVERROR(ENOMEM); @@ -2793,7 +3024,7 @@ static int matroska_parse_laces(MatroskaDemuxContext *matroska, uint8_t **buf, *laces = *data + 1; data += 1; size -= 1; - lace_size = av_mallocz(*laces * sizeof(int)); + lace_size = av_malloc_array(*laces, sizeof(*lace_size)); if (!lace_size) return AVERROR(ENOMEM); @@ -2803,6 +3034,8 @@ static int matroska_parse_laces(MatroskaDemuxContext *matroska, uint8_t **buf, uint8_t temp; uint32_t total = 0; for (n = 0; res == 0 && n < *laces - 1; n++) { + lace_size[n] = 0; + while (1) { if (size <= total) { res = AVERROR_INVALIDDATA; @@ -3317,7 +3550,6 @@ static int matroska_parse_block(MatroskaDemuxContext *matroska, AVBufferRef *buf int trust_default_duration = 1; if ((n = matroska_ebmlnum_uint(matroska, data, size, &num)) < 0) { - av_log(matroska->ctx, AV_LOG_ERROR, "EBML block data error\n"); return n; } data += n; @@ -3326,7 +3558,7 @@ static int matroska_parse_block(MatroskaDemuxContext *matroska, AVBufferRef *buf track = matroska_find_track_by_num(matroska, num); if (!track || !track->stream) { av_log(matroska->ctx, AV_LOG_INFO, - "Invalid stream %"PRIu64" or size %u\n", num, size); + "Invalid stream %"PRIu64"\n", num); return AVERROR_INVALIDDATA; } else if (size <= 3) return 0; @@ -3438,89 +3670,59 @@ end: return res; } -static int matroska_parse_cluster_incremental(MatroskaDemuxContext *matroska) -{ - EbmlList *blocks_list; - MatroskaBlock *blocks; - int i, res; - res = ebml_parse(matroska, - matroska_cluster_incremental_parsing, - &matroska->current_cluster); - if (res == 1) { - /* New Cluster */ - if (matroska->current_cluster_pos) - ebml_level_end(matroska); - ebml_free(matroska_cluster, &matroska->current_cluster); - memset(&matroska->current_cluster, 0, sizeof(MatroskaCluster)); - matroska->current_cluster_num_blocks = 0; - matroska->current_cluster_pos = avio_tell(matroska->ctx->pb); - /* sizeof the ID which was already read */ - if (matroska->current_id) - matroska->current_cluster_pos -= 4; - res = ebml_parse(matroska, - matroska_clusters_incremental, - &matroska->current_cluster); - /* Try parsing the block again. */ - if (res == 1) - res = ebml_parse(matroska, - matroska_cluster_incremental_parsing, - &matroska->current_cluster); - } - - if (!res && - matroska->current_cluster_num_blocks < - matroska->current_cluster.blocks.nb_elem) { - blocks_list = &matroska->current_cluster.blocks; - blocks = blocks_list->elem; - - matroska->current_cluster_num_blocks = blocks_list->nb_elem; - i = blocks_list->nb_elem - 1; - if (blocks[i].bin.size > 0 && blocks[i].bin.data) { - int is_keyframe = blocks[i].non_simple ? blocks[i].reference == INT64_MIN : -1; - uint8_t* additional = blocks[i].additional.size > 0 ? - blocks[i].additional.data : NULL; - if (!blocks[i].non_simple) - blocks[i].duration = 0; - res = matroska_parse_block(matroska, blocks[i].bin.buf, blocks[i].bin.data, - blocks[i].bin.size, blocks[i].bin.pos, - matroska->current_cluster.timecode, - blocks[i].duration, is_keyframe, - additional, blocks[i].additional_id, - blocks[i].additional.size, - matroska->current_cluster_pos, - blocks[i].discard_padding); - } - } - - return res; -} - static int matroska_parse_cluster(MatroskaDemuxContext *matroska) { - MatroskaCluster cluster = { 0 }; - EbmlList *blocks_list; - MatroskaBlock *blocks; - int i, res; - int64_t pos; + MatroskaCluster *cluster = &matroska->current_cluster; + MatroskaBlock *block = &cluster->block; + int res; - if (!matroska->contains_ssa) - return matroska_parse_cluster_incremental(matroska); - pos = avio_tell(matroska->ctx->pb); - if (matroska->current_id) - pos -= 4; /* sizeof the ID which was already read */ - res = ebml_parse(matroska, matroska_clusters, &cluster); - blocks_list = &cluster.blocks; - blocks = blocks_list->elem; - for (i = 0; i < blocks_list->nb_elem; i++) - if (blocks[i].bin.size > 0 && blocks[i].bin.data) { - int is_keyframe = blocks[i].non_simple ? blocks[i].reference == INT64_MIN : -1; - res = matroska_parse_block(matroska, blocks[i].bin.buf, blocks[i].bin.data, - blocks[i].bin.size, blocks[i].bin.pos, - cluster.timecode, blocks[i].duration, - is_keyframe, NULL, 0, 0, pos, - blocks[i].discard_padding); + av_assert0(matroska->num_levels <= 2); + + if (matroska->num_levels == 1) { + res = ebml_parse(matroska, matroska_segment, NULL); + + if (res == 1) { + /* Found a cluster: subtract the size of the ID already read. */ + cluster->pos = avio_tell(matroska->ctx->pb) - 4; + + res = ebml_parse(matroska, matroska_cluster_enter, cluster); + if (res < 0) + return res; } - ebml_free(matroska_cluster, &cluster); + } + + if (matroska->num_levels == 2) { + /* We are inside a cluster. */ + res = ebml_parse(matroska, matroska_cluster_parsing, cluster); + + if (res >= 0 && block->bin.size > 0) { + int is_keyframe = block->non_simple ? block->reference == INT64_MIN : -1; + uint8_t* additional = block->additional.size > 0 ? + block->additional.data : NULL; + + res = matroska_parse_block(matroska, block->bin.buf, block->bin.data, + block->bin.size, block->bin.pos, + cluster->timecode, block->duration, + is_keyframe, additional, block->additional_id, + block->additional.size, cluster->pos, + block->discard_padding); + } + + ebml_free(matroska_blockgroup, block); + memset(block, 0, sizeof(*block)); + } else if (!matroska->num_levels) { + if (!avio_feof(matroska->ctx->pb)) { + avio_r8(matroska->ctx->pb); + if (!avio_feof(matroska->ctx->pb)) { + av_log(matroska->ctx, AV_LOG_WARNING, "File extends beyond " + "end of segment.\n"); + return AVERROR_INVALIDDATA; + } + } + matroska->done = 1; + return AVERROR_EOF; + } + return res; } @@ -3529,12 +3731,16 @@ static int matroska_read_packet(AVFormatContext *s, AVPacket *pkt) MatroskaDemuxContext *matroska = s->priv_data; int ret = 0; + if (matroska->resync_pos == -1) { + // This can only happen if generic seeking has been used. + matroska->resync_pos = avio_tell(s->pb); + } + while (matroska_deliver_packet(matroska, pkt)) { - int64_t pos = avio_tell(matroska->ctx->pb); if (matroska->done) return (ret < 0) ? ret : AVERROR_EOF; - if (matroska_parse_cluster(matroska) < 0) - ret = matroska_resync(matroska, pos); + if (matroska_parse_cluster(matroska) < 0 && !matroska->done) + ret = matroska_resync(matroska, matroska->resync_pos); } return 0; @@ -3546,7 +3752,7 @@ static int matroska_read_seek(AVFormatContext *s, int stream_index, MatroskaDemuxContext *matroska = s->priv_data; MatroskaTrack *tracks = NULL; AVStream *st = s->streams[stream_index]; - int i, index, index_min; + int i, index; /* Parse the CUES now since we need the index data to seek. */ if (matroska->cues_parsing_deferred > 0) { @@ -3559,9 +3765,7 @@ static int matroska_read_seek(AVFormatContext *s, int stream_index, timestamp = FFMAX(timestamp, st->index_entries[0].timestamp); if ((index = av_index_search_timestamp(st, timestamp, flags)) < 0 || index == st->nb_index_entries - 1) { - avio_seek(s->pb, st->index_entries[st->nb_index_entries - 1].pos, - SEEK_SET); - matroska->current_id = 0; + matroska_reset_status(matroska, 0, st->index_entries[st->nb_index_entries - 1].pos); while ((index = av_index_search_timestamp(st, timestamp, flags)) < 0 || index == st->nb_index_entries - 1) { matroska_clear_queue(matroska); if (matroska_parse_cluster(matroska) < 0) @@ -3573,7 +3777,6 @@ static int matroska_read_seek(AVFormatContext *s, int stream_index, if (index < 0 || (matroska->cues_parsing_deferred < 0 && index == st->nb_index_entries - 1)) goto err; - index_min = index; tracks = matroska->tracks.elem; for (i = 0; i < matroska->tracks.nb_elem; i++) { tracks[i].audio.pkt_cnt = 0; @@ -3582,8 +3785,8 @@ static int matroska_read_seek(AVFormatContext *s, int stream_index, tracks[i].end_timecode = 0; } - avio_seek(s->pb, st->index_entries[index_min].pos, SEEK_SET); - matroska->current_id = 0; + /* We seek to a level 1 element, so set the appropriate status. */ + matroska_reset_status(matroska, 0, st->index_entries[index].pos); if (flags & AVSEEK_FLAG_ANY) { st->skip_to_keyframe = 0; matroska->skip_to_timecode = timestamp; @@ -3593,18 +3796,17 @@ static int matroska_read_seek(AVFormatContext *s, int stream_index, } matroska->skip_to_keyframe = 1; matroska->done = 0; - matroska->num_levels = 0; ff_update_cur_dts(s, st, st->index_entries[index].timestamp); return 0; err: // slightly hackish but allows proper fallback to // the generic seeking code. + matroska_reset_status(matroska, 0, -1); + matroska->resync_pos = -1; matroska_clear_queue(matroska); - matroska->current_id = 0; st->skip_to_keyframe = matroska->skip_to_keyframe = 0; matroska->done = 0; - matroska->num_levels = 0; return -1; } @@ -3619,7 +3821,6 @@ static int matroska_read_close(AVFormatContext *s) for (n = 0; n < matroska->tracks.nb_elem; n++) if (tracks[n].type == MATROSKA_TRACK_TYPE_AUDIO) av_freep(&tracks[n].audio.buf); - ebml_free(matroska_cluster, &matroska->current_cluster); ebml_free(matroska_segment, matroska); return 0; @@ -3668,6 +3869,7 @@ static CueDesc get_cue_desc(AVFormatContext *s, int64_t ts, int64_t cues_start) static int webm_clusters_start_with_keyframe(AVFormatContext *s) { MatroskaDemuxContext *matroska = s->priv_data; + uint32_t id = matroska->current_id; int64_t cluster_pos, before_pos; int index, rv = 1; if (s->streams[0]->nb_index_entries <= 0) return 0; @@ -3677,30 +3879,36 @@ static int webm_clusters_start_with_keyframe(AVFormatContext *s) cluster_pos = s->streams[0]->index_entries[index].pos; before_pos = avio_tell(s->pb); while (1) { - int64_t cluster_id = 0, cluster_length = 0; + uint64_t cluster_id, cluster_length; + int read; AVPacket *pkt; avio_seek(s->pb, cluster_pos, SEEK_SET); // read cluster id and length - ebml_read_num(matroska, matroska->ctx->pb, 4, &cluster_id); - ebml_read_length(matroska, matroska->ctx->pb, &cluster_length); - if (cluster_id != 0xF43B675) { // done with all clusters + read = ebml_read_num(matroska, matroska->ctx->pb, 4, &cluster_id, 1); + if (read < 0 || cluster_id != 0xF43B675) // done with all clusters break; - } - avio_seek(s->pb, cluster_pos, SEEK_SET); - matroska->current_id = 0; + read = ebml_read_length(matroska, matroska->ctx->pb, &cluster_length); + if (read < 0) + break; + + matroska_reset_status(matroska, 0, cluster_pos); matroska_clear_queue(matroska); if (matroska_parse_cluster(matroska) < 0 || !matroska->queue) { break; } pkt = &matroska->queue->pkt; - cluster_pos += cluster_length + 12; // 12 is the offset of the cluster id and length. + // 4 + read is the length of the cluster id and the cluster length field. + cluster_pos += 4 + read + cluster_length; if (!(pkt->flags & AV_PKT_FLAG_KEY)) { rv = 0; break; } } - avio_seek(s->pb, before_pos, SEEK_SET); + + /* Restore the status after matroska_read_header: */ + matroska_reset_status(matroska, id, before_pos); + return rv; } @@ -3893,12 +4101,17 @@ static int webm_dash_manifest_cues(AVFormatContext *s, int64_t init_range) cues_start = seekhead[i].pos + matroska->segment_start; if (avio_seek(matroska->ctx->pb, cues_start, SEEK_SET) == cues_start) { // cues_end is computed as cues_start + cues_length + length of the - // Cues element ID + EBML length of the Cues element. cues_end is - // inclusive and the above sum is reduced by 1. - uint64_t cues_length = 0, cues_id = 0, bytes_read = 0; - bytes_read += ebml_read_num(matroska, matroska->ctx->pb, 4, &cues_id); - bytes_read += ebml_read_length(matroska, matroska->ctx->pb, &cues_length); - cues_end = cues_start + cues_length + bytes_read - 1; + // Cues element ID (i.e. 4) + EBML length of the Cues element. + // cues_end is inclusive and the above sum is reduced by 1. + uint64_t cues_length, cues_id; + int bytes_read; + bytes_read = ebml_read_num (matroska, matroska->ctx->pb, 4, &cues_id, 1); + if (bytes_read < 0 || cues_id != (MATROSKA_ID_CUES & 0xfffffff)) + return bytes_read < 0 ? bytes_read : AVERROR_INVALIDDATA; + bytes_read = ebml_read_length(matroska, matroska->ctx->pb, &cues_length); + if (bytes_read < 0) + return bytes_read; + cues_end = cues_start + 4 + bytes_read + cues_length - 1; } avio_seek(matroska->ctx->pb, before_pos, SEEK_SET); if (cues_start == -1 || cues_end == -1) return -1; @@ -3912,7 +4125,7 @@ static int webm_dash_manifest_cues(AVFormatContext *s, int64_t init_range) // cues end av_dict_set_int(&s->streams[0]->metadata, CUES_END, cues_end, 0); - // if the file has cues at the start, fix up the init range so tht + // if the file has cues at the start, fix up the init range so that // it does not include it if (cues_start <= init_range) av_dict_set_int(&s->streams[0]->metadata, INITIALIZATION_RANGE, cues_start - 1, 0); @@ -3927,22 +4140,19 @@ static int webm_dash_manifest_cues(AVFormatContext *s, int64_t init_range) // store cue point timestamps as a comma separated list for checking subsegment alignment in // the muxer. assumes that each timestamp cannot be more than 20 characters long. - buf = av_malloc_array(s->streams[0]->nb_index_entries, 20 * sizeof(char)); + buf = av_malloc_array(s->streams[0]->nb_index_entries, 20); if (!buf) return -1; strcpy(buf, ""); for (i = 0; i < s->streams[0]->nb_index_entries; i++) { - int ret = snprintf(buf + end, 20 * sizeof(char), - "%" PRId64, s->streams[0]->index_entries[i].timestamp); + int ret = snprintf(buf + end, 20, + "%" PRId64"%s", s->streams[0]->index_entries[i].timestamp, + i != s->streams[0]->nb_index_entries - 1 ? "," : ""); if (ret <= 0 || (ret == 20 && i == s->streams[0]->nb_index_entries - 1)) { av_log(s, AV_LOG_ERROR, "timestamp too long.\n"); av_free(buf); return AVERROR_INVALIDDATA; } end += ret; - if (i != s->streams[0]->nb_index_entries - 1) { - strncat(buf, ",", sizeof(char)); - end++; - } } av_dict_set(&s->streams[0]->metadata, CUE_TIMESTAMPS, buf, 0); av_free(buf); diff --git a/libavformat/matroskaenc.c b/libavformat/matroskaenc.c index 5950b4de4..cef504fa0 100644 --- a/libavformat/matroskaenc.c +++ b/libavformat/matroskaenc.c @@ -21,6 +21,7 @@ #include +#include "av1.h" #include "avc.h" #include "hevc.h" #include "avformat.h" @@ -57,12 +58,12 @@ #include "libavcodec/internal.h" typedef struct ebml_master { - int64_t pos; ///< absolute offset in the file where the master's elements start + int64_t pos; ///< absolute offset in the containing AVIOContext where the master's elements start int sizebytes; ///< how many bytes were reserved for the size } ebml_master; typedef struct mkv_seekhead_entry { - unsigned int elementid; + uint32_t elementid; uint64_t segmentpos; } mkv_seekhead_entry; @@ -117,23 +118,22 @@ typedef struct mkv_attachments { #define MAX_TRACKS 126 typedef struct MatroskaMuxContext { - const AVClass *class; + const AVClass *class; int mode; - AVIOContext *dyn_bc; AVIOContext *tags_bc; - ebml_master tags; + int64_t tags_pos; AVIOContext *info_bc; - ebml_master info; + int64_t info_pos; AVIOContext *tracks_bc; - ebml_master tracks_master; + int64_t tracks_pos; ebml_master segment; int64_t segment_offset; - ebml_master cluster; + AVIOContext *cluster_bc; int64_t cluster_pos; ///< file offset of the current cluster int64_t cluster_pts; int64_t duration_offset; int64_t duration; - mkv_seekhead *main_seekhead; + mkv_seekhead *seekhead; mkv_cues *cues; mkv_track *tracks; mkv_attachments *attachments; @@ -157,33 +157,36 @@ typedef struct MatroskaMuxContext { int64_t last_track_timestamp[MAX_TRACKS]; - int64_t* stream_durations; - int64_t* stream_duration_offsets; + int64_t *stream_durations; + int64_t *stream_duration_offsets; int allow_raw_vfw; } MatroskaMuxContext; +/** 2 bytes * 7 for EBML IDs, 7 1-byte EBML lengths, 6 1-byte uint, + * 8 byte for "matroska" doctype string */ +#define MAX_EBML_HEADER_SIZE 35 /** 2 bytes * 3 for EBML IDs, 3 1-byte EBML lengths, 8 bytes for 64 bit * offset, 4 bytes for target EBML ID */ #define MAX_SEEKENTRY_SIZE 21 -/** per-cuepoint-track - 5 1-byte EBML IDs, 5 1-byte EBML sizes, 4 - * 8-byte uint max */ -#define MAX_CUETRACKPOS_SIZE 42 +/** per-cuepoint-track - 5 1-byte EBML IDs, 5 1-byte EBML sizes, 3 8-byte uint max + * and one 1-byte uint for the track number (this assumes MAX_TRACKS to be <= 255) */ +#define MAX_CUETRACKPOS_SIZE 35 -/** per-cuepoint - 2 1-byte EBML IDs, 2 1-byte EBML sizes, 8-byte uint max */ -#define MAX_CUEPOINT_SIZE(num_tracks) 12 + MAX_CUETRACKPOS_SIZE * num_tracks +/** per-cuepoint - 1 1-byte EBML ID, 1 1-byte EBML size, 8-byte uint max */ +#define MAX_CUEPOINT_CONTENT_SIZE(num_tracks) 10 + MAX_CUETRACKPOS_SIZE * num_tracks /** Seek preroll value for opus */ #define OPUS_SEEK_PREROLL 80000000 -static int ebml_id_size(unsigned int id) +static int ebml_id_size(uint32_t id) { return (av_log2(id + 1) - 1) / 7 + 1; } -static void put_ebml_id(AVIOContext *pb, unsigned int id) +static void put_ebml_id(AVIOContext *pb, uint32_t id) { int i = ebml_id_size(id); while (i--) @@ -238,7 +241,7 @@ static void put_ebml_num(AVIOContext *pb, uint64_t num, int bytes) avio_w8(pb, (uint8_t)(num >> i * 8)); } -static void put_ebml_uint(AVIOContext *pb, unsigned int elementid, uint64_t val) +static void put_ebml_uint(AVIOContext *pb, uint32_t elementid, uint64_t val) { int i, bytes = 1; uint64_t tmp = val; @@ -251,7 +254,7 @@ static void put_ebml_uint(AVIOContext *pb, unsigned int elementid, uint64_t val) avio_w8(pb, (uint8_t)(val >> i * 8)); } -static void put_ebml_sint(AVIOContext *pb, unsigned int elementid, int64_t val) +static void put_ebml_sint(AVIOContext *pb, uint32_t elementid, int64_t val) { int i, bytes = 1; uint64_t tmp = 2*(val < 0 ? val^-1 : val); @@ -264,14 +267,14 @@ static void put_ebml_sint(AVIOContext *pb, unsigned int elementid, int64_t val) avio_w8(pb, (uint8_t)(val >> i * 8)); } -static void put_ebml_float(AVIOContext *pb, unsigned int elementid, double val) +static void put_ebml_float(AVIOContext *pb, uint32_t elementid, double val) { put_ebml_id(pb, elementid); put_ebml_num(pb, 8, 0); avio_wb64(pb, av_double2int(val)); } -static void put_ebml_binary(AVIOContext *pb, unsigned int elementid, +static void put_ebml_binary(AVIOContext *pb, uint32_t elementid, const void *buf, int size) { put_ebml_id(pb, elementid); @@ -279,7 +282,7 @@ static void put_ebml_binary(AVIOContext *pb, unsigned int elementid, avio_write(pb, buf, size); } -static void put_ebml_string(AVIOContext *pb, unsigned int elementid, +static void put_ebml_string(AVIOContext *pb, uint32_t elementid, const char *str) { put_ebml_binary(pb, elementid, str, strlen(str)); @@ -308,13 +311,14 @@ static void put_ebml_void(AVIOContext *pb, uint64_t size) ffio_fill(pb, 0, currentpos + size - avio_tell(pb)); } -static ebml_master start_ebml_master(AVIOContext *pb, unsigned int elementid, +static ebml_master start_ebml_master(AVIOContext *pb, uint32_t elementid, uint64_t expectedsize) { int bytes = expectedsize ? ebml_num_size(expectedsize) : 8; + put_ebml_id(pb, elementid); put_ebml_size_unknown(pb, bytes); - return (ebml_master) {avio_tell(pb), bytes }; + return (ebml_master) { avio_tell(pb), bytes }; } static void end_ebml_master(AVIOContext *pb, ebml_master master) @@ -328,61 +332,51 @@ static void end_ebml_master(AVIOContext *pb, ebml_master master) } static int start_ebml_master_crc32(AVIOContext *pb, AVIOContext **dyn_cp, MatroskaMuxContext *mkv, - ebml_master *master, unsigned int elementid, uint64_t expectedsize) + uint32_t elementid) { int ret; if ((ret = avio_open_dyn_buf(dyn_cp)) < 0) return ret; - if (pb->seekable & AVIO_SEEKABLE_NORMAL) { - *master = start_ebml_master(pb, elementid, expectedsize); - if (mkv->write_crc && mkv->mode != MODE_WEBM) - put_ebml_void(*dyn_cp, 6); /* Reserve space for CRC32 so position/size calculations using avio_tell() take it into account */ - } else - *master = start_ebml_master(*dyn_cp, elementid, expectedsize); + put_ebml_id(pb, elementid); + if (mkv->write_crc) + put_ebml_void(*dyn_cp, 6); /* Reserve space for CRC32 so position/size calculations using avio_tell() take it into account */ return 0; } -static void end_ebml_master_crc32(AVIOContext *pb, AVIOContext **dyn_cp, MatroskaMuxContext *mkv, - ebml_master master) +static void end_ebml_master_crc32(AVIOContext *pb, AVIOContext **dyn_cp, MatroskaMuxContext *mkv) { uint8_t *buf, crc[4]; int size, skip = 0; - if (pb->seekable & AVIO_SEEKABLE_NORMAL) { - size = avio_close_dyn_buf(*dyn_cp, &buf); - if (mkv->write_crc && mkv->mode != MODE_WEBM) { - skip = 6; /* Skip reserved 6-byte long void element from the dynamic buffer. */ - AV_WL32(crc, av_crc(av_crc_get_table(AV_CRC_32_IEEE_LE), UINT32_MAX, buf + skip, size - skip) ^ UINT32_MAX); - put_ebml_binary(pb, EBML_ID_CRC32, crc, sizeof(crc)); - } - avio_write(pb, buf + skip, size - skip); - end_ebml_master(pb, master); - } else { - end_ebml_master(*dyn_cp, master); - size = avio_close_dyn_buf(*dyn_cp, &buf); - avio_write(pb, buf, size); + size = avio_close_dyn_buf(*dyn_cp, &buf); + put_ebml_num(pb, size, 0); + if (mkv->write_crc) { + skip = 6; /* Skip reserved 6-byte long void element from the dynamic buffer. */ + AV_WL32(crc, av_crc(av_crc_get_table(AV_CRC_32_IEEE_LE), UINT32_MAX, buf + skip, size - skip) ^ UINT32_MAX); + put_ebml_binary(pb, EBML_ID_CRC32, crc, sizeof(crc)); } + avio_write(pb, buf + skip, size - skip); + av_free(buf); *dyn_cp = NULL; } /** -* Complete ebml master whithout destroying the buffer, allowing for later updates +* Complete ebml master without destroying the buffer, allowing for later updates */ static void end_ebml_master_crc32_preliminary(AVIOContext *pb, AVIOContext **dyn_cp, MatroskaMuxContext *mkv, - ebml_master master) + int64_t *pos) { - if (pb->seekable & AVIO_SEEKABLE_NORMAL) { + uint8_t *buf; + int size = avio_get_dyn_buf(*dyn_cp, &buf); - uint8_t *buf; - int size = avio_get_dyn_buf(*dyn_cp, &buf); + *pos = avio_tell(pb); - avio_write(pb, buf, size); - end_ebml_master(pb, master); - } + put_ebml_num(pb, size, 0); + avio_write(pb, buf, size); } static void put_xiph_size(AVIOContext *pb, int size) @@ -396,8 +390,8 @@ static void put_xiph_size(AVIOContext *pb, int size) */ static void mkv_free(MatroskaMuxContext *mkv) { uint8_t* buf; - if (mkv->dyn_bc) { - avio_close_dyn_buf(mkv->dyn_bc, &buf); + if (mkv->cluster_bc) { + avio_close_dyn_buf(mkv->cluster_bc, &buf); av_free(buf); } if (mkv->info_bc) { @@ -412,9 +406,9 @@ static void mkv_free(MatroskaMuxContext *mkv) { avio_close_dyn_buf(mkv->tags_bc, &buf); av_free(buf); } - if (mkv->main_seekhead) { - av_freep(&mkv->main_seekhead->entries); - av_freep(&mkv->main_seekhead); + if (mkv->seekhead) { + av_freep(&mkv->seekhead->entries); + av_freep(&mkv->seekhead); } if (mkv->cues) { av_freep(&mkv->cues->entries); @@ -461,7 +455,7 @@ static mkv_seekhead *mkv_start_seekhead(AVIOContext *pb, int64_t segment_offset, return new_seekhead; } -static int mkv_add_seekhead_entry(mkv_seekhead *seekhead, unsigned int elementid, uint64_t filepos) +static int mkv_add_seekhead_entry(mkv_seekhead *seekhead, uint32_t elementid, uint64_t filepos) { mkv_seekhead_entry *entries = seekhead->entries; @@ -492,8 +486,8 @@ static int mkv_add_seekhead_entry(mkv_seekhead *seekhead, unsigned int elementid static int64_t mkv_write_seekhead(AVIOContext *pb, MatroskaMuxContext *mkv) { AVIOContext *dyn_cp; - mkv_seekhead *seekhead = mkv->main_seekhead; - ebml_master metaseek, seekentry; + mkv_seekhead *seekhead = mkv->seekhead; + ebml_master seekentry; int64_t currentpos; int i; @@ -506,8 +500,7 @@ static int64_t mkv_write_seekhead(AVIOContext *pb, MatroskaMuxContext *mkv) } } - if (start_ebml_master_crc32(pb, &dyn_cp, mkv, &metaseek, MATROSKA_ID_SEEKHEAD, - seekhead->reserved_size) < 0) { + if (start_ebml_master_crc32(pb, &dyn_cp, mkv, MATROSKA_ID_SEEKHEAD) < 0) { currentpos = -1; goto fail; } @@ -524,7 +517,7 @@ static int64_t mkv_write_seekhead(AVIOContext *pb, MatroskaMuxContext *mkv) put_ebml_uint(dyn_cp, MATROSKA_ID_SEEKPOSITION, entry->segmentpos); end_ebml_master(dyn_cp, seekentry); } - end_ebml_master_crc32(pb, &dyn_cp, mkv, metaseek); + end_ebml_master_crc32(pb, &dyn_cp, mkv); if (seekhead->reserved_size > 0) { uint64_t remaining = seekhead->filepos + seekhead->reserved_size - avio_tell(pb); @@ -534,8 +527,8 @@ static int64_t mkv_write_seekhead(AVIOContext *pb, MatroskaMuxContext *mkv) currentpos = seekhead->filepos; } fail: - av_freep(&mkv->main_seekhead->entries); - av_freep(&mkv->main_seekhead); + av_freep(&mkv->seekhead->entries); + av_freep(&mkv->seekhead); return currentpos; } @@ -577,12 +570,11 @@ static int64_t mkv_write_cues(AVFormatContext *s, mkv_cues *cues, mkv_track *tra { MatroskaMuxContext *mkv = s->priv_data; AVIOContext *dyn_cp, *pb = s->pb; - ebml_master cues_element; int64_t currentpos; int i, j, ret; currentpos = avio_tell(pb); - ret = start_ebml_master_crc32(pb, &dyn_cp, mkv, &cues_element, MATROSKA_ID_CUES, 0); + ret = start_ebml_master_crc32(pb, &dyn_cp, mkv, MATROSKA_ID_CUES); if (ret < 0) return ret; @@ -604,7 +596,7 @@ static int64_t mkv_write_cues(AVFormatContext *s, mkv_cues *cues, mkv_track *tra ctp_nb ++; } - cuepoint = start_ebml_master(dyn_cp, MATROSKA_ID_POINTENTRY, MAX_CUEPOINT_SIZE(ctp_nb)); + cuepoint = start_ebml_master(dyn_cp, MATROSKA_ID_POINTENTRY, MAX_CUEPOINT_CONTENT_SIZE(ctp_nb)); put_ebml_uint(dyn_cp, MATROSKA_ID_CUETIME, pts); // put all the entries from different tracks that have the exact same @@ -628,7 +620,7 @@ static int64_t mkv_write_cues(AVFormatContext *s, mkv_cues *cues, mkv_track *tra i += j - 1; end_ebml_master(dyn_cp, cuepoint); } - end_ebml_master_crc32(pb, &dyn_cp, mkv, cues_element); + end_ebml_master_crc32(pb, &dyn_cp, mkv); return currentpos; } @@ -692,9 +684,11 @@ static int put_flac_codecpriv(AVFormatContext *s, snprintf(buf, sizeof(buf), "0x%"PRIx64, par->channel_layout); av_dict_set(&dict, "WAVEFORMATEXTENSIBLE_CHANNEL_MASK", buf, 0); - len = ff_vorbiscomment_length(dict, vendor); - if (len >= ((1<<24) - 4)) + len = ff_vorbiscomment_length(dict, vendor, NULL, 0); + if (len >= ((1<<24) - 4)) { + av_dict_free(&dict); return AVERROR(EINVAL); + } data = av_malloc(len + 4); if (!data) { @@ -706,7 +700,7 @@ static int put_flac_codecpriv(AVFormatContext *s, AV_WB24(data + 1, len); p = data + 4; - ff_vorbiscomment_write(&p, &dict, vendor); + ff_vorbiscomment_write(&p, &dict, vendor, NULL, 0); avio_write(pb, data, len + 4); @@ -769,6 +763,13 @@ static int mkv_write_native_codecprivate(AVFormatContext *s, AVIOContext *pb, ff_isom_write_hvcc(dyn_cp, par->extradata, par->extradata_size, 0); return 0; + case AV_CODEC_ID_AV1: + if (par->extradata_size) + return ff_isom_write_av1c(dyn_cp, par->extradata, + par->extradata_size); + else + put_ebml_void(pb, 4 + 3); + break; case AV_CODEC_ID_ALAC: if (par->extradata_size < 36) { av_log(s, AV_LOG_ERROR, @@ -1230,21 +1231,38 @@ static int mkv_write_track(AVFormatContext *s, MatroskaMuxContext *mkv, if (st->disposition & AV_DISPOSITION_FORCED) put_ebml_uint(pb, MATROSKA_ID_TRACKFLAGFORCED, 1); - if (mkv->mode == MODE_WEBM && par->codec_id == AV_CODEC_ID_WEBVTT) { + if (mkv->mode == MODE_WEBM) { const char *codec_id; - if (st->disposition & AV_DISPOSITION_CAPTIONS) { - codec_id = "D_WEBVTT/CAPTIONS"; - native_id = MATROSKA_TRACK_TYPE_SUBTITLE; - } else if (st->disposition & AV_DISPOSITION_DESCRIPTIONS) { - codec_id = "D_WEBVTT/DESCRIPTIONS"; - native_id = MATROSKA_TRACK_TYPE_METADATA; - } else if (st->disposition & AV_DISPOSITION_METADATA) { - codec_id = "D_WEBVTT/METADATA"; - native_id = MATROSKA_TRACK_TYPE_METADATA; - } else { - codec_id = "D_WEBVTT/SUBTITLES"; - native_id = MATROSKA_TRACK_TYPE_SUBTITLE; + if (par->codec_type != AVMEDIA_TYPE_SUBTITLE) { + for (j = 0; ff_webm_codec_tags[j].id != AV_CODEC_ID_NONE; j++) { + if (ff_webm_codec_tags[j].id == par->codec_id) { + codec_id = ff_webm_codec_tags[j].str; + native_id = 1; + break; + } + } + } else if (par->codec_id == AV_CODEC_ID_WEBVTT) { + if (st->disposition & AV_DISPOSITION_CAPTIONS) { + codec_id = "D_WEBVTT/CAPTIONS"; + native_id = MATROSKA_TRACK_TYPE_SUBTITLE; + } else if (st->disposition & AV_DISPOSITION_DESCRIPTIONS) { + codec_id = "D_WEBVTT/DESCRIPTIONS"; + native_id = MATROSKA_TRACK_TYPE_METADATA; + } else if (st->disposition & AV_DISPOSITION_METADATA) { + codec_id = "D_WEBVTT/METADATA"; + native_id = MATROSKA_TRACK_TYPE_METADATA; + } else { + codec_id = "D_WEBVTT/SUBTITLES"; + native_id = MATROSKA_TRACK_TYPE_SUBTITLE; + } } + + if (!native_id) { + av_log(s, AV_LOG_ERROR, + "Only VP8 or VP9 or AV1 video and Vorbis or Opus audio and WebVTT subtitles are supported for WebM.\n"); + return AVERROR(EINVAL); + } + put_ebml_string(pb, MATROSKA_ID_CODECID, codec_id); } else { // look for a codec ID string specific to mkv to use, @@ -1286,16 +1304,6 @@ static int mkv_write_track(AVFormatContext *s, MatroskaMuxContext *mkv, put_ebml_uint(pb, MATROSKA_ID_SEEKPREROLL, OPUS_SEEK_PREROLL); } - if (mkv->mode == MODE_WEBM && !(par->codec_id == AV_CODEC_ID_VP8 || - par->codec_id == AV_CODEC_ID_VP9 || - par->codec_id == AV_CODEC_ID_OPUS || - par->codec_id == AV_CODEC_ID_VORBIS || - par->codec_id == AV_CODEC_ID_WEBVTT)) { - av_log(s, AV_LOG_ERROR, - "Only VP8 or VP9 video and Vorbis or Opus audio and WebVTT subtitles are supported for WebM.\n"); - return AVERROR(EINVAL); - } - switch (par->codec_type) { case AVMEDIA_TYPE_VIDEO: mkv->have_video = 1; @@ -1304,8 +1312,6 @@ static int mkv_write_track(AVFormatContext *s, MatroskaMuxContext *mkv, if( st->avg_frame_rate.num > 0 && st->avg_frame_rate.den > 0 && av_cmp_q(av_inv_q(st->avg_frame_rate), st->time_base) > 0) put_ebml_uint(pb, MATROSKA_ID_TRACKDEFAULTDURATION, 1000000000LL * st->avg_frame_rate.den / st->avg_frame_rate.num); - else - put_ebml_uint(pb, MATROSKA_ID_TRACKDEFAULTDURATION, 1000000000LL * st->time_base.num / st->time_base.den); if (!native_id && ff_codec_get_tag(ff_codec_movvideo_tags, par->codec_id) && @@ -1440,11 +1446,11 @@ static int mkv_write_tracks(AVFormatContext *s) AVIOContext *pb = s->pb; int i, ret, default_stream_exists = 0; - ret = mkv_add_seekhead_entry(mkv->main_seekhead, MATROSKA_ID_TRACKS, avio_tell(pb)); + ret = mkv_add_seekhead_entry(mkv->seekhead, MATROSKA_ID_TRACKS, avio_tell(pb)); if (ret < 0) return ret; - ret = start_ebml_master_crc32(pb, &mkv->tracks_bc, mkv, &mkv->tracks_master, MATROSKA_ID_TRACKS, 0); + ret = start_ebml_master_crc32(pb, &mkv->tracks_bc, mkv, MATROSKA_ID_TRACKS); if (ret < 0) return ret; @@ -1459,9 +1465,9 @@ static int mkv_write_tracks(AVFormatContext *s) } if ((pb->seekable & AVIO_SEEKABLE_NORMAL) && !mkv->is_live) - end_ebml_master_crc32_preliminary(pb, &mkv->tracks_bc, mkv, mkv->tracks_master); + end_ebml_master_crc32_preliminary(pb, &mkv->tracks_bc, mkv, &mkv->tracks_pos); else - end_ebml_master_crc32(pb, &mkv->tracks_bc, mkv, mkv->tracks_master); + end_ebml_master_crc32(pb, &mkv->tracks_bc, mkv); return 0; } @@ -1470,17 +1476,17 @@ static int mkv_write_chapters(AVFormatContext *s) { MatroskaMuxContext *mkv = s->priv_data; AVIOContext *dyn_cp, *pb = s->pb; - ebml_master chapters, editionentry; + ebml_master editionentry; AVRational scale = {1, 1E9}; int i, ret; if (!s->nb_chapters || mkv->wrote_chapters) return 0; - ret = mkv_add_seekhead_entry(mkv->main_seekhead, MATROSKA_ID_CHAPTERS, avio_tell(pb)); + ret = mkv_add_seekhead_entry(mkv->seekhead, MATROSKA_ID_CHAPTERS, avio_tell(pb)); if (ret < 0) return ret; - ret = start_ebml_master_crc32(pb, &dyn_cp, mkv, &chapters, MATROSKA_ID_CHAPTERS, 0); + ret = start_ebml_master_crc32(pb, &dyn_cp, mkv, MATROSKA_ID_CHAPTERS); if (ret < 0) return ret; editionentry = start_ebml_master(dyn_cp, MATROSKA_ID_EDITIONENTRY, 0); @@ -1518,7 +1524,7 @@ static int mkv_write_chapters(AVFormatContext *s) end_ebml_master(dyn_cp, chapteratom); } end_ebml_master(dyn_cp, editionentry); - end_ebml_master_crc32(pb, &dyn_cp, mkv, chapters); + end_ebml_master_crc32(pb, &dyn_cp, mkv); mkv->wrote_chapters = 1; return 0; @@ -1558,24 +1564,23 @@ static int mkv_write_simpletag(AVIOContext *pb, AVDictionaryEntry *t) return 0; } -static int mkv_write_tag_targets(AVFormatContext *s, - unsigned int elementid, unsigned int uid, - ebml_master *tags, ebml_master* tag) +static int mkv_write_tag_targets(AVFormatContext *s, uint32_t elementid, + unsigned int uid, ebml_master *tag) { AVIOContext *pb; MatroskaMuxContext *mkv = s->priv_data; ebml_master targets; int ret; - if (!tags->pos) { - ret = mkv_add_seekhead_entry(mkv->main_seekhead, MATROSKA_ID_TAGS, avio_tell(s->pb)); + if (!mkv->tags_bc) { + ret = mkv_add_seekhead_entry(mkv->seekhead, MATROSKA_ID_TAGS, avio_tell(s->pb)); if (ret < 0) return ret; - start_ebml_master_crc32(s->pb, &mkv->tags_bc, mkv, tags, MATROSKA_ID_TAGS, 0); + start_ebml_master_crc32(s->pb, &mkv->tags_bc, mkv, MATROSKA_ID_TAGS); } pb = mkv->tags_bc; - *tag = start_ebml_master(pb, MATROSKA_ID_TAG, 0); + *tag = start_ebml_master(pb, MATROSKA_ID_TAG, 0); targets = start_ebml_master(pb, MATROSKA_ID_TAGTARGETS, 0); if (elementid) put_ebml_uint(pb, elementid, uid); @@ -1583,7 +1588,7 @@ static int mkv_write_tag_targets(AVFormatContext *s, return 0; } -static int mkv_check_tag_name(const char *name, unsigned int elementid) +static int mkv_check_tag_name(const char *name, uint32_t elementid) { return av_strcasecmp(name, "title") && av_strcasecmp(name, "stereo_mode") && @@ -1597,15 +1602,15 @@ static int mkv_check_tag_name(const char *name, unsigned int elementid) av_strcasecmp(name, "mimetype"))); } -static int mkv_write_tag(AVFormatContext *s, AVDictionary *m, unsigned int elementid, - unsigned int uid, ebml_master *tags) +static int mkv_write_tag(AVFormatContext *s, AVDictionary *m, uint32_t elementid, + unsigned int uid) { MatroskaMuxContext *mkv = s->priv_data; ebml_master tag; int ret; AVDictionaryEntry *t = NULL; - ret = mkv_write_tag_targets(s, elementid, uid, tags, &tag); + ret = mkv_write_tag_targets(s, elementid, uid, &tag); if (ret < 0) return ret; @@ -1621,7 +1626,7 @@ static int mkv_write_tag(AVFormatContext *s, AVDictionary *m, unsigned int eleme return 0; } -static int mkv_check_tag(AVDictionary *m, unsigned int elementid) +static int mkv_check_tag(AVDictionary *m, uint32_t elementid) { AVDictionaryEntry *t = NULL; @@ -1640,7 +1645,7 @@ static int mkv_write_tags(AVFormatContext *s) ff_metadata_conv_ctx(s, ff_mkv_metadata_conv, NULL); if (mkv_check_tag(s->metadata, 0)) { - ret = mkv_write_tag(s, s->metadata, 0, 0, &mkv->tags); + ret = mkv_write_tag(s, s->metadata, 0, 0); if (ret < 0) return ret; } @@ -1653,7 +1658,7 @@ static int mkv_write_tags(AVFormatContext *s) if (!mkv_check_tag(st->metadata, MATROSKA_ID_TAGTARGETS_TRACKUID)) continue; - ret = mkv_write_tag(s, st->metadata, MATROSKA_ID_TAGTARGETS_TRACKUID, i + 1, &mkv->tags); + ret = mkv_write_tag(s, st->metadata, MATROSKA_ID_TAGTARGETS_TRACKUID, i + 1); if (ret < 0) return ret; } @@ -1667,7 +1672,7 @@ static int mkv_write_tags(AVFormatContext *s) if (st->codecpar->codec_type == AVMEDIA_TYPE_ATTACHMENT) continue; - mkv_write_tag_targets(s, MATROSKA_ID_TAGTARGETS_TRACKUID, i + 1, &mkv->tags, &tag_target); + mkv_write_tag_targets(s, MATROSKA_ID_TAGTARGETS_TRACKUID, i + 1, &tag_target); pb = mkv->tags_bc; tag = start_ebml_master(pb, MATROSKA_ID_SIMPLETAG, 0); @@ -1689,7 +1694,7 @@ static int mkv_write_tags(AVFormatContext *s) if (!mkv_check_tag(ch->metadata, MATROSKA_ID_TAGTARGETS_CHAPTERUID)) continue; - ret = mkv_write_tag(s, ch->metadata, MATROSKA_ID_TAGTARGETS_CHAPTERUID, ch->id + mkv->chapter_id_offset, &mkv->tags); + ret = mkv_write_tag(s, ch->metadata, MATROSKA_ID_TAGTARGETS_CHAPTERUID, ch->id + mkv->chapter_id_offset); if (ret < 0) return ret; } @@ -1703,17 +1708,17 @@ static int mkv_write_tags(AVFormatContext *s) if (!mkv_check_tag(st->metadata, MATROSKA_ID_TAGTARGETS_ATTACHUID)) continue; - ret = mkv_write_tag(s, st->metadata, MATROSKA_ID_TAGTARGETS_ATTACHUID, attachment->fileuid, &mkv->tags); + ret = mkv_write_tag(s, st->metadata, MATROSKA_ID_TAGTARGETS_ATTACHUID, attachment->fileuid); if (ret < 0) return ret; } } - if (mkv->tags.pos) { + if (mkv->tags_bc) { if ((s->pb->seekable & AVIO_SEEKABLE_NORMAL) && !mkv->is_live) - end_ebml_master_crc32_preliminary(s->pb, &mkv->tags_bc, mkv, mkv->tags); + end_ebml_master_crc32_preliminary(s->pb, &mkv->tags_bc, mkv, &mkv->tags_pos); else - end_ebml_master_crc32(s->pb, &mkv->tags_bc, mkv, mkv->tags); + end_ebml_master_crc32(s->pb, &mkv->tags_bc, mkv); } return 0; } @@ -1722,7 +1727,6 @@ static int mkv_write_attachments(AVFormatContext *s) { MatroskaMuxContext *mkv = s->priv_data; AVIOContext *dyn_cp, *pb = s->pb; - ebml_master attachments; AVLFG c; int i, ret; @@ -1735,10 +1739,10 @@ static int mkv_write_attachments(AVFormatContext *s) av_lfg_init(&c, av_get_random_seed()); - ret = mkv_add_seekhead_entry(mkv->main_seekhead, MATROSKA_ID_ATTACHMENTS, avio_tell(pb)); + ret = mkv_add_seekhead_entry(mkv->seekhead, MATROSKA_ID_ATTACHMENTS, avio_tell(pb)); if (ret < 0) return ret; - ret = start_ebml_master_crc32(pb, &dyn_cp, mkv, &attachments, MATROSKA_ID_ATTACHMENTS, 0); + ret = start_ebml_master_crc32(pb, &dyn_cp, mkv, MATROSKA_ID_ATTACHMENTS); if (ret < 0) return ret; for (i = 0; i < s->nb_streams; i++) { @@ -1811,7 +1815,7 @@ static int mkv_write_attachments(AVFormatContext *s) mkv->attachments->entries[mkv->attachments->num_entries].stream_idx = i; mkv->attachments->entries[mkv->attachments->num_entries++].fileuid = fileuid; } - end_ebml_master_crc32(pb, &dyn_cp, mkv, attachments); + end_ebml_master_crc32(pb, &dyn_cp, mkv); return 0; } @@ -1849,9 +1853,10 @@ static int mkv_write_header(AVFormatContext *s) int ret, i, version = 2; int64_t creation_time; - if (!strcmp(s->oformat->name, "webm")) - mkv->mode = MODE_WEBM; - else + if (!strcmp(s->oformat->name, "webm")) { + mkv->mode = MODE_WEBM; + mkv->write_crc = 0; + } else mkv->mode = MODE_MATROSKAv2; if (mkv->mode != MODE_WEBM || @@ -1871,34 +1876,32 @@ static int mkv_write_header(AVFormatContext *s) ret = AVERROR(ENOMEM); goto fail; } - ebml_header = start_ebml_master(pb, EBML_ID_HEADER, 0); - put_ebml_uint (pb, EBML_ID_EBMLVERSION , 1); - put_ebml_uint (pb, EBML_ID_EBMLREADVERSION , 1); - put_ebml_uint (pb, EBML_ID_EBMLMAXIDLENGTH , 4); - put_ebml_uint (pb, EBML_ID_EBMLMAXSIZELENGTH , 8); - put_ebml_string (pb, EBML_ID_DOCTYPE , s->oformat->name); - put_ebml_uint (pb, EBML_ID_DOCTYPEVERSION , version); - put_ebml_uint (pb, EBML_ID_DOCTYPEREADVERSION , 2); + ebml_header = start_ebml_master(pb, EBML_ID_HEADER, MAX_EBML_HEADER_SIZE); + put_ebml_uint (pb, EBML_ID_EBMLVERSION , 1); + put_ebml_uint (pb, EBML_ID_EBMLREADVERSION , 1); + put_ebml_uint (pb, EBML_ID_EBMLMAXIDLENGTH , 4); + put_ebml_uint (pb, EBML_ID_EBMLMAXSIZELENGTH , 8); + put_ebml_string(pb, EBML_ID_DOCTYPE , s->oformat->name); + put_ebml_uint (pb, EBML_ID_DOCTYPEVERSION , version); + put_ebml_uint (pb, EBML_ID_DOCTYPEREADVERSION, 2); end_ebml_master(pb, ebml_header); mkv->segment = start_ebml_master(pb, MATROSKA_ID_SEGMENT, 0); mkv->segment_offset = avio_tell(pb); - // we write 2 seek heads - one at the end of the file to point to each - // cluster, and one at the beginning to point to all other level one - // elements (including the seek head at the end of the file), which - // isn't more than 10 elements if we only write one of each other - // currently defined level 1 element - mkv->main_seekhead = mkv_start_seekhead(pb, mkv->segment_offset, 10); - if (!mkv->main_seekhead) { + // we write a seek head at the beginning to point to all other level + // one elements, which aren't more than 10 elements as we write only one + // of every other currently defined level 1 element + mkv->seekhead = mkv_start_seekhead(pb, mkv->segment_offset, 10); + if (!mkv->seekhead) { ret = AVERROR(ENOMEM); goto fail; } - ret = mkv_add_seekhead_entry(mkv->main_seekhead, MATROSKA_ID_INFO, avio_tell(pb)); + ret = mkv_add_seekhead_entry(mkv->seekhead, MATROSKA_ID_INFO, avio_tell(pb)); if (ret < 0) goto fail; - ret = start_ebml_master_crc32(pb, &mkv->info_bc, mkv, &mkv->info, MATROSKA_ID_INFO, 0); + ret = start_ebml_master_crc32(pb, &mkv->info_bc, mkv, MATROSKA_ID_INFO); if (ret < 0) return ret; pb = mkv->info_bc; @@ -1957,13 +1960,13 @@ static int mkv_write_header(AVFormatContext *s) } } if ((s->pb->seekable & AVIO_SEEKABLE_NORMAL) && !mkv->is_live) - end_ebml_master_crc32_preliminary(s->pb, &mkv->info_bc, mkv, mkv->info); + end_ebml_master_crc32_preliminary(s->pb, &mkv->info_bc, mkv, &mkv->info_pos); else - end_ebml_master_crc32(s->pb, &mkv->info_bc, mkv, mkv->info); + end_ebml_master_crc32(s->pb, &mkv->info_bc, mkv); pb = s->pb; // initialize stream_duration fields - mkv->stream_durations = av_mallocz(s->nb_streams * sizeof(int64_t)); + mkv->stream_durations = av_mallocz(s->nb_streams * sizeof(int64_t)); mkv->stream_duration_offsets = av_mallocz(s->nb_streams * sizeof(int64_t)); if (!mkv->stream_durations || !mkv->stream_duration_offsets) { ret = AVERROR(ENOMEM); @@ -1999,6 +2002,13 @@ static int mkv_write_header(AVFormatContext *s) ret = AVERROR(ENOMEM); goto fail; } + + if (s->metadata_header_padding > 0) { + if (s->metadata_header_padding == 1) + s->metadata_header_padding++; + put_ebml_void(pb, s->metadata_header_padding); + } + if ((pb->seekable & AVIO_SEEKABLE_NORMAL) && mkv->reserve_cues_space) { mkv->cues_pos = avio_tell(pb); if (mkv->reserve_cues_space == 1) @@ -2037,9 +2047,7 @@ static int mkv_blockgroup_size(int pkt_size) int size = pkt_size + 4; size += ebml_num_size(size); size += 2; // EBML ID for block and block duration - size += 8; // max size of block duration - size += ebml_num_size(size); - size += 1; // blockgroup EBML ID + size += 9; // max size of block duration incl. length field return size; } @@ -2097,7 +2105,7 @@ fail: } static void mkv_write_block(AVFormatContext *s, AVIOContext *pb, - unsigned int blockid, AVPacket *pkt, int keyframe) + uint32_t blockid, AVPacket *pkt, int keyframe) { MatroskaMuxContext *mkv = s->priv_data; AVCodecParameters *par = s->streams[pkt->stream_index]->codecpar; @@ -2111,10 +2119,14 @@ static void mkv_write_block(AVFormatContext *s, AVIOContext *pb, ts += mkv->tracks[pkt->stream_index].ts_offset; - av_log(s, AV_LOG_DEBUG, "Writing block at offset %" PRIu64 ", size %d, " - "pts %" PRId64 ", dts %" PRId64 ", duration %" PRId64 ", keyframe %d\n", - avio_tell(pb), pkt->size, pkt->pts, pkt->dts, pkt->duration, - keyframe != 0); + /* The following string is identical to the one in mkv_write_vtt_blocks + * so that only one copy needs to exist in binaries. */ + av_log(s, AV_LOG_DEBUG, + "Writing block of size %d with pts %" PRId64 ", dts %" PRId64 ", " + "duration %" PRId64 " at relative offset %" PRId64 " in cluster " + "at offset %" PRId64 ". TrackNumber %d, keyframe %d\n", + pkt->size, pkt->pts, pkt->dts, pkt->duration, avio_tell(pb), + mkv->cluster_pos, track_number, keyframe != 0); if (par->codec_id == AV_CODEC_ID_H264 && par->extradata_size > 0 && (AV_RB24(par->extradata) == 1 || AV_RB32(par->extradata) == 1)) ff_avc_parse_nal_units_buf(pkt->data, &data, &size); @@ -2122,6 +2134,8 @@ static void mkv_write_block(AVFormatContext *s, AVIOContext *pb, (AV_RB24(par->extradata) == 1 || AV_RB32(par->extradata) == 1)) /* extradata is Annex B, assume the bitstream is too and convert it */ ff_hevc_annexb2mp4_buf(pkt->data, &data, &size, 0, NULL); + else if (par->codec_id == AV_CODEC_ID_AV1) + ff_av1_filter_obus_buf(pkt->data, &data, &size); else if (par->codec_id == AV_CODEC_ID_WAVPACK) { int ret = mkv_strip_wavpack(pkt->data, &data, &size); if (ret < 0) { @@ -2216,9 +2230,14 @@ static int mkv_write_vtt_blocks(AVFormatContext *s, AVIOContext *pb, AVPacket *p size = id_size + 1 + settings_size + 1 + pkt->size; - av_log(s, AV_LOG_DEBUG, "Writing block at offset %" PRIu64 ", size %d, " - "pts %" PRId64 ", dts %" PRId64 ", duration %" PRId64 ", flags %d\n", - avio_tell(pb), size, pkt->pts, pkt->dts, pkt->duration, flags); + /* The following string is identical to the one in mkv_write_block so that + * only one copy needs to exist in binaries. */ + av_log(s, AV_LOG_DEBUG, + "Writing block of size %d with pts %" PRId64 ", dts %" PRId64 ", " + "duration %" PRId64 " at relative offset %" PRId64 " in cluster " + "at offset %" PRId64 ". TrackNumber %d, keyframe %d\n", + size, pkt->pts, pkt->dts, pkt->duration, avio_tell(pb), + mkv->cluster_pos, pkt->stream_index + 1, 1); blockgroup = start_ebml_master(pb, MATROSKA_ID_BLOCKGROUP, mkv_blockgroup_size(size)); @@ -2239,17 +2258,12 @@ static void mkv_start_new_cluster(AVFormatContext *s, AVPacket *pkt) { MatroskaMuxContext *mkv = s->priv_data; - end_ebml_master_crc32(s->pb, &mkv->dyn_bc, mkv, mkv->cluster); + end_ebml_master_crc32(s->pb, &mkv->cluster_bc, mkv); mkv->cluster_pos = -1; - if (s->pb->seekable & AVIO_SEEKABLE_NORMAL) - av_log(s, AV_LOG_DEBUG, - "Starting new cluster at offset %" PRIu64 " bytes, " - "pts %" PRIu64 "dts %" PRIu64 "\n", - avio_tell(s->pb), pkt->pts, pkt->dts); - else - av_log(s, AV_LOG_DEBUG, "Starting new cluster, " - "pts %" PRIu64 "dts %" PRIu64 "\n", - pkt->pts, pkt->dts); + av_log(s, AV_LOG_DEBUG, + "Starting new cluster at offset %" PRIu64 " bytes, " + "pts %" PRIu64 ", dts %" PRIu64 "\n", + avio_tell(s->pb), pkt->pts, pkt->dts); avio_flush(s->pb); } @@ -2321,6 +2335,37 @@ static int mkv_check_new_extra_data(AVFormatContext *s, AVPacket *pkt) avcodec_parameters_free(&codecpriv_par); } break; + // FIXME: Remove the following once libaom starts propagating extradata during init() + // See https://bugs.chromium.org/p/aomedia/issues/detail?id=2012 + case AV_CODEC_ID_AV1: + if (side_data_size && (s->pb->seekable & AVIO_SEEKABLE_NORMAL) && !mkv->is_live && + !par->extradata_size) { + AVIOContext *dyn_cp; + uint8_t *codecpriv; + int codecpriv_size; + int64_t curpos; + ret = avio_open_dyn_buf(&dyn_cp); + if (ret < 0) + return ret; + ff_isom_write_av1c(dyn_cp, side_data, side_data_size); + codecpriv_size = avio_close_dyn_buf(dyn_cp, &codecpriv); + if (!codecpriv_size) { + av_free(codecpriv); + return AVERROR_INVALIDDATA; + } + curpos = avio_tell(mkv->tracks_bc); + avio_seek(mkv->tracks_bc, track->codecpriv_offset, SEEK_SET); + // Do not write the OBUs as we don't have space saved for them + put_ebml_binary(mkv->tracks_bc, MATROSKA_ID_CODECPRIVATE, codecpriv, 4); + av_free(codecpriv); + avio_seek(mkv->tracks_bc, curpos, SEEK_SET); + ret = ff_alloc_extradata(par, side_data_size); + if (ret < 0) + return ret; + memcpy(par->extradata, side_data, side_data_size); + } else if (!par->extradata_size) + return AVERROR_INVALIDDATA; + break; default: if (side_data_size) av_log(s, AV_LOG_DEBUG, "Ignoring new extradata in a packet for stream %d.\n", pkt->stream_index); @@ -2349,7 +2394,7 @@ static int mkv_write_packet_internal(AVFormatContext *s, AVPacket *pkt, int add_ ts += mkv->tracks[pkt->stream_index].ts_offset; if (mkv->cluster_pos != -1) { - int64_t cluster_time = ts - mkv->cluster_pts + mkv->tracks[pkt->stream_index].ts_offset; + int64_t cluster_time = ts - mkv->cluster_pts; if ((int16_t)cluster_time != cluster_time) { av_log(s, AV_LOG_WARNING, "Starting new cluster due to timestamp\n"); mkv_start_new_cluster(s, pkt); @@ -2358,13 +2403,13 @@ static int mkv_write_packet_internal(AVFormatContext *s, AVPacket *pkt, int add_ if (mkv->cluster_pos == -1) { mkv->cluster_pos = avio_tell(s->pb); - ret = start_ebml_master_crc32(s->pb, &mkv->dyn_bc, mkv, &mkv->cluster, MATROSKA_ID_CLUSTER, 0); + ret = start_ebml_master_crc32(s->pb, &mkv->cluster_bc, mkv, MATROSKA_ID_CLUSTER); if (ret < 0) return ret; - put_ebml_uint(mkv->dyn_bc, MATROSKA_ID_CLUSTERTIMECODE, FFMAX(0, ts)); + put_ebml_uint(mkv->cluster_bc, MATROSKA_ID_CLUSTERTIMECODE, FFMAX(0, ts)); mkv->cluster_pts = FFMAX(0, ts); } - pb = mkv->dyn_bc; + pb = mkv->cluster_bc; relative_packet_pos = avio_tell(pb); @@ -2434,7 +2479,7 @@ static int mkv_write_packet(AVFormatContext *s, AVPacket *pkt) // start a new cluster every 5 MB or 5 sec, or 32k / 1 sec for streaming or // after 4k and on a keyframe - cluster_size = avio_tell(mkv->dyn_bc); + cluster_size = avio_tell(mkv->cluster_bc); if (mkv->is_dash && codec_type == AVMEDIA_TYPE_VIDEO) { // WebM DASH specification states that the first block of every cluster @@ -2481,7 +2526,8 @@ static int mkv_write_packet(AVFormatContext *s, AVPacket *pkt) // buffer an audio packet to ensure the packet containing the video // keyframe's timecode is contained in the same cluster for WebM if (codec_type == AVMEDIA_TYPE_AUDIO) { - ret = av_packet_ref(&mkv->cur_audio_pkt, pkt); + if (pkt->size > 0) + ret = av_packet_ref(&mkv->cur_audio_pkt, pkt); } else ret = mkv_write_packet_internal(s, pkt, 0); return ret; @@ -2493,14 +2539,11 @@ static int mkv_write_flush_packet(AVFormatContext *s, AVPacket *pkt) if (!pkt) { if (mkv->cluster_pos != -1) { - end_ebml_master_crc32(s->pb, &mkv->dyn_bc, mkv, mkv->cluster); + end_ebml_master_crc32(s->pb, &mkv->cluster_bc, mkv); mkv->cluster_pos = -1; - if (s->pb->seekable & AVIO_SEEKABLE_NORMAL) - av_log(s, AV_LOG_DEBUG, - "Flushing cluster at offset %" PRIu64 " bytes\n", - avio_tell(s->pb)); - else - av_log(s, AV_LOG_DEBUG, "Flushing cluster\n"); + av_log(s, AV_LOG_DEBUG, + "Flushing cluster at offset %" PRIu64 " bytes\n", + avio_tell(s->pb)); avio_flush(s->pb); } return 1; @@ -2526,8 +2569,8 @@ static int mkv_write_trailer(AVFormatContext *s) } } - if (mkv->dyn_bc) { - end_ebml_master_crc32(pb, &mkv->dyn_bc, mkv, mkv->cluster); + if (mkv->cluster_bc) { + end_ebml_master_crc32(pb, &mkv->cluster_bc, mkv); } ret = mkv_write_chapters(s); @@ -2562,7 +2605,7 @@ static int mkv_write_trailer(AVFormatContext *s) cuespos = mkv_write_cues(s, mkv->cues, mkv->tracks, s->nb_streams); } - ret = mkv_add_seekhead_entry(mkv->main_seekhead, MATROSKA_ID_CUES, + ret = mkv_add_seekhead_entry(mkv->seekhead, MATROSKA_ID_CUES, cuespos); if (ret < 0) return ret; @@ -2575,12 +2618,12 @@ static int mkv_write_trailer(AVFormatContext *s) currentpos = avio_tell(pb); avio_seek(mkv->info_bc, mkv->duration_offset, SEEK_SET); put_ebml_float(mkv->info_bc, MATROSKA_ID_DURATION, mkv->duration); - avio_seek(pb, mkv->info.pos, SEEK_SET); - end_ebml_master_crc32(pb, &mkv->info_bc, mkv, mkv->info); + avio_seek(pb, mkv->info_pos, SEEK_SET); + end_ebml_master_crc32(pb, &mkv->info_bc, mkv); // write tracks master - avio_seek(pb, mkv->tracks_master.pos, SEEK_SET); - end_ebml_master_crc32(pb, &mkv->tracks_bc, mkv, mkv->tracks_master); + avio_seek(pb, mkv->tracks_pos, SEEK_SET); + end_ebml_master_crc32(pb, &mkv->tracks_bc, mkv); // update stream durations if (!mkv->is_live && mkv->stream_durations) { @@ -2607,9 +2650,9 @@ static int mkv_write_trailer(AVFormatContext *s) } avio_seek(mkv->tags_bc, curr, SEEK_SET); } - if (mkv->tags.pos && !mkv->is_live) { - avio_seek(pb, mkv->tags.pos, SEEK_SET); - end_ebml_master_crc32(pb, &mkv->tags_bc, mkv, mkv->tags); + if (mkv->tags_bc && !mkv->is_live) { + avio_seek(pb, mkv->tags_pos, SEEK_SET); + end_ebml_master_crc32(pb, &mkv->tags_bc, mkv); } avio_seek(pb, currentpos, SEEK_SET); @@ -2640,6 +2683,16 @@ static int mkv_query_codec(enum AVCodecID codec_id, int std_compliance) return 0; } +static int webm_query_codec(enum AVCodecID codec_id, int std_compliance) +{ + int i; + for (i = 0; ff_webm_codec_tags[i].id != AV_CODEC_ID_NONE; i++) + if (ff_webm_codec_tags[i].id == codec_id) + return 1; + + return 0; +} + static int mkv_init(struct AVFormatContext *s) { int i; @@ -2695,7 +2748,6 @@ static int mkv_check_bitstream(struct AVFormatContext *s, const AVPacket *pkt) static const AVCodecTag additional_audio_tags[] = { { AV_CODEC_ID_ALAC, 0XFFFFFFFF }, - { AV_CODEC_ID_EAC3, 0XFFFFFFFF }, { AV_CODEC_ID_MLP, 0xFFFFFFFF }, { AV_CODEC_ID_OPUS, 0xFFFFFFFF }, { AV_CODEC_ID_PCM_S16BE, 0xFFFFFFFF }, @@ -2714,13 +2766,12 @@ static const AVCodecTag additional_video_tags[] = { { AV_CODEC_ID_RV10, 0xFFFFFFFF }, { AV_CODEC_ID_RV20, 0xFFFFFFFF }, { AV_CODEC_ID_RV30, 0xFFFFFFFF }, - { AV_CODEC_ID_RV40, 0xFFFFFFFF }, - { AV_CODEC_ID_VP9, 0xFFFFFFFF }, { AV_CODEC_ID_NONE, 0xFFFFFFFF } }; static const AVCodecTag additional_subtitle_tags[] = { { AV_CODEC_ID_DVB_SUBTITLE, 0xFFFFFFFF }, + { AV_CODEC_ID_DVD_SUBTITLE, 0xFFFFFFFF }, { AV_CODEC_ID_HDMV_PGS_SUBTITLE, 0xFFFFFFFF }, { AV_CODEC_ID_NONE, 0xFFFFFFFF } }; @@ -2795,6 +2846,7 @@ AVOutputFormat ff_webm_muxer = { .write_header = mkv_write_header, .write_packet = mkv_write_flush_packet, .write_trailer = mkv_write_trailer, + .query_codec = webm_query_codec, .check_bitstream = mkv_check_bitstream, .flags = AVFMT_GLOBALHEADER | AVFMT_VARIABLE_FPS | AVFMT_TS_NONSTRICT | AVFMT_ALLOW_FLUSH, diff --git a/libavformat/mgsts.c b/libavformat/mgsts.c index 0720de8d8..415e05272 100644 --- a/libavformat/mgsts.c +++ b/libavformat/mgsts.c @@ -24,7 +24,7 @@ #include "avformat.h" #include "riff.h" -static int read_probe(AVProbeData *p) +static int read_probe(const AVProbeData *p) { if (AV_RB32(p->buf ) != 0x000E || AV_RB32(p->buf + 4) != 0x0050 || diff --git a/libavformat/microdvddec.c b/libavformat/microdvddec.c index c2f1ac45c..ca9086afe 100644 --- a/libavformat/microdvddec.c +++ b/libavformat/microdvddec.c @@ -36,7 +36,7 @@ typedef struct { } MicroDVDContext; -static int microdvd_probe(AVProbeData *p) +static int microdvd_probe(const AVProbeData *p) { unsigned char c; const uint8_t *ptr = p->buf; @@ -102,6 +102,8 @@ static int microdvd_read_header(AVFormatContext *s) if (!len) break; line[strcspn(line, "\r\n")] = 0; + if (!*p) + continue; if (i++ < 3) { int frame; double fps; diff --git a/libavformat/mj2kdec.c b/libavformat/mj2kdec.c index 1fb94094c..703ff91ef 100644 --- a/libavformat/mj2kdec.c +++ b/libavformat/mj2kdec.c @@ -24,7 +24,7 @@ #include "rawdec.h" #if CONFIG_MJPEG_2000_DEMUXER -static int mjpeg2000_probe(AVProbeData *p) +static int mjpeg2000_probe(const AVProbeData *p) { const uint8_t *b = p->buf; int i, marker, marker_size; diff --git a/libavformat/mlpdec.c b/libavformat/mlpdec.c index d82df219d..40b183376 100644 --- a/libavformat/mlpdec.c +++ b/libavformat/mlpdec.c @@ -25,7 +25,7 @@ #include "rawdec.h" #include "libavutil/intreadwrite.h" -static int av_always_inline mlp_thd_probe(AVProbeData *p, uint32_t sync) +static int av_always_inline mlp_thd_probe(const AVProbeData *p, uint32_t sync) { const uint8_t *buf, *last_buf = p->buf, *end = p->buf + p->buf_size; int frames = 0, valid = 0, size = 0; @@ -51,11 +51,12 @@ static int av_always_inline mlp_thd_probe(AVProbeData *p, uint32_t sync) } #if CONFIG_MLP_DEMUXER -static int mlp_probe(AVProbeData *p) +static int mlp_probe(const AVProbeData *p) { return mlp_thd_probe(p, 0xf8726fbb); } +FF_RAW_DEMUXER_CLASS(mlp) AVInputFormat ff_mlp_demuxer = { .name = "mlp", .long_name = NULL_IF_CONFIG_SMALL("raw MLP"), @@ -65,15 +66,18 @@ AVInputFormat ff_mlp_demuxer = { .flags = AVFMT_GENERIC_INDEX | AVFMT_NOTIMESTAMPS, .extensions = "mlp", .raw_codec_id = AV_CODEC_ID_MLP, + .priv_data_size = sizeof(FFRawDemuxerContext), + .priv_class = &mlp_demuxer_class, }; #endif #if CONFIG_TRUEHD_DEMUXER -static int thd_probe(AVProbeData *p) +static int thd_probe(const AVProbeData *p) { return mlp_thd_probe(p, 0xf8726fba); } +FF_RAW_DEMUXER_CLASS(truehd) AVInputFormat ff_truehd_demuxer = { .name = "truehd", .long_name = NULL_IF_CONFIG_SMALL("raw TrueHD"), @@ -83,6 +87,8 @@ AVInputFormat ff_truehd_demuxer = { .flags = AVFMT_GENERIC_INDEX | AVFMT_NOTIMESTAMPS, .extensions = "thd", .raw_codec_id = AV_CODEC_ID_TRUEHD, + .priv_data_size = sizeof(FFRawDemuxerContext), + .priv_class = &truehd_demuxer_class, }; #endif diff --git a/libavformat/mlvdec.c b/libavformat/mlvdec.c index ded8196af..68ca2c5e1 100644 --- a/libavformat/mlvdec.c +++ b/libavformat/mlvdec.c @@ -52,7 +52,7 @@ typedef struct { uint64_t pts; } MlvContext; -static int probe(AVProbeData *p) +static int probe(const AVProbeData *p) { if (AV_RL32(p->buf) == MKTAG('M','L','V','I') && AV_RL32(p->buf + 4) >= 52 && diff --git a/libavformat/mm.c b/libavformat/mm.c index 8a1382e03..83b3c200c 100644 --- a/libavformat/mm.c +++ b/libavformat/mm.c @@ -58,7 +58,7 @@ typedef struct MmDemuxContext { unsigned int audio_pts, video_pts; } MmDemuxContext; -static int probe(AVProbeData *p) +static int probe(const AVProbeData *p) { int len, type, fps, w, h; if (p->buf_size < MM_HEADER_LEN_AV + MM_PREAMBLE_SIZE) diff --git a/libavformat/mmf.c b/libavformat/mmf.c index 1393627d8..917113066 100644 --- a/libavformat/mmf.c +++ b/libavformat/mmf.c @@ -180,7 +180,7 @@ static int mmf_write_trailer(AVFormatContext *s) } #endif /* CONFIG_MMF_MUXER */ -static int mmf_probe(AVProbeData *p) +static int mmf_probe(const AVProbeData *p) { /* check file header */ if (p->buf[0] == 'M' && p->buf[1] == 'M' && diff --git a/libavformat/mov.c b/libavformat/mov.c index 7a34a228c..327a25bbd 100644 --- a/libavformat/mov.c +++ b/libavformat/mov.c @@ -765,7 +765,8 @@ static int mov_read_hdlr(MOVContext *c, AVIOContext *pb, MOVAtom atom) title_str[title_size] = 0; if (title_str[0]) { int off = (!c->isom && title_str[0] == title_size - 1); - av_dict_set(&st->metadata, "handler_name", title_str + off, 0); + // flag added so as to not set stream handler name if already set from mdia->hdlr + av_dict_set(&st->metadata, "handler_name", title_str + off, AV_DICT_DONT_OVERWRITE); } av_freep(&title_str); } @@ -1233,16 +1234,12 @@ static int search_frag_moof_offset(MOVFragmentIndex *frag_index, int64_t offset) static int64_t get_stream_info_time(MOVFragmentStreamInfo * frag_stream_info) { - - if (frag_stream_info) { - if (frag_stream_info->sidx_pts != AV_NOPTS_VALUE) - return frag_stream_info->sidx_pts; - if (frag_stream_info->first_tfra_pts != AV_NOPTS_VALUE) - return frag_stream_info->first_tfra_pts; - if (frag_stream_info->tfdt_dts != AV_NOPTS_VALUE) - return frag_stream_info->tfdt_dts; - } - return AV_NOPTS_VALUE; + av_assert0(frag_stream_info); + if (frag_stream_info->sidx_pts != AV_NOPTS_VALUE) + return frag_stream_info->sidx_pts; + if (frag_stream_info->first_tfra_pts != AV_NOPTS_VALUE) + return frag_stream_info->first_tfra_pts; + return frag_stream_info->tfdt_dts; } static int64_t get_frag_time(MOVFragmentIndex *frag_index, @@ -1269,7 +1266,7 @@ static int64_t get_frag_time(MOVFragmentIndex *frag_index, static int search_frag_timestamp(MOVFragmentIndex *frag_index, AVStream *st, int64_t timestamp) { - int a, b, m; + int a, b, m, m0; int64_t frag_time; int id = -1; @@ -1285,15 +1282,18 @@ static int search_frag_timestamp(MOVFragmentIndex *frag_index, b = frag_index->nb_items; while (b - a > 1) { - m = (a + b) >> 1; - frag_time = get_frag_time(frag_index, m, id); - if (frag_time != AV_NOPTS_VALUE) { - if (frag_time >= timestamp) - b = m; - if (frag_time <= timestamp) - a = m; - } + m0 = m = (a + b) >> 1; + + while (m < b && + (frag_time = get_frag_time(frag_index, m, id)) == AV_NOPTS_VALUE) + m++; + + if (m < b && frag_time <= timestamp) + a = m; + else + b = m0; } + return a; } @@ -1334,6 +1334,7 @@ static int update_frag_index(MOVContext *c, int64_t offset) frag_stream_info[i].tfdt_dts = AV_NOPTS_VALUE; frag_stream_info[i].first_tfra_pts = AV_NOPTS_VALUE; frag_stream_info[i].index_entry = -1; + frag_stream_info[i].encryption_index = NULL; } if (index < c->frag_index.nb_items) @@ -1907,6 +1908,13 @@ static int mov_read_glbl(MOVContext *c, AVIOContext *pb, MOVAtom atom) ret = ff_get_extradata(c->fc, st->codecpar, pb, atom.size); if (ret < 0) return ret; + if (atom.type == MKTAG('h','v','c','C') && st->codecpar->codec_tag == MKTAG('d','v','h','1')) + /* HEVC-based Dolby Vision derived from hvc1. + Happens to match with an identifier + previously utilized for DV. Thus, if we have + the hvcC extradata box available as specified, + set codec to HEVC */ + st->codecpar->codec_id = AV_CODEC_ID_HEVC; return 0; } @@ -2037,6 +2045,8 @@ static int mov_codec_id(AVStream *st, uint32_t format) id = ff_codec_get_id(ff_codec_movsubtitle_tags, format); if (id > 0) st->codecpar->codec_type = AVMEDIA_TYPE_SUBTITLE; + else + id = ff_codec_get_id(ff_codec_movdata_tags, format); } } @@ -2123,8 +2133,8 @@ static void mov_parse_stsd_audio(MOVContext *c, AVIOContext *pb, // Read QT version 1 fields. In version 0 these do not exist. av_log(c->fc, AV_LOG_TRACE, "version =%d, isom =%d\n", version, c->isom); if (!c->isom || - (compatible_brands && strstr(compatible_brands->value, "qt "))) { - + (compatible_brands && strstr(compatible_brands->value, "qt ")) || + (sc->stsd_version == 0 && version > 0)) { if (version == 1) { sc->samples_per_frame = avio_rb32(pb); avio_rb32(pb); /* bytes per packet */ @@ -2495,18 +2505,16 @@ int ff_mov_read_stsd_entries(MOVContext *c, AVIOContext *pb, int entries) "size=%"PRId64" 4CC=%s codec_type=%d\n", size, av_fourcc2str(format), st->codecpar->codec_type); + st->codecpar->codec_id = id; if (st->codecpar->codec_type==AVMEDIA_TYPE_VIDEO) { - st->codecpar->codec_id = id; mov_parse_stsd_video(c, pb, st, sc); } else if (st->codecpar->codec_type==AVMEDIA_TYPE_AUDIO) { - st->codecpar->codec_id = id; mov_parse_stsd_audio(c, pb, st, sc); if (st->codecpar->sample_rate < 0) { av_log(c->fc, AV_LOG_ERROR, "Invalid sample rate %d\n", st->codecpar->sample_rate); return AVERROR_INVALIDDATA; } } else if (st->codecpar->codec_type==AVMEDIA_TYPE_SUBTITLE){ - st->codecpar->codec_id = id; mov_parse_stsd_subtitle(c, pb, st, sc, size - (avio_tell(pb) - start_pos)); } else { @@ -2557,7 +2565,7 @@ static int mov_read_stsd(MOVContext *c, AVIOContext *pb, MOVAtom atom) st = c->fc->streams[c->fc->nb_streams - 1]; sc = st->priv_data; - avio_r8(pb); /* version */ + sc->stsd_version = avio_r8(pb); avio_rb24(pb); /* flags */ entries = avio_rb32(pb); @@ -2851,7 +2859,8 @@ static int mov_read_stsz(MOVContext *c, AVIOContext *pb, MOVAtom atom) if (ret < 0) { av_freep(&sc->sample_sizes); av_free(buf); - return ret; + av_log(c->fc, AV_LOG_WARNING, "STSZ atom truncated\n"); + return 0; } init_get_bits(&gb, buf, 8*num_bytes); @@ -2923,12 +2932,6 @@ static int mov_read_stts(MOVContext *c, AVIOContext *pb, MOVAtom atom) av_log(c->fc, AV_LOG_TRACE, "sample_count=%d, sample_duration=%d\n", sample_count, sample_duration); - if ( i+1 == entries - && i - && sample_count == 1 - && total_sample_count > 100 - && sample_duration/10 > duration / total_sample_count) - sample_duration = duration / total_sample_count; duration+=(int64_t)sample_duration*(uint64_t)sample_count; total_sample_count+=sample_count; } @@ -2937,7 +2940,7 @@ static int mov_read_stts(MOVContext *c, AVIOContext *pb, MOVAtom atom) if (duration > 0 && duration <= INT64_MAX - sc->duration_for_fps && - total_sample_count <= INT64_MAX - sc->nb_frames_for_fps + total_sample_count <= INT_MAX - sc->nb_frames_for_fps ) { sc->duration_for_fps += duration; sc->nb_frames_for_fps += total_sample_count; @@ -2950,7 +2953,7 @@ static int mov_read_stts(MOVContext *c, AVIOContext *pb, MOVAtom atom) st->nb_frames= total_sample_count; if (duration) - st->duration= duration; + st->duration= FFMIN(st->duration, duration); sc->track_end = duration; return 0; } @@ -3443,6 +3446,7 @@ static void mov_fix_index(MOVContext *mov, AVStream *st) MOVIndexRange *current_index_range; int i; int found_keyframe_after_edit = 0; + int found_non_empty_edit = 0; if (!msc->elst_data || msc->elst_count <= 0 || nb_old <= 0) { return; @@ -3489,10 +3493,11 @@ static void mov_fix_index(MOVContext *mov, AVStream *st) edit_list_dts_counter = edit_list_dts_entry_end; edit_list_dts_entry_end += edit_list_duration; num_discarded_begin = 0; - if (edit_list_media_time == -1) { + if (!found_non_empty_edit && edit_list_media_time == -1) { empty_edits_sum_duration += edit_list_duration; continue; } + found_non_empty_edit = 1; // If we encounter a non-negative edit list reset the skip_samples/start_pad fields and set them // according to the edit list below. @@ -3599,7 +3604,7 @@ static void mov_fix_index(MOVContext *mov, AVStream *st) flags |= AVINDEX_DISCARD_FRAME; av_log(mov->fc, AV_LOG_DEBUG, "drop a frame at curr_cts: %"PRId64" @ %"PRId64"\n", curr_cts, index); - if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && edit_list_start_encountered == 0) { + if (edit_list_start_encountered == 0) { num_discarded_begin++; frame_duration_buffer = av_realloc(frame_duration_buffer, num_discarded_begin * sizeof(int64_t)); @@ -3610,7 +3615,8 @@ static void mov_fix_index(MOVContext *mov, AVStream *st) frame_duration_buffer[num_discarded_begin - 1] = frame_duration; // Increment skip_samples for the first non-zero audio edit list - if (first_non_zero_audio_edit > 0 && st->codecpar->codec_id != AV_CODEC_ID_VORBIS) { + if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && + first_non_zero_audio_edit > 0 && st->codecpar->codec_id != AV_CODEC_ID_VORBIS) { st->skip_samples += frame_duration; } } @@ -3623,9 +3629,9 @@ static void mov_fix_index(MOVContext *mov, AVStream *st) } if (edit_list_start_encountered == 0) { edit_list_start_encountered = 1; - // Make timestamps strictly monotonically increasing for audio, by rewriting timestamps for + // Make timestamps strictly monotonically increasing by rewriting timestamps for // discarded packets. - if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && frame_duration_buffer) { + if (frame_duration_buffer) { fix_index_entry_timestamps(st, st->nb_index_entries, edit_list_dts_counter, frame_duration_buffer, num_discarded_begin); av_freep(&frame_duration_buffer); @@ -3684,15 +3690,19 @@ static void mov_fix_index(MOVContext *mov, AVStream *st) // If the minimum pts turns out to be greater than zero after fixing the index, then we subtract the // dts by that amount to make the first pts zero. - if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && msc->min_corrected_pts > 0) { - av_log(mov->fc, AV_LOG_DEBUG, "Offset DTS by %"PRId64" to make first pts zero.\n", msc->min_corrected_pts); - for (i = 0; i < st->nb_index_entries; ++i) { - st->index_entries[i].timestamp -= msc->min_corrected_pts; + if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { + if (msc->min_corrected_pts > 0) { + av_log(mov->fc, AV_LOG_DEBUG, "Offset DTS by %"PRId64" to make first pts zero.\n", msc->min_corrected_pts); + for (i = 0; i < st->nb_index_entries; ++i) { + st->index_entries[i].timestamp -= msc->min_corrected_pts; + } } } + // Start time should be equal to zero or the duration of any empty edits. + st->start_time = empty_edits_sum_duration; - // Update av stream length - st->duration = edit_list_dts_entry_end - start_dts; + // Update av stream length, if it ends up shorter than the track's media duration + st->duration = FFMIN(st->duration, edit_list_dts_entry_end - start_dts); msc->start_pad = st->skip_samples; // Free the old index and the old CTTS structures @@ -4024,6 +4034,14 @@ static void mov_build_index(MOVContext *mov, AVStream *st) mov_fix_index(mov, st); } + // Update start time of the stream. + if (st->start_time == AV_NOPTS_VALUE && st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && st->nb_index_entries > 0) { + st->start_time = st->index_entries[0].timestamp + sc->dts_shift; + if (sc->ctts_data) { + st->start_time += sc->ctts_data[0].duration; + } + } + mov_estimate_video_delay(mov, st); } @@ -4544,25 +4562,24 @@ static int mov_read_tfhd(MOVContext *c, AVIOContext *pb, MOVAtom atom) MOVTrackExt *trex = NULL; int flags, track_id, i; - c->fragment.found_tfhd = 1; - avio_r8(pb); /* version */ flags = avio_rb24(pb); track_id = avio_rb32(pb); if (!track_id) return AVERROR_INVALIDDATA; - frag->track_id = track_id; - set_frag_stream(&c->frag_index, track_id); for (i = 0; i < c->trex_count; i++) - if (c->trex_data[i].track_id == frag->track_id) { + if (c->trex_data[i].track_id == track_id) { trex = &c->trex_data[i]; break; } if (!trex) { - av_log(c->fc, AV_LOG_ERROR, "could not find corresponding trex\n"); - return AVERROR_INVALIDDATA; + av_log(c->fc, AV_LOG_WARNING, "could not find corresponding trex (id %u)\n", track_id); + return 0; } + c->fragment.found_tfhd = 1; + frag->track_id = track_id; + set_frag_stream(&c->frag_index, track_id); frag->base_data_offset = flags & MOV_TFHD_BASE_DATA_OFFSET ? avio_rb64(pb) : flags & MOV_TFHD_DEFAULT_BASE_IS_MOOF ? @@ -4641,8 +4658,8 @@ static int mov_read_tfdt(MOVContext *c, AVIOContext *pb, MOVAtom atom) } } if (!st) { - av_log(c->fc, AV_LOG_ERROR, "could not find corresponding track id %u\n", frag->track_id); - return AVERROR_INVALIDDATA; + av_log(c->fc, AV_LOG_WARNING, "could not find corresponding track id %u\n", frag->track_id); + return 0; } sc = st->priv_data; if (sc->pseudo_stream_id + 1 != frag->stsd_id && sc->pseudo_stream_id != -1) @@ -4693,8 +4710,8 @@ static int mov_read_trun(MOVContext *c, AVIOContext *pb, MOVAtom atom) } } if (!st) { - av_log(c->fc, AV_LOG_ERROR, "could not find corresponding track id %u\n", frag->track_id); - return AVERROR_INVALIDDATA; + av_log(c->fc, AV_LOG_WARNING, "could not find corresponding track id %u\n", frag->track_id); + return 0; } sc = st->priv_data; if (sc->pseudo_stream_id+1 != frag->stsd_id && sc->pseudo_stream_id != -1) @@ -4879,7 +4896,7 @@ static int mov_read_trun(MOVContext *c, AVIOContext *pb, MOVAtom atom) sc->data_size += sample_size; if (sample_duration <= INT64_MAX - sc->duration_for_fps && - 1 <= INT64_MAX - sc->nb_frames_for_fps + 1 <= INT_MAX - sc->nb_frames_for_fps ) { sc->duration_for_fps += sample_duration; sc->nb_frames_for_fps ++; @@ -5200,6 +5217,34 @@ static int mov_read_tmcd(MOVContext *c, AVIOContext *pb, MOVAtom atom) return 0; } +static int mov_read_av1c(MOVContext *c, AVIOContext *pb, MOVAtom atom) +{ + AVStream *st; + int ret; + + if (c->fc->nb_streams < 1) + return 0; + st = c->fc->streams[c->fc->nb_streams - 1]; + + if (atom.size < 4) { + av_log(c->fc, AV_LOG_ERROR, "Empty AV1 Codec Configuration Box\n"); + return AVERROR_INVALIDDATA; + } + + /* For now, propagate only the OBUs, if any. Once libavcodec is + updated to handle isobmff style extradata this can be removed. */ + avio_skip(pb, 4); + + if (atom.size == 4) + return 0; + + ret = ff_get_extradata(c->fc, st->codecpar, pb, atom.size - 4); + if (ret < 0) + return ret; + + return 0; +} + static int mov_read_vpcc(MOVContext *c, AVIOContext *pb, MOVAtom atom) { AVStream *st; @@ -5247,9 +5292,7 @@ static int mov_read_vpcc(MOVContext *c, AVIOContext *pb, MOVAtom atom) static int mov_read_smdm(MOVContext *c, AVIOContext *pb, MOVAtom atom) { MOVStreamContext *sc; - const int chroma_den = 50000; - const int luma_den = 10000; - int i, j, version; + int i, version; if (c->fc->nb_streams < 1) return AVERROR_INVALIDDATA; @@ -5272,17 +5315,15 @@ static int mov_read_smdm(MOVContext *c, AVIOContext *pb, MOVAtom atom) if (!sc->mastering) return AVERROR(ENOMEM); - for (i = 0; i < 3; i++) - for (j = 0; j < 2; j++) - sc->mastering->display_primaries[i][j] = - av_make_q(lrint(((double)avio_rb16(pb) / (1 << 16)) * chroma_den), chroma_den); - for (i = 0; i < 2; i++) - sc->mastering->white_point[i] = - av_make_q(lrint(((double)avio_rb16(pb) / (1 << 16)) * chroma_den), chroma_den); - sc->mastering->max_luminance = - av_make_q(lrint(((double)avio_rb32(pb) / (1 << 8)) * luma_den), luma_den); - sc->mastering->min_luminance = - av_make_q(lrint(((double)avio_rb32(pb) / (1 << 14)) * luma_den), luma_den); + for (i = 0; i < 3; i++) { + sc->mastering->display_primaries[i][0] = av_make_q(avio_rb16(pb), 1 << 16); + sc->mastering->display_primaries[i][1] = av_make_q(avio_rb16(pb), 1 << 16); + } + sc->mastering->white_point[0] = av_make_q(avio_rb16(pb), 1 << 16); + sc->mastering->white_point[1] = av_make_q(avio_rb16(pb), 1 << 16); + + sc->mastering->max_luminance = av_make_q(avio_rb32(pb), 1 << 8); + sc->mastering->min_luminance = av_make_q(avio_rb32(pb), 1 << 14); sc->mastering->has_primaries = 1; sc->mastering->has_luminance = 1; @@ -5805,117 +5846,635 @@ static int mov_read_frma(MOVContext *c, AVIOContext *pb, MOVAtom atom) return 0; } +/** + * Gets the current encryption info and associated current stream context. If + * we are parsing a track fragment, this will return the specific encryption + * info for this fragment; otherwise this will return the global encryption + * info for the current stream. + */ +static int get_current_encryption_info(MOVContext *c, MOVEncryptionIndex **encryption_index, MOVStreamContext **sc) +{ + MOVFragmentStreamInfo *frag_stream_info; + AVStream *st; + int i; + + frag_stream_info = get_current_frag_stream_info(&c->frag_index); + if (frag_stream_info) { + for (i = 0; i < c->fc->nb_streams; i++) { + if (c->fc->streams[i]->id == frag_stream_info->id) { + st = c->fc->streams[i]; + break; + } + } + if (i == c->fc->nb_streams) + return 0; + *sc = st->priv_data; + + if (!frag_stream_info->encryption_index) { + // If this stream isn't encrypted, don't create the index. + if (!(*sc)->cenc.default_encrypted_sample) + return 0; + frag_stream_info->encryption_index = av_mallocz(sizeof(*frag_stream_info->encryption_index)); + if (!frag_stream_info->encryption_index) + return AVERROR(ENOMEM); + } + *encryption_index = frag_stream_info->encryption_index; + return 1; + } else { + // No current track fragment, using stream level encryption info. + + if (c->fc->nb_streams < 1) + return 0; + st = c->fc->streams[c->fc->nb_streams - 1]; + *sc = st->priv_data; + + if (!(*sc)->cenc.encryption_index) { + // If this stream isn't encrypted, don't create the index. + if (!(*sc)->cenc.default_encrypted_sample) + return 0; + (*sc)->cenc.encryption_index = av_mallocz(sizeof(*frag_stream_info->encryption_index)); + if (!(*sc)->cenc.encryption_index) + return AVERROR(ENOMEM); + } + + *encryption_index = (*sc)->cenc.encryption_index; + return 1; + } +} + +static int mov_read_sample_encryption_info(MOVContext *c, AVIOContext *pb, MOVStreamContext *sc, AVEncryptionInfo **sample, int use_subsamples) +{ + int i; + unsigned int subsample_count; + AVSubsampleEncryptionInfo *subsamples; + + if (!sc->cenc.default_encrypted_sample) { + av_log(c->fc, AV_LOG_ERROR, "Missing schm or tenc\n"); + return AVERROR_INVALIDDATA; + } + + *sample = av_encryption_info_clone(sc->cenc.default_encrypted_sample); + if (!*sample) + return AVERROR(ENOMEM); + + if (sc->cenc.per_sample_iv_size != 0) { + if (avio_read(pb, (*sample)->iv, sc->cenc.per_sample_iv_size) != sc->cenc.per_sample_iv_size) { + av_log(c->fc, AV_LOG_ERROR, "failed to read the initialization vector\n"); + av_encryption_info_free(*sample); + *sample = NULL; + return AVERROR_INVALIDDATA; + } + } + + if (use_subsamples) { + subsample_count = avio_rb16(pb); + av_free((*sample)->subsamples); + (*sample)->subsamples = av_mallocz_array(subsample_count, sizeof(*subsamples)); + if (!(*sample)->subsamples) { + av_encryption_info_free(*sample); + *sample = NULL; + return AVERROR(ENOMEM); + } + + for (i = 0; i < subsample_count && !pb->eof_reached; i++) { + (*sample)->subsamples[i].bytes_of_clear_data = avio_rb16(pb); + (*sample)->subsamples[i].bytes_of_protected_data = avio_rb32(pb); + } + + if (pb->eof_reached) { + av_log(c->fc, AV_LOG_ERROR, "hit EOF while reading sub-sample encryption info\n"); + av_encryption_info_free(*sample); + *sample = NULL; + return AVERROR_INVALIDDATA; + } + (*sample)->subsample_count = subsample_count; + } + + return 0; +} + static int mov_read_senc(MOVContext *c, AVIOContext *pb, MOVAtom atom) { - AVStream *st; + AVEncryptionInfo **encrypted_samples; + MOVEncryptionIndex *encryption_index; MOVStreamContext *sc; - size_t auxiliary_info_size; + int use_subsamples, ret; + unsigned int sample_count, i, alloc_size = 0; - if (c->decryption_key_len == 0 || c->fc->nb_streams < 1) + ret = get_current_encryption_info(c, &encryption_index, &sc); + if (ret != 1) + return ret; + + if (encryption_index->nb_encrypted_samples) { + // This can happen if we have both saio/saiz and senc atoms. + av_log(c->fc, AV_LOG_DEBUG, "Ignoring duplicate encryption info in senc\n"); return 0; - - st = c->fc->streams[c->fc->nb_streams - 1]; - sc = st->priv_data; - - if (sc->cenc.aes_ctr) { - av_log(c->fc, AV_LOG_ERROR, "duplicate senc atom\n"); - return AVERROR_INVALIDDATA; } avio_r8(pb); /* version */ - sc->cenc.use_subsamples = avio_rb24(pb) & 0x02; /* flags */ + use_subsamples = avio_rb24(pb) & 0x02; /* flags */ - avio_rb32(pb); /* entries */ - - if (atom.size < 8 || atom.size > FFMIN(INT_MAX, SIZE_MAX)) { - av_log(c->fc, AV_LOG_ERROR, "senc atom size %"PRId64" invalid\n", atom.size); - return AVERROR_INVALIDDATA; - } - - /* save the auxiliary info as is */ - auxiliary_info_size = atom.size - 8; - - sc->cenc.auxiliary_info = av_malloc(auxiliary_info_size); - if (!sc->cenc.auxiliary_info) { + sample_count = avio_rb32(pb); + if (sample_count >= INT_MAX / sizeof(*encrypted_samples)) return AVERROR(ENOMEM); + + for (i = 0; i < sample_count; i++) { + unsigned int min_samples = FFMIN(FFMAX(i + 1, 1024 * 1024), sample_count); + encrypted_samples = av_fast_realloc(encryption_index->encrypted_samples, &alloc_size, + min_samples * sizeof(*encrypted_samples)); + if (encrypted_samples) { + encryption_index->encrypted_samples = encrypted_samples; + + ret = mov_read_sample_encryption_info( + c, pb, sc, &encryption_index->encrypted_samples[i], use_subsamples); + } else { + ret = AVERROR(ENOMEM); + } + if (pb->eof_reached) { + av_log(c->fc, AV_LOG_ERROR, "Hit EOF while reading senc\n"); + ret = AVERROR_INVALIDDATA; + } + + if (ret < 0) { + for (; i > 0; i--) + av_encryption_info_free(encryption_index->encrypted_samples[i - 1]); + av_freep(&encryption_index->encrypted_samples); + return ret; + } } + encryption_index->nb_encrypted_samples = sample_count; - sc->cenc.auxiliary_info_end = sc->cenc.auxiliary_info + auxiliary_info_size; - sc->cenc.auxiliary_info_pos = sc->cenc.auxiliary_info; - sc->cenc.auxiliary_info_index = 0; + return 0; +} - if (avio_read(pb, sc->cenc.auxiliary_info, auxiliary_info_size) != auxiliary_info_size) { - av_log(c->fc, AV_LOG_ERROR, "failed to read the auxiliary info"); - return AVERROR_INVALIDDATA; +static int mov_parse_auxiliary_info(MOVContext *c, MOVStreamContext *sc, AVIOContext *pb, MOVEncryptionIndex *encryption_index) +{ + AVEncryptionInfo **sample, **encrypted_samples; + int64_t prev_pos; + size_t sample_count, sample_info_size, i; + int ret = 0; + unsigned int alloc_size = 0; + + if (encryption_index->nb_encrypted_samples) + return 0; + sample_count = encryption_index->auxiliary_info_sample_count; + if (encryption_index->auxiliary_offsets_count != 1) { + av_log(c->fc, AV_LOG_ERROR, "Multiple auxiliary info chunks are not supported\n"); + return AVERROR_PATCHWELCOME; } - - /* initialize the cipher */ - sc->cenc.aes_ctr = av_aes_ctr_alloc(); - if (!sc->cenc.aes_ctr) { + if (sample_count >= INT_MAX / sizeof(*encrypted_samples)) return AVERROR(ENOMEM); + + prev_pos = avio_tell(pb); + if (!(pb->seekable & AVIO_SEEKABLE_NORMAL) || + avio_seek(pb, encryption_index->auxiliary_offsets[0], SEEK_SET) != encryption_index->auxiliary_offsets[0]) { + av_log(c->fc, AV_LOG_INFO, "Failed to seek for auxiliary info, will only parse senc atoms for encryption info\n"); + goto finish; } - return av_aes_ctr_init(sc->cenc.aes_ctr, c->decryption_key); + for (i = 0; i < sample_count && !pb->eof_reached; i++) { + unsigned int min_samples = FFMIN(FFMAX(i + 1, 1024 * 1024), sample_count); + encrypted_samples = av_fast_realloc(encryption_index->encrypted_samples, &alloc_size, + min_samples * sizeof(*encrypted_samples)); + if (!encrypted_samples) { + ret = AVERROR(ENOMEM); + goto finish; + } + encryption_index->encrypted_samples = encrypted_samples; + + sample = &encryption_index->encrypted_samples[i]; + sample_info_size = encryption_index->auxiliary_info_default_size + ? encryption_index->auxiliary_info_default_size + : encryption_index->auxiliary_info_sizes[i]; + + ret = mov_read_sample_encryption_info(c, pb, sc, sample, sample_info_size > sc->cenc.per_sample_iv_size); + if (ret < 0) + goto finish; + } + if (pb->eof_reached) { + av_log(c->fc, AV_LOG_ERROR, "Hit EOF while reading auxiliary info\n"); + ret = AVERROR_INVALIDDATA; + } else { + encryption_index->nb_encrypted_samples = sample_count; + } + +finish: + avio_seek(pb, prev_pos, SEEK_SET); + if (ret < 0) { + for (; i > 0; i--) { + av_encryption_info_free(encryption_index->encrypted_samples[i - 1]); + } + av_freep(&encryption_index->encrypted_samples); + } + return ret; +} + +/** + * Tries to read the given number of bytes from the stream and puts it in a + * newly allocated buffer. This reads in small chunks to avoid allocating large + * memory if the file contains an invalid/malicious size value. + */ +static int mov_try_read_block(AVIOContext *pb, size_t size, uint8_t **data) +{ + const unsigned int block_size = 1024 * 1024; + uint8_t *buffer = NULL; + unsigned int alloc_size = 0, offset = 0; + while (offset < size) { + unsigned int new_size = + alloc_size >= INT_MAX - block_size ? INT_MAX : alloc_size + block_size; + uint8_t *new_buffer = av_fast_realloc(buffer, &alloc_size, new_size); + unsigned int to_read = FFMIN(size, alloc_size) - offset; + if (!new_buffer) { + av_free(buffer); + return AVERROR(ENOMEM); + } + buffer = new_buffer; + + if (avio_read(pb, buffer + offset, to_read) != to_read) { + av_free(buffer); + return AVERROR_INVALIDDATA; + } + offset += to_read; + } + + *data = buffer; + return 0; } static int mov_read_saiz(MOVContext *c, AVIOContext *pb, MOVAtom atom) { - AVStream *st; + MOVEncryptionIndex *encryption_index; MOVStreamContext *sc; - size_t data_size; - int atom_header_size; - int flags; + int ret; + unsigned int sample_count, aux_info_type, aux_info_param; - if (c->decryption_key_len == 0 || c->fc->nb_streams < 1) + ret = get_current_encryption_info(c, &encryption_index, &sc); + if (ret != 1) + return ret; + + if (encryption_index->nb_encrypted_samples) { + // This can happen if we have both saio/saiz and senc atoms. + av_log(c->fc, AV_LOG_DEBUG, "Ignoring duplicate encryption info in saiz\n"); return 0; - - st = c->fc->streams[c->fc->nb_streams - 1]; - sc = st->priv_data; - - if (sc->cenc.auxiliary_info_sizes || sc->cenc.auxiliary_info_default_size) { - av_log(c->fc, AV_LOG_ERROR, "duplicate saiz atom\n"); - return AVERROR_INVALIDDATA; } - atom_header_size = 9; + if (encryption_index->auxiliary_info_sample_count) { + av_log(c->fc, AV_LOG_ERROR, "Duplicate saiz atom\n"); + return AVERROR_INVALIDDATA; + } avio_r8(pb); /* version */ - flags = avio_rb24(pb); - - if ((flags & 0x01) != 0) { - atom_header_size += 8; - - avio_rb32(pb); /* info type */ - avio_rb32(pb); /* info type param */ - } - - sc->cenc.auxiliary_info_default_size = avio_r8(pb); - avio_rb32(pb); /* entries */ - - if (atom.size <= atom_header_size) { + if (avio_rb24(pb) & 0x01) { /* flags */ + aux_info_type = avio_rb32(pb); + aux_info_param = avio_rb32(pb); + if (sc->cenc.default_encrypted_sample) { + if (aux_info_type != sc->cenc.default_encrypted_sample->scheme) { + av_log(c->fc, AV_LOG_DEBUG, "Ignoring saiz box with non-zero aux_info_type\n"); + return 0; + } + if (aux_info_param != 0) { + av_log(c->fc, AV_LOG_DEBUG, "Ignoring saiz box with non-zero aux_info_type_parameter\n"); + return 0; + } + } else { + // Didn't see 'schm' or 'tenc', so this isn't encrypted. + if ((aux_info_type == MKBETAG('c','e','n','c') || + aux_info_type == MKBETAG('c','e','n','s') || + aux_info_type == MKBETAG('c','b','c','1') || + aux_info_type == MKBETAG('c','b','c','s')) && + aux_info_param == 0) { + av_log(c->fc, AV_LOG_ERROR, "Saw encrypted saiz without schm/tenc\n"); + return AVERROR_INVALIDDATA; + } else { + return 0; + } + } + } else if (!sc->cenc.default_encrypted_sample) { + // Didn't see 'schm' or 'tenc', so this isn't encrypted. return 0; } - if (atom.size > FFMIN(INT_MAX, SIZE_MAX)) { - av_log(c->fc, AV_LOG_ERROR, "saiz atom auxiliary_info_sizes size %"PRId64" invalid\n", atom.size); + encryption_index->auxiliary_info_default_size = avio_r8(pb); + sample_count = avio_rb32(pb); + encryption_index->auxiliary_info_sample_count = sample_count; + + if (encryption_index->auxiliary_info_default_size == 0) { + ret = mov_try_read_block(pb, sample_count, &encryption_index->auxiliary_info_sizes); + if (ret < 0) { + av_log(c->fc, AV_LOG_ERROR, "Failed to read the auxiliary info\n"); + return ret; + } + } + + if (encryption_index->auxiliary_offsets_count) { + return mov_parse_auxiliary_info(c, sc, pb, encryption_index); + } + + return 0; +} + +static int mov_read_saio(MOVContext *c, AVIOContext *pb, MOVAtom atom) +{ + uint64_t *auxiliary_offsets; + MOVEncryptionIndex *encryption_index; + MOVStreamContext *sc; + int i, ret; + unsigned int version, entry_count, aux_info_type, aux_info_param; + unsigned int alloc_size = 0; + + ret = get_current_encryption_info(c, &encryption_index, &sc); + if (ret != 1) + return ret; + + if (encryption_index->nb_encrypted_samples) { + // This can happen if we have both saio/saiz and senc atoms. + av_log(c->fc, AV_LOG_DEBUG, "Ignoring duplicate encryption info in saio\n"); + return 0; + } + + if (encryption_index->auxiliary_offsets_count) { + av_log(c->fc, AV_LOG_ERROR, "Duplicate saio atom\n"); return AVERROR_INVALIDDATA; } - /* save the auxiliary info sizes as is */ - data_size = atom.size - atom_header_size; + version = avio_r8(pb); /* version */ + if (avio_rb24(pb) & 0x01) { /* flags */ + aux_info_type = avio_rb32(pb); + aux_info_param = avio_rb32(pb); + if (sc->cenc.default_encrypted_sample) { + if (aux_info_type != sc->cenc.default_encrypted_sample->scheme) { + av_log(c->fc, AV_LOG_DEBUG, "Ignoring saio box with non-zero aux_info_type\n"); + return 0; + } + if (aux_info_param != 0) { + av_log(c->fc, AV_LOG_DEBUG, "Ignoring saio box with non-zero aux_info_type_parameter\n"); + return 0; + } + } else { + // Didn't see 'schm' or 'tenc', so this isn't encrypted. + if ((aux_info_type == MKBETAG('c','e','n','c') || + aux_info_type == MKBETAG('c','e','n','s') || + aux_info_type == MKBETAG('c','b','c','1') || + aux_info_type == MKBETAG('c','b','c','s')) && + aux_info_param == 0) { + av_log(c->fc, AV_LOG_ERROR, "Saw encrypted saio without schm/tenc\n"); + return AVERROR_INVALIDDATA; + } else { + return 0; + } + } + } else if (!sc->cenc.default_encrypted_sample) { + // Didn't see 'schm' or 'tenc', so this isn't encrypted. + return 0; + } - sc->cenc.auxiliary_info_sizes = av_malloc(data_size); - if (!sc->cenc.auxiliary_info_sizes) { + entry_count = avio_rb32(pb); + if (entry_count >= INT_MAX / sizeof(*auxiliary_offsets)) return AVERROR(ENOMEM); + + for (i = 0; i < entry_count && !pb->eof_reached; i++) { + unsigned int min_offsets = FFMIN(FFMAX(i + 1, 1024), entry_count); + auxiliary_offsets = av_fast_realloc( + encryption_index->auxiliary_offsets, &alloc_size, + min_offsets * sizeof(*auxiliary_offsets)); + if (!auxiliary_offsets) { + av_freep(&encryption_index->auxiliary_offsets); + return AVERROR(ENOMEM); + } + encryption_index->auxiliary_offsets = auxiliary_offsets; + + if (version == 0) { + encryption_index->auxiliary_offsets[i] = avio_rb32(pb); + } else { + encryption_index->auxiliary_offsets[i] = avio_rb64(pb); + } + if (c->frag_index.current >= 0) { + encryption_index->auxiliary_offsets[i] += c->fragment.base_data_offset; + } } - sc->cenc.auxiliary_info_sizes_count = data_size; - - if (avio_read(pb, sc->cenc.auxiliary_info_sizes, data_size) != data_size) { - av_log(c->fc, AV_LOG_ERROR, "failed to read the auxiliary info sizes"); + if (pb->eof_reached) { + av_log(c->fc, AV_LOG_ERROR, "Hit EOF while reading saio\n"); + av_freep(&encryption_index->auxiliary_offsets); return AVERROR_INVALIDDATA; } + encryption_index->auxiliary_offsets_count = entry_count; + + if (encryption_index->auxiliary_info_sample_count) { + return mov_parse_auxiliary_info(c, sc, pb, encryption_index); + } + + return 0; +} + +static int mov_read_pssh(MOVContext *c, AVIOContext *pb, MOVAtom atom) +{ + AVEncryptionInitInfo *info, *old_init_info; + uint8_t **key_ids; + AVStream *st; + uint8_t *side_data, *extra_data, *old_side_data; + size_t side_data_size; + int ret = 0, old_side_data_size; + unsigned int version, kid_count, extra_data_size, alloc_size = 0; + + if (c->fc->nb_streams < 1) + return 0; + st = c->fc->streams[c->fc->nb_streams-1]; + + version = avio_r8(pb); /* version */ + avio_rb24(pb); /* flags */ + + info = av_encryption_init_info_alloc(/* system_id_size */ 16, /* num_key_ids */ 0, + /* key_id_size */ 16, /* data_size */ 0); + if (!info) + return AVERROR(ENOMEM); + + if (avio_read(pb, info->system_id, 16) != 16) { + av_log(c->fc, AV_LOG_ERROR, "Failed to read the system id\n"); + ret = AVERROR_INVALIDDATA; + goto finish; + } + + if (version > 0) { + kid_count = avio_rb32(pb); + if (kid_count >= INT_MAX / sizeof(*key_ids)) + return AVERROR(ENOMEM); + + for (unsigned int i = 0; i < kid_count && !pb->eof_reached; i++) { + unsigned int min_kid_count = FFMIN(FFMAX(i + 1, 1024), kid_count); + key_ids = av_fast_realloc(info->key_ids, &alloc_size, + min_kid_count * sizeof(*key_ids)); + if (!key_ids) { + ret = AVERROR(ENOMEM); + goto finish; + } + info->key_ids = key_ids; + + info->key_ids[i] = av_mallocz(16); + if (!info->key_ids[i]) { + ret = AVERROR(ENOMEM); + goto finish; + } + info->num_key_ids = i + 1; + + if (avio_read(pb, info->key_ids[i], 16) != 16) { + av_log(c->fc, AV_LOG_ERROR, "Failed to read the key id\n"); + ret = AVERROR_INVALIDDATA; + goto finish; + } + } + + if (pb->eof_reached) { + av_log(c->fc, AV_LOG_ERROR, "Hit EOF while reading pssh\n"); + ret = AVERROR_INVALIDDATA; + goto finish; + } + } + + extra_data_size = avio_rb32(pb); + ret = mov_try_read_block(pb, extra_data_size, &extra_data); + if (ret < 0) + goto finish; + + av_freep(&info->data); // malloc(0) may still allocate something. + info->data = extra_data; + info->data_size = extra_data_size; + + // If there is existing initialization data, append to the list. + old_side_data = av_stream_get_side_data(st, AV_PKT_DATA_ENCRYPTION_INIT_INFO, &old_side_data_size); + if (old_side_data) { + old_init_info = av_encryption_init_info_get_side_data(old_side_data, old_side_data_size); + if (old_init_info) { + // Append to the end of the list. + for (AVEncryptionInitInfo *cur = old_init_info;; cur = cur->next) { + if (!cur->next) { + cur->next = info; + break; + } + } + info = old_init_info; + } else { + // Assume existing side-data will be valid, so the only error we could get is OOM. + ret = AVERROR(ENOMEM); + goto finish; + } + } + + side_data = av_encryption_init_info_add_side_data(info, &side_data_size); + if (!side_data) { + ret = AVERROR(ENOMEM); + goto finish; + } + ret = av_stream_add_side_data(st, AV_PKT_DATA_ENCRYPTION_INIT_INFO, + side_data, side_data_size); + if (ret < 0) + av_free(side_data); + +finish: + av_encryption_init_info_free(info); + return ret; +} + +static int mov_read_schm(MOVContext *c, AVIOContext *pb, MOVAtom atom) +{ + AVStream *st; + MOVStreamContext *sc; + + if (c->fc->nb_streams < 1) + return 0; + st = c->fc->streams[c->fc->nb_streams-1]; + sc = st->priv_data; + + if (sc->pseudo_stream_id != 0) { + av_log(c->fc, AV_LOG_ERROR, "schm boxes are only supported in first sample descriptor\n"); + return AVERROR_PATCHWELCOME; + } + + if (atom.size < 8) + return AVERROR_INVALIDDATA; + + avio_rb32(pb); /* version and flags */ + + if (!sc->cenc.default_encrypted_sample) { + sc->cenc.default_encrypted_sample = av_encryption_info_alloc(0, 16, 16); + if (!sc->cenc.default_encrypted_sample) { + return AVERROR(ENOMEM); + } + } + + sc->cenc.default_encrypted_sample->scheme = avio_rb32(pb); + return 0; +} + +static int mov_read_tenc(MOVContext *c, AVIOContext *pb, MOVAtom atom) +{ + AVStream *st; + MOVStreamContext *sc; + unsigned int version, pattern, is_protected, iv_size; + + if (c->fc->nb_streams < 1) + return 0; + st = c->fc->streams[c->fc->nb_streams-1]; + sc = st->priv_data; + + if (sc->pseudo_stream_id != 0) { + av_log(c->fc, AV_LOG_ERROR, "tenc atom are only supported in first sample descriptor\n"); + return AVERROR_PATCHWELCOME; + } + + if (!sc->cenc.default_encrypted_sample) { + sc->cenc.default_encrypted_sample = av_encryption_info_alloc(0, 16, 16); + if (!sc->cenc.default_encrypted_sample) { + return AVERROR(ENOMEM); + } + } + + if (atom.size < 20) + return AVERROR_INVALIDDATA; + + version = avio_r8(pb); /* version */ + avio_rb24(pb); /* flags */ + + avio_r8(pb); /* reserved */ + pattern = avio_r8(pb); + + if (version > 0) { + sc->cenc.default_encrypted_sample->crypt_byte_block = pattern >> 4; + sc->cenc.default_encrypted_sample->skip_byte_block = pattern & 0xf; + } + + is_protected = avio_r8(pb); + if (is_protected && !sc->cenc.encryption_index) { + // The whole stream should be by-default encrypted. + sc->cenc.encryption_index = av_mallocz(sizeof(MOVEncryptionIndex)); + if (!sc->cenc.encryption_index) + return AVERROR(ENOMEM); + } + sc->cenc.per_sample_iv_size = avio_r8(pb); + if (sc->cenc.per_sample_iv_size != 0 && sc->cenc.per_sample_iv_size != 8 && + sc->cenc.per_sample_iv_size != 16) { + av_log(c->fc, AV_LOG_ERROR, "invalid per-sample IV size value\n"); + return AVERROR_INVALIDDATA; + } + if (avio_read(pb, sc->cenc.default_encrypted_sample->key_id, 16) != 16) { + av_log(c->fc, AV_LOG_ERROR, "failed to read the default key ID\n"); + return AVERROR_INVALIDDATA; + } + + if (is_protected && !sc->cenc.per_sample_iv_size) { + iv_size = avio_r8(pb); + if (iv_size != 8 && iv_size != 16) { + av_log(c->fc, AV_LOG_ERROR, "invalid default_constant_IV_size in tenc atom\n"); + return AVERROR_INVALIDDATA; + } + + if (avio_read(pb, sc->cenc.default_encrypted_sample->iv, iv_size) != iv_size) { + av_log(c->fc, AV_LOG_ERROR, "failed to read the default IV\n"); + return AVERROR_INVALIDDATA; + } + } + return 0; } @@ -5956,108 +6515,123 @@ static int mov_read_dfla(MOVContext *c, AVIOContext *pb, MOVAtom atom) return 0; } -static int mov_seek_auxiliary_info(MOVContext *c, MOVStreamContext *sc, int64_t index) +static int cenc_decrypt(MOVContext *c, MOVStreamContext *sc, AVEncryptionInfo *sample, uint8_t *input, int size) { - size_t auxiliary_info_seek_offset = 0; - int i; + int i, ret; - if (sc->cenc.auxiliary_info_default_size) { - auxiliary_info_seek_offset = (size_t)sc->cenc.auxiliary_info_default_size * index; - } else if (sc->cenc.auxiliary_info_sizes) { - if (index > sc->cenc.auxiliary_info_sizes_count) { - av_log(c, AV_LOG_ERROR, "current sample %"PRId64" greater than the number of auxiliary info sample sizes %"SIZE_SPECIFIER"\n", - index, sc->cenc.auxiliary_info_sizes_count); - return AVERROR_INVALIDDATA; - } - - for (i = 0; i < index; i++) { - auxiliary_info_seek_offset += sc->cenc.auxiliary_info_sizes[i]; - } + if (sample->scheme != MKBETAG('c','e','n','c') || sample->crypt_byte_block != 0 || sample->skip_byte_block != 0) { + av_log(c->fc, AV_LOG_ERROR, "Only the 'cenc' encryption scheme is supported\n"); + return AVERROR_PATCHWELCOME; } - if (auxiliary_info_seek_offset > sc->cenc.auxiliary_info_end - sc->cenc.auxiliary_info) { - av_log(c, AV_LOG_ERROR, "auxiliary info offset %"SIZE_SPECIFIER" greater than auxiliary info size %"SIZE_SPECIFIER"\n", - auxiliary_info_seek_offset, (size_t)(sc->cenc.auxiliary_info_end - sc->cenc.auxiliary_info)); - return AVERROR_INVALIDDATA; - } + if (!sc->cenc.aes_ctr) { + /* initialize the cipher */ + sc->cenc.aes_ctr = av_aes_ctr_alloc(); + if (!sc->cenc.aes_ctr) { + return AVERROR(ENOMEM); + } - sc->cenc.auxiliary_info_pos = sc->cenc.auxiliary_info + auxiliary_info_seek_offset; - sc->cenc.auxiliary_info_index = index; - return 0; -} - -static int cenc_filter(MOVContext *c, MOVStreamContext *sc, int64_t index, uint8_t *input, int size) -{ - uint32_t encrypted_bytes; - uint16_t subsample_count; - uint16_t clear_bytes; - uint8_t* input_end = input + size; - int ret; - - if (index != sc->cenc.auxiliary_info_index) { - ret = mov_seek_auxiliary_info(c, sc, index); + ret = av_aes_ctr_init(sc->cenc.aes_ctr, c->decryption_key); if (ret < 0) { return ret; } } - /* read the iv */ - if (AES_CTR_IV_SIZE > sc->cenc.auxiliary_info_end - sc->cenc.auxiliary_info_pos) { - av_log(c->fc, AV_LOG_ERROR, "failed to read iv from the auxiliary info\n"); - return AVERROR_INVALIDDATA; - } + av_aes_ctr_set_full_iv(sc->cenc.aes_ctr, sample->iv); - av_aes_ctr_set_iv(sc->cenc.aes_ctr, sc->cenc.auxiliary_info_pos); - sc->cenc.auxiliary_info_pos += AES_CTR_IV_SIZE; - - if (!sc->cenc.use_subsamples) + if (!sample->subsample_count) { /* decrypt the whole packet */ av_aes_ctr_crypt(sc->cenc.aes_ctr, input, input, size); return 0; } - /* read the subsample count */ - if (sizeof(uint16_t) > sc->cenc.auxiliary_info_end - sc->cenc.auxiliary_info_pos) { - av_log(c->fc, AV_LOG_ERROR, "failed to read subsample count from the auxiliary info\n"); - return AVERROR_INVALIDDATA; - } - - subsample_count = AV_RB16(sc->cenc.auxiliary_info_pos); - sc->cenc.auxiliary_info_pos += sizeof(uint16_t); - - for (; subsample_count > 0; subsample_count--) + for (i = 0; i < sample->subsample_count; i++) { - if (6 > sc->cenc.auxiliary_info_end - sc->cenc.auxiliary_info_pos) { - av_log(c->fc, AV_LOG_ERROR, "failed to read subsample from the auxiliary info\n"); - return AVERROR_INVALIDDATA; - } - - /* read the number of clear / encrypted bytes */ - clear_bytes = AV_RB16(sc->cenc.auxiliary_info_pos); - sc->cenc.auxiliary_info_pos += sizeof(uint16_t); - encrypted_bytes = AV_RB32(sc->cenc.auxiliary_info_pos); - sc->cenc.auxiliary_info_pos += sizeof(uint32_t); - - if ((uint64_t)clear_bytes + encrypted_bytes > input_end - input) { + if (sample->subsamples[i].bytes_of_clear_data + sample->subsamples[i].bytes_of_protected_data > size) { av_log(c->fc, AV_LOG_ERROR, "subsample size exceeds the packet size left\n"); return AVERROR_INVALIDDATA; } /* skip the clear bytes */ - input += clear_bytes; + input += sample->subsamples[i].bytes_of_clear_data; + size -= sample->subsamples[i].bytes_of_clear_data; /* decrypt the encrypted bytes */ - av_aes_ctr_crypt(sc->cenc.aes_ctr, input, input, encrypted_bytes); - input += encrypted_bytes; + av_aes_ctr_crypt(sc->cenc.aes_ctr, input, input, sample->subsamples[i].bytes_of_protected_data); + input += sample->subsamples[i].bytes_of_protected_data; + size -= sample->subsamples[i].bytes_of_protected_data; } - if (input < input_end) { + if (size > 0) { av_log(c->fc, AV_LOG_ERROR, "leftover packet bytes after subsample processing\n"); return AVERROR_INVALIDDATA; } - sc->cenc.auxiliary_info_index++; + return 0; +} + +static int cenc_filter(MOVContext *mov, AVStream* st, MOVStreamContext *sc, AVPacket *pkt, int current_index) +{ + MOVFragmentStreamInfo *frag_stream_info; + MOVEncryptionIndex *encryption_index; + AVEncryptionInfo *encrypted_sample; + int encrypted_index, ret; + + frag_stream_info = get_frag_stream_info(&mov->frag_index, mov->frag_index.current, st->id); + encrypted_index = current_index; + encryption_index = NULL; + if (frag_stream_info) { + // Note this only supports encryption info in the first sample descriptor. + if (mov->fragment.stsd_id == 1) { + if (frag_stream_info->encryption_index) { + encrypted_index = current_index - frag_stream_info->index_entry; + encryption_index = frag_stream_info->encryption_index; + } else { + encryption_index = sc->cenc.encryption_index; + } + } + } else { + encryption_index = sc->cenc.encryption_index; + } + + if (encryption_index) { + if (encryption_index->auxiliary_info_sample_count && + !encryption_index->nb_encrypted_samples) { + av_log(mov->fc, AV_LOG_ERROR, "saiz atom found without saio\n"); + return AVERROR_INVALIDDATA; + } + if (encryption_index->auxiliary_offsets_count && + !encryption_index->nb_encrypted_samples) { + av_log(mov->fc, AV_LOG_ERROR, "saio atom found without saiz\n"); + return AVERROR_INVALIDDATA; + } + + if (!encryption_index->nb_encrypted_samples) { + // Full-sample encryption with default settings. + encrypted_sample = sc->cenc.default_encrypted_sample; + } else if (encrypted_index >= 0 && encrypted_index < encryption_index->nb_encrypted_samples) { + // Per-sample setting override. + encrypted_sample = encryption_index->encrypted_samples[encrypted_index]; + } else { + av_log(mov->fc, AV_LOG_ERROR, "Incorrect number of samples in encryption info\n"); + return AVERROR_INVALIDDATA; + } + + if (mov->decryption_key) { + return cenc_decrypt(mov, sc, encrypted_sample, pkt->data, pkt->size); + } else { + size_t size; + uint8_t *side_data = av_encryption_info_add_side_data(encrypted_sample, &size); + if (!side_data) + return AVERROR(ENOMEM); + ret = av_packet_add_side_data(pkt, AV_PKT_DATA_ENCRYPTION_INFO, side_data, size); + if (ret < 0) + av_free(side_data); + return ret; + } + } + return 0; } @@ -6066,7 +6640,7 @@ static int mov_read_dops(MOVContext *c, AVIOContext *pb, MOVAtom atom) const int OPUS_SEEK_PREROLL_MS = 80; AVStream *st; size_t size; - int16_t pre_skip; + uint16_t pre_skip; if (c->fc->nb_streams < 1) return 0; @@ -6115,6 +6689,7 @@ static const MOVParseTableEntry mov_default_parse_table[] = { { MKTAG('A','A','L','P'), mov_read_avid }, { MKTAG('A','R','E','S'), mov_read_ares }, { MKTAG('a','v','s','s'), mov_read_avss }, +{ MKTAG('a','v','1','C'), mov_read_av1c }, { MKTAG('c','h','p','l'), mov_read_chpl }, { MKTAG('c','o','6','4'), mov_read_stco }, { MKTAG('c','o','l','r'), mov_read_colr }, @@ -6187,6 +6762,11 @@ static const MOVParseTableEntry mov_default_parse_table[] = { { MKTAG('f','r','m','a'), mov_read_frma }, { MKTAG('s','e','n','c'), mov_read_senc }, { MKTAG('s','a','i','z'), mov_read_saiz }, +{ MKTAG('s','a','i','o'), mov_read_saio }, +{ MKTAG('p','s','s','h'), mov_read_pssh }, +{ MKTAG('s','c','h','m'), mov_read_schm }, +{ MKTAG('s','c','h','i'), mov_read_default }, +{ MKTAG('t','e','n','c'), mov_read_tenc }, { MKTAG('d','f','L','a'), mov_read_dfla }, { MKTAG('s','t','3','d'), mov_read_st3d }, /* stereoscopic 3D video box */ { MKTAG('s','v','3','d'), mov_read_sv3d }, /* spherical video box */ @@ -6320,7 +6900,7 @@ static int mov_read_default(MOVContext *c, AVIOContext *pb, MOVAtom atom) return 0; } -static int mov_probe(AVProbeData *p) +static int mov_probe(const AVProbeData *p) { int64_t offset; uint32_t tag; @@ -6572,6 +7152,18 @@ static int mov_read_timecode_track(AVFormatContext *s, AVStream *st) return 0; } +static void mov_free_encryption_index(MOVEncryptionIndex **index) { + int i; + if (!index || !*index) return; + for (i = 0; i < (*index)->nb_encrypted_samples; i++) { + av_encryption_info_free((*index)->encrypted_samples[i]); + } + av_freep(&(*index)->encrypted_samples); + av_freep(&(*index)->auxiliary_info_sizes); + av_freep(&(*index)->auxiliary_offsets); + av_freep(index); +} + static int mov_read_close(AVFormatContext *s) { MOVContext *mov = s->priv_data; @@ -6614,8 +7206,8 @@ static int mov_read_close(AVFormatContext *s) av_freep(&sc->extradata); av_freep(&sc->extradata_size); - av_freep(&sc->cenc.auxiliary_info); - av_freep(&sc->cenc.auxiliary_info_sizes); + mov_free_encryption_index(&sc->cenc.encryption_index); + av_encryption_info_free(sc->cenc.default_encrypted_sample); av_aes_ctr_free(sc->cenc.aes_ctr); av_freep(&sc->stereo3d); @@ -6640,6 +7232,10 @@ static int mov_read_close(AVFormatContext *s) av_freep(&mov->bitrates); for (i = 0; i < mov->frag_index.nb_items; i++) { + MOVFragmentStreamInfo *frag = mov->frag_index.item[i].stream_info; + for (j = 0; j < mov->frag_index.item[i].nb_stream_info; j++) { + mov_free_encryption_index(&frag[j].encryption_index); + } av_freep(&mov->frag_index.item[i].stream_info); } av_freep(&mov->frag_index.item); @@ -7212,12 +7808,9 @@ static int mov_read_packet(AVFormatContext *s, AVPacket *pkt) if (mov->aax_mode) aax_filter(pkt->data, pkt->size, mov); - if (sc->cenc.aes_ctr) { - ret = cenc_filter(mov, sc, current_index, pkt->data, pkt->size); - if (ret) { - return ret; - } - } + ret = cenc_filter(mov, st, sc, pkt, current_index); + if (ret < 0) + return ret; return 0; } @@ -7278,6 +7871,7 @@ static int mov_seek_stream(AVFormatContext *s, AVStream *st, int64_t timestamp, } /* adjust stsd index */ + if (sc->chunk_count) { time_sample = 0; for (i = 0; i < sc->stsc_count; i++) { int64_t next = time_sample + mov_get_stsc_samples(sc, i); @@ -7289,6 +7883,7 @@ static int mov_seek_stream(AVFormatContext *s, AVStream *st, int64_t timestamp, av_assert0(next == (int)next); time_sample = next; } + } return sample; } @@ -7410,5 +8005,5 @@ AVInputFormat ff_mov_demuxer = { .read_packet = mov_read_packet, .read_close = mov_read_close, .read_seek = mov_read_seek, - .flags = AVFMT_NO_BYTE_SEEK, + .flags = AVFMT_NO_BYTE_SEEK | AVFMT_SEEK_TO_PTS, }; diff --git a/libavformat/movenc.c b/libavformat/movenc.c index 415637d46..a96139077 100644 --- a/libavformat/movenc.c +++ b/libavformat/movenc.c @@ -30,6 +30,7 @@ #include "riff.h" #include "avio.h" #include "isom.h" +#include "av1.h" #include "avc.h" #include "libavcodec/ac3_parser_internal.h" #include "libavcodec/dnxhddata.h" @@ -74,6 +75,7 @@ static const AVOption options[] = { { "frag_discont", "Signal that the next fragment is discontinuous from earlier ones", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_FRAG_DISCONT}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "movflags" }, { "delay_moov", "Delay writing the initial moov until the first fragment is cut, or until the first fragment flush", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_DELAY_MOOV}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "movflags" }, { "global_sidx", "Write a global sidx index at the start of the file", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_GLOBAL_SIDX}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "movflags" }, + { "skip_sidx", "Skip writing of sidx atom", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_SKIP_SIDX}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "movflags" }, { "write_colr", "Write colr atom (Experimental, may be renamed or changed, do not use from scripts)", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_WRITE_COLR}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "movflags" }, { "write_gama", "Write deprecated gama atom", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_WRITE_GAMA}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "movflags" }, { "use_metadata_tags", "Use mdta atom for metadata.", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_USE_MDTA}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "movflags" }, @@ -98,6 +100,10 @@ static const AVOption options[] = { { "encryption_kid", "The media encryption key identifier (hex)", offsetof(MOVMuxContext, encryption_kid), AV_OPT_TYPE_BINARY, .flags = AV_OPT_FLAG_ENCODING_PARAM }, { "use_stream_ids_as_track_ids", "use stream ids as track ids", offsetof(MOVMuxContext, use_stream_ids_as_track_ids), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, AV_OPT_FLAG_ENCODING_PARAM}, { "write_tmcd", "force or disable writing tmcd", offsetof(MOVMuxContext, write_tmcd), AV_OPT_TYPE_BOOL, {.i64 = -1}, -1, 1, AV_OPT_FLAG_ENCODING_PARAM}, + { "write_prft", "Write producer reference time box with specified time source", offsetof(MOVMuxContext, write_prft), AV_OPT_TYPE_INT, {.i64 = MOV_PRFT_NONE}, 0, MOV_PRFT_NB-1, AV_OPT_FLAG_ENCODING_PARAM, "prft"}, + { "wallclock", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = MOV_PRFT_SRC_WALLCLOCK}, 0, 0, AV_OPT_FLAG_ENCODING_PARAM, "prft"}, + { "pts", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = MOV_PRFT_SRC_PTS}, 0, 0, AV_OPT_FLAG_ENCODING_PARAM, "prft"}, + { "empty_hdlr_name", "write zero-length name string in hdlr atoms within mdia and minf atoms", offsetof(MOVMuxContext, empty_hdlr_name), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, AV_OPT_FLAG_ENCODING_PARAM}, { NULL }, }; @@ -307,15 +313,19 @@ static int mov_write_amr_tag(AVIOContext *pb, MOVTrack *track) return 0x11; } -static int mov_write_ac3_tag(AVIOContext *pb, MOVTrack *track) +static int mov_write_ac3_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track) { GetBitContext gbc; PutBitContext pbc; uint8_t buf[3]; int fscod, bsid, bsmod, acmod, lfeon, frmsizecod; - if (track->vos_len < 7) - return -1; + if (track->vos_len < 7) { + av_log(s, AV_LOG_ERROR, + "Cannot write moov atom before AC3 packets." + " Set the delay_moov flag to fix this.\n"); + return AVERROR(EINVAL); + } avio_wb32(pb, 11); ffio_wfourcc(pb, "dac3"); @@ -525,22 +535,24 @@ end: } #endif -static int mov_write_eac3_tag(AVIOContext *pb, MOVTrack *track) +static int mov_write_eac3_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track) { PutBitContext pbc; uint8_t *buf; struct eac3_info *info; int size, i; - if (!track->eac3_priv) + if (!track->eac3_priv) { + av_log(s, AV_LOG_ERROR, + "Cannot write moov atom before EAC3 packets parsed.\n"); return AVERROR(EINVAL); + } info = track->eac3_priv; - size = 2 + 4 * (info->num_ind_sub + 1); + size = 2 + ((34 * (info->num_ind_sub + 1) + 7) >> 3); buf = av_malloc(size); if (!buf) { - size = AVERROR(ENOMEM); - goto end; + return AVERROR(ENOMEM); } init_put_bits(&pbc, buf, size); @@ -558,12 +570,12 @@ static int mov_write_eac3_tag(AVIOContext *pb, MOVTrack *track) put_bits(&pbc, 4, info->substream[i].num_dep_sub); if (!info->substream[i].num_dep_sub) { put_bits(&pbc, 1, 0); /* reserved */ - size--; } else { put_bits(&pbc, 9, info->substream[i].chan_loc); } } flush_put_bits(&pbc); + size = put_bits_count(&pbc) >> 3; avio_wb32(pb, size + 8); ffio_wfourcc(pb, "dec3"); @@ -571,10 +583,6 @@ static int mov_write_eac3_tag(AVIOContext *pb, MOVTrack *track) av_free(buf); -end: - av_packet_unref(&info->pkt); - av_freep(&track->eac3_priv); - return size; } @@ -740,14 +748,14 @@ static int mov_write_dfla_tag(AVIOContext *pb, MOVTrack *track) return update_size(pb, pos); } -static int mov_write_dops_tag(AVIOContext *pb, MOVTrack *track) +static int mov_write_dops_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track) { int64_t pos = avio_tell(pb); avio_wb32(pb, 0); ffio_wfourcc(pb, "dOps"); avio_w8(pb, 0); /* Version */ if (track->par->extradata_size < 19) { - av_log(pb, AV_LOG_ERROR, "invalid extradata size\n"); + av_log(s, AV_LOG_ERROR, "invalid extradata size\n"); return AVERROR_INVALIDDATA; } /* extradata contains an Ogg OpusHead, other than byte-ordering and @@ -817,9 +825,9 @@ static int mov_write_wave_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *tra } else if (track->par->codec_id == AV_CODEC_ID_AMR_NB) { mov_write_amr_tag(pb, track); } else if (track->par->codec_id == AV_CODEC_ID_AC3) { - mov_write_ac3_tag(pb, track); + mov_write_ac3_tag(s, pb, track); } else if (track->par->codec_id == AV_CODEC_ID_EAC3) { - mov_write_eac3_tag(pb, track); + mov_write_eac3_tag(s, pb, track); } else if (track->par->codec_id == AV_CODEC_ID_ALAC || track->par->codec_id == AV_CODEC_ID_QDM2) { mov_write_extradata_tag(pb, track); @@ -1016,6 +1024,7 @@ static int mov_write_audio_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContex int64_t pos = avio_tell(pb); int version = 0; uint32_t tag = track->tag; + int ret = 0; if (track->mode == MODE_MOV) { if (track->timescale > UINT16_MAX || !track->par->channels) { @@ -1073,12 +1082,14 @@ static int mov_write_audio_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContex avio_wb16(pb, track->audio_vbr ? -2 : 0); /* compression ID */ } else { /* reserved for mp4/3gp */ if (track->par->codec_id == AV_CODEC_ID_FLAC || + track->par->codec_id == AV_CODEC_ID_ALAC || track->par->codec_id == AV_CODEC_ID_OPUS) { avio_wb16(pb, track->par->channels); } else { avio_wb16(pb, 2); } - if (track->par->codec_id == AV_CODEC_ID_FLAC) { + if (track->par->codec_id == AV_CODEC_ID_FLAC || + track->par->codec_id == AV_CODEC_ID_ALAC) { avio_wb16(pb, track->par->bits_per_raw_sample); } else { avio_wb16(pb, 16); @@ -1117,34 +1128,41 @@ static int mov_write_audio_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContex track->par->codec_id == AV_CODEC_ID_QDM2 || (mov_pcm_le_gt16(track->par->codec_id) && version==1) || (mov_pcm_be_gt16(track->par->codec_id) && version==1))) - mov_write_wave_tag(s, pb, track); + ret = mov_write_wave_tag(s, pb, track); else if (track->tag == MKTAG('m','p','4','a')) - mov_write_esds_tag(pb, track); + ret = mov_write_esds_tag(pb, track); else if (track->par->codec_id == AV_CODEC_ID_AMR_NB) - mov_write_amr_tag(pb, track); + ret = mov_write_amr_tag(pb, track); else if (track->par->codec_id == AV_CODEC_ID_AC3) - mov_write_ac3_tag(pb, track); + ret = mov_write_ac3_tag(s, pb, track); else if (track->par->codec_id == AV_CODEC_ID_EAC3) - mov_write_eac3_tag(pb, track); + ret = mov_write_eac3_tag(s, pb, track); else if (track->par->codec_id == AV_CODEC_ID_ALAC) - mov_write_extradata_tag(pb, track); + ret = mov_write_extradata_tag(pb, track); else if (track->par->codec_id == AV_CODEC_ID_WMAPRO) - mov_write_wfex_tag(s, pb, track); + ret = mov_write_wfex_tag(s, pb, track); else if (track->par->codec_id == AV_CODEC_ID_FLAC) - mov_write_dfla_tag(pb, track); + ret = mov_write_dfla_tag(pb, track); else if (track->par->codec_id == AV_CODEC_ID_OPUS) - mov_write_dops_tag(pb, track); + ret = mov_write_dops_tag(s, pb, track); else if (track->vos_len > 0) - mov_write_glbl_tag(pb, track); + ret = mov_write_glbl_tag(pb, track); - if (track->mode == MODE_MOV && track->par->codec_type == AVMEDIA_TYPE_AUDIO) - mov_write_chan_tag(s, pb, track); + if (ret < 0) + return ret; - if (mov->encryption_scheme != MOV_ENC_NONE) { - ff_mov_cenc_write_sinf_tag(track, pb, mov->encryption_kid); + if (track->mode == MODE_MOV && track->par->codec_type == AVMEDIA_TYPE_AUDIO + && ((ret = mov_write_chan_tag(s, pb, track)) < 0)) { + return ret; } - return update_size(pb, pos); + if (mov->encryption_scheme != MOV_ENC_NONE + && ((ret = ff_mov_cenc_write_sinf_tag(track, pb, mov->encryption_kid)) < 0)) { + return ret; + } + + ret = update_size(pb, pos); + return ret; } static int mov_write_d263_tag(AVIOContext *pb) @@ -1159,6 +1177,16 @@ static int mov_write_d263_tag(AVIOContext *pb) return 0xf; } +static int mov_write_av1c_tag(AVIOContext *pb, MOVTrack *track) +{ + int64_t pos = avio_tell(pb); + + avio_wb32(pb, 0); + ffio_wfourcc(pb, "av1C"); + ff_isom_write_av1c(pb, track->vos_data, track->vos_len); + return update_size(pb, pos); +} + static int mov_write_avcc_tag(AVIOContext *pb, MOVTrack *track) { int64_t pos = avio_tell(pb); @@ -1520,9 +1548,9 @@ static int mov_get_rawvideo_codec_tag(AVFormatContext *s, MOVTrack *track) return tag; } -static int mov_get_codec_tag(AVFormatContext *s, MOVTrack *track) +static unsigned int mov_get_codec_tag(AVFormatContext *s, MOVTrack *track) { - int tag = track->par->codec_tag; + unsigned int tag = track->par->codec_tag; if (!tag || (s->strict_std_compliance >= FF_COMPLIANCE_NORMAL && (track->par->codec_id == AV_CODEC_ID_DVVIDEO || @@ -1574,32 +1602,43 @@ static const AVCodecTag codec_cover_image_tags[] = { { AV_CODEC_ID_NONE, 0 }, }; -static int mov_find_codec_tag(AVFormatContext *s, MOVTrack *track) +static unsigned int validate_codec_tag(const AVCodecTag *const *tags, + unsigned int tag, int codec_id) { - int tag; + int i; + /** + * Check that tag + id is in the table + */ + for (i = 0; tags && tags[i]; i++) { + const AVCodecTag *codec_tags = tags[i]; + while (codec_tags->id != AV_CODEC_ID_NONE) { + if (avpriv_toupper4(codec_tags->tag) == avpriv_toupper4(tag) && + codec_tags->id == codec_id) + return codec_tags->tag; + codec_tags++; + } + } + return 0; +} + +static unsigned int mov_find_codec_tag(AVFormatContext *s, MOVTrack *track) +{ if (is_cover_image(track->st)) return ff_codec_get_tag(codec_cover_image_tags, track->par->codec_id); - if (track->mode == MODE_MP4 || track->mode == MODE_PSP) - tag = track->par->codec_tag; - else if (track->mode == MODE_ISM) - tag = track->par->codec_tag; - else if (track->mode == MODE_IPOD) { + if (track->mode == MODE_IPOD) if (!av_match_ext(s->url, "m4a") && !av_match_ext(s->url, "m4v") && !av_match_ext(s->url, "m4b")) av_log(s, AV_LOG_WARNING, "Warning, extension is not .m4a nor .m4v " "Quicktime/Ipod might not play the file\n"); - tag = track->par->codec_tag; - } else if (track->mode & MODE_3GP) - tag = track->par->codec_tag; - else if (track->mode == MODE_F4V) - tag = track->par->codec_tag; - else - tag = mov_get_codec_tag(s, track); - return tag; + if (track->mode == MODE_MOV) { + return mov_get_codec_tag(s, track); + } else + return validate_codec_tag(s->oformat->codec_tag, track->par->codec_tag, + track->par->codec_id); } /** Write uuid atom. @@ -1652,12 +1691,12 @@ static int mov_write_subtitle_tag(AVIOContext *pb, MOVTrack *track) return update_size(pb, pos); } -static int mov_write_st3d_tag(AVIOContext *pb, AVStereo3D *stereo_3d) +static int mov_write_st3d_tag(AVFormatContext *s, AVIOContext *pb, AVStereo3D *stereo_3d) { int8_t stereo_mode; if (stereo_3d->flags != 0) { - av_log(pb, AV_LOG_WARNING, "Unsupported stereo_3d flags %x. st3d not written.\n", stereo_3d->flags); + av_log(s, AV_LOG_WARNING, "Unsupported stereo_3d flags %x. st3d not written.\n", stereo_3d->flags); return 0; } @@ -1672,7 +1711,7 @@ static int mov_write_st3d_tag(AVIOContext *pb, AVStereo3D *stereo_3d) stereo_mode = 2; break; default: - av_log(pb, AV_LOG_WARNING, "Unsupported stereo_3d type %s. st3d not written.\n", av_stereo3d_type_name(stereo_3d->type)); + av_log(s, AV_LOG_WARNING, "Unsupported stereo_3d type %s. st3d not written.\n", av_stereo3d_type_name(stereo_3d->type)); return 0; } avio_wb32(pb, 13); /* size */ @@ -1690,7 +1729,7 @@ static int mov_write_sv3d_tag(AVFormatContext *s, AVIOContext *pb, AVSphericalMa if (spherical_mapping->projection != AV_SPHERICAL_EQUIRECTANGULAR && spherical_mapping->projection != AV_SPHERICAL_EQUIRECTANGULAR_TILE && spherical_mapping->projection != AV_SPHERICAL_CUBEMAP) { - av_log(pb, AV_LOG_WARNING, "Unsupported projection %d. sv3d not written.\n", spherical_mapping->projection); + av_log(s, AV_LOG_WARNING, "Unsupported projection %d. sv3d not written.\n", spherical_mapping->projection); return 0; } @@ -1768,27 +1807,25 @@ static int mov_write_pasp_tag(AVIOContext *pb, MOVTrack *track) return 16; } -static int mov_write_gama_tag(AVIOContext *pb, MOVTrack *track, double gamma) +static int mov_write_gama_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track, double gamma) { uint32_t gama = 0; - if (gamma <= 0.0) - { + if (gamma <= 0.0) { gamma = avpriv_get_gamma_from_trc(track->par->color_trc); } - av_log(pb, AV_LOG_DEBUG, "gamma value %g\n", gamma); + av_log(s, AV_LOG_DEBUG, "gamma value %g\n", gamma); if (gamma > 1e-6) { gama = (uint32_t)lrint((double)(1<<16) * gamma); - av_log(pb, AV_LOG_DEBUG, "writing gama value %"PRId32"\n", gama); + av_log(s, AV_LOG_DEBUG, "writing gama value %"PRId32"\n", gama); av_assert0(track->mode == MODE_MOV); avio_wb32(pb, 12); ffio_wfourcc(pb, "gama"); avio_wb32(pb, gama); return 12; - } - else { - av_log(pb, AV_LOG_WARNING, "gamma value unknown, unable to write gama atom\n"); + } else { + av_log(s, AV_LOG_WARNING, "gamma value unknown, unable to write gama atom\n"); } return 0; } @@ -1902,7 +1939,7 @@ static void find_compressor(char * compressor_name, int len, MOVTrack *track) } } -static int mov_write_video_tag(AVIOContext *pb, MOVMuxContext *mov, MOVTrack *track) +static int mov_write_video_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContext *mov, MOVTrack *track) { int64_t pos = avio_tell(pb); char compressor_name[32] = { 0 }; @@ -2005,6 +2042,8 @@ static int mov_write_video_tag(AVIOContext *pb, MOVMuxContext *mov, MOVTrack *tr mov_write_uuid_tag_ipod(pb); } else if (track->par->codec_id == AV_CODEC_ID_VP9) { mov_write_vpcc_tag(mov->fc, pb, track); + } else if (track->par->codec_id == AV_CODEC_ID_AV1) { + mov_write_av1c_tag(pb, track); } else if (track->par->codec_id == AV_CODEC_ID_VC1 && track->vos_len > 0) mov_write_dvc1_tag(pb, track); else if (track->par->codec_id == AV_CODEC_ID_VP6F || @@ -2035,7 +2074,7 @@ static int mov_write_video_tag(AVIOContext *pb, MOVMuxContext *mov, MOVTrack *tr if (mov->flags & FF_MOV_FLAG_WRITE_GAMA) { if (track->mode == MODE_MOV) - mov_write_gama_tag(pb, track, mov->gamma); + mov_write_gama_tag(s, pb, track, mov->gamma); else av_log(mov->fc, AV_LOG_WARNING, "Not writing 'gama' atom. Format is not MOV.\n"); } @@ -2051,7 +2090,7 @@ static int mov_write_video_tag(AVIOContext *pb, MOVMuxContext *mov, MOVTrack *tr AVSphericalMapping* spherical_mapping = (AVSphericalMapping*)av_stream_get_side_data(track->st, AV_PKT_DATA_SPHERICAL, NULL); if (stereo_3d) - mov_write_st3d_tag(pb, stereo_3d); + mov_write_st3d_tag(s, pb, stereo_3d); if (spherical_mapping) mov_write_sv3d_tag(mov->fc, pb, spherical_mapping); } @@ -2186,22 +2225,27 @@ static int mov_write_gpmd_tag(AVIOContext *pb, const MOVTrack *track) static int mov_write_stsd_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContext *mov, MOVTrack *track) { int64_t pos = avio_tell(pb); + int ret = 0; avio_wb32(pb, 0); /* size */ ffio_wfourcc(pb, "stsd"); avio_wb32(pb, 0); /* version & flags */ avio_wb32(pb, 1); /* entry count */ if (track->par->codec_type == AVMEDIA_TYPE_VIDEO) - mov_write_video_tag(pb, mov, track); + ret = mov_write_video_tag(s, pb, mov, track); else if (track->par->codec_type == AVMEDIA_TYPE_AUDIO) - mov_write_audio_tag(s, pb, mov, track); + ret = mov_write_audio_tag(s, pb, mov, track); else if (track->par->codec_type == AVMEDIA_TYPE_SUBTITLE) - mov_write_subtitle_tag(pb, track); + ret = mov_write_subtitle_tag(pb, track); else if (track->par->codec_tag == MKTAG('r','t','p',' ')) - mov_write_rtp_tag(pb, track); + ret = mov_write_rtp_tag(pb, track); else if (track->par->codec_tag == MKTAG('t','m','c','d')) - mov_write_tmcd_tag(pb, track); + ret = mov_write_tmcd_tag(pb, track); else if (track->par->codec_tag == MKTAG('g','p','m','d')) - mov_write_gpmd_tag(pb, track); + ret = mov_write_gpmd_tag(pb, track); + + if (ret < 0) + return ret; + return update_size(pb, pos); } @@ -2348,9 +2392,9 @@ static int mov_preroll_write_stbl_atoms(AVIOContext *pb, MOVTrack *track) decoded. */ if (roll_samples_remaining > 0) distance = 0; - /* Verify distance is a minimum of 2 (60ms) packets and a maximum of - 32 (2.5ms) packets. */ - av_assert0(distance == 0 || (distance >= 2 && distance <= 32)); + /* Verify distance is a maximum of 32 (2.5ms) packets. */ + if (distance > 32) + return AVERROR_INVALIDDATA; if (i && distance == sgpd_entries[entries].roll_distance) { sgpd_entries[entries].count++; } else { @@ -2404,11 +2448,12 @@ static int mov_preroll_write_stbl_atoms(AVIOContext *pb, MOVTrack *track) static int mov_write_stbl_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContext *mov, MOVTrack *track) { int64_t pos = avio_tell(pb); - int ret; + int ret = 0; avio_wb32(pb, 0); /* size */ ffio_wfourcc(pb, "stbl"); - mov_write_stsd_tag(s, pb, mov, track); + if ((ret = mov_write_stsd_tag(s, pb, mov, track)) < 0) + return ret; mov_write_stts_tag(pb, track); if ((track->par->codec_type == AVMEDIA_TYPE_VIDEO || track->par->codec_tag == MKTAG('r','t','p',' ')) && @@ -2554,6 +2599,7 @@ static int is_clcp_track(MOVTrack *track) static int mov_write_hdlr_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track) { + MOVMuxContext *mov = s->priv_data; const char *hdlr, *descr = NULL, *hdlr_type = NULL; int64_t pos = avio_tell(pb); @@ -2602,12 +2648,15 @@ static int mov_write_hdlr_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *tra // of the track. So if an alternate handler description is // specified, use it. AVDictionaryEntry *t; - t = av_dict_get(track->st->metadata, "handler", NULL, 0); + t = av_dict_get(track->st->metadata, "handler_name", NULL, 0); if (t && utf8len(t->value)) descr = t->value; } } + if (mov->empty_hdlr_name) /* expressly allowed by QTFF and not prohibited in ISO 14496-12 8.4.3.3 */ + descr = ""; + avio_wb32(pb, 0); /* size */ ffio_wfourcc(pb, "hdlr"); avio_wb32(pb, 0); /* Version & flags */ @@ -2666,7 +2715,7 @@ static int mov_write_minf_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContext } else if (track->tag == MKTAG('g','p','m','d')) { mov_write_gmhd_tag(pb, track); } - if (track->mode == MODE_MOV) /* FIXME: Why do it for MODE_MOV only ? */ + if (track->mode == MODE_MOV) /* ISO 14496-12 8.4.3.1 specifies hdlr only within mdia or meta boxes */ mov_write_hdlr_tag(s, pb, NULL); mov_write_dinf_tag(pb); if ((ret = mov_write_stbl_tag(s, pb, mov, track)) < 0) @@ -2706,8 +2755,8 @@ static int mov_write_mdhd_tag(AVIOContext *pb, MOVMuxContext *mov, if (version != 0 && track->mode == MODE_MOV) { av_log(NULL, AV_LOG_ERROR, "FATAL error, file duration too long for timebase, this file will not be\n" - "playable with quicktime. Choose a different timebase or a different\n" - "container format\n"); + "playable with QuickTime. Choose a different timebase with " + "-video_track_timescale or a different container format\n"); } return 32; @@ -4517,6 +4566,49 @@ static int mov_write_sidx_tags(AVIOContext *pb, MOVMuxContext *mov, return 0; } +static int mov_write_prft_tag(AVIOContext *pb, MOVMuxContext *mov, int tracks) +{ + int64_t pos = avio_tell(pb), pts_us, ntp_ts; + MOVTrack *first_track; + + /* PRFT should be associated with at most one track. So, choosing only the + * first track. */ + if (tracks > 0) + return 0; + first_track = &(mov->tracks[0]); + + if (!first_track->entry) { + av_log(mov->fc, AV_LOG_WARNING, "Unable to write PRFT, no entries in the track\n"); + return 0; + } + + if (first_track->cluster[0].pts == AV_NOPTS_VALUE) { + av_log(mov->fc, AV_LOG_WARNING, "Unable to write PRFT, first PTS is invalid\n"); + return 0; + } + + if (mov->write_prft == MOV_PRFT_SRC_WALLCLOCK) { + ntp_ts = ff_get_formatted_ntp_time(ff_ntp_time()); + } else if (mov->write_prft == MOV_PRFT_SRC_PTS) { + pts_us = av_rescale_q(first_track->cluster[0].pts, + first_track->st->time_base, AV_TIME_BASE_Q); + ntp_ts = ff_get_formatted_ntp_time(pts_us + NTP_OFFSET_US); + } else { + av_log(mov->fc, AV_LOG_WARNING, "Unsupported PRFT box configuration: %d\n", + mov->write_prft); + return 0; + } + + avio_wb32(pb, 0); // Size place holder + ffio_wfourcc(pb, "prft"); // Type + avio_w8(pb, 1); // Version + avio_wb24(pb, 0); // Flags + avio_wb32(pb, first_track->track_id); // reference track ID + avio_wb64(pb, ntp_ts); // NTP time stamp + avio_wb64(pb, first_track->cluster[0].pts); //media time + return update_size(pb, pos); +} + static int mov_write_moof_tag(AVIOContext *pb, MOVMuxContext *mov, int tracks, int64_t mdat_size) { @@ -4528,9 +4620,13 @@ static int mov_write_moof_tag(AVIOContext *pb, MOVMuxContext *mov, int tracks, mov_write_moof_tag_internal(avio_buf, mov, tracks, 0); moof_size = ffio_close_null_buf(avio_buf); - if (mov->flags & FF_MOV_FLAG_DASH && !(mov->flags & FF_MOV_FLAG_GLOBAL_SIDX)) + if (mov->flags & FF_MOV_FLAG_DASH && + !(mov->flags & (FF_MOV_FLAG_GLOBAL_SIDX | FF_MOV_FLAG_SKIP_SIDX))) mov_write_sidx_tags(pb, mov, tracks, moof_size + 8 + mdat_size); + if (mov->write_prft > MOV_PRFT_NONE && mov->write_prft < MOV_PRFT_NB) + mov_write_prft_tag(pb, mov, tracks); + if (mov->flags & FF_MOV_FLAG_GLOBAL_SIDX || !(mov->flags & FF_MOV_FLAG_SKIP_TRAILER) || mov->ism_lookahead) { @@ -5270,6 +5366,13 @@ int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt) } else { size = ff_hevc_annexb2mp4(pb, pkt->data, pkt->size, 0, NULL); } + } else if (par->codec_id == AV_CODEC_ID_AV1) { + if (trk->hint_track >= 0 && trk->hint_track < mov->nb_streams) { + ff_av1_filter_obus_buf(pkt->data, &reformatted_data, &size); + avio_write(pb, reformatted_data, size); + } else { + size = ff_av1_filter_obus(pb, pkt->data, pkt->size); + } #if CONFIG_AC3_PARSER } else if (par->codec_id == AV_CODEC_ID_EAC3) { size = handle_eac3(mov, pkt, trk); @@ -5324,6 +5427,7 @@ int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt) trk->cluster[trk->entry].size = size; trk->cluster[trk->entry].entries = samples_in_chunk; trk->cluster[trk->entry].dts = pkt->dts; + trk->cluster[trk->entry].pts = pkt->pts; if (!trk->entry && trk->start_dts != AV_NOPTS_VALUE) { if (!trk->frag_discont) { /* First packet of a new fragment. We already wrote the duration @@ -5336,7 +5440,8 @@ int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt) * the next fragment. This means the cts of the first sample must * be the same in all fragments, unless end_pts was updated by * the packet causing the fragment to be written. */ - if ((mov->flags & FF_MOV_FLAG_DASH && !(mov->flags & FF_MOV_FLAG_GLOBAL_SIDX)) || + if ((mov->flags & FF_MOV_FLAG_DASH && + !(mov->flags & (FF_MOV_FLAG_GLOBAL_SIDX | FF_MOV_FLAG_SKIP_SIDX))) || mov->mode == MODE_ISM) pkt->pts = pkt->dts + trk->end_pts - trk->cluster[trk->entry].dts; } else { @@ -5462,6 +5567,7 @@ static int mov_write_single_packet(AVFormatContext *s, AVPacket *pkt) if (trk->par->codec_id == AV_CODEC_ID_MP4ALS || trk->par->codec_id == AV_CODEC_ID_AAC || + trk->par->codec_id == AV_CODEC_ID_AV1 || trk->par->codec_id == AV_CODEC_ID_FLAC) { int side_size = 0; uint8_t *side = av_packet_get_side_data(pkt, AV_PKT_DATA_NEW_EXTRADATA, &side_size); @@ -5860,6 +5966,11 @@ static void mov_free(AVFormatContext *s) av_freep(&mov->tracks[i].frag_info); av_packet_unref(&mov->tracks[i].cover_image); + if (mov->tracks[i].eac3_priv) { + struct eac3_info *info = mov->tracks[i].eac3_priv; + av_packet_unref(&info->pkt); + av_freep(&mov->tracks[i].eac3_priv); + } if (mov->tracks[i].vos_len) av_freep(&mov->tracks[i].vos_data); @@ -5970,7 +6081,7 @@ static int mov_init(AVFormatContext *s) /* Set other implicit flags immediately */ if (mov->mode == MODE_ISM) mov->flags |= FF_MOV_FLAG_EMPTY_MOOV | FF_MOV_FLAG_SEPARATE_MOOF | - FF_MOV_FLAG_FRAGMENT; + FF_MOV_FLAG_FRAGMENT | FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS; if (mov->flags & FF_MOV_FLAG_DASH) mov->flags |= FF_MOV_FLAG_FRAGMENT | FF_MOV_FLAG_EMPTY_MOOV | FF_MOV_FLAG_DEFAULT_BASE_MOOF; @@ -5980,6 +6091,11 @@ static int mov_init(AVFormatContext *s) s->flags &= ~AVFMT_FLAG_AUTO_BSF; } + if (mov->flags & FF_MOV_FLAG_GLOBAL_SIDX && mov->flags & FF_MOV_FLAG_SKIP_SIDX) { + av_log(s, AV_LOG_WARNING, "Global SIDX enabled; Ignoring skip_sidx option\n"); + mov->flags &= ~FF_MOV_FLAG_SKIP_SIDX; + } + if (mov->flags & FF_MOV_FLAG_FASTSTART) { mov->reserved_moov_size = -1; } @@ -6103,7 +6219,7 @@ static int mov_init(AVFormatContext *s) track->par = st->codecpar; track->language = ff_mov_iso639_to_lang(lang?lang->value:"und", mov->mode!=MODE_MOV); if (track->language < 0) - track->language = 0; + track->language = 32767; // Unspecified Macintosh language code track->mode = mov->mode; track->tag = mov_find_codec_tag(s, track); if (!track->tag) { @@ -6159,15 +6275,12 @@ static int mov_init(AVFormatContext *s) pix_fmt == AV_PIX_FMT_MONOWHITE || pix_fmt == AV_PIX_FMT_MONOBLACK; } - if (track->par->codec_id == AV_CODEC_ID_VP9) { + if (track->par->codec_id == AV_CODEC_ID_VP9 || + track->par->codec_id == AV_CODEC_ID_AV1) { if (track->mode != MODE_MP4) { - av_log(s, AV_LOG_ERROR, "VP9 only supported in MP4.\n"); + av_log(s, AV_LOG_ERROR, "%s only supported in MP4.\n", avcodec_get_name(track->par->codec_id)); return AVERROR(EINVAL); } - } else if (track->par->codec_id == AV_CODEC_ID_AV1) { - /* spec is not finished, so forbid for now */ - av_log(s, AV_LOG_ERROR, "AV1 muxing is currently not supported.\n"); - return AVERROR_PATCHWELCOME; } else if (track->par->codec_id == AV_CODEC_ID_VP8) { /* altref frames handling is not defined in the spec as of version v1.0, * so just forbid muxing VP8 streams altogether until a new version does */ @@ -6266,7 +6379,7 @@ static int mov_write_header(AVFormatContext *s) nb_tracks++; } - if (mov->mode == MODE_MOV || mov->mode == MODE_MP4) + if (mov->nb_meta_tmcd) tmcd_track = nb_tracks; for (i = 0; i < s->nb_streams; i++) { @@ -6630,9 +6743,8 @@ static int mov_write_trailer(AVFormatContext *s) avio_seek(pb, mov->reserved_header_pos, SEEK_SET); mov_write_sidx_tags(pb, mov, -1, 0); avio_seek(pb, end, SEEK_SET); - avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_TRAILER); - mov_write_mfra_tag(pb, mov); - } else if (!(mov->flags & FF_MOV_FLAG_SKIP_TRAILER)) { + } + if (!(mov->flags & FF_MOV_FLAG_SKIP_TRAILER)) { avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_TRAILER); mov_write_mfra_tag(pb, mov); } @@ -6682,6 +6794,7 @@ const AVCodecTag codec_mp4_tags[] = { { AV_CODEC_ID_DIRAC , MKTAG('d', 'r', 'a', 'c') }, { AV_CODEC_ID_TSCC2 , MKTAG('m', 'p', '4', 'v') }, { AV_CODEC_ID_VP9 , MKTAG('v', 'p', '0', '9') }, + { AV_CODEC_ID_AV1 , MKTAG('a', 'v', '0', '1') }, { AV_CODEC_ID_AAC , MKTAG('m', 'p', '4', 'a') }, { AV_CODEC_ID_MP4ALS , MKTAG('m', 'p', '4', 'a') }, { AV_CODEC_ID_MP3 , MKTAG('m', 'p', '4', 'a') }, @@ -6696,6 +6809,7 @@ const AVCodecTag codec_mp4_tags[] = { { AV_CODEC_ID_EVRC , MKTAG('m', 'p', '4', 'a') }, { AV_CODEC_ID_DVD_SUBTITLE, MKTAG('m', 'p', '4', 's') }, { AV_CODEC_ID_MOV_TEXT , MKTAG('t', 'x', '3', 'g') }, + { AV_CODEC_ID_BIN_DATA , MKTAG('g', 'p', 'm', 'd') }, { AV_CODEC_ID_NONE , 0 }, }; @@ -6741,7 +6855,7 @@ AVOutputFormat ff_mov_muxer = { .deinit = mov_free, .flags = AVFMT_GLOBALHEADER | AVFMT_ALLOW_FLUSH | AVFMT_TS_NEGATIVE, .codec_tag = (const AVCodecTag* const []){ - ff_codec_movvideo_tags, ff_codec_movaudio_tags, 0 + ff_codec_movvideo_tags, ff_codec_movaudio_tags, ff_codec_movsubtitle_tags, 0 }, .check_bitstream = mov_check_bitstream, .priv_class = &mov_muxer_class, diff --git a/libavformat/movenc.h b/libavformat/movenc.h index c9b4072fb..68d6f23a5 100644 --- a/libavformat/movenc.h +++ b/libavformat/movenc.h @@ -46,6 +46,7 @@ typedef struct MOVIentry { uint64_t pos; int64_t dts; + int64_t pts; unsigned int size; unsigned int samples_in_chunk; unsigned int chunkNum; ///< Chunk number if the current entry is a chunk start otherwise 0 @@ -169,6 +170,13 @@ typedef enum { MOV_ENC_CENC_AES_CTR, } MOVEncryptionScheme; +typedef enum { + MOV_PRFT_NONE = 0, + MOV_PRFT_SRC_WALLCLOCK, + MOV_PRFT_SRC_PTS, + MOV_PRFT_NB +} MOVPrftBox; + typedef struct MOVMuxContext { const AVClass *av_class; int mode; @@ -224,6 +232,8 @@ typedef struct MOVMuxContext { int use_stream_ids_as_track_ids; int track_ids_ok; int write_tmcd; + MOVPrftBox write_prft; + int empty_hdlr_name; } MOVMuxContext; #define FF_MOV_FLAG_RTP_HINT (1 << 0) @@ -247,6 +257,7 @@ typedef struct MOVMuxContext { #define FF_MOV_FLAG_SKIP_TRAILER (1 << 18) #define FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS (1 << 19) #define FF_MOV_FLAG_FRAG_EVERY_FRAME (1 << 20) +#define FF_MOV_FLAG_SKIP_SIDX (1 << 21) int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt); diff --git a/libavformat/mp3dec.c b/libavformat/mp3dec.c index a76fe32e5..258f19174 100644 --- a/libavformat/mp3dec.c +++ b/libavformat/mp3dec.c @@ -66,11 +66,12 @@ static int check(AVIOContext *pb, int64_t pos, uint32_t *header); /* mp3 read */ -static int mp3_read_probe(AVProbeData *p) +static int mp3_read_probe(const AVProbeData *p) { int max_frames, first_frames = 0; int whole_used = 0; int frames, ret; + int framesizes, max_framesizes; uint32_t header; const uint8_t *buf, *buf0, *buf2, *end; @@ -80,11 +81,12 @@ static int mp3_read_probe(AVProbeData *p) buf0++; max_frames = 0; + max_framesizes = 0; buf = buf0; for(; buf < end; buf= buf2+1) { buf2 = buf; - for(frames = 0; buf2 < end; frames++) { + for(framesizes = frames = 0; buf2 < end; frames++) { MPADecodeHeader h; header = AV_RB32(buf2); @@ -92,8 +94,10 @@ static int mp3_read_probe(AVProbeData *p) if (ret != 0) break; buf2 += h.frame_size; + framesizes += h.frame_size; } max_frames = FFMAX(max_frames, frames); + max_framesizes = FFMAX(max_framesizes, framesizes); if(buf == buf0) { first_frames= frames; if (buf2 == end + sizeof(uint32_t)) @@ -103,12 +107,12 @@ static int mp3_read_probe(AVProbeData *p) // keep this in sync with ac3 probe, both need to avoid // issues with MPEG-files! if (first_frames>=7) return AVPROBE_SCORE_EXTENSION + 1; - else if(max_frames>200)return AVPROBE_SCORE_EXTENSION; - else if(max_frames>=4 && max_frames >= p->buf_size/10000) return AVPROBE_SCORE_EXTENSION / 2; + else if(max_frames>200 && p->buf_size < 2*max_framesizes)return AVPROBE_SCORE_EXTENSION; + else if(max_frames>=4 && p->buf_size < 2*max_framesizes) return AVPROBE_SCORE_EXTENSION / 2; else if(ff_id3v2_match(buf0, ID3v2_DEFAULT_MAGIC) && 2*ff_id3v2_tag_len(buf0) >= p->buf_size) return p->buf_size < PROBE_BUF_MAX ? AVPROBE_SCORE_EXTENSION / 4 : AVPROBE_SCORE_EXTENSION - 2; else if(first_frames > 1 && whole_used) return 5; - else if(max_frames>=1 && max_frames >= p->buf_size/10000) return 1; + else if(max_frames>=1 && p->buf_size < 10*max_framesizes) return 1; else return 0; //mpegps_mp3_unrecognized_format.mpg has max_frames=3 } diff --git a/libavformat/mp3enc.c b/libavformat/mp3enc.c index dd662f547..f4814be80 100644 --- a/libavformat/mp3enc.c +++ b/libavformat/mp3enc.c @@ -391,6 +391,7 @@ static void mp3_update_xing(AVFormatContext *s) uint16_t tag_crc; uint8_t *toc; int i, rg_size; + int64_t old_pos = avio_tell(s->pb); /* replace "Xing" identification string with "Info" for CBR files. */ if (!mp3->has_variable_bitrate) @@ -450,7 +451,7 @@ static void mp3_update_xing(AVFormatContext *s) avio_seek(s->pb, mp3->xing_frame_offset, SEEK_SET); avio_write(s->pb, mp3->xing_frame, mp3->xing_frame_size); - avio_seek(s->pb, 0, SEEK_END); + avio_seek(s->pb, old_pos, SEEK_SET); } static int mp3_write_trailer(struct AVFormatContext *s) diff --git a/libavformat/mpc.c b/libavformat/mpc.c index af333746e..a7b2e116e 100644 --- a/libavformat/mpc.c +++ b/libavformat/mpc.c @@ -45,7 +45,7 @@ typedef struct MPCContext { int frames_noted; } MPCContext; -static int mpc_probe(AVProbeData *p) +static int mpc_probe(const AVProbeData *p) { const uint8_t *d = p->buf; if (d[0] == 'M' && d[1] == 'P' && d[2] == '+' && (d[3] == 0x17 || d[3] == 0x7)) @@ -88,7 +88,7 @@ static int mpc_read_header(AVFormatContext *s) st = avformat_new_stream(s, NULL); if (!st) - return AVERROR(ENOMEM); + goto mem_error; st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO; st->codecpar->codec_id = AV_CODEC_ID_MUSEPACK7; st->codecpar->channels = 2; @@ -96,7 +96,7 @@ static int mpc_read_header(AVFormatContext *s) st->codecpar->bits_per_coded_sample = 16; if (ff_get_extradata(s, st->codecpar, s->pb, 16) < 0) - return AVERROR(ENOMEM); + goto mem_error; st->codecpar->sample_rate = mpc_rate[st->codecpar->extradata[2] & 3]; avpriv_set_pts_info(st, 32, MPC_FRAMESIZE, st->codecpar->sample_rate); /* scan for seekpoints */ @@ -113,6 +113,9 @@ static int mpc_read_header(AVFormatContext *s) } return 0; +mem_error: + av_freep(&c->frames); + return AVERROR(ENOMEM); } static int mpc_read_packet(AVFormatContext *s, AVPacket *pkt) diff --git a/libavformat/mpc8.c b/libavformat/mpc8.c index 79e5f6a9a..0eb879ffc 100644 --- a/libavformat/mpc8.c +++ b/libavformat/mpc8.c @@ -73,7 +73,7 @@ static inline int64_t bs_get_v(const uint8_t **bs) return v - br; } -static int mpc8_probe(AVProbeData *p) +static int mpc8_probe(const AVProbeData *p) { const uint8_t *bs = p->buf + 4; const uint8_t *bs_end = bs + p->buf_size; diff --git a/libavformat/mpeg.c b/libavformat/mpeg.c index 8ae474092..3205f209e 100644 --- a/libavformat/mpeg.c +++ b/libavformat/mpeg.c @@ -64,7 +64,7 @@ static int check_pack_header(const uint8_t *buf) return (buf[1] & 0xC0) == 0x40 || (buf[1] & 0xF0) == 0x20; } -static int mpegps_probe(AVProbeData *p) +static int mpegps_probe(const AVProbeData *p) { uint32_t code = -1; int i; @@ -525,31 +525,34 @@ redo: } es_type = m->psm_es_type[startcode & 0xff]; - if (es_type == STREAM_TYPE_VIDEO_MPEG1) { - codec_id = AV_CODEC_ID_MPEG2VIDEO; - type = AVMEDIA_TYPE_VIDEO; - } else if (es_type == STREAM_TYPE_VIDEO_MPEG2) { - codec_id = AV_CODEC_ID_MPEG2VIDEO; - type = AVMEDIA_TYPE_VIDEO; - } else if (es_type == STREAM_TYPE_AUDIO_MPEG1 || - es_type == STREAM_TYPE_AUDIO_MPEG2) { - codec_id = AV_CODEC_ID_MP3; - type = AVMEDIA_TYPE_AUDIO; - } else if (es_type == STREAM_TYPE_AUDIO_AAC) { - codec_id = AV_CODEC_ID_AAC; - type = AVMEDIA_TYPE_AUDIO; - } else if (es_type == STREAM_TYPE_VIDEO_MPEG4) { - codec_id = AV_CODEC_ID_MPEG4; - type = AVMEDIA_TYPE_VIDEO; - } else if (es_type == STREAM_TYPE_VIDEO_H264) { - codec_id = AV_CODEC_ID_H264; - type = AVMEDIA_TYPE_VIDEO; - } else if (es_type == STREAM_TYPE_AUDIO_AC3) { - codec_id = AV_CODEC_ID_AC3; - type = AVMEDIA_TYPE_AUDIO; - } else if (m->imkh_cctv && es_type == 0x91) { - codec_id = AV_CODEC_ID_PCM_MULAW; - type = AVMEDIA_TYPE_AUDIO; + if (es_type == STREAM_TYPE_VIDEO_MPEG1) { + codec_id = AV_CODEC_ID_MPEG2VIDEO; + type = AVMEDIA_TYPE_VIDEO; + } else if (es_type == STREAM_TYPE_VIDEO_MPEG2) { + codec_id = AV_CODEC_ID_MPEG2VIDEO; + type = AVMEDIA_TYPE_VIDEO; + } else if (es_type == STREAM_TYPE_AUDIO_MPEG1 || + es_type == STREAM_TYPE_AUDIO_MPEG2) { + codec_id = AV_CODEC_ID_MP3; + type = AVMEDIA_TYPE_AUDIO; + } else if (es_type == STREAM_TYPE_AUDIO_AAC) { + codec_id = AV_CODEC_ID_AAC; + type = AVMEDIA_TYPE_AUDIO; + } else if (es_type == STREAM_TYPE_VIDEO_MPEG4) { + codec_id = AV_CODEC_ID_MPEG4; + type = AVMEDIA_TYPE_VIDEO; + } else if (es_type == STREAM_TYPE_VIDEO_H264) { + codec_id = AV_CODEC_ID_H264; + type = AVMEDIA_TYPE_VIDEO; + } else if (es_type == STREAM_TYPE_VIDEO_HEVC) { + codec_id = AV_CODEC_ID_HEVC; + type = AVMEDIA_TYPE_VIDEO; + } else if (es_type == STREAM_TYPE_AUDIO_AC3) { + codec_id = AV_CODEC_ID_AC3; + type = AVMEDIA_TYPE_AUDIO; + } else if (m->imkh_cctv && es_type == 0x91) { + codec_id = AV_CODEC_ID_PCM_MULAW; + type = AVMEDIA_TYPE_AUDIO; } else if (startcode >= 0x1e0 && startcode <= 0x1ef) { static const unsigned char avs_seqh[4] = { 0, 0, 1, 0xb0 }; unsigned char buf[8]; @@ -647,7 +650,7 @@ found: pkt->stream_index = st->index; if (s->debug & FF_FDEBUG_TS) - av_log(s, AV_LOG_TRACE, "%d: pts=%0.3f dts=%0.3f size=%d\n", + av_log(s, AV_LOG_DEBUG, "%d: pts=%0.3f dts=%0.3f size=%d\n", pkt->stream_index, pkt->pts / 90000.0, pkt->dts / 90000.0, pkt->size); @@ -668,7 +671,7 @@ static int64_t mpegps_read_dts(AVFormatContext *s, int stream_index, len = mpegps_read_pes_header(s, &pos, &startcode, &pts, &dts); if (len < 0) { if (s->debug & FF_FDEBUG_TS) - av_log(s, AV_LOG_TRACE, "none (ret=%d)\n", len); + av_log(s, AV_LOG_DEBUG, "none (ret=%d)\n", len); return AV_NOPTS_VALUE; } if (startcode == s->streams[stream_index]->id && @@ -678,7 +681,7 @@ static int64_t mpegps_read_dts(AVFormatContext *s, int stream_index, avio_skip(s->pb, len); } if (s->debug & FF_FDEBUG_TS) - av_log(s, AV_LOG_TRACE, "pos=0x%"PRIx64" dts=0x%"PRIx64" %0.3f\n", + av_log(s, AV_LOG_DEBUG, "pos=0x%"PRIx64" dts=0x%"PRIx64" %0.3f\n", pos, dts, dts / 90000.0); *ppos = pos; return dts; @@ -700,7 +703,7 @@ AVInputFormat ff_mpegps_demuxer = { #define REF_STRING "# VobSub index file," #define MAX_LINE_SIZE 2048 -static int vobsub_probe(AVProbeData *p) +static int vobsub_probe(const AVProbeData *p) { if (!strncmp(p->buf, REF_STRING, sizeof(REF_STRING) - 1)) return AVPROBE_SCORE_MAX; @@ -719,7 +722,7 @@ static int vobsub_read_header(AVFormatContext *s) int stream_id = -1; char id[64] = {0}; char alt[MAX_LINE_SIZE] = {0}; - AVInputFormat *iformat; + ff_const59 AVInputFormat *iformat; if (!vobsub->sub_name) { char *ext; diff --git a/libavformat/mpeg.h b/libavformat/mpeg.h index 617e36cba..b63529577 100644 --- a/libavformat/mpeg.h +++ b/libavformat/mpeg.h @@ -55,6 +55,7 @@ #define STREAM_TYPE_AUDIO_AAC 0x0f #define STREAM_TYPE_VIDEO_MPEG4 0x10 #define STREAM_TYPE_VIDEO_H264 0x1b +#define STREAM_TYPE_VIDEO_HEVC 0x24 #define STREAM_TYPE_VIDEO_CAVS 0x42 #define STREAM_TYPE_AUDIO_AC3 0x81 diff --git a/libavformat/mpegenc.c b/libavformat/mpegenc.c index 4c6fa67fb..43ebc46e0 100644 --- a/libavformat/mpegenc.c +++ b/libavformat/mpegenc.c @@ -364,12 +364,7 @@ static av_cold int mpeg_mux_init(AVFormatContext *ctx) stream->id = ac3_id++; } else if (st->codecpar->codec_id == AV_CODEC_ID_DTS) { stream->id = dts_id++; - } else if (st->codecpar->codec_id == AV_CODEC_ID_PCM_S16BE || - st->codecpar->codec_id == AV_CODEC_ID_PCM_DVD) { - if (st->codecpar->bits_per_coded_sample != 16) { - av_log(ctx, AV_LOG_ERROR, "Only 16 bit LPCM streams can be muxed.\n"); - goto fail; - } + } else if (st->codecpar->codec_id == AV_CODEC_ID_PCM_S16BE) { stream->id = lpcm_id++; for (j = 0; j < 4; j++) { if (lpcm_freq_tab[j] == st->codecpar->sample_rate) @@ -392,6 +387,36 @@ static av_cold int mpeg_mux_init(AVFormatContext *ctx) stream->lpcm_header[1] = (st->codecpar->channels - 1) | (j << 4); stream->lpcm_header[2] = 0x80; stream->lpcm_align = st->codecpar->channels * 2; + } else if (st->codecpar->codec_id == AV_CODEC_ID_PCM_DVD) { + int freq; + + switch (st->codecpar->sample_rate) { + case 48000: freq = 0; break; + case 96000: freq = 1; break; + case 44100: freq = 2; break; + case 32000: freq = 3; break; + default: + av_log(ctx, AV_LOG_ERROR, "Unsupported sample rate.\n"); + return AVERROR(EINVAL); + } + + stream->lpcm_header[0] = 0x0c; + stream->lpcm_header[1] = (freq << 4) | + (((st->codecpar->bits_per_coded_sample - 16) / 4) << 6) | + st->codecpar->channels - 1; + stream->lpcm_header[2] = 0x80; + stream->id = lpcm_id++; + stream->lpcm_align = st->codecpar->channels * st->codecpar->bits_per_coded_sample / 8; + } else if (st->codecpar->codec_id == AV_CODEC_ID_MLP || + st->codecpar->codec_id == AV_CODEC_ID_TRUEHD) { + av_log(ctx, AV_LOG_ERROR, "Support for muxing audio codec %s not implemented.\n", + avcodec_get_name(st->codecpar->codec_id)); + return AVERROR_PATCHWELCOME; + } else if (st->codecpar->codec_id != AV_CODEC_ID_MP1 && + st->codecpar->codec_id != AV_CODEC_ID_MP2 && + st->codecpar->codec_id != AV_CODEC_ID_MP3) { + av_log(ctx, AV_LOG_ERROR, "Unsupported audio codec. Must be one of mp1, mp2, mp3, 16-bit pcm_dvd, pcm_s16be, ac3 or dts.\n"); + goto fail; } else { stream->id = mpa_id++; } diff --git a/libavformat/mpegts.c b/libavformat/mpegts.c index 92baca61a..0415ceea0 100644 --- a/libavformat/mpegts.c +++ b/libavformat/mpegts.c @@ -37,6 +37,9 @@ #include "avio_internal.h" #include "mpeg.h" #include "isom.h" +#if CONFIG_ICONV +#include +#endif /* maximum size in which we look for synchronization if * synchronization is lost */ @@ -53,6 +56,9 @@ (prev_dividend) = (dividend); \ } while (0) +#define PROBE_PACKET_MAX_BUF 8192 +#define PROBE_PACKET_MARGIN 5 + enum MpegTSFilterType { MPEGTS_PES, MPEGTS_SECTION, @@ -91,6 +97,7 @@ struct MpegTSFilter { int es_id; int last_cc; /* last cc code (-1 if first packet) */ int64_t last_pcr; + int discard; enum MpegTSFilterType type; union { MpegTSPESFilter pes_filter; @@ -143,10 +150,12 @@ struct MpegTSContext { int skip_changes; int skip_clear; + int skip_unknown_pmt; int scan_all_pmts; int resync_size; + int merge_pmt_versions; /******************************************/ /* private mpegts data */ @@ -172,6 +181,10 @@ static const AVOption options[] = { {.i64 = 0}, 0, 0, AV_OPT_FLAG_DECODING_PARAM | AV_OPT_FLAG_EXPORT | AV_OPT_FLAG_READONLY }, {"scan_all_pmts", "scan and combine all PMTs", offsetof(MpegTSContext, scan_all_pmts), AV_OPT_TYPE_BOOL, {.i64 = -1}, -1, 1, AV_OPT_FLAG_DECODING_PARAM }, + {"skip_unknown_pmt", "skip PMTs for programs not advertised in the PAT", offsetof(MpegTSContext, skip_unknown_pmt), AV_OPT_TYPE_BOOL, + {.i64 = 0}, 0, 1, AV_OPT_FLAG_DECODING_PARAM }, + {"merge_pmt_versions", "re-use streams when PMT's version/pids change", offsetof(MpegTSContext, merge_pmt_versions), AV_OPT_TYPE_BOOL, + {.i64 = 0}, 0, 1, AV_OPT_FLAG_DECODING_PARAM }, {"skip_changes", "skip changing / adding streams / programs", offsetof(MpegTSContext, skip_changes), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, 0 }, {"skip_clear", "skip clearing programs", offsetof(MpegTSContext, skip_clear), AV_OPT_TYPE_BOOL, @@ -241,6 +254,7 @@ typedef struct PESContext { uint8_t header[MAX_PES_HEADER_SIZE]; AVBufferRef *buffer; SLConfigDescr sl; + int merged_st; } PESContext; extern AVInputFormat ff_mpegts_demuxer; @@ -330,12 +344,23 @@ static void set_pmt_found(MpegTSContext *ts, unsigned int programid) p->pmt_found = 1; } -static void set_pcr_pid(AVFormatContext *s, unsigned int programid, unsigned int pid) +static void update_av_program_info(AVFormatContext *s, unsigned int programid, + unsigned int pid, int version) { int i; for (i = 0; i < s->nb_programs; i++) { - if (s->programs[i]->id == programid) { - s->programs[i]->pcr_pid = pid; + AVProgram *program = s->programs[i]; + if (program->id == programid) { + int old_pcr_pid = program->pcr_pid, + old_version = program->pmt_version; + program->pcr_pid = pid; + program->pmt_version = version; + + if (old_version != -1 && old_version != version) { + av_log(s, AV_LOG_VERBOSE, + "detected PMT change (program=%d, version=%d/%d, pcr_pid=0x%x/0x%x)\n", + programid, old_version, version, old_pcr_pid, pid); + } break; } } @@ -534,8 +559,8 @@ static void mpegts_close_filter(MpegTSContext *ts, MpegTSFilter *filter) PESContext *pes = filter->u.pes_filter.opaque; av_buffer_unref(&pes->buffer); /* referenced private data will be freed later in - * avformat_close_input */ - if (!((PESContext *)filter->u.pes_filter.opaque)->st) { + * avformat_close_input (pes->st->priv_data == pes) */ + if (!pes->st || pes->merged_st) { av_freep(&filter->u.pes_filter.opaque); } } @@ -572,28 +597,42 @@ static int analyze(const uint8_t *buf, int size, int packet_size, return best_score - FFMAX(stat_all - 10*best_score, 0)/10; } -/* autodetect fec presence. Must have at least 1024 bytes */ -static int get_packet_size(const uint8_t *buf, int size) +/* autodetect fec presence */ +static int get_packet_size(AVFormatContext* s) { int score, fec_score, dvhs_score; + int margin; + int ret; - if (size < (TS_FEC_PACKET_SIZE * 5 + 1)) - return AVERROR_INVALIDDATA; + /*init buffer to store stream for probing */ + uint8_t buf[PROBE_PACKET_MAX_BUF] = {0}; + int buf_size = 0; - score = analyze(buf, size, TS_PACKET_SIZE, 0); - dvhs_score = analyze(buf, size, TS_DVHS_PACKET_SIZE, 0); - fec_score = analyze(buf, size, TS_FEC_PACKET_SIZE, 0); - av_log(NULL, AV_LOG_TRACE, "score: %d, dvhs_score: %d, fec_score: %d \n", - score, dvhs_score, fec_score); + while (buf_size < PROBE_PACKET_MAX_BUF) { + ret = avio_read_partial(s->pb, buf + buf_size, PROBE_PACKET_MAX_BUF - buf_size); + if (ret < 0) + return AVERROR_INVALIDDATA; + buf_size += ret; - if (score > fec_score && score > dvhs_score) - return TS_PACKET_SIZE; - else if (dvhs_score > score && dvhs_score > fec_score) - return TS_DVHS_PACKET_SIZE; - else if (score < fec_score && dvhs_score < fec_score) - return TS_FEC_PACKET_SIZE; - else - return AVERROR_INVALIDDATA; + score = analyze(buf, buf_size, TS_PACKET_SIZE, 0); + dvhs_score = analyze(buf, buf_size, TS_DVHS_PACKET_SIZE, 0); + fec_score = analyze(buf, buf_size, TS_FEC_PACKET_SIZE, 0); + av_log(s, AV_LOG_TRACE, "Probe: %d, score: %d, dvhs_score: %d, fec_score: %d \n", + buf_size, score, dvhs_score, fec_score); + + margin = mid_pred(score, fec_score, dvhs_score); + + if (buf_size < PROBE_PACKET_MAX_BUF) + margin += PROBE_PACKET_MARGIN; /*if buffer not filled */ + + if (score > margin) + return TS_PACKET_SIZE; + else if (dvhs_score > margin) + return TS_DVHS_PACKET_SIZE; + else if (fec_score > margin) + return TS_FEC_PACKET_SIZE; + } + return AVERROR_INVALIDDATA; } typedef struct SectionHeader { @@ -655,6 +694,51 @@ static char *getstr8(const uint8_t **pp, const uint8_t *p_end) return NULL; if (len > p_end - p) return NULL; +#if CONFIG_ICONV + if (len) { + const char *encodings[] = { + "ISO6937", "ISO-8859-5", "ISO-8859-6", "ISO-8859-7", + "ISO-8859-8", "ISO-8859-9", "ISO-8859-10", "ISO-8859-11", + "", "ISO-8859-13", "ISO-8859-14", "ISO-8859-15", "", "", "", "", + "", "UCS-2BE", "KSC_5601", "GB2312", "UCS-2BE", "UTF-8", "", "", + "", "", "", "", "", "", "", "" + }; + iconv_t cd; + char *in, *out; + size_t inlen = len, outlen = inlen * 6 + 1; + if (len >= 3 && p[0] == 0x10 && !p[1] && p[2] && p[2] <= 0xf && p[2] != 0xc) { + char iso8859[12]; + snprintf(iso8859, sizeof(iso8859), "ISO-8859-%d", p[2]); + inlen -= 3; + in = (char *)p + 3; + cd = iconv_open("UTF-8", iso8859); + } else if (p[0] < 0x20) { + inlen -= 1; + in = (char *)p + 1; + cd = iconv_open("UTF-8", encodings[*p]); + } else { + in = (char *)p; + cd = iconv_open("UTF-8", encodings[0]); + } + if (cd == (iconv_t)-1) + goto no_iconv; + str = out = av_malloc(outlen); + if (!str) { + iconv_close(cd); + return NULL; + } + if (iconv(cd, &in, &inlen, &out, &outlen) == -1) { + iconv_close(cd); + av_freep(&str); + goto no_iconv; + } + iconv_close(cd); + *out = 0; + *pp = p + len; + return str; + } +no_iconv: +#endif str = av_malloc(len + 1); if (!str) return NULL; @@ -1073,6 +1157,8 @@ static int mpegts_push_data(MpegTSFilter *filter, if (!pes->st) { if (ts->skip_changes) goto skip; + if (ts->merge_pmt_versions) + goto skip; /* wait for PMT to merge new stream */ pes->st = avformat_new_stream(ts->stream, NULL); if (!pes->st) @@ -1199,6 +1285,7 @@ skip: || pes->st->codecpar->codec_id == AV_CODEC_ID_DVB_SUBTITLE) ) { AVProgram *p = NULL; + int pcr_found = 0; while ((p = av_find_program_from_stream(pes->stream, p, pes->st->index))) { if (p->pcr_pid != -1 && p->discard != AVDISCARD_ALL) { MpegTSFilter *f = pes->ts->pids[p->pcr_pid]; @@ -1216,14 +1303,17 @@ skip: st = pst; } } - if (f->last_pcr != -1 && st && st->discard != AVDISCARD_ALL) { + if (f->last_pcr != -1 && !f->discard) { // teletext packets do not always have correct timestamps, // the standard says they should be handled after 40.6 ms at most, // and the pcr error to this packet should be no more than 100 ms. // TODO: we should interpolate the PCR, not just use the last one int64_t pcr = f->last_pcr / 300; - pes->st->pts_wrap_reference = st->pts_wrap_reference; - pes->st->pts_wrap_behavior = st->pts_wrap_behavior; + pcr_found = 1; + if (st) { + pes->st->pts_wrap_reference = st->pts_wrap_reference; + pes->st->pts_wrap_behavior = st->pts_wrap_behavior; + } if (pes->dts == AV_NOPTS_VALUE || pes->dts < pcr) { pes->pts = pes->dts = pcr; } else if (pes->st->codecpar->codec_id == AV_CODEC_ID_DVB_TELETEXT && @@ -1238,6 +1328,15 @@ skip: } } } + + if (!pcr_found) { + av_log(pes->stream, AV_LOG_VERBOSE, + "Forcing DTS/PTS to be unset for a " + "non-trustworthy PES packet for PID %d as " + "PCR hasn't been received yet.\n", + pes->pid); + pes->dts = pes->pts = AV_NOPTS_VALUE; + } } } break; @@ -1626,6 +1725,13 @@ static void scte_data_cb(MpegTSFilter *filter, const uint8_t *section, if (idx < 0) return; + /** + * In case we receive an SCTE-35 packet before mpegts context is fully + * initialized. + */ + if (!ts->pkt) + return; + new_data_packet(section, section_len, ts->pkt); ts->pkt->stream_index = idx; prg = av_find_program_from_stream(ts->stream, NULL, idx); @@ -1684,6 +1790,11 @@ int ff_parse_mpeg2_descriptor(AVFormatContext *fc, AVStream *st, int stream_type mpegts_find_stream_type(st, desc_tag, DESC_types); switch (desc_tag) { + case 0x02: /* video stream descriptor */ + if (get8(pp, desc_end) & 0x1) { + st->disposition |= AV_DISPOSITION_STILL_IMAGE; + } + break; case 0x1E: /* SL descriptor */ desc_es_id = get16(pp, desc_end); if (desc_es_id < 0) @@ -1848,6 +1959,7 @@ int ff_parse_mpeg2_descriptor(AVFormatContext *fc, AVStream *st, int stream_type break; case 0x03: st->disposition |= AV_DISPOSITION_VISUAL_IMPAIRED; + st->disposition |= AV_DISPOSITION_DESCRIPTIONS; break; } } @@ -1923,6 +2035,7 @@ int ff_parse_mpeg2_descriptor(AVFormatContext *fc, AVStream *st, int stream_type switch ((flags >> 2) & 0x1F) { /* editorial_classification */ case 0x01: st->disposition |= AV_DISPOSITION_VISUAL_IMPAIRED; + st->disposition |= AV_DISPOSITION_DESCRIPTIONS; break; case 0x02: st->disposition |= AV_DISPOSITION_HEARING_IMPAIRED; @@ -1947,6 +2060,78 @@ int ff_parse_mpeg2_descriptor(AVFormatContext *fc, AVStream *st, int stream_type } } break; + case 0x6a: /* ac-3_descriptor */ + { + int component_type_flag = get8(pp, desc_end) & (1 << 7); + if (component_type_flag) { + int component_type = get8(pp, desc_end); + int service_type_mask = 0x38; // 0b00111000 + int service_type = ((component_type & service_type_mask) >> 3); + if (service_type == 0x02 /* 0b010 */) { + st->disposition |= AV_DISPOSITION_DESCRIPTIONS; + av_log(ts ? ts->stream : fc, AV_LOG_DEBUG, "New track disposition for id %u: %u\n", st->id, st->disposition); + } + } + } + break; + case 0x7a: /* enhanced_ac-3_descriptor */ + { + int component_type_flag = get8(pp, desc_end) & (1 << 7); + if (component_type_flag) { + int component_type = get8(pp, desc_end); + int service_type_mask = 0x38; // 0b00111000 + int service_type = ((component_type & service_type_mask) >> 3); + if (service_type == 0x02 /* 0b010 */) { + st->disposition |= AV_DISPOSITION_DESCRIPTIONS; + av_log(ts ? ts->stream : fc, AV_LOG_DEBUG, "New track disposition for id %u: %u\n", st->id, st->disposition); + } + } + } + break; + case 0xfd: /* ARIB data coding type descriptor */ + // STD-B24, fascicle 3, chapter 4 defines private_stream_1 + // for captions + if (stream_type == STREAM_TYPE_PRIVATE_DATA) { + // This structure is defined in STD-B10, part 1, listing 5.4 and + // part 2, 6.2.20). + // Listing of data_component_ids is in STD-B10, part 2, Annex J. + // Component tag limits are documented in TR-B14, fascicle 2, + // Vol. 3, Section 2, 4.2.8.1 + int actual_component_tag = st->stream_identifier - 1; + int picked_profile = FF_PROFILE_UNKNOWN; + int data_component_id = get16(pp, desc_end); + if (data_component_id < 0) + return AVERROR_INVALIDDATA; + + switch (data_component_id) { + case 0x0008: + // [0x30..0x37] are component tags utilized for + // non-mobile captioning service ("profile A"). + if (actual_component_tag >= 0x30 && + actual_component_tag <= 0x37) { + picked_profile = FF_PROFILE_ARIB_PROFILE_A; + } + break; + case 0x0012: + // component tag 0x87 signifies a mobile/partial reception + // (1seg) captioning service ("profile C"). + if (actual_component_tag == 0x87) { + picked_profile = FF_PROFILE_ARIB_PROFILE_C; + } + break; + default: + break; + } + + if (picked_profile == FF_PROFILE_UNKNOWN) + break; + + st->codecpar->codec_type = AVMEDIA_TYPE_SUBTITLE; + st->codecpar->codec_id = AV_CODEC_ID_ARIB_CAPTION; + st->codecpar->profile = picked_profile; + st->request_probe = 0; + } + break; default: break; } @@ -1954,6 +2139,74 @@ int ff_parse_mpeg2_descriptor(AVFormatContext *fc, AVStream *st, int stream_type return 0; } +static AVStream *find_matching_stream(MpegTSContext *ts, int pid, unsigned int programid, + int stream_identifier, int pmt_stream_idx) +{ + AVFormatContext *s = ts->stream; + int i; + AVStream *found = NULL; + + for (i = 0; i < s->nb_streams; i++) { + AVStream *st = s->streams[i]; + if (st->program_num != programid) + continue; + if (stream_identifier != -1) { /* match based on "stream identifier descriptor" if present */ + if (st->stream_identifier == stream_identifier+1) { + found = st; + break; + } + } else if (st->pmt_stream_idx == pmt_stream_idx) { /* match based on position within the PMT */ + found = st; + break; + } + } + + if (found) { + av_log(ts->stream, AV_LOG_VERBOSE, + "re-using existing %s stream %d (pid=0x%x) for new pid=0x%x\n", + av_get_media_type_string(found->codecpar->codec_type), + i, found->id, pid); + } + + return found; +} + +static int parse_stream_identifier_desc(const uint8_t *p, const uint8_t *p_end) +{ + const uint8_t **pp = &p; + const uint8_t *desc_list_end; + const uint8_t *desc_end; + int desc_list_len; + int desc_len, desc_tag; + + desc_list_len = get16(pp, p_end); + if (desc_list_len < 0) + return -1; + desc_list_len &= 0xfff; + desc_list_end = p + desc_list_len; + if (desc_list_end > p_end) + return -1; + + while (1) { + desc_tag = get8(pp, desc_list_end); + if (desc_tag < 0) + return -1; + desc_len = get8(pp, desc_list_end); + if (desc_len < 0) + return -1; + desc_end = *pp + desc_len; + if (desc_end > desc_list_end) + return -1; + + if (desc_tag == 0x52) { + return get8(pp, desc_end); + } + *pp = desc_end; + } + + return -1; +} + static int is_pes_stream(int stream_type, uint32_t prog_reg_desc) { return !(stream_type == 0x13 || @@ -1971,6 +2224,7 @@ static void pmt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len int program_info_length, pcr_pid, pid, stream_type; int desc_list_len; uint32_t prog_reg_desc = 0; /* registration descriptor */ + int stream_identifier = -1; int mp4_descr_count = 0; Mp4Descr mp4_descr[MAX_MP4_DESCR_COUNT] = { { 0 } }; @@ -1994,6 +2248,8 @@ static void pmt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len if (!ts->scan_all_pmts && ts->skip_changes) return; + if (ts->skip_unknown_pmt && !get_program(ts, h->id)) + return; if (!ts->skip_clear) clear_program(ts, h->id); @@ -2002,7 +2258,7 @@ static void pmt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len return; pcr_pid &= 0x1fff; add_pid_to_pmt(ts, h->id, pcr_pid); - set_pcr_pid(ts->stream, h->id, pcr_pid); + update_av_program_info(ts->stream, h->id, pcr_pid, h->version); av_log(ts->stream, AV_LOG_TRACE, "pcr_pid=0x%x\n", pcr_pid); @@ -2044,7 +2300,7 @@ static void pmt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len set_pmt_found(ts, h->id); - for (;;) { + for (i = 0; ; i++) { st = 0; pes = NULL; stream_type = get8(&p, p_end); @@ -2057,35 +2313,67 @@ static void pmt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len if (pid == ts->current_pid) goto out; + if (ts->merge_pmt_versions) + stream_identifier = parse_stream_identifier_desc(p, p_end); + /* now create stream */ if (ts->pids[pid] && ts->pids[pid]->type == MPEGTS_PES) { pes = ts->pids[pid]->u.pes_filter.opaque; + if (ts->merge_pmt_versions && !pes->st) { + st = find_matching_stream(ts, pid, h->id, stream_identifier, i); + if (st) { + pes->st = st; + pes->stream_type = stream_type; + pes->merged_st = 1; + } + } if (!pes->st) { - pes->st = avformat_new_stream(pes->stream, NULL); + pes->st = avformat_new_stream(pes->stream, NULL); if (!pes->st) goto out; pes->st->id = pes->pid; + pes->st->program_num = h->id; + pes->st->pmt_version = h->version; + pes->st->pmt_stream_idx = i; } st = pes->st; } else if (is_pes_stream(stream_type, prog_reg_desc)) { if (ts->pids[pid]) mpegts_close_filter(ts, ts->pids[pid]); // wrongly added sdt filter probably pes = add_pes_stream(ts, pid, pcr_pid); - if (pes) { + if (ts->merge_pmt_versions && pes && !pes->st) { + st = find_matching_stream(ts, pid, h->id, stream_identifier, i); + if (st) { + pes->st = st; + pes->stream_type = stream_type; + pes->merged_st = 1; + } + } + if (pes && !pes->st) { st = avformat_new_stream(pes->stream, NULL); if (!st) goto out; st->id = pes->pid; + st->program_num = h->id; + st->pmt_version = h->version; + st->pmt_stream_idx = i; } } else { int idx = ff_find_stream_index(ts->stream, pid); if (idx >= 0) { st = ts->stream->streams[idx]; - } else { + } + if (ts->merge_pmt_versions && !st) { + st = find_matching_stream(ts, pid, h->id, stream_identifier, i); + } + if (!st) { st = avformat_new_stream(ts->stream, NULL); if (!st) goto out; st->id = pid; + st->program_num = h->id; + st->pmt_version = h->version; + st->pmt_stream_idx = i; st->codecpar->codec_type = AVMEDIA_TYPE_DATA; if (stream_type == 0x86 && prog_reg_desc == AV_RL32("CUEI")) { mpegts_find_stream_type(st, stream_type, SCTE_types); @@ -2307,8 +2595,6 @@ static int handle_packet(MpegTSContext *ts, const uint8_t *packet) int64_t pos; pid = AV_RB16(packet + 1) & 0x1fff; - if (pid && discard_pid(ts, pid)) - return 0; is_start = packet[1] & 0x40; tss = ts->pids[pid]; if (ts->auto_guess && !tss && is_start) { @@ -2317,6 +2603,10 @@ static int handle_packet(MpegTSContext *ts, const uint8_t *packet) } if (!tss) return 0; + if (is_start) + tss->discard = discard_pid(ts, pid); + if (tss->discard) + return 0; ts->current_pid = pid; afc = (packet[3] >> 4) & 3; @@ -2589,7 +2879,7 @@ static int handle_packets(MpegTSContext *ts, int64_t nb_packets) return ret; } -static int mpegts_probe(AVProbeData *p) +static int mpegts_probe(const AVProbeData *p) { const int size = p->buf_size; int maxscore = 0; @@ -2671,8 +2961,6 @@ static int mpegts_read_header(AVFormatContext *s) { MpegTSContext *ts = s->priv_data; AVIOContext *pb = s->pb; - uint8_t buf[8 * 1024] = {0}; - int len; int64_t pos, probesize = s->probesize; s->internal->prefer_codec_framerate = 1; @@ -2680,10 +2968,8 @@ static int mpegts_read_header(AVFormatContext *s) if (ffio_ensure_seekback(pb, probesize) < 0) av_log(s, AV_LOG_WARNING, "Failed to allocate buffers for seekback\n"); - /* read the first 8192 bytes to get packet size */ pos = avio_tell(pb); - len = avio_read(pb, buf, sizeof(buf)); - ts->raw_packet_size = get_packet_size(buf, len); + ts->raw_packet_size = get_packet_size(s); if (ts->raw_packet_size <= 0) { av_log(s, AV_LOG_WARNING, "Could not detect TS packet size, defaulting to non-FEC/DVHS\n"); ts->raw_packet_size = TS_PACKET_SIZE; diff --git a/libavformat/mpegtsenc.c b/libavformat/mpegtsenc.c index 8b0736ac4..fc0ea225c 100644 --- a/libavformat/mpegtsenc.c +++ b/libavformat/mpegtsenc.c @@ -54,8 +54,8 @@ typedef struct MpegTSSection { typedef struct MpegTSService { MpegTSSection pmt; /* MPEG-2 PMT table context */ int sid; /* service ID */ - char *name; - char *provider_name; + uint8_t name[256]; + uint8_t provider_name[256]; int pcr_pid; int pcr_packet_count; int pcr_packet_period; @@ -264,25 +264,21 @@ static void mpegts_write_pat(AVFormatContext *s) data, q - data); } -/* NOTE: !str is accepted for an empty string */ -static void putstr8(uint8_t **q_ptr, const char *str, int write_len) +static void putbuf(uint8_t **q_ptr, const uint8_t *buf, size_t len) { - uint8_t *q; - int len; + memcpy(*q_ptr, buf, len); + *q_ptr += len; +} - q = *q_ptr; - if (!str) - len = 0; - else - len = strlen(str); - if (write_len) - *q++ = len; - if (!str) { - *q_ptr = q; - return; - } - memcpy(q, str, len); - q += len; +static void put_registration_descriptor(uint8_t **q_ptr, uint32_t tag) +{ + uint8_t *q = *q_ptr; + *q++ = 0x05; /* MPEG-2 registration descriptor*/ + *q++ = 4; + *q++ = tag; + *q++ = tag >> 8; + *q++ = tag >> 16; + *q++ = tag >> 24; *q_ptr = q; } @@ -412,14 +408,8 @@ static int mpegts_write_pmt(AVFormatContext *s, MpegTSService *service) *q++=1; // 1 byte, all flags sets to 0 *q++=0; // omit all fields... } - if (st->codecpar->codec_id==AV_CODEC_ID_S302M) { - *q++ = 0x05; /* MPEG-2 registration descriptor*/ - *q++ = 4; - *q++ = 'B'; - *q++ = 'S'; - *q++ = 'S'; - *q++ = 'D'; - } + if (st->codecpar->codec_id==AV_CODEC_ID_S302M) + put_registration_descriptor(&q, MKTAG('B', 'S', 'S', 'D')); if (st->codecpar->codec_id==AV_CODEC_ID_OPUS) { /* 6 bytes registration descriptor, 4 bytes Opus audio descriptor */ if (q - data > SECTION_LENGTH - 6 - 4) { @@ -427,12 +417,7 @@ static int mpegts_write_pmt(AVFormatContext *s, MpegTSService *service) break; } - *q++ = 0x05; /* MPEG-2 registration descriptor*/ - *q++ = 4; - *q++ = 'O'; - *q++ = 'p'; - *q++ = 'u'; - *q++ = 's'; + put_registration_descriptor(&q, MKTAG('O', 'p', 'u', 's')); *q++ = 0x7f; /* DVB extension descriptor */ *q++ = 2; @@ -618,37 +603,24 @@ static int mpegts_write_pmt(AVFormatContext *s, MpegTSService *service) break; case AVMEDIA_TYPE_VIDEO: if (stream_type == STREAM_TYPE_VIDEO_DIRAC) { - *q++ = 0x05; /*MPEG-2 registration descriptor*/ - *q++ = 4; - *q++ = 'd'; - *q++ = 'r'; - *q++ = 'a'; - *q++ = 'c'; + put_registration_descriptor(&q, MKTAG('d', 'r', 'a', 'c')); } else if (stream_type == STREAM_TYPE_VIDEO_VC1) { - *q++ = 0x05; /*MPEG-2 registration descriptor*/ - *q++ = 4; - *q++ = 'V'; - *q++ = 'C'; - *q++ = '-'; - *q++ = '1'; + put_registration_descriptor(&q, MKTAG('V', 'C', '-', '1')); + } else if (stream_type == STREAM_TYPE_VIDEO_HEVC && s->strict_std_compliance <= FF_COMPLIANCE_NORMAL) { + put_registration_descriptor(&q, MKTAG('H', 'E', 'V', 'C')); } break; case AVMEDIA_TYPE_DATA: if (st->codecpar->codec_id == AV_CODEC_ID_SMPTE_KLV) { - *q++ = 0x05; /* MPEG-2 registration descriptor */ - *q++ = 4; - *q++ = 'K'; - *q++ = 'L'; - *q++ = 'V'; - *q++ = 'A'; + put_registration_descriptor(&q, MKTAG('K', 'L', 'V', 'A')); } else if (st->codecpar->codec_id == AV_CODEC_ID_TIMED_ID3) { const char *tag = "ID3 "; *q++ = 0x26; /* metadata descriptor */ *q++ = 13; put16(&q, 0xffff); /* metadata application format */ - putstr8(&q, tag, 0); + putbuf(&q, tag, strlen(tag)); *q++ = 0xff; /* metadata format */ - putstr8(&q, tag, 0); + putbuf(&q, tag, strlen(tag)); *q++ = 0; /* metadata service ID */ *q++ = 0xF; /* metadata_locator_record_flag|MPEG_carriage_flags|reserved */ } @@ -695,8 +667,8 @@ static void mpegts_write_sdt(AVFormatContext *s) desc_len_ptr = q; q++; *q++ = ts->service_type; - putstr8(&q, service->provider_name, 1); - putstr8(&q, service->name, 1); + putbuf(&q, service->provider_name, service->provider_name[0] + 1); + putbuf(&q, service->name, service->name[0] + 1); desc_len_ptr[0] = q - desc_len_ptr - 1; /* fill descriptor length */ @@ -709,10 +681,47 @@ static void mpegts_write_sdt(AVFormatContext *s) data, q - data); } -static MpegTSService *mpegts_add_service(MpegTSWrite *ts, int sid, +/* This stores a string in buf with the correct encoding and also sets the + * first byte as the length. !str is accepted for an empty string. + * If the string is already encoded, invalid UTF-8 or has no multibyte sequence + * then we keep it as is, otherwise we signal UTF-8 encoding. */ +static int encode_str8(uint8_t *buf, const char *str) +{ + size_t str_len; + if (!str) + str = ""; + str_len = strlen(str); + if (str[0] && (unsigned)str[0] >= 0x20) { /* Make sure the string is not already encoded. */ + const uint8_t *q = str; + int has_multibyte = 0; + while (*q) { + uint32_t code; + GET_UTF8(code, *q++, goto invalid;) /* Is it valid UTF-8? */ + has_multibyte |= (code > 127); /* Does it have multibyte UTF-8 chars in it? */ + } + if (has_multibyte) { /* If we have multibyte chars and valid UTF-8, then encode as such! */ + if (str_len > 254) + return AVERROR(EINVAL); + buf[0] = str_len + 1; + buf[1] = 0x15; + memcpy(&buf[2], str, str_len); + return 0; + } + } +invalid: + /* Otherwise let's just encode the string as is! */ + if (str_len > 255) + return AVERROR(EINVAL); + buf[0] = str_len; + memcpy(&buf[1], str, str_len); + return 0; +} + +static MpegTSService *mpegts_add_service(AVFormatContext *s, int sid, const char *provider_name, const char *name) { + MpegTSWrite *ts = s->priv_data; MpegTSService *service; service = av_mallocz(sizeof(MpegTSService)); @@ -721,17 +730,16 @@ static MpegTSService *mpegts_add_service(MpegTSWrite *ts, int sid, service->pmt.pid = ts->pmt_start_pid + ts->nb_services; service->sid = sid; service->pcr_pid = 0x1fff; - service->provider_name = av_strdup(provider_name); - service->name = av_strdup(name); - if (!service->provider_name || !service->name) + if (encode_str8(service->provider_name, provider_name) < 0 || + encode_str8(service->name, name) < 0) { + av_log(s, AV_LOG_ERROR, "Too long service or provider name\n"); goto fail; + } if (av_dynarray_add_nofree(&ts->services, &ts->nb_services, service) < 0) goto fail; return service; fail: - av_freep(&service->provider_name); - av_freep(&service->name); av_free(service); return NULL; } @@ -790,7 +798,7 @@ static int mpegts_init(AVFormatContext *s) service_name = title ? title->value : DEFAULT_SERVICE_NAME; provider = av_dict_get(s->metadata, "service_provider", NULL, 0); provider_name = provider ? provider->value : DEFAULT_PROVIDER_NAME; - service = mpegts_add_service(ts, ts->service_id, + service = mpegts_add_service(s, ts->service_id, provider_name, service_name); if (!service) @@ -809,7 +817,7 @@ static int mpegts_init(AVFormatContext *s) service_name = title ? title->value : DEFAULT_SERVICE_NAME; provider = av_dict_get(program->metadata, "service_provider", NULL, 0); provider_name = provider ? provider->value : DEFAULT_PROVIDER_NAME; - service = mpegts_add_service(ts, program->id, + service = mpegts_add_service(s, program->id, provider_name, service_name); if (!service) @@ -1523,7 +1531,7 @@ static int mpegts_write_packet_internal(AVFormatContext *s, AVPacket *pkt) int64_t dts = pkt->dts, pts = pkt->pts; int opus_samples = 0; int side_data_size; - char *side_data = NULL; + uint8_t *side_data = NULL; int stream_id = -1; side_data = av_packet_get_side_data(pkt, @@ -1839,8 +1847,6 @@ static void mpegts_deinit(AVFormatContext *s) for (i = 0; i < ts->nb_services; i++) { service = ts->services[i]; - av_freep(&service->provider_name); - av_freep(&service->name); av_freep(&service); } av_freep(&ts->services); @@ -1983,6 +1989,6 @@ AVOutputFormat ff_mpegts_muxer = { .write_trailer = mpegts_write_end, .deinit = mpegts_deinit, .check_bitstream = mpegts_check_bitstream, - .flags = AVFMT_ALLOW_FLUSH | AVFMT_VARIABLE_FPS, + .flags = AVFMT_ALLOW_FLUSH | AVFMT_VARIABLE_FPS | AVFMT_NODIMENSIONS, .priv_class = &mpegts_muxer_class, }; diff --git a/libavformat/mpegvideodec.c b/libavformat/mpegvideodec.c index aca962123..2d6f81aaa 100644 --- a/libavformat/mpegvideodec.c +++ b/libavformat/mpegvideodec.c @@ -34,7 +34,7 @@ #define VIDEO_ID 0x000001e0 #define AUDIO_ID 0x000001c0 -static int mpegvideo_probe(AVProbeData *p) +static int mpegvideo_probe(const AVProbeData *p) { uint32_t code= -1; int pic=0, seq=0, slice=0, pspack=0, vpes=0, apes=0, res=0, sicle=0; diff --git a/libavformat/mpjpegdec.c b/libavformat/mpjpegdec.c index 83aa70d0c..e653b5cc9 100644 --- a/libavformat/mpjpegdec.c +++ b/libavformat/mpjpegdec.c @@ -111,7 +111,7 @@ static int mpjpeg_read_close(AVFormatContext *s) return 0; } -static int mpjpeg_read_probe(AVProbeData *p) +static int mpjpeg_read_probe(const AVProbeData *p) { AVIOContext *pb; int ret = 0; @@ -375,7 +375,7 @@ static int mpjpeg_read_packet(AVFormatContext *s, AVPacket *pkt) #define OFFSET(x) offsetof(MPJPEGDemuxContext, x) #define DEC AV_OPT_FLAG_DECODING_PARAM -const AVOption mpjpeg_options[] = { +static const AVOption mpjpeg_options[] = { { "strict_mime_boundary", "require MIME boundaries match", OFFSET(strict_mime_boundary), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, DEC }, { NULL } }; diff --git a/libavformat/mpl2dec.c b/libavformat/mpl2dec.c index dfcdf5a56..4ae18390f 100644 --- a/libavformat/mpl2dec.c +++ b/libavformat/mpl2dec.c @@ -33,7 +33,7 @@ typedef struct { FFDemuxSubtitlesQueue q; } MPL2Context; -static int mpl2_probe(AVProbeData *p) +static int mpl2_probe(const AVProbeData *p) { int i; char c; diff --git a/libavformat/mpsubdec.c b/libavformat/mpsubdec.c index 1236efa71..4ff49ba3c 100644 --- a/libavformat/mpsubdec.c +++ b/libavformat/mpsubdec.c @@ -31,7 +31,7 @@ typedef struct { FFDemuxSubtitlesQueue q; } MPSubContext; -static int mpsub_probe(AVProbeData *p) +static int mpsub_probe(const AVProbeData *p) { const char *ptr = p->buf; const char *ptr_end = p->buf + p->buf_size; diff --git a/libavformat/msf.c b/libavformat/msf.c index 6bd18f29b..155f488e4 100644 --- a/libavformat/msf.c +++ b/libavformat/msf.c @@ -23,7 +23,7 @@ #include "avformat.h" #include "internal.h" -static int msf_probe(AVProbeData *p) +static int msf_probe(const AVProbeData *p) { if (memcmp(p->buf, "MSF", 3)) return 0; diff --git a/libavformat/msnwc_tcp.c b/libavformat/msnwc_tcp.c index 3c73ac7b2..650f0d271 100644 --- a/libavformat/msnwc_tcp.c +++ b/libavformat/msnwc_tcp.c @@ -36,7 +36,7 @@ * uint32_t ts; // time */ -static int msnwc_tcp_probe(AVProbeData *p) +static int msnwc_tcp_probe(const AVProbeData *p) { int i; diff --git a/libavformat/mtaf.c b/libavformat/mtaf.c index b25c2aa40..8764a43a7 100644 --- a/libavformat/mtaf.c +++ b/libavformat/mtaf.c @@ -24,7 +24,7 @@ #include "avformat.h" #include "internal.h" -static int mtaf_probe(AVProbeData *p) +static int mtaf_probe(const AVProbeData *p) { if (p->buf_size < 0x44) return 0; diff --git a/libavformat/mtv.c b/libavformat/mtv.c index dcf4aa428..728f4a478 100644 --- a/libavformat/mtv.c +++ b/libavformat/mtv.c @@ -51,7 +51,7 @@ typedef struct MTVDemuxContext { } MTVDemuxContext; -static int mtv_probe(AVProbeData *p) +static int mtv_probe(const AVProbeData *p) { /* we need at least 57 bytes from the header * to try parsing all required fields diff --git a/libavformat/musx.c b/libavformat/musx.c index aff6c31a8..8537eb7e7 100644 --- a/libavformat/musx.c +++ b/libavformat/musx.c @@ -23,7 +23,7 @@ #include "avformat.h" #include "internal.h" -static int musx_probe(AVProbeData *p) +static int musx_probe(const AVProbeData *p) { if (memcmp(p->buf, "MUSX", 4)) return 0; diff --git a/libavformat/mux.c b/libavformat/mux.c index a13f0e3a1..8ab5ea8c2 100644 --- a/libavformat/mux.c +++ b/libavformat/mux.c @@ -145,7 +145,7 @@ enum AVChromaLocation ff_choose_chroma_location(AVFormatContext *s, AVStream *st } -int avformat_alloc_output_context2(AVFormatContext **avctx, AVOutputFormat *oformat, +int avformat_alloc_output_context2(AVFormatContext **avctx, ff_const59 AVOutputFormat *oformat, const char *format, const char *filename) { AVFormatContext *s = avformat_alloc_context(); @@ -246,7 +246,7 @@ static int init_muxer(AVFormatContext *s, AVDictionary **options) AVStream *st; AVDictionary *tmp = NULL; AVCodecParameters *par = NULL; - AVOutputFormat *of = s->oformat; + const AVOutputFormat *of = s->oformat; const AVCodecDescriptor *desc; AVDictionaryEntry *e; @@ -571,7 +571,7 @@ static int compute_muxer_pkt_fields(AVFormatContext *s, AVStream *st, AVPacket * } if (s->debug & FF_FDEBUG_TS) - av_log(s, AV_LOG_TRACE, "compute_muxer_pkt_fields: pts:%s dts:%s cur_dts:%s b:%d size:%d st:%d\n", + av_log(s, AV_LOG_DEBUG, "compute_muxer_pkt_fields: pts:%s dts:%s cur_dts:%s b:%d size:%d st:%d\n", av_ts2str(pkt->pts), av_ts2str(pkt->dts), av_ts2str(st->cur_dts), delay, pkt->size, pkt->stream_index); if (pkt->duration < 0 && st->codecpar->codec_type != AVMEDIA_TYPE_SUBTITLE) { @@ -633,7 +633,7 @@ static int compute_muxer_pkt_fields(AVFormatContext *s, AVStream *st, AVPacket * } if (s->debug & FF_FDEBUG_TS) - av_log(s, AV_LOG_TRACE, "av_write_frame: pts2:%s dts2:%s\n", + av_log(s, AV_LOG_DEBUG, "av_write_frame: pts2:%s dts2:%s\n", av_ts2str(pkt->pts), av_ts2str(pkt->dts)); st->cur_dts = pkt->dts; @@ -865,7 +865,7 @@ static int do_packet_auto_bsf(AVFormatContext *s, AVPacket *pkt) { if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) return 0; av_log(ctx, AV_LOG_ERROR, - "Failed to send packet to filter %s for stream %d\n", + "Failed to receive packet from filter %s for stream %d\n", ctx->filter->name, pkt->stream_index); if (s->error_recognition & AV_EF_EXPLODE) return ret; @@ -1001,15 +1001,22 @@ static int interleave_compare_dts(AVFormatContext *s, AVPacket *next, AVStream *st2 = s->streams[next->stream_index]; int comp = av_compare_ts(next->dts, st2->time_base, pkt->dts, st->time_base); - if (s->audio_preload && ((st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) != (st2->codecpar->codec_type == AVMEDIA_TYPE_AUDIO))) { - int64_t ts = av_rescale_q(pkt ->dts, st ->time_base, AV_TIME_BASE_Q) - s->audio_preload*(st ->codecpar->codec_type == AVMEDIA_TYPE_AUDIO); - int64_t ts2= av_rescale_q(next->dts, st2->time_base, AV_TIME_BASE_Q) - s->audio_preload*(st2->codecpar->codec_type == AVMEDIA_TYPE_AUDIO); - if (ts == ts2) { - ts= ( pkt ->dts* st->time_base.num*AV_TIME_BASE - s->audio_preload*(int64_t)(st ->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)* st->time_base.den)*st2->time_base.den - -( next->dts*st2->time_base.num*AV_TIME_BASE - s->audio_preload*(int64_t)(st2->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)*st2->time_base.den)* st->time_base.den; - ts2=0; + if (s->audio_preload) { + int preload = st ->codecpar->codec_type == AVMEDIA_TYPE_AUDIO; + int preload2 = st2->codecpar->codec_type == AVMEDIA_TYPE_AUDIO; + if (preload != preload2) { + int64_t ts, ts2; + preload *= s->audio_preload; + preload2 *= s->audio_preload; + ts = av_rescale_q(pkt ->dts, st ->time_base, AV_TIME_BASE_Q) - preload; + ts2= av_rescale_q(next->dts, st2->time_base, AV_TIME_BASE_Q) - preload2; + if (ts == ts2) { + ts = ((uint64_t)pkt ->dts*st ->time_base.num*AV_TIME_BASE - (uint64_t)preload *st ->time_base.den)*st2->time_base.den + - ((uint64_t)next->dts*st2->time_base.num*AV_TIME_BASE - (uint64_t)preload2*st2->time_base.den)*st ->time_base.den; + ts2 = 0; + } + comp = (ts2 > ts) - (ts2 < ts); } - comp= (ts>ts2) - (tsdebug & FF_FDEBUG_TS) - av_log(s, AV_LOG_TRACE, "av_interleaved_write_frame size:%d dts:%s pts:%s\n", + av_log(s, AV_LOG_DEBUG, "av_interleaved_write_frame size:%d dts:%s pts:%s\n", pkt->size, av_ts2str(pkt->dts), av_ts2str(pkt->pts)); #if FF_API_COMPUTE_PKT_FIELDS2 && FF_API_LAVF_AVCTX diff --git a/libavformat/mvdec.c b/libavformat/mvdec.c index fa596179e..4f75dcacd 100644 --- a/libavformat/mvdec.c +++ b/libavformat/mvdec.c @@ -46,7 +46,7 @@ typedef struct MvContext { #define AUDIO_FORMAT_SIGNED 401 -static int mv_probe(AVProbeData *p) +static int mv_probe(const AVProbeData *p) { if (AV_RB32(p->buf) == MKBETAG('M', 'O', 'V', 'I') && AV_RB16(p->buf + 4) < 3) diff --git a/libavformat/mxf.c b/libavformat/mxf.c index a909401f0..451cbcfb2 100644 --- a/libavformat/mxf.c +++ b/libavformat/mxf.c @@ -28,6 +28,7 @@ const MXFCodecUL ff_mxf_data_definition_uls[] = { { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x01,0x03,0x02,0x02,0x01,0x00,0x00,0x00 }, 13, AVMEDIA_TYPE_VIDEO }, { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x01,0x03,0x02,0x02,0x02,0x00,0x00,0x00 }, 13, AVMEDIA_TYPE_AUDIO }, + { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x01,0x03,0x02,0x02,0x03,0x00,0x00,0x00 }, 13, AVMEDIA_TYPE_DATA }, { { 0x80,0x7D,0x00,0x60,0x08,0x14,0x3E,0x6F,0x6F,0x3C,0x8C,0xE1,0x6C,0xEF,0x11,0xD2 }, 16, AVMEDIA_TYPE_VIDEO }, /* LegacyPicture Avid Media Composer MXF */ { { 0x80,0x7D,0x00,0x60,0x08,0x14,0x3E,0x6F,0x78,0xE1,0xEB,0xE1,0x6C,0xEF,0x11,0xD2 }, 16, AVMEDIA_TYPE_AUDIO }, /* LegacySound Avid Media Composer MXF */ { { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, 0, AVMEDIA_TYPE_DATA }, @@ -134,7 +135,7 @@ static const MXFSamplesPerFrame mxf_spf[] = { { { 1001, 24000 }, { 2002, 0, 0, 0, 0, 0 } }, // FILM 23.976 { { 1, 24}, { 2000, 0, 0, 0, 0, 0 } }, // FILM 24 { { 1001, 30000 }, { 1602, 1601, 1602, 1601, 1602, 0 } }, // NTSC 29.97 - { { 1001, 60000 }, { 801, 801, 801, 801, 800, 0 } }, // NTSC 59.94 + { { 1001, 60000 }, { 801, 801, 800, 801, 801, 0 } }, // NTSC 59.94 { { 1, 25 }, { 1920, 0, 0, 0, 0, 0 } }, // PAL 25 { { 1, 50 }, { 960, 0, 0, 0, 0, 0 } }, // PAL 50 { { 1, 60 }, { 800, 0, 0, 0, 0, 0 } }, @@ -171,3 +172,20 @@ const MXFSamplesPerFrame *ff_mxf_get_samples_per_frame(AVFormatContext *s, return &mxf_spf[idx]; } + +static const int mxf_content_package_rates[] = { + 3, 2, 7, 13, 4, 10, 12, +}; + +int ff_mxf_get_content_package_rate(AVRational time_base) +{ + int idx = av_find_nearest_q_idx(time_base, mxf_time_base); + AVRational diff = av_sub_q(time_base, mxf_time_base[idx]); + + diff.num = FFABS(diff.num); + + if (av_cmp_q(diff, (AVRational){1, 1000}) >= 0) + return -1; + + return mxf_content_package_rates[idx]; +} diff --git a/libavformat/mxf.h b/libavformat/mxf.h index ffcc429a8..f32124f77 100644 --- a/libavformat/mxf.h +++ b/libavformat/mxf.h @@ -48,6 +48,7 @@ enum MXFMetadataSetType { EssenceGroup, TaggedValue, TapeDescriptor, + AVCSubDescriptor, }; enum MXFFrameLayout { @@ -62,12 +63,23 @@ typedef struct KLVPacket { UID key; int64_t offset; uint64_t length; + int64_t next_klv; } KLVPacket; +typedef enum { + NormalWrap = 0, + D10D11Wrap, + RawAWrap, + RawVWrap +} MXFWrappingIndicatorType; + typedef struct MXFCodecUL { UID uid; unsigned matching_len; int id; + const char *desc; + unsigned wrapping_indicator_pos; + MXFWrappingIndicatorType wrapping_indicator_type; } MXFCodecUL; typedef struct { @@ -82,6 +94,8 @@ extern const MXFCodecUL ff_mxf_codec_tag_uls[]; int ff_mxf_decode_pixel_layout(const char pixel_layout[16], enum AVPixelFormat *pix_fmt); const MXFSamplesPerFrame *ff_mxf_get_samples_per_frame(AVFormatContext *s, AVRational time_base); +int ff_mxf_get_content_package_rate(AVRational time_base); + #define PRIxUID \ "%02x.%02x.%02x.%02x." \ diff --git a/libavformat/mxfdec.c b/libavformat/mxfdec.c index c78e272a7..397f820b3 100644 --- a/libavformat/mxfdec.c +++ b/libavformat/mxfdec.c @@ -52,10 +52,13 @@ #include "libavutil/intreadwrite.h" #include "libavutil/parseutils.h" #include "libavutil/timecode.h" +#include "libavutil/opt.h" #include "avformat.h" #include "internal.h" #include "mxf.h" +#define MXF_MAX_CHUNK_SIZE (32 << 20) + typedef enum { Header, BodyPartition, @@ -76,6 +79,12 @@ typedef enum { OPSONYOpt, /* FATE sample, violates the spec in places */ } MXFOP; +typedef enum { + UnknownWrapped = 0, + FrameWrapped, + ClipWrapped, +} MXFWrappingScheme; + typedef struct MXFPartition { int closed; int complete; @@ -92,6 +101,7 @@ typedef struct MXFPartition { int pack_length; int64_t pack_ofs; ///< absolute offset of pack in file, including run-in int64_t body_offset; + KLVPacket first_essence_klv; } MXFPartition; typedef struct MXFCryptoContext { @@ -165,6 +175,8 @@ typedef struct { int64_t original_duration; /* st->duration in SampleRate/EditRate units */ int index_sid; int body_sid; + MXFWrappingScheme wrapping; + int edit_units_per_packet; /* how many edit units to read at a time (PCM, ClipWrapped) */ } MXFTrack; typedef struct MXFDescriptor { @@ -254,6 +266,7 @@ typedef struct MXFIndexTable { } MXFIndexTable; typedef struct MXFContext { + const AVClass *class; /**< Class for private options. */ MXFPartition *partitions; unsigned partitions_count; MXFOP op; @@ -269,23 +282,16 @@ typedef struct MXFContext { int local_tags_count; uint64_t footer_partition; KLVPacket current_klv_data; - int current_klv_index; int run_in; MXFPartition *current_partition; int parsing_backward; int64_t last_forward_tell; int last_forward_partition; - int64_t current_edit_unit; int nb_index_tables; MXFIndexTable *index_tables; - int edit_units_per_packet; ///< how many edit units to read at a time (PCM, OPAtom) + int eia608_extract; } MXFContext; -enum MXFWrappingScheme { - Frame, - Clip, -}; - /* NOTE: klv_offset is not set (-1) for local keys */ typedef int MXFMetadataReadFunc(void *arg, AVIOContext *pb, int tag, int size, UID uid, int64_t klv_offset); @@ -372,6 +378,8 @@ static int64_t klv_decode_ber_length(AVIOContext *pb) while (bytes_num--) size = size << 8 | avio_r8(pb); } + if (size > INT64_MAX) + return AVERROR_INVALIDDATA; return size; } @@ -390,13 +398,21 @@ static int mxf_read_sync(AVIOContext *pb, const uint8_t *key, unsigned size) static int klv_read_packet(KLVPacket *klv, AVIOContext *pb) { + int64_t length, pos; if (!mxf_read_sync(pb, mxf_klv_key, 4)) return AVERROR_INVALIDDATA; klv->offset = avio_tell(pb) - 4; memcpy(klv->key, mxf_klv_key, 4); avio_read(pb, klv->key + 4, 12); - klv->length = klv_decode_ber_length(pb); - return klv->length == -1 ? -1 : 0; + length = klv_decode_ber_length(pb); + if (length < 0) + return length; + klv->length = length; + pos = avio_tell(pb); + if (pos > INT64_MAX - length) + return AVERROR_INVALIDDATA; + klv->next_klv = pos + length; + return 0; } static int mxf_get_stream_index(AVFormatContext *s, KLVPacket *klv, int body_sid) @@ -410,22 +426,22 @@ static int mxf_get_stream_index(AVFormatContext *s, KLVPacket *klv, int body_sid return i; } /* return 0 if only one stream, for OP Atom files with 0 as track number */ - return s->nb_streams == 1 ? 0 : -1; + return s->nb_streams == 1 && s->streams[0]->priv_data ? 0 : -1; } -static int find_body_sid_by_offset(MXFContext *mxf, int64_t offset) +static int find_body_sid_by_absolute_offset(MXFContext *mxf, int64_t offset) { // we look for partition where the offset is placed int a, b, m; - int64_t this_partition; + int64_t pack_ofs; a = -1; b = mxf->partitions_count; while (b - a > 1) { - m = (a + b) >> 1; - this_partition = mxf->partitions[m].this_partition; - if (this_partition <= offset) + m = (a + b) >> 1; + pack_ofs = mxf->partitions[m].pack_ofs; + if (pack_ofs <= offset) a = m; else b = m; @@ -436,6 +452,81 @@ static int find_body_sid_by_offset(MXFContext *mxf, int64_t offset) return mxf->partitions[a].body_sid; } +static int mxf_get_eia608_packet(AVFormatContext *s, AVStream *st, AVPacket *pkt, int64_t length) +{ + int count = avio_rb16(s->pb); + int cdp_identifier, cdp_length, cdp_footer_id, ccdata_id, cc_count; + int line_num, sample_coding, sample_count; + int did, sdid, data_length; + int i, ret; + + if (count != 1) + av_log(s, AV_LOG_WARNING, "unsupported multiple ANC packets (%d) per KLV packet\n", count); + + for (i = 0; i < count; i++) { + if (length < 6) { + av_log(s, AV_LOG_ERROR, "error reading s436m packet %"PRId64"\n", length); + return AVERROR_INVALIDDATA; + } + line_num = avio_rb16(s->pb); + avio_r8(s->pb); // wrapping type + sample_coding = avio_r8(s->pb); + sample_count = avio_rb16(s->pb); + length -= 6 + 8 + sample_count; + if (line_num != 9 && line_num != 11) + continue; + if (sample_coding == 7 || sample_coding == 8 || sample_coding == 9) { + av_log(s, AV_LOG_WARNING, "unsupported s436m 10 bit sample coding\n"); + continue; + } + if (length < 0) + return AVERROR_INVALIDDATA; + + avio_rb32(s->pb); // array count + avio_rb32(s->pb); // array elem size + did = avio_r8(s->pb); + sdid = avio_r8(s->pb); + data_length = avio_r8(s->pb); + if (did != 0x61 || sdid != 1) { + av_log(s, AV_LOG_WARNING, "unsupported did or sdid: %x %x\n", did, sdid); + continue; + } + cdp_identifier = avio_rb16(s->pb); // cdp id + if (cdp_identifier != 0x9669) { + av_log(s, AV_LOG_ERROR, "wrong cdp identifier %x\n", cdp_identifier); + return AVERROR_INVALIDDATA; + } + cdp_length = avio_r8(s->pb); + avio_r8(s->pb); // cdp_frame_rate + avio_r8(s->pb); // cdp_flags + avio_rb16(s->pb); // cdp_hdr_sequence_cntr + ccdata_id = avio_r8(s->pb); // ccdata_id + if (ccdata_id != 0x72) { + av_log(s, AV_LOG_ERROR, "wrong cdp data section %x\n", ccdata_id); + return AVERROR_INVALIDDATA; + } + cc_count = avio_r8(s->pb) & 0x1f; + ret = av_get_packet(s->pb, pkt, cc_count * 3); + if (ret < 0) + return ret; + if (cdp_length - 9 - 4 < cc_count * 3) { + av_log(s, AV_LOG_ERROR, "wrong cdp size %d cc count %d\n", cdp_length, cc_count); + return AVERROR_INVALIDDATA; + } + avio_skip(s->pb, data_length - 9 - 4 - cc_count * 3); + cdp_footer_id = avio_r8(s->pb); + if (cdp_footer_id != 0x74) { + av_log(s, AV_LOG_ERROR, "wrong cdp footer section %x\n", cdp_footer_id); + return AVERROR_INVALIDDATA; + } + avio_rb16(s->pb); // cdp_ftr_sequence_cntr + avio_r8(s->pb); // packet_checksum + break; + } + + return 0; +} + /* XXX: use AVBitStreamFilter */ static int mxf_get_d10_aes3_packet(AVIOContext *pb, AVStream *st, AVPacket *pkt, int64_t length) { @@ -486,7 +577,10 @@ static int mxf_decrypt_triplet(AVFormatContext *s, AVPacket *pkt, KLVPacket *klv av_aes_init(mxf->aesc, s->key, 128, 1); } // crypto context - avio_skip(pb, klv_decode_ber_length(pb)); + size = klv_decode_ber_length(pb); + if (size < 0) + return size; + avio_skip(pb, size); // plaintext offset klv_decode_ber_length(pb); plaintext_size = avio_rb64(pb); @@ -496,7 +590,7 @@ static int mxf_decrypt_triplet(AVFormatContext *s, AVPacket *pkt, KLVPacket *klv if (!IS_KLV_KEY(klv, mxf_essence_element_key)) return AVERROR_INVALIDDATA; - body_sid = find_body_sid_by_offset(mxf, klv->offset); + body_sid = find_body_sid_by_absolute_offset(mxf, klv->offset); index = mxf_get_stream_index(s, klv, body_sid); if (index < 0) return AVERROR_INVALIDDATA; @@ -560,6 +654,7 @@ static int mxf_read_primer_pack(void *arg, AVIOContext *pb, int tag, int size, U static int mxf_read_partition_pack(void *arg, AVIOContext *pb, int tag, int size, UID uid, int64_t klv_offset) { MXFContext *mxf = arg; + AVFormatContext *s = mxf->fc; MXFPartition *partition, *tmp_part; UID op; uint64_t footer_partition; @@ -624,6 +719,12 @@ static int mxf_read_partition_pack(void *arg, AVIOContext *pb, int tag, int size } nb_essence_containers = avio_rb32(pb); + if (partition->type == Header) { + char str[36]; + snprintf(str, sizeof(str), "%08x.%08x.%08x.%08x", AV_RB32(&op[0]), AV_RB32(&op[4]), AV_RB32(&op[8]), AV_RB32(&op[12])); + av_dict_set(&s->metadata, "operational_pattern_ul", str, 0); + } + if (partition->this_partition && partition->previous_partition == partition->this_partition) { av_log(mxf->fc, AV_LOG_ERROR, @@ -1220,15 +1321,21 @@ static void *mxf_resolve_strong_ref(MXFContext *mxf, UID *strong_ref, enum MXFMe static const MXFCodecUL mxf_picture_essence_container_uls[] = { // video essence container uls - { { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x07,0x0d,0x01,0x03,0x01,0x02,0x0c,0x01,0x00 }, 14, AV_CODEC_ID_JPEG2000 }, - { { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x02,0x0d,0x01,0x03,0x01,0x02,0x10,0x60,0x01 }, 14, AV_CODEC_ID_H264 }, /* H.264 frame wrapped */ - { { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x02,0x0d,0x01,0x03,0x01,0x02,0x12,0x01,0x00 }, 14, AV_CODEC_ID_VC1 }, /* VC-1 frame wrapped */ - { { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x02,0x0d,0x01,0x03,0x01,0x02,0x04,0x60,0x01 }, 14, AV_CODEC_ID_MPEG2VIDEO }, /* MPEG-ES frame wrapped */ - { { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x01,0x0d,0x01,0x03,0x01,0x02,0x01,0x04,0x01 }, 14, AV_CODEC_ID_MPEG2VIDEO }, /* Type D-10 mapping of 40Mbps 525/60-I */ - { { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x01,0x0d,0x01,0x03,0x01,0x02,0x02,0x41,0x01 }, 14, AV_CODEC_ID_DVVIDEO }, /* DV 625 25mbps */ - { { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x01,0x0d,0x01,0x03,0x01,0x02,0x05,0x00,0x00 }, 14, AV_CODEC_ID_RAWVIDEO }, /* uncompressed picture */ + { { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x07,0x0d,0x01,0x03,0x01,0x02,0x0c,0x01,0x00 }, 14, AV_CODEC_ID_JPEG2000, NULL, 14 }, + { { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x02,0x0d,0x01,0x03,0x01,0x02,0x10,0x60,0x01 }, 14, AV_CODEC_ID_H264, NULL, 15 }, /* H.264 */ + { { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x02,0x0d,0x01,0x03,0x01,0x02,0x11,0x01,0x00 }, 14, AV_CODEC_ID_DNXHD, NULL, 14 }, /* VC-3 */ + { { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x02,0x0d,0x01,0x03,0x01,0x02,0x12,0x01,0x00 }, 14, AV_CODEC_ID_VC1, NULL, 14 }, /* VC-1 */ + { { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x02,0x0d,0x01,0x03,0x01,0x02,0x14,0x01,0x00 }, 14, AV_CODEC_ID_TIFF, NULL, 14 }, /* TIFF */ + { { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x02,0x0d,0x01,0x03,0x01,0x02,0x15,0x01,0x00 }, 14, AV_CODEC_ID_DIRAC, NULL, 14 }, /* VC-2 */ + { { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x02,0x0d,0x01,0x03,0x01,0x02,0x1b,0x01,0x00 }, 14, AV_CODEC_ID_CFHD, NULL, 14 }, /* VC-5 */ + { { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x02,0x0d,0x01,0x03,0x01,0x02,0x1c,0x01,0x00 }, 14, AV_CODEC_ID_PRORES, NULL, 14 }, /* ProRes */ + { { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x02,0x0d,0x01,0x03,0x01,0x02,0x04,0x60,0x01 }, 14, AV_CODEC_ID_MPEG2VIDEO, NULL, 15 }, /* MPEG-ES */ + { { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x01,0x0d,0x01,0x03,0x01,0x02,0x01,0x04,0x01 }, 14, AV_CODEC_ID_MPEG2VIDEO, NULL, 15, D10D11Wrap }, /* SMPTE D-10 mapping */ + { { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x01,0x0d,0x01,0x03,0x01,0x02,0x02,0x41,0x01 }, 14, AV_CODEC_ID_DVVIDEO, NULL, 15 }, /* DV 625 25mbps */ + { { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x01,0x0d,0x01,0x03,0x01,0x02,0x05,0x00,0x00 }, 14, AV_CODEC_ID_RAWVIDEO, NULL, 15, RawVWrap }, /* uncompressed picture */ { { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0a,0x0e,0x0f,0x03,0x01,0x02,0x20,0x01,0x01 }, 15, AV_CODEC_ID_HQ_HQA }, { { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0a,0x0e,0x0f,0x03,0x01,0x02,0x20,0x02,0x01 }, 15, AV_CODEC_ID_HQX }, + { { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0a,0x0e,0x15,0x00,0x04,0x02,0x10,0x00,0x01 }, 16, AV_CODEC_ID_HEVC, NULL, 15 }, /* Canon XF-HEVC */ { { 0x06,0x0e,0x2b,0x34,0x01,0x01,0x01,0xff,0x4b,0x46,0x41,0x41,0x00,0x0d,0x4d,0x4f }, 14, AV_CODEC_ID_RAWVIDEO }, /* Legacy ?? Uncompressed Picture */ { { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, 0, AV_CODEC_ID_NONE }, }; @@ -1257,22 +1364,54 @@ static const MXFCodecUL mxf_intra_only_picture_coded_width[] = { static const MXFCodecUL mxf_sound_essence_container_uls[] = { // sound essence container uls - { { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x01,0x0d,0x01,0x03,0x01,0x02,0x06,0x01,0x00 }, 14, AV_CODEC_ID_PCM_S16LE }, /* BWF Frame wrapped */ - { { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x02,0x0d,0x01,0x03,0x01,0x02,0x04,0x40,0x01 }, 14, AV_CODEC_ID_MP2 }, /* MPEG-ES Frame wrapped, 0x40 ??? stream id */ - { { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x01,0x0d,0x01,0x03,0x01,0x02,0x01,0x01,0x01 }, 14, AV_CODEC_ID_PCM_S16LE }, /* D-10 Mapping 50Mbps PAL Extended Template */ + { { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x01,0x0d,0x01,0x03,0x01,0x02,0x06,0x01,0x00 }, 14, AV_CODEC_ID_PCM_S16LE, NULL, 14, RawAWrap }, /* BWF */ + { { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x02,0x0d,0x01,0x03,0x01,0x02,0x04,0x40,0x01 }, 14, AV_CODEC_ID_MP2, NULL, 15 }, /* MPEG-ES */ + { { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x01,0x0d,0x01,0x03,0x01,0x02,0x01,0x01,0x01 }, 14, AV_CODEC_ID_PCM_S16LE, NULL, 13 }, /* D-10 Mapping 50Mbps PAL Extended Template */ { { 0x06,0x0e,0x2b,0x34,0x01,0x01,0x01,0xff,0x4b,0x46,0x41,0x41,0x00,0x0d,0x4d,0x4F }, 14, AV_CODEC_ID_PCM_S16LE }, /* 0001GL00.MXF.A1.mxf_opatom.mxf */ { { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x03,0x04,0x02,0x02,0x02,0x03,0x03,0x01,0x00 }, 14, AV_CODEC_ID_AAC }, /* MPEG-2 AAC ADTS (legacy) */ { { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, 0, AV_CODEC_ID_NONE }, }; static const MXFCodecUL mxf_data_essence_container_uls[] = { - { { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x09,0x0d,0x01,0x03,0x01,0x02,0x0e,0x00,0x00 }, 16, 0 }, + { { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x09,0x0d,0x01,0x03,0x01,0x02,0x0d,0x00,0x00 }, 16, AV_CODEC_ID_NONE, "vbi_smpte_436M", 11 }, + { { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x09,0x0d,0x01,0x03,0x01,0x02,0x0e,0x00,0x00 }, 16, AV_CODEC_ID_NONE, "vbi_vanc_smpte_436M", 11 }, + { { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x09,0x0d,0x01,0x03,0x01,0x02,0x13,0x01,0x01 }, 16, AV_CODEC_ID_TTML }, { { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, 0, AV_CODEC_ID_NONE }, }; -static const char * const mxf_data_essence_descriptor[] = { - "vbi_vanc_smpte_436M", -}; +static MXFWrappingScheme mxf_get_wrapping_kind(UID *essence_container_ul) +{ + int val; + const MXFCodecUL *codec_ul; + + codec_ul = mxf_get_codec_ul(mxf_picture_essence_container_uls, essence_container_ul); + if (!codec_ul->uid[0]) + codec_ul = mxf_get_codec_ul(mxf_sound_essence_container_uls, essence_container_ul); + if (!codec_ul->uid[0]) + codec_ul = mxf_get_codec_ul(mxf_data_essence_container_uls, essence_container_ul); + if (!codec_ul->uid[0] || !codec_ul->wrapping_indicator_pos) + return UnknownWrapped; + + val = (*essence_container_ul)[codec_ul->wrapping_indicator_pos]; + switch (codec_ul->wrapping_indicator_type) { + case RawVWrap: + val = val % 4; + break; + case RawAWrap: + if (val == 0x03 || val == 0x04) + val -= 0x02; + break; + case D10D11Wrap: + if (val == 0x02) + val = 0x01; + break; + } + if (val == 0x01) + return FrameWrapped; + if (val == 0x02) + return ClipWrapped; + return UnknownWrapped; +} static int mxf_get_sorted_table_segments(MXFContext *mxf, int *nb_sorted_segments, MXFIndexTableSegment ***sorted_segments) { @@ -1295,9 +1434,22 @@ static int mxf_get_sorted_table_segments(MXFContext *mxf, int *nb_sorted_segment return AVERROR(ENOMEM); } - for (i = j = 0; i < mxf->metadata_sets_count; i++) - if (mxf->metadata_sets[i]->type == IndexTableSegment) - unsorted_segments[j++] = (MXFIndexTableSegment*)mxf->metadata_sets[i]; + for (i = nb_segments = 0; i < mxf->metadata_sets_count; i++) { + if (mxf->metadata_sets[i]->type == IndexTableSegment) { + MXFIndexTableSegment *s = (MXFIndexTableSegment*)mxf->metadata_sets[i]; + if (s->edit_unit_byte_count || s->nb_index_entries) + unsorted_segments[nb_segments++] = s; + else + av_log(mxf->fc, AV_LOG_WARNING, "IndexSID %i segment at %"PRId64" missing EditUnitByteCount and IndexEntryArray\n", + s->index_sid, s->index_start_position); + } + } + + if (!nb_segments) { + av_freep(sorted_segments); + av_free(unsorted_segments); + return AVERROR_INVALIDDATA; + } *nb_sorted_segments = 0; @@ -1348,7 +1500,7 @@ static int mxf_get_sorted_table_segments(MXFContext *mxf, int *nb_sorted_segment /** * Computes the absolute file offset of the given essence container offset */ -static int mxf_absolute_bodysid_offset(MXFContext *mxf, int body_sid, int64_t offset, int64_t *offset_out) +static int mxf_absolute_bodysid_offset(MXFContext *mxf, int body_sid, int64_t offset, int64_t *offset_out, MXFPartition **partition_out) { MXFPartition *last_p = NULL; int a, b, m, m0; @@ -1376,6 +1528,8 @@ static int mxf_absolute_bodysid_offset(MXFContext *mxf, int body_sid, int64_t of if (last_p && (!last_p->essence_length || last_p->essence_length > (offset - last_p->body_offset))) { *offset_out = last_p->essence_offset + (offset - last_p->body_offset); + if (partition_out) + *partition_out = last_p; return 0; } @@ -1391,10 +1545,7 @@ static int mxf_absolute_bodysid_offset(MXFContext *mxf, int body_sid, int64_t of */ static int64_t mxf_essence_container_end(MXFContext *mxf, int body_sid) { - int x; - int64_t ret = 0; - - for (x = 0; x < mxf->partitions_count; x++) { + for (int x = mxf->partitions_count - 1; x >= 0; x--) { MXFPartition *p = &mxf->partitions[x]; if (p->body_sid != body_sid) @@ -1403,18 +1554,20 @@ static int64_t mxf_essence_container_end(MXFContext *mxf, int body_sid) if (!p->essence_length) return 0; - ret = p->essence_offset + p->essence_length; + return p->essence_offset + p->essence_length; } - return ret; + return 0; } /* EditUnit -> absolute offset */ -static int mxf_edit_unit_absolute_offset(MXFContext *mxf, MXFIndexTable *index_table, int64_t edit_unit, int64_t *edit_unit_out, int64_t *offset_out, int nag) +static int mxf_edit_unit_absolute_offset(MXFContext *mxf, MXFIndexTable *index_table, int64_t edit_unit, AVRational edit_rate, int64_t *edit_unit_out, int64_t *offset_out, MXFPartition **partition_out, int nag) { int i; int64_t offset_temp = 0; + edit_unit = av_rescale_q(edit_unit, index_table->segments[0]->index_edit_rate, edit_rate); + for (i = 0; i < index_table->nb_segments; i++) { MXFIndexTableSegment *s = index_table->segments[i]; @@ -1425,7 +1578,7 @@ static int mxf_edit_unit_absolute_offset(MXFContext *mxf, MXFIndexTable *index_t if (s->edit_unit_byte_count) offset_temp += s->edit_unit_byte_count * index; - else if (s->nb_index_entries) { + else { if (s->nb_index_entries == 2 * s->index_duration + 1) index *= 2; /* Avid index */ @@ -1436,16 +1589,12 @@ static int mxf_edit_unit_absolute_offset(MXFContext *mxf, MXFIndexTable *index_t } offset_temp = s->stream_offset_entries[index]; - } else { - av_log(mxf->fc, AV_LOG_ERROR, "IndexSID %i segment at %"PRId64" missing EditUnitByteCount and IndexEntryArray\n", - index_table->index_sid, s->index_start_position); - return AVERROR_INVALIDDATA; } if (edit_unit_out) - *edit_unit_out = edit_unit; + *edit_unit_out = av_rescale_q(edit_unit, edit_rate, s->index_edit_rate); - return mxf_absolute_bodysid_offset(mxf, index_table->body_sid, offset_temp, offset_out); + return mxf_absolute_bodysid_offset(mxf, index_table->body_sid, offset_temp, offset_out, partition_out); } else { /* EditUnitByteCount == 0 for VBR indexes, which is fine since they use explicit StreamOffsets */ offset_temp += s->edit_unit_byte_count * s->index_duration; @@ -1473,6 +1622,12 @@ static int mxf_compute_ptses_fake_index(MXFContext *mxf, MXFIndexTable *index_ta return 0; /* no TemporalOffsets */ } + if (s->index_duration > INT_MAX - index_table->nb_ptses) { + index_table->nb_ptses = 0; + av_log(mxf->fc, AV_LOG_ERROR, "ignoring IndexSID %d, duration is too large\n", s->index_sid); + return 0; + } + index_table->nb_ptses += s->index_duration; } @@ -1651,6 +1806,13 @@ static int mxf_compute_index_tables(MXFContext *mxf) /* fix zero IndexDurations */ for (k = 0; k < t->nb_segments; k++) { + if (!t->segments[k]->index_edit_rate.num || !t->segments[k]->index_edit_rate.den) { + av_log(mxf->fc, AV_LOG_WARNING, "IndexSID %i segment %i has invalid IndexEditRate\n", + t->index_sid, k); + if (mxf_track) + t->segments[k]->index_edit_rate = mxf_track->edit_rate; + } + if (t->segments[k]->index_duration) continue; @@ -1913,15 +2075,15 @@ static int mxf_parse_physical_source_package(MXFContext *mxf, MXFTrack *source_t continue; } - if (physical_track->edit_rate.num <= 0 || - physical_track->edit_rate.den <= 0) { - av_log(mxf->fc, AV_LOG_WARNING, - "Invalid edit rate (%d/%d) found on structural" - " component #%d, defaulting to 25/1\n", - physical_track->edit_rate.num, - physical_track->edit_rate.den, i); - physical_track->edit_rate = (AVRational){25, 1}; - } + if (physical_track->edit_rate.num <= 0 || + physical_track->edit_rate.den <= 0) { + av_log(mxf->fc, AV_LOG_WARNING, + "Invalid edit rate (%d/%d) found on structural" + " component #%d, defaulting to 25/1\n", + physical_track->edit_rate.num, + physical_track->edit_rate.den, i); + physical_track->edit_rate = (AVRational){25, 1}; + } for (k = 0; k < physical_track->sequence->structural_components_count; k++) { if (!(mxf_tc = mxf_resolve_timecode_component(mxf, &physical_track->sequence->structural_components_refs[k]))) @@ -2165,6 +2327,9 @@ static int mxf_parse_structural_metadata(MXFContext *mxf) PRINT_KEY(mxf->fc, "essence codec ul", descriptor->essence_codec_ul); PRINT_KEY(mxf->fc, "essence container ul", descriptor->essence_container_ul); essence_container_ul = &descriptor->essence_container_ul; + source_track->wrapping = (mxf->op == OPAtom) ? ClipWrapped : mxf_get_wrapping_kind(essence_container_ul); + if (source_track->wrapping == UnknownWrapped) + av_log(mxf->fc, AV_LOG_INFO, "wrapping of stream %d is unknown\n", st->index); /* HACK: replacing the original key with mxf_encrypted_essence_container * is not allowed according to s429-6, try to find correct information anyway */ if (IS_KLV_KEY(essence_container_ul, mxf_encrypted_essence_container)) { @@ -2272,6 +2437,18 @@ static int mxf_parse_structural_metadata(MXFContext *mxf) default: av_log(mxf->fc, AV_LOG_INFO, "Unknown frame layout type: %d\n", descriptor->frame_layout); } + + if (st->codecpar->codec_id == AV_CODEC_ID_PRORES) { + switch (descriptor->essence_codec_ul[14]) { + case 1: st->codecpar->codec_tag = MKTAG('a','p','c','o'); break; + case 2: st->codecpar->codec_tag = MKTAG('a','p','c','s'); break; + case 3: st->codecpar->codec_tag = MKTAG('a','p','c','n'); break; + case 4: st->codecpar->codec_tag = MKTAG('a','p','c','h'); break; + case 5: st->codecpar->codec_tag = MKTAG('a','p','4','h'); break; + case 6: st->codecpar->codec_tag = MKTAG('a','p','4','x'); break; + } + } + if (st->codecpar->codec_id == AV_CODEC_ID_RAWVIDEO) { st->codecpar->format = descriptor->pix_fmt; if (st->codecpar->format == AV_PIX_FMT_NONE) { @@ -2308,7 +2485,6 @@ static int mxf_parse_structural_metadata(MXFContext *mxf) if (st->codecpar->codec_id == AV_CODEC_ID_NONE || (st->codecpar->codec_id == AV_CODEC_ID_PCM_ALAW && (enum AVCodecID)container_ul->id != AV_CODEC_ID_NONE)) st->codecpar->codec_id = (enum AVCodecID)container_ul->id; st->codecpar->channels = descriptor->channels; - st->codecpar->bits_per_coded_sample = descriptor->bits_per_sample; if (descriptor->sample_rate.den > 0) { st->codecpar->sample_rate = descriptor->sample_rate.num / descriptor->sample_rate.den; @@ -2341,13 +2517,21 @@ static int mxf_parse_structural_metadata(MXFContext *mxf) } else if (st->codecpar->codec_id == AV_CODEC_ID_MP2) { st->need_parsing = AVSTREAM_PARSE_FULL; } + st->codecpar->bits_per_coded_sample = av_get_bits_per_sample(st->codecpar->codec_id); } else if (st->codecpar->codec_type == AVMEDIA_TYPE_DATA) { - int codec_id = mxf_get_codec_ul(mxf_data_essence_container_uls, - essence_container_ul)->id; - if (codec_id >= 0 && - codec_id < FF_ARRAY_ELEMS(mxf_data_essence_descriptor)) { - av_dict_set(&st->metadata, "data_type", - mxf_data_essence_descriptor[codec_id], 0); + enum AVMediaType type; + container_ul = mxf_get_codec_ul(mxf_data_essence_container_uls, essence_container_ul); + if (st->codecpar->codec_id == AV_CODEC_ID_NONE) + st->codecpar->codec_id = container_ul->id; + type = avcodec_get_type(st->codecpar->codec_id); + if (type == AVMEDIA_TYPE_SUBTITLE) + st->codecpar->codec_type = type; + if (container_ul->desc) + av_dict_set(&st->metadata, "data_type", container_ul->desc, 0); + if (mxf->eia608_extract && + !strcmp(container_ul->desc, "vbi_vanc_smpte_436M")) { + st->codecpar->codec_type = AVMEDIA_TYPE_SUBTITLE; + st->codecpar->codec_id = AV_CODEC_ID_EIA_608; } } if (descriptor->extradata) { @@ -2363,12 +2547,30 @@ static int mxf_parse_structural_metadata(MXFContext *mxf) if (ret < 0) return ret; } - if (st->codecpar->codec_type != AVMEDIA_TYPE_DATA && (*essence_container_ul)[15] > 0x01) { + if (st->codecpar->codec_type != AVMEDIA_TYPE_DATA && source_track->wrapping != FrameWrapped) { /* TODO: decode timestamps */ st->need_parsing = AVSTREAM_PARSE_TIMESTAMPS; } } + for (int i = 0; i < mxf->fc->nb_streams; i++) { + MXFTrack *track1 = mxf->fc->streams[i]->priv_data; + if (track1 && track1->body_sid) { + for (int j = i + 1; j < mxf->fc->nb_streams; j++) { + MXFTrack *track2 = mxf->fc->streams[j]->priv_data; + if (track2 && track1->body_sid == track2->body_sid && track1->wrapping != track2->wrapping) { + if (track1->wrapping == UnknownWrapped) + track1->wrapping = track2->wrapping; + else if (track2->wrapping == UnknownWrapped) + track2->wrapping = track1->wrapping; + else + av_log(mxf->fc, AV_LOG_ERROR, "stream %d and stream %d have the same BodySID (%d) " + "with different wrapping\n", i, j, track1->body_sid); + } + } + } + } + ret = 0; fail_and_free: return ret; @@ -2377,23 +2579,24 @@ fail_and_free: static int64_t mxf_timestamp_to_int64(uint64_t timestamp) { struct tm time = { 0 }; + int msecs; time.tm_year = (timestamp >> 48) - 1900; time.tm_mon = (timestamp >> 40 & 0xFF) - 1; time.tm_mday = (timestamp >> 32 & 0xFF); time.tm_hour = (timestamp >> 24 & 0xFF); time.tm_min = (timestamp >> 16 & 0xFF); time.tm_sec = (timestamp >> 8 & 0xFF); + msecs = (timestamp & 0xFF) * 4; - /* msvcrt versions of strftime calls the invalid parameter handler - * (aborting the process if one isn't set) if the parameters are out - * of range. */ + /* Clip values for legacy reasons. Maybe we should return error instead? */ time.tm_mon = av_clip(time.tm_mon, 0, 11); time.tm_mday = av_clip(time.tm_mday, 1, 31); time.tm_hour = av_clip(time.tm_hour, 0, 23); time.tm_min = av_clip(time.tm_min, 0, 59); time.tm_sec = av_clip(time.tm_sec, 0, 59); + msecs = av_clip(msecs, 0, 999); - return (int64_t)av_timegm(&time) * 1000000; + return (int64_t)av_timegm(&time) * 1000000 + msecs * 1000; } #define SET_STR_METADATA(pb, name, str) do { \ @@ -2411,7 +2614,7 @@ static int64_t mxf_timestamp_to_int64(uint64_t timestamp) #define SET_TS_METADATA(pb, name, var, str) do { \ var = avio_rb64(pb); \ - if ((ret = avpriv_dict_set_timestamp(&s->metadata, name, mxf_timestamp_to_int64(var)) < 0)) \ + if (var && (ret = avpriv_dict_set_timestamp(&s->metadata, name, mxf_timestamp_to_int64(var))) < 0) \ return ret; \ } while (0) @@ -2493,8 +2696,10 @@ static const MXFMetadataReadTableEntry mxf_metadata_read_table[] = { { { 0x06,0x0e,0x2b,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x48,0x00 }, mxf_read_generic_descriptor, sizeof(MXFDescriptor), Descriptor }, /* Wave */ { { 0x06,0x0e,0x2b,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x47,0x00 }, mxf_read_generic_descriptor, sizeof(MXFDescriptor), Descriptor }, /* AES3 */ { { 0x06,0x0e,0x2b,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x51,0x00 }, mxf_read_generic_descriptor, sizeof(MXFDescriptor), Descriptor }, /* MPEG2VideoDescriptor */ + { { 0x06,0x0e,0x2b,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x5b,0x00 }, mxf_read_generic_descriptor, sizeof(MXFDescriptor), Descriptor }, /* VBI - SMPTE 436M */ { { 0x06,0x0e,0x2b,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x5c,0x00 }, mxf_read_generic_descriptor, sizeof(MXFDescriptor), Descriptor }, /* VANC/VBI - SMPTE 436M */ { { 0x06,0x0e,0x2b,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x5e,0x00 }, mxf_read_generic_descriptor, sizeof(MXFDescriptor), Descriptor }, /* MPEG2AudioDescriptor */ + { { 0x06,0x0e,0x2b,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x64,0x00 }, mxf_read_generic_descriptor, sizeof(MXFDescriptor), Descriptor }, /* DC Timed Text Descriptor */ { { 0x06,0x0e,0x2b,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x3A,0x00 }, mxf_read_track, sizeof(MXFTrack), Track }, /* Static Track */ { { 0x06,0x0e,0x2b,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x3B,0x00 }, mxf_read_track, sizeof(MXFTrack), Track }, /* Generic Track */ { { 0x06,0x0e,0x2b,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x14,0x00 }, mxf_read_timecode_component, sizeof(MXFTimecodeComponent), TimecodeComponent }, @@ -2554,7 +2759,8 @@ static int mxf_read_local_tags(MXFContext *mxf, KLVPacket *klv, MXFMetadataReadF if (ctx_size && tag == 0x3C0A) { avio_read(pb, ctx->uid, 16); } else if ((ret = read_child(ctx, pb, tag, size, uid, -1)) < 0) { - mxf_free_metadataset(&ctx, !!ctx_size); + if (ctx_size) + mxf_free_metadataset(&ctx, 1); return ret; } @@ -2563,7 +2769,7 @@ static int mxf_read_local_tags(MXFContext *mxf, KLVPacket *klv, MXFMetadataReadF if (avio_tell(pb) > klv_end) { if (ctx_size) { ctx->type = type; - mxf_free_metadataset(&ctx, !!ctx_size); + mxf_free_metadataset(&ctx, 1); } av_log(mxf->fc, AV_LOG_ERROR, @@ -2725,65 +2931,70 @@ static int mxf_parse_handle_partition_or_eof(MXFContext *mxf) return mxf->parsing_backward ? mxf_seek_to_previous_partition(mxf) : 1; } +static MXFWrappingScheme mxf_get_wrapping_by_body_sid(AVFormatContext *s, int body_sid) +{ + for (int i = 0; i < s->nb_streams; i++) { + MXFTrack *track = s->streams[i]->priv_data; + if (track && track->body_sid == body_sid && track->wrapping != UnknownWrapped) + return track->wrapping; + } + return UnknownWrapped; +} + /** * Figures out the proper offset and length of the essence container in each partition */ -static void mxf_compute_essence_containers(MXFContext *mxf) +static void mxf_compute_essence_containers(AVFormatContext *s) { + MXFContext *mxf = s->priv_data; int x; - /* everything is already correct */ - if (mxf->op == OPAtom) - return; - for (x = 0; x < mxf->partitions_count; x++) { MXFPartition *p = &mxf->partitions[x]; + MXFWrappingScheme wrapping; if (!p->body_sid) continue; /* BodySID == 0 -> no essence */ - if (x >= mxf->partitions_count - 1) - break; /* FooterPartition - can't compute length (and we don't need to) */ + /* for clip wrapped essences we point essence_offset after the KL (usually klv.offset + 20 or 25) + * otherwise we point essence_offset at the key of the first essence KLV. + */ - /* essence container spans to the next partition */ - p->essence_length = mxf->partitions[x+1].this_partition - p->essence_offset; + wrapping = (mxf->op == OPAtom) ? ClipWrapped : mxf_get_wrapping_by_body_sid(s, p->body_sid); - if (p->essence_length < 0) { - /* next ThisPartition < essence_offset */ - p->essence_length = 0; - av_log(mxf->fc, AV_LOG_ERROR, - "partition %i: bad ThisPartition = %"PRIX64"\n", - x+1, mxf->partitions[x+1].this_partition); + if (wrapping == ClipWrapped) { + p->essence_offset = p->first_essence_klv.next_klv - p->first_essence_klv.length; + p->essence_length = p->first_essence_klv.length; + } else { + p->essence_offset = p->first_essence_klv.offset; + + /* essence container spans to the next partition */ + if (x < mxf->partitions_count - 1) + p->essence_length = mxf->partitions[x+1].this_partition - p->essence_offset; + + if (p->essence_length < 0) { + /* next ThisPartition < essence_offset */ + p->essence_length = 0; + av_log(mxf->fc, AV_LOG_ERROR, + "partition %i: bad ThisPartition = %"PRIX64"\n", + x+1, mxf->partitions[x+1].this_partition); + } } } } -static int64_t round_to_kag(int64_t position, int kag_size) -{ - /* TODO: account for run-in? the spec isn't clear whether KAG should account for it */ - /* NOTE: kag_size may be any integer between 1 - 2^10 */ - int64_t ret = (position / kag_size) * kag_size; - return ret == position ? ret : ret + kag_size; -} - static int is_pcm(enum AVCodecID codec_id) { /* we only care about "normal" PCM codecs until we get samples */ return codec_id >= AV_CODEC_ID_PCM_S16LE && codec_id < AV_CODEC_ID_PCM_S24DAUD; } -static AVStream* mxf_get_opatom_stream(MXFContext *mxf) +static MXFIndexTable *mxf_find_index_table(MXFContext *mxf, int index_sid) { int i; - - if (mxf->op != OPAtom) - return NULL; - - for (i = 0; i < mxf->fc->nb_streams; i++) { - if (mxf->fc->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_DATA) - continue; - return mxf->fc->streams[i]; - } + for (i = 0; i < mxf->nb_index_tables; i++) + if (mxf->index_tables[i].index_sid == index_sid) + return &mxf->index_tables[i]; return NULL; } @@ -2792,63 +3003,62 @@ static AVStream* mxf_get_opatom_stream(MXFContext *mxf) * very small (2, 4..). In those cases we should read more than one * sample per call to mxf_read_packet(). */ -static void mxf_handle_small_eubc(AVFormatContext *s) +static void mxf_compute_edit_units_per_packet(MXFContext *mxf, AVStream *st) { - MXFContext *mxf = s->priv_data; - MXFTrack *track; + MXFTrack *track = st->priv_data; + MXFIndexTable *t; - /* assuming non-OPAtom == frame wrapped - * no sane writer would wrap 2 byte PCM packets with 20 byte headers.. */ - AVStream *st = mxf_get_opatom_stream(mxf); - if (!st) + if (!track) return; + track->edit_units_per_packet = 1; + if (track->wrapping != ClipWrapped) + return; + + t = mxf_find_index_table(mxf, track->index_sid); /* expect PCM with exactly one index table segment and a small (< 32) EUBC */ if (st->codecpar->codec_type != AVMEDIA_TYPE_AUDIO || !is_pcm(st->codecpar->codec_id) || - mxf->nb_index_tables != 1 || - mxf->index_tables[0].nb_segments != 1 || - mxf->index_tables[0].segments[0]->edit_unit_byte_count >= 32) + !t || + t->nb_segments != 1 || + t->segments[0]->edit_unit_byte_count >= 32) return; /* arbitrarily default to 48 kHz PAL audio frame size */ /* TODO: We could compute this from the ratio between the audio * and video edit rates for 48 kHz NTSC we could use the * 1802-1802-1802-1802-1801 pattern. */ - track = st->priv_data; - mxf->edit_units_per_packet = FFMAX(1, track->edit_rate.num / track->edit_rate.den / 25); + track->edit_units_per_packet = FFMAX(1, track->edit_rate.num / track->edit_rate.den / 25); } /** - * Deal with the case where OPAtom files does not have any IndexTableSegments. + * Deal with the case where ClipWrapped essences does not have any IndexTableSegments. */ -static int mxf_handle_missing_index_segment(MXFContext *mxf) +static int mxf_handle_missing_index_segment(MXFContext *mxf, AVStream *st) { - AVFormatContext *s = mxf->fc; - AVStream *st = NULL; + MXFTrack *track = st->priv_data; MXFIndexTableSegment *segment = NULL; MXFPartition *p = NULL; int essence_partition_count = 0; + int edit_unit_byte_count = 0; int i, ret; - st = mxf_get_opatom_stream(mxf); - if (!st) + if (!track || track->wrapping != ClipWrapped) return 0; - /* TODO: support raw video without an index if they exist */ - if (st->codecpar->codec_type != AVMEDIA_TYPE_AUDIO || !is_pcm(st->codecpar->codec_id)) - return 0; - - /* check if file already has a IndexTableSegment */ + /* check if track already has an IndexTableSegment */ for (i = 0; i < mxf->metadata_sets_count; i++) { - if (mxf->metadata_sets[i]->type == IndexTableSegment) - return 0; + if (mxf->metadata_sets[i]->type == IndexTableSegment) { + MXFIndexTableSegment *s = (MXFIndexTableSegment*)mxf->metadata_sets[i]; + if (s->body_sid == track->body_sid) + return 0; + } } /* find the essence partition */ for (i = 0; i < mxf->partitions_count; i++) { /* BodySID == 0 -> no essence */ - if (!mxf->partitions[i].body_sid) + if (mxf->partitions[i].body_sid != track->body_sid) continue; p = &mxf->partitions[i]; @@ -2859,6 +3069,17 @@ static int mxf_handle_missing_index_segment(MXFContext *mxf) if (essence_partition_count != 1) return 0; + if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && is_pcm(st->codecpar->codec_id)) { + edit_unit_byte_count = (av_get_bits_per_sample(st->codecpar->codec_id) * st->codecpar->channels) >> 3; + } else if (st->duration > 0 && p->first_essence_klv.length > 0 && p->first_essence_klv.length % st->duration == 0) { + edit_unit_byte_count = p->first_essence_klv.length / st->duration; + } + + if (edit_unit_byte_count <= 0) + return 0; + + av_log(mxf->fc, AV_LOG_WARNING, "guessing index for stream %d using edit unit byte count %d\n", st->index, edit_unit_byte_count); + if (!(segment = av_mallocz(sizeof(*segment)))) return AVERROR(ENOMEM); @@ -2867,12 +3088,18 @@ static int mxf_handle_missing_index_segment(MXFContext *mxf) return ret; } + /* Make sure we have nonzero unique index_sid, body_sid will be ok, because + * using the same SID for index is forbidden in MXF. */ + if (!track->index_sid) + track->index_sid = track->body_sid; + segment->type = IndexTableSegment; /* stream will be treated as small EditUnitByteCount */ - segment->edit_unit_byte_count = (av_get_bits_per_sample(st->codecpar->codec_id) * st->codecpar->channels) >> 3; + segment->edit_unit_byte_count = edit_unit_byte_count; segment->index_start_position = 0; - segment->index_duration = s->streams[0]->duration; - segment->index_sid = p->index_sid; + segment->index_duration = st->duration; + segment->index_edit_rate = av_inv_q(st->time_base); + segment->index_sid = track->index_sid; segment->body_sid = p->body_sid; return 0; } @@ -2911,9 +3138,12 @@ static void mxf_read_random_index_pack(AVFormatContext *s) goto end; avio_seek(s->pb, file_size - length, SEEK_SET); if (klv_read_packet(&klv, s->pb) < 0 || - !IS_KLV_KEY(klv.key, mxf_random_index_pack_key) || - klv.length != length - 20) + !IS_KLV_KEY(klv.key, mxf_random_index_pack_key)) goto end; + if (klv.next_klv != file_size || klv.length <= 4 || (klv.length - 4) % 12) { + av_log(s, AV_LOG_WARNING, "Invalid RIP KLV length\n"); + goto end; + } avio_skip(s->pb, klv.length - 12); mxf->footer_partition = avio_rb64(s->pb); @@ -2936,7 +3166,6 @@ static int mxf_read_header(AVFormatContext *s) int ret; mxf->last_forward_tell = INT64_MAX; - mxf->edit_units_per_packet = 1; if (!mxf_read_sync(s->pb, mxf_header_partition_pack_key, 14)) { av_log(s, AV_LOG_ERROR, "could not find header partition pack key\n"); @@ -2963,6 +3192,7 @@ static int mxf_read_header(AVFormatContext *s) av_log(s, AV_LOG_TRACE, "size %"PRIu64" offset %#"PRIx64"\n", klv.length, klv.offset); if (IS_KLV_KEY(klv.key, mxf_encrypted_triplet_key) || IS_KLV_KEY(klv.key, mxf_essence_element_key) || + IS_KLV_KEY(klv.key, mxf_canopus_essence_element_key) || IS_KLV_KEY(klv.key, mxf_avid_essence_element_key) || IS_KLV_KEY(klv.key, mxf_system_item_key_cp) || IS_KLV_KEY(klv.key, mxf_system_item_key_gc)) { @@ -2972,32 +3202,8 @@ static int mxf_read_header(AVFormatContext *s) return AVERROR_INVALIDDATA; } - if (!mxf->current_partition->essence_offset) { - /* for OP1a we compute essence_offset - * for OPAtom we point essence_offset after the KL (usually op1a_essence_offset + 20 or 25) - * TODO: for OP1a we could eliminate this entire if statement, always stopping parsing at op1a_essence_offset - * for OPAtom we still need the actual essence_offset though (the KL's length can vary) - */ - int64_t op1a_essence_offset = - mxf->current_partition->this_partition + - round_to_kag(mxf->current_partition->pack_length, mxf->current_partition->kag_size) + - round_to_kag(mxf->current_partition->header_byte_count, mxf->current_partition->kag_size) + - round_to_kag(mxf->current_partition->index_byte_count, mxf->current_partition->kag_size); - - if (mxf->op == OPAtom) { - /* point essence_offset to the actual data - * OPAtom has all the essence in one big KLV - */ - mxf->current_partition->essence_offset = avio_tell(s->pb); - mxf->current_partition->essence_length = klv.length; - } else { - /* NOTE: op1a_essence_offset may be less than to klv.offset (C0023S01.mxf) */ - if (IS_KLV_KEY(klv.key, mxf_system_item_key_cp) || IS_KLV_KEY(klv.key, mxf_system_item_key_gc)) - mxf->current_partition->essence_offset = klv.offset; - else - mxf->current_partition->essence_offset = op1a_essence_offset; - } - } + if (!mxf->current_partition->first_essence_klv.offset) + mxf->current_partition->first_essence_klv = klv; if (!essence_offset) essence_offset = klv.offset; @@ -3036,14 +3242,14 @@ static int mxf_read_header(AVFormatContext *s) } avio_seek(s->pb, essence_offset, SEEK_SET); - mxf_compute_essence_containers(mxf); - /* we need to do this before computing the index tables * to be able to fill in zero IndexDurations with st->duration */ if ((ret = mxf_parse_structural_metadata(mxf)) < 0) goto fail; - mxf_handle_missing_index_segment(mxf); + for (int i = 0; i < s->nb_streams; i++) + mxf_handle_missing_index_segment(mxf, s->streams[i]); + if ((ret = mxf_compute_index_tables(mxf)) < 0) goto fail; @@ -3051,13 +3257,16 @@ static int mxf_read_header(AVFormatContext *s) /* TODO: look up which IndexSID to use via EssenceContainerData */ av_log(mxf->fc, AV_LOG_INFO, "got %i index tables - only the first one (IndexSID %i) will be used\n", mxf->nb_index_tables, mxf->index_tables[0].index_sid); - } else if (mxf->nb_index_tables == 0 && mxf->op == OPAtom) { + } else if (mxf->nb_index_tables == 0 && mxf->op == OPAtom && (s->error_recognition & AV_EF_EXPLODE)) { av_log(mxf->fc, AV_LOG_ERROR, "cannot demux OPAtom without an index\n"); ret = AVERROR_INVALIDDATA; goto fail; } - mxf_handle_small_eubc(s); + mxf_compute_essence_containers(s); + + for (int i = 0; i < s->nb_streams; i++) + mxf_compute_edit_units_per_packet(mxf, s->streams[i]); return 0; fail: @@ -3066,15 +3275,6 @@ fail: return ret; } -static MXFIndexTable *mxf_find_index_table(MXFContext *mxf, int index_sid) -{ - int i; - for (i = 0; i < mxf->nb_index_tables; i++) - if (mxf->index_tables[i].index_sid == index_sid) - return &mxf->index_tables[i]; - return NULL; -} - /* Get the edit unit of the next packet from current_offset in a track. The returned edit unit can be original_duration as well! */ static int mxf_get_next_track_edit_unit(MXFContext *mxf, MXFTrack *track, int64_t current_offset, int64_t *edit_unit_out) { @@ -3089,7 +3289,7 @@ static int mxf_get_next_track_edit_unit(MXFContext *mxf, MXFTrack *track, int64_ while (b - a > 1) { m = (a + b) >> 1; - if (mxf_edit_unit_absolute_offset(mxf, t, m, NULL, &offset, 0) < 0) + if (mxf_edit_unit_absolute_offset(mxf, t, m, track->edit_rate, NULL, &offset, NULL, 0) < 0) return -1; if (offset < current_offset) a = m; @@ -3102,71 +3302,32 @@ static int mxf_get_next_track_edit_unit(MXFContext *mxf, MXFTrack *track, int64_ return 0; } -/** - * Sets mxf->current_edit_unit based on what offset we're currently at. - * @return next_ofs if OK, <0 on error - */ -static int64_t mxf_set_current_edit_unit(MXFContext *mxf, int64_t current_offset) -{ - int64_t last_ofs = -1, next_ofs = -1; - MXFIndexTable *t = &mxf->index_tables[0]; - - /* this is called from the OP1a demuxing logic, which means there - * may be no index tables */ - if (mxf->nb_index_tables <= 0) - return -1; - - /* find mxf->current_edit_unit so that the next edit unit starts ahead of current_offset */ - while (mxf->current_edit_unit >= 0) { - if (mxf_edit_unit_absolute_offset(mxf, t, mxf->current_edit_unit + 1, NULL, &next_ofs, 0) < 0) - return -2; - - if (next_ofs <= last_ofs) { - /* large next_ofs didn't change or current_edit_unit wrapped - * around this fixes the infinite loop on zzuf3.mxf */ - av_log(mxf->fc, AV_LOG_ERROR, - "next_ofs didn't change. not deriving packet timestamps\n"); - return -1; - } - - if (next_ofs > current_offset) - break; - - last_ofs = next_ofs; - mxf->current_edit_unit++; - } - - /* not checking mxf->current_edit_unit >= t->nb_ptses here since CBR files may lack IndexEntryArrays */ - if (mxf->current_edit_unit < 0) - return -1; - - return next_ofs; -} - -static int mxf_compute_sample_count(MXFContext *mxf, int stream_index, - uint64_t *sample_count) +static int64_t mxf_compute_sample_count(MXFContext *mxf, AVStream *st, + int64_t edit_unit) { int i, total = 0, size = 0; - AVStream *st = mxf->fc->streams[stream_index]; MXFTrack *track = st->priv_data; AVRational time_base = av_inv_q(track->edit_rate); AVRational sample_rate = av_inv_q(st->time_base); const MXFSamplesPerFrame *spf = NULL; + int64_t sample_count; + + // For non-audio sample_count equals current edit unit + if (st->codecpar->codec_type != AVMEDIA_TYPE_AUDIO) + return edit_unit; if ((sample_rate.num / sample_rate.den) == 48000) spf = ff_mxf_get_samples_per_frame(mxf->fc, time_base); if (!spf) { int remainder = (sample_rate.num * time_base.num) % (time_base.den * sample_rate.den); - *sample_count = av_q2d(av_mul_q((AVRational){mxf->current_edit_unit, 1}, - av_mul_q(sample_rate, time_base))); if (remainder) av_log(mxf->fc, AV_LOG_WARNING, "seeking detected on stream #%d with time base (%d/%d) and " "sample rate (%d/%d), audio pts won't be accurate.\n", - stream_index, time_base.num, time_base.den, + st->index, time_base.num, time_base.den, sample_rate.num, sample_rate.den); - return 0; + return av_rescale_q(edit_unit, sample_rate, track->edit_rate); } while (spf->samples_per_frame[size]) { @@ -3176,18 +3337,62 @@ static int mxf_compute_sample_count(MXFContext *mxf, int stream_index, av_assert2(size); - *sample_count = (mxf->current_edit_unit / size) * (uint64_t)total; - for (i = 0; i < mxf->current_edit_unit % size; i++) { - *sample_count += spf->samples_per_frame[i]; + sample_count = (edit_unit / size) * (uint64_t)total; + for (i = 0; i < edit_unit % size; i++) { + sample_count += spf->samples_per_frame[i]; } - return 0; + return sample_count; +} + +/** + * Make sure track->sample_count is correct based on what offset we're currently at. + * Also determine the next edit unit (or packet) offset. + * @return next_ofs if OK, <0 on error + */ +static int64_t mxf_set_current_edit_unit(MXFContext *mxf, AVStream *st, int64_t current_offset, int resync) +{ + int64_t next_ofs = -1; + MXFTrack *track = st->priv_data; + int64_t edit_unit = av_rescale_q(track->sample_count, st->time_base, av_inv_q(track->edit_rate)); + int64_t new_edit_unit; + MXFIndexTable *t = mxf_find_index_table(mxf, track->index_sid); + + if (!t || track->wrapping == UnknownWrapped) + return -1; + + if (mxf_edit_unit_absolute_offset(mxf, t, edit_unit + track->edit_units_per_packet, track->edit_rate, NULL, &next_ofs, NULL, 0) < 0 && + (next_ofs = mxf_essence_container_end(mxf, t->body_sid)) <= 0) { + av_log(mxf->fc, AV_LOG_ERROR, "unable to compute the size of the last packet\n"); + return -1; + } + + /* check if the next edit unit offset (next_ofs) starts ahead of current_offset */ + if (next_ofs > current_offset) + return next_ofs; + + if (!resync) { + av_log(mxf->fc, AV_LOG_ERROR, "cannot find current edit unit for stream %d, invalid index?\n", st->index); + return -1; + } + + if (mxf_get_next_track_edit_unit(mxf, track, current_offset + 1, &new_edit_unit) < 0 || new_edit_unit <= 0) { + av_log(mxf->fc, AV_LOG_ERROR, "failed to find next track edit unit in stream %d\n", st->index); + return -1; + } + + new_edit_unit--; + track->sample_count = mxf_compute_sample_count(mxf, st, new_edit_unit); + av_log(mxf->fc, AV_LOG_WARNING, "edit unit sync lost on stream %d, jumping from %"PRId64" to %"PRId64"\n", st->index, edit_unit, new_edit_unit); + + return mxf_set_current_edit_unit(mxf, st, current_offset, 0); } static int mxf_set_audio_pts(MXFContext *mxf, AVCodecParameters *par, AVPacket *pkt) { - MXFTrack *track = mxf->fc->streams[pkt->stream_index]->priv_data; + AVStream *st = mxf->fc->streams[pkt->stream_index]; + MXFTrack *track = st->priv_data; int64_t bits_per_sample = par->bits_per_coded_sample; if (!bits_per_sample) @@ -3198,61 +3403,82 @@ static int mxf_set_audio_pts(MXFContext *mxf, AVCodecParameters *par, if ( par->channels <= 0 || bits_per_sample <= 0 || par->channels * (int64_t)bits_per_sample < 8) - return AVERROR(EINVAL); - track->sample_count += pkt->size / (par->channels * (int64_t)bits_per_sample / 8); + track->sample_count = mxf_compute_sample_count(mxf, st, av_rescale_q(track->sample_count, st->time_base, av_inv_q(track->edit_rate)) + 1); + else + track->sample_count += pkt->size / (par->channels * (int64_t)bits_per_sample / 8); + return 0; } -static int mxf_set_pts(MXFContext *mxf, AVStream *st, AVPacket *pkt, int64_t next_ofs) +static int mxf_set_pts(MXFContext *mxf, AVStream *st, AVPacket *pkt) { AVCodecParameters *par = st->codecpar; MXFTrack *track = st->priv_data; - if (par->codec_type == AVMEDIA_TYPE_VIDEO && (next_ofs >= 0 || next_ofs == -2 && st->duration == mxf->current_edit_unit + 1)) { - /* mxf->current_edit_unit good - see if we have an - * index table to derive timestamps from */ - MXFIndexTable *t = &mxf->index_tables[0]; + if (par->codec_type == AVMEDIA_TYPE_VIDEO) { + /* see if we have an index table to derive timestamps from */ + MXFIndexTable *t = mxf_find_index_table(mxf, track->index_sid); - if (mxf->nb_index_tables >= 1 && mxf->current_edit_unit < t->nb_ptses) { - pkt->dts = mxf->current_edit_unit + t->first_dts; - pkt->pts = t->ptses[mxf->current_edit_unit]; - } else if (track && track->intra_only) { + if (t && track->sample_count < t->nb_ptses) { + pkt->dts = track->sample_count + t->first_dts; + pkt->pts = t->ptses[track->sample_count]; + } else if (track->intra_only) { /* intra-only -> PTS = EditUnit. * let utils.c figure out DTS since it can be < PTS if low_delay = 0 (Sony IMX30) */ - pkt->pts = mxf->current_edit_unit; + pkt->pts = track->sample_count; } + track->sample_count++; } else if (par->codec_type == AVMEDIA_TYPE_AUDIO) { int ret = mxf_set_audio_pts(mxf, par, pkt); if (ret < 0) return ret; + } else if (track) { + pkt->dts = pkt->pts = track->sample_count; + pkt->duration = 1; + track->sample_count++; } return 0; } -static int mxf_read_packet_old(AVFormatContext *s, AVPacket *pkt) +static int mxf_read_packet(AVFormatContext *s, AVPacket *pkt) { KLVPacket klv; MXFContext *mxf = s->priv_data; int ret; - while ((ret = klv_read_packet(&klv, s->pb)) == 0) { - PRINT_KEY(s, "read packet", klv.key); - av_log(s, AV_LOG_TRACE, "size %"PRIu64" offset %#"PRIx64"\n", klv.length, klv.offset); - if (IS_KLV_KEY(klv.key, mxf_encrypted_triplet_key)) { - ret = mxf_decrypt_triplet(s, pkt, &klv); - if (ret < 0) { - av_log(s, AV_LOG_ERROR, "invalid encoded triplet\n"); - return ret; + while (1) { + int64_t max_data_size; + int64_t pos = avio_tell(s->pb); + + if (pos < mxf->current_klv_data.next_klv - mxf->current_klv_data.length || pos >= mxf->current_klv_data.next_klv) { + mxf->current_klv_data = (KLVPacket){{0}}; + ret = klv_read_packet(&klv, s->pb); + if (ret < 0) + break; + max_data_size = klv.length; + pos = klv.next_klv - klv.length; + PRINT_KEY(s, "read packet", klv.key); + av_log(s, AV_LOG_TRACE, "size %"PRIu64" offset %#"PRIx64"\n", klv.length, klv.offset); + if (IS_KLV_KEY(klv.key, mxf_encrypted_triplet_key)) { + ret = mxf_decrypt_triplet(s, pkt, &klv); + if (ret < 0) { + av_log(s, AV_LOG_ERROR, "invalid encoded triplet\n"); + return ret; + } + return 0; } - return 0; + } else { + klv = mxf->current_klv_data; + max_data_size = klv.next_klv - pos; } if (IS_KLV_KEY(klv.key, mxf_essence_element_key) || IS_KLV_KEY(klv.key, mxf_canopus_essence_element_key) || IS_KLV_KEY(klv.key, mxf_avid_essence_element_key)) { - int body_sid = find_body_sid_by_offset(mxf, klv.offset); + int body_sid = find_body_sid_by_absolute_offset(mxf, klv.offset); int index = mxf_get_stream_index(s, &klv, body_sid); - int64_t next_ofs, next_klv; + int64_t next_ofs; AVStream *st; + MXFTrack *track; if (index < 0) { av_log(s, AV_LOG_ERROR, @@ -3262,22 +3488,38 @@ static int mxf_read_packet_old(AVFormatContext *s, AVPacket *pkt) } st = s->streams[index]; + track = st->priv_data; if (s->streams[index]->discard == AVDISCARD_ALL) goto skip; - next_klv = avio_tell(s->pb) + klv.length; - next_ofs = mxf_set_current_edit_unit(mxf, klv.offset); + next_ofs = mxf_set_current_edit_unit(mxf, st, pos, 1); - if (next_ofs >= 0 && next_klv > next_ofs) { - /* if this check is hit then it's possible OPAtom was treated as OP1a - * truncate the packet since it's probably very large (>2 GiB is common) */ - avpriv_request_sample(s, - "OPAtom misinterpreted as OP1a? " - "KLV for edit unit %"PRId64" extending into " - "next edit unit", - mxf->current_edit_unit); - klv.length = next_ofs - avio_tell(s->pb); + if (track->wrapping != FrameWrapped) { + int64_t size; + + if (next_ofs <= 0) { + // If we have no way to packetize the data, then return it in chunks... + if (klv.next_klv - klv.length == pos && max_data_size > MXF_MAX_CHUNK_SIZE) { + st->need_parsing = AVSTREAM_PARSE_FULL; + avpriv_request_sample(s, "Huge KLV without proper index in non-frame wrapped essence"); + } + size = FFMIN(max_data_size, MXF_MAX_CHUNK_SIZE); + } else { + if ((size = next_ofs - pos) <= 0) { + av_log(s, AV_LOG_ERROR, "bad size: %"PRId64"\n", size); + mxf->current_klv_data = (KLVPacket){{0}}; + return AVERROR_INVALIDDATA; + } + // We must not overread, because the next edit unit might be in another KLV + if (size > max_data_size) + size = max_data_size; + } + + mxf->current_klv_data = klv; + klv.offset = pos; + klv.length = size; + klv.next_klv = klv.offset + klv.length; } /* check for 8 channels AES3 element */ @@ -3286,93 +3528,45 @@ static int mxf_read_packet_old(AVFormatContext *s, AVPacket *pkt) pkt, klv.length); if (ret < 0) { av_log(s, AV_LOG_ERROR, "error reading D-10 aes3 frame\n"); + mxf->current_klv_data = (KLVPacket){{0}}; + return ret; + } + } else if (mxf->eia608_extract && + s->streams[index]->codecpar->codec_id == AV_CODEC_ID_EIA_608) { + ret = mxf_get_eia608_packet(s, s->streams[index], pkt, klv.length); + if (ret < 0) { + mxf->current_klv_data = (KLVPacket){{0}}; return ret; } } else { ret = av_get_packet(s->pb, pkt, klv.length); - if (ret < 0) + if (ret < 0) { + mxf->current_klv_data = (KLVPacket){{0}}; return ret; + } } pkt->stream_index = index; pkt->pos = klv.offset; - ret = mxf_set_pts(mxf, st, pkt, next_ofs); - if (ret < 0) + ret = mxf_set_pts(mxf, st, pkt); + if (ret < 0) { + mxf->current_klv_data = (KLVPacket){{0}}; return ret; + } /* seek for truncated packets */ - avio_seek(s->pb, next_klv, SEEK_SET); + avio_seek(s->pb, klv.next_klv, SEEK_SET); return 0; - } else + } else { skip: - avio_skip(s->pb, klv.length); + avio_skip(s->pb, max_data_size); + mxf->current_klv_data = (KLVPacket){{0}}; + } } return avio_feof(s->pb) ? AVERROR_EOF : ret; } -static int mxf_read_packet(AVFormatContext *s, AVPacket *pkt) -{ - MXFContext *mxf = s->priv_data; - int ret, size; - int64_t ret64, pos, next_pos; - AVStream *st; - MXFIndexTable *t; - MXFTrack *track; - int edit_units; - - if (mxf->op != OPAtom) - return mxf_read_packet_old(s, pkt); - - // If we have no streams then we basically are at EOF - st = mxf_get_opatom_stream(mxf); - if (!st) - return AVERROR_EOF; - - track = st->priv_data; - - /* OPAtom - clip wrapped demuxing */ - /* NOTE: mxf_read_header() makes sure nb_index_tables > 0 for OPAtom */ - t = &mxf->index_tables[0]; - - if (mxf->current_edit_unit >= track->original_duration) - return AVERROR_EOF; - - edit_units = FFMIN(mxf->edit_units_per_packet, track->original_duration - mxf->current_edit_unit); - - if ((ret = mxf_edit_unit_absolute_offset(mxf, t, mxf->current_edit_unit, NULL, &pos, 1)) < 0) - return ret; - - /* compute size by finding the next edit unit or the end of the essence container - * not pretty, but it works */ - if ((ret = mxf_edit_unit_absolute_offset(mxf, t, mxf->current_edit_unit + edit_units, NULL, &next_pos, 0)) < 0 && - (next_pos = mxf_essence_container_end(mxf, t->body_sid)) <= 0) { - av_log(s, AV_LOG_ERROR, "unable to compute the size of the last packet\n"); - return AVERROR_INVALIDDATA; - } - - if ((size = next_pos - pos) <= 0) { - av_log(s, AV_LOG_ERROR, "bad size: %i\n", size); - return AVERROR_INVALIDDATA; - } - - if ((ret64 = avio_seek(s->pb, pos, SEEK_SET)) < 0) - return ret64; - - if ((size = av_get_packet(s->pb, pkt, size)) < 0) - return size; - - pkt->stream_index = st->index; - - ret = mxf_set_pts(mxf, st, pkt, next_pos); - if (ret < 0) - return ret; - - mxf->current_edit_unit += edit_units; - - return 0; -} - static int mxf_read_close(AVFormatContext *s) { MXFContext *mxf = s->priv_data; @@ -3405,7 +3599,7 @@ static int mxf_read_close(AVFormatContext *s) return 0; } -static int mxf_probe(AVProbeData *p) { +static int mxf_probe(const AVProbeData *p) { const uint8_t *bufp = p->buf; const uint8_t *end = p->buf + p->buf_size; @@ -3442,7 +3636,7 @@ static int mxf_read_seek(AVFormatContext *s, int stream_index, int64_t sample_ti MXFIndexTable *t; MXFTrack *source_track = st->priv_data; - if(st->codecpar->codec_type == AVMEDIA_TYPE_DATA) + if (!source_track) return 0; /* if audio then truncate sample_time to EditRate */ @@ -3462,8 +3656,10 @@ static int mxf_read_seek(AVFormatContext *s, int stream_index, int64_t sample_ti return seekpos; ff_update_cur_dts(s, st, sample_time); - mxf->current_edit_unit = sample_time; + mxf->current_klv_data = (KLVPacket){{0}}; } else { + MXFPartition *partition; + t = &mxf->index_tables[0]; if (t->index_sid != source_track->index_sid) { /* If the first index table does not belong to the stream, then find a stream which does belong to the index table */ @@ -3506,11 +3702,23 @@ static int mxf_read_seek(AVFormatContext *s, int stream_index, int64_t sample_ti sample_time = FFMIN(sample_time, source_track->original_duration - 1); } - if ((ret = mxf_edit_unit_absolute_offset(mxf, t, sample_time, &sample_time, &seekpos, 1)) < 0) + if (source_track->wrapping == UnknownWrapped) + av_log(mxf->fc, AV_LOG_WARNING, "attempted seek in an UnknownWrapped essence\n"); + + if ((ret = mxf_edit_unit_absolute_offset(mxf, t, sample_time, source_track->edit_rate, &sample_time, &seekpos, &partition, 1)) < 0) return ret; ff_update_cur_dts(s, st, sample_time); - mxf->current_edit_unit = sample_time; + if (source_track->wrapping == ClipWrapped) { + KLVPacket klv = partition->first_essence_klv; + if (seekpos < klv.next_klv - klv.length || seekpos >= klv.next_klv) { + av_log(mxf->fc, AV_LOG_ERROR, "attempted seek out of clip wrapped KLV\n"); + return AVERROR_INVALIDDATA; + } + mxf->current_klv_data = klv; + } else { + mxf->current_klv_data = (KLVPacket){{0}}; + } avio_seek(s->pb, seekpos, SEEK_SET); } @@ -3518,24 +3726,31 @@ static int mxf_read_seek(AVFormatContext *s, int stream_index, int64_t sample_ti for (i = 0; i < s->nb_streams; i++) { AVStream *cur_st = s->streams[i]; MXFTrack *cur_track = cur_st->priv_data; - if (cur_st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) { - int64_t track_edit_unit; - if (st != cur_st && mxf_get_next_track_edit_unit(mxf, cur_track, seekpos, &track_edit_unit) >= 0) { - cur_track->sample_count = av_rescale_q(track_edit_unit, - av_inv_q(cur_track->edit_rate), - cur_st->time_base); - } else { - uint64_t current_sample_count = 0; - ret = mxf_compute_sample_count(mxf, i, ¤t_sample_count); - if (ret < 0) - return ret; - cur_track->sample_count = current_sample_count; - } + if (cur_track) { + int64_t track_edit_unit = sample_time; + if (st != cur_st) + mxf_get_next_track_edit_unit(mxf, cur_track, seekpos, &track_edit_unit); + cur_track->sample_count = mxf_compute_sample_count(mxf, cur_st, track_edit_unit); } } return 0; } +static const AVOption options[] = { + { "eia608_extract", "extract eia 608 captions from s436m track", + offsetof(MXFContext, eia608_extract), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, + AV_OPT_FLAG_DECODING_PARAM }, + { NULL }, +}; + +static const AVClass demuxer_class = { + .class_name = "mxf", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, + .category = AV_CLASS_CATEGORY_DEMUXER, +}; + AVInputFormat ff_mxf_demuxer = { .name = "mxf", .long_name = NULL_IF_CONFIG_SMALL("MXF (Material eXchange Format)"), @@ -3546,4 +3761,5 @@ AVInputFormat ff_mxf_demuxer = { .read_packet = mxf_read_packet, .read_close = mxf_read_close, .read_seek = mxf_read_seek, + .priv_class = &demuxer_class, }; diff --git a/libavformat/mxfenc.c b/libavformat/mxfenc.c index 3bb70326f..2e54320cf 100644 --- a/libavformat/mxfenc.c +++ b/libavformat/mxfenc.c @@ -49,12 +49,14 @@ #include "libavcodec/bytestream.h" #include "libavcodec/dnxhddata.h" #include "libavcodec/dv_profile.h" -#include "libavcodec/h264.h" +#include "libavcodec/h264_ps.h" +#include "libavcodec/golomb.h" #include "libavcodec/internal.h" #include "audiointerleave.h" #include "avformat.h" #include "avio_internal.h" #include "internal.h" +#include "avc.h" #include "mxf.h" #include "config.h" @@ -88,10 +90,18 @@ typedef struct MXFStreamContext { int color_siting; int signal_standard; int h_chroma_sub_sample; + int v_chroma_sub_sample; int temporal_reordering; AVRational aspect_ratio; ///< display aspect ratio int closed_gop; ///< gop is closed, used in mpeg-2 frame parsing int video_bit_rate; + int slice_offset; + int frame_size; ///< frame size in bytes + int seq_closed_gop; ///< all gops in sequence are closed, used in mpeg-2 descriptor + int max_gop; ///< maximum gop size, used by mpeg-2 descriptor + int b_picture_count; ///< maximum number of consecutive b pictures, used in mpeg-2 descriptor + int low_delay; ///< low delay, used in mpeg-2 descriptor + int avc_intra; } MXFStreamContext; typedef struct MXFContainerEssenceEntry { @@ -135,18 +145,11 @@ enum ULIndex { INDEX_DV100_1080_50, INDEX_DV100_720_60, INDEX_DV100_720_50, - INDEX_DNXHD_1080p_10bit_HIGH, - INDEX_DNXHD_1080p_8bit_MEDIUM, - INDEX_DNXHD_1080p_8bit_HIGH, - INDEX_DNXHD_1080i_10bit_HIGH, - INDEX_DNXHD_1080i_8bit_MEDIUM, - INDEX_DNXHD_1080i_8bit_HIGH, - INDEX_DNXHD_720p_10bit, - INDEX_DNXHD_720p_8bit_HIGH, - INDEX_DNXHD_720p_8bit_MEDIUM, - INDEX_DNXHD_720p_8bit_LOW, + INDEX_DNXHD, INDEX_JPEG2000, INDEX_H264, + INDEX_S436M, + INDEX_PRORES, }; static const struct { @@ -157,17 +160,20 @@ static const struct { { AV_CODEC_ID_PCM_S24LE, INDEX_AES3 }, { AV_CODEC_ID_PCM_S16LE, INDEX_AES3 }, { AV_CODEC_ID_DVVIDEO, INDEX_DV }, - { AV_CODEC_ID_DNXHD, INDEX_DNXHD_1080p_10bit_HIGH }, + { AV_CODEC_ID_DNXHD, INDEX_DNXHD }, { AV_CODEC_ID_JPEG2000, INDEX_JPEG2000 }, { AV_CODEC_ID_H264, INDEX_H264 }, + { AV_CODEC_ID_PRORES, INDEX_PRORES }, { AV_CODEC_ID_NONE } }; static void mxf_write_wav_desc(AVFormatContext *s, AVStream *st); static void mxf_write_aes3_desc(AVFormatContext *s, AVStream *st); static void mxf_write_mpegvideo_desc(AVFormatContext *s, AVStream *st); +static void mxf_write_h264_desc(AVFormatContext *s, AVStream *st); static void mxf_write_cdci_desc(AVFormatContext *s, AVStream *st); static void mxf_write_generic_sound_desc(AVFormatContext *s, AVStream *st); +static void mxf_write_s436m_anc_desc(AVFormatContext *s, AVStream *st); static const MXFContainerEssenceEntry mxf_essence_container_uls[] = { { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x02,0x0D,0x01,0x03,0x01,0x02,0x04,0x60,0x01 }, @@ -294,56 +300,11 @@ static const MXFContainerEssenceEntry mxf_essence_container_uls[] = { { 0x06,0x0E,0x2B,0x34,0x01,0x02,0x01,0x01,0x0D,0x01,0x03,0x01,0x18,0x01,0x01,0x00 }, { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x04,0x01,0x02,0x02,0x02,0x02,0x08,0x00 }, mxf_write_cdci_desc }, - // DNxHD 1080p 10bit high + // DNxHD { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x0D,0x01,0x03,0x01,0x02,0x11,0x01,0x00 }, { 0x06,0x0E,0x2B,0x34,0x01,0x02,0x01,0x01,0x0D,0x01,0x03,0x01,0x15,0x01,0x05,0x00 }, { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0A,0x04,0x01,0x02,0x02,0x71,0x01,0x00,0x00 }, mxf_write_cdci_desc }, - // DNxHD 1080p 8bit medium - { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x0D,0x01,0x03,0x01,0x02,0x11,0x01,0x00 }, - { 0x06,0x0E,0x2B,0x34,0x01,0x02,0x01,0x01,0x0D,0x01,0x03,0x01,0x15,0x01,0x05,0x00 }, - { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0A,0x04,0x01,0x02,0x02,0x71,0x03,0x00,0x00 }, - mxf_write_cdci_desc }, - // DNxHD 1080p 8bit high - { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x0D,0x01,0x03,0x01,0x02,0x11,0x01,0x00 }, - { 0x06,0x0E,0x2B,0x34,0x01,0x02,0x01,0x01,0x0D,0x01,0x03,0x01,0x15,0x01,0x05,0x00 }, - { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0A,0x04,0x01,0x02,0x02,0x71,0x04,0x00,0x00 }, - mxf_write_cdci_desc }, - // DNxHD 1080i 10bit high - { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x0D,0x01,0x03,0x01,0x02,0x11,0x01,0x00 }, - { 0x06,0x0E,0x2B,0x34,0x01,0x02,0x01,0x01,0x0D,0x01,0x03,0x01,0x15,0x01,0x05,0x00 }, - { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0A,0x04,0x01,0x02,0x02,0x71,0x07,0x00,0x00 }, - mxf_write_cdci_desc }, - // DNxHD 1080i 8bit medium - { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x0D,0x01,0x03,0x01,0x02,0x11,0x01,0x00 }, - { 0x06,0x0E,0x2B,0x34,0x01,0x02,0x01,0x01,0x0D,0x01,0x03,0x01,0x15,0x01,0x05,0x00 }, - { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0A,0x04,0x01,0x02,0x02,0x71,0x08,0x00,0x00 }, - mxf_write_cdci_desc }, - // DNxHD 1080i 8bit high - { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x0D,0x01,0x03,0x01,0x02,0x11,0x01,0x00 }, - { 0x06,0x0E,0x2B,0x34,0x01,0x02,0x01,0x01,0x0D,0x01,0x03,0x01,0x15,0x01,0x05,0x00 }, - { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0A,0x04,0x01,0x02,0x02,0x71,0x09,0x00,0x00 }, - mxf_write_cdci_desc }, - // DNxHD 720p 10bit - { { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x01,0x0d,0x01,0x03,0x01,0x02,0x11,0x01,0x00 }, - { 0x06,0x0e,0x2b,0x34,0x01,0x02,0x01,0x01,0x0d,0x01,0x03,0x01,0x15,0x01,0x05,0x00 }, - { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0A,0x04,0x01,0x02,0x02,0x71,0x10,0x00,0x00 }, - mxf_write_cdci_desc }, - // DNxHD 720p 8bit high - { { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x01,0x0d,0x01,0x03,0x01,0x02,0x11,0x01,0x00 }, - { 0x06,0x0e,0x2b,0x34,0x01,0x02,0x01,0x01,0x0d,0x01,0x03,0x01,0x15,0x01,0x05,0x00 }, - { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0A,0x04,0x01,0x02,0x02,0x71,0x11,0x00,0x00 }, - mxf_write_cdci_desc }, - // DNxHD 720p 8bit medium - { { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x01,0x0d,0x01,0x03,0x01,0x02,0x11,0x01,0x00 }, - { 0x06,0x0e,0x2b,0x34,0x01,0x02,0x01,0x01,0x0d,0x01,0x03,0x01,0x15,0x01,0x05,0x00 }, - { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0A,0x04,0x01,0x02,0x02,0x71,0x12,0x00,0x00 }, - mxf_write_cdci_desc }, - // DNxHD 720p 8bit low - { { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x01,0x0d,0x01,0x03,0x01,0x02,0x11,0x01,0x00 }, - { 0x06,0x0e,0x2b,0x34,0x01,0x02,0x01,0x01,0x0d,0x01,0x03,0x01,0x15,0x01,0x05,0x00 }, - { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x0A,0x04,0x01,0x02,0x02,0x71,0x13,0x00,0x00 }, - mxf_write_cdci_desc }, // JPEG2000 { { 0x06,0x0e,0x2b,0x34,0x04,0x01,0x01,0x07,0x0d,0x01,0x03,0x01,0x02,0x0c,0x01,0x00 }, { 0x06,0x0e,0x2b,0x34,0x01,0x02,0x01,0x01,0x0d,0x01,0x03,0x01,0x15,0x01,0x08,0x00 }, @@ -353,7 +314,17 @@ static const MXFContainerEssenceEntry mxf_essence_container_uls[] = { { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x0D,0x01,0x03,0x01,0x02,0x10,0x60,0x01 }, { 0x06,0x0E,0x2B,0x34,0x01,0x02,0x01,0x01,0x0D,0x01,0x03,0x01,0x15,0x01,0x05,0x00 }, { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x00,0x00,0x00 }, - mxf_write_mpegvideo_desc }, + mxf_write_h264_desc }, + // S436M ANC + { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x0D,0x01,0x03,0x01,0x02,0x0e,0x00,0x00 }, + { 0x06,0x0E,0x2B,0x34,0x01,0x02,0x01,0x01,0x0D,0x01,0x03,0x01,0x17,0x01,0x02,0x00 }, + { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x01,0x5C,0x00 }, + mxf_write_s436m_anc_desc }, + // ProRes + { { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0d,0x0d,0x01,0x03,0x01,0x02,0x1c,0x01,0x00 }, + { 0x06,0x0E,0x2B,0x34,0x01,0x02,0x01,0x01,0x0d,0x01,0x03,0x01,0x15,0x01,0x17,0x00 }, + { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0d,0x04,0x01,0x02,0x02,0x03,0x06,0x03,0x00 }, + mxf_write_cdci_desc }, { { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, @@ -379,6 +350,7 @@ typedef struct MXFContext { AVStream *timecode_track; int timecode_base; ///< rounded time code base (25 or 30) int edit_unit_byte_count; ///< fixed edit unit byte count + int content_package_rate; ///< content package rate in system element, see SMPTE 326M uint64_t body_offset; uint32_t instance_number; uint8_t umid[16]; ///< unique material identifier @@ -388,6 +360,7 @@ typedef struct MXFContext { AVRational audio_edit_rate; int store_user_comments; int track_instance_count; // used to generate MXFTrack uuids + int cbr_index; ///< use a constant bitrate index } MXFContext; static const uint8_t uuid_base[] = { 0xAD,0xAB,0x44,0x24,0x2f,0x25,0x4d,0xc7,0x92,0xff,0x29,0xbd }; @@ -422,6 +395,7 @@ static const MXFLocalTagPair mxf_local_tag_batch[] = { { 0x3C0A, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x01,0x01,0x01,0x15,0x02,0x00,0x00,0x00,0x00}}, /* Instance UID */ { 0x3B02, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x02,0x07,0x02,0x01,0x10,0x02,0x04,0x00,0x00}}, /* Last Modified Date */ { 0x3B05, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x02,0x03,0x01,0x02,0x01,0x05,0x00,0x00,0x00}}, /* Version */ + { 0x3B07, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x02,0x03,0x01,0x02,0x01,0x04,0x00,0x00,0x00}}, /* Object Model Version */ { 0x3B06, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x02,0x06,0x01,0x01,0x04,0x06,0x04,0x00,0x00}}, /* Identifications reference */ { 0x3B03, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x02,0x06,0x01,0x01,0x04,0x02,0x01,0x00,0x00}}, /* Content Storage reference */ { 0x3B09, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x05,0x01,0x02,0x02,0x03,0x00,0x00,0x00,0x00}}, /* Operational Pattern UL */ @@ -431,9 +405,12 @@ static const MXFLocalTagPair mxf_local_tag_batch[] = { { 0x3C09, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x02,0x05,0x20,0x07,0x01,0x01,0x00,0x00,0x00}}, /* This Generation UID */ { 0x3C01, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x02,0x05,0x20,0x07,0x01,0x02,0x01,0x00,0x00}}, /* Company Name */ { 0x3C02, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x02,0x05,0x20,0x07,0x01,0x03,0x01,0x00,0x00}}, /* Product Name */ + { 0x3C03, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x02,0x05,0x20,0x07,0x01,0x04,0x00,0x00,0x00}}, /* Product Version */ { 0x3C04, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x02,0x05,0x20,0x07,0x01,0x05,0x01,0x00,0x00}}, /* Version String */ { 0x3C05, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x02,0x05,0x20,0x07,0x01,0x07,0x00,0x00,0x00}}, /* Product ID */ { 0x3C06, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x02,0x07,0x02,0x01,0x10,0x02,0x03,0x00,0x00}}, /* Modification Date */ + { 0x3C07, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x02,0x05,0x20,0x07,0x01,0x0A,0x00,0x00,0x00}}, /* Toolkit Version */ + { 0x3C08, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x02,0x05,0x20,0x07,0x01,0x06,0x01,0x00,0x00}}, /* Platform */ // Content Storage { 0x1901, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x02,0x06,0x01,0x01,0x04,0x05,0x01,0x00,0x00}}, /* Package strong reference batch */ { 0x1902, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x02,0x06,0x01,0x01,0x04,0x05,0x02,0x00,0x00}}, /* Package strong reference batch */ @@ -476,20 +453,36 @@ static const MXFLocalTagPair mxf_local_tag_batch[] = { { 0x320D, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x02,0x04,0x01,0x03,0x02,0x05,0x00,0x00,0x00}}, /* Video Line Map */ { 0x3203, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x01,0x04,0x01,0x05,0x02,0x02,0x00,0x00,0x00}}, /* Stored Width */ { 0x3202, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x01,0x04,0x01,0x05,0x02,0x01,0x00,0x00,0x00}}, /* Stored Height */ + { 0x3216, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x05,0x04,0x01,0x03,0x02,0x08,0x00,0x00,0x00}}, /* Stored F2 Offset */ + { 0x3205, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x01,0x04,0x01,0x05,0x01,0x08,0x00,0x00,0x00}}, /* Sampled Width */ + { 0x3204, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x01,0x04,0x01,0x05,0x01,0x07,0x00,0x00,0x00}}, /* Sampled Height */ + { 0x3206, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x01,0x04,0x01,0x05,0x01,0x09,0x00,0x00,0x00}}, /* Sampled X Offset */ + { 0x3207, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x01,0x04,0x01,0x05,0x01,0x0A,0x00,0x00,0x00}}, /* Sampled Y Offset */ { 0x3209, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x01,0x04,0x01,0x05,0x01,0x0C,0x00,0x00,0x00}}, /* Display Width */ { 0x3208, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x01,0x04,0x01,0x05,0x01,0x0B,0x00,0x00,0x00}}, /* Display Height */ + { 0x320A, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x01,0x04,0x01,0x05,0x01,0x0D,0x00,0x00,0x00}}, /* Display X offset */ { 0x320B, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x01,0x04,0x01,0x05,0x01,0x0E,0x00,0x00,0x00}}, /* Presentation Y offset */ + { 0x3217, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x05,0x04,0x01,0x03,0x02,0x07,0x00,0x00,0x00}}, /* Display F2 offset */ { 0x320E, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x01,0x04,0x01,0x01,0x01,0x01,0x00,0x00,0x00}}, /* Aspect Ratio */ + { 0x3210, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x02,0x04,0x01,0x02,0x01,0x01,0x01,0x02,0x00}}, /* Transfer characteristic */ + { 0x3213, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x02,0x04,0x18,0x01,0x02,0x00,0x00,0x00,0x00}}, /* Image Start Offset */ + { 0x3214, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x02,0x04,0x18,0x01,0x03,0x00,0x00,0x00,0x00}}, /* Image End Offset */ { 0x3201, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x02,0x04,0x01,0x06,0x01,0x00,0x00,0x00,0x00}}, /* Picture Essence Coding */ { 0x3212, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x02,0x04,0x01,0x03,0x01,0x06,0x00,0x00,0x00}}, /* Field Dominance (Opt) */ { 0x3215, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x05,0x04,0x05,0x01,0x13,0x00,0x00,0x00,0x00}}, /* Signal Standard */ // CDCI Picture Essence Descriptor { 0x3301, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x02,0x04,0x01,0x05,0x03,0x0A,0x00,0x00,0x00}}, /* Component Depth */ { 0x3302, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x01,0x04,0x01,0x05,0x01,0x05,0x00,0x00,0x00}}, /* Horizontal Subsampling */ + { 0x3308, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x02,0x04,0x01,0x05,0x01,0x10,0x00,0x00,0x00}}, /* Vertical Subsampling */ { 0x3303, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x01,0x04,0x01,0x05,0x01,0x06,0x00,0x00,0x00}}, /* Color Siting */ + { 0x3307, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x02,0x04,0x18,0x01,0x04,0x00,0x00,0x00,0x00}}, /* Padding Bits */ + { 0x3304, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x01,0x04,0x01,0x05,0x03,0x03,0x00,0x00,0x00}}, /* Black Ref level */ + { 0x3305, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x01,0x04,0x01,0x05,0x03,0x04,0x00,0x00,0x00}}, /* White Ref level */ + { 0x3306, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x02,0x04,0x01,0x05,0x03,0x05,0x00,0x00,0x00}}, /* Color Range */ // Generic Sound Essence Descriptor { 0x3D02, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x04,0x04,0x02,0x03,0x01,0x04,0x00,0x00,0x00}}, /* Locked/Unlocked */ { 0x3D03, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x05,0x04,0x02,0x03,0x01,0x01,0x01,0x00,0x00}}, /* Audio sampling rate */ + { 0x3D04, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x01,0x04,0x02,0x01,0x01,0x03,0x00,0x00,0x00}}, /* Audio Ref Level */ { 0x3D07, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x05,0x04,0x02,0x01,0x01,0x04,0x00,0x00,0x00}}, /* ChannelCount */ { 0x3D01, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x04,0x04,0x02,0x03,0x03,0x04,0x00,0x00,0x00}}, /* Quantization bits */ { 0x3D06, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x02,0x04,0x02,0x04,0x02,0x00,0x00,0x00,0x00}}, /* Sound Essence Compression */ @@ -504,12 +497,23 @@ static const MXFLocalTagPair mxf_local_tag_batch[] = { { 0x3F0A, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x05,0x04,0x04,0x04,0x02,0x05,0x00,0x00,0x00}}, /* Index Entry Array */ // MPEG video Descriptor { 0x8000, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x05,0x04,0x01,0x06,0x02,0x01,0x0B,0x00,0x00}}, /* BitRate */ + { 0x8003, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x05,0x04,0x01,0x06,0x02,0x01,0x05,0x00,0x00}}, /* LowDelay */ + { 0x8004, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x05,0x04,0x01,0x06,0x02,0x01,0x06,0x00,0x00}}, /* ClosedGOP */ + { 0x8006, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x05,0x04,0x01,0x06,0x02,0x01,0x08,0x00,0x00}}, /* MaxGOP */ { 0x8007, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x05,0x04,0x01,0x06,0x02,0x01,0x0A,0x00,0x00}}, /* ProfileAndLevel */ + { 0x8008, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x05,0x04,0x01,0x06,0x02,0x01,0x09,0x00,0x00}}, /* BPictureCount */ // Wave Audio Essence Descriptor { 0x3D09, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x05,0x04,0x02,0x03,0x03,0x05,0x00,0x00,0x00}}, /* Average Bytes Per Second */ { 0x3D0A, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x05,0x04,0x02,0x03,0x02,0x01,0x00,0x00,0x00}}, /* Block Align */ }; +static const MXFLocalTagPair mxf_avc_subdescriptor_local_tags[] = { + { 0x8100, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x09,0x06,0x01,0x01,0x04,0x06,0x10,0x00,0x00}}, /* SubDescriptors */ + { 0x8200, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x0E,0x04,0x01,0x06,0x06,0x01,0x0E,0x00,0x00}}, /* AVC Decoding Delay */ + { 0x8201, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x0E,0x04,0x01,0x06,0x06,0x01,0x0A,0x00,0x00}}, /* AVC Profile */ + { 0x8202, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x0E,0x04,0x01,0x06,0x06,0x01,0x0D,0x00,0x00}}, /* AVC Level */ +}; + static const MXFLocalTagPair mxf_user_comments_local_tag[] = { { 0x4406, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x02,0x03,0x02,0x01,0x02,0x0C,0x00,0x00,0x00}}, /* User Comments */ { 0x5001, {0x06,0x0E,0x2B,0x34,0x01,0x01,0x01,0x02,0x03,0x02,0x01,0x02,0x09,0x01,0x00,0x00}}, /* Name */ @@ -591,15 +595,33 @@ static int mxf_get_essence_container_ul_index(enum AVCodecID id) return -1; } +static void mxf_write_local_tags(AVIOContext *pb, const MXFLocalTagPair *local_tags, int count) +{ + int i; + for (i = 0; i < count; i++) { + avio_wb16(pb, local_tags[i].local_tag); + avio_write(pb, local_tags[i].uid, 16); + } +} + static void mxf_write_primer_pack(AVFormatContext *s) { MXFContext *mxf = s->priv_data; AVIOContext *pb = s->pb; int local_tag_number, i = 0; + int avc_tags_count = 0; local_tag_number = FF_ARRAY_ELEMS(mxf_local_tag_batch); local_tag_number += mxf->store_user_comments * FF_ARRAY_ELEMS(mxf_user_comments_local_tag); + for (i = 0; i < s->nb_streams; i++) { + MXFStreamContext *sc = s->streams[i]->priv_data; + if (s->streams[i]->codecpar->codec_id == AV_CODEC_ID_H264 && !sc->avc_intra) { + avc_tags_count = FF_ARRAY_ELEMS(mxf_avc_subdescriptor_local_tags); + local_tag_number += avc_tags_count; + } + } + avio_write(pb, primer_pack_key, 16); klv_encode_ber_length(pb, local_tag_number * 18 + 8); @@ -615,6 +637,8 @@ static void mxf_write_primer_pack(AVFormatContext *s) avio_wb16(pb, mxf_user_comments_local_tag[i].local_tag); avio_write(pb, mxf_user_comments_local_tag[i].uid, 16); } + if (avc_tags_count > 0) + mxf_write_local_tags(pb, mxf_avc_subdescriptor_local_tags, avc_tags_count); } static void mxf_write_local_tag(AVIOContext *pb, int size, int tag) @@ -662,9 +686,14 @@ static void mxf_write_essence_container_refs(AVFormatContext *s) mxf_write_refs_count(pb, DESCRIPTOR_COUNT(c->essence_container_count)); av_log(s,AV_LOG_DEBUG, "essence container count:%d\n", c->essence_container_count); - for (i = 0; i < c->essence_container_count; i++) { + for (i = 0; i < s->nb_streams; i++) { MXFStreamContext *sc = s->streams[i]->priv_data; + // check first track of essence container type and only write it once + if (sc->track_essence_element_key[15] != 0) + continue; avio_write(pb, mxf_essence_container_uls[sc->index].container_ul, 16); + if (c->essence_container_count == 1) + break; } if (c->essence_container_count > 1) @@ -678,7 +707,7 @@ static void mxf_write_preface(AVFormatContext *s) mxf_write_metadata_key(pb, 0x012f00); PRINT_KEY(s, "preface key", pb->buf_ptr - 16); - klv_encode_ber_length(pb, 130 + 16LL * DESCRIPTOR_COUNT(mxf->essence_container_count)); + klv_encode_ber_length(pb, 138 + 16LL * DESCRIPTOR_COUNT(mxf->essence_container_count)); // write preface set uid mxf_write_local_tag(pb, 16, 0x3C0A); @@ -691,7 +720,11 @@ static void mxf_write_preface(AVFormatContext *s) // write version mxf_write_local_tag(pb, 2, 0x3B05); - avio_wb16(pb, 258); // v1.2 + avio_wb16(pb, 259); // v1.3 + + // Object Model Version + mxf_write_local_tag(pb, 4, 0x3B07); + avio_wb32(pb, 1); // write identification_refs mxf_write_local_tag(pb, 16 + 8, 0x3B06); @@ -776,6 +809,22 @@ static void mxf_write_local_tag_utf16(AVIOContext *pb, int tag, const char *valu avio_put_str16be(pb, value); } +static void store_version(AVFormatContext *s){ + AVIOContext *pb = s->pb; + + if (s->flags & AVFMT_FLAG_BITEXACT) { + avio_wb16(pb, 0); // major + avio_wb16(pb, 0); // minor + avio_wb16(pb, 0); // tertiary + } else { + avio_wb16(pb, LIBAVFORMAT_VERSION_MAJOR); // major + avio_wb16(pb, LIBAVFORMAT_VERSION_MINOR); // minor + avio_wb16(pb, LIBAVFORMAT_VERSION_MICRO); // tertiary + } + avio_wb16(pb, 0); // patch + avio_wb16(pb, 0); // release +} + static void mxf_write_identification(AVFormatContext *s) { MXFContext *mxf = s->priv_data; @@ -790,7 +839,7 @@ static void mxf_write_identification(AVFormatContext *s) version = s->flags & AVFMT_FLAG_BITEXACT ? "0.0.0" : AV_STRINGIFY(LIBAVFORMAT_VERSION); - length = 72 + mxf_utf16_local_tag_length(company) + + length = 100 +mxf_utf16_local_tag_length(company) + mxf_utf16_local_tag_length(product) + mxf_utf16_local_tag_length(version); klv_encode_ber_length(pb, length); @@ -805,6 +854,10 @@ static void mxf_write_identification(AVFormatContext *s) mxf_write_uuid(pb, Identification, 1); mxf_write_local_tag_utf16(pb, 0x3C01, company); // Company Name mxf_write_local_tag_utf16(pb, 0x3C02, product); // Product Name + + mxf_write_local_tag(pb, 10, 0x3C03); // Product Version + store_version(s); + mxf_write_local_tag_utf16(pb, 0x3C04, version); // Version String // write product uid @@ -814,6 +867,9 @@ static void mxf_write_identification(AVFormatContext *s) // modification date mxf_write_local_tag(pb, 8, 0x3C06); avio_wb64(pb, mxf->timestamp); + + mxf_write_local_tag(pb, 10, 0x3C07); // Toolkit Version + store_version(s); } static void mxf_write_content_storage(AVFormatContext *s, MXFPackage *packages, int package_count) @@ -1056,14 +1112,16 @@ static void mxf_write_multi_descriptor(AVFormatContext *s) mxf_write_uuid(pb, SubDescriptor, i); } -static void mxf_write_generic_desc(AVFormatContext *s, AVStream *st, const UID key, unsigned size) +static int64_t mxf_write_generic_desc(AVFormatContext *s, AVStream *st, const UID key) { MXFContext *mxf = s->priv_data; MXFStreamContext *sc = st->priv_data; AVIOContext *pb = s->pb; + int64_t pos; avio_write(pb, key, 16); - klv_encode_ber4_length(pb, size+20+8+12+20); + klv_encode_ber4_length(pb, 0); + pos = avio_tell(pb); mxf_write_local_tag(pb, 16, 0x3C0A); mxf_write_uuid(pb, SubDescriptor, st->index); @@ -1088,35 +1146,96 @@ static void mxf_write_generic_desc(AVFormatContext *s, AVStream *st, const UID k mxf_write_local_tag(pb, 16, 0x3004); avio_write(pb, mxf_essence_container_uls[sc->index].container_ul, 16); + + return pos; } +static const UID mxf_s436m_anc_descriptor_key = { 0x06,0x0e,0x2b,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x5c,0x00 }; static const UID mxf_mpegvideo_descriptor_key = { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x51,0x00 }; static const UID mxf_wav_descriptor_key = { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x48,0x00 }; static const UID mxf_aes3_descriptor_key = { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x47,0x00 }; static const UID mxf_cdci_descriptor_key = { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0D,0x01,0x01,0x01,0x01,0x01,0x28,0x00 }; static const UID mxf_generic_sound_descriptor_key = { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0D,0x01,0x01,0x01,0x01,0x01,0x42,0x00 }; -static void mxf_write_cdci_common(AVFormatContext *s, AVStream *st, const UID key, unsigned size) +static const UID mxf_avc_subdescriptor_key = { 0x06,0x0E,0x2B,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x6E,0x00 }; + +static int get_trc(UID ul, enum AVColorTransferCharacteristic trc) +{ + switch (trc){ + case AVCOL_TRC_GAMMA28 : + case AVCOL_TRC_GAMMA22 : + memcpy(ul, ((UID){0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x04,0x01,0x01,0x01,0x01,0x01,0x00,0x00}), 16); + return 0; + case AVCOL_TRC_BT709 : + case AVCOL_TRC_SMPTE170M : + memcpy(ul, ((UID){0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x04,0x01,0x01,0x01,0x01,0x02,0x00,0x00}), 16); + return 0; + case AVCOL_TRC_SMPTE240M : + memcpy(ul, ((UID){0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x04,0x01,0x01,0x01,0x01,0x03,0x00,0x00}), 16); + return 0; + case AVCOL_TRC_BT1361_ECG: + memcpy(ul, ((UID){0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x06,0x04,0x01,0x01,0x01,0x01,0x05,0x00,0x00}), 16); + return 0; + case AVCOL_TRC_LINEAR : + memcpy(ul, ((UID){0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x06,0x04,0x01,0x01,0x01,0x01,0x06,0x00,0x00}), 16); + return 0; + case AVCOL_TRC_SMPTE428 : + memcpy(ul, ((UID){0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x08,0x04,0x01,0x01,0x01,0x01,0x07,0x00,0x00}), 16); + return 0; + default: + return -1; + } +} + +static int64_t mxf_write_cdci_common(AVFormatContext *s, AVStream *st, const UID key) { MXFStreamContext *sc = st->priv_data; AVIOContext *pb = s->pb; + int stored_width = (st->codecpar->width +15)/16*16; int stored_height = (st->codecpar->height+15)/16*16; int display_height; int f1, f2; - unsigned desc_size = size+8+8+8+8+8+8+8+5+16+4+12+20+5; - if (sc->interlaced && sc->field_dominance) - desc_size += 5; - if (sc->signal_standard) - desc_size += 5; + UID transfer_ul = {0}; + int64_t pos = mxf_write_generic_desc(s, st, key); - mxf_write_generic_desc(s, st, key, desc_size); + get_trc(transfer_ul, st->codecpar->color_trc); mxf_write_local_tag(pb, 4, 0x3203); - avio_wb32(pb, st->codecpar->width); + avio_wb32(pb, stored_width); mxf_write_local_tag(pb, 4, 0x3202); avio_wb32(pb, stored_height>>sc->interlaced); + if (s->oformat == &ff_mxf_d10_muxer) { + //Stored F2 Offset + mxf_write_local_tag(pb, 4, 0x3216); + avio_wb32(pb, 0); + + //Image Start Offset + mxf_write_local_tag(pb, 4, 0x3213); + avio_wb32(pb, 0); + + //Image End Offset + mxf_write_local_tag(pb, 4, 0x3214); + avio_wb32(pb, 0); + } + + //Sampled width + mxf_write_local_tag(pb, 4, 0x3205); + avio_wb32(pb, st->codecpar->width); + + //Samples height + mxf_write_local_tag(pb, 4, 0x3204); + avio_wb32(pb, st->codecpar->height>>sc->interlaced); + + //Sampled X Offset + mxf_write_local_tag(pb, 4, 0x3206); + avio_wb32(pb, 0); + + //Sampled Y Offset + mxf_write_local_tag(pb, 4, 0x3207); + avio_wb32(pb, 0); + mxf_write_local_tag(pb, 4, 0x3209); avio_wb32(pb, st->codecpar->width); @@ -1130,10 +1249,20 @@ static void mxf_write_cdci_common(AVFormatContext *s, AVStream *st, const UID ke mxf_write_local_tag(pb, 4, 0x3208); avio_wb32(pb, display_height>>sc->interlaced); - // presentation Y offset + // display X offset + mxf_write_local_tag(pb, 4, 0x320A); + avio_wb32(pb, 0); + + // display Y offset mxf_write_local_tag(pb, 4, 0x320B); avio_wb32(pb, (st->codecpar->height - display_height)>>sc->interlaced); + if (sc->interlaced) { + //Display F2 Offset + mxf_write_local_tag(pb, 4, 0x3217); + avio_wb32(pb, -((st->codecpar->height - display_height)&1)); + } + // component depth mxf_write_local_tag(pb, 4, 0x3301); avio_wb32(pb, sc->component_depth); @@ -1142,10 +1271,35 @@ static void mxf_write_cdci_common(AVFormatContext *s, AVStream *st, const UID ke mxf_write_local_tag(pb, 4, 0x3302); avio_wb32(pb, sc->h_chroma_sub_sample); + // vertical subsampling + mxf_write_local_tag(pb, 4, 0x3308); + avio_wb32(pb, sc->v_chroma_sub_sample); + // color siting mxf_write_local_tag(pb, 1, 0x3303); avio_w8(pb, sc->color_siting); + // Padding Bits + mxf_write_local_tag(pb, 2, 0x3307); + avio_wb16(pb, 0); + + if (st->codecpar->color_range != AVCOL_RANGE_UNSPECIFIED) { + int black = 0, + white = (1<component_depth) - 1, + color = (1<component_depth) - 1; + if (st->codecpar->color_range == AVCOL_RANGE_MPEG) { + black = 1 << (sc->component_depth - 4); + white = 235 << (sc->component_depth - 8); + color = (14 << (sc->component_depth - 4)) + 1; + } + mxf_write_local_tag(pb, 4, 0x3304); + avio_wb32(pb, black); + mxf_write_local_tag(pb, 4, 0x3305); + avio_wb32(pb, white); + mxf_write_local_tag(pb, 4, 0x3306); + avio_wb32(pb, color); + } + if (sc->signal_standard) { mxf_write_local_tag(pb, 1, 0x3215); avio_w8(pb, sc->signal_standard); @@ -1166,7 +1320,7 @@ static void mxf_write_cdci_common(AVFormatContext *s, AVStream *st, const UID ke default: f1 = 0; f2 = 0; break; } - if (!sc->interlaced) { + if (!sc->interlaced && f2) { f2 = 0; f1 *= 2; } @@ -1182,6 +1336,12 @@ static void mxf_write_cdci_common(AVFormatContext *s, AVStream *st, const UID ke avio_wb32(pb, sc->aspect_ratio.num); avio_wb32(pb, sc->aspect_ratio.den); + //Transfer characteristic + if (transfer_ul[0]) { + mxf_write_local_tag(pb, 16, 0x3210); + avio_write(pb, transfer_ul, 16); + }; + mxf_write_local_tag(pb, 16, 0x3201); avio_write(pb, *sc->codec_ul, 16); @@ -1190,11 +1350,75 @@ static void mxf_write_cdci_common(AVFormatContext *s, AVStream *st, const UID ke avio_w8(pb, sc->field_dominance); } + if (st->codecpar->codec_id == AV_CODEC_ID_H264 && !sc->avc_intra) { + // write avc sub descriptor ref + mxf_write_local_tag(pb, 8 + 16, 0x8100); + mxf_write_refs_count(pb, 1); + mxf_write_uuid(pb, AVCSubDescriptor, 0); + } + + return pos; +} + +static void mxf_update_klv_size(AVIOContext *pb, int64_t pos) +{ + int64_t cur_pos = avio_tell(pb); + int size = cur_pos - pos; + avio_seek(pb, pos - 4, SEEK_SET); + klv_encode_ber4_length(pb, size); + avio_seek(pb, cur_pos, SEEK_SET); +} + +static void mxf_write_avc_subdesc(AVFormatContext *s, AVStream *st) +{ + AVIOContext *pb = s->pb; + int64_t pos; + + avio_write(pb, mxf_avc_subdescriptor_key, 16); + klv_encode_ber4_length(pb, 0); + pos = avio_tell(pb); + + mxf_write_local_tag(pb, 16, 0x3C0A); + mxf_write_uuid(pb, AVCSubDescriptor, 0); + + mxf_write_local_tag(pb, 1, 0x8200); + avio_w8(pb, 0xFF); // AVC Decoding Delay, unknown + + mxf_write_local_tag(pb, 1, 0x8201); + avio_w8(pb, st->codecpar->profile); // AVC Profile + + mxf_write_local_tag(pb, 1, 0x8202); + avio_w8(pb, st->codecpar->level); // AVC Level + + mxf_update_klv_size(s->pb, pos); } static void mxf_write_cdci_desc(AVFormatContext *s, AVStream *st) { - mxf_write_cdci_common(s, st, mxf_cdci_descriptor_key, 0); + int64_t pos = mxf_write_cdci_common(s, st, mxf_cdci_descriptor_key); + mxf_update_klv_size(s->pb, pos); + + if (st->codecpar->codec_id == AV_CODEC_ID_H264) { + mxf_write_avc_subdesc(s, st); + } +} + +static void mxf_write_h264_desc(AVFormatContext *s, AVStream *st) +{ + MXFStreamContext *sc = st->priv_data; + if (sc->avc_intra) { + mxf_write_mpegvideo_desc(s, st); + } else { + int64_t pos = mxf_write_cdci_common(s, st, mxf_cdci_descriptor_key); + mxf_update_klv_size(s->pb, pos); + mxf_write_avc_subdesc(s, st); + } +} + +static void mxf_write_s436m_anc_desc(AVFormatContext *s, AVStream *st) +{ + int64_t pos = mxf_write_generic_desc(s, st, mxf_s436m_anc_descriptor_key); + mxf_update_klv_size(s->pb, pos); } static void mxf_write_mpegvideo_desc(AVFormatContext *s, AVStream *st) @@ -1202,10 +1426,9 @@ static void mxf_write_mpegvideo_desc(AVFormatContext *s, AVStream *st) AVIOContext *pb = s->pb; MXFStreamContext *sc = st->priv_data; int profile_and_level = (st->codecpar->profile<<4) | st->codecpar->level; + int64_t pos = mxf_write_cdci_common(s, st, mxf_mpegvideo_descriptor_key); if (st->codecpar->codec_id != AV_CODEC_ID_H264) { - mxf_write_cdci_common(s, st, mxf_mpegvideo_descriptor_key, 8+5); - // bit rate mxf_write_local_tag(pb, 4, 0x8000); avio_wb32(pb, sc->video_bit_rate); @@ -1215,24 +1438,35 @@ static void mxf_write_mpegvideo_desc(AVFormatContext *s, AVStream *st) if (!st->codecpar->profile) profile_and_level |= 0x80; // escape bit avio_w8(pb, profile_and_level); - } else { - mxf_write_cdci_common(s, st, mxf_mpegvideo_descriptor_key, 0); + + // low delay + mxf_write_local_tag(pb, 1, 0x8003); + avio_w8(pb, sc->low_delay); + + // closed gop + mxf_write_local_tag(pb, 1, 0x8004); + avio_w8(pb, sc->seq_closed_gop); + + // max gop + mxf_write_local_tag(pb, 2, 0x8006); + avio_wb16(pb, sc->max_gop); + + // b picture count + mxf_write_local_tag(pb, 2, 0x8008); + avio_wb16(pb, sc->b_picture_count); } + + mxf_update_klv_size(pb, pos); } -static void mxf_write_generic_sound_common(AVFormatContext *s, AVStream *st, const UID key, unsigned size) +static int64_t mxf_write_generic_sound_common(AVFormatContext *s, AVStream *st, const UID key) { AVIOContext *pb = s->pb; MXFContext *mxf = s->priv_data; int show_warnings = !mxf->footer_partition_offset; - int duration_size = 0; + int64_t pos = mxf_write_generic_desc(s, st, key); - if (s->oformat == &ff_mxf_opatom_muxer) - duration_size = 12; - - mxf_write_generic_desc(s, st, key, size+duration_size+5+12+8+8); - - if (duration_size > 0) { + if (s->oformat == &ff_mxf_opatom_muxer) { mxf_write_local_tag(pb, 8, 0x3002); avio_wb64(pb, mxf->body_offset / mxf->edit_unit_byte_count); } @@ -1246,6 +1480,11 @@ static void mxf_write_generic_sound_common(AVFormatContext *s, AVStream *st, con avio_wb32(pb, st->codecpar->sample_rate); avio_wb32(pb, 1); + if (s->oformat == &ff_mxf_d10_muxer) { + mxf_write_local_tag(pb, 1, 0x3D04); + avio_w8(pb, 0); + } + mxf_write_local_tag(pb, 4, 0x3D07); if (mxf->channel_count == -1) { if (show_warnings && (s->oformat == &ff_mxf_d10_muxer) && (st->codecpar->channels != 4) && (st->codecpar->channels != 8)) @@ -1263,13 +1502,14 @@ static void mxf_write_generic_sound_common(AVFormatContext *s, AVStream *st, con mxf_write_local_tag(pb, 4, 0x3D01); avio_wb32(pb, av_get_bits_per_sample(st->codecpar->codec_id)); + + return pos; } -static void mxf_write_wav_common(AVFormatContext *s, AVStream *st, const UID key, unsigned size) +static int64_t mxf_write_wav_common(AVFormatContext *s, AVStream *st, const UID key) { AVIOContext *pb = s->pb; - - mxf_write_generic_sound_common(s, st, key, size+6+8); + int64_t pos = mxf_write_generic_sound_common(s, st, key); mxf_write_local_tag(pb, 2, 0x3D0A); avio_wb16(pb, st->codecpar->block_align); @@ -1277,21 +1517,26 @@ static void mxf_write_wav_common(AVFormatContext *s, AVStream *st, const UID key // avg bytes per sec mxf_write_local_tag(pb, 4, 0x3D09); avio_wb32(pb, st->codecpar->block_align*st->codecpar->sample_rate); + + return pos; } static void mxf_write_wav_desc(AVFormatContext *s, AVStream *st) { - mxf_write_wav_common(s, st, mxf_wav_descriptor_key, 0); + int64_t pos = mxf_write_wav_common(s, st, mxf_wav_descriptor_key); + mxf_update_klv_size(s->pb, pos); } static void mxf_write_aes3_desc(AVFormatContext *s, AVStream *st) { - mxf_write_wav_common(s, st, mxf_aes3_descriptor_key, 0); + int64_t pos = mxf_write_wav_common(s, st, mxf_aes3_descriptor_key); + mxf_update_klv_size(s->pb, pos); } static void mxf_write_generic_sound_desc(AVFormatContext *s, AVStream *st) { - mxf_write_generic_sound_common(s, st, mxf_generic_sound_descriptor_key, 0); + int64_t pos = mxf_write_generic_sound_common(s, st, mxf_generic_sound_descriptor_key); + mxf_update_klv_size(s->pb, pos); } static const uint8_t mxf_indirect_value_utf16le[] = { 0x4c,0x00,0x02,0x10,0x01,0x00,0x00,0x00,0x00,0x06,0x0e,0x2b,0x34,0x01,0x04,0x01,0x01 }; @@ -1529,6 +1774,9 @@ static void mxf_write_index_table_segment(AVFormatContext *s) AVIOContext *pb = s->pb; int i, j, temporal_reordering = 0; int key_index = mxf->last_key_index; + int prev_non_b_picture = 0; + int audio_frame_size = 0; + int64_t pos; av_log(s, AV_LOG_DEBUG, "edit units count %d\n", mxf->edit_units_count); @@ -1537,12 +1785,8 @@ static void mxf_write_index_table_segment(AVFormatContext *s) avio_write(pb, index_table_segment_key, 16); - if (mxf->edit_unit_byte_count) { - klv_encode_ber_length(pb, 80); - } else { - klv_encode_ber_length(pb, 85 + 12+(s->nb_streams+1LL)*6 + - 12+mxf->edit_units_count*(11+mxf->slice_count*4LL)); - } + klv_encode_ber4_length(pb, 0); + pos = avio_tell(pb); // instance id mxf_write_local_tag(pb, 16, 0x3C0A); @@ -1576,44 +1820,52 @@ static void mxf_write_index_table_segment(AVFormatContext *s) mxf_write_local_tag(pb, 4, 0x3F07); avio_wb32(pb, 1); - if (!mxf->edit_unit_byte_count) { - // real slice count - 1 - mxf_write_local_tag(pb, 1, 0x3F08); - avio_w8(pb, mxf->slice_count); + // real slice count - 1 + mxf_write_local_tag(pb, 1, 0x3F08); + avio_w8(pb, !mxf->edit_unit_byte_count); // only one slice for CBR - // delta entry array - mxf_write_local_tag(pb, 8 + (s->nb_streams+1)*6, 0x3F09); - avio_wb32(pb, s->nb_streams+1); // num of entries - avio_wb32(pb, 6); // size of one entry - // write system item delta entry - avio_w8(pb, 0); - avio_w8(pb, 0); // slice entry - avio_wb32(pb, 0); // element delta - for (i = 0; i < s->nb_streams; i++) { - AVStream *st = s->streams[i]; - MXFStreamContext *sc = st->priv_data; - avio_w8(pb, sc->temporal_reordering); - if (sc->temporal_reordering) - temporal_reordering = 1; - if (i == 0) { // video track - avio_w8(pb, 0); // slice number - avio_wb32(pb, KAG_SIZE); // system item size including klv fill - } else { // audio track - unsigned audio_frame_size = sc->aic.samples[0]*sc->aic.sample_size; + // delta entry array + mxf_write_local_tag(pb, 8 + (s->nb_streams+1)*6, 0x3F09); + avio_wb32(pb, s->nb_streams+1); // num of entries + avio_wb32(pb, 6); // size of one entry + // write system item delta entry + avio_w8(pb, 0); + avio_w8(pb, 0); // slice entry + avio_wb32(pb, 0); // element delta + // write each stream delta entry + for (i = 0; i < s->nb_streams; i++) { + AVStream *st = s->streams[i]; + MXFStreamContext *sc = st->priv_data; + avio_w8(pb, sc->temporal_reordering); + if (sc->temporal_reordering) + temporal_reordering = 1; + if (mxf->edit_unit_byte_count) { + avio_w8(pb, 0); // slice number + avio_wb32(pb, sc->slice_offset); + } else if (i == 0) { // video track + avio_w8(pb, 0); // slice number + avio_wb32(pb, KAG_SIZE); // system item size including klv fill + } else { // audio or data track + if (!audio_frame_size) { + audio_frame_size = sc->aic.samples[0]*sc->aic.sample_size; audio_frame_size += klv_fill_size(audio_frame_size); - avio_w8(pb, 1); - avio_wb32(pb, (i-1)*audio_frame_size); // element delta } + avio_w8(pb, 1); + avio_wb32(pb, (i-1)*audio_frame_size); // element delta } + } - mxf_write_local_tag(pb, 8 + mxf->edit_units_count*(11+mxf->slice_count*4), 0x3F0A); + if (!mxf->edit_unit_byte_count) { + MXFStreamContext *sc = s->streams[0]->priv_data; + mxf_write_local_tag(pb, 8 + mxf->edit_units_count*15, 0x3F0A); avio_wb32(pb, mxf->edit_units_count); // num of entries - avio_wb32(pb, 11+mxf->slice_count*4); // size of one entry + avio_wb32(pb, 15); // size of one entry for (i = 0; i < mxf->edit_units_count; i++) { int temporal_offset = 0; if (!(mxf->index_entries[i].flags & 0x33)) { // I-frame + sc->max_gop = FFMAX(sc->max_gop, i - mxf->last_key_index); mxf->last_key_index = key_index; key_index = i; } @@ -1633,11 +1885,13 @@ static void mxf_write_index_table_segment(AVFormatContext *s) avio_w8(pb, temporal_offset); if ((mxf->index_entries[i].flags & 0x30) == 0x30) { // back and forward prediction + sc->b_picture_count = FFMAX(sc->b_picture_count, i - prev_non_b_picture); avio_w8(pb, mxf->last_key_index - i); } else { avio_w8(pb, key_index - i); // key frame offset if ((mxf->index_entries[i].flags & 0x20) == 0x20) // only forward mxf->last_key_index = key_index; + prev_non_b_picture = i; } if (!(mxf->index_entries[i].flags & 0x33) && // I-frame @@ -1648,12 +1902,16 @@ static void mxf_write_index_table_segment(AVFormatContext *s) avio_wb64(pb, mxf->index_entries[i].offset); if (s->nb_streams > 1) avio_wb32(pb, mxf->index_entries[i].slice_offset); + else + avio_wb32(pb, 0); } mxf->last_key_index = key_index - mxf->edit_units_count; mxf->last_indexed_edit_unit += mxf->edit_units_count; mxf->edit_units_count = 0; } + + mxf_update_klv_size(pb, pos); } static void mxf_write_klv_fill(AVFormatContext *s) @@ -1681,13 +1939,12 @@ static int mxf_write_partition(AVFormatContext *s, int bodysid, if (!mxf->edit_unit_byte_count && mxf->edit_units_count) index_byte_count = 85 + 12+(s->nb_streams+1)*6 + - 12+mxf->edit_units_count*(11+mxf->slice_count*4); + 12+mxf->edit_units_count*15; else if (mxf->edit_unit_byte_count && indexsid) index_byte_count = 80; if (index_byte_count) { - // add encoded ber length - index_byte_count += 16 + klv_ber_length(index_byte_count); + index_byte_count += 16 + 4; // add encoded ber4 length index_byte_count += klv_fill_size(index_byte_count); } @@ -1706,11 +1963,11 @@ static int mxf_write_partition(AVFormatContext *s, int bodysid, else avio_write(pb, body_partition_key, 16); - klv_encode_ber_length(pb, 88 + 16LL * DESCRIPTOR_COUNT(mxf->essence_container_count)); + klv_encode_ber4_length(pb, 88 + 16LL * DESCRIPTOR_COUNT(mxf->essence_container_count)); // write partition value avio_wb16(pb, 1); // majorVersion - avio_wb16(pb, 2); // minorVersion + avio_wb16(pb, 3); // minorVersion avio_wb32(pb, KAG_SIZE); // KAGSize avio_wb64(pb, partition_offset); // ThisPartition @@ -1757,6 +2014,7 @@ static int mxf_write_partition(AVFormatContext *s, int bodysid, mxf_write_klv_fill(s); start = avio_tell(s->pb); mxf_write_primer_pack(s); + mxf_write_klv_fill(s); mxf_write_header_metadata_sets(s); pos = avio_tell(s->pb); header_byte_count = pos - start + klv_fill_size(pos); @@ -1773,87 +2031,119 @@ static int mxf_write_partition(AVFormatContext *s, int bodysid, return 0; } -static int mxf_parse_dnxhd_frame(AVFormatContext *s, AVStream *st, -AVPacket *pkt) +static const struct { + int profile; + UID codec_ul; +} mxf_prores_codec_uls[] = { + { FF_PROFILE_PRORES_PROXY, { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0d,0x04,0x01,0x02,0x02,0x03,0x06,0x01,0x00 } }, + { FF_PROFILE_PRORES_LT, { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0d,0x04,0x01,0x02,0x02,0x03,0x06,0x02,0x00 } }, + { FF_PROFILE_PRORES_STANDARD, { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0d,0x04,0x01,0x02,0x02,0x03,0x06,0x03,0x00 } }, + { FF_PROFILE_PRORES_HQ, { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0d,0x04,0x01,0x02,0x02,0x03,0x06,0x04,0x00 } }, + { FF_PROFILE_PRORES_4444, { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0d,0x04,0x01,0x02,0x02,0x03,0x06,0x05,0x00 } }, + { FF_PROFILE_PRORES_XQ, { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0d,0x04,0x01,0x02,0x02,0x03,0x06,0x06,0x00 } }, +}; + +static int mxf_parse_prores_frame(AVFormatContext *s, AVStream *st, AVPacket *pkt) { MXFContext *mxf = s->priv_data; MXFStreamContext *sc = st->priv_data; - int i, cid; - uint8_t* header_cid; - int frame_size = 0; + int i, profile; + + if (mxf->header_written) + return 1; + + sc->codec_ul = NULL; + profile = st->codecpar->profile; + for (i = 0; i < FF_ARRAY_ELEMS(mxf_prores_codec_uls); i++) { + if (profile == mxf_prores_codec_uls[i].profile) { + sc->codec_ul = &mxf_prores_codec_uls[i].codec_ul; + break; + } + } + if (!sc->codec_ul) + return 0; + + sc->frame_size = pkt->size; + + return 1; +} + +static const struct { + int cid; + UID codec_ul; +} mxf_dnxhd_codec_uls[] = { + { 1235, { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x71,0x01,0x00,0x00 } }, // 1080p 10bit HIGH + { 1237, { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x71,0x03,0x00,0x00 } }, // 1080p 8bit MED + { 1238, { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x71,0x04,0x00,0x00 } }, // 1080p 8bit HIGH + { 1241, { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x71,0x07,0x00,0x00 } }, // 1080i 10bit HIGH + { 1242, { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x71,0x08,0x00,0x00 } }, // 1080i 8bit MED + { 1243, { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x71,0x09,0x00,0x00 } }, // 1080i 8bit HIGH + { 1244, { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x71,0x0a,0x00,0x00 } }, // 1080i 8bit TR + { 1250, { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x71,0x10,0x00,0x00 } }, // 720p 10bit + { 1251, { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x71,0x11,0x00,0x00 } }, // 720p 8bit HIGH + { 1252, { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x71,0x12,0x00,0x00 } }, // 720p 8bit MED + { 1253, { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x71,0x13,0x00,0x00 } }, // 720p 8bit LOW + { 1256, { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x71,0x16,0x00,0x00 } }, // 1080p 10bit 444 + { 1258, { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x71,0x18,0x00,0x00 } }, // 720p 8bit TR + { 1259, { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x71,0x19,0x00,0x00 } }, // 1080p 8bit TR + { 1260, { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x71,0x1a,0x00,0x00 } }, // 1080i 8bit TR MBAFF + { 1270, { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x71,0x24,0x00,0x00 } }, // DNXHR 444 + { 1271, { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x71,0x25,0x00,0x00 } }, // DNXHR HQX + { 1272, { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x71,0x26,0x00,0x00 } }, // DNXHR HQ + { 1273, { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x71,0x27,0x00,0x00 } }, // DNXHR SQ + { 1274, { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x71,0x28,0x00,0x00 } }, // DNXHR LB +}; + +static int mxf_parse_dnxhd_frame(AVFormatContext *s, AVStream *st, AVPacket *pkt) +{ + MXFContext *mxf = s->priv_data; + MXFStreamContext *sc = st->priv_data; + int i, cid, frame_size = 0; if (mxf->header_written) return 1; if (pkt->size < 43) - return -1; + return 0; - header_cid = pkt->data + 0x28; - cid = header_cid[0] << 24 | header_cid[1] << 16 | header_cid[2] << 8 | header_cid[3]; - - if ((frame_size = avpriv_dnxhd_get_frame_size(cid)) < 0) - return -1; - if ((sc->interlaced = avpriv_dnxhd_get_interlaced(cid)) < 0) - return AVERROR_INVALIDDATA; - - switch (cid) { - case 1235: - sc->index = INDEX_DNXHD_1080p_10bit_HIGH; - sc->component_depth = 10; - break; - case 1237: - sc->index = INDEX_DNXHD_1080p_8bit_MEDIUM; - break; - case 1238: - sc->index = INDEX_DNXHD_1080p_8bit_HIGH; - break; - case 1241: - sc->index = INDEX_DNXHD_1080i_10bit_HIGH; - sc->component_depth = 10; - break; - case 1242: - sc->index = INDEX_DNXHD_1080i_8bit_MEDIUM; - break; - case 1243: - sc->index = INDEX_DNXHD_1080i_8bit_HIGH; - break; - case 1250: - sc->index = INDEX_DNXHD_720p_10bit; - sc->component_depth = 10; - break; - case 1251: - sc->index = INDEX_DNXHD_720p_8bit_HIGH; - break; - case 1252: - sc->index = INDEX_DNXHD_720p_8bit_MEDIUM; - break; - case 1253: - sc->index = INDEX_DNXHD_720p_8bit_LOW; - break; - default: - return -1; - } - - sc->codec_ul = &mxf_essence_container_uls[sc->index].codec_ul; - sc->aspect_ratio = (AVRational){ 16, 9 }; - - if (s->oformat == &ff_mxf_opatom_muxer) { - mxf->edit_unit_byte_count = frame_size; - return 1; - } - - mxf->edit_unit_byte_count = KAG_SIZE; - for (i = 0; i < s->nb_streams; i++) { - AVStream *st = s->streams[i]; - MXFStreamContext *sc = st->priv_data; - if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) { - mxf->edit_unit_byte_count += 16 + 4 + sc->aic.samples[0]*sc->aic.sample_size; - mxf->edit_unit_byte_count += klv_fill_size(mxf->edit_unit_byte_count); - } else if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { - mxf->edit_unit_byte_count += 16 + 4 + frame_size; - mxf->edit_unit_byte_count += klv_fill_size(mxf->edit_unit_byte_count); + sc->codec_ul = NULL; + cid = AV_RB32(pkt->data + 0x28); + for (i = 0; i < FF_ARRAY_ELEMS(mxf_dnxhd_codec_uls); i++) { + if (cid == mxf_dnxhd_codec_uls[i].cid) { + sc->codec_ul = &mxf_dnxhd_codec_uls[i].codec_ul; + break; } } + if (!sc->codec_ul) + return 0; + + sc->component_depth = 0; + switch (pkt->data[0x21] >> 5) { + case 1: sc->component_depth = 8; break; + case 2: sc->component_depth = 10; break; + case 3: sc->component_depth = 12; break; + } + if (!sc->component_depth) + return 0; + + if ((frame_size = avpriv_dnxhd_get_frame_size(cid)) == DNXHD_VARIABLE) { + frame_size = avpriv_dnxhd_get_hr_frame_size(cid, st->codecpar->width, st->codecpar->height); + } + if (frame_size < 0) + return 0; + + if ((sc->interlaced = avpriv_dnxhd_get_interlaced(cid)) < 0) + return 0; + + if (cid >= 1270) { // RI raster + av_reduce(&sc->aspect_ratio.num, &sc->aspect_ratio.den, + st->codecpar->width, st->codecpar->height, + INT_MAX); + } else { + sc->aspect_ratio = (AVRational){ 16, 9 }; + } + + sc->frame_size = pkt->size; return 1; } @@ -1863,7 +2153,7 @@ static int mxf_parse_dv_frame(AVFormatContext *s, AVStream *st, AVPacket *pkt) MXFContext *mxf = s->priv_data; MXFStreamContext *sc = st->priv_data; uint8_t *vs_pack, *vsc_pack; - int i, ul_index, frame_size, stype, pal; + int ul_index, stype, pal; const AVDVProfile *profile; if (mxf->header_written) @@ -1894,7 +2184,6 @@ static int mxf_parse_dv_frame(AVFormatContext *s, AVStream *st, AVPacket *pkt) switch (stype) { case 0x18: // DV100 720p ul_index = INDEX_DV100_720_50 + pal; - frame_size = pal ? 288000 : 240000; if (sc->interlaced) { av_log(s, AV_LOG_ERROR, "source marked as interlaced but codec profile is progressive\n"); sc->interlaced = 0; @@ -1902,42 +2191,21 @@ static int mxf_parse_dv_frame(AVFormatContext *s, AVStream *st, AVPacket *pkt) break; case 0x14: // DV100 1080i ul_index = INDEX_DV100_1080_50 + pal; - frame_size = pal ? 576000 : 480000; break; case 0x04: // DV50 ul_index = INDEX_DV50_525_60 + pal; - frame_size = pal ? 288000 : 240000; break; default: // DV25 if (profile && profile->pix_fmt == AV_PIX_FMT_YUV420P && pal) { ul_index = INDEX_DV25_525_60_IEC + pal; - frame_size = pal ? 144000 : 120000; break; } ul_index = INDEX_DV25_525_60 + pal; - frame_size = pal ? 144000 : 120000; } sc->index = ul_index; sc->codec_ul = &mxf_essence_container_uls[sc->index].codec_ul; - - if(s->oformat == &ff_mxf_opatom_muxer) { - mxf->edit_unit_byte_count = frame_size; - return 1; - } - - mxf->edit_unit_byte_count = KAG_SIZE; - for (i = 0; i < s->nb_streams; i++) { - AVStream *st = s->streams[i]; - MXFStreamContext *sc = st->priv_data; - if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) { - mxf->edit_unit_byte_count += 16 + 4 + sc->aic.samples[0]*sc->aic.sample_size; - mxf->edit_unit_byte_count += klv_fill_size(mxf->edit_unit_byte_count); - } else if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { - mxf->edit_unit_byte_count += 16 + 4 + frame_size; - mxf->edit_unit_byte_count += klv_fill_size(mxf->edit_unit_byte_count); - } - } + sc->frame_size = pkt->size; return 1; } @@ -1947,22 +2215,31 @@ static const struct { int frame_size; int profile; uint8_t interlaced; + int intra_only; // 1 or 0 when there are separate UIDs for Long GOP and Intra, -1 when Intra/LGOP detection can be ignored } mxf_h264_codec_uls[] = { - {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x31,0x11,0x01 }, 0, 66, 0 }, // AVC Baseline, Unconstrained Coding - {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x32,0x20,0x01 }, 0, 110, 0 }, // AVC High 10 Intra - {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x32,0x21,0x01 }, 232960, 0, 1 }, // AVC Intra 50 1080i60 - {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x32,0x21,0x02 }, 281088, 0, 1 }, // AVC Intra 50 1080i50 - {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x32,0x21,0x03 }, 232960, 0, 0 }, // AVC Intra 50 1080p30 - {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x32,0x21,0x04 }, 281088, 0, 0 }, // AVC Intra 50 1080p25 - {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x32,0x21,0x08 }, 116736, 0, 0 }, // AVC Intra 50 720p60 - {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x32,0x21,0x09 }, 140800, 0, 0 }, // AVC Intra 50 720p50 - {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x32,0x30,0x01 }, 0, 122, 0 }, // AVC High 422 Intra - {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x32,0x31,0x01 }, 472576, 0, 1 }, // AVC Intra 100 1080i60 - {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x32,0x31,0x02 }, 568832, 0, 1 }, // AVC Intra 100 1080i50 - {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x32,0x31,0x03 }, 472576, 0, 0 }, // AVC Intra 100 1080p30 - {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x32,0x31,0x04 }, 568832, 0, 0 }, // AVC Intra 100 1080p25 - {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x32,0x31,0x08 }, 236544, 0, 0 }, // AVC Intra 100 720p60 - {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x32,0x31,0x09 }, 284672, 0, 0 }, // AVC Intra 100 720p50 + {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x31,0x11,0x01 }, 0, 66, 0, -1 }, // AVC Baseline + {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x31,0x20,0x01 }, 0, 77, 0, -1 }, // AVC Main + {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x31,0x30,0x01 }, 0, 88, 0, -1 }, // AVC Extended + {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x31,0x40,0x01 }, 0, 100, 0, -1 }, // AVC High + {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x31,0x50,0x01 }, 0, 110, 0, 0 }, // AVC High 10 + {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x31,0x60,0x01 }, 0, 122, 0, 0 }, // AVC High 422 + {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x31,0x70,0x01 }, 0, 244, 0, 0 }, // AVC High 444 + {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x32,0x20,0x01 }, 0, 110, 0, 1 }, // AVC High 10 Intra + {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x32,0x21,0x01 }, 232960, 110, 1, 1 }, // AVC High 10 Intra RP2027 Class 50 1080/59.94i + {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x32,0x21,0x02 }, 281088, 110, 1, 1 }, // AVC High 10 Intra RP2027 Class 50 1080/50i + {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x32,0x21,0x03 }, 232960, 110, 0, 1 }, // AVC High 10 Intra RP2027 Class 50 1080/29.97p + {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x32,0x21,0x04 }, 281088, 110, 0, 1 }, // AVC High 10 Intra RP2027 Class 50 1080/25p + {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x32,0x21,0x08 }, 116736, 110, 0, 1 }, // AVC High 10 Intra RP2027 Class 50 720/59.94p + {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x32,0x21,0x09 }, 140800, 110, 0, 1 }, // AVC High 10 Intra RP2027 Class 50 720/50p + {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x32,0x30,0x01 }, 0, 122, 0, 1 }, // AVC High 422 Intra + {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x32,0x31,0x01 }, 472576, 122, 1, 1 }, // AVC High 422 Intra RP2027 Class 100 1080/59.94i + {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x32,0x31,0x02 }, 568832, 122, 1, 1 }, // AVC High 422 Intra RP2027 Class 100 1080/50i + {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x32,0x31,0x03 }, 472576, 122, 0, 1 }, // AVC High 422 Intra RP2027 Class 100 1080/29.97p + {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x32,0x31,0x04 }, 568832, 122, 0, 1 }, // AVC High 422 Intra RP2027 Class 100 1080/25p + {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x32,0x31,0x08 }, 236544, 122, 0, 1 }, // AVC High 422 Intra RP2027 Class 100 720/59.94p + {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0a,0x04,0x01,0x02,0x02,0x01,0x32,0x31,0x09 }, 284672, 122, 0, 1 }, // AVC High 422 Intra RP2027 Class 100 720/50p + {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0d,0x04,0x01,0x02,0x02,0x01,0x32,0x40,0x01 }, 0, 244, 0, 1 }, // AVC High 444 Intra + {{ 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x0d,0x04,0x01,0x02,0x02,0x01,0x32,0x50,0x01 }, 0, 44, 0, -1 }, // AVC CAVLC 444 }; static int mxf_parse_h264_frame(AVFormatContext *s, AVStream *st, @@ -1970,34 +2247,70 @@ static int mxf_parse_h264_frame(AVFormatContext *s, AVStream *st, { MXFContext *mxf = s->priv_data; MXFStreamContext *sc = st->priv_data; - static const int mxf_h264_num_codec_uls = sizeof(mxf_h264_codec_uls) / sizeof(mxf_h264_codec_uls[0]); + H264SequenceParameterSet *sps = NULL; + GetBitContext gb; const uint8_t *buf = pkt->data; const uint8_t *buf_end = pkt->data + pkt->size; + const uint8_t *nal_end; uint32_t state = -1; int extra_size = 512; // support AVC Intra files without SPS/PPS header - int i, frame_size; - uint8_t uid_found; - - if (pkt->size > extra_size) - buf_end -= pkt->size - extra_size; // no need to parse beyond SPS/PPS header + int i, frame_size, slice_type, intra_only = 0; for (;;) { buf = avpriv_find_start_code(buf, buf_end, &state); if (buf >= buf_end) break; - --buf; + switch (state & 0x1f) { case H264_NAL_SPS: - st->codecpar->profile = buf[1]; e->flags |= 0x40; + + if (mxf->header_written) + break; + + nal_end = ff_avc_find_startcode(buf, buf_end); + sps = ff_avc_decode_sps(buf, nal_end - buf); + if (!sps) { + av_log(s, AV_LOG_ERROR, "error parsing sps\n"); + return 0; + } + + sc->aspect_ratio.num = st->codecpar->width * sps->sar.num; + sc->aspect_ratio.den = st->codecpar->height * sps->sar.den; + av_reduce(&sc->aspect_ratio.num, &sc->aspect_ratio.den, + sc->aspect_ratio.num, sc->aspect_ratio.den, 1024*1024); + intra_only = (sps->constraint_set_flags >> 3) & 1; + sc->interlaced = !sps->frame_mbs_only_flag; + sc->component_depth = sps->bit_depth_luma; + + buf = nal_end; break; case H264_NAL_PPS: if (e->flags & 0x40) { // sequence header present e->flags |= 0x80; // random access extra_size = 0; - buf = buf_end; } break; + case H264_NAL_IDR_SLICE: + e->flags |= 0x04; // IDR Picture + buf = buf_end; + break; + case H264_NAL_SLICE: + init_get_bits8(&gb, buf, buf_end - buf); + get_ue_golomb_long(&gb); // skip first_mb_in_slice + slice_type = get_ue_golomb_31(&gb); + switch (slice_type % 5) { + case 0: + e->flags |= 0x20; // P Picture + e->flags |= 0x06; // P Picture + break; + case 1: + e->flags |= 0x30; // B Picture + e->flags |= 0x03; // non-referenced B Picture + break; + } + buf = buf_end; + break; default: break; } @@ -2006,26 +2319,38 @@ static int mxf_parse_h264_frame(AVFormatContext *s, AVStream *st, if (mxf->header_written) return 1; - sc->aspect_ratio = (AVRational){ 16, 9 }; // 16:9 is mandatory for broadcast HD - sc->component_depth = 10; // AVC Intra is always 10 Bit - sc->interlaced = st->codecpar->field_order != AV_FIELD_PROGRESSIVE ? 1 : 0; - if (sc->interlaced) - sc->field_dominance = 1; // top field first is mandatory for AVC Intra - - uid_found = 0; + if (!sps) + sc->interlaced = st->codecpar->field_order != AV_FIELD_PROGRESSIVE ? 1 : 0; + sc->codec_ul = NULL; frame_size = pkt->size + extra_size; - for (i = 0; i < mxf_h264_num_codec_uls; i++) { + + for (i = 0; i < FF_ARRAY_ELEMS(mxf_h264_codec_uls); i++) { if (frame_size == mxf_h264_codec_uls[i].frame_size && sc->interlaced == mxf_h264_codec_uls[i].interlaced) { sc->codec_ul = &mxf_h264_codec_uls[i].uid; - return 1; - } else if (st->codecpar->profile == mxf_h264_codec_uls[i].profile) { + sc->component_depth = 10; // AVC Intra is always 10 Bit + sc->aspect_ratio = (AVRational){ 16, 9 }; // 16:9 is mandatory for broadcast HD + st->codecpar->profile = mxf_h264_codec_uls[i].profile; + sc->avc_intra = 1; + mxf->cbr_index = 1; + sc->frame_size = pkt->size; + if (sc->interlaced) + sc->field_dominance = 1; // top field first is mandatory for AVC Intra + break; + } else if (sps && mxf_h264_codec_uls[i].frame_size == 0 && + mxf_h264_codec_uls[i].profile == sps->profile_idc && + (mxf_h264_codec_uls[i].intra_only < 0 || + mxf_h264_codec_uls[i].intra_only == intra_only)) { sc->codec_ul = &mxf_h264_codec_uls[i].uid; - uid_found = 1; + st->codecpar->profile = sps->profile_idc; + st->codecpar->level = sps->level_idc; + // continue to check for avc intra } } - if (!uid_found) { - av_log(s, AV_LOG_ERROR, "AVC Intra 50/100 supported only\n"); + av_free(sps); + + if (!sc->codec_ul) { + av_log(s, AV_LOG_ERROR, "h264 profile not supported\n"); return 0; } @@ -2078,6 +2403,7 @@ static int mxf_parse_mpeg2_frame(AVFormatContext *s, AVStream *st, if ((pkt->data[i+1] & 0xf0) == 0x10) { // seq ext st->codecpar->profile = pkt->data[i+1] & 0x07; st->codecpar->level = pkt->data[i+2] >> 4; + sc->low_delay = pkt->data[i+6] >> 7; } else if (i + 5 < pkt->size && (pkt->data[i+1] & 0xf0) == 0x80) { // pict coding ext sc->interlaced = !(pkt->data[i+5] & 0x80); // progressive frame if (sc->interlaced) @@ -2086,9 +2412,14 @@ static int mxf_parse_mpeg2_frame(AVFormatContext *s, AVStream *st, } } else if (c == 0x1b8) { // gop if (pkt->data[i+4]>>6 & 0x01) { // closed + if (sc->seq_closed_gop == -1) + sc->seq_closed_gop = 1; sc->closed_gop = 1; if (e->flags & 0x40) // sequence header present e->flags |= 0x80; // random access + } else { + sc->seq_closed_gop = 0; + sc->closed_gop = 0; } } else if (c == 0x1b3) { // seq e->flags |= 0x40; @@ -2123,8 +2454,9 @@ static int mxf_parse_mpeg2_frame(AVFormatContext *s, AVStream *st, return !!sc->codec_ul; } -static uint64_t mxf_parse_timestamp(time_t timestamp) +static uint64_t mxf_parse_timestamp(int64_t timestamp64) { + time_t timestamp = timestamp64 / 1000000; struct tm tmbuf; struct tm *time = gmtime_r(×tamp, &tmbuf); if (!time) @@ -2134,7 +2466,8 @@ static uint64_t mxf_parse_timestamp(time_t timestamp) (uint64_t) time->tm_mday << 32 | time->tm_hour << 24 | time->tm_min << 16 | - time->tm_sec << 8; + time->tm_sec << 8 | + (timestamp64 % 1000000) / 4000; } static void mxf_gen_umid(AVFormatContext *s) @@ -2200,11 +2533,18 @@ static int mxf_write_header(AVFormatContext *s) // Default component depth to 8 sc->component_depth = 8; sc->h_chroma_sub_sample = 2; + sc->v_chroma_sub_sample = 2; sc->color_siting = 0xFF; + if (st->codecpar->sample_aspect_ratio.num && st->codecpar->sample_aspect_ratio.den) { + sc->aspect_ratio = av_mul_q(st->codecpar->sample_aspect_ratio, + av_make_q(st->codecpar->width, st->codecpar->height)); + } + if (pix_desc) { sc->component_depth = pix_desc->comp[0].depth; sc->h_chroma_sub_sample = 1 << pix_desc->log2_chroma_w; + sc->v_chroma_sub_sample = 1 << pix_desc->log2_chroma_h; } switch (ff_choose_chroma_location(s, st)) { case AVCHROMA_LOC_TOPLEFT: sc->color_siting = 0; break; @@ -2220,13 +2560,24 @@ static int mxf_write_header(AVFormatContext *s) tbc.den, tbc.num); return AVERROR(EINVAL); } + mxf->content_package_rate = ff_mxf_get_content_package_rate(tbc); mxf->time_base = spf->time_base; rate = av_inv_q(mxf->time_base); avpriv_set_pts_info(st, 64, mxf->time_base.num, mxf->time_base.den); if((ret = mxf_init_timecode(s, st, rate)) < 0) return ret; + if (st->codecpar->codec_id == AV_CODEC_ID_MPEG2VIDEO) { + sc->seq_closed_gop = -1; // unknown yet + } + sc->video_bit_rate = st->codecpar->bit_rate; + + if (s->oformat == &ff_mxf_d10_muxer || + st->codecpar->codec_id == AV_CODEC_ID_DNXHD || + st->codecpar->codec_id == AV_CODEC_ID_DVVIDEO) + mxf->cbr_index = 1; + if (s->oformat == &ff_mxf_d10_muxer) { if (st->codecpar->codec_id != AV_CODEC_ID_MPEG2VIDEO) { av_log(s, AV_LOG_ERROR, "error MXF D-10 only support MPEG-2 Video\n"); @@ -2247,14 +2598,10 @@ static int mxf_write_header(AVFormatContext *s) return -1; } - mxf->edit_unit_byte_count = KAG_SIZE; // system element - mxf->edit_unit_byte_count += 16 + 4 + (uint64_t)sc->video_bit_rate * - mxf->time_base.num / (8*mxf->time_base.den); - mxf->edit_unit_byte_count += klv_fill_size(mxf->edit_unit_byte_count); - mxf->edit_unit_byte_count += 16 + 4 + 4 + spf->samples_per_frame[0]*8*4; - mxf->edit_unit_byte_count += klv_fill_size(mxf->edit_unit_byte_count); - sc->signal_standard = 1; + sc->color_siting = 0; + sc->frame_size = (int64_t)sc->video_bit_rate * + mxf->time_base.num / (8*mxf->time_base.den); } if (mxf->signal_standard >= 0) sc->signal_standard = mxf->signal_standard; @@ -2274,6 +2621,7 @@ static int mxf_write_header(AVFormatContext *s) av_log(s, AV_LOG_ERROR, "MXF D-10 only support 16 or 24 bits le audio\n"); } sc->index = ((MXFStreamContext*)s->streams[0]->priv_data)->index + 1; + sc->frame_size = 4 + 8 * spf[0].samples_per_frame[0] * 4; } else if (s->oformat == &ff_mxf_opatom_muxer) { AVRational tbc = av_inv_q(mxf->audio_edit_rate); @@ -2302,6 +2650,20 @@ static int mxf_write_header(AVFormatContext *s) sc->index = INDEX_WAV; } else { mxf->slice_count = 1; + sc->frame_size = (st->codecpar->channels * spf[0].samples_per_frame[0] * + av_get_bits_per_sample(st->codecpar->codec_id)) / 8; + } + } else if (st->codecpar->codec_type == AVMEDIA_TYPE_DATA) { + AVDictionaryEntry *e = av_dict_get(st->metadata, "data_type", NULL, 0); + if (e && !strcmp(e->value, "vbi_vanc_smpte_436M")) { + sc->index = INDEX_S436M; + } else { + av_log(s, AV_LOG_ERROR, "track %d: unsupported data type\n", i); + return -1; + } + if (st->index != s->nb_streams - 1) { + av_log(s, AV_LOG_ERROR, "data track must be placed last\n"); + return -1; } } @@ -2342,7 +2704,7 @@ static int mxf_write_header(AVFormatContext *s) sc->order = AV_RB32(sc->track_essence_element_key+12); } - if (ff_parse_creation_time_metadata(s, ×tamp, 1) > 0) + if (ff_parse_creation_time_metadata(s, ×tamp, 0) > 0) mxf->timestamp = mxf_parse_timestamp(timestamp); mxf->duration = -1; @@ -2372,14 +2734,22 @@ static void mxf_write_system_item(AVFormatContext *s) AVIOContext *pb = s->pb; unsigned frame; uint32_t time_code; + int i, system_item_bitmap = 0x58; // UL, user date/time stamp, picture present frame = mxf->last_indexed_edit_unit + mxf->edit_units_count; // write system metadata pack avio_write(pb, system_metadata_pack_key, 16); klv_encode_ber4_length(pb, 57); - avio_w8(pb, 0x5c); // UL, user date/time stamp, picture and sound item present - avio_w8(pb, 0x04); // content package rate + + for (i = 0; i < s->nb_streams; i++) { + if (s->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) + system_item_bitmap |= 0x4; + else if (s->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_DATA) + system_item_bitmap |= 0x2; + } + avio_w8(pb, system_item_bitmap); + avio_w8(pb, mxf->content_package_rate); // content package rate avio_w8(pb, 0x00); // content package type avio_wb16(pb, 0x00); // channel handle avio_wb16(pb, (mxf->tc.start + frame) & 0xFFFF); // continuity count, supposed to overflow @@ -2407,35 +2777,6 @@ static void mxf_write_system_item(AVFormatContext *s) mxf_write_umid(s, 1); } -static void mxf_write_d10_video_packet(AVFormatContext *s, AVStream *st, AVPacket *pkt) -{ - MXFContext *mxf = s->priv_data; - AVIOContext *pb = s->pb; - MXFStreamContext *sc = st->priv_data; - int packet_size = (uint64_t)sc->video_bit_rate*mxf->time_base.num / - (8*mxf->time_base.den); // frame size - int pad; - - packet_size += 16 + 4; - packet_size += klv_fill_size(packet_size); - - klv_encode_ber4_length(pb, pkt->size); - avio_write(pb, pkt->data, pkt->size); - - // ensure CBR muxing by padding to correct video frame size - pad = packet_size - pkt->size - 16 - 4; - if (pad > 20) { - avio_write(s->pb, klv_fill_key, 16); - pad -= 16 + 4; - klv_encode_ber4_length(s->pb, pad); - ffio_fill(s->pb, 0, pad); - av_assert1(!(avio_tell(s->pb) & (KAG_SIZE-1))); - } else { - av_log(s, AV_LOG_WARNING, "cannot fill d-10 video packet\n"); - ffio_fill(s->pb, 0, pad); - } -} - static void mxf_write_d10_audio_packet(AVFormatContext *s, AVStream *st, AVPacket *pkt) { MXFContext *mxf = s->priv_data; @@ -2519,6 +2860,27 @@ static int mxf_write_opatom_packet(AVFormatContext *s, AVPacket *pkt, MXFIndexEn return 0; } +static void mxf_compute_edit_unit_byte_count(AVFormatContext *s) +{ + MXFContext *mxf = s->priv_data; + int i; + + if (s->oformat == &ff_mxf_opatom_muxer) { + MXFStreamContext *sc = s->streams[0]->priv_data; + mxf->edit_unit_byte_count = sc->frame_size; + return; + } + + mxf->edit_unit_byte_count = KAG_SIZE; // system element + for (i = 0; i < s->nb_streams; i++) { + AVStream *st = s->streams[i]; + MXFStreamContext *sc = st->priv_data; + sc->slice_offset = mxf->edit_unit_byte_count; + mxf->edit_unit_byte_count += 16 + 4 + sc->frame_size; + mxf->edit_unit_byte_count += klv_fill_size(mxf->edit_unit_byte_count); + } +} + static int mxf_write_packet(AVFormatContext *s, AVPacket *pkt) { MXFContext *mxf = s->priv_data; @@ -2528,7 +2890,7 @@ static int mxf_write_packet(AVFormatContext *s, AVPacket *pkt) MXFIndexEntry ie = {0}; int err; - if (!mxf->edit_unit_byte_count && !(mxf->edit_units_count % EDIT_UNITS_PER_BODY)) { + if (!mxf->cbr_index && !mxf->edit_unit_byte_count && !(mxf->edit_units_count % EDIT_UNITS_PER_BODY)) { if ((err = av_reallocp_array(&mxf->index_entries, mxf->edit_units_count + EDIT_UNITS_PER_BODY, sizeof(*mxf->index_entries))) < 0) { mxf->edit_units_count = 0; @@ -2547,6 +2909,11 @@ static int mxf_write_packet(AVFormatContext *s, AVPacket *pkt) av_log(s, AV_LOG_ERROR, "could not get dnxhd profile\n"); return -1; } + } else if (st->codecpar->codec_id == AV_CODEC_ID_PRORES) { + if (!mxf_parse_prores_frame(s, st, pkt)) { + av_log(s, AV_LOG_ERROR, "could not get prores profile\n"); + return -1; + } } else if (st->codecpar->codec_id == AV_CODEC_ID_DVVIDEO) { if (!mxf_parse_dv_frame(s, st, pkt)) { av_log(s, AV_LOG_ERROR, "could not get dv profile\n"); @@ -2559,6 +2926,16 @@ static int mxf_write_packet(AVFormatContext *s, AVPacket *pkt) } } + if (mxf->cbr_index) { + if (pkt->size != sc->frame_size && st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { + av_log(s, AV_LOG_ERROR, "track %d: frame size does not match index unit size, %d != %d\n", + st->index, pkt->size, sc->frame_size); + return -1; + } + if (!mxf->header_written) + mxf_compute_edit_unit_byte_count(s); + } + if (s->oformat == &ff_mxf_opatom_muxer) return mxf_write_opatom_packet(s, pkt, &ie); @@ -2607,11 +2984,9 @@ static int mxf_write_packet(AVFormatContext *s, AVPacket *pkt) mxf_write_klv_fill(s); avio_write(pb, sc->track_essence_element_key, 16); // write key - if (s->oformat == &ff_mxf_d10_muxer) { - if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) - mxf_write_d10_video_packet(s, st, pkt); - else - mxf_write_d10_audio_packet(s, st, pkt); + if (s->oformat == &ff_mxf_d10_muxer && + st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) { + mxf_write_d10_audio_packet(s, st, pkt); } else { klv_encode_ber4_length(pb, pkt->size); // write length avio_write(pb, pkt->data, pkt->size); @@ -2654,7 +3029,7 @@ static int mxf_write_footer(AVFormatContext *s) { MXFContext *mxf = s->priv_data; AVIOContext *pb = s->pb; - int err = 0; + int i, err = 0; if (!mxf->header_written || (s->oformat == &ff_mxf_opatom_muxer && !mxf->body_partition_offset)) { @@ -2698,6 +3073,11 @@ static int mxf_write_footer(AVFormatContext *s) if ((err = mxf_write_partition(s, 0, 0, header_closed_partition_key, 1)) < 0) goto end; } + // update footer partition offset + for (i = 0; i < mxf->body_partitions_count; i++) { + avio_seek(pb, mxf->body_partition_offset[i]+44, SEEK_SET); + avio_wb64(pb, mxf->footer_partition_offset); + } } end: @@ -2728,6 +3108,9 @@ static int mxf_interleave_get_packet(AVFormatContext *s, AVPacket *out, AVPacket while (pktl) { if (!stream_count || pktl->pkt.stream_index == 0) break; + // update last packet in packet buffer + if (s->streams[pktl->pkt.stream_index]->last_in_packet_buffer != pktl) + s->streams[pktl->pkt.stream_index]->last_in_packet_buffer = pktl; last = pktl; pktl = pktl->next; stream_count--; @@ -2735,9 +3118,6 @@ static int mxf_interleave_get_packet(AVFormatContext *s, AVPacket *out, AVPacket // purge packet queue while (pktl) { AVPacketList *next = pktl->next; - - if(s->streams[pktl->pkt.stream_index]->last_in_packet_buffer == pktl) - s->streams[pktl->pkt.stream_index]->last_in_packet_buffer= NULL; av_packet_unref(&pktl->pkt); av_freep(&pktl); pktl = next; @@ -2784,7 +3164,7 @@ static int mxf_interleave(AVFormatContext *s, AVPacket *out, AVPacket *pkt, int } #define MXF_COMMON_OPTIONS \ - { "signal_standard", "Force/set Sigal Standard",\ + { "signal_standard", "Force/set Signal Standard",\ offsetof(MXFContext, signal_standard), AV_OPT_TYPE_INT, {.i64 = -1}, -1, 7, AV_OPT_FLAG_ENCODING_PARAM, "signal_standard"},\ { "bt601", "ITU-R BT.601 and BT.656, also SMPTE 125M (525 and 625 line interlaced)",\ 0, AV_OPT_TYPE_CONST, {.i64 = 1}, -1, 7, AV_OPT_FLAG_ENCODING_PARAM, "signal_standard"},\ @@ -2837,6 +3217,8 @@ static const AVOption opatom_options[] = { { "mxf_audio_edit_rate", "Audio edit rate for timecode", offsetof(MXFContext, audio_edit_rate), AV_OPT_TYPE_RATIONAL, {.dbl=25}, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM }, MXF_COMMON_OPTIONS + { "store_user_comments", "", + offsetof(MXFContext, store_user_comments), AV_OPT_TYPE_BOOL, {.i64 = 1}, 0, 1, AV_OPT_FLAG_ENCODING_PARAM}, { NULL }, }; diff --git a/libavformat/ncdec.c b/libavformat/ncdec.c index 8cadcc7cd..bc3d3e82b 100644 --- a/libavformat/ncdec.c +++ b/libavformat/ncdec.c @@ -26,7 +26,7 @@ #define NC_VIDEO_FLAG 0x1A5 -static int nc_probe(AVProbeData *probe_packet) +static int nc_probe(const AVProbeData *probe_packet) { int size; diff --git a/libavformat/network.c b/libavformat/network.c index d5c82e9ab..5664455d1 100644 --- a/libavformat/network.c +++ b/libavformat/network.c @@ -24,6 +24,7 @@ #include "url.h" #include "libavcodec/internal.h" #include "libavutil/avutil.h" +#include "libavutil/avassert.h" #include "libavutil/mem.h" #include "libavutil/time.h" @@ -165,14 +166,17 @@ static int ff_poll_interrupt(struct pollfd *p, nfds_t nfds, int timeout, if (ff_check_interrupt(cb)) return AVERROR_EXIT; ret = poll(p, nfds, POLLING_TIME); - if (ret != 0) + if (ret != 0) { + if (ret < 0) + ret = ff_neterrno(); + if (ret == AVERROR(EINTR)) + continue; break; + } } while (timeout <= 0 || runs-- > 0); if (!ret) return AVERROR(ETIMEDOUT); - if (ret < 0) - return ff_neterrno(); return ret; } @@ -194,8 +198,11 @@ int ff_socket(int af, int type, int proto) #endif } #ifdef SO_NOSIGPIPE - if (fd != -1) - setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, &(int){1}, sizeof(int)); + if (fd != -1) { + if (setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, &(int){1}, sizeof(int))) { + av_log(NULL, AV_LOG_WARNING, "setsockopt(SO_NOSIGPIPE) failed\n"); + } + } #endif return fd; } @@ -293,6 +300,230 @@ int ff_listen_connect(int fd, const struct sockaddr *addr, return ret; } +static void interleave_addrinfo(struct addrinfo *base) +{ + struct addrinfo **next = &base->ai_next; + while (*next) { + struct addrinfo *cur = *next; + // Iterate forward until we find an entry of a different family. + if (cur->ai_family == base->ai_family) { + next = &cur->ai_next; + continue; + } + if (cur == base->ai_next) { + // If the first one following base is of a different family, just + // move base forward one step and continue. + base = cur; + next = &base->ai_next; + continue; + } + // Unchain cur from the rest of the list from its current spot. + *next = cur->ai_next; + // Hook in cur directly after base. + cur->ai_next = base->ai_next; + base->ai_next = cur; + // Restart with a new base. We know that before moving the cur element, + // everything between the previous base and cur had the same family, + // different from cur->ai_family. Therefore, we can keep next pointing + // where it was, and continue from there with base at the one after + // cur. + base = cur->ai_next; + } +} + +static void print_address_list(void *ctx, const struct addrinfo *addr, + const char *title) +{ + char hostbuf[100], portbuf[20]; + av_log(ctx, AV_LOG_DEBUG, "%s:\n", title); + while (addr) { + getnameinfo(addr->ai_addr, addr->ai_addrlen, + hostbuf, sizeof(hostbuf), portbuf, sizeof(portbuf), + NI_NUMERICHOST | NI_NUMERICSERV); + av_log(ctx, AV_LOG_DEBUG, "Address %s port %s\n", hostbuf, portbuf); + addr = addr->ai_next; + } +} + +struct ConnectionAttempt { + int fd; + int64_t deadline_us; + struct addrinfo *addr; +}; + +// Returns < 0 on error, 0 on successfully started connection attempt, +// > 0 for a connection that succeeded already. +static int start_connect_attempt(struct ConnectionAttempt *attempt, + struct addrinfo **ptr, int timeout_ms, + URLContext *h, + void (*customize_fd)(void *, int), void *customize_ctx) +{ + struct addrinfo *ai = *ptr; + int ret; + + *ptr = ai->ai_next; + + attempt->fd = ff_socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); + if (attempt->fd < 0) + return ff_neterrno(); + attempt->deadline_us = av_gettime_relative() + timeout_ms * 1000; + attempt->addr = ai; + + ff_socket_nonblock(attempt->fd, 1); + + if (customize_fd) + customize_fd(customize_ctx, attempt->fd); + + while ((ret = connect(attempt->fd, ai->ai_addr, ai->ai_addrlen))) { + ret = ff_neterrno(); + switch (ret) { + case AVERROR(EINTR): + if (ff_check_interrupt(&h->interrupt_callback)) { + closesocket(attempt->fd); + attempt->fd = -1; + return AVERROR_EXIT; + } + continue; + case AVERROR(EINPROGRESS): + case AVERROR(EAGAIN): + return 0; + default: + closesocket(attempt->fd); + attempt->fd = -1; + return ret; + } + } + return 1; +} + +// Try a new connection to another address after 200 ms, as suggested in +// RFC 8305 (or sooner if an earlier attempt fails). +#define NEXT_ATTEMPT_DELAY_MS 200 + +int ff_connect_parallel(struct addrinfo *addrs, int timeout_ms_per_address, + int parallel, URLContext *h, int *fd, + void (*customize_fd)(void *, int), void *customize_ctx) +{ + struct ConnectionAttempt attempts[3]; + struct pollfd pfd[3]; + int nb_attempts = 0, i, j; + int64_t next_attempt_us = av_gettime_relative(), next_deadline_us; + int last_err = AVERROR(EIO); + socklen_t optlen; + char errbuf[100], hostbuf[100], portbuf[20]; + + if (parallel > FF_ARRAY_ELEMS(attempts)) + parallel = FF_ARRAY_ELEMS(attempts); + + print_address_list(h, addrs, "Original list of addresses"); + // This mutates the list, but the head of the list is still the same + // element, so the caller, who owns the list, doesn't need to get + // an updated pointer. + interleave_addrinfo(addrs); + print_address_list(h, addrs, "Interleaved list of addresses"); + + while (nb_attempts > 0 || addrs) { + // Start a new connection attempt, if possible. + if (nb_attempts < parallel && addrs) { + getnameinfo(addrs->ai_addr, addrs->ai_addrlen, + hostbuf, sizeof(hostbuf), portbuf, sizeof(portbuf), + NI_NUMERICHOST | NI_NUMERICSERV); + av_log(h, AV_LOG_VERBOSE, "Starting connection attempt to %s port %s\n", + hostbuf, portbuf); + last_err = start_connect_attempt(&attempts[nb_attempts], &addrs, + timeout_ms_per_address, h, + customize_fd, customize_ctx); + if (last_err < 0) { + av_strerror(last_err, errbuf, sizeof(errbuf)); + av_log(h, AV_LOG_VERBOSE, "Connected attempt failed: %s\n", + errbuf); + continue; + } + if (last_err > 0) { + for (i = 0; i < nb_attempts; i++) + closesocket(attempts[i].fd); + *fd = attempts[nb_attempts].fd; + return 0; + } + pfd[nb_attempts].fd = attempts[nb_attempts].fd; + pfd[nb_attempts].events = POLLOUT; + next_attempt_us = av_gettime_relative() + NEXT_ATTEMPT_DELAY_MS * 1000; + nb_attempts++; + } + + av_assert0(nb_attempts > 0); + // The connection attempts are sorted from oldest to newest, so the + // first one will have the earliest deadline. + next_deadline_us = attempts[0].deadline_us; + // If we can start another attempt in parallel, wait until that time. + if (nb_attempts < parallel && addrs) + next_deadline_us = FFMIN(next_deadline_us, next_attempt_us); + last_err = ff_poll_interrupt(pfd, nb_attempts, + (next_deadline_us - av_gettime_relative())/1000, + &h->interrupt_callback); + if (last_err < 0 && last_err != AVERROR(ETIMEDOUT)) + break; + + // Check the status from the poll output. + for (i = 0; i < nb_attempts; i++) { + last_err = 0; + if (pfd[i].revents) { + // Some sort of action for this socket, check its status (either + // a successful connection or an error). + optlen = sizeof(last_err); + if (getsockopt(attempts[i].fd, SOL_SOCKET, SO_ERROR, &last_err, &optlen)) + last_err = ff_neterrno(); + else if (last_err != 0) + last_err = AVERROR(last_err); + if (last_err == 0) { + // Everything is ok, we seem to have a successful + // connection. Close other sockets and return this one. + for (j = 0; j < nb_attempts; j++) + if (j != i) + closesocket(attempts[j].fd); + *fd = attempts[i].fd; + getnameinfo(attempts[i].addr->ai_addr, attempts[i].addr->ai_addrlen, + hostbuf, sizeof(hostbuf), portbuf, sizeof(portbuf), + NI_NUMERICHOST | NI_NUMERICSERV); + av_log(h, AV_LOG_VERBOSE, "Successfully connected to %s port %s\n", + hostbuf, portbuf); + return 0; + } + } + if (attempts[i].deadline_us < av_gettime_relative() && !last_err) + last_err = AVERROR(ETIMEDOUT); + if (!last_err) + continue; + // Error (or timeout) for this socket; close the socket and remove + // it from the attempts/pfd arrays, to let a new attempt start + // directly. + getnameinfo(attempts[i].addr->ai_addr, attempts[i].addr->ai_addrlen, + hostbuf, sizeof(hostbuf), portbuf, sizeof(portbuf), + NI_NUMERICHOST | NI_NUMERICSERV); + av_strerror(last_err, errbuf, sizeof(errbuf)); + av_log(h, AV_LOG_VERBOSE, "Connection attempt to %s port %s " + "failed: %s\n", hostbuf, portbuf, errbuf); + closesocket(attempts[i].fd); + memmove(&attempts[i], &attempts[i + 1], + (nb_attempts - i - 1) * sizeof(*attempts)); + memmove(&pfd[i], &pfd[i + 1], + (nb_attempts - i - 1) * sizeof(*pfd)); + i--; + nb_attempts--; + } + } + for (i = 0; i < nb_attempts; i++) + closesocket(attempts[i].fd); + if (last_err >= 0) + last_err = AVERROR(ECONNREFUSED); + if (last_err != AVERROR_EXIT) { + av_strerror(last_err, errbuf, sizeof(errbuf)); + av_log(h, AV_LOG_ERROR, "Connection to %s failed: %s\n", + h->filename, errbuf); + } + return last_err; +} + static int match_host_pattern(const char *pattern, const char *hostname) { int len_p, len_h; @@ -346,3 +577,10 @@ int ff_http_match_no_proxy(const char *no_proxy, const char *hostname) av_free(buf); return ret; } + +void ff_log_net_error(void *ctx, int level, const char* prefix) +{ + char errbuf[100]; + av_strerror(ff_neterrno(), errbuf, sizeof(errbuf)); + av_log(ctx, level, "%s: %s\n", prefix, errbuf); +} diff --git a/libavformat/network.h b/libavformat/network.h index e3fda4d5e..7f467304a 100644 --- a/libavformat/network.h +++ b/libavformat/network.h @@ -87,9 +87,9 @@ int ff_network_wait_fd(int fd, int write); * This works similarly to ff_network_wait_fd, but waits up to 'timeout' microseconds * Uses ff_network_wait_fd in a loop * - * @fd Socket descriptor - * @write Set 1 to wait for socket able to be read, 0 to be written - * @timeout Timeout interval, in microseconds. Actual precision is 100000 mcs, due to ff_network_wait_fd usage + * @param fd Socket descriptor + * @param write Set 1 to wait for socket able to be read, 0 to be written + * @param timeout Timeout interval, in microseconds. Actual precision is 100000 mcs, due to ff_network_wait_fd usage * @param int_cb Interrupt callback, is checked before each ff_network_wait_fd call * @return 0 if data can be read/written, AVERROR(ETIMEDOUT) if timeout expired, or negative error code */ @@ -98,7 +98,7 @@ int ff_network_wait_fd_timeout(int fd, int write, int64_t timeout, AVIOInterrupt /** * Waits for up to 'timeout' microseconds. If the usert's int_cb is set and * triggered, return before that. - * @timeout Timeout in microseconds. Maybe have lower actual precision. + * @param timeout Timeout in microseconds. Maybe have lower actual precision. * @param int_cb Interrupt callback, is checked regularly. * @return AVERROR(ETIMEDOUT) if timeout expirted, AVERROR_EXIT if interrupted by int_cb */ @@ -304,4 +304,34 @@ int ff_http_match_no_proxy(const char *no_proxy, const char *hostname); int ff_socket(int domain, int type, int protocol); +void ff_log_net_error(void *ctx, int level, const char* prefix); + +/** + * Connect to any of the given addrinfo addresses, with multiple attempts + * running in parallel. + * + * @param addrs The list of addresses to try to connect to. + * This list will be mutated internally, but the list head + * will remain as such, so this doesn't affect the caller + * freeing the list afterwards. + * @param timeout_ms_per_address The number of milliseconds to wait for each + * connection attempt. Since multiple addresses are tried, + * some of them in parallel, the total run time will at most + * be timeout_ms_per_address*ceil(nb_addrs/parallel) + + * (parallel - 1) * NEXT_ATTEMPT_DELAY_MS. + * @param parallel The maximum number of connections to attempt in parallel. + * This is limited to an internal maximum capacity. + * @param h URLContext providing interrupt check + * callback and logging context. + * @param fd If successful, the connected socket is returned here. + * @param customize_fd Function that will be called for each socket created, + * to allow the caller to set socket options before calling + * connect() on it, may be NULL. + * @param customize_ctx Context parameter passed to customize_fd. + * @return 0 on success, AVERROR on failure. + */ +int ff_connect_parallel(struct addrinfo *addrs, int timeout_ms_per_address, + int parallel, URLContext *h, int *fd, + void (*customize_fd)(void *, int), void *customize_ctx); + #endif /* AVFORMAT_NETWORK_H */ diff --git a/libavformat/nistspheredec.c b/libavformat/nistspheredec.c index 55f22ebcf..3ef3843d5 100644 --- a/libavformat/nistspheredec.c +++ b/libavformat/nistspheredec.c @@ -25,7 +25,7 @@ #include "internal.h" #include "pcm.h" -static int nist_probe(AVProbeData *p) +static int nist_probe(const AVProbeData *p) { if (AV_RL64(p->buf) == AV_RL64("NIST_1A\x0a")) return AVPROBE_SCORE_MAX; diff --git a/libavformat/nspdec.c b/libavformat/nspdec.c index 34c747b65..68f8f99eb 100644 --- a/libavformat/nspdec.c +++ b/libavformat/nspdec.c @@ -25,7 +25,7 @@ #include "internal.h" #include "pcm.h" -static int nsp_probe(AVProbeData *p) +static int nsp_probe(const AVProbeData *p) { if (AV_RB32(p->buf) == AV_RB32("FORM") && AV_RB32(p->buf + 4) == AV_RB32("DS16")) diff --git a/libavformat/nsvdec.c b/libavformat/nsvdec.c index 92f7d178f..7aa1b605b 100644 --- a/libavformat/nsvdec.c +++ b/libavformat/nsvdec.c @@ -697,7 +697,7 @@ static int nsv_read_close(AVFormatContext *s) return 0; } -static int nsv_probe(AVProbeData *p) +static int nsv_probe(const AVProbeData *p) { int i, score = 0; diff --git a/libavformat/nut.c b/libavformat/nut.c index 592fe4dc2..937f45287 100644 --- a/libavformat/nut.c +++ b/libavformat/nut.c @@ -43,6 +43,7 @@ const AVCodecTag ff_nut_video_tags[] = { { AV_CODEC_ID_XFACE, MKTAG('X', 'F', 'A', 'C') }, { AV_CODEC_ID_VP9, MKTAG('V', 'P', '9', '0') }, { AV_CODEC_ID_HEVC, MKTAG('H', 'E', 'V', 'C') }, + { AV_CODEC_ID_CPIA, MKTAG('C', 'P', 'i', 'A') }, { AV_CODEC_ID_RAWVIDEO, MKTAG('R', 'G', 'B', 15 ) }, { AV_CODEC_ID_RAWVIDEO, MKTAG('B', 'G', 'R', 15 ) }, { AV_CODEC_ID_RAWVIDEO, MKTAG('R', 'G', 'B', 16 ) }, @@ -143,6 +144,11 @@ const AVCodecTag ff_nut_video_tags[] = { { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '4', 0, 10) }, { AV_CODEC_ID_RAWVIDEO, MKTAG(10, 0, '4', 'Y') }, + { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '4', 0, 12) }, + { AV_CODEC_ID_RAWVIDEO, MKTAG(12, 0, '4', 'Y') }, + { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '4', 10, 12) }, + { AV_CODEC_ID_RAWVIDEO, MKTAG(12, 10, '4', 'Y') }, + { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '1', 0, 12) }, { AV_CODEC_ID_RAWVIDEO, MKTAG(12, 0, '1', 'Y') }, { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '1', 0, 16) }, @@ -154,6 +160,9 @@ const AVCodecTag ff_nut_video_tags[] = { { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '4', 0, 16) }, { AV_CODEC_ID_RAWVIDEO, MKTAG(16, 0, '4', 'Y') }, + { AV_CODEC_ID_RAWVIDEO, MKTAG('Y', '1', 0, 14) }, + { AV_CODEC_ID_RAWVIDEO, MKTAG(14, 0, '1', 'Y') }, + { AV_CODEC_ID_RAWVIDEO, MKTAG('G', '3', 0, 8) }, { AV_CODEC_ID_RAWVIDEO, MKTAG('G', '3', 0, 9) }, diff --git a/libavformat/nutdec.c b/libavformat/nutdec.c index 27440c88d..979cb9a03 100644 --- a/libavformat/nutdec.c +++ b/libavformat/nutdec.c @@ -149,7 +149,7 @@ static int64_t find_startcode(AVIOContext *bc, uint64_t code, int64_t pos) } } -static int nut_probe(AVProbeData *p) +static int nut_probe(const AVProbeData *p) { int i; @@ -582,7 +582,7 @@ static int decode_info_header(NUTContext *nut) if (stream_id_plus1 && !strcmp(name, "r_frame_rate")) { sscanf(str_value, "%d/%d", &st->r_frame_rate.num, &st->r_frame_rate.den); if (st->r_frame_rate.num >= 1000LL*st->r_frame_rate.den || - st->r_frame_rate.num < 0 || st->r_frame_rate.num < 0) + st->r_frame_rate.num < 0 || st->r_frame_rate.den < 0) st->r_frame_rate.num = st->r_frame_rate.den = 0; continue; } @@ -1016,9 +1016,9 @@ static int decode_frame_header(NUTContext *nut, int64_t *pts, int *stream_id, } stc = &nut->stream[*stream_id]; if (flags & FLAG_CODED_PTS) { - int coded_pts = ffio_read_varlen(bc); + int64_t coded_pts = ffio_read_varlen(bc); // FIXME check last_pts validity? - if (coded_pts < (1 << stc->msb_pts_shift)) { + if (coded_pts < (1LL << stc->msb_pts_shift)) { *pts = ff_lsb2full(stc, coded_pts); } else *pts = coded_pts - (1LL << stc->msb_pts_shift); diff --git a/libavformat/nuv.c b/libavformat/nuv.c index 9bdea4ab5..a1edbf88d 100644 --- a/libavformat/nuv.c +++ b/libavformat/nuv.c @@ -47,7 +47,7 @@ typedef enum { NUV_MYTHEXT = 'X' } nuv_frametype; -static int nuv_probe(AVProbeData *p) +static int nuv_probe(const AVProbeData *p) { if (!memcmp(p->buf, "NuppelVideo", 12)) return AVPROBE_SCORE_MAX; diff --git a/libavformat/oggdec.c b/libavformat/oggdec.c index 27d16a3e4..e815f4213 100644 --- a/libavformat/oggdec.c +++ b/libavformat/oggdec.c @@ -941,7 +941,7 @@ static int ogg_read_seek(AVFormatContext *s, int stream_index, return ret; } -static int ogg_probe(AVProbeData *p) +static int ogg_probe(const AVProbeData *p) { if (!memcmp("OggS", p->buf, 5) && p->buf[5] <= 0x7) return AVPROBE_SCORE_MAX; diff --git a/libavformat/oggenc.c b/libavformat/oggenc.c index 10c4eda06..06021c4f4 100644 --- a/libavformat/oggenc.c +++ b/libavformat/oggenc.c @@ -291,7 +291,8 @@ static int ogg_buffer_data(AVFormatContext *s, AVStream *st, } static uint8_t *ogg_write_vorbiscomment(int64_t offset, int bitexact, - int *header_len, AVDictionary **m, int framing_bit) + int *header_len, AVDictionary **m, int framing_bit, + AVChapter **chapters, unsigned int nb_chapters) { const char *vendor = bitexact ? "ffmpeg" : LIBAVFORMAT_IDENT; int64_t size; @@ -299,7 +300,7 @@ static uint8_t *ogg_write_vorbiscomment(int64_t offset, int bitexact, ff_metadata_conv(m, ff_vorbiscomment_metadata_conv, NULL); - size = offset + ff_vorbiscomment_length(*m, vendor) + framing_bit; + size = offset + ff_vorbiscomment_length(*m, vendor, chapters, nb_chapters) + framing_bit; if (size > INT_MAX) return NULL; p = av_mallocz(size); @@ -308,7 +309,7 @@ static uint8_t *ogg_write_vorbiscomment(int64_t offset, int bitexact, p0 = p; p += offset; - ff_vorbiscomment_write(&p, m, vendor); + ff_vorbiscomment_write(&p, m, vendor, chapters, nb_chapters); if (framing_bit) bytestream_put_byte(&p, 1); @@ -342,7 +343,7 @@ static int ogg_build_flac_headers(AVCodecParameters *par, bytestream_put_buffer(&p, par->extradata, FLAC_STREAMINFO_SIZE); // second packet: VorbisComment - p = ogg_write_vorbiscomment(4, bitexact, &oggstream->header_len[1], m, 0); + p = ogg_write_vorbiscomment(4, bitexact, &oggstream->header_len[1], m, 0, NULL, 0); if (!p) return AVERROR(ENOMEM); oggstream->header[1] = p; @@ -373,7 +374,7 @@ static int ogg_build_speex_headers(AVCodecParameters *par, AV_WL32(&oggstream->header[0][68], 0); // set extra_headers to 0 // second packet: VorbisComment - p = ogg_write_vorbiscomment(0, bitexact, &oggstream->header_len[1], m, 0); + p = ogg_write_vorbiscomment(0, bitexact, &oggstream->header_len[1], m, 0, NULL, 0); if (!p) return AVERROR(ENOMEM); oggstream->header[1] = p; @@ -385,7 +386,8 @@ static int ogg_build_speex_headers(AVCodecParameters *par, static int ogg_build_opus_headers(AVCodecParameters *par, OGGStreamContext *oggstream, int bitexact, - AVDictionary **m) + AVDictionary **m, AVChapter **chapters, + unsigned int nb_chapters) { uint8_t *p; @@ -401,7 +403,7 @@ static int ogg_build_opus_headers(AVCodecParameters *par, bytestream_put_buffer(&p, par->extradata, par->extradata_size); /* second packet: VorbisComment */ - p = ogg_write_vorbiscomment(8, bitexact, &oggstream->header_len[1], m, 0); + p = ogg_write_vorbiscomment(8, bitexact, &oggstream->header_len[1], m, 0, chapters, nb_chapters); if (!p) return AVERROR(ENOMEM); oggstream->header[1] = p; @@ -446,7 +448,7 @@ static int ogg_build_vp8_headers(AVFormatContext *s, AVStream *st, /* optional second packet: VorbisComment */ if (av_dict_get(st->metadata, "", NULL, AV_DICT_IGNORE_SUFFIX)) { - p = ogg_write_vorbiscomment(7, bitexact, &oggstream->header_len[1], &st->metadata, 0); + p = ogg_write_vorbiscomment(7, bitexact, &oggstream->header_len[1], &st->metadata, 0, NULL, 0); if (!p) return AVERROR(ENOMEM); oggstream->header[1] = p; @@ -560,7 +562,7 @@ static int ogg_init(AVFormatContext *s) } else if (st->codecpar->codec_id == AV_CODEC_ID_OPUS) { int err = ogg_build_opus_headers(st->codecpar, oggstream, s->flags & AVFMT_FLAG_BITEXACT, - &st->metadata); + &st->metadata, s->chapters, s->nb_chapters); if (err) { av_log(s, AV_LOG_ERROR, "Error writing Opus headers\n"); av_freep(&st->priv_data); @@ -590,7 +592,7 @@ static int ogg_init(AVFormatContext *s) p = ogg_write_vorbiscomment(7, s->flags & AVFMT_FLAG_BITEXACT, &oggstream->header_len[1], &st->metadata, - framing_bit); + framing_bit, NULL, 0); oggstream->header[1] = p; if (!p) return AVERROR(ENOMEM); diff --git a/libavformat/oggparseogm.c b/libavformat/oggparseogm.c index a07453760..b07a5d55b 100644 --- a/libavformat/oggparseogm.c +++ b/libavformat/oggparseogm.c @@ -114,6 +114,9 @@ ogm_header(AVFormatContext *s, int idx) bytestream2_get_buffer(&p, st->codecpar->extradata, st->codecpar->extradata_size); } } + + // Update internal avctx with changes to codecpar above. + st->internal->need_context_update = 1; } else if (bytestream2_peek_byte(&p) == 3) { bytestream2_skip(&p, 7); if (bytestream2_get_bytes_left(&p) > 1) diff --git a/libavformat/oggparsevorbis.c b/libavformat/oggparsevorbis.c index bcfd246b8..43f05f928 100644 --- a/libavformat/oggparsevorbis.c +++ b/libavformat/oggparsevorbis.c @@ -44,7 +44,7 @@ static int ogm_chapter(AVFormatContext *as, uint8_t *key, uint8_t *val) int i, cnum, h, m, s, ms, keylen = strlen(key); AVChapter *chapter = NULL; - if (keylen < 9 || sscanf(key, "CHAPTER%03d", &cnum) != 1) + if (keylen < 9 || av_strncasecmp(key, "CHAPTER", 7) || sscanf(key+7, "%03d", &cnum) != 1) return 0; if (keylen <= 10) { @@ -55,7 +55,7 @@ static int ogm_chapter(AVFormatContext *as, uint8_t *key, uint8_t *val) ms + 1000 * (s + 60 * (m + 60 * h)), AV_NOPTS_VALUE, NULL); av_free(val); - } else if (!strcmp(key + keylen - 4, "NAME")) { + } else if (!av_strcasecmp(key + keylen - 4, "NAME")) { for (i = 0; i < as->nb_chapters; i++) if (as->chapters[i]->id == cnum) { chapter = as->chapters[i]; @@ -91,7 +91,7 @@ int ff_vorbis_comment(AVFormatContext *as, AVDictionary **m, const uint8_t *p = buf; const uint8_t *end = buf + size; int updates = 0; - unsigned n, j; + unsigned n; int s; /* must have vendor_length and user_comment_list_length */ @@ -139,8 +139,7 @@ int ff_vorbis_comment(AVFormatContext *as, AVDictionary **m, return AVERROR(ENOMEM); } - for (j = 0; j < tl; j++) - tt[j] = av_toupper(t[j]); + memcpy(tt, t, tl); tt[tl] = 0; memcpy(ct, v, vl); diff --git a/libavformat/omadec.c b/libavformat/omadec.c index 423d52b3a..60cbf3a87 100644 --- a/libavformat/omadec.c +++ b/libavformat/omadec.c @@ -539,7 +539,7 @@ static int oma_read_packet(AVFormatContext *s, AVPacket *pkt) return oc->read_packet(s, pkt); } -static int oma_read_probe(AVProbeData *p) +static int oma_read_probe(const AVProbeData *p) { const uint8_t *buf = p->buf; unsigned tag_len = 0; diff --git a/libavformat/options_table.h b/libavformat/options_table.h index 7c4d84798..f2f077b34 100644 --- a/libavformat/options_table.h +++ b/libavformat/options_table.h @@ -52,7 +52,9 @@ static const AVOption avformat_options[] = { {"keepside", "deprecated, does nothing", 0, AV_OPT_TYPE_CONST, {.i64 = AVFMT_FLAG_KEEP_SIDE_DATA }, INT_MIN, INT_MAX, D, "fflags"}, #endif {"fastseek", "fast but inaccurate seeks", 0, AV_OPT_TYPE_CONST, {.i64 = AVFMT_FLAG_FAST_SEEK }, INT_MIN, INT_MAX, D, "fflags"}, -{"latm", "enable RTP MP4A-LATM payload", 0, AV_OPT_TYPE_CONST, {.i64 = AVFMT_FLAG_MP4A_LATM }, INT_MIN, INT_MAX, E, "fflags"}, +#if FF_API_LAVF_MP4A_LATM +{"latm", "deprecated, does nothing", 0, AV_OPT_TYPE_CONST, {.i64 = AVFMT_FLAG_MP4A_LATM }, INT_MIN, INT_MAX, E, "fflags"}, +#endif {"nobuffer", "reduce the latency introduced by optional buffering", 0, AV_OPT_TYPE_CONST, {.i64 = AVFMT_FLAG_NOBUFFER }, 0, INT_MAX, D, "fflags"}, {"bitexact", "do not write random/volatile data", 0, AV_OPT_TYPE_CONST, { .i64 = AVFMT_FLAG_BITEXACT }, 0, 0, E, "fflags" }, {"shortest", "stop muxing with the shortest stream", 0, AV_OPT_TYPE_CONST, { .i64 = AVFMT_FLAG_SHORTEST }, 0, 0, E, "fflags" }, @@ -108,6 +110,7 @@ static const AVOption avformat_options[] = { {"protocol_whitelist", "List of protocols that are allowed to be used", OFFSET(protocol_whitelist), AV_OPT_TYPE_STRING, { .str = NULL }, CHAR_MIN, CHAR_MAX, D }, {"protocol_blacklist", "List of protocols that are not allowed to be used", OFFSET(protocol_blacklist), AV_OPT_TYPE_STRING, { .str = NULL }, CHAR_MIN, CHAR_MAX, D }, {"max_streams", "maximum number of streams", OFFSET(max_streams), AV_OPT_TYPE_INT, { .i64 = 1000 }, 0, INT_MAX, D }, +{"skip_estimate_duration_from_pts", "skip duration calculation in estimate_timings_from_pts", OFFSET(skip_estimate_duration_from_pts), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, D}, {NULL}, }; diff --git a/libavformat/os_support.c b/libavformat/os_support.c index 099d7b501..15cea7fa5 100644 --- a/libavformat/os_support.c +++ b/libavformat/os_support.c @@ -43,6 +43,7 @@ #include "network.h" +#if !HAVE_GETADDRINFO #if !HAVE_INET_ATON #include @@ -62,7 +63,6 @@ static int inet_aton(const char *str, struct in_addr *add) } #endif /* !HAVE_INET_ATON */ -#if !HAVE_GETADDRINFO int ff_getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res) { diff --git a/libavformat/os_support.h b/libavformat/os_support.h index 7a56dc9a7..5e6b32d2d 100644 --- a/libavformat/os_support.h +++ b/libavformat/os_support.h @@ -76,17 +76,7 @@ static inline int is_dos_path(const char *path) return 0; } -#if defined(__OS2__) -#define SHUT_RD 0 -#define SHUT_WR 1 -#define SHUT_RDWR 2 -#endif - #if defined(_WIN32) -#define SHUT_RD SD_RECEIVE -#define SHUT_WR SD_SEND -#define SHUT_RDWR SD_BOTH - #ifndef S_IRUSR #define S_IRUSR S_IREAD #endif @@ -96,6 +86,19 @@ static inline int is_dos_path(const char *path) #endif #if CONFIG_NETWORK +#if defined(_WIN32) +#define SHUT_RD SD_RECEIVE +#define SHUT_WR SD_SEND +#define SHUT_RDWR SD_BOTH +#else +#include +#if !defined(SHUT_RD) /* OS/2, DJGPP */ +#define SHUT_RD 0 +#define SHUT_WR 1 +#define SHUT_RDWR 2 +#endif +#endif + #if !HAVE_SOCKLEN_T typedef int socklen_t; #endif diff --git a/libavformat/paf.c b/libavformat/paf.c index fa30cdd72..b3c8e786b 100644 --- a/libavformat/paf.c +++ b/libavformat/paf.c @@ -53,7 +53,7 @@ typedef struct PAFDemuxContext { int got_audio; } PAFDemuxContext; -static int read_probe(AVProbeData *p) +static int read_probe(const AVProbeData *p) { if ((p->buf_size >= strlen(MAGIC)) && !memcmp(p->buf, MAGIC, strlen(MAGIC))) diff --git a/libavformat/pcmdec.c b/libavformat/pcmdec.c index d0ceea6fa..9895af03a 100644 --- a/libavformat/pcmdec.c +++ b/libavformat/pcmdec.c @@ -50,9 +50,9 @@ static int pcm_read_header(AVFormatContext *s) av_opt_get(s->pb, "mime_type", AV_OPT_SEARCH_CHILDREN, &mime_type); if (mime_type && s->iformat->mime_type) { - int rate = 0, channels = 0; + int rate = 0, channels = 0, little_endian = 0; size_t len = strlen(s->iformat->mime_type); - if (!strncmp(s->iformat->mime_type, mime_type, len)) { + if (!av_strncasecmp(s->iformat->mime_type, mime_type, len)) { /* audio/L16 */ uint8_t *options = mime_type + len; len = strlen(mime_type); while (options < mime_type + len) { @@ -63,6 +63,12 @@ static int pcm_read_header(AVFormatContext *s) sscanf(options, " rate=%d", &rate); if (!channels) sscanf(options, " channels=%d", &channels); + if (!little_endian) { + char val[14]; /* sizeof("little-endian") == 14 */ + if (sscanf(options, " endianness=%13s", val) == 1) { + little_endian = strcmp(val, "little-endian") == 0; + } + } } if (rate <= 0) { av_log(s, AV_LOG_ERROR, @@ -74,6 +80,8 @@ static int pcm_read_header(AVFormatContext *s) st->codecpar->sample_rate = rate; if (channels > 0) st->codecpar->channels = channels; + if (little_endian) + st->codecpar->codec_id = AV_CODEC_ID_PCM_S16LE; } } av_freep(&mime_type); @@ -142,10 +150,10 @@ PCMDEF(s24le, "PCM signed 24-bit little-endian", NULL, AV_CODEC_ID_PCM_S24LE) PCMDEF(s16be, "PCM signed 16-bit big-endian", - AV_NE("sw", NULL), AV_CODEC_ID_PCM_S16BE) + AV_NE("sw", NULL), AV_CODEC_ID_PCM_S16BE, .mime_type = "audio/L16") PCMDEF(s16le, "PCM signed 16-bit little-endian", - AV_NE(NULL, "sw"), AV_CODEC_ID_PCM_S16LE, .mime_type = "audio/L16",) + AV_NE(NULL, "sw"), AV_CODEC_ID_PCM_S16LE) PCMDEF(s8, "PCM signed 8-bit", "sb", AV_CODEC_ID_PCM_S8) @@ -177,6 +185,9 @@ PCMDEF(alaw, "PCM A-law", PCMDEF(mulaw, "PCM mu-law", "ul", AV_CODEC_ID_PCM_MULAW) +PCMDEF(vidc, "PCM Archimedes VIDC", + NULL, AV_CODEC_ID_PCM_VIDC) + static const AVOption sln_options[] = { { "sample_rate", "", offsetof(PCMAudioDemuxerContext, sample_rate), AV_OPT_TYPE_INT, {.i64 = 8000}, 0, INT_MAX, AV_OPT_FLAG_DECODING_PARAM }, { "channels", "", offsetof(PCMAudioDemuxerContext, channels), AV_OPT_TYPE_INT, {.i64 = 1}, 0, INT_MAX, AV_OPT_FLAG_DECODING_PARAM }, diff --git a/libavformat/pcmenc.c b/libavformat/pcmenc.c index 3e4f30805..1760b3bef 100644 --- a/libavformat/pcmenc.c +++ b/libavformat/pcmenc.c @@ -92,3 +92,6 @@ PCMDEF(alaw, "PCM A-law", PCMDEF(mulaw, "PCM mu-law", "ul", AV_CODEC_ID_PCM_MULAW) + +PCMDEF(vidc, "PCM Archimedes VIDC", + NULL, AV_CODEC_ID_PCM_VIDC) diff --git a/libavformat/pjsdec.c b/libavformat/pjsdec.c index bb587b569..50b1a48e4 100644 --- a/libavformat/pjsdec.c +++ b/libavformat/pjsdec.c @@ -33,7 +33,7 @@ typedef struct { FFDemuxSubtitlesQueue q; } PJSContext; -static int pjs_probe(AVProbeData *p) +static int pjs_probe(const AVProbeData *p) { char c; int64_t start, end; diff --git a/libavformat/pmpdec.c b/libavformat/pmpdec.c index 0e80a095f..0c2b6f5a9 100644 --- a/libavformat/pmpdec.c +++ b/libavformat/pmpdec.c @@ -32,7 +32,7 @@ typedef struct { int packet_sizes_alloc; } PMPContext; -static int pmp_probe(AVProbeData *p) { +static int pmp_probe(const AVProbeData *p) { if (AV_RN32(p->buf) == AV_RN32("pmpm") && AV_RL32(p->buf + 4) == 1) return AVPROBE_SCORE_MAX; diff --git a/libavformat/psxstr.c b/libavformat/psxstr.c index f7b9495bb..ddc17e35d 100644 --- a/libavformat/psxstr.c +++ b/libavformat/psxstr.c @@ -68,7 +68,7 @@ typedef struct StrDemuxContext { static const uint8_t sync_header[12] = {0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00}; -static int str_probe(AVProbeData *p) +static int str_probe(const AVProbeData *p) { const uint8_t *sector= p->buf; const uint8_t *end= sector + p->buf_size; diff --git a/libavformat/pva.c b/libavformat/pva.c index 04ae8e280..58ec78750 100644 --- a/libavformat/pva.c +++ b/libavformat/pva.c @@ -40,7 +40,7 @@ static int pva_check(const uint8_t *p) { return length + 8; } -static int pva_probe(AVProbeData * pd) { +static int pva_probe(const AVProbeData * pd) { const unsigned char *buf = pd->buf; int len = pva_check(buf); diff --git a/libavformat/pvfdec.c b/libavformat/pvfdec.c index c6652b9b4..4c919942c 100644 --- a/libavformat/pvfdec.c +++ b/libavformat/pvfdec.c @@ -24,7 +24,7 @@ #include "internal.h" #include "pcm.h" -static int pvf_probe(AVProbeData *p) +static int pvf_probe(const AVProbeData *p) { if (!memcmp(p->buf, "PVF1\n", 5)) return AVPROBE_SCORE_MAX; diff --git a/libavformat/qcp.c b/libavformat/qcp.c index b842e2633..168030dc1 100644 --- a/libavformat/qcp.c +++ b/libavformat/qcp.c @@ -79,7 +79,7 @@ static int is_qcelp_13k_guid(const uint8_t *guid) { && !memcmp(guid+1, guid_qcelp_13k_part, sizeof(guid_qcelp_13k_part)); } -static int qcp_probe(AVProbeData *pd) +static int qcp_probe(const AVProbeData *pd) { if (AV_RL32(pd->buf ) == AV_RL32("RIFF") && AV_RL64(pd->buf+8) == AV_RL64("QLCMfmt ")) diff --git a/libavformat/r3d.c b/libavformat/r3d.c index 1f53d847e..224bcf780 100644 --- a/libavformat/r3d.c +++ b/libavformat/r3d.c @@ -368,7 +368,7 @@ static int r3d_read_packet(AVFormatContext *s, AVPacket *pkt) return err; } -static int r3d_probe(AVProbeData *p) +static int r3d_probe(const AVProbeData *p) { if (AV_RL32(p->buf + 4) == MKTAG('R','E','D','1')) return AVPROBE_SCORE_MAX; diff --git a/libavformat/rawdec.c b/libavformat/rawdec.c index b38a4b5e5..59b49e3f7 100644 --- a/libavformat/rawdec.c +++ b/libavformat/rawdec.c @@ -34,9 +34,10 @@ int ff_raw_read_partial_packet(AVFormatContext *s, AVPacket *pkt) { + FFRawDemuxerContext *raw = s->priv_data; int ret, size; - size = RAW_PACKET_SIZE; + size = raw->raw_packet_size; if (av_new_packet(pkt, size) < 0) return AVERROR(ENOMEM); @@ -91,6 +92,17 @@ fail: return ret; } +int ff_raw_subtitle_read_header(AVFormatContext *s) +{ + AVStream *st = avformat_new_stream(s, NULL); + if (!st) + return AVERROR(ENOMEM); + st->codecpar->codec_type = AVMEDIA_TYPE_SUBTITLE; + st->codecpar->codec_id = s->iformat->raw_codec_id; + st->start_time = 0; + return 0; +} + int ff_raw_data_read_header(AVFormatContext *s) { AVStream *st = avformat_new_stream(s, NULL); @@ -108,10 +120,17 @@ int ff_raw_data_read_header(AVFormatContext *s) #define DEC AV_OPT_FLAG_DECODING_PARAM const AVOption ff_rawvideo_options[] = { { "framerate", "", OFFSET(framerate), AV_OPT_TYPE_VIDEO_RATE, {.str = "25"}, 0, INT_MAX, DEC}, + { "raw_packet_size", "", OFFSET(raw_packet_size), AV_OPT_TYPE_INT, {.i64 = RAW_PACKET_SIZE }, 1, INT_MAX, DEC}, + { NULL }, +}; +const AVOption ff_raw_options[] = { + { "raw_packet_size", "", OFFSET(raw_packet_size), AV_OPT_TYPE_INT, {.i64 = RAW_PACKET_SIZE }, 1, INT_MAX, DEC}, { NULL }, }; #if CONFIG_DATA_DEMUXER +FF_RAW_DEMUXER_CLASS(raw_data) + AVInputFormat ff_data_demuxer = { .name = "data", .long_name = NULL_IF_CONFIG_SMALL("raw data"), @@ -119,11 +138,13 @@ AVInputFormat ff_data_demuxer = { .read_packet = ff_raw_read_partial_packet, .raw_codec_id = AV_CODEC_ID_NONE, .flags = AVFMT_NOTIMESTAMPS, + .priv_data_size = sizeof(FFRawDemuxerContext),\ + .priv_class = &raw_data_demuxer_class,\ }; #endif #if CONFIG_MJPEG_DEMUXER -static int mjpeg_probe(AVProbeData *p) +static int mjpeg_probe(const AVProbeData *p) { int i; int state = -1; diff --git a/libavformat/rawdec.h b/libavformat/rawdec.h index a464bbb43..85e0790c8 100644 --- a/libavformat/rawdec.h +++ b/libavformat/rawdec.h @@ -28,12 +28,19 @@ typedef struct FFRawVideoDemuxerContext { const AVClass *class; /**< Class for private options. */ + int raw_packet_size; char *video_size; /**< String describing video size, set by a private option. */ char *pixel_format; /**< Set by a private option. */ AVRational framerate; /**< AVRational describing framerate, set by a private option. */ } FFRawVideoDemuxerContext; +typedef struct FFRawDemuxerContext { + const AVClass *class; /**< Class for private options. */ + int raw_packet_size; +} FFRawDemuxerContext; + extern const AVOption ff_rawvideo_options[]; +extern const AVOption ff_raw_options[]; int ff_raw_read_partial_packet(AVFormatContext *s, AVPacket *pkt); @@ -41,8 +48,18 @@ int ff_raw_audio_read_header(AVFormatContext *s); int ff_raw_video_read_header(AVFormatContext *s); +int ff_raw_subtitle_read_header(AVFormatContext *s); + int ff_raw_data_read_header(AVFormatContext *s); +#define FF_RAW_DEMUXER_CLASS(name)\ +static const AVClass name ## _demuxer_class = {\ + .class_name = #name " demuxer",\ + .item_name = av_default_item_name,\ + .option = ff_raw_options,\ + .version = LIBAVUTIL_VERSION_INT,\ +}; + #define FF_RAWVIDEO_DEMUXER_CLASS(name)\ static const AVClass name ## _demuxer_class = {\ .class_name = #name " demuxer",\ @@ -73,7 +90,7 @@ FF_DEF_RAWVIDEO_DEMUXER2(shortname, longname, probe, ext, id, AVFMT_GENERIC_INDE static const AVClass name ## _demuxer_class = {\ .class_name = #name " demuxer",\ .item_name = av_default_item_name,\ - .option = NULL,\ + .option = ff_raw_options,\ .version = LIBAVUTIL_VERSION_INT,\ }; @@ -83,12 +100,12 @@ AVInputFormat ff_ ## shortname ## _demuxer = {\ .name = #shortname,\ .long_name = NULL_IF_CONFIG_SMALL(longname),\ .read_probe = probe,\ - .read_header = ff_raw_data_read_header,\ + .read_header = ff_raw_subtitle_read_header,\ .read_packet = ff_raw_read_partial_packet,\ .extensions = ext,\ .flags = flag,\ .raw_codec_id = id,\ - .priv_data_size = 0,\ + .priv_data_size = sizeof(FFRawDemuxerContext),\ .priv_class = &shortname ## _demuxer_class,\ }; diff --git a/libavformat/rawenc.c b/libavformat/rawenc.c index 809ca23b1..32704f9bf 100644 --- a/libavformat/rawenc.c +++ b/libavformat/rawenc.c @@ -39,6 +39,18 @@ static int force_one_stream(AVFormatContext *s) s->oformat->name); return AVERROR(EINVAL); } + if ( s->oformat->audio_codec != AV_CODEC_ID_NONE + && s->streams[0]->codecpar->codec_type != AVMEDIA_TYPE_AUDIO) { + av_log(s, AV_LOG_ERROR, "%s files have exactly one audio stream\n", + s->oformat->name); + return AVERROR(EINVAL); + } + if ( s->oformat->video_codec != AV_CODEC_ID_NONE + && s->streams[0]->codecpar->codec_type != AVMEDIA_TYPE_VIDEO) { + av_log(s, AV_LOG_ERROR, "%s files have exactly one video stream\n", + s->oformat->name); + return AVERROR(EINVAL); + } return 0; } @@ -117,6 +129,19 @@ AVOutputFormat ff_aptx_hd_muxer = { }; #endif +#if CONFIG_AVS2_MUXER +AVOutputFormat ff_avs2_muxer = { + .name = "avs2", + .long_name = NULL_IF_CONFIG_SMALL("raw AVS2-P2/IEEE1857.4 video"), + .extensions = "avs,avs2", + .audio_codec = AV_CODEC_ID_NONE, + .video_codec = AV_CODEC_ID_AVS2, + .write_header = force_one_stream, + .write_packet = ff_raw_write_packet, + .flags = AVFMT_NOTIMESTAMPS, +}; +#endif + #if CONFIG_CAVSVIDEO_MUXER AVOutputFormat ff_cavsvideo_muxer = { .name = "cavsvideo", diff --git a/libavformat/realtextdec.c b/libavformat/realtextdec.c index 618d4f78e..c2316da0e 100644 --- a/libavformat/realtextdec.c +++ b/libavformat/realtextdec.c @@ -35,7 +35,7 @@ typedef struct { FFDemuxSubtitlesQueue q; } RealTextContext; -static int realtext_probe(AVProbeData *p) +static int realtext_probe(const AVProbeData *p) { char buf[7]; FFTextReader tr; @@ -87,6 +87,10 @@ static int realtext_read_header(AVFormatContext *s) /* save header to extradata */ const char *p = ff_smil_get_attr_ptr(buf.str, "duration"); + if (st->codecpar->extradata) { + res = AVERROR_INVALIDDATA; + goto end; + } if (p) duration = read_ts(p); st->codecpar->extradata = av_strdup(buf.str); @@ -119,6 +123,8 @@ static int realtext_read_header(AVFormatContext *s) end: av_bprint_finalize(&buf, NULL); + if (res < 0) + ff_subtitles_queue_clean(&rt->q); return res; } diff --git a/libavformat/redspark.c b/libavformat/redspark.c index c24704658..f1f2b3156 100644 --- a/libavformat/redspark.c +++ b/libavformat/redspark.c @@ -32,7 +32,7 @@ typedef struct RedSparkContext { int samples_count; } RedSparkContext; -static int redspark_probe(AVProbeData *p) +static int redspark_probe(const AVProbeData *p) { uint32_t key, data; uint8_t header[8]; diff --git a/libavformat/riff.c b/libavformat/riff.c index 89117250d..52b0bf8f0 100644 --- a/libavformat/riff.c +++ b/libavformat/riff.c @@ -307,6 +307,7 @@ const AVCodecTag ff_codec_bmp_tags[] = { { AV_CODEC_ID_INDEO5, MKTAG('I', 'V', '5', '0') }, { AV_CODEC_ID_VP3, MKTAG('V', 'P', '3', '1') }, { AV_CODEC_ID_VP3, MKTAG('V', 'P', '3', '0') }, + { AV_CODEC_ID_VP4, MKTAG('V', 'P', '4', '0') }, { AV_CODEC_ID_VP5, MKTAG('V', 'P', '5', '0') }, { AV_CODEC_ID_VP6, MKTAG('V', 'P', '6', '0') }, { AV_CODEC_ID_VP6, MKTAG('V', 'P', '6', '1') }, @@ -369,6 +370,7 @@ const AVCodecTag ff_codec_bmp_tags[] = { { AV_CODEC_ID_ZMBV, MKTAG('Z', 'M', 'B', 'V') }, { AV_CODEC_ID_KMVC, MKTAG('K', 'M', 'V', 'C') }, { AV_CODEC_ID_CAVS, MKTAG('C', 'A', 'V', 'S') }, + { AV_CODEC_ID_AVS2, MKTAG('A', 'V', 'S', '2') }, { AV_CODEC_ID_JPEG2000, MKTAG('m', 'j', 'p', '2') }, { AV_CODEC_ID_JPEG2000, MKTAG('M', 'J', '2', 'C') }, { AV_CODEC_ID_JPEG2000, MKTAG('L', 'J', '2', 'C') }, @@ -452,6 +454,7 @@ const AVCodecTag ff_codec_bmp_tags[] = { { AV_CODEC_ID_MAGICYUV, MKTAG('M', '0', 'R', 'G') }, { AV_CODEC_ID_MAGICYUV, MKTAG('M', '0', 'G', '0') }, { AV_CODEC_ID_MAGICYUV, MKTAG('M', '0', 'Y', '2') }, + { AV_CODEC_ID_MAGICYUV, MKTAG('M', '0', 'Y', '4') }, { AV_CODEC_ID_MAGICYUV, MKTAG('M', '2', 'R', 'A') }, { AV_CODEC_ID_MAGICYUV, MKTAG('M', '2', 'R', 'G') }, { AV_CODEC_ID_YLC, MKTAG('Y', 'L', 'C', '0') }, @@ -469,6 +472,27 @@ const AVCodecTag ff_codec_bmp_tags[] = { { AV_CODEC_ID_AV1, MKTAG('A', 'V', '0', '1') }, { AV_CODEC_ID_MSCC, MKTAG('M', 'S', 'C', 'C') }, { AV_CODEC_ID_SRGC, MKTAG('S', 'R', 'G', 'C') }, + { AV_CODEC_ID_IMM4, MKTAG('I', 'M', 'M', '4') }, + { AV_CODEC_ID_PROSUMER, MKTAG('B', 'T', '2', '0') }, + { AV_CODEC_ID_MWSC, MKTAG('M', 'W', 'S', 'C') }, + { AV_CODEC_ID_WCMV, MKTAG('W', 'C', 'M', 'V') }, + { AV_CODEC_ID_RASC, MKTAG('R', 'A', 'S', 'C') }, + { AV_CODEC_ID_HYMT, MKTAG('H', 'Y', 'M', 'T') }, + { AV_CODEC_ID_ARBC, MKTAG('A', 'R', 'B', 'C') }, + { AV_CODEC_ID_AGM, MKTAG('A', 'G', 'M', '0') }, + { AV_CODEC_ID_AGM, MKTAG('A', 'G', 'M', '1') }, + { AV_CODEC_ID_AGM, MKTAG('A', 'G', 'M', '2') }, + { AV_CODEC_ID_AGM, MKTAG('A', 'G', 'M', '3') }, + { AV_CODEC_ID_AGM, MKTAG('A', 'G', 'M', '4') }, + { AV_CODEC_ID_AGM, MKTAG('A', 'G', 'M', '5') }, + { AV_CODEC_ID_AGM, MKTAG('A', 'G', 'M', '6') }, + { AV_CODEC_ID_AGM, MKTAG('A', 'G', 'M', '7') }, + { AV_CODEC_ID_LSCR, MKTAG('L', 'S', 'C', 'R') }, + { AV_CODEC_ID_NONE, 0 } +}; + +const AVCodecTag ff_codec_bmp_tags_unofficial[] = { + { AV_CODEC_ID_HEVC, MKTAG('H', 'E', 'V', 'C') }, { AV_CODEC_ID_NONE, 0 } }; @@ -586,7 +610,9 @@ const struct AVCodecTag *avformat_get_riff_audio_tags(void) const AVCodecGuid ff_codec_wav_guids[] = { { AV_CODEC_ID_AC3, { 0x2C, 0x80, 0x6D, 0xE0, 0x46, 0xDB, 0xCF, 0x11, 0xB4, 0xD1, 0x00, 0x80, 0x5F, 0x6C, 0xBB, 0xEA } }, { AV_CODEC_ID_ATRAC3P, { 0xBF, 0xAA, 0x23, 0xE9, 0x58, 0xCB, 0x71, 0x44, 0xA1, 0x19, 0xFF, 0xFA, 0x01, 0xE4, 0xCE, 0x62 } }, + { AV_CODEC_ID_ATRAC9, { 0xD2, 0x42, 0xE1, 0x47, 0xBA, 0x36, 0x8D, 0x4D, 0x88, 0xFC, 0x61, 0x65, 0x4F, 0x8C, 0x83, 0x6C } }, { AV_CODEC_ID_EAC3, { 0xAF, 0x87, 0xFB, 0xA7, 0x02, 0x2D, 0xFB, 0x42, 0xA4, 0xD4, 0x05, 0xCD, 0x93, 0x84, 0x3B, 0xDD } }, { AV_CODEC_ID_MP2, { 0x2B, 0x80, 0x6D, 0xE0, 0x46, 0xDB, 0xCF, 0x11, 0xB4, 0xD1, 0x00, 0x80, 0x5F, 0x6C, 0xBB, 0xEA } }, + { AV_CODEC_ID_ADPCM_AGM,{ 0x82, 0xEC, 0x1F, 0x6A, 0xCA, 0xDB, 0x19, 0x45, 0xBD, 0xE7, 0x56, 0xD3, 0xB3, 0xEF, 0x98, 0x1D } }, { AV_CODEC_ID_NONE } }; diff --git a/libavformat/riff.h b/libavformat/riff.h index 323aa38b4..21078b77c 100644 --- a/libavformat/riff.h +++ b/libavformat/riff.h @@ -73,6 +73,8 @@ int ff_get_wav_header(AVFormatContext *s, AVIOContext *pb, AVCodecParameters *pa extern const AVCodecTag ff_codec_bmp_tags[]; // exposed through avformat_get_riff_video_tags() extern const AVCodecTag ff_codec_wav_tags[]; +extern const AVCodecTag ff_codec_bmp_tags_unofficial[]; + void ff_parse_specific_params(AVStream *st, int *au_rate, int *au_ssize, int *au_scale); int ff_read_riff_info(AVFormatContext *s, int64_t size); diff --git a/libavformat/riffdec.c b/libavformat/riffdec.c index b448f9116..5523b31ad 100644 --- a/libavformat/riffdec.c +++ b/libavformat/riffdec.c @@ -58,7 +58,7 @@ enum AVCodecID ff_codec_guid_get_id(const AVCodecGuid *guids, ff_asf_guid guid) * an openended structure. */ -static void parse_waveformatex(AVIOContext *pb, AVCodecParameters *par) +static void parse_waveformatex(AVFormatContext *s, AVIOContext *pb, AVCodecParameters *par) { ff_asf_guid subformat; int bps; @@ -81,7 +81,7 @@ static void parse_waveformatex(AVIOContext *pb, AVCodecParameters *par) } else { par->codec_id = ff_codec_guid_get_id(ff_codec_wav_guids, subformat); if (!par->codec_id) - av_log(pb, AV_LOG_WARNING, + av_log(s, AV_LOG_WARNING, "unknown subformat:"FF_PRI_GUID"\n", FF_ARG_GUID(subformat)); } @@ -140,7 +140,7 @@ int ff_get_wav_header(AVFormatContext *s, AVIOContext *pb, size -= 18; cbSize = FFMIN(size, cbSize); if (cbSize >= 22 && id == 0xfffe) { /* WAVEFORMATEXTENSIBLE */ - parse_waveformatex(pb, par); + parse_waveformatex(s, pb, par); cbSize -= 22; size -= 22; } diff --git a/libavformat/rl2.c b/libavformat/rl2.c index eb1682dfc..d847d9aaa 100644 --- a/libavformat/rl2.c +++ b/libavformat/rl2.c @@ -55,7 +55,7 @@ typedef struct Rl2DemuxContext { * @param p probe buffer * @return 0 when the probe buffer does not contain rl2 data, > 0 otherwise */ -static int rl2_probe(AVProbeData *p) +static int rl2_probe(const AVProbeData *p) { if(AV_RB32(&p->buf[0]) != FORM_TAG) diff --git a/libavformat/rmdec.c b/libavformat/rmdec.c index f26c5b4d9..c9abd38d3 100644 --- a/libavformat/rmdec.c +++ b/libavformat/rmdec.c @@ -1067,7 +1067,7 @@ static int rm_read_close(AVFormatContext *s) return 0; } -static int rm_probe(AVProbeData *p) +static int rm_probe(const AVProbeData *p) { /* check file header */ if ((p->buf[0] == '.' && p->buf[1] == 'R' && @@ -1158,7 +1158,7 @@ AVInputFormat ff_rdt_demuxer = { .flags = AVFMT_NOFILE, }; -static int ivr_probe(AVProbeData *p) +static int ivr_probe(const AVProbeData *p) { if (memcmp(p->buf, ".R1M\x0\x1\x1", 7) && memcmp(p->buf, ".REC", 4)) diff --git a/libavformat/rpl.c b/libavformat/rpl.c index d37360047..6afd37381 100644 --- a/libavformat/rpl.c +++ b/libavformat/rpl.c @@ -33,7 +33,7 @@ /** 256 is arbitrary, but should be big enough for any reasonable file. */ #define RPL_LINE_LENGTH 256 -static int rpl_probe(AVProbeData *p) +static int rpl_probe(const AVProbeData *p) { if (memcmp(p->buf, RPL_SIGNATURE, RPL_SIGNATURE_SIZE)) return 0; @@ -119,10 +119,12 @@ static int rpl_read_header(AVFormatContext *s) AVStream *vst = NULL, *ast = NULL; int total_audio_size; int error = 0; + const char *endptr; + char audio_type[RPL_LINE_LENGTH]; uint32_t i; - int32_t audio_format, chunk_catalog_offset, number_of_chunks; + int32_t video_format, audio_format, chunk_catalog_offset, number_of_chunks; AVRational fps; char line[RPL_LINE_LENGTH]; @@ -142,38 +144,46 @@ static int rpl_read_header(AVFormatContext *s) av_dict_set(&s->metadata, "author" , line, 0); // video headers - vst = avformat_new_stream(s, NULL); - if (!vst) - return AVERROR(ENOMEM); - vst->codecpar->codec_type = AVMEDIA_TYPE_VIDEO; - vst->codecpar->codec_tag = read_line_and_int(pb, &error); // video format - vst->codecpar->width = read_line_and_int(pb, &error); // video width - vst->codecpar->height = read_line_and_int(pb, &error); // video height - vst->codecpar->bits_per_coded_sample = read_line_and_int(pb, &error); // video bits per sample + video_format = read_line_and_int(pb, &error); + if (video_format) { + vst = avformat_new_stream(s, NULL); + if (!vst) + return AVERROR(ENOMEM); + vst->codecpar->codec_type = AVMEDIA_TYPE_VIDEO; + vst->codecpar->codec_tag = video_format; + vst->codecpar->width = read_line_and_int(pb, &error); // video width + vst->codecpar->height = read_line_and_int(pb, &error); // video height + vst->codecpar->bits_per_coded_sample = read_line_and_int(pb, &error); // video bits per sample + + // Figure out the video codec + switch (vst->codecpar->codec_tag) { +#if 0 + case 122: + vst->codecpar->codec_id = AV_CODEC_ID_ESCAPE122; + break; +#endif + case 124: + vst->codecpar->codec_id = AV_CODEC_ID_ESCAPE124; + // The header is wrong here, at least sometimes + vst->codecpar->bits_per_coded_sample = 16; + break; + case 130: + vst->codecpar->codec_id = AV_CODEC_ID_ESCAPE130; + break; + default: + avpriv_report_missing_feature(s, "Video format %s", + av_fourcc2str(vst->codecpar->codec_tag)); + vst->codecpar->codec_id = AV_CODEC_ID_NONE; + } + } else { + for (i = 0; i < 3; i++) + error |= read_line(pb, line, sizeof(line)); + } + error |= read_line(pb, line, sizeof(line)); // video frames per second fps = read_fps(line, &error); - avpriv_set_pts_info(vst, 32, fps.den, fps.num); - - // Figure out the video codec - switch (vst->codecpar->codec_tag) { -#if 0 - case 122: - vst->codecpar->codec_id = AV_CODEC_ID_ESCAPE122; - break; -#endif - case 124: - vst->codecpar->codec_id = AV_CODEC_ID_ESCAPE124; - // The header is wrong here, at least sometimes - vst->codecpar->bits_per_coded_sample = 16; - break; - case 130: - vst->codecpar->codec_id = AV_CODEC_ID_ESCAPE130; - break; - default: - avpriv_report_missing_feature(s, "Video format %s", - av_fourcc2str(vst->codecpar->codec_tag)); - vst->codecpar->codec_id = AV_CODEC_ID_NONE; - } + if (vst) + avpriv_set_pts_info(vst, 32, fps.den, fps.num); // Audio headers @@ -188,7 +198,9 @@ static int rpl_read_header(AVFormatContext *s) ast->codecpar->codec_tag = audio_format; ast->codecpar->sample_rate = read_line_and_int(pb, &error); // audio bitrate ast->codecpar->channels = read_line_and_int(pb, &error); // number of audio channels - ast->codecpar->bits_per_coded_sample = read_line_and_int(pb, &error); // audio bits per sample + error |= read_line(pb, line, sizeof(line)); + ast->codecpar->bits_per_coded_sample = read_int(line, &endptr, &error); // audio bits per sample + av_strlcpy(audio_type, endptr, RPL_LINE_LENGTH); // At least one sample uses 0 for ADPCM, which is really 4 bits // per sample. if (ast->codecpar->bits_per_coded_sample == 0) @@ -205,6 +217,17 @@ static int rpl_read_header(AVFormatContext *s) // 16-bit audio is always signed ast->codecpar->codec_id = AV_CODEC_ID_PCM_S16LE; break; + } else if (ast->codecpar->bits_per_coded_sample == 8) { + if(av_stristr(audio_type, "unsigned") != NULL) { + ast->codecpar->codec_id = AV_CODEC_ID_PCM_U8; + break; + } else if(av_stristr(audio_type, "linear") != NULL) { + ast->codecpar->codec_id = AV_CODEC_ID_PCM_S8; + break; + } else { + ast->codecpar->codec_id = AV_CODEC_ID_PCM_VIDC; + break; + } } // There are some other formats listed as legal per the spec; // samples needed. @@ -231,7 +254,7 @@ static int rpl_read_header(AVFormatContext *s) } rpl->frames_per_chunk = read_line_and_int(pb, &error); // video frames per chunk - if (rpl->frames_per_chunk > 1 && vst->codecpar->codec_tag != 124) + if (vst && rpl->frames_per_chunk > 1 && vst->codecpar->codec_tag != 124) av_log(s, AV_LOG_WARNING, "Don't know how to split frames for video format %s. " "Video stream will be broken!\n", av_fourcc2str(vst->codecpar->codec_tag)); @@ -246,7 +269,10 @@ static int rpl_read_header(AVFormatContext *s) read_line_and_int(pb, &error); // (file index) error |= read_line(pb, line, sizeof(line)); // offset to "helpful" sprite error |= read_line(pb, line, sizeof(line)); // size of "helpful" sprite - error |= read_line(pb, line, sizeof(line)); // offset to key frame list + if (vst) { + error |= read_line(pb, line, sizeof(line)); // offset to key frame list + vst->duration = number_of_chunks * rpl->frames_per_chunk; + } // Read the index avio_seek(pb, chunk_catalog_offset, SEEK_SET); @@ -259,8 +285,9 @@ static int rpl_read_header(AVFormatContext *s) error = -1; continue; } - av_add_index_entry(vst, offset, i * rpl->frames_per_chunk, - video_size, rpl->frames_per_chunk, 0); + if (vst) + av_add_index_entry(vst, offset, i * rpl->frames_per_chunk, + video_size, rpl->frames_per_chunk, 0); if (ast) av_add_index_entry(ast, offset + video_size, total_audio_size, audio_size, audio_size * 8, 0); diff --git a/libavformat/rsd.c b/libavformat/rsd.c index 1c99f8c21..396a431f3 100644 --- a/libavformat/rsd.c +++ b/libavformat/rsd.c @@ -41,7 +41,7 @@ static const uint32_t rsd_unsupported_tags[] = { MKTAG('O','G','G',' '), }; -static int rsd_probe(AVProbeData *p) +static int rsd_probe(const AVProbeData *p) { if (memcmp(p->buf, "RSD", 3) || p->buf[3] - '0' < 2 || p->buf[3] - '0' > 6) return 0; diff --git a/libavformat/rtmpcrypt.c b/libavformat/rtmpcrypt.c index c41ae4308..253b8ca2c 100644 --- a/libavformat/rtmpcrypt.c +++ b/libavformat/rtmpcrypt.c @@ -301,7 +301,7 @@ static int rtmpe_write(URLContext *h, const uint8_t *buf, int size) if (rt->handshaked) { /* encrypt data to send to the server */ - av_rc4_crypt(&rt->key_out, buf, buf, size, NULL, 1); + av_rc4_crypt(&rt->key_out, (uint8_t *)buf, buf, size, NULL, 1); } if ((ret = ffurl_write(rt->stream, buf, size)) < 0) diff --git a/libavformat/rtmpdh.c b/libavformat/rtmpdh.c index 8eb088237..5ddae537a 100644 --- a/libavformat/rtmpdh.c +++ b/libavformat/rtmpdh.c @@ -38,6 +38,11 @@ #include "rtmpdh.h" +#if CONFIG_MBEDTLS +#include +#include +#endif + #define P1024 \ "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" \ "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" \ @@ -159,6 +164,56 @@ static int bn_modexp(FFBigNum bn, FFBigNum y, FFBigNum q, FFBigNum p) BN_CTX_free(ctx); return 0; } +#elif CONFIG_MBEDTLS +#define bn_new(bn) \ + do { \ + bn = av_malloc(sizeof(*bn)); \ + if (bn) \ + mbedtls_mpi_init(bn); \ + } while (0) +#define bn_free(bn) \ + do { \ + mbedtls_mpi_free(bn); \ + av_free(bn); \ + } while (0) +#define bn_set_word(bn, w) mbedtls_mpi_lset(bn, w) +#define bn_cmp(a, b) mbedtls_mpi_cmp_mpi(a, b) +#define bn_copy(to, from) mbedtls_mpi_copy(to, from) +#define bn_sub_word(bn, w) mbedtls_mpi_sub_int(bn, bn, w) +#define bn_cmp_1(bn) mbedtls_mpi_cmp_int(bn, 1) +#define bn_num_bytes(bn) (mbedtls_mpi_bitlen(bn) + 7) / 8 +#define bn_bn2bin(bn, buf, len) mbedtls_mpi_write_binary(bn, buf, len) +#define bn_bin2bn(bn, buf, len) \ + do { \ + bn_new(bn); \ + if (bn) \ + mbedtls_mpi_read_binary(bn, buf, len); \ + } while (0) +#define bn_hex2bn(bn, buf, ret) \ + do { \ + bn_new(bn); \ + if (bn) \ + ret = (mbedtls_mpi_read_string(bn, 16, buf) == 0); \ + else \ + ret = 1; \ + } while (0) +#define bn_random(bn, num_bits) \ + do { \ + mbedtls_entropy_context entropy_ctx; \ + mbedtls_ctr_drbg_context ctr_drbg_ctx; \ + \ + mbedtls_entropy_init(&entropy_ctx); \ + mbedtls_ctr_drbg_init(&ctr_drbg_ctx); \ + mbedtls_ctr_drbg_seed(&ctr_drbg_ctx, \ + mbedtls_entropy_func, \ + &entropy_ctx, \ + NULL, 0); \ + mbedtls_mpi_fill_random(bn, (num_bits + 7) / 8, mbedtls_ctr_drbg_random, &ctr_drbg_ctx); \ + mbedtls_ctr_drbg_free(&ctr_drbg_ctx); \ + mbedtls_entropy_free(&entropy_ctx); \ + } while (0) +#define bn_modexp(bn, y, q, p) mbedtls_mpi_exp_mod(bn, y, q, p, 0) + #endif #define MAX_BYTES 18000 diff --git a/libavformat/rtmpdh.h b/libavformat/rtmpdh.h index 188aad7a4..8cc1a42b6 100644 --- a/libavformat/rtmpdh.h +++ b/libavformat/rtmpdh.h @@ -40,6 +40,11 @@ typedef gcry_mpi_t FFBigNum; #include typedef BIGNUM *FFBigNum; +#elif CONFIG_MBEDTLS +#include + +typedef mbedtls_mpi *FFBigNum; + #endif typedef struct FF_DH { diff --git a/libavformat/rtp.c b/libavformat/rtp.c index 4745e54bb..38e234391 100644 --- a/libavformat/rtp.c +++ b/libavformat/rtp.c @@ -91,7 +91,7 @@ int ff_rtp_get_payload_type(AVFormatContext *fmt, AVCodecParameters *par, int idx) { int i; - AVOutputFormat *ofmt = fmt ? fmt->oformat : NULL; + const AVOutputFormat *ofmt = fmt ? fmt->oformat : NULL; /* Was the payload type already specified for the RTP muxer? */ if (ofmt && ofmt->priv_class && fmt->priv_data) { diff --git a/libavformat/rtpdec.h b/libavformat/rtpdec.h index 5a47d6f79..9144edbe8 100644 --- a/libavformat/rtpdec.h +++ b/libavformat/rtpdec.h @@ -154,7 +154,6 @@ struct RTPDemuxContext { uint16_t seq; uint32_t timestamp; uint32_t base_timestamp; - uint32_t cur_timestamp; int64_t unwrapped_timestamp; int64_t range_start_offset; int max_payload_size; diff --git a/libavformat/rtpdec_asf.c b/libavformat/rtpdec_asf.c index 54ffef687..e58f0260f 100644 --- a/libavformat/rtpdec_asf.c +++ b/libavformat/rtpdec_asf.c @@ -106,7 +106,7 @@ int ff_wms_parse_sdp_a_line(AVFormatContext *s, const char *p) AVDictionary *opts = NULL; int len = strlen(p) * 6 / 8; char *buf = av_mallocz(len); - AVInputFormat *iformat; + ff_const59 AVInputFormat *iformat; if (!buf) return AVERROR(ENOMEM); diff --git a/libavformat/rtpenc_chain.c b/libavformat/rtpenc_chain.c index e69fdc27c..e6b603db7 100644 --- a/libavformat/rtpenc_chain.c +++ b/libavformat/rtpenc_chain.c @@ -31,7 +31,7 @@ int ff_rtp_chain_mux_open(AVFormatContext **out, AVFormatContext *s, { AVFormatContext *rtpctx = NULL; int ret; - AVOutputFormat *rtp_format = av_guess_format("rtp", NULL, NULL); + ff_const59 AVOutputFormat *rtp_format = av_guess_format("rtp", NULL, NULL); uint8_t *rtpflags; AVDictionary *opts = NULL; @@ -58,7 +58,8 @@ int ff_rtp_chain_mux_open(AVFormatContext **out, AVFormatContext *s, rtpctx->max_delay = s->max_delay; /* Copy other stream parameters. */ rtpctx->streams[0]->sample_aspect_ratio = st->sample_aspect_ratio; - rtpctx->flags |= s->flags & (AVFMT_FLAG_MP4A_LATM | AVFMT_FLAG_BITEXACT); + rtpctx->flags |= s->flags & AVFMT_FLAG_BITEXACT; + rtpctx->strict_std_compliance = s->strict_std_compliance; /* Get the payload type from the codec */ if (st->id < RTP_PT_PRIVATE) diff --git a/libavformat/rtpenc_mpegts.c b/libavformat/rtpenc_mpegts.c index 5f81e1a14..969dbff3d 100644 --- a/libavformat/rtpenc_mpegts.c +++ b/libavformat/rtpenc_mpegts.c @@ -48,8 +48,8 @@ static int rtp_mpegts_write_header(AVFormatContext *s) { struct MuxChain *chain = s->priv_data; AVFormatContext *mpegts_ctx = NULL, *rtp_ctx = NULL; - AVOutputFormat *mpegts_format = av_guess_format("mpegts", NULL, NULL); - AVOutputFormat *rtp_format = av_guess_format("rtp", NULL, NULL); + ff_const59 AVOutputFormat *mpegts_format = av_guess_format("mpegts", NULL, NULL); + ff_const59 AVOutputFormat *rtp_format = av_guess_format("rtp", NULL, NULL); int i, ret = AVERROR(ENOMEM); AVStream *st; diff --git a/libavformat/rtpproto.c b/libavformat/rtpproto.c index c01d9cea1..1f0a82ac7 100644 --- a/libavformat/rtpproto.c +++ b/libavformat/rtpproto.c @@ -32,6 +32,7 @@ #include "rtp.h" #include "rtpproto.h" #include "url.h" +#include "ip.h" #include #include "internal.h" @@ -39,14 +40,14 @@ #include "os_support.h" #include #if HAVE_POLL_H -#include +#include #endif typedef struct RTPContext { const AVClass *class; URLContext *rtp_hd, *rtcp_hd, *fec_hd; - int rtp_fd, rtcp_fd, nb_ssm_include_addrs, nb_ssm_exclude_addrs; - struct sockaddr_storage **ssm_include_addrs, **ssm_exclude_addrs; + int rtp_fd, rtcp_fd; + IPSourceFilters filters; int write_to_source; struct sockaddr_storage last_rtp_source, last_rtcp_source; socklen_t last_rtp_source_len, last_rtcp_source_len; @@ -126,45 +127,6 @@ int ff_rtp_set_remote_url(URLContext *h, const char *uri) return 0; } -static struct addrinfo* rtp_resolve_host(const char *hostname, int port, - int type, int family, int flags) -{ - struct addrinfo hints = { 0 }, *res = 0; - int error; - char service[16]; - - snprintf(service, sizeof(service), "%d", port); - hints.ai_socktype = type; - hints.ai_family = family; - hints.ai_flags = flags; - if ((error = getaddrinfo(hostname, service, &hints, &res))) { - res = NULL; - av_log(NULL, AV_LOG_ERROR, "rtp_resolve_host: %s\n", gai_strerror(error)); - } - - return res; -} - -static int compare_addr(const struct sockaddr_storage *a, - const struct sockaddr_storage *b) -{ - if (a->ss_family != b->ss_family) - return 1; - if (a->ss_family == AF_INET) { - return (((const struct sockaddr_in *)a)->sin_addr.s_addr != - ((const struct sockaddr_in *)b)->sin_addr.s_addr); - } - -#if HAVE_STRUCT_SOCKADDR_IN6 - if (a->ss_family == AF_INET6) { - const uint8_t *s6_addr_a = ((const struct sockaddr_in6 *)a)->sin6_addr.s6_addr; - const uint8_t *s6_addr_b = ((const struct sockaddr_in6 *)b)->sin6_addr.s6_addr; - return memcmp(s6_addr_a, s6_addr_b, 16); - } -#endif - return 1; -} - static int get_port(const struct sockaddr_storage *ss) { if (ss->ss_family == AF_INET) @@ -186,25 +148,6 @@ static void set_port(struct sockaddr_storage *ss, int port) #endif } -static int rtp_check_source_lists(RTPContext *s, struct sockaddr_storage *source_addr_ptr) -{ - int i; - if (s->nb_ssm_exclude_addrs) { - for (i = 0; i < s->nb_ssm_exclude_addrs; i++) { - if (!compare_addr(source_addr_ptr, s->ssm_exclude_addrs[i])) - return 1; - } - } - if (s->nb_ssm_include_addrs) { - for (i = 0; i < s->nb_ssm_include_addrs; i++) { - if (!compare_addr(source_addr_ptr, s->ssm_include_addrs[i])) - return 0; - } - return 1; - } - return 0; -} - /** * add option to url of the form: * "http://host:port/path?option1=val1&option2=val2... @@ -252,48 +195,6 @@ static void build_udp_url(RTPContext *s, url_add_option(buf, buf_size, "block=%s", exclude_sources); } -static void rtp_parse_addr_list(URLContext *h, char *buf, - struct sockaddr_storage ***address_list_ptr, - int *address_list_size_ptr) -{ - struct addrinfo *ai = NULL; - struct sockaddr_storage *source_addr; - char tmp = '\0', *p = buf, *next; - - /* Resolve all of the IPs */ - - while (p && p[0]) { - next = strchr(p, ','); - - if (next) { - tmp = *next; - *next = '\0'; - } - - ai = rtp_resolve_host(p, 0, SOCK_DGRAM, AF_UNSPEC, 0); - if (ai) { - source_addr = av_mallocz(sizeof(struct sockaddr_storage)); - if (!source_addr) { - freeaddrinfo(ai); - break; - } - - memcpy(source_addr, ai->ai_addr, ai->ai_addrlen); - freeaddrinfo(ai); - dynarray_add(address_list_ptr, address_list_size_ptr, source_addr); - } else { - av_log(h, AV_LOG_WARNING, "Unable to resolve %s\n", p); - } - - if (next) { - *next = tmp; - p = next + 1; - } else { - p = NULL; - } - } -} - /** * url syntax: rtp://host:port[?option=val...] * option: 'ttl=n' : set the ttl value (for multicast only) @@ -366,17 +267,16 @@ static int rtp_open(URLContext *h, const char *uri, int flags) } if (av_find_info_tag(buf, sizeof(buf), "sources", p)) { av_strlcpy(include_sources, buf, sizeof(include_sources)); - - rtp_parse_addr_list(h, buf, &s->ssm_include_addrs, &s->nb_ssm_include_addrs); + ff_ip_parse_sources(h, buf, &s->filters); } else { - rtp_parse_addr_list(h, s->sources, &s->ssm_include_addrs, &s->nb_ssm_include_addrs); + ff_ip_parse_sources(h, s->sources, &s->filters); sources = s->sources; } if (av_find_info_tag(buf, sizeof(buf), "block", p)) { av_strlcpy(exclude_sources, buf, sizeof(exclude_sources)); - rtp_parse_addr_list(h, buf, &s->ssm_exclude_addrs, &s->nb_ssm_exclude_addrs); + ff_ip_parse_blocks(h, buf, &s->filters); } else { - rtp_parse_addr_list(h, s->block, &s->ssm_exclude_addrs, &s->nb_ssm_exclude_addrs); + ff_ip_parse_blocks(h, s->block, &s->filters); block = s->block; } } @@ -500,7 +400,7 @@ static int rtp_read(URLContext *h, uint8_t *buf, int size) continue; return AVERROR(EIO); } - if (rtp_check_source_lists(s, addrs[i])) + if (ff_ip_check_source_lists(addrs[i], &s->filters)) continue; return len; } @@ -603,14 +503,8 @@ static int rtp_write(URLContext *h, const uint8_t *buf, int size) static int rtp_close(URLContext *h) { RTPContext *s = h->priv_data; - int i; - for (i = 0; i < s->nb_ssm_include_addrs; i++) - av_freep(&s->ssm_include_addrs[i]); - av_freep(&s->ssm_include_addrs); - for (i = 0; i < s->nb_ssm_exclude_addrs; i++) - av_freep(&s->ssm_exclude_addrs[i]); - av_freep(&s->ssm_exclude_addrs); + ff_ip_reset_filters(&s->filters); ffurl_close(s->rtp_hd); ffurl_close(s->rtcp_hd); diff --git a/libavformat/rtsp.c b/libavformat/rtsp.c index 975637cf5..c153cac88 100644 --- a/libavformat/rtsp.c +++ b/libavformat/rtsp.c @@ -76,7 +76,8 @@ #define COMMON_OPTS() \ { "reorder_queue_size", "set number of packets to buffer for handling of reordered packets", OFFSET(reordering_queue_size), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, DEC }, \ - { "buffer_size", "Underlying protocol send/receive buffer size", OFFSET(buffer_size), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, DEC|ENC } \ + { "buffer_size", "Underlying protocol send/receive buffer size", OFFSET(buffer_size), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, DEC|ENC }, \ + { "pkt_size", "Underlying protocol send packet size", OFFSET(pkt_size), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, ENC } \ const AVOption ff_rtsp_options[] = { @@ -87,6 +88,7 @@ const AVOption ff_rtsp_options[] = { { "tcp", "TCP", 0, AV_OPT_TYPE_CONST, {.i64 = 1 << RTSP_LOWER_TRANSPORT_TCP}, 0, 0, DEC|ENC, "rtsp_transport" }, \ { "udp_multicast", "UDP multicast", 0, AV_OPT_TYPE_CONST, {.i64 = 1 << RTSP_LOWER_TRANSPORT_UDP_MULTICAST}, 0, 0, DEC, "rtsp_transport" }, { "http", "HTTP tunneling", 0, AV_OPT_TYPE_CONST, {.i64 = (1 << RTSP_LOWER_TRANSPORT_HTTP)}, 0, 0, DEC, "rtsp_transport" }, + { "https", "HTTPS tunneling", 0, AV_OPT_TYPE_CONST, {.i64 = (1 << RTSP_LOWER_TRANSPORT_HTTPS )}, 0, 0, DEC, "rtsp_transport" }, RTSP_FLAG_OPTS("rtsp_flags", "set RTSP flags"), { "listen", "wait for incoming connections", 0, AV_OPT_TYPE_CONST, {.i64 = RTSP_FLAG_LISTEN}, 0, 0, DEC, "rtsp_flags" }, { "prefer_tcp", "try RTP via TCP first, if available", 0, AV_OPT_TYPE_CONST, {.i64 = RTSP_FLAG_PREFER_TCP}, 0, 0, DEC|ENC, "rtsp_flags" }, @@ -131,6 +133,8 @@ static AVDictionary *map_to_opts(RTSPState *rt) snprintf(buf, sizeof(buf), "%d", rt->buffer_size); av_dict_set(&opts, "buffer_size", buf, 0); + snprintf(buf, sizeof(buf), "%d", rt->pkt_size); + av_dict_set(&opts, "pkt_size", buf, 0); return opts; } @@ -1669,6 +1673,7 @@ int ff_rtsp_connect(AVFormatContext *s) RTSPMessageHeader reply1, *reply = &reply1; int lower_transport_mask = 0; int default_port = RTSP_DEFAULT_PORT; + int https_tunnel = 0; char real_challenge[64] = ""; struct sockaddr_storage peer; socklen_t peer_len = sizeof(peer); @@ -1687,7 +1692,9 @@ int ff_rtsp_connect(AVFormatContext *s) s->max_delay = s->iformat ? DEFAULT_REORDERING_DELAY : 0; rt->control_transport = RTSP_MODE_PLAIN; - if (rt->lower_transport_mask & (1 << RTSP_LOWER_TRANSPORT_HTTP)) { + if (rt->lower_transport_mask & ((1 << RTSP_LOWER_TRANSPORT_HTTP) | + (1 << RTSP_LOWER_TRANSPORT_HTTPS))) { + https_tunnel = !!(rt->lower_transport_mask & (1 << RTSP_LOWER_TRANSPORT_HTTPS)); rt->lower_transport_mask = 1 << RTSP_LOWER_TRANSPORT_TCP; rt->control_transport = RTSP_MODE_TUNNEL; } @@ -1740,8 +1747,11 @@ redirect: char httpname[1024]; char sessioncookie[17]; char headers[1024]; + AVDictionary *options = NULL; - ff_url_join(httpname, sizeof(httpname), "http", auth, host, port, "%s", path); + av_dict_set_int(&options, "timeout", rt->stimeout, 0); + + ff_url_join(httpname, sizeof(httpname), https_tunnel ? "https" : "http", auth, host, port, "%s", path); snprintf(sessioncookie, sizeof(sessioncookie), "%08x%08x", av_get_random_seed(), av_get_random_seed()); @@ -1770,7 +1780,8 @@ redirect: } /* complete the connection */ - if (ffurl_connect(rt->rtsp_hd, NULL)) { + if (ffurl_connect(rt->rtsp_hd, &options)) { + av_dict_free(&options); err = AVERROR(EIO); goto fail; } @@ -1793,6 +1804,7 @@ redirect: sessioncookie); av_opt_set(rt->rtsp_hd_out->priv_data, "headers", headers, 0); av_opt_set(rt->rtsp_hd_out->priv_data, "chunked_post", "0", 0); + av_opt_set(rt->rtsp_hd_out->priv_data, "send_expect_100", "0", 0); /* Initialize the authentication state for the POST session. The HTTP * protocol implementation doesn't properly handle multi-pass @@ -1813,10 +1825,12 @@ redirect: ff_http_init_auth_state(rt->rtsp_hd_out, rt->rtsp_hd); /* complete the connection */ - if (ffurl_connect(rt->rtsp_hd_out, NULL)) { + if (ffurl_connect(rt->rtsp_hd_out, &options)) { + av_dict_free(&options); err = AVERROR(EIO); goto fail; } + av_dict_free(&options); } else { int ret; /* open the tcp connection */ @@ -2281,7 +2295,7 @@ end: #endif /* CONFIG_RTPDEC */ #if CONFIG_SDP_DEMUXER -static int sdp_probe(AVProbeData *p1) +static int sdp_probe(const AVProbeData *p1) { const char *p = p1->buf, *p_end = p1->buf + p1->buf_size; @@ -2420,7 +2434,7 @@ AVInputFormat ff_sdp_demuxer = { #endif /* CONFIG_SDP_DEMUXER */ #if CONFIG_RTP_DEMUXER -static int rtp_probe(AVProbeData *p) +static int rtp_probe(const AVProbeData *p) { if (av_strstart(p->filename, "rtp:", NULL)) return AVPROBE_SCORE_MAX; diff --git a/libavformat/rtsp.h b/libavformat/rtsp.h index 9a7f366b3..54a9a30c1 100644 --- a/libavformat/rtsp.h +++ b/libavformat/rtsp.h @@ -42,6 +42,7 @@ enum RTSPLowerTransport { RTSP_LOWER_TRANSPORT_HTTP = 8, /**< HTTP tunneled - not a proper transport mode as such, only for use via AVOptions */ + RTSP_LOWER_TRANSPORT_HTTPS, /**< HTTPS tunneled */ RTSP_LOWER_TRANSPORT_CUSTOM = 16, /**< Custom IO - not a public option for lower_transport_mask, but set in the SDP demuxer based @@ -409,6 +410,7 @@ typedef struct RTSPState { char default_lang[4]; int buffer_size; + int pkt_size; } RTSPState; #define RTSP_FLAG_FILTER_SRC 0x1 /**< Filter incoming UDP packets - diff --git a/libavformat/rtspdec.c b/libavformat/rtspdec.c index 32dff2319..bd2e8f47f 100644 --- a/libavformat/rtspdec.c +++ b/libavformat/rtspdec.c @@ -699,7 +699,7 @@ static int rtsp_listen(AVFormatContext *s) } } -static int rtsp_probe(AVProbeData *p) +static int rtsp_probe(const AVProbeData *p) { if ( #if CONFIG_TLS_PROTOCOL diff --git a/libavformat/s337m.c b/libavformat/s337m.c index 2e85d487b..48ab66a6d 100644 --- a/libavformat/s337m.c +++ b/libavformat/s337m.c @@ -82,7 +82,7 @@ static int s337m_get_offset_and_codec(AVFormatContext *s, return 0; } -static int s337m_probe(AVProbeData *p) +static int s337m_probe(const AVProbeData *p) { uint64_t state = 0; int markers[3] = { 0 }; diff --git a/libavformat/samidec.c b/libavformat/samidec.c index 7ea1bdfdd..fd9839308 100644 --- a/libavformat/samidec.c +++ b/libavformat/samidec.c @@ -36,7 +36,7 @@ typedef struct { FFDemuxSubtitlesQueue q; } SAMIContext; -static int sami_probe(AVProbeData *p) +static int sami_probe(const AVProbeData *p) { char buf[6]; FFTextReader tr; diff --git a/libavformat/sapdec.c b/libavformat/sapdec.c index 7a6c8bf17..eddeddeae 100644 --- a/libavformat/sapdec.c +++ b/libavformat/sapdec.c @@ -42,7 +42,7 @@ struct SAPState { int eof; }; -static int sap_probe(AVProbeData *p) +static int sap_probe(const AVProbeData *p) { if (av_strstart(p->filename, "sap:", NULL)) return AVPROBE_SCORE_MAX; @@ -68,7 +68,7 @@ static int sap_read_header(AVFormatContext *s) uint8_t recvbuf[RTP_MAX_PACKET_LENGTH]; int port; int ret, i; - AVInputFormat* infmt; + ff_const59 AVInputFormat* infmt; if (!ff_network_init()) return AVERROR(EIO); diff --git a/libavformat/sbcdec.c b/libavformat/sbcdec.c index ae74a220d..7a455ce12 100644 --- a/libavformat/sbcdec.c +++ b/libavformat/sbcdec.c @@ -22,6 +22,7 @@ #include "avformat.h" #include "rawdec.h" +FF_RAW_DEMUXER_CLASS(sbc) AVInputFormat ff_sbc_demuxer = { .name = "sbc", .long_name = NULL_IF_CONFIG_SMALL("raw SBC (low-complexity subband codec)"), @@ -30,4 +31,6 @@ AVInputFormat ff_sbc_demuxer = { .read_header = ff_raw_audio_read_header, .read_packet = ff_raw_read_partial_packet, .flags = AVFMT_GENERIC_INDEX, + .priv_data_size = sizeof(FFRawDemuxerContext), + .priv_class = &sbc_demuxer_class, }; diff --git a/libavformat/sbgdec.c b/libavformat/sbgdec.c index cbedd120f..4155395da 100644 --- a/libavformat/sbgdec.c +++ b/libavformat/sbgdec.c @@ -197,7 +197,7 @@ static int str_to_time(const char *str, int64_t *rtime) if (end > cur + 1) cur = end; } - *rtime = (hours * 3600 + minutes * 60 + seconds) * AV_TIME_BASE; + *rtime = (hours * 3600LL + minutes * 60LL + seconds) * AV_TIME_BASE; return cur - str; } @@ -1367,7 +1367,7 @@ static int encode_intervals(struct sbg_script *s, AVCodecParameters *par, return 0; } -static av_cold int sbg_read_probe(AVProbeData *p) +static av_cold int sbg_read_probe(const AVProbeData *p) { int r, score; struct sbg_script script = { 0 }; diff --git a/libavformat/sccdec.c b/libavformat/sccdec.c index 89d21b9c1..412d8aaf4 100644 --- a/libavformat/sccdec.c +++ b/libavformat/sccdec.c @@ -29,7 +29,7 @@ typedef struct SCCContext { FFDemuxSubtitlesQueue q; } SCCContext; -static int scc_probe(AVProbeData *p) +static int scc_probe(const AVProbeData *p) { char buf[18]; FFTextReader tr; @@ -110,6 +110,7 @@ static int scc_read_header(AVFormatContext *s) ts_end = (hh2 * 3600LL + mm2 * 60LL + ss2) * 1000LL + fs2 * 33; count++; +try_again: lline = (char *)&line; lline += 12; @@ -138,9 +139,13 @@ static int scc_read_header(AVFormatContext *s) sub->pts = ts_start; sub->duration = FFMAX(1200, ts_end - ts_start); memmove(line, line2, sizeof(line)); + line2[0] = 0; FFSWAP(ptrdiff_t, len, len2); } + if (line[0]) + goto try_again; + ff_subtitles_queue_finalize(s, &scc->q); return ret; diff --git a/libavformat/sdp.c b/libavformat/sdp.c index a5d202e99..34e9839b6 100644 --- a/libavformat/sdp.c +++ b/libavformat/sdp.c @@ -347,7 +347,8 @@ static char *extradata2config(AVFormatContext *s, AVCodecParameters *par) static char *xiph_extradata2config(AVFormatContext *s, AVCodecParameters *par) { - char *config, *encoded_config; + uint8_t *config; + char *encoded_config; const uint8_t *header_start[3]; int headers_len, header_len[3], config_len; int first_header_size; diff --git a/libavformat/sdr2.c b/libavformat/sdr2.c index c9953336c..50abdf939 100644 --- a/libavformat/sdr2.c +++ b/libavformat/sdr2.c @@ -23,7 +23,7 @@ #include "avformat.h" #include "internal.h" -static int sdr2_probe(AVProbeData *p) +static int sdr2_probe(const AVProbeData *p) { if (AV_RL32(p->buf) != MKTAG('S', 'R', 'A', 1)) return 0; diff --git a/libavformat/sdsdec.c b/libavformat/sdsdec.c index 081bb4ca2..9c361cdff 100644 --- a/libavformat/sdsdec.c +++ b/libavformat/sdsdec.c @@ -30,7 +30,7 @@ typedef struct SDSContext { void (*read_block)(const uint8_t *src, uint32_t *dst); } SDSContext; -static int sds_probe(AVProbeData *p) +static int sds_probe(const AVProbeData *p) { if (AV_RB32(p->buf) == 0xF07E0001 && p->buf[20] == 0xF7 && p->buf[6] >= 8 && p->buf[6] <= 28) diff --git a/libavformat/sdxdec.c b/libavformat/sdxdec.c index e8e7a4f88..19651048a 100644 --- a/libavformat/sdxdec.c +++ b/libavformat/sdxdec.c @@ -25,7 +25,7 @@ #include "internal.h" #include "pcm.h" -static int sdx_probe(AVProbeData *p) +static int sdx_probe(const AVProbeData *p) { if (AV_RB32(p->buf) == AV_RB32("SDX:")) return AVPROBE_SCORE_EXTENSION; diff --git a/libavformat/segafilm.c b/libavformat/segafilm.c index b0c6c419c..777606bcb 100644 --- a/libavformat/segafilm.c +++ b/libavformat/segafilm.c @@ -64,7 +64,7 @@ typedef struct FilmDemuxContext { unsigned int version; } FilmDemuxContext; -static int film_probe(AVProbeData *p) +static int film_probe(const AVProbeData *p) { if (AV_RB32(&p->buf[0]) != FILM_TAG) return 0; diff --git a/libavformat/segafilmenc.c b/libavformat/segafilmenc.c index 5b0d7e69e..524230e46 100644 --- a/libavformat/segafilmenc.c +++ b/libavformat/segafilmenc.c @@ -69,7 +69,7 @@ static int film_write_packet_to_header(AVFormatContext *format_context, FILMPack info1 = pkt->pts; info2 = pkt->duration; /* The top bit being set indicates a key frame */ - if (pkt->keyframe) + if (!pkt->keyframe) info1 |= (1 << 31); } diff --git a/libavformat/segment.c b/libavformat/segment.c index 7fb4dc7d2..e3082063d 100644 --- a/libavformat/segment.c +++ b/libavformat/segment.c @@ -72,7 +72,7 @@ typedef struct SegmentContext { int segment_idx_wrap; ///< number after which the index wraps int segment_idx_wrap_nb; ///< number of time the index has wraped int segment_count; ///< number of segment files already written - AVOutputFormat *oformat; + ff_const59 AVOutputFormat *oformat; AVFormatContext *avf; char *format; ///< format to use for output segment files char *format_options_str; ///< format options to use for output segment files @@ -180,6 +180,13 @@ static int segment_mux_init(AVFormatContext *s) } st->sample_aspect_ratio = s->streams[i]->sample_aspect_ratio; st->time_base = s->streams[i]->time_base; + st->avg_frame_rate = s->streams[i]->avg_frame_rate; +#if FF_API_LAVF_AVCTX +FF_DISABLE_DEPRECATION_WARNINGS + if (s->streams[i]->codecpar->codec_tag == MKTAG('t','m','c','d')) + st->codec->time_base = s->streams[i]->codec->time_base; +FF_ENABLE_DEPRECATION_WARNINGS +#endif av_dict_copy(&st->metadata, s->streams[i]->metadata, 0); } @@ -421,7 +428,7 @@ static int segment_end(AVFormatContext *s, int write_trailer, int is_last) rate = s->streams[i]->avg_frame_rate;/* Get fps from the video stream */ err = av_timecode_init_from_string(&tc, rate, tcr->value, s); if (err < 0) { - av_log(s, AV_LOG_WARNING, "Could not increment timecode, error occurred during timecode creation."); + av_log(s, AV_LOG_WARNING, "Could not increment global timecode, error occurred during timecode creation.\n"); break; } tc.start += (int)((seg->cur_entry.end_time - seg->cur_entry.start_time) * av_q2d(rate));/* increment timecode */ @@ -431,7 +438,23 @@ static int segment_end(AVFormatContext *s, int write_trailer, int is_last) } } } else { - av_log(s, AV_LOG_WARNING, "Could not increment timecode, no timecode metadata found"); + av_log(s, AV_LOG_WARNING, "Could not increment global timecode, no global timecode metadata found.\n"); + } + for (i = 0; i < s->nb_streams; i++) { + if (s->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { + char st_buf[AV_TIMECODE_STR_SIZE]; + AVTimecode st_tc; + AVRational st_rate = s->streams[i]->avg_frame_rate; + AVDictionaryEntry *st_tcr = av_dict_get(s->streams[i]->metadata, "timecode", NULL, 0); + if (st_tcr) { + if ((av_timecode_init_from_string(&st_tc, st_rate, st_tcr->value, s) < 0)) { + av_log(s, AV_LOG_WARNING, "Could not increment stream %d timecode, error occurred during timecode creation.\n", i); + continue; + } + st_tc.start += (int)((seg->cur_entry.end_time - seg->cur_entry.start_time) * av_q2d(st_rate)); // increment timecode + av_dict_set(&s->streams[i]->metadata, "timecode", av_timecode_make_string(&st_tc, st_buf, 0), 0); + } + } } } @@ -859,6 +882,20 @@ static int seg_write_packet(AVFormatContext *s, AVPacket *pkt) if (!seg->avf || !seg->avf->pb) return AVERROR(EINVAL); + if (!st->codecpar->extradata_size) { + int pkt_extradata_size = 0; + uint8_t *pkt_extradata = av_packet_get_side_data(pkt, AV_PKT_DATA_NEW_EXTRADATA, &pkt_extradata_size); + if (pkt_extradata && pkt_extradata_size > 0) { + ret = ff_alloc_extradata(st->codecpar, pkt_extradata_size); + if (ret < 0) { + av_log(s, AV_LOG_WARNING, "Unable to add extradata to stream. Output segments may be invalid.\n"); + goto calc_times; + } + memcpy(st->codecpar->extradata, pkt_extradata, pkt_extradata_size); + st->codecpar->extradata_size = pkt_extradata_size; + } + } + calc_times: if (seg->times) { end_pts = seg->segment_count < seg->nb_times ? @@ -1045,7 +1082,7 @@ static const AVOption options[] = { { "segment_clocktime_offset", "set segment clocktime offset", OFFSET(clocktime_offset), AV_OPT_TYPE_DURATION, {.i64 = 0}, 0, 86400000000LL, E}, { "segment_clocktime_wrap_duration", "set segment clocktime wrapping duration", OFFSET(clocktime_wrap_duration), AV_OPT_TYPE_DURATION, {.i64 = INT64_MAX}, 0, INT64_MAX, E}, { "segment_time", "set segment duration", OFFSET(time_str),AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E }, - { "segment_time_delta","set approximation value used for the segment times", OFFSET(time_delta), AV_OPT_TYPE_DURATION, {.i64 = 0}, 0, 0, E }, + { "segment_time_delta","set approximation value used for the segment times", OFFSET(time_delta), AV_OPT_TYPE_DURATION, {.i64 = 0}, 0, INT64_MAX, E }, { "segment_times", "set segment split time points", OFFSET(times_str),AV_OPT_TYPE_STRING,{.str = NULL}, 0, 0, E }, { "segment_frames", "set segment split frame numbers", OFFSET(frames_str),AV_OPT_TYPE_STRING,{.str = NULL}, 0, 0, E }, { "segment_wrap", "set number after which the index wraps", OFFSET(segment_idx_wrap), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, E }, diff --git a/libavformat/serdec.c b/libavformat/serdec.c new file mode 100644 index 000000000..5745ae143 --- /dev/null +++ b/libavformat/serdec.c @@ -0,0 +1,146 @@ +/* + * SER demuxer + * Copyright (c) 2018 Paul B Mahol + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/imgutils.h" +#include "libavutil/parseutils.h" +#include "libavutil/pixdesc.h" +#include "libavutil/opt.h" +#include "internal.h" +#include "avformat.h" + +#define SER_MAGIC "LUCAM-RECORDER" + +typedef struct SERDemuxerContext { + const AVClass *class; + int width, height; + AVRational framerate; + int64_t end; +} SERDemuxerContext; + +static int ser_probe(const AVProbeData *pd) +{ + if (memcmp(pd->buf, SER_MAGIC, 14) == 0) + return AVPROBE_SCORE_MAX; + else + return 0; +} + +static int ser_read_header(AVFormatContext *s) +{ + SERDemuxerContext *ser = s->priv_data; + enum AVPixelFormat pix_fmt; + int depth, color_id, endian; + int packet_size; + AVStream *st; + + st = avformat_new_stream(s, NULL); + if (!st) + return AVERROR(ENOMEM); + + avio_skip(s->pb, 14); + avio_skip(s->pb, 4); + color_id = avio_rl32(s->pb); + endian = avio_rl32(s->pb); + ser->width = avio_rl32(s->pb); + ser->height = avio_rl32(s->pb); + depth = avio_rl32(s->pb); + st->nb_frames = st->duration = avio_rl32(s->pb); + avio_skip(s->pb, 120); + avio_skip(s->pb, 8); + avio_skip(s->pb, 8); + + switch (color_id) { + case 0: pix_fmt = depth <= 8 ? AV_PIX_FMT_GRAY8 : endian ? AV_PIX_FMT_GRAY16LE : AV_PIX_FMT_GRAY16BE; break; + case 8: pix_fmt = depth <= 8 ? AV_PIX_FMT_BAYER_RGGB8 : endian ? AV_PIX_FMT_BAYER_RGGB16LE : AV_PIX_FMT_BAYER_RGGB16BE; break; + case 9: pix_fmt = depth <= 8 ? AV_PIX_FMT_BAYER_GRBG8 : endian ? AV_PIX_FMT_BAYER_GRBG16LE : AV_PIX_FMT_BAYER_GRBG16BE; break; + case 10: pix_fmt = depth <= 8 ? AV_PIX_FMT_BAYER_GBRG8 : endian ? AV_PIX_FMT_BAYER_GBRG16LE : AV_PIX_FMT_BAYER_GBRG16BE; break; + case 11: pix_fmt = depth <= 8 ? AV_PIX_FMT_BAYER_BGGR8 : endian ? AV_PIX_FMT_BAYER_BGGR16LE : AV_PIX_FMT_BAYER_BGGR16BE; break; + case 100: pix_fmt = depth <= 8 ? AV_PIX_FMT_RGB24 : endian ? AV_PIX_FMT_RGB48LE : AV_PIX_FMT_RGB48BE; break; + case 101: pix_fmt = depth <= 8 ? AV_PIX_FMT_BGR24 : endian ? AV_PIX_FMT_BGR48LE : AV_PIX_FMT_BGR48BE; break; + default: + return AVERROR_PATCHWELCOME; + } + + st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO; + st->codecpar->codec_id = s->iformat->raw_codec_id; + + avpriv_set_pts_info(st, 64, ser->framerate.den, ser->framerate.num); + + st->codecpar->width = ser->width; + st->codecpar->height = ser->height; + st->codecpar->format = pix_fmt; + packet_size = av_image_get_buffer_size(st->codecpar->format, ser->width, ser->height, 1); + if (packet_size < 0) + return packet_size; + ser->end = 178 + st->nb_frames * packet_size; + s->packet_size = packet_size; + st->codecpar->bit_rate = av_rescale_q(s->packet_size, + (AVRational){8,1}, st->time_base); + + return 0; +} + + +static int ser_read_packet(AVFormatContext *s, AVPacket *pkt) +{ + SERDemuxerContext *ser = s->priv_data; + int64_t pos; + int ret; + + pos = avio_tell(s->pb); + if (pos >= ser->end) + return AVERROR_EOF; + + ret = av_get_packet(s->pb, pkt, s->packet_size); + pkt->pts = pkt->dts = (pkt->pos - s->internal->data_offset) / s->packet_size; + + pkt->stream_index = 0; + if (ret < 0) + return ret; + return 0; +} + +#define OFFSET(x) offsetof(SERDemuxerContext, x) +#define DEC AV_OPT_FLAG_DECODING_PARAM +static const AVOption ser_options[] = { + { "framerate", "set frame rate", OFFSET(framerate), AV_OPT_TYPE_VIDEO_RATE, {.str = "25"}, 0, INT_MAX, DEC }, + { NULL }, +}; + +static const AVClass ser_demuxer_class = { + .class_name = "ser demuxer", + .item_name = av_default_item_name, + .option = ser_options, + .version = LIBAVUTIL_VERSION_INT, +}; + +AVInputFormat ff_ser_demuxer = { + .name = "ser", + .long_name = NULL_IF_CONFIG_SMALL("SER (Simple uncompressed video format for astronomical capturing)"), + .priv_data_size = sizeof(SERDemuxerContext), + .read_probe = ser_probe, + .read_header = ser_read_header, + .read_packet = ser_read_packet, + .flags = AVFMT_GENERIC_INDEX, + .extensions = "ser", + .raw_codec_id = AV_CODEC_ID_RAWVIDEO, + .priv_class = &ser_demuxer_class, +}; diff --git a/libavformat/shortendec.c b/libavformat/shortendec.c index 42fcdf75c..a2879dc5a 100644 --- a/libavformat/shortendec.c +++ b/libavformat/shortendec.c @@ -25,7 +25,7 @@ #include "rawdec.h" #include "libavcodec/golomb.h" -static int shn_probe(AVProbeData *p) +static int shn_probe(const AVProbeData *p) { GetBitContext gb; int version, internal_ftype, channels, blocksize; @@ -59,6 +59,7 @@ static int shn_probe(AVProbeData *p) return AVPROBE_SCORE_EXTENSION + 1; } +FF_RAW_DEMUXER_CLASS(shorten) AVInputFormat ff_shorten_demuxer = { .name = "shn", .long_name = NULL_IF_CONFIG_SMALL("raw Shorten"), @@ -68,4 +69,6 @@ AVInputFormat ff_shorten_demuxer = { .flags = AVFMT_NOBINSEARCH | AVFMT_NOGENSEARCH | AVFMT_NO_BYTE_SEEK | AVFMT_NOTIMESTAMPS, .extensions = "shn", .raw_codec_id = AV_CODEC_ID_SHORTEN, + .priv_data_size = sizeof(FFRawDemuxerContext), + .priv_class = &shorten_demuxer_class, }; diff --git a/libavformat/sierravmd.c b/libavformat/sierravmd.c index 6960c2868..d586fc6ac 100644 --- a/libavformat/sierravmd.c +++ b/libavformat/sierravmd.c @@ -62,7 +62,7 @@ typedef struct VmdDemuxContext { unsigned char vmd_header[VMD_HEADER_SIZE]; } VmdDemuxContext; -static int vmd_probe(AVProbeData *p) +static int vmd_probe(const AVProbeData *p) { int w, h, sample_rate; if (p->buf_size < 806) diff --git a/libavformat/siff.c b/libavformat/siff.c index ddd171568..24d5ebb42 100644 --- a/libavformat/siff.c +++ b/libavformat/siff.c @@ -62,7 +62,7 @@ typedef struct SIFFContext { uint8_t gmc[4]; } SIFFContext; -static int siff_probe(AVProbeData *p) +static int siff_probe(const AVProbeData *p) { uint32_t tag = AV_RL32(p->buf + 8); /* check file header */ diff --git a/libavformat/smacker.c b/libavformat/smacker.c index 8a21cc076..b5c858aa9 100644 --- a/libavformat/smacker.c +++ b/libavformat/smacker.c @@ -92,7 +92,7 @@ static const uint8_t smk_pal[64] = { }; -static int smacker_probe(AVProbeData *p) +static int smacker_probe(const AVProbeData *p) { if ( AV_RL32(p->buf) != MKTAG('S', 'M', 'K', '2') && AV_RL32(p->buf) != MKTAG('S', 'M', 'K', '4')) diff --git a/libavformat/smjpegdec.c b/libavformat/smjpegdec.c index c184c0d9f..5bc04921f 100644 --- a/libavformat/smjpegdec.c +++ b/libavformat/smjpegdec.c @@ -36,7 +36,7 @@ typedef struct SMJPEGContext { int video_stream_index; } SMJPEGContext; -static int smjpeg_probe(AVProbeData *p) +static int smjpeg_probe(const AVProbeData *p) { if (!memcmp(p->buf, SMJPEG_MAGIC, 8)) return AVPROBE_SCORE_MAX; diff --git a/libavformat/smoothstreamingenc.c b/libavformat/smoothstreamingenc.c index 094712af2..1ed19ebb2 100644 --- a/libavformat/smoothstreamingenc.c +++ b/libavformat/smoothstreamingenc.c @@ -293,7 +293,7 @@ static int ism_write_header(AVFormatContext *s) { SmoothStreamingContext *c = s->priv_data; int ret = 0, i; - AVOutputFormat *oformat; + ff_const59 AVOutputFormat *oformat; if (mkdir(s->url, 0777) == -1 && errno != EEXIST) { ret = AVERROR(errno); @@ -320,11 +320,13 @@ static int ism_write_header(AVFormatContext *s) AVDictionary *opts = NULL; if (!s->streams[i]->codecpar->bit_rate) { - av_log(s, AV_LOG_ERROR, "No bit rate set for stream %d\n", i); - ret = AVERROR(EINVAL); - goto fail; + av_log(s, AV_LOG_WARNING, "No bit rate set for stream %d\n", i); + // create a tmp name for the directory of fragments + snprintf(os->dirname, sizeof(os->dirname), "%s/QualityLevels(Tmp_%d)", s->url, i); + } else { + snprintf(os->dirname, sizeof(os->dirname), "%s/QualityLevels(%"PRId64")", s->url, s->streams[i]->codecpar->bit_rate); } - snprintf(os->dirname, sizeof(os->dirname), "%s/QualityLevels(%"PRId64")", s->url, s->streams[i]->codecpar->bit_rate); + if (mkdir(os->dirname, 0777) == -1 && errno != EEXIST) { ret = AVERROR(errno); av_log(s, AV_LOG_ERROR, "mkdir failed\n"); @@ -519,7 +521,7 @@ static int ism_flush(AVFormatContext *s, int final) for (i = 0; i < s->nb_streams; i++) { OutputStream *os = &c->streams[i]; - char filename[1024], target_filename[1024], header_filename[1024]; + char filename[1024], target_filename[1024], header_filename[1024], curr_dirname[1024]; int64_t size; int64_t start_ts, duration, moof_size; if (!os->packets_written) @@ -541,6 +543,26 @@ static int ism_flush(AVFormatContext *s, int final) size = os->tail_pos - os->cur_start_pos; if ((ret = parse_fragment(s, filename, &start_ts, &duration, &moof_size, size)) < 0) break; + + if (!s->streams[i]->codecpar->bit_rate) { + int64_t bitrate = (int64_t) size * 8 * AV_TIME_BASE / av_rescale_q(duration, s->streams[i]->time_base, AV_TIME_BASE_Q); + if (!bitrate) { + av_log(s, AV_LOG_ERROR, "calculating bitrate got zero.\n"); + ret = AVERROR(EINVAL); + return ret; + } + + av_log(s, AV_LOG_DEBUG, "calculated bitrate: %"PRId64"\n", bitrate); + s->streams[i]->codecpar->bit_rate = bitrate; + memcpy(curr_dirname, os->dirname, sizeof(os->dirname)); + snprintf(os->dirname, sizeof(os->dirname), "%s/QualityLevels(%"PRId64")", s->url, s->streams[i]->codecpar->bit_rate); + snprintf(filename, sizeof(filename), "%s/temp", os->dirname); + + // rename the tmp folder back to the correct name since we now have the bitrate + if ((ret = ff_rename((const char*)curr_dirname, os->dirname, s)) < 0) + return ret; + } + snprintf(header_filename, sizeof(header_filename), "%s/FragmentInfo(%s=%"PRIu64")", os->dirname, os->stream_type_tag, start_ts); snprintf(target_filename, sizeof(target_filename), "%s/Fragments(%s=%"PRIu64")", os->dirname, os->stream_type_tag, start_ts); copy_moof(s, filename, header_filename, moof_size); diff --git a/libavformat/smush.c b/libavformat/smush.c index fe544d876..20352adf9 100644 --- a/libavformat/smush.c +++ b/libavformat/smush.c @@ -31,7 +31,7 @@ typedef struct SMUSHContext { int video_stream_index; } SMUSHContext; -static int smush_read_probe(AVProbeData *p) +static int smush_read_probe(const AVProbeData *p) { if (((AV_RL32(p->buf) == MKTAG('S', 'A', 'N', 'M') && AV_RL32(p->buf + 8) == MKTAG('S', 'H', 'D', 'R')) || diff --git a/libavformat/sol.c b/libavformat/sol.c index 5796f8d23..19905e84f 100644 --- a/libavformat/sol.c +++ b/libavformat/sol.c @@ -32,7 +32,7 @@ /* if we don't know the size in advance */ #define AU_UNKNOWN_SIZE ((uint32_t)(~0)) -static int sol_probe(AVProbeData *p) +static int sol_probe(const AVProbeData *p) { /* check file header */ uint16_t magic = AV_RL32(p->buf); diff --git a/libavformat/soxdec.c b/libavformat/soxdec.c index 12a94c8ff..d3f709f9a 100644 --- a/libavformat/soxdec.c +++ b/libavformat/soxdec.c @@ -37,7 +37,7 @@ #include "pcm.h" #include "sox.h" -static int sox_probe(AVProbeData *p) +static int sox_probe(const AVProbeData *p) { if (AV_RL32(p->buf) == SOX_TAG || AV_RB32(p->buf) == SOX_TAG) return AVPROBE_SCORE_MAX; diff --git a/libavformat/spdifdec.c b/libavformat/spdifdec.c index 21bfce422..d74f58d82 100644 --- a/libavformat/spdifdec.c +++ b/libavformat/spdifdec.c @@ -107,7 +107,7 @@ static int spdif_get_offset_and_codec(AVFormatContext *s, samples = 4096 */ #define SPDIF_MAX_OFFSET 16384 -static int spdif_probe(AVProbeData *p) +static int spdif_probe(const AVProbeData *p) { enum AVCodecID codec; return ff_spdif_probe (p->buf, p->buf_size, &codec); diff --git a/libavformat/spdifenc.c b/libavformat/spdifenc.c index 9514ff8e1..4307942a4 100644 --- a/libavformat/spdifenc.c +++ b/libavformat/spdifenc.c @@ -422,8 +422,13 @@ static int spdif_header_truehd(AVFormatContext *s, AVPacket *pkt) memcpy(&ctx->hd_buf[ctx->hd_buf_count * TRUEHD_FRAME_OFFSET - BURST_HEADER_SIZE + mat_code_length], pkt->data, pkt->size); - memset(&ctx->hd_buf[ctx->hd_buf_count * TRUEHD_FRAME_OFFSET - BURST_HEADER_SIZE + mat_code_length + pkt->size], - 0, TRUEHD_FRAME_OFFSET - pkt->size - mat_code_length); + if (ctx->hd_buf_count < 23) { + memset(&ctx->hd_buf[ctx->hd_buf_count * TRUEHD_FRAME_OFFSET - BURST_HEADER_SIZE + mat_code_length + pkt->size], + 0, TRUEHD_FRAME_OFFSET - pkt->size - mat_code_length); + } else { + size_t padding = MAT_FRAME_SIZE - (ctx->hd_buf_count * TRUEHD_FRAME_OFFSET - BURST_HEADER_SIZE + pkt->size); + memset(&ctx->hd_buf[MAT_FRAME_SIZE - padding], 0, padding); + } if (++ctx->hd_buf_count < 24){ ctx->pkt_offset = 0; diff --git a/libavformat/srtdec.c b/libavformat/srtdec.c index 56bd0c43f..40d324b44 100644 --- a/libavformat/srtdec.c +++ b/libavformat/srtdec.c @@ -30,7 +30,7 @@ typedef struct { FFDemuxSubtitlesQueue q; } SRTContext; -static int srt_probe(AVProbeData *p) +static int srt_probe(const AVProbeData *p) { int v; char buf[64], *pbuf; diff --git a/libavformat/stldec.c b/libavformat/stldec.c index 35de49322..d6e0713f8 100644 --- a/libavformat/stldec.c +++ b/libavformat/stldec.c @@ -34,7 +34,7 @@ typedef struct { FFDemuxSubtitlesQueue q; } STLContext; -static int stl_probe(AVProbeData *p) +static int stl_probe(const AVProbeData *p) { char c; const unsigned char *ptr = p->buf; diff --git a/libavformat/subfile.c b/libavformat/subfile.c index b527f2bee..2f162e0a3 100644 --- a/libavformat/subfile.c +++ b/libavformat/subfile.c @@ -116,11 +116,17 @@ static int subfile_read(URLContext *h, unsigned char *buf, int size) static int64_t subfile_seek(URLContext *h, int64_t pos, int whence) { SubfileContext *c = h->priv_data; - int64_t new_pos = -1; + int64_t new_pos = -1, end; int ret; + if (whence == AVSEEK_SIZE || whence == SEEK_END) { + end = c->end; + if (end == INT64_MAX && (end = ffurl_seek(c->h, 0, AVSEEK_SIZE)) < 0) + return end; + } + if (whence == AVSEEK_SIZE) - return c->end - c->start; + return end - c->start; switch (whence) { case SEEK_SET: new_pos = c->start + pos; @@ -129,7 +135,7 @@ static int64_t subfile_seek(URLContext *h, int64_t pos, int whence) new_pos += pos; break; case SEEK_END: - new_pos = c->end + c->pos; + new_pos = end + c->pos; break; } if (new_pos < c->start) diff --git a/libavformat/subtitles.c b/libavformat/subtitles.c index 93c9ef05c..659c99d1c 100644 --- a/libavformat/subtitles.c +++ b/libavformat/subtitles.c @@ -417,7 +417,7 @@ ptrdiff_t ff_subtitles_read_line(FFTextReader *tr, char *buf, size_t size) buf[cur++] = c; buf[cur] = '\0'; } - if (ff_text_peek_r8(tr) == '\r') + while (ff_text_peek_r8(tr) == '\r') ff_text_r8(tr); if (ff_text_peek_r8(tr) == '\n') ff_text_r8(tr); diff --git a/libavformat/subtitles.h b/libavformat/subtitles.h index ca78db224..6b418e362 100644 --- a/libavformat/subtitles.h +++ b/libavformat/subtitles.h @@ -188,7 +188,7 @@ static av_always_inline int ff_subtitles_next_line(const char *ptr) { int n = strcspn(ptr, "\r\n"); ptr += n; - if (*ptr == '\r') { + while (*ptr == '\r') { ptr++; n++; } diff --git a/libavformat/subviewer1dec.c b/libavformat/subviewer1dec.c index e579d1ca9..1360d9b7d 100644 --- a/libavformat/subviewer1dec.c +++ b/libavformat/subviewer1dec.c @@ -31,7 +31,7 @@ typedef struct { FFDemuxSubtitlesQueue q; } SubViewer1Context; -static int subviewer1_probe(AVProbeData *p) +static int subviewer1_probe(const AVProbeData *p) { const unsigned char *ptr = p->buf; diff --git a/libavformat/subviewerdec.c b/libavformat/subviewerdec.c index af084f485..06b827b70 100644 --- a/libavformat/subviewerdec.c +++ b/libavformat/subviewerdec.c @@ -27,6 +27,7 @@ #include "avformat.h" #include "internal.h" #include "subtitles.h" +#include "avio_internal.h" #include "libavcodec/internal.h" #include "libavutil/avstring.h" #include "libavutil/bprint.h" @@ -36,7 +37,7 @@ typedef struct { FFDemuxSubtitlesQueue q; } SubViewerContext; -static int subviewer_probe(AVProbeData *p) +static int subviewer_probe(const AVProbeData *p) { char c; const unsigned char *ptr = p->buf; @@ -78,6 +79,11 @@ static int subviewer_read_header(AVFormatContext *s) if (!st) return AVERROR(ENOMEM); + res = ffio_ensure_seekback(s->pb, 3); + if (res < 0) + return res; + if (avio_rb24(s->pb) != 0xefbbbf) + avio_seek(s->pb, -3, SEEK_CUR); avpriv_set_pts_info(st, 64, 1, 100); st->codecpar->codec_type = AVMEDIA_TYPE_SUBTITLE; st->codecpar->codec_id = AV_CODEC_ID_SUBVIEWER; diff --git a/libavformat/supdec.c b/libavformat/supdec.c index 0930dbcef..d3fb2510c 100644 --- a/libavformat/supdec.c +++ b/libavformat/supdec.c @@ -68,7 +68,7 @@ static int sup_read_packet(AVFormatContext *s, AVPacket *pkt) return 0; } -static int sup_probe(AVProbeData *p) +static int sup_probe(const AVProbeData *p) { unsigned char *buf = p->buf; size_t buf_size = p->buf_size; diff --git a/libavformat/supenc.c b/libavformat/supenc.c index f5f6b58c8..643dda5ff 100644 --- a/libavformat/supenc.c +++ b/libavformat/supenc.c @@ -32,10 +32,10 @@ static int sup_write_packet(AVFormatContext *s, AVPacket *pkt) uint32_t pts = 0, dts = 0; if (pkt->pts != AV_NOPTS_VALUE) { - pts = (uint32_t)pkt->pts; + pts = pkt->pts; } if (pkt->dts != AV_NOPTS_VALUE) { - dts = (uint32_t)pkt->dts; + dts = pkt->dts; } /* @@ -46,8 +46,8 @@ static int sup_write_packet(AVFormatContext *s, AVPacket *pkt) size_t len = AV_RB16(data + 1) + 3; if (len > size) { - av_log(s, AV_LOG_ERROR, "Not enough data, skipping %d bytes\n", - (int)size); + av_log(s, AV_LOG_ERROR, "Not enough data, skipping %"SIZE_SPECIFIER" bytes\n", + size); return AVERROR_INVALIDDATA; } @@ -63,8 +63,8 @@ static int sup_write_packet(AVFormatContext *s, AVPacket *pkt) } if (size > 0) { - av_log(s, AV_LOG_ERROR, "Skipping %d bytes after last segment in frame\n", - (int)size); + av_log(s, AV_LOG_ERROR, "Skipping %"SIZE_SPECIFIER" bytes after last segment in frame\n", + size); return AVERROR_INVALIDDATA; } diff --git a/libavformat/svag.c b/libavformat/svag.c index 828b85348..83e033b10 100644 --- a/libavformat/svag.c +++ b/libavformat/svag.c @@ -22,7 +22,7 @@ #include "avformat.h" #include "internal.h" -static int svag_probe(AVProbeData *p) +static int svag_probe(const AVProbeData *p) { if (memcmp(p->buf, "Svag", 4)) return 0; diff --git a/libavformat/swfdec.c b/libavformat/swfdec.c index 212157f54..85bd30404 100644 --- a/libavformat/swfdec.c +++ b/libavformat/swfdec.c @@ -61,7 +61,7 @@ static int get_swf_tag(AVIOContext *pb, int *len_ptr) } -static int swf_probe(AVProbeData *p) +static int swf_probe(const AVProbeData *p) { GetBitContext gb; int len, xmin, xmax, ymin, ymax; diff --git a/libavformat/takdec.c b/libavformat/takdec.c index 6fda35c1b..6d18b6af2 100644 --- a/libavformat/takdec.c +++ b/libavformat/takdec.c @@ -31,11 +31,13 @@ #include "rawdec.h" typedef struct TAKDemuxContext { + AVClass *class; + int raw_packet_size; int mlast_frame; int64_t data_end; } TAKDemuxContext; -static int tak_probe(AVProbeData *p) +static int tak_probe(const AVProbeData *p) { if (!memcmp(p->buf, "tBaK", 4)) return AVPROBE_SCORE_EXTENSION; @@ -80,6 +82,8 @@ static int tak_read_header(AVFormatContext *s) switch (type) { case TAK_METADATA_STREAMINFO: + if (st->codecpar->extradata) + return AVERROR_INVALIDDATA; case TAK_METADATA_LAST_FRAME: case TAK_METADATA_ENCODER: if (size <= 3) @@ -146,7 +150,7 @@ static int tak_read_header(AVFormatContext *s) ret = avpriv_tak_parse_streaminfo(&ti, buffer, size -3); if (ret < 0) - return AVERROR_INVALIDDATA; + goto end; if (ti.samples > 0) st->duration = ti.samples; st->codecpar->bits_per_coded_sample = ti.bps; @@ -160,8 +164,10 @@ static int tak_read_header(AVFormatContext *s) st->codecpar->extradata_size = size - 3; buffer = NULL; } else if (type == TAK_METADATA_LAST_FRAME) { - if (size != 11) - return AVERROR_INVALIDDATA; + if (size != 11) { + ret = AVERROR_INVALIDDATA; + goto end; + } init_get_bits8(&gb, buffer, size - 3); tc->mlast_frame = 1; tc->data_end = get_bits64(&gb, TAK_LAST_FRAME_POS_BITS) + @@ -176,6 +182,9 @@ static int tak_read_header(AVFormatContext *s) } return AVERROR_EOF; +end: + av_freep(&buffer); + return ret; } static int raw_read_packet(AVFormatContext *s, AVPacket *pkt) @@ -204,6 +213,7 @@ static int raw_read_packet(AVFormatContext *s, AVPacket *pkt) return ret; } +FF_RAW_DEMUXER_CLASS(tak) AVInputFormat ff_tak_demuxer = { .name = "tak", .long_name = NULL_IF_CONFIG_SMALL("raw TAK"), @@ -214,4 +224,5 @@ AVInputFormat ff_tak_demuxer = { .flags = AVFMT_GENERIC_INDEX, .extensions = "tak", .raw_codec_id = AV_CODEC_ID_TAK, + .priv_class = &tak_demuxer_class, }; diff --git a/libavformat/tcp.c b/libavformat/tcp.c index 8773493df..2198e0f00 100644 --- a/libavformat/tcp.c +++ b/libavformat/tcp.c @@ -42,6 +42,9 @@ typedef struct TCPContext { int recv_buffer_size; int send_buffer_size; int tcp_nodelay; +#if !HAVE_WINSOCK2_H + int tcp_mss; +#endif /* !HAVE_WINSOCK2_H */ } TCPContext; #define OFFSET(x) offsetof(TCPContext, x) @@ -54,6 +57,9 @@ static const AVOption options[] = { { "send_buffer_size", "Socket send buffer size (in bytes)", OFFSET(send_buffer_size), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, .flags = D|E }, { "recv_buffer_size", "Socket receive buffer size (in bytes)", OFFSET(recv_buffer_size), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, .flags = D|E }, { "tcp_nodelay", "Use TCP_NODELAY to disable nagle's algorithm", OFFSET(tcp_nodelay), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, .flags = D|E }, +#if !HAVE_WINSOCK2_H + { "tcp_mss", "Maximum segment size for outgoing TCP packets", OFFSET(tcp_mss), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, .flags = D|E }, +#endif /* !HAVE_WINSOCK2_H */ { NULL } }; @@ -64,6 +70,35 @@ static const AVClass tcp_class = { .version = LIBAVUTIL_VERSION_INT, }; +static void customize_fd(void *ctx, int fd) +{ + TCPContext *s = ctx; + /* Set the socket's send or receive buffer sizes, if specified. + If unspecified or setting fails, system default is used. */ + if (s->recv_buffer_size > 0) { + if (setsockopt (fd, SOL_SOCKET, SO_RCVBUF, &s->recv_buffer_size, sizeof (s->recv_buffer_size))) { + ff_log_net_error(ctx, AV_LOG_WARNING, "setsockopt(SO_RCVBUF)"); + } + } + if (s->send_buffer_size > 0) { + if (setsockopt (fd, SOL_SOCKET, SO_SNDBUF, &s->send_buffer_size, sizeof (s->send_buffer_size))) { + ff_log_net_error(ctx, AV_LOG_WARNING, "setsockopt(SO_SNDBUF)"); + } + } + if (s->tcp_nodelay > 0) { + if (setsockopt (fd, IPPROTO_TCP, TCP_NODELAY, &s->tcp_nodelay, sizeof (s->tcp_nodelay))) { + ff_log_net_error(ctx, AV_LOG_WARNING, "setsockopt(TCP_NODELAY)"); + } + } +#if !HAVE_WINSOCK2_H + if (s->tcp_mss > 0) { + if (setsockopt (fd, IPPROTO_TCP, TCP_MAXSEG, &s->tcp_mss, sizeof (s->tcp_mss))) { + ff_log_net_error(ctx, AV_LOG_WARNING, "setsockopt(TCP_MAXSEG)"); + } + } +#endif /* !HAVE_WINSOCK2_H */ +} + /* return non zero if error */ static int tcp_open(URLContext *h, const char *uri, int flags) { @@ -123,7 +158,6 @@ static int tcp_open(URLContext *h, const char *uri, int flags) cur_ai = ai; - restart: #if HAVE_STRUCT_SOCKADDR_IN6 // workaround for IOS9 getaddrinfo in IPv6 only network use hardcode IPv4 address can not resolve port number. if (cur_ai->ai_family == AF_INET6){ @@ -134,24 +168,19 @@ static int tcp_open(URLContext *h, const char *uri, int flags) } #endif - fd = ff_socket(cur_ai->ai_family, - cur_ai->ai_socktype, - cur_ai->ai_protocol); - if (fd < 0) { - ret = ff_neterrno(); - goto fail; - } - - /* Set the socket's send or receive buffer sizes, if specified. - If unspecified or setting fails, system default is used. */ - if (s->recv_buffer_size > 0) { - setsockopt (fd, SOL_SOCKET, SO_RCVBUF, &s->recv_buffer_size, sizeof (s->recv_buffer_size)); - } - if (s->send_buffer_size > 0) { - setsockopt (fd, SOL_SOCKET, SO_SNDBUF, &s->send_buffer_size, sizeof (s->send_buffer_size)); - } - if (s->tcp_nodelay > 0) { - setsockopt (fd, IPPROTO_TCP, TCP_NODELAY, &s->tcp_nodelay, sizeof (s->tcp_nodelay)); + if (s->listen > 0) { + while (cur_ai && fd < 0) { + fd = ff_socket(cur_ai->ai_family, + cur_ai->ai_socktype, + cur_ai->ai_protocol); + if (fd < 0) { + ret = ff_neterrno(); + cur_ai = cur_ai->ai_next; + } + } + if (fd < 0) + goto fail1; + customize_fd(s, fd); } if (s->listen == 2) { @@ -166,14 +195,9 @@ static int tcp_open(URLContext *h, const char *uri, int flags) // Socket descriptor already closed here. Safe to overwrite to client one. fd = ret; } else { - if ((ret = ff_listen_connect(fd, cur_ai->ai_addr, cur_ai->ai_addrlen, - s->open_timeout / 1000, h, !!cur_ai->ai_next)) < 0) { - - if (ret == AVERROR_EXIT) - goto fail1; - else - goto fail; - } + ret = ff_connect_parallel(ai, s->open_timeout / 1000, 3, h, &fd, customize_fd, s); + if (ret < 0) + goto fail1; } h->is_streamed = 1; @@ -182,15 +206,6 @@ static int tcp_open(URLContext *h, const char *uri, int flags) freeaddrinfo(ai); return 0; - fail: - if (cur_ai->ai_next) { - /* Retry with the next sockaddr */ - cur_ai = cur_ai->ai_next; - if (fd >= 0) - closesocket(fd); - ret = 0; - goto restart; - } fail1: if (fd >= 0) closesocket(fd); @@ -208,8 +223,10 @@ static int tcp_accept(URLContext *s, URLContext **c) return ret; cc = (*c)->priv_data; ret = ff_accept(sc->fd, sc->listen_timeout, s); - if (ret < 0) + if (ret < 0) { + ffurl_closep(c); return ret; + } cc->fd = ret; return 0; } diff --git a/libavformat/tedcaptionsdec.c b/libavformat/tedcaptionsdec.c index 774d4993b..5572bfd93 100644 --- a/libavformat/tedcaptionsdec.c +++ b/libavformat/tedcaptionsdec.c @@ -94,7 +94,7 @@ static int parse_string(AVIOContext *pb, int *cur_byte, AVBPrint *bp, int full) { int ret; - av_bprint_init(bp, 0, full ? -1 : 1); + av_bprint_init(bp, 0, full ? AV_BPRINT_SIZE_UNLIMITED : AV_BPRINT_SIZE_AUTOMATIC); ret = expect_byte(pb, cur_byte, '"'); if (ret < 0) goto fail; @@ -321,7 +321,7 @@ static int tedcaptions_read_close(AVFormatContext *avf) return 0; } -static av_cold int tedcaptions_read_probe(AVProbeData *p) +static av_cold int tedcaptions_read_probe(const AVProbeData *p) { static const char *const tags[] = { "\"captions\"", "\"duration\"", "\"content\"", diff --git a/libavformat/tee.c b/libavformat/tee.c index ef3b113a4..89a4ceb28 100644 --- a/libavformat/tee.c +++ b/libavformat/tee.c @@ -236,6 +236,7 @@ static int open_slave(AVFormatContext *avf, char *slave, TeeSlave *tee_slave) avf2->io_close = avf->io_close; avf2->interrupt_callback = avf->interrupt_callback; avf2->flags = avf->flags; + avf2->strict_std_compliance = avf->strict_std_compliance; tee_slave->stream_map = av_calloc(avf->nb_streams, sizeof(*tee_slave->stream_map)); if (!tee_slave->stream_map) { diff --git a/libavformat/thp.c b/libavformat/thp.c index 76b9b3820..ee5c78b6d 100644 --- a/libavformat/thp.c +++ b/libavformat/thp.c @@ -45,7 +45,7 @@ typedef struct ThpDemuxContext { } ThpDemuxContext; -static int thp_probe(AVProbeData *p) +static int thp_probe(const AVProbeData *p) { double d; /* check file header */ diff --git a/libavformat/tiertexseq.c b/libavformat/tiertexseq.c index 6e00692e2..a89a0a9d6 100644 --- a/libavformat/tiertexseq.c +++ b/libavformat/tiertexseq.c @@ -60,7 +60,7 @@ typedef struct SeqDemuxContext { } SeqDemuxContext; -static int seq_probe(AVProbeData *p) +static int seq_probe(const AVProbeData *p) { int i; @@ -182,6 +182,17 @@ static int seq_parse_frame_data(SeqDemuxContext *seq, AVIOContext *pb) return 0; } +static int seq_read_close(AVFormatContext *s) +{ + int i; + SeqDemuxContext *seq = s->priv_data; + + for (i = 0; i < SEQ_NUM_FRAME_BUFFERS; i++) + av_freep(&seq->frame_buffers[i].data); + + return 0; +} + static int seq_read_header(AVFormatContext *s) { int i, rc; @@ -191,16 +202,20 @@ static int seq_read_header(AVFormatContext *s) /* init internal buffers */ rc = seq_init_frame_buffers(seq, pb); - if (rc) + if (rc) { + seq_read_close(s); return rc; + } seq->current_frame_offs = 0; /* preload (no audio data, just buffer operations related data) */ for (i = 1; i <= 100; i++) { rc = seq_parse_frame_data(seq, pb); - if (rc) + if (rc) { + seq_read_close(s); return rc; + } } seq->current_frame_pts = 0; @@ -209,8 +224,10 @@ static int seq_read_header(AVFormatContext *s) /* initialize the video decoder stream */ st = avformat_new_stream(s, NULL); - if (!st) + if (!st) { + seq_read_close(s); return AVERROR(ENOMEM); + } avpriv_set_pts_info(st, 32, 1, SEQ_FRAME_RATE); seq->video_stream_index = st->index; @@ -222,8 +239,10 @@ static int seq_read_header(AVFormatContext *s) /* initialize the audio decoder stream */ st = avformat_new_stream(s, NULL); - if (!st) + if (!st) { + seq_read_close(s); return AVERROR(ENOMEM); + } st->start_time = 0; avpriv_set_pts_info(st, 32, 1, SEQ_SAMPLE_RATE); @@ -295,17 +314,6 @@ static int seq_read_packet(AVFormatContext *s, AVPacket *pkt) return 0; } -static int seq_read_close(AVFormatContext *s) -{ - int i; - SeqDemuxContext *seq = s->priv_data; - - for (i = 0; i < SEQ_NUM_FRAME_BUFFERS; i++) - av_freep(&seq->frame_buffers[i].data); - - return 0; -} - AVInputFormat ff_tiertexseq_demuxer = { .name = "tiertexseq", .long_name = NULL_IF_CONFIG_SMALL("Tiertex Limited SEQ"), diff --git a/libavformat/tls_gnutls.c b/libavformat/tls_gnutls.c index e3c43683b..f32bc2821 100644 --- a/libavformat/tls_gnutls.c +++ b/libavformat/tls_gnutls.c @@ -182,11 +182,13 @@ static int tls_open(URLContext *h, const char *uri, int flags, AVDictionary **op gnutls_transport_set_push_function(p->session, gnutls_url_push); gnutls_transport_set_ptr(p->session, c->tcp); gnutls_priority_set_direct(p->session, "NORMAL", NULL); - ret = gnutls_handshake(p->session); - if (ret) { - ret = print_tls_error(h, ret); - goto fail; - } + do { + ret = gnutls_handshake(p->session); + if (gnutls_error_is_fatal(ret)) { + ret = print_tls_error(h, ret); + goto fail; + } + } while (ret); p->need_shutdown = 1; if (c->verify) { unsigned int status, cert_list_size; diff --git a/libavformat/tls_mbedtls.c b/libavformat/tls_mbedtls.c new file mode 100644 index 000000000..9b80a1e3c --- /dev/null +++ b/libavformat/tls_mbedtls.c @@ -0,0 +1,351 @@ +/* + * TLS/SSL Protocol + * Copyright (c) 2018 Thomas Volkert + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "avformat.h" +#include "internal.h" +#include "url.h" +#include "tls.h" +#include "libavutil/parseutils.h" + +typedef struct TLSContext { + const AVClass *class; + TLSShared tls_shared; + mbedtls_ssl_context ssl_context; + mbedtls_ssl_config ssl_config; + mbedtls_entropy_context entropy_context; + mbedtls_ctr_drbg_context ctr_drbg_context; + mbedtls_x509_crt ca_cert; + mbedtls_x509_crt own_cert; + mbedtls_pk_context priv_key; + char *priv_key_pw; +} TLSContext; + +#define OFFSET(x) offsetof(TLSContext, x) + +static int tls_close(URLContext *h) +{ + TLSContext *tls_ctx = h->priv_data; + + mbedtls_ssl_close_notify(&tls_ctx->ssl_context); + mbedtls_pk_free(&tls_ctx->priv_key); + mbedtls_x509_crt_free(&tls_ctx->ca_cert); + mbedtls_x509_crt_free(&tls_ctx->own_cert); + mbedtls_ssl_free(&tls_ctx->ssl_context); + mbedtls_ssl_config_free(&tls_ctx->ssl_config); + mbedtls_ctr_drbg_free(&tls_ctx->ctr_drbg_context); + mbedtls_entropy_free(&tls_ctx->entropy_context); + + return 0; +} + +static int handle_transport_error(URLContext *h, const char* func_name, int react_on_eagain, int ret) +{ + switch (ret) { + case AVERROR(EAGAIN): + return react_on_eagain; + case AVERROR_EXIT: + return 0; + case AVERROR(EPIPE): + case AVERROR(ECONNRESET): + return MBEDTLS_ERR_NET_CONN_RESET; + default: + av_log(h, AV_LOG_ERROR, "%s returned 0x%x\n", func_name, ret); + errno = EIO; + return MBEDTLS_ERR_NET_SEND_FAILED; + } +} + +static int mbedtls_send(void *ctx, const unsigned char *buf, size_t len) +{ + URLContext *h = (URLContext*) ctx; + int ret = ffurl_write(h, buf, len); + if (ret >= 0) + return ret; + + if (h->max_packet_size && len > h->max_packet_size) + return MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL; + + return handle_transport_error(h, "ffurl_write", MBEDTLS_ERR_SSL_WANT_WRITE, ret); +} + +static int mbedtls_recv(void *ctx, unsigned char *buf, size_t len) +{ + URLContext *h = (URLContext*) ctx; + int ret = ffurl_read(h, buf, len); + if (ret >= 0) + return ret; + + if (h->max_packet_size && len > h->max_packet_size) + return MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL; + + return handle_transport_error(h, "ffurl_read", MBEDTLS_ERR_SSL_WANT_READ, ret); +} + +static void handle_pk_parse_error(URLContext *h, int ret) +{ + switch (ret) { + case MBEDTLS_ERR_PK_FILE_IO_ERROR: + av_log(h, AV_LOG_ERROR, "Read of key file failed. Is it actually there, are the access permissions correct?\n"); + break; + case MBEDTLS_ERR_PK_PASSWORD_REQUIRED: + av_log(h, AV_LOG_ERROR, "A password for the private key is missing.\n"); + break; + case MBEDTLS_ERR_PK_PASSWORD_MISMATCH: + av_log(h, AV_LOG_ERROR, "The given password for the private key is wrong.\n"); + break; + default: + av_log(h, AV_LOG_ERROR, "mbedtls_pk_parse_key returned -0x%x\n", -ret); + break; + } +} + +static void handle_handshake_error(URLContext *h, int ret) +{ + switch (ret) { + case MBEDTLS_ERR_SSL_NO_USABLE_CIPHERSUITE: + av_log(h, AV_LOG_ERROR, "None of the common ciphersuites is usable. Was the local certificate correctly set?\n"); + break; + case MBEDTLS_ERR_SSL_FATAL_ALERT_MESSAGE: + av_log(h, AV_LOG_ERROR, "A fatal alert message was received from the peer, has the peer a correct certificate?\n"); + break; + case MBEDTLS_ERR_SSL_CA_CHAIN_REQUIRED: + av_log(h, AV_LOG_ERROR, "No CA chain is set, but required to operate. Was the CA correctly set?\n"); + break; + case MBEDTLS_ERR_NET_CONN_RESET: + av_log(h, AV_LOG_ERROR, "TLS handshake was aborted by peer.\n"); + break; + default: + av_log(h, AV_LOG_ERROR, "mbedtls_ssl_handshake returned -0x%x\n", -ret); + break; + } +} + +static void parse_options(TLSContext *tls_ctxc, const char *uri) +{ + char buf[1024]; + const char *p = strchr(uri, '?'); + if (!p) + return; + + if (!tls_ctxc->priv_key_pw && av_find_info_tag(buf, sizeof(buf), "key_password", p)) + tls_ctxc->priv_key_pw = av_strdup(buf); +} + +static int tls_open(URLContext *h, const char *uri, int flags, AVDictionary **options) +{ + TLSContext *tls_ctx = h->priv_data; + TLSShared *shr = &tls_ctx->tls_shared; + uint32_t verify_res_flags; + int ret; + + // parse additional options + parse_options(tls_ctx, uri); + + if ((ret = ff_tls_open_underlying(shr, h, uri, options)) < 0) + goto fail; + + mbedtls_ssl_init(&tls_ctx->ssl_context); + mbedtls_ssl_config_init(&tls_ctx->ssl_config); + mbedtls_entropy_init(&tls_ctx->entropy_context); + mbedtls_ctr_drbg_init(&tls_ctx->ctr_drbg_context); + mbedtls_x509_crt_init(&tls_ctx->ca_cert); + mbedtls_pk_init(&tls_ctx->priv_key); + + // load trusted CA + if (shr->ca_file) { + if ((ret = mbedtls_x509_crt_parse_file(&tls_ctx->ca_cert, shr->ca_file)) != 0) { + av_log(h, AV_LOG_ERROR, "mbedtls_x509_crt_parse_file for CA cert returned %d\n", ret); + goto fail; + } + } + + // load own certificate + if (shr->cert_file) { + if ((ret = mbedtls_x509_crt_parse_file(&tls_ctx->own_cert, shr->cert_file)) != 0) { + av_log(h, AV_LOG_ERROR, "mbedtls_x509_crt_parse_file for own cert returned %d\n", ret); + goto fail; + } + } + + // load key file + if (shr->key_file) { + if ((ret = mbedtls_pk_parse_keyfile(&tls_ctx->priv_key, + shr->key_file, + tls_ctx->priv_key_pw)) != 0) { + handle_pk_parse_error(h, ret); + goto fail; + } + } + + // seed the random number generator + if ((ret = mbedtls_ctr_drbg_seed(&tls_ctx->ctr_drbg_context, + mbedtls_entropy_func, + &tls_ctx->entropy_context, + NULL, 0)) != 0) { + av_log(h, AV_LOG_ERROR, "mbedtls_ctr_drbg_seed returned %d\n", ret); + goto fail; + } + + if ((ret = mbedtls_ssl_config_defaults(&tls_ctx->ssl_config, + shr->listen ? MBEDTLS_SSL_IS_SERVER : MBEDTLS_SSL_IS_CLIENT, + MBEDTLS_SSL_TRANSPORT_STREAM, + MBEDTLS_SSL_PRESET_DEFAULT)) != 0) { + av_log(h, AV_LOG_ERROR, "mbedtls_ssl_config_defaults returned %d\n", ret); + goto fail; + } + + mbedtls_ssl_conf_authmode(&tls_ctx->ssl_config, + shr->ca_file ? MBEDTLS_SSL_VERIFY_REQUIRED : MBEDTLS_SSL_VERIFY_NONE); + mbedtls_ssl_conf_rng(&tls_ctx->ssl_config, mbedtls_ctr_drbg_random, &tls_ctx->ctr_drbg_context); + mbedtls_ssl_conf_ca_chain(&tls_ctx->ssl_config, &tls_ctx->ca_cert, NULL); + + // set own certificate and private key + if ((ret = mbedtls_ssl_conf_own_cert(&tls_ctx->ssl_config, &tls_ctx->own_cert, &tls_ctx->priv_key)) != 0) { + av_log(h, AV_LOG_ERROR, "mbedtls_ssl_conf_own_cert returned %d\n", ret); + goto fail; + } + + if ((ret = mbedtls_ssl_setup(&tls_ctx->ssl_context, &tls_ctx->ssl_config)) != 0) { + av_log(h, AV_LOG_ERROR, "mbedtls_ssl_setup returned %d\n", ret); + goto fail; + } + + if (!shr->listen && !shr->numerichost) { + if ((ret = mbedtls_ssl_set_hostname(&tls_ctx->ssl_context, shr->host)) != 0) { + av_log(h, AV_LOG_ERROR, "mbedtls_ssl_set_hostname returned %d\n", ret); + goto fail; + } + } + + // set I/O functions to use FFmpeg internal code for transport layer + mbedtls_ssl_set_bio(&tls_ctx->ssl_context, shr->tcp, mbedtls_send, mbedtls_recv, NULL); + + // ssl handshake + while ((ret = mbedtls_ssl_handshake(&tls_ctx->ssl_context)) != 0) { + if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) { + handle_handshake_error(h, ret); + goto fail; + } + } + + if (shr->verify) { + // check the result of the certificate verification + if ((verify_res_flags = mbedtls_ssl_get_verify_result(&tls_ctx->ssl_context)) != 0) { + av_log(h, AV_LOG_ERROR, "mbedtls_ssl_get_verify_result reported problems "\ + "with the certificate verification, returned flags: %u\n", + verify_res_flags); + if (verify_res_flags & MBEDTLS_X509_BADCERT_NOT_TRUSTED) + av_log(h, AV_LOG_ERROR, "The certificate is not correctly signed by the trusted CA.\n"); + goto fail; + } + } + + return 0; + +fail: + tls_close(h); + return AVERROR(EIO); +} + +static int handle_tls_error(URLContext *h, const char* func_name, int ret) +{ + switch (ret) { + case MBEDTLS_ERR_SSL_WANT_READ: + case MBEDTLS_ERR_SSL_WANT_WRITE: + return AVERROR(EAGAIN); + case MBEDTLS_ERR_NET_SEND_FAILED: + case MBEDTLS_ERR_NET_RECV_FAILED: + return AVERROR(EIO); + case MBEDTLS_ERR_NET_CONN_RESET: + case MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY: + av_log(h, AV_LOG_WARNING, "%s reported connection reset by peer\n", func_name); + return AVERROR_EOF; + default: + av_log(h, AV_LOG_ERROR, "%s returned -0x%x\n", func_name, -ret); + return AVERROR(EIO); + } +} + +static int tls_read(URLContext *h, uint8_t *buf, int size) +{ + TLSContext *tls_ctx = h->priv_data; + int ret; + + if ((ret = mbedtls_ssl_read(&tls_ctx->ssl_context, buf, size)) > 0) { + // return read length + return ret; + } + + return handle_tls_error(h, "mbedtls_ssl_read", ret); +} + +static int tls_write(URLContext *h, const uint8_t *buf, int size) +{ + TLSContext *tls_ctx = h->priv_data; + int ret; + + if ((ret = mbedtls_ssl_write(&tls_ctx->ssl_context, buf, size)) > 0) { + // return written length + return ret; + } + + return handle_tls_error(h, "mbedtls_ssl_write", ret); +} + +static int tls_get_file_handle(URLContext *h) +{ + TLSContext *c = h->priv_data; + return ffurl_get_file_handle(c->tls_shared.tcp); +} + +static const AVOption options[] = { + TLS_COMMON_OPTIONS(TLSContext, tls_shared), \ + {"key_password", "Password for the private key file", OFFSET(priv_key_pw), AV_OPT_TYPE_STRING, .flags = TLS_OPTFL }, \ + { NULL } +}; + +static const AVClass tls_class = { + .class_name = "tls", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; + +const URLProtocol ff_tls_protocol = { + .name = "tls", + .url_open2 = tls_open, + .url_read = tls_read, + .url_write = tls_write, + .url_close = tls_close, + .url_get_file_handle = tls_get_file_handle, + .priv_data_size = sizeof(TLSContext), + .flags = URL_PROTOCOL_FLAG_NETWORK, + .priv_data_class = &tls_class, +}; diff --git a/libavformat/tls_openssl.c b/libavformat/tls_openssl.c index 59a86150a..7ae71bdaf 100644 --- a/libavformat/tls_openssl.c +++ b/libavformat/tls_openssl.c @@ -119,7 +119,7 @@ static int print_tls_error(URLContext *h, int ret) TLSContext *c = h->priv_data; if (h->flags & AVIO_FLAG_NONBLOCK) { int err = SSL_get_error(c->ssl, ret); - if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_READ) + if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) return AVERROR(EAGAIN); } av_log(h, AV_LOG_ERROR, "%s\n", ERR_error_string(ERR_get_error(), NULL)); diff --git a/libavformat/tls_schannel.c b/libavformat/tls_schannel.c index f41b00777..4f0badcb8 100644 --- a/libavformat/tls_schannel.c +++ b/libavformat/tls_schannel.c @@ -148,7 +148,7 @@ static int tls_client_handshake_loop(URLContext *h, int initial) TLSContext *c = h->priv_data; TLSShared *s = &c->tls_shared; SECURITY_STATUS sspi_ret; - SecBuffer outbuf[3]; + SecBuffer outbuf[3] = { 0 }; SecBufferDesc outbuf_desc; SecBuffer inbuf[2]; SecBufferDesc inbuf_desc; diff --git a/libavformat/tmv.c b/libavformat/tmv.c index 2e351714b..b74af547c 100644 --- a/libavformat/tmv.c +++ b/libavformat/tmv.c @@ -51,7 +51,7 @@ typedef struct TMVContext { #define PROBE_MAX_FPS 120 #define PROBE_MIN_AUDIO_SIZE (PROBE_MIN_SAMPLE_RATE / PROBE_MAX_FPS) -static int tmv_probe(AVProbeData *p) +static int tmv_probe(const AVProbeData *p) { if (AV_RL32(p->buf) == TMV_TAG && AV_RL16(p->buf+4) >= PROBE_MIN_SAMPLE_RATE && diff --git a/libavformat/tta.c b/libavformat/tta.c index ae90a8554..467c24455 100644 --- a/libavformat/tta.c +++ b/libavformat/tta.c @@ -35,7 +35,7 @@ typedef struct TTAContext { int last_frame_size; } TTAContext; -static int tta_probe(AVProbeData *p) +static int tta_probe(const AVProbeData *p) { if (AV_RL32(&p->buf[0]) == MKTAG('T', 'T', 'A', '1') && (AV_RL16(&p->buf[4]) == 1 || AV_RL16(&p->buf[4]) == 2) && diff --git a/libavformat/txd.c b/libavformat/txd.c index 18c968395..072cd04f5 100644 --- a/libavformat/txd.c +++ b/libavformat/txd.c @@ -31,7 +31,7 @@ #define TXD_MARKER 0x1803ffff #define TXD_MARKER2 0x1003ffff -static int txd_probe(AVProbeData * pd) { +static int txd_probe(const AVProbeData * pd) { if (AV_RL32(pd->buf ) == TXD_FILE && (AV_RL32(pd->buf+8) == TXD_MARKER || AV_RL32(pd->buf+8) == TXD_MARKER2)) return AVPROBE_SCORE_MAX; diff --git a/libavformat/ty.c b/libavformat/ty.c index d348643f4..bbb2e28a9 100644 --- a/libavformat/ty.c +++ b/libavformat/ty.c @@ -106,7 +106,7 @@ typedef struct TYDemuxContext { uint8_t chunk[CHUNK_SIZE]; } TYDemuxContext; -static int ty_probe(AVProbeData *p) +static int ty_probe(const AVProbeData *p) { int i; @@ -254,7 +254,7 @@ static int analyze_chunk(AVFormatContext *s, const uint8_t *chunk) if (data_offset + hdrs[i].rec_size > CHUNK_SIZE) break; - if ((hdrs[i].subrec_type << 0x08 | hdrs[i].rec_type) == 0x3c0 && hdrs[i].rec_size > 15) { + if ((hdrs[i].subrec_type << 8 | hdrs[i].rec_type) == 0x3c0 && hdrs[i].rec_size > 15) { /* first make sure we're aligned */ int pes_offset = find_es_header(ty_MPEGAudioPacket, &chunk[data_offset], 5); diff --git a/libavformat/udp.c b/libavformat/udp.c index 0dde0353f..cf73d331e 100644 --- a/libavformat/udp.c +++ b/libavformat/udp.c @@ -41,6 +41,7 @@ #include "network.h" #include "os_support.h" #include "url.h" +#include "ip.h" #ifdef __APPLE__ #include "TargetConditionals.h" @@ -109,6 +110,7 @@ typedef struct UDPContext { struct sockaddr_storage local_addr_storage; char *sources; char *block; + IPSourceFilters filters; } UDPContext; #define OFFSET(x) offsetof(UDPContext, x) @@ -150,20 +152,13 @@ static const AVClass udplite_context_class = { .version = LIBAVUTIL_VERSION_INT, }; -static void log_net_error(void *ctx, int level, const char* prefix) -{ - char errbuf[100]; - av_strerror(ff_neterrno(), errbuf, sizeof(errbuf)); - av_log(ctx, level, "%s: %s\n", prefix, errbuf); -} - static int udp_set_multicast_ttl(int sockfd, int mcastTTL, struct sockaddr *addr) { #ifdef IP_MULTICAST_TTL if (addr->sa_family == AF_INET) { if (setsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_TTL, &mcastTTL, sizeof(mcastTTL)) < 0) { - log_net_error(NULL, AV_LOG_ERROR, "setsockopt(IP_MULTICAST_TTL)"); + ff_log_net_error(NULL, AV_LOG_ERROR, "setsockopt(IP_MULTICAST_TTL)"); return -1; } } @@ -171,7 +166,7 @@ static int udp_set_multicast_ttl(int sockfd, int mcastTTL, #if defined(IPPROTO_IPV6) && defined(IPV6_MULTICAST_HOPS) if (addr->sa_family == AF_INET6) { if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &mcastTTL, sizeof(mcastTTL)) < 0) { - log_net_error(NULL, AV_LOG_ERROR, "setsockopt(IPV6_MULTICAST_HOPS)"); + ff_log_net_error(NULL, AV_LOG_ERROR, "setsockopt(IPV6_MULTICAST_HOPS)"); return -1; } } @@ -191,7 +186,7 @@ static int udp_join_multicast_group(int sockfd, struct sockaddr *addr,struct soc else mreq.imr_interface.s_addr= INADDR_ANY; if (setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (const void *)&mreq, sizeof(mreq)) < 0) { - log_net_error(NULL, AV_LOG_ERROR, "setsockopt(IP_ADD_MEMBERSHIP)"); + ff_log_net_error(NULL, AV_LOG_ERROR, "setsockopt(IP_ADD_MEMBERSHIP)"); return -1; } } @@ -201,9 +196,10 @@ static int udp_join_multicast_group(int sockfd, struct sockaddr *addr,struct soc struct ipv6_mreq mreq6; memcpy(&mreq6.ipv6mr_multiaddr, &(((struct sockaddr_in6 *)addr)->sin6_addr), sizeof(struct in6_addr)); + //TODO: Interface index should be looked up from local_addr mreq6.ipv6mr_interface= 0; if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq6, sizeof(mreq6)) < 0) { - log_net_error(NULL, AV_LOG_ERROR, "setsockopt(IPV6_ADD_MEMBERSHIP)"); + ff_log_net_error(NULL, AV_LOG_ERROR, "setsockopt(IPV6_ADD_MEMBERSHIP)"); return -1; } } @@ -223,7 +219,7 @@ static int udp_leave_multicast_group(int sockfd, struct sockaddr *addr,struct so else mreq.imr_interface.s_addr= INADDR_ANY; if (setsockopt(sockfd, IPPROTO_IP, IP_DROP_MEMBERSHIP, (const void *)&mreq, sizeof(mreq)) < 0) { - log_net_error(NULL, AV_LOG_ERROR, "setsockopt(IP_DROP_MEMBERSHIP)"); + ff_log_net_error(NULL, AV_LOG_ERROR, "setsockopt(IP_DROP_MEMBERSHIP)"); return -1; } } @@ -233,9 +229,10 @@ static int udp_leave_multicast_group(int sockfd, struct sockaddr *addr,struct so struct ipv6_mreq mreq6; memcpy(&mreq6.ipv6mr_multiaddr, &(((struct sockaddr_in6 *)addr)->sin6_addr), sizeof(struct in6_addr)); + //TODO: Interface index should be looked up from local_addr mreq6.ipv6mr_interface= 0; if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP, &mreq6, sizeof(mreq6)) < 0) { - log_net_error(NULL, AV_LOG_ERROR, "setsockopt(IPV6_DROP_MEMBERSHIP)"); + ff_log_net_error(NULL, AV_LOG_ERROR, "setsockopt(IPV6_DROP_MEMBERSHIP)"); return -1; } } @@ -243,102 +240,67 @@ static int udp_leave_multicast_group(int sockfd, struct sockaddr *addr,struct so return 0; } -static struct addrinfo *udp_resolve_host(URLContext *h, - const char *hostname, int port, - int type, int family, int flags) -{ - struct addrinfo hints = { 0 }, *res = 0; - int error; - char sport[16]; - const char *node = 0, *service = "0"; - - if (port > 0) { - snprintf(sport, sizeof(sport), "%d", port); - service = sport; - } - if ((hostname) && (hostname[0] != '\0') && (hostname[0] != '?')) { - node = hostname; - } - hints.ai_socktype = type; - hints.ai_family = family; - hints.ai_flags = flags; - if ((error = getaddrinfo(node, service, &hints, &res))) { - res = NULL; - av_log(h, AV_LOG_ERROR, "getaddrinfo(%s, %s): %s\n", - node ? node : "unknown", - service, - gai_strerror(error)); - } - - return res; -} - static int udp_set_multicast_sources(URLContext *h, int sockfd, struct sockaddr *addr, - int addr_len, char **sources, + int addr_len, struct sockaddr_storage *local_addr, + struct sockaddr_storage *sources, int nb_sources, int include) { -#if HAVE_STRUCT_GROUP_SOURCE_REQ && defined(MCAST_BLOCK_SOURCE) && !defined(_WIN32) && (!defined(TARGET_OS_TV) || !TARGET_OS_TV) - /* These ones are available in the microsoft SDK, but don't seem to work - * as on linux, so just prefer the v4-only approach there for now. */ - int i; - for (i = 0; i < nb_sources; i++) { - struct group_source_req mreqs; - int level = addr->sa_family == AF_INET ? IPPROTO_IP : IPPROTO_IPV6; - struct addrinfo *sourceaddr = udp_resolve_host(h, sources[i], 0, - SOCK_DGRAM, AF_UNSPEC, - 0); - if (!sourceaddr) - return AVERROR(ENOENT); - - mreqs.gsr_interface = 0; - memcpy(&mreqs.gsr_group, addr, addr_len); - memcpy(&mreqs.gsr_source, sourceaddr->ai_addr, sourceaddr->ai_addrlen); - freeaddrinfo(sourceaddr); - - if (setsockopt(sockfd, level, - include ? MCAST_JOIN_SOURCE_GROUP : MCAST_BLOCK_SOURCE, - (const void *)&mreqs, sizeof(mreqs)) < 0) { - if (include) - log_net_error(NULL, AV_LOG_ERROR, "setsockopt(MCAST_JOIN_SOURCE_GROUP)"); - else - log_net_error(NULL, AV_LOG_ERROR, "setsockopt(MCAST_BLOCK_SOURCE)"); - return ff_neterrno(); - } - } -#elif HAVE_STRUCT_IP_MREQ_SOURCE && defined(IP_BLOCK_SOURCE) int i; if (addr->sa_family != AF_INET) { +#if HAVE_STRUCT_GROUP_SOURCE_REQ && defined(MCAST_BLOCK_SOURCE) + /* For IPv4 prefer the old approach, as that alone works reliably on + * Windows and it also supports supplying the interface based on its + * address. */ + int i; + for (i = 0; i < nb_sources; i++) { + struct group_source_req mreqs; + int level = addr->sa_family == AF_INET ? IPPROTO_IP : IPPROTO_IPV6; + + //TODO: Interface index should be looked up from local_addr + mreqs.gsr_interface = 0; + memcpy(&mreqs.gsr_group, addr, addr_len); + memcpy(&mreqs.gsr_source, &sources[i], sizeof(*sources)); + + if (setsockopt(sockfd, level, + include ? MCAST_JOIN_SOURCE_GROUP : MCAST_BLOCK_SOURCE, + (const void *)&mreqs, sizeof(mreqs)) < 0) { + if (include) + ff_log_net_error(NULL, AV_LOG_ERROR, "setsockopt(MCAST_JOIN_SOURCE_GROUP)"); + else + ff_log_net_error(NULL, AV_LOG_ERROR, "setsockopt(MCAST_BLOCK_SOURCE)"); + return ff_neterrno(); + } + } + return 0; +#else av_log(NULL, AV_LOG_ERROR, "Setting multicast sources only supported for IPv4\n"); return AVERROR(EINVAL); +#endif } +#if HAVE_STRUCT_IP_MREQ_SOURCE && defined(IP_BLOCK_SOURCE) for (i = 0; i < nb_sources; i++) { struct ip_mreq_source mreqs; - struct addrinfo *sourceaddr = udp_resolve_host(h, sources[i], 0, - SOCK_DGRAM, AF_UNSPEC, - 0); - if (!sourceaddr) - return AVERROR(ENOENT); - if (sourceaddr->ai_addr->sa_family != AF_INET) { - freeaddrinfo(sourceaddr); - av_log(NULL, AV_LOG_ERROR, "%s is of incorrect protocol family\n", - sources[i]); + if (sources[i].ss_family != AF_INET) { + av_log(NULL, AV_LOG_ERROR, "Source/block address %d is of incorrect protocol family\n", i + 1); return AVERROR(EINVAL); } mreqs.imr_multiaddr.s_addr = ((struct sockaddr_in *)addr)->sin_addr.s_addr; - mreqs.imr_interface.s_addr = INADDR_ANY; - mreqs.imr_sourceaddr.s_addr = ((struct sockaddr_in *)sourceaddr->ai_addr)->sin_addr.s_addr; - freeaddrinfo(sourceaddr); + if (local_addr) + mreqs.imr_interface= ((struct sockaddr_in *)local_addr)->sin_addr; + else + mreqs.imr_interface.s_addr= INADDR_ANY; + mreqs.imr_sourceaddr.s_addr = ((struct sockaddr_in *)&sources[i])->sin_addr.s_addr; if (setsockopt(sockfd, IPPROTO_IP, include ? IP_ADD_SOURCE_MEMBERSHIP : IP_BLOCK_SOURCE, (const void *)&mreqs, sizeof(mreqs)) < 0) { if (include) - log_net_error(NULL, AV_LOG_ERROR, "setsockopt(IP_ADD_SOURCE_MEMBERSHIP)"); + ff_log_net_error(NULL, AV_LOG_ERROR, "setsockopt(IP_ADD_SOURCE_MEMBERSHIP)"); else - log_net_error(NULL, AV_LOG_ERROR, "setsockopt(IP_BLOCK_SOURCE)"); + ff_log_net_error(NULL, AV_LOG_ERROR, "setsockopt(IP_BLOCK_SOURCE)"); return ff_neterrno(); } } @@ -354,7 +316,7 @@ static int udp_set_url(URLContext *h, struct addrinfo *res0; int addr_len; - res0 = udp_resolve_host(h, hostname, port, SOCK_DGRAM, AF_UNSPEC, 0); + res0 = ff_ip_resolve_host(h, hostname, port, SOCK_DGRAM, AF_UNSPEC, 0); if (!res0) return AVERROR(EIO); memcpy(addr, res0->ai_addr, res0->ai_addrlen); addr_len = res0->ai_addrlen; @@ -373,7 +335,7 @@ static int udp_socket_create(URLContext *h, struct sockaddr_storage *addr, if (((struct sockaddr *) &s->dest_addr)->sa_family) family = ((struct sockaddr *) &s->dest_addr)->sa_family; - res0 = udp_resolve_host(h, (localaddr && localaddr[0]) ? localaddr : NULL, + res0 = ff_ip_resolve_host(h, (localaddr && localaddr[0]) ? localaddr : NULL, s->local_port, SOCK_DGRAM, family, AI_PASSIVE); if (!res0) @@ -384,7 +346,7 @@ static int udp_socket_create(URLContext *h, struct sockaddr_storage *addr, else udp_fd = ff_socket(res->ai_family, SOCK_DGRAM, 0); if (udp_fd != -1) break; - log_net_error(NULL, AV_LOG_ERROR, "socket"); + ff_log_net_error(NULL, AV_LOG_ERROR, "socket"); } if (udp_fd < 0) @@ -459,7 +421,7 @@ int ff_udp_set_remote_url(URLContext *h, const char *uri) if (connect(s->udp_fd, (struct sockaddr *) &s->dest_addr, s->dest_addr_len)) { s->is_connected = 0; - log_net_error(h, AV_LOG_ERROR, "connect"); + ff_log_net_error(h, AV_LOG_ERROR, "connect"); return AVERROR(EIO); } } @@ -507,13 +469,15 @@ static void *circular_buffer_task_rx( void *_URLContext) } while(1) { int len; + struct sockaddr_storage addr; + socklen_t addr_len = sizeof(addr); pthread_mutex_unlock(&s->mutex); /* Blocking operations are always cancellation points; see "General Information" / "Thread Cancelation Overview" in Single Unix. */ pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &old_cancelstate); - len = recv(s->udp_fd, s->tmp+4, sizeof(s->tmp)-4, 0); + len = recvfrom(s->udp_fd, s->tmp+4, sizeof(s->tmp)-4, 0, (struct sockaddr *)&addr, &addr_len); pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &old_cancelstate); pthread_mutex_lock(&s->mutex); if (len < 0) { @@ -523,6 +487,8 @@ static void *circular_buffer_task_rx( void *_URLContext) } continue; } + if (ff_ip_check_source_lists(&addr, &s->filters)) + continue; AV_WL32(s->tmp, len); if(av_fifo_space(s->fifo) < len + 4) { @@ -653,27 +619,6 @@ end: #endif -static int parse_source_list(char *buf, char **sources, int *num_sources, - int max_sources) -{ - char *source_start; - - source_start = buf; - while (1) { - char *next = strchr(source_start, ','); - if (next) - *next = '\0'; - sources[*num_sources] = av_strdup(source_start); - if (!sources[*num_sources]) - return AVERROR(ENOMEM); - source_start = next + 1; - (*num_sources)++; - if (*num_sources >= max_sources || !next) - break; - } - return 0; -} - /* put it in UDP context */ /* return non zero if error */ static int udp_open(URLContext *h, const char *uri, int flags) @@ -686,8 +631,6 @@ static int udp_open(URLContext *h, const char *uri, int flags) char buf[256]; struct sockaddr_storage my_addr; socklen_t len; - int i, num_include_sources = 0, num_exclude_sources = 0; - char *include_sources[32], *exclude_sources[32]; h->is_streamed = 1; @@ -696,15 +639,12 @@ static int udp_open(URLContext *h, const char *uri, int flags) s->buffer_size = is_output ? UDP_TX_BUF_SIZE : UDP_MAX_PKT_SIZE; if (s->sources) { - if (parse_source_list(s->sources, include_sources, - &num_include_sources, - FF_ARRAY_ELEMS(include_sources))) + if (ff_ip_parse_sources(h, s->sources, &s->filters) < 0) goto fail; } if (s->block) { - if (parse_source_list(s->block, exclude_sources, &num_exclude_sources, - FF_ARRAY_ELEMS(exclude_sources))) + if (ff_ip_parse_blocks(h, s->block, &s->filters) < 0) goto fail; } @@ -773,13 +713,11 @@ static int udp_open(URLContext *h, const char *uri, int flags) av_strlcpy(localaddr, buf, sizeof(localaddr)); } if (av_find_info_tag(buf, sizeof(buf), "sources", p)) { - if (parse_source_list(buf, include_sources, &num_include_sources, - FF_ARRAY_ELEMS(include_sources))) + if (ff_ip_parse_sources(h, buf, &s->filters) < 0) goto fail; } if (av_find_info_tag(buf, sizeof(buf), "block", p)) { - if (parse_source_list(buf, exclude_sources, &num_exclude_sources, - FF_ARRAY_ELEMS(exclude_sources))) + if (ff_ip_parse_blocks(h, buf, &s->filters) < 0) goto fail; } if (!is_output && av_find_info_tag(buf, sizeof(buf), "timeout", p)) @@ -866,7 +804,7 @@ static int udp_open(URLContext *h, const char *uri, int flags) * bind failed */ /* the bind is needed to give a port to the socket now */ if (bind_ret < 0 && bind(udp_fd,(struct sockaddr *)&my_addr, len) < 0) { - log_net_error(h, AV_LOG_ERROR, "bind failed"); + ff_log_net_error(h, AV_LOG_ERROR, "bind failed"); goto fail; } @@ -882,27 +820,23 @@ static int udp_open(URLContext *h, const char *uri, int flags) } if (h->flags & AVIO_FLAG_READ) { /* input */ - if (num_include_sources && num_exclude_sources) { - av_log(h, AV_LOG_ERROR, "Simultaneously including and excluding multicast sources is not supported\n"); - goto fail; - } - if (num_include_sources) { + if (s->filters.nb_include_addrs) { if (udp_set_multicast_sources(h, udp_fd, (struct sockaddr *)&s->dest_addr, - s->dest_addr_len, - include_sources, - num_include_sources, 1) < 0) + s->dest_addr_len, &s->local_addr_storage, + s->filters.include_addrs, + s->filters.nb_include_addrs, 1) < 0) goto fail; } else { if (udp_join_multicast_group(udp_fd, (struct sockaddr *)&s->dest_addr,(struct sockaddr *)&s->local_addr_storage) < 0) goto fail; } - if (num_exclude_sources) { + if (s->filters.nb_exclude_addrs) { if (udp_set_multicast_sources(h, udp_fd, (struct sockaddr *)&s->dest_addr, - s->dest_addr_len, - exclude_sources, - num_exclude_sources, 0) < 0) + s->dest_addr_len, &s->local_addr_storage, + s->filters.exclude_addrs, + s->filters.nb_exclude_addrs, 0) < 0) goto fail; } } @@ -912,18 +846,18 @@ static int udp_open(URLContext *h, const char *uri, int flags) /* limit the tx buf size to limit latency */ tmp = s->buffer_size; if (setsockopt(udp_fd, SOL_SOCKET, SO_SNDBUF, &tmp, sizeof(tmp)) < 0) { - log_net_error(h, AV_LOG_ERROR, "setsockopt(SO_SNDBUF)"); + ff_log_net_error(h, AV_LOG_ERROR, "setsockopt(SO_SNDBUF)"); goto fail; } } else { /* set udp recv buffer size to the requested value (default 64K) */ tmp = s->buffer_size; if (setsockopt(udp_fd, SOL_SOCKET, SO_RCVBUF, &tmp, sizeof(tmp)) < 0) { - log_net_error(h, AV_LOG_WARNING, "setsockopt(SO_RECVBUF)"); + ff_log_net_error(h, AV_LOG_WARNING, "setsockopt(SO_RECVBUF)"); } len = sizeof(tmp); if (getsockopt(udp_fd, SOL_SOCKET, SO_RCVBUF, &tmp, &len) < 0) { - log_net_error(h, AV_LOG_WARNING, "getsockopt(SO_RCVBUF)"); + ff_log_net_error(h, AV_LOG_WARNING, "getsockopt(SO_RCVBUF)"); } else { av_log(h, AV_LOG_DEBUG, "end receive buffer size reported is %d\n", tmp); if(tmp < s->buffer_size) @@ -935,16 +869,11 @@ static int udp_open(URLContext *h, const char *uri, int flags) } if (s->is_connected) { if (connect(udp_fd, (struct sockaddr *) &s->dest_addr, s->dest_addr_len)) { - log_net_error(h, AV_LOG_ERROR, "connect"); + ff_log_net_error(h, AV_LOG_ERROR, "connect"); goto fail; } } - for (i = 0; i < num_include_sources; i++) - av_freep(&include_sources[i]); - for (i = 0; i < num_exclude_sources; i++) - av_freep(&exclude_sources[i]); - s->udp_fd = udp_fd; #if HAVE_PTHREAD_CANCEL @@ -994,10 +923,7 @@ static int udp_open(URLContext *h, const char *uri, int flags) if (udp_fd >= 0) closesocket(udp_fd); av_fifo_freep(&s->fifo); - for (i = 0; i < num_include_sources; i++) - av_freep(&include_sources[i]); - for (i = 0; i < num_exclude_sources; i++) - av_freep(&exclude_sources[i]); + ff_ip_reset_filters(&s->filters); return AVERROR(EIO); } @@ -1015,6 +941,8 @@ static int udp_read(URLContext *h, uint8_t *buf, int size) { UDPContext *s = h->priv_data; int ret; + struct sockaddr_storage addr; + socklen_t addr_len = sizeof(addr); #if HAVE_PTHREAD_CANCEL int avail, nonblock = h->flags & AVIO_FLAG_NONBLOCK; @@ -1065,9 +993,12 @@ static int udp_read(URLContext *h, uint8_t *buf, int size) if (ret < 0) return ret; } - ret = recv(s->udp_fd, buf, size, 0); - - return ret < 0 ? ff_neterrno() : ret; + ret = recvfrom(s->udp_fd, buf, size, 0, (struct sockaddr *)&addr, &addr_len); + if (ret < 0) + return ff_neterrno(); + if (ff_ip_check_source_lists(&addr, &s->filters)) + return AVERROR(EINTR); + return ret; } static int udp_write(URLContext *h, const uint8_t *buf, int size) @@ -1151,6 +1082,7 @@ static int udp_close(URLContext *h) #endif closesocket(s->udp_fd); av_fifo_freep(&s->fifo); + ff_ip_reset_filters(&s->filters); return 0; } diff --git a/libavformat/utils.c b/libavformat/utils.c index 58ecaabd8..6c6f4e1bd 100644 --- a/libavformat/utils.c +++ b/libavformat/utils.c @@ -357,7 +357,7 @@ static int set_codec_from_probe_data(AVFormatContext *s, AVStream *st, { 0 } }; int score; - AVInputFormat *fmt = av_probe_input_format3(pd, 1, &score); + const AVInputFormat *fmt = av_probe_input_format3(pd, 1, &score); if (fmt) { int i; @@ -535,7 +535,7 @@ FF_ENABLE_DEPRECATION_WARNINGS int avformat_open_input(AVFormatContext **ps, const char *filename, - AVInputFormat *fmt, AVDictionary **options) + ff_const59 AVInputFormat *fmt, AVDictionary **options) { AVFormatContext *s = *ps; int i, ret = 0; @@ -646,7 +646,7 @@ FF_ENABLE_DEPRECATION_WARNINGS if (id3v2_extra_meta) { if (!strcmp(s->iformat->name, "mp3") || !strcmp(s->iformat->name, "aac") || - !strcmp(s->iformat->name, "tta")) { + !strcmp(s->iformat->name, "tta") || !strcmp(s->iformat->name, "wav")) { if ((ret = ff_id3v2_parse_apic(s, &id3v2_extra_meta)) < 0) goto fail; if ((ret = ff_id3v2_parse_chapters(s, &id3v2_extra_meta)) < 0) @@ -1332,7 +1332,7 @@ static void compute_pkt_fields(AVFormatContext *s, AVStream *st, presentation_delayed = 1; if (s->debug & FF_FDEBUG_TS) - av_log(s, AV_LOG_TRACE, + av_log(s, AV_LOG_DEBUG, "IN delayed:%d pts:%s, dts:%s cur_dts:%s st:%d pc:%p duration:%"PRId64" delay:%d onein_oneout:%d\n", presentation_delayed, av_ts2str(pkt->pts), av_ts2str(pkt->dts), av_ts2str(st->cur_dts), pkt->stream_index, pc, pkt->duration, delay, onein_oneout); @@ -1402,11 +1402,11 @@ static void compute_pkt_fields(AVFormatContext *s, AVStream *st, st->cur_dts = pkt->dts; if (s->debug & FF_FDEBUG_TS) - av_log(s, AV_LOG_TRACE, "OUTdelayed:%d/%d pts:%s, dts:%s cur_dts:%s\n", - presentation_delayed, delay, av_ts2str(pkt->pts), av_ts2str(pkt->dts), av_ts2str(st->cur_dts)); + av_log(s, AV_LOG_DEBUG, "OUTdelayed:%d/%d pts:%s, dts:%s cur_dts:%s st:%d (%d)\n", + presentation_delayed, delay, av_ts2str(pkt->pts), av_ts2str(pkt->dts), av_ts2str(st->cur_dts), st->index, st->id); /* update flags */ - if (is_intra_only(st->codecpar->codec_id)) + if (st->codecpar->codec_type == AVMEDIA_TYPE_DATA || is_intra_only(st->codecpar->codec_id)) pkt->flags |= AV_PKT_FLAG_KEY; #if FF_API_CONVERGENCE_DURATION FF_DISABLE_DEPRECATION_WARNINGS @@ -2163,7 +2163,7 @@ static int64_t ff_read_timestamp(AVFormatContext *s, int stream_index, int64_t * int ff_seek_frame_binary(AVFormatContext *s, int stream_index, int64_t target_ts, int flags) { - AVInputFormat *avif = s->iformat; + const AVInputFormat *avif = s->iformat; int64_t av_uninit(pos_min), av_uninit(pos_max), pos, pos_limit; int64_t ts_min, ts_max, ts; int index; @@ -2667,7 +2667,7 @@ static void update_stream_timings(AVFormatContext *ic) duration = FFMAX(duration, duration1); } } - if (start_time == INT64_MAX || (start_time > start_time_text && start_time - start_time_text < AV_TIME_BASE)) + if (start_time == INT64_MAX || (start_time > start_time_text && start_time - (uint64_t)start_time_text < AV_TIME_BASE)) start_time = start_time_text; else if (start_time > start_time_text) av_log(ic, AV_LOG_VERBOSE, "Ignoring outlier non primary stream starttime %f\n", start_time_text / (float)AV_TIME_BASE); @@ -2813,6 +2813,11 @@ static void estimate_timings_from_pts(AVFormatContext *ic, int64_t old_offset) } } + if (ic->skip_estimate_duration_from_pts) { + av_log(ic, AV_LOG_INFO, "Skipping duration calculation in estimate_timings_from_pts\n"); + goto skip_duration_calc; + } + av_opt_set(ic, "skip_changes", "1", AV_OPT_SEARCH_CHILDREN); /* estimate the end time (duration) */ /* XXX: may need to support wrapping */ @@ -2897,6 +2902,7 @@ static void estimate_timings_from_pts(AVFormatContext *ic, int64_t old_offset) } } } +skip_duration_calc: fill_all_stream_timings(ic); avio_seek(ic->pb, old_offset, SEEK_SET); @@ -2947,6 +2953,7 @@ static void estimate_timings(AVFormatContext *ic, int64_t old_offset) AVStream av_unused *st; for (i = 0; i < ic->nb_streams; i++) { st = ic->streams[i]; + if (st->time_base.den) av_log(ic, AV_LOG_TRACE, "stream %d: start_time: %0.3f duration: %0.3f\n", i, (double) st->start_time * av_q2d(st->time_base), (double) st->duration * av_q2d(st->time_base)); @@ -3341,8 +3348,10 @@ int ff_rfps_add_frame(AVFormatContext *ic, AVStream *st, int64_t ts) } } } - st->info->duration_count++; - st->info->rfps_duration_sum += duration; + if (st->info->rfps_duration_sum <= INT64_MAX - duration) { + st->info->duration_count++; + st->info->rfps_duration_sum += duration; + } if (st->info->duration_count % 10 == 0) { int n = st->info->duration_count; @@ -3456,7 +3465,7 @@ static int extract_extradata_check(AVStream *st) static int extract_extradata_init(AVStream *st) { - AVStreamInternal *i = st->internal; + AVStreamInternal *sti = st->internal; const AVBitStreamFilter *f; int ret; @@ -3469,70 +3478,66 @@ static int extract_extradata_init(AVStream *st) if (!ret) goto finish; - i->extract_extradata.pkt = av_packet_alloc(); - if (!i->extract_extradata.pkt) + sti->extract_extradata.pkt = av_packet_alloc(); + if (!sti->extract_extradata.pkt) return AVERROR(ENOMEM); - ret = av_bsf_alloc(f, &i->extract_extradata.bsf); + ret = av_bsf_alloc(f, &sti->extract_extradata.bsf); if (ret < 0) goto fail; - ret = avcodec_parameters_copy(i->extract_extradata.bsf->par_in, + ret = avcodec_parameters_copy(sti->extract_extradata.bsf->par_in, st->codecpar); if (ret < 0) goto fail; - i->extract_extradata.bsf->time_base_in = st->time_base; + sti->extract_extradata.bsf->time_base_in = st->time_base; - /* if init fails here, we assume extracting extradata is just not - * supported for this codec, so we return success */ - ret = av_bsf_init(i->extract_extradata.bsf); - if (ret < 0) { - av_bsf_free(&i->extract_extradata.bsf); - ret = 0; - } + ret = av_bsf_init(sti->extract_extradata.bsf); + if (ret < 0) + goto fail; finish: - i->extract_extradata.inited = 1; + sti->extract_extradata.inited = 1; return 0; fail: - av_bsf_free(&i->extract_extradata.bsf); - av_packet_free(&i->extract_extradata.pkt); + av_bsf_free(&sti->extract_extradata.bsf); + av_packet_free(&sti->extract_extradata.pkt); return ret; } static int extract_extradata(AVStream *st, AVPacket *pkt) { - AVStreamInternal *i = st->internal; + AVStreamInternal *sti = st->internal; AVPacket *pkt_ref; int ret; - if (!i->extract_extradata.inited) { + if (!sti->extract_extradata.inited) { ret = extract_extradata_init(st); if (ret < 0) return ret; } - if (i->extract_extradata.inited && !i->extract_extradata.bsf) + if (sti->extract_extradata.inited && !sti->extract_extradata.bsf) return 0; - pkt_ref = i->extract_extradata.pkt; + pkt_ref = sti->extract_extradata.pkt; ret = av_packet_ref(pkt_ref, pkt); if (ret < 0) return ret; - ret = av_bsf_send_packet(i->extract_extradata.bsf, pkt_ref); + ret = av_bsf_send_packet(sti->extract_extradata.bsf, pkt_ref); if (ret < 0) { av_packet_unref(pkt_ref); return ret; } - while (ret >= 0 && !i->avctx->extradata) { + while (ret >= 0 && !sti->avctx->extradata) { int extradata_size; uint8_t *extradata; - ret = av_bsf_receive_packet(i->extract_extradata.bsf, pkt_ref); + ret = av_bsf_receive_packet(sti->extract_extradata.bsf, pkt_ref); if (ret < 0) { if (ret != AVERROR(EAGAIN) && ret != AVERROR_EOF) return ret; @@ -3543,15 +3548,15 @@ static int extract_extradata(AVStream *st, AVPacket *pkt) &extradata_size); if (extradata) { - av_assert0(!i->avctx->extradata); + av_assert0(!sti->avctx->extradata); if ((unsigned)extradata_size < FF_MAX_EXTRADATA_SIZE) - i->avctx->extradata = av_mallocz(extradata_size + AV_INPUT_BUFFER_PADDING_SIZE); - if (!i->avctx->extradata) { + sti->avctx->extradata = av_mallocz(extradata_size + AV_INPUT_BUFFER_PADDING_SIZE); + if (!sti->avctx->extradata) { av_packet_unref(pkt_ref); return AVERROR(ENOMEM); } - memcpy(i->avctx->extradata, extradata, extradata_size); - i->avctx->extradata_size = extradata_size; + memcpy(sti->avctx->extradata, extradata, extradata_size); + sti->avctx->extradata_size = extradata_size; } av_packet_unref(pkt_ref); } @@ -3866,7 +3871,7 @@ FF_ENABLE_DEPRECATION_WARNINGS break; } if (pkt->duration) { - if (avctx->codec_type == AVMEDIA_TYPE_SUBTITLE && pkt->pts != AV_NOPTS_VALUE && pkt->pts >= st->start_time) { + if (avctx->codec_type == AVMEDIA_TYPE_SUBTITLE && pkt->pts != AV_NOPTS_VALUE && st->start_time != AV_NOPTS_VALUE && pkt->pts >= st->start_time) { st->info->codec_info_duration = FFMIN(pkt->pts - st->start_time, st->info->codec_info_duration + pkt->duration); } else st->info->codec_info_duration += pkt->duration; @@ -4216,7 +4221,8 @@ int av_find_best_stream(AVFormatContext *ic, enum AVMediaType type, continue; } } - disposition = !(st->disposition & (AV_DISPOSITION_HEARING_IMPAIRED | AV_DISPOSITION_VISUAL_IMPAIRED)); + disposition = !(st->disposition & (AV_DISPOSITION_HEARING_IMPAIRED | AV_DISPOSITION_VISUAL_IMPAIRED)) + + !! (st->disposition & AV_DISPOSITION_DEFAULT); count = st->codec_info_nb_frames; bitrate = par->bit_rate; multiframe = FFMIN(5, count); @@ -4566,6 +4572,7 @@ AVProgram *av_new_program(AVFormatContext *ac, int id) return NULL; dynarray_add(&ac->programs, &ac->nb_programs, program); program->discard = AVDISCARD_NONE; + program->pmt_version = -1; } program->id = id; program->pts_wrap_reference = AV_NOPTS_VALUE; @@ -4640,6 +4647,28 @@ uint64_t ff_ntp_time(void) return (av_gettime() / 1000) * 1000 + NTP_OFFSET_US; } +uint64_t ff_get_formatted_ntp_time(uint64_t ntp_time_us) +{ + uint64_t ntp_ts, frac_part, sec; + uint32_t usec; + + //current ntp time in seconds and micro seconds + sec = ntp_time_us / 1000000; + usec = ntp_time_us % 1000000; + + //encoding in ntp timestamp format + frac_part = usec * 0xFFFFFFFFULL; + frac_part /= 1000000; + + if (sec > 0xFFFFFFFFULL) + av_log(NULL, AV_LOG_WARNING, "NTP time format roll over detected\n"); + + ntp_ts = sec << 32; + ntp_ts |= frac_part; + + return ntp_ts; +} + int av_get_frame_filename2(char *buf, int buf_size, const char *path, int number, int flags) { const char *p; @@ -4771,6 +4800,40 @@ void av_url_split(char *proto, int proto_size, } } +int ff_mkdir_p(const char *path) +{ + int ret = 0; + char *temp = av_strdup(path); + char *pos = temp; + char tmp_ch = '\0'; + + if (!path || !temp) { + return -1; + } + + if (!av_strncasecmp(temp, "/", 1) || !av_strncasecmp(temp, "\\", 1)) { + pos++; + } else if (!av_strncasecmp(temp, "./", 2) || !av_strncasecmp(temp, ".\\", 2)) { + pos += 2; + } + + for ( ; *pos != '\0'; ++pos) { + if (*pos == '/' || *pos == '\\') { + tmp_ch = *pos; + *pos = '\0'; + ret = mkdir(temp, 0755); + *pos = tmp_ch; + } + } + + if ((*(pos - 1) != '/') || (*(pos - 1) != '\\')) { + ret = mkdir(temp, 0755); + } + + av_free(temp); + return ret; +} + char *ff_data_to_hex(char *buff, const uint8_t *src, int s, int lowercase) { int i; @@ -5038,244 +5101,211 @@ AVRational av_guess_frame_rate(AVFormatContext *format, AVStream *st, AVFrame *f return fr; } +/** + * Matches a stream specifier (but ignores requested index). + * + * @param indexptr set to point to the requested stream index if there is one + * + * @return <0 on error + * 0 if st is NOT a matching stream + * >0 if st is a matching stream + */ +static int match_stream_specifier(AVFormatContext *s, AVStream *st, + const char *spec, const char **indexptr, AVProgram **p) +{ + int match = 1; /* Stores if the specifier matches so far. */ + while (*spec) { + if (*spec <= '9' && *spec >= '0') { /* opt:index */ + if (indexptr) + *indexptr = spec; + return match; + } else if (*spec == 'v' || *spec == 'a' || *spec == 's' || *spec == 'd' || + *spec == 't' || *spec == 'V') { /* opt:[vasdtV] */ + enum AVMediaType type; + int nopic = 0; + + switch (*spec++) { + case 'v': type = AVMEDIA_TYPE_VIDEO; break; + case 'a': type = AVMEDIA_TYPE_AUDIO; break; + case 's': type = AVMEDIA_TYPE_SUBTITLE; break; + case 'd': type = AVMEDIA_TYPE_DATA; break; + case 't': type = AVMEDIA_TYPE_ATTACHMENT; break; + case 'V': type = AVMEDIA_TYPE_VIDEO; nopic = 1; break; + default: av_assert0(0); + } + if (*spec && *spec++ != ':') /* If we are not at the end, then another specifier must follow. */ + return AVERROR(EINVAL); + +#if FF_API_LAVF_AVCTX +FF_DISABLE_DEPRECATION_WARNINGS + if (type != st->codecpar->codec_type + && (st->codecpar->codec_type != AVMEDIA_TYPE_UNKNOWN || st->codec->codec_type != type)) + match = 0; + FF_ENABLE_DEPRECATION_WARNINGS +#else + if (type != st->codecpar->codec_type) + match = 0; +#endif + if (nopic && (st->disposition & AV_DISPOSITION_ATTACHED_PIC)) + match = 0; + } else if (*spec == 'p' && *(spec + 1) == ':') { + int prog_id, i, j; + int found = 0; + char *endptr; + spec += 2; + prog_id = strtol(spec, &endptr, 0); + /* Disallow empty id and make sure that if we are not at the end, then another specifier must follow. */ + if (spec == endptr || (*endptr && *endptr++ != ':')) + return AVERROR(EINVAL); + spec = endptr; + if (match) { + for (i = 0; i < s->nb_programs; i++) { + if (s->programs[i]->id != prog_id) + continue; + + for (j = 0; j < s->programs[i]->nb_stream_indexes; j++) { + if (st->index == s->programs[i]->stream_index[j]) { + found = 1; + if (p) + *p = s->programs[i]; + i = s->nb_programs; + break; + } + } + } + } + if (!found) + match = 0; + } else if (*spec == '#' || + (*spec == 'i' && *(spec + 1) == ':')) { + int stream_id; + char *endptr; + spec += 1 + (*spec == 'i'); + stream_id = strtol(spec, &endptr, 0); + if (spec == endptr || *endptr) /* Disallow empty id and make sure we are at the end. */ + return AVERROR(EINVAL); + return match && (stream_id == st->id); + } else if (*spec == 'm' && *(spec + 1) == ':') { + AVDictionaryEntry *tag; + char *key, *val; + int ret; + + if (match) { + spec += 2; + val = strchr(spec, ':'); + + key = val ? av_strndup(spec, val - spec) : av_strdup(spec); + if (!key) + return AVERROR(ENOMEM); + + tag = av_dict_get(st->metadata, key, NULL, 0); + if (tag) { + if (!val || !strcmp(tag->value, val + 1)) + ret = 1; + else + ret = 0; + } else + ret = 0; + + av_freep(&key); + } + return match && ret; + } else if (*spec == 'u' && *(spec + 1) == '\0') { + AVCodecParameters *par = st->codecpar; +#if FF_API_LAVF_AVCTX +FF_DISABLE_DEPRECATION_WARNINGS + AVCodecContext *codec = st->codec; +FF_ENABLE_DEPRECATION_WARNINGS +#endif + int val; + switch (par->codec_type) { + case AVMEDIA_TYPE_AUDIO: + val = par->sample_rate && par->channels; +#if FF_API_LAVF_AVCTX + val = val || (codec->sample_rate && codec->channels); +#endif + if (par->format == AV_SAMPLE_FMT_NONE +#if FF_API_LAVF_AVCTX + && codec->sample_fmt == AV_SAMPLE_FMT_NONE +#endif + ) + return 0; + break; + case AVMEDIA_TYPE_VIDEO: + val = par->width && par->height; +#if FF_API_LAVF_AVCTX + val = val || (codec->width && codec->height); +#endif + if (par->format == AV_PIX_FMT_NONE +#if FF_API_LAVF_AVCTX + && codec->pix_fmt == AV_PIX_FMT_NONE +#endif + ) + return 0; + break; + case AVMEDIA_TYPE_UNKNOWN: + val = 0; + break; + default: + val = 1; + break; + } +#if FF_API_LAVF_AVCTX + return match && ((par->codec_id != AV_CODEC_ID_NONE || codec->codec_id != AV_CODEC_ID_NONE) && val != 0); +#else + return match && (par->codec_id != AV_CODEC_ID_NONE && val != 0); +#endif + } else { + return AVERROR(EINVAL); + } + } + + return match; +} + + int avformat_match_stream_specifier(AVFormatContext *s, AVStream *st, const char *spec) { - if (*spec <= '9' && *spec >= '0') /* opt:index */ - return strtol(spec, NULL, 0) == st->index; - else if (*spec == 'v' || *spec == 'a' || *spec == 's' || *spec == 'd' || - *spec == 't' || *spec == 'V') { /* opt:[vasdtV] */ - enum AVMediaType type; - int nopic = 0; + int ret, index; + char *endptr; + const char *indexptr = NULL; + AVProgram *p = NULL; + int nb_streams; - switch (*spec++) { - case 'v': type = AVMEDIA_TYPE_VIDEO; break; - case 'a': type = AVMEDIA_TYPE_AUDIO; break; - case 's': type = AVMEDIA_TYPE_SUBTITLE; break; - case 'd': type = AVMEDIA_TYPE_DATA; break; - case 't': type = AVMEDIA_TYPE_ATTACHMENT; break; - case 'V': type = AVMEDIA_TYPE_VIDEO; nopic = 1; break; - default: av_assert0(0); - } -#if FF_API_LAVF_AVCTX -FF_DISABLE_DEPRECATION_WARNINGS - if (type != st->codecpar->codec_type - && (st->codecpar->codec_type != AVMEDIA_TYPE_UNKNOWN || st->codec->codec_type != type)) - return 0; -FF_ENABLE_DEPRECATION_WARNINGS -#else - if (type != st->codecpar->codec_type) - return 0; -#endif - if (nopic && (st->disposition & AV_DISPOSITION_ATTACHED_PIC)) - return 0; - if (*spec++ == ':') { /* possibly followed by :index */ - int i, index = strtol(spec, NULL, 0); - for (i = 0; i < s->nb_streams; i++) { -#if FF_API_LAVF_AVCTX -FF_DISABLE_DEPRECATION_WARNINGS - if ((s->streams[i]->codecpar->codec_type == type - || s->streams[i]->codec->codec_type == type - ) && - !(nopic && (st->disposition & AV_DISPOSITION_ATTACHED_PIC)) && - index-- == 0) - return i == st->index; -FF_ENABLE_DEPRECATION_WARNINGS -#else - if ((s->streams[i]->codecpar->codec_type == type) && - !(nopic && (st->disposition & AV_DISPOSITION_ATTACHED_PIC)) && - index-- == 0) - return i == st->index; -#endif - } - return 0; - } - return 1; - } else if (*spec == 'p' && *(spec + 1) == ':') { - int prog_id, i, j; - char *endptr; - spec += 2; - prog_id = strtol(spec, &endptr, 0); - for (i = 0; i < s->nb_programs; i++) { - if (s->programs[i]->id != prog_id) - continue; + ret = match_stream_specifier(s, st, spec, &indexptr, &p); + if (ret < 0) + goto error; - if (*endptr++ == ':') { // p::.... - if ( *endptr == 'a' || *endptr == 'v' || - *endptr == 's' || *endptr == 'd') { // p::[:] - enum AVMediaType type; - - switch (*endptr++) { - case 'v': type = AVMEDIA_TYPE_VIDEO; break; - case 'a': type = AVMEDIA_TYPE_AUDIO; break; - case 's': type = AVMEDIA_TYPE_SUBTITLE; break; - case 'd': type = AVMEDIA_TYPE_DATA; break; - default: av_assert0(0); - } - if (*endptr++ == ':') { // p::: - int stream_idx = strtol(endptr, NULL, 0), type_counter = 0; - for (j = 0; j < s->programs[i]->nb_stream_indexes; j++) { - int stream_index = s->programs[i]->stream_index[j]; - if (st->index == s->programs[i]->stream_index[j]) { -#if FF_API_LAVF_AVCTX -FF_DISABLE_DEPRECATION_WARNINGS - return type_counter == stream_idx && - (type == st->codecpar->codec_type || - type == st->codec->codec_type); -FF_ENABLE_DEPRECATION_WARNINGS -#else - return type_counter == stream_idx && - type == st->codecpar->codec_type; -#endif - } -#if FF_API_LAVF_AVCTX -FF_DISABLE_DEPRECATION_WARNINGS - if (type == s->streams[stream_index]->codecpar->codec_type || - type == s->streams[stream_index]->codec->codec_type) - type_counter++; -FF_ENABLE_DEPRECATION_WARNINGS -#else - if (type == s->streams[stream_index]->codecpar->codec_type) - type_counter++; -#endif - } - return 0; - } else { // p:: - for (j = 0; j < s->programs[i]->nb_stream_indexes; j++) - if (st->index == s->programs[i]->stream_index[j]) { -#if FF_API_LAVF_AVCTX -FF_DISABLE_DEPRECATION_WARNINGS - return type == st->codecpar->codec_type || - type == st->codec->codec_type; -FF_ENABLE_DEPRECATION_WARNINGS -#else - return type == st->codecpar->codec_type; -#endif - } - return 0; - } - - } else if ( *endptr == 'm') { // p::m: - AVDictionaryEntry *tag; - char *key, *val; - int ret = 0; - - if (*(++endptr) != ':') { - av_log(s, AV_LOG_ERROR, "Invalid stream specifier syntax, missing ':' sign after :m.\n"); - return AVERROR(EINVAL); - } - - val = strchr(++endptr, ':'); - key = val ? av_strndup(endptr, val - endptr) : av_strdup(endptr); - if (!key) - return AVERROR(ENOMEM); - - for (j = 0; j < s->programs[i]->nb_stream_indexes; j++) - if (st->index == s->programs[i]->stream_index[j]) { - tag = av_dict_get(st->metadata, key, NULL, 0); - if (tag && (!val || !strcmp(tag->value, val + 1))) - ret = 1; - - break; - } - - av_freep(&key); - return ret; - - } else { // p:: - int stream_idx = strtol(endptr, NULL, 0); - return stream_idx >= 0 && - stream_idx < s->programs[i]->nb_stream_indexes && - st->index == s->programs[i]->stream_index[stream_idx]; - } - } - - for (j = 0; j < s->programs[i]->nb_stream_indexes; j++) - if (st->index == s->programs[i]->stream_index[j]) - return 1; - } - return 0; - } else if (*spec == '#' || - (*spec == 'i' && *(spec + 1) == ':')) { - int stream_id; - char *endptr; - spec += 1 + (*spec == 'i'); - stream_id = strtol(spec, &endptr, 0); - if (!*endptr) - return stream_id == st->id; - } else if (*spec == 'm' && *(spec + 1) == ':') { - AVDictionaryEntry *tag; - char *key, *val; - int ret; - - spec += 2; - val = strchr(spec, ':'); - - key = val ? av_strndup(spec, val - spec) : av_strdup(spec); - if (!key) - return AVERROR(ENOMEM); - - tag = av_dict_get(st->metadata, key, NULL, 0); - if (tag) { - if (!val || !strcmp(tag->value, val + 1)) - ret = 1; - else - ret = 0; - } else - ret = 0; - - av_freep(&key); + if (!indexptr) return ret; - } else if (*spec == 'u') { - AVCodecParameters *par = st->codecpar; -#if FF_API_LAVF_AVCTX -FF_DISABLE_DEPRECATION_WARNINGS - AVCodecContext *codec = st->codec; -FF_ENABLE_DEPRECATION_WARNINGS -#endif - int val; - switch (par->codec_type) { - case AVMEDIA_TYPE_AUDIO: - val = par->sample_rate && par->channels; -#if FF_API_LAVF_AVCTX - val = val || (codec->sample_rate && codec->channels); -#endif - if (par->format == AV_SAMPLE_FMT_NONE -#if FF_API_LAVF_AVCTX - && codec->sample_fmt == AV_SAMPLE_FMT_NONE -#endif - ) - return 0; - break; - case AVMEDIA_TYPE_VIDEO: - val = par->width && par->height; -#if FF_API_LAVF_AVCTX - val = val || (codec->width && codec->height); -#endif - if (par->format == AV_PIX_FMT_NONE -#if FF_API_LAVF_AVCTX - && codec->pix_fmt == AV_PIX_FMT_NONE -#endif - ) - return 0; - break; - case AVMEDIA_TYPE_UNKNOWN: - val = 0; - break; - default: - val = 1; - break; - } -#if FF_API_LAVF_AVCTX - return (par->codec_id != AV_CODEC_ID_NONE || codec->codec_id != AV_CODEC_ID_NONE) && val != 0; -#else - return par->codec_id != AV_CODEC_ID_NONE && val != 0; -#endif - } else if (!*spec) /* empty specifier, matches everything */ - return 1; - av_log(s, AV_LOG_ERROR, "Invalid stream specifier: %s.\n", spec); - return AVERROR(EINVAL); + index = strtol(indexptr, &endptr, 0); + if (*endptr) { /* We can't have anything after the requested index. */ + ret = AVERROR(EINVAL); + goto error; + } + + /* This is not really needed but saves us a loop for simple stream index specifiers. */ + if (spec == indexptr) + return (index == st->index); + + /* If we requested a matching stream index, we have to ensure st is that. */ + nb_streams = p ? p->nb_stream_indexes : s->nb_streams; + for (int i = 0; i < nb_streams && index >= 0; i++) { + AVStream *candidate = p ? s->streams[p->stream_index[i]] : s->streams[i]; + ret = match_stream_specifier(s, candidate, spec, NULL, NULL); + if (ret < 0) + goto error; + if (ret > 0 && index-- == 0 && st == candidate) + return 1; + } + return 0; + +error: + if (ret == AVERROR(EINVAL)) + av_log(s, AV_LOG_ERROR, "Invalid stream specifier: %s.\n", spec); + return ret; } int ff_generate_avci_extradata(AVStream *st) diff --git a/libavformat/vag.c b/libavformat/vag.c index e8ebcaffd..51045e6fe 100644 --- a/libavformat/vag.c +++ b/libavformat/vag.c @@ -23,7 +23,7 @@ #include "avformat.h" #include "internal.h" -static int vag_probe(AVProbeData *p) +static int vag_probe(const AVProbeData *p) { if (memcmp(p->buf, "VAGp\0\0\0", 7)) return 0; diff --git a/libavformat/vapoursynth.c b/libavformat/vapoursynth.c new file mode 100644 index 000000000..46e08ee0f --- /dev/null +++ b/libavformat/vapoursynth.c @@ -0,0 +1,496 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** +* @file +* VapourSynth demuxer +* +* Synthesizes vapour (?) +*/ + +#include + +#include +#include + +#include "libavutil/avassert.h" +#include "libavutil/avstring.h" +#include "libavutil/eval.h" +#include "libavutil/imgutils.h" +#include "libavutil/opt.h" +#include "libavutil/pixdesc.h" +#include "avformat.h" +#include "internal.h" + +struct VSState { + VSScript *vss; +}; + +typedef struct VSContext { + const AVClass *class; + + AVBufferRef *vss_state; + + const VSAPI *vsapi; + VSCore *vscore; + + VSNodeRef *outnode; + int is_cfr; + int current_frame; + + int c_order[4]; + + /* options */ + int64_t max_script_size; +} VSContext; + +#define OFFSET(x) offsetof(VSContext, x) +#define A AV_OPT_FLAG_AUDIO_PARAM +#define D AV_OPT_FLAG_DECODING_PARAM +static const AVOption options[] = { + {"max_script_size", "set max file size supported (in bytes)", OFFSET(max_script_size), AV_OPT_TYPE_INT64, {.i64 = 1 * 1024 * 1024}, 0, SIZE_MAX - 1, A|D}, + {NULL} +}; + +static void free_vss_state(void *opaque, uint8_t *data) +{ + struct VSState *vss = opaque; + + if (vss->vss) { + vsscript_freeScript(vss->vss); + vsscript_finalize(); + } +} + +static av_cold int read_close_vs(AVFormatContext *s) +{ + VSContext *vs = s->priv_data; + + if (vs->outnode) + vs->vsapi->freeNode(vs->outnode); + + av_buffer_unref(&vs->vss_state); + + vs->vsapi = NULL; + vs->vscore = NULL; + vs->outnode = NULL; + + return 0; +} + +static av_cold int is_native_endian(enum AVPixelFormat pixfmt) +{ + enum AVPixelFormat other = av_pix_fmt_swap_endianness(pixfmt); + const AVPixFmtDescriptor *pd; + if (other == AV_PIX_FMT_NONE || other == pixfmt) + return 1; // not affected by byte order + pd = av_pix_fmt_desc_get(pixfmt); + return pd && (!!HAVE_BIGENDIAN == !!(pd->flags & AV_PIX_FMT_FLAG_BE)); +} + +static av_cold enum AVPixelFormat match_pixfmt(const VSFormat *vsf, int c_order[4]) +{ + static const int yuv_order[4] = {0, 1, 2, 0}; + static const int rgb_order[4] = {1, 2, 0, 0}; + const AVPixFmtDescriptor *pd; + + for (pd = av_pix_fmt_desc_next(NULL); pd; pd = av_pix_fmt_desc_next(pd)) { + int is_rgb, is_yuv, i; + const int *order; + enum AVPixelFormat pixfmt; + + pixfmt = av_pix_fmt_desc_get_id(pd); + + if (pd->flags & (AV_PIX_FMT_FLAG_BAYER | AV_PIX_FMT_FLAG_ALPHA | + AV_PIX_FMT_FLAG_HWACCEL | AV_PIX_FMT_FLAG_BITSTREAM)) + continue; + + if (pd->log2_chroma_w != vsf->subSamplingW || + pd->log2_chroma_h != vsf->subSamplingH) + continue; + + is_rgb = vsf->colorFamily == cmRGB; + if (is_rgb != !!(pd->flags & AV_PIX_FMT_FLAG_RGB)) + continue; + + is_yuv = vsf->colorFamily == cmYUV || + vsf->colorFamily == cmYCoCg || + vsf->colorFamily == cmGray; + if (!is_rgb && !is_yuv) + continue; + + if (vsf->sampleType != ((pd->flags & AV_PIX_FMT_FLAG_FLOAT) ? stFloat : stInteger)) + continue; + + if (av_pix_fmt_count_planes(pixfmt) != vsf->numPlanes) + continue; + + if (strncmp(pd->name, "xyz", 3) == 0) + continue; + + if (!is_native_endian(pixfmt)) + continue; + + order = is_yuv ? yuv_order : rgb_order; + + for (i = 0; i < pd->nb_components; i++) { + const AVComponentDescriptor *c = &pd->comp[i]; + if (order[c->plane] != i || + c->offset != 0 || c->shift != 0 || + c->step != vsf->bytesPerSample || + c->depth != vsf->bitsPerSample) + goto cont; + } + + // Use it. + memcpy(c_order, order, sizeof(int[4])); + return pixfmt; + + cont: ; + } + + return AV_PIX_FMT_NONE; +} + +static av_cold int read_header_vs(AVFormatContext *s) +{ + AVStream *st; + AVIOContext *pb = s->pb; + VSContext *vs = s->priv_data; + int64_t sz = avio_size(pb); + char *buf = NULL; + char dummy; + const VSVideoInfo *info; + struct VSState *vss_state; + int err = 0; + + vss_state = av_mallocz(sizeof(*vss_state)); + if (!vss_state) { + err = AVERROR(ENOMEM); + goto done; + } + + vs->vss_state = av_buffer_create(NULL, 0, free_vss_state, vss_state, 0); + if (!vs->vss_state) { + err = AVERROR(ENOMEM); + av_free(vss_state); + goto done; + } + + if (!vsscript_init()) { + av_log(s, AV_LOG_ERROR, "Failed to initialize VSScript (possibly PYTHONPATH not set).\n"); + err = AVERROR_EXTERNAL; + goto done; + } + + if (vsscript_createScript(&vss_state->vss)) { + av_log(s, AV_LOG_ERROR, "Failed to create script instance.\n"); + err = AVERROR_EXTERNAL; + vsscript_finalize(); + goto done; + } + + if (sz < 0 || sz > vs->max_script_size) { + if (sz < 0) + av_log(s, AV_LOG_WARNING, "Could not determine file size\n"); + sz = vs->max_script_size; + } + + buf = av_malloc(sz + 1); + if (!buf) { + err = AVERROR(ENOMEM); + goto done; + } + sz = avio_read(pb, buf, sz); + + if (sz < 0) { + av_log(s, AV_LOG_ERROR, "Could not read script.\n"); + err = sz; + goto done; + } + + // Data left means our buffer (the max_script_size option) is too small + if (avio_read(pb, &dummy, 1) == 1) { + av_log(s, AV_LOG_ERROR, "File size is larger than max_script_size option " + "value %"PRIi64", consider increasing the max_script_size option\n", + vs->max_script_size); + err = AVERROR_BUFFER_TOO_SMALL; + goto done; + } + + buf[sz] = '\0'; + if (vsscript_evaluateScript(&vss_state->vss, buf, s->url, 0)) { + const char *msg = vsscript_getError(vss_state->vss); + av_log(s, AV_LOG_ERROR, "Failed to parse script: %s\n", msg ? msg : "(unknown)"); + err = AVERROR_EXTERNAL; + goto done; + } + + vs->vsapi = vsscript_getVSApi(); + vs->vscore = vsscript_getCore(vss_state->vss); + + vs->outnode = vsscript_getOutput(vss_state->vss, 0); + if (!vs->outnode) { + av_log(s, AV_LOG_ERROR, "Could not get script output node.\n"); + err = AVERROR_EXTERNAL; + goto done; + } + + st = avformat_new_stream(s, NULL); + if (!st) { + err = AVERROR(ENOMEM); + goto done; + } + + info = vs->vsapi->getVideoInfo(vs->outnode); + + if (!info->format || !info->width || !info->height) { + av_log(s, AV_LOG_ERROR, "Non-constant input format not supported.\n"); + err = AVERROR_PATCHWELCOME; + goto done; + } + + if (info->fpsDen) { + vs->is_cfr = 1; + avpriv_set_pts_info(st, 64, info->fpsDen, info->fpsNum); + st->duration = info->numFrames; + } else { + // VFR. Just set "something". + avpriv_set_pts_info(st, 64, 1, AV_TIME_BASE); + s->ctx_flags |= AVFMTCTX_UNSEEKABLE; + } + + st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO; + st->codecpar->codec_id = AV_CODEC_ID_WRAPPED_AVFRAME; + st->codecpar->width = info->width; + st->codecpar->height = info->height; + st->codecpar->format = match_pixfmt(info->format, vs->c_order); + + if (st->codecpar->format == AV_PIX_FMT_NONE) { + av_log(s, AV_LOG_ERROR, "Unsupported VS pixel format %s\n", info->format->name); + err = AVERROR_EXTERNAL; + goto done; + } + av_log(s, AV_LOG_VERBOSE, "VS format %s -> pixfmt %s\n", info->format->name, + av_get_pix_fmt_name(st->codecpar->format)); + + if (info->format->colorFamily == cmYCoCg) + st->codecpar->color_space = AVCOL_SPC_YCGCO; + +done: + av_free(buf); + if (err < 0) + read_close_vs(s); + return err; +} + +static void free_frame(void *opaque, uint8_t *data) +{ + AVFrame *frame = (AVFrame *)data; + + av_frame_free(&frame); +} + +static int get_vs_prop_int(AVFormatContext *s, const VSMap *map, const char *name, int def) +{ + VSContext *vs = s->priv_data; + int64_t res; + int err = 1; + + res = vs->vsapi->propGetInt(map, name, 0, &err); + return err || res < INT_MIN || res > INT_MAX ? def : res; +} + +struct vsframe_ref_data { + const VSAPI *vsapi; + const VSFrameRef *frame; + AVBufferRef *vss_state; +}; + +static void free_vsframe_ref(void *opaque, uint8_t *data) +{ + struct vsframe_ref_data *d = opaque; + + if (d->frame) + d->vsapi->freeFrame(d->frame); + + av_buffer_unref(&d->vss_state); + + av_free(d); +} + +static int read_packet_vs(AVFormatContext *s, AVPacket *pkt) +{ + VSContext *vs = s->priv_data; + AVStream *st = s->streams[0]; + AVFrame *frame = NULL; + char vserr[80]; + const VSFrameRef *vsframe; + const VSVideoInfo *info = vs->vsapi->getVideoInfo(vs->outnode); + const VSMap *props; + const AVPixFmtDescriptor *desc; + AVBufferRef *vsframe_ref = NULL; + struct vsframe_ref_data *ref_data; + int err = 0; + int i; + + if (vs->current_frame >= info->numFrames) + return AVERROR_EOF; + + ref_data = av_mallocz(sizeof(*ref_data)); + if (!ref_data) { + err = AVERROR(ENOMEM); + goto end; + } + + // (the READONLY flag is important because the ref is reused for plane data) + vsframe_ref = av_buffer_create(NULL, 0, free_vsframe_ref, ref_data, AV_BUFFER_FLAG_READONLY); + if (!vsframe_ref) { + err = AVERROR(ENOMEM); + av_free(ref_data); + goto end; + } + + vsframe = vs->vsapi->getFrame(vs->current_frame, vs->outnode, vserr, sizeof(vserr)); + if (!vsframe) { + av_log(s, AV_LOG_ERROR, "Error getting frame: %s\n", vserr); + err = AVERROR_EXTERNAL; + goto end; + } + + ref_data->vsapi = vs->vsapi; + ref_data->frame = vsframe; + + ref_data->vss_state = av_buffer_ref(vs->vss_state); + if (!ref_data->vss_state) { + err = AVERROR(ENOMEM); + goto end; + } + + props = vs->vsapi->getFramePropsRO(vsframe); + + frame = av_frame_alloc(); + if (!frame) { + err = AVERROR(ENOMEM); + goto end; + } + + frame->format = st->codecpar->format; + frame->width = st->codecpar->width; + frame->height = st->codecpar->height; + frame->colorspace = st->codecpar->color_space; + + // Values according to ISO/IEC 14496-10. + frame->colorspace = get_vs_prop_int(s, props, "_Matrix", frame->colorspace); + frame->color_primaries = get_vs_prop_int(s, props, "_Primaries", frame->color_primaries); + frame->color_trc = get_vs_prop_int(s, props, "_Transfer", frame->color_trc); + + if (get_vs_prop_int(s, props, "_ColorRange", 1) == 0) + frame->color_range = AVCOL_RANGE_JPEG; + + frame->sample_aspect_ratio.num = get_vs_prop_int(s, props, "_SARNum", 0); + frame->sample_aspect_ratio.den = get_vs_prop_int(s, props, "_SARDen", 1); + + av_assert0(vs->vsapi->getFrameWidth(vsframe, 0) == frame->width); + av_assert0(vs->vsapi->getFrameHeight(vsframe, 0) == frame->height); + + desc = av_pix_fmt_desc_get(frame->format); + + for (i = 0; i < info->format->numPlanes; i++) { + int p = vs->c_order[i]; + ptrdiff_t plane_h = frame->height; + + frame->data[i] = (void *)vs->vsapi->getReadPtr(vsframe, p); + frame->linesize[i] = vs->vsapi->getStride(vsframe, p); + + frame->buf[i] = av_buffer_ref(vsframe_ref); + if (!frame->buf[i]) { + err = AVERROR(ENOMEM); + goto end; + } + + // Each plane needs an AVBufferRef that indicates the correct plane + // memory range. VapourSynth doesn't even give us the memory range, + // so make up a bad guess to make FFmpeg happy (even if almost nothing + // checks the memory range). + if (i == 1 || i == 2) + plane_h = AV_CEIL_RSHIFT(plane_h, desc->log2_chroma_h); + frame->buf[i]->data = frame->data[i]; + frame->buf[i]->size = frame->linesize[i] * plane_h; + } + + pkt->buf = av_buffer_create((uint8_t*)frame, sizeof(*frame), + free_frame, NULL, 0); + if (!pkt->buf) { + err = AVERROR(ENOMEM); + goto end; + } + + frame = NULL; // pkt owns it now + + pkt->data = pkt->buf->data; + pkt->size = pkt->buf->size; + pkt->flags |= AV_PKT_FLAG_TRUSTED; + + if (vs->is_cfr) + pkt->pts = vs->current_frame; + + vs->current_frame++; + +end: + av_frame_free(&frame); + av_buffer_unref(&vsframe_ref); + return err; +} + +static int read_seek_vs(AVFormatContext *s, int stream_idx, int64_t ts, int flags) +{ + VSContext *vs = s->priv_data; + + if (!vs->is_cfr) + return AVERROR(ENOSYS); + + vs->current_frame = FFMIN(FFMAX(0, ts), s->streams[0]->duration); + return 0; +} + +static av_cold int probe_vs(const AVProbeData *p) +{ + // Explicitly do not support this. VS scripts are written in Python, and + // can run arbitrary code on the user's system. + return 0; +} + +static const AVClass class_vs = { + .class_name = "VapourSynth demuxer", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; + +AVInputFormat ff_vapoursynth_demuxer = { + .name = "vapoursynth", + .long_name = NULL_IF_CONFIG_SMALL("VapourSynth demuxer"), + .priv_data_size = sizeof(VSContext), + .read_probe = probe_vs, + .read_header = read_header_vs, + .read_packet = read_packet_vs, + .read_close = read_close_vs, + .read_seek = read_seek_vs, + .priv_class = &class_vs, +}; diff --git a/libavformat/vc1dec.c b/libavformat/vc1dec.c index 33f84652e..fdbb05d6d 100644 --- a/libavformat/vc1dec.c +++ b/libavformat/vc1dec.c @@ -24,9 +24,9 @@ #include "libavutil/intreadwrite.h" #include "libavcodec/vc1_common.h" -static int vc1_probe(AVProbeData *p) +static int vc1_probe(const AVProbeData *p) { - int seq = 0, entry = 0, frame = 0, i; + int seq = 0, entry = 0, invalid = 0, frame = 0, i; for (i = 0; i < p->buf_size + 5; i++) { uint32_t code = AV_RB32(p->buf + i); @@ -39,16 +39,19 @@ static int vc1_probe(AVProbeData *p) profile = (p->buf[i] & 0xc0) >> 6; if (profile != PROFILE_ADVANCED) { seq = 0; + invalid++; continue; } level = (p->buf[i] & 0x38) >> 3; if (level >= 5) { seq = 0; + invalid++; continue; } chromaformat = (p->buf[i] & 0x6) >> 1; if (chromaformat != 1) { seq = 0; + invalid++; continue; } seq++; @@ -56,8 +59,10 @@ static int vc1_probe(AVProbeData *p) break; } case VC1_CODE_ENTRYPOINT: - if (!seq) + if (!seq) { + invalid++; continue; + } entry++; i += 2; break; @@ -71,9 +76,9 @@ static int vc1_probe(AVProbeData *p) } } - if (frame > 1) + if (frame > 1 && frame >> 1 > invalid) return AVPROBE_SCORE_EXTENSION / 2 + 1; - if (frame == 1) + if (frame >= 1) return AVPROBE_SCORE_EXTENSION / 4; return 0; } diff --git a/libavformat/vc1test.c b/libavformat/vc1test.c index a801f4bd2..3c677931f 100644 --- a/libavformat/vc1test.c +++ b/libavformat/vc1test.c @@ -32,11 +32,16 @@ #define VC1_EXTRADATA_SIZE 4 -static int vc1t_probe(AVProbeData *p) +static int vc1t_probe(const AVProbeData *p) { + uint32_t size; + if (p->buf_size < 24) return 0; - if (p->buf[3] != 0xC5 || AV_RL32(&p->buf[4]) != 4 || AV_RL32(&p->buf[20]) != 0xC) + + size = AV_RL32(&p->buf[4]); + if (p->buf[3] != 0xC5 || size < 4 || size > p->buf_size - 20 || + AV_RL32(&p->buf[size+16]) != 0xC) return 0; return AVPROBE_SCORE_EXTENSION; @@ -48,9 +53,10 @@ static int vc1t_read_header(AVFormatContext *s) AVStream *st; int frames; uint32_t fps; + uint32_t size; frames = avio_rl24(pb); - if(avio_r8(pb) != 0xC5 || avio_rl32(pb) != 4) + if (avio_r8(pb) != 0xC5 || ((size = avio_rl32(pb)) < 4)) return AVERROR_INVALIDDATA; /* init video codec */ @@ -63,6 +69,8 @@ static int vc1t_read_header(AVFormatContext *s) if (ff_get_extradata(s, st->codecpar, pb, VC1_EXTRADATA_SIZE) < 0) return AVERROR(ENOMEM); + + avio_skip(pb, size - 4); st->codecpar->height = avio_rl32(pb); st->codecpar->width = avio_rl32(pb); if(avio_rl32(pb) != 0xC) @@ -114,5 +122,6 @@ AVInputFormat ff_vc1t_demuxer = { .read_probe = vc1t_probe, .read_header = vc1t_read_header, .read_packet = vc1t_read_packet, + .extensions = "rcv", .flags = AVFMT_GENERIC_INDEX, }; diff --git a/libavformat/version.h b/libavformat/version.h index a0a26d536..22ed534bf 100644 --- a/libavformat/version.h +++ b/libavformat/version.h @@ -32,7 +32,7 @@ // Major bumping may affect Ticket5467, 5421, 5451(compatibility with Chromium) // Also please add any ticket numbers that you believe might be affected here #define LIBAVFORMAT_VERSION_MAJOR 58 -#define LIBAVFORMAT_VERSION_MINOR 12 +#define LIBAVFORMAT_VERSION_MINOR 29 #define LIBAVFORMAT_VERSION_MICRO 100 #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \ @@ -70,6 +70,9 @@ #ifndef FF_API_HLS_WRAP #define FF_API_HLS_WRAP (LIBAVFORMAT_VERSION_MAJOR < 59) #endif +#ifndef FF_API_HLS_USE_LOCALTIME +#define FF_API_HLS_USE_LOCALTIME (LIBAVFORMAT_VERSION_MAJOR < 59) +#endif #ifndef FF_API_LAVF_KEEPSIDE_FLAG #define FF_API_LAVF_KEEPSIDE_FLAG (LIBAVFORMAT_VERSION_MAJOR < 59) #endif @@ -94,6 +97,15 @@ #ifndef FF_API_NEXT #define FF_API_NEXT (LIBAVFORMAT_VERSION_MAJOR < 59) #endif +#ifndef FF_API_DASH_MIN_SEG_DURATION +#define FF_API_DASH_MIN_SEG_DURATION (LIBAVFORMAT_VERSION_MAJOR < 59) +#endif +#ifndef FF_API_LAVF_MP4A_LATM +#define FF_API_LAVF_MP4A_LATM (LIBAVFORMAT_VERSION_MAJOR < 59) +#endif +#ifndef FF_API_AVIOFORMAT +#define FF_API_AVIOFORMAT (LIBAVFORMAT_VERSION_MAJOR < 59) +#endif #ifndef FF_API_R_FRAME_RATE diff --git a/libavformat/vividas.c b/libavformat/vividas.c new file mode 100644 index 000000000..1ac86a107 --- /dev/null +++ b/libavformat/vividas.c @@ -0,0 +1,757 @@ +/* + * Vividas VIV format Demuxer + * Copyright (c) 2012 Krzysztof Klinikowski + * Copyright (c) 2010 Andrzej Szombierski + * based on vivparse Copyright (c) 2007 Måns Rullgård + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * @brief Vividas VIV (.viv) file demuxer + * @author Andrzej Szombierski [qq at kuku eu org] (2010-07) + * @sa http://wiki.multimedia.cx/index.php?title=Vividas_VIV + */ + +#include "libavutil/intreadwrite.h" +#include "avio_internal.h" +#include "avformat.h" +#include "internal.h" + +#define MAX_AUDIO_SUBPACKETS 100 + +typedef struct VIV_SB_block { + int size, n_packets; + int64_t byte_offset; + int64_t packet_offset; +} VIV_SB_block; + +typedef struct VIV_SB_entry { + int size, flag; +} VIV_SB_entry; + +typedef struct VIV_AudioSubpacket { + int start, pcm_bytes; +} VIV_AudioSubpacket; + +typedef struct VividasDemuxContext { + int n_sb_blocks; + VIV_SB_block *sb_blocks; + + uint32_t sb_key; + int64_t sb_offset; + + int current_sb, current_sb_entry; + uint8_t *sb_buf; + AVIOContext *sb_pb; + int n_sb_entries; + VIV_SB_entry *sb_entries; + + int n_audio_subpackets; + int current_audio_subpacket; + + int64_t audio_sample; + + VIV_AudioSubpacket audio_subpackets[MAX_AUDIO_SUBPACKETS]; +} VividasDemuxContext; + +static int viv_probe(const AVProbeData *p) +{ + if (memcmp(p->buf, "vividas03", 9)) + return 0; + + return AVPROBE_SCORE_MAX; +} + +static const uint8_t keybits[32] = { + 20, 52, 111, 10, 27, 71, 142, 53, + 82, 138, 1, 78, 86, 121, 183, 85, +105, 152, 39, 140, 172, 11, 64, 144, +155, 6, 71, 163, 186, 49, 126, 43, +}; + +static uint32_t decode_key(uint8_t *buf) +{ + uint32_t key = 0; + + for (int i = 0; i < 32; i++) { + unsigned p = keybits[i]; + key |= ((buf[p] >> ((i*5+3)&7)) & 1u) << i; + } + + return key; +} + +static void put_v(uint8_t *p, unsigned v) +{ + if (v>>28) + *p++ = ((v>>28)&0x7f)|0x80; + if (v>>21) + *p++ = ((v>>21)&0x7f)|0x80; + if (v>>14) + *p++ = ((v>>14)&0x7f)|0x80; + if (v>>7) + *p++ = ((v>>7)&0x7f)|0x80; +} + +static unsigned recover_key(unsigned char sample[4], unsigned expected_size) +{ + unsigned char plaintext[8] = { 'S', 'B' }; + + put_v(plaintext+2, expected_size); + + return AV_RL32(sample) ^ AV_RL32(plaintext); +} + +static void xor_block(void *p1, void *p2, unsigned size, int key, unsigned *key_ptr) +{ + unsigned *d1 = p1; + unsigned *d2 = p2; + unsigned k = *key_ptr; + + size >>= 2; + + while (size > 0) { + *d2 = *d1 ^ (HAVE_BIGENDIAN ? av_bswap32(k) : k); + k += key; + d1++; + d2++; + size--; + } + + *key_ptr = k; +} + +static void decode_block(uint8_t *src, uint8_t *dest, unsigned size, + uint32_t key, uint32_t *key_ptr, + int align) +{ + unsigned s = size; + char tmp[4]; + int a2; + + if (!size) + return; + + align &= 3; + a2 = (4 - align) & 3; + + if (align) { + uint32_t tmpkey = *key_ptr - key; + if (a2 > s) { + a2 = s; + avpriv_request_sample(NULL, "tiny aligned block\n"); + } + memcpy(tmp + align, src, a2); + xor_block(tmp, tmp, 4, key, &tmpkey); + memcpy(dest, tmp + align, a2); + s -= a2; + } + + if (s >= 4) { + if (!align) + align = 4; + xor_block(src + a2, dest + a2, s & ~3, + key, key_ptr); + s &= 3; + } + + if (s) { + size -= s; + memcpy(tmp, src + size, s); + xor_block(&tmp, &tmp, 4, key, key_ptr); + memcpy(dest + size, tmp, s); + } +} + +static uint32_t get_v(uint8_t *p, int len) +{ + uint32_t v = 0; + const uint8_t *end = p + len; + + do { + if (p >= end || v >= UINT_MAX / 128 - *p) + return v; + v <<= 7; + v += *p & 0x7f; + } while (*p++ & 0x80); + + return v; +} + +static uint8_t *read_vblock(AVIOContext *src, uint32_t *size, + uint32_t key, uint32_t *k2, int align) +{ + uint8_t tmp[4]; + uint8_t *buf; + unsigned n; + + if (avio_read(src, tmp, 4) != 4) + return NULL; + + decode_block(tmp, tmp, 4, key, k2, align); + + n = get_v(tmp, 4); + if (n < 4) + return NULL; + + buf = av_malloc(n); + if (!buf) + return NULL; + + *size = n; + n -= 4; + + memcpy(buf, tmp, 4); + + if (avio_read(src, buf + 4, n) == n) { + decode_block(buf + 4, buf + 4, n, key, k2, align + 4); + } else { + av_free(buf); + buf = NULL; + } + + return buf; +} + +static uint8_t *read_sb_block(AVIOContext *src, unsigned *size, + uint32_t *key, unsigned expected_size) +{ + uint8_t *buf; + uint8_t ibuf[8], sbuf[8]; + uint32_t k2; + unsigned n; + + if (avio_read(src, ibuf, 8) < 8) + return NULL; + + k2 = *key; + decode_block(ibuf, sbuf, 8, *key, &k2, 0); + + n = get_v(sbuf+2, 6); + + if (sbuf[0] != 'S' || sbuf[1] != 'B' || (expected_size>0 && n != expected_size)) { + uint32_t tmpkey = recover_key(ibuf, expected_size); + k2 = tmpkey; + decode_block(ibuf, sbuf, 8, tmpkey, &k2, 0); + n = get_v(sbuf+2, 6); + if (sbuf[0] != 'S' || sbuf[1] != 'B' || expected_size != n) + return NULL; + *key = tmpkey; + } + + if (n < 8) + return NULL; + + buf = av_malloc(n); + if (!buf) + return NULL; + + memcpy(buf, sbuf, 8); + + *size = n; + n -= 8; + + if (avio_read(src, buf+8, n) < n) { + av_free(buf); + return NULL; + } + + decode_block(buf + 8, buf + 8, n, *key, &k2, 0); + + return buf; +} + +static int track_header(VividasDemuxContext *viv, AVFormatContext *s, uint8_t *buf, int size) +{ + int i,j; + int64_t off; + int val_1; + int num_video, num_audio; + AVIOContext *pb; + + pb = avio_alloc_context(buf, size, 0, NULL, NULL, NULL, NULL); + if (!pb) + return AVERROR(ENOMEM); + + ffio_read_varlen(pb); // track_header_len + avio_r8(pb); // '1' + + val_1 = ffio_read_varlen(pb); + + for (i=0;iid = i; + + st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO; + st->codecpar->codec_id = AV_CODEC_ID_VP6; + + off = avio_tell(pb); + off += ffio_read_varlen(pb); + avio_r8(pb); // '3' + avio_r8(pb); // val_7 + st->time_base.num = avio_rl32(pb); // frame_time + st->time_base.den = avio_rl32(pb); // time_base + st->nb_frames = avio_rl32(pb); // n frames + st->codecpar->width = avio_rl16(pb); // width + st->codecpar->height = avio_rl16(pb); // height + avio_r8(pb); // val_8 + avio_rl32(pb); // val_9 + + avio_seek(pb, off, SEEK_SET); + } + + off = avio_tell(pb); + off += ffio_read_varlen(pb); // val_10 + avio_r8(pb); // '4' + num_audio = avio_r8(pb); + avio_seek(pb, off, SEEK_SET); + + if (num_audio != 1) + av_log(s, AV_LOG_WARNING, "number of audio tracks %d is not 1\n", num_audio); + + for(i=0;iid = num_video + i; + + st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO; + st->codecpar->codec_id = AV_CODEC_ID_VORBIS; + + off = avio_tell(pb); + off += ffio_read_varlen(pb); // length + avio_r8(pb); // '5' + avio_r8(pb); //codec_id + avio_rl16(pb); //codec_subid + st->codecpar->channels = avio_rl16(pb); // channels + st->codecpar->sample_rate = avio_rl32(pb); // sample_rate + avio_seek(pb, 10, SEEK_CUR); // data_1 + q = avio_r8(pb); + avio_seek(pb, q, SEEK_CUR); // data_2 + avio_r8(pb); // zeropad + + if (avio_tell(pb) < off) { + int num_data; + int xd_size = 0; + int data_len[256]; + int offset = 1; + uint8_t *p; + ffio_read_varlen(pb); // val_13 + avio_r8(pb); // '19' + ffio_read_varlen(pb); // len_3 + num_data = avio_r8(pb); + for (j = 0; j < num_data; j++) { + uint64_t len = ffio_read_varlen(pb); + if (len > INT_MAX/2 - xd_size) { + av_free(pb); + return AVERROR_INVALIDDATA; + } + data_len[j] = len; + xd_size += len; + } + + st->codecpar->extradata_size = 64 + xd_size + xd_size / 255; + if (ff_alloc_extradata(st->codecpar, st->codecpar->extradata_size)) { + av_free(pb); + return AVERROR(ENOMEM); + } + + p = st->codecpar->extradata; + p[0] = 2; + + for (j = 0; j < num_data - 1; j++) { + unsigned delta = av_xiphlacing(&p[offset], data_len[j]); + if (delta > data_len[j]) { + av_free(pb); + return AVERROR_INVALIDDATA; + } + offset += delta; + } + + for (j = 0; j < num_data; j++) { + int ret = avio_read(pb, &p[offset], data_len[j]); + if (ret < data_len[j]) { + st->codecpar->extradata_size = 0; + av_freep(&st->codecpar->extradata); + break; + } + offset += data_len[j]; + } + + if (offset < st->codecpar->extradata_size) + st->codecpar->extradata_size = offset; + } + } + + av_free(pb); + return 0; +} + +static void track_index(VividasDemuxContext *viv, AVFormatContext *s, uint8_t *buf, unsigned size) +{ + int64_t off; + int64_t poff; + int maxnp=0; + AVIOContext *pb; + int i; + + pb = avio_alloc_context(buf, size, 0, NULL, NULL, NULL, NULL); + if (!pb) + return; + + ffio_read_varlen(pb); // track_index_len + avio_r8(pb); // 'c' + viv->n_sb_blocks = ffio_read_varlen(pb); + viv->sb_blocks = av_calloc(viv->n_sb_blocks, sizeof(VIV_SB_block)); + if (!viv->sb_blocks) { + viv->n_sb_blocks = 0; + av_free(pb); + return; + } + + off = 0; + poff = 0; + + for (i = 0; i < viv->n_sb_blocks; i++) { + viv->sb_blocks[i].byte_offset = off; + viv->sb_blocks[i].packet_offset = poff; + + viv->sb_blocks[i].size = ffio_read_varlen(pb); + viv->sb_blocks[i].n_packets = ffio_read_varlen(pb); + + off += viv->sb_blocks[i].size; + poff += viv->sb_blocks[i].n_packets; + + + if (maxnp < viv->sb_blocks[i].n_packets) + maxnp = viv->sb_blocks[i].n_packets; + } + + viv->sb_entries = av_calloc(maxnp, sizeof(VIV_SB_entry)); + av_free(pb); +} + +static void load_sb_block(AVFormatContext *s, VividasDemuxContext *viv, unsigned expected_size) +{ + uint32_t size = 0; + int i; + AVIOContext *pb = 0; + + if (viv->sb_pb) { + av_free(viv->sb_pb); + viv->sb_pb = NULL; + } + + if (viv->sb_buf) + av_free(viv->sb_buf); + + viv->sb_buf = read_sb_block(s->pb, &size, &viv->sb_key, expected_size); + if (!viv->sb_buf) { + return; + } + + pb = avio_alloc_context(viv->sb_buf, size, 0, NULL, NULL, NULL, NULL); + if (!pb) + return; + + viv->sb_pb = pb; + + avio_r8(pb); // 'S' + avio_r8(pb); // 'B' + ffio_read_varlen(pb); // size + avio_r8(pb); // junk + ffio_read_varlen(pb); // first packet + + viv->n_sb_entries = viv->sb_blocks[viv->current_sb].n_packets; + + for (i = 0; i < viv->n_sb_entries; i++) { + viv->sb_entries[i].size = ffio_read_varlen(pb); + viv->sb_entries[i].flag = avio_r8(pb); + } + + ffio_read_varlen(pb); + avio_r8(pb); + + viv->current_sb_entry = 0; +} + +static int viv_read_header(AVFormatContext *s) +{ + VividasDemuxContext *viv = s->priv_data; + AVIOContext *pb = s->pb; + int64_t header_end; + int num_tracks; + uint32_t key, k2; + uint32_t v; + uint8_t keybuffer[187]; + uint32_t b22_size = 0; + uint32_t b22_key = 0; + uint8_t *buf = 0; + int ret; + + avio_skip(pb, 9); + + header_end = avio_tell(pb); + + header_end += ffio_read_varlen(pb); + + num_tracks = avio_r8(pb); + + if (num_tracks != 1) { + av_log(s, AV_LOG_ERROR, "number of tracks %d is not 1\n", num_tracks); + return AVERROR(EINVAL); + } + + v = avio_r8(pb); + avio_seek(pb, v, SEEK_CUR); + + avio_read(pb, keybuffer, 187); + key = decode_key(keybuffer); + viv->sb_key = key; + + avio_rl32(pb); + + for (;;) { + int64_t here = avio_tell(pb); + int block_len, block_type; + + if (here >= header_end) + break; + + block_len = ffio_read_varlen(pb); + if (avio_feof(pb) || block_len <= 0) + return AVERROR_INVALIDDATA; + + block_type = avio_r8(pb); + + if (block_type == 22) { + avio_read(pb, keybuffer, 187); + b22_key = decode_key(keybuffer); + b22_size = avio_rl32(pb); + } + + avio_seek(pb, here + block_len, SEEK_SET); + } + + if (b22_size) { + k2 = b22_key; + buf = read_vblock(pb, &v, b22_key, &k2, 0); + if (!buf) + return AVERROR(EIO); + + av_free(buf); + } + + k2 = key; + buf = read_vblock(pb, &v, key, &k2, 0); + if (!buf) + return AVERROR(EIO); + ret = track_header(viv, s, buf, v); + av_free(buf); + if (ret < 0) + return ret; + + buf = read_vblock(pb, &v, key, &k2, v); + if (!buf) + return AVERROR(EIO); + track_index(viv, s, buf, v); + av_free(buf); + + viv->sb_offset = avio_tell(pb); + if (viv->n_sb_blocks > 0) { + viv->current_sb = 0; + load_sb_block(s, viv, viv->sb_blocks[0].size); + } else { + viv->current_sb = -1; + } + + return 0; +} + +static int viv_read_packet(AVFormatContext *s, + AVPacket *pkt) +{ + VividasDemuxContext *viv = s->priv_data; + AVIOContext *pb; + int64_t off; + int ret; + + if (!viv->sb_pb) + return AVERROR(EIO); + if (avio_feof(viv->sb_pb)) + return AVERROR_EOF; + + if (viv->current_audio_subpacket < viv->n_audio_subpackets) { + AVStream *astream; + int size = viv->audio_subpackets[viv->current_audio_subpacket+1].start - viv->audio_subpackets[viv->current_audio_subpacket].start; + + pb = viv->sb_pb; + ret = av_get_packet(pb, pkt, size); + if (ret < 0) + return ret; + pkt->pos += viv->sb_offset + viv->sb_blocks[viv->current_sb].byte_offset; + + pkt->stream_index = 1; + astream = s->streams[pkt->stream_index]; + + pkt->pts = av_rescale(viv->audio_sample, astream->time_base.den, astream->time_base.num) / astream->codecpar->sample_rate; + viv->audio_sample += viv->audio_subpackets[viv->current_audio_subpacket].pcm_bytes / 2 / astream->codecpar->channels; + pkt->flags |= AV_PKT_FLAG_KEY; + viv->current_audio_subpacket++; + return 0; + } + + if (viv->current_sb_entry >= viv->n_sb_entries) { + if (viv->current_sb+1 >= viv->n_sb_blocks) + return AVERROR(EIO); + viv->current_sb++; + + load_sb_block(s, viv, 0); + viv->current_sb_entry = 0; + } + + pb = viv->sb_pb; + if (!pb) + return AVERROR(EIO); + off = avio_tell(pb); + off += viv->sb_entries[viv->current_sb_entry].size; + + if (viv->sb_entries[viv->current_sb_entry].flag == 0) { + uint64_t v_size = ffio_read_varlen(pb); + + ffio_read_varlen(pb); + if (v_size > INT_MAX) + return AVERROR_INVALIDDATA; + ret = av_get_packet(pb, pkt, v_size); + if (ret < 0) + return ret; + pkt->pos += viv->sb_offset + viv->sb_blocks[viv->current_sb].byte_offset; + + pkt->pts = viv->sb_blocks[viv->current_sb].packet_offset + viv->current_sb_entry; + pkt->flags |= (pkt->data[0]&0x80)?0:AV_PKT_FLAG_KEY; + pkt->stream_index = 0; + + for (int i = 0; i < MAX_AUDIO_SUBPACKETS - 1; i++) { + int start, pcm_bytes; + start = ffio_read_varlen(pb); + pcm_bytes = ffio_read_varlen(pb); + + if (i > 0 && start == 0) + break; + + viv->n_audio_subpackets = i + 1; + viv->audio_subpackets[i].start = start; + viv->audio_subpackets[i].pcm_bytes = pcm_bytes; + } + viv->audio_subpackets[viv->n_audio_subpackets].start = (int)(off - avio_tell(pb)); + viv->current_audio_subpacket = 0; + + } else { + uint64_t v_size = ffio_read_varlen(pb); + + if (v_size > INT_MAX) + return AVERROR_INVALIDDATA; + ret = av_get_packet(pb, pkt, v_size); + if (ret < 0) + return ret; + pkt->pos += viv->sb_offset + viv->sb_blocks[viv->current_sb].byte_offset; + pkt->pts = viv->sb_blocks[viv->current_sb].packet_offset + viv->current_sb_entry; + pkt->flags |= (pkt->data[0] & 0x80) ? 0 : AV_PKT_FLAG_KEY; + pkt->stream_index = 0; + } + + viv->current_sb_entry++; + + return 0; +} + +static int viv_read_close(AVFormatContext *s) +{ + VividasDemuxContext *viv = s->priv_data; + + av_freep(&viv->sb_pb); + av_freep(&viv->sb_buf); + av_freep(&viv->sb_blocks); + av_freep(&viv->sb_entries); + + return 0; +} + +static int viv_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp, int flags) +{ + VividasDemuxContext *viv = s->priv_data; + int64_t frame; + + if (stream_index == 0) + frame = timestamp; + else + frame = av_rescale_q(timestamp, s->streams[0]->time_base, s->streams[stream_index]->time_base); + + for (int i = 0; i < viv->n_sb_blocks; i++) { + if (frame >= viv->sb_blocks[i].packet_offset && frame < viv->sb_blocks[i].packet_offset + viv->sb_blocks[i].n_packets) { + // flush audio packet queue + viv->current_audio_subpacket = 0; + viv->n_audio_subpackets = 0; + viv->current_sb = i; + // seek to ith sb block + avio_seek(s->pb, viv->sb_offset + viv->sb_blocks[i].byte_offset, SEEK_SET); + // load the block + load_sb_block(s, viv, 0); + // most problematic part: guess audio offset + viv->audio_sample = av_rescale_q(viv->sb_blocks[i].packet_offset, av_make_q(s->streams[1]->codecpar->sample_rate, 1), av_inv_q(s->streams[0]->time_base)); + // hand-tuned 1.s a/v offset + viv->audio_sample += s->streams[1]->codecpar->sample_rate; + viv->current_sb_entry = 0; + return 1; + } + } + return 0; +} + +AVInputFormat ff_vividas_demuxer = { + .name = "vividas", + .long_name = NULL_IF_CONFIG_SMALL("Vividas VIV"), + .priv_data_size = sizeof(VividasDemuxContext), + .read_probe = viv_probe, + .read_header = viv_read_header, + .read_packet = viv_read_packet, + .read_close = viv_read_close, + .read_seek = viv_read_seek, +}; diff --git a/libavformat/vivo.c b/libavformat/vivo.c index c9e9c37f3..9a07c4384 100644 --- a/libavformat/vivo.c +++ b/libavformat/vivo.c @@ -40,7 +40,7 @@ typedef struct VivoContext { uint8_t text[1024 + 1]; } VivoContext; -static int vivo_probe(AVProbeData *p) +static int vivo_probe(const AVProbeData *p) { const unsigned char *buf = p->buf; unsigned c, length = 0; @@ -166,7 +166,7 @@ static int vivo_read_header(AVFormatContext *s) value = strchr(key, ':'); if (!value) { av_log(s, AV_LOG_WARNING, "missing colon in key:value pair '%s'\n", - value); + key); continue; } diff --git a/libavformat/vocdec.c b/libavformat/vocdec.c index 10df28b80..fd1ca20c9 100644 --- a/libavformat/vocdec.c +++ b/libavformat/vocdec.c @@ -23,7 +23,7 @@ #include "voc.h" #include "internal.h" -static int voc_probe(AVProbeData *p) +static int voc_probe(const AVProbeData *p) { int version, check; diff --git a/libavformat/vorbiscomment.c b/libavformat/vorbiscomment.c index 575dd1332..fb5c655a2 100644 --- a/libavformat/vorbiscomment.c +++ b/libavformat/vorbiscomment.c @@ -38,10 +38,21 @@ const AVMetadataConv ff_vorbiscomment_metadata_conv[] = { { 0 } }; -int64_t ff_vorbiscomment_length(AVDictionary *m, const char *vendor_string) +int64_t ff_vorbiscomment_length(AVDictionary *m, const char *vendor_string, + AVChapter **chapters, unsigned int nb_chapters) { int64_t len = 8; len += strlen(vendor_string); + if (chapters && nb_chapters) { + for (int i = 0; i < nb_chapters; i++) { + AVDictionaryEntry *tag = NULL; + len += 4 + 12 + 1 + 10; + while ((tag = av_dict_get(chapters[i]->metadata, "", tag, AV_DICT_IGNORE_SUFFIX))) { + int64_t len1 = !strcmp(tag->key, "title") ? 4 : strlen(tag->key); + len += 4 + 10 + len1 + 1 + strlen(tag->value); + } + } + } if (m) { AVDictionaryEntry *tag = NULL; while ((tag = av_dict_get(m, "", tag, AV_DICT_IGNORE_SUFFIX))) { @@ -52,12 +63,19 @@ int64_t ff_vorbiscomment_length(AVDictionary *m, const char *vendor_string) } int ff_vorbiscomment_write(uint8_t **p, AVDictionary **m, - const char *vendor_string) + const char *vendor_string, + AVChapter **chapters, unsigned int nb_chapters) { + int cm_count = 0; bytestream_put_le32(p, strlen(vendor_string)); bytestream_put_buffer(p, vendor_string, strlen(vendor_string)); + if (chapters && nb_chapters) { + for (int i = 0; i < nb_chapters; i++) { + cm_count += av_dict_count(chapters[i]->metadata) + 1; + } + } if (*m) { - int count = av_dict_count(*m); + int count = av_dict_count(*m) + cm_count; AVDictionaryEntry *tag = NULL; bytestream_put_le32(p, count); while ((tag = av_dict_get(*m, "", tag, AV_DICT_IGNORE_SUFFIX))) { @@ -70,6 +88,42 @@ int ff_vorbiscomment_write(uint8_t **p, AVDictionary **m, bytestream_put_byte(p, '='); bytestream_put_buffer(p, tag->value, len2); } + for (int i = 0; i < nb_chapters; i++) { + AVChapter *chp = chapters[i]; + char chapter_time[13]; + char chapter_number[4]; + int h, m, s, ms; + + s = av_rescale(chp->start, chp->time_base.num, chp->time_base.den); + h = s / 3600; + m = (s / 60) % 60; + ms = av_rescale_q(chp->start, chp->time_base, av_make_q( 1, 1000)) % 1000; + s = s % 60; + snprintf(chapter_number, sizeof(chapter_number), "%03d", i); + snprintf(chapter_time, sizeof(chapter_time), "%02d:%02d:%02d.%03d", h, m, s, ms); + bytestream_put_le32(p, 10+1+12); + bytestream_put_buffer(p, "CHAPTER", 7); + bytestream_put_buffer(p, chapter_number, 3); + bytestream_put_byte(p, '='); + bytestream_put_buffer(p, chapter_time, 12); + + tag = NULL; + while ((tag = av_dict_get(chapters[i]->metadata, "", tag, AV_DICT_IGNORE_SUFFIX))) { + int64_t len1 = !strcmp(tag->key, "title") ? 4 : strlen(tag->key); + int64_t len2 = strlen(tag->value); + if (len1+1+len2+10 > UINT32_MAX) + return AVERROR(EINVAL); + bytestream_put_le32(p, 10+len1+1+len2); + bytestream_put_buffer(p, "CHAPTER", 7); + bytestream_put_buffer(p, chapter_number, 3); + if (!strcmp(tag->key, "title")) + bytestream_put_buffer(p, "NAME", 4); + else + bytestream_put_buffer(p, tag->key, len1); + bytestream_put_byte(p, '='); + bytestream_put_buffer(p, tag->value, len2); + } + } } else bytestream_put_le32(p, 0); return 0; diff --git a/libavformat/vorbiscomment.h b/libavformat/vorbiscomment.h index e0d30b14a..4ff3dd6c2 100644 --- a/libavformat/vorbiscomment.h +++ b/libavformat/vorbiscomment.h @@ -34,7 +34,8 @@ * For no string, set to an empty string. * @return The length in bytes. */ -int64_t ff_vorbiscomment_length(AVDictionary *m, const char *vendor_string); +int64_t ff_vorbiscomment_length(AVDictionary *m, const char *vendor_string, + AVChapter **chapters, unsigned int nb_chapters); /** * Write a VorbisComment into a buffer. The buffer, p, must have enough @@ -45,9 +46,12 @@ int64_t ff_vorbiscomment_length(AVDictionary *m, const char *vendor_string); * @param p The buffer in which to write. * @param m The metadata struct to write. * @param vendor_string The vendor string to write. + * @param chapters The chapters to write. + * @param nb_chapters The number of chapters to write. */ int ff_vorbiscomment_write(uint8_t **p, AVDictionary **m, - const char *vendor_string); + const char *vendor_string, + AVChapter **chapters, unsigned int nb_chapters); extern const AVMetadataConv ff_vorbiscomment_metadata_conv[]; diff --git a/libavformat/vpcc.c b/libavformat/vpcc.c index df08de59a..e0b7f288a 100644 --- a/libavformat/vpcc.c +++ b/libavformat/vpcc.c @@ -67,11 +67,58 @@ static int get_vpx_video_full_range_flag(enum AVColorRange color_range) return color_range == AVCOL_RANGE_JPEG; } -int ff_isom_write_vpcc(AVFormatContext *s, AVIOContext *pb, - AVCodecParameters *par) +// Find approximate VP9 level based on the Luma's Sample rate and Picture size. +static int get_vp9_level(AVCodecParameters *par, AVRational *frame_rate) { + int picture_size = par->width * par->height; + int64_t sample_rate; + + // All decisions will be based on picture_size, if frame rate is missing/invalid + if (!frame_rate || !frame_rate->den) + sample_rate = 0; + else + sample_rate = ((int64_t)picture_size * frame_rate->num) / frame_rate->den; + + if (picture_size <= 0) { + return 0; + } else if (sample_rate <= 829440 && picture_size <= 36864) { + return 10; + } else if (sample_rate <= 2764800 && picture_size <= 73728) { + return 11; + } else if (sample_rate <= 4608000 && picture_size <= 122880) { + return 20; + } else if (sample_rate <= 9216000 && picture_size <= 245760) { + return 21; + } else if (sample_rate <= 20736000 && picture_size <= 552960) { + return 30; + } else if (sample_rate <= 36864000 && picture_size <= 983040) { + return 31; + } else if (sample_rate <= 83558400 && picture_size <= 2228224) { + return 40; + } else if (sample_rate <= 160432128 && picture_size <= 2228224) { + return 41; + } else if (sample_rate <= 311951360 && picture_size <= 8912896) { + return 50; + } else if (sample_rate <= 588251136 && picture_size <= 8912896) { + return 51; + } else if (sample_rate <= 1176502272 && picture_size <= 8912896) { + return 52; + } else if (sample_rate <= 1176502272 && picture_size <= 35651584) { + return 60; + } else if (sample_rate <= 2353004544 && picture_size <= 35651584) { + return 61; + } else if (sample_rate <= 4706009088 && picture_size <= 35651584) { + return 62; + } else { + return 0; + } +} + +int ff_isom_get_vpcc_features(AVFormatContext *s, AVCodecParameters *par, + AVRational *frame_rate, VPCC *vpcc) { int profile = par->profile; - int level = par->level == FF_LEVEL_UNKNOWN ? 0 : par->level; + int level = par->level == FF_LEVEL_UNKNOWN ? + get_vp9_level(par, frame_rate) : par->level; int bit_depth = get_bit_depth(s, par->format); int vpx_chroma_subsampling = get_vpx_chroma_subsampling(s, par->format, par->chroma_location); @@ -90,9 +137,28 @@ int ff_isom_write_vpcc(AVFormatContext *s, AVIOContext *pb, } } - avio_w8(pb, profile); - avio_w8(pb, level); - avio_w8(pb, (bit_depth << 4) | (vpx_chroma_subsampling << 1) | vpx_video_full_range_flag); + vpcc->profile = profile; + vpcc->level = level; + vpcc->bitdepth = bit_depth; + vpcc->chroma_subsampling = vpx_chroma_subsampling; + vpcc->full_range_flag = vpx_video_full_range_flag; + + return 0; +} + +int ff_isom_write_vpcc(AVFormatContext *s, AVIOContext *pb, + AVCodecParameters *par) +{ + VPCC vpcc; + int ret; + + ret = ff_isom_get_vpcc_features(s, par, NULL, &vpcc); + if (ret < 0) + return ret; + + avio_w8(pb, vpcc.profile); + avio_w8(pb, vpcc.level); + avio_w8(pb, (vpcc.bitdepth << 4) | (vpcc.chroma_subsampling << 1) | vpcc.full_range_flag); avio_w8(pb, par->color_primaries); avio_w8(pb, par->color_trc); avio_w8(pb, par->color_space); diff --git a/libavformat/vpcc.h b/libavformat/vpcc.h index 184e8579f..e87bec55c 100644 --- a/libavformat/vpcc.h +++ b/libavformat/vpcc.h @@ -32,6 +32,14 @@ #include "avformat.h" #include "libavcodec/avcodec.h" +typedef struct VPCC { + int profile; + int level; + int bitdepth; + int chroma_subsampling; + int full_range_flag; +} VPCC; + /** * Writes VP codec configuration to the provided AVIOContext. * @@ -44,4 +52,7 @@ int ff_isom_write_vpcc(AVFormatContext *s, AVIOContext *pb, AVCodecParameters *par); +int ff_isom_get_vpcc_features(AVFormatContext *s, AVCodecParameters *par, + AVRational *frame_rate, VPCC *vpcc); + #endif /* AVFORMAT_VPCC_H */ diff --git a/libavformat/vpk.c b/libavformat/vpk.c index bb9eabb2b..255d6030b 100644 --- a/libavformat/vpk.c +++ b/libavformat/vpk.c @@ -29,7 +29,7 @@ typedef struct VPKDemuxContext { unsigned last_block_size; } VPKDemuxContext; -static int vpk_probe(AVProbeData *p) +static int vpk_probe(const AVProbeData *p) { if (AV_RL32(p->buf) != MKBETAG('V','P','K',' ')) return 0; @@ -56,16 +56,19 @@ static int vpk_read_header(AVFormatContext *s) st->codecpar->codec_id = AV_CODEC_ID_ADPCM_PSX; st->codecpar->block_align = avio_rl32(s->pb); st->codecpar->sample_rate = avio_rl32(s->pb); - if (st->codecpar->sample_rate <= 0) + if (st->codecpar->sample_rate <= 0 || st->codecpar->block_align <= 0) return AVERROR_INVALIDDATA; st->codecpar->channels = avio_rl32(s->pb); if (st->codecpar->channels <= 0) return AVERROR_INVALIDDATA; - samples_per_block = ((st->codecpar->block_align / st->codecpar->channels) * 28) / 16; + samples_per_block = ((st->codecpar->block_align / st->codecpar->channels) * 28LL) / 16; if (samples_per_block <= 0) return AVERROR_INVALIDDATA; vpk->block_count = (st->duration + (samples_per_block - 1)) / samples_per_block; vpk->last_block_size = (st->duration % samples_per_block) * 16 * st->codecpar->channels / 28; + + if (offset < avio_tell(s->pb)) + return AVERROR_INVALIDDATA; avio_skip(s->pb, offset - avio_tell(s->pb)); avpriv_set_pts_info(st, 64, 1, st->codecpar->sample_rate); diff --git a/libavformat/vplayerdec.c b/libavformat/vplayerdec.c index 49943d0d0..e3e7b4efb 100644 --- a/libavformat/vplayerdec.c +++ b/libavformat/vplayerdec.c @@ -31,7 +31,7 @@ typedef struct { FFDemuxSubtitlesQueue q; } VPlayerContext; -static int vplayer_probe(AVProbeData *p) +static int vplayer_probe(const AVProbeData *p) { char c; const unsigned char *ptr = p->buf; diff --git a/libavformat/vqf.c b/libavformat/vqf.c index d00fa5e08..755849bac 100644 --- a/libavformat/vqf.c +++ b/libavformat/vqf.c @@ -32,7 +32,7 @@ typedef struct VqfContext { int remaining_bits; } VqfContext; -static int vqf_probe(AVProbeData *probe_packet) +static int vqf_probe(const AVProbeData *probe_packet) { if (AV_RL32(probe_packet->buf) != MKTAG('T','W','I','N')) return 0; @@ -107,6 +107,9 @@ static int vqf_read_header(AVFormatContext *s) header_size = avio_rb32(s->pb); + if (header_size < 0) + return AVERROR_INVALIDDATA; + st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO; st->codecpar->codec_id = AV_CODEC_ID_TWINVQ; st->start_time = 0; @@ -120,7 +123,7 @@ static int vqf_read_header(AVFormatContext *s) len = avio_rb32(s->pb); - if ((unsigned) len > INT_MAX/2) { + if ((unsigned) len > INT_MAX/2 || header_size < 8) { av_log(s, AV_LOG_ERROR, "Malformed header\n"); return -1; } diff --git a/libavformat/wavdec.c b/libavformat/wavdec.c index e280be4d4..684efd97f 100644 --- a/libavformat/wavdec.c +++ b/libavformat/wavdec.c @@ -34,6 +34,7 @@ #include "avformat.h" #include "avio.h" #include "avio_internal.h" +#include "id3v2.h" #include "internal.h" #include "metadata.h" #include "pcm.h" @@ -128,7 +129,7 @@ static int64_t find_tag(WAVDemuxContext * wav, AVIOContext *pb, uint32_t tag1) return size; } -static int wav_probe(AVProbeData *p) +static int wav_probe(const AVProbeData *p) { /* check file header */ if (p->buf_size <= 32) @@ -232,9 +233,9 @@ static inline int wav_parse_bext_string(AVFormatContext *s, const char *key, char temp[257]; int ret; - av_assert0(length <= sizeof(temp)); - if ((ret = avio_read(s->pb, temp, length)) < 0) - return ret; + av_assert0(length < sizeof(temp)); + if ((ret = avio_read(s->pb, temp, length)) != length) + return ret < 0 ? ret : AVERROR_INVALIDDATA; temp[length] = 0; @@ -303,8 +304,10 @@ static int wav_parse_bext_tag(AVFormatContext *s, int64_t size) if (!(coding_history = av_malloc(size + 1))) return AVERROR(ENOMEM); - if ((ret = avio_read(s->pb, coding_history, size)) < 0) - return ret; + if ((ret = avio_read(s->pb, coding_history, size)) != size) { + av_free(coding_history); + return ret < 0 ? ret : AVERROR_INVALIDDATA; + } coding_history[size] = 0; if ((ret = av_dict_set(&s->metadata, "coding_history", coding_history, @@ -500,6 +503,18 @@ static int wav_read_header(AVFormatContext *s) ff_read_riff_info(s, size - 4); } break; + case MKTAG('I', 'D', '3', ' '): + case MKTAG('i', 'd', '3', ' '): { + ID3v2ExtraMeta *id3v2_extra_meta = NULL; + ff_id3v2_read_dict(pb, &s->internal->id3v2_meta, ID3v2_DEFAULT_MAGIC, &id3v2_extra_meta); + if (id3v2_extra_meta) { + ff_id3v2_parse_apic(s, &id3v2_extra_meta); + ff_id3v2_parse_chapters(s, &id3v2_extra_meta); + ff_id3v2_parse_priv(s, &id3v2_extra_meta); + } + ff_id3v2_free_extra_meta(&id3v2_extra_meta); + } + break; } /* seek to next tag unless we know that we'll run into EOF */ @@ -761,7 +776,7 @@ AVInputFormat ff_wav_demuxer = { #endif /* CONFIG_WAV_DEMUXER */ #if CONFIG_W64_DEMUXER -static int w64_probe(AVProbeData *p) +static int w64_probe(const AVProbeData *p) { if (p->buf_size <= 40) return 0; diff --git a/libavformat/wc3movie.c b/libavformat/wc3movie.c index cb4d4d933..27f5eb196 100644 --- a/libavformat/wc3movie.c +++ b/libavformat/wc3movie.c @@ -73,7 +73,7 @@ typedef struct Wc3DemuxContext { } Wc3DemuxContext; -static int wc3_probe(AVProbeData *p) +static int wc3_probe(const AVProbeData *p) { if (p->buf_size < 12) return 0; diff --git a/libavformat/webm_chunk.c b/libavformat/webm_chunk.c index 7ceb276fc..4e2ce21a7 100644 --- a/libavformat/webm_chunk.c +++ b/libavformat/webm_chunk.c @@ -52,8 +52,8 @@ typedef struct WebMChunkContext { int chunk_index; char *http_method; uint64_t duration_written; - int prev_pts; - AVOutputFormat *oformat; + int64_t prev_pts; + ff_const59 AVOutputFormat *oformat; AVFormatContext *avf; } WebMChunkContext; @@ -84,7 +84,7 @@ static int chunk_mux_init(AVFormatContext *s) return 0; } -static int get_chunk_filename(AVFormatContext *s, int is_header, char *filename) +static int get_chunk_filename(AVFormatContext *s, int is_header, char filename[MAX_FILENAME_SIZE]) { WebMChunkContext *wc = s->priv_data; AVFormatContext *oc = wc->avf; @@ -92,11 +92,16 @@ static int get_chunk_filename(AVFormatContext *s, int is_header, char *filename) return AVERROR(EINVAL); } if (is_header) { + int len; if (!wc->header_filename) { av_log(oc, AV_LOG_ERROR, "No header filename provided\n"); return AVERROR(EINVAL); } - av_strlcpy(filename, wc->header_filename, strlen(wc->header_filename) + 1); + len = av_strlcpy(filename, wc->header_filename, MAX_FILENAME_SIZE); + if (len >= MAX_FILENAME_SIZE) { + av_log(oc, AV_LOG_ERROR, "Header filename too long\n"); + return AVERROR(EINVAL); + } } else { if (av_get_frame_filename(filename, MAX_FILENAME_SIZE, s->url, wc->chunk_index - 1) < 0) { @@ -124,6 +129,7 @@ static int webm_chunk_write_header(AVFormatContext *s) wc->oformat = av_guess_format("webm", s->url, "video/webm"); if (!wc->oformat) return AVERROR_MUXER_NOT_FOUND; + wc->prev_pts = AV_NOPTS_VALUE; ret = chunk_mux_init(s); if (ret < 0) @@ -168,7 +174,7 @@ static int chunk_start(AVFormatContext *s) return 0; } -static int chunk_end(AVFormatContext *s) +static int chunk_end(AVFormatContext *s, int flush) { WebMChunkContext *wc = s->priv_data; AVFormatContext *oc = wc->avf; @@ -179,11 +185,14 @@ static int chunk_end(AVFormatContext *s) char filename[MAX_FILENAME_SIZE]; AVDictionary *options = NULL; - if (wc->chunk_start_index == wc->chunk_index) + if (!oc->pb) return 0; - // Flush the cluster in WebM muxer. - oc->oformat->write_packet(oc, NULL); + + if (flush) + // Flush the cluster in WebM muxer. + oc->oformat->write_packet(oc, NULL); buffer_size = avio_close_dyn_buf(oc->pb, &buffer); + oc->pb = NULL; ret = get_chunk_filename(s, 0, filename); if (ret < 0) goto fail; @@ -194,7 +203,6 @@ static int chunk_end(AVFormatContext *s) goto fail; avio_write(pb, buffer, buffer_size); ff_format_io_close(s, &pb); - oc->pb = NULL; fail: av_dict_free(&options); av_free(buffer); @@ -209,34 +217,27 @@ static int webm_chunk_write_packet(AVFormatContext *s, AVPacket *pkt) int ret; if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) { - wc->duration_written += av_rescale_q(pkt->pts - wc->prev_pts, - st->time_base, - (AVRational) {1, 1000}); + if (wc->prev_pts != AV_NOPTS_VALUE) + wc->duration_written += av_rescale_q(pkt->pts - wc->prev_pts, + st->time_base, + (AVRational) {1, 1000}); wc->prev_pts = pkt->pts; } // For video, a new chunk is started only on key frames. For audio, a new - // chunk is started based on chunk_duration. - if ((st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && + // chunk is started based on chunk_duration. Also, a new chunk is started + // unconditionally if there is no currently open chunk. + if (!oc->pb || (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && (pkt->flags & AV_PKT_FLAG_KEY)) || (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && - (pkt->pts == 0 || wc->duration_written >= wc->chunk_duration))) { + wc->duration_written >= wc->chunk_duration)) { wc->duration_written = 0; - if ((ret = chunk_end(s)) < 0 || (ret = chunk_start(s)) < 0) { - goto fail; + if ((ret = chunk_end(s, 1)) < 0 || (ret = chunk_start(s)) < 0) { + return ret; } } ret = oc->oformat->write_packet(oc, pkt); - if (ret < 0) - goto fail; - -fail: - if (ret < 0) { - oc->streams = NULL; - oc->nb_streams = 0; - avformat_free_context(oc); - } return ret; } @@ -245,12 +246,20 @@ static int webm_chunk_write_trailer(AVFormatContext *s) { WebMChunkContext *wc = s->priv_data; AVFormatContext *oc = wc->avf; + int ret; + + if (!oc->pb) { + ret = chunk_start(s); + if (ret < 0) + goto fail; + } oc->oformat->write_trailer(oc); - chunk_end(s); + ret = chunk_end(s, 0); +fail: oc->streams = NULL; oc->nb_streams = 0; avformat_free_context(oc); - return 0; + return ret; } #define OFFSET(x) offsetof(WebMChunkContext, x) diff --git a/libavformat/webvttdec.c b/libavformat/webvttdec.c index 0aeb8a63f..52579c5ed 100644 --- a/libavformat/webvttdec.c +++ b/libavformat/webvttdec.c @@ -37,7 +37,7 @@ typedef struct { int kind; } WebVTTContext; -static int webvtt_probe(AVProbeData *p) +static int webvtt_probe(const AVProbeData *p) { const uint8_t *ptr = p->buf; @@ -192,14 +192,14 @@ static int webvtt_read_close(AVFormatContext *s) } #define OFFSET(x) offsetof(WebVTTContext, x) -#define KIND_FLAGS AV_OPT_FLAG_SUBTITLE_PARAM +#define KIND_FLAGS AV_OPT_FLAG_SUBTITLE_PARAM|AV_OPT_FLAG_DECODING_PARAM static const AVOption options[] = { { "kind", "Set kind of WebVTT track", OFFSET(kind), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, KIND_FLAGS, "webvtt_kind" }, - { "subtitles", "WebVTT subtitles kind", 0, AV_OPT_TYPE_CONST, { .i64 = 0 }, INT_MIN, INT_MAX, 0, "webvtt_kind" }, - { "captions", "WebVTT captions kind", 0, AV_OPT_TYPE_CONST, { .i64 = AV_DISPOSITION_CAPTIONS }, INT_MIN, INT_MAX, 0, "webvtt_kind" }, - { "descriptions", "WebVTT descriptions kind", 0, AV_OPT_TYPE_CONST, { .i64 = AV_DISPOSITION_DESCRIPTIONS }, INT_MIN, INT_MAX, 0, "webvtt_kind" }, - { "metadata", "WebVTT metadata kind", 0, AV_OPT_TYPE_CONST, { .i64 = AV_DISPOSITION_METADATA }, INT_MIN, INT_MAX, 0, "webvtt_kind" }, + { "subtitles", "WebVTT subtitles kind", 0, AV_OPT_TYPE_CONST, { .i64 = 0 }, INT_MIN, INT_MAX, KIND_FLAGS, "webvtt_kind" }, + { "captions", "WebVTT captions kind", 0, AV_OPT_TYPE_CONST, { .i64 = AV_DISPOSITION_CAPTIONS }, INT_MIN, INT_MAX, KIND_FLAGS, "webvtt_kind" }, + { "descriptions", "WebVTT descriptions kind", 0, AV_OPT_TYPE_CONST, { .i64 = AV_DISPOSITION_DESCRIPTIONS }, INT_MIN, INT_MAX, KIND_FLAGS, "webvtt_kind" }, + { "metadata", "WebVTT metadata kind", 0, AV_OPT_TYPE_CONST, { .i64 = AV_DISPOSITION_METADATA }, INT_MIN, INT_MAX, KIND_FLAGS, "webvtt_kind" }, { NULL } }; diff --git a/libavformat/webvttenc.c b/libavformat/webvttenc.c index 4827de05d..61b7f5462 100644 --- a/libavformat/webvttenc.c +++ b/libavformat/webvttenc.c @@ -38,7 +38,7 @@ static void webvtt_write_time(AVIOContext *pb, int64_t millisec) min -= 60 * hour; if (hour > 0) - avio_printf(pb, "%"PRId64":", hour); + avio_printf(pb, "%02"PRId64":", hour); avio_printf(pb, "%02"PRId64":%02"PRId64".%03"PRId64"", min, sec, millisec); } diff --git a/libavformat/westwood_aud.c b/libavformat/westwood_aud.c index 9c2d35cb8..9e3d80752 100644 --- a/libavformat/westwood_aud.c +++ b/libavformat/westwood_aud.c @@ -42,7 +42,7 @@ #define AUD_CHUNK_PREAMBLE_SIZE 8 #define AUD_CHUNK_SIGNATURE 0x0000DEAF -static int wsaud_probe(AVProbeData *p) +static int wsaud_probe(const AVProbeData *p) { int field; diff --git a/libavformat/westwood_vqa.c b/libavformat/westwood_vqa.c index efb9847ff..c21a3e31f 100644 --- a/libavformat/westwood_vqa.c +++ b/libavformat/westwood_vqa.c @@ -62,7 +62,7 @@ typedef struct WsVqaDemuxContext { int video_stream_index; } WsVqaDemuxContext; -static int wsvqa_probe(AVProbeData *p) +static int wsvqa_probe(const AVProbeData *p) { /* need 12 bytes to qualify */ if (p->buf_size < 12) diff --git a/libavformat/wsddec.c b/libavformat/wsddec.c index 81a4dcc71..2313b0ec4 100644 --- a/libavformat/wsddec.c +++ b/libavformat/wsddec.c @@ -25,7 +25,7 @@ #include "internal.h" #include "rawdec.h" -static int wsd_probe(AVProbeData *p) +static int wsd_probe(const AVProbeData *p) { if (p->buf_size < 45 || memcmp(p->buf, "1bit", 4) || !AV_RB32(p->buf + 36) || !p->buf[44] || @@ -137,7 +137,7 @@ static int wsd_read_header(AVFormatContext *s) if (!(channel_assign & 1)) { int i; for (i = 1; i < 32; i++) - if (channel_assign & (1 << i)) + if ((channel_assign >> i) & 1) st->codecpar->channel_layout |= wsd_to_av_channel_layoyt(s, i); } @@ -161,6 +161,7 @@ static int wsd_read_header(AVFormatContext *s) return avio_seek(pb, data_offset, SEEK_SET); } +FF_RAW_DEMUXER_CLASS(wsd) AVInputFormat ff_wsd_demuxer = { .name = "wsd", .long_name = NULL_IF_CONFIG_SMALL("Wideband Single-bit Data (WSD)"), @@ -170,4 +171,6 @@ AVInputFormat ff_wsd_demuxer = { .extensions = "wsd", .flags = AVFMT_GENERIC_INDEX | AVFMT_NO_BYTE_SEEK, .raw_codec_id = AV_CODEC_ID_DSD_MSBF, + .priv_data_size = sizeof(FFRawDemuxerContext), + .priv_class = &wsd_demuxer_class, }; diff --git a/libavformat/wtvdec.c b/libavformat/wtvdec.c index 301163bdc..706e8ca38 100644 --- a/libavformat/wtvdec.c +++ b/libavformat/wtvdec.c @@ -149,7 +149,7 @@ static int read_ints(AVIOContext *pb, uint32_t *data, int count) * @param depth File allocation table depth * @return NULL on error */ -static AVIOContext * wtvfile_open_sector(int first_sector, uint64_t length, int depth, AVFormatContext *s) +static AVIOContext * wtvfile_open_sector(unsigned first_sector, uint64_t length, int depth, AVFormatContext *s) { AVIOContext *pb; WtvFile *wf; @@ -371,7 +371,7 @@ static const ff_asf_guid mediasubtype_dtvccdata = static const ff_asf_guid mediasubtype_mpeg2_sections = {0x79,0x85,0x9F,0x4A,0xF8,0x6B,0x92,0x43,0x8A,0x6D,0xD2,0xDD,0x09,0xFA,0x78,0x61}; -static int read_probe(AVProbeData *p) +static int read_probe(const AVProbeData *p) { return ff_guidcmp(p->buf, ff_wtv_guid) ? 0 : AVPROBE_SCORE_MAX; } @@ -957,7 +957,8 @@ static int parse_chunks(AVFormatContext *s, int mode, int64_t seekts, int *len_p static int read_header(AVFormatContext *s) { WtvContext *wtv = s->priv_data; - int root_sector, root_size; + unsigned root_sector; + int root_size; uint8_t root[WTV_SECTOR_SIZE]; AVIOContext *pb; int64_t timeline_pos; diff --git a/libavformat/wvdec.c b/libavformat/wvdec.c index 2060523c3..649791d15 100644 --- a/libavformat/wvdec.c +++ b/libavformat/wvdec.c @@ -60,7 +60,7 @@ typedef struct WVContext { int64_t apetag_start; } WVContext; -static int wv_probe(AVProbeData *p) +static int wv_probe(const AVProbeData *p) { /* check file header */ if (p->buf_size <= 32) @@ -159,10 +159,17 @@ static int wv_read_block_header(AVFormatContext *ctx, AVIOContext *pb) case 3: chmask = avio_rl32(pb); break; + case 4: + avio_skip(pb, 1); + chan |= (avio_r8(pb) & 0xF) << 8; + chan += 1; + chmask = avio_rl24(pb); + break; case 5: avio_skip(pb, 1); chan |= (avio_r8(pb) & 0xF) << 8; - chmask = avio_rl24(pb); + chan += 1; + chmask = avio_rl32(pb); break; default: av_log(ctx, AV_LOG_ERROR, diff --git a/libavformat/wvedec.c b/libavformat/wvedec.c index 89c00016c..4d9d3e520 100644 --- a/libavformat/wvedec.c +++ b/libavformat/wvedec.c @@ -22,7 +22,7 @@ #include "internal.h" #include "pcm.h" -static int wve_probe(AVProbeData *p) +static int wve_probe(const AVProbeData *p) { if (memcmp(p->buf, "ALawSoundFile**\0\017\020", 18) || memcmp(p->buf + 22, "\0\0\0\1\0\0\0\0\0\0", 10)) diff --git a/libavformat/xa.c b/libavformat/xa.c index 810e0c019..a07271b31 100644 --- a/libavformat/xa.c +++ b/libavformat/xa.c @@ -40,7 +40,7 @@ typedef struct MaxisXADemuxContext { uint32_t sent_bytes; } MaxisXADemuxContext; -static int xa_probe(AVProbeData *p) +static int xa_probe(const AVProbeData *p) { int channels, srate, bits_per_sample; if (p->buf_size < 24) diff --git a/libavformat/xmv.c b/libavformat/xmv.c index b974e5a6e..7f1295645 100644 --- a/libavformat/xmv.c +++ b/libavformat/xmv.c @@ -79,7 +79,7 @@ typedef struct XMVAudioPacket { uint16_t channels; ///< Number of channels. int32_t sample_rate; ///< Sampling rate. uint16_t bits_per_sample; ///< Bits per compressed sample. - uint32_t bit_rate; ///< Bits of compressed data per second. + uint64_t bit_rate; ///< Bits of compressed data per second. uint16_t flags; ///< Flags unsigned block_align; ///< Bytes per compressed block. uint16_t block_samples; ///< Decompressed samples per compressed block. @@ -115,7 +115,7 @@ typedef struct XMVDemuxContext { XMVAudioPacket *audio; ///< The audio packets contained in each packet. } XMVDemuxContext; -static int xmv_probe(AVProbeData *p) +static int xmv_probe(const AVProbeData *p) { uint32_t file_version; @@ -191,7 +191,7 @@ static int xmv_read_header(AVFormatContext *s) packet->bits_per_sample = avio_rl16(pb); packet->flags = avio_rl16(pb); - packet->bit_rate = packet->bits_per_sample * + packet->bit_rate = (uint64_t)packet->bits_per_sample * packet->sample_rate * packet->channels; packet->block_align = XMV_BLOCK_ALIGN_SIZE * packet->channels; diff --git a/libavformat/xvag.c b/libavformat/xvag.c index 22e4f1e3c..e95d84aa3 100644 --- a/libavformat/xvag.c +++ b/libavformat/xvag.c @@ -24,7 +24,7 @@ #include "avformat.h" #include "internal.h" -static int xvag_probe(AVProbeData *p) +static int xvag_probe(const AVProbeData *p) { if (memcmp(p->buf, "XVAG", 4) || memcmp(p->buf+32, "fmat", 4)) diff --git a/libavformat/xwma.c b/libavformat/xwma.c index 1c1877292..b08444929 100644 --- a/libavformat/xwma.c +++ b/libavformat/xwma.c @@ -34,7 +34,7 @@ typedef struct XWMAContext { int64_t data_end; } XWMAContext; -static int xwma_probe(AVProbeData *p) +static int xwma_probe(const AVProbeData *p) { if (!memcmp(p->buf, "RIFF", 4) && !memcmp(p->buf + 8, "XWMA", 4)) return AVPROBE_SCORE_MAX; @@ -80,19 +80,43 @@ static int xwma_read_header(AVFormatContext *s) return ret; st->need_parsing = AVSTREAM_PARSE_NONE; - /* All xWMA files I have seen contained WMAv2 data. If there are files - * using WMA Pro or some other codec, then we need to figure out the right - * extradata for that. Thus, ask the user for feedback, but try to go on - * anyway. - */ + /* XWMA encoder only allows a few channel/sample rate/bitrate combinations, + * but some create identical files with fake bitrate (1ch 22050hz at + * 20/48/192kbps are all 20kbps, with the exact same codec data). + * Decoder needs correct bitrate to work, so it's normalized here. */ + if (st->codecpar->codec_id == AV_CODEC_ID_WMAV2) { + int ch = st->codecpar->channels; + int sr = st->codecpar->sample_rate; + int br = st->codecpar->bit_rate; + + if (ch == 1) { + if (sr == 22050 && (br==48000 || br==192000)) + br = 20000; + else if (sr == 32000 && (br==48000 || br==192000)) + br = 20000; + else if (sr == 44100 && (br==96000 || br==192000)) + br = 48000; + } + else if (ch == 2) { + if (sr == 22050 && (br==48000 || br==192000)) + br = 32000; + else if (sr == 32000 && (br==192000)) + br = 48000; + } + + st->codecpar->bit_rate = br; + } + + /* Normally xWMA can only contain WMAv2 with 1/2 channels, + * and WMAPRO with 6 channels. */ if (st->codecpar->codec_id != AV_CODEC_ID_WMAV2 && st->codecpar->codec_id != AV_CODEC_ID_WMAPRO) { avpriv_request_sample(s, "Unexpected codec (tag %s; id %d)", av_fourcc2str(st->codecpar->codec_tag), st->codecpar->codec_id); } else { - /* In all xWMA files I have seen, there is no extradata. But the WMA - * codecs require extradata, so we provide our own fake extradata. + /* xWMA shouldn't have extradata. But the WMA codecs require it, + * so we provide our own fake extradata. * * First, check that there really was no extradata in the header. If * there was, then try to use it, after asking the user to provide a diff --git a/libavformat/yop.c b/libavformat/yop.c index e6fd89666..f9ead026a 100644 --- a/libavformat/yop.c +++ b/libavformat/yop.c @@ -36,7 +36,7 @@ typedef struct yop_dec_context { int palette_size; } YopDecContext; -static int yop_probe(AVProbeData *probe_packet) +static int yop_probe(const AVProbeData *probe_packet) { if (AV_RB16(probe_packet->buf) == AV_RB16("YO") && probe_packet->buf[2]<10 && @@ -68,10 +68,6 @@ static int yop_read_header(AVFormatContext *s) if (!audio_stream || !video_stream) return AVERROR(ENOMEM); - // Extra data that will be passed to the decoder - if (ff_alloc_extradata(video_stream->codecpar, 8)) - return AVERROR(ENOMEM); - // Audio audio_par = audio_stream->codecpar; audio_par->codec_type = AVMEDIA_TYPE_AUDIO; @@ -94,9 +90,9 @@ static int yop_read_header(AVFormatContext *s) video_stream->sample_aspect_ratio = (AVRational){1, 2}; - ret = avio_read(pb, video_par->extradata, 8); - if (ret < 8) - return ret < 0 ? ret : AVERROR_EOF; + ret = ff_get_extradata(s, video_par, pb, 8); + if (ret < 0) + return ret; yop->palette_size = video_par->extradata[0] * 3 + 4; yop->audio_block_length = AV_RL16(video_par->extradata + 6); diff --git a/libavformat/yuv4mpegdec.c b/libavformat/yuv4mpegdec.c index ff0125e4c..fc2f0ca05 100644 --- a/libavformat/yuv4mpegdec.c +++ b/libavformat/yuv4mpegdec.c @@ -41,6 +41,7 @@ static int yuv4_read_header(AVFormatContext *s) enum AVPixelFormat pix_fmt = AV_PIX_FMT_NONE, alt_pix_fmt = AV_PIX_FMT_NONE; enum AVChromaLocation chroma_sample_location = AVCHROMA_LOC_UNSPECIFIED; enum AVFieldOrder field_order = AV_FIELD_UNKNOWN; + enum AVColorRange color_range = AVCOL_RANGE_UNSPECIFIED; AVStream *st; for (i = 0; i < MAX_YUV4_HEADER; i++) { @@ -220,6 +221,12 @@ static int yuv4_read_header(AVFormatContext *s) alt_pix_fmt = AV_PIX_FMT_YUV422P; else if (strncmp("444", tokstart, 3) == 0) alt_pix_fmt = AV_PIX_FMT_YUV444P; + } else if (strncmp("COLORRANGE=", tokstart, 11) == 0) { + tokstart += 11; + if (strncmp("FULL",tokstart, 4) == 0) + color_range = AVCOL_RANGE_JPEG; + else if (strncmp("LIMITED", tokstart, 7) == 0) + color_range = AVCOL_RANGE_MPEG; } while (tokstart < header_end && *tokstart != 0x20) tokstart++; @@ -263,6 +270,7 @@ static int yuv4_read_header(AVFormatContext *s) st->codecpar->codec_id = AV_CODEC_ID_RAWVIDEO; st->sample_aspect_ratio = (AVRational){ aspectn, aspectd }; st->codecpar->chroma_location = chroma_sample_location; + st->codecpar->color_range = color_range; st->codecpar->field_order = field_order; s->packet_size = av_image_get_buffer_size(st->codecpar->format, width, height, 1) + Y4M_FRAME_MAGIC_LEN; if ((int) s->packet_size < 0) @@ -314,12 +322,18 @@ static int yuv4_read_packet(AVFormatContext *s, AVPacket *pkt) static int yuv4_read_seek(AVFormatContext *s, int stream_index, int64_t pts, int flags) { - if (avio_seek(s->pb, pts * s->packet_size + s->internal->data_offset, SEEK_SET) < 0) + int64_t pos; + + if (flags & AVSEEK_FLAG_BACKWARD) + pts = FFMAX(0, pts - 1); + pos = pts * s->packet_size; + + if (avio_seek(s->pb, pos + s->internal->data_offset, SEEK_SET) < 0) return -1; return 0; } -static int yuv4_probe(AVProbeData *pd) +static int yuv4_probe(const AVProbeData *pd) { /* check file header */ if (strncmp(pd->buf, Y4M_MAGIC, sizeof(Y4M_MAGIC) - 1) == 0) diff --git a/libavformat/yuv4mpegenc.c b/libavformat/yuv4mpegenc.c index 44f40bbad..e84dbf956 100644 --- a/libavformat/yuv4mpegenc.c +++ b/libavformat/yuv4mpegenc.c @@ -33,6 +33,7 @@ static int yuv4_generate_header(AVFormatContext *s, char* buf) int raten, rated, aspectn, aspectd, n; char inter; const char *colorspace = ""; + const char *colorrange = ""; int field_order; st = s->streams[0]; @@ -57,6 +58,17 @@ static int yuv4_generate_header(AVFormatContext *s, char* buf) FF_ENABLE_DEPRECATION_WARNINGS #endif + switch(st->codecpar->color_range) { + case AVCOL_RANGE_MPEG: + colorrange = " XCOLORRANGE=LIMITED"; + break; + case AVCOL_RANGE_JPEG: + colorrange = " XCOLORRANGE=FULL"; + break; + default: + break; + } + switch (field_order) { case AV_FIELD_TB: case AV_FIELD_TT: inter = 't'; break; @@ -84,6 +96,18 @@ static int yuv4_generate_header(AVFormatContext *s, char* buf) case AV_PIX_FMT_YUV411P: colorspace = " C411 XYSCSS=411"; break; + case AV_PIX_FMT_YUVJ420P: + colorspace = " C420jpeg XYSCSS=420JPEG"; + colorrange = " XCOLORRANGE=FULL"; + break; + case AV_PIX_FMT_YUVJ422P: + colorspace = " C422 XYSCSS=422"; + colorrange = " XCOLORRANGE=FULL"; + break; + case AV_PIX_FMT_YUVJ444P: + colorspace = " C444 XYSCSS=444"; + colorrange = " XCOLORRANGE=FULL"; + break; case AV_PIX_FMT_YUV420P: switch (st->codecpar->chroma_location) { case AVCHROMA_LOC_TOPLEFT: colorspace = " C420paldv XYSCSS=420PALDV"; break; @@ -145,13 +169,14 @@ static int yuv4_generate_header(AVFormatContext *s, char* buf) } /* construct stream header, if this is the first frame */ - n = snprintf(buf, Y4M_LINE_MAX, "%s W%d H%d F%d:%d I%c A%d:%d%s\n", + n = snprintf(buf, Y4M_LINE_MAX, "%s W%d H%d F%d:%d I%c A%d:%d%s%s\n", Y4M_MAGIC, width, height, raten, rated, inter, - aspectn, aspectd, colorspace); + aspectn, aspectd, colorspace, colorrange); return n; } + static int yuv4_write_packet(AVFormatContext *s, AVPacket *pkt) { AVStream *st = s->streams[pkt->stream_index]; @@ -192,6 +217,10 @@ static int yuv4_write_packet(AVFormatContext *s, AVPacket *pkt) case AV_PIX_FMT_YUV420P: case AV_PIX_FMT_YUV422P: case AV_PIX_FMT_YUV444P: + // TODO: remove YUVJ pixel formats when they are completely removed from the codebase. + case AV_PIX_FMT_YUVJ420P: + case AV_PIX_FMT_YUVJ422P: + case AV_PIX_FMT_YUVJ444P: break; case AV_PIX_FMT_GRAY9: case AV_PIX_FMT_GRAY10: @@ -271,6 +300,10 @@ static int yuv4_write_header(AVFormatContext *s) case AV_PIX_FMT_YUV420P: case AV_PIX_FMT_YUV422P: case AV_PIX_FMT_YUV444P: + // TODO: remove YUVJ pixel formats when they are completely removed from the codebase. + case AV_PIX_FMT_YUVJ420P: + case AV_PIX_FMT_YUVJ422P: + case AV_PIX_FMT_YUVJ444P: break; case AV_PIX_FMT_GRAY9: case AV_PIX_FMT_GRAY10: diff --git a/libavutil/Makefile b/libavutil/Makefile index a63ba523c..8a7a44e4b 100644 --- a/libavutil/Makefile +++ b/libavutil/Makefile @@ -31,6 +31,7 @@ HEADERS = adler32.h \ file.h \ frame.h \ hash.h \ + hdr_dynamic_metadata.h \ hmac.h \ hwcontext.h \ hwcontext_cuda.h \ @@ -78,6 +79,7 @@ HEADERS = adler32.h \ version.h \ xtea.h \ tea.h \ + tx.h \ HEADERS-$(CONFIG_LZO) += lzo.h @@ -94,6 +96,7 @@ OBJS = adler32.o \ aes_ctr.o \ audio_fifo.o \ avstring.o \ + avsscanf.o \ base64.o \ blowfish.o \ bprint.o \ @@ -118,6 +121,7 @@ OBJS = adler32.o \ fixed_dsp.o \ frame.o \ hash.o \ + hdr_dynamic_metadata.o \ hmac.o \ hwcontext.o \ imgutils.o \ @@ -156,18 +160,19 @@ OBJS = adler32.o \ xga_font_data.o \ xtea.o \ tea.o \ + tx.o \ OBJS-$(CONFIG_CUDA) += hwcontext_cuda.o OBJS-$(CONFIG_D3D11VA) += hwcontext_d3d11va.o OBJS-$(CONFIG_DXVA2) += hwcontext_dxva2.o -OBJS-$(CONFIG_QSV) += hwcontext_qsv.o OBJS-$(CONFIG_LIBDRM) += hwcontext_drm.o OBJS-$(CONFIG_LZO) += lzo.o +OBJS-$(CONFIG_MEDIACODEC) += hwcontext_mediacodec.o OBJS-$(CONFIG_OPENCL) += hwcontext_opencl.o +OBJS-$(CONFIG_QSV) += hwcontext_qsv.o OBJS-$(CONFIG_VAAPI) += hwcontext_vaapi.o OBJS-$(CONFIG_VIDEOTOOLBOX) += hwcontext_videotoolbox.o OBJS-$(CONFIG_VDPAU) += hwcontext_vdpau.o -OBJS-$(CONFIG_MEDIACODEC) += hwcontext_mediacodec.o OBJS += $(COMPAT_OBJS:%=../compat/%) @@ -175,10 +180,11 @@ OBJS += $(COMPAT_OBJS:%=../compat/%) SLIBOBJS-$(HAVE_GNU_WINDRES) += avutilres.o SKIPHEADERS-$(HAVE_CUDA_H) += hwcontext_cuda.h -SKIPHEADERS-$(CONFIG_CUDA) += hwcontext_cuda_internal.h +SKIPHEADERS-$(CONFIG_CUDA) += hwcontext_cuda_internal.h \ + cuda_check.h SKIPHEADERS-$(CONFIG_D3D11VA) += hwcontext_d3d11va.h SKIPHEADERS-$(CONFIG_DXVA2) += hwcontext_dxva2.h -SKIPHEADERS-$(CONFIG_QSV) += hwcontext_qsv.h +SKIPHEADERS-$(CONFIG_QSV) += hwcontext_qsv.h SKIPHEADERS-$(CONFIG_OPENCL) += hwcontext_opencl.h SKIPHEADERS-$(CONFIG_VAAPI) += hwcontext_vaapi.h SKIPHEADERS-$(CONFIG_VIDEOTOOLBOX) += hwcontext_videotoolbox.h @@ -200,12 +206,14 @@ TESTPROGS = adler32 \ des \ dict \ display \ + encryption_info \ error \ eval \ file \ fifo \ hash \ hmac \ + hwdevice \ integer \ imgutils \ lfg \ diff --git a/libavutil/aarch64/asm.S b/libavutil/aarch64/asm.S index fd32bf784..5c329430f 100644 --- a/libavutil/aarch64/asm.S +++ b/libavutil/aarch64/asm.S @@ -63,6 +63,8 @@ ELF .size \name, . - \name .else .section .rodata .endif +#elif defined(_WIN32) + .section .rdata #elif !defined(__MACH__) .section .rodata #else diff --git a/libavutil/arm/asm.S b/libavutil/arm/asm.S index 6744f2a20..e3a8c7f06 100644 --- a/libavutil/arm/asm.S +++ b/libavutil/arm/asm.S @@ -46,6 +46,12 @@ # define FPU @ #endif +#if CONFIG_THUMB && defined(__APPLE__) +# define TFUNC +#else +# define TFUNC @ +#endif + #if HAVE_AS_ARCH_DIRECTIVE #if HAVE_NEON .arch armv7-a @@ -98,10 +104,12 @@ FUNC .endfunc .global EXTERN_ASM\name ELF .type EXTERN_ASM\name, %function FUNC .func EXTERN_ASM\name +TFUNC .thumb_func EXTERN_ASM\name EXTERN_ASM\name: .else ELF .type \name, %function FUNC .func \name +TFUNC .thumb_func \name \name: .endif .endm @@ -117,6 +125,8 @@ ELF .size \name, . - \name .else .section .rodata .endif +#elif defined(_WIN32) + .section .rdata #elif !defined(__MACH__) .section .rodata #else diff --git a/libavutil/avassert.h b/libavutil/avassert.h index 46f3fea58..9abeadea4 100644 --- a/libavutil/avassert.h +++ b/libavutil/avassert.h @@ -66,7 +66,7 @@ #endif /** - * Assert that floating point opperations can be executed. + * Assert that floating point operations can be executed. * * This will av_assert0() that the cpu is not in MMX state on X86 */ diff --git a/libavutil/avsscanf.c b/libavutil/avsscanf.c new file mode 100644 index 000000000..1c85412fd --- /dev/null +++ b/libavutil/avsscanf.c @@ -0,0 +1,970 @@ +/* + * Copyright (c) 2005-2014 Rich Felker, et al. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include +#include +#include + +#include "config.h" +#include "common.h" +#include "mem.h" +#include "avassert.h" +#include "avstring.h" +#include "bprint.h" + +typedef struct FFFILE { + size_t buf_size; + unsigned char *buf; + unsigned char *rpos, *rend; + unsigned char *shend; + ptrdiff_t shlim, shcnt; + void *cookie; + size_t (*read)(struct FFFILE *, unsigned char *, size_t); +} FFFILE; + +#define SIZE_hh -2 +#define SIZE_h -1 +#define SIZE_def 0 +#define SIZE_l 1 +#define SIZE_L 2 +#define SIZE_ll 3 + +#define shcnt(f) ((f)->shcnt + ((f)->rpos - (f)->buf)) + +static int fftoread(FFFILE *f) +{ + f->rpos = f->rend = f->buf + f->buf_size; + return 0; +} + +static size_t ffstring_read(FFFILE *f, unsigned char *buf, size_t len) +{ + char *src = f->cookie; + size_t k = len+256; + char *end = memchr(src, 0, k); + + if (end) k = end-src; + if (k < len) len = k; + memcpy(buf, src, len); + f->rpos = (void *)(src+len); + f->rend = (void *)(src+k); + f->cookie = src+k; + + return len; +} + +static int ffuflow(FFFILE *f) +{ + unsigned char c; + if (!fftoread(f) && f->read(f, &c, 1)==1) return c; + return EOF; +} + +static void ffshlim(FFFILE *f, ptrdiff_t lim) +{ + f->shlim = lim; + f->shcnt = f->buf - f->rpos; + /* If lim is nonzero, rend must be a valid pointer. */ + if (lim && f->rend - f->rpos > lim) + f->shend = f->rpos + lim; + else + f->shend = f->rend; +} + +static int ffshgetc(FFFILE *f) +{ + int c; + ptrdiff_t cnt = shcnt(f); + if (f->shlim && cnt >= f->shlim || (c=ffuflow(f)) < 0) { + f->shcnt = f->buf - f->rpos + cnt; + f->shend = 0; + return EOF; + } + cnt++; + if (f->shlim && f->rend - f->rpos > f->shlim - cnt) + f->shend = f->rpos + (f->shlim - cnt); + else + f->shend = f->rend; + f->shcnt = f->buf - f->rpos + cnt; + if (f->rpos[-1] != c) f->rpos[-1] = c; + return c; +} + +#define shlim(f, lim) ffshlim((f), (lim)) +#define shgetc(f) (((f)->rpos != (f)->shend) ? *(f)->rpos++ : ffshgetc(f)) +#define shunget(f) ((f)->shend ? (void)(f)->rpos-- : (void)0) + +static const unsigned char table[] = { -1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1, + -1,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24, + 25,26,27,28,29,30,31,32,33,34,35,-1,-1,-1,-1,-1, + -1,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24, + 25,26,27,28,29,30,31,32,33,34,35,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, +}; + +static unsigned long long ffintscan(FFFILE *f, unsigned base, int pok, unsigned long long lim) +{ + const unsigned char *val = table+1; + int c, neg=0; + unsigned x; + unsigned long long y; + if (base > 36 || base == 1) { + errno = EINVAL; + return 0; + } + while (av_isspace((c=shgetc(f)))); + if (c=='+' || c=='-') { + neg = -(c=='-'); + c = shgetc(f); + } + if ((base == 0 || base == 16) && c=='0') { + c = shgetc(f); + if ((c|32)=='x') { + c = shgetc(f); + if (val[c]>=16) { + shunget(f); + if (pok) shunget(f); + else shlim(f, 0); + return 0; + } + base = 16; + } else if (base == 0) { + base = 8; + } + } else { + if (base == 0) base = 10; + if (val[c] >= base) { + shunget(f); + shlim(f, 0); + errno = EINVAL; + return 0; + } + } + if (base == 10) { + for (x=0; c-'0'<10U && x<=UINT_MAX/10-1; c=shgetc(f)) + x = x*10 + (c-'0'); + for (y=x; c-'0'<10U && y<=ULLONG_MAX/10 && 10*y<=ULLONG_MAX-(c-'0'); c=shgetc(f)) + y = y*10 + (c-'0'); + if (c-'0'>=10U) goto done; + } else if (!(base & base-1)) { + int bs = "\0\1\2\4\7\3\6\5"[(0x17*base)>>5&7]; + for (x=0; val[c]>bs; c=shgetc(f)) + y = y<=lim) { + if (!(lim&1) && !neg) { + errno = ERANGE; + return lim-1; + } else if (y>lim) { + errno = ERANGE; + return lim; + } + } + return (y^neg)-neg; +} + +static long long scanexp(FFFILE *f, int pok) +{ + int c; + int x; + long long y; + int neg = 0; + + c = shgetc(f); + if (c=='+' || c=='-') { + neg = (c=='-'); + c = shgetc(f); + if (c-'0'>=10U && pok) shunget(f); + } + if (c-'0'>=10U) { + shunget(f); + return LLONG_MIN; + } + for (x=0; c-'0'<10U && x=0) { + shunget(f); + } + if (!gotdig) { + errno = EINVAL; + shlim(f, 0); + return 0; + } + + /* Handle zero specially to avoid nasty special cases later */ + if (!x[0]) return sign * 0.0; + + /* Optimize small integers (w/no exponent) and over/under-flow */ + if (lrp==dc && dc<10 && (bits>30 || x[0]>>bits==0)) + return sign * (double)x[0]; + if (lrp > -emin/2) { + errno = ERANGE; + return sign * DBL_MAX * DBL_MAX; + } + if (lrp < emin-2*DBL_MANT_DIG) { + errno = ERANGE; + return sign * DBL_MIN * DBL_MIN; + } + + /* Align incomplete final B1B digit */ + if (j) { + for (; j<9; j++) x[k]*=10; + k++; + j=0; + } + + a = 0; + z = k; + e2 = 0; + rp = lrp; + + /* Optimize small to mid-size integers (even in exp. notation) */ + if (lnz<9 && lnz<=rp && rp < 18) { + int bitlim; + if (rp == 9) return sign * (double)x[0]; + if (rp < 9) return sign * (double)x[0] / p10s[8-rp]; + bitlim = bits-3*(int)(rp-9); + if (bitlim>30 || x[0]>>bitlim==0) + return sign * (double)x[0] * p10s[rp-10]; + } + + /* Drop trailing zeros */ + for (; !x[z-1]; z--); + + /* Align radix point to B1B digit boundary */ + if (rp % 9) { + int rpm9 = rp>=0 ? rp%9 : rp%9+9; + int p10 = p10s[8-rpm9]; + uint32_t carry = 0; + for (k=a; k!=z; k++) { + uint32_t tmp = x[k] % p10; + x[k] = x[k]/p10 + carry; + carry = 1000000000/p10 * tmp; + if (k==a && !x[k]) { + a = (a+1 & MASK); + rp -= 9; + } + } + if (carry) x[z++] = carry; + rp += 9-rpm9; + } + + /* Upscale until desired number of bits are left of radix point */ + while (rp < 9*LD_B1B_DIG || (rp == 9*LD_B1B_DIG && x[a] 1000000000) { + carry = tmp / 1000000000; + x[k] = tmp % 1000000000; + } else { + carry = 0; + x[k] = tmp; + } + if (k==(z-1 & MASK) && k!=a && !x[k]) z = k; + if (k==a) break; + } + if (carry) { + rp += 9; + a = (a-1 & MASK); + if (a == z) { + z = (z-1 & MASK); + x[z-1 & MASK] |= x[z]; + } + x[a] = carry; + } + } + + /* Downscale until exactly number of bits are left of radix point */ + for (;;) { + uint32_t carry = 0; + int sh = 1; + for (i=0; i th[i]) break; + } + if (i==LD_B1B_DIG && rp==9*LD_B1B_DIG) break; + /* FIXME: find a way to compute optimal sh */ + if (rp > 9+9*LD_B1B_DIG) sh = 9; + e2 += sh; + for (k=a; k!=z; k=(k+1 & MASK)) { + uint32_t tmp = x[k] & (1<>sh) + carry; + carry = (1000000000>>sh) * tmp; + if (k==a && !x[k]) { + a = (a+1 & MASK); + i--; + rp -= 9; + } + } + if (carry) { + if ((z+1 & MASK) != a) { + x[z] = carry; + z = (z+1 & MASK); + } else x[z-1 & MASK] |= 1; + } + } + + /* Assemble desired bits into floating point variable */ + for (y=i=0; i DBL_MANT_DIG+e2-emin) { + bits = DBL_MANT_DIG+e2-emin; + if (bits<0) bits=0; + denormal = 1; + } + + /* Calculate bias term to force rounding, move out lower bits */ + if (bits < DBL_MANT_DIG) { + bias = copysign(scalbn(1, 2*DBL_MANT_DIG-bits-1), y); + frac = fmod(y, scalbn(1, DBL_MANT_DIG-bits)); + y -= frac; + y += bias; + } + + /* Process tail of decimal input so it can affect rounding */ + if ((a+i & MASK) != z) { + uint32_t t = x[a+i & MASK]; + if (t < 500000000 && (t || (a+i+1 & MASK) != z)) + frac += 0.25*sign; + else if (t > 500000000) + frac += 0.75*sign; + else if (t == 500000000) { + if ((a+i+1 & MASK) == z) + frac += 0.5*sign; + else + frac += 0.75*sign; + } + if (DBL_MANT_DIG-bits >= 2 && !fmod(frac, 1)) + frac++; + } + + y += frac; + y -= bias; + + if ((e2+DBL_MANT_DIG & INT_MAX) > emax-5) { + if (fabs(y) >= pow(2, DBL_MANT_DIG)) { + if (denormal && bits==DBL_MANT_DIG+e2-emin) + denormal = 0; + y *= 0.5; + e2++; + } + if (e2+DBL_MANT_DIG>emax || (denormal && frac)) + errno = ERANGE; + } + + return scalbn(y, e2); +} + +static double hexfloat(FFFILE *f, int bits, int emin, int sign, int pok) +{ + uint32_t x = 0; + double y = 0; + double scale = 1; + double bias = 0; + int gottail = 0, gotrad = 0, gotdig = 0; + long long rp = 0; + long long dc = 0; + long long e2 = 0; + int d; + int c; + + c = shgetc(f); + + /* Skip leading zeros */ + for (; c=='0'; c = shgetc(f)) + gotdig = 1; + + if (c=='.') { + gotrad = 1; + c = shgetc(f); + /* Count zeros after the radix point before significand */ + for (rp=0; c=='0'; c = shgetc(f), rp--) gotdig = 1; + } + + for (; c-'0'<10U || (c|32)-'a'<6U || c=='.'; c = shgetc(f)) { + if (c=='.') { + if (gotrad) break; + rp = dc; + gotrad = 1; + } else { + gotdig = 1; + if (c > '9') d = (c|32)+10-'a'; + else d = c-'0'; + if (dc<8) { + x = x*16 + d; + } else if (dc < DBL_MANT_DIG/4+1) { + y += d*(scale/=16); + } else if (d && !gottail) { + y += 0.5*scale; + gottail = 1; + } + dc++; + } + } + if (!gotdig) { + shunget(f); + if (pok) { + shunget(f); + if (gotrad) shunget(f); + } else { + shlim(f, 0); + } + return sign * 0.0; + } + if (!gotrad) rp = dc; + while (dc<8) x *= 16, dc++; + if ((c|32)=='p') { + e2 = scanexp(f, pok); + if (e2 == LLONG_MIN) { + if (pok) { + shunget(f); + } else { + shlim(f, 0); + return 0; + } + e2 = 0; + } + } else { + shunget(f); + } + e2 += 4*rp - 32; + + if (!x) return sign * 0.0; + if (e2 > -emin) { + errno = ERANGE; + return sign * DBL_MAX * DBL_MAX; + } + if (e2 < emin-2*DBL_MANT_DIG) { + errno = ERANGE; + return sign * DBL_MIN * DBL_MIN; + } + + while (x < 0x80000000) { + if (y>=0.5) { + x += x + 1; + y += y - 1; + } else { + x += x; + y += y; + } + e2--; + } + + if (bits > 32+e2-emin) { + bits = 32+e2-emin; + if (bits<0) bits=0; + } + + if (bits < DBL_MANT_DIG) + bias = copysign(scalbn(1, 32+DBL_MANT_DIG-bits-1), sign); + + if (bits<32 && y && !(x&1)) x++, y=0; + + y = bias + sign*(double)x + sign*y; + y -= bias; + + if (!y) errno = ERANGE; + + return scalbn(y, e2); +} + +static double fffloatscan(FFFILE *f, int prec, int pok) +{ + int sign = 1; + size_t i; + int bits; + int emin; + int c; + + switch (prec) { + case 0: + bits = FLT_MANT_DIG; + emin = FLT_MIN_EXP-bits; + break; + case 1: + bits = DBL_MANT_DIG; + emin = DBL_MIN_EXP-bits; + break; + case 2: + bits = DBL_MANT_DIG; + emin = DBL_MIN_EXP-bits; + break; + default: + return 0; + } + + while (av_isspace((c = shgetc(f)))); + + if (c=='+' || c=='-') { + sign -= 2*(c=='-'); + c = shgetc(f); + } + + for (i=0; i<8 && (c|32)=="infinity"[i]; i++) + if (i<7) c = shgetc(f); + if (i==3 || i==8 || (i>3 && pok)) { + if (i!=8) { + shunget(f); + if (pok) for (; i>3; i--) shunget(f); + } + return sign * INFINITY; + } + if (!i) for (i=0; i<3 && (c|32)=="nan"[i]; i++) + if (i<2) c = shgetc(f); + if (i==3) { + if (shgetc(f) != '(') { + shunget(f); + return NAN; + } + for (i=1; ; i++) { + c = shgetc(f); + if (c-'0'<10U || c-'A'<26U || c-'a'<26U || c=='_') + continue; + if (c==')') return NAN; + shunget(f); + if (!pok) { + errno = EINVAL; + shlim(f, 0); + return 0; + } + while (i--) shunget(f); + return NAN; + } + return NAN; + } + + if (i) { + shunget(f); + errno = EINVAL; + shlim(f, 0); + return 0; + } + + if (c=='0') { + c = shgetc(f); + if ((c|32) == 'x') + return hexfloat(f, bits, emin, sign, pok); + shunget(f); + c = '0'; + } + + return decfloat(f, c, bits, emin, sign, pok); +} + +static void *arg_n(va_list ap, unsigned int n) +{ + void *p; + unsigned int i; + va_list ap2; + va_copy(ap2, ap); + for (i=n; i>1; i--) va_arg(ap2, void *); + p = va_arg(ap2, void *); + va_end(ap2); + return p; +} + +static void store_int(void *dest, int size, unsigned long long i) +{ + if (!dest) return; + switch (size) { + case SIZE_hh: + *(char *)dest = i; + break; + case SIZE_h: + *(short *)dest = i; + break; + case SIZE_def: + *(int *)dest = i; + break; + case SIZE_l: + *(long *)dest = i; + break; + case SIZE_ll: + *(long long *)dest = i; + break; + } +} + +static int ff_vfscanf(FFFILE *f, const char *fmt, va_list ap) +{ + int width; + int size; + int base; + const unsigned char *p; + int c, t; + char *s; + void *dest=NULL; + int invert; + int matches=0; + unsigned long long x; + double y; + ptrdiff_t pos = 0; + unsigned char scanset[257]; + size_t i; + + for (p=(const unsigned char *)fmt; *p; p++) { + + if (av_isspace(*p)) { + while (av_isspace(p[1])) p++; + shlim(f, 0); + while (av_isspace(shgetc(f))); + shunget(f); + pos += shcnt(f); + continue; + } + if (*p != '%' || p[1] == '%') { + shlim(f, 0); + if (*p == '%') { + p++; + while (av_isspace((c=shgetc(f)))); + } else { + c = shgetc(f); + } + if (c!=*p) { + shunget(f); + if (c<0) goto input_fail; + goto match_fail; + } + pos += shcnt(f); + continue; + } + + p++; + if (*p=='*') { + dest = 0; p++; + } else if (av_isdigit(*p) && p[1]=='$') { + dest = arg_n(ap, *p-'0'); p+=2; + } else { + dest = va_arg(ap, void *); + } + + for (width=0; av_isdigit(*p); p++) { + width = 10*width + *p - '0'; + } + + if (*p=='m') { + s = 0; + p++; + } + + size = SIZE_def; + switch (*p++) { + case 'h': + if (*p == 'h') p++, size = SIZE_hh; + else size = SIZE_h; + break; + case 'l': + if (*p == 'l') p++, size = SIZE_ll; + else size = SIZE_l; + break; + case 'j': + size = SIZE_ll; + break; + case 'z': + case 't': + size = SIZE_l; + break; + case 'L': + size = SIZE_L; + break; + case 'd': case 'i': case 'o': case 'u': case 'x': + case 'a': case 'e': case 'f': case 'g': + case 'A': case 'E': case 'F': case 'G': case 'X': + case 's': case 'c': case '[': + case 'S': case 'C': + case 'p': case 'n': + p--; + break; + default: + goto fmt_fail; + } + + t = *p; + + /* C or S */ + if ((t&0x2f) == 3) { + t |= 32; + size = SIZE_l; + } + + switch (t) { + case 'c': + if (width < 1) width = 1; + case '[': + break; + case 'n': + store_int(dest, size, pos); + /* do not increment match count, etc! */ + continue; + default: + shlim(f, 0); + while (av_isspace(shgetc(f))); + shunget(f); + pos += shcnt(f); + } + + shlim(f, width); + if (shgetc(f) < 0) goto input_fail; + shunget(f); + + switch (t) { + case 's': + case 'c': + case '[': + if (t == 'c' || t == 's') { + memset(scanset, -1, sizeof scanset); + scanset[0] = 0; + if (t == 's') { + scanset[1 + '\t'] = 0; + scanset[1 + '\n'] = 0; + scanset[1 + '\v'] = 0; + scanset[1 + '\f'] = 0; + scanset[1 + '\r'] = 0; + scanset[1 + ' ' ] = 0; + } + } else { + if (*++p == '^') p++, invert = 1; + else invert = 0; + memset(scanset, invert, sizeof scanset); + scanset[0] = 0; + if (*p == '-') p++, scanset[1+'-'] = 1-invert; + else if (*p == ']') p++, scanset[1+']'] = 1-invert; + for (; *p != ']'; p++) { + if (!*p) goto fmt_fail; + if (*p=='-' && p[1] && p[1] != ']') + for (c=p++[-1]; c<*p; c++) + scanset[1+c] = 1-invert; + scanset[1+*p] = 1-invert; + } + } + s = 0; + i = 0; + if ((s = dest)) { + while (scanset[(c=shgetc(f))+1]) + s[i++] = c; + } else { + while (scanset[(c=shgetc(f))+1]); + } + shunget(f); + if (!shcnt(f)) goto match_fail; + if (t == 'c' && shcnt(f) != width) goto match_fail; + if (t != 'c') { + if (s) s[i] = 0; + } + break; + case 'p': + case 'X': + case 'x': + base = 16; + goto int_common; + case 'o': + base = 8; + goto int_common; + case 'd': + case 'u': + base = 10; + goto int_common; + case 'i': + base = 0; +int_common: + x = ffintscan(f, base, 0, ULLONG_MAX); + if (!shcnt(f)) + goto match_fail; + if (t=='p' && dest) + *(void **)dest = (void *)(uintptr_t)x; + else + store_int(dest, size, x); + break; + case 'a': case 'A': + case 'e': case 'E': + case 'f': case 'F': + case 'g': case 'G': + y = fffloatscan(f, size, 0); + if (!shcnt(f)) + goto match_fail; + if (dest) { + switch (size) { + case SIZE_def: + *(float *)dest = y; + break; + case SIZE_l: + *(double *)dest = y; + break; + case SIZE_L: + *(double *)dest = y; + break; + } + } + break; + } + + pos += shcnt(f); + if (dest) matches++; + } + if (0) { +fmt_fail: +input_fail: + if (!matches) matches--; + } +match_fail: + return matches; +} + +static int ff_vsscanf(const char *s, const char *fmt, va_list ap) +{ + FFFILE f = { + .buf = (void *)s, .cookie = (void *)s, + .read = ffstring_read, + }; + + return ff_vfscanf(&f, fmt, ap); +} + +int av_sscanf(const char *string, const char *format, ...) +{ + int ret; + va_list ap; + va_start(ap, format); + ret = ff_vsscanf(string, format, ap); + va_end(ap); + return ret; +} diff --git a/libavutil/avstring.c b/libavutil/avstring.c index f03dd2514..4c068f5bc 100644 --- a/libavutil/avstring.c +++ b/libavutil/avstring.c @@ -222,12 +222,13 @@ int av_strcasecmp(const char *a, const char *b) int av_strncasecmp(const char *a, const char *b, size_t n) { - const char *end = a + n; uint8_t c1, c2; + if (n <= 0) + return 0; do { c1 = av_tolower(*a++); c2 = av_tolower(*b++); - } while (a < end && c1 && c1 == c2); + } while (--n && c1 && c1 == c2); return c1 - c2; } diff --git a/libavutil/avstring.h b/libavutil/avstring.h index 04d269564..37dd4e2da 100644 --- a/libavutil/avstring.h +++ b/libavutil/avstring.h @@ -400,6 +400,12 @@ int av_utf8_decode(int32_t *codep, const uint8_t **bufp, const uint8_t *buf_end, */ int av_match_list(const char *name, const char *list, char separator); +/** + * See libc sscanf manual for more information. + * Locale-independent sscanf implementation. + */ +int av_sscanf(const char *string, const char *format, ...); + /** * @} */ diff --git a/libavutil/colorspace.h b/libavutil/colorspace.h index b6dba2c95..ef6f6107d 100644 --- a/libavutil/colorspace.h +++ b/libavutil/colorspace.h @@ -107,4 +107,44 @@ static inline int C_JPEG_TO_CCIR(int y) { (((FIX(0.50000*224.0/255.0) * r1 - FIX(0.41869*224.0/255.0) * g1 - \ FIX(0.08131*224.0/255.0) * b1 + (ONE_HALF << shift) - 1) >> (SCALEBITS + shift)) + 128) +#define RGB_TO_Y_JPEG(r, g, b) \ +(FFMIN((FIX(0.29900) * (r) + FIX(0.58700) * (g) + \ + FIX(0.11400) * (b) + (ONE_HALF)) >> SCALEBITS, 255)) + +#define RGB_TO_U_JPEG(r1, g1, b1)\ +(((- FIX(0.16874) * r1 - FIX(0.33126) * g1 + \ + FIX(0.50000) * b1 + (ONE_HALF) - 1) >> (SCALEBITS)) + 128) + +#define RGB_TO_V_JPEG(r1, g1, b1)\ +(((FIX(0.50000) * r1 - FIX(0.41869) * g1 - \ + FIX(0.08131) * b1 + (ONE_HALF) - 1) >> (SCALEBITS)) + 128) + +// Conversion macros for 8-bit RGB to YUV +// Derived from ITU-R BT.709-6 (06/2015) Item 3.5 +// https://www.itu.int/rec/R-REC-BT.709-6-201506-I/en + +#define RGB_TO_Y_BT709(r, g, b) \ +((FIX(0.21260*219.0/255.0) * (r) + FIX(0.71520*219.0/255.0) * (g) + \ + FIX(0.07220*219.0/255.0) * (b) + (ONE_HALF + (16 << SCALEBITS))) >> SCALEBITS) + +#define RGB_TO_U_BT709(r1, g1, b1, shift)\ +(((- FIX(0.11457*224.0/255.0) * r1 - FIX(0.38543*224.0/255.0) * g1 + \ + FIX(0.50000*224.0/255.0) * b1 + (ONE_HALF << shift) - 1) >> (SCALEBITS + shift)) + 128) + +#define RGB_TO_V_BT709(r1, g1, b1, shift)\ +(((FIX(0.50000*224.0/255.0) * r1 - FIX(0.45415*224.0/255.0) * g1 - \ + FIX(0.04585*224.0/255.0) * b1 + (ONE_HALF << shift) - 1) >> (SCALEBITS + shift)) + 128) + +#define RGB_TO_Y_BT709_FULL(r, g, b) \ +(FFMIN((FIX(0.21260) * (r) + FIX(0.71520) * (g) + \ + FIX(0.07220) * (b) + (ONE_HALF)) >> SCALEBITS, 255)) + +#define RGB_TO_U_BT709_FULL(r1, g1, b1)\ +(((- FIX(0.11457) * r1 - FIX(0.38543) * g1 + \ + FIX(0.50000) * b1 + (ONE_HALF) - 1) >> (SCALEBITS)) + 128) + +#define RGB_TO_V_BT709_FULL(r1, g1, b1)\ +(((FIX(0.50000) * r1 - FIX(0.45415) * g1 - \ + FIX(0.04585) * b1 + (ONE_HALF) - 1) >> (SCALEBITS)) + 128) + #endif /* AVUTIL_COLORSPACE_H */ diff --git a/libavutil/cuda_check.h b/libavutil/cuda_check.h new file mode 100644 index 000000000..d02ea7eec --- /dev/null +++ b/libavutil/cuda_check.h @@ -0,0 +1,64 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +#ifndef AVUTIL_CUDA_CHECK_H +#define AVUTIL_CUDA_CHECK_H + +typedef CUresult CUDAAPI cuda_check_GetErrorName(CUresult error, const char** pstr); +typedef CUresult CUDAAPI cuda_check_GetErrorString(CUresult error, const char** pstr); + +/** + * Wrap a CUDA function call and print error information if it fails. + */ +static inline int ff_cuda_check(void *avctx, + void *cuGetErrorName_fn, void *cuGetErrorString_fn, + CUresult err, const char *func) +{ + const char *err_name; + const char *err_string; + + av_log(avctx, AV_LOG_TRACE, "Calling %s\n", func); + + if (err == CUDA_SUCCESS) + return 0; + + ((cuda_check_GetErrorName *)cuGetErrorName_fn)(err, &err_name); + ((cuda_check_GetErrorString *)cuGetErrorString_fn)(err, &err_string); + + av_log(avctx, AV_LOG_ERROR, "%s failed", func); + if (err_name && err_string) + av_log(avctx, AV_LOG_ERROR, " -> %s: %s", err_name, err_string); + av_log(avctx, AV_LOG_ERROR, "\n"); + + return AVERROR_EXTERNAL; +} + +/** + * Convenience wrapper for ff_cuda_check when directly linking libcuda. + */ + +#define FF_CUDA_CHECK(avclass, x) ff_cuda_check(avclass, cuGetErrorName, cuGetErrorString, (x), #x) + +/** + * Convenience wrapper for ff_cuda_check when dynamically loading cuda symbols. + */ + +#define FF_CUDA_CHECK_DL(avclass, cudl, x) ff_cuda_check(avclass, cudl->cuGetErrorName, cudl->cuGetErrorString, (x), #x) + +#endif /* AVUTIL_CUDA_CHECK_H */ diff --git a/libavutil/dynarray.h b/libavutil/dynarray.h index 034a9fedf..3a7e14642 100644 --- a/libavutil/dynarray.h +++ b/libavutil/dynarray.h @@ -23,7 +23,7 @@ #include "mem.h" /** - * Add an element of to a dynamic array. + * Add an element to a dynamic array. * * The array is reallocated when its number of elements reaches powers of 2. * Therefore, the amortized cost of adding an element is constant. diff --git a/libavutil/encryption_info.c b/libavutil/encryption_info.c index 20a752d6b..812c70477 100644 --- a/libavutil/encryption_info.c +++ b/libavutil/encryption_info.c @@ -160,13 +160,16 @@ uint8_t *av_encryption_info_add_side_data(const AVEncryptionInfo *info, size_t * } // The format of the AVEncryptionInitInfo side data: -// u32be system_id_size -// u32be num_key_ids -// u32be key_id_size -// u32be data_size -// u8[system_id_size] system_id -// u8[key_id_size][num_key_id] key_ids -// u8[data_size] data +// u32be init_info_count +// { +// u32be system_id_size +// u32be num_key_ids +// u32be key_id_size +// u32be data_size +// u8[system_id_size] system_id +// u8[key_id_size][num_key_id] key_ids +// u8[data_size] data +// }[init_info_count] #define FF_ENCRYPTION_INIT_INFO_EXTRA 16 @@ -215,6 +218,7 @@ void av_encryption_init_info_free(AVEncryptionInitInfo *info) for (i = 0; i < info->num_key_ids; i++) { av_free(info->key_ids[i]); } + av_encryption_init_info_free(info->next); av_free(info->system_id); av_free(info->key_ids); av_free(info->data); @@ -225,71 +229,111 @@ void av_encryption_init_info_free(AVEncryptionInitInfo *info) AVEncryptionInitInfo *av_encryption_init_info_get_side_data( const uint8_t *side_data, size_t side_data_size) { - AVEncryptionInitInfo *info; - uint64_t system_id_size, num_key_ids, key_id_size, data_size, i; + // |ret| tracks the front of the list, |info| tracks the back. + AVEncryptionInitInfo *ret = NULL, *info, *temp_info; + uint64_t system_id_size, num_key_ids, key_id_size, data_size, i, j; + uint64_t init_info_count; - if (!side_data || side_data_size < FF_ENCRYPTION_INIT_INFO_EXTRA) + if (!side_data || side_data_size < 4) return NULL; - system_id_size = AV_RB32(side_data); - num_key_ids = AV_RB32(side_data + 4); - key_id_size = AV_RB32(side_data + 8); - data_size = AV_RB32(side_data + 12); + init_info_count = AV_RB32(side_data); + side_data += 4; + side_data_size -= 4; + for (i = 0; i < init_info_count; i++) { + if (side_data_size < FF_ENCRYPTION_INIT_INFO_EXTRA) { + av_encryption_init_info_free(ret); + return NULL; + } - // UINT32_MAX + UINT32_MAX + UINT32_MAX * UINT32_MAX == UINT64_MAX - if (side_data_size - FF_ENCRYPTION_INIT_INFO_EXTRA < system_id_size + data_size + num_key_ids * key_id_size) - return NULL; + system_id_size = AV_RB32(side_data); + num_key_ids = AV_RB32(side_data + 4); + key_id_size = AV_RB32(side_data + 8); + data_size = AV_RB32(side_data + 12); - info = av_encryption_init_info_alloc(system_id_size, num_key_ids, key_id_size, data_size); - if (!info) - return NULL; + // UINT32_MAX + UINT32_MAX + UINT32_MAX * UINT32_MAX == UINT64_MAX + if (side_data_size - FF_ENCRYPTION_INIT_INFO_EXTRA < system_id_size + data_size + num_key_ids * key_id_size) { + av_encryption_init_info_free(ret); + return NULL; + } + side_data += FF_ENCRYPTION_INIT_INFO_EXTRA; + side_data_size -= FF_ENCRYPTION_INIT_INFO_EXTRA; - memcpy(info->system_id, side_data + 16, system_id_size); - side_data += system_id_size + 16; - for (i = 0; i < num_key_ids; i++) { - memcpy(info->key_ids[i], side_data, key_id_size); - side_data += key_id_size; + temp_info = av_encryption_init_info_alloc(system_id_size, num_key_ids, key_id_size, data_size); + if (!temp_info) { + av_encryption_init_info_free(ret); + return NULL; + } + if (i == 0) { + info = ret = temp_info; + } else { + info->next = temp_info; + info = temp_info; + } + + memcpy(info->system_id, side_data, system_id_size); + side_data += system_id_size; + side_data_size -= system_id_size; + for (j = 0; j < num_key_ids; j++) { + memcpy(info->key_ids[j], side_data, key_id_size); + side_data += key_id_size; + side_data_size -= key_id_size; + } + memcpy(info->data, side_data, data_size); + side_data += data_size; + side_data_size -= data_size; } - memcpy(info->data, side_data, data_size); - return info; + return ret; } uint8_t *av_encryption_init_info_add_side_data(const AVEncryptionInitInfo *info, size_t *side_data_size) { + const AVEncryptionInitInfo *cur_info; uint8_t *buffer, *cur_buffer; - uint32_t i, max_size; + uint32_t i, init_info_count; + uint64_t temp_side_data_size; - if (UINT32_MAX - FF_ENCRYPTION_INIT_INFO_EXTRA < info->system_id_size || - UINT32_MAX - FF_ENCRYPTION_INIT_INFO_EXTRA - info->system_id_size < info->data_size) { - return NULL; - } - - if (info->num_key_ids) { - max_size = UINT32_MAX - FF_ENCRYPTION_INIT_INFO_EXTRA - info->system_id_size - info->data_size; - if (max_size / info->num_key_ids < info->key_id_size) + temp_side_data_size = 4; + init_info_count = 0; + for (cur_info = info; cur_info; cur_info = cur_info->next) { + temp_side_data_size += (uint64_t)FF_ENCRYPTION_INIT_INFO_EXTRA + cur_info->system_id_size + cur_info->data_size; + if (init_info_count == UINT32_MAX || temp_side_data_size > UINT32_MAX) { return NULL; + } + init_info_count++; + + if (cur_info->num_key_ids) { + temp_side_data_size += (uint64_t)cur_info->num_key_ids * cur_info->key_id_size; + if (temp_side_data_size > UINT32_MAX) { + return NULL; + } + } } + *side_data_size = temp_side_data_size; - *side_data_size = FF_ENCRYPTION_INIT_INFO_EXTRA + info->system_id_size + - info->data_size + (info->num_key_ids * info->key_id_size); cur_buffer = buffer = av_malloc(*side_data_size); if (!buffer) return NULL; - AV_WB32(cur_buffer, info->system_id_size); - AV_WB32(cur_buffer + 4, info->num_key_ids); - AV_WB32(cur_buffer + 8, info->key_id_size); - AV_WB32(cur_buffer + 12, info->data_size); - cur_buffer += 16; + AV_WB32(cur_buffer, init_info_count); + cur_buffer += 4; + for (cur_info = info; cur_info; cur_info = cur_info->next) { + AV_WB32(cur_buffer, cur_info->system_id_size); + AV_WB32(cur_buffer + 4, cur_info->num_key_ids); + AV_WB32(cur_buffer + 8, cur_info->key_id_size); + AV_WB32(cur_buffer + 12, cur_info->data_size); + cur_buffer += 16; - memcpy(cur_buffer, info->system_id, info->system_id_size); - cur_buffer += info->system_id_size; - for (i = 0; i < info->num_key_ids; i++) { - memcpy(cur_buffer, info->key_ids[i], info->key_id_size); - cur_buffer += info->key_id_size; + memcpy(cur_buffer, cur_info->system_id, cur_info->system_id_size); + cur_buffer += cur_info->system_id_size; + for (i = 0; i < cur_info->num_key_ids; i++) { + memcpy(cur_buffer, cur_info->key_ids[i], cur_info->key_id_size); + cur_buffer += cur_info->key_id_size; + } + memcpy(cur_buffer, cur_info->data, cur_info->data_size); + cur_buffer += cur_info->data_size; } - memcpy(cur_buffer, info->data, info->data_size); return buffer; } diff --git a/libavutil/encryption_info.h b/libavutil/encryption_info.h index 47dc3a35c..8fe7ebfe4 100644 --- a/libavutil/encryption_info.h +++ b/libavutil/encryption_info.h @@ -41,7 +41,7 @@ typedef struct AVSubsampleEncryptionInfo { * The size of this struct is not part of the public ABI. */ typedef struct AVEncryptionInfo { - /** The fourcc encryption scheme. */ + /** The fourcc encryption scheme, in big-endian byte order. */ uint32_t scheme; /** @@ -115,6 +115,11 @@ typedef struct AVEncryptionInitInfo { */ uint8_t* data; uint32_t data_size; + + /** + * An optional pointer to the next initialization info in the list. + */ + struct AVEncryptionInitInfo *next; } AVEncryptionInitInfo; /** @@ -124,7 +129,7 @@ typedef struct AVEncryptionInitInfo { * * @param subsample_count The number of subsamples. * @param key_id_size The number of bytes in the key ID, should be 16. - * @param key_id_size The number of bytes in the IV, should be 16. + * @param iv_size The number of bytes in the IV, should be 16. * * @return The new AVEncryptionInfo structure, or NULL on error. */ diff --git a/libavutil/file.c b/libavutil/file.c index 24a86c3f3..d946085b2 100644 --- a/libavutil/file.c +++ b/libavutil/file.c @@ -85,6 +85,11 @@ int av_file_map(const char *filename, uint8_t **bufptr, size_t *size, } *size = off_size; + if (!*size) { + *bufptr = NULL; + goto out; + } + #if HAVE_MMAP ptr = mmap(NULL, *size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0); if (ptr == MAP_FAILED) { @@ -126,12 +131,15 @@ int av_file_map(const char *filename, uint8_t **bufptr, size_t *size, read(fd, *bufptr, *size); #endif +out: close(fd); return 0; } void av_file_unmap(uint8_t *bufptr, size_t size) { + if (!size) + return; #if HAVE_MMAP munmap(bufptr, size); #elif HAVE_MAPVIEWOFFILE diff --git a/libavutil/file.h b/libavutil/file.h index 8666c7b1d..3ef4a6022 100644 --- a/libavutil/file.h +++ b/libavutil/file.h @@ -33,6 +33,8 @@ * allocated buffer or map it with mmap() when available. * In case of success set *bufptr to the read or mmapped buffer, and * *size to the size in bytes of the buffer in *bufptr. + * Unlike mmap this function succeeds with zero sized files, in this + * case *bufptr will be set to NULL and *size will be set to 0. * The returned buffer must be released with av_file_unmap(). * * @param log_offset loglevel offset used for logging diff --git a/libavutil/file_open.c b/libavutil/file_open.c index a8da28358..cc302f2f7 100644 --- a/libavutil/file_open.c +++ b/libavutil/file_open.c @@ -138,7 +138,7 @@ int avpriv_tempfile(const char *prefix, char **filename, int log_offset, void *l #else snprintf(*filename, len, "/tmp/%sXXXXXX", prefix); fd = mkstemp(*filename); -#if defined(_WIN32) || defined (__ANDROID__) +#if defined(_WIN32) || defined (__ANDROID__) || defined(__DJGPP__) if (fd < 0) { snprintf(*filename, len, "./%sXXXXXX", prefix); fd = mkstemp(*filename); diff --git a/libavutil/float_dsp.c b/libavutil/float_dsp.c index 1d4911d81..6e28d71b5 100644 --- a/libavutil/float_dsp.c +++ b/libavutil/float_dsp.c @@ -32,6 +32,14 @@ static void vector_fmul_c(float *dst, const float *src0, const float *src1, dst[i] = src0[i] * src1[i]; } +static void vector_dmul_c(double *dst, const double *src0, const double *src1, + int len) +{ + int i; + for (i = 0; i < len; i++) + dst[i] = src0[i] * src1[i]; +} + static void vector_fmac_scalar_c(float *dst, const float *src, float mul, int len) { @@ -131,6 +139,7 @@ av_cold AVFloatDSPContext *avpriv_float_dsp_alloc(int bit_exact) return NULL; fdsp->vector_fmul = vector_fmul_c; + fdsp->vector_dmul = vector_dmul_c; fdsp->vector_fmac_scalar = vector_fmac_scalar_c; fdsp->vector_fmul_scalar = vector_fmul_scalar_c; fdsp->vector_dmac_scalar = vector_dmac_scalar_c; diff --git a/libavutil/float_dsp.h b/libavutil/float_dsp.h index 2c24d9347..9c664592b 100644 --- a/libavutil/float_dsp.h +++ b/libavutil/float_dsp.h @@ -173,6 +173,22 @@ typedef struct AVFloatDSPContext { * @return sum of elementwise products */ float (*scalarproduct_float)(const float *v1, const float *v2, int len); + + /** + * Calculate the entry wise product of two vectors of doubles and store the result in + * a vector of doubles. + * + * @param dst output vector + * constraints: 32-byte aligned + * @param src0 first input vector + * constraints: 32-byte aligned + * @param src1 second input vector + * constraints: 32-byte aligned + * @param len number of elements in the input + * constraints: multiple of 16 + */ + void (*vector_dmul)(double *dst, const double *src0, const double *src1, + int len); } AVFloatDSPContext; /** diff --git a/libavutil/frame.c b/libavutil/frame.c index 00215ac29..dcf1fc3d1 100644 --- a/libavutil/frame.c +++ b/libavutil/frame.c @@ -211,7 +211,8 @@ void av_frame_free(AVFrame **frame) static int get_video_buffer(AVFrame *frame, int align) { const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(frame->format); - int ret, i; + int ret, i, padded_height; + int plane_padding = FFMAX(16 + 16/*STRIDE_ALIGN*/, align); if (!desc) return AVERROR(EINVAL); @@ -236,23 +237,24 @@ static int get_video_buffer(AVFrame *frame, int align) frame->linesize[i] = FFALIGN(frame->linesize[i], align); } - for (i = 0; i < 4 && frame->linesize[i]; i++) { - int h = FFALIGN(frame->height, 32); - if (i == 1 || i == 2) - h = AV_CEIL_RSHIFT(h, desc->log2_chroma_h); + padded_height = FFALIGN(frame->height, 32); + if ((ret = av_image_fill_pointers(frame->data, frame->format, padded_height, + NULL, frame->linesize)) < 0) + return ret; - frame->buf[i] = av_buffer_alloc(frame->linesize[i] * h + 16 + 16/*STRIDE_ALIGN*/ - 1); - if (!frame->buf[i]) - goto fail; - - frame->data[i] = frame->buf[i]->data; + frame->buf[0] = av_buffer_alloc(ret + 4*plane_padding); + if (!frame->buf[0]) { + ret = AVERROR(ENOMEM); + goto fail; } - if (desc->flags & AV_PIX_FMT_FLAG_PAL || desc->flags & FF_PSEUDOPAL) { - av_buffer_unref(&frame->buf[1]); - frame->buf[1] = av_buffer_alloc(AVPALETTE_SIZE); - if (!frame->buf[1]) - goto fail; - frame->data[1] = frame->buf[1]->data; + + if ((ret = av_image_fill_pointers(frame->data, frame->format, padded_height, + frame->buf[0]->data, frame->linesize)) < 0) + goto fail; + + for (i = 1; i < 4; i++) { + if (frame->data[i]) + frame->data[i] += i * plane_padding; } frame->extended_data = frame->data; @@ -260,7 +262,7 @@ static int get_video_buffer(AVFrame *frame, int align) return 0; fail: av_frame_unref(frame); - return AVERROR(ENOMEM); + return ret; } static int get_audio_buffer(AVFrame *frame, int align) @@ -819,7 +821,7 @@ const char *av_frame_side_data_name(enum AVFrameSideDataType type) switch(type) { case AV_FRAME_DATA_PANSCAN: return "AVPanScan"; case AV_FRAME_DATA_A53_CC: return "ATSC A53 Part 4 Closed Captions"; - case AV_FRAME_DATA_STEREO3D: return "Stereoscopic 3d metadata"; + case AV_FRAME_DATA_STEREO3D: return "Stereo 3D"; case AV_FRAME_DATA_MATRIXENCODING: return "AVMatrixEncoding"; case AV_FRAME_DATA_DOWNMIX_INFO: return "Metadata relevant to a downmix procedure"; case AV_FRAME_DATA_REPLAYGAIN: return "AVReplayGain"; @@ -831,9 +833,15 @@ const char *av_frame_side_data_name(enum AVFrameSideDataType type) case AV_FRAME_DATA_MASTERING_DISPLAY_METADATA: return "Mastering display metadata"; case AV_FRAME_DATA_CONTENT_LIGHT_LEVEL: return "Content light level metadata"; case AV_FRAME_DATA_GOP_TIMECODE: return "GOP timecode"; + case AV_FRAME_DATA_S12M_TIMECODE: return "SMPTE 12-1 timecode"; + case AV_FRAME_DATA_SPHERICAL: return "Spherical Mapping"; case AV_FRAME_DATA_ICC_PROFILE: return "ICC profile"; +#if FF_API_FRAME_QP case AV_FRAME_DATA_QP_TABLE_PROPERTIES: return "QP table properties"; case AV_FRAME_DATA_QP_TABLE_DATA: return "QP table data"; +#endif + case AV_FRAME_DATA_DYNAMIC_HDR_PLUS: return "HDR Dynamic Metadata SMPTE2094-40 (HDR10+)"; + case AV_FRAME_DATA_REGIONS_OF_INTEREST: return "Regions Of Interest"; } return NULL; } diff --git a/libavutil/frame.h b/libavutil/frame.h index 9d57d6ce6..5d3231e7b 100644 --- a/libavutil/frame.h +++ b/libavutil/frame.h @@ -158,6 +158,27 @@ enum AVFrameSideDataType { */ AV_FRAME_DATA_QP_TABLE_DATA, #endif + + /** + * Timecode which conforms to SMPTE ST 12-1. The data is an array of 4 uint32_t + * where the first uint32_t describes how many (1-3) of the other timecodes are used. + * The timecode format is described in the av_timecode_get_smpte_from_framenum() + * function in libavutil/timecode.c. + */ + AV_FRAME_DATA_S12M_TIMECODE, + + /** + * HDR dynamic metadata associated with a video frame. The payload is + * an AVDynamicHDRPlus type and contains information for color + * volume transform - application 4 of SMPTE 2094-40:2016 standard. + */ + AV_FRAME_DATA_DYNAMIC_HDR_PLUS, + + /** + * Regions Of Interest, the data is an array of AVRegionOfInterest type, the number of + * array element is implied by AVFrameSideData.size / AVRegionOfInterest.self_size. + */ + AV_FRAME_DATA_REGIONS_OF_INTEREST, }; enum AVActiveFormatDescription { @@ -185,6 +206,62 @@ typedef struct AVFrameSideData { AVBufferRef *buf; } AVFrameSideData; +/** + * Structure describing a single Region Of Interest. + * + * When multiple regions are defined in a single side-data block, they + * should be ordered from most to least important - some encoders are only + * capable of supporting a limited number of distinct regions, so will have + * to truncate the list. + * + * When overlapping regions are defined, the first region containing a given + * area of the frame applies. + */ +typedef struct AVRegionOfInterest { + /** + * Must be set to the size of this data structure (that is, + * sizeof(AVRegionOfInterest)). + */ + uint32_t self_size; + /** + * Distance in pixels from the top edge of the frame to the top and + * bottom edges and from the left edge of the frame to the left and + * right edges of the rectangle defining this region of interest. + * + * The constraints on a region are encoder dependent, so the region + * actually affected may be slightly larger for alignment or other + * reasons. + */ + int top; + int bottom; + int left; + int right; + /** + * Quantisation offset. + * + * Must be in the range -1 to +1. A value of zero indicates no quality + * change. A negative value asks for better quality (less quantisation), + * while a positive value asks for worse quality (greater quantisation). + * + * The range is calibrated so that the extreme values indicate the + * largest possible offset - if the rest of the frame is encoded with the + * worst possible quality, an offset of -1 indicates that this region + * should be encoded with the best possible quality anyway. Intermediate + * values are then interpolated in some codec-dependent way. + * + * For example, in 10-bit H.264 the quantisation parameter varies between + * -12 and 51. A typical qoffset value of -1/10 therefore indicates that + * this region should be encoded with a QP around one-tenth of the full + * range better than the rest of the frame. So, if most of the frame + * were to be encoded with a QP of around 30, this region would get a QP + * of around 24 (an offset of approximately -1/10 * (51 - -12) = -6.3). + * An extreme value of -1 would indicate that this region should be + * encoded with the best possible quality regardless of the treatment of + * the rest of the frame - that is, should be encoded at a QP of -12. + */ + AVRational qoffset; +} AVRegionOfInterest; + /** * This structure describes decoded (raw) audio or video data. * @@ -381,7 +458,6 @@ typedef struct AVFrame { * that time, * the decoder reorders values as needed and sets AVFrame.reordered_opaque * to exactly one of the values provided by the user through AVCodecContext.reordered_opaque - * @deprecated in favor of pkt_pts */ int64_t reordered_opaque; @@ -514,6 +590,8 @@ typedef struct AVFrame { int decode_error_flags; #define FF_DECODE_ERROR_INVALID_BITSTREAM 1 #define FF_DECODE_ERROR_MISSING_REFERENCE 2 +#define FF_DECODE_ERROR_CONCEALMENT_ACTIVE 4 +#define FF_DECODE_ERROR_DECODE_SLICES 8 /** * number of audio channels, only used for audio. diff --git a/libavutil/hdr_dynamic_metadata.c b/libavutil/hdr_dynamic_metadata.c new file mode 100644 index 000000000..0fa1ee82d --- /dev/null +++ b/libavutil/hdr_dynamic_metadata.c @@ -0,0 +1,47 @@ +/** + * Copyright (c) 2018 Mohammad Izadi + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "hdr_dynamic_metadata.h" +#include "mem.h" + +AVDynamicHDRPlus *av_dynamic_hdr_plus_alloc(size_t *size) +{ + AVDynamicHDRPlus *hdr_plus = av_mallocz(sizeof(AVDynamicHDRPlus)); + if (!hdr_plus) + return NULL; + + if (size) + *size = sizeof(*hdr_plus); + + return hdr_plus; +} + +AVDynamicHDRPlus *av_dynamic_hdr_plus_create_side_data(AVFrame *frame) +{ + AVFrameSideData *side_data = av_frame_new_side_data(frame, + AV_FRAME_DATA_DYNAMIC_HDR_PLUS, + sizeof(AVDynamicHDRPlus)); + if (!side_data) + return NULL; + + memset(side_data->data, 0, sizeof(AVDynamicHDRPlus)); + + return (AVDynamicHDRPlus *)side_data->data; +} diff --git a/libavutil/hdr_dynamic_metadata.h b/libavutil/hdr_dynamic_metadata.h new file mode 100644 index 000000000..2d72de56a --- /dev/null +++ b/libavutil/hdr_dynamic_metadata.h @@ -0,0 +1,343 @@ +/* + * Copyright (c) 2018 Mohammad Izadi + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_HDR_DYNAMIC_METADATA_H +#define AVUTIL_HDR_DYNAMIC_METADATA_H + +#include "frame.h" +#include "rational.h" + +/** + * Option for overlapping elliptical pixel selectors in an image. + */ +enum AVHDRPlusOverlapProcessOption { + AV_HDR_PLUS_OVERLAP_PROCESS_WEIGHTED_AVERAGING = 0, + AV_HDR_PLUS_OVERLAP_PROCESS_LAYERING = 1, +}; + +/** + * Represents the percentile at a specific percentage in + * a distribution. + */ +typedef struct AVHDRPlusPercentile { + /** + * The percentage value corresponding to a specific percentile linearized + * RGB value in the processing window in the scene. The value shall be in + * the range of 0 to100, inclusive. + */ + uint8_t percentage; + + /** + * The linearized maxRGB value at a specific percentile in the processing + * window in the scene. The value shall be in the range of 0 to 1, inclusive + * and in multiples of 0.00001. + */ + AVRational percentile; +} AVHDRPlusPercentile; + +/** + * Color transform parameters at a processing window in a dynamic metadata for + * SMPTE 2094-40. + */ +typedef struct AVHDRPlusColorTransformParams { + /** + * The relative x coordinate of the top left pixel of the processing + * window. The value shall be in the range of 0 and 1, inclusive and + * in multiples of 1/(width of Picture - 1). The value 1 corresponds + * to the absolute coordinate of width of Picture - 1. The value for + * first processing window shall be 0. + */ + AVRational window_upper_left_corner_x; + + /** + * The relative y coordinate of the top left pixel of the processing + * window. The value shall be in the range of 0 and 1, inclusive and + * in multiples of 1/(height of Picture - 1). The value 1 corresponds + * to the absolute coordinate of height of Picture - 1. The value for + * first processing window shall be 0. + */ + AVRational window_upper_left_corner_y; + + /** + * The relative x coordinate of the bottom right pixel of the processing + * window. The value shall be in the range of 0 and 1, inclusive and + * in multiples of 1/(width of Picture - 1). The value 1 corresponds + * to the absolute coordinate of width of Picture - 1. The value for + * first processing window shall be 1. + */ + AVRational window_lower_right_corner_x; + + /** + * The relative y coordinate of the bottom right pixel of the processing + * window. The value shall be in the range of 0 and 1, inclusive and + * in multiples of 1/(height of Picture - 1). The value 1 corresponds + * to the absolute coordinate of height of Picture - 1. The value for + * first processing window shall be 1. + */ + AVRational window_lower_right_corner_y; + + /** + * The x coordinate of the center position of the concentric internal and + * external ellipses of the elliptical pixel selector in the processing + * window. The value shall be in the range of 0 to (width of Picture - 1), + * inclusive and in multiples of 1 pixel. + */ + uint16_t center_of_ellipse_x; + + /** + * The y coordinate of the center position of the concentric internal and + * external ellipses of the elliptical pixel selector in the processing + * window. The value shall be in the range of 0 to (height of Picture - 1), + * inclusive and in multiples of 1 pixel. + */ + uint16_t center_of_ellipse_y; + + /** + * The clockwise rotation angle in degree of arc with respect to the + * positive direction of the x-axis of the concentric internal and external + * ellipses of the elliptical pixel selector in the processing window. The + * value shall be in the range of 0 to 180, inclusive and in multiples of 1. + */ + uint8_t rotation_angle; + + /** + * The semi-major axis value of the internal ellipse of the elliptical pixel + * selector in amount of pixels in the processing window. The value shall be + * in the range of 1 to 65535, inclusive and in multiples of 1 pixel. + */ + uint16_t semimajor_axis_internal_ellipse; + + /** + * The semi-major axis value of the external ellipse of the elliptical pixel + * selector in amount of pixels in the processing window. The value + * shall not be less than semimajor_axis_internal_ellipse of the current + * processing window. The value shall be in the range of 1 to 65535, + * inclusive and in multiples of 1 pixel. + */ + uint16_t semimajor_axis_external_ellipse; + + /** + * The semi-minor axis value of the external ellipse of the elliptical pixel + * selector in amount of pixels in the processing window. The value shall be + * in the range of 1 to 65535, inclusive and in multiples of 1 pixel. + */ + uint16_t semiminor_axis_external_ellipse; + + /** + * Overlap process option indicates one of the two methods of combining + * rendered pixels in the processing window in an image with at least one + * elliptical pixel selector. For overlapping elliptical pixel selectors + * in an image, overlap_process_option shall have the same value. + */ + enum AVHDRPlusOverlapProcessOption overlap_process_option; + + /** + * The maximum of the color components of linearized RGB values in the + * processing window in the scene. The values should be in the range of 0 to + * 1, inclusive and in multiples of 0.00001. maxscl[ 0 ], maxscl[ 1 ], and + * maxscl[ 2 ] are corresponding to R, G, B color components respectively. + */ + AVRational maxscl[3]; + + /** + * The average of linearized maxRGB values in the processing window in the + * scene. The value should be in the range of 0 to 1, inclusive and in + * multiples of 0.00001. + */ + AVRational average_maxrgb; + + /** + * The number of linearized maxRGB values at given percentiles in the + * processing window in the scene. The maximum value shall be 15. + */ + uint8_t num_distribution_maxrgb_percentiles; + + /** + * The linearized maxRGB values at given percentiles in the + * processing window in the scene. + */ + AVHDRPlusPercentile distribution_maxrgb[15]; + + /** + * The fraction of selected pixels in the image that contains the brightest + * pixel in the scene. The value shall be in the range of 0 to 1, inclusive + * and in multiples of 0.001. + */ + AVRational fraction_bright_pixels; + + /** + * This flag indicates that the metadata for the tone mapping function in + * the processing window is present (for value of 1). + */ + uint8_t tone_mapping_flag; + + /** + * The x coordinate of the separation point between the linear part and the + * curved part of the tone mapping function. The value shall be in the range + * of 0 to 1, excluding 0 and in multiples of 1/4095. + */ + AVRational knee_point_x; + + /** + * The y coordinate of the separation point between the linear part and the + * curved part of the tone mapping function. The value shall be in the range + * of 0 to 1, excluding 0 and in multiples of 1/4095. + */ + AVRational knee_point_y; + + /** + * The number of the intermediate anchor parameters of the tone mapping + * function in the processing window. The maximum value shall be 15. + */ + uint8_t num_bezier_curve_anchors; + + /** + * The intermediate anchor parameters of the tone mapping function in the + * processing window in the scene. The values should be in the range of 0 + * to 1, inclusive and in multiples of 1/1023. + */ + AVRational bezier_curve_anchors[15]; + + /** + * This flag shall be equal to 0 in bitstreams conforming to this version of + * this Specification. Other values are reserved for future use. + */ + uint8_t color_saturation_mapping_flag; + + /** + * The color saturation gain in the processing window in the scene. The + * value shall be in the range of 0 to 63/8, inclusive and in multiples of + * 1/8. The default value shall be 1. + */ + AVRational color_saturation_weight; +} AVHDRPlusColorTransformParams; + +/** + * This struct represents dynamic metadata for color volume transform - + * application 4 of SMPTE 2094-40:2016 standard. + * + * To be used as payload of a AVFrameSideData or AVPacketSideData with the + * appropriate type. + * + * @note The struct should be allocated with + * av_dynamic_hdr_plus_alloc() and its size is not a part of + * the public ABI. + */ +typedef struct AVDynamicHDRPlus { + /** + * Country code by Rec. ITU-T T.35 Annex A. The value shall be 0xB5. + */ + uint8_t itu_t_t35_country_code; + + /** + * Application version in the application defining document in ST-2094 + * suite. The value shall be set to 0. + */ + uint8_t application_version; + + /** + * The number of processing windows. The value shall be in the range + * of 1 to 3, inclusive. + */ + uint8_t num_windows; + + /** + * The color transform parameters for every processing window. + */ + AVHDRPlusColorTransformParams params[3]; + + /** + * The nominal maximum display luminance of the targeted system display, + * in units of 0.0001 candelas per square metre. The value shall be in + * the range of 0 to 10000, inclusive. + */ + AVRational targeted_system_display_maximum_luminance; + + /** + * This flag shall be equal to 0 in bit streams conforming to this version + * of this Specification. The value 1 is reserved for future use. + */ + uint8_t targeted_system_display_actual_peak_luminance_flag; + + /** + * The number of rows in the targeted system_display_actual_peak_luminance + * array. The value shall be in the range of 2 to 25, inclusive. + */ + uint8_t num_rows_targeted_system_display_actual_peak_luminance; + + /** + * The number of columns in the + * targeted_system_display_actual_peak_luminance array. The value shall be + * in the range of 2 to 25, inclusive. + */ + uint8_t num_cols_targeted_system_display_actual_peak_luminance; + + /** + * The normalized actual peak luminance of the targeted system display. The + * values should be in the range of 0 to 1, inclusive and in multiples of + * 1/15. + */ + AVRational targeted_system_display_actual_peak_luminance[25][25]; + + /** + * This flag shall be equal to 0 in bitstreams conforming to this version of + * this Specification. The value 1 is reserved for future use. + */ + uint8_t mastering_display_actual_peak_luminance_flag; + + /** + * The number of rows in the mastering_display_actual_peak_luminance array. + * The value shall be in the range of 2 to 25, inclusive. + */ + uint8_t num_rows_mastering_display_actual_peak_luminance; + + /** + * The number of columns in the mastering_display_actual_peak_luminance + * array. The value shall be in the range of 2 to 25, inclusive. + */ + uint8_t num_cols_mastering_display_actual_peak_luminance; + + /** + * The normalized actual peak luminance of the mastering display used for + * mastering the image essence. The values should be in the range of 0 to 1, + * inclusive and in multiples of 1/15. + */ + AVRational mastering_display_actual_peak_luminance[25][25]; +} AVDynamicHDRPlus; + +/** + * Allocate an AVDynamicHDRPlus structure and set its fields to + * default values. The resulting struct can be freed using av_freep(). + * + * @return An AVDynamicHDRPlus filled with default values or NULL + * on failure. + */ +AVDynamicHDRPlus *av_dynamic_hdr_plus_alloc(size_t *size); + +/** + * Allocate a complete AVDynamicHDRPlus and add it to the frame. + * @param frame The frame which side data is added to. + * + * @return The AVDynamicHDRPlus structure to be filled by caller or NULL + * on failure. + */ +AVDynamicHDRPlus *av_dynamic_hdr_plus_create_side_data(AVFrame *frame); + +#endif /* AVUTIL_HDR_DYNAMIC_METADATA_H */ diff --git a/libavutil/hwcontext.c b/libavutil/hwcontext.c index 70c556eca..f1e404ab2 100644 --- a/libavutil/hwcontext.c +++ b/libavutil/hwcontext.c @@ -646,6 +646,9 @@ int av_hwdevice_ctx_create_derived(AVBufferRef **dst_ref_ptr, ret = AVERROR(ENOMEM); goto fail; } + ret = av_hwdevice_ctx_init(dst_ref); + if (ret < 0) + goto fail; goto done; } if (ret != AVERROR(ENOSYS)) @@ -658,10 +661,6 @@ int av_hwdevice_ctx_create_derived(AVBufferRef **dst_ref_ptr, goto fail; done: - ret = av_hwdevice_ctx_init(dst_ref); - if (ret < 0) - goto fail; - *dst_ref_ptr = dst_ref; return 0; @@ -871,3 +870,10 @@ fail: av_buffer_unref(&dst_ref); return ret; } + +int ff_hwframe_map_replace(AVFrame *dst, const AVFrame *src) +{ + HWMapDescriptor *hwmap = (HWMapDescriptor*)dst->buf[0]->data; + av_frame_unref(hwmap->source); + return av_frame_ref(hwmap->source, src); +} diff --git a/libavutil/hwcontext_cuda.c b/libavutil/hwcontext_cuda.c index 37827a770..cca39e9fc 100644 --- a/libavutil/hwcontext_cuda.c +++ b/libavutil/hwcontext_cuda.c @@ -21,9 +21,11 @@ #include "hwcontext.h" #include "hwcontext_internal.h" #include "hwcontext_cuda_internal.h" +#include "cuda_check.h" #include "mem.h" #include "pixdesc.h" #include "pixfmt.h" +#include "imgutils.h" #define CUDA_FRAME_ALIGNMENT 256 @@ -38,8 +40,12 @@ static const enum AVPixelFormat supported_formats[] = { AV_PIX_FMT_P010, AV_PIX_FMT_P016, AV_PIX_FMT_YUV444P16, + AV_PIX_FMT_0RGB32, + AV_PIX_FMT_0BGR32, }; +#define CHECK_CU(x) FF_CUDA_CHECK_DL(device_ctx, cu, x) + static int cuda_frames_get_constraints(AVHWDeviceContext *ctx, const void *hwconfig, AVHWFramesConstraints *constraints) @@ -67,55 +73,54 @@ static int cuda_frames_get_constraints(AVHWDeviceContext *ctx, static void cuda_buffer_free(void *opaque, uint8_t *data) { - AVHWFramesContext *ctx = opaque; - AVCUDADeviceContext *hwctx = ctx->device_ctx->hwctx; - CudaFunctions *cu = hwctx->internal->cuda_dl; + AVHWFramesContext *ctx = opaque; + AVHWDeviceContext *device_ctx = ctx->device_ctx; + AVCUDADeviceContext *hwctx = device_ctx->hwctx; + CudaFunctions *cu = hwctx->internal->cuda_dl; CUcontext dummy; - cu->cuCtxPushCurrent(hwctx->cuda_ctx); + CHECK_CU(cu->cuCtxPushCurrent(hwctx->cuda_ctx)); - cu->cuMemFree((CUdeviceptr)data); + CHECK_CU(cu->cuMemFree((CUdeviceptr)data)); - cu->cuCtxPopCurrent(&dummy); + CHECK_CU(cu->cuCtxPopCurrent(&dummy)); } static AVBufferRef *cuda_pool_alloc(void *opaque, int size) { - AVHWFramesContext *ctx = opaque; - AVCUDADeviceContext *hwctx = ctx->device_ctx->hwctx; - CudaFunctions *cu = hwctx->internal->cuda_dl; + AVHWFramesContext *ctx = opaque; + AVHWDeviceContext *device_ctx = ctx->device_ctx; + AVCUDADeviceContext *hwctx = device_ctx->hwctx; + CudaFunctions *cu = hwctx->internal->cuda_dl; AVBufferRef *ret = NULL; CUcontext dummy = NULL; CUdeviceptr data; - CUresult err; + int err; - err = cu->cuCtxPushCurrent(hwctx->cuda_ctx); - if (err != CUDA_SUCCESS) { - av_log(ctx, AV_LOG_ERROR, "Error setting current CUDA context\n"); + err = CHECK_CU(cu->cuCtxPushCurrent(hwctx->cuda_ctx)); + if (err < 0) return NULL; - } - err = cu->cuMemAlloc(&data, size); - if (err != CUDA_SUCCESS) + err = CHECK_CU(cu->cuMemAlloc(&data, size)); + if (err < 0) goto fail; ret = av_buffer_create((uint8_t*)data, size, cuda_buffer_free, ctx, 0); if (!ret) { - cu->cuMemFree(data); + CHECK_CU(cu->cuMemFree(data)); goto fail; } fail: - cu->cuCtxPopCurrent(&dummy); + CHECK_CU(cu->cuCtxPopCurrent(&dummy)); return ret; } static int cuda_frames_init(AVHWFramesContext *ctx) { CUDAFramesContext *priv = ctx->internal->priv; - int aligned_width = FFALIGN(ctx->width, CUDA_FRAME_ALIGNMENT); int i; for (i = 0; i < FF_ARRAY_ELEMS(supported_formats); i++) { @@ -131,25 +136,9 @@ static int cuda_frames_init(AVHWFramesContext *ctx) av_pix_fmt_get_chroma_sub_sample(ctx->sw_format, &priv->shift_width, &priv->shift_height); if (!ctx->pool) { - int size; - - switch (ctx->sw_format) { - case AV_PIX_FMT_NV12: - case AV_PIX_FMT_YUV420P: - size = aligned_width * ctx->height * 3 / 2; - break; - case AV_PIX_FMT_YUV444P: - case AV_PIX_FMT_P010: - case AV_PIX_FMT_P016: - size = aligned_width * ctx->height * 3; - break; - case AV_PIX_FMT_YUV444P16: - size = aligned_width * ctx->height * 6; - break; - default: - av_log(ctx, AV_LOG_ERROR, "BUG: Pixel format missing from size calculation."); - return AVERROR_BUG; - } + int size = av_image_get_buffer_size(ctx->sw_format, ctx->width, ctx->height, CUDA_FRAME_ALIGNMENT); + if (size < 0) + return size; ctx->internal->pool_internal = av_buffer_pool_init2(size, ctx, cuda_pool_alloc, NULL); if (!ctx->internal->pool_internal) @@ -161,49 +150,23 @@ static int cuda_frames_init(AVHWFramesContext *ctx) static int cuda_get_buffer(AVHWFramesContext *ctx, AVFrame *frame) { - int aligned_width; - int width_in_bytes = ctx->width; - - if (ctx->sw_format == AV_PIX_FMT_P010 || - ctx->sw_format == AV_PIX_FMT_P016 || - ctx->sw_format == AV_PIX_FMT_YUV444P16) { - width_in_bytes *= 2; - } - aligned_width = FFALIGN(width_in_bytes, CUDA_FRAME_ALIGNMENT); + int res; frame->buf[0] = av_buffer_pool_get(ctx->pool); if (!frame->buf[0]) return AVERROR(ENOMEM); - switch (ctx->sw_format) { - case AV_PIX_FMT_NV12: - case AV_PIX_FMT_P010: - case AV_PIX_FMT_P016: - frame->data[0] = frame->buf[0]->data; - frame->data[1] = frame->data[0] + aligned_width * ctx->height; - frame->linesize[0] = aligned_width; - frame->linesize[1] = aligned_width; - break; - case AV_PIX_FMT_YUV420P: - frame->data[0] = frame->buf[0]->data; - frame->data[2] = frame->data[0] + aligned_width * ctx->height; - frame->data[1] = frame->data[2] + aligned_width * ctx->height / 4; - frame->linesize[0] = aligned_width; - frame->linesize[1] = aligned_width / 2; - frame->linesize[2] = aligned_width / 2; - break; - case AV_PIX_FMT_YUV444P: - case AV_PIX_FMT_YUV444P16: - frame->data[0] = frame->buf[0]->data; - frame->data[1] = frame->data[0] + aligned_width * ctx->height; - frame->data[2] = frame->data[1] + aligned_width * ctx->height; - frame->linesize[0] = aligned_width; - frame->linesize[1] = aligned_width; - frame->linesize[2] = aligned_width; - break; - default: - av_frame_unref(frame); - return AVERROR_BUG; + res = av_image_fill_arrays(frame->data, frame->linesize, frame->buf[0]->data, + ctx->sw_format, ctx->width, ctx->height, CUDA_FRAME_ALIGNMENT); + if (res < 0) + return res; + + // YUV420P is a special case. + // Nvenc expects the U/V planes in swapped order from how ffmpeg expects them, also chroma is half-aligned + if (ctx->sw_format == AV_PIX_FMT_YUV420P) { + frame->linesize[1] = frame->linesize[2] = frame->linesize[0] / 2; + frame->data[2] = frame->data[1]; + frame->data[1] = frame->data[2] + frame->linesize[2] * ctx->height / 2; } frame->format = AV_PIX_FMT_CUDA; @@ -234,17 +197,17 @@ static int cuda_transfer_get_formats(AVHWFramesContext *ctx, static int cuda_transfer_data_from(AVHWFramesContext *ctx, AVFrame *dst, const AVFrame *src) { - CUDAFramesContext *priv = ctx->internal->priv; - AVCUDADeviceContext *device_hwctx = ctx->device_ctx->hwctx; - CudaFunctions *cu = device_hwctx->internal->cuda_dl; + CUDAFramesContext *priv = ctx->internal->priv; + AVHWDeviceContext *device_ctx = ctx->device_ctx; + AVCUDADeviceContext *hwctx = device_ctx->hwctx; + CudaFunctions *cu = hwctx->internal->cuda_dl; CUcontext dummy; - CUresult err; - int i; + int i, ret; - err = cu->cuCtxPushCurrent(device_hwctx->cuda_ctx); - if (err != CUDA_SUCCESS) - return AVERROR_UNKNOWN; + ret = CHECK_CU(cu->cuCtxPushCurrent(hwctx->cuda_ctx)); + if (ret < 0) + return ret; for (i = 0; i < FF_ARRAY_ELEMS(src->data) && src->data[i]; i++) { CUDA_MEMCPY2D cpy = { @@ -258,14 +221,17 @@ static int cuda_transfer_data_from(AVHWFramesContext *ctx, AVFrame *dst, .Height = src->height >> (i ? priv->shift_height : 0), }; - err = cu->cuMemcpy2D(&cpy); - if (err != CUDA_SUCCESS) { - av_log(ctx, AV_LOG_ERROR, "Error transferring the data from the CUDA frame\n"); - return AVERROR_UNKNOWN; - } + ret = CHECK_CU(cu->cuMemcpy2DAsync(&cpy, hwctx->stream)); + if (ret < 0) + goto exit; } - cu->cuCtxPopCurrent(&dummy); + ret = CHECK_CU(cu->cuStreamSynchronize(hwctx->stream)); + if (ret < 0) + goto exit; + +exit: + CHECK_CU(cu->cuCtxPopCurrent(&dummy)); return 0; } @@ -273,17 +239,17 @@ static int cuda_transfer_data_from(AVHWFramesContext *ctx, AVFrame *dst, static int cuda_transfer_data_to(AVHWFramesContext *ctx, AVFrame *dst, const AVFrame *src) { - CUDAFramesContext *priv = ctx->internal->priv; - AVCUDADeviceContext *device_hwctx = ctx->device_ctx->hwctx; - CudaFunctions *cu = device_hwctx->internal->cuda_dl; + CUDAFramesContext *priv = ctx->internal->priv; + AVHWDeviceContext *device_ctx = ctx->device_ctx; + AVCUDADeviceContext *hwctx = device_ctx->hwctx; + CudaFunctions *cu = hwctx->internal->cuda_dl; CUcontext dummy; - CUresult err; - int i; + int i, ret; - err = cu->cuCtxPushCurrent(device_hwctx->cuda_ctx); - if (err != CUDA_SUCCESS) - return AVERROR_UNKNOWN; + ret = CHECK_CU(cu->cuCtxPushCurrent(hwctx->cuda_ctx)); + if (ret < 0) + return ret; for (i = 0; i < FF_ARRAY_ELEMS(src->data) && src->data[i]; i++) { CUDA_MEMCPY2D cpy = { @@ -297,25 +263,25 @@ static int cuda_transfer_data_to(AVHWFramesContext *ctx, AVFrame *dst, .Height = src->height >> (i ? priv->shift_height : 0), }; - err = cu->cuMemcpy2D(&cpy); - if (err != CUDA_SUCCESS) { - av_log(ctx, AV_LOG_ERROR, "Error transferring the data from the CUDA frame\n"); - return AVERROR_UNKNOWN; - } + ret = CHECK_CU(cu->cuMemcpy2DAsync(&cpy, hwctx->stream)); + if (ret < 0) + goto exit; } - cu->cuCtxPopCurrent(&dummy); +exit: + CHECK_CU(cu->cuCtxPopCurrent(&dummy)); return 0; } -static void cuda_device_uninit(AVHWDeviceContext *ctx) +static void cuda_device_uninit(AVHWDeviceContext *device_ctx) { - AVCUDADeviceContext *hwctx = ctx->hwctx; + AVCUDADeviceContext *hwctx = device_ctx->hwctx; if (hwctx->internal) { + CudaFunctions *cu = hwctx->internal->cuda_dl; if (hwctx->internal->is_allocated && hwctx->cuda_ctx) { - hwctx->internal->cuda_dl->cuCtxDestroy(hwctx->cuda_ctx); + CHECK_CU(cu->cuCtxDestroy(hwctx->cuda_ctx)); hwctx->cuda_ctx = NULL; } cuda_free_functions(&hwctx->internal->cuda_dl); @@ -350,50 +316,47 @@ error: return ret; } -static int cuda_device_create(AVHWDeviceContext *ctx, const char *device, +static int cuda_device_create(AVHWDeviceContext *device_ctx, + const char *device, AVDictionary *opts, int flags) { - AVCUDADeviceContext *hwctx = ctx->hwctx; + AVCUDADeviceContext *hwctx = device_ctx->hwctx; CudaFunctions *cu; CUdevice cu_device; CUcontext dummy; - CUresult err; - int device_idx = 0; + int ret, device_idx = 0; if (device) device_idx = strtol(device, NULL, 0); - if (cuda_device_init(ctx) < 0) + if (cuda_device_init(device_ctx) < 0) goto error; cu = hwctx->internal->cuda_dl; - err = cu->cuInit(0); - if (err != CUDA_SUCCESS) { - av_log(ctx, AV_LOG_ERROR, "Could not initialize the CUDA driver API\n"); + ret = CHECK_CU(cu->cuInit(0)); + if (ret < 0) goto error; - } - err = cu->cuDeviceGet(&cu_device, device_idx); - if (err != CUDA_SUCCESS) { - av_log(ctx, AV_LOG_ERROR, "Could not get the device number %d\n", device_idx); + ret = CHECK_CU(cu->cuDeviceGet(&cu_device, device_idx)); + if (ret < 0) goto error; - } - err = cu->cuCtxCreate(&hwctx->cuda_ctx, CU_CTX_SCHED_BLOCKING_SYNC, cu_device); - if (err != CUDA_SUCCESS) { - av_log(ctx, AV_LOG_ERROR, "Error creating a CUDA context\n"); + ret = CHECK_CU(cu->cuCtxCreate(&hwctx->cuda_ctx, CU_CTX_SCHED_BLOCKING_SYNC, cu_device)); + if (ret < 0) goto error; - } - cu->cuCtxPopCurrent(&dummy); + // Setting stream to NULL will make functions automatically use the default CUstream + hwctx->stream = NULL; + + CHECK_CU(cu->cuCtxPopCurrent(&dummy)); hwctx->internal->is_allocated = 1; return 0; error: - cuda_device_uninit(ctx); + cuda_device_uninit(device_ctx); return AVERROR_UNKNOWN; } diff --git a/libavutil/hwcontext_cuda.h b/libavutil/hwcontext_cuda.h index 12dae8449..81a0552ca 100644 --- a/libavutil/hwcontext_cuda.h +++ b/libavutil/hwcontext_cuda.h @@ -41,6 +41,7 @@ typedef struct AVCUDADeviceContextInternal AVCUDADeviceContextInternal; */ typedef struct AVCUDADeviceContext { CUcontext cuda_ctx; + CUstream stream; AVCUDADeviceContextInternal *internal; } AVCUDADeviceContext; diff --git a/libavutil/hwcontext_d3d11va.c b/libavutil/hwcontext_d3d11va.c index b68d26280..6670c4757 100644 --- a/libavutil/hwcontext_d3d11va.c +++ b/libavutil/hwcontext_d3d11va.c @@ -410,7 +410,7 @@ static int d3d11va_transfer_data(AVHWFramesContext *ctx, AVFrame *dst, fill_texture_ptrs(map_data, map_linesize, ctx, &desc, &map); - av_image_copy(dst->data, dst->linesize, map_data, map_linesize, + av_image_copy(dst->data, dst->linesize, (const uint8_t **)map_data, map_linesize, ctx->sw_format, w, h); ID3D11DeviceContext_Unmap(device_hwctx->device_context, staging, 0); @@ -422,7 +422,7 @@ static int d3d11va_transfer_data(AVHWFramesContext *ctx, AVFrame *dst, fill_texture_ptrs(map_data, map_linesize, ctx, &desc, &map); - av_image_copy(map_data, map_linesize, src->data, src->linesize, + av_image_copy(map_data, map_linesize, (const uint8_t **)src->data, src->linesize, ctx->sw_format, w, h); ID3D11DeviceContext_Unmap(device_hwctx->device_context, staging, 0); @@ -550,7 +550,7 @@ static int d3d11va_device_create(AVHWDeviceContext *ctx, const char *device, } if (pAdapter) { - DXGI_ADAPTER_DESC2 desc; + DXGI_ADAPTER_DESC desc; hr = IDXGIAdapter2_GetDesc(pAdapter, &desc); if (!FAILED(hr)) { av_log(ctx, AV_LOG_INFO, "Using device %04x:%04x (%ls).\n", diff --git a/libavutil/hwcontext_dxva2.c b/libavutil/hwcontext_dxva2.c index 4585f323b..64366cea8 100644 --- a/libavutil/hwcontext_dxva2.c +++ b/libavutil/hwcontext_dxva2.c @@ -348,7 +348,7 @@ static int dxva2_transfer_data_to(AVHWFramesContext *ctx, AVFrame *dst, if (ret < 0) goto fail; - av_image_copy(map->data, map->linesize, src->data, src->linesize, + av_image_copy(map->data, map->linesize, (const uint8_t **)src->data, src->linesize, ctx->sw_format, src->width, src->height); fail: @@ -379,7 +379,7 @@ static int dxva2_transfer_data_from(AVHWFramesContext *ctx, AVFrame *dst, dst_linesize[i] = dst->linesize[i]; src_linesize[i] = map->linesize[i]; } - av_image_copy_uc_from(dst->data, dst_linesize, map->data, src_linesize, + av_image_copy_uc_from(dst->data, dst_linesize, (const uint8_t **)map->data, src_linesize, ctx->sw_format, src->width, src->height); fail: av_frame_free(&map); diff --git a/libavutil/hwcontext_internal.h b/libavutil/hwcontext_internal.h index 332062dda..77dc47ddd 100644 --- a/libavutil/hwcontext_internal.h +++ b/libavutil/hwcontext_internal.h @@ -156,6 +156,11 @@ int ff_hwframe_map_create(AVBufferRef *hwframe_ref, HWMapDescriptor *hwmap), void *priv); +/** + * Replace the current hwmap of dst with the one from src, used for indirect + * mappings like VAAPI->(DRM)->OpenCL/Vulkan where a direct interop is missing + */ +int ff_hwframe_map_replace(AVFrame *dst, const AVFrame *src); extern const HWContextType ff_hwcontext_type_cuda; extern const HWContextType ff_hwcontext_type_d3d11va; diff --git a/libavutil/hwcontext_opencl.c b/libavutil/hwcontext_opencl.c index 43b5c5ae0..41fdfe96f 100644 --- a/libavutil/hwcontext_opencl.c +++ b/libavutil/hwcontext_opencl.c @@ -46,9 +46,11 @@ #endif #if HAVE_OPENCL_VAAPI_INTEL_MEDIA +#if CONFIG_LIBMFX #include +#endif #include -#include +#include #include "hwcontext_vaapi.h" #endif @@ -141,9 +143,10 @@ typedef struct OpenCLFramesContext { } OpenCLFramesContext; -static void opencl_error_callback(const char *errinfo, - const void *private_info, size_t cb, - void *user_data) +static void CL_CALLBACK opencl_error_callback(const char *errinfo, + const void *private_info, + size_t cb, + void *user_data) { AVHWDeviceContext *ctx = user_data; av_log(ctx, AV_LOG_ERROR, "OpenCL error: %s\n", errinfo); @@ -497,6 +500,9 @@ static int opencl_device_create_internal(AVHWDeviceContext *hwdev, *device_name_src = NULL; int err, found, p, d; + av_assert0(selector->enumerate_platforms && + selector->enumerate_devices); + err = selector->enumerate_platforms(hwdev, &nb_platforms, &platforms, selector->context); if (err) @@ -528,9 +534,9 @@ static int opencl_device_create_internal(AVHWDeviceContext *hwdev, continue; } - err = opencl_enumerate_devices(hwdev, platforms[p], platform_name, - &nb_devices, &devices, - selector->context); + err = selector->enumerate_devices(hwdev, platforms[p], platform_name, + &nb_devices, &devices, + selector->context); if (err < 0) continue; @@ -925,7 +931,6 @@ static int opencl_enumerate_intel_media_vaapi_devices(AVHWDeviceContext *hwdev, clGetDeviceIDsFromVA_APIMediaAdapterINTEL_fn clGetDeviceIDsFromVA_APIMediaAdapterINTEL; cl_int cle; - int err; clGetDeviceIDsFromVA_APIMediaAdapterINTEL = clGetExtensionFunctionAddressForPlatform(platform_id, @@ -1358,10 +1363,7 @@ static int opencl_device_derive(AVHWDeviceContext *hwdev, break; } - if (err < 0) - return err; - - return opencl_device_init(hwdev); + return err; } static int opencl_get_plane_format(enum AVPixelFormat pixfmt, @@ -1417,8 +1419,9 @@ static int opencl_get_plane_format(enum AVPixelFormat pixfmt, // from the same component. if (step && comp->step != step) return AVERROR(EINVAL); - order = order * 10 + c + 1; + depth = comp->depth; + order = order * 10 + comp->offset / ((depth + 7) / 8) + 1; step = comp->step; alpha = (desc->flags & AV_PIX_FMT_FLAG_ALPHA && c == desc->nb_components - 1); @@ -1454,14 +1457,10 @@ static int opencl_get_plane_format(enum AVPixelFormat pixfmt, case order: image_format->image_channel_order = type; break; switch (order) { CHANNEL_ORDER(1, CL_R); - CHANNEL_ORDER(2, CL_R); - CHANNEL_ORDER(3, CL_R); - CHANNEL_ORDER(4, CL_R); CHANNEL_ORDER(12, CL_RG); - CHANNEL_ORDER(23, CL_RG); CHANNEL_ORDER(1234, CL_RGBA); + CHANNEL_ORDER(2341, CL_ARGB); CHANNEL_ORDER(3214, CL_BGRA); - CHANNEL_ORDER(4123, CL_ARGB); #ifdef CL_ABGR CHANNEL_ORDER(4321, CL_ABGR); #endif @@ -1727,10 +1726,13 @@ static void opencl_frames_uninit(AVHWFramesContext *hwfc) av_freep(&priv->mapped_frames); #endif - cle = clReleaseCommandQueue(priv->command_queue); - if (cle != CL_SUCCESS) { - av_log(hwfc, AV_LOG_ERROR, "Failed to release frame " - "command queue: %d.\n", cle); + if (priv->command_queue) { + cle = clReleaseCommandQueue(priv->command_queue); + if (cle != CL_SUCCESS) { + av_log(hwfc, AV_LOG_ERROR, "Failed to release frame " + "command queue: %d.\n", cle); + } + priv->command_queue = NULL; } } @@ -2153,7 +2155,6 @@ static int opencl_map_from_vaapi(AVHWFramesContext *dst_fc, AVFrame *dst, const AVFrame *src, int flags) { - HWMapDescriptor *hwmap; AVFrame *tmp; int err; @@ -2171,10 +2172,7 @@ static int opencl_map_from_vaapi(AVHWFramesContext *dst_fc, if (err < 0) goto fail; - // Adjust the map descriptor so that unmap works correctly. - hwmap = (HWMapDescriptor*)dst->buf[0]->data; - av_frame_unref(hwmap->source); - err = av_frame_ref(hwmap->source, src); + err = ff_hwframe_map_replace(dst, src); fail: av_frame_free(&tmp); @@ -2248,10 +2246,13 @@ static int opencl_map_from_qsv(AVHWFramesContext *dst_fc, AVFrame *dst, cl_int cle; int err, p; +#if CONFIG_LIBMFX if (src->format == AV_PIX_FMT_QSV) { mfxFrameSurface1 *mfx_surface = (mfxFrameSurface1*)src->data[3]; va_surface = *(VASurfaceID*)mfx_surface->Data.MemId; - } else if (src->format == AV_PIX_FMT_VAAPI) { + } else +#endif + if (src->format == AV_PIX_FMT_VAAPI) { va_surface = (VASurfaceID)(uintptr_t)src->data[3]; } else { return AVERROR(ENOSYS); @@ -2809,7 +2810,7 @@ static int opencl_map_from(AVHWFramesContext *hwfc, AVFrame *dst, static int opencl_map_to(AVHWFramesContext *hwfc, AVFrame *dst, const AVFrame *src, int flags) { - OpenCLDeviceContext *priv = hwfc->device_ctx->internal->priv; + av_unused OpenCLDeviceContext *priv = hwfc->device_ctx->internal->priv; av_assert0(dst->format == AV_PIX_FMT_OPENCL); switch (src->format) { #if HAVE_OPENCL_DRM_BEIGNET @@ -2850,7 +2851,7 @@ static int opencl_map_to(AVHWFramesContext *hwfc, AVFrame *dst, static int opencl_frames_derive_to(AVHWFramesContext *dst_fc, AVHWFramesContext *src_fc, int flags) { - OpenCLDeviceContext *priv = dst_fc->device_ctx->internal->priv; + av_unused OpenCLDeviceContext *priv = dst_fc->device_ctx->internal->priv; switch (src_fc->device_ctx->type) { #if HAVE_OPENCL_DRM_BEIGNET case AV_HWDEVICE_TYPE_DRM: diff --git a/libavutil/hwcontext_qsv.c b/libavutil/hwcontext_qsv.c index 250091c4e..59e4ed915 100644 --- a/libavutil/hwcontext_qsv.c +++ b/libavutil/hwcontext_qsv.c @@ -23,6 +23,10 @@ #include "config.h" +#if HAVE_PTHREADS +#include +#endif + #if CONFIG_VAAPI #include "hwcontext_vaapi.h" #endif @@ -56,7 +60,13 @@ typedef struct QSVDeviceContext { typedef struct QSVFramesContext { mfxSession session_download; + int session_download_init; mfxSession session_upload; + int session_upload_init; +#if HAVE_PTHREADS + pthread_mutex_t session_lock; + pthread_cond_t session_cond; +#endif AVBufferRef *child_frames_ref; mfxFrameSurface1 *surfaces_internal; @@ -90,6 +100,7 @@ static const struct { uint32_t fourcc; } supported_pixel_formats[] = { { AV_PIX_FMT_NV12, MFX_FOURCC_NV12 }, + { AV_PIX_FMT_BGRA, MFX_FOURCC_RGB4 }, { AV_PIX_FMT_P010, MFX_FOURCC_P010 }, { AV_PIX_FMT_PAL8, MFX_FOURCC_P8 }, }; @@ -147,12 +158,19 @@ static void qsv_frames_uninit(AVHWFramesContext *ctx) MFXClose(s->session_download); } s->session_download = NULL; + s->session_download_init = 0; if (s->session_upload) { MFXVideoVPP_Close(s->session_upload); MFXClose(s->session_upload); } s->session_upload = NULL; + s->session_upload_init = 0; + +#if HAVE_PTHREADS + pthread_mutex_destroy(&s->session_lock); + pthread_cond_destroy(&s->session_cond); +#endif av_freep(&s->mem_ids); av_freep(&s->surface_ptrs); @@ -371,7 +389,7 @@ static mfxStatus frame_alloc(mfxHDL pthis, mfxFrameAllocRequest *req, !(req->Type & (MFX_MEMTYPE_FROM_VPPIN | MFX_MEMTYPE_FROM_VPPOUT)) || !(req->Type & MFX_MEMTYPE_EXTERNAL_FRAME)) return MFX_ERR_UNSUPPORTED; - if (i->Width != i1->Width || i->Height != i1->Height || + if (i->Width > i1->Width || i->Height > i1->Height || i->FourCC != i1->FourCC || i->ChromaFormat != i1->ChromaFormat) { av_log(ctx, AV_LOG_ERROR, "Mismatching surface properties in an " "allocation request: %dx%d %d %d vs %dx%d %d %d\n", @@ -535,13 +553,16 @@ static int qsv_frames_init(AVHWFramesContext *ctx) s->mem_ids[i] = frames_hwctx->surfaces[i].Data.MemId; } - ret = qsv_init_internal_session(ctx, &s->session_download, 0); - if (ret < 0) - return ret; + s->session_download = NULL; + s->session_upload = NULL; - ret = qsv_init_internal_session(ctx, &s->session_upload, 1); - if (ret < 0) - return ret; + s->session_download_init = 0; + s->session_upload_init = 0; + +#if HAVE_PTHREADS + pthread_mutex_init(&s->session_lock, NULL); + pthread_cond_init(&s->session_cond, NULL); +#endif return 0; } @@ -731,6 +752,37 @@ static int qsv_transfer_data_child(AVHWFramesContext *ctx, AVFrame *dst, return ret; } +static int map_frame_to_surface(const AVFrame *frame, mfxFrameSurface1 *surface) +{ + switch (frame->format) { + case AV_PIX_FMT_NV12: + case AV_PIX_FMT_P010: + surface->Data.Y = frame->data[0]; + surface->Data.UV = frame->data[1]; + break; + + case AV_PIX_FMT_YUV420P: + surface->Data.Y = frame->data[0]; + surface->Data.U = frame->data[1]; + surface->Data.V = frame->data[2]; + break; + + case AV_PIX_FMT_BGRA: + surface->Data.B = frame->data[0]; + surface->Data.G = frame->data[0] + 1; + surface->Data.R = frame->data[0] + 2; + surface->Data.A = frame->data[0] + 3; + break; + + default: + return MFX_ERR_UNSUPPORTED; + } + surface->Data.Pitch = frame->linesize[0]; + surface->Data.TimeStamp = frame->pts; + + return 0; +} + static int qsv_transfer_data_from(AVHWFramesContext *ctx, AVFrame *dst, const AVFrame *src) { @@ -740,6 +792,32 @@ static int qsv_transfer_data_from(AVHWFramesContext *ctx, AVFrame *dst, mfxSyncPoint sync = NULL; mfxStatus err; + int ret = 0; + + while (!s->session_download_init && !s->session_download && !ret) { +#if HAVE_PTHREADS + if (pthread_mutex_trylock(&s->session_lock) == 0) { +#endif + if (!s->session_download_init) { + ret = qsv_init_internal_session(ctx, &s->session_download, 0); + if (s->session_download) + s->session_download_init = 1; + } +#if HAVE_PTHREADS + pthread_mutex_unlock(&s->session_lock); + pthread_cond_signal(&s->session_cond); + } else { + pthread_mutex_lock(&s->session_lock); + while (!s->session_download_init && !s->session_download) { + pthread_cond_wait(&s->session_cond, &s->session_lock); + } + pthread_mutex_unlock(&s->session_lock); + } +#endif + } + + if (ret < 0) + return ret; if (!s->session_download) { if (s->child_frames_ref) @@ -750,11 +828,7 @@ static int qsv_transfer_data_from(AVHWFramesContext *ctx, AVFrame *dst, } out.Info = in->Info; - out.Data.PitchLow = dst->linesize[0]; - out.Data.Y = dst->data[0]; - out.Data.U = dst->data[1]; - out.Data.V = dst->data[2]; - out.Data.A = dst->data[3]; + map_frame_to_surface(dst, &out); do { err = MFXVideoVPP_RunFrameVPPAsync(s->session_download, in, &out, NULL, &sync); @@ -787,21 +861,66 @@ static int qsv_transfer_data_to(AVHWFramesContext *ctx, AVFrame *dst, mfxSyncPoint sync = NULL; mfxStatus err; + int ret = 0; + /* make a copy if the input is not padded as libmfx requires */ + AVFrame tmp_frame; + const AVFrame *src_frame; + int realigned = 0; + + + while (!s->session_upload_init && !s->session_upload && !ret) { +#if HAVE_PTHREADS + if (pthread_mutex_trylock(&s->session_lock) == 0) { +#endif + if (!s->session_upload_init) { + ret = qsv_init_internal_session(ctx, &s->session_upload, 1); + if (s->session_upload) + s->session_upload_init = 1; + } +#if HAVE_PTHREADS + pthread_mutex_unlock(&s->session_lock); + pthread_cond_signal(&s->session_cond); + } else { + pthread_mutex_lock(&s->session_lock); + while (!s->session_upload_init && !s->session_upload) { + pthread_cond_wait(&s->session_cond, &s->session_lock); + } + pthread_mutex_unlock(&s->session_lock); + } +#endif + } + if (ret < 0) + return ret; + + if (src->height & 15 || src->linesize[0] & 15) { + realigned = 1; + memset(&tmp_frame, 0, sizeof(tmp_frame)); + tmp_frame.format = src->format; + tmp_frame.width = FFALIGN(src->width, 16); + tmp_frame.height = FFALIGN(src->height, 16); + ret = av_frame_get_buffer(&tmp_frame, 32); + if (ret < 0) + return ret; + + ret = av_frame_copy(&tmp_frame, src); + if (ret < 0) { + av_frame_unref(&tmp_frame); + return ret; + } + } + + src_frame = realigned ? &tmp_frame : src; if (!s->session_upload) { if (s->child_frames_ref) - return qsv_transfer_data_child(ctx, dst, src); + return qsv_transfer_data_child(ctx, dst, src_frame); av_log(ctx, AV_LOG_ERROR, "Surface upload not possible\n"); return AVERROR(ENOSYS); } in.Info = out->Info; - in.Data.PitchLow = src->linesize[0]; - in.Data.Y = src->data[0]; - in.Data.U = src->data[1]; - in.Data.V = src->data[2]; - in.Data.A = src->data[3]; + map_frame_to_surface(src_frame, &in); do { err = MFXVideoVPP_RunFrameVPPAsync(s->session_upload, &in, out, NULL, &sync); @@ -822,6 +941,9 @@ static int qsv_transfer_data_to(AVHWFramesContext *ctx, AVFrame *dst, return AVERROR_UNKNOWN; } + if (realigned) + av_frame_unref(&tmp_frame); + return 0; } @@ -1084,6 +1206,7 @@ static int qsv_device_create(AVHWDeviceContext *ctx, const char *device, QSVDevicePriv *priv; enum AVHWDeviceType child_device_type; AVHWDeviceContext *child_device; + AVDictionary *child_device_opts; AVDictionaryEntry *e; mfxIMPL impl; @@ -1098,9 +1221,17 @@ static int qsv_device_create(AVHWDeviceContext *ctx, const char *device, e = av_dict_get(opts, "child_device", NULL, 0); - if (CONFIG_VAAPI) + child_device_opts = NULL; + if (CONFIG_VAAPI) { child_device_type = AV_HWDEVICE_TYPE_VAAPI; - else if (CONFIG_DXVA2) + // libmfx does not actually implement VAAPI properly, rather it + // depends on the specific behaviour of a matching iHD driver when + // used on recent Intel hardware. Set options to the VAAPI device + // creation so that we should pick a usable setup by default if + // possible, even when multiple devices and drivers are available. + av_dict_set(&child_device_opts, "kernel_driver", "i915", 0); + av_dict_set(&child_device_opts, "driver", "iHD", 0); + } else if (CONFIG_DXVA2) child_device_type = AV_HWDEVICE_TYPE_DXVA2; else { av_log(ctx, AV_LOG_ERROR, "No supported child device type is enabled\n"); @@ -1108,7 +1239,7 @@ static int qsv_device_create(AVHWDeviceContext *ctx, const char *device, } ret = av_hwdevice_ctx_create(&priv->child_device_ctx, child_device_type, - e ? e->value : NULL, NULL, 0); + e ? e->value : NULL, child_device_opts, 0); if (ret < 0) return ret; diff --git a/libavutil/hwcontext_vaapi.c b/libavutil/hwcontext_vaapi.c index 7daaa951c..cf117640f 100644 --- a/libavutil/hwcontext_vaapi.c +++ b/libavutil/hwcontext_vaapi.c @@ -27,6 +27,7 @@ #if CONFIG_LIBDRM # include +# include # include # ifndef DRM_FORMAT_MOD_INVALID # define DRM_FORMAT_MOD_INVALID ((1ULL << 56) - 1) @@ -87,57 +88,82 @@ typedef struct VAAPIMapping { int flags; } VAAPIMapping; -#define MAP(va, rt, av) { \ - VA_FOURCC_ ## va, \ - VA_RT_FORMAT_ ## rt, \ - AV_PIX_FMT_ ## av \ - } -// The map fourcc <-> pix_fmt isn't bijective because of the annoying U/V -// plane swap cases. The frame handling below tries to hide these. -static const struct { +typedef struct VAAPIFormat { unsigned int fourcc; unsigned int rt_format; enum AVPixelFormat pix_fmt; -} vaapi_format_map[] = { - MAP(NV12, YUV420, NV12), - MAP(YV12, YUV420, YUV420P), // With U/V planes swapped. - MAP(IYUV, YUV420, YUV420P), + int chroma_planes_swapped; +} VAAPIFormatDescriptor; + +#define MAP(va, rt, av, swap_uv) { \ + VA_FOURCC_ ## va, \ + VA_RT_FORMAT_ ## rt, \ + AV_PIX_FMT_ ## av, \ + swap_uv, \ + } +// The map fourcc <-> pix_fmt isn't bijective because of the annoying U/V +// plane swap cases. The frame handling below tries to hide these. +static const VAAPIFormatDescriptor vaapi_format_map[] = { + MAP(NV12, YUV420, NV12, 0), #ifdef VA_FOURCC_I420 - MAP(I420, YUV420, YUV420P), + MAP(I420, YUV420, YUV420P, 0), #endif + MAP(YV12, YUV420, YUV420P, 1), + MAP(IYUV, YUV420, YUV420P, 0), + MAP(422H, YUV422, YUV422P, 0), #ifdef VA_FOURCC_YV16 - MAP(YV16, YUV422, YUV422P), // With U/V planes swapped. + MAP(YV16, YUV422, YUV422P, 1), #endif - MAP(422H, YUV422, YUV422P), - MAP(UYVY, YUV422, UYVY422), - MAP(YUY2, YUV422, YUYV422), - MAP(411P, YUV411, YUV411P), - MAP(422V, YUV422, YUV440P), - MAP(444P, YUV444, YUV444P), - MAP(Y800, YUV400, GRAY8), + MAP(UYVY, YUV422, UYVY422, 0), + MAP(YUY2, YUV422, YUYV422, 0), + MAP(411P, YUV411, YUV411P, 0), + MAP(422V, YUV422, YUV440P, 0), + MAP(444P, YUV444, YUV444P, 0), + MAP(Y800, YUV400, GRAY8, 0), #ifdef VA_FOURCC_P010 - MAP(P010, YUV420_10BPP, P010), + MAP(P010, YUV420_10BPP, P010, 0), #endif - MAP(BGRA, RGB32, BGRA), - MAP(BGRX, RGB32, BGR0), - MAP(RGBA, RGB32, RGBA), - MAP(RGBX, RGB32, RGB0), + MAP(BGRA, RGB32, BGRA, 0), + MAP(BGRX, RGB32, BGR0, 0), + MAP(RGBA, RGB32, RGBA, 0), + MAP(RGBX, RGB32, RGB0, 0), #ifdef VA_FOURCC_ABGR - MAP(ABGR, RGB32, ABGR), - MAP(XBGR, RGB32, 0BGR), + MAP(ABGR, RGB32, ABGR, 0), + MAP(XBGR, RGB32, 0BGR, 0), #endif - MAP(ARGB, RGB32, ARGB), - MAP(XRGB, RGB32, 0RGB), + MAP(ARGB, RGB32, ARGB, 0), + MAP(XRGB, RGB32, 0RGB, 0), }; #undef MAP -static enum AVPixelFormat vaapi_pix_fmt_from_fourcc(unsigned int fourcc) +static const VAAPIFormatDescriptor * + vaapi_format_from_fourcc(unsigned int fourcc) { int i; for (i = 0; i < FF_ARRAY_ELEMS(vaapi_format_map); i++) if (vaapi_format_map[i].fourcc == fourcc) - return vaapi_format_map[i].pix_fmt; - return AV_PIX_FMT_NONE; + return &vaapi_format_map[i]; + return NULL; +} + +static const VAAPIFormatDescriptor * + vaapi_format_from_pix_fmt(enum AVPixelFormat pix_fmt) +{ + int i; + for (i = 0; i < FF_ARRAY_ELEMS(vaapi_format_map); i++) + if (vaapi_format_map[i].pix_fmt == pix_fmt) + return &vaapi_format_map[i]; + return NULL; +} + +static enum AVPixelFormat vaapi_pix_fmt_from_fourcc(unsigned int fourcc) +{ + const VAAPIFormatDescriptor *desc; + desc = vaapi_format_from_fourcc(fourcc); + if (desc) + return desc->pix_fmt; + else + return AV_PIX_FMT_NONE; } static int vaapi_get_image_format(AVHWDeviceContext *hwdev, @@ -279,11 +305,14 @@ static const struct { const char *match_string; unsigned int quirks; } vaapi_driver_quirks_table[] = { +#if !VA_CHECK_VERSION(1, 0, 0) + // The i965 driver did not conform before version 2.0. { "Intel i965 (Quick Sync)", "i965", AV_VAAPI_DRIVER_QUIRK_RENDER_PARAM_BUFFERS, }, +#endif { "Intel iHD", "ubit", @@ -344,29 +373,37 @@ static int vaapi_device_init(AVHWDeviceContext *hwdev) } } + vendor_string = vaQueryVendorString(hwctx->display); + if (vendor_string) + av_log(hwdev, AV_LOG_VERBOSE, "VAAPI driver: %s.\n", vendor_string); + if (hwctx->driver_quirks & AV_VAAPI_DRIVER_QUIRK_USER_SET) { - av_log(hwdev, AV_LOG_VERBOSE, "Not detecting driver: " - "quirks set by user.\n"); + av_log(hwdev, AV_LOG_VERBOSE, "Using quirks set by user (%#x).\n", + hwctx->driver_quirks); } else { // Detect the driver in use and set quirk flags if necessary. - vendor_string = vaQueryVendorString(hwctx->display); hwctx->driver_quirks = 0; if (vendor_string) { for (i = 0; i < FF_ARRAY_ELEMS(vaapi_driver_quirks_table); i++) { if (strstr(vendor_string, vaapi_driver_quirks_table[i].match_string)) { - av_log(hwdev, AV_LOG_VERBOSE, "Matched \"%s\" as known " - "driver \"%s\".\n", vendor_string, - vaapi_driver_quirks_table[i].friendly_name); + av_log(hwdev, AV_LOG_VERBOSE, "Matched driver string " + "as known nonstandard driver \"%s\", setting " + "quirks (%#x).\n", + vaapi_driver_quirks_table[i].friendly_name, + vaapi_driver_quirks_table[i].quirks); hwctx->driver_quirks |= vaapi_driver_quirks_table[i].quirks; break; } } if (!(i < FF_ARRAY_ELEMS(vaapi_driver_quirks_table))) { - av_log(hwdev, AV_LOG_VERBOSE, "Unknown driver \"%s\", " - "assuming standard behaviour.\n", vendor_string); + av_log(hwdev, AV_LOG_VERBOSE, "Driver not found in known " + "nonstandard list, using standard behaviour.\n"); } + } else { + av_log(hwdev, AV_LOG_VERBOSE, "Driver has no vendor string, " + "assuming standard behaviour.\n"); } } @@ -450,22 +487,16 @@ static int vaapi_frames_init(AVHWFramesContext *hwfc) AVVAAPIFramesContext *avfc = hwfc->hwctx; VAAPIFramesContext *ctx = hwfc->internal->priv; AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx; + const VAAPIFormatDescriptor *desc; VAImageFormat *expected_format; AVBufferRef *test_surface = NULL; VASurfaceID test_surface_id; VAImage test_image; VAStatus vas; int err, i; - unsigned int fourcc, rt_format; - for (i = 0; i < FF_ARRAY_ELEMS(vaapi_format_map); i++) { - if (vaapi_format_map[i].pix_fmt == hwfc->sw_format) { - fourcc = vaapi_format_map[i].fourcc; - rt_format = vaapi_format_map[i].rt_format; - break; - } - } - if (i >= FF_ARRAY_ELEMS(vaapi_format_map)) { + desc = vaapi_format_from_pix_fmt(hwfc->sw_format); + if (!desc) { av_log(hwfc, AV_LOG_ERROR, "Unsupported format: %s.\n", av_get_pix_fmt_name(hwfc->sw_format)); return AVERROR(EINVAL); @@ -506,7 +537,7 @@ static int vaapi_frames_init(AVHWFramesContext *hwfc) .type = VASurfaceAttribPixelFormat, .flags = VA_SURFACE_ATTRIB_SETTABLE, .value.type = VAGenericValueTypeInteger, - .value.value.i = fourcc, + .value.value.i = desc->fourcc, }; } av_assert0(i == ctx->nb_attributes); @@ -515,7 +546,7 @@ static int vaapi_frames_init(AVHWFramesContext *hwfc) ctx->nb_attributes = 0; } - ctx->rt_format = rt_format; + ctx->rt_format = desc->rt_format; if (hwfc->initial_pool_size > 0) { // This pool will be usable as a render target, so we need to store @@ -705,6 +736,7 @@ static int vaapi_map_frame(AVHWFramesContext *hwfc, AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx; VAAPIFramesContext *ctx = hwfc->internal->priv; VASurfaceID surface_id; + const VAAPIFormatDescriptor *desc; VAImageFormat *image_format; VAAPIMapping *map; VAStatus vas; @@ -813,11 +845,9 @@ static int vaapi_map_frame(AVHWFramesContext *hwfc, dst->data[i] = (uint8_t*)address + map->image.offsets[i]; dst->linesize[i] = map->image.pitches[i]; } - if ( -#ifdef VA_FOURCC_YV16 - map->image.format.fourcc == VA_FOURCC_YV16 || -#endif - map->image.format.fourcc == VA_FOURCC_YV12) { + + desc = vaapi_format_from_fourcc(map->image.format.fourcc); + if (desc && desc->chroma_planes_swapped) { // Chroma planes are YVU rather than YUV, so swap them. FFSWAP(uint8_t*, dst->data[1], dst->data[2]); } @@ -970,9 +1000,10 @@ static int vaapi_map_from_drm(AVHWFramesContext *src_fc, AVFrame *dst, (AVHWFramesContext*)dst->hw_frames_ctx->data; AVVAAPIDeviceContext *dst_dev = dst_fc->device_ctx->hwctx; const AVDRMFrameDescriptor *desc; + const VAAPIFormatDescriptor *format_desc; VASurfaceID surface_id; VAStatus vas; - uint32_t va_fourcc, va_rt_format; + uint32_t va_fourcc; int err, i, j, k; unsigned long buffer_handle; @@ -1023,10 +1054,8 @@ static int vaapi_map_from_drm(AVHWFramesContext *src_fc, AVFrame *dst, av_log(dst_fc, AV_LOG_DEBUG, "Map DRM object %d to VAAPI as " "%08x.\n", desc->objects[0].fd, va_fourcc); - for (i = 0; i < FF_ARRAY_ELEMS(vaapi_format_map); i++) { - if (vaapi_format_map[i].fourcc == va_fourcc) - va_rt_format = vaapi_format_map[i].rt_format; - } + format_desc = vaapi_format_from_fourcc(va_fourcc); + av_assert0(format_desc); buffer_handle = desc->objects[0].fd; buffer_desc.pixel_format = va_fourcc; @@ -1047,7 +1076,13 @@ static int vaapi_map_from_drm(AVHWFramesContext *src_fc, AVFrame *dst, } buffer_desc.num_planes = k; - vas = vaCreateSurfaces(dst_dev->display, va_rt_format, + if (format_desc->chroma_planes_swapped && + buffer_desc.num_planes == 3) { + FFSWAP(uint32_t, buffer_desc.pitches[1], buffer_desc.pitches[2]); + FFSWAP(uint32_t, buffer_desc.offsets[1], buffer_desc.offsets[2]); + } + + vas = vaCreateSurfaces(dst_dev->display, format_desc->rt_format, src->width, src->height, &surface_id, 1, attrs, FF_ARRAY_ELEMS(attrs)); @@ -1435,6 +1470,8 @@ static int vaapi_device_create(AVHWDeviceContext *ctx, const char *device, { VAAPIDevicePriv *priv; VADisplay display = NULL; + const AVDictionaryEntry *ent; + int try_drm, try_x11, try_all; priv = av_mallocz(sizeof(*priv)); if (!priv) @@ -1445,8 +1482,95 @@ static int vaapi_device_create(AVHWDeviceContext *ctx, const char *device, ctx->user_opaque = priv; ctx->free = vaapi_device_free; + ent = av_dict_get(opts, "connection_type", NULL, 0); + if (ent) { + try_all = try_drm = try_x11 = 0; + if (!strcmp(ent->value, "drm")) { + try_drm = 1; + } else if (!strcmp(ent->value, "x11")) { + try_x11 = 1; + } else { + av_log(ctx, AV_LOG_ERROR, "Invalid connection type %s.\n", + ent->value); + return AVERROR(EINVAL); + } + } else { + try_all = 1; + try_drm = HAVE_VAAPI_DRM; + try_x11 = HAVE_VAAPI_X11; + } + +#if HAVE_VAAPI_DRM + while (!display && try_drm) { + // If the device is specified, try to open it as a DRM device node. + // If not, look for a usable render node, possibly restricted to those + // using a specified kernel driver. + int loglevel = try_all ? AV_LOG_VERBOSE : AV_LOG_ERROR; + if (device) { + priv->drm_fd = open(device, O_RDWR); + if (priv->drm_fd < 0) { + av_log(ctx, loglevel, "Failed to open %s as " + "DRM device node.\n", device); + break; + } + } else { + char path[64]; + int n, max_devices = 8; +#if CONFIG_LIBDRM + const AVDictionaryEntry *kernel_driver; + kernel_driver = av_dict_get(opts, "kernel_driver", NULL, 0); +#endif + for (n = 0; n < max_devices; n++) { + snprintf(path, sizeof(path), + "/dev/dri/renderD%d", 128 + n); + priv->drm_fd = open(path, O_RDWR); + if (priv->drm_fd < 0) { + av_log(ctx, AV_LOG_VERBOSE, "Cannot open " + "DRM render node for device %d.\n", n); + break; + } +#if CONFIG_LIBDRM + if (kernel_driver) { + drmVersion *info; + info = drmGetVersion(priv->drm_fd); + if (strcmp(kernel_driver->value, info->name)) { + av_log(ctx, AV_LOG_VERBOSE, "Ignoring device %d " + "with non-matching kernel driver (%s).\n", + n, info->name); + drmFreeVersion(info); + close(priv->drm_fd); + priv->drm_fd = -1; + continue; + } + av_log(ctx, AV_LOG_VERBOSE, "Trying to use " + "DRM render node for device %d, " + "with matching kernel driver (%s).\n", + n, info->name); + drmFreeVersion(info); + } else +#endif + { + av_log(ctx, AV_LOG_VERBOSE, "Trying to use " + "DRM render node for device %d.\n", n); + } + break; + } + if (n >= max_devices) + break; + } + + display = vaGetDisplayDRM(priv->drm_fd); + if (!display) { + av_log(ctx, AV_LOG_VERBOSE, "Cannot open a VA display " + "from DRM device %s.\n", device); + return AVERROR_EXTERNAL; + } + break; + } +#endif + #if HAVE_VAAPI_X11 - if (!display && !(device && device[0] == '/')) { + if (!display && try_x11) { // Try to open the device as an X11 display. priv->x11_display = XOpenDisplay(device); if (!priv->x11_display) { @@ -1466,36 +1590,33 @@ static int vaapi_device_create(AVHWDeviceContext *ctx, const char *device, } #endif -#if HAVE_VAAPI_DRM if (!display) { - // Try to open the device as a DRM path. - // Default to using the first render node if the user did not - // supply a path. - const char *path = device ? device : "/dev/dri/renderD128"; - priv->drm_fd = open(path, O_RDWR); - if (priv->drm_fd < 0) { - av_log(ctx, AV_LOG_VERBOSE, "Cannot open DRM device %s.\n", - path); - } else { - display = vaGetDisplayDRM(priv->drm_fd); - if (!display) { - av_log(ctx, AV_LOG_ERROR, "Cannot open a VA display " - "from DRM device %s.\n", path); - return AVERROR_UNKNOWN; - } - - av_log(ctx, AV_LOG_VERBOSE, "Opened VA display via " - "DRM device %s.\n", path); - } - } -#endif - - if (!display) { - av_log(ctx, AV_LOG_ERROR, "No VA display found for " - "device: %s.\n", device ? device : ""); + if (device) + av_log(ctx, AV_LOG_ERROR, "No VA display found for " + "device %s.\n", device); + else + av_log(ctx, AV_LOG_ERROR, "No VA display found for " + "any default device.\n"); return AVERROR(EINVAL); } + ent = av_dict_get(opts, "driver", NULL, 0); + if (ent) { +#if VA_CHECK_VERSION(0, 38, 0) + VAStatus vas; + vas = vaSetDriverName(display, ent->value); + if (vas != VA_STATUS_SUCCESS) { + av_log(ctx, AV_LOG_ERROR, "Failed to set driver name to " + "%s: %d (%s).\n", ent->value, vas, vaErrorStr(vas)); + vaTerminate(display); + return AVERROR_EXTERNAL; + } +#else + av_log(ctx, AV_LOG_WARNING, "Driver name setting is not " + "supported with this VAAPI version.\n"); +#endif + } + return vaapi_device_connect(ctx, display); } diff --git a/libavutil/hwcontext_vdpau.c b/libavutil/hwcontext_vdpau.c index c11c3cfda..6b8c1d5f7 100644 --- a/libavutil/hwcontext_vdpau.c +++ b/libavutil/hwcontext_vdpau.c @@ -73,8 +73,10 @@ static const VDPAUPixFmtMap pix_fmts_422[] = { }; static const VDPAUPixFmtMap pix_fmts_444[] = { - { VDP_YCBCR_FORMAT_YV12, AV_PIX_FMT_YUV444P }, - { 0, AV_PIX_FMT_NONE, }, +#ifdef VDP_YCBCR_FORMAT_Y_U_V_444 + { VDP_YCBCR_FORMAT_Y_U_V_444, AV_PIX_FMT_YUV444P }, +#endif + { 0, AV_PIX_FMT_NONE, }, }; static const struct { @@ -349,7 +351,11 @@ static int vdpau_transfer_data_from(AVHWFramesContext *ctx, AVFrame *dst, return AVERROR(EINVAL); } - if (vdpau_format == VDP_YCBCR_FORMAT_YV12) + if ((vdpau_format == VDP_YCBCR_FORMAT_YV12) +#ifdef VDP_YCBCR_FORMAT_Y_U_V_444 + || (vdpau_format == VDP_YCBCR_FORMAT_Y_U_V_444) +#endif + ) FFSWAP(void*, data[1], data[2]); err = priv->get_data(surf, vdpau_format, data, linesize); @@ -400,7 +406,11 @@ static int vdpau_transfer_data_to(AVHWFramesContext *ctx, AVFrame *dst, return AVERROR(EINVAL); } - if (vdpau_format == VDP_YCBCR_FORMAT_YV12) + if ((vdpau_format == VDP_YCBCR_FORMAT_YV12) +#ifdef VDP_YCBCR_FORMAT_Y_U_V_444 + || (vdpau_format == VDP_YCBCR_FORMAT_Y_U_V_444) +#endif + ) FFSWAP(const void*, data[1], data[2]); err = priv->put_data(surf, vdpau_format, data, linesize); diff --git a/libavutil/hwcontext_videotoolbox.c b/libavutil/hwcontext_videotoolbox.c index cc00f1f2f..6eac2c077 100644 --- a/libavutil/hwcontext_videotoolbox.c +++ b/libavutil/hwcontext_videotoolbox.c @@ -42,6 +42,9 @@ static const struct { #ifdef kCFCoreFoundationVersionNumber10_7 { kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange, AV_PIX_FMT_NV12 }, #endif +#if HAVE_KCVPIXELFORMATTYPE_420YPCBCR10BIPLANARVIDEORANGE + { kCVPixelFormatType_420YpCbCr10BiPlanarVideoRange, AV_PIX_FMT_P010 }, +#endif }; enum AVPixelFormat av_map_videotoolbox_format_to_pixfmt(uint32_t cv_fmt) diff --git a/libavutil/imgutils.c b/libavutil/imgutils.c index afc73e2de..c733cb5cf 100644 --- a/libavutil/imgutils.c +++ b/libavutil/imgutils.c @@ -311,8 +311,8 @@ static void image_copy_plane(uint8_t *dst, ptrdiff_t dst_linesize, { if (!dst || !src) return; - av_assert0(abs(src_linesize) >= bytewidth); - av_assert0(abs(dst_linesize) >= bytewidth); + av_assert0(FFABS(src_linesize) >= bytewidth); + av_assert0(FFABS(dst_linesize) >= bytewidth); for (;height > 0; height--) { memcpy(dst, src, bytewidth); dst += dst_linesize; diff --git a/libavutil/internal.h b/libavutil/internal.h index 06bd561e8..4acbcf56c 100644 --- a/libavutil/internal.h +++ b/libavutil/internal.h @@ -52,7 +52,7 @@ #endif #ifndef emms_c -# define emms_c() while(0) +# define emms_c() do {} while(0) #endif #ifndef attribute_align_arg diff --git a/libavutil/intreadwrite.h b/libavutil/intreadwrite.h index 67c763b13..4c8413a53 100644 --- a/libavutil/intreadwrite.h +++ b/libavutil/intreadwrite.h @@ -542,6 +542,21 @@ union unaligned_16 { uint16_t l; } __attribute__((packed)) av_alias; # define AV_WN64A(p, v) AV_WNA(64, p, v) #endif +#if AV_HAVE_BIGENDIAN +# define AV_RLA(s, p) av_bswap##s(AV_RN##s##A(p)) +# define AV_WLA(s, p, v) AV_WN##s##A(p, av_bswap##s(v)) +#else +# define AV_RLA(s, p) AV_RN##s##A(p) +# define AV_WLA(s, p, v) AV_WN##s##A(p, v) +#endif + +#ifndef AV_RL64A +# define AV_RL64A(p) AV_RLA(64, p) +#endif +#ifndef AV_WL64A +# define AV_WL64A(p, v) AV_WLA(64, p, v) +#endif + /* * The AV_COPYxxU macros are suitable for copying data to/from unaligned * memory locations. diff --git a/libavutil/log.c b/libavutil/log.c index 9b7d48487..93a156b8e 100644 --- a/libavutil/log.c +++ b/libavutil/log.c @@ -247,9 +247,9 @@ static void format_line(void *avcl, int level, const char *fmt, va_list vl, AVBPrint part[4], int *print_prefix, int type[2]) { AVClass* avc = avcl ? *(AVClass **) avcl : NULL; - av_bprint_init(part+0, 0, 1); - av_bprint_init(part+1, 0, 1); - av_bprint_init(part+2, 0, 1); + av_bprint_init(part+0, 0, AV_BPRINT_SIZE_AUTOMATIC); + av_bprint_init(part+1, 0, AV_BPRINT_SIZE_AUTOMATIC); + av_bprint_init(part+2, 0, AV_BPRINT_SIZE_AUTOMATIC); av_bprint_init(part+3, 0, 65536); if(type) type[0] = type[1] = AV_CLASS_CATEGORY_NA + 16; diff --git a/libavutil/mem.h b/libavutil/mem.h index 7e0b12a8a..5fb1a02dd 100644 --- a/libavutil/mem.h +++ b/libavutil/mem.h @@ -339,7 +339,7 @@ av_alloc_size(2, 3) void *av_realloc_array(void *ptr, size_t nmemb, size_t size) * @warning Unlike av_malloc(), the allocated memory is not guaranteed to be * correctly aligned. */ -av_alloc_size(2, 3) int av_reallocp_array(void *ptr, size_t nmemb, size_t size); +int av_reallocp_array(void *ptr, size_t nmemb, size_t size); /** * Reallocate the given buffer if it is not large enough, otherwise do nothing. @@ -363,10 +363,10 @@ av_alloc_size(2, 3) int av_reallocp_array(void *ptr, size_t nmemb, size_t size); * @endcode * * @param[in,out] ptr Already allocated buffer, or `NULL` - * @param[in,out] size Pointer to current size of buffer `ptr`. `*size` is - * changed to `min_size` in case of success or 0 in - * case of failure - * @param[in] min_size New size of buffer `ptr` + * @param[in,out] size Pointer to the size of buffer `ptr`. `*size` is + * updated to the new allocated size, in particular 0 + * in case of failure. + * @param[in] min_size Desired minimal size of buffer `ptr` * @return `ptr` if the buffer is large enough, a pointer to newly reallocated * buffer if the buffer was not large enough, or `NULL` in case of * error @@ -397,10 +397,10 @@ void *av_fast_realloc(void *ptr, unsigned int *size, size_t min_size); * @param[in,out] ptr Pointer to pointer to an already allocated buffer. * `*ptr` will be overwritten with pointer to new * buffer on success or `NULL` on failure - * @param[in,out] size Pointer to current size of buffer `*ptr`. `*size` is - * changed to `min_size` in case of success or 0 in - * case of failure - * @param[in] min_size New size of buffer `*ptr` + * @param[in,out] size Pointer to the size of buffer `*ptr`. `*size` is + * updated to the new allocated size, in particular 0 + * in case of failure. + * @param[in] min_size Desired minimal size of buffer `*ptr` * @see av_realloc() * @see av_fast_mallocz() */ @@ -418,10 +418,10 @@ void av_fast_malloc(void *ptr, unsigned int *size, size_t min_size); * @param[in,out] ptr Pointer to pointer to an already allocated buffer. * `*ptr` will be overwritten with pointer to new * buffer on success or `NULL` on failure - * @param[in,out] size Pointer to current size of buffer `*ptr`. `*size` is - * changed to `min_size` in case of success or 0 in - * case of failure - * @param[in] min_size New size of buffer `*ptr` + * @param[in,out] size Pointer to the size of buffer `*ptr`. `*size` is + * updated to the new allocated size, in particular 0 + * in case of failure. + * @param[in] min_size Desired minimal size of buffer `*ptr` * @see av_fast_malloc() */ void av_fast_mallocz(void *ptr, unsigned int *size, size_t min_size); diff --git a/libavutil/mips/generic_macros_msa.h b/libavutil/mips/generic_macros_msa.h index 6a4670466..9ac058376 100644 --- a/libavutil/mips/generic_macros_msa.h +++ b/libavutil/mips/generic_macros_msa.h @@ -23,6 +23,11 @@ #include #include +#include + +#if HAVE_MSA2 +#include +#endif #define ALIGNMENT 16 #define ALLOC_ALIGNED(align) __attribute__ ((aligned((align) << 1))) @@ -344,19 +349,6 @@ } #define LD_SH16(...) LD_V16(v8i16, __VA_ARGS__) -/* Description : Load as 4x4 block of signed halfword elements from 1D source - data into 4 vectors (Each vector with 4 signed halfwords) - Arguments : Inputs - psrc - Outputs - out0, out1, out2, out3 -*/ -#define LD4x4_SH(psrc, out0, out1, out2, out3) \ -{ \ - out0 = LD_SH(psrc); \ - out2 = LD_SH(psrc + 8); \ - out1 = (v8i16) __msa_ilvl_d((v2i64) out0, (v2i64) out0); \ - out3 = (v8i16) __msa_ilvl_d((v2i64) out2, (v2i64) out2); \ -} - /* Description : Store vectors with stride Arguments : Inputs - in0, in1, stride Outputs - pdst (destination pointer to store to) @@ -400,198 +392,127 @@ #define ST_SH8(...) ST_V8(v8i16, __VA_ARGS__) #define ST_SW8(...) ST_V8(v4i32, __VA_ARGS__) -/* Description : Store as 2x4 byte block to destination memory from input vector - Arguments : Inputs - in, stidx, pdst, stride - Return Type - unsigned byte - Details : Index stidx halfword element from 'in' vector is copied and - stored on first line - Index stidx+1 halfword element from 'in' vector is copied and - stored on second line - Index stidx+2 halfword element from 'in' vector is copied and - stored on third line - Index stidx+3 halfword element from 'in' vector is copied and - stored on fourth line -*/ -#define ST2x4_UB(in, stidx, pdst, stride) \ -{ \ - uint16_t out0_m, out1_m, out2_m, out3_m; \ - uint8_t *pblk_2x4_m = (uint8_t *) (pdst); \ - \ - out0_m = __msa_copy_u_h((v8i16) in, (stidx)); \ - out1_m = __msa_copy_u_h((v8i16) in, (stidx + 1)); \ - out2_m = __msa_copy_u_h((v8i16) in, (stidx + 2)); \ - out3_m = __msa_copy_u_h((v8i16) in, (stidx + 3)); \ - \ - SH(out0_m, pblk_2x4_m); \ - SH(out1_m, pblk_2x4_m + stride); \ - SH(out2_m, pblk_2x4_m + 2 * stride); \ - SH(out3_m, pblk_2x4_m + 3 * stride); \ +/* Description : Store half word elements of vector with stride + * Arguments : Inputs - in source vector + * - pdst (destination pointer to store to) + * - stride + * Details : Stores half word 'idx0' from 'in' to (pdst) + * Stores half word 'idx1' from 'in' to (pdst + stride) + * Similar for other elements + */ +#define ST_H1(in, idx, pdst) \ +{ \ + uint16_t out0_m; \ + out0_m = __msa_copy_u_h((v8i16) in, idx); \ + SH(out0_m, (pdst)); \ +} +#define ST_H2(in, idx0, idx1, pdst, stride) \ +{ \ + uint16_t out0_m, out1_m; \ + out0_m = __msa_copy_u_h((v8i16) in, idx0); \ + out1_m = __msa_copy_u_h((v8i16) in, idx1); \ + SH(out0_m, (pdst)); \ + SH(out1_m, (pdst) + stride); \ +} +#define ST_H4(in, idx0, idx1, idx2, idx3, pdst, stride) \ +{ \ + uint16_t out0_m, out1_m, out2_m, out3_m; \ + out0_m = __msa_copy_u_h((v8i16) in, idx0); \ + out1_m = __msa_copy_u_h((v8i16) in, idx1); \ + out2_m = __msa_copy_u_h((v8i16) in, idx2); \ + out3_m = __msa_copy_u_h((v8i16) in, idx3); \ + SH(out0_m, (pdst)); \ + SH(out1_m, (pdst) + stride); \ + SH(out2_m, (pdst) + 2 * stride); \ + SH(out3_m, (pdst) + 3 * stride); \ +} +#define ST_H8(in, idx0, idx1, idx2, idx3, idx4, idx5, \ + idx6, idx7, pdst, stride) \ +{ \ + ST_H4(in, idx0, idx1, idx2, idx3, pdst, stride) \ + ST_H4(in, idx4, idx5, idx6, idx7, (pdst) + 4*stride, stride) \ } -/* Description : Store as 4x2 byte block to destination memory from input vector - Arguments : Inputs - in, pdst, stride - Return Type - unsigned byte - Details : Index 0 word element from input vector is copied and stored - on first line - Index 1 word element from input vector is copied and stored - on second line -*/ -#define ST4x2_UB(in, pdst, stride) \ +/* Description : Store word elements of vector with stride + * Arguments : Inputs - in source vector + * - pdst (destination pointer to store to) + * - stride + * Details : Stores word 'idx0' from 'in' to (pdst) + * Stores word 'idx1' from 'in' to (pdst + stride) + * Similar for other elements + */ +#define ST_W1(in, idx, pdst) \ +{ \ + uint32_t out0_m; \ + out0_m = __msa_copy_u_w((v4i32) in, idx); \ + SW(out0_m, (pdst)); \ +} +#define ST_W2(in, idx0, idx1, pdst, stride) \ +{ \ + uint32_t out0_m, out1_m; \ + out0_m = __msa_copy_u_w((v4i32) in, idx0); \ + out1_m = __msa_copy_u_w((v4i32) in, idx1); \ + SW(out0_m, (pdst)); \ + SW(out1_m, (pdst) + stride); \ +} +#define ST_W4(in, idx0, idx1, idx2, idx3, pdst, stride) \ +{ \ + uint32_t out0_m, out1_m, out2_m, out3_m; \ + out0_m = __msa_copy_u_w((v4i32) in, idx0); \ + out1_m = __msa_copy_u_w((v4i32) in, idx1); \ + out2_m = __msa_copy_u_w((v4i32) in, idx2); \ + out3_m = __msa_copy_u_w((v4i32) in, idx3); \ + SW(out0_m, (pdst)); \ + SW(out1_m, (pdst) + stride); \ + SW(out2_m, (pdst) + 2*stride); \ + SW(out3_m, (pdst) + 3*stride); \ +} +#define ST_W8(in0, in1, idx0, idx1, idx2, idx3, \ + idx4, idx5, idx6, idx7, pdst, stride) \ +{ \ + ST_W4(in0, idx0, idx1, idx2, idx3, pdst, stride) \ + ST_W4(in1, idx4, idx5, idx6, idx7, pdst + 4*stride, stride) \ +} + +/* Description : Store double word elements of vector with stride + * Arguments : Inputs - in source vector + * - pdst (destination pointer to store to) + * - stride + * Details : Stores double word 'idx0' from 'in' to (pdst) + * Stores double word 'idx1' from 'in' to (pdst + stride) + * Similar for other elements + */ +#define ST_D1(in, idx, pdst) \ { \ - uint32_t out0_m, out1_m; \ - uint8_t *pblk_4x2_m = (uint8_t *) (pdst); \ - \ - out0_m = __msa_copy_u_w((v4i32) in, 0); \ - out1_m = __msa_copy_u_w((v4i32) in, 1); \ - \ - SW(out0_m, pblk_4x2_m); \ - SW(out1_m, pblk_4x2_m + stride); \ + uint64_t out0_m; \ + out0_m = __msa_copy_u_d((v2i64) in, idx); \ + SD(out0_m, (pdst)); \ } - -/* Description : Store as 4x4 byte block to destination memory from input vector - Arguments : Inputs - in0, in1, pdst, stride - Return Type - unsigned byte - Details : Idx0 word element from input vector 'in0' is copied and stored - on first line - Idx1 word element from input vector 'in0' is copied and stored - on second line - Idx2 word element from input vector 'in1' is copied and stored - on third line - Idx3 word element from input vector 'in1' is copied and stored - on fourth line -*/ -#define ST4x4_UB(in0, in1, idx0, idx1, idx2, idx3, pdst, stride) \ -{ \ - uint32_t out0_m, out1_m, out2_m, out3_m; \ - uint8_t *pblk_4x4_m = (uint8_t *) (pdst); \ - \ - out0_m = __msa_copy_u_w((v4i32) in0, idx0); \ - out1_m = __msa_copy_u_w((v4i32) in0, idx1); \ - out2_m = __msa_copy_u_w((v4i32) in1, idx2); \ - out3_m = __msa_copy_u_w((v4i32) in1, idx3); \ - \ - SW4(out0_m, out1_m, out2_m, out3_m, pblk_4x4_m, stride); \ -} -#define ST4x8_UB(in0, in1, pdst, stride) \ -{ \ - uint8_t *pblk_4x8 = (uint8_t *) (pdst); \ - \ - ST4x4_UB(in0, in0, 0, 1, 2, 3, pblk_4x8, stride); \ - ST4x4_UB(in1, in1, 0, 1, 2, 3, pblk_4x8 + 4 * stride, stride); \ -} - -/* Description : Store as 6x4 byte block to destination memory from input - vectors - Arguments : Inputs - in0, in1, pdst, stride - Return Type - unsigned byte - Details : Index 0 word element from input vector 'in0' is copied and - stored on first line followed by index 2 halfword element - Index 2 word element from input vector 'in0' is copied and - stored on second line followed by index 2 halfword element - Index 0 word element from input vector 'in1' is copied and - stored on third line followed by index 2 halfword element - Index 2 word element from input vector 'in1' is copied and - stored on fourth line followed by index 2 halfword element -*/ -#define ST6x4_UB(in0, in1, pdst, stride) \ -{ \ - uint32_t out0_m, out1_m, out2_m, out3_m; \ - uint16_t out4_m, out5_m, out6_m, out7_m; \ - uint8_t *pblk_6x4_m = (uint8_t *) (pdst); \ - \ - out0_m = __msa_copy_u_w((v4i32) in0, 0); \ - out1_m = __msa_copy_u_w((v4i32) in0, 2); \ - out2_m = __msa_copy_u_w((v4i32) in1, 0); \ - out3_m = __msa_copy_u_w((v4i32) in1, 2); \ - \ - out4_m = __msa_copy_u_h((v8i16) in0, 2); \ - out5_m = __msa_copy_u_h((v8i16) in0, 6); \ - out6_m = __msa_copy_u_h((v8i16) in1, 2); \ - out7_m = __msa_copy_u_h((v8i16) in1, 6); \ - \ - SW(out0_m, pblk_6x4_m); \ - SH(out4_m, (pblk_6x4_m + 4)); \ - pblk_6x4_m += stride; \ - SW(out1_m, pblk_6x4_m); \ - SH(out5_m, (pblk_6x4_m + 4)); \ - pblk_6x4_m += stride; \ - SW(out2_m, pblk_6x4_m); \ - SH(out6_m, (pblk_6x4_m + 4)); \ - pblk_6x4_m += stride; \ - SW(out3_m, pblk_6x4_m); \ - SH(out7_m, (pblk_6x4_m + 4)); \ -} - -/* Description : Store as 8x1 byte block to destination memory from input vector - Arguments : Inputs - in, pdst - Details : Index 0 double word element from input vector 'in' is copied - and stored to destination memory at (pdst) -*/ -#define ST8x1_UB(in, pdst) \ -{ \ - uint64_t out0_m; \ - out0_m = __msa_copy_u_d((v2i64) in, 0); \ - SD(out0_m, pdst); \ -} - -/* Description : Store as 8x2 byte block to destination memory from input vector - Arguments : Inputs - in, pdst, stride - Details : Index 0 double word element from input vector 'in' is copied - and stored to destination memory at (pdst) - Index 1 double word element from input vector 'in' is copied - and stored to destination memory at (pdst + stride) -*/ -#define ST8x2_UB(in, pdst, stride) \ +#define ST_D2(in, idx0, idx1, pdst, stride) \ { \ uint64_t out0_m, out1_m; \ - uint8_t *pblk_8x2_m = (uint8_t *) (pdst); \ - \ - out0_m = __msa_copy_u_d((v2i64) in, 0); \ - out1_m = __msa_copy_u_d((v2i64) in, 1); \ - \ - SD(out0_m, pblk_8x2_m); \ - SD(out1_m, pblk_8x2_m + stride); \ + out0_m = __msa_copy_u_d((v2i64) in, idx0); \ + out1_m = __msa_copy_u_d((v2i64) in, idx1); \ + SD(out0_m, (pdst)); \ + SD(out1_m, (pdst) + stride); \ } - -/* Description : Store as 8x4 byte block to destination memory from input - vectors - Arguments : Inputs - in0, in1, pdst, stride - Details : Index 0 double word element from input vector 'in0' is copied - and stored to destination memory at (pblk_8x4_m) - Index 1 double word element from input vector 'in0' is copied - and stored to destination memory at (pblk_8x4_m + stride) - Index 0 double word element from input vector 'in1' is copied - and stored to destination memory at (pblk_8x4_m + 2 * stride) - Index 1 double word element from input vector 'in1' is copied - and stored to destination memory at (pblk_8x4_m + 3 * stride) -*/ -#define ST8x4_UB(in0, in1, pdst, stride) \ +#define ST_D4(in0, in1, idx0, idx1, idx2, idx3, pdst, stride) \ { \ uint64_t out0_m, out1_m, out2_m, out3_m; \ - uint8_t *pblk_8x4_m = (uint8_t *) (pdst); \ - \ - out0_m = __msa_copy_u_d((v2i64) in0, 0); \ - out1_m = __msa_copy_u_d((v2i64) in0, 1); \ - out2_m = __msa_copy_u_d((v2i64) in1, 0); \ - out3_m = __msa_copy_u_d((v2i64) in1, 1); \ - \ - SD4(out0_m, out1_m, out2_m, out3_m, pblk_8x4_m, stride); \ + out0_m = __msa_copy_u_d((v2i64) in0, idx0); \ + out1_m = __msa_copy_u_d((v2i64) in0, idx1); \ + out2_m = __msa_copy_u_d((v2i64) in1, idx2); \ + out3_m = __msa_copy_u_d((v2i64) in1, idx3); \ + SD(out0_m, (pdst)); \ + SD(out1_m, (pdst) + stride); \ + SD(out2_m, (pdst) + 2 * stride); \ + SD(out3_m, (pdst) + 3 * stride); \ } -#define ST8x8_UB(in0, in1, in2, in3, pdst, stride) \ -{ \ - uint8_t *pblk_8x8_m = (uint8_t *) (pdst); \ - \ - ST8x4_UB(in0, in1, pblk_8x8_m, stride); \ - ST8x4_UB(in2, in3, pblk_8x8_m + 4 * stride, stride); \ -} -#define ST12x4_UB(in0, in1, in2, pdst, stride) \ -{ \ - uint8_t *pblk_12x4_m = (uint8_t *) (pdst); \ - \ - /* left 8x4 */ \ - ST8x4_UB(in0, in1, pblk_12x4_m, stride); \ - /* right 4x4 */ \ - ST4x4_UB(in2, in2, 0, 1, 2, 3, pblk_12x4_m + 8, stride); \ +#define ST_D8(in0, in1, in2, in3, idx0, idx1, idx2, idx3, \ + idx4, idx5, idx6, idx7, pdst, stride) \ +{ \ + ST_D4(in0, in1, idx0, idx1, idx2, idx3, pdst, stride) \ + ST_D4(in2, in3, idx4, idx5, idx6, idx7, pdst + 4 * stride, stride) \ } /* Description : Store as 12x8 byte block to destination memory from @@ -1234,6 +1155,15 @@ unsigned absolute diff values, even-odd pairs are added together to generate 8 halfword results. */ +#if HAVE_MSA2 +#define SAD_UB2_UH(in0, in1, ref0, ref1) \ +( { \ + v8u16 sad_m = { 0 }; \ + sad_m += __builtin_msa2_sad_adj2_u_w2x_b((v16u8) in0, (v16u8) ref0); \ + sad_m += __builtin_msa2_sad_adj2_u_w2x_b((v16u8) in1, (v16u8) ref1); \ + sad_m; \ +} ) +#else #define SAD_UB2_UH(in0, in1, ref0, ref1) \ ( { \ v16u8 diff0_m, diff1_m; \ @@ -1247,6 +1177,7 @@ \ sad_m; \ } ) +#endif // #if HAVE_MSA2 /* Description : Insert specified word elements from input vectors to 1 destination vector @@ -2287,6 +2218,12 @@ extracted and interleaved with same vector 'in0' to generate 4 word elements keeping sign intact */ +#if HAVE_MSA2 +#define UNPCK_R_SH_SW(in, out) \ +{ \ + out = (v4i32) __builtin_msa2_w2x_lo_s_h((v8i16) in); \ +} +#else #define UNPCK_R_SH_SW(in, out) \ { \ v8i16 sign_m; \ @@ -2294,6 +2231,7 @@ sign_m = __msa_clti_s_h((v8i16) in, 0); \ out = (v4i32) __msa_ilvr_h(sign_m, (v8i16) in); \ } +#endif // #if HAVE_MSA2 /* Description : Sign extend byte elements from input vector and return halfword results in pair of vectors @@ -2306,6 +2244,13 @@ Then interleaved left with same vector 'in0' to generate 8 signed halfword elements in 'out1' */ +#if HAVE_MSA2 +#define UNPCK_SB_SH(in, out0, out1) \ +{ \ + out0 = (v4i32) __builtin_msa2_w2x_lo_s_b((v16i8) in); \ + out1 = (v4i32) __builtin_msa2_w2x_hi_s_b((v16i8) in); \ +} +#else #define UNPCK_SB_SH(in, out0, out1) \ { \ v16i8 tmp_m; \ @@ -2313,6 +2258,7 @@ tmp_m = __msa_clti_s_b((v16i8) in, 0); \ ILVRL_B2_SH(tmp_m, in, out0, out1); \ } +#endif // #if HAVE_MSA2 /* Description : Zero extend unsigned byte elements to halfword elements Arguments : Inputs - in (1 input unsigned byte vector) @@ -2339,6 +2285,13 @@ Then interleaved left with same vector 'in0' to generate 4 signed word elements in 'out1' */ +#if HAVE_MSA2 +#define UNPCK_SH_SW(in, out0, out1) \ +{ \ + out0 = (v4i32) __builtin_msa2_w2x_lo_s_h((v8i16) in); \ + out1 = (v4i32) __builtin_msa2_w2x_hi_s_h((v8i16) in); \ +} +#else #define UNPCK_SH_SW(in, out0, out1) \ { \ v8i16 tmp_m; \ @@ -2346,6 +2299,7 @@ tmp_m = __msa_clti_s_h((v8i16) in, 0); \ ILVRL_H2_SW(tmp_m, in, out0, out1); \ } +#endif // #if HAVE_MSA2 /* Description : Swap two variables Arguments : Inputs - in0, in1 @@ -2850,13 +2804,11 @@ */ #define DPADD_SH3_SH(in0, in1, in2, coeff0, coeff1, coeff2) \ ( { \ - v8i16 tmp1_m; \ v8i16 out0_m; \ \ out0_m = __msa_dotp_s_h((v16i8) in0, (v16i8) coeff0); \ out0_m = __msa_dpadd_s_h(out0_m, (v16i8) in1, (v16i8) coeff1); \ - tmp1_m = __msa_dotp_s_h((v16i8) in2, (v16i8) coeff2); \ - out0_m = __msa_adds_s_h(out0_m, tmp1_m); \ + out0_m = __msa_dpadd_s_h(out0_m, (v16i8) in2, (v16i8) coeff2); \ \ out0_m; \ } ) @@ -2890,7 +2842,7 @@ tmp0_m = PCKEV_XORI128_UB(in0, in1); \ tmp1_m = PCKEV_XORI128_UB(in2, in3); \ AVER_UB2_UB(tmp0_m, dst0, tmp1_m, dst1, tmp0_m, tmp1_m); \ - ST8x4_UB(tmp0_m, tmp1_m, pdst_m, stride); \ + ST_D4(tmp0_m, tmp1_m, 0, 1, 0, 1, pdst_m, stride); \ } /* Description : Pack even byte elements, extract 0 & 2 index words from pair diff --git a/libavutil/mips/mmiutils.h b/libavutil/mips/mmiutils.h index 491579ec6..05f6b3115 100644 --- a/libavutil/mips/mmiutils.h +++ b/libavutil/mips/mmiutils.h @@ -201,41 +201,164 @@ #endif /* HAVE_LOONGSON2 */ -#define TRANSPOSE_4H(m1, m2, m3, m4, t1, t2, t3, t4, t5, r1, zero, shift) \ - "li "#r1", 0x93 \n\t" \ - "xor "#zero","#zero","#zero" \n\t" \ - "mtc1 "#r1", "#shift" \n\t" \ - "punpcklhw "#t1", "#m1", "#zero" \n\t" \ - "punpcklhw "#t5", "#m2", "#zero" \n\t" \ - "pshufh "#t5", "#t5", "#shift" \n\t" \ - "or "#t1", "#t1", "#t5" \n\t" \ - "punpckhhw "#t2", "#m1", "#zero" \n\t" \ - "punpckhhw "#t5", "#m2", "#zero" \n\t" \ - "pshufh "#t5", "#t5", "#shift" \n\t" \ - "or "#t2", "#t2", "#t5" \n\t" \ - "punpcklhw "#t3", "#m3", "#zero" \n\t" \ - "punpcklhw "#t5", "#m4", "#zero" \n\t" \ - "pshufh "#t5", "#t5", "#shift" \n\t" \ - "or "#t3", "#t3", "#t5" \n\t" \ - "punpckhhw "#t4", "#m3", "#zero" \n\t" \ - "punpckhhw "#t5", "#m4", "#zero" \n\t" \ - "pshufh "#t5", "#t5", "#shift" \n\t" \ - "or "#t4", "#t4", "#t5" \n\t" \ - "punpcklwd "#m1", "#t1", "#t3" \n\t" \ - "punpckhwd "#m2", "#t1", "#t3" \n\t" \ - "punpcklwd "#m3", "#t2", "#t4" \n\t" \ - "punpckhwd "#m4", "#t2", "#t4" \n\t" +/** + * backup register + */ +#define BACKUP_REG \ + double temp_backup_reg[8]; \ + if (_MIPS_SIM == _ABI64) \ + __asm__ volatile ( \ + "gssqc1 $f25, $f24, 0x00(%[temp]) \n\t" \ + "gssqc1 $f27, $f26, 0x10(%[temp]) \n\t" \ + "gssqc1 $f29, $f28, 0x20(%[temp]) \n\t" \ + "gssqc1 $f31, $f30, 0x30(%[temp]) \n\t" \ + : \ + : [temp]"r"(temp_backup_reg) \ + : "memory" \ + ); \ + else \ + __asm__ volatile ( \ + "gssqc1 $f22, $f20, 0x00(%[temp]) \n\t" \ + "gssqc1 $f26, $f24, 0x10(%[temp]) \n\t" \ + "gssqc1 $f30, $f28, 0x20(%[temp]) \n\t" \ + : \ + : [temp]"r"(temp_backup_reg) \ + : "memory" \ + ); +/** + * recover register + */ +#define RECOVER_REG \ + if (_MIPS_SIM == _ABI64) \ + __asm__ volatile ( \ + "gslqc1 $f25, $f24, 0x00(%[temp]) \n\t" \ + "gslqc1 $f27, $f26, 0x10(%[temp]) \n\t" \ + "gslqc1 $f29, $f28, 0x20(%[temp]) \n\t" \ + "gslqc1 $f31, $f30, 0x30(%[temp]) \n\t" \ + : \ + : [temp]"r"(temp_backup_reg) \ + : "memory" \ + ); \ + else \ + __asm__ volatile ( \ + "gslqc1 $f22, $f20, 0x00(%[temp]) \n\t" \ + "gslqc1 $f26, $f24, 0x10(%[temp]) \n\t" \ + "gslqc1 $f30, $f28, 0x20(%[temp]) \n\t" \ + : \ + : [temp]"r"(temp_backup_reg) \ + : "memory" \ + ); -#define PSRAH_4_MMI(fp1, fp2, fp3, fp4, shift) \ - "psrah "#fp1", "#fp1", "#shift" \n\t" \ - "psrah "#fp2", "#fp2", "#shift" \n\t" \ - "psrah "#fp3", "#fp3", "#shift" \n\t" \ +/** + * brief: Transpose 2X2 word packaged data. + * fr_i0, fr_i1: src + * fr_o0, fr_o1: dst + */ +#define TRANSPOSE_2W(fr_i0, fr_i1, fr_o0, fr_o1) \ + "punpcklwd "#fr_o0", "#fr_i0", "#fr_i1" \n\t" \ + "punpckhwd "#fr_o1", "#fr_i0", "#fr_i1" \n\t" + +/** + * brief: Transpose 4X4 half word packaged data. + * fr_i0, fr_i1, fr_i2, fr_i3: src & dst + * fr_t0, fr_t1, fr_t2, fr_t3: temporary register + */ +#define TRANSPOSE_4H(fr_i0, fr_i1, fr_i2, fr_i3, \ + fr_t0, fr_t1, fr_t2, fr_t3) \ + "punpcklhw "#fr_t0", "#fr_i0", "#fr_i1" \n\t" \ + "punpckhhw "#fr_t1", "#fr_i0", "#fr_i1" \n\t" \ + "punpcklhw "#fr_t2", "#fr_i2", "#fr_i3" \n\t" \ + "punpckhhw "#fr_t3", "#fr_i2", "#fr_i3" \n\t" \ + "punpcklwd "#fr_i0", "#fr_t0", "#fr_t2" \n\t" \ + "punpckhwd "#fr_i1", "#fr_t0", "#fr_t2" \n\t" \ + "punpcklwd "#fr_i2", "#fr_t1", "#fr_t3" \n\t" \ + "punpckhwd "#fr_i3", "#fr_t1", "#fr_t3" \n\t" + +/** + * brief: Transpose 8x8 byte packaged data. + * fr_i0~i7: src & dst + * fr_t0~t3: temporary register + */ +#define TRANSPOSE_8B(fr_i0, fr_i1, fr_i2, fr_i3, fr_i4, fr_i5, \ + fr_i6, fr_i7, fr_t0, fr_t1, fr_t2, fr_t3) \ + "punpcklbh "#fr_t0", "#fr_i0", "#fr_i1" \n\t" \ + "punpckhbh "#fr_t1", "#fr_i0", "#fr_i1" \n\t" \ + "punpcklbh "#fr_t2", "#fr_i2", "#fr_i3" \n\t" \ + "punpckhbh "#fr_t3", "#fr_i2", "#fr_i3" \n\t" \ + "punpcklbh "#fr_i0", "#fr_i4", "#fr_i5" \n\t" \ + "punpckhbh "#fr_i1", "#fr_i4", "#fr_i5" \n\t" \ + "punpcklbh "#fr_i2", "#fr_i6", "#fr_i7" \n\t" \ + "punpckhbh "#fr_i3", "#fr_i6", "#fr_i7" \n\t" \ + "punpcklhw "#fr_i4", "#fr_t0", "#fr_t2" \n\t" \ + "punpckhhw "#fr_i5", "#fr_t0", "#fr_t2" \n\t" \ + "punpcklhw "#fr_i6", "#fr_t1", "#fr_t3" \n\t" \ + "punpckhhw "#fr_i7", "#fr_t1", "#fr_t3" \n\t" \ + "punpcklhw "#fr_t0", "#fr_i0", "#fr_i2" \n\t" \ + "punpckhhw "#fr_t1", "#fr_i0", "#fr_i2" \n\t" \ + "punpcklhw "#fr_t2", "#fr_i1", "#fr_i3" \n\t" \ + "punpckhhw "#fr_t3", "#fr_i1", "#fr_i3" \n\t" \ + "punpcklwd "#fr_i0", "#fr_i4", "#fr_t0" \n\t" \ + "punpckhwd "#fr_i1", "#fr_i4", "#fr_t0" \n\t" \ + "punpcklwd "#fr_i2", "#fr_i5", "#fr_t1" \n\t" \ + "punpckhwd "#fr_i3", "#fr_i5", "#fr_t1" \n\t" \ + "punpcklwd "#fr_i4", "#fr_i6", "#fr_t2" \n\t" \ + "punpckhwd "#fr_i5", "#fr_i6", "#fr_t2" \n\t" \ + "punpcklwd "#fr_i6", "#fr_i7", "#fr_t3" \n\t" \ + "punpckhwd "#fr_i7", "#fr_i7", "#fr_t3" \n\t" + +/** + * brief: Parallel SRA for 8 byte packaged data. + * fr_i0: src + * fr_i1: SRA number(SRAB number + 8) + * fr_t0, fr_t1: temporary register + * fr_d0: dst + */ +#define PSRAB_MMI(fr_i0, fr_i1, fr_t0, fr_t1, fr_d0) \ + "punpcklbh "#fr_t0", "#fr_t0", "#fr_i0" \n\t" \ + "punpckhbh "#fr_t1", "#fr_t1", "#fr_i0" \n\t" \ + "psrah "#fr_t0", "#fr_t0", "#fr_i1" \n\t" \ + "psrah "#fr_t1", "#fr_t1", "#fr_i1" \n\t" \ + "packsshb "#fr_d0", "#fr_t0", "#fr_t1" \n\t" + +/** + * brief: Parallel SRL for 8 byte packaged data. + * fr_i0: src + * fr_i1: SRL number(SRLB number + 8) + * fr_t0, fr_t1: temporary register + * fr_d0: dst + */ +#define PSRLB_MMI(fr_i0, fr_i1, fr_t0, fr_t1, fr_d0) \ + "punpcklbh "#fr_t0", "#fr_t0", "#fr_i0" \n\t" \ + "punpckhbh "#fr_t1", "#fr_t1", "#fr_i0" \n\t" \ + "psrlh "#fr_t0", "#fr_t0", "#fr_i1" \n\t" \ + "psrlh "#fr_t1", "#fr_t1", "#fr_i1" \n\t" \ + "packsshb "#fr_d0", "#fr_t0", "#fr_t1" \n\t" + +#define PSRAH_4_MMI(fp1, fp2, fp3, fp4, shift) \ + "psrah "#fp1", "#fp1", "#shift" \n\t" \ + "psrah "#fp2", "#fp2", "#shift" \n\t" \ + "psrah "#fp3", "#fp3", "#shift" \n\t" \ "psrah "#fp4", "#fp4", "#shift" \n\t" -#define PSRAH_8_MMI(fp1, fp2, fp3, fp4, fp5, fp6, fp7, fp8, shift) \ - PSRAH_4_MMI(fp1, fp2, fp3, fp4, shift) \ +#define PSRAH_8_MMI(fp1, fp2, fp3, fp4, fp5, fp6, fp7, fp8, shift) \ + PSRAH_4_MMI(fp1, fp2, fp3, fp4, shift) \ PSRAH_4_MMI(fp5, fp6, fp7, fp8, shift) +/** + * brief: (((value) + (1 << ((n) - 1))) >> (n)) + * fr_i0: src & dst + * fr_i1: Operand number + * fr_t0, fr_t1: temporary FPR + * gr_t0: temporary GPR + */ +#define ROUND_POWER_OF_TWO_MMI(fr_i0, fr_i1, fr_t0, fr_t1, gr_t0) \ + "li "#gr_t0", 0x01 \n\t" \ + "dmtc1 "#gr_t0", "#fr_t0" \n\t" \ + "punpcklwd "#fr_t0", "#fr_t0", "#fr_t0" \n\t" \ + "psubw "#fr_t1", "#fr_i1", "#fr_t0" \n\t" \ + "psllw "#fr_t1", "#fr_t0", "#fr_t1" \n\t" \ + "paddw "#fr_i0", "#fr_i0", "#fr_t1" \n\t" \ + "psraw "#fr_i0", "#fr_i0", "#fr_i1" \n\t" #endif /* AVUTILS_MIPS_MMIUTILS_H */ diff --git a/libavutil/opt.c b/libavutil/opt.c index 3b0aab4ee..93d6c26c1 100644 --- a/libavutil/opt.c +++ b/libavutil/opt.c @@ -463,6 +463,9 @@ int av_opt_set(void *obj, const char *name, const char *val, int search_flags) if (o->flags & AV_OPT_FLAG_READONLY) return AVERROR(EINVAL); + if (o->flags & AV_OPT_FLAG_DEPRECATED) + av_log(obj, AV_LOG_WARNING, "The \"%s\" option is deprecated: %s\n", name, o->help); + dst = ((uint8_t *)target_obj) + o->offset; switch (o->type) { case AV_OPT_TYPE_BOOL: @@ -493,15 +496,22 @@ int av_opt_set(void *obj, const char *name, const char *val, int search_flags) case AV_OPT_TYPE_SAMPLE_FMT: return set_string_sample_fmt(obj, o, val, dst); case AV_OPT_TYPE_DURATION: - if (!val) { - *(int64_t *)dst = 0; + { + int64_t usecs = 0; + if (val) { + if ((ret = av_parse_time(&usecs, val, 1)) < 0) { + av_log(obj, AV_LOG_ERROR, "Unable to parse option value \"%s\" as duration\n", val); + return ret; + } + } + if (usecs < o->min || usecs > o->max) { + av_log(obj, AV_LOG_ERROR, "Value %f for parameter '%s' out of range [%g - %g]\n", + usecs / 1000000.0, o->name, o->min / 1000000.0, o->max / 1000000.0); + return AVERROR(ERANGE); + } + *(int64_t *)dst = usecs; return 0; - } else { - if ((ret = av_parse_time(dst, val, 1)) < 0) - av_log(obj, AV_LOG_ERROR, "Unable to parse option value \"%s\" as duration\n", val); - return ret; } - break; case AV_OPT_TYPE_COLOR: return set_string_color(obj, o, val, dst); case AV_OPT_TYPE_CHANNEL_LAYOUT: @@ -759,6 +769,9 @@ int av_opt_get(void *obj, const char *name, int search_flags, uint8_t **out_val) if (!o || !target_obj || (o->offset<=0 && o->type != AV_OPT_TYPE_CONST)) return AVERROR_OPTION_NOT_FOUND; + if (o->flags & AV_OPT_FLAG_DEPRECATED) + av_log(obj, AV_LOG_WARNING, "The \"%s\" option is deprecated: %s\n", name, o->help); + dst = (uint8_t *)target_obj + o->offset; buf[0] = 0; diff --git a/libavutil/opt.h b/libavutil/opt.h index 07da68ea2..39f4a8dda 100644 --- a/libavutil/opt.h +++ b/libavutil/opt.h @@ -289,6 +289,7 @@ typedef struct AVOption { #define AV_OPT_FLAG_READONLY 128 #define AV_OPT_FLAG_BSF_PARAM (1<<8) ///< a generic parameter which can be set by the user for bit stream filtering #define AV_OPT_FLAG_FILTERING_PARAM (1<<16) ///< a generic parameter which can be set by the user for filtering +#define AV_OPT_FLAG_DEPRECATED (1<<17) ///< set if option is deprecated, users should refer to AVOption.help text for more information //FIXME think about enc-audio, ... style flags /** diff --git a/libavutil/parseutils.c b/libavutil/parseutils.c index 924c49d52..167e82264 100644 --- a/libavutil/parseutils.c +++ b/libavutil/parseutils.c @@ -504,7 +504,7 @@ char *av_small_strptime(const char *p, const char *fmt, struct tm *dt) switch(c) { case 'H': case 'J': - val = date_get_num(&p, 0, c == 'H' ? 23 : INT_MAX, 2); + val = date_get_num(&p, 0, c == 'H' ? 23 : INT_MAX, c == 'H' ? 2 : 4); if (val == -1) return NULL; @@ -661,12 +661,15 @@ int av_parse_time(int64_t *timeval, const char *timestr, int duration) if (!q) { char *o; /* parse timestr as S+ */ - dt.tm_sec = strtol(p, &o, 10); + errno = 0; + t = strtoll(p, &o, 10); if (o == p) /* the parsing didn't succeed */ return AVERROR(EINVAL); - dt.tm_min = 0; - dt.tm_hour = 0; + if (errno == ERANGE) + return AVERROR(ERANGE); q = o; + } else { + t = dt.tm_hour * 3600 + dt.tm_min * 60 + dt.tm_sec; } } @@ -688,7 +691,6 @@ int av_parse_time(int64_t *timeval, const char *timestr, int duration) } if (duration) { - t = dt.tm_hour * 3600 + dt.tm_min * 60 + dt.tm_sec; if (q[0] == 'm' && q[1] == 's') { suffix = 1000; microseconds /= 1000; @@ -734,7 +736,11 @@ int av_parse_time(int64_t *timeval, const char *timestr, int duration) if (*q) return AVERROR(EINVAL); + if (INT64_MAX / suffix < t) + return AVERROR(ERANGE); t *= suffix; + if (INT64_MAX - microseconds < t) + return AVERROR(ERANGE); t += microseconds; *timeval = negative ? -t : t; return 0; diff --git a/libavutil/pixdesc.c b/libavutil/pixdesc.c index 8ed52751c..b97b0665b 100644 --- a/libavutil/pixdesc.c +++ b/libavutil/pixdesc.c @@ -31,19 +31,22 @@ #include "intreadwrite.h" #include "version.h" -void av_read_image_line(uint16_t *dst, +void av_read_image_line2(void *dst, const uint8_t *data[4], const int linesize[4], const AVPixFmtDescriptor *desc, int x, int y, int c, int w, - int read_pal_component) + int read_pal_component, + int dst_element_size) { AVComponentDescriptor comp = desc->comp[c]; int plane = comp.plane; int depth = comp.depth; - int mask = (1 << depth) - 1; + unsigned mask = (1ULL << depth) - 1; int shift = comp.shift; int step = comp.step; int flags = desc->flags; + uint16_t *dst16 = dst; + uint32_t *dst32 = dst; if (flags & AV_PIX_FMT_FLAG_BITSTREAM) { int skip = x * step + comp.offset; @@ -57,38 +60,56 @@ void av_read_image_line(uint16_t *dst, shift -= step; p -= shift >> 3; shift &= 7; - *dst++ = val; + if (dst_element_size == 4) *dst32++ = val; + else *dst16++ = val; } } else { const uint8_t *p = data[plane] + y * linesize[plane] + x * step + comp.offset; int is_8bit = shift + depth <= 8; + int is_16bit= shift + depth <=16; if (is_8bit) p += !!(flags & AV_PIX_FMT_FLAG_BE); while (w--) { - int val = is_8bit ? *p : - flags & AV_PIX_FMT_FLAG_BE ? AV_RB16(p) : AV_RL16(p); + unsigned val; + if (is_8bit) val = *p; + else if(is_16bit) val = flags & AV_PIX_FMT_FLAG_BE ? AV_RB16(p) : AV_RL16(p); + else val = flags & AV_PIX_FMT_FLAG_BE ? AV_RB32(p) : AV_RL32(p); val = (val >> shift) & mask; if (read_pal_component) val = data[1][4 * val + c]; p += step; - *dst++ = val; + if (dst_element_size == 4) *dst32++ = val; + else *dst16++ = val; } } } -void av_write_image_line(const uint16_t *src, +void av_read_image_line(uint16_t *dst, + const uint8_t *data[4], const int linesize[4], + const AVPixFmtDescriptor *desc, + int x, int y, int c, int w, + int read_pal_component) +{ + av_read_image_line2(dst, data, linesize, desc,x, y, c, w, + read_pal_component, + 2); +} + +void av_write_image_line2(const void *src, uint8_t *data[4], const int linesize[4], const AVPixFmtDescriptor *desc, - int x, int y, int c, int w) + int x, int y, int c, int w, int src_element_size) { AVComponentDescriptor comp = desc->comp[c]; int plane = comp.plane; int depth = comp.depth; int step = comp.step; int flags = desc->flags; + const uint32_t *src32 = src; + const uint16_t *src16 = src; if (flags & AV_PIX_FMT_FLAG_BITSTREAM) { int skip = x * step + comp.offset; @@ -96,7 +117,7 @@ void av_write_image_line(const uint16_t *src, int shift = 8 - depth - (skip & 7); while (w--) { - *p |= *src++ << shift; + *p |= (src_element_size == 4 ? *src32++ : *src16++) << shift; shift -= step; p -= shift >> 3; shift &= 7; @@ -109,17 +130,28 @@ void av_write_image_line(const uint16_t *src, if (shift + depth <= 8) { p += !!(flags & AV_PIX_FMT_FLAG_BE); while (w--) { - *p |= (*src++ << shift); + *p |= ((src_element_size == 4 ? *src32++ : *src16++) << shift); p += step; } } else { while (w--) { - if (flags & AV_PIX_FMT_FLAG_BE) { - uint16_t val = AV_RB16(p) | (*src++ << shift); - AV_WB16(p, val); + unsigned s = (src_element_size == 4 ? *src32++ : *src16++); + if (shift + depth <= 16) { + if (flags & AV_PIX_FMT_FLAG_BE) { + uint16_t val = AV_RB16(p) | (s << shift); + AV_WB16(p, val); + } else { + uint16_t val = AV_RL16(p) | (s << shift); + AV_WL16(p, val); + } } else { - uint16_t val = AV_RL16(p) | (*src++ << shift); - AV_WL16(p, val); + if (flags & AV_PIX_FMT_FLAG_BE) { + uint32_t val = AV_RB32(p) | (s << shift); + AV_WB32(p, val); + } else { + uint32_t val = AV_RL32(p) | (s << shift); + AV_WL32(p, val); + } } p += step; } @@ -127,6 +159,14 @@ void av_write_image_line(const uint16_t *src, } } +void av_write_image_line(const uint16_t *src, + uint8_t *data[4], const int linesize[4], + const AVPixFmtDescriptor *desc, + int x, int y, int c, int w) +{ + av_write_image_line2(src, data, linesize, desc, x, y, c, w, 2); +} + #if FF_API_PLUS1_MINUS1 FF_DISABLE_DEPRECATION_WARNINGS #endif @@ -288,7 +328,7 @@ static const AVPixFmtDescriptor av_pix_fmt_descriptors[AV_PIX_FMT_NB] = { .comp = { { 0, 1, 0, 0, 8, 0, 7, 1 }, }, - .flags = AV_PIX_FMT_FLAG_PAL, + .flags = AV_PIX_FMT_FLAG_PAL | AV_PIX_FMT_FLAG_ALPHA, }, [AV_PIX_FMT_YUVJ420P] = { .name = "yuvj420p", @@ -611,6 +651,27 @@ static const AVPixFmtDescriptor av_pix_fmt_descriptors[AV_PIX_FMT_NB] = { }, .alias = "y12le", }, + [AV_PIX_FMT_GRAY14BE] = { + .name = "gray14be", + .nb_components = 1, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 14, 1, 13, 1 }, /* Y */ + }, + .flags = AV_PIX_FMT_FLAG_BE, + .alias = "y14be", + }, + [AV_PIX_FMT_GRAY14LE] = { + .name = "gray14le", + .nb_components = 1, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 14, 1, 13, 1 }, /* Y */ + }, + .alias = "y14le", + }, [AV_PIX_FMT_GRAY16BE] = { .name = "gray16be", .nb_components = 1, @@ -2185,6 +2246,104 @@ static const AVPixFmtDescriptor av_pix_fmt_descriptors[AV_PIX_FMT_NB] = { .name = "opencl", .flags = AV_PIX_FMT_FLAG_HWACCEL, }, + [AV_PIX_FMT_GRAYF32BE] = { + .name = "grayf32be", + .nb_components = 1, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 4, 0, 0, 32, 3, 31, 1 }, /* Y */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_FLOAT, + .alias = "yf32be", + }, + [AV_PIX_FMT_GRAYF32LE] = { + .name = "grayf32le", + .nb_components = 1, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 4, 0, 0, 32, 3, 31, 1 }, /* Y */ + }, + .flags = AV_PIX_FMT_FLAG_FLOAT, + .alias = "yf32le", + }, + [AV_PIX_FMT_YUVA422P12BE] = { + .name = "yuva422p12be", + .nb_components = 4, + .log2_chroma_w = 1, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 12, 1, 11, 1 }, /* Y */ + { 1, 2, 0, 0, 12, 1, 11, 1 }, /* U */ + { 2, 2, 0, 0, 12, 1, 11, 1 }, /* V */ + { 3, 2, 0, 0, 12, 1, 11, 1 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_ALPHA, + }, + [AV_PIX_FMT_YUVA422P12LE] = { + .name = "yuva422p12le", + .nb_components = 4, + .log2_chroma_w = 1, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 12, 1, 11, 1 }, /* Y */ + { 1, 2, 0, 0, 12, 1, 11, 1 }, /* U */ + { 2, 2, 0, 0, 12, 1, 11, 1 }, /* V */ + { 3, 2, 0, 0, 12, 1, 11, 1 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_ALPHA, + }, + [AV_PIX_FMT_YUVA444P12BE] = { + .name = "yuva444p12be", + .nb_components = 4, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 12, 1, 11, 1 }, /* Y */ + { 1, 2, 0, 0, 12, 1, 11, 1 }, /* U */ + { 2, 2, 0, 0, 12, 1, 11, 1 }, /* V */ + { 3, 2, 0, 0, 12, 1, 11, 1 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_BE | AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_ALPHA, + }, + [AV_PIX_FMT_YUVA444P12LE] = { + .name = "yuva444p12le", + .nb_components = 4, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 2, 0, 0, 12, 1, 11, 1 }, /* Y */ + { 1, 2, 0, 0, 12, 1, 11, 1 }, /* U */ + { 2, 2, 0, 0, 12, 1, 11, 1 }, /* V */ + { 3, 2, 0, 0, 12, 1, 11, 1 }, /* A */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_ALPHA, + }, + [AV_PIX_FMT_NV24] = { + .name = "nv24", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 1, 0, 0, 8, 0, 7, 1 }, /* Y */ + { 1, 2, 0, 0, 8, 1, 7, 1 }, /* U */ + { 1, 2, 1, 0, 8, 1, 7, 2 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR, + }, + [AV_PIX_FMT_NV42] = { + .name = "nv42", + .nb_components = 3, + .log2_chroma_w = 0, + .log2_chroma_h = 0, + .comp = { + { 0, 1, 0, 0, 8, 0, 7, 1 }, /* Y */ + { 1, 2, 1, 0, 8, 1, 7, 2 }, /* U */ + { 1, 2, 0, 0, 8, 1, 7, 1 }, /* V */ + }, + .flags = AV_PIX_FMT_FLAG_PLANAR, + }, }; #if FF_API_PLUS1_MINUS1 FF_ENABLE_DEPRECATION_WARNINGS @@ -2432,7 +2591,6 @@ void ff_check_pixfmt_descriptors(void){ av_assert0(d->log2_chroma_h <= 3); av_assert0(d->nb_components <= 4); av_assert0(d->name && d->name[0]); - av_assert0((d->nb_components==4 || d->nb_components==2) == !!(d->flags & AV_PIX_FMT_FLAG_ALPHA)); av_assert2(av_get_pix_fmt(d->name) == i); for (j=0; jcomp); j++) { @@ -2483,7 +2641,7 @@ enum AVPixelFormat av_pix_fmt_swap_endianness(enum AVPixelFormat pix_fmt) #define FF_COLOR_XYZ 4 #define pixdesc_has_alpha(pixdesc) \ - ((pixdesc)->nb_components == 2 || (pixdesc)->nb_components == 4 || (pixdesc)->flags & AV_PIX_FMT_FLAG_PAL) + ((pixdesc)->flags & AV_PIX_FMT_FLAG_ALPHA) static int get_color_type(const AVPixFmtDescriptor *desc) { @@ -2717,7 +2875,12 @@ int av_color_primaries_from_name(const char *name) int i; for (i = 0; i < FF_ARRAY_ELEMS(color_primaries_names); i++) { - size_t len = strlen(color_primaries_names[i]); + size_t len; + + if (!color_primaries_names[i]) + continue; + + len = strlen(color_primaries_names[i]); if (!strncmp(color_primaries_names[i], name, len)) return i; } @@ -2736,7 +2899,12 @@ int av_color_transfer_from_name(const char *name) int i; for (i = 0; i < FF_ARRAY_ELEMS(color_transfer_names); i++) { - size_t len = strlen(color_transfer_names[i]); + size_t len; + + if (!color_transfer_names[i]) + continue; + + len = strlen(color_transfer_names[i]); if (!strncmp(color_transfer_names[i], name, len)) return i; } @@ -2755,7 +2923,12 @@ int av_color_space_from_name(const char *name) int i; for (i = 0; i < FF_ARRAY_ELEMS(color_space_names); i++) { - size_t len = strlen(color_space_names[i]); + size_t len; + + if (!color_space_names[i]) + continue; + + len = strlen(color_space_names[i]); if (!strncmp(color_space_names[i], name, len)) return i; } @@ -2774,7 +2947,12 @@ int av_chroma_location_from_name(const char *name) int i; for (i = 0; i < FF_ARRAY_ELEMS(chroma_location_names); i++) { - size_t len = strlen(chroma_location_names[i]); + size_t len; + + if (!chroma_location_names[i]) + continue; + + len = strlen(chroma_location_names[i]); if (!strncmp(chroma_location_names[i], name, len)) return i; } diff --git a/libavutil/pixdesc.h b/libavutil/pixdesc.h index 1ab372782..c055810ae 100644 --- a/libavutil/pixdesc.h +++ b/libavutil/pixdesc.h @@ -167,12 +167,8 @@ typedef struct AVPixFmtDescriptor { /** * The pixel format has an alpha channel. This is set on all formats that - * support alpha in some way. The exception is AV_PIX_FMT_PAL8, which can - * carry alpha as part of the palette. Details are explained in the - * AVPixelFormat enum, and are also encoded in the corresponding - * AVPixFmtDescriptor. - * - * The alpha is always straight, never pre-multiplied. + * support alpha in some way, including AV_PIX_FMT_PAL8. The alpha is always + * straight, never pre-multiplied. * * If a codec or a filter does not support alpha, it should set all alpha to * opaque, or use the equivalent pixel formats without alpha component, e.g. @@ -347,7 +343,13 @@ char *av_get_pix_fmt_string(char *buf, int buf_size, * format writes the values corresponding to the palette * component c in data[1] to dst, rather than the palette indexes in * data[0]. The behavior is undefined if the format is not paletted. + * @param dst_element_size size of elements in dst array (2 or 4 byte) */ +void av_read_image_line2(void *dst, const uint8_t *data[4], + const int linesize[4], const AVPixFmtDescriptor *desc, + int x, int y, int c, int w, int read_pal_component, + int dst_element_size); + void av_read_image_line(uint16_t *dst, const uint8_t *data[4], const int linesize[4], const AVPixFmtDescriptor *desc, int x, int y, int c, int w, int read_pal_component); @@ -365,7 +367,12 @@ void av_read_image_line(uint16_t *dst, const uint8_t *data[4], * @param y the vertical coordinate of the first pixel to write * @param w the width of the line to write, that is the number of * values to write to the image line + * @param src_element_size size of elements in src array (2 or 4 byte) */ +void av_write_image_line2(const void *src, uint8_t *data[4], + const int linesize[4], const AVPixFmtDescriptor *desc, + int x, int y, int c, int w, int src_element_size); + void av_write_image_line(const uint16_t *src, uint8_t *data[4], const int linesize[4], const AVPixFmtDescriptor *desc, int x, int y, int c, int w); diff --git a/libavutil/pixelutils.c b/libavutil/pixelutils.c index b663027b4..ebee3d6f9 100644 --- a/libavutil/pixelutils.c +++ b/libavutil/pixelutils.c @@ -51,12 +51,14 @@ DECLARE_BLOCK_FUNCTIONS(2) DECLARE_BLOCK_FUNCTIONS(4) DECLARE_BLOCK_FUNCTIONS(8) DECLARE_BLOCK_FUNCTIONS(16) +DECLARE_BLOCK_FUNCTIONS(32) static const av_pixelutils_sad_fn sad_c[] = { block_sad_2x2_c, block_sad_4x4_c, block_sad_8x8_c, block_sad_16x16_c, + block_sad_32x32_c, }; #endif /* CONFIG_PIXELUTILS */ diff --git a/libavutil/pixfmt.h b/libavutil/pixfmt.h index 34a153148..8b54c9415 100644 --- a/libavutil/pixfmt.h +++ b/libavutil/pixfmt.h @@ -334,6 +334,20 @@ enum AVPixelFormat { */ AV_PIX_FMT_OPENCL, + AV_PIX_FMT_GRAY14BE, ///< Y , 14bpp, big-endian + AV_PIX_FMT_GRAY14LE, ///< Y , 14bpp, little-endian + + AV_PIX_FMT_GRAYF32BE, ///< IEEE-754 single precision Y, 32bpp, big-endian + AV_PIX_FMT_GRAYF32LE, ///< IEEE-754 single precision Y, 32bpp, little-endian + + AV_PIX_FMT_YUVA422P12BE, ///< planar YUV 4:2:2,24bpp, (1 Cr & Cb sample per 2x1 Y samples), 12b alpha, big-endian + AV_PIX_FMT_YUVA422P12LE, ///< planar YUV 4:2:2,24bpp, (1 Cr & Cb sample per 2x1 Y samples), 12b alpha, little-endian + AV_PIX_FMT_YUVA444P12BE, ///< planar YUV 4:4:4,36bpp, (1 Cr & Cb sample per 1x1 Y samples), 12b alpha, big-endian + AV_PIX_FMT_YUVA444P12LE, ///< planar YUV 4:4:4,36bpp, (1 Cr & Cb sample per 1x1 Y samples), 12b alpha, little-endian + + AV_PIX_FMT_NV24, ///< planar YUV 4:4:4, 24bpp, 1 plane for Y and 1 plane for the UV components, which are interleaved (first byte U and the following byte V) + AV_PIX_FMT_NV42, ///< as above, but U and V bytes are swapped + AV_PIX_FMT_NB ///< number of pixel formats, DO NOT USE THIS if you want to link with shared libav* because the number of formats might differ between versions }; @@ -353,6 +367,7 @@ enum AVPixelFormat { #define AV_PIX_FMT_GRAY9 AV_PIX_FMT_NE(GRAY9BE, GRAY9LE) #define AV_PIX_FMT_GRAY10 AV_PIX_FMT_NE(GRAY10BE, GRAY10LE) #define AV_PIX_FMT_GRAY12 AV_PIX_FMT_NE(GRAY12BE, GRAY12LE) +#define AV_PIX_FMT_GRAY14 AV_PIX_FMT_NE(GRAY14BE, GRAY14LE) #define AV_PIX_FMT_GRAY16 AV_PIX_FMT_NE(GRAY16BE, GRAY16LE) #define AV_PIX_FMT_YA16 AV_PIX_FMT_NE(YA16BE, YA16LE) #define AV_PIX_FMT_RGB48 AV_PIX_FMT_NE(RGB48BE, RGB48LE) @@ -401,12 +416,16 @@ enum AVPixelFormat { #define AV_PIX_FMT_GBRPF32 AV_PIX_FMT_NE(GBRPF32BE, GBRPF32LE) #define AV_PIX_FMT_GBRAPF32 AV_PIX_FMT_NE(GBRAPF32BE, GBRAPF32LE) +#define AV_PIX_FMT_GRAYF32 AV_PIX_FMT_NE(GRAYF32BE, GRAYF32LE) + #define AV_PIX_FMT_YUVA420P9 AV_PIX_FMT_NE(YUVA420P9BE , YUVA420P9LE) #define AV_PIX_FMT_YUVA422P9 AV_PIX_FMT_NE(YUVA422P9BE , YUVA422P9LE) #define AV_PIX_FMT_YUVA444P9 AV_PIX_FMT_NE(YUVA444P9BE , YUVA444P9LE) #define AV_PIX_FMT_YUVA420P10 AV_PIX_FMT_NE(YUVA420P10BE, YUVA420P10LE) #define AV_PIX_FMT_YUVA422P10 AV_PIX_FMT_NE(YUVA422P10BE, YUVA422P10LE) #define AV_PIX_FMT_YUVA444P10 AV_PIX_FMT_NE(YUVA444P10BE, YUVA444P10LE) +#define AV_PIX_FMT_YUVA422P12 AV_PIX_FMT_NE(YUVA422P12BE, YUVA422P12LE) +#define AV_PIX_FMT_YUVA444P12 AV_PIX_FMT_NE(YUVA444P12BE, YUVA444P12LE) #define AV_PIX_FMT_YUVA420P16 AV_PIX_FMT_NE(YUVA420P16BE, YUVA420P16LE) #define AV_PIX_FMT_YUVA422P16 AV_PIX_FMT_NE(YUVA422P16BE, YUVA422P16LE) #define AV_PIX_FMT_YUVA444P16 AV_PIX_FMT_NE(YUVA444P16BE, YUVA444P16LE) diff --git a/libavutil/ppc/cpu.c b/libavutil/ppc/cpu.c index 7bb7cd813..b022149fa 100644 --- a/libavutil/ppc/cpu.c +++ b/libavutil/ppc/cpu.c @@ -92,14 +92,14 @@ int ff_get_cpu_flags_ppc(void) #ifdef PPC_FEATURE_HAS_VSX if (buf[i + 1] & PPC_FEATURE_HAS_VSX) ret |= AV_CPU_FLAG_VSX; -#endif -#ifdef PPC_FEATURE_ARCH_2_07 - if (buf[i + 1] & PPC_FEATURE_HAS_POWER8) - ret |= AV_CPU_FLAG_POWER8; #endif if (ret & AV_CPU_FLAG_VSX) av_assert0(ret & AV_CPU_FLAG_ALTIVEC); - goto out; + } else if (buf[i] == AT_HWCAP2) { +#ifdef PPC_FEATURE2_ARCH_2_07 + if (buf[i + 1] & PPC_FEATURE2_ARCH_2_07) + ret |= AV_CPU_FLAG_POWER8; +#endif } } } diff --git a/libavutil/softfloat_ieee754.h b/libavutil/softfloat_ieee754.h index b8957fb0a..3398aa18b 100644 --- a/libavutil/softfloat_ieee754.h +++ b/libavutil/softfloat_ieee754.h @@ -64,7 +64,7 @@ static inline SoftFloat_IEEE754 av_int2sf_ieee754(int64_t n, int e) { * by the IEEE 754 spec. */ static inline SoftFloat_IEEE754 av_bits2sf_ieee754(uint32_t n) { - return ((SoftFloat_IEEE754) { (n & 0x80000000UL), (n & 0x7FFFFFUL), (n & 0x7F800000UL) }); + return ((SoftFloat_IEEE754) { (n & 0x80000000UL) >> 31, (n & 0x7FFFFFUL), (int8_t)((n & 0x7F800000UL) >> 23)}); } /** Convert the softfloat to integer diff --git a/libavutil/tests/bprint.c b/libavutil/tests/bprint.c index d7f381dd5..5a46f55d7 100644 --- a/libavutil/tests/bprint.c +++ b/libavutil/tests/bprint.c @@ -47,13 +47,13 @@ int main(void) char buf[256]; struct tm testtime = { .tm_year = 100, .tm_mon = 11, .tm_mday = 20 }; - av_bprint_init(&b, 0, -1); + av_bprint_init(&b, 0, AV_BPRINT_SIZE_UNLIMITED); bprint_pascal(&b, 5); printf("Short text in unlimited buffer: %u/%u\n", (unsigned)strlen(b.str), b.len); printf("%s\n", b.str); av_bprint_finalize(&b, NULL); - av_bprint_init(&b, 0, -1); + av_bprint_init(&b, 0, AV_BPRINT_SIZE_UNLIMITED); bprint_pascal(&b, 25); printf("Long text in unlimited buffer: %u/%u\n", (unsigned)strlen(b.str), b.len); av_bprint_finalize(&b, NULL); @@ -63,16 +63,16 @@ int main(void) printf("Long text in limited buffer: %u/%u\n", (unsigned)strlen(b.str), b.len); av_bprint_finalize(&b, NULL); - av_bprint_init(&b, 0, 1); + av_bprint_init(&b, 0, AV_BPRINT_SIZE_AUTOMATIC); bprint_pascal(&b, 5); printf("Short text in automatic buffer: %u/%u\n", (unsigned)strlen(b.str), b.len); - av_bprint_init(&b, 0, 1); + av_bprint_init(&b, 0, AV_BPRINT_SIZE_AUTOMATIC); bprint_pascal(&b, 25); printf("Long text in automatic buffer: %u/%u\n", (unsigned)strlen(b.str)/8*8, b.len); /* Note that the size of the automatic buffer is arch-dependent. */ - av_bprint_init(&b, 0, 0); + av_bprint_init(&b, 0, AV_BPRINT_SIZE_COUNT_ONLY); bprint_pascal(&b, 25); printf("Long text count only buffer: %u/%u\n", (unsigned)strlen(b.str), b.len); @@ -80,7 +80,7 @@ int main(void) bprint_pascal(&b, 25); printf("Long text count only buffer: %u/%u\n", (unsigned)strlen(buf), b.len); - av_bprint_init(&b, 0, -1); + av_bprint_init(&b, 0, AV_BPRINT_SIZE_UNLIMITED); av_bprint_strftime(&b, "%Y-%m-%d", &testtime); printf("strftime full: %u/%u \"%s\"\n", (unsigned)strlen(buf), b.len, b.str); av_bprint_finalize(&b, NULL); diff --git a/libavutil/tests/encryption_info.c b/libavutil/tests/encryption_info.c new file mode 100644 index 000000000..d489612b7 --- /dev/null +++ b/libavutil/tests/encryption_info.c @@ -0,0 +1,176 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/encryption_info.h" + +#include +#include + +#include "libavutil/avassert.h" + +static const AVSubsampleEncryptionInfo test_subsamples[] = {{1, 2}, {3, 4}, {5, 6}, {7, 8}}; +static const size_t test_subsample_count = sizeof(test_subsamples) / sizeof(test_subsamples[0]); +static const uint8_t test_iv[] = {0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18}; +static const uint8_t test_key_id[] = {0x21, 0x22, 0x23, 0x24}; +static const uint8_t test_key_id_2[] = {0x31, 0x32, 0x33, 0x34}; +static const uint8_t test_system_id[] = {0x41, 0x42, 0x43}; +static const uint8_t test_data[] = {0x51, 0x52}; + +static int compare_encryption_info(const AVEncryptionInfo *a, const AVEncryptionInfo *b) { + if (!a || !b || a->scheme != b->scheme || a->crypt_byte_block != b->crypt_byte_block || + a->skip_byte_block != b->skip_byte_block || a->key_id_size != b->key_id_size || + a->iv_size != b->iv_size || a->subsample_count != b->subsample_count) + return 1; + + if (memcmp(a->key_id, b->key_id, a->key_id_size) != 0 || + memcmp(a->iv, b->iv, a->iv_size) != 0 || + memcmp(a->subsamples, b->subsamples, a->subsample_count * sizeof(a->subsamples[0]))) + return 1; + + return 0; +} + +static int compare_encryption_init_info(const AVEncryptionInitInfo *a, const AVEncryptionInitInfo *b) { + if (!a || !b || a->system_id_size != b->system_id_size || + a->num_key_ids != b->num_key_ids || a->key_id_size != b->key_id_size || + a->data_size != b->data_size) + return 1; + + if (memcmp(a->system_id, b->system_id, a->system_id_size) != 0 || + memcmp(a->data, b->data, a->data_size) != 0) + return 1; + + for (uint32_t i = 0; i < a->num_key_ids; i++) { + if (memcmp(a->key_ids[i], b->key_ids[i], a->key_id_size) != 0) + return 1; + } + + if (a->next || b->next) { + if (!a->next || !b->next) + return 1; + if (compare_encryption_init_info(a->next, b->next) != 0) + return 1; + } + + return 0; +} + +static void run_encryption_info_test(void) +{ + AVEncryptionInfo *info, *copy; + uint8_t *side_data; + size_t side_data_size; + + info = av_encryption_info_alloc(test_subsample_count, sizeof(test_key_id), sizeof(test_iv)); + av_assert0(info); + av_assert0(info->key_id); + av_assert0(info->key_id_size == sizeof(test_key_id)); + av_assert0(info->iv); + av_assert0(info->iv_size == sizeof(test_iv)); + av_assert0(info->subsamples); + av_assert0(info->subsample_count == test_subsample_count); + + info->scheme = 1234; + info->crypt_byte_block = 333; + info->skip_byte_block = 444; + memcpy(info->key_id, test_key_id, sizeof(test_key_id)); + memcpy(info->iv, test_iv, sizeof(test_iv)); + memcpy(info->subsamples, test_subsamples, sizeof(test_subsamples)); + + copy = av_encryption_info_clone(info); + av_assert0(copy); + av_assert0(copy != info); + av_assert0(compare_encryption_info(info, copy) == 0); + av_encryption_info_free(copy); + + side_data = av_encryption_info_add_side_data(info, &side_data_size); + av_assert0(side_data); + av_assert0(side_data_size > 0); + + copy = av_encryption_info_get_side_data(side_data, side_data_size); + av_assert0(copy); + av_assert0(copy != info); + av_assert0(compare_encryption_info(info, copy) == 0); + av_encryption_info_free(copy); + av_free(side_data); + + av_encryption_info_free(info); +} + +static AVEncryptionInitInfo *create_init_info(void) +{ + AVEncryptionInitInfo *info; + + info = av_encryption_init_info_alloc(sizeof(test_system_id), 2, sizeof(test_key_id), sizeof(test_data)); + av_assert0(info); + av_assert0(info->system_id); + av_assert0(info->system_id_size == sizeof(test_system_id)); + av_assert0(info->key_ids); + av_assert0(info->num_key_ids == 2); + av_assert0(info->key_id_size == sizeof(test_key_id)); + av_assert0(info->key_ids[0]); + av_assert0(info->key_ids[1]); + av_assert0(info->data); + av_assert0(info->data_size == sizeof(test_data)); + av_assert0(!info->next); + + memcpy(info->system_id, test_system_id, sizeof(test_system_id)); + memcpy(info->key_ids[0], test_key_id, sizeof(test_key_id)); + memcpy(info->key_ids[1], test_key_id_2, sizeof(test_key_id_2)); + memcpy(info->data, test_data, sizeof(test_data)); + + return info; +} + +static void run_encryption_init_info_test(void) +{ + AVEncryptionInitInfo *info, *copy; + uint8_t *side_data; + size_t side_data_size; + + info = create_init_info(); + + side_data = av_encryption_init_info_add_side_data(info, &side_data_size); + av_assert0(side_data); + av_assert0(side_data_size > 0); + copy = av_encryption_init_info_get_side_data(side_data, side_data_size); + av_assert0(copy); + av_assert0(compare_encryption_init_info(info, copy) == 0); + av_encryption_init_info_free(copy); + av_free(side_data); + + // Make the first init info different from the second to test the correct order. + memset(info->system_id, 0, info->system_id_size); + info->next = create_init_info(); + side_data = av_encryption_init_info_add_side_data(info, &side_data_size); + av_assert0(side_data); + copy = av_encryption_init_info_get_side_data(side_data, side_data_size); + av_assert0(copy); + av_assert0(compare_encryption_init_info(info, copy) == 0); + av_encryption_init_info_free(copy); + av_free(side_data); + + av_encryption_init_info_free(info); +} + +int main(int argc, char **argv) +{ + run_encryption_info_test(); + run_encryption_init_info_test(); + return 0; +} diff --git a/libavutil/tests/hwdevice.c b/libavutil/tests/hwdevice.c new file mode 100644 index 000000000..7eb355c98 --- /dev/null +++ b/libavutil/tests/hwdevice.c @@ -0,0 +1,226 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include "libavutil/hwcontext.h" + +static int test_derivation(AVBufferRef *src_ref, const char *src_name) +{ + enum AVHWDeviceType derived_type; + const char *derived_name; + AVBufferRef *derived_ref = NULL, *back_ref = NULL; + AVHWDeviceContext *src_dev, *derived_dev; + int err; + + src_dev = (AVHWDeviceContext*)src_ref->data; + + derived_type = AV_HWDEVICE_TYPE_NONE; + while (1) { + derived_type = av_hwdevice_iterate_types(derived_type); + if (derived_type == AV_HWDEVICE_TYPE_NONE) + break; + + derived_name = av_hwdevice_get_type_name(derived_type); + + err = av_hwdevice_ctx_create_derived(&derived_ref, derived_type, + src_ref, 0); + if (err < 0) { + fprintf(stderr, "Unable to derive %s -> %s: %d.\n", + src_name, derived_name, err); + continue; + } + + derived_dev = (AVHWDeviceContext*)derived_ref->data; + if (derived_dev->type != derived_type) { + fprintf(stderr, "Device derived as type %d has type %d.\n", + derived_type, derived_dev->type); + goto fail; + } + + if (derived_type == src_dev->type) { + if (derived_dev != src_dev) { + fprintf(stderr, "Derivation of %s from itself succeeded " + "but did not return the same device.\n", src_name); + goto fail; + } + av_buffer_unref(&derived_ref); + continue; + } + + err = av_hwdevice_ctx_create_derived(&back_ref, src_dev->type, + derived_ref, 0); + if (err < 0) { + fprintf(stderr, "Derivation %s to %s succeeded, but derivation " + "back again failed: %d.\n", + src_name, derived_name, err); + goto fail; + } + + if (back_ref->data != src_ref->data) { + fprintf(stderr, "Derivation %s to %s succeeded, but derivation " + "back again did not return the original device.\n", + src_name, derived_name); + goto fail; + } + + fprintf(stderr, "Successfully tested derivation %s -> %s.\n", + src_name, derived_name); + + av_buffer_unref(&derived_ref); + av_buffer_unref(&back_ref); + } + + return 0; + +fail: + av_buffer_unref(&derived_ref); + av_buffer_unref(&back_ref); + return -1; +} + +static int test_device(enum AVHWDeviceType type, const char *name, + const char *device, AVDictionary *opts, int flags) +{ + AVBufferRef *ref; + AVHWDeviceContext *dev; + int err; + + err = av_hwdevice_ctx_create(&ref, type, device, opts, flags); + if (err < 0) { + fprintf(stderr, "Failed to create %s device: %d.\n", name, err); + return 1; + } + + dev = (AVHWDeviceContext*)ref->data; + if (dev->type != type) { + fprintf(stderr, "Device created as type %d has type %d.\n", + type, dev->type); + av_buffer_unref(&ref); + return -1; + } + + fprintf(stderr, "Device type %s successfully created.\n", name); + + err = test_derivation(ref, name); + + av_buffer_unref(&ref); + + return err; +} + +static const struct { + enum AVHWDeviceType type; + const char *possible_devices[5]; +} test_devices[] = { + { AV_HWDEVICE_TYPE_CUDA, + { "0", "1", "2" } }, + { AV_HWDEVICE_TYPE_DRM, + { "/dev/dri/card0", "/dev/dri/card1", + "/dev/dri/renderD128", "/dev/dri/renderD129" } }, + { AV_HWDEVICE_TYPE_DXVA2, + { "0", "1", "2" } }, + { AV_HWDEVICE_TYPE_D3D11VA, + { "0", "1", "2" } }, + { AV_HWDEVICE_TYPE_OPENCL, + { "0.0", "0.1", "1.0", "1.1" } }, + { AV_HWDEVICE_TYPE_VAAPI, + { "/dev/dri/renderD128", "/dev/dri/renderD129", ":0" } }, +}; + +static int test_device_type(enum AVHWDeviceType type) +{ + enum AVHWDeviceType check; + const char *name; + int i, j, found, err; + + name = av_hwdevice_get_type_name(type); + if (!name) { + fprintf(stderr, "No name available for device type %d.\n", type); + return -1; + } + + check = av_hwdevice_find_type_by_name(name); + if (check != type) { + fprintf(stderr, "Type %d maps to name %s maps to type %d.\n", + type, name, check); + return -1; + } + + found = 0; + + err = test_device(type, name, NULL, NULL, 0); + if (err < 0) { + fprintf(stderr, "Test failed for %s with default options.\n", name); + return -1; + } + if (err == 0) { + fprintf(stderr, "Test passed for %s with default options.\n", name); + ++found; + } + + for (i = 0; i < FF_ARRAY_ELEMS(test_devices); i++) { + if (test_devices[i].type != type) + continue; + + for (j = 0; test_devices[i].possible_devices[j]; j++) { + err = test_device(type, name, + test_devices[i].possible_devices[j], + NULL, 0); + if (err < 0) { + fprintf(stderr, "Test failed for %s with device %s.\n", + name, test_devices[i].possible_devices[j]); + return -1; + } + if (err == 0) { + fprintf(stderr, "Test passed for %s with device %s.\n", + name, test_devices[i].possible_devices[j]); + ++found; + } + } + } + + return !found; +} + +int main(void) +{ + enum AVHWDeviceType type = AV_HWDEVICE_TYPE_NONE; + int pass, fail, skip, err; + + pass = fail = skip = 0; + while (1) { + type = av_hwdevice_iterate_types(type); + if (type == AV_HWDEVICE_TYPE_NONE) + break; + + err = test_device_type(type); + if (err == 0) + ++pass; + else if (err < 0) + ++fail; + else + ++skip; + } + + fprintf(stderr, "Attempted to test %d device types: " + "%d passed, %d failed, %d skipped.\n", + pass + fail + skip, pass, fail, skip); + + return fail > 0; +} diff --git a/libavutil/tests/parseutils.c b/libavutil/tests/parseutils.c index 180f62400..a1ac8d44e 100644 --- a/libavutil/tests/parseutils.c +++ b/libavutil/tests/parseutils.c @@ -185,6 +185,10 @@ static void test_av_parse_time(void) "42.1729", "-1729.42", "12:34", + "2147483648s", + "4294967296ms", + "8589934592us", + "9223372036854775808us", }; av_log_set_level(AV_LOG_DEBUG); diff --git a/libavutil/tests/pixdesc.c b/libavutil/tests/pixdesc.c index 7fbfeea96..34e2bea93 100644 --- a/libavutil/tests/pixdesc.c +++ b/libavutil/tests/pixdesc.c @@ -37,10 +37,6 @@ int main(void){ skip = 0; } av_log(NULL, AV_LOG_INFO, "pix fmt %s avg_bpp:%d colortype:%d\n", desc->name, av_get_padded_bits_per_pixel(desc), get_color_type(desc)); - if ((!(desc->flags & AV_PIX_FMT_FLAG_ALPHA)) != (desc->nb_components != 2 && desc->nb_components != 4)) { - av_log(NULL, AV_LOG_ERROR, "Alpha flag mismatch\n"); - err = 1; - } } return err; } diff --git a/libavutil/tests/pixelutils.c b/libavutil/tests/pixelutils.c index ec4dc8fe8..2f807584b 100644 --- a/libavutil/tests/pixelutils.c +++ b/libavutil/tests/pixelutils.c @@ -115,7 +115,7 @@ int main(void) goto end; /* Exact buffer sizes, to check for overreads */ - for (i = 1; i <= 4; i++) { + for (i = 1; i <= 5; i++) { for (align = 0; align < 3; align++) { int size1, size2; diff --git a/libavutil/tests/pixfmt_best.c b/libavutil/tests/pixfmt_best.c index e98fcc19a..53f726420 100644 --- a/libavutil/tests/pixfmt_best.c +++ b/libavutil/tests/pixfmt_best.c @@ -76,6 +76,7 @@ int main(void) TEST(AV_PIX_FMT_P010, AV_PIX_FMT_YUV420P10); TEST(AV_PIX_FMT_P016, AV_PIX_FMT_YUV420P16); TEST(AV_PIX_FMT_NV16, AV_PIX_FMT_YUV422P); + TEST(AV_PIX_FMT_NV24, AV_PIX_FMT_YUV444P); TEST(AV_PIX_FMT_YUYV422, AV_PIX_FMT_YUV422P); TEST(AV_PIX_FMT_UYVY422, AV_PIX_FMT_YUV422P); TEST(AV_PIX_FMT_BGR565, AV_PIX_FMT_RGB565); diff --git a/libavutil/tests/random_seed.c b/libavutil/tests/random_seed.c index 78067dbe4..bf0c6c798 100644 --- a/libavutil/tests/random_seed.c +++ b/libavutil/tests/random_seed.c @@ -47,7 +47,7 @@ int main(void) retry:; } if (retry >= 3) { - printf("rsf %d: FAIL at %d with %X\n", rsf, j, seeds[j]); + printf("rsf %d: FAIL at %d with %"PRIX32"\n", rsf, j, seeds[j]); return 1; } } diff --git a/libavutil/threadmessage.c b/libavutil/threadmessage.c index 872e9392b..764b7fb81 100644 --- a/libavutil/threadmessage.c +++ b/libavutil/threadmessage.c @@ -102,6 +102,19 @@ void av_thread_message_queue_free(AVThreadMessageQueue **mq) #endif } +int av_thread_message_queue_nb_elems(AVThreadMessageQueue *mq) +{ +#if HAVE_THREADS + int ret; + pthread_mutex_lock(&mq->lock); + ret = av_fifo_size(mq->fifo); + pthread_mutex_unlock(&mq->lock); + return ret / mq->elsize; +#else + return AVERROR(ENOSYS); +#endif +} + #if HAVE_THREADS static int av_thread_message_queue_send_locked(AVThreadMessageQueue *mq, diff --git a/libavutil/threadmessage.h b/libavutil/threadmessage.h index 8480a0a3d..42ce655f3 100644 --- a/libavutil/threadmessage.h +++ b/libavutil/threadmessage.h @@ -95,6 +95,14 @@ void av_thread_message_queue_set_err_recv(AVThreadMessageQueue *mq, void av_thread_message_queue_set_free_func(AVThreadMessageQueue *mq, void (*free_func)(void *msg)); +/** + * Return the current number of messages in the queue. + * + * @return the current number of messages or AVERROR(ENOSYS) if lavu was built + * without thread support + */ +int av_thread_message_queue_nb_elems(AVThreadMessageQueue *mq); + /** * Flush the message queue * diff --git a/libavutil/time_internal.h b/libavutil/time_internal.h index 612a75a04..d0f007ab1 100644 --- a/libavutil/time_internal.h +++ b/libavutil/time_internal.h @@ -23,7 +23,7 @@ #include "config.h" #if !HAVE_GMTIME_R && !defined(gmtime_r) -static inline struct tm *gmtime_r(const time_t* clock, struct tm *result) +static inline struct tm *ff_gmtime_r(const time_t* clock, struct tm *result) { struct tm *ptr = gmtime(clock); if (!ptr) @@ -31,10 +31,11 @@ static inline struct tm *gmtime_r(const time_t* clock, struct tm *result) *result = *ptr; return result; } +#define gmtime_r ff_gmtime_r #endif #if !HAVE_LOCALTIME_R && !defined(localtime_r) -static inline struct tm *localtime_r(const time_t* clock, struct tm *result) +static inline struct tm *ff_localtime_r(const time_t* clock, struct tm *result) { struct tm *ptr = localtime(clock); if (!ptr) @@ -42,6 +43,7 @@ static inline struct tm *localtime_r(const time_t* clock, struct tm *result) *result = *ptr; return result; } +#define localtime_r ff_localtime_r #endif #endif /* AVUTIL_TIME_INTERNAL_H */ diff --git a/libavutil/tx.c b/libavutil/tx.c new file mode 100644 index 000000000..93f6e489d --- /dev/null +++ b/libavutil/tx.c @@ -0,0 +1,803 @@ +/* + * Copyright (c) 2019 Lynne + * Power of two FFT: + * Copyright (c) 2008 Loren Merritt + * Copyright (c) 2002 Fabrice Bellard + * Partly based on libdjbfft by D. J. Bernstein + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include "tx.h" +#include "thread.h" +#include "mem.h" +#include "avassert.h" + +typedef float FFTSample; +typedef AVComplexFloat FFTComplex; + +struct AVTXContext { + int n; /* Nptwo part */ + int m; /* Ptwo part */ + + FFTComplex *exptab; /* MDCT exptab */ + FFTComplex *tmp; /* Temporary buffer needed for all compound transforms */ + int *pfatab; /* Input/Output mapping for compound transforms */ + int *revtab; /* Input mapping for power of two transforms */ +}; + +#define FFT_NAME(x) x + +#define COSTABLE(size) \ + static DECLARE_ALIGNED(32, FFTSample, FFT_NAME(ff_cos_##size))[size/2] + +static FFTSample * const FFT_NAME(ff_cos_tabs)[18]; + +COSTABLE(16); +COSTABLE(32); +COSTABLE(64); +COSTABLE(128); +COSTABLE(256); +COSTABLE(512); +COSTABLE(1024); +COSTABLE(2048); +COSTABLE(4096); +COSTABLE(8192); +COSTABLE(16384); +COSTABLE(32768); +COSTABLE(65536); +COSTABLE(131072); + +static av_cold void init_ff_cos_tabs(int index) +{ + int m = 1 << index; + double freq = 2*M_PI/m; + FFTSample *tab = FFT_NAME(ff_cos_tabs)[index]; + for(int i = 0; i <= m/4; i++) + tab[i] = cos(i*freq); + for(int i = 1; i < m/4; i++) + tab[m/2 - i] = tab[i]; +} + +typedef struct CosTabsInitOnce { + void (*func)(void); + AVOnce control; +} CosTabsInitOnce; + +#define INIT_FF_COS_TABS_FUNC(index, size) \ +static av_cold void init_ff_cos_tabs_ ## size (void) \ +{ \ + init_ff_cos_tabs(index); \ +} + +INIT_FF_COS_TABS_FUNC(4, 16) +INIT_FF_COS_TABS_FUNC(5, 32) +INIT_FF_COS_TABS_FUNC(6, 64) +INIT_FF_COS_TABS_FUNC(7, 128) +INIT_FF_COS_TABS_FUNC(8, 256) +INIT_FF_COS_TABS_FUNC(9, 512) +INIT_FF_COS_TABS_FUNC(10, 1024) +INIT_FF_COS_TABS_FUNC(11, 2048) +INIT_FF_COS_TABS_FUNC(12, 4096) +INIT_FF_COS_TABS_FUNC(13, 8192) +INIT_FF_COS_TABS_FUNC(14, 16384) +INIT_FF_COS_TABS_FUNC(15, 32768) +INIT_FF_COS_TABS_FUNC(16, 65536) +INIT_FF_COS_TABS_FUNC(17, 131072) + +static CosTabsInitOnce cos_tabs_init_once[] = { + { NULL }, + { NULL }, + { NULL }, + { NULL }, + { init_ff_cos_tabs_16, AV_ONCE_INIT }, + { init_ff_cos_tabs_32, AV_ONCE_INIT }, + { init_ff_cos_tabs_64, AV_ONCE_INIT }, + { init_ff_cos_tabs_128, AV_ONCE_INIT }, + { init_ff_cos_tabs_256, AV_ONCE_INIT }, + { init_ff_cos_tabs_512, AV_ONCE_INIT }, + { init_ff_cos_tabs_1024, AV_ONCE_INIT }, + { init_ff_cos_tabs_2048, AV_ONCE_INIT }, + { init_ff_cos_tabs_4096, AV_ONCE_INIT }, + { init_ff_cos_tabs_8192, AV_ONCE_INIT }, + { init_ff_cos_tabs_16384, AV_ONCE_INIT }, + { init_ff_cos_tabs_32768, AV_ONCE_INIT }, + { init_ff_cos_tabs_65536, AV_ONCE_INIT }, + { init_ff_cos_tabs_131072, AV_ONCE_INIT }, +}; + +static FFTSample * const FFT_NAME(ff_cos_tabs)[] = { + NULL, NULL, NULL, NULL, + FFT_NAME(ff_cos_16), + FFT_NAME(ff_cos_32), + FFT_NAME(ff_cos_64), + FFT_NAME(ff_cos_128), + FFT_NAME(ff_cos_256), + FFT_NAME(ff_cos_512), + FFT_NAME(ff_cos_1024), + FFT_NAME(ff_cos_2048), + FFT_NAME(ff_cos_4096), + FFT_NAME(ff_cos_8192), + FFT_NAME(ff_cos_16384), + FFT_NAME(ff_cos_32768), + FFT_NAME(ff_cos_65536), + FFT_NAME(ff_cos_131072), +}; + +static av_cold void ff_init_ff_cos_tabs(int index) +{ + ff_thread_once(&cos_tabs_init_once[index].control, + cos_tabs_init_once[index].func); +} + +static AVOnce tabs_53_once = AV_ONCE_INIT; +static DECLARE_ALIGNED(32, FFTComplex, FFT_NAME(ff_53_tabs))[4]; + +static av_cold void ff_init_53_tabs(void) +{ + ff_53_tabs[0] = (FFTComplex){ cos(2 * M_PI / 12), cos(2 * M_PI / 12) }; + ff_53_tabs[1] = (FFTComplex){ 0.5, 0.5 }; + ff_53_tabs[2] = (FFTComplex){ cos(2 * M_PI / 5), sin(2 * M_PI / 5) }; + ff_53_tabs[3] = (FFTComplex){ cos(2 * M_PI / 10), sin(2 * M_PI / 10) }; +} + +#define BF(x, y, a, b) do { \ + x = (a) - (b); \ + y = (a) + (b); \ + } while (0) + +#define CMUL(dre, dim, are, aim, bre, bim) do { \ + (dre) = (are) * (bre) - (aim) * (bim); \ + (dim) = (are) * (bim) + (aim) * (bre); \ + } while (0) + +#define CMUL3(c, a, b) CMUL((c).re, (c).im, (a).re, (a).im, (b).re, (b).im) + +static av_always_inline void fft3(FFTComplex *out, FFTComplex *in, + ptrdiff_t stride) +{ + FFTComplex tmp[2]; + + tmp[0].re = in[1].im - in[2].im; + tmp[0].im = in[1].re - in[2].re; + tmp[1].re = in[1].re + in[2].re; + tmp[1].im = in[1].im + in[2].im; + + out[0*stride].re = in[0].re + tmp[1].re; + out[0*stride].im = in[0].im + tmp[1].im; + + tmp[0].re *= ff_53_tabs[0].re; + tmp[0].im *= ff_53_tabs[0].im; + tmp[1].re *= ff_53_tabs[1].re; + tmp[1].im *= ff_53_tabs[1].re; + + out[1*stride].re = in[0].re - tmp[1].re + tmp[0].re; + out[1*stride].im = in[0].im - tmp[1].im - tmp[0].im; + out[2*stride].re = in[0].re - tmp[1].re - tmp[0].re; + out[2*stride].im = in[0].im - tmp[1].im + tmp[0].im; +} + +#define DECL_FFT5(NAME, D0, D1, D2, D3, D4) \ +static av_always_inline void NAME(FFTComplex *out, FFTComplex *in, \ + ptrdiff_t stride) \ +{ \ + FFTComplex z0[4], t[6]; \ + \ + t[0].re = in[1].re + in[4].re; \ + t[0].im = in[1].im + in[4].im; \ + t[1].im = in[1].re - in[4].re; \ + t[1].re = in[1].im - in[4].im; \ + t[2].re = in[2].re + in[3].re; \ + t[2].im = in[2].im + in[3].im; \ + t[3].im = in[2].re - in[3].re; \ + t[3].re = in[2].im - in[3].im; \ + \ + out[D0*stride].re = in[0].re + in[1].re + in[2].re + \ + in[3].re + in[4].re; \ + out[D0*stride].im = in[0].im + in[1].im + in[2].im + \ + in[3].im + in[4].im; \ + \ + t[4].re = ff_53_tabs[2].re * t[2].re - ff_53_tabs[3].re * t[0].re; \ + t[4].im = ff_53_tabs[2].re * t[2].im - ff_53_tabs[3].re * t[0].im; \ + t[0].re = ff_53_tabs[2].re * t[0].re - ff_53_tabs[3].re * t[2].re; \ + t[0].im = ff_53_tabs[2].re * t[0].im - ff_53_tabs[3].re * t[2].im; \ + t[5].re = ff_53_tabs[2].im * t[3].re - ff_53_tabs[3].im * t[1].re; \ + t[5].im = ff_53_tabs[2].im * t[3].im - ff_53_tabs[3].im * t[1].im; \ + t[1].re = ff_53_tabs[2].im * t[1].re + ff_53_tabs[3].im * t[3].re; \ + t[1].im = ff_53_tabs[2].im * t[1].im + ff_53_tabs[3].im * t[3].im; \ + \ + z0[0].re = t[0].re - t[1].re; \ + z0[0].im = t[0].im - t[1].im; \ + z0[1].re = t[4].re + t[5].re; \ + z0[1].im = t[4].im + t[5].im; \ + \ + z0[2].re = t[4].re - t[5].re; \ + z0[2].im = t[4].im - t[5].im; \ + z0[3].re = t[0].re + t[1].re; \ + z0[3].im = t[0].im + t[1].im; \ + \ + out[D1*stride].re = in[0].re + z0[3].re; \ + out[D1*stride].im = in[0].im + z0[0].im; \ + out[D2*stride].re = in[0].re + z0[2].re; \ + out[D2*stride].im = in[0].im + z0[1].im; \ + out[D3*stride].re = in[0].re + z0[1].re; \ + out[D3*stride].im = in[0].im + z0[2].im; \ + out[D4*stride].re = in[0].re + z0[0].re; \ + out[D4*stride].im = in[0].im + z0[3].im; \ +} + +DECL_FFT5(fft5, 0, 1, 2, 3, 4) +DECL_FFT5(fft5_m1, 0, 6, 12, 3, 9) +DECL_FFT5(fft5_m2, 10, 1, 7, 13, 4) +DECL_FFT5(fft5_m3, 5, 11, 2, 8, 14) + +static av_always_inline void fft15(FFTComplex *out, FFTComplex *in, + ptrdiff_t stride) +{ + FFTComplex tmp[15]; + + for (int i = 0; i < 5; i++) + fft3(tmp + i, in + i*3, 5); + + fft5_m1(out, tmp + 0, stride); + fft5_m2(out, tmp + 5, stride); + fft5_m3(out, tmp + 10, stride); +} + +#define BUTTERFLIES(a0,a1,a2,a3) {\ + BF(t3, t5, t5, t1);\ + BF(a2.re, a0.re, a0.re, t5);\ + BF(a3.im, a1.im, a1.im, t3);\ + BF(t4, t6, t2, t6);\ + BF(a3.re, a1.re, a1.re, t4);\ + BF(a2.im, a0.im, a0.im, t6);\ +} + +// force loading all the inputs before storing any. +// this is slightly slower for small data, but avoids store->load aliasing +// for addresses separated by large powers of 2. +#define BUTTERFLIES_BIG(a0,a1,a2,a3) {\ + FFTSample r0=a0.re, i0=a0.im, r1=a1.re, i1=a1.im;\ + BF(t3, t5, t5, t1);\ + BF(a2.re, a0.re, r0, t5);\ + BF(a3.im, a1.im, i1, t3);\ + BF(t4, t6, t2, t6);\ + BF(a3.re, a1.re, r1, t4);\ + BF(a2.im, a0.im, i0, t6);\ +} + +#define TRANSFORM(a0,a1,a2,a3,wre,wim) {\ + CMUL(t1, t2, a2.re, a2.im, wre, -wim);\ + CMUL(t5, t6, a3.re, a3.im, wre, wim);\ + BUTTERFLIES(a0,a1,a2,a3)\ +} + +#define TRANSFORM_ZERO(a0,a1,a2,a3) {\ + t1 = a2.re;\ + t2 = a2.im;\ + t5 = a3.re;\ + t6 = a3.im;\ + BUTTERFLIES(a0,a1,a2,a3)\ +} + +/* z[0...8n-1], w[1...2n-1] */ +#define PASS(name)\ +static void name(FFTComplex *z, const FFTSample *wre, unsigned int n)\ +{\ + FFTSample t1, t2, t3, t4, t5, t6;\ + int o1 = 2*n;\ + int o2 = 4*n;\ + int o3 = 6*n;\ + const FFTSample *wim = wre+o1;\ + n--;\ +\ + TRANSFORM_ZERO(z[0],z[o1],z[o2],z[o3]);\ + TRANSFORM(z[1],z[o1+1],z[o2+1],z[o3+1],wre[1],wim[-1]);\ + do {\ + z += 2;\ + wre += 2;\ + wim -= 2;\ + TRANSFORM(z[0],z[o1],z[o2],z[o3],wre[0],wim[0]);\ + TRANSFORM(z[1],z[o1+1],z[o2+1],z[o3+1],wre[1],wim[-1]);\ + } while(--n);\ +} + +PASS(pass) +#undef BUTTERFLIES +#define BUTTERFLIES BUTTERFLIES_BIG +PASS(pass_big) + +#define DECL_FFT(n,n2,n4)\ +static void fft##n(FFTComplex *z)\ +{\ + fft##n2(z);\ + fft##n4(z+n4*2);\ + fft##n4(z+n4*3);\ + pass(z,FFT_NAME(ff_cos_##n),n4/2);\ +} + +static void fft4(FFTComplex *z) +{ + FFTSample t1, t2, t3, t4, t5, t6, t7, t8; + + BF(t3, t1, z[0].re, z[1].re); + BF(t8, t6, z[3].re, z[2].re); + BF(z[2].re, z[0].re, t1, t6); + BF(t4, t2, z[0].im, z[1].im); + BF(t7, t5, z[2].im, z[3].im); + BF(z[3].im, z[1].im, t4, t8); + BF(z[3].re, z[1].re, t3, t7); + BF(z[2].im, z[0].im, t2, t5); +} + +static void fft8(FFTComplex *z) +{ + FFTSample t1, t2, t3, t4, t5, t6; + + fft4(z); + + BF(t1, z[5].re, z[4].re, -z[5].re); + BF(t2, z[5].im, z[4].im, -z[5].im); + BF(t5, z[7].re, z[6].re, -z[7].re); + BF(t6, z[7].im, z[6].im, -z[7].im); + + BUTTERFLIES(z[0],z[2],z[4],z[6]); + TRANSFORM(z[1],z[3],z[5],z[7],M_SQRT1_2,M_SQRT1_2); +} + +static void fft16(FFTComplex *z) +{ + FFTSample t1, t2, t3, t4, t5, t6; + FFTSample cos_16_1 = FFT_NAME(ff_cos_16)[1]; + FFTSample cos_16_3 = FFT_NAME(ff_cos_16)[3]; + + fft8(z); + fft4(z+8); + fft4(z+12); + + TRANSFORM_ZERO(z[0],z[4],z[8],z[12]); + TRANSFORM(z[2],z[6],z[10],z[14],M_SQRT1_2,M_SQRT1_2); + TRANSFORM(z[1],z[5],z[9],z[13],cos_16_1,cos_16_3); + TRANSFORM(z[3],z[7],z[11],z[15],cos_16_3,cos_16_1); +} + +DECL_FFT(32,16,8) +DECL_FFT(64,32,16) +DECL_FFT(128,64,32) +DECL_FFT(256,128,64) +DECL_FFT(512,256,128) +#define pass pass_big +DECL_FFT(1024,512,256) +DECL_FFT(2048,1024,512) +DECL_FFT(4096,2048,1024) +DECL_FFT(8192,4096,2048) +DECL_FFT(16384,8192,4096) +DECL_FFT(32768,16384,8192) +DECL_FFT(65536,32768,16384) +DECL_FFT(131072,65536,32768) + +static void (* const fft_dispatch[])(FFTComplex*) = { + fft4, fft8, fft16, fft32, fft64, fft128, fft256, fft512, fft1024, + fft2048, fft4096, fft8192, fft16384, fft32768, fft65536, fft131072 +}; + +#define DECL_COMP_FFT(N) \ +static void compound_fft_##N##xM(AVTXContext *s, void *_out, \ + void *_in, ptrdiff_t stride) \ +{ \ + const int m = s->m, *in_map = s->pfatab, *out_map = in_map + N*m; \ + FFTComplex *in = _in; \ + FFTComplex *out = _out; \ + FFTComplex fft##N##in[N]; \ + void (*fftp)(FFTComplex *z) = fft_dispatch[av_log2(m) - 2]; \ + \ + for (int i = 0; i < m; i++) { \ + for (int j = 0; j < N; j++) \ + fft##N##in[j] = in[in_map[i*N + j]]; \ + fft##N(s->tmp + s->revtab[i], fft##N##in, m); \ + } \ + \ + for (int i = 0; i < N; i++) \ + fftp(s->tmp + m*i); \ + \ + for (int i = 0; i < N*m; i++) \ + out[i] = s->tmp[out_map[i]]; \ +} + +DECL_COMP_FFT(3) +DECL_COMP_FFT(5) +DECL_COMP_FFT(15) + +static void monolithic_fft(AVTXContext *s, void *_out, void *_in, + ptrdiff_t stride) +{ + FFTComplex *in = _in; + FFTComplex *out = _out; + int m = s->m, mb = av_log2(m) - 2; + for (int i = 0; i < m; i++) + out[s->revtab[i]] = in[i]; + fft_dispatch[mb](out); +} + +#define DECL_COMP_IMDCT(N) \ +static void compound_imdct_##N##xM(AVTXContext *s, void *_dst, void *_src, \ + ptrdiff_t stride) \ +{ \ + FFTComplex fft##N##in[N]; \ + FFTComplex *z = _dst, *exp = s->exptab; \ + const int m = s->m, len8 = N*m >> 1; \ + const int *in_map = s->pfatab, *out_map = in_map + N*m; \ + const float *src = _src, *in1, *in2; \ + void (*fftp)(FFTComplex *) = fft_dispatch[av_log2(m) - 2]; \ + \ + stride /= sizeof(*src); /* To convert it from bytes */ \ + in1 = src; \ + in2 = src + ((N*m*2) - 1) * stride; \ + \ + for (int i = 0; i < m; i++) { \ + for (int j = 0; j < N; j++) { \ + const int k = in_map[i*N + j]; \ + FFTComplex tmp = { in2[-k*stride], in1[k*stride] }; \ + CMUL3(fft##N##in[j], tmp, exp[k >> 1]); \ + } \ + fft##N(s->tmp + s->revtab[i], fft##N##in, m); \ + } \ + \ + for (int i = 0; i < N; i++) \ + fftp(s->tmp + m*i); \ + \ + for (int i = 0; i < len8; i++) { \ + const int i0 = len8 + i, i1 = len8 - i - 1; \ + const int s0 = out_map[i0], s1 = out_map[i1]; \ + FFTComplex src1 = { s->tmp[s1].im, s->tmp[s1].re }; \ + FFTComplex src0 = { s->tmp[s0].im, s->tmp[s0].re }; \ + \ + CMUL(z[i1].re, z[i0].im, src1.re, src1.im, exp[i1].im, exp[i1].re); \ + CMUL(z[i0].re, z[i1].im, src0.re, src0.im, exp[i0].im, exp[i0].re); \ + } \ +} + +DECL_COMP_IMDCT(3) +DECL_COMP_IMDCT(5) +DECL_COMP_IMDCT(15) + +#define DECL_COMP_MDCT(N) \ +static void compound_mdct_##N##xM(AVTXContext *s, void *_dst, void *_src, \ + ptrdiff_t stride) \ +{ \ + float *src = _src, *dst = _dst; \ + FFTComplex *exp = s->exptab, tmp, fft##N##in[N]; \ + const int m = s->m, len4 = N*m, len3 = len4 * 3, len8 = len4 >> 1; \ + const int *in_map = s->pfatab, *out_map = in_map + N*m; \ + void (*fftp)(FFTComplex *) = fft_dispatch[av_log2(m) - 2]; \ + \ + stride /= sizeof(*dst); \ + \ + for (int i = 0; i < m; i++) { /* Folding and pre-reindexing */ \ + for (int j = 0; j < N; j++) { \ + const int k = in_map[i*N + j]; \ + if (k < len4) { \ + tmp.re = -src[ len4 + k] + src[1*len4 - 1 - k]; \ + tmp.im = -src[ len3 + k] - src[1*len3 - 1 - k]; \ + } else { \ + tmp.re = -src[ len4 + k] - src[5*len4 - 1 - k]; \ + tmp.im = src[-len4 + k] - src[1*len3 - 1 - k]; \ + } \ + CMUL(fft##N##in[j].im, fft##N##in[j].re, tmp.re, tmp.im, \ + exp[k >> 1].re, exp[k >> 1].im); \ + } \ + fft##N(s->tmp + s->revtab[i], fft##N##in, m); \ + } \ + \ + for (int i = 0; i < N; i++) \ + fftp(s->tmp + m*i); \ + \ + for (int i = 0; i < len8; i++) { \ + const int i0 = len8 + i, i1 = len8 - i - 1; \ + const int s0 = out_map[i0], s1 = out_map[i1]; \ + FFTComplex src1 = { s->tmp[s1].re, s->tmp[s1].im }; \ + FFTComplex src0 = { s->tmp[s0].re, s->tmp[s0].im }; \ + \ + CMUL(dst[2*i1*stride + stride], dst[2*i0*stride], src0.re, src0.im, \ + exp[i0].im, exp[i0].re); \ + CMUL(dst[2*i0*stride + stride], dst[2*i1*stride], src1.re, src1.im, \ + exp[i1].im, exp[i1].re); \ + } \ +} + +DECL_COMP_MDCT(3) +DECL_COMP_MDCT(5) +DECL_COMP_MDCT(15) + +static void monolithic_imdct(AVTXContext *s, void *_dst, void *_src, + ptrdiff_t stride) +{ + FFTComplex *z = _dst, *exp = s->exptab; + const int m = s->m, len8 = m >> 1; + const float *src = _src, *in1, *in2; + void (*fftp)(FFTComplex *) = fft_dispatch[av_log2(m) - 2]; + + stride /= sizeof(*src); + in1 = src; + in2 = src + ((m*2) - 1) * stride; + + for (int i = 0; i < m; i++) { + FFTComplex tmp = { in2[-2*i*stride], in1[2*i*stride] }; + CMUL3(z[s->revtab[i]], tmp, exp[i]); + } + + fftp(z); + + for (int i = 0; i < len8; i++) { + const int i0 = len8 + i, i1 = len8 - i - 1; + FFTComplex src1 = { z[i1].im, z[i1].re }; + FFTComplex src0 = { z[i0].im, z[i0].re }; + + CMUL(z[i1].re, z[i0].im, src1.re, src1.im, exp[i1].im, exp[i1].re); + CMUL(z[i0].re, z[i1].im, src0.re, src0.im, exp[i0].im, exp[i0].re); + } +} + +static void monolithic_mdct(AVTXContext *s, void *_dst, void *_src, + ptrdiff_t stride) +{ + float *src = _src, *dst = _dst; + FFTComplex *exp = s->exptab, tmp, *z = _dst; + const int m = s->m, len4 = m, len3 = len4 * 3, len8 = len4 >> 1; + void (*fftp)(FFTComplex *) = fft_dispatch[av_log2(m) - 2]; + + stride /= sizeof(*dst); + + for (int i = 0; i < m; i++) { /* Folding and pre-reindexing */ + const int k = 2*i; + if (k < len4) { + tmp.re = -src[ len4 + k] + src[1*len4 - 1 - k]; + tmp.im = -src[ len3 + k] - src[1*len3 - 1 - k]; + } else { + tmp.re = -src[ len4 + k] - src[5*len4 - 1 - k]; + tmp.im = src[-len4 + k] - src[1*len3 - 1 - k]; + } + CMUL(z[s->revtab[i]].im, z[s->revtab[i]].re, tmp.re, tmp.im, + exp[i].re, exp[i].im); + } + + fftp(z); + + for (int i = 0; i < len8; i++) { + const int i0 = len8 + i, i1 = len8 - i - 1; + FFTComplex src1 = { z[i1].re, z[i1].im }; + FFTComplex src0 = { z[i0].re, z[i0].im }; + + CMUL(dst[2*i1*stride + stride], dst[2*i0*stride], src0.re, src0.im, + exp[i0].im, exp[i0].re); + CMUL(dst[2*i0*stride + stride], dst[2*i1*stride], src1.re, src1.im, + exp[i1].im, exp[i1].re); + } +} + +/* Calculates the modular multiplicative inverse, not fast, replace */ +static int mulinv(int n, int m) +{ + n = n % m; + for (int x = 1; x < m; x++) + if (((n * x) % m) == 1) + return x; + av_assert0(0); /* Never reached */ +} + +/* Guaranteed to work for any n, m where gcd(n, m) == 1 */ +static int gen_compound_mapping(AVTXContext *s, int n, int m, int inv, + enum AVTXType type) +{ + int *in_map, *out_map; + const int len = n*m; + const int m_inv = mulinv(m, n); + const int n_inv = mulinv(n, m); + const int mdct = type == AV_TX_FLOAT_MDCT; + + if (!(s->pfatab = av_malloc(2*len*sizeof(*s->pfatab)))) + return AVERROR(ENOMEM); + + in_map = s->pfatab; + out_map = s->pfatab + n*m; + + /* Ruritanian map for input, CRT map for output, can be swapped */ + for (int j = 0; j < m; j++) { + for (int i = 0; i < n; i++) { + /* Shifted by 1 to simplify forward MDCTs */ + in_map[j*n + i] = ((i*m + j*n) % len) << mdct; + out_map[(i*m*m_inv + j*n*n_inv) % len] = i*m + j; + } + } + + /* Change transform direction by reversing all ACs */ + if (inv) { + for (int i = 0; i < m; i++) { + int *in = &in_map[i*n + 1]; /* Skip the DC */ + for (int j = 0; j < ((n - 1) >> 1); j++) + FFSWAP(int, in[j], in[n - j - 2]); + } + } + + /* Our 15-point transform is also a compound one, so embed its input map */ + if (n == 15) { + for (int k = 0; k < m; k++) { + int tmp[15]; + memcpy(tmp, &in_map[k*15], 15*sizeof(*tmp)); + for (int i = 0; i < 5; i++) { + for (int j = 0; j < 3; j++) + in_map[k*15 + i*3 + j] = tmp[(i*3 + j*5) % 15]; + } + } + } + + return 0; +} + +static int split_radix_permutation(int i, int n, int inverse) +{ + int m; + if (n <= 2) + return i & 1; + m = n >> 1; + if (!(i & m)) + return split_radix_permutation(i, m, inverse)*2; + m >>= 1; + if (inverse == !(i & m)) + return split_radix_permutation(i, m, inverse)*4 + 1; + else + return split_radix_permutation(i, m, inverse)*4 - 1; +} + +static int get_ptwo_revtab(AVTXContext *s, int m, int inv) +{ + if (!(s->revtab = av_malloc(m*sizeof(*s->revtab)))) + return AVERROR(ENOMEM); + + /* Default */ + for (int i = 0; i < m; i++) { + int k = -split_radix_permutation(i, m, inv) & (m - 1); + s->revtab[k] = i; + } + + return 0; +} + +static int gen_mdct_exptab(AVTXContext *s, int len4, double scale) +{ + const double theta = (scale < 0 ? len4 : 0) + 1.0/8.0; + + if (!(s->exptab = av_malloc_array(len4, sizeof(*s->exptab)))) + return AVERROR(ENOMEM); + + scale = sqrt(fabs(scale)); + for (int i = 0; i < len4; i++) { + const double alpha = M_PI_2 * (i + theta) / len4; + s->exptab[i].re = cos(alpha) * scale; + s->exptab[i].im = sin(alpha) * scale; + } + + return 0; +} + +av_cold void av_tx_uninit(AVTXContext **ctx) +{ + if (!(*ctx)) + return; + + av_free((*ctx)->pfatab); + av_free((*ctx)->exptab); + av_free((*ctx)->revtab); + av_free((*ctx)->tmp); + + av_freep(ctx); +} + +static int init_mdct_fft(AVTXContext *s, av_tx_fn *tx, enum AVTXType type, + int inv, int len, const void *scale, uint64_t flags) +{ + int err, n = 1, m = 1, max_ptwo = 1 << (FF_ARRAY_ELEMS(fft_dispatch) + 1); + + if (type == AV_TX_FLOAT_MDCT) + len >>= 1; + +#define CHECK_FACTOR(DST, FACTOR, SRC) \ + if (DST == 1 && !(SRC % FACTOR)) { \ + DST = FACTOR; \ + SRC /= FACTOR; \ + } + CHECK_FACTOR(n, 15, len) + CHECK_FACTOR(n, 5, len) + CHECK_FACTOR(n, 3, len) +#undef CHECK_NPTWO_FACTOR + + /* len must be a power of two now */ + if (!(len & (len - 1)) && len >= 4 && len <= max_ptwo) { + m = len; + len = 1; + } + + /* Filter out direct 3, 5 and 15 transforms, too niche */ + if (len > 1 || m == 1) { + av_log(NULL, AV_LOG_ERROR, "Unsupported transform size: n = %i, " + "m = %i, residual = %i!\n", n, m, len); + return AVERROR(EINVAL); + } else if (n > 1 && m > 1) { /* 2D transform case */ + if ((err = gen_compound_mapping(s, n, m, inv, type))) + return err; + if (!(s->tmp = av_malloc(n*m*sizeof(*s->tmp)))) + return AVERROR(ENOMEM); + *tx = n == 3 ? compound_fft_3xM : + n == 5 ? compound_fft_5xM : + compound_fft_15xM; + if (type == AV_TX_FLOAT_MDCT) + *tx = n == 3 ? inv ? compound_imdct_3xM : compound_mdct_3xM : + n == 5 ? inv ? compound_imdct_5xM : compound_mdct_5xM : + inv ? compound_imdct_15xM : compound_mdct_15xM; + } else { /* Direct transform case */ + *tx = monolithic_fft; + if (type == AV_TX_FLOAT_MDCT) + *tx = inv ? monolithic_imdct : monolithic_mdct; + } + + if (n != 1) + ff_thread_once(&tabs_53_once, ff_init_53_tabs); + if (m != 1) { + get_ptwo_revtab(s, m, inv); + for (int i = 4; i <= av_log2(m); i++) + ff_init_ff_cos_tabs(i); + } + + if (type == AV_TX_FLOAT_MDCT) + if ((err = gen_mdct_exptab(s, n*m, *((float *)scale)))) + return err; + + s->n = n; + s->m = m; + + return 0; +} + +av_cold int av_tx_init(AVTXContext **ctx, av_tx_fn *tx, enum AVTXType type, + int inv, int len, const void *scale, uint64_t flags) +{ + int err; + AVTXContext *s = av_mallocz(sizeof(*s)); + if (!s) + return AVERROR(ENOMEM); + + switch (type) { + case AV_TX_FLOAT_FFT: + case AV_TX_FLOAT_MDCT: + if ((err = init_mdct_fft(s, tx, type, inv, len, scale, flags))) + goto fail; + break; + default: + err = AVERROR(EINVAL); + goto fail; + } + + *ctx = s; + + return 0; + +fail: + av_tx_uninit(&s); + *tx = NULL; + return err; +} diff --git a/libavutil/tx.h b/libavutil/tx.h new file mode 100644 index 000000000..b1f2d9635 --- /dev/null +++ b/libavutil/tx.h @@ -0,0 +1,81 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_TX_H +#define AVUTIL_TX_H + +#include +#include + +typedef struct AVTXContext AVTXContext; + +typedef struct AVComplexFloat { + float re, im; +} AVComplexFloat; + +enum AVTXType { + /** + * Standard complex to complex FFT with sample data type AVComplexFloat. + * Scaling currently unsupported + */ + AV_TX_FLOAT_FFT = 0, + /** + * Standard MDCT with sample data type of float and a scale type of + * float. Length is the frame size, not the window size (which is 2x frame) + */ + AV_TX_FLOAT_MDCT = 1, +}; + +/** + * Function pointer to a function to perform the transform. + * + * @note Using a different context than the one allocated during av_tx_init() + * is not allowed. + * + * @param s the transform context + * @param out the output array + * @param in the input array + * @param stride the input or output stride (depending on transform direction) + * in bytes, currently implemented for all MDCT transforms + */ +typedef void (*av_tx_fn)(AVTXContext *s, void *out, void *in, ptrdiff_t stride); + +/** + * Initialize a transform context with the given configuration + * Currently power of two lengths from 4 to 131072 are supported, along with + * any length decomposable to a power of two and either 3, 5 or 15. + * + * @param ctx the context to allocate, will be NULL on error + * @param tx pointer to the transform function pointer to set + * @param type type the type of transform + * @param inv whether to do an inverse or a forward transform + * @param len the size of the transform in samples + * @param scale pointer to the value to scale the output if supported by type + * @param flags currently unused + * + * @return 0 on success, negative error code on failure + */ +int av_tx_init(AVTXContext **ctx, av_tx_fn *tx, enum AVTXType type, + int inv, int len, const void *scale, uint64_t flags); + +/** + * Frees a context and sets ctx to NULL, does nothing when ctx == NULL + */ +void av_tx_uninit(AVTXContext **ctx); + +#endif /* AVUTIL_TX_H */ diff --git a/libavutil/version.h b/libavutil/version.h index 3a63e6355..24ca8ab7d 100644 --- a/libavutil/version.h +++ b/libavutil/version.h @@ -79,7 +79,7 @@ */ #define LIBAVUTIL_VERSION_MAJOR 56 -#define LIBAVUTIL_VERSION_MINOR 14 +#define LIBAVUTIL_VERSION_MINOR 31 #define LIBAVUTIL_VERSION_MICRO 100 #define LIBAVUTIL_VERSION_INT AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \ diff --git a/libavutil/x86/cpu.c b/libavutil/x86/cpu.c index aca893174..bcd41a50a 100644 --- a/libavutil/x86/cpu.c +++ b/libavutil/x86/cpu.c @@ -127,7 +127,7 @@ int ff_get_cpu_flags_x86(void) rval |= AV_CPU_FLAG_SSE4; if (ecx & 0x00100000 ) rval |= AV_CPU_FLAG_SSE42; - if (ecx & 0x01000000 ) + if (ecx & 0x02000000 ) rval |= AV_CPU_FLAG_AESNI; #if HAVE_AVX /* Check OXSAVE and AVX bits */ diff --git a/libavutil/x86/float_dsp.asm b/libavutil/x86/float_dsp.asm index 06d2d2cfd..517fd6363 100644 --- a/libavutil/x86/float_dsp.asm +++ b/libavutil/x86/float_dsp.asm @@ -58,6 +58,39 @@ INIT_YMM avx VECTOR_FMUL %endif +;----------------------------------------------------------------------------- +; void vector_dmul(double *dst, const double *src0, const double *src1, int len) +;----------------------------------------------------------------------------- +%macro VECTOR_DMUL 0 +cglobal vector_dmul, 4,4,4, dst, src0, src1, len + lea lend, [lenq*8 - mmsize*4] +ALIGN 16 +.loop: + movaps m0, [src0q + lenq + 0*mmsize] + movaps m1, [src0q + lenq + 1*mmsize] + movaps m2, [src0q + lenq + 2*mmsize] + movaps m3, [src0q + lenq + 3*mmsize] + mulpd m0, m0, [src1q + lenq + 0*mmsize] + mulpd m1, m1, [src1q + lenq + 1*mmsize] + mulpd m2, m2, [src1q + lenq + 2*mmsize] + mulpd m3, m3, [src1q + lenq + 3*mmsize] + movaps [dstq + lenq + 0*mmsize], m0 + movaps [dstq + lenq + 1*mmsize], m1 + movaps [dstq + lenq + 2*mmsize], m2 + movaps [dstq + lenq + 3*mmsize], m3 + + sub lenq, mmsize*4 + jge .loop + RET +%endmacro + +INIT_XMM sse2 +VECTOR_DMUL +%if HAVE_AVX_EXTERNAL +INIT_YMM avx +VECTOR_DMUL +%endif + ;------------------------------------------------------------------------------ ; void ff_vector_fmac_scalar(float *dst, const float *src, float mul, int len) ;------------------------------------------------------------------------------ diff --git a/libavutil/x86/float_dsp_init.c b/libavutil/x86/float_dsp_init.c index 122087a19..8826e4e2c 100644 --- a/libavutil/x86/float_dsp_init.c +++ b/libavutil/x86/float_dsp_init.c @@ -29,6 +29,11 @@ void ff_vector_fmul_sse(float *dst, const float *src0, const float *src1, void ff_vector_fmul_avx(float *dst, const float *src0, const float *src1, int len); +void ff_vector_dmul_sse2(double *dst, const double *src0, const double *src1, + int len); +void ff_vector_dmul_avx(double *dst, const double *src0, const double *src1, + int len); + void ff_vector_fmac_scalar_sse(float *dst, const float *src, float mul, int len); void ff_vector_fmac_scalar_avx(float *dst, const float *src, float mul, @@ -92,11 +97,13 @@ av_cold void ff_float_dsp_init_x86(AVFloatDSPContext *fdsp) fdsp->butterflies_float = ff_butterflies_float_sse; } if (EXTERNAL_SSE2(cpu_flags)) { + fdsp->vector_dmul = ff_vector_dmul_sse2; fdsp->vector_dmac_scalar = ff_vector_dmac_scalar_sse2; fdsp->vector_dmul_scalar = ff_vector_dmul_scalar_sse2; } if (EXTERNAL_AVX_FAST(cpu_flags)) { fdsp->vector_fmul = ff_vector_fmul_avx; + fdsp->vector_dmul = ff_vector_dmul_avx; fdsp->vector_fmac_scalar = ff_vector_fmac_scalar_avx; fdsp->vector_dmul_scalar = ff_vector_dmul_scalar_avx; fdsp->vector_dmac_scalar = ff_vector_dmac_scalar_avx; diff --git a/libavutil/x86/pixelutils.asm b/libavutil/x86/pixelutils.asm index 7af3007d0..36c57c5f7 100644 --- a/libavutil/x86/pixelutils.asm +++ b/libavutil/x86/pixelutils.asm @@ -104,8 +104,8 @@ cglobal pixelutils_sad_16x16, 4,4,0, src1, stride1, src2, stride2 RET ;------------------------------------------------------------------------------- -; int ff_pixelutils_sad_16x16_sse(const uint8_t *src1, ptrdiff_t stride1, -; const uint8_t *src2, ptrdiff_t stride2); +; int ff_pixelutils_sad_16x16_sse2(const uint8_t *src1, ptrdiff_t stride1, +; const uint8_t *src2, ptrdiff_t stride2); ;------------------------------------------------------------------------------- INIT_XMM sse2 cglobal pixelutils_sad_16x16, 4,4,5, src1, stride1, src2, stride2 @@ -134,8 +134,8 @@ cglobal pixelutils_sad_16x16, 4,4,5, src1, stride1, src2, stride2 RET ;------------------------------------------------------------------------------- -; int ff_pixelutils_sad_[au]_16x16_sse(const uint8_t *src1, ptrdiff_t stride1, -; const uint8_t *src2, ptrdiff_t stride2); +; int ff_pixelutils_sad_[au]_16x16_sse2(const uint8_t *src1, ptrdiff_t stride1, +; const uint8_t *src2, ptrdiff_t stride2); ;------------------------------------------------------------------------------- %macro SAD_XMM_16x16 1 INIT_XMM sse2 @@ -163,3 +163,224 @@ cglobal pixelutils_sad_%1_16x16, 4,4,3, src1, stride1, src2, stride2 SAD_XMM_16x16 a SAD_XMM_16x16 u + + +%macro PROCESS_SAD_32x4_U 0 + movu m1, [r2] + movu m2, [r2 + 16] + movu m3, [r0] + movu m4, [r0 + 16] + psadbw m1, m3 + psadbw m2, m4 + paddd m1, m2 + paddd m0, m1 + lea r2, [r2 + r3] + lea r0, [r0 + r1] + + movu m1, [r2] + movu m2, [r2 + 16] + movu m3, [r0] + movu m4, [r0 + 16] + psadbw m1, m3 + psadbw m2, m4 + paddd m1, m2 + paddd m0, m1 + lea r2, [r2 + r3] + lea r0, [r0 + r1] + + movu m1, [r2] + movu m2, [r2 + 16] + movu m3, [r0] + movu m4, [r0 + 16] + psadbw m1, m3 + psadbw m2, m4 + paddd m1, m2 + paddd m0, m1 + lea r2, [r2 + r3] + lea r0, [r0 + r1] + + movu m1, [r2] + movu m2, [r2 + 16] + movu m3, [r0] + movu m4, [r0 + 16] + psadbw m1, m3 + psadbw m2, m4 + paddd m1, m2 + paddd m0, m1 + lea r2, [r2 + r3] + lea r0, [r0 + r1] +%endmacro + +%macro PROCESS_SAD_32x4 1 + mov%1 m1, [r2] + mov%1 m2, [r2 + 16] + psadbw m1, [r0] + psadbw m2, [r0 + 16] + paddd m1, m2 + paddd m0, m1 + lea r2, [r2 + r3] + lea r0, [r0 + r1] + + mov%1 m1, [r2] + mov%1 m2, [r2 + 16] + psadbw m1, [r0] + psadbw m2, [r0 + 16] + paddd m1, m2 + paddd m0, m1 + lea r2, [r2 + r3] + lea r0, [r0 + r1] + + mov%1 m1, [r2] + mov%1 m2, [r2 + 16] + psadbw m1, [r0] + psadbw m2, [r0 + 16] + paddd m1, m2 + paddd m0, m1 + lea r2, [r2 + r3] + lea r0, [r0 + r1] + + mov%1 m1, [r2] + mov%1 m2, [r2 + 16] + psadbw m1, [r0] + psadbw m2, [r0 + 16] + paddd m1, m2 + paddd m0, m1 + lea r2, [r2 + r3] + lea r0, [r0 + r1] +%endmacro + +;----------------------------------------------------------------------------- +; int ff_pixelutils_sad_32x32_sse2(const uint8_t *src1, ptrdiff_t stride1, +; const uint8_t *src2, ptrdiff_t stride2); +;----------------------------------------------------------------------------- +INIT_XMM sse2 +cglobal pixelutils_sad_32x32, 4,5,5, src1, stride1, src2, stride2 + pxor m0, m0 + mov r4d, 4 +.loop: + PROCESS_SAD_32x4_U + PROCESS_SAD_32x4_U + dec r4d + jnz .loop + + movhlps m1, m0 + paddd m0, m1 + movd eax, m0 + RET + +;------------------------------------------------------------------------------- +; int ff_pixelutils_sad_[au]_32x32_sse2(const uint8_t *src1, ptrdiff_t stride1, +; const uint8_t *src2, ptrdiff_t stride2); +;------------------------------------------------------------------------------- +%macro SAD_XMM_32x32 1 +INIT_XMM sse2 +cglobal pixelutils_sad_%1_32x32, 4,5,3, src1, stride1, src2, stride2 + pxor m0, m0 + mov r4d, 4 +.loop: + PROCESS_SAD_32x4 %1 + PROCESS_SAD_32x4 %1 + dec r4d + jnz .loop + + movhlps m1, m0 + paddd m0, m1 + movd eax, m0 + RET +%endmacro + +SAD_XMM_32x32 a +SAD_XMM_32x32 u + +%if HAVE_AVX2_EXTERNAL +;------------------------------------------------------------------------------- +; int ff_pixelutils_sad_32x32_avx2(const uint8_t *src1, ptrdiff_t stride1, +; const uint8_t *src2, ptrdiff_t stride2); +;------------------------------------------------------------------------------- +INIT_YMM avx2 +cglobal pixelutils_sad_32x32, 4,7,5, src1, stride1, src2, stride2 + pxor m0, m0 + mov r4d, 32/4 + lea r5, [stride1q * 3] + lea r6, [stride2q * 3] + +.loop: + movu m1, [src1q] ; row 0 of pix0 + movu m2, [src2q] ; row 0 of pix1 + movu m3, [src1q + stride1q] ; row 1 of pix0 + movu m4, [src2q + stride2q] ; row 1 of pix1 + + psadbw m1, m2 + psadbw m3, m4 + paddd m0, m1 + paddd m0, m3 + + movu m1, [src1q + 2 * stride1q] ; row 2 of pix0 + movu m2, [src2q + 2 * stride2q] ; row 2 of pix1 + movu m3, [src1q + r5] ; row 3 of pix0 + movu m4, [src2q + r6] ; row 3 of pix1 + + psadbw m1, m2 + psadbw m3, m4 + paddd m0, m1 + paddd m0, m3 + + lea src2q, [src2q + 4 * stride2q] + lea src1q, [src1q + 4 * stride1q] + + dec r4d + jnz .loop + + vextracti128 xm1, m0, 1 + paddd xm0, xm1 + pshufd xm1, xm0, 2 + paddd xm0, xm1 + movd eax, xm0 + RET + +;------------------------------------------------------------------------------- +; int ff_pixelutils_sad_[au]_32x32_avx2(const uint8_t *src1, ptrdiff_t stride1, +; const uint8_t *src2, ptrdiff_t stride2); +;------------------------------------------------------------------------------- +%macro SAD_AVX2_32x32 1 +INIT_YMM avx2 +cglobal pixelutils_sad_%1_32x32, 4,7,3, src1, stride1, src2, stride2 + pxor m0, m0 + mov r4d, 32/4 + lea r5, [stride1q * 3] + lea r6, [stride2q * 3] + +.loop: + mov%1 m1, [src2q] ; row 0 of pix1 + psadbw m1, [src1q] + mov%1 m2, [src2q + stride2q] ; row 1 of pix1 + psadbw m2, [src1q + stride1q] + + paddd m0, m1 + paddd m0, m2 + + mov%1 m1, [src2q + 2 * stride2q] ; row 2 of pix1 + psadbw m1, [src1q + 2 * stride1q] + mov%1 m2, [src2q + r6] ; row 3 of pix1 + psadbw m2, [src1q + r5] + + paddd m0, m1 + paddd m0, m2 + + lea src2q, [src2q + 4 * stride2q] + lea src1q, [src1q + 4 * stride1q] + + dec r4d + jnz .loop + + vextracti128 xm1, m0, 1 + paddd xm0, xm1 + pshufd xm1, xm0, 2 + paddd xm0, xm1 + movd eax, xm0 + RET +%endmacro + +SAD_AVX2_32x32 a +SAD_AVX2_32x32 u +%endif diff --git a/libavutil/x86/pixelutils_init.c b/libavutil/x86/pixelutils_init.c index c24a533ae..184a3a4a9 100644 --- a/libavutil/x86/pixelutils_init.c +++ b/libavutil/x86/pixelutils_init.c @@ -35,6 +35,20 @@ int ff_pixelutils_sad_a_16x16_sse2(const uint8_t *src1, ptrdiff_t stride1, int ff_pixelutils_sad_u_16x16_sse2(const uint8_t *src1, ptrdiff_t stride1, const uint8_t *src2, ptrdiff_t stride2); +int ff_pixelutils_sad_32x32_sse2(const uint8_t *src1, ptrdiff_t stride1, + const uint8_t *src2, ptrdiff_t stride2); +int ff_pixelutils_sad_a_32x32_sse2(const uint8_t *src1, ptrdiff_t stride1, + const uint8_t *src2, ptrdiff_t stride2); +int ff_pixelutils_sad_u_32x32_sse2(const uint8_t *src1, ptrdiff_t stride1, + const uint8_t *src2, ptrdiff_t stride2); + +int ff_pixelutils_sad_32x32_avx2(const uint8_t *src1, ptrdiff_t stride1, + const uint8_t *src2, ptrdiff_t stride2); +int ff_pixelutils_sad_a_32x32_avx2(const uint8_t *src1, ptrdiff_t stride1, + const uint8_t *src2, ptrdiff_t stride2); +int ff_pixelutils_sad_u_32x32_avx2(const uint8_t *src1, ptrdiff_t stride1, + const uint8_t *src2, ptrdiff_t stride2); + void ff_pixelutils_sad_init_x86(av_pixelutils_sad_fn *sad, int aligned) { int cpu_flags = av_get_cpu_flags(); @@ -61,4 +75,20 @@ void ff_pixelutils_sad_init_x86(av_pixelutils_sad_fn *sad, int aligned) case 2: sad[3] = ff_pixelutils_sad_a_16x16_sse2; break; // src1 aligned, src2 aligned } } + + if (EXTERNAL_SSE2(cpu_flags)) { + switch (aligned) { + case 0: sad[4] = ff_pixelutils_sad_32x32_sse2; break; // src1 unaligned, src2 unaligned + case 1: sad[4] = ff_pixelutils_sad_u_32x32_sse2; break; // src1 aligned, src2 unaligned + case 2: sad[4] = ff_pixelutils_sad_a_32x32_sse2; break; // src1 aligned, src2 aligned + } + } + + if (EXTERNAL_AVX2_FAST(cpu_flags)) { + switch (aligned) { + case 0: sad[4] = ff_pixelutils_sad_32x32_avx2; break; // src1 unaligned, src2 unaligned + case 1: sad[4] = ff_pixelutils_sad_u_32x32_avx2; break; // src1 aligned, src2 unaligned + case 2: sad[4] = ff_pixelutils_sad_a_32x32_avx2; break; // src1 aligned, src2 aligned + } + } } diff --git a/libpostproc/version.h b/libpostproc/version.h index c6772055a..fa6d12c83 100644 --- a/libpostproc/version.h +++ b/libpostproc/version.h @@ -29,7 +29,7 @@ #include "libavutil/avutil.h" #define LIBPOSTPROC_VERSION_MAJOR 55 -#define LIBPOSTPROC_VERSION_MINOR 1 +#define LIBPOSTPROC_VERSION_MINOR 5 #define LIBPOSTPROC_VERSION_MICRO 100 #define LIBPOSTPROC_VERSION_INT AV_VERSION_INT(LIBPOSTPROC_VERSION_MAJOR, \ diff --git a/libswresample/rematrix.c b/libswresample/rematrix.c index 822773005..6b5feaa07 100644 --- a/libswresample/rematrix.c +++ b/libswresample/rematrix.c @@ -384,8 +384,8 @@ av_cold static int auto_matrix(SwrContext *s) av_cold int swri_rematrix_init(SwrContext *s){ int i, j; - int nb_in = av_get_channel_layout_nb_channels(s->in_ch_layout); - int nb_out = av_get_channel_layout_nb_channels(s->out_ch_layout); + int nb_in = s->used_ch_count; + int nb_out = s->out.ch_count; s->mix_any_f = NULL; diff --git a/libswresample/swresample.c b/libswresample/swresample.c index 6d28e6a79..1ac5ef9a3 100644 --- a/libswresample/swresample.c +++ b/libswresample/swresample.c @@ -164,6 +164,14 @@ av_cold int swr_init(struct SwrContext *s){ return AVERROR(EINVAL); } + if(s-> in_sample_rate <= 0){ + av_log(s, AV_LOG_ERROR, "Requested input sample rate %d is invalid\n", s->in_sample_rate); + return AVERROR(EINVAL); + } + if(s->out_sample_rate <= 0){ + av_log(s, AV_LOG_ERROR, "Requested output sample rate %d is invalid\n", s->out_sample_rate); + return AVERROR(EINVAL); + } s->out.ch_count = s-> user_out_ch_count; s-> in.ch_count = s-> user_in_ch_count; s->used_ch_count = s->user_used_ch_count; diff --git a/libswresample/version.h b/libswresample/version.h index efc462f46..a0b361bc1 100644 --- a/libswresample/version.h +++ b/libswresample/version.h @@ -29,7 +29,7 @@ #include "libavutil/avutil.h" #define LIBSWRESAMPLE_VERSION_MAJOR 3 -#define LIBSWRESAMPLE_VERSION_MINOR 1 +#define LIBSWRESAMPLE_VERSION_MINOR 5 #define LIBSWRESAMPLE_VERSION_MICRO 100 #define LIBSWRESAMPLE_VERSION_INT AV_VERSION_INT(LIBSWRESAMPLE_VERSION_MAJOR, \ diff --git a/libswresample/x86/rematrix_init.c b/libswresample/x86/rematrix_init.c index d71b41a73..d6616f83b 100644 --- a/libswresample/x86/rematrix_init.c +++ b/libswresample/x86/rematrix_init.c @@ -33,8 +33,8 @@ D(int16, sse2) av_cold int swri_rematrix_init_x86(struct SwrContext *s){ #if HAVE_X86ASM int mm_flags = av_get_cpu_flags(); - int nb_in = av_get_channel_layout_nb_channels(s->in_ch_layout); - int nb_out = av_get_channel_layout_nb_channels(s->out_ch_layout); + int nb_in = s->used_ch_count; + int nb_out = s->out.ch_count; int num = nb_in * nb_out; int i,j; diff --git a/libswscale/input.c b/libswscale/input.c index bb2f4933e..064f8da31 100644 --- a/libswscale/input.c +++ b/libswscale/input.c @@ -942,6 +942,30 @@ static av_always_inline void planar_rgb16_to_uv(uint8_t *_dstU, uint8_t *_dstV, } #undef rdpx +static av_always_inline void grayf32ToY16_c(uint8_t *_dst, const uint8_t *_src, const uint8_t *unused1, + const uint8_t *unused2, int width, uint32_t *unused) +{ + int i; + const float *src = (const float *)_src; + uint16_t *dst = (uint16_t *)_dst; + + for (i = 0; i < width; ++i){ + dst[i] = av_clip_uint16(lrintf(65535.0f * src[i])); + } +} + +static av_always_inline void grayf32ToY16_bswap_c(uint8_t *_dst, const uint8_t *_src, const uint8_t *unused1, + const uint8_t *unused2, int width, uint32_t *unused) +{ + int i; + const uint32_t *src = (const uint32_t *)_src; + uint16_t *dst = (uint16_t *)_dst; + + for (i = 0; i < width; ++i){ + dst[i] = av_clip_uint16(lrintf(65535.0f * av_int2float(av_bswap32(src[i])))); + } +} + #define rgb9plus_planar_funcs_endian(nbits, endian_name, endian) \ static void planar_rgb##nbits##endian_name##_to_y(uint8_t *dst, const uint8_t *src[4], \ int w, int32_t *rgb2yuv) \ @@ -996,9 +1020,11 @@ av_cold void ff_sws_init_input_funcs(SwsContext *c) c->chrToYV12 = uyvyToUV_c; break; case AV_PIX_FMT_NV12: + case AV_PIX_FMT_NV24: c->chrToYV12 = nv12ToUV_c; break; case AV_PIX_FMT_NV21: + case AV_PIX_FMT_NV42: c->chrToYV12 = nv21ToUV_c; break; case AV_PIX_FMT_RGB8: @@ -1073,6 +1099,8 @@ av_cold void ff_sws_init_input_funcs(SwsContext *c) case AV_PIX_FMT_YUVA420P10LE: case AV_PIX_FMT_YUVA422P10LE: case AV_PIX_FMT_YUVA444P10LE: + case AV_PIX_FMT_YUVA422P12LE: + case AV_PIX_FMT_YUVA444P12LE: case AV_PIX_FMT_YUVA420P16LE: case AV_PIX_FMT_YUVA422P16LE: case AV_PIX_FMT_YUVA444P16LE: @@ -1103,6 +1131,8 @@ av_cold void ff_sws_init_input_funcs(SwsContext *c) case AV_PIX_FMT_YUVA420P10BE: case AV_PIX_FMT_YUVA422P10BE: case AV_PIX_FMT_YUVA444P10BE: + case AV_PIX_FMT_YUVA422P12BE: + case AV_PIX_FMT_YUVA444P12BE: case AV_PIX_FMT_YUVA420P16BE: case AV_PIX_FMT_YUVA422P16BE: case AV_PIX_FMT_YUVA444P16BE: @@ -1365,6 +1395,7 @@ av_cold void ff_sws_init_input_funcs(SwsContext *c) case AV_PIX_FMT_GRAY9LE: case AV_PIX_FMT_GRAY10LE: case AV_PIX_FMT_GRAY12LE: + case AV_PIX_FMT_GRAY14LE: case AV_PIX_FMT_GRAY16LE: case AV_PIX_FMT_P016LE: @@ -1376,6 +1407,8 @@ av_cold void ff_sws_init_input_funcs(SwsContext *c) case AV_PIX_FMT_YUVA420P10LE: case AV_PIX_FMT_YUVA422P10LE: case AV_PIX_FMT_YUVA444P10LE: + case AV_PIX_FMT_YUVA422P12LE: + case AV_PIX_FMT_YUVA444P12LE: case AV_PIX_FMT_YUVA420P16LE: case AV_PIX_FMT_YUVA422P16LE: case AV_PIX_FMT_YUVA444P16LE: @@ -1404,6 +1437,7 @@ av_cold void ff_sws_init_input_funcs(SwsContext *c) case AV_PIX_FMT_GRAY9BE: case AV_PIX_FMT_GRAY10BE: case AV_PIX_FMT_GRAY12BE: + case AV_PIX_FMT_GRAY14BE: case AV_PIX_FMT_GRAY16BE: case AV_PIX_FMT_P016BE: @@ -1415,6 +1449,8 @@ av_cold void ff_sws_init_input_funcs(SwsContext *c) case AV_PIX_FMT_YUVA420P10BE: case AV_PIX_FMT_YUVA422P10BE: case AV_PIX_FMT_YUVA444P10BE: + case AV_PIX_FMT_YUVA422P12BE: + case AV_PIX_FMT_YUVA444P12BE: case AV_PIX_FMT_YUVA420P16BE: case AV_PIX_FMT_YUVA422P16BE: case AV_PIX_FMT_YUVA444P16BE: @@ -1536,6 +1572,20 @@ av_cold void ff_sws_init_input_funcs(SwsContext *c) case AV_PIX_FMT_P010BE: c->lumToYV12 = p010BEToY_c; break; + case AV_PIX_FMT_GRAYF32LE: +#if HAVE_BIGENDIAN + c->lumToYV12 = grayf32ToY16_bswap_c; +#else + c->lumToYV12 = grayf32ToY16_c; +#endif + break; + case AV_PIX_FMT_GRAYF32BE: +#if HAVE_BIGENDIAN + c->lumToYV12 = grayf32ToY16_c; +#else + c->lumToYV12 = grayf32ToY16_bswap_c; +#endif + break; } if (c->needAlpha) { if (is16BPS(srcFormat) || isNBPS(srcFormat)) { diff --git a/libswscale/output.c b/libswscale/output.c index 0af2fffea..26b0ff3d4 100644 --- a/libswscale/output.c +++ b/libswscale/output.c @@ -208,6 +208,105 @@ static void yuv2p016cX_c(SwsContext *c, const int16_t *chrFilter, int chrFilterS } } +static av_always_inline void +yuv2plane1_float_c_template(const int32_t *src, float *dest, int dstW) +{ + static const int big_endian = HAVE_BIGENDIAN; + static const int shift = 3; + static const float float_mult = 1.0f / 65535.0f; + int i, val; + uint16_t val_uint; + + for (i = 0; i < dstW; ++i){ + val = src[i] + (1 << (shift - 1)); + output_pixel(&val_uint, val, 0, uint); + dest[i] = float_mult * (float)val_uint; + } +} + +static av_always_inline void +yuv2plane1_float_bswap_c_template(const int32_t *src, uint32_t *dest, int dstW) +{ + static const int big_endian = HAVE_BIGENDIAN; + static const int shift = 3; + static const float float_mult = 1.0f / 65535.0f; + int i, val; + uint16_t val_uint; + + for (i = 0; i < dstW; ++i){ + val = src[i] + (1 << (shift - 1)); + output_pixel(&val_uint, val, 0, uint); + dest[i] = av_bswap32(av_float2int(float_mult * (float)val_uint)); + } +} + +static av_always_inline void +yuv2planeX_float_c_template(const int16_t *filter, int filterSize, const int32_t **src, + float *dest, int dstW) +{ + static const int big_endian = HAVE_BIGENDIAN; + static const int shift = 15; + static const float float_mult = 1.0f / 65535.0f; + int i, j, val; + uint16_t val_uint; + + for (i = 0; i < dstW; ++i){ + val = (1 << (shift - 1)) - 0x40000000; + for (j = 0; j < filterSize; ++j){ + val += src[j][i] * (unsigned)filter[j]; + } + output_pixel(&val_uint, val, 0x8000, int); + dest[i] = float_mult * (float)val_uint; + } +} + +static av_always_inline void +yuv2planeX_float_bswap_c_template(const int16_t *filter, int filterSize, const int32_t **src, + uint32_t *dest, int dstW) +{ + static const int big_endian = HAVE_BIGENDIAN; + static const int shift = 15; + static const float float_mult = 1.0f / 65535.0f; + int i, j, val; + uint16_t val_uint; + + for (i = 0; i < dstW; ++i){ + val = (1 << (shift - 1)) - 0x40000000; + for (j = 0; j < filterSize; ++j){ + val += src[j][i] * (unsigned)filter[j]; + } + output_pixel(&val_uint, val, 0x8000, int); + dest[i] = av_bswap32(av_float2int(float_mult * (float)val_uint)); + } +} + +#define yuv2plane1_float(template, dest_type, BE_LE) \ +static void yuv2plane1_float ## BE_LE ## _c(const int16_t *src, uint8_t *dest, int dstW, \ + const uint8_t *dither, int offset) \ +{ \ + template((const int32_t *)src, (dest_type *)dest, dstW); \ +} + +#define yuv2planeX_float(template, dest_type, BE_LE) \ +static void yuv2planeX_float ## BE_LE ## _c(const int16_t *filter, int filterSize, \ + const int16_t **src, uint8_t *dest, int dstW, \ + const uint8_t *dither, int offset) \ +{ \ + template(filter, filterSize, (const int32_t **)src, (dest_type *)dest, dstW); \ +} + +#if HAVE_BIGENDIAN +yuv2plane1_float(yuv2plane1_float_c_template, float, BE) +yuv2plane1_float(yuv2plane1_float_bswap_c_template, uint32_t, LE) +yuv2planeX_float(yuv2planeX_float_c_template, float, BE) +yuv2planeX_float(yuv2planeX_float_bswap_c_template, uint32_t, LE) +#else +yuv2plane1_float(yuv2plane1_float_c_template, float, LE) +yuv2plane1_float(yuv2plane1_float_bswap_c_template, uint32_t, BE) +yuv2planeX_float(yuv2planeX_float_c_template, float, LE) +yuv2planeX_float(yuv2planeX_float_bswap_c_template, uint32_t, BE) +#endif + #undef output_pixel #define output_pixel(pos, val) \ @@ -311,7 +410,8 @@ static void yuv2nv12cX_c(SwsContext *c, const int16_t *chrFilter, int chrFilterS const uint8_t *chrDither = c->chrDither8; int i; - if (dstFormat == AV_PIX_FMT_NV12) + if (dstFormat == AV_PIX_FMT_NV12 || + dstFormat == AV_PIX_FMT_NV24) for (i=0; i>= 15; + Y = av_clip_uint16(Y); + + if (hasAlpha) { + for (j = 0; j < lumFilterSize; j++) + A += alpSrc[j][i] * lumFilter[j]; + + A >>= 15; + A = av_clip_uint16(A); + } + + output_pixel(&dest[2 * i ], Y); + output_pixel(&dest[2 * i + 1], hasAlpha ? A : 65535); + } +} + +static av_always_inline void +yuv2ya16_2_c_template(SwsContext *c, const int32_t *buf[2], + const int32_t *unused_ubuf[2], const int32_t *unused_vbuf[2], + const int32_t *abuf[2], uint16_t *dest, int dstW, + int yalpha, int unused_uvalpha, int y, + enum AVPixelFormat target, int unused_hasAlpha, int unused_eightbytes) +{ + int hasAlpha = abuf && abuf[0] && abuf[1]; + const int32_t *buf0 = buf[0], *buf1 = buf[1], + *abuf0 = hasAlpha ? abuf[0] : NULL, + *abuf1 = hasAlpha ? abuf[1] : NULL; + int yalpha1 = 4096 - yalpha; + int i; + + av_assert2(yalpha <= 4096U); + + for (i = 0; i < dstW; i++) { + int Y = (buf0[i] * yalpha1 + buf1[i] * yalpha) >> 15; + int A; + + Y = av_clip_uint16(Y); + + if (hasAlpha) { + A = (abuf0[i] * yalpha1 + abuf1[i] * yalpha) >> 15; + A = av_clip_uint16(A); + } + + output_pixel(&dest[2 * i ], Y); + output_pixel(&dest[2 * i + 1], hasAlpha ? A : 65535); + } +} + +static av_always_inline void +yuv2ya16_1_c_template(SwsContext *c, const int32_t *buf0, + const int32_t *unused_ubuf[2], const int32_t *unused_vbuf[2], + const int32_t *abuf0, uint16_t *dest, int dstW, + int unused_uvalpha, int y, enum AVPixelFormat target, int unused_hasAlpha, int unused_eightbytes) +{ + int hasAlpha = !!abuf0; + int i; + + for (i = 0; i < dstW; i++) { + int Y = buf0[i] >> 3;/* 19 - 16 */ + int A; + + Y = av_clip_uint16(Y); + + if (hasAlpha) { + A = abuf0[i] >> 3; + if (A & 0x100) + A = av_clip_uint16(A); + } + + output_pixel(&dest[2 * i ], Y); + output_pixel(&dest[2 * i + 1], hasAlpha ? A : 65535); + } +} + static av_always_inline void yuv2rgba64_X_c_template(SwsContext *c, const int16_t *lumFilter, const int32_t **lumSrc, int lumFilterSize, @@ -1306,6 +1489,8 @@ YUV2PACKED16WRAPPER(yuv2, rgba64, bgra64be, AV_PIX_FMT_BGRA64BE, 1, 1) YUV2PACKED16WRAPPER(yuv2, rgba64, bgra64le, AV_PIX_FMT_BGRA64LE, 1, 1) YUV2PACKED16WRAPPER(yuv2, rgba64, bgrx64be, AV_PIX_FMT_BGRA64BE, 0, 1) YUV2PACKED16WRAPPER(yuv2, rgba64, bgrx64le, AV_PIX_FMT_BGRA64LE, 0, 1) +YUV2PACKED16WRAPPER(yuv2, ya16, ya16be, AV_PIX_FMT_YA16BE, 1, 0) +YUV2PACKED16WRAPPER(yuv2, ya16, ya16le, AV_PIX_FMT_YA16LE, 1, 0) YUV2PACKED16WRAPPER(yuv2, rgba64_full, rgb48be_full, AV_PIX_FMT_RGB48BE, 0, 0) YUV2PACKED16WRAPPER(yuv2, rgba64_full, rgb48le_full, AV_PIX_FMT_RGB48LE, 0, 0) @@ -2303,10 +2488,17 @@ av_cold void ff_sws_init_output_funcs(SwsContext *c, *yuv2plane1 = isBE(dstFormat) ? yuv2plane1_14BE_c : yuv2plane1_14LE_c; } else av_assert0(0); + } else if (dstFormat == AV_PIX_FMT_GRAYF32BE) { + *yuv2planeX = yuv2planeX_floatBE_c; + *yuv2plane1 = yuv2plane1_floatBE_c; + } else if (dstFormat == AV_PIX_FMT_GRAYF32LE) { + *yuv2planeX = yuv2planeX_floatLE_c; + *yuv2plane1 = yuv2plane1_floatLE_c; } else { *yuv2plane1 = yuv2plane1_8_c; *yuv2planeX = yuv2planeX_8_c; - if (dstFormat == AV_PIX_FMT_NV12 || dstFormat == AV_PIX_FMT_NV21) + if (dstFormat == AV_PIX_FMT_NV12 || dstFormat == AV_PIX_FMT_NV21 || + dstFormat == AV_PIX_FMT_NV24 || dstFormat == AV_PIX_FMT_NV42) *yuv2nv12cX = yuv2nv12cX_c; } @@ -2730,6 +2922,16 @@ av_cold void ff_sws_init_output_funcs(SwsContext *c, *yuv2packed2 = yuv2ya8_2_c; *yuv2packedX = yuv2ya8_X_c; break; + case AV_PIX_FMT_YA16LE: + *yuv2packed1 = yuv2ya16le_1_c; + *yuv2packed2 = yuv2ya16le_2_c; + *yuv2packedX = yuv2ya16le_X_c; + break; + case AV_PIX_FMT_YA16BE: + *yuv2packed1 = yuv2ya16be_1_c; + *yuv2packed2 = yuv2ya16be_2_c; + *yuv2packedX = yuv2ya16be_X_c; + break; case AV_PIX_FMT_AYUV64LE: *yuv2packedX = yuv2ayuv64le_X_c; break; diff --git a/libswscale/ppc/Makefile b/libswscale/ppc/Makefile index d1b596eb3..0a31a3025 100644 --- a/libswscale/ppc/Makefile +++ b/libswscale/ppc/Makefile @@ -1,3 +1,4 @@ OBJS += ppc/swscale_altivec.o \ ppc/yuv2rgb_altivec.o \ ppc/yuv2yuv_altivec.o \ + ppc/swscale_vsx.o diff --git a/libswscale/ppc/swscale_altivec.c b/libswscale/ppc/swscale_altivec.c index 9438a63ff..6b8cc2c19 100644 --- a/libswscale/ppc/swscale_altivec.c +++ b/libswscale/ppc/swscale_altivec.c @@ -32,34 +32,27 @@ #include "libavutil/ppc/util_altivec.h" #if HAVE_ALTIVEC +#if HAVE_BIGENDIAN #define vzero vec_splat_s32(0) -#if HAVE_BIGENDIAN #define GET_LS(a,b,c,s) {\ vector signed short l2 = vec_ld(((b) << 1) + 16, s);\ ls = vec_perm(a, l2, c);\ a = l2;\ } -#else -#define GET_LS(a,b,c,s) {\ - ls = a;\ - a = vec_vsx_ld(((b) << 1) + 16, s);\ - } -#endif #define yuv2planeX_8(d1, d2, l1, src, x, perm, filter) do {\ vector signed short ls;\ + vector signed int vf1, vf2, i1, i2;\ GET_LS(l1, x, perm, src);\ - vector signed int i1 = vec_mule(filter, ls);\ - vector signed int i2 = vec_mulo(filter, ls);\ - vector signed int vf1, vf2;\ + i1 = vec_mule(filter, ls);\ + i2 = vec_mulo(filter, ls);\ vf1 = vec_mergeh(i1, i2);\ vf2 = vec_mergel(i1, i2);\ d1 = vec_add(d1, vf1);\ d2 = vec_add(d2, vf2);\ } while (0) -#if HAVE_BIGENDIAN #define LOAD_FILTER(vf,f) {\ vector unsigned char perm0 = vec_lvsl(joffset, f);\ vf = vec_ld(joffset, f);\ @@ -69,89 +62,7 @@ p = vec_lvsl(xoffset, s);\ ll1 = vec_ld(xoffset, s);\ } -#else -#define LOAD_FILTER(vf,f) {\ - vf = vec_vsx_ld(joffset, f);\ -} -#define LOAD_L1(ll1,s,p){\ - ll1 = vec_vsx_ld(xoffset, s);\ -} -#endif -static void yuv2planeX_16_altivec(const int16_t *filter, int filterSize, - const int16_t **src, uint8_t *dest, - const uint8_t *dither, int offset, int x) -{ - register int i, j; - LOCAL_ALIGNED(16, int, val, [16]); - vector signed int vo1, vo2, vo3, vo4; - vector unsigned short vs1, vs2; - vector unsigned char vf; - vector unsigned int altivec_vectorShiftInt19 = - vec_add(vec_splat_u32(10), vec_splat_u32(9)); - - for (i = 0; i < 16; i++) - val[i] = dither[(x + i + offset) & 7] << 12; - - vo1 = vec_ld(0, val); - vo2 = vec_ld(16, val); - vo3 = vec_ld(32, val); - vo4 = vec_ld(48, val); - - for (j = 0; j < filterSize; j++) { - unsigned int joffset=j<<1; - unsigned int xoffset=x<<1; - vector unsigned char perm; - vector signed short l1,vLumFilter; - LOAD_FILTER(vLumFilter,filter); - vLumFilter = vec_splat(vLumFilter, 0); - LOAD_L1(l1,src[j],perm); - yuv2planeX_8(vo1, vo2, l1, src[j], x, perm, vLumFilter); - yuv2planeX_8(vo3, vo4, l1, src[j], x + 8, perm, vLumFilter); - } - - vo1 = vec_sra(vo1, altivec_vectorShiftInt19); - vo2 = vec_sra(vo2, altivec_vectorShiftInt19); - vo3 = vec_sra(vo3, altivec_vectorShiftInt19); - vo4 = vec_sra(vo4, altivec_vectorShiftInt19); - vs1 = vec_packsu(vo1, vo2); - vs2 = vec_packsu(vo3, vo4); - vf = vec_packsu(vs1, vs2); - VEC_ST(vf, 0, dest); -} - - -static inline void yuv2planeX_u(const int16_t *filter, int filterSize, - const int16_t **src, uint8_t *dest, int dstW, - const uint8_t *dither, int offset, int x) -{ - int i, j; - - for (i = x; i < dstW; i++) { - int t = dither[(i + offset) & 7] << 12; - for (j = 0; j < filterSize; j++) - t += src[j][i] * filter[j]; - dest[i] = av_clip_uint8(t >> 19); - } -} - -static void yuv2planeX_altivec(const int16_t *filter, int filterSize, - const int16_t **src, uint8_t *dest, int dstW, - const uint8_t *dither, int offset) -{ - int dst_u = -(uintptr_t)dest & 15; - int i; - - yuv2planeX_u(filter, filterSize, src, dest, dst_u, dither, offset, 0); - - for (i = dst_u; i < dstW - 15; i += 16) - yuv2planeX_16_altivec(filter, filterSize, src, dest + i, dither, - offset, i); - - yuv2planeX_u(filter, filterSize, src, dest, dstW, dither, offset, i); -} - -#if HAVE_BIGENDIAN // The 3 above is 2 (filterSize == 4) + 1 (sizeof(short) == 2). // The neat trick: We only care for half the elements, @@ -187,143 +98,141 @@ static void yuv2planeX_altivec(const int16_t *filter, int filterSize, vf1 = vec_ld((a * 2 * filterSize) + (b * 2) + 16 + off, f);\ vf = vec_perm(vf0, vf1, per);\ } -#else /* else of #if HAVE_BIGENDIAN */ -#define GET_VF4(a, vf, f) {\ - vf = (vector signed short)vec_vsx_ld(a << 3, f);\ - vf = vec_mergeh(vf, (vector signed short)vzero);\ -} -#define FIRST_LOAD(sv, pos, s, per) {} -#define UPDATE_PTR(s0, d0, s1, d1) {} -#define LOAD_SRCV(pos, a, s, per, v0, v1, vf) {\ - vf = vec_vsx_ld(pos + a, s);\ -} -#define LOAD_SRCV8(pos, a, s, per, v0, v1, vf) LOAD_SRCV(pos, a, s, per, v0, v1, vf) -#define GET_VFD(a, b, f, vf0, vf1, per, vf, off) {\ - vf = vec_vsx_ld((a * 2 * filterSize) + (b * 2) + off, f);\ -} -#endif /* end of #if HAVE_BIGENDIAN */ -static void hScale_altivec_real(SwsContext *c, int16_t *dst, int dstW, - const uint8_t *src, const int16_t *filter, - const int32_t *filterPos, int filterSize) +#define FUNC(name) name ## _altivec +#include "swscale_ppc_template.c" +#undef FUNC + +#undef vzero + +#endif /* HAVE_BIGENDIAN */ + +#define output_pixel(pos, val, bias, signedness) \ + if (big_endian) { \ + AV_WB16(pos, bias + av_clip_ ## signedness ## 16(val >> shift)); \ + } else { \ + AV_WL16(pos, bias + av_clip_ ## signedness ## 16(val >> shift)); \ + } + +static void +yuv2plane1_float_u(const int32_t *src, float *dest, int dstW, int start) { - register int i; - LOCAL_ALIGNED(16, int, tempo, [4]); + static const int big_endian = HAVE_BIGENDIAN; + static const int shift = 3; + static const float float_mult = 1.0f / 65535.0f; + int i, val; + uint16_t val_uint; - if (filterSize % 4) { - for (i = 0; i < dstW; i++) { - register int j; - register int srcPos = filterPos[i]; - register int val = 0; - for (j = 0; j < filterSize; j++) - val += ((int)src[srcPos + j]) * filter[filterSize * i + j]; - dst[i] = FFMIN(val >> 7, (1 << 15) - 1); - } - } else - switch (filterSize) { - case 4: - for (i = 0; i < dstW; i++) { - register int srcPos = filterPos[i]; - - vector unsigned char src_vF = unaligned_load(srcPos, src); - vector signed short src_v, filter_v; - vector signed int val_vEven, val_s; - src_v = // vec_unpackh sign-extends... - (vector signed short)(VEC_MERGEH((vector unsigned char)vzero, src_vF)); - // now put our elements in the even slots - src_v = vec_mergeh(src_v, (vector signed short)vzero); - GET_VF4(i, filter_v, filter); - val_vEven = vec_mule(src_v, filter_v); - val_s = vec_sums(val_vEven, vzero); - vec_st(val_s, 0, tempo); - dst[i] = FFMIN(tempo[3] >> 7, (1 << 15) - 1); - } - break; - case 8: - for (i = 0; i < dstW; i++) { - register int srcPos = filterPos[i]; - vector unsigned char src_vF, src_v0, src_v1; - vector unsigned char permS; - vector signed short src_v, filter_v; - vector signed int val_v, val_s; - FIRST_LOAD(src_v0, srcPos, src, permS); - LOAD_SRCV8(srcPos, 0, src, permS, src_v0, src_v1, src_vF); - src_v = // vec_unpackh sign-extends... - (vector signed short)(VEC_MERGEH((vector unsigned char)vzero, src_vF)); - filter_v = vec_ld(i << 4, filter); - val_v = vec_msums(src_v, filter_v, (vector signed int)vzero); - val_s = vec_sums(val_v, vzero); - vec_st(val_s, 0, tempo); - dst[i] = FFMIN(tempo[3] >> 7, (1 << 15) - 1); - } - break; - - case 16: - for (i = 0; i < dstW; i++) { - register int srcPos = filterPos[i]; - - vector unsigned char src_vF = unaligned_load(srcPos, src); - vector signed short src_vA = // vec_unpackh sign-extends... - (vector signed short)(VEC_MERGEH((vector unsigned char)vzero, src_vF)); - vector signed short src_vB = // vec_unpackh sign-extends... - (vector signed short)(VEC_MERGEL((vector unsigned char)vzero, src_vF)); - vector signed short filter_v0 = vec_ld(i << 5, filter); - vector signed short filter_v1 = vec_ld((i << 5) + 16, filter); - - vector signed int val_acc = vec_msums(src_vA, filter_v0, (vector signed int)vzero); - vector signed int val_v = vec_msums(src_vB, filter_v1, val_acc); - - vector signed int val_s = vec_sums(val_v, vzero); - - VEC_ST(val_s, 0, tempo); - dst[i] = FFMIN(tempo[3] >> 7, (1 << 15) - 1); - } - break; - - default: - for (i = 0; i < dstW; i++) { - register int j, offset = i * 2 * filterSize; - register int srcPos = filterPos[i]; - - vector signed int val_s, val_v = (vector signed int)vzero; - vector signed short filter_v0R; - vector unsigned char permF, src_v0, permS; - FIRST_LOAD(filter_v0R, offset, filter, permF); - FIRST_LOAD(src_v0, srcPos, src, permS); - - for (j = 0; j < filterSize - 15; j += 16) { - vector unsigned char src_v1, src_vF; - vector signed short filter_v1R, filter_v2R, filter_v0, filter_v1; - LOAD_SRCV(srcPos, j, src, permS, src_v0, src_v1, src_vF); - vector signed short src_vA = // vec_unpackh sign-extends... - (vector signed short)(VEC_MERGEH((vector unsigned char)vzero, src_vF)); - vector signed short src_vB = // vec_unpackh sign-extends... - (vector signed short)(VEC_MERGEL((vector unsigned char)vzero, src_vF)); - GET_VFD(i, j, filter, filter_v0R, filter_v1R, permF, filter_v0, 0); - GET_VFD(i, j, filter, filter_v1R, filter_v2R, permF, filter_v1, 16); - - vector signed int val_acc = vec_msums(src_vA, filter_v0, val_v); - val_v = vec_msums(src_vB, filter_v1, val_acc); - UPDATE_PTR(filter_v2R, filter_v0R, src_v1, src_v0); - } - - if (j < filterSize - 7) { - // loading src_v0 is useless, it's already done above - vector unsigned char src_v1, src_vF; - vector signed short src_v, filter_v1R, filter_v; - LOAD_SRCV8(srcPos, j, src, permS, src_v0, src_v1, src_vF); - src_v = // vec_unpackh sign-extends... - (vector signed short)(VEC_MERGEH((vector unsigned char)vzero, src_vF)); - GET_VFD(i, j, filter, filter_v0R, filter_v1R, permF, filter_v, 0); - val_v = vec_msums(src_v, filter_v, val_v); - } - val_s = vec_sums(val_v, vzero); - - VEC_ST(val_s, 0, tempo); - dst[i] = FFMIN(tempo[3] >> 7, (1 << 15) - 1); - } - } + for (i = start; i < dstW; ++i){ + val = src[i] + (1 << (shift - 1)); + output_pixel(&val_uint, val, 0, uint); + dest[i] = float_mult * (float)val_uint; + } } + +static void +yuv2plane1_float_bswap_u(const int32_t *src, uint32_t *dest, int dstW, int start) +{ + static const int big_endian = HAVE_BIGENDIAN; + static const int shift = 3; + static const float float_mult = 1.0f / 65535.0f; + int i, val; + uint16_t val_uint; + + for (i = start; i < dstW; ++i){ + val = src[i] + (1 << (shift - 1)); + output_pixel(&val_uint, val, 0, uint); + dest[i] = av_bswap32(av_float2int(float_mult * (float)val_uint)); + } +} + +static void yuv2plane1_float_altivec(const int32_t *src, float *dest, int dstW) +{ + const int dst_u = -(uintptr_t)dest & 3; + const int shift = 3; + const int add = (1 << (shift - 1)); + const int clip = (1 << 16) - 1; + const float fmult = 1.0f / 65535.0f; + const vector uint32_t vadd = (vector uint32_t) {add, add, add, add}; + const vector uint32_t vshift = (vector uint32_t) vec_splat_u32(shift); + const vector uint32_t vlargest = (vector uint32_t) {clip, clip, clip, clip}; + const vector float vmul = (vector float) {fmult, fmult, fmult, fmult}; + const vector float vzero = (vector float) {0, 0, 0, 0}; + vector uint32_t v; + vector float vd; + int i; + + yuv2plane1_float_u(src, dest, dst_u, 0); + + for (i = dst_u; i < dstW - 3; i += 4) { + v = vec_ld(0, (const uint32_t *) &src[i]); + v = vec_add(v, vadd); + v = vec_sr(v, vshift); + v = vec_min(v, vlargest); + + vd = vec_ctf(v, 0); + vd = vec_madd(vd, vmul, vzero); + + vec_st(vd, 0, &dest[i]); + } + + yuv2plane1_float_u(src, dest, dstW, i); +} + +static void yuv2plane1_float_bswap_altivec(const int32_t *src, uint32_t *dest, int dstW) +{ + const int dst_u = -(uintptr_t)dest & 3; + const int shift = 3; + const int add = (1 << (shift - 1)); + const int clip = (1 << 16) - 1; + const float fmult = 1.0f / 65535.0f; + const vector uint32_t vadd = (vector uint32_t) {add, add, add, add}; + const vector uint32_t vshift = (vector uint32_t) vec_splat_u32(shift); + const vector uint32_t vlargest = (vector uint32_t) {clip, clip, clip, clip}; + const vector float vmul = (vector float) {fmult, fmult, fmult, fmult}; + const vector float vzero = (vector float) {0, 0, 0, 0}; + const vector uint32_t vswapbig = (vector uint32_t) {16, 16, 16, 16}; + const vector uint16_t vswapsmall = vec_splat_u16(8); + vector uint32_t v; + vector float vd; + int i; + + yuv2plane1_float_bswap_u(src, dest, dst_u, 0); + + for (i = dst_u; i < dstW - 3; i += 4) { + v = vec_ld(0, (const uint32_t *) &src[i]); + v = vec_add(v, vadd); + v = vec_sr(v, vshift); + v = vec_min(v, vlargest); + + vd = vec_ctf(v, 0); + vd = vec_madd(vd, vmul, vzero); + + vd = (vector float) vec_rl((vector uint32_t) vd, vswapbig); + vd = (vector float) vec_rl((vector uint16_t) vd, vswapsmall); + + vec_st(vd, 0, (float *) &dest[i]); + } + + yuv2plane1_float_bswap_u(src, dest, dstW, i); +} + +#define yuv2plane1_float(template, dest_type, BE_LE) \ +static void yuv2plane1_float ## BE_LE ## _altivec(const int16_t *src, uint8_t *dest, \ + int dstW, \ + const uint8_t *dither, int offset) \ +{ \ + template((const int32_t *)src, (dest_type *)dest, dstW); \ +} + +#if HAVE_BIGENDIAN +yuv2plane1_float(yuv2plane1_float_altivec, float, BE) +yuv2plane1_float(yuv2plane1_float_bswap_altivec, uint32_t, LE) +#else +yuv2plane1_float(yuv2plane1_float_altivec, float, LE) +yuv2plane1_float(yuv2plane1_float_bswap_altivec, uint32_t, BE) +#endif + #endif /* HAVE_ALTIVEC */ av_cold void ff_sws_init_swscale_ppc(SwsContext *c) @@ -334,14 +243,22 @@ av_cold void ff_sws_init_swscale_ppc(SwsContext *c) if (!(av_get_cpu_flags() & AV_CPU_FLAG_ALTIVEC)) return; +#if HAVE_BIGENDIAN if (c->srcBpc == 8 && c->dstBpc <= 14) { - c->hyScale = c->hcScale = hScale_altivec_real; + c->hyScale = c->hcScale = hScale_real_altivec; } - if (!is16BPS(dstFormat) && !isNBPS(dstFormat) && - dstFormat != AV_PIX_FMT_NV12 && dstFormat != AV_PIX_FMT_NV21 && + if (!is16BPS(dstFormat) && !isNBPS(dstFormat) && !isSemiPlanarYUV(dstFormat) && + dstFormat != AV_PIX_FMT_GRAYF32BE && dstFormat != AV_PIX_FMT_GRAYF32LE && !c->needAlpha) { c->yuv2planeX = yuv2planeX_altivec; } +#endif + + if (dstFormat == AV_PIX_FMT_GRAYF32BE) { + c->yuv2plane1 = yuv2plane1_floatBE_altivec; + } else if (dstFormat == AV_PIX_FMT_GRAYF32LE) { + c->yuv2plane1 = yuv2plane1_floatLE_altivec; + } /* The following list of supported dstFormat values should * match what's found in the body of ff_yuv2packedX_altivec() */ @@ -368,4 +285,6 @@ av_cold void ff_sws_init_swscale_ppc(SwsContext *c) } } #endif /* HAVE_ALTIVEC */ + + ff_sws_init_swscale_vsx(c); } diff --git a/libswscale/ppc/swscale_ppc_template.c b/libswscale/ppc/swscale_ppc_template.c new file mode 100644 index 000000000..aff2dd79f --- /dev/null +++ b/libswscale/ppc/swscale_ppc_template.c @@ -0,0 +1,219 @@ +/* + * AltiVec-enhanced yuv2yuvX + * + * Copyright (C) 2004 Romain Dolbeau + * based on the equivalent C code in swscale.c + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +static void FUNC(yuv2planeX_8_16)(const int16_t *filter, int filterSize, + const int16_t **src, uint8_t *dest, + const uint8_t *dither, int offset, int x) +{ + register int i, j; + LOCAL_ALIGNED(16, int, val, [16]); + vector signed int vo1, vo2, vo3, vo4; + vector unsigned short vs1, vs2; + vector unsigned char vf; + vector unsigned int altivec_vectorShiftInt19 = + vec_add(vec_splat_u32(10), vec_splat_u32(9)); + + for (i = 0; i < 16; i++) + val[i] = dither[(x + i + offset) & 7] << 12; + + vo1 = vec_ld(0, val); + vo2 = vec_ld(16, val); + vo3 = vec_ld(32, val); + vo4 = vec_ld(48, val); + + for (j = 0; j < filterSize; j++) { + unsigned int joffset=j<<1; + unsigned int xoffset=x<<1; + vector unsigned char av_unused perm; + vector signed short l1,vLumFilter; + LOAD_FILTER(vLumFilter,filter); + vLumFilter = vec_splat(vLumFilter, 0); + LOAD_L1(l1,src[j],perm); + yuv2planeX_8(vo1, vo2, l1, src[j], x, perm, vLumFilter); + yuv2planeX_8(vo3, vo4, l1, src[j], x + 8, perm, vLumFilter); + } + + vo1 = vec_sra(vo1, altivec_vectorShiftInt19); + vo2 = vec_sra(vo2, altivec_vectorShiftInt19); + vo3 = vec_sra(vo3, altivec_vectorShiftInt19); + vo4 = vec_sra(vo4, altivec_vectorShiftInt19); + vs1 = vec_packsu(vo1, vo2); + vs2 = vec_packsu(vo3, vo4); + vf = vec_packsu(vs1, vs2); + VEC_ST(vf, 0, dest); +} + + +static inline void yuv2planeX_u(const int16_t *filter, int filterSize, + const int16_t **src, uint8_t *dest, int dstW, + const uint8_t *dither, int offset, int x) +{ + int i, j; + + for (i = x; i < dstW; i++) { + int t = dither[(i + offset) & 7] << 12; + for (j = 0; j < filterSize; j++) + t += src[j][i] * filter[j]; + dest[i] = av_clip_uint8(t >> 19); + } +} + +static void FUNC(yuv2planeX)(const int16_t *filter, int filterSize, + const int16_t **src, uint8_t *dest, int dstW, + const uint8_t *dither, int offset) +{ + int dst_u = -(uintptr_t)dest & 15; + int i; + + yuv2planeX_u(filter, filterSize, src, dest, dst_u, dither, offset, 0); + + for (i = dst_u; i < dstW - 15; i += 16) + FUNC(yuv2planeX_8_16)(filter, filterSize, src, dest + i, dither, + offset, i); + + yuv2planeX_u(filter, filterSize, src, dest, dstW, dither, offset, i); +} + +static void FUNC(hScale_real)(SwsContext *c, int16_t *dst, int dstW, + const uint8_t *src, const int16_t *filter, + const int32_t *filterPos, int filterSize) +{ + register int i; + LOCAL_ALIGNED(16, int, tempo, [4]); + + if (filterSize % 4) { + for (i = 0; i < dstW; i++) { + register int j; + register int srcPos = filterPos[i]; + register int val = 0; + for (j = 0; j < filterSize; j++) + val += ((int)src[srcPos + j]) * filter[filterSize * i + j]; + dst[i] = FFMIN(val >> 7, (1 << 15) - 1); + } + } else + switch (filterSize) { + case 4: + for (i = 0; i < dstW; i++) { + register int srcPos = filterPos[i]; + + vector unsigned char src_vF = unaligned_load(srcPos, src); + vector signed short src_v, filter_v; + vector signed int val_vEven, val_s; + src_v = // vec_unpackh sign-extends... + (vector signed short)(VEC_MERGEH((vector unsigned char)vzero, src_vF)); + // now put our elements in the even slots + src_v = vec_mergeh(src_v, (vector signed short)vzero); + GET_VF4(i, filter_v, filter); + val_vEven = vec_mule(src_v, filter_v); + val_s = vec_sums(val_vEven, vzero); + vec_st(val_s, 0, tempo); + dst[i] = FFMIN(tempo[3] >> 7, (1 << 15) - 1); + } + break; + case 8: + for (i = 0; i < dstW; i++) { + register int srcPos = filterPos[i]; + vector unsigned char src_vF, av_unused src_v0, av_unused src_v1; + vector unsigned char av_unused permS; + vector signed short src_v, filter_v; + vector signed int val_v, val_s; + FIRST_LOAD(src_v0, srcPos, src, permS); + LOAD_SRCV8(srcPos, 0, src, permS, src_v0, src_v1, src_vF); + src_v = // vec_unpackh sign-extends... + (vector signed short)(VEC_MERGEH((vector unsigned char)vzero, src_vF)); + filter_v = vec_ld(i << 4, filter); + val_v = vec_msums(src_v, filter_v, (vector signed int)vzero); + val_s = vec_sums(val_v, vzero); + vec_st(val_s, 0, tempo); + dst[i] = FFMIN(tempo[3] >> 7, (1 << 15) - 1); + } + break; + + case 16: + for (i = 0; i < dstW; i++) { + register int srcPos = filterPos[i]; + + vector unsigned char src_vF = unaligned_load(srcPos, src); + vector signed short src_vA = // vec_unpackh sign-extends... + (vector signed short)(VEC_MERGEH((vector unsigned char)vzero, src_vF)); + vector signed short src_vB = // vec_unpackh sign-extends... + (vector signed short)(VEC_MERGEL((vector unsigned char)vzero, src_vF)); + vector signed short filter_v0 = vec_ld(i << 5, filter); + vector signed short filter_v1 = vec_ld((i << 5) + 16, filter); + + vector signed int val_acc = vec_msums(src_vA, filter_v0, (vector signed int)vzero); + vector signed int val_v = vec_msums(src_vB, filter_v1, val_acc); + + vector signed int val_s = vec_sums(val_v, vzero); + + VEC_ST(val_s, 0, tempo); + dst[i] = FFMIN(tempo[3] >> 7, (1 << 15) - 1); + } + break; + + default: + for (i = 0; i < dstW; i++) { + register int j, av_unused offset = i * 2 * filterSize; + register int srcPos = filterPos[i]; + + vector signed int val_s, val_v = (vector signed int)vzero; + vector signed short av_unused filter_v0R; + vector unsigned char av_unused permF, av_unused src_v0, av_unused permS; + FIRST_LOAD(filter_v0R, offset, filter, permF); + FIRST_LOAD(src_v0, srcPos, src, permS); + + for (j = 0; j < filterSize - 15; j += 16) { + vector unsigned char av_unused src_v1, src_vF; + vector signed short av_unused filter_v1R, av_unused filter_v2R, + filter_v0, filter_v1, src_vA, src_vB; + vector signed int val_acc; + LOAD_SRCV(srcPos, j, src, permS, src_v0, src_v1, src_vF); + src_vA = // vec_unpackh sign-extends... + (vector signed short)(VEC_MERGEH((vector unsigned char)vzero, src_vF)); + src_vB = // vec_unpackh sign-extends... + (vector signed short)(VEC_MERGEL((vector unsigned char)vzero, src_vF)); + GET_VFD(i, j, filter, filter_v0R, filter_v1R, permF, filter_v0, 0); + GET_VFD(i, j, filter, filter_v1R, filter_v2R, permF, filter_v1, 16); + + val_acc = vec_msums(src_vA, filter_v0, val_v); + val_v = vec_msums(src_vB, filter_v1, val_acc); + UPDATE_PTR(filter_v2R, filter_v0R, src_v1, src_v0); + } + + if (j < filterSize - 7) { + // loading src_v0 is useless, it's already done above + vector unsigned char av_unused src_v1, src_vF; + vector signed short src_v, av_unused filter_v1R, filter_v; + LOAD_SRCV8(srcPos, j, src, permS, src_v0, src_v1, src_vF); + src_v = // vec_unpackh sign-extends... + (vector signed short)(VEC_MERGEH((vector unsigned char)vzero, src_vF)); + GET_VFD(i, j, filter, filter_v0R, filter_v1R, permF, filter_v, 0); + val_v = vec_msums(src_v, filter_v, val_v); + } + val_s = vec_sums(val_v, vzero); + + VEC_ST(val_s, 0, tempo); + dst[i] = FFMIN(tempo[3] >> 7, (1 << 15) - 1); + } + } +} diff --git a/libswscale/ppc/swscale_vsx.c b/libswscale/ppc/swscale_vsx.c new file mode 100644 index 000000000..75dee5ea5 --- /dev/null +++ b/libswscale/ppc/swscale_vsx.c @@ -0,0 +1,2263 @@ +/* + * AltiVec-enhanced yuv2yuvX + * + * Copyright (C) 2004 Romain Dolbeau + * based on the equivalent C code in swscale.c + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include "config.h" +#include "libswscale/swscale.h" +#include "libswscale/swscale_internal.h" +#include "libavutil/attributes.h" +#include "libavutil/cpu.h" +#include "yuv2rgb_altivec.h" +#include "libavutil/ppc/util_altivec.h" + +#if HAVE_VSX +#define vzero vec_splat_s32(0) + +#if !HAVE_BIGENDIAN +#define GET_LS(a,b,c,s) {\ + ls = a;\ + a = vec_vsx_ld(((b) << 1) + 16, s);\ + } + +#define yuv2planeX_8(d1, d2, l1, src, x, perm, filter) do {\ + vector signed short ls;\ + vector signed int vf1, vf2, i1, i2;\ + GET_LS(l1, x, perm, src);\ + i1 = vec_mule(filter, ls);\ + i2 = vec_mulo(filter, ls);\ + vf1 = vec_mergeh(i1, i2);\ + vf2 = vec_mergel(i1, i2);\ + d1 = vec_add(d1, vf1);\ + d2 = vec_add(d2, vf2);\ + } while (0) + +#define LOAD_FILTER(vf,f) {\ + vf = vec_vsx_ld(joffset, f);\ +} +#define LOAD_L1(ll1,s,p){\ + ll1 = vec_vsx_ld(xoffset, s);\ +} + +// The 3 above is 2 (filterSize == 4) + 1 (sizeof(short) == 2). + +// The neat trick: We only care for half the elements, +// high or low depending on (i<<3)%16 (it's 0 or 8 here), +// and we're going to use vec_mule, so we choose +// carefully how to "unpack" the elements into the even slots. +#define GET_VF4(a, vf, f) {\ + vf = (vector signed short)vec_vsx_ld(a << 3, f);\ + vf = vec_mergeh(vf, (vector signed short)vzero);\ +} +#define FIRST_LOAD(sv, pos, s, per) {} +#define UPDATE_PTR(s0, d0, s1, d1) {} +#define LOAD_SRCV(pos, a, s, per, v0, v1, vf) {\ + vf = vec_vsx_ld(pos + a, s);\ +} +#define LOAD_SRCV8(pos, a, s, per, v0, v1, vf) LOAD_SRCV(pos, a, s, per, v0, v1, vf) +#define GET_VFD(a, b, f, vf0, vf1, per, vf, off) {\ + vf = vec_vsx_ld((a * 2 * filterSize) + (b * 2) + off, f);\ +} + +#define FUNC(name) name ## _vsx +#include "swscale_ppc_template.c" +#undef FUNC + +#undef vzero + +#endif /* !HAVE_BIGENDIAN */ + +static void yuv2plane1_8_u(const int16_t *src, uint8_t *dest, int dstW, + const uint8_t *dither, int offset, int start) +{ + int i; + for (i = start; i < dstW; i++) { + int val = (src[i] + dither[(i + offset) & 7]) >> 7; + dest[i] = av_clip_uint8(val); + } +} + +static void yuv2plane1_8_vsx(const int16_t *src, uint8_t *dest, int dstW, + const uint8_t *dither, int offset) +{ + const int dst_u = -(uintptr_t)dest & 15; + int i, j; + LOCAL_ALIGNED(16, int16_t, val, [16]); + const vector uint16_t shifts = (vector uint16_t) {7, 7, 7, 7, 7, 7, 7, 7}; + vector int16_t vi, vileft, ditherleft, ditherright; + vector uint8_t vd; + + for (j = 0; j < 16; j++) { + val[j] = dither[(dst_u + offset + j) & 7]; + } + + ditherleft = vec_ld(0, val); + ditherright = vec_ld(0, &val[8]); + + yuv2plane1_8_u(src, dest, dst_u, dither, offset, 0); + + for (i = dst_u; i < dstW - 15; i += 16) { + + vi = vec_vsx_ld(0, &src[i]); + vi = vec_adds(ditherleft, vi); + vileft = vec_sra(vi, shifts); + + vi = vec_vsx_ld(0, &src[i + 8]); + vi = vec_adds(ditherright, vi); + vi = vec_sra(vi, shifts); + + vd = vec_packsu(vileft, vi); + vec_st(vd, 0, &dest[i]); + } + + yuv2plane1_8_u(src, dest, dstW, dither, offset, i); +} + +#if !HAVE_BIGENDIAN + +#define output_pixel(pos, val) \ + if (big_endian) { \ + AV_WB16(pos, av_clip_uintp2(val >> shift, output_bits)); \ + } else { \ + AV_WL16(pos, av_clip_uintp2(val >> shift, output_bits)); \ + } + +static void yuv2plane1_nbps_u(const int16_t *src, uint16_t *dest, int dstW, + int big_endian, int output_bits, int start) +{ + int i; + int shift = 15 - output_bits; + + for (i = start; i < dstW; i++) { + int val = src[i] + (1 << (shift - 1)); + output_pixel(&dest[i], val); + } +} + +static void yuv2plane1_nbps_vsx(const int16_t *src, uint16_t *dest, int dstW, + int big_endian, int output_bits) +{ + const int dst_u = -(uintptr_t)dest & 7; + const int shift = 15 - output_bits; + const int add = (1 << (shift - 1)); + const int clip = (1 << output_bits) - 1; + const vector uint16_t vadd = (vector uint16_t) {add, add, add, add, add, add, add, add}; + const vector uint16_t vswap = (vector uint16_t) vec_splat_u16(big_endian ? 8 : 0); + const vector uint16_t vshift = (vector uint16_t) vec_splat_u16(shift); + const vector uint16_t vlargest = (vector uint16_t) {clip, clip, clip, clip, clip, clip, clip, clip}; + vector uint16_t v; + int i; + + yuv2plane1_nbps_u(src, dest, dst_u, big_endian, output_bits, 0); + + for (i = dst_u; i < dstW - 7; i += 8) { + v = vec_vsx_ld(0, (const uint16_t *) &src[i]); + v = vec_add(v, vadd); + v = vec_sr(v, vshift); + v = vec_min(v, vlargest); + v = vec_rl(v, vswap); + vec_st(v, 0, &dest[i]); + } + + yuv2plane1_nbps_u(src, dest, dstW, big_endian, output_bits, i); +} + +static void yuv2planeX_nbps_u(const int16_t *filter, int filterSize, + const int16_t **src, uint16_t *dest, int dstW, + int big_endian, int output_bits, int start) +{ + int i; + int shift = 11 + 16 - output_bits; + + for (i = start; i < dstW; i++) { + int val = 1 << (shift - 1); + int j; + + for (j = 0; j < filterSize; j++) + val += src[j][i] * filter[j]; + + output_pixel(&dest[i], val); + } +} + +static void yuv2planeX_nbps_vsx(const int16_t *filter, int filterSize, + const int16_t **src, uint16_t *dest, int dstW, + int big_endian, int output_bits) +{ + const int dst_u = -(uintptr_t)dest & 7; + const int shift = 11 + 16 - output_bits; + const int add = (1 << (shift - 1)); + const int clip = (1 << output_bits) - 1; + const uint16_t swap = big_endian ? 8 : 0; + const vector uint32_t vadd = (vector uint32_t) {add, add, add, add}; + const vector uint32_t vshift = (vector uint32_t) {shift, shift, shift, shift}; + const vector uint16_t vswap = (vector uint16_t) {swap, swap, swap, swap, swap, swap, swap, swap}; + const vector uint16_t vlargest = (vector uint16_t) {clip, clip, clip, clip, clip, clip, clip, clip}; + const vector int16_t vzero = vec_splat_s16(0); + const vector uint8_t vperm = (vector uint8_t) {0, 1, 8, 9, 2, 3, 10, 11, 4, 5, 12, 13, 6, 7, 14, 15}; + vector int16_t vfilter[MAX_FILTER_SIZE], vin; + vector uint16_t v; + vector uint32_t vleft, vright, vtmp; + int i, j; + + for (i = 0; i < filterSize; i++) { + vfilter[i] = (vector int16_t) {filter[i], filter[i], filter[i], filter[i], + filter[i], filter[i], filter[i], filter[i]}; + } + + yuv2planeX_nbps_u(filter, filterSize, src, dest, dst_u, big_endian, output_bits, 0); + + for (i = dst_u; i < dstW - 7; i += 8) { + vleft = vright = vadd; + + for (j = 0; j < filterSize; j++) { + vin = vec_vsx_ld(0, &src[j][i]); + vtmp = (vector uint32_t) vec_mule(vin, vfilter[j]); + vleft = vec_add(vleft, vtmp); + vtmp = (vector uint32_t) vec_mulo(vin, vfilter[j]); + vright = vec_add(vright, vtmp); + } + + vleft = vec_sra(vleft, vshift); + vright = vec_sra(vright, vshift); + v = vec_packsu(vleft, vright); + v = (vector uint16_t) vec_max((vector int16_t) v, vzero); + v = vec_min(v, vlargest); + v = vec_rl(v, vswap); + v = vec_perm(v, v, vperm); + vec_st(v, 0, &dest[i]); + } + + yuv2planeX_nbps_u(filter, filterSize, src, dest, dstW, big_endian, output_bits, i); +} + + +#undef output_pixel + +#define output_pixel(pos, val, bias, signedness) \ + if (big_endian) { \ + AV_WB16(pos, bias + av_clip_ ## signedness ## 16(val >> shift)); \ + } else { \ + AV_WL16(pos, bias + av_clip_ ## signedness ## 16(val >> shift)); \ + } + +static void yuv2plane1_16_u(const int32_t *src, uint16_t *dest, int dstW, + int big_endian, int output_bits, int start) +{ + int i; + const int shift = 3; + + for (i = start; i < dstW; i++) { + int val = src[i] + (1 << (shift - 1)); + output_pixel(&dest[i], val, 0, uint); + } +} + +static void yuv2plane1_16_vsx(const int32_t *src, uint16_t *dest, int dstW, + int big_endian, int output_bits) +{ + const int dst_u = -(uintptr_t)dest & 7; + const int shift = 3; + const int add = (1 << (shift - 1)); + const vector uint32_t vadd = (vector uint32_t) {add, add, add, add}; + const vector uint16_t vswap = (vector uint16_t) vec_splat_u16(big_endian ? 8 : 0); + const vector uint32_t vshift = (vector uint32_t) vec_splat_u32(shift); + vector uint32_t v, v2; + vector uint16_t vd; + int i; + + yuv2plane1_16_u(src, dest, dst_u, big_endian, output_bits, 0); + + for (i = dst_u; i < dstW - 7; i += 8) { + v = vec_vsx_ld(0, (const uint32_t *) &src[i]); + v = vec_add(v, vadd); + v = vec_sr(v, vshift); + + v2 = vec_vsx_ld(0, (const uint32_t *) &src[i + 4]); + v2 = vec_add(v2, vadd); + v2 = vec_sr(v2, vshift); + + vd = vec_packsu(v, v2); + vd = vec_rl(vd, vswap); + + vec_st(vd, 0, &dest[i]); + } + + yuv2plane1_16_u(src, dest, dstW, big_endian, output_bits, i); +} + +#if HAVE_POWER8 + +static void yuv2planeX_16_u(const int16_t *filter, int filterSize, + const int32_t **src, uint16_t *dest, int dstW, + int big_endian, int output_bits, int start) +{ + int i; + int shift = 15; + + for (i = start; i < dstW; i++) { + int val = 1 << (shift - 1); + int j; + + /* range of val is [0,0x7FFFFFFF], so 31 bits, but with lanczos/spline + * filters (or anything with negative coeffs, the range can be slightly + * wider in both directions. To account for this overflow, we subtract + * a constant so it always fits in the signed range (assuming a + * reasonable filterSize), and re-add that at the end. */ + val -= 0x40000000; + for (j = 0; j < filterSize; j++) + val += src[j][i] * (unsigned)filter[j]; + + output_pixel(&dest[i], val, 0x8000, int); + } +} + +static void yuv2planeX_16_vsx(const int16_t *filter, int filterSize, + const int32_t **src, uint16_t *dest, int dstW, + int big_endian, int output_bits) +{ + const int dst_u = -(uintptr_t)dest & 7; + const int shift = 15; + const int bias = 0x8000; + const int add = (1 << (shift - 1)) - 0x40000000; + const uint16_t swap = big_endian ? 8 : 0; + const vector uint32_t vadd = (vector uint32_t) {add, add, add, add}; + const vector uint32_t vshift = (vector uint32_t) {shift, shift, shift, shift}; + const vector uint16_t vswap = (vector uint16_t) {swap, swap, swap, swap, swap, swap, swap, swap}; + const vector uint16_t vbias = (vector uint16_t) {bias, bias, bias, bias, bias, bias, bias, bias}; + vector int32_t vfilter[MAX_FILTER_SIZE]; + vector uint16_t v; + vector uint32_t vleft, vright, vtmp; + vector int32_t vin32l, vin32r; + int i, j; + + for (i = 0; i < filterSize; i++) { + vfilter[i] = (vector int32_t) {filter[i], filter[i], filter[i], filter[i]}; + } + + yuv2planeX_16_u(filter, filterSize, src, dest, dst_u, big_endian, output_bits, 0); + + for (i = dst_u; i < dstW - 7; i += 8) { + vleft = vright = vadd; + + for (j = 0; j < filterSize; j++) { + vin32l = vec_vsx_ld(0, &src[j][i]); + vin32r = vec_vsx_ld(0, &src[j][i + 4]); + + vtmp = (vector uint32_t) vec_mul(vin32l, vfilter[j]); + vleft = vec_add(vleft, vtmp); + vtmp = (vector uint32_t) vec_mul(vin32r, vfilter[j]); + vright = vec_add(vright, vtmp); + } + + vleft = vec_sra(vleft, vshift); + vright = vec_sra(vright, vshift); + v = (vector uint16_t) vec_packs((vector int32_t) vleft, (vector int32_t) vright); + v = vec_add(v, vbias); + v = vec_rl(v, vswap); + vec_st(v, 0, &dest[i]); + } + + yuv2planeX_16_u(filter, filterSize, src, dest, dstW, big_endian, output_bits, i); +} + +#endif /* HAVE_POWER8 */ + +#define yuv2NBPS(bits, BE_LE, is_be, template_size, typeX_t) \ + yuv2NBPS1(bits, BE_LE, is_be, template_size, typeX_t) \ + yuv2NBPSX(bits, BE_LE, is_be, template_size, typeX_t) + +#define yuv2NBPS1(bits, BE_LE, is_be, template_size, typeX_t) \ +static void yuv2plane1_ ## bits ## BE_LE ## _vsx(const int16_t *src, \ + uint8_t *dest, int dstW, \ + const uint8_t *dither, int offset) \ +{ \ + yuv2plane1_ ## template_size ## _vsx((const typeX_t *) src, \ + (uint16_t *) dest, dstW, is_be, bits); \ +} + +#define yuv2NBPSX(bits, BE_LE, is_be, template_size, typeX_t) \ +static void yuv2planeX_ ## bits ## BE_LE ## _vsx(const int16_t *filter, int filterSize, \ + const int16_t **src, uint8_t *dest, int dstW, \ + const uint8_t *dither, int offset)\ +{ \ + yuv2planeX_## template_size ## _vsx(filter, \ + filterSize, (const typeX_t **) src, \ + (uint16_t *) dest, dstW, is_be, bits); \ +} + +yuv2NBPS( 9, BE, 1, nbps, int16_t) +yuv2NBPS( 9, LE, 0, nbps, int16_t) +yuv2NBPS(10, BE, 1, nbps, int16_t) +yuv2NBPS(10, LE, 0, nbps, int16_t) +yuv2NBPS(12, BE, 1, nbps, int16_t) +yuv2NBPS(12, LE, 0, nbps, int16_t) +yuv2NBPS(14, BE, 1, nbps, int16_t) +yuv2NBPS(14, LE, 0, nbps, int16_t) + +yuv2NBPS1(16, BE, 1, 16, int32_t) +yuv2NBPS1(16, LE, 0, 16, int32_t) +#if HAVE_POWER8 +yuv2NBPSX(16, BE, 1, 16, int32_t) +yuv2NBPSX(16, LE, 0, 16, int32_t) +#endif + +#define WRITERGB \ + R_l = vec_max(R_l, zero32); \ + R_r = vec_max(R_r, zero32); \ + G_l = vec_max(G_l, zero32); \ + G_r = vec_max(G_r, zero32); \ + B_l = vec_max(B_l, zero32); \ + B_r = vec_max(B_r, zero32); \ +\ + R_l = vec_min(R_l, rgbclip); \ + R_r = vec_min(R_r, rgbclip); \ + G_l = vec_min(G_l, rgbclip); \ + G_r = vec_min(G_r, rgbclip); \ + B_l = vec_min(B_l, rgbclip); \ + B_r = vec_min(B_r, rgbclip); \ +\ + R_l = vec_sr(R_l, shift22); \ + R_r = vec_sr(R_r, shift22); \ + G_l = vec_sr(G_l, shift22); \ + G_r = vec_sr(G_r, shift22); \ + B_l = vec_sr(B_l, shift22); \ + B_r = vec_sr(B_r, shift22); \ +\ + rd16 = vec_packsu(R_l, R_r); \ + gd16 = vec_packsu(G_l, G_r); \ + bd16 = vec_packsu(B_l, B_r); \ + rd = vec_packsu(rd16, zero16); \ + gd = vec_packsu(gd16, zero16); \ + bd = vec_packsu(bd16, zero16); \ +\ + switch(target) { \ + case AV_PIX_FMT_RGB24: \ + out0 = vec_perm(rd, gd, perm3rg0); \ + out0 = vec_perm(out0, bd, perm3tb0); \ + out1 = vec_perm(rd, gd, perm3rg1); \ + out1 = vec_perm(out1, bd, perm3tb1); \ +\ + vec_vsx_st(out0, 0, dest); \ + vec_vsx_st(out1, 16, dest); \ +\ + dest += 24; \ + break; \ + case AV_PIX_FMT_BGR24: \ + out0 = vec_perm(bd, gd, perm3rg0); \ + out0 = vec_perm(out0, rd, perm3tb0); \ + out1 = vec_perm(bd, gd, perm3rg1); \ + out1 = vec_perm(out1, rd, perm3tb1); \ +\ + vec_vsx_st(out0, 0, dest); \ + vec_vsx_st(out1, 16, dest); \ +\ + dest += 24; \ + break; \ + case AV_PIX_FMT_BGRA: \ + out0 = vec_mergeh(bd, gd); \ + out1 = vec_mergeh(rd, ad); \ +\ + tmp8 = (vector uint8_t) vec_mergeh((vector uint16_t) out0, (vector uint16_t) out1); \ + vec_vsx_st(tmp8, 0, dest); \ + tmp8 = (vector uint8_t) vec_mergel((vector uint16_t) out0, (vector uint16_t) out1); \ + vec_vsx_st(tmp8, 16, dest); \ +\ + dest += 32; \ + break; \ + case AV_PIX_FMT_RGBA: \ + out0 = vec_mergeh(rd, gd); \ + out1 = vec_mergeh(bd, ad); \ +\ + tmp8 = (vector uint8_t) vec_mergeh((vector uint16_t) out0, (vector uint16_t) out1); \ + vec_vsx_st(tmp8, 0, dest); \ + tmp8 = (vector uint8_t) vec_mergel((vector uint16_t) out0, (vector uint16_t) out1); \ + vec_vsx_st(tmp8, 16, dest); \ +\ + dest += 32; \ + break; \ + case AV_PIX_FMT_ARGB: \ + out0 = vec_mergeh(ad, rd); \ + out1 = vec_mergeh(gd, bd); \ +\ + tmp8 = (vector uint8_t) vec_mergeh((vector uint16_t) out0, (vector uint16_t) out1); \ + vec_vsx_st(tmp8, 0, dest); \ + tmp8 = (vector uint8_t) vec_mergel((vector uint16_t) out0, (vector uint16_t) out1); \ + vec_vsx_st(tmp8, 16, dest); \ +\ + dest += 32; \ + break; \ + case AV_PIX_FMT_ABGR: \ + out0 = vec_mergeh(ad, bd); \ + out1 = vec_mergeh(gd, rd); \ +\ + tmp8 = (vector uint8_t) vec_mergeh((vector uint16_t) out0, (vector uint16_t) out1); \ + vec_vsx_st(tmp8, 0, dest); \ + tmp8 = (vector uint8_t) vec_mergel((vector uint16_t) out0, (vector uint16_t) out1); \ + vec_vsx_st(tmp8, 16, dest); \ +\ + dest += 32; \ + break; \ + } + +static av_always_inline void +yuv2rgb_full_X_vsx_template(SwsContext *c, const int16_t *lumFilter, + const int16_t **lumSrc, int lumFilterSize, + const int16_t *chrFilter, const int16_t **chrUSrc, + const int16_t **chrVSrc, int chrFilterSize, + const int16_t **alpSrc, uint8_t *dest, + int dstW, int y, enum AVPixelFormat target, int hasAlpha) +{ + vector int16_t vv; + vector int32_t vy32_l, vy32_r, vu32_l, vu32_r, vv32_l, vv32_r, tmp32; + vector int32_t R_l, R_r, G_l, G_r, B_l, B_r; + vector int32_t tmp, tmp2, tmp3, tmp4; + vector uint16_t rd16, gd16, bd16; + vector uint8_t rd, bd, gd, ad, out0, out1, tmp8; + vector int16_t vlumFilter[MAX_FILTER_SIZE], vchrFilter[MAX_FILTER_SIZE]; + const vector int32_t ystart = vec_splats(1 << 9); + const vector int32_t uvstart = vec_splats((1 << 9) - (128 << 19)); + const vector uint16_t zero16 = vec_splat_u16(0); + const vector int32_t y_offset = vec_splats(c->yuv2rgb_y_offset); + const vector int32_t y_coeff = vec_splats(c->yuv2rgb_y_coeff); + const vector int32_t y_add = vec_splats(1 << 21); + const vector int32_t v2r_coeff = vec_splats(c->yuv2rgb_v2r_coeff); + const vector int32_t v2g_coeff = vec_splats(c->yuv2rgb_v2g_coeff); + const vector int32_t u2g_coeff = vec_splats(c->yuv2rgb_u2g_coeff); + const vector int32_t u2b_coeff = vec_splats(c->yuv2rgb_u2b_coeff); + const vector int32_t rgbclip = vec_splats(1 << 30); + const vector int32_t zero32 = vec_splat_s32(0); + const vector uint32_t shift22 = vec_splats(22U); + const vector uint32_t shift10 = vec_splat_u32(10); + int i, j; + + // Various permutations + const vector uint8_t perm3rg0 = (vector uint8_t) {0x0, 0x10, 0, + 0x1, 0x11, 0, + 0x2, 0x12, 0, + 0x3, 0x13, 0, + 0x4, 0x14, 0, + 0x5 }; + const vector uint8_t perm3rg1 = (vector uint8_t) { 0x15, 0, + 0x6, 0x16, 0, + 0x7, 0x17, 0 }; + const vector uint8_t perm3tb0 = (vector uint8_t) {0x0, 0x1, 0x10, + 0x3, 0x4, 0x11, + 0x6, 0x7, 0x12, + 0x9, 0xa, 0x13, + 0xc, 0xd, 0x14, + 0xf }; + const vector uint8_t perm3tb1 = (vector uint8_t) { 0x0, 0x15, + 0x2, 0x3, 0x16, + 0x5, 0x6, 0x17 }; + + ad = vec_splats((uint8_t) 255); + + for (i = 0; i < lumFilterSize; i++) + vlumFilter[i] = vec_splats(lumFilter[i]); + for (i = 0; i < chrFilterSize; i++) + vchrFilter[i] = vec_splats(chrFilter[i]); + + for (i = 0; i < dstW; i += 8) { + vy32_l = + vy32_r = ystart; + vu32_l = + vu32_r = + vv32_l = + vv32_r = uvstart; + + for (j = 0; j < lumFilterSize; j++) { + vv = vec_ld(0, &lumSrc[j][i]); + tmp = vec_mule(vv, vlumFilter[j]); + tmp2 = vec_mulo(vv, vlumFilter[j]); + tmp3 = vec_mergeh(tmp, tmp2); + tmp4 = vec_mergel(tmp, tmp2); + + vy32_l = vec_adds(vy32_l, tmp3); + vy32_r = vec_adds(vy32_r, tmp4); + } + + for (j = 0; j < chrFilterSize; j++) { + vv = vec_ld(0, &chrUSrc[j][i]); + tmp = vec_mule(vv, vchrFilter[j]); + tmp2 = vec_mulo(vv, vchrFilter[j]); + tmp3 = vec_mergeh(tmp, tmp2); + tmp4 = vec_mergel(tmp, tmp2); + + vu32_l = vec_adds(vu32_l, tmp3); + vu32_r = vec_adds(vu32_r, tmp4); + + vv = vec_ld(0, &chrVSrc[j][i]); + tmp = vec_mule(vv, vchrFilter[j]); + tmp2 = vec_mulo(vv, vchrFilter[j]); + tmp3 = vec_mergeh(tmp, tmp2); + tmp4 = vec_mergel(tmp, tmp2); + + vv32_l = vec_adds(vv32_l, tmp3); + vv32_r = vec_adds(vv32_r, tmp4); + } + + vy32_l = vec_sra(vy32_l, shift10); + vy32_r = vec_sra(vy32_r, shift10); + vu32_l = vec_sra(vu32_l, shift10); + vu32_r = vec_sra(vu32_r, shift10); + vv32_l = vec_sra(vv32_l, shift10); + vv32_r = vec_sra(vv32_r, shift10); + + vy32_l = vec_sub(vy32_l, y_offset); + vy32_r = vec_sub(vy32_r, y_offset); + vy32_l = vec_mul(vy32_l, y_coeff); + vy32_r = vec_mul(vy32_r, y_coeff); + vy32_l = vec_add(vy32_l, y_add); + vy32_r = vec_add(vy32_r, y_add); + + R_l = vec_mul(vv32_l, v2r_coeff); + R_l = vec_add(R_l, vy32_l); + R_r = vec_mul(vv32_r, v2r_coeff); + R_r = vec_add(R_r, vy32_r); + G_l = vec_mul(vv32_l, v2g_coeff); + tmp32 = vec_mul(vu32_l, u2g_coeff); + G_l = vec_add(G_l, vy32_l); + G_l = vec_add(G_l, tmp32); + G_r = vec_mul(vv32_r, v2g_coeff); + tmp32 = vec_mul(vu32_r, u2g_coeff); + G_r = vec_add(G_r, vy32_r); + G_r = vec_add(G_r, tmp32); + + B_l = vec_mul(vu32_l, u2b_coeff); + B_l = vec_add(B_l, vy32_l); + B_r = vec_mul(vu32_r, u2b_coeff); + B_r = vec_add(B_r, vy32_r); + + WRITERGB + } +} + +#define SETUP(x, buf0, alpha1, buf1, alpha) { \ + x = vec_ld(0, buf0); \ + tmp = vec_mule(x, alpha1); \ + tmp2 = vec_mulo(x, alpha1); \ + tmp3 = vec_mergeh(tmp, tmp2); \ + tmp4 = vec_mergel(tmp, tmp2); \ +\ + x = vec_ld(0, buf1); \ + tmp = vec_mule(x, alpha); \ + tmp2 = vec_mulo(x, alpha); \ + tmp5 = vec_mergeh(tmp, tmp2); \ + tmp6 = vec_mergel(tmp, tmp2); \ +\ + tmp3 = vec_add(tmp3, tmp5); \ + tmp4 = vec_add(tmp4, tmp6); \ +} + + +static av_always_inline void +yuv2rgb_full_2_vsx_template(SwsContext *c, const int16_t *buf[2], + const int16_t *ubuf[2], const int16_t *vbuf[2], + const int16_t *abuf[2], uint8_t *dest, int dstW, + int yalpha, int uvalpha, int y, + enum AVPixelFormat target, int hasAlpha) +{ + const int16_t *buf0 = buf[0], *buf1 = buf[1], + *ubuf0 = ubuf[0], *ubuf1 = ubuf[1], + *vbuf0 = vbuf[0], *vbuf1 = vbuf[1], + *abuf0 = hasAlpha ? abuf[0] : NULL, + *abuf1 = hasAlpha ? abuf[1] : NULL; + const int16_t yalpha1 = 4096 - yalpha; + const int16_t uvalpha1 = 4096 - uvalpha; + vector int16_t vy, vu, vv, A = vec_splat_s16(0); + vector int32_t vy32_l, vy32_r, vu32_l, vu32_r, vv32_l, vv32_r, tmp32; + vector int32_t R_l, R_r, G_l, G_r, B_l, B_r; + vector int32_t tmp, tmp2, tmp3, tmp4, tmp5, tmp6; + vector uint16_t rd16, gd16, bd16; + vector uint8_t rd, bd, gd, ad, out0, out1, tmp8; + const vector int16_t vyalpha1 = vec_splats(yalpha1); + const vector int16_t vuvalpha1 = vec_splats(uvalpha1); + const vector int16_t vyalpha = vec_splats((int16_t) yalpha); + const vector int16_t vuvalpha = vec_splats((int16_t) uvalpha); + const vector uint16_t zero16 = vec_splat_u16(0); + const vector int32_t y_offset = vec_splats(c->yuv2rgb_y_offset); + const vector int32_t y_coeff = vec_splats(c->yuv2rgb_y_coeff); + const vector int32_t y_add = vec_splats(1 << 21); + const vector int32_t v2r_coeff = vec_splats(c->yuv2rgb_v2r_coeff); + const vector int32_t v2g_coeff = vec_splats(c->yuv2rgb_v2g_coeff); + const vector int32_t u2g_coeff = vec_splats(c->yuv2rgb_u2g_coeff); + const vector int32_t u2b_coeff = vec_splats(c->yuv2rgb_u2b_coeff); + const vector int32_t rgbclip = vec_splats(1 << 30); + const vector int32_t zero32 = vec_splat_s32(0); + const vector uint32_t shift19 = vec_splats(19U); + const vector uint32_t shift22 = vec_splats(22U); + const vector uint32_t shift10 = vec_splat_u32(10); + const vector int32_t dec128 = vec_splats(128 << 19); + const vector int32_t add18 = vec_splats(1 << 18); + int i; + + // Various permutations + const vector uint8_t perm3rg0 = (vector uint8_t) {0x0, 0x10, 0, + 0x1, 0x11, 0, + 0x2, 0x12, 0, + 0x3, 0x13, 0, + 0x4, 0x14, 0, + 0x5 }; + const vector uint8_t perm3rg1 = (vector uint8_t) { 0x15, 0, + 0x6, 0x16, 0, + 0x7, 0x17, 0 }; + const vector uint8_t perm3tb0 = (vector uint8_t) {0x0, 0x1, 0x10, + 0x3, 0x4, 0x11, + 0x6, 0x7, 0x12, + 0x9, 0xa, 0x13, + 0xc, 0xd, 0x14, + 0xf }; + const vector uint8_t perm3tb1 = (vector uint8_t) { 0x0, 0x15, + 0x2, 0x3, 0x16, + 0x5, 0x6, 0x17 }; + + av_assert2(yalpha <= 4096U); + av_assert2(uvalpha <= 4096U); + + for (i = 0; i < dstW; i += 8) { + SETUP(vy, &buf0[i], vyalpha1, &buf1[i], vyalpha); + vy32_l = vec_sra(tmp3, shift10); + vy32_r = vec_sra(tmp4, shift10); + + SETUP(vu, &ubuf0[i], vuvalpha1, &ubuf1[i], vuvalpha); + tmp3 = vec_sub(tmp3, dec128); + tmp4 = vec_sub(tmp4, dec128); + vu32_l = vec_sra(tmp3, shift10); + vu32_r = vec_sra(tmp4, shift10); + + SETUP(vv, &vbuf0[i], vuvalpha1, &vbuf1[i], vuvalpha); + tmp3 = vec_sub(tmp3, dec128); + tmp4 = vec_sub(tmp4, dec128); + vv32_l = vec_sra(tmp3, shift10); + vv32_r = vec_sra(tmp4, shift10); + + if (hasAlpha) { + SETUP(A, &abuf0[i], vyalpha1, &abuf1[i], vyalpha); + tmp3 = vec_add(tmp3, add18); + tmp4 = vec_add(tmp4, add18); + tmp3 = vec_sra(tmp3, shift19); + tmp4 = vec_sra(tmp4, shift19); + A = vec_packs(tmp3, tmp4); + ad = vec_packsu(A, (vector int16_t) zero16); + } else { + ad = vec_splats((uint8_t) 255); + } + + vy32_l = vec_sub(vy32_l, y_offset); + vy32_r = vec_sub(vy32_r, y_offset); + vy32_l = vec_mul(vy32_l, y_coeff); + vy32_r = vec_mul(vy32_r, y_coeff); + vy32_l = vec_add(vy32_l, y_add); + vy32_r = vec_add(vy32_r, y_add); + + R_l = vec_mul(vv32_l, v2r_coeff); + R_l = vec_add(R_l, vy32_l); + R_r = vec_mul(vv32_r, v2r_coeff); + R_r = vec_add(R_r, vy32_r); + G_l = vec_mul(vv32_l, v2g_coeff); + tmp32 = vec_mul(vu32_l, u2g_coeff); + G_l = vec_add(G_l, vy32_l); + G_l = vec_add(G_l, tmp32); + G_r = vec_mul(vv32_r, v2g_coeff); + tmp32 = vec_mul(vu32_r, u2g_coeff); + G_r = vec_add(G_r, vy32_r); + G_r = vec_add(G_r, tmp32); + + B_l = vec_mul(vu32_l, u2b_coeff); + B_l = vec_add(B_l, vy32_l); + B_r = vec_mul(vu32_r, u2b_coeff); + B_r = vec_add(B_r, vy32_r); + + WRITERGB + } +} + +static av_always_inline void +yuv2rgb_2_vsx_template(SwsContext *c, const int16_t *buf[2], + const int16_t *ubuf[2], const int16_t *vbuf[2], + const int16_t *abuf[2], uint8_t *dest, int dstW, + int yalpha, int uvalpha, int y, + enum AVPixelFormat target, int hasAlpha) +{ + const int16_t *buf0 = buf[0], *buf1 = buf[1], + *ubuf0 = ubuf[0], *ubuf1 = ubuf[1], + *vbuf0 = vbuf[0], *vbuf1 = vbuf[1], + *abuf0 = hasAlpha ? abuf[0] : NULL, + *abuf1 = hasAlpha ? abuf[1] : NULL; + const int16_t yalpha1 = 4096 - yalpha; + const int16_t uvalpha1 = 4096 - uvalpha; + vector int16_t vy, vu, vv, A = vec_splat_s16(0); + vector int32_t vy32_l, vy32_r, vu32_l, vu32_r, vv32_l, vv32_r, tmp32; + vector int32_t R_l, R_r, G_l, G_r, B_l, B_r, vud32_l, vud32_r, vvd32_l, vvd32_r; + vector int32_t tmp, tmp2, tmp3, tmp4, tmp5, tmp6; + vector uint16_t rd16, gd16, bd16; + vector uint8_t rd, bd, gd, ad, out0, out1, tmp8; + const vector int16_t vyalpha1 = vec_splats(yalpha1); + const vector int16_t vuvalpha1 = vec_splats(uvalpha1); + const vector int16_t vyalpha = vec_splats((int16_t) yalpha); + const vector int16_t vuvalpha = vec_splats((int16_t) uvalpha); + const vector uint16_t zero16 = vec_splat_u16(0); + const vector int32_t y_offset = vec_splats(c->yuv2rgb_y_offset); + const vector int32_t y_coeff = vec_splats(c->yuv2rgb_y_coeff); + const vector int32_t y_add = vec_splats(1 << 21); + const vector int32_t v2r_coeff = vec_splats(c->yuv2rgb_v2r_coeff); + const vector int32_t v2g_coeff = vec_splats(c->yuv2rgb_v2g_coeff); + const vector int32_t u2g_coeff = vec_splats(c->yuv2rgb_u2g_coeff); + const vector int32_t u2b_coeff = vec_splats(c->yuv2rgb_u2b_coeff); + const vector int32_t rgbclip = vec_splats(1 << 30); + const vector int32_t zero32 = vec_splat_s32(0); + const vector uint32_t shift19 = vec_splats(19U); + const vector uint32_t shift22 = vec_splats(22U); + const vector uint32_t shift10 = vec_splat_u32(10); + const vector int32_t dec128 = vec_splats(128 << 19); + const vector int32_t add18 = vec_splats(1 << 18); + int i; + + // Various permutations + const vector uint8_t doubleleft = (vector uint8_t) {0, 1, 2, 3, + 0, 1, 2, 3, + 4, 5, 6, 7, + 4, 5, 6, 7 }; + const vector uint8_t doubleright = (vector uint8_t) {8, 9, 10, 11, + 8, 9, 10, 11, + 12, 13, 14, 15, + 12, 13, 14, 15 }; + const vector uint8_t perm3rg0 = (vector uint8_t) {0x0, 0x10, 0, + 0x1, 0x11, 0, + 0x2, 0x12, 0, + 0x3, 0x13, 0, + 0x4, 0x14, 0, + 0x5 }; + const vector uint8_t perm3rg1 = (vector uint8_t) { 0x15, 0, + 0x6, 0x16, 0, + 0x7, 0x17, 0 }; + const vector uint8_t perm3tb0 = (vector uint8_t) {0x0, 0x1, 0x10, + 0x3, 0x4, 0x11, + 0x6, 0x7, 0x12, + 0x9, 0xa, 0x13, + 0xc, 0xd, 0x14, + 0xf }; + const vector uint8_t perm3tb1 = (vector uint8_t) { 0x0, 0x15, + 0x2, 0x3, 0x16, + 0x5, 0x6, 0x17 }; + + av_assert2(yalpha <= 4096U); + av_assert2(uvalpha <= 4096U); + + for (i = 0; i < (dstW + 1) >> 1; i += 8) { + SETUP(vy, &buf0[i * 2], vyalpha1, &buf1[i * 2], vyalpha); + vy32_l = vec_sra(tmp3, shift10); + vy32_r = vec_sra(tmp4, shift10); + + SETUP(vu, &ubuf0[i], vuvalpha1, &ubuf1[i], vuvalpha); + tmp3 = vec_sub(tmp3, dec128); + tmp4 = vec_sub(tmp4, dec128); + vu32_l = vec_sra(tmp3, shift10); + vu32_r = vec_sra(tmp4, shift10); + + SETUP(vv, &vbuf0[i], vuvalpha1, &vbuf1[i], vuvalpha); + tmp3 = vec_sub(tmp3, dec128); + tmp4 = vec_sub(tmp4, dec128); + vv32_l = vec_sra(tmp3, shift10); + vv32_r = vec_sra(tmp4, shift10); + + if (hasAlpha) { + SETUP(A, &abuf0[i], vyalpha1, &abuf1[i], vyalpha); + tmp3 = vec_add(tmp3, add18); + tmp4 = vec_add(tmp4, add18); + tmp3 = vec_sra(tmp3, shift19); + tmp4 = vec_sra(tmp4, shift19); + A = vec_packs(tmp3, tmp4); + ad = vec_packsu(A, (vector int16_t) zero16); + } else { + ad = vec_splats((uint8_t) 255); + } + + vy32_l = vec_sub(vy32_l, y_offset); + vy32_r = vec_sub(vy32_r, y_offset); + vy32_l = vec_mul(vy32_l, y_coeff); + vy32_r = vec_mul(vy32_r, y_coeff); + vy32_l = vec_add(vy32_l, y_add); + vy32_r = vec_add(vy32_r, y_add); + + // Use the first UV half + vud32_l = vec_perm(vu32_l, vu32_l, doubleleft); + vud32_r = vec_perm(vu32_l, vu32_l, doubleright); + vvd32_l = vec_perm(vv32_l, vv32_l, doubleleft); + vvd32_r = vec_perm(vv32_l, vv32_l, doubleright); + + R_l = vec_mul(vvd32_l, v2r_coeff); + R_l = vec_add(R_l, vy32_l); + R_r = vec_mul(vvd32_r, v2r_coeff); + R_r = vec_add(R_r, vy32_r); + G_l = vec_mul(vvd32_l, v2g_coeff); + tmp32 = vec_mul(vud32_l, u2g_coeff); + G_l = vec_add(G_l, vy32_l); + G_l = vec_add(G_l, tmp32); + G_r = vec_mul(vvd32_r, v2g_coeff); + tmp32 = vec_mul(vud32_r, u2g_coeff); + G_r = vec_add(G_r, vy32_r); + G_r = vec_add(G_r, tmp32); + + B_l = vec_mul(vud32_l, u2b_coeff); + B_l = vec_add(B_l, vy32_l); + B_r = vec_mul(vud32_r, u2b_coeff); + B_r = vec_add(B_r, vy32_r); + + WRITERGB + + // New Y for the second half + SETUP(vy, &buf0[i * 2 + 8], vyalpha1, &buf1[i * 2 + 8], vyalpha); + vy32_l = vec_sra(tmp3, shift10); + vy32_r = vec_sra(tmp4, shift10); + + vy32_l = vec_sub(vy32_l, y_offset); + vy32_r = vec_sub(vy32_r, y_offset); + vy32_l = vec_mul(vy32_l, y_coeff); + vy32_r = vec_mul(vy32_r, y_coeff); + vy32_l = vec_add(vy32_l, y_add); + vy32_r = vec_add(vy32_r, y_add); + + // Second UV half + vud32_l = vec_perm(vu32_r, vu32_r, doubleleft); + vud32_r = vec_perm(vu32_r, vu32_r, doubleright); + vvd32_l = vec_perm(vv32_r, vv32_r, doubleleft); + vvd32_r = vec_perm(vv32_r, vv32_r, doubleright); + + R_l = vec_mul(vvd32_l, v2r_coeff); + R_l = vec_add(R_l, vy32_l); + R_r = vec_mul(vvd32_r, v2r_coeff); + R_r = vec_add(R_r, vy32_r); + G_l = vec_mul(vvd32_l, v2g_coeff); + tmp32 = vec_mul(vud32_l, u2g_coeff); + G_l = vec_add(G_l, vy32_l); + G_l = vec_add(G_l, tmp32); + G_r = vec_mul(vvd32_r, v2g_coeff); + tmp32 = vec_mul(vud32_r, u2g_coeff); + G_r = vec_add(G_r, vy32_r); + G_r = vec_add(G_r, tmp32); + + B_l = vec_mul(vud32_l, u2b_coeff); + B_l = vec_add(B_l, vy32_l); + B_r = vec_mul(vud32_r, u2b_coeff); + B_r = vec_add(B_r, vy32_r); + + WRITERGB + } +} + +#undef SETUP + +static av_always_inline void +yuv2rgb_full_1_vsx_template(SwsContext *c, const int16_t *buf0, + const int16_t *ubuf[2], const int16_t *vbuf[2], + const int16_t *abuf0, uint8_t *dest, int dstW, + int uvalpha, int y, enum AVPixelFormat target, + int hasAlpha) +{ + const int16_t *ubuf0 = ubuf[0], *vbuf0 = vbuf[0]; + const int16_t *ubuf1 = ubuf[1], *vbuf1 = vbuf[1]; + vector int16_t vy, vu, vv, A = vec_splat_s16(0), tmp16; + vector int32_t vy32_l, vy32_r, vu32_l, vu32_r, vv32_l, vv32_r, tmp32, tmp32_2; + vector int32_t R_l, R_r, G_l, G_r, B_l, B_r; + vector uint16_t rd16, gd16, bd16; + vector uint8_t rd, bd, gd, ad, out0, out1, tmp8; + const vector uint16_t zero16 = vec_splat_u16(0); + const vector int32_t y_offset = vec_splats(c->yuv2rgb_y_offset); + const vector int32_t y_coeff = vec_splats(c->yuv2rgb_y_coeff); + const vector int32_t y_add = vec_splats(1 << 21); + const vector int32_t v2r_coeff = vec_splats(c->yuv2rgb_v2r_coeff); + const vector int32_t v2g_coeff = vec_splats(c->yuv2rgb_v2g_coeff); + const vector int32_t u2g_coeff = vec_splats(c->yuv2rgb_u2g_coeff); + const vector int32_t u2b_coeff = vec_splats(c->yuv2rgb_u2b_coeff); + const vector int32_t rgbclip = vec_splats(1 << 30); + const vector int32_t zero32 = vec_splat_s32(0); + const vector uint32_t shift2 = vec_splat_u32(2); + const vector uint32_t shift22 = vec_splats(22U); + const vector uint16_t sub7 = vec_splats((uint16_t) (128 << 7)); + const vector uint16_t sub8 = vec_splats((uint16_t) (128 << 8)); + const vector int16_t mul4 = vec_splat_s16(4); + const vector int16_t mul8 = vec_splat_s16(8); + const vector int16_t add64 = vec_splat_s16(64); + const vector uint16_t shift7 = vec_splat_u16(7); + const vector int16_t max255 = vec_splat_s16(255); + int i; + + // Various permutations + const vector uint8_t perm3rg0 = (vector uint8_t) {0x0, 0x10, 0, + 0x1, 0x11, 0, + 0x2, 0x12, 0, + 0x3, 0x13, 0, + 0x4, 0x14, 0, + 0x5 }; + const vector uint8_t perm3rg1 = (vector uint8_t) { 0x15, 0, + 0x6, 0x16, 0, + 0x7, 0x17, 0 }; + const vector uint8_t perm3tb0 = (vector uint8_t) {0x0, 0x1, 0x10, + 0x3, 0x4, 0x11, + 0x6, 0x7, 0x12, + 0x9, 0xa, 0x13, + 0xc, 0xd, 0x14, + 0xf }; + const vector uint8_t perm3tb1 = (vector uint8_t) { 0x0, 0x15, + 0x2, 0x3, 0x16, + 0x5, 0x6, 0x17 }; + + for (i = 0; i < dstW; i += 8) { // The x86 asm also overwrites padding bytes. + vy = vec_ld(0, &buf0[i]); + vy32_l = vec_unpackh(vy); + vy32_r = vec_unpackl(vy); + vy32_l = vec_sl(vy32_l, shift2); + vy32_r = vec_sl(vy32_r, shift2); + + vu = vec_ld(0, &ubuf0[i]); + vv = vec_ld(0, &vbuf0[i]); + if (uvalpha < 2048) { + vu = (vector int16_t) vec_sub((vector uint16_t) vu, sub7); + vv = (vector int16_t) vec_sub((vector uint16_t) vv, sub7); + + tmp32 = vec_mule(vu, mul4); + tmp32_2 = vec_mulo(vu, mul4); + vu32_l = vec_mergeh(tmp32, tmp32_2); + vu32_r = vec_mergel(tmp32, tmp32_2); + tmp32 = vec_mule(vv, mul4); + tmp32_2 = vec_mulo(vv, mul4); + vv32_l = vec_mergeh(tmp32, tmp32_2); + vv32_r = vec_mergel(tmp32, tmp32_2); + } else { + tmp16 = vec_ld(0, &ubuf1[i]); + vu = vec_add(vu, tmp16); + vu = (vector int16_t) vec_sub((vector uint16_t) vu, sub8); + tmp16 = vec_ld(0, &vbuf1[i]); + vv = vec_add(vv, tmp16); + vv = (vector int16_t) vec_sub((vector uint16_t) vv, sub8); + + vu32_l = vec_mule(vu, mul8); + vu32_r = vec_mulo(vu, mul8); + vv32_l = vec_mule(vv, mul8); + vv32_r = vec_mulo(vv, mul8); + } + + if (hasAlpha) { + A = vec_ld(0, &abuf0[i]); + A = vec_add(A, add64); + A = vec_sr(A, shift7); + A = vec_max(A, max255); + ad = vec_packsu(A, (vector int16_t) zero16); + } else { + ad = vec_splats((uint8_t) 255); + } + + vy32_l = vec_sub(vy32_l, y_offset); + vy32_r = vec_sub(vy32_r, y_offset); + vy32_l = vec_mul(vy32_l, y_coeff); + vy32_r = vec_mul(vy32_r, y_coeff); + vy32_l = vec_add(vy32_l, y_add); + vy32_r = vec_add(vy32_r, y_add); + + R_l = vec_mul(vv32_l, v2r_coeff); + R_l = vec_add(R_l, vy32_l); + R_r = vec_mul(vv32_r, v2r_coeff); + R_r = vec_add(R_r, vy32_r); + G_l = vec_mul(vv32_l, v2g_coeff); + tmp32 = vec_mul(vu32_l, u2g_coeff); + G_l = vec_add(G_l, vy32_l); + G_l = vec_add(G_l, tmp32); + G_r = vec_mul(vv32_r, v2g_coeff); + tmp32 = vec_mul(vu32_r, u2g_coeff); + G_r = vec_add(G_r, vy32_r); + G_r = vec_add(G_r, tmp32); + + B_l = vec_mul(vu32_l, u2b_coeff); + B_l = vec_add(B_l, vy32_l); + B_r = vec_mul(vu32_r, u2b_coeff); + B_r = vec_add(B_r, vy32_r); + + WRITERGB + } +} + +static av_always_inline void +yuv2rgb_1_vsx_template(SwsContext *c, const int16_t *buf0, + const int16_t *ubuf[2], const int16_t *vbuf[2], + const int16_t *abuf0, uint8_t *dest, int dstW, + int uvalpha, int y, enum AVPixelFormat target, + int hasAlpha) +{ + const int16_t *ubuf0 = ubuf[0], *vbuf0 = vbuf[0]; + const int16_t *ubuf1 = ubuf[1], *vbuf1 = vbuf[1]; + vector int16_t vy, vu, vv, A = vec_splat_s16(0), tmp16; + vector int32_t vy32_l, vy32_r, vu32_l, vu32_r, vv32_l, vv32_r, tmp32, tmp32_2; + vector int32_t vud32_l, vud32_r, vvd32_l, vvd32_r; + vector int32_t R_l, R_r, G_l, G_r, B_l, B_r; + vector uint16_t rd16, gd16, bd16; + vector uint8_t rd, bd, gd, ad, out0, out1, tmp8; + const vector uint16_t zero16 = vec_splat_u16(0); + const vector int32_t y_offset = vec_splats(c->yuv2rgb_y_offset); + const vector int32_t y_coeff = vec_splats(c->yuv2rgb_y_coeff); + const vector int32_t y_add = vec_splats(1 << 21); + const vector int32_t v2r_coeff = vec_splats(c->yuv2rgb_v2r_coeff); + const vector int32_t v2g_coeff = vec_splats(c->yuv2rgb_v2g_coeff); + const vector int32_t u2g_coeff = vec_splats(c->yuv2rgb_u2g_coeff); + const vector int32_t u2b_coeff = vec_splats(c->yuv2rgb_u2b_coeff); + const vector int32_t rgbclip = vec_splats(1 << 30); + const vector int32_t zero32 = vec_splat_s32(0); + const vector uint32_t shift2 = vec_splat_u32(2); + const vector uint32_t shift22 = vec_splats(22U); + const vector uint16_t sub7 = vec_splats((uint16_t) (128 << 7)); + const vector uint16_t sub8 = vec_splats((uint16_t) (128 << 8)); + const vector int16_t mul4 = vec_splat_s16(4); + const vector int16_t mul8 = vec_splat_s16(8); + const vector int16_t add64 = vec_splat_s16(64); + const vector uint16_t shift7 = vec_splat_u16(7); + const vector int16_t max255 = vec_splat_s16(255); + int i; + + // Various permutations + const vector uint8_t doubleleft = (vector uint8_t) {0, 1, 2, 3, + 0, 1, 2, 3, + 4, 5, 6, 7, + 4, 5, 6, 7 }; + const vector uint8_t doubleright = (vector uint8_t) {8, 9, 10, 11, + 8, 9, 10, 11, + 12, 13, 14, 15, + 12, 13, 14, 15 }; + const vector uint8_t perm3rg0 = (vector uint8_t) {0x0, 0x10, 0, + 0x1, 0x11, 0, + 0x2, 0x12, 0, + 0x3, 0x13, 0, + 0x4, 0x14, 0, + 0x5 }; + const vector uint8_t perm3rg1 = (vector uint8_t) { 0x15, 0, + 0x6, 0x16, 0, + 0x7, 0x17, 0 }; + const vector uint8_t perm3tb0 = (vector uint8_t) {0x0, 0x1, 0x10, + 0x3, 0x4, 0x11, + 0x6, 0x7, 0x12, + 0x9, 0xa, 0x13, + 0xc, 0xd, 0x14, + 0xf }; + const vector uint8_t perm3tb1 = (vector uint8_t) { 0x0, 0x15, + 0x2, 0x3, 0x16, + 0x5, 0x6, 0x17 }; + + for (i = 0; i < (dstW + 1) >> 1; i += 8) { // The x86 asm also overwrites padding bytes. + vy = vec_ld(0, &buf0[i * 2]); + vy32_l = vec_unpackh(vy); + vy32_r = vec_unpackl(vy); + vy32_l = vec_sl(vy32_l, shift2); + vy32_r = vec_sl(vy32_r, shift2); + + vu = vec_ld(0, &ubuf0[i]); + vv = vec_ld(0, &vbuf0[i]); + if (uvalpha < 2048) { + vu = (vector int16_t) vec_sub((vector uint16_t) vu, sub7); + vv = (vector int16_t) vec_sub((vector uint16_t) vv, sub7); + + tmp32 = vec_mule(vu, mul4); + tmp32_2 = vec_mulo(vu, mul4); + vu32_l = vec_mergeh(tmp32, tmp32_2); + vu32_r = vec_mergel(tmp32, tmp32_2); + tmp32 = vec_mule(vv, mul4); + tmp32_2 = vec_mulo(vv, mul4); + vv32_l = vec_mergeh(tmp32, tmp32_2); + vv32_r = vec_mergel(tmp32, tmp32_2); + } else { + tmp16 = vec_ld(0, &ubuf1[i]); + vu = vec_add(vu, tmp16); + vu = (vector int16_t) vec_sub((vector uint16_t) vu, sub8); + tmp16 = vec_ld(0, &vbuf1[i]); + vv = vec_add(vv, tmp16); + vv = (vector int16_t) vec_sub((vector uint16_t) vv, sub8); + + vu32_l = vec_mule(vu, mul8); + vu32_r = vec_mulo(vu, mul8); + vv32_l = vec_mule(vv, mul8); + vv32_r = vec_mulo(vv, mul8); + } + + if (hasAlpha) { + A = vec_ld(0, &abuf0[i]); + A = vec_add(A, add64); + A = vec_sr(A, shift7); + A = vec_max(A, max255); + ad = vec_packsu(A, (vector int16_t) zero16); + } else { + ad = vec_splats((uint8_t) 255); + } + + vy32_l = vec_sub(vy32_l, y_offset); + vy32_r = vec_sub(vy32_r, y_offset); + vy32_l = vec_mul(vy32_l, y_coeff); + vy32_r = vec_mul(vy32_r, y_coeff); + vy32_l = vec_add(vy32_l, y_add); + vy32_r = vec_add(vy32_r, y_add); + + // Use the first UV half + vud32_l = vec_perm(vu32_l, vu32_l, doubleleft); + vud32_r = vec_perm(vu32_l, vu32_l, doubleright); + vvd32_l = vec_perm(vv32_l, vv32_l, doubleleft); + vvd32_r = vec_perm(vv32_l, vv32_l, doubleright); + + R_l = vec_mul(vvd32_l, v2r_coeff); + R_l = vec_add(R_l, vy32_l); + R_r = vec_mul(vvd32_r, v2r_coeff); + R_r = vec_add(R_r, vy32_r); + G_l = vec_mul(vvd32_l, v2g_coeff); + tmp32 = vec_mul(vud32_l, u2g_coeff); + G_l = vec_add(G_l, vy32_l); + G_l = vec_add(G_l, tmp32); + G_r = vec_mul(vvd32_r, v2g_coeff); + tmp32 = vec_mul(vud32_r, u2g_coeff); + G_r = vec_add(G_r, vy32_r); + G_r = vec_add(G_r, tmp32); + + B_l = vec_mul(vud32_l, u2b_coeff); + B_l = vec_add(B_l, vy32_l); + B_r = vec_mul(vud32_r, u2b_coeff); + B_r = vec_add(B_r, vy32_r); + + WRITERGB + + // New Y for the second half + vy = vec_ld(16, &buf0[i * 2]); + vy32_l = vec_unpackh(vy); + vy32_r = vec_unpackl(vy); + vy32_l = vec_sl(vy32_l, shift2); + vy32_r = vec_sl(vy32_r, shift2); + + vy32_l = vec_sub(vy32_l, y_offset); + vy32_r = vec_sub(vy32_r, y_offset); + vy32_l = vec_mul(vy32_l, y_coeff); + vy32_r = vec_mul(vy32_r, y_coeff); + vy32_l = vec_add(vy32_l, y_add); + vy32_r = vec_add(vy32_r, y_add); + + // Second UV half + vud32_l = vec_perm(vu32_r, vu32_r, doubleleft); + vud32_r = vec_perm(vu32_r, vu32_r, doubleright); + vvd32_l = vec_perm(vv32_r, vv32_r, doubleleft); + vvd32_r = vec_perm(vv32_r, vv32_r, doubleright); + + R_l = vec_mul(vvd32_l, v2r_coeff); + R_l = vec_add(R_l, vy32_l); + R_r = vec_mul(vvd32_r, v2r_coeff); + R_r = vec_add(R_r, vy32_r); + G_l = vec_mul(vvd32_l, v2g_coeff); + tmp32 = vec_mul(vud32_l, u2g_coeff); + G_l = vec_add(G_l, vy32_l); + G_l = vec_add(G_l, tmp32); + G_r = vec_mul(vvd32_r, v2g_coeff); + tmp32 = vec_mul(vud32_r, u2g_coeff); + G_r = vec_add(G_r, vy32_r); + G_r = vec_add(G_r, tmp32); + + B_l = vec_mul(vud32_l, u2b_coeff); + B_l = vec_add(B_l, vy32_l); + B_r = vec_mul(vud32_r, u2b_coeff); + B_r = vec_add(B_r, vy32_r); + + WRITERGB + } +} + +#undef WRITERGB + +#define YUV2RGBWRAPPERX(name, base, ext, fmt, hasAlpha) \ +static void name ## ext ## _X_vsx(SwsContext *c, const int16_t *lumFilter, \ + const int16_t **lumSrc, int lumFilterSize, \ + const int16_t *chrFilter, const int16_t **chrUSrc, \ + const int16_t **chrVSrc, int chrFilterSize, \ + const int16_t **alpSrc, uint8_t *dest, int dstW, \ + int y) \ +{ \ + name ## base ## _X_vsx_template(c, lumFilter, lumSrc, lumFilterSize, \ + chrFilter, chrUSrc, chrVSrc, chrFilterSize, \ + alpSrc, dest, dstW, y, fmt, hasAlpha); \ +} + +#define YUV2RGBWRAPPERX2(name, base, ext, fmt, hasAlpha) \ +static void name ## ext ## _2_vsx(SwsContext *c, const int16_t *buf[2], \ + const int16_t *ubuf[2], const int16_t *vbuf[2], \ + const int16_t *abuf[2], uint8_t *dest, int dstW, \ + int yalpha, int uvalpha, int y) \ +{ \ + name ## base ## _2_vsx_template(c, buf, ubuf, vbuf, abuf, \ + dest, dstW, yalpha, uvalpha, y, fmt, hasAlpha); \ +} + +#define YUV2RGBWRAPPER(name, base, ext, fmt, hasAlpha) \ +static void name ## ext ## _1_vsx(SwsContext *c, const int16_t *buf0, \ + const int16_t *ubuf[2], const int16_t *vbuf[2], \ + const int16_t *abuf0, uint8_t *dest, int dstW, \ + int uvalpha, int y) \ +{ \ + name ## base ## _1_vsx_template(c, buf0, ubuf, vbuf, abuf0, dest, \ + dstW, uvalpha, y, fmt, hasAlpha); \ +} + +YUV2RGBWRAPPER(yuv2, rgb, bgrx32, AV_PIX_FMT_BGRA, 0) +YUV2RGBWRAPPER(yuv2, rgb, rgbx32, AV_PIX_FMT_RGBA, 0) +YUV2RGBWRAPPER(yuv2, rgb, xrgb32, AV_PIX_FMT_ARGB, 0) +YUV2RGBWRAPPER(yuv2, rgb, xbgr32, AV_PIX_FMT_ABGR, 0) + +YUV2RGBWRAPPER(yuv2, rgb, rgb24, AV_PIX_FMT_RGB24, 0) +YUV2RGBWRAPPER(yuv2, rgb, bgr24, AV_PIX_FMT_BGR24, 0) + +YUV2RGBWRAPPERX2(yuv2, rgb, bgrx32, AV_PIX_FMT_BGRA, 0) +YUV2RGBWRAPPERX2(yuv2, rgb, rgbx32, AV_PIX_FMT_RGBA, 0) +YUV2RGBWRAPPERX2(yuv2, rgb, xrgb32, AV_PIX_FMT_ARGB, 0) +YUV2RGBWRAPPERX2(yuv2, rgb, xbgr32, AV_PIX_FMT_ABGR, 0) + +YUV2RGBWRAPPERX2(yuv2, rgb, rgb24, AV_PIX_FMT_RGB24, 0) +YUV2RGBWRAPPERX2(yuv2, rgb, bgr24, AV_PIX_FMT_BGR24, 0) + +YUV2RGBWRAPPER(yuv2, rgb_full, bgrx32_full, AV_PIX_FMT_BGRA, 0) +YUV2RGBWRAPPER(yuv2, rgb_full, rgbx32_full, AV_PIX_FMT_RGBA, 0) +YUV2RGBWRAPPER(yuv2, rgb_full, xrgb32_full, AV_PIX_FMT_ARGB, 0) +YUV2RGBWRAPPER(yuv2, rgb_full, xbgr32_full, AV_PIX_FMT_ABGR, 0) + +YUV2RGBWRAPPER(yuv2, rgb_full, rgb24_full, AV_PIX_FMT_RGB24, 0) +YUV2RGBWRAPPER(yuv2, rgb_full, bgr24_full, AV_PIX_FMT_BGR24, 0) + +YUV2RGBWRAPPERX2(yuv2, rgb_full, bgrx32_full, AV_PIX_FMT_BGRA, 0) +YUV2RGBWRAPPERX2(yuv2, rgb_full, rgbx32_full, AV_PIX_FMT_RGBA, 0) +YUV2RGBWRAPPERX2(yuv2, rgb_full, xrgb32_full, AV_PIX_FMT_ARGB, 0) +YUV2RGBWRAPPERX2(yuv2, rgb_full, xbgr32_full, AV_PIX_FMT_ABGR, 0) + +YUV2RGBWRAPPERX2(yuv2, rgb_full, rgb24_full, AV_PIX_FMT_RGB24, 0) +YUV2RGBWRAPPERX2(yuv2, rgb_full, bgr24_full, AV_PIX_FMT_BGR24, 0) + +YUV2RGBWRAPPERX(yuv2, rgb_full, bgrx32_full, AV_PIX_FMT_BGRA, 0) +YUV2RGBWRAPPERX(yuv2, rgb_full, rgbx32_full, AV_PIX_FMT_RGBA, 0) +YUV2RGBWRAPPERX(yuv2, rgb_full, xrgb32_full, AV_PIX_FMT_ARGB, 0) +YUV2RGBWRAPPERX(yuv2, rgb_full, xbgr32_full, AV_PIX_FMT_ABGR, 0) + +YUV2RGBWRAPPERX(yuv2, rgb_full, rgb24_full, AV_PIX_FMT_RGB24, 0) +YUV2RGBWRAPPERX(yuv2, rgb_full, bgr24_full, AV_PIX_FMT_BGR24, 0) + +static av_always_inline void +write422(const vector int16_t vy1, const vector int16_t vy2, + const vector int16_t vu, const vector int16_t vv, + uint8_t *dest, const enum AVPixelFormat target) +{ + vector uint8_t vd1, vd2, tmp; + const vector uint8_t yuyv1 = (vector uint8_t) { + 0x0, 0x10, 0x1, 0x18, + 0x2, 0x11, 0x3, 0x19, + 0x4, 0x12, 0x5, 0x1a, + 0x6, 0x13, 0x7, 0x1b }; + const vector uint8_t yuyv2 = (vector uint8_t) { + 0x8, 0x14, 0x9, 0x1c, + 0xa, 0x15, 0xb, 0x1d, + 0xc, 0x16, 0xd, 0x1e, + 0xe, 0x17, 0xf, 0x1f }; + const vector uint8_t yvyu1 = (vector uint8_t) { + 0x0, 0x18, 0x1, 0x10, + 0x2, 0x19, 0x3, 0x11, + 0x4, 0x1a, 0x5, 0x12, + 0x6, 0x1b, 0x7, 0x13 }; + const vector uint8_t yvyu2 = (vector uint8_t) { + 0x8, 0x1c, 0x9, 0x14, + 0xa, 0x1d, 0xb, 0x15, + 0xc, 0x1e, 0xd, 0x16, + 0xe, 0x1f, 0xf, 0x17 }; + const vector uint8_t uyvy1 = (vector uint8_t) { + 0x10, 0x0, 0x18, 0x1, + 0x11, 0x2, 0x19, 0x3, + 0x12, 0x4, 0x1a, 0x5, + 0x13, 0x6, 0x1b, 0x7 }; + const vector uint8_t uyvy2 = (vector uint8_t) { + 0x14, 0x8, 0x1c, 0x9, + 0x15, 0xa, 0x1d, 0xb, + 0x16, 0xc, 0x1e, 0xd, + 0x17, 0xe, 0x1f, 0xf }; + + vd1 = vec_packsu(vy1, vy2); + vd2 = vec_packsu(vu, vv); + + switch (target) { + case AV_PIX_FMT_YUYV422: + tmp = vec_perm(vd1, vd2, yuyv1); + vec_st(tmp, 0, dest); + tmp = vec_perm(vd1, vd2, yuyv2); + vec_st(tmp, 16, dest); + break; + case AV_PIX_FMT_YVYU422: + tmp = vec_perm(vd1, vd2, yvyu1); + vec_st(tmp, 0, dest); + tmp = vec_perm(vd1, vd2, yvyu2); + vec_st(tmp, 16, dest); + break; + case AV_PIX_FMT_UYVY422: + tmp = vec_perm(vd1, vd2, uyvy1); + vec_st(tmp, 0, dest); + tmp = vec_perm(vd1, vd2, uyvy2); + vec_st(tmp, 16, dest); + break; + } +} + +static av_always_inline void +yuv2422_X_vsx_template(SwsContext *c, const int16_t *lumFilter, + const int16_t **lumSrc, int lumFilterSize, + const int16_t *chrFilter, const int16_t **chrUSrc, + const int16_t **chrVSrc, int chrFilterSize, + const int16_t **alpSrc, uint8_t *dest, int dstW, + int y, enum AVPixelFormat target) +{ + int i, j; + vector int16_t vy1, vy2, vu, vv; + vector int32_t vy32[4], vu32[2], vv32[2], tmp, tmp2, tmp3, tmp4; + vector int16_t vlumFilter[MAX_FILTER_SIZE], vchrFilter[MAX_FILTER_SIZE]; + const vector int32_t start = vec_splats(1 << 18); + const vector uint32_t shift19 = vec_splats(19U); + + for (i = 0; i < lumFilterSize; i++) + vlumFilter[i] = vec_splats(lumFilter[i]); + for (i = 0; i < chrFilterSize; i++) + vchrFilter[i] = vec_splats(chrFilter[i]); + + for (i = 0; i < ((dstW + 1) >> 1); i += 8) { + vy32[0] = + vy32[1] = + vy32[2] = + vy32[3] = + vu32[0] = + vu32[1] = + vv32[0] = + vv32[1] = start; + + for (j = 0; j < lumFilterSize; j++) { + vv = vec_ld(0, &lumSrc[j][i * 2]); + tmp = vec_mule(vv, vlumFilter[j]); + tmp2 = vec_mulo(vv, vlumFilter[j]); + tmp3 = vec_mergeh(tmp, tmp2); + tmp4 = vec_mergel(tmp, tmp2); + + vy32[0] = vec_adds(vy32[0], tmp3); + vy32[1] = vec_adds(vy32[1], tmp4); + + vv = vec_ld(0, &lumSrc[j][(i + 4) * 2]); + tmp = vec_mule(vv, vlumFilter[j]); + tmp2 = vec_mulo(vv, vlumFilter[j]); + tmp3 = vec_mergeh(tmp, tmp2); + tmp4 = vec_mergel(tmp, tmp2); + + vy32[2] = vec_adds(vy32[2], tmp3); + vy32[3] = vec_adds(vy32[3], tmp4); + } + + for (j = 0; j < chrFilterSize; j++) { + vv = vec_ld(0, &chrUSrc[j][i]); + tmp = vec_mule(vv, vchrFilter[j]); + tmp2 = vec_mulo(vv, vchrFilter[j]); + tmp3 = vec_mergeh(tmp, tmp2); + tmp4 = vec_mergel(tmp, tmp2); + + vu32[0] = vec_adds(vu32[0], tmp3); + vu32[1] = vec_adds(vu32[1], tmp4); + + vv = vec_ld(0, &chrVSrc[j][i]); + tmp = vec_mule(vv, vchrFilter[j]); + tmp2 = vec_mulo(vv, vchrFilter[j]); + tmp3 = vec_mergeh(tmp, tmp2); + tmp4 = vec_mergel(tmp, tmp2); + + vv32[0] = vec_adds(vv32[0], tmp3); + vv32[1] = vec_adds(vv32[1], tmp4); + } + + for (j = 0; j < 4; j++) { + vy32[j] = vec_sra(vy32[j], shift19); + } + for (j = 0; j < 2; j++) { + vu32[j] = vec_sra(vu32[j], shift19); + vv32[j] = vec_sra(vv32[j], shift19); + } + + vy1 = vec_packs(vy32[0], vy32[1]); + vy2 = vec_packs(vy32[2], vy32[3]); + vu = vec_packs(vu32[0], vu32[1]); + vv = vec_packs(vv32[0], vv32[1]); + + write422(vy1, vy2, vu, vv, &dest[i * 4], target); + } +} + +#define SETUP(x, buf0, buf1, alpha) { \ + x = vec_ld(0, buf0); \ + tmp = vec_mule(x, alpha); \ + tmp2 = vec_mulo(x, alpha); \ + tmp3 = vec_mergeh(tmp, tmp2); \ + tmp4 = vec_mergel(tmp, tmp2); \ +\ + x = vec_ld(0, buf1); \ + tmp = vec_mule(x, alpha); \ + tmp2 = vec_mulo(x, alpha); \ + tmp5 = vec_mergeh(tmp, tmp2); \ + tmp6 = vec_mergel(tmp, tmp2); \ +\ + tmp3 = vec_add(tmp3, tmp5); \ + tmp4 = vec_add(tmp4, tmp6); \ +\ + tmp3 = vec_sra(tmp3, shift19); \ + tmp4 = vec_sra(tmp4, shift19); \ + x = vec_packs(tmp3, tmp4); \ +} + +static av_always_inline void +yuv2422_2_vsx_template(SwsContext *c, const int16_t *buf[2], + const int16_t *ubuf[2], const int16_t *vbuf[2], + const int16_t *abuf[2], uint8_t *dest, int dstW, + int yalpha, int uvalpha, int y, + enum AVPixelFormat target) +{ + const int16_t *buf0 = buf[0], *buf1 = buf[1], + *ubuf0 = ubuf[0], *ubuf1 = ubuf[1], + *vbuf0 = vbuf[0], *vbuf1 = vbuf[1]; + const int16_t yalpha1 = 4096 - yalpha; + const int16_t uvalpha1 = 4096 - uvalpha; + vector int16_t vy1, vy2, vu, vv; + vector int32_t tmp, tmp2, tmp3, tmp4, tmp5, tmp6; + const vector int16_t vyalpha1 = vec_splats(yalpha1); + const vector int16_t vuvalpha1 = vec_splats(uvalpha1); + const vector uint32_t shift19 = vec_splats(19U); + int i; + av_assert2(yalpha <= 4096U); + av_assert2(uvalpha <= 4096U); + + for (i = 0; i < ((dstW + 1) >> 1); i += 8) { + + SETUP(vy1, &buf0[i * 2], &buf1[i * 2], vyalpha1) + SETUP(vy2, &buf0[(i + 4) * 2], &buf1[(i + 4) * 2], vyalpha1) + SETUP(vu, &ubuf0[i], &ubuf1[i], vuvalpha1) + SETUP(vv, &vbuf0[i], &vbuf1[i], vuvalpha1) + + write422(vy1, vy2, vu, vv, &dest[i * 4], target); + } +} + +#undef SETUP + +static av_always_inline void +yuv2422_1_vsx_template(SwsContext *c, const int16_t *buf0, + const int16_t *ubuf[2], const int16_t *vbuf[2], + const int16_t *abuf0, uint8_t *dest, int dstW, + int uvalpha, int y, enum AVPixelFormat target) +{ + const int16_t *ubuf0 = ubuf[0], *vbuf0 = vbuf[0]; + vector int16_t vy1, vy2, vu, vv, tmp; + const vector int16_t add64 = vec_splats((int16_t) 64); + const vector int16_t add128 = vec_splats((int16_t) 128); + const vector uint16_t shift7 = vec_splat_u16(7); + const vector uint16_t shift8 = vec_splat_u16(8); + int i; + + if (uvalpha < 2048) { + for (i = 0; i < ((dstW + 1) >> 1); i += 8) { + vy1 = vec_ld(0, &buf0[i * 2]); + vy2 = vec_ld(0, &buf0[(i + 4) * 2]); + vu = vec_ld(0, &ubuf0[i]); + vv = vec_ld(0, &vbuf0[i]); + + vy1 = vec_add(vy1, add64); + vy2 = vec_add(vy2, add64); + vu = vec_add(vu, add64); + vv = vec_add(vv, add64); + + vy1 = vec_sra(vy1, shift7); + vy2 = vec_sra(vy2, shift7); + vu = vec_sra(vu, shift7); + vv = vec_sra(vv, shift7); + + write422(vy1, vy2, vu, vv, &dest[i * 4], target); + } + } else { + const int16_t *ubuf1 = ubuf[1], *vbuf1 = vbuf[1]; + for (i = 0; i < ((dstW + 1) >> 1); i += 8) { + vy1 = vec_ld(0, &buf0[i * 2]); + vy2 = vec_ld(0, &buf0[(i + 4) * 2]); + vu = vec_ld(0, &ubuf0[i]); + tmp = vec_ld(0, &ubuf1[i]); + vu = vec_adds(vu, tmp); + vv = vec_ld(0, &vbuf0[i]); + tmp = vec_ld(0, &vbuf1[i]); + vv = vec_adds(vv, tmp); + + vy1 = vec_add(vy1, add64); + vy2 = vec_add(vy2, add64); + vu = vec_adds(vu, add128); + vv = vec_adds(vv, add128); + + vy1 = vec_sra(vy1, shift7); + vy2 = vec_sra(vy2, shift7); + vu = vec_sra(vu, shift8); + vv = vec_sra(vv, shift8); + + write422(vy1, vy2, vu, vv, &dest[i * 4], target); + } + } +} + +#define YUV2PACKEDWRAPPERX(name, base, ext, fmt) \ +static void name ## ext ## _X_vsx(SwsContext *c, const int16_t *lumFilter, \ + const int16_t **lumSrc, int lumFilterSize, \ + const int16_t *chrFilter, const int16_t **chrUSrc, \ + const int16_t **chrVSrc, int chrFilterSize, \ + const int16_t **alpSrc, uint8_t *dest, int dstW, \ + int y) \ +{ \ + name ## base ## _X_vsx_template(c, lumFilter, lumSrc, lumFilterSize, \ + chrFilter, chrUSrc, chrVSrc, chrFilterSize, \ + alpSrc, dest, dstW, y, fmt); \ +} + +#define YUV2PACKEDWRAPPER2(name, base, ext, fmt) \ +YUV2PACKEDWRAPPERX(name, base, ext, fmt) \ +static void name ## ext ## _2_vsx(SwsContext *c, const int16_t *buf[2], \ + const int16_t *ubuf[2], const int16_t *vbuf[2], \ + const int16_t *abuf[2], uint8_t *dest, int dstW, \ + int yalpha, int uvalpha, int y) \ +{ \ + name ## base ## _2_vsx_template(c, buf, ubuf, vbuf, abuf, \ + dest, dstW, yalpha, uvalpha, y, fmt); \ +} + +#define YUV2PACKEDWRAPPER(name, base, ext, fmt) \ +YUV2PACKEDWRAPPER2(name, base, ext, fmt) \ +static void name ## ext ## _1_vsx(SwsContext *c, const int16_t *buf0, \ + const int16_t *ubuf[2], const int16_t *vbuf[2], \ + const int16_t *abuf0, uint8_t *dest, int dstW, \ + int uvalpha, int y) \ +{ \ + name ## base ## _1_vsx_template(c, buf0, ubuf, vbuf, \ + abuf0, dest, dstW, uvalpha, \ + y, fmt); \ +} + +YUV2PACKEDWRAPPER(yuv2, 422, yuyv422, AV_PIX_FMT_YUYV422) +YUV2PACKEDWRAPPER(yuv2, 422, yvyu422, AV_PIX_FMT_YVYU422) +YUV2PACKEDWRAPPER(yuv2, 422, uyvy422, AV_PIX_FMT_UYVY422) + +static void hyscale_fast_vsx(SwsContext *c, int16_t *dst, int dstWidth, + const uint8_t *src, int srcW, int xInc) +{ + int i; + unsigned int xpos = 0, xx; + vector uint8_t vin, vin2, vperm; + vector int8_t vmul, valpha; + vector int16_t vtmp, vtmp2, vtmp3, vtmp4; + vector uint16_t vd_l, vd_r, vcoord16[2]; + vector uint32_t vcoord[4]; + const vector uint32_t vadd = (vector uint32_t) { + 0, + xInc * 1, + xInc * 2, + xInc * 3, + }; + const vector uint16_t vadd16 = (vector uint16_t) { // Modulo math + 0, + xInc * 1, + xInc * 2, + xInc * 3, + xInc * 4, + xInc * 5, + xInc * 6, + xInc * 7, + }; + const vector uint32_t vshift16 = vec_splats((uint32_t) 16); + const vector uint16_t vshift9 = vec_splat_u16(9); + const vector uint8_t vzero = vec_splat_u8(0); + const vector uint16_t vshift = vec_splat_u16(7); + + for (i = 0; i < dstWidth; i += 16) { + vcoord16[0] = vec_splats((uint16_t) xpos); + vcoord16[1] = vec_splats((uint16_t) (xpos + xInc * 8)); + + vcoord16[0] = vec_add(vcoord16[0], vadd16); + vcoord16[1] = vec_add(vcoord16[1], vadd16); + + vcoord16[0] = vec_sr(vcoord16[0], vshift9); + vcoord16[1] = vec_sr(vcoord16[1], vshift9); + valpha = (vector int8_t) vec_pack(vcoord16[0], vcoord16[1]); + + xx = xpos >> 16; + vin = vec_vsx_ld(0, &src[xx]); + + vcoord[0] = vec_splats(xpos & 0xffff); + vcoord[1] = vec_splats((xpos & 0xffff) + xInc * 4); + vcoord[2] = vec_splats((xpos & 0xffff) + xInc * 8); + vcoord[3] = vec_splats((xpos & 0xffff) + xInc * 12); + + vcoord[0] = vec_add(vcoord[0], vadd); + vcoord[1] = vec_add(vcoord[1], vadd); + vcoord[2] = vec_add(vcoord[2], vadd); + vcoord[3] = vec_add(vcoord[3], vadd); + + vcoord[0] = vec_sr(vcoord[0], vshift16); + vcoord[1] = vec_sr(vcoord[1], vshift16); + vcoord[2] = vec_sr(vcoord[2], vshift16); + vcoord[3] = vec_sr(vcoord[3], vshift16); + + vcoord16[0] = vec_pack(vcoord[0], vcoord[1]); + vcoord16[1] = vec_pack(vcoord[2], vcoord[3]); + vperm = vec_pack(vcoord16[0], vcoord16[1]); + + vin = vec_perm(vin, vin, vperm); + + vin2 = vec_vsx_ld(1, &src[xx]); + vin2 = vec_perm(vin2, vin2, vperm); + + vmul = (vector int8_t) vec_sub(vin2, vin); + vtmp = vec_mule(vmul, valpha); + vtmp2 = vec_mulo(vmul, valpha); + vtmp3 = vec_mergeh(vtmp, vtmp2); + vtmp4 = vec_mergel(vtmp, vtmp2); + + vd_l = (vector uint16_t) vec_mergeh(vin, vzero); + vd_r = (vector uint16_t) vec_mergel(vin, vzero); + vd_l = vec_sl(vd_l, vshift); + vd_r = vec_sl(vd_r, vshift); + + vd_l = vec_add(vd_l, (vector uint16_t) vtmp3); + vd_r = vec_add(vd_r, (vector uint16_t) vtmp4); + + vec_st((vector int16_t) vd_l, 0, &dst[i]); + vec_st((vector int16_t) vd_r, 0, &dst[i + 8]); + + xpos += xInc * 16; + } + for (i=dstWidth-1; (i*xInc)>>16 >=srcW-1; i--) + dst[i] = src[srcW-1]*128; +} + +#define HCSCALE(in, out) \ + vin = vec_vsx_ld(0, &in[xx]); \ + vin = vec_perm(vin, vin, vperm); \ +\ + vin2 = vec_vsx_ld(1, &in[xx]); \ + vin2 = vec_perm(vin2, vin2, vperm); \ +\ + vtmp = vec_mule(vin, valphaxor); \ + vtmp2 = vec_mulo(vin, valphaxor); \ + vtmp3 = vec_mergeh(vtmp, vtmp2); \ + vtmp4 = vec_mergel(vtmp, vtmp2); \ +\ + vtmp = vec_mule(vin2, valpha); \ + vtmp2 = vec_mulo(vin2, valpha); \ + vd_l = vec_mergeh(vtmp, vtmp2); \ + vd_r = vec_mergel(vtmp, vtmp2); \ +\ + vd_l = vec_add(vd_l, vtmp3); \ + vd_r = vec_add(vd_r, vtmp4); \ +\ + vec_st((vector int16_t) vd_l, 0, &out[i]); \ + vec_st((vector int16_t) vd_r, 0, &out[i + 8]) + +static void hcscale_fast_vsx(SwsContext *c, int16_t *dst1, int16_t *dst2, + int dstWidth, const uint8_t *src1, + const uint8_t *src2, int srcW, int xInc) +{ + int i; + unsigned int xpos = 0, xx; + vector uint8_t vin, vin2, vperm; + vector uint8_t valpha, valphaxor; + vector uint16_t vtmp, vtmp2, vtmp3, vtmp4; + vector uint16_t vd_l, vd_r, vcoord16[2]; + vector uint32_t vcoord[4]; + const vector uint8_t vxor = vec_splats((uint8_t) 127); + const vector uint32_t vadd = (vector uint32_t) { + 0, + xInc * 1, + xInc * 2, + xInc * 3, + }; + const vector uint16_t vadd16 = (vector uint16_t) { // Modulo math + 0, + xInc * 1, + xInc * 2, + xInc * 3, + xInc * 4, + xInc * 5, + xInc * 6, + xInc * 7, + }; + const vector uint32_t vshift16 = vec_splats((uint32_t) 16); + const vector uint16_t vshift9 = vec_splat_u16(9); + + for (i = 0; i < dstWidth; i += 16) { + vcoord16[0] = vec_splats((uint16_t) xpos); + vcoord16[1] = vec_splats((uint16_t) (xpos + xInc * 8)); + + vcoord16[0] = vec_add(vcoord16[0], vadd16); + vcoord16[1] = vec_add(vcoord16[1], vadd16); + + vcoord16[0] = vec_sr(vcoord16[0], vshift9); + vcoord16[1] = vec_sr(vcoord16[1], vshift9); + valpha = vec_pack(vcoord16[0], vcoord16[1]); + valphaxor = vec_xor(valpha, vxor); + + xx = xpos >> 16; + + vcoord[0] = vec_splats(xpos & 0xffff); + vcoord[1] = vec_splats((xpos & 0xffff) + xInc * 4); + vcoord[2] = vec_splats((xpos & 0xffff) + xInc * 8); + vcoord[3] = vec_splats((xpos & 0xffff) + xInc * 12); + + vcoord[0] = vec_add(vcoord[0], vadd); + vcoord[1] = vec_add(vcoord[1], vadd); + vcoord[2] = vec_add(vcoord[2], vadd); + vcoord[3] = vec_add(vcoord[3], vadd); + + vcoord[0] = vec_sr(vcoord[0], vshift16); + vcoord[1] = vec_sr(vcoord[1], vshift16); + vcoord[2] = vec_sr(vcoord[2], vshift16); + vcoord[3] = vec_sr(vcoord[3], vshift16); + + vcoord16[0] = vec_pack(vcoord[0], vcoord[1]); + vcoord16[1] = vec_pack(vcoord[2], vcoord[3]); + vperm = vec_pack(vcoord16[0], vcoord16[1]); + + HCSCALE(src1, dst1); + HCSCALE(src2, dst2); + + xpos += xInc * 16; + } + for (i=dstWidth-1; (i*xInc)>>16 >=srcW-1; i--) { + dst1[i] = src1[srcW-1]*128; + dst2[i] = src2[srcW-1]*128; + } +} + +#undef HCSCALE + +static void hScale8To19_vsx(SwsContext *c, int16_t *_dst, int dstW, + const uint8_t *src, const int16_t *filter, + const int32_t *filterPos, int filterSize) +{ + int i, j; + int32_t *dst = (int32_t *) _dst; + vector int16_t vfilter, vin; + vector uint8_t vin8; + vector int32_t vout; + const vector uint8_t vzero = vec_splat_u8(0); + const vector uint8_t vunusedtab[8] = { + (vector uint8_t) {0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, + 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf}, + (vector uint8_t) {0x0, 0x1, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10}, + (vector uint8_t) {0x0, 0x1, 0x2, 0x3, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10}, + (vector uint8_t) {0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10}, + (vector uint8_t) {0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10}, + (vector uint8_t) {0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, + 0x8, 0x9, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10}, + (vector uint8_t) {0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, + 0x8, 0x9, 0xa, 0xb, 0x10, 0x10, 0x10, 0x10}, + (vector uint8_t) {0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, + 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0x10, 0x10}, + }; + const vector uint8_t vunused = vunusedtab[filterSize % 8]; + + if (filterSize == 1) { + for (i = 0; i < dstW; i++) { + int srcPos = filterPos[i]; + int val = 0; + for (j = 0; j < filterSize; j++) { + val += ((int)src[srcPos + j]) * filter[filterSize * i + j]; + } + dst[i] = FFMIN(val >> 3, (1 << 19) - 1); // the cubic equation does overflow ... + } + } else { + for (i = 0; i < dstW; i++) { + const int srcPos = filterPos[i]; + vout = vec_splat_s32(0); + for (j = 0; j < filterSize; j += 8) { + vin8 = vec_vsx_ld(0, &src[srcPos + j]); + vin = (vector int16_t) vec_mergeh(vin8, vzero); + if (j + 8 > filterSize) // Remove the unused elements on the last round + vin = vec_perm(vin, (vector int16_t) vzero, vunused); + + vfilter = vec_vsx_ld(0, &filter[filterSize * i + j]); + vout = vec_msums(vin, vfilter, vout); + } + vout = vec_sums(vout, (vector int32_t) vzero); + dst[i] = FFMIN(vout[3] >> 3, (1 << 19) - 1); + } + } +} + +static void hScale16To19_vsx(SwsContext *c, int16_t *_dst, int dstW, + const uint8_t *_src, const int16_t *filter, + const int32_t *filterPos, int filterSize) +{ + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(c->srcFormat); + int i, j; + int32_t *dst = (int32_t *) _dst; + const uint16_t *src = (const uint16_t *) _src; + int bits = desc->comp[0].depth - 1; + int sh = bits - 4; + vector int16_t vfilter, vin; + vector int32_t vout, vtmp, vtmp2, vfilter32_l, vfilter32_r; + const vector uint8_t vzero = vec_splat_u8(0); + const vector uint8_t vunusedtab[8] = { + (vector uint8_t) {0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, + 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf}, + (vector uint8_t) {0x0, 0x1, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10}, + (vector uint8_t) {0x0, 0x1, 0x2, 0x3, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10}, + (vector uint8_t) {0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10}, + (vector uint8_t) {0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10}, + (vector uint8_t) {0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, + 0x8, 0x9, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10}, + (vector uint8_t) {0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, + 0x8, 0x9, 0xa, 0xb, 0x10, 0x10, 0x10, 0x10}, + (vector uint8_t) {0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, + 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0x10, 0x10}, + }; + const vector uint8_t vunused = vunusedtab[filterSize % 8]; + + if ((isAnyRGB(c->srcFormat) || c->srcFormat==AV_PIX_FMT_PAL8) && desc->comp[0].depth<16) { + sh = 9; + } else if (desc->flags & AV_PIX_FMT_FLAG_FLOAT) { /* float input are process like uint 16bpc */ + sh = 16 - 1 - 4; + } + + if (filterSize == 1) { + for (i = 0; i < dstW; i++) { + int srcPos = filterPos[i]; + int val = 0; + + for (j = 0; j < filterSize; j++) { + val += src[srcPos + j] * filter[filterSize * i + j]; + } + // filter=14 bit, input=16 bit, output=30 bit, >> 11 makes 19 bit + dst[i] = FFMIN(val >> sh, (1 << 19) - 1); + } + } else { + for (i = 0; i < dstW; i++) { + const int srcPos = filterPos[i]; + vout = vec_splat_s32(0); + for (j = 0; j < filterSize; j += 8) { + vin = (vector int16_t) vec_vsx_ld(0, &src[srcPos + j]); + if (j + 8 > filterSize) // Remove the unused elements on the last round + vin = vec_perm(vin, (vector int16_t) vzero, vunused); + + vfilter = vec_vsx_ld(0, &filter[filterSize * i + j]); + vfilter32_l = vec_unpackh(vfilter); + vfilter32_r = vec_unpackl(vfilter); + + vtmp = (vector int32_t) vec_mergeh(vin, (vector int16_t) vzero); + vtmp2 = (vector int32_t) vec_mergel(vin, (vector int16_t) vzero); + + vtmp = vec_mul(vtmp, vfilter32_l); + vtmp2 = vec_mul(vtmp2, vfilter32_r); + + vout = vec_adds(vout, vtmp); + vout = vec_adds(vout, vtmp2); + } + vout = vec_sums(vout, (vector int32_t) vzero); + dst[i] = FFMIN(vout[3] >> sh, (1 << 19) - 1); + } + } +} + +static void hScale16To15_vsx(SwsContext *c, int16_t *dst, int dstW, + const uint8_t *_src, const int16_t *filter, + const int32_t *filterPos, int filterSize) +{ + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(c->srcFormat); + int i, j; + const uint16_t *src = (const uint16_t *) _src; + int sh = desc->comp[0].depth - 1; + vector int16_t vfilter, vin; + vector int32_t vout, vtmp, vtmp2, vfilter32_l, vfilter32_r; + const vector uint8_t vzero = vec_splat_u8(0); + const vector uint8_t vunusedtab[8] = { + (vector uint8_t) {0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, + 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf}, + (vector uint8_t) {0x0, 0x1, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10}, + (vector uint8_t) {0x0, 0x1, 0x2, 0x3, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10}, + (vector uint8_t) {0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10}, + (vector uint8_t) {0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10}, + (vector uint8_t) {0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, + 0x8, 0x9, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10}, + (vector uint8_t) {0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, + 0x8, 0x9, 0xa, 0xb, 0x10, 0x10, 0x10, 0x10}, + (vector uint8_t) {0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, + 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0x10, 0x10}, + }; + const vector uint8_t vunused = vunusedtab[filterSize % 8]; + + if (sh<15) { + sh = isAnyRGB(c->srcFormat) || c->srcFormat==AV_PIX_FMT_PAL8 ? 13 : (desc->comp[0].depth - 1); + } else if (desc->flags & AV_PIX_FMT_FLAG_FLOAT) { /* float input are process like uint 16bpc */ + sh = 16 - 1; + } + + if (filterSize == 1) { + for (i = 0; i < dstW; i++) { + int srcPos = filterPos[i]; + int val = 0; + + for (j = 0; j < filterSize; j++) { + val += src[srcPos + j] * filter[filterSize * i + j]; + } + // filter=14 bit, input=16 bit, output=30 bit, >> 15 makes 15 bit + dst[i] = FFMIN(val >> sh, (1 << 15) - 1); + } + } else { + for (i = 0; i < dstW; i++) { + const int srcPos = filterPos[i]; + vout = vec_splat_s32(0); + for (j = 0; j < filterSize; j += 8) { + vin = (vector int16_t) vec_vsx_ld(0, &src[srcPos + j]); + if (j + 8 > filterSize) // Remove the unused elements on the last round + vin = vec_perm(vin, (vector int16_t) vzero, vunused); + + vfilter = vec_vsx_ld(0, &filter[filterSize * i + j]); + vfilter32_l = vec_unpackh(vfilter); + vfilter32_r = vec_unpackl(vfilter); + + vtmp = (vector int32_t) vec_mergeh(vin, (vector int16_t) vzero); + vtmp2 = (vector int32_t) vec_mergel(vin, (vector int16_t) vzero); + + vtmp = vec_mul(vtmp, vfilter32_l); + vtmp2 = vec_mul(vtmp2, vfilter32_r); + + vout = vec_adds(vout, vtmp); + vout = vec_adds(vout, vtmp2); + } + vout = vec_sums(vout, (vector int32_t) vzero); + dst[i] = FFMIN(vout[3] >> sh, (1 << 15) - 1); + } + } +} + +#endif /* !HAVE_BIGENDIAN */ + +#endif /* HAVE_VSX */ + +av_cold void ff_sws_init_swscale_vsx(SwsContext *c) +{ +#if HAVE_VSX + enum AVPixelFormat dstFormat = c->dstFormat; + const int cpu_flags = av_get_cpu_flags(); + const unsigned char power8 = HAVE_POWER8 && cpu_flags & AV_CPU_FLAG_POWER8; + + if (!(cpu_flags & AV_CPU_FLAG_VSX)) + return; + +#if !HAVE_BIGENDIAN + if (c->srcBpc == 8) { + if (c->dstBpc <= 14) { + c->hyScale = c->hcScale = hScale_real_vsx; + if (c->flags & SWS_FAST_BILINEAR && c->dstW >= c->srcW && c->chrDstW >= c->chrSrcW) { + c->hyscale_fast = hyscale_fast_vsx; + c->hcscale_fast = hcscale_fast_vsx; + } + } else { + c->hyScale = c->hcScale = hScale8To19_vsx; + } + } else { + if (power8) { + c->hyScale = c->hcScale = c->dstBpc > 14 ? hScale16To19_vsx + : hScale16To15_vsx; + } + } + if (!is16BPS(dstFormat) && !isNBPS(dstFormat) && !isSemiPlanarYUV(dstFormat) && + dstFormat != AV_PIX_FMT_GRAYF32BE && dstFormat != AV_PIX_FMT_GRAYF32LE && + !c->needAlpha) { + c->yuv2planeX = yuv2planeX_vsx; + } +#endif + + if (!(c->flags & (SWS_BITEXACT | SWS_FULL_CHR_H_INT)) && !c->needAlpha) { + switch (c->dstBpc) { + case 8: + c->yuv2plane1 = yuv2plane1_8_vsx; + break; +#if !HAVE_BIGENDIAN + case 9: + c->yuv2plane1 = isBE(dstFormat) ? yuv2plane1_9BE_vsx : yuv2plane1_9LE_vsx; + c->yuv2planeX = isBE(dstFormat) ? yuv2planeX_9BE_vsx : yuv2planeX_9LE_vsx; + break; + case 10: + c->yuv2plane1 = isBE(dstFormat) ? yuv2plane1_10BE_vsx : yuv2plane1_10LE_vsx; + c->yuv2planeX = isBE(dstFormat) ? yuv2planeX_10BE_vsx : yuv2planeX_10LE_vsx; + break; + case 12: + c->yuv2plane1 = isBE(dstFormat) ? yuv2plane1_12BE_vsx : yuv2plane1_12LE_vsx; + c->yuv2planeX = isBE(dstFormat) ? yuv2planeX_12BE_vsx : yuv2planeX_12LE_vsx; + break; + case 14: + c->yuv2plane1 = isBE(dstFormat) ? yuv2plane1_14BE_vsx : yuv2plane1_14LE_vsx; + c->yuv2planeX = isBE(dstFormat) ? yuv2planeX_14BE_vsx : yuv2planeX_14LE_vsx; + break; + case 16: + c->yuv2plane1 = isBE(dstFormat) ? yuv2plane1_16BE_vsx : yuv2plane1_16LE_vsx; +#if HAVE_POWER8 + if (cpu_flags & AV_CPU_FLAG_POWER8) { + c->yuv2planeX = isBE(dstFormat) ? yuv2planeX_16BE_vsx : yuv2planeX_16LE_vsx; + } +#endif /* HAVE_POWER8 */ + break; +#endif /* !HAVE_BIGENDIAN */ + } + } + + if (c->flags & SWS_BITEXACT) + return; + +#if !HAVE_BIGENDIAN + if (c->flags & SWS_FULL_CHR_H_INT) { + switch (dstFormat) { + case AV_PIX_FMT_RGB24: + if (power8) { + c->yuv2packed1 = yuv2rgb24_full_1_vsx; + c->yuv2packed2 = yuv2rgb24_full_2_vsx; + c->yuv2packedX = yuv2rgb24_full_X_vsx; + } + break; + case AV_PIX_FMT_BGR24: + if (power8) { + c->yuv2packed1 = yuv2bgr24_full_1_vsx; + c->yuv2packed2 = yuv2bgr24_full_2_vsx; + c->yuv2packedX = yuv2bgr24_full_X_vsx; + } + break; + case AV_PIX_FMT_BGRA: + if (power8) { + if (!c->needAlpha) { + c->yuv2packed1 = yuv2bgrx32_full_1_vsx; + c->yuv2packed2 = yuv2bgrx32_full_2_vsx; + c->yuv2packedX = yuv2bgrx32_full_X_vsx; + } + } + break; + case AV_PIX_FMT_RGBA: + if (power8) { + if (!c->needAlpha) { + c->yuv2packed1 = yuv2rgbx32_full_1_vsx; + c->yuv2packed2 = yuv2rgbx32_full_2_vsx; + c->yuv2packedX = yuv2rgbx32_full_X_vsx; + } + } + break; + case AV_PIX_FMT_ARGB: + if (power8) { + if (!c->needAlpha) { + c->yuv2packed1 = yuv2xrgb32_full_1_vsx; + c->yuv2packed2 = yuv2xrgb32_full_2_vsx; + c->yuv2packedX = yuv2xrgb32_full_X_vsx; + } + } + break; + case AV_PIX_FMT_ABGR: + if (power8) { + if (!c->needAlpha) { + c->yuv2packed1 = yuv2xbgr32_full_1_vsx; + c->yuv2packed2 = yuv2xbgr32_full_2_vsx; + c->yuv2packedX = yuv2xbgr32_full_X_vsx; + } + } + break; + } + } else { /* !SWS_FULL_CHR_H_INT */ + switch (dstFormat) { + case AV_PIX_FMT_YUYV422: + c->yuv2packed1 = yuv2yuyv422_1_vsx; + c->yuv2packed2 = yuv2yuyv422_2_vsx; + c->yuv2packedX = yuv2yuyv422_X_vsx; + break; + case AV_PIX_FMT_YVYU422: + c->yuv2packed1 = yuv2yvyu422_1_vsx; + c->yuv2packed2 = yuv2yvyu422_2_vsx; + c->yuv2packedX = yuv2yvyu422_X_vsx; + break; + case AV_PIX_FMT_UYVY422: + c->yuv2packed1 = yuv2uyvy422_1_vsx; + c->yuv2packed2 = yuv2uyvy422_2_vsx; + c->yuv2packedX = yuv2uyvy422_X_vsx; + break; + case AV_PIX_FMT_BGRA: + if (power8) { + if (!c->needAlpha) { + c->yuv2packed1 = yuv2bgrx32_1_vsx; + c->yuv2packed2 = yuv2bgrx32_2_vsx; + } + } + break; + case AV_PIX_FMT_RGBA: + if (power8) { + if (!c->needAlpha) { + c->yuv2packed1 = yuv2rgbx32_1_vsx; + c->yuv2packed2 = yuv2rgbx32_2_vsx; + } + } + break; + case AV_PIX_FMT_ARGB: + if (power8) { + if (!c->needAlpha) { + c->yuv2packed1 = yuv2xrgb32_1_vsx; + c->yuv2packed2 = yuv2xrgb32_2_vsx; + } + } + break; + case AV_PIX_FMT_ABGR: + if (power8) { + if (!c->needAlpha) { + c->yuv2packed1 = yuv2xbgr32_1_vsx; + c->yuv2packed2 = yuv2xbgr32_2_vsx; + } + } + break; + case AV_PIX_FMT_RGB24: + if (power8) { + c->yuv2packed1 = yuv2rgb24_1_vsx; + c->yuv2packed2 = yuv2rgb24_2_vsx; + } + break; + case AV_PIX_FMT_BGR24: + if (power8) { + c->yuv2packed1 = yuv2bgr24_1_vsx; + c->yuv2packed2 = yuv2bgr24_2_vsx; + } + break; + } + } +#endif /* !HAVE_BIGENDIAN */ + +#endif /* HAVE_VSX */ +} diff --git a/libswscale/rgb2rgb_template.c b/libswscale/rgb2rgb_template.c index fb7d663cc..f7385e372 100644 --- a/libswscale/rgb2rgb_template.c +++ b/libswscale/rgb2rgb_template.c @@ -342,6 +342,7 @@ static inline void shuffle_bytes_0321_c(const uint8_t *src, uint8_t *dst, } } +#if !HAVE_BIGENDIAN #define DEFINE_SHUFFLE_BYTES(name, a, b, c, d) \ static void shuffle_bytes_##name (const uint8_t *src, \ uint8_t *dst, int src_size) \ @@ -359,6 +360,7 @@ static void shuffle_bytes_##name (const uint8_t *src, \ DEFINE_SHUFFLE_BYTES(1230_c, 1, 2, 3, 0) DEFINE_SHUFFLE_BYTES(3012_c, 3, 0, 1, 2) DEFINE_SHUFFLE_BYTES(3210_c, 3, 2, 1, 0) +#endif static inline void rgb24tobgr24_c(const uint8_t *src, uint8_t *dst, int src_size) { diff --git a/libswscale/swscale.c b/libswscale/swscale.c index 7f3e22355..40695503a 100644 --- a/libswscale/swscale.c +++ b/libswscale/swscale.c @@ -74,8 +74,11 @@ static void hScale16To19_c(SwsContext *c, int16_t *_dst, int dstW, int bits = desc->comp[0].depth - 1; int sh = bits - 4; - if((isAnyRGB(c->srcFormat) || c->srcFormat==AV_PIX_FMT_PAL8) && desc->comp[0].depth<16) - sh= 9; + if ((isAnyRGB(c->srcFormat) || c->srcFormat==AV_PIX_FMT_PAL8) && desc->comp[0].depth<16) { + sh = 9; + } else if (desc->flags & AV_PIX_FMT_FLAG_FLOAT) { /* float input are process like uint 16bpc */ + sh = 16 - 1 - 4; + } for (i = 0; i < dstW; i++) { int j; @@ -99,8 +102,11 @@ static void hScale16To15_c(SwsContext *c, int16_t *dst, int dstW, const uint16_t *src = (const uint16_t *) _src; int sh = desc->comp[0].depth - 1; - if(sh<15) - sh= isAnyRGB(c->srcFormat) || c->srcFormat==AV_PIX_FMT_PAL8 ? 13 : (desc->comp[0].depth - 1); + if (sh<15) { + sh = isAnyRGB(c->srcFormat) || c->srcFormat==AV_PIX_FMT_PAL8 ? 13 : (desc->comp[0].depth - 1); + } else if (desc->flags & AV_PIX_FMT_FLAG_FLOAT) { /* float input are process like uint 16bpc */ + sh = 16 - 1; + } for (i = 0; i < dstW; i++) { int j; diff --git a/libswscale/swscale_internal.h b/libswscale/swscale_internal.h index 1703856ab..a59d12745 100644 --- a/libswscale/swscale_internal.h +++ b/libswscale/swscale_internal.h @@ -336,6 +336,8 @@ typedef struct SwsContext { uint32_t pal_yuv[256]; uint32_t pal_rgb[256]; + float uint2float_lut[256]; + /** * @name Scaled horizontal lines ring buffer. * The horizontal scaler keeps just enough scaled lines in a ring buffer @@ -764,6 +766,13 @@ static av_always_inline int isAnyRGB(enum AVPixelFormat pix_fmt) pix_fmt == AV_PIX_FMT_MONOBLACK || pix_fmt == AV_PIX_FMT_MONOWHITE; } +static av_always_inline int isFloat(enum AVPixelFormat pix_fmt) +{ + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt); + av_assert0(desc); + return desc->flags & AV_PIX_FMT_FLAG_FLOAT; +} + static av_always_inline int isALPHA(enum AVPixelFormat pix_fmt) { const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt); @@ -859,6 +868,7 @@ void ff_sws_init_output_funcs(SwsContext *c, yuv2packedX_fn *yuv2packedX, yuv2anyX_fn *yuv2anyX); void ff_sws_init_swscale_ppc(SwsContext *c); +void ff_sws_init_swscale_vsx(SwsContext *c); void ff_sws_init_swscale_x86(SwsContext *c); void ff_sws_init_swscale_aarch64(SwsContext *c); void ff_sws_init_swscale_arm(SwsContext *c); diff --git a/libswscale/swscale_unscaled.c b/libswscale/swscale_unscaled.c index 13f9cd83e..e0b9e9937 100644 --- a/libswscale/swscale_unscaled.c +++ b/libswscale/swscale_unscaled.c @@ -150,10 +150,10 @@ static int planarToNv12Wrapper(SwsContext *c, const uint8_t *src[], dstParam[0], dstStride[0]); if (c->dstFormat == AV_PIX_FMT_NV12) - interleaveBytes(src[1], src[2], dst, c->srcW / 2, srcSliceH / 2, + interleaveBytes(src[1], src[2], dst, c->chrSrcW, (srcSliceH + 1) / 2, srcStride[1], srcStride[2], dstStride[1]); else - interleaveBytes(src[2], src[1], dst, c->srcW / 2, srcSliceH / 2, + interleaveBytes(src[2], src[1], dst, c->chrSrcW, (srcSliceH + 1) / 2, srcStride[2], srcStride[1], dstStride[1]); return srcSliceH; @@ -171,10 +171,51 @@ static int nv12ToPlanarWrapper(SwsContext *c, const uint8_t *src[], dstParam[0], dstStride[0]); if (c->srcFormat == AV_PIX_FMT_NV12) - deinterleaveBytes(src[1], dst1, dst2,c->srcW / 2, srcSliceH / 2, + deinterleaveBytes(src[1], dst1, dst2, c->chrSrcW, (srcSliceH + 1) / 2, srcStride[1], dstStride[1], dstStride[2]); else - deinterleaveBytes(src[1], dst2, dst1, c->srcW / 2, srcSliceH / 2, + deinterleaveBytes(src[1], dst2, dst1, c->chrSrcW, (srcSliceH + 1) / 2, + srcStride[1], dstStride[2], dstStride[1]); + + return srcSliceH; +} + +static int planarToNv24Wrapper(SwsContext *c, const uint8_t *src[], + int srcStride[], int srcSliceY, + int srcSliceH, uint8_t *dstParam[], + int dstStride[]) +{ + uint8_t *dst = dstParam[1] + dstStride[1] * srcSliceY; + + copyPlane(src[0], srcStride[0], srcSliceY, srcSliceH, c->srcW, + dstParam[0], dstStride[0]); + + if (c->dstFormat == AV_PIX_FMT_NV24) + interleaveBytes(src[1], src[2], dst, c->chrSrcW, srcSliceH, + srcStride[1], srcStride[2], dstStride[1]); + else + interleaveBytes(src[2], src[1], dst, c->chrSrcW, srcSliceH, + srcStride[2], srcStride[1], dstStride[1]); + + return srcSliceH; +} + +static int nv24ToPlanarWrapper(SwsContext *c, const uint8_t *src[], + int srcStride[], int srcSliceY, + int srcSliceH, uint8_t *dstParam[], + int dstStride[]) +{ + uint8_t *dst1 = dstParam[1] + dstStride[1] * srcSliceY; + uint8_t *dst2 = dstParam[2] + dstStride[2] * srcSliceY; + + copyPlane(src[0], srcStride[0], srcSliceY, srcSliceH, c->srcW, + dstParam[0], dstStride[0]); + + if (c->srcFormat == AV_PIX_FMT_NV24) + deinterleaveBytes(src[1], dst1, dst2, c->chrSrcW, srcSliceH, + srcStride[1], dstStride[1], dstStride[2]); + else + deinterleaveBytes(src[1], dst2, dst1, c->chrSrcW, srcSliceH, srcStride[1], dstStride[2], dstStride[1]); return srcSliceH; @@ -423,7 +464,7 @@ static void gray8aToPacked24(const uint8_t *src, uint8_t *dst, int num_pixels, } } -static int packed_16bpc_bswap(SwsContext *c, const uint8_t *src[], +static int bswap_16bpc(SwsContext *c, const uint8_t *src[], int srcStride[], int srcSliceY, int srcSliceH, uint8_t *dst[], int dstStride[]) { @@ -916,6 +957,91 @@ static void gbr24ptopacked32(const uint8_t *src[], int srcStride[], } } +static void gbraptopacked32(const uint8_t *src[], int srcStride[], + uint8_t *dst, int dstStride, int srcSliceH, + int alpha_first, int width) +{ + int x, h, i; + for (h = 0; h < srcSliceH; h++) { + uint8_t *dest = dst + dstStride * h; + + if (alpha_first) { + for (x = 0; x < width; x++) { + *dest++ = src[3][x]; + *dest++ = src[0][x]; + *dest++ = src[1][x]; + *dest++ = src[2][x]; + } + } else { + for (x = 0; x < width; x++) { + *dest++ = src[0][x]; + *dest++ = src[1][x]; + *dest++ = src[2][x]; + *dest++ = src[3][x]; + } + } + + for (i = 0; i < 4; i++) + src[i] += srcStride[i]; + } +} + +static int planarRgbaToRgbWrapper(SwsContext *c, const uint8_t *src[], + int srcStride[], int srcSliceY, int srcSliceH, + uint8_t *dst[], int dstStride[]) +{ + int alpha_first = 0; + const uint8_t *src102[] = { src[1], src[0], src[2], src[3] }; + const uint8_t *src201[] = { src[2], src[0], src[1], src[3] }; + int stride102[] = { srcStride[1], srcStride[0], srcStride[2], srcStride[3] }; + int stride201[] = { srcStride[2], srcStride[0], srcStride[1], srcStride[3] }; + + if (c->srcFormat != AV_PIX_FMT_GBRAP) { + av_log(c, AV_LOG_ERROR, "unsupported planar RGB conversion %s -> %s\n", + av_get_pix_fmt_name(c->srcFormat), + av_get_pix_fmt_name(c->dstFormat)); + return srcSliceH; + } + + switch (c->dstFormat) { + case AV_PIX_FMT_BGR24: + gbr24ptopacked24(src102, stride102, + dst[0] + srcSliceY * dstStride[0], dstStride[0], + srcSliceH, c->srcW); + break; + + case AV_PIX_FMT_RGB24: + gbr24ptopacked24(src201, stride201, + dst[0] + srcSliceY * dstStride[0], dstStride[0], + srcSliceH, c->srcW); + break; + + case AV_PIX_FMT_ARGB: + alpha_first = 1; + case AV_PIX_FMT_RGBA: + gbraptopacked32(src201, stride201, + dst[0] + srcSliceY * dstStride[0], dstStride[0], + srcSliceH, alpha_first, c->srcW); + break; + + case AV_PIX_FMT_ABGR: + alpha_first = 1; + case AV_PIX_FMT_BGRA: + gbraptopacked32(src102, stride102, + dst[0] + srcSliceY * dstStride[0], dstStride[0], + srcSliceH, alpha_first, c->srcW); + break; + + default: + av_log(c, AV_LOG_ERROR, + "unsupported planar RGB conversion %s -> %s\n", + av_get_pix_fmt_name(c->srcFormat), + av_get_pix_fmt_name(c->dstFormat)); + } + + return srcSliceH; +} + static int planarRgbToRgbWrapper(SwsContext *c, const uint8_t *src[], int srcStride[], int srcSliceY, int srcSliceH, uint8_t *dst[], int dstStride[]) @@ -1467,6 +1593,46 @@ static int yvu9ToYv12Wrapper(SwsContext *c, const uint8_t *src[], return srcSliceH; } +static int uint_y_to_float_y_wrapper(SwsContext *c, const uint8_t *src[], + int srcStride[], int srcSliceY, + int srcSliceH, uint8_t *dst[], int dstStride[]) +{ + int y, x; + ptrdiff_t dstStrideFloat = dstStride[0] >> 2; + const uint8_t *srcPtr = src[0]; + float *dstPtr = (float *)(dst[0] + dstStride[0] * srcSliceY); + + for (y = 0; y < srcSliceH; ++y){ + for (x = 0; x < c->srcW; ++x){ + dstPtr[x] = c->uint2float_lut[srcPtr[x]]; + } + srcPtr += srcStride[0]; + dstPtr += dstStrideFloat; + } + + return srcSliceH; +} + +static int float_y_to_uint_y_wrapper(SwsContext *c, const uint8_t* src[], + int srcStride[], int srcSliceY, + int srcSliceH, uint8_t* dst[], int dstStride[]) +{ + int y, x; + ptrdiff_t srcStrideFloat = srcStride[0] >> 2; + const float *srcPtr = (const float *)src[0]; + uint8_t *dstPtr = dst[0] + dstStride[0] * srcSliceY; + + for (y = 0; y < srcSliceH; ++y){ + for (x = 0; x < c->srcW; ++x){ + dstPtr[x] = av_clip_uint8(lrintf(255.0f * srcPtr[x])); + } + srcPtr += srcStrideFloat; + dstPtr += dstStride[0]; + } + + return srcSliceH; +} + /* unscaled copy like stuff (assumes nearly identical formats) */ static int packedCopyWrapper(SwsContext *c, const uint8_t *src[], int srcStride[], int srcSliceY, int srcSliceH, @@ -1696,6 +1862,14 @@ static int planarCopyWrapper(SwsContext *c, const uint8_t *src[], srcPtr += srcStride[plane]; dstPtr += dstStride[plane]; } + } else if (isFloat(c->srcFormat) && isFloat(c->dstFormat) && + isBE(c->srcFormat) != isBE(c->dstFormat)) { /* swap float plane */ + for (i = 0; i < height; i++) { + for (j = 0; j < length; j++) + ((uint32_t *) dstPtr)[j] = av_bswap32(((const uint32_t *) srcPtr)[j]); + srcPtr += srcStride[plane]; + dstPtr += dstStride[plane]; + } } else if (dstStride[plane] == srcStride[plane] && srcStride[plane] > 0 && srcStride[plane] == length) { memcpy(dst[plane] + dstStride[plane] * y, src[plane], @@ -1739,11 +1913,21 @@ void ff_get_unscaled_swscale(SwsContext *c) (dstFormat == AV_PIX_FMT_NV12 || dstFormat == AV_PIX_FMT_NV21)) { c->swscale = planarToNv12Wrapper; } + /* yv24_to_nv24 */ + if ((srcFormat == AV_PIX_FMT_YUV444P || srcFormat == AV_PIX_FMT_YUVA444P) && + (dstFormat == AV_PIX_FMT_NV24 || dstFormat == AV_PIX_FMT_NV42)) { + c->swscale = planarToNv24Wrapper; + } /* nv12_to_yv12 */ if (dstFormat == AV_PIX_FMT_YUV420P && (srcFormat == AV_PIX_FMT_NV12 || srcFormat == AV_PIX_FMT_NV21)) { c->swscale = nv12ToPlanarWrapper; } + /* nv24_to_yv24 */ + if (dstFormat == AV_PIX_FMT_YUV444P && + (srcFormat == AV_PIX_FMT_NV24 || srcFormat == AV_PIX_FMT_NV42)) { + c->swscale = nv24ToPlanarWrapper; + } /* yuv2bgr */ if ((srcFormat == AV_PIX_FMT_YUV420P || srcFormat == AV_PIX_FMT_YUV422P || srcFormat == AV_PIX_FMT_YUVA420P) && isAnyRGB(dstFormat) && @@ -1797,6 +1981,9 @@ void ff_get_unscaled_swscale(SwsContext *c) if (srcFormat == AV_PIX_FMT_GBRP && isPlanar(srcFormat) && isByteRGB(dstFormat)) c->swscale = planarRgbToRgbWrapper; + if (srcFormat == AV_PIX_FMT_GBRAP && isByteRGB(dstFormat)) + c->swscale = planarRgbaToRgbWrapper; + if ((srcFormat == AV_PIX_FMT_RGB48LE || srcFormat == AV_PIX_FMT_RGB48BE || srcFormat == AV_PIX_FMT_BGR48LE || srcFormat == AV_PIX_FMT_BGR48BE || srcFormat == AV_PIX_FMT_RGBA64LE || srcFormat == AV_PIX_FMT_RGBA64BE || @@ -1852,6 +2039,7 @@ void ff_get_unscaled_swscale(SwsContext *c) IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_GRAY9) || IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_GRAY10) || IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_GRAY12) || + IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_GRAY14) || IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_GRAY16) || IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_YA16) || IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_AYUV64) || @@ -1886,7 +2074,7 @@ void ff_get_unscaled_swscale(SwsContext *c) IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_YUV444P12) || IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_YUV444P14) || IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_YUV444P16)) - c->swscale = packed_16bpc_bswap; + c->swscale = bswap_16bpc; if (usePal(srcFormat) && isByteRGB(dstFormat)) c->swscale = palToRgbWrapper; @@ -1898,6 +2086,16 @@ void ff_get_unscaled_swscale(SwsContext *c) c->swscale = yuv422pToUyvyWrapper; } + /* uint Y to float Y */ + if (srcFormat == AV_PIX_FMT_GRAY8 && dstFormat == AV_PIX_FMT_GRAYF32){ + c->swscale = uint_y_to_float_y_wrapper; + } + + /* float Y to uint Y */ + if (srcFormat == AV_PIX_FMT_GRAYF32 && dstFormat == AV_PIX_FMT_GRAY8){ + c->swscale = float_y_to_uint_y_wrapper; + } + /* LQ converters if -sws 0 or -sws 4*/ if (c->flags&(SWS_FAST_BILINEAR|SWS_POINT)) { /* yv12_to_yuy2 */ @@ -1924,13 +2122,13 @@ void ff_get_unscaled_swscale(SwsContext *c) if ( srcFormat == dstFormat || (srcFormat == AV_PIX_FMT_YUVA420P && dstFormat == AV_PIX_FMT_YUV420P) || (srcFormat == AV_PIX_FMT_YUV420P && dstFormat == AV_PIX_FMT_YUVA420P) || - (isPlanarYUV(srcFormat) && isPlanarGray(dstFormat)) || + (isFloat(srcFormat) == isFloat(dstFormat)) && ((isPlanarYUV(srcFormat) && isPlanarGray(dstFormat)) || (isPlanarYUV(dstFormat) && isPlanarGray(srcFormat)) || (isPlanarGray(dstFormat) && isPlanarGray(srcFormat)) || (isPlanarYUV(srcFormat) && isPlanarYUV(dstFormat) && c->chrDstHSubSample == c->chrSrcHSubSample && c->chrDstVSubSample == c->chrSrcVSubSample && - !isSemiPlanarYUV(srcFormat) && !isSemiPlanarYUV(dstFormat))) + !isSemiPlanarYUV(srcFormat) && !isSemiPlanarYUV(dstFormat)))) { if (isPacked(c->srcFormat)) c->swscale = packedCopyWrapper; diff --git a/libswscale/tests/pixdesc_query.c b/libswscale/tests/pixdesc_query.c index a5585c431..f6dd8bae6 100644 --- a/libswscale/tests/pixdesc_query.c +++ b/libswscale/tests/pixdesc_query.c @@ -32,6 +32,7 @@ static const struct { {"isBE", isBE}, {"isYUV", isYUV}, {"isPlanarYUV", isPlanarYUV}, + {"isSemiPlanarYUV", isSemiPlanarYUV}, {"isRGB", isRGB}, {"Gray", isGray}, {"RGBinInt", isRGBinInt}, diff --git a/libswscale/tests/swscale.c b/libswscale/tests/swscale.c index e72c4c330..19878a787 100644 --- a/libswscale/tests/swscale.c +++ b/libswscale/tests/swscale.c @@ -312,22 +312,22 @@ static int fileTest(const uint8_t * const ref[4], int refStride[4], while (fgets(buf, sizeof(buf), fp)) { struct Results r; enum AVPixelFormat srcFormat; - char srcStr[12]; + char srcStr[21]; int srcW = 0, srcH = 0; enum AVPixelFormat dstFormat; - char dstStr[12]; + char dstStr[21]; int dstW = 0, dstH = 0; int flags; int ret; ret = sscanf(buf, - " %12s %dx%d -> %12s %dx%d flags=%d CRC=%x" + " %20s %dx%d -> %20s %dx%d flags=%d CRC=%x" " SSD=%"SCNu64 ", %"SCNu64 ", %"SCNu64 ", %"SCNu64 "\n", srcStr, &srcW, &srcH, dstStr, &dstW, &dstH, &flags, &r.crc, &r.ssdY, &r.ssdU, &r.ssdV, &r.ssdA); if (ret != 12) { srcStr[0] = dstStr[0] = 0; - ret = sscanf(buf, "%12s -> %12s\n", srcStr, dstStr); + ret = sscanf(buf, "%20s -> %20s\n", srcStr, dstStr); } srcFormat = av_get_pix_fmt(srcStr); diff --git a/libswscale/utils.c b/libswscale/utils.c index 98a6b9947..1b1f77953 100644 --- a/libswscale/utils.c +++ b/libswscale/utils.c @@ -137,6 +137,8 @@ static const FormatEntry format_entries[AV_PIX_FMT_NB] = { [AV_PIX_FMT_GRAY10LE] = { 1, 1 }, [AV_PIX_FMT_GRAY12BE] = { 1, 1 }, [AV_PIX_FMT_GRAY12LE] = { 1, 1 }, + [AV_PIX_FMT_GRAY14BE] = { 1, 1 }, + [AV_PIX_FMT_GRAY14LE] = { 1, 1 }, [AV_PIX_FMT_GRAY16BE] = { 1, 1 }, [AV_PIX_FMT_GRAY16LE] = { 1, 1 }, [AV_PIX_FMT_YUV440P] = { 1, 1 }, @@ -189,8 +191,8 @@ static const FormatEntry format_entries[AV_PIX_FMT_NB] = { [AV_PIX_FMT_BGR444LE] = { 1, 1 }, [AV_PIX_FMT_BGR444BE] = { 1, 1 }, [AV_PIX_FMT_YA8] = { 1, 1 }, - [AV_PIX_FMT_YA16BE] = { 1, 0 }, - [AV_PIX_FMT_YA16LE] = { 1, 0 }, + [AV_PIX_FMT_YA16BE] = { 1, 1 }, + [AV_PIX_FMT_YA16LE] = { 1, 1 }, [AV_PIX_FMT_BGR48BE] = { 1, 1 }, [AV_PIX_FMT_BGR48LE] = { 1, 1 }, [AV_PIX_FMT_BGRA64BE] = { 1, 1, 1 }, @@ -256,6 +258,14 @@ static const FormatEntry format_entries[AV_PIX_FMT_NB] = { [AV_PIX_FMT_P010BE] = { 1, 1 }, [AV_PIX_FMT_P016LE] = { 1, 1 }, [AV_PIX_FMT_P016BE] = { 1, 1 }, + [AV_PIX_FMT_GRAYF32LE] = { 1, 1 }, + [AV_PIX_FMT_GRAYF32BE] = { 1, 1 }, + [AV_PIX_FMT_YUVA422P12BE] = { 1, 1 }, + [AV_PIX_FMT_YUVA422P12LE] = { 1, 1 }, + [AV_PIX_FMT_YUVA444P12BE] = { 1, 1 }, + [AV_PIX_FMT_YUVA444P12LE] = { 1, 1 }, + [AV_PIX_FMT_NV24] = { 1, 1 }, + [AV_PIX_FMT_NV42] = { 1, 1 }, }; int sws_isSupportedInput(enum AVPixelFormat pix_fmt) @@ -1024,6 +1034,8 @@ static int handle_jpeg(enum AVPixelFormat *format) case AV_PIX_FMT_GRAY10BE: case AV_PIX_FMT_GRAY12LE: case AV_PIX_FMT_GRAY12BE: + case AV_PIX_FMT_GRAY14LE: + case AV_PIX_FMT_GRAY14BE: case AV_PIX_FMT_GRAY16LE: case AV_PIX_FMT_GRAY16BE: case AV_PIX_FMT_YA16BE: @@ -1169,6 +1181,7 @@ av_cold int sws_init_context(SwsContext *c, SwsFilter *srcFilter, const AVPixFmtDescriptor *desc_dst; int ret = 0; enum AVPixelFormat tmpFmt; + static const float float_mult = 1.0f / 255.0f; cpu_flags = av_get_cpu_flags(); flags = c->flags; @@ -1533,6 +1546,19 @@ av_cold int sws_init_context(SwsContext *c, SwsFilter *srcFilter, } } + if (unscaled && c->srcBpc == 8 && dstFormat == AV_PIX_FMT_GRAYF32){ + for (i = 0; i < 256; ++i){ + c->uint2float_lut[i] = (float)i * float_mult; + } + } + + // float will be converted to uint16_t + if ((srcFormat == AV_PIX_FMT_GRAYF32BE || srcFormat == AV_PIX_FMT_GRAYF32LE) && + (!unscaled || unscaled && dstFormat != srcFormat && (srcFormat != AV_PIX_FMT_GRAYF32 || + dstFormat != AV_PIX_FMT_GRAY8))){ + c->srcBpc = 16; + } + if (CONFIG_SWSCALE_ALPHA && isALPHA(srcFormat) && !isALPHA(dstFormat)) { enum AVPixelFormat tmpFormat = alphaless_fmt(srcFormat); @@ -1789,7 +1815,8 @@ av_cold int sws_init_context(SwsContext *c, SwsFilter *srcFilter, /* unscaled special cases */ if (unscaled && !usesHFilter && !usesVFilter && - (c->srcRange == c->dstRange || isAnyRGB(dstFormat))) { + (c->srcRange == c->dstRange || isAnyRGB(dstFormat) || + isFloat(srcFormat) || isFloat(dstFormat))){ ff_get_unscaled_swscale(c); if (c->swscale) { diff --git a/libswscale/version.h b/libswscale/version.h index 6d8052750..acb289d7c 100644 --- a/libswscale/version.h +++ b/libswscale/version.h @@ -27,7 +27,7 @@ #include "libavutil/version.h" #define LIBSWSCALE_VERSION_MAJOR 5 -#define LIBSWSCALE_VERSION_MINOR 1 +#define LIBSWSCALE_VERSION_MINOR 5 #define LIBSWSCALE_VERSION_MICRO 100 #define LIBSWSCALE_VERSION_INT AV_VERSION_INT(LIBSWSCALE_VERSION_MAJOR, \ diff --git a/libswscale/x86/rgb2rgb.c b/libswscale/x86/rgb2rgb.c index e5f318a72..2d6fc2ad2 100644 --- a/libswscale/x86/rgb2rgb.c +++ b/libswscale/x86/rgb2rgb.c @@ -144,12 +144,22 @@ DECLARE_ALIGNED(8, extern const uint64_t, ff_bgr2UVOffset); #endif /* HAVE_INLINE_ASM */ +void ff_shuffle_bytes_2103_mmxext(const uint8_t *src, uint8_t *dst, int src_size); void ff_shuffle_bytes_2103_ssse3(const uint8_t *src, uint8_t *dst, int src_size); void ff_shuffle_bytes_0321_ssse3(const uint8_t *src, uint8_t *dst, int src_size); void ff_shuffle_bytes_1230_ssse3(const uint8_t *src, uint8_t *dst, int src_size); void ff_shuffle_bytes_3012_ssse3(const uint8_t *src, uint8_t *dst, int src_size); void ff_shuffle_bytes_3210_ssse3(const uint8_t *src, uint8_t *dst, int src_size); +#if ARCH_X86_64 +void ff_uyvytoyuv422_sse2(uint8_t *ydst, uint8_t *udst, uint8_t *vdst, + const uint8_t *src, int width, int height, + int lumStride, int chromStride, int srcStride); +void ff_uyvytoyuv422_avx(uint8_t *ydst, uint8_t *udst, uint8_t *vdst, + const uint8_t *src, int width, int height, + int lumStride, int chromStride, int srcStride); +#endif + av_cold void rgb2rgb_init_x86(void) { int cpu_flags = av_get_cpu_flags(); @@ -167,6 +177,14 @@ av_cold void rgb2rgb_init_x86(void) rgb2rgb_init_avx(); #endif /* HAVE_INLINE_ASM */ + if (EXTERNAL_MMXEXT(cpu_flags)) { + shuffle_bytes_2103 = ff_shuffle_bytes_2103_mmxext; + } + if (EXTERNAL_SSE2(cpu_flags)) { +#if ARCH_X86_64 + uyvytoyuv422 = ff_uyvytoyuv422_sse2; +#endif + } if (EXTERNAL_SSSE3(cpu_flags)) { shuffle_bytes_0321 = ff_shuffle_bytes_0321_ssse3; shuffle_bytes_2103 = ff_shuffle_bytes_2103_ssse3; @@ -174,4 +192,9 @@ av_cold void rgb2rgb_init_x86(void) shuffle_bytes_3012 = ff_shuffle_bytes_3012_ssse3; shuffle_bytes_3210 = ff_shuffle_bytes_3210_ssse3; } + if (EXTERNAL_AVX(cpu_flags)) { +#if ARCH_X86_64 + uyvytoyuv422 = ff_uyvytoyuv422_avx; +#endif + } } diff --git a/libswscale/x86/rgb2rgb_template.c b/libswscale/x86/rgb2rgb_template.c index d59bd5679..ae2469e66 100644 --- a/libswscale/x86/rgb2rgb_template.c +++ b/libswscale/x86/rgb2rgb_template.c @@ -1034,68 +1034,6 @@ static inline void RENAME(rgb16to32)(const uint8_t *src, uint8_t *dst, int src_s } } -static inline void RENAME(shuffle_bytes_2103)(const uint8_t *src, uint8_t *dst, int src_size) -{ - x86_reg idx = 15 - src_size; - const uint8_t *s = src-idx; - uint8_t *d = dst-idx; - __asm__ volatile( - "test %0, %0 \n\t" - "jns 2f \n\t" - PREFETCH" (%1, %0) \n\t" - "movq %3, %%mm7 \n\t" - "pxor %4, %%mm7 \n\t" - "movq %%mm7, %%mm6 \n\t" - "pxor %5, %%mm7 \n\t" - ".p2align 4 \n\t" - "1: \n\t" - PREFETCH" 32(%1, %0) \n\t" - "movq (%1, %0), %%mm0 \n\t" - "movq 8(%1, %0), %%mm1 \n\t" -# if COMPILE_TEMPLATE_MMXEXT - "pshufw $177, %%mm0, %%mm3 \n\t" - "pshufw $177, %%mm1, %%mm5 \n\t" - "pand %%mm7, %%mm0 \n\t" - "pand %%mm6, %%mm3 \n\t" - "pand %%mm7, %%mm1 \n\t" - "pand %%mm6, %%mm5 \n\t" - "por %%mm3, %%mm0 \n\t" - "por %%mm5, %%mm1 \n\t" -# else - "movq %%mm0, %%mm2 \n\t" - "movq %%mm1, %%mm4 \n\t" - "pand %%mm7, %%mm0 \n\t" - "pand %%mm6, %%mm2 \n\t" - "pand %%mm7, %%mm1 \n\t" - "pand %%mm6, %%mm4 \n\t" - "movq %%mm2, %%mm3 \n\t" - "movq %%mm4, %%mm5 \n\t" - "pslld $16, %%mm2 \n\t" - "psrld $16, %%mm3 \n\t" - "pslld $16, %%mm4 \n\t" - "psrld $16, %%mm5 \n\t" - "por %%mm2, %%mm0 \n\t" - "por %%mm4, %%mm1 \n\t" - "por %%mm3, %%mm0 \n\t" - "por %%mm5, %%mm1 \n\t" -# endif - MOVNTQ" %%mm0, (%2, %0) \n\t" - MOVNTQ" %%mm1, 8(%2, %0) \n\t" - "add $16, %0 \n\t" - "js 1b \n\t" - SFENCE" \n\t" - EMMS" \n\t" - "2: \n\t" - : "+&r"(idx) - : "r" (s), "r" (d), "m" (mask32b), "m" (mask32r), "m" (mmx_one) - : "memory"); - for (; idx<15; idx+=4) { - register unsigned v = *(const uint32_t *)&s[idx], g = v & 0xff00ff00; - v &= 0xff00ff; - *(uint32_t *)&d[idx] = (v>>16) + g + (v<<16); - } -} - static inline void RENAME(rgb24tobgr24)(const uint8_t *src, uint8_t *dst, int src_size) { unsigned i; @@ -2572,7 +2510,6 @@ static av_cold void RENAME(rgb2rgb_init)(void) rgb24to15 = RENAME(rgb24to15); rgb24to16 = RENAME(rgb24to16); rgb24tobgr24 = RENAME(rgb24tobgr24); - shuffle_bytes_2103 = RENAME(shuffle_bytes_2103); rgb32tobgr16 = RENAME(rgb32tobgr16); rgb32tobgr15 = RENAME(rgb32tobgr15); yv12toyuy2 = RENAME(yv12toyuy2); diff --git a/libswscale/x86/rgb_2_rgb.asm b/libswscale/x86/rgb_2_rgb.asm index db45e313d..29b856e28 100644 --- a/libswscale/x86/rgb_2_rgb.asm +++ b/libswscale/x86/rgb_2_rgb.asm @@ -2,6 +2,7 @@ ;* Copyright Nick Kurshev ;* Copyright Michael (michaelni@gmx.at) ;* Copyright 2018 Jokyo Images +;* Copyright Ivo van Poorten ;* ;* This file is part of FFmpeg. ;* @@ -24,6 +25,7 @@ SECTION_RODATA +pb_mask_shuffle2103_mmx times 8 dw 255 pb_shuffle2103: db 2, 1, 0, 3, 6, 5, 4, 7, 10, 9, 8, 11, 14, 13, 12, 15 pb_shuffle0321: db 0, 3, 2, 1, 4, 7, 6, 5, 8, 11, 10, 9, 12, 15, 14, 13 pb_shuffle1230: db 1, 2, 3, 0, 5, 6, 7, 4, 9, 10, 11, 8, 13, 14, 15, 12 @@ -32,6 +34,78 @@ pb_shuffle3210: db 3, 2, 1, 0, 7, 6, 5, 4, 11, 10, 9, 8, 15, 14, 13, 12 SECTION .text +%macro RSHIFT_COPY 3 +; %1 dst ; %2 src ; %3 shift +%if cpuflag(avx) + psrldq %1, %2, %3 +%else + mova %1, %2 + RSHIFT %1, %3 +%endif +%endmacro + +;------------------------------------------------------------------------------ +; shuffle_bytes_2103_mmext (const uint8_t *src, uint8_t *dst, int src_size) +;------------------------------------------------------------------------------ +INIT_MMX mmxext +cglobal shuffle_bytes_2103, 3, 5, 8, src, dst, w, tmp, x + mova m6, [pb_mask_shuffle2103_mmx] + mova m7, m6 + psllq m7, 8 + + movsxdifnidn wq, wd + mov xq, wq + + add srcq, wq + add dstq, wq + neg wq + +;calc scalar loop + and xq, mmsize*2 -4 + je .loop_simd + +.loop_scalar: + mov tmpb, [srcq + wq + 2] + mov [dstq+wq + 0], tmpb + mov tmpb, [srcq + wq + 1] + mov [dstq+wq + 1], tmpb + mov tmpb, [srcq + wq + 0] + mov [dstq+wq + 2], tmpb + mov tmpb, [srcq + wq + 3] + mov [dstq+wq + 3], tmpb + add wq, 4 + sub xq, 4 + jg .loop_scalar + +;check if src_size < mmsize * 2 +cmp wq, 0 +jge .end + +.loop_simd: + movu m0, [srcq+wq] + movu m1, [srcq+wq+8] + + pshufw m3, m0, 177 + pshufw m5, m1, 177 + + pand m0, m7 + pand m3, m6 + + pand m1, m7 + pand m5, m6 + + por m0, m3 + por m1, m5 + + movu [dstq+wq], m0 + movu [dstq+wq + 8], m1 + + add wq, mmsize*2 + jl .loop_simd + +.end: + RET + ;------------------------------------------------------------------------------ ; shuffle_bytes_## (const uint8_t *src, uint8_t *dst, int src_size) ;------------------------------------------------------------------------------ @@ -84,3 +158,143 @@ SHUFFLE_BYTES 0, 3, 2, 1 SHUFFLE_BYTES 1, 2, 3, 0 SHUFFLE_BYTES 3, 0, 1, 2 SHUFFLE_BYTES 3, 2, 1, 0 + +;----------------------------------------------------------------------------------------------- +; uyvytoyuv422(uint8_t *ydst, uint8_t *udst, uint8_t *vdst, +; const uint8_t *src, int width, int height, +; int lumStride, int chromStride, int srcStride) +;----------------------------------------------------------------------------------------------- +%macro UYVY_TO_YUV422 0 +cglobal uyvytoyuv422, 9, 14, 8, ydst, udst, vdst, src, w, h, lum_stride, chrom_stride, src_stride, wtwo, whalf, tmp, x, back_w + pxor m0, m0 + pcmpeqw m1, m1 + psrlw m1, 8 + + movsxdifnidn wq, wd + movsxdifnidn lum_strideq, lum_strided + movsxdifnidn chrom_strideq, chrom_strided + movsxdifnidn src_strideq, src_strided + + mov back_wq, wq + mov whalfq, wq + shr whalfq, 1 ; whalf = width / 2 + + lea srcq, [srcq + wq * 2] + add ydstq, wq + add udstq, whalfq + add vdstq, whalfq + +.loop_line: + mov xq, wq + mov wtwoq, wq + add wtwoq, wtwoq ; wtwo = width * 2 + + neg wq + neg wtwoq + neg whalfq + + ;calc scalar loop count + and xq, mmsize * 2 - 1 + je .loop_simd + + .loop_scalar: + mov tmpb, [srcq + wtwoq + 0] + mov [udstq + whalfq], tmpb + + mov tmpb, [srcq + wtwoq + 1] + mov [ydstq + wq], tmpb + + mov tmpb, [srcq + wtwoq + 2] + mov [vdstq + whalfq], tmpb + + mov tmpb, [srcq + wtwoq + 3] + mov [ydstq + wq + 1], tmpb + + add wq, 2 + add wtwoq, 4 + add whalfq, 1 + sub xq, 2 + jg .loop_scalar + + ; check if simd loop is need + cmp wq, 0 + jge .end_line + + .loop_simd: + movu m2, [srcq + wtwoq ] + movu m3, [srcq + wtwoq + mmsize ] + movu m4, [srcq + wtwoq + mmsize * 2] + movu m5, [srcq + wtwoq + mmsize * 3] + + ; extract y part 1 + RSHIFT_COPY m6, m2, 1 ; UYVY UYVY -> YVYU YVY... + pand m6, m1; YxYx YxYx... + + RSHIFT_COPY m7, m3, 1 ; UYVY UYVY -> YVYU YVY... + pand m7, m1 ; YxYx YxYx... + + packuswb m6, m7 ; YYYY YYYY... + movu [ydstq + wq], m6 + + ; extract y part 2 + RSHIFT_COPY m6, m4, 1 ; UYVY UYVY -> YVYU YVY... + pand m6, m1; YxYx YxYx... + + RSHIFT_COPY m7, m5, 1 ; UYVY UYVY -> YVYU YVY... + pand m7, m1 ; YxYx YxYx... + + packuswb m6, m7 ; YYYY YYYY... + movu [ydstq + wq + mmsize], m6 + + ; extract uv + pand m2, m1 ; UxVx... + pand m3, m1 ; UxVx... + pand m4, m1 ; UxVx... + pand m5, m1 ; UxVx... + + packuswb m2, m3 ; UVUV... + packuswb m4, m5 ; UVUV... + + ; U + pand m6, m2, m1 ; UxUx... + pand m7, m4, m1 ; UxUx... + + packuswb m6, m7 ; UUUU + movu [udstq + whalfq], m6 + + + ; V + psrlw m2, 8 ; VxVx... + psrlw m4, 8 ; VxVx... + packuswb m2, m4 ; VVVV + movu [vdstq + whalfq], m2 + + add whalfq, mmsize + add wtwoq, mmsize * 4 + add wq, mmsize * 2 + jl .loop_simd + + .end_line: + add srcq, src_strideq + add ydstq, lum_strideq + add udstq, chrom_strideq + add vdstq, chrom_strideq + + ;restore initial state of line variable + mov wq, back_wq + mov xq, wq + mov whalfq, wq + shr whalfq, 1 ; whalf = width / 2 + sub hd, 1 + jg .loop_line + + RET +%endmacro + +%if ARCH_X86_64 +INIT_XMM sse2 +UYVY_TO_YUV422 + +INIT_XMM avx +UYVY_TO_YUV422 +%endif diff --git a/libswscale/x86/swscale_template.c b/libswscale/x86/swscale_template.c index b8bdcd4d0..823056c2e 100644 --- a/libswscale/x86/swscale_template.c +++ b/libswscale/x86/swscale_template.c @@ -1499,8 +1499,9 @@ static av_cold void RENAME(sws_init_swscale)(SwsContext *c) enum AVPixelFormat dstFormat = c->dstFormat; c->use_mmx_vfilter= 0; - if (!is16BPS(dstFormat) && !isNBPS(dstFormat) && dstFormat != AV_PIX_FMT_NV12 - && dstFormat != AV_PIX_FMT_NV21 && !(c->flags & SWS_BITEXACT)) { + if (!is16BPS(dstFormat) && !isNBPS(dstFormat) && !isSemiPlanarYUV(dstFormat) + && dstFormat != AV_PIX_FMT_GRAYF32BE && dstFormat != AV_PIX_FMT_GRAYF32LE + && !(c->flags & SWS_BITEXACT)) { if (c->flags & SWS_ACCURATE_RND) { if (!(c->flags & SWS_FULL_CHR_H_INT)) { switch (c->dstFormat) { diff --git a/libswscale/yuv2rgb.c b/libswscale/yuv2rgb.c index 737cbb06c..d0df061e4 100644 --- a/libswscale/yuv2rgb.c +++ b/libswscale/yuv2rgb.c @@ -993,7 +993,7 @@ av_cold int ff_yuv2rgb_c_init_tables(SwsContext *c, const int inv_table[4], default: if(!isPlanar(c->dstFormat) || bpp <= 24) av_log(c, AV_LOG_ERROR, "%ibpp not supported by yuv2rgb\n", bpp); - return -1; + return AVERROR(EINVAL); } return 0; } diff --git a/tests/Makefile b/tests/Makefile index 6074ac748..624292d45 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -10,7 +10,8 @@ FFMPEG=ffmpeg$(PROGSSUF)$(EXESUF) $(AREF): CMP= APITESTSDIR := tests/api -OBJDIRS += tests/data tests/vsynth1 tests/data/filtergraphs $(APITESTSDIR)/ +FATE_OUTDIRS = tests/data tests/data/fate tests/data/filtergraphs tests/data/lavf tests/data/lavf-fate tests/data/pixfmt tests/vsynth1 $(APITESTSDIR) +OUTDIRS += $(FATE_OUTDIRS) $(VREF): tests/videogen$(HOSTEXESUF) | tests/vsynth1 $(M)./$< 'tests/vsynth1/' @@ -88,7 +89,11 @@ include $(SRC_PATH)/$(APITESTSDIR)/Makefile include $(SRC_PATH)/tests/fate/acodec.mak include $(SRC_PATH)/tests/fate/vcodec.mak -include $(SRC_PATH)/tests/fate/avformat.mak +include $(SRC_PATH)/tests/fate/lavf-audio.mak +include $(SRC_PATH)/tests/fate/lavf-container.mak +include $(SRC_PATH)/tests/fate/lavf-image.mak +include $(SRC_PATH)/tests/fate/lavf-image2pipe.mak +include $(SRC_PATH)/tests/fate/lavf-video.mak include $(SRC_PATH)/tests/fate/seek.mak include $(SRC_PATH)/tests/fate/aac.mak @@ -131,6 +136,8 @@ include $(SRC_PATH)/tests/fate/gif.mak include $(SRC_PATH)/tests/fate/h264.mak include $(SRC_PATH)/tests/fate/hap.mak include $(SRC_PATH)/tests/fate/hevc.mak +include $(SRC_PATH)/tests/fate/hlsenc.mak +include $(SRC_PATH)/tests/fate/hw.mak include $(SRC_PATH)/tests/fate/id3v2.mak include $(SRC_PATH)/tests/fate/image.mak include $(SRC_PATH)/tests/fate/indeo.mak @@ -155,6 +162,7 @@ include $(SRC_PATH)/tests/fate/mpegts.mak include $(SRC_PATH)/tests/fate/mxf.mak include $(SRC_PATH)/tests/fate/opus.mak include $(SRC_PATH)/tests/fate/pcm.mak +include $(SRC_PATH)/tests/fate/pixfmt.mak include $(SRC_PATH)/tests/fate/pixlet.mak include $(SRC_PATH)/tests/fate/probe.mak include $(SRC_PATH)/tests/fate/prores.mak @@ -162,6 +170,7 @@ include $(SRC_PATH)/tests/fate/qt.mak include $(SRC_PATH)/tests/fate/qtrle.mak include $(SRC_PATH)/tests/fate/real.mak include $(SRC_PATH)/tests/fate/screen.mak +include $(SRC_PATH)/tests/fate/segment.mak include $(SRC_PATH)/tests/fate/source.mak include $(SRC_PATH)/tests/fate/speedhq.mak include $(SRC_PATH)/tests/fate/subtitles.mak @@ -181,7 +190,7 @@ FATE-$(CONFIG_FFPROBE) += $(FATE_FFPROBE) FATE_SAMPLES_AVCONV += $(FATE_SAMPLES_AVCONV-yes) FATE_SAMPLES_FFMPEG += $(FATE_SAMPLES_FFMPEG-yes) -FATE_EXTERN-$(CONFIG_FFMPEG) += $(FATE_SAMPLES_AVCONV) $(FATE_SAMPLES_FFMPEG) $(FATE_SAMPLES_FFPROBE) +FATE_EXTERN-$(CONFIG_FFMPEG) += $(FATE_SAMPLES_AVCONV) $(FATE_SAMPLES_FFMPEG) $(FATE_SAMPLES_FFPROBE) $(FATE_SAMPLES_FASTSTART) FATE_EXTERN += $(FATE_EXTERN-yes) FATE += $(FATE-yes) @@ -193,6 +202,8 @@ $(FATE_FFMPEG) $(FATE_SAMPLES_AVCONV) $(FATE_SAMPLES_FFMPEG): ffmpeg$(PROGSSUF)$ $(FATE_FFPROBE) $(FATE_SAMPLES_FFPROBE): ffprobe$(PROGSSUF)$(EXESUF) +$(FATE_SAMPLES_FASTSTART): tools/qt-faststart$(EXESUF) + ifdef SAMPLES FATE += $(FATE_FULL) $(FATE_FULL-yes) FATE += $(FATE_EXTERN) @@ -215,10 +226,16 @@ $(addprefix fate-, $(IGNORE_TESTS)): REPORT=ignore fate:: $(FATE) +# Tests requiring hardware support are not included in a default fate run. +fate-hw: $(FATE_HW-yes) +FATE += $(FATE_HW-yes) + $(FATE) $(FATE_TESTS-no): export PROGSUF = $(PROGSSUF) -$(FATE) $(FATE_TESTS-no): $(FATE_UTILS:%=tests/%$(HOSTEXESUF)) +$(FATE) $(FATE_TESTS-no): export EXECSUF = $(EXESUF) +$(FATE) $(FATE_TESTS-no): export HOSTEXECSUF = $(HOSTEXESUF) +$(FATE) $(FATE_TESTS-no): $(FATE_UTILS:%=tests/%$(HOSTEXESUF)) | $(FATE_OUTDIRS) @echo "TEST $(@:fate-%=%)" - $(Q)$(SRC_PATH)/tests/fate-run.sh $@ "$(TARGET_SAMPLES)" "$(TARGET_EXEC)" "$(TARGET_PATH)" '$(CMD)' '$(CMP)' '$(REF)' '$(FUZZ)' '$(THREADS)' '$(THREAD_TYPE)' '$(CPUFLAGS)' '$(CMP_SHIFT)' '$(CMP_TARGET)' '$(SIZE_TOLERANCE)' '$(CMP_UNIT)' '$(GEN)' '$(HWACCEL)' '$(REPORT)' + $(Q)$(SRC_PATH)/tests/fate-run.sh $@ "$(TARGET_SAMPLES)" "$(TARGET_EXEC)" "$(TARGET_PATH)" '$(CMD)' '$(CMP)' '$(REF)' '$(FUZZ)' '$(THREADS)' '$(THREAD_TYPE)' '$(CPUFLAGS)' '$(CMP_SHIFT)' '$(CMP_TARGET)' '$(SIZE_TOLERANCE)' '$(CMP_UNIT)' '$(GEN)' '$(HWACCEL)' '$(REPORT)' '$(KEEP)' fate-list: @printf '%s\n' $(sort $(FATE)) diff --git a/tests/api/Makefile b/tests/api/Makefile index 759dd9d24..b5c4ccae2 100644 --- a/tests/api/Makefile +++ b/tests/api/Makefile @@ -1,5 +1,6 @@ APITESTPROGS-$(call ENCDEC, FLAC, FLAC) += api-flac APITESTPROGS-$(call DEMDEC, H264, H264) += api-h264 +APITESTPROGS-$(call DEMDEC, H264, H264) += api-h264-slice APITESTPROGS-yes += api-seek APITESTPROGS-yes += api-codec-param APITESTPROGS-$(call DEMDEC, H263, H263) += api-band diff --git a/tests/api/api-flac-test.c b/tests/api/api-flac-test.c index 2e9081266..e8e8cbf1e 100644 --- a/tests/api/api-flac-test.c +++ b/tests/api/api-flac-test.c @@ -31,7 +31,7 @@ #include "libavutil/common.h" #include "libavutil/samplefmt.h" -#define NUMBER_OF_FRAMES 200 +#define NUMBER_OF_AUDIO_FRAMES 200 #define NAME_BUFF_SIZE 100 /* generate i-th frame of test audio */ @@ -137,19 +137,19 @@ static int run_test(AVCodec *enc, AVCodec *dec, AVCodecContext *enc_ctx, return AVERROR(ENOMEM); } - raw_in = av_malloc(in_frame->linesize[0] * NUMBER_OF_FRAMES); + raw_in = av_malloc(in_frame->linesize[0] * NUMBER_OF_AUDIO_FRAMES); if (!raw_in) { av_log(NULL, AV_LOG_ERROR, "Can't allocate memory for raw_in\n"); return AVERROR(ENOMEM); } - raw_out = av_malloc(in_frame->linesize[0] * NUMBER_OF_FRAMES); + raw_out = av_malloc(in_frame->linesize[0] * NUMBER_OF_AUDIO_FRAMES); if (!raw_out) { av_log(NULL, AV_LOG_ERROR, "Can't allocate memory for raw_out\n"); return AVERROR(ENOMEM); } - for (i = 0; i < NUMBER_OF_FRAMES; i++) { + for (i = 0; i < NUMBER_OF_AUDIO_FRAMES; i++) { av_init_packet(&enc_pkt); enc_pkt.data = NULL; enc_pkt.size = 0; @@ -209,7 +209,7 @@ static int run_test(AVCodec *enc, AVCodec *dec, AVCodecContext *enc_ctx, av_packet_unref(&enc_pkt); } - if (memcmp(raw_in, raw_out, out_frame_bytes * NUMBER_OF_FRAMES) != 0) { + if (memcmp(raw_in, raw_out, out_frame_bytes * NUMBER_OF_AUDIO_FRAMES) != 0) { av_log(NULL, AV_LOG_ERROR, "Output differs\n"); return 1; } diff --git a/tests/api/api-h264-slice-test.c b/tests/api/api-h264-slice-test.c new file mode 100644 index 000000000..dee93b834 --- /dev/null +++ b/tests/api/api-h264-slice-test.c @@ -0,0 +1,238 @@ +/* + * Copyright (c) 2001 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#define MAX_SLICES 8 + +#include "config.h" + +#include +#include +#include +#include + +#if HAVE_UNISTD_H +#include +#endif +#if HAVE_IO_H +#include +#endif +#include +#include +#include + +#include "libavcodec/avcodec.h" +#include "libavutil/pixdesc.h" +#include "libavutil/hash.h" +#include "libavutil/bswap.h" + +static int header = 0; + +static int decode(AVCodecContext *dec_ctx, AVFrame *frame, + AVPacket *pkt) +{ + static uint64_t frame_cnt = 0; + int ret; + + ret = avcodec_send_packet(dec_ctx, pkt); + if (ret < 0) { + fprintf(stderr, "Error sending a packet for decoding: %s\n", av_err2str(ret)); + return ret; + } + + while (ret >= 0) { + const AVPixFmtDescriptor *desc; + char sum[AV_HASH_MAX_SIZE * 2 + 1]; + struct AVHashContext *hash; + + ret = avcodec_receive_frame(dec_ctx, frame); + if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) { + return 0; + } else if (ret < 0) { + fprintf(stderr, "Error during decoding: %s\n", av_err2str(ret)); + return ret; + } + + if (!header) { + printf( + "#format: frame checksums\n" + "#version: 2\n" + "#hash: MD5\n" + "#tb 0: 1/30\n" + "#media_type 0: video\n" + "#codec_id 0: rawvideo\n" + "#dimensions 0: 352x288\n" + "#sar 0: 128/117\n" + "#stream#, dts, pts, duration, size, hash\n"); + header = 1; + } + desc = av_pix_fmt_desc_get(dec_ctx->pix_fmt); + if ((ret = av_hash_alloc(&hash, "md5")) < 0) { + return ret; + } + av_hash_init(hash); + + for (int i = 0; i < frame->height; i++) + av_hash_update(hash, &frame->data[0][i * frame->linesize[0]], frame->width); + for (int i = 0; i < frame->height >> desc->log2_chroma_h; i++) + av_hash_update(hash, &frame->data[1][i * frame->linesize[1]], frame->width >> desc->log2_chroma_w); + for (int i = 0; i < frame->height >> desc->log2_chroma_h; i++) + av_hash_update(hash, &frame->data[2][i * frame->linesize[2]], frame->width >> desc->log2_chroma_w); + + av_hash_final_hex(hash, sum, av_hash_get_size(hash) * 2 + 1); + printf("0, %10"PRId64", %10"PRId64", 1, %8d, %s\n", + frame_cnt, frame_cnt, + (frame->width * frame->height + 2 * (frame->height >> desc->log2_chroma_h) * (frame->width >> desc->log2_chroma_w)), sum); + frame_cnt += 1; + av_hash_freep(&hash); + } + return 0; +} + +int main(int argc, char **argv) +{ + const AVCodec *codec = NULL; + AVCodecContext *c = NULL; + AVFrame *frame = NULL; + unsigned int threads; + AVPacket *pkt; + FILE *file = NULL; + char * nal = NULL; + int nals = 0, ret = 0; + char *p; + + if (argc < 3) { + fprintf(stderr, "Usage: %s \n", argv[0]); + return -1; + } + + if (!(threads = strtoul(argv[1], NULL, 0))) + threads = 1; + else if (threads > MAX_SLICES) + threads = MAX_SLICES; + +#ifdef _WIN32 + setmode(fileno(stdout), O_BINARY); +#endif + + if (!(pkt = av_packet_alloc())) { + return -1; + } + + nal = av_malloc(MAX_SLICES * UINT16_MAX + AV_INPUT_BUFFER_PADDING_SIZE); + if (!nal) + goto err; + p = nal; + + if (!(codec = avcodec_find_decoder(AV_CODEC_ID_H264))) { + fprintf(stderr, "Codec not found\n"); + ret = -1; + goto err; + } + + if (!(c = avcodec_alloc_context3(codec))) { + fprintf(stderr, "Could not allocate video codec context\n"); + ret = -1; + goto err; + } + + c->width = 352; + c->height = 288; + + c->flags2 |= AV_CODEC_FLAG2_CHUNKS; + c->thread_type = FF_THREAD_SLICE; + c->thread_count = threads; + + if ((ret = avcodec_open2(c, codec, NULL)) < 0) { + fprintf(stderr, "Could not open codec\n"); + goto err; + } + +#if HAVE_THREADS + if (c->active_thread_type != FF_THREAD_SLICE) { + fprintf(stderr, "Couldn't activate slice threading: %d\n", c->active_thread_type); + ret = -1; + goto err; + } +#else + fprintf(stderr, "WARN: not using threads, only checking decoding slice NALUs\n"); +#endif + + if (!(frame = av_frame_alloc())) { + fprintf(stderr, "Could not allocate video frame\n"); + ret = -1; + goto err; + } + + if (!(file = fopen(argv[2], "rb"))) { + fprintf(stderr, "Couldn't open NALU file: %s\n", argv[2]); + ret = -1; + goto err; + } + + while(1) { + uint16_t size = 0; + size_t ret = fread(&size, 1, sizeof(uint16_t), file); + if (ret != sizeof(uint16_t)) + break; + + size = av_be2ne16(size); + ret = fread(p, 1, size, file); + if (ret != size) { + perror("Couldn't read data"); + goto err; + } + p += ret; + + if (++nals >= threads) { + int decret = 0; + pkt->data = nal; + pkt->size = p - nal; + if ((decret = decode(c, frame, pkt)) < 0) { + goto err; + } + memset(nal, 0, MAX_SLICES * UINT16_MAX + AV_INPUT_BUFFER_PADDING_SIZE); + nals = 0; + p = nal; + } + } + + if (nals) { + pkt->data = nal; + pkt->size = p - nal; + if ((ret = decode(c, frame, pkt)) < 0) { + goto err; + } + } + + ret = decode(c, frame, NULL); + +err: + if (nal) + av_free(nal); + if (file) + fclose(file); + av_frame_free(&frame); + avcodec_free_context(&c); + av_packet_free(&pkt); + + return ret; +} diff --git a/tests/api/api-h264-test.c b/tests/api/api-h264-test.c index 66669fa0c..60a3ae5ef 100644 --- a/tests/api/api-h264-test.c +++ b/tests/api/api-h264-test.c @@ -28,6 +28,7 @@ #include "libavcodec/avcodec.h" #include "libavformat/avformat.h" #include "libavutil/imgutils.h" +#include "libavutil/timestamp.h" static int video_decode_example(const char *input_filename) { @@ -131,9 +132,9 @@ static int video_decode_example(const char *input_filename) av_log(NULL, AV_LOG_ERROR, "Can't copy image to buffer\n"); return number_of_written_bytes; } - printf("%d, %10"PRId64", %10"PRId64", %8"PRId64", %8d, 0x%08lx\n", video_stream, - fr->pts, fr->pkt_dts, fr->pkt_duration, - number_of_written_bytes, av_adler32_update(0, (const uint8_t*)byte_buffer, number_of_written_bytes)); + printf("%d, %s, %s, %8"PRId64", %8d, 0x%08lx\n", video_stream, + av_ts2str(fr->pts), av_ts2str(fr->pkt_dts), fr->pkt_duration, + number_of_written_bytes, av_adler32_update(0, (const uint8_t*)byte_buffer, number_of_written_bytes)); } av_packet_unref(&pkt); av_init_packet(&pkt); diff --git a/tests/api/api-threadmessage-test.c b/tests/api/api-threadmessage-test.c index 05a8062b8..3c693a70d 100644 --- a/tests/api/api-threadmessage-test.c +++ b/tests/api/api-threadmessage-test.c @@ -130,7 +130,9 @@ static void *receiver_thread(void *arg) for (i = 0; i < rd->workload; i++) { if (rand() % rd->workload < rd->workload / 10) { - av_log(NULL, AV_LOG_INFO, "receiver #%d: flushing the queue\n", rd->id); + av_log(NULL, AV_LOG_INFO, "receiver #%d: flushing the queue, " + "discarding %d message(s)\n", rd->id, + av_thread_message_queue_nb_elems(rd->queue)); av_thread_message_flush(rd->queue); } else { struct message msg; diff --git a/tests/audiogen.c b/tests/audiogen.c index 8d596b510..c43bb70ff 100644 --- a/tests/audiogen.c +++ b/tests/audiogen.c @@ -26,7 +26,7 @@ #include #include -#define MAX_CHANNELS 8 +#define MAX_CHANNELS 12 static unsigned int myrnd(unsigned int *seed_ptr, int n) { diff --git a/tests/checkasm/Makefile b/tests/checkasm/Makefile index 0233d2f98..f5780eedb 100644 --- a/tests/checkasm/Makefile +++ b/tests/checkasm/Makefile @@ -25,16 +25,20 @@ AVCODECOBJS-$(CONFIG_JPEG2000_DECODER) += jpeg2000dsp.o AVCODECOBJS-$(CONFIG_PIXBLOCKDSP) += pixblockdsp.o AVCODECOBJS-$(CONFIG_HEVC_DECODER) += hevc_add_res.o hevc_idct.o hevc_sao.o AVCODECOBJS-$(CONFIG_UTVIDEO_DECODER) += utvideodsp.o +AVCODECOBJS-$(CONFIG_V210_DECODER) += v210dec.o AVCODECOBJS-$(CONFIG_V210_ENCODER) += v210enc.o AVCODECOBJS-$(CONFIG_VP9_DECODER) += vp9dsp.o CHECKASMOBJS-$(CONFIG_AVCODEC) += $(AVCODECOBJS-yes) # libavfilter tests +AVFILTEROBJS-$(CONFIG_AFIR_FILTER) += af_afir.o AVFILTEROBJS-$(CONFIG_BLEND_FILTER) += vf_blend.o AVFILTEROBJS-$(CONFIG_COLORSPACE_FILTER) += vf_colorspace.o +AVFILTEROBJS-$(CONFIG_GBLUR_FILTER) += vf_gblur.o AVFILTEROBJS-$(CONFIG_HFLIP_FILTER) += vf_hflip.o AVFILTEROBJS-$(CONFIG_THRESHOLD_FILTER) += vf_threshold.o +AVFILTEROBJS-$(CONFIG_NLMEANS_FILTER) += vf_nlmeans.o CHECKASMOBJS-$(CONFIG_AVFILTER) += $(AVFILTEROBJS-yes) @@ -60,7 +64,7 @@ CHECKASMOBJS := $(sort $(CHECKASMOBJS:%=tests/checkasm/%)) CHECKASMDIRS := $(sort $(dir $(CHECKASMOBJS))) $(CHECKASMOBJS): | $(CHECKASMDIRS) -OBJDIRS += $(CHECKASMDIRS) +OUTDIRS += $(CHECKASMDIRS) tests/checkasm/checkasm.o: CFLAGS += -Umain diff --git a/tests/checkasm/af_afir.c b/tests/checkasm/af_afir.c new file mode 100644 index 000000000..e3fb76e8e --- /dev/null +++ b/tests/checkasm/af_afir.c @@ -0,0 +1,83 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with FFmpeg; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "config.h" + +#include +#include + +#include "libavfilter/af_afir.h" +#include "libavutil/internal.h" +#include "checkasm.h" + +#define LEN 256 + +#define randomize_buffer(buf) \ +do { \ + int i; \ + double bmg[2], stddev = 10.0, mean = 0.0; \ + \ + for (i = 0; i < LEN*2+8; i += 2) { \ + av_bmg_get(&checkasm_lfg, bmg); \ + buf[i] = bmg[0] * stddev + mean; \ + buf[i + 1] = bmg[1] * stddev + mean; \ + } \ +} while(0); + +static void test_fcmul_add(const float *src0, const float *src1, const float *src2) +{ + LOCAL_ALIGNED_32(float, cdst, [LEN*2+8]); + LOCAL_ALIGNED_32(float, odst, [LEN*2+8]); + int i; + + declare_func(void, float *sum, const float *t, const float *c, + ptrdiff_t len); + + memcpy(cdst, src0, (LEN*2+8) * sizeof(float)); + memcpy(odst, src0, (LEN*2+8) * sizeof(float)); + call_ref(cdst, src1, src2, LEN); + call_new(odst, src1, src2, LEN); + for (i = 0; i <= LEN*2; i++) { + if (!float_near_abs_eps(cdst[i], odst[i], 6.2e-05)) { + fprintf(stderr, "%d: %- .12f - %- .12f = % .12g\n", + i, cdst[i], odst[i], cdst[i] - odst[i]); + fail(); + break; + } + } + memcpy(odst, src0, (LEN*2+8) * sizeof(float)); + bench_new(odst, src1, src2, LEN); +} + +void checkasm_check_afir(void) +{ + LOCAL_ALIGNED_32(float, src0, [LEN*2+8]); + LOCAL_ALIGNED_32(float, src1, [LEN*2+8]); + LOCAL_ALIGNED_32(float, src2, [LEN*2+8]); + AudioFIRDSPContext fir = { 0 }; + + ff_afir_init(&fir); + + randomize_buffer(src0); + randomize_buffer(src1); + randomize_buffer(src2); + + if (check_func(fir.fcmul_add, "fcmul_add")) + test_fcmul_add(src0, src1, src2); + report("fcmul_add"); +} diff --git a/tests/checkasm/checkasm.c b/tests/checkasm/checkasm.c index ba1d1d025..3e2ec377b 100644 --- a/tests/checkasm/checkasm.c +++ b/tests/checkasm/checkasm.c @@ -136,6 +136,9 @@ static const struct { #if CONFIG_UTVIDEO_DECODER { "utvideodsp", checkasm_check_utvideodsp }, #endif + #if CONFIG_V210_DECODER + { "v210dec", checkasm_check_v210dec }, + #endif #if CONFIG_V210_ENCODER { "v210enc", checkasm_check_v210enc }, #endif @@ -150,15 +153,24 @@ static const struct { #endif #endif #if CONFIG_AVFILTER + #if CONFIG_AFIR_FILTER + { "af_afir", checkasm_check_afir }, + #endif #if CONFIG_BLEND_FILTER { "vf_blend", checkasm_check_blend }, #endif #if CONFIG_COLORSPACE_FILTER { "vf_colorspace", checkasm_check_colorspace }, #endif + #if CONFIG_GBLUR_FILTER + { "vf_gblur", checkasm_check_vf_gblur }, + #endif #if CONFIG_HFLIP_FILTER { "vf_hflip", checkasm_check_vf_hflip }, #endif + #if CONFIG_NLMEANS_FILTER + { "vf_nlmeans", checkasm_check_nlmeans }, + #endif #if CONFIG_THRESHOLD_FILTER { "vf_threshold", checkasm_check_vf_threshold }, #endif @@ -606,6 +618,7 @@ static int bench_init_linux(void) } #endif +#if !CONFIG_LINUX_PERF static int bench_init_ffmpeg(void) { #ifdef AV_READ_TIME @@ -616,6 +629,7 @@ static int bench_init_ffmpeg(void) return -1; #endif } +#endif static int bench_init(void) { diff --git a/tests/checkasm/checkasm.h b/tests/checkasm/checkasm.h index dcab74de0..aed15b5fa 100644 --- a/tests/checkasm/checkasm.h +++ b/tests/checkasm/checkasm.h @@ -40,6 +40,7 @@ #include "libavutil/timer.h" void checkasm_check_aacpsdsp(void); +void checkasm_check_afir(void); void checkasm_check_alacdsp(void); void checkasm_check_audiodsp(void); void checkasm_check_blend(void); @@ -62,12 +63,15 @@ void checkasm_check_huffyuvdsp(void); void checkasm_check_jpeg2000dsp(void); void checkasm_check_llviddsp(void); void checkasm_check_llviddspenc(void); +void checkasm_check_nlmeans(void); void checkasm_check_pixblockdsp(void); void checkasm_check_sbrdsp(void); void checkasm_check_synth_filter(void); void checkasm_check_sw_rgb(void); void checkasm_check_utvideodsp(void); +void checkasm_check_v210dec(void); void checkasm_check_v210enc(void); +void checkasm_check_vf_gblur(void); void checkasm_check_vf_hflip(void); void checkasm_check_vf_threshold(void); void checkasm_check_vp8dsp(void); diff --git a/tests/checkasm/float_dsp.c b/tests/checkasm/float_dsp.c index 2f999a316..2abe4eccb 100644 --- a/tests/checkasm/float_dsp.c +++ b/tests/checkasm/float_dsp.c @@ -61,6 +61,28 @@ static void test_vector_fmul(const float *src0, const float *src1) bench_new(odst, src0, src1, LEN); } +static void test_vector_dmul(const double *src0, const double *src1) +{ + LOCAL_ALIGNED_32(double, cdst, [LEN]); + LOCAL_ALIGNED_32(double, odst, [LEN]); + int i; + + declare_func(void, double *dst, const double *src0, const double *src1, + int len); + + call_ref(cdst, src0, src1, LEN); + call_new(odst, src0, src1, LEN); + for (i = 0; i < LEN; i++) { + if (!double_near_abs_eps(cdst[i], odst[i], DBL_EPSILON)) { + fprintf(stderr, "%d: %- .12f - %- .12f = % .12g\n", + i, cdst[i], odst[i], cdst[i] - odst[i]); + fail(); + break; + } + } + bench_new(odst, src0, src1, LEN); +} + #define ARBITRARY_FMUL_ADD_CONST 0.005 static void test_vector_fmul_add(const float *src0, const float *src1, const float *src2) { @@ -294,6 +316,8 @@ void checkasm_check_float_dsp(void) if (check_func(fdsp->vector_fmac_scalar, "vector_fmac_scalar")) test_vector_fmac_scalar(src0, src1, src2); report("vector_fmac"); + if (check_func(fdsp->vector_dmul, "vector_dmul")) + test_vector_dmul(dbl_src0, dbl_src1); if (check_func(fdsp->vector_dmul_scalar, "vector_dmul_scalar")) test_vector_dmul_scalar(dbl_src0, dbl_src1); report("vector_dmul"); diff --git a/tests/checkasm/h264dsp.c b/tests/checkasm/h264dsp.c index 5f73bc9f0..697520574 100644 --- a/tests/checkasm/h264dsp.c +++ b/tests/checkasm/h264dsp.c @@ -28,6 +28,7 @@ #include "libavutil/intreadwrite.h" static const uint32_t pixel_mask[3] = { 0xffffffff, 0x01ff01ff, 0x03ff03ff }; +static const uint32_t pixel_mask_lf[3] = { 0xff0fff0f, 0x01ff000f, 0x03ff000f }; #define SIZEOF_PIXEL ((bit_depth + 7) / 8) #define SIZEOF_COEF (2 * ((bit_depth + 7) / 8)) @@ -312,9 +313,140 @@ static void check_idct_multiple(void) } } + +static void check_loop_filter(void) +{ + LOCAL_ALIGNED_16(uint8_t, dst, [32 * 16 * 2]); + LOCAL_ALIGNED_16(uint8_t, dst0, [32 * 16 * 2]); + LOCAL_ALIGNED_16(uint8_t, dst1, [32 * 16 * 2]); + H264DSPContext h; + int bit_depth; + int alphas[36], betas[36]; + int8_t tc0[36][4]; + + declare_func_emms(AV_CPU_FLAG_MMX, void, uint8_t *pix, ptrdiff_t stride, + int alpha, int beta, int8_t *tc0); + + for (bit_depth = 8; bit_depth <= 10; bit_depth++) { + int i, j, a, c; + uint32_t mask = pixel_mask_lf[bit_depth - 8]; + ff_h264dsp_init(&h, bit_depth, 1); + for (i = 35, a = 255, c = 250; i >= 0; i--) { + alphas[i] = a << (bit_depth - 8); + betas[i] = (i + 1) / 2 << (bit_depth - 8); + tc0[i][0] = tc0[i][3] = (c + 6) / 10; + tc0[i][1] = (c + 7) / 15; + tc0[i][2] = (c + 9) / 20; + a = a*9/10; + c = c*9/10; + } + +#define CHECK_LOOP_FILTER(name, align, idc) \ + do { \ + if (check_func(h.name, #name #idc "_%dbpp", bit_depth)) { \ + for (j = 0; j < 36; j++) { \ + intptr_t off = 8 * 32 + (j & 15) * 4 * !align; \ + for (i = 0; i < 1024; i+=4) { \ + AV_WN32A(dst + i, rnd() & mask); \ + } \ + memcpy(dst0, dst, 32 * 16 * 2); \ + memcpy(dst1, dst, 32 * 16 * 2); \ + \ + call_ref(dst0 + off, 32, alphas[j], betas[j], tc0[j]); \ + call_new(dst1 + off, 32, alphas[j], betas[j], tc0[j]); \ + if (memcmp(dst0, dst1, 32 * 16 * SIZEOF_PIXEL)) { \ + fprintf(stderr, #name #idc ": j:%d, alpha:%d beta:%d " \ + "tc0:{%d,%d,%d,%d}\n", j, alphas[j], betas[j], \ + tc0[j][0], tc0[j][1], tc0[j][2], tc0[j][3]); \ + fail(); \ + } \ + bench_new(dst1, 32, alphas[j], betas[j], tc0[j]); \ + } \ + } \ + } while (0) + + CHECK_LOOP_FILTER(h264_v_loop_filter_luma, 1,); + CHECK_LOOP_FILTER(h264_h_loop_filter_luma, 0,); + CHECK_LOOP_FILTER(h264_h_loop_filter_luma_mbaff, 0,); + CHECK_LOOP_FILTER(h264_v_loop_filter_chroma, 1,); + CHECK_LOOP_FILTER(h264_h_loop_filter_chroma, 0,); + CHECK_LOOP_FILTER(h264_h_loop_filter_chroma_mbaff, 0,); + + ff_h264dsp_init(&h, bit_depth, 2); + CHECK_LOOP_FILTER(h264_h_loop_filter_chroma, 0, 422); + CHECK_LOOP_FILTER(h264_h_loop_filter_chroma_mbaff, 0, 422); +#undef CHECK_LOOP_FILTER + } +} + +static void check_loop_filter_intra(void) +{ + LOCAL_ALIGNED_16(uint8_t, dst, [32 * 16 * 2]); + LOCAL_ALIGNED_16(uint8_t, dst0, [32 * 16 * 2]); + LOCAL_ALIGNED_16(uint8_t, dst1, [32 * 16 * 2]); + H264DSPContext h; + int bit_depth; + int alphas[36], betas[36]; + + declare_func_emms(AV_CPU_FLAG_MMX, void, uint8_t *pix, ptrdiff_t stride, + int alpha, int beta); + + for (bit_depth = 8; bit_depth <= 10; bit_depth++) { + int i, j, a; + uint32_t mask = pixel_mask_lf[bit_depth - 8]; + ff_h264dsp_init(&h, bit_depth, 1); + for (i = 35, a = 255; i >= 0; i--) { + alphas[i] = a << (bit_depth - 8); + betas[i] = (i + 1) / 2 << (bit_depth - 8); + a = a*9/10; + } + +#define CHECK_LOOP_FILTER(name, align, idc) \ + do { \ + if (check_func(h.name, #name #idc "_%dbpp", bit_depth)) { \ + for (j = 0; j < 36; j++) { \ + intptr_t off = 8 * 32 + (j & 15) * 4 * !align; \ + for (i = 0; i < 1024; i+=4) { \ + AV_WN32A(dst + i, rnd() & mask); \ + } \ + memcpy(dst0, dst, 32 * 16 * 2); \ + memcpy(dst1, dst, 32 * 16 * 2); \ + \ + call_ref(dst0 + off, 32, alphas[j], betas[j]); \ + call_new(dst1 + off, 32, alphas[j], betas[j]); \ + if (memcmp(dst0, dst1, 32 * 16 * SIZEOF_PIXEL)) { \ + fprintf(stderr, #name #idc ": j:%d, alpha:%d beta:%d\n", \ + j, alphas[j], betas[j]); \ + fail(); \ + } \ + bench_new(dst1, 32, alphas[j], betas[j]); \ + } \ + } \ + } while (0) + + CHECK_LOOP_FILTER(h264_v_loop_filter_luma_intra, 1,); + CHECK_LOOP_FILTER(h264_h_loop_filter_luma_intra, 0,); + CHECK_LOOP_FILTER(h264_h_loop_filter_luma_mbaff_intra, 0,); + CHECK_LOOP_FILTER(h264_v_loop_filter_chroma_intra, 1,); + CHECK_LOOP_FILTER(h264_h_loop_filter_chroma_intra, 0,); + CHECK_LOOP_FILTER(h264_h_loop_filter_chroma_mbaff_intra, 0,); + + ff_h264dsp_init(&h, bit_depth, 2); + CHECK_LOOP_FILTER(h264_h_loop_filter_chroma_intra, 0, 422); + CHECK_LOOP_FILTER(h264_h_loop_filter_chroma_mbaff_intra, 0, 422); +#undef CHECK_LOOP_FILTER + } +} + void checkasm_check_h264dsp(void) { check_idct(); check_idct_multiple(); report("idct"); + + check_loop_filter(); + report("loop_filter"); + + check_loop_filter_intra(); + report("loop_filter_intra"); } diff --git a/tests/checkasm/sw_rgb.c b/tests/checkasm/sw_rgb.c index 8fc2cfee9..000420d8f 100644 --- a/tests/checkasm/sw_rgb.c +++ b/tests/checkasm/sw_rgb.c @@ -35,8 +35,12 @@ } while (0) static const uint8_t width[] = {12, 16, 20, 32, 36, 128}; +static const struct {uint8_t w, h, s;} planes[] = { + {12,16,12}, {16,16,16}, {20,23,25}, {32,18,48}, {8,128,16}, {128,128,128} +}; #define MAX_STRIDE 128 +#define MAX_HEIGHT 128 static void check_shuffle_bytes(void * func, const char * report) { @@ -64,6 +68,49 @@ static void check_shuffle_bytes(void * func, const char * report) } } +static void check_uyvy_to_422p(void) +{ + int i; + + LOCAL_ALIGNED_32(uint8_t, src0, [MAX_STRIDE * MAX_HEIGHT * 2]); + LOCAL_ALIGNED_32(uint8_t, src1, [MAX_STRIDE * MAX_HEIGHT * 2]); + LOCAL_ALIGNED_32(uint8_t, dst_y_0, [MAX_STRIDE * MAX_HEIGHT]); + LOCAL_ALIGNED_32(uint8_t, dst_y_1, [MAX_STRIDE * MAX_HEIGHT]); + LOCAL_ALIGNED_32(uint8_t, dst_u_0, [(MAX_STRIDE/2) * MAX_HEIGHT]); + LOCAL_ALIGNED_32(uint8_t, dst_u_1, [(MAX_STRIDE/2) * MAX_HEIGHT]); + LOCAL_ALIGNED_32(uint8_t, dst_v_0, [(MAX_STRIDE/2) * MAX_HEIGHT]); + LOCAL_ALIGNED_32(uint8_t, dst_v_1, [(MAX_STRIDE/2) * MAX_HEIGHT]); + + declare_func_emms(AV_CPU_FLAG_MMX, void, uint8_t *ydst, uint8_t *udst, uint8_t *vdst, + const uint8_t *src, int width, int height, + int lumStride, int chromStride, int srcStride); + + randomize_buffers(src0, MAX_STRIDE * MAX_HEIGHT * 2); + memcpy(src1, src0, MAX_STRIDE * MAX_HEIGHT * 2); + + if (check_func(uyvytoyuv422, "uyvytoyuv422")) { + for (i = 0; i < 6; i ++) { + memset(dst_y_0, 0, MAX_STRIDE * MAX_HEIGHT); + memset(dst_y_1, 0, MAX_STRIDE * MAX_HEIGHT); + memset(dst_u_0, 0, (MAX_STRIDE/2) * MAX_HEIGHT); + memset(dst_u_1, 0, (MAX_STRIDE/2) * MAX_HEIGHT); + memset(dst_v_0, 0, (MAX_STRIDE/2) * MAX_HEIGHT); + memset(dst_v_1, 0, (MAX_STRIDE/2) * MAX_HEIGHT); + + call_ref(dst_y_0, dst_u_0, dst_v_0, src0, planes[i].w, planes[i].h, + MAX_STRIDE, MAX_STRIDE / 2, planes[i].s); + call_new(dst_y_1, dst_u_1, dst_v_1, src1, planes[i].w, planes[i].h, + MAX_STRIDE, MAX_STRIDE / 2, planes[i].s); + if (memcmp(dst_y_0, dst_y_1, MAX_STRIDE * MAX_HEIGHT) || + memcmp(dst_u_0, dst_u_1, (MAX_STRIDE/2) * MAX_HEIGHT) || + memcmp(dst_v_0, dst_v_1, (MAX_STRIDE/2) * MAX_HEIGHT)) + fail(); + } + bench_new(dst_y_1, dst_u_1, dst_v_1, src1, planes[5].w, planes[5].h, + MAX_STRIDE, MAX_STRIDE / 2, planes[5].s); + } +} + void checkasm_check_sw_rgb(void) { ff_sws_rgb2rgb_init(); @@ -82,4 +129,7 @@ void checkasm_check_sw_rgb(void) check_shuffle_bytes(shuffle_bytes_3210, "shuffle_bytes_3210"); report("shuffle_bytes_3210"); + + check_uyvy_to_422p(); + report("uyvytoyuv422"); } diff --git a/tests/checkasm/v210dec.c b/tests/checkasm/v210dec.c new file mode 100644 index 000000000..7dd50a827 --- /dev/null +++ b/tests/checkasm/v210dec.c @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2019 James Darnley + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with FFmpeg; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include "checkasm.h" +#include "libavcodec/v210dec.h" + +static uint32_t get_v210(void) +{ + uint32_t t0 = rnd() & 0x3ff, + t1 = rnd() & 0x3ff, + t2 = rnd() & 0x3ff; + uint32_t value = t0 + | (t1 << 10) + | (t2 << 20); + return value; +} + +#define NUM_SAMPLES 2048 + +static void randomize_buffers(uint32_t *src0, uint32_t *src1, int len) +{ + for (int i = 0; i < len; i++) { + uint32_t value = get_v210(); + src0[i] = value; + src1[i] = value; + } +} + +void checkasm_check_v210dec(void) +{ + V210DecContext h; + + h.aligned_input = 0; + ff_v210dec_init(&h); + + if (check_func(h.unpack_frame, "v210_unpack")) { + uint32_t src0[NUM_SAMPLES/3]; + uint32_t src1[NUM_SAMPLES/3]; + uint16_t y0[NUM_SAMPLES/2]; + uint16_t y1[NUM_SAMPLES/2]; + uint16_t u0[NUM_SAMPLES/4]; + uint16_t u1[NUM_SAMPLES/4]; + uint16_t v0[NUM_SAMPLES/4]; + uint16_t v1[NUM_SAMPLES/4]; + declare_func(void, const uint32_t *src, uint16_t *y, uint16_t *u, uint16_t *v, int width); + const int pixels = NUM_SAMPLES / 2 / 6 * 6; + + randomize_buffers(src0, src1, NUM_SAMPLES/3); + call_ref(src0, y0, u0, v0, pixels); + call_new(src1, y1, u1, v1, pixels); + if (memcmp(src0, src1, NUM_SAMPLES/3 * sizeof src0[0]) + || memcmp(y0, y1, pixels * sizeof y0[0]) + || memcmp(u0, u1, pixels/2 * sizeof u0[0]) + || memcmp(v0, v1, pixels/2 * sizeof v0[0])) + fail(); + bench_new(src1, y1, u1, v1, pixels); + } + report("v210_unpack"); +} diff --git a/tests/checkasm/vf_blend.c b/tests/checkasm/vf_blend.c index 912f3a2c3..a7578fec3 100644 --- a/tests/checkasm/vf_blend.c +++ b/tests/checkasm/vf_blend.c @@ -71,7 +71,7 @@ w = WIDTH / depth; \ \ for (i = 0; i < BUF_UNITS - 1; i++) { \ - int src_offset = i * SIZE_PER_UNIT + i; /* Test various alignments */ \ + int src_offset = i * SIZE_PER_UNIT + (BUF_UNITS - 1 - i) * depth; /* Test various alignments */ \ int dst_offset = i * SIZE_PER_UNIT; /* dst must be aligned */ \ randomize_buffers(); \ call_ref(top1 + src_offset, w, bot1 + src_offset, w, \ diff --git a/tests/checkasm/vf_gblur.c b/tests/checkasm/vf_gblur.c new file mode 100644 index 000000000..1d63fc22a --- /dev/null +++ b/tests/checkasm/vf_gblur.c @@ -0,0 +1,66 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with FFmpeg; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include "checkasm.h" +#include "libavfilter/gblur.h" + +#define WIDTH 256 +#define HEIGHT 256 +#define PIXELS (WIDTH * HEIGHT) +#define BUF_SIZE (PIXELS * 4) + +#define randomize_buffers(buf, size) \ + do { \ + int j; \ + float *tmp_buf = (float *)buf; \ + for (j = 0; j < size; j++) \ + tmp_buf[j] = (float)(rnd() & 0xFF); \ + } while (0) + +void checkasm_check_vf_gblur(void) +{ + float *dst_ref = av_malloc(BUF_SIZE); + float *dst_new = av_malloc(BUF_SIZE); + int w = WIDTH; + int h = HEIGHT; + int steps = 2; + float nu = 0.101f; + float bscale = 1.112f; + GBlurContext s; + + declare_func(void, float *dst, int w, int h, int steps, float nu, float bscale); + + randomize_buffers(dst_ref, PIXELS); + memcpy(dst_new, dst_ref, BUF_SIZE); + + ff_gblur_init(&s); + + if (check_func(s.horiz_slice, "horiz_slice")) { + call_ref(dst_ref, w, h, steps, nu, bscale); + call_new(dst_new, w, h, steps, nu, bscale); + + if (!float_near_abs_eps_array(dst_ref, dst_new, 0.01f, PIXELS)) { + fail(); + } + bench_new(dst_new, w, h, 1, nu, bscale); + } + report("horiz_slice"); + av_freep(&dst_ref); + av_freep(&dst_new); +} diff --git a/tests/checkasm/vf_nlmeans.c b/tests/checkasm/vf_nlmeans.c new file mode 100644 index 000000000..32c6931a4 --- /dev/null +++ b/tests/checkasm/vf_nlmeans.c @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2018 Clément Bœsch + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "checkasm.h" +#include "libavfilter/vf_nlmeans.h" +#include "libavutil/avassert.h" + +#define randomize_buffer(buf, size) do { \ + int i; \ + for (i = 0; i < size / 4; i++) \ + ((uint32_t *)buf)[i] = rnd(); \ +} while (0) + +void checkasm_check_nlmeans(void) +{ + NLMeansDSPContext dsp = {0}; + + const int w = 123; // source width + const int h = 45; // source height + const int p = 3; // patch half size + const int r = 2; // research window half size + + ff_nlmeans_init(&dsp); + + /* See the filter's code for the explanations on the variables */ + if (check_func(dsp.compute_safe_ssd_integral_image, "ssd_integral_image")) { + int offx, offy; + const int e = p + r; + const int ii_w = w + e*2; + const int ii_h = h + e*2; + const int ii_lz_32 = FFALIGN(ii_w + 1, 4); + uint32_t *ii_orig_ref = av_mallocz_array(ii_h + 1, ii_lz_32 * sizeof(*ii_orig_ref)); + uint32_t *ii_ref = ii_orig_ref + ii_lz_32 + 1; + uint32_t *ii_orig_new = av_mallocz_array(ii_h + 1, ii_lz_32 * sizeof(*ii_orig_new)); + uint32_t *ii_new = ii_orig_new + ii_lz_32 + 1; + const int src_lz = FFALIGN(w, 16); + uint8_t *src = av_mallocz_array(h, src_lz); + + declare_func(void, uint32_t *dst, ptrdiff_t dst_linesize_32, + const uint8_t *s1, ptrdiff_t linesize1, + const uint8_t *s2, ptrdiff_t linesize2, + int w, int h); + + randomize_buffer(src, h * src_lz); + + for (offy = -r; offy <= r; offy++) { + for (offx = -r; offx <= r; offx++) { + if (offx || offy) { + const int s1x = e; + const int s1y = e; + const int s2x = e + offx; + const int s2y = e + offy; + const int startx_safe = FFMAX(s1x, s2x); + const int starty_safe = FFMAX(s1y, s2y); + const int u_endx_safe = FFMIN(s1x + w, s2x + w); + const int endy_safe = FFMIN(s1y + h, s2y + h); + const int safe_pw = (u_endx_safe - startx_safe) & ~0xf; + const int safe_ph = endy_safe - starty_safe; + + av_assert0(safe_pw && safe_ph); + av_assert0(startx_safe - s1x >= 0); av_assert0(startx_safe - s1x < w); + av_assert0(starty_safe - s1y >= 0); av_assert0(starty_safe - s1y < h); + av_assert0(startx_safe - s2x >= 0); av_assert0(startx_safe - s2x < w); + av_assert0(starty_safe - s2y >= 0); av_assert0(starty_safe - s2y < h); + + memset(ii_ref, 0, (ii_lz_32 * ii_h - 1) * sizeof(*ii_ref)); + memset(ii_new, 0, (ii_lz_32 * ii_h - 1) * sizeof(*ii_new)); + + call_ref(ii_ref + starty_safe*ii_lz_32 + startx_safe, ii_lz_32, + src + (starty_safe - s1y) * src_lz + (startx_safe - s1x), src_lz, + src + (starty_safe - s2y) * src_lz + (startx_safe - s2x), src_lz, + safe_pw, safe_ph); + call_new(ii_new + starty_safe*ii_lz_32 + startx_safe, ii_lz_32, + src + (starty_safe - s1y) * src_lz + (startx_safe - s1x), src_lz, + src + (starty_safe - s2y) * src_lz + (startx_safe - s2x), src_lz, + safe_pw, safe_ph); + + if (memcmp(ii_ref, ii_new, (ii_lz_32 * ii_h - 1) * sizeof(*ii_ref))) + fail(); + + memset(ii_new, 0, (ii_lz_32 * ii_h - 1) * sizeof(*ii_new)); + bench_new(ii_new + starty_safe*ii_lz_32 + startx_safe, ii_lz_32, + src + (starty_safe - s1y) * src_lz + (startx_safe - s1x), src_lz, + src + (starty_safe - s2y) * src_lz + (startx_safe - s2x), src_lz, + safe_pw, safe_ph); + } + } + } + + av_freep(&ii_orig_ref); + av_freep(&ii_orig_new); + av_freep(&src); + } + + report("dsp"); +} diff --git a/tests/fate-run.sh b/tests/fate-run.sh index 457761c15..2f1991da5 100755 --- a/tests/fate-run.sh +++ b/tests/fate-run.sh @@ -5,7 +5,7 @@ export LC_ALL=C base=$(dirname $0) . "${base}/md5.sh" -base64=tests/base64 +base64=tests/base64${HOSTEXECSUF} test="${1#fate-}" target_samples=$2 @@ -25,6 +25,7 @@ cmp_unit=${15:-2} gen=${16:-no} hwaccel=${17:-none} report_type=${18:-standard} +keep=${19:-0} outdir="tests/data/fate" outfile="${outdir}/${test}" @@ -44,7 +45,7 @@ compare(){ } do_tiny_psnr(){ - psnr=$(tests/tiny_psnr "$1" "$2" $cmp_unit $cmp_shift 0) || return 1 + psnr=$(tests/tiny_psnr${HOSTEXECSUF} "$1" "$2" $cmp_unit $cmp_shift 0) || return 1 val=$(expr "$psnr" : ".*$3: *\([0-9.]*\)") size1=$(expr "$psnr" : '.*bytes: *\([0-9]*\)') size2=$(expr "$psnr" : '.*bytes:[ 0-9]*/ *\([0-9]*\)') @@ -85,11 +86,11 @@ runecho(){ } probefmt(){ - run ffprobe${PROGSUF} -show_entries format=format_name -print_format default=nw=1:nk=1 -v 0 "$@" + run ffprobe${PROGSUF}${EXECSUF} -show_entries format=format_name -print_format default=nw=1:nk=1 -v 0 "$@" } probetags(){ - run ffprobe${PROGSUF} -show_entries format_tags -v 0 "$@" + run ffprobe${PROGSUF}${EXECSUF} -show_entries format_tags -v 0 "$@" } runlocal(){ @@ -98,24 +99,24 @@ runlocal(){ } probeframes(){ - run ffprobe${PROGSUF} -show_frames -v 0 "$@" + run ffprobe${PROGSUF}${EXECSUF} -show_frames -v 0 "$@" } probechapters(){ - run ffprobe${PROGSUF} -show_chapters -v 0 "$@" + run ffprobe${PROGSUF}${EXECSUF} -show_chapters -v 0 "$@" } probegaplessinfo(){ filename="$1" shift - run ffprobe${PROGSUF} -bitexact -select_streams a -show_entries format=start_time,duration:stream=index,start_pts,duration_ts -v 0 "$filename" "$@" + run ffprobe${PROGSUF}${EXECSUF} -bitexact -select_streams a -show_entries format=start_time,duration:stream=index,start_pts,duration_ts -v 0 "$filename" "$@" pktfile1="${outdir}/${test}.pkts" framefile1="${outdir}/${test}.frames" cleanfiles="$cleanfiles $pktfile1 $framefile1" - run ffprobe${PROGSUF} -bitexact -select_streams a -of compact -count_packets -show_entries packet=pts,dts,duration,flags:stream=nb_read_packets -v 0 "$filename" "$@" > "$pktfile1" + run ffprobe${PROGSUF}${EXECSUF} -bitexact -select_streams a -of compact -count_packets -show_entries packet=pts,dts,duration,flags:stream=nb_read_packets -v 0 "$filename" "$@" > "$pktfile1" head -n 8 "$pktfile1" tail -n 9 "$pktfile1" - run ffprobe${PROGSUF} -bitexact -select_streams a -of compact -count_frames -show_entries frame=pkt_pts,pkt_dts,best_effort_timestamp,pkt_duration,nb_samples:stream=nb_read_frames -v 0 "$filename" "$@" > "$framefile1" + run ffprobe${PROGSUF}${EXECSUF} -bitexact -select_streams a -of compact -count_frames -show_entries frame=pkt_pts,pkt_dts,best_effort_timestamp,pkt_duration,nb_samples:stream=nb_read_frames -v 0 "$filename" "$@" > "$framefile1" head -n 8 "$framefile1" tail -n 9 "$framefile1" } @@ -127,7 +128,7 @@ ffmpeg(){ [ x${arg} = x-i ] && ffmpeg_args="${ffmpeg_args} ${dec_opts}" ffmpeg_args="${ffmpeg_args} ${arg}" done - run ffmpeg${PROGSUF} ${ffmpeg_args} + run ffmpeg${PROGSUF}${EXECSUF} ${ffmpeg_args} } framecrc(){ @@ -205,7 +206,7 @@ enc_dec(){ ffmpeg $8 $DEC_OPTS -i $tencfile $ENC_OPTS $dec_opt $FLAGS \ -f $dec_fmt -y $tdecfile || return do_md5sum $decfile - tests/tiny_psnr $srcfile $decfile $cmp_unit $cmp_shift + tests/tiny_psnr${HOSTEXECSUF} $srcfile $decfile $cmp_unit $cmp_shift } transcode(){ @@ -242,16 +243,110 @@ stream_remux(){ -f framecrc - || return } -lavffatetest(){ - t="${test#lavf-fate-}" - ref=${base}/ref/lavf-fate/$t - ${base}/lavf-regression.sh $t lavf-fate tests/vsynth1 "$target_exec" "$target_path" "$threads" "$thread_type" "$cpuflags" "$target_samples" +# FIXME: There is a certain duplication between the avconv-related helper +# functions above and below that should be refactored. +ffmpeg2="$target_exec ${target_path}/ffmpeg${PROGSUF}${EXECSUF}" +raw_src="${target_path}/tests/vsynth1/%02d.pgm" +pcm_src="${target_path}/tests/data/asynth1.sw" +crcfile="tests/data/$test.lavf.crc" +target_crcfile="${target_path}/$crcfile" + +[ "${V-0}" -gt 0 ] && echov=echov || echov=: + +echov(){ + echo "$@" >&3 } -lavftest(){ +AVCONV_OPTS="-nostdin -nostats -y -cpuflags $cpuflags" +COMMON_OPTS="-flags +bitexact -idct simple -sws_flags +accurate_rnd+bitexact -fflags +bitexact" +DEC_OPTS="$COMMON_OPTS -threads $threads" +ENC_OPTS="$COMMON_OPTS -threads 1 -dct fastint" + +run_avconv(){ + $echov $ffmpeg2 $AVCONV_OPTS $* + $ffmpeg2 $AVCONV_OPTS $* +} + +do_avconv(){ + f="$1" + shift + set -- $* ${target_path}/$f + run_avconv $* + do_md5sum $f + echo $(wc -c $f) +} + +do_avconv_crc(){ + f="$1" + shift + run_avconv $* -f crc "$target_crcfile" + echo "$f $(cat $crcfile)" +} + +lavf_audio(){ t="${test#lavf-}" - ref=${base}/ref/lavf/$t - ${base}/lavf-regression.sh $t lavf tests/vsynth1 "$target_exec" "$target_path" "$threads" "$thread_type" "$cpuflags" "$target_samples" + outdir="tests/data/lavf" + file=${outdir}/lavf.$t + do_avconv $file $DEC_OPTS $1 -ar 44100 -f s16le -i $pcm_src "$ENC_OPTS -metadata title=lavftest" -t 1 -qscale 10 $2 + do_avconv_crc $file $DEC_OPTS $3 -i $target_path/$file +} + +lavf_container(){ + t="${test#lavf-}" + outdir="tests/data/lavf" + file=${outdir}/lavf.$t + do_avconv $file $DEC_OPTS -f image2 -c:v pgmyuv -i $raw_src $DEC_OPTS -ar 44100 -f s16le $1 -i $pcm_src "$ENC_OPTS -metadata title=lavftest" -b:a 64k -t 1 -qscale:v 10 $2 + test $3 = "disable_crc" || + do_avconv_crc $file $DEC_OPTS -i $target_path/$file $3 +} + +lavf_container_attach() { lavf_container "" "$1 -attach ${raw_src%/*}/00.pgm -metadata:s:t mimetype=image/x-portable-greymap"; } +lavf_container_timecode_nodrop() { lavf_container "" "$1 -timecode 02:56:14:13"; } +lavf_container_timecode_drop() { lavf_container "" "$1 -timecode 02:56:14.13 -r 30000/1001"; } + +lavf_container_timecode() +{ + lavf_container_timecode_nodrop "$@" + lavf_container_timecode_drop "$@" + lavf_container "" "$1" +} + +lavf_container_fate() +{ + t="${test#lavf-fate-}" + outdir="tests/data/lavf-fate" + file=${outdir}/lavf.$t + input="${target_samples}/$1" + do_avconv $file $DEC_OPTS $2 -i "$input" "$ENC_OPTS -metadata title=lavftest" -vcodec copy -acodec copy + do_avconv_crc $file $DEC_OPTS -i $target_path/$file $3 +} + +lavf_image(){ + t="${test#lavf-}" + outdir="tests/data/images/$t" + mkdir -p "$outdir" + file=${outdir}/%02d.$t + run_avconv $DEC_OPTS -f image2 -c:v pgmyuv -i $raw_src $1 "$ENC_OPTS -metadata title=lavftest" -frames 13 -y -qscale 10 $target_path/$file + do_md5sum ${outdir}/02.$t + do_avconv_crc $file $DEC_OPTS $2 -i $target_path/$file $2 + echo $(wc -c ${outdir}/02.$t) +} + +lavf_image2pipe(){ + t="${test#lavf-}" + t="${t%pipe}" + outdir="tests/data/lavf" + file=${outdir}/${t}pipe.$t + do_avconv $file $DEC_OPTS -f image2 -c:v pgmyuv -i $raw_src -f image2pipe "$ENC_OPTS -metadata title=lavftest" -t 1 -qscale 10 + do_avconv_crc $file $DEC_OPTS -f image2pipe -i $target_path/$file +} + +lavf_video(){ + t="${test#lavf-}" + outdir="tests/data/lavf" + file=${outdir}/lavf.$t + do_avconv $file $DEC_OPTS -f image2 -c:v pgmyuv -i $raw_src "$ENC_OPTS -metadata title=lavftest" -t 1 -qscale 10 $1 $2 + do_avconv_crc $file $DEC_OPTS -i $target_path/$file $1 } refcmp_metadata(){ @@ -263,6 +358,17 @@ refcmp_metadata(){ -f null /dev/null | awk -v ref=${ref} -v fuzz=${fuzz} -f ${base}/refcmp-metadata.awk - } +pixfmt_conversion(){ + conversion="${test#pixfmt-}" + outdir="tests/data/pixfmt" + raw_dst="$outdir/$conversion.out.yuv" + file=${outdir}/${conversion}.yuv + run_avconv $DEC_OPTS -r 1 -f image2 -c:v pgmyuv -i $raw_src \ + $ENC_OPTS -f rawvideo -t 1 -s 352x288 -pix_fmt $conversion $target_path/$raw_dst + do_avconv $file $DEC_OPTS -f rawvideo -s 352x288 -pix_fmt $conversion -i $target_path/$raw_dst \ + $ENC_OPTS -f rawvideo -s 352x288 -pix_fmt yuv444p +} + video_filter(){ filters=$1 shift @@ -280,7 +386,7 @@ pixfmts(){ prefilter_chain=$2 nframes=${3:-1} - showfiltfmts="$target_exec $target_path/libavfilter/tests/filtfmts" + showfiltfmts="$target_exec $target_path/libavfilter/tests/filtfmts${EXECSUF}" scale_exclude_fmts=${outfile}_scale_exclude_fmts scale_in_fmts=${outfile}_scale_in_fmts scale_out_fmts=${outfile}_scale_out_fmts @@ -349,7 +455,7 @@ audio_match(){ cleanfiles="$cleanfiles $decfile" ffmpeg -i "$sample" -bitexact $extra_args -y $decfile - tests/audiomatch $decfile $trefile + tests/audiomatch${HOSTEXECSUF} $decfile $trefile } concat(){ @@ -365,10 +471,10 @@ concat(){ awk "{gsub(/%SRCFILE%/, \"$sample\"); print}" $template > $concatfile if [ "$mode" = "md5" ]; then - run ffprobe${PROGSUF} -bitexact -show_streams -show_packets -v 0 -fflags keepside -safe 0 $extra_args $concatfile | tr -d '\r' > $packetfile + run ffprobe${PROGSUF}${EXECSUF} -bitexact -show_streams -show_packets -v 0 -fflags keepside -safe 0 $extra_args $concatfile | tr -d '\r' > $packetfile do_md5sum $packetfile else - run ffprobe${PROGSUF} -bitexact -show_streams -show_packets -v 0 -of compact=p=0:nk=1 -fflags keepside -safe 0 $extra_args $concatfile + run ffprobe${PROGSUF}${EXECSUF} -bitexact -show_streams -show_packets -v 0 -of compact=p=0:nk=1 -fflags keepside -safe 0 $extra_args $concatfile fi } @@ -376,8 +482,6 @@ null(){ : } -mkdir -p "$outdir" - # Disable globbing: command arguments may contain globbing characters and # must be kept verbatim set -f @@ -428,7 +532,9 @@ if test $err != 0 && test $gen != "no" ; then fi if test $err = 0; then - rm -f $outfile $errfile $cmpfile $cleanfiles + if test $keep = 0; then + rm -f $outfile $errfile $cmpfile $cleanfiles + fi elif test $gen = "no"; then echo "Test $test failed. Look at $errfile for details." test "${V:-0}" -gt 0 && cat $errfile diff --git a/tests/fate/api.mak b/tests/fate/api.mak index eb656e68a..3e1cc992e 100644 --- a/tests/fate/api.mak +++ b/tests/fate/api.mak @@ -1,33 +1,37 @@ FATE_API_LIBAVCODEC-$(call ENCDEC, FLAC, FLAC) += fate-api-flac fate-api-flac: $(APITESTSDIR)/api-flac-test$(EXESUF) -fate-api-flac: CMD = run $(APITESTSDIR)/api-flac-test +fate-api-flac: CMD = run $(APITESTSDIR)/api-flac-test$(EXESUF) fate-api-flac: CMP = null FATE_API_SAMPLES_LIBAVFORMAT-$(call DEMDEC, FLV, FLV) += fate-api-band fate-api-band: $(APITESTSDIR)/api-band-test$(EXESUF) -fate-api-band: CMD = run $(APITESTSDIR)/api-band-test $(TARGET_SAMPLES)/mpeg4/resize_down-up.h263 +fate-api-band: CMD = run $(APITESTSDIR)/api-band-test$(EXESUF) $(TARGET_SAMPLES)/mpeg4/resize_down-up.h263 fate-api-band: CMP = null FATE_API_SAMPLES_LIBAVFORMAT-$(call DEMDEC, H264, H264) += fate-api-h264 fate-api-h264: $(APITESTSDIR)/api-h264-test$(EXESUF) -fate-api-h264: CMD = run $(APITESTSDIR)/api-h264-test $(TARGET_SAMPLES)/h264-conformance/SVA_NL2_E.264 +fate-api-h264: CMD = run $(APITESTSDIR)/api-h264-test$(EXESUF) $(TARGET_SAMPLES)/h264-conformance/SVA_NL2_E.264 + +FATE_API_SAMPLES_LIBAVFORMAT-$(call DEMDEC, H264, H264) += fate-api-h264-slice +fate-api-h264-slice: $(APITESTSDIR)/api-h264-slice-test$(EXESUF) +fate-api-h264-slice: CMD = run $(APITESTSDIR)/api-h264-slice-test$(EXESUF) 2 $(TARGET_SAMPLES)/h264/crew_cif.nal FATE_API_LIBAVFORMAT-$(call DEMDEC, FLV, FLV) += fate-api-seek -fate-api-seek: $(APITESTSDIR)/api-seek-test$(EXESUF) fate-lavf-flv_fmt -fate-api-seek: CMD = run $(APITESTSDIR)/api-seek-test $(TARGET_PATH)/tests/data/lavf/lavf.flv 0 720 +fate-api-seek: $(APITESTSDIR)/api-seek-test$(EXESUF) fate-lavf-flv +fate-api-seek: CMD = run $(APITESTSDIR)/api-seek-test$(EXESUF) $(TARGET_PATH)/tests/data/lavf/lavf.flv 0 720 fate-api-seek: CMP = null FATE_API_SAMPLES_LIBAVFORMAT-$(call DEMDEC, IMAGE2, PNG) += fate-api-png-codec-param fate-api-png-codec-param: $(APITESTSDIR)/api-codec-param-test$(EXESUF) -fate-api-png-codec-param: CMD = run $(APITESTSDIR)/api-codec-param-test $(TARGET_SAMPLES)/png1/lena-rgba.png +fate-api-png-codec-param: CMD = run $(APITESTSDIR)/api-codec-param-test$(EXESUF) $(TARGET_SAMPLES)/png1/lena-rgba.png FATE_API_SAMPLES_LIBAVFORMAT-$(call DEMDEC, IMAGE2, MJPEG) += fate-api-mjpeg-codec-param fate-api-mjpeg-codec-param: $(APITESTSDIR)/api-codec-param-test$(EXESUF) -fate-api-mjpeg-codec-param: CMD = run $(APITESTSDIR)/api-codec-param-test $(TARGET_SAMPLES)/exif/image_small.jpg +fate-api-mjpeg-codec-param: CMD = run $(APITESTSDIR)/api-codec-param-test$(EXESUF) $(TARGET_SAMPLES)/exif/image_small.jpg FATE_API-$(HAVE_THREADS) += fate-api-threadmessage fate-api-threadmessage: $(APITESTSDIR)/api-threadmessage-test$(EXESUF) -fate-api-threadmessage: CMD = run $(APITESTSDIR)/api-threadmessage-test 3 10 30 50 2 20 40 +fate-api-threadmessage: CMD = run $(APITESTSDIR)/api-threadmessage-test$(EXESUF) 3 10 30 50 2 20 40 fate-api-threadmessage: CMP = null FATE_API_SAMPLES-$(CONFIG_AVFORMAT) += $(FATE_API_SAMPLES_LIBAVFORMAT-yes) diff --git a/tests/fate/audio.mak b/tests/fate/audio.mak index 40c4ca7b7..c41958ea2 100644 --- a/tests/fate/audio.mak +++ b/tests/fate/audio.mak @@ -19,10 +19,20 @@ fate-bmv-audio: CMD = framecrc -i $(TARGET_SAMPLES)/bmv/SURFING-partial.BMV -vn FATE_SAMPLES_AUDIO-$(call DEMDEC, DSICIN, DSICINAUDIO) += fate-delphine-cin-audio fate-delphine-cin-audio: CMD = framecrc -i $(TARGET_SAMPLES)/delphine-cin/LOGO-partial.CIN -vn +FATE_SAMPLES_AUDIO-$(call DEMDEC, S337M, DOLBY_E) += fate-dolby-e +fate-dolby-e: CMD = pcm -i $(TARGET_SAMPLES)/dolby_e/16-11 +fate-dolby-e: CMP = oneoff +fate-dolby-e: REF = $(SAMPLES)/dolby_e/16-11.pcm + FATE_SAMPLES_AUDIO-$(call DEMDEC, DSS, DSS_SP) += fate-dss-lp fate-dss-sp fate-dss-lp: CMD = framecrc -i $(TARGET_SAMPLES)/dss/lp.dss -frames 30 fate-dss-sp: CMD = framecrc -i $(TARGET_SAMPLES)/dss/sp.dss -frames 30 +FATE_SAMPLES_AUDIO-$(call DEMDEC, DSF, DST) += fate-dsf-dst +fate-dsf-dst: CMD = pcm -i $(TARGET_SAMPLES)/dst/dst-64fs44-2ch.dff +fate-dsf-dst: CMP = oneoff +fate-dsf-dst: REF = $(SAMPLES)/dst/dst-64fs44-2ch.pcm + FATE_SAMPLES_AUDIO-$(call DEMDEC, AVI, IMC) += fate-imc fate-imc: CMD = pcm -i $(TARGET_SAMPLES)/imc/imc.avi fate-imc: CMP = oneoff diff --git a/tests/fate/cbs.mak b/tests/fate/cbs.mak index fc5967e6f..f2ef04ced 100644 --- a/tests/fate/cbs.mak +++ b/tests/fate/cbs.mak @@ -2,19 +2,19 @@ # arguments, it decomposes the stream fully and then recomposes it # without making any changes. -fate-cbs: fate-cbs-h264 fate-cbs-hevc fate-cbs-mpeg2 +fate-cbs: fate-cbs-h264 fate-cbs-hevc fate-cbs-mpeg2 fate-cbs-vp9 -FATE_CBS_DEPS = $(call ALLYES, $(1)_DEMUXER $(1)_PARSER $(2)_METADATA_BSF $(3)_DECODER $(3)_MUXER) +FATE_CBS_DEPS = $(call ALLYES, $(1)_DEMUXER $(2)_PARSER $(3)_METADATA_BSF $(4)_DECODER $(5)_MUXER) define FATE_CBS_TEST # (codec, test_name, sample_file, output_format) FATE_CBS_$(1) += fate-cbs-$(1)-$(2) -fate-cbs-$(1)-$(2): CMD = md5 -i $(TARGET_SAMPLES)/$(3) -c:v copy -bsf:v $(1)_metadata -f $(4) +fate-cbs-$(1)-$(2): CMD = md5 -i $(TARGET_SAMPLES)/$(3) -c:v copy -y -bsf:v $(1)_metadata -f $(4) endef # H.264 read/write -FATE_CBS_H264_SAMPLES = \ +FATE_CBS_H264_CONFORMANCE_SAMPLES = \ SVA_Base_B.264 \ BASQP1_Sony_C.jsv \ FM1_BT_B.h264 \ @@ -30,9 +30,13 @@ FATE_CBS_H264_SAMPLES = \ CVSE2_Sony_B.jsv \ CABACI3_Sony_B.jsv -$(foreach N,$(FATE_CBS_H264_SAMPLES),$(eval $(call FATE_CBS_TEST,h264,$(basename $(N)),h264-conformance/$(N),h264))) +FATE_CBS_H264_SAMPLES = \ + sei-1.h264 -FATE_CBS_H264-$(call FATE_CBS_DEPS, H264, H264, H264) = $(FATE_CBS_h264) +$(foreach N,$(FATE_CBS_H264_CONFORMANCE_SAMPLES),$(eval $(call FATE_CBS_TEST,h264,$(basename $(N)),h264-conformance/$(N),h264))) +$(foreach N,$(FATE_CBS_H264_SAMPLES),$(eval $(call FATE_CBS_TEST,h264,$(basename $(N)),h264/$(N),h264))) + +FATE_CBS_H264-$(call FATE_CBS_DEPS, H264, H264, H264, H264, H264) = $(FATE_CBS_h264) FATE_SAMPLES_AVCONV += $(FATE_CBS_H264-yes) fate-cbs-h264: $(FATE_CBS_H264-yes) @@ -57,11 +61,12 @@ FATE_CBS_HEVC_SAMPLES = \ LTRPSPS_A_Qualcomm_1.bit \ RPLM_A_qualcomm_4.bit \ CONFWIN_A_Sony_1.bit \ - HRD_A_Fujitsu_2.bit + HRD_A_Fujitsu_2.bit \ + SLPPLP_A_VIDYO_2.bit $(foreach N,$(FATE_CBS_HEVC_SAMPLES),$(eval $(call FATE_CBS_TEST,hevc,$(basename $(N)),hevc-conformance/$(N),hevc))) -FATE_CBS_HEVC-$(call FATE_CBS_DEPS, HEVC, HEVC, HEVC) = $(FATE_CBS_hevc) +FATE_CBS_HEVC-$(call FATE_CBS_DEPS, HEVC, HEVC, HEVC, HEVC, HEVC) = $(FATE_CBS_hevc) FATE_SAMPLES_AVCONV += $(FATE_CBS_HEVC-yes) fate-cbs-hevc: $(FATE_CBS_HEVC-yes) @@ -74,6 +79,30 @@ FATE_CBS_MPEG2_SAMPLES = \ $(foreach N,$(FATE_CBS_MPEG2_SAMPLES),$(eval $(call FATE_CBS_TEST,mpeg2,$(basename $(N)),mpeg2/$(N),mpeg2video))) -FATE_CBS_MPEG2-$(call FATE_CBS_DEPS, MPEGVIDEO, MPEG2, MPEG2VIDEO) = $(FATE_CBS_mpeg2) +FATE_CBS_MPEG2-$(call FATE_CBS_DEPS, MPEGVIDEO, MPEGVIDEO, MPEG2, MPEG2VIDEO, MPEG2VIDEO) = $(FATE_CBS_mpeg2) FATE_SAMPLES_AVCONV += $(FATE_CBS_MPEG2-yes) fate-cbs-mpeg2: $(FATE_CBS_MPEG2-yes) + +# VP9 read/write + +FATE_CBS_VP9_SAMPLES = \ + vp90-2-03-deltaq.webm \ + vp90-2-05-resize.ivf \ + vp90-2-06-bilinear.webm \ + vp90-2-09-lf_deltas.webm \ + vp90-2-10-show-existing-frame.webm \ + vp90-2-10-show-existing-frame2.webm \ + vp90-2-segmentation-aq-akiyo.webm \ + vp90-2-segmentation-sf-akiyo.webm \ + vp90-2-tiling-pedestrian.webm \ + vp91-2-04-yuv440.webm \ + vp91-2-04-yuv444.webm \ + vp92-2-20-10bit-yuv420.webm \ + vp93-2-20-10bit-yuv422.webm \ + vp93-2-20-12bit-yuv444.webm + +$(foreach N,$(FATE_CBS_VP9_SAMPLES),$(eval $(call FATE_CBS_TEST,vp9,$(basename $(N)),vp9-test-vectors/$(N),ivf))) + +FATE_CBS_VP9-$(call FATE_CBS_DEPS, IVF, VP9, VP9, VP9, IVF) = $(FATE_CBS_vp9) +FATE_SAMPLES_AVCONV += $(FATE_CBS_VP9-yes) +fate-cbs-vp9: $(FATE_CBS_VP9-yes) diff --git a/tests/fate/checkasm.mak b/tests/fate/checkasm.mak index a722b4a91..618bde509 100644 --- a/tests/fate/checkasm.mak +++ b/tests/fate/checkasm.mak @@ -1,4 +1,5 @@ FATE_CHECKASM = fate-checkasm-aacpsdsp \ + fate-checkasm-af_afir \ fate-checkasm-alacdsp \ fate-checkasm-audiodsp \ fate-checkasm-blockdsp \ @@ -22,9 +23,11 @@ FATE_CHECKASM = fate-checkasm-aacpsdsp \ fate-checkasm-sbrdsp \ fate-checkasm-synth_filter \ fate-checkasm-sw_rgb \ + fate-checkasm-v210dec \ fate-checkasm-v210enc \ fate-checkasm-vf_blend \ fate-checkasm-vf_colorspace \ + fate-checkasm-vf_gblur \ fate-checkasm-vf_hflip \ fate-checkasm-vf_threshold \ fate-checkasm-videodsp \ @@ -32,7 +35,7 @@ FATE_CHECKASM = fate-checkasm-aacpsdsp \ fate-checkasm-vp9dsp \ $(FATE_CHECKASM): tests/checkasm/checkasm$(EXESUF) -$(FATE_CHECKASM): CMD = run tests/checkasm/checkasm --test=$(@:fate-checkasm-%=%) +$(FATE_CHECKASM): CMD = run tests/checkasm/checkasm$(EXESUF) --test=$(@:fate-checkasm-%=%) $(FATE_CHECKASM): CMP = null FATE += $(FATE_CHECKASM) diff --git a/tests/fate/demux.mak b/tests/fate/demux.mak index ef9e67782..eb8d8c365 100644 --- a/tests/fate/demux.mak +++ b/tests/fate/demux.mak @@ -76,6 +76,9 @@ fate-mov-mp3-demux: CMD = framecrc -i $(TARGET_SAMPLES)/mpegaudio/packed_maindat FATE_SAMPLES_DEMUX-$(CONFIG_MPEGTS_DEMUXER) += fate-ts-opus-demux fate-ts-opus-demux: CMD = framecrc -i $(TARGET_SAMPLES)/opus/test-8-7.1.opus-small.ts -c copy +FATE_SAMPLES_DEMUX-$(CONFIG_MPEGTS_DEMUXER) += fate-ts-small-demux +fate-ts-small-demux: CMD = framecrc -i $(TARGET_SAMPLES)/mpegts/h264small.ts -c copy + FATE_SAMPLES_DEMUX-$(CONFIG_MTV_DEMUXER) += fate-mtv fate-mtv: CMD = framecrc -i $(TARGET_SAMPLES)/mtv/comedian_auto-partial.mtv -c copy diff --git a/tests/fate/ffmpeg.mak b/tests/fate/ffmpeg.mak index 0975af261..71ab2f1f6 100644 --- a/tests/fate/ffmpeg.mak +++ b/tests/fate/ffmpeg.mak @@ -93,6 +93,10 @@ fate-copy-trac2211-avi: $(TARGET_SAMPLES)/h264/bbc2.sample.h264 fate-copy-trac2211-avi: CMD = transcode "h264 -r 14" $(TARGET_SAMPLES)/h264/bbc2.sample.h264\ avi "-c:a copy -c:v copy" +FATE_STREAMCOPY-$(call ENCDEC, APNG, APNG) += fate-copy-apng +fate-copy-apng: fate-lavf-apng +fate-copy-apng: CMD = transcode apng tests/data/lavf/lavf.apng apng "-c:v copy" + FATE_STREAMCOPY-$(call DEMMUX, OGG, OGG) += fate-limited_input_seek fate-limited_input_seek-copyts fate-limited_input_seek: $(TARGET_SAMPLES)/vorbis/moog_small.ogg fate-limited_input_seek: CMD = md5 -ss 1.5 -t 1.3 -i $(TARGET_SAMPLES)/vorbis/moog_small.ogg -c:a copy -fflags +bitexact -f ogg diff --git a/tests/fate/fft.mak b/tests/fate/fft.mak index c7c26cd63..5da6e687e 100644 --- a/tests/fate/fft.mak +++ b/tests/fate/fft.mak @@ -24,7 +24,7 @@ fate-rdft-float: $(FATE_RDFT-yes) FATE_FFT_ALL = $(FATE_DCT-yes) $(FATE_FFT-yes) $(FATE_MDCT-yes) $(FATE_RDFT-yes) $(FATE_FFT_ALL): libavcodec/tests/fft$(EXESUF) -$(FATE_FFT_ALL): CMD = run libavcodec/tests/fft $(CPUFLAGS:%=-c%) $(ARGS) +$(FATE_FFT_ALL): CMD = run libavcodec/tests/fft$(EXESUF) $(CPUFLAGS:%=-c%) $(ARGS) define DEF_FFT_FIXED FATE_FFT_FIXED-$(CONFIG_FFT) += fate-fft-fixed-$(1) fate-ifft-fixed-$(1) @@ -44,7 +44,7 @@ fate-mdct-fixed: $(FATE_MDCT_FIXED-yes) FATE_FFT_FIXED_ALL = $(FATE_FFT_FIXED-yes) $(FATE_MDCT_FIXED-yes) $(FATE_FFT_FIXED_ALL): libavcodec/tests/fft-fixed$(EXESUF) -$(FATE_FFT_FIXED_ALL): CMD = run libavcodec/tests/fft-fixed $(CPUFLAGS:%=-c%) $(ARGS) +$(FATE_FFT_FIXED_ALL): CMD = run libavcodec/tests/fft-fixed$(EXESUF) $(CPUFLAGS:%=-c%) $(ARGS) $(FATE_FFT_ALL) $(FATE_FFT_FIXED_ALL): CMP = null @@ -62,7 +62,7 @@ $(foreach N, 4 5 6 7 8 9 10 11 12, $(eval $(call DEF_FFT_FIXED32,$(N)))) fate-fft-fixed32: $(FATE_FFT_FIXED32) $(FATE_FFT_FIXED32): libavcodec/tests/fft-fixed32$(EXESUF) -$(FATE_FFT_FIXED32): CMD = run libavcodec/tests/fft-fixed32 $(CPUFLAGS:%=-c%) $(ARGS) +$(FATE_FFT_FIXED32): CMD = run libavcodec/tests/fft-fixed32$(EXESUF) $(CPUFLAGS:%=-c%) $(ARGS) $(FATE_FFT_FIXED32): CMP = null define DEF_AV_FFT @@ -91,7 +91,7 @@ fate-av-rdft-float: $(FATE_AV_RDFT-yes) FATE_AV_FFT_ALL = $(FATE_AV_DCT-yes) $(FATE_AV_FFT-yes) $(FATE_AV_MDCT-yes) $(FATE_AV_RDFT-yes) $(FATE_AV_FFT_ALL): libavcodec/tests/avfft$(EXESUF) -$(FATE_AV_FFT_ALL): CMD = run libavcodec/tests/avfft $(CPUFLAGS:%=-c%) $(ARGS) +$(FATE_AV_FFT_ALL): CMD = run libavcodec/tests/avfft$(EXESUF) $(CPUFLAGS:%=-c%) $(ARGS) $(FATE_AV_FFT_ALL): CMP = null fate-dct: fate-dct-float diff --git a/tests/fate/filter-audio.mak b/tests/fate/filter-audio.mak index 2a3ba1992..f1db7b9f0 100644 --- a/tests/fate/filter-audio.mak +++ b/tests/fate/filter-audio.mak @@ -156,11 +156,31 @@ fate-filter-pan-stereo3: CMD = framecrc -ss 3.14 -i $(SRC) -frames:a 20 -filter: FATE_AFILTER-$(call FILTERDEMDECENCMUX, PAN, WAV, PCM_S16LE, PCM_S16LE, WAV) += fate-filter-pan-stereo4 fate-filter-pan-stereo4: tests/data/asynth-44100-2.wav fate-filter-pan-stereo4: SRC = $(TARGET_PATH)/tests/data/asynth-44100-2.wav -fate-filter-pan-stereo4: CMD = framecrc -ss 3.14 -guess_layout_max 0 -i $(SRC) -frames:a 20 -filter:a "pan=4C|c0=c0-0.5*c1|c1=c1+0.5*c0|c2=0*c0|c3=0*c0" +fate-filter-pan-stereo4: CMD = framecrc -ss 3.14 -guess_layout_max 0 -i $(SRC) -frames:a 20 -filter:a "pan=2C|c0=c0-0.5*c1|c1=c1+0.5*c0" + +FATE_AFILTER-$(call FILTERDEMDECENCMUX, PAN, WAV, PCM_S16LE, PCM_S16LE, WAV) += fate-filter-pan-upmix1 +fate-filter-pan-upmix1: tests/data/asynth-44100-2.wav +fate-filter-pan-upmix1: SRC = $(TARGET_PATH)/tests/data/asynth-44100-2.wav +fate-filter-pan-upmix1: CMD = framecrc -ss 3.14 -guess_layout_max 0 -i $(SRC) -frames:a 20 -filter:a "pan=4C|c0=c0-0.5*c1|c1=c1+0.5*c0|c2=0*c0|c3=0*c0" + +FATE_AFILTER-$(call FILTERDEMDECENCMUX, PAN, WAV, PCM_S16LE, PCM_S16LE, WAV) += fate-filter-pan-upmix2 +fate-filter-pan-upmix2: tests/data/asynth-44100-4.wav +fate-filter-pan-upmix2: SRC = $(TARGET_PATH)/tests/data/asynth-44100-4.wav +fate-filter-pan-upmix2: CMD = framecrc -ss 3.14 -i $(SRC) -frames:a 20 -filter:a "pan=9C|c0=c0-c1|c1=c2+c3|c2=c0+c1|c3=c2-c3|c4=c1-c0|c5=c3+c2|c6=c1+c0|c7=c3-c2|c8=c0-c3" + +FATE_AFILTER-$(call FILTERDEMDECENCMUX, PAN, WAV, PCM_S16LE, PCM_S16LE, WAV) += fate-filter-pan-downmix1 +fate-filter-pan-downmix1: tests/data/asynth-44100-4.wav +fate-filter-pan-downmix1: SRC = $(TARGET_PATH)/tests/data/asynth-44100-4.wav +fate-filter-pan-downmix1: CMD = framecrc -ss 3.14 -i $(SRC) -frames:a 20 -filter:a "pan=2c|FL/dev/null + +FATE_AFILTER-$(call ALLYES, HLS_DEMUXER MPEGTS_MUXER MPEGTS_DEMUXER AEVALSRC_FILTER LAVFI_INDEV MP2FIXED_ENCODER) += fate-hls-live-no-endlist +fate-hls-live-no-endlist: tests/data/live_no_endlist.m3u8 +fate-hls-live-no-endlist: SRC = $(TARGET_PATH)/tests/data/live_no_endlist.m3u8 +fate-hls-live-no-endlist: CMD = md5 -i $(SRC) -af hdcd=process_stereo=false -t 6 -f s24le +fate-hls-live-no-endlist: CMP = oneline +fate-hls-live-no-endlist: REF = e038bb8e65d4c1745b9b3ed643e607a3 + +tests/data/live_last_endlist.m3u8: TAG = GEN +tests/data/live_last_endlist.m3u8: ffmpeg$(PROGSSUF)$(EXESUF) | tests/data + $(M)$(TARGET_EXEC) $(TARGET_PATH)/$< \ + -f lavfi -v verbose -i "aevalsrc=cos(2*PI*t)*sin(2*PI*(440+4*t)*t):d=20" -f hls -hls_time 3 -map 0 \ + -codec:a mp2fixed -hls_segment_filename $(TARGET_PATH)/tests/data/live_last_endlist_%03d.ts \ + $(TARGET_PATH)/tests/data/live_last_endlist.m3u8 2>/dev/null + +FATE_AFILTER-$(call ALLYES, HLS_DEMUXER MPEGTS_MUXER MPEGTS_DEMUXER AEVALSRC_FILTER LAVFI_INDEV MP2FIXED_ENCODER) += fate-hls-live-last-endlist +fate-hls-live-last-endlist: tests/data/live_last_endlist.m3u8 +fate-hls-live-last-endlist: SRC = $(TARGET_PATH)/tests/data/live_last_endlist.m3u8 +fate-hls-live-last-endlist: CMD = md5 -i $(SRC) -af hdcd=process_stereo=false -t 6 -f s24le +fate-hls-live-last-endlist: CMP = oneline +fate-hls-live-last-endlist: REF = 2ca8567092dcf01e37bedd50454d1ab7 + + +tests/data/live_endlist.m3u8: TAG = GEN +tests/data/live_endlist.m3u8: ffmpeg$(PROGSSUF)$(EXESUF) | tests/data + $(M)$(TARGET_EXEC) $(TARGET_PATH)/$< \ + -f lavfi -i "aevalsrc=cos(2*PI*t)*sin(2*PI*(440+4*t)*t):d=20" -f hls -hls_time 3 -map 0 \ + -hls_list_size 0 -codec:a mp2fixed -hls_segment_filename $(TARGET_PATH)/tests/data/live_endlist_%d.ts \ + $(TARGET_PATH)/tests/data/live_endlist.m3u8 2>/dev/null + +FATE_AFILTER-$(call ALLYES, HLS_DEMUXER MPEGTS_MUXER MPEGTS_DEMUXER AEVALSRC_FILTER LAVFI_INDEV MP2FIXED_ENCODER) += fate-hls-live-endlist +fate-hls-live-endlist: tests/data/live_endlist.m3u8 +fate-hls-live-endlist: SRC = $(TARGET_PATH)/tests/data/live_endlist.m3u8 +fate-hls-live-endlist: CMD = md5 -i $(SRC) -af hdcd=process_stereo=false -t 20 -f s24le +fate-hls-live-endlist: CMP = oneline +fate-hls-live-endlist: REF = e189ce781d9c87882f58e3929455167b + +tests/data/hls_segment_size.m3u8: TAG = GEN +tests/data/hls_segment_size.m3u8: ffmpeg$(PROGSSUF)$(EXESUF) | tests/data + $(M)$(TARGET_EXEC) $(TARGET_PATH)/$< \ + -f lavfi -i "aevalsrc=cos(2*PI*t)*sin(2*PI*(440+4*t)*t):d=20" -f hls -hls_segment_size 300000 -map 0 \ + -hls_list_size 0 -codec:a mp2fixed -hls_segment_filename $(TARGET_PATH)/tests/data/hls_segment_size_%d.ts \ + $(TARGET_PATH)/tests/data/hls_segment_size.m3u8 2>/dev/null + +FATE_AFILTER-$(call ALLYES, HLS_DEMUXER MPEGTS_MUXER MPEGTS_DEMUXER AEVALSRC_FILTER LAVFI_INDEV MP2FIXED_ENCODER) += fate-hls-segment-size +fate-hls-segment-size: tests/data/hls_segment_size.m3u8 +fate-hls-segment-size: CMD = framecrc -flags +bitexact -i $(TARGET_PATH)/tests/data/hls_segment_size.m3u8 -vf setpts=N*23 + +tests/data/hls_init_time.m3u8: TAG = GEN +tests/data/hls_init_time.m3u8: ffmpeg$(PROGSSUF)$(EXESUF) | tests/data + $(M)$(TARGET_EXEC) $(TARGET_PATH)/$< \ + -f lavfi -i "aevalsrc=cos(2*PI*t)*sin(2*PI*(440+4*t)*t):d=11" -f hls -hls_init_time 1 -hls_time 3 -map 0 \ + -hls_list_size 5 -codec:a mp2fixed -hls_segment_filename $(TARGET_PATH)/tests/data/hls_init_time_%d.ts \ + $(TARGET_PATH)/tests/data/hls_init_time.m3u8 2>/dev/null + +FATE_AFILTER-$(call ALLYES, HLS_DEMUXER MPEGTS_MUXER MPEGTS_DEMUXER AEVALSRC_FILTER LAVFI_INDEV MP2FIXED_ENCODER) += fate-hls-init-time +fate-hls-init-time: tests/data/hls_init_time.m3u8 +fate-hls-init-time: CMD = framecrc -flags +bitexact -i $(TARGET_PATH)/tests/data/hls_init_time.m3u8 -vf setpts=N*23 + +tests/data/hls_list_size.m3u8: TAG = GEN +tests/data/hls_list_size.m3u8: ffmpeg$(PROGSSUF)$(EXESUF) | tests/data + $(M)$(TARGET_EXEC) $(TARGET_PATH)/$< \ + -f lavfi -i "aevalsrc=cos(2*PI*t)*sin(2*PI*(440+4*t)*t):d=20" -f hls -hls_time 4 -map 0 \ + -hls_list_size 4 -codec:a mp2fixed -hls_segment_filename $(TARGET_PATH)/tests/data/hls_list_size_%d.ts \ + $(TARGET_PATH)/tests/data/hls_list_size.m3u8 2>/dev/null + +FATE_AFILTER-$(call ALLYES, HLS_DEMUXER MPEGTS_MUXER MPEGTS_DEMUXER AEVALSRC_FILTER LAVFI_INDEV MP2FIXED_ENCODER) += fate-hls-list-size +fate-hls-list-size: tests/data/hls_list_size.m3u8 +fate-hls-list-size: CMD = framecrc -flags +bitexact -i $(TARGET_PATH)/tests/data/hls_list_size.m3u8 -vf setpts=N*23 + +tests/data/hls_segment_type_fmp4.m3u8: TAG = GEN +tests/data/hls_segment_type_fmp4.m3u8: ffmpeg$(PROGSSUF)$(EXESUF) | tests/data + $(M)$(TARGET_EXEC) $(TARGET_PATH)/$< \ + -f lavfi -re -i "aevalsrc=cos(2*PI*t)*sin(2*PI*(440+4*t)*t):d=5" -map 0 -codec:a mp2fixed \ + -hls_segment_type mpegts -hls_fmp4_init_filename now.mp4 -hls_list_size 0 \ + -hls_time 1 -hls_segment_filename "$(TARGET_PATH)/tests/data/hls_fmp4_%d.m4s" \ + $(TARGET_PATH)/tests/data/hls_fmp4.m3u8 2>/dev/null + +FATE_AFILTER-$(call ALLYES, HLS_DEMUXER MPEGTS_MUXER MPEGTS_DEMUXER AEVALSRC_FILTER LAVFI_INDEV MP2FIXED_ENCODER) += fate-hls-fmp4 +fate-hls-fmp4: tests/data/hls_segment_type_fmp4.m3u8 +fate-hls-fmp4: CMD = framecrc -flags +bitexact -i $(TARGET_PATH)/tests/data/hls_fmp4.m3u8 -vf setpts=N*23 + diff --git a/tests/fate/hw.mak b/tests/fate/hw.mak new file mode 100644 index 000000000..0f126892f --- /dev/null +++ b/tests/fate/hw.mak @@ -0,0 +1,6 @@ +FATE_HWCONTEXT += fate-hwdevice +fate-hwdevice: libavutil/tests/hwdevice$(EXESUF) +fate-hwdevice: CMD = run libavutil/tests/hwdevice$(EXESUF) +fate-hwdevice: CMP = null + +FATE_HW-$(CONFIG_AVUTIL) += $(FATE_HWCONTEXT) diff --git a/tests/fate/lavf-audio.mak b/tests/fate/lavf-audio.mak new file mode 100644 index 000000000..0be7a3a05 --- /dev/null +++ b/tests/fate/lavf-audio.mak @@ -0,0 +1,38 @@ +FATE_LAVF_AUDIO-$(call ENCDEC, PCM_S16BE, AIFF) += aiff +FATE_LAVF_AUDIO-$(call ENCDEC, PCM_ALAW, PCM_ALAW) += al +FATE_LAVF_AUDIO-$(call ENCDEC, PCM_S16BE_PLANAR, AST) += ast +FATE_LAVF_AUDIO-$(call ENCDEC, PCM_S16BE, AU) += au +FATE_LAVF_AUDIO-$(call ENCDEC, PCM_S16BE, CAF) += caf +FATE_LAVF_AUDIO-$(call ENCDEC, ADPCM_YAMAHA, MMF) += mmf +FATE_LAVF_AUDIO-$(call ENCDEC, FLAC, OGG) += ogg +FATE_LAVF_AUDIO-$(call ENCDEC, PCM_U8, RSO) += rso +FATE_LAVF_AUDIO-$(call ENCDEC, PCM_S16LE, SOX) += sox +FATE_LAVF_AUDIO-$(call ENCDEC, PCM_MULAW, PCM_MULAW) += ul +FATE_LAVF_AUDIO-$(call ENCDEC, PCM_U8, VOC) += voc +FATE_LAVF_AUDIO-$(call ENCDEC, PCM_S16LE, IRCAM) += ircam +FATE_LAVF_AUDIO-$(call ENCDEC, PCM_S16LE, VOC) += s16.voc +FATE_LAVF_AUDIO-$(call ENCDEC, PCM_S16LE, WAV) += wav +FATE_LAVF_AUDIO-$(call ENCDEC, PCM_S16LE, WAV) += peak.wav +FATE_LAVF_AUDIO-$(call ENCDEC, PCM_S16LE, WAV) += peak_only.wav +FATE_LAVF_AUDIO-$(call ENCDEC, PCM_S16LE, W64) += w64 +FATE_LAVF_AUDIO-$(call ENCDEC, TTA, TTA) += tta +FATE_LAVF_AUDIO-$(call ENCMUX, TTA, MATROSKA_AUDIO) += mka +FATE_LAVF_AUDIO-$(call ENCDEC, WAVPACK, WV) += wv + +FATE_LAVF_AUDIO = $(FATE_LAVF_AUDIO-yes:%=fate-lavf-%) + +$(FATE_LAVF_AUDIO): CMD = lavf_audio +$(FATE_LAVF_AUDIO): REF = $(SRC_PATH)/tests/ref/lavf/$(@:fate-lavf-%=%) +$(FATE_LAVF_AUDIO): $(AREF) + +fate-lavf-al fate-lavf-ul: CMD = lavf_audio "" "" "-ar 44100" +fate-lavf-ogg: CMD = lavf_audio "" "-c:a flac" +fate-lavf-s16.voc: CMD = lavf_audio "-ac 2" "-c:a pcm_s16le" +fate-lavf-ast: CMD = lavf_audio "-ac 2" "-loopstart 1 -loopend 10" +fate-lavf-mka: CMD = lavf_audio "" "-c:a tta" +fate-lavf-voc: CMD = lavf_audio "" "-c:a pcm_u8" +fate-lavf-peak.wav: CMD = lavf_audio "" "-write_peak on" +fate-lavf-peak_only.wav: CMD = lavf_audio "" "-write_peak only" + +FATE_AVCONV += $(FATE_LAVF_AUDIO) +fate-lavf-audio fate-lavf: $(FATE_LAVF_AUDIO) diff --git a/tests/fate/lavf-container.mak b/tests/fate/lavf-container.mak new file mode 100644 index 000000000..22387d04d --- /dev/null +++ b/tests/fate/lavf-container.mak @@ -0,0 +1,79 @@ +FATE_LAVF_CONTAINER-$(call ENCDEC2, MSMPEG4V3, MP2, ASF) += asf +FATE_LAVF_CONTAINER-$(call ENCDEC2, MPEG4, MP2, AVI) += avi +FATE_LAVF_CONTAINER-$(call ENCDEC2, DVVIDEO, PCM_S16LE, AVI) += dv dv_pal dv_ntsc +FATE_LAVF_CONTAINER-$(call ENCDEC, FLV, FLV) += flv +FATE_LAVF_CONTAINER-$(call ENCDEC, RAWVIDEO, FILMSTRIP) += flm +FATE_LAVF_CONTAINER-$(call ENCDEC2, MPEG2VIDEO, PCM_S16LE, GXF) += gxf gxf_pal gxf_ntsc +FATE_LAVF_CONTAINER-$(call ENCDEC2, MPEG4, MP2, MATROSKA) += mkv mkv_attachment +FATE_LAVF_CONTAINER-$(call ENCDEC2, MPEG4, PCM_ALAW, MOV) += mov mov_rtphint ismv +FATE_LAVF_CONTAINER-$(call ENCDEC, MPEG4, MOV) += mp4 +FATE_LAVF_CONTAINER-$(call ENCDEC2, MPEG1VIDEO, MP2, MPEG1SYSTEM MPEGPS) += mpg +FATE_LAVF_CONTAINER-$(call ENCDEC2, MPEG2VIDEO, PCM_S16LE, MXF) += mxf mxf_dv25 mxf_dvcpro50 +FATE_LAVF_CONTAINER-$(call ENCDEC2, MPEG2VIDEO, PCM_S16LE, MXF_D10 MXF) += mxf_d10 +FATE_LAVF_CONTAINER-$(call ENCDEC2, DNXHD, PCM_S16LE, MXF_OPATOM MXF) += mxf_opatom mxf_opatom_audio +FATE_LAVF_CONTAINER-$(call ENCDEC2, MPEG4, MP2, NUT) += nut +FATE_LAVF_CONTAINER-$(call ENCMUX, RV10 AC3_FIXED, RM) += rm +FATE_LAVF_CONTAINER-$(call ENCMUX, MJPEG PCM_S16LE, SMJPEG) += smjpeg +FATE_LAVF_CONTAINER-$(call ENCDEC, FLV, SWF) += swf +FATE_LAVF_CONTAINER-$(call ENCDEC2, MPEG2VIDEO, MP2, MPEGTS) += ts +FATE_LAVF_CONTAINER-$(call ENCDEC, MP2, WTV) += wtv + +FATE_LAVF_CONTAINER = $(FATE_LAVF_CONTAINER-yes:%=fate-lavf-%) + +$(FATE_LAVF_CONTAINER): CMD = lavf_container +$(FATE_LAVF_CONTAINER): REF = $(SRC_PATH)/tests/ref/lavf/$(@:fate-lavf-%=%) +$(FATE_LAVF_CONTAINER): $(AREF) $(VREF) + +fate-lavf-asf: CMD = lavf_container "" "-c:a mp2 -ar 44100" "-r 25" +fate-lavf-avi fate-lavf-nut: CMD = lavf_container "" "-c:a mp2 -ar 44100 -threads 1" +fate-lavf-dv: CMD = lavf_container "-ar 48000 -channel_layout stereo" "-r 25 -s pal" +fate-lavf-dv_pal: CMD = lavf_container_timecode_nodrop "-ar 48000 -r 25 -s pal -ac 2 -f dv" +fate-lavf-dv_ntsc: CMD = lavf_container_timecode_drop "-ar 48000 -pix_fmt yuv411p -s ntsc -ac 2 -f dv" +fate-lavf-flv fate-lavf-swf: CMD = lavf_container "" "-an" +fate-lavf-flm: CMD = lavf_container "" "-pix_fmt rgba" +fate-lavf-gxf: CMD = lavf_container "-ar 48000" "-r 25 -s pal -ac 1 -threads 1" +fate-lavf-gxf_pal: CMD = lavf_container_timecode_nodrop "-ar 48000 -r 25 -s pal -ac 1 -threads 1 -f gxf" +fate-lavf-gxf_ntsc: CMD = lavf_container_timecode_drop "-ar 48000 -s ntsc -ac 1 -threads 1 -f gxf" +fate-lavf-ismv: CMD = lavf_container_timecode "-an -write_tmcd 1 -c:v mpeg4 -threads 1" +fate-lavf-mkv: CMD = lavf_container "" "-c:a mp2 -c:v mpeg4 -ar 44100 -threads 1" +fate-lavf-mkv_attachment: CMD = lavf_container_attach "-c:a mp2 -c:v mpeg4 -threads 1 -f matroska" +fate-lavf-mov: CMD = lavf_container_timecode "-movflags +faststart -c:a pcm_alaw -c:v mpeg4 -threads 1" +fate-lavf-mov_rtphint: CMD = lavf_container "" "-movflags +rtphint -c:a pcm_alaw -c:v mpeg4 -threads 1 -f mov" +fate-lavf-mp4: CMD = lavf_container_timecode "-c:v mpeg4 -an -threads 1" +fate-lavf-mpg: CMD = lavf_container_timecode "-ar 44100 -threads 1" +fate-lavf-mxf: CMD = lavf_container_timecode "-ar 48000 -bf 2 -threads 1" +fate-lavf-mxf_d10: CMD = lavf_container "-ar 48000 -ac 2" "-r 25 -vf scale=720:576,pad=720:608:0:32 -c:v mpeg2video -g 0 -flags +ildct+low_delay -dc 10 -non_linear_quant 1 -intra_vlc 1 -qscale 1 -ps 1 -qmin 1 -rc_max_vbv_use 1 -rc_min_vbv_use 1 -pix_fmt yuv422p -minrate 30000k -maxrate 30000k -b 30000k -bufsize 1200000 -top 1 -rc_init_occupancy 1200000 -qmax 12 -f mxf_d10" +fate-lavf-mxf_dv25: CMD = lavf_container "-ar 48000 -ac 2" "-r 25 -vf scale=720:576,setdar=4/3 -c:v dvvideo -pix_fmt yuv420p -b 25000k -top 0 -f mxf" +fate-lavf-mxf_dvcpro50: CMD = lavf_container "-ar 48000 -ac 2" "-r 25 -vf scale=720:576,setdar=16/9 -c:v dvvideo -pix_fmt yuv422p -b 50000k -top 0 -f mxf" +fate-lavf-mxf_opatom: CMD = lavf_container "" "-s 1920x1080 -c:v dnxhd -pix_fmt yuv422p -vb 36M -f mxf_opatom -map 0" +fate-lavf-mxf_opatom_audio: CMD = lavf_container "-ar 48000 -ac 1" "-f mxf_opatom -mxf_audio_edit_rate 25 -map 1" +fate-lavf-smjpeg: CMD = lavf_container "" "-f smjpeg" +# The RealMedia muxer is broken. +fate-lavf-rm: CMD = lavf_container "" "-c:a ac3_fixed" disable_crc +fate-lavf-ts: CMD = lavf_container "" "-mpegts_transport_stream_id 42 -ar 44100 -threads 1" +fate-lavf-wtv: CMD = lavf_container "" "-c:a mp2 -threads 1" + +FATE_AVCONV += $(FATE_LAVF_CONTAINER) +fate-lavf-container fate-lavf: $(FATE_LAVF_CONTAINER) + +FATE_LAVF_CONTAINER_FATE-$(call ALLYES, MATROSKA_DEMUXER OGG_MUXER) += vp3.ogg +FATE_LAVF_CONTAINER_FATE-$(call ALLYES, MATROSKA_DEMUXER OGV_MUXER) += vp8.ogg +FATE_LAVF_CONTAINER_FATE-$(call ALLYES, MOV_DEMUXER LATM_MUXER) += latm +FATE_LAVF_CONTAINER_FATE-$(call ALLYES, MP3_DEMUXER MP3_MUXER) += mp3 +FATE_LAVF_CONTAINER_FATE-$(call ALLYES, MOV_DEMUXER MOV_MUXER) += qtrle_mace6.mov +FATE_LAVF_CONTAINER_FATE-$(call ALLYES, AVI_DEMUXER AVI_MUXER) += cram.avi + +FATE_LAVF_CONTAINER_FATE = $(FATE_LAVF_CONTAINER_FATE-yes:%=fate-lavf-fate-%) + +$(FATE_LAVF_CONTAINER_FATE): REF = $(SRC_PATH)/tests/ref/lavf-fate/$(@:fate-lavf-fate-%=%) +$(FATE_LAVF_CONTAINER_FATE): $(AREF) $(VREF) + +fate-lavf-fate-vp3.ogg: CMD = lavf_container_fate "vp3/coeff_level64.mkv" "-idct auto" +fate-lavf-fate-vp8.ogg: CMD = lavf_container_fate "vp8/RRSF49-short.webm" "" "-acodec copy" +fate-lavf-fate-latm: CMD = lavf_container_fate "aac/al04_44.mp4" "" "-acodec copy" +fate-lavf-fate-mp3: CMD = lavf_container_fate "mp3-conformance/he_32khz.bit" "" "-acodec copy" +fate-lavf-fate-qtrle_mace6.mov: CMD = lavf_container_fate "qtrle/Animation-16Greys.mov" "-idct auto" +fate-lavf-fate-cram.avi: CMD = lavf_container_fate "cram/toon.avi" "-idct auto" + +FATE_SAMPLES_FFMPEG += $(FATE_LAVF_CONTAINER_FATE) +fate-lavf-fate fate-lavf: $(FATE_LAVF_CONTAINER_FATE) diff --git a/tests/fate/lavf-image.mak b/tests/fate/lavf-image.mak new file mode 100644 index 000000000..dbbd37430 --- /dev/null +++ b/tests/fate/lavf-image.mak @@ -0,0 +1,64 @@ +FATE_LAVF_IMAGES-$(call ENCDEC, BMP, IMAGE2) += bmp +FATE_LAVF_IMAGES-$(call ENCDEC, DPX, IMAGE2) += dpx +FATE_LAVF_IMAGES-$(call ENCDEC, DPX, IMAGE2) += gbrp10le.dpx +FATE_LAVF_IMAGES-$(call ENCDEC, DPX, IMAGE2) += gbrp12le.dpx +FATE_LAVF_IMAGES-$(call ENCDEC, DPX, IMAGE2) += rgb48le.dpx +FATE_LAVF_IMAGES-$(call ENCDEC, DPX, IMAGE2) += rgb48le_10.dpx +FATE_LAVF_IMAGES-$(call ENCDEC, DPX, IMAGE2) += rgba64le.dpx +FATE_LAVF_IMAGES-$(call ENCDEC, MJPEG, IMAGE2) += jpg +FATE_LAVF_IMAGES-$(call ENCDEC, PAM, IMAGE2) += pam +FATE_LAVF_IMAGES-$(call ENCDEC, PAM, IMAGE2) += rgba.pam +FATE_LAVF_IMAGES-$(call ENCDEC, PAM, IMAGE2) += gray.pam +FATE_LAVF_IMAGES-$(call ENCDEC, PAM, IMAGE2) += gray16be.pam +FATE_LAVF_IMAGES-$(call ENCDEC, PAM, IMAGE2) += rgb48be.pam +FATE_LAVF_IMAGES-$(call ENCDEC, PAM, IMAGE2) += monob.pam +FATE_LAVF_IMAGES-$(call ENCDEC, PCX, IMAGE2) += pcx +FATE_LAVF_IMAGES-$(call ENCDEC, PGM, IMAGE2) += pgm +FATE_LAVF_IMAGES-$(call ENCDEC, PNG, IMAGE2) += png +FATE_LAVF_IMAGES-$(call ENCDEC, PNG, IMAGE2) += gray16be.png +FATE_LAVF_IMAGES-$(call ENCDEC, PNG, IMAGE2) += rgb48be.png +FATE_LAVF_IMAGES-$(call ENCDEC, PPM, IMAGE2) += ppm +FATE_LAVF_IMAGES-$(call ENCDEC, SGI, IMAGE2) += sgi +FATE_LAVF_IMAGES-$(call ENCDEC, SUNRAST, IMAGE2) += sun +FATE_LAVF_IMAGES-$(call ENCDEC, TARGA, IMAGE2) += tga +FATE_LAVF_IMAGES-$(call ENCDEC, TIFF, IMAGE2) += tiff +FATE_LAVF_IMAGES-$(call ENCDEC, XBM, IMAGE2) += xbm +FATE_LAVF_IMAGES-$(call ENCDEC, XWD, IMAGE2) += xwd +FATE_LAVF_IMAGES-$(call ENCDEC, XWD, IMAGE2) += rgba.xwd +FATE_LAVF_IMAGES-$(call ENCDEC, XWD, IMAGE2) += rgb565be.xwd +FATE_LAVF_IMAGES-$(call ENCDEC, XWD, IMAGE2) += rgb555be.xwd +FATE_LAVF_IMAGES-$(call ENCDEC, XWD, IMAGE2) += rgb8.xwd +FATE_LAVF_IMAGES-$(call ENCDEC, XWD, IMAGE2) += rgb4_byte.xwd +FATE_LAVF_IMAGES-$(call ENCDEC, XWD, IMAGE2) += gray.xwd +FATE_LAVF_IMAGES-$(call ENCDEC, XWD, IMAGE2) += monow.xwd + +FATE_LAVF_IMAGES = $(FATE_LAVF_IMAGES-yes:%=fate-lavf-%) + +$(FATE_LAVF_IMAGES): CMD = lavf_image +$(FATE_LAVF_IMAGES): REF = $(SRC_PATH)/tests/ref/lavf/$(@:fate-lavf-%=%) +$(FATE_LAVF_IMAGES): $(VREF) + +fate-lavf-jpg: CMD = lavf_image "-pix_fmt yuvj420p" +fate-lavf-tiff: CMD = lavf_image "-pix_fmt rgb24" +fate-lavf-gbrp10le.dpx: CMD = lavf_image "-pix_fmt gbrp10le" "-pix_fmt gbrp10le" +fate-lavf-gbrp12le.dpx: CMD = lavf_image "-pix_fmt gbrp12le" "-pix_fmt gbrp12le" +fate-lavf-rgb48le.dpx: CMD = lavf_image "-pix_fmt rgb48le" +fate-lavf-rgb48le_10.dpx: CMD = lavf_image "-pix_fmt rgb48le -bits_per_raw_sample 10" "-pix_fmt rgb48le" +fate-lavf-rgba64le.dpx: CMD = lavf_image "-pix_fmt rgba64le" +fate-lavf-rgba.pam: CMD = lavf_image "-pix_fmt rgba" +fate-lavf-gray.pam: CMD = lavf_image "-pix_fmt gray" +fate-lavf-gray16be.pam: CMD = lavf_image "-pix_fmt gray16be" "-pix_fmt gray16be" +fate-lavf-rgb48be.pam: CMD = lavf_image "-pix_fmt rgb48be" "-pix_fmt rgb48be" +fate-lavf-monob.pam: CMD = lavf_image "-pix_fmt monob" +fate-lavf-gray16be.png: CMD = lavf_image "-pix_fmt gray16be" +fate-lavf-rgb48be.png: CMD = lavf_image "-pix_fmt rgb48be" +fate-lavf-rgba.xwd: CMD = lavf_image "-pix_fmt rgba" +fate-lavf-rgb565be.xwd: CMD = lavf_image "-pix_fmt rgb565be" +fate-lavf-rgb555be.xwd: CMD = lavf_image "-pix_fmt rgb555be" +fate-lavf-rgb8.xwd: CMD = lavf_image "-pix_fmt rgb8" +fate-lavf-rgb4_byte.xwd: CMD = lavf_image "-pix_fmt rgb4_byte" +fate-lavf-gray.xwd: CMD = lavf_image "-pix_fmt gray" +fate-lavf-monow.xwd: CMD = lavf_image "-pix_fmt monow" + +FATE_AVCONV += $(FATE_LAVF_IMAGES) +fate-lavf-images fate-lavf: $(FATE_LAVF_IMAGES) diff --git a/tests/fate/lavf-image2pipe.mak b/tests/fate/lavf-image2pipe.mak new file mode 100644 index 000000000..297f677ad --- /dev/null +++ b/tests/fate/lavf-image2pipe.mak @@ -0,0 +1,12 @@ +FATE_LAVF_IMAGE2PIPE-$(call ENCDEC, PBM, IMAGE2PIPE) += pbmpipe +FATE_LAVF_IMAGE2PIPE-$(call ENCDEC, PGM, IMAGE2PIPE) += pgmpipe +FATE_LAVF_IMAGE2PIPE-$(call ENCDEC, PPM, IMAGE2PIPE) += ppmpipe + +FATE_LAVF_IMAGE2PIPE = $(FATE_LAVF_IMAGE2PIPE-yes:%=fate-lavf-%) + +$(FATE_LAVF_IMAGE2PIPE): CMD = lavf_image2pipe +$(FATE_LAVF_IMAGE2PIPE): REF = $(SRC_PATH)/tests/ref/lavf/$(@:fate-lavf-%=%) +$(FATE_LAVF_IMAGE2PIPE): $(VREF) + +FATE_AVCONV += $(FATE_LAVF_IMAGE2PIPE) +fate-lavf-image2pipe fate-lavf: $(FATE_LAVF_IMAGE2PIPE) diff --git a/tests/fate/lavf-video.mak b/tests/fate/lavf-video.mak new file mode 100644 index 000000000..7a70ac90c --- /dev/null +++ b/tests/fate/lavf-video.mak @@ -0,0 +1,29 @@ +FATE_LAVF_VIDEO-$(call ENCDEC, APNG, APNG) += apng +FATE_LAVF_VIDEO-$(call ENCDEC, APNG, APNG) += apng.png +FATE_LAVF_VIDEO-$(call ENCDEC, FITS, FITS) += gray.fits +FATE_LAVF_VIDEO-$(call ENCDEC, FITS, FITS) += gray16be.fits +FATE_LAVF_VIDEO-$(call ENCDEC, FITS, FITS) += gbrp.fits +FATE_LAVF_VIDEO-$(call ENCDEC, FITS, FITS) += gbrap.fits +FATE_LAVF_VIDEO-$(call ENCDEC, FITS, FITS) += gbrp16be.fits +FATE_LAVF_VIDEO-$(call ENCDEC, FITS, FITS) += gbrap16be.fits +FATE_LAVF_VIDEO-$(call ENCDEC, GIF, FITS) += gif +FATE_LAVF_VIDEO-$(CONFIG_YUV4MPEGPIPE_MUXER) += y4m + +FATE_LAVF_VIDEO = $(FATE_LAVF_VIDEO-yes:%=fate-lavf-%) + +$(FATE_LAVF_VIDEO): CMD = lavf_video +$(FATE_LAVF_VIDEO): REF = $(SRC_PATH)/tests/ref/lavf/$(@:fate-lavf-%=%) +$(FATE_LAVF_VIDEO): $(VREF) + +fate-lavf-apng: CMD = lavf_video "-pix_fmt rgb24" +fate-lavf-apng.png: CMD = lavf_video "-pix_fmt rgb24" "-frames:v 1 -f apng" +fate-lavf-gray.fits: CMD = lavf_video "-pix_fmt gray" +fate-lavf-gray16be.fits: CMD = lavf_video "-pix_fmt gray16be" +fate-lavf-gbrp.fits: CMD = lavf_video "-pix_fmt gbrp" +fate-lavf-gbrap.fits: CMD = lavf_video "-pix_fmt gbrap" +fate-lavf-gbrp16be.fits: CMD = lavf_video "-pix_fmt gbrp16be" +fate-lavf-gbrap16be.fits: CMD = lavf_video "-pix_fmt gbrap16be" +fate-lavf-gif: CMD = lavf_video "-pix_fmt rgb24" + +FATE_AVCONV += $(FATE_LAVF_VIDEO) +fate-lavf-video fate-lavf: $(FATE_LAVF_VIDEO) diff --git a/tests/fate/libavcodec.mak b/tests/fate/libavcodec.mak index d3b2dd874..d9b26bae9 100644 --- a/tests/fate/libavcodec.mak +++ b/tests/fate/libavcodec.mak @@ -1,91 +1,101 @@ FATE_LIBAVCODEC-yes += fate-avpacket fate-avpacket: libavcodec/tests/avpacket$(EXESUF) -fate-avpacket: CMD = run libavcodec/tests/avpacket +fate-avpacket: CMD = run libavcodec/tests/avpacket$(EXESUF) fate-avpacket: CMP = null FATE_LIBAVCODEC-$(CONFIG_CABAC) += fate-cabac fate-cabac: libavcodec/tests/cabac$(EXESUF) -fate-cabac: CMD = run libavcodec/tests/cabac +fate-cabac: CMD = run libavcodec/tests/cabac$(EXESUF) fate-cabac: CMP = null FATE_LIBAVCODEC-yes += fate-celp_math fate-celp_math: libavcodec/tests/celp_math$(EXESUF) -fate-celp_math: CMD = run libavcodec/tests/celp_math +fate-celp_math: CMD = run libavcodec/tests/celp_math$(EXESUF) fate-celp_math: CMP = null FATE_LIBAVCODEC-yes += fate-codec_desc fate-codec_desc: libavcodec/tests/codec_desc$(EXESUF) -fate-codec_desc: CMD = run libavcodec/tests/codec_desc +fate-codec_desc: CMD = run libavcodec/tests/codec_desc$(EXESUF) fate-codec_desc: CMP = null FATE_LIBAVCODEC-$(CONFIG_GOLOMB) += fate-golomb fate-golomb: libavcodec/tests/golomb$(EXESUF) -fate-golomb: CMD = run libavcodec/tests/golomb +fate-golomb: CMD = run libavcodec/tests/golomb$(EXESUF) fate-golomb: CMP = null FATE_LIBAVCODEC-$(CONFIG_IDCTDSP) += fate-idct8x8-0 fate-idct8x8-1 fate-idct8x8-2 fate-idct248 fate-idct8x8-0: libavcodec/tests/dct$(EXESUF) -fate-idct8x8-0: CMD = run libavcodec/tests/dct -i 0 +fate-idct8x8-0: CMD = run libavcodec/tests/dct$(EXESUF) -i 0 fate-idct8x8-0: CMP = null fate-idct8x8-1: libavcodec/tests/dct$(EXESUF) -fate-idct8x8-1: CMD = run libavcodec/tests/dct -i 1 +fate-idct8x8-1: CMD = run libavcodec/tests/dct$(EXESUF) -i 1 fate-idct8x8-1: CMP = null fate-idct8x8-2: libavcodec/tests/dct$(EXESUF) -fate-idct8x8-2: CMD = run libavcodec/tests/dct -i 2 +fate-idct8x8-2: CMD = run libavcodec/tests/dct$(EXESUF) -i 2 fate-idct8x8-2: CMP = null fate-idct248: libavcodec/tests/dct$(EXESUF) -fate-idct248: CMD = run libavcodec/tests/dct -4 +fate-idct248: CMD = run libavcodec/tests/dct$(EXESUF) -4 fate-idct248: CMP = null FATE_LIBAVCODEC-$(CONFIG_IDCTDSP) += fate-dct8x8 fate-dct8x8: libavcodec/tests/dct$(EXESUF) -fate-dct8x8: CMD = run libavcodec/tests/dct +fate-dct8x8: CMD = run libavcodec/tests/dct$(EXESUF) fate-dct8x8: CMP = null +FATE_LIBAVCODEC-$(CONFIG_H264_METADATA_BSF) += fate-h264-levels +fate-h264-levels: libavcodec/tests/h264_levels$(EXESUF) +fate-h264-levels: CMD = run libavcodec/tests/h264_levels$(EXESUF) +fate-h264-levels: REF = /dev/null + +FATE_LIBAVCODEC-$(CONFIG_HEVC_METADATA_BSF) += fate-h265-levels +fate-h265-levels: libavcodec/tests/h265_levels$(EXESUF) +fate-h265-levels: CMD = run libavcodec/tests/h265_levels +fate-h265-levels: REF = /dev/null + FATE_LIBAVCODEC-$(CONFIG_IIRFILTER) += fate-iirfilter fate-iirfilter: libavcodec/tests/iirfilter$(EXESUF) -fate-iirfilter: CMD = run libavcodec/tests/iirfilter +fate-iirfilter: CMD = run libavcodec/tests/iirfilter$(EXESUF) FATE_LIBAVCODEC-$(CONFIG_MPEGVIDEO) += fate-mpeg12framerate fate-mpeg12framerate: libavcodec/tests/mpeg12framerate$(EXESUF) -fate-mpeg12framerate: CMD = run libavcodec/tests/mpeg12framerate +fate-mpeg12framerate: CMD = run libavcodec/tests/mpeg12framerate$(EXESUF) fate-mpeg12framerate: REF = /dev/null FATE_LIBAVCODEC-yes += fate-libavcodec-options fate-libavcodec-options: libavcodec/tests/options$(EXESUF) -fate-libavcodec-options: CMD = run libavcodec/tests/options +fate-libavcodec-options: CMD = run libavcodec/tests/options$(EXESUF) FATE_LIBAVCODEC-$(CONFIG_RANGECODER) += fate-rangecoder fate-rangecoder: libavcodec/tests/rangecoder$(EXESUF) -fate-rangecoder: CMD = run libavcodec/tests/rangecoder +fate-rangecoder: CMD = run libavcodec/tests/rangecoder$(EXESUF) fate-rangecoder: CMP = null FATE_LIBAVCODEC-yes += fate-mathops fate-mathops: libavcodec/tests/mathops$(EXESUF) -fate-mathops: CMD = run libavcodec/tests/mathops +fate-mathops: CMD = run libavcodec/tests/mathops$(EXESUF) fate-mathops: CMP = null FATE_LIBAVCODEC-$(CONFIG_JPEG2000_ENCODER) += fate-j2k-dwt fate-j2k-dwt: libavcodec/tests/jpeg2000dwt$(EXESUF) -fate-j2k-dwt: CMD = run libavcodec/tests/jpeg2000dwt +fate-j2k-dwt: CMD = run libavcodec/tests/jpeg2000dwt$(EXESUF) FATE_LIBAVCODEC-yes += fate-libavcodec-utils fate-libavcodec-utils: libavcodec/tests/utils$(EXESUF) -fate-libavcodec-utils: CMD = run libavcodec/tests/utils +fate-libavcodec-utils: CMD = run libavcodec/tests/utils$(EXESUF) fate-libavcodec-utils: CMP = null FATE_LIBAVCODEC-yes += fate-libavcodec-huffman fate-libavcodec-huffman: libavcodec/tests/mjpegenc_huffman$(EXESUF) -fate-libavcodec-huffman: CMD = run libavcodec/tests/mjpegenc_huffman +fate-libavcodec-huffman: CMD = run libavcodec/tests/mjpegenc_huffman$(EXESUF) fate-libavcodec-huffman: CMP = null FATE_LIBAVCODEC-yes += fate-libavcodec-htmlsubtitles fate-libavcodec-htmlsubtitles: libavcodec/tests/htmlsubtitles$(EXESUF) -fate-libavcodec-htmlsubtitles: CMD = run libavcodec/tests/htmlsubtitles +fate-libavcodec-htmlsubtitles: CMD = run libavcodec/tests/htmlsubtitles$(EXESUF) FATE-$(CONFIG_AVCODEC) += $(FATE_LIBAVCODEC-yes) fate-libavcodec: $(FATE_LIBAVCODEC-yes) diff --git a/tests/fate/libavformat.mak b/tests/fate/libavformat.mak index cf1ba189d..d1e81284e 100644 --- a/tests/fate/libavformat.mak +++ b/tests/fate/libavformat.mak @@ -4,23 +4,23 @@ FATE_LIBAVFORMAT-$(CONFIG_NETWORK) += fate-noproxy fate-noproxy: libavformat/tests/noproxy$(EXESUF) -fate-noproxy: CMD = run libavformat/tests/noproxy +fate-noproxy: CMD = run libavformat/tests/noproxy$(EXESUF) FATE_LIBAVFORMAT-$(CONFIG_FFRTMPCRYPT_PROTOCOL) += fate-rtmpdh fate-rtmpdh: libavformat/tests/rtmpdh$(EXESUF) -fate-rtmpdh: CMD = run libavformat/tests/rtmpdh +fate-rtmpdh: CMD = run libavformat/tests/rtmpdh$(EXESUF) FATE_LIBAVFORMAT-$(CONFIG_SRTP) += fate-srtp fate-srtp: libavformat/tests/srtp$(EXESUF) -fate-srtp: CMD = run libavformat/tests/srtp +fate-srtp: CMD = run libavformat/tests/srtp$(EXESUF) FATE_LIBAVFORMAT-yes += fate-url fate-url: libavformat/tests/url$(EXESUF) -fate-url: CMD = run libavformat/tests/url +fate-url: CMD = run libavformat/tests/url$(EXESUF) FATE_LIBAVFORMAT-$(CONFIG_MOV_MUXER) += fate-movenc fate-movenc: libavformat/tests/movenc$(EXESUF) -fate-movenc: CMD = run libavformat/tests/movenc +fate-movenc: CMD = run libavformat/tests/movenc$(EXESUF) FATE_LIBAVFORMAT += $(FATE_LIBAVFORMAT-yes) FATE-$(CONFIG_AVFORMAT) += $(FATE_LIBAVFORMAT) diff --git a/tests/fate/libavutil.mak b/tests/fate/libavutil.mak index 9b32d880f..1ec9ed00a 100644 --- a/tests/fate/libavutil.mak +++ b/tests/fate/libavutil.mak @@ -1,165 +1,170 @@ FATE_LIBAVUTIL += fate-adler32 fate-adler32: libavutil/tests/adler32$(EXESUF) -fate-adler32: CMD = run libavutil/tests/adler32 +fate-adler32: CMD = run libavutil/tests/adler32$(EXESUF) fate-adler32: CMP = null FATE_LIBAVUTIL += fate-aes fate-aes: libavutil/tests/aes$(EXESUF) -fate-aes: CMD = run libavutil/tests/aes +fate-aes: CMD = run libavutil/tests/aes$(EXESUF) fate-aes: CMP = null FATE_LIBAVUTIL += fate-aes_ctr fate-aes_ctr: libavutil/tests/aes_ctr$(EXESUF) -fate-aes_ctr: CMD = run libavutil/tests/aes_ctr +fate-aes_ctr: CMD = run libavutil/tests/aes_ctr$(EXESUF) fate-aes_ctr: CMP = null FATE_LIBAVUTIL += fate-camellia fate-camellia: libavutil/tests/camellia$(EXESUF) -fate-camellia: CMD = run libavutil/tests/camellia +fate-camellia: CMD = run libavutil/tests/camellia$(EXESUF) fate-camellia: CMP = null FATE_LIBAVUTIL += fate-cast5 fate-cast5: libavutil/tests/cast5$(EXESUF) -fate-cast5: CMD = run libavutil/tests/cast5 +fate-cast5: CMD = run libavutil/tests/cast5$(EXESUF) fate-cast5: CMP = null FATE_LIBAVUTIL += fate-audio_fifo fate-audio_fifo: libavutil/tests/audio_fifo$(EXESUF) -fate-audio_fifo: CMD = run libavutil/tests/audio_fifo +fate-audio_fifo: CMD = run libavutil/tests/audio_fifo$(EXESUF) FATE_LIBAVUTIL += fate-avstring fate-avstring: libavutil/tests/avstring$(EXESUF) -fate-avstring: CMD = run libavutil/tests/avstring +fate-avstring: CMD = run libavutil/tests/avstring$(EXESUF) FATE_LIBAVUTIL += fate-base64 fate-base64: libavutil/tests/base64$(EXESUF) -fate-base64: CMD = run libavutil/tests/base64 +fate-base64: CMD = run libavutil/tests/base64$(EXESUF) FATE_LIBAVUTIL += fate-blowfish fate-blowfish: libavutil/tests/blowfish$(EXESUF) -fate-blowfish: CMD = run libavutil/tests/blowfish +fate-blowfish: CMD = run libavutil/tests/blowfish$(EXESUF) FATE_LIBAVUTIL += fate-bprint fate-bprint: libavutil/tests/bprint$(EXESUF) -fate-bprint: CMD = run libavutil/tests/bprint +fate-bprint: CMD = run libavutil/tests/bprint$(EXESUF) FATE_LIBAVUTIL += fate-cpu fate-cpu: libavutil/tests/cpu$(EXESUF) -fate-cpu: CMD = runecho libavutil/tests/cpu $(CPUFLAGS:%=-c%) $(THREADS:%=-t%) +fate-cpu: CMD = runecho libavutil/tests/cpu$(EXESUF) $(CPUFLAGS:%=-c%) $(THREADS:%=-t%) fate-cpu: CMP = null FATE_LIBAVUTIL-$(HAVE_THREADS) += fate-cpu_init fate-cpu_init: libavutil/tests/cpu_init$(EXESUF) -fate-cpu_init: CMD = run libavutil/tests/cpu_init +fate-cpu_init: CMD = run libavutil/tests/cpu_init$(EXESUF) fate-cpu_init: CMP = null FATE_LIBAVUTIL += fate-crc fate-crc: libavutil/tests/crc$(EXESUF) -fate-crc: CMD = run libavutil/tests/crc +fate-crc: CMD = run libavutil/tests/crc$(EXESUF) FATE_LIBAVUTIL += fate-color_utils fate-color_utils: libavutil/tests/color_utils$(EXESUF) -fate-color_utils: CMD = run libavutil/tests/color_utils +fate-color_utils: CMD = run libavutil/tests/color_utils$(EXESUF) FATE_LIBAVUTIL += fate-des fate-des: libavutil/tests/des$(EXESUF) -fate-des: CMD = run libavutil/tests/des +fate-des: CMD = run libavutil/tests/des$(EXESUF) fate-des: CMP = null FATE_LIBAVUTIL += fate-dict fate-dict: libavutil/tests/dict$(EXESUF) -fate-dict: CMD = run libavutil/tests/dict +fate-dict: CMD = run libavutil/tests/dict$(EXESUF) + +FATE_LIBAVUTIL += fate-encryption-info +fate-encryption-info: libavutil/tests/encryption_info$(EXESUF) +fate-encryption-info: CMD = run libavutil/tests/encryption_info$(EXESUF) +fate-encryption-info: CMP = null FATE_LIBAVUTIL += fate-eval fate-eval: libavutil/tests/eval$(EXESUF) -fate-eval: CMD = run libavutil/tests/eval +fate-eval: CMD = run libavutil/tests/eval$(EXESUF) FATE_LIBAVUTIL += fate-fifo fate-fifo: libavutil/tests/fifo$(EXESUF) -fate-fifo: CMD = run libavutil/tests/fifo +fate-fifo: CMD = run libavutil/tests/fifo$(EXESUF) FATE_LIBAVUTIL += fate-hash fate-hash: libavutil/tests/hash$(EXESUF) -fate-hash: CMD = run libavutil/tests/hash +fate-hash: CMD = run libavutil/tests/hash$(EXESUF) FATE_LIBAVUTIL += fate-hmac fate-hmac: libavutil/tests/hmac$(EXESUF) -fate-hmac: CMD = run libavutil/tests/hmac +fate-hmac: CMD = run libavutil/tests/hmac$(EXESUF) FATE_LIBAVUTIL += fate-imgutils fate-imgutils: libavutil/tests/imgutils$(EXESUF) -fate-imgutils: CMD = run libavutil/tests/imgutils +fate-imgutils: CMD = run libavutil/tests/imgutils$(EXESUF) FATE_LIBAVUTIL += fate-integer fate-integer: libavutil/tests/integer$(EXESUF) -fate-integer: CMD = run libavutil/tests/integer +fate-integer: CMD = run libavutil/tests/integer$(EXESUF) fate-integer: CMP = null FATE_LIBAVUTIL += fate-lfg fate-lfg: libavutil/tests/lfg$(EXESUF) -fate-lfg: CMD = run libavutil/tests/lfg +fate-lfg: CMD = run libavutil/tests/lfg$(EXESUF) FATE_LIBAVUTIL += fate-md5 fate-md5: libavutil/tests/md5$(EXESUF) -fate-md5: CMD = run libavutil/tests/md5 +fate-md5: CMD = run libavutil/tests/md5$(EXESUF) FATE_LIBAVUTIL += fate-murmur3 fate-murmur3: libavutil/tests/murmur3$(EXESUF) -fate-murmur3: CMD = run libavutil/tests/murmur3 +fate-murmur3: CMD = run libavutil/tests/murmur3$(EXESUF) FATE_LIBAVUTIL += fate-parseutils fate-parseutils: libavutil/tests/parseutils$(EXESUF) -fate-parseutils: CMD = run libavutil/tests/parseutils +fate-parseutils: CMD = run libavutil/tests/parseutils$(EXESUF) FATE_LIBAVUTIL-$(CONFIG_PIXELUTILS) += fate-pixelutils fate-pixelutils: libavutil/tests/pixelutils$(EXESUF) -fate-pixelutils: CMD = run libavutil/tests/pixelutils +fate-pixelutils: CMD = run libavutil/tests/pixelutils$(EXESUF) FATE_LIBAVUTIL += fate-pixfmt_best fate-pixfmt_best: libavutil/tests/pixfmt_best$(EXESUF) -fate-pixfmt_best: CMD = run libavutil/tests/pixfmt_best +fate-pixfmt_best: CMD = run libavutil/tests/pixfmt_best$(EXESUF) FATE_LIBAVUTIL += fate-display fate-display: libavutil/tests/display$(EXESUF) -fate-display: CMD = run libavutil/tests/display +fate-display: CMD = run libavutil/tests/display$(EXESUF) FATE_LIBAVUTIL += fate-random_seed fate-random_seed: libavutil/tests/random_seed$(EXESUF) -fate-random_seed: CMD = run libavutil/tests/random_seed +fate-random_seed: CMD = run libavutil/tests/random_seed$(EXESUF) FATE_LIBAVUTIL += fate-ripemd fate-ripemd: libavutil/tests/ripemd$(EXESUF) -fate-ripemd: CMD = run libavutil/tests/ripemd +fate-ripemd: CMD = run libavutil/tests/ripemd$(EXESUF) FATE_LIBAVUTIL += fate-sha fate-sha: libavutil/tests/sha$(EXESUF) -fate-sha: CMD = run libavutil/tests/sha +fate-sha: CMD = run libavutil/tests/sha$(EXESUF) FATE_LIBAVUTIL += fate-sha512 fate-sha512: libavutil/tests/sha512$(EXESUF) -fate-sha512: CMD = run libavutil/tests/sha512 +fate-sha512: CMD = run libavutil/tests/sha512$(EXESUF) FATE_LIBAVUTIL += fate-tree fate-tree: libavutil/tests/tree$(EXESUF) -fate-tree: CMD = run libavutil/tests/tree +fate-tree: CMD = run libavutil/tests/tree$(EXESUF) fate-tree: CMP = null FATE_LIBAVUTIL += fate-twofish fate-twofish: libavutil/tests/twofish$(EXESUF) -fate-twofish: CMD = run libavutil/tests/twofish +fate-twofish: CMD = run libavutil/tests/twofish$(EXESUF) fate-twofish: CMP = null FATE_LIBAVUTIL += fate-xtea fate-xtea: libavutil/tests/xtea$(EXESUF) -fate-xtea: CMD = run libavutil/tests/xtea +fate-xtea: CMD = run libavutil/tests/xtea$(EXESUF) FATE_LIBAVUTIL += fate-tea fate-tea: libavutil/tests/tea$(EXESUF) -fate-tea: CMD = run libavutil/tests/tea +fate-tea: CMD = run libavutil/tests/tea$(EXESUF) FATE_LIBAVUTIL += fate-opt fate-opt: libavutil/tests/opt$(EXESUF) -fate-opt: CMD = run libavutil/tests/opt +fate-opt: CMD = run libavutil/tests/opt$(EXESUF) FATE_LIBAVUTIL += $(FATE_LIBAVUTIL-yes) FATE-$(CONFIG_AVUTIL) += $(FATE_LIBAVUTIL) diff --git a/tests/fate/libswscale.mak b/tests/fate/libswscale.mak index e72fe590a..68eb159fe 100644 --- a/tests/fate/libswscale.mak +++ b/tests/fate/libswscale.mak @@ -1,6 +1,6 @@ FATE_LIBSWSCALE += fate-sws-pixdesc-query fate-sws-pixdesc-query: libswscale/tests/pixdesc_query$(EXESUF) -fate-sws-pixdesc-query: CMD = run libswscale/tests/pixdesc_query +fate-sws-pixdesc-query: CMD = run libswscale/tests/pixdesc_query$(EXESUF) FATE_LIBSWSCALE += $(FATE_LIBSWSCALE-yes) FATE-$(CONFIG_SWSCALE) += $(FATE_LIBSWSCALE) diff --git a/tests/fate/matroska.mak b/tests/fate/matroska.mak index 2747496e1..98a49a4d7 100644 --- a/tests/fate/matroska.mak +++ b/tests/fate/matroska.mak @@ -4,7 +4,7 @@ FATE_MATROSKA-$(call DEMMUX, MATROSKA, MATROSKA) += fate-matroska-remux fate-matroska-remux: CMD = md5pipe -i $(TARGET_SAMPLES)/vp9-test-vectors/vp90-2-2pass-akiyo.webm -color_trc 4 -c:v copy -fflags +bitexact -strict -2 -f matroska fate-matroska-remux: CMP = oneline -fate-matroska-remux: REF = 1ed49a4f2b6790357fac268938357353 +fate-matroska-remux: REF = e5457e5fa606d564a54914bd12f426c8 FATE_MATROSKA_FFPROBE-$(call ALLYES, MATROSKA_DEMUXER) += fate-matroska-spherical-mono fate-matroska-spherical-mono: CMD = run ffprobe$(PROGSSUF)$(EXESUF) -show_entries stream_side_data_list -select_streams v -v 0 $(TARGET_SAMPLES)/mkv/spherical.mkv diff --git a/tests/fate/microsoft.mak b/tests/fate/microsoft.mak index c450c0d8e..a2c3b626c 100644 --- a/tests/fate/microsoft.mak +++ b/tests/fate/microsoft.mak @@ -71,6 +71,12 @@ fate-vc1_sa20021: CMD = framecrc -i $(TARGET_SAMPLES)/vc1/SA20021.vc1 FATE_VC1-$(CONFIG_VC1_DEMUXER) += fate-vc1_ilaced_twomv fate-vc1_ilaced_twomv: CMD = framecrc -flags +bitexact -i $(TARGET_SAMPLES)/vc1/ilaced_twomv.vc1 +FATE_VC1-$(CONFIG_VC1T_DEMUXER) += fate-vc1test_smm0005 +fate-vc1test_smm0005: CMD = framecrc -i $(TARGET_SAMPLES)/vc1/SMM0005.rcv + +FATE_VC1-$(CONFIG_VC1T_DEMUXER) += fate-vc1test_smm0015 +fate-vc1test_smm0015: CMD = framecrc -i $(TARGET_SAMPLES)/vc1/SMM0015.rcv + FATE_VC1-$(CONFIG_MOV_DEMUXER) += fate-vc1-ism fate-vc1-ism: CMD = framecrc -i $(TARGET_SAMPLES)/isom/vc1-wmapro.ism -an diff --git a/tests/fate/mov.mak b/tests/fate/mov.mak index 9d7d62a02..8ed66cf13 100644 --- a/tests/fate/mov.mak +++ b/tests/fate/mov.mak @@ -6,6 +6,8 @@ FATE_MOV = fate-mov-3elist \ fate-mov-1elist-ends-last-bframe \ fate-mov-2elist-elist1-ends-bframe \ fate-mov-3elist-encrypted \ + fate-mov-frag-encrypted \ + fate-mov-tenc-only-encrypted \ fate-mov-invalid-elst-entry-count \ fate-mov-gpmf-remux \ fate-mov-440hz-10ms \ @@ -14,8 +16,10 @@ FATE_MOV = fate-mov-3elist \ fate-mov-frag-overlap \ fate-mov-bbi-elst-starts-b \ fate-mov-neg-firstpts-discard-frames \ + fate-mov-stream-shorter-than-movie \ FATE_MOV_FFPROBE = fate-mov-neg-firstpts-discard \ + fate-mov-neg-firstpts-discard-vorbis \ fate-mov-aac-2048-priming \ fate-mov-zombie \ fate-mov-init-nonkeyframe \ @@ -24,11 +28,15 @@ FATE_MOV_FFPROBE = fate-mov-neg-firstpts-discard \ fate-mov-guess-delay-1 \ fate-mov-guess-delay-2 \ fate-mov-guess-delay-3 \ + fate-mov-mp4-with-mov-in24-ver \ + +FATE_MOV_FASTSTART = fate-mov-faststart-4gb-overflow \ FATE_SAMPLES_AVCONV += $(FATE_MOV) FATE_SAMPLES_FFPROBE += $(FATE_MOV_FFPROBE) +FATE_SAMPLES_FASTSTART += $(FATE_MOV_FASTSTART) -fate-mov: $(FATE_MOV) $(FATE_MOV_FFPROBE) +fate-mov: $(FATE_MOV) $(FATE_MOV_FFPROBE) $(FATE_MOV_FASTSTART) # Make sure we handle edit lists correctly in normal cases. fate-mov-1elist-noctts: CMD = framemd5 -i $(TARGET_SAMPLES)/mov/mov-1elist-noctts.mov @@ -39,6 +47,12 @@ fate-mov-3elist-1ctts: CMD = framemd5 -i $(TARGET_SAMPLES)/mov/mov-3elist-1ctts. # Edit list with encryption fate-mov-3elist-encrypted: CMD = framemd5 -decryption_key 12345678901234567890123456789012 -i $(TARGET_SAMPLES)/mov/mov-3elist-encrypted.mov +# Fragmented encryption with senc boxes in movie fragments. +fate-mov-frag-encrypted: CMD = framemd5 -decryption_key 12345678901234567890123456789012 -i $(TARGET_SAMPLES)/mov/mov-frag-encrypted.mp4 + +# Full-sample encryption and constant IV using only tenc atom (no senc/saio/saiz). +fate-mov-tenc-only-encrypted: CMD = framemd5 -decryption_key 12345678901234567890123456789012 -i $(TARGET_SAMPLES)/mov/mov-tenc-only-encrypted.mp4 + # Makes sure that the CTTS is also modified when we fix avindex in mov.c while parsing edit lists. fate-mov-elist-starts-ctts-2ndsample: CMD = framemd5 -i $(TARGET_SAMPLES)/mov/mov-elist-starts-ctts-2ndsample.mov @@ -77,9 +91,16 @@ fate-mov-bbi-elst-starts-b: CMD = framemd5 -flags +bitexact -acodec aac_fixed -i # Makes sure that the stream start_time is not negative when the first packet is a DISCARD packet with negative timestamp. fate-mov-neg-firstpts-discard: CMD = run ffprobe$(PROGSSUF)$(EXESUF) -show_entries stream=start_time -bitexact $(TARGET_SAMPLES)/mov/mov_neg_first_pts_discard.mov +# Makes sure that the VORBIS audio stream start_time is not negative when the first few packets are DISCARD packets +# with negative timestamps (skip_samples is not set for Vorbis, so ffmpeg computes start_time as negative if not specified by demuxer). +fate-mov-neg-firstpts-discard-vorbis: CMD = run ffprobe$(PROGSSUF)$(EXESUF) -show_entries stream=start_time -bitexact $(TARGET_SAMPLES)/mov/mov_neg_first_pts_discard_vorbis.mp4 + # Makes sure that expected frames are generated for mov_neg_first_pts_discard.mov with -vsync 1 fate-mov-neg-firstpts-discard-frames: CMD = framemd5 -flags +bitexact -i $(TARGET_SAMPLES)/mov/mov_neg_first_pts_discard.mov -vsync 1 +# Makes sure that no frame is dropped/duplicated with fps filter due to start_time / duration miscalculations. +fate-mov-stream-shorter-than-movie: CMD = framemd5 -flags +bitexact -i $(TARGET_SAMPLES)/mov/mov_stream_shorter_than_movie.mov -vf fps=fps=24 -an + fate-mov-aac-2048-priming: CMD = run ffprobe$(PROGSSUF)$(EXESUF) -show_packets -print_format compact $(TARGET_SAMPLES)/mov/aac-2048-priming.mov fate-mov-zombie: CMD = run ffprobe$(PROGSSUF)$(EXESUF) -show_streams -show_packets -show_frames -bitexact -print_format compact $(TARGET_SAMPLES)/mov/white_zombie_scrunch-part.mov @@ -97,3 +118,9 @@ fate-mov-gpmf-remux: REF = 8f48e435ee1f6b7e173ea756141eabf3 fate-mov-guess-delay-1: CMD = run ffprobe$(PROGSSUF)$(EXESUF) -show_entries stream=has_b_frames -select_streams v $(TARGET_SAMPLES)/h264/h264_3bf_nopyramid_nobsrestriction.mp4 fate-mov-guess-delay-2: CMD = run ffprobe$(PROGSSUF)$(EXESUF) -show_entries stream=has_b_frames -select_streams v $(TARGET_SAMPLES)/h264/h264_3bf_pyramid_nobsrestriction.mp4 fate-mov-guess-delay-3: CMD = run ffprobe$(PROGSSUF)$(EXESUF) -show_entries stream=has_b_frames -select_streams v $(TARGET_SAMPLES)/h264/h264_4bf_pyramid_nobsrestriction.mp4 + +fate-mov-faststart-4gb-overflow: CMD = run tools/qt-faststart$(EXESUF) $(TARGET_SAMPLES)/mov/faststart-4gb-overflow.mov faststart-4gb-overflow-output.mov > /dev/null ; do_md5sum faststart-4gb-overflow-output.mov | cut -d " " -f1 ; rm faststart-4gb-overflow-output.mov +fate-mov-faststart-4gb-overflow: CMP = oneline +fate-mov-faststart-4gb-overflow: REF = bc875921f151871e787c4b4023269b29 + +fate-mov-mp4-with-mov-in24-ver: CMD = run ffprobe$(PROGSSUF)$(EXESUF) -show_entries stream=codec_name -select_streams 1 $(TARGET_SAMPLES)/mov/mp4-with-mov-in24-ver.mp4 diff --git a/tests/fate/mpegts.mak b/tests/fate/mpegts.mak index 2b128492e..bbcbfc47b 100644 --- a/tests/fate/mpegts.mak +++ b/tests/fate/mpegts.mak @@ -15,6 +15,11 @@ fate-mpegts-probe-program: SRC = $(TARGET_SAMPLES)/mpegts/loewe.ts fate-mpegts-probe-program: CMD = run $(PROBE_CODEC_NAME_COMMAND) -select_streams p:769:v:0 -i "$(SRC)" +FATE_MPEGTS_PROBE-$(call DEMDEC, MPEGTS) += fate-mpegts-probe-pmt-merge +fate-mpegts-probe-pmt-merge: SRC = $(TARGET_SAMPLES)/mpegts/pmtchange.ts +fate-mpegts-probe-pmt-merge: CMD = run $(PROBE_CODEC_NAME_COMMAND) -merge_pmt_versions 1 -i "$(SRC)" + + FATE_SAMPLES_FFPROBE += $(FATE_MPEGTS_PROBE-yes) fate-mpegts: $(FATE_MPEGTS_PROBE-yes) diff --git a/tests/fate/mxf.mak b/tests/fate/mxf.mak index dce23d522..62e4ec01c 100644 --- a/tests/fate/mxf.mak +++ b/tests/fate/mxf.mak @@ -37,9 +37,22 @@ FATE_MXF_REEL_NAME-$(call ENCDEC2, MPEG2VIDEO, PCM_S16LE, MXF) += fate-mxf-reel_ fate-mxf-reel_name: $(TARGET_SAMPLES)/mxf/Sony-00001.mxf fate-mxf-reel_name: CMD = md5 -y -i $(TARGET_SAMPLES)/mxf/Sony-00001.mxf -c copy -timecode 00:00:00:00 -metadata "reel_name=test_reel" -fflags +bitexact -f mxf +FATE_MXF_USER_COMMENTS-$(call ENCDEC2, MPEG2VIDEO, PCM_S16LE, MXF) += fate-mxf-user-comments +fate-mxf-user-comments: $(TARGET_SAMPLES)/mxf/Sony-00001.mxf +fate-mxf-user-comments: CMD = md5 -y -i $(TARGET_SAMPLES)/mxf/Sony-00001.mxf -c copy -metadata "comment_test=value" -fflags +bitexact -f mxf + +FATE_MXF_D10_USER_COMMENTS-$(call ENCDEC2, MPEG2VIDEO, PCM_S16LE, MXF) += fate-mxf-d10-user-comments +fate-mxf-d10-user-comments: $(TARGET_SAMPLES)/mxf/Sony-00001.mxf +fate-mxf-d10-user-comments: CMD = md5 -y -i $(TARGET_SAMPLES)/mxf/Sony-00001.mxf -c copy -metadata "comment_test=value" -store_user_comments 1 -fflags +bitexact -f mxf_d10 + +FATE_MXF_OPATOM_USER_COMMENTS-$(call ENCDEC2, MPEG2VIDEO, PCM_S16LE, MXF) += fate-mxf-opatom-user-comments +fate-mxf-opatom-user-comments: $(TARGET_SAMPLES)/mxf/Sony-00001.mxf +fate-mxf-opatom-user-comments: CMD = md5 -y -i $(TARGET_SAMPLES)/mxf/Sony-00001.mxf -an -vcodec copy -metadata "comment_test=value" -fflags +bitexact -f mxf_opatom + FATE_MXF-$(CONFIG_MXF_DEMUXER) += $(FATE_MXF) FATE_SAMPLES_AVCONV += $(FATE_MXF-yes) $(FATE_MXF_REEL_NAME-yes) +FATE_SAMPLES_AVCONV += $(FATE_MXF_USER_COMMENTS-yes) $(FATE_MXF_D10_USER_COMMENTS-yes) $(FATE_MXF_OPATOM_USER_COMMENTS-yes) FATE_SAMPLES_FFPROBE += $(FATE_MXF_PROBE-yes) -fate-mxf: $(FATE_MXF-yes) $(FATE_MXF_PROBE-yes) $(FATE_MXF_REEL_NAME-yes) +fate-mxf: $(FATE_MXF-yes) $(FATE_MXF_PROBE-yes) $(FATE_MXF_REEL_NAME-yes) $(FATE_MXF_USER_COMMENTS-yes) $(FATE_MXF_D10_USER_COMMENTS-yes) $(FATE_MXF_OPATOM_USER_COMMENTS-yes) diff --git a/tests/fate/opus.mak b/tests/fate/opus.mak index 7f289455c..c50d88f5e 100644 --- a/tests/fate/opus.mak +++ b/tests/fate/opus.mak @@ -36,6 +36,7 @@ fate-opus-testvector09: CMP_TARGET = 0 fate-opus-testvector10: CMP_TARGET = 38 fate-opus-testvector11: CMP_TARGET = 0 fate-opus-testvector12: CMP_TARGET = 160 +fate-opus-tron.6ch.tinypkts: CMP_SHIFT = 1440 fate-opus-tron.6ch.tinypkts: CMP_TARGET = 0 $(FATE_OPUS_CELT): CMP = oneoff diff --git a/tests/fate/pixfmt.mak b/tests/fate/pixfmt.mak new file mode 100644 index 000000000..46fd888ac --- /dev/null +++ b/tests/fate/pixfmt.mak @@ -0,0 +1,28 @@ +FATE_PIXFMT-$(CONFIG_SCALE_FILTER) = bgr24 \ + gray \ + monob \ + monow \ + rgb24 \ + rgb32 \ + rgb555 \ + rgb565 \ + yuv410p \ + yuv411p \ + yuv420p \ + yuv422p \ + yuv440p \ + yuv444p \ + yuvj420p \ + yuvj422p \ + yuvj440p \ + yuvj444p \ + yuyv422 \ + +FATE_PIXFMT := $(FATE_PIXFMT-yes:%=fate-pixfmt-%) + +$(FATE_PIXFMT): CMD = pixfmt_conversion +$(FATE_PIXFMT): REF = $(SRC_PATH)/tests/ref/pixfmt/$(@:fate-pixfmt-%=%) +$(FATE_PIXFMT): $(VREF) + +FATE_AVCONV += $(FATE_PIXFMT) +fate-pixfmt: $(FATE_PIXFMT) diff --git a/tests/fate/prores.mak b/tests/fate/prores.mak index f7f52ca7f..b7fcc7449 100644 --- a/tests/fate/prores.mak +++ b/tests/fate/prores.mak @@ -15,8 +15,14 @@ fate-prores-422: CMD = framecrc -flags +bitexact -i $(TARGET_SAMPLES)/pror fate-prores-422_hq: CMD = framecrc -flags +bitexact -i $(TARGET_SAMPLES)/prores/Sequence_1-Apple_ProRes_422_HQ.mov -pix_fmt yuv422p10le fate-prores-422_lt: CMD = framecrc -flags +bitexact -i $(TARGET_SAMPLES)/prores/Sequence_1-Apple_ProRes_422_LT.mov -pix_fmt yuv422p10le fate-prores-422_proxy: CMD = framecrc -flags +bitexact -i $(TARGET_SAMPLES)/prores/Sequence_1-Apple_ProRes_422_Proxy.mov -pix_fmt yuv422p10le -fate-prores-alpha: CMD = framecrc -flags +bitexact -i $(TARGET_SAMPLES)/prores/Sequence_1-Apple_ProRes_with_Alpha.mov -pix_fmt yuva444p10le -fate-prores-alpha_skip: CMD = framecrc -flags +bitexact -skip_alpha 1 -i $(TARGET_SAMPLES)/prores/Sequence_1-Apple_ProRes_with_Alpha.mov -pix_fmt yuv444p10le -fate-prores-transparency: CMD = framecrc -flags +bitexact -i $(TARGET_SAMPLES)/prores/prores4444_with_transparency.mov -pix_fmt yuva444p10le -fate-prores-transparency_skip: CMD = framecrc -flags +bitexact -skip_alpha 1 -i $(TARGET_SAMPLES)/prores/prores4444_with_transparency.mov -pix_fmt yuv444p10le +fate-prores-alpha: CMD = framecrc -flags +bitexact -i $(TARGET_SAMPLES)/prores/Sequence_1-Apple_ProRes_with_Alpha.mov -pix_fmt yuva444p12le +fate-prores-alpha_skip: CMD = framecrc -flags +bitexact -skip_alpha 1 -i $(TARGET_SAMPLES)/prores/Sequence_1-Apple_ProRes_with_Alpha.mov -pix_fmt yuv444p12le +fate-prores-transparency: CMD = framecrc -flags +bitexact -i $(TARGET_SAMPLES)/prores/prores4444_with_transparency.mov -pix_fmt yuva444p12le +fate-prores-transparency_skip: CMD = framecrc -flags +bitexact -skip_alpha 1 -i $(TARGET_SAMPLES)/prores/prores4444_with_transparency.mov -pix_fmt yuv444p12le fate-prores-gray: CMD = framecrc -flags +bitexact -c:a aac_fixed -i $(TARGET_SAMPLES)/prores/gray.mov -pix_fmt yuv422p10le + +#Test bsf prores-metadata +FATE_PRORES_METADATA_BSF += fate-prores-metadata +fate-prores-metadata: CMD = md5 -i $(TARGET_SAMPLES)/prores/Sequence_1-Apple_ProRes_422_Proxy.mov -c:v copy -bsf:v prores_metadata=color_primaries=bt470bg:color_trc=bt709:colorspace=smpte170m -bitexact -f mov + +FATE_SAMPLES_FFMPEG-$(call ALLYES, MOV_DEMUXER PRORES_METADATA_BSF) += $(FATE_PRORES_METADATA_BSF) diff --git a/tests/fate/qtrle.mak b/tests/fate/qtrle.mak index 774a81652..1f26ffea7 100644 --- a/tests/fate/qtrle.mak +++ b/tests/fate/qtrle.mak @@ -17,7 +17,7 @@ FATE_QTRLE += fate-qtrle-24bit fate-qtrle-24bit: CMD = framecrc -i $(TARGET_SAMPLES)/qtrle/aletrek-rle.mov FATE_QTRLE += fate-qtrle-32bit -fate-qtrle-32bit: CMD = framecrc -i $(TARGET_SAMPLES)/qtrle/ultra_demo_720_480_32bpp_rle.mov -pix_fmt rgb24 +fate-qtrle-32bit: CMD = framecrc -i $(TARGET_SAMPLES)/qtrle/ultra_demo_720_480_32bpp_rle.mov -pix_fmt bgra FATE_SAMPLES_AVCONV-$(call DEMDEC, MOV, QTRLE) += $(FATE_QTRLE) fate-qtrle: $(FATE_QTRLE) diff --git a/tests/fate/seek.mak b/tests/fate/seek.mak index 6a9f843d8..a15c9e919 100644 --- a/tests/fate/seek.mak +++ b/tests/fate/seek.mak @@ -162,13 +162,13 @@ FATE_SAMPLES_SEEK += $(FATE_SEEK_VSYNTH_LENA-yes:%=fate-seek-vsynth_lena-%) # files from fate-lavf FATE_SEEK_LAVF-$(call ENCDEC, PCM_S16BE, AIFF) += aiff -FATE_SEEK_LAVF-$(call ENCDEC, PCM_ALAW, PCM_ALAW) += alaw +FATE_SEEK_LAVF-$(call ENCDEC, PCM_ALAW, PCM_ALAW) += al FATE_SEEK_LAVF-$(call ENCDEC2, MSMPEG4V3, MP2, ASF) += asf FATE_SEEK_LAVF-$(call ENCDEC, PCM_S16BE, AU) += au FATE_SEEK_LAVF-$(call ENCDEC2, MPEG4, MP2, AVI) += avi FATE_SEEK_LAVF-$(call ENCDEC, BMP, IMAGE2) += bmp -FATE_SEEK_LAVF-$(call ENCDEC2, DVVIDEO, PCM_S16LE, AVI) += dv_fmt -FATE_SEEK_LAVF-$(call ENCDEC, FLV, FLV) += flv_fmt +FATE_SEEK_LAVF-$(call ENCDEC2, DVVIDEO, PCM_S16LE, AVI) += dv +FATE_SEEK_LAVF-$(call ENCDEC, FLV, FLV) += flv FATE_SEEK_LAVF-$(call ENCDEC, GIF, IMAGE2) += gif FATE_SEEK_LAVF-$(call ENCDEC2, MPEG2VIDEO, PCM_S16LE, GXF) += gxf FATE_SEEK_LAVF-$(call ENCDEC, MJPEG, IMAGE2) += jpg @@ -176,7 +176,7 @@ FATE_SEEK_LAVF-$(call ENCDEC2, MPEG4, MP2, MATROSKA) += mkv FATE_SEEK_LAVF-$(call ENCDEC, ADPCM_YAMAHA, MMF) += mmf FATE_SEEK_LAVF-$(call ENCDEC2, MPEG4, PCM_ALAW, MOV) += mov FATE_SEEK_LAVF-$(call ENCDEC2, MPEG1VIDEO, MP2, MPEG1SYSTEM MPEGPS) += mpg -FATE_SEEK_LAVF-$(call ENCDEC, PCM_MULAW, PCM_MULAW) += mulaw +FATE_SEEK_LAVF-$(call ENCDEC, PCM_MULAW, PCM_MULAW) += ul FATE_SEEK_LAVF-$(call ENCDEC2, MPEG2VIDEO, PCM_S16LE, MXF) += mxf FATE_SEEK_LAVF-$(call ENCDEC2, MPEG2VIDEO, PCM_S16LE, MXF_D10 MXF) += mxf_d10 FATE_SEEK_LAVF-$(call ENCDEC2, DVVIDEO, PCM_S16LE, MXF) += mxf_dv25 @@ -200,16 +200,16 @@ FATE_SEEK_LAVF-$(call ENCDEC2, MPEG2VIDEO, MP2, MPEGTS) += ts FATE_SEEK_LAVF-$(call ENCDEC, PCM_U8, VOC) += voc FATE_SEEK_LAVF-$(call ENCDEC, PCM_S16LE, WAV) += wav FATE_SEEK_LAVF-$(call ENCDEC, MP2, WTV) += wtv -FATE_SEEK_LAVF-$(CONFIG_YUV4MPEGPIPE_MUXER) += yuv4mpeg +FATE_SEEK_LAVF-$(CONFIG_YUV4MPEGPIPE_MUXER) += y4m -fate-seek-lavf-aiff: SRC = lavf/lavf.aif -fate-seek-lavf-alaw: SRC = lavf/lavf.al +fate-seek-lavf-aiff: SRC = lavf/lavf.aiff +fate-seek-lavf-al: SRC = lavf/lavf.al fate-seek-lavf-asf: SRC = lavf/lavf.asf fate-seek-lavf-au: SRC = lavf/lavf.au fate-seek-lavf-avi: SRC = lavf/lavf.avi fate-seek-lavf-bmp: SRC = images/bmp/%02d.bmp -fate-seek-lavf-dv_fmt: SRC = lavf/lavf.dv -fate-seek-lavf-flv_fmt: SRC = lavf/lavf.flv +fate-seek-lavf-dv: SRC = lavf/lavf.dv +fate-seek-lavf-flv: SRC = lavf/lavf.flv fate-seek-lavf-gif: SRC = lavf/lavf.gif fate-seek-lavf-gxf: SRC = lavf/lavf.gxf fate-seek-lavf-jpg: SRC = images/jpg/%02d.jpg @@ -217,7 +217,7 @@ fate-seek-lavf-mkv: SRC = lavf/lavf.mkv fate-seek-lavf-mmf: SRC = lavf/lavf.mmf fate-seek-lavf-mov: SRC = lavf/lavf.mov fate-seek-lavf-mpg: SRC = lavf/lavf.mpg -fate-seek-lavf-mulaw: SRC = lavf/lavf.ul +fate-seek-lavf-ul: SRC = lavf/lavf.ul fate-seek-lavf-mxf: SRC = lavf/lavf.mxf fate-seek-lavf-mxf_d10: SRC = lavf/lavf.mxf_d10 fate-seek-lavf-mxf_dv25: SRC = lavf/lavf.mxf_dv25 @@ -241,7 +241,7 @@ fate-seek-lavf-ts: SRC = lavf/lavf.ts fate-seek-lavf-voc: SRC = lavf/lavf.voc fate-seek-lavf-wav: SRC = lavf/lavf.wav fate-seek-lavf-wtv: SRC = lavf/lavf.wtv -fate-seek-lavf-yuv4mpeg: SRC = lavf/lavf.y4m +fate-seek-lavf-y4m: SRC = lavf/lavf.y4m FATE_SEEK += $(FATE_SEEK_LAVF-yes:%=fate-seek-lavf-%) diff --git a/tests/fate/segment.mak b/tests/fate/segment.mak new file mode 100644 index 000000000..ddefbed3b --- /dev/null +++ b/tests/fate/segment.mak @@ -0,0 +1,55 @@ +tests/data/mp4-to-ts.m3u8: TAG = GEN +tests/data/mp4-to-ts.m3u8: ffmpeg$(PROGSSUF)$(EXESUF) | tests/data + $(M)$(TARGET_EXEC) $(TARGET_PATH)/$< \ + -i $(TARGET_SAMPLES)/h264/interlaced_crop.mp4 \ + -f ssegment -segment_time 1 -map 0 -flags +bitexact -codec copy \ + -segment_list $(TARGET_PATH)/$@ -y $(TARGET_PATH)/tests/data/mp4-to-ts-%03d.ts 2>/dev/null + +tests/data/adts-to-mkv.m3u8: TAG = GEN +tests/data/adts-to-mkv.m3u8: ffmpeg$(PROGSSUF)$(EXESUF) | tests/data + $(M)$(TARGET_EXEC) $(TARGET_PATH)/$< \ + -i $(TARGET_SAMPLES)/audiomatch/tones_afconvert_16000_mono_aac_lc.m4a \ + -f segment -segment_time 1 -map 0 -flags +bitexact -codec copy -segment_format_options live=1 \ + -segment_list $(TARGET_PATH)/$@ -y $(TARGET_PATH)/tests/data/adts-to-mkv-%03d.mkv 2>/dev/null + +tests/data/adts-to-mkv-header.mkv: TAG = GEN +tests/data/adts-to-mkv-header.mkv: ffmpeg$(PROGSSUF)$(EXESUF) | tests/data + $(M)$(TARGET_EXEC) $(TARGET_PATH)/$< \ + -i $(TARGET_SAMPLES)/audiomatch/tones_afconvert_16000_mono_aac_lc.m4a \ + -f segment -segment_time 1 -map 0 -flags +bitexact -codec copy -segment_format_options live=1 \ + -segment_header_filename $(TARGET_PATH)/tests/data/adts-to-mkv-header.mkv \ + -y $(TARGET_PATH)/tests/data/adts-to-mkv-header-%03d.mkv 2>/dev/null + +tests/data/adts-to-mkv-header-%.mkv: tests/data/adts-to-mkv-header.mkv ; + +FATE_SEGMENT_PARTS += 000 001 002 + +tests/data/adts-to-mkv-cated-all.mkv: TAG = GEN +tests/data/adts-to-mkv-cated-all.mkv: tests/data/adts-to-mkv-header.mkv $(FATE_SEGMENT_PARTS:%=tests/data/adts-to-mkv-header-%.mkv) | tests/data + $(M)cat $^ >$@ + +tests/data/adts-to-mkv-cated-%.mkv: TAG = GEN +tests/data/adts-to-mkv-cated-%.mkv: tests/data/adts-to-mkv-header.mkv tests/data/adts-to-mkv-header-%.mkv | tests/data + $(M)cat $^ >$@ + +FATE_SEGMENT += fate-segment-mp4-to-ts +fate-segment-mp4-to-ts: tests/data/mp4-to-ts.m3u8 +fate-segment-mp4-to-ts: CMD = framecrc -flags +bitexact -i $(TARGET_PATH)/tests/data/mp4-to-ts.m3u8 -c copy +FATE_SEGMENT-$(call ALLYES, MOV_DEMUXER H264_MP4TOANNEXB_BSF MPEGTS_MUXER MATROSKA_DEMUXER SEGMENT_MUXER HLS_DEMUXER) += fate-segment-mp4-to-ts + +FATE_SEGMENT += fate-segment-adts-to-mkv +fate-segment-adts-to-mkv: tests/data/adts-to-mkv.m3u8 +fate-segment-adts-to-mkv: CMD = framecrc -flags +bitexact -i $(TARGET_PATH)/tests/data/adts-to-mkv.m3u8 -c copy +fate-segment-adts-to-mkv: REF = $(SRC_PATH)/tests/ref/fate/segment-adts-to-mkv-header-all +FATE_SEGMENT-$(call ALLYES, AAC_DEMUXER AAC_ADTSTOASC_BSF MATROSKA_MUXER MATROSKA_DEMUXER SEGMENT_MUXER HLS_DEMUXER) += fate-segment-adts-to-mkv + +FATE_SEGMENT_ALLPARTS = $(FATE_SEGMENT_PARTS) +FATE_SEGMENT_ALLPARTS += all +FATE_SEGMENT_SPLIT += $(FATE_SEGMENT_ALLPARTS:%=fate-segment-adts-to-mkv-header-%) +$(foreach N,$(FATE_SEGMENT_ALLPARTS),$(eval $(N:%=fate-segment-adts-to-mkv-header-%): tests/data/adts-to-mkv-cated-$(N).mkv)) +fate-segment-adts-to-mkv-header-%: CMD = framecrc -flags +bitexact -i $(TARGET_PATH)/tests/data/$(@:fate-segment-adts-to-mkv-header-%=adts-to-mkv-cated-%).mkv -c copy +FATE_SEGMENT-$(call ALLYES, AAC_DEMUXER AAC_ADTSTOASC_BSF MATROSKA_MUXER MATROSKA_DEMUXER SEGMENT_MUXER HLS_DEMUXER) += $(FATE_SEGMENT_SPLIT) + +FATE_SAMPLES_FFMPEG += $(FATE_SEGMENT-yes) + +fate-segment: $(FATE_SEGMENT-yes) diff --git a/tests/fate/vcodec.mak b/tests/fate/vcodec.mak index bbcf25d72..2705d2227 100644 --- a/tests/fate/vcodec.mak +++ b/tests/fate/vcodec.mak @@ -38,17 +38,25 @@ FATE_VCODEC-$(call ENCDEC, DNXHD, DNXHD) += dnxhd-720p \ FATE_VCODEC-$(call ENCDEC, VC2 DIRAC, MOV) += vc2-420p vc2-420p10 vc2-420p12 \ vc2-422p vc2-422p10 vc2-422p12 \ - vc2-444p vc2-444p10 vc2-444p12 -fate-vsynth1-vc2-%: FMT = mov -fate-vsynth1-vc2-%: ENCOPTS = -pix_fmt yuv$(@:fate-vsynth1-vc2-%=%) \ + vc2-444p vc2-444p10 vc2-444p12 \ + vc2-thaar vc2-t5_3 +fate-vsynth1-vc2-4%: FMT = mov +fate-vsynth1-vc2-4%: ENCOPTS = -pix_fmt yuv$(@:fate-vsynth1-vc2-%=%) \ -c:v vc2 -frames 5 -strict -1 -fate-vsynth2-vc2-%: FMT = mov -fate-vsynth2-vc2-%: ENCOPTS = -pix_fmt yuv$(@:fate-vsynth2-vc2-%=%) \ +fate-vsynth2-vc2-4%: FMT = mov +fate-vsynth2-vc2-4%: ENCOPTS = -pix_fmt yuv$(@:fate-vsynth2-vc2-%=%) \ -c:v vc2 -frames 5 -strict -1 -fate-vsynth_lena-vc2-%: FMT = mov -fate-vsynth_lena-vc2-%: ENCOPTS = -pix_fmt yuv$(@:fate-vsynth_lena-vc2-%=%) \ +fate-vsynth_lena-vc2-4%: FMT = mov +fate-vsynth_lena-vc2-4%: ENCOPTS = -pix_fmt yuv$(@:fate-vsynth_lena-vc2-%=%) \ -c:v vc2 -frames 5 -strict -1 +fate-vsynth1-vc2-t%: FMT = mov +fate-vsynth1-vc2-t%: ENCOPTS = -pix_fmt yuv422p10 -c:v vc2 -frames 5 -strict -1 -wavelet_type $(@:fate-vsynth1-vc2-t%=%) +fate-vsynth2-vc2-t%: FMT = mov +fate-vsynth2-vc2-t%: ENCOPTS = -pix_fmt yuv422p10 -c:v vc2 -frames 5 -strict -1 -wavelet_type $(@:fate-vsynth2-vc2-t%=%) +fate-vsynth_lena-vc2-t%: FMT = mov +fate-vsynth_lena-vc2-t%: ENCOPTS = -pix_fmt yuv422p10 -c:v vc2 -frames 5 -strict -1 -wavelet_type $(@:fate-vsynth_lena-vc2-t%=%) + fate-vsynth%-dnxhd-720p: ENCOPTS = -s hd720 -b 90M \ -pix_fmt yuv422p -frames 5 -qmax 8 fate-vsynth%-dnxhd-720p: FMT = dnxhd @@ -328,9 +336,21 @@ fate-vsynth%-mpng: CODEC = png FATE_VCODEC-$(call ENCDEC, MSVIDEO1, AVI) += msvideo1 -FATE_VCODEC-$(call ENCDEC, PRORES, MOV) += prores prores_ks +FATE_VCODEC-$(call ENCDEC, PRORES, MOV) += prores prores_int prores_444 prores_444_int prores_ks fate-vsynth%-prores: FMT = mov +fate-vsynth%-prores_int: CODEC = prores +fate-vsynth%-prores_int: ENCOPTS = -flags +ildct +fate-vsynth%-prores_int: FMT = mov + +fate-vsynth%-prores_444: CODEC = prores +fate-vsynth%-prores_444: ENCOPTS = -pix_fmt yuv444p10 +fate-vsynth%-prores_444: FMT = mov + +fate-vsynth%-prores_444_int: CODEC = prores +fate-vsynth%-prores_444_int: ENCOPTS = -pix_fmt yuv444p10 -flags +ildct +fate-vsynth%-prores_444_int: FMT = mov + fate-vsynth%-prores_ks: ENCOPTS = -profile hq fate-vsynth%-prores_ks: FMT = mov @@ -434,7 +454,7 @@ FATE_VSYNTH_LENA = $(FATE_VCODEC:%=fate-vsynth_lena-%) RESIZE_OFF = dnxhd-720p dnxhd-720p-rd dnxhd-720p-10bit dnxhd-1080i \ dv dv-411 dv-50 avui snow snow-hpel snow-ll vc2-420p \ vc2-420p10 vc2-420p12 vc2-422p vc2-422p10 vc2-422p12 \ - vc2-444p vc2-444p10 vc2-444p12 + vc2-444p vc2-444p10 vc2-444p12 vc2-thaar vc2-t5_3 # Incorrect parameters - usually size or color format restrictions INC_PAR_OFF = cinepak h261 h261-trellis h263 h263p h263-obmc msvideo1 \ roqvideo rv10 rv20 y41p qtrlegray diff --git a/tests/fate/video.mak b/tests/fate/video.mak index 43c3432c9..be1458c8b 100644 --- a/tests/fate/video.mak +++ b/tests/fate/video.mak @@ -259,7 +259,7 @@ fate-mxpeg: CMD = framecrc -idct simple -flags +bitexact -i $(TARGET_SAMPLES)/mx # FIXME dropped frames in this test because of coarse timebase FATE_NUV += fate-nuv-rtjpeg -fate-nuv-rtjpeg: CMD = framecrc -idct simple -i $(TARGET_SAMPLES)/nuv/Today.nuv -an +fate-nuv-rtjpeg: CMD = framecrc -idct simple -i $(TARGET_SAMPLES)/nuv/Today.nuv -an -r 1000 FATE_NUV += fate-nuv-rtjpeg-fh fate-nuv-rtjpeg-fh: CMD = framecrc -idct simple -i $(TARGET_SAMPLES)/nuv/rtjpeg_frameheader.nuv -an diff --git a/tests/fate/vpx.mak b/tests/fate/vpx.mak index 0be5aa2aa..3b3da18fe 100644 --- a/tests/fate/vpx.mak +++ b/tests/fate/vpx.mak @@ -34,6 +34,9 @@ fate-vp31: CMD = framecrc -flags +bitexact -i $(TARGET_SAMPLES)/vp3/vp31.avi FATE_SAMPLES_AVCONV += $(FATE_VP3-yes) fate-vp3: $(FATE_VP3-yes) +FATE_SAMPLES_AVCONV-$(call DEMDEC, AVI, VP4) += fate-vp4 +fate-vp4: CMD = framecrc -flags +bitexact -i $(TARGET_SAMPLES)/vp4/KTkvw8dg1J8.avi + FATE_SAMPLES_AVCONV-$(call DEMDEC, AVI, VP5) += fate-vp5 fate-vp5: CMD = framecrc -flags +bitexact -i $(TARGET_SAMPLES)/vp5/potter512-400-partial.avi -an diff --git a/tests/fate/wavpack.mak b/tests/fate/wavpack.mak index e4e8d4712..286e17f2a 100644 --- a/tests/fate/wavpack.mak +++ b/tests/fate/wavpack.mak @@ -91,12 +91,12 @@ fate-wavpack-matroskamode: CMD = md5 -i $(TARGET_SAMPLES)/wavpack/special/matros FATE_WAVPACK-$(call DEMMUX, WV, MATROSKA) += fate-wavpack-matroska_mux-mono fate-wavpack-matroska_mux-mono: CMD = md5pipe -i $(TARGET_SAMPLES)/wavpack/num_channels/mono_16bit_int.wv -c copy -fflags +bitexact -f matroska fate-wavpack-matroska_mux-mono: CMP = oneline -fate-wavpack-matroska_mux-mono: REF = 11773e2a518edc788475f3880d849230 +fate-wavpack-matroska_mux-mono: REF = c5a2b46d8b31c9c2e7bfb436f9d56f02 FATE_WAVPACK-$(call DEMMUX, WV, MATROSKA) += fate-wavpack-matroska_mux-61 fate-wavpack-matroska_mux-61: CMD = md5pipe -i $(TARGET_SAMPLES)/wavpack/num_channels/eva_2.22_6.1_16bit-partial.wv -c copy -fflags +bitexact -f matroska fate-wavpack-matroska_mux-61: CMP = oneline -fate-wavpack-matroska_mux-61: REF = 9641abdf596c10c2e21bd9b026d4bade +fate-wavpack-matroska_mux-61: REF = 22fc2a591be22657d19cab89ad6eef55 FATE_SAMPLES_AVCONV += $(FATE_WAVPACK-yes) fate-wavpack: $(FATE_WAVPACK-yes) diff --git a/tests/ref/acodec/alac b/tests/ref/acodec/alac index 7d6ebe8c8..da2a84a88 100644 --- a/tests/ref/acodec/alac +++ b/tests/ref/acodec/alac @@ -1,4 +1,4 @@ -8d9fb9f5433962e7880b666e6e2e428e *tests/data/fate/acodec-alac.mov +61b22c509780e86dfb2fd1be816d8c68 *tests/data/fate/acodec-alac.mov 389018 tests/data/fate/acodec-alac.mov 95e54b261530a1bcf6de6fe3b21dc5f6 *tests/data/fate/acodec-alac.out.wav stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 1058400/ 1058400 diff --git a/tests/ref/acodec/pcm-s16be b/tests/ref/acodec/pcm-s16be index a9b4593b5..2c051ce61 100644 --- a/tests/ref/acodec/pcm-s16be +++ b/tests/ref/acodec/pcm-s16be @@ -1,4 +1,4 @@ -d2515f35266ae6dba525c700bb76d893 *tests/data/fate/acodec-pcm-s16be.mov +5acf4268c4c4485ab79893f5e2f24e26 *tests/data/fate/acodec-pcm-s16be.mov 1059069 tests/data/fate/acodec-pcm-s16be.mov 95e54b261530a1bcf6de6fe3b21dc5f6 *tests/data/fate/acodec-pcm-s16be.out.wav stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 1058400/ 1058400 diff --git a/tests/ref/acodec/pcm-s24be b/tests/ref/acodec/pcm-s24be index 916aceb01..e36b503d7 100644 --- a/tests/ref/acodec/pcm-s24be +++ b/tests/ref/acodec/pcm-s24be @@ -1,4 +1,4 @@ -0f4a37a77619124f486f656f03c53d33 *tests/data/fate/acodec-pcm-s24be.mov +62e578b2e3e115a228e1ebfceeeb65c2 *tests/data/fate/acodec-pcm-s24be.mov 1588323 tests/data/fate/acodec-pcm-s24be.mov 95e54b261530a1bcf6de6fe3b21dc5f6 *tests/data/fate/acodec-pcm-s24be.out.wav stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 1058400/ 1058400 diff --git a/tests/ref/acodec/pcm-s32be b/tests/ref/acodec/pcm-s32be index 5a48bb275..128187362 100644 --- a/tests/ref/acodec/pcm-s32be +++ b/tests/ref/acodec/pcm-s32be @@ -1,4 +1,4 @@ -d6380bf54ac3e452c190ce302c264bf0 *tests/data/fate/acodec-pcm-s32be.mov +2a4d853ef4916ca5081fafe234d18596 *tests/data/fate/acodec-pcm-s32be.mov 2117527 tests/data/fate/acodec-pcm-s32be.mov 95e54b261530a1bcf6de6fe3b21dc5f6 *tests/data/fate/acodec-pcm-s32be.out.wav stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 1058400/ 1058400 diff --git a/tests/ref/acodec/pcm-s8 b/tests/ref/acodec/pcm-s8 index 14f4c8562..9e9f4172b 100644 --- a/tests/ref/acodec/pcm-s8 +++ b/tests/ref/acodec/pcm-s8 @@ -1,4 +1,4 @@ -00a9d90e06e8ecb79e5dd4c6c8460836 *tests/data/fate/acodec-pcm-s8.mov +65f02f9b48be05cf7b4d104c8a9d3566 *tests/data/fate/acodec-pcm-s8.mov 529853 tests/data/fate/acodec-pcm-s8.mov 652edf30f35ad89bf27bcc9d2f9c7b53 *tests/data/fate/acodec-pcm-s8.out.wav stddev: 147.89 PSNR: 52.93 MAXDIFF: 255 bytes: 1058400/ 1058400 diff --git a/tests/ref/fate/aac-autobsf-adtstoasc b/tests/ref/fate/aac-autobsf-adtstoasc index 9ca8e7ed9..9bf9dfe78 100644 --- a/tests/ref/fate/aac-autobsf-adtstoasc +++ b/tests/ref/fate/aac-autobsf-adtstoasc @@ -1,5 +1,5 @@ -b0375ba00bcbd55023a176255b8d4ba2 *tests/data/fate/aac-autobsf-adtstoasc.matroska -6728 tests/data/fate/aac-autobsf-adtstoasc.matroska +b09fc2f554712adbf84fe7899eb679d4 *tests/data/fate/aac-autobsf-adtstoasc.matroska +6695 tests/data/fate/aac-autobsf-adtstoasc.matroska #extradata 0: 2, 0x0030001c #tb 0: 1/1000 #media_type 0: audio diff --git a/tests/ref/fate/adtstoasc_ticket3715 b/tests/ref/fate/adtstoasc_ticket3715 index 96795a2ca..49fa3eb8d 100644 --- a/tests/ref/fate/adtstoasc_ticket3715 +++ b/tests/ref/fate/adtstoasc_ticket3715 @@ -1,4 +1,4 @@ -0221e04333e6ac432fa42960502f0d5a *tests/data/fate/adtstoasc_ticket3715.mov +4110be924e21846d0e174fac679b062e *tests/data/fate/adtstoasc_ticket3715.mov 33324 tests/data/fate/adtstoasc_ticket3715.mov #extradata 0: 2, 0x00340022 #tb 0: 1/44100 @@ -92,4 +92,4 @@ 0, 83968, 83968, 1024, 465, 0xeb3ce0af 0, 84992, 84992, 1024, 326, 0x7be4a667 0, 86016, 86016, 1024, 339, 0x2cf4a71f -0, 87040, 87040, 1028, 258, 0xd4007ad4 +0, 87040, 87040, 1024, 258, 0xd4007ad4 diff --git a/tests/ref/fate/api-h264-slice b/tests/ref/fate/api-h264-slice new file mode 100644 index 000000000..1d463d30a --- /dev/null +++ b/tests/ref/fate/api-h264-slice @@ -0,0 +1,309 @@ +#format: frame checksums +#version: 2 +#hash: MD5 +#tb 0: 1/30 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 352x288 +#sar 0: 128/117 +#stream#, dts, pts, duration, size, hash +0, 0, 0, 1, 152064, 28a2f99d62b553403fcffc1f680d5403 +0, 1, 1, 1, 152064, cd95f40841e08160ace0d64506f8adbf +0, 2, 2, 1, 152064, 32f37a1b3ddc2b8b0f6283f0c403a976 +0, 3, 3, 1, 152064, 643c0b0702072038578ef5ae2000c1a0 +0, 4, 4, 1, 152064, 8d9c9660705f7533e7f49f11693aedf9 +0, 5, 5, 1, 152064, 66a794f8a116c055451091e0e4cd911e +0, 6, 6, 1, 152064, 8ad529648796ae6da279de0b7ca34f72 +0, 7, 7, 1, 152064, 898ad4170eb740d713de254eb4bfe255 +0, 8, 8, 1, 152064, f96cfc1f00df10003e144529a5fae6c6 +0, 9, 9, 1, 152064, 0351a3b68dc87ba5963624e1461788da +0, 10, 10, 1, 152064, 6718e4086a0039584bcc37dcd4be6a67 +0, 11, 11, 1, 152064, fb4fec78d9434b9579b31f8ad0472762 +0, 12, 12, 1, 152064, ec2dcc547d84e15383dcee8462bb9d0c +0, 13, 13, 1, 152064, ea62711bf59b4d1d56cb9dbcb68a8eda +0, 14, 14, 1, 152064, 75b1cb899a9d9e695106f187c20b91f8 +0, 15, 15, 1, 152064, 44a13e4235c2ed3692af5ef698efe4d3 +0, 16, 16, 1, 152064, 6d5f1249d96573782fa95e9228d1ad0a +0, 17, 17, 1, 152064, fce8503dd9472fc7932ffbe21425d45a +0, 18, 18, 1, 152064, e93489a6b4c38d611493a3721aa994d7 +0, 19, 19, 1, 152064, 04580677a663ddba1b747c2ab0d598e6 +0, 20, 20, 1, 152064, a28cceb666c92eaecc3da3e092b83715 +0, 21, 21, 1, 152064, ba9ce0f84fb16c27453666265ad54e35 +0, 22, 22, 1, 152064, 946e014822ab2b45c52d3e08e7db97c2 +0, 23, 23, 1, 152064, b7a40ebb6ac72b322ccfca2568fa521a +0, 24, 24, 1, 152064, cb5a0564af00a00496950ad705a160ce +0, 25, 25, 1, 152064, dbad9e8e79c04b1df497884ec28e3a59 +0, 26, 26, 1, 152064, 3c748cdc0e6ec79ca72482e22f0c3ef8 +0, 27, 27, 1, 152064, 1740911da2ebbdc729cbbea0df466c44 +0, 28, 28, 1, 152064, 3b322e03fcc16d6a0dea651634ce0b40 +0, 29, 29, 1, 152064, a7fca405425015b85cb58ec1aece575b +0, 30, 30, 1, 152064, 2004eec0c923f1855b4b918e6dcb5e02 +0, 31, 31, 1, 152064, 20542f58f1622f58f3cbf4b2bf0b772f +0, 32, 32, 1, 152064, 8872f5cb900ed8d317f3abe50a147934 +0, 33, 33, 1, 152064, 774ba43dc0cd7932099e3e0633e25721 +0, 34, 34, 1, 152064, 4f2d9b7e6d115bd103ccd9945f85582f +0, 35, 35, 1, 152064, f53542ca7f6d5ec462770ffff3f4bfd0 +0, 36, 36, 1, 152064, 43b5f8c4e6dc3dc1acc903687bc90293 +0, 37, 37, 1, 152064, aa7d265ab285ded777a970debe6a08d5 +0, 38, 38, 1, 152064, 818ae082b3dd9557e04710d7cfd700be +0, 39, 39, 1, 152064, 44cfe472ccedf8a44d0b90c97932caae +0, 40, 40, 1, 152064, 5d2756c81c90bb10484e2e892fce0e0c +0, 41, 41, 1, 152064, c1b254a4b66dc9d769e10316976f5538 +0, 42, 42, 1, 152064, 03808a3f7b01293dbe6089b33e3dc103 +0, 43, 43, 1, 152064, 8c689a6143a8a89415d2e645bb0fe925 +0, 44, 44, 1, 152064, 24268cac7d78eefd8e247ec599e60b4f +0, 45, 45, 1, 152064, ac3195c57a3ebe3871992acfc3182e2f +0, 46, 46, 1, 152064, 8730a99fb5a2573475f61d4e7998ba44 +0, 47, 47, 1, 152064, 651042c34273096db82879fcdd91310d +0, 48, 48, 1, 152064, 972b47241098a9b6471ba6c8ccc2b83b +0, 49, 49, 1, 152064, e8e53022355e6bf7ac50d53bcb1bdc92 +0, 50, 50, 1, 152064, e5b003b04a88e0d60d446eb5b600cc66 +0, 51, 51, 1, 152064, 1c2317c071a33b0b465bbcea04411ddf +0, 52, 52, 1, 152064, 7bd53f4e852370aaeb6b0d042d24b94a +0, 53, 53, 1, 152064, 6ef30966b0d9c0d92b2350e2f45197a8 +0, 54, 54, 1, 152064, 354e2afff0d056193d6c4c2667c638d3 +0, 55, 55, 1, 152064, e67767e97f44c3ef80ea4acee41af0ff +0, 56, 56, 1, 152064, 32589395bf7d07c1c6df644d43b5bbba +0, 57, 57, 1, 152064, 2f2b56210b87142fa3620cce5c56af02 +0, 58, 58, 1, 152064, 599781773ace555c82ac591cc2acf8ec +0, 59, 59, 1, 152064, 2465cf6313dab6bda9171993ff6168de +0, 60, 60, 1, 152064, 54cc6c8a9b3fd95b9700d319c4a69297 +0, 61, 61, 1, 152064, 9e813429ebf7ee4e11fcd4976974fea0 +0, 62, 62, 1, 152064, fac0303897b4d1bd1a202fe0a7d1c6f7 +0, 63, 63, 1, 152064, accb382b99f2d27cefbc9f7ea315f80c +0, 64, 64, 1, 152064, b88711feaee9f7f84da34028b7e2cc81 +0, 65, 65, 1, 152064, 80549aebdcc5629dfc3bee8112536bac +0, 66, 66, 1, 152064, 9c63aa480b5d9937d839b809ba67eee2 +0, 67, 67, 1, 152064, 5e5a729c45a995ba2a97083fca69c9e9 +0, 68, 68, 1, 152064, 6b59c5d4460d78fa337b94b080e72215 +0, 69, 69, 1, 152064, 166d675f774f4f74dbce7e2728afd16c +0, 70, 70, 1, 152064, 3051629ff9281ea8879bce0ed62c1e71 +0, 71, 71, 1, 152064, c2ff4493434ca4fea45c724c10bcbe55 +0, 72, 72, 1, 152064, 907274f16ebeb7c09de8bc124c1fe586 +0, 73, 73, 1, 152064, 88efefc9fc00d88fbce20f4d74a55d25 +0, 74, 74, 1, 152064, 357bdbcb828c088b748022df9e47b9c7 +0, 75, 75, 1, 152064, 4550087923c1d4195ab536899a99d429 +0, 76, 76, 1, 152064, 2b07777d9109577eaedc87321dd3ff69 +0, 77, 77, 1, 152064, 4a377c552c62cba06d5285aa8478a540 +0, 78, 78, 1, 152064, a0e893c028e106c2394f0578f00ae88a +0, 79, 79, 1, 152064, c0db0e2ee3768d2e4e71581a2be30707 +0, 80, 80, 1, 152064, 954e0cd38b00ea2181b8c322511536f0 +0, 81, 81, 1, 152064, 53ff687670a2490ac3f94405014251b8 +0, 82, 82, 1, 152064, 64a588b7adbc560ec4ad6823c37e41c6 +0, 83, 83, 1, 152064, 60d65e899976214cd3b2b5abb10f2b83 +0, 84, 84, 1, 152064, 1bf0efef4b204a72d05b21c18a569585 +0, 85, 85, 1, 152064, 65d814be6b698ab1185f082c9c9d7de3 +0, 86, 86, 1, 152064, de26e7e663aaeb642e0a94776c5bf22c +0, 87, 87, 1, 152064, f7b0b259ccf21e59fcacd95945a013c3 +0, 88, 88, 1, 152064, 7f3185bb4dc3368733bd29c9aa9e08eb +0, 89, 89, 1, 152064, 3cedc14798d145fcdc8b8a3082de3b88 +0, 90, 90, 1, 152064, c5792622ca4a04d21e1f2c2b2ff692fe +0, 91, 91, 1, 152064, d13199fa94e53643902a8a26e33c9862 +0, 92, 92, 1, 152064, b380359e836896d7698a8dadfe6d6fdc +0, 93, 93, 1, 152064, 4c7c5f1f093f7bcaddf06068b9b1d2e5 +0, 94, 94, 1, 152064, 73f33e1eedea9aa5e6c3f2b636dd2c23 +0, 95, 95, 1, 152064, f0d2aad6477ace945f87b25cb44f3ff0 +0, 96, 96, 1, 152064, d90bddd7c2279bbd0266a26915202712 +0, 97, 97, 1, 152064, 0b377a48dea8fc2702395796808af63f +0, 98, 98, 1, 152064, ea0099179e806a9680f019446e39d125 +0, 99, 99, 1, 152064, a77dd3069c54b255e45b261f31be80d2 +0, 100, 100, 1, 152064, d362dcbe415329e713ff6ef9e6447d87 +0, 101, 101, 1, 152064, 15441bcb307ac24766ceba8db42f9413 +0, 102, 102, 1, 152064, 79b953e72d11d3fa6d6974e4b8b13392 +0, 103, 103, 1, 152064, ec8c35c829fac56ca8ae2f0160ae5d7f +0, 104, 104, 1, 152064, c104f8f1d17629b0449f4a2af2e40f73 +0, 105, 105, 1, 152064, 4661c4b3c2b1a03a8e23e7e88e974f22 +0, 106, 106, 1, 152064, 7cb48bae9841f67294b2e25a73d46a8e +0, 107, 107, 1, 152064, bddcb2c64a4257760f50714ec8c49243 +0, 108, 108, 1, 152064, c2123750802357c25c352f09bd1b1de2 +0, 109, 109, 1, 152064, 6eb5af4f3ad69cc88e0c08f6aa9bb034 +0, 110, 110, 1, 152064, 063991a633a051d6889f0fff41059e5f +0, 111, 111, 1, 152064, fa736839a01ad04fe08d437c7fa60a2d +0, 112, 112, 1, 152064, 85a43397c5a1defe15b61464c8d1457a +0, 113, 113, 1, 152064, da50c437613be59486012b69c7953f63 +0, 114, 114, 1, 152064, eb32e24757a98192928324d3a389a3dc +0, 115, 115, 1, 152064, 1bf511fb8245e3be71ebefdcf506575d +0, 116, 116, 1, 152064, 4479c195c4cd4111afe561a07c0f626d +0, 117, 117, 1, 152064, 0b1815f0c28bb55aae515a5dc3a34f3b +0, 118, 118, 1, 152064, 300d3c32442bd554384b3c804dd519ad +0, 119, 119, 1, 152064, 197df868e0488b8b12c0b42d8c4b2aec +0, 120, 120, 1, 152064, 03bce34c3214e0144a0928b9b9acc8e8 +0, 121, 121, 1, 152064, ba73a879b8fca5db4a354075b26ccb6a +0, 122, 122, 1, 152064, b1c34c6d2535bf1e7af3a6936d1627df +0, 123, 123, 1, 152064, 77d162995974428c5c7766ee5627eac1 +0, 124, 124, 1, 152064, fa4c70aa68850bcae2579046557c0b5f +0, 125, 125, 1, 152064, 63ce618e67f380000030c97db78ac4ae +0, 126, 126, 1, 152064, 7e32538d501127faf058792e83fbbe43 +0, 127, 127, 1, 152064, 61bc1d685553a97a7c3b0cbb3790faad +0, 128, 128, 1, 152064, 57f3b97e4a80ded30b9e8f12cfc8ff44 +0, 129, 129, 1, 152064, 31db51a64307ca6f1db866a01befa301 +0, 130, 130, 1, 152064, 59924d342068caf1ad7329b947279e2d +0, 131, 131, 1, 152064, 2f0f9dd3056cac40c17684bcccdf267d +0, 132, 132, 1, 152064, b00df17142f99bdc077cb2e4c5c8b747 +0, 133, 133, 1, 152064, e7c40734dea5433038b975666be7b21e +0, 134, 134, 1, 152064, 51d77965d3a9d431a2c409244c9bc465 +0, 135, 135, 1, 152064, 15b54bdc5e2098fe7c01ce689babe08b +0, 136, 136, 1, 152064, 3fa3284ae3f714ea197ad614bff7c5c5 +0, 137, 137, 1, 152064, c6512a19b7b1b29c05c7b825b41ab930 +0, 138, 138, 1, 152064, b13c8bc436186d47595dc69186f1f927 +0, 139, 139, 1, 152064, d5eff490784883a93dd3aaea08c46d5b +0, 140, 140, 1, 152064, a005ac77851ea3a44e261d9067ee835f +0, 141, 141, 1, 152064, 6706b74dc10c72f27e9f6341710e56ac +0, 142, 142, 1, 152064, 46479f86f53f55d2094354eb9bed78df +0, 143, 143, 1, 152064, 17f5cd040eb766ece29d1c1e283e9c20 +0, 144, 144, 1, 152064, 4f34c43eeeac2c751aac486ba42d9b9a +0, 145, 145, 1, 152064, 24c16b9d01c316305686af1a12f7be49 +0, 146, 146, 1, 152064, 9ae9b1f109fa3d02f226fefdaf395be6 +0, 147, 147, 1, 152064, eb98c1c6e473d8b53069206ffc69a9cb +0, 148, 148, 1, 152064, f0768d9cb981d277b70d1b3b928f4915 +0, 149, 149, 1, 152064, c1a5cef2bdb3f3b932a051c29d31f889 +0, 150, 150, 1, 152064, 8f75fb3a6f994b90999f8b0c664ad7c4 +0, 151, 151, 1, 152064, 3a778c9c86afaf03f2e60668d849e25b +0, 152, 152, 1, 152064, 4c3dd11965a2cf55790088a99289981a +0, 153, 153, 1, 152064, 763f810845e6f4e798a6edb6633f5506 +0, 154, 154, 1, 152064, 6b305b9d79151c1644c924d522091eea +0, 155, 155, 1, 152064, e981ce0e01f24eca2e89c7c81480fb07 +0, 156, 156, 1, 152064, 91349f36d44383dc1cd72f0a3f9c76ed +0, 157, 157, 1, 152064, 9a67f029ed2370983ff3e24d8c2c65d2 +0, 158, 158, 1, 152064, cf5717cb593fbafad6abf8bdb7ca2737 +0, 159, 159, 1, 152064, 7ece8c2497ca72e4f8e9eb69048391f8 +0, 160, 160, 1, 152064, 9dccce22ca32a7ec8890f77e4de1fa42 +0, 161, 161, 1, 152064, f418dc75e266c47ba84275741f0635cb +0, 162, 162, 1, 152064, aeddab213baab78ed0c44abb7409e291 +0, 163, 163, 1, 152064, a0b5e3c0616105580a310529ed71d072 +0, 164, 164, 1, 152064, e0e96da8724b472868634b6b145ebb2e +0, 165, 165, 1, 152064, bdaaf9623f5d329c8706e4850db0beea +0, 166, 166, 1, 152064, 6566ddd82da9096458e039caa7d56674 +0, 167, 167, 1, 152064, b882cb5f1c6059d338273e8fdb18e41e +0, 168, 168, 1, 152064, f9723e59ce02828e64c16d32216441b2 +0, 169, 169, 1, 152064, 98b5a843bf125eeae0240bde40016d6a +0, 170, 170, 1, 152064, 8958b81f8a028928c4b9a7024a4eebff +0, 171, 171, 1, 152064, 25a8acfdd14a472a8090d41626472070 +0, 172, 172, 1, 152064, 6faf859c0b264b6d76e0823c6045cebd +0, 173, 173, 1, 152064, 0774a3470360c37ede375d19aebe1844 +0, 174, 174, 1, 152064, 5dd921d4f05976fb6bbf5cc6996254e0 +0, 175, 175, 1, 152064, d03d789e3c439420a07e3e919ddd1cf0 +0, 176, 176, 1, 152064, 1fad139023f7d7022f8f65a6e31f68a9 +0, 177, 177, 1, 152064, 0c706070d649da054eeaf686d2e14a1d +0, 178, 178, 1, 152064, 51e4156b19bdc55e993d1956473827e3 +0, 179, 179, 1, 152064, e447458fd86c022852cedf56dc58f34f +0, 180, 180, 1, 152064, 59732caeb824f052044b4434ef564227 +0, 181, 181, 1, 152064, cf5ccf671ddc89e1f430878afb86fced +0, 182, 182, 1, 152064, e3e98f92e4cf8f0ccce27482407ebbf1 +0, 183, 183, 1, 152064, 089d236d04d1918b319524e3002d21c8 +0, 184, 184, 1, 152064, 7063afc35aa2c24b1e3dc781bb612af1 +0, 185, 185, 1, 152064, 902e5153028215ac60bf0f998673e3ca +0, 186, 186, 1, 152064, 2360fb2ed2b0e7c37a318fb7f9df7550 +0, 187, 187, 1, 152064, be0788a6a06906f57f7ad1e0e4c0aba7 +0, 188, 188, 1, 152064, db90ee89bbeefcd54b79f022ed9d62d9 +0, 189, 189, 1, 152064, 7237b5c1e6f182805d4e324e636f2a45 +0, 190, 190, 1, 152064, e5da5c0643e457087f54935cfa50f7c0 +0, 191, 191, 1, 152064, 89b5d462accdc4cfaed1e57de4589f39 +0, 192, 192, 1, 152064, b670710e2f897f20d83c42bcd0ee7d85 +0, 193, 193, 1, 152064, 9c7ceba12895f2a670e4a1498d28951c +0, 194, 194, 1, 152064, 4b426b0719a67bc228e1928e83b47b53 +0, 195, 195, 1, 152064, b2c646cd4d3b100619fd6e626ea8b3cb +0, 196, 196, 1, 152064, ad9abc825e1b87ec0defb1df032364e6 +0, 197, 197, 1, 152064, 21423e23c708f43a9d615bc2bc700d97 +0, 198, 198, 1, 152064, 14a42211968cd4b8416ebc0285eb02b3 +0, 199, 199, 1, 152064, a45eb0c4f6a9c5beeb90a292be71461e +0, 200, 200, 1, 152064, f9bfba991f0a0ea6bbfdde5d23bd8785 +0, 201, 201, 1, 152064, 49d33752288ddef86dc702652f688c75 +0, 202, 202, 1, 152064, 97b50290b4a1e2f31c704cc302fe89d8 +0, 203, 203, 1, 152064, c3006dcc89d2f45379c840c7dd5f7559 +0, 204, 204, 1, 152064, 4a861c22e63478ffe73571909da9a15f +0, 205, 205, 1, 152064, e7a8bff496059d3cd40470920fb26c75 +0, 206, 206, 1, 152064, 989d818e0d7d8eea14da209c37ad3e0b +0, 207, 207, 1, 152064, 1732c746805ca221c85fb5570911378d +0, 208, 208, 1, 152064, 60ece5f795f5756bef34ba84fb6fec2a +0, 209, 209, 1, 152064, 9fd355648ef40dd0e15c81554b111637 +0, 210, 210, 1, 152064, 2a3b9220b98ea648e395ab9ea12023d2 +0, 211, 211, 1, 152064, eea2a06e68196917ba2a754563953cd5 +0, 212, 212, 1, 152064, 3c2ec831a9802a968654df1bee81ca40 +0, 213, 213, 1, 152064, 590abeedce1cfa9df8a00d7ab9cf2c8e +0, 214, 214, 1, 152064, bc07f89391568a78854f99ad9fd62c49 +0, 215, 215, 1, 152064, 0bd866450376be96a85690595d96d909 +0, 216, 216, 1, 152064, 33483531a4d760bdc30a77d5de49aff7 +0, 217, 217, 1, 152064, b0294c6e784fa3f15532331063c5036f +0, 218, 218, 1, 152064, f4f3ba2781b2a9be3c2dd5b4c445e0d9 +0, 219, 219, 1, 152064, 8550626512e0602a1c53bfb8c51427d8 +0, 220, 220, 1, 152064, 0c2d0229196825910e5f487c33b45ef3 +0, 221, 221, 1, 152064, 93dbbed468f0012b921aa0b2b6751a70 +0, 222, 222, 1, 152064, 2f0d99dc6d4b5c65bc18946b1e6cdc4c +0, 223, 223, 1, 152064, fb25cbe655fc050bbcbfe9cc3fa06ffe +0, 224, 224, 1, 152064, 376d3f894957b3bac2308f2662ad5c82 +0, 225, 225, 1, 152064, 46b5c54ea38987b9e3d371a64d06300d +0, 226, 226, 1, 152064, 9bd24bc1a94aed633ff63aac5b720269 +0, 227, 227, 1, 152064, df0bb3f7724048f67c4a60a1dbb3d5e6 +0, 228, 228, 1, 152064, a9d1c8b8007ea61c0ab2f97b3cfc2aea +0, 229, 229, 1, 152064, fd5a4ccab51773b09edca30e665999e8 +0, 230, 230, 1, 152064, 0eaf8218244c9b2e78660cf923755557 +0, 231, 231, 1, 152064, 40f4fc64016fd148b14aea2da7652125 +0, 232, 232, 1, 152064, 6f075b312e9f7e1b4c3343441a9e1f7f +0, 233, 233, 1, 152064, 93f7523632abfe91fa701208aafdc29a +0, 234, 234, 1, 152064, 3c3ea7aa12a89df2309b76c22053b0ff +0, 235, 235, 1, 152064, 2181a1aec4278efa70dec025878d88c0 +0, 236, 236, 1, 152064, 35dffda6543fdf43ad182484564abda8 +0, 237, 237, 1, 152064, bf2b65551a8fcf3b1b4185e0ebfca2a7 +0, 238, 238, 1, 152064, 49fd2dd18ddbb7f005c3705910bff99f +0, 239, 239, 1, 152064, 9f6826599ebd45a1159e46d293fc8f7b +0, 240, 240, 1, 152064, 5b88b8ec1da51a165e2741f8a6b710ad +0, 241, 241, 1, 152064, a81229c0d464cc8d376f8b0153b50fc2 +0, 242, 242, 1, 152064, 07ef482c1c9967700a6cef5cdd010384 +0, 243, 243, 1, 152064, d4ebe4de6e096f7cccd5ae2be856e983 +0, 244, 244, 1, 152064, 6daf25ffb2c2baf02e483e84733fc37b +0, 245, 245, 1, 152064, d52f485c747e945bfe34aeeaaec4fe78 +0, 246, 246, 1, 152064, 408e5b502af7a10454af6f388e2722be +0, 247, 247, 1, 152064, 684d285dc9c08791ce16e02a1f65e22b +0, 248, 248, 1, 152064, 5de9b8f8678c6b7a1ff04f217ef8c0c3 +0, 249, 249, 1, 152064, b60f9e37dcfc3924adcfc96d08fb2656 +0, 250, 250, 1, 152064, 8975d551bb7c01cb520b5694e73d1809 +0, 251, 251, 1, 152064, af55f9897a3fa51eacdcebf3a21f5fe5 +0, 252, 252, 1, 152064, 10c21c5167cba09ce54f361e88e6e3c9 +0, 253, 253, 1, 152064, 8cb92c4a8d32fe00a92c5bd4a163cc45 +0, 254, 254, 1, 152064, 3d39fd1222c8421f0eed3c8249c3d772 +0, 255, 255, 1, 152064, 43c5629af47dc4fd659bffe481e84999 +0, 256, 256, 1, 152064, ad6d5a0f4d2d2738809b7f610f6da823 +0, 257, 257, 1, 152064, d2f0dbca68098d58468e94b84ef0fb8b +0, 258, 258, 1, 152064, 247487ae60500313df92dd0175ac4e0f +0, 259, 259, 1, 152064, cfbbabb4b8c93c87c221f76a155bb0fc +0, 260, 260, 1, 152064, c708254a644abc41788d717dd59b8baf +0, 261, 261, 1, 152064, fa710d87bddd1a65970c5618a8a0158f +0, 262, 262, 1, 152064, 31210937c8a67c6aafda2e03226b9770 +0, 263, 263, 1, 152064, ac518a56fc537de251f3d28d380e25cb +0, 264, 264, 1, 152064, afcb7642c336bcef9b605a40e518d305 +0, 265, 265, 1, 152064, 15fd29e16aaebae6f74e49455631c1f8 +0, 266, 266, 1, 152064, 938b90999b05595e9875c6d4f9836407 +0, 267, 267, 1, 152064, 2fe744b939902a5f4bb69e9243c55d08 +0, 268, 268, 1, 152064, a902057edac1638a1cd218fe5b88bfc2 +0, 269, 269, 1, 152064, 78087115b9600b5499866c127d175c0f +0, 270, 270, 1, 152064, 877c729e2d2b599dd6cac1f59f12e068 +0, 271, 271, 1, 152064, 77e6b4b761902fbe27fb0ff9eb6d02ac +0, 272, 272, 1, 152064, dd3ee373cb4935eca46947aedda3b991 +0, 273, 273, 1, 152064, b3ee6b4a18f6d20f9b9fd8dc9e8af90e +0, 274, 274, 1, 152064, 492afb7421667468fa95017c693ec47b +0, 275, 275, 1, 152064, 9abb912d8101de895b8f482c199934c2 +0, 276, 276, 1, 152064, 08ca372dfb5e90382f1b58345a0e51b1 +0, 277, 277, 1, 152064, 805559cb3f3385e7865df692336dba29 +0, 278, 278, 1, 152064, c5cc85e4d44010e048fd2013535d7180 +0, 279, 279, 1, 152064, ef9a05a7a4e0b5beff9a8119af44ebc7 +0, 280, 280, 1, 152064, e6983be0a0c1705cfede1e7476aad381 +0, 281, 281, 1, 152064, a4bb0c3d4deb17784b07d3713db05302 +0, 282, 282, 1, 152064, 0fd5bb9259e8c27aba7670b08cd9a26b +0, 283, 283, 1, 152064, 43d6df9fd672b13e2c59db924e9fe30b +0, 284, 284, 1, 152064, 3aaf3b87705c46495c9d1b9f4ea706bf +0, 285, 285, 1, 152064, 0d2ba631f5c716d9c5e5b2a75d3b6433 +0, 286, 286, 1, 152064, bf29cc016dce85e621aaa7647fae1544 +0, 287, 287, 1, 152064, 3374284a808d79e9be32bf3610b0fd17 +0, 288, 288, 1, 152064, ea3f305e76009f3bf2cd5014d339eafa +0, 289, 289, 1, 152064, 95ce7320a841a71b5a8871cef385ce41 +0, 290, 290, 1, 152064, 88613d96dbda681edab4ed41c3f08536 +0, 291, 291, 1, 152064, b9e9e9045b91c4f7917274088de64a5e +0, 292, 292, 1, 152064, e0b90055449e7403289a8dda9c02add0 +0, 293, 293, 1, 152064, 367ee1603fa7778dad3e99be8db779ee +0, 294, 294, 1, 152064, 6bb0eaa6140d673b452eee6ac6c262c2 +0, 295, 295, 1, 152064, 9af4ef919ae61e1597db1b9acd6af95a +0, 296, 296, 1, 152064, e8f29872e86e54ac26b5fb0a20f10d3e +0, 297, 297, 1, 152064, 09aaad95cd7d173bfe609b79440cbfc8 +0, 298, 298, 1, 152064, c03abe502be10f76e33d93e1c40cc674 +0, 299, 299, 1, 152064, 3e7e315be8aef281714a63f4cf086085 diff --git a/tests/ref/fate/api-mjpeg-codec-param b/tests/ref/fate/api-mjpeg-codec-param index 290f941ff..0815919d7 100644 --- a/tests/ref/fate/api-mjpeg-codec-param +++ b/tests/ref/fate/api-mjpeg-codec-param @@ -3,6 +3,7 @@ stream=0, decode=0 ab=0 bt=4000000 flags=0x00000000 + flags2=0x00000000 time_base=0/1 g=12 ar=0 @@ -56,14 +57,9 @@ stream=0, decode=0 aspect=180/180 sar=180/180 debug=0x00000000 - cmp=0 - subcmp=0 - mbcmp=0 - ildctcmp=8 dia_size=0 last_pred=0 preme=0 - precmp=0 pre_dia_size=0 subq=8 me_range=0 @@ -75,7 +71,6 @@ stream=0, decode=0 sc_threshold=0 nr=0 rc_init_occupancy=0 - flags2=0x00000000 threads=1 dc=0 nssew=8 @@ -88,6 +83,11 @@ stream=0, decode=0 skip_factor=0 skip_exp=0 skipcmp=13 + cmp=0 + subcmp=0 + mbcmp=0 + ildctcmp=8 + precmp=0 mblmin=236 mblmax=3658 mepc=256 @@ -138,11 +138,13 @@ stream=0, decode=0 max_pixels=2147483647 hwaccel_flags=0x00000001 extra_hw_frames=-1 + discard_damaged_percentage=95 stream=0, decode=1 b=0 ab=0 bt=4000000 flags=0x00000000 + flags2=0x00000000 time_base=0/1 g=12 ar=0 @@ -196,14 +198,9 @@ stream=0, decode=1 aspect=180/180 sar=180/180 debug=0x00000000 - cmp=0 - subcmp=0 - mbcmp=0 - ildctcmp=8 dia_size=0 last_pred=0 preme=0 - precmp=0 pre_dia_size=0 subq=8 me_range=0 @@ -215,7 +212,6 @@ stream=0, decode=1 sc_threshold=0 nr=0 rc_init_occupancy=0 - flags2=0x00000000 threads=1 dc=0 nssew=8 @@ -228,6 +224,11 @@ stream=0, decode=1 skip_factor=0 skip_exp=0 skipcmp=13 + cmp=0 + subcmp=0 + mbcmp=0 + ildctcmp=8 + precmp=0 mblmin=236 mblmax=3658 mepc=256 @@ -278,3 +279,4 @@ stream=0, decode=1 max_pixels=2147483647 hwaccel_flags=0x00000001 extra_hw_frames=-1 + discard_damaged_percentage=95 diff --git a/tests/ref/fate/api-png-codec-param b/tests/ref/fate/api-png-codec-param index f04ffa757..a47d0963d 100644 --- a/tests/ref/fate/api-png-codec-param +++ b/tests/ref/fate/api-png-codec-param @@ -3,6 +3,7 @@ stream=0, decode=0 ab=0 bt=4000000 flags=0x00000000 + flags2=0x00000000 time_base=0/1 g=12 ar=0 @@ -56,14 +57,9 @@ stream=0, decode=0 aspect=2835/2835 sar=2835/2835 debug=0x00000000 - cmp=0 - subcmp=0 - mbcmp=0 - ildctcmp=8 dia_size=0 last_pred=0 preme=0 - precmp=0 pre_dia_size=0 subq=8 me_range=0 @@ -75,7 +71,6 @@ stream=0, decode=0 sc_threshold=0 nr=0 rc_init_occupancy=0 - flags2=0x00000000 threads=1 dc=0 nssew=8 @@ -88,6 +83,11 @@ stream=0, decode=0 skip_factor=0 skip_exp=0 skipcmp=13 + cmp=0 + subcmp=0 + mbcmp=0 + ildctcmp=8 + precmp=0 mblmin=236 mblmax=3658 mepc=256 @@ -138,11 +138,13 @@ stream=0, decode=0 max_pixels=2147483647 hwaccel_flags=0x00000001 extra_hw_frames=-1 + discard_damaged_percentage=95 stream=0, decode=1 b=0 ab=0 bt=4000000 flags=0x00000000 + flags2=0x00000000 time_base=0/1 g=12 ar=0 @@ -196,14 +198,9 @@ stream=0, decode=1 aspect=2835/2835 sar=2835/2835 debug=0x00000000 - cmp=0 - subcmp=0 - mbcmp=0 - ildctcmp=8 dia_size=0 last_pred=0 preme=0 - precmp=0 pre_dia_size=0 subq=8 me_range=0 @@ -215,7 +212,6 @@ stream=0, decode=1 sc_threshold=0 nr=0 rc_init_occupancy=0 - flags2=0x00000000 threads=1 dc=0 nssew=8 @@ -228,6 +224,11 @@ stream=0, decode=1 skip_factor=0 skip_exp=0 skipcmp=13 + cmp=0 + subcmp=0 + mbcmp=0 + ildctcmp=8 + precmp=0 mblmin=236 mblmax=3658 mepc=256 @@ -278,3 +279,4 @@ stream=0, decode=1 max_pixels=2147483647 hwaccel_flags=0x00000001 extra_hw_frames=-1 + discard_damaged_percentage=95 diff --git a/tests/ref/fate/binsub-mksenc b/tests/ref/fate/binsub-mksenc index f247d9d22..4b13ef217 100644 --- a/tests/ref/fate/binsub-mksenc +++ b/tests/ref/fate/binsub-mksenc @@ -1 +1 @@ -f80f42e646fce972e73aa6d99dcfa470 +a5811caa0caba3a3f9a449b91569745c diff --git a/tests/ref/fate/binsub-movtextenc b/tests/ref/fate/binsub-movtextenc index 22ee85a2f..dacee0931 100644 --- a/tests/ref/fate/binsub-movtextenc +++ b/tests/ref/fate/binsub-movtextenc @@ -1 +1 @@ -af6a8f38d7c11d9af7823cc44554d2ad +66b25412f7ca699ee525ba162246edb6 diff --git a/tests/ref/fate/cbs-h264-sei-1 b/tests/ref/fate/cbs-h264-sei-1 new file mode 100644 index 000000000..2d1cb1fe7 --- /dev/null +++ b/tests/ref/fate/cbs-h264-sei-1 @@ -0,0 +1 @@ +5f537551b7dfab76a172f1aebb028986 diff --git a/tests/ref/fate/cbs-hevc-SLPPLP_A_VIDYO_2 b/tests/ref/fate/cbs-hevc-SLPPLP_A_VIDYO_2 new file mode 100644 index 000000000..5945221a9 --- /dev/null +++ b/tests/ref/fate/cbs-hevc-SLPPLP_A_VIDYO_2 @@ -0,0 +1 @@ +e5309cf061c06496f8fe2b8b313e6c39 diff --git a/tests/ref/fate/cbs-vp9-vp90-2-03-deltaq b/tests/ref/fate/cbs-vp9-vp90-2-03-deltaq new file mode 100644 index 000000000..db09cfd5e --- /dev/null +++ b/tests/ref/fate/cbs-vp9-vp90-2-03-deltaq @@ -0,0 +1 @@ +bb630ef560f83951fa6547a664fdb636 diff --git a/tests/ref/fate/cbs-vp9-vp90-2-05-resize b/tests/ref/fate/cbs-vp9-vp90-2-05-resize new file mode 100644 index 000000000..8f036bba8 --- /dev/null +++ b/tests/ref/fate/cbs-vp9-vp90-2-05-resize @@ -0,0 +1 @@ +6838422ebb45df353a2bad62b9aff8e9 diff --git a/tests/ref/fate/cbs-vp9-vp90-2-06-bilinear b/tests/ref/fate/cbs-vp9-vp90-2-06-bilinear new file mode 100644 index 000000000..f57945917 --- /dev/null +++ b/tests/ref/fate/cbs-vp9-vp90-2-06-bilinear @@ -0,0 +1 @@ +2ca9d012c7212e38f5e2727ac66ec6c5 diff --git a/tests/ref/fate/cbs-vp9-vp90-2-09-lf_deltas b/tests/ref/fate/cbs-vp9-vp90-2-09-lf_deltas new file mode 100644 index 000000000..e0b5686d0 --- /dev/null +++ b/tests/ref/fate/cbs-vp9-vp90-2-09-lf_deltas @@ -0,0 +1 @@ +78f5e46bfaecbcd62b9126697a0d97b7 diff --git a/tests/ref/fate/cbs-vp9-vp90-2-10-show-existing-frame b/tests/ref/fate/cbs-vp9-vp90-2-10-show-existing-frame new file mode 100644 index 000000000..4a4d75242 --- /dev/null +++ b/tests/ref/fate/cbs-vp9-vp90-2-10-show-existing-frame @@ -0,0 +1 @@ +eea9d10a696c6ed971e4fae9fb619b10 diff --git a/tests/ref/fate/cbs-vp9-vp90-2-10-show-existing-frame2 b/tests/ref/fate/cbs-vp9-vp90-2-10-show-existing-frame2 new file mode 100644 index 000000000..6da899911 --- /dev/null +++ b/tests/ref/fate/cbs-vp9-vp90-2-10-show-existing-frame2 @@ -0,0 +1 @@ +abf4c7d4be7d3576d96b6f92166b5894 diff --git a/tests/ref/fate/cbs-vp9-vp90-2-segmentation-aq-akiyo b/tests/ref/fate/cbs-vp9-vp90-2-segmentation-aq-akiyo new file mode 100644 index 000000000..12dfb10d4 --- /dev/null +++ b/tests/ref/fate/cbs-vp9-vp90-2-segmentation-aq-akiyo @@ -0,0 +1 @@ +86cd3750cc9a0672717643c9b9f87fd5 diff --git a/tests/ref/fate/cbs-vp9-vp90-2-segmentation-sf-akiyo b/tests/ref/fate/cbs-vp9-vp90-2-segmentation-sf-akiyo new file mode 100644 index 000000000..c2b1b8723 --- /dev/null +++ b/tests/ref/fate/cbs-vp9-vp90-2-segmentation-sf-akiyo @@ -0,0 +1 @@ +5d12fbe6220aae9e62b1d79785a83387 diff --git a/tests/ref/fate/cbs-vp9-vp90-2-tiling-pedestrian b/tests/ref/fate/cbs-vp9-vp90-2-tiling-pedestrian new file mode 100644 index 000000000..f9cab39bd --- /dev/null +++ b/tests/ref/fate/cbs-vp9-vp90-2-tiling-pedestrian @@ -0,0 +1 @@ +4c51f3c796baa7c2baa4b7ec0d011406 diff --git a/tests/ref/fate/cbs-vp9-vp91-2-04-yuv440 b/tests/ref/fate/cbs-vp9-vp91-2-04-yuv440 new file mode 100644 index 000000000..628993007 --- /dev/null +++ b/tests/ref/fate/cbs-vp9-vp91-2-04-yuv440 @@ -0,0 +1 @@ +293bdc92851ca1105e27f04737d8c5f3 diff --git a/tests/ref/fate/cbs-vp9-vp91-2-04-yuv444 b/tests/ref/fate/cbs-vp9-vp91-2-04-yuv444 new file mode 100644 index 000000000..628ea9a4d --- /dev/null +++ b/tests/ref/fate/cbs-vp9-vp91-2-04-yuv444 @@ -0,0 +1 @@ +911eafd8e442e646c5ce97d781757ca8 diff --git a/tests/ref/fate/cbs-vp9-vp92-2-20-10bit-yuv420 b/tests/ref/fate/cbs-vp9-vp92-2-20-10bit-yuv420 new file mode 100644 index 000000000..eeb7580d7 --- /dev/null +++ b/tests/ref/fate/cbs-vp9-vp92-2-20-10bit-yuv420 @@ -0,0 +1 @@ +16198c32c29228e0513004ed1bf6fcee diff --git a/tests/ref/fate/cbs-vp9-vp93-2-20-10bit-yuv422 b/tests/ref/fate/cbs-vp9-vp93-2-20-10bit-yuv422 new file mode 100644 index 000000000..b25bc1166 --- /dev/null +++ b/tests/ref/fate/cbs-vp9-vp93-2-20-10bit-yuv422 @@ -0,0 +1 @@ +4bceedef4aa6a663a09761971e43b5a8 diff --git a/tests/ref/fate/cbs-vp9-vp93-2-20-12bit-yuv444 b/tests/ref/fate/cbs-vp9-vp93-2-20-12bit-yuv444 new file mode 100644 index 000000000..8d122d137 --- /dev/null +++ b/tests/ref/fate/cbs-vp9-vp93-2-20-12bit-yuv444 @@ -0,0 +1 @@ +0f413b840633bfcfcc78b4c9fab933bf diff --git a/tests/ref/fate/concat-demuxer-extended-lavf-mxf b/tests/ref/fate/concat-demuxer-extended-lavf-mxf index c47f14faa..2fb5fce4b 100644 --- a/tests/ref/fate/concat-demuxer-extended-lavf-mxf +++ b/tests/ref/fate/concat-demuxer-extended-lavf-mxf @@ -1 +1 @@ -7e53f4c5cb0c9afda2771c9f0c697d9c *tests/data/fate/concat-demuxer-extended-lavf-mxf.ffprobe +a6fb9c37dc71cb43eb9664a8ae9f1c66 *tests/data/fate/concat-demuxer-extended-lavf-mxf.ffprobe diff --git a/tests/ref/fate/concat-demuxer-extended-lavf-mxf_d10 b/tests/ref/fate/concat-demuxer-extended-lavf-mxf_d10 index 75d386e3c..60d729b3d 100644 --- a/tests/ref/fate/concat-demuxer-extended-lavf-mxf_d10 +++ b/tests/ref/fate/concat-demuxer-extended-lavf-mxf_d10 @@ -1 +1 @@ -44810fc2eeee0072d9d7011b0d2afe59 *tests/data/fate/concat-demuxer-extended-lavf-mxf_d10.ffprobe +cb7c8eac6f8917e39658e1fa4a250da8 *tests/data/fate/concat-demuxer-extended-lavf-mxf_d10.ffprobe diff --git a/tests/ref/fate/concat-demuxer-simple1-lavf-mxf b/tests/ref/fate/concat-demuxer-simple1-lavf-mxf index 1174a1e18..d18e35b7b 100644 --- a/tests/ref/fate/concat-demuxer-simple1-lavf-mxf +++ b/tests/ref/fate/concat-demuxer-simple1-lavf-mxf @@ -1,124 +1,124 @@ -video|0|0|0.000000|-1|-0.040000|1|0.040000|N/A|N/A|24801|6144|K_ -audio|1|0|0.000000|0|0.000000|1920|0.040000|N/A|N/A|3840|31232|K_ -video|0|3|0.120000|0|0.000000|1|0.040000|N/A|N/A|16743|35840|__ -audio|1|1920|0.040000|1920|0.040000|1920|0.040000|N/A|N/A|3840|52736|K_ -video|0|1|0.040000|1|0.040000|1|0.040000|N/A|N/A|13812|57344|__ -audio|1|3840|0.080000|3840|0.080000|1920|0.040000|N/A|N/A|3840|71680|K_ -video|0|2|0.080000|2|0.080000|1|0.040000|N/A|N/A|13607|76288|__ -audio|1|5760|0.120000|5760|0.120000|1920|0.040000|N/A|N/A|3840|90112|K_ -video|0|6|0.240000|3|0.120000|1|0.040000|N/A|N/A|16158|94720|__ -audio|1|7680|0.160000|7680|0.160000|1920|0.040000|N/A|N/A|3840|111104|K_ -video|0|4|0.160000|4|0.160000|1|0.040000|N/A|N/A|13943|115712|__ -audio|1|9600|0.200000|9600|0.200000|1920|0.040000|N/A|N/A|3840|130048|K_ -video|0|5|0.200000|5|0.200000|1|0.040000|N/A|N/A|11223|134656|__ -audio|1|11520|0.240000|11520|0.240000|1920|0.040000|N/A|N/A|3840|145920|K_ -video|0|9|0.360000|6|0.240000|1|0.040000|N/A|N/A|20298|150528|__ -audio|1|13440|0.280000|13440|0.280000|1920|0.040000|N/A|N/A|3840|171008|K_ -video|0|7|0.280000|7|0.280000|1|0.040000|N/A|N/A|13341|175616|__ -audio|1|15360|0.320000|15360|0.320000|1920|0.040000|N/A|N/A|3840|189440|K_ -video|0|8|0.320000|8|0.320000|1|0.040000|N/A|N/A|12362|194048|__ -audio|1|17280|0.360000|17280|0.360000|1920|0.040000|N/A|N/A|3840|206848|K_ -video|0|12|0.480000|9|0.360000|1|0.040000|N/A|N/A|24786|211456|K_ -audio|1|19200|0.400000|19200|0.400000|1920|0.040000|N/A|N/A|3840|236544|K_ -video|0|10|0.400000|10|0.400000|1|0.040000|N/A|N/A|13377|241152|__ -audio|1|21120|0.440000|21120|0.440000|1920|0.040000|N/A|N/A|3840|254976|K_ -video|0|11|0.440000|11|0.440000|1|0.040000|N/A|N/A|15624|259584|__ -audio|1|23040|0.480000|23040|0.480000|1920|0.040000|N/A|N/A|3840|275456|K_ -video|0|15|0.600000|12|0.480000|1|0.040000|N/A|N/A|22597|280064|__ -audio|1|24960|0.520000|24960|0.520000|1920|0.040000|N/A|N/A|3840|303104|K_ -video|0|13|0.520000|13|0.520000|1|0.040000|N/A|N/A|15028|307712|__ -audio|1|26880|0.560000|26880|0.560000|1920|0.040000|N/A|N/A|3840|323072|K_ -video|0|14|0.560000|14|0.560000|1|0.040000|N/A|N/A|14014|327680|__ -audio|1|28800|0.600000|28800|0.600000|1920|0.040000|N/A|N/A|3840|342016|K_ -video|0|18|0.720000|15|0.600000|1|0.040000|N/A|N/A|20731|346624|__ -audio|1|30720|0.640000|30720|0.640000|1920|0.040000|N/A|N/A|3840|367616|K_ -video|0|16|0.640000|16|0.640000|1|0.040000|N/A|N/A|11946|372224|__ -audio|1|32640|0.680000|32640|0.680000|1920|0.040000|N/A|N/A|3840|384512|K_ -video|0|17|0.680000|17|0.680000|1|0.040000|N/A|N/A|14464|389120|__ -audio|1|34560|0.720000|34560|0.720000|1920|0.040000|N/A|N/A|3840|403968|K_ -video|0|21|0.840000|18|0.720000|1|0.040000|N/A|N/A|16189|408576|__ -audio|1|36480|0.760000|36480|0.760000|1920|0.040000|N/A|N/A|3840|424960|K_ -video|0|19|0.760000|19|0.760000|1|0.040000|N/A|N/A|10524|429568|__ -audio|1|38400|0.800000|38400|0.800000|1920|0.040000|N/A|N/A|3840|440320|K_ -video|0|20|0.800000|20|0.800000|1|0.040000|N/A|N/A|10599|444928|__ -audio|1|40320|0.840000|40320|0.840000|1920|0.040000|N/A|N/A|3840|455680|K_ -video|0|24|0.960000|21|0.840000|1|0.040000|N/A|N/A|24711|460288|K_ -audio|1|42240|0.880000|42240|0.880000|1920|0.040000|N/A|N/A|3840|485376|K_ -video|0|22|0.880000|22|0.880000|1|0.040000|N/A|N/A|10840|489984|__ -audio|1|44160|0.920000|44160|0.920000|1920|0.040000|N/A|N/A|3840|501248|K_ -video|0|23|0.920000|23|0.920000|1|0.040000|N/A|N/A|13350|505856|__ -audio|1|46080|0.960000|46080|0.960000|1920|0.040000|N/A|N/A|3840|519680|K_ -video|0|17|0.680000|14|0.560000|1|0.040000|N/A|N/A|24786|211456|K_ -audio|1|28800|0.600000|28800|0.600000|1920|0.040000|N/A|N/A|3840|236544|K_ -video|0|15|0.600000|15|0.600000|1|0.040000|N/A|N/A|13377|241152|__ -audio|1|30720|0.640000|30720|0.640000|1920|0.040000|N/A|N/A|3840|254976|K_ -video|0|16|0.640000|16|0.640000|1|0.040000|N/A|N/A|15624|259584|__ -audio|1|32640|0.680000|32640|0.680000|1920|0.040000|N/A|N/A|3840|275456|K_ -video|0|20|0.800000|17|0.680000|1|0.040000|N/A|N/A|22597|280064|__ -audio|1|34560|0.720000|34560|0.720000|1920|0.040000|N/A|N/A|3840|303104|K_ -video|0|18|0.720000|18|0.720000|1|0.040000|N/A|N/A|15028|307712|__ -audio|1|36480|0.760000|36480|0.760000|1920|0.040000|N/A|N/A|3840|323072|K_ -video|0|19|0.760000|19|0.760000|1|0.040000|N/A|N/A|14014|327680|__ -audio|1|38400|0.800000|38400|0.800000|1920|0.040000|N/A|N/A|3840|342016|K_ -video|0|23|0.920000|20|0.800000|1|0.040000|N/A|N/A|20731|346624|__ -audio|1|40320|0.840000|40320|0.840000|1920|0.040000|N/A|N/A|3840|367616|K_ -video|0|21|0.840000|21|0.840000|1|0.040000|N/A|N/A|11946|372224|__ -audio|1|42240|0.880000|42240|0.880000|1920|0.040000|N/A|N/A|3840|384512|K_ -video|0|22|0.880000|22|0.880000|1|0.040000|N/A|N/A|14464|389120|__ -audio|1|44160|0.920000|44160|0.920000|1920|0.040000|N/A|N/A|3840|403968|K_ -video|0|26|1.040000|23|0.920000|1|0.040000|N/A|N/A|16189|408576|__ -audio|1|46080|0.960000|46080|0.960000|1920|0.040000|N/A|N/A|3840|424960|K_ -video|0|24|0.960000|24|0.960000|1|0.040000|N/A|N/A|10524|429568|__ -audio|1|48000|1.000000|48000|1.000000|1920|0.040000|N/A|N/A|3840|440320|K_ -video|0|25|1.000000|25|1.000000|1|0.040000|N/A|N/A|10599|444928|__ -audio|1|49920|1.040000|49920|1.040000|1920|0.040000|N/A|N/A|3840|455680|K_ -video|0|29|1.160000|26|1.040000|1|0.040000|N/A|N/A|24711|460288|K_ -audio|1|51840|1.080000|51840|1.080000|1920|0.040000|N/A|N/A|3840|485376|K_ -video|0|27|1.080000|27|1.080000|1|0.040000|N/A|N/A|10840|489984|__ -audio|1|53760|1.120000|53760|1.120000|1920|0.040000|N/A|N/A|3840|501248|K_ -video|0|28|1.120000|28|1.120000|1|0.040000|N/A|N/A|13350|505856|__ -audio|1|55680|1.160000|55680|1.160000|1920|0.040000|N/A|N/A|3840|519680|K_ -video|0|25|1.000000|24|0.960000|1|0.040000|N/A|N/A|24801|6144|K_|1 +video|0|0|0.000000|-1|-0.040000|1|0.040000|N/A|N/A|24801|7168|K_ +audio|1|0|0.000000|0|0.000000|1920|0.040000|N/A|N/A|3840|32256|K_ +video|0|3|0.120000|0|0.000000|1|0.040000|N/A|N/A|16743|36864|__ +audio|1|1920|0.040000|1920|0.040000|1920|0.040000|N/A|N/A|3840|53760|K_ +video|0|1|0.040000|1|0.040000|1|0.040000|N/A|N/A|13812|58368|__ +audio|1|3840|0.080000|3840|0.080000|1920|0.040000|N/A|N/A|3840|72704|K_ +video|0|2|0.080000|2|0.080000|1|0.040000|N/A|N/A|13607|77312|__ +audio|1|5760|0.120000|5760|0.120000|1920|0.040000|N/A|N/A|3840|91136|K_ +video|0|6|0.240000|3|0.120000|1|0.040000|N/A|N/A|16158|95744|__ +audio|1|7680|0.160000|7680|0.160000|1920|0.040000|N/A|N/A|3840|112128|K_ +video|0|4|0.160000|4|0.160000|1|0.040000|N/A|N/A|13943|116736|__ +audio|1|9600|0.200000|9600|0.200000|1920|0.040000|N/A|N/A|3840|131072|K_ +video|0|5|0.200000|5|0.200000|1|0.040000|N/A|N/A|11223|135680|__ +audio|1|11520|0.240000|11520|0.240000|1920|0.040000|N/A|N/A|3840|146944|K_ +video|0|9|0.360000|6|0.240000|1|0.040000|N/A|N/A|20298|151552|__ +audio|1|13440|0.280000|13440|0.280000|1920|0.040000|N/A|N/A|3840|172032|K_ +video|0|7|0.280000|7|0.280000|1|0.040000|N/A|N/A|13341|176640|__ +audio|1|15360|0.320000|15360|0.320000|1920|0.040000|N/A|N/A|3840|190464|K_ +video|0|8|0.320000|8|0.320000|1|0.040000|N/A|N/A|12362|195072|__ +audio|1|17280|0.360000|17280|0.360000|1920|0.040000|N/A|N/A|3840|207872|K_ +video|0|12|0.480000|9|0.360000|1|0.040000|N/A|N/A|24786|212480|K_ +audio|1|19200|0.400000|19200|0.400000|1920|0.040000|N/A|N/A|3840|237568|K_ +video|0|10|0.400000|10|0.400000|1|0.040000|N/A|N/A|13377|242176|__ +audio|1|21120|0.440000|21120|0.440000|1920|0.040000|N/A|N/A|3840|256000|K_ +video|0|11|0.440000|11|0.440000|1|0.040000|N/A|N/A|15624|260608|__ +audio|1|23040|0.480000|23040|0.480000|1920|0.040000|N/A|N/A|3840|276480|K_ +video|0|15|0.600000|12|0.480000|1|0.040000|N/A|N/A|22597|281088|__ +audio|1|24960|0.520000|24960|0.520000|1920|0.040000|N/A|N/A|3840|304128|K_ +video|0|13|0.520000|13|0.520000|1|0.040000|N/A|N/A|15028|308736|__ +audio|1|26880|0.560000|26880|0.560000|1920|0.040000|N/A|N/A|3840|324096|K_ +video|0|14|0.560000|14|0.560000|1|0.040000|N/A|N/A|14014|328704|__ +audio|1|28800|0.600000|28800|0.600000|1920|0.040000|N/A|N/A|3840|343040|K_ +video|0|18|0.720000|15|0.600000|1|0.040000|N/A|N/A|20731|347648|__ +audio|1|30720|0.640000|30720|0.640000|1920|0.040000|N/A|N/A|3840|368640|K_ +video|0|16|0.640000|16|0.640000|1|0.040000|N/A|N/A|11946|373248|__ +audio|1|32640|0.680000|32640|0.680000|1920|0.040000|N/A|N/A|3840|385536|K_ +video|0|17|0.680000|17|0.680000|1|0.040000|N/A|N/A|14464|390144|__ +audio|1|34560|0.720000|34560|0.720000|1920|0.040000|N/A|N/A|3840|404992|K_ +video|0|21|0.840000|18|0.720000|1|0.040000|N/A|N/A|16189|409600|__ +audio|1|36480|0.760000|36480|0.760000|1920|0.040000|N/A|N/A|3840|425984|K_ +video|0|19|0.760000|19|0.760000|1|0.040000|N/A|N/A|10524|430592|__ +audio|1|38400|0.800000|38400|0.800000|1920|0.040000|N/A|N/A|3840|441344|K_ +video|0|20|0.800000|20|0.800000|1|0.040000|N/A|N/A|10599|445952|__ +audio|1|40320|0.840000|40320|0.840000|1920|0.040000|N/A|N/A|3840|456704|K_ +video|0|24|0.960000|21|0.840000|1|0.040000|N/A|N/A|24711|461312|K_ +audio|1|42240|0.880000|42240|0.880000|1920|0.040000|N/A|N/A|3840|486400|K_ +video|0|22|0.880000|22|0.880000|1|0.040000|N/A|N/A|10840|491008|__ +audio|1|44160|0.920000|44160|0.920000|1920|0.040000|N/A|N/A|3840|502272|K_ +video|0|23|0.920000|23|0.920000|1|0.040000|N/A|N/A|13350|506880|__ +audio|1|46080|0.960000|46080|0.960000|1920|0.040000|N/A|N/A|3840|520704|K_ +video|0|17|0.680000|14|0.560000|1|0.040000|N/A|N/A|24786|212480|K_ +audio|1|28800|0.600000|28800|0.600000|1920|0.040000|N/A|N/A|3840|237568|K_ +video|0|15|0.600000|15|0.600000|1|0.040000|N/A|N/A|13377|242176|__ +audio|1|30720|0.640000|30720|0.640000|1920|0.040000|N/A|N/A|3840|256000|K_ +video|0|16|0.640000|16|0.640000|1|0.040000|N/A|N/A|15624|260608|__ +audio|1|32640|0.680000|32640|0.680000|1920|0.040000|N/A|N/A|3840|276480|K_ +video|0|20|0.800000|17|0.680000|1|0.040000|N/A|N/A|22597|281088|__ +audio|1|34560|0.720000|34560|0.720000|1920|0.040000|N/A|N/A|3840|304128|K_ +video|0|18|0.720000|18|0.720000|1|0.040000|N/A|N/A|15028|308736|__ +audio|1|36480|0.760000|36480|0.760000|1920|0.040000|N/A|N/A|3840|324096|K_ +video|0|19|0.760000|19|0.760000|1|0.040000|N/A|N/A|14014|328704|__ +audio|1|38400|0.800000|38400|0.800000|1920|0.040000|N/A|N/A|3840|343040|K_ +video|0|23|0.920000|20|0.800000|1|0.040000|N/A|N/A|20731|347648|__ +audio|1|40320|0.840000|40320|0.840000|1920|0.040000|N/A|N/A|3840|368640|K_ +video|0|21|0.840000|21|0.840000|1|0.040000|N/A|N/A|11946|373248|__ +audio|1|42240|0.880000|42240|0.880000|1920|0.040000|N/A|N/A|3840|385536|K_ +video|0|22|0.880000|22|0.880000|1|0.040000|N/A|N/A|14464|390144|__ +audio|1|44160|0.920000|44160|0.920000|1920|0.040000|N/A|N/A|3840|404992|K_ +video|0|26|1.040000|23|0.920000|1|0.040000|N/A|N/A|16189|409600|__ +audio|1|46080|0.960000|46080|0.960000|1920|0.040000|N/A|N/A|3840|425984|K_ +video|0|24|0.960000|24|0.960000|1|0.040000|N/A|N/A|10524|430592|__ +audio|1|48000|1.000000|48000|1.000000|1920|0.040000|N/A|N/A|3840|441344|K_ +video|0|25|1.000000|25|1.000000|1|0.040000|N/A|N/A|10599|445952|__ +audio|1|49920|1.040000|49920|1.040000|1920|0.040000|N/A|N/A|3840|456704|K_ +video|0|29|1.160000|26|1.040000|1|0.040000|N/A|N/A|24711|461312|K_ +audio|1|51840|1.080000|51840|1.080000|1920|0.040000|N/A|N/A|3840|486400|K_ +video|0|27|1.080000|27|1.080000|1|0.040000|N/A|N/A|10840|491008|__ +audio|1|53760|1.120000|53760|1.120000|1920|0.040000|N/A|N/A|3840|502272|K_ +video|0|28|1.120000|28|1.120000|1|0.040000|N/A|N/A|13350|506880|__ +audio|1|55680|1.160000|55680|1.160000|1920|0.040000|N/A|N/A|3840|520704|K_ +video|0|25|1.000000|24|0.960000|1|0.040000|N/A|N/A|24801|7168|K_|1 Strings Metadata -audio|1|48000|1.000000|48000|1.000000|1920|0.040000|N/A|N/A|3840|31232|K_|1 +audio|1|48000|1.000000|48000|1.000000|1920|0.040000|N/A|N/A|3840|32256|K_|1 Strings Metadata -video|0|28|1.120000|25|1.000000|1|0.040000|N/A|N/A|16743|35840|__|1 +video|0|28|1.120000|25|1.000000|1|0.040000|N/A|N/A|16743|36864|__|1 Strings Metadata -audio|1|49920|1.040000|49920|1.040000|1920|0.040000|N/A|N/A|3840|52736|K_|1 +audio|1|49920|1.040000|49920|1.040000|1920|0.040000|N/A|N/A|3840|53760|K_|1 Strings Metadata -video|0|26|1.040000|26|1.040000|1|0.040000|N/A|N/A|13812|57344|__|1 +video|0|26|1.040000|26|1.040000|1|0.040000|N/A|N/A|13812|58368|__|1 Strings Metadata -audio|1|51840|1.080000|51840|1.080000|1920|0.040000|N/A|N/A|3840|71680|K_|1 +audio|1|51840|1.080000|51840|1.080000|1920|0.040000|N/A|N/A|3840|72704|K_|1 Strings Metadata -video|0|27|1.080000|27|1.080000|1|0.040000|N/A|N/A|13607|76288|__|1 +video|0|27|1.080000|27|1.080000|1|0.040000|N/A|N/A|13607|77312|__|1 Strings Metadata -audio|1|53760|1.120000|53760|1.120000|1920|0.040000|N/A|N/A|3840|90112|K_|1 +audio|1|53760|1.120000|53760|1.120000|1920|0.040000|N/A|N/A|3840|91136|K_|1 Strings Metadata -video|0|31|1.240000|28|1.120000|1|0.040000|N/A|N/A|16158|94720|__|1 +video|0|31|1.240000|28|1.120000|1|0.040000|N/A|N/A|16158|95744|__|1 Strings Metadata -audio|1|55680|1.160000|55680|1.160000|1920|0.040000|N/A|N/A|3840|111104|K_|1 +audio|1|55680|1.160000|55680|1.160000|1920|0.040000|N/A|N/A|3840|112128|K_|1 Strings Metadata -video|0|29|1.160000|29|1.160000|1|0.040000|N/A|N/A|13943|115712|__|1 +video|0|29|1.160000|29|1.160000|1|0.040000|N/A|N/A|13943|116736|__|1 Strings Metadata -audio|1|57600|1.200000|57600|1.200000|1920|0.040000|N/A|N/A|3840|130048|K_|1 +audio|1|57600|1.200000|57600|1.200000|1920|0.040000|N/A|N/A|3840|131072|K_|1 Strings Metadata -video|0|30|1.200000|30|1.200000|1|0.040000|N/A|N/A|11223|134656|__|1 +video|0|30|1.200000|30|1.200000|1|0.040000|N/A|N/A|11223|135680|__|1 Strings Metadata -audio|1|59520|1.240000|59520|1.240000|1920|0.040000|N/A|N/A|3840|145920|K_|1 +audio|1|59520|1.240000|59520|1.240000|1920|0.040000|N/A|N/A|3840|146944|K_|1 Strings Metadata -video|0|34|1.360000|31|1.240000|1|0.040000|N/A|N/A|20298|150528|__|1 +video|0|34|1.360000|31|1.240000|1|0.040000|N/A|N/A|20298|151552|__|1 Strings Metadata -audio|1|61440|1.280000|61440|1.280000|1920|0.040000|N/A|N/A|3840|171008|K_|1 +audio|1|61440|1.280000|61440|1.280000|1920|0.040000|N/A|N/A|3840|172032|K_|1 Strings Metadata -video|0|32|1.280000|32|1.280000|1|0.040000|N/A|N/A|13341|175616|__|1 +video|0|32|1.280000|32|1.280000|1|0.040000|N/A|N/A|13341|176640|__|1 Strings Metadata -audio|1|63360|1.320000|63360|1.320000|1920|0.040000|N/A|N/A|3840|189440|K_|1 +audio|1|63360|1.320000|63360|1.320000|1920|0.040000|N/A|N/A|3840|190464|K_|1 Strings Metadata -video|0|33|1.320000|33|1.320000|1|0.040000|N/A|N/A|12362|194048|__|1 +video|0|33|1.320000|33|1.320000|1|0.040000|N/A|N/A|12362|195072|__|1 Strings Metadata -audio|1|65280|1.360000|65280|1.360000|1920|0.040000|N/A|N/A|3840|206848|K_|1 +audio|1|65280|1.360000|65280|1.360000|1920|0.040000|N/A|N/A|3840|207872|K_|1 Strings Metadata -video|0|37|1.480000|34|1.360000|1|0.040000|N/A|N/A|24786|211456|K_|1 +video|0|37|1.480000|34|1.360000|1|0.040000|N/A|N/A|24786|212480|K_|1 Strings Metadata 0|mpeg2video|4|video|1/25|[0][0][0][0]|0x0000|352|288|0|0|1|1:1|11:9|yuv420p|8|tv|unknown|unknown|unknown|left|progressive|N/A|1|N/A|25/1|25/1|1/25|N/A|N/A|N/A|N/A|N/A|N/A|N/A|N/A|N/A|51|0|0|0|0|0|0|0|0|0|0|0|0|0x060A2B340101010501010D001300000000000000000000000000000000000001 1|pcm_s16le|unknown|audio|1/48000|[0][0][0][0]|0x0000|s16|48000|1|unknown|16|N/A|0/0|0/0|1/48000|0|0.000000|N/A|N/A|768000|N/A|N/A|N/A|N/A|50|0|0|0|0|0|0|0|0|0|0|0|0|0x060A2B340101010501010D001300000000000000000000000000000000000001 diff --git a/tests/ref/fate/concat-demuxer-simple1-lavf-mxf_d10 b/tests/ref/fate/concat-demuxer-simple1-lavf-mxf_d10 index bd0e5e2a7..e83d1bf84 100644 --- a/tests/ref/fate/concat-demuxer-simple1-lavf-mxf_d10 +++ b/tests/ref/fate/concat-demuxer-simple1-lavf-mxf_d10 @@ -1,82 +1,82 @@ -video|0|0|0.000000|0|0.000000|1|0.040000|N/A|N/A|150000|6144|K_ -audio|1|0|0.000000|0|0.000000|1920|0.040000|N/A|N/A|7680|156672|K_ -video|0|1|0.040000|1|0.040000|1|0.040000|N/A|N/A|150000|219136|K_ -audio|1|1920|0.040000|1920|0.040000|1920|0.040000|N/A|N/A|7680|369664|K_ -video|0|2|0.080000|2|0.080000|1|0.040000|N/A|N/A|150000|432128|K_ -audio|1|3840|0.080000|3840|0.080000|1920|0.040000|N/A|N/A|7680|582656|K_ -video|0|3|0.120000|3|0.120000|1|0.040000|N/A|N/A|150000|645120|K_ -audio|1|5760|0.120000|5760|0.120000|1920|0.040000|N/A|N/A|7680|795648|K_ -video|0|4|0.160000|4|0.160000|1|0.040000|N/A|N/A|150000|858112|K_ -audio|1|7680|0.160000|7680|0.160000|1920|0.040000|N/A|N/A|7680|1008640|K_ -video|0|5|0.200000|5|0.200000|1|0.040000|N/A|N/A|150000|1071104|K_ -audio|1|9600|0.200000|9600|0.200000|1920|0.040000|N/A|N/A|7680|1221632|K_ -video|0|6|0.240000|6|0.240000|1|0.040000|N/A|N/A|150000|1284096|K_ -audio|1|11520|0.240000|11520|0.240000|1920|0.040000|N/A|N/A|7680|1434624|K_ -video|0|7|0.280000|7|0.280000|1|0.040000|N/A|N/A|150000|1497088|K_ -audio|1|13440|0.280000|13440|0.280000|1920|0.040000|N/A|N/A|7680|1647616|K_ -video|0|8|0.320000|8|0.320000|1|0.040000|N/A|N/A|150000|1710080|K_ -audio|1|15360|0.320000|15360|0.320000|1920|0.040000|N/A|N/A|7680|1860608|K_ -video|0|9|0.360000|9|0.360000|1|0.040000|N/A|N/A|150000|1923072|K_ -audio|1|17280|0.360000|17280|0.360000|1920|0.040000|N/A|N/A|7680|2073600|K_ -video|0|10|0.400000|10|0.400000|1|0.040000|N/A|N/A|150000|2136064|K_ -audio|1|19200|0.400000|19200|0.400000|1920|0.040000|N/A|N/A|7680|2286592|K_ -video|0|11|0.440000|11|0.440000|1|0.040000|N/A|N/A|150000|2349056|K_ -audio|1|21120|0.440000|21120|0.440000|1920|0.040000|N/A|N/A|7680|2499584|K_ -video|0|12|0.480000|12|0.480000|1|0.040000|N/A|N/A|150000|2562048|K_ -audio|1|23040|0.480000|23040|0.480000|1920|0.040000|N/A|N/A|7680|2712576|K_ -video|0|13|0.520000|13|0.520000|1|0.040000|N/A|N/A|150000|2775040|K_ -audio|1|24960|0.520000|24960|0.520000|1920|0.040000|N/A|N/A|7680|2925568|K_ -video|0|14|0.560000|14|0.560000|1|0.040000|N/A|N/A|150000|2988032|K_ -audio|1|26880|0.560000|26880|0.560000|1920|0.040000|N/A|N/A|7680|3138560|K_ -video|0|15|0.600000|15|0.600000|1|0.040000|N/A|N/A|150000|3201024|K_ -audio|1|28800|0.600000|28800|0.600000|1920|0.040000|N/A|N/A|7680|3351552|K_ -video|0|16|0.640000|16|0.640000|1|0.040000|N/A|N/A|150000|3414016|K_ -audio|1|30720|0.640000|30720|0.640000|1920|0.040000|N/A|N/A|7680|3564544|K_ -video|0|17|0.680000|17|0.680000|1|0.040000|N/A|N/A|150000|3627008|K_ -audio|1|32640|0.680000|32640|0.680000|1920|0.040000|N/A|N/A|7680|3777536|K_ -video|0|18|0.720000|18|0.720000|1|0.040000|N/A|N/A|150000|3840000|K_ -audio|1|34560|0.720000|34560|0.720000|1920|0.040000|N/A|N/A|7680|3990528|K_ -video|0|19|0.760000|19|0.760000|1|0.040000|N/A|N/A|150000|4052992|K_ -audio|1|36480|0.760000|36480|0.760000|1920|0.040000|N/A|N/A|7680|4203520|K_ -video|0|20|0.800000|20|0.800000|1|0.040000|N/A|N/A|150000|4265984|K_ -audio|1|38400|0.800000|38400|0.800000|1920|0.040000|N/A|N/A|7680|4416512|K_ -video|0|21|0.840000|21|0.840000|1|0.040000|N/A|N/A|150000|4478976|K_ -audio|1|40320|0.840000|40320|0.840000|1920|0.040000|N/A|N/A|7680|4629504|K_ -video|0|22|0.880000|22|0.880000|1|0.040000|N/A|N/A|150000|4691968|K_ -audio|1|42240|0.880000|42240|0.880000|1920|0.040000|N/A|N/A|7680|4842496|K_ -video|0|23|0.920000|23|0.920000|1|0.040000|N/A|N/A|150000|4904960|K_ -audio|1|44160|0.920000|44160|0.920000|1920|0.040000|N/A|N/A|7680|5055488|K_ -video|0|24|0.960000|24|0.960000|1|0.040000|N/A|N/A|150000|5117952|K_ -audio|1|46080|0.960000|46080|0.960000|1920|0.040000|N/A|N/A|7680|5268480|K_ -video|0|25|1.000000|25|1.000000|1|0.040000|N/A|N/A|150000|4265984|K_ -audio|1|48000|1.000000|48000|1.000000|1920|0.040000|N/A|N/A|7680|4416512|K_ -video|0|26|1.040000|26|1.040000|1|0.040000|N/A|N/A|150000|4478976|K_ -audio|1|49920|1.040000|49920|1.040000|1920|0.040000|N/A|N/A|7680|4629504|K_ -video|0|27|1.080000|27|1.080000|1|0.040000|N/A|N/A|150000|4691968|K_ -audio|1|51840|1.080000|51840|1.080000|1920|0.040000|N/A|N/A|7680|4842496|K_ -video|0|28|1.120000|28|1.120000|1|0.040000|N/A|N/A|150000|4904960|K_ -audio|1|53760|1.120000|53760|1.120000|1920|0.040000|N/A|N/A|7680|5055488|K_ -video|0|29|1.160000|29|1.160000|1|0.040000|N/A|N/A|150000|5117952|K_ -audio|1|55680|1.160000|55680|1.160000|1920|0.040000|N/A|N/A|7680|5268480|K_ -video|0|30|1.200000|30|1.200000|1|0.040000|N/A|N/A|150000|1071104|K_|1 +video|0|0|0.000000|0|0.000000|1|0.040000|N/A|N/A|150000|7168|K_ +audio|1|0|0.000000|0|0.000000|1920|0.040000|N/A|N/A|7680|157696|K_ +video|0|1|0.040000|1|0.040000|1|0.040000|N/A|N/A|150000|220160|K_ +audio|1|1920|0.040000|1920|0.040000|1920|0.040000|N/A|N/A|7680|370688|K_ +video|0|2|0.080000|2|0.080000|1|0.040000|N/A|N/A|150000|433152|K_ +audio|1|3840|0.080000|3840|0.080000|1920|0.040000|N/A|N/A|7680|583680|K_ +video|0|3|0.120000|3|0.120000|1|0.040000|N/A|N/A|150000|646144|K_ +audio|1|5760|0.120000|5760|0.120000|1920|0.040000|N/A|N/A|7680|796672|K_ +video|0|4|0.160000|4|0.160000|1|0.040000|N/A|N/A|150000|859136|K_ +audio|1|7680|0.160000|7680|0.160000|1920|0.040000|N/A|N/A|7680|1009664|K_ +video|0|5|0.200000|5|0.200000|1|0.040000|N/A|N/A|150000|1072128|K_ +audio|1|9600|0.200000|9600|0.200000|1920|0.040000|N/A|N/A|7680|1222656|K_ +video|0|6|0.240000|6|0.240000|1|0.040000|N/A|N/A|150000|1285120|K_ +audio|1|11520|0.240000|11520|0.240000|1920|0.040000|N/A|N/A|7680|1435648|K_ +video|0|7|0.280000|7|0.280000|1|0.040000|N/A|N/A|150000|1498112|K_ +audio|1|13440|0.280000|13440|0.280000|1920|0.040000|N/A|N/A|7680|1648640|K_ +video|0|8|0.320000|8|0.320000|1|0.040000|N/A|N/A|150000|1711104|K_ +audio|1|15360|0.320000|15360|0.320000|1920|0.040000|N/A|N/A|7680|1861632|K_ +video|0|9|0.360000|9|0.360000|1|0.040000|N/A|N/A|150000|1924096|K_ +audio|1|17280|0.360000|17280|0.360000|1920|0.040000|N/A|N/A|7680|2074624|K_ +video|0|10|0.400000|10|0.400000|1|0.040000|N/A|N/A|150000|2137088|K_ +audio|1|19200|0.400000|19200|0.400000|1920|0.040000|N/A|N/A|7680|2287616|K_ +video|0|11|0.440000|11|0.440000|1|0.040000|N/A|N/A|150000|2350080|K_ +audio|1|21120|0.440000|21120|0.440000|1920|0.040000|N/A|N/A|7680|2500608|K_ +video|0|12|0.480000|12|0.480000|1|0.040000|N/A|N/A|150000|2563072|K_ +audio|1|23040|0.480000|23040|0.480000|1920|0.040000|N/A|N/A|7680|2713600|K_ +video|0|13|0.520000|13|0.520000|1|0.040000|N/A|N/A|150000|2776064|K_ +audio|1|24960|0.520000|24960|0.520000|1920|0.040000|N/A|N/A|7680|2926592|K_ +video|0|14|0.560000|14|0.560000|1|0.040000|N/A|N/A|150000|2989056|K_ +audio|1|26880|0.560000|26880|0.560000|1920|0.040000|N/A|N/A|7680|3139584|K_ +video|0|15|0.600000|15|0.600000|1|0.040000|N/A|N/A|150000|3202048|K_ +audio|1|28800|0.600000|28800|0.600000|1920|0.040000|N/A|N/A|7680|3352576|K_ +video|0|16|0.640000|16|0.640000|1|0.040000|N/A|N/A|150000|3415040|K_ +audio|1|30720|0.640000|30720|0.640000|1920|0.040000|N/A|N/A|7680|3565568|K_ +video|0|17|0.680000|17|0.680000|1|0.040000|N/A|N/A|150000|3628032|K_ +audio|1|32640|0.680000|32640|0.680000|1920|0.040000|N/A|N/A|7680|3778560|K_ +video|0|18|0.720000|18|0.720000|1|0.040000|N/A|N/A|150000|3841024|K_ +audio|1|34560|0.720000|34560|0.720000|1920|0.040000|N/A|N/A|7680|3991552|K_ +video|0|19|0.760000|19|0.760000|1|0.040000|N/A|N/A|150000|4054016|K_ +audio|1|36480|0.760000|36480|0.760000|1920|0.040000|N/A|N/A|7680|4204544|K_ +video|0|20|0.800000|20|0.800000|1|0.040000|N/A|N/A|150000|4267008|K_ +audio|1|38400|0.800000|38400|0.800000|1920|0.040000|N/A|N/A|7680|4417536|K_ +video|0|21|0.840000|21|0.840000|1|0.040000|N/A|N/A|150000|4480000|K_ +audio|1|40320|0.840000|40320|0.840000|1920|0.040000|N/A|N/A|7680|4630528|K_ +video|0|22|0.880000|22|0.880000|1|0.040000|N/A|N/A|150000|4692992|K_ +audio|1|42240|0.880000|42240|0.880000|1920|0.040000|N/A|N/A|7680|4843520|K_ +video|0|23|0.920000|23|0.920000|1|0.040000|N/A|N/A|150000|4905984|K_ +audio|1|44160|0.920000|44160|0.920000|1920|0.040000|N/A|N/A|7680|5056512|K_ +video|0|24|0.960000|24|0.960000|1|0.040000|N/A|N/A|150000|5118976|K_ +audio|1|46080|0.960000|46080|0.960000|1920|0.040000|N/A|N/A|7680|5269504|K_ +video|0|25|1.000000|25|1.000000|1|0.040000|N/A|N/A|150000|4267008|K_ +audio|1|48000|1.000000|48000|1.000000|1920|0.040000|N/A|N/A|7680|4417536|K_ +video|0|26|1.040000|26|1.040000|1|0.040000|N/A|N/A|150000|4480000|K_ +audio|1|49920|1.040000|49920|1.040000|1920|0.040000|N/A|N/A|7680|4630528|K_ +video|0|27|1.080000|27|1.080000|1|0.040000|N/A|N/A|150000|4692992|K_ +audio|1|51840|1.080000|51840|1.080000|1920|0.040000|N/A|N/A|7680|4843520|K_ +video|0|28|1.120000|28|1.120000|1|0.040000|N/A|N/A|150000|4905984|K_ +audio|1|53760|1.120000|53760|1.120000|1920|0.040000|N/A|N/A|7680|5056512|K_ +video|0|29|1.160000|29|1.160000|1|0.040000|N/A|N/A|150000|5118976|K_ +audio|1|55680|1.160000|55680|1.160000|1920|0.040000|N/A|N/A|7680|5269504|K_ +video|0|30|1.200000|30|1.200000|1|0.040000|N/A|N/A|150000|1072128|K_|1 Strings Metadata -audio|1|57600|1.200000|57600|1.200000|1920|0.040000|N/A|N/A|7680|1221632|K_|1 +audio|1|57600|1.200000|57600|1.200000|1920|0.040000|N/A|N/A|7680|1222656|K_|1 Strings Metadata -video|0|31|1.240000|31|1.240000|1|0.040000|N/A|N/A|150000|1284096|K_|1 +video|0|31|1.240000|31|1.240000|1|0.040000|N/A|N/A|150000|1285120|K_|1 Strings Metadata -audio|1|59520|1.240000|59520|1.240000|1920|0.040000|N/A|N/A|7680|1434624|K_|1 +audio|1|59520|1.240000|59520|1.240000|1920|0.040000|N/A|N/A|7680|1435648|K_|1 Strings Metadata -video|0|32|1.280000|32|1.280000|1|0.040000|N/A|N/A|150000|1497088|K_|1 +video|0|32|1.280000|32|1.280000|1|0.040000|N/A|N/A|150000|1498112|K_|1 Strings Metadata -audio|1|61440|1.280000|61440|1.280000|1920|0.040000|N/A|N/A|7680|1647616|K_|1 +audio|1|61440|1.280000|61440|1.280000|1920|0.040000|N/A|N/A|7680|1648640|K_|1 Strings Metadata -video|0|33|1.320000|33|1.320000|1|0.040000|N/A|N/A|150000|1710080|K_|1 +video|0|33|1.320000|33|1.320000|1|0.040000|N/A|N/A|150000|1711104|K_|1 Strings Metadata -audio|1|63360|1.320000|63360|1.320000|1920|0.040000|N/A|N/A|7680|1860608|K_|1 +audio|1|63360|1.320000|63360|1.320000|1920|0.040000|N/A|N/A|7680|1861632|K_|1 Strings Metadata -video|0|34|1.360000|34|1.360000|1|0.040000|N/A|N/A|150000|1923072|K_|1 +video|0|34|1.360000|34|1.360000|1|0.040000|N/A|N/A|150000|1924096|K_|1 Strings Metadata -audio|1|65280|1.360000|65280|1.360000|1920|0.040000|N/A|N/A|7680|2073600|K_|1 +audio|1|65280|1.360000|65280|1.360000|1920|0.040000|N/A|N/A|7680|2074624|K_|1 Strings Metadata 0|mpeg2video|0|video|1/25|[0][0][0][0]|0x0000|720|608|0|0|0|1:1|45:38|yuv422p|5|tv|unknown|unknown|unknown|topleft|tt|N/A|1|N/A|25/1|25/1|1/25|0|0.000000|N/A|N/A|30000000|N/A|N/A|N/A|N/A|35|0|0|0|0|0|0|0|0|0|0|0|0|0x060A2B340101010501010D001300000000000000000000000000000000000001 1|pcm_s16le|unknown|audio|1/48000|[0][0][0][0]|0x0000|s16|48000|2|unknown|16|N/A|0/0|0/0|1/48000|0|0.000000|N/A|N/A|1536000|N/A|N/A|N/A|N/A|35|0|0|0|0|0|0|0|0|0|0|0|0|0x060A2B340101010501010D001300000000000000000000000000000000000001 diff --git a/tests/ref/fate/copy-apng b/tests/ref/fate/copy-apng new file mode 100644 index 000000000..3057573ce --- /dev/null +++ b/tests/ref/fate/copy-apng @@ -0,0 +1,32 @@ +a4c46fad7716ad094eb3c78b74ca0244 *tests/data/fate/copy-apng.apng +6209864 tests/data/fate/copy-apng.apng +#tb 0: 1/25 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 352x288 +#sar 0: 0/1 +0, 0, 0, 1, 304128, 0x348bb7a0 +0, 1, 1, 1, 304128, 0xaf9634d7 +0, 2, 2, 1, 304128, 0x81161fd3 +0, 3, 3, 1, 304128, 0x6839b383 +0, 4, 4, 1, 304128, 0xa55299b8 +0, 5, 5, 1, 304128, 0x66fb65b3 +0, 6, 6, 1, 304128, 0xe6be2a99 +0, 7, 7, 1, 304128, 0xfb33cb55 +0, 8, 8, 1, 304128, 0x51ab3d74 +0, 9, 9, 1, 304128, 0x67dc44ee +0, 10, 10, 1, 304128, 0x2eac3b50 +0, 11, 11, 1, 304128, 0xd4a4c377 +0, 12, 12, 1, 304128, 0x1eefe29c +0, 13, 13, 1, 304128, 0x3a84d488 +0, 14, 14, 1, 304128, 0x70d3b165 +0, 15, 15, 1, 304128, 0x578e58d4 +0, 16, 16, 1, 304128, 0x08bba87e +0, 17, 17, 1, 304128, 0xccc86c47 +0, 18, 18, 1, 304128, 0x70bf9aa2 +0, 19, 19, 1, 304128, 0x3fc3d5b5 +0, 20, 20, 1, 304128, 0xef52590b +0, 21, 21, 1, 304128, 0x4f7adde0 +0, 22, 22, 1, 304128, 0xc076ef54 +0, 23, 23, 1, 304128, 0xed2bba2d +0, 24, 24, 1, 304128, 0x6fce6367 diff --git a/tests/ref/fate/copy-psp b/tests/ref/fate/copy-psp index 81eb17254..44ec46126 100644 --- a/tests/ref/fate/copy-psp +++ b/tests/ref/fate/copy-psp @@ -1,5 +1,5 @@ -cada61453a2483ef8ba1fb82c8bbff25 *tests/data/fate/copy-psp.psp -2041433 tests/data/fate/copy-psp.psp +65a177552e03123c9a62ddb942970d05 *tests/data/fate/copy-psp.psp +2041445 tests/data/fate/copy-psp.psp #extradata 0: 51, 0xaf6d1012 #extradata 1: 2, 0x00b200a1 #tb 0: 1/90000 diff --git a/tests/ref/fate/copy-trac236 b/tests/ref/fate/copy-trac236 index c5240ca3d..2ac05e63e 100644 --- a/tests/ref/fate/copy-trac236 +++ b/tests/ref/fate/copy-trac236 @@ -1,5 +1,5 @@ -d6e3d97b522ce881ed29c5da74cc7e63 *tests/data/fate/copy-trac236.mov -630810 tests/data/fate/copy-trac236.mov +959a4d78c6c11936e361fc3101a013eb *tests/data/fate/copy-trac236.mov +630860 tests/data/fate/copy-trac236.mov #tb 0: 100/2997 #media_type 0: video #codec_id 0: rawvideo diff --git a/tests/ref/fate/copy-trac3074 b/tests/ref/fate/copy-trac3074 index 5ce569426..ff6690025 100644 --- a/tests/ref/fate/copy-trac3074 +++ b/tests/ref/fate/copy-trac3074 @@ -1,5 +1,5 @@ -39aef1afff761d673fd1be07182941d1 *tests/data/fate/copy-trac3074.mp4 -333991 tests/data/fate/copy-trac3074.mp4 +f92a201033712bda262f1e071e25544a *tests/data/fate/copy-trac3074.mp4 +333992 tests/data/fate/copy-trac3074.mp4 #tb 0: 1/48000 #media_type 0: audio #codec_id 0: eac3 diff --git a/tests/ref/fate/copy-trac4914 b/tests/ref/fate/copy-trac4914 index a8f287faf..7c8d0e915 100644 --- a/tests/ref/fate/copy-trac4914 +++ b/tests/ref/fate/copy-trac4914 @@ -1,5 +1,5 @@ -05fdc4a6e28abb2c26e96224682d2684 *tests/data/fate/copy-trac4914.mxf -560697 tests/data/fate/copy-trac4914.mxf +b37c4d5693cdb5b9ed9b33501ffb682a *tests/data/fate/copy-trac4914.mxf +561721 tests/data/fate/copy-trac4914.mxf #tb 0: 1001/30000 #media_type 0: video #codec_id 0: rawvideo diff --git a/tests/ref/fate/filter-curves b/tests/ref/fate/filter-curves index 401bd2eaf..fd427e237 100644 --- a/tests/ref/fate/filter-curves +++ b/tests/ref/fate/filter-curves @@ -3,8 +3,8 @@ #codec_id 0: rawvideo #dimensions 0: 640x480 #sar 0: 0/1 -0, 0, 0, 1, 921600, 0xcf426780 -0, 1, 1, 1, 921600, 0x7642892d -0, 2, 2, 1, 921600, 0x13c1ab7e -0, 3, 3, 1, 921600, 0x3eca04bf -0, 4, 4, 1, 921600, 0x61539162 +0, 0, 0, 1, 921600, 0x3ed36780 +0, 1, 1, 1, 921600, 0x7dbd892d +0, 2, 2, 1, 921600, 0x0894ab7e +0, 3, 3, 1, 921600, 0x471004bf +0, 4, 4, 1, 921600, 0x79c79162 diff --git a/tests/ref/fate/filter-hls-append b/tests/ref/fate/filter-hls-append index be65c82f5..52b7dff48 100644 --- a/tests/ref/fate/filter-hls-append +++ b/tests/ref/fate/filter-hls-append @@ -5,1534 +5,1534 @@ #channel_layout 0: 4 #channel_layout_name 0: mono 0, 0, 0, 1152, 2304, 0x907cb7fa -0, 1152, 1152, 1152, 2304, 0xb8dc7525 -0, 2304, 2304, 1152, 2304, 0x3e7d6905 -0, 3456, 3456, 1152, 2304, 0xef47877b -0, 4608, 4608, 1152, 2304, 0xfe916b7e -0, 5760, 5760, 1152, 2304, 0xe3d08cde -0, 6912, 6912, 1152, 2304, 0xff7f86cf -0, 8064, 8064, 1152, 2304, 0x843e6f95 -0, 9216, 9216, 1152, 2304, 0x81577c26 -0, 10368, 10368, 1152, 2304, 0x04a085d5 -0, 11520, 11520, 1152, 2304, 0x1c5a76f5 -0, 12672, 12672, 1152, 2304, 0x4ee78623 -0, 13824, 13824, 1152, 2304, 0x8ec861dc -0, 14976, 14976, 1152, 2304, 0x0ca179d8 -0, 16128, 16128, 1152, 2304, 0xc6da750f -0, 17280, 17280, 1152, 2304, 0xf6bf79b5 -0, 18432, 18432, 1152, 2304, 0x97b88a43 -0, 19584, 19584, 1152, 2304, 0xf13c7b9c -0, 20736, 20736, 1152, 2304, 0xdfba83af -0, 21888, 21888, 1152, 2304, 0xc9467d4b -0, 23040, 23040, 1152, 2304, 0xbbb58e2b -0, 24192, 24192, 1152, 2304, 0x3a1078ea -0, 25344, 25344, 1152, 2304, 0xe9587a5c -0, 26496, 26496, 1152, 2304, 0xef5a8039 -0, 27648, 27648, 1152, 2304, 0x9d5f782f -0, 28800, 28800, 1152, 2304, 0x1a548291 -0, 29952, 29952, 1152, 2304, 0x07517701 -0, 31104, 31104, 1152, 2304, 0x78127d6e -0, 32256, 32256, 1152, 2304, 0x62e2788a -0, 33408, 33408, 1152, 2304, 0x29397ad9 -0, 34560, 34560, 1152, 2304, 0x45da82d6 -0, 35712, 35712, 1152, 2304, 0x8ed66e51 -0, 36864, 36864, 1152, 2304, 0x660775cd -0, 38016, 38016, 1152, 2304, 0x802c767a -0, 39168, 39168, 1152, 2304, 0xcc055840 -0, 40320, 40320, 1152, 2304, 0x701b7eaf -0, 41472, 41472, 1152, 2304, 0x8290749f -0, 42624, 42624, 1152, 2304, 0x2c7b7d30 -0, 43776, 43776, 1152, 2304, 0xe4f17743 -0, 44928, 44928, 1152, 2304, 0x0e747d6e -0, 46080, 46080, 1152, 2304, 0xbe7775a0 -0, 47232, 47232, 1152, 2304, 0xcf797673 -0, 48384, 48384, 1152, 2304, 0x29cb7800 -0, 49536, 49536, 1152, 2304, 0xfc947890 -0, 50688, 50688, 1152, 2304, 0x62757fc6 -0, 51840, 51840, 1152, 2304, 0x098876d0 -0, 52992, 52992, 1152, 2304, 0xa9567ee2 -0, 54144, 54144, 1152, 2304, 0xe3bb9173 -0, 55296, 55296, 1152, 2304, 0xcc2d6dee -0, 56448, 56448, 1152, 2304, 0xe94591ab -0, 57600, 57600, 1152, 2304, 0x5c7588de -0, 58752, 58752, 1152, 2304, 0xfd83643c -0, 59904, 59904, 1152, 2304, 0x528177f1 -0, 61056, 61056, 1152, 2304, 0x65d08474 -0, 62208, 62208, 1152, 2304, 0x738d765b -0, 63360, 63360, 1152, 2304, 0xdd3d810e -0, 64512, 64512, 1152, 2304, 0xef4f90d3 -0, 65664, 65664, 1152, 2304, 0x61e28d43 -0, 66816, 66816, 1152, 2304, 0x9a11796b -0, 67968, 67968, 1152, 2304, 0x96c97dcd -0, 69120, 69120, 1152, 2304, 0xa8fe8621 -0, 70272, 70272, 1152, 2304, 0x499b7d38 -0, 71424, 71424, 1152, 2304, 0xfcb078a9 -0, 72576, 72576, 1152, 2304, 0x40d78651 -0, 73728, 73728, 1152, 2304, 0xa4af7234 -0, 74880, 74880, 1152, 2304, 0x6831870a -0, 76032, 76032, 1152, 2304, 0x030e7b9d -0, 77184, 77184, 1152, 2304, 0x445a75b6 -0, 78336, 78336, 1152, 2304, 0x09857389 -0, 79488, 79488, 1152, 2304, 0x0d018866 -0, 80640, 80640, 1152, 2304, 0x2afe810a -0, 81792, 81792, 1152, 2304, 0x0bcf7c43 -0, 82944, 82944, 1152, 2304, 0x13737c12 -0, 84096, 84096, 1152, 2304, 0x716c7bba -0, 85248, 85248, 1152, 2304, 0xb801823b -0, 86400, 86400, 1152, 2304, 0x0fd573ee -0, 87552, 87552, 1152, 2304, 0xe1ab879c -0, 88704, 88704, 1152, 2304, 0x49e6764f -0, 89856, 89856, 1152, 2304, 0xd5f26ddc -0, 91008, 91008, 1152, 2304, 0x076775ff -0, 92160, 92160, 1152, 2304, 0xfbb86fce -0, 93312, 93312, 1152, 2304, 0x20c56858 -0, 94464, 94464, 1152, 2304, 0x043e6891 -0, 95616, 95616, 1152, 2304, 0x59648729 -0, 96768, 96768, 1152, 2304, 0xd4907a63 -0, 97920, 97920, 1152, 2304, 0xd0208a4c -0, 99072, 99072, 1152, 2304, 0xce968383 -0, 100224, 100224, 1152, 2304, 0x3cfc7cd1 -0, 101376, 101376, 1152, 2304, 0x628a7bf5 -0, 102528, 102528, 1152, 2304, 0x9cfe8a4f -0, 103680, 103680, 1152, 2304, 0xdf6f7c6d -0, 104832, 104832, 1152, 2304, 0x6cf6882a -0, 105984, 105984, 1152, 2304, 0x099773a3 -0, 107136, 107136, 1152, 2304, 0x4a1c7649 -0, 108288, 108288, 1152, 2304, 0x31ea71cb -0, 109440, 109440, 1152, 2304, 0xed127ed9 -0, 110592, 110592, 1152, 2304, 0x5b156954 -0, 111744, 111744, 1152, 2304, 0xdd638532 -0, 112896, 112896, 1152, 2304, 0xf1a271f2 -0, 114048, 114048, 1152, 2304, 0x779184d7 -0, 115200, 115200, 1152, 2304, 0x49a88aa8 -0, 116352, 116352, 1152, 2304, 0xa11b7c90 -0, 117504, 117504, 1152, 2304, 0xbf488274 -0, 118656, 118656, 1152, 2304, 0x002f79a8 -0, 119808, 119808, 1152, 2304, 0x0ed97e2f -0, 120960, 120960, 1152, 2304, 0x7845878f -0, 122112, 122112, 1152, 2304, 0x46d777dc -0, 123264, 123264, 1152, 2304, 0x8d0179e3 -0, 124416, 124416, 1152, 2304, 0x38917f9f -0, 125568, 125568, 1152, 2304, 0x449876e7 -0, 126720, 126720, 1152, 2304, 0x001a8769 -0, 127872, 127872, 1152, 2304, 0x06c1826b -0, 129024, 129024, 1152, 2304, 0x41b68047 -0, 130176, 130176, 1152, 2304, 0xeb9782c6 -0, 131328, 131328, 1152, 2304, 0x7cd9719c -0, 132480, 132480, 1152, 2304, 0x3a4a767c -0, 133632, 133632, 1152, 2304, 0x7f887e81 -0, 134784, 134784, 1152, 2304, 0xf75d714b -0, 135936, 135936, 1152, 2304, 0x33b57e9f -0, 137088, 137088, 1152, 2304, 0xc732749e -0, 138240, 138240, 1152, 2304, 0x386f7e1a -0, 139392, 139392, 1152, 2304, 0x6b9c767d -0, 140544, 140544, 1152, 2304, 0x701c83e5 -0, 141696, 141696, 1152, 2304, 0xb92571e1 -0, 142848, 142848, 1152, 2304, 0x833a84bc -0, 144000, 144000, 1152, 2304, 0x1b6984e0 -0, 145152, 145152, 1152, 2304, 0x1b2474ba -0, 146304, 146304, 1152, 2304, 0xc22775a6 -0, 147456, 147456, 1152, 2304, 0x3e8f7972 -0, 148608, 148608, 1152, 2304, 0x17a28a65 -0, 149760, 149760, 1152, 2304, 0x9b6178a4 -0, 150912, 150912, 1152, 2304, 0x5d707873 -0, 152064, 152064, 1152, 2304, 0x68e2645a -0, 153216, 153216, 1152, 2304, 0x1e377d28 -0, 154368, 154368, 1152, 2304, 0x54b384be -0, 155520, 155520, 1152, 2304, 0x0617808c -0, 156672, 156672, 1152, 2304, 0xbc2b8a6c -0, 157824, 157824, 1152, 2304, 0x7ced7180 -0, 158976, 158976, 1152, 2304, 0xf22180ab -0, 160128, 160128, 1152, 2304, 0xf13682c9 -0, 161280, 161280, 1152, 2304, 0x7eff87fd -0, 162432, 162432, 1152, 2304, 0x5a0b5cec -0, 163584, 163584, 1152, 2304, 0x57c18906 -0, 164736, 164736, 1152, 2304, 0xb55a6a16 -0, 165888, 165888, 1152, 2304, 0xf2608371 -0, 167040, 167040, 1152, 2304, 0x36df7576 -0, 168192, 168192, 1152, 2304, 0xdb106fb4 -0, 169344, 169344, 1152, 2304, 0x7e4f85d0 -0, 170496, 170496, 1152, 2304, 0xe3ee78ab -0, 171648, 171648, 1152, 2304, 0xd36b7dc7 -0, 172800, 172800, 1152, 2304, 0xadab7c5c -0, 173952, 173952, 1152, 2304, 0x70786f26 -0, 175104, 175104, 1152, 2304, 0xcd5d717e -0, 176256, 176256, 1152, 2304, 0xc1a96f9a -0, 177408, 177408, 1152, 2304, 0xad777887 -0, 178560, 178560, 1152, 2304, 0x98277c16 -0, 179712, 179712, 1152, 2304, 0x868882c5 -0, 180864, 180864, 1152, 2304, 0xc48092b9 -0, 182016, 182016, 1152, 2304, 0x230069da -0, 183168, 183168, 1152, 2304, 0x14147ad6 -0, 184320, 184320, 1152, 2304, 0xc9007172 -0, 185472, 185472, 1152, 2304, 0x85d67bcc -0, 186624, 186624, 1152, 2304, 0x22418bab -0, 187776, 187776, 1152, 2304, 0xe53c8b71 -0, 188928, 188928, 1152, 2304, 0x5a1a9053 -0, 190080, 190080, 1152, 2304, 0x9cd179af -0, 191232, 191232, 1152, 2304, 0xbb3c7d72 -0, 192384, 192384, 1152, 2304, 0x477a8677 -0, 193536, 193536, 1152, 2304, 0xe3337834 -0, 194688, 194688, 1152, 2304, 0x1cb56d77 -0, 195840, 195840, 1152, 2304, 0xe89d6dac -0, 196992, 196992, 1152, 2304, 0xd468827e -0, 198144, 198144, 1152, 2304, 0xebc46b87 -0, 199296, 199296, 1152, 2304, 0x5fbb78d2 -0, 200448, 200448, 1152, 2304, 0xa1b483d6 -0, 201600, 201600, 1152, 2304, 0x6fec7cab -0, 202752, 202752, 1152, 2304, 0xd86d6f6c -0, 203904, 203904, 1152, 2304, 0x8c2c7d51 -0, 205056, 205056, 1152, 2304, 0xe8377cd7 -0, 206208, 206208, 1152, 2304, 0xb57071b4 -0, 207360, 207360, 1152, 2304, 0xc35c71fd -0, 208512, 208512, 1152, 2304, 0x789079e9 -0, 209664, 209664, 1152, 2304, 0x413b710e -0, 210816, 210816, 1152, 2304, 0x82678332 -0, 211968, 211968, 1152, 2304, 0xe1576e75 -0, 213120, 213120, 1152, 2304, 0x7c0b7ad6 -0, 214272, 214272, 1152, 2304, 0xc6b6786d -0, 215424, 215424, 1152, 2304, 0x736f7b89 -0, 216576, 216576, 1152, 2304, 0x0ded72f1 -0, 217728, 217728, 1152, 2304, 0xcb877a3c -0, 218880, 218880, 1152, 2304, 0x7c497d40 -0, 220032, 220032, 1152, 2304, 0xaefc798c -0, 221184, 221184, 1152, 2304, 0x4cce748c -0, 222336, 222336, 1152, 2304, 0xaa187fbe -0, 223488, 223488, 1152, 2304, 0x1aa77db9 -0, 224640, 224640, 1152, 2304, 0x9e0074b8 -0, 225792, 225792, 1152, 2304, 0x74ee822b -0, 226944, 226944, 1152, 2304, 0x975c6ff6 -0, 228096, 228096, 1152, 2304, 0xe1847bb4 -0, 229248, 229248, 1152, 2304, 0xe0828777 -0, 230400, 230400, 1152, 2304, 0xf4027205 -0, 231552, 231552, 1152, 2304, 0x535e7a20 -0, 232704, 232704, 1152, 2304, 0x5bd88404 -0, 233856, 233856, 1152, 2304, 0xf29478b1 -0, 235008, 235008, 1152, 2304, 0x9b7c7d88 -0, 236160, 236160, 1152, 2304, 0xaeb07335 -0, 237312, 237312, 1152, 2304, 0xbef06e08 -0, 238464, 238464, 1152, 2304, 0x795f7b8c -0, 239616, 239616, 1152, 2304, 0x435a674d -0, 240768, 240768, 1152, 2304, 0xd8ee7a09 -0, 241920, 241920, 1152, 2304, 0x9059812e -0, 243072, 243072, 1152, 2304, 0x7481744a -0, 244224, 244224, 1152, 2304, 0xdff27475 -0, 245376, 245376, 1152, 2304, 0xb17783ab -0, 246528, 246528, 1152, 2304, 0x42e9706b -0, 247680, 247680, 1152, 2304, 0x9f0d86b4 -0, 248832, 248832, 1152, 2304, 0x2963955f -0, 249984, 249984, 1152, 2304, 0x059a6957 -0, 251136, 251136, 1152, 2304, 0x85948206 -0, 252288, 252288, 1152, 2304, 0x185e8400 -0, 253440, 253440, 1152, 2304, 0xe98e70df -0, 254592, 254592, 1152, 2304, 0x69057b27 -0, 255744, 255744, 1152, 2304, 0x49e26f21 -0, 256896, 256896, 1152, 2304, 0xb0867da5 -0, 258048, 258048, 1152, 2304, 0x785980ff -0, 259200, 259200, 1152, 2304, 0xf4b774be -0, 260352, 260352, 1152, 2304, 0x63897e8c -0, 261504, 261504, 1152, 2304, 0x248b89af -0, 262656, 262656, 1152, 2304, 0xd3627c4a -0, 263808, 263808, 1152, 2304, 0x5a4d9349 -0, 264960, 264960, 1152, 2304, 0xe2ce7c4c -0, 266112, 266112, 1152, 2304, 0x321f6c0b -0, 267264, 267264, 1152, 2304, 0x51ac74e0 -0, 268416, 268416, 1152, 2304, 0x8efa91ba -0, 269568, 269568, 1152, 2304, 0x8b4b784c -0, 270720, 270720, 1152, 2304, 0xe9e4879e -0, 271872, 271872, 1152, 2304, 0x8dc28081 -0, 273024, 273024, 1152, 2304, 0x44b477b0 -0, 274176, 274176, 1152, 2304, 0xf7b67084 -0, 275328, 275328, 1152, 2304, 0x4b198c17 -0, 276480, 276480, 1152, 2304, 0x9c947194 -0, 277632, 277632, 1152, 2304, 0x6eaa7f15 -0, 278784, 278784, 1152, 2304, 0x119f7c1d -0, 279936, 279936, 1152, 2304, 0x157b7f43 -0, 281088, 281088, 1152, 2304, 0xcd2e7acc -0, 282240, 282240, 1152, 2304, 0x97597247 -0, 283392, 283392, 1152, 2304, 0x7ba06acb -0, 284544, 284544, 1152, 2304, 0x233c7995 -0, 285696, 285696, 1152, 2304, 0x08e28587 -0, 286848, 286848, 1152, 2304, 0x92be84b5 -0, 288000, 288000, 1152, 2304, 0xbb857d43 -0, 289152, 289152, 1152, 2304, 0x168e7c74 -0, 290304, 290304, 1152, 2304, 0xac5465d9 -0, 291456, 291456, 1152, 2304, 0x18f58831 -0, 292608, 292608, 1152, 2304, 0x19b48196 -0, 293760, 293760, 1152, 2304, 0x20297653 -0, 294912, 294912, 1152, 2304, 0x93397a82 -0, 296064, 296064, 1152, 2304, 0x65ea7deb -0, 297216, 297216, 1152, 2304, 0xd7316e20 -0, 298368, 298368, 1152, 2304, 0x94107f2b -0, 299520, 299520, 1152, 2304, 0xec3b7dc6 -0, 300672, 300672, 1152, 2304, 0x2d3783aa -0, 301824, 301824, 1152, 2304, 0x07e47340 -0, 302976, 302976, 1152, 2304, 0xbc117893 -0, 304128, 304128, 1152, 2304, 0x8bd97851 -0, 305280, 305280, 1152, 2304, 0xc27376a9 -0, 306432, 306432, 1152, 2304, 0x30d88c83 -0, 307584, 307584, 1152, 2304, 0x19c2704c -0, 308736, 308736, 1152, 2304, 0x093b7b6e -0, 309888, 309888, 1152, 2304, 0x221a7349 -0, 311040, 311040, 1152, 2304, 0xa4fd82cd -0, 312192, 312192, 1152, 2304, 0x762e6bc9 -0, 313344, 313344, 1152, 2304, 0x270075d4 -0, 314496, 314496, 1152, 2304, 0xa5f27b90 -0, 315648, 315648, 1152, 2304, 0xf72e7edc -0, 316800, 316800, 1152, 2304, 0x42178486 -0, 317952, 317952, 1152, 2304, 0x5f7978e8 -0, 319104, 319104, 1152, 2304, 0x5d7c6703 -0, 320256, 320256, 1152, 2304, 0x2c4483d5 -0, 321408, 321408, 1152, 2304, 0x31bd951d -0, 322560, 322560, 1152, 2304, 0x99487af0 -0, 323712, 323712, 1152, 2304, 0x0bd27ee7 -0, 324864, 324864, 1152, 2304, 0xc3e07ac4 -0, 326016, 326016, 1152, 2304, 0x98a16ba7 -0, 327168, 327168, 1152, 2304, 0xd7a5747b -0, 328320, 328320, 1152, 2304, 0x96fb811c -0, 329472, 329472, 1152, 2304, 0x7cee8109 -0, 330624, 330624, 1152, 2304, 0x52b18ba2 -0, 331776, 331776, 1152, 2304, 0x33be8861 -0, 332928, 332928, 1152, 2304, 0xf41282a0 -0, 334080, 334080, 1152, 2304, 0xb4268993 -0, 335232, 335232, 1152, 2304, 0x52126a1c -0, 336384, 336384, 1152, 2304, 0x050b6f7a -0, 337536, 337536, 1152, 2304, 0x67a26fc3 -0, 338688, 338688, 1152, 2304, 0x966c7cf2 -0, 339840, 339840, 1152, 2304, 0x22097750 -0, 340992, 340992, 1152, 2304, 0xfbb0796c -0, 342144, 342144, 1152, 2304, 0xbd508964 -0, 343296, 343296, 1152, 2304, 0xc24478d8 -0, 344448, 344448, 1152, 2304, 0x3913769d -0, 345600, 345600, 1152, 2304, 0x8aab872f -0, 346752, 346752, 1152, 2304, 0x7cb4822f -0, 347904, 347904, 1152, 2304, 0xea318144 -0, 349056, 349056, 1152, 2304, 0xaf0f86d2 -0, 350208, 350208, 1152, 2304, 0x24f27598 -0, 351360, 351360, 1152, 2304, 0xd76f6d40 -0, 352512, 352512, 1152, 2304, 0x085071a7 -0, 353664, 353664, 1152, 2304, 0x1d11704c -0, 354816, 354816, 1152, 2304, 0x21517cbd -0, 355968, 355968, 1152, 2304, 0xcdca8d32 -0, 357120, 357120, 1152, 2304, 0x71c18433 -0, 358272, 358272, 1152, 2304, 0xd39d7d81 -0, 359424, 359424, 1152, 2304, 0x7a0d7a43 -0, 360576, 360576, 1152, 2304, 0x007c8884 -0, 361728, 361728, 1152, 2304, 0x403282d0 -0, 362880, 362880, 1152, 2304, 0xe3737214 -0, 364032, 364032, 1152, 2304, 0xaf906f47 -0, 365184, 365184, 1152, 2304, 0x54f57b3b -0, 366336, 366336, 1152, 2304, 0x29be7791 -0, 367488, 367488, 1152, 2304, 0xe3c663d5 -0, 368640, 368640, 1152, 2304, 0xd7258238 -0, 369792, 369792, 1152, 2304, 0x3719820d -0, 370944, 370944, 1152, 2304, 0xbe04814f -0, 372096, 372096, 1152, 2304, 0x556c815e -0, 373248, 373248, 1152, 2304, 0xb2447e10 -0, 374400, 374400, 1152, 2304, 0x7c16867c -0, 375552, 375552, 1152, 2304, 0x6a7b78ed -0, 376704, 376704, 1152, 2304, 0x5d307b81 -0, 377856, 377856, 1152, 2304, 0xaab680d3 -0, 379008, 379008, 1152, 2304, 0xb5d37a23 -0, 380160, 380160, 1152, 2304, 0x7f7d6f76 -0, 381312, 381312, 1152, 2304, 0x317a8296 -0, 382464, 382464, 1152, 2304, 0x8a987b3d -0, 383616, 383616, 1152, 2304, 0x4f317a27 -0, 384768, 384768, 1152, 2304, 0xfc65852f -0, 385920, 385920, 1152, 2304, 0x40527719 -0, 387072, 387072, 1152, 2304, 0x84988e13 -0, 388224, 388224, 1152, 2304, 0x318b6ddc -0, 389376, 389376, 1152, 2304, 0x94cf7939 -0, 390528, 390528, 1152, 2304, 0x6f22819d -0, 391680, 391680, 1152, 2304, 0xa7dd80a9 -0, 392832, 392832, 1152, 2304, 0x1c7968fa -0, 393984, 393984, 1152, 2304, 0xd9937bae -0, 395136, 395136, 1152, 2304, 0xf7137cf9 -0, 396288, 396288, 1152, 2304, 0xeadb84b5 -0, 397440, 397440, 1152, 2304, 0x9a2390ac -0, 398592, 398592, 1152, 2304, 0xdb6a73f6 -0, 399744, 399744, 1152, 2304, 0x69e07507 -0, 400896, 400896, 1152, 2304, 0xbc8478b2 -0, 402048, 402048, 1152, 2304, 0x32cf8638 -0, 403200, 403200, 1152, 2304, 0x2b8d755a -0, 404352, 404352, 1152, 2304, 0x52e05bd2 -0, 405504, 405504, 1152, 2304, 0x2aed8c49 -0, 406656, 406656, 1152, 2304, 0x587a896e -0, 407808, 407808, 1152, 2304, 0x6dd87dee -0, 408960, 408960, 1152, 2304, 0xd2858338 -0, 410112, 410112, 1152, 2304, 0xd90f7842 -0, 411264, 411264, 1152, 2304, 0xd6fb6d4a -0, 412416, 412416, 1152, 2304, 0x85498aea -0, 413568, 413568, 1152, 2304, 0x18597790 -0, 414720, 414720, 1152, 2304, 0x3cd78fea -0, 415872, 415872, 1152, 2304, 0x94377fbc -0, 417024, 417024, 1152, 2304, 0xf9db73f5 -0, 418176, 418176, 1152, 2304, 0x14fb6fca -0, 419328, 419328, 1152, 2304, 0xe9d17d69 -0, 420480, 420480, 1152, 2304, 0xdeb57286 -0, 421632, 421632, 1152, 2304, 0xa5d37e17 -0, 422784, 422784, 1152, 2304, 0xcf6882fb -0, 423936, 423936, 1152, 2304, 0x31758066 -0, 425088, 425088, 1152, 2304, 0x6b4d8175 -0, 426240, 426240, 1152, 2304, 0x2a3d7f8e -0, 427392, 427392, 1152, 2304, 0xc066743b -0, 428544, 428544, 1152, 2304, 0xcab88146 -0, 429696, 429696, 1152, 2304, 0x2b4c6e13 -0, 430848, 430848, 1152, 2304, 0x00b36b6f -0, 432000, 432000, 1152, 2304, 0x664a88d3 -0, 433152, 433152, 1152, 2304, 0x18a66f76 -0, 434304, 434304, 1152, 2304, 0x4f828a8b -0, 435456, 435456, 1152, 2304, 0x9cc7728e -0, 436608, 436608, 1152, 2304, 0xbe357936 -0, 437760, 437760, 1152, 2304, 0x19878f8d -0, 438912, 438912, 1152, 2304, 0x227b7c71 -0, 440064, 440064, 1152, 2304, 0xf7c879ec -0, 441216, 441216, 1152, 2304, 0x0bca7b50 -0, 442368, 442368, 1152, 2304, 0xe4398304 -0, 443520, 443520, 1152, 2304, 0xf5da75c7 -0, 444672, 444672, 1152, 2304, 0x9f9070a3 -0, 445824, 445824, 1152, 2304, 0x789076f6 -0, 446976, 446976, 1152, 2304, 0x362977cc -0, 448128, 448128, 1152, 2304, 0x4d0a8928 -0, 449280, 449280, 1152, 2304, 0x1bb767ec -0, 450432, 450432, 1152, 2304, 0xbe727fa5 -0, 451584, 451584, 1152, 2304, 0x27f38347 -0, 452736, 452736, 1152, 2304, 0x0a3c8783 -0, 453888, 453888, 1152, 2304, 0x8249639c -0, 455040, 455040, 1152, 2304, 0x3b076f69 -0, 456192, 456192, 1152, 2304, 0xd9597ee3 -0, 457344, 457344, 1152, 2304, 0x026e7fad -0, 458496, 458496, 1152, 2304, 0xbd7a6de4 -0, 459648, 459648, 1152, 2304, 0x7d718a4d -0, 460800, 460800, 1152, 2304, 0x1f5e83b4 -0, 461952, 461952, 1152, 2304, 0x597d7755 -0, 463104, 463104, 1152, 2304, 0x3fb080bd -0, 464256, 464256, 1152, 2304, 0xdcbd7b16 -0, 465408, 465408, 1152, 2304, 0x5c48865f -0, 466560, 466560, 1152, 2304, 0xcda37ae8 -0, 467712, 467712, 1152, 2304, 0x4810796d -0, 468864, 468864, 1152, 2304, 0x34317fd0 -0, 470016, 470016, 1152, 2304, 0x5c0e7456 -0, 471168, 471168, 1152, 2304, 0x44d78040 -0, 472320, 472320, 1152, 2304, 0x88587882 -0, 473472, 473472, 1152, 2304, 0x77687d5e -0, 474624, 474624, 1152, 2304, 0x116d68bb -0, 475776, 475776, 1152, 2304, 0x3e5b6f60 -0, 476928, 476928, 1152, 2304, 0x64ea783c -0, 478080, 478080, 1152, 2304, 0x23547f7d -0, 479232, 479232, 1152, 2304, 0x2eee7892 -0, 480384, 480384, 1152, 2304, 0xfb837cba -0, 481536, 481536, 1152, 2304, 0x86518209 -0, 482688, 482688, 1152, 2304, 0x672f7bba -0, 483840, 483840, 1152, 2304, 0x6ab583fb -0, 484992, 484992, 1152, 2304, 0xc1297428 -0, 486144, 486144, 1152, 2304, 0x164e7717 -0, 487296, 487296, 1152, 2304, 0xb754976d -0, 488448, 488448, 1152, 2304, 0xb99d81b2 -0, 489600, 489600, 1152, 2304, 0x79046fd6 -0, 490752, 490752, 1152, 2304, 0x9a3f8426 -0, 491904, 491904, 1152, 2304, 0x896371f5 -0, 493056, 493056, 1152, 2304, 0x63d1799f -0, 494208, 494208, 1152, 2304, 0x4842844e -0, 495360, 495360, 1152, 2304, 0x850e8372 -0, 496512, 496512, 1152, 2304, 0x85d07022 -0, 497664, 497664, 1152, 2304, 0x9e6683d1 -0, 498816, 498816, 1152, 2304, 0x301b8981 -0, 499968, 499968, 1152, 2304, 0x1f1e98c5 -0, 501120, 501120, 1152, 2304, 0xc8797b03 -0, 502272, 502272, 1152, 2304, 0xf9d189f5 -0, 503424, 503424, 1152, 2304, 0x0e0d88be -0, 504576, 504576, 1152, 2304, 0x6c1d7843 -0, 505728, 505728, 1152, 2304, 0xd13b8a38 -0, 506880, 506880, 1152, 2304, 0x9b8f773c -0, 508032, 508032, 1152, 2304, 0x9acd7309 -0, 509184, 509184, 1152, 2304, 0x5e7d7d15 -0, 510336, 510336, 1152, 2304, 0xf09d7640 -0, 511488, 511488, 1152, 2304, 0xaebb718f -0, 512640, 512640, 1152, 2304, 0x0c8570f4 -0, 513792, 513792, 1152, 2304, 0x3c93862c -0, 514944, 514944, 1152, 2304, 0xcee46696 -0, 516096, 516096, 1152, 2304, 0x01ba7e20 -0, 517248, 517248, 1152, 2304, 0x7fcb7a09 -0, 518400, 518400, 1152, 2304, 0xddf18c14 -0, 519552, 519552, 1152, 2304, 0xd2e97eeb -0, 520704, 520704, 1152, 2304, 0x514d8719 -0, 521856, 521856, 1152, 2304, 0xe89279c9 -0, 523008, 523008, 1152, 2304, 0x806d6a95 -0, 524160, 524160, 1152, 2304, 0xbc7a8a60 -0, 525312, 525312, 1152, 2304, 0x302f8fa8 -0, 526464, 526464, 1152, 2304, 0xb136784c -0, 527616, 527616, 1152, 2304, 0x9b0f6aab -0, 528768, 528768, 1152, 2304, 0xd8e27582 -0, 529920, 529920, 1152, 2304, 0xdaaf78b1 -0, 531072, 531072, 1152, 2304, 0x65967f5f -0, 532224, 532224, 1152, 2304, 0x6f917aa4 -0, 533376, 533376, 1152, 2304, 0x7f607444 -0, 534528, 534528, 1152, 2304, 0xfd316f2c -0, 535680, 535680, 1152, 2304, 0x776e83c7 -0, 536832, 536832, 1152, 2304, 0xb9c17e16 -0, 537984, 537984, 1152, 2304, 0xdf287de8 -0, 539136, 539136, 1152, 2304, 0xf33d96a3 -0, 540288, 540288, 1152, 2304, 0xad216e5b -0, 541440, 541440, 1152, 2304, 0x4a328342 -0, 542592, 542592, 1152, 2304, 0xcf3f8079 -0, 543744, 543744, 1152, 2304, 0xb46f77b0 -0, 544896, 544896, 1152, 2304, 0x3199713d -0, 546048, 546048, 1152, 2304, 0x5e667a0d -0, 547200, 547200, 1152, 2304, 0xa3047ae3 -0, 548352, 548352, 1152, 2304, 0x9edf8594 -0, 549504, 549504, 1152, 2304, 0xd16382d5 -0, 550656, 550656, 1152, 2304, 0x6e838328 -0, 551808, 551808, 1152, 2304, 0xa1f697c1 -0, 552960, 552960, 1152, 2304, 0xefcc749c -0, 554112, 554112, 1152, 2304, 0x1f94839e -0, 555264, 555264, 1152, 2304, 0x429e7c5b -0, 556416, 556416, 1152, 2304, 0x9b59711c -0, 557568, 557568, 1152, 2304, 0xdac27323 -0, 558720, 558720, 1152, 2304, 0xa4856d2b -0, 559872, 559872, 1152, 2304, 0x07a37498 -0, 561024, 561024, 1152, 2304, 0xe1ce7512 -0, 562176, 562176, 1152, 2304, 0x15e182c3 -0, 563328, 563328, 1152, 2304, 0x0fa46b8c -0, 564480, 564480, 1152, 2304, 0xbdf07bfd -0, 565632, 565632, 1152, 2304, 0xe0238b2a -0, 566784, 566784, 1152, 2304, 0xab537267 -0, 567936, 567936, 1152, 2304, 0xd46b75f3 -0, 569088, 569088, 1152, 2304, 0xec73794b -0, 570240, 570240, 1152, 2304, 0x680580c1 -0, 571392, 571392, 1152, 2304, 0x1ace8f6c -0, 572544, 572544, 1152, 2304, 0x19d583ac -0, 573696, 573696, 1152, 2304, 0x4b6b8105 -0, 574848, 574848, 1152, 2304, 0x392a78b2 -0, 576000, 576000, 1152, 2304, 0xd3916dad -0, 577152, 577152, 1152, 2304, 0x569c7a75 -0, 578304, 578304, 1152, 2304, 0xf5ac814b -0, 579456, 579456, 1152, 2304, 0x18d77e98 -0, 580608, 580608, 1152, 2304, 0x007074ce -0, 581760, 581760, 1152, 2304, 0x0fe38373 -0, 582912, 582912, 1152, 2304, 0x5a967920 -0, 584064, 584064, 1152, 2304, 0x22167501 -0, 585216, 585216, 1152, 2304, 0xf0828cab -0, 586368, 586368, 1152, 2304, 0xaeec71b7 -0, 587520, 587520, 1152, 2304, 0xc47b62ff -0, 588672, 588672, 1152, 2304, 0xab688478 -0, 589824, 589824, 1152, 2304, 0xf35e7bd2 -0, 590976, 590976, 1152, 2304, 0x9cff763e -0, 592128, 592128, 1152, 2304, 0x59568dc8 -0, 593280, 593280, 1152, 2304, 0x51a278ac -0, 594432, 594432, 1152, 2304, 0xc08a6e68 -0, 595584, 595584, 1152, 2304, 0xd3067ef4 -0, 596736, 596736, 1152, 2304, 0x54767c49 -0, 597888, 597888, 1152, 2304, 0xf8ff8386 -0, 599040, 599040, 1152, 2304, 0xef267f63 -0, 600192, 600192, 1152, 2304, 0xe2537cd9 -0, 601344, 601344, 1152, 2304, 0x77a57680 -0, 602496, 602496, 1152, 2304, 0x325c74ad -0, 603648, 603648, 1152, 2304, 0xd7fe87c4 -0, 604800, 604800, 1152, 2304, 0x2e756310 -0, 605952, 605952, 1152, 2304, 0x6a81796b -0, 607104, 607104, 1152, 2304, 0x2f057daf -0, 608256, 608256, 1152, 2304, 0xcd9f7c9d -0, 609408, 609408, 1152, 2304, 0xc91560a0 -0, 610560, 610560, 1152, 2304, 0x962a91eb -0, 611712, 611712, 1152, 2304, 0xa0ff7416 -0, 612864, 612864, 1152, 2304, 0xcb5c7dff -0, 614016, 614016, 1152, 2304, 0xd3527041 -0, 615168, 615168, 1152, 2304, 0xc89d77c2 -0, 616320, 616320, 1152, 2304, 0xe1ce7ccf -0, 617472, 617472, 1152, 2304, 0xe3417c4c -0, 618624, 618624, 1152, 2304, 0x3f1a7166 -0, 619776, 619776, 1152, 2304, 0xcdcc7e23 -0, 620928, 620928, 1152, 2304, 0x4e727e97 -0, 622080, 622080, 1152, 2304, 0x53427ff1 -0, 623232, 623232, 1152, 2304, 0x173f6ca9 -0, 624384, 624384, 1152, 2304, 0x962887ec -0, 625536, 625536, 1152, 2304, 0xcbec67f4 -0, 626688, 626688, 1152, 2304, 0x7a2c943d -0, 627840, 627840, 1152, 2304, 0x8b877570 -0, 628992, 628992, 1152, 2304, 0xcf337323 -0, 630144, 630144, 1152, 2304, 0x8c8682a4 -0, 631296, 631296, 1152, 2304, 0x94c3753c -0, 632448, 632448, 1152, 2304, 0x86898d79 -0, 633600, 633600, 1152, 2304, 0xdf667312 -0, 634752, 634752, 1152, 2304, 0x062f8ba8 -0, 635904, 635904, 1152, 2304, 0xa2c36f08 -0, 637056, 637056, 1152, 2304, 0x5bca7358 -0, 638208, 638208, 1152, 2304, 0x5648804d -0, 639360, 639360, 1152, 2304, 0xefac87c8 -0, 640512, 640512, 1152, 2304, 0x66bf7dcf -0, 641664, 641664, 1152, 2304, 0x62ad73bc -0, 642816, 642816, 1152, 2304, 0x72fe630c -0, 643968, 643968, 1152, 2304, 0xeebe87da -0, 645120, 645120, 1152, 2304, 0x11c870cf -0, 646272, 646272, 1152, 2304, 0x18fb7c27 -0, 647424, 647424, 1152, 2304, 0x39047145 -0, 648576, 648576, 1152, 2304, 0xdcf07032 -0, 649728, 649728, 1152, 2304, 0x61027c50 -0, 650880, 650880, 1152, 2304, 0x6e2e89de -0, 652032, 652032, 1152, 2304, 0xc50c6d1d -0, 653184, 653184, 1152, 2304, 0xeed587ee -0, 654336, 654336, 1152, 2304, 0xe38269c7 -0, 655488, 655488, 1152, 2304, 0xcf66806e -0, 656640, 656640, 1152, 2304, 0x2d3b7c1b -0, 657792, 657792, 1152, 2304, 0xa4127d48 -0, 658944, 658944, 1152, 2304, 0x480b8325 -0, 660096, 660096, 1152, 2304, 0xc1527221 -0, 661248, 661248, 1152, 2304, 0x94c1769a -0, 662400, 662400, 1152, 2304, 0xcfb37271 -0, 663552, 663552, 1152, 2304, 0x946d7a96 -0, 664704, 664704, 1152, 2304, 0xdfc18e50 -0, 665856, 665856, 1152, 2304, 0x10c48393 -0, 667008, 667008, 1152, 2304, 0x58556b10 -0, 668160, 668160, 1152, 2304, 0x997b7993 -0, 669312, 669312, 1152, 2304, 0x4a787992 -0, 670464, 670464, 1152, 2304, 0x11406c20 -0, 671616, 671616, 1152, 2304, 0x04a4874a -0, 672768, 672768, 1152, 2304, 0xf3077164 -0, 673920, 673920, 1152, 2304, 0x08ac80e3 -0, 675072, 675072, 1152, 2304, 0x268370d0 -0, 676224, 676224, 1152, 2304, 0x1d137778 -0, 677376, 677376, 1152, 2304, 0xfa148e97 -0, 678528, 678528, 1152, 2304, 0xec50717c -0, 679680, 679680, 1152, 2304, 0xcbf46b75 -0, 680832, 680832, 1152, 2304, 0xd4168038 -0, 681984, 681984, 1152, 2304, 0xdd9577f0 -0, 683136, 683136, 1152, 2304, 0xc7077685 -0, 684288, 684288, 1152, 2304, 0x34d25e91 -0, 685440, 685440, 1152, 2304, 0x96537e6d -0, 686592, 686592, 1152, 2304, 0xb12e7940 -0, 687744, 687744, 1152, 2304, 0x861d64c0 -0, 688896, 688896, 1152, 2304, 0xa2bc64ed -0, 690048, 690048, 1152, 2304, 0x0c5f8261 -0, 691200, 691200, 1152, 2304, 0x540584ff -0, 692352, 692352, 1152, 2304, 0xe8328b09 -0, 693504, 693504, 1152, 2304, 0x1e777079 -0, 694656, 694656, 1152, 2304, 0x453483b4 -0, 695808, 695808, 1152, 2304, 0x1cab7a1e -0, 696960, 696960, 1152, 2304, 0xcb37856d -0, 698112, 698112, 1152, 2304, 0x5a4883ed -0, 699264, 699264, 1152, 2304, 0xd1f27cbf -0, 700416, 700416, 1152, 2304, 0x0d377a4d -0, 701568, 701568, 1152, 2304, 0x264e76df -0, 702720, 702720, 1152, 2304, 0x2a68771e -0, 703872, 703872, 1152, 2304, 0xcb317a31 -0, 705024, 705024, 1152, 2304, 0xfc5d7a27 -0, 706176, 706176, 1152, 2304, 0x6e067d96 -0, 707328, 707328, 1152, 2304, 0x0c538560 -0, 708480, 708480, 1152, 2304, 0xfbad717a -0, 709632, 709632, 1152, 2304, 0xf9fc7608 -0, 710784, 710784, 1152, 2304, 0xb1817c8f -0, 711936, 711936, 1152, 2304, 0x57c37f82 -0, 713088, 713088, 1152, 2304, 0x8cac8356 -0, 714240, 714240, 1152, 2304, 0x97108186 -0, 715392, 715392, 1152, 2304, 0x095d81bb -0, 716544, 716544, 1152, 2304, 0x475f6b2b -0, 717696, 717696, 1152, 2304, 0xdf7c8cc5 -0, 718848, 718848, 1152, 2304, 0x979c77be -0, 720000, 720000, 1152, 2304, 0x56a7844b -0, 721152, 721152, 1152, 2304, 0x7ee46b21 -0, 722304, 722304, 1152, 2304, 0x05b67220 -0, 723456, 723456, 1152, 2304, 0x25787252 -0, 724608, 724608, 1152, 2304, 0x8ad278ad -0, 725760, 725760, 1152, 2304, 0x67bd722e -0, 726912, 726912, 1152, 2304, 0x204f77be -0, 728064, 728064, 1152, 2304, 0x82d27ae2 -0, 729216, 729216, 1152, 2304, 0x23fa82e4 -0, 730368, 730368, 1152, 2304, 0xa9cf8159 -0, 731520, 731520, 1152, 2304, 0x13f08749 -0, 732672, 732672, 1152, 2304, 0xf84f71b5 -0, 733824, 733824, 1152, 2304, 0x1cb777c8 -0, 734976, 734976, 1152, 2304, 0x11236722 -0, 736128, 736128, 1152, 2304, 0x10197cac -0, 737280, 737280, 1152, 2304, 0xbd417e65 -0, 738432, 738432, 1152, 2304, 0x9a1c7d05 -0, 739584, 739584, 1152, 2304, 0x4c3a85de -0, 740736, 740736, 1152, 2304, 0x03816eb7 -0, 741888, 741888, 1152, 2304, 0x80186e6c -0, 743040, 743040, 1152, 2304, 0x5c097928 -0, 744192, 744192, 1152, 2304, 0x94aa823d -0, 745344, 745344, 1152, 2304, 0xa1c27f04 -0, 746496, 746496, 1152, 2304, 0x6ddb74a9 -0, 747648, 747648, 1152, 2304, 0x5ea67901 -0, 748800, 748800, 1152, 2304, 0xd710742d -0, 749952, 749952, 1152, 2304, 0xf8c27add -0, 751104, 751104, 1152, 2304, 0xf1717011 -0, 752256, 752256, 1152, 2304, 0xb59072d0 -0, 753408, 753408, 1152, 2304, 0xc8dc84a7 -0, 754560, 754560, 1152, 2304, 0x33116737 -0, 755712, 755712, 1152, 2304, 0x86216bdd -0, 756864, 756864, 1152, 2304, 0xa2f87866 -0, 758016, 758016, 1152, 2304, 0x5d77771e -0, 759168, 759168, 1152, 2304, 0x5d8c77fd -0, 760320, 760320, 1152, 2304, 0x23cc89cb -0, 761472, 761472, 1152, 2304, 0x334e7407 -0, 762624, 762624, 1152, 2304, 0x01c976ff -0, 763776, 763776, 1152, 2304, 0x3a3b7b15 -0, 764928, 764928, 1152, 2304, 0xfa427de9 -0, 766080, 766080, 1152, 2304, 0xbeaa7c91 -0, 767232, 767232, 1152, 2304, 0xd6988b31 -0, 768384, 768384, 1152, 2304, 0x4db47f80 -0, 769536, 769536, 1152, 2304, 0xea687d9e -0, 770688, 770688, 1152, 2304, 0x1a6281ce -0, 771840, 771840, 1152, 2304, 0xe1958003 -0, 772992, 772992, 1152, 2304, 0xb4ae7c5e -0, 774144, 774144, 1152, 2304, 0x28827c8a -0, 775296, 775296, 1152, 2304, 0x1fb88b25 -0, 776448, 776448, 1152, 2304, 0x588d71e8 -0, 777600, 777600, 1152, 2304, 0x68227c34 -0, 778752, 778752, 1152, 2304, 0xee4d73e8 -0, 779904, 779904, 1152, 2304, 0x69287c6d -0, 781056, 781056, 1152, 2304, 0xbb04926a -0, 782208, 782208, 1152, 2304, 0x89456cec -0, 783360, 783360, 1152, 2304, 0xabe18992 -0, 784512, 784512, 1152, 2304, 0x50cc7f6c -0, 785664, 785664, 1152, 2304, 0x6d7270be -0, 786816, 786816, 1152, 2304, 0x664c6fef -0, 787968, 787968, 1152, 2304, 0x7f7982f3 -0, 789120, 789120, 1152, 2304, 0x6ca170e9 -0, 790272, 790272, 1152, 2304, 0x36437d5b -0, 791424, 791424, 1152, 2304, 0xfd2380e8 -0, 792576, 792576, 1152, 2304, 0x2e3c6e9f -0, 793728, 793728, 1152, 2304, 0xc8427f3f -0, 794880, 794880, 1152, 2304, 0x962a79ad -0, 796032, 796032, 1152, 2304, 0xc9597c8b -0, 797184, 797184, 1152, 2304, 0x899580bb -0, 798336, 798336, 1152, 2304, 0x2d179dff -0, 799488, 799488, 1152, 2304, 0x4ac1707c -0, 800640, 800640, 1152, 2304, 0x32ea7e95 -0, 801792, 801792, 1152, 2304, 0x265e9a2d -0, 802944, 802944, 1152, 2304, 0x1c6484d0 -0, 804096, 804096, 1152, 2304, 0x39ae6884 -0, 805248, 805248, 1152, 2304, 0x82ed7bc5 -0, 806400, 806400, 1152, 2304, 0x556b7b3c -0, 807552, 807552, 1152, 2304, 0xb7f778dd -0, 808704, 808704, 1152, 2304, 0x74447d55 -0, 809856, 809856, 1152, 2304, 0x0c66861e -0, 811008, 811008, 1152, 2304, 0x15ba7932 -0, 812160, 812160, 1152, 2304, 0xb19170fc -0, 813312, 813312, 1152, 2304, 0x19d37551 -0, 814464, 814464, 1152, 2304, 0xdc529142 -0, 815616, 815616, 1152, 2304, 0xf2637e77 -0, 816768, 816768, 1152, 2304, 0xd065944b -0, 817920, 817920, 1152, 2304, 0x22878123 -0, 819072, 819072, 1152, 2304, 0xc21a8bf7 -0, 820224, 820224, 1152, 2304, 0x2e3582dc -0, 821376, 821376, 1152, 2304, 0xd42f7987 -0, 822528, 822528, 1152, 2304, 0x69b88236 -0, 823680, 823680, 1152, 2304, 0x7c988f90 -0, 824832, 824832, 1152, 2304, 0x2cd66ded -0, 825984, 825984, 1152, 2304, 0x3e65828b -0, 827136, 827136, 1152, 2304, 0x7e9871c9 -0, 828288, 828288, 1152, 2304, 0xf1f2806b -0, 829440, 829440, 1152, 2304, 0xf5087c7b -0, 830592, 830592, 1152, 2304, 0x62b98097 -0, 831744, 831744, 1152, 2304, 0xec457c43 -0, 832896, 832896, 1152, 2304, 0x87af87a6 -0, 834048, 834048, 1152, 2304, 0x97cc757d -0, 835200, 835200, 1152, 2304, 0x08ca76bd -0, 836352, 836352, 1152, 2304, 0x14ae7cbd -0, 837504, 837504, 1152, 2304, 0x1f79709a -0, 838656, 838656, 1152, 2304, 0x17948207 -0, 839808, 839808, 1152, 2304, 0x16ee7228 -0, 840960, 840960, 1152, 2304, 0x76cc82d7 -0, 842112, 842112, 1152, 2304, 0x8f327a8e -0, 843264, 843264, 1152, 2304, 0x14ee7756 -0, 844416, 844416, 1152, 2304, 0x15996d2f -0, 845568, 845568, 1152, 2304, 0x4c707d5c -0, 846720, 846720, 1152, 2304, 0x268c6fee -0, 847872, 847872, 1152, 2304, 0x6d838c76 -0, 849024, 849024, 1152, 2304, 0xafa17e64 -0, 850176, 850176, 1152, 2304, 0xb6546e66 -0, 851328, 851328, 1152, 2304, 0x945d8b9f -0, 852480, 852480, 1152, 2304, 0x5bfb7446 -0, 853632, 853632, 1152, 2304, 0xae6086f9 -0, 854784, 854784, 1152, 2304, 0xa01380cd -0, 855936, 855936, 1152, 2304, 0x06f0828f -0, 857088, 857088, 1152, 2304, 0x0ae07176 -0, 858240, 858240, 1152, 2304, 0x66f07522 -0, 859392, 859392, 1152, 2304, 0x44018106 -0, 860544, 860544, 1152, 2304, 0x8cd283da -0, 861696, 861696, 1152, 2304, 0x14257f45 -0, 862848, 862848, 1152, 2304, 0x04979537 -0, 864000, 864000, 1152, 2304, 0x8b5f797c -0, 865152, 865152, 1152, 2304, 0x12d67493 -0, 866304, 866304, 1152, 2304, 0xc8886a25 -0, 867456, 867456, 1152, 2304, 0x614b803a -0, 868608, 868608, 1152, 2304, 0x75667d35 -0, 869760, 869760, 1152, 2304, 0xe42c7b00 -0, 870912, 870912, 1152, 2304, 0x37787927 -0, 872064, 872064, 1152, 2304, 0x85db8409 -0, 873216, 873216, 1152, 2304, 0x823b822c -0, 874368, 874368, 1152, 2304, 0xa1658479 -0, 875520, 875520, 1152, 2304, 0xdbe58ff7 -0, 876672, 876672, 1152, 2304, 0x725175e2 -0, 877824, 877824, 1152, 2304, 0xb2ae7741 -0, 878976, 878976, 1152, 2304, 0x4de169e4 -0, 880128, 880128, 1152, 2304, 0x3cb18530 -0, 881280, 881280, 1152, 2304, 0x5a0c5e7b -0, 882432, 882432, 1152, 2304, 0x4e1f68b6 -0, 883584, 883584, 1152, 2304, 0x9a0c7525 -0, 884736, 884736, 1152, 2304, 0x86ae6a04 -0, 885888, 885888, 1152, 2304, 0xf508877c -0, 887040, 887040, 1152, 2304, 0x29746d7c -0, 888192, 888192, 1152, 2304, 0x24078edb -0, 889344, 889344, 1152, 2304, 0x4f9784d2 -0, 890496, 890496, 1152, 2304, 0x24186e95 -0, 891648, 891648, 1152, 2304, 0xd1927b28 -0, 892800, 892800, 1152, 2304, 0xc77283d5 -0, 893952, 893952, 1152, 2304, 0xc0ad73f8 -0, 895104, 895104, 1152, 2304, 0x0de78524 -0, 896256, 896256, 1152, 2304, 0x8b0061dc -0, 897408, 897408, 1152, 2304, 0x37c77ad6 -0, 898560, 898560, 1152, 2304, 0x5eae7410 -0, 899712, 899712, 1152, 2304, 0x72d97ab5 -0, 900864, 900864, 1152, 2304, 0x1afd8745 -0, 902016, 902016, 1152, 2304, 0xe30b7c9b -0, 903168, 903168, 1152, 2304, 0xe86480b3 -0, 904320, 904320, 1152, 2304, 0xb9c77a4e -0, 905472, 905472, 1152, 2304, 0x64508f2a -0, 906624, 906624, 1152, 2304, 0x839a74ed -0, 907776, 907776, 1152, 2304, 0x12147a5d -0, 908928, 908928, 1152, 2304, 0x33b07d3b -0, 910080, 910080, 1152, 2304, 0x65e67731 -0, 911232, 911232, 1152, 2304, 0x8d1c8191 -0, 912384, 912384, 1152, 2304, 0xada17701 -0, 913536, 913536, 1152, 2304, 0x49d47f6c -0, 914688, 914688, 1152, 2304, 0x5df97989 -0, 915840, 915840, 1152, 2304, 0x0db17ad9 -0, 916992, 916992, 1152, 2304, 0x0d3281d7 -0, 918144, 918144, 1152, 2304, 0x2503704f -0, 919296, 919296, 1152, 2304, 0xdf7c73d0 -0, 920448, 920448, 1152, 2304, 0x93dd737c -0, 921600, 921600, 1152, 2304, 0x48ed5740 -0, 922752, 922752, 1152, 2304, 0x6d477eaf -0, 923904, 923904, 1152, 2304, 0xe72373a1 -0, 925056, 925056, 1152, 2304, 0x7d3e7e2e -0, 926208, 926208, 1152, 2304, 0x0d167743 -0, 927360, 927360, 1152, 2304, 0xc2d97f6c -0, 928512, 928512, 1152, 2304, 0xc66175a0 -0, 929664, 929664, 1152, 2304, 0xd0127475 -0, 930816, 930816, 1152, 2304, 0xdbf57801 -0, 931968, 931968, 1152, 2304, 0x52b47a8e -0, 933120, 933120, 1152, 2304, 0xc96b80c5 -0, 934272, 934272, 1152, 2304, 0x070c76cf -0, 935424, 935424, 1152, 2304, 0x2aa07ee2 -0, 936576, 936576, 1152, 2304, 0x04059074 -0, 937728, 937728, 1152, 2304, 0x228f6def -0, 938880, 938880, 1152, 2304, 0x927893a8 -0, 940032, 940032, 1152, 2304, 0x581a87df -0, 941184, 941184, 1152, 2304, 0x0d3f653c -0, 942336, 942336, 1152, 2304, 0xc0e775f3 -0, 943488, 943488, 1152, 2304, 0x41d98473 -0, 944640, 944640, 1152, 2304, 0x68fb775a -0, 945792, 945792, 1152, 2304, 0x81e0810e -0, 946944, 946944, 1152, 2304, 0xf35790d3 -0, 948096, 948096, 1152, 2304, 0xc1468c45 -0, 949248, 949248, 1152, 2304, 0x6949796a -0, 950400, 950400, 1152, 2304, 0xa0bb7dcd -0, 951552, 951552, 1152, 2304, 0x50af8424 -0, 952704, 952704, 1152, 2304, 0x449b7d37 -0, 953856, 953856, 1152, 2304, 0xcf2779a8 -0, 955008, 955008, 1152, 2304, 0x069d894e -0, 956160, 956160, 1152, 2304, 0x41bd7334 -0, 957312, 957312, 1152, 2304, 0x0dfd8c05 -0, 958464, 958464, 1152, 2304, 0x2ce27b9d -0, 959616, 959616, 1152, 2304, 0x422875b5 -0, 960768, 960768, 1152, 2304, 0xd5297389 -0, 961920, 961920, 1152, 2304, 0x49ed8668 -0, 963072, 963072, 1152, 2304, 0x2a9a810b -0, 964224, 964224, 1152, 2304, 0x5a3f7b43 -0, 965376, 965376, 1152, 2304, 0x32087c12 -0, 966528, 966528, 1152, 2304, 0x759c7bba -0, 967680, 967680, 1152, 2304, 0x5b26823b -0, 968832, 968832, 1152, 2304, 0xeeb872ef -0, 969984, 969984, 1152, 2304, 0x6eb0869d -0, 971136, 971136, 1152, 2304, 0x4b3e764f -0, 972288, 972288, 1152, 2304, 0x30a66fdb -0, 973440, 973440, 1152, 2304, 0x958374ff -0, 974592, 974592, 1152, 2304, 0x411b71cc -0, 975744, 975744, 1152, 2304, 0x80136759 -0, 976896, 976896, 1152, 2304, 0x05ed6793 -0, 978048, 978048, 1152, 2304, 0x48f18827 -0, 979200, 979200, 1152, 2304, 0xb40d7866 -0, 980352, 980352, 1152, 2304, 0xcad18c4a -0, 981504, 981504, 1152, 2304, 0x9ad68582 -0, 982656, 982656, 1152, 2304, 0x3ad17fce -0, 983808, 983808, 1152, 2304, 0x824b7af6 -0, 984960, 984960, 1152, 2304, 0xcc9d894f -0, 986112, 986112, 1152, 2304, 0x46167a70 -0, 987264, 987264, 1152, 2304, 0x2479872a -0, 988416, 988416, 1152, 2304, 0x58cb72a5 -0, 989568, 989568, 1152, 2304, 0x01957747 -0, 990720, 990720, 1152, 2304, 0x6df172cb -0, 991872, 991872, 1152, 2304, 0x9ebd7ed9 -0, 993024, 993024, 1152, 2304, 0x89436a53 -0, 994176, 994176, 1152, 2304, 0xcce78433 -0, 995328, 995328, 1152, 2304, 0x1b7a70f2 -0, 996480, 996480, 1152, 2304, 0x530584d7 -0, 997632, 997632, 1152, 2304, 0xda158aa9 -0, 998784, 998784, 1152, 2304, 0xe85e7b90 -0, 999936, 999936, 1152, 2304, 0xa8ac8176 -0, 1001088, 1001088, 1152, 2304, 0xe43578a9 -0, 1002240, 1002240, 1152, 2304, 0x9ecc7c30 -0, 1003392, 1003392, 1152, 2304, 0x1cbd8591 -0, 1004544, 1004544, 1152, 2304, 0x84917bd9 -0, 1005696, 1005696, 1152, 2304, 0xea8477e4 -0, 1006848, 1006848, 1152, 2304, 0xf50c7ea1 -0, 1008000, 1008000, 1152, 2304, 0xc85e76e7 -0, 1009152, 1009152, 1152, 2304, 0xa5148768 -0, 1010304, 1010304, 1152, 2304, 0x2bd5846a -0, 1011456, 1011456, 1152, 2304, 0x1cd88641 -0, 1012608, 1012608, 1152, 2304, 0x04b883c5 -0, 1013760, 1013760, 1152, 2304, 0x5bf1719b -0, 1014912, 1014912, 1152, 2304, 0x0abe777c -0, 1016064, 1016064, 1152, 2304, 0xc74a7f7f -0, 1017216, 1017216, 1152, 2304, 0xd36a724b -0, 1018368, 1018368, 1152, 2304, 0x4ae67e9e -0, 1019520, 1019520, 1152, 2304, 0xfb6173a0 -0, 1020672, 1020672, 1152, 2304, 0x31d77e19 -0, 1021824, 1021824, 1152, 2304, 0x6153767d -0, 1022976, 1022976, 1152, 2304, 0xe40d84e4 -0, 1024128, 1024128, 1152, 2304, 0xc8ef71e2 -0, 1025280, 1025280, 1152, 2304, 0xdeca81be -0, 1026432, 1026432, 1152, 2304, 0x75da85df -0, 1027584, 1027584, 1152, 2304, 0x6c8e71bd -0, 1028736, 1028736, 1152, 2304, 0x6f8576a4 -0, 1029888, 1029888, 1152, 2304, 0xe6637b71 -0, 1031040, 1031040, 1152, 2304, 0xddfe8866 -0, 1032192, 1032192, 1152, 2304, 0xa08578a5 -0, 1033344, 1033344, 1152, 2304, 0x72af7873 -0, 1034496, 1034496, 1152, 2304, 0xb550615c -0, 1035648, 1035648, 1152, 2304, 0x9ef87d28 -0, 1036800, 1036800, 1152, 2304, 0xe30d83bf -0, 1037952, 1037952, 1152, 2304, 0xf030818c -0, 1039104, 1039104, 1152, 2304, 0x1e23896c -0, 1040256, 1040256, 1152, 2304, 0xf4c87180 -0, 1041408, 1041408, 1152, 2304, 0xe34181aa -0, 1042560, 1042560, 1152, 2304, 0x660681cb -0, 1043712, 1043712, 1152, 2304, 0x7ebb87fc -0, 1044864, 1044864, 1152, 2304, 0xa8305eeb -0, 1046016, 1046016, 1152, 2304, 0xea898906 -0, 1047168, 1047168, 1152, 2304, 0x342b6c13 -0, 1048320, 1048320, 1152, 2304, 0x7fd18372 -0, 1049472, 1049472, 1152, 2304, 0x965c7377 -0, 1050624, 1050624, 1152, 2304, 0xb53b70b3 -0, 1051776, 1051776, 1152, 2304, 0xd54884d1 -0, 1052928, 1052928, 1152, 2304, 0x546d77ac -0, 1054080, 1054080, 1152, 2304, 0xd7a77dc7 -0, 1055232, 1055232, 1152, 2304, 0x4b0e7c5c -0, 1056384, 1056384, 1152, 2304, 0x346d7026 -0, 1057536, 1057536, 1152, 2304, 0x3f346e81 -0, 1058688, 1058688, 1152, 2304, 0x3f167098 -0, 1059840, 1059840, 1152, 2304, 0x1c857987 -0, 1060992, 1060992, 1152, 2304, 0xf9317c16 -0, 1062144, 1062144, 1152, 2304, 0x25ea82c4 -0, 1063296, 1063296, 1152, 2304, 0x2b0f90bb -0, 1064448, 1064448, 1152, 2304, 0x999668db -0, 1065600, 1065600, 1152, 2304, 0x9a0676da -0, 1066752, 1066752, 1152, 2304, 0x97a87172 -0, 1067904, 1067904, 1152, 2304, 0x323d7ace -0, 1069056, 1069056, 1152, 2304, 0x1b538baa -0, 1070208, 1070208, 1152, 2304, 0xeb208b72 -0, 1071360, 1071360, 1152, 2304, 0x36c69152 -0, 1072512, 1072512, 1152, 2304, 0x570c7bac -0, 1073664, 1073664, 1152, 2304, 0xd7287c72 -0, 1074816, 1074816, 1152, 2304, 0xc4d78776 -0, 1075968, 1075968, 1152, 2304, 0xdcbb7735 -0, 1077120, 1077120, 1152, 2304, 0x08066d78 -0, 1078272, 1078272, 1152, 2304, 0x5cb96bad -0, 1079424, 1079424, 1152, 2304, 0x30d58180 -0, 1080576, 1080576, 1152, 2304, 0x3ac96b87 -0, 1081728, 1081728, 1152, 2304, 0x1fc878d2 -0, 1082880, 1082880, 1152, 2304, 0x2c7c85d4 -0, 1084032, 1084032, 1152, 2304, 0x6c307caa -0, 1085184, 1085184, 1152, 2304, 0x647b6d6e -0, 1086336, 1086336, 1152, 2304, 0xfbef7e51 -0, 1087488, 1087488, 1152, 2304, 0x27867bd7 -0, 1088640, 1088640, 1152, 2304, 0xa2b875b1 -0, 1089792, 1089792, 1152, 2304, 0xc7dd73fb -0, 1090944, 1090944, 1152, 2304, 0x717e79e9 -0, 1092096, 1092096, 1152, 2304, 0xfecb710d -0, 1093248, 1093248, 1152, 2304, 0xa5308333 -0, 1094400, 1094400, 1152, 2304, 0x92fe6b77 -0, 1095552, 1095552, 1152, 2304, 0x7db17ad6 -0, 1096704, 1096704, 1152, 2304, 0x1248786d -0, 1097856, 1097856, 1152, 2304, 0xf3647a8a -0, 1099008, 1099008, 1152, 2304, 0x7b2173f0 -0, 1100160, 1100160, 1152, 2304, 0xfd1f7a3c -0, 1101312, 1101312, 1152, 2304, 0x09e57f3e -0, 1102464, 1102464, 1152, 2304, 0x13d7798d -0, 1103616, 1103616, 1152, 2304, 0x7d4d758a -0, 1104768, 1104768, 1152, 2304, 0xdf1a80be -0, 1105920, 1105920, 1152, 2304, 0xb91b7cb9 -0, 1107072, 1107072, 1152, 2304, 0x102e73ba -0, 1108224, 1108224, 1152, 2304, 0x8dce8428 -0, 1109376, 1109376, 1152, 2304, 0xdf9070f6 -0, 1110528, 1110528, 1152, 2304, 0x27d77bb4 -0, 1111680, 1111680, 1152, 2304, 0x2f8a8579 -0, 1112832, 1112832, 1152, 2304, 0xd1e27204 -0, 1113984, 1113984, 1152, 2304, 0x4f087920 -0, 1115136, 1115136, 1152, 2304, 0x69f58306 -0, 1116288, 1116288, 1152, 2304, 0xfc7378b0 -0, 1117440, 1117440, 1152, 2304, 0x8b167d89 -0, 1118592, 1118592, 1152, 2304, 0x0c867235 -0, 1119744, 1119744, 1152, 2304, 0xc3126e09 -0, 1120896, 1120896, 1152, 2304, 0x7d097d89 -0, 1122048, 1122048, 1152, 2304, 0x73dc664e -0, 1123200, 1123200, 1152, 2304, 0xdc247a0a -0, 1124352, 1124352, 1152, 2304, 0xaa8d7f2f -0, 1125504, 1125504, 1152, 2304, 0x9a1d744b -0, 1126656, 1126656, 1152, 2304, 0xd9e87475 -0, 1127808, 1127808, 1152, 2304, 0xf6f182ab -0, 1128960, 1128960, 1152, 2304, 0x4937706b -0, 1130112, 1130112, 1152, 2304, 0x837189b1 -0, 1131264, 1131264, 1152, 2304, 0xd565975d -0, 1132416, 1132416, 1152, 2304, 0xc6156a56 -0, 1133568, 1133568, 1152, 2304, 0xcd9c8107 -0, 1134720, 1134720, 1152, 2304, 0x1f868400 -0, 1135872, 1135872, 1152, 2304, 0xeddb71e0 -0, 1137024, 1137024, 1152, 2304, 0x5fa2782a -0, 1138176, 1138176, 1152, 2304, 0x9b076e22 -0, 1139328, 1139328, 1152, 2304, 0x90027ba7 -0, 1140480, 1140480, 1152, 2304, 0x40a481fd -0, 1141632, 1141632, 1152, 2304, 0x240873bf -0, 1142784, 1142784, 1152, 2304, 0x28cd7d8e -0, 1143936, 1143936, 1152, 2304, 0x5d4287b0 -0, 1145088, 1145088, 1152, 2304, 0xf9567c4b -0, 1146240, 1146240, 1152, 2304, 0x67dd924a -0, 1147392, 1147392, 1152, 2304, 0x33d37b4c -0, 1148544, 1148544, 1152, 2304, 0x37316d0b -0, 1149696, 1149696, 1152, 2304, 0x43a877dc -0, 1150848, 1150848, 1152, 2304, 0x44fc90bc -0, 1152000, 1152000, 1152, 2304, 0x90f5774c -0, 1153152, 1153152, 1152, 2304, 0x106e85a0 -0, 1154304, 1154304, 1152, 2304, 0xb78b7f83 -0, 1155456, 1155456, 1152, 2304, 0x3c3a77af -0, 1156608, 1156608, 1152, 2304, 0x7a5f7282 -0, 1157760, 1157760, 1152, 2304, 0x164d891a -0, 1158912, 1158912, 1152, 2304, 0x930a7194 -0, 1160064, 1160064, 1152, 2304, 0xb2628013 -0, 1161216, 1161216, 1152, 2304, 0x3adf7e1c -0, 1162368, 1162368, 1152, 2304, 0x48627c45 -0, 1163520, 1163520, 1152, 2304, 0xa3367cca -0, 1164672, 1164672, 1152, 2304, 0x9cf77248 -0, 1165824, 1165824, 1152, 2304, 0x75a86acb -0, 1166976, 1166976, 1152, 2304, 0x75487698 -0, 1168128, 1168128, 1152, 2304, 0xd65b8389 -0, 1169280, 1169280, 1152, 2304, 0xb71d84b5 -0, 1170432, 1170432, 1152, 2304, 0xdca87e42 -0, 1171584, 1171584, 1152, 2304, 0x44dd7d72 -0, 1172736, 1172736, 1152, 2304, 0xb29465da -0, 1173888, 1173888, 1152, 2304, 0x88ed8930 -0, 1175040, 1175040, 1152, 2304, 0xabdd8096 -0, 1176192, 1176192, 1152, 2304, 0xe5f57653 -0, 1177344, 1177344, 1152, 2304, 0x7c777984 -0, 1178496, 1178496, 1152, 2304, 0x631d7deb -0, 1179648, 1179648, 1152, 2304, 0x70d36e1f -0, 1180800, 1180800, 1152, 2304, 0x412c802b -0, 1181952, 1181952, 1152, 2304, 0xacc281c1 -0, 1183104, 1183104, 1152, 2304, 0x569d86a8 -0, 1184256, 1184256, 1152, 2304, 0x5c69743f -0, 1185408, 1185408, 1152, 2304, 0x29637794 -0, 1186560, 1186560, 1152, 2304, 0x0d1b7a4f -0, 1187712, 1187712, 1152, 2304, 0xfc6978a6 -0, 1188864, 1188864, 1152, 2304, 0x9b178987 -0, 1190016, 1190016, 1152, 2304, 0xe436714a -0, 1191168, 1191168, 1152, 2304, 0x783a7b6e -0, 1192320, 1192320, 1152, 2304, 0x6ff16f4e -0, 1193472, 1193472, 1152, 2304, 0x9fd582cc -0, 1194624, 1194624, 1152, 2304, 0xff0d6bc9 -0, 1195776, 1195776, 1152, 2304, 0x6f4975d5 -0, 1196928, 1196928, 1152, 2304, 0x94a77a90 -0, 1198080, 1198080, 1152, 2304, 0x764f80db -0, 1199232, 1199232, 1152, 2304, 0x68e88782 -0, 1200384, 1200384, 1152, 2304, 0x91a378e8 -0, 1201536, 1201536, 1152, 2304, 0x29f26903 -0, 1202688, 1202688, 1152, 2304, 0xc3b684d4 -0, 1203840, 1203840, 1152, 2304, 0x7d95921f -0, 1204992, 1204992, 1152, 2304, 0x876a7ded -0, 1206144, 1206144, 1152, 2304, 0x0fbe7ee8 -0, 1207296, 1207296, 1152, 2304, 0x7d0f78c5 -0, 1208448, 1208448, 1152, 2304, 0xce906ba8 -0, 1209600, 1209600, 1152, 2304, 0xd281747b -0, 1210752, 1210752, 1152, 2304, 0xec38811b -0, 1211904, 1211904, 1152, 2304, 0x8170810a -0, 1213056, 1213056, 1152, 2304, 0x4d858ba2 -0, 1214208, 1214208, 1152, 2304, 0x8c798662 -0, 1215360, 1215360, 1152, 2304, 0x23a8879b -0, 1216512, 1216512, 1152, 2304, 0x9d0c8894 -0, 1217664, 1217664, 1152, 2304, 0xf07c681f -0, 1218816, 1218816, 1152, 2304, 0x03ab6f7a -0, 1219968, 1219968, 1152, 2304, 0x88c170c2 -0, 1221120, 1221120, 1152, 2304, 0xeb977bf3 -0, 1222272, 1222272, 1152, 2304, 0x33b6774f -0, 1223424, 1223424, 1152, 2304, 0x534c776e -0, 1224576, 1224576, 1152, 2304, 0x33c4826a -0, 1225728, 1225728, 1152, 2304, 0xdb9878d8 -0, 1226880, 1226880, 1152, 2304, 0xeffd789b -0, 1228032, 1228032, 1152, 2304, 0x2cc9862f -0, 1229184, 1229184, 1152, 2304, 0x9bf18131 -0, 1230336, 1230336, 1152, 2304, 0xfa078144 -0, 1231488, 1231488, 1152, 2304, 0x922885d2 -0, 1232640, 1232640, 1152, 2304, 0x29ad7796 -0, 1233792, 1233792, 1152, 2304, 0x62766f3f -0, 1234944, 1234944, 1152, 2304, 0x72a873a5 -0, 1236096, 1236096, 1152, 2304, 0x65176e4d -0, 1237248, 1237248, 1152, 2304, 0x75447cbd -0, 1238400, 1238400, 1152, 2304, 0x83528e32 -0, 1239552, 1239552, 1152, 2304, 0x0c758531 -0, 1240704, 1240704, 1152, 2304, 0x4a5c7a84 -0, 1241856, 1241856, 1152, 2304, 0xd5937648 -0, 1243008, 1243008, 1152, 2304, 0xef5c8983 -0, 1244160, 1244160, 1152, 2304, 0x24b281d0 -0, 1245312, 1245312, 1152, 2304, 0xc0af7017 -0, 1246464, 1246464, 1152, 2304, 0xf1cc7145 -0, 1247616, 1247616, 1152, 2304, 0x7ddb7a3b -0, 1248768, 1248768, 1152, 2304, 0xd2e57692 -0, 1249920, 1249920, 1152, 2304, 0x7abc61d6 -0, 1251072, 1251072, 1152, 2304, 0x44a68338 -0, 1252224, 1252224, 1152, 2304, 0x9cad810e -0, 1253376, 1253376, 1152, 2304, 0xbf3a7f51 -0, 1254528, 1254528, 1152, 2304, 0x52ac815e -0, 1255680, 1255680, 1152, 2304, 0xdf327e10 -0, 1256832, 1256832, 1152, 2304, 0x797c867b -0, 1257984, 1257984, 1152, 2304, 0x685b79ec -0, 1259136, 1259136, 1152, 2304, 0x60267b82 -0, 1260288, 1260288, 1152, 2304, 0xe70e7fd4 -0, 1261440, 1261440, 1152, 2304, 0xaf197a22 -0, 1262592, 1262592, 1152, 2304, 0xf5e57075 -0, 1263744, 1263744, 1152, 2304, 0xa86f8197 -0, 1264896, 1264896, 1152, 2304, 0x922c7b3d -0, 1266048, 1266048, 1152, 2304, 0x8e3b7929 -0, 1267200, 1267200, 1152, 2304, 0x816f862d -0, 1268352, 1268352, 1152, 2304, 0xc09c761a -0, 1269504, 1269504, 1152, 2304, 0xf1cd9010 -0, 1270656, 1270656, 1152, 2304, 0xcf5c72d8 -0, 1271808, 1271808, 1152, 2304, 0x0e607a38 -0, 1272960, 1272960, 1152, 2304, 0x6cb0819c -0, 1274112, 1274112, 1152, 2304, 0x9e2880aa -0, 1275264, 1275264, 1152, 2304, 0xb46f69f9 -0, 1276416, 1276416, 1152, 2304, 0xbc807eab -0, 1277568, 1277568, 1152, 2304, 0x91237cf9 -0, 1278720, 1278720, 1152, 2304, 0xb6bf82b6 -0, 1279872, 1279872, 1152, 2304, 0xfcd58daf -0, 1281024, 1281024, 1152, 2304, 0x53b176f4 -0, 1282176, 1282176, 1152, 2304, 0xc79d7507 -0, 1283328, 1283328, 1152, 2304, 0x810677b2 -0, 1284480, 1284480, 1152, 2304, 0x13148737 -0, 1285632, 1285632, 1152, 2304, 0x2eb5755a -0, 1286784, 1286784, 1152, 2304, 0x5bec5cd2 -0, 1287936, 1287936, 1152, 2304, 0x66c68d47 -0, 1289088, 1289088, 1152, 2304, 0x55d18770 -0, 1290240, 1290240, 1152, 2304, 0x13997def -0, 1291392, 1291392, 1152, 2304, 0x23cd8437 -0, 1292544, 1292544, 1152, 2304, 0x5cd07942 -0, 1293696, 1293696, 1152, 2304, 0x43ab6b4c -0, 1294848, 1294848, 1152, 2304, 0xc55788ec -0, 1296000, 1296000, 1152, 2304, 0x6b69788e -0, 1297152, 1297152, 1152, 2304, 0xcacb8fea -0, 1298304, 1298304, 1152, 2304, 0x83407ebd -0, 1299456, 1299456, 1152, 2304, 0x998275f3 -0, 1300608, 1300608, 1152, 2304, 0x0ca76dcc -0, 1301760, 1301760, 1152, 2304, 0xa1ff7c6a -0, 1302912, 1302912, 1152, 2304, 0x4a597683 -0, 1304064, 1304064, 1152, 2304, 0xc8e57f16 -0, 1305216, 1305216, 1152, 2304, 0x376d82fb -0, 1306368, 1306368, 1152, 2304, 0x489b8164 -0, 1307520, 1307520, 1152, 2304, 0xece27f77 -0, 1308672, 1308672, 1152, 2304, 0x4c197e8f -0, 1309824, 1309824, 1152, 2304, 0x6eb07739 -0, 1310976, 1310976, 1152, 2304, 0xef628145 -0, 1312128, 1312128, 1152, 2304, 0x549d6f12 -0, 1313280, 1313280, 1152, 2304, 0xbe566b70 -0, 1314432, 1314432, 1152, 2304, 0x2bde87d3 -0, 1315584, 1315584, 1152, 2304, 0x0ffd7175 -0, 1316736, 1316736, 1152, 2304, 0x47d28a8b -0, 1317888, 1317888, 1152, 2304, 0x6f6c718e -0, 1319040, 1319040, 1152, 2304, 0x665e7937 -0, 1320192, 1320192, 1152, 2304, 0x73538e8d -0, 1321344, 1321344, 1152, 2304, 0x56167d71 -0, 1322496, 1322496, 1152, 2304, 0x3d0278ed -0, 1323648, 1323648, 1152, 2304, 0x9baf7a51 -0, 1324800, 1324800, 1152, 2304, 0x8c058105 -0, 1325952, 1325952, 1152, 2304, 0x2b9573ca -0, 1327104, 1327104, 1152, 2304, 0x4a2271a1 -0, 1328256, 1328256, 1152, 2304, 0x3d5276f6 -0, 1329408, 1329408, 1152, 2304, 0x43c076cd -0, 1330560, 1330560, 1152, 2304, 0x4fec8929 -0, 1331712, 1331712, 1152, 2304, 0xaa7167ec -0, 1332864, 1332864, 1152, 2304, 0x39ff7ea5 -0, 1334016, 1334016, 1152, 2304, 0x2dd58348 -0, 1335168, 1335168, 1152, 2304, 0x03fc8782 -0, 1336320, 1336320, 1152, 2304, 0x55a4649c -0, 1337472, 1337472, 1152, 2304, 0x71407067 -0, 1338624, 1338624, 1152, 2304, 0x3b667ce6 -0, 1339776, 1339776, 1152, 2304, 0xb12e81aa -0, 1340928, 1340928, 1152, 2304, 0xc1646ee3 -0, 1342080, 1342080, 1152, 2304, 0x6b55884f -0, 1343232, 1343232, 1152, 2304, 0x292382b5 -0, 1344384, 1344384, 1152, 2304, 0x18f97854 -0, 1345536, 1345536, 1152, 2304, 0x47a480be -0, 1346688, 1346688, 1152, 2304, 0xe0857b16 -0, 1347840, 1347840, 1152, 2304, 0xe3368462 -0, 1348992, 1348992, 1152, 2304, 0xced17ae8 -0, 1350144, 1350144, 1152, 2304, 0x4020796d -0, 1351296, 1351296, 1152, 2304, 0x26797fd0 -0, 1352448, 1352448, 1152, 2304, 0x0e087554 -0, 1353600, 1353600, 1152, 2304, 0xf8868040 -0, 1354752, 1354752, 1152, 2304, 0x3f0a7784 -0, 1355904, 1355904, 1152, 2304, 0xbe517d5e -0, 1357056, 1357056, 1152, 2304, 0xed0b66bc -0, 1358208, 1358208, 1152, 2304, 0x79b96d63 -0, 1359360, 1359360, 1152, 2304, 0x1ab4793a -0, 1360512, 1360512, 1152, 2304, 0xd2db7f7d -0, 1361664, 1361664, 1152, 2304, 0x91017992 -0, 1362816, 1362816, 1152, 2304, 0xf88f7cb9 -0, 1363968, 1363968, 1152, 2304, 0x0cc98309 -0, 1365120, 1365120, 1152, 2304, 0x38b77cb8 -0, 1366272, 1366272, 1152, 2304, 0x0cb185f9 -0, 1367424, 1367424, 1152, 2304, 0xc4a27824 -0, 1368576, 1368576, 1152, 2304, 0x1ce97618 -0, 1369728, 1369728, 1152, 2304, 0x1423976e -0, 1370880, 1370880, 1152, 2304, 0xdbb781b2 -0, 1372032, 1372032, 1152, 2304, 0x156d71d3 -0, 1373184, 1373184, 1152, 2304, 0xce228625 -0, 1374336, 1374336, 1152, 2304, 0x318072f3 -0, 1375488, 1375488, 1152, 2304, 0x464b77a1 -0, 1376640, 1376640, 1152, 2304, 0x0204854d -0, 1377792, 1377792, 1152, 2304, 0x498c8373 -0, 1378944, 1378944, 1152, 2304, 0xfe1a6e23 -0, 1380096, 1380096, 1152, 2304, 0x705284d0 -0, 1381248, 1381248, 1152, 2304, 0x91848980 -0, 1382400, 1382400, 1152, 2304, 0x259098c5 -0, 1383552, 1383552, 1152, 2304, 0x52b07c02 -0, 1384704, 1384704, 1152, 2304, 0x017289f6 -0, 1385856, 1385856, 1152, 2304, 0xb87687bf -0, 1387008, 1387008, 1152, 2304, 0x72de7843 -0, 1388160, 1388160, 1152, 2304, 0x3daf8939 -0, 1389312, 1389312, 1152, 2304, 0x0dfb763c -0, 1390464, 1390464, 1152, 2304, 0xc3017408 -0, 1391616, 1391616, 1152, 2304, 0x73f27f14 -0, 1392768, 1392768, 1152, 2304, 0x1c517541 -0, 1393920, 1393920, 1152, 2304, 0xf390748b -0, 1395072, 1395072, 1152, 2304, 0xe6ac71f3 -0, 1396224, 1396224, 1152, 2304, 0x6277862d -0, 1397376, 1397376, 1152, 2304, 0x923d6794 -0, 1398528, 1398528, 1152, 2304, 0x320a7f20 -0, 1399680, 1399680, 1152, 2304, 0x12f07a09 -0, 1400832, 1400832, 1152, 2304, 0xf9568b14 -0, 1401984, 1401984, 1152, 2304, 0x4d787fea -0, 1403136, 1403136, 1152, 2304, 0x57c5861a -0, 1404288, 1404288, 1152, 2304, 0x826b7cc7 -0, 1405440, 1405440, 1152, 2304, 0x7d056a94 -0, 1406592, 1406592, 1152, 2304, 0xbf3e8a60 -0, 1407744, 1407744, 1152, 2304, 0x5e518cab -0, 1408896, 1408896, 1152, 2304, 0x64e7794b -0, 1410048, 1410048, 1152, 2304, 0x9c9569ac -0, 1411200, 1411200, 1152, 2304, 0xde167582 -0, 1412352, 1412352, 1152, 2304, 0xdd8f78b1 -0, 1413504, 1413504, 1152, 2304, 0xec577e60 -0, 1414656, 1414656, 1152, 2304, 0x06877aa4 -0, 1415808, 1415808, 1152, 2304, 0xb5157742 -0, 1416960, 1416960, 1152, 2304, 0xf9be6f2b -0, 1418112, 1418112, 1152, 2304, 0xf95784c7 -0, 1419264, 1419264, 1152, 2304, 0x5aec7e15 -0, 1420416, 1420416, 1152, 2304, 0x666e7ce9 -0, 1421568, 1421568, 1152, 2304, 0xa76393a7 -0, 1422720, 1422720, 1152, 2304, 0xd1bb6d5c -0, 1423872, 1423872, 1152, 2304, 0x48d88144 -0, 1425024, 1425024, 1152, 2304, 0xa7df8177 -0, 1426176, 1426176, 1152, 2304, 0x906476b1 -0, 1427328, 1427328, 1152, 2304, 0x9f46723d -0, 1428480, 1428480, 1152, 2304, 0xa6d37a0c -0, 1429632, 1429632, 1152, 2304, 0x73e57be2 -0, 1430784, 1430784, 1152, 2304, 0x666e8594 -0, 1431936, 1431936, 1152, 2304, 0xd4b481d7 -0, 1433088, 1433088, 1152, 2304, 0xfced8427 -0, 1434240, 1434240, 1152, 2304, 0x743999bd -0, 1435392, 1435392, 1152, 2304, 0x71dd759b -0, 1436544, 1436544, 1152, 2304, 0x54a2849e -0, 1437696, 1437696, 1152, 2304, 0x07377f58 -0, 1438848, 1438848, 1152, 2304, 0xfd8f721a -0, 1440000, 1440000, 1152, 2304, 0x4d917422 -0, 1441152, 1441152, 1152, 2304, 0xaaa46e2b -0, 1442304, 1442304, 1152, 2304, 0x49e57597 -0, 1443456, 1443456, 1152, 2304, 0x29337511 -0, 1444608, 1444608, 1152, 2304, 0xdfee84c2 -0, 1445760, 1445760, 1152, 2304, 0x57266b8c -0, 1446912, 1446912, 1152, 2304, 0x5bf27cfc -0, 1448064, 1448064, 1152, 2304, 0xdc4b8b29 -0, 1449216, 1449216, 1152, 2304, 0xf49e7466 -0, 1450368, 1450368, 1152, 2304, 0xf1d975f3 -0, 1451520, 1451520, 1152, 2304, 0xc863774d -0, 1452672, 1452672, 1152, 2304, 0x5fab80c0 -0, 1453824, 1453824, 1152, 2304, 0x19548d6f -0, 1454976, 1454976, 1152, 2304, 0x165983ac -0, 1456128, 1456128, 1152, 2304, 0x2d658203 -0, 1457280, 1457280, 1152, 2304, 0x717678b2 -0, 1458432, 1458432, 1152, 2304, 0x1ed26dae -0, 1459584, 1459584, 1152, 2304, 0xecef7975 -0, 1460736, 1460736, 1152, 2304, 0xcd2b804c -0, 1461888, 1461888, 1152, 2304, 0xf4597f97 -0, 1463040, 1463040, 1152, 2304, 0x904b75cd -0, 1464192, 1464192, 1152, 2304, 0x6b508374 -0, 1465344, 1465344, 1152, 2304, 0xb6b4791f -0, 1466496, 1466496, 1152, 2304, 0xce6d7501 -0, 1467648, 1467648, 1152, 2304, 0x99ec8bac -0, 1468800, 1468800, 1152, 2304, 0x65d772b7 -0, 1469952, 1469952, 1152, 2304, 0xbc2762ff -0, 1471104, 1471104, 1152, 2304, 0xf8a48378 -0, 1472256, 1472256, 1152, 2304, 0x18057ad4 -0, 1473408, 1473408, 1152, 2304, 0x89af753f -0, 1474560, 1474560, 1152, 2304, 0x95a48fc5 -0, 1475712, 1475712, 1152, 2304, 0x8b7576af -0, 1476864, 1476864, 1152, 2304, 0xcdcb6e67 -0, 1478016, 1478016, 1152, 2304, 0xe02a7ff3 -0, 1479168, 1479168, 1152, 2304, 0x4f0a7d48 -0, 1480320, 1480320, 1152, 2304, 0x9bab8287 -0, 1481472, 1481472, 1152, 2304, 0xc1fa8063 -0, 1482624, 1482624, 1152, 2304, 0x410e7dd7 -0, 1483776, 1483776, 1152, 2304, 0xd4de777f -0, 1484928, 1484928, 1152, 2304, 0x403675ac -0, 1486080, 1486080, 1152, 2304, 0x4d7687c5 -0, 1487232, 1487232, 1152, 2304, 0x10c6650d -0, 1488384, 1488384, 1152, 2304, 0xd7e67b69 -0, 1489536, 1489536, 1152, 2304, 0x42b97fae -0, 1490688, 1490688, 1152, 2304, 0xa8b57a9f -0, 1491840, 1491840, 1152, 2304, 0xc24960a0 -0, 1492992, 1492992, 1152, 2304, 0x16198fec -0, 1494144, 1494144, 1152, 2304, 0x29297416 -0, 1495296, 1495296, 1152, 2304, 0x129b7d00 -0, 1496448, 1496448, 1152, 2304, 0xa9677141 -0, 1497600, 1497600, 1152, 2304, 0x86a779bf -0, 1498752, 1498752, 1152, 2304, 0xa3857dce -0, 1499904, 1499904, 1152, 2304, 0xee6d7c4d -0, 1501056, 1501056, 1152, 2304, 0x97127166 -0, 1502208, 1502208, 1152, 2304, 0x6e407c25 -0, 1503360, 1503360, 1152, 2304, 0x82a07c9a -0, 1504512, 1504512, 1152, 2304, 0xf62381ef -0, 1505664, 1505664, 1152, 2304, 0x2ab86ca8 -0, 1506816, 1506816, 1152, 2304, 0x97ca87ed -0, 1507968, 1507968, 1152, 2304, 0x6b4868f2 -0, 1509120, 1509120, 1152, 2304, 0xdb2a953c -0, 1510272, 1510272, 1152, 2304, 0x061e7770 -0, 1511424, 1511424, 1152, 2304, 0xae067224 -0, 1512576, 1512576, 1152, 2304, 0x88a282a3 -0, 1513728, 1513728, 1152, 2304, 0x4e14743e -0, 1514880, 1514880, 1152, 2304, 0x3dbd8b7b -0, 1516032, 1516032, 1152, 2304, 0xcae57312 -0, 1517184, 1517184, 1152, 2304, 0xf9038ca7 -0, 1518336, 1518336, 1152, 2304, 0x03ec6f07 -0, 1519488, 1519488, 1152, 2304, 0x8c297359 -0, 1520640, 1520640, 1152, 2304, 0x8af1804c -0, 1521792, 1521792, 1152, 2304, 0xf30087c8 -0, 1522944, 1522944, 1152, 2304, 0x21127cd1 -0, 1524096, 1524096, 1152, 2304, 0xc66772bd -0, 1525248, 1525248, 1152, 2304, 0x05e6630b -0, 1526400, 1526400, 1152, 2304, 0x020688d9 -0, 1527552, 1527552, 1152, 2304, 0xee3873cd -0, 1528704, 1528704, 1152, 2304, 0xf263782b -0, 1529856, 1529856, 1152, 2304, 0xf8877144 -0, 1531008, 1531008, 1152, 2304, 0xce1e6f33 -0, 1532160, 1532160, 1152, 2304, 0xf0457e4f -0, 1533312, 1533312, 1152, 2304, 0xde9387df -0, 1534464, 1534464, 1152, 2304, 0x5df86d1d -0, 1535616, 1535616, 1152, 2304, 0x949087ef -0, 1536768, 1536768, 1152, 2304, 0xdbd269c6 -0, 1537920, 1537920, 1152, 2304, 0xd530806e -0, 1539072, 1539072, 1152, 2304, 0x80027b1d -0, 1540224, 1540224, 1152, 2304, 0xccb47c48 -0, 1541376, 1541376, 1152, 2304, 0x4f2f8326 -0, 1542528, 1542528, 1152, 2304, 0xfe046f23 -0, 1543680, 1543680, 1152, 2304, 0x5939759b -0, 1544832, 1544832, 1152, 2304, 0x83147073 -0, 1545984, 1545984, 1152, 2304, 0xc9e77b95 -0, 1547136, 1547136, 1152, 2304, 0x702d8e51 -0, 1548288, 1548288, 1152, 2304, 0x5f5f8492 -0, 1549440, 1549440, 1152, 2304, 0x10116d0e -0, 1550592, 1550592, 1152, 2304, 0xb8587894 -0, 1551744, 1551744, 1152, 2304, 0x2b357892 -0, 1552896, 1552896, 1152, 2304, 0x160e6c20 -0, 1554048, 1554048, 1152, 2304, 0x0534874b -0, 1555200, 1555200, 1152, 2304, 0xde687064 -0, 1556352, 1556352, 1152, 2304, 0x91ef7fe4 -0, 1557504, 1557504, 1152, 2304, 0x077473ce -0, 1558656, 1558656, 1152, 2304, 0x1be77777 -0, 1559808, 1559808, 1152, 2304, 0xaada9096 -0, 1560960, 1560960, 1152, 2304, 0xeac96f7e -0, 1562112, 1562112, 1152, 2304, 0xe9ca6e72 -0, 1563264, 1563264, 1152, 2304, 0xd0868038 -0, 1564416, 1564416, 1152, 2304, 0x689176f1 -0, 1565568, 1565568, 1152, 2304, 0xdfdb7684 -0, 1566720, 1566720, 1152, 2304, 0x83c55d92 -0, 1567872, 1567872, 1152, 2304, 0x77587b70 -0, 1569024, 1569024, 1152, 2304, 0x60937941 -0, 1570176, 1570176, 1152, 2304, 0xb00267bd -0, 1571328, 1571328, 1152, 2304, 0xd0a166eb -0, 1572480, 1572480, 1152, 2304, 0x88718162 -0, 1573632, 1573632, 1152, 2304, 0xf9e084ff -0, 1574784, 1574784, 1152, 2304, 0x2ddc8c08 -0, 1575936, 1575936, 1152, 2304, 0x843a7178 -0, 1577088, 1577088, 1152, 2304, 0x1d9784b4 -0, 1578240, 1578240, 1152, 2304, 0x98aa7b1d -0, 1579392, 1579392, 1152, 2304, 0x583e846e -0, 1580544, 1580544, 1152, 2304, 0xa6d284ec -0, 1581696, 1581696, 1152, 2304, 0xa0147cbf -0, 1582848, 1582848, 1152, 2304, 0xb3bf7b4b -0, 1584000, 1584000, 1152, 2304, 0x7f8b78dd -0, 1585152, 1585152, 1152, 2304, 0xd3fb761f -0, 1586304, 1586304, 1152, 2304, 0x78147c2f -0, 1587456, 1587456, 1152, 2304, 0x5e747b26 -0, 1588608, 1588608, 1152, 2304, 0x0d8e7d96 -0, 1589760, 1589760, 1152, 2304, 0x73728362 -0, 1590912, 1590912, 1152, 2304, 0x7c54707b -0, 1592064, 1592064, 1152, 2304, 0xb89c7806 -0, 1593216, 1593216, 1152, 2304, 0x5f0f7a91 -0, 1594368, 1594368, 1152, 2304, 0x35217e84 -0, 1595520, 1595520, 1152, 2304, 0xb3798553 -0, 1596672, 1596672, 1152, 2304, 0xd8377e8a -0, 1597824, 1597824, 1152, 2304, 0x339181ba -0, 1598976, 1598976, 1152, 2304, 0xbe196b2c -0, 1600128, 1600128, 1152, 2304, 0xdc708cc4 -0, 1601280, 1601280, 1152, 2304, 0x649c74c1 -0, 1602432, 1602432, 1152, 2304, 0xac128649 -0, 1603584, 1603584, 1152, 2304, 0xcd266a22 -0, 1604736, 1604736, 1152, 2304, 0xdfde7023 -0, 1605888, 1605888, 1152, 2304, 0xf92d7450 -0, 1607040, 1607040, 1152, 2304, 0x9ce379ac -0, 1608192, 1608192, 1152, 2304, 0xee5e712e -0, 1609344, 1609344, 1152, 2304, 0xa12676c0 -0, 1610496, 1610496, 1152, 2304, 0x4cee7be1 -0, 1611648, 1611648, 1152, 2304, 0x90c881e5 -0, 1612800, 1612800, 1152, 2304, 0xa6a78158 -0, 1613952, 1613952, 1152, 2304, 0xd248864a -0, 1615104, 1615104, 1152, 2304, 0x7a8972b4 -0, 1616256, 1616256, 1152, 2304, 0x5c8a75cb -0, 1617408, 1617408, 1152, 2304, 0x07606722 -0, 1618560, 1618560, 1152, 2304, 0xbf497aae -0, 1619712, 1619712, 1152, 2304, 0xffab7d66 -0, 1620864, 1620864, 1152, 2304, 0xefdc7d05 -0, 1622016, 1622016, 1152, 2304, 0x02d686dd -0, 1623168, 1623168, 1152, 2304, 0x852e6eb6 -0, 1624320, 1624320, 1152, 2304, 0x3445706b -0, 1625472, 1625472, 1152, 2304, 0x04677828 -0, 1626624, 1626624, 1152, 2304, 0x5d5c833c -0, 1627776, 1627776, 1152, 2304, 0xf4277e06 -0, 1628928, 1628928, 1152, 2304, 0xcece72ab -0, 1630080, 1630080, 1152, 2304, 0x10837aff -0, 1631232, 1631232, 1152, 2304, 0x0265762b -0, 1632384, 1632384, 1152, 2304, 0x0fc979de -0, 1633536, 1633536, 1152, 2304, 0xeecf7010 -0, 1634688, 1634688, 1152, 2304, 0x313975cd -0, 1635840, 1635840, 1152, 2304, 0xccce84a7 -0, 1636992, 1636992, 1152, 2304, 0x823e6935 -0, 1638144, 1638144, 1152, 2304, 0xa0606ade -0, 1639296, 1639296, 1152, 2304, 0x2c2d7866 -0, 1640448, 1640448, 1152, 2304, 0x3a5a781e -0, 1641600, 1641600, 1152, 2304, 0xdaf677fd -0, 1642752, 1642752, 1152, 2304, 0x79d88aca -0, 1643904, 1643904, 1152, 2304, 0x3db27308 -0, 1645056, 1645056, 1152, 2304, 0x627175ff -0, 1646208, 1646208, 1152, 2304, 0x40697b16 -0, 1647360, 1647360, 1152, 2304, 0x40e47ee7 -0, 1648512, 1648512, 1152, 2304, 0x6a6a7d91 -0, 1649664, 1649664, 1152, 2304, 0x8d3e8a32 -0, 1650816, 1650816, 1152, 2304, 0x576a817e -0, 1651968, 1651968, 1152, 2304, 0x86287f9b -0, 1653120, 1653120, 1152, 2304, 0x43e081ce -0, 1654272, 1654272, 1152, 2304, 0xe44b8003 -0, 1655424, 1655424, 1152, 2304, 0xfb237f5b -0, 1656576, 1656576, 1152, 2304, 0x28967c8a -0, 1657728, 1657728, 1152, 2304, 0x97478829 -0, 1658880, 1658880, 1152, 2304, 0x615570e8 -0, 1660032, 1660032, 1152, 2304, 0xa52c7d34 -0, 1661184, 1661184, 1152, 2304, 0xb55473e8 -0, 1662336, 1662336, 1152, 2304, 0x08a07d6c -0, 1663488, 1663488, 1152, 2304, 0x2eed916a -0, 1664640, 1664640, 1152, 2304, 0x8ce36cec -0, 1665792, 1665792, 1152, 2304, 0x775e8992 -0, 1666944, 1666944, 1152, 2304, 0x99ad816b -0, 1668096, 1668096, 1152, 2304, 0x697a70be -0, 1669248, 1669248, 1152, 2304, 0x38c46cf2 -0, 1670400, 1670400, 1152, 2304, 0xf9d681f4 -0, 1671552, 1671552, 1152, 2304, 0xa7336fea -0, 1672704, 1672704, 1152, 2304, 0xd2a97e59 -0, 1673856, 1673856, 1152, 2304, 0x02b880e9 -0, 1675008, 1675008, 1152, 2304, 0x2a486e9e -0, 1676160, 1676160, 1152, 2304, 0x5f197c43 -0, 1677312, 1677312, 1152, 2304, 0x266679ad -0, 1678464, 1678464, 1152, 2304, 0x7cfd7c8a -0, 1679616, 1679616, 1152, 2304, 0x43b681bb -0, 1680768, 1680768, 1152, 2304, 0x63309cff -0, 1681920, 1681920, 1152, 2304, 0x80f36f7d -0, 1683072, 1683072, 1152, 2304, 0xcead7b98 -0, 1684224, 1684224, 1152, 2304, 0x8475992f -0, 1685376, 1685376, 1152, 2304, 0x746782d2 -0, 1686528, 1686528, 1152, 2304, 0x2b486982 -0, 1687680, 1687680, 1152, 2304, 0xc80c7fc2 -0, 1688832, 1688832, 1152, 2304, 0x148c7c3b -0, 1689984, 1689984, 1152, 2304, 0x49c477df -0, 1691136, 1691136, 1152, 2304, 0x1bf97c56 -0, 1692288, 1692288, 1152, 2304, 0x89a38221 -0, 1693440, 1693440, 1152, 2304, 0xcb757a31 -0, 1694592, 1694592, 1152, 2304, 0xd3bb72fa -0, 1695744, 1695744, 1152, 2304, 0xe5727650 -0, 1696896, 1696896, 1152, 2304, 0x5d4e9242 -0, 1698048, 1698048, 1152, 2304, 0x29207f75 -0, 1699200, 1699200, 1152, 2304, 0x5b1d954a -0, 1700352, 1700352, 1152, 2304, 0xa2888223 -0, 1701504, 1701504, 1152, 2304, 0xe31d8af7 -0, 1702656, 1702656, 1152, 2304, 0x29ee82dd -0, 1703808, 1703808, 1152, 2304, 0x4b1d7887 -0, 1704960, 1704960, 1152, 2304, 0xc0308236 -0, 1706112, 1706112, 1152, 2304, 0xaed68e92 -0, 1707264, 1707264, 1152, 2304, 0xbc1171e9 -0, 1708416, 1708416, 1152, 2304, 0x379f828b -0, 1709568, 1709568, 1152, 2304, 0x83de72c8 -0, 1710720, 1710720, 1152, 2304, 0xb11a806a -0, 1711872, 1711872, 1152, 2304, 0x7ac17e7a -0, 1713024, 1713024, 1152, 2304, 0x031b7d9a -0, 1714176, 1714176, 1152, 2304, 0xebc97c43 -0, 1715328, 1715328, 1152, 2304, 0x914e86a7 -0, 1716480, 1716480, 1152, 2304, 0x88e2747e -0, 1717632, 1717632, 1152, 2304, 0x153076bc -0, 1718784, 1718784, 1152, 2304, 0xdacc7ebb -0, 1719936, 1719936, 1152, 2304, 0x0905709a -0, 1721088, 1721088, 1152, 2304, 0x13358109 -0, 1722240, 1722240, 1152, 2304, 0x18227228 -0, 1723392, 1723392, 1152, 2304, 0x318082d7 -0, 1724544, 1724544, 1152, 2304, 0x8aec7a8e -0, 1725696, 1725696, 1152, 2304, 0x8c9c7755 -0, 1726848, 1726848, 1152, 2304, 0xdba46e2f -0, 1728000, 1728000, 1152, 2304, 0xd47d7f5a -0, 1729152, 1729152, 1152, 2304, 0xeb1370ec -0, 1730304, 1730304, 1152, 2304, 0xf6d68e74 -0, 1731456, 1731456, 1152, 2304, 0x3d5a7c66 -0, 1732608, 1732608, 1152, 2304, 0x264b6d68 -0, 1733760, 1733760, 1152, 2304, 0x7cde8b9f -0, 1734912, 1734912, 1152, 2304, 0xba467347 -0, 1736064, 1736064, 1152, 2304, 0x921987f7 -0, 1737216, 1737216, 1152, 2304, 0x9c6c7fce -0, 1738368, 1738368, 1152, 2304, 0x02cb828f -0, 1739520, 1739520, 1152, 2304, 0x3b427077 -0, 1740672, 1740672, 1152, 2304, 0x6f9c7523 -0, 1741824, 1741824, 1152, 2304, 0xef688204 -0, 1742976, 1742976, 1152, 2304, 0x263782dc -0, 1744128, 1744128, 1152, 2304, 0xb6ca7e46 -0, 1745280, 1745280, 1152, 2304, 0xb0929636 -0, 1746432, 1746432, 1152, 2304, 0x60a97b7a -0, 1747584, 1747584, 1152, 2304, 0xcf037690 -0, 1748736, 1748736, 1152, 2304, 0xc9046a25 -0, 1749888, 1749888, 1152, 2304, 0xbf247f3c -0, 1751040, 1751040, 1152, 2304, 0x71e77d34 -0, 1752192, 1752192, 1152, 2304, 0x96ce7a01 -0, 1753344, 1753344, 1152, 2304, 0xf9b07a27 -0, 1754496, 1754496, 1152, 2304, 0x984b830b -0, 1755648, 1755648, 1152, 2304, 0xff11822b -0, 1756800, 1756800, 1152, 2304, 0xb0a18578 -0, 1757952, 1757952, 1152, 2304, 0xa9d98ef8 -0, 1759104, 1759104, 1152, 2304, 0x4f9076e1 -0, 1760256, 1760256, 1152, 2304, 0xb63c7742 -0, 1761408, 1761408, 1152, 2304, 0xb4c06ae2 -0, 1762560, 1762560, 1152, 2304, 0x41738531 -0, 1763712, 1763712, 1152, 2304, 0x55125e7b +0, 26496, 26496, 1152, 2304, 0xb8dc7525 +0, 52992, 52992, 1152, 2304, 0x3e7d6905 +0, 79488, 79488, 1152, 2304, 0xef47877b +0, 105984, 105984, 1152, 2304, 0xfe916b7e +0, 132480, 132480, 1152, 2304, 0xe3d08cde +0, 158976, 158976, 1152, 2304, 0xff7f86cf +0, 185472, 185472, 1152, 2304, 0x843e6f95 +0, 211968, 211968, 1152, 2304, 0x81577c26 +0, 238464, 238464, 1152, 2304, 0x04a085d5 +0, 264960, 264960, 1152, 2304, 0x1c5a76f5 +0, 291456, 291456, 1152, 2304, 0x4ee78623 +0, 317952, 317952, 1152, 2304, 0x8ec861dc +0, 344448, 344448, 1152, 2304, 0x0ca179d8 +0, 370944, 370944, 1152, 2304, 0xc6da750f +0, 397440, 397440, 1152, 2304, 0xf6bf79b5 +0, 423936, 423936, 1152, 2304, 0x97b88a43 +0, 450432, 450432, 1152, 2304, 0xf13c7b9c +0, 476928, 476928, 1152, 2304, 0xdfba83af +0, 503424, 503424, 1152, 2304, 0xc9467d4b +0, 529920, 529920, 1152, 2304, 0xbbb58e2b +0, 556416, 556416, 1152, 2304, 0x3a1078ea +0, 582912, 582912, 1152, 2304, 0xe9587a5c +0, 609408, 609408, 1152, 2304, 0xef5a8039 +0, 635904, 635904, 1152, 2304, 0x9d5f782f +0, 662400, 662400, 1152, 2304, 0x1a548291 +0, 688896, 688896, 1152, 2304, 0x07517701 +0, 715392, 715392, 1152, 2304, 0x78127d6e +0, 741888, 741888, 1152, 2304, 0x62e2788a +0, 768384, 768384, 1152, 2304, 0x29397ad9 +0, 794880, 794880, 1152, 2304, 0x45da82d6 +0, 821376, 821376, 1152, 2304, 0x8ed66e51 +0, 847872, 847872, 1152, 2304, 0x660775cd +0, 874368, 874368, 1152, 2304, 0x802c767a +0, 900864, 900864, 1152, 2304, 0xcc055840 +0, 927360, 927360, 1152, 2304, 0x701b7eaf +0, 953856, 953856, 1152, 2304, 0x8290749f +0, 980352, 980352, 1152, 2304, 0x2c7b7d30 +0, 1006848, 1006848, 1152, 2304, 0xe4f17743 +0, 1033344, 1033344, 1152, 2304, 0x0e747d6e +0, 1059840, 1059840, 1152, 2304, 0xbe7775a0 +0, 1086336, 1086336, 1152, 2304, 0xcf797673 +0, 1112832, 1112832, 1152, 2304, 0x29cb7800 +0, 1139328, 1139328, 1152, 2304, 0xfc947890 +0, 1165824, 1165824, 1152, 2304, 0x62757fc6 +0, 1192320, 1192320, 1152, 2304, 0x098876d0 +0, 1218816, 1218816, 1152, 2304, 0xa9567ee2 +0, 1245312, 1245312, 1152, 2304, 0xe3bb9173 +0, 1271808, 1271808, 1152, 2304, 0xcc2d6dee +0, 1298304, 1298304, 1152, 2304, 0xe94591ab +0, 1324800, 1324800, 1152, 2304, 0x5c7588de +0, 1351296, 1351296, 1152, 2304, 0xfd83643c +0, 1377792, 1377792, 1152, 2304, 0x528177f1 +0, 1404288, 1404288, 1152, 2304, 0x65d08474 +0, 1430784, 1430784, 1152, 2304, 0x738d765b +0, 1457280, 1457280, 1152, 2304, 0xdd3d810e +0, 1483776, 1483776, 1152, 2304, 0xef4f90d3 +0, 1510272, 1510272, 1152, 2304, 0x61e28d43 +0, 1536768, 1536768, 1152, 2304, 0x9a11796b +0, 1563264, 1563264, 1152, 2304, 0x96c97dcd +0, 1589760, 1589760, 1152, 2304, 0xa8fe8621 +0, 1616256, 1616256, 1152, 2304, 0x499b7d38 +0, 1642752, 1642752, 1152, 2304, 0xfcb078a9 +0, 1669248, 1669248, 1152, 2304, 0x40d78651 +0, 1695744, 1695744, 1152, 2304, 0xa4af7234 +0, 1722240, 1722240, 1152, 2304, 0x6831870a +0, 1748736, 1748736, 1152, 2304, 0x030e7b9d +0, 1775232, 1775232, 1152, 2304, 0x445a75b6 +0, 1801728, 1801728, 1152, 2304, 0x09857389 +0, 1828224, 1828224, 1152, 2304, 0x0d018866 +0, 1854720, 1854720, 1152, 2304, 0x2afe810a +0, 1881216, 1881216, 1152, 2304, 0x0bcf7c43 +0, 1907712, 1907712, 1152, 2304, 0x13737c12 +0, 1934208, 1934208, 1152, 2304, 0x716c7bba +0, 1960704, 1960704, 1152, 2304, 0xb801823b +0, 1987200, 1987200, 1152, 2304, 0x0fd573ee +0, 2013696, 2013696, 1152, 2304, 0xe1ab879c +0, 2040192, 2040192, 1152, 2304, 0x49e6764f +0, 2066688, 2066688, 1152, 2304, 0xd5f26ddc +0, 2093184, 2093184, 1152, 2304, 0x076775ff +0, 2119680, 2119680, 1152, 2304, 0xfbb86fce +0, 2146176, 2146176, 1152, 2304, 0x20c56858 +0, 2172672, 2172672, 1152, 2304, 0x043e6891 +0, 2199168, 2199168, 1152, 2304, 0x59648729 +0, 2225664, 2225664, 1152, 2304, 0xd4907a63 +0, 2252160, 2252160, 1152, 2304, 0xd0208a4c +0, 2278656, 2278656, 1152, 2304, 0xce968383 +0, 2305152, 2305152, 1152, 2304, 0x3cfc7cd1 +0, 2331648, 2331648, 1152, 2304, 0x628a7bf5 +0, 2358144, 2358144, 1152, 2304, 0x9cfe8a4f +0, 2384640, 2384640, 1152, 2304, 0xdf6f7c6d +0, 2411136, 2411136, 1152, 2304, 0x6cf6882a +0, 2437632, 2437632, 1152, 2304, 0x099773a3 +0, 2464128, 2464128, 1152, 2304, 0x4a1c7649 +0, 2490624, 2490624, 1152, 2304, 0x31ea71cb +0, 2517120, 2517120, 1152, 2304, 0xed127ed9 +0, 2543616, 2543616, 1152, 2304, 0x5b156954 +0, 2570112, 2570112, 1152, 2304, 0xdd638532 +0, 2596608, 2596608, 1152, 2304, 0xf1a271f2 +0, 2623104, 2623104, 1152, 2304, 0x779184d7 +0, 2649600, 2649600, 1152, 2304, 0x49a88aa8 +0, 2676096, 2676096, 1152, 2304, 0xa11b7c90 +0, 2702592, 2702592, 1152, 2304, 0xbf488274 +0, 2729088, 2729088, 1152, 2304, 0x002f79a8 +0, 2755584, 2755584, 1152, 2304, 0x0ed97e2f +0, 2782080, 2782080, 1152, 2304, 0x7845878f +0, 2808576, 2808576, 1152, 2304, 0x46d777dc +0, 2835072, 2835072, 1152, 2304, 0x8d0179e3 +0, 2861568, 2861568, 1152, 2304, 0x38917f9f +0, 2888064, 2888064, 1152, 2304, 0x449876e7 +0, 2914560, 2914560, 1152, 2304, 0x001a8769 +0, 2941056, 2941056, 1152, 2304, 0x06c1826b +0, 2967552, 2967552, 1152, 2304, 0x41b68047 +0, 2994048, 2994048, 1152, 2304, 0xeb9782c6 +0, 3020544, 3020544, 1152, 2304, 0x7cd9719c +0, 3047040, 3047040, 1152, 2304, 0x3a4a767c +0, 3073536, 3073536, 1152, 2304, 0x7f887e81 +0, 3100032, 3100032, 1152, 2304, 0xf75d714b +0, 3126528, 3126528, 1152, 2304, 0x33b57e9f +0, 3153024, 3153024, 1152, 2304, 0xc732749e +0, 3179520, 3179520, 1152, 2304, 0x386f7e1a +0, 3206016, 3206016, 1152, 2304, 0x6b9c767d +0, 3232512, 3232512, 1152, 2304, 0x701c83e5 +0, 3259008, 3259008, 1152, 2304, 0xb92571e1 +0, 3285504, 3285504, 1152, 2304, 0x833a84bc +0, 3312000, 3312000, 1152, 2304, 0x1b6984e0 +0, 3338496, 3338496, 1152, 2304, 0x1b2474ba +0, 3364992, 3364992, 1152, 2304, 0xc22775a6 +0, 3391488, 3391488, 1152, 2304, 0x3e8f7972 +0, 3417984, 3417984, 1152, 2304, 0x17a28a65 +0, 3444480, 3444480, 1152, 2304, 0x9b6178a4 +0, 3470976, 3470976, 1152, 2304, 0x5d707873 +0, 3497472, 3497472, 1152, 2304, 0x68e2645a +0, 3523968, 3523968, 1152, 2304, 0x1e377d28 +0, 3550464, 3550464, 1152, 2304, 0x54b384be +0, 3576960, 3576960, 1152, 2304, 0x0617808c +0, 3603456, 3603456, 1152, 2304, 0xbc2b8a6c +0, 3629952, 3629952, 1152, 2304, 0x7ced7180 +0, 3656448, 3656448, 1152, 2304, 0xf22180ab +0, 3682944, 3682944, 1152, 2304, 0xf13682c9 +0, 3709440, 3709440, 1152, 2304, 0x7eff87fd +0, 3735936, 3735936, 1152, 2304, 0x5a0b5cec +0, 3762432, 3762432, 1152, 2304, 0x57c18906 +0, 3788928, 3788928, 1152, 2304, 0xb55a6a16 +0, 3815424, 3815424, 1152, 2304, 0xf2608371 +0, 3841920, 3841920, 1152, 2304, 0x36df7576 +0, 3868416, 3868416, 1152, 2304, 0xdb106fb4 +0, 3894912, 3894912, 1152, 2304, 0x7e4f85d0 +0, 3921408, 3921408, 1152, 2304, 0xe3ee78ab +0, 3947904, 3947904, 1152, 2304, 0xd36b7dc7 +0, 3974400, 3974400, 1152, 2304, 0xadab7c5c +0, 4000896, 4000896, 1152, 2304, 0x70786f26 +0, 4027392, 4027392, 1152, 2304, 0xcd5d717e +0, 4053888, 4053888, 1152, 2304, 0xc1a96f9a +0, 4080384, 4080384, 1152, 2304, 0xad777887 +0, 4106880, 4106880, 1152, 2304, 0x98277c16 +0, 4133376, 4133376, 1152, 2304, 0x868882c5 +0, 4159872, 4159872, 1152, 2304, 0xc48092b9 +0, 4186368, 4186368, 1152, 2304, 0x230069da +0, 4212864, 4212864, 1152, 2304, 0x14147ad6 +0, 4239360, 4239360, 1152, 2304, 0xc9007172 +0, 4265856, 4265856, 1152, 2304, 0x85d67bcc +0, 4292352, 4292352, 1152, 2304, 0x22418bab +0, 4318848, 4318848, 1152, 2304, 0xe53c8b71 +0, 4345344, 4345344, 1152, 2304, 0x5a1a9053 +0, 4371840, 4371840, 1152, 2304, 0x9cd179af +0, 4398336, 4398336, 1152, 2304, 0xbb3c7d72 +0, 4424832, 4424832, 1152, 2304, 0x477a8677 +0, 4451328, 4451328, 1152, 2304, 0xe3337834 +0, 4477824, 4477824, 1152, 2304, 0x1cb56d77 +0, 4504320, 4504320, 1152, 2304, 0xe89d6dac +0, 4530816, 4530816, 1152, 2304, 0xd468827e +0, 4557312, 4557312, 1152, 2304, 0xebc46b87 +0, 4583808, 4583808, 1152, 2304, 0x5fbb78d2 +0, 4610304, 4610304, 1152, 2304, 0xa1b483d6 +0, 4636800, 4636800, 1152, 2304, 0x6fec7cab +0, 4663296, 4663296, 1152, 2304, 0xd86d6f6c +0, 4689792, 4689792, 1152, 2304, 0x8c2c7d51 +0, 4716288, 4716288, 1152, 2304, 0xe8377cd7 +0, 4742784, 4742784, 1152, 2304, 0xb57071b4 +0, 4769280, 4769280, 1152, 2304, 0xc35c71fd +0, 4795776, 4795776, 1152, 2304, 0x789079e9 +0, 4822272, 4822272, 1152, 2304, 0x413b710e +0, 4848768, 4848768, 1152, 2304, 0x82678332 +0, 4875264, 4875264, 1152, 2304, 0xe1576e75 +0, 4901760, 4901760, 1152, 2304, 0x7c0b7ad6 +0, 4928256, 4928256, 1152, 2304, 0xc6b6786d +0, 4954752, 4954752, 1152, 2304, 0x736f7b89 +0, 4981248, 4981248, 1152, 2304, 0x0ded72f1 +0, 5007744, 5007744, 1152, 2304, 0xcb877a3c +0, 5034240, 5034240, 1152, 2304, 0x7c497d40 +0, 5060736, 5060736, 1152, 2304, 0xaefc798c +0, 5087232, 5087232, 1152, 2304, 0x4cce748c +0, 5113728, 5113728, 1152, 2304, 0xaa187fbe +0, 5140224, 5140224, 1152, 2304, 0x1aa77db9 +0, 5166720, 5166720, 1152, 2304, 0x9e0074b8 +0, 5193216, 5193216, 1152, 2304, 0x74ee822b +0, 5219712, 5219712, 1152, 2304, 0x975c6ff6 +0, 5246208, 5246208, 1152, 2304, 0xe1847bb4 +0, 5272704, 5272704, 1152, 2304, 0xe0828777 +0, 5299200, 5299200, 1152, 2304, 0xf4027205 +0, 5325696, 5325696, 1152, 2304, 0x535e7a20 +0, 5352192, 5352192, 1152, 2304, 0x5bd88404 +0, 5378688, 5378688, 1152, 2304, 0xf29478b1 +0, 5405184, 5405184, 1152, 2304, 0x9b7c7d88 +0, 5431680, 5431680, 1152, 2304, 0xaeb07335 +0, 5458176, 5458176, 1152, 2304, 0xbef06e08 +0, 5484672, 5484672, 1152, 2304, 0x795f7b8c +0, 5511168, 5511168, 1152, 2304, 0x435a674d +0, 5537664, 5537664, 1152, 2304, 0xd8ee7a09 +0, 5564160, 5564160, 1152, 2304, 0x9059812e +0, 5590656, 5590656, 1152, 2304, 0x7481744a +0, 5617152, 5617152, 1152, 2304, 0xdff27475 +0, 5643648, 5643648, 1152, 2304, 0xb17783ab +0, 5670144, 5670144, 1152, 2304, 0x42e9706b +0, 5696640, 5696640, 1152, 2304, 0x9f0d86b4 +0, 5723136, 5723136, 1152, 2304, 0x2963955f +0, 5749632, 5749632, 1152, 2304, 0x059a6957 +0, 5776128, 5776128, 1152, 2304, 0x85948206 +0, 5802624, 5802624, 1152, 2304, 0x185e8400 +0, 5829120, 5829120, 1152, 2304, 0xe98e70df +0, 5855616, 5855616, 1152, 2304, 0x69057b27 +0, 5882112, 5882112, 1152, 2304, 0x49e26f21 +0, 5908608, 5908608, 1152, 2304, 0xb0867da5 +0, 5935104, 5935104, 1152, 2304, 0x785980ff +0, 5961600, 5961600, 1152, 2304, 0xf4b774be +0, 5988096, 5988096, 1152, 2304, 0x63897e8c +0, 6014592, 6014592, 1152, 2304, 0x248b89af +0, 6041088, 6041088, 1152, 2304, 0xd3627c4a +0, 6067584, 6067584, 1152, 2304, 0x5a4d9349 +0, 6094080, 6094080, 1152, 2304, 0xe2ce7c4c +0, 6120576, 6120576, 1152, 2304, 0x321f6c0b +0, 6147072, 6147072, 1152, 2304, 0x51ac74e0 +0, 6173568, 6173568, 1152, 2304, 0x8efa91ba +0, 6200064, 6200064, 1152, 2304, 0x8b4b784c +0, 6226560, 6226560, 1152, 2304, 0xe9e4879e +0, 6253056, 6253056, 1152, 2304, 0x8dc28081 +0, 6279552, 6279552, 1152, 2304, 0x44b477b0 +0, 6306048, 6306048, 1152, 2304, 0xf7b67084 +0, 6332544, 6332544, 1152, 2304, 0x4b198c17 +0, 6359040, 6359040, 1152, 2304, 0x9c947194 +0, 6385536, 6385536, 1152, 2304, 0x6eaa7f15 +0, 6412032, 6412032, 1152, 2304, 0x119f7c1d +0, 6438528, 6438528, 1152, 2304, 0x157b7f43 +0, 6465024, 6465024, 1152, 2304, 0xcd2e7acc +0, 6491520, 6491520, 1152, 2304, 0x97597247 +0, 6518016, 6518016, 1152, 2304, 0x7ba06acb +0, 6544512, 6544512, 1152, 2304, 0x233c7995 +0, 6571008, 6571008, 1152, 2304, 0x08e28587 +0, 6597504, 6597504, 1152, 2304, 0x92be84b5 +0, 6624000, 6624000, 1152, 2304, 0xbb857d43 +0, 6650496, 6650496, 1152, 2304, 0x168e7c74 +0, 6676992, 6676992, 1152, 2304, 0xac5465d9 +0, 6703488, 6703488, 1152, 2304, 0x18f58831 +0, 6729984, 6729984, 1152, 2304, 0x19b48196 +0, 6756480, 6756480, 1152, 2304, 0x20297653 +0, 6782976, 6782976, 1152, 2304, 0x93397a82 +0, 6809472, 6809472, 1152, 2304, 0x65ea7deb +0, 6835968, 6835968, 1152, 2304, 0xd7316e20 +0, 6862464, 6862464, 1152, 2304, 0x94107f2b +0, 6888960, 6888960, 1152, 2304, 0xec3b7dc6 +0, 6915456, 6915456, 1152, 2304, 0x2d3783aa +0, 6941952, 6941952, 1152, 2304, 0x07e47340 +0, 6968448, 6968448, 1152, 2304, 0xbc117893 +0, 6994944, 6994944, 1152, 2304, 0x8bd97851 +0, 7021440, 7021440, 1152, 2304, 0xc27376a9 +0, 7047936, 7047936, 1152, 2304, 0x30d88c83 +0, 7074432, 7074432, 1152, 2304, 0x19c2704c +0, 7100928, 7100928, 1152, 2304, 0x093b7b6e +0, 7127424, 7127424, 1152, 2304, 0x221a7349 +0, 7153920, 7153920, 1152, 2304, 0xa4fd82cd +0, 7180416, 7180416, 1152, 2304, 0x762e6bc9 +0, 7206912, 7206912, 1152, 2304, 0x270075d4 +0, 7233408, 7233408, 1152, 2304, 0xa5f27b90 +0, 7259904, 7259904, 1152, 2304, 0xf72e7edc +0, 7286400, 7286400, 1152, 2304, 0x42178486 +0, 7312896, 7312896, 1152, 2304, 0x5f7978e8 +0, 7339392, 7339392, 1152, 2304, 0x5d7c6703 +0, 7365888, 7365888, 1152, 2304, 0x2c4483d5 +0, 7392384, 7392384, 1152, 2304, 0x31bd951d +0, 7418880, 7418880, 1152, 2304, 0x99487af0 +0, 7445376, 7445376, 1152, 2304, 0x0bd27ee7 +0, 7471872, 7471872, 1152, 2304, 0xc3e07ac4 +0, 7498368, 7498368, 1152, 2304, 0x98a16ba7 +0, 7524864, 7524864, 1152, 2304, 0xd7a5747b +0, 7551360, 7551360, 1152, 2304, 0x96fb811c +0, 7577856, 7577856, 1152, 2304, 0x7cee8109 +0, 7604352, 7604352, 1152, 2304, 0x52b18ba2 +0, 7630848, 7630848, 1152, 2304, 0x33be8861 +0, 7657344, 7657344, 1152, 2304, 0xf41282a0 +0, 7683840, 7683840, 1152, 2304, 0xb4268993 +0, 7710336, 7710336, 1152, 2304, 0x52126a1c +0, 7736832, 7736832, 1152, 2304, 0x050b6f7a +0, 7763328, 7763328, 1152, 2304, 0x67a26fc3 +0, 7789824, 7789824, 1152, 2304, 0x966c7cf2 +0, 7816320, 7816320, 1152, 2304, 0x22097750 +0, 7842816, 7842816, 1152, 2304, 0xfbb0796c +0, 7869312, 7869312, 1152, 2304, 0xbd508964 +0, 7895808, 7895808, 1152, 2304, 0xc24478d8 +0, 7922304, 7922304, 1152, 2304, 0x3913769d +0, 7948800, 7948800, 1152, 2304, 0x8aab872f +0, 7975296, 7975296, 1152, 2304, 0x7cb4822f +0, 8001792, 8001792, 1152, 2304, 0xea318144 +0, 8028288, 8028288, 1152, 2304, 0xaf0f86d2 +0, 8054784, 8054784, 1152, 2304, 0x24f27598 +0, 8081280, 8081280, 1152, 2304, 0xd76f6d40 +0, 8107776, 8107776, 1152, 2304, 0x085071a7 +0, 8134272, 8134272, 1152, 2304, 0x1d11704c +0, 8160768, 8160768, 1152, 2304, 0x21517cbd +0, 8187264, 8187264, 1152, 2304, 0xcdca8d32 +0, 8213760, 8213760, 1152, 2304, 0x71c18433 +0, 8240256, 8240256, 1152, 2304, 0xd39d7d81 +0, 8266752, 8266752, 1152, 2304, 0x7a0d7a43 +0, 8293248, 8293248, 1152, 2304, 0x007c8884 +0, 8319744, 8319744, 1152, 2304, 0x403282d0 +0, 8346240, 8346240, 1152, 2304, 0xe3737214 +0, 8372736, 8372736, 1152, 2304, 0xaf906f47 +0, 8399232, 8399232, 1152, 2304, 0x54f57b3b +0, 8425728, 8425728, 1152, 2304, 0x29be7791 +0, 8452224, 8452224, 1152, 2304, 0xe3c663d5 +0, 8478720, 8478720, 1152, 2304, 0xd7258238 +0, 8505216, 8505216, 1152, 2304, 0x3719820d +0, 8531712, 8531712, 1152, 2304, 0xbe04814f +0, 8558208, 8558208, 1152, 2304, 0x556c815e +0, 8584704, 8584704, 1152, 2304, 0xb2447e10 +0, 8611200, 8611200, 1152, 2304, 0x7c16867c +0, 8637696, 8637696, 1152, 2304, 0x6a7b78ed +0, 8664192, 8664192, 1152, 2304, 0x5d307b81 +0, 8690688, 8690688, 1152, 2304, 0xaab680d3 +0, 8717184, 8717184, 1152, 2304, 0xb5d37a23 +0, 8743680, 8743680, 1152, 2304, 0x7f7d6f76 +0, 8770176, 8770176, 1152, 2304, 0x317a8296 +0, 8796672, 8796672, 1152, 2304, 0x8a987b3d +0, 8823168, 8823168, 1152, 2304, 0x4f317a27 +0, 8849664, 8849664, 1152, 2304, 0xfc65852f +0, 8876160, 8876160, 1152, 2304, 0x40527719 +0, 8902656, 8902656, 1152, 2304, 0x84988e13 +0, 8929152, 8929152, 1152, 2304, 0x318b6ddc +0, 8955648, 8955648, 1152, 2304, 0x94cf7939 +0, 8982144, 8982144, 1152, 2304, 0x6f22819d +0, 9008640, 9008640, 1152, 2304, 0xa7dd80a9 +0, 9035136, 9035136, 1152, 2304, 0x1c7968fa +0, 9061632, 9061632, 1152, 2304, 0xd9937bae +0, 9088128, 9088128, 1152, 2304, 0xf7137cf9 +0, 9114624, 9114624, 1152, 2304, 0xeadb84b5 +0, 9141120, 9141120, 1152, 2304, 0x9a2390ac +0, 9167616, 9167616, 1152, 2304, 0xdb6a73f6 +0, 9194112, 9194112, 1152, 2304, 0x69e07507 +0, 9220608, 9220608, 1152, 2304, 0xbc8478b2 +0, 9247104, 9247104, 1152, 2304, 0x32cf8638 +0, 9273600, 9273600, 1152, 2304, 0x2b8d755a +0, 9300096, 9300096, 1152, 2304, 0x52e05bd2 +0, 9326592, 9326592, 1152, 2304, 0x2aed8c49 +0, 9353088, 9353088, 1152, 2304, 0x587a896e +0, 9379584, 9379584, 1152, 2304, 0x6dd87dee +0, 9406080, 9406080, 1152, 2304, 0xd2858338 +0, 9432576, 9432576, 1152, 2304, 0xd90f7842 +0, 9459072, 9459072, 1152, 2304, 0xd6fb6d4a +0, 9485568, 9485568, 1152, 2304, 0x85498aea +0, 9512064, 9512064, 1152, 2304, 0x18597790 +0, 9538560, 9538560, 1152, 2304, 0x3cd78fea +0, 9565056, 9565056, 1152, 2304, 0x94377fbc +0, 9591552, 9591552, 1152, 2304, 0xf9db73f5 +0, 9618048, 9618048, 1152, 2304, 0x14fb6fca +0, 9644544, 9644544, 1152, 2304, 0xe9d17d69 +0, 9671040, 9671040, 1152, 2304, 0xdeb57286 +0, 9697536, 9697536, 1152, 2304, 0xa5d37e17 +0, 9724032, 9724032, 1152, 2304, 0xcf6882fb +0, 9750528, 9750528, 1152, 2304, 0x31758066 +0, 9777024, 9777024, 1152, 2304, 0x6b4d8175 +0, 9803520, 9803520, 1152, 2304, 0x2a3d7f8e +0, 9830016, 9830016, 1152, 2304, 0xc066743b +0, 9856512, 9856512, 1152, 2304, 0xcab88146 +0, 9883008, 9883008, 1152, 2304, 0x2b4c6e13 +0, 9909504, 9909504, 1152, 2304, 0x00b36b6f +0, 9936000, 9936000, 1152, 2304, 0x664a88d3 +0, 9962496, 9962496, 1152, 2304, 0x18a66f76 +0, 9988992, 9988992, 1152, 2304, 0x4f828a8b +0, 10015488, 10015488, 1152, 2304, 0x9cc7728e +0, 10041984, 10041984, 1152, 2304, 0xbe357936 +0, 10068480, 10068480, 1152, 2304, 0x19878f8d +0, 10094976, 10094976, 1152, 2304, 0x227b7c71 +0, 10121472, 10121472, 1152, 2304, 0xf7c879ec +0, 10147968, 10147968, 1152, 2304, 0x0bca7b50 +0, 10174464, 10174464, 1152, 2304, 0xe4398304 +0, 10200960, 10200960, 1152, 2304, 0xf5da75c7 +0, 10227456, 10227456, 1152, 2304, 0x9f9070a3 +0, 10253952, 10253952, 1152, 2304, 0x789076f6 +0, 10280448, 10280448, 1152, 2304, 0x362977cc +0, 10306944, 10306944, 1152, 2304, 0x4d0a8928 +0, 10333440, 10333440, 1152, 2304, 0x1bb767ec +0, 10359936, 10359936, 1152, 2304, 0xbe727fa5 +0, 10386432, 10386432, 1152, 2304, 0x27f38347 +0, 10412928, 10412928, 1152, 2304, 0x0a3c8783 +0, 10439424, 10439424, 1152, 2304, 0x8249639c +0, 10465920, 10465920, 1152, 2304, 0x3b076f69 +0, 10492416, 10492416, 1152, 2304, 0xd9597ee3 +0, 10518912, 10518912, 1152, 2304, 0x026e7fad +0, 10545408, 10545408, 1152, 2304, 0xbd7a6de4 +0, 10571904, 10571904, 1152, 2304, 0x7d718a4d +0, 10598400, 10598400, 1152, 2304, 0x1f5e83b4 +0, 10624896, 10624896, 1152, 2304, 0x597d7755 +0, 10651392, 10651392, 1152, 2304, 0x3fb080bd +0, 10677888, 10677888, 1152, 2304, 0xdcbd7b16 +0, 10704384, 10704384, 1152, 2304, 0x5c48865f +0, 10730880, 10730880, 1152, 2304, 0xcda37ae8 +0, 10757376, 10757376, 1152, 2304, 0x4810796d +0, 10783872, 10783872, 1152, 2304, 0x34317fd0 +0, 10810368, 10810368, 1152, 2304, 0x5c0e7456 +0, 10836864, 10836864, 1152, 2304, 0x44d78040 +0, 10863360, 10863360, 1152, 2304, 0x88587882 +0, 10889856, 10889856, 1152, 2304, 0x77687d5e +0, 10916352, 10916352, 1152, 2304, 0x116d68bb +0, 10942848, 10942848, 1152, 2304, 0x3e5b6f60 +0, 10969344, 10969344, 1152, 2304, 0x64ea783c +0, 10995840, 10995840, 1152, 2304, 0x23547f7d +0, 11022336, 11022336, 1152, 2304, 0x2eee7892 +0, 11048832, 11048832, 1152, 2304, 0xfb837cba +0, 11075328, 11075328, 1152, 2304, 0x86518209 +0, 11101824, 11101824, 1152, 2304, 0x672f7bba +0, 11128320, 11128320, 1152, 2304, 0x6ab583fb +0, 11154816, 11154816, 1152, 2304, 0xc1297428 +0, 11181312, 11181312, 1152, 2304, 0x164e7717 +0, 11207808, 11207808, 1152, 2304, 0xb754976d +0, 11234304, 11234304, 1152, 2304, 0xb99d81b2 +0, 11260800, 11260800, 1152, 2304, 0x79046fd6 +0, 11287296, 11287296, 1152, 2304, 0x9a3f8426 +0, 11313792, 11313792, 1152, 2304, 0x896371f5 +0, 11340288, 11340288, 1152, 2304, 0x63d1799f +0, 11366784, 11366784, 1152, 2304, 0x4842844e +0, 11393280, 11393280, 1152, 2304, 0x850e8372 +0, 11419776, 11419776, 1152, 2304, 0x85d07022 +0, 11446272, 11446272, 1152, 2304, 0x9e6683d1 +0, 11472768, 11472768, 1152, 2304, 0x301b8981 +0, 11499264, 11499264, 1152, 2304, 0x1f1e98c5 +0, 11525760, 11525760, 1152, 2304, 0xc8797b03 +0, 11552256, 11552256, 1152, 2304, 0xf9d189f5 +0, 11578752, 11578752, 1152, 2304, 0x0e0d88be +0, 11605248, 11605248, 1152, 2304, 0x6c1d7843 +0, 11631744, 11631744, 1152, 2304, 0xd13b8a38 +0, 11658240, 11658240, 1152, 2304, 0x9b8f773c +0, 11684736, 11684736, 1152, 2304, 0x9acd7309 +0, 11711232, 11711232, 1152, 2304, 0x5e7d7d15 +0, 11737728, 11737728, 1152, 2304, 0xf09d7640 +0, 11764224, 11764224, 1152, 2304, 0xaebb718f +0, 11790720, 11790720, 1152, 2304, 0x0c8570f4 +0, 11817216, 11817216, 1152, 2304, 0x3c93862c +0, 11843712, 11843712, 1152, 2304, 0xcee46696 +0, 11870208, 11870208, 1152, 2304, 0x01ba7e20 +0, 11896704, 11896704, 1152, 2304, 0x7fcb7a09 +0, 11923200, 11923200, 1152, 2304, 0xddf18c14 +0, 11949696, 11949696, 1152, 2304, 0xd2e97eeb +0, 11976192, 11976192, 1152, 2304, 0x514d8719 +0, 12002688, 12002688, 1152, 2304, 0xe89279c9 +0, 12029184, 12029184, 1152, 2304, 0x806d6a95 +0, 12055680, 12055680, 1152, 2304, 0xbc7a8a60 +0, 12082176, 12082176, 1152, 2304, 0x302f8fa8 +0, 12108672, 12108672, 1152, 2304, 0xb136784c +0, 12135168, 12135168, 1152, 2304, 0x9b0f6aab +0, 12161664, 12161664, 1152, 2304, 0xd8e27582 +0, 12188160, 12188160, 1152, 2304, 0xdaaf78b1 +0, 12214656, 12214656, 1152, 2304, 0x65967f5f +0, 12241152, 12241152, 1152, 2304, 0x6f917aa4 +0, 12267648, 12267648, 1152, 2304, 0x7f607444 +0, 12294144, 12294144, 1152, 2304, 0xfd316f2c +0, 12320640, 12320640, 1152, 2304, 0x776e83c7 +0, 12347136, 12347136, 1152, 2304, 0xb9c17e16 +0, 12373632, 12373632, 1152, 2304, 0xdf287de8 +0, 12400128, 12400128, 1152, 2304, 0xf33d96a3 +0, 12426624, 12426624, 1152, 2304, 0xad216e5b +0, 12453120, 12453120, 1152, 2304, 0x4a328342 +0, 12479616, 12479616, 1152, 2304, 0xcf3f8079 +0, 12506112, 12506112, 1152, 2304, 0xb46f77b0 +0, 12532608, 12532608, 1152, 2304, 0x3199713d +0, 12559104, 12559104, 1152, 2304, 0x5e667a0d +0, 12585600, 12585600, 1152, 2304, 0xa3047ae3 +0, 12612096, 12612096, 1152, 2304, 0x9edf8594 +0, 12638592, 12638592, 1152, 2304, 0xd16382d5 +0, 12665088, 12665088, 1152, 2304, 0x6e838328 +0, 12691584, 12691584, 1152, 2304, 0xa1f697c1 +0, 12718080, 12718080, 1152, 2304, 0xefcc749c +0, 12744576, 12744576, 1152, 2304, 0x1f94839e +0, 12771072, 12771072, 1152, 2304, 0x429e7c5b +0, 12797568, 12797568, 1152, 2304, 0x9b59711c +0, 12824064, 12824064, 1152, 2304, 0xdac27323 +0, 12850560, 12850560, 1152, 2304, 0xa4856d2b +0, 12877056, 12877056, 1152, 2304, 0x07a37498 +0, 12903552, 12903552, 1152, 2304, 0xe1ce7512 +0, 12930048, 12930048, 1152, 2304, 0x15e182c3 +0, 12956544, 12956544, 1152, 2304, 0x0fa46b8c +0, 12983040, 12983040, 1152, 2304, 0xbdf07bfd +0, 13009536, 13009536, 1152, 2304, 0xe0238b2a +0, 13036032, 13036032, 1152, 2304, 0xab537267 +0, 13062528, 13062528, 1152, 2304, 0xd46b75f3 +0, 13089024, 13089024, 1152, 2304, 0xec73794b +0, 13115520, 13115520, 1152, 2304, 0x680580c1 +0, 13142016, 13142016, 1152, 2304, 0x1ace8f6c +0, 13168512, 13168512, 1152, 2304, 0x19d583ac +0, 13195008, 13195008, 1152, 2304, 0x4b6b8105 +0, 13221504, 13221504, 1152, 2304, 0x392a78b2 +0, 13248000, 13248000, 1152, 2304, 0xd3916dad +0, 13274496, 13274496, 1152, 2304, 0x569c7a75 +0, 13300992, 13300992, 1152, 2304, 0xf5ac814b +0, 13327488, 13327488, 1152, 2304, 0x18d77e98 +0, 13353984, 13353984, 1152, 2304, 0x007074ce +0, 13380480, 13380480, 1152, 2304, 0x0fe38373 +0, 13406976, 13406976, 1152, 2304, 0x5a967920 +0, 13433472, 13433472, 1152, 2304, 0x22167501 +0, 13459968, 13459968, 1152, 2304, 0xf0828cab +0, 13486464, 13486464, 1152, 2304, 0xaeec71b7 +0, 13512960, 13512960, 1152, 2304, 0xc47b62ff +0, 13539456, 13539456, 1152, 2304, 0xab688478 +0, 13565952, 13565952, 1152, 2304, 0xf35e7bd2 +0, 13592448, 13592448, 1152, 2304, 0x9cff763e +0, 13618944, 13618944, 1152, 2304, 0x59568dc8 +0, 13645440, 13645440, 1152, 2304, 0x51a278ac +0, 13671936, 13671936, 1152, 2304, 0xc08a6e68 +0, 13698432, 13698432, 1152, 2304, 0xd3067ef4 +0, 13724928, 13724928, 1152, 2304, 0x54767c49 +0, 13751424, 13751424, 1152, 2304, 0xf8ff8386 +0, 13777920, 13777920, 1152, 2304, 0xef267f63 +0, 13804416, 13804416, 1152, 2304, 0xe2537cd9 +0, 13830912, 13830912, 1152, 2304, 0x77a57680 +0, 13857408, 13857408, 1152, 2304, 0x325c74ad +0, 13883904, 13883904, 1152, 2304, 0xd7fe87c4 +0, 13910400, 13910400, 1152, 2304, 0x2e756310 +0, 13936896, 13936896, 1152, 2304, 0x6a81796b +0, 13963392, 13963392, 1152, 2304, 0x2f057daf +0, 13989888, 13989888, 1152, 2304, 0xcd9f7c9d +0, 14016384, 14016384, 1152, 2304, 0xc91560a0 +0, 14042880, 14042880, 1152, 2304, 0x962a91eb +0, 14069376, 14069376, 1152, 2304, 0xa0ff7416 +0, 14095872, 14095872, 1152, 2304, 0xcb5c7dff +0, 14122368, 14122368, 1152, 2304, 0xd3527041 +0, 14148864, 14148864, 1152, 2304, 0xc89d77c2 +0, 14175360, 14175360, 1152, 2304, 0xe1ce7ccf +0, 14201856, 14201856, 1152, 2304, 0xe3417c4c +0, 14228352, 14228352, 1152, 2304, 0x3f1a7166 +0, 14254848, 14254848, 1152, 2304, 0xcdcc7e23 +0, 14281344, 14281344, 1152, 2304, 0x4e727e97 +0, 14307840, 14307840, 1152, 2304, 0x53427ff1 +0, 14334336, 14334336, 1152, 2304, 0x173f6ca9 +0, 14360832, 14360832, 1152, 2304, 0x962887ec +0, 14387328, 14387328, 1152, 2304, 0xcbec67f4 +0, 14413824, 14413824, 1152, 2304, 0x7a2c943d +0, 14440320, 14440320, 1152, 2304, 0x8b877570 +0, 14466816, 14466816, 1152, 2304, 0xcf337323 +0, 14493312, 14493312, 1152, 2304, 0x8c8682a4 +0, 14519808, 14519808, 1152, 2304, 0x94c3753c +0, 14546304, 14546304, 1152, 2304, 0x86898d79 +0, 14572800, 14572800, 1152, 2304, 0xdf667312 +0, 14599296, 14599296, 1152, 2304, 0x062f8ba8 +0, 14625792, 14625792, 1152, 2304, 0xa2c36f08 +0, 14652288, 14652288, 1152, 2304, 0x5bca7358 +0, 14678784, 14678784, 1152, 2304, 0x5648804d +0, 14705280, 14705280, 1152, 2304, 0xefac87c8 +0, 14731776, 14731776, 1152, 2304, 0x66bf7dcf +0, 14758272, 14758272, 1152, 2304, 0x62ad73bc +0, 14784768, 14784768, 1152, 2304, 0x72fe630c +0, 14811264, 14811264, 1152, 2304, 0xeebe87da +0, 14837760, 14837760, 1152, 2304, 0x11c870cf +0, 14864256, 14864256, 1152, 2304, 0x18fb7c27 +0, 14890752, 14890752, 1152, 2304, 0x39047145 +0, 14917248, 14917248, 1152, 2304, 0xdcf07032 +0, 14943744, 14943744, 1152, 2304, 0x61027c50 +0, 14970240, 14970240, 1152, 2304, 0x6e2e89de +0, 14996736, 14996736, 1152, 2304, 0xc50c6d1d +0, 15023232, 15023232, 1152, 2304, 0xeed587ee +0, 15049728, 15049728, 1152, 2304, 0xe38269c7 +0, 15076224, 15076224, 1152, 2304, 0xcf66806e +0, 15102720, 15102720, 1152, 2304, 0x2d3b7c1b +0, 15129216, 15129216, 1152, 2304, 0xa4127d48 +0, 15155712, 15155712, 1152, 2304, 0x480b8325 +0, 15182208, 15182208, 1152, 2304, 0xc1527221 +0, 15208704, 15208704, 1152, 2304, 0x94c1769a +0, 15235200, 15235200, 1152, 2304, 0xcfb37271 +0, 15261696, 15261696, 1152, 2304, 0x946d7a96 +0, 15288192, 15288192, 1152, 2304, 0xdfc18e50 +0, 15314688, 15314688, 1152, 2304, 0x10c48393 +0, 15341184, 15341184, 1152, 2304, 0x58556b10 +0, 15367680, 15367680, 1152, 2304, 0x997b7993 +0, 15394176, 15394176, 1152, 2304, 0x4a787992 +0, 15420672, 15420672, 1152, 2304, 0x11406c20 +0, 15447168, 15447168, 1152, 2304, 0x04a4874a +0, 15473664, 15473664, 1152, 2304, 0xf3077164 +0, 15500160, 15500160, 1152, 2304, 0x08ac80e3 +0, 15526656, 15526656, 1152, 2304, 0x268370d0 +0, 15553152, 15553152, 1152, 2304, 0x1d137778 +0, 15579648, 15579648, 1152, 2304, 0xfa148e97 +0, 15606144, 15606144, 1152, 2304, 0xec50717c +0, 15632640, 15632640, 1152, 2304, 0xcbf46b75 +0, 15659136, 15659136, 1152, 2304, 0xd4168038 +0, 15685632, 15685632, 1152, 2304, 0xdd9577f0 +0, 15712128, 15712128, 1152, 2304, 0xc7077685 +0, 15738624, 15738624, 1152, 2304, 0x34d25e91 +0, 15765120, 15765120, 1152, 2304, 0x96537e6d +0, 15791616, 15791616, 1152, 2304, 0xb12e7940 +0, 15818112, 15818112, 1152, 2304, 0x861d64c0 +0, 15844608, 15844608, 1152, 2304, 0xa2bc64ed +0, 15871104, 15871104, 1152, 2304, 0x0c5f8261 +0, 15897600, 15897600, 1152, 2304, 0x540584ff +0, 15924096, 15924096, 1152, 2304, 0xe8328b09 +0, 15950592, 15950592, 1152, 2304, 0x1e777079 +0, 15977088, 15977088, 1152, 2304, 0x453483b4 +0, 16003584, 16003584, 1152, 2304, 0x1cab7a1e +0, 16030080, 16030080, 1152, 2304, 0xcb37856d +0, 16056576, 16056576, 1152, 2304, 0x5a4883ed +0, 16083072, 16083072, 1152, 2304, 0xd1f27cbf +0, 16109568, 16109568, 1152, 2304, 0x0d377a4d +0, 16136064, 16136064, 1152, 2304, 0x264e76df +0, 16162560, 16162560, 1152, 2304, 0x2a68771e +0, 16189056, 16189056, 1152, 2304, 0xcb317a31 +0, 16215552, 16215552, 1152, 2304, 0xfc5d7a27 +0, 16242048, 16242048, 1152, 2304, 0x6e067d96 +0, 16268544, 16268544, 1152, 2304, 0x0c538560 +0, 16295040, 16295040, 1152, 2304, 0xfbad717a +0, 16321536, 16321536, 1152, 2304, 0xf9fc7608 +0, 16348032, 16348032, 1152, 2304, 0xb1817c8f +0, 16374528, 16374528, 1152, 2304, 0x57c37f82 +0, 16401024, 16401024, 1152, 2304, 0x8cac8356 +0, 16427520, 16427520, 1152, 2304, 0x97108186 +0, 16454016, 16454016, 1152, 2304, 0x095d81bb +0, 16480512, 16480512, 1152, 2304, 0x475f6b2b +0, 16507008, 16507008, 1152, 2304, 0xdf7c8cc5 +0, 16533504, 16533504, 1152, 2304, 0x979c77be +0, 16560000, 16560000, 1152, 2304, 0x56a7844b +0, 16586496, 16586496, 1152, 2304, 0x7ee46b21 +0, 16612992, 16612992, 1152, 2304, 0x05b67220 +0, 16639488, 16639488, 1152, 2304, 0x25787252 +0, 16665984, 16665984, 1152, 2304, 0x8ad278ad +0, 16692480, 16692480, 1152, 2304, 0x67bd722e +0, 16718976, 16718976, 1152, 2304, 0x204f77be +0, 16745472, 16745472, 1152, 2304, 0x82d27ae2 +0, 16771968, 16771968, 1152, 2304, 0x23fa82e4 +0, 16798464, 16798464, 1152, 2304, 0xa9cf8159 +0, 16824960, 16824960, 1152, 2304, 0x13f08749 +0, 16851456, 16851456, 1152, 2304, 0xf84f71b5 +0, 16877952, 16877952, 1152, 2304, 0x1cb777c8 +0, 16904448, 16904448, 1152, 2304, 0x11236722 +0, 16930944, 16930944, 1152, 2304, 0x10197cac +0, 16957440, 16957440, 1152, 2304, 0xbd417e65 +0, 16983936, 16983936, 1152, 2304, 0x9a1c7d05 +0, 17010432, 17010432, 1152, 2304, 0x4c3a85de +0, 17036928, 17036928, 1152, 2304, 0x03816eb7 +0, 17063424, 17063424, 1152, 2304, 0x80186e6c +0, 17089920, 17089920, 1152, 2304, 0x5c097928 +0, 17116416, 17116416, 1152, 2304, 0x94aa823d +0, 17142912, 17142912, 1152, 2304, 0xa1c27f04 +0, 17169408, 17169408, 1152, 2304, 0x6ddb74a9 +0, 17195904, 17195904, 1152, 2304, 0x5ea67901 +0, 17222400, 17222400, 1152, 2304, 0xd710742d +0, 17248896, 17248896, 1152, 2304, 0xf8c27add +0, 17275392, 17275392, 1152, 2304, 0xf1717011 +0, 17301888, 17301888, 1152, 2304, 0xb59072d0 +0, 17328384, 17328384, 1152, 2304, 0xc8dc84a7 +0, 17354880, 17354880, 1152, 2304, 0x33116737 +0, 17381376, 17381376, 1152, 2304, 0x86216bdd +0, 17407872, 17407872, 1152, 2304, 0xa2f87866 +0, 17434368, 17434368, 1152, 2304, 0x5d77771e +0, 17460864, 17460864, 1152, 2304, 0x5d8c77fd +0, 17487360, 17487360, 1152, 2304, 0x23cc89cb +0, 17513856, 17513856, 1152, 2304, 0x334e7407 +0, 17540352, 17540352, 1152, 2304, 0x01c976ff +0, 17566848, 17566848, 1152, 2304, 0x3a3b7b15 +0, 17593344, 17593344, 1152, 2304, 0xfa427de9 +0, 17619840, 17619840, 1152, 2304, 0xbeaa7c91 +0, 17646336, 17646336, 1152, 2304, 0xd6988b31 +0, 17672832, 17672832, 1152, 2304, 0x4db47f80 +0, 17699328, 17699328, 1152, 2304, 0xea687d9e +0, 17725824, 17725824, 1152, 2304, 0x1a6281ce +0, 17752320, 17752320, 1152, 2304, 0xe1958003 +0, 17778816, 17778816, 1152, 2304, 0xb4ae7c5e +0, 17805312, 17805312, 1152, 2304, 0x28827c8a +0, 17831808, 17831808, 1152, 2304, 0x1fb88b25 +0, 17858304, 17858304, 1152, 2304, 0x588d71e8 +0, 17884800, 17884800, 1152, 2304, 0x68227c34 +0, 17911296, 17911296, 1152, 2304, 0xee4d73e8 +0, 17937792, 17937792, 1152, 2304, 0x69287c6d +0, 17964288, 17964288, 1152, 2304, 0xbb04926a +0, 17990784, 17990784, 1152, 2304, 0x89456cec +0, 18017280, 18017280, 1152, 2304, 0xabe18992 +0, 18043776, 18043776, 1152, 2304, 0x50cc7f6c +0, 18070272, 18070272, 1152, 2304, 0x6d7270be +0, 18096768, 18096768, 1152, 2304, 0x664c6fef +0, 18123264, 18123264, 1152, 2304, 0x7f7982f3 +0, 18149760, 18149760, 1152, 2304, 0x6ca170e9 +0, 18176256, 18176256, 1152, 2304, 0x36437d5b +0, 18202752, 18202752, 1152, 2304, 0xfd2380e8 +0, 18229248, 18229248, 1152, 2304, 0x2e3c6e9f +0, 18255744, 18255744, 1152, 2304, 0xc8427f3f +0, 18282240, 18282240, 1152, 2304, 0x962a79ad +0, 18308736, 18308736, 1152, 2304, 0xc9597c8b +0, 18335232, 18335232, 1152, 2304, 0x899580bb +0, 18361728, 18361728, 1152, 2304, 0x2d179dff +0, 18388224, 18388224, 1152, 2304, 0x4ac1707c +0, 18414720, 18414720, 1152, 2304, 0x32ea7e95 +0, 18441216, 18441216, 1152, 2304, 0x265e9a2d +0, 18467712, 18467712, 1152, 2304, 0x1c6484d0 +0, 18494208, 18494208, 1152, 2304, 0x39ae6884 +0, 18520704, 18520704, 1152, 2304, 0x82ed7bc5 +0, 18547200, 18547200, 1152, 2304, 0x556b7b3c +0, 18573696, 18573696, 1152, 2304, 0xb7f778dd +0, 18600192, 18600192, 1152, 2304, 0x74447d55 +0, 18626688, 18626688, 1152, 2304, 0x0c66861e +0, 18653184, 18653184, 1152, 2304, 0x15ba7932 +0, 18679680, 18679680, 1152, 2304, 0xb19170fc +0, 18706176, 18706176, 1152, 2304, 0x19d37551 +0, 18732672, 18732672, 1152, 2304, 0xdc529142 +0, 18759168, 18759168, 1152, 2304, 0xf2637e77 +0, 18785664, 18785664, 1152, 2304, 0xd065944b +0, 18812160, 18812160, 1152, 2304, 0x22878123 +0, 18838656, 18838656, 1152, 2304, 0xc21a8bf7 +0, 18865152, 18865152, 1152, 2304, 0x2e3582dc +0, 18891648, 18891648, 1152, 2304, 0xd42f7987 +0, 18918144, 18918144, 1152, 2304, 0x69b88236 +0, 18944640, 18944640, 1152, 2304, 0x7c988f90 +0, 18971136, 18971136, 1152, 2304, 0x2cd66ded +0, 18997632, 18997632, 1152, 2304, 0x3e65828b +0, 19024128, 19024128, 1152, 2304, 0x7e9871c9 +0, 19050624, 19050624, 1152, 2304, 0xf1f2806b +0, 19077120, 19077120, 1152, 2304, 0xf5087c7b +0, 19103616, 19103616, 1152, 2304, 0x62b98097 +0, 19130112, 19130112, 1152, 2304, 0xec457c43 +0, 19156608, 19156608, 1152, 2304, 0x87af87a6 +0, 19183104, 19183104, 1152, 2304, 0x97cc757d +0, 19209600, 19209600, 1152, 2304, 0x08ca76bd +0, 19236096, 19236096, 1152, 2304, 0x14ae7cbd +0, 19262592, 19262592, 1152, 2304, 0x1f79709a +0, 19289088, 19289088, 1152, 2304, 0x17948207 +0, 19315584, 19315584, 1152, 2304, 0x16ee7228 +0, 19342080, 19342080, 1152, 2304, 0x76cc82d7 +0, 19368576, 19368576, 1152, 2304, 0x8f327a8e +0, 19395072, 19395072, 1152, 2304, 0x14ee7756 +0, 19421568, 19421568, 1152, 2304, 0x15996d2f +0, 19448064, 19448064, 1152, 2304, 0x4c707d5c +0, 19474560, 19474560, 1152, 2304, 0x268c6fee +0, 19501056, 19501056, 1152, 2304, 0x6d838c76 +0, 19527552, 19527552, 1152, 2304, 0xafa17e64 +0, 19554048, 19554048, 1152, 2304, 0xb6546e66 +0, 19580544, 19580544, 1152, 2304, 0x945d8b9f +0, 19607040, 19607040, 1152, 2304, 0x5bfb7446 +0, 19633536, 19633536, 1152, 2304, 0xae6086f9 +0, 19660032, 19660032, 1152, 2304, 0xa01380cd +0, 19686528, 19686528, 1152, 2304, 0x06f0828f +0, 19713024, 19713024, 1152, 2304, 0x0ae07176 +0, 19739520, 19739520, 1152, 2304, 0x66f07522 +0, 19766016, 19766016, 1152, 2304, 0x44018106 +0, 19792512, 19792512, 1152, 2304, 0x8cd283da +0, 19819008, 19819008, 1152, 2304, 0x14257f45 +0, 19845504, 19845504, 1152, 2304, 0x04979537 +0, 19872000, 19872000, 1152, 2304, 0x8b5f797c +0, 19898496, 19898496, 1152, 2304, 0x12d67493 +0, 19924992, 19924992, 1152, 2304, 0xc8886a25 +0, 19951488, 19951488, 1152, 2304, 0x614b803a +0, 19977984, 19977984, 1152, 2304, 0x75667d35 +0, 20004480, 20004480, 1152, 2304, 0xe42c7b00 +0, 20030976, 20030976, 1152, 2304, 0x37787927 +0, 20057472, 20057472, 1152, 2304, 0x85db8409 +0, 20083968, 20083968, 1152, 2304, 0x823b822c +0, 20110464, 20110464, 1152, 2304, 0xa1658479 +0, 20136960, 20136960, 1152, 2304, 0xdbe58ff7 +0, 20163456, 20163456, 1152, 2304, 0x725175e2 +0, 20189952, 20189952, 1152, 2304, 0xb2ae7741 +0, 20216448, 20216448, 1152, 2304, 0x4de169e4 +0, 20242944, 20242944, 1152, 2304, 0x3cb18530 +0, 20269440, 20269440, 1152, 2304, 0x5a0c5e7b +0, 20295936, 20295936, 1152, 2304, 0x4e1f68b6 +0, 20322432, 20322432, 1152, 2304, 0x9a0c7525 +0, 20348928, 20348928, 1152, 2304, 0x86ae6a04 +0, 20375424, 20375424, 1152, 2304, 0xf508877c +0, 20401920, 20401920, 1152, 2304, 0x29746d7c +0, 20428416, 20428416, 1152, 2304, 0x24078edb +0, 20454912, 20454912, 1152, 2304, 0x4f9784d2 +0, 20481408, 20481408, 1152, 2304, 0x24186e95 +0, 20507904, 20507904, 1152, 2304, 0xd1927b28 +0, 20534400, 20534400, 1152, 2304, 0xc77283d5 +0, 20560896, 20560896, 1152, 2304, 0xc0ad73f8 +0, 20587392, 20587392, 1152, 2304, 0x0de78524 +0, 20613888, 20613888, 1152, 2304, 0x8b0061dc +0, 20640384, 20640384, 1152, 2304, 0x37c77ad6 +0, 20666880, 20666880, 1152, 2304, 0x5eae7410 +0, 20693376, 20693376, 1152, 2304, 0x72d97ab5 +0, 20719872, 20719872, 1152, 2304, 0x1afd8745 +0, 20746368, 20746368, 1152, 2304, 0xe30b7c9b +0, 20772864, 20772864, 1152, 2304, 0xe86480b3 +0, 20799360, 20799360, 1152, 2304, 0xb9c77a4e +0, 20825856, 20825856, 1152, 2304, 0x64508f2a +0, 20852352, 20852352, 1152, 2304, 0x839a74ed +0, 20878848, 20878848, 1152, 2304, 0x12147a5d +0, 20905344, 20905344, 1152, 2304, 0x33b07d3b +0, 20931840, 20931840, 1152, 2304, 0x65e67731 +0, 20958336, 20958336, 1152, 2304, 0x8d1c8191 +0, 20984832, 20984832, 1152, 2304, 0xada17701 +0, 21011328, 21011328, 1152, 2304, 0x49d47f6c +0, 21037824, 21037824, 1152, 2304, 0x5df97989 +0, 21064320, 21064320, 1152, 2304, 0x0db17ad9 +0, 21090816, 21090816, 1152, 2304, 0x0d3281d7 +0, 21117312, 21117312, 1152, 2304, 0x2503704f +0, 21143808, 21143808, 1152, 2304, 0xdf7c73d0 +0, 21170304, 21170304, 1152, 2304, 0x93dd737c +0, 21196800, 21196800, 1152, 2304, 0x48ed5740 +0, 21223296, 21223296, 1152, 2304, 0x6d477eaf +0, 21249792, 21249792, 1152, 2304, 0xe72373a1 +0, 21276288, 21276288, 1152, 2304, 0x7d3e7e2e +0, 21302784, 21302784, 1152, 2304, 0x0d167743 +0, 21329280, 21329280, 1152, 2304, 0xc2d97f6c +0, 21355776, 21355776, 1152, 2304, 0xc66175a0 +0, 21382272, 21382272, 1152, 2304, 0xd0127475 +0, 21408768, 21408768, 1152, 2304, 0xdbf57801 +0, 21435264, 21435264, 1152, 2304, 0x52b47a8e +0, 21461760, 21461760, 1152, 2304, 0xc96b80c5 +0, 21488256, 21488256, 1152, 2304, 0x070c76cf +0, 21514752, 21514752, 1152, 2304, 0x2aa07ee2 +0, 21541248, 21541248, 1152, 2304, 0x04059074 +0, 21567744, 21567744, 1152, 2304, 0x228f6def +0, 21594240, 21594240, 1152, 2304, 0x927893a8 +0, 21620736, 21620736, 1152, 2304, 0x581a87df +0, 21647232, 21647232, 1152, 2304, 0x0d3f653c +0, 21673728, 21673728, 1152, 2304, 0xc0e775f3 +0, 21700224, 21700224, 1152, 2304, 0x41d98473 +0, 21726720, 21726720, 1152, 2304, 0x68fb775a +0, 21753216, 21753216, 1152, 2304, 0x81e0810e +0, 21779712, 21779712, 1152, 2304, 0xf35790d3 +0, 21806208, 21806208, 1152, 2304, 0xc1468c45 +0, 21832704, 21832704, 1152, 2304, 0x6949796a +0, 21859200, 21859200, 1152, 2304, 0xa0bb7dcd +0, 21885696, 21885696, 1152, 2304, 0x50af8424 +0, 21912192, 21912192, 1152, 2304, 0x449b7d37 +0, 21938688, 21938688, 1152, 2304, 0xcf2779a8 +0, 21965184, 21965184, 1152, 2304, 0x069d894e +0, 21991680, 21991680, 1152, 2304, 0x41bd7334 +0, 22018176, 22018176, 1152, 2304, 0x0dfd8c05 +0, 22044672, 22044672, 1152, 2304, 0x2ce27b9d +0, 22071168, 22071168, 1152, 2304, 0x422875b5 +0, 22097664, 22097664, 1152, 2304, 0xd5297389 +0, 22124160, 22124160, 1152, 2304, 0x49ed8668 +0, 22150656, 22150656, 1152, 2304, 0x2a9a810b +0, 22177152, 22177152, 1152, 2304, 0x5a3f7b43 +0, 22203648, 22203648, 1152, 2304, 0x32087c12 +0, 22230144, 22230144, 1152, 2304, 0x759c7bba +0, 22256640, 22256640, 1152, 2304, 0x5b26823b +0, 22283136, 22283136, 1152, 2304, 0xeeb872ef +0, 22309632, 22309632, 1152, 2304, 0x6eb0869d +0, 22336128, 22336128, 1152, 2304, 0x4b3e764f +0, 22362624, 22362624, 1152, 2304, 0x30a66fdb +0, 22389120, 22389120, 1152, 2304, 0x958374ff +0, 22415616, 22415616, 1152, 2304, 0x411b71cc +0, 22442112, 22442112, 1152, 2304, 0x80136759 +0, 22468608, 22468608, 1152, 2304, 0x05ed6793 +0, 22495104, 22495104, 1152, 2304, 0x48f18827 +0, 22521600, 22521600, 1152, 2304, 0xb40d7866 +0, 22548096, 22548096, 1152, 2304, 0xcad18c4a +0, 22574592, 22574592, 1152, 2304, 0x9ad68582 +0, 22601088, 22601088, 1152, 2304, 0x3ad17fce +0, 22627584, 22627584, 1152, 2304, 0x824b7af6 +0, 22654080, 22654080, 1152, 2304, 0xcc9d894f +0, 22680576, 22680576, 1152, 2304, 0x46167a70 +0, 22707072, 22707072, 1152, 2304, 0x2479872a +0, 22733568, 22733568, 1152, 2304, 0x58cb72a5 +0, 22760064, 22760064, 1152, 2304, 0x01957747 +0, 22786560, 22786560, 1152, 2304, 0x6df172cb +0, 22813056, 22813056, 1152, 2304, 0x9ebd7ed9 +0, 22839552, 22839552, 1152, 2304, 0x89436a53 +0, 22866048, 22866048, 1152, 2304, 0xcce78433 +0, 22892544, 22892544, 1152, 2304, 0x1b7a70f2 +0, 22919040, 22919040, 1152, 2304, 0x530584d7 +0, 22945536, 22945536, 1152, 2304, 0xda158aa9 +0, 22972032, 22972032, 1152, 2304, 0xe85e7b90 +0, 22998528, 22998528, 1152, 2304, 0xa8ac8176 +0, 23025024, 23025024, 1152, 2304, 0xe43578a9 +0, 23051520, 23051520, 1152, 2304, 0x9ecc7c30 +0, 23078016, 23078016, 1152, 2304, 0x1cbd8591 +0, 23104512, 23104512, 1152, 2304, 0x84917bd9 +0, 23131008, 23131008, 1152, 2304, 0xea8477e4 +0, 23157504, 23157504, 1152, 2304, 0xf50c7ea1 +0, 23184000, 23184000, 1152, 2304, 0xc85e76e7 +0, 23210496, 23210496, 1152, 2304, 0xa5148768 +0, 23236992, 23236992, 1152, 2304, 0x2bd5846a +0, 23263488, 23263488, 1152, 2304, 0x1cd88641 +0, 23289984, 23289984, 1152, 2304, 0x04b883c5 +0, 23316480, 23316480, 1152, 2304, 0x5bf1719b +0, 23342976, 23342976, 1152, 2304, 0x0abe777c +0, 23369472, 23369472, 1152, 2304, 0xc74a7f7f +0, 23395968, 23395968, 1152, 2304, 0xd36a724b +0, 23422464, 23422464, 1152, 2304, 0x4ae67e9e +0, 23448960, 23448960, 1152, 2304, 0xfb6173a0 +0, 23475456, 23475456, 1152, 2304, 0x31d77e19 +0, 23501952, 23501952, 1152, 2304, 0x6153767d +0, 23528448, 23528448, 1152, 2304, 0xe40d84e4 +0, 23554944, 23554944, 1152, 2304, 0xc8ef71e2 +0, 23581440, 23581440, 1152, 2304, 0xdeca81be +0, 23607936, 23607936, 1152, 2304, 0x75da85df +0, 23634432, 23634432, 1152, 2304, 0x6c8e71bd +0, 23660928, 23660928, 1152, 2304, 0x6f8576a4 +0, 23687424, 23687424, 1152, 2304, 0xe6637b71 +0, 23713920, 23713920, 1152, 2304, 0xddfe8866 +0, 23740416, 23740416, 1152, 2304, 0xa08578a5 +0, 23766912, 23766912, 1152, 2304, 0x72af7873 +0, 23793408, 23793408, 1152, 2304, 0xb550615c +0, 23819904, 23819904, 1152, 2304, 0x9ef87d28 +0, 23846400, 23846400, 1152, 2304, 0xe30d83bf +0, 23872896, 23872896, 1152, 2304, 0xf030818c +0, 23899392, 23899392, 1152, 2304, 0x1e23896c +0, 23925888, 23925888, 1152, 2304, 0xf4c87180 +0, 23952384, 23952384, 1152, 2304, 0xe34181aa +0, 23978880, 23978880, 1152, 2304, 0x660681cb +0, 24005376, 24005376, 1152, 2304, 0x7ebb87fc +0, 24031872, 24031872, 1152, 2304, 0xa8305eeb +0, 24058368, 24058368, 1152, 2304, 0xea898906 +0, 24084864, 24084864, 1152, 2304, 0x342b6c13 +0, 24111360, 24111360, 1152, 2304, 0x7fd18372 +0, 24137856, 24137856, 1152, 2304, 0x965c7377 +0, 24164352, 24164352, 1152, 2304, 0xb53b70b3 +0, 24190848, 24190848, 1152, 2304, 0xd54884d1 +0, 24217344, 24217344, 1152, 2304, 0x546d77ac +0, 24243840, 24243840, 1152, 2304, 0xd7a77dc7 +0, 24270336, 24270336, 1152, 2304, 0x4b0e7c5c +0, 24296832, 24296832, 1152, 2304, 0x346d7026 +0, 24323328, 24323328, 1152, 2304, 0x3f346e81 +0, 24349824, 24349824, 1152, 2304, 0x3f167098 +0, 24376320, 24376320, 1152, 2304, 0x1c857987 +0, 24402816, 24402816, 1152, 2304, 0xf9317c16 +0, 24429312, 24429312, 1152, 2304, 0x25ea82c4 +0, 24455808, 24455808, 1152, 2304, 0x2b0f90bb +0, 24482304, 24482304, 1152, 2304, 0x999668db +0, 24508800, 24508800, 1152, 2304, 0x9a0676da +0, 24535296, 24535296, 1152, 2304, 0x97a87172 +0, 24561792, 24561792, 1152, 2304, 0x323d7ace +0, 24588288, 24588288, 1152, 2304, 0x1b538baa +0, 24614784, 24614784, 1152, 2304, 0xeb208b72 +0, 24641280, 24641280, 1152, 2304, 0x36c69152 +0, 24667776, 24667776, 1152, 2304, 0x570c7bac +0, 24694272, 24694272, 1152, 2304, 0xd7287c72 +0, 24720768, 24720768, 1152, 2304, 0xc4d78776 +0, 24747264, 24747264, 1152, 2304, 0xdcbb7735 +0, 24773760, 24773760, 1152, 2304, 0x08066d78 +0, 24800256, 24800256, 1152, 2304, 0x5cb96bad +0, 24826752, 24826752, 1152, 2304, 0x30d58180 +0, 24853248, 24853248, 1152, 2304, 0x3ac96b87 +0, 24879744, 24879744, 1152, 2304, 0x1fc878d2 +0, 24906240, 24906240, 1152, 2304, 0x2c7c85d4 +0, 24932736, 24932736, 1152, 2304, 0x6c307caa +0, 24959232, 24959232, 1152, 2304, 0x647b6d6e +0, 24985728, 24985728, 1152, 2304, 0xfbef7e51 +0, 25012224, 25012224, 1152, 2304, 0x27867bd7 +0, 25038720, 25038720, 1152, 2304, 0xa2b875b1 +0, 25065216, 25065216, 1152, 2304, 0xc7dd73fb +0, 25091712, 25091712, 1152, 2304, 0x717e79e9 +0, 25118208, 25118208, 1152, 2304, 0xfecb710d +0, 25144704, 25144704, 1152, 2304, 0xa5308333 +0, 25171200, 25171200, 1152, 2304, 0x92fe6b77 +0, 25197696, 25197696, 1152, 2304, 0x7db17ad6 +0, 25224192, 25224192, 1152, 2304, 0x1248786d +0, 25250688, 25250688, 1152, 2304, 0xf3647a8a +0, 25277184, 25277184, 1152, 2304, 0x7b2173f0 +0, 25303680, 25303680, 1152, 2304, 0xfd1f7a3c +0, 25330176, 25330176, 1152, 2304, 0x09e57f3e +0, 25356672, 25356672, 1152, 2304, 0x13d7798d +0, 25383168, 25383168, 1152, 2304, 0x7d4d758a +0, 25409664, 25409664, 1152, 2304, 0xdf1a80be +0, 25436160, 25436160, 1152, 2304, 0xb91b7cb9 +0, 25462656, 25462656, 1152, 2304, 0x102e73ba +0, 25489152, 25489152, 1152, 2304, 0x8dce8428 +0, 25515648, 25515648, 1152, 2304, 0xdf9070f6 +0, 25542144, 25542144, 1152, 2304, 0x27d77bb4 +0, 25568640, 25568640, 1152, 2304, 0x2f8a8579 +0, 25595136, 25595136, 1152, 2304, 0xd1e27204 +0, 25621632, 25621632, 1152, 2304, 0x4f087920 +0, 25648128, 25648128, 1152, 2304, 0x69f58306 +0, 25674624, 25674624, 1152, 2304, 0xfc7378b0 +0, 25701120, 25701120, 1152, 2304, 0x8b167d89 +0, 25727616, 25727616, 1152, 2304, 0x0c867235 +0, 25754112, 25754112, 1152, 2304, 0xc3126e09 +0, 25780608, 25780608, 1152, 2304, 0x7d097d89 +0, 25807104, 25807104, 1152, 2304, 0x73dc664e +0, 25833600, 25833600, 1152, 2304, 0xdc247a0a +0, 25860096, 25860096, 1152, 2304, 0xaa8d7f2f +0, 25886592, 25886592, 1152, 2304, 0x9a1d744b +0, 25913088, 25913088, 1152, 2304, 0xd9e87475 +0, 25939584, 25939584, 1152, 2304, 0xf6f182ab +0, 25966080, 25966080, 1152, 2304, 0x4937706b +0, 25992576, 25992576, 1152, 2304, 0x837189b1 +0, 26019072, 26019072, 1152, 2304, 0xd565975d +0, 26045568, 26045568, 1152, 2304, 0xc6156a56 +0, 26072064, 26072064, 1152, 2304, 0xcd9c8107 +0, 26098560, 26098560, 1152, 2304, 0x1f868400 +0, 26125056, 26125056, 1152, 2304, 0xeddb71e0 +0, 26151552, 26151552, 1152, 2304, 0x5fa2782a +0, 26178048, 26178048, 1152, 2304, 0x9b076e22 +0, 26204544, 26204544, 1152, 2304, 0x90027ba7 +0, 26231040, 26231040, 1152, 2304, 0x40a481fd +0, 26257536, 26257536, 1152, 2304, 0x240873bf +0, 26284032, 26284032, 1152, 2304, 0x28cd7d8e +0, 26310528, 26310528, 1152, 2304, 0x5d4287b0 +0, 26337024, 26337024, 1152, 2304, 0xf9567c4b +0, 26363520, 26363520, 1152, 2304, 0x67dd924a +0, 26390016, 26390016, 1152, 2304, 0x33d37b4c +0, 26416512, 26416512, 1152, 2304, 0x37316d0b +0, 26443008, 26443008, 1152, 2304, 0x43a877dc +0, 26469504, 26469504, 1152, 2304, 0x44fc90bc +0, 26496000, 26496000, 1152, 2304, 0x90f5774c +0, 26522496, 26522496, 1152, 2304, 0x106e85a0 +0, 26548992, 26548992, 1152, 2304, 0xb78b7f83 +0, 26575488, 26575488, 1152, 2304, 0x3c3a77af +0, 26601984, 26601984, 1152, 2304, 0x7a5f7282 +0, 26628480, 26628480, 1152, 2304, 0x164d891a +0, 26654976, 26654976, 1152, 2304, 0x930a7194 +0, 26681472, 26681472, 1152, 2304, 0xb2628013 +0, 26707968, 26707968, 1152, 2304, 0x3adf7e1c +0, 26734464, 26734464, 1152, 2304, 0x48627c45 +0, 26760960, 26760960, 1152, 2304, 0xa3367cca +0, 26787456, 26787456, 1152, 2304, 0x9cf77248 +0, 26813952, 26813952, 1152, 2304, 0x75a86acb +0, 26840448, 26840448, 1152, 2304, 0x75487698 +0, 26866944, 26866944, 1152, 2304, 0xd65b8389 +0, 26893440, 26893440, 1152, 2304, 0xb71d84b5 +0, 26919936, 26919936, 1152, 2304, 0xdca87e42 +0, 26946432, 26946432, 1152, 2304, 0x44dd7d72 +0, 26972928, 26972928, 1152, 2304, 0xb29465da +0, 26999424, 26999424, 1152, 2304, 0x88ed8930 +0, 27025920, 27025920, 1152, 2304, 0xabdd8096 +0, 27052416, 27052416, 1152, 2304, 0xe5f57653 +0, 27078912, 27078912, 1152, 2304, 0x7c777984 +0, 27105408, 27105408, 1152, 2304, 0x631d7deb +0, 27131904, 27131904, 1152, 2304, 0x70d36e1f +0, 27158400, 27158400, 1152, 2304, 0x412c802b +0, 27184896, 27184896, 1152, 2304, 0xacc281c1 +0, 27211392, 27211392, 1152, 2304, 0x569d86a8 +0, 27237888, 27237888, 1152, 2304, 0x5c69743f +0, 27264384, 27264384, 1152, 2304, 0x29637794 +0, 27290880, 27290880, 1152, 2304, 0x0d1b7a4f +0, 27317376, 27317376, 1152, 2304, 0xfc6978a6 +0, 27343872, 27343872, 1152, 2304, 0x9b178987 +0, 27370368, 27370368, 1152, 2304, 0xe436714a +0, 27396864, 27396864, 1152, 2304, 0x783a7b6e +0, 27423360, 27423360, 1152, 2304, 0x6ff16f4e +0, 27449856, 27449856, 1152, 2304, 0x9fd582cc +0, 27476352, 27476352, 1152, 2304, 0xff0d6bc9 +0, 27502848, 27502848, 1152, 2304, 0x6f4975d5 +0, 27529344, 27529344, 1152, 2304, 0x94a77a90 +0, 27555840, 27555840, 1152, 2304, 0x764f80db +0, 27582336, 27582336, 1152, 2304, 0x68e88782 +0, 27608832, 27608832, 1152, 2304, 0x91a378e8 +0, 27635328, 27635328, 1152, 2304, 0x29f26903 +0, 27661824, 27661824, 1152, 2304, 0xc3b684d4 +0, 27688320, 27688320, 1152, 2304, 0x7d95921f +0, 27714816, 27714816, 1152, 2304, 0x876a7ded +0, 27741312, 27741312, 1152, 2304, 0x0fbe7ee8 +0, 27767808, 27767808, 1152, 2304, 0x7d0f78c5 +0, 27794304, 27794304, 1152, 2304, 0xce906ba8 +0, 27820800, 27820800, 1152, 2304, 0xd281747b +0, 27847296, 27847296, 1152, 2304, 0xec38811b +0, 27873792, 27873792, 1152, 2304, 0x8170810a +0, 27900288, 27900288, 1152, 2304, 0x4d858ba2 +0, 27926784, 27926784, 1152, 2304, 0x8c798662 +0, 27953280, 27953280, 1152, 2304, 0x23a8879b +0, 27979776, 27979776, 1152, 2304, 0x9d0c8894 +0, 28006272, 28006272, 1152, 2304, 0xf07c681f +0, 28032768, 28032768, 1152, 2304, 0x03ab6f7a +0, 28059264, 28059264, 1152, 2304, 0x88c170c2 +0, 28085760, 28085760, 1152, 2304, 0xeb977bf3 +0, 28112256, 28112256, 1152, 2304, 0x33b6774f +0, 28138752, 28138752, 1152, 2304, 0x534c776e +0, 28165248, 28165248, 1152, 2304, 0x33c4826a +0, 28191744, 28191744, 1152, 2304, 0xdb9878d8 +0, 28218240, 28218240, 1152, 2304, 0xeffd789b +0, 28244736, 28244736, 1152, 2304, 0x2cc9862f +0, 28271232, 28271232, 1152, 2304, 0x9bf18131 +0, 28297728, 28297728, 1152, 2304, 0xfa078144 +0, 28324224, 28324224, 1152, 2304, 0x922885d2 +0, 28350720, 28350720, 1152, 2304, 0x29ad7796 +0, 28377216, 28377216, 1152, 2304, 0x62766f3f +0, 28403712, 28403712, 1152, 2304, 0x72a873a5 +0, 28430208, 28430208, 1152, 2304, 0x65176e4d +0, 28456704, 28456704, 1152, 2304, 0x75447cbd +0, 28483200, 28483200, 1152, 2304, 0x83528e32 +0, 28509696, 28509696, 1152, 2304, 0x0c758531 +0, 28536192, 28536192, 1152, 2304, 0x4a5c7a84 +0, 28562688, 28562688, 1152, 2304, 0xd5937648 +0, 28589184, 28589184, 1152, 2304, 0xef5c8983 +0, 28615680, 28615680, 1152, 2304, 0x24b281d0 +0, 28642176, 28642176, 1152, 2304, 0xc0af7017 +0, 28668672, 28668672, 1152, 2304, 0xf1cc7145 +0, 28695168, 28695168, 1152, 2304, 0x7ddb7a3b +0, 28721664, 28721664, 1152, 2304, 0xd2e57692 +0, 28748160, 28748160, 1152, 2304, 0x7abc61d6 +0, 28774656, 28774656, 1152, 2304, 0x44a68338 +0, 28801152, 28801152, 1152, 2304, 0x9cad810e +0, 28827648, 28827648, 1152, 2304, 0xbf3a7f51 +0, 28854144, 28854144, 1152, 2304, 0x52ac815e +0, 28880640, 28880640, 1152, 2304, 0xdf327e10 +0, 28907136, 28907136, 1152, 2304, 0x797c867b +0, 28933632, 28933632, 1152, 2304, 0x685b79ec +0, 28960128, 28960128, 1152, 2304, 0x60267b82 +0, 28986624, 28986624, 1152, 2304, 0xe70e7fd4 +0, 29013120, 29013120, 1152, 2304, 0xaf197a22 +0, 29039616, 29039616, 1152, 2304, 0xf5e57075 +0, 29066112, 29066112, 1152, 2304, 0xa86f8197 +0, 29092608, 29092608, 1152, 2304, 0x922c7b3d +0, 29119104, 29119104, 1152, 2304, 0x8e3b7929 +0, 29145600, 29145600, 1152, 2304, 0x816f862d +0, 29172096, 29172096, 1152, 2304, 0xc09c761a +0, 29198592, 29198592, 1152, 2304, 0xf1cd9010 +0, 29225088, 29225088, 1152, 2304, 0xcf5c72d8 +0, 29251584, 29251584, 1152, 2304, 0x0e607a38 +0, 29278080, 29278080, 1152, 2304, 0x6cb0819c +0, 29304576, 29304576, 1152, 2304, 0x9e2880aa +0, 29331072, 29331072, 1152, 2304, 0xb46f69f9 +0, 29357568, 29357568, 1152, 2304, 0xbc807eab +0, 29384064, 29384064, 1152, 2304, 0x91237cf9 +0, 29410560, 29410560, 1152, 2304, 0xb6bf82b6 +0, 29437056, 29437056, 1152, 2304, 0xfcd58daf +0, 29463552, 29463552, 1152, 2304, 0x53b176f4 +0, 29490048, 29490048, 1152, 2304, 0xc79d7507 +0, 29516544, 29516544, 1152, 2304, 0x810677b2 +0, 29543040, 29543040, 1152, 2304, 0x13148737 +0, 29569536, 29569536, 1152, 2304, 0x2eb5755a +0, 29596032, 29596032, 1152, 2304, 0x5bec5cd2 +0, 29622528, 29622528, 1152, 2304, 0x66c68d47 +0, 29649024, 29649024, 1152, 2304, 0x55d18770 +0, 29675520, 29675520, 1152, 2304, 0x13997def +0, 29702016, 29702016, 1152, 2304, 0x23cd8437 +0, 29728512, 29728512, 1152, 2304, 0x5cd07942 +0, 29755008, 29755008, 1152, 2304, 0x43ab6b4c +0, 29781504, 29781504, 1152, 2304, 0xc55788ec +0, 29808000, 29808000, 1152, 2304, 0x6b69788e +0, 29834496, 29834496, 1152, 2304, 0xcacb8fea +0, 29860992, 29860992, 1152, 2304, 0x83407ebd +0, 29887488, 29887488, 1152, 2304, 0x998275f3 +0, 29913984, 29913984, 1152, 2304, 0x0ca76dcc +0, 29940480, 29940480, 1152, 2304, 0xa1ff7c6a +0, 29966976, 29966976, 1152, 2304, 0x4a597683 +0, 29993472, 29993472, 1152, 2304, 0xc8e57f16 +0, 30019968, 30019968, 1152, 2304, 0x376d82fb +0, 30046464, 30046464, 1152, 2304, 0x489b8164 +0, 30072960, 30072960, 1152, 2304, 0xece27f77 +0, 30099456, 30099456, 1152, 2304, 0x4c197e8f +0, 30125952, 30125952, 1152, 2304, 0x6eb07739 +0, 30152448, 30152448, 1152, 2304, 0xef628145 +0, 30178944, 30178944, 1152, 2304, 0x549d6f12 +0, 30205440, 30205440, 1152, 2304, 0xbe566b70 +0, 30231936, 30231936, 1152, 2304, 0x2bde87d3 +0, 30258432, 30258432, 1152, 2304, 0x0ffd7175 +0, 30284928, 30284928, 1152, 2304, 0x47d28a8b +0, 30311424, 30311424, 1152, 2304, 0x6f6c718e +0, 30337920, 30337920, 1152, 2304, 0x665e7937 +0, 30364416, 30364416, 1152, 2304, 0x73538e8d +0, 30390912, 30390912, 1152, 2304, 0x56167d71 +0, 30417408, 30417408, 1152, 2304, 0x3d0278ed +0, 30443904, 30443904, 1152, 2304, 0x9baf7a51 +0, 30470400, 30470400, 1152, 2304, 0x8c058105 +0, 30496896, 30496896, 1152, 2304, 0x2b9573ca +0, 30523392, 30523392, 1152, 2304, 0x4a2271a1 +0, 30549888, 30549888, 1152, 2304, 0x3d5276f6 +0, 30576384, 30576384, 1152, 2304, 0x43c076cd +0, 30602880, 30602880, 1152, 2304, 0x4fec8929 +0, 30629376, 30629376, 1152, 2304, 0xaa7167ec +0, 30655872, 30655872, 1152, 2304, 0x39ff7ea5 +0, 30682368, 30682368, 1152, 2304, 0x2dd58348 +0, 30708864, 30708864, 1152, 2304, 0x03fc8782 +0, 30735360, 30735360, 1152, 2304, 0x55a4649c +0, 30761856, 30761856, 1152, 2304, 0x71407067 +0, 30788352, 30788352, 1152, 2304, 0x3b667ce6 +0, 30814848, 30814848, 1152, 2304, 0xb12e81aa +0, 30841344, 30841344, 1152, 2304, 0xc1646ee3 +0, 30867840, 30867840, 1152, 2304, 0x6b55884f +0, 30894336, 30894336, 1152, 2304, 0x292382b5 +0, 30920832, 30920832, 1152, 2304, 0x18f97854 +0, 30947328, 30947328, 1152, 2304, 0x47a480be +0, 30973824, 30973824, 1152, 2304, 0xe0857b16 +0, 31000320, 31000320, 1152, 2304, 0xe3368462 +0, 31026816, 31026816, 1152, 2304, 0xced17ae8 +0, 31053312, 31053312, 1152, 2304, 0x4020796d +0, 31079808, 31079808, 1152, 2304, 0x26797fd0 +0, 31106304, 31106304, 1152, 2304, 0x0e087554 +0, 31132800, 31132800, 1152, 2304, 0xf8868040 +0, 31159296, 31159296, 1152, 2304, 0x3f0a7784 +0, 31185792, 31185792, 1152, 2304, 0xbe517d5e +0, 31212288, 31212288, 1152, 2304, 0xed0b66bc +0, 31238784, 31238784, 1152, 2304, 0x79b96d63 +0, 31265280, 31265280, 1152, 2304, 0x1ab4793a +0, 31291776, 31291776, 1152, 2304, 0xd2db7f7d +0, 31318272, 31318272, 1152, 2304, 0x91017992 +0, 31344768, 31344768, 1152, 2304, 0xf88f7cb9 +0, 31371264, 31371264, 1152, 2304, 0x0cc98309 +0, 31397760, 31397760, 1152, 2304, 0x38b77cb8 +0, 31424256, 31424256, 1152, 2304, 0x0cb185f9 +0, 31450752, 31450752, 1152, 2304, 0xc4a27824 +0, 31477248, 31477248, 1152, 2304, 0x1ce97618 +0, 31503744, 31503744, 1152, 2304, 0x1423976e +0, 31530240, 31530240, 1152, 2304, 0xdbb781b2 +0, 31556736, 31556736, 1152, 2304, 0x156d71d3 +0, 31583232, 31583232, 1152, 2304, 0xce228625 +0, 31609728, 31609728, 1152, 2304, 0x318072f3 +0, 31636224, 31636224, 1152, 2304, 0x464b77a1 +0, 31662720, 31662720, 1152, 2304, 0x0204854d +0, 31689216, 31689216, 1152, 2304, 0x498c8373 +0, 31715712, 31715712, 1152, 2304, 0xfe1a6e23 +0, 31742208, 31742208, 1152, 2304, 0x705284d0 +0, 31768704, 31768704, 1152, 2304, 0x91848980 +0, 31795200, 31795200, 1152, 2304, 0x259098c5 +0, 31821696, 31821696, 1152, 2304, 0x52b07c02 +0, 31848192, 31848192, 1152, 2304, 0x017289f6 +0, 31874688, 31874688, 1152, 2304, 0xb87687bf +0, 31901184, 31901184, 1152, 2304, 0x72de7843 +0, 31927680, 31927680, 1152, 2304, 0x3daf8939 +0, 31954176, 31954176, 1152, 2304, 0x0dfb763c +0, 31980672, 31980672, 1152, 2304, 0xc3017408 +0, 32007168, 32007168, 1152, 2304, 0x73f27f14 +0, 32033664, 32033664, 1152, 2304, 0x1c517541 +0, 32060160, 32060160, 1152, 2304, 0xf390748b +0, 32086656, 32086656, 1152, 2304, 0xe6ac71f3 +0, 32113152, 32113152, 1152, 2304, 0x6277862d +0, 32139648, 32139648, 1152, 2304, 0x923d6794 +0, 32166144, 32166144, 1152, 2304, 0x320a7f20 +0, 32192640, 32192640, 1152, 2304, 0x12f07a09 +0, 32219136, 32219136, 1152, 2304, 0xf9568b14 +0, 32245632, 32245632, 1152, 2304, 0x4d787fea +0, 32272128, 32272128, 1152, 2304, 0x57c5861a +0, 32298624, 32298624, 1152, 2304, 0x826b7cc7 +0, 32325120, 32325120, 1152, 2304, 0x7d056a94 +0, 32351616, 32351616, 1152, 2304, 0xbf3e8a60 +0, 32378112, 32378112, 1152, 2304, 0x5e518cab +0, 32404608, 32404608, 1152, 2304, 0x64e7794b +0, 32431104, 32431104, 1152, 2304, 0x9c9569ac +0, 32457600, 32457600, 1152, 2304, 0xde167582 +0, 32484096, 32484096, 1152, 2304, 0xdd8f78b1 +0, 32510592, 32510592, 1152, 2304, 0xec577e60 +0, 32537088, 32537088, 1152, 2304, 0x06877aa4 +0, 32563584, 32563584, 1152, 2304, 0xb5157742 +0, 32590080, 32590080, 1152, 2304, 0xf9be6f2b +0, 32616576, 32616576, 1152, 2304, 0xf95784c7 +0, 32643072, 32643072, 1152, 2304, 0x5aec7e15 +0, 32669568, 32669568, 1152, 2304, 0x666e7ce9 +0, 32696064, 32696064, 1152, 2304, 0xa76393a7 +0, 32722560, 32722560, 1152, 2304, 0xd1bb6d5c +0, 32749056, 32749056, 1152, 2304, 0x48d88144 +0, 32775552, 32775552, 1152, 2304, 0xa7df8177 +0, 32802048, 32802048, 1152, 2304, 0x906476b1 +0, 32828544, 32828544, 1152, 2304, 0x9f46723d +0, 32855040, 32855040, 1152, 2304, 0xa6d37a0c +0, 32881536, 32881536, 1152, 2304, 0x73e57be2 +0, 32908032, 32908032, 1152, 2304, 0x666e8594 +0, 32934528, 32934528, 1152, 2304, 0xd4b481d7 +0, 32961024, 32961024, 1152, 2304, 0xfced8427 +0, 32987520, 32987520, 1152, 2304, 0x743999bd +0, 33014016, 33014016, 1152, 2304, 0x71dd759b +0, 33040512, 33040512, 1152, 2304, 0x54a2849e +0, 33067008, 33067008, 1152, 2304, 0x07377f58 +0, 33093504, 33093504, 1152, 2304, 0xfd8f721a +0, 33120000, 33120000, 1152, 2304, 0x4d917422 +0, 33146496, 33146496, 1152, 2304, 0xaaa46e2b +0, 33172992, 33172992, 1152, 2304, 0x49e57597 +0, 33199488, 33199488, 1152, 2304, 0x29337511 +0, 33225984, 33225984, 1152, 2304, 0xdfee84c2 +0, 33252480, 33252480, 1152, 2304, 0x57266b8c +0, 33278976, 33278976, 1152, 2304, 0x5bf27cfc +0, 33305472, 33305472, 1152, 2304, 0xdc4b8b29 +0, 33331968, 33331968, 1152, 2304, 0xf49e7466 +0, 33358464, 33358464, 1152, 2304, 0xf1d975f3 +0, 33384960, 33384960, 1152, 2304, 0xc863774d +0, 33411456, 33411456, 1152, 2304, 0x5fab80c0 +0, 33437952, 33437952, 1152, 2304, 0x19548d6f +0, 33464448, 33464448, 1152, 2304, 0x165983ac +0, 33490944, 33490944, 1152, 2304, 0x2d658203 +0, 33517440, 33517440, 1152, 2304, 0x717678b2 +0, 33543936, 33543936, 1152, 2304, 0x1ed26dae +0, 33570432, 33570432, 1152, 2304, 0xecef7975 +0, 33596928, 33596928, 1152, 2304, 0xcd2b804c +0, 33623424, 33623424, 1152, 2304, 0xf4597f97 +0, 33649920, 33649920, 1152, 2304, 0x904b75cd +0, 33676416, 33676416, 1152, 2304, 0x6b508374 +0, 33702912, 33702912, 1152, 2304, 0xb6b4791f +0, 33729408, 33729408, 1152, 2304, 0xce6d7501 +0, 33755904, 33755904, 1152, 2304, 0x99ec8bac +0, 33782400, 33782400, 1152, 2304, 0x65d772b7 +0, 33808896, 33808896, 1152, 2304, 0xbc2762ff +0, 33835392, 33835392, 1152, 2304, 0xf8a48378 +0, 33861888, 33861888, 1152, 2304, 0x18057ad4 +0, 33888384, 33888384, 1152, 2304, 0x89af753f +0, 33914880, 33914880, 1152, 2304, 0x95a48fc5 +0, 33941376, 33941376, 1152, 2304, 0x8b7576af +0, 33967872, 33967872, 1152, 2304, 0xcdcb6e67 +0, 33994368, 33994368, 1152, 2304, 0xe02a7ff3 +0, 34020864, 34020864, 1152, 2304, 0x4f0a7d48 +0, 34047360, 34047360, 1152, 2304, 0x9bab8287 +0, 34073856, 34073856, 1152, 2304, 0xc1fa8063 +0, 34100352, 34100352, 1152, 2304, 0x410e7dd7 +0, 34126848, 34126848, 1152, 2304, 0xd4de777f +0, 34153344, 34153344, 1152, 2304, 0x403675ac +0, 34179840, 34179840, 1152, 2304, 0x4d7687c5 +0, 34206336, 34206336, 1152, 2304, 0x10c6650d +0, 34232832, 34232832, 1152, 2304, 0xd7e67b69 +0, 34259328, 34259328, 1152, 2304, 0x42b97fae +0, 34285824, 34285824, 1152, 2304, 0xa8b57a9f +0, 34312320, 34312320, 1152, 2304, 0xc24960a0 +0, 34338816, 34338816, 1152, 2304, 0x16198fec +0, 34365312, 34365312, 1152, 2304, 0x29297416 +0, 34391808, 34391808, 1152, 2304, 0x129b7d00 +0, 34418304, 34418304, 1152, 2304, 0xa9677141 +0, 34444800, 34444800, 1152, 2304, 0x86a779bf +0, 34471296, 34471296, 1152, 2304, 0xa3857dce +0, 34497792, 34497792, 1152, 2304, 0xee6d7c4d +0, 34524288, 34524288, 1152, 2304, 0x97127166 +0, 34550784, 34550784, 1152, 2304, 0x6e407c25 +0, 34577280, 34577280, 1152, 2304, 0x82a07c9a +0, 34603776, 34603776, 1152, 2304, 0xf62381ef +0, 34630272, 34630272, 1152, 2304, 0x2ab86ca8 +0, 34656768, 34656768, 1152, 2304, 0x97ca87ed +0, 34683264, 34683264, 1152, 2304, 0x6b4868f2 +0, 34709760, 34709760, 1152, 2304, 0xdb2a953c +0, 34736256, 34736256, 1152, 2304, 0x061e7770 +0, 34762752, 34762752, 1152, 2304, 0xae067224 +0, 34789248, 34789248, 1152, 2304, 0x88a282a3 +0, 34815744, 34815744, 1152, 2304, 0x4e14743e +0, 34842240, 34842240, 1152, 2304, 0x3dbd8b7b +0, 34868736, 34868736, 1152, 2304, 0xcae57312 +0, 34895232, 34895232, 1152, 2304, 0xf9038ca7 +0, 34921728, 34921728, 1152, 2304, 0x03ec6f07 +0, 34948224, 34948224, 1152, 2304, 0x8c297359 +0, 34974720, 34974720, 1152, 2304, 0x8af1804c +0, 35001216, 35001216, 1152, 2304, 0xf30087c8 +0, 35027712, 35027712, 1152, 2304, 0x21127cd1 +0, 35054208, 35054208, 1152, 2304, 0xc66772bd +0, 35080704, 35080704, 1152, 2304, 0x05e6630b +0, 35107200, 35107200, 1152, 2304, 0x020688d9 +0, 35133696, 35133696, 1152, 2304, 0xee3873cd +0, 35160192, 35160192, 1152, 2304, 0xf263782b +0, 35186688, 35186688, 1152, 2304, 0xf8877144 +0, 35213184, 35213184, 1152, 2304, 0xce1e6f33 +0, 35239680, 35239680, 1152, 2304, 0xf0457e4f +0, 35266176, 35266176, 1152, 2304, 0xde9387df +0, 35292672, 35292672, 1152, 2304, 0x5df86d1d +0, 35319168, 35319168, 1152, 2304, 0x949087ef +0, 35345664, 35345664, 1152, 2304, 0xdbd269c6 +0, 35372160, 35372160, 1152, 2304, 0xd530806e +0, 35398656, 35398656, 1152, 2304, 0x80027b1d +0, 35425152, 35425152, 1152, 2304, 0xccb47c48 +0, 35451648, 35451648, 1152, 2304, 0x4f2f8326 +0, 35478144, 35478144, 1152, 2304, 0xfe046f23 +0, 35504640, 35504640, 1152, 2304, 0x5939759b +0, 35531136, 35531136, 1152, 2304, 0x83147073 +0, 35557632, 35557632, 1152, 2304, 0xc9e77b95 +0, 35584128, 35584128, 1152, 2304, 0x702d8e51 +0, 35610624, 35610624, 1152, 2304, 0x5f5f8492 +0, 35637120, 35637120, 1152, 2304, 0x10116d0e +0, 35663616, 35663616, 1152, 2304, 0xb8587894 +0, 35690112, 35690112, 1152, 2304, 0x2b357892 +0, 35716608, 35716608, 1152, 2304, 0x160e6c20 +0, 35743104, 35743104, 1152, 2304, 0x0534874b +0, 35769600, 35769600, 1152, 2304, 0xde687064 +0, 35796096, 35796096, 1152, 2304, 0x91ef7fe4 +0, 35822592, 35822592, 1152, 2304, 0x077473ce +0, 35849088, 35849088, 1152, 2304, 0x1be77777 +0, 35875584, 35875584, 1152, 2304, 0xaada9096 +0, 35902080, 35902080, 1152, 2304, 0xeac96f7e +0, 35928576, 35928576, 1152, 2304, 0xe9ca6e72 +0, 35955072, 35955072, 1152, 2304, 0xd0868038 +0, 35981568, 35981568, 1152, 2304, 0x689176f1 +0, 36008064, 36008064, 1152, 2304, 0xdfdb7684 +0, 36034560, 36034560, 1152, 2304, 0x83c55d92 +0, 36061056, 36061056, 1152, 2304, 0x77587b70 +0, 36087552, 36087552, 1152, 2304, 0x60937941 +0, 36114048, 36114048, 1152, 2304, 0xb00267bd +0, 36140544, 36140544, 1152, 2304, 0xd0a166eb +0, 36167040, 36167040, 1152, 2304, 0x88718162 +0, 36193536, 36193536, 1152, 2304, 0xf9e084ff +0, 36220032, 36220032, 1152, 2304, 0x2ddc8c08 +0, 36246528, 36246528, 1152, 2304, 0x843a7178 +0, 36273024, 36273024, 1152, 2304, 0x1d9784b4 +0, 36299520, 36299520, 1152, 2304, 0x98aa7b1d +0, 36326016, 36326016, 1152, 2304, 0x583e846e +0, 36352512, 36352512, 1152, 2304, 0xa6d284ec +0, 36379008, 36379008, 1152, 2304, 0xa0147cbf +0, 36405504, 36405504, 1152, 2304, 0xb3bf7b4b +0, 36432000, 36432000, 1152, 2304, 0x7f8b78dd +0, 36458496, 36458496, 1152, 2304, 0xd3fb761f +0, 36484992, 36484992, 1152, 2304, 0x78147c2f +0, 36511488, 36511488, 1152, 2304, 0x5e747b26 +0, 36537984, 36537984, 1152, 2304, 0x0d8e7d96 +0, 36564480, 36564480, 1152, 2304, 0x73728362 +0, 36590976, 36590976, 1152, 2304, 0x7c54707b +0, 36617472, 36617472, 1152, 2304, 0xb89c7806 +0, 36643968, 36643968, 1152, 2304, 0x5f0f7a91 +0, 36670464, 36670464, 1152, 2304, 0x35217e84 +0, 36696960, 36696960, 1152, 2304, 0xb3798553 +0, 36723456, 36723456, 1152, 2304, 0xd8377e8a +0, 36749952, 36749952, 1152, 2304, 0x339181ba +0, 36776448, 36776448, 1152, 2304, 0xbe196b2c +0, 36802944, 36802944, 1152, 2304, 0xdc708cc4 +0, 36829440, 36829440, 1152, 2304, 0x649c74c1 +0, 36855936, 36855936, 1152, 2304, 0xac128649 +0, 36882432, 36882432, 1152, 2304, 0xcd266a22 +0, 36908928, 36908928, 1152, 2304, 0xdfde7023 +0, 36935424, 36935424, 1152, 2304, 0xf92d7450 +0, 36961920, 36961920, 1152, 2304, 0x9ce379ac +0, 36988416, 36988416, 1152, 2304, 0xee5e712e +0, 37014912, 37014912, 1152, 2304, 0xa12676c0 +0, 37041408, 37041408, 1152, 2304, 0x4cee7be1 +0, 37067904, 37067904, 1152, 2304, 0x90c881e5 +0, 37094400, 37094400, 1152, 2304, 0xa6a78158 +0, 37120896, 37120896, 1152, 2304, 0xd248864a +0, 37147392, 37147392, 1152, 2304, 0x7a8972b4 +0, 37173888, 37173888, 1152, 2304, 0x5c8a75cb +0, 37200384, 37200384, 1152, 2304, 0x07606722 +0, 37226880, 37226880, 1152, 2304, 0xbf497aae +0, 37253376, 37253376, 1152, 2304, 0xffab7d66 +0, 37279872, 37279872, 1152, 2304, 0xefdc7d05 +0, 37306368, 37306368, 1152, 2304, 0x02d686dd +0, 37332864, 37332864, 1152, 2304, 0x852e6eb6 +0, 37359360, 37359360, 1152, 2304, 0x3445706b +0, 37385856, 37385856, 1152, 2304, 0x04677828 +0, 37412352, 37412352, 1152, 2304, 0x5d5c833c +0, 37438848, 37438848, 1152, 2304, 0xf4277e06 +0, 37465344, 37465344, 1152, 2304, 0xcece72ab +0, 37491840, 37491840, 1152, 2304, 0x10837aff +0, 37518336, 37518336, 1152, 2304, 0x0265762b +0, 37544832, 37544832, 1152, 2304, 0x0fc979de +0, 37571328, 37571328, 1152, 2304, 0xeecf7010 +0, 37597824, 37597824, 1152, 2304, 0x313975cd +0, 37624320, 37624320, 1152, 2304, 0xccce84a7 +0, 37650816, 37650816, 1152, 2304, 0x823e6935 +0, 37677312, 37677312, 1152, 2304, 0xa0606ade +0, 37703808, 37703808, 1152, 2304, 0x2c2d7866 +0, 37730304, 37730304, 1152, 2304, 0x3a5a781e +0, 37756800, 37756800, 1152, 2304, 0xdaf677fd +0, 37783296, 37783296, 1152, 2304, 0x79d88aca +0, 37809792, 37809792, 1152, 2304, 0x3db27308 +0, 37836288, 37836288, 1152, 2304, 0x627175ff +0, 37862784, 37862784, 1152, 2304, 0x40697b16 +0, 37889280, 37889280, 1152, 2304, 0x40e47ee7 +0, 37915776, 37915776, 1152, 2304, 0x6a6a7d91 +0, 37942272, 37942272, 1152, 2304, 0x8d3e8a32 +0, 37968768, 37968768, 1152, 2304, 0x576a817e +0, 37995264, 37995264, 1152, 2304, 0x86287f9b +0, 38021760, 38021760, 1152, 2304, 0x43e081ce +0, 38048256, 38048256, 1152, 2304, 0xe44b8003 +0, 38074752, 38074752, 1152, 2304, 0xfb237f5b +0, 38101248, 38101248, 1152, 2304, 0x28967c8a +0, 38127744, 38127744, 1152, 2304, 0x97478829 +0, 38154240, 38154240, 1152, 2304, 0x615570e8 +0, 38180736, 38180736, 1152, 2304, 0xa52c7d34 +0, 38207232, 38207232, 1152, 2304, 0xb55473e8 +0, 38233728, 38233728, 1152, 2304, 0x08a07d6c +0, 38260224, 38260224, 1152, 2304, 0x2eed916a +0, 38286720, 38286720, 1152, 2304, 0x8ce36cec +0, 38313216, 38313216, 1152, 2304, 0x775e8992 +0, 38339712, 38339712, 1152, 2304, 0x99ad816b +0, 38366208, 38366208, 1152, 2304, 0x697a70be +0, 38392704, 38392704, 1152, 2304, 0x38c46cf2 +0, 38419200, 38419200, 1152, 2304, 0xf9d681f4 +0, 38445696, 38445696, 1152, 2304, 0xa7336fea +0, 38472192, 38472192, 1152, 2304, 0xd2a97e59 +0, 38498688, 38498688, 1152, 2304, 0x02b880e9 +0, 38525184, 38525184, 1152, 2304, 0x2a486e9e +0, 38551680, 38551680, 1152, 2304, 0x5f197c43 +0, 38578176, 38578176, 1152, 2304, 0x266679ad +0, 38604672, 38604672, 1152, 2304, 0x7cfd7c8a +0, 38631168, 38631168, 1152, 2304, 0x43b681bb +0, 38657664, 38657664, 1152, 2304, 0x63309cff +0, 38684160, 38684160, 1152, 2304, 0x80f36f7d +0, 38710656, 38710656, 1152, 2304, 0xcead7b98 +0, 38737152, 38737152, 1152, 2304, 0x8475992f +0, 38763648, 38763648, 1152, 2304, 0x746782d2 +0, 38790144, 38790144, 1152, 2304, 0x2b486982 +0, 38816640, 38816640, 1152, 2304, 0xc80c7fc2 +0, 38843136, 38843136, 1152, 2304, 0x148c7c3b +0, 38869632, 38869632, 1152, 2304, 0x49c477df +0, 38896128, 38896128, 1152, 2304, 0x1bf97c56 +0, 38922624, 38922624, 1152, 2304, 0x89a38221 +0, 38949120, 38949120, 1152, 2304, 0xcb757a31 +0, 38975616, 38975616, 1152, 2304, 0xd3bb72fa +0, 39002112, 39002112, 1152, 2304, 0xe5727650 +0, 39028608, 39028608, 1152, 2304, 0x5d4e9242 +0, 39055104, 39055104, 1152, 2304, 0x29207f75 +0, 39081600, 39081600, 1152, 2304, 0x5b1d954a +0, 39108096, 39108096, 1152, 2304, 0xa2888223 +0, 39134592, 39134592, 1152, 2304, 0xe31d8af7 +0, 39161088, 39161088, 1152, 2304, 0x29ee82dd +0, 39187584, 39187584, 1152, 2304, 0x4b1d7887 +0, 39214080, 39214080, 1152, 2304, 0xc0308236 +0, 39240576, 39240576, 1152, 2304, 0xaed68e92 +0, 39267072, 39267072, 1152, 2304, 0xbc1171e9 +0, 39293568, 39293568, 1152, 2304, 0x379f828b +0, 39320064, 39320064, 1152, 2304, 0x83de72c8 +0, 39346560, 39346560, 1152, 2304, 0xb11a806a +0, 39373056, 39373056, 1152, 2304, 0x7ac17e7a +0, 39399552, 39399552, 1152, 2304, 0x031b7d9a +0, 39426048, 39426048, 1152, 2304, 0xebc97c43 +0, 39452544, 39452544, 1152, 2304, 0x914e86a7 +0, 39479040, 39479040, 1152, 2304, 0x88e2747e +0, 39505536, 39505536, 1152, 2304, 0x153076bc +0, 39532032, 39532032, 1152, 2304, 0xdacc7ebb +0, 39558528, 39558528, 1152, 2304, 0x0905709a +0, 39585024, 39585024, 1152, 2304, 0x13358109 +0, 39611520, 39611520, 1152, 2304, 0x18227228 +0, 39638016, 39638016, 1152, 2304, 0x318082d7 +0, 39664512, 39664512, 1152, 2304, 0x8aec7a8e +0, 39691008, 39691008, 1152, 2304, 0x8c9c7755 +0, 39717504, 39717504, 1152, 2304, 0xdba46e2f +0, 39744000, 39744000, 1152, 2304, 0xd47d7f5a +0, 39770496, 39770496, 1152, 2304, 0xeb1370ec +0, 39796992, 39796992, 1152, 2304, 0xf6d68e74 +0, 39823488, 39823488, 1152, 2304, 0x3d5a7c66 +0, 39849984, 39849984, 1152, 2304, 0x264b6d68 +0, 39876480, 39876480, 1152, 2304, 0x7cde8b9f +0, 39902976, 39902976, 1152, 2304, 0xba467347 +0, 39929472, 39929472, 1152, 2304, 0x921987f7 +0, 39955968, 39955968, 1152, 2304, 0x9c6c7fce +0, 39982464, 39982464, 1152, 2304, 0x02cb828f +0, 40008960, 40008960, 1152, 2304, 0x3b427077 +0, 40035456, 40035456, 1152, 2304, 0x6f9c7523 +0, 40061952, 40061952, 1152, 2304, 0xef688204 +0, 40088448, 40088448, 1152, 2304, 0x263782dc +0, 40114944, 40114944, 1152, 2304, 0xb6ca7e46 +0, 40141440, 40141440, 1152, 2304, 0xb0929636 +0, 40167936, 40167936, 1152, 2304, 0x60a97b7a +0, 40194432, 40194432, 1152, 2304, 0xcf037690 +0, 40220928, 40220928, 1152, 2304, 0xc9046a25 +0, 40247424, 40247424, 1152, 2304, 0xbf247f3c +0, 40273920, 40273920, 1152, 2304, 0x71e77d34 +0, 40300416, 40300416, 1152, 2304, 0x96ce7a01 +0, 40326912, 40326912, 1152, 2304, 0xf9b07a27 +0, 40353408, 40353408, 1152, 2304, 0x984b830b +0, 40379904, 40379904, 1152, 2304, 0xff11822b +0, 40406400, 40406400, 1152, 2304, 0xb0a18578 +0, 40432896, 40432896, 1152, 2304, 0xa9d98ef8 +0, 40459392, 40459392, 1152, 2304, 0x4f9076e1 +0, 40485888, 40485888, 1152, 2304, 0xb63c7742 +0, 40512384, 40512384, 1152, 2304, 0xb4c06ae2 +0, 40538880, 40538880, 1152, 2304, 0x41738531 +0, 40565376, 40565376, 1152, 2304, 0x55125e7b diff --git a/tests/ref/fate/filter-hue1 b/tests/ref/fate/filter-hue1 new file mode 100644 index 000000000..7059ba766 --- /dev/null +++ b/tests/ref/fate/filter-hue1 @@ -0,0 +1 @@ +hue1 57463dd9bc17156a51b704dd7271c863 diff --git a/tests/ref/fate/filter-hue2 b/tests/ref/fate/filter-hue2 new file mode 100644 index 000000000..2e060e1ab --- /dev/null +++ b/tests/ref/fate/filter-hue2 @@ -0,0 +1 @@ +hue2 e951ae8ffb279552abc4354c4de7cb5b diff --git a/tests/ref/fate/filter-hue3 b/tests/ref/fate/filter-hue3 new file mode 100644 index 000000000..14a837933 --- /dev/null +++ b/tests/ref/fate/filter-hue3 @@ -0,0 +1 @@ +hue3 149dc22f5dc9f578f7d281dc3120c09b diff --git a/tests/ref/fate/filter-hue4 b/tests/ref/fate/filter-hue4 new file mode 100644 index 000000000..2a08c3331 --- /dev/null +++ b/tests/ref/fate/filter-hue4 @@ -0,0 +1 @@ +hue4 6279ed43527e7b5be645819e08880107 diff --git a/tests/ref/fate/filter-pal100bars b/tests/ref/fate/filter-pal100bars new file mode 100644 index 000000000..0ee8d22d3 --- /dev/null +++ b/tests/ref/fate/filter-pal100bars @@ -0,0 +1,10 @@ +#tb 0: 1/5 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 320x240 +#sar 0: 1/1 +0, 0, 0, 1, 115200, 0x97a31f02 +0, 1, 1, 1, 115200, 0x97a31f02 +0, 2, 2, 1, 115200, 0x97a31f02 +0, 3, 3, 1, 115200, 0x97a31f02 +0, 4, 4, 1, 115200, 0x97a31f02 diff --git a/tests/ref/fate/filter-pal75bars b/tests/ref/fate/filter-pal75bars new file mode 100644 index 000000000..a2d2e1710 --- /dev/null +++ b/tests/ref/fate/filter-pal75bars @@ -0,0 +1,10 @@ +#tb 0: 1/5 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 320x240 +#sar 0: 1/1 +0, 0, 0, 1, 115200, 0xa131179a +0, 1, 1, 1, 115200, 0xa131179a +0, 2, 2, 1, 115200, 0xa131179a +0, 3, 3, 1, 115200, 0xa131179a +0, 4, 4, 1, 115200, 0xa131179a diff --git a/tests/ref/fate/filter-palettegen-2 b/tests/ref/fate/filter-palettegen-2 index aa07b6cb9..9abec0fe8 100644 --- a/tests/ref/fate/filter-palettegen-2 +++ b/tests/ref/fate/filter-palettegen-2 @@ -3,4 +3,4 @@ #codec_id 0: rawvideo #dimensions 0: 16x16 #sar 0: 1/1 -0, 0, 0, 1, 1024, 0x906ff5aa +0, 0, 0, 1, 1024, 0x23e072c8 diff --git a/tests/ref/fate/filter-pan-downmix1 b/tests/ref/fate/filter-pan-downmix1 new file mode 100644 index 000000000..47d5044da --- /dev/null +++ b/tests/ref/fate/filter-pan-downmix1 @@ -0,0 +1,26 @@ +#tb 0: 1/44100 +#media_type 0: audio +#codec_id 0: pcm_s16le +#sample_rate 0: 44100 +#channel_layout 0: 3 +#channel_layout_name 0: stereo +0, 0, 0, 512, 2048, 0xccb10170 +0, 512, 512, 512, 2048, 0xc51cf8e7 +0, 1024, 1024, 512, 2048, 0x959eef2d +0, 1536, 1536, 512, 2048, 0x559f0751 +0, 2048, 2048, 512, 2048, 0x4c4c08e1 +0, 2560, 2560, 512, 2048, 0x41c3fd6f +0, 3072, 3072, 512, 2048, 0x4c92f8d2 +0, 3584, 3584, 512, 2048, 0x9defee05 +0, 4096, 4096, 512, 2048, 0x2d33f4dc +0, 4608, 4608, 512, 2048, 0xd854eeca +0, 5120, 5120, 512, 2048, 0xdb55eaf7 +0, 5632, 5632, 512, 2048, 0x2bac060d +0, 6144, 6144, 512, 2048, 0x91beec0f +0, 6656, 6656, 512, 2048, 0x3262f0da +0, 7168, 7168, 512, 2048, 0xf00708a6 +0, 7680, 7680, 512, 2048, 0xc90cfa02 +0, 8192, 8192, 512, 2048, 0x09e9f413 +0, 8704, 8704, 512, 2048, 0xcd0d0c36 +0, 9216, 9216, 512, 2048, 0x6f6bff82 +0, 9728, 9728, 512, 2048, 0x18a40912 diff --git a/tests/ref/fate/filter-pan-downmix2 b/tests/ref/fate/filter-pan-downmix2 new file mode 100644 index 000000000..8d3ee1081 --- /dev/null +++ b/tests/ref/fate/filter-pan-downmix2 @@ -0,0 +1,26 @@ +#tb 0: 1/44100 +#media_type 0: audio +#codec_id 0: pcm_s16le +#sample_rate 0: 44100 +#channel_layout 0: 0 +#channel_layout_name 0: 5 channels +0, 0, 0, 186, 1860, 0x2480a20e +0, 186, 186, 186, 1860, 0xde9e9c40 +0, 372, 372, 186, 1860, 0xc497b2a0 +0, 558, 558, 186, 1860, 0xe5a8a2d7 +0, 744, 744, 186, 1860, 0x01c09b6a +0, 930, 930, 186, 1860, 0xb26fae2f +0, 1116, 1116, 186, 1860, 0x1292a9ab +0, 1302, 1302, 186, 1860, 0xe7a79136 +0, 1488, 1488, 186, 1860, 0x57dc81a3 +0, 1674, 1674, 186, 1860, 0xc13b9a1b +0, 1860, 1860, 186, 1860, 0xdf7c9fd6 +0, 2046, 2046, 186, 1860, 0x4d769cff +0, 2232, 2232, 186, 1860, 0xb8b79977 +0, 2418, 2418, 186, 1860, 0xd287989f +0, 2604, 2604, 186, 1860, 0xc2a38f03 +0, 2790, 2790, 186, 1860, 0xd7149438 +0, 2976, 2976, 186, 1860, 0xc3719081 +0, 3162, 3162, 186, 1860, 0xb9fba1a3 +0, 3348, 3348, 186, 1860, 0xe92cb2de +0, 3534, 3534, 186, 1860, 0x9dd9b272 diff --git a/tests/ref/fate/filter-pan-stereo4 b/tests/ref/fate/filter-pan-stereo4 index 87c70a7f1..6d10ed62a 100644 --- a/tests/ref/fate/filter-pan-stereo4 +++ b/tests/ref/fate/filter-pan-stereo4 @@ -3,24 +3,24 @@ #codec_id 0: pcm_s16le #sample_rate 0: 44100 #channel_layout 0: 0 -#channel_layout_name 0: 4 channels -0, 0, 0, 1024, 8192, 0xdaadfc44 -0, 1024, 1024, 1024, 8192, 0xe6d9ec37 -0, 2048, 2048, 1024, 8192, 0x5edfea64 -0, 3072, 3072, 1024, 8192, 0x7f7be38c -0, 4096, 4096, 1024, 8192, 0x3f60f5c9 -0, 5120, 5120, 1024, 8192, 0xcee4fe06 -0, 6144, 6144, 1024, 8192, 0xdb98fa3e -0, 7168, 7168, 1024, 8192, 0x4cb30687 -0, 8192, 8192, 1024, 8192, 0x00f6ecab -0, 9216, 9216, 1024, 8192, 0xa7b0e0db -0, 10240, 10240, 1024, 8192, 0xc2dcf89c -0, 11264, 11264, 1024, 8192, 0x30d6f2fe -0, 12288, 12288, 1024, 8192, 0xf83ae182 -0, 13312, 13312, 1024, 8192, 0xeecd05d1 -0, 14336, 14336, 1024, 8192, 0xfd3b0559 -0, 15360, 15360, 1024, 8192, 0xcd69e3e6 -0, 16384, 16384, 1024, 8192, 0xdf80fc29 -0, 17408, 17408, 1024, 8192, 0x7e8bf52b -0, 18432, 18432, 1024, 8192, 0xee07e5f7 -0, 19456, 19456, 1024, 8192, 0xc874f294 +#channel_layout_name 0: 2 channels +0, 0, 0, 1024, 4096, 0x7bd6fc44 +0, 1024, 1024, 1024, 4096, 0xed38ec37 +0, 2048, 2048, 1024, 4096, 0x4696ea64 +0, 3072, 3072, 1024, 4096, 0xf2c8e38c +0, 4096, 4096, 1024, 4096, 0x9aa8f5c9 +0, 5120, 5120, 1024, 4096, 0xfb46fe06 +0, 6144, 6144, 1024, 4096, 0x6700fa3e +0, 7168, 7168, 1024, 4096, 0x235e0687 +0, 8192, 8192, 1024, 4096, 0x8b9aecab +0, 9216, 9216, 1024, 4096, 0x62f3e0db +0, 10240, 10240, 1024, 4096, 0xe59ef89c +0, 11264, 11264, 1024, 4096, 0x1a48f2fe +0, 12288, 12288, 1024, 4096, 0x9026e182 +0, 13312, 13312, 1024, 4096, 0xec4d05d1 +0, 14336, 14336, 1024, 4096, 0x7ee70559 +0, 15360, 15360, 1024, 4096, 0x807ae3e6 +0, 16384, 16384, 1024, 4096, 0xf0d2fc29 +0, 17408, 17408, 1024, 4096, 0xd9e7f52b +0, 18432, 18432, 1024, 4096, 0x0f1ce5f7 +0, 19456, 19456, 1024, 4096, 0x6b3cf294 diff --git a/tests/ref/fate/filter-pan-upmix1 b/tests/ref/fate/filter-pan-upmix1 new file mode 100644 index 000000000..87c70a7f1 --- /dev/null +++ b/tests/ref/fate/filter-pan-upmix1 @@ -0,0 +1,26 @@ +#tb 0: 1/44100 +#media_type 0: audio +#codec_id 0: pcm_s16le +#sample_rate 0: 44100 +#channel_layout 0: 0 +#channel_layout_name 0: 4 channels +0, 0, 0, 1024, 8192, 0xdaadfc44 +0, 1024, 1024, 1024, 8192, 0xe6d9ec37 +0, 2048, 2048, 1024, 8192, 0x5edfea64 +0, 3072, 3072, 1024, 8192, 0x7f7be38c +0, 4096, 4096, 1024, 8192, 0x3f60f5c9 +0, 5120, 5120, 1024, 8192, 0xcee4fe06 +0, 6144, 6144, 1024, 8192, 0xdb98fa3e +0, 7168, 7168, 1024, 8192, 0x4cb30687 +0, 8192, 8192, 1024, 8192, 0x00f6ecab +0, 9216, 9216, 1024, 8192, 0xa7b0e0db +0, 10240, 10240, 1024, 8192, 0xc2dcf89c +0, 11264, 11264, 1024, 8192, 0x30d6f2fe +0, 12288, 12288, 1024, 8192, 0xf83ae182 +0, 13312, 13312, 1024, 8192, 0xeecd05d1 +0, 14336, 14336, 1024, 8192, 0xfd3b0559 +0, 15360, 15360, 1024, 8192, 0xcd69e3e6 +0, 16384, 16384, 1024, 8192, 0xdf80fc29 +0, 17408, 17408, 1024, 8192, 0x7e8bf52b +0, 18432, 18432, 1024, 8192, 0xee07e5f7 +0, 19456, 19456, 1024, 8192, 0xc874f294 diff --git a/tests/ref/fate/filter-pan-upmix2 b/tests/ref/fate/filter-pan-upmix2 new file mode 100644 index 000000000..56db1c17e --- /dev/null +++ b/tests/ref/fate/filter-pan-upmix2 @@ -0,0 +1,26 @@ +#tb 0: 1/44100 +#media_type 0: audio +#codec_id 0: pcm_s16le +#sample_rate 0: 44100 +#channel_layout 0: 0 +#channel_layout_name 0: 9 channels +0, 0, 0, 512, 9216, 0xd561bb2b +0, 512, 512, 512, 9216, 0x591805f9 +0, 1024, 1024, 512, 9216, 0xd46fecd6 +0, 1536, 1536, 512, 9216, 0x1e1f176b +0, 2048, 2048, 512, 9216, 0xe383f1a6 +0, 2560, 2560, 512, 9216, 0xc628c661 +0, 3072, 3072, 512, 9216, 0x1ad09914 +0, 3584, 3584, 512, 9216, 0x798533cc +0, 4096, 4096, 512, 9216, 0x4913d581 +0, 4608, 4608, 512, 9216, 0x59f506b3 +0, 5120, 5120, 512, 9216, 0x8885fa28 +0, 5632, 5632, 512, 9216, 0x769ffa95 +0, 6144, 6144, 512, 9216, 0xc636cc46 +0, 6656, 6656, 512, 9216, 0x4740f34b +0, 7168, 7168, 512, 9216, 0x00d2de28 +0, 7680, 7680, 512, 9216, 0x704a07fc +0, 8192, 8192, 512, 9216, 0x54a4f682 +0, 8704, 8704, 512, 9216, 0xd6dac181 +0, 9216, 9216, 512, 9216, 0xfcd6fe28 +0, 9728, 9728, 512, 9216, 0x5c41cbdc diff --git a/tests/ref/fate/filter-pixdesc-gray14be b/tests/ref/fate/filter-pixdesc-gray14be new file mode 100644 index 000000000..dc7836a10 --- /dev/null +++ b/tests/ref/fate/filter-pixdesc-gray14be @@ -0,0 +1 @@ +pixdesc-gray14be 6c9faae02a63f17d78ae6bff2866c0c1 diff --git a/tests/ref/fate/filter-pixdesc-gray14le b/tests/ref/fate/filter-pixdesc-gray14le new file mode 100644 index 000000000..9057875bd --- /dev/null +++ b/tests/ref/fate/filter-pixdesc-gray14le @@ -0,0 +1 @@ +pixdesc-gray14le 713c6b98b8f22a0716bf3541fb311936 diff --git a/tests/ref/fate/filter-pixdesc-grayf32be b/tests/ref/fate/filter-pixdesc-grayf32be new file mode 100644 index 000000000..171475483 --- /dev/null +++ b/tests/ref/fate/filter-pixdesc-grayf32be @@ -0,0 +1 @@ +pixdesc-grayf32be 9b23c74e8e8ffae5d7c7e82bbf5929da diff --git a/tests/ref/fate/filter-pixdesc-grayf32le b/tests/ref/fate/filter-pixdesc-grayf32le new file mode 100644 index 000000000..d598d123b --- /dev/null +++ b/tests/ref/fate/filter-pixdesc-grayf32le @@ -0,0 +1 @@ +pixdesc-grayf32le 291f074a24c44799a1f437d1c55556f1 diff --git a/tests/ref/fate/filter-pixdesc-nv24 b/tests/ref/fate/filter-pixdesc-nv24 new file mode 100644 index 000000000..ce0733199 --- /dev/null +++ b/tests/ref/fate/filter-pixdesc-nv24 @@ -0,0 +1 @@ +pixdesc-nv24 7437f36b6ee58050564b20a1f839ff07 diff --git a/tests/ref/fate/filter-pixdesc-nv42 b/tests/ref/fate/filter-pixdesc-nv42 new file mode 100644 index 000000000..88ef431a1 --- /dev/null +++ b/tests/ref/fate/filter-pixdesc-nv42 @@ -0,0 +1 @@ +pixdesc-nv42 110bad2f58424ab800ad832f6966cafe diff --git a/tests/ref/fate/filter-pixdesc-ya16be b/tests/ref/fate/filter-pixdesc-ya16be new file mode 100644 index 000000000..3fadfa355 --- /dev/null +++ b/tests/ref/fate/filter-pixdesc-ya16be @@ -0,0 +1 @@ +pixdesc-ya16be c5bf539478020302a30f36c5059b7695 diff --git a/tests/ref/fate/filter-pixdesc-ya16le b/tests/ref/fate/filter-pixdesc-ya16le new file mode 100644 index 000000000..ae5764c1f --- /dev/null +++ b/tests/ref/fate/filter-pixdesc-ya16le @@ -0,0 +1 @@ +pixdesc-ya16le d238b5905b3ab79f7f00d5ea03ee4b87 diff --git a/tests/ref/fate/filter-pixdesc-yuva422p12be b/tests/ref/fate/filter-pixdesc-yuva422p12be new file mode 100644 index 000000000..16df4e45c --- /dev/null +++ b/tests/ref/fate/filter-pixdesc-yuva422p12be @@ -0,0 +1 @@ +pixdesc-yuva422p12be0420bebaa8a56fea28a06fd565f8e6b3 diff --git a/tests/ref/fate/filter-pixdesc-yuva422p12le b/tests/ref/fate/filter-pixdesc-yuva422p12le new file mode 100644 index 000000000..b7452ccf7 --- /dev/null +++ b/tests/ref/fate/filter-pixdesc-yuva422p12le @@ -0,0 +1 @@ +pixdesc-yuva422p12le5dff3afb6301abbc0e2a85761b8c5c64 diff --git a/tests/ref/fate/filter-pixdesc-yuva444p12be b/tests/ref/fate/filter-pixdesc-yuva444p12be new file mode 100644 index 000000000..cfe454f49 --- /dev/null +++ b/tests/ref/fate/filter-pixdesc-yuva444p12be @@ -0,0 +1 @@ +pixdesc-yuva444p12be952d5e6b4a3494c5228527237fdfc413 diff --git a/tests/ref/fate/filter-pixdesc-yuva444p12le b/tests/ref/fate/filter-pixdesc-yuva444p12le new file mode 100644 index 000000000..95aa2a984 --- /dev/null +++ b/tests/ref/fate/filter-pixdesc-yuva444p12le @@ -0,0 +1 @@ +pixdesc-yuva444p12le235218d42dbbe40fbc044755825c6a95 diff --git a/tests/ref/fate/filter-pixfmts-copy b/tests/ref/fate/filter-pixfmts-copy index c45ce937b..4675b6e83 100644 --- a/tests/ref/fate/filter-pixfmts-copy +++ b/tests/ref/fate/filter-pixfmts-copy @@ -41,14 +41,20 @@ gray10be d486558ecd2e27afc17930be861f0e4c gray10le 917d687103b2adcca7132bfc070ca54a gray12be 9685614450f1282be433d2b07234ca1f gray12le 2700bd7fb3fea56e54eb03e31d6d4e57 +gray14be 19ed2bf25878980d6f81f6ae699024ec +gray14le 4b148b26b30040c05dc248a8852f31ac gray16be 08d997a3faa25a3db9d6be272d282eef gray16le df65eb804360795e3e38a2701fa9641a gray9be 6382a14594a8b68f0ec7de25531f9334 gray9le 4eb1dda58706436e3b69aef29b0089db +grayf32be f3bf178835f8146aa09d1da94bba4d8a +grayf32le fb6ea85bfbc8cd21c51fc0e110197294 monob 8b04f859fee6a0be856be184acd7a0b5 monow 54d16d2c01abfd72ecdb5e51e283937c nv12 8e24feb2c544dc26a20047a71e4c27aa nv21 335d85c9af6110f26ae9e187a82ed2cf +nv24 f30fc8d0ac40af69e119ea919a314572 +nv42 29a212f70f8780fe0eb99abcae81894d p010be 7f9842d6015026136bad60d03c035cc3 p010le c453421b9f726bdaf2bacf59a492c43b p016be 7f9842d6015026136bad60d03c035cc3 @@ -72,6 +78,8 @@ rgba64le b91e1d77f799eb92241a2d2d28437b15 uyvy422 3bcf3c80047592f2211fae3260b1b65d xyz12be a1ef56bf746d71f59669c28e48fc8450 xyz12le 831ff03c1ba4ef19374686f16a064d8c +ya16be 2f2c27f1854ac00c73d13861dcab2705 +ya16le 2c1fbd127c9f0435adc0e9b2ea3f486b ya8 dbb99fbcdc204aaa1a7397ff561f1a67 yuv410p 5d4d992a7728431aa4e0700f87fb7fd8 yuv411p 7e1300e89f5bc07939e2c4a6acbdf267 @@ -123,6 +131,8 @@ yuva420p9le 0e9c9803aaaddc9f38e419de587793c2 yuva422p 8f6bb778647e5dee62f544d646321171 yuva422p10be 2f7204c93a1e5bfb04538852f99e4074 yuva422p10le c8082548aca999edde77ef2749b1ff4c +yuva422p12be 19f8205cca3d19bfd4ad9cd2bfb07a0e +yuva422p12le 38e6c7d87332852d660df5594529fa6e yuva422p16be 427ad55f7464121bb3ce164641772bc6 yuva422p16le af6f8df651275de58129e010bb45ffcd yuva422p9be 47579cc2cea861ca1461589b80c4720f @@ -130,6 +140,8 @@ yuva422p9le aaeab2bfe80a29390e8666103ed8bb40 yuva444p 459fad5abfd16db9bb6a52761dc74cc1 yuva444p10be fa16bae4fc25429deb944ffa9f5b28a0 yuva444p10le 92f820d3481b7ebcb48b98a73e7b4c90 +yuva444p12be d8193387128a1b1efc51f36a12c85385 +yuva444p12le 9c17bf72b083f93040d1e19516b54de7 yuva444p16be c80c1899789a6411d0025730efc8f01c yuva444p16le 2ed56ea50fafda4d226c9b133755dad8 yuva444p9be 4903fde22b15d28da90761ac1cfcb1c5 diff --git a/tests/ref/fate/filter-pixfmts-crop b/tests/ref/fate/filter-pixfmts-crop index c5bb8a413..4b9f67cf6 100644 --- a/tests/ref/fate/filter-pixfmts-crop +++ b/tests/ref/fate/filter-pixfmts-crop @@ -41,12 +41,18 @@ gray10be 18ed76cab145ab9058cc353fcec6d3c4 gray10le fd83f7489880160783ddb125615b4638 gray12be 472700c26cc49b8d5f74af141f6a0d38 gray12le 4f6537fe1f32b3963350f8c435009433 +gray14be 302b5b534f64ee15fffe2d3818e8c29c +gray14le 9c205ae791cbb9e479beb0ece236c05f gray16be 38f599da990224de86e3dc7a543121a9 gray16le 9ff7c866bd98def4e6c91542c1c45f80 gray9be 8ffcb18d699480f55414bfc21ab33321 gray9le 4d1932d4968a248584f5e39c25f1dd43 +grayf32be cf40ec06a8abe54852b7f85a00549eec +grayf32le b672526c9da9c8959ab881f242f6890a nv12 92cda427f794374731ec0321ee00caac nv21 1bcfc197f4fb95de85ba58182d8d2f69 +nv24 514c8f12082f0737e558778cbe7de258 +nv42 ece9baae1c5de579dac2c66a89e08ef3 p010be 8b2de2eb6b099bbf355bfc55a0694ddc p010le 373b50c766dfd0a8e79c9a73246d803a p016be 8b2de2eb6b099bbf355bfc55a0694ddc @@ -69,6 +75,8 @@ rgba64be 89910046972ab3c68e2a348302cc8ca9 rgba64le fea8ebfc869b52adf353778f29eac7a7 xyz12be cb4571f9aaa7b59f999ef327276104b7 xyz12le cd6aae8d26b18bdb4b9d068586276d91 +ya16be 029a3b7c523de988e3161484d41ea15c +ya16le 32929a08d11982aec66ea1e665cfba3a ya8 51a8dd297e35d40b06d3ebe8f4717895 yuv410p 3bb6c7b64f2c46bc5e8b77198ce4ea58 yuv411p 693e4afe96998e6dd91734037d75d887 @@ -120,6 +128,8 @@ yuva420p9le abff60ecbe6e867949399710953bd1fc yuva422p ad564e513a8c08ff0ec99324e204dfbd yuva422p10be 61c806e5e02ea4c90ad3156c90957a18 yuva422p10le 41507ce136674ad458e562d44c67ddca +yuva422p12be e686b37d6738aae3c1d25bd36f3e518c +yuva422p12le 95bb91f2922bdd2eb9aa6fabe86d4994 yuva422p16be 3437cce47184e4b9a7a681831816e1ea yuva422p16le 0d534fcd61fc54fa9d4bbae5bde537ec yuva422p9be 588f72cd85285ed71a519525a947dedc @@ -127,6 +137,8 @@ yuva422p9le d5a5d50f414caa1563700207931f0e0a yuva444p 64bd3debe7c2b8cca91bc1d6e2a8d80e yuva444p10be 1291045203be7d60b9015fa7e34b5716 yuva444p10le 75865370fb0c018fb8663958bafcdc51 +yuva444p12be ff58aed06f42e1258ae04509bccaad0a +yuva444p12le 00ab9d34f0fd4ba23b48e8ae4bf93c17 yuva444p16be f817caf234aaf5848b2bc9679582ed56 yuva444p16le b32ad623fc423f897ff31c4073ea2a6f yuva444p9be 48498d994c3c9070f31773e39da306dd diff --git a/tests/ref/fate/filter-pixfmts-field b/tests/ref/fate/filter-pixfmts-field index df43ce693..059347e3e 100644 --- a/tests/ref/fate/filter-pixfmts-field +++ b/tests/ref/fate/filter-pixfmts-field @@ -41,14 +41,20 @@ gray10be 437713f3d081238cddb738e106e5a27d gray10le c749b80049b152f4ba3e66a72c0c5acc gray12be d34c50810b37e6f97dffdf6a8ab958de gray12le cf71b8fee47ce7821f3ae9f9b62ae39a +gray14be 2644f330259d70793d789b8dc3c01226 +gray14le 7776a471945d303088012cbc2ff2a2d0 gray16be e1700e056de9917744a7ff4ab2ca63fd gray16le 338de7ac5f7d36d5ad5ac2c8d5bbea68 gray9be 25e50940fa300a8f09edfb6eba4fd250 gray9le 1146cfc1b92bfd07ed238e65ffcd134f +grayf32be 72fbfa47b2863658a8a80d588f23b3e7 +grayf32le 6b856bdbf2a2bfcd2bc7d50f109daaf0 monob 2129cc72a484d7e10a44de9117aa9f80 monow 03d783611d265cae78293f88ea126ea1 nv12 16f7a46708ef25ebd0b72e47920cc11e nv21 7294574037cc7f9373ef5695d8ebe809 +nv24 3b100fb527b64ee2b2d7120da573faf5 +nv42 1841ce853152d86b27c130f319ea0db2 p010be a0311a09bba7383553267d2b3b9c075e p010le ee09a18aefa3ebe97715b3a7312cb8ff p016be a0311a09bba7383553267d2b3b9c075e @@ -72,6 +78,8 @@ rgba64le dfdba4de4a7cac9abf08852666c341d3 uyvy422 1c49e44ab3f060e85fc4a3a9464f045e xyz12be d2fa69ec91d3ed862f2dac3f8e7a3437 xyz12le 02bccd5e0b6824779a1f848b0ea3e3b5 +ya16be c0ce74d2a3da641ea634a3898dda7455 +ya16le 9b098d425e5bc27fa8a8ac8b176d592d ya8 28cea4f98ed452bd3da9c752e5e3399c yuv410p a85920d6bd26f51306e2ecbe71d1c554 yuv411p 9106e283d5dbcfba01c611886d58871a @@ -123,6 +131,8 @@ yuva420p9le 00d48d3b1b0383b92ccdb26543cfb7f8 yuva422p 801bfb0d4c9e7a524d97bfa11f7995fd yuva422p10be a0d743770698deea2be35ceb2bb0eaad yuva422p10le 6a0861e5c887f3213dc34d8674611950 +yuva422p12be 87dc9f7efc97d5e1bbea7564eca62a2a +yuva422p12le 137f75ade26b6d631d3998127e411a00 yuva422p16be c870b697714221ef9168b6984294e501 yuva422p16le fef7d5f29dfec9ee36216b7a610b4b39 yuva422p9be 83ff1ae035bb587dc59acf4121602dac @@ -130,6 +140,8 @@ yuva422p9le 75baca2a93a8e76b27ea208858213819 yuva444p cfbd995b538c34dee9c107ecf875b283 yuva444p10be de8b80b4c3a12624412530f09de6dd39 yuva444p10le 04c93877f724a29b47bc8c0a10a3036b +yuva444p12be a9efd9944314bb7fc9ba359bc3446446 +yuva444p12le acc831041bbf13e75636c0426f82aa19 yuva444p16be b10fd7c1b61ac22bdb285f0d91a390f1 yuva444p16le cac82ffc36b7052747407663fc5ed510 yuva444p9be a6f66d08b3370fdd90987a6143b7b91c diff --git a/tests/ref/fate/filter-pixfmts-fieldmatch b/tests/ref/fate/filter-pixfmts-fieldmatch index 99946c8d1..c3165b872 100644 --- a/tests/ref/fate/filter-pixfmts-fieldmatch +++ b/tests/ref/fate/filter-pixfmts-fieldmatch @@ -2,4 +2,4 @@ yuv410p a6c9b4065e8253d8120772f69be0bf04 yuv411p b913e634ad37ce046240252bed8681fb yuv420p a9286560141eb14595e427dbe5829b00 yuv422p 11ad22ce00c5e8a30d0472f29fb15434 -yuv444p 9350a3f23cd7d95ec441a49f63f55953 +yuv444p 6c5b0c1343d625d0656b6755906fd874 diff --git a/tests/ref/fate/filter-pixfmts-fieldorder b/tests/ref/fate/filter-pixfmts-fieldorder index 84a9e003c..066b94451 100644 --- a/tests/ref/fate/filter-pixfmts-fieldorder +++ b/tests/ref/fate/filter-pixfmts-fieldorder @@ -41,10 +41,16 @@ gray10be c26c73de96b630f1207ff589b6553ebd gray10le 16e4db1d611ec3fa5c9fd8fbdbf1ffcc gray12be 1c3285c150e1dddcf0fbee405cfb068e gray12le a57b6199f5690add0ac0150fa95c4988 +gray14be 1e3d0d0421cf84eac93d7ab1964207ff +gray14le 04899f53627203bd1fe3f17fb0de199c gray16be 293a36548ce16543494790f8f7f76a05 gray16le 84f83f5fcbb5d458efb8395a50a3797e gray9be ec877f5bcf0ea275a6f36c12cc9adf11 gray9le fba944fde7923d5089f4f52d12988b9e +grayf32be 1aa7960131f880c54fe3c77f13448674 +grayf32le 4029ac9d197f255794c1b9e416520fc7 +nv24 4fdbef26042c77f012df114e666efdb2 +nv42 59608290fece913e6b7d61edf581a529 rgb0 2e3d8c91c7a83d451593dfd06607ff39 rgb24 b82577f8215d3dc2681be60f1da247af rgb444be 1c3afc3a0c53c51139c76504f59bb1f4 @@ -63,6 +69,8 @@ rgba64le b34e6e30621ae579519a2d91a96a0acf uyvy422 75de70e31c435dde878002d3f22b238a xyz12be 15f5cda71de5fef9cec5e75e3833b6bc xyz12le 7be6c8781f38c21a6b8f602f62ca31e6 +ya16be 205d6a21890c1f057c9c20fbbba590e2 +ya16le f35616fdb5d3fbf767a4f11118cf8ad1 ya8 055ac5ab5ff8533dd319edc17a398af1 yuv411p e4a040e0e786c4dae07d9d3f90a54905 yuv422p 16ce67249c6ce7ef57a433646ad6dfc1 @@ -90,6 +98,8 @@ yuv444p9le 9bb3dde9fadb3c03a0ef8305b5f67a7e yuva422p c470da57cde22b452deb8874df710dce yuva422p10be a2ffa080ae661c1033aa38be28002922 yuva422p10le a4f5e8006f8ea3f964206605045e0fe0 +yuva422p12be ec44f9fc083d5f39051f2a65daea6890 +yuva422p12le 5fd785e19f68538ba76e6e505447239c yuva422p16be 929ec5d4bcfac13ba8a02f12e3f5fc7f yuva422p16le 7155a6036e25719f2e4d2d47212f077d yuva422p9be b1af62d553d790e041e80cf89608efe3 @@ -97,6 +107,8 @@ yuva422p9le 65c80faeb0021deb232ee451f77c89e3 yuva444p 9ac54882677f1fc5553a97ea558e942d yuva444p10be 3326267d176a8dfed2c7511b926962e6 yuva444p10le bfe957d1b5fea3585b3942cbfdd529ad +yuva444p12be ecaa57b7f0b04c3e8779a5f5dcd23032 +yuva444p12le 6b645eeaff8363d82ff686b3b020cae3 yuva444p16be 2f80d411847856e1364659dee8b23485 yuva444p16le 5796be8d66371b60037fc8053c27e900 yuva444p9be a83599c0e9fca08f6b7c6e02c2413fcf diff --git a/tests/ref/fate/filter-pixfmts-hflip b/tests/ref/fate/filter-pixfmts-hflip index a98314b0b..100dd708c 100644 --- a/tests/ref/fate/filter-pixfmts-hflip +++ b/tests/ref/fate/filter-pixfmts-hflip @@ -41,12 +41,18 @@ gray10be 160dd03e30d33379de92c70ee52c01fd gray10le 6baac1da6be3789409b67cd506afe7da gray12be de7b5ef4b513e7e8270c617249d1cbdf gray12le e8d0739ff61649bd82722b3134cbe776 +gray14be 22560aaac37f5bb2982819b752bf4608 +gray14le d4b2f5e7c4bbd39130655b8f2c55f010 gray16be cf7294d9aa23e1b838692ec01ade587b gray16le d91ce41e304419bcf32ac792f01bd64f gray9be ac8d260669479ae720a5b6d4d8639e34 gray9le 424fc581947bc8c357c9ec5e3c1c04d1 +grayf32be a69add7bbf892a71fe81b3b75982dbe2 +grayf32le 4563e176a35dc8a8a07e0829fad5eb88 nv12 801e58f1be5fd0b5bc4bf007c604b0b4 nv21 9f10dfff8963dc327d3395af21f0554f +nv24 f0c5b2f42970f8d4003621d8857a872f +nv42 4dcf9aec82b110712b396a8b365dcb13 p010be 744b13e44d39e1ff7588983fa03e0101 p010le a50b160346ab94f55a425065b57006f0 p016be 744b13e44d39e1ff7588983fa03e0101 @@ -69,6 +75,8 @@ rgba64be c910444019f4cfbf4d995227af55da8d rgba64le 0c810d8b3a6bca10321788e1cb145340 xyz12be 25f90259ff8a226befdaec3dfe82996e xyz12le 926c0791d59aaff61b2778e8ada3316d +ya16be 632b2e6e8e20c3edcfe99356fa7fca9e +ya16le e2ff5a2fb969c70dcc862937f9224873 ya8 4ad5920716de3d2fbbc49f95adb60345 yuv410p c49fd0c55c41185b1580aac77211992b yuv411p c416371077dce13d31bf1dc706111ae7 @@ -120,6 +128,8 @@ yuva420p9le 15e6654f50eddf97f852070d8dd8f009 yuva422p 902dc911ee175d9b1f2addcc03aab9a3 yuva422p10be fb927978446e975f7424600495a7acde yuva422p10le 1d0b5a5946b824810b1b83a7ce429274 +yuva422p12be 5407e82d1c4356472ad549e5ae38ea1e +yuva422p12le 5dc0e1910b248e12989ae937ddeec342 yuva422p16be 88977e5ddcee9377525c3f251fdeb25e yuva422p16le d6a50a91be5fc720ca97fc2f6fbd3bb2 yuva422p9be 996d8d73648c602c73c51e2d95b6cf9b @@ -127,6 +137,8 @@ yuva422p9le 2d64684a8844967e9ffe827c04e3c917 yuva444p 53247be24822d158c0866cd58d2ceeba yuva444p10be 9f3c25c3b9d26787d0bf8da2b15c75c6 yuva444p10le 1721b843b721629da7a0cd76ac665708 +yuva444p12be 9feb6e1d8bfe9b7fd5e352465f278704 +yuva444p12le 12a949ebcf0f94e4a2f9915ef778680a yuva444p16be 635fb2720470e0042a7c9b70bf908a2c yuva444p16le 6d5bd13f8bb804bd1158c1af732a24e1 yuva444p9be 3d3e7491192aa4e396015bf8e3755a24 diff --git a/tests/ref/fate/filter-pixfmts-il b/tests/ref/fate/filter-pixfmts-il index 3ed6c4622..979eb0ce3 100644 --- a/tests/ref/fate/filter-pixfmts-il +++ b/tests/ref/fate/filter-pixfmts-il @@ -41,14 +41,20 @@ gray10be 8400dec0eefb172849b785d35fc55674 gray10le b7d6e49e8d1291f2b0a57d55e9478ef1 gray12be c62bc3def5ea217dfb68433905cb9d64 gray12le 5bd0fef836928e1e19a315782a8c1302 +gray14be 5b3a15c182e2daed65dc39c33fd62735 +gray14le 3573d6870b14256f01800066d36ad862 gray16be 92c3b09f371b610cc1b6a9776034f4d0 gray16le 1db278d23a554e01910cedacc6c02521 gray9be ed7db5bb2ddc09bc26068c8b858db204 gray9le 2ec9188f0dcfefef76a09f371d7beb8e +grayf32be f36197c9e2ef5c50a995e980c1a37203 +grayf32le 8bf3d295c3ffd53da0e06d0702e7c1ca monob faba75df28033ba7ce3d82ff2a99ee68 monow 6e9cfb8d3a344c5f0c3e1d5e1297e580 nv12 3c3ba9b1b4c4dfff09c26f71b51dd146 nv21 ab586d8781246b5a32d8760a61db9797 +nv24 554153c71d142e3fd8e40b7dcaaec229 +nv42 d699724c8deaeb4f87faf2766512eec3 p010be 3df51286ef66b53e3e283dbbab582263 p010le eadcd8241e97e35b2b47d5eb2eaea6cd p016be 3df51286ef66b53e3e283dbbab582263 @@ -71,6 +77,8 @@ rgba64le a8a2daae04374a27219bc1c890204007 uyvy422 d6ee3ca43356d08c392382b24b22cda5 xyz12be 7c7d54c55f136cbbc50b18029f3be0b3 xyz12le 090ba6b1170baf2b1358b43b971d33b0 +ya16be bf2cf1e89c9fdb5bc10425db567ba2da +ya16le 4e9c9097fae615b8a5f4c3b237f752f0 ya8 a38d6e288f582f1a04310232ed764afc yuv410p dea1ab8843465adf5b8240b2d98fd85b yuv411p 8bf73777a5ff43c126be274245aceff1 @@ -122,6 +130,8 @@ yuva420p9le fbc3300867510900fec84caf718e8601 yuva422p 6c347a539965cd63cddfeec598858c11 yuva422p10be d34bf5f06ac5c67e12409aa111b4e21b yuva422p10le ecb3cc8d77cee05e54d4de60831be159 +yuva422p12be de287adba746037e68ff81cf7dc59e57 +yuva422p12le 761e18a8a73b55113e57ec39de33a4e6 yuva422p16be 47a8d3c98492d31bce0ed0d6f74f5131 yuva422p16le a950acae1f7ffc47a0951a40e3309b09 yuva422p9be 0217ba7015245e017ceb0a3eeb39fa56 @@ -129,6 +139,8 @@ yuva422p9le 1bbb5ba2b649bbe47c928012deb4e3ae yuva444p c8153b52159fb0f392459b8be406c294 yuva444p10be b0456e5ecdd87c983573e1016db85178 yuva444p10le f9b10500666ba220ce42b478a6785dae +yuva444p12be eb83a157ff3d750d3ee71c9c598c01b9 +yuva444p12le 6cc82bf7cc18194db81397debfc01951 yuva444p16be 97f8cb6ed835c7c5cd2fb112b1e135c7 yuva444p16le 47170401a8c348d3f05f6530607d066b yuva444p9be d5c0170b41221a9607e6ae586880a383 diff --git a/tests/ref/fate/filter-pixfmts-lut b/tests/ref/fate/filter-pixfmts-lut index 6cf798ad7..41c66e2bf 100644 --- a/tests/ref/fate/filter-pixfmts-lut +++ b/tests/ref/fate/filter-pixfmts-lut @@ -15,6 +15,7 @@ gbrp9le a8c4e29f4cb627db81ba053e0853e702 gray 20b14b5e26cd11300ed1249e04082170 gray10le 8f4140b55e847cc423002b89666db5ea gray12le ea89c02f6b3af49ddaf13364ed33d86d +gray14le 12bebea325a7822e890675bfc5111f0c gray16le aa10599924fb2440fa12b76e90f57dcb gray9le 7d9cc9ad6118674c547a54281d10cf05 rgb24 a356171207723a580e7d277078072005 diff --git a/tests/ref/fate/filter-pixfmts-null b/tests/ref/fate/filter-pixfmts-null index c45ce937b..4675b6e83 100644 --- a/tests/ref/fate/filter-pixfmts-null +++ b/tests/ref/fate/filter-pixfmts-null @@ -41,14 +41,20 @@ gray10be d486558ecd2e27afc17930be861f0e4c gray10le 917d687103b2adcca7132bfc070ca54a gray12be 9685614450f1282be433d2b07234ca1f gray12le 2700bd7fb3fea56e54eb03e31d6d4e57 +gray14be 19ed2bf25878980d6f81f6ae699024ec +gray14le 4b148b26b30040c05dc248a8852f31ac gray16be 08d997a3faa25a3db9d6be272d282eef gray16le df65eb804360795e3e38a2701fa9641a gray9be 6382a14594a8b68f0ec7de25531f9334 gray9le 4eb1dda58706436e3b69aef29b0089db +grayf32be f3bf178835f8146aa09d1da94bba4d8a +grayf32le fb6ea85bfbc8cd21c51fc0e110197294 monob 8b04f859fee6a0be856be184acd7a0b5 monow 54d16d2c01abfd72ecdb5e51e283937c nv12 8e24feb2c544dc26a20047a71e4c27aa nv21 335d85c9af6110f26ae9e187a82ed2cf +nv24 f30fc8d0ac40af69e119ea919a314572 +nv42 29a212f70f8780fe0eb99abcae81894d p010be 7f9842d6015026136bad60d03c035cc3 p010le c453421b9f726bdaf2bacf59a492c43b p016be 7f9842d6015026136bad60d03c035cc3 @@ -72,6 +78,8 @@ rgba64le b91e1d77f799eb92241a2d2d28437b15 uyvy422 3bcf3c80047592f2211fae3260b1b65d xyz12be a1ef56bf746d71f59669c28e48fc8450 xyz12le 831ff03c1ba4ef19374686f16a064d8c +ya16be 2f2c27f1854ac00c73d13861dcab2705 +ya16le 2c1fbd127c9f0435adc0e9b2ea3f486b ya8 dbb99fbcdc204aaa1a7397ff561f1a67 yuv410p 5d4d992a7728431aa4e0700f87fb7fd8 yuv411p 7e1300e89f5bc07939e2c4a6acbdf267 @@ -123,6 +131,8 @@ yuva420p9le 0e9c9803aaaddc9f38e419de587793c2 yuva422p 8f6bb778647e5dee62f544d646321171 yuva422p10be 2f7204c93a1e5bfb04538852f99e4074 yuva422p10le c8082548aca999edde77ef2749b1ff4c +yuva422p12be 19f8205cca3d19bfd4ad9cd2bfb07a0e +yuva422p12le 38e6c7d87332852d660df5594529fa6e yuva422p16be 427ad55f7464121bb3ce164641772bc6 yuva422p16le af6f8df651275de58129e010bb45ffcd yuva422p9be 47579cc2cea861ca1461589b80c4720f @@ -130,6 +140,8 @@ yuva422p9le aaeab2bfe80a29390e8666103ed8bb40 yuva444p 459fad5abfd16db9bb6a52761dc74cc1 yuva444p10be fa16bae4fc25429deb944ffa9f5b28a0 yuva444p10le 92f820d3481b7ebcb48b98a73e7b4c90 +yuva444p12be d8193387128a1b1efc51f36a12c85385 +yuva444p12le 9c17bf72b083f93040d1e19516b54de7 yuva444p16be c80c1899789a6411d0025730efc8f01c yuva444p16le 2ed56ea50fafda4d226c9b133755dad8 yuva444p9be 4903fde22b15d28da90761ac1cfcb1c5 diff --git a/tests/ref/fate/filter-pixfmts-pad b/tests/ref/fate/filter-pixfmts-pad index e777211cd..41ccec8c2 100644 --- a/tests/ref/fate/filter-pixfmts-pad +++ b/tests/ref/fate/filter-pixfmts-pad @@ -18,14 +18,18 @@ gbrp9le 9e827f438e081d334a6cae7e282698b0 gray ddc663a0491df3959d9c5795dceaa72e gray10le e6559c1c8c05ce89f44b465573db44e7 gray12le 1e6c6757658c7ae8a1f830432c5b7722 +gray14le af3f2f911c71cb34a8179a3291b5c90f gray16le 468bda6155bdc7a7a20c34d6e599fd16 gray9le f8f3dfe31ca5fcba828285bceefdab9a nv12 381574979cb04be10c9168540310afad nv21 0fdeb2cdd56cf5a7147dc273456fa217 +nv24 193b9eadcc06ad5081609f76249b3e47 +nv42 1738ad3c31c6c16e17679f5b09ce4677 rgb0 78d500c8361ab6423a4826a00268c908 rgb24 17f9e2e0c609009acaf2175c42d4a2a5 rgba b157c90191463d34fb3ce77b36c96386 xyz12le 85abf80b77a9236a76ba0b00fcbdea2d +ya16le 17cbe58356d56ff0f0f00280a31e6ca6 ya8 5fc0f471207ddf7aa01b07027d56b672 yuv410p cb871dcc1e84a7ef1d21f9237b88cf6e yuv411p aec2c1740de9a62db0d41f4dda9121b0 @@ -56,14 +60,16 @@ yuva420p16le ff45de790e7bdd3c25d8aad51289aba9 yuva420p9le 8ef1f3b3e01b5ce222e4caeec3dec396 yuva422p 91dcecc4bfdff1f0db9ef8b9b5b9ac2a yuva422p10le 1ba292c74c8646fd077a6116142b1bc8 +yuva422p12le 50e59879a9b64ac0fc7f76a110537baa yuva422p16le 383226550fe9c93d6e8bf0d45d1423d1 yuva422p9le 0fb76788c905c6d448143aa3c5eae116 yuva444p fb60941a57596b277417a3c7c00aa194 yuva444p10le 251ea4ead8300d752eb355a08cbb0352 +yuva444p12le f38b7c5747b43bcc6d647f143cb069cf yuva444p16le 5b65287e1862d2d9f1ad2cfdcde94661 yuva444p9le e6946c10b94c271e7ea24b3bcff314e1 -yuvj411p ca967e68759a4956729dd366adc7e7fa -yuvj420p c00611cd5f1558047d579d8a7d30e381 -yuvj422p b3acdf07147a7598836065836ad8420b -yuvj440p 3446ba4b1d7fdf536c926cee643c2b35 -yuvj444p 3b0f1a185af048b9e0b202d003fc7e62 +yuvj411p 87dbac57b211ab4823c1abbd702f1516 +yuvj420p 1abef62bce65131ca4913eb2006fd860 +yuvj422p 198c57b519e2be14b150889bd7f94898 +yuvj440p e6533260d197ad15e39319117c57473e +yuvj444p 26a44748960513783ea676eff409d89a diff --git a/tests/ref/fate/filter-pixfmts-scale b/tests/ref/fate/filter-pixfmts-scale index 1611c60ea..2f38241d8 100644 --- a/tests/ref/fate/filter-pixfmts-scale +++ b/tests/ref/fate/filter-pixfmts-scale @@ -41,14 +41,20 @@ gray10be 9452756d0b37f4f5c7cae7635e22d747 gray10le 37fd2e1ec6b66410212d39a342e864df gray12be 950de5d1b6b943a26c51f6a157e19a14 gray12le 9c3b154a8bb0a73a3b465892dbc23b36 +gray14be db9094229f32fb22c5cf06471b9a1cfa +gray14le c33308eb8b40142dfd9273249c1cd73a gray16be 32891cb0928b1119d8d43a6e1bef0e2b gray16le f96cfb5652b090dad52615930f0ce65f gray9be 779dec0c6c2df008128b91622a20daf8 gray9le fa87a96ca275f82260358635f838b514 +grayf32be 5e4c715519f53c15f1345df90481e5f5 +grayf32le 2ff1b84023e820307b1ba7a9550115bc monob f01cb0b623357387827902d9d0963435 monow 35c68b86c226d6990b2dcb573a05ff6b nv12 b118d24a3653fe66e5d9e079033aef79 nv21 c74bb1c10dbbdee8a1f682b194486c4d +nv24 2aa6e805bf6d4179ed8d7dea37d75db3 +nv42 80714d1eb2d8bcaeab3abc3124df1abd p010be 1d6726d94bf1385996a9a9840dd0e878 p010le 4b316f2b9e18972299beb73511278fa8 p016be 31e204018cbb53f8988c4e1174ea8ce9 @@ -72,6 +78,8 @@ rgba64le 783d2779adfafe3548bdb671ec0de69e uyvy422 aeb4ba4f9f003ae21f6d18089198244f xyz12be c7ba8345998c0141ddc079cdd29b1a40 xyz12le 95f5d3a0de834cc495c9032a14987cde +ya16be 372195dc947eee1bcb6f733a3544272e +ya16le 3923551514cfa588cf528e6f48e8cb9a ya8 0a9db5bb4b009de9197eede5e9d19e16 yuv410p e8f49b5fb9335b62c074f7f8bb0234fc yuv411p 5af32557c93beb482e26e7af693104c6 @@ -123,6 +131,8 @@ yuva420p9le 1fdfcde9cf7ef1d41002175b5793435f yuva422p 3a80cb3e08782033aabfeff1e8969403 yuva422p10be 94b13db95ceb970ded9773c095ade7d4 yuva422p10le 544965627ee94964b9cc57750c385b31 +yuva422p12be 4285def72fb83a9c918d78453220a4b7 +yuva422p12le accda73617ccfa3c45ced5e2a48a8323 yuva422p16be 95be33f9599958669f3c1cb24e54a5e5 yuva422p16le ed83cc6e8fb70306d0622962504d1fcf yuva422p9be 5ff6aeca90b8392133d7b1addfbd639b @@ -130,6 +140,8 @@ yuva422p9le 451965b076c628b0eabaa4ef33f98ded yuva444p f120326d9d940c9ac5cf5fd160969b82 yuva444p10be 1838cd61a24fda56a7379c9cd9cb1629 yuva444p10le c5c2f602caab63c58954f5a80691436a +yuva444p12be befc6a3602bc58df4f4e8490ae6782cf +yuva444p12le 8d13b714cdbadd2aa4e16c1ec673c0e2 yuva444p16be 39ca2e32aa61b210b6c528855d24a16b yuva444p16le cd2e0a001d8175f2204b2eb411c6a801 yuva444p9be 58add24afbf43ff0ff7079cc1948fb56 diff --git a/tests/ref/fate/filter-pixfmts-swapuv b/tests/ref/fate/filter-pixfmts-swapuv index e02380988..676a44069 100644 --- a/tests/ref/fate/filter-pixfmts-swapuv +++ b/tests/ref/fate/filter-pixfmts-swapuv @@ -48,6 +48,8 @@ yuva420p9le 7f445bfa33b6875cc65b47cee24c3154 yuva422p a1bd5c90b7bde1d3657025612a6f231e yuva422p10be 05bcc2394cfb0406d37b942423f6dbe7 yuva422p10le c166994709af82b9cdcebe4a7057348c +yuva422p12be 30f4f9d6a2a623c45c4474e4aac8f7b9 +yuva422p12le 79dfb02173b19beb76b9f0b76a96d1d5 yuva422p16be 9599ed5721f52028c3acfeb7b33ddc87 yuva422p16le dbb74e0bb2cf732e39e669f60ec6e1cf yuva422p9be 39093fec98b02e83b7e20dab3e5e4cf6 @@ -55,6 +57,8 @@ yuva422p9le a0a6dd2e62ea01e8a2268c7d88385252 yuva444p ff2441de373fbfaed7bc199a7abe5a3e yuva444p10be 857043b712213eee329d2fb584d74c3e yuva444p10le c3c451b3605af959a5d80146f4170e9d +yuva444p12be d60fd21b48fa6a3677a9070d5b2eafdb +yuva444p12le 8f43565353cf0ce0a06f6b1261e42a53 yuva444p16be 356d72791dfd91861b21630e315d40cb yuva444p16le 176591ce074ba8befc5fb279446ca1be yuva444p9be 675f0ed3e6572b05f06d9e44611bdff5 diff --git a/tests/ref/fate/filter-pixfmts-transpose b/tests/ref/fate/filter-pixfmts-transpose index 49069d6e0..b2ab3b72d 100644 --- a/tests/ref/fate/filter-pixfmts-transpose +++ b/tests/ref/fate/filter-pixfmts-transpose @@ -41,12 +41,18 @@ gray10be 48b421da79c195fd91dffb8fca79a8a2 gray10le 7774e3296916b896afa46f626334a280 gray12be 89f1c4b7821b771f6d967f9db871f8ef gray12le 43d392c3dcbd79b47cce31f2006c5050 +gray14be 5e2d1eb84d6d375502b3210d572d7433 +gray14le 6114774e9d07b08ec52fabaf6d0ee85a gray16be 4aef307021a91b1de67f1d4381a39132 gray16le 76f2afe156edca7ae05cfa4e5867126e gray9be 2c425fa532c940d226822da8b3592310 gray9le bcc575942910b3c72eaa72e8794f3acd +grayf32be 823288e1ec497bb1f22c070e502e5272 +grayf32le 6e9ec0e1cac3617f3041e681afd2c575 nv12 1965e3826144686748f2f6b516fca5ba nv21 292adaf5271c5c8516b71640458c01f4 +nv24 ea9de8b47faed722ee40182f89489beb +nv42 636af6cd6a4f3ac5edc0fc3ce3c56d63 p010be ad0de2cc9bff81688b182a870fcf7000 p010le e7ff5143595021246733ce6bd0a769e8 p016be ad0de2cc9bff81688b182a870fcf7000 @@ -68,6 +74,8 @@ rgba64be a60041217f4c0cd796d19d3940a12a41 rgba64le ad47197774858858ae7b0c177dffa459 xyz12be 68e5cba640f6e4ef72dff950e88b5342 xyz12le 8b6b6a6db4d7561e80db88ccaecce7a9 +ya16be 41b7ad48693e3ce8b4d3220016ef6b15 +ya16le 8ea70315667011a6ed50b6750f42b142 ya8 d4b7a62f80681fa44c977ff3a64f4ce4 yuv410p 4c0143429edd30aa01493447c90132ea yuv420p 2fa5b2201c75034206cc20e2c6134aed @@ -102,6 +110,8 @@ yuva420p9le 6e5cb3e761a9c45e26370307c49f8831 yuva444p 4f9e649fbc2c0c91178d1576e462bb31 yuva444p10be 9450fbac30b5f9da7414c895695591a9 yuva444p10le 84a93637bf2c7e498380beff9b1fc503 +yuva444p12be 3eae4234e38ce068600dd7fdb39e04d2 +yuva444p12le c4a4a3601a7fb9ef02770384e155f3d7 yuva444p16be 9fd2f00ea9bef8e488228bc0b47b28cb yuva444p16le ae9fd8d1baea0f8626b963816d667d2d yuva444p9be 4ce11ae57780f74c78cdd5c06be4bded diff --git a/tests/ref/fate/filter-pixfmts-vflip b/tests/ref/fate/filter-pixfmts-vflip index d49e50196..e4d58f9f1 100644 --- a/tests/ref/fate/filter-pixfmts-vflip +++ b/tests/ref/fate/filter-pixfmts-vflip @@ -41,14 +41,20 @@ gray10be 52710b3ab3ccf6101d28109f58cd48c4 gray10le 9c432a163f0cfe9ee2a4b72ae8a7c307 gray12be 7423ce8a77fbc40c5d4776eb28fec60a gray12le 808158633559d7deebc7dac2d79e88f8 +gray14be 68b14e31a089d6bd1fa2082d66d004da +gray14le 3842b874a9b05ce2ae3cad9ef7131013 gray16be 29f24ba7cb0fc4fd2ae78963d008f6e6 gray16le a37e9c4ea76e8eeddc2af8f600ba2c10 gray9be dda11d4ffd62b414012ffc4667fb4971 gray9le 159bf6482d217b2b8276eb2216cd7a09 +grayf32be c1ba5943a0d24d70e6a280f37e4f4593 +grayf32le 8e6c048a5b3b8b26d3a5ddfce255f3f6 monob 7810c4857822ccfc844d78f5e803269a monow 90a947bfcd5f2261e83b577f48ec57b1 nv12 261ebe585ae2aa4e70d39a10c1679294 nv21 2909feacd27bebb080c8e0fa41795269 +nv24 334420b9d3df84499d2ca16bb66eed2b +nv42 ba4063e2795c17fea3c8a646b01fd1f5 p010be 06e9354b6e0e38ba41736352cedc0bd5 p010le fd18d322bffbf5816902c13102872e22 p016be 06e9354b6e0e38ba41736352cedc0bd5 @@ -72,6 +78,8 @@ rgba64le 48f45b10503b7dd140329c3dd0d54c98 uyvy422 3a237e8376264e0cfa78f8a3fdadec8a xyz12be 810644e008deb231850d779aaa27cc7e xyz12le 829701db461b43533cf9241e0743bc61 +ya16be 01fa2780505ce1bd187ae7f9dcc5fcc3 +ya16le 492f528782acf22769b0b633187be212 ya8 4299c6ca3b470a7d8a420e26eb485b1d yuv410p c7adfe96c8e043a6cb9290c39bf8063c yuv411p 3fce29db403a25f81be39e01aaf6ff3a @@ -123,6 +131,8 @@ yuva420p9le aec21fa8f1088b7898cd80a30f382224 yuva422p 39707b0dfdaadeefa20819080365db15 yuva422p10be 53fbfe6d7eb01e2007003383c5d91850 yuva422p10le df1f95630ccd7bf05b95b6b3061cbeef +yuva422p12be 6b13c0f628b4369c2ecabb3aaf02dbc6 +yuva422p12le 5413c3f022d30fbdd9f1d4e35468c8c4 yuva422p16be 35ad91fa92b04e13d6b557d2f250ade1 yuva422p16le 8fb93970118fde962f5dbcd156966722 yuva422p9be 2b16b2dc102ad688a3023f30e3c6f9d9 @@ -130,6 +140,8 @@ yuva422p9le 6a23d290358691a9d8bab49582265764 yuva444p 442a690385166bed3e785d9262c1c501 yuva444p10be bb6d52902c30f5cc63ddc3fbe3346bf5 yuva444p10le 6e43f7c44e070fce492dcb1b038de85e +yuva444p12be 437e75242255bcaeb853c35284f3b58c +yuva444p12le 5864b489dff8cd98f46ca86b32f357e2 yuva444p16be b8801dccf64b3eadc2a5b5db67ae0b0f yuva444p16le 8e72ae66754badf5d1eeb094e6bf0ddc yuva444p9be bcd845394351ca6d15e947342802957d diff --git a/tests/ref/fate/gifenc-bgr4_byte b/tests/ref/fate/gifenc-bgr4_byte index 3495a8bbe..2cf3b7f93 100644 --- a/tests/ref/fate/gifenc-bgr4_byte +++ b/tests/ref/fate/gifenc-bgr4_byte @@ -3,176 +3,176 @@ #codec_id 0: gif #dimensions 0: 217x217 #sar 0: 0/1 -0, 0, 0, 1, 508, 0xa1b80fc0 -0, 1, 1, 1, 213, 0x4f554bd7, S=1, 1024, 0xb6327c81 -0, 2, 2, 1, 131, 0x283b2988, S=1, 1024, 0xae3a7c81 -0, 3, 3, 1, 384, 0xc4fea72a, S=1, 1024, 0xb6327c81 -0, 4, 4, 1, 381, 0x050ba2b8, S=1, 1024, 0x9e4a7c81 -0, 5, 5, 1, 430, 0x00cfb2ae, S=1, 1024, 0x9e4a7c81 -0, 6, 6, 1, 518, 0xc8e5d827, S=1, 1024, 0x9e4a7c81 -0, 7, 7, 1, 535, 0x326ce62a, S=1, 1024, 0x9e4a7c81 -0, 8, 8, 1, 438, 0x34d6b7c0, S=1, 1024, 0xb6327c81 -0, 9, 9, 1, 923, 0x9fb1a37c, S=1, 1024, 0xb6327c81 -0, 10, 10, 1, 694, 0xf20449a5, S=1, 1024, 0xb6327c81 -0, 11, 11, 1, 1194, 0x67cd2ab5, S=1, 1024, 0xb6327c81 -0, 12, 12, 1, 1291, 0x1d23539d, S=1, 1024, 0xb6327c81 -0, 13, 13, 1, 1245, 0x065f32e6, S=1, 1024, 0xb6327c81 -0, 14, 14, 1, 1330, 0x83ec51a4, S=1, 1024, 0xb6327c81 -0, 15, 15, 1, 1276, 0x2acf38dc, S=1, 1024, 0xb6327c81 -0, 16, 16, 1, 1475, 0x4cd197ef, S=1, 1024, 0xb6327c81 -0, 17, 17, 1, 1784, 0xd1e84ae6, S=1, 1024, 0xde0a7c81 -0, 18, 18, 1, 1675, 0x092dfa86, S=1, 1024, 0xde0a7c81 -0, 19, 19, 1, 1509, 0x639aaa00, S=1, 1024, 0xde0a7c81 -0, 20, 20, 1, 1705, 0xfd3719d5, S=1, 1024, 0xde0a7c81 -0, 21, 21, 1, 1745, 0x8a761db4, S=1, 1024, 0xde0a7c81 -0, 22, 22, 1, 1642, 0x18830245, S=1, 1024, 0xde0a7c81 -0, 23, 23, 1, 1718, 0x3c8d1ebe, S=1, 1024, 0xde0a7c81 -0, 24, 24, 1, 1900, 0x2ea879d1, S=1, 1024, 0xde0a7c81 -0, 25, 25, 1, 1807, 0x02b35230, S=1, 1024, 0xde0a7c81 -0, 26, 26, 1, 1915, 0x22d48344, S=1, 1024, 0xde0a7c81 -0, 27, 27, 1, 2100, 0x55fcd063, S=1, 1024, 0xde0a7c81 -0, 28, 28, 1, 2700, 0x7cc5f08b, S=1, 1024, 0xde0a7c81 -0, 29, 29, 1, 2673, 0xb997a80d, S=1, 1024, 0xde0a7c81 -0, 30, 30, 1, 2895, 0xab69484d, S=1, 1024, 0xde0a7c81 -0, 31, 31, 1, 3257, 0xf753cf24, S=1, 1024, 0xde0a7c81 -0, 32, 32, 1, 3179, 0x34f2c13b, S=1, 1024, 0xde0a7c81 -0, 33, 33, 1, 3296, 0x7c06e72f, S=1, 1024, 0xde0a7c81 -0, 34, 34, 1, 3600, 0x4ca67634, S=1, 1024, 0xde0a7c81 -0, 35, 35, 1, 3699, 0xabe89fe3, S=1, 1024, 0xde0a7c81 -0, 36, 36, 1, 3814, 0x1869d3f4, S=1, 1024, 0xde0a7c81 -0, 37, 37, 1, 3627, 0x19bd7da7, S=1, 1024, 0xde0a7c81 -0, 38, 38, 1, 2950, 0x048a6055, S=1, 1024, 0xde0a7c81 -0, 39, 39, 1, 3086, 0x64ec8fc2, S=1, 1024, 0xde0a7c81 -0, 40, 40, 1, 3094, 0x1a388553, S=1, 1024, 0xde0a7c81 -0, 41, 41, 1, 3456, 0x01432c82, S=1, 1024, 0xde0a7c81 -0, 42, 42, 1, 4108, 0xf9505c66, S=1, 1024, 0xde0a7c81 -0, 43, 43, 1, 4217, 0x7f985ba4, S=1, 1024, 0xde0a7c81 -0, 44, 44, 1, 3613, 0xd0684d83, S=1, 1024, 0xde0a7c81 -0, 45, 45, 1, 3910, 0x0070e692, S=1, 1024, 0xde0a7c81 -0, 46, 46, 1, 4461, 0x5cc9e33d, S=1, 1024, 0xde0a7c81 -0, 47, 47, 1, 4593, 0x33a32dd1, S=1, 1024, 0xde0a7c81 -0, 48, 48, 1, 4822, 0x59549883, S=1, 1024, 0xde0a7c81 -0, 49, 49, 1, 5398, 0xb7bac31e, S=1, 1024, 0xde0a7c81 -0, 50, 50, 1, 5266, 0x21c695aa, S=1, 1024, 0xde0a7c81 -0, 51, 51, 1, 5416, 0xf305e3ed, S=1, 1024, 0xde0a7c81 -0, 52, 52, 1, 5519, 0x857d071f, S=1, 1024, 0xde0a7c81 -0, 53, 53, 1, 5701, 0x8f885c9c, S=1, 1024, 0xde0a7c81 -0, 54, 54, 1, 6160, 0x48523e83, S=1, 1024, 0xde0a7c81 -0, 55, 55, 1, 6233, 0x8fd2511e, S=1, 1024, 0xde0a7c81 -0, 56, 56, 1, 5911, 0x92d4c516, S=1, 1024, 0xde0a7c81 -0, 57, 57, 1, 5997, 0xbd7cfa15, S=1, 1024, 0xde0a7c81 -0, 58, 58, 1, 5946, 0x8f5fedff, S=1, 1024, 0xde0a7c81 -0, 59, 59, 1, 6468, 0x45c0cb8c, S=1, 1024, 0xde0a7c81 -0, 60, 60, 1, 6737, 0x4e1e39ac, S=1, 1024, 0xde0a7c81 -0, 61, 61, 1, 6275, 0x1d5e8f4c, S=1, 1024, 0xde0a7c81 -0, 62, 62, 1, 6641, 0x844b3aad, S=1, 1024, 0xde0a7c81 -0, 63, 63, 1, 6378, 0x52568640, S=1, 1024, 0xde0a7c81 -0, 64, 64, 1, 6257, 0xfabc585f, S=1, 1024, 0xde0a7c81 -0, 65, 65, 1, 6908, 0xf261701c, S=1, 1024, 0xde0a7c81 -0, 66, 66, 1, 7230, 0xb4f524ce, S=1, 1024, 0xde0a7c81 -0, 67, 67, 1, 7556, 0x89c1a712, S=1, 1024, 0xde0a7c81 -0, 68, 68, 1, 7413, 0x553970a4, S=1, 1024, 0xde0a7c81 -0, 69, 69, 1, 7476, 0x24d2a761, S=1, 1024, 0xde0a7c81 -0, 70, 70, 1, 7596, 0xf072e431, S=1, 1024, 0xde0a7c81 -0, 71, 71, 1, 7756, 0x131205c0, S=1, 1024, 0xde0a7c81 -0, 72, 72, 1, 8015, 0xf4536a7f, S=1, 1024, 0xde0a7c81 -0, 73, 73, 1, 8128, 0xba80be2b, S=1, 1024, 0xde0a7c81 -0, 74, 74, 1, 8101, 0x44ceb3a2, S=1, 1024, 0xde0a7c81 -0, 75, 75, 1, 7863, 0x55043dfd, S=1, 1024, 0xde0a7c81 -0, 76, 76, 1, 7960, 0x38399182, S=1, 1024, 0xde0a7c81 -0, 77, 77, 1, 8238, 0x1d52ecf3, S=1, 1024, 0xde0a7c81 -0, 78, 78, 1, 8321, 0xd8d24a5c, S=1, 1024, 0xde0a7c81 -0, 79, 79, 1, 8562, 0x4a0cc02b, S=1, 1024, 0xde0a7c81 -0, 80, 80, 1, 8746, 0x2db40da7, S=1, 1024, 0xde0a7c81 -0, 81, 81, 1, 8578, 0x46f9a4c1, S=1, 1024, 0xde0a7c81 -0, 82, 82, 1, 8878, 0xf58d5a19, S=1, 1024, 0xde0a7c81 -0, 83, 83, 1, 9077, 0x78de57f6, S=1, 1024, 0xde0a7c81 -0, 84, 84, 1, 9310, 0x8c10f77a, S=1, 1024, 0xde0a7c81 -0, 85, 85, 1, 9394, 0x741f431e, S=1, 1024, 0xde0a7c81 -0, 86, 86, 1, 9161, 0x6f499587, S=1, 1024, 0xde0a7c81 -0, 87, 87, 1, 9462, 0x628936c3, S=1, 1024, 0xde0a7c81 -0, 88, 88, 1, 9650, 0x4cb4936e, S=1, 1024, 0xde0a7c81 -0, 89, 89, 1, 9701, 0x5e069c40, S=1, 1024, 0xde0a7c81 -0, 90, 90, 1, 9523, 0x66a13c83, S=1, 1024, 0xde0a7c81 -0, 91, 91, 1, 9891, 0x43ea0e93, S=1, 1024, 0xde0a7c81 -0, 92, 92, 1, 10005, 0x96a849e7, S=1, 1024, 0xde0a7c81 -0, 93, 93, 1, 10038, 0x68032d25, S=1, 1024, 0xde0a7c81 -0, 94, 94, 1, 10086, 0xef59458d, S=1, 1024, 0xde0a7c81 -0, 95, 95, 1, 10438, 0x3466fed0, S=1, 1024, 0xde0a7c81 -0, 96, 96, 1, 10583, 0x8bdd5477, S=1, 1024, 0xde0a7c81 -0, 97, 97, 1, 10581, 0x69d27fee, S=1, 1024, 0xde0a7c81 -0, 98, 98, 1, 10807, 0xde62d6e3, S=1, 1024, 0xde0a7c81 -0, 99, 99, 1, 11111, 0x34eb4c13, S=1, 1024, 0xde0a7c81 -0, 100, 100, 1, 11194, 0x584f6b73, S=1, 1024, 0xde0a7c81 -0, 101, 101, 1, 11240, 0xc90ba13f, S=1, 1024, 0xde0a7c81 -0, 102, 102, 1, 11483, 0x59c4f3c5, S=1, 1024, 0xde0a7c81 -0, 103, 103, 1, 11680, 0xc62c5bc1, S=1, 1024, 0xde0a7c81 -0, 104, 104, 1, 11785, 0xc9bab793, S=1, 1024, 0xde0a7c81 -0, 105, 105, 1, 11436, 0xc9c40809, S=1, 1024, 0xde0a7c81 -0, 106, 106, 1, 11928, 0x4b77c9a7, S=1, 1024, 0xde0a7c81 -0, 107, 107, 1, 11932, 0x722abcbe, S=1, 1024, 0xde0a7c81 -0, 108, 108, 1, 12281, 0x0d136f53, S=1, 1024, 0xde0a7c81 -0, 109, 109, 1, 12334, 0x04a47f78, S=1, 1024, 0xde0a7c81 -0, 110, 110, 1, 12452, 0xa02db188, S=1, 1024, 0xde0a7c81 -0, 111, 111, 1, 12695, 0x1a813b2e, S=1, 1024, 0xde0a7c81 -0, 112, 112, 1, 12668, 0x81b24f79, S=1, 1024, 0xde0a7c81 -0, 113, 113, 1, 12957, 0x4da59f8c, S=1, 1024, 0xde0a7c81 -0, 114, 114, 1, 13054, 0x7abedf5a, S=1, 1024, 0xde0a7c81 -0, 115, 115, 1, 13147, 0x138f2bbd, S=1, 1024, 0xde0a7c81 -0, 116, 116, 1, 13171, 0x43c1195f, S=1, 1024, 0xde0a7c81 -0, 117, 117, 1, 13198, 0x2c8d58d4, S=1, 1024, 0xde0a7c81 -0, 118, 118, 1, 13211, 0x12c36193, S=1, 1024, 0xde0a7c81 -0, 119, 119, 1, 13210, 0xfe496107, S=1, 1024, 0xde0a7c81 -0, 120, 120, 1, 13467, 0x4d8ea128, S=1, 1024, 0xde0a7c81 -0, 121, 121, 1, 13665, 0x94caddde, S=1, 1024, 0xde0a7c81 -0, 122, 122, 1, 13692, 0xe38febd9, S=1, 1024, 0xde0a7c81 -0, 123, 123, 1, 13821, 0xee592e62, S=1, 1024, 0xde0a7c81 -0, 124, 124, 1, 13946, 0xceb09235, S=1, 1024, 0xde0a7c81 -0, 125, 125, 1, 14063, 0x7361d2f5, S=1, 1024, 0xde0a7c81 -0, 126, 126, 1, 14124, 0x226bcac1, S=1, 1024, 0xde0a7c81 -0, 127, 127, 1, 14331, 0x0649512b, S=1, 1024, 0xde0a7c81 -0, 128, 128, 1, 14469, 0x0d7da45b, S=1, 1024, 0xde0a7c81 -0, 129, 129, 1, 14536, 0x73cca242, S=1, 1024, 0xde0a7c81 -0, 130, 130, 1, 14608, 0x1f3dd14e, S=1, 1024, 0xde0a7c81 -0, 131, 131, 1, 14898, 0xd13d258e, S=1, 1024, 0xde0a7c81 -0, 132, 132, 1, 14978, 0xfa049fea, S=1, 1024, 0xde0a7c81 -0, 133, 133, 1, 15142, 0x1dfad60c, S=1, 1024, 0xde0a7c81 -0, 134, 134, 1, 15129, 0x5962bae7, S=1, 1024, 0xde0a7c81 -0, 135, 135, 1, 15243, 0x2c2c113b, S=1, 1024, 0xde0a7c81 -0, 136, 136, 1, 15337, 0x3cab623b, S=1, 1024, 0xde0a7c81 -0, 137, 137, 1, 15638, 0xbff3a100, S=1, 1024, 0xde0a7c81 -0, 138, 138, 1, 15912, 0x13bf1fb2, S=1, 1024, 0xde0a7c81 -0, 139, 139, 1, 16041, 0x01134246, S=1, 1024, 0xde0a7c81 -0, 140, 140, 1, 16228, 0xe2f80035, S=1, 1024, 0xde0a7c81 -0, 141, 141, 1, 16262, 0xc8d3ea51, S=1, 1024, 0xde0a7c81 -0, 142, 142, 1, 16371, 0xe7da07f2, S=1, 1024, 0xde0a7c81 -0, 143, 143, 1, 16661, 0x10ada592, S=1, 1024, 0xde0a7c81 -0, 144, 144, 1, 16917, 0xbfb717e5, S=1, 1024, 0xde0a7c81 -0, 145, 145, 1, 17149, 0x4074ca41, S=1, 1024, 0xde0a7c81 -0, 146, 146, 1, 17172, 0xf749b49f, S=1, 1024, 0xde0a7c81 -0, 147, 147, 1, 17315, 0x2abea8a0, S=1, 1024, 0xde0a7c81 -0, 148, 148, 1, 17397, 0x14f71122, S=1, 1024, 0xde0a7c81 -0, 149, 149, 1, 17431, 0xce49f2d3, S=1, 1024, 0xde0a7c81 -0, 150, 150, 1, 17576, 0x7c6552ad, S=1, 1024, 0xde0a7c81 -0, 151, 151, 1, 17764, 0x1d198d60, S=1, 1024, 0xde0a7c81 -0, 152, 152, 1, 17826, 0xe1727f57, S=1, 1024, 0xde0a7c81 -0, 153, 153, 1, 17918, 0xb78d9b9f, S=1, 1024, 0xde0a7c81 -0, 154, 154, 1, 17823, 0xc9fabf19, S=1, 1024, 0xde0a7c81 -0, 155, 155, 1, 18142, 0xeb5b21a9, S=1, 1024, 0xde0a7c81 -0, 156, 156, 1, 18257, 0x7b38822c, S=1, 1024, 0xde0a7c81 -0, 157, 157, 1, 18337, 0xd395c279, S=1, 1024, 0xde0a7c81 -0, 158, 158, 1, 18293, 0x6c3b3766, S=1, 1024, 0xde0a7c81 -0, 159, 159, 1, 18418, 0x2abcbcf8, S=1, 1024, 0xde0a7c81 -0, 160, 160, 1, 18607, 0x79424730, S=1, 1024, 0xde0a7c81 -0, 161, 161, 1, 18916, 0x8707bbc6, S=1, 1024, 0xde0a7c81 -0, 162, 162, 1, 19073, 0xd82c03f6, S=1, 1024, 0xde0a7c81 -0, 163, 163, 1, 19168, 0xb7d6fe27, S=1, 1024, 0xde0a7c81 -0, 164, 164, 1, 19210, 0x79f301eb, S=1, 1024, 0xde0a7c81 -0, 165, 165, 1, 19398, 0x0a5663c6, S=1, 1024, 0xde0a7c81 -0, 166, 166, 1, 19480, 0x4fe09e5b, S=1, 1024, 0xde0a7c81 -0, 167, 167, 1, 19659, 0xab971088, S=1, 1024, 0xde0a7c81 -0, 168, 168, 1, 19672, 0x2e331553, S=1, 1024, 0xde0a7c81 -0, 169, 169, 1, 19936, 0x2eea628a, S=1, 1024, 0xde0a7c81 -0, 170, 170, 1, 19975, 0xd6bb9ab2, S=1, 1024, 0xde0a7c81 -0, 171, 171, 1, 20021, 0xf7e98dc5, S=1, 1024, 0xde0a7c81 -0, 172, 172, 1, 20060, 0x20017807, S=1, 1024, 0xde0a7c81 +0, 0, 0, 1, 1297, 0x53e8b1c1 +0, 1, 1, 1, 221, 0x52d24d05, F=0x0 +0, 2, 2, 1, 139, 0xc9e32ab4, F=0x0 +0, 3, 3, 1, 392, 0x9244a858, F=0x0 +0, 4, 4, 1, 389, 0xc5bea3e0, F=0x0 +0, 5, 5, 1, 438, 0xfa2ab3d6, F=0x0 +0, 6, 6, 1, 526, 0x281ed94f, F=0x0 +0, 7, 7, 1, 543, 0xa53ee752, F=0x0 +0, 8, 8, 1, 446, 0x41d0b8ee, F=0x0 +0, 9, 9, 1, 931, 0xe8efa4aa, F=0x0 +0, 10, 10, 1, 702, 0x2d1c4ad3, F=0x0 +0, 11, 11, 1, 1202, 0xf0cc2be3, F=0x0 +0, 12, 12, 1, 1299, 0x189f54cb, F=0x0 +0, 13, 13, 1, 1253, 0xcb883414, F=0x0 +0, 14, 14, 1, 1338, 0xad6a52d2, F=0x0 +0, 15, 15, 1, 1284, 0x14993a0a, F=0x0 +0, 16, 16, 1, 1483, 0x216c991d, F=0x0 +0, 17, 17, 1, 1792, 0x58eb4c1e, F=0x0 +0, 18, 18, 1, 1683, 0x0b49fbbe, F=0x0 +0, 19, 19, 1, 1517, 0x9b57ab38, F=0x0 +0, 20, 20, 1, 1713, 0x23f21b0d, F=0x0 +0, 21, 21, 1, 1753, 0xe1e21eec, F=0x0 +0, 22, 22, 1, 1650, 0xf258037d, F=0x0 +0, 23, 23, 1, 1726, 0x73111ff6, F=0x0 +0, 24, 24, 1, 1908, 0x430b7b09, F=0x0 +0, 25, 25, 1, 1815, 0xa5af5368, F=0x0 +0, 26, 26, 1, 1923, 0x497f847c, F=0x0 +0, 27, 27, 1, 2108, 0x5e2ed19b, F=0x0 +0, 28, 28, 1, 2708, 0x6064f1c3, F=0x0 +0, 29, 29, 1, 2681, 0x7c4ea945, F=0x0 +0, 30, 30, 1, 2903, 0x7cbf4985, F=0x0 +0, 31, 31, 1, 3265, 0x81f7d05c, F=0x0 +0, 32, 32, 1, 3187, 0x6077c273, F=0x0 +0, 33, 33, 1, 3304, 0x3632e867, F=0x0 +0, 34, 34, 1, 3608, 0x7961776c, F=0x0 +0, 35, 35, 1, 3707, 0x515aa11b, F=0x0 +0, 36, 36, 1, 3822, 0x4a03d52c, F=0x0 +0, 37, 37, 1, 3635, 0x67607edf, F=0x0 +0, 38, 38, 1, 2958, 0x18e8618d, F=0x0 +0, 39, 39, 1, 3094, 0x1f1990fa, F=0x0 +0, 40, 40, 1, 3102, 0xde16868b, F=0x0 +0, 41, 41, 1, 3464, 0x7e6f2dba, F=0x0 +0, 42, 42, 1, 4116, 0x91585d9e, F=0x0 +0, 43, 43, 1, 4225, 0x9c785cdc, F=0x0 +0, 44, 44, 1, 3621, 0x0d0a4ebb, F=0x0 +0, 45, 45, 1, 3918, 0xa70ae7ca, F=0x0 +0, 46, 46, 1, 4469, 0xa318e475, F=0x0 +0, 47, 47, 1, 4601, 0x1ae12f09, F=0x0 +0, 48, 48, 1, 4830, 0x57b999bb, F=0x0 +0, 49, 49, 1, 5406, 0x744cc456, F=0x0 +0, 50, 50, 1, 5274, 0x3d6996e2, F=0x0 +0, 51, 51, 1, 5424, 0xc587e525, F=0x0 +0, 52, 52, 1, 5527, 0xd5870857, F=0x0 +0, 53, 53, 1, 5709, 0xbd715dd4, F=0x0 +0, 54, 54, 1, 6168, 0xa5c13fbb, F=0x0 +0, 55, 55, 1, 6241, 0x46485256, F=0x0 +0, 56, 56, 1, 5919, 0xc0bcc64e, F=0x0 +0, 57, 57, 1, 6005, 0x5443fb4d, F=0x0 +0, 58, 58, 1, 5954, 0xe7efef37, F=0x0 +0, 59, 59, 1, 6476, 0x1aadccc4, F=0x0 +0, 60, 60, 1, 6745, 0x6af23ae4, F=0x0 +0, 61, 61, 1, 6283, 0x07049084, F=0x0 +0, 62, 62, 1, 6649, 0x2c1f3be5, F=0x0 +0, 63, 63, 1, 6386, 0xb9848778, F=0x0 +0, 64, 64, 1, 6265, 0xce725997, F=0x0 +0, 65, 65, 1, 6916, 0xdfac7154, F=0x0 +0, 66, 66, 1, 7238, 0x2ace2606, F=0x0 +0, 67, 67, 1, 7564, 0x8cf9a84a, F=0x0 +0, 68, 68, 1, 7421, 0xaa1a71dc, F=0x0 +0, 69, 69, 1, 7484, 0xc67ba899, F=0x0 +0, 70, 70, 1, 7604, 0x2479e569, F=0x0 +0, 71, 71, 1, 7764, 0x0a1906f8, F=0x0 +0, 72, 72, 1, 8023, 0x27206bb7, F=0x0 +0, 73, 73, 1, 8136, 0x7705bf63, F=0x0 +0, 74, 74, 1, 8109, 0xe05cb4da, F=0x0 +0, 75, 75, 1, 7871, 0xce733f35, F=0x0 +0, 76, 76, 1, 7968, 0x27ef92ba, F=0x0 +0, 77, 77, 1, 8246, 0x5fe7ee2b, F=0x0 +0, 78, 78, 1, 8329, 0x809e4b94, F=0x0 +0, 79, 79, 1, 8570, 0x179fc163, F=0x0 +0, 80, 80, 1, 8754, 0xdb870edf, F=0x0 +0, 81, 81, 1, 8586, 0x280ca5f9, F=0x0 +0, 82, 82, 1, 8886, 0x445e5b51, F=0x0 +0, 83, 83, 1, 9085, 0xba37592e, F=0x0 +0, 84, 84, 1, 9318, 0xe970f8b2, F=0x0 +0, 85, 85, 1, 9402, 0x37ee4456, F=0x0 +0, 86, 86, 1, 9169, 0x171196bf, F=0x0 +0, 87, 87, 1, 9470, 0x793837fb, F=0x0 +0, 88, 88, 1, 9658, 0x489294a6, F=0x0 +0, 89, 89, 1, 9709, 0x980c9d78, F=0x0 +0, 90, 90, 1, 9531, 0xc7a83dbb, F=0x0 +0, 91, 91, 1, 9899, 0x658f0fcb, F=0x0 +0, 92, 92, 1, 10013, 0x434c4b1f, F=0x0 +0, 93, 93, 1, 10046, 0x3cdf2e5d, F=0x0 +0, 94, 94, 1, 10094, 0xfeb546c5, F=0x0 +0, 95, 95, 1, 10446, 0xf0d10017, F=0x0 +0, 96, 96, 1, 10591, 0xf90f55af, F=0x0 +0, 97, 97, 1, 10589, 0xd4948126, F=0x0 +0, 98, 98, 1, 10815, 0x5cb2d81b, F=0x0 +0, 99, 99, 1, 11119, 0x25ca4d4b, F=0x0 +0, 100, 100, 1, 11202, 0xae566cab, F=0x0 +0, 101, 101, 1, 11248, 0x5731a277, F=0x0 +0, 102, 102, 1, 11491, 0x1021f4fd, F=0x0 +0, 103, 103, 1, 11688, 0x6cb05cf9, F=0x0 +0, 104, 104, 1, 11793, 0xf036b8cb, F=0x0 +0, 105, 105, 1, 11444, 0x46d90941, F=0x0 +0, 106, 106, 1, 11936, 0x204acadf, F=0x0 +0, 107, 107, 1, 11940, 0x4bddbdf6, F=0x0 +0, 108, 108, 1, 12289, 0x902d708b, F=0x0 +0, 109, 109, 1, 12342, 0xc85680b0, F=0x0 +0, 110, 110, 1, 12460, 0xf3beb2c0, F=0x0 +0, 111, 111, 1, 12703, 0x96493c66, F=0x0 +0, 112, 112, 1, 12676, 0xdc9250b1, F=0x0 +0, 113, 113, 1, 12965, 0x08dba0c4, F=0x0 +0, 114, 114, 1, 13062, 0xac2ce092, F=0x0 +0, 115, 115, 1, 13155, 0xb6552cf5, F=0x0 +0, 116, 116, 1, 13179, 0x03d61a97, F=0x0 +0, 117, 117, 1, 13206, 0x0d8a5a0c, F=0x0 +0, 118, 118, 1, 13219, 0x039862cb, F=0x0 +0, 119, 119, 1, 13218, 0xede6623f, F=0x0 +0, 120, 120, 1, 13475, 0x7672a260, F=0x0 +0, 121, 121, 1, 13673, 0xaf0ddf16, F=0x0 +0, 122, 122, 1, 13700, 0x1ec9ed11, F=0x0 +0, 123, 123, 1, 13829, 0xc6cb2f9a, F=0x0 +0, 124, 124, 1, 13954, 0x3f89936d, F=0x0 +0, 125, 125, 1, 14071, 0x72d2d42d, F=0x0 +0, 126, 126, 1, 14132, 0x6c34cbf9, F=0x0 +0, 127, 127, 1, 14339, 0x4c695263, F=0x0 +0, 128, 128, 1, 14477, 0xfbcda593, F=0x0 +0, 129, 129, 1, 14544, 0xb3d3a37a, F=0x0 +0, 130, 130, 1, 14616, 0xb704d286, F=0x0 +0, 131, 131, 1, 14906, 0xca9226c6, F=0x0 +0, 132, 132, 1, 14986, 0x54e8a122, F=0x0 +0, 133, 133, 1, 15150, 0x40bed744, F=0x0 +0, 134, 134, 1, 15137, 0x6c4ebc1f, F=0x0 +0, 135, 135, 1, 15251, 0xca081273, F=0x0 +0, 136, 136, 1, 15345, 0x4d266373, F=0x0 +0, 137, 137, 1, 15646, 0x3f64a238, F=0x0 +0, 138, 138, 1, 15920, 0xe12020ea, F=0x0 +0, 139, 139, 1, 16049, 0x6bbb437e, F=0x0 +0, 140, 140, 1, 16236, 0x31a6016d, F=0x0 +0, 141, 141, 1, 16270, 0x40f1eb89, F=0x0 +0, 142, 142, 1, 16379, 0xe4d0092a, F=0x0 +0, 143, 143, 1, 16669, 0x6f22a6ca, F=0x0 +0, 144, 144, 1, 16925, 0x564a191d, F=0x0 +0, 145, 145, 1, 17157, 0xf1c7cb79, F=0x0 +0, 146, 146, 1, 17180, 0xc4b3b5d7, F=0x0 +0, 147, 147, 1, 17323, 0xa670a9d8, F=0x0 +0, 148, 148, 1, 17405, 0xf499125a, F=0x0 +0, 149, 149, 1, 17439, 0xd76af40b, F=0x0 +0, 150, 150, 1, 17584, 0x364d53e5, F=0x0 +0, 151, 151, 1, 17772, 0xbc218e98, F=0x0 +0, 152, 152, 1, 17834, 0xcc19808f, F=0x0 +0, 153, 153, 1, 17926, 0x12639cd7, F=0x0 +0, 154, 154, 1, 17831, 0xb0f9c051, F=0x0 +0, 155, 155, 1, 18150, 0x574022e1, F=0x0 +0, 156, 156, 1, 18265, 0x73458364, F=0x0 +0, 157, 157, 1, 18345, 0x2d31c3b1, F=0x0 +0, 158, 158, 1, 18301, 0x9028389e, F=0x0 +0, 159, 159, 1, 18426, 0xe701be30, F=0x0 +0, 160, 160, 1, 18615, 0x1bfd4868, F=0x0 +0, 161, 161, 1, 18924, 0xa269bcfe, F=0x0 +0, 162, 162, 1, 19081, 0xb2f5052e, F=0x0 +0, 163, 163, 1, 19176, 0x0676ff5f, F=0x0 +0, 164, 164, 1, 19218, 0xfbb40323, F=0x0 +0, 165, 165, 1, 19406, 0x714664fe, F=0x0 +0, 166, 166, 1, 19488, 0x1acf9f93, F=0x0 +0, 167, 167, 1, 19667, 0x50bd11c0, F=0x0 +0, 168, 168, 1, 19680, 0xe322168b, F=0x0 +0, 169, 169, 1, 19944, 0x25b763c2, F=0x0 +0, 170, 170, 1, 19983, 0xfd109bea, F=0x0 +0, 171, 171, 1, 20029, 0x565d8efd, F=0x0 +0, 172, 172, 1, 20068, 0xadee793f, F=0x0 diff --git a/tests/ref/fate/gifenc-bgr8 b/tests/ref/fate/gifenc-bgr8 index 0a4e5d48c..58767a6b0 100644 --- a/tests/ref/fate/gifenc-bgr8 +++ b/tests/ref/fate/gifenc-bgr8 @@ -3,176 +3,176 @@ #codec_id 0: gif #dimensions 0: 217x217 #sar 0: 0/1 -0, 0, 0, 1, 552, 0x271a2dd3 -0, 1, 1, 1, 297, 0x90168a95, S=1, 1024, 0xf351799f -0, 2, 2, 1, 438, 0x91efce1b, S=1, 1024, 0xf351799f -0, 3, 3, 1, 450, 0x7c2dcfad, S=1, 1024, 0xf351799f -0, 4, 4, 1, 547, 0xc131fd3b, S=1, 1024, 0xf351799f -0, 5, 5, 1, 614, 0x68182006, S=1, 1024, 0xf351799f -0, 6, 6, 1, 642, 0x78bb1f5f, S=1, 1024, 0xf351799f -0, 7, 7, 1, 660, 0x35c033a2, S=1, 1024, 0xf351799f -0, 8, 8, 1, 821, 0xaf30790b, S=1, 1024, 0xf351799f -0, 9, 9, 1, 1157, 0x741c2da1, S=1, 1024, 0xf351799f -0, 10, 10, 1, 179, 0x3a27517c, S=1, 1024, 0xf351799f -0, 11, 11, 1, 1333, 0x5ee76f3c, S=1, 1024, 0xf351799f -0, 12, 12, 1, 1638, 0x5f640e86, S=1, 1024, 0xf351799f -0, 13, 13, 1, 1531, 0xccb8e437, S=1, 1024, 0xf351799f -0, 14, 14, 1, 1720, 0xc95d45ec, S=1, 1024, 0xf351799f -0, 15, 15, 1, 1910, 0x56cc831e, S=1, 1024, 0xf351799f -0, 16, 16, 1, 2124, 0x9cc8e130, S=1, 1024, 0xf351799f -0, 17, 17, 1, 2248, 0x05a325b1, S=1, 1024, 0xf351799f -0, 18, 18, 1, 2311, 0xdc633703, S=1, 1024, 0xf351799f -0, 19, 19, 1, 2408, 0x91c26f3e, S=1, 1024, 0xf351799f -0, 20, 20, 1, 2601, 0x8cf3c157, S=1, 1024, 0xf351799f -0, 21, 21, 1, 2687, 0x8f6400e6, S=1, 1024, 0xf351799f -0, 22, 22, 1, 2784, 0xaa880e55, S=1, 1024, 0xf351799f -0, 23, 23, 1, 2884, 0x46f546f6, S=1, 1024, 0xf351799f -0, 24, 24, 1, 2982, 0x807c7ad5, S=1, 1024, 0xf351799f -0, 25, 25, 1, 3101, 0xbcc89bec, S=1, 1024, 0xf351799f -0, 26, 26, 1, 3253, 0xd032f3fa, S=1, 1024, 0xf351799f -0, 27, 27, 1, 3329, 0xe4d42430, S=1, 1024, 0xf351799f -0, 28, 28, 1, 3572, 0xf8058aa0, S=1, 1024, 0xf351799f -0, 29, 29, 1, 3807, 0x3d2af9f3, S=1, 1024, 0xf351799f -0, 30, 30, 1, 2750, 0x814d1c33, S=1, 1024, 0xf351799f -0, 31, 31, 1, 4031, 0x3b077006, S=1, 1024, 0xf351799f -0, 32, 32, 1, 3025, 0x86729c1c, S=1, 1024, 0xf351799f -0, 33, 33, 1, 4295, 0xf71b0b38, S=1, 1024, 0xf351799f -0, 34, 34, 1, 2044, 0x5adcb93b, S=1, 1024, 0xf351799f -0, 35, 35, 1, 3212, 0xcf79eeed, S=1, 1024, 0xf351799f -0, 36, 36, 1, 2292, 0xb4386334, S=1, 1024, 0xf351799f -0, 37, 37, 1, 3633, 0x0010992f, S=1, 1024, 0xf351799f -0, 38, 38, 1, 3552, 0x23697490, S=1, 1024, 0xf351799f -0, 39, 39, 1, 3690, 0x62afdbb8, S=1, 1024, 0xf351799f -0, 40, 40, 1, 1559, 0x5baef54a, S=1, 1024, 0xf351799f -0, 41, 41, 1, 954, 0xca75ca79, S=1, 1024, 0xf351799f -0, 42, 42, 1, 273, 0x3687799b, S=1, 1024, 0xf351799f -0, 43, 43, 1, 930, 0x29f3b0c4, S=1, 1024, 0xf351799f -0, 44, 44, 1, 271, 0x305e8094, S=1, 1024, 0xf351799f -0, 45, 45, 1, 196, 0xf5ab51ee, S=1, 1024, 0xf351799f -0, 46, 46, 1, 4299, 0x67ec0d55, S=1, 1024, 0xf351799f -0, 47, 47, 1, 4895, 0xb394406c, S=1, 1024, 0xf351799f -0, 48, 48, 1, 4928, 0x233919d7, S=1, 1024, 0xf351799f -0, 49, 49, 1, 4941, 0x58a357da, S=1, 1024, 0xf351799f -0, 50, 50, 1, 4154, 0x21f2ac33, S=1, 1024, 0xf351799f -0, 51, 51, 1, 4678, 0xab3cc050, S=1, 1024, 0xf351799f -0, 52, 52, 1, 4741, 0x1974b581, S=1, 1024, 0xf351799f -0, 53, 53, 1, 4982, 0x891456d5, S=1, 1024, 0xf351799f -0, 54, 54, 1, 5179, 0x860fc6a1, S=1, 1024, 0xf351799f -0, 55, 55, 1, 5046, 0xce9183d3, S=1, 1024, 0xf351799f -0, 56, 56, 1, 5140, 0xa6d7b9af, S=1, 1024, 0xf351799f -0, 57, 57, 1, 4301, 0x03b6ef3f, S=1, 1024, 0xf351799f -0, 58, 58, 1, 5079, 0xa8d59e01, S=1, 1024, 0xf351799f -0, 59, 59, 1, 5284, 0xea34e3b3, S=1, 1024, 0xf351799f -0, 60, 60, 1, 5426, 0x556a15cd, S=1, 1024, 0xf351799f -0, 61, 61, 1, 4645, 0x061e8936, S=1, 1024, 0xf351799f -0, 62, 62, 1, 5263, 0x7536cf7d, S=1, 1024, 0xf351799f -0, 63, 63, 1, 5221, 0x9fbac3ca, S=1, 1024, 0xf351799f -0, 64, 64, 1, 5217, 0x02269bd2, S=1, 1024, 0xf351799f -0, 65, 65, 1, 5395, 0x120fff66, S=1, 1024, 0xf351799f -0, 66, 66, 1, 5220, 0x77cedcc5, S=1, 1024, 0xf351799f -0, 67, 67, 1, 5704, 0xba42dd96, S=1, 1024, 0xf351799f -0, 68, 68, 1, 5636, 0xcb91a25b, S=1, 1024, 0xf351799f -0, 69, 69, 1, 5818, 0x8dc0df92, S=1, 1024, 0xf351799f -0, 70, 70, 1, 5763, 0x51d5d5f0, S=1, 1024, 0xf351799f -0, 71, 71, 1, 6116, 0x09558b48, S=1, 1024, 0xf351799f -0, 72, 72, 1, 6069, 0x41926817, S=1, 1024, 0xf351799f -0, 73, 73, 1, 5796, 0x7fbeda44, S=1, 1024, 0xf351799f -0, 74, 74, 1, 5999, 0xe07d3770, S=1, 1024, 0xf351799f -0, 75, 75, 1, 6220, 0x6607b06f, S=1, 1024, 0xf351799f -0, 76, 76, 1, 6374, 0x7628e533, S=1, 1024, 0xf351799f -0, 77, 77, 1, 6465, 0xfe956b15, S=1, 1024, 0xf351799f -0, 78, 78, 1, 7019, 0x6c9a1aef, S=1, 1024, 0xf351799f -0, 79, 79, 1, 7255, 0x5fa5c1bf, S=1, 1024, 0xf351799f -0, 80, 80, 1, 8197, 0xf11d6ef2, S=1, 1024, 0xf351799f -0, 81, 81, 1, 8358, 0x027279e8, S=1, 1024, 0xf351799f -0, 82, 82, 1, 7708, 0x607f8e8b, S=1, 1024, 0xf351799f -0, 83, 83, 1, 7412, 0x6bb2105f, S=1, 1024, 0xf351799f -0, 84, 84, 1, 7541, 0xfdc02154, S=1, 1024, 0xf351799f -0, 85, 85, 1, 7948, 0x916ecd8b, S=1, 1024, 0xf351799f -0, 86, 86, 1, 8408, 0x1f97d414, S=1, 1024, 0xf351799f -0, 87, 87, 1, 8056, 0x9cbf159c, S=1, 1024, 0xf351799f -0, 88, 88, 1, 7401, 0x2625addb, S=1, 1024, 0xf351799f -0, 89, 89, 1, 7494, 0x2877eacb, S=1, 1024, 0xf351799f -0, 90, 90, 1, 7806, 0xe32574a3, S=1, 1024, 0xf351799f -0, 91, 91, 1, 7768, 0x25ed7ee7, S=1, 1024, 0xf351799f -0, 92, 92, 1, 7749, 0x6d8e978e, S=1, 1024, 0xf351799f -0, 93, 93, 1, 8047, 0xec4b150c, S=1, 1024, 0xf351799f -0, 94, 94, 1, 7618, 0x88cf30d5, S=1, 1024, 0xf351799f -0, 95, 95, 1, 7979, 0x0eb1cf2a, S=1, 1024, 0xf351799f -0, 96, 96, 1, 12062, 0xb49d9125, S=1, 1024, 0xf351799f -0, 97, 97, 1, 12317, 0x2d8fd6e9, S=1, 1024, 0xf351799f -0, 98, 98, 1, 12217, 0x9b3be549, S=1, 1024, 0xf351799f -0, 99, 99, 1, 11227, 0x067e9118, S=1, 1024, 0xf351799f -0, 100, 100, 1, 11108, 0x5e5b0afd, S=1, 1024, 0xf351799f -0, 101, 101, 1, 11366, 0xb38e8d15, S=1, 1024, 0xf351799f -0, 102, 102, 1, 11896, 0xeb3e35ca, S=1, 1024, 0xf351799f -0, 103, 103, 1, 11479, 0xbf7581e9, S=1, 1024, 0xf351799f -0, 104, 104, 1, 13395, 0x415b38d8, S=1, 1024, 0xf351799f -0, 105, 105, 1, 12913, 0x61544631, S=1, 1024, 0xf351799f -0, 106, 106, 1, 13864, 0xd39fe768, S=1, 1024, 0xf351799f -0, 107, 107, 1, 13551, 0x76c167d1, S=1, 1024, 0xf351799f -0, 108, 108, 1, 14041, 0x2f206888, S=1, 1024, 0xf351799f -0, 109, 109, 1, 14144, 0x9ec030d3, S=1, 1024, 0xf351799f -0, 110, 110, 1, 14277, 0xa84b3a9b, S=1, 1024, 0xf351799f -0, 111, 111, 1, 14424, 0xf5f1e06e, S=1, 1024, 0xf351799f -0, 112, 112, 1, 14689, 0xbca0adb5, S=1, 1024, 0xf351799f -0, 113, 113, 1, 14598, 0xc1d45745, S=1, 1024, 0xf351799f -0, 114, 114, 1, 15213, 0x8f3080fc, S=1, 1024, 0xf351799f -0, 115, 115, 1, 15425, 0xb0aa8f59, S=1, 1024, 0xf351799f -0, 116, 116, 1, 15595, 0x1406e5d5, S=1, 1024, 0xf351799f -0, 117, 117, 1, 15598, 0x48ec7d08, S=1, 1024, 0xf351799f -0, 118, 118, 1, 15863, 0x5381db7b, S=1, 1024, 0xf351799f -0, 119, 119, 1, 15717, 0xb87a1b87, S=1, 1024, 0xf351799f -0, 120, 120, 1, 16078, 0x5bab2453, S=1, 1024, 0xf351799f -0, 121, 121, 1, 16225, 0xa1f88113, S=1, 1024, 0xf351799f -0, 122, 122, 1, 16135, 0x6af2f4e1, S=1, 1024, 0xf351799f -0, 123, 123, 1, 16661, 0xf02a3343, S=1, 1024, 0xf351799f -0, 124, 124, 1, 16619, 0xc71935a4, S=1, 1024, 0xf351799f -0, 125, 125, 1, 16829, 0x29849844, S=1, 1024, 0xf351799f -0, 126, 126, 1, 16944, 0x3423ae77, S=1, 1024, 0xf351799f -0, 127, 127, 1, 17119, 0x609b4409, S=1, 1024, 0xf351799f -0, 128, 128, 1, 17150, 0xf85dfd31, S=1, 1024, 0xf351799f -0, 129, 129, 1, 17321, 0x38eccb10, S=1, 1024, 0xf351799f -0, 130, 130, 1, 17395, 0x0ba08b85, S=1, 1024, 0xf351799f -0, 131, 131, 1, 17666, 0x6fbc0264, S=1, 1024, 0xf351799f -0, 132, 132, 1, 17730, 0x3dcc64a6, S=1, 1024, 0xf351799f -0, 133, 133, 1, 17934, 0xb539974b, S=1, 1024, 0xf351799f -0, 134, 134, 1, 17944, 0x2214ec94, S=1, 1024, 0xf351799f -0, 135, 135, 1, 18238, 0x70f9ff1d, S=1, 1024, 0xf351799f -0, 136, 136, 1, 18391, 0x4b149209, S=1, 1024, 0xf351799f -0, 137, 137, 1, 18543, 0x45a1c02f, S=1, 1024, 0xf351799f -0, 138, 138, 1, 18939, 0x2789a88c, S=1, 1024, 0xf351799f -0, 139, 139, 1, 19145, 0x5daafd7a, S=1, 1024, 0xf351799f -0, 140, 140, 1, 19120, 0x565f80e6, S=1, 1024, 0xf351799f -0, 141, 141, 1, 19130, 0xff70cc21, S=1, 1024, 0xf351799f -0, 142, 142, 1, 19494, 0xbfa284db, S=1, 1024, 0xf351799f -0, 143, 143, 1, 19534, 0x3d40743b, S=1, 1024, 0xf351799f -0, 144, 144, 1, 19747, 0x33c9b108, S=1, 1024, 0xf351799f -0, 145, 145, 1, 20114, 0x9d223e36, S=1, 1024, 0xf351799f -0, 146, 146, 1, 20257, 0xe7bdaf43, S=1, 1024, 0xf351799f -0, 147, 147, 1, 20370, 0x0c5f1970, S=1, 1024, 0xf351799f -0, 148, 148, 1, 20292, 0x6986d20e, S=1, 1024, 0xf351799f -0, 149, 149, 1, 20491, 0xd88e4c08, S=1, 1024, 0xf351799f -0, 150, 150, 1, 20647, 0x1aefaffc, S=1, 1024, 0xf351799f -0, 151, 151, 1, 20666, 0x43e4aaaa, S=1, 1024, 0xf351799f -0, 152, 152, 1, 21007, 0xa7ca3ef0, S=1, 1024, 0xf351799f -0, 153, 153, 1, 21058, 0x06814351, S=1, 1024, 0xf351799f -0, 154, 154, 1, 21153, 0x3c852b10, S=1, 1024, 0xf351799f -0, 155, 155, 1, 21078, 0x8df15855, S=1, 1024, 0xf351799f -0, 156, 156, 1, 21458, 0xd3a531d6, S=1, 1024, 0xf351799f -0, 157, 157, 1, 21669, 0x88baca53, S=1, 1024, 0xf351799f -0, 158, 158, 1, 21581, 0xd692fa1f, S=1, 1024, 0xf351799f -0, 159, 159, 1, 21654, 0x30fb9061, S=1, 1024, 0xf351799f -0, 160, 160, 1, 21987, 0xe7646d8b, S=1, 1024, 0xf351799f -0, 161, 161, 1, 22205, 0x0fc55b6a, S=1, 1024, 0xf351799f -0, 162, 162, 1, 22475, 0x4bc4c032, S=1, 1024, 0xf351799f -0, 163, 163, 1, 22490, 0x58ca23f6, S=1, 1024, 0xf351799f -0, 164, 164, 1, 22460, 0xf9ceb0ac, S=1, 1024, 0xf351799f -0, 165, 165, 1, 22861, 0xb05f0f84, S=1, 1024, 0xf351799f -0, 166, 166, 1, 22746, 0x0df23a5c, S=1, 1024, 0xf351799f -0, 167, 167, 1, 23165, 0xbd7147ad, S=1, 1024, 0xf351799f -0, 168, 168, 1, 23273, 0x9781a34f, S=1, 1024, 0xf351799f -0, 169, 169, 1, 23211, 0x69c7606b, S=1, 1024, 0xf351799f -0, 170, 170, 1, 23648, 0xdafde037, S=1, 1024, 0xf351799f -0, 171, 171, 1, 23675, 0x2a2147ed, S=1, 1024, 0xf351799f -0, 172, 172, 1, 23874, 0x12c184b6, S=1, 1024, 0xf351799f +0, 0, 0, 1, 1341, 0xe4e2af18 +0, 1, 1, 1, 305, 0xefa98bbd, F=0x0 +0, 2, 2, 1, 446, 0x9499cf43, F=0x0 +0, 3, 3, 1, 458, 0x8cb7d0d5, F=0x0 +0, 4, 4, 1, 555, 0x41f2fe63, F=0x0 +0, 5, 5, 1, 622, 0x3651212e, F=0x0 +0, 6, 6, 1, 650, 0x67542087, F=0x0 +0, 7, 7, 1, 668, 0x392934ca, F=0x0 +0, 8, 8, 1, 829, 0x6cd07a33, F=0x0 +0, 9, 9, 1, 1165, 0xb64b2ec9, F=0x0 +0, 10, 10, 1, 187, 0x114a52a4, F=0x0 +0, 11, 11, 1, 1341, 0x6ca57064, F=0x0 +0, 12, 12, 1, 1646, 0xcdd90fae, F=0x0 +0, 13, 13, 1, 1539, 0xbf75e55f, F=0x0 +0, 14, 14, 1, 1728, 0x96b14714, F=0x0 +0, 15, 15, 1, 1918, 0xffd08446, F=0x0 +0, 16, 16, 1, 2132, 0x3d5ae258, F=0x0 +0, 17, 17, 1, 2256, 0x359526d9, F=0x0 +0, 18, 18, 1, 2319, 0x553c382b, F=0x0 +0, 19, 19, 1, 2416, 0x7ac37066, F=0x0 +0, 20, 20, 1, 2609, 0x552bc27f, F=0x0 +0, 21, 21, 1, 2695, 0xbb0c020e, F=0x0 +0, 22, 22, 1, 2792, 0x46670f7d, F=0x0 +0, 23, 23, 1, 2892, 0x5674481e, F=0x0 +0, 24, 24, 1, 2990, 0x015a7bfd, F=0x0 +0, 25, 25, 1, 3109, 0xc73e9d14, F=0x0 +0, 26, 26, 1, 3261, 0x8a77f522, F=0x0 +0, 27, 27, 1, 3337, 0xf6f92558, F=0x0 +0, 28, 28, 1, 3580, 0x23408bc8, F=0x0 +0, 29, 29, 1, 3815, 0x781dfb1b, F=0x0 +0, 30, 30, 1, 2758, 0xf5cd1d5b, F=0x0 +0, 31, 31, 1, 4039, 0x7909712e, F=0x0 +0, 32, 32, 1, 3033, 0x39089d44, F=0x0 +0, 33, 33, 1, 4303, 0x667b0c60, F=0x0 +0, 34, 34, 1, 2052, 0x9edfba63, F=0x0 +0, 35, 35, 1, 3220, 0x5a56f015, F=0x0 +0, 36, 36, 1, 2300, 0x1719645c, F=0x0 +0, 37, 37, 1, 3641, 0x71c49a57, F=0x0 +0, 38, 38, 1, 3560, 0x377575b8, F=0x0 +0, 39, 39, 1, 3698, 0x165adce0, F=0x0 +0, 40, 40, 1, 1567, 0x6ecbf672, F=0x0 +0, 41, 41, 1, 962, 0x21eccba1, F=0x0 +0, 42, 42, 1, 281, 0x7a5a7ac3, F=0x0 +0, 43, 43, 1, 938, 0x659bb1ec, F=0x0 +0, 44, 44, 1, 279, 0x71e181bc, F=0x0 +0, 45, 45, 1, 204, 0xe0765316, F=0x0 +0, 46, 46, 1, 4307, 0xdbdd0e7d, F=0x0 +0, 47, 47, 1, 4903, 0xd8d24194, F=0x0 +0, 48, 48, 1, 4936, 0x6e9f1aff, F=0x0 +0, 49, 49, 1, 4949, 0xb3115902, F=0x0 +0, 50, 50, 1, 4162, 0xee2cad5b, F=0x0 +0, 51, 51, 1, 4686, 0xd583c178, F=0x0 +0, 52, 52, 1, 4749, 0x8c93b6a9, F=0x0 +0, 53, 53, 1, 4990, 0x12f957fd, F=0x0 +0, 54, 54, 1, 5187, 0xf3bcc7c9, F=0x0 +0, 55, 55, 1, 5054, 0xa27684fb, F=0x0 +0, 56, 56, 1, 5148, 0xe76cbad7, F=0x0 +0, 57, 57, 1, 4309, 0x79f7f067, F=0x0 +0, 58, 58, 1, 5087, 0xa2e29f29, F=0x0 +0, 59, 59, 1, 5292, 0xd158e4db, F=0x0 +0, 60, 60, 1, 5434, 0xe0be16f5, F=0x0 +0, 61, 61, 1, 4653, 0x0a3d8a5e, F=0x0 +0, 62, 62, 1, 5271, 0x4412d0a5, F=0x0 +0, 63, 63, 1, 5229, 0x3e06c4f2, F=0x0 +0, 64, 64, 1, 5225, 0x9bc39cfa, F=0x0 +0, 65, 65, 1, 5403, 0x798b009d, F=0x0 +0, 66, 66, 1, 5228, 0x14f2dded, F=0x0 +0, 67, 67, 1, 5712, 0x8724debe, F=0x0 +0, 68, 68, 1, 5644, 0x49d3a383, F=0x0 +0, 69, 69, 1, 5826, 0xde72e0ba, F=0x0 +0, 70, 70, 1, 5771, 0x62efd718, F=0x0 +0, 71, 71, 1, 6124, 0xb2a68c70, F=0x0 +0, 72, 72, 1, 6077, 0xb48b693f, F=0x0 +0, 73, 73, 1, 5804, 0xb700db6c, F=0x0 +0, 74, 74, 1, 6007, 0x02953898, F=0x0 +0, 75, 75, 1, 6228, 0x87a7b197, F=0x0 +0, 76, 76, 1, 6382, 0x49e7e65b, F=0x0 +0, 77, 77, 1, 6473, 0x3b9b6c3d, F=0x0 +0, 78, 78, 1, 7027, 0x2a4e1c17, F=0x0 +0, 79, 79, 1, 7263, 0x2e48c2e7, F=0x0 +0, 80, 80, 1, 8205, 0x013b701a, F=0x0 +0, 81, 81, 1, 8366, 0xcca97b10, F=0x0 +0, 82, 82, 1, 7716, 0x3b088fb3, F=0x0 +0, 83, 83, 1, 7420, 0xefdd1187, F=0x0 +0, 84, 84, 1, 7549, 0x1731227c, F=0x0 +0, 85, 85, 1, 7956, 0x8186ceb3, F=0x0 +0, 86, 86, 1, 8416, 0x23add53c, F=0x0 +0, 87, 87, 1, 8064, 0x09c616c4, F=0x0 +0, 88, 88, 1, 7409, 0x9d98af03, F=0x0 +0, 89, 89, 1, 7502, 0x0b81ebf3, F=0x0 +0, 90, 90, 1, 7814, 0x2f0d75cb, F=0x0 +0, 91, 91, 1, 7776, 0x45d6800f, F=0x0 +0, 92, 92, 1, 7757, 0x777f98b6, F=0x0 +0, 93, 93, 1, 8055, 0x4eea1634, F=0x0 +0, 94, 94, 1, 7626, 0xfb3931fd, F=0x0 +0, 95, 95, 1, 7987, 0x22a1d052, F=0x0 +0, 96, 96, 1, 12070, 0x3aa2924d, F=0x0 +0, 97, 97, 1, 12325, 0xda6cd811, F=0x0 +0, 98, 98, 1, 12225, 0xd478e671, F=0x0 +0, 99, 99, 1, 11235, 0xc6c09240, F=0x0 +0, 100, 100, 1, 11116, 0x95050c25, F=0x0 +0, 101, 101, 1, 11374, 0x14a68e3d, F=0x0 +0, 102, 102, 1, 11904, 0xb14436f2, F=0x0 +0, 103, 103, 1, 11487, 0xa3358311, F=0x0 +0, 104, 104, 1, 13403, 0xccf33a00, F=0x0 +0, 105, 105, 1, 12921, 0xbf7e4759, F=0x0 +0, 106, 106, 1, 13872, 0x7dace890, F=0x0 +0, 107, 107, 1, 13559, 0xb6c868f9, F=0x0 +0, 108, 108, 1, 14049, 0xa5d569b0, F=0x0 +0, 109, 109, 1, 14152, 0x8c9c31fb, F=0x0 +0, 110, 110, 1, 14285, 0x2ffe3bc3, F=0x0 +0, 111, 111, 1, 14432, 0x27abe196, F=0x0 +0, 112, 112, 1, 14697, 0x20d1aedd, F=0x0 +0, 113, 113, 1, 14606, 0xbcbe586d, F=0x0 +0, 114, 114, 1, 15221, 0x515f8224, F=0x0 +0, 115, 115, 1, 15433, 0x68089081, F=0x0 +0, 116, 116, 1, 15603, 0x8ff4e6fd, F=0x0 +0, 117, 117, 1, 15606, 0xc8527e30, F=0x0 +0, 118, 118, 1, 15871, 0x056ddca3, F=0x0 +0, 119, 119, 1, 15725, 0xc1871caf, F=0x0 +0, 120, 120, 1, 16086, 0x063e257b, F=0x0 +0, 121, 121, 1, 16233, 0xf683823b, F=0x0 +0, 122, 122, 1, 16143, 0x576df609, F=0x0 +0, 123, 123, 1, 16669, 0x3d02346b, F=0x0 +0, 124, 124, 1, 16627, 0xe35236cc, F=0x0 +0, 125, 125, 1, 16837, 0x389c996c, F=0x0 +0, 126, 126, 1, 16952, 0xc833af9f, F=0x0 +0, 127, 127, 1, 17127, 0xbf124531, F=0x0 +0, 128, 128, 1, 17158, 0x7abbfe59, F=0x0 +0, 129, 129, 1, 17329, 0x8102cc38, F=0x0 +0, 130, 130, 1, 17403, 0xa9468cad, F=0x0 +0, 131, 131, 1, 17674, 0x46d8038c, F=0x0 +0, 132, 132, 1, 17738, 0x5ee865ce, F=0x0 +0, 133, 133, 1, 17942, 0xc2449873, F=0x0 +0, 134, 134, 1, 17952, 0x3aafedbc, F=0x0 +0, 135, 135, 1, 18246, 0xdd930054, F=0x0 +0, 136, 136, 1, 18399, 0x68a59331, F=0x0 +0, 137, 137, 1, 18551, 0x1301c157, F=0x0 +0, 138, 138, 1, 18947, 0xbed8a9b4, F=0x0 +0, 139, 139, 1, 19153, 0xe338fea2, F=0x0 +0, 140, 140, 1, 19128, 0xbf05820e, F=0x0 +0, 141, 141, 1, 19138, 0x73b5cd49, F=0x0 +0, 142, 142, 1, 19502, 0xd8d68603, F=0x0 +0, 143, 143, 1, 19542, 0x84b47563, F=0x0 +0, 144, 144, 1, 19755, 0x7194b230, F=0x0 +0, 145, 145, 1, 20122, 0x83633f5e, F=0x0 +0, 146, 146, 1, 20265, 0x7365b06b, F=0x0 +0, 147, 147, 1, 20378, 0x1aaf1a98, F=0x0 +0, 148, 148, 1, 20300, 0x1da6d336, F=0x0 +0, 149, 149, 1, 20499, 0x72d54d30, F=0x0 +0, 150, 150, 1, 20655, 0x6996b124, F=0x0 +0, 151, 151, 1, 20674, 0xa883abd2, F=0x0 +0, 152, 152, 1, 21015, 0x96cf4018, F=0x0 +0, 153, 153, 1, 21066, 0x307e4479, F=0x0 +0, 154, 154, 1, 21161, 0xd45a2c38, F=0x0 +0, 155, 155, 1, 21086, 0xcf0e597d, F=0x0 +0, 156, 156, 1, 21466, 0xcc4032fe, F=0x0 +0, 157, 157, 1, 21677, 0x755ccb7b, F=0x0 +0, 158, 158, 1, 21589, 0x5d74fb47, F=0x0 +0, 159, 159, 1, 21662, 0x0c459189, F=0x0 +0, 160, 160, 1, 21995, 0x43d46eb3, F=0x0 +0, 161, 161, 1, 22213, 0x68455c92, F=0x0 +0, 162, 162, 1, 22483, 0xdc83c15a, F=0x0 +0, 163, 163, 1, 22498, 0xfae1251e, F=0x0 +0, 164, 164, 1, 22468, 0x7944b1d4, F=0x0 +0, 165, 165, 1, 22869, 0xff8c10ac, F=0x0 +0, 166, 166, 1, 22754, 0xd8183b84, F=0x0 +0, 167, 167, 1, 23173, 0x6c3c48d5, F=0x0 +0, 168, 168, 1, 23281, 0xc32ca477, F=0x0 +0, 169, 169, 1, 23219, 0x4dc26193, F=0x0 +0, 170, 170, 1, 23656, 0xb85ee15f, F=0x0 +0, 171, 171, 1, 23683, 0x26ba4915, F=0x0 +0, 172, 172, 1, 23882, 0xf57285de, F=0x0 diff --git a/tests/ref/fate/gifenc-gray b/tests/ref/fate/gifenc-gray index 81cdd1888..324aff49b 100644 --- a/tests/ref/fate/gifenc-gray +++ b/tests/ref/fate/gifenc-gray @@ -3,176 +3,176 @@ #codec_id 0: gif #dimensions 0: 217x217 #sar 0: 0/1 -0, 0, 0, 1, 579, 0x0d0e3ab8 -0, 1, 1, 1, 150, 0x178b3a8c, S=1, 1024, 0xc2f67c9f -0, 2, 2, 1, 155, 0x941743f5, S=1, 1024, 0xc2f67c9f -0, 3, 3, 1, 144, 0x68c73711, S=1, 1024, 0xc2f67c9f -0, 4, 4, 1, 152, 0xaf9a3f2e, S=1, 1024, 0xc2f67c9f -0, 5, 5, 1, 136, 0x68593d85, S=1, 1024, 0xc2f67c9f -0, 6, 6, 1, 134, 0x0dcb373f, S=1, 1024, 0xc2f67c9f -0, 7, 7, 1, 129, 0x3baf3279, S=1, 1024, 0xc2f67c9f -0, 8, 8, 1, 123, 0x9c963148, S=1, 1024, 0xc2f67c9f -0, 9, 9, 1, 123, 0x5c272d6b, S=1, 1024, 0xc2f67c9f -0, 10, 10, 1, 150, 0x5f8d41aa, S=1, 1024, 0xc2f67c9f -0, 11, 11, 1, 134, 0x6f582fee, S=1, 1024, 0xc2f67c9f -0, 12, 12, 1, 134, 0x85d53038, S=1, 1024, 0xc2f67c9f -0, 13, 13, 1, 123, 0x6d2a2cb2, S=1, 1024, 0xc2f67c9f -0, 14, 14, 1, 127, 0x1e78327b, S=1, 1024, 0xc2f67c9f -0, 15, 15, 1, 119, 0xbafc2c31, S=1, 1024, 0xc2f67c9f -0, 16, 16, 1, 138, 0x57553638, S=1, 1024, 0xc2f67c9f -0, 17, 17, 1, 140, 0xf7423adb, S=1, 1024, 0xc2f67c9f -0, 18, 18, 1, 122, 0x7e592f8b, S=1, 1024, 0xc2f67c9f -0, 19, 19, 1, 123, 0xaa7d313c, S=1, 1024, 0xc2f67c9f -0, 20, 20, 1, 140, 0x4fd63b34, S=1, 1024, 0xc2f67c9f -0, 21, 21, 1, 123, 0x67753163, S=1, 1024, 0xc2f67c9f -0, 22, 22, 1, 123, 0x02193147, S=1, 1024, 0xc2f67c9f -0, 23, 23, 1, 124, 0xa85131e9, S=1, 1024, 0xc2f67c9f -0, 24, 24, 1, 122, 0xef8731e2, S=1, 1024, 0xc2f67c9f -0, 25, 25, 1, 122, 0x06d432c9, S=1, 1024, 0xc2f67c9f -0, 26, 26, 1, 123, 0xcc8831cd, S=1, 1024, 0xc2f67c9f -0, 27, 27, 1, 118, 0xa1d33166, S=1, 1024, 0xc2f67c9f -0, 28, 28, 1, 159, 0xcc8c454c, S=1, 1024, 0xc2f67c9f -0, 29, 29, 1, 140, 0x8a0231ad, S=1, 1024, 0xc2f67c9f -0, 30, 30, 1, 163, 0xe78248d2, S=1, 1024, 0xc2f67c9f -0, 31, 31, 1, 142, 0x3b293489, S=1, 1024, 0xc2f67c9f -0, 32, 32, 1, 170, 0x5f504b12, S=1, 1024, 0xc2f67c9f -0, 33, 33, 1, 146, 0x38a53693, S=1, 1024, 0xc2f67c9f -0, 34, 34, 1, 132, 0xb18a3499, S=1, 1024, 0xc2f67c9f -0, 35, 35, 1, 113, 0x55182bda, S=1, 1024, 0xc2f67c9f -0, 36, 36, 1, 132, 0xaced3333, S=1, 1024, 0xc2f67c9f -0, 37, 37, 1, 120, 0x9ffe2e4f, S=1, 1024, 0xc2f67c9f -0, 38, 38, 1, 135, 0x6223351e, S=1, 1024, 0xc2f67c9f -0, 39, 39, 1, 123, 0x269b3058, S=1, 1024, 0xc2f67c9f -0, 40, 40, 1, 119, 0x17052def, S=1, 1024, 0xc2f67c9f -0, 41, 41, 1, 119, 0x36da2ee2, S=1, 1024, 0xc2f67c9f -0, 42, 42, 1, 120, 0x984e31be, S=1, 1024, 0xc2f67c9f -0, 43, 43, 1, 114, 0xfd382c9d, S=1, 1024, 0xc2f67c9f -0, 44, 44, 1, 125, 0x926a36c6, S=1, 1024, 0xc2f67c9f -0, 45, 45, 1, 117, 0xbceb3183, S=1, 1024, 0xc2f67c9f -0, 46, 46, 1, 116, 0xf4c72d82, S=1, 1024, 0xc2f67c9f -0, 47, 47, 1, 124, 0x0c19343c, S=1, 1024, 0xc2f67c9f -0, 48, 48, 1, 117, 0x1f032eb1, S=1, 1024, 0xc2f67c9f -0, 49, 49, 1, 135, 0x31a437e6, S=1, 1024, 0xc2f67c9f -0, 50, 50, 1, 131, 0x4c1735fe, S=1, 1024, 0xc2f67c9f -0, 51, 51, 1, 122, 0xb7603463, S=1, 1024, 0xc2f67c9f -0, 52, 52, 1, 122, 0x7f5e34e1, S=1, 1024, 0xc2f67c9f -0, 53, 53, 1, 124, 0x9562350f, S=1, 1024, 0xc2f67c9f -0, 54, 54, 1, 126, 0x18b33759, S=1, 1024, 0xc2f67c9f -0, 55, 55, 1, 117, 0x748f3243, S=1, 1024, 0xc2f67c9f -0, 56, 56, 1, 109, 0x72832fe7, S=1, 1024, 0xc2f67c9f -0, 57, 57, 1, 120, 0x748a2e38, S=1, 1024, 0xc2f67c9f -0, 58, 58, 1, 120, 0x61f82fb2, S=1, 1024, 0xc2f67c9f -0, 59, 59, 1, 122, 0x2a6b3282, S=1, 1024, 0xc2f67c9f -0, 60, 60, 1, 116, 0x8b542de6, S=1, 1024, 0xc2f67c9f -0, 61, 61, 1, 119, 0xf33c318e, S=1, 1024, 0xc2f67c9f -0, 62, 62, 1, 116, 0xff182f36, S=1, 1024, 0xc2f67c9f -0, 63, 63, 1, 119, 0xeb9e2fcc, S=1, 1024, 0xc2f67c9f -0, 64, 64, 1, 118, 0xe82d304e, S=1, 1024, 0xc2f67c9f -0, 65, 65, 1, 137, 0x98303d30, S=1, 1024, 0xc2f67c9f -0, 66, 66, 1, 149, 0x01123fff, S=1, 1024, 0xc2f67c9f -0, 67, 67, 1, 115, 0x4ca92f75, S=1, 1024, 0xc2f67c9f -0, 68, 68, 1, 131, 0xf4193bc0, S=1, 1024, 0xc2f67c9f -0, 69, 69, 1, 115, 0xda5e2f30, S=1, 1024, 0xc2f67c9f -0, 70, 70, 1, 100, 0x9ba32a58, S=1, 1024, 0xc2f67c9f -0, 71, 71, 1, 109, 0xa47e2c91, S=1, 1024, 0xc2f67c9f -0, 72, 72, 1, 120, 0x22452fd6, S=1, 1024, 0xc2f67c9f -0, 73, 73, 1, 116, 0xd3c52c26, S=1, 1024, 0xc2f67c9f -0, 74, 74, 1, 106, 0x95b42c9f, S=1, 1024, 0xc2f67c9f -0, 75, 75, 1, 96, 0xfdc12639, S=1, 1024, 0xc2f67c9f -0, 76, 76, 1, 99, 0x210f251b, S=1, 1024, 0xc2f67c9f -0, 77, 77, 1, 119, 0x173b341c, S=1, 1024, 0xc2f67c9f -0, 78, 78, 1, 119, 0x3bca2f29, S=1, 1024, 0xc2f67c9f -0, 79, 79, 1, 213, 0x9e905d4c, S=1, 1024, 0xc2f67c9f -0, 80, 80, 1, 209, 0xa0015e94, S=1, 1024, 0xc2f67c9f -0, 81, 81, 1, 120, 0x36762bd4, S=1, 1024, 0xc2f67c9f -0, 82, 82, 1, 119, 0x019b2edc, S=1, 1024, 0xc2f67c9f -0, 83, 83, 1, 124, 0x211d30e7, S=1, 1024, 0xc2f67c9f -0, 84, 84, 1, 125, 0x538732ff, S=1, 1024, 0xc2f67c9f -0, 85, 85, 1, 123, 0x2887308a, S=1, 1024, 0xc2f67c9f -0, 86, 86, 1, 119, 0x7ff930f4, S=1, 1024, 0xc2f67c9f -0, 87, 87, 1, 119, 0xa50c2e16, S=1, 1024, 0xc2f67c9f -0, 88, 88, 1, 107, 0x9ed02cea, S=1, 1024, 0xc2f67c9f -0, 89, 89, 1, 119, 0xc234332a, S=1, 1024, 0xc2f67c9f -0, 90, 90, 1, 115, 0x38353092, S=1, 1024, 0xc2f67c9f -0, 91, 91, 1, 162, 0x6cda4644, S=1, 1024, 0xc2f67c9f -0, 92, 92, 1, 124, 0x2f683081, S=1, 1024, 0xc2f67c9f -0, 93, 93, 1, 116, 0x72952d04, S=1, 1024, 0xc2f67c9f -0, 94, 94, 1, 84, 0x1a532301, S=1, 1024, 0xc2f67c9f -0, 95, 95, 1, 176, 0xfb3c5400, S=1, 1024, 0xc2f67c9f -0, 96, 96, 1, 137, 0x253132d1, S=1, 1024, 0xc2f67c9f -0, 97, 97, 1, 179, 0x2b38528b, S=1, 1024, 0xc2f67c9f -0, 98, 98, 1, 150, 0xbe413cbe, S=1, 1024, 0xc2f67c9f -0, 99, 99, 1, 140, 0x9e93392a, S=1, 1024, 0xc2f67c9f -0, 100, 100, 1, 129, 0x577e331e, S=1, 1024, 0xc2f67c9f -0, 101, 101, 1, 146, 0x16ff3924, S=1, 1024, 0xc2f67c9f -0, 102, 102, 1, 133, 0x756a3163, S=1, 1024, 0xc2f67c9f -0, 103, 103, 1, 190, 0x3e865b77, S=1, 1024, 0xc2f67c9f -0, 104, 104, 1, 159, 0xdf393fc8, S=1, 1024, 0xc2f67c9f -0, 105, 105, 1, 188, 0x84be5168, S=1, 1024, 0xc2f67c9f -0, 106, 106, 1, 163, 0x4c0e41f0, S=1, 1024, 0xc2f67c9f -0, 107, 107, 1, 144, 0x5fda3792, S=1, 1024, 0xc2f67c9f -0, 108, 108, 1, 136, 0x028c3800, S=1, 1024, 0xc2f67c9f -0, 109, 109, 1, 150, 0x75d43a8d, S=1, 1024, 0xc2f67c9f -0, 110, 110, 1, 134, 0x81123999, S=1, 1024, 0xc2f67c9f -0, 111, 111, 1, 198, 0x0a875baa, S=1, 1024, 0xc2f67c9f -0, 112, 112, 1, 169, 0xfdd7458c, S=1, 1024, 0xc2f67c9f -0, 113, 113, 1, 210, 0x9b195be4, S=1, 1024, 0xc2f67c9f -0, 114, 114, 1, 174, 0x0a424a76, S=1, 1024, 0xc2f67c9f -0, 115, 115, 1, 137, 0xb1b535fd, S=1, 1024, 0xc2f67c9f -0, 116, 116, 1, 122, 0x4d3f327b, S=1, 1024, 0xc2f67c9f -0, 117, 117, 1, 152, 0x5e423b0c, S=1, 1024, 0xc2f67c9f -0, 118, 118, 1, 137, 0xd13a39f7, S=1, 1024, 0xc2f67c9f -0, 119, 119, 1, 156, 0x40864321, S=1, 1024, 0xc2f67c9f -0, 120, 120, 1, 140, 0xbe1e393c, S=1, 1024, 0xc2f67c9f -0, 121, 121, 1, 179, 0xaf204635, S=1, 1024, 0xc2f67c9f -0, 122, 122, 1, 116, 0x5ac83123, S=1, 1024, 0xc2f67c9f -0, 123, 123, 1, 118, 0x22bc2ec5, S=1, 1024, 0xc2f67c9f -0, 124, 124, 1, 123, 0xc9b5302d, S=1, 1024, 0xc2f67c9f -0, 125, 125, 1, 125, 0x5cee3077, S=1, 1024, 0xc2f67c9f -0, 126, 126, 1, 194, 0xccc159ca, S=1, 1024, 0xc2f67c9f -0, 127, 127, 1, 122, 0x4d243229, S=1, 1024, 0xc2f67c9f -0, 128, 128, 1, 124, 0x948f330b, S=1, 1024, 0xc2f67c9f -0, 129, 129, 1, 133, 0xd53c35ca, S=1, 1024, 0xc2f67c9f -0, 130, 130, 1, 126, 0xc5543710, S=1, 1024, 0xc2f67c9f -0, 131, 131, 1, 208, 0x6cf15ea2, S=1, 1024, 0xc2f67c9f -0, 132, 132, 1, 131, 0xa8d33505, S=1, 1024, 0xc2f67c9f -0, 133, 133, 1, 114, 0x0ae53001, S=1, 1024, 0xc2f67c9f -0, 134, 134, 1, 129, 0xe9ff37c4, S=1, 1024, 0xc2f67c9f -0, 135, 135, 1, 120, 0x02623359, S=1, 1024, 0xc2f67c9f -0, 136, 136, 1, 164, 0x9dc545e5, S=1, 1024, 0xc2f67c9f -0, 137, 137, 1, 245, 0xc170715a, S=1, 1024, 0xc2f67c9f -0, 138, 138, 1, 215, 0xc93d5fbe, S=1, 1024, 0xc2f67c9f -0, 139, 139, 1, 225, 0x14866349, S=1, 1024, 0xc2f67c9f -0, 140, 140, 1, 123, 0x70cd2b64, S=1, 1024, 0xc2f67c9f -0, 141, 141, 1, 124, 0xe9002fb5, S=1, 1024, 0xc2f67c9f -0, 142, 142, 1, 125, 0x106e309b, S=1, 1024, 0xc2f67c9f -0, 143, 143, 1, 122, 0x050e32b0, S=1, 1024, 0xc2f67c9f -0, 144, 144, 1, 224, 0xf548614f, S=1, 1024, 0xc2f67c9f -0, 145, 145, 1, 239, 0x125c6ade, S=1, 1024, 0xc2f67c9f -0, 146, 146, 1, 127, 0x398734b6, S=1, 1024, 0xc2f67c9f -0, 147, 147, 1, 126, 0x2ff431e5, S=1, 1024, 0xc2f67c9f -0, 148, 148, 1, 124, 0x9583313b, S=1, 1024, 0xc2f67c9f -0, 149, 149, 1, 126, 0xc1fc3692, S=1, 1024, 0xc2f67c9f -0, 150, 150, 1, 123, 0xd0bf3170, S=1, 1024, 0xc2f67c9f -0, 151, 151, 1, 117, 0x651f3032, S=1, 1024, 0xc2f67c9f -0, 152, 152, 1, 119, 0x268a3078, S=1, 1024, 0xc2f67c9f -0, 153, 153, 1, 117, 0x9e4d3283, S=1, 1024, 0xc2f67c9f -0, 154, 154, 1, 149, 0x8f1043ba, S=1, 1024, 0xc2f67c9f -0, 155, 155, 1, 127, 0x352338bc, S=1, 1024, 0xc2f67c9f -0, 156, 156, 1, 113, 0xf877314e, S=1, 1024, 0xc2f67c9f -0, 157, 157, 1, 128, 0x88103a62, S=1, 1024, 0xc2f67c9f -0, 158, 158, 1, 111, 0xbf0630d9, S=1, 1024, 0xc2f67c9f -0, 159, 159, 1, 146, 0x159c44f7, S=1, 1024, 0xc2f67c9f -0, 160, 160, 1, 237, 0x4e45662e, S=1, 1024, 0xc2f67c9f -0, 161, 161, 1, 233, 0x8f9e6354, S=1, 1024, 0xc2f67c9f -0, 162, 162, 1, 160, 0x9c3f431f, S=1, 1024, 0xc2f67c9f -0, 163, 163, 1, 125, 0xbd2b33c6, S=1, 1024, 0xc2f67c9f -0, 164, 164, 1, 131, 0x3ecd3ba5, S=1, 1024, 0xc2f67c9f -0, 165, 165, 1, 231, 0xdf286db6, S=1, 1024, 0xc2f67c9f -0, 166, 166, 1, 153, 0xb6da408d, S=1, 1024, 0xc2f67c9f -0, 167, 167, 1, 126, 0x6741365e, S=1, 1024, 0xc2f67c9f -0, 168, 168, 1, 113, 0x658f2c90, S=1, 1024, 0xc2f67c9f -0, 169, 169, 1, 125, 0xc0033320, S=1, 1024, 0xc2f67c9f -0, 170, 170, 1, 122, 0xe38a2db1, S=1, 1024, 0xc2f67c9f -0, 171, 171, 1, 145, 0x29d63e83, S=1, 1024, 0xc2f67c9f -0, 172, 172, 1, 171, 0xc0e44b70, S=1, 1024, 0xc2f67c9f +0, 0, 0, 1, 1368, 0x6cf0befd +0, 1, 1, 1, 158, 0xcd173bb4, F=0x0 +0, 2, 2, 1, 163, 0x4f7a451d, F=0x0 +0, 3, 3, 1, 152, 0x17723839, F=0x0 +0, 4, 4, 1, 160, 0x67854056, F=0x0 +0, 5, 5, 1, 144, 0x0dc43ead, F=0x0 +0, 6, 6, 1, 142, 0xb0d73867, F=0x0 +0, 7, 7, 1, 137, 0xd8f333a1, F=0x0 +0, 8, 8, 1, 131, 0x32f93270, F=0x0 +0, 9, 9, 1, 131, 0xf27b2e93, F=0x0 +0, 10, 10, 1, 158, 0x152842d2, F=0x0 +0, 11, 11, 1, 142, 0x12733116, F=0x0 +0, 12, 12, 1, 142, 0x28f03160, F=0x0 +0, 13, 13, 1, 131, 0x038d2dda, F=0x0 +0, 14, 14, 1, 135, 0xb96c33a3, F=0x0 +0, 15, 15, 1, 127, 0x4cbf2d59, F=0x0 +0, 16, 16, 1, 146, 0xff013760, F=0x0 +0, 17, 17, 1, 148, 0xa14d3c03, F=0x0 +0, 18, 18, 1, 130, 0x139430b3, F=0x0 +0, 19, 19, 1, 131, 0x40e03264, F=0x0 +0, 20, 20, 1, 148, 0xf9d23c5c, F=0x0 +0, 21, 21, 1, 131, 0xfdc9328b, F=0x0 +0, 22, 22, 1, 131, 0x986d326f, F=0x0 +0, 23, 23, 1, 132, 0x3fdc3311, F=0x0 +0, 24, 24, 1, 130, 0x84c2330a, F=0x0 +0, 25, 25, 1, 130, 0x9c0033f1, F=0x0 +0, 26, 26, 1, 131, 0x62eb32f5, F=0x0 +0, 27, 27, 1, 126, 0x326e328e, F=0x0 +0, 28, 28, 1, 167, 0x8c8f4674, F=0x0 +0, 29, 29, 1, 148, 0x340d32d5, F=0x0 +0, 30, 30, 1, 171, 0xac2549fa, F=0x0 +0, 31, 31, 1, 150, 0xe77535b1, F=0x0 +0, 32, 32, 1, 178, 0x2c0b4c3a, F=0x0 +0, 33, 33, 1, 154, 0xe99137bb, F=0x0 +0, 34, 34, 1, 140, 0x525535c1, F=0x0 +0, 35, 35, 1, 121, 0xdfdc2d02, F=0x0 +0, 36, 36, 1, 140, 0x4db8345b, F=0x0 +0, 37, 37, 1, 128, 0x32e92f77, F=0x0 +0, 38, 38, 1, 143, 0x06663646, F=0x0 +0, 39, 39, 1, 131, 0xbcef3180, F=0x0 +0, 40, 40, 1, 127, 0xa8b92f17, F=0x0 +0, 41, 41, 1, 127, 0xc88e300a, F=0x0 +0, 42, 42, 1, 128, 0x2b3932e6, F=0x0 +0, 43, 43, 1, 122, 0x89332dc5, F=0x0 +0, 44, 44, 1, 133, 0x2b1d37ee, F=0x0 +0, 45, 45, 1, 125, 0x4c5e32ab, F=0x0 +0, 46, 46, 1, 124, 0x83122eaa, F=0x0 +0, 47, 47, 1, 132, 0xa3953564, F=0x0 +0, 48, 48, 1, 125, 0xae672fd9, F=0x0 +0, 49, 49, 1, 143, 0xd5d8390e, F=0x0 +0, 50, 50, 1, 139, 0xebab3726, F=0x0 +0, 51, 51, 1, 130, 0x4c9b358b, F=0x0 +0, 52, 52, 1, 130, 0x14993609, F=0x0 +0, 53, 53, 1, 132, 0x2ced3637, F=0x0 +0, 54, 54, 1, 134, 0xb27f3881, F=0x0 +0, 55, 55, 1, 125, 0x0402336b, F=0x0 +0, 56, 56, 1, 117, 0xf8a7310f, F=0x0 +0, 57, 57, 1, 128, 0x07752f60, F=0x0 +0, 58, 58, 1, 128, 0xf4d430da, F=0x0 +0, 59, 59, 1, 130, 0xbf9733aa, F=0x0 +0, 60, 60, 1, 124, 0x199f2f0e, F=0x0 +0, 61, 61, 1, 127, 0x84ff32b6, F=0x0 +0, 62, 62, 1, 124, 0x8d63305e, F=0x0 +0, 63, 63, 1, 127, 0x7d6130f4, F=0x0 +0, 64, 64, 1, 126, 0x78c83176, F=0x0 +0, 65, 65, 1, 145, 0x3ec33e58, F=0x0 +0, 66, 66, 1, 157, 0xb5764127, F=0x0 +0, 67, 67, 1, 123, 0xd9bd309d, F=0x0 +0, 68, 68, 1, 139, 0x93bc3ce8, F=0x0 +0, 69, 69, 1, 123, 0x67813058, F=0x0 +0, 70, 70, 1, 108, 0x176e2b80, F=0x0 +0, 71, 71, 1, 117, 0x2ab12db9, F=0x0 +0, 72, 72, 1, 128, 0xb52130fe, F=0x0 +0, 73, 73, 1, 124, 0x62102d4e, F=0x0 +0, 74, 74, 1, 114, 0x186f2dc7, F=0x0 +0, 75, 75, 1, 104, 0x74ec2761, F=0x0 +0, 76, 76, 1, 107, 0x9ba32643, F=0x0 +0, 77, 77, 1, 127, 0xa8ef3544, F=0x0 +0, 78, 78, 1, 127, 0xcd7e3051, F=0x0 +0, 79, 79, 1, 221, 0x9d035e74, F=0x0 +0, 80, 80, 1, 217, 0x99d45fbc, F=0x0 +0, 81, 81, 1, 128, 0xc9522cfc, F=0x0 +0, 82, 82, 1, 127, 0x934f3004, F=0x0 +0, 83, 83, 1, 132, 0xb899320f, F=0x0 +0, 84, 84, 1, 133, 0xec2b3427, F=0x0 +0, 85, 85, 1, 131, 0xbedb31b2, F=0x0 +0, 86, 86, 1, 127, 0x11bc321c, F=0x0 +0, 87, 87, 1, 127, 0x36cf2f3e, F=0x0 +0, 88, 88, 1, 115, 0x22b32e12, F=0x0 +0, 89, 89, 1, 127, 0x53f73452, F=0x0 +0, 90, 90, 1, 123, 0xc54931ba, F=0x0 +0, 91, 91, 1, 170, 0x3055476c, F=0x0 +0, 92, 92, 1, 132, 0xc6e431a9, F=0x0 +0, 93, 93, 1, 124, 0x00e02e2c, F=0x0 +0, 94, 94, 1, 92, 0x838f2429, F=0x0 +0, 95, 95, 1, 184, 0xcee75528, F=0x0 +0, 96, 96, 1, 145, 0xcbb533f9, F=0x0 +0, 97, 97, 1, 187, 0x025b53b3, F=0x0 +0, 98, 98, 1, 158, 0x73dc3de6, F=0x0 +0, 99, 99, 1, 148, 0x489e3a52, F=0x0 +0, 100, 100, 1, 137, 0xf4c23446, F=0x0 +0, 101, 101, 1, 154, 0xc7eb3a4c, F=0x0 +0, 102, 102, 1, 141, 0x175d328b, F=0x0 +0, 103, 103, 1, 198, 0x22615c9f, F=0x0 +0, 104, 104, 1, 167, 0x9f3c40f0, F=0x0 +0, 105, 105, 1, 196, 0x66495290, F=0x0 +0, 106, 106, 1, 171, 0x10b14318, F=0x0 +0, 107, 107, 1, 152, 0x0e8538ba, F=0x0 +0, 108, 108, 1, 144, 0xa7e83928, F=0x0 +0, 109, 109, 1, 158, 0x2b6f3bb5, F=0x0 +0, 110, 110, 1, 142, 0x242d3ac1, F=0x0 +0, 111, 111, 1, 206, 0xf7935cd2, F=0x0 +0, 112, 112, 1, 177, 0xc96a46b4, F=0x0 +0, 113, 113, 1, 218, 0x96145d0c, F=0x0 +0, 114, 114, 1, 182, 0xdb8e4b9e, F=0x0 +0, 115, 115, 1, 145, 0x58483725, F=0x0 +0, 116, 116, 1, 130, 0xe26b33a3, F=0x0 +0, 117, 117, 1, 160, 0x162d3c34, F=0x0 +0, 118, 118, 1, 145, 0x77cd3b1f, F=0x0 +0, 119, 119, 1, 164, 0xfd024449, F=0x0 +0, 120, 120, 1, 148, 0x68293a64, F=0x0 +0, 121, 121, 1, 187, 0x8643475d, F=0x0 +0, 122, 122, 1, 124, 0xe904324b, F=0x0 +0, 123, 123, 1, 126, 0xb3482fed, F=0x0 +0, 124, 124, 1, 131, 0x60183155, F=0x0 +0, 125, 125, 1, 133, 0xf592319f, F=0x0 +0, 126, 126, 1, 202, 0xb53c5af2, F=0x0 +0, 127, 127, 1, 130, 0xe2503351, F=0x0 +0, 128, 128, 1, 132, 0x2c1a3433, F=0x0 +0, 129, 129, 1, 141, 0x772f36f2, F=0x0 +0, 130, 130, 1, 134, 0x5f2f3838, F=0x0 +0, 131, 131, 1, 216, 0x659c5fca, F=0x0 +0, 132, 132, 1, 139, 0x4876362d, F=0x0 +0, 133, 133, 1, 122, 0x96d13129, F=0x0 +0, 134, 134, 1, 137, 0x875238ec, F=0x0 +0, 135, 135, 1, 128, 0x953e3481, F=0x0 +0, 136, 136, 1, 172, 0x6390470d, F=0x0 +0, 137, 137, 1, 253, 0xe4e37282, F=0x0 +0, 138, 138, 1, 223, 0xca0060e6, F=0x0 +0, 139, 139, 1, 233, 0x20d96471, F=0x0 +0, 140, 140, 1, 131, 0x07302c8c, F=0x0 +0, 141, 141, 1, 132, 0x808b30dd, F=0x0 +0, 142, 142, 1, 133, 0xa91231c3, F=0x0 +0, 143, 143, 1, 130, 0x9a3a33d8, F=0x0 +0, 144, 144, 1, 232, 0x00826277, F=0x0 +0, 145, 145, 1, 247, 0x2edf6c06, F=0x0 +0, 146, 146, 1, 135, 0xd47b35de, F=0x0 +0, 147, 147, 1, 134, 0xc9c0330d, F=0x0 +0, 148, 148, 1, 132, 0x2d0e3263, F=0x0 +0, 149, 149, 1, 134, 0x5bd737ba, F=0x0 +0, 150, 150, 1, 131, 0x67223298, F=0x0 +0, 151, 151, 1, 125, 0xf483315a, F=0x0 +0, 152, 152, 1, 127, 0xb83e31a0, F=0x0 +0, 153, 153, 1, 125, 0x2dc033ab, F=0x0 +0, 154, 154, 1, 157, 0x438344e2, F=0x0 +0, 155, 155, 1, 135, 0xd01739e4, F=0x0 +0, 156, 156, 1, 121, 0x834a3276, F=0x0 +0, 157, 157, 1, 136, 0x243b3b8a, F=0x0 +0, 158, 158, 1, 119, 0x47893201, F=0x0 +0, 159, 159, 1, 154, 0xc688461f, F=0x0 +0, 160, 160, 1, 245, 0x68786756, F=0x0 +0, 161, 161, 1, 241, 0xa531647c, F=0x0 +0, 162, 162, 1, 168, 0x5d6a4447, F=0x0 +0, 163, 163, 1, 133, 0x55de34ee, F=0x0 +0, 164, 164, 1, 139, 0xde613ccd, F=0x0 +0, 165, 165, 1, 239, 0xf26b6ede, F=0x0 +0, 166, 166, 1, 161, 0x6fed41b5, F=0x0 +0, 167, 167, 1, 134, 0x011c3786, F=0x0 +0, 168, 168, 1, 121, 0xf0532db8, F=0x0 +0, 169, 169, 1, 133, 0x58b63448, F=0x0 +0, 170, 170, 1, 130, 0x78c52ed9, F=0x0 +0, 171, 171, 1, 153, 0xd99a3fab, F=0x0 +0, 172, 172, 1, 179, 0x8ec74c98, F=0x0 diff --git a/tests/ref/fate/gifenc-pal8 b/tests/ref/fate/gifenc-pal8 index a6d574199..3ed39357f 100644 --- a/tests/ref/fate/gifenc-pal8 +++ b/tests/ref/fate/gifenc-pal8 @@ -3,176 +3,176 @@ #codec_id 0: gif #dimensions 0: 217x217 #sar 0: 0/1 -0, 0, 0, 1, 552, 0x271a2dd3, S=1, 1024, 0xec907a9e -0, 1, 1, 1, 297, 0x90168a95, S=1, 1024, 0xf351799f -0, 2, 2, 1, 438, 0x91efce1b, S=1, 1024, 0xf351799f -0, 3, 3, 1, 450, 0x7c2dcfad, S=1, 1024, 0xf351799f -0, 4, 4, 1, 547, 0xc131fd3b, S=1, 1024, 0xf351799f -0, 5, 5, 1, 614, 0x68182006, S=1, 1024, 0xf351799f -0, 6, 6, 1, 642, 0x78bb1f5f, S=1, 1024, 0xf351799f -0, 7, 7, 1, 660, 0x35c033a2, S=1, 1024, 0xf351799f -0, 8, 8, 1, 821, 0xaf30790b, S=1, 1024, 0xf351799f -0, 9, 9, 1, 1157, 0x741c2da1, S=1, 1024, 0xf351799f -0, 10, 10, 1, 179, 0x3a27517c, S=1, 1024, 0xf351799f -0, 11, 11, 1, 1333, 0x5ee76f3c, S=1, 1024, 0xf351799f -0, 12, 12, 1, 1638, 0x5f640e86, S=1, 1024, 0xf351799f -0, 13, 13, 1, 1531, 0xccb8e437, S=1, 1024, 0xf351799f -0, 14, 14, 1, 1720, 0xc95d45ec, S=1, 1024, 0xf351799f -0, 15, 15, 1, 1910, 0x56cc831e, S=1, 1024, 0xf351799f -0, 16, 16, 1, 2124, 0x9cc8e130, S=1, 1024, 0xf351799f -0, 17, 17, 1, 2248, 0x05a325b1, S=1, 1024, 0xf351799f -0, 18, 18, 1, 2311, 0xdc633703, S=1, 1024, 0xf351799f -0, 19, 19, 1, 2408, 0x91c26f3e, S=1, 1024, 0xf351799f -0, 20, 20, 1, 2601, 0x8cf3c157, S=1, 1024, 0xf351799f -0, 21, 21, 1, 2687, 0x8f6400e6, S=1, 1024, 0xf351799f -0, 22, 22, 1, 2784, 0xaa880e55, S=1, 1024, 0xf351799f -0, 23, 23, 1, 2884, 0x46f546f6, S=1, 1024, 0xf351799f -0, 24, 24, 1, 2982, 0x807c7ad5, S=1, 1024, 0xf351799f -0, 25, 25, 1, 3101, 0xbcc89bec, S=1, 1024, 0xf351799f -0, 26, 26, 1, 3253, 0xd032f3fa, S=1, 1024, 0xf351799f -0, 27, 27, 1, 3329, 0xe4d42430, S=1, 1024, 0xf351799f -0, 28, 28, 1, 3572, 0xf8058aa0, S=1, 1024, 0xf351799f -0, 29, 29, 1, 3807, 0x3d2af9f3, S=1, 1024, 0xf351799f -0, 30, 30, 1, 2750, 0x814d1c33, S=1, 1024, 0xf351799f -0, 31, 31, 1, 4031, 0x3b077006, S=1, 1024, 0xf351799f -0, 32, 32, 1, 3025, 0x86729c1c, S=1, 1024, 0xf351799f -0, 33, 33, 1, 4295, 0xf71b0b38, S=1, 1024, 0xf351799f -0, 34, 34, 1, 2044, 0x5adcb93b, S=1, 1024, 0xf351799f -0, 35, 35, 1, 3212, 0xcf79eeed, S=1, 1024, 0xf351799f -0, 36, 36, 1, 2292, 0xb4386334, S=1, 1024, 0xf351799f -0, 37, 37, 1, 3633, 0x0010992f, S=1, 1024, 0xf351799f -0, 38, 38, 1, 3552, 0x23697490, S=1, 1024, 0xf351799f -0, 39, 39, 1, 3690, 0x62afdbb8, S=1, 1024, 0xf351799f -0, 40, 40, 1, 1559, 0x5baef54a, S=1, 1024, 0xf351799f -0, 41, 41, 1, 954, 0xca75ca79, S=1, 1024, 0xf351799f -0, 42, 42, 1, 273, 0x3687799b, S=1, 1024, 0xf351799f -0, 43, 43, 1, 930, 0x29f3b0c4, S=1, 1024, 0xf351799f -0, 44, 44, 1, 271, 0x305e8094, S=1, 1024, 0xf351799f -0, 45, 45, 1, 196, 0xf5ab51ee, S=1, 1024, 0xf351799f -0, 46, 46, 1, 4299, 0x67ec0d55, S=1, 1024, 0xf351799f -0, 47, 47, 1, 4895, 0xb394406c, S=1, 1024, 0xf351799f -0, 48, 48, 1, 4928, 0x233919d7, S=1, 1024, 0xf351799f -0, 49, 49, 1, 4941, 0x58a357da, S=1, 1024, 0xf351799f -0, 50, 50, 1, 4154, 0x21f2ac33, S=1, 1024, 0xf351799f -0, 51, 51, 1, 4678, 0xab3cc050, S=1, 1024, 0xf351799f -0, 52, 52, 1, 4741, 0x1974b581, S=1, 1024, 0xf351799f -0, 53, 53, 1, 4982, 0x891456d5, S=1, 1024, 0xf351799f -0, 54, 54, 1, 5179, 0x860fc6a1, S=1, 1024, 0xf351799f -0, 55, 55, 1, 5046, 0xce9183d3, S=1, 1024, 0xf351799f -0, 56, 56, 1, 5140, 0xa6d7b9af, S=1, 1024, 0xf351799f -0, 57, 57, 1, 4301, 0x03b6ef3f, S=1, 1024, 0xf351799f -0, 58, 58, 1, 5079, 0xa8d59e01, S=1, 1024, 0xf351799f -0, 59, 59, 1, 5284, 0xea34e3b3, S=1, 1024, 0xf351799f -0, 60, 60, 1, 5426, 0x556a15cd, S=1, 1024, 0xf351799f -0, 61, 61, 1, 4645, 0x061e8936, S=1, 1024, 0xf351799f -0, 62, 62, 1, 5263, 0x7536cf7d, S=1, 1024, 0xf351799f -0, 63, 63, 1, 5221, 0x9fbac3ca, S=1, 1024, 0xf351799f -0, 64, 64, 1, 5217, 0x02269bd2, S=1, 1024, 0xf351799f -0, 65, 65, 1, 5395, 0x120fff66, S=1, 1024, 0xf351799f -0, 66, 66, 1, 5220, 0x77cedcc5, S=1, 1024, 0xf351799f -0, 67, 67, 1, 5704, 0xba42dd96, S=1, 1024, 0xf351799f -0, 68, 68, 1, 5636, 0xcb91a25b, S=1, 1024, 0xf351799f -0, 69, 69, 1, 5818, 0x8dc0df92, S=1, 1024, 0xf351799f -0, 70, 70, 1, 5763, 0x51d5d5f0, S=1, 1024, 0xf351799f -0, 71, 71, 1, 6116, 0x09558b48, S=1, 1024, 0xf351799f -0, 72, 72, 1, 6069, 0x41926817, S=1, 1024, 0xf351799f -0, 73, 73, 1, 5796, 0x7fbeda44, S=1, 1024, 0xf351799f -0, 74, 74, 1, 5999, 0xe07d3770, S=1, 1024, 0xf351799f -0, 75, 75, 1, 6220, 0x6607b06f, S=1, 1024, 0xf351799f -0, 76, 76, 1, 6374, 0x7628e533, S=1, 1024, 0xf351799f -0, 77, 77, 1, 6465, 0xfe956b15, S=1, 1024, 0xf351799f -0, 78, 78, 1, 7019, 0x6c9a1aef, S=1, 1024, 0xf351799f -0, 79, 79, 1, 7255, 0x5fa5c1bf, S=1, 1024, 0xf351799f -0, 80, 80, 1, 8197, 0xf11d6ef2, S=1, 1024, 0xf351799f -0, 81, 81, 1, 8358, 0x027279e8, S=1, 1024, 0xf351799f -0, 82, 82, 1, 7708, 0x607f8e8b, S=1, 1024, 0xf351799f -0, 83, 83, 1, 7412, 0x6bb2105f, S=1, 1024, 0xf351799f -0, 84, 84, 1, 7541, 0xfdc02154, S=1, 1024, 0xf351799f -0, 85, 85, 1, 7948, 0x916ecd8b, S=1, 1024, 0xf351799f -0, 86, 86, 1, 8408, 0x1f97d414, S=1, 1024, 0xf351799f -0, 87, 87, 1, 8056, 0x9cbf159c, S=1, 1024, 0xf351799f -0, 88, 88, 1, 7401, 0x2625addb, S=1, 1024, 0xf351799f -0, 89, 89, 1, 7494, 0x2877eacb, S=1, 1024, 0xf351799f -0, 90, 90, 1, 7806, 0xe32574a3, S=1, 1024, 0xf351799f -0, 91, 91, 1, 7768, 0x25ed7ee7, S=1, 1024, 0xf351799f -0, 92, 92, 1, 7749, 0x6d8e978e, S=1, 1024, 0xf351799f -0, 93, 93, 1, 8047, 0xec4b150c, S=1, 1024, 0xf351799f -0, 94, 94, 1, 7618, 0x88cf30d5, S=1, 1024, 0xf351799f -0, 95, 95, 1, 7979, 0x0eb1cf2a, S=1, 1024, 0xf351799f -0, 96, 96, 1, 12062, 0xb49d9125, S=1, 1024, 0xf351799f -0, 97, 97, 1, 12317, 0x2d8fd6e9, S=1, 1024, 0xf351799f -0, 98, 98, 1, 12217, 0x9b3be549, S=1, 1024, 0xf351799f -0, 99, 99, 1, 11227, 0x067e9118, S=1, 1024, 0xf351799f -0, 100, 100, 1, 11108, 0x5e5b0afd, S=1, 1024, 0xf351799f -0, 101, 101, 1, 11366, 0xb38e8d15, S=1, 1024, 0xf351799f -0, 102, 102, 1, 11896, 0xeb3e35ca, S=1, 1024, 0xf351799f -0, 103, 103, 1, 11479, 0xbf7581e9, S=1, 1024, 0xf351799f -0, 104, 104, 1, 13395, 0x415b38d8, S=1, 1024, 0xf351799f -0, 105, 105, 1, 12913, 0x61544631, S=1, 1024, 0xf351799f -0, 106, 106, 1, 13864, 0xd39fe768, S=1, 1024, 0xf351799f -0, 107, 107, 1, 13551, 0x76c167d1, S=1, 1024, 0xf351799f -0, 108, 108, 1, 14041, 0x2f206888, S=1, 1024, 0xf351799f -0, 109, 109, 1, 14144, 0x9ec030d3, S=1, 1024, 0xf351799f -0, 110, 110, 1, 14277, 0xa84b3a9b, S=1, 1024, 0xf351799f -0, 111, 111, 1, 14424, 0xf5f1e06e, S=1, 1024, 0xf351799f -0, 112, 112, 1, 14689, 0xbca0adb5, S=1, 1024, 0xf351799f -0, 113, 113, 1, 14598, 0xc1d45745, S=1, 1024, 0xf351799f -0, 114, 114, 1, 15213, 0x8f3080fc, S=1, 1024, 0xf351799f -0, 115, 115, 1, 15425, 0xb0aa8f59, S=1, 1024, 0xf351799f -0, 116, 116, 1, 15595, 0x1406e5d5, S=1, 1024, 0xf351799f -0, 117, 117, 1, 15598, 0x48ec7d08, S=1, 1024, 0xf351799f -0, 118, 118, 1, 15863, 0x5381db7b, S=1, 1024, 0xf351799f -0, 119, 119, 1, 15717, 0xb87a1b87, S=1, 1024, 0xf351799f -0, 120, 120, 1, 16078, 0x5bab2453, S=1, 1024, 0xf351799f -0, 121, 121, 1, 16225, 0xa1f88113, S=1, 1024, 0xf351799f -0, 122, 122, 1, 16135, 0x6af2f4e1, S=1, 1024, 0xf351799f -0, 123, 123, 1, 16661, 0xf02a3343, S=1, 1024, 0xf351799f -0, 124, 124, 1, 16619, 0xc71935a4, S=1, 1024, 0xf351799f -0, 125, 125, 1, 16829, 0x29849844, S=1, 1024, 0xf351799f -0, 126, 126, 1, 16944, 0x3423ae77, S=1, 1024, 0xf351799f -0, 127, 127, 1, 17119, 0x609b4409, S=1, 1024, 0xf351799f -0, 128, 128, 1, 17150, 0xf85dfd31, S=1, 1024, 0xf351799f -0, 129, 129, 1, 17321, 0x38eccb10, S=1, 1024, 0xf351799f -0, 130, 130, 1, 17395, 0x0ba08b85, S=1, 1024, 0xf351799f -0, 131, 131, 1, 17666, 0x6fbc0264, S=1, 1024, 0xf351799f -0, 132, 132, 1, 17730, 0x3dcc64a6, S=1, 1024, 0xf351799f -0, 133, 133, 1, 17934, 0xb539974b, S=1, 1024, 0xf351799f -0, 134, 134, 1, 17944, 0x2214ec94, S=1, 1024, 0xf351799f -0, 135, 135, 1, 18238, 0x70f9ff1d, S=1, 1024, 0xf351799f -0, 136, 136, 1, 18391, 0x4b149209, S=1, 1024, 0xf351799f -0, 137, 137, 1, 18543, 0x45a1c02f, S=1, 1024, 0xf351799f -0, 138, 138, 1, 18939, 0x2789a88c, S=1, 1024, 0xf351799f -0, 139, 139, 1, 19145, 0x5daafd7a, S=1, 1024, 0xf351799f -0, 140, 140, 1, 19120, 0x565f80e6, S=1, 1024, 0xf351799f -0, 141, 141, 1, 19130, 0xff70cc21, S=1, 1024, 0xf351799f -0, 142, 142, 1, 19494, 0xbfa284db, S=1, 1024, 0xf351799f -0, 143, 143, 1, 19534, 0x3d40743b, S=1, 1024, 0xf351799f -0, 144, 144, 1, 19747, 0x33c9b108, S=1, 1024, 0xf351799f -0, 145, 145, 1, 20114, 0x9d223e36, S=1, 1024, 0xf351799f -0, 146, 146, 1, 20257, 0xe7bdaf43, S=1, 1024, 0xf351799f -0, 147, 147, 1, 20370, 0x0c5f1970, S=1, 1024, 0xf351799f -0, 148, 148, 1, 20292, 0x6986d20e, S=1, 1024, 0xf351799f -0, 149, 149, 1, 20491, 0xd88e4c08, S=1, 1024, 0xf351799f -0, 150, 150, 1, 20647, 0x1aefaffc, S=1, 1024, 0xf351799f -0, 151, 151, 1, 20666, 0x43e4aaaa, S=1, 1024, 0xf351799f -0, 152, 152, 1, 21007, 0xa7ca3ef0, S=1, 1024, 0xf351799f -0, 153, 153, 1, 21058, 0x06814351, S=1, 1024, 0xf351799f -0, 154, 154, 1, 21153, 0x3c852b10, S=1, 1024, 0xf351799f -0, 155, 155, 1, 21078, 0x8df15855, S=1, 1024, 0xf351799f -0, 156, 156, 1, 21458, 0xd3a531d6, S=1, 1024, 0xf351799f -0, 157, 157, 1, 21669, 0x88baca53, S=1, 1024, 0xf351799f -0, 158, 158, 1, 21581, 0xd692fa1f, S=1, 1024, 0xf351799f -0, 159, 159, 1, 21654, 0x30fb9061, S=1, 1024, 0xf351799f -0, 160, 160, 1, 21987, 0xe7646d8b, S=1, 1024, 0xf351799f -0, 161, 161, 1, 22205, 0x0fc55b6a, S=1, 1024, 0xf351799f -0, 162, 162, 1, 22475, 0x4bc4c032, S=1, 1024, 0xf351799f -0, 163, 163, 1, 22490, 0x58ca23f6, S=1, 1024, 0xf351799f -0, 164, 164, 1, 22460, 0xf9ceb0ac, S=1, 1024, 0xf351799f -0, 165, 165, 1, 22861, 0xb05f0f84, S=1, 1024, 0xf351799f -0, 166, 166, 1, 22746, 0x0df23a5c, S=1, 1024, 0xf351799f -0, 167, 167, 1, 23165, 0xbd7147ad, S=1, 1024, 0xf351799f -0, 168, 168, 1, 23273, 0x9781a34f, S=1, 1024, 0xf351799f -0, 169, 169, 1, 23211, 0x69c7606b, S=1, 1024, 0xf351799f -0, 170, 170, 1, 23648, 0xdafde037, S=1, 1024, 0xf351799f -0, 171, 171, 1, 23675, 0x2a2147ed, S=1, 1024, 0xf351799f -0, 172, 172, 1, 23874, 0x12c184b6, S=1, 1024, 0xf351799f +0, 0, 0, 1, 2109, 0x39642b3d +0, 1, 1, 1, 305, 0xefa98bbd, F=0x0 +0, 2, 2, 1, 446, 0x9499cf43, F=0x0 +0, 3, 3, 1, 458, 0x8cb7d0d5, F=0x0 +0, 4, 4, 1, 555, 0x41f2fe63, F=0x0 +0, 5, 5, 1, 622, 0x3651212e, F=0x0 +0, 6, 6, 1, 650, 0x67542087, F=0x0 +0, 7, 7, 1, 668, 0x392934ca, F=0x0 +0, 8, 8, 1, 829, 0x6cd07a33, F=0x0 +0, 9, 9, 1, 1165, 0xb64b2ec9, F=0x0 +0, 10, 10, 1, 187, 0x114a52a4, F=0x0 +0, 11, 11, 1, 1341, 0x6ca57064, F=0x0 +0, 12, 12, 1, 1646, 0xcdd90fae, F=0x0 +0, 13, 13, 1, 1539, 0xbf75e55f, F=0x0 +0, 14, 14, 1, 1728, 0x96b14714, F=0x0 +0, 15, 15, 1, 1918, 0xffd08446, F=0x0 +0, 16, 16, 1, 2132, 0x3d5ae258, F=0x0 +0, 17, 17, 1, 2256, 0x359526d9, F=0x0 +0, 18, 18, 1, 2319, 0x553c382b, F=0x0 +0, 19, 19, 1, 2416, 0x7ac37066, F=0x0 +0, 20, 20, 1, 2609, 0x552bc27f, F=0x0 +0, 21, 21, 1, 2695, 0xbb0c020e, F=0x0 +0, 22, 22, 1, 2792, 0x46670f7d, F=0x0 +0, 23, 23, 1, 2892, 0x5674481e, F=0x0 +0, 24, 24, 1, 2990, 0x015a7bfd, F=0x0 +0, 25, 25, 1, 3109, 0xc73e9d14, F=0x0 +0, 26, 26, 1, 3261, 0x8a77f522, F=0x0 +0, 27, 27, 1, 3337, 0xf6f92558, F=0x0 +0, 28, 28, 1, 3580, 0x23408bc8, F=0x0 +0, 29, 29, 1, 3815, 0x781dfb1b, F=0x0 +0, 30, 30, 1, 2758, 0xf5cd1d5b, F=0x0 +0, 31, 31, 1, 4039, 0x7909712e, F=0x0 +0, 32, 32, 1, 3033, 0x39089d44, F=0x0 +0, 33, 33, 1, 4303, 0x667b0c60, F=0x0 +0, 34, 34, 1, 2052, 0x9edfba63, F=0x0 +0, 35, 35, 1, 3220, 0x5a56f015, F=0x0 +0, 36, 36, 1, 2300, 0x1719645c, F=0x0 +0, 37, 37, 1, 3641, 0x71c49a57, F=0x0 +0, 38, 38, 1, 3560, 0x377575b8, F=0x0 +0, 39, 39, 1, 3698, 0x165adce0, F=0x0 +0, 40, 40, 1, 1567, 0x6ecbf672, F=0x0 +0, 41, 41, 1, 962, 0x21eccba1, F=0x0 +0, 42, 42, 1, 281, 0x7a5a7ac3, F=0x0 +0, 43, 43, 1, 938, 0x659bb1ec, F=0x0 +0, 44, 44, 1, 279, 0x71e181bc, F=0x0 +0, 45, 45, 1, 204, 0xe0765316, F=0x0 +0, 46, 46, 1, 4307, 0xdbdd0e7d, F=0x0 +0, 47, 47, 1, 4903, 0xd8d24194, F=0x0 +0, 48, 48, 1, 4936, 0x6e9f1aff, F=0x0 +0, 49, 49, 1, 4949, 0xb3115902, F=0x0 +0, 50, 50, 1, 4162, 0xee2cad5b, F=0x0 +0, 51, 51, 1, 4686, 0xd583c178, F=0x0 +0, 52, 52, 1, 4749, 0x8c93b6a9, F=0x0 +0, 53, 53, 1, 4990, 0x12f957fd, F=0x0 +0, 54, 54, 1, 5187, 0xf3bcc7c9, F=0x0 +0, 55, 55, 1, 5054, 0xa27684fb, F=0x0 +0, 56, 56, 1, 5148, 0xe76cbad7, F=0x0 +0, 57, 57, 1, 4309, 0x79f7f067, F=0x0 +0, 58, 58, 1, 5087, 0xa2e29f29, F=0x0 +0, 59, 59, 1, 5292, 0xd158e4db, F=0x0 +0, 60, 60, 1, 5434, 0xe0be16f5, F=0x0 +0, 61, 61, 1, 4653, 0x0a3d8a5e, F=0x0 +0, 62, 62, 1, 5271, 0x4412d0a5, F=0x0 +0, 63, 63, 1, 5229, 0x3e06c4f2, F=0x0 +0, 64, 64, 1, 5225, 0x9bc39cfa, F=0x0 +0, 65, 65, 1, 5403, 0x798b009d, F=0x0 +0, 66, 66, 1, 5228, 0x14f2dded, F=0x0 +0, 67, 67, 1, 5712, 0x8724debe, F=0x0 +0, 68, 68, 1, 5644, 0x49d3a383, F=0x0 +0, 69, 69, 1, 5826, 0xde72e0ba, F=0x0 +0, 70, 70, 1, 5771, 0x62efd718, F=0x0 +0, 71, 71, 1, 6124, 0xb2a68c70, F=0x0 +0, 72, 72, 1, 6077, 0xb48b693f, F=0x0 +0, 73, 73, 1, 5804, 0xb700db6c, F=0x0 +0, 74, 74, 1, 6007, 0x02953898, F=0x0 +0, 75, 75, 1, 6228, 0x87a7b197, F=0x0 +0, 76, 76, 1, 6382, 0x49e7e65b, F=0x0 +0, 77, 77, 1, 6473, 0x3b9b6c3d, F=0x0 +0, 78, 78, 1, 7027, 0x2a4e1c17, F=0x0 +0, 79, 79, 1, 7263, 0x2e48c2e7, F=0x0 +0, 80, 80, 1, 8205, 0x013b701a, F=0x0 +0, 81, 81, 1, 8366, 0xcca97b10, F=0x0 +0, 82, 82, 1, 7716, 0x3b088fb3, F=0x0 +0, 83, 83, 1, 7420, 0xefdd1187, F=0x0 +0, 84, 84, 1, 7549, 0x1731227c, F=0x0 +0, 85, 85, 1, 7956, 0x8186ceb3, F=0x0 +0, 86, 86, 1, 8416, 0x23add53c, F=0x0 +0, 87, 87, 1, 8064, 0x09c616c4, F=0x0 +0, 88, 88, 1, 7409, 0x9d98af03, F=0x0 +0, 89, 89, 1, 7502, 0x0b81ebf3, F=0x0 +0, 90, 90, 1, 7814, 0x2f0d75cb, F=0x0 +0, 91, 91, 1, 7776, 0x45d6800f, F=0x0 +0, 92, 92, 1, 7757, 0x777f98b6, F=0x0 +0, 93, 93, 1, 8055, 0x4eea1634, F=0x0 +0, 94, 94, 1, 7626, 0xfb3931fd, F=0x0 +0, 95, 95, 1, 7987, 0x22a1d052, F=0x0 +0, 96, 96, 1, 12070, 0x3aa2924d, F=0x0 +0, 97, 97, 1, 12325, 0xda6cd811, F=0x0 +0, 98, 98, 1, 12225, 0xd478e671, F=0x0 +0, 99, 99, 1, 11235, 0xc6c09240, F=0x0 +0, 100, 100, 1, 11116, 0x95050c25, F=0x0 +0, 101, 101, 1, 11374, 0x14a68e3d, F=0x0 +0, 102, 102, 1, 11904, 0xb14436f2, F=0x0 +0, 103, 103, 1, 11487, 0xa3358311, F=0x0 +0, 104, 104, 1, 13403, 0xccf33a00, F=0x0 +0, 105, 105, 1, 12921, 0xbf7e4759, F=0x0 +0, 106, 106, 1, 13872, 0x7dace890, F=0x0 +0, 107, 107, 1, 13559, 0xb6c868f9, F=0x0 +0, 108, 108, 1, 14049, 0xa5d569b0, F=0x0 +0, 109, 109, 1, 14152, 0x8c9c31fb, F=0x0 +0, 110, 110, 1, 14285, 0x2ffe3bc3, F=0x0 +0, 111, 111, 1, 14432, 0x27abe196, F=0x0 +0, 112, 112, 1, 14697, 0x20d1aedd, F=0x0 +0, 113, 113, 1, 14606, 0xbcbe586d, F=0x0 +0, 114, 114, 1, 15221, 0x515f8224, F=0x0 +0, 115, 115, 1, 15433, 0x68089081, F=0x0 +0, 116, 116, 1, 15603, 0x8ff4e6fd, F=0x0 +0, 117, 117, 1, 15606, 0xc8527e30, F=0x0 +0, 118, 118, 1, 15871, 0x056ddca3, F=0x0 +0, 119, 119, 1, 15725, 0xc1871caf, F=0x0 +0, 120, 120, 1, 16086, 0x063e257b, F=0x0 +0, 121, 121, 1, 16233, 0xf683823b, F=0x0 +0, 122, 122, 1, 16143, 0x576df609, F=0x0 +0, 123, 123, 1, 16669, 0x3d02346b, F=0x0 +0, 124, 124, 1, 16627, 0xe35236cc, F=0x0 +0, 125, 125, 1, 16837, 0x389c996c, F=0x0 +0, 126, 126, 1, 16952, 0xc833af9f, F=0x0 +0, 127, 127, 1, 17127, 0xbf124531, F=0x0 +0, 128, 128, 1, 17158, 0x7abbfe59, F=0x0 +0, 129, 129, 1, 17329, 0x8102cc38, F=0x0 +0, 130, 130, 1, 17403, 0xa9468cad, F=0x0 +0, 131, 131, 1, 17674, 0x46d8038c, F=0x0 +0, 132, 132, 1, 17738, 0x5ee865ce, F=0x0 +0, 133, 133, 1, 17942, 0xc2449873, F=0x0 +0, 134, 134, 1, 17952, 0x3aafedbc, F=0x0 +0, 135, 135, 1, 18246, 0xdd930054, F=0x0 +0, 136, 136, 1, 18399, 0x68a59331, F=0x0 +0, 137, 137, 1, 18551, 0x1301c157, F=0x0 +0, 138, 138, 1, 18947, 0xbed8a9b4, F=0x0 +0, 139, 139, 1, 19153, 0xe338fea2, F=0x0 +0, 140, 140, 1, 19128, 0xbf05820e, F=0x0 +0, 141, 141, 1, 19138, 0x73b5cd49, F=0x0 +0, 142, 142, 1, 19502, 0xd8d68603, F=0x0 +0, 143, 143, 1, 19542, 0x84b47563, F=0x0 +0, 144, 144, 1, 19755, 0x7194b230, F=0x0 +0, 145, 145, 1, 20122, 0x83633f5e, F=0x0 +0, 146, 146, 1, 20265, 0x7365b06b, F=0x0 +0, 147, 147, 1, 20378, 0x1aaf1a98, F=0x0 +0, 148, 148, 1, 20300, 0x1da6d336, F=0x0 +0, 149, 149, 1, 20499, 0x72d54d30, F=0x0 +0, 150, 150, 1, 20655, 0x6996b124, F=0x0 +0, 151, 151, 1, 20674, 0xa883abd2, F=0x0 +0, 152, 152, 1, 21015, 0x96cf4018, F=0x0 +0, 153, 153, 1, 21066, 0x307e4479, F=0x0 +0, 154, 154, 1, 21161, 0xd45a2c38, F=0x0 +0, 155, 155, 1, 21086, 0xcf0e597d, F=0x0 +0, 156, 156, 1, 21466, 0xcc4032fe, F=0x0 +0, 157, 157, 1, 21677, 0x755ccb7b, F=0x0 +0, 158, 158, 1, 21589, 0x5d74fb47, F=0x0 +0, 159, 159, 1, 21662, 0x0c459189, F=0x0 +0, 160, 160, 1, 21995, 0x43d46eb3, F=0x0 +0, 161, 161, 1, 22213, 0x68455c92, F=0x0 +0, 162, 162, 1, 22483, 0xdc83c15a, F=0x0 +0, 163, 163, 1, 22498, 0xfae1251e, F=0x0 +0, 164, 164, 1, 22468, 0x7944b1d4, F=0x0 +0, 165, 165, 1, 22869, 0xff8c10ac, F=0x0 +0, 166, 166, 1, 22754, 0xd8183b84, F=0x0 +0, 167, 167, 1, 23173, 0x6c3c48d5, F=0x0 +0, 168, 168, 1, 23281, 0xc32ca477, F=0x0 +0, 169, 169, 1, 23219, 0x4dc26193, F=0x0 +0, 170, 170, 1, 23656, 0xb85ee15f, F=0x0 +0, 171, 171, 1, 23683, 0x26ba4915, F=0x0 +0, 172, 172, 1, 23882, 0xf57285de, F=0x0 diff --git a/tests/ref/fate/gifenc-rgb4_byte b/tests/ref/fate/gifenc-rgb4_byte index 067accd69..c99c983f8 100644 --- a/tests/ref/fate/gifenc-rgb4_byte +++ b/tests/ref/fate/gifenc-rgb4_byte @@ -3,176 +3,176 @@ #codec_id 0: gif #dimensions 0: 217x217 #sar 0: 0/1 -0, 0, 0, 1, 508, 0xf04a113b -0, 1, 1, 1, 213, 0x23c24d3d, S=1, 1024, 0xf7700427 -0, 2, 2, 1, 131, 0x56d22a39, S=1, 1024, 0x03730427 -0, 3, 3, 1, 384, 0xb1d8a4bd, S=1, 1024, 0xf7700427 -0, 4, 4, 1, 381, 0x37a3a2c9, S=1, 1024, 0xf3740427 -0, 5, 5, 1, 430, 0x162bb3d3, S=1, 1024, 0xf3740427 -0, 6, 6, 1, 518, 0x195bd738, S=1, 1024, 0xf3740427 -0, 7, 7, 1, 535, 0x12cde6b7, S=1, 1024, 0xf3740427 -0, 8, 8, 1, 438, 0xa653b946, S=1, 1024, 0x0b6b0427 -0, 9, 9, 1, 923, 0xd2e2a35f, S=1, 1024, 0x0b6b0427 -0, 10, 10, 1, 694, 0xe1cf4a1f, S=1, 1024, 0x0b6b0427 -0, 11, 11, 1, 1194, 0xa6152c8a, S=1, 1024, 0x0b6b0427 -0, 12, 12, 1, 1291, 0x94d25581, S=1, 1024, 0x0b6b0427 -0, 13, 13, 1, 1245, 0x5b483525, S=1, 1024, 0x0b6b0427 -0, 14, 14, 1, 1330, 0xfb5351c8, S=1, 1024, 0x0b6b0427 -0, 15, 15, 1, 1276, 0x6f403914, S=1, 1024, 0x0b6b0427 -0, 16, 16, 1, 1475, 0xbf459755, S=1, 1024, 0x0b6b0427 -0, 17, 17, 1, 1784, 0xe9954aa7, S=1, 1024, 0xecb30526 -0, 18, 18, 1, 1675, 0x219dfaf8, S=1, 1024, 0xecb30526 -0, 19, 19, 1, 1509, 0xd7f5abbe, S=1, 1024, 0xecb30526 -0, 20, 20, 1, 1705, 0x44a01729, S=1, 1024, 0xecb30526 -0, 21, 21, 1, 1745, 0x31ff1f89, S=1, 1024, 0xecb30526 -0, 22, 22, 1, 1642, 0x55420147, S=1, 1024, 0xecb30526 -0, 23, 23, 1, 1718, 0x68ef1cb8, S=1, 1024, 0xecb30526 -0, 24, 24, 1, 1900, 0xd7737a09, S=1, 1024, 0xecb30526 -0, 25, 25, 1, 1807, 0x4f6c5140, S=1, 1024, 0xecb30526 -0, 26, 26, 1, 1915, 0x976d80e6, S=1, 1024, 0xecb30526 -0, 27, 27, 1, 2100, 0x0ae6d1ce, S=1, 1024, 0xecb30526 -0, 28, 28, 1, 2700, 0x7a89f104, S=1, 1024, 0xecb30526 -0, 29, 29, 1, 2673, 0xf6b6a71d, S=1, 1024, 0xecb30526 -0, 30, 30, 1, 2895, 0x9079484b, S=1, 1024, 0xecb30526 -0, 31, 31, 1, 3257, 0x0b0cd125, S=1, 1024, 0xecb30526 -0, 32, 32, 1, 3179, 0x3ee2c161, S=1, 1024, 0xecb30526 -0, 33, 33, 1, 3296, 0x6230e506, S=1, 1024, 0xecb30526 -0, 34, 34, 1, 3600, 0x021775d7, S=1, 1024, 0xecb30526 -0, 35, 35, 1, 3699, 0xfb03a043, S=1, 1024, 0xecb30526 -0, 36, 36, 1, 3814, 0x96a8d57e, S=1, 1024, 0xecb30526 -0, 37, 37, 1, 3627, 0x33a37f8f, S=1, 1024, 0xecb30526 -0, 38, 38, 1, 2950, 0x50806197, S=1, 1024, 0xecb30526 -0, 39, 39, 1, 3086, 0x72068d4c, S=1, 1024, 0xecb30526 -0, 40, 40, 1, 3094, 0x2880861f, S=1, 1024, 0xecb30526 -0, 41, 41, 1, 3456, 0x6d232a96, S=1, 1024, 0xecb30526 -0, 42, 42, 1, 4108, 0x46d75ebb, S=1, 1024, 0xecb30526 -0, 43, 43, 1, 4217, 0x04a258f4, S=1, 1024, 0xecb30526 -0, 44, 44, 1, 3613, 0x667f4ff8, S=1, 1024, 0xecb30526 -0, 45, 45, 1, 3910, 0x8f37e73e, S=1, 1024, 0xecb30526 -0, 46, 46, 1, 4461, 0x5db9e0bf, S=1, 1024, 0xecb30526 -0, 47, 47, 1, 4593, 0x883f2f49, S=1, 1024, 0xecb30526 -0, 48, 48, 1, 4822, 0x03d99b73, S=1, 1024, 0xecb30526 -0, 49, 49, 1, 5398, 0x39f7bff4, S=1, 1024, 0xecb30526 -0, 50, 50, 1, 5266, 0xd5ab9630, S=1, 1024, 0xecb30526 -0, 51, 51, 1, 5416, 0x5876e16f, S=1, 1024, 0xecb30526 -0, 52, 52, 1, 5519, 0x30ed05d8, S=1, 1024, 0xecb30526 -0, 53, 53, 1, 5701, 0x5bae5af7, S=1, 1024, 0xecb30526 -0, 54, 54, 1, 6160, 0x98364177, S=1, 1024, 0xecb30526 -0, 55, 55, 1, 6233, 0x52a05075, S=1, 1024, 0xecb30526 -0, 56, 56, 1, 5911, 0x04bfc46a, S=1, 1024, 0xecb30526 -0, 57, 57, 1, 5997, 0xf1e6f586, S=1, 1024, 0xecb30526 -0, 58, 58, 1, 5946, 0xe6f3f055, S=1, 1024, 0xecb30526 -0, 59, 59, 1, 6468, 0xc8a3cf61, S=1, 1024, 0xecb30526 -0, 60, 60, 1, 6737, 0xc27b3b79, S=1, 1024, 0xecb30526 -0, 61, 61, 1, 6275, 0x84d88e2b, S=1, 1024, 0xecb30526 -0, 62, 62, 1, 6641, 0xb44b3534, S=1, 1024, 0xecb30526 -0, 63, 63, 1, 6378, 0x3965888b, S=1, 1024, 0xecb30526 -0, 64, 64, 1, 6257, 0x12115750, S=1, 1024, 0xecb30526 -0, 65, 65, 1, 6908, 0x57137217, S=1, 1024, 0xecb30526 -0, 66, 66, 1, 7230, 0xbacc24ee, S=1, 1024, 0xecb30526 -0, 67, 67, 1, 7556, 0x1aa2a694, S=1, 1024, 0xecb30526 -0, 68, 68, 1, 7413, 0xbc9e7718, S=1, 1024, 0xecb30526 -0, 69, 69, 1, 7476, 0xb2a1aba0, S=1, 1024, 0xecb30526 -0, 70, 70, 1, 7596, 0x3301e56d, S=1, 1024, 0xecb30526 -0, 71, 71, 1, 7756, 0x8f2504f8, S=1, 1024, 0xecb30526 -0, 72, 72, 1, 8015, 0xd4146c80, S=1, 1024, 0xecb30526 -0, 73, 73, 1, 8128, 0x11b2bf4c, S=1, 1024, 0xecb30526 -0, 74, 74, 1, 8101, 0xc627adbe, S=1, 1024, 0xecb30526 -0, 75, 75, 1, 7863, 0xe99f3f3b, S=1, 1024, 0xecb30526 -0, 76, 76, 1, 7960, 0x4bc091b8, S=1, 1024, 0xecb30526 -0, 77, 77, 1, 8238, 0x1086ea8a, S=1, 1024, 0xecb30526 -0, 78, 78, 1, 8321, 0x3a404791, S=1, 1024, 0xecb30526 -0, 79, 79, 1, 8562, 0xcbdcc01e, S=1, 1024, 0xecb30526 -0, 80, 80, 1, 8746, 0xec190b22, S=1, 1024, 0xecb30526 -0, 81, 81, 1, 8578, 0x12e7a4e8, S=1, 1024, 0xecb30526 -0, 82, 82, 1, 8878, 0x51c05771, S=1, 1024, 0xecb30526 -0, 83, 83, 1, 9077, 0xe12b589b, S=1, 1024, 0xecb30526 -0, 84, 84, 1, 9310, 0xde3bf881, S=1, 1024, 0xecb30526 -0, 85, 85, 1, 9394, 0x1eba46cc, S=1, 1024, 0xecb30526 -0, 86, 86, 1, 9161, 0x7c359911, S=1, 1024, 0xecb30526 -0, 87, 87, 1, 9462, 0xccda3664, S=1, 1024, 0xecb30526 -0, 88, 88, 1, 9650, 0x6e6292fc, S=1, 1024, 0xecb30526 -0, 89, 89, 1, 9701, 0x08909b95, S=1, 1024, 0xecb30526 -0, 90, 90, 1, 9523, 0xe61b38bb, S=1, 1024, 0xecb30526 -0, 91, 91, 1, 9891, 0x96b90b98, S=1, 1024, 0xecb30526 -0, 92, 92, 1, 10005, 0x2db84c80, S=1, 1024, 0xecb30526 -0, 93, 93, 1, 10038, 0x37e52a72, S=1, 1024, 0xecb30526 -0, 94, 94, 1, 10086, 0x135a43e4, S=1, 1024, 0xecb30526 -0, 95, 95, 1, 10438, 0x472c0372, S=1, 1024, 0xecb30526 -0, 96, 96, 1, 10583, 0xcf4c5862, S=1, 1024, 0xecb30526 -0, 97, 97, 1, 10581, 0xce658137, S=1, 1024, 0xecb30526 -0, 98, 98, 1, 10807, 0x3954dad9, S=1, 1024, 0xecb30526 -0, 99, 99, 1, 11111, 0x5f8d504f, S=1, 1024, 0xecb30526 -0, 100, 100, 1, 11194, 0x3c7e6a77, S=1, 1024, 0xecb30526 -0, 101, 101, 1, 11240, 0x5112a0a3, S=1, 1024, 0xecb30526 -0, 102, 102, 1, 11483, 0xaf10f4fa, S=1, 1024, 0xecb30526 -0, 103, 103, 1, 11680, 0x44a25971, S=1, 1024, 0xecb30526 -0, 104, 104, 1, 11785, 0x7350b5db, S=1, 1024, 0xecb30526 -0, 105, 105, 1, 11436, 0xe3170ad5, S=1, 1024, 0xecb30526 -0, 106, 106, 1, 11928, 0x13d8c885, S=1, 1024, 0xecb30526 -0, 107, 107, 1, 11932, 0xecb5bdf7, S=1, 1024, 0xecb30526 -0, 108, 108, 1, 12281, 0x18bb76d5, S=1, 1024, 0xecb30526 -0, 109, 109, 1, 12334, 0x16147fc3, S=1, 1024, 0xecb30526 -0, 110, 110, 1, 12452, 0x61a8b3d7, S=1, 1024, 0xecb30526 -0, 111, 111, 1, 12695, 0x8b703e74, S=1, 1024, 0xecb30526 -0, 112, 112, 1, 12668, 0x19505176, S=1, 1024, 0xecb30526 -0, 113, 113, 1, 12957, 0x3b839f0d, S=1, 1024, 0xecb30526 -0, 114, 114, 1, 13054, 0xb8a5e3db, S=1, 1024, 0xecb30526 -0, 115, 115, 1, 13147, 0xdf5c2e68, S=1, 1024, 0xecb30526 -0, 116, 116, 1, 13171, 0x15961ca2, S=1, 1024, 0xecb30526 -0, 117, 117, 1, 13198, 0xfd855718, S=1, 1024, 0xecb30526 -0, 118, 118, 1, 13211, 0x1a625e31, S=1, 1024, 0xecb30526 -0, 119, 119, 1, 13210, 0x246661c9, S=1, 1024, 0xecb30526 -0, 120, 120, 1, 13467, 0xfcaaa461, S=1, 1024, 0xecb30526 -0, 121, 121, 1, 13665, 0x8100dbf2, S=1, 1024, 0xecb30526 -0, 122, 122, 1, 13692, 0xddd1eab9, S=1, 1024, 0xecb30526 -0, 123, 123, 1, 13821, 0xc70e2af0, S=1, 1024, 0xecb30526 -0, 124, 124, 1, 13946, 0xe15d9134, S=1, 1024, 0xecb30526 -0, 125, 125, 1, 14063, 0xf652d232, S=1, 1024, 0xecb30526 -0, 126, 126, 1, 14124, 0x756ccc81, S=1, 1024, 0xecb30526 -0, 127, 127, 1, 14331, 0x56d64fe8, S=1, 1024, 0xecb30526 -0, 128, 128, 1, 14469, 0x4c3faa7f, S=1, 1024, 0xecb30526 -0, 129, 129, 1, 14536, 0xad02a19b, S=1, 1024, 0xecb30526 -0, 130, 130, 1, 14608, 0x0971d168, S=1, 1024, 0xecb30526 -0, 131, 131, 1, 14898, 0x1a6827b3, S=1, 1024, 0xecb30526 -0, 132, 132, 1, 14978, 0xf9709fef, S=1, 1024, 0xecb30526 -0, 133, 133, 1, 15142, 0x3598da63, S=1, 1024, 0xecb30526 -0, 134, 134, 1, 15129, 0x062fb976, S=1, 1024, 0xecb30526 -0, 135, 135, 1, 15243, 0x0a6a12f9, S=1, 1024, 0xecb30526 -0, 136, 136, 1, 15337, 0x0f9a65d6, S=1, 1024, 0xecb30526 -0, 137, 137, 1, 15638, 0xf7bc9ef5, S=1, 1024, 0xecb30526 -0, 138, 138, 1, 15912, 0x2d5b26bb, S=1, 1024, 0xecb30526 -0, 139, 139, 1, 16041, 0xbfaf4857, S=1, 1024, 0xecb30526 -0, 140, 140, 1, 16228, 0xdac701f0, S=1, 1024, 0xecb30526 -0, 141, 141, 1, 16262, 0xcd0ae5e4, S=1, 1024, 0xecb30526 -0, 142, 142, 1, 16371, 0x9d4f0e73, S=1, 1024, 0xecb30526 -0, 143, 143, 1, 16661, 0xd37ba990, S=1, 1024, 0xecb30526 -0, 144, 144, 1, 16917, 0xd5b01774, S=1, 1024, 0xecb30526 -0, 145, 145, 1, 17149, 0x435ecdd4, S=1, 1024, 0xecb30526 -0, 146, 146, 1, 17172, 0x045fb234, S=1, 1024, 0xecb30526 -0, 147, 147, 1, 17315, 0xc5ddadab, S=1, 1024, 0xecb30526 -0, 148, 148, 1, 17397, 0xff8e15b6, S=1, 1024, 0xecb30526 -0, 149, 149, 1, 17431, 0x6832f8c0, S=1, 1024, 0xecb30526 -0, 150, 150, 1, 17576, 0x5c2a5445, S=1, 1024, 0xecb30526 -0, 151, 151, 1, 17764, 0x609f8c3b, S=1, 1024, 0xecb30526 -0, 152, 152, 1, 17826, 0x538c8532, S=1, 1024, 0xecb30526 -0, 153, 153, 1, 17918, 0x84fc9a95, S=1, 1024, 0xecb30526 -0, 154, 154, 1, 17823, 0x788fbada, S=1, 1024, 0xecb30526 -0, 155, 155, 1, 18142, 0x56881e47, S=1, 1024, 0xecb30526 -0, 156, 156, 1, 18257, 0xa35b86cf, S=1, 1024, 0xecb30526 -0, 157, 157, 1, 18337, 0x82ddbc21, S=1, 1024, 0xecb30526 -0, 158, 158, 1, 18293, 0xf0d838d6, S=1, 1024, 0xecb30526 -0, 159, 159, 1, 18418, 0x7ed8bba6, S=1, 1024, 0xecb30526 -0, 160, 160, 1, 18607, 0xccea47f6, S=1, 1024, 0xecb30526 -0, 161, 161, 1, 18916, 0x880ebd63, S=1, 1024, 0xecb30526 -0, 162, 162, 1, 19073, 0x055f02e3, S=1, 1024, 0xecb30526 -0, 163, 163, 1, 19168, 0xcc2c02d7, S=1, 1024, 0xecb30526 -0, 164, 164, 1, 19210, 0xa538ffc1, S=1, 1024, 0xecb30526 -0, 165, 165, 1, 19398, 0x4777644d, S=1, 1024, 0xecb30526 -0, 166, 166, 1, 19480, 0xcb2aa0fa, S=1, 1024, 0xecb30526 -0, 167, 167, 1, 19659, 0xe3c1122d, S=1, 1024, 0xecb30526 -0, 168, 168, 1, 19672, 0x1d1e193f, S=1, 1024, 0xecb30526 -0, 169, 169, 1, 19936, 0xcd036346, S=1, 1024, 0xecb30526 -0, 170, 170, 1, 19975, 0x96529b21, S=1, 1024, 0xecb30526 -0, 171, 171, 1, 20021, 0xcdaf8bb5, S=1, 1024, 0xecb30526 -0, 172, 172, 1, 20060, 0x1cea7784, S=1, 1024, 0xecb30526 +0, 0, 0, 1, 1297, 0x5618fe71 +0, 1, 1, 1, 221, 0x230c4e66, F=0x0 +0, 2, 2, 1, 139, 0xf87a2b65, F=0x0 +0, 3, 3, 1, 392, 0x7794a5e6, F=0x0 +0, 4, 4, 1, 389, 0xf856a3f1, F=0x0 +0, 5, 5, 1, 438, 0x0f95b4fb, F=0x0 +0, 6, 6, 1, 526, 0x7885d860, F=0x0 +0, 7, 7, 1, 543, 0x859fe7df, F=0x0 +0, 8, 8, 1, 446, 0xb34dba74, F=0x0 +0, 9, 9, 1, 931, 0x1c2fa48d, F=0x0 +0, 10, 10, 1, 702, 0x1ce74b4d, F=0x0 +0, 11, 11, 1, 1202, 0x2f232db8, F=0x0 +0, 12, 12, 1, 1299, 0x904e56af, F=0x0 +0, 13, 13, 1, 1253, 0x20803653, F=0x0 +0, 14, 14, 1, 1338, 0x24e052f6, F=0x0 +0, 15, 15, 1, 1284, 0x590a3a42, F=0x0 +0, 16, 16, 1, 1483, 0x93e09883, F=0x0 +0, 17, 17, 1, 1792, 0x70984bdf, F=0x0 +0, 18, 18, 1, 1683, 0x23b9fc30, F=0x0 +0, 19, 19, 1, 1517, 0x0fc1acf6, F=0x0 +0, 20, 20, 1, 1713, 0x6b4c1861, F=0x0 +0, 21, 21, 1, 1753, 0x896b20c1, F=0x0 +0, 22, 22, 1, 1650, 0x2f26027f, F=0x0 +0, 23, 23, 1, 1726, 0x9f731df0, F=0x0 +0, 24, 24, 1, 1908, 0xebd67b41, F=0x0 +0, 25, 25, 1, 1815, 0xf2685278, F=0x0 +0, 26, 26, 1, 1923, 0xbe18821e, F=0x0 +0, 27, 27, 1, 2108, 0x1318d306, F=0x0 +0, 28, 28, 1, 2708, 0x5e28f23c, F=0x0 +0, 29, 29, 1, 2681, 0xb96da855, F=0x0 +0, 30, 30, 1, 2903, 0x61cf4983, F=0x0 +0, 31, 31, 1, 3265, 0x95a1d25d, F=0x0 +0, 32, 32, 1, 3187, 0x6a67c299, F=0x0 +0, 33, 33, 1, 3304, 0x1c5ce63e, F=0x0 +0, 34, 34, 1, 3608, 0x2ed2770f, F=0x0 +0, 35, 35, 1, 3707, 0xa075a17b, F=0x0 +0, 36, 36, 1, 3822, 0xc842d6b6, F=0x0 +0, 37, 37, 1, 3635, 0x814680c7, F=0x0 +0, 38, 38, 1, 2958, 0x64de62cf, F=0x0 +0, 39, 39, 1, 3094, 0x2c338e84, F=0x0 +0, 40, 40, 1, 3102, 0xec5e8757, F=0x0 +0, 41, 41, 1, 3464, 0xea4f2bce, F=0x0 +0, 42, 42, 1, 4116, 0xded05ff3, F=0x0 +0, 43, 43, 1, 4225, 0x21825a2c, F=0x0 +0, 44, 44, 1, 3621, 0xa3125130, F=0x0 +0, 45, 45, 1, 3918, 0x35e0e876, F=0x0 +0, 46, 46, 1, 4469, 0xa408e1f7, F=0x0 +0, 47, 47, 1, 4601, 0x6f7d3081, F=0x0 +0, 48, 48, 1, 4830, 0x023e9cab, F=0x0 +0, 49, 49, 1, 5406, 0xf67ac12c, F=0x0 +0, 50, 50, 1, 5274, 0xf14e9768, F=0x0 +0, 51, 51, 1, 5424, 0x2af8e2a7, F=0x0 +0, 52, 52, 1, 5527, 0x80f70710, F=0x0 +0, 53, 53, 1, 5709, 0x89975c2f, F=0x0 +0, 54, 54, 1, 6168, 0xf5a542af, F=0x0 +0, 55, 55, 1, 6241, 0x091651ad, F=0x0 +0, 56, 56, 1, 5919, 0x32a7c5a2, F=0x0 +0, 57, 57, 1, 6005, 0x88adf6be, F=0x0 +0, 58, 58, 1, 5954, 0x3f92f18d, F=0x0 +0, 59, 59, 1, 6476, 0x9d90d099, F=0x0 +0, 60, 60, 1, 6745, 0xdf4f3cb1, F=0x0 +0, 61, 61, 1, 6283, 0x6e7e8f63, F=0x0 +0, 62, 62, 1, 6649, 0x5c1f366c, F=0x0 +0, 63, 63, 1, 6386, 0xa09389c3, F=0x0 +0, 64, 64, 1, 6265, 0xe5b85888, F=0x0 +0, 65, 65, 1, 6916, 0x445e734f, F=0x0 +0, 66, 66, 1, 7238, 0x30a52626, F=0x0 +0, 67, 67, 1, 7564, 0x1ddaa7cc, F=0x0 +0, 68, 68, 1, 7421, 0x118e7850, F=0x0 +0, 69, 69, 1, 7484, 0x5459acd8, F=0x0 +0, 70, 70, 1, 7604, 0x66f9e6a5, F=0x0 +0, 71, 71, 1, 7764, 0x862c0630, F=0x0 +0, 72, 72, 1, 8023, 0x06e16db8, F=0x0 +0, 73, 73, 1, 8136, 0xce28c084, F=0x0 +0, 74, 74, 1, 8109, 0x61c4aef6, F=0x0 +0, 75, 75, 1, 7871, 0x631d4073, F=0x0 +0, 76, 76, 1, 7968, 0x3b7692f0, F=0x0 +0, 77, 77, 1, 8246, 0x531bebc2, F=0x0 +0, 78, 78, 1, 8329, 0xe1fd48c9, F=0x0 +0, 79, 79, 1, 8570, 0x996fc156, F=0x0 +0, 80, 80, 1, 8754, 0x99fb0c5a, F=0x0 +0, 81, 81, 1, 8586, 0xf3eba620, F=0x0 +0, 82, 82, 1, 8886, 0xa08258a9, F=0x0 +0, 83, 83, 1, 9085, 0x229359d3, F=0x0 +0, 84, 84, 1, 9318, 0x3baaf9b9, F=0x0 +0, 85, 85, 1, 9402, 0xe27a4804, F=0x0 +0, 86, 86, 1, 9169, 0x23fd9a49, F=0x0 +0, 87, 87, 1, 9470, 0xe389379c, F=0x0 +0, 88, 88, 1, 9658, 0x6a409434, F=0x0 +0, 89, 89, 1, 9709, 0x42969ccd, F=0x0 +0, 90, 90, 1, 9531, 0x473139f3, F=0x0 +0, 91, 91, 1, 9899, 0xb85e0cd0, F=0x0 +0, 92, 92, 1, 10013, 0xda4d4db8, F=0x0 +0, 93, 93, 1, 10046, 0x0cc12baa, F=0x0 +0, 94, 94, 1, 10094, 0x22b6451c, F=0x0 +0, 95, 95, 1, 10446, 0x03a604aa, F=0x0 +0, 96, 96, 1, 10591, 0x3c8d599a, F=0x0 +0, 97, 97, 1, 10589, 0x3936826f, F=0x0 +0, 98, 98, 1, 10815, 0xb795dc11, F=0x0 +0, 99, 99, 1, 11119, 0x506c5187, F=0x0 +0, 100, 100, 1, 11202, 0x92856baf, F=0x0 +0, 101, 101, 1, 11248, 0xdf29a1db, F=0x0 +0, 102, 102, 1, 11491, 0x656df632, F=0x0 +0, 103, 103, 1, 11688, 0xeb175aa9, F=0x0 +0, 104, 104, 1, 11793, 0x99ccb713, F=0x0 +0, 105, 105, 1, 11444, 0x602c0c0d, F=0x0 +0, 106, 106, 1, 11936, 0xe89cc9bd, F=0x0 +0, 107, 107, 1, 11940, 0xc668bf2f, F=0x0 +0, 108, 108, 1, 12289, 0x9bd5780d, F=0x0 +0, 109, 109, 1, 12342, 0xd9c680fb, F=0x0 +0, 110, 110, 1, 12460, 0xb539b50f, F=0x0 +0, 111, 111, 1, 12703, 0x07473fac, F=0x0 +0, 112, 112, 1, 12676, 0x743052ae, F=0x0 +0, 113, 113, 1, 12965, 0xf6aaa045, F=0x0 +0, 114, 114, 1, 13062, 0xea13e513, F=0x0 +0, 115, 115, 1, 13155, 0x82312fa0, F=0x0 +0, 116, 116, 1, 13179, 0xd59c1dda, F=0x0 +0, 117, 117, 1, 13206, 0xde825850, F=0x0 +0, 118, 118, 1, 13219, 0x0b375f69, F=0x0 +0, 119, 119, 1, 13218, 0x14036301, F=0x0 +0, 120, 120, 1, 13475, 0x259da599, F=0x0 +0, 121, 121, 1, 13673, 0x9b43dd2a, F=0x0 +0, 122, 122, 1, 13700, 0x190bebf1, F=0x0 +0, 123, 123, 1, 13829, 0x9f802c28, F=0x0 +0, 124, 124, 1, 13954, 0x5236926c, F=0x0 +0, 125, 125, 1, 14071, 0xf5c3d36a, F=0x0 +0, 126, 126, 1, 14132, 0xbf35cdb9, F=0x0 +0, 127, 127, 1, 14339, 0x9cf65120, F=0x0 +0, 128, 128, 1, 14477, 0x3a9eabb7, F=0x0 +0, 129, 129, 1, 14544, 0xed09a2d3, F=0x0 +0, 130, 130, 1, 14616, 0xa138d2a0, F=0x0 +0, 131, 131, 1, 14906, 0x13bd28eb, F=0x0 +0, 132, 132, 1, 14986, 0x5454a127, F=0x0 +0, 133, 133, 1, 15150, 0x585cdb9b, F=0x0 +0, 134, 134, 1, 15137, 0x191bbaae, F=0x0 +0, 135, 135, 1, 15251, 0xa8461431, F=0x0 +0, 136, 136, 1, 15345, 0x2015670e, F=0x0 +0, 137, 137, 1, 15646, 0x772da02d, F=0x0 +0, 138, 138, 1, 15920, 0xfabc27f3, F=0x0 +0, 139, 139, 1, 16049, 0x2a66498f, F=0x0 +0, 140, 140, 1, 16236, 0x29750328, F=0x0 +0, 141, 141, 1, 16270, 0x4528e71c, F=0x0 +0, 142, 142, 1, 16379, 0x9a450fab, F=0x0 +0, 143, 143, 1, 16669, 0x31ffaac8, F=0x0 +0, 144, 144, 1, 16925, 0x6c4318ac, F=0x0 +0, 145, 145, 1, 17157, 0xf4b1cf0c, F=0x0 +0, 146, 146, 1, 17180, 0xd1bab36c, F=0x0 +0, 147, 147, 1, 17323, 0x419eaee3, F=0x0 +0, 148, 148, 1, 17405, 0xdf3f16ee, F=0x0 +0, 149, 149, 1, 17439, 0x7153f9f8, F=0x0 +0, 150, 150, 1, 17584, 0x1612557d, F=0x0 +0, 151, 151, 1, 17772, 0xffa78d73, F=0x0 +0, 152, 152, 1, 17834, 0x3e33866a, F=0x0 +0, 153, 153, 1, 17926, 0xdfc39bcd, F=0x0 +0, 154, 154, 1, 17831, 0x5f8ebc12, F=0x0 +0, 155, 155, 1, 18150, 0xc25e1f7f, F=0x0 +0, 156, 156, 1, 18265, 0x9b688807, F=0x0 +0, 157, 157, 1, 18345, 0xdc6abd59, F=0x0 +0, 158, 158, 1, 18301, 0x14d43a0e, F=0x0 +0, 159, 159, 1, 18426, 0x3b2cbcde, F=0x0 +0, 160, 160, 1, 18615, 0x6fa5492e, F=0x0 +0, 161, 161, 1, 18924, 0xa370be9b, F=0x0 +0, 162, 162, 1, 19081, 0xe019041b, F=0x0 +0, 163, 163, 1, 19176, 0x1acc040f, F=0x0 +0, 164, 164, 1, 19218, 0x27080108, F=0x0 +0, 165, 165, 1, 19406, 0xae676585, F=0x0 +0, 166, 166, 1, 19488, 0x9619a232, F=0x0 +0, 167, 167, 1, 19667, 0x88e71365, F=0x0 +0, 168, 168, 1, 19680, 0xd20d1a77, F=0x0 +0, 169, 169, 1, 19944, 0xc3d0647e, F=0x0 +0, 170, 170, 1, 19983, 0xbca79c59, F=0x0 +0, 171, 171, 1, 20029, 0x2c238ced, F=0x0 +0, 172, 172, 1, 20068, 0xaad778bc, F=0x0 diff --git a/tests/ref/fate/gifenc-rgb8 b/tests/ref/fate/gifenc-rgb8 index 490e4d0b1..c5ff394d9 100644 --- a/tests/ref/fate/gifenc-rgb8 +++ b/tests/ref/fate/gifenc-rgb8 @@ -3,176 +3,176 @@ #codec_id 0: gif #dimensions 0: 217x217 #sar 0: 0/1 -0, 0, 0, 1, 552, 0x47602c6c -0, 1, 1, 1, 297, 0x49dd8847, S=1, 1024, 0xcfc8799f -0, 2, 2, 1, 438, 0x4776d352, S=1, 1024, 0xcfc8799f -0, 3, 3, 1, 450, 0x2254d187, S=1, 1024, 0xcfc8799f -0, 4, 4, 1, 547, 0xe16104bc, S=1, 1024, 0xcfc8799f -0, 5, 5, 1, 614, 0x0fdc2027, S=1, 1024, 0xcfc8799f -0, 6, 6, 1, 642, 0xa0af1edf, S=1, 1024, 0xcfc8799f -0, 7, 7, 1, 660, 0xd0763931, S=1, 1024, 0xcfc8799f -0, 8, 8, 1, 821, 0xc38f7fac, S=1, 1024, 0xcfc8799f -0, 9, 9, 1, 1157, 0x4c112ecd, S=1, 1024, 0xcfc8799f -0, 10, 10, 1, 179, 0x0690541c, S=1, 1024, 0xcfc8799f -0, 11, 11, 1, 1333, 0x216f70a7, S=1, 1024, 0xcfc8799f -0, 12, 12, 1, 1638, 0x901c093d, S=1, 1024, 0xcfc8799f -0, 13, 13, 1, 1531, 0xc9bae5ff, S=1, 1024, 0xcfc8799f -0, 14, 14, 1, 1720, 0xce854743, S=1, 1024, 0xcfc8799f -0, 15, 15, 1, 1910, 0x2690866d, S=1, 1024, 0xcfc8799f -0, 16, 16, 1, 2124, 0xa586dad0, S=1, 1024, 0xcfc8799f -0, 17, 17, 1, 2248, 0x9ddc2a88, S=1, 1024, 0xcfc8799f -0, 18, 18, 1, 2311, 0xd64235af, S=1, 1024, 0xcfc8799f -0, 19, 19, 1, 2408, 0xe2a66cc9, S=1, 1024, 0xcfc8799f -0, 20, 20, 1, 2601, 0xeab6c267, S=1, 1024, 0xcfc8799f -0, 21, 21, 1, 2687, 0xfe1d0311, S=1, 1024, 0xcfc8799f -0, 22, 22, 1, 2784, 0xca600dee, S=1, 1024, 0xcfc8799f -0, 23, 23, 1, 2884, 0xc7134b99, S=1, 1024, 0xcfc8799f -0, 24, 24, 1, 2982, 0x0b1e7825, S=1, 1024, 0xcfc8799f -0, 25, 25, 1, 3101, 0x3e029e0e, S=1, 1024, 0xcfc8799f -0, 26, 26, 1, 3253, 0x846af678, S=1, 1024, 0xcfc8799f -0, 27, 27, 1, 3329, 0x29a81b71, S=1, 1024, 0xcfc8799f -0, 28, 28, 1, 3572, 0xa3e08a52, S=1, 1024, 0xcfc8799f -0, 29, 29, 1, 3807, 0x18e1fed2, S=1, 1024, 0xcfc8799f -0, 30, 30, 1, 2750, 0xff6e1f9e, S=1, 1024, 0xcfc8799f -0, 31, 31, 1, 4031, 0x6d4f7329, S=1, 1024, 0xcfc8799f -0, 32, 32, 1, 3025, 0xb43c9e94, S=1, 1024, 0xcfc8799f -0, 33, 33, 1, 4295, 0xc1850a80, S=1, 1024, 0xcfc8799f -0, 34, 34, 1, 2044, 0x0440c072, S=1, 1024, 0xcfc8799f -0, 35, 35, 1, 3212, 0xe91af08f, S=1, 1024, 0xcfc8799f -0, 36, 36, 1, 2292, 0x6765633e, S=1, 1024, 0xcfc8799f -0, 37, 37, 1, 3633, 0xac779aa3, S=1, 1024, 0xcfc8799f -0, 38, 38, 1, 3552, 0xed2c75b2, S=1, 1024, 0xcfc8799f -0, 39, 39, 1, 3690, 0x2020dd0d, S=1, 1024, 0xcfc8799f -0, 40, 40, 1, 1559, 0x596ef330, S=1, 1024, 0xcfc8799f -0, 41, 41, 1, 954, 0xac12c9c5, S=1, 1024, 0xcfc8799f -0, 42, 42, 1, 273, 0x138c7831, S=1, 1024, 0xcfc8799f -0, 43, 43, 1, 930, 0xf1c3ae3f, S=1, 1024, 0xcfc8799f -0, 44, 44, 1, 271, 0x921a80af, S=1, 1024, 0xcfc8799f -0, 45, 45, 1, 196, 0xa5de5322, S=1, 1024, 0xcfc8799f -0, 46, 46, 1, 4299, 0x5bac0d86, S=1, 1024, 0xcfc8799f -0, 47, 47, 1, 4895, 0xc43639a6, S=1, 1024, 0xcfc8799f -0, 48, 48, 1, 4928, 0xf17d13e8, S=1, 1024, 0xcfc8799f -0, 49, 49, 1, 4941, 0x71915520, S=1, 1024, 0xcfc8799f -0, 50, 50, 1, 4154, 0xc860b8a6, S=1, 1024, 0xcfc8799f -0, 51, 51, 1, 4678, 0x2651c339, S=1, 1024, 0xcfc8799f -0, 52, 52, 1, 4741, 0xffd6bb45, S=1, 1024, 0xcfc8799f -0, 53, 53, 1, 4982, 0x132c5977, S=1, 1024, 0xcfc8799f -0, 54, 54, 1, 5179, 0x97aac3a1, S=1, 1024, 0xcfc8799f -0, 55, 55, 1, 5046, 0x836a80cd, S=1, 1024, 0xcfc8799f -0, 56, 56, 1, 5140, 0xa725c1e7, S=1, 1024, 0xcfc8799f -0, 57, 57, 1, 4301, 0x0203f239, S=1, 1024, 0xcfc8799f -0, 58, 58, 1, 5079, 0xb2e7a2de, S=1, 1024, 0xcfc8799f -0, 59, 59, 1, 5284, 0xb757dfe1, S=1, 1024, 0xcfc8799f -0, 60, 60, 1, 5426, 0xf9f11e57, S=1, 1024, 0xcfc8799f -0, 61, 61, 1, 4645, 0xf0f289e1, S=1, 1024, 0xcfc8799f -0, 62, 62, 1, 5263, 0x8617d7e9, S=1, 1024, 0xcfc8799f -0, 63, 63, 1, 5221, 0x26e3ca43, S=1, 1024, 0xcfc8799f -0, 64, 64, 1, 5217, 0x90989cfb, S=1, 1024, 0xcfc8799f -0, 65, 65, 1, 5395, 0xe29a01cb, S=1, 1024, 0xcfc8799f -0, 66, 66, 1, 5220, 0xe2dee355, S=1, 1024, 0xcfc8799f -0, 67, 67, 1, 5704, 0xcfbcd55e, S=1, 1024, 0xcfc8799f -0, 68, 68, 1, 5636, 0x7fc2a1e5, S=1, 1024, 0xcfc8799f -0, 69, 69, 1, 5818, 0x6090ebbd, S=1, 1024, 0xcfc8799f -0, 70, 70, 1, 5763, 0xc110c791, S=1, 1024, 0xcfc8799f -0, 71, 71, 1, 6116, 0xb4ee8e30, S=1, 1024, 0xcfc8799f -0, 72, 72, 1, 6069, 0x21b263db, S=1, 1024, 0xcfc8799f -0, 73, 73, 1, 5796, 0x2514df52, S=1, 1024, 0xcfc8799f -0, 74, 74, 1, 5999, 0x1c3c3701, S=1, 1024, 0xcfc8799f -0, 75, 75, 1, 6220, 0x8340b150, S=1, 1024, 0xcfc8799f -0, 76, 76, 1, 6374, 0x00d8eaa5, S=1, 1024, 0xcfc8799f -0, 77, 77, 1, 6465, 0x74c4778a, S=1, 1024, 0xcfc8799f -0, 78, 78, 1, 7019, 0xdb1a28a3, S=1, 1024, 0xcfc8799f -0, 79, 79, 1, 7255, 0x1e19b76e, S=1, 1024, 0xcfc8799f -0, 80, 80, 1, 8197, 0x26bc6a79, S=1, 1024, 0xcfc8799f -0, 81, 81, 1, 8358, 0x118781e0, S=1, 1024, 0xcfc8799f -0, 82, 82, 1, 7708, 0xfc0c963d, S=1, 1024, 0xcfc8799f -0, 83, 83, 1, 7412, 0xdcc311ee, S=1, 1024, 0xcfc8799f -0, 84, 84, 1, 7541, 0x4d2819c1, S=1, 1024, 0xcfc8799f -0, 85, 85, 1, 7948, 0xf12eca3d, S=1, 1024, 0xcfc8799f -0, 86, 86, 1, 8408, 0x43add468, S=1, 1024, 0xcfc8799f -0, 87, 87, 1, 8056, 0x2d162377, S=1, 1024, 0xcfc8799f -0, 88, 88, 1, 7401, 0x26ebb649, S=1, 1024, 0xcfc8799f -0, 89, 89, 1, 7494, 0x35fcf9ae, S=1, 1024, 0xcfc8799f -0, 90, 90, 1, 7806, 0x4238723d, S=1, 1024, 0xcfc8799f -0, 91, 91, 1, 7768, 0xb01e795a, S=1, 1024, 0xcfc8799f -0, 92, 92, 1, 7749, 0x6ab39c12, S=1, 1024, 0xcfc8799f -0, 93, 93, 1, 8047, 0x0e5f24aa, S=1, 1024, 0xcfc8799f -0, 94, 94, 1, 7618, 0xd787340f, S=1, 1024, 0xcfc8799f -0, 95, 95, 1, 7979, 0x0824c4df, S=1, 1024, 0xcfc8799f -0, 96, 96, 1, 12062, 0xc46d9d92, S=1, 1024, 0xcfc8799f -0, 97, 97, 1, 12317, 0x1314dc0c, S=1, 1024, 0xcfc8799f -0, 98, 98, 1, 12217, 0x78c2ed30, S=1, 1024, 0xcfc8799f -0, 99, 99, 1, 11227, 0x2a578eb9, S=1, 1024, 0xcfc8799f -0, 100, 100, 1, 11108, 0x4eaa068c, S=1, 1024, 0xcfc8799f -0, 101, 101, 1, 11366, 0x48f8993f, S=1, 1024, 0xcfc8799f -0, 102, 102, 1, 11896, 0x32414841, S=1, 1024, 0xcfc8799f -0, 103, 103, 1, 11479, 0xeaa38225, S=1, 1024, 0xcfc8799f -0, 104, 104, 1, 13395, 0xaa9d4c72, S=1, 1024, 0xcfc8799f -0, 105, 105, 1, 12913, 0x28854353, S=1, 1024, 0xcfc8799f -0, 106, 106, 1, 13864, 0x663df630, S=1, 1024, 0xcfc8799f -0, 107, 107, 1, 13551, 0xf7ba7be7, S=1, 1024, 0xcfc8799f -0, 108, 108, 1, 14041, 0x2dc071b9, S=1, 1024, 0xcfc8799f -0, 109, 109, 1, 14144, 0x33a03d1d, S=1, 1024, 0xcfc8799f -0, 110, 110, 1, 14277, 0x6bda5935, S=1, 1024, 0xcfc8799f -0, 111, 111, 1, 14424, 0xa696efd8, S=1, 1024, 0xcfc8799f -0, 112, 112, 1, 14689, 0x8e3ad12c, S=1, 1024, 0xcfc8799f -0, 113, 113, 1, 14598, 0x544668b4, S=1, 1024, 0xcfc8799f -0, 114, 114, 1, 15213, 0x60009558, S=1, 1024, 0xcfc8799f -0, 115, 115, 1, 15425, 0x86e5adf4, S=1, 1024, 0xcfc8799f -0, 116, 116, 1, 15595, 0x878d09b9, S=1, 1024, 0xcfc8799f -0, 117, 117, 1, 15598, 0x10daabc4, S=1, 1024, 0xcfc8799f -0, 118, 118, 1, 15863, 0x2462016c, S=1, 1024, 0xcfc8799f -0, 119, 119, 1, 15717, 0xe05041c4, S=1, 1024, 0xcfc8799f -0, 120, 120, 1, 16078, 0x7c8f3a8c, S=1, 1024, 0xcfc8799f -0, 121, 121, 1, 16225, 0x9771a52e, S=1, 1024, 0xcfc8799f -0, 122, 122, 1, 16135, 0x2dfc1692, S=1, 1024, 0xcfc8799f -0, 123, 123, 1, 16661, 0x09c96d7e, S=1, 1024, 0xcfc8799f -0, 124, 124, 1, 16619, 0xc4735b56, S=1, 1024, 0xcfc8799f -0, 125, 125, 1, 16829, 0x589dc13f, S=1, 1024, 0xcfc8799f -0, 126, 126, 1, 16944, 0x997cd18f, S=1, 1024, 0xcfc8799f -0, 127, 127, 1, 17119, 0x6c396b60, S=1, 1024, 0xcfc8799f -0, 128, 128, 1, 17150, 0x8e603d31, S=1, 1024, 0xcfc8799f -0, 129, 129, 1, 17321, 0x0bbcee5a, S=1, 1024, 0xcfc8799f -0, 130, 130, 1, 17395, 0x99f0c974, S=1, 1024, 0xcfc8799f -0, 131, 131, 1, 17666, 0x37184223, S=1, 1024, 0xcfc8799f -0, 132, 132, 1, 17730, 0xa0d385b3, S=1, 1024, 0xcfc8799f -0, 133, 133, 1, 17934, 0xb22cc97d, S=1, 1024, 0xcfc8799f -0, 134, 134, 1, 17944, 0x0cd309c6, S=1, 1024, 0xcfc8799f -0, 135, 135, 1, 18238, 0x6b7e3237, S=1, 1024, 0xcfc8799f -0, 136, 136, 1, 18391, 0x4df3c48a, S=1, 1024, 0xcfc8799f -0, 137, 137, 1, 18543, 0x90a2f238, S=1, 1024, 0xcfc8799f -0, 138, 138, 1, 18939, 0xc57dda5b, S=1, 1024, 0xcfc8799f -0, 139, 139, 1, 19145, 0x1267294a, S=1, 1024, 0xcfc8799f -0, 140, 140, 1, 19120, 0xeac6a9c3, S=1, 1024, 0xcfc8799f -0, 141, 141, 1, 19130, 0x31f3edbc, S=1, 1024, 0xcfc8799f -0, 142, 142, 1, 19494, 0x3259a2f3, S=1, 1024, 0xcfc8799f -0, 143, 143, 1, 19534, 0xda22a752, S=1, 1024, 0xcfc8799f -0, 144, 144, 1, 19747, 0x8805c379, S=1, 1024, 0xcfc8799f -0, 145, 145, 1, 20114, 0xaaf96864, S=1, 1024, 0xcfc8799f -0, 146, 146, 1, 20257, 0x7223da26, S=1, 1024, 0xcfc8799f -0, 147, 147, 1, 20370, 0x08ef382a, S=1, 1024, 0xcfc8799f -0, 148, 148, 1, 20292, 0x4b47f207, S=1, 1024, 0xcfc8799f -0, 149, 149, 1, 20491, 0xeedd6d1c, S=1, 1024, 0xcfc8799f -0, 150, 150, 1, 20647, 0xb0d1dd45, S=1, 1024, 0xcfc8799f -0, 151, 151, 1, 20666, 0x382cc8a4, S=1, 1024, 0xcfc8799f -0, 152, 152, 1, 21007, 0x398f4f7d, S=1, 1024, 0xcfc8799f -0, 153, 153, 1, 21058, 0xd6616a9d, S=1, 1024, 0xcfc8799f -0, 154, 154, 1, 21153, 0x988749db, S=1, 1024, 0xcfc8799f -0, 155, 155, 1, 21078, 0x1b328059, S=1, 1024, 0xcfc8799f -0, 156, 156, 1, 21458, 0x6348529c, S=1, 1024, 0xcfc8799f -0, 157, 157, 1, 21669, 0xcf63e2de, S=1, 1024, 0xcfc8799f -0, 158, 158, 1, 21581, 0x1fc021af, S=1, 1024, 0xcfc8799f -0, 159, 159, 1, 21654, 0x899dab18, S=1, 1024, 0xcfc8799f -0, 160, 160, 1, 21987, 0x634086fe, S=1, 1024, 0xcfc8799f -0, 161, 161, 1, 22205, 0x617a7335, S=1, 1024, 0xcfc8799f -0, 162, 162, 1, 22475, 0x9fa2e01c, S=1, 1024, 0xcfc8799f -0, 163, 163, 1, 22490, 0x7dc5376c, S=1, 1024, 0xcfc8799f -0, 164, 164, 1, 22460, 0x33e6bbfe, S=1, 1024, 0xcfc8799f -0, 165, 165, 1, 22861, 0x18993510, S=1, 1024, 0xcfc8799f -0, 166, 166, 1, 22746, 0xdff85615, S=1, 1024, 0xcfc8799f -0, 167, 167, 1, 23165, 0xf0ac66a3, S=1, 1024, 0xcfc8799f -0, 168, 168, 1, 23273, 0x13869ad9, S=1, 1024, 0xcfc8799f -0, 169, 169, 1, 23211, 0xd30b6205, S=1, 1024, 0xcfc8799f -0, 170, 170, 1, 23648, 0xa0cef01b, S=1, 1024, 0xcfc8799f -0, 171, 171, 1, 23675, 0x760460b9, S=1, 1024, 0xcfc8799f -0, 172, 172, 1, 23874, 0xacf998c5, S=1, 1024, 0xcfc8799f +0, 0, 0, 1, 1341, 0xaa85adb1 +0, 1, 1, 1, 305, 0xa970896f, F=0x0 +0, 2, 2, 1, 446, 0x4a20d47a, F=0x0 +0, 3, 3, 1, 458, 0x32ded2af, F=0x0 +0, 4, 4, 1, 555, 0x622205e4, F=0x0 +0, 5, 5, 1, 622, 0xde06214f, F=0x0 +0, 6, 6, 1, 650, 0x8f482007, F=0x0 +0, 7, 7, 1, 668, 0xd3df3a59, F=0x0 +0, 8, 8, 1, 829, 0x812f80d4, F=0x0 +0, 9, 9, 1, 1165, 0x8e402ff5, F=0x0 +0, 10, 10, 1, 187, 0xdda45544, F=0x0 +0, 11, 11, 1, 1341, 0x2f2d71cf, F=0x0 +0, 12, 12, 1, 1646, 0xfe910a65, F=0x0 +0, 13, 13, 1, 1539, 0xbc77e727, F=0x0 +0, 14, 14, 1, 1728, 0x9bd9486b, F=0x0 +0, 15, 15, 1, 1918, 0xcf948795, F=0x0 +0, 16, 16, 1, 2132, 0x4618dbf8, F=0x0 +0, 17, 17, 1, 2256, 0xcdce2bb0, F=0x0 +0, 18, 18, 1, 2319, 0x4f1b36d7, F=0x0 +0, 19, 19, 1, 2416, 0xcba76df1, F=0x0 +0, 20, 20, 1, 2609, 0xb2eec38f, F=0x0 +0, 21, 21, 1, 2695, 0x29d40439, F=0x0 +0, 22, 22, 1, 2792, 0x663f0f16, F=0x0 +0, 23, 23, 1, 2892, 0xd6924cc1, F=0x0 +0, 24, 24, 1, 2990, 0x8bed794d, F=0x0 +0, 25, 25, 1, 3109, 0x48789f36, F=0x0 +0, 26, 26, 1, 3261, 0x3eaff7a0, F=0x0 +0, 27, 27, 1, 3337, 0x3bcd1c99, F=0x0 +0, 28, 28, 1, 3580, 0xcf0c8b7a, F=0x0 +0, 29, 29, 1, 3815, 0x53d40009, F=0x0 +0, 30, 30, 1, 2758, 0x73fd20c6, F=0x0 +0, 31, 31, 1, 4039, 0xab517451, F=0x0 +0, 32, 32, 1, 3033, 0x66d29fbc, F=0x0 +0, 33, 33, 1, 4303, 0x30e50ba8, F=0x0 +0, 34, 34, 1, 2052, 0x4843c19a, F=0x0 +0, 35, 35, 1, 3220, 0x73f7f1b7, F=0x0 +0, 36, 36, 1, 2300, 0xca376466, F=0x0 +0, 37, 37, 1, 3641, 0x1e3a9bcb, F=0x0 +0, 38, 38, 1, 3560, 0x014776da, F=0x0 +0, 39, 39, 1, 3698, 0xd3bcde35, F=0x0 +0, 40, 40, 1, 1567, 0x6c8bf458, F=0x0 +0, 41, 41, 1, 962, 0x0389caed, F=0x0 +0, 42, 42, 1, 281, 0x575f7959, F=0x0 +0, 43, 43, 1, 938, 0x2d7aaf67, F=0x0 +0, 44, 44, 1, 279, 0xd39d81d7, F=0x0 +0, 45, 45, 1, 204, 0x90a9544a, F=0x0 +0, 46, 46, 1, 4307, 0xcf9d0eae, F=0x0 +0, 47, 47, 1, 4903, 0xe9743ace, F=0x0 +0, 48, 48, 1, 4936, 0x3cf21510, F=0x0 +0, 49, 49, 1, 4949, 0xcbff5648, F=0x0 +0, 50, 50, 1, 4162, 0x94a9b9ce, F=0x0 +0, 51, 51, 1, 4686, 0x5098c461, F=0x0 +0, 52, 52, 1, 4749, 0x7304bc6d, F=0x0 +0, 53, 53, 1, 4990, 0x9d025a9f, F=0x0 +0, 54, 54, 1, 5187, 0x0566c4c9, F=0x0 +0, 55, 55, 1, 5054, 0x574f81f5, F=0x0 +0, 56, 56, 1, 5148, 0xe7bac30f, F=0x0 +0, 57, 57, 1, 4309, 0x7844f361, F=0x0 +0, 58, 58, 1, 5087, 0xacf4a406, F=0x0 +0, 59, 59, 1, 5292, 0x9e7be109, F=0x0 +0, 60, 60, 1, 5434, 0x85541f7f, F=0x0 +0, 61, 61, 1, 4653, 0xf5118b09, F=0x0 +0, 62, 62, 1, 5271, 0x54f3d911, F=0x0 +0, 63, 63, 1, 5229, 0xc520cb6b, F=0x0 +0, 64, 64, 1, 5225, 0x2a449e23, F=0x0 +0, 65, 65, 1, 5403, 0x4a2502f3, F=0x0 +0, 66, 66, 1, 5228, 0x8002e47d, F=0x0 +0, 67, 67, 1, 5712, 0x9c9ed686, F=0x0 +0, 68, 68, 1, 5644, 0xfdf5a30d, F=0x0 +0, 69, 69, 1, 5826, 0xb142ece5, F=0x0 +0, 70, 70, 1, 5771, 0xd22ac8b9, F=0x0 +0, 71, 71, 1, 6124, 0x5e4e8f58, F=0x0 +0, 72, 72, 1, 6077, 0x94ab6503, F=0x0 +0, 73, 73, 1, 5804, 0x5c56e07a, F=0x0 +0, 74, 74, 1, 6007, 0x3e453829, F=0x0 +0, 75, 75, 1, 6228, 0xa4e0b278, F=0x0 +0, 76, 76, 1, 6382, 0xd488ebcd, F=0x0 +0, 77, 77, 1, 6473, 0xb1bb78b2, F=0x0 +0, 78, 78, 1, 7027, 0x98ce29cb, F=0x0 +0, 79, 79, 1, 7263, 0xecadb896, F=0x0 +0, 80, 80, 1, 8205, 0x36cb6ba1, F=0x0 +0, 81, 81, 1, 8366, 0xdbbe8308, F=0x0 +0, 82, 82, 1, 7716, 0xd6959765, F=0x0 +0, 83, 83, 1, 7420, 0x60fd1316, F=0x0 +0, 84, 84, 1, 7549, 0x668a1ae9, F=0x0 +0, 85, 85, 1, 7956, 0xe146cb65, F=0x0 +0, 86, 86, 1, 8416, 0x47c3d590, F=0x0 +0, 87, 87, 1, 8064, 0x9a0e249f, F=0x0 +0, 88, 88, 1, 7409, 0x9e5eb771, F=0x0 +0, 89, 89, 1, 7502, 0x1906fad6, F=0x0 +0, 90, 90, 1, 7814, 0x8e117365, F=0x0 +0, 91, 91, 1, 7776, 0xd0077a82, F=0x0 +0, 92, 92, 1, 7757, 0x74a49d3a, F=0x0 +0, 93, 93, 1, 8055, 0x70ef25d2, F=0x0 +0, 94, 94, 1, 7626, 0x4a003537, F=0x0 +0, 95, 95, 1, 7987, 0x1c14c607, F=0x0 +0, 96, 96, 1, 12070, 0x4a729eba, F=0x0 +0, 97, 97, 1, 12325, 0xbff1dd34, F=0x0 +0, 98, 98, 1, 12225, 0xb1ffee58, F=0x0 +0, 99, 99, 1, 11235, 0xea998fe1, F=0x0 +0, 100, 100, 1, 11116, 0x855407b4, F=0x0 +0, 101, 101, 1, 11374, 0xaa019a67, F=0x0 +0, 102, 102, 1, 11904, 0xf8384969, F=0x0 +0, 103, 103, 1, 11487, 0xce63834d, F=0x0 +0, 104, 104, 1, 13403, 0x36444d9a, F=0x0 +0, 105, 105, 1, 12921, 0x86af447b, F=0x0 +0, 106, 106, 1, 13872, 0x104af758, F=0x0 +0, 107, 107, 1, 13559, 0x37d07d0f, F=0x0 +0, 108, 108, 1, 14049, 0xa47572e1, F=0x0 +0, 109, 109, 1, 14152, 0x217c3e45, F=0x0 +0, 110, 110, 1, 14285, 0xf37e5a5d, F=0x0 +0, 111, 111, 1, 14432, 0xd841f100, F=0x0 +0, 112, 112, 1, 14697, 0xf25cd254, F=0x0 +0, 113, 113, 1, 14606, 0x4f3069dc, F=0x0 +0, 114, 114, 1, 15221, 0x222f9680, F=0x0 +0, 115, 115, 1, 15433, 0x3e43af1c, F=0x0 +0, 116, 116, 1, 15603, 0x038a0ae1, F=0x0 +0, 117, 117, 1, 15606, 0x9040acec, F=0x0 +0, 118, 118, 1, 15871, 0xd63f0294, F=0x0 +0, 119, 119, 1, 15725, 0xe95d42ec, F=0x0 +0, 120, 120, 1, 16086, 0x27223bb4, F=0x0 +0, 121, 121, 1, 16233, 0xebfca656, F=0x0 +0, 122, 122, 1, 16143, 0x1a7717ba, F=0x0 +0, 123, 123, 1, 16669, 0x56926ea6, F=0x0 +0, 124, 124, 1, 16627, 0xe0ac5c7e, F=0x0 +0, 125, 125, 1, 16837, 0x67b5c267, F=0x0 +0, 126, 126, 1, 16952, 0x2d9bd2b7, F=0x0 +0, 127, 127, 1, 17127, 0xcab06c88, F=0x0 +0, 128, 128, 1, 17158, 0x10be3e59, F=0x0 +0, 129, 129, 1, 17329, 0x53d2ef82, F=0x0 +0, 130, 130, 1, 17403, 0x37a5ca9c, F=0x0 +0, 131, 131, 1, 17674, 0x0e34434b, F=0x0 +0, 132, 132, 1, 17738, 0xc1ef86db, F=0x0 +0, 133, 133, 1, 17942, 0xbf37caa5, F=0x0 +0, 134, 134, 1, 17952, 0x256e0aee, F=0x0 +0, 135, 135, 1, 18246, 0xd818335f, F=0x0 +0, 136, 136, 1, 18399, 0x6b84c5b2, F=0x0 +0, 137, 137, 1, 18551, 0x5e02f360, F=0x0 +0, 138, 138, 1, 18947, 0x5cdbdb83, F=0x0 +0, 139, 139, 1, 19153, 0x97f52a72, F=0x0 +0, 140, 140, 1, 19128, 0x537baaeb, F=0x0 +0, 141, 141, 1, 19138, 0xa629eee4, F=0x0 +0, 142, 142, 1, 19502, 0x4b8da41b, F=0x0 +0, 143, 143, 1, 19542, 0x21a5a87a, F=0x0 +0, 144, 144, 1, 19755, 0xc5d0c4a1, F=0x0 +0, 145, 145, 1, 20122, 0x913a698c, F=0x0 +0, 146, 146, 1, 20265, 0xfdbcdb4e, F=0x0 +0, 147, 147, 1, 20378, 0x173f3952, F=0x0 +0, 148, 148, 1, 20300, 0xff58f32f, F=0x0 +0, 149, 149, 1, 20499, 0x89246e44, F=0x0 +0, 150, 150, 1, 20655, 0xff78de6d, F=0x0 +0, 151, 151, 1, 20674, 0x9ccbc9cc, F=0x0 +0, 152, 152, 1, 21015, 0x289450a5, F=0x0 +0, 153, 153, 1, 21066, 0x006d6bc5, F=0x0 +0, 154, 154, 1, 21161, 0x306b4b03, F=0x0 +0, 155, 155, 1, 21086, 0x5c4f8181, F=0x0 +0, 156, 156, 1, 21466, 0x5be353c4, F=0x0 +0, 157, 157, 1, 21677, 0xbc05e406, F=0x0 +0, 158, 158, 1, 21589, 0xa69322d7, F=0x0 +0, 159, 159, 1, 21662, 0x64e7ac40, F=0x0 +0, 160, 160, 1, 21995, 0xbfa18826, F=0x0 +0, 161, 161, 1, 22213, 0xb9fa745d, F=0x0 +0, 162, 162, 1, 22483, 0x3070e144, F=0x0 +0, 163, 163, 1, 22498, 0x1feb3894, F=0x0 +0, 164, 164, 1, 22468, 0xb34dbd26, F=0x0 +0, 165, 165, 1, 22869, 0x67c63638, F=0x0 +0, 166, 166, 1, 22754, 0xaa2d573d, F=0x0 +0, 167, 167, 1, 23173, 0x9f7767cb, F=0x0 +0, 168, 168, 1, 23281, 0x3f319c01, F=0x0 +0, 169, 169, 1, 23219, 0xb706632d, F=0x0 +0, 170, 170, 1, 23656, 0x7e2ff143, F=0x0 +0, 171, 171, 1, 23683, 0x729d61e1, F=0x0 +0, 172, 172, 1, 23882, 0x8fb999ed, F=0x0 diff --git a/tests/ref/fate/h264-timecode b/tests/ref/fate/h264-timecode new file mode 100644 index 000000000..b78f700c6 --- /dev/null +++ b/tests/ref/fate/h264-timecode @@ -0,0 +1,305 @@ +#tb 0: 1/30 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 352x288 +#sar 0: 128/117 +0, 0, 0, 1, 152064, 0x70684c80 +0, 1, 1, 1, 152064, 0xb5c8b300 +0, 2, 2, 1, 152064, 0x5777ac60 +0, 3, 3, 1, 152064, 0xb27646a5 +0, 4, 4, 1, 152064, 0x20bd98ec +0, 5, 5, 1, 152064, 0xcf5ac1b0 +0, 6, 6, 1, 152064, 0x85a42952 +0, 7, 7, 1, 152064, 0xc25aa530 +0, 8, 8, 1, 152064, 0x97b14be9 +0, 9, 9, 1, 152064, 0xf67ec91a +0, 10, 10, 1, 152064, 0x3890d6a3 +0, 11, 11, 1, 152064, 0xc52c8467 +0, 12, 12, 1, 152064, 0x30a7af36 +0, 13, 13, 1, 152064, 0x27528a98 +0, 14, 14, 1, 152064, 0x245c08c5 +0, 15, 15, 1, 152064, 0x7e0220f3 +0, 16, 16, 1, 152064, 0x4b254c89 +0, 17, 17, 1, 152064, 0x1586e3e5 +0, 18, 18, 1, 152064, 0x594dfc58 +0, 19, 19, 1, 152064, 0x85ba9c8e +0, 20, 20, 1, 152064, 0x1e235100 +0, 21, 21, 1, 152064, 0xa02c6a72 +0, 22, 22, 1, 152064, 0xd1166fb6 +0, 23, 23, 1, 152064, 0xcc9b1546 +0, 24, 24, 1, 152064, 0x55e35a35 +0, 25, 25, 1, 152064, 0xea63e2ae +0, 26, 26, 1, 152064, 0x936a1802 +0, 27, 27, 1, 152064, 0x354a749c +0, 28, 28, 1, 152064, 0x5cd0f246 +0, 29, 29, 1, 152064, 0x0376e69b +0, 30, 30, 1, 152064, 0x5af5fb61 +0, 31, 31, 1, 152064, 0x9a053ab8 +0, 32, 32, 1, 152064, 0x57cbbfcc +0, 33, 33, 1, 152064, 0x81f19e93 +0, 34, 34, 1, 152064, 0x0812953d +0, 35, 35, 1, 152064, 0x0ae2a166 +0, 36, 36, 1, 152064, 0x193125b8 +0, 37, 37, 1, 152064, 0xab7eca7b +0, 38, 38, 1, 152064, 0x91ff1870 +0, 39, 39, 1, 152064, 0x8f522dde +0, 40, 40, 1, 152064, 0x98faab46 +0, 41, 41, 1, 152064, 0xa2119231 +0, 42, 42, 1, 152064, 0xfe591321 +0, 43, 43, 1, 152064, 0x6c8a1bf5 +0, 44, 44, 1, 152064, 0x857c925c +0, 45, 45, 1, 152064, 0xe81a77f2 +0, 46, 46, 1, 152064, 0x08234e83 +0, 47, 47, 1, 152064, 0x76cb39f6 +0, 48, 48, 1, 152064, 0x26168d25 +0, 49, 49, 1, 152064, 0x4dd3b273 +0, 50, 50, 1, 152064, 0xd6e8398e +0, 51, 51, 1, 152064, 0x55986a57 +0, 52, 52, 1, 152064, 0x9c2768fb +0, 53, 53, 1, 152064, 0x03517efe +0, 54, 54, 1, 152064, 0x3a48451f +0, 55, 55, 1, 152064, 0x1f6d6b87 +0, 56, 56, 1, 152064, 0x0917fb2a +0, 57, 57, 1, 152064, 0x0f49e7a9 +0, 58, 58, 1, 152064, 0x3c56d4e1 +0, 59, 59, 1, 152064, 0x487cca35 +0, 60, 60, 1, 152064, 0x5c6b8b1c +0, 61, 61, 1, 152064, 0x767d8a34 +0, 62, 62, 1, 152064, 0xcd8d692a +0, 63, 63, 1, 152064, 0x788b3ebf +0, 64, 64, 1, 152064, 0x4cae3852 +0, 65, 65, 1, 152064, 0x1150f0aa +0, 66, 66, 1, 152064, 0x9d4b3366 +0, 67, 67, 1, 152064, 0xedcb8863 +0, 68, 68, 1, 152064, 0x2c09ca8c +0, 69, 69, 1, 152064, 0x20930842 +0, 70, 70, 1, 152064, 0xd653b16f +0, 71, 71, 1, 152064, 0x41f38d77 +0, 72, 72, 1, 152064, 0xa5f69360 +0, 73, 73, 1, 152064, 0xf0f5ce27 +0, 74, 74, 1, 152064, 0xf2a6246c +0, 75, 75, 1, 152064, 0x7e76fabc +0, 76, 76, 1, 152064, 0xf76e1982 +0, 77, 77, 1, 152064, 0x40c1be5a +0, 78, 78, 1, 152064, 0x132ca50e +0, 79, 79, 1, 152064, 0xae0c69ed +0, 80, 80, 1, 152064, 0x5f775778 +0, 81, 81, 1, 152064, 0x62bb9790 +0, 82, 82, 1, 152064, 0x8b448e83 +0, 83, 83, 1, 152064, 0xcc35d9fe +0, 84, 84, 1, 152064, 0x51560127 +0, 85, 85, 1, 152064, 0xb915829b +0, 86, 86, 1, 152064, 0x3a3f2b0c +0, 87, 87, 1, 152064, 0x4e2d2260 +0, 88, 88, 1, 152064, 0x9fdb7567 +0, 89, 89, 1, 152064, 0xe34b2f4e +0, 90, 90, 1, 152064, 0x8650ec13 +0, 91, 91, 1, 152064, 0xdff3e299 +0, 92, 92, 1, 152064, 0x100f8f0c +0, 93, 93, 1, 152064, 0xa9aff101 +0, 94, 94, 1, 152064, 0xa80add4c +0, 95, 95, 1, 152064, 0xa7994880 +0, 96, 96, 1, 152064, 0xc74ecb79 +0, 97, 97, 1, 152064, 0xbada663d +0, 98, 98, 1, 152064, 0xff7f0592 +0, 99, 99, 1, 152064, 0x44731be5 +0, 100, 100, 1, 152064, 0x1a61f9ac +0, 101, 101, 1, 152064, 0x848ace19 +0, 102, 102, 1, 152064, 0x22858567 +0, 103, 103, 1, 152064, 0x2b3a9ba7 +0, 104, 104, 1, 152064, 0x02889774 +0, 105, 105, 1, 152064, 0x29a54516 +0, 106, 106, 1, 152064, 0x737f2833 +0, 107, 107, 1, 152064, 0x28b5a183 +0, 108, 108, 1, 152064, 0xaff9112a +0, 109, 109, 1, 152064, 0x0a7652b5 +0, 110, 110, 1, 152064, 0x03fa3e91 +0, 111, 111, 1, 152064, 0x9deade68 +0, 112, 112, 1, 152064, 0xb9af1a27 +0, 113, 113, 1, 152064, 0xe9f07f00 +0, 114, 114, 1, 152064, 0x1b03894a +0, 115, 115, 1, 152064, 0xf89e26c5 +0, 116, 116, 1, 152064, 0x6d6b5508 +0, 117, 117, 1, 152064, 0x735ce75d +0, 118, 118, 1, 152064, 0x30017005 +0, 119, 119, 1, 152064, 0x606ad5ab +0, 120, 120, 1, 152064, 0xb442ac30 +0, 121, 121, 1, 152064, 0xac321998 +0, 122, 122, 1, 152064, 0x4507990b +0, 123, 123, 1, 152064, 0xe40f986d +0, 124, 124, 1, 152064, 0xc9840540 +0, 125, 125, 1, 152064, 0x74cfbc82 +0, 126, 126, 1, 152064, 0x1ac9744b +0, 127, 127, 1, 152064, 0x8ac2a889 +0, 128, 128, 1, 152064, 0x3074a1bc +0, 129, 129, 1, 152064, 0x389ae633 +0, 130, 130, 1, 152064, 0xaadb4325 +0, 131, 131, 1, 152064, 0x7d1a91b5 +0, 132, 132, 1, 152064, 0xaa047ddc +0, 133, 133, 1, 152064, 0xe5cafebc +0, 134, 134, 1, 152064, 0x24314a0c +0, 135, 135, 1, 152064, 0x530cfa1c +0, 136, 136, 1, 152064, 0x3f973f68 +0, 137, 137, 1, 152064, 0xf51d3e20 +0, 138, 138, 1, 152064, 0x24aca84c +0, 139, 139, 1, 152064, 0x96b411e9 +0, 140, 140, 1, 152064, 0x6d046ea3 +0, 141, 141, 1, 152064, 0x9237974f +0, 142, 142, 1, 152064, 0x0a808964 +0, 143, 143, 1, 152064, 0x9d6ad957 +0, 144, 144, 1, 152064, 0x9d6381ea +0, 145, 145, 1, 152064, 0xfeceab64 +0, 146, 146, 1, 152064, 0x7fa00e6f +0, 147, 147, 1, 152064, 0x635ac444 +0, 148, 148, 1, 152064, 0xf0db3036 +0, 149, 149, 1, 152064, 0xc5ddef73 +0, 150, 150, 1, 152064, 0x7fea7516 +0, 151, 151, 1, 152064, 0x7f3f7460 +0, 152, 152, 1, 152064, 0x446dfa20 +0, 153, 153, 1, 152064, 0x5d7167c4 +0, 154, 154, 1, 152064, 0xf9da05b7 +0, 155, 155, 1, 152064, 0xc007383d +0, 156, 156, 1, 152064, 0xbf461f08 +0, 157, 157, 1, 152064, 0xf722508f +0, 158, 158, 1, 152064, 0x2699fa56 +0, 159, 159, 1, 152064, 0xa49ca6d8 +0, 160, 160, 1, 152064, 0x58f70dfd +0, 161, 161, 1, 152064, 0x391383db +0, 162, 162, 1, 152064, 0xb859f2fd +0, 163, 163, 1, 152064, 0xbb77d0a7 +0, 164, 164, 1, 152064, 0xd4c9881d +0, 165, 165, 1, 152064, 0xb46d7272 +0, 166, 166, 1, 152064, 0x78237e5e +0, 167, 167, 1, 152064, 0xbcd9f633 +0, 168, 168, 1, 152064, 0x17e09080 +0, 169, 169, 1, 152064, 0x4a9bdacf +0, 170, 170, 1, 152064, 0x600c972f +0, 171, 171, 1, 152064, 0x858e399a +0, 172, 172, 1, 152064, 0xf9ef200d +0, 173, 173, 1, 152064, 0x6aec0fda +0, 174, 174, 1, 152064, 0x4d7ba9a8 +0, 175, 175, 1, 152064, 0x0df5dbdb +0, 176, 176, 1, 152064, 0x77d598f8 +0, 177, 177, 1, 152064, 0x7d78c129 +0, 178, 178, 1, 152064, 0xf6b79ad2 +0, 179, 179, 1, 152064, 0x2b458750 +0, 180, 180, 1, 152064, 0xdbec9727 +0, 181, 181, 1, 152064, 0xcb073a1a +0, 182, 182, 1, 152064, 0xa95e913a +0, 183, 183, 1, 152064, 0x5ca9da6e +0, 184, 184, 1, 152064, 0x82e09caf +0, 185, 185, 1, 152064, 0x319f59c5 +0, 186, 186, 1, 152064, 0x11003b19 +0, 187, 187, 1, 152064, 0xcdfc5077 +0, 188, 188, 1, 152064, 0xa56fc40d +0, 189, 189, 1, 152064, 0x3d2425dc +0, 190, 190, 1, 152064, 0x907f51d3 +0, 191, 191, 1, 152064, 0xc52dc2dc +0, 192, 192, 1, 152064, 0xea800778 +0, 193, 193, 1, 152064, 0xc0b022f9 +0, 194, 194, 1, 152064, 0x106b4ea2 +0, 195, 195, 1, 152064, 0x50c6cbf2 +0, 196, 196, 1, 152064, 0x480711b5 +0, 197, 197, 1, 152064, 0x1954bca7 +0, 198, 198, 1, 152064, 0x7894a1c1 +0, 199, 199, 1, 152064, 0xaa39601a +0, 200, 200, 1, 152064, 0x07652fa2 +0, 201, 201, 1, 152064, 0x84ac1bce +0, 202, 202, 1, 152064, 0x89104737 +0, 203, 203, 1, 152064, 0x832bf2b0 +0, 204, 204, 1, 152064, 0x45fa87f4 +0, 205, 205, 1, 152064, 0xde5b6e82 +0, 206, 206, 1, 152064, 0x8d88f89b +0, 207, 207, 1, 152064, 0xba6488c8 +0, 208, 208, 1, 152064, 0xd9bc3312 +0, 209, 209, 1, 152064, 0xdba30d10 +0, 210, 210, 1, 152064, 0xd208cb34 +0, 211, 211, 1, 152064, 0x0642aadc +0, 212, 212, 1, 152064, 0xf392e67a +0, 213, 213, 1, 152064, 0xec6041d0 +0, 214, 214, 1, 152064, 0x52463e92 +0, 215, 215, 1, 152064, 0x218174a8 +0, 216, 216, 1, 152064, 0x9408f728 +0, 217, 217, 1, 152064, 0xabd31db7 +0, 218, 218, 1, 152064, 0x3e72f003 +0, 219, 219, 1, 152064, 0x638e603b +0, 220, 220, 1, 152064, 0xf1f896c7 +0, 221, 221, 1, 152064, 0x786554ff +0, 222, 222, 1, 152064, 0x9bb909f5 +0, 223, 223, 1, 152064, 0x726cf59e +0, 224, 224, 1, 152064, 0xc18c15a1 +0, 225, 225, 1, 152064, 0x45ea8f83 +0, 226, 226, 1, 152064, 0xcb88e67a +0, 227, 227, 1, 152064, 0x18d09432 +0, 228, 228, 1, 152064, 0x99d02a0a +0, 229, 229, 1, 152064, 0x7ddc3691 +0, 230, 230, 1, 152064, 0x47710c00 +0, 231, 231, 1, 152064, 0xe28646c7 +0, 232, 232, 1, 152064, 0xe8a2a4e5 +0, 233, 233, 1, 152064, 0xed19f345 +0, 234, 234, 1, 152064, 0xceffaf7f +0, 235, 235, 1, 152064, 0x8d116def +0, 236, 236, 1, 152064, 0xccb68ae8 +0, 237, 237, 1, 152064, 0x3529b3db +0, 238, 238, 1, 152064, 0x529911b8 +0, 239, 239, 1, 152064, 0x3a676438 +0, 240, 240, 1, 152064, 0x18508f5d +0, 241, 241, 1, 152064, 0x4577d18b +0, 242, 242, 1, 152064, 0x420f5881 +0, 243, 243, 1, 152064, 0x60341b86 +0, 244, 244, 1, 152064, 0x2f51de6a +0, 245, 245, 1, 152064, 0xc70bbf8d +0, 246, 246, 1, 152064, 0xc1ff63f7 +0, 247, 247, 1, 152064, 0x2dc1662b +0, 248, 248, 1, 152064, 0x1bbb3b70 +0, 249, 249, 1, 152064, 0x74f44ec2 +0, 250, 250, 1, 152064, 0x9b93084e +0, 251, 251, 1, 152064, 0x1493f82d +0, 252, 252, 1, 152064, 0x069d9869 +0, 253, 253, 1, 152064, 0xc9a4f706 +0, 254, 254, 1, 152064, 0xf80092ed +0, 255, 255, 1, 152064, 0xdc347577 +0, 256, 256, 1, 152064, 0x1df12299 +0, 257, 257, 1, 152064, 0x40d19951 +0, 258, 258, 1, 152064, 0xfb63dbf1 +0, 259, 259, 1, 152064, 0x9153714c +0, 260, 260, 1, 152064, 0x6cfd514c +0, 261, 261, 1, 152064, 0xc0ef7bf3 +0, 262, 262, 1, 152064, 0x5fce6828 +0, 263, 263, 1, 152064, 0xe7d0074d +0, 264, 264, 1, 152064, 0x9e3f7351 +0, 265, 265, 1, 152064, 0x3a0c5d56 +0, 266, 266, 1, 152064, 0xd5581f3c +0, 267, 267, 1, 152064, 0x9a4ec0d1 +0, 268, 268, 1, 152064, 0x150b9a54 +0, 269, 269, 1, 152064, 0x950eb994 +0, 270, 270, 1, 152064, 0xda31e3bf +0, 271, 271, 1, 152064, 0x14ff5d3c +0, 272, 272, 1, 152064, 0xd593bafc +0, 273, 273, 1, 152064, 0xd4cf7c58 +0, 274, 274, 1, 152064, 0x2be70997 +0, 275, 275, 1, 152064, 0xe551703b +0, 276, 276, 1, 152064, 0x7adaf447 +0, 277, 277, 1, 152064, 0x0435ea0f +0, 278, 278, 1, 152064, 0x87e5bba1 +0, 279, 279, 1, 152064, 0xea1fdf88 +0, 280, 280, 1, 152064, 0xaea5b4c4 +0, 281, 281, 1, 152064, 0x32f79e89 +0, 282, 282, 1, 152064, 0xcd5694bc +0, 283, 283, 1, 152064, 0x6b12830f +0, 284, 284, 1, 152064, 0xaf681652 +0, 285, 285, 1, 152064, 0x3b26e20b +0, 286, 286, 1, 152064, 0x2a9eee33 +0, 287, 287, 1, 152064, 0x8d5fe982 +0, 288, 288, 1, 152064, 0xa4cb5d02 +0, 289, 289, 1, 152064, 0x867dd0b0 +0, 290, 290, 1, 152064, 0x23c885e9 +0, 291, 291, 1, 152064, 0x99fd7b2b +0, 292, 292, 1, 152064, 0xa710e871 +0, 293, 293, 1, 152064, 0x3ecbaaeb +0, 294, 294, 1, 152064, 0x3d1c7de2 +0, 295, 295, 1, 152064, 0x378935f3 +0, 296, 296, 1, 152064, 0xce893553 +0, 297, 297, 1, 152064, 0xa834374c +0, 298, 298, 1, 152064, 0x665094f4 +0, 299, 299, 1, 152064, 0x3fee89c6 diff --git a/tests/ref/fate/hapqa-extract-nosnappy-to-hapalphaonly-mov b/tests/ref/fate/hapqa-extract-nosnappy-to-hapalphaonly-mov index f5ecdd431..eacb1f191 100644 --- a/tests/ref/fate/hapqa-extract-nosnappy-to-hapalphaonly-mov +++ b/tests/ref/fate/hapqa-extract-nosnappy-to-hapalphaonly-mov @@ -17,7 +17,6 @@ data_hash=adler32:ed83c166 [STREAM] index=0 codec_name=hap -codec_long_name=Vidvox Hap profile=unknown codec_type=video codec_time_base=1/25 @@ -68,6 +67,6 @@ DISPOSITION:clean_effects=0 DISPOSITION:attached_pic=0 DISPOSITION:timed_thumbnails=0 TAG:language=eng -TAG:handler_name=DataHandler +TAG:handler_name=Module de gestion video TAG:encoder=HAPAlpha Only [/STREAM] diff --git a/tests/ref/fate/hapqa-extract-nosnappy-to-hapq-mov b/tests/ref/fate/hapqa-extract-nosnappy-to-hapq-mov index c3a0a599f..ff96888f4 100644 --- a/tests/ref/fate/hapqa-extract-nosnappy-to-hapq-mov +++ b/tests/ref/fate/hapqa-extract-nosnappy-to-hapq-mov @@ -17,7 +17,6 @@ data_hash=adler32:b3ccc147 [STREAM] index=0 codec_name=hap -codec_long_name=Vidvox Hap profile=unknown codec_type=video codec_time_base=1/25 @@ -68,6 +67,6 @@ DISPOSITION:clean_effects=0 DISPOSITION:attached_pic=0 DISPOSITION:timed_thumbnails=0 TAG:language=eng -TAG:handler_name=DataHandler +TAG:handler_name=Module de gestion video TAG:encoder=HAPQ [/STREAM] diff --git a/tests/ref/fate/hevc-monochrome-crop b/tests/ref/fate/hevc-monochrome-crop new file mode 100644 index 000000000..4e45412ac --- /dev/null +++ b/tests/ref/fate/hevc-monochrome-crop @@ -0,0 +1,8 @@ +[FRAME] +width=384 +height=240 +[/FRAME] +[STREAM] +width=384 +height=240 +[/STREAM] diff --git a/tests/ref/fate/hevc-two-first-slice b/tests/ref/fate/hevc-two-first-slice new file mode 100644 index 000000000..586b8ef5c --- /dev/null +++ b/tests/ref/fate/hevc-two-first-slice @@ -0,0 +1,39 @@ +#format: frame checksums +#version: 2 +#hash: MD5 +#tb 0: 1/15 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 1920x1080 +#sar 0: 0/1 +#stream#, dts, pts, duration, size, hash +0, 0, 0, 1, 3110400, c88154281ada839d3f209b0eab012577 +0, 1, 1, 1, 3110400, a2623ba4639cf246b803c08e7233112f +0, 2, 2, 1, 3110400, 9208fcdb16664e91ada77d15cc29ace9 +0, 3, 3, 1, 3110400, 62a5afb0c4d189b831c8cca033a396e0 +0, 4, 4, 1, 3110400, a8f208f1323e9c14181549d480055e3c +0, 5, 5, 1, 3110400, 3a66c0ab75362a73eebb9ef668bee3da +0, 6, 6, 1, 3110400, 8096734441fe76d8f7bba8384029b1be +0, 7, 7, 1, 3110400, ee8db0610de85f015ec76a0c14475ab8 +0, 8, 8, 1, 3110400, f52df359246a4ac396dfc74f75285347 +0, 9, 9, 1, 3110400, 8fb6ddd74e4b71c7596e90d47e50d8f1 +0, 10, 10, 1, 3110400, 70542a3ac5df77437c3d8097d19315c2 +0, 11, 11, 1, 3110400, 20bdf9399f6752578c574248627c3a9f +0, 12, 12, 1, 3110400, a8b564575af5d72a2cc6d566e99e0176 +0, 13, 13, 1, 3110400, 0d4ace74eb6b452ea9cb2cc72371794a +0, 14, 14, 1, 3110400, d9736a1e47da6541306cbf8496d97635 +0, 15, 15, 1, 3110400, 49bc2b608000c7d545fa362418035277 +0, 16, 16, 1, 3110400, bd64e9d545c666f818ea1af791ac4201 +0, 17, 17, 1, 3110400, 75b86260724937fdeddf47e1f28530a1 +0, 18, 18, 1, 3110400, 7df76be996e2c652da048e690e45313f +0, 19, 19, 1, 3110400, 057b9a27f76c9205fe7f378c7e4fe1b4 +0, 20, 20, 1, 3110400, 08241ea9c8d27bd14117ca07485a9892 +0, 21, 21, 1, 3110400, 7d5f4d4e043d6f3e794d1222046cb9cf +0, 22, 22, 1, 3110400, dfb6916da415ff5323a1925cc329c8e2 +0, 23, 23, 1, 3110400, 574730243f89b4824a313ea1b690e31b +0, 24, 24, 1, 3110400, 63054e31f52171dda84faa201523dc3b +0, 25, 25, 1, 3110400, d8ba349a9a5a6f38527e47f5519fd335 +0, 26, 26, 1, 3110400, e653543eb8a8a49147676a91bafbdec8 +0, 27, 27, 1, 3110400, b3194aced03ff1bc4d65560792eeab98 +0, 28, 28, 1, 3110400, 6ba07b8fd8422b3c14976062f5468fab +0, 29, 29, 1, 3110400, bf8359596ddfd9fdbc243fc2fee56669 diff --git a/tests/ref/fate/hls-fmp4 b/tests/ref/fate/hls-fmp4 new file mode 100644 index 000000000..98b037fc8 --- /dev/null +++ b/tests/ref/fate/hls-fmp4 @@ -0,0 +1,198 @@ +#tb 0: 1/44100 +#media_type 0: audio +#codec_id 0: pcm_s16le +#sample_rate 0: 44100 +#channel_layout 0: 4 +#channel_layout_name 0: mono +0, 0, 0, 1152, 2304, 0x907cb7fa +0, 1152, 1152, 1152, 2304, 0xb8dc7525 +0, 2304, 2304, 1152, 2304, 0x3e7d6905 +0, 3456, 3456, 1152, 2304, 0xef47877b +0, 4608, 4608, 1152, 2304, 0xfe916b7e +0, 5760, 5760, 1152, 2304, 0xe3d08cde +0, 6912, 6912, 1152, 2304, 0xff7f86cf +0, 8064, 8064, 1152, 2304, 0x843e6f95 +0, 9216, 9216, 1152, 2304, 0x81577c26 +0, 10368, 10368, 1152, 2304, 0x04a085d5 +0, 11520, 11520, 1152, 2304, 0x1c5a76f5 +0, 12672, 12672, 1152, 2304, 0x4ee78623 +0, 13824, 13824, 1152, 2304, 0x8ec861dc +0, 14976, 14976, 1152, 2304, 0x0ca179d8 +0, 16128, 16128, 1152, 2304, 0xc6da750f +0, 17280, 17280, 1152, 2304, 0xf6bf79b5 +0, 18432, 18432, 1152, 2304, 0x97b88a43 +0, 19584, 19584, 1152, 2304, 0xf13c7b9c +0, 20736, 20736, 1152, 2304, 0xdfba83af +0, 21888, 21888, 1152, 2304, 0xc9467d4b +0, 23040, 23040, 1152, 2304, 0xbbb58e2b +0, 24192, 24192, 1152, 2304, 0x3a1078ea +0, 25344, 25344, 1152, 2304, 0xe9587a5c +0, 26496, 26496, 1152, 2304, 0xef5a8039 +0, 27648, 27648, 1152, 2304, 0x9d5f782f +0, 28800, 28800, 1152, 2304, 0x1a548291 +0, 29952, 29952, 1152, 2304, 0x07517701 +0, 31104, 31104, 1152, 2304, 0x78127d6e +0, 32256, 32256, 1152, 2304, 0x62e2788a +0, 33408, 33408, 1152, 2304, 0x29397ad9 +0, 34560, 34560, 1152, 2304, 0x45da82d6 +0, 35712, 35712, 1152, 2304, 0x8ed66e51 +0, 36864, 36864, 1152, 2304, 0x660775cd +0, 38016, 38016, 1152, 2304, 0x802c767a +0, 39168, 39168, 1152, 2304, 0xcc055840 +0, 40320, 40320, 1152, 2304, 0x701b7eaf +0, 41472, 41472, 1152, 2304, 0x8290749f +0, 42624, 42624, 1152, 2304, 0x2c7b7d30 +0, 43776, 43776, 1152, 2304, 0xe4f17743 +0, 44928, 44928, 1152, 2304, 0x0e747d6e +0, 46080, 46080, 1152, 2304, 0xbe7775a0 +0, 47232, 47232, 1152, 2304, 0xcf797673 +0, 48384, 48384, 1152, 2304, 0x29cb7800 +0, 49536, 49536, 1152, 2304, 0xfc947890 +0, 50688, 50688, 1152, 2304, 0x62757fc6 +0, 51840, 51840, 1152, 2304, 0x098876d0 +0, 52992, 52992, 1152, 2304, 0xa9567ee2 +0, 54144, 54144, 1152, 2304, 0xe3bb9173 +0, 55296, 55296, 1152, 2304, 0xcc2d6dee +0, 56448, 56448, 1152, 2304, 0xe94591ab +0, 57600, 57600, 1152, 2304, 0x5c7588de +0, 58752, 58752, 1152, 2304, 0xfd83643c +0, 59904, 59904, 1152, 2304, 0x528177f1 +0, 61056, 61056, 1152, 2304, 0x65d08474 +0, 62208, 62208, 1152, 2304, 0x738d765b +0, 63360, 63360, 1152, 2304, 0xdd3d810e +0, 64512, 64512, 1152, 2304, 0xef4f90d3 +0, 65664, 65664, 1152, 2304, 0x61e28d43 +0, 66816, 66816, 1152, 2304, 0x9a11796b +0, 67968, 67968, 1152, 2304, 0x96c97dcd +0, 69120, 69120, 1152, 2304, 0xa8fe8621 +0, 70272, 70272, 1152, 2304, 0x499b7d38 +0, 71424, 71424, 1152, 2304, 0xfcb078a9 +0, 72576, 72576, 1152, 2304, 0x40d78651 +0, 73728, 73728, 1152, 2304, 0xa4af7234 +0, 74880, 74880, 1152, 2304, 0x6831870a +0, 76032, 76032, 1152, 2304, 0x030e7b9d +0, 77184, 77184, 1152, 2304, 0x445a75b6 +0, 78336, 78336, 1152, 2304, 0x09857389 +0, 79488, 79488, 1152, 2304, 0x0d018866 +0, 80640, 80640, 1152, 2304, 0x2afe810a +0, 81792, 81792, 1152, 2304, 0x0bcf7c43 +0, 82944, 82944, 1152, 2304, 0x13737c12 +0, 84096, 84096, 1152, 2304, 0x716c7bba +0, 85248, 85248, 1152, 2304, 0xb801823b +0, 86400, 86400, 1152, 2304, 0x0fd573ee +0, 87552, 87552, 1152, 2304, 0xe1ab879c +0, 88704, 88704, 1152, 2304, 0x49e6764f +0, 89856, 89856, 1152, 2304, 0xd5f26ddc +0, 91008, 91008, 1152, 2304, 0x076775ff +0, 92160, 92160, 1152, 2304, 0xfbb86fce +0, 93312, 93312, 1152, 2304, 0x20c56858 +0, 94464, 94464, 1152, 2304, 0x043e6891 +0, 95616, 95616, 1152, 2304, 0x59648729 +0, 96768, 96768, 1152, 2304, 0xd4907a63 +0, 97920, 97920, 1152, 2304, 0xd0208a4c +0, 99072, 99072, 1152, 2304, 0xce968383 +0, 100224, 100224, 1152, 2304, 0x3cfc7cd1 +0, 101376, 101376, 1152, 2304, 0x628a7bf5 +0, 102528, 102528, 1152, 2304, 0x9cfe8a4f +0, 103680, 103680, 1152, 2304, 0xdf6f7c6d +0, 104832, 104832, 1152, 2304, 0x6cf6882a +0, 105984, 105984, 1152, 2304, 0x099773a3 +0, 107136, 107136, 1152, 2304, 0x4a1c7649 +0, 108288, 108288, 1152, 2304, 0x31ea71cb +0, 109440, 109440, 1152, 2304, 0xed127ed9 +0, 110592, 110592, 1152, 2304, 0x5b156954 +0, 111744, 111744, 1152, 2304, 0xdd638532 +0, 112896, 112896, 1152, 2304, 0xf1a271f2 +0, 114048, 114048, 1152, 2304, 0x779184d7 +0, 115200, 115200, 1152, 2304, 0x49a88aa8 +0, 116352, 116352, 1152, 2304, 0xa11b7c90 +0, 117504, 117504, 1152, 2304, 0xbf488274 +0, 118656, 118656, 1152, 2304, 0x002f79a8 +0, 119808, 119808, 1152, 2304, 0x0ed97e2f +0, 120960, 120960, 1152, 2304, 0x7845878f +0, 122112, 122112, 1152, 2304, 0x46d777dc +0, 123264, 123264, 1152, 2304, 0x8d0179e3 +0, 124416, 124416, 1152, 2304, 0x38917f9f +0, 125568, 125568, 1152, 2304, 0x449876e7 +0, 126720, 126720, 1152, 2304, 0x001a8769 +0, 127872, 127872, 1152, 2304, 0x06c1826b +0, 129024, 129024, 1152, 2304, 0x41b68047 +0, 130176, 130176, 1152, 2304, 0xeb9782c6 +0, 131328, 131328, 1152, 2304, 0x7cd9719c +0, 132480, 132480, 1152, 2304, 0x3a4a767c +0, 133632, 133632, 1152, 2304, 0x7f887e81 +0, 134784, 134784, 1152, 2304, 0xf75d714b +0, 135936, 135936, 1152, 2304, 0x33b57e9f +0, 137088, 137088, 1152, 2304, 0xc732749e +0, 138240, 138240, 1152, 2304, 0x386f7e1a +0, 139392, 139392, 1152, 2304, 0x6b9c767d +0, 140544, 140544, 1152, 2304, 0x701c83e5 +0, 141696, 141696, 1152, 2304, 0xb92571e1 +0, 142848, 142848, 1152, 2304, 0x833a84bc +0, 144000, 144000, 1152, 2304, 0x1b6984e0 +0, 145152, 145152, 1152, 2304, 0x1b2474ba +0, 146304, 146304, 1152, 2304, 0xc22775a6 +0, 147456, 147456, 1152, 2304, 0x3e8f7972 +0, 148608, 148608, 1152, 2304, 0x17a28a65 +0, 149760, 149760, 1152, 2304, 0x9b6178a4 +0, 150912, 150912, 1152, 2304, 0x5d707873 +0, 152064, 152064, 1152, 2304, 0x68e2645a +0, 153216, 153216, 1152, 2304, 0x1e377d28 +0, 154368, 154368, 1152, 2304, 0x54b384be +0, 155520, 155520, 1152, 2304, 0x0617808c +0, 156672, 156672, 1152, 2304, 0xbc2b8a6c +0, 157824, 157824, 1152, 2304, 0x7ced7180 +0, 158976, 158976, 1152, 2304, 0xf22180ab +0, 160128, 160128, 1152, 2304, 0xf13682c9 +0, 161280, 161280, 1152, 2304, 0x7eff87fd +0, 162432, 162432, 1152, 2304, 0x5a0b5cec +0, 163584, 163584, 1152, 2304, 0x57c18906 +0, 164736, 164736, 1152, 2304, 0xb55a6a16 +0, 165888, 165888, 1152, 2304, 0xf2608371 +0, 167040, 167040, 1152, 2304, 0x36df7576 +0, 168192, 168192, 1152, 2304, 0xdb106fb4 +0, 169344, 169344, 1152, 2304, 0x7e4f85d0 +0, 170496, 170496, 1152, 2304, 0xe3ee78ab +0, 171648, 171648, 1152, 2304, 0xd36b7dc7 +0, 172800, 172800, 1152, 2304, 0xadab7c5c +0, 173952, 173952, 1152, 2304, 0x70786f26 +0, 175104, 175104, 1152, 2304, 0xcd5d717e +0, 176256, 176256, 1152, 2304, 0xc1a96f9a +0, 177408, 177408, 1152, 2304, 0xad777887 +0, 178560, 178560, 1152, 2304, 0x98277c16 +0, 179712, 179712, 1152, 2304, 0x868882c5 +0, 180864, 180864, 1152, 2304, 0xc48092b9 +0, 182016, 182016, 1152, 2304, 0x230069da +0, 183168, 183168, 1152, 2304, 0x14147ad6 +0, 184320, 184320, 1152, 2304, 0xc9007172 +0, 185472, 185472, 1152, 2304, 0x85d67bcc +0, 186624, 186624, 1152, 2304, 0x22418bab +0, 187776, 187776, 1152, 2304, 0xe53c8b71 +0, 188928, 188928, 1152, 2304, 0x5a1a9053 +0, 190080, 190080, 1152, 2304, 0x9cd179af +0, 191232, 191232, 1152, 2304, 0xbb3c7d72 +0, 192384, 192384, 1152, 2304, 0x477a8677 +0, 193536, 193536, 1152, 2304, 0xe3337834 +0, 194688, 194688, 1152, 2304, 0x1cb56d77 +0, 195840, 195840, 1152, 2304, 0xe89d6dac +0, 196992, 196992, 1152, 2304, 0xd468827e +0, 198144, 198144, 1152, 2304, 0xebc46b87 +0, 199296, 199296, 1152, 2304, 0x5fbb78d2 +0, 200448, 200448, 1152, 2304, 0xa1b483d6 +0, 201600, 201600, 1152, 2304, 0x6fec7cab +0, 202752, 202752, 1152, 2304, 0xd86d6f6c +0, 203904, 203904, 1152, 2304, 0x8c2c7d51 +0, 205056, 205056, 1152, 2304, 0xe8377cd7 +0, 206208, 206208, 1152, 2304, 0xb57071b4 +0, 207360, 207360, 1152, 2304, 0xc35c71fd +0, 208512, 208512, 1152, 2304, 0x789079e9 +0, 209664, 209664, 1152, 2304, 0x413b710e +0, 210816, 210816, 1152, 2304, 0x82678332 +0, 211968, 211968, 1152, 2304, 0xe1576e75 +0, 213120, 213120, 1152, 2304, 0x7c0b7ad6 +0, 214272, 214272, 1152, 2304, 0xc6b6786d +0, 215424, 215424, 1152, 2304, 0x736f7b89 +0, 216576, 216576, 1152, 2304, 0x0ded72f1 +0, 217728, 217728, 1152, 2304, 0xcb877a3c +0, 218880, 218880, 1152, 2304, 0x7c497d40 +0, 220032, 220032, 1152, 2304, 0xb4a77052 diff --git a/tests/ref/fate/hls-init-time b/tests/ref/fate/hls-init-time new file mode 100644 index 000000000..5bc12272c --- /dev/null +++ b/tests/ref/fate/hls-init-time @@ -0,0 +1,313 @@ +#tb 0: 1/44100 +#media_type 0: audio +#codec_id 0: pcm_s16le +#sample_rate 0: 44100 +#channel_layout 0: 4 +#channel_layout_name 0: mono +0, 0, 0, 1152, 2304, 0x28123557 +0, 1152, 1152, 1152, 2304, 0x838c7e81 +0, 2304, 2304, 1152, 2304, 0x4fb8704c +0, 3456, 3456, 1152, 2304, 0x5f787f9e +0, 4608, 4608, 1152, 2304, 0xc866749f +0, 5760, 5760, 1152, 2304, 0x30057e19 +0, 6912, 6912, 1152, 2304, 0xaa64747f +0, 8064, 8064, 1152, 2304, 0x8d3c84e4 +0, 9216, 9216, 1152, 2304, 0xffb871e1 +0, 10368, 10368, 1152, 2304, 0x0dfe84bc +0, 11520, 11520, 1152, 2304, 0x341385e0 +0, 12672, 12672, 1152, 2304, 0x069e72bb +0, 13824, 13824, 1152, 2304, 0xc3b175a6 +0, 14976, 14976, 1152, 2304, 0x3f777972 +0, 16128, 16128, 1152, 2304, 0xb7598a65 +0, 17280, 17280, 1152, 2304, 0x9bd178a4 +0, 18432, 18432, 1152, 2304, 0xedca7972 +0, 19584, 19584, 1152, 2304, 0x8db2625c +0, 20736, 20736, 1152, 2304, 0x99c67c29 +0, 21888, 21888, 1152, 2304, 0x54f984be +0, 23040, 23040, 1152, 2304, 0x4669828a +0, 24192, 24192, 1152, 2304, 0x3e4b8b6b +0, 25344, 25344, 1152, 2304, 0x7f1f7180 +0, 26496, 26496, 1152, 2304, 0x3af882a9 +0, 27648, 27648, 1152, 2304, 0x091181cb +0, 28800, 28800, 1152, 2304, 0x7b9187fc +0, 29952, 29952, 1152, 2304, 0x59f55cec +0, 31104, 31104, 1152, 2304, 0xdf888807 +0, 32256, 32256, 1152, 2304, 0xe0216c14 +0, 33408, 33408, 1152, 2304, 0x91248470 +0, 34560, 34560, 1152, 2304, 0xe7d07576 +0, 35712, 35712, 1152, 2304, 0xdb446fb4 +0, 36864, 36864, 1152, 2304, 0x815d85d0 +0, 38016, 38016, 1152, 2304, 0x67e877ac +0, 39168, 39168, 1152, 2304, 0x51307bc9 +0, 40320, 40320, 1152, 2304, 0xad597c5c +0, 41472, 41472, 1152, 2304, 0x84a77124 +0, 42624, 42624, 1152, 2304, 0xcef5717e +0, 43776, 43776, 1152, 2304, 0xc1596f9a +0, 44928, 44928, 1152, 2304, 0xcbb57986 +0, 46080, 46080, 1152, 2304, 0x5dd97b17 +0, 47232, 47232, 1152, 2304, 0x88d882c5 +0, 48384, 48384, 1152, 2304, 0x869491ba +0, 49536, 49536, 1152, 2304, 0x254e69da +0, 50688, 50688, 1152, 2304, 0xe4b579d7 +0, 51840, 51840, 1152, 2304, 0x1fcd7271 +0, 52992, 52992, 1152, 2304, 0x872c7bcc +0, 54144, 54144, 1152, 2304, 0x23818bab +0, 55296, 55296, 1152, 2304, 0x3cc28b72 +0, 56448, 56448, 1152, 2304, 0x9cd79250 +0, 57600, 57600, 1152, 2304, 0xeb3979af +0, 58752, 58752, 1152, 2304, 0xbe647d72 +0, 59904, 59904, 1152, 2304, 0xa5858875 +0, 61056, 61056, 1152, 2304, 0xbb247834 +0, 62208, 62208, 1152, 2304, 0xe9846e76 +0, 63360, 63360, 1152, 2304, 0x17d06cad +0, 64512, 64512, 1152, 2304, 0x6ae6817f +0, 65664, 65664, 1152, 2304, 0xcb1c6c86 +0, 66816, 66816, 1152, 2304, 0x606778d2 +0, 67968, 67968, 1152, 2304, 0xa21e83d7 +0, 69120, 69120, 1152, 2304, 0xc5fd7caa +0, 70272, 70272, 1152, 2304, 0x68866e6d +0, 71424, 71424, 1152, 2304, 0x28ee7d51 +0, 72576, 72576, 1152, 2304, 0xe1f87ad9 +0, 73728, 73728, 1152, 2304, 0xbf4175b0 +0, 74880, 74880, 1152, 2304, 0xe9c372fd +0, 76032, 76032, 1152, 2304, 0xc7a77ae7 +0, 77184, 77184, 1152, 2304, 0x9a74700f +0, 78336, 78336, 1152, 2304, 0xe2288431 +0, 79488, 79488, 1152, 2304, 0xa7bd6d76 +0, 80640, 80640, 1152, 2304, 0x73fe7cd4 +0, 81792, 81792, 1152, 2304, 0xfa0c796c +0, 82944, 82944, 1152, 2304, 0x020c7a8a +0, 84096, 84096, 1152, 2304, 0xeba674ef +0, 85248, 85248, 1152, 2304, 0x6efc793d +0, 86400, 86400, 1152, 2304, 0xcfb07e3f +0, 87552, 87552, 1152, 2304, 0xe6027a8c +0, 88704, 88704, 1152, 2304, 0x4db4748c +0, 89856, 89856, 1152, 2304, 0x7cf27ec0 +0, 91008, 91008, 1152, 2304, 0x72bb7bba +0, 92160, 92160, 1152, 2304, 0x275f73b9 +0, 93312, 93312, 1152, 2304, 0x6791812c +0, 94464, 94464, 1152, 2304, 0x9bb06ff6 +0, 95616, 95616, 1152, 2304, 0x8c1b7cb4 +0, 96768, 96768, 1152, 2304, 0xafd38677 +0, 97920, 97920, 1152, 2304, 0x7eca7304 +0, 99072, 99072, 1152, 2304, 0xfbb17c1e +0, 100224, 100224, 1152, 2304, 0xb5448405 +0, 101376, 101376, 1152, 2304, 0xe2ea77b1 +0, 102528, 102528, 1152, 2304, 0x9d347d88 +0, 103680, 103680, 1152, 2304, 0xed007236 +0, 104832, 104832, 1152, 2304, 0xc0bc6e08 +0, 105984, 105984, 1152, 2304, 0x97bb7b8c +0, 107136, 107136, 1152, 2304, 0x47e2674d +0, 108288, 108288, 1152, 2304, 0x4971790b +0, 109440, 109440, 1152, 2304, 0x8823812d +0, 110592, 110592, 1152, 2304, 0xc30e7549 +0, 111744, 111744, 1152, 2304, 0xdee87475 +0, 112896, 112896, 1152, 2304, 0x6c6184aa +0, 114048, 114048, 1152, 2304, 0x45ff706b +0, 115200, 115200, 1152, 2304, 0xc14688b2 +0, 116352, 116352, 1152, 2304, 0xd011965e +0, 117504, 117504, 1152, 2304, 0x07946957 +0, 118656, 118656, 1152, 2304, 0xed518404 +0, 119808, 119808, 1152, 2304, 0xa6168301 +0, 120960, 120960, 1152, 2304, 0xed5c70df +0, 122112, 122112, 1152, 2304, 0xb897782a +0, 123264, 123264, 1152, 2304, 0x4a626f21 +0, 124416, 124416, 1152, 2304, 0xe63b7ca6 +0, 125568, 125568, 1152, 2304, 0x79d780ff +0, 126720, 126720, 1152, 2304, 0xf68974be +0, 127872, 127872, 1152, 2304, 0x66657e8c +0, 129024, 129024, 1152, 2304, 0xc0b28aae +0, 130176, 130176, 1152, 2304, 0xbf587c4a +0, 131328, 131328, 1152, 2304, 0x5d139349 +0, 132480, 132480, 1152, 2304, 0x0e067a4e +0, 133632, 133632, 1152, 2304, 0x328d6c0b +0, 134784, 134784, 1152, 2304, 0x1f4b77dd +0, 135936, 135936, 1152, 2304, 0xba5b92ba +0, 137088, 137088, 1152, 2304, 0xd158794a +0, 138240, 138240, 1152, 2304, 0xea02879e +0, 139392, 139392, 1152, 2304, 0x8de08081 +0, 140544, 140544, 1152, 2304, 0x406776b1 +0, 141696, 141696, 1152, 2304, 0xfb0e7084 +0, 142848, 142848, 1152, 2304, 0x7499891a +0, 144000, 144000, 1152, 2304, 0x823f7094 +0, 145152, 145152, 1152, 2304, 0x6ec27f15 +0, 146304, 146304, 1152, 2304, 0xe2087d1c +0, 147456, 147456, 1152, 2304, 0x0bd48042 +0, 148608, 148608, 1152, 2304, 0xce227acc +0, 149760, 149760, 1152, 2304, 0x97b17248 +0, 150912, 150912, 1152, 2304, 0x8d436bc9 +0, 152064, 152064, 1152, 2304, 0x6f477995 +0, 153216, 153216, 1152, 2304, 0x09008588 +0, 154368, 154368, 1152, 2304, 0x87e084b4 +0, 155520, 155520, 1152, 2304, 0xe1187e42 +0, 156672, 156672, 1152, 2304, 0x4ab37d73 +0, 157824, 157824, 1152, 2304, 0x615c64da +0, 158976, 158976, 1152, 2304, 0x16598832 +0, 160128, 160128, 1152, 2304, 0x03998393 +0, 161280, 161280, 1152, 2304, 0x20317653 +0, 162432, 162432, 1152, 2304, 0x74c57983 +0, 163584, 163584, 1152, 2304, 0xdacd7eea +0, 164736, 164736, 1152, 2304, 0xd8896e20 +0, 165888, 165888, 1152, 2304, 0x98247f2c +0, 167040, 167040, 1152, 2304, 0xe4ad7dc5 +0, 168192, 168192, 1152, 2304, 0x444f86a7 +0, 169344, 169344, 1152, 2304, 0x64e57440 +0, 170496, 170496, 1152, 2304, 0xb1197892 +0, 171648, 171648, 1152, 2304, 0xf7627a4f +0, 172800, 172800, 1152, 2304, 0xc26776a9 +0, 173952, 173952, 1152, 2304, 0xa2f18a85 +0, 175104, 175104, 1152, 2304, 0x112e6f4d +0, 176256, 176256, 1152, 2304, 0x5c887a6f +0, 177408, 177408, 1152, 2304, 0xeb3c724a +0, 178560, 178560, 1152, 2304, 0xba8983cc +0, 179712, 179712, 1152, 2304, 0x74dc6bc9 +0, 180864, 180864, 1152, 2304, 0x262c75d5 +0, 182016, 182016, 1152, 2304, 0xaba97a90 +0, 183168, 183168, 1152, 2304, 0xf3067fdb +0, 184320, 184320, 1152, 2304, 0x4b8a8684 +0, 185472, 185472, 1152, 2304, 0x86c979e7 +0, 186624, 186624, 1152, 2304, 0x26d16a02 +0, 187776, 187776, 1152, 2304, 0x222c83d4 +0, 188928, 188928, 1152, 2304, 0x4f43951d +0, 190080, 190080, 1152, 2304, 0x9b4179f1 +0, 191232, 191232, 1152, 2304, 0x17727ee7 +0, 192384, 192384, 1152, 2304, 0xc4267ac4 +0, 193536, 193536, 1152, 2304, 0x987f6ba7 +0, 194688, 194688, 1152, 2304, 0xdb5d747c +0, 195840, 195840, 1152, 2304, 0x3fa1801c +0, 196992, 196992, 1152, 2304, 0x28b7800a +0, 198144, 198144, 1152, 2304, 0x553d8ba3 +0, 199296, 199296, 1152, 2304, 0xe837895f +0, 200448, 200448, 1152, 2304, 0xf59682a0 +0, 201600, 201600, 1152, 2304, 0xb8008993 +0, 202752, 202752, 1152, 2304, 0x0c43681f +0, 203904, 203904, 1152, 2304, 0xfba06f7a +0, 205056, 205056, 1152, 2304, 0x8d7372bf +0, 206208, 206208, 1152, 2304, 0x9e4b7cf2 +0, 207360, 207360, 1152, 2304, 0x538e784f +0, 208512, 208512, 1152, 2304, 0xba75786d +0, 209664, 209664, 1152, 2304, 0x03f18a64 +0, 210816, 210816, 1152, 2304, 0x09ef77d9 +0, 211968, 211968, 1152, 2304, 0xf072779c +0, 213120, 213120, 1152, 2304, 0xc331892d +0, 214272, 214272, 1152, 2304, 0x46188131 +0, 215424, 215424, 1152, 2304, 0xdfaf8143 +0, 216576, 216576, 1152, 2304, 0xf0e286d2 +0, 217728, 217728, 1152, 2304, 0x28547598 +0, 218880, 218880, 1152, 2304, 0xaedc6e3f +0, 220032, 220032, 1152, 2304, 0x542b6fa9 +0, 221184, 221184, 1152, 2304, 0xe7ec6f4d +0, 222336, 222336, 1152, 2304, 0xacc47bbe +0, 223488, 223488, 1152, 2304, 0xcec48d33 +0, 224640, 224640, 1152, 2304, 0xa78a8531 +0, 225792, 225792, 1152, 2304, 0xd6337d81 +0, 226944, 226944, 1152, 2304, 0xf9e07944 +0, 228096, 228096, 1152, 2304, 0x01368885 +0, 229248, 229248, 1152, 2304, 0x301981d0 +0, 230400, 230400, 1152, 2304, 0x40ed7214 +0, 231552, 231552, 1152, 2304, 0x6f096f46 +0, 232704, 232704, 1152, 2304, 0x567d7b3b +0, 233856, 233856, 1152, 2304, 0xd1d97692 +0, 235008, 235008, 1152, 2304, 0xe6ac63d5 +0, 236160, 236160, 1152, 2304, 0x5dae8337 +0, 237312, 237312, 1152, 2304, 0x3a75820d +0, 238464, 238464, 1152, 2304, 0xc66c7f52 +0, 239616, 239616, 1152, 2304, 0x4e72815d +0, 240768, 240768, 1152, 2304, 0x1eb67d12 +0, 241920, 241920, 1152, 2304, 0xc51f8879 +0, 243072, 243072, 1152, 2304, 0x6b0c78ed +0, 244224, 244224, 1152, 2304, 0x5e2c7b81 +0, 245376, 245376, 1152, 2304, 0xd3487fd4 +0, 246528, 246528, 1152, 2304, 0xb56b7a23 +0, 247680, 247680, 1152, 2304, 0x744e6e77 +0, 248832, 248832, 1152, 2304, 0x63528197 +0, 249984, 249984, 1152, 2304, 0xdda4793f +0, 251136, 251136, 1152, 2304, 0x23317a27 +0, 252288, 252288, 1152, 2304, 0x82738430 +0, 253440, 253440, 1152, 2304, 0xeb7d7619 +0, 254592, 254592, 1152, 2304, 0x05079110 +0, 255744, 255744, 1152, 2304, 0x5ecc6edb +0, 256896, 256896, 1152, 2304, 0xe6897a38 +0, 258048, 258048, 1152, 2304, 0x55f2839b +0, 259200, 259200, 1152, 2304, 0x95f57eab +0, 260352, 260352, 1152, 2304, 0xb39367fb +0, 261504, 261504, 1152, 2304, 0x48537cae +0, 262656, 262656, 1152, 2304, 0xee6d7cf9 +0, 263808, 263808, 1152, 2304, 0xe35f84b4 +0, 264960, 264960, 1152, 2304, 0x16028fad +0, 266112, 266112, 1152, 2304, 0xdf6673f7 +0, 267264, 267264, 1152, 2304, 0xe1d97408 +0, 268416, 268416, 1152, 2304, 0xb48878b1 +0, 269568, 269568, 1152, 2304, 0x354b8638 +0, 270720, 270720, 1152, 2304, 0xb1767659 +0, 271872, 271872, 1152, 2304, 0x546a5cd1 +0, 273024, 273024, 1152, 2304, 0x2d238c49 +0, 274176, 274176, 1152, 2304, 0xcfc4886f +0, 275328, 275328, 1152, 2304, 0x95b47cef +0, 276480, 276480, 1152, 2304, 0x389f8338 +0, 277632, 277632, 1152, 2304, 0xcfb17744 +0, 278784, 278784, 1152, 2304, 0x50d76c4a +0, 279936, 279936, 1152, 2304, 0x38a08aea +0, 281088, 281088, 1152, 2304, 0xc3977790 +0, 282240, 282240, 1152, 2304, 0x086c8eeb +0, 283392, 283392, 1152, 2304, 0xa1867ebd +0, 284544, 284544, 1152, 2304, 0xd14c74f4 +0, 285696, 285696, 1152, 2304, 0x742e71c8 +0, 286848, 286848, 1152, 2304, 0xee737d69 +0, 288000, 288000, 1152, 2304, 0xc28b7385 +0, 289152, 289152, 1152, 2304, 0xce1b7f16 +0, 290304, 290304, 1152, 2304, 0xa5e180fe +0, 291456, 291456, 1152, 2304, 0xb1788164 +0, 292608, 292608, 1152, 2304, 0xa6698076 +0, 293760, 293760, 1152, 2304, 0x2c017f8e +0, 294912, 294912, 1152, 2304, 0x8359743b +0, 296064, 296064, 1152, 2304, 0xcb4c8146 +0, 297216, 297216, 1152, 2304, 0x505d6f12 +0, 298368, 298368, 1152, 2304, 0x5ba16a70 +0, 299520, 299520, 1152, 2304, 0xdb8988d3 +0, 300672, 300672, 1152, 2304, 0x24447075 +0, 301824, 301824, 1152, 2304, 0x506e8a8b +0, 302976, 302976, 1152, 2304, 0xe0c5728e +0, 304128, 304128, 1152, 2304, 0x67d57a36 +0, 305280, 305280, 1152, 2304, 0x1d27908b +0, 306432, 306432, 1152, 2304, 0xbeaf7c71 +0, 307584, 307584, 1152, 2304, 0x437678ed +0, 308736, 308736, 1152, 2304, 0x0bca7b50 +0, 309888, 309888, 1152, 2304, 0xa7858205 +0, 311040, 311040, 1152, 2304, 0x294573c9 +0, 312192, 312192, 1152, 2304, 0x519271a2 +0, 313344, 313344, 1152, 2304, 0x3c4676f6 +0, 314496, 314496, 1152, 2304, 0x449e76cd +0, 315648, 315648, 1152, 2304, 0x17248928 +0, 316800, 316800, 1152, 2304, 0x585367ed +0, 317952, 317952, 1152, 2304, 0xb70a7fa4 +0, 319104, 319104, 1152, 2304, 0x3ee18149 +0, 320256, 320256, 1152, 2304, 0x019c8782 +0, 321408, 321408, 1152, 2304, 0x38ab639d +0, 322560, 322560, 1152, 2304, 0x289c6f68 +0, 323712, 323712, 1152, 2304, 0xe7597fe2 +0, 324864, 324864, 1152, 2304, 0x80ff80ac +0, 326016, 326016, 1152, 2304, 0xafe86ee3 +0, 327168, 327168, 1152, 2304, 0x9f3f8a4d +0, 328320, 328320, 1152, 2304, 0x1fae83b4 +0, 329472, 329472, 1152, 2304, 0x9b087557 +0, 330624, 330624, 1152, 2304, 0x3f0280bd +0, 331776, 331776, 1152, 2304, 0xd82b7c15 +0, 332928, 332928, 1152, 2304, 0xe1f18560 +0, 334080, 334080, 1152, 2304, 0xcf857ae8 +0, 335232, 335232, 1152, 2304, 0x1037786e +0, 336384, 336384, 1152, 2304, 0x52e17ed1 +0, 337536, 337536, 1152, 2304, 0x1ebc7456 +0, 338688, 338688, 1152, 2304, 0xf3de8040 +0, 339840, 339840, 1152, 2304, 0x71657685 +0, 340992, 340992, 1152, 2304, 0x6e5c7d5d +0, 342144, 342144, 1152, 2304, 0x147d68bb +0, 343296, 343296, 1152, 2304, 0xc43e6d62 +0, 344448, 344448, 1152, 2304, 0x1b34783c +0, 345600, 345600, 1152, 2304, 0xe2c97e7e +0, 346752, 346752, 1152, 2304, 0xcaf97991 +0, 347904, 347904, 1152, 2304, 0xee117db9 +0, 349056, 349056, 1152, 2304, 0x7cdc810a +0, 350208, 350208, 1152, 2304, 0x2d687abb +0, 351360, 351360, 1152, 2304, 0x7ccf84fa +0, 352512, 352512, 1152, 2304, 0x3bc25b1d diff --git a/tests/ref/fate/hls-list-size b/tests/ref/fate/hls-list-size new file mode 100644 index 000000000..cf7fb9fe3 --- /dev/null +++ b/tests/ref/fate/hls-list-size @@ -0,0 +1,618 @@ +#tb 0: 1/44100 +#media_type 0: audio +#codec_id 0: pcm_s16le +#sample_rate 0: 44100 +#channel_layout 0: 4 +#channel_layout_name 0: mono +0, 0, 0, 1152, 2304, 0x9ce3278a +0, 1152, 1152, 1152, 2304, 0x5cd17b17 +0, 2304, 2304, 1152, 2304, 0x8aec82c5 +0, 3456, 3456, 1152, 2304, 0xe8ce8fbc +0, 4608, 4608, 1152, 2304, 0x262c69da +0, 5760, 5760, 1152, 2304, 0x6afc7ad6 +0, 6912, 6912, 1152, 2304, 0x9f2a7370 +0, 8064, 8064, 1152, 2304, 0x88fe7bcc +0, 9216, 9216, 1152, 2304, 0x228b8bab +0, 10368, 10368, 1152, 2304, 0xd87f8c71 +0, 11520, 11520, 1152, 2304, 0x82989151 +0, 12672, 12672, 1152, 2304, 0x1e0f7aae +0, 13824, 13824, 1152, 2304, 0xbdcc7d72 +0, 14976, 14976, 1152, 2304, 0xa7af8875 +0, 16128, 16128, 1152, 2304, 0xb9aa7834 +0, 17280, 17280, 1152, 2304, 0xea8e6e76 +0, 18432, 18432, 1152, 2304, 0x7bbe6bae +0, 19584, 19584, 1152, 2304, 0x2bbd817f +0, 20736, 20736, 1152, 2304, 0xccd46c86 +0, 21888, 21888, 1152, 2304, 0x603178d2 +0, 23040, 23040, 1152, 2304, 0xa2d283d7 +0, 24192, 24192, 1152, 2304, 0xc6e97caa +0, 25344, 25344, 1152, 2304, 0x67e06e6d +0, 26496, 26496, 1152, 2304, 0x27c47d51 +0, 27648, 27648, 1152, 2304, 0x17f47cd7 +0, 28800, 28800, 1152, 2304, 0xbedb75b0 +0, 29952, 29952, 1152, 2304, 0xeb1f72fd +0, 31104, 31104, 1152, 2304, 0x6dae79e9 +0, 32256, 32256, 1152, 2304, 0x90e36f0e +0, 33408, 33408, 1152, 2304, 0xe0748431 +0, 34560, 34560, 1152, 2304, 0xa78f6d76 +0, 35712, 35712, 1152, 2304, 0xa9cf7cd4 +0, 36864, 36864, 1152, 2304, 0xfa12796c +0, 38016, 38016, 1152, 2304, 0x73d47c88 +0, 39168, 39168, 1152, 2304, 0xec8c74ef +0, 40320, 40320, 1152, 2304, 0x6eda793d +0, 41472, 41472, 1152, 2304, 0xd26c7e3f +0, 42624, 42624, 1152, 2304, 0xd7e3788d +0, 43776, 43776, 1152, 2304, 0x4f26748c +0, 44928, 44928, 1152, 2304, 0x7ce07ec0 +0, 46080, 46080, 1152, 2304, 0x72ab7bba +0, 47232, 47232, 1152, 2304, 0x287b73b9 +0, 48384, 48384, 1152, 2304, 0x78b8822b +0, 49536, 49536, 1152, 2304, 0x9cc46ff6 +0, 50688, 50688, 1152, 2304, 0x2fdd7bb5 +0, 51840, 51840, 1152, 2304, 0x03118776 +0, 52992, 52992, 1152, 2304, 0x1f0e7403 +0, 54144, 54144, 1152, 2304, 0xfbd97c1e +0, 55296, 55296, 1152, 2304, 0xcd118405 +0, 56448, 56448, 1152, 2304, 0xb5ce78b0 +0, 57600, 57600, 1152, 2304, 0x87b27d88 +0, 58752, 58752, 1152, 2304, 0xebd07236 +0, 59904, 59904, 1152, 2304, 0xc27c6e08 +0, 61056, 61056, 1152, 2304, 0xe17f7b8c +0, 62208, 62208, 1152, 2304, 0x46ac674d +0, 63360, 63360, 1152, 2304, 0x44d47b09 +0, 64512, 64512, 1152, 2304, 0x8901812d +0, 65664, 65664, 1152, 2304, 0xc348754a +0, 66816, 66816, 1152, 2304, 0xd6b27474 +0, 67968, 67968, 1152, 2304, 0x6dbd84aa +0, 69120, 69120, 1152, 2304, 0x47a3706b +0, 70272, 70272, 1152, 2304, 0x162188b2 +0, 71424, 71424, 1152, 2304, 0xf127955f +0, 72576, 72576, 1152, 2304, 0xce3d6a56 +0, 73728, 73728, 1152, 2304, 0x32308305 +0, 74880, 74880, 1152, 2304, 0xa7088301 +0, 76032, 76032, 1152, 2304, 0xed6670df +0, 77184, 77184, 1152, 2304, 0xbfe1782a +0, 78336, 78336, 1152, 2304, 0x4ac26f21 +0, 79488, 79488, 1152, 2304, 0x37557da5 +0, 80640, 80640, 1152, 2304, 0x7bb580ff +0, 81792, 81792, 1152, 2304, 0xf76f74be +0, 82944, 82944, 1152, 2304, 0x68557e8c +0, 84096, 84096, 1152, 2304, 0x3f6d88b0 +0, 85248, 85248, 1152, 2304, 0xbfa47c4b +0, 86400, 86400, 1152, 2304, 0xb58d9447 +0, 87552, 87552, 1152, 2304, 0xc297794f +0, 88704, 88704, 1152, 2304, 0x36a36c0c +0, 89856, 89856, 1152, 2304, 0x15d777dc +0, 91008, 91008, 1152, 2304, 0xa16b91bb +0, 92160, 92160, 1152, 2304, 0x064f7a49 +0, 93312, 93312, 1152, 2304, 0xe8ea879e +0, 94464, 94464, 1152, 2304, 0xb8137f82 +0, 95616, 95616, 1152, 2304, 0x3f2976b1 +0, 96768, 96768, 1152, 2304, 0xfafe7084 +0, 97920, 97920, 1152, 2304, 0x29948b18 +0, 99072, 99072, 1152, 2304, 0x83577094 +0, 100224, 100224, 1152, 2304, 0x753c7e16 +0, 101376, 101376, 1152, 2304, 0xe2587d1c +0, 102528, 102528, 1152, 2304, 0x84817e44 +0, 103680, 103680, 1152, 2304, 0xcdf07acc +0, 104832, 104832, 1152, 2304, 0x981d7248 +0, 105984, 105984, 1152, 2304, 0x8dd16bc9 +0, 107136, 107136, 1152, 2304, 0x6fb57995 +0, 108288, 108288, 1152, 2304, 0x0cf88687 +0, 109440, 109440, 1152, 2304, 0xf6a885b3 +0, 110592, 110592, 1152, 2304, 0xe34e7e42 +0, 111744, 111744, 1152, 2304, 0x4c357d73 +0, 112896, 112896, 1152, 2304, 0x5fee64da +0, 114048, 114048, 1152, 2304, 0x090e8931 +0, 115200, 115200, 1152, 2304, 0xf2768294 +0, 116352, 116352, 1152, 2304, 0xec607554 +0, 117504, 117504, 1152, 2304, 0x76d17983 +0, 118656, 118656, 1152, 2304, 0xdc357eea +0, 119808, 119808, 1152, 2304, 0xd8c56e20 +0, 120960, 120960, 1152, 2304, 0x98367f2c +0, 122112, 122112, 1152, 2304, 0xe3af7dc5 +0, 123264, 123264, 1152, 2304, 0x0c6e85a9 +0, 124416, 124416, 1152, 2304, 0x5b89743f +0, 125568, 125568, 1152, 2304, 0xb0bf7893 +0, 126720, 126720, 1152, 2304, 0xee887a4e +0, 127872, 127872, 1152, 2304, 0xc39f76a9 +0, 129024, 129024, 1152, 2304, 0x521c8986 +0, 130176, 130176, 1152, 2304, 0x101e6f4d +0, 131328, 131328, 1152, 2304, 0x5d3a7a6f +0, 132480, 132480, 1152, 2304, 0xeafe724a +0, 133632, 133632, 1152, 2304, 0xba4d83cc +0, 134784, 134784, 1152, 2304, 0x74c86bc9 +0, 135936, 135936, 1152, 2304, 0x275675d5 +0, 137088, 137088, 1152, 2304, 0xab577a90 +0, 138240, 138240, 1152, 2304, 0xf62b80da +0, 139392, 139392, 1152, 2304, 0x70f68783 +0, 140544, 140544, 1152, 2304, 0x87e779e7 +0, 141696, 141696, 1152, 2304, 0x25cd6a02 +0, 142848, 142848, 1152, 2304, 0x235c83d4 +0, 144000, 144000, 1152, 2304, 0xb44b931f +0, 145152, 145152, 1152, 2304, 0x9c9979f1 +0, 146304, 146304, 1152, 2304, 0x15a07ee7 +0, 147456, 147456, 1152, 2304, 0xb57079c5 +0, 148608, 148608, 1152, 2304, 0x65c66aa9 +0, 149760, 149760, 1152, 2304, 0xd3f9747b +0, 150912, 150912, 1152, 2304, 0x3e89801c +0, 152064, 152064, 1152, 2304, 0x128d8109 +0, 153216, 153216, 1152, 2304, 0x56518ba3 +0, 154368, 154368, 1152, 2304, 0xe889895f +0, 155520, 155520, 1152, 2304, 0x3474839f +0, 156672, 156672, 1152, 2304, 0x3c928795 +0, 157824, 157824, 1152, 2304, 0x0d55681f +0, 158976, 158976, 1152, 2304, 0xff086f7a +0, 160128, 160128, 1152, 2304, 0xa0d373be +0, 161280, 161280, 1152, 2304, 0x9d3f7cf3 +0, 162432, 162432, 1152, 2304, 0x4b4a784e +0, 163584, 163584, 1152, 2304, 0xba89786d +0, 164736, 164736, 1152, 2304, 0x038b8a64 +0, 165888, 165888, 1152, 2304, 0xbaf678d8 +0, 167040, 167040, 1152, 2304, 0xf198779c +0, 168192, 168192, 1152, 2304, 0xb9b18a2c +0, 169344, 169344, 1152, 2304, 0x46e68131 +0, 170496, 170496, 1152, 2304, 0xe0638143 +0, 171648, 171648, 1152, 2304, 0x438488d0 +0, 172800, 172800, 1152, 2304, 0x8ade7697 +0, 173952, 173952, 1152, 2304, 0xaf9c6e3f +0, 175104, 175104, 1152, 2304, 0x54016fa9 +0, 176256, 176256, 1152, 2304, 0xe7aa6f4d +0, 177408, 177408, 1152, 2304, 0x32987abf +0, 178560, 178560, 1152, 2304, 0xd0dc8d33 +0, 179712, 179712, 1152, 2304, 0xa7708531 +0, 180864, 180864, 1152, 2304, 0xd01d7c82 +0, 182016, 182016, 1152, 2304, 0xfb267944 +0, 183168, 183168, 1152, 2304, 0x01f28885 +0, 184320, 184320, 1152, 2304, 0x2bb382cf +0, 185472, 185472, 1152, 2304, 0x40337214 +0, 186624, 186624, 1152, 2304, 0x6f496f46 +0, 187776, 187776, 1152, 2304, 0x55297b3b +0, 188928, 188928, 1152, 2304, 0xd2c77692 +0, 190080, 190080, 1152, 2304, 0x7b8c61d6 +0, 191232, 191232, 1152, 2304, 0x5f4a8337 +0, 192384, 192384, 1152, 2304, 0x3b7d820e +0, 193536, 193536, 1152, 2304, 0xbe4c7f51 +0, 194688, 194688, 1152, 2304, 0x4f68815d +0, 195840, 195840, 1152, 2304, 0xdfd77b14 +0, 196992, 196992, 1152, 2304, 0xc7558879 +0, 198144, 198144, 1152, 2304, 0x6a8678ed +0, 199296, 199296, 1152, 2304, 0x5fd47b81 +0, 200448, 200448, 1152, 2304, 0xebc27fd5 +0, 201600, 201600, 1152, 2304, 0xabd77a22 +0, 202752, 202752, 1152, 2304, 0xd98a6d78 +0, 203904, 203904, 1152, 2304, 0xd30b8098 +0, 205056, 205056, 1152, 2304, 0xdf32793f +0, 206208, 206208, 1152, 2304, 0x8c317928 +0, 207360, 207360, 1152, 2304, 0x83958430 +0, 208512, 208512, 1152, 2304, 0xea357619 +0, 209664, 209664, 1152, 2304, 0x074b9110 +0, 210816, 210816, 1152, 2304, 0x5e686edb +0, 211968, 211968, 1152, 2304, 0xe6f97a38 +0, 213120, 213120, 1152, 2304, 0x440c829c +0, 214272, 214272, 1152, 2304, 0x96b57eab +0, 215424, 215424, 1152, 2304, 0x96f466fc +0, 216576, 216576, 1152, 2304, 0x49277cae +0, 217728, 217728, 1152, 2304, 0xee5b7cf9 +0, 218880, 218880, 1152, 2304, 0x9fd483b5 +0, 220032, 220032, 1152, 2304, 0x99bd90ac +0, 221184, 221184, 1152, 2304, 0xe03a73f7 +0, 222336, 222336, 1152, 2304, 0xe1737408 +0, 223488, 223488, 1152, 2304, 0xc14578b1 +0, 224640, 224640, 1152, 2304, 0x34b18638 +0, 225792, 225792, 1152, 2304, 0xb1707659 +0, 226944, 226944, 1152, 2304, 0x56a45cd1 +0, 228096, 228096, 1152, 2304, 0x6f608d48 +0, 229248, 229248, 1152, 2304, 0xd044886f +0, 230400, 230400, 1152, 2304, 0x4a827bf0 +0, 231552, 231552, 1152, 2304, 0x58298536 +0, 232704, 232704, 1152, 2304, 0x06147843 +0, 233856, 233856, 1152, 2304, 0x520d6c4a +0, 235008, 235008, 1152, 2304, 0xfb3089eb +0, 236160, 236160, 1152, 2304, 0x762b788f +0, 237312, 237312, 1152, 2304, 0x0a888eeb +0, 238464, 238464, 1152, 2304, 0xdf617fbc +0, 239616, 239616, 1152, 2304, 0xd18474f4 +0, 240768, 240768, 1152, 2304, 0x77e170c9 +0, 241920, 241920, 1152, 2304, 0xed557d69 +0, 243072, 243072, 1152, 2304, 0xc2397385 +0, 244224, 244224, 1152, 2304, 0xcee57f16 +0, 245376, 245376, 1152, 2304, 0x6a197fff +0, 246528, 246528, 1152, 2304, 0xb17c8164 +0, 247680, 247680, 1152, 2304, 0xb8707e78 +0, 248832, 248832, 1152, 2304, 0x2ba77f8e +0, 249984, 249984, 1152, 2304, 0x3dbd753b +0, 251136, 251136, 1152, 2304, 0xf4948145 +0, 252288, 252288, 1152, 2304, 0x3ab77110 +0, 253440, 253440, 1152, 2304, 0x5c656a71 +0, 254592, 254592, 1152, 2304, 0xd33388d2 +0, 255744, 255744, 1152, 2304, 0x23de7075 +0, 256896, 256896, 1152, 2304, 0x51d28a8c +0, 258048, 258048, 1152, 2304, 0x6c6e718e +0, 259200, 259200, 1152, 2304, 0x67c77a36 +0, 260352, 260352, 1152, 2304, 0x79178f8c +0, 261504, 261504, 1152, 2304, 0xbe817c71 +0, 262656, 262656, 1152, 2304, 0x103a79ec +0, 263808, 263808, 1152, 2304, 0x0bd07b50 +0, 264960, 264960, 1152, 2304, 0xa6278205 +0, 266112, 266112, 1152, 2304, 0xbb3d72cb +0, 267264, 267264, 1152, 2304, 0x47dc71a1 +0, 268416, 268416, 1152, 2304, 0x3dd876f6 +0, 269568, 269568, 1152, 2304, 0x6dd275ce +0, 270720, 270720, 1152, 2304, 0xeb12882a +0, 271872, 271872, 1152, 2304, 0x99ac68eb +0, 273024, 273024, 1152, 2304, 0xb86c7fa4 +0, 274176, 274176, 1152, 2304, 0x6315804a +0, 275328, 275328, 1152, 2304, 0x034e8782 +0, 276480, 276480, 1152, 2304, 0x9605629e +0, 277632, 277632, 1152, 2304, 0xdb736f68 +0, 278784, 278784, 1152, 2304, 0xe6c97fe3 +0, 279936, 279936, 1152, 2304, 0x7a9980ab +0, 281088, 281088, 1152, 2304, 0xb0906ee3 +0, 282240, 282240, 1152, 2304, 0x9ea58a4d +0, 283392, 283392, 1152, 2304, 0x1f6283b4 +0, 284544, 284544, 1152, 2304, 0x9be27557 +0, 285696, 285696, 1152, 2304, 0x3fec80bd +0, 286848, 286848, 1152, 2304, 0xdf477b16 +0, 288000, 288000, 1152, 2304, 0x3708865f +0, 289152, 289152, 1152, 2304, 0xd0297ae8 +0, 290304, 290304, 1152, 2304, 0x0ebd786e +0, 291456, 291456, 1152, 2304, 0x52b77ed1 +0, 292608, 292608, 1152, 2304, 0x13a77357 +0, 293760, 293760, 1152, 2304, 0xf3ac8040 +0, 294912, 294912, 1152, 2304, 0x72517685 +0, 296064, 296064, 1152, 2304, 0x9f1f7c5e +0, 297216, 297216, 1152, 2304, 0x14d368bb +0, 298368, 298368, 1152, 2304, 0xc52e6d62 +0, 299520, 299520, 1152, 2304, 0x1ade783c +0, 300672, 300672, 1152, 2304, 0x34387d7f +0, 301824, 301824, 1152, 2304, 0x48957a90 +0, 302976, 302976, 1152, 2304, 0xf1a57db9 +0, 304128, 304128, 1152, 2304, 0x7d22810a +0, 305280, 305280, 1152, 2304, 0x2e187abb +0, 306432, 306432, 1152, 2304, 0x0d6b85f9 +0, 307584, 307584, 1152, 2304, 0xc2a77428 +0, 308736, 308736, 1152, 2304, 0x173a7717 +0, 309888, 309888, 1152, 2304, 0x53bf986c +0, 311040, 311040, 1152, 2304, 0xa9c082b1 +0, 312192, 312192, 1152, 2304, 0x9d9b6fd6 +0, 313344, 313344, 1152, 2304, 0xc4898426 +0, 314496, 314496, 1152, 2304, 0x60236ff7 +0, 315648, 315648, 1152, 2304, 0x7e7a7a9e +0, 316800, 316800, 1152, 2304, 0x66a9844e +0, 317952, 317952, 1152, 2304, 0x45188372 +0, 319104, 319104, 1152, 2304, 0x068f6e23 +0, 320256, 320256, 1152, 2304, 0x853083d2 +0, 321408, 321408, 1152, 2304, 0x79ad8782 +0, 322560, 322560, 1152, 2304, 0x210098c5 +0, 323712, 323712, 1152, 2304, 0xd1a77d01 +0, 324864, 324864, 1152, 2304, 0xfc8389f6 +0, 326016, 326016, 1152, 2304, 0xf59f88bd +0, 327168, 327168, 1152, 2304, 0x6fa97843 +0, 328320, 328320, 1152, 2304, 0x0a62893a +0, 329472, 329472, 1152, 2304, 0x0c07763c +0, 330624, 330624, 1152, 2304, 0x9a817309 +0, 331776, 331776, 1152, 2304, 0xbe927c16 +0, 332928, 332928, 1152, 2304, 0x7e1e7541 +0, 334080, 334080, 1152, 2304, 0x9aec738d +0, 335232, 335232, 1152, 2304, 0x5a706ef6 +0, 336384, 336384, 1152, 2304, 0x2be7862c +0, 337536, 337536, 1152, 2304, 0xc6266696 +0, 338688, 338688, 1152, 2304, 0x02107e20 +0, 339840, 339840, 1152, 2304, 0x3fe67b09 +0, 340992, 340992, 1152, 2304, 0x3fd38b14 +0, 342144, 342144, 1152, 2304, 0xd23d7eeb +0, 343296, 343296, 1152, 2304, 0x52818719 +0, 344448, 344448, 1152, 2304, 0x78cd7ac8 +0, 345600, 345600, 1152, 2304, 0x82676a95 +0, 346752, 346752, 1152, 2304, 0xa73b8b5f +0, 347904, 347904, 1152, 2304, 0x51008ea9 +0, 349056, 349056, 1152, 2304, 0xaf9e784c +0, 350208, 350208, 1152, 2304, 0xfaf56ca9 +0, 351360, 351360, 1152, 2304, 0xd9d67582 +0, 352512, 352512, 1152, 2304, 0x3a9c77b2 +0, 353664, 353664, 1152, 2304, 0xe4557e60 +0, 354816, 354816, 1152, 2304, 0x1df079a5 +0, 355968, 355968, 1152, 2304, 0xd9377543 +0, 357120, 357120, 1152, 2304, 0xdf2e6d2e +0, 358272, 358272, 1152, 2304, 0xfd8983c7 +0, 359424, 359424, 1152, 2304, 0x050c7d17 +0, 360576, 360576, 1152, 2304, 0x62907ce9 +0, 361728, 361728, 1152, 2304, 0x324395a4 +0, 362880, 362880, 1152, 2304, 0xb0396e5b +0, 364032, 364032, 1152, 2304, 0xb0f48243 +0, 365184, 365184, 1152, 2304, 0xf2698178 +0, 366336, 366336, 1152, 2304, 0xa8b478af +0, 367488, 367488, 1152, 2304, 0x7407713d +0, 368640, 368640, 1152, 2304, 0xaf3a780f +0, 369792, 369792, 1152, 2304, 0x29d37ae3 +0, 370944, 370944, 1152, 2304, 0x63ed8495 +0, 372096, 372096, 1152, 2304, 0xd37d82d5 +0, 373248, 373248, 1152, 2304, 0x70518328 +0, 374400, 374400, 1152, 2304, 0x35b396c1 +0, 375552, 375552, 1152, 2304, 0xef88749c +0, 376704, 376704, 1152, 2304, 0x675382a0 +0, 377856, 377856, 1152, 2304, 0x29447c5b +0, 379008, 379008, 1152, 2304, 0x8af97319 +0, 380160, 380160, 1152, 2304, 0xa47d7224 +0, 381312, 381312, 1152, 2304, 0xa46d6d2c +0, 382464, 382464, 1152, 2304, 0x46337596 +0, 383616, 383616, 1152, 2304, 0x01417512 +0, 384768, 384768, 1152, 2304, 0x18b982c3 +0, 385920, 385920, 1152, 2304, 0x39056a8e +0, 387072, 387072, 1152, 2304, 0xb6b07bfc +0, 388224, 388224, 1152, 2304, 0xe2b58b2a +0, 389376, 389376, 1152, 2304, 0xc5687366 +0, 390528, 390528, 1152, 2304, 0xf66d75f3 +0, 391680, 391680, 1152, 2304, 0x29ab764e +0, 392832, 392832, 1152, 2304, 0x682980c1 +0, 393984, 393984, 1152, 2304, 0x6ee1906c +0, 395136, 395136, 1152, 2304, 0xedba82ac +0, 396288, 396288, 1152, 2304, 0x335f8204 +0, 397440, 397440, 1152, 2304, 0x002079b1 +0, 398592, 398592, 1152, 2304, 0x35986caf +0, 399744, 399744, 1152, 2304, 0x50a87a74 +0, 400896, 400896, 1152, 2304, 0x20587f4d +0, 402048, 402048, 1152, 2304, 0xe9d47f97 +0, 403200, 403200, 1152, 2304, 0x08fc74ce +0, 404352, 404352, 1152, 2304, 0x39f88373 +0, 405504, 405504, 1152, 2304, 0x376e7a1f +0, 406656, 406656, 1152, 2304, 0x1ad17600 +0, 407808, 407808, 1152, 2304, 0xfb358cab +0, 408960, 408960, 1152, 2304, 0x3c2072b7 +0, 410112, 410112, 1152, 2304, 0xbcc962ff +0, 411264, 411264, 1152, 2304, 0xa4b48477 +0, 412416, 412416, 1152, 2304, 0x9d1f78d6 +0, 413568, 413568, 1152, 2304, 0x0eb9773d +0, 414720, 414720, 1152, 2304, 0xab9b8ec6 +0, 415872, 415872, 1152, 2304, 0x54aa78ac +0, 417024, 417024, 1152, 2304, 0xccf66d69 +0, 418176, 418176, 1152, 2304, 0xe0667ff3 +0, 419328, 419328, 1152, 2304, 0xbf337e47 +0, 420480, 420480, 1152, 2304, 0xfa3b8386 +0, 421632, 421632, 1152, 2304, 0xc13e8062 +0, 422784, 422784, 1152, 2304, 0xa3957bda +0, 423936, 423936, 1152, 2304, 0x807b777f +0, 425088, 425088, 1152, 2304, 0x349874ad +0, 426240, 426240, 1152, 2304, 0x924486c5 +0, 427392, 427392, 1152, 2304, 0x32c76310 +0, 428544, 428544, 1152, 2304, 0x572e7a6a +0, 429696, 429696, 1152, 2304, 0x12987eae +0, 430848, 430848, 1152, 2304, 0xb79a7b9e +0, 432000, 432000, 1152, 2304, 0xc77f60a0 +0, 433152, 433152, 1152, 2304, 0x997e91eb +0, 434304, 434304, 1152, 2304, 0xcfe17515 +0, 435456, 435456, 1152, 2304, 0x81c67c01 +0, 436608, 436608, 1152, 2304, 0xd83c7041 +0, 437760, 437760, 1152, 2304, 0x8f0579c0 +0, 438912, 438912, 1152, 2304, 0x685e7dce +0, 440064, 440064, 1152, 2304, 0xac3e7e49 +0, 441216, 441216, 1152, 2304, 0xc6bb7265 +0, 442368, 442368, 1152, 2304, 0xede17e23 +0, 443520, 443520, 1152, 2304, 0x7e127c9a +0, 444672, 444672, 1152, 2304, 0xdc727ff1 +0, 445824, 445824, 1152, 2304, 0x0bba6ba9 +0, 446976, 446976, 1152, 2304, 0x970687ec +0, 448128, 448128, 1152, 2304, 0x738469f2 +0, 449280, 449280, 1152, 2304, 0x7b7c943d +0, 450432, 450432, 1152, 2304, 0x2ee4796d +0, 451584, 451584, 1152, 2304, 0xebfb7423 +0, 452736, 452736, 1152, 2304, 0x84ba82a3 +0, 453888, 453888, 1152, 2304, 0xbd417240 +0, 455040, 455040, 1152, 2304, 0x52dc8b7a +0, 456192, 456192, 1152, 2304, 0xab707213 +0, 457344, 457344, 1152, 2304, 0x76da8ba9 +0, 458496, 458496, 1152, 2304, 0x9bed6f07 +0, 459648, 459648, 1152, 2304, 0x5c727358 +0, 460800, 460800, 1152, 2304, 0xd09c7f4e +0, 461952, 461952, 1152, 2304, 0xf42887c8 +0, 463104, 463104, 1152, 2304, 0xb8067cd0 +0, 464256, 464256, 1152, 2304, 0x4fed74bb +0, 465408, 465408, 1152, 2304, 0x41bb650a +0, 466560, 466560, 1152, 2304, 0xf08e87da +0, 467712, 467712, 1152, 2304, 0x324d72cd +0, 468864, 468864, 1152, 2304, 0x4db57b28 +0, 470016, 470016, 1152, 2304, 0x01d47145 +0, 471168, 471168, 1152, 2304, 0xcae06f33 +0, 472320, 472320, 1152, 2304, 0x428d7e4f +0, 473472, 473472, 1152, 2304, 0x621c89dd +0, 474624, 474624, 1152, 2304, 0x70426d1d +0, 475776, 475776, 1152, 2304, 0xa47987ee +0, 476928, 476928, 1152, 2304, 0xb0b46ac6 +0, 478080, 478080, 1152, 2304, 0xd2b2806e +0, 479232, 479232, 1152, 2304, 0xcf577c1b +0, 480384, 480384, 1152, 2304, 0xa7347d48 +0, 481536, 481536, 1152, 2304, 0x4c2d8325 +0, 482688, 482688, 1152, 2304, 0x57297122 +0, 483840, 483840, 1152, 2304, 0x6891769a +0, 484992, 484992, 1152, 2304, 0x2e5c7172 +0, 486144, 486144, 1152, 2304, 0x36d97997 +0, 487296, 487296, 1152, 2304, 0xd511904f +0, 488448, 488448, 1152, 2304, 0x2ad78293 +0, 489600, 489600, 1152, 2304, 0x7bb46e0e +0, 490752, 490752, 1152, 2304, 0x199d7795 +0, 491904, 491904, 1152, 2304, 0x42167793 +0, 493056, 493056, 1152, 2304, 0x13726c20 +0, 494208, 494208, 1152, 2304, 0x04fa874a +0, 495360, 495360, 1152, 2304, 0x41016f66 +0, 496512, 496512, 1152, 2304, 0x0d8880e3 +0, 497664, 497664, 1152, 2304, 0x107d6fd2 +0, 498816, 498816, 1152, 2304, 0x145b7777 +0, 499968, 499968, 1152, 2304, 0xba228f96 +0, 501120, 501120, 1152, 2304, 0x4f97707e +0, 502272, 502272, 1152, 2304, 0xa7b86c74 +0, 503424, 503424, 1152, 2304, 0xce588037 +0, 504576, 504576, 1152, 2304, 0xdf0577f0 +0, 505728, 505728, 1152, 2304, 0xcde37685 +0, 506880, 506880, 1152, 2304, 0x2c7c5d92 +0, 508032, 508032, 1152, 2304, 0xe3937d6e +0, 509184, 509184, 1152, 2304, 0xee5f7842 +0, 510336, 510336, 1152, 2304, 0x67dd66bd +0, 511488, 511488, 1152, 2304, 0xbafc65ed +0, 512640, 512640, 1152, 2304, 0x579a8063 +0, 513792, 513792, 1152, 2304, 0xa06484ff +0, 514944, 514944, 1152, 2304, 0x93318c07 +0, 516096, 516096, 1152, 2304, 0x54067277 +0, 517248, 517248, 1152, 2304, 0x02d785b4 +0, 518400, 518400, 1152, 2304, 0x999a7b1c +0, 519552, 519552, 1152, 2304, 0xcf67856e +0, 520704, 520704, 1152, 2304, 0x55d683ed +0, 521856, 521856, 1152, 2304, 0x502c7cbf +0, 523008, 523008, 1152, 2304, 0x05177a4c +0, 524160, 524160, 1152, 2304, 0x272a75e0 +0, 525312, 525312, 1152, 2304, 0x5659771e +0, 526464, 526464, 1152, 2304, 0xc3267c2f +0, 527616, 527616, 1152, 2304, 0x58b67b26 +0, 528768, 528768, 1152, 2304, 0x705c7d96 +0, 529920, 529920, 1152, 2304, 0xc8db8461 +0, 531072, 531072, 1152, 2304, 0xfae1717a +0, 532224, 532224, 1152, 2304, 0xb44b7707 +0, 533376, 533376, 1152, 2304, 0x57fb7a91 +0, 534528, 534528, 1152, 2304, 0xe76c8082 +0, 535680, 535680, 1152, 2304, 0xaf1e8256 +0, 536832, 536832, 1152, 2304, 0xc4ca7f89 +0, 537984, 537984, 1152, 2304, 0x6cd681ba +0, 539136, 539136, 1152, 2304, 0xc3e76c2b +0, 540288, 540288, 1152, 2304, 0x982b8bc5 +0, 541440, 541440, 1152, 2304, 0x21f975c0 +0, 542592, 542592, 1152, 2304, 0x5ce7854a +0, 543744, 543744, 1152, 2304, 0x67916923 +0, 544896, 544896, 1152, 2304, 0x1d107023 +0, 546048, 546048, 1152, 2304, 0xd0667153 +0, 547200, 547200, 1152, 2304, 0xdde57ca9 +0, 548352, 548352, 1152, 2304, 0xec10712e +0, 549504, 549504, 1152, 2304, 0x67a278be +0, 550656, 550656, 1152, 2304, 0x427079e3 +0, 551808, 551808, 1152, 2304, 0xe44c81e5 +0, 552960, 552960, 1152, 2304, 0xa4d78158 +0, 554112, 554112, 1152, 2304, 0x07308848 +0, 555264, 555264, 1152, 2304, 0x797372b4 +0, 556416, 556416, 1152, 2304, 0x02f676c9 +0, 557568, 557568, 1152, 2304, 0x0eb46723 +0, 558720, 558720, 1152, 2304, 0xb9d57aad +0, 559872, 559872, 1152, 2304, 0x05047d67 +0, 561024, 561024, 1152, 2304, 0xd80c7d04 +0, 562176, 562176, 1152, 2304, 0xbd5585de +0, 563328, 563328, 1152, 2304, 0xb2cd70b5 +0, 564480, 564480, 1152, 2304, 0x5c2b706b +0, 565632, 565632, 1152, 2304, 0xc75a7828 +0, 566784, 566784, 1152, 2304, 0x59e6833c +0, 567936, 567936, 1152, 2304, 0x8a808003 +0, 569088, 569088, 1152, 2304, 0x0f2674aa +0, 570240, 570240, 1152, 2304, 0xfa1a7bfe +0, 571392, 571392, 1152, 2304, 0x9c88762b +0, 572544, 572544, 1152, 2304, 0x59f778de +0, 573696, 573696, 1152, 2304, 0xf5997011 +0, 574848, 574848, 1152, 2304, 0xc90573cf +0, 576000, 576000, 1152, 2304, 0x2d3e83a8 +0, 577152, 577152, 1152, 2304, 0x233f6638 +0, 578304, 578304, 1152, 2304, 0xab636ade +0, 579456, 579456, 1152, 2304, 0x2c097965 +0, 580608, 580608, 1152, 2304, 0x95147620 +0, 581760, 581760, 1152, 2304, 0xe89e76fe +0, 582912, 582912, 1152, 2304, 0xe9668cc8 +0, 584064, 584064, 1152, 2304, 0x69677209 +0, 585216, 585216, 1152, 2304, 0x39097600 +0, 586368, 586368, 1152, 2304, 0x3bf97b15 +0, 587520, 587520, 1152, 2304, 0x492c7ee8 +0, 588672, 588672, 1152, 2304, 0xc2147c92 +0, 589824, 589824, 1152, 2304, 0xcb7b8b31 +0, 590976, 590976, 1152, 2304, 0x49707f80 +0, 592128, 592128, 1152, 2304, 0xe4067d9d +0, 593280, 593280, 1152, 2304, 0x416e81ce +0, 594432, 594432, 1152, 2304, 0x4ee57f03 +0, 595584, 595584, 1152, 2304, 0x3dbd7d5d +0, 596736, 596736, 1152, 2304, 0x2a107c8a +0, 597888, 597888, 1152, 2304, 0x02568927 +0, 599040, 599040, 1152, 2304, 0xf6f370e9 +0, 600192, 600192, 1152, 2304, 0x687c7c34 +0, 601344, 601344, 1152, 2304, 0xbadb74e7 +0, 602496, 602496, 1152, 2304, 0x11067d6d +0, 603648, 603648, 1152, 2304, 0x1d6d906b +0, 604800, 604800, 1152, 2304, 0xead26aed +0, 605952, 605952, 1152, 2304, 0x73988992 +0, 607104, 607104, 1152, 2304, 0x6b6d816a +0, 608256, 608256, 1152, 2304, 0xcd6a6fbf +0, 609408, 609408, 1152, 2304, 0xbff26ef1 +0, 610560, 610560, 1152, 2304, 0xe09b82f2 +0, 611712, 611712, 1152, 2304, 0xad536feb +0, 612864, 612864, 1152, 2304, 0x31777d5a +0, 614016, 614016, 1152, 2304, 0xff6b80e9 +0, 615168, 615168, 1152, 2304, 0x27b86e9e +0, 616320, 616320, 1152, 2304, 0x4b307e40 +0, 617472, 617472, 1152, 2304, 0x113577af +0, 618624, 618624, 1152, 2304, 0xcc257c8b +0, 619776, 619776, 1152, 2304, 0x984280bc +0, 620928, 620928, 1152, 2304, 0x25039dfe +0, 622080, 622080, 1152, 2304, 0x807d6f7d +0, 623232, 623232, 1152, 2304, 0x3e807d96 +0, 624384, 624384, 1152, 2304, 0x553f992e +0, 625536, 625536, 1152, 2304, 0x117783d2 +0, 626688, 626688, 1152, 2304, 0x0d986883 +0, 627840, 627840, 1152, 2304, 0x7c797ec2 +0, 628992, 628992, 1152, 2304, 0x5a317b3c +0, 630144, 630144, 1152, 2304, 0x44db77de +0, 631296, 631296, 1152, 2304, 0x22027e55 +0, 632448, 632448, 1152, 2304, 0x8c9a841f +0, 633600, 633600, 1152, 2304, 0xf6f27c2f +0, 634752, 634752, 1152, 2304, 0x2be471fb +0, 635904, 635904, 1152, 2304, 0xe35a7650 +0, 637056, 637056, 1152, 2304, 0x9c0a9044 +0, 638208, 638208, 1152, 2304, 0x25787f75 +0, 639360, 639360, 1152, 2304, 0xd2fb944b +0, 640512, 640512, 1152, 2304, 0x1de48222 +0, 641664, 641664, 1152, 2304, 0xc6628bf7 +0, 642816, 642816, 1152, 2304, 0x806983db +0, 643968, 643968, 1152, 2304, 0x071c7a86 +0, 645120, 645120, 1152, 2304, 0xda718335 +0, 646272, 646272, 1152, 2304, 0xc6b18f91 +0, 647424, 647424, 1152, 2304, 0xb00970e9 +0, 648576, 648576, 1152, 2304, 0x4055828b +0, 649728, 649728, 1152, 2304, 0x812471c9 +0, 650880, 650880, 1152, 2304, 0x68cf806b +0, 652032, 652032, 1152, 2304, 0xa8a87d7b +0, 653184, 653184, 1152, 2304, 0xcd387f97 +0, 654336, 654336, 1152, 2304, 0xeddd7c43 +0, 655488, 655488, 1152, 2304, 0xb78a88a6 +0, 656640, 656640, 1152, 2304, 0x01ef767b +0, 657792, 657792, 1152, 2304, 0xf5c776bd +0, 658944, 658944, 1152, 2304, 0xd96c7ebb +0, 660096, 660096, 1152, 2304, 0xd3f16f9b +0, 661248, 661248, 1152, 2304, 0x165c8208 +0, 662400, 662400, 1152, 2304, 0x10947227 +0, 663552, 663552, 1152, 2304, 0x382c82d7 +0, 664704, 664704, 1152, 2304, 0x07c87b8d +0, 665856, 665856, 1152, 2304, 0x1fbb7657 +0, 667008, 667008, 1152, 2304, 0xd6566e2f +0, 668160, 668160, 1152, 2304, 0x1b8c7d5b +0, 669312, 669312, 1152, 2304, 0xf3886fee +0, 670464, 670464, 1152, 2304, 0xdece8d75 +0, 671616, 671616, 1152, 2304, 0x72237c65 +0, 672768, 672768, 1152, 2304, 0xbabc6e66 +0, 673920, 673920, 1152, 2304, 0xe8f08b9f +0, 675072, 675072, 1152, 2304, 0x49d27348 +0, 676224, 676224, 1152, 2304, 0xa61286f8 +0, 677376, 677376, 1152, 2304, 0xa2b980cd +0, 678528, 678528, 1152, 2304, 0x7775838e +0, 679680, 679680, 1152, 2304, 0x15b57077 +0, 680832, 680832, 1152, 2304, 0x6a0a7522 +0, 681984, 681984, 1152, 2304, 0xdd8d8106 +0, 683136, 683136, 1152, 2304, 0x32fb82dc +0, 684288, 684288, 1152, 2304, 0x3b258143 +0, 685440, 685440, 1152, 2304, 0xfd0a9537 +0, 686592, 686592, 1152, 2304, 0x8467797b +0, 687744, 687744, 1152, 2304, 0xac4f7394 +0, 688896, 688896, 1152, 2304, 0xcb226a25 +0, 690048, 690048, 1152, 2304, 0xd39e813a +0, 691200, 691200, 1152, 2304, 0xf2067c35 +0, 692352, 692352, 1152, 2304, 0x46a77bff +0, 693504, 693504, 1152, 2304, 0xb6627b26 +0, 694656, 694656, 1152, 2304, 0xd6e28409 +0, 695808, 695808, 1152, 2304, 0xefc0832b +0, 696960, 696960, 1152, 2304, 0xa7b18479 +0, 698112, 698112, 1152, 2304, 0xdf618ff7 +0, 699264, 699264, 1152, 2304, 0xfe5b77e0 +0, 700416, 700416, 1152, 2304, 0xb30e7742 +0, 701568, 701568, 1152, 2304, 0x451d69e3 +0, 702720, 702720, 1152, 2304, 0x3d178531 +0, 703872, 703872, 1152, 2304, 0x177c5f79 diff --git a/tests/ref/fate/hls-segment-size b/tests/ref/fate/hls-segment-size new file mode 100644 index 000000000..ee3c7b2c6 --- /dev/null +++ b/tests/ref/fate/hls-segment-size @@ -0,0 +1,772 @@ +#tb 0: 1/44100 +#media_type 0: audio +#codec_id 0: pcm_s16le +#sample_rate 0: 44100 +#channel_layout 0: 4 +#channel_layout_name 0: mono +0, 0, 0, 1152, 2304, 0x907cb7fa +0, 1152, 1152, 1152, 2304, 0xb8dc7525 +0, 2304, 2304, 1152, 2304, 0x3e7d6905 +0, 3456, 3456, 1152, 2304, 0xef47877b +0, 4608, 4608, 1152, 2304, 0xfe916b7e +0, 5760, 5760, 1152, 2304, 0xe3d08cde +0, 6912, 6912, 1152, 2304, 0xff7f86cf +0, 8064, 8064, 1152, 2304, 0x843e6f95 +0, 9216, 9216, 1152, 2304, 0x81577c26 +0, 10368, 10368, 1152, 2304, 0x04a085d5 +0, 11520, 11520, 1152, 2304, 0x1c5a76f5 +0, 12672, 12672, 1152, 2304, 0x4ee78623 +0, 13824, 13824, 1152, 2304, 0x8ec861dc +0, 14976, 14976, 1152, 2304, 0x0ca179d8 +0, 16128, 16128, 1152, 2304, 0xc6da750f +0, 17280, 17280, 1152, 2304, 0xf6bf79b5 +0, 18432, 18432, 1152, 2304, 0x97b88a43 +0, 19584, 19584, 1152, 2304, 0xf13c7b9c +0, 20736, 20736, 1152, 2304, 0xdfba83af +0, 21888, 21888, 1152, 2304, 0xc9467d4b +0, 23040, 23040, 1152, 2304, 0xbbb58e2b +0, 24192, 24192, 1152, 2304, 0x3a1078ea +0, 25344, 25344, 1152, 2304, 0xe9587a5c +0, 26496, 26496, 1152, 2304, 0xef5a8039 +0, 27648, 27648, 1152, 2304, 0x9d5f782f +0, 28800, 28800, 1152, 2304, 0x1a548291 +0, 29952, 29952, 1152, 2304, 0x07517701 +0, 31104, 31104, 1152, 2304, 0x78127d6e +0, 32256, 32256, 1152, 2304, 0x62e2788a +0, 33408, 33408, 1152, 2304, 0x29397ad9 +0, 34560, 34560, 1152, 2304, 0x45da82d6 +0, 35712, 35712, 1152, 2304, 0x8ed66e51 +0, 36864, 36864, 1152, 2304, 0x660775cd +0, 38016, 38016, 1152, 2304, 0x802c767a +0, 39168, 39168, 1152, 2304, 0xcc055840 +0, 40320, 40320, 1152, 2304, 0x701b7eaf +0, 41472, 41472, 1152, 2304, 0x8290749f +0, 42624, 42624, 1152, 2304, 0x2c7b7d30 +0, 43776, 43776, 1152, 2304, 0xe4f17743 +0, 44928, 44928, 1152, 2304, 0x0e747d6e +0, 46080, 46080, 1152, 2304, 0xbe7775a0 +0, 47232, 47232, 1152, 2304, 0xcf797673 +0, 48384, 48384, 1152, 2304, 0x29cb7800 +0, 49536, 49536, 1152, 2304, 0xfc947890 +0, 50688, 50688, 1152, 2304, 0x62757fc6 +0, 51840, 51840, 1152, 2304, 0x098876d0 +0, 52992, 52992, 1152, 2304, 0xa9567ee2 +0, 54144, 54144, 1152, 2304, 0xe3bb9173 +0, 55296, 55296, 1152, 2304, 0xcc2d6dee +0, 56448, 56448, 1152, 2304, 0xe94591ab +0, 57600, 57600, 1152, 2304, 0x5c7588de +0, 58752, 58752, 1152, 2304, 0xfd83643c +0, 59904, 59904, 1152, 2304, 0x528177f1 +0, 61056, 61056, 1152, 2304, 0x65d08474 +0, 62208, 62208, 1152, 2304, 0x738d765b +0, 63360, 63360, 1152, 2304, 0xdd3d810e +0, 64512, 64512, 1152, 2304, 0xef4f90d3 +0, 65664, 65664, 1152, 2304, 0x61e28d43 +0, 66816, 66816, 1152, 2304, 0x9a11796b +0, 67968, 67968, 1152, 2304, 0x96c97dcd +0, 69120, 69120, 1152, 2304, 0xa8fe8621 +0, 70272, 70272, 1152, 2304, 0x499b7d38 +0, 71424, 71424, 1152, 2304, 0xfcb078a9 +0, 72576, 72576, 1152, 2304, 0x40d78651 +0, 73728, 73728, 1152, 2304, 0xa4af7234 +0, 74880, 74880, 1152, 2304, 0x6831870a +0, 76032, 76032, 1152, 2304, 0x030e7b9d +0, 77184, 77184, 1152, 2304, 0x445a75b6 +0, 78336, 78336, 1152, 2304, 0x09857389 +0, 79488, 79488, 1152, 2304, 0x0d018866 +0, 80640, 80640, 1152, 2304, 0x2afe810a +0, 81792, 81792, 1152, 2304, 0x0bcf7c43 +0, 82944, 82944, 1152, 2304, 0x13737c12 +0, 84096, 84096, 1152, 2304, 0x716c7bba +0, 85248, 85248, 1152, 2304, 0xb801823b +0, 86400, 86400, 1152, 2304, 0x0fd573ee +0, 87552, 87552, 1152, 2304, 0xe1ab879c +0, 88704, 88704, 1152, 2304, 0x49e6764f +0, 89856, 89856, 1152, 2304, 0xd5f26ddc +0, 91008, 91008, 1152, 2304, 0x076775ff +0, 92160, 92160, 1152, 2304, 0xfbb86fce +0, 93312, 93312, 1152, 2304, 0x20c56858 +0, 94464, 94464, 1152, 2304, 0x043e6891 +0, 95616, 95616, 1152, 2304, 0x59648729 +0, 96768, 96768, 1152, 2304, 0xd4907a63 +0, 97920, 97920, 1152, 2304, 0xd0208a4c +0, 99072, 99072, 1152, 2304, 0xce968383 +0, 100224, 100224, 1152, 2304, 0x3cfc7cd1 +0, 101376, 101376, 1152, 2304, 0x628a7bf5 +0, 102528, 102528, 1152, 2304, 0x9cfe8a4f +0, 103680, 103680, 1152, 2304, 0xdf6f7c6d +0, 104832, 104832, 1152, 2304, 0x6cf6882a +0, 105984, 105984, 1152, 2304, 0x099773a3 +0, 107136, 107136, 1152, 2304, 0x4a1c7649 +0, 108288, 108288, 1152, 2304, 0x31ea71cb +0, 109440, 109440, 1152, 2304, 0xed127ed9 +0, 110592, 110592, 1152, 2304, 0x5b156954 +0, 111744, 111744, 1152, 2304, 0xdd638532 +0, 112896, 112896, 1152, 2304, 0xf1a271f2 +0, 114048, 114048, 1152, 2304, 0x779184d7 +0, 115200, 115200, 1152, 2304, 0x49a88aa8 +0, 116352, 116352, 1152, 2304, 0xa11b7c90 +0, 117504, 117504, 1152, 2304, 0xbf488274 +0, 118656, 118656, 1152, 2304, 0x002f79a8 +0, 119808, 119808, 1152, 2304, 0x0ed97e2f +0, 120960, 120960, 1152, 2304, 0x7845878f +0, 122112, 122112, 1152, 2304, 0x46d777dc +0, 123264, 123264, 1152, 2304, 0x8d0179e3 +0, 124416, 124416, 1152, 2304, 0x38917f9f +0, 125568, 125568, 1152, 2304, 0x449876e7 +0, 126720, 126720, 1152, 2304, 0x001a8769 +0, 127872, 127872, 1152, 2304, 0x06c1826b +0, 129024, 129024, 1152, 2304, 0x41b68047 +0, 130176, 130176, 1152, 2304, 0xeb9782c6 +0, 131328, 131328, 1152, 2304, 0x7cd9719c +0, 132480, 132480, 1152, 2304, 0x3a4a767c +0, 133632, 133632, 1152, 2304, 0x7f887e81 +0, 134784, 134784, 1152, 2304, 0xf75d714b +0, 135936, 135936, 1152, 2304, 0x33b57e9f +0, 137088, 137088, 1152, 2304, 0xc732749e +0, 138240, 138240, 1152, 2304, 0x386f7e1a +0, 139392, 139392, 1152, 2304, 0x6b9c767d +0, 140544, 140544, 1152, 2304, 0x701c83e5 +0, 141696, 141696, 1152, 2304, 0xb92571e1 +0, 142848, 142848, 1152, 2304, 0x833a84bc +0, 144000, 144000, 1152, 2304, 0x1b6984e0 +0, 145152, 145152, 1152, 2304, 0x1b2474ba +0, 146304, 146304, 1152, 2304, 0xc22775a6 +0, 147456, 147456, 1152, 2304, 0x3e8f7972 +0, 148608, 148608, 1152, 2304, 0x17a28a65 +0, 149760, 149760, 1152, 2304, 0x9b6178a4 +0, 150912, 150912, 1152, 2304, 0x5d707873 +0, 152064, 152064, 1152, 2304, 0x68e2645a +0, 153216, 153216, 1152, 2304, 0x1e377d28 +0, 154368, 154368, 1152, 2304, 0x54b384be +0, 155520, 155520, 1152, 2304, 0x0617808c +0, 156672, 156672, 1152, 2304, 0xbc2b8a6c +0, 157824, 157824, 1152, 2304, 0x7ced7180 +0, 158976, 158976, 1152, 2304, 0xf22180ab +0, 160128, 160128, 1152, 2304, 0xf13682c9 +0, 161280, 161280, 1152, 2304, 0x7eff87fd +0, 162432, 162432, 1152, 2304, 0x5a0b5cec +0, 163584, 163584, 1152, 2304, 0x57c18906 +0, 164736, 164736, 1152, 2304, 0xb55a6a16 +0, 165888, 165888, 1152, 2304, 0xf2608371 +0, 167040, 167040, 1152, 2304, 0x36df7576 +0, 168192, 168192, 1152, 2304, 0xdb106fb4 +0, 169344, 169344, 1152, 2304, 0x7e4f85d0 +0, 170496, 170496, 1152, 2304, 0xe3ee78ab +0, 171648, 171648, 1152, 2304, 0xd36b7dc7 +0, 172800, 172800, 1152, 2304, 0xadab7c5c +0, 173952, 173952, 1152, 2304, 0x70786f26 +0, 175104, 175104, 1152, 2304, 0xcd5d717e +0, 176256, 176256, 1152, 2304, 0xc1a96f9a +0, 177408, 177408, 1152, 2304, 0xad777887 +0, 178560, 178560, 1152, 2304, 0x98277c16 +0, 179712, 179712, 1152, 2304, 0x868882c5 +0, 180864, 180864, 1152, 2304, 0xc48092b9 +0, 182016, 182016, 1152, 2304, 0x230069da +0, 183168, 183168, 1152, 2304, 0x14147ad6 +0, 184320, 184320, 1152, 2304, 0xc9007172 +0, 185472, 185472, 1152, 2304, 0x85d67bcc +0, 186624, 186624, 1152, 2304, 0x22418bab +0, 187776, 187776, 1152, 2304, 0xe53c8b71 +0, 188928, 188928, 1152, 2304, 0x5a1a9053 +0, 190080, 190080, 1152, 2304, 0x9cd179af +0, 191232, 191232, 1152, 2304, 0xbb3c7d72 +0, 192384, 192384, 1152, 2304, 0x477a8677 +0, 193536, 193536, 1152, 2304, 0xe3337834 +0, 194688, 194688, 1152, 2304, 0x1cb56d77 +0, 195840, 195840, 1152, 2304, 0xe89d6dac +0, 196992, 196992, 1152, 2304, 0xd468827e +0, 198144, 198144, 1152, 2304, 0xebc46b87 +0, 199296, 199296, 1152, 2304, 0x5fbb78d2 +0, 200448, 200448, 1152, 2304, 0xa1b483d6 +0, 201600, 201600, 1152, 2304, 0x6fec7cab +0, 202752, 202752, 1152, 2304, 0xd86d6f6c +0, 203904, 203904, 1152, 2304, 0x8c2c7d51 +0, 205056, 205056, 1152, 2304, 0xe8377cd7 +0, 206208, 206208, 1152, 2304, 0xb57071b4 +0, 207360, 207360, 1152, 2304, 0xc35c71fd +0, 208512, 208512, 1152, 2304, 0x789079e9 +0, 209664, 209664, 1152, 2304, 0x413b710e +0, 210816, 210816, 1152, 2304, 0x82678332 +0, 211968, 211968, 1152, 2304, 0xe1576e75 +0, 213120, 213120, 1152, 2304, 0x7c0b7ad6 +0, 214272, 214272, 1152, 2304, 0xc6b6786d +0, 215424, 215424, 1152, 2304, 0x736f7b89 +0, 216576, 216576, 1152, 2304, 0x0ded72f1 +0, 217728, 217728, 1152, 2304, 0xcb877a3c +0, 218880, 218880, 1152, 2304, 0x7c497d40 +0, 220032, 220032, 1152, 2304, 0xaefc798c +0, 221184, 221184, 1152, 2304, 0x4cce748c +0, 222336, 222336, 1152, 2304, 0xaa187fbe +0, 223488, 223488, 1152, 2304, 0x1aa77db9 +0, 224640, 224640, 1152, 2304, 0x9e0074b8 +0, 225792, 225792, 1152, 2304, 0x74ee822b +0, 226944, 226944, 1152, 2304, 0x975c6ff6 +0, 228096, 228096, 1152, 2304, 0xe1847bb4 +0, 229248, 229248, 1152, 2304, 0xe0828777 +0, 230400, 230400, 1152, 2304, 0xf4027205 +0, 231552, 231552, 1152, 2304, 0x535e7a20 +0, 232704, 232704, 1152, 2304, 0x5bd88404 +0, 233856, 233856, 1152, 2304, 0xf29478b1 +0, 235008, 235008, 1152, 2304, 0x9b7c7d88 +0, 236160, 236160, 1152, 2304, 0xaeb07335 +0, 237312, 237312, 1152, 2304, 0xbef06e08 +0, 238464, 238464, 1152, 2304, 0x795f7b8c +0, 239616, 239616, 1152, 2304, 0x435a674d +0, 240768, 240768, 1152, 2304, 0xd8ee7a09 +0, 241920, 241920, 1152, 2304, 0x9059812e +0, 243072, 243072, 1152, 2304, 0x7481744a +0, 244224, 244224, 1152, 2304, 0xdff27475 +0, 245376, 245376, 1152, 2304, 0xb17783ab +0, 246528, 246528, 1152, 2304, 0x42e9706b +0, 247680, 247680, 1152, 2304, 0x9f0d86b4 +0, 248832, 248832, 1152, 2304, 0x2963955f +0, 249984, 249984, 1152, 2304, 0x059a6957 +0, 251136, 251136, 1152, 2304, 0x85948206 +0, 252288, 252288, 1152, 2304, 0x185e8400 +0, 253440, 253440, 1152, 2304, 0xe98e70df +0, 254592, 254592, 1152, 2304, 0x69057b27 +0, 255744, 255744, 1152, 2304, 0x49e26f21 +0, 256896, 256896, 1152, 2304, 0xb0867da5 +0, 258048, 258048, 1152, 2304, 0x785980ff +0, 259200, 259200, 1152, 2304, 0xf4b774be +0, 260352, 260352, 1152, 2304, 0x63897e8c +0, 261504, 261504, 1152, 2304, 0x248b89af +0, 262656, 262656, 1152, 2304, 0xd3627c4a +0, 263808, 263808, 1152, 2304, 0x5a4d9349 +0, 264960, 264960, 1152, 2304, 0xe2ce7c4c +0, 266112, 266112, 1152, 2304, 0x321f6c0b +0, 267264, 267264, 1152, 2304, 0x51ac74e0 +0, 268416, 268416, 1152, 2304, 0x8efa91ba +0, 269568, 269568, 1152, 2304, 0x8b4b784c +0, 270720, 270720, 1152, 2304, 0xe9e4879e +0, 271872, 271872, 1152, 2304, 0x8dc28081 +0, 273024, 273024, 1152, 2304, 0x44b477b0 +0, 274176, 274176, 1152, 2304, 0xf7b67084 +0, 275328, 275328, 1152, 2304, 0x4b198c17 +0, 276480, 276480, 1152, 2304, 0x9c947194 +0, 277632, 277632, 1152, 2304, 0x6eaa7f15 +0, 278784, 278784, 1152, 2304, 0x119f7c1d +0, 279936, 279936, 1152, 2304, 0x157b7f43 +0, 281088, 281088, 1152, 2304, 0xcd2e7acc +0, 282240, 282240, 1152, 2304, 0x97597247 +0, 283392, 283392, 1152, 2304, 0x7ba06acb +0, 284544, 284544, 1152, 2304, 0x233c7995 +0, 285696, 285696, 1152, 2304, 0x08e28587 +0, 286848, 286848, 1152, 2304, 0x92be84b5 +0, 288000, 288000, 1152, 2304, 0xbb857d43 +0, 289152, 289152, 1152, 2304, 0x168e7c74 +0, 290304, 290304, 1152, 2304, 0xac5465d9 +0, 291456, 291456, 1152, 2304, 0x18f58831 +0, 292608, 292608, 1152, 2304, 0x19b48196 +0, 293760, 293760, 1152, 2304, 0x20297653 +0, 294912, 294912, 1152, 2304, 0x93397a82 +0, 296064, 296064, 1152, 2304, 0x65ea7deb +0, 297216, 297216, 1152, 2304, 0xd7316e20 +0, 298368, 298368, 1152, 2304, 0x94107f2b +0, 299520, 299520, 1152, 2304, 0xec3b7dc6 +0, 300672, 300672, 1152, 2304, 0x2d3783aa +0, 301824, 301824, 1152, 2304, 0x07e47340 +0, 302976, 302976, 1152, 2304, 0xbc117893 +0, 304128, 304128, 1152, 2304, 0x8bd97851 +0, 305280, 305280, 1152, 2304, 0xc27376a9 +0, 306432, 306432, 1152, 2304, 0x30d88c83 +0, 307584, 307584, 1152, 2304, 0x19c2704c +0, 308736, 308736, 1152, 2304, 0x093b7b6e +0, 309888, 309888, 1152, 2304, 0x221a7349 +0, 311040, 311040, 1152, 2304, 0xa4fd82cd +0, 312192, 312192, 1152, 2304, 0x762e6bc9 +0, 313344, 313344, 1152, 2304, 0x270075d4 +0, 314496, 314496, 1152, 2304, 0xa5f27b90 +0, 315648, 315648, 1152, 2304, 0xf72e7edc +0, 316800, 316800, 1152, 2304, 0x42178486 +0, 317952, 317952, 1152, 2304, 0x5f7978e8 +0, 319104, 319104, 1152, 2304, 0x5d7c6703 +0, 320256, 320256, 1152, 2304, 0x2c4483d5 +0, 321408, 321408, 1152, 2304, 0x31bd951d +0, 322560, 322560, 1152, 2304, 0x99487af0 +0, 323712, 323712, 1152, 2304, 0x0bd27ee7 +0, 324864, 324864, 1152, 2304, 0xc3e07ac4 +0, 326016, 326016, 1152, 2304, 0x98a16ba7 +0, 327168, 327168, 1152, 2304, 0xd7a5747b +0, 328320, 328320, 1152, 2304, 0x96fb811c +0, 329472, 329472, 1152, 2304, 0x7cee8109 +0, 330624, 330624, 1152, 2304, 0x52b18ba2 +0, 331776, 331776, 1152, 2304, 0x33be8861 +0, 332928, 332928, 1152, 2304, 0xf41282a0 +0, 334080, 334080, 1152, 2304, 0xb4268993 +0, 335232, 335232, 1152, 2304, 0x52126a1c +0, 336384, 336384, 1152, 2304, 0x050b6f7a +0, 337536, 337536, 1152, 2304, 0x67a26fc3 +0, 338688, 338688, 1152, 2304, 0x966c7cf2 +0, 339840, 339840, 1152, 2304, 0x22097750 +0, 340992, 340992, 1152, 2304, 0xfbb0796c +0, 342144, 342144, 1152, 2304, 0xbd508964 +0, 343296, 343296, 1152, 2304, 0xc24478d8 +0, 344448, 344448, 1152, 2304, 0x3913769d +0, 345600, 345600, 1152, 2304, 0x8aab872f +0, 346752, 346752, 1152, 2304, 0x7cb4822f +0, 347904, 347904, 1152, 2304, 0xea318144 +0, 349056, 349056, 1152, 2304, 0xaf0f86d2 +0, 350208, 350208, 1152, 2304, 0x24f27598 +0, 351360, 351360, 1152, 2304, 0xd76f6d40 +0, 352512, 352512, 1152, 2304, 0x085071a7 +0, 353664, 353664, 1152, 2304, 0x1d11704c +0, 354816, 354816, 1152, 2304, 0x21517cbd +0, 355968, 355968, 1152, 2304, 0xcdca8d32 +0, 357120, 357120, 1152, 2304, 0x71c18433 +0, 358272, 358272, 1152, 2304, 0xd39d7d81 +0, 359424, 359424, 1152, 2304, 0x7a0d7a43 +0, 360576, 360576, 1152, 2304, 0x007c8884 +0, 361728, 361728, 1152, 2304, 0x403282d0 +0, 362880, 362880, 1152, 2304, 0xe3737214 +0, 364032, 364032, 1152, 2304, 0xaf906f47 +0, 365184, 365184, 1152, 2304, 0x54f57b3b +0, 366336, 366336, 1152, 2304, 0x29be7791 +0, 367488, 367488, 1152, 2304, 0xe3c663d5 +0, 368640, 368640, 1152, 2304, 0xd7258238 +0, 369792, 369792, 1152, 2304, 0x3719820d +0, 370944, 370944, 1152, 2304, 0xbe04814f +0, 372096, 372096, 1152, 2304, 0x556c815e +0, 373248, 373248, 1152, 2304, 0xb2447e10 +0, 374400, 374400, 1152, 2304, 0x7c16867c +0, 375552, 375552, 1152, 2304, 0x6a7b78ed +0, 376704, 376704, 1152, 2304, 0x5d307b81 +0, 377856, 377856, 1152, 2304, 0xaab680d3 +0, 379008, 379008, 1152, 2304, 0xb5d37a23 +0, 380160, 380160, 1152, 2304, 0x7f7d6f76 +0, 381312, 381312, 1152, 2304, 0x317a8296 +0, 382464, 382464, 1152, 2304, 0x8a987b3d +0, 383616, 383616, 1152, 2304, 0x4f317a27 +0, 384768, 384768, 1152, 2304, 0xfc65852f +0, 385920, 385920, 1152, 2304, 0x40527719 +0, 387072, 387072, 1152, 2304, 0x84988e13 +0, 388224, 388224, 1152, 2304, 0x318b6ddc +0, 389376, 389376, 1152, 2304, 0x94cf7939 +0, 390528, 390528, 1152, 2304, 0x6f22819d +0, 391680, 391680, 1152, 2304, 0xa7dd80a9 +0, 392832, 392832, 1152, 2304, 0x1c7968fa +0, 393984, 393984, 1152, 2304, 0xd9937bae +0, 395136, 395136, 1152, 2304, 0xf7137cf9 +0, 396288, 396288, 1152, 2304, 0xeadb84b5 +0, 397440, 397440, 1152, 2304, 0x9a2390ac +0, 398592, 398592, 1152, 2304, 0xdb6a73f6 +0, 399744, 399744, 1152, 2304, 0x69e07507 +0, 400896, 400896, 1152, 2304, 0xbc8478b2 +0, 402048, 402048, 1152, 2304, 0x32cf8638 +0, 403200, 403200, 1152, 2304, 0x2b8d755a +0, 404352, 404352, 1152, 2304, 0x52e05bd2 +0, 405504, 405504, 1152, 2304, 0x2aed8c49 +0, 406656, 406656, 1152, 2304, 0x587a896e +0, 407808, 407808, 1152, 2304, 0x6dd87dee +0, 408960, 408960, 1152, 2304, 0xd2858338 +0, 410112, 410112, 1152, 2304, 0xd90f7842 +0, 411264, 411264, 1152, 2304, 0xd6fb6d4a +0, 412416, 412416, 1152, 2304, 0x85498aea +0, 413568, 413568, 1152, 2304, 0x18597790 +0, 414720, 414720, 1152, 2304, 0x3cd78fea +0, 415872, 415872, 1152, 2304, 0x94377fbc +0, 417024, 417024, 1152, 2304, 0xf9db73f5 +0, 418176, 418176, 1152, 2304, 0x14fb6fca +0, 419328, 419328, 1152, 2304, 0xe9d17d69 +0, 420480, 420480, 1152, 2304, 0xdeb57286 +0, 421632, 421632, 1152, 2304, 0xa5d37e17 +0, 422784, 422784, 1152, 2304, 0xcf6882fb +0, 423936, 423936, 1152, 2304, 0x31758066 +0, 425088, 425088, 1152, 2304, 0x6b4d8175 +0, 426240, 426240, 1152, 2304, 0x2a3d7f8e +0, 427392, 427392, 1152, 2304, 0xc066743b +0, 428544, 428544, 1152, 2304, 0xcab88146 +0, 429696, 429696, 1152, 2304, 0x2b4c6e13 +0, 430848, 430848, 1152, 2304, 0x00b36b6f +0, 432000, 432000, 1152, 2304, 0x664a88d3 +0, 433152, 433152, 1152, 2304, 0x18a66f76 +0, 434304, 434304, 1152, 2304, 0x4f828a8b +0, 435456, 435456, 1152, 2304, 0x9cc7728e +0, 436608, 436608, 1152, 2304, 0xbe357936 +0, 437760, 437760, 1152, 2304, 0x19878f8d +0, 438912, 438912, 1152, 2304, 0x227b7c71 +0, 440064, 440064, 1152, 2304, 0xf7c879ec +0, 441216, 441216, 1152, 2304, 0x0bca7b50 +0, 442368, 442368, 1152, 2304, 0xe4398304 +0, 443520, 443520, 1152, 2304, 0xf5da75c7 +0, 444672, 444672, 1152, 2304, 0x9f9070a3 +0, 445824, 445824, 1152, 2304, 0x789076f6 +0, 446976, 446976, 1152, 2304, 0x362977cc +0, 448128, 448128, 1152, 2304, 0x4d0a8928 +0, 449280, 449280, 1152, 2304, 0x1bb767ec +0, 450432, 450432, 1152, 2304, 0xbe727fa5 +0, 451584, 451584, 1152, 2304, 0x27f38347 +0, 452736, 452736, 1152, 2304, 0x0a3c8783 +0, 453888, 453888, 1152, 2304, 0x8249639c +0, 455040, 455040, 1152, 2304, 0x3b076f69 +0, 456192, 456192, 1152, 2304, 0xd9597ee3 +0, 457344, 457344, 1152, 2304, 0x026e7fad +0, 458496, 458496, 1152, 2304, 0xbd7a6de4 +0, 459648, 459648, 1152, 2304, 0x7d718a4d +0, 460800, 460800, 1152, 2304, 0x1f5e83b4 +0, 461952, 461952, 1152, 2304, 0x597d7755 +0, 463104, 463104, 1152, 2304, 0x3fb080bd +0, 464256, 464256, 1152, 2304, 0xdcbd7b16 +0, 465408, 465408, 1152, 2304, 0x5c48865f +0, 466560, 466560, 1152, 2304, 0xcda37ae8 +0, 467712, 467712, 1152, 2304, 0x4810796d +0, 468864, 468864, 1152, 2304, 0x34317fd0 +0, 470016, 470016, 1152, 2304, 0x5c0e7456 +0, 471168, 471168, 1152, 2304, 0x44d78040 +0, 472320, 472320, 1152, 2304, 0x88587882 +0, 473472, 473472, 1152, 2304, 0x77687d5e +0, 474624, 474624, 1152, 2304, 0x116d68bb +0, 475776, 475776, 1152, 2304, 0x3e5b6f60 +0, 476928, 476928, 1152, 2304, 0x64ea783c +0, 478080, 478080, 1152, 2304, 0x23547f7d +0, 479232, 479232, 1152, 2304, 0x2eee7892 +0, 480384, 480384, 1152, 2304, 0xfb837cba +0, 481536, 481536, 1152, 2304, 0x86518209 +0, 482688, 482688, 1152, 2304, 0x672f7bba +0, 483840, 483840, 1152, 2304, 0x6ab583fb +0, 484992, 484992, 1152, 2304, 0xc1297428 +0, 486144, 486144, 1152, 2304, 0x164e7717 +0, 487296, 487296, 1152, 2304, 0xb754976d +0, 488448, 488448, 1152, 2304, 0xb99d81b2 +0, 489600, 489600, 1152, 2304, 0x79046fd6 +0, 490752, 490752, 1152, 2304, 0x9a3f8426 +0, 491904, 491904, 1152, 2304, 0x896371f5 +0, 493056, 493056, 1152, 2304, 0x63d1799f +0, 494208, 494208, 1152, 2304, 0x4842844e +0, 495360, 495360, 1152, 2304, 0x850e8372 +0, 496512, 496512, 1152, 2304, 0x85d07022 +0, 497664, 497664, 1152, 2304, 0x9e6683d1 +0, 498816, 498816, 1152, 2304, 0x301b8981 +0, 499968, 499968, 1152, 2304, 0x1f1e98c5 +0, 501120, 501120, 1152, 2304, 0xc8797b03 +0, 502272, 502272, 1152, 2304, 0xf9d189f5 +0, 503424, 503424, 1152, 2304, 0x0e0d88be +0, 504576, 504576, 1152, 2304, 0x6c1d7843 +0, 505728, 505728, 1152, 2304, 0xd13b8a38 +0, 506880, 506880, 1152, 2304, 0x9b8f773c +0, 508032, 508032, 1152, 2304, 0x9acd7309 +0, 509184, 509184, 1152, 2304, 0x5e7d7d15 +0, 510336, 510336, 1152, 2304, 0xf09d7640 +0, 511488, 511488, 1152, 2304, 0xaebb718f +0, 512640, 512640, 1152, 2304, 0x0c8570f4 +0, 513792, 513792, 1152, 2304, 0x3c93862c +0, 514944, 514944, 1152, 2304, 0xcee46696 +0, 516096, 516096, 1152, 2304, 0x01ba7e20 +0, 517248, 517248, 1152, 2304, 0x7fcb7a09 +0, 518400, 518400, 1152, 2304, 0xddf18c14 +0, 519552, 519552, 1152, 2304, 0xd2e97eeb +0, 520704, 520704, 1152, 2304, 0x514d8719 +0, 521856, 521856, 1152, 2304, 0xe89279c9 +0, 523008, 523008, 1152, 2304, 0x806d6a95 +0, 524160, 524160, 1152, 2304, 0xbc7a8a60 +0, 525312, 525312, 1152, 2304, 0x302f8fa8 +0, 526464, 526464, 1152, 2304, 0xb136784c +0, 527616, 527616, 1152, 2304, 0x9b0f6aab +0, 528768, 528768, 1152, 2304, 0xd8e27582 +0, 529920, 529920, 1152, 2304, 0xdaaf78b1 +0, 531072, 531072, 1152, 2304, 0x65967f5f +0, 532224, 532224, 1152, 2304, 0x6f917aa4 +0, 533376, 533376, 1152, 2304, 0x7f607444 +0, 534528, 534528, 1152, 2304, 0xfd316f2c +0, 535680, 535680, 1152, 2304, 0x776e83c7 +0, 536832, 536832, 1152, 2304, 0xb9c17e16 +0, 537984, 537984, 1152, 2304, 0xdf287de8 +0, 539136, 539136, 1152, 2304, 0xf33d96a3 +0, 540288, 540288, 1152, 2304, 0xad216e5b +0, 541440, 541440, 1152, 2304, 0x4a328342 +0, 542592, 542592, 1152, 2304, 0xcf3f8079 +0, 543744, 543744, 1152, 2304, 0xb46f77b0 +0, 544896, 544896, 1152, 2304, 0x3199713d +0, 546048, 546048, 1152, 2304, 0x5e667a0d +0, 547200, 547200, 1152, 2304, 0xa3047ae3 +0, 548352, 548352, 1152, 2304, 0x9edf8594 +0, 549504, 549504, 1152, 2304, 0xd16382d5 +0, 550656, 550656, 1152, 2304, 0x6e838328 +0, 551808, 551808, 1152, 2304, 0xa1f697c1 +0, 552960, 552960, 1152, 2304, 0xefcc749c +0, 554112, 554112, 1152, 2304, 0x1f94839e +0, 555264, 555264, 1152, 2304, 0x429e7c5b +0, 556416, 556416, 1152, 2304, 0x9b59711c +0, 557568, 557568, 1152, 2304, 0xdac27323 +0, 558720, 558720, 1152, 2304, 0xa4856d2b +0, 559872, 559872, 1152, 2304, 0x07a37498 +0, 561024, 561024, 1152, 2304, 0xe1ce7512 +0, 562176, 562176, 1152, 2304, 0x15e182c3 +0, 563328, 563328, 1152, 2304, 0x0fa46b8c +0, 564480, 564480, 1152, 2304, 0xbdf07bfd +0, 565632, 565632, 1152, 2304, 0xe0238b2a +0, 566784, 566784, 1152, 2304, 0xab537267 +0, 567936, 567936, 1152, 2304, 0xd46b75f3 +0, 569088, 569088, 1152, 2304, 0xec73794b +0, 570240, 570240, 1152, 2304, 0x680580c1 +0, 571392, 571392, 1152, 2304, 0x1ace8f6c +0, 572544, 572544, 1152, 2304, 0x19d583ac +0, 573696, 573696, 1152, 2304, 0x4b6b8105 +0, 574848, 574848, 1152, 2304, 0x392a78b2 +0, 576000, 576000, 1152, 2304, 0xd3916dad +0, 577152, 577152, 1152, 2304, 0x569c7a75 +0, 578304, 578304, 1152, 2304, 0xf5ac814b +0, 579456, 579456, 1152, 2304, 0x18d77e98 +0, 580608, 580608, 1152, 2304, 0x007074ce +0, 581760, 581760, 1152, 2304, 0x0fe38373 +0, 582912, 582912, 1152, 2304, 0x5a967920 +0, 584064, 584064, 1152, 2304, 0x22167501 +0, 585216, 585216, 1152, 2304, 0xf0828cab +0, 586368, 586368, 1152, 2304, 0xaeec71b7 +0, 587520, 587520, 1152, 2304, 0xc47b62ff +0, 588672, 588672, 1152, 2304, 0xab688478 +0, 589824, 589824, 1152, 2304, 0xf35e7bd2 +0, 590976, 590976, 1152, 2304, 0x9cff763e +0, 592128, 592128, 1152, 2304, 0x59568dc8 +0, 593280, 593280, 1152, 2304, 0x51a278ac +0, 594432, 594432, 1152, 2304, 0xc08a6e68 +0, 595584, 595584, 1152, 2304, 0xd3067ef4 +0, 596736, 596736, 1152, 2304, 0x54767c49 +0, 597888, 597888, 1152, 2304, 0xf8ff8386 +0, 599040, 599040, 1152, 2304, 0xef267f63 +0, 600192, 600192, 1152, 2304, 0xe2537cd9 +0, 601344, 601344, 1152, 2304, 0x77a57680 +0, 602496, 602496, 1152, 2304, 0x325c74ad +0, 603648, 603648, 1152, 2304, 0xd7fe87c4 +0, 604800, 604800, 1152, 2304, 0x2e756310 +0, 605952, 605952, 1152, 2304, 0x6a81796b +0, 607104, 607104, 1152, 2304, 0x2f057daf +0, 608256, 608256, 1152, 2304, 0xcd9f7c9d +0, 609408, 609408, 1152, 2304, 0xc91560a0 +0, 610560, 610560, 1152, 2304, 0x962a91eb +0, 611712, 611712, 1152, 2304, 0xa0ff7416 +0, 612864, 612864, 1152, 2304, 0xcb5c7dff +0, 614016, 614016, 1152, 2304, 0xd3527041 +0, 615168, 615168, 1152, 2304, 0xc89d77c2 +0, 616320, 616320, 1152, 2304, 0xe1ce7ccf +0, 617472, 617472, 1152, 2304, 0xe3417c4c +0, 618624, 618624, 1152, 2304, 0x3f1a7166 +0, 619776, 619776, 1152, 2304, 0xcdcc7e23 +0, 620928, 620928, 1152, 2304, 0x4e727e97 +0, 622080, 622080, 1152, 2304, 0x53427ff1 +0, 623232, 623232, 1152, 2304, 0x173f6ca9 +0, 624384, 624384, 1152, 2304, 0x962887ec +0, 625536, 625536, 1152, 2304, 0xcbec67f4 +0, 626688, 626688, 1152, 2304, 0x7a2c943d +0, 627840, 627840, 1152, 2304, 0x8b877570 +0, 628992, 628992, 1152, 2304, 0xcf337323 +0, 630144, 630144, 1152, 2304, 0x8c8682a4 +0, 631296, 631296, 1152, 2304, 0x94c3753c +0, 632448, 632448, 1152, 2304, 0x86898d79 +0, 633600, 633600, 1152, 2304, 0xdf667312 +0, 634752, 634752, 1152, 2304, 0x062f8ba8 +0, 635904, 635904, 1152, 2304, 0xa2c36f08 +0, 637056, 637056, 1152, 2304, 0x5bca7358 +0, 638208, 638208, 1152, 2304, 0x5648804d +0, 639360, 639360, 1152, 2304, 0xefac87c8 +0, 640512, 640512, 1152, 2304, 0x66bf7dcf +0, 641664, 641664, 1152, 2304, 0x62ad73bc +0, 642816, 642816, 1152, 2304, 0x72fe630c +0, 643968, 643968, 1152, 2304, 0xeebe87da +0, 645120, 645120, 1152, 2304, 0x11c870cf +0, 646272, 646272, 1152, 2304, 0x18fb7c27 +0, 647424, 647424, 1152, 2304, 0x39047145 +0, 648576, 648576, 1152, 2304, 0xdcf07032 +0, 649728, 649728, 1152, 2304, 0x61027c50 +0, 650880, 650880, 1152, 2304, 0x6e2e89de +0, 652032, 652032, 1152, 2304, 0xc50c6d1d +0, 653184, 653184, 1152, 2304, 0xeed587ee +0, 654336, 654336, 1152, 2304, 0xe38269c7 +0, 655488, 655488, 1152, 2304, 0xcf66806e +0, 656640, 656640, 1152, 2304, 0x2d3b7c1b +0, 657792, 657792, 1152, 2304, 0xa4127d48 +0, 658944, 658944, 1152, 2304, 0x480b8325 +0, 660096, 660096, 1152, 2304, 0xc1527221 +0, 661248, 661248, 1152, 2304, 0x94c1769a +0, 662400, 662400, 1152, 2304, 0xcfb37271 +0, 663552, 663552, 1152, 2304, 0x946d7a96 +0, 664704, 664704, 1152, 2304, 0xdfc18e50 +0, 665856, 665856, 1152, 2304, 0x10c48393 +0, 667008, 667008, 1152, 2304, 0x58556b10 +0, 668160, 668160, 1152, 2304, 0x997b7993 +0, 669312, 669312, 1152, 2304, 0x4a787992 +0, 670464, 670464, 1152, 2304, 0x11406c20 +0, 671616, 671616, 1152, 2304, 0x04a4874a +0, 672768, 672768, 1152, 2304, 0xf3077164 +0, 673920, 673920, 1152, 2304, 0x08ac80e3 +0, 675072, 675072, 1152, 2304, 0x268370d0 +0, 676224, 676224, 1152, 2304, 0x1d137778 +0, 677376, 677376, 1152, 2304, 0xfa148e97 +0, 678528, 678528, 1152, 2304, 0xec50717c +0, 679680, 679680, 1152, 2304, 0xcbf46b75 +0, 680832, 680832, 1152, 2304, 0xd4168038 +0, 681984, 681984, 1152, 2304, 0xdd9577f0 +0, 683136, 683136, 1152, 2304, 0xc7077685 +0, 684288, 684288, 1152, 2304, 0x34d25e91 +0, 685440, 685440, 1152, 2304, 0x96537e6d +0, 686592, 686592, 1152, 2304, 0xb12e7940 +0, 687744, 687744, 1152, 2304, 0x861d64c0 +0, 688896, 688896, 1152, 2304, 0xa2bc64ed +0, 690048, 690048, 1152, 2304, 0x0c5f8261 +0, 691200, 691200, 1152, 2304, 0x540584ff +0, 692352, 692352, 1152, 2304, 0xe8328b09 +0, 693504, 693504, 1152, 2304, 0x1e777079 +0, 694656, 694656, 1152, 2304, 0x453483b4 +0, 695808, 695808, 1152, 2304, 0x1cab7a1e +0, 696960, 696960, 1152, 2304, 0xcb37856d +0, 698112, 698112, 1152, 2304, 0x5a4883ed +0, 699264, 699264, 1152, 2304, 0xd1f27cbf +0, 700416, 700416, 1152, 2304, 0x0d377a4d +0, 701568, 701568, 1152, 2304, 0x264e76df +0, 702720, 702720, 1152, 2304, 0x2a68771e +0, 703872, 703872, 1152, 2304, 0xcb317a31 +0, 705024, 705024, 1152, 2304, 0xfc5d7a27 +0, 706176, 706176, 1152, 2304, 0x6e067d96 +0, 707328, 707328, 1152, 2304, 0x0c538560 +0, 708480, 708480, 1152, 2304, 0xfbad717a +0, 709632, 709632, 1152, 2304, 0xf9fc7608 +0, 710784, 710784, 1152, 2304, 0xb1817c8f +0, 711936, 711936, 1152, 2304, 0x57c37f82 +0, 713088, 713088, 1152, 2304, 0x8cac8356 +0, 714240, 714240, 1152, 2304, 0x97108186 +0, 715392, 715392, 1152, 2304, 0x095d81bb +0, 716544, 716544, 1152, 2304, 0x475f6b2b +0, 717696, 717696, 1152, 2304, 0xdf7c8cc5 +0, 718848, 718848, 1152, 2304, 0x979c77be +0, 720000, 720000, 1152, 2304, 0x56a7844b +0, 721152, 721152, 1152, 2304, 0x7ee46b21 +0, 722304, 722304, 1152, 2304, 0x05b67220 +0, 723456, 723456, 1152, 2304, 0x25787252 +0, 724608, 724608, 1152, 2304, 0x8ad278ad +0, 725760, 725760, 1152, 2304, 0x67bd722e +0, 726912, 726912, 1152, 2304, 0x204f77be +0, 728064, 728064, 1152, 2304, 0x82d27ae2 +0, 729216, 729216, 1152, 2304, 0x23fa82e4 +0, 730368, 730368, 1152, 2304, 0xa9cf8159 +0, 731520, 731520, 1152, 2304, 0x13f08749 +0, 732672, 732672, 1152, 2304, 0xf84f71b5 +0, 733824, 733824, 1152, 2304, 0x1cb777c8 +0, 734976, 734976, 1152, 2304, 0x11236722 +0, 736128, 736128, 1152, 2304, 0x10197cac +0, 737280, 737280, 1152, 2304, 0xbd417e65 +0, 738432, 738432, 1152, 2304, 0x9a1c7d05 +0, 739584, 739584, 1152, 2304, 0x4c3a85de +0, 740736, 740736, 1152, 2304, 0x03816eb7 +0, 741888, 741888, 1152, 2304, 0x80186e6c +0, 743040, 743040, 1152, 2304, 0x5c097928 +0, 744192, 744192, 1152, 2304, 0x94aa823d +0, 745344, 745344, 1152, 2304, 0xa1c27f04 +0, 746496, 746496, 1152, 2304, 0x6ddb74a9 +0, 747648, 747648, 1152, 2304, 0x5ea67901 +0, 748800, 748800, 1152, 2304, 0xd710742d +0, 749952, 749952, 1152, 2304, 0xf8c27add +0, 751104, 751104, 1152, 2304, 0xf1717011 +0, 752256, 752256, 1152, 2304, 0xb59072d0 +0, 753408, 753408, 1152, 2304, 0xc8dc84a7 +0, 754560, 754560, 1152, 2304, 0x33116737 +0, 755712, 755712, 1152, 2304, 0x86216bdd +0, 756864, 756864, 1152, 2304, 0xa2f87866 +0, 758016, 758016, 1152, 2304, 0x5d77771e +0, 759168, 759168, 1152, 2304, 0x5d8c77fd +0, 760320, 760320, 1152, 2304, 0x23cc89cb +0, 761472, 761472, 1152, 2304, 0x334e7407 +0, 762624, 762624, 1152, 2304, 0x01c976ff +0, 763776, 763776, 1152, 2304, 0x3a3b7b15 +0, 764928, 764928, 1152, 2304, 0xfa427de9 +0, 766080, 766080, 1152, 2304, 0xbeaa7c91 +0, 767232, 767232, 1152, 2304, 0xd6988b31 +0, 768384, 768384, 1152, 2304, 0x4db47f80 +0, 769536, 769536, 1152, 2304, 0xea687d9e +0, 770688, 770688, 1152, 2304, 0x1a6281ce +0, 771840, 771840, 1152, 2304, 0xe1958003 +0, 772992, 772992, 1152, 2304, 0xb4ae7c5e +0, 774144, 774144, 1152, 2304, 0x28827c8a +0, 775296, 775296, 1152, 2304, 0x1fb88b25 +0, 776448, 776448, 1152, 2304, 0x588d71e8 +0, 777600, 777600, 1152, 2304, 0x68227c34 +0, 778752, 778752, 1152, 2304, 0xee4d73e8 +0, 779904, 779904, 1152, 2304, 0x69287c6d +0, 781056, 781056, 1152, 2304, 0xbb04926a +0, 782208, 782208, 1152, 2304, 0x89456cec +0, 783360, 783360, 1152, 2304, 0xabe18992 +0, 784512, 784512, 1152, 2304, 0x50cc7f6c +0, 785664, 785664, 1152, 2304, 0x6d7270be +0, 786816, 786816, 1152, 2304, 0x664c6fef +0, 787968, 787968, 1152, 2304, 0x7f7982f3 +0, 789120, 789120, 1152, 2304, 0x6ca170e9 +0, 790272, 790272, 1152, 2304, 0x36437d5b +0, 791424, 791424, 1152, 2304, 0xfd2380e8 +0, 792576, 792576, 1152, 2304, 0x2e3c6e9f +0, 793728, 793728, 1152, 2304, 0xc8427f3f +0, 794880, 794880, 1152, 2304, 0x962a79ad +0, 796032, 796032, 1152, 2304, 0xc9597c8b +0, 797184, 797184, 1152, 2304, 0x899580bb +0, 798336, 798336, 1152, 2304, 0x2d179dff +0, 799488, 799488, 1152, 2304, 0x4ac1707c +0, 800640, 800640, 1152, 2304, 0x32ea7e95 +0, 801792, 801792, 1152, 2304, 0x265e9a2d +0, 802944, 802944, 1152, 2304, 0x1c6484d0 +0, 804096, 804096, 1152, 2304, 0x39ae6884 +0, 805248, 805248, 1152, 2304, 0x82ed7bc5 +0, 806400, 806400, 1152, 2304, 0x556b7b3c +0, 807552, 807552, 1152, 2304, 0xb7f778dd +0, 808704, 808704, 1152, 2304, 0x74447d55 +0, 809856, 809856, 1152, 2304, 0x0c66861e +0, 811008, 811008, 1152, 2304, 0x15ba7932 +0, 812160, 812160, 1152, 2304, 0xb19170fc +0, 813312, 813312, 1152, 2304, 0x19d37551 +0, 814464, 814464, 1152, 2304, 0xdc529142 +0, 815616, 815616, 1152, 2304, 0xf2637e77 +0, 816768, 816768, 1152, 2304, 0xd065944b +0, 817920, 817920, 1152, 2304, 0x22878123 +0, 819072, 819072, 1152, 2304, 0xc21a8bf7 +0, 820224, 820224, 1152, 2304, 0x2e3582dc +0, 821376, 821376, 1152, 2304, 0xd42f7987 +0, 822528, 822528, 1152, 2304, 0x69b88236 +0, 823680, 823680, 1152, 2304, 0x7c988f90 +0, 824832, 824832, 1152, 2304, 0x2cd66ded +0, 825984, 825984, 1152, 2304, 0x3e65828b +0, 827136, 827136, 1152, 2304, 0x7e9871c9 +0, 828288, 828288, 1152, 2304, 0xf1f2806b +0, 829440, 829440, 1152, 2304, 0xf5087c7b +0, 830592, 830592, 1152, 2304, 0x62b98097 +0, 831744, 831744, 1152, 2304, 0xec457c43 +0, 832896, 832896, 1152, 2304, 0x87af87a6 +0, 834048, 834048, 1152, 2304, 0x97cc757d +0, 835200, 835200, 1152, 2304, 0x08ca76bd +0, 836352, 836352, 1152, 2304, 0x14ae7cbd +0, 837504, 837504, 1152, 2304, 0x1f79709a +0, 838656, 838656, 1152, 2304, 0x17948207 +0, 839808, 839808, 1152, 2304, 0x16ee7228 +0, 840960, 840960, 1152, 2304, 0x76cc82d7 +0, 842112, 842112, 1152, 2304, 0x8f327a8e +0, 843264, 843264, 1152, 2304, 0x14ee7756 +0, 844416, 844416, 1152, 2304, 0x15996d2f +0, 845568, 845568, 1152, 2304, 0x4c707d5c +0, 846720, 846720, 1152, 2304, 0x268c6fee +0, 847872, 847872, 1152, 2304, 0x6d838c76 +0, 849024, 849024, 1152, 2304, 0xafa17e64 +0, 850176, 850176, 1152, 2304, 0xb6546e66 +0, 851328, 851328, 1152, 2304, 0x945d8b9f +0, 852480, 852480, 1152, 2304, 0x5bfb7446 +0, 853632, 853632, 1152, 2304, 0xae6086f9 +0, 854784, 854784, 1152, 2304, 0xa01380cd +0, 855936, 855936, 1152, 2304, 0x06f0828f +0, 857088, 857088, 1152, 2304, 0x0ae07176 +0, 858240, 858240, 1152, 2304, 0x66f07522 +0, 859392, 859392, 1152, 2304, 0x44018106 +0, 860544, 860544, 1152, 2304, 0x8cd283da +0, 861696, 861696, 1152, 2304, 0x14257f45 +0, 862848, 862848, 1152, 2304, 0x04979537 +0, 864000, 864000, 1152, 2304, 0x8b5f797c +0, 865152, 865152, 1152, 2304, 0x12d67493 +0, 866304, 866304, 1152, 2304, 0xc8886a25 +0, 867456, 867456, 1152, 2304, 0x614b803a +0, 868608, 868608, 1152, 2304, 0x75667d35 +0, 869760, 869760, 1152, 2304, 0xe42c7b00 +0, 870912, 870912, 1152, 2304, 0x37787927 +0, 872064, 872064, 1152, 2304, 0x85db8409 +0, 873216, 873216, 1152, 2304, 0x823b822c +0, 874368, 874368, 1152, 2304, 0xa1658479 +0, 875520, 875520, 1152, 2304, 0xdbe58ff7 +0, 876672, 876672, 1152, 2304, 0x725175e2 +0, 877824, 877824, 1152, 2304, 0xb2ae7741 +0, 878976, 878976, 1152, 2304, 0x4de169e4 +0, 880128, 880128, 1152, 2304, 0x3cb18530 +0, 881280, 881280, 1152, 2304, 0x5a0c5e7b diff --git a/tests/ref/fate/lagarith-red b/tests/ref/fate/lagarith-red index 0e065d60d..7cfb792d4 100644 --- a/tests/ref/fate/lagarith-red +++ b/tests/ref/fate/lagarith-red @@ -3,28 +3,28 @@ #codec_id 0: rawvideo #dimensions 0: 320x240 #sar 0: 0/1 -0, 0, 0, 1, 230400, 0x67dfe576 -0, 1, 1, 1, 230400, 0x67dfe576 -0, 2, 2, 1, 230400, 0x67dfe576 -0, 3, 3, 1, 230400, 0x67dfe576 -0, 4, 4, 1, 230400, 0x67dfe576 -0, 5, 5, 1, 230400, 0x67dfe576 -0, 6, 6, 1, 230400, 0x67dfe576 -0, 7, 7, 1, 230400, 0x67dfe576 -0, 8, 8, 1, 230400, 0x67dfe576 -0, 9, 9, 1, 230400, 0x67dfe576 -0, 10, 10, 1, 230400, 0x67dfe576 -0, 11, 11, 1, 230400, 0x67dfe576 -0, 12, 12, 1, 230400, 0x67dfe576 -0, 13, 13, 1, 230400, 0x67dfe576 -0, 14, 14, 1, 230400, 0x67dfe576 -0, 15, 15, 1, 230400, 0x67dfe576 -0, 16, 16, 1, 230400, 0x67dfe576 -0, 17, 17, 1, 230400, 0x67dfe576 -0, 18, 18, 1, 230400, 0x67dfe576 -0, 19, 19, 1, 230400, 0x67dfe576 -0, 20, 20, 1, 230400, 0x67dfe576 -0, 21, 21, 1, 230400, 0x67dfe576 -0, 22, 22, 1, 230400, 0x67dfe576 -0, 23, 23, 1, 230400, 0x67dfe576 -0, 24, 24, 1, 230400, 0x67dfe576 +0, 0, 0, 1, 230400, 0x77f0e576 +0, 1, 1, 1, 230400, 0x77f0e576 +0, 2, 2, 1, 230400, 0x77f0e576 +0, 3, 3, 1, 230400, 0x77f0e576 +0, 4, 4, 1, 230400, 0x77f0e576 +0, 5, 5, 1, 230400, 0x77f0e576 +0, 6, 6, 1, 230400, 0x77f0e576 +0, 7, 7, 1, 230400, 0x77f0e576 +0, 8, 8, 1, 230400, 0x77f0e576 +0, 9, 9, 1, 230400, 0x77f0e576 +0, 10, 10, 1, 230400, 0x77f0e576 +0, 11, 11, 1, 230400, 0x77f0e576 +0, 12, 12, 1, 230400, 0x77f0e576 +0, 13, 13, 1, 230400, 0x77f0e576 +0, 14, 14, 1, 230400, 0x77f0e576 +0, 15, 15, 1, 230400, 0x77f0e576 +0, 16, 16, 1, 230400, 0x77f0e576 +0, 17, 17, 1, 230400, 0x77f0e576 +0, 18, 18, 1, 230400, 0x77f0e576 +0, 19, 19, 1, 230400, 0x77f0e576 +0, 20, 20, 1, 230400, 0x77f0e576 +0, 21, 21, 1, 230400, 0x77f0e576 +0, 22, 22, 1, 230400, 0x77f0e576 +0, 23, 23, 1, 230400, 0x77f0e576 +0, 24, 24, 1, 230400, 0x77f0e576 diff --git a/tests/ref/fate/lagarith-rgb24 b/tests/ref/fate/lagarith-rgb24 index 63250c6bd..dea49e91b 100644 --- a/tests/ref/fate/lagarith-rgb24 +++ b/tests/ref/fate/lagarith-rgb24 @@ -3,7 +3,7 @@ #codec_id 0: rawvideo #dimensions 0: 480x256 #sar 0: 0/1 -0, 0, 0, 1, 368640, 0x26f74db2 -0, 1, 1, 1, 368640, 0x63b29ea4 -0, 2, 2, 1, 368640, 0x19467f03 -0, 3, 3, 1, 368640, 0x5fdc3575 +0, 0, 0, 1, 368640, 0x18364db2 +0, 1, 1, 1, 368640, 0x60e79ea4 +0, 2, 2, 1, 368640, 0xb28a7f03 +0, 3, 3, 1, 368640, 0x2ed83575 diff --git a/tests/ref/fate/lagarith-ticket4119 b/tests/ref/fate/lagarith-ticket4119 index c46ef041e..c1de9dce0 100644 --- a/tests/ref/fate/lagarith-ticket4119 +++ b/tests/ref/fate/lagarith-ticket4119 @@ -4,5 +4,5 @@ #dimensions 0: 640x360 #sar 0: 0/1 0, 0, 0, 1, 691200, 0x00000000 -0, 25, 25, 1, 691200, 0xc88a6f24 -0, 50, 50, 1, 691200, 0x906d474c +0, 25, 25, 1, 691200, 0x1c4a6f24 +0, 50, 50, 1, 691200, 0x1fa0474c diff --git a/tests/ref/fate/lagarith-ticket4119-cfr b/tests/ref/fate/lagarith-ticket4119-cfr index 324fe4483..1b689011b 100644 --- a/tests/ref/fate/lagarith-ticket4119-cfr +++ b/tests/ref/fate/lagarith-ticket4119-cfr @@ -27,53 +27,53 @@ 0, 21, 21, 1, 691200, 0x00000000 0, 22, 22, 1, 691200, 0x00000000 0, 23, 23, 1, 691200, 0x00000000 -0, 24, 24, 1, 691200, 0xc88a6f24 -0, 25, 25, 1, 691200, 0xc88a6f24 -0, 26, 26, 1, 691200, 0xc88a6f24 -0, 27, 27, 1, 691200, 0xc88a6f24 -0, 28, 28, 1, 691200, 0xc88a6f24 -0, 29, 29, 1, 691200, 0xc88a6f24 -0, 30, 30, 1, 691200, 0xc88a6f24 -0, 31, 31, 1, 691200, 0xc88a6f24 -0, 32, 32, 1, 691200, 0xc88a6f24 -0, 33, 33, 1, 691200, 0xc88a6f24 -0, 34, 34, 1, 691200, 0xc88a6f24 -0, 35, 35, 1, 691200, 0xc88a6f24 -0, 36, 36, 1, 691200, 0xc88a6f24 -0, 37, 37, 1, 691200, 0xc88a6f24 -0, 38, 38, 1, 691200, 0xc88a6f24 -0, 39, 39, 1, 691200, 0xc88a6f24 -0, 40, 40, 1, 691200, 0xc88a6f24 -0, 41, 41, 1, 691200, 0xc88a6f24 -0, 42, 42, 1, 691200, 0xc88a6f24 -0, 43, 43, 1, 691200, 0xc88a6f24 -0, 44, 44, 1, 691200, 0xc88a6f24 -0, 45, 45, 1, 691200, 0xc88a6f24 -0, 46, 46, 1, 691200, 0xc88a6f24 -0, 47, 47, 1, 691200, 0xc88a6f24 -0, 48, 48, 1, 691200, 0xc88a6f24 -0, 49, 49, 1, 691200, 0x906d474c -0, 50, 50, 1, 691200, 0x906d474c -0, 51, 51, 1, 691200, 0x906d474c -0, 52, 52, 1, 691200, 0x906d474c -0, 53, 53, 1, 691200, 0x906d474c -0, 54, 54, 1, 691200, 0x906d474c -0, 55, 55, 1, 691200, 0x906d474c -0, 56, 56, 1, 691200, 0x906d474c -0, 57, 57, 1, 691200, 0x906d474c -0, 58, 58, 1, 691200, 0x906d474c -0, 59, 59, 1, 691200, 0x906d474c -0, 60, 60, 1, 691200, 0x906d474c -0, 61, 61, 1, 691200, 0x906d474c -0, 62, 62, 1, 691200, 0x906d474c -0, 63, 63, 1, 691200, 0x906d474c -0, 64, 64, 1, 691200, 0x906d474c -0, 65, 65, 1, 691200, 0x906d474c -0, 66, 66, 1, 691200, 0x906d474c -0, 67, 67, 1, 691200, 0x906d474c -0, 68, 68, 1, 691200, 0x906d474c -0, 69, 69, 1, 691200, 0x906d474c -0, 70, 70, 1, 691200, 0x906d474c -0, 71, 71, 1, 691200, 0x906d474c -0, 72, 72, 1, 691200, 0x906d474c -0, 73, 73, 1, 691200, 0x906d474c +0, 24, 24, 1, 691200, 0x1c4a6f24 +0, 25, 25, 1, 691200, 0x1c4a6f24 +0, 26, 26, 1, 691200, 0x1c4a6f24 +0, 27, 27, 1, 691200, 0x1c4a6f24 +0, 28, 28, 1, 691200, 0x1c4a6f24 +0, 29, 29, 1, 691200, 0x1c4a6f24 +0, 30, 30, 1, 691200, 0x1c4a6f24 +0, 31, 31, 1, 691200, 0x1c4a6f24 +0, 32, 32, 1, 691200, 0x1c4a6f24 +0, 33, 33, 1, 691200, 0x1c4a6f24 +0, 34, 34, 1, 691200, 0x1c4a6f24 +0, 35, 35, 1, 691200, 0x1c4a6f24 +0, 36, 36, 1, 691200, 0x1c4a6f24 +0, 37, 37, 1, 691200, 0x1c4a6f24 +0, 38, 38, 1, 691200, 0x1c4a6f24 +0, 39, 39, 1, 691200, 0x1c4a6f24 +0, 40, 40, 1, 691200, 0x1c4a6f24 +0, 41, 41, 1, 691200, 0x1c4a6f24 +0, 42, 42, 1, 691200, 0x1c4a6f24 +0, 43, 43, 1, 691200, 0x1c4a6f24 +0, 44, 44, 1, 691200, 0x1c4a6f24 +0, 45, 45, 1, 691200, 0x1c4a6f24 +0, 46, 46, 1, 691200, 0x1c4a6f24 +0, 47, 47, 1, 691200, 0x1c4a6f24 +0, 48, 48, 1, 691200, 0x1c4a6f24 +0, 49, 49, 1, 691200, 0x1fa0474c +0, 50, 50, 1, 691200, 0x1fa0474c +0, 51, 51, 1, 691200, 0x1fa0474c +0, 52, 52, 1, 691200, 0x1fa0474c +0, 53, 53, 1, 691200, 0x1fa0474c +0, 54, 54, 1, 691200, 0x1fa0474c +0, 55, 55, 1, 691200, 0x1fa0474c +0, 56, 56, 1, 691200, 0x1fa0474c +0, 57, 57, 1, 691200, 0x1fa0474c +0, 58, 58, 1, 691200, 0x1fa0474c +0, 59, 59, 1, 691200, 0x1fa0474c +0, 60, 60, 1, 691200, 0x1fa0474c +0, 61, 61, 1, 691200, 0x1fa0474c +0, 62, 62, 1, 691200, 0x1fa0474c +0, 63, 63, 1, 691200, 0x1fa0474c +0, 64, 64, 1, 691200, 0x1fa0474c +0, 65, 65, 1, 691200, 0x1fa0474c +0, 66, 66, 1, 691200, 0x1fa0474c +0, 67, 67, 1, 691200, 0x1fa0474c +0, 68, 68, 1, 691200, 0x1fa0474c +0, 69, 69, 1, 691200, 0x1fa0474c +0, 70, 70, 1, 691200, 0x1fa0474c +0, 71, 71, 1, 691200, 0x1fa0474c +0, 72, 72, 1, 691200, 0x1fa0474c +0, 73, 73, 1, 691200, 0x1fa0474c diff --git a/tests/ref/fate/lagarith-ticket4119-drop b/tests/ref/fate/lagarith-ticket4119-drop index abc58d5cb..c7738aeca 100644 --- a/tests/ref/fate/lagarith-ticket4119-drop +++ b/tests/ref/fate/lagarith-ticket4119-drop @@ -4,5 +4,5 @@ #dimensions 0: 640x360 #sar 0: 0/1 0, 0, 0, 1, 691200, 0x00000000 -0, 1, 1, 1, 691200, 0xc88a6f24 -0, 2, 2, 1, 691200, 0x906d474c +0, 1, 1, 1, 691200, 0x1c4a6f24 +0, 2, 2, 1, 691200, 0x1fa0474c diff --git a/tests/ref/fate/lagarith-ticket4119-pass b/tests/ref/fate/lagarith-ticket4119-pass index c46ef041e..c1de9dce0 100644 --- a/tests/ref/fate/lagarith-ticket4119-pass +++ b/tests/ref/fate/lagarith-ticket4119-pass @@ -4,5 +4,5 @@ #dimensions 0: 640x360 #sar 0: 0/1 0, 0, 0, 1, 691200, 0x00000000 -0, 25, 25, 1, 691200, 0xc88a6f24 -0, 50, 50, 1, 691200, 0x906d474c +0, 25, 25, 1, 691200, 0x1c4a6f24 +0, 50, 50, 1, 691200, 0x1fa0474c diff --git a/tests/ref/fate/lagarith-ticket4119-vfr b/tests/ref/fate/lagarith-ticket4119-vfr index c46ef041e..c1de9dce0 100644 --- a/tests/ref/fate/lagarith-ticket4119-vfr +++ b/tests/ref/fate/lagarith-ticket4119-vfr @@ -4,5 +4,5 @@ #dimensions 0: 640x360 #sar 0: 0/1 0, 0, 0, 1, 691200, 0x00000000 -0, 25, 25, 1, 691200, 0xc88a6f24 -0, 50, 50, 1, 691200, 0x906d474c +0, 25, 25, 1, 691200, 0x1c4a6f24 +0, 50, 50, 1, 691200, 0x1fa0474c diff --git a/tests/ref/fate/limited_input_seek b/tests/ref/fate/limited_input_seek index e0c4bf151..3269dcedc 100644 --- a/tests/ref/fate/limited_input_seek +++ b/tests/ref/fate/limited_input_seek @@ -1 +1 @@ -20a1bb9a1cfb23c1fe86f14e6065cd95 +ae878bdaec23f36a63d142165fe57f49 diff --git a/tests/ref/fate/limited_input_seek-copyts b/tests/ref/fate/limited_input_seek-copyts index 92790a8b9..6eeaef882 100644 --- a/tests/ref/fate/limited_input_seek-copyts +++ b/tests/ref/fate/limited_input_seek-copyts @@ -1 +1 @@ -ec3604b1954ed80de364b8ef491771ce +ffe8a674bdf38e4f650f91963debc654 diff --git a/tests/ref/fate/loco-rgb b/tests/ref/fate/loco-rgb index 289e73f7e..446f5d83c 100644 --- a/tests/ref/fate/loco-rgb +++ b/tests/ref/fate/loco-rgb @@ -3,8 +3,8 @@ #codec_id 0: rawvideo #dimensions 0: 188x128 #sar 0: 0/1 -0, 0, 0, 1, 72192, 0x1847500c -0, 1, 1, 1, 72192, 0x1b0e2e87 -0, 2, 2, 1, 72192, 0x293276c8 -0, 3, 3, 1, 72192, 0x743b9705 -0, 4, 4, 1, 72192, 0xcc1b2530 +0, 0, 0, 1, 72192, 0xbe9f500c +0, 1, 1, 1, 72192, 0xafc82e87 +0, 2, 2, 1, 72192, 0x3a2476c8 +0, 3, 3, 1, 72192, 0x1fda9705 +0, 4, 4, 1, 72192, 0x46b82530 diff --git a/tests/ref/fate/mov-frag-encrypted b/tests/ref/fate/mov-frag-encrypted new file mode 100644 index 000000000..e6c109b56 --- /dev/null +++ b/tests/ref/fate/mov-frag-encrypted @@ -0,0 +1,57 @@ +#format: frame checksums +#version: 2 +#hash: MD5 +#tb 0: 1/24 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 120x52 +#sar 0: 544/545 +#stream#, dts, pts, duration, size, hash +0, 0, 0, 1, 9360, 920bdc277a6a31c1daed9aca44b10caf +0, 1, 1, 1, 9360, f1c0b61fef593de57cb97be7fa846569 +0, 2, 2, 1, 9360, 6ef32d9d4398355aebf6d3fb11d51d3f +0, 3, 3, 1, 9360, d38fd3ef1e5a92fc109b8dd9eb6dadeb +0, 4, 4, 1, 9360, 54cc0c8a25d2f14f32663837d5e646f1 +0, 5, 5, 1, 9360, b4b6829726dc3decb8b80ba0c35bcf30 +0, 6, 6, 1, 9360, fca3f941e60a2f0a4ce30d5e0efbec3c +0, 7, 7, 1, 9360, cda6e26b6c1039ff3d229b262c9210c3 +0, 8, 8, 1, 9360, f0d69255e3a27a8b4ae8a4b7b210929d +0, 9, 9, 1, 9360, 12cb23dd4e32af9c3b35f943714e3fdd +0, 10, 10, 1, 9360, 082aaf3216124ddcecb422fe5c832e82 +0, 11, 11, 1, 9360, ff37bb8cd6bd0412a3b3cb45db54afc9 +0, 12, 12, 1, 9360, dfb9085441575732844b6c2f05d5f542 +0, 13, 13, 1, 9360, 0017100feaaa9fc7eacd2447d50d7542 +0, 14, 14, 1, 9360, 4e2f1b8c4e04c59934c2f58541e62613 +0, 15, 15, 1, 9360, 27a44dfea7cd2d30e488194c34ab473c +0, 16, 16, 1, 9360, fc7b56bd95e990a33cf575d1ef820902 +0, 17, 17, 1, 9360, fa2d1609e69714dffc410e65f3c8b755 +0, 18, 18, 1, 9360, 705d7429f447cb13febe202d567795f2 +0, 19, 19, 1, 9360, 234802ce86e868faaf2cd40a286846ea +0, 20, 20, 1, 9360, 2f0354b40d211d0a4ade4568bea4f85e +0, 21, 21, 1, 9360, e96af3b6c0cc931463ca77d6be0f1148 +0, 22, 22, 1, 9360, 04a904d798361959971361401879c7e4 +0, 23, 23, 1, 9360, 2f119642340df6d25362b5590ded46b7 +0, 24, 24, 1, 9360, 5993fca2e60050706f857ac76e48f386 +0, 25, 25, 1, 9360, 2ff3b5775fed3d527bfbbeea786787fe +0, 26, 26, 1, 9360, 42024dbe23d3fb5b0d8987ae1ce390a8 +0, 27, 27, 1, 9360, d804204f0bd9db5f6a758e2c934d9e38 +0, 28, 28, 1, 9360, e322712e6e34c58ec1a2ab5e2c1e3bfe +0, 29, 29, 1, 9360, 3975bd1a5f6a6b6260276777f9de611e +0, 30, 30, 1, 9360, 4388f0412efc6310706a7cdedc859ea9 +0, 31, 31, 1, 9360, b4b9a11b0b86635267345a569640e8d4 +0, 32, 32, 1, 9360, 31879c7b8d6b67a4209ffde786bb8cb4 +0, 33, 33, 1, 9360, 4b6dc02d7c889fe4abd4e013b25f585a +0, 34, 34, 1, 9360, dc73aae82bd39a1220d1106c8d3e8252 +0, 35, 35, 1, 9360, 54c7dfbd49f312806f6c1a89f7c2c36f +0, 36, 36, 1, 9360, 150abc64f8994d444a521ea90570443c +0, 37, 37, 1, 9360, d277cdc7dcadbe0016f2e950459e7ebf +0, 38, 38, 1, 9360, 2196bf338ead90ea54687b85c73c8229 +0, 39, 39, 1, 9360, 53ce5da5365abc0bd3217dd98e7c465d +0, 40, 40, 1, 9360, 34ee9832aea55c0c4e6f4381c413c10e +0, 41, 41, 1, 9360, 1769c7b5849e4681119067a06ac29a4f +0, 42, 42, 1, 9360, 71f53df739ef283a5184c91ef4b158e8 +0, 43, 43, 1, 9360, d2d394739e9a59c06f0354c16843cb63 +0, 44, 44, 1, 9360, d8e458e92ae29344505a24a3059fc584 +0, 45, 45, 1, 9360, 0f1b11a09911851b798df2ef76253a7f +0, 46, 46, 1, 9360, 5c4a9f22baecf4e749c0d5c65a4f1007 +0, 47, 47, 1, 9360, 3e2b7e7262fdca08d9d1ef6070125c4b diff --git a/tests/ref/fate/mov-mp4-with-mov-in24-ver b/tests/ref/fate/mov-mp4-with-mov-in24-ver new file mode 100644 index 000000000..b5522454d --- /dev/null +++ b/tests/ref/fate/mov-mp4-with-mov-in24-ver @@ -0,0 +1,3 @@ +[STREAM] +codec_name=pcm_s24le +[/STREAM] diff --git a/tests/ref/fate/mov-neg-firstpts-discard b/tests/ref/fate/mov-neg-firstpts-discard index 7c982d3ff..2e295e3b6 100644 --- a/tests/ref/fate/mov-neg-firstpts-discard +++ b/tests/ref/fate/mov-neg-firstpts-discard @@ -1,3 +1,3 @@ [STREAM] -start_time=N/A +start_time=0.000000 [/STREAM] diff --git a/tests/ref/fate/mov-neg-firstpts-discard-vorbis b/tests/ref/fate/mov-neg-firstpts-discard-vorbis new file mode 100644 index 000000000..2e295e3b6 --- /dev/null +++ b/tests/ref/fate/mov-neg-firstpts-discard-vorbis @@ -0,0 +1,3 @@ +[STREAM] +start_time=0.000000 +[/STREAM] diff --git a/tests/ref/fate/mov-stream-shorter-than-movie b/tests/ref/fate/mov-stream-shorter-than-movie new file mode 100644 index 000000000..28f3ef378 --- /dev/null +++ b/tests/ref/fate/mov-stream-shorter-than-movie @@ -0,0 +1,33 @@ +#format: frame checksums +#version: 2 +#hash: MD5 +#tb 0: 1/24 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 640x480 +#sar 0: 0/1 +#stream#, dts, pts, duration, size, hash +0, 0, 0, 1, 460800, 3a26ddfa53f09d535c701138027e49dc +0, 1, 1, 1, 460800, f09fe0d079ee81eb7db617b48ab5eecf +0, 2, 2, 1, 460800, 40a165b074c7f4d34a41f320400737fc +0, 3, 3, 1, 460800, 8ba73359c89ebc51e29847ef0e27f7c3 +0, 4, 4, 1, 460800, 0d783fcf3d37b99e7b41c0450e28f905 +0, 5, 5, 1, 460800, 7251de6f3e2ebccc2183aa7090dd59fb +0, 6, 6, 1, 460800, 5d2ab26df00d2ef9adf763480f9c0493 +0, 7, 7, 1, 460800, b545f2623d4f4b3bc5ba28ca842cb00e +0, 8, 8, 1, 460800, b3132e721028d0ccd0a734ef44fec5ff +0, 9, 9, 1, 460800, 354af9e99c0d5b9cb910b468e8afc89e +0, 10, 10, 1, 460800, 55452405c3cf6c44365d2dbe6cf37be3 +0, 11, 11, 1, 460800, 8ad58d19a00acc37536054706e235868 +0, 12, 12, 1, 460800, 833295be0a52fc2cf8dc7ae0375fd4f1 +0, 13, 13, 1, 460800, 3a943976671337231b962c659bb70f5c +0, 14, 14, 1, 460800, 1dddc5aae4adb42b582565bc19f3f464 +0, 15, 15, 1, 460800, 0562a855137f84269cbfaa94e7d0f623 +0, 16, 16, 1, 460800, e4a89894c47c7142fbc0b9122a7c0561 +0, 17, 17, 1, 460800, 31f4354cc10c6a9d3fc35c0123710528 +0, 18, 18, 1, 460800, c4cfbb24b55d09be1a9b6f1f3fe3ae33 +0, 19, 19, 1, 460800, 0643e1e9cf7e3a4494ad4b425e7dcce7 +0, 20, 20, 1, 460800, 1caf065c1fcb1541e5625d9d5e9d0944 +0, 21, 21, 1, 460800, f519db6dcb739a494e4b57bff2c3b021 +0, 22, 22, 1, 460800, 5bcd1c762ff8edf2b9a4e489be97f18d +0, 23, 23, 1, 460800, a818d6d3a94270294d6cf9432b19daa5 diff --git a/tests/ref/fate/mov-tenc-only-encrypted b/tests/ref/fate/mov-tenc-only-encrypted new file mode 100644 index 000000000..1d57aa6a8 --- /dev/null +++ b/tests/ref/fate/mov-tenc-only-encrypted @@ -0,0 +1,57 @@ +#format: frame checksums +#version: 2 +#hash: MD5 +#tb 0: 1/24 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 1024x436 +#sar 0: 1/1 +#stream#, dts, pts, duration, size, hash +0, 0, 0, 1, 669696, f48f296a85eda5ba069dc851a3228bef +0, 1, 1, 1, 669696, a50c5f69bfa3387d49b5bdf738e6529c +0, 2, 2, 1, 669696, 05061299003760f6a4795b408f72aa31 +0, 3, 3, 1, 669696, 2572119f0b0cdd83f8a7e06252cecd3b +0, 4, 4, 1, 669696, 29fe6a6bdb4a69018e318886a297f07e +0, 5, 5, 1, 669696, e8233c7fbaecfbff965c7dfdd3982b1b +0, 6, 6, 1, 669696, d9259df9880ff5d4a4b38282e67f407b +0, 7, 7, 1, 669696, 3e8d795195038993503ea9ab6984c915 +0, 8, 8, 1, 669696, bc4e2d253b715a34f85aae1b080e3460 +0, 9, 9, 1, 669696, 09aba8b3a96f53f9268e7420a10bfab6 +0, 10, 10, 1, 669696, 179447977dd580da8b35fb5310a809ca +0, 11, 11, 1, 669696, 7a0eea9d54577990345f5705ab9882be +0, 12, 12, 1, 669696, 5bb96eb76f461825740e5938456df759 +0, 13, 13, 1, 669696, bd4ac4a760ead774b9422a27dc071964 +0, 14, 14, 1, 669696, 1cc05f760a9b751fc89e77f2bcc97259 +0, 15, 15, 1, 669696, 825d0dee6f0174ba7102892c7de30b4d +0, 16, 16, 1, 669696, d26a2ef5267f6bb03c4e1d8514eee0df +0, 17, 17, 1, 669696, c916ffdeadca76596a8f7fd47914b5ef +0, 18, 18, 1, 669696, 6e085acfa7fee0658ea0ae6188274c17 +0, 19, 19, 1, 669696, 1e95fa5b3561283f05bf0bd44cb91721 +0, 20, 20, 1, 669696, 37e3d135aba9dfb8b87e441753115374 +0, 21, 21, 1, 669696, 9c398310e8564491de624393c16265ce +0, 22, 22, 1, 669696, c87209e4d2617bc2ab40a75f455f09da +0, 23, 23, 1, 669696, 2679c2f8d1d1af21982e245945c1ee60 +0, 24, 24, 1, 669696, 6151ab4781f31c5beb66b356ad547122 +0, 25, 25, 1, 669696, f7ef6293bfb3a6a329061cb6a5ed5a38 +0, 26, 26, 1, 669696, 2f6e666d14dfc407ca0c0f347b13eb08 +0, 27, 27, 1, 669696, 3454fa1730d79b1aa8dbbc865dc150f4 +0, 28, 28, 1, 669696, e93dc683e2453419a0419ab9af0f8f95 +0, 29, 29, 1, 669696, 031eb3154f7f83cf86d42bee66be9cf7 +0, 30, 30, 1, 669696, 1205c36723e88811206c68892d3aaed6 +0, 31, 31, 1, 669696, 7dd7a8a19dcd73b31ddc6a6d0c597a42 +0, 32, 32, 1, 669696, 7c91115368ea2531262a1197468bc3f4 +0, 33, 33, 1, 669696, 3cf6d9ba385e0fff76da33299ed5380c +0, 34, 34, 1, 669696, 859fc8c3ef049e3c1175a85fb0a90a3d +0, 35, 35, 1, 669696, 1d09ce6c7027103d99a4d5799f6e72ab +0, 36, 36, 1, 669696, 3dcb8357408ac88abd734128d8f5dd6f +0, 37, 37, 1, 669696, 4dafce137a0a5178f6efaec878e64d36 +0, 38, 38, 1, 669696, 44c478f29a1399ed03275a7357f57d48 +0, 39, 39, 1, 669696, 6e9edaac7414c0e14591ac3d4d0b1ac4 +0, 40, 40, 1, 669696, 522e4aaeea0825da27f631a9e690d654 +0, 41, 41, 1, 669696, 85f2502a718440834c40051d30f8a65e +0, 42, 42, 1, 669696, ae8816f7bd4645ef1a17ee6d09b4c8d2 +0, 43, 43, 1, 669696, 914b006fa92f1eb3e590245749f6810d +0, 44, 44, 1, 669696, 9406901542e94c429dff46108782ed69 +0, 45, 45, 1, 669696, 324c13641c39eef5c476023e358c0391 +0, 46, 46, 1, 669696, 4058e886e17c22e4eb9da1dd0d6ad891 +0, 47, 47, 1, 669696, 9edf9cd15eea985b42fd1f5035b1d693 diff --git a/tests/ref/fate/mov-zombie b/tests/ref/fate/mov-zombie index fef2adc35..f45fa5963 100644 --- a/tests/ref/fate/mov-zombie +++ b/tests/ref/fate/mov-zombie @@ -129,5 +129,5 @@ packet|codec_type=video|stream_index=0|pts=188623|pts_time=2.095811|dts=188622|d frame|media_type=video|stream_index=0|key_frame=0|pkt_pts=188623|pkt_pts_time=2.095811|pkt_dts=188622|pkt_dts_time=2.095800|best_effort_timestamp=188623|best_effort_timestamp_time=2.095811|pkt_duration=3003|pkt_duration_time=0.033367|pkt_pos=100846|pkt_size=974|width=160|height=240|pix_fmt=yuv420p|sample_aspect_ratio=2:1|pict_type=B|coded_picture_number=64|display_picture_number=0|interlaced_frame=0|top_field_first=0|repeat_pict=0|color_range=tv|color_space=smpte170m|color_primaries=smpte170m|color_transfer=bt709|chroma_location=topleft packet|codec_type=video|stream_index=0|pts=197632|pts_time=2.195911|dts=191625|dts_time=2.129167|duration=3003|duration_time=0.033367|convergence_duration=N/A|convergence_duration_time=N/A|size=580|pos=101820|flags=__ frame|media_type=video|stream_index=0|key_frame=0|pkt_pts=191626|pkt_pts_time=2.129178|pkt_dts=N/A|pkt_dts_time=N/A|best_effort_timestamp=191626|best_effort_timestamp_time=2.129178|pkt_duration=3003|pkt_duration_time=0.033367|pkt_pos=99180|pkt_size=1666|width=160|height=240|pix_fmt=yuv420p|sample_aspect_ratio=2:1|pict_type=P|coded_picture_number=63|display_picture_number=0|interlaced_frame=0|top_field_first=0|repeat_pict=0|color_range=tv|color_space=smpte170m|color_primaries=smpte170m|color_transfer=bt709|chroma_location=topleft -stream|index=0|codec_name=h264|profile=77|codec_type=video|codec_time_base=212521/12744000|codec_tag_string=avc1|codec_tag=0x31637661|width=160|height=240|coded_width=160|coded_height=240|has_b_frames=1|sample_aspect_ratio=2:1|display_aspect_ratio=4:3|pix_fmt=yuv420p|level=12|color_range=tv|color_space=smpte170m|color_transfer=bt709|color_primaries=smpte170m|chroma_location=topleft|field_order=unknown|timecode=N/A|refs=2|is_avc=true|nal_length_size=4|id=N/A|r_frame_rate=30000/1001|avg_frame_rate=6372000/212521|time_base=1/90000|start_pts=0|start_time=0.000000|duration_ts=2125200|duration=23.613333|bit_rate=333874|max_bit_rate=N/A|bits_per_raw_sample=8|nb_frames=708|nb_read_frames=65|nb_read_packets=66|disposition:default=1|disposition:dub=0|disposition:original=0|disposition:comment=0|disposition:lyrics=0|disposition:karaoke=0|disposition:forced=0|disposition:hearing_impaired=0|disposition:visual_impaired=0|disposition:clean_effects=0|disposition:attached_pic=0|disposition:timed_thumbnails=0|tag:rotate=0|tag:creation_time=2008-05-12T20:59:27.000000Z|tag:language=eng|tag:handler_name=Apple Alias Data Handler|tag:encoder=H.264 +stream|index=0|codec_name=h264|profile=77|codec_type=video|codec_time_base=212521/12744000|codec_tag_string=avc1|codec_tag=0x31637661|width=160|height=240|coded_width=160|coded_height=240|has_b_frames=1|sample_aspect_ratio=2:1|display_aspect_ratio=4:3|pix_fmt=yuv420p|level=12|color_range=tv|color_space=smpte170m|color_transfer=bt709|color_primaries=smpte170m|chroma_location=topleft|field_order=unknown|timecode=N/A|refs=2|is_avc=true|nal_length_size=4|id=N/A|r_frame_rate=30000/1001|avg_frame_rate=6372000/212521|time_base=1/90000|start_pts=0|start_time=0.000000|duration_ts=2125200|duration=23.613333|bit_rate=333874|max_bit_rate=N/A|bits_per_raw_sample=8|nb_frames=708|nb_read_frames=65|nb_read_packets=66|disposition:default=1|disposition:dub=0|disposition:original=0|disposition:comment=0|disposition:lyrics=0|disposition:karaoke=0|disposition:forced=0|disposition:hearing_impaired=0|disposition:visual_impaired=0|disposition:clean_effects=0|disposition:attached_pic=0|disposition:timed_thumbnails=0|tag:rotate=0|tag:creation_time=2008-05-12T20:59:27.000000Z|tag:language=eng|tag:handler_name=Apple Video Media Handler|tag:encoder=H.264 side_data|side_data_type=Display Matrix|displaymatrix=\n00000000: 131072 0 0\n00000001: 0 65536 0\n00000002: 0 0 1073741824\n|rotation=0 diff --git a/tests/ref/fate/movenc b/tests/ref/fate/movenc index 872796ebc..5e8f324ea 100644 --- a/tests/ref/fate/movenc +++ b/tests/ref/fate/movenc @@ -17,10 +17,10 @@ write_data len 20, time nopts, type header atom ftyp write_data len 1171, time nopts, type header atom - write_data len 728, time 0, type sync atom moof write_data len 828, time nopts, type unknown atom - -write_data len 728, time 1013106, type sync atom moof +write_data len 728, time 1046439, type sync atom moof write_data len 812, time nopts, type unknown atom - write_data len 148, time nopts, type trailer atom - -1f37c1a8e01651e8bebcd66f00b6a226 4435 ismv +49bf122c4c732a344ef68b58acd19be5 4435 ismv write_data len 36, time nopts, type header atom ftyp write_data len 1123, time nopts, type header atom - write_data len 796, time 0, type sync atom moof diff --git a/tests/ref/fate/mpegts-probe-pmt-merge b/tests/ref/fate/mpegts-probe-pmt-merge new file mode 100644 index 000000000..6e424af5d --- /dev/null +++ b/tests/ref/fate/mpegts-probe-pmt-merge @@ -0,0 +1,32 @@ +[PROGRAM] +[STREAM] +codec_name=ac3 +[/STREAM] +[STREAM] +codec_name=ac3 +[/STREAM] +[STREAM] +codec_name=ac3 +[/STREAM] +[STREAM] +codec_name=mpeg2video +[/STREAM] +[STREAM] +codec_name=scte_35 +[/STREAM] +[/PROGRAM] +[STREAM] +codec_name=ac3 +[/STREAM] +[STREAM] +codec_name=ac3 +[/STREAM] +[STREAM] +codec_name=ac3 +[/STREAM] +[STREAM] +codec_name=mpeg2video +[/STREAM] +[STREAM] +codec_name=scte_35 +[/STREAM] diff --git a/tests/ref/fate/mxf-d10-user-comments b/tests/ref/fate/mxf-d10-user-comments new file mode 100644 index 000000000..e78765020 --- /dev/null +++ b/tests/ref/fate/mxf-d10-user-comments @@ -0,0 +1 @@ +b659c1204f8d04e2a5607af083590dca diff --git a/tests/ref/fate/mxf-opatom-user-comments b/tests/ref/fate/mxf-opatom-user-comments new file mode 100644 index 000000000..1834b9e07 --- /dev/null +++ b/tests/ref/fate/mxf-opatom-user-comments @@ -0,0 +1 @@ +892cf02e44bf7d61b6d6f01e41db9375 diff --git a/tests/ref/fate/mxf-probe-d10 b/tests/ref/fate/mxf-probe-d10 index 30ceaaf42..ab564467b 100644 --- a/tests/ref/fate/mxf-probe-d10 +++ b/tests/ref/fate/mxf-probe-d10 @@ -96,6 +96,7 @@ TAG:file_package_umid=0x060A2B340101010501010D1313000000AE86B2009131058000000800 format_name=mxf duration=0.178375 bit_rate=56419744 +TAG:operational_pattern_ul=060e2b34.04010101.0d010201.01010900 TAG:uid=0086b200-9131-0580-0000-080046a54011 TAG:generation_uid=b486b200-9131-0580-0000-080046a54011 TAG:company_name=SONY diff --git a/tests/ref/fate/mxf-probe-dnxhd b/tests/ref/fate/mxf-probe-dnxhd index c4de291d3..39968ad98 100644 --- a/tests/ref/fate/mxf-probe-dnxhd +++ b/tests/ref/fate/mxf-probe-dnxhd @@ -167,6 +167,7 @@ TAG:timecode=01:00:00:00 format_name=mxf duration=0.250250 bit_rate=25340195 +TAG:operational_pattern_ul=060e2b34.04010102.0d010201.10030000 TAG:project_name=UHD TAG:uid=784c8132-ae36-ed4d-b0ff-2edf1f3f2d92 TAG:generation_uid=b6bcfcab-70ff-7331-c47c-478869de11d2 diff --git a/tests/ref/fate/mxf-probe-dv25 b/tests/ref/fate/mxf-probe-dv25 index 6e02dd980..00028b08c 100644 --- a/tests/ref/fate/mxf-probe-dv25 +++ b/tests/ref/fate/mxf-probe-dv25 @@ -137,6 +137,7 @@ TAG:file_package_umid=0x060A2B340101010501010D4313000000F2E2FCE98722F14F947F08DE format_name=mxf duration=1.000000 bit_rate=30679040 +TAG:operational_pattern_ul=060e2b34.04010101.0d010201.01010900 TAG:uid=a741d0c7-244a-bc4a-bd36-3323d04f8954 TAG:generation_uid=c1d7a0ee-89d6-754d-bd52-cdf42b53de9f TAG:company_name=AVID diff --git a/tests/ref/fate/mxf-reel_name b/tests/ref/fate/mxf-reel_name index fb9586097..cfe62dfdb 100644 --- a/tests/ref/fate/mxf-reel_name +++ b/tests/ref/fate/mxf-reel_name @@ -1 +1 @@ -dda6c54b642b8794a87d809fdb361f95 +a788589c14f343dcc6d75aaaec0f0266 diff --git a/tests/ref/fate/mxf-user-comments b/tests/ref/fate/mxf-user-comments new file mode 100644 index 000000000..4b734a0f8 --- /dev/null +++ b/tests/ref/fate/mxf-user-comments @@ -0,0 +1 @@ +683bacb0105e5bc5bbf46aa430c644d1 diff --git a/tests/ref/fate/nuv-rtjpeg b/tests/ref/fate/nuv-rtjpeg index e4a5be626..b6f3b080d 100644 --- a/tests/ref/fate/nuv-rtjpeg +++ b/tests/ref/fate/nuv-rtjpeg @@ -1,13 +1,13 @@ -#tb 0: 100/2997 +#tb 0: 1/1000 #media_type 0: video #codec_id 0: rawvideo #dimensions 0: 640x480 #sar 0: 1/1 -0, 4, 4, 1, 460800, 0x54aedafe -0, 5, 5, 1, 460800, 0xb7aa8b56 -0, 6, 6, 1, 460800, 0x283ea3b5 -0, 7, 7, 1, 460800, 0x283ea3b5 -0, 8, 8, 1, 460800, 0x10e577de -0, 9, 9, 1, 460800, 0x4e091ee2 -0, 10, 10, 1, 460800, 0x2ea88828 -0, 11, 11, 1, 460800, 0x4b7f4df0 +0, 118, 118, 0, 460800, 0x54aedafe +0, 152, 152, 0, 460800, 0xb7aa8b56 +0, 177, 177, 0, 460800, 0x283ea3b5 +0, 202, 202, 0, 460800, 0x283ea3b5 +0, 235, 235, 0, 460800, 0x10e577de +0, 269, 269, 0, 460800, 0x4e091ee2 +0, 302, 302, 0, 460800, 0x2ea88828 +0, 335, 335, 0, 460800, 0x4b7f4df0 diff --git a/tests/ref/fate/parseutils b/tests/ref/fate/parseutils index 568b6d28b..bd36c9b01 100644 --- a/tests/ref/fate/parseutils +++ b/tests/ref/fate/parseutils @@ -90,6 +90,10 @@ now -> 1331972053.200000 = 2012-03-17T08:14:13Z 42.1729 -> +42172900 -1729.42 -> -1729420000 12:34 -> +754000000 +2147483648s -> +2147483648000000 +4294967296ms -> +4294967296000 +8589934592us -> +8589934592 +9223372036854775808us -> error Testing av_get_known_color_name() AliceBlue -> R(240) G(248) B(255) A(0) diff --git a/tests/ref/fate/pixelutils b/tests/ref/fate/pixelutils index 493497fb8..df72d52e6 100644 --- a/tests/ref/fate/pixelutils +++ b/tests/ref/fate/pixelutils @@ -2,38 +2,47 @@ [OK] [UU] SAD [random] 4x4=1370 ref=1370 [OK] [UU] SAD [random] 8x8=5178 ref=5178 [OK] [UU] SAD [random] 16x16=20946 ref=20946 +[OK] [UU] SAD [random] 32x32=83150 ref=83150 [OK] [AU] SAD [random] 2x2=320 ref=320 [OK] [AU] SAD [random] 4x4=1522 ref=1522 [OK] [AU] SAD [random] 8x8=5821 ref=5821 [OK] [AU] SAD [random] 16x16=21951 ref=21951 +[OK] [AU] SAD [random] 32x32=86983 ref=86983 [OK] [AA] SAD [random] 2x2=276 ref=276 [OK] [AA] SAD [random] 4x4=1521 ref=1521 [OK] [AA] SAD [random] 8x8=5130 ref=5130 [OK] [AA] SAD [random] 16x16=20775 ref=20775 +[OK] [AA] SAD [random] 32x32=83402 ref=83402 [OK] [UU] SAD [max] 2x2=1020 ref=1020 [OK] [UU] SAD [max] 4x4=4080 ref=4080 [OK] [UU] SAD [max] 8x8=16320 ref=16320 [OK] [UU] SAD [max] 16x16=65280 ref=65280 +[OK] [UU] SAD [max] 32x32=261120 ref=261120 [OK] [AU] SAD [max] 2x2=1020 ref=1020 [OK] [AU] SAD [max] 4x4=4080 ref=4080 [OK] [AU] SAD [max] 8x8=16320 ref=16320 [OK] [AU] SAD [max] 16x16=65280 ref=65280 +[OK] [AU] SAD [max] 32x32=261120 ref=261120 [OK] [AA] SAD [max] 2x2=1020 ref=1020 [OK] [AA] SAD [max] 4x4=4080 ref=4080 [OK] [AA] SAD [max] 8x8=16320 ref=16320 [OK] [AA] SAD [max] 16x16=65280 ref=65280 +[OK] [AA] SAD [max] 32x32=261120 ref=261120 [OK] [UU] SAD [min] 2x2=0 ref=0 [OK] [UU] SAD [min] 4x4=0 ref=0 [OK] [UU] SAD [min] 8x8=0 ref=0 [OK] [UU] SAD [min] 16x16=0 ref=0 +[OK] [UU] SAD [min] 32x32=0 ref=0 [OK] [AU] SAD [min] 2x2=0 ref=0 [OK] [AU] SAD [min] 4x4=0 ref=0 [OK] [AU] SAD [min] 8x8=0 ref=0 [OK] [AU] SAD [min] 16x16=0 ref=0 +[OK] [AU] SAD [min] 32x32=0 ref=0 [OK] [AA] SAD [min] 2x2=0 ref=0 [OK] [AA] SAD [min] 4x4=0 ref=0 [OK] [AA] SAD [min] 8x8=0 ref=0 [OK] [AA] SAD [min] 16x16=0 ref=0 +[OK] [AA] SAD [min] 32x32=0 ref=0 [OK] [UU] SAD [small] 2x2=400 ref=400 [OK] [AU] SAD [small] 2x2=384 ref=384 [OK] [AA] SAD [small] 2x2=409 ref=409 @@ -46,3 +55,6 @@ [OK] [UU] SAD [small] 16x16=19490 ref=19490 [OK] [AU] SAD [small] 16x16=21037 ref=21037 [OK] [AA] SAD [small] 16x16=22986 ref=22986 +[OK] [UU] SAD [small] 32x32=86550 ref=86550 +[OK] [AU] SAD [small] 32x32=83656 ref=83656 +[OK] [AA] SAD [small] 32x32=85164 ref=85164 diff --git a/tests/ref/fate/pixfmt_best b/tests/ref/fate/pixfmt_best index 699e2e421..5f51e2d84 100644 --- a/tests/ref/fate/pixfmt_best +++ b/tests/ref/fate/pixfmt_best @@ -1 +1 @@ -72 tests passed, 0 tests failed. +73 tests passed, 0 tests failed. diff --git a/tests/ref/fate/prores-alpha b/tests/ref/fate/prores-alpha index f451d83ae..d5e3e6877 100644 --- a/tests/ref/fate/prores-alpha +++ b/tests/ref/fate/prores-alpha @@ -3,5 +3,5 @@ #codec_id 0: rawvideo #dimensions 0: 1920x1080 #sar 0: 0/1 -0, 0, 0, 1, 16588800, 0x8e4dac48 -0, 1, 1, 1, 16588800, 0x8e4dac48 +0, 0, 0, 1, 16588800, 0xb035f658 +0, 1, 1, 1, 16588800, 0xb035f658 diff --git a/tests/ref/fate/prores-alpha_skip b/tests/ref/fate/prores-alpha_skip index a17cef810..09691310e 100644 --- a/tests/ref/fate/prores-alpha_skip +++ b/tests/ref/fate/prores-alpha_skip @@ -3,5 +3,5 @@ #codec_id 0: rawvideo #dimensions 0: 1920x1080 #sar 0: 0/1 -0, 0, 0, 1, 12441600, 0xf11685dd -0, 1, 1, 1, 12441600, 0xf11685dd +0, 0, 0, 1, 12441600, 0x65e009b8 +0, 1, 1, 1, 12441600, 0x65e009b8 diff --git a/tests/ref/fate/prores-metadata b/tests/ref/fate/prores-metadata new file mode 100644 index 000000000..56153c394 --- /dev/null +++ b/tests/ref/fate/prores-metadata @@ -0,0 +1 @@ +3492734b4bd0dd097cd9f264457c8345 diff --git a/tests/ref/fate/prores-transparency b/tests/ref/fate/prores-transparency index 7b3efc633..4e8815283 100644 --- a/tests/ref/fate/prores-transparency +++ b/tests/ref/fate/prores-transparency @@ -9,6 +9,6 @@ #sample_rate 1: 48000 #channel_layout 1: 3 #channel_layout_name 1: stereo -0, 0, 0, 1, 16588800, 0x7163b01a +0, 0, 0, 1, 16588800, 0xcfb3d806 1, 0, 0, 1024, 4096, 0x00000000 1, 1024, 1024, 896, 3584, 0x00000000 diff --git a/tests/ref/fate/prores-transparency_skip b/tests/ref/fate/prores-transparency_skip index 5c98d3e43..82c180d17 100644 --- a/tests/ref/fate/prores-transparency_skip +++ b/tests/ref/fate/prores-transparency_skip @@ -9,6 +9,6 @@ #sample_rate 1: 48000 #channel_layout 1: 3 #channel_layout_name 1: stereo -0, 0, 0, 1, 12441600, 0x627d1548 +0, 0, 0, 1, 12441600, 0x74f53304 1, 0, 0, 1024, 4096, 0x00000000 1, 1024, 1024, 896, 3584, 0x00000000 diff --git a/tests/ref/fate/qtrle-32bit b/tests/ref/fate/qtrle-32bit index aaaf8d647..5e2b58dad 100644 --- a/tests/ref/fate/qtrle-32bit +++ b/tests/ref/fate/qtrle-32bit @@ -3,29 +3,29 @@ #codec_id 0: rawvideo #dimensions 0: 720x480 #sar 0: 0/1 -0, 0, 0, 1, 1036800, 0x2a90d062 -0, 1, 1, 1, 1036800, 0x6565aded -0, 2, 2, 1, 1036800, 0xf0b587d2 -0, 3, 3, 1, 1036800, 0xf0b4e53f -0, 4, 4, 1, 1036800, 0x5ba4b96a -0, 5, 5, 1, 1036800, 0x501df9c1 -0, 6, 6, 1, 1036800, 0xcf45b940 -0, 7, 7, 1, 1036800, 0xa454df07 -0, 8, 8, 1, 1036800, 0xc504d152 -0, 9, 9, 1, 1036800, 0xd90ecac7 -0, 10, 10, 1, 1036800, 0xe30368df -0, 11, 11, 1, 1036800, 0x0ca35522 -0, 12, 12, 1, 1036800, 0xe76b8d43 -0, 13, 13, 1, 1036800, 0x7c85a447 -0, 14, 14, 1, 1036800, 0x3e2d1b5f -0, 15, 15, 1, 1036800, 0x230fa5a6 -0, 16, 16, 1, 1036800, 0x4fad025e -0, 17, 17, 1, 1036800, 0x7d3366ae -0, 18, 18, 1, 1036800, 0xa83720f7 -0, 19, 19, 1, 1036800, 0x5dbd13b1 -0, 20, 20, 1, 1036800, 0xd0ebd56d -0, 21, 21, 1, 1036800, 0x4d7c67f3 -0, 22, 22, 1, 1036800, 0x226baa3f -0, 23, 23, 1, 1036800, 0xc0e93acf -0, 24, 24, 1, 1036800, 0x5a466c17 -0, 25, 25, 1, 1036800, 0xfdb7d2ea +0, 0, 0, 1, 1382400, 0xfe6e6fd3 +0, 1, 1, 1, 1382400, 0x3c7809c8 +0, 2, 2, 1, 1382400, 0x06901a04 +0, 3, 3, 1, 1382400, 0xd7d7c910 +0, 4, 4, 1, 1382400, 0x017e8fda +0, 5, 5, 1, 1382400, 0xab9ee842 +0, 6, 6, 1, 1382400, 0x08615b93 +0, 7, 7, 1, 1382400, 0x105cb681 +0, 8, 8, 1, 1382400, 0xd9dd224f +0, 9, 9, 1, 1382400, 0x058cabbf +0, 10, 10, 1, 1382400, 0x73424fc0 +0, 11, 11, 1, 1382400, 0x39d0a78b +0, 12, 12, 1, 1382400, 0x956d1393 +0, 13, 13, 1, 1382400, 0xe4aff472 +0, 14, 14, 1, 1382400, 0x83ff20ce +0, 15, 15, 1, 1382400, 0xb53383df +0, 16, 16, 1, 1382400, 0x181e55e8 +0, 17, 17, 1, 1382400, 0x0716c90c +0, 18, 18, 1, 1382400, 0x092aae25 +0, 19, 19, 1, 1382400, 0x0a23b4cb +0, 20, 20, 1, 1382400, 0xe72000b0 +0, 21, 21, 1, 1382400, 0x0b8d02e8 +0, 22, 22, 1, 1382400, 0xec2a3b0d +0, 23, 23, 1, 1382400, 0x4ddc4e19 +0, 24, 24, 1, 1382400, 0xc4656abb +0, 25, 25, 1, 1382400, 0x60d78517 diff --git a/tests/ref/fate/qtrle-8bit b/tests/ref/fate/qtrle-8bit index 8da113d83..27bb8aad7 100644 --- a/tests/ref/fate/qtrle-8bit +++ b/tests/ref/fate/qtrle-8bit @@ -4,169 +4,60 @@ #dimensions 0: 640x480 #sar 0: 0/1 0, 0, 0, 1, 921600, 0x1492e3ed -0, 1, 1, 1, 921600, 0x1492e3ed -0, 2, 2, 1, 921600, 0x1492e3ed 0, 3, 3, 1, 921600, 0x23ef4fc7 -0, 4, 4, 1, 921600, 0x23ef4fc7 0, 5, 5, 1, 921600, 0xe406d4be -0, 6, 6, 1, 921600, 0xe406d4be -0, 7, 7, 1, 921600, 0xe406d4be 0, 8, 8, 1, 921600, 0x62b8b5a1 -0, 9, 9, 1, 921600, 0x62b8b5a1 0, 10, 10, 1, 921600, 0x7d8ba674 -0, 11, 11, 1, 921600, 0x7d8ba674 -0, 12, 12, 1, 921600, 0x7d8ba674 0, 13, 13, 1, 921600, 0xfe666be7 -0, 14, 14, 1, 921600, 0xfe666be7 0, 15, 15, 1, 921600, 0x721baec0 -0, 16, 16, 1, 921600, 0x721baec0 -0, 17, 17, 1, 921600, 0x721baec0 0, 18, 18, 1, 921600, 0xc237180a -0, 19, 19, 1, 921600, 0xc237180a 0, 20, 20, 1, 921600, 0xf03a7482 -0, 21, 21, 1, 921600, 0xf03a7482 -0, 22, 22, 1, 921600, 0xf03a7482 0, 23, 23, 1, 921600, 0x5612a391 -0, 24, 24, 1, 921600, 0x5612a391 0, 25, 25, 1, 921600, 0x9dbcc46a -0, 26, 26, 1, 921600, 0x9dbcc46a -0, 27, 27, 1, 921600, 0x9dbcc46a 0, 28, 28, 1, 921600, 0xa128a5d5 -0, 29, 29, 1, 921600, 0xa128a5d5 0, 30, 30, 1, 921600, 0x63e0025c -0, 31, 31, 1, 921600, 0x63e0025c -0, 32, 32, 1, 921600, 0x63e0025c 0, 33, 33, 1, 921600, 0x262359ed -0, 34, 34, 1, 921600, 0x262359ed 0, 35, 35, 1, 921600, 0x343688e8 -0, 36, 36, 1, 921600, 0x343688e8 -0, 37, 37, 1, 921600, 0x343688e8 -0, 38, 38, 1, 921600, 0x343688e8 -0, 39, 39, 1, 921600, 0x343688e8 -0, 40, 40, 1, 921600, 0x343688e8 -0, 41, 41, 1, 921600, 0x343688e8 -0, 42, 42, 1, 921600, 0x343688e8 -0, 43, 43, 1, 921600, 0x343688e8 -0, 44, 44, 1, 921600, 0x343688e8 0, 45, 45, 1, 921600, 0xe4b29d57 -0, 46, 46, 1, 921600, 0xe4b29d57 -0, 47, 47, 1, 921600, 0xe4b29d57 0, 48, 48, 1, 921600, 0x198e8a4a -0, 49, 49, 1, 921600, 0x198e8a4a 0, 50, 50, 1, 921600, 0x0cad8dc9 -0, 51, 51, 1, 921600, 0x0cad8dc9 -0, 52, 52, 1, 921600, 0x0cad8dc9 0, 53, 53, 1, 921600, 0x1f74cf3d -0, 54, 54, 1, 921600, 0x1f74cf3d 0, 55, 55, 1, 921600, 0xec5b5449 -0, 56, 56, 1, 921600, 0xec5b5449 -0, 57, 57, 1, 921600, 0xec5b5449 0, 58, 58, 1, 921600, 0x39829711 -0, 59, 59, 1, 921600, 0x39829711 0, 60, 60, 1, 921600, 0x6de5b9c6 -0, 61, 61, 1, 921600, 0x6de5b9c6 -0, 62, 62, 1, 921600, 0x6de5b9c6 0, 63, 63, 1, 921600, 0x47b0e9d4 -0, 64, 64, 1, 921600, 0x47b0e9d4 0, 65, 65, 1, 921600, 0x756452b8 -0, 66, 66, 1, 921600, 0x756452b8 -0, 67, 67, 1, 921600, 0x756452b8 0, 68, 68, 1, 921600, 0x6fce3478 -0, 69, 69, 1, 921600, 0x6fce3478 0, 70, 70, 1, 921600, 0x372397cd -0, 71, 71, 1, 921600, 0x372397cd -0, 72, 72, 1, 921600, 0x372397cd 0, 73, 73, 1, 921600, 0xe3999ba1 -0, 74, 74, 1, 921600, 0xe3999ba1 0, 75, 75, 1, 921600, 0x6ba26b43 -0, 76, 76, 1, 921600, 0x6ba26b43 -0, 77, 77, 1, 921600, 0x6ba26b43 0, 78, 78, 1, 921600, 0x4e9ee49e -0, 79, 79, 1, 921600, 0x4e9ee49e 0, 80, 80, 1, 921600, 0xdb5fd6e7 -0, 81, 81, 1, 921600, 0xdb5fd6e7 -0, 82, 82, 1, 921600, 0xdb5fd6e7 0, 83, 83, 1, 921600, 0x8f2254a5 -0, 84, 84, 1, 921600, 0x8f2254a5 -0, 85, 85, 1, 921600, 0x8f2254a5 -0, 86, 86, 1, 921600, 0x8f2254a5 -0, 87, 87, 1, 921600, 0x8f2254a5 -0, 88, 88, 1, 921600, 0x8f2254a5 -0, 89, 89, 1, 921600, 0x8f2254a5 -0, 90, 90, 1, 921600, 0x8f2254a5 -0, 91, 91, 1, 921600, 0x8f2254a5 -0, 92, 92, 1, 921600, 0x8f2254a5 0, 93, 93, 1, 921600, 0x57e95c32 -0, 94, 94, 1, 921600, 0x57e95c32 0, 95, 95, 1, 921600, 0x41627a9b -0, 96, 96, 1, 921600, 0x41627a9b -0, 97, 97, 1, 921600, 0x41627a9b 0, 98, 98, 1, 921600, 0x7412dcee -0, 99, 99, 1, 921600, 0x7412dcee 0, 100, 100, 1, 921600, 0xaebe10ed -0, 101, 101, 1, 921600, 0xaebe10ed -0, 102, 102, 1, 921600, 0xaebe10ed 0, 103, 103, 1, 921600, 0x411a91f6 -0, 104, 104, 1, 921600, 0x411a91f6 0, 105, 105, 1, 921600, 0xb059df3f -0, 106, 106, 1, 921600, 0xb059df3f -0, 107, 107, 1, 921600, 0xb059df3f 0, 108, 108, 1, 921600, 0x4d6f5a77 -0, 109, 109, 1, 921600, 0x4d6f5a77 0, 110, 110, 1, 921600, 0xbbf06df4 -0, 111, 111, 1, 921600, 0xbbf06df4 -0, 112, 112, 1, 921600, 0xbbf06df4 0, 113, 113, 1, 921600, 0xe27f7bf6 -0, 114, 114, 1, 921600, 0xe27f7bf6 0, 115, 115, 1, 921600, 0xd7e8360e -0, 116, 116, 1, 921600, 0xd7e8360e -0, 117, 117, 1, 921600, 0xd7e8360e 0, 118, 118, 1, 921600, 0x1dd4c344 -0, 119, 119, 1, 921600, 0x1dd4c344 0, 120, 120, 1, 921600, 0x7995a7ce -0, 121, 121, 1, 921600, 0x7995a7ce -0, 122, 122, 1, 921600, 0x7995a7ce 0, 123, 123, 1, 921600, 0x2ef3c566 -0, 124, 124, 1, 921600, 0x2ef3c566 0, 125, 125, 1, 921600, 0xf296736e -0, 126, 126, 1, 921600, 0xf296736e -0, 127, 127, 1, 921600, 0xf296736e -0, 128, 128, 1, 921600, 0xf296736e -0, 129, 129, 1, 921600, 0xf296736e -0, 130, 130, 1, 921600, 0xf296736e -0, 131, 131, 1, 921600, 0xf296736e -0, 132, 132, 1, 921600, 0xf296736e -0, 133, 133, 1, 921600, 0xf296736e -0, 134, 134, 1, 921600, 0xf296736e 0, 135, 135, 1, 921600, 0x1a488311 -0, 136, 136, 1, 921600, 0x1a488311 -0, 137, 137, 1, 921600, 0x1a488311 0, 138, 138, 1, 921600, 0x9e28011b -0, 139, 139, 1, 921600, 0x9e28011b 0, 140, 140, 1, 921600, 0x84d1ea80 -0, 141, 141, 1, 921600, 0x84d1ea80 -0, 142, 142, 1, 921600, 0x84d1ea80 0, 143, 143, 1, 921600, 0x9ed41052 -0, 144, 144, 1, 921600, 0x9ed41052 0, 145, 145, 1, 921600, 0xd4db7206 -0, 146, 146, 1, 921600, 0xd4db7206 -0, 147, 147, 1, 921600, 0xd4db7206 0, 148, 148, 1, 921600, 0x55f695a9 -0, 149, 149, 1, 921600, 0x55f695a9 0, 150, 150, 1, 921600, 0x9d8c667f -0, 151, 151, 1, 921600, 0x9d8c667f -0, 152, 152, 1, 921600, 0x9d8c667f 0, 153, 153, 1, 921600, 0x9b6037ec -0, 154, 154, 1, 921600, 0x9b6037ec 0, 155, 155, 1, 921600, 0x57c5e835 -0, 156, 156, 1, 921600, 0x57c5e835 -0, 157, 157, 1, 921600, 0x57c5e835 0, 158, 158, 1, 921600, 0x476dad89 -0, 159, 159, 1, 921600, 0x476dad89 0, 160, 160, 1, 921600, 0xcfd6ad2b -0, 161, 161, 1, 921600, 0xcfd6ad2b -0, 162, 162, 1, 921600, 0xcfd6ad2b 0, 163, 163, 1, 921600, 0x3b372379 -0, 164, 164, 1, 921600, 0x3b372379 0, 165, 165, 1, 921600, 0x36f245f5 -0, 166, 166, 1, 921600, 0x36f245f5 diff --git a/tests/ref/fate/rgb24-mkv b/tests/ref/fate/rgb24-mkv index 439b2bc5e..b9db53f59 100644 --- a/tests/ref/fate/rgb24-mkv +++ b/tests/ref/fate/rgb24-mkv @@ -1,5 +1,5 @@ -09ee413b2d92a6be5e3b18e9e20a1f74 *tests/data/fate/rgb24-mkv.matroska -58342 tests/data/fate/rgb24-mkv.matroska +ffe2c21083d56764aaae7945fd146326 *tests/data/fate/rgb24-mkv.matroska +58305 tests/data/fate/rgb24-mkv.matroska #tb 0: 1/10 #media_type 0: video #codec_id 0: rawvideo diff --git a/tests/ref/fate/source b/tests/ref/fate/source index 809c4632d..ad1e5b95d 100644 --- a/tests/ref/fate/source +++ b/tests/ref/fate/source @@ -2,6 +2,8 @@ Files without standard license headers: compat/avisynth/windowsPorts/basicDataTypeConversions.h compat/avisynth/windowsPorts/windows2linux.h libavcodec/file_open.c +libavcodec/ilbcdata.h +libavcodec/ilbcdec.c libavcodec/interplayacm.c libavcodec/log2_tab.c libavcodec/reverse.c @@ -23,7 +25,7 @@ compat/avisynth/avs/types.h compat/avisynth/avxsynth_c.h compat/avisynth/windowsPorts/basicDataTypeConversions.h compat/avisynth/windowsPorts/windows2linux.h -compat/cuda/dynlink_loader.h +compat/djgpp/math.h compat/float/float.h compat/float/limits.h Use of av_clip() where av_clip_uintp2() could be used: diff --git a/tests/ref/fate/sub-jacosub b/tests/ref/fate/sub-jacosub index a30fe4a19..5f282cdcf 100644 --- a/tests/ref/fate/sub-jacosub +++ b/tests/ref/fate/sub-jacosub @@ -10,14 +10,14 @@ Style: Default,Arial,16,&Hffffff,&Hffffff,&H0,&H0,0,0,0,0,100,100,0,0,1,1,0,2,10 [Events] Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text -Dialogue: 0,0:00:00.12,0:00:04.36,Default,,0,0,0,,{\an5}JACOsub\N\NThis script demonstrates some of the capabilities of JACOsub. -Dialogue: 0,0:00:04.12,0:00:14.86,Default,,0,0,0,,{\an8}Text may be positioned at the top, -Dialogue: 0,0:00:05.12,0:00:17.46,Default,,0,0,0,,{\an5}middle, -Dialogue: 0,0:00:06.12,0:00:20.06,Default,,0,0,0,,{\an2}or bottom of the screen. -Dialogue: 0,0:00:08.12,0:00:27.36,Default,,0,0,0,,{\an5}{this is a comment} (And, you just saw, {another comment} timing ranges for different lines of text. -Dialogue: 0,0:00:11.12,0:00:35.86,Default,,0,0,0,,{\an1}Within margin constraints\Nthat you set, text may be\Nleft justified, -Dialogue: 0,0:00:13.62,0:00:42.11,Default,,0,0,0,,{\an2}{the JC is redundant - it's the default}center\Njustified, -Dialogue: 0,0:00:14.87,0:00:45.86,Default,,0,0,0,,{\an3}and also\Nright justified. -Dialogue: 0,0:00:22.42,0:01:12.76,Default,,0,0,0,,Text may appear in different styles\N(Normal, {\b1}Bold{\r}, {\i1}Italic{\r}) -Dialogue: 0,0:01:16.12,0:03:53.36,Default,,0,0,0,,{\an5}\N\NAt that time, you may press any key to return to the Editor. -Dialogue: 0,0:01:16.12,0:03:53.36,Default,,0,0,0,,OK, this script will be finished when the screen goes blank. +Dialogue: 0,0:00:00.12,0:00:04.12,Default,,0,0,0,,{\an5}JACOsub\N\NThis script demonstrates some of the capabilities of JACOsub. +Dialogue: 0,0:00:04.12,0:00:06.62,Default,,0,0,0,,{\an8}Text may be positioned at the top, +Dialogue: 0,0:00:05.12,0:00:07.22,Default,,0,0,0,,{\an5}middle, +Dialogue: 0,0:00:06.12,0:00:07.82,Default,,0,0,0,,{\an2}or bottom of the screen. +Dialogue: 0,0:00:08.12,0:00:11.12,Default,,0,0,0,,{\an5}{this is a comment} (And, you just saw, {another comment} timing ranges for different lines of text. +Dialogue: 0,0:00:11.12,0:00:13.62,Default,,0,0,0,,{\an1}Within margin constraints\Nthat you set, text may be\Nleft justified, +Dialogue: 0,0:00:13.62,0:00:14.87,Default,,0,0,0,,{\an2}{the JC is redundant - it's the default}center\Njustified, +Dialogue: 0,0:00:14.87,0:00:16.12,Default,,0,0,0,,{\an3}and also\Nright justified. +Dialogue: 0,0:00:22.42,0:00:27.92,Default,,0,0,0,,Text may appear in different styles\N(Normal, {\b1}Bold{\r}, {\i1}Italic{\r}) +Dialogue: 0,0:01:16.12,0:01:21.12,Default,,0,0,0,,{\an5}\N\NAt that time, you may press any key to return to the Editor. +Dialogue: 0,0:01:16.12,0:01:21.12,Default,,0,0,0,,OK, this script will be finished when the screen goes blank. diff --git a/tests/ref/fate/sws-pixdesc-query b/tests/ref/fate/sws-pixdesc-query index 0adfdcaf9..e23492293 100644 --- a/tests/ref/fate/sws-pixdesc-query +++ b/tests/ref/fate/sws-pixdesc-query @@ -49,6 +49,8 @@ isNBPS: gray10le gray12be gray12le + gray14be + gray14le gray9be gray9le nv20be @@ -91,10 +93,14 @@ isNBPS: yuva420p9le yuva422p10be yuva422p10le + yuva422p12be + yuva422p12le yuva422p9be yuva422p9le yuva444p10be yuva444p10le + yuva444p12be + yuva444p12le yuva444p9be yuva444p9le @@ -121,8 +127,10 @@ isBE: gbrpf32be gray10be gray12be + gray14be gray16be gray9be + grayf32be nv20be p010be p016be @@ -154,9 +162,11 @@ isBE: yuva420p16be yuva420p9be yuva422p10be + yuva422p12be yuva422p16be yuva422p9be yuva444p10be + yuva444p12be yuva444p16be yuva444p9be @@ -168,6 +178,8 @@ isYUV: nv20be nv20le nv21 + nv24 + nv42 p010be p010le p016be @@ -229,6 +241,8 @@ isYUV: yuva422p yuva422p10be yuva422p10le + yuva422p12be + yuva422p12le yuva422p16be yuva422p16le yuva422p9be @@ -236,6 +250,8 @@ isYUV: yuva444p yuva444p10be yuva444p10le + yuva444p12be + yuva444p12le yuva444p16be yuva444p16le yuva444p9be @@ -254,6 +270,8 @@ isPlanarYUV: nv20be nv20le nv21 + nv24 + nv42 p010be p010le p016be @@ -308,6 +326,8 @@ isPlanarYUV: yuva422p yuva422p10be yuva422p10le + yuva422p12be + yuva422p12le yuva422p16be yuva422p16le yuva422p9be @@ -315,6 +335,8 @@ isPlanarYUV: yuva444p yuva444p10be yuva444p10le + yuva444p12be + yuva444p12le yuva444p16be yuva444p16le yuva444p9be @@ -325,6 +347,19 @@ isPlanarYUV: yuvj440p yuvj444p +isSemiPlanarYUV: + nv12 + nv16 + nv20be + nv20le + nv21 + nv24 + nv42 + p010be + p010le + p016be + p016le + isRGB: 0bgr 0rgb @@ -403,10 +438,14 @@ Gray: gray10le gray12be gray12le + gray14be + gray14le gray16be gray16le gray9be gray9le + grayf32be + grayf32le ya16be ya16le ya8 @@ -573,6 +612,8 @@ ALPHA: yuva422p yuva422p10be yuva422p10le + yuva422p12be + yuva422p12le yuva422p16be yuva422p16le yuva422p9be @@ -580,6 +621,8 @@ ALPHA: yuva444p yuva444p10be yuva444p10le + yuva444p12be + yuva444p12le yuva444p16be yuva444p16le yuva444p9be @@ -677,6 +720,8 @@ Planar: nv20be nv20le nv21 + nv24 + nv42 p010be p010le p016be @@ -731,6 +776,8 @@ Planar: yuva422p yuva422p10be yuva422p10le + yuva422p12be + yuva422p12le yuva422p16be yuva422p16le yuva422p9be @@ -738,6 +785,8 @@ Planar: yuva444p yuva444p10be yuva444p10le + yuva444p12be + yuva444p12le yuva444p16be yuva444p16le yuva444p9be diff --git a/tests/ref/fate/time_base b/tests/ref/fate/time_base index 4dd14084d..710fde100 100644 --- a/tests/ref/fate/time_base +++ b/tests/ref/fate/time_base @@ -1 +1 @@ -f97551f884df5ab709c5869c66c7b9bc +42863a53f6c63efbc8c5a2eb76f13f5f diff --git a/tests/ref/fate/ts-small-demux b/tests/ref/fate/ts-small-demux new file mode 100644 index 000000000..cdd7c09f2 --- /dev/null +++ b/tests/ref/fate/ts-small-demux @@ -0,0 +1,80 @@ +#extradata 0: 35, 0x83f4073d +#tb 0: 1/90000 +#media_type 0: video +#codec_id 0: h264 +#dimensions 0: 82x144 +#sar 0: 1/1 +0, 0, 0, 6000, 1290, 0x4684e0ab, S=1, 1, 0x00e000e0 +0, 6000, 6000, 6000, 21, 0x267504dc, F=0x0, S=1, 1, 0x00e000e0 +0, 12000, 12000, 6000, 15, 0x0f9402f6, F=0x0, S=1, 1, 0x00e000e0 +0, 18000, 18000, 6000, 15, 0x0ff40316, F=0x0, S=1, 1, 0x00e000e0 +0, 24000, 24000, 6000, 15, 0x10540336, F=0x0, S=1, 1, 0x00e000e0 +0, 30000, 30000, 6000, 15, 0x10b40356, F=0x0, S=1, 1, 0x00e000e0 +0, 36000, 36000, 6000, 15, 0x11140376, F=0x0, S=1, 1, 0x00e000e0 +0, 42000, 42000, 6000, 15, 0x11740396, F=0x0, S=1, 1, 0x00e000e0 +0, 48000, 48000, 6000, 15, 0x0ed802b7, F=0x0, S=1, 1, 0x00e000e0 +0, 54000, 54000, 6000, 15, 0x0f3802d7, F=0x0, S=1, 1, 0x00e000e0 +0, 60000, 60000, 6000, 15, 0x0f9802f7, F=0x0, S=1, 1, 0x00e000e0 +0, 66000, 66000, 6000, 15, 0x0ff80317, F=0x0, S=1, 1, 0x00e000e0 +0, 72000, 72000, 6000, 15, 0x10580337, F=0x0, S=1, 1, 0x00e000e0 +0, 78000, 78000, 6000, 15, 0x10b80357, F=0x0, S=1, 1, 0x00e000e0 +0, 84000, 84000, 6000, 15, 0x11180377, F=0x0, S=1, 1, 0x00e000e0 +0, 90000, 90000, 6000, 15, 0x11780397, F=0x0, S=1, 1, 0x00e000e0 +0, 96000, 96000, 6000, 15, 0x0ed402b6, F=0x0, S=1, 1, 0x00e000e0 +0, 102000, 102000, 6000, 15, 0x0f3402d6, F=0x0, S=1, 1, 0x00e000e0 +0, 108000, 108000, 6000, 15, 0x0f9402f6, F=0x0, S=1, 1, 0x00e000e0 +0, 114000, 114000, 6000, 15, 0x0ff40316, F=0x0, S=1, 1, 0x00e000e0 +0, 120000, 120000, 6000, 15, 0x10540336, F=0x0, S=1, 1, 0x00e000e0 +0, 126000, 126000, 6000, 15, 0x10b40356, F=0x0, S=1, 1, 0x00e000e0 +0, 132000, 132000, 6000, 15, 0x11140376, F=0x0, S=1, 1, 0x00e000e0 +0, 138000, 138000, 6000, 15, 0x11740396, F=0x0, S=1, 1, 0x00e000e0 +0, 144000, 144000, 6000, 15, 0x0ed802b7, F=0x0, S=1, 1, 0x00e000e0 +0, 150000, 150000, 6000, 15, 0x0f3802d7, F=0x0, S=1, 1, 0x00e000e0 +0, 156000, 156000, 6000, 15, 0x0f9802f7, F=0x0, S=1, 1, 0x00e000e0 +0, 162000, 162000, 6000, 15, 0x0ff80317, F=0x0, S=1, 1, 0x00e000e0 +0, 168000, 168000, 6000, 15, 0x10580337, F=0x0, S=1, 1, 0x00e000e0 +0, 174000, 174000, 6000, 15, 0x10b80357, F=0x0, S=1, 1, 0x00e000e0 +0, 180000, 180000, 6000, 15, 0x11180377, F=0x0, S=1, 1, 0x00e000e0 +0, 186000, 186000, 6000, 15, 0x11780397, F=0x0, S=1, 1, 0x00e000e0 +0, 192000, 192000, 6000, 15, 0x0ed402b6, F=0x0, S=1, 1, 0x00e000e0 +0, 198000, 198000, 6000, 15, 0x0f3402d6, F=0x0, S=1, 1, 0x00e000e0 +0, 204000, 204000, 6000, 15, 0x0f9402f6, F=0x0, S=1, 1, 0x00e000e0 +0, 210000, 210000, 6000, 15, 0x0ff40316, F=0x0, S=1, 1, 0x00e000e0 +0, 216000, 216000, 6000, 15, 0x10540336, F=0x0, S=1, 1, 0x00e000e0 +0, 222000, 222000, 6000, 15, 0x10b40356, F=0x0, S=1, 1, 0x00e000e0 +0, 228000, 228000, 6000, 15, 0x11140376, F=0x0, S=1, 1, 0x00e000e0 +0, 234000, 234000, 6000, 15, 0x11740396, F=0x0, S=1, 1, 0x00e000e0 +0, 240000, 240000, 6000, 15, 0x0ed802b7, F=0x0, S=1, 1, 0x00e000e0 +0, 246000, 246000, 6000, 15, 0x0f3802d7, F=0x0, S=1, 1, 0x00e000e0 +0, 252000, 252000, 6000, 15, 0x0f9802f7, F=0x0, S=1, 1, 0x00e000e0 +0, 258000, 258000, 6000, 15, 0x0ff80317, F=0x0, S=1, 1, 0x00e000e0 +0, 264000, 264000, 6000, 15, 0x10580337, F=0x0, S=1, 1, 0x00e000e0 +0, 270000, 270000, 6000, 15, 0x10b80357, F=0x0, S=1, 1, 0x00e000e0 +0, 276000, 276000, 6000, 15, 0x11180377, F=0x0, S=1, 1, 0x00e000e0 +0, 282000, 282000, 6000, 15, 0x11780397, F=0x0, S=1, 1, 0x00e000e0 +0, 288000, 288000, 6000, 15, 0x0ed402b6, F=0x0, S=1, 1, 0x00e000e0 +0, 294000, 294000, 6000, 15, 0x0f3402d6, F=0x0, S=1, 1, 0x00e000e0 +0, 300000, 300000, 6000, 15, 0x0f9402f6, F=0x0, S=1, 1, 0x00e000e0 +0, 306000, 306000, 6000, 15, 0x0ff40316, F=0x0, S=1, 1, 0x00e000e0 +0, 312000, 312000, 6000, 15, 0x10540336, F=0x0, S=1, 1, 0x00e000e0 +0, 318000, 318000, 6000, 15, 0x10b40356, F=0x0, S=1, 1, 0x00e000e0 +0, 324000, 324000, 6000, 15, 0x11140376, F=0x0, S=1, 1, 0x00e000e0 +0, 330000, 330000, 6000, 15, 0x11740396, F=0x0, S=1, 1, 0x00e000e0 +0, 336000, 336000, 6000, 15, 0x0ed802b7, F=0x0, S=1, 1, 0x00e000e0 +0, 342000, 342000, 6000, 15, 0x0f3802d7, F=0x0, S=1, 1, 0x00e000e0 +0, 348000, 348000, 6000, 15, 0x0f9802f7, F=0x0, S=1, 1, 0x00e000e0 +0, 354000, 354000, 6000, 15, 0x0ff80317, F=0x0, S=1, 1, 0x00e000e0 +0, 360000, 360000, 6000, 15, 0x10580337, F=0x0, S=1, 1, 0x00e000e0 +0, 366000, 366000, 6000, 15, 0x10b80357, F=0x0, S=1, 1, 0x00e000e0 +0, 372000, 372000, 6000, 15, 0x11180377, F=0x0, S=1, 1, 0x00e000e0 +0, 378000, 378000, 6000, 15, 0x11780397, F=0x0, S=1, 1, 0x00e000e0 +0, 384000, 384000, 6000, 15, 0x0ed402b6, F=0x0, S=1, 1, 0x00e000e0 +0, 390000, 390000, 6000, 15, 0x0f3402d6, F=0x0, S=1, 1, 0x00e000e0 +0, 396000, 396000, 6000, 15, 0x0f9402f6, F=0x0, S=1, 1, 0x00e000e0 +0, 402000, 402000, 6000, 15, 0x0ff40316, F=0x0, S=1, 1, 0x00e000e0 +0, 408000, 408000, 6000, 15, 0x10540336, F=0x0, S=1, 1, 0x00e000e0 +0, 414000, 414000, 6000, 15, 0x10b40356, F=0x0, S=1, 1, 0x00e000e0 +0, 420000, 420000, 6000, 15, 0x11140376, F=0x0, S=1, 1, 0x00e000e0 +0, 426000, 426000, 6000, 16, 0x15a2042d, F=0x0, S=1, 1, 0x00e000e0 +0, 432000, 432000, 6000, 16, 0x1227034e, F=0x0, S=1, 1, 0x00e000e0 +0, 438000, 438000, 6000, 16, 0x136703ae, F=0x0 diff --git a/tests/ref/fate/tscc-15bit b/tests/ref/fate/tscc-15bit index abfe6a6ae..ded8ad43e 100644 --- a/tests/ref/fate/tscc-15bit +++ b/tests/ref/fate/tscc-15bit @@ -11,93 +11,34 @@ #channel_layout_name 1: mono 0, 0, 0, 1, 657600, 0x50b3a0c2 1, 0, 0, 11025, 22050, 0x1740aaec -0, 1, 1, 1, 657600, 0x50b3a0c2 -0, 2, 2, 1, 657600, 0x50b3a0c2 0, 3, 3, 1, 657600, 0x661aa145 -0, 4, 4, 1, 657600, 0x661aa145 -0, 5, 5, 1, 657600, 0x661aa145 -0, 6, 6, 1, 657600, 0x661aa145 -0, 7, 7, 1, 657600, 0x661aa145 -0, 8, 8, 1, 657600, 0x661aa145 -0, 9, 9, 1, 657600, 0x661aa145 -0, 10, 10, 1, 657600, 0x661aa145 -0, 11, 11, 1, 657600, 0x661aa145 -0, 12, 12, 1, 657600, 0x661aa145 -0, 13, 13, 1, 657600, 0x661aa145 -0, 14, 14, 1, 657600, 0x661aa145 -0, 15, 15, 1, 657600, 0x661aa145 1, 11025, 11025, 11025, 22050, 0x75ed6086 -0, 16, 16, 1, 657600, 0x661aa145 -0, 17, 17, 1, 657600, 0x661aa145 -0, 18, 18, 1, 657600, 0x661aa145 -0, 19, 19, 1, 657600, 0x661aa145 -0, 20, 20, 1, 657600, 0x661aa145 0, 21, 21, 1, 657600, 0x3c29a73f -0, 22, 22, 1, 657600, 0x3c29a73f -0, 23, 23, 1, 657600, 0x3c29a73f 0, 24, 24, 1, 657600, 0xee2ca145 -0, 25, 25, 1, 657600, 0xee2ca145 -0, 26, 26, 1, 657600, 0xee2ca145 -0, 27, 27, 1, 657600, 0xee2ca145 -0, 28, 28, 1, 657600, 0xee2ca145 -0, 29, 29, 1, 657600, 0xee2ca145 0, 30, 30, 1, 657600, 0xeb6fa442 1, 22050, 22050, 11025, 22050, 0xca52a4e9 -0, 31, 31, 1, 657600, 0xeb6fa442 -0, 32, 32, 1, 657600, 0xeb6fa442 0, 33, 33, 1, 657600, 0xb235a145 -0, 34, 34, 1, 657600, 0xb235a145 -0, 35, 35, 1, 657600, 0xb235a145 0, 36, 36, 1, 657600, 0x39f7ad39 -0, 37, 37, 1, 657600, 0x39f7ad39 -0, 38, 38, 1, 657600, 0x39f7ad39 0, 39, 39, 1, 657600, 0xb851abda -0, 40, 40, 1, 657600, 0xb851abda -0, 41, 41, 1, 657600, 0xb851abda 0, 42, 42, 1, 657600, 0xf6574b22 0, 43, 43, 1, 657600, 0x1a154a9f 0, 44, 44, 1, 657600, 0x3de64916 0, 45, 45, 1, 657600, 0xca3d9cd5 1, 33075, 33075, 11025, 22050, 0xb306d419 -0, 46, 46, 1, 657600, 0xca3d9cd5 0, 47, 47, 1, 657600, 0x4779a2cf -0, 48, 48, 1, 657600, 0x4779a2cf -0, 49, 49, 1, 657600, 0x4779a2cf -0, 50, 50, 1, 657600, 0x4779a2cf -0, 51, 51, 1, 657600, 0x4779a2cf -0, 52, 52, 1, 657600, 0x4779a2cf -0, 53, 53, 1, 657600, 0x4779a2cf -0, 54, 54, 1, 657600, 0x4779a2cf -0, 55, 55, 1, 657600, 0x4779a2cf -0, 56, 56, 1, 657600, 0x4779a2cf 0, 57, 57, 1, 657600, 0x29af1818 -0, 58, 58, 1, 657600, 0x29af1818 -0, 59, 59, 1, 657600, 0x29af1818 0, 60, 60, 1, 657600, 0x77ace9c5 1, 44100, 44100, 11025, 22050, 0x8cbb9625 -0, 61, 61, 1, 657600, 0x77ace9c5 0, 62, 62, 1, 657600, 0x61b8e74b 0, 63, 63, 1, 657600, 0x8c6deace -0, 64, 64, 1, 657600, 0x8c6deace -0, 65, 65, 1, 657600, 0x8c6deace 0, 66, 66, 1, 657600, 0xbe1fe8d7 -0, 67, 67, 1, 657600, 0xbe1fe8d7 -0, 68, 68, 1, 657600, 0xbe1fe8d7 0, 69, 69, 1, 657600, 0x633209db -0, 70, 70, 1, 657600, 0x633209db -0, 71, 71, 1, 657600, 0x633209db 0, 72, 72, 1, 657600, 0x3148adb5 -0, 73, 73, 1, 657600, 0x3148adb5 0, 74, 74, 1, 657600, 0x3b5f5216 -0, 75, 75, 1, 657600, 0x3b5f5216 1, 55125, 55125, 11025, 22050, 0x34a11f66 -0, 76, 76, 1, 657600, 0x3b5f5216 -0, 77, 77, 1, 657600, 0x3b5f5216 0, 78, 78, 1, 657600, 0x5e51fb89 -0, 79, 79, 1, 657600, 0x5e51fb89 0, 80, 80, 1, 657600, 0x48eafb06 0, 81, 81, 1, 657600, 0x9f7a8653 -0, 82, 82, 1, 657600, 0x9f7a8653 0, 83, 83, 1, 657600, 0x29fc83d9 0, 84, 84, 1, 657600, 0xe7689f10 0, 85, 85, 1, 657600, 0x9f788dba @@ -107,145 +48,66 @@ 0, 89, 89, 1, 657600, 0xf7583802 0, 90, 90, 1, 657600, 0x239e2fc6 1, 66150, 66150, 11025, 22050, 0x1ae81230 -0, 91, 91, 1, 657600, 0x239e2fc6 -0, 92, 92, 1, 657600, 0x239e2fc6 0, 93, 93, 1, 657600, 0x001c134c 0, 94, 94, 1, 657600, 0x5c85134c -0, 95, 95, 1, 657600, 0x5c85134c -0, 96, 96, 1, 657600, 0x5c85134c -0, 97, 97, 1, 657600, 0x5c85134c -0, 98, 98, 1, 657600, 0x5c85134c 0, 99, 99, 1, 657600, 0x5fef8bea -0, 100, 100, 1, 657600, 0x5fef8bea 0, 101, 101, 1, 657600, 0x23135efa -0, 102, 102, 1, 657600, 0x23135efa -0, 103, 103, 1, 657600, 0x23135efa -0, 104, 104, 1, 657600, 0x23135efa -0, 105, 105, 1, 657600, 0x23135efa 1, 77175, 77175, 11025, 22050, 0x1217eeba -0, 106, 106, 1, 657600, 0x23135efa -0, 107, 107, 1, 657600, 0x23135efa 0, 108, 108, 1, 657600, 0x50cf63ee -0, 109, 109, 1, 657600, 0x50cf63ee -0, 110, 110, 1, 657600, 0x50cf63ee 0, 111, 111, 1, 657600, 0x2f5c5efa -0, 112, 112, 1, 657600, 0x2f5c5efa -0, 113, 113, 1, 657600, 0x2f5c5efa 0, 114, 114, 1, 657600, 0x9980d3c1 -0, 115, 115, 1, 657600, 0x9980d3c1 -0, 116, 116, 1, 657600, 0x9980d3c1 0, 117, 117, 1, 657600, 0x23f02141 -0, 118, 118, 1, 657600, 0x23f02141 -0, 119, 119, 1, 657600, 0x23f02141 0, 120, 120, 1, 657600, 0x3d31ea57 1, 88200, 88200, 11025, 22050, 0x50e70baa 0, 121, 121, 1, 657600, 0x1e9be92f -0, 122, 122, 1, 657600, 0x1e9be92f 0, 123, 123, 1, 657600, 0x05091a2e -0, 124, 124, 1, 657600, 0x05091a2e -0, 125, 125, 1, 657600, 0x05091a2e 0, 126, 126, 1, 657600, 0xd214c71a -0, 127, 127, 1, 657600, 0xd214c71a -0, 128, 128, 1, 657600, 0xd214c71a 0, 129, 129, 1, 657600, 0x3b07f720 -0, 130, 130, 1, 657600, 0x3b07f720 -0, 131, 131, 1, 657600, 0x3b07f720 0, 132, 132, 1, 657600, 0x02becc42 0, 133, 133, 1, 657600, 0x3d8fcf2e -0, 134, 134, 1, 657600, 0x3d8fcf2e 0, 135, 135, 1, 657600, 0xec51ddd7 1, 99225, 99225, 11025, 22050, 0xb19e89c0 -0, 136, 136, 1, 657600, 0xec51ddd7 -0, 137, 137, 1, 657600, 0xec51ddd7 -0, 138, 138, 1, 657600, 0xec51ddd7 -0, 139, 139, 1, 657600, 0xec51ddd7 -0, 140, 140, 1, 657600, 0xec51ddd7 0, 141, 141, 1, 657600, 0x40a3b905 -0, 142, 142, 1, 657600, 0x40a3b905 0, 143, 143, 1, 657600, 0xbfc5baa9 -0, 144, 144, 1, 657600, 0xbfc5baa9 -0, 145, 145, 1, 657600, 0xbfc5baa9 -0, 146, 146, 1, 657600, 0xbfc5baa9 -0, 147, 147, 1, 657600, 0xbfc5baa9 -0, 148, 148, 1, 657600, 0xbfc5baa9 -0, 149, 149, 1, 657600, 0xbfc5baa9 0, 150, 150, 1, 657600, 0x54a2f8dd 1, 110250, 110250, 11025, 22050, 0x78526696 0, 151, 151, 1, 657600, 0x0b96f90d -0, 152, 152, 1, 657600, 0x0b96f90d 0, 153, 153, 1, 657600, 0xa18119e9 0, 154, 154, 1, 657600, 0x70a11ce6 0, 155, 155, 1, 657600, 0xb36f19e9 0, 156, 156, 1, 657600, 0xeb2219e9 -0, 157, 157, 1, 657600, 0xeb2219e9 -0, 158, 158, 1, 657600, 0xeb2219e9 0, 159, 159, 1, 657600, 0xb98f19e9 0, 160, 160, 1, 657600, 0xa4281966 0, 161, 161, 1, 657600, 0xf0e61966 0, 162, 162, 1, 657600, 0x065c19e9 -0, 163, 163, 1, 657600, 0x065c19e9 -0, 164, 164, 1, 657600, 0x065c19e9 -0, 165, 165, 1, 657600, 0x065c19e9 1, 121275, 121275, 11025, 22050, 0x48e3bb21 -0, 166, 166, 1, 657600, 0x065c19e9 -0, 167, 167, 1, 657600, 0x065c19e9 -0, 168, 168, 1, 657600, 0x065c19e9 -0, 169, 169, 1, 657600, 0x065c19e9 -0, 170, 170, 1, 657600, 0x065c19e9 0, 171, 171, 1, 657600, 0x2f1d1ce6 -0, 172, 172, 1, 657600, 0x2f1d1ce6 0, 173, 173, 1, 657600, 0x181719e9 0, 174, 174, 1, 657600, 0x938d1ce6 -0, 175, 175, 1, 657600, 0x938d1ce6 -0, 176, 176, 1, 657600, 0x938d1ce6 0, 177, 177, 1, 657600, 0xf0acbabf -0, 178, 178, 1, 657600, 0xf0acbabf -0, 179, 179, 1, 657600, 0xf0acbabf 0, 180, 180, 1, 657600, 0x0f47804f 1, 132300, 132300, 11025, 22050, 0xbc32204a -0, 181, 181, 1, 657600, 0x0f47804f 0, 182, 182, 1, 657600, 0x5e0c7a55 0, 183, 183, 1, 657600, 0x0c8f4374 0, 184, 184, 1, 657600, 0x709a3b00 -0, 185, 185, 1, 657600, 0x709a3b00 0, 186, 186, 1, 657600, 0xf57b7a0f 0, 187, 187, 1, 657600, 0x99427f1b -0, 188, 188, 1, 657600, 0x99427f1b 0, 189, 189, 1, 657600, 0xcb3608e7 0, 190, 190, 1, 657600, 0x0992fd64 -0, 191, 191, 1, 657600, 0x0992fd64 0, 192, 192, 1, 657600, 0x7a95fa02 -0, 193, 193, 1, 657600, 0x7a95fa02 -0, 194, 194, 1, 657600, 0x7a95fa02 0, 195, 195, 1, 657600, 0xb97dd910 1, 143325, 143325, 11025, 22050, 0xdf6f1e46 -0, 196, 196, 1, 657600, 0xb97dd910 -0, 197, 197, 1, 657600, 0xb97dd910 0, 198, 198, 1, 657600, 0x3be07a66 -0, 199, 199, 1, 657600, 0x3be07a66 0, 200, 200, 1, 657600, 0x1ae77960 0, 201, 201, 1, 657600, 0x62177f5a 0, 202, 202, 1, 657600, 0xf57c7c5d 0, 203, 203, 1, 657600, 0x600e7960 0, 204, 204, 1, 657600, 0xe15d7960 0, 205, 205, 1, 657600, 0x79427663 -0, 206, 206, 1, 657600, 0x79427663 0, 207, 207, 1, 657600, 0xa7c77960 -0, 208, 208, 1, 657600, 0xa7c77960 0, 209, 209, 1, 657600, 0x75f67663 0, 210, 210, 1, 657600, 0x3a157960 1, 154350, 154350, 11025, 22050, 0x4c91da9d 0, 211, 211, 1, 657600, 0x72aa7663 -0, 212, 212, 1, 657600, 0x72aa7663 0, 213, 213, 1, 657600, 0x1b277663 -0, 214, 214, 1, 657600, 0x1b277663 -0, 215, 215, 1, 657600, 0x1b277663 0, 216, 216, 1, 657600, 0x6f5e7663 -0, 217, 217, 1, 657600, 0x6f5e7663 -0, 218, 218, 1, 657600, 0x6f5e7663 -0, 219, 219, 1, 657600, 0x6f5e7663 -0, 220, 220, 1, 657600, 0x6f5e7663 -0, 221, 221, 1, 657600, 0x6f5e7663 -0, 222, 222, 1, 657600, 0x6f5e7663 -0, 223, 223, 1, 657600, 0x6f5e7663 -0, 224, 224, 1, 657600, 0x6f5e7663 diff --git a/tests/ref/fate/tscc-32bit b/tests/ref/fate/tscc-32bit index dfb37a9be..7e8e6b95c 100644 --- a/tests/ref/fate/tscc-32bit +++ b/tests/ref/fate/tscc-32bit @@ -11,151 +11,30 @@ 0, 5, 5, 1, 2359296, 0xbb0e0026 0, 6, 6, 1, 2359296, 0x66a905ab 0, 7, 7, 1, 2359296, 0xe990f855 -0, 8, 8, 1, 2359296, 0xe990f855 0, 9, 9, 1, 2359296, 0x3ec2c64e 0, 13, 13, 1, 2359296, 0xda3ba3cf 0, 14, 14, 1, 2359296, 0x60a070fd 0, 15, 15, 1, 2359296, 0x42e5fedc -0, 16, 16, 1, 2359296, 0x42e5fedc 0, 17, 17, 1, 2359296, 0x699cf990 -0, 18, 18, 1, 2359296, 0x699cf990 -0, 19, 19, 1, 2359296, 0x699cf990 -0, 20, 20, 1, 2359296, 0x699cf990 -0, 21, 21, 1, 2359296, 0x699cf990 -0, 22, 22, 1, 2359296, 0x699cf990 -0, 23, 23, 1, 2359296, 0x699cf990 0, 24, 24, 1, 2359296, 0x1524160c -0, 25, 25, 1, 2359296, 0x1524160c -0, 26, 26, 1, 2359296, 0x1524160c -0, 27, 27, 1, 2359296, 0x1524160c -0, 28, 28, 1, 2359296, 0x1524160c -0, 29, 29, 1, 2359296, 0x1524160c -0, 30, 30, 1, 2359296, 0x1524160c 0, 31, 31, 1, 2359296, 0x33df0c8c -0, 32, 32, 1, 2359296, 0x33df0c8c -0, 33, 33, 1, 2359296, 0x33df0c8c -0, 34, 34, 1, 2359296, 0x33df0c8c -0, 35, 35, 1, 2359296, 0x33df0c8c -0, 36, 36, 1, 2359296, 0x33df0c8c -0, 37, 37, 1, 2359296, 0x33df0c8c 0, 38, 38, 1, 2359296, 0xfe3d29f8 -0, 39, 39, 1, 2359296, 0xfe3d29f8 -0, 40, 40, 1, 2359296, 0xfe3d29f8 -0, 41, 41, 1, 2359296, 0xfe3d29f8 -0, 42, 42, 1, 2359296, 0xfe3d29f8 -0, 43, 43, 1, 2359296, 0xfe3d29f8 -0, 44, 44, 1, 2359296, 0xfe3d29f8 0, 45, 45, 1, 2359296, 0x1b9d197f -0, 46, 46, 1, 2359296, 0x1b9d197f -0, 47, 47, 1, 2359296, 0x1b9d197f -0, 48, 48, 1, 2359296, 0x1b9d197f -0, 49, 49, 1, 2359296, 0x1b9d197f -0, 50, 50, 1, 2359296, 0x1b9d197f -0, 51, 51, 1, 2359296, 0x1b9d197f 0, 52, 52, 1, 2359296, 0x48c126fb -0, 53, 53, 1, 2359296, 0x48c126fb -0, 54, 54, 1, 2359296, 0x48c126fb -0, 55, 55, 1, 2359296, 0x48c126fb -0, 56, 56, 1, 2359296, 0x48c126fb -0, 57, 57, 1, 2359296, 0x48c126fb -0, 58, 58, 1, 2359296, 0x48c126fb 0, 59, 59, 1, 2359296, 0xcaa31c7c -0, 60, 60, 1, 2359296, 0xcaa31c7c -0, 61, 61, 1, 2359296, 0xcaa31c7c -0, 62, 62, 1, 2359296, 0xcaa31c7c -0, 63, 63, 1, 2359296, 0xcaa31c7c -0, 64, 64, 1, 2359296, 0xcaa31c7c -0, 65, 65, 1, 2359296, 0xcaa31c7c 0, 66, 66, 1, 2359296, 0xc6a333ee -0, 67, 67, 1, 2359296, 0xc6a333ee -0, 68, 68, 1, 2359296, 0xc6a333ee -0, 69, 69, 1, 2359296, 0xc6a333ee -0, 70, 70, 1, 2359296, 0xc6a333ee -0, 71, 71, 1, 2359296, 0xc6a333ee -0, 72, 72, 1, 2359296, 0xc6a333ee 0, 73, 73, 1, 2359296, 0xb96d1583 -0, 74, 74, 1, 2359296, 0xb96d1583 -0, 75, 75, 1, 2359296, 0xb96d1583 -0, 76, 76, 1, 2359296, 0xb96d1583 -0, 77, 77, 1, 2359296, 0xb96d1583 -0, 78, 78, 1, 2359296, 0xb96d1583 -0, 79, 79, 1, 2359296, 0xb96d1583 0, 80, 80, 1, 2359296, 0x878135ec -0, 82, 82, 1, 2359296, 0x878135ec -0, 83, 83, 1, 2359296, 0x878135ec -0, 84, 84, 1, 2359296, 0x878135ec -0, 85, 85, 1, 2359296, 0x878135ec -0, 86, 86, 1, 2359296, 0x878135ec -0, 87, 87, 1, 2359296, 0x878135ec 0, 88, 88, 1, 2359296, 0x76922870 -0, 89, 89, 1, 2359296, 0x76922870 -0, 90, 90, 1, 2359296, 0x76922870 -0, 91, 91, 1, 2359296, 0x76922870 -0, 92, 92, 1, 2359296, 0x76922870 -0, 93, 93, 1, 2359296, 0x76922870 -0, 94, 94, 1, 2359296, 0x76922870 0, 95, 95, 1, 2359296, 0xb0e031f0 -0, 96, 96, 1, 2359296, 0xb0e031f0 -0, 97, 97, 1, 2359296, 0xb0e031f0 -0, 98, 98, 1, 2359296, 0xb0e031f0 -0, 99, 99, 1, 2359296, 0xb0e031f0 -0, 100, 100, 1, 2359296, 0xb0e031f0 -0, 101, 101, 1, 2359296, 0xb0e031f0 0, 102, 102, 1, 2359296, 0xb2ef2a6e -0, 103, 103, 1, 2359296, 0xb2ef2a6e -0, 104, 104, 1, 2359296, 0xb2ef2a6e 0, 105, 105, 1, 2359296, 0x083c2474 -0, 106, 106, 1, 2359296, 0x083c2474 -0, 107, 107, 1, 2359296, 0x083c2474 -0, 108, 108, 1, 2359296, 0x083c2474 0, 109, 109, 1, 2359296, 0xbdfe2ef3 -0, 110, 110, 1, 2359296, 0xbdfe2ef3 -0, 111, 111, 1, 2359296, 0xbdfe2ef3 -0, 112, 112, 1, 2359296, 0xbdfe2ef3 -0, 113, 113, 1, 2359296, 0xbdfe2ef3 -0, 114, 114, 1, 2359296, 0xbdfe2ef3 -0, 115, 115, 1, 2359296, 0xbdfe2ef3 0, 116, 116, 1, 2359296, 0x934b1484 -0, 117, 117, 1, 2359296, 0x934b1484 -0, 118, 118, 1, 2359296, 0x934b1484 -0, 119, 119, 1, 2359296, 0x934b1484 0, 120, 120, 1, 2359296, 0x3e0d1a7e -0, 121, 121, 1, 2359296, 0x3e0d1a7e -0, 122, 122, 1, 2359296, 0x3e0d1a7e 0, 123, 123, 1, 2359296, 0x3ce539e8 -0, 124, 124, 1, 2359296, 0x3ce539e8 -0, 125, 125, 1, 2359296, 0x3ce539e8 -0, 126, 126, 1, 2359296, 0x3ce539e8 -0, 127, 127, 1, 2359296, 0x3ce539e8 -0, 128, 128, 1, 2359296, 0x3ce539e8 -0, 129, 129, 1, 2359296, 0x3ce539e8 0, 130, 130, 1, 2359296, 0xd46c2f69 -0, 131, 131, 1, 2359296, 0xd46c2f69 -0, 132, 132, 1, 2359296, 0xd46c2f69 -0, 133, 133, 1, 2359296, 0xd46c2f69 -0, 134, 134, 1, 2359296, 0xd46c2f69 -0, 135, 135, 1, 2359296, 0xd46c2f69 -0, 136, 136, 1, 2359296, 0xd46c2f69 0, 137, 137, 1, 2359296, 0x8d2933ee -0, 138, 138, 1, 2359296, 0x8d2933ee -0, 139, 139, 1, 2359296, 0x8d2933ee -0, 140, 140, 1, 2359296, 0x8d2933ee -0, 141, 141, 1, 2359296, 0x8d2933ee -0, 142, 142, 1, 2359296, 0x8d2933ee -0, 143, 143, 1, 2359296, 0x8d2933ee 0, 144, 144, 1, 2359296, 0xb6092b6d -0, 145, 145, 1, 2359296, 0xb6092b6d -0, 146, 146, 1, 2359296, 0xb6092b6d -0, 147, 147, 1, 2359296, 0xb6092b6d -0, 148, 148, 1, 2359296, 0xb6092b6d -0, 149, 149, 1, 2359296, 0xb6092b6d -0, 150, 150, 1, 2359296, 0xb6092b6d 0, 151, 151, 1, 2359296, 0xe4ef27fa -0, 152, 152, 1, 2359296, 0xe4ef27fa -0, 153, 153, 1, 2359296, 0xe4ef27fa -0, 154, 154, 1, 2359296, 0xe4ef27fa -0, 155, 155, 1, 2359296, 0xe4ef27fa -0, 156, 156, 1, 2359296, 0xe4ef27fa -0, 157, 157, 1, 2359296, 0xe4ef27fa 0, 158, 158, 1, 2359296, 0x5e5b2672 -0, 159, 159, 1, 2359296, 0x5e5b2672 diff --git a/tests/ref/fate/vc1_ilaced_twomv b/tests/ref/fate/vc1_ilaced_twomv index fa56b2949..096e5fc87 100644 --- a/tests/ref/fate/vc1_ilaced_twomv +++ b/tests/ref/fate/vc1_ilaced_twomv @@ -3,16 +3,16 @@ #codec_id 0: rawvideo #dimensions 0: 1920x1080 #sar 0: 1/1 -0, 0, 0, 1, 3110400, 0x764f8856 -0, 2, 2, 1, 3110400, 0x3b615b79 -0, 3, 3, 1, 3110400, 0x4fbb6f84 -0, 4, 4, 1, 3110400, 0xc1ca8532 -0, 5, 5, 1, 3110400, 0xb6e7d363 -0, 6, 6, 1, 3110400, 0x1beb5c34 -0, 7, 7, 1, 3110400, 0xcb8cb061 -0, 8, 8, 1, 3110400, 0x13ddbd61 -0, 9, 9, 1, 3110400, 0xde8f052f -0, 10, 10, 1, 3110400, 0x4d4072db -0, 11, 11, 1, 3110400, 0x4e5d29e3 -0, 12, 12, 1, 3110400, 0x75300531 -0, 13, 13, 1, 3110400, 0x1114285a +0, 0, 0, 1, 3110400, 0xc95e8861 +0, 2, 2, 1, 3110400, 0xf58b5cbf +0, 3, 3, 1, 3110400, 0x2f866f33 +0, 4, 4, 1, 3110400, 0x05c18415 +0, 5, 5, 1, 3110400, 0x4077ca93 +0, 6, 6, 1, 3110400, 0x44d105fc +0, 7, 7, 1, 3110400, 0xa0608374 +0, 8, 8, 1, 3110400, 0x407689dc +0, 9, 9, 1, 3110400, 0x4707d00a +0, 10, 10, 1, 3110400, 0x74986831 +0, 11, 11, 1, 3110400, 0xa5912619 +0, 12, 12, 1, 3110400, 0x44aa5565 +0, 13, 13, 1, 3110400, 0xb9752774 diff --git a/tests/ref/fate/vc1_sa10143 b/tests/ref/fate/vc1_sa10143 index d6904819d..db89cc9e4 100644 --- a/tests/ref/fate/vc1_sa10143 +++ b/tests/ref/fate/vc1_sa10143 @@ -3,33 +3,33 @@ #codec_id 0: rawvideo #dimensions 0: 720x480 #sar 0: 1/1 -0, 0, 0, 1, 518400, 0x89407f55 -0, 2, 2, 1, 518400, 0xaa896afd -0, 3, 3, 1, 518400, 0x0e69ff59 -0, 4, 4, 1, 518400, 0x0c30bfa0 -0, 5, 5, 1, 518400, 0x1a5b6a69 -0, 6, 6, 1, 518400, 0x23470858 -0, 7, 7, 1, 518400, 0x9a4e3c54 -0, 8, 8, 1, 518400, 0xad63160b -0, 9, 9, 1, 518400, 0x0fcfeebc -0, 10, 10, 1, 518400, 0x20b31777 -0, 11, 11, 1, 518400, 0x9d79df09 -0, 12, 12, 1, 518400, 0x3e86766f -0, 13, 13, 1, 518400, 0x638a8746 -0, 14, 14, 1, 518400, 0x7a6c1a0e -0, 15, 15, 1, 518400, 0x306f6cef -0, 16, 16, 1, 518400, 0x81f81281 -0, 17, 17, 1, 518400, 0x49ab5bf5 -0, 18, 18, 1, 518400, 0x8f316e44 -0, 19, 19, 1, 518400, 0x95ae00c9 -0, 20, 20, 1, 518400, 0xf71bb7f5 -0, 21, 21, 1, 518400, 0x5205ea68 -0, 22, 22, 1, 518400, 0x74a1d8b9 -0, 23, 23, 1, 518400, 0xa3217616 -0, 24, 24, 1, 518400, 0x2b28bbf8 -0, 25, 25, 1, 518400, 0xf024872a -0, 26, 26, 1, 518400, 0x2fdbaaf3 -0, 27, 27, 1, 518400, 0xa3a2418e -0, 28, 28, 1, 518400, 0x55bfe435 -0, 29, 29, 1, 518400, 0x50fb6c94 -0, 30, 30, 1, 518400, 0x5584bb40 +0, 0, 0, 1, 518400, 0x34fa7f55 +0, 2, 2, 1, 518400, 0x60466bc1 +0, 3, 3, 1, 518400, 0xe68dff1e +0, 4, 4, 1, 518400, 0x790ac06a +0, 5, 5, 1, 518400, 0xb3b26b27 +0, 6, 6, 1, 518400, 0x8840096c +0, 7, 7, 1, 518400, 0xf75c3d61 +0, 8, 8, 1, 518400, 0xca071781 +0, 9, 9, 1, 518400, 0xa8e6edf9 +0, 10, 10, 1, 518400, 0xabb61984 +0, 11, 11, 1, 518400, 0x0b31dedd +0, 12, 12, 1, 518400, 0xf44378ef +0, 13, 13, 1, 518400, 0xf7268996 +0, 14, 14, 1, 518400, 0x8c5b1ff4 +0, 15, 15, 1, 518400, 0xda356fd2 +0, 16, 16, 1, 518400, 0x0e091c57 +0, 17, 17, 1, 518400, 0x17645e68 +0, 18, 18, 1, 518400, 0xf47a71ef +0, 19, 19, 1, 518400, 0x6c440498 +0, 20, 20, 1, 518400, 0xd705bd32 +0, 21, 21, 1, 518400, 0x0800edd0 +0, 22, 22, 1, 518400, 0x902be119 +0, 23, 23, 1, 518400, 0x0f7d7bc4 +0, 24, 24, 1, 518400, 0x9f4dc421 +0, 25, 25, 1, 518400, 0x3b8c8d5a +0, 26, 26, 1, 518400, 0xbcdfb2b9 +0, 27, 27, 1, 518400, 0xa02a46c3 +0, 28, 28, 1, 518400, 0x8ecde915 +0, 29, 29, 1, 518400, 0x20576bfd +0, 30, 30, 1, 518400, 0xac40bc36 diff --git a/tests/ref/fate/vc1test_smm0005 b/tests/ref/fate/vc1test_smm0005 new file mode 100644 index 000000000..0c189ca55 --- /dev/null +++ b/tests/ref/fate/vc1test_smm0005 @@ -0,0 +1,29 @@ +#tb 0: 1/1 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 720x480 +#sar 0: 0/1 +0, 0, 0, 1, 518400, 0xfc2e6c0f +0, 1, 1, 1, 518400, 0xb6fa68ba +0, 2, 2, 1, 518400, 0x0c13a4c9 +0, 3, 3, 1, 518400, 0x351e940d +0, 4, 4, 1, 518400, 0x07ad35cb +0, 5, 5, 1, 518400, 0x0c2b1413 +0, 6, 6, 1, 518400, 0xf770b86b +0, 7, 7, 1, 518400, 0xb1ec5f47 +0, 8, 8, 1, 518400, 0xee591da8 +0, 9, 9, 1, 518400, 0x18046c55 +0, 10, 10, 1, 518400, 0xcfe7bb62 +0, 11, 11, 1, 518400, 0x260e7ecd +0, 12, 12, 1, 518400, 0x3a3034cc +0, 13, 13, 1, 518400, 0xee7800dd +0, 14, 14, 1, 518400, 0xdc4176b4 +0, 15, 15, 1, 518400, 0x7bb037db +0, 16, 16, 1, 518400, 0x4d4721d1 +0, 17, 17, 1, 518400, 0xbd5cc3b4 +0, 18, 18, 1, 518400, 0x678acc34 +0, 19, 19, 1, 518400, 0xb3ffba44 +0, 20, 20, 1, 518400, 0xda9ebefb +0, 21, 21, 1, 518400, 0xb810bc59 +0, 22, 22, 1, 518400, 0xc79fc02d +0, 23, 23, 1, 518400, 0x28d9ad0d diff --git a/tests/ref/fate/vc1test_smm0015 b/tests/ref/fate/vc1test_smm0015 new file mode 100644 index 000000000..3183d6b7a --- /dev/null +++ b/tests/ref/fate/vc1test_smm0015 @@ -0,0 +1,30 @@ +#tb 0: 1/25 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 720x576 +#sar 0: 0/1 +0, 0, 0, 1, 622080, 0x68c84e70 +0, 1, 1, 1, 622080, 0xc29f7155 +0, 2, 2, 1, 622080, 0x78900210 +0, 3, 3, 1, 622080, 0x4d44c353 +0, 4, 4, 1, 622080, 0xd230b3dd +0, 5, 5, 1, 622080, 0xd72a029c +0, 6, 6, 1, 622080, 0xc76acb50 +0, 7, 7, 1, 622080, 0xf90816ab +0, 8, 8, 1, 622080, 0x56996b77 +0, 9, 9, 1, 622080, 0x1784890f +0, 10, 10, 1, 622080, 0xbc4c81f2 +0, 11, 11, 1, 622080, 0xab5f02ac +0, 12, 12, 1, 622080, 0x539bb59c +0, 13, 13, 1, 622080, 0xa34bf120 +0, 14, 14, 1, 622080, 0xa671eaac +0, 15, 15, 1, 622080, 0x51d77a74 +0, 16, 16, 1, 622080, 0x6d15c7b0 +0, 17, 17, 1, 622080, 0x1bf7535a +0, 18, 18, 1, 622080, 0x8ed2e73c +0, 19, 19, 1, 622080, 0x9f4f86a6 +0, 20, 20, 1, 622080, 0x95e05b22 +0, 21, 21, 1, 622080, 0x29c570a0 +0, 22, 22, 1, 622080, 0xc612f057 +0, 23, 23, 1, 622080, 0xe782d106 +0, 24, 24, 1, 622080, 0xeee9a3b7 diff --git a/tests/ref/fate/vp4 b/tests/ref/fate/vp4 new file mode 100644 index 000000000..dae848eab --- /dev/null +++ b/tests/ref/fate/vp4 @@ -0,0 +1,29 @@ +#tb 0: 1/24 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 608x256 +#sar 0: 0/1 +0, 0, 0, 1, 233472, 0xcf3a25ae +0, 1, 1, 1, 233472, 0xcc16c0bb +0, 2, 2, 1, 233472, 0xb2dcf0fd +0, 3, 3, 1, 233472, 0xbc0f0aea +0, 4, 4, 1, 233472, 0x97a1b4e9 +0, 5, 5, 1, 233472, 0x40d1661e +0, 6, 6, 1, 233472, 0x2bc13fe4 +0, 7, 7, 1, 233472, 0xe9ff96b4 +0, 8, 8, 1, 233472, 0xd57585ad +0, 9, 9, 1, 233472, 0xcf1a0cbe +0, 10, 10, 1, 233472, 0x4b49d6e0 +0, 11, 11, 1, 233472, 0x9e2562f1 +0, 12, 12, 1, 233472, 0x62675663 +0, 13, 13, 1, 233472, 0x8b27fc45 +0, 14, 14, 1, 233472, 0x437eb1f7 +0, 15, 15, 1, 233472, 0x1be26067 +0, 16, 16, 1, 233472, 0x479f32fb +0, 17, 17, 1, 233472, 0x405bdeb0 +0, 18, 18, 1, 233472, 0x966b3045 +0, 19, 19, 1, 233472, 0x4630a436 +0, 20, 20, 1, 233472, 0x70141070 +0, 21, 21, 1, 233472, 0x50a66c51 +0, 22, 22, 1, 233472, 0x266e9b5a +0, 23, 23, 1, 233472, 0xbbde5029 diff --git a/tests/ref/fate/vp60 b/tests/ref/fate/vp60 index 4becf2a8e..2381c2775 100644 --- a/tests/ref/fate/vp60 +++ b/tests/ref/fate/vp60 @@ -18,114 +18,114 @@ 0, 12, 12, 1, 55296, 0xe76b7df7 0, 13, 13, 1, 55296, 0x5a049f33 0, 14, 14, 1, 55296, 0xc83d9b90 -0, 15, 15, 1, 55296, 0x567877b8 -0, 16, 16, 1, 55296, 0x334c7f6e -0, 17, 17, 1, 55296, 0x9317945c -0, 18, 18, 1, 55296, 0xf032831e -0, 19, 19, 1, 55296, 0x7b6c8d2c -0, 20, 20, 1, 55296, 0x37109fd6 -0, 21, 21, 1, 55296, 0xe9b0b61b -0, 22, 22, 1, 55296, 0x7385dae8 -0, 23, 23, 1, 55296, 0x74a8a9f5 -0, 24, 24, 1, 55296, 0xbcd2e218 -0, 25, 25, 1, 55296, 0x0aa6c623 -0, 26, 26, 1, 55296, 0x2224d6d6 -0, 27, 27, 1, 55296, 0x8c8ee4d9 -0, 28, 28, 1, 55296, 0x0d4ceccc -0, 29, 29, 1, 55296, 0x623f10c7 -0, 30, 30, 1, 55296, 0x13a61f8f -0, 31, 31, 1, 55296, 0x5343fa8d -0, 32, 32, 1, 55296, 0x21fef1b5 -0, 33, 33, 1, 55296, 0x380de6b4 -0, 34, 34, 1, 55296, 0x04bedfd3 -0, 35, 35, 1, 55296, 0x428cf510 -0, 36, 36, 1, 55296, 0xbca8c214 -0, 37, 37, 1, 55296, 0x947faa34 -0, 38, 38, 1, 55296, 0x70769f45 -0, 39, 39, 1, 55296, 0xcb9483ad +0, 15, 15, 1, 55296, 0x464d77d6 +0, 16, 16, 1, 55296, 0x725d7fa2 +0, 17, 17, 1, 55296, 0xc30494d5 +0, 18, 18, 1, 55296, 0x5687839f +0, 19, 19, 1, 55296, 0x38be8df5 +0, 20, 20, 1, 55296, 0x62afa0ca +0, 21, 21, 1, 55296, 0x683ab733 +0, 22, 22, 1, 55296, 0xccbedc72 +0, 23, 23, 1, 55296, 0x43c4abc5 +0, 24, 24, 1, 55296, 0xf2f2e3f5 +0, 25, 25, 1, 55296, 0x5fb8c813 +0, 26, 26, 1, 55296, 0x7814d907 +0, 27, 27, 1, 55296, 0xbb87e71a +0, 28, 28, 1, 55296, 0x41c6ef34 +0, 29, 29, 1, 55296, 0x3f041373 +0, 30, 30, 1, 55296, 0x14b62281 +0, 31, 31, 1, 55296, 0x9a41fddb +0, 32, 32, 1, 55296, 0x8961f556 +0, 33, 33, 1, 55296, 0x98edea61 +0, 34, 34, 1, 55296, 0x434ae3dd +0, 35, 35, 1, 55296, 0x0aa4fa23 +0, 36, 36, 1, 55296, 0x0b8bc77f +0, 37, 37, 1, 55296, 0x79dfafbc +0, 38, 38, 1, 55296, 0x199ea4da +0, 39, 39, 1, 55296, 0xd270896d 0, 40, 40, 1, 55296, 0xac4ea82b -0, 41, 41, 1, 55296, 0xa3816977 -0, 42, 42, 1, 55296, 0xcfd54ec4 -0, 43, 43, 1, 55296, 0x97743f0e -0, 44, 44, 1, 55296, 0x4cb4424d -0, 45, 45, 1, 55296, 0x0b503c11 -0, 46, 46, 1, 55296, 0x879f333a -0, 47, 47, 1, 55296, 0x6ff9eb8f -0, 48, 48, 1, 55296, 0x7cd6e5af -0, 49, 49, 1, 55296, 0x44e2c36f -0, 50, 50, 1, 55296, 0x4e8993fb -0, 51, 51, 1, 55296, 0xf0bb9664 -0, 52, 52, 1, 55296, 0xde608458 -0, 53, 53, 1, 55296, 0xb3017f01 -0, 54, 54, 1, 55296, 0x2e096579 -0, 55, 55, 1, 55296, 0xd7295790 -0, 56, 56, 1, 55296, 0xc40b81cb -0, 57, 57, 1, 55296, 0x53a86e41 -0, 58, 58, 1, 55296, 0x74142f89 -0, 59, 59, 1, 55296, 0x2a1428ce -0, 60, 60, 1, 55296, 0x5d0c2852 -0, 61, 61, 1, 55296, 0x162058a4 -0, 62, 62, 1, 55296, 0x4e8c6ce8 -0, 63, 63, 1, 55296, 0x1d382af2 -0, 64, 64, 1, 55296, 0x35dd2b75 -0, 65, 65, 1, 55296, 0x1e4c205f -0, 66, 66, 1, 55296, 0x74a22383 -0, 67, 67, 1, 55296, 0x6ddb237d -0, 68, 68, 1, 55296, 0xd290263b -0, 69, 69, 1, 55296, 0xc778249f +0, 41, 41, 1, 55296, 0x770b6984 +0, 42, 42, 1, 55296, 0x378b4f1a +0, 43, 43, 1, 55296, 0xe8253faf +0, 44, 44, 1, 55296, 0xc8224326 +0, 45, 45, 1, 55296, 0x22b33d1b +0, 46, 46, 1, 55296, 0x83c33475 +0, 47, 47, 1, 55296, 0xbd2aed59 +0, 48, 48, 1, 55296, 0xe058e7e6 +0, 49, 49, 1, 55296, 0x575fc611 +0, 50, 50, 1, 55296, 0x218196dd +0, 51, 51, 1, 55296, 0x0882998c +0, 52, 52, 1, 55296, 0x380887dd +0, 53, 53, 1, 55296, 0x833f82c8 +0, 54, 54, 1, 55296, 0x9db9697b +0, 55, 55, 1, 55296, 0xb8dd5be8 +0, 56, 56, 1, 55296, 0x1df1869b +0, 57, 57, 1, 55296, 0xe0bd7399 +0, 58, 58, 1, 55296, 0xc2413536 +0, 59, 59, 1, 55296, 0x90bb2ebf +0, 60, 60, 1, 55296, 0x6fe72e97 +0, 61, 61, 1, 55296, 0x41385f50 +0, 62, 62, 1, 55296, 0x360973b0 +0, 63, 63, 1, 55296, 0x211d31c4 +0, 64, 64, 1, 55296, 0xe40632a9 +0, 65, 65, 1, 55296, 0xc4052794 +0, 66, 66, 1, 55296, 0x2ff82adf +0, 67, 67, 1, 55296, 0x7d272ac3 +0, 68, 68, 1, 55296, 0x37512dcc +0, 69, 69, 1, 55296, 0x66832c7f 0, 70, 70, 1, 55296, 0xbc1046fb 0, 71, 71, 1, 55296, 0xf44d470f 0, 72, 72, 1, 55296, 0x28d85a11 -0, 73, 73, 1, 55296, 0xa68953b6 -0, 74, 74, 1, 55296, 0x02593ce5 -0, 75, 75, 1, 55296, 0x61be53d5 -0, 76, 76, 1, 55296, 0x4c503c54 -0, 77, 77, 1, 55296, 0x3d3e60f7 -0, 78, 78, 1, 55296, 0xec876b9d -0, 79, 79, 1, 55296, 0x5b5f59e4 -0, 80, 80, 1, 55296, 0xbd2d5f84 -0, 81, 81, 1, 55296, 0xaa7a6410 -0, 82, 82, 1, 55296, 0xaa196189 -0, 83, 83, 1, 55296, 0x81365cca -0, 84, 84, 1, 55296, 0xa85f6861 -0, 85, 85, 1, 55296, 0xcb46562e -0, 86, 86, 1, 55296, 0x1b935862 -0, 87, 87, 1, 55296, 0x80a45a60 -0, 88, 88, 1, 55296, 0x8e8aabba -0, 89, 89, 1, 55296, 0x38939b53 -0, 90, 90, 1, 55296, 0x4f397c22 -0, 91, 91, 1, 55296, 0x7d0d8476 -0, 92, 92, 1, 55296, 0x943e8044 -0, 93, 93, 1, 55296, 0xabc6b323 -0, 94, 94, 1, 55296, 0x87dfb605 -0, 95, 95, 1, 55296, 0x5ca89202 +0, 73, 73, 1, 55296, 0xbdb153c7 +0, 74, 74, 1, 55296, 0x87093d2d +0, 75, 75, 1, 55296, 0x132c5459 +0, 76, 76, 1, 55296, 0x293e3cff +0, 77, 77, 1, 55296, 0x1a2c61a2 +0, 78, 78, 1, 55296, 0xc9756c48 +0, 79, 79, 1, 55296, 0xd90f5a89 +0, 80, 80, 1, 55296, 0x83eb6053 +0, 81, 81, 1, 55296, 0x713864df +0, 82, 82, 1, 55296, 0xf0ef6273 +0, 83, 83, 1, 55296, 0x24875dc4 +0, 84, 84, 1, 55296, 0x094a696e +0, 85, 85, 1, 55296, 0xe2d95761 +0, 86, 86, 1, 55296, 0x33265995 +0, 87, 87, 1, 55296, 0xc24b5bb9 +0, 88, 88, 1, 55296, 0xc130ad3d +0, 89, 89, 1, 55296, 0x42389d02 +0, 90, 90, 1, 55296, 0x372b7dbd +0, 91, 91, 1, 55296, 0x8645860d +0, 92, 92, 1, 55296, 0x218581dc +0, 93, 93, 1, 55296, 0xaea2b4e7 +0, 94, 94, 1, 55296, 0x3b14b7fa +0, 95, 95, 1, 55296, 0x7b7d93f7 0, 96, 96, 1, 55296, 0x61bc9b27 0, 97, 97, 1, 55296, 0x1e4baa30 -0, 98, 98, 1, 55296, 0xd8a7adb0 +0, 98, 98, 1, 55296, 0x2a6dadac 0, 99, 99, 1, 55296, 0x0d0aa8fb -0, 100, 100, 1, 55296, 0x1f1ba33c -0, 101, 101, 1, 55296, 0xa000a80b -0, 102, 102, 1, 55296, 0xb49dd332 -0, 103, 103, 1, 55296, 0x6b8ac499 -0, 104, 104, 1, 55296, 0x9636ed15 -0, 105, 105, 1, 55296, 0xa152f03d -0, 106, 106, 1, 55296, 0x47a8cfc7 -0, 107, 107, 1, 55296, 0x9f94c82a -0, 108, 108, 1, 55296, 0xe208d626 -0, 109, 109, 1, 55296, 0x28cc0616 -0, 110, 110, 1, 55296, 0xc545179e -0, 111, 111, 1, 55296, 0xd38e05af -0, 112, 112, 1, 55296, 0x25d6ed99 -0, 113, 113, 1, 55296, 0x7a6bf86e -0, 114, 114, 1, 55296, 0xbb3bfbcd -0, 115, 115, 1, 55296, 0x33de2984 -0, 116, 116, 1, 55296, 0xd5b10c27 -0, 117, 117, 1, 55296, 0x19e31f78 -0, 118, 118, 1, 55296, 0xf62f1a4f -0, 119, 119, 1, 55296, 0x3f792203 -0, 120, 120, 1, 55296, 0xe4ed6202 -0, 121, 121, 1, 55296, 0xee265136 -0, 122, 122, 1, 55296, 0x408af73c +0, 100, 100, 1, 55296, 0x3c6aa33a +0, 101, 101, 1, 55296, 0xbd4fa809 +0, 102, 102, 1, 55296, 0x55edd382 +0, 103, 103, 1, 55296, 0x6a9cc4df +0, 104, 104, 1, 55296, 0x49a5ed7f +0, 105, 105, 1, 55296, 0x0c33f0b3 +0, 106, 106, 1, 55296, 0xd5e4d037 +0, 107, 107, 1, 55296, 0x2ddfc89a +0, 108, 108, 1, 55296, 0xb39ed6c6 +0, 109, 109, 1, 55296, 0x8fe606e2 +0, 110, 110, 1, 55296, 0x10ce18ec +0, 111, 111, 1, 55296, 0xe2110705 +0, 112, 112, 1, 55296, 0x1a00ef28 +0, 113, 113, 1, 55296, 0x9c90fa21 +0, 114, 114, 1, 55296, 0xfafffdbe +0, 115, 115, 1, 55296, 0x741e2bc8 +0, 116, 116, 1, 55296, 0xf5b00ece +0, 117, 117, 1, 55296, 0x3b2e224d +0, 118, 118, 1, 55296, 0x29e81d73 +0, 119, 119, 1, 55296, 0xe3412580 +0, 120, 120, 1, 55296, 0x3c2865dc +0, 121, 121, 1, 55296, 0xd4b5553b +0, 122, 122, 1, 55296, 0x1ad8fa27 0, 123, 123, 1, 55296, 0xc1533ef5 0, 124, 124, 1, 55296, 0xf671f85d 0, 125, 125, 1, 55296, 0xae2670e0 diff --git a/tests/ref/fate/vp61 b/tests/ref/fate/vp61 index 2d3beea18..13146c407 100644 --- a/tests/ref/fate/vp61 +++ b/tests/ref/fate/vp61 @@ -4,122 +4,122 @@ #dimensions 0: 112x112 #sar 0: 0/1 0, 0, 0, 1, 18816, 0xc3fe9fc7 -0, 1, 1, 1, 18816, 0x6ddf972f -0, 2, 2, 1, 18816, 0x72808b6e -0, 3, 3, 1, 18816, 0x8f09857f -0, 4, 4, 1, 18816, 0xe8027c00 -0, 5, 5, 1, 18816, 0x308670cf -0, 6, 6, 1, 18816, 0x0e656170 -0, 7, 7, 1, 18816, 0x594e54a4 -0, 8, 8, 1, 18816, 0x36944b05 -0, 9, 9, 1, 18816, 0x87013a34 -0, 10, 10, 1, 18816, 0xc0f32f0d -0, 11, 11, 1, 18816, 0x911f1951 -0, 12, 12, 1, 18816, 0xad590d59 -0, 13, 13, 1, 18816, 0x943afff0 -0, 14, 14, 1, 18816, 0x7f5ef719 -0, 15, 15, 1, 18816, 0x889feafc -0, 16, 16, 1, 18816, 0x4334e12b -0, 17, 17, 1, 18816, 0xd080cc67 -0, 18, 18, 1, 18816, 0xc3c1c04c -0, 19, 19, 1, 18816, 0x816bae4b -0, 20, 20, 1, 18816, 0xed23a5c7 -0, 21, 21, 1, 18816, 0x86689c2f -0, 22, 22, 1, 18816, 0x63408c52 -0, 23, 23, 1, 18816, 0x399c79d6 -0, 24, 24, 1, 18816, 0xf0ff63bf -0, 25, 25, 1, 18816, 0xa6185353 -0, 26, 26, 1, 18816, 0xe33d46fc -0, 27, 27, 1, 18816, 0xd58d3c6d -0, 28, 28, 1, 18816, 0xc94a27ea -0, 29, 29, 1, 18816, 0x62f31c59 -0, 30, 30, 1, 18816, 0x71880825 -0, 31, 31, 1, 18816, 0xa6ce01d7 -0, 32, 32, 1, 18816, 0xa1d4fc06 -0, 33, 33, 1, 18816, 0xc208f570 -0, 34, 34, 1, 18816, 0xc862e637 -0, 35, 35, 1, 18816, 0xcf9ed93a -0, 36, 36, 1, 18816, 0x85a8cbcc -0, 37, 37, 1, 18816, 0x650ac6c1 -0, 38, 38, 1, 18816, 0xb418c12b -0, 39, 39, 1, 18816, 0x9fe5b412 -0, 40, 40, 1, 18816, 0x80f6a7c1 -0, 41, 41, 1, 18816, 0x283299e4 -0, 42, 42, 1, 18816, 0x15429202 -0, 43, 43, 1, 18816, 0x9f0f8c8a -0, 44, 44, 1, 18816, 0x8e828811 -0, 45, 45, 1, 18816, 0xaac67993 -0, 46, 46, 1, 18816, 0x8f3b6f4f -0, 47, 47, 1, 18816, 0x0b125f95 -0, 48, 48, 1, 18816, 0xb4e75d14 -0, 49, 49, 1, 18816, 0x1bac5933 -0, 50, 50, 1, 18816, 0x300b521b -0, 51, 51, 1, 18816, 0x51174590 -0, 52, 52, 1, 18816, 0x03df3d70 -0, 53, 53, 1, 18816, 0x338a344a -0, 54, 54, 1, 18816, 0x45ad328d -0, 55, 55, 1, 18816, 0x2d4e321a -0, 56, 56, 1, 18816, 0x15932563 -0, 57, 57, 1, 18816, 0x9b4f1c76 -0, 58, 58, 1, 18816, 0x8e31153c -0, 59, 59, 1, 18816, 0xfb391185 -0, 60, 60, 1, 18816, 0x93ee0cdc -0, 61, 61, 1, 18816, 0xddeb0642 -0, 62, 62, 1, 18816, 0xda6cf529 -0, 63, 63, 1, 18816, 0xdbd6f085 -0, 64, 64, 1, 18816, 0x357aec81 -0, 65, 65, 1, 18816, 0x36eaecca -0, 66, 66, 1, 18816, 0x6535ee02 -0, 67, 67, 1, 18816, 0xb7dfe466 -0, 68, 68, 1, 18816, 0x58d3d86b -0, 69, 69, 1, 18816, 0xd8aad64b -0, 70, 70, 1, 18816, 0x37ecd588 -0, 71, 71, 1, 18816, 0xe2f9cee4 -0, 72, 72, 1, 18816, 0xcd1ac93e -0, 73, 73, 1, 18816, 0x18e1be81 -0, 74, 74, 1, 18816, 0xa05bb9d7 -0, 75, 75, 1, 18816, 0xe0ebb663 -0, 76, 76, 1, 18816, 0x7d61b39a -0, 77, 77, 1, 18816, 0x01b8acb5 -0, 78, 78, 1, 18816, 0x7577aa8b -0, 79, 79, 1, 18816, 0x6bbda4b5 -0, 80, 80, 1, 18816, 0xd0cc9b29 -0, 81, 81, 1, 18816, 0xb2858cbb -0, 82, 82, 1, 18816, 0x93608c9d -0, 83, 83, 1, 18816, 0x80c38e03 -0, 84, 84, 1, 18816, 0x37d6843c -0, 85, 85, 1, 18816, 0xacc47b9a -0, 86, 86, 1, 18816, 0xc4317178 -0, 87, 87, 1, 18816, 0xc92f6ebd -0, 88, 88, 1, 18816, 0xc1217a3b -0, 89, 89, 1, 18816, 0x03a37ccb -0, 90, 90, 1, 18816, 0xf38c71a2 -0, 91, 91, 1, 18816, 0x68ff697d -0, 92, 92, 1, 18816, 0x0fe358e5 -0, 93, 93, 1, 18816, 0x58455870 -0, 94, 94, 1, 18816, 0xc9075ce7 -0, 95, 95, 1, 18816, 0x16685773 -0, 96, 96, 1, 18816, 0x1b434c0e -0, 97, 97, 1, 18816, 0x008e4c97 -0, 98, 98, 1, 18816, 0xb4d04f4f -0, 99, 99, 1, 18816, 0xc8c94848 -0, 100, 100, 1, 18816, 0x64664191 -0, 101, 101, 1, 18816, 0xd591367f -0, 102, 102, 1, 18816, 0xc70d3141 -0, 103, 103, 1, 18816, 0x8d492655 -0, 104, 104, 1, 18816, 0x7e7f22c8 -0, 105, 105, 1, 18816, 0x335d23f9 -0, 106, 106, 1, 18816, 0x0a7f22b6 -0, 107, 107, 1, 18816, 0x6cf51cb2 -0, 108, 108, 1, 18816, 0x312516e1 -0, 109, 109, 1, 18816, 0x8a3c0c7a -0, 110, 110, 1, 18816, 0x997d0d20 -0, 111, 111, 1, 18816, 0xffbd117e -0, 112, 112, 1, 18816, 0x855808ca -0, 113, 113, 1, 18816, 0xe335fb94 -0, 114, 114, 1, 18816, 0x12e6f95c -0, 115, 115, 1, 18816, 0x2d62f845 -0, 116, 116, 1, 18816, 0x7e63f591 -0, 117, 117, 1, 18816, 0x7463f175 -0, 118, 118, 1, 18816, 0x1521e0d2 -0, 119, 119, 1, 18816, 0x96a8dbce +0, 1, 1, 1, 18816, 0xab429744 +0, 2, 2, 1, 18816, 0x1eec8b7d +0, 3, 3, 1, 18816, 0x3817859f +0, 4, 4, 1, 18816, 0x8f487c41 +0, 5, 5, 1, 18816, 0x4ce87138 +0, 6, 6, 1, 18816, 0x499361dd +0, 7, 7, 1, 18816, 0xd26c5518 +0, 8, 8, 1, 18816, 0xfb1a4b88 +0, 9, 9, 1, 18816, 0x4ac63ac7 +0, 10, 10, 1, 18816, 0x39642fad +0, 11, 11, 1, 18816, 0x4dd219f6 +0, 12, 12, 1, 18816, 0x6c500df7 +0, 13, 13, 1, 18816, 0x700e00b4 +0, 14, 14, 1, 18816, 0xbebaf7e0 +0, 15, 15, 1, 18816, 0x22c1ebf6 +0, 16, 16, 1, 18816, 0x723fe229 +0, 17, 17, 1, 18816, 0x9b22cd91 +0, 18, 18, 1, 18816, 0x45ddc17a +0, 19, 19, 1, 18816, 0x9b33af88 +0, 20, 20, 1, 18816, 0xf9d1a70d +0, 21, 21, 1, 18816, 0x9bfd9d84 +0, 22, 22, 1, 18816, 0x27048da1 +0, 23, 23, 1, 18816, 0x0e497b2d +0, 24, 24, 1, 18816, 0x508264fd +0, 25, 25, 1, 18816, 0xf6985495 +0, 26, 26, 1, 18816, 0xa5014869 +0, 27, 27, 1, 18816, 0x426e3de4 +0, 28, 28, 1, 18816, 0xd72129b9 +0, 29, 29, 1, 18816, 0x12e51e1c +0, 30, 30, 1, 18816, 0x754109eb +0, 31, 31, 1, 18816, 0x2fb5039e +0, 32, 32, 1, 18816, 0x9407fdea +0, 33, 33, 1, 18816, 0x59f2f752 +0, 34, 34, 1, 18816, 0xb448e831 +0, 35, 35, 1, 18816, 0xf31fdb2e +0, 36, 36, 1, 18816, 0x6bedcdec +0, 37, 37, 1, 18816, 0xbbfec8e6 +0, 38, 38, 1, 18816, 0x104ac345 +0, 39, 39, 1, 18816, 0xd387b629 +0, 40, 40, 1, 18816, 0x4187a9e7 +0, 41, 41, 1, 18816, 0x1c649c17 +0, 42, 42, 1, 18816, 0xcc869431 +0, 43, 43, 1, 18816, 0x8bc78ed1 +0, 44, 44, 1, 18816, 0x34de8a5f +0, 45, 45, 1, 18816, 0x42727bd0 +0, 46, 46, 1, 18816, 0x6e9c7192 +0, 47, 47, 1, 18816, 0xd93761c1 +0, 48, 48, 1, 18816, 0x69455f50 +0, 49, 49, 1, 18816, 0xa35d5b8b +0, 50, 50, 1, 18816, 0xe6635469 +0, 51, 51, 1, 18816, 0x285d47f9 +0, 52, 52, 1, 18816, 0xdb0a3fdf +0, 53, 53, 1, 18816, 0x608336d0 +0, 54, 54, 1, 18816, 0x39e9353f +0, 55, 55, 1, 18816, 0xad2034bd +0, 56, 56, 1, 18816, 0xa0f527e7 +0, 57, 57, 1, 18816, 0x5ed71ef1 +0, 58, 58, 1, 18816, 0xd2df1798 +0, 59, 59, 1, 18816, 0x932513d3 +0, 60, 60, 1, 18816, 0xab600f1b +0, 61, 61, 1, 18816, 0x665d087e +0, 62, 62, 1, 18816, 0x8d71f765 +0, 63, 63, 1, 18816, 0xfc80f2ae +0, 64, 64, 1, 18816, 0x885bee81 +0, 65, 65, 1, 18816, 0x6c4feec9 +0, 66, 66, 1, 18816, 0x5010f017 +0, 67, 67, 1, 18816, 0x63d5e683 +0, 68, 68, 1, 18816, 0x216ddab5 +0, 69, 69, 1, 18816, 0xb758d8c2 +0, 70, 70, 1, 18816, 0xeae4d7e5 +0, 71, 71, 1, 18816, 0x2553d137 +0, 72, 72, 1, 18816, 0xced6cb97 +0, 73, 73, 1, 18816, 0xd332c103 +0, 74, 74, 1, 18816, 0xe84bbc67 +0, 75, 75, 1, 18816, 0x21f7b90d +0, 76, 76, 1, 18816, 0xbd88b648 +0, 77, 77, 1, 18816, 0xe7b8af59 +0, 78, 78, 1, 18816, 0x30f5ad3d +0, 79, 79, 1, 18816, 0x79bfa7bb +0, 80, 80, 1, 18816, 0xd5919e34 +0, 81, 81, 1, 18816, 0x43758fda +0, 82, 82, 1, 18816, 0x93ff8fcc +0, 83, 83, 1, 18816, 0xa444913f +0, 84, 84, 1, 18816, 0xc41d878b +0, 85, 85, 1, 18816, 0x526d7f09 +0, 86, 86, 1, 18816, 0x40307528 +0, 87, 87, 1, 18816, 0xf63d725c +0, 88, 88, 1, 18816, 0x45587ddb +0, 89, 89, 1, 18816, 0x37018069 +0, 90, 90, 1, 18816, 0x69567572 +0, 91, 91, 1, 18816, 0xa8086d54 +0, 92, 92, 1, 18816, 0x2ab65ccc +0, 93, 93, 1, 18816, 0xa5475c5d +0, 94, 94, 1, 18816, 0x87dc60e2 +0, 95, 95, 1, 18816, 0x54295b5d +0, 96, 96, 1, 18816, 0xce424fe9 +0, 97, 97, 1, 18816, 0x99e0506d +0, 98, 98, 1, 18816, 0x6ac55324 +0, 99, 99, 1, 18816, 0xa60f4c1a +0, 100, 100, 1, 18816, 0x7eba456e +0, 101, 101, 1, 18816, 0xab703a88 +0, 102, 102, 1, 18816, 0xb8263539 +0, 103, 103, 1, 18816, 0x829e2abb +0, 104, 104, 1, 18816, 0x2e9f2736 +0, 105, 105, 1, 18816, 0x7a3d2885 +0, 106, 106, 1, 18816, 0x8023274f +0, 107, 107, 1, 18816, 0x39bf2196 +0, 108, 108, 1, 18816, 0x21cf1bcb +0, 109, 109, 1, 18816, 0x016911b9 +0, 110, 110, 1, 18816, 0x2a791237 +0, 111, 111, 1, 18816, 0x093f16a7 +0, 112, 112, 1, 18816, 0x07a90df3 +0, 113, 113, 1, 18816, 0x8de800ca +0, 114, 114, 1, 18816, 0xe379fe68 +0, 115, 115, 1, 18816, 0x267afd69 +0, 116, 116, 1, 18816, 0x5b29fac1 +0, 117, 117, 1, 18816, 0x3606f6b6 +0, 118, 118, 1, 18816, 0xcbdce61e +0, 119, 119, 1, 18816, 0x28ffe113 diff --git a/tests/ref/fate/vp6a b/tests/ref/fate/vp6a index b4f33630f..8fb2630ff 100644 --- a/tests/ref/fate/vp6a +++ b/tests/ref/fate/vp6a @@ -4,95 +4,95 @@ #dimensions 0: 300x180 #sar 0: 0/1 0, 0, 0, 1, 135000, 0x9dceed6d -0, 1, 1, 1, 135000, 0x47e5778d -0, 2, 2, 1, 135000, 0x5de36599 -0, 3, 3, 1, 135000, 0x540d8079 -0, 4, 4, 1, 135000, 0xba9ea534 -0, 5, 5, 1, 135000, 0xa75088f8 -0, 6, 6, 1, 135000, 0x7d867559 -0, 7, 7, 1, 135000, 0xcc678fee -0, 8, 8, 1, 135000, 0x79c590b9 -0, 9, 9, 1, 135000, 0x87789918 -0, 10, 10, 1, 135000, 0xaa939213 -0, 11, 11, 1, 135000, 0x3912916d -0, 12, 12, 1, 135000, 0x41305d0b -0, 13, 13, 1, 135000, 0x2686b5dd -0, 14, 14, 1, 135000, 0xa69ae422 -0, 15, 15, 1, 135000, 0x998a3478 -0, 16, 16, 1, 135000, 0x5842768d -0, 17, 17, 1, 135000, 0xf6a85b16 -0, 18, 18, 1, 135000, 0x7a5b2708 -0, 19, 19, 1, 135000, 0x8b2abb63 -0, 20, 20, 1, 135000, 0x7dc8468b -0, 21, 21, 1, 135000, 0x04d85001 -0, 22, 22, 1, 135000, 0x83e3c647 -0, 23, 23, 1, 135000, 0xcddd687e -0, 24, 24, 1, 135000, 0x818e785e -0, 25, 25, 1, 135000, 0x3a915080 -0, 26, 26, 1, 135000, 0x953d603d -0, 27, 27, 1, 135000, 0x79005ebf -0, 28, 28, 1, 135000, 0x80afec75 -0, 29, 29, 1, 135000, 0xfc8e376b -0, 30, 30, 1, 135000, 0xf957b7ef -0, 31, 31, 1, 135000, 0xe878da44 -0, 32, 32, 1, 135000, 0xe68ecca3 -0, 33, 33, 1, 135000, 0x1a2cc7d3 -0, 34, 34, 1, 135000, 0x4f346a69 -0, 35, 35, 1, 135000, 0x7a0cf4ac -0, 36, 36, 1, 135000, 0x6d4eee7a -0, 37, 37, 1, 135000, 0xf0688cbd -0, 38, 38, 1, 135000, 0xca4abbbc -0, 39, 39, 1, 135000, 0x87669519 -0, 40, 40, 1, 135000, 0xd090e9d7 -0, 41, 41, 1, 135000, 0xd7f536c1 -0, 42, 42, 1, 135000, 0x353ede54 -0, 43, 43, 1, 135000, 0xbc8f5358 -0, 44, 44, 1, 135000, 0xb52cd59a -0, 45, 45, 1, 135000, 0x0b882eba -0, 46, 46, 1, 135000, 0xc544cd54 -0, 47, 47, 1, 135000, 0x31ca7e73 +0, 1, 1, 1, 135000, 0x1fc377a4 +0, 2, 2, 1, 135000, 0x0b4465d4 +0, 3, 3, 1, 135000, 0x136b8062 +0, 4, 4, 1, 135000, 0x4691a55c +0, 5, 5, 1, 135000, 0x55bb8a19 +0, 6, 6, 1, 135000, 0xdbf67651 +0, 7, 7, 1, 135000, 0x6fb19113 +0, 8, 8, 1, 135000, 0x3edc9227 +0, 9, 9, 1, 135000, 0x53b39aff +0, 10, 10, 1, 135000, 0x699e94b0 +0, 11, 11, 1, 135000, 0xeedd9388 +0, 12, 12, 1, 135000, 0x14055f96 +0, 13, 13, 1, 135000, 0x71fbb5fd +0, 14, 14, 1, 135000, 0x6fb4e491 +0, 15, 15, 1, 135000, 0x35ca3482 +0, 16, 16, 1, 135000, 0x0c2a7530 +0, 17, 17, 1, 135000, 0x422c5581 +0, 18, 18, 1, 135000, 0x19eb2155 +0, 19, 19, 1, 135000, 0x07e1b114 +0, 20, 20, 1, 135000, 0xa10f3f81 +0, 21, 21, 1, 135000, 0x75684dcd +0, 22, 22, 1, 135000, 0x1721c337 +0, 23, 23, 1, 135000, 0x3897667d +0, 24, 24, 1, 135000, 0x1232769e +0, 25, 25, 1, 135000, 0xec975059 +0, 26, 26, 1, 135000, 0xb2a46123 +0, 27, 27, 1, 135000, 0x052c5f72 +0, 28, 28, 1, 135000, 0x3087eb2f +0, 29, 29, 1, 135000, 0xd1e0373a +0, 30, 30, 1, 135000, 0x64dab704 +0, 31, 31, 1, 135000, 0xa44dd89e +0, 32, 32, 1, 135000, 0x380ecae9 +0, 33, 33, 1, 135000, 0x8c6fc4ab +0, 34, 34, 1, 135000, 0x02096903 +0, 35, 35, 1, 135000, 0x11edf432 +0, 36, 36, 1, 135000, 0x3585ee5f +0, 37, 37, 1, 135000, 0xe1338c40 +0, 38, 38, 1, 135000, 0x5edfbd0c +0, 39, 39, 1, 135000, 0x9420965c +0, 40, 40, 1, 135000, 0x0caceb17 +0, 41, 41, 1, 135000, 0x3fdc36c3 +0, 42, 42, 1, 135000, 0x8a24df14 +0, 43, 43, 1, 135000, 0x5dc057b0 +0, 44, 44, 1, 135000, 0xdc5eda65 +0, 45, 45, 1, 135000, 0x60433612 +0, 46, 46, 1, 135000, 0x6a91d6c9 +0, 47, 47, 1, 135000, 0x53598734 0, 48, 48, 1, 135000, 0xb1569ce9 -0, 49, 49, 1, 135000, 0x8bf4394f -0, 50, 50, 1, 135000, 0xf413812a -0, 51, 51, 1, 135000, 0xf2fa90ab -0, 52, 52, 1, 135000, 0xdcd8b265 -0, 53, 53, 1, 135000, 0xa89cdba1 -0, 54, 54, 1, 135000, 0x212b59a5 -0, 55, 55, 1, 135000, 0x10c589c3 -0, 56, 56, 1, 135000, 0x432ab5b4 +0, 49, 49, 1, 135000, 0xf5e83a33 +0, 50, 50, 1, 135000, 0xebe18275 +0, 51, 51, 1, 135000, 0x98af9447 +0, 52, 52, 1, 135000, 0x3f03b765 +0, 53, 53, 1, 135000, 0x7423e0b8 +0, 54, 54, 1, 135000, 0x6c1b5faa +0, 55, 55, 1, 135000, 0xebf98d52 +0, 56, 56, 1, 135000, 0xf3dfb8b6 0, 57, 57, 1, 135000, 0x85a9634a -0, 58, 58, 1, 135000, 0x10db5b87 -0, 59, 59, 1, 135000, 0x583145d9 -0, 60, 60, 1, 135000, 0x7d3a33bd -0, 61, 61, 1, 135000, 0xcf592423 -0, 62, 62, 1, 135000, 0xb59728e5 -0, 63, 63, 1, 135000, 0x1eeca660 -0, 64, 64, 1, 135000, 0xff7bcc34 -0, 65, 65, 1, 135000, 0x0ef8f271 -0, 66, 66, 1, 135000, 0x8c9ca8ee -0, 67, 67, 1, 135000, 0x8a7ece34 -0, 68, 68, 1, 135000, 0x7d4c3b5d -0, 69, 69, 1, 135000, 0x99118f21 -0, 70, 70, 1, 135000, 0xd97fe7e2 -0, 71, 71, 1, 135000, 0xf93842f1 -0, 72, 72, 1, 135000, 0x35c912e8 -0, 73, 73, 1, 135000, 0x14e59e97 +0, 58, 58, 1, 135000, 0x4d425bb5 +0, 59, 59, 1, 135000, 0xfb7945ee +0, 60, 60, 1, 135000, 0x593534c1 +0, 61, 61, 1, 135000, 0xe3fa2517 +0, 62, 62, 1, 135000, 0x893629e3 +0, 63, 63, 1, 135000, 0xdc3ca6ad +0, 64, 64, 1, 135000, 0x16b1ce27 +0, 65, 65, 1, 135000, 0x8296f478 +0, 66, 66, 1, 135000, 0x9e9baaa3 +0, 67, 67, 1, 135000, 0x994ecd4a +0, 68, 68, 1, 135000, 0x40f83b3c +0, 69, 69, 1, 135000, 0x0de38f90 +0, 70, 70, 1, 135000, 0x5455ea6c +0, 71, 71, 1, 135000, 0x053e41e8 +0, 72, 72, 1, 135000, 0x0fee1281 +0, 73, 73, 1, 135000, 0xa0c9a434 0, 74, 74, 1, 135000, 0x8e4c19aa -0, 75, 75, 1, 135000, 0x4adfbc53 -0, 76, 76, 1, 135000, 0x0613adde -0, 77, 77, 1, 135000, 0x8db264ab -0, 78, 78, 1, 135000, 0x3948b619 -0, 79, 79, 1, 135000, 0x843d7c02 -0, 80, 80, 1, 135000, 0x534fea34 +0, 75, 75, 1, 135000, 0x34bebc00 +0, 76, 76, 1, 135000, 0x6670ad6f +0, 77, 77, 1, 135000, 0xdbba63fc +0, 78, 78, 1, 135000, 0xe34fb839 +0, 79, 79, 1, 135000, 0xa3ce7eb1 +0, 80, 80, 1, 135000, 0xdec7ed7d 0, 81, 81, 1, 135000, 0xdb7041bf -0, 82, 82, 1, 135000, 0xd0ce1cce -0, 83, 83, 1, 135000, 0x3c008335 -0, 84, 84, 1, 135000, 0xb699208f -0, 85, 85, 1, 135000, 0xe07da3ca -0, 86, 86, 1, 135000, 0x26331f41 -0, 87, 87, 1, 135000, 0x4e19fe83 -0, 88, 88, 1, 135000, 0xaa9a9e45 -0, 89, 89, 1, 135000, 0x336b7ed0 -0, 90, 90, 1, 135000, 0xc9bf7611 +0, 82, 82, 1, 135000, 0x2b1d1dc1 +0, 83, 83, 1, 135000, 0xaaa384c1 +0, 84, 84, 1, 135000, 0x37f42217 +0, 85, 85, 1, 135000, 0x928ba4da +0, 86, 86, 1, 135000, 0x2b681f41 +0, 87, 87, 1, 135000, 0xcbe1ff84 +0, 88, 88, 1, 135000, 0x47949f24 +0, 89, 89, 1, 135000, 0x368b7fe5 +0, 90, 90, 1, 135000, 0x1cf4773b 0, 91, 91, 1, 135000, 0x14c33a35 0, 92, 92, 1, 135000, 0xdc08470e diff --git a/tests/ref/fate/vp6a-skip_alpha b/tests/ref/fate/vp6a-skip_alpha index e2c435f40..f09277802 100644 --- a/tests/ref/fate/vp6a-skip_alpha +++ b/tests/ref/fate/vp6a-skip_alpha @@ -4,95 +4,95 @@ #dimensions 0: 300x180 #sar 0: 0/1 0, 0, 0, 1, 81000, 0xcb92962d -0, 1, 1, 1, 81000, 0xae381904 -0, 2, 2, 1, 81000, 0x1fcc0c75 -0, 3, 3, 1, 81000, 0x023f0c21 -0, 4, 4, 1, 81000, 0xad691402 -0, 5, 5, 1, 81000, 0x42390be0 -0, 6, 6, 1, 81000, 0xc1c10a4e -0, 7, 7, 1, 81000, 0x9c0315ac -0, 8, 8, 1, 81000, 0xc2a315a7 -0, 9, 9, 1, 81000, 0x3a631392 -0, 10, 10, 1, 81000, 0x11591414 -0, 11, 11, 1, 81000, 0x1a551125 -0, 12, 12, 1, 81000, 0x2e1efa4f -0, 13, 13, 1, 81000, 0x4aa3f016 -0, 14, 14, 1, 81000, 0x74c029d8 -0, 15, 15, 1, 81000, 0xdee9a98b -0, 16, 16, 1, 81000, 0xdf3502d5 -0, 17, 17, 1, 81000, 0x4653536b -0, 18, 18, 1, 81000, 0x7f658c75 -0, 19, 19, 1, 81000, 0xab18ff13 -0, 20, 20, 1, 81000, 0xac2b8f3b -0, 21, 21, 1, 81000, 0xd61ff094 -0, 22, 22, 1, 81000, 0x425bfc2b -0, 23, 23, 1, 81000, 0x6be7ecd3 -0, 24, 24, 1, 81000, 0x0b0ee65b -0, 25, 25, 1, 81000, 0x3c6f146b -0, 26, 26, 1, 81000, 0x27c4e9c8 -0, 27, 27, 1, 81000, 0x174022c4 -0, 28, 28, 1, 81000, 0x3320fe81 -0, 29, 29, 1, 81000, 0x7a3c342e -0, 30, 30, 1, 81000, 0x448b4346 -0, 31, 31, 1, 81000, 0xd285b23d -0, 32, 32, 1, 81000, 0x852ed590 -0, 33, 33, 1, 81000, 0xc9d3df17 -0, 34, 34, 1, 81000, 0x4d23727b -0, 35, 35, 1, 81000, 0x1fae66cd -0, 36, 36, 1, 81000, 0x384d54ab -0, 37, 37, 1, 81000, 0x2fee6ba3 -0, 38, 38, 1, 81000, 0xd7ad6f59 -0, 39, 39, 1, 81000, 0xaf5e3e76 -0, 40, 40, 1, 81000, 0x10fceda4 -0, 41, 41, 1, 81000, 0xb26df92b -0, 42, 42, 1, 81000, 0xd6676e08 -0, 43, 43, 1, 81000, 0xff6b1b95 -0, 44, 44, 1, 81000, 0x6196d598 -0, 45, 45, 1, 81000, 0x833ebf1b -0, 46, 46, 1, 81000, 0x7b085af1 -0, 47, 47, 1, 81000, 0xe8f583b4 +0, 1, 1, 1, 81000, 0x8fef1925 +0, 2, 2, 1, 81000, 0xf0350cb6 +0, 3, 3, 1, 81000, 0xa70a0c52 +0, 4, 4, 1, 81000, 0x21ef1490 +0, 5, 5, 1, 81000, 0x98bc0c96 +0, 6, 6, 1, 81000, 0x92380b27 +0, 7, 7, 1, 81000, 0xbba216cd +0, 8, 8, 1, 81000, 0x92a8172b +0, 9, 9, 1, 81000, 0xfbc21592 +0, 10, 10, 1, 81000, 0xdad416a1 +0, 11, 11, 1, 81000, 0xec4d13aa +0, 12, 12, 1, 81000, 0xaf36fcff +0, 13, 13, 1, 81000, 0xb4fcf056 +0, 14, 14, 1, 81000, 0xe3782a3f +0, 15, 15, 1, 81000, 0x714daa0b +0, 16, 16, 1, 81000, 0xe2770382 +0, 17, 17, 1, 81000, 0x553253ff +0, 18, 18, 1, 81000, 0x928d8c46 +0, 19, 19, 1, 81000, 0x06c8fe82 +0, 20, 20, 1, 81000, 0xb8198f5a +0, 21, 21, 1, 81000, 0x0029f118 +0, 22, 22, 1, 81000, 0x6fe7fc6f +0, 23, 23, 1, 81000, 0x9165edde +0, 24, 24, 1, 81000, 0xe76ae791 +0, 25, 25, 1, 81000, 0xa4dd145a +0, 26, 26, 1, 81000, 0x2d7de9d8 +0, 27, 27, 1, 81000, 0xe102228b +0, 28, 28, 1, 81000, 0xc57ffe0e +0, 29, 29, 1, 81000, 0x324434cb +0, 30, 30, 1, 81000, 0xedc0433e +0, 31, 31, 1, 81000, 0xd42bb18a +0, 32, 32, 1, 81000, 0xedb3d561 +0, 33, 33, 1, 81000, 0x5244de92 +0, 34, 34, 1, 81000, 0x0bb27280 +0, 35, 35, 1, 81000, 0xc6116736 +0, 36, 36, 1, 81000, 0x42f154e2 +0, 37, 37, 1, 81000, 0xffbd6bf9 +0, 38, 38, 1, 81000, 0x813170d0 +0, 39, 39, 1, 81000, 0x430c4040 +0, 40, 40, 1, 81000, 0x56d1eecb +0, 41, 41, 1, 81000, 0xaa4afa12 +0, 42, 42, 1, 81000, 0x2c3d6fb8 +0, 43, 43, 1, 81000, 0xfedf1e3e +0, 44, 44, 1, 81000, 0xf538d893 +0, 45, 45, 1, 81000, 0xcc81c3b5 +0, 46, 46, 1, 81000, 0x59b95fbc +0, 47, 47, 1, 81000, 0xb4da87a0 0, 48, 48, 1, 81000, 0x3426d5e4 -0, 49, 49, 1, 81000, 0x214069ed -0, 50, 50, 1, 81000, 0x7dbdfd3f -0, 51, 51, 1, 81000, 0xf19b3f45 -0, 52, 52, 1, 81000, 0x0f05c7e2 -0, 53, 53, 1, 81000, 0xba94e323 -0, 54, 54, 1, 81000, 0x0de7b0c2 -0, 55, 55, 1, 81000, 0xfcf93c55 -0, 56, 56, 1, 81000, 0x8a8dbd55 +0, 49, 49, 1, 81000, 0x8d066aae +0, 50, 50, 1, 81000, 0x09effe79 +0, 51, 51, 1, 81000, 0xecc540ae +0, 52, 52, 1, 81000, 0x845dc90c +0, 53, 53, 1, 81000, 0x9c2fe4d2 +0, 54, 54, 1, 81000, 0x8887b277 +0, 55, 55, 1, 81000, 0x3bdc3ca9 +0, 56, 56, 1, 81000, 0x094fbe27 0, 57, 57, 1, 81000, 0xddf22b97 -0, 58, 58, 1, 81000, 0x49a830ff -0, 59, 59, 1, 81000, 0x82ab2a4b -0, 60, 60, 1, 81000, 0xd23420e5 -0, 61, 61, 1, 81000, 0x7c1017d1 -0, 62, 62, 1, 81000, 0x9aa61b38 -0, 63, 63, 1, 81000, 0x2a724a18 -0, 64, 64, 1, 81000, 0xc18055f2 -0, 65, 65, 1, 81000, 0xecba3855 -0, 66, 66, 1, 81000, 0x0eed6b0f -0, 67, 67, 1, 81000, 0x4be73816 -0, 68, 68, 1, 81000, 0xa681214e -0, 69, 69, 1, 81000, 0x4958f83d -0, 70, 70, 1, 81000, 0xca0f0d61 -0, 71, 71, 1, 81000, 0x3c453de1 -0, 72, 72, 1, 81000, 0xff60360a -0, 73, 73, 1, 81000, 0xdcef0949 +0, 58, 58, 1, 81000, 0x31b23156 +0, 59, 59, 1, 81000, 0xf5bf2ad8 +0, 60, 60, 1, 81000, 0x4a9321c4 +0, 61, 61, 1, 81000, 0xdd1b18ca +0, 62, 62, 1, 81000, 0x4ece1cdd +0, 63, 63, 1, 81000, 0x6a9a4b53 +0, 64, 64, 1, 81000, 0x6624578b +0, 65, 65, 1, 81000, 0x89273a0f +0, 66, 66, 1, 81000, 0x9eb56c4c +0, 67, 67, 1, 81000, 0xe60238f5 +0, 68, 68, 1, 81000, 0xbc4c228a +0, 69, 69, 1, 81000, 0x3feefa08 +0, 70, 70, 1, 81000, 0x0d620f37 +0, 71, 71, 1, 81000, 0x93693fc8 +0, 72, 72, 1, 81000, 0xfc4b3848 +0, 73, 73, 1, 81000, 0xd9950bfb 0, 74, 74, 1, 81000, 0xe5e3732d -0, 75, 75, 1, 81000, 0x39747fd4 -0, 76, 76, 1, 81000, 0x6bec70e6 -0, 77, 77, 1, 81000, 0x7026a8c0 -0, 78, 78, 1, 81000, 0x92de5b61 -0, 79, 79, 1, 81000, 0x3f00507f -0, 80, 80, 1, 81000, 0x5620c377 +0, 75, 75, 1, 81000, 0x53517fd2 +0, 76, 76, 1, 81000, 0xb57c70b0 +0, 77, 77, 1, 81000, 0x378ea87c +0, 78, 78, 1, 81000, 0xfd2b5b58 +0, 79, 79, 1, 81000, 0x66d45077 +0, 80, 80, 1, 81000, 0x6e07c3f8 0, 81, 81, 1, 81000, 0x39f5ed38 -0, 82, 82, 1, 81000, 0x6ee35d67 -0, 83, 83, 1, 81000, 0x4f99a409 -0, 84, 84, 1, 81000, 0x0a05b6ea -0, 85, 85, 1, 81000, 0xd6c442d9 -0, 86, 86, 1, 81000, 0x0bb3d2f0 -0, 87, 87, 1, 81000, 0x6891c5b1 -0, 88, 88, 1, 81000, 0xf16ba9be -0, 89, 89, 1, 81000, 0xba53528e -0, 90, 90, 1, 81000, 0xc847de49 +0, 82, 82, 1, 81000, 0x55b05da7 +0, 83, 83, 1, 81000, 0x7f78a42c +0, 84, 84, 1, 81000, 0x5139b79c +0, 85, 85, 1, 81000, 0x4054437d +0, 86, 86, 1, 81000, 0x0f9dd327 +0, 87, 87, 1, 81000, 0xa885c60e +0, 88, 88, 1, 81000, 0x37abaa72 +0, 89, 89, 1, 81000, 0xdab25345 +0, 90, 90, 1, 81000, 0xbdf4df9d 0, 91, 91, 1, 81000, 0xc5b2e2b0 0, 92, 92, 1, 81000, 0xb0b497ff diff --git a/tests/ref/fate/vp6f b/tests/ref/fate/vp6f index 65e113174..c76e077cb 100644 --- a/tests/ref/fate/vp6f +++ b/tests/ref/fate/vp6f @@ -4,176 +4,176 @@ #dimensions 0: 112x80 #sar 0: 0/1 0, 0, 0, 1, 13440, 0x7cb0a22f -0, 1, 1, 1, 13440, 0xdfcea6ba -0, 2, 2, 1, 13440, 0x59b2a5da -0, 3, 3, 1, 13440, 0x12f1b2d8 -0, 4, 4, 1, 13440, 0x280fb9f6 -0, 5, 5, 1, 13440, 0x7bace8b3 -0, 6, 6, 1, 13440, 0x4ec91480 -0, 7, 7, 1, 13440, 0xa8010450 -0, 8, 8, 1, 13440, 0x61d8fc46 -0, 9, 9, 1, 13440, 0x242bb24e -0, 10, 10, 1, 13440, 0x88397a36 -0, 11, 11, 1, 13440, 0x10e15726 -0, 12, 12, 1, 13440, 0x3018438c -0, 13, 13, 1, 13440, 0xbbb94c21 -0, 14, 14, 1, 13440, 0xfc3e5e2b -0, 15, 15, 1, 13440, 0xeaa69354 -0, 16, 16, 1, 13440, 0x96f1cc01 -0, 17, 17, 1, 13440, 0x333fdaff -0, 18, 18, 1, 13440, 0xb5230ed2 -0, 19, 19, 1, 13440, 0x59383446 -0, 20, 20, 1, 13440, 0x954939e6 -0, 21, 21, 1, 13440, 0x53813d2f -0, 22, 22, 1, 13440, 0x3ca53600 -0, 23, 23, 1, 13440, 0x7b30227a -0, 24, 24, 1, 13440, 0x5145bbfe -0, 25, 25, 1, 13440, 0xa0979632 -0, 26, 26, 1, 13440, 0x08026e21 -0, 27, 27, 1, 13440, 0x3f456d1e -0, 28, 28, 1, 13440, 0x7d036b62 -0, 29, 29, 1, 13440, 0x508085fb -0, 30, 30, 1, 13440, 0x251dc193 -0, 31, 31, 1, 13440, 0xf3121c9b -0, 32, 32, 1, 13440, 0xf5da772e -0, 33, 33, 1, 13440, 0x8179ccf7 -0, 34, 34, 1, 13440, 0xd57ceeb3 -0, 35, 35, 1, 13440, 0xc8f2169c -0, 36, 36, 1, 13440, 0xbf8296c3 -0, 37, 37, 1, 13440, 0xee1927d0 -0, 38, 38, 1, 13440, 0xdd84e8d1 -0, 39, 39, 1, 13440, 0x7be57be2 -0, 40, 40, 1, 13440, 0xae353f91 -0, 41, 41, 1, 13440, 0x3ae927f2 -0, 42, 42, 1, 13440, 0x417227c6 -0, 43, 43, 1, 13440, 0x32572bea -0, 44, 44, 1, 13440, 0x8b9e4839 -0, 45, 45, 1, 13440, 0xad669441 -0, 46, 46, 1, 13440, 0xc9de99a6 -0, 47, 47, 1, 13440, 0xb3ffb88b -0, 48, 48, 1, 13440, 0xb321b8a0 -0, 49, 49, 1, 13440, 0x2efdbf53 -0, 50, 50, 1, 13440, 0x9b7aa566 -0, 51, 51, 1, 13440, 0x563c8d60 -0, 52, 52, 1, 13440, 0xe3848ee8 -0, 53, 53, 1, 13440, 0xa84b8f1d -0, 54, 54, 1, 13440, 0x52da9f9f -0, 55, 55, 1, 13440, 0x2ed56d97 -0, 56, 56, 1, 13440, 0x4e8534c2 -0, 57, 57, 1, 13440, 0x318900a6 -0, 58, 58, 1, 13440, 0xda96de39 -0, 59, 59, 1, 13440, 0xaae7ac0b +0, 1, 1, 1, 13440, 0xe38fa6b7 +0, 2, 2, 1, 13440, 0xe003a5c6 +0, 3, 3, 1, 13440, 0xe502b2f6 +0, 4, 4, 1, 13440, 0xb731ba56 +0, 5, 5, 1, 13440, 0x8168e8f5 +0, 6, 6, 1, 13440, 0x776d14fb +0, 7, 7, 1, 13440, 0xb5d0049c +0, 8, 8, 1, 13440, 0x3434fc98 +0, 9, 9, 1, 13440, 0xd219b282 +0, 10, 10, 1, 13440, 0xd2027a7c +0, 11, 11, 1, 13440, 0xd50b5799 +0, 12, 12, 1, 13440, 0x091543c4 +0, 13, 13, 1, 13440, 0x26374c6b +0, 14, 14, 1, 13440, 0x5b4f5e1e +0, 15, 15, 1, 13440, 0x55ba92da +0, 16, 16, 1, 13440, 0x1ff5cb4d +0, 17, 17, 1, 13440, 0x0ccbda45 +0, 18, 18, 1, 13440, 0x5ff80e6a +0, 19, 19, 1, 13440, 0x09df3417 +0, 20, 20, 1, 13440, 0xfbed3a0f +0, 21, 21, 1, 13440, 0xd65c3c7f +0, 22, 22, 1, 13440, 0xc8173576 +0, 23, 23, 1, 13440, 0xd5e521f8 +0, 24, 24, 1, 13440, 0xe440bb55 +0, 25, 25, 1, 13440, 0xcbeb95c8 +0, 26, 26, 1, 13440, 0x8cd66dba +0, 27, 27, 1, 13440, 0x5f356cbc +0, 28, 28, 1, 13440, 0x54e16ad7 +0, 29, 29, 1, 13440, 0x17ed8566 +0, 30, 30, 1, 13440, 0x1aa1c121 +0, 31, 31, 1, 13440, 0x64e31cac +0, 32, 32, 1, 13440, 0x869677a4 +0, 33, 33, 1, 13440, 0x7df6cdba +0, 34, 34, 1, 13440, 0x23f3ef45 +0, 35, 35, 1, 13440, 0x176217b4 +0, 36, 36, 1, 13440, 0x493897cb +0, 37, 37, 1, 13440, 0x0591296d +0, 38, 38, 1, 13440, 0xb58aeae8 +0, 39, 39, 1, 13440, 0x38fd7e58 +0, 40, 40, 1, 13440, 0x200c424c +0, 41, 41, 1, 13440, 0x2ee42b14 +0, 42, 42, 1, 13440, 0xdcba2ae5 +0, 43, 43, 1, 13440, 0xbb102f41 +0, 44, 44, 1, 13440, 0x034d4b06 +0, 45, 45, 1, 13440, 0x62d99722 +0, 46, 46, 1, 13440, 0x174d9ce4 +0, 47, 47, 1, 13440, 0xf676bbc8 +0, 48, 48, 1, 13440, 0xe2e5bbef +0, 49, 49, 1, 13440, 0x6ef0c2af +0, 50, 50, 1, 13440, 0x8d08a917 +0, 51, 51, 1, 13440, 0x030d90e8 +0, 52, 52, 1, 13440, 0x4d6f9232 +0, 53, 53, 1, 13440, 0xb7a792f6 +0, 54, 54, 1, 13440, 0xa0daa330 +0, 55, 55, 1, 13440, 0xe9f870a3 +0, 56, 56, 1, 13440, 0xed4f36cb +0, 57, 57, 1, 13440, 0x8a6f02c3 +0, 58, 58, 1, 13440, 0x663ee03d +0, 59, 59, 1, 13440, 0x2571adef 0, 60, 60, 1, 13440, 0x7533ad99 -0, 61, 61, 1, 13440, 0x4e70c2c9 -0, 62, 62, 1, 13440, 0x9ce5e3fa -0, 63, 63, 1, 13440, 0xc788fbbc -0, 64, 64, 1, 13440, 0xd36604a9 -0, 65, 65, 1, 13440, 0x246221a4 -0, 66, 66, 1, 13440, 0x290c5c2b -0, 67, 67, 1, 13440, 0xde6c68ec -0, 68, 68, 1, 13440, 0x56248dbf -0, 69, 69, 1, 13440, 0x5b898cbd -0, 70, 70, 1, 13440, 0x090574b9 -0, 71, 71, 1, 13440, 0x8df2814a -0, 72, 72, 1, 13440, 0xd4a6b285 -0, 73, 73, 1, 13440, 0xa016e921 -0, 74, 74, 1, 13440, 0x7f93fdc1 -0, 75, 75, 1, 13440, 0xfd0dee6f -0, 76, 76, 1, 13440, 0xef04ce0e -0, 77, 77, 1, 13440, 0x7560bee3 -0, 78, 78, 1, 13440, 0x5a8cdc85 -0, 79, 79, 1, 13440, 0x4788f7bc -0, 80, 80, 1, 13440, 0xc001e34d -0, 81, 81, 1, 13440, 0xc687eb74 -0, 82, 82, 1, 13440, 0xbf20feba -0, 83, 83, 1, 13440, 0xd32647a8 -0, 84, 84, 1, 13440, 0xe69a955a -0, 85, 85, 1, 13440, 0x1b56951f -0, 86, 86, 1, 13440, 0xd1977378 -0, 87, 87, 1, 13440, 0x1620357d -0, 88, 88, 1, 13440, 0x2596116f -0, 89, 89, 1, 13440, 0x7473feca -0, 90, 90, 1, 13440, 0x7f92bb47 -0, 91, 91, 1, 13440, 0x6866a683 -0, 92, 92, 1, 13440, 0xe9b08d7e -0, 93, 93, 1, 13440, 0xa3fd7546 -0, 94, 94, 1, 13440, 0xa4416522 -0, 95, 95, 1, 13440, 0xd8f5572e -0, 96, 96, 1, 13440, 0xf5746dbd -0, 97, 97, 1, 13440, 0x256a87c6 -0, 98, 98, 1, 13440, 0x722aa2c8 -0, 99, 99, 1, 13440, 0xb26de5f5 -0, 100, 100, 1, 13440, 0x117f0841 -0, 101, 101, 1, 13440, 0xda2d192c -0, 102, 102, 1, 13440, 0xb022442d -0, 103, 103, 1, 13440, 0xbc4044f2 -0, 104, 104, 1, 13440, 0x68b330da -0, 105, 105, 1, 13440, 0xc07228cf -0, 106, 106, 1, 13440, 0xaa3f3d44 -0, 107, 107, 1, 13440, 0x25867aad -0, 108, 108, 1, 13440, 0xa3ecb432 -0, 109, 109, 1, 13440, 0x93ccdcbb -0, 110, 110, 1, 13440, 0x8302fa4f -0, 111, 111, 1, 13440, 0x2f960f33 -0, 112, 112, 1, 13440, 0x15d41d14 -0, 113, 113, 1, 13440, 0x636529d0 -0, 114, 114, 1, 13440, 0x11035be5 -0, 115, 115, 1, 13440, 0x9b6e9167 -0, 116, 116, 1, 13440, 0x7b01adc7 +0, 61, 61, 1, 13440, 0xe3aec2d4 +0, 62, 62, 1, 13440, 0x3368e416 +0, 63, 63, 1, 13440, 0xe2ecfbf5 +0, 64, 64, 1, 13440, 0x45010538 +0, 65, 65, 1, 13440, 0xc075222c +0, 66, 66, 1, 13440, 0x5bf45cc4 +0, 67, 67, 1, 13440, 0xa06869b5 +0, 68, 68, 1, 13440, 0x1ff98e6f +0, 69, 69, 1, 13440, 0x11c88d84 +0, 70, 70, 1, 13440, 0x95c275e8 +0, 71, 71, 1, 13440, 0x81a68285 +0, 72, 72, 1, 13440, 0xb903b402 +0, 73, 73, 1, 13440, 0xa9d2eb1c +0, 74, 74, 1, 13440, 0x2c48ff65 +0, 75, 75, 1, 13440, 0xc024eff6 +0, 76, 76, 1, 13440, 0x41bacff0 +0, 77, 77, 1, 13440, 0x2cf9c144 +0, 78, 78, 1, 13440, 0x9e67de72 +0, 79, 79, 1, 13440, 0x3e74fa36 +0, 80, 80, 1, 13440, 0x9b9be609 +0, 81, 81, 1, 13440, 0x594eee16 +0, 82, 82, 1, 13440, 0x8a7c00d7 +0, 83, 83, 1, 13440, 0x56104a2a +0, 84, 84, 1, 13440, 0xd94d97cc +0, 85, 85, 1, 13440, 0x95d09887 +0, 86, 86, 1, 13440, 0xe02a769b +0, 87, 87, 1, 13440, 0x847839d0 +0, 88, 88, 1, 13440, 0x47441606 +0, 89, 89, 1, 13440, 0x19b10373 +0, 90, 90, 1, 13440, 0x3ddfbf15 +0, 91, 91, 1, 13440, 0xf4fdab37 +0, 92, 92, 1, 13440, 0xfe9a92ad +0, 93, 93, 1, 13440, 0xaa387bfb +0, 94, 94, 1, 13440, 0xe57a6c85 +0, 95, 95, 1, 13440, 0x68ef5f30 +0, 96, 96, 1, 13440, 0x481d76f7 +0, 97, 97, 1, 13440, 0x5b0e9192 +0, 98, 98, 1, 13440, 0xebc1ac80 +0, 99, 99, 1, 13440, 0x13bfef3e +0, 100, 100, 1, 13440, 0xb7b01291 +0, 101, 101, 1, 13440, 0xc8c72419 +0, 102, 102, 1, 13440, 0x9dca4f32 +0, 103, 103, 1, 13440, 0x67635158 +0, 104, 104, 1, 13440, 0x6c773e0d +0, 105, 105, 1, 13440, 0x6c2f3777 +0, 106, 106, 1, 13440, 0x19574d97 +0, 107, 107, 1, 13440, 0xd9f48cc1 +0, 108, 108, 1, 13440, 0xd19dc87c +0, 109, 109, 1, 13440, 0xa23cf2ab +0, 110, 110, 1, 13440, 0x3f7611b6 +0, 111, 111, 1, 13440, 0x183d2723 +0, 112, 112, 1, 13440, 0xf79b3534 +0, 113, 113, 1, 13440, 0xcbba4280 +0, 114, 114, 1, 13440, 0x03777586 +0, 115, 115, 1, 13440, 0xea1aac72 +0, 116, 116, 1, 13440, 0xad27cae0 0, 117, 117, 1, 13440, 0xa237e05d -0, 118, 118, 1, 13440, 0xd2f4f134 -0, 119, 119, 1, 13440, 0x2052d368 -0, 120, 120, 1, 13440, 0x08f7ae0d -0, 121, 121, 1, 13440, 0xa89185bc -0, 122, 122, 1, 13440, 0xfa628236 -0, 123, 123, 1, 13440, 0xdf79848b -0, 124, 124, 1, 13440, 0xd19a906f -0, 125, 125, 1, 13440, 0x219f9324 -0, 126, 126, 1, 13440, 0x46509b6d -0, 127, 127, 1, 13440, 0xc5d9a568 -0, 128, 128, 1, 13440, 0xb21aaaa8 -0, 129, 129, 1, 13440, 0x925a97ed -0, 130, 130, 1, 13440, 0xc5e3557f -0, 131, 131, 1, 13440, 0x7c57155a -0, 132, 132, 1, 13440, 0x6b26d005 -0, 133, 133, 1, 13440, 0xfdc7b369 -0, 134, 134, 1, 13440, 0x99919fc2 -0, 135, 135, 1, 13440, 0xcfe889e4 -0, 136, 136, 1, 13440, 0xd1196856 -0, 137, 137, 1, 13440, 0xec8348c6 -0, 138, 138, 1, 13440, 0x5ede0d9a -0, 139, 139, 1, 13440, 0x198ef66e -0, 140, 140, 1, 13440, 0x62fcefdf -0, 141, 141, 1, 13440, 0x7791f415 -0, 142, 142, 1, 13440, 0xfbdb0029 -0, 143, 143, 1, 13440, 0xdab12b01 -0, 144, 144, 1, 13440, 0x646b2d5f -0, 145, 145, 1, 13440, 0x5410f52e -0, 146, 146, 1, 13440, 0x7186eef8 -0, 147, 147, 1, 13440, 0xca251ef6 -0, 148, 148, 1, 13440, 0x757c3b43 -0, 149, 149, 1, 13440, 0x59ff4982 -0, 150, 150, 1, 13440, 0xbe8ff084 -0, 151, 151, 1, 13440, 0xc85a9e38 -0, 152, 152, 1, 13440, 0x541b9a19 -0, 153, 153, 1, 13440, 0x274893c9 -0, 154, 154, 1, 13440, 0x7634b5d2 -0, 155, 155, 1, 13440, 0x1bd8e10c -0, 156, 156, 1, 13440, 0xa661dfb1 -0, 157, 157, 1, 13440, 0x9d01bf92 -0, 158, 158, 1, 13440, 0xcb1eb220 -0, 159, 159, 1, 13440, 0x0ce27d25 -0, 160, 160, 1, 13440, 0x523b594f -0, 161, 161, 1, 13440, 0xf0a04c4f -0, 162, 162, 1, 13440, 0x0f0ffc3d -0, 163, 163, 1, 13440, 0xb0d8b778 -0, 164, 164, 1, 13440, 0x5137a642 -0, 165, 165, 1, 13440, 0xd213a552 -0, 166, 166, 1, 13440, 0xc2fbc9b1 -0, 167, 167, 1, 13440, 0xfc2ee379 -0, 168, 168, 1, 13440, 0xfb80f737 -0, 169, 169, 1, 13440, 0xd6cb2447 -0, 170, 170, 1, 13440, 0x124b606d -0, 171, 171, 1, 13440, 0xf788a066 -0, 172, 172, 1, 13440, 0xa16eed6e -0, 173, 173, 1, 13440, 0x73ff0f82 +0, 118, 118, 1, 13440, 0xb683f189 +0, 119, 119, 1, 13440, 0x2058d3cd +0, 120, 120, 1, 13440, 0x715dae96 +0, 121, 121, 1, 13440, 0xd8f88677 +0, 122, 122, 1, 13440, 0x45818329 +0, 123, 123, 1, 13440, 0x69ad852f +0, 124, 124, 1, 13440, 0x56369125 +0, 125, 125, 1, 13440, 0xdfde941b +0, 126, 126, 1, 13440, 0xf1209c90 +0, 127, 127, 1, 13440, 0x82e6a6aa +0, 128, 128, 1, 13440, 0xb0ceabd1 +0, 129, 129, 1, 13440, 0x05f899a6 +0, 130, 130, 1, 13440, 0x9ef95758 +0, 131, 131, 1, 13440, 0x63e716d9 +0, 132, 132, 1, 13440, 0x7cb0d149 +0, 133, 133, 1, 13440, 0x3585b4f1 +0, 134, 134, 1, 13440, 0x623ea1fc +0, 135, 135, 1, 13440, 0x762b8c32 +0, 136, 136, 1, 13440, 0xc1b96add +0, 137, 137, 1, 13440, 0x95e24baf +0, 138, 138, 1, 13440, 0x74631106 +0, 139, 139, 1, 13440, 0x78b5fa14 +0, 140, 140, 1, 13440, 0x5f33f34a +0, 141, 141, 1, 13440, 0x7e6ff799 +0, 142, 142, 1, 13440, 0x9f8303b0 +0, 143, 143, 1, 13440, 0x7c3d2eb9 +0, 144, 144, 1, 13440, 0x3c0530d2 +0, 145, 145, 1, 13440, 0xe7ecf960 +0, 146, 146, 1, 13440, 0x82c3f316 +0, 147, 147, 1, 13440, 0x008922b4 +0, 148, 148, 1, 13440, 0x0d263f5f +0, 149, 149, 1, 13440, 0x57dc4dd0 +0, 150, 150, 1, 13440, 0xbcbbf4f1 +0, 151, 151, 1, 13440, 0x62e9a335 +0, 152, 152, 1, 13440, 0x65699f37 +0, 153, 153, 1, 13440, 0xe4b69939 +0, 154, 154, 1, 13440, 0xbd4ebb6c +0, 155, 155, 1, 13440, 0xb7d6e71e +0, 156, 156, 1, 13440, 0xfc0ae5b6 +0, 157, 157, 1, 13440, 0xe55ec65c +0, 158, 158, 1, 13440, 0x2095b8fc +0, 159, 159, 1, 13440, 0x479c8408 +0, 160, 160, 1, 13440, 0x2981604c +0, 161, 161, 1, 13440, 0xa4e55397 +0, 162, 162, 1, 13440, 0x0bc703f8 +0, 163, 163, 1, 13440, 0xd43bbf89 +0, 164, 164, 1, 13440, 0xdcd6aeca +0, 165, 165, 1, 13440, 0x07b1ad84 +0, 166, 166, 1, 13440, 0xfb17d20b +0, 167, 167, 1, 13440, 0x0c4aebd9 +0, 168, 168, 1, 13440, 0x826effc4 +0, 169, 169, 1, 13440, 0x4ccf2ca4 +0, 170, 170, 1, 13440, 0xe4f968f3 +0, 171, 171, 1, 13440, 0xe1b4a93a +0, 172, 172, 1, 13440, 0x8597f65e +0, 173, 173, 1, 13440, 0xb4f7184f diff --git a/tests/ref/lavf-fate/cram.avi b/tests/ref/lavf-fate/cram.avi new file mode 100644 index 000000000..a591889f0 --- /dev/null +++ b/tests/ref/lavf-fate/cram.avi @@ -0,0 +1,3 @@ +6fc88702c23b895c305c5e1f51a0904e *tests/data/lavf-fate/lavf.cram.avi +928260 tests/data/lavf-fate/lavf.cram.avi +tests/data/lavf-fate/lavf.cram.avi CRC=0xa4770de2 diff --git a/tests/ref/lavf-fate/latm b/tests/ref/lavf-fate/latm index 8c4f5412a..c41384df9 100644 --- a/tests/ref/lavf-fate/latm +++ b/tests/ref/lavf-fate/latm @@ -1,3 +1,3 @@ -eb13788e71c9b5bc7d62ceb748312bbb *./tests/data/lavf-fate/lavf.latm -67876 ./tests/data/lavf-fate/lavf.latm -./tests/data/lavf-fate/lavf.latm CRC=0xcf94c59d +eb13788e71c9b5bc7d62ceb748312bbb *tests/data/lavf-fate/lavf.latm +67876 tests/data/lavf-fate/lavf.latm +tests/data/lavf-fate/lavf.latm CRC=0xcf94c59d diff --git a/tests/ref/lavf-fate/mp3 b/tests/ref/lavf-fate/mp3 index b5595387a..bd65cbb24 100644 --- a/tests/ref/lavf-fate/mp3 +++ b/tests/ref/lavf-fate/mp3 @@ -1,3 +1,3 @@ -f231c5316357fd747573cbcb02f889c5 *./tests/data/lavf-fate/lavf.mp3 -96016 ./tests/data/lavf-fate/lavf.mp3 -./tests/data/lavf-fate/lavf.mp3 CRC=0x6c9850fe +f231c5316357fd747573cbcb02f889c5 *tests/data/lavf-fate/lavf.mp3 +96016 tests/data/lavf-fate/lavf.mp3 +tests/data/lavf-fate/lavf.mp3 CRC=0x6c9850fe diff --git a/tests/ref/lavf-fate/qtrle_mace6.mov b/tests/ref/lavf-fate/qtrle_mace6.mov new file mode 100644 index 000000000..85c585fe3 --- /dev/null +++ b/tests/ref/lavf-fate/qtrle_mace6.mov @@ -0,0 +1,3 @@ +f0ae34fb90e11342624e092094273aef *tests/data/lavf-fate/lavf.qtrle_mace6.mov +1270415 tests/data/lavf-fate/lavf.qtrle_mace6.mov +tests/data/lavf-fate/lavf.qtrle_mace6.mov CRC=0x9320cd26 diff --git a/tests/ref/lavf-fate/vp3.ogg b/tests/ref/lavf-fate/vp3.ogg new file mode 100644 index 000000000..f4e22dc16 --- /dev/null +++ b/tests/ref/lavf-fate/vp3.ogg @@ -0,0 +1,3 @@ +4bd51dac3194fa88ae33767c25b4b1e6 *tests/data/lavf-fate/lavf.vp3.ogg +417621 tests/data/lavf-fate/lavf.vp3.ogg +tests/data/lavf-fate/lavf.vp3.ogg CRC=0x037e3e79 diff --git a/tests/ref/lavf-fate/vp8.ogg b/tests/ref/lavf-fate/vp8.ogg new file mode 100644 index 000000000..1a4082556 --- /dev/null +++ b/tests/ref/lavf-fate/vp8.ogg @@ -0,0 +1,3 @@ +c56d8dce728d46d4f0ab4c7cc9f86abc *tests/data/lavf-fate/lavf.vp8.ogg +95009 tests/data/lavf-fate/lavf.vp8.ogg +tests/data/lavf-fate/lavf.vp8.ogg CRC=0x8c067a66 diff --git a/tests/ref/lavf/aiff b/tests/ref/lavf/aiff index c504c18c4..d72ec8515 100644 --- a/tests/ref/lavf/aiff +++ b/tests/ref/lavf/aiff @@ -1,3 +1,3 @@ -2c129d88acef834e32869145fe792b9c *./tests/data/lavf/lavf.aif -88270 ./tests/data/lavf/lavf.aif -./tests/data/lavf/lavf.aif CRC=0x3a1da17e +2c129d88acef834e32869145fe792b9c *tests/data/lavf/lavf.aiff +88270 tests/data/lavf/lavf.aiff +tests/data/lavf/lavf.aiff CRC=0x3a1da17e diff --git a/tests/ref/lavf/al b/tests/ref/lavf/al new file mode 100644 index 000000000..c383c3628 --- /dev/null +++ b/tests/ref/lavf/al @@ -0,0 +1,3 @@ +652d96e474869ddb01403743deb35117 *tests/data/lavf/lavf.al +44100 tests/data/lavf/lavf.al +tests/data/lavf/lavf.al CRC=0xf9643112 diff --git a/tests/ref/lavf/apng b/tests/ref/lavf/apng index 8e9e5e6b7..95f1fbee6 100644 --- a/tests/ref/lavf/apng +++ b/tests/ref/lavf/apng @@ -1,9 +1,3 @@ -a4c46fad7716ad094eb3c78b74ca0244 *./tests/data/lavf/lavf.apng -6209864 ./tests/data/lavf/lavf.apng -./tests/data/lavf/lavf.apng CRC=0x87b3c15f -a4c46fad7716ad094eb3c78b74ca0244 *./tests/data/lavf/lavf.copy.apng -6209864 ./tests/data/lavf/lavf.copy.apng -./tests/data/lavf/lavf.copy.apng CRC=0x87b3c15f -c5900fdd1b2fc30b985793f5226fd0c4 *./tests/data/lavf/lavf.png -248854 ./tests/data/lavf/lavf.png -./tests/data/lavf/lavf.png CRC=0xd8c7b7a1 +a4c46fad7716ad094eb3c78b74ca0244 *tests/data/lavf/lavf.apng +6209864 tests/data/lavf/lavf.apng +tests/data/lavf/lavf.apng CRC=0x87b3c15f diff --git a/tests/ref/lavf/apng.png b/tests/ref/lavf/apng.png new file mode 100644 index 000000000..b42f5a8db --- /dev/null +++ b/tests/ref/lavf/apng.png @@ -0,0 +1,3 @@ +c5900fdd1b2fc30b985793f5226fd0c4 *tests/data/lavf/lavf.apng.png +248854 tests/data/lavf/lavf.apng.png +tests/data/lavf/lavf.apng.png CRC=0xd8c7b7a1 diff --git a/tests/ref/lavf/asf b/tests/ref/lavf/asf index 911af7205..fbcbd480d 100644 --- a/tests/ref/lavf/asf +++ b/tests/ref/lavf/asf @@ -1,3 +1,3 @@ -76f131a5426f0ba5fc7409d1a1bbfdd7 *./tests/data/lavf/lavf.asf -333585 ./tests/data/lavf/lavf.asf -./tests/data/lavf/lavf.asf CRC=0xf6340a10 +76f131a5426f0ba5fc7409d1a1bbfdd7 *tests/data/lavf/lavf.asf +333585 tests/data/lavf/lavf.asf +tests/data/lavf/lavf.asf CRC=0xf6340a10 diff --git a/tests/ref/lavf/ast b/tests/ref/lavf/ast index 513c612e7..2f2e8de46 100644 --- a/tests/ref/lavf/ast +++ b/tests/ref/lavf/ast @@ -1,3 +1,3 @@ -07f5d23aa8bade984034f7005bd72947 *./tests/data/lavf/lavf.ast -177872 ./tests/data/lavf/lavf.ast -./tests/data/lavf/lavf.ast CRC=0xe61e3bd0 +07f5d23aa8bade984034f7005bd72947 *tests/data/lavf/lavf.ast +177872 tests/data/lavf/lavf.ast +tests/data/lavf/lavf.ast CRC=0xe61e3bd0 diff --git a/tests/ref/lavf/au b/tests/ref/lavf/au index dcd02f335..4abedf309 100644 --- a/tests/ref/lavf/au +++ b/tests/ref/lavf/au @@ -1,3 +1,3 @@ -5228ad3783888c45a08dac5ab6118794 *./tests/data/lavf/lavf.au -88240 ./tests/data/lavf/lavf.au -./tests/data/lavf/lavf.au CRC=0x3a1da17e +5228ad3783888c45a08dac5ab6118794 *tests/data/lavf/lavf.au +88240 tests/data/lavf/lavf.au +tests/data/lavf/lavf.au CRC=0x3a1da17e diff --git a/tests/ref/lavf/avi b/tests/ref/lavf/avi index dfdb392de..b8c2f7a38 100644 --- a/tests/ref/lavf/avi +++ b/tests/ref/lavf/avi @@ -1,3 +1,3 @@ -ab696052289d8dfea193e4cf94a94a6f *./tests/data/lavf/lavf.avi -330814 ./tests/data/lavf/lavf.avi -./tests/data/lavf/lavf.avi CRC=0xec6c3c68 +ab696052289d8dfea193e4cf94a94a6f *tests/data/lavf/lavf.avi +330814 tests/data/lavf/lavf.avi +tests/data/lavf/lavf.avi CRC=0xec6c3c68 diff --git a/tests/ref/lavf/bmp b/tests/ref/lavf/bmp index 8958855ee..af767e552 100644 --- a/tests/ref/lavf/bmp +++ b/tests/ref/lavf/bmp @@ -1,3 +1,3 @@ -71f4d64a6b3c71f43a4eff526f84841c *./tests/data/images/bmp/02.bmp -./tests/data/images/bmp/%02d.bmp CRC=0xe6c71946 -304182 ./tests/data/images/bmp/02.bmp +71f4d64a6b3c71f43a4eff526f84841c *tests/data/images/bmp/02.bmp +tests/data/images/bmp/%02d.bmp CRC=0xe6c71946 +304182 tests/data/images/bmp/02.bmp diff --git a/tests/ref/lavf/caf b/tests/ref/lavf/caf index 7b2a67d1c..8488f3fee 100644 --- a/tests/ref/lavf/caf +++ b/tests/ref/lavf/caf @@ -1,3 +1,3 @@ -c3c38cba600722c87c0e75bd0688b7fc *./tests/data/lavf/lavf.caf -88323 ./tests/data/lavf/lavf.caf -./tests/data/lavf/lavf.caf CRC=0x3a1da17e +c3c38cba600722c87c0e75bd0688b7fc *tests/data/lavf/lavf.caf +88323 tests/data/lavf/lavf.caf +tests/data/lavf/lavf.caf CRC=0x3a1da17e diff --git a/tests/ref/lavf/dpx b/tests/ref/lavf/dpx index 7bbed3e8c..68fe25afc 100644 --- a/tests/ref/lavf/dpx +++ b/tests/ref/lavf/dpx @@ -1,18 +1,3 @@ -4c8880d5835ffb5fe37c1ed8c8d404de *./tests/data/images/dpx/02.dpx -./tests/data/images/dpx/%02d.dpx CRC=0x6da01946 -305792 ./tests/data/images/dpx/02.dpx -7ca935d5d5e00c54acbc85565d3039b6 *./tests/data/images/dpx/02.dpx -./tests/data/images/dpx/%02d.dpx CRC=0xe6663fba -407168 ./tests/data/images/dpx/02.dpx -a4cfea1797c928f2eff73573e559675d *./tests/data/images/dpx/02.dpx -./tests/data/images/dpx/%02d.dpx CRC=0x1c755633 -609920 ./tests/data/images/dpx/02.dpx -075963c3c08978b6a20555ba09161434 *./tests/data/images/dpx/02.dpx -./tests/data/images/dpx/%02d.dpx CRC=0xe5b9c023 -609920 ./tests/data/images/dpx/02.dpx -b9f22728f8ff393bf30cf6cbd624fa95 *./tests/data/images/dpx/02.dpx -./tests/data/images/dpx/%02d.dpx CRC=0xf38d5830 -407168 ./tests/data/images/dpx/02.dpx -545603630f30dec2768c8ae8d12eb8ea *./tests/data/images/dpx/02.dpx -./tests/data/images/dpx/%02d.dpx CRC=0xe72ce131 -812672 ./tests/data/images/dpx/02.dpx +4c8880d5835ffb5fe37c1ed8c8d404de *tests/data/images/dpx/02.dpx +tests/data/images/dpx/%02d.dpx CRC=0x6da01946 +305792 tests/data/images/dpx/02.dpx diff --git a/tests/ref/lavf/dv b/tests/ref/lavf/dv new file mode 100644 index 000000000..7ae4223a2 --- /dev/null +++ b/tests/ref/lavf/dv @@ -0,0 +1,3 @@ +2fb332aab8f2ba9c33b1b2368194392a *tests/data/lavf/lavf.dv +3600000 tests/data/lavf/lavf.dv +tests/data/lavf/lavf.dv CRC=0xbdaf7f52 diff --git a/tests/ref/lavf/dv_ntsc b/tests/ref/lavf/dv_ntsc new file mode 100644 index 000000000..410b6ec25 --- /dev/null +++ b/tests/ref/lavf/dv_ntsc @@ -0,0 +1,3 @@ +5569626370c7c72d40de2c4559e32856 *tests/data/lavf/lavf.dv_ntsc +3480000 tests/data/lavf/lavf.dv_ntsc +tests/data/lavf/lavf.dv_ntsc CRC=0xa0088163 diff --git a/tests/ref/lavf/dv_pal b/tests/ref/lavf/dv_pal new file mode 100644 index 000000000..93bb728c4 --- /dev/null +++ b/tests/ref/lavf/dv_pal @@ -0,0 +1,3 @@ +7830f9c6716ceb6011f865f1e521b951 *tests/data/lavf/lavf.dv_pal +3600000 tests/data/lavf/lavf.dv_pal +tests/data/lavf/lavf.dv_pal CRC=0xd428d3ee diff --git a/tests/ref/lavf/flm b/tests/ref/lavf/flm index 59aac922a..15ca5ff45 100644 --- a/tests/ref/lavf/flm +++ b/tests/ref/lavf/flm @@ -1,3 +1,3 @@ -ef4783171ebbc38855331c9ead978322 *./tests/data/lavf/lavf.flm -10137636 ./tests/data/lavf/lavf.flm -./tests/data/lavf/lavf.flm CRC=0xcdf15757 +ef4783171ebbc38855331c9ead978322 *tests/data/lavf/lavf.flm +10137636 tests/data/lavf/lavf.flm +tests/data/lavf/lavf.flm CRC=0xcdf15757 diff --git a/tests/ref/lavf/flv b/tests/ref/lavf/flv new file mode 100644 index 000000000..315347265 --- /dev/null +++ b/tests/ref/lavf/flv @@ -0,0 +1,3 @@ +0d229f87b3aad778074ace499359d137 *tests/data/lavf/lavf.flv +329554 tests/data/lavf/lavf.flv +tests/data/lavf/lavf.flv CRC=0x4eac88c5 diff --git a/tests/ref/lavf/gbrap.fits b/tests/ref/lavf/gbrap.fits new file mode 100644 index 000000000..57c71e179 --- /dev/null +++ b/tests/ref/lavf/gbrap.fits @@ -0,0 +1,3 @@ +28eb102547b82acca57ef097a6c639d8 *tests/data/lavf/lavf.gbrap.fits +10224000 tests/data/lavf/lavf.gbrap.fits +tests/data/lavf/lavf.gbrap.fits CRC=0x883af247 diff --git a/tests/ref/lavf/gbrap16be.fits b/tests/ref/lavf/gbrap16be.fits new file mode 100644 index 000000000..030a6d90e --- /dev/null +++ b/tests/ref/lavf/gbrap16be.fits @@ -0,0 +1,3 @@ +ff5fb24a67aeabd4f56088ca8b03d8b0 *tests/data/lavf/lavf.gbrap16be.fits +20376000 tests/data/lavf/lavf.gbrap16be.fits +tests/data/lavf/lavf.gbrap16be.fits CRC=0xa981271b diff --git a/tests/ref/lavf/gbrp.fits b/tests/ref/lavf/gbrp.fits new file mode 100644 index 000000000..2b60ddb33 --- /dev/null +++ b/tests/ref/lavf/gbrp.fits @@ -0,0 +1,3 @@ +dae49b5f6eb58981ba91e3e108355717 *tests/data/lavf/lavf.gbrp.fits +7704000 tests/data/lavf/lavf.gbrp.fits +tests/data/lavf/lavf.gbrp.fits CRC=0x80745c5e diff --git a/tests/ref/lavf/gbrp10le.dpx b/tests/ref/lavf/gbrp10le.dpx new file mode 100644 index 000000000..b33da34e2 --- /dev/null +++ b/tests/ref/lavf/gbrp10le.dpx @@ -0,0 +1,3 @@ +7ca935d5d5e00c54acbc85565d3039b6 *tests/data/images/gbrp10le.dpx/02.gbrp10le.dpx +tests/data/images/gbrp10le.dpx/%02d.gbrp10le.dpx CRC=0xe6663fba +407168 tests/data/images/gbrp10le.dpx/02.gbrp10le.dpx diff --git a/tests/ref/lavf/gbrp12le.dpx b/tests/ref/lavf/gbrp12le.dpx new file mode 100644 index 000000000..e2e794ecc --- /dev/null +++ b/tests/ref/lavf/gbrp12le.dpx @@ -0,0 +1,3 @@ +a4cfea1797c928f2eff73573e559675d *tests/data/images/gbrp12le.dpx/02.gbrp12le.dpx +tests/data/images/gbrp12le.dpx/%02d.gbrp12le.dpx CRC=0x1c755633 +609920 tests/data/images/gbrp12le.dpx/02.gbrp12le.dpx diff --git a/tests/ref/lavf/gbrp16be.fits b/tests/ref/lavf/gbrp16be.fits new file mode 100644 index 000000000..9aa9db60a --- /dev/null +++ b/tests/ref/lavf/gbrp16be.fits @@ -0,0 +1,3 @@ +693ea80c33eb9b348db27a0bc4a5cc8a *tests/data/lavf/lavf.gbrp16be.fits +15336000 tests/data/lavf/lavf.gbrp16be.fits +tests/data/lavf/lavf.gbrp16be.fits CRC=0x9573fb2b diff --git a/tests/ref/lavf/gif b/tests/ref/lavf/gif index d2e2f11e9..fc94b9df3 100644 --- a/tests/ref/lavf/gif +++ b/tests/ref/lavf/gif @@ -1,3 +1,3 @@ -e35f5ea283bbcb249818e0078ec72664 *./tests/data/lavf/lavf.gif -2011766 ./tests/data/lavf/lavf.gif -./tests/data/lavf/lavf.gif CRC=0x2429faff +e35f5ea283bbcb249818e0078ec72664 *tests/data/lavf/lavf.gif +2011766 tests/data/lavf/lavf.gif +tests/data/lavf/lavf.gif CRC=0x2429faff diff --git a/tests/ref/lavf/gray.fits b/tests/ref/lavf/gray.fits new file mode 100644 index 000000000..ce6783b7c --- /dev/null +++ b/tests/ref/lavf/gray.fits @@ -0,0 +1,3 @@ +d76b46a5a336b56f73451817cdf3897c *tests/data/lavf/lavf.gray.fits +2664000 tests/data/lavf/lavf.gray.fits +tests/data/lavf/lavf.gray.fits CRC=0x7aa0122f diff --git a/tests/ref/lavf/gray.pam b/tests/ref/lavf/gray.pam new file mode 100644 index 000000000..77af981c4 --- /dev/null +++ b/tests/ref/lavf/gray.pam @@ -0,0 +1,3 @@ +35cb9e42b2d3181be494f8693af1ddea *tests/data/images/gray.pam/02.gray.pam +tests/data/images/gray.pam/%02d.gray.pam CRC=0x0ff205be +101445 tests/data/images/gray.pam/02.gray.pam diff --git a/tests/ref/lavf/gray.xwd b/tests/ref/lavf/gray.xwd new file mode 100644 index 000000000..15c80fba3 --- /dev/null +++ b/tests/ref/lavf/gray.xwd @@ -0,0 +1,3 @@ +85e9b8b814a1dea71d143aac2e487037 *tests/data/images/gray.xwd/02.gray.xwd +tests/data/images/gray.xwd/%02d.gray.xwd CRC=0x0ff205be +101487 tests/data/images/gray.xwd/02.gray.xwd diff --git a/tests/ref/lavf/gray16be.fits b/tests/ref/lavf/gray16be.fits new file mode 100644 index 000000000..078d6c867 --- /dev/null +++ b/tests/ref/lavf/gray16be.fits @@ -0,0 +1,3 @@ +15e85a553bbd07783f92377ed369308b *tests/data/lavf/lavf.gray16be.fits +5184000 tests/data/lavf/lavf.gray16be.fits +tests/data/lavf/lavf.gray16be.fits CRC=0x8b840cff diff --git a/tests/ref/lavf/gray16be.pam b/tests/ref/lavf/gray16be.pam new file mode 100644 index 000000000..5038384bb --- /dev/null +++ b/tests/ref/lavf/gray16be.pam @@ -0,0 +1,3 @@ +740eb42157af9e9eed46b70ba6a6cf4d *tests/data/images/gray16be.pam/02.gray16be.pam +tests/data/images/gray16be.pam/%02d.gray16be.pam CRC=0x893f10ef +202823 tests/data/images/gray16be.pam/02.gray16be.pam diff --git a/tests/ref/lavf/gray16be.png b/tests/ref/lavf/gray16be.png new file mode 100644 index 000000000..2f52a8336 --- /dev/null +++ b/tests/ref/lavf/gray16be.png @@ -0,0 +1,3 @@ +6cf54c13aa407b77547cf6dfe23ecba3 *tests/data/images/gray16be.png/02.gray16be.png +tests/data/images/gray16be.png/%02d.gray16be.png CRC=0x893f10ef +47365 tests/data/images/gray16be.png/02.gray16be.png diff --git a/tests/ref/lavf/gxf b/tests/ref/lavf/gxf index 4dd463cd2..e8351fab8 100644 --- a/tests/ref/lavf/gxf +++ b/tests/ref/lavf/gxf @@ -1,9 +1,3 @@ -6ef34e8bedf699cd1601022c4a0a4910 *./tests/data/lavf/lavf.gxf -795876 ./tests/data/lavf/lavf.gxf -./tests/data/lavf/lavf.gxf CRC=0x1dbfef76 -7780c428dde2c93a9ff04794f7168440 *./tests/data/lavf/lavf.gxf -794656 ./tests/data/lavf/lavf.gxf -./tests/data/lavf/lavf.gxf CRC=0xdcd39443 -0638c4d073ac224608baaba16732b68f *./tests/data/lavf/lavf.gxf -795876 ./tests/data/lavf/lavf.gxf -./tests/data/lavf/lavf.gxf CRC=0x5ade0285 +0638c4d073ac224608baaba16732b68f *tests/data/lavf/lavf.gxf +795876 tests/data/lavf/lavf.gxf +tests/data/lavf/lavf.gxf CRC=0x5ade0285 diff --git a/tests/ref/lavf/gxf_ntsc b/tests/ref/lavf/gxf_ntsc new file mode 100644 index 000000000..60efd8046 --- /dev/null +++ b/tests/ref/lavf/gxf_ntsc @@ -0,0 +1,3 @@ +9a27673c85f1671ba9ff7cd33e5735de *tests/data/lavf/lavf.gxf_ntsc +794660 tests/data/lavf/lavf.gxf_ntsc +tests/data/lavf/lavf.gxf_ntsc CRC=0xdcd39443 diff --git a/tests/ref/lavf/gxf_pal b/tests/ref/lavf/gxf_pal new file mode 100644 index 000000000..aefcd0cca --- /dev/null +++ b/tests/ref/lavf/gxf_pal @@ -0,0 +1,3 @@ +4d1bd16c6d52468c05711d8301e4e302 *tests/data/lavf/lavf.gxf_pal +795880 tests/data/lavf/lavf.gxf_pal +tests/data/lavf/lavf.gxf_pal CRC=0x1dbfef76 diff --git a/tests/ref/lavf/ircam b/tests/ref/lavf/ircam index 47e07098e..7a17fb232 100644 --- a/tests/ref/lavf/ircam +++ b/tests/ref/lavf/ircam @@ -1,3 +1,3 @@ -45d9a4667030e95d1d8fb6ab012f1aa0 *./tests/data/lavf/lavf.ircam -89224 ./tests/data/lavf/lavf.ircam -./tests/data/lavf/lavf.ircam CRC=0x3a1da17e +45d9a4667030e95d1d8fb6ab012f1aa0 *tests/data/lavf/lavf.ircam +89224 tests/data/lavf/lavf.ircam +tests/data/lavf/lavf.ircam CRC=0x3a1da17e diff --git a/tests/ref/lavf/ismv b/tests/ref/lavf/ismv index f29b5ff3e..865a6913c 100644 --- a/tests/ref/lavf/ismv +++ b/tests/ref/lavf/ismv @@ -1,9 +1,9 @@ -a9ccbb4cd1436d222ef4425567b4e03d *./tests/data/lavf/lavf.ismv -312542 ./tests/data/lavf/lavf.ismv -./tests/data/lavf/lavf.ismv CRC=0x9d9a638a -440d85f9fd5b9f63c2676638782b5c15 *./tests/data/lavf/lavf.ismv -321448 ./tests/data/lavf/lavf.ismv -./tests/data/lavf/lavf.ismv CRC=0xe8130120 -a9ccbb4cd1436d222ef4425567b4e03d *./tests/data/lavf/lavf.ismv -312542 ./tests/data/lavf/lavf.ismv -./tests/data/lavf/lavf.ismv CRC=0x9d9a638a +bd88b50defa57766619c092ea89f25a6 *tests/data/lavf/lavf.ismv +313165 tests/data/lavf/lavf.ismv +tests/data/lavf/lavf.ismv CRC=0x9d9a638a +805a2557bf952c84835f3c10b6893e15 *tests/data/lavf/lavf.ismv +322071 tests/data/lavf/lavf.ismv +tests/data/lavf/lavf.ismv CRC=0xe8130120 +96053075a3f60d271131fe2d0765c267 *tests/data/lavf/lavf.ismv +312542 tests/data/lavf/lavf.ismv +tests/data/lavf/lavf.ismv CRC=0x9d9a638a diff --git a/tests/ref/lavf/jpg b/tests/ref/lavf/jpg index 508066747..ecbb22ceb 100644 --- a/tests/ref/lavf/jpg +++ b/tests/ref/lavf/jpg @@ -1,3 +1,3 @@ -1e7c6d937f21c045e0b238a83f62f3c5 *./tests/data/images/jpg/02.jpg -./tests/data/images/jpg/%02d.jpg CRC=0xe3509f33 -26037 ./tests/data/images/jpg/02.jpg +1e7c6d937f21c045e0b238a83f62f3c5 *tests/data/images/jpg/02.jpg +tests/data/images/jpg/%02d.jpg CRC=0xe3509f33 +26037 tests/data/images/jpg/02.jpg diff --git a/tests/ref/lavf/mka b/tests/ref/lavf/mka index ac0f6cf31..a244893cf 100644 --- a/tests/ref/lavf/mka +++ b/tests/ref/lavf/mka @@ -1,3 +1,3 @@ -2d9722c0691e140237af0036e3a178b0 *./tests/data/lavf/lavf.mka -43684 ./tests/data/lavf/lavf.mka -./tests/data/lavf/lavf.mka CRC=0x3a1da17e +a91bfdb08ff5a1e62b039748d16b07f7 *tests/data/lavf/lavf.mka +43652 tests/data/lavf/lavf.mka +tests/data/lavf/lavf.mka CRC=0x3a1da17e diff --git a/tests/ref/lavf/mkv b/tests/ref/lavf/mkv index 008303395..05999b79f 100644 --- a/tests/ref/lavf/mkv +++ b/tests/ref/lavf/mkv @@ -1,6 +1,3 @@ -7c8697c324e8ad79c5ea14364a6c39b8 *./tests/data/lavf/lavf.mkv -472759 ./tests/data/lavf/lavf.mkv -./tests/data/lavf/lavf.mkv CRC=0xec6c3c68 -9767a3b526d7e56d7400164cb888990c *./tests/data/lavf/lavf.mkv -320603 ./tests/data/lavf/lavf.mkv -./tests/data/lavf/lavf.mkv CRC=0xec6c3c68 +3cddd26ed41f34925d3f34acabab174e *tests/data/lavf/lavf.mkv +320555 tests/data/lavf/lavf.mkv +tests/data/lavf/lavf.mkv CRC=0xec6c3c68 diff --git a/tests/ref/lavf/mkv_attachment b/tests/ref/lavf/mkv_attachment new file mode 100644 index 000000000..230dff369 --- /dev/null +++ b/tests/ref/lavf/mkv_attachment @@ -0,0 +1,3 @@ +4a25c53150c09537cd4fcbff8f8f14ff *tests/data/lavf/lavf.mkv_attachment +472706 tests/data/lavf/lavf.mkv_attachment +tests/data/lavf/lavf.mkv_attachment CRC=0xec6c3c68 diff --git a/tests/ref/lavf/mmf b/tests/ref/lavf/mmf index fae95cadd..36094bc90 100644 --- a/tests/ref/lavf/mmf +++ b/tests/ref/lavf/mmf @@ -1,3 +1,3 @@ -643fadf7482f6d937ed75ec4f508e4f1 *./tests/data/lavf/lavf.mmf -22611 ./tests/data/lavf/lavf.mmf -./tests/data/lavf/lavf.mmf CRC=0x8dea1388 +643fadf7482f6d937ed75ec4f508e4f1 *tests/data/lavf/lavf.mmf +22611 tests/data/lavf/lavf.mmf +tests/data/lavf/lavf.mmf CRC=0x8dea1388 diff --git a/tests/ref/lavf/monob.pam b/tests/ref/lavf/monob.pam new file mode 100644 index 000000000..488907e11 --- /dev/null +++ b/tests/ref/lavf/monob.pam @@ -0,0 +1,3 @@ +d2f5eb2f959ca3a90c02f1887b6e0c4f *tests/data/images/monob.pam/02.monob.pam +tests/data/images/monob.pam/%02d.monob.pam CRC=0xab19200d +101447 tests/data/images/monob.pam/02.monob.pam diff --git a/tests/ref/lavf/monow.xwd b/tests/ref/lavf/monow.xwd new file mode 100644 index 000000000..da09d8b19 --- /dev/null +++ b/tests/ref/lavf/monow.xwd @@ -0,0 +1,3 @@ +796e2e309ac0844cfb2f4959816508ee *tests/data/images/monow.xwd/02.monow.xwd +tests/data/images/monow.xwd/%02d.monow.xwd CRC=0xc9a20204 +12783 tests/data/images/monow.xwd/02.monow.xwd diff --git a/tests/ref/lavf/mov b/tests/ref/lavf/mov index 2e1f24dfc..75a0c4892 100644 --- a/tests/ref/lavf/mov +++ b/tests/ref/lavf/mov @@ -1,21 +1,9 @@ -a10d50f2679df92264e1fc21cb8be630 *./tests/data/lavf/lavf.mov -366449 ./tests/data/lavf/lavf.mov -./tests/data/lavf/lavf.mov CRC=0xbb2b949b -6258f70f974e3c802e01d02ac33c7bbd *./tests/data/lavf/lavf.mov -357539 ./tests/data/lavf/lavf.mov -./tests/data/lavf/lavf.mov CRC=0xbb2b949b -ba3b8b49e420510a0d417400dbedfc2d *./tests/data/lavf/lavf.mov -366621 ./tests/data/lavf/lavf.mov -./tests/data/lavf/lavf.mov CRC=0xa9793231 -fd0e4de8e7f6d0c8c0681d7020f00f50 *./tests/data/lavf/lavf.mov -356921 ./tests/data/lavf/lavf.mov -./tests/data/lavf/lavf.mov CRC=0xbb2b949b -ebca72c186a4f3ba9bb17d9cb5b74fef *./tests/data/lavf/lavf.mp4 -312457 ./tests/data/lavf/lavf.mp4 -./tests/data/lavf/lavf.mp4 CRC=0x9d9a638a -9944512475d82d2d601f3c96101bdf9c *./tests/data/lavf/lavf.mp4 -321343 ./tests/data/lavf/lavf.mp4 -./tests/data/lavf/lavf.mp4 CRC=0xe8130120 -7b3e71f294901067046c09f03a426bdc *./tests/data/lavf/lavf.mp4 -312001 ./tests/data/lavf/lavf.mp4 -./tests/data/lavf/lavf.mp4 CRC=0x9d9a638a +11bd76730274924e02623172b82b5236 *tests/data/lavf/lavf.mov +357539 tests/data/lavf/lavf.mov +tests/data/lavf/lavf.mov CRC=0xbb2b949b +6efa586655e3db043cb29668f5216610 *tests/data/lavf/lavf.mov +366621 tests/data/lavf/lavf.mov +tests/data/lavf/lavf.mov CRC=0xa9793231 +c80c625ded376602e71d5aa6ac6fdb1c *tests/data/lavf/lavf.mov +356921 tests/data/lavf/lavf.mov +tests/data/lavf/lavf.mov CRC=0xbb2b949b diff --git a/tests/ref/lavf/mov_rtphint b/tests/ref/lavf/mov_rtphint new file mode 100644 index 000000000..79a760694 --- /dev/null +++ b/tests/ref/lavf/mov_rtphint @@ -0,0 +1,3 @@ +7014419d8267c2751314303a8fb303c1 *tests/data/lavf/lavf.mov_rtphint +366449 tests/data/lavf/lavf.mov_rtphint +tests/data/lavf/lavf.mov_rtphint CRC=0xbb2b949b diff --git a/tests/ref/lavf/mp4 b/tests/ref/lavf/mp4 new file mode 100644 index 000000000..848281238 --- /dev/null +++ b/tests/ref/lavf/mp4 @@ -0,0 +1,9 @@ +ebca72c186a4f3ba9bb17d9cb5b74fef *tests/data/lavf/lavf.mp4 +312457 tests/data/lavf/lavf.mp4 +tests/data/lavf/lavf.mp4 CRC=0x9d9a638a +9944512475d82d2d601f3c96101bdf9c *tests/data/lavf/lavf.mp4 +321343 tests/data/lavf/lavf.mp4 +tests/data/lavf/lavf.mp4 CRC=0xe8130120 +7b3e71f294901067046c09f03a426bdc *tests/data/lavf/lavf.mp4 +312001 tests/data/lavf/lavf.mp4 +tests/data/lavf/lavf.mp4 CRC=0x9d9a638a diff --git a/tests/ref/lavf/mpg b/tests/ref/lavf/mpg index 7aab14f84..332b7114b 100644 --- a/tests/ref/lavf/mpg +++ b/tests/ref/lavf/mpg @@ -1,9 +1,9 @@ -01bbdea588da51ab4a9d1d26f3443c96 *./tests/data/lavf/lavf.mpg -372736 ./tests/data/lavf/lavf.mpg -./tests/data/lavf/lavf.mpg CRC=0x000e23ae -87b447b78a7d1141b9d41bb3aa50434d *./tests/data/lavf/lavf.mpg -389120 ./tests/data/lavf/lavf.mpg -./tests/data/lavf/lavf.mpg CRC=0x60ba4ab9 -284f41c914df75c12de01e223d65f87f *./tests/data/lavf/lavf.mpg -372736 ./tests/data/lavf/lavf.mpg -./tests/data/lavf/lavf.mpg CRC=0x000e23ae +01bbdea588da51ab4a9d1d26f3443c96 *tests/data/lavf/lavf.mpg +372736 tests/data/lavf/lavf.mpg +tests/data/lavf/lavf.mpg CRC=0x000e23ae +87b447b78a7d1141b9d41bb3aa50434d *tests/data/lavf/lavf.mpg +389120 tests/data/lavf/lavf.mpg +tests/data/lavf/lavf.mpg CRC=0x60ba4ab9 +284f41c914df75c12de01e223d65f87f *tests/data/lavf/lavf.mpg +372736 tests/data/lavf/lavf.mpg +tests/data/lavf/lavf.mpg CRC=0x000e23ae diff --git a/tests/ref/lavf/mxf b/tests/ref/lavf/mxf index 7318447ec..471fc5518 100644 --- a/tests/ref/lavf/mxf +++ b/tests/ref/lavf/mxf @@ -1,9 +1,9 @@ -d4140129463dec64bdb4a7d7ad1b0c82 *./tests/data/lavf/lavf.mxf -525369 ./tests/data/lavf/lavf.mxf -./tests/data/lavf/lavf.mxf CRC=0x8dddfaab -a27bb8cd5e185ea13b0a8daa4eb221cd *./tests/data/lavf/lavf.mxf -560697 ./tests/data/lavf/lavf.mxf -./tests/data/lavf/lavf.mxf CRC=0xf21b1b48 -395bf0047c97ceca96935357166b94c7 *./tests/data/lavf/lavf.mxf -525369 ./tests/data/lavf/lavf.mxf -./tests/data/lavf/lavf.mxf CRC=0x8dddfaab +649009e3d3d62eb3b6c56334d057cc4d *tests/data/lavf/lavf.mxf +526393 tests/data/lavf/lavf.mxf +tests/data/lavf/lavf.mxf CRC=0x8dddfaab +9076b7015cffe8aa72883e900a2041a5 *tests/data/lavf/lavf.mxf +561721 tests/data/lavf/lavf.mxf +tests/data/lavf/lavf.mxf CRC=0x96ff1b48 +02bf8f0cd8951a49e277306691cb1538 *tests/data/lavf/lavf.mxf +526393 tests/data/lavf/lavf.mxf +tests/data/lavf/lavf.mxf CRC=0x8dddfaab diff --git a/tests/ref/lavf/mxf_d10 b/tests/ref/lavf/mxf_d10 index 2384d427b..aea469bb5 100644 --- a/tests/ref/lavf/mxf_d10 +++ b/tests/ref/lavf/mxf_d10 @@ -1,3 +1,3 @@ -f4694941b0cd5b5e3c91064d84dbd345 *./tests/data/lavf/lavf.mxf_d10 -5330989 ./tests/data/lavf/lavf.mxf_d10 -./tests/data/lavf/lavf.mxf_d10 CRC=0x6c74d488 +e597f73ef9c9819710d2f815813eb91f *tests/data/lavf/lavf.mxf_d10 +5332013 tests/data/lavf/lavf.mxf_d10 +tests/data/lavf/lavf.mxf_d10 CRC=0x6c74d488 diff --git a/tests/ref/lavf/mxf_dv25 b/tests/ref/lavf/mxf_dv25 index e836b1424..db6b76c6f 100644 --- a/tests/ref/lavf/mxf_dv25 +++ b/tests/ref/lavf/mxf_dv25 @@ -1,3 +1,3 @@ -1ca8143bf6cf322fd39f6e856959d502 *./tests/data/lavf/lavf.mxf_dv25 -3833389 ./tests/data/lavf/lavf.mxf_dv25 -./tests/data/lavf/lavf.mxf_dv25 CRC=0xbdaf7f52 +0fc964fa22bc8b3a389b81b9a2efccb3 *tests/data/lavf/lavf.mxf_dv25 +3834413 tests/data/lavf/lavf.mxf_dv25 +tests/data/lavf/lavf.mxf_dv25 CRC=0xbdaf7f52 diff --git a/tests/ref/lavf/mxf_dvcpro50 b/tests/ref/lavf/mxf_dvcpro50 index bb3d6b928..09999914b 100644 --- a/tests/ref/lavf/mxf_dvcpro50 +++ b/tests/ref/lavf/mxf_dvcpro50 @@ -1,3 +1,3 @@ -987fd4b2abb36433fba0e35f4092efc6 *./tests/data/lavf/lavf.mxf_dvcpro50 -7430189 ./tests/data/lavf/lavf.mxf_dvcpro50 -./tests/data/lavf/lavf.mxf_dvcpro50 CRC=0xe3bbe4b4 +aa81ea83af44a69e73849e327cc4bd12 *tests/data/lavf/lavf.mxf_dvcpro50 +7431213 tests/data/lavf/lavf.mxf_dvcpro50 +tests/data/lavf/lavf.mxf_dvcpro50 CRC=0xe3bbe4b4 diff --git a/tests/ref/lavf/mxf_opatom b/tests/ref/lavf/mxf_opatom index 1cc612e62..05794a4e5 100644 --- a/tests/ref/lavf/mxf_opatom +++ b/tests/ref/lavf/mxf_opatom @@ -1,3 +1,3 @@ -b8fe60f7457b83709f33357d04c8db0c *./tests/data/lavf/lavf.mxf_opatom -4717113 ./tests/data/lavf/lavf.mxf_opatom -./tests/data/lavf/lavf.mxf_opatom CRC=0xf55aa22a +06a1816aa91c733e1ef7e45d82e4f1d3 *tests/data/lavf/lavf.mxf_opatom +4717625 tests/data/lavf/lavf.mxf_opatom +tests/data/lavf/lavf.mxf_opatom CRC=0xf55aa22a diff --git a/tests/ref/lavf/mxf_opatom_audio b/tests/ref/lavf/mxf_opatom_audio index deed55e52..2b9306f1d 100644 --- a/tests/ref/lavf/mxf_opatom_audio +++ b/tests/ref/lavf/mxf_opatom_audio @@ -1,3 +1,3 @@ -e7da52bd591e6eddb4e1af381a4e5bd4 *./tests/data/lavf/lavf.mxf_opatom_audio -101945 ./tests/data/lavf/lavf.mxf_opatom_audio -./tests/data/lavf/lavf.mxf_opatom_audio CRC=0xd155c6ff +c45bb140605339556a77e751fda2c449 *tests/data/lavf/lavf.mxf_opatom_audio +102969 tests/data/lavf/lavf.mxf_opatom_audio +tests/data/lavf/lavf.mxf_opatom_audio CRC=0xd155c6ff diff --git a/tests/ref/lavf/nut b/tests/ref/lavf/nut index 1c3d7107d..1ba91dfb8 100644 --- a/tests/ref/lavf/nut +++ b/tests/ref/lavf/nut @@ -1,3 +1,3 @@ -424e8037d7b6f3d3c09cf76bf06a63cb *./tests/data/lavf/lavf.nut -319958 ./tests/data/lavf/lavf.nut -./tests/data/lavf/lavf.nut CRC=0xec6c3c68 +424e8037d7b6f3d3c09cf76bf06a63cb *tests/data/lavf/lavf.nut +319958 tests/data/lavf/lavf.nut +tests/data/lavf/lavf.nut CRC=0xec6c3c68 diff --git a/tests/ref/lavf/ogg b/tests/ref/lavf/ogg index a08fb5ed8..3ac10e6f7 100644 --- a/tests/ref/lavf/ogg +++ b/tests/ref/lavf/ogg @@ -1,3 +1,3 @@ -81b9366cacb23644c2803585dced9996 *./tests/data/lavf/lavf.ogg -13516 ./tests/data/lavf/lavf.ogg -./tests/data/lavf/lavf.ogg CRC=0x3a1da17e +81b9366cacb23644c2803585dced9996 *tests/data/lavf/lavf.ogg +13516 tests/data/lavf/lavf.ogg +tests/data/lavf/lavf.ogg CRC=0x3a1da17e diff --git a/tests/ref/lavf/pam b/tests/ref/lavf/pam index 97893f60c..8ac3f2b10 100644 --- a/tests/ref/lavf/pam +++ b/tests/ref/lavf/pam @@ -1,18 +1,3 @@ -0dce5565222cf0f8b309467f279aecd2 *./tests/data/images/pam/02.pam -./tests/data/images/pam/%02d.pam CRC=0x6da01946 -304191 ./tests/data/images/pam/02.pam -2ed31ca8d8de560afb3e0fd7a873cde5 *./tests/data/images/pam/02.pam -./tests/data/images/pam/%02d.pam CRC=0xf07d29cd -405573 ./tests/data/images/pam/02.pam -35cb9e42b2d3181be494f8693af1ddea *./tests/data/images/pam/02.pam -./tests/data/images/pam/%02d.pam CRC=0x0ff205be -101445 ./tests/data/images/pam/02.pam -740eb42157af9e9eed46b70ba6a6cf4d *./tests/data/images/pam/02.pam -./tests/data/images/pam/%02d.pam CRC=0x893f10ef -202823 ./tests/data/images/pam/02.pam -032538f0313b4f240b44a5bef115f5bf *./tests/data/images/pam/02.pam -./tests/data/images/pam/%02d.pam CRC=0x5984c023 -608321 ./tests/data/images/pam/02.pam -d2f5eb2f959ca3a90c02f1887b6e0c4f *./tests/data/images/pam/02.pam -./tests/data/images/pam/%02d.pam CRC=0xab19200d -101447 ./tests/data/images/pam/02.pam +0dce5565222cf0f8b309467f279aecd2 *tests/data/images/pam/02.pam +tests/data/images/pam/%02d.pam CRC=0x6da01946 +304191 tests/data/images/pam/02.pam diff --git a/tests/ref/lavf/pbmpipe b/tests/ref/lavf/pbmpipe index 284f90b16..5cfb9b5e7 100644 --- a/tests/ref/lavf/pbmpipe +++ b/tests/ref/lavf/pbmpipe @@ -1,3 +1,3 @@ -8b974da7f48f9e6d5ae327b4444a71fb *./tests/data/lavf/pbmpipe.pbm -317075 ./tests/data/lavf/pbmpipe.pbm -./tests/data/lavf/pbmpipe.pbm CRC=0xfc010c66 +8b974da7f48f9e6d5ae327b4444a71fb *tests/data/lavf/pbmpipe.pbm +317075 tests/data/lavf/pbmpipe.pbm +tests/data/lavf/pbmpipe.pbm CRC=0xfc010c66 diff --git a/tests/ref/lavf/pcx b/tests/ref/lavf/pcx index 6568b6028..2767ccf32 100644 --- a/tests/ref/lavf/pcx +++ b/tests/ref/lavf/pcx @@ -1,3 +1,3 @@ -c4faf65ecc812ec8412cc26140c13bd5 *./tests/data/images/pcx/02.pcx -./tests/data/images/pcx/%02d.pcx CRC=0x6da01946 -364147 ./tests/data/images/pcx/02.pcx +c4faf65ecc812ec8412cc26140c13bd5 *tests/data/images/pcx/02.pcx +tests/data/images/pcx/%02d.pcx CRC=0x6da01946 +364147 tests/data/images/pcx/02.pcx diff --git a/tests/ref/lavf/peak.wav b/tests/ref/lavf/peak.wav new file mode 100644 index 000000000..573d53221 --- /dev/null +++ b/tests/ref/lavf/peak.wav @@ -0,0 +1,3 @@ +105805963fb767d00da056f42f32d9f3 *tests/data/lavf/lavf.peak.wav +89094 tests/data/lavf/lavf.peak.wav +tests/data/lavf/lavf.peak.wav CRC=0x3a1da17e diff --git a/tests/ref/lavf/peak_only.wav b/tests/ref/lavf/peak_only.wav new file mode 100644 index 000000000..c468731b0 --- /dev/null +++ b/tests/ref/lavf/peak_only.wav @@ -0,0 +1,3 @@ +f1a8aeeae8069f3992c4d780436c3d23 *tests/data/lavf/lavf.peak_only.wav +832 tests/data/lavf/lavf.peak_only.wav +tests/data/lavf/lavf.peak_only.wav diff --git a/tests/ref/lavf/pgm b/tests/ref/lavf/pgm index 816579fa8..4100ac95c 100644 --- a/tests/ref/lavf/pgm +++ b/tests/ref/lavf/pgm @@ -1,3 +1,3 @@ -cc777c5fc4d116d4c5a996eac8d3133e *./tests/data/images/pgm/02.pgm -./tests/data/images/pgm/%02d.pgm CRC=0x0ff205be -101391 ./tests/data/images/pgm/02.pgm +cc777c5fc4d116d4c5a996eac8d3133e *tests/data/images/pgm/02.pgm +tests/data/images/pgm/%02d.pgm CRC=0x0ff205be +101391 tests/data/images/pgm/02.pgm diff --git a/tests/ref/lavf/pgmpipe b/tests/ref/lavf/pgmpipe index da6f9a6d3..1077a9514 100644 --- a/tests/ref/lavf/pgmpipe +++ b/tests/ref/lavf/pgmpipe @@ -1,3 +1,3 @@ -c34e37ea49237c2d1ea81a5944328e59 *./tests/data/lavf/pgmpipe.pgm -2534775 ./tests/data/lavf/pgmpipe.pgm -./tests/data/lavf/pgmpipe.pgm CRC=0x7aa0122f +c34e37ea49237c2d1ea81a5944328e59 *tests/data/lavf/pgmpipe.pgm +2534775 tests/data/lavf/pgmpipe.pgm +tests/data/lavf/pgmpipe.pgm CRC=0x7aa0122f diff --git a/tests/ref/lavf/png b/tests/ref/lavf/png index 9cf677b21..165513e98 100644 --- a/tests/ref/lavf/png +++ b/tests/ref/lavf/png @@ -1,9 +1,3 @@ -2af72da4468e61a37c220b25cb28618a *./tests/data/images/png/02.png -./tests/data/images/png/%02d.png CRC=0x6da01946 -248633 ./tests/data/images/png/02.png -6cf54c13aa407b77547cf6dfe23ecba3 *./tests/data/images/png/02.png -./tests/data/images/png/%02d.png CRC=0x893f10ef -47365 ./tests/data/images/png/02.png -b4e38244c97debe3f528e7d1adb283ef *./tests/data/images/png/02.png -./tests/data/images/png/%02d.png CRC=0x5984c023 -511900 ./tests/data/images/png/02.png +2af72da4468e61a37c220b25cb28618a *tests/data/images/png/02.png +tests/data/images/png/%02d.png CRC=0x6da01946 +248633 tests/data/images/png/02.png diff --git a/tests/ref/lavf/ppm b/tests/ref/lavf/ppm index 97093aaac..04377f12d 100644 --- a/tests/ref/lavf/ppm +++ b/tests/ref/lavf/ppm @@ -1,3 +1,3 @@ -16d5dadf0b362fc8ba3cb676c5dde985 *./tests/data/images/ppm/02.ppm -./tests/data/images/ppm/%02d.ppm CRC=0x6da01946 -304143 ./tests/data/images/ppm/02.ppm +16d5dadf0b362fc8ba3cb676c5dde985 *tests/data/images/ppm/02.ppm +tests/data/images/ppm/%02d.ppm CRC=0x6da01946 +304143 tests/data/images/ppm/02.ppm diff --git a/tests/ref/lavf/ppmpipe b/tests/ref/lavf/ppmpipe index b703e16e5..a50dbb067 100644 --- a/tests/ref/lavf/ppmpipe +++ b/tests/ref/lavf/ppmpipe @@ -1,3 +1,3 @@ -74f1f6651ad8f192a7b4c11c2b6c71e5 *./tests/data/lavf/ppmpipe.ppm -7603575 ./tests/data/lavf/ppmpipe.ppm -./tests/data/lavf/ppmpipe.ppm CRC=0x87b3c15f +74f1f6651ad8f192a7b4c11c2b6c71e5 *tests/data/lavf/ppmpipe.ppm +7603575 tests/data/lavf/ppmpipe.ppm +tests/data/lavf/ppmpipe.ppm CRC=0x87b3c15f diff --git a/tests/ref/lavf/rgb48be.pam b/tests/ref/lavf/rgb48be.pam new file mode 100644 index 000000000..13e5f77ac --- /dev/null +++ b/tests/ref/lavf/rgb48be.pam @@ -0,0 +1,3 @@ +032538f0313b4f240b44a5bef115f5bf *tests/data/images/rgb48be.pam/02.rgb48be.pam +tests/data/images/rgb48be.pam/%02d.rgb48be.pam CRC=0x5984c023 +608321 tests/data/images/rgb48be.pam/02.rgb48be.pam diff --git a/tests/ref/lavf/rgb48be.png b/tests/ref/lavf/rgb48be.png new file mode 100644 index 000000000..84f4d46f5 --- /dev/null +++ b/tests/ref/lavf/rgb48be.png @@ -0,0 +1,3 @@ +b4e38244c97debe3f528e7d1adb283ef *tests/data/images/rgb48be.png/02.rgb48be.png +tests/data/images/rgb48be.png/%02d.rgb48be.png CRC=0x5984c023 +511900 tests/data/images/rgb48be.png/02.rgb48be.png diff --git a/tests/ref/lavf/rgb48le.dpx b/tests/ref/lavf/rgb48le.dpx new file mode 100644 index 000000000..073153898 --- /dev/null +++ b/tests/ref/lavf/rgb48le.dpx @@ -0,0 +1,3 @@ +075963c3c08978b6a20555ba09161434 *tests/data/images/rgb48le.dpx/02.rgb48le.dpx +tests/data/images/rgb48le.dpx/%02d.rgb48le.dpx CRC=0xe5b9c023 +609920 tests/data/images/rgb48le.dpx/02.rgb48le.dpx diff --git a/tests/ref/lavf/rgb48le_10.dpx b/tests/ref/lavf/rgb48le_10.dpx new file mode 100644 index 000000000..ce36e5079 --- /dev/null +++ b/tests/ref/lavf/rgb48le_10.dpx @@ -0,0 +1,3 @@ +b9f22728f8ff393bf30cf6cbd624fa95 *tests/data/images/rgb48le_10.dpx/02.rgb48le_10.dpx +tests/data/images/rgb48le_10.dpx/%02d.rgb48le_10.dpx CRC=0xf38d5830 +407168 tests/data/images/rgb48le_10.dpx/02.rgb48le_10.dpx diff --git a/tests/ref/lavf/rgb4_byte.xwd b/tests/ref/lavf/rgb4_byte.xwd new file mode 100644 index 000000000..fee4cf728 --- /dev/null +++ b/tests/ref/lavf/rgb4_byte.xwd @@ -0,0 +1,3 @@ +fe1af954966a40c2cd35fc27094ff823 *tests/data/images/rgb4_byte.xwd/02.rgb4_byte.xwd +tests/data/images/rgb4_byte.xwd/%02d.rgb4_byte.xwd CRC=0xce042dcc +104559 tests/data/images/rgb4_byte.xwd/02.rgb4_byte.xwd diff --git a/tests/ref/lavf/rgb555be.xwd b/tests/ref/lavf/rgb555be.xwd new file mode 100644 index 000000000..1f9c579bc --- /dev/null +++ b/tests/ref/lavf/rgb555be.xwd @@ -0,0 +1,3 @@ +1300938325d5ac12caa09a43bd58f37c *tests/data/images/rgb555be.xwd/02.rgb555be.xwd +tests/data/images/rgb555be.xwd/%02d.rgb555be.xwd CRC=0x14555d6e +202863 tests/data/images/rgb555be.xwd/02.rgb555be.xwd diff --git a/tests/ref/lavf/rgb565be.xwd b/tests/ref/lavf/rgb565be.xwd new file mode 100644 index 000000000..02a5bc28d --- /dev/null +++ b/tests/ref/lavf/rgb565be.xwd @@ -0,0 +1,3 @@ +c0866e9e710fce735423594a93bee604 *tests/data/images/rgb565be.xwd/02.rgb565be.xwd +tests/data/images/rgb565be.xwd/%02d.rgb565be.xwd CRC=0x53209216 +202863 tests/data/images/rgb565be.xwd/02.rgb565be.xwd diff --git a/tests/ref/lavf/rgb8.xwd b/tests/ref/lavf/rgb8.xwd new file mode 100644 index 000000000..52f4e3eeb --- /dev/null +++ b/tests/ref/lavf/rgb8.xwd @@ -0,0 +1,3 @@ +c6f3cb7c45f7238474a89d2ad61a1caf *tests/data/images/rgb8.xwd/02.rgb8.xwd +tests/data/images/rgb8.xwd/%02d.rgb8.xwd CRC=0xf217a95e +104559 tests/data/images/rgb8.xwd/02.rgb8.xwd diff --git a/tests/ref/lavf/rgba.pam b/tests/ref/lavf/rgba.pam new file mode 100644 index 000000000..56e43a4ac --- /dev/null +++ b/tests/ref/lavf/rgba.pam @@ -0,0 +1,3 @@ +2ed31ca8d8de560afb3e0fd7a873cde5 *tests/data/images/rgba.pam/02.rgba.pam +tests/data/images/rgba.pam/%02d.rgba.pam CRC=0xf07d29cd +405573 tests/data/images/rgba.pam/02.rgba.pam diff --git a/tests/ref/lavf/rgba.xwd b/tests/ref/lavf/rgba.xwd new file mode 100644 index 000000000..95aafdceb --- /dev/null +++ b/tests/ref/lavf/rgba.xwd @@ -0,0 +1,3 @@ +1cdb43599c956dc8563f1e09fac5df00 *tests/data/images/rgba.xwd/02.rgba.xwd +tests/data/images/rgba.xwd/%02d.rgba.xwd CRC=0xf07d29cd +405615 tests/data/images/rgba.xwd/02.rgba.xwd diff --git a/tests/ref/lavf/rgba64le.dpx b/tests/ref/lavf/rgba64le.dpx new file mode 100644 index 000000000..b4092c9fd --- /dev/null +++ b/tests/ref/lavf/rgba64le.dpx @@ -0,0 +1,3 @@ +545603630f30dec2768c8ae8d12eb8ea *tests/data/images/rgba64le.dpx/02.rgba64le.dpx +tests/data/images/rgba64le.dpx/%02d.rgba64le.dpx CRC=0xe72ce131 +812672 tests/data/images/rgba64le.dpx/02.rgba64le.dpx diff --git a/tests/ref/lavf/rm b/tests/ref/lavf/rm index 62e0a3173..43ea4c789 100644 --- a/tests/ref/lavf/rm +++ b/tests/ref/lavf/rm @@ -1,2 +1,2 @@ -e30681d05d6f3d24108d3614600bf116 *./tests/data/lavf/lavf.rm -346424 ./tests/data/lavf/lavf.rm +e30681d05d6f3d24108d3614600bf116 *tests/data/lavf/lavf.rm +346424 tests/data/lavf/lavf.rm diff --git a/tests/ref/lavf/rso b/tests/ref/lavf/rso index 5878f434a..6b2f03e18 100644 --- a/tests/ref/lavf/rso +++ b/tests/ref/lavf/rso @@ -1,3 +1,3 @@ -443b72346065d6318ca18c8395aa1d87 *./tests/data/lavf/lavf.rso -44108 ./tests/data/lavf/lavf.rso -./tests/data/lavf/lavf.rso CRC=0x298fd284 +443b72346065d6318ca18c8395aa1d87 *tests/data/lavf/lavf.rso +44108 tests/data/lavf/lavf.rso +tests/data/lavf/lavf.rso CRC=0x298fd284 diff --git a/tests/ref/lavf/s16.voc b/tests/ref/lavf/s16.voc new file mode 100644 index 000000000..9b17a4c9b --- /dev/null +++ b/tests/ref/lavf/s16.voc @@ -0,0 +1,3 @@ +db9fa22ff71992bd8b6cc80047223c92 *tests/data/lavf/lavf.s16.voc +176615 tests/data/lavf/lavf.s16.voc +tests/data/lavf/lavf.s16.voc CRC=0xe61e3bd0 diff --git a/tests/ref/lavf/sgi b/tests/ref/lavf/sgi index 6f45802d8..504927806 100644 --- a/tests/ref/lavf/sgi +++ b/tests/ref/lavf/sgi @@ -1,3 +1,3 @@ -d446e540a7c18da5fd3cc0e9942cd46f *./tests/data/images/sgi/02.sgi -./tests/data/images/sgi/%02d.sgi CRC=0x6da01946 -307287 ./tests/data/images/sgi/02.sgi +d446e540a7c18da5fd3cc0e9942cd46f *tests/data/images/sgi/02.sgi +tests/data/images/sgi/%02d.sgi CRC=0x6da01946 +307287 tests/data/images/sgi/02.sgi diff --git a/tests/ref/lavf/smjpeg b/tests/ref/lavf/smjpeg index fb8c6542f..537c0847c 100644 --- a/tests/ref/lavf/smjpeg +++ b/tests/ref/lavf/smjpeg @@ -1,3 +1,3 @@ -3fe90213ac4f5275eb85ad0a4e4bdb44 *./tests/data/lavf/lavf.smjpeg -728642 ./tests/data/lavf/lavf.smjpeg -./tests/data/lavf/lavf.smjpeg CRC=0x54bf6147 +3fe90213ac4f5275eb85ad0a4e4bdb44 *tests/data/lavf/lavf.smjpeg +728642 tests/data/lavf/lavf.smjpeg +tests/data/lavf/lavf.smjpeg CRC=0x54bf6147 diff --git a/tests/ref/lavf/sox b/tests/ref/lavf/sox index fc368b135..fc3953e12 100644 --- a/tests/ref/lavf/sox +++ b/tests/ref/lavf/sox @@ -1,3 +1,3 @@ -683635d5cb1344e44fa96df90c3a993c *./tests/data/lavf/lavf.sox -176432 ./tests/data/lavf/lavf.sox -./tests/data/lavf/lavf.sox CRC=0x3a1da17e +683635d5cb1344e44fa96df90c3a993c *tests/data/lavf/lavf.sox +176432 tests/data/lavf/lavf.sox +tests/data/lavf/lavf.sox CRC=0x3a1da17e diff --git a/tests/ref/lavf/sun b/tests/ref/lavf/sun new file mode 100644 index 000000000..5dc0011e7 --- /dev/null +++ b/tests/ref/lavf/sun @@ -0,0 +1,3 @@ +07518bcb0841bc677ce6aea8464ea240 *tests/data/images/sun/02.sun +tests/data/images/sun/%02d.sun CRC=0xe6c71946 +304123 tests/data/images/sun/02.sun diff --git a/tests/ref/lavf/swf b/tests/ref/lavf/swf index 7ce0fa46c..b4e5bb978 100644 --- a/tests/ref/lavf/swf +++ b/tests/ref/lavf/swf @@ -1,3 +1,3 @@ -11e9e9bf99a0ae6a0ba5434b745eae21 *./tests/data/lavf/lavf.swf -329474 ./tests/data/lavf/lavf.swf -./tests/data/lavf/lavf.swf CRC=0x4eac88c5 +11e9e9bf99a0ae6a0ba5434b745eae21 *tests/data/lavf/lavf.swf +329474 tests/data/lavf/lavf.swf +tests/data/lavf/lavf.swf CRC=0x4eac88c5 diff --git a/tests/ref/lavf/tga b/tests/ref/lavf/tga index 7efaf9782..c7e33b043 100644 --- a/tests/ref/lavf/tga +++ b/tests/ref/lavf/tga @@ -1,3 +1,3 @@ -c0305c53e6d79d4ed9f35f04f671246c *./tests/data/images/tga/02.tga -./tests/data/images/tga/%02d.tga CRC=0xe6c71946 -304172 ./tests/data/images/tga/02.tga +c0305c53e6d79d4ed9f35f04f671246c *tests/data/images/tga/02.tga +tests/data/images/tga/%02d.tga CRC=0xe6c71946 +304172 tests/data/images/tga/02.tga diff --git a/tests/ref/lavf/tiff b/tests/ref/lavf/tiff index 4b0b985f7..c708642f9 100644 --- a/tests/ref/lavf/tiff +++ b/tests/ref/lavf/tiff @@ -1,3 +1,3 @@ -b3299346a8959553a437e486d8f3bf76 *./tests/data/images/tiff/02.tiff -./tests/data/images/tiff/%02d.tiff CRC=0x6da01946 -307131 ./tests/data/images/tiff/02.tiff +b3299346a8959553a437e486d8f3bf76 *tests/data/images/tiff/02.tiff +tests/data/images/tiff/%02d.tiff CRC=0x6da01946 +307131 tests/data/images/tiff/02.tiff diff --git a/tests/ref/lavf/ts b/tests/ref/lavf/ts index 2be3526c7..09960f84d 100644 --- a/tests/ref/lavf/ts +++ b/tests/ref/lavf/ts @@ -1,3 +1,3 @@ -38f4b14d43a0e416be8d598628997cbc *./tests/data/lavf/lavf.ts -407020 ./tests/data/lavf/lavf.ts -./tests/data/lavf/lavf.ts CRC=0x71287e25 +38f4b14d43a0e416be8d598628997cbc *tests/data/lavf/lavf.ts +407020 tests/data/lavf/lavf.ts +tests/data/lavf/lavf.ts CRC=0x71287e25 diff --git a/tests/ref/lavf/tta b/tests/ref/lavf/tta index d86d097e3..f6fe9d84f 100644 --- a/tests/ref/lavf/tta +++ b/tests/ref/lavf/tta @@ -1,3 +1,3 @@ -d86c5cccb2554143d34d1786ab460a31 *./tests/data/lavf/lavf.tta -43200 ./tests/data/lavf/lavf.tta -./tests/data/lavf/lavf.tta CRC=0x3a1da17e +d86c5cccb2554143d34d1786ab460a31 *tests/data/lavf/lavf.tta +43200 tests/data/lavf/lavf.tta +tests/data/lavf/lavf.tta CRC=0x3a1da17e diff --git a/tests/ref/lavf/ul b/tests/ref/lavf/ul new file mode 100644 index 000000000..cf025937b --- /dev/null +++ b/tests/ref/lavf/ul @@ -0,0 +1,3 @@ +ad492935e361f830f2f8302aa102701d *tests/data/lavf/lavf.ul +44100 tests/data/lavf/lavf.ul +tests/data/lavf/lavf.ul CRC=0x4515fa26 diff --git a/tests/ref/lavf/voc b/tests/ref/lavf/voc index ded8af722..0ac933e2f 100644 --- a/tests/ref/lavf/voc +++ b/tests/ref/lavf/voc @@ -1,3 +1,3 @@ -bb5ad96a5e1b35683d50bf18115db821 *./tests/data/lavf/lavf.voc -44305 ./tests/data/lavf/lavf.voc -./tests/data/lavf/lavf.voc CRC=0x298fd284 +bb5ad96a5e1b35683d50bf18115db821 *tests/data/lavf/lavf.voc +44305 tests/data/lavf/lavf.voc +tests/data/lavf/lavf.voc CRC=0x298fd284 diff --git a/tests/ref/lavf/w64 b/tests/ref/lavf/w64 index 26c68688e..2b6bc23ae 100644 --- a/tests/ref/lavf/w64 +++ b/tests/ref/lavf/w64 @@ -1,3 +1,3 @@ -82c75c9cb61924fda68d9602ea69c445 *./tests/data/lavf/lavf.w64 -88304 ./tests/data/lavf/lavf.w64 -./tests/data/lavf/lavf.w64 CRC=0x3a1da17e +82c75c9cb61924fda68d9602ea69c445 *tests/data/lavf/lavf.w64 +88304 tests/data/lavf/lavf.w64 +tests/data/lavf/lavf.w64 CRC=0x3a1da17e diff --git a/tests/ref/lavf/wav b/tests/ref/lavf/wav index da3bfc24e..0540eab07 100644 --- a/tests/ref/lavf/wav +++ b/tests/ref/lavf/wav @@ -1,3 +1,3 @@ -fc958a32b4fca7b1c40cbdaef2d1416e *./tests/data/lavf/lavf.wav -88274 ./tests/data/lavf/lavf.wav -./tests/data/lavf/lavf.wav CRC=0x3a1da17e +fc958a32b4fca7b1c40cbdaef2d1416e *tests/data/lavf/lavf.wav +88274 tests/data/lavf/lavf.wav +tests/data/lavf/lavf.wav CRC=0x3a1da17e diff --git a/tests/ref/lavf/wtv b/tests/ref/lavf/wtv index 11c04c5e6..8f991818b 100644 --- a/tests/ref/lavf/wtv +++ b/tests/ref/lavf/wtv @@ -1,3 +1,3 @@ -c5328b1c3e5fe70468c3f587c34ffd82 *./tests/data/lavf/lavf.wtv -413696 ./tests/data/lavf/lavf.wtv -./tests/data/lavf/lavf.wtv CRC=0x71287e25 +c5328b1c3e5fe70468c3f587c34ffd82 *tests/data/lavf/lavf.wtv +413696 tests/data/lavf/lavf.wtv +tests/data/lavf/lavf.wtv CRC=0x71287e25 diff --git a/tests/ref/lavf/wv b/tests/ref/lavf/wv index 323c5df6d..07205093f 100644 --- a/tests/ref/lavf/wv +++ b/tests/ref/lavf/wv @@ -1,3 +1,3 @@ -47d9a381d9c3f99b8b059f3b17f1dc11 *./tests/data/lavf/lavf.wv -59560 ./tests/data/lavf/lavf.wv -./tests/data/lavf/lavf.wv CRC=0x3a1da17e +47d9a381d9c3f99b8b059f3b17f1dc11 *tests/data/lavf/lavf.wv +59560 tests/data/lavf/lavf.wv +tests/data/lavf/lavf.wv CRC=0x3a1da17e diff --git a/tests/ref/lavf/xbm b/tests/ref/lavf/xbm index 705713b22..bc157834f 100644 --- a/tests/ref/lavf/xbm +++ b/tests/ref/lavf/xbm @@ -1,3 +1,3 @@ -0629055fd82366317c651a0af4bb82d7 *./tests/data/images/xbm/02.xbm -./tests/data/images/xbm/%02d.xbm CRC=0xc9a20204 -76411 ./tests/data/images/xbm/02.xbm +0629055fd82366317c651a0af4bb82d7 *tests/data/images/xbm/02.xbm +tests/data/images/xbm/%02d.xbm CRC=0xc9a20204 +76411 tests/data/images/xbm/02.xbm diff --git a/tests/ref/lavf/xwd b/tests/ref/lavf/xwd index b263ce699..7a426ed1f 100644 --- a/tests/ref/lavf/xwd +++ b/tests/ref/lavf/xwd @@ -1,24 +1,3 @@ -50baa5560b7d1aa3188b19c1162bf7dc *./tests/data/images/xwd/02.xwd -./tests/data/images/xwd/%02d.xwd CRC=0x6da01946 -304239 ./tests/data/images/xwd/02.xwd -1cdb43599c956dc8563f1e09fac5df00 *./tests/data/images/xwd/02.xwd -./tests/data/images/xwd/%02d.xwd CRC=0xf07d29cd -405615 ./tests/data/images/xwd/02.xwd -c0866e9e710fce735423594a93bee604 *./tests/data/images/xwd/02.xwd -./tests/data/images/xwd/%02d.xwd CRC=0x53209216 -202863 ./tests/data/images/xwd/02.xwd -1300938325d5ac12caa09a43bd58f37c *./tests/data/images/xwd/02.xwd -./tests/data/images/xwd/%02d.xwd CRC=0x14555d6e -202863 ./tests/data/images/xwd/02.xwd -c6f3cb7c45f7238474a89d2ad61a1caf *./tests/data/images/xwd/02.xwd -./tests/data/images/xwd/%02d.xwd CRC=0xf217a95e -104559 ./tests/data/images/xwd/02.xwd -fe1af954966a40c2cd35fc27094ff823 *./tests/data/images/xwd/02.xwd -./tests/data/images/xwd/%02d.xwd CRC=0xce042dcc -104559 ./tests/data/images/xwd/02.xwd -85e9b8b814a1dea71d143aac2e487037 *./tests/data/images/xwd/02.xwd -./tests/data/images/xwd/%02d.xwd CRC=0x0ff205be -101487 ./tests/data/images/xwd/02.xwd -796e2e309ac0844cfb2f4959816508ee *./tests/data/images/xwd/02.xwd -./tests/data/images/xwd/%02d.xwd CRC=0xc9a20204 -12783 ./tests/data/images/xwd/02.xwd +50baa5560b7d1aa3188b19c1162bf7dc *tests/data/images/xwd/02.xwd +tests/data/images/xwd/%02d.xwd CRC=0x6da01946 +304239 tests/data/images/xwd/02.xwd diff --git a/tests/ref/lavf/y4m b/tests/ref/lavf/y4m new file mode 100644 index 000000000..82c708767 --- /dev/null +++ b/tests/ref/lavf/y4m @@ -0,0 +1,3 @@ +ec8178cb152f9cdbfd9cb724d977db2e *tests/data/lavf/lavf.y4m +3801808 tests/data/lavf/lavf.y4m +tests/data/lavf/lavf.y4m CRC=0x0a941f26 diff --git a/tests/ref/pixfmt/bgr24 b/tests/ref/pixfmt/bgr24 new file mode 100644 index 000000000..43af80b8a --- /dev/null +++ b/tests/ref/pixfmt/bgr24 @@ -0,0 +1,2 @@ +6bb61113e7b70eb09dbcec356122a0e2 *tests/data/pixfmt/bgr24.yuv +304128 tests/data/pixfmt/bgr24.yuv diff --git a/tests/ref/pixfmt/gray b/tests/ref/pixfmt/gray new file mode 100644 index 000000000..fe5e5464f --- /dev/null +++ b/tests/ref/pixfmt/gray @@ -0,0 +1,2 @@ +1e080c12bd9755c41ecb8e19b756f406 *tests/data/pixfmt/gray.yuv +304128 tests/data/pixfmt/gray.yuv diff --git a/tests/ref/pixfmt/monob b/tests/ref/pixfmt/monob new file mode 100644 index 000000000..002dda1d3 --- /dev/null +++ b/tests/ref/pixfmt/monob @@ -0,0 +1,2 @@ +d87cf0c2e7a13cc693fe6ece22461c83 *tests/data/pixfmt/monob.yuv +304128 tests/data/pixfmt/monob.yuv diff --git a/tests/ref/pixfmt/monow b/tests/ref/pixfmt/monow new file mode 100644 index 000000000..485f256bb --- /dev/null +++ b/tests/ref/pixfmt/monow @@ -0,0 +1,2 @@ +d87cf0c2e7a13cc693fe6ece22461c83 *tests/data/pixfmt/monow.yuv +304128 tests/data/pixfmt/monow.yuv diff --git a/tests/ref/pixfmt/rgb24 b/tests/ref/pixfmt/rgb24 new file mode 100644 index 000000000..b38611343 --- /dev/null +++ b/tests/ref/pixfmt/rgb24 @@ -0,0 +1,2 @@ +6bb61113e7b70eb09dbcec356122a0e2 *tests/data/pixfmt/rgb24.yuv +304128 tests/data/pixfmt/rgb24.yuv diff --git a/tests/ref/pixfmt/rgb32 b/tests/ref/pixfmt/rgb32 new file mode 100644 index 000000000..741e60a4e --- /dev/null +++ b/tests/ref/pixfmt/rgb32 @@ -0,0 +1,2 @@ +6bb61113e7b70eb09dbcec356122a0e2 *tests/data/pixfmt/rgb32.yuv +304128 tests/data/pixfmt/rgb32.yuv diff --git a/tests/ref/pixfmt/rgb555 b/tests/ref/pixfmt/rgb555 new file mode 100644 index 000000000..eecc974d1 --- /dev/null +++ b/tests/ref/pixfmt/rgb555 @@ -0,0 +1,2 @@ +0df2a477af1415a1b8fbf2a3e552bc39 *tests/data/pixfmt/rgb555.yuv +304128 tests/data/pixfmt/rgb555.yuv diff --git a/tests/ref/pixfmt/rgb565 b/tests/ref/pixfmt/rgb565 new file mode 100644 index 000000000..b249f4a0e --- /dev/null +++ b/tests/ref/pixfmt/rgb565 @@ -0,0 +1,2 @@ +efa7c0337cc00c796c6df615223716f1 *tests/data/pixfmt/rgb565.yuv +304128 tests/data/pixfmt/rgb565.yuv diff --git a/tests/ref/pixfmt/yuv410p b/tests/ref/pixfmt/yuv410p new file mode 100644 index 000000000..0f1dcfda8 --- /dev/null +++ b/tests/ref/pixfmt/yuv410p @@ -0,0 +1,2 @@ +507c7e9f0c97660385df977469ca9e6d *tests/data/pixfmt/yuv410p.yuv +304128 tests/data/pixfmt/yuv410p.yuv diff --git a/tests/ref/pixfmt/yuv411p b/tests/ref/pixfmt/yuv411p new file mode 100644 index 000000000..0122b68e4 --- /dev/null +++ b/tests/ref/pixfmt/yuv411p @@ -0,0 +1,2 @@ +8594ea0b8d7c2c964525b0801b5351de *tests/data/pixfmt/yuv411p.yuv +304128 tests/data/pixfmt/yuv411p.yuv diff --git a/tests/ref/pixfmt/yuv420p b/tests/ref/pixfmt/yuv420p new file mode 100644 index 000000000..9adf81f85 --- /dev/null +++ b/tests/ref/pixfmt/yuv420p @@ -0,0 +1,2 @@ +5641dba168ff665af1cdb4a91e1afdd6 *tests/data/pixfmt/yuv420p.yuv +304128 tests/data/pixfmt/yuv420p.yuv diff --git a/tests/ref/pixfmt/yuv422p b/tests/ref/pixfmt/yuv422p new file mode 100644 index 000000000..4240ec95a --- /dev/null +++ b/tests/ref/pixfmt/yuv422p @@ -0,0 +1,2 @@ +ac68f9fdd9d55efd0306d9b004038761 *tests/data/pixfmt/yuv422p.yuv +304128 tests/data/pixfmt/yuv422p.yuv diff --git a/tests/ref/pixfmt/yuv440p b/tests/ref/pixfmt/yuv440p new file mode 100644 index 000000000..4e6ee4df6 --- /dev/null +++ b/tests/ref/pixfmt/yuv440p @@ -0,0 +1,2 @@ +00b85790df5740bab95e2559d81603a7 *tests/data/pixfmt/yuv440p.yuv +304128 tests/data/pixfmt/yuv440p.yuv diff --git a/tests/ref/pixfmt/yuv444p b/tests/ref/pixfmt/yuv444p new file mode 100644 index 000000000..85c871229 --- /dev/null +++ b/tests/ref/pixfmt/yuv444p @@ -0,0 +1,2 @@ +5641dba168ff665af1cdb4a91e1afdd6 *tests/data/pixfmt/yuv444p.yuv +304128 tests/data/pixfmt/yuv444p.yuv diff --git a/tests/ref/pixfmt/yuvj420p b/tests/ref/pixfmt/yuvj420p new file mode 100644 index 000000000..47a729ed4 --- /dev/null +++ b/tests/ref/pixfmt/yuvj420p @@ -0,0 +1,2 @@ +e176bd14185788110e055f945de7f95f *tests/data/pixfmt/yuvj420p.yuv +304128 tests/data/pixfmt/yuvj420p.yuv diff --git a/tests/ref/pixfmt/yuvj422p b/tests/ref/pixfmt/yuvj422p new file mode 100644 index 000000000..6ab97d59d --- /dev/null +++ b/tests/ref/pixfmt/yuvj422p @@ -0,0 +1,2 @@ +472028e46a81c98d9b2477507def4723 *tests/data/pixfmt/yuvj422p.yuv +304128 tests/data/pixfmt/yuvj422p.yuv diff --git a/tests/ref/pixfmt/yuvj440p b/tests/ref/pixfmt/yuvj440p new file mode 100644 index 000000000..2beeae52c --- /dev/null +++ b/tests/ref/pixfmt/yuvj440p @@ -0,0 +1,2 @@ +4d8d402c45d913038d4b725396719111 *tests/data/pixfmt/yuvj440p.yuv +304128 tests/data/pixfmt/yuvj440p.yuv diff --git a/tests/ref/pixfmt/yuvj444p b/tests/ref/pixfmt/yuvj444p new file mode 100644 index 000000000..63fb813d4 --- /dev/null +++ b/tests/ref/pixfmt/yuvj444p @@ -0,0 +1,2 @@ +c10442da177c9f1d12be3c53be6fa12c *tests/data/pixfmt/yuvj444p.yuv +304128 tests/data/pixfmt/yuvj444p.yuv diff --git a/tests/ref/pixfmt/yuyv422 b/tests/ref/pixfmt/yuyv422 new file mode 100644 index 000000000..097869000 --- /dev/null +++ b/tests/ref/pixfmt/yuyv422 @@ -0,0 +1,2 @@ +ac68f9fdd9d55efd0306d9b004038761 *tests/data/pixfmt/yuyv422.yuv +304128 tests/data/pixfmt/yuyv422.yuv diff --git a/tests/ref/seek/lavf-al b/tests/ref/seek/lavf-al new file mode 100644 index 000000000..8d517fa2b --- /dev/null +++ b/tests/ref/seek/lavf-al @@ -0,0 +1,53 @@ +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size: 882 +ret: 0 st:-1 flags:0 ts:-1.000000 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size: 882 +ret: 0 st:-1 flags:1 ts: 1.894167 +ret: 0 st: 0 flags:1 dts: 1.894150 pts: 1.894150 pos: 41766 size: 882 +ret: 0 st: 0 flags:0 ts: 0.788345 +ret: 0 st: 0 flags:1 dts: 0.788345 pts: 0.788345 pos: 17383 size: 882 +ret: 0 st: 0 flags:1 ts:-0.317506 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size: 882 +ret: 0 st:-1 flags:0 ts: 2.576668 +ret:-EOF +ret: 0 st:-1 flags:1 ts: 1.470835 +ret: 0 st: 0 flags:1 dts: 1.470839 pts: 1.470839 pos: 32432 size: 882 +ret: 0 st: 0 flags:0 ts: 0.364989 +ret: 0 st: 0 flags:1 dts: 0.364989 pts: 0.364989 pos: 8048 size: 882 +ret: 0 st: 0 flags:1 ts:-0.740816 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size: 882 +ret: 0 st:-1 flags:0 ts: 2.153336 +ret:-EOF +ret: 0 st:-1 flags:1 ts: 1.047503 +ret: 0 st: 0 flags:1 dts: 1.047483 pts: 1.047483 pos: 23097 size: 882 +ret: 0 st: 0 flags:0 ts:-0.058322 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size: 882 +ret: 0 st: 0 flags:1 ts: 2.835828 +ret:-EOF +ret: 0 st:-1 flags:0 ts: 1.730004 +ret: 0 st: 0 flags:1 dts: 1.730023 pts: 1.730023 pos: 38147 size: 882 +ret: 0 st:-1 flags:1 ts: 0.624171 +ret: 0 st: 0 flags:1 dts: 0.624172 pts: 0.624172 pos: 13763 size: 882 +ret: 0 st: 0 flags:0 ts:-0.481678 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size: 882 +ret: 0 st: 0 flags:1 ts: 2.412517 +ret:-EOF +ret: 0 st:-1 flags:0 ts: 1.306672 +ret: 0 st: 0 flags:1 dts: 1.306667 pts: 1.306667 pos: 28812 size: 882 +ret: 0 st:-1 flags:1 ts: 0.200839 +ret: 0 st: 0 flags:1 dts: 0.200816 pts: 0.200816 pos: 4428 size: 882 +ret: 0 st: 0 flags:0 ts:-0.904989 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size: 882 +ret: 0 st: 0 flags:1 ts: 1.989161 +ret: 0 st: 0 flags:1 dts: 1.989161 pts: 1.989161 pos: 43861 size: 239 +ret: 0 st:-1 flags:0 ts: 0.883340 +ret: 0 st: 0 flags:1 dts: 0.883356 pts: 0.883356 pos: 19478 size: 882 +ret: 0 st:-1 flags:1 ts:-0.222493 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size: 882 +ret: 0 st: 0 flags:0 ts: 2.671655 +ret:-EOF +ret: 0 st: 0 flags:1 ts: 1.565850 +ret: 0 st: 0 flags:1 dts: 1.565850 pts: 1.565850 pos: 34527 size: 882 +ret: 0 st:-1 flags:0 ts: 0.460008 +ret: 0 st: 0 flags:1 dts: 0.460000 pts: 0.460000 pos: 10143 size: 882 +ret: 0 st:-1 flags:1 ts:-0.645825 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size: 882 diff --git a/tests/ref/seek/lavf-dv b/tests/ref/seek/lavf-dv new file mode 100644 index 000000000..0000ff5ab --- /dev/null +++ b/tests/ref/seek/lavf-dv @@ -0,0 +1,53 @@ +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size:144000 +ret: 0 st:-1 flags:0 ts:-1.000000 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size:144000 +ret: 0 st:-1 flags:1 ts: 1.894167 +ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:3456000 size:144000 +ret: 0 st: 0 flags:0 ts: 0.800000 +ret: 0 st: 0 flags:1 dts: 0.800000 pts: 0.800000 pos:2880000 size:144000 +ret: 0 st: 0 flags:1 ts:-0.320000 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size:144000 +ret: 0 st: 1 flags:0 ts: 2.576667 +ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:3456000 size:144000 +ret: 0 st: 1 flags:1 ts: 1.470833 +ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:3456000 size:144000 +ret: 0 st:-1 flags:0 ts: 0.365002 +ret: 0 st: 0 flags:1 dts: 0.360000 pts: 0.360000 pos:1296000 size:144000 +ret: 0 st:-1 flags:1 ts:-0.740831 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size:144000 +ret: 0 st: 0 flags:0 ts: 2.160000 +ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:3456000 size:144000 +ret: 0 st: 0 flags:1 ts: 1.040000 +ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:3456000 size:144000 +ret: 0 st: 1 flags:0 ts:-0.058333 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size:144000 +ret: 0 st: 1 flags:1 ts: 2.835833 +ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:3456000 size:144000 +ret: 0 st:-1 flags:0 ts: 1.730004 +ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:3456000 size:144000 +ret: 0 st:-1 flags:1 ts: 0.624171 +ret: 0 st: 0 flags:1 dts: 0.640000 pts: 0.640000 pos:2304000 size:144000 +ret: 0 st: 0 flags:0 ts:-0.480000 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size:144000 +ret: 0 st: 0 flags:1 ts: 2.400000 +ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:3456000 size:144000 +ret: 0 st: 1 flags:0 ts: 1.306667 +ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:3456000 size:144000 +ret: 0 st: 1 flags:1 ts: 0.200833 +ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:3456000 size:144000 +ret: 0 st:-1 flags:0 ts:-0.904994 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size:144000 +ret: 0 st:-1 flags:1 ts: 1.989173 +ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:3456000 size:144000 +ret: 0 st: 0 flags:0 ts: 0.880000 +ret: 0 st: 0 flags:1 dts: 0.880000 pts: 0.880000 pos:3168000 size:144000 +ret: 0 st: 0 flags:1 ts:-0.240000 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size:144000 +ret: 0 st: 1 flags:0 ts: 2.671667 +ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:3456000 size:144000 +ret: 0 st: 1 flags:1 ts: 1.565833 +ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:3456000 size:144000 +ret: 0 st:-1 flags:0 ts: 0.460008 +ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos:1728000 size:144000 +ret: 0 st:-1 flags:1 ts:-0.645825 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size:144000 diff --git a/tests/ref/seek/lavf-flv b/tests/ref/seek/lavf-flv new file mode 100644 index 000000000..9d86a811e --- /dev/null +++ b/tests/ref/seek/lavf-flv @@ -0,0 +1,44 @@ +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 205 size: 31074 +ret: 0 st:-1 flags:0 ts:-1.000000 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 205 size: 31074 +ret: 0 st:-1 flags:1 ts: 1.894167 +ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 298404 size: 31134 +ret: 0 st: 0 flags:0 ts: 0.788000 +ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 298404 size: 31134 +ret:-1 st: 0 flags:1 ts:-0.317000 +ret:-1 st:-1 flags:0 ts: 2.576668 +ret: 0 st:-1 flags:1 ts: 1.470835 +ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 298404 size: 31134 +ret: 0 st: 0 flags:0 ts: 0.365000 +ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 149444 size: 31125 +ret:-1 st: 0 flags:1 ts:-0.741000 +ret:-1 st:-1 flags:0 ts: 2.153336 +ret: 0 st:-1 flags:1 ts: 1.047503 +ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 298404 size: 31134 +ret: 0 st: 0 flags:0 ts:-0.058000 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 205 size: 31074 +ret: 0 st: 0 flags:1 ts: 2.836000 +ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 298404 size: 31134 +ret:-1 st:-1 flags:0 ts: 1.730004 +ret: 0 st:-1 flags:1 ts: 0.624171 +ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 149444 size: 31125 +ret: 0 st: 0 flags:0 ts:-0.482000 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 205 size: 31074 +ret: 0 st: 0 flags:1 ts: 2.413000 +ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 298404 size: 31134 +ret:-1 st:-1 flags:0 ts: 1.306672 +ret: 0 st:-1 flags:1 ts: 0.200839 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 205 size: 31074 +ret: 0 st: 0 flags:0 ts:-0.905000 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 205 size: 31074 +ret: 0 st: 0 flags:1 ts: 1.989000 +ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 298404 size: 31134 +ret: 0 st:-1 flags:0 ts: 0.883340 +ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 298404 size: 31134 +ret:-1 st:-1 flags:1 ts:-0.222493 +ret:-1 st: 0 flags:0 ts: 2.672000 +ret: 0 st: 0 flags:1 ts: 1.566000 +ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 298404 size: 31134 +ret: 0 st:-1 flags:0 ts: 0.460008 +ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos: 149444 size: 31125 +ret:-1 st:-1 flags:1 ts:-0.645825 diff --git a/tests/ref/seek/lavf-mkv b/tests/ref/seek/lavf-mkv index cea34e99a..6ed1f3a76 100644 --- a/tests/ref/seek/lavf-mkv +++ b/tests/ref/seek/lavf-mkv @@ -1,48 +1,48 @@ -ret: 0 st: 1 flags:1 dts: 0.000000 pts: 0.000000 pos: 834 size: 208 +ret: 0 st: 1 flags:1 dts: 0.000000 pts: 0.000000 pos: 803 size: 208 ret: 0 st:-1 flags:0 ts:-1.000000 -ret: 0 st: 0 flags:1 dts: 0.011000 pts: 0.011000 pos: 1050 size: 27837 +ret: 0 st: 0 flags:1 dts: 0.011000 pts: 0.011000 pos: 1019 size: 27837 ret: 0 st:-1 flags:1 ts: 1.894167 -ret: 0 st: 0 flags:1 dts: 0.971000 pts: 0.971000 pos: 292476 size: 27834 +ret: 0 st: 0 flags:1 dts: 0.971000 pts: 0.971000 pos: 292435 size: 27834 ret: 0 st: 0 flags:0 ts: 0.788000 -ret: 0 st: 0 flags:1 dts: 0.971000 pts: 0.971000 pos: 292476 size: 27834 +ret: 0 st: 0 flags:1 dts: 0.971000 pts: 0.971000 pos: 292435 size: 27834 ret: 0 st: 0 flags:1 ts:-0.317000 -ret: 0 st: 0 flags:1 dts: 0.011000 pts: 0.011000 pos: 1050 size: 27837 +ret: 0 st: 0 flags:1 dts: 0.011000 pts: 0.011000 pos: 1019 size: 27837 ret:-1 st: 1 flags:0 ts: 2.577000 ret: 0 st: 1 flags:1 ts: 1.471000 -ret: 0 st: 1 flags:1 dts: 0.993000 pts: 0.993000 pos: 320317 size: 209 +ret: 0 st: 1 flags:1 dts: 0.993000 pts: 0.993000 pos: 320276 size: 209 ret: 0 st:-1 flags:0 ts: 0.365002 -ret: 0 st: 0 flags:1 dts: 0.491000 pts: 0.491000 pos: 147023 size: 27925 +ret: 0 st: 0 flags:1 dts: 0.491000 pts: 0.491000 pos: 146987 size: 27925 ret: 0 st:-1 flags:1 ts:-0.740831 -ret: 0 st: 0 flags:1 dts: 0.011000 pts: 0.011000 pos: 1050 size: 27837 +ret: 0 st: 0 flags:1 dts: 0.011000 pts: 0.011000 pos: 1019 size: 27837 ret:-1 st: 0 flags:0 ts: 2.153000 ret: 0 st: 0 flags:1 ts: 1.048000 -ret: 0 st: 0 flags:1 dts: 0.971000 pts: 0.971000 pos: 292476 size: 27834 +ret: 0 st: 0 flags:1 dts: 0.971000 pts: 0.971000 pos: 292435 size: 27834 ret: 0 st: 1 flags:0 ts:-0.058000 -ret: 0 st: 1 flags:1 dts: 0.000000 pts: 0.000000 pos: 834 size: 208 +ret: 0 st: 1 flags:1 dts: 0.000000 pts: 0.000000 pos: 803 size: 208 ret: 0 st: 1 flags:1 ts: 2.836000 -ret: 0 st: 1 flags:1 dts: 0.993000 pts: 0.993000 pos: 320317 size: 209 +ret: 0 st: 1 flags:1 dts: 0.993000 pts: 0.993000 pos: 320276 size: 209 ret:-1 st:-1 flags:0 ts: 1.730004 ret: 0 st:-1 flags:1 ts: 0.624171 -ret: 0 st: 0 flags:1 dts: 0.491000 pts: 0.491000 pos: 147023 size: 27925 +ret: 0 st: 0 flags:1 dts: 0.491000 pts: 0.491000 pos: 146987 size: 27925 ret: 0 st: 0 flags:0 ts:-0.482000 -ret: 0 st: 0 flags:1 dts: 0.011000 pts: 0.011000 pos: 1050 size: 27837 +ret: 0 st: 0 flags:1 dts: 0.011000 pts: 0.011000 pos: 1019 size: 27837 ret: 0 st: 0 flags:1 ts: 2.413000 -ret: 0 st: 0 flags:1 dts: 0.971000 pts: 0.971000 pos: 292476 size: 27834 +ret: 0 st: 0 flags:1 dts: 0.971000 pts: 0.971000 pos: 292435 size: 27834 ret:-1 st: 1 flags:0 ts: 1.307000 ret: 0 st: 1 flags:1 ts: 0.201000 -ret: 0 st: 1 flags:1 dts: 0.000000 pts: 0.000000 pos: 834 size: 208 +ret: 0 st: 1 flags:1 dts: 0.000000 pts: 0.000000 pos: 803 size: 208 ret: 0 st:-1 flags:0 ts:-0.904994 -ret: 0 st: 0 flags:1 dts: 0.011000 pts: 0.011000 pos: 1050 size: 27837 +ret: 0 st: 0 flags:1 dts: 0.011000 pts: 0.011000 pos: 1019 size: 27837 ret: 0 st:-1 flags:1 ts: 1.989173 -ret: 0 st: 0 flags:1 dts: 0.971000 pts: 0.971000 pos: 292476 size: 27834 +ret: 0 st: 0 flags:1 dts: 0.971000 pts: 0.971000 pos: 292435 size: 27834 ret: 0 st: 0 flags:0 ts: 0.883000 -ret: 0 st: 0 flags:1 dts: 0.971000 pts: 0.971000 pos: 292476 size: 27834 +ret: 0 st: 0 flags:1 dts: 0.971000 pts: 0.971000 pos: 292435 size: 27834 ret: 0 st: 0 flags:1 ts:-0.222000 -ret: 0 st: 0 flags:1 dts: 0.011000 pts: 0.011000 pos: 1050 size: 27837 +ret: 0 st: 0 flags:1 dts: 0.011000 pts: 0.011000 pos: 1019 size: 27837 ret:-1 st: 1 flags:0 ts: 2.672000 ret: 0 st: 1 flags:1 ts: 1.566000 -ret: 0 st: 1 flags:1 dts: 0.993000 pts: 0.993000 pos: 320317 size: 209 +ret: 0 st: 1 flags:1 dts: 0.993000 pts: 0.993000 pos: 320276 size: 209 ret: 0 st:-1 flags:0 ts: 0.460008 -ret: 0 st: 0 flags:1 dts: 0.491000 pts: 0.491000 pos: 147023 size: 27925 +ret: 0 st: 0 flags:1 dts: 0.491000 pts: 0.491000 pos: 146987 size: 27925 ret: 0 st:-1 flags:1 ts:-0.645825 -ret: 0 st: 0 flags:1 dts: 0.011000 pts: 0.011000 pos: 1050 size: 27837 +ret: 0 st: 0 flags:1 dts: 0.011000 pts: 0.011000 pos: 1019 size: 27837 diff --git a/tests/ref/seek/lavf-mxf b/tests/ref/seek/lavf-mxf index 93d419722..495badd60 100644 --- a/tests/ref/seek/lavf-mxf +++ b/tests/ref/seek/lavf-mxf @@ -1,48 +1,48 @@ -ret: 0 st: 0 flags:1 dts:-0.040000 pts: 0.000000 pos: 6144 size: 24801 +ret: 0 st: 0 flags:1 dts:-0.040000 pts: 0.000000 pos: 7168 size: 24801 ret: 0 st:-1 flags:0 ts:-1.000000 -ret: 0 st: 0 flags:1 dts:-0.040000 pts: 0.000000 pos: 6144 size: 24801 +ret: 0 st: 0 flags:1 dts:-0.040000 pts: 0.000000 pos: 7168 size: 24801 ret: 0 st:-1 flags:1 ts: 1.894167 -ret: 0 st: 0 flags:1 dts: 0.840000 pts: 0.960000 pos: 460288 size: 24711 +ret: 0 st: 0 flags:1 dts: 0.840000 pts: 0.960000 pos: 461312 size: 24711 ret: 0 st: 0 flags:0 ts: 0.800000 -ret: 0 st: 0 flags:1 dts: 0.840000 pts: 0.960000 pos: 460288 size: 24711 +ret: 0 st: 0 flags:1 dts: 0.840000 pts: 0.960000 pos: 461312 size: 24711 ret: 0 st: 0 flags:1 ts:-0.320000 -ret: 0 st: 0 flags:1 dts:-0.040000 pts: 0.000000 pos: 6144 size: 24801 +ret: 0 st: 0 flags:1 dts:-0.040000 pts: 0.000000 pos: 7168 size: 24801 ret:-1 st: 1 flags:0 ts: 2.576667 ret: 0 st: 1 flags:1 ts: 1.470833 -ret: 0 st: 0 flags:1 dts: 0.840000 pts: 0.960000 pos: 460288 size: 24711 +ret: 0 st: 0 flags:1 dts: 0.840000 pts: 0.960000 pos: 461312 size: 24711 ret: 0 st:-1 flags:0 ts: 0.365002 -ret: 0 st: 0 flags:1 dts: 0.360000 pts: 0.480000 pos: 211456 size: 24786 +ret: 0 st: 0 flags:1 dts: 0.360000 pts: 0.480000 pos: 212480 size: 24786 ret: 0 st:-1 flags:1 ts:-0.740831 -ret: 0 st: 0 flags:1 dts:-0.040000 pts: 0.000000 pos: 6144 size: 24801 +ret: 0 st: 0 flags:1 dts:-0.040000 pts: 0.000000 pos: 7168 size: 24801 ret:-1 st: 0 flags:0 ts: 2.160000 ret: 0 st: 0 flags:1 ts: 1.040000 -ret: 0 st: 0 flags:1 dts: 0.840000 pts: 0.960000 pos: 460288 size: 24711 +ret: 0 st: 0 flags:1 dts: 0.840000 pts: 0.960000 pos: 461312 size: 24711 ret: 0 st: 1 flags:0 ts:-0.058333 -ret: 0 st: 0 flags:1 dts:-0.040000 pts: 0.000000 pos: 6144 size: 24801 +ret: 0 st: 0 flags:1 dts:-0.040000 pts: 0.000000 pos: 7168 size: 24801 ret: 0 st: 1 flags:1 ts: 2.835833 -ret: 0 st: 0 flags:1 dts: 0.840000 pts: 0.960000 pos: 460288 size: 24711 +ret: 0 st: 0 flags:1 dts: 0.840000 pts: 0.960000 pos: 461312 size: 24711 ret:-1 st:-1 flags:0 ts: 1.730004 ret: 0 st:-1 flags:1 ts: 0.624171 -ret: 0 st: 0 flags:1 dts: 0.360000 pts: 0.480000 pos: 211456 size: 24786 +ret: 0 st: 0 flags:1 dts: 0.360000 pts: 0.480000 pos: 212480 size: 24786 ret: 0 st: 0 flags:0 ts:-0.480000 -ret: 0 st: 0 flags:1 dts:-0.040000 pts: 0.000000 pos: 6144 size: 24801 +ret: 0 st: 0 flags:1 dts:-0.040000 pts: 0.000000 pos: 7168 size: 24801 ret: 0 st: 0 flags:1 ts: 2.400000 -ret: 0 st: 0 flags:1 dts: 0.840000 pts: 0.960000 pos: 460288 size: 24711 +ret: 0 st: 0 flags:1 dts: 0.840000 pts: 0.960000 pos: 461312 size: 24711 ret:-1 st: 1 flags:0 ts: 1.306667 ret: 0 st: 1 flags:1 ts: 0.200833 -ret: 0 st: 0 flags:1 dts:-0.040000 pts: 0.000000 pos: 6144 size: 24801 +ret: 0 st: 0 flags:1 dts:-0.040000 pts: 0.000000 pos: 7168 size: 24801 ret: 0 st:-1 flags:0 ts:-0.904994 -ret: 0 st: 0 flags:1 dts:-0.040000 pts: 0.000000 pos: 6144 size: 24801 +ret: 0 st: 0 flags:1 dts:-0.040000 pts: 0.000000 pos: 7168 size: 24801 ret: 0 st:-1 flags:1 ts: 1.989173 -ret: 0 st: 0 flags:1 dts: 0.840000 pts: 0.960000 pos: 460288 size: 24711 +ret: 0 st: 0 flags:1 dts: 0.840000 pts: 0.960000 pos: 461312 size: 24711 ret: 0 st: 0 flags:0 ts: 0.880000 -ret: 0 st: 0 flags:1 dts: 0.840000 pts: 0.960000 pos: 460288 size: 24711 +ret: 0 st: 0 flags:1 dts: 0.840000 pts: 0.960000 pos: 461312 size: 24711 ret: 0 st: 0 flags:1 ts:-0.240000 -ret: 0 st: 0 flags:1 dts:-0.040000 pts: 0.000000 pos: 6144 size: 24801 +ret: 0 st: 0 flags:1 dts:-0.040000 pts: 0.000000 pos: 7168 size: 24801 ret:-1 st: 1 flags:0 ts: 2.671667 ret: 0 st: 1 flags:1 ts: 1.565833 -ret: 0 st: 0 flags:1 dts: 0.840000 pts: 0.960000 pos: 460288 size: 24711 +ret: 0 st: 0 flags:1 dts: 0.840000 pts: 0.960000 pos: 461312 size: 24711 ret: 0 st:-1 flags:0 ts: 0.460008 -ret: 0 st: 0 flags:1 dts: 0.360000 pts: 0.480000 pos: 211456 size: 24786 +ret: 0 st: 0 flags:1 dts: 0.360000 pts: 0.480000 pos: 212480 size: 24786 ret: 0 st:-1 flags:1 ts:-0.645825 -ret: 0 st: 0 flags:1 dts:-0.040000 pts: 0.000000 pos: 6144 size: 24801 +ret: 0 st: 0 flags:1 dts:-0.040000 pts: 0.000000 pos: 7168 size: 24801 diff --git a/tests/ref/seek/lavf-mxf_d10 b/tests/ref/seek/lavf-mxf_d10 index 5a682f092..ad3e4dac2 100644 --- a/tests/ref/seek/lavf-mxf_d10 +++ b/tests/ref/seek/lavf-mxf_d10 @@ -1,53 +1,53 @@ -ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 6144 size:150000 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 7168 size:150000 ret: 0 st:-1 flags:0 ts:-1.000000 -ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 6144 size:150000 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 7168 size:150000 ret: 0 st:-1 flags:1 ts: 1.894167 -ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:5117952 size:150000 +ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:5118976 size:150000 ret: 0 st: 0 flags:0 ts: 0.800000 -ret: 0 st: 0 flags:1 dts: 0.800000 pts: 0.800000 pos:4265984 size:150000 +ret: 0 st: 0 flags:1 dts: 0.800000 pts: 0.800000 pos:4267008 size:150000 ret: 0 st: 0 flags:1 ts:-0.320000 -ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 6144 size:150000 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 7168 size:150000 ret: 0 st: 1 flags:0 ts: 2.576667 -ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:5117952 size:150000 +ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:5118976 size:150000 ret: 0 st: 1 flags:1 ts: 1.470833 -ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:5117952 size:150000 +ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:5118976 size:150000 ret: 0 st:-1 flags:0 ts: 0.365002 -ret: 0 st: 0 flags:1 dts: 0.360000 pts: 0.360000 pos:1923072 size:150000 +ret: 0 st: 0 flags:1 dts: 0.360000 pts: 0.360000 pos:1924096 size:150000 ret: 0 st:-1 flags:1 ts:-0.740831 -ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 6144 size:150000 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 7168 size:150000 ret: 0 st: 0 flags:0 ts: 2.160000 -ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:5117952 size:150000 +ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:5118976 size:150000 ret: 0 st: 0 flags:1 ts: 1.040000 -ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:5117952 size:150000 +ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:5118976 size:150000 ret: 0 st: 1 flags:0 ts:-0.058333 -ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 6144 size:150000 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 7168 size:150000 ret: 0 st: 1 flags:1 ts: 2.835833 -ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:5117952 size:150000 +ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:5118976 size:150000 ret: 0 st:-1 flags:0 ts: 1.730004 -ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:5117952 size:150000 +ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:5118976 size:150000 ret: 0 st:-1 flags:1 ts: 0.624171 -ret: 0 st: 0 flags:1 dts: 0.640000 pts: 0.640000 pos:3414016 size:150000 +ret: 0 st: 0 flags:1 dts: 0.640000 pts: 0.640000 pos:3415040 size:150000 ret: 0 st: 0 flags:0 ts:-0.480000 -ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 6144 size:150000 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 7168 size:150000 ret: 0 st: 0 flags:1 ts: 2.400000 -ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:5117952 size:150000 +ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:5118976 size:150000 ret: 0 st: 1 flags:0 ts: 1.306667 -ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:5117952 size:150000 +ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:5118976 size:150000 ret: 0 st: 1 flags:1 ts: 0.200833 -ret: 0 st: 0 flags:1 dts: 0.200000 pts: 0.200000 pos:1071104 size:150000 +ret: 0 st: 0 flags:1 dts: 0.200000 pts: 0.200000 pos:1072128 size:150000 ret: 0 st:-1 flags:0 ts:-0.904994 -ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 6144 size:150000 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 7168 size:150000 ret: 0 st:-1 flags:1 ts: 1.989173 -ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:5117952 size:150000 +ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:5118976 size:150000 ret: 0 st: 0 flags:0 ts: 0.880000 -ret: 0 st: 0 flags:1 dts: 0.880000 pts: 0.880000 pos:4691968 size:150000 +ret: 0 st: 0 flags:1 dts: 0.880000 pts: 0.880000 pos:4692992 size:150000 ret: 0 st: 0 flags:1 ts:-0.240000 -ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 6144 size:150000 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 7168 size:150000 ret: 0 st: 1 flags:0 ts: 2.671667 -ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:5117952 size:150000 +ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:5118976 size:150000 ret: 0 st: 1 flags:1 ts: 1.565833 -ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:5117952 size:150000 +ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:5118976 size:150000 ret: 0 st:-1 flags:0 ts: 0.460008 -ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos:2562048 size:150000 +ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos:2563072 size:150000 ret: 0 st:-1 flags:1 ts:-0.645825 -ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 6144 size:150000 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 7168 size:150000 diff --git a/tests/ref/seek/lavf-mxf_dv25 b/tests/ref/seek/lavf-mxf_dv25 index 42b3bbdfc..755b84723 100644 --- a/tests/ref/seek/lavf-mxf_dv25 +++ b/tests/ref/seek/lavf-mxf_dv25 @@ -1,53 +1,53 @@ -ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 6144 size:144000 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 7168 size:144000 ret: 0 st:-1 flags:0 ts:-1.000000 -ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 6144 size:144000 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 7168 size:144000 ret: 0 st:-1 flags:1 ts: 1.894167 -ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:3680256 size:144000 +ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:3681280 size:144000 ret: 0 st: 0 flags:0 ts: 0.800000 -ret: 0 st: 0 flags:1 dts: 0.800000 pts: 0.800000 pos:3067904 size:144000 +ret: 0 st: 0 flags:1 dts: 0.800000 pts: 0.800000 pos:3068928 size:144000 ret: 0 st: 0 flags:1 ts:-0.320000 -ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 6144 size:144000 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 7168 size:144000 ret: 0 st: 1 flags:0 ts: 2.576667 -ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos:3680256 size:144000 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos:3681280 size:144000 ret: 0 st: 1 flags:1 ts: 1.470833 -ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos:3680256 size:144000 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos:3681280 size:144000 ret: 0 st:-1 flags:0 ts: 0.365002 -ret: 0 st: 0 flags:1 dts: 0.360000 pts: 0.360000 pos:1383936 size:144000 +ret: 0 st: 0 flags:1 dts: 0.360000 pts: 0.360000 pos:1384960 size:144000 ret: 0 st:-1 flags:1 ts:-0.740831 -ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 6144 size:144000 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 7168 size:144000 ret: 0 st: 0 flags:0 ts: 2.160000 -ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:3680256 size:144000 +ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:3681280 size:144000 ret: 0 st: 0 flags:1 ts: 1.040000 -ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:3680256 size:144000 +ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:3681280 size:144000 ret: 0 st: 1 flags:0 ts:-0.058333 -ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 6144 size:144000 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 7168 size:144000 ret: 0 st: 1 flags:1 ts: 2.835833 -ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos:3680256 size:144000 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos:3681280 size:144000 ret: 0 st:-1 flags:0 ts: 1.730004 -ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:3680256 size:144000 +ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:3681280 size:144000 ret: 0 st:-1 flags:1 ts: 0.624171 -ret: 0 st: 0 flags:1 dts: 0.640000 pts: 0.640000 pos:2455552 size:144000 +ret: 0 st: 0 flags:1 dts: 0.640000 pts: 0.640000 pos:2456576 size:144000 ret: 0 st: 0 flags:0 ts:-0.480000 -ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 6144 size:144000 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 7168 size:144000 ret: 0 st: 0 flags:1 ts: 2.400000 -ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:3680256 size:144000 +ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:3681280 size:144000 ret: 0 st: 1 flags:0 ts: 1.306667 -ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos:3680256 size:144000 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos:3681280 size:144000 ret: 0 st: 1 flags:1 ts: 0.200833 -ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 771584 size:144000 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 772608 size:144000 ret: 0 st:-1 flags:0 ts:-0.904994 -ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 6144 size:144000 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 7168 size:144000 ret: 0 st:-1 flags:1 ts: 1.989173 -ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:3680256 size:144000 +ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:3681280 size:144000 ret: 0 st: 0 flags:0 ts: 0.880000 -ret: 0 st: 0 flags:1 dts: 0.880000 pts: 0.880000 pos:3374080 size:144000 +ret: 0 st: 0 flags:1 dts: 0.880000 pts: 0.880000 pos:3375104 size:144000 ret: 0 st: 0 flags:1 ts:-0.240000 -ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 6144 size:144000 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 7168 size:144000 ret: 0 st: 1 flags:0 ts: 2.671667 -ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos:3680256 size:144000 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos:3681280 size:144000 ret: 0 st: 1 flags:1 ts: 1.565833 -ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos:3680256 size:144000 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos:3681280 size:144000 ret: 0 st:-1 flags:0 ts: 0.460008 -ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos:1843200 size:144000 +ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos:1844224 size:144000 ret: 0 st:-1 flags:1 ts:-0.645825 -ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 6144 size:144000 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 7168 size:144000 diff --git a/tests/ref/seek/lavf-mxf_dvcpro50 b/tests/ref/seek/lavf-mxf_dvcpro50 index c3d9d3afd..f6c26db2f 100644 --- a/tests/ref/seek/lavf-mxf_dvcpro50 +++ b/tests/ref/seek/lavf-mxf_dvcpro50 @@ -1,53 +1,53 @@ -ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 6144 size:288000 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 7168 size:288000 ret: 0 st:-1 flags:0 ts:-1.000000 -ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 6144 size:288000 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 7168 size:288000 ret: 0 st:-1 flags:1 ts: 1.894167 -ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:7133184 size:288000 +ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:7134208 size:288000 ret: 0 st: 0 flags:0 ts: 0.800000 -ret: 0 st: 0 flags:1 dts: 0.800000 pts: 0.800000 pos:5945344 size:288000 +ret: 0 st: 0 flags:1 dts: 0.800000 pts: 0.800000 pos:5946368 size:288000 ret: 0 st: 0 flags:1 ts:-0.320000 -ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 6144 size:288000 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 7168 size:288000 ret: 0 st: 1 flags:0 ts: 2.576667 -ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos:7133184 size:288000 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos:7134208 size:288000 ret: 0 st: 1 flags:1 ts: 1.470833 -ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos:7133184 size:288000 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos:7134208 size:288000 ret: 0 st:-1 flags:0 ts: 0.365002 -ret: 0 st: 0 flags:1 dts: 0.360000 pts: 0.360000 pos:2678784 size:288000 +ret: 0 st: 0 flags:1 dts: 0.360000 pts: 0.360000 pos:2679808 size:288000 ret: 0 st:-1 flags:1 ts:-0.740831 -ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 6144 size:288000 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 7168 size:288000 ret: 0 st: 0 flags:0 ts: 2.160000 -ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:7133184 size:288000 +ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:7134208 size:288000 ret: 0 st: 0 flags:1 ts: 1.040000 -ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:7133184 size:288000 +ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:7134208 size:288000 ret: 0 st: 1 flags:0 ts:-0.058333 -ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 6144 size:288000 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 7168 size:288000 ret: 0 st: 1 flags:1 ts: 2.835833 -ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos:7133184 size:288000 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos:7134208 size:288000 ret: 0 st:-1 flags:0 ts: 1.730004 -ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:7133184 size:288000 +ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:7134208 size:288000 ret: 0 st:-1 flags:1 ts: 0.624171 -ret: 0 st: 0 flags:1 dts: 0.640000 pts: 0.640000 pos:4757504 size:288000 +ret: 0 st: 0 flags:1 dts: 0.640000 pts: 0.640000 pos:4758528 size:288000 ret: 0 st: 0 flags:0 ts:-0.480000 -ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 6144 size:288000 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 7168 size:288000 ret: 0 st: 0 flags:1 ts: 2.400000 -ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:7133184 size:288000 +ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:7134208 size:288000 ret: 0 st: 1 flags:0 ts: 1.306667 -ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos:7133184 size:288000 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos:7134208 size:288000 ret: 0 st: 1 flags:1 ts: 0.200833 -ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos:1490944 size:288000 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos:1491968 size:288000 ret: 0 st:-1 flags:0 ts:-0.904994 -ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 6144 size:288000 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 7168 size:288000 ret: 0 st:-1 flags:1 ts: 1.989173 -ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:7133184 size:288000 +ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:7134208 size:288000 ret: 0 st: 0 flags:0 ts: 0.880000 -ret: 0 st: 0 flags:1 dts: 0.880000 pts: 0.880000 pos:6539264 size:288000 +ret: 0 st: 0 flags:1 dts: 0.880000 pts: 0.880000 pos:6540288 size:288000 ret: 0 st: 0 flags:1 ts:-0.240000 -ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 6144 size:288000 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 7168 size:288000 ret: 0 st: 1 flags:0 ts: 2.671667 -ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos:7133184 size:288000 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos:7134208 size:288000 ret: 0 st: 1 flags:1 ts: 1.565833 -ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos:7133184 size:288000 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos:7134208 size:288000 ret: 0 st:-1 flags:0 ts: 0.460008 -ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos:3569664 size:288000 +ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos:3570688 size:288000 ret: 0 st:-1 flags:1 ts:-0.645825 -ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 6144 size:288000 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 7168 size:288000 diff --git a/tests/ref/seek/lavf-mxf_opatom b/tests/ref/seek/lavf-mxf_opatom index ca17ba78f..11367cd72 100644 --- a/tests/ref/seek/lavf-mxf_opatom +++ b/tests/ref/seek/lavf-mxf_opatom @@ -1,53 +1,53 @@ -ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5145 size:188416 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5657 size:188416 ret: 0 st:-1 flags:0 ts:-1.000000 -ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5145 size:188416 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5657 size:188416 ret: 0 st:-1 flags:1 ts: 1.894167 -ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:4527129 size:188416 +ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:4527641 size:188416 ret: 0 st: 0 flags:0 ts: 0.800000 -ret: 0 st: 0 flags:1 dts: 0.800000 pts: 0.800000 pos:3773465 size:188416 +ret: 0 st: 0 flags:1 dts: 0.800000 pts: 0.800000 pos:3773977 size:188416 ret: 0 st: 0 flags:1 ts:-0.320000 -ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5145 size:188416 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5657 size:188416 ret: 0 st:-1 flags:0 ts: 2.576668 -ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:4527129 size:188416 +ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:4527641 size:188416 ret: 0 st:-1 flags:1 ts: 1.470835 -ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:4527129 size:188416 +ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:4527641 size:188416 ret: 0 st: 0 flags:0 ts: 0.360000 -ret: 0 st: 0 flags:1 dts: 0.360000 pts: 0.360000 pos:1700889 size:188416 +ret: 0 st: 0 flags:1 dts: 0.360000 pts: 0.360000 pos:1701401 size:188416 ret: 0 st: 0 flags:1 ts:-0.760000 -ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5145 size:188416 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5657 size:188416 ret: 0 st:-1 flags:0 ts: 2.153336 -ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:4527129 size:188416 +ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:4527641 size:188416 ret: 0 st:-1 flags:1 ts: 1.047503 -ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:4527129 size:188416 +ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:4527641 size:188416 ret: 0 st: 0 flags:0 ts:-0.040000 -ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5145 size:188416 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5657 size:188416 ret: 0 st: 0 flags:1 ts: 2.840000 -ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:4527129 size:188416 +ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:4527641 size:188416 ret: 0 st:-1 flags:0 ts: 1.730004 -ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:4527129 size:188416 +ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:4527641 size:188416 ret: 0 st:-1 flags:1 ts: 0.624171 -ret: 0 st: 0 flags:1 dts: 0.640000 pts: 0.640000 pos:3019801 size:188416 +ret: 0 st: 0 flags:1 dts: 0.640000 pts: 0.640000 pos:3020313 size:188416 ret: 0 st: 0 flags:0 ts:-0.480000 -ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5145 size:188416 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5657 size:188416 ret: 0 st: 0 flags:1 ts: 2.400000 -ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:4527129 size:188416 +ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:4527641 size:188416 ret: 0 st:-1 flags:0 ts: 1.306672 -ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:4527129 size:188416 +ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:4527641 size:188416 ret: 0 st:-1 flags:1 ts: 0.200839 -ret: 0 st: 0 flags:1 dts: 0.200000 pts: 0.200000 pos: 947225 size:188416 +ret: 0 st: 0 flags:1 dts: 0.200000 pts: 0.200000 pos: 947737 size:188416 ret: 0 st: 0 flags:0 ts:-0.920000 -ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5145 size:188416 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5657 size:188416 ret: 0 st: 0 flags:1 ts: 2.000000 -ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:4527129 size:188416 +ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:4527641 size:188416 ret: 0 st:-1 flags:0 ts: 0.883340 -ret: 0 st: 0 flags:1 dts: 0.880000 pts: 0.880000 pos:4150297 size:188416 +ret: 0 st: 0 flags:1 dts: 0.880000 pts: 0.880000 pos:4150809 size:188416 ret: 0 st:-1 flags:1 ts:-0.222493 -ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5145 size:188416 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5657 size:188416 ret: 0 st: 0 flags:0 ts: 2.680000 -ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:4527129 size:188416 +ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:4527641 size:188416 ret: 0 st: 0 flags:1 ts: 1.560000 -ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:4527129 size:188416 +ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:4527641 size:188416 ret: 0 st:-1 flags:0 ts: 0.460008 -ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos:2266137 size:188416 +ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos:2266649 size:188416 ret: 0 st:-1 flags:1 ts:-0.645825 -ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5145 size:188416 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5657 size:188416 diff --git a/tests/ref/seek/lavf-mxf_opatom_audio b/tests/ref/seek/lavf-mxf_opatom_audio index 2d1a7cc35..9bc0bfcf7 100644 --- a/tests/ref/seek/lavf-mxf_opatom_audio +++ b/tests/ref/seek/lavf-mxf_opatom_audio @@ -1,53 +1,53 @@ -ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 4633 size: 3840 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5657 size: 3840 ret: 0 st:-1 flags:0 ts:-1.000000 -ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 4633 size: 3840 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5657 size: 3840 ret: 0 st:-1 flags:1 ts: 1.894167 -ret: 0 st: 0 flags:1 dts: 0.999979 pts: 0.999979 pos: 100631 size: 2 +ret: 0 st: 0 flags:1 dts: 0.999979 pts: 0.999979 pos: 101655 size: 2 ret: 0 st: 0 flags:0 ts: 0.788333 -ret: 0 st: 0 flags:1 dts: 0.788333 pts: 0.788333 pos: 80313 size: 3840 +ret: 0 st: 0 flags:1 dts: 0.788333 pts: 0.788333 pos: 81337 size: 3840 ret: 0 st: 0 flags:1 ts:-0.317500 -ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 4633 size: 3840 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5657 size: 3840 ret: 0 st:-1 flags:0 ts: 2.576668 -ret: 0 st: 0 flags:1 dts: 0.999979 pts: 0.999979 pos: 100631 size: 2 +ret: 0 st: 0 flags:1 dts: 0.999979 pts: 0.999979 pos: 101655 size: 2 ret: 0 st:-1 flags:1 ts: 1.470835 -ret: 0 st: 0 flags:1 dts: 0.999979 pts: 0.999979 pos: 100631 size: 2 +ret: 0 st: 0 flags:1 dts: 0.999979 pts: 0.999979 pos: 101655 size: 2 ret: 0 st: 0 flags:0 ts: 0.365000 -ret: 0 st: 0 flags:1 dts: 0.365000 pts: 0.365000 pos: 39673 size: 3840 +ret: 0 st: 0 flags:1 dts: 0.365000 pts: 0.365000 pos: 40697 size: 3840 ret: 0 st: 0 flags:1 ts:-0.740833 -ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 4633 size: 3840 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5657 size: 3840 ret: 0 st:-1 flags:0 ts: 2.153336 -ret: 0 st: 0 flags:1 dts: 0.999979 pts: 0.999979 pos: 100631 size: 2 +ret: 0 st: 0 flags:1 dts: 0.999979 pts: 0.999979 pos: 101655 size: 2 ret: 0 st:-1 flags:1 ts: 1.047503 -ret: 0 st: 0 flags:1 dts: 0.999979 pts: 0.999979 pos: 100631 size: 2 +ret: 0 st: 0 flags:1 dts: 0.999979 pts: 0.999979 pos: 101655 size: 2 ret: 0 st: 0 flags:0 ts:-0.058333 -ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 4633 size: 3840 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5657 size: 3840 ret: 0 st: 0 flags:1 ts: 2.835833 -ret: 0 st: 0 flags:1 dts: 0.999979 pts: 0.999979 pos: 100631 size: 2 +ret: 0 st: 0 flags:1 dts: 0.999979 pts: 0.999979 pos: 101655 size: 2 ret: 0 st:-1 flags:0 ts: 1.730004 -ret: 0 st: 0 flags:1 dts: 0.999979 pts: 0.999979 pos: 100631 size: 2 +ret: 0 st: 0 flags:1 dts: 0.999979 pts: 0.999979 pos: 101655 size: 2 ret: 0 st:-1 flags:1 ts: 0.624171 -ret: 0 st: 0 flags:1 dts: 0.624167 pts: 0.624167 pos: 64553 size: 3840 +ret: 0 st: 0 flags:1 dts: 0.624167 pts: 0.624167 pos: 65577 size: 3840 ret: 0 st: 0 flags:0 ts:-0.481667 -ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 4633 size: 3840 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5657 size: 3840 ret: 0 st: 0 flags:1 ts: 2.412500 -ret: 0 st: 0 flags:1 dts: 0.999979 pts: 0.999979 pos: 100631 size: 2 +ret: 0 st: 0 flags:1 dts: 0.999979 pts: 0.999979 pos: 101655 size: 2 ret: 0 st:-1 flags:0 ts: 1.306672 -ret: 0 st: 0 flags:1 dts: 0.999979 pts: 0.999979 pos: 100631 size: 2 +ret: 0 st: 0 flags:1 dts: 0.999979 pts: 0.999979 pos: 101655 size: 2 ret: 0 st:-1 flags:1 ts: 0.200839 -ret: 0 st: 0 flags:1 dts: 0.200833 pts: 0.200833 pos: 23913 size: 3840 +ret: 0 st: 0 flags:1 dts: 0.200833 pts: 0.200833 pos: 24937 size: 3840 ret: 0 st: 0 flags:0 ts:-0.905000 -ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 4633 size: 3840 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5657 size: 3840 ret: 0 st: 0 flags:1 ts: 1.989167 -ret: 0 st: 0 flags:1 dts: 0.999979 pts: 0.999979 pos: 100631 size: 2 +ret: 0 st: 0 flags:1 dts: 0.999979 pts: 0.999979 pos: 101655 size: 2 ret: 0 st:-1 flags:0 ts: 0.883340 -ret: 0 st: 0 flags:1 dts: 0.883333 pts: 0.883333 pos: 89433 size: 3840 +ret: 0 st: 0 flags:1 dts: 0.883333 pts: 0.883333 pos: 90457 size: 3840 ret: 0 st:-1 flags:1 ts:-0.222493 -ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 4633 size: 3840 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5657 size: 3840 ret: 0 st: 0 flags:0 ts: 2.671667 -ret: 0 st: 0 flags:1 dts: 0.999979 pts: 0.999979 pos: 100631 size: 2 +ret: 0 st: 0 flags:1 dts: 0.999979 pts: 0.999979 pos: 101655 size: 2 ret: 0 st: 0 flags:1 ts: 1.565833 -ret: 0 st: 0 flags:1 dts: 0.999979 pts: 0.999979 pos: 100631 size: 2 +ret: 0 st: 0 flags:1 dts: 0.999979 pts: 0.999979 pos: 101655 size: 2 ret: 0 st:-1 flags:0 ts: 0.460008 -ret: 0 st: 0 flags:1 dts: 0.460000 pts: 0.460000 pos: 48793 size: 3840 +ret: 0 st: 0 flags:1 dts: 0.460000 pts: 0.460000 pos: 49817 size: 3840 ret: 0 st:-1 flags:1 ts:-0.645825 -ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 4633 size: 3840 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 5657 size: 3840 diff --git a/tests/ref/seek/lavf-ul b/tests/ref/seek/lavf-ul new file mode 100644 index 000000000..8d517fa2b --- /dev/null +++ b/tests/ref/seek/lavf-ul @@ -0,0 +1,53 @@ +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size: 882 +ret: 0 st:-1 flags:0 ts:-1.000000 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size: 882 +ret: 0 st:-1 flags:1 ts: 1.894167 +ret: 0 st: 0 flags:1 dts: 1.894150 pts: 1.894150 pos: 41766 size: 882 +ret: 0 st: 0 flags:0 ts: 0.788345 +ret: 0 st: 0 flags:1 dts: 0.788345 pts: 0.788345 pos: 17383 size: 882 +ret: 0 st: 0 flags:1 ts:-0.317506 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size: 882 +ret: 0 st:-1 flags:0 ts: 2.576668 +ret:-EOF +ret: 0 st:-1 flags:1 ts: 1.470835 +ret: 0 st: 0 flags:1 dts: 1.470839 pts: 1.470839 pos: 32432 size: 882 +ret: 0 st: 0 flags:0 ts: 0.364989 +ret: 0 st: 0 flags:1 dts: 0.364989 pts: 0.364989 pos: 8048 size: 882 +ret: 0 st: 0 flags:1 ts:-0.740816 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size: 882 +ret: 0 st:-1 flags:0 ts: 2.153336 +ret:-EOF +ret: 0 st:-1 flags:1 ts: 1.047503 +ret: 0 st: 0 flags:1 dts: 1.047483 pts: 1.047483 pos: 23097 size: 882 +ret: 0 st: 0 flags:0 ts:-0.058322 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size: 882 +ret: 0 st: 0 flags:1 ts: 2.835828 +ret:-EOF +ret: 0 st:-1 flags:0 ts: 1.730004 +ret: 0 st: 0 flags:1 dts: 1.730023 pts: 1.730023 pos: 38147 size: 882 +ret: 0 st:-1 flags:1 ts: 0.624171 +ret: 0 st: 0 flags:1 dts: 0.624172 pts: 0.624172 pos: 13763 size: 882 +ret: 0 st: 0 flags:0 ts:-0.481678 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size: 882 +ret: 0 st: 0 flags:1 ts: 2.412517 +ret:-EOF +ret: 0 st:-1 flags:0 ts: 1.306672 +ret: 0 st: 0 flags:1 dts: 1.306667 pts: 1.306667 pos: 28812 size: 882 +ret: 0 st:-1 flags:1 ts: 0.200839 +ret: 0 st: 0 flags:1 dts: 0.200816 pts: 0.200816 pos: 4428 size: 882 +ret: 0 st: 0 flags:0 ts:-0.904989 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size: 882 +ret: 0 st: 0 flags:1 ts: 1.989161 +ret: 0 st: 0 flags:1 dts: 1.989161 pts: 1.989161 pos: 43861 size: 239 +ret: 0 st:-1 flags:0 ts: 0.883340 +ret: 0 st: 0 flags:1 dts: 0.883356 pts: 0.883356 pos: 19478 size: 882 +ret: 0 st:-1 flags:1 ts:-0.222493 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size: 882 +ret: 0 st: 0 flags:0 ts: 2.671655 +ret:-EOF +ret: 0 st: 0 flags:1 ts: 1.565850 +ret: 0 st: 0 flags:1 dts: 1.565850 pts: 1.565850 pos: 34527 size: 882 +ret: 0 st:-1 flags:0 ts: 0.460008 +ret: 0 st: 0 flags:1 dts: 0.460000 pts: 0.460000 pos: 10143 size: 882 +ret: 0 st:-1 flags:1 ts:-0.645825 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size: 882 diff --git a/tests/ref/seek/lavf-y4m b/tests/ref/seek/lavf-y4m new file mode 100644 index 000000000..c416b4657 --- /dev/null +++ b/tests/ref/seek/lavf-y4m @@ -0,0 +1,49 @@ +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 64 size:152064 +ret:-1 st:-1 flags:0 ts:-1.000000 +ret: 0 st:-1 flags:1 ts: 1.894167 +ret:-EOF +ret: 0 st: 0 flags:0 ts: 0.800000 +ret: 0 st: 0 flags:1 dts: 0.800000 pts: 0.800000 pos:3041464 size:152064 +ret: 0 st: 0 flags:1 ts:-0.320000 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 64 size:152064 +ret: 0 st:-1 flags:0 ts: 2.576668 +ret:-EOF +ret: 0 st:-1 flags:1 ts: 1.470835 +ret:-EOF +ret: 0 st: 0 flags:0 ts: 0.360000 +ret: 0 st: 0 flags:1 dts: 0.360000 pts: 0.360000 pos:1368694 size:152064 +ret: 0 st: 0 flags:1 ts:-0.760000 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 64 size:152064 +ret: 0 st:-1 flags:0 ts: 2.153336 +ret:-EOF +ret: 0 st:-1 flags:1 ts: 1.047503 +ret:-EOF +ret:-1 st: 0 flags:0 ts:-0.040000 +ret: 0 st: 0 flags:1 ts: 2.840000 +ret:-EOF +ret: 0 st:-1 flags:0 ts: 1.730004 +ret:-EOF +ret: 0 st:-1 flags:1 ts: 0.624171 +ret: 0 st: 0 flags:1 dts: 0.600000 pts: 0.600000 pos:2281114 size:152064 +ret:-1 st: 0 flags:0 ts:-0.480000 +ret: 0 st: 0 flags:1 ts: 2.400000 +ret:-EOF +ret: 0 st:-1 flags:0 ts: 1.306672 +ret:-EOF +ret: 0 st:-1 flags:1 ts: 0.200839 +ret: 0 st: 0 flags:1 dts: 0.160000 pts: 0.160000 pos: 608344 size:152064 +ret:-1 st: 0 flags:0 ts:-0.920000 +ret: 0 st: 0 flags:1 ts: 2.000000 +ret:-EOF +ret: 0 st:-1 flags:0 ts: 0.883340 +ret: 0 st: 0 flags:1 dts: 0.880000 pts: 0.880000 pos:3345604 size:152064 +ret: 0 st:-1 flags:1 ts:-0.222493 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 64 size:152064 +ret: 0 st: 0 flags:0 ts: 2.680000 +ret:-EOF +ret: 0 st: 0 flags:1 ts: 1.560000 +ret:-EOF +ret: 0 st:-1 flags:0 ts: 0.460008 +ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos:1824904 size:152064 +ret: 0 st:-1 flags:1 ts:-0.645825 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 64 size:152064 diff --git a/tests/ref/vsynth/vsynth1-avui b/tests/ref/vsynth/vsynth1-avui index 1f080532b..8e76b9a11 100644 --- a/tests/ref/vsynth/vsynth1-avui +++ b/tests/ref/vsynth/vsynth1-avui @@ -1,4 +1,4 @@ -25ef49e1aee0b20d4feee89b8dc093b4 *tests/data/fate/vsynth1-avui.mov +be8ffb8056d1fb5f8c500b95bf7af14c *tests/data/fate/vsynth1-avui.mov 42625037 tests/data/fate/vsynth1-avui.mov c5ccac874dbf808e9088bc3107860042 *tests/data/fate/vsynth1-avui.out.rawvideo stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 7603200/ 7603200 diff --git a/tests/ref/vsynth/vsynth1-dnxhd-1080i b/tests/ref/vsynth/vsynth1-dnxhd-1080i index 02f989f30..0e7844b0e 100644 --- a/tests/ref/vsynth/vsynth1-dnxhd-1080i +++ b/tests/ref/vsynth/vsynth1-dnxhd-1080i @@ -1,4 +1,4 @@ -a0234e0a8516d958f423b119aa9e35c4 *tests/data/fate/vsynth1-dnxhd-1080i.mov +af5cbe239839f6282a68f1a106ed3a77 *tests/data/fate/vsynth1-dnxhd-1080i.mov 3031911 tests/data/fate/vsynth1-dnxhd-1080i.mov fed9ed2a5179c9df0ef58772b025e303 *tests/data/fate/vsynth1-dnxhd-1080i.out.rawvideo stddev: 6.18 PSNR: 32.31 MAXDIFF: 64 bytes: 7603200/ 760320 diff --git a/tests/ref/vsynth/vsynth1-dnxhd-1080i-10bit b/tests/ref/vsynth/vsynth1-dnxhd-1080i-10bit index dd96e1423..c3f3fda08 100644 --- a/tests/ref/vsynth/vsynth1-dnxhd-1080i-10bit +++ b/tests/ref/vsynth/vsynth1-dnxhd-1080i-10bit @@ -1,4 +1,4 @@ -f562845d1848bf5d3e524b418b742e01 *tests/data/fate/vsynth1-dnxhd-1080i-10bit.mov +1a8261120bcc764a7bbdd198febff4c7 *tests/data/fate/vsynth1-dnxhd-1080i-10bit.mov 4588391 tests/data/fate/vsynth1-dnxhd-1080i-10bit.mov 31032fcb7e6af79daaac02288254c6d6 *tests/data/fate/vsynth1-dnxhd-1080i-10bit.out.rawvideo stddev: 5.69 PSNR: 33.02 MAXDIFF: 55 bytes: 7603200/ 760320 diff --git a/tests/ref/vsynth/vsynth1-dnxhd-1080i-colr b/tests/ref/vsynth/vsynth1-dnxhd-1080i-colr index ac429667d..1965e3135 100644 --- a/tests/ref/vsynth/vsynth1-dnxhd-1080i-colr +++ b/tests/ref/vsynth/vsynth1-dnxhd-1080i-colr @@ -1,4 +1,4 @@ -5fccdb16c0f14dea1b6b603bac90b97e *tests/data/fate/vsynth1-dnxhd-1080i-colr.mov +2caca2edcb519c88543c38e129ded03b *tests/data/fate/vsynth1-dnxhd-1080i-colr.mov 3031929 tests/data/fate/vsynth1-dnxhd-1080i-colr.mov 6f2d5429ffc4529a76acfeb28b560542 *tests/data/fate/vsynth1-dnxhd-1080i-colr.out.rawvideo stddev: 5.65 PSNR: 33.09 MAXDIFF: 55 bytes: 7603200/ 760320 diff --git a/tests/ref/vsynth/vsynth1-dnxhd-hr-hq-mov b/tests/ref/vsynth/vsynth1-dnxhd-hr-hq-mov index 559c2f018..a8ee88c63 100644 --- a/tests/ref/vsynth/vsynth1-dnxhd-hr-hq-mov +++ b/tests/ref/vsynth/vsynth1-dnxhd-hr-hq-mov @@ -1,4 +1,4 @@ -c8b5d2bde45776bbf13f0262c915f5b9 *tests/data/fate/vsynth1-dnxhd-hr-hq-mov.mov +36729f1faaa24daa9c643428bc87f090 *tests/data/fate/vsynth1-dnxhd-hr-hq-mov.mov 4772599 tests/data/fate/vsynth1-dnxhd-hr-hq-mov.mov 388c7c84573abe28cc963e3ad5e15a31 *tests/data/fate/vsynth1-dnxhd-hr-hq-mov.out.rawvideo stddev: 5.73 PSNR: 32.96 MAXDIFF: 56 bytes: 7603200/ 760320 diff --git a/tests/ref/vsynth/vsynth1-dnxhd-hr-lb-mov b/tests/ref/vsynth/vsynth1-dnxhd-hr-lb-mov index 2e2b4a301..7d2890db5 100644 --- a/tests/ref/vsynth/vsynth1-dnxhd-hr-lb-mov +++ b/tests/ref/vsynth/vsynth1-dnxhd-hr-lb-mov @@ -1,4 +1,4 @@ -254aa3f0be811882ff351172fd391492 *tests/data/fate/vsynth1-dnxhd-hr-lb-mov.mov +ee2f1559d2cf82930d893ca4d0937c01 *tests/data/fate/vsynth1-dnxhd-hr-lb-mov.mov 3748599 tests/data/fate/vsynth1-dnxhd-hr-lb-mov.mov 21c68252f500bada13ccce232e1ecfca *tests/data/fate/vsynth1-dnxhd-hr-lb-mov.out.rawvideo stddev: 5.59 PSNR: 33.17 MAXDIFF: 55 bytes: 7603200/ 760320 diff --git a/tests/ref/vsynth/vsynth1-dnxhd-hr-sq-mov b/tests/ref/vsynth/vsynth1-dnxhd-hr-sq-mov index 2c52e3e92..b647cbe7b 100644 --- a/tests/ref/vsynth/vsynth1-dnxhd-hr-sq-mov +++ b/tests/ref/vsynth/vsynth1-dnxhd-hr-sq-mov @@ -1,4 +1,4 @@ -7d7fb47e926aa565b51661264f1a39e9 *tests/data/fate/vsynth1-dnxhd-hr-sq-mov.mov +31544b301d8a23101c1cf03d26546fb8 *tests/data/fate/vsynth1-dnxhd-hr-sq-mov.mov 2560763 tests/data/fate/vsynth1-dnxhd-hr-sq-mov.mov 66d29f91cdf038753894dd42e65d997a *tests/data/fate/vsynth1-dnxhd-hr-sq-mov.out.rawvideo stddev: 5.77 PSNR: 32.91 MAXDIFF: 58 bytes: 7603200/ 760320 diff --git a/tests/ref/vsynth/vsynth1-mov-bgr24 b/tests/ref/vsynth/vsynth1-mov-bgr24 index ec60442fa..6639d0d54 100644 --- a/tests/ref/vsynth/vsynth1-mov-bgr24 +++ b/tests/ref/vsynth/vsynth1-mov-bgr24 @@ -1,4 +1,4 @@ -93d3a2e5701c3da06da27cffa04fb730 *tests/data/fate/vsynth1-mov-bgr24.mov +ba9d5cbc4b432db076fb501b1d5fa536 *tests/data/fate/vsynth1-mov-bgr24.mov 15207169 tests/data/fate/vsynth1-mov-bgr24.mov 93695a27c24a61105076ca7b1f010bbd *tests/data/fate/vsynth1-mov-bgr24.out.rawvideo stddev: 3.42 PSNR: 37.44 MAXDIFF: 48 bytes: 7603200/ 7603200 diff --git a/tests/ref/vsynth/vsynth1-mov-bpp15 b/tests/ref/vsynth/vsynth1-mov-bpp15 index cfb5e861d..d42c40b19 100644 --- a/tests/ref/vsynth/vsynth1-mov-bpp15 +++ b/tests/ref/vsynth/vsynth1-mov-bpp15 @@ -1,4 +1,4 @@ -00cd1f0cf8c335b8f4d7dfa81e188e75 *tests/data/fate/vsynth1-mov-bpp15.mov +dfd88a906ae74dddd4caf3c455224fa3 *tests/data/fate/vsynth1-mov-bpp15.mov 10138329 tests/data/fate/vsynth1-mov-bpp15.mov 99bece160cfb0da47f446b60d42fa3ae *tests/data/fate/vsynth1-mov-bpp15.out.rawvideo stddev: 4.06 PSNR: 35.94 MAXDIFF: 47 bytes: 7603200/ 7603200 diff --git a/tests/ref/vsynth/vsynth1-mov-bpp16 b/tests/ref/vsynth/vsynth1-mov-bpp16 index 8b17895c0..bdafbf14c 100644 --- a/tests/ref/vsynth/vsynth1-mov-bpp16 +++ b/tests/ref/vsynth/vsynth1-mov-bpp16 @@ -1,4 +1,4 @@ -623f62ed23abf406c2d67bf65adaf421 *tests/data/fate/vsynth1-mov-bpp16.mov +3d7e3f8bd238c341b0b4d55a30d8f5a2 *tests/data/fate/vsynth1-mov-bpp16.mov 10138329 tests/data/fate/vsynth1-mov-bpp16.mov 0cea382b9b0a4ce88260c1edc20b3f5b *tests/data/fate/vsynth1-mov-bpp16.out.rawvideo stddev: 3.79 PSNR: 36.55 MAXDIFF: 46 bytes: 7603200/ 7603200 diff --git a/tests/ref/vsynth/vsynth1-prores b/tests/ref/vsynth/vsynth1-prores index 14de8b9cf..3c59eb71a 100644 --- a/tests/ref/vsynth/vsynth1-prores +++ b/tests/ref/vsynth/vsynth1-prores @@ -1,4 +1,4 @@ -7ca7d2f9f5d8ac2ead691b1b6a70d409 *tests/data/fate/vsynth1-prores.mov +460f69344752e6af2dc46b00169b78a3 *tests/data/fate/vsynth1-prores.mov 5022821 tests/data/fate/vsynth1-prores.mov fb4a9e025d12afc0dbbca8d82831858f *tests/data/fate/vsynth1-prores.out.rawvideo stddev: 2.47 PSNR: 40.27 MAXDIFF: 31 bytes: 7603200/ 7603200 diff --git a/tests/ref/vsynth/vsynth1-prores_444 b/tests/ref/vsynth/vsynth1-prores_444 new file mode 100644 index 000000000..f7f8e9033 --- /dev/null +++ b/tests/ref/vsynth/vsynth1-prores_444 @@ -0,0 +1,4 @@ +509e0407dff118c775dcaa4f509a4aae *tests/data/fate/vsynth1-prores_444.mov +7778954 tests/data/fate/vsynth1-prores_444.mov +e0da52b5d58171294d1b299539801ae0 *tests/data/fate/vsynth1-prores_444.out.rawvideo +stddev: 2.80 PSNR: 39.17 MAXDIFF: 44 bytes: 7603200/ 7603200 diff --git a/tests/ref/vsynth/vsynth1-prores_444_int b/tests/ref/vsynth/vsynth1-prores_444_int new file mode 100644 index 000000000..951588721 --- /dev/null +++ b/tests/ref/vsynth/vsynth1-prores_444_int @@ -0,0 +1,4 @@ +1d5e484fa8ca08781ef2ed8428963d12 *tests/data/fate/vsynth1-prores_444_int.mov +9940947 tests/data/fate/vsynth1-prores_444_int.mov +732ceeb6887524e0aee98762fe50578b *tests/data/fate/vsynth1-prores_444_int.out.rawvideo +stddev: 2.83 PSNR: 39.08 MAXDIFF: 45 bytes: 7603200/ 7603200 diff --git a/tests/ref/vsynth/vsynth1-prores_int b/tests/ref/vsynth/vsynth1-prores_int new file mode 100644 index 000000000..16a66874a --- /dev/null +++ b/tests/ref/vsynth/vsynth1-prores_int @@ -0,0 +1,4 @@ +3711e22aa5052f39dabfcb9ee3a42045 *tests/data/fate/vsynth1-prores_int.mov +6308688 tests/data/fate/vsynth1-prores_int.mov +164a4ca890695cf594293d1acec9463c *tests/data/fate/vsynth1-prores_int.out.rawvideo +stddev: 2.66 PSNR: 39.62 MAXDIFF: 34 bytes: 7603200/ 7603200 diff --git a/tests/ref/vsynth/vsynth1-prores_ks b/tests/ref/vsynth/vsynth1-prores_ks index 6e5ed172b..22c248909 100644 --- a/tests/ref/vsynth/vsynth1-prores_ks +++ b/tests/ref/vsynth/vsynth1-prores_ks @@ -1,4 +1,4 @@ -fe41a284da97ea5ec8866ca9a55b84da *tests/data/fate/vsynth1-prores_ks.mov +5b0970bacd4b03d70f7648fee2f0c85f *tests/data/fate/vsynth1-prores_ks.mov 3858911 tests/data/fate/vsynth1-prores_ks.mov 100eb002413fe7a632d440dfbdf7e3ff *tests/data/fate/vsynth1-prores_ks.out.rawvideo stddev: 3.17 PSNR: 38.09 MAXDIFF: 39 bytes: 7603200/ 7603200 diff --git a/tests/ref/vsynth/vsynth1-qtrle b/tests/ref/vsynth/vsynth1-qtrle index 4b920815c..02164ddb9 100644 --- a/tests/ref/vsynth/vsynth1-qtrle +++ b/tests/ref/vsynth/vsynth1-qtrle @@ -1,4 +1,4 @@ -35d8a1446d886fadcdffae192bed7e4e *tests/data/fate/vsynth1-qtrle.mov +fb84d62fc821cf063b5877c61b975e62 *tests/data/fate/vsynth1-qtrle.mov 15263158 tests/data/fate/vsynth1-qtrle.mov 93695a27c24a61105076ca7b1f010bbd *tests/data/fate/vsynth1-qtrle.out.rawvideo stddev: 3.42 PSNR: 37.44 MAXDIFF: 48 bytes: 7603200/ 7603200 diff --git a/tests/ref/vsynth/vsynth1-qtrlegray b/tests/ref/vsynth/vsynth1-qtrlegray index c3d571d92..3cf64d14a 100644 --- a/tests/ref/vsynth/vsynth1-qtrlegray +++ b/tests/ref/vsynth/vsynth1-qtrlegray @@ -1,4 +1,4 @@ -651b745a37a06ddd52adfe8e0a45b115 *tests/data/fate/vsynth1-qtrlegray.mov +75753ab19241d1e45297219204a0925d *tests/data/fate/vsynth1-qtrlegray.mov 5113293 tests/data/fate/vsynth1-qtrlegray.mov cb20af0e5a65aad7cf47002fcb52288e *tests/data/fate/vsynth1-qtrlegray.out.rawvideo stddev: 25.34 PSNR: 20.05 MAXDIFF: 122 bytes: 7603200/ 7603200 diff --git a/tests/ref/vsynth/vsynth1-r210 b/tests/ref/vsynth/vsynth1-r210 index 825e1d478..110330806 100644 --- a/tests/ref/vsynth/vsynth1-r210 +++ b/tests/ref/vsynth/vsynth1-r210 @@ -1,4 +1,4 @@ -1ea72f280b110ed65fc535c3438d27f9 *tests/data/fate/vsynth1-r210.avi +1a522a30ddd8c2865a731a5659001717 *tests/data/fate/vsynth1-r210.avi 22125252 tests/data/fate/vsynth1-r210.avi -ecaafa9eec11b5e1453a63ed6d194eed *tests/data/fate/vsynth1-r210.out.rawvideo -stddev: 3.23 PSNR: 37.94 MAXDIFF: 48 bytes: 7603200/ 7603200 +b6444935d6c4d8c75fe63d5978f5b457 *tests/data/fate/vsynth1-r210.out.rawvideo +stddev: 3.73 PSNR: 36.68 MAXDIFF: 48 bytes: 7603200/ 7603200 diff --git a/tests/ref/vsynth/vsynth1-svq1 b/tests/ref/vsynth/vsynth1-svq1 index 9c1b6ff7a..cb89915d2 100644 --- a/tests/ref/vsynth/vsynth1-svq1 +++ b/tests/ref/vsynth/vsynth1-svq1 @@ -1,4 +1,4 @@ -a3206831d34197a2d236d82dd0248646 *tests/data/fate/vsynth1-svq1.mov +39ec74da265e3ef27756618108641181 *tests/data/fate/vsynth1-svq1.mov 1334233 tests/data/fate/vsynth1-svq1.mov 9cc35c54b2c77d36bd7e308b393c1f81 *tests/data/fate/vsynth1-svq1.out.rawvideo stddev: 9.58 PSNR: 28.50 MAXDIFF: 210 bytes: 7603200/ 7603200 diff --git a/tests/ref/vsynth/vsynth1-vc2-420p b/tests/ref/vsynth/vsynth1-vc2-420p index e925c53ba..0c4c9cbeb 100644 --- a/tests/ref/vsynth/vsynth1-vc2-420p +++ b/tests/ref/vsynth/vsynth1-vc2-420p @@ -1,4 +1,4 @@ -fb8fffcfc17558c87dd11a67ccb0f615 *tests/data/fate/vsynth1-vc2-420p.mov +74df65b15463f098587d8c09d87286a1 *tests/data/fate/vsynth1-vc2-420p.mov 1155415 tests/data/fate/vsynth1-vc2-420p.mov 387696707c79cf1a6c9aeff4024226b9 *tests/data/fate/vsynth1-vc2-420p.out.rawvideo stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 7603200/ 760320 diff --git a/tests/ref/vsynth/vsynth1-vc2-420p10 b/tests/ref/vsynth/vsynth1-vc2-420p10 index 025a1cc77..2a70b657e 100644 --- a/tests/ref/vsynth/vsynth1-vc2-420p10 +++ b/tests/ref/vsynth/vsynth1-vc2-420p10 @@ -1,4 +1,4 @@ -1365742985b6315f6796c765aa17f39e *tests/data/fate/vsynth1-vc2-420p10.mov +f469f3b94c9262fd421a67b20e1809e7 *tests/data/fate/vsynth1-vc2-420p10.mov 1417047 tests/data/fate/vsynth1-vc2-420p10.mov 387696707c79cf1a6c9aeff4024226b9 *tests/data/fate/vsynth1-vc2-420p10.out.rawvideo stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 7603200/ 760320 diff --git a/tests/ref/vsynth/vsynth1-vc2-420p12 b/tests/ref/vsynth/vsynth1-vc2-420p12 index 719f0d5f3..4d1a1a224 100644 --- a/tests/ref/vsynth/vsynth1-vc2-420p12 +++ b/tests/ref/vsynth/vsynth1-vc2-420p12 @@ -1,4 +1,4 @@ -08a844d17940cd612da269fb08430628 *tests/data/fate/vsynth1-vc2-420p12.mov +9e482c1b03d49cfec89c6515888bc735 *tests/data/fate/vsynth1-vc2-420p12.mov 1746007 tests/data/fate/vsynth1-vc2-420p12.mov 387696707c79cf1a6c9aeff4024226b9 *tests/data/fate/vsynth1-vc2-420p12.out.rawvideo stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 7603200/ 760320 diff --git a/tests/ref/vsynth/vsynth1-vc2-422p b/tests/ref/vsynth/vsynth1-vc2-422p index 8fc61887d..15f988a39 100644 --- a/tests/ref/vsynth/vsynth1-vc2-422p +++ b/tests/ref/vsynth/vsynth1-vc2-422p @@ -1,4 +1,4 @@ -19f01a985e87e14664e0e5d14c02d046 *tests/data/fate/vsynth1-vc2-422p.mov +19b0ed7a894cda7378ace68f05c143cd *tests/data/fate/vsynth1-vc2-422p.mov 1229783 tests/data/fate/vsynth1-vc2-422p.mov 57a7f41235e7f9f094aa7ba5bdc82f02 *tests/data/fate/vsynth1-vc2-422p.out.rawvideo stddev: 1.89 PSNR: 42.58 MAXDIFF: 23 bytes: 7603200/ 760320 diff --git a/tests/ref/vsynth/vsynth1-vc2-422p10 b/tests/ref/vsynth/vsynth1-vc2-422p10 index ac1072f3d..c561eaf12 100644 --- a/tests/ref/vsynth/vsynth1-vc2-422p10 +++ b/tests/ref/vsynth/vsynth1-vc2-422p10 @@ -1,4 +1,4 @@ -88e3488e4689cf06e75959c71e2f9d96 *tests/data/fate/vsynth1-vc2-422p10.mov +e3ddb55b47e8960eba9412c4e38ce77a *tests/data/fate/vsynth1-vc2-422p10.mov 1684055 tests/data/fate/vsynth1-vc2-422p10.mov f35dd1c1df4726bb1d75d95e321b0698 *tests/data/fate/vsynth1-vc2-422p10.out.rawvideo stddev: 1.88 PSNR: 42.61 MAXDIFF: 23 bytes: 7603200/ 760320 diff --git a/tests/ref/vsynth/vsynth1-vc2-422p12 b/tests/ref/vsynth/vsynth1-vc2-422p12 index 0ad4798e6..baa67153b 100644 --- a/tests/ref/vsynth/vsynth1-vc2-422p12 +++ b/tests/ref/vsynth/vsynth1-vc2-422p12 @@ -1,4 +1,4 @@ -b162a7c531fb06f436c79b38fb3d7403 *tests/data/fate/vsynth1-vc2-422p12.mov +4dd111ed0272534faa258cb6a2dab13d *tests/data/fate/vsynth1-vc2-422p12.mov 2135131 tests/data/fate/vsynth1-vc2-422p12.mov 1b56b3d127320c0e6c643e3430b7ffd1 *tests/data/fate/vsynth1-vc2-422p12.out.rawvideo stddev: 1.88 PSNR: 42.62 MAXDIFF: 23 bytes: 7603200/ 760320 diff --git a/tests/ref/vsynth/vsynth1-vc2-444p b/tests/ref/vsynth/vsynth1-vc2-444p index d01e9381b..1d0dffc39 100644 --- a/tests/ref/vsynth/vsynth1-vc2-444p +++ b/tests/ref/vsynth/vsynth1-vc2-444p @@ -1,4 +1,4 @@ -b3f0d987dcb0b5d1eb0b87f356ad21c4 *tests/data/fate/vsynth1-vc2-444p.mov +377d8c8f5bf8cec078d96d4d62df6296 *tests/data/fate/vsynth1-vc2-444p.mov 1593810 tests/data/fate/vsynth1-vc2-444p.mov 791cf0f21558ad4a4cad43da05628e06 *tests/data/fate/vsynth1-vc2-444p.out.rawvideo stddev: 2.69 PSNR: 39.51 MAXDIFF: 37 bytes: 7603200/ 760320 diff --git a/tests/ref/vsynth/vsynth1-vc2-444p10 b/tests/ref/vsynth/vsynth1-vc2-444p10 index af0074678..fee9afbd7 100644 --- a/tests/ref/vsynth/vsynth1-vc2-444p10 +++ b/tests/ref/vsynth/vsynth1-vc2-444p10 @@ -1,4 +1,4 @@ -ef286696c5d37277b4064c4f87f6e564 *tests/data/fate/vsynth1-vc2-444p10.mov +dca4f23469c7446fecf5c123bbc71b2b *tests/data/fate/vsynth1-vc2-444p10.mov 2167643 tests/data/fate/vsynth1-vc2-444p10.mov 0e2cd6d0e1d68ffee64d269dcb57d66d *tests/data/fate/vsynth1-vc2-444p10.out.rawvideo stddev: 2.69 PSNR: 39.53 MAXDIFF: 37 bytes: 7603200/ 760320 diff --git a/tests/ref/vsynth/vsynth1-vc2-444p12 b/tests/ref/vsynth/vsynth1-vc2-444p12 index 6a71b6735..e548deca1 100644 --- a/tests/ref/vsynth/vsynth1-vc2-444p12 +++ b/tests/ref/vsynth/vsynth1-vc2-444p12 @@ -1,4 +1,4 @@ -21aaed7828fa847ce5b75399efbc768c *tests/data/fate/vsynth1-vc2-444p12.mov +f5ef425d9d29829e8dc4287ef253d3c7 *tests/data/fate/vsynth1-vc2-444p12.mov 2755159 tests/data/fate/vsynth1-vc2-444p12.mov 55998114d7386d219a49011c8b804a58 *tests/data/fate/vsynth1-vc2-444p12.out.rawvideo stddev: 2.69 PSNR: 39.53 MAXDIFF: 37 bytes: 7603200/ 760320 diff --git a/tests/ref/vsynth/vsynth1-vc2-t5_3 b/tests/ref/vsynth/vsynth1-vc2-t5_3 new file mode 100644 index 000000000..e2fb05407 --- /dev/null +++ b/tests/ref/vsynth/vsynth1-vc2-t5_3 @@ -0,0 +1,4 @@ +4e1ca89ec825e7926717146b945c916d *tests/data/fate/vsynth1-vc2-t5_3.mov +1604316 tests/data/fate/vsynth1-vc2-t5_3.mov +f35dd1c1df4726bb1d75d95e321b0698 *tests/data/fate/vsynth1-vc2-t5_3.out.rawvideo +stddev: 1.88 PSNR: 42.61 MAXDIFF: 23 bytes: 7603200/ 760320 diff --git a/tests/ref/vsynth/vsynth1-vc2-thaar b/tests/ref/vsynth/vsynth1-vc2-thaar new file mode 100644 index 000000000..883102778 --- /dev/null +++ b/tests/ref/vsynth/vsynth1-vc2-thaar @@ -0,0 +1,4 @@ +a0aba4e9628b8952fe774bd8c1f3f18d *tests/data/fate/vsynth1-vc2-thaar.mov +1717724 tests/data/fate/vsynth1-vc2-thaar.mov +f35dd1c1df4726bb1d75d95e321b0698 *tests/data/fate/vsynth1-vc2-thaar.out.rawvideo +stddev: 1.88 PSNR: 42.61 MAXDIFF: 23 bytes: 7603200/ 760320 diff --git a/tests/ref/vsynth/vsynth2-avui b/tests/ref/vsynth/vsynth2-avui index 2423916f4..f4666ee9c 100644 --- a/tests/ref/vsynth/vsynth2-avui +++ b/tests/ref/vsynth/vsynth2-avui @@ -1,4 +1,4 @@ -8f6ab410bb6b5dc4599e12968dbd0366 *tests/data/fate/vsynth2-avui.mov +4a08755db5e09933a45178bc6f5f61b6 *tests/data/fate/vsynth2-avui.mov 42625037 tests/data/fate/vsynth2-avui.mov 36d7ca943916e1743cefa609eba0205c *tests/data/fate/vsynth2-avui.out.rawvideo stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 7603200/ 7603200 diff --git a/tests/ref/vsynth/vsynth2-dnxhd-1080i b/tests/ref/vsynth/vsynth2-dnxhd-1080i index eabb6a2b2..0668a44f9 100644 --- a/tests/ref/vsynth/vsynth2-dnxhd-1080i +++ b/tests/ref/vsynth/vsynth2-dnxhd-1080i @@ -1,4 +1,4 @@ -2b75889122f8d918e1b068d128b618ca *tests/data/fate/vsynth2-dnxhd-1080i.mov +0067903558c99e3abed402ed65297735 *tests/data/fate/vsynth2-dnxhd-1080i.mov 3031911 tests/data/fate/vsynth2-dnxhd-1080i.mov e941d2587cfeccddc450da7f41f7f911 *tests/data/fate/vsynth2-dnxhd-1080i.out.rawvideo stddev: 1.50 PSNR: 44.56 MAXDIFF: 31 bytes: 7603200/ 760320 diff --git a/tests/ref/vsynth/vsynth2-dnxhd-1080i-10bit b/tests/ref/vsynth/vsynth2-dnxhd-1080i-10bit index 3361c9341..7689e2c22 100644 --- a/tests/ref/vsynth/vsynth2-dnxhd-1080i-10bit +++ b/tests/ref/vsynth/vsynth2-dnxhd-1080i-10bit @@ -1,4 +1,4 @@ -514607eecfd9004aa4da1d216f7620ce *tests/data/fate/vsynth2-dnxhd-1080i-10bit.mov +16e86953a697e1e7f9d80903ff4fef0c *tests/data/fate/vsynth2-dnxhd-1080i-10bit.mov 4588391 tests/data/fate/vsynth2-dnxhd-1080i-10bit.mov e4ca9be476869afb94962d945f90bdf6 *tests/data/fate/vsynth2-dnxhd-1080i-10bit.out.rawvideo stddev: 1.57 PSNR: 44.18 MAXDIFF: 33 bytes: 7603200/ 760320 diff --git a/tests/ref/vsynth/vsynth2-dnxhd-1080i-colr b/tests/ref/vsynth/vsynth2-dnxhd-1080i-colr index 06731a885..aac70c286 100644 --- a/tests/ref/vsynth/vsynth2-dnxhd-1080i-colr +++ b/tests/ref/vsynth/vsynth2-dnxhd-1080i-colr @@ -1,4 +1,4 @@ -f9827e9867b0ea4f7585d8e362a58413 *tests/data/fate/vsynth2-dnxhd-1080i-colr.mov +e7e5cd8d6d1596596ded1007f37c3193 *tests/data/fate/vsynth2-dnxhd-1080i-colr.mov 3031929 tests/data/fate/vsynth2-dnxhd-1080i-colr.mov ec40a8014b819d02951b2f06bee7b514 *tests/data/fate/vsynth2-dnxhd-1080i-colr.out.rawvideo stddev: 1.54 PSNR: 44.33 MAXDIFF: 33 bytes: 7603200/ 760320 diff --git a/tests/ref/vsynth/vsynth2-dnxhd-hr-hq-mov b/tests/ref/vsynth/vsynth2-dnxhd-hr-hq-mov index ab49a3aae..b8d3ab999 100644 --- a/tests/ref/vsynth/vsynth2-dnxhd-hr-hq-mov +++ b/tests/ref/vsynth/vsynth2-dnxhd-hr-hq-mov @@ -1,4 +1,4 @@ -a15a4d267dcaeba7a366733be0b508df *tests/data/fate/vsynth2-dnxhd-hr-hq-mov.mov +a71fffeebf680f52aaae2df02b85d2fe *tests/data/fate/vsynth2-dnxhd-hr-hq-mov.mov 4772599 tests/data/fate/vsynth2-dnxhd-hr-hq-mov.mov 9c087836b5e07bddb96533d27939219f *tests/data/fate/vsynth2-dnxhd-hr-hq-mov.out.rawvideo stddev: 1.56 PSNR: 44.25 MAXDIFF: 33 bytes: 7603200/ 760320 diff --git a/tests/ref/vsynth/vsynth2-dnxhd-hr-lb-mov b/tests/ref/vsynth/vsynth2-dnxhd-hr-lb-mov index 1f0f49688..9370d87aa 100644 --- a/tests/ref/vsynth/vsynth2-dnxhd-hr-lb-mov +++ b/tests/ref/vsynth/vsynth2-dnxhd-hr-lb-mov @@ -1,4 +1,4 @@ -f8c366051fb16025e97f1bf78f13e1af *tests/data/fate/vsynth2-dnxhd-hr-lb-mov.mov +6a514f231b36542a3bc6af90bbc04dcd *tests/data/fate/vsynth2-dnxhd-hr-lb-mov.mov 3748599 tests/data/fate/vsynth2-dnxhd-hr-lb-mov.mov 6d4cdd8822ead300690af9ce52db037c *tests/data/fate/vsynth2-dnxhd-hr-lb-mov.out.rawvideo stddev: 1.52 PSNR: 44.49 MAXDIFF: 33 bytes: 7603200/ 760320 diff --git a/tests/ref/vsynth/vsynth2-dnxhd-hr-sq-mov b/tests/ref/vsynth/vsynth2-dnxhd-hr-sq-mov index 7bffbedb4..0b8e9571e 100644 --- a/tests/ref/vsynth/vsynth2-dnxhd-hr-sq-mov +++ b/tests/ref/vsynth/vsynth2-dnxhd-hr-sq-mov @@ -1,4 +1,4 @@ -863b1780cfdabfd713ddf722792a5e61 *tests/data/fate/vsynth2-dnxhd-hr-sq-mov.mov +2398b73a57a5ae4c4cd54b3ebb796bfb *tests/data/fate/vsynth2-dnxhd-hr-sq-mov.mov 2560763 tests/data/fate/vsynth2-dnxhd-hr-sq-mov.mov ba86d472b3f160e2f1d00cf569231e3f *tests/data/fate/vsynth2-dnxhd-hr-sq-mov.out.rawvideo stddev: 1.58 PSNR: 44.13 MAXDIFF: 35 bytes: 7603200/ 760320 diff --git a/tests/ref/vsynth/vsynth2-mov-bgr24 b/tests/ref/vsynth/vsynth2-mov-bgr24 index 8d9adc1f3..1db6aee65 100644 --- a/tests/ref/vsynth/vsynth2-mov-bgr24 +++ b/tests/ref/vsynth/vsynth2-mov-bgr24 @@ -1,4 +1,4 @@ -ed8dbb665820659d9c4fa659e0a20c65 *tests/data/fate/vsynth2-mov-bgr24.mov +1c5a5b9e299c5e02e757d8be98999cf4 *tests/data/fate/vsynth2-mov-bgr24.mov 15207169 tests/data/fate/vsynth2-mov-bgr24.mov 32fae3e665407bb4317b3f90fedb903c *tests/data/fate/vsynth2-mov-bgr24.out.rawvideo stddev: 1.54 PSNR: 44.37 MAXDIFF: 17 bytes: 7603200/ 7603200 diff --git a/tests/ref/vsynth/vsynth2-mov-bpp15 b/tests/ref/vsynth/vsynth2-mov-bpp15 index c61b88a73..ce1c13a34 100644 --- a/tests/ref/vsynth/vsynth2-mov-bpp15 +++ b/tests/ref/vsynth/vsynth2-mov-bpp15 @@ -1,4 +1,4 @@ -d694493c1fe20211e12d797620d622ec *tests/data/fate/vsynth2-mov-bpp15.mov +a004683db50f49520abd74479b25cbd1 *tests/data/fate/vsynth2-mov-bpp15.mov 10138329 tests/data/fate/vsynth2-mov-bpp15.mov eb3f0c974ed17ede7cd3ce30ce417d8d *tests/data/fate/vsynth2-mov-bpp15.out.rawvideo stddev: 2.81 PSNR: 39.14 MAXDIFF: 19 bytes: 7603200/ 7603200 diff --git a/tests/ref/vsynth/vsynth2-mov-bpp16 b/tests/ref/vsynth/vsynth2-mov-bpp16 index 1839e55cc..f7f40c58c 100644 --- a/tests/ref/vsynth/vsynth2-mov-bpp16 +++ b/tests/ref/vsynth/vsynth2-mov-bpp16 @@ -1,4 +1,4 @@ -c2685405eaec39007a68108c4533ba0e *tests/data/fate/vsynth2-mov-bpp16.mov +b7ffee543580662d2cae327233816fca *tests/data/fate/vsynth2-mov-bpp16.mov 10138329 tests/data/fate/vsynth2-mov-bpp16.mov 7747ab837f0e832be2124120d4f7df1c *tests/data/fate/vsynth2-mov-bpp16.out.rawvideo stddev: 2.21 PSNR: 41.24 MAXDIFF: 18 bytes: 7603200/ 7603200 diff --git a/tests/ref/vsynth/vsynth2-prores b/tests/ref/vsynth/vsynth2-prores index a1b4bb748..8e48cb041 100644 --- a/tests/ref/vsynth/vsynth2-prores +++ b/tests/ref/vsynth/vsynth2-prores @@ -1,4 +1,4 @@ -aa57fd1221b7eefaf1f34f9d57d6a7cb *tests/data/fate/vsynth2-prores.mov -3265056 tests/data/fate/vsynth2-prores.mov -537b0ff66d7c8c3c12faa89d042e6a49 *tests/data/fate/vsynth2-prores.out.rawvideo +a38660faa093dbc8a1ae8e570b6e595b *tests/data/fate/vsynth2-prores.mov +3260123 tests/data/fate/vsynth2-prores.mov +416fa8773615889c70491452428d6710 *tests/data/fate/vsynth2-prores.out.rawvideo stddev: 1.38 PSNR: 45.29 MAXDIFF: 12 bytes: 7603200/ 7603200 diff --git a/tests/ref/vsynth/vsynth2-prores_444 b/tests/ref/vsynth/vsynth2-prores_444 new file mode 100644 index 000000000..c6084f590 --- /dev/null +++ b/tests/ref/vsynth/vsynth2-prores_444 @@ -0,0 +1,4 @@ +21f973c4c6076ea21f82d5fe486c0c98 *tests/data/fate/vsynth2-prores_444.mov +5219722 tests/data/fate/vsynth2-prores_444.mov +e425b6af7afa51b5e64fc529528b3691 *tests/data/fate/vsynth2-prores_444.out.rawvideo +stddev: 0.88 PSNR: 49.18 MAXDIFF: 14 bytes: 7603200/ 7603200 diff --git a/tests/ref/vsynth/vsynth2-prores_444_int b/tests/ref/vsynth/vsynth2-prores_444_int new file mode 100644 index 000000000..a727bb2d2 --- /dev/null +++ b/tests/ref/vsynth/vsynth2-prores_444_int @@ -0,0 +1,4 @@ +500a8249bc63ec6bb79f816bce5b6db1 *tests/data/fate/vsynth2-prores_444_int.mov +6420787 tests/data/fate/vsynth2-prores_444_int.mov +33a5db4f0423168d4ae4f1db3610928e *tests/data/fate/vsynth2-prores_444_int.out.rawvideo +stddev: 0.93 PSNR: 48.73 MAXDIFF: 14 bytes: 7603200/ 7603200 diff --git a/tests/ref/vsynth/vsynth2-prores_int b/tests/ref/vsynth/vsynth2-prores_int new file mode 100644 index 000000000..0f27acdca --- /dev/null +++ b/tests/ref/vsynth/vsynth2-prores_int @@ -0,0 +1,4 @@ +dd7835992e7a30b7be9014916411b5b3 *tests/data/fate/vsynth2-prores_int.mov +4070996 tests/data/fate/vsynth2-prores_int.mov +bef9e38387a1fbb1ce2e4401b6d41674 *tests/data/fate/vsynth2-prores_int.out.rawvideo +stddev: 1.54 PSNR: 44.37 MAXDIFF: 13 bytes: 7603200/ 7603200 diff --git a/tests/ref/vsynth/vsynth2-prores_ks b/tests/ref/vsynth/vsynth2-prores_ks index b42e7b38c..5186f55b4 100644 --- a/tests/ref/vsynth/vsynth2-prores_ks +++ b/tests/ref/vsynth/vsynth2-prores_ks @@ -1,4 +1,4 @@ -00c75fc738859e41c48cbe36ad60c2e2 *tests/data/fate/vsynth2-prores_ks.mov +abde4f84a5e4060492e3d8fcb56f2467 *tests/data/fate/vsynth2-prores_ks.mov 3868162 tests/data/fate/vsynth2-prores_ks.mov fe7ad707205c6100e9a3956d4e1c300e *tests/data/fate/vsynth2-prores_ks.out.rawvideo stddev: 1.17 PSNR: 46.72 MAXDIFF: 14 bytes: 7603200/ 7603200 diff --git a/tests/ref/vsynth/vsynth2-qtrle b/tests/ref/vsynth/vsynth2-qtrle index 4adf913d1..8593845d9 100644 --- a/tests/ref/vsynth/vsynth2-qtrle +++ b/tests/ref/vsynth/vsynth2-qtrle @@ -1,4 +1,4 @@ -b44d1cd0bb4c1e7c57d668bd9c1d319a *tests/data/fate/vsynth2-qtrle.mov +492bef0aea081c076307d668d94fb9c4 *tests/data/fate/vsynth2-qtrle.mov 14035926 tests/data/fate/vsynth2-qtrle.mov 32fae3e665407bb4317b3f90fedb903c *tests/data/fate/vsynth2-qtrle.out.rawvideo stddev: 1.54 PSNR: 44.37 MAXDIFF: 17 bytes: 7603200/ 7603200 diff --git a/tests/ref/vsynth/vsynth2-qtrlegray b/tests/ref/vsynth/vsynth2-qtrlegray index 824e64b28..b92d24544 100644 --- a/tests/ref/vsynth/vsynth2-qtrlegray +++ b/tests/ref/vsynth/vsynth2-qtrlegray @@ -1,4 +1,4 @@ -4910471607743da624ef7339637a33e2 *tests/data/fate/vsynth2-qtrlegray.mov +109c88cbb3528378c1e848e50cf1792d *tests/data/fate/vsynth2-qtrlegray.mov 4988372 tests/data/fate/vsynth2-qtrlegray.mov 510a92a21b552c51fcafab8188982f4d *tests/data/fate/vsynth2-qtrlegray.out.rawvideo stddev: 16.31 PSNR: 23.88 MAXDIFF: 89 bytes: 7603200/ 7603200 diff --git a/tests/ref/vsynth/vsynth2-r210 b/tests/ref/vsynth/vsynth2-r210 index dc5ff1849..5efd87d6f 100644 --- a/tests/ref/vsynth/vsynth2-r210 +++ b/tests/ref/vsynth/vsynth2-r210 @@ -1,4 +1,4 @@ -2f928096d892ce0239832afc369e117c *tests/data/fate/vsynth2-r210.avi +9a27c0c96f9e658d610d2590b61416a1 *tests/data/fate/vsynth2-r210.avi 22125252 tests/data/fate/vsynth2-r210.avi -2ade5f6167d7a4a1589e168ddbbc35d0 *tests/data/fate/vsynth2-r210.out.rawvideo -stddev: 1.17 PSNR: 46.71 MAXDIFF: 15 bytes: 7603200/ 7603200 +d43196c64fd611f6e9c046e0ef3e570e *tests/data/fate/vsynth2-r210.out.rawvideo +stddev: 1.37 PSNR: 45.34 MAXDIFF: 14 bytes: 7603200/ 7603200 diff --git a/tests/ref/vsynth/vsynth2-svq1 b/tests/ref/vsynth/vsynth2-svq1 index 9c7db7f03..4a5077550 100644 --- a/tests/ref/vsynth/vsynth2-svq1 +++ b/tests/ref/vsynth/vsynth2-svq1 @@ -1,4 +1,4 @@ -c767386f0f6f36b554d278592bc6e9a4 *tests/data/fate/vsynth2-svq1.mov +1c12440c323bc8ace5464587b5369c4a *tests/data/fate/vsynth2-svq1.mov 940289 tests/data/fate/vsynth2-svq1.mov a8cd3b833cd7f570ddbf1e6b3eb125b6 *tests/data/fate/vsynth2-svq1.out.rawvideo stddev: 3.71 PSNR: 36.72 MAXDIFF: 210 bytes: 7603200/ 7603200 diff --git a/tests/ref/vsynth/vsynth2-vc2-420p b/tests/ref/vsynth/vsynth2-vc2-420p index f355e8d30..28c1aedf7 100644 --- a/tests/ref/vsynth/vsynth2-vc2-420p +++ b/tests/ref/vsynth/vsynth2-vc2-420p @@ -1,4 +1,4 @@ -ac4df937fed73532bd8713b0e07870c9 *tests/data/fate/vsynth2-vc2-420p.mov +78daa3a27c0630aa37024121a43a7908 *tests/data/fate/vsynth2-vc2-420p.mov 860743 tests/data/fate/vsynth2-vc2-420p.mov 01389f7ae4f2a3dc0d7b8384d435fd83 *tests/data/fate/vsynth2-vc2-420p.out.rawvideo stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 7603200/ 760320 diff --git a/tests/ref/vsynth/vsynth2-vc2-420p10 b/tests/ref/vsynth/vsynth2-vc2-420p10 index 48d97d60e..12b5fe022 100644 --- a/tests/ref/vsynth/vsynth2-vc2-420p10 +++ b/tests/ref/vsynth/vsynth2-vc2-420p10 @@ -1,4 +1,4 @@ -1197f8108683b9eb6b0777adb2db1aa8 *tests/data/fate/vsynth2-vc2-420p10.mov +e4627f308056d82de52a849b3a07b415 *tests/data/fate/vsynth2-vc2-420p10.mov 1181271 tests/data/fate/vsynth2-vc2-420p10.mov 01389f7ae4f2a3dc0d7b8384d435fd83 *tests/data/fate/vsynth2-vc2-420p10.out.rawvideo stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 7603200/ 760320 diff --git a/tests/ref/vsynth/vsynth2-vc2-420p12 b/tests/ref/vsynth/vsynth2-vc2-420p12 index 9b9ccb8ec..dc67229f6 100644 --- a/tests/ref/vsynth/vsynth2-vc2-420p12 +++ b/tests/ref/vsynth/vsynth2-vc2-420p12 @@ -1,4 +1,4 @@ -0e6b3aefd70fca45e67dc8cbc99640e8 *tests/data/fate/vsynth2-vc2-420p12.mov +8ff2cd721eae2e95d91568dde88a9970 *tests/data/fate/vsynth2-vc2-420p12.mov 1525079 tests/data/fate/vsynth2-vc2-420p12.mov 01389f7ae4f2a3dc0d7b8384d435fd83 *tests/data/fate/vsynth2-vc2-420p12.out.rawvideo stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 7603200/ 760320 diff --git a/tests/ref/vsynth/vsynth2-vc2-422p b/tests/ref/vsynth/vsynth2-vc2-422p index 83689a73e..b53ca286b 100644 --- a/tests/ref/vsynth/vsynth2-vc2-422p +++ b/tests/ref/vsynth/vsynth2-vc2-422p @@ -1,4 +1,4 @@ -b2573399e0ed62ede66b1708de86412a *tests/data/fate/vsynth2-vc2-422p.mov +2a5213e25c03b60685e8467dfb11883c *tests/data/fate/vsynth2-vc2-422p.mov 1035207 tests/data/fate/vsynth2-vc2-422p.mov c14eb0038a5dba9382f42f750d46ed3c *tests/data/fate/vsynth2-vc2-422p.out.rawvideo stddev: 0.35 PSNR: 57.21 MAXDIFF: 7 bytes: 7603200/ 760320 diff --git a/tests/ref/vsynth/vsynth2-vc2-422p10 b/tests/ref/vsynth/vsynth2-vc2-422p10 index af9a0b15f..12b5bbe79 100644 --- a/tests/ref/vsynth/vsynth2-vc2-422p10 +++ b/tests/ref/vsynth/vsynth2-vc2-422p10 @@ -1,4 +1,4 @@ -ca65de033b17c67be94356e0b6e0b128 *tests/data/fate/vsynth2-vc2-422p10.mov +6a99394db4353cc092e6bd9697e836ef *tests/data/fate/vsynth2-vc2-422p10.mov 1321687 tests/data/fate/vsynth2-vc2-422p10.mov 8f629e5cea24cc804d6aeadceacf0b2a *tests/data/fate/vsynth2-vc2-422p10.out.rawvideo stddev: 0.37 PSNR: 56.66 MAXDIFF: 7 bytes: 7603200/ 760320 diff --git a/tests/ref/vsynth/vsynth2-vc2-422p12 b/tests/ref/vsynth/vsynth2-vc2-422p12 index 16f978a87..c1ac2216e 100644 --- a/tests/ref/vsynth/vsynth2-vc2-422p12 +++ b/tests/ref/vsynth/vsynth2-vc2-422p12 @@ -1,4 +1,4 @@ -4e95706b063adbcc1f7f82a4e7d7d027 *tests/data/fate/vsynth2-vc2-422p12.mov +ef1f1484a569008ba64803f25b06df54 *tests/data/fate/vsynth2-vc2-422p12.mov 1752535 tests/data/fate/vsynth2-vc2-422p12.mov 7241b922e7c17d14701567db6c743a9e *tests/data/fate/vsynth2-vc2-422p12.out.rawvideo stddev: 0.37 PSNR: 56.73 MAXDIFF: 7 bytes: 7603200/ 760320 diff --git a/tests/ref/vsynth/vsynth2-vc2-444p b/tests/ref/vsynth/vsynth2-vc2-444p index 83979964d..f356056a0 100644 --- a/tests/ref/vsynth/vsynth2-vc2-444p +++ b/tests/ref/vsynth/vsynth2-vc2-444p @@ -1,4 +1,4 @@ -644a39d1b853f44722a4332d5a13797e *tests/data/fate/vsynth2-vc2-444p.mov +a2cae781cdec41c7128a6cc71fbf6b3b *tests/data/fate/vsynth2-vc2-444p.mov 1202386 tests/data/fate/vsynth2-vc2-444p.mov 6b35f3ddc3b52f4424237d4191a2461f *tests/data/fate/vsynth2-vc2-444p.out.rawvideo stddev: 0.44 PSNR: 55.07 MAXDIFF: 10 bytes: 7603200/ 760320 diff --git a/tests/ref/vsynth/vsynth2-vc2-444p10 b/tests/ref/vsynth/vsynth2-vc2-444p10 index 7d9367a4c..7a94bcd9b 100644 --- a/tests/ref/vsynth/vsynth2-vc2-444p10 +++ b/tests/ref/vsynth/vsynth2-vc2-444p10 @@ -1,4 +1,4 @@ -36cfc3da2ab6ff6d48f17ab43e77774d *tests/data/fate/vsynth2-vc2-444p10.mov +77b67d38ccb0d0e8d6c0af256afb1496 *tests/data/fate/vsynth2-vc2-444p10.mov 1603927 tests/data/fate/vsynth2-vc2-444p10.mov d5c80ee1881a0306b0487e3c868529a3 *tests/data/fate/vsynth2-vc2-444p10.out.rawvideo stddev: 0.48 PSNR: 54.46 MAXDIFF: 10 bytes: 7603200/ 760320 diff --git a/tests/ref/vsynth/vsynth2-vc2-444p12 b/tests/ref/vsynth/vsynth2-vc2-444p12 index 00098309a..fbd98ffe3 100644 --- a/tests/ref/vsynth/vsynth2-vc2-444p12 +++ b/tests/ref/vsynth/vsynth2-vc2-444p12 @@ -1,4 +1,4 @@ -6117c2ee6d5c22ee5a0b0ac6b70e6c17 *tests/data/fate/vsynth2-vc2-444p12.mov +1b535238247c0cdca338f2927e2c8c37 *tests/data/fate/vsynth2-vc2-444p12.mov 2145499 tests/data/fate/vsynth2-vc2-444p12.mov 38836be5c12b951c9b280d15fe3b31ce *tests/data/fate/vsynth2-vc2-444p12.out.rawvideo stddev: 0.48 PSNR: 54.46 MAXDIFF: 10 bytes: 7603200/ 760320 diff --git a/tests/ref/vsynth/vsynth2-vc2-t5_3 b/tests/ref/vsynth/vsynth2-vc2-t5_3 new file mode 100644 index 000000000..c4100acb5 --- /dev/null +++ b/tests/ref/vsynth/vsynth2-vc2-t5_3 @@ -0,0 +1,4 @@ +89aa19c48c8f1ba7c418102706980efa *tests/data/fate/vsynth2-vc2-t5_3.mov +1335772 tests/data/fate/vsynth2-vc2-t5_3.mov +8f629e5cea24cc804d6aeadceacf0b2a *tests/data/fate/vsynth2-vc2-t5_3.out.rawvideo +stddev: 0.37 PSNR: 56.66 MAXDIFF: 7 bytes: 7603200/ 760320 diff --git a/tests/ref/vsynth/vsynth2-vc2-thaar b/tests/ref/vsynth/vsynth2-vc2-thaar new file mode 100644 index 000000000..d4f37df74 --- /dev/null +++ b/tests/ref/vsynth/vsynth2-vc2-thaar @@ -0,0 +1,4 @@ +866641af5f57980f9da4c78c105155f1 *tests/data/fate/vsynth2-vc2-thaar.mov +1470300 tests/data/fate/vsynth2-vc2-thaar.mov +8f629e5cea24cc804d6aeadceacf0b2a *tests/data/fate/vsynth2-vc2-thaar.out.rawvideo +stddev: 0.37 PSNR: 56.66 MAXDIFF: 7 bytes: 7603200/ 760320 diff --git a/tests/ref/vsynth/vsynth3-dnxhd-1080i-10bit b/tests/ref/vsynth/vsynth3-dnxhd-1080i-10bit index 006af6c5d..2a040e12d 100644 --- a/tests/ref/vsynth/vsynth3-dnxhd-1080i-10bit +++ b/tests/ref/vsynth/vsynth3-dnxhd-1080i-10bit @@ -1,4 +1,4 @@ -dea8862f8ae9fb03f665f358dde75962 *tests/data/fate/vsynth3-dnxhd-1080i-10bit.mov +4e6185e273297061def8e0b7fabff71b *tests/data/fate/vsynth3-dnxhd-1080i-10bit.mov 4588391 tests/data/fate/vsynth3-dnxhd-1080i-10bit.mov c192f36ef8687e56c72a3dc416c7e191 *tests/data/fate/vsynth3-dnxhd-1080i-10bit.out.rawvideo stddev: 6.92 PSNR: 31.32 MAXDIFF: 50 bytes: 86700/ 8670 diff --git a/tests/ref/vsynth/vsynth3-dnxhd-1080i-colr b/tests/ref/vsynth/vsynth3-dnxhd-1080i-colr index 8d7d3b653..093489e45 100644 --- a/tests/ref/vsynth/vsynth3-dnxhd-1080i-colr +++ b/tests/ref/vsynth/vsynth3-dnxhd-1080i-colr @@ -1,4 +1,4 @@ -ee7a70832f37793b62642f770d988bdb *tests/data/fate/vsynth3-dnxhd-1080i-colr.mov +f5a7d7f837a750784458c60fb7b4d091 *tests/data/fate/vsynth3-dnxhd-1080i-colr.mov 3031929 tests/data/fate/vsynth3-dnxhd-1080i-colr.mov f907fd2d48bedbc5283fbfc3fb9f61a0 *tests/data/fate/vsynth3-dnxhd-1080i-colr.out.rawvideo stddev: 6.92 PSNR: 31.32 MAXDIFF: 50 bytes: 86700/ 8670 diff --git a/tests/ref/vsynth/vsynth3-dnxhd-hr-hq-mov b/tests/ref/vsynth/vsynth3-dnxhd-hr-hq-mov index e46e1514b..a5808dd77 100644 --- a/tests/ref/vsynth/vsynth3-dnxhd-hr-hq-mov +++ b/tests/ref/vsynth/vsynth3-dnxhd-hr-hq-mov @@ -1,4 +1,4 @@ -ca442de6ac8971a1da0afed0ee7fbd18 *tests/data/fate/vsynth3-dnxhd-hr-hq-mov.mov +1b9e337636198690850f102c7a987eae *tests/data/fate/vsynth3-dnxhd-hr-hq-mov.mov 4772599 tests/data/fate/vsynth3-dnxhd-hr-hq-mov.mov aa2e6c13a1e7760a22fccfca9faacdf3 *tests/data/fate/vsynth3-dnxhd-hr-hq-mov.out.rawvideo stddev: 6.92 PSNR: 31.32 MAXDIFF: 50 bytes: 86700/ 8670 diff --git a/tests/ref/vsynth/vsynth3-dnxhd-hr-lb-mov b/tests/ref/vsynth/vsynth3-dnxhd-hr-lb-mov index f869caf0c..7a888c5b0 100644 --- a/tests/ref/vsynth/vsynth3-dnxhd-hr-lb-mov +++ b/tests/ref/vsynth/vsynth3-dnxhd-hr-lb-mov @@ -1,4 +1,4 @@ -921f16751950320d8da7a1dde215c2ff *tests/data/fate/vsynth3-dnxhd-hr-lb-mov.mov +1ac0627cfcad3df568026aea4696901f *tests/data/fate/vsynth3-dnxhd-hr-lb-mov.mov 3748599 tests/data/fate/vsynth3-dnxhd-hr-lb-mov.mov 1a4d12fd893e4585944dd9c68fb23edf *tests/data/fate/vsynth3-dnxhd-hr-lb-mov.out.rawvideo stddev: 6.92 PSNR: 31.32 MAXDIFF: 50 bytes: 86700/ 8670 diff --git a/tests/ref/vsynth/vsynth3-dnxhd-hr-sq-mov b/tests/ref/vsynth/vsynth3-dnxhd-hr-sq-mov index b247ce787..bd94e686c 100644 --- a/tests/ref/vsynth/vsynth3-dnxhd-hr-sq-mov +++ b/tests/ref/vsynth/vsynth3-dnxhd-hr-sq-mov @@ -1,4 +1,4 @@ -aa51e1aaf9bd8899e282096d2dcb4f25 *tests/data/fate/vsynth3-dnxhd-hr-sq-mov.mov +3b1420fc4cb6de03ea4a7858f5a0438e *tests/data/fate/vsynth3-dnxhd-hr-sq-mov.mov 2560763 tests/data/fate/vsynth3-dnxhd-hr-sq-mov.mov 730c00cc5a24e13ee99a75789806cb28 *tests/data/fate/vsynth3-dnxhd-hr-sq-mov.out.rawvideo stddev: 6.91 PSNR: 31.33 MAXDIFF: 50 bytes: 86700/ 8670 diff --git a/tests/ref/vsynth/vsynth3-mov-bgr24 b/tests/ref/vsynth/vsynth3-mov-bgr24 index 9ceb69eed..4fc3cc979 100644 --- a/tests/ref/vsynth/vsynth3-mov-bgr24 +++ b/tests/ref/vsynth/vsynth3-mov-bgr24 @@ -1,4 +1,4 @@ -9af1caa30e99cc422c8a0734051f7f95 *tests/data/fate/vsynth3-mov-bgr24.mov +0141cd3b6e8eea836d392adf6949afc4 *tests/data/fate/vsynth3-mov-bgr24.mov 174093 tests/data/fate/vsynth3-mov-bgr24.mov 693aff10c094f8bd31693f74cf79d2b2 *tests/data/fate/vsynth3-mov-bgr24.out.rawvideo stddev: 3.67 PSNR: 36.82 MAXDIFF: 43 bytes: 86700/ 86700 diff --git a/tests/ref/vsynth/vsynth3-mov-bpp15 b/tests/ref/vsynth/vsynth3-mov-bpp15 index dfee45858..4c289cf16 100644 --- a/tests/ref/vsynth/vsynth3-mov-bpp15 +++ b/tests/ref/vsynth/vsynth3-mov-bpp15 @@ -1,4 +1,4 @@ -3d64ea4e9c78e72fcedca5e00363db7b *tests/data/fate/vsynth3-mov-bpp15.mov +96e1406b041b16e9598092d928ea9d3e *tests/data/fate/vsynth3-mov-bpp15.mov 116293 tests/data/fate/vsynth3-mov-bpp15.mov 19f61c34cbdef98b0f4aca6c19f59ed4 *tests/data/fate/vsynth3-mov-bpp15.out.rawvideo stddev: 4.35 PSNR: 35.35 MAXDIFF: 46 bytes: 86700/ 86700 diff --git a/tests/ref/vsynth/vsynth3-mov-bpp16 b/tests/ref/vsynth/vsynth3-mov-bpp16 index 86c6d7ae6..55537d4bf 100644 --- a/tests/ref/vsynth/vsynth3-mov-bpp16 +++ b/tests/ref/vsynth/vsynth3-mov-bpp16 @@ -1,4 +1,4 @@ -ddff7831e0d3e950cee4fdb7fceeb76a *tests/data/fate/vsynth3-mov-bpp16.mov +65b51e9a83da767fae244fd6816f2bc7 *tests/data/fate/vsynth3-mov-bpp16.mov 116293 tests/data/fate/vsynth3-mov-bpp16.mov 756f68dd5412d245d4bbeda7b5d51829 *tests/data/fate/vsynth3-mov-bpp16.out.rawvideo stddev: 4.07 PSNR: 35.93 MAXDIFF: 46 bytes: 86700/ 86700 diff --git a/tests/ref/vsynth/vsynth3-prores b/tests/ref/vsynth/vsynth3-prores index f63a7a736..8dfaf09d2 100644 --- a/tests/ref/vsynth/vsynth3-prores +++ b/tests/ref/vsynth/vsynth3-prores @@ -1,4 +1,4 @@ -b060c59be88b4b089ece5ee8dc4f1c58 *tests/data/fate/vsynth3-prores.mov +3e6f1fd0e4fdad4a8dd351dec08b0bf5 *tests/data/fate/vsynth3-prores.mov 105367 tests/data/fate/vsynth3-prores.mov fff5e7ad21d78501c8fa4749bf4bf289 *tests/data/fate/vsynth3-prores.out.rawvideo stddev: 2.80 PSNR: 39.17 MAXDIFF: 27 bytes: 86700/ 86700 diff --git a/tests/ref/vsynth/vsynth3-prores_444 b/tests/ref/vsynth/vsynth3-prores_444 new file mode 100644 index 000000000..f05894b33 --- /dev/null +++ b/tests/ref/vsynth/vsynth3-prores_444 @@ -0,0 +1,4 @@ +3070da65c30c1a9905ee31c7ede1cf57 *tests/data/fate/vsynth3-prores_444.mov +159127 tests/data/fate/vsynth3-prores_444.mov +025b48feb3d9a9652983ef71e6cb7e7c *tests/data/fate/vsynth3-prores_444.out.rawvideo +stddev: 3.21 PSNR: 37.98 MAXDIFF: 41 bytes: 86700/ 86700 diff --git a/tests/ref/vsynth/vsynth3-prores_444_int b/tests/ref/vsynth/vsynth3-prores_444_int new file mode 100644 index 000000000..f6ba6bc28 --- /dev/null +++ b/tests/ref/vsynth/vsynth3-prores_444_int @@ -0,0 +1,4 @@ +c6279e0584575ffa1e2e13047cc7ecec *tests/data/fate/vsynth3-prores_444_int.mov +184397 tests/data/fate/vsynth3-prores_444_int.mov +a8852aa2841c2ce5f2aa86176ceda4ef *tests/data/fate/vsynth3-prores_444_int.out.rawvideo +stddev: 3.24 PSNR: 37.91 MAXDIFF: 41 bytes: 86700/ 86700 diff --git a/tests/ref/vsynth/vsynth3-prores_int b/tests/ref/vsynth/vsynth3-prores_int new file mode 100644 index 000000000..c9b8ba691 --- /dev/null +++ b/tests/ref/vsynth/vsynth3-prores_int @@ -0,0 +1,4 @@ +6085fc27cc6cc7c02abc59ce914d85cb *tests/data/fate/vsynth3-prores_int.mov +120484 tests/data/fate/vsynth3-prores_int.mov +e5859ba47a99f9e53c1ddcaa68a8f8f8 *tests/data/fate/vsynth3-prores_int.out.rawvideo +stddev: 2.92 PSNR: 38.81 MAXDIFF: 29 bytes: 86700/ 86700 diff --git a/tests/ref/vsynth/vsynth3-prores_ks b/tests/ref/vsynth/vsynth3-prores_ks index 99cfc1397..561ee48de 100644 --- a/tests/ref/vsynth/vsynth3-prores_ks +++ b/tests/ref/vsynth/vsynth3-prores_ks @@ -1,4 +1,4 @@ -7ceff8c9cffca766f8a167ba73dad0e2 *tests/data/fate/vsynth3-prores_ks.mov +f6ce1e8e2272cea0592d3f969d48c1de *tests/data/fate/vsynth3-prores_ks.mov 95053 tests/data/fate/vsynth3-prores_ks.mov 9ab6d3e3cc7749796cd9fa984c60d890 *tests/data/fate/vsynth3-prores_ks.out.rawvideo stddev: 4.09 PSNR: 35.88 MAXDIFF: 35 bytes: 86700/ 86700 diff --git a/tests/ref/vsynth/vsynth3-qtrle b/tests/ref/vsynth/vsynth3-qtrle index 6f9323278..2056e1b7e 100644 --- a/tests/ref/vsynth/vsynth3-qtrle +++ b/tests/ref/vsynth/vsynth3-qtrle @@ -1,4 +1,4 @@ -33ec7d4f0a18fcf6da3bdacb494e2035 *tests/data/fate/vsynth3-qtrle.mov +b9152e4c2931818140086903c9d9a8ae *tests/data/fate/vsynth3-qtrle.mov 179656 tests/data/fate/vsynth3-qtrle.mov 693aff10c094f8bd31693f74cf79d2b2 *tests/data/fate/vsynth3-qtrle.out.rawvideo stddev: 3.67 PSNR: 36.82 MAXDIFF: 43 bytes: 86700/ 86700 diff --git a/tests/ref/vsynth/vsynth3-r210 b/tests/ref/vsynth/vsynth3-r210 index 75c424cf2..253657cd8 100644 --- a/tests/ref/vsynth/vsynth3-r210 +++ b/tests/ref/vsynth/vsynth3-r210 @@ -1,4 +1,4 @@ -229e700e0fab4e81481e99a70e00bec9 *tests/data/fate/vsynth3-r210.avi +fd12f6dde75d0872ccf9012b342208de *tests/data/fate/vsynth3-r210.avi 442052 tests/data/fate/vsynth3-r210.avi -e1d882babc8754f7418aa91ce48f7ab0 *tests/data/fate/vsynth3-r210.out.rawvideo -stddev: 3.48 PSNR: 37.28 MAXDIFF: 42 bytes: 86700/ 86700 +a2c4e460ebede1109bd794b1b7b05a1f *tests/data/fate/vsynth3-r210.out.rawvideo +stddev: 4.10 PSNR: 35.87 MAXDIFF: 48 bytes: 86700/ 86700 diff --git a/tests/ref/vsynth/vsynth3-svq1 b/tests/ref/vsynth/vsynth3-svq1 index b51fa03e8..e760abbdb 100644 --- a/tests/ref/vsynth/vsynth3-svq1 +++ b/tests/ref/vsynth/vsynth3-svq1 @@ -1,4 +1,4 @@ -1eaf318269afd7426406d73397c39a48 *tests/data/fate/vsynth3-svq1.mov +1972e0df8be667443992e405cceec291 *tests/data/fate/vsynth3-svq1.mov 40773 tests/data/fate/vsynth3-svq1.mov a1e5334cf67649bf8c7d95dc4d1bf148 *tests/data/fate/vsynth3-svq1.out.rawvideo stddev: 14.49 PSNR: 24.91 MAXDIFF: 183 bytes: 86700/ 86700 diff --git a/tests/ref/vsynth/vsynth_lena-avui b/tests/ref/vsynth/vsynth_lena-avui index c2fced8e6..f4e5ef943 100644 --- a/tests/ref/vsynth/vsynth_lena-avui +++ b/tests/ref/vsynth/vsynth_lena-avui @@ -1,4 +1,4 @@ -26805e15d9e732cd24aea91ae564d5c3 *tests/data/fate/vsynth_lena-avui.mov +7b670636544a60f4fb2c153e3caabdee *tests/data/fate/vsynth_lena-avui.mov 42625037 tests/data/fate/vsynth_lena-avui.mov dde5895817ad9d219f79a52d0bdfb001 *tests/data/fate/vsynth_lena-avui.out.rawvideo stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 7603200/ 7603200 diff --git a/tests/ref/vsynth/vsynth_lena-dnxhd-1080i b/tests/ref/vsynth/vsynth_lena-dnxhd-1080i index 16702db71..ae5c51516 100644 --- a/tests/ref/vsynth/vsynth_lena-dnxhd-1080i +++ b/tests/ref/vsynth/vsynth_lena-dnxhd-1080i @@ -1,4 +1,4 @@ -f7412afbcb4454692f7492f6710189e3 *tests/data/fate/vsynth_lena-dnxhd-1080i.mov +1bb94b5a7917c1d81f3a92dd9b5b66ae *tests/data/fate/vsynth_lena-dnxhd-1080i.mov 3031911 tests/data/fate/vsynth_lena-dnxhd-1080i.mov 7d0ca92f12711535d57eff3609462b31 *tests/data/fate/vsynth_lena-dnxhd-1080i.out.rawvideo stddev: 1.29 PSNR: 45.87 MAXDIFF: 22 bytes: 7603200/ 760320 diff --git a/tests/ref/vsynth/vsynth_lena-dnxhd-1080i-10bit b/tests/ref/vsynth/vsynth_lena-dnxhd-1080i-10bit index 109e3d562..5112f2a37 100644 --- a/tests/ref/vsynth/vsynth_lena-dnxhd-1080i-10bit +++ b/tests/ref/vsynth/vsynth_lena-dnxhd-1080i-10bit @@ -1,4 +1,4 @@ -72144676d0c6e320ff2c9b28bc3e4fa2 *tests/data/fate/vsynth_lena-dnxhd-1080i-10bit.mov +55e1097376ac44e916528eee5ee2266e *tests/data/fate/vsynth_lena-dnxhd-1080i-10bit.mov 4588391 tests/data/fate/vsynth_lena-dnxhd-1080i-10bit.mov f2dc4375c58e0406d442e0cb28573e91 *tests/data/fate/vsynth_lena-dnxhd-1080i-10bit.out.rawvideo stddev: 1.36 PSNR: 45.40 MAXDIFF: 22 bytes: 7603200/ 760320 diff --git a/tests/ref/vsynth/vsynth_lena-dnxhd-1080i-colr b/tests/ref/vsynth/vsynth_lena-dnxhd-1080i-colr index 8e43a3f9d..ae855cd46 100644 --- a/tests/ref/vsynth/vsynth_lena-dnxhd-1080i-colr +++ b/tests/ref/vsynth/vsynth_lena-dnxhd-1080i-colr @@ -1,4 +1,4 @@ -5ba3ddb58b10e5f0069cb4f82d594695 *tests/data/fate/vsynth_lena-dnxhd-1080i-colr.mov +3a681c0e174ccf85fe1504cdf8546788 *tests/data/fate/vsynth_lena-dnxhd-1080i-colr.mov 3031929 tests/data/fate/vsynth_lena-dnxhd-1080i-colr.mov ce4993a69ef55c8c4b18138716f17b6f *tests/data/fate/vsynth_lena-dnxhd-1080i-colr.out.rawvideo stddev: 1.33 PSNR: 45.59 MAXDIFF: 22 bytes: 7603200/ 760320 diff --git a/tests/ref/vsynth/vsynth_lena-dnxhd-hr-hq-mov b/tests/ref/vsynth/vsynth_lena-dnxhd-hr-hq-mov index 9cea76242..2d58c5e7a 100644 --- a/tests/ref/vsynth/vsynth_lena-dnxhd-hr-hq-mov +++ b/tests/ref/vsynth/vsynth_lena-dnxhd-hr-hq-mov @@ -1,4 +1,4 @@ -b232775e04c6a6a7995799db6cd8c255 *tests/data/fate/vsynth_lena-dnxhd-hr-hq-mov.mov +f19dfcd4d9d7a0da1131c0dd909ad0ae *tests/data/fate/vsynth_lena-dnxhd-hr-hq-mov.mov 4772599 tests/data/fate/vsynth_lena-dnxhd-hr-hq-mov.mov e6c3531cb32eb3d0c465c44098746fea *tests/data/fate/vsynth_lena-dnxhd-hr-hq-mov.out.rawvideo stddev: 1.34 PSNR: 45.54 MAXDIFF: 23 bytes: 7603200/ 760320 diff --git a/tests/ref/vsynth/vsynth_lena-dnxhd-hr-lb-mov b/tests/ref/vsynth/vsynth_lena-dnxhd-hr-lb-mov index a582b882d..904780556 100644 --- a/tests/ref/vsynth/vsynth_lena-dnxhd-hr-lb-mov +++ b/tests/ref/vsynth/vsynth_lena-dnxhd-hr-lb-mov @@ -1,4 +1,4 @@ -2c6881ebb8efdb02189862f67cd72851 *tests/data/fate/vsynth_lena-dnxhd-hr-lb-mov.mov +f27068c1444d2e11e094fab37eceb9d5 *tests/data/fate/vsynth_lena-dnxhd-hr-lb-mov.mov 3748599 tests/data/fate/vsynth_lena-dnxhd-hr-lb-mov.mov 0951de00b90d1bf34d2ff10a51db705d *tests/data/fate/vsynth_lena-dnxhd-hr-lb-mov.out.rawvideo stddev: 1.31 PSNR: 45.72 MAXDIFF: 21 bytes: 7603200/ 760320 diff --git a/tests/ref/vsynth/vsynth_lena-dnxhd-hr-sq-mov b/tests/ref/vsynth/vsynth_lena-dnxhd-hr-sq-mov index 80a689785..9a2db8a88 100644 --- a/tests/ref/vsynth/vsynth_lena-dnxhd-hr-sq-mov +++ b/tests/ref/vsynth/vsynth_lena-dnxhd-hr-sq-mov @@ -1,4 +1,4 @@ -b3b2380b019f0f655af5d61caa76cf12 *tests/data/fate/vsynth_lena-dnxhd-hr-sq-mov.mov +b1d5da9fd4811b87b1bf05afee6e44e4 *tests/data/fate/vsynth_lena-dnxhd-hr-sq-mov.mov 2560763 tests/data/fate/vsynth_lena-dnxhd-hr-sq-mov.mov 95e7da46fc066ed795de4ec1cf4d4ab5 *tests/data/fate/vsynth_lena-dnxhd-hr-sq-mov.out.rawvideo stddev: 1.35 PSNR: 45.51 MAXDIFF: 23 bytes: 7603200/ 760320 diff --git a/tests/ref/vsynth/vsynth_lena-mov-bgr24 b/tests/ref/vsynth/vsynth_lena-mov-bgr24 index 3117bf2a8..098dd9125 100644 --- a/tests/ref/vsynth/vsynth_lena-mov-bgr24 +++ b/tests/ref/vsynth/vsynth_lena-mov-bgr24 @@ -1,4 +1,4 @@ -f1eccd8c8719e3fabfe7855dad997699 *tests/data/fate/vsynth_lena-mov-bgr24.mov +3656f10647727ff16119ad54e11ed09d *tests/data/fate/vsynth_lena-mov-bgr24.mov 15207169 tests/data/fate/vsynth_lena-mov-bgr24.mov 98d0e2854731472c5bf13d8638502d0a *tests/data/fate/vsynth_lena-mov-bgr24.out.rawvideo stddev: 1.26 PSNR: 46.10 MAXDIFF: 13 bytes: 7603200/ 7603200 diff --git a/tests/ref/vsynth/vsynth_lena-mov-bpp15 b/tests/ref/vsynth/vsynth_lena-mov-bpp15 index 2a7ddd671..7a61797ef 100644 --- a/tests/ref/vsynth/vsynth_lena-mov-bpp15 +++ b/tests/ref/vsynth/vsynth_lena-mov-bpp15 @@ -1,4 +1,4 @@ -286e9e0712da1efb186a7228b6d4a177 *tests/data/fate/vsynth_lena-mov-bpp15.mov +846672fbdf449e0345cec63e1611661a *tests/data/fate/vsynth_lena-mov-bpp15.mov 10138329 tests/data/fate/vsynth_lena-mov-bpp15.mov be0e64bdf519ce1097613063804eded9 *tests/data/fate/vsynth_lena-mov-bpp15.out.rawvideo stddev: 2.16 PSNR: 41.43 MAXDIFF: 17 bytes: 7603200/ 7603200 diff --git a/tests/ref/vsynth/vsynth_lena-mov-bpp16 b/tests/ref/vsynth/vsynth_lena-mov-bpp16 index 2c478b904..4e4cb44da 100644 --- a/tests/ref/vsynth/vsynth_lena-mov-bpp16 +++ b/tests/ref/vsynth/vsynth_lena-mov-bpp16 @@ -1,4 +1,4 @@ -1da4058a0cfb241d735ed46a0b18efa3 *tests/data/fate/vsynth_lena-mov-bpp16.mov +f425fe7f36bd821d4afa260088542cf9 *tests/data/fate/vsynth_lena-mov-bpp16.mov 10138329 tests/data/fate/vsynth_lena-mov-bpp16.mov 789bfa1dc2a72f498928f2ae85e461c3 *tests/data/fate/vsynth_lena-mov-bpp16.out.rawvideo stddev: 1.76 PSNR: 43.18 MAXDIFF: 17 bytes: 7603200/ 7603200 diff --git a/tests/ref/vsynth/vsynth_lena-prores b/tests/ref/vsynth/vsynth_lena-prores index 5b8c3fe1b..573fc1273 100644 --- a/tests/ref/vsynth/vsynth_lena-prores +++ b/tests/ref/vsynth/vsynth_lena-prores @@ -1,4 +1,4 @@ -637f34b5fd81f072f76a967595fa6af7 *tests/data/fate/vsynth_lena-prores.mov +eed04261f5d5878ea3b91321420270a0 *tests/data/fate/vsynth_lena-prores.mov 2844076 tests/data/fate/vsynth_lena-prores.mov 03fd29e3963716a09d232b6f817ecb57 *tests/data/fate/vsynth_lena-prores.out.rawvideo stddev: 1.31 PSNR: 45.77 MAXDIFF: 11 bytes: 7603200/ 7603200 diff --git a/tests/ref/vsynth/vsynth_lena-prores_444 b/tests/ref/vsynth/vsynth_lena-prores_444 new file mode 100644 index 000000000..29141239c --- /dev/null +++ b/tests/ref/vsynth/vsynth_lena-prores_444 @@ -0,0 +1,4 @@ +b8677f9e1da7be861e8b7207028b3a9e *tests/data/fate/vsynth_lena-prores_444.mov +4734395 tests/data/fate/vsynth_lena-prores_444.mov +a704e05e3e0a451edef7515b25a76bb8 *tests/data/fate/vsynth_lena-prores_444.out.rawvideo +stddev: 0.81 PSNR: 49.88 MAXDIFF: 8 bytes: 7603200/ 7603200 diff --git a/tests/ref/vsynth/vsynth_lena-prores_444_int b/tests/ref/vsynth/vsynth_lena-prores_444_int new file mode 100644 index 000000000..005ab68cc --- /dev/null +++ b/tests/ref/vsynth/vsynth_lena-prores_444_int @@ -0,0 +1,4 @@ +38195b0437f6ae1c910ba108e7a799d1 *tests/data/fate/vsynth_lena-prores_444_int.mov +5696258 tests/data/fate/vsynth_lena-prores_444_int.mov +466380156e4d2b811f4ffb9c5a8bca72 *tests/data/fate/vsynth_lena-prores_444_int.out.rawvideo +stddev: 0.88 PSNR: 49.23 MAXDIFF: 9 bytes: 7603200/ 7603200 diff --git a/tests/ref/vsynth/vsynth_lena-prores_int b/tests/ref/vsynth/vsynth_lena-prores_int new file mode 100644 index 000000000..3e31b018d --- /dev/null +++ b/tests/ref/vsynth/vsynth_lena-prores_int @@ -0,0 +1,4 @@ +f45bc9026780bbbcdbbcc0d54c21ef06 *tests/data/fate/vsynth_lena-prores_int.mov +3532698 tests/data/fate/vsynth_lena-prores_int.mov +eb5caa9824ca294f403cd13f33c40f23 *tests/data/fate/vsynth_lena-prores_int.out.rawvideo +stddev: 1.47 PSNR: 44.78 MAXDIFF: 12 bytes: 7603200/ 7603200 diff --git a/tests/ref/vsynth/vsynth_lena-prores_ks b/tests/ref/vsynth/vsynth_lena-prores_ks index 0cdfa9bb2..333578bc1 100644 --- a/tests/ref/vsynth/vsynth_lena-prores_ks +++ b/tests/ref/vsynth/vsynth_lena-prores_ks @@ -1,4 +1,4 @@ -b03741c69037cbdcd2809278c00c0350 *tests/data/fate/vsynth_lena-prores_ks.mov +86b9932d5f78d0b5836533e972a37a65 *tests/data/fate/vsynth_lena-prores_ks.mov 3884596 tests/data/fate/vsynth_lena-prores_ks.mov 6cfe987de99cf8ac9d43bdc5cd150838 *tests/data/fate/vsynth_lena-prores_ks.out.rawvideo stddev: 0.92 PSNR: 48.78 MAXDIFF: 10 bytes: 7603200/ 7603200 diff --git a/tests/ref/vsynth/vsynth_lena-qtrle b/tests/ref/vsynth/vsynth_lena-qtrle index 9ce6abe5b..f426fe0ab 100644 --- a/tests/ref/vsynth/vsynth_lena-qtrle +++ b/tests/ref/vsynth/vsynth_lena-qtrle @@ -1,4 +1,4 @@ -4863978263d966d704ffaaa6d23123bb *tests/data/fate/vsynth_lena-qtrle.mov +513ca7d64af25676f5f99f00e2287ced *tests/data/fate/vsynth_lena-qtrle.mov 14798345 tests/data/fate/vsynth_lena-qtrle.mov 98d0e2854731472c5bf13d8638502d0a *tests/data/fate/vsynth_lena-qtrle.out.rawvideo stddev: 1.26 PSNR: 46.10 MAXDIFF: 13 bytes: 7603200/ 7603200 diff --git a/tests/ref/vsynth/vsynth_lena-qtrlegray b/tests/ref/vsynth/vsynth_lena-qtrlegray index 951e7a768..e0c18c970 100644 --- a/tests/ref/vsynth/vsynth_lena-qtrlegray +++ b/tests/ref/vsynth/vsynth_lena-qtrlegray @@ -1,4 +1,4 @@ -2c4e69b59d8e8e19903c843575806d5f *tests/data/fate/vsynth_lena-qtrlegray.mov +8db6b52b706a91f483c37eaa2f011cfe *tests/data/fate/vsynth_lena-qtrlegray.mov 5111283 tests/data/fate/vsynth_lena-qtrlegray.mov d7bfbe259af9ae323bb94b09c33570a5 *tests/data/fate/vsynth_lena-qtrlegray.out.rawvideo stddev: 18.65 PSNR: 22.72 MAXDIFF: 72 bytes: 7603200/ 7603200 diff --git a/tests/ref/vsynth/vsynth_lena-r210 b/tests/ref/vsynth/vsynth_lena-r210 index 8fd1a666a..0a113dc69 100644 --- a/tests/ref/vsynth/vsynth_lena-r210 +++ b/tests/ref/vsynth/vsynth_lena-r210 @@ -1,4 +1,4 @@ -94874a48987fd401494f4d7ca8e1273b *tests/data/fate/vsynth_lena-r210.avi +61fd53566d99b725e75212747b35893f *tests/data/fate/vsynth_lena-r210.avi 22125252 tests/data/fate/vsynth_lena-r210.avi -6ea4fcd93fc83defc8770e85b64b60bb *tests/data/fate/vsynth_lena-r210.out.rawvideo -stddev: 0.70 PSNR: 51.12 MAXDIFF: 12 bytes: 7603200/ 7603200 +4b7425191bb6a7fc4ca0dc649d9ba202 *tests/data/fate/vsynth_lena-r210.out.rawvideo +stddev: 0.93 PSNR: 48.72 MAXDIFF: 11 bytes: 7603200/ 7603200 diff --git a/tests/ref/vsynth/vsynth_lena-svq1 b/tests/ref/vsynth/vsynth_lena-svq1 index 1558c504f..01c1b06c7 100644 --- a/tests/ref/vsynth/vsynth_lena-svq1 +++ b/tests/ref/vsynth/vsynth_lena-svq1 @@ -1,4 +1,4 @@ -6e9678439ab7460db1fcc8e41ca1a1e0 *tests/data/fate/vsynth_lena-svq1.mov +a6398d8fd306cfe96dc41060335e67e8 *tests/data/fate/vsynth_lena-svq1.mov 766701 tests/data/fate/vsynth_lena-svq1.mov aa03471dac3f49455a33a2b19fda1098 *tests/data/fate/vsynth_lena-svq1.out.rawvideo stddev: 3.23 PSNR: 37.93 MAXDIFF: 61 bytes: 7603200/ 7603200 diff --git a/tests/ref/vsynth/vsynth_lena-vc2-420p b/tests/ref/vsynth/vsynth_lena-vc2-420p index 89966c2a5..cdaca3c83 100644 --- a/tests/ref/vsynth/vsynth_lena-vc2-420p +++ b/tests/ref/vsynth/vsynth_lena-vc2-420p @@ -1,4 +1,4 @@ -b920eaf484af9ed3fbff4a85d043b544 *tests/data/fate/vsynth_lena-vc2-420p.mov +9e1e6da4f166d6d4998923ad52d047c9 *tests/data/fate/vsynth_lena-vc2-420p.mov 849735 tests/data/fate/vsynth_lena-vc2-420p.mov b1c660113acab8eb4075f3d9fbb9cee9 *tests/data/fate/vsynth_lena-vc2-420p.out.rawvideo stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 7603200/ 760320 diff --git a/tests/ref/vsynth/vsynth_lena-vc2-420p10 b/tests/ref/vsynth/vsynth_lena-vc2-420p10 index 2558ef8e9..8ddb6acb5 100644 --- a/tests/ref/vsynth/vsynth_lena-vc2-420p10 +++ b/tests/ref/vsynth/vsynth_lena-vc2-420p10 @@ -1,4 +1,4 @@ -5bccec653c330f03b90065a84fad9b4b *tests/data/fate/vsynth_lena-vc2-420p10.mov +b989bdb42043851048f4b489463e585d *tests/data/fate/vsynth_lena-vc2-420p10.mov 1154775 tests/data/fate/vsynth_lena-vc2-420p10.mov b1c660113acab8eb4075f3d9fbb9cee9 *tests/data/fate/vsynth_lena-vc2-420p10.out.rawvideo stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 7603200/ 760320 diff --git a/tests/ref/vsynth/vsynth_lena-vc2-420p12 b/tests/ref/vsynth/vsynth_lena-vc2-420p12 index bc60116ff..efbb72964 100644 --- a/tests/ref/vsynth/vsynth_lena-vc2-420p12 +++ b/tests/ref/vsynth/vsynth_lena-vc2-420p12 @@ -1,4 +1,4 @@ -d27a6d3517cc9a6d22e338f4b206545c *tests/data/fate/vsynth_lena-vc2-420p12.mov +98c9ce4afcbedb6634b10dcba9e5d8ec *tests/data/fate/vsynth_lena-vc2-420p12.mov 1516759 tests/data/fate/vsynth_lena-vc2-420p12.mov b1c660113acab8eb4075f3d9fbb9cee9 *tests/data/fate/vsynth_lena-vc2-420p12.out.rawvideo stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 7603200/ 760320 diff --git a/tests/ref/vsynth/vsynth_lena-vc2-422p b/tests/ref/vsynth/vsynth_lena-vc2-422p index 6f958387c..388b80e97 100644 --- a/tests/ref/vsynth/vsynth_lena-vc2-422p +++ b/tests/ref/vsynth/vsynth_lena-vc2-422p @@ -1,4 +1,4 @@ -94d3a24e9eec6cb88c84780796adbec5 *tests/data/fate/vsynth_lena-vc2-422p.mov +f326f79e00a1499a4e387d01ea07b812 *tests/data/fate/vsynth_lena-vc2-422p.mov 1049287 tests/data/fate/vsynth_lena-vc2-422p.mov c4b2e69278c822f22655344068ea486d *tests/data/fate/vsynth_lena-vc2-422p.out.rawvideo stddev: 0.26 PSNR: 59.82 MAXDIFF: 5 bytes: 7603200/ 760320 diff --git a/tests/ref/vsynth/vsynth_lena-vc2-422p10 b/tests/ref/vsynth/vsynth_lena-vc2-422p10 index 11904c2d8..e521da43e 100644 --- a/tests/ref/vsynth/vsynth_lena-vc2-422p10 +++ b/tests/ref/vsynth/vsynth_lena-vc2-422p10 @@ -1,4 +1,4 @@ -fc955b863eb3f22694d37e8a70085a6c *tests/data/fate/vsynth_lena-vc2-422p10.mov +b5a757abdf6e7e2a777520ecf99107b7 *tests/data/fate/vsynth_lena-vc2-422p10.mov 1294039 tests/data/fate/vsynth_lena-vc2-422p10.mov e5ea17416bda234ae58f27dea27e8135 *tests/data/fate/vsynth_lena-vc2-422p10.out.rawvideo stddev: 0.30 PSNR: 58.58 MAXDIFF: 5 bytes: 7603200/ 760320 diff --git a/tests/ref/vsynth/vsynth_lena-vc2-422p12 b/tests/ref/vsynth/vsynth_lena-vc2-422p12 index 51a62d0cc..3cf50b4da 100644 --- a/tests/ref/vsynth/vsynth_lena-vc2-422p12 +++ b/tests/ref/vsynth/vsynth_lena-vc2-422p12 @@ -1,4 +1,4 @@ -2cef57ce35f32642c829f24a0ca3e260 *tests/data/fate/vsynth_lena-vc2-422p12.mov +c2ec3fa0b1faf0cfdbee4410655037a0 *tests/data/fate/vsynth_lena-vc2-422p12.mov 1768027 tests/data/fate/vsynth_lena-vc2-422p12.mov bd374304997834410a69ee6c6e047d19 *tests/data/fate/vsynth_lena-vc2-422p12.out.rawvideo stddev: 0.29 PSNR: 58.76 MAXDIFF: 5 bytes: 7603200/ 760320 diff --git a/tests/ref/vsynth/vsynth_lena-vc2-444p b/tests/ref/vsynth/vsynth_lena-vc2-444p index bf779181f..1f9a9602a 100644 --- a/tests/ref/vsynth/vsynth_lena-vc2-444p +++ b/tests/ref/vsynth/vsynth_lena-vc2-444p @@ -1,4 +1,4 @@ -cbdf2421fdd6cf0789c1f308009666f6 *tests/data/fate/vsynth_lena-vc2-444p.mov +37eb0398cf913a66e0f628d6419775b5 *tests/data/fate/vsynth_lena-vc2-444p.mov 1174738 tests/data/fate/vsynth_lena-vc2-444p.mov f9306b14ff827ced1a992301d1ab02ca *tests/data/fate/vsynth_lena-vc2-444p.out.rawvideo stddev: 0.38 PSNR: 56.43 MAXDIFF: 6 bytes: 7603200/ 760320 diff --git a/tests/ref/vsynth/vsynth_lena-vc2-444p10 b/tests/ref/vsynth/vsynth_lena-vc2-444p10 index 10a33e22d..05d69169d 100644 --- a/tests/ref/vsynth/vsynth_lena-vc2-444p10 +++ b/tests/ref/vsynth/vsynth_lena-vc2-444p10 @@ -1,4 +1,4 @@ -acda7042ecc5b917824d9cf62ee3b46c *tests/data/fate/vsynth_lena-vc2-444p10.mov +c0de26ba4c95df2e07ab249158fa947c *tests/data/fate/vsynth_lena-vc2-444p10.mov 1577815 tests/data/fate/vsynth_lena-vc2-444p10.mov da13c67fe1c6d98dd73e92a6ba006edc *tests/data/fate/vsynth_lena-vc2-444p10.out.rawvideo stddev: 0.42 PSNR: 55.56 MAXDIFF: 7 bytes: 7603200/ 760320 diff --git a/tests/ref/vsynth/vsynth_lena-vc2-444p12 b/tests/ref/vsynth/vsynth_lena-vc2-444p12 index 7d6c21161..7d4f9b6a7 100644 --- a/tests/ref/vsynth/vsynth_lena-vc2-444p12 +++ b/tests/ref/vsynth/vsynth_lena-vc2-444p12 @@ -1,4 +1,4 @@ -a31f2e6a54896fb8c02272c9f50db716 *tests/data/fate/vsynth_lena-vc2-444p12.mov +effbd39862492bb3f81973ddce70a1d7 *tests/data/fate/vsynth_lena-vc2-444p12.mov 2134875 tests/data/fate/vsynth_lena-vc2-444p12.mov a505434ec95362772a57d274f63a3f5a *tests/data/fate/vsynth_lena-vc2-444p12.out.rawvideo stddev: 0.42 PSNR: 55.58 MAXDIFF: 7 bytes: 7603200/ 760320 diff --git a/tests/ref/vsynth/vsynth_lena-vc2-t5_3 b/tests/ref/vsynth/vsynth_lena-vc2-t5_3 new file mode 100644 index 000000000..50a60d7e2 --- /dev/null +++ b/tests/ref/vsynth/vsynth_lena-vc2-t5_3 @@ -0,0 +1,4 @@ +950197d63d02f51021c0ed238b44181b *tests/data/fate/vsynth_lena-vc2-t5_3.mov +1305436 tests/data/fate/vsynth_lena-vc2-t5_3.mov +e5ea17416bda234ae58f27dea27e8135 *tests/data/fate/vsynth_lena-vc2-t5_3.out.rawvideo +stddev: 0.30 PSNR: 58.58 MAXDIFF: 5 bytes: 7603200/ 760320 diff --git a/tests/ref/vsynth/vsynth_lena-vc2-thaar b/tests/ref/vsynth/vsynth_lena-vc2-thaar new file mode 100644 index 000000000..31be2836a --- /dev/null +++ b/tests/ref/vsynth/vsynth_lena-vc2-thaar @@ -0,0 +1,4 @@ +33a539a633dba8051c65c61564c578fd *tests/data/fate/vsynth_lena-vc2-thaar.mov +1431772 tests/data/fate/vsynth_lena-vc2-thaar.mov +e5ea17416bda234ae58f27dea27e8135 *tests/data/fate/vsynth_lena-vc2-thaar.out.rawvideo +stddev: 0.30 PSNR: 58.58 MAXDIFF: 5 bytes: 7603200/ 760320 diff --git a/tools/Makefile b/tools/Makefile index 3909e7cfd..370ee3541 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -5,7 +5,10 @@ TOOLS-$(CONFIG_ZLIB) += cws2fws tools/target_dec_%_fuzzer.o: tools/target_dec_fuzzer.c $(COMPILE_C) -DFFMPEG_DECODER=$* -OBJDIRS += tools +tools/target_dem_fuzzer.o: tools/target_dem_fuzzer.c + $(COMPILE_C) + +OUTDIRS += tools clean:: $(RM) $(CLEANSUFFIXES:%=tools/%) diff --git a/tools/crypto_bench.c b/tools/crypto_bench.c index 203bffe19..0aff4ea78 100644 --- a/tools/crypto_bench.c +++ b/tools/crypto_bench.c @@ -19,10 +19,11 @@ */ /* Optional external libraries; can be enabled using: - * make VERSUS=crypto+gcrypt+tomcrypt tools/crypto_bench */ + * make VERSUS=crypto+gcrypt+tomcrypt+mbedcrypto tools/crypto_bench */ #define USE_crypto 0x01 /* OpenSSL's libcrypto */ #define USE_gcrypt 0x02 /* GnuTLS's libgcrypt */ #define USE_tomcrypt 0x04 /* LibTomCrypt */ +#define USE_mbedcrypto 0x08 /* mbed TLS */ #include #include @@ -311,29 +312,140 @@ DEFINE_GCRYPT_WRAPPER(sha256, SHA256) DEFINE_GCRYPT_WRAPPER(sha512, SHA512) DEFINE_GCRYPT_WRAPPER(ripemd160, RMD160) -#define DEFINE_GCRYPT_CYPHER_WRAPPER(suffix, cypher, sz) \ +#define DEFINE_GCRYPT_CYPHER_WRAPPER(suffix, cypher, mode, sz) \ static void run_gcrypt_ ## suffix(uint8_t *output, \ const uint8_t *input, unsigned size) \ { \ static gcry_cipher_hd_t suffix; \ if (!suffix) \ - gcry_cipher_open(&suffix, GCRY_CIPHER_ ## cypher, GCRY_CIPHER_MODE_ECB, 0); \ + gcry_cipher_open(&suffix, GCRY_CIPHER_ ## cypher, GCRY_CIPHER_MODE_ ## mode, 0); \ gcry_cipher_setkey(suffix, hardcoded_key, sz); \ gcry_cipher_encrypt(suffix, output, size, input, size); \ } -DEFINE_GCRYPT_CYPHER_WRAPPER(aes128, AES128, 16) -DEFINE_GCRYPT_CYPHER_WRAPPER(blowfish, BLOWFISH, 16) -DEFINE_GCRYPT_CYPHER_WRAPPER(camellia, CAMELLIA128, 16) -DEFINE_GCRYPT_CYPHER_WRAPPER(cast128, CAST5, 16) -DEFINE_GCRYPT_CYPHER_WRAPPER(des, DES, 8) -DEFINE_GCRYPT_CYPHER_WRAPPER(twofish, TWOFISH128, 16) +DEFINE_GCRYPT_CYPHER_WRAPPER(aes128, AES128, ECB, 16) +DEFINE_GCRYPT_CYPHER_WRAPPER(blowfish, BLOWFISH, ECB, 16) +DEFINE_GCRYPT_CYPHER_WRAPPER(camellia, CAMELLIA128, ECB, 16) +DEFINE_GCRYPT_CYPHER_WRAPPER(cast128, CAST5, ECB, 16) +DEFINE_GCRYPT_CYPHER_WRAPPER(des, DES, ECB, 8) +DEFINE_GCRYPT_CYPHER_WRAPPER(twofish, TWOFISH128, ECB, 16) +DEFINE_GCRYPT_CYPHER_WRAPPER(rc4, ARCFOUR, STREAM, 16) #define IMPL_USE_gcrypt(...) IMPL_USE(__VA_ARGS__) #else #define IMPL_USE_gcrypt(...) /* ignore */ #endif +/*************************************************************************** + * mbedcrypto: mbed TLS + ***************************************************************************/ + +#if (USE_EXT_LIBS) & USE_mbedcrypto + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DEFINE_MBEDCRYPTO_WRAPPER(suffix) \ +static void run_mbedcrypto_ ## suffix(uint8_t *output, \ + const uint8_t *input, unsigned size) \ +{ \ + mbedtls_ ## suffix ## _ret(input, size, output); \ +} + +#define DEFINE_MBEDCRYPTO_WRAPPER_SHA2(suffix) \ +static void run_mbedcrypto_ ## suffix(uint8_t *output, \ + const uint8_t *input, unsigned size) \ +{ \ + mbedtls_ ## suffix ## _ret(input, size, output, 0); \ +} + +DEFINE_MBEDCRYPTO_WRAPPER(md5) +DEFINE_MBEDCRYPTO_WRAPPER(ripemd160) +DEFINE_MBEDCRYPTO_WRAPPER(sha1) +DEFINE_MBEDCRYPTO_WRAPPER_SHA2(sha256) +DEFINE_MBEDCRYPTO_WRAPPER_SHA2(sha512) + + +#define DEFINE_MBEDCRYPTO_CYPHER_WRAPPER(suffix, cypher, algo) \ +static void run_mbedcrypto_ ## suffix(uint8_t *output, \ + const uint8_t *input, unsigned size) \ +{ \ + mbedtls_ ## cypher ## _context cypher; \ + \ + mbedtls_ ## cypher ## _init(&cypher); \ + mbedtls_ ## cypher ## _setkey_enc(&cypher, hardcoded_key, 128); \ + for (int i = 0; i < size; i += 16) \ + mbedtls_ ## cypher ## _crypt_ecb(&cypher, MBEDTLS_ ## algo ## _ENCRYPT, \ + input + i, output + i); \ + mbedtls_ ## cypher ## _free(&cypher); \ +} + +DEFINE_MBEDCRYPTO_CYPHER_WRAPPER(aes128, aes, AES) +DEFINE_MBEDCRYPTO_CYPHER_WRAPPER(camellia, camellia, CAMELLIA) + +static void run_mbedcrypto_blowfish(uint8_t *output, + const uint8_t *input, unsigned size) +{ + mbedtls_blowfish_context blowfish; + + mbedtls_blowfish_init(&blowfish); + mbedtls_blowfish_setkey(&blowfish, hardcoded_key, 128); + for (int i = 0; i < size; i += 8) + mbedtls_blowfish_crypt_ecb(&blowfish, MBEDTLS_BLOWFISH_ENCRYPT, + input + i, output + i); + mbedtls_blowfish_free(&blowfish); +} + +static void run_mbedcrypto_des(uint8_t *output, + const uint8_t *input, unsigned size) +{ + mbedtls_des_context des; + + mbedtls_des_init(&des); + mbedtls_des_setkey_enc(&des, hardcoded_key); + for (int i = 0; i < size; i += 8) + mbedtls_des_crypt_ecb(&des, input + i, output + i); + mbedtls_des_free(&des); +} + +static void run_mbedcrypto_rc4(uint8_t *output, + const uint8_t *input, unsigned size) +{ + mbedtls_arc4_context rc4; + + mbedtls_arc4_init(&rc4); + mbedtls_arc4_setup(&rc4, hardcoded_key, 16); + mbedtls_arc4_crypt(&rc4, size, input, output); + mbedtls_arc4_free(&rc4); +} + +static void run_mbedcrypto_xtea(uint8_t *output, + const uint8_t *input, unsigned size) +{ + mbedtls_xtea_context xtea; + + mbedtls_xtea_init(&xtea); + mbedtls_xtea_setup(&xtea, hardcoded_key); + for (int i = 0; i < size; i += 8) + mbedtls_xtea_crypt_ecb(&xtea, MBEDTLS_XTEA_ENCRYPT, + input + i, output + i); + mbedtls_xtea_free(&xtea); +} + +#define IMPL_USE_mbedcrypto(...) IMPL_USE(__VA_ARGS__) +#else +#define IMPL_USE_mbedcrypto(...) /* ignore */ +#endif + /*************************************************************************** * tomcrypt: LibTomCrypt ***************************************************************************/ @@ -416,6 +528,16 @@ static void run_tomcrypt_des(uint8_t *output, des_ecb_encrypt(input + i, output + i, &des); } +static void run_tomcrypt_rc4(uint8_t *output, + const uint8_t *input, unsigned size) +{ + rc4_state rc4; + + rc4_stream_setup(&rc4, hardcoded_key, 16); + rc4_stream_crypt(&rc4, input, size, output); + rc4_stream_done(&rc4); +} + static void run_tomcrypt_twofish(uint8_t *output, const uint8_t *input, unsigned size) { @@ -512,6 +634,7 @@ static void run_implementation(const uint8_t *input, uint8_t *output, IMPL(lavu, __VA_ARGS__) \ IMPL(crypto, __VA_ARGS__) \ IMPL(gcrypt, __VA_ARGS__) \ + IMPL(mbedcrypto, __VA_ARGS__) \ IMPL(tomcrypt, __VA_ARGS__) struct hash_impl implementations[] = { @@ -525,22 +648,25 @@ struct hash_impl implementations[] = { IMPL_ALL("RIPEMD-160", ripemd160, "62a5321e4fc8784903bb43ab7752c75f8b25af00") IMPL_ALL("AES-128", aes128, "crc:ff6bc888") IMPL_ALL("CAMELLIA", camellia, "crc:7abb59a7") - IMPL_ALL("CAST-128", cast128, "crc:456aa584") + IMPL(lavu, "CAST-128", cast128, "crc:456aa584") + IMPL(crypto, "CAST-128", cast128, "crc:456aa584") + IMPL(gcrypt, "CAST-128", cast128, "crc:456aa584") + IMPL(tomcrypt, "CAST-128", cast128, "crc:456aa584") IMPL_ALL("BLOWFISH", blowfish, "crc:33e8aa74") IMPL_ALL("DES", des, "crc:31291e0b") IMPL(lavu, "TWOFISH", twofish, "crc:9edbd5c1") IMPL(gcrypt, "TWOFISH", twofish, "crc:9edbd5c1") IMPL(tomcrypt, "TWOFISH", twofish, "crc:9edbd5c1") - IMPL(lavu, "RC4", rc4, "crc:538d37b2") - IMPL(crypto, "RC4", rc4, "crc:538d37b2") + IMPL_ALL("RC4", rc4, "crc:538d37b2") IMPL(lavu, "XTEA", xtea, "crc:931fc270") + IMPL(mbedcrypto, "XTEA", xtea, "crc:931fc270") IMPL(tomcrypt, "XTEA", xtea, "crc:931fc270") }; int main(int argc, char **argv) { - uint8_t *input = av_malloc(MAX_INPUT_SIZE * 2); - uint8_t *output = input + MAX_INPUT_SIZE; + uint8_t *input; + uint8_t *output; unsigned i, impl, size; int opt; @@ -561,26 +687,29 @@ int main(int argc, char **argv) argv[0]); if ((USE_EXT_LIBS)) { char buf[1024]; - snprintf(buf, sizeof(buf), "%s%s%s", + snprintf(buf, sizeof(buf), "%s%s%s%s", ((USE_EXT_LIBS) & USE_crypto) ? "+crypto" : "", ((USE_EXT_LIBS) & USE_gcrypt) ? "+gcrypt" : "", + ((USE_EXT_LIBS) & USE_mbedcrypto) ? "+mbedcrypto" : "", ((USE_EXT_LIBS) & USE_tomcrypt) ? "+tomcrypt" : ""); fprintf(stderr, "Built with the following external libraries:\n" "make VERSUS=%s\n", buf + 1); } else { fprintf(stderr, "Built without external libraries; use\n" - "make VERSUS=crypto+gcrypt+tomcrypt tools/crypto_bench\n" + "make VERSUS=crypto+gcrypt+mbedcrypto+tomcrypt tools/crypto_bench\n" "to enable them.\n"); } exit(opt != 'h'); } } - + input = av_malloc(MAX_INPUT_SIZE * 2); if (!input) fatal_error("out of memory"); for (i = 0; i < MAX_INPUT_SIZE; i += 4) AV_WB32(input + i, i); + output = input + MAX_INPUT_SIZE; + size = MAX_INPUT_SIZE; for (impl = 0; impl < FF_ARRAY_ELEMS(implementations); impl++) run_implementation(input, output, &implementations[impl], size); diff --git a/tools/python/convert.py b/tools/python/convert.py new file mode 100644 index 000000000..662b42906 --- /dev/null +++ b/tools/python/convert.py @@ -0,0 +1,52 @@ +# Copyright (c) 2019 Guo Yejun +# +# This file is part of FFmpeg. +# +# FFmpeg is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# FFmpeg is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with FFmpeg; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +# ============================================================================== + +# verified with Python 3.5.2 on Ubuntu 16.04 +import argparse +import os +from convert_from_tensorflow import * + +def get_arguments(): + parser = argparse.ArgumentParser(description='generate native mode model with weights from deep learning model') + parser.add_argument('--outdir', type=str, default='./', help='where to put generated files') + parser.add_argument('--infmt', type=str, default='tensorflow', help='format of the deep learning model') + parser.add_argument('infile', help='path to the deep learning model with weights') + + return parser.parse_args() + +def main(): + args = get_arguments() + + if not os.path.isfile(args.infile): + print('the specified input file %s does not exist' % args.infile) + exit(1) + + if not os.path.exists(args.outdir): + print('create output directory %s' % args.outdir) + os.mkdir(args.outdir) + + basefile = os.path.split(args.infile)[1] + basefile = os.path.splitext(basefile)[0] + outfile = os.path.join(args.outdir, basefile) + '.model' + + if args.infmt == 'tensorflow': + convert_from_tensorflow(args.infile, outfile) + +if __name__ == '__main__': + main() diff --git a/tools/python/convert_from_tensorflow.py b/tools/python/convert_from_tensorflow.py new file mode 100644 index 000000000..37049e58d --- /dev/null +++ b/tools/python/convert_from_tensorflow.py @@ -0,0 +1,201 @@ +# Copyright (c) 2019 Guo Yejun +# +# This file is part of FFmpeg. +# +# FFmpeg is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# FFmpeg is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with FFmpeg; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +# ============================================================================== + +import tensorflow as tf +import numpy as np +import sys, struct + +__all__ = ['convert_from_tensorflow'] + +# as the first step to be compatible with vf_sr, it is not general. +# it will be refined step by step. + +class TFConverter: + def __init__(self, graph_def, nodes, outfile): + self.graph_def = graph_def + self.nodes = nodes + self.outfile = outfile + self.layer_number = 0 + self.output_names = [] + self.name_node_dict = {} + self.edges = {} + self.conv_activations = {'Relu':0, 'Tanh':1, 'Sigmoid':2, 'LeakyRelu':4} + self.conv_paddings = {'VALID':2, 'SAME':1} + self.converted_nodes = set() + self.op2code = {'Conv2D':1, 'DepthToSpace':2} + + + def dump_for_tensorboard(self): + graph = tf.get_default_graph() + tf.import_graph_def(self.graph_def, name="") + # tensorboard --logdir=/tmp/graph + tf.summary.FileWriter('/tmp/graph', graph) + + + def get_conv2d_params(self, node): + knode = self.name_node_dict[node.input[1]] + bnode = None + activation = 'None' + next = self.edges[node.name][0] + if next.op == 'BiasAdd': + self.converted_nodes.add(next.name) + bnode = self.name_node_dict[next.input[1]] + next = self.edges[next.name][0] + if next.op in self.conv_activations: + self.converted_nodes.add(next.name) + activation = next.op + return knode, bnode, activation + + + def dump_conv2d_to_file(self, node, f): + assert(node.op == 'Conv2D') + self.layer_number = self.layer_number + 1 + self.converted_nodes.add(node.name) + knode, bnode, activation = self.get_conv2d_params(node) + + dilation = node.attr['dilations'].list.i[0] + padding = node.attr['padding'].s + padding = self.conv_paddings[padding.decode("utf-8")] + + ktensor = knode.attr['value'].tensor + filter_height = ktensor.tensor_shape.dim[0].size + filter_width = ktensor.tensor_shape.dim[1].size + in_channels = ktensor.tensor_shape.dim[2].size + out_channels = ktensor.tensor_shape.dim[3].size + kernel = np.frombuffer(ktensor.tensor_content, dtype=np.float32) + kernel = kernel.reshape(filter_height, filter_width, in_channels, out_channels) + kernel = np.transpose(kernel, [3, 0, 1, 2]) + + np.array([self.op2code[node.op], dilation, padding, self.conv_activations[activation], in_channels, out_channels, filter_height], dtype=np.uint32).tofile(f) + kernel.tofile(f) + + btensor = bnode.attr['value'].tensor + if btensor.tensor_shape.dim[0].size == 1: + bias = struct.pack("f", btensor.float_val[0]) + else: + bias = btensor.tensor_content + f.write(bias) + + + def dump_depth2space_to_file(self, node, f): + assert(node.op == 'DepthToSpace') + self.layer_number = self.layer_number + 1 + block_size = node.attr['block_size'].i + np.array([self.op2code[node.op], block_size], dtype=np.uint32).tofile(f) + self.converted_nodes.add(node.name) + + + def generate_layer_number(self): + # in current hard code implementation, the layer number is the first data written to the native model file + # it is not easy to know it at the beginning time in the general converter, so first do a dry run for compatibility + # will be refined later. + with open('/tmp/tmp.model', 'wb') as f: + self.dump_layers_to_file(f) + self.converted_nodes.clear() + + + def dump_layers_to_file(self, f): + for node in self.nodes: + if node.name in self.converted_nodes: + continue + if node.op == 'Conv2D': + self.dump_conv2d_to_file(node, f) + elif node.op == 'DepthToSpace': + self.dump_depth2space_to_file(node, f) + + + def dump_to_file(self): + self.generate_layer_number() + with open(self.outfile, 'wb') as f: + np.array([self.layer_number], dtype=np.uint32).tofile(f) + self.dump_layers_to_file(f) + + + def generate_name_node_dict(self): + for node in self.nodes: + self.name_node_dict[node.name] = node + + + def generate_output_names(self): + used_names = [] + for node in self.nodes: + for input in node.input: + used_names.append(input) + + for node in self.nodes: + if node.name not in used_names: + self.output_names.append(node.name) + + + def remove_identity(self): + id_nodes = [] + id_dict = {} + for node in self.nodes: + if node.op == 'Identity': + name = node.name + input = node.input[0] + id_nodes.append(node) + # do not change the output name + if name in self.output_names: + self.name_node_dict[input].name = name + self.name_node_dict[name] = self.name_node_dict[input] + del self.name_node_dict[input] + else: + id_dict[name] = input + + for idnode in id_nodes: + self.nodes.remove(idnode) + + for node in self.nodes: + for i in range(len(node.input)): + input = node.input[i] + if input in id_dict: + node.input[i] = id_dict[input] + + + def generate_edges(self): + for node in self.nodes: + for input in node.input: + if input in self.edges: + self.edges[input].append(node) + else: + self.edges[input] = [node] + + + def run(self): + self.generate_name_node_dict() + self.generate_output_names() + self.remove_identity() + self.generate_edges() + + #check the graph with tensorboard with human eyes + #self.dump_for_tensorboard() + + self.dump_to_file() + + +def convert_from_tensorflow(infile, outfile): + with open(infile, 'rb') as f: + # read the file in .proto format + graph_def = tf.GraphDef() + graph_def.ParseFromString(f.read()) + nodes = graph_def.node + + converter = TFConverter(graph_def, nodes, outfile) + converter.run() diff --git a/tools/qt-faststart.c b/tools/qt-faststart.c index 97be019c5..46950a5cf 100644 --- a/tools/qt-faststart.c +++ b/tools/qt-faststart.c @@ -28,6 +28,7 @@ #include #include #include +#include #ifdef __MINGW32__ #undef fseeko @@ -43,8 +44,6 @@ #define MIN(a,b) ((a) > (b) ? (b) : (a)) -#define BE_16(x) ((((uint8_t*)(x))[0] << 8) | ((uint8_t*)(x))[1]) - #define BE_32(x) (((uint32_t)(((uint8_t*)(x))[0]) << 24) | \ (((uint8_t*)(x))[1] << 16) | \ (((uint8_t*)(x))[2] << 8) | \ @@ -59,6 +58,18 @@ ((uint64_t)(((uint8_t*)(x))[6]) << 8) | \ ((uint64_t)( (uint8_t*)(x))[7])) +#define AV_WB32(p, val) { \ + ((uint8_t*)(p))[0] = ((val) >> 24) & 0xff; \ + ((uint8_t*)(p))[1] = ((val) >> 16) & 0xff; \ + ((uint8_t*)(p))[2] = ((val) >> 8) & 0xff; \ + ((uint8_t*)(p))[3] = (val) & 0xff; \ + } + +#define AV_WB64(p, val) { \ + AV_WB32(p, (val) >> 32) \ + AV_WB32(p + 4, val) \ + } + #define BE_FOURCC(ch0, ch1, ch2, ch3) \ ( (uint32_t)(unsigned char)(ch3) | \ ((uint32_t)(unsigned char)(ch2) << 8) | \ @@ -79,11 +90,342 @@ #define UUID_ATOM QT_ATOM('u', 'u', 'i', 'd') #define CMOV_ATOM QT_ATOM('c', 'm', 'o', 'v') +#define TRAK_ATOM QT_ATOM('t', 'r', 'a', 'k') +#define MDIA_ATOM QT_ATOM('m', 'd', 'i', 'a') +#define MINF_ATOM QT_ATOM('m', 'i', 'n', 'f') +#define STBL_ATOM QT_ATOM('s', 't', 'b', 'l') #define STCO_ATOM QT_ATOM('s', 't', 'c', 'o') #define CO64_ATOM QT_ATOM('c', 'o', '6', '4') #define ATOM_PREAMBLE_SIZE 8 #define COPY_BUFFER_SIZE 33554432 +#define MAX_FTYP_ATOM_SIZE 1048576 + +typedef struct { + uint32_t type; + uint32_t header_size; + uint64_t size; + unsigned char *data; +} atom_t; + +typedef struct { + uint64_t moov_atom_size; + uint64_t stco_offset_count; + uint64_t stco_data_size; + int stco_overflow; + uint32_t depth; +} update_chunk_offsets_context_t; + +typedef struct { + unsigned char *dest; + uint64_t original_moov_size; + uint64_t new_moov_size; +} upgrade_stco_context_t; + +typedef int (*parse_atoms_callback_t)(void *context, atom_t *atom); + +static int parse_atoms( + unsigned char *buf, + uint64_t size, + parse_atoms_callback_t callback, + void *context) +{ + unsigned char *pos = buf; + unsigned char *end = pos + size; + atom_t atom; + int ret; + + while (end - pos >= ATOM_PREAMBLE_SIZE) { + atom.size = BE_32(pos); + atom.type = BE_32(pos + 4); + pos += ATOM_PREAMBLE_SIZE; + atom.header_size = ATOM_PREAMBLE_SIZE; + + switch (atom.size) { + case 1: + if (end - pos < 8) { + fprintf(stderr, "not enough room for 64 bit atom size\n"); + return -1; + } + + atom.size = BE_64(pos); + pos += 8; + atom.header_size = ATOM_PREAMBLE_SIZE + 8; + break; + + case 0: + atom.size = ATOM_PREAMBLE_SIZE + end - pos; + break; + } + + if (atom.size < atom.header_size) { + fprintf(stderr, "atom size %"PRIu64" too small\n", atom.size); + return -1; + } + + atom.size -= atom.header_size; + + if (atom.size > end - pos) { + fprintf(stderr, "atom size %"PRIu64" too big\n", atom.size); + return -1; + } + + atom.data = pos; + ret = callback(context, &atom); + if (ret < 0) { + return ret; + } + + pos += atom.size; + } + + return 0; +} + +static int update_stco_offsets(update_chunk_offsets_context_t *context, atom_t *atom) +{ + uint32_t current_offset; + uint32_t offset_count; + unsigned char *pos; + unsigned char *end; + + printf(" patching stco atom...\n"); + if (atom->size < 8) { + fprintf(stderr, "stco atom size %"PRIu64" too small\n", atom->size); + return -1; + } + + offset_count = BE_32(atom->data + 4); + if (offset_count > (atom->size - 8) / 4) { + fprintf(stderr, "stco offset count %"PRIu32" too big\n", offset_count); + return -1; + } + + context->stco_offset_count += offset_count; + context->stco_data_size += atom->size - 8; + + for (pos = atom->data + 8, end = pos + offset_count * 4; + pos < end; + pos += 4) { + current_offset = BE_32(pos); + if (current_offset > UINT_MAX - context->moov_atom_size) { + context->stco_overflow = 1; + } + current_offset += context->moov_atom_size; + AV_WB32(pos, current_offset); + } + + return 0; +} + +static int update_co64_offsets(update_chunk_offsets_context_t *context, atom_t *atom) +{ + uint64_t current_offset; + uint32_t offset_count; + unsigned char *pos; + unsigned char *end; + + printf(" patching co64 atom...\n"); + if (atom->size < 8) { + fprintf(stderr, "co64 atom size %"PRIu64" too small\n", atom->size); + return -1; + } + + offset_count = BE_32(atom->data + 4); + if (offset_count > (atom->size - 8) / 8) { + fprintf(stderr, "co64 offset count %"PRIu32" too big\n", offset_count); + return -1; + } + + for (pos = atom->data + 8, end = pos + offset_count * 8; + pos < end; + pos += 8) { + current_offset = BE_64(pos); + current_offset += context->moov_atom_size; + AV_WB64(pos, current_offset); + } + + return 0; +} + +static int update_chunk_offsets_callback(void *ctx, atom_t *atom) +{ + update_chunk_offsets_context_t *context = ctx; + int ret; + + switch (atom->type) { + case STCO_ATOM: + return update_stco_offsets(context, atom); + + case CO64_ATOM: + return update_co64_offsets(context, atom); + + case MOOV_ATOM: + case TRAK_ATOM: + case MDIA_ATOM: + case MINF_ATOM: + case STBL_ATOM: + context->depth++; + if (context->depth > 10) { + fprintf(stderr, "atoms too deeply nested\n"); + return -1; + } + + ret = parse_atoms( + atom->data, + atom->size, + update_chunk_offsets_callback, + context); + context->depth--; + return ret; + } + + return 0; +} + +static void set_atom_size(unsigned char *header, uint32_t header_size, uint64_t size) +{ + switch (header_size) { + case 8: + AV_WB32(header, size); + break; + + case 16: + AV_WB64(header + 8, size); + break; + } +} + +static void upgrade_stco_atom(upgrade_stco_context_t *context, atom_t *atom) +{ + unsigned char *pos; + unsigned char *end; + uint64_t new_offset; + uint32_t offset_count; + uint32_t original_offset; + + /* Note: not performing validations since they were performed on the first pass */ + + offset_count = BE_32(atom->data + 4); + + /* write the header */ + memcpy(context->dest, atom->data - atom->header_size, atom->header_size + 8); + AV_WB32(context->dest + 4, CO64_ATOM); + set_atom_size(context->dest, atom->header_size, atom->header_size + 8 + offset_count * 8); + context->dest += atom->header_size + 8; + + /* write the data */ + for (pos = atom->data + 8, end = pos + offset_count * 4; + pos < end; + pos += 4) { + original_offset = BE_32(pos) - context->original_moov_size; + new_offset = (uint64_t)original_offset + context->new_moov_size; + AV_WB64(context->dest, new_offset); + context->dest += 8; + } +} + +static int upgrade_stco_callback(void *ctx, atom_t *atom) +{ + upgrade_stco_context_t *context = ctx; + unsigned char *start_pos; + uint64_t copy_size; + + switch (atom->type) { + case STCO_ATOM: + upgrade_stco_atom(context, atom); + break; + + case MOOV_ATOM: + case TRAK_ATOM: + case MDIA_ATOM: + case MINF_ATOM: + case STBL_ATOM: + /* write the atom header */ + memcpy(context->dest, atom->data - atom->header_size, atom->header_size); + start_pos = context->dest; + context->dest += atom->header_size; + + /* parse internal atoms*/ + if (parse_atoms( + atom->data, + atom->size, + upgrade_stco_callback, + context) < 0) { + return -1; + } + + /* update the atom size */ + set_atom_size(start_pos, atom->header_size, context->dest - start_pos); + break; + + default: + copy_size = atom->header_size + atom->size; + memcpy(context->dest, atom->data - atom->header_size, copy_size); + context->dest += copy_size; + break; + } + + return 0; +} + +static int update_moov_atom( + unsigned char **moov_atom, + uint64_t *moov_atom_size) +{ + update_chunk_offsets_context_t update_context = { 0 }; + upgrade_stco_context_t upgrade_context; + unsigned char *new_moov_atom; + + update_context.moov_atom_size = *moov_atom_size; + + if (parse_atoms( + *moov_atom, + *moov_atom_size, + update_chunk_offsets_callback, + &update_context) < 0) { + return -1; + } + + if (!update_context.stco_overflow) { + return 0; + } + + printf(" upgrading stco atoms to co64...\n"); + upgrade_context.new_moov_size = *moov_atom_size + + update_context.stco_offset_count * 8 - + update_context.stco_data_size; + + new_moov_atom = malloc(upgrade_context.new_moov_size); + if (new_moov_atom == NULL) { + fprintf(stderr, "could not allocate %"PRIu64" bytes for updated moov atom\n", + upgrade_context.new_moov_size); + return -1; + } + + upgrade_context.original_moov_size = *moov_atom_size; + upgrade_context.dest = new_moov_atom; + + if (parse_atoms( + *moov_atom, + *moov_atom_size, + upgrade_stco_callback, + &upgrade_context) < 0) { + free(new_moov_atom); + return -1; + } + + free(*moov_atom); + *moov_atom = new_moov_atom; + *moov_atom_size = upgrade_context.new_moov_size; + + if (upgrade_context.dest != *moov_atom + *moov_atom_size) { + fprintf(stderr, "unexpected - wrong number of moov bytes written\n"); + return -1; + } + + return 0; +} int main(int argc, char *argv[]) { @@ -98,12 +440,11 @@ int main(int argc, char *argv[]) unsigned char *ftyp_atom = NULL; uint64_t moov_atom_size; uint64_t ftyp_atom_size = 0; - uint64_t i, j; - uint32_t offset_count; - uint64_t current_offset; int64_t start_offset = 0; unsigned char *copy_buffer = NULL; int bytes_to_copy; + uint64_t free_size = 0; + uint64_t moov_size = 0; if (argc != 3) { printf("Usage: qt-faststart \n" @@ -133,11 +474,16 @@ int main(int argc, char *argv[]) /* keep ftyp atom */ if (atom_type == FTYP_ATOM) { + if (atom_size > MAX_FTYP_ATOM_SIZE) { + fprintf(stderr, "ftyp atom size %"PRIu64" too big\n", + atom_size); + goto error_out; + } ftyp_atom_size = atom_size; free(ftyp_atom); ftyp_atom = malloc(ftyp_atom_size); if (!ftyp_atom) { - printf("could not allocate %"PRIu64" bytes for ftyp atom\n", + fprintf(stderr, "could not allocate %"PRIu64" bytes for ftyp atom\n", atom_size); goto error_out; } @@ -181,7 +527,7 @@ int main(int argc, char *argv[]) (atom_type != PICT_ATOM) && (atom_type != UUID_ATOM) && (atom_type != FTYP_ATOM)) { - printf("encountered non-QT top-level atom (is this a QuickTime file?)\n"); + fprintf(stderr, "encountered non-QT top-level atom (is this a QuickTime file?)\n"); break; } atom_offset += atom_size; @@ -191,6 +537,15 @@ int main(int argc, char *argv[]) * able to continue scanning sensibly after this atom, so break. */ if (atom_size < 8) break; + + if (atom_type == MOOV_ATOM) + moov_size = atom_size; + + if (moov_size && atom_type == FREE_ATOM) { + free_size += atom_size; + atom_type = MOOV_ATOM; + atom_size = moov_size; + } } if (atom_type != MOOV_ATOM) { @@ -200,9 +555,14 @@ int main(int argc, char *argv[]) return 0; } + if (atom_size < 16) { + fprintf(stderr, "bad moov atom size\n"); + goto error_out; + } + /* moov atom was, in fact, the last atom in the chunk; load the whole * moov atom */ - if (fseeko(infile, -atom_size, SEEK_END)) { + if (fseeko(infile, -(atom_size + free_size), SEEK_END)) { perror(argv[1]); goto error_out; } @@ -214,7 +574,7 @@ int main(int argc, char *argv[]) moov_atom_size = atom_size; moov_atom = malloc(moov_atom_size); if (!moov_atom) { - printf("could not allocate %"PRIu64" bytes for moov atom\n", atom_size); + fprintf(stderr, "could not allocate %"PRIu64" bytes for moov atom\n", atom_size); goto error_out; } if (fread(moov_atom, atom_size, 1, infile) != 1) { @@ -225,7 +585,7 @@ int main(int argc, char *argv[]) /* this utility does not support compressed atoms yet, so disqualify * files with compressed QT atoms */ if (BE_32(&moov_atom[12]) == CMOV_ATOM) { - printf("this utility does not support compressed moov atoms yet\n"); + fprintf(stderr, "this utility does not support compressed moov atoms yet\n"); goto error_out; } @@ -233,56 +593,8 @@ int main(int argc, char *argv[]) fclose(infile); infile = NULL; - /* crawl through the moov chunk in search of stco or co64 atoms */ - for (i = 4; i < moov_atom_size - 4; i++) { - atom_type = BE_32(&moov_atom[i]); - if (atom_type == STCO_ATOM) { - printf(" patching stco atom...\n"); - atom_size = BE_32(&moov_atom[i - 4]); - if (i + atom_size - 4 > moov_atom_size) { - printf(" bad atom size\n"); - goto error_out; - } - offset_count = BE_32(&moov_atom[i + 8]); - if (i + 12 + offset_count * UINT64_C(4) > moov_atom_size) { - printf(" bad atom size/element count\n"); - goto error_out; - } - for (j = 0; j < offset_count; j++) { - current_offset = BE_32(&moov_atom[i + 12 + j * 4]); - current_offset += moov_atom_size; - moov_atom[i + 12 + j * 4 + 0] = (current_offset >> 24) & 0xFF; - moov_atom[i + 12 + j * 4 + 1] = (current_offset >> 16) & 0xFF; - moov_atom[i + 12 + j * 4 + 2] = (current_offset >> 8) & 0xFF; - moov_atom[i + 12 + j * 4 + 3] = (current_offset >> 0) & 0xFF; - } - i += atom_size - 4; - } else if (atom_type == CO64_ATOM) { - printf(" patching co64 atom...\n"); - atom_size = BE_32(&moov_atom[i - 4]); - if (i + atom_size - 4 > moov_atom_size) { - printf(" bad atom size\n"); - goto error_out; - } - offset_count = BE_32(&moov_atom[i + 8]); - if (i + 12 + offset_count * UINT64_C(8) > moov_atom_size) { - printf(" bad atom size/element count\n"); - goto error_out; - } - for (j = 0; j < offset_count; j++) { - current_offset = BE_64(&moov_atom[i + 12 + j * 8]); - current_offset += moov_atom_size; - moov_atom[i + 12 + j * 8 + 0] = (current_offset >> 56) & 0xFF; - moov_atom[i + 12 + j * 8 + 1] = (current_offset >> 48) & 0xFF; - moov_atom[i + 12 + j * 8 + 2] = (current_offset >> 40) & 0xFF; - moov_atom[i + 12 + j * 8 + 3] = (current_offset >> 32) & 0xFF; - moov_atom[i + 12 + j * 8 + 4] = (current_offset >> 24) & 0xFF; - moov_atom[i + 12 + j * 8 + 5] = (current_offset >> 16) & 0xFF; - moov_atom[i + 12 + j * 8 + 6] = (current_offset >> 8) & 0xFF; - moov_atom[i + 12 + j * 8 + 7] = (current_offset >> 0) & 0xFF; - } - i += atom_size - 4; - } + if (update_moov_atom(&moov_atom, &moov_atom_size) < 0) { + goto error_out; } /* re-open the input file and open the output file */ @@ -327,7 +639,7 @@ int main(int argc, char *argv[]) bytes_to_copy = MIN(COPY_BUFFER_SIZE, last_offset); copy_buffer = malloc(bytes_to_copy); if (!copy_buffer) { - printf("could not allocate %d bytes for copy_buffer\n", bytes_to_copy); + fprintf(stderr, "could not allocate %d bytes for copy_buffer\n", bytes_to_copy); goto error_out; } printf(" copying rest of file...\n"); diff --git a/tools/target_dec_fate.list b/tools/target_dec_fate.list new file mode 100644 index 000000000..13b0721a5 --- /dev/null +++ b/tools/target_dec_fate.list @@ -0,0 +1,656 @@ +496/clusterfuzz-testcase-5805083497332736 target_dec_jpegls_fuzzer +498/clusterfuzz-testcase-6157986632302592 target_dec_tiff_fuzzer +500/clusterfuzz-testcase-6315221727576064 target_dec_png_fuzzer +501/clusterfuzz-testcase-5672752870588416 target_dec_sipr_fuzzer +503/clusterfuzz-testcase-6386429735206912 target_dec_mp3_fuzzer +508/clusterfuzz-testcase-6245747678773248 target_dec_amrnb_fuzzer +510/clusterfuzz-testcase-5737865715646464 target_dec_dca_fuzzer +540/clusterfuzz-testcase-5674546153652224 target_dec_jpegls_fuzzer +544/clusterfuzz-testcase-5936536407244800.f8bd9b24_8ba77916_70c2c7be_3df6a2ea_96cd9f14 target_dec_interplay_video_fuzzer +546/clusterfuzz-testcase-4809433909559296 target_dec_png_fuzzer +555/clusterfuzz-testcase-5986646595993600 target_dec_movtext_fuzzer +559/clusterfuzz-testcase-6424225917173760 target_dec_pictor_fuzzer +607/clusterfuzz-testcase-5108792465293312 target_dec_wavpack_fuzzer +608/clusterfuzz-testcase-6039782863929344 target_dec_mpeg2video_fuzzer +609/clusterfuzz-testcase-4825202619842560 target_dec_png_fuzzer +610/clusterfuzz-testcase-4831030085156864 target_dec_ac3_fuzzer +611/clusterfuzz-testcase-5613455820193792 target_dec_mjpeg_fuzzer +612/clusterfuzz-testcase-4707817137111040 target_dec_mpeg4_fuzzer +614/clusterfuzz-testcase-4931860079575040 target_dec_h264_fuzzer +615/clusterfuzz-testcase-5488002644049920 target_dec_h264_fuzzer +616/clusterfuzz-testcase-5724692654587904 target_dec_jpegls_fuzzer +617/clusterfuzz-testcase-6413875723370496 target_dec_subrip_fuzzer +618/clusterfuzz-testcase-6594990333493248 target_dec_h263_fuzzer +619/clusterfuzz-testcase-5803914534322176 target_dec_dvbsub_fuzzer +622/clusterfuzz-testcase-5745722022428672 target_dec_pictor_fuzzer +626/clusterfuzz-testcase-4738718621499392 target_dec_flac_fuzzer +628/clusterfuzz-testcase-6187747641393152 target_dec_flac_fuzzer +629/clusterfuzz-testcase-6697457381539840 target_dec_dca_fuzzer +630/clusterfuzz-testcase-6608718928019456 target_dec_rv40_fuzzer +631/clusterfuzz-testcase-6725491035734016 target_dec_mp3_fuzzer +633/clusterfuzz-testcase-4553133554401280 target_dec_dvvideo_fuzzer +634/clusterfuzz-testcase-5285420445204480 target_dec_h264_fuzzer +637/clusterfuzz-testcase-5713159862091776 target_dec_rv40_fuzzer +639/clusterfuzz-testcase-5143866241974272 target_dec_h263_fuzzer +656/clusterfuzz-testcase-6463814516080640 target_dec_mpeg4_fuzzer +657/clusterfuzz-testcase-6674741433729024 target_dec_jpegls_fuzzer +658/clusterfuzz-testcase-6691260146384896 target_dec_mpeg4_fuzzer +659/clusterfuzz-testcase-5866673603084288 target_dec_h263_fuzzer +662/clusterfuzz-testcase-4898131432964096 target_dec_rv30_fuzzer +662/clusterfuzz-testcase-4898131432964096 target_dec_rv40_fuzzer +664/clusterfuzz-testcase-4917047475568640 target_dec_vp6_fuzzer +665/clusterfuzz-testcase-4863789881098240 target_dec_mp2_fuzzer +665/clusterfuzz-testcase-4863789881098240 target_dec_mp3_fuzzer +670/clusterfuzz-testcase-4852021066727424 target_dec_h263_fuzzer +671/clusterfuzz-testcase-4990381827555328 target_dec_mpeg1video_fuzzer +672/clusterfuzz-testcase-5595018867769344 target_dec_eac3_fuzzer +673/clusterfuzz-testcase-5948736536576000 target_dec_flac_fuzzer +674/clusterfuzz-testcase-6713275880308736 target_dec_mpeg4_fuzzer +675/clusterfuzz-testcase-6722971232108544 target_dec_pictor_fuzzer +677/clusterfuzz-testcase-6635120628858880 target_dec_h264_fuzzer +680/clusterfuzz-testcase-5416627266912256 target_dec_dca_fuzzer +681/clusterfuzz-testcase-5013323462475776 target_dec_dca_fuzzer +700/clusterfuzz-testcase-5660909504561152 target_dec_vp6_fuzzer +701/clusterfuzz-testcase-6594719951880192 target_dec_mpeg4_fuzzer +702/clusterfuzz-testcase-4553541576294400 target_dec_vp5_fuzzer +712/clusterfuzz-testcase-6647676227551232 target_dec_h264_fuzzer +713/clusterfuzz-testcase-4999324687663104 target_dec_h264_fuzzer +716/clusterfuzz-testcase-4890287480504320 target_dec_mpeg4_fuzzer +717/clusterfuzz-testcase-5434924129583104 target_dec_wavpack_fuzzer +719/clusterfuzz-testcase-6214837208088576 target_dec_vp6f_fuzzer +722/clusterfuzz-testcase-5711268868521984 target_dec_dca_fuzzer +723/clusterfuzz-testcase-6471394663596032 target_dec_wavpack_fuzzer +724/clusterfuzz-testcase-6738249571631104 target_dec_pictor_fuzzer +729/clusterfuzz-testcase-5154831595470848 target_dec_wavpack_fuzzer +730/clusterfuzz-testcase-5265113739165696 target_dec_vp8_fuzzer +731/clusterfuzz-testcase-5391628980191232 target_dec_flac_fuzzer +732/clusterfuzz-testcase-4872990070145024 target_dec_dca_fuzzer +733/clusterfuzz-testcase-4682158096515072 target_dec_mjpeg_fuzzer +734/clusterfuzz-testcase-4821293192970240 target_dec_h264_fuzzer +736/clusterfuzz-testcase-5580263943831552 target_dec_mpeg4_fuzzer +741/clusterfuzz-testcase-5869962004529152 target_dec_movtext_fuzzer +755/clusterfuzz-testcase-5369072516595712 target_dec_h264_fuzzer +758/clusterfuzz-testcase-4720832028868608 target_dec_vp5_fuzzer +761/clusterfuzz-testcase-5442222252097536 target_dec_wavpack_fuzzer +762/clusterfuzz-testcase-5927683747741696 target_dec_dca_fuzzer +763/clusterfuzz-testcase-6007567320875008 target_dec_amrwb_fuzzer +764/clusterfuzz-testcase-6273034652483584 target_dec_mpeg2video_fuzzer +766/clusterfuzz-testcase-4603047080624128 target_dec_vp6_fuzzer +767/clusterfuzz-testcase-6743603416137728 target_dec_vp6f_fuzzer +768/clusterfuzz-testcase-4807444305805312 target_dec_rv40_fuzzer +772/clusterfuzz-testcase-5453962780082176 target_dec_h264_fuzzer +773/clusterfuzz-testcase-6362160458366976 target_dec_vp6f_fuzzer +779/clusterfuzz-testcase-5568669545398272 target_dec_mpeg4_fuzzer +780/clusterfuzz-testcase-6393552642768896 target_dec_gif_fuzzer +807/clusterfuzz-testcase-6470061042696192 target_dec_vp6f_fuzzer +808/clusterfuzz-testcase-4715513349406720 target_dec_wavpack_fuzzer +809/clusterfuzz-testcase-6172687908995072 target_dec_vp6f_fuzzer +810/clusterfuzz-testcase-5249282825256960 target_dec_targa_fuzzer +811/clusterfuzz-testcase-6465493076541440 target_dec_mjpeg_fuzzer +822/clusterfuzz-testcase-4873433189974016 target_dec_wavpack_fuzzer +823/clusterfuzz-testcase-6727060074528768 target_dec_pictor_fuzzer +826/clusterfuzz-testcase-5316921379520512 target_dec_tiff_fuzzer +830/clusterfuzz-testcase-6253175327686656 target_dec_mp2_fuzzer +839/clusterfuzz-testcase-4871084446842880 target_dec_wavpack_fuzzer +842/clusterfuzz-testcase-6361547318231040 target_dec_tiff_fuzzer +847/clusterfuzz-testcase-5291877358108672 target_dec_vp5_fuzzer +848/clusterfuzz-testcase-5432155620507648 target_dec_vp6f_fuzzer +850/clusterfuzz-testcase-5721296509861888 target_dec_vp6f_fuzzer +857/clusterfuzz-testcase-5319093760557056 target_dec_h264_fuzzer +858/clusterfuzz-testcase-5168477042114560 target_dec_h264_fuzzer +861/clusterfuzz-testcase-5688284384591872 target_dec_tiff_fuzzer +864/clusterfuzz-testcase-4774385942528000 target_dec_h264_fuzzer +870/clusterfuzz-testcase-5649105424482304 target_dec_mjpeg_fuzzer +873/clusterfuzz-testcase-5714546230558720 target_dec_mp3_fuzzer +874/clusterfuzz-testcase-5252796175613952 target_dec_tiff_fuzzer +894/clusterfuzz-testcase-4841537823309824 target_dec_wavpack_fuzzer +898/clusterfuzz-testcase-6149765467209728 target_dec_pictor_fuzzer +902/clusterfuzz-testcase-4561155144024064 target_dec_h264_fuzzer +911/clusterfuzz-testcase-5415105606975488 target_dec_h264_fuzzer +936/clusterfuzz-testcase-4700061919346688 target_dec_tiff_fuzzer +938/clusterfuzz-testcase-4791735110598656 target_dec_amrnb_fuzzer +939/clusterfuzz-testcase-6515070404132864 target_dec_h264_fuzzer +940/clusterfuzz-testcase-5200378381467648 target_dec_wavpack_fuzzer +943/clusterfuzz-testcase-5114865297391616 target_dec_jpegls_fuzzer +943/clusterfuzz-testcase-5114865297391616 target_dec_mjpeg_fuzzer +945/clusterfuzz-testcase-6037937588273152 target_dec_wavpack_fuzzer +979/clusterfuzz-testcase-4940780542099456 target_dec_h264_fuzzer +1044/clusterfuzz-testcase-minimized-ffmpeg_AUDIO_AV_CODEC_ID_DTS_fuzzer-6135262067294208 target_dec_dca_fuzzer +1072/clusterfuzz-testcase-6456688074817536 target_dec_aac_fuzzer +1080/clusterfuzz-testcase-5353236754071552 target_dec_dvdsub_fuzzer +1085/clusterfuzz-testcase-6089649833377792 target_dec_tiff_fuzzer +1133/clusterfuzz-testcase-minimized-ffmpeg_VIDEO_AV_CODEC_ID_MJPEG_fuzzer-4861925596856320 target_dec_mjpeg_fuzzer +1136/clusterfuzz-testcase-6024209379622912 target_dec_sipr_fuzzer +1137/clusterfuzz-testcase-6711216560930816 target_dec_jpegls_fuzzer +1141/clusterfuzz-testcase-6659734767665152 target_dec_amrnb_fuzzer +1213/clusterfuzz-testcase-minimized-6022987469815808 target_dec_tiff_fuzzer +1214/clusterfuzz-testcase-minimized-6130606599569408 target_dec_h264_fuzzer +1271/clusterfuzz-testcase-minimized-6095220498235392 target_dec_targa_fuzzer +1275/clusterfuzz-testcase-minimized-6718162017976320 target_dec_mdec_fuzzer +1280/clusterfuzz-testcase-minimized-6102353767825408 target_dec_svq3_fuzzer +1282/clusterfuzz-testcase-minimized-5400131681648640 target_dec_bmp_fuzzer +1283/clusterfuzz-testcase-minimized-6221126759874560 target_dec_vp3_fuzzer +1290/clusterfuzz-testcase-minimized-5815578902134784 target_dec_indeo2_fuzzer +1292/clusterfuzz-testcase-minimized-5795512143839232 target_dec_flic_fuzzer +1293/clusterfuzz-testcase-minimized-6054752074858496 target_dec_smc_fuzzer +1298/clusterfuzz-testcase-minimized-5955580877340672 target_dec_mpeg4_fuzzer +1305/clusterfuzz-testcase-minimized-5787235003662336 target_dec_amv_fuzzer +1306/clusterfuzz-testcase-minimized-6152296217968640 target_dec_msvideo1_fuzzer +1309/clusterfuzz-testcase-minimized-5754803370065920 target_dec_pcx_fuzzer +1314/clusterfuzz-testcase-minimized-4621997222920192 target_dec_png_fuzzer +1321/clusterfuzz-testcase-minimized-5875549597597696 target_dec_cinepak_fuzzer +1322/clusterfuzz-testcase-minimized-4728193644756992 target_dec_png_fuzzer +1335/clusterfuzz-testcase-minimized-5566961566089216 target_dec_cavs_fuzzer +1336/clusterfuzz-testcase-minimized-4761381930795008 target_dec_pixlet_fuzzer +1337/clusterfuzz-testcase-minimized-5212314171080704 target_dec_aac_fuzzer +1338/clusterfuzz-testcase-minimized-6485546354343936 target_dec_wnv1_fuzzer +1339/clusterfuzz-testcase-minimized-4614671485108224 target_dec_dss_sp_fuzzer +1340/clusterfuzz-testcase-minimized-4669892148068352 target_dec_adpcm_g722_fuzzer +1341/clusterfuzz-testcase-minimized-5441502618583040 target_dec_cdxl_fuzzer +1342/clusterfuzz-testcase-minimized-5490842129137664 target_dec_nellymoser_fuzzer +1344/clusterfuzz-testcase-minimized-5567131804499968 target_dec_zmbv_fuzzer +1345/clusterfuzz-testcase-minimized-6062963045695488 target_dec_dfa_fuzzer +1346/clusterfuzz-testcase-minimized-5776732600664064 target_dec_mdec_fuzzer +1348/clusterfuzz-testcase-minimized-6195673642827776 target_dec_tiertexseqvideo_fuzzer +1349/clusterfuzz-testcase-minimized-5370707196248064 target_dec_aac_fuzzer +1351/clusterfuzz-testcase-minimized-5861971645693952 target_dec_indeo4_fuzzer +1352/clusterfuzz-testcase-minimized-5757565017260032 target_dec_ac3_fixed_fuzzer +1353/clusterfuzz-testcase-minimized-5208180449607680 target_dec_snow_fuzzer +1354/clusterfuzz-testcase-minimized-5520132195483648 target_dec_sami_fuzzer +1355/clusterfuzz-testcase-minimized-6662205472768000 target_dec_mlp_fuzzer +1356/clusterfuzz-testcase-minimized-6008489086287872 target_dec_fic_fuzzer +1360/clusterfuzz-testcase-minimized-5606472043986944 target_dec_clearvideo_fuzzer +1362/clusterfuzz-testcase-minimized-6097275002552320 target_dec_opus_fuzzer +1365/clusterfuzz-testcase-minimized-5624158450876416 target_dec_mimic_fuzzer +1366/clusterfuzz-testcase-minimized-5958052211589120 target_dec_ppm_fuzzer +1367/clusterfuzz-testcase-minimized-5714968823463936 target_dec_g723_1_fuzzer +1368/clusterfuzz-testcase-minimized-4507293276176384 target_dec_dfa_fuzzer +1369/clusterfuzz-testcase-minimized-5048908029886464 target_dec_webp_fuzzer +1371/clusterfuzz-testcase-minimized-5770822591447040 target_dec_shorten_fuzzer +1372/clusterfuzz-testcase-minimized-5712192982745088 target_dec_msa1_fuzzer +1374/clusterfuzz-testcase-minimized-5692496346611712 target_dec_mpeg1video_fuzzer +1375/clusterfuzz-testcase-minimized-6070134701555712 target_dec_hq_hqa_fuzzer +1376/clusterfuzz-testcase-minimized-6361794975105024 target_dec_targa_y216_fuzzer +1377/clusterfuzz-testcase-minimized-5487049807233024 target_dec_aac_fixed_fuzzer +1378/clusterfuzz-testcase-minimized-5715088008806400 target_dec_cdxl_fuzzer +1380/clusterfuzz-testcase-minimized-6501225451225088 target_dec_dds_fuzzer +1381/clusterfuzz-testcase-minimized-5513944540119040 target_dec_msmpeg4v1_fuzzer +1382/clusterfuzz-testcase-minimized-6013445293998080 target_dec_svq3_fuzzer +1385/clusterfuzz-testcase-minimized-5552882663292928 target_dec_indeo4_fuzzer +1386/clusterfuzz-testcase-minimized-5323086394032128 target_dec_txd_fuzzer +1387/clusterfuzz-testcase-minimized-4802757766676480 target_dec_mts2_fuzzer +1388/clusterfuzz-testcase-minimized-6680800936329216 target_dec_ra_144_fuzzer +1389/clusterfuzz-testcase-minimized-5330877464707072 target_dec_shorten_fuzzer +1390/clusterfuzz-testcase-minimized-5452757630713856 target_dec_magicyuv_fuzzer +1391/clusterfuzz-testcase-minimized-4556900198776832 target_dec_indeo4_fuzzer +1393/clusterfuzz-testcase-minimized-5948366791901184 target_dec_adpcm_g726_fuzzer +1394/clusterfuzz-testcase-minimized-6493376885030912 target_dec_eamad_fuzzer +1395/clusterfuzz-testcase-minimized-5330939741732864 target_dec_s302m_fuzzer +1397/clusterfuzz-testcase-minimized-6369226291937280 target_dec_hevc_fuzzer +1398/clusterfuzz-testcase-minimized-4576913622302720 target_dec_aac_fuzzer +1399/clusterfuzz-testcase-minimized-4866094172995584 target_dec_xwd_fuzzer +1401/clusterfuzz-testcase-minimized-6526248148795392 target_dec_wmv2_fuzzer +1402/clusterfuzz-testcase-minimized-6302213041291264 target_dec_h264_fuzzer +1403/clusterfuzz-testcase-minimized-4724820484816896 target_dec_ffv1_fuzzer +1404/clusterfuzz-testcase-minimized-5000441286885376 target_dec_cavs_fuzzer +1405/clusterfuzz-testcase-minimized-5011491835084800 target_dec_hqx_fuzzer +1406/clusterfuzz-testcase-minimized-5064865125236736 target_dec_vp7_fuzzer +1407/clusterfuzz-testcase-minimized-6044604124102656 target_dec_webp_fuzzer +1408/clusterfuzz-testcase-minimized-6529985844084736 target_dec_dvbsub_fuzzer +1409/clusterfuzz-testcase-minimized-5237365020819456 target_dec_dss_sp_fuzzer +1410/clusterfuzz-testcase-minimized-6065423843852288 target_dec_magicyuv_fuzzer +1411/clusterfuzz-testcase-minimized-5776085184675840 target_dec_bmv_video_fuzzer +1412/clusterfuzz-testcase-minimized-6561308772139008 target_dec_g723_1_fuzzer +1413/clusterfuzz-testcase-minimized-5923451770503168 target_dec_fic_fuzzer +1415/clusterfuzz-testcase-minimized-6417783363469312 target_dec_dvbsub_fuzzer +1416/clusterfuzz-testcase-minimized-5536862435278848 target_dec_indeo2_fuzzer +1417/clusterfuzz-testcase-minimized-6606778030620672 target_dec_clearvideo_fuzzer +1418/clusterfuzz-testcase-minimized-5934472438480896 target_dec_flac_fuzzer +1419/clusterfuzz-testcase-minimized-6108700873850880 target_dec_snow_fuzzer +1420/clusterfuzz-testcase-minimized-6059927359455232 target_dec_webp_fuzzer +1421/clusterfuzz-testcase-minimized-6239947507892224 target_dec_cllc_fuzzer +1422/clusterfuzz-testcase-minimized-5030993939398656 target_dec_scpr_fuzzer +1423/clusterfuzz-testcase-minimized-5063889899225088 target_dec_tak_fuzzer +1424/clusterfuzz-testcase-minimized-6088327159611392 target_dec_lagarith_fuzzer +1425/clusterfuzz-testcase-minimized-6295712339853312 target_dec_lagarith_fuzzer +1426/clusterfuzz-testcase-minimized-4774371304407040 target_dec_lagarith_fuzzer +1427/clusterfuzz-testcase-minimized-5020737339392000 target_dec_cdxl_fuzzer +1428/clusterfuzz-testcase-minimized-5263281793007616 target_dec_dds_fuzzer +1429/clusterfuzz-testcase-minimized-5959951610544128 target_dec_svq3_fuzzer +1434/clusterfuzz-testcase-minimized-6314998085189632 target_dec_webp_fuzzer +1435/clusterfuzz-testcase-minimized-6483783723253760 target_dec_webp_fuzzer +1437/clusterfuzz-testcase-minimized-4569970002362368 target_dec_y41p_fuzzer +1438/clusterfuzz-testcase-minimized-4917542646710272 target_dec_cavs_fuzzer +1439/clusterfuzz-testcase-minimized-4999148417843200 target_dec_g723_1_fuzzer +1440/clusterfuzz-testcase-minimized-5785716111966208 target_dec_vp7_fuzzer +1441/clusterfuzz-testcase-minimized-6223152357048320 target_dec_dss_sp_fuzzer +1443/clusterfuzz-testcase-minimized-4826998612426752 target_dec_eatqi_fuzzer +1446/clusterfuzz-testcase-minimized-5577409124368384 target_dec_truemotion1_fuzzer +1453/clusterfuzz-testcase-minimized-5024976874766336 target_dec_wavpack_fuzzer +1462/clusterfuzz-testcase-minimized-6558894463647744 target_dec_pixlet_fuzzer +1464/clusterfuzz-testcase-minimized-4925445571084288 target_dec_mpeg2video_fuzzer +1466/clusterfuzz-testcase-minimized-5961584419536896 target_dec_xpm_fuzzer +1468/clusterfuzz-testcase-minimized-5235964056174592 target_dec_mimic_fuzzer +1470/clusterfuzz-testcase-minimized-5404421666111488 target_dec_webp_fuzzer +1471/clusterfuzz-testcase-minimized-6376460543590400 target_dec_aac_fixed_fuzzer +1472/clusterfuzz-testcase-minimized-5677426430443520 target_dec_webp_fuzzer +1473/clusterfuzz-testcase-minimized-5768907824562176 target_dec_dvbsub_fuzzer +1478/clusterfuzz-testcase-minimized-5285486908145664 target_dec_scpr_fuzzer +1479/clusterfuzz-testcase-minimized-6638493360979968 target_dec_cllc_fuzzer +1480/clusterfuzz-testcase-minimized-5188321007370240 target_dec_msmpeg4v2_fuzzer +1481/clusterfuzz-testcase-minimized-5264379509473280 target_dec_shorten_fuzzer +1483/clusterfuzz-testcase-minimized-6386507814273024 target_dec_msa1_fuzzer +1485/clusterfuzz-testcase-minimized-6639880215986176 target_dec_msa1_fuzzer +1487/clusterfuzz-testcase-minimized-6288036495097856 target_dec_dirac_fuzzer +1489/clusterfuzz-testcase-minimized-5075102901207040 target_dec_aac_fuzzer +1503/clusterfuzz-testcase-minimized-5369271855087616 target_dec_wmv2_fuzzer +1504/clusterfuzz-testcase-minimized-6249212138225664 target_dec_g723_1_fuzzer +1505/clusterfuzz-testcase-minimized-4561688818876416 target_dec_dds_fuzzer +1506/clusterfuzz-testcase-minimized-5401272918212608 target_dec_cavs_fuzzer +1507/clusterfuzz-testcase-minimized-4955228300378112 target_dec_hq_hqa_fuzzer +1508/clusterfuzz-testcase-minimized-5011336327069696 target_dec_fmvc_fuzzer +1509/clusterfuzz-testcase-minimized-5129419876204544 target_dec_rscc_fuzzer +1510/clusterfuzz-testcase-minimized-5826231746428928 target_dec_dds_fuzzer +1511/clusterfuzz-testcase-minimized-5906663800307712 target_dec_ffv1_fuzzer +1512/clusterfuzz-testcase-minimized-4713846423945216 target_dec_mlp_fuzzer +1513/clusterfuzz-testcase-minimized-6246484833992704 target_dec_h264_fuzzer +1514/clusterfuzz-testcase-minimized-6437666243477504 target_dec_indeo4_fuzzer +1519/clusterfuzz-testcase-minimized-5286680976162816 target_dec_scpr_fuzzer +1535/clusterfuzz-testcase-minimized-5826695535788032 target_dec_aac_fixed_fuzzer +1536/clusterfuzz-testcase-minimized-5973925404082176 target_dec_webp_fuzzer +1538/clusterfuzz-testcase-minimized-4696904925446144 target_dec_ac3_fuzzer +1541/clusterfuzz-testcase-minimized-6403410590957568 target_dec_mlp_fuzzer +1556/clusterfuzz-testcase-minimized-5027865978470400 target_dec_svq3_fuzzer +1557/clusterfuzz-testcase-minimized-6535013757616128 target_dec_webp_fuzzer +1559/clusterfuzz-testcase-minimized-5048096079740928 target_dec_ffv1_fuzzer +1560/clusterfuzz-testcase-minimized-6011037813833728 target_dec_ffv1_fuzzer +1567/clusterfuzz-testcase-minimized-5693653555085312 target_dec_g723_1_fuzzer +1568/clusterfuzz-testcase-minimized-5944868608147456 target_dec_hqx_fuzzer +1569/clusterfuzz-testcase-minimized-6328690508038144 target_dec_pixlet_fuzzer +1570/clusterfuzz-testcase-minimized-6455337349545984 target_dec_ac3_fuzzer +1572/clusterfuzz-testcase-minimized-4578773729017856 target_dec_mpeg4_fuzzer +1576/clusterfuzz-testcase-minimized-5592896440893440 target_dec_tiff_fuzzer +1604/clusterfuzz-testcase-minimized-5312060206350336 target_dec_svq3_fuzzer +1609/clusterfuzz-testcase-minimized-5102163007111168 target_dec_g723_1_fuzzer +1615/clusterfuzz-testcase-minimized-6625214647500800 target_dec_scpr_fuzzer +1616/clusterfuzz-testcase-minimized-5119196578971648 target_dec_truemotion1_fuzzer +1626/clusterfuzz-testcase-minimized-6416580571299840 target_dec_hq_hqa_fuzzer +1630/clusterfuzz-testcase-minimized-6326111917047808 target_dec_tak_fuzzer +1631/clusterfuzz-testcase-minimized-4861568200212480 target_dec_tiff_fuzzer +1635/clusterfuzz-testcase-minimized-4992749856096256 target_dec_tak_fuzzer +1636/clusterfuzz-testcase-minimized-5310494757879808 target_dec_mlp_fuzzer +1637/clusterfuzz-testcase-minimized-5376582493405184 target_dec_flic_fuzzer +1639/clusterfuzz-testcase-minimized-5693801463021568 target_dec_h264_fuzzer +1643/clusterfuzz-testcase-minimized-6117573403869184 target_dec_fmvc_fuzzer +1654/clusterfuzz-testcase-minimized-5151903795118080 target_dec_aac_fixed_fuzzer +1655/clusterfuzz-testcase-minimized-5587079276789760 target_dec_rv40_fuzzer +1656/clusterfuzz-testcase-minimized-5900404925661184 target_dec_aac_latm_fuzzer +1657/clusterfuzz-testcase-minimized-4710000079405056 target_dec_dfa_fuzzer +1658/clusterfuzz-testcase-minimized-4889937130291200 target_dec_mlp_fuzzer +1659/clusterfuzz-testcase-minimized-5396490639900672 target_dec_wavpack_fuzzer +1664/clusterfuzz-testcase-minimized-6587801187385344 target_dec_pixlet_fuzzer +1669/clusterfuzz-testcase-minimized-5287529198649344 target_dec_fic_fuzzer +1671/clusterfuzz-testcase-minimized-4759078033162240 target_dec_mimic_fuzzer +1674/clusterfuzz-testcase-minimized-6092531563495424 target_dec_aac_fixed_fuzzer +1681/clusterfuzz-testcase-minimized-5970545365483520 target_dec_aac_fixed_fuzzer +1686/clusterfuzz-testcase-minimized-6282691643179008 target_dec_aac_fixed_fuzzer +1699/clusterfuzz-testcase-minimized-6327177438035968 target_dec_mlp_fuzzer +1702/clusterfuzz-testcase-minimized-5777869676478464 target_dec_ffv1_fuzzer +1706/clusterfuzz-testcase-minimized-6112772670619648 target_dec_tak_fuzzer +1707/clusterfuzz-testcase-minimized-6502767008940032 target_dec_escape124_fuzzer +1708/clusterfuzz-testcase-minimized-5035111957397504 target_dec_mlp_fuzzer +1709/clusterfuzz-testcase-minimized-4513580554649600 target_dec_aac_fixed_fuzzer +1710/clusterfuzz-testcase-minimized-4837032931098624 target_dec_vp9_fuzzer +1711/clusterfuzz-testcase-minimized-5248503515185152 target_dec_mlp_fuzzer +1713/clusterfuzz-testcase-minimized-5791887476654080 target_dec_tak_fuzzer +1716/clusterfuzz-testcase-minimized-4691012196761600 target_dec_aac_fixed_fuzzer +1717/clusterfuzz-testcase-minimized-5491696676634624 target_dec_vmnc_fuzzer +1719/clusterfuzz-testcase-minimized-6375090079924224 target_dec_tscc2_fuzzer +1720/clusterfuzz-testcase-minimized-4952373438971904 target_dec_mlp_fuzzer +1721/clusterfuzz-testcase-minimized-4719352135811072 target_dec_aac_fixed_fuzzer +1723/clusterfuzz-testcase-minimized-5309409372667904 target_dec_mpeg4_fuzzer +1724/clusterfuzz-testcase-minimized-4842395432648704 target_dec_thp_fuzzer +1725/clusterfuzz-testcase-minimized-5132425044688896 target_dec_cavs_fuzzer +1726/clusterfuzz-testcase-minimized-4509005575618560 target_dec_aac_fixed_fuzzer +1727/clusterfuzz-testcase-minimized-5900685306494976 target_dec_mpeg4_fuzzer +1731/clusterfuzz-testcase-minimized-5123972414832640 target_dec_mp3adu_fuzzer +1734/clusterfuzz-testcase-minimized-5385630815092736 target_dec_indeo5_fuzzer +1735/clusterfuzz-testcase-minimized-5350472347025408 target_dec_aac_fixed_fuzzer +1737/clusterfuzz-testcase-minimized-5922321338466304 target_dec_mpeg4_fuzzer +1738/clusterfuzz-testcase-minimized-6734814327603200 target_dec_aac_fixed_fuzzer +1739/clusterfuzz-testcase-minimized-5399237707694080 target_dec_tak_fuzzer +1743/clusterfuzz-testcase-minimized-4994834022531072 target_dec_tak_fuzzer +1745/clusterfuzz-testcase-minimized-6160693365571584 target_dec_paf_video_fuzzer +1746/clusterfuzz-testcase-minimized-6687393392361472 target_dec_asv2_fuzzer +1747/clusterfuzz-testcase-minimized-6035451213250560 target_dec_xsub_fuzzer +1748/clusterfuzz-testcase-minimized-6690208340770816 target_dec_ffv1_fuzzer +1753/clusterfuzz-testcase-minimized-6205127620820992 target_dec_pbm_fuzzer +1758/clusterfuzz-testcase-minimized-6054857184116736 target_dec_g723_1_fuzzer +1762/clusterfuzz-testcase-minimized-5150981081792512 target_dec_aac_fixed_fuzzer +1763/clusterfuzz-testcase-minimized-5191733576990720 target_dec_pam_fuzzer +1764/clusterfuzz-testcase-minimized-5394243164045312 target_dec_lagarith_fuzzer +1766/clusterfuzz-testcase-minimized-6562020075765760 target_dec_g723_1_fuzzer +1767/clusterfuzz-testcase-minimized-6657181250224128 target_dec_pgm_fuzzer +1770/clusterfuzz-testcase-minimized-5285511235108864 target_dec_aac_fixed_fuzzer +1773/clusterfuzz-testcase-minimized-4832523987189760 target_dec_mjpeg_fuzzer +1775/clusterfuzz-testcase-minimized-5330288148217856 target_dec_aac_fixed_fuzzer +1776/clusterfuzz-testcase-minimized-6191258231898112 target_dec_wavpack_fuzzer +1778/clusterfuzz-testcase-minimized-5128953268273152 target_dec_wavpack_fuzzer +1781/clusterfuzz-testcase-minimized-4617176877105152 target_dec_dirac_fuzzer +1785/clusterfuzz-testcase-minimized-6035918794260480 target_dec_ppm_fuzzer +1802/clusterfuzz-testcase-minimized-5008293510512640 target_dec_cllc_fuzzer +1807/clusterfuzz-testcase-minimized-6258676199325696 target_dec_wavpack_fuzzer +1815/clusterfuzz-testcase-minimized-5237739320508416 target_dec_jpeg2000_fuzzer +1817/clusterfuzz-testcase-minimized-5104230530547712 target_dec_subrip_fuzzer +1818/clusterfuzz-testcase-minimized-5039166473633792 target_dec_smc_fuzzer +1821/clusterfuzz-testcase-minimized-6050283782144000 target_dec_vp3_fuzzer +1825/clusterfuzz-testcase-minimized-6002833050566656 target_dec_aac_fixed_fuzzer +1826/clusterfuzz-testcase-minimized-5728569256837120 target_dec_clearvideo_fuzzer +1829/clusterfuzz-testcase-minimized-5527165321871360 target_dec_pixlet_fuzzer +1830/clusterfuzz-testcase-minimized-5828293733384192 target_dec_ra_144_fuzzer +1832/clusterfuzz-testcase-minimized-6574546079449088 target_dec_mlp_fuzzer +1839/clusterfuzz-testcase-minimized-6238490993885184 target_dec_indeo4_fuzzer +1841/clusterfuzz-testcase-minimized-5858969564217344 target_dec_aac_fixed_fuzzer +1845/clusterfuzz-testcase-minimized-5075974343360512 target_dec_wnv1_fuzzer +1851/clusterfuzz-testcase-minimized-5692607495667712 target_dec_aac_fixed_fuzzer +1853/clusterfuzz-testcase-minimized-5471155626442752 target_dec_wavpack_fuzzer +1858/clusterfuzz-testcase-minimized-6450473802399744 target_dec_sheervideo_fuzzer +1870/clusterfuzz-testcase-minimized-4686788029317120 target_dec_jpeg2000_fuzzer +1871/clusterfuzz-testcase-minimized-5719950331215872 target_dec_snow_fuzzer +1874/clusterfuzz-testcase-minimized-5037763613163520 target_dec_ylc_fuzzer +1875/clusterfuzz-testcase-minimized-5536474562822144 target_dec_webp_fuzzer +1878/clusterfuzz-testcase-minimized-6441918630199296 target_dec_aac_fixed_fuzzer +1880/clusterfuzz-testcase-minimized-4900645322620928 target_dec_aac_fixed_fuzzer +1882/clusterfuzz-testcase-minimized-5539735650959360 target_dec_aac_fuzzer +1884/clusterfuzz-testcase-minimized-4637425835966464 target_dec_ra_144_fuzzer +1885/clusterfuzz-testcase-minimized-5336328549957632 target_dec_ra_144_fuzzer +1888/clusterfuzz-testcase-minimized-5237704826552320 target_dec_truemotion2_fuzzer +1890/clusterfuzz-testcase-minimized-6329019509243904 target_dec_jpeg2000_fuzzer +1891/clusterfuzz-testcase-minimized-6274417925554176 target_dec_dds_fuzzer +1892/clusterfuzz-testcase-minimized-4519341733183488 target_dec_ansi_fuzzer +1894/clusterfuzz-testcase-minimized-4716739789062144 target_dec_wavpack_fuzzer +1898/clusterfuzz-testcase-minimized-5970744880136192 target_dec_wavpack_fuzzer +1902/clusterfuzz-testcase-minimized-4762451407011840 target_dec_amrwb_fuzzer +1903/clusterfuzz-testcase-minimized-5359318167715840 target_dec_cavs_fuzzer +1906/clusterfuzz-testcase-minimized-4599315114754048 target_dec_pgmyuv_fuzzer +1908/clusterfuzz-testcase-minimized-5392712477966336 target_dec_ra_144_fuzzer +1909/clusterfuzz-testcase-minimized-6732072662073344 target_dec_hevc_fuzzer +1917/clusterfuzz-testcase-minimized-5023221273329664 target_dec_cinepak_fuzzer +1922/clusterfuzz-testcase-minimized-5561194112876544 target_dec_wavpack_fuzzer +1925/clusterfuzz-testcase-minimized-5564569688735744 target_dec_cfhd_fuzzer +1934/clusterfuzz-testcase-minimized-4659523174268928 target_dec_mp1_fuzzer +1935/clusterfuzz-testcase-minimized-4939127826939904 target_dec_mp2float_fuzzer +1938/clusterfuzz-testcase-minimized-6595305602547712 target_dec_mp3float_fuzzer +1939/clusterfuzz-testcase-minimized-5544941956628480 target_dec_vp9_fuzzer +1941/clusterfuzz-testcase-minimized-4719816059387904 target_dec_h264_fuzzer +1942/clusterfuzz-testcase-minimized-4870171724349440 target_dec_h264_fuzzer +1943/clusterfuzz-testcase-minimized-4912348974284800 target_dec_vp9_fuzzer +1944/clusterfuzz-testcase-minimized-4957953339686912 target_dec_aac_fixed_fuzzer +1946/clusterfuzz-testcase-minimized-5780475010351104 target_dec_vp9_fuzzer +1947/clusterfuzz-testcase-minimized-6266250911023104 target_dec_vp9_fuzzer +1948/clusterfuzz-testcase-minimized-6601933810827264 target_dec_rv40_fuzzer +1949/clusterfuzz-testcase-minimized-6645980176842752 target_dec_svq3_fuzzer +1967/clusterfuzz-testcase-minimized-5757031199801344 target_dec_wavpack_fuzzer +2001/clusterfuzz-testcase-minimized-6187599389523968 target_dec_asv2_fuzzer +2004/clusterfuzz-testcase-minimized-5533262866808832 target_dec_snow_fuzzer +2005/clusterfuzz-testcase-minimized-5744226438479872 target_dec_aac_fixed_fuzzer +2006/clusterfuzz-testcase-minimized-5766515037044736 target_dec_dxv_fuzzer +2010/clusterfuzz-testcase-minimized-6209288450080768 target_dec_hevc_fuzzer +2014/clusterfuzz-testcase-minimized-5186337030275072 target_dec_aac_fixed_fuzzer +2038/clusterfuzz-testcase-minimized-4521466148159488 target_dec_wavpack_fuzzer +2045/clusterfuzz-testcase-minimized-6751255865065472 target_dec_aac_fixed_fuzzer +2065/clusterfuzz-testcase-minimized-6298930457346048 target_dec_qdraw_fuzzer +2067/clusterfuzz-testcase-minimized-5578430902960128 target_dec_cavs_fuzzer +2071/clusterfuzz-testcase-minimized-6036414271586304 target_dec_aac_fixed_fuzzer +2076/clusterfuzz-testcase-minimized-6542640243802112 target_dec_tiff_fuzzer +2079/clusterfuzz-testcase-minimized-5345861779324928 target_dec_tak_fuzzer +2096/clusterfuzz-testcase-minimized-4901566068817920 target_dec_aac_fixed_fuzzer +2097/clusterfuzz-testcase-minimized-5036861833609216 target_dec_mxpeg_fuzzer +2100/clusterfuzz-testcase-minimized-4522961547558912 target_dec_paf_video_fuzzer +2106/clusterfuzz-testcase-minimized-6136503639998464 target_dec_mpeg4_fuzzer +2113/clusterfuzz-testcase-minimized-6510704959946752 target_dec_ac3_fixed_fuzzer +2115/clusterfuzz-testcase-minimized-6594111748440064 target_dec_indeo4_fuzzer +2127/clusterfuzz-testcase-minimized-6595787859427328 target_dec_subrip_fuzzer +2131/clusterfuzz-testcase-minimized-4718045157130240 target_dec_shorten_fuzzer +2134/clusterfuzz-testcase-minimized-4619258405322752 target_dec_wavpack_fuzzer +2143/clusterfuzz-testcase-minimized-5482288060039168 target_dec_dvbsub_fuzzer +2145/clusterfuzz-testcase-minimized-5866217724182528 target_dec_h264_fuzzer +2154/clusterfuzz-testcase-minimized-4879971375906816 target_dec_hevc_fuzzer +2159/clusterfuzz-testcase-minimized-5267945972301824 target_dec_h264_fuzzer +2164/clusterfuzz-testcase-minimized-4715936172998656 target_dec_aac_fixed_fuzzer +2169/clusterfuzz-testcase-minimized-5688641642823680 target_dec_cfhd_fuzzer +2174/clusterfuzz-testcase-minimized-5739234533048320 target_dec_flic_fuzzer +2175/clusterfuzz-testcase-minimized-5809657849315328 target_dec_ra_144_fuzzer +2176/clusterfuzz-testcase-minimized-5908197216878592 target_dec_tiff_fuzzer +2181/clusterfuzz-testcase-minimized-6314784322486272 target_dec_wavpack_fuzzer +2192/clusterfuzz-testcase-minimized-5370387988742144 target_dec_mpeg4_fuzzer +2195/clusterfuzz-testcase-minimized-4736721533009920 target_dec_aac_fixed_fuzzer +2197/clusterfuzz-testcase-minimized-6010716676947968 target_dec_snow_fuzzer +2204/clusterfuzz-testcase-minimized-5616756909408256 target_dec_mpeg4_fuzzer +2208/clusterfuzz-testcase-minimized-5976593765761024 target_dec_jpeg2000_fuzzer +2209/clusterfuzz-testcase-minimized-5012343912136704 target_dec_hevc_fuzzer +2224/clusterfuzz-testcase-minimized-6208559949807616 target_dec_aac_fixed_fuzzer +2225/clusterfuzz-testcase-minimized-5505632079708160 target_dec_jpeg2000_fuzzer +2231/clusterfuzz-testcase-minimized-4565181982048256 target_dec_jpeg2000_fuzzer +2233/clusterfuzz-testcase-minimized-5943031318446080 target_dec_truemotion2_fuzzer +2234/clusterfuzz-testcase-minimized-6266896041115648 target_dec_tak_fuzzer +2239/clusterfuzz-testcase-minimized-5639766592716800 target_dec_jpeg2000_fuzzer +2243/clusterfuzz-testcase-minimized-4683988125876224 target_dec_vp9_fuzzer +2247/clusterfuzz-testcase-minimized-5165385038954496 target_dec_vp9_fuzzer +2249/clusterfuzz-testcase-minimized-5388542379294720 target_dec_gdv_fuzzer +2250/clusterfuzz-testcase-minimized-5693382112313344 target_dec_hevc_fuzzer +2254/clusterfuzz-testcase-minimized-4735977664806912 target_dec_vp9_fuzzer +2255/clusterfuzz-testcase-minimized-4917394667470848 target_dec_vp9_fuzzer +2257/clusterfuzz-testcase-minimized-5622708022804480 target_dec_vp9_fuzzer +2258/clusterfuzz-testcase-minimized-5924773878038528 target_dec_vp9_fuzzer +2263/clusterfuzz-testcase-minimized-4800359627227136 target_dec_hevc_fuzzer +2271/clusterfuzz-testcase-minimized-5778297776504832 target_dec_jpeg2000_fuzzer +2272/clusterfuzz-testcase-minimized-5059103858622464 target_dec_iff_ilbm_fuzzer +2286/clusterfuzz-testcase-minimized-5711764169687040 target_dec_aac_fixed_fuzzer +2291/clusterfuzz-testcase-minimized-5538453481586688 target_dec_wavpack_fuzzer +2292/clusterfuzz-testcase-minimized-6156080415506432 target_dec_mpeg4_fuzzer +2299/clusterfuzz-testcase-minimized-4843509351710720 target_dec_hevc_fuzzer +2303/clusterfuzz-testcase-minimized-5529675273076736 target_dec_cfhd_fuzzer +2306/clusterfuzz-testcase-minimized-5002997392211968 target_dec_cfhd_fuzzer +2310/clusterfuzz-testcase-minimized-4534784887881728 target_dec_tiff_fuzzer +2314/clusterfuzz-testcase-minimized-4519333877252096 target_dec_tak_fuzzer +2331/clusterfuzz-testcase-minimized-6182185830711296 target_dec_wavpack_fuzzer +2333/clusterfuzz-testcase-minimized-5223935677300736 target_dec_hevc_fuzzer +2338/clusterfuzz-testcase-minimized-5153426541379584 target_dec_mpeg4_fuzzer +2339/clusterfuzz-testcase-minimized-6663164320022528 target_dec_hevc_fuzzer +2351/clusterfuzz-testcase-minimized-5359403240783872 target_dec_wavpack_fuzzer +2365/clusterfuzz-testcase-minimized-6020421927305216 target_dec_jpeg2000_fuzzer +2367/clusterfuzz-testcase-minimized-4648678897745920 target_dec_jpeg2000_fuzzer +2377/clusterfuzz-testcase-minimized-6108505935183872 target_dec_wavpack_fuzzer +2385/clusterfuzz-testcase-minimized-6594333576790016 target_dec_hevc_fuzzer +2393/clusterfuzz-testcase-minimized-6128334993883136 target_dec_vb_fuzzer +2395/clusterfuzz-testcase-minimized-6540529313513472 target_dec_cfhd_fuzzer +2406/clusterfuzz-testcase-minimized-5294603055923200 target_dec_interplay_video_fuzzer +2407/clusterfuzz-testcase-minimized-5858436027777024 target_dec_interplay_video_fuzzer +2408/clusterfuzz-testcase-minimized-5432734438653952 target_dec_interplay_video_fuzzer +2415/clusterfuzz-testcase-minimized-4672827619803136 target_dec_interplay_video_fuzzer +2422/clusterfuzz-testcase-minimized-5242114713583616 target_dec_hevc_fuzzer +2442/clusterfuzz-testcase-minimized-4985479546011648 target_dec_interplay_video_fuzzer +2451/clusterfuzz-testcase-minimized-4781613957251072 target_dec_hevc_fuzzer +2456/clusterfuzz-testcase-minimized-4822695051001856 target_dec_h264_fuzzer +2467/clusterfuzz-testcase-minimized-4755798049685504 target_dec_interplay_video_fuzzer +2478/clusterfuzz-testcase-minimized-4649584649306112 target_dec_aac_fuzzer +2515/clusterfuzz-testcase-minimized-6197200012967936 target_dec_ylc_fuzzer +2527/clusterfuzz-testcase-minimized-5260915396050944 target_dec_aac_fixed_fuzzer +2533/clusterfuzz-testcase-minimized-5372857678823424 target_dec_thp_fuzzer +2550/clusterfuzz-testcase-minimized-6275019871092736 target_dec_aac_fixed_fuzzer +2568/clusterfuzz-testcase-minimized-4926115716005888 target_dec_magicyuv_fuzzer +2576/clusterfuzz-testcase-minimized-6002596705730560 target_dec_hevc_fuzzer +2577/clusterfuzz-testcase-minimized-4802472348483584 target_dec_shorten_fuzzer +2578/clusterfuzz-testcase-minimized-5098313588146176 target_dec_h264_fuzzer +2581/clusterfuzz-testcase-minimized-4681474395602944 target_dec_aac_fixed_fuzzer +2614/clusterfuzz-testcase-minimized-5949228129976320 target_dec_dirac_fuzzer +2634/clusterfuzz-testcase-minimized-4540890636877824 target_dec_ffv1_fuzzer +2674/clusterfuzz-testcase-minimized-4999700518273024 target_dec_dirac_fuzzer +2678/clusterfuzz-testcase-minimized-4702787684270080 target_dec_aac_fixed_fuzzer +2698/clusterfuzz-testcase-minimized-4713541443518464 target_dec_ylc_fuzzer +2699/clusterfuzz-testcase-minimized-5631303862976512 target_dec_aac_fixed_fuzzer +2702/clusterfuzz-testcase-minimized-4511932591636480 target_dec_hevc_fuzzer +2707/clusterfuzz-testcase-minimized-5179636394754048 target_dec_jpeg2000_fuzzer +2708/clusterfuzz-testcase-minimized-5510405650644992 target_dec_pixlet_fuzzer +2710/clusterfuzz-testcase-minimized-4750001420894208 target_dec_zmbv_fuzzer +2711/clusterfuzz-testcase-minimized-4975142398590976 target_dec_tak_fuzzer +2715/clusterfuzz-testcase-minimized-5099055292088320 target_dec_jpeg2000_fuzzer +2729/clusterfuzz-testcase-minimized-5902915464069120 target_dec_dirac_fuzzer +2737/clusterfuzz-testcase-minimized-4968639147016192 target_dec_dirac_fuzzer +2739/clusterfuzz-testcase-minimized-6737297955356672 target_dec_dirac_fuzzer +2742/clusterfuzz-testcase-minimized-5724322402402304 target_dec_dirac_fuzzer +2743/clusterfuzz-testcase-minimized-5820652076400640 target_dec_snow_fuzzer +2744/clusterfuzz-testcase-minimized-4672435653705728 target_dec_dirac_fuzzer +2747/clusterfuzz-testcase-minimized-5108132302815232 target_dec_dirac_fuzzer +2749/clusterfuzz-testcase-minimized-5298741273690112 target_dec_dirac_fuzzer +2764/clusterfuzz-testcase-minimized-5382561922547712 target_dec_dirac_fuzzer +2809/clusterfuzz-testcase-minimized-4785181833560064 target_dec_h264_fuzzer +2815/clusterfuzz-testcase-minimized-6062914471460864 target_dec_hevc_fuzzer +2817/clusterfuzz-testcase-minimized-5289691240726528 target_dec_h264_fuzzer +2818/clusterfuzz-testcase-minimized-5062943676825600 target_dec_aac_fixed_fuzzer +2819/clusterfuzz-testcase-minimized-4743700301217792 target_dec_dirac_fuzzer +2826/clusterfuzz-testcase-minimized-5901511613743104 target_dec_mpeg4_fuzzer +2834/clusterfuzz-testcase-minimized-5988039123795968 target_dec_ffv1_fuzzer +2838/clusterfuzz-testcase-minimized-6260066086813696 target_dec_dirac_fuzzer +2841/clusterfuzz-testcase-minimized-4869071805874176 target_dec_dirac_fuzzer +2844/clusterfuzz-testcase-minimized-5561715838156800 target_dec_dirac_fuzzer +2860/clusterfuzz-testcase-minimized-4672811689836544 target_dec_dirac_fuzzer +2861/clusterfuzz-testcase-minimized-5361070510178304 target_dec_dirac_fuzzer +2866/clusterfuzz-testcase-minimized-4581973265743872 target_dec_hevc_fuzzer +2873/clusterfuzz-testcase-minimized-5924145713905664 target_dec_aac_latm_fuzzer +2879/clusterfuzz-testcase-minimized-6317542639403008 target_dec_pixlet_fuzzer +2891/clusterfuzz-testcase-minimized-5881795457318912 target_dec_h264_fuzzer +2893/clusterfuzz-testcase-minimized-5809330567774208 target_dec_hevc_fuzzer +#2914/clusterfuzz-testcase-minimized-4787845073993728 target_dec_mpeg4_fuzzer +#2919/clusterfuzz-testcase-minimized-4828609145470976 target_dec_dnxhd_fuzzer +#2925/clusterfuzz-testcase-minimized-4971717589991424 target_dec_dca_fuzzer +#2926/clusterfuzz-testcase-minimized-4987110014582784 target_dec_gdv_fuzzer +#2928/clusterfuzz-testcase-minimized-4992812120539136 target_dec_shorten_fuzzer +#2931/clusterfuzz-testcase-minimized-5051106906341376 target_dec_aac_latm_fuzzer +#2933/clusterfuzz-testcase-minimized-5124990208835584 target_dec_lagarith_fuzzer +#2943/clusterfuzz-testcase-minimized-5430257156882432 target_dec_cavs_fuzzer +#2953/clusterfuzz-testcase-minimized-5604124211019776 target_dec_thp_fuzzer +#2962/clusterfuzz-testcase-minimized-5812616687517696 target_dec_mjpeg_fuzzer +#2971/clusterfuzz-testcase-minimized-6130678276030464 target_dec_ffv1_fuzzer +#2973/clusterfuzz-testcase-minimized-6244323446226944 target_dec_vp9_fuzzer +#2992/clusterfuzz-testcase-minimized-6649611793989632 target_dec_comfortnoise_fuzzer +3013/clusterfuzz-testcase-minimized-4644084197097472 target_dec_dirac_fuzzer +3023/clusterfuzz-testcase-minimized-6421736130084864 target_dec_snow_fuzzer +3024/clusterfuzz-testcase-minimized-5885660323905536 target_dec_fic_fuzzer +3030/clusterfuzz-testcase-minimized-4649809254285312 target_dec_pixlet_fuzzer +3042/clusterfuzz-testcase-minimized-5174210131394560 target_dec_jpeg2000_fuzzer +3051/clusterfuzz-testcase-minimized-5745818336231424 target_dec_dvbsub_fuzzer +3053/clusterfuzz-testcase-minimized-6355082062856192 target_dec_dirac_fuzzer +#3073/clusterfuzz-testcase-minimized-6717666356101120 target_dec_jpegls_fuzzer +3077/clusterfuzz-testcase-minimized-4684917524922368 target_dec_hevc_fuzzer +3081/clusterfuzz-testcase-minimized-4807564879462400 target_dec_dirac_fuzzer +3091/clusterfuzz-testcase-minimized-6229767969832960 target_dec_hevc_fuzzer +3124/clusterfuzz-testcase-minimized-4546434357526528 target_dec_dirac_fuzzer +#3142/clusterfuzz-testcase-minimized-5007853163118592 target_dec_snow_fuzzer +#3147/clusterfuzz-testcase-minimized-4870592182353920 target_dec_clearvideo_fuzzer +3175/clusterfuzz-testcase-minimized-4736774054084608 target_dec_hevc_fuzzer +3191/clusterfuzz-testcase-minimized-5688798451073024 target_dec_aac_fixed_fuzzer +3196/clusterfuzz-testcase-minimized-4528307146063872 target_dec_tak_fuzzer +#3200/clusterfuzz-testcase-minimized-5750022136135680 target_dec_wmv2_fuzzer +3202/clusterfuzz-testcase-minimized-4988291642294272 target_dec_tak_fuzzer +3203/clusterfuzz-testcase-minimized-4514553595428864 target_dec_png_fuzzer +#3218/clusterfuzz-testcase-minimized-5390672154591232 target_dec_dvbsub_fuzzer +#3242/clusterfuzz-testcase-minimized-5811951672229888 target_dec_scpr_fuzzer +3279/clusterfuzz-testcase-minimized-4564805744590848 target_dec_dirac_fuzzer +#3291/clusterfuzz-testcase-minimized-4630024655208448 target_dec_dxv_fuzzer +3295/clusterfuzz-testcase-minimized-4738998142500864 target_dec_dirac_fuzzer +3336/clusterfuzz-testcase-minimized-5656839179993088 target_dec_truemotion2_fuzzer +3348/clusterfuzz-testcase-minimized-4809500517203968 target_dec_svq3_fuzzer +3361/clusterfuzz-testcase-minimized-5065842955911168 target_dec_ffv1_fuzzer +3373/clusterfuzz-testcase-minimized-5604083912146944 target_dec_hevc_fuzzer +3410/clusterfuzz-testcase-minimized-5313377960198144 target_dec_prores_fuzzer +3416/clusterfuzz-testcase-minimized-6125587682820096 target_dec_h264_fuzzer +3443/clusterfuzz-testcase-minimized-5369987105554432 target_dec_aac_fixed_fuzzer +3444/clusterfuzz-testcase-minimized-6270352105668608 target_dec_aac_latm_fuzzer +3453/clusterfuzz-testcase-minimized-5555554657239040 target_dec_mpeg4_fuzzer +3463/clusterfuzz-testcase-minimized-5557381989662720 target_dec_tiff_fuzzer +3482/clusterfuzz-testcase-minimized-5446915875405824 target_dec_prores_fuzzer +3485/clusterfuzz-testcase-minimized-4940429332054016 target_dec_dirac_fuzzer +3492/clusterfuzz-testcase-minimized-5784775283441664 target_dec_aac_fixed_fuzzer +3512/clusterfuzz-testcase-minimized-4812747210489856 target_dec_snow_fuzzer +3516/clusterfuzz-testcase-minimized-4608518562775040 target_dec_mpeg4_fuzzer +3528/clusterfuzz-testcase-minimized-6283628420005888 target_dec_mpeg4_fuzzer +#3529/clusterfuzz-testcase-minimized-5057068371279872 target_dec_paf_video_fuzzer +3541/clusterfuzz-testcase-minimized-6469958596820992 target_dec_jpeg2000_fuzzer +3547/clusterfuzz-testcase-minimized-6009386439802880 target_dec_aac_fixed_fuzzer +3594/clusterfuzz-testcase-minimized-4650622935629824 target_dec_aac_fixed_fuzzer +3612/clusterfuzz-testcase-minimized-6393461273001984 target_dec_xan_wc3_fuzzer +3642/clusterfuzz-testcase-minimized-5443853801750528 target_dec_aac_fixed_fuzzer +#3707/clusterfuzz-testcase-minimized-6465922706440192 target_dec_xan_wc3_fuzzer +3787/clusterfuzz-testcase-minimized-5728764920070144 target_dec_exr_fuzzer +3805/clusterfuzz-testcase-minimized-6578427831255040 target_dec_h264_fuzzer +3902/clusterfuzz-testcase-minimized-6081926122176512 target_dec_exr_fuzzer +3984/clusterfuzz-testcase-minimized-5265759929368576 target_dec_snow_fuzzer +4019/clusterfuzz-testcase-minimized-5823336006287360 target_dec_h264_fuzzer +4035/clusterfuzz-testcase-minimized-6479308925173760 target_dec_dirac_fuzzer +4037/clusterfuzz-testcase-minimized-5290998163832832 target_dec_hevc_fuzzer +4074/clusterfuzz-testcase-minimized-4516104123711488 target_dec_truehd_fuzzer +#4086/clusterfuzz-testcase-minimized-5452429861584896 target_dec_h264_fuzzer +4143/clusterfuzz-testcase-minimized-4736864637419520 target_dec_zmbv_fuzzer +4151/clusterfuzz-testcase-minimized-4854089193095168 target_dec_libfdk_aac_fuzzer +4196/clusterfuzz-testcase-minimized-5580648594014208 target_dec_h264_fuzzer +#4271/clusterfuzz-testcase-minimized-4676667768307712 target_dec_kgv1_fuzzer +4326/clusterfuzz-testcase-minimized-5689449645080576 target_dec_truehd_fuzzer +4337/clusterfuzz-testcase-minimized-6192658616680448 target_dec_aac_fixed_fuzzer +4354/clusterfuzz-testcase-minimized-4671122764201984 target_dec_dirac_fuzzer +4397/clusterfuzz-testcase-minimized-4779061080489984 target_dec_hevc_fuzzer +4415/clusterfuzz-testcase-minimized-4677752314658816 target_dec_amrwb_fuzzer +4427/clusterfuzz-testcase-minimized-5106919271301120 target_dec_jpeg2000_fuzzer +4478/clusterfuzz-testcase-minimized-4752113767809024 target_dec_dirac_fuzzer +4479/clusterfuzz-testcase-minimized-6529894147162112 target_dec_dirac_fuzzer +4490/clusterfuzz-testcase-minimized-5210014592532480 target_dec_vp9_fuzzer +4524/clusterfuzz-testcase-minimized-6055590120914944 target_dec_hevc_fuzzer +4525/clusterfuzz-testcase-minimized-6400713073623040 target_dec_jpeg2000_fuzzer +4554/clusterfuzz-testcase-minimized-4843714515042304 target_dec_hevc_fuzzer +4555/clusterfuzz-testcase-minimized-4505532481142784 target_dec_hevc_fuzzer +4563/clusterfuzz-testcase-minimized-5438979567517696 target_dec_dirac_fuzzer +4626/clusterfuzz-testcase-minimized-5647837887987712 target_dec_hevc_fuzzer +4671/clusterfuzz-testcase-minimized-6027464343027712 target_dec_dnxhd_fuzzer +4683/clusterfuzz-testcase-minimized-6152313673613312 target_dec_exr_fuzzer +4688/clusterfuzz-testcase-minimized-6572210748653568 target_dec_flac_fuzzer +4690/clusterfuzz-testcase-minimized-6117482428366848 target_dec_hevc_fuzzer +4698/clusterfuzz-testcase-minimized-5096956322906112 target_dec_h264_fuzzer +4716/clusterfuzz-testcase-minimized-5835915940331520 target_dec_flac_fuzzer +4756/clusterfuzz-testcase-minimized-4812495563784192 target_dec_jpeg2000_fuzzer +4780/clusterfuzz-testcase-minimized-4709066174627840 target_dec_h264_fuzzer +4792/clusterfuzz-testcase-minimized-6322450775146496 target_dec_dirac_fuzzer +4793/clusterfuzz-testcase-minimized-5707366629638144 target_dec_exr_fuzzer +4800/clusterfuzz-testcase-minimized-6110372403609600 target_dec_ac3_fixed_fuzzer +4810/clusterfuzz-testcase-minimized-6034253235093504 target_dec_jpeg2000_fuzzer +4823/clusterfuzz-testcase-minimized-4551896611160064 target_dec_wavpack_fuzzer +4828/clusterfuzz-testcase-minimized-5100849937252352 target_dec_snow_fuzzer +4830/clusterfuzz-testcase-minimized-5255392054476800 target_dec_dirac_fuzzer +#4832/clusterfuzz-testcase-minimized-4699096590843904 target_dec_ulti_fuzzer +4833/clusterfuzz-testcase-minimized-5302840101699584 target_dec_hevc_fuzzer +4861/clusterfuzz-testcase-minimized-4570316383715328 target_dec_truemotion2_fuzzer +#4863/clusterfuzz-testcase-minimized-6347354178322432 target_dec_dxtory_fuzzer +4868/clusterfuzz-testcase-minimized-6236542906400768 target_dec_hevc_fuzzer +4900/clusterfuzz-testcase-minimized-5769019744321536 target_dec_thp_fuzzer +4959/clusterfuzz-testcase-minimized-6035350934781952 target_dec_aac_fixed_fuzzer +5237/clusterfuzz-testcase-minimized-4569895275593728 target_dec_dirac_fuzzer +5264/clusterfuzz-testcase-minimized-4621956621008896 target_dec_indeo5_fuzzer +5275/clusterfuzz-testcase-minimized-5367635958038528 target_dec_aac_fixed_fuzzer +5396/clusterfuzz-testcase-minimized-6558555529281536 target_dec_wavpack_fuzzer +#5487/clusterfuzz-testcase-minimized-4696837035393024 target_dec_ffvhuff_fuzzer +5540/clusterfuzz-testcase-minimized-6122458273808384 target_dec_scpr_fuzzer +5549/clusterfuzz-testcase-minimized-5390553567985664 target_dec_paf_video_fuzzer +5567/clusterfuzz-testcase-minimized-5769966247739392 target_dec_truemotion2_fuzzer +#5653/clusterfuzz-testcase-minimized-5497680018014208 target_dec_vp7_fuzzer +5733/clusterfuzz-testcase-minimized-4906757966004224 target_dec_jpeg2000_fuzzer +5746/clusterfuzz-testcase-minimized-6270097623613440 target_dec_h264_fuzzer +#5792/clusterfuzz-testcase-minimized-6698155757273088 target_dec_hevc_fuzzer +5796/clusterfuzz-testcase-minimized-5206729085157376 target_dec_dxtory_fuzzer +5888/clusterfuzz-testcase-minimized-5634701067812864 target_dec_hevc_fuzzer +5894/clusterfuzz-testcase-minimized-5315325420634112 target_dec_dirac_fuzzer +5911/clusterfuzz-testcase-minimized-6450382197751808 target_dec_dirac_fuzzer +5918/clusterfuzz-testcase-minimized-5120505435652096 target_dec_jpeg2000_fuzzer +5919/clusterfuzz-testcase-minimized-5859311382167552 target_dec_vp3_fuzzer +5948/clusterfuzz-testcase-minimized-5791479856365568 target_dec_aac_fixed_fuzzer +7279/clusterfuzz-testcase-minimized-ffmpeg_AV_CODEC_ID_G2M_fuzzer-5977332473921536 target_dec_g2m_fuzzer +10053/clusterfuzz-testcase-minimized-ffmpeg_AV_CODEC_ID_PROSUMER_fuzzer-5636993883570176 target_dec_prosumer_fuzzer diff --git a/tools/target_dec_fate.sh b/tools/target_dec_fate.sh new file mode 100755 index 000000000..1377b6b4e --- /dev/null +++ b/tools/target_dec_fate.sh @@ -0,0 +1,83 @@ +#!/bin/sh +# +# * Copyright (C) 2018 Michael Niedermayer (michaelni@gmx.at) +# * +# * This file is part of FFmpeg. +# * +# * FFmpeg is free software; you can redistribute it and/or modify +# * it under the terms of the GNU General Public License as published by +# * the Free Software Foundation; either version 2 of the License, or +# * (at your option) any later version. +# * +# * FFmpeg is distributed in the hope that it will be useful, +# * but WITHOUT ANY WARRANTY; without even the implied warranty of +# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# * GNU General Public License for more details. +# * +# * You should have received a copy of the GNU General Public License +# * along with FFmpeg; if not, write to the Free Software +# * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +set -e + +LC_ALL=C +export LC_ALL + +LIST=target_dec_fate.list + +show_help(){ + cat < [] + +directory the directory into which sample files will be downloaded +test to run the number of the issue to test +Note, some test samples may not yet be available to the public, also this +script will not download samples which are already in the directory. So you +may want to preserve its content between runs. +EOF + exit 0 +} + +test -z "$1" && show_help +test ! -d "$1" && echo $1 is not an accessable directory && show_help +test ! -f target_dec_fate.sh && echo $0 Must be run from its location && show_help +grep 'CONFIG_OSSFUZZ 0' ../config.h && echo not configured for ossfuzz && show_help + +#Download testcases +while read -r LINE; do + ISSUE_NUM=`echo $LINE | sed 's#/.*##'` + FILE_ID=`echo $LINE | sed 's#.*/clusterfuzz-testcase[a-zA-Z0-9_-]*-\([0-9]*\).*#\1#'` + FILE=`echo $LINE | sed 's# .*##'` + if test -f "$1/$FILE" ; then + echo exists $FILE + elif echo "$ISSUE_NUM" | grep '#' >/dev/null ; then + echo disabled $FILE + else + echo downloading $FILE + mkdir -p "$1/$ISSUE_NUM" + wget -O "$1/$FILE" "https://oss-fuzz.com/download?testcase_id=$FILE_ID" || rm "$1/$FILE" + fi +done < "$LIST" + +#Find which fuzzers we need to build +TOOLS= +while read -r LINE; do + TOOL_ID=`echo $LINE | sed 's#[^ ]* ##'` + TOOLS="$TOOLS tools/$TOOL_ID" +done < "$LIST" + +cd .. +#Build fuzzers +make -j4 $TOOLS + +#Run testcases +while read -r LINE; do + TOOL_ID=`echo $LINE | sed 's#[^ ]* ##'` + FILE=`echo $LINE | sed 's# .*##'` + if ! test -f "$1/$FILE" ; then + continue + fi + tools/$TOOL_ID $1/$FILE +done < "tools/$LIST" + +echo OK diff --git a/tools/target_dec_fuzzer.c b/tools/target_dec_fuzzer.c index 62d62a9de..8ba25b4e8 100644 --- a/tools/target_dec_fuzzer.c +++ b/tools/target_dec_fuzzer.c @@ -30,7 +30,7 @@ * build the fuzz target. Choose the value of FFMPEG_CODEC (e.g. AV_CODEC_ID_DVD_SUBTITLE) and choose one of FUZZ_FFMPEG_VIDEO, FUZZ_FFMPEG_AUDIO, FUZZ_FFMPEG_SUBTITLE. - clang -fsanitize=address -fsanitize-coverage=trace-pc-guard,trace-cmp tools/target_dec_fuzzer.c -o target_dec_fuzzer -I. -DFFMPEG_CODEC=AV_CODEC_ID_MPEG1VIDEO -DFUZZ_FFMPEG_VIDEO ../../libfuzzer/libFuzzer.a -Llibavcodec -Llibavdevice -Llibavfilter -Llibavformat -Llibavresample -Llibavutil -Llibpostproc -Llibswscale -Llibswresample -Wl,--as-needed -Wl,-z,noexecstack -Wl,--warn-common -Wl,-rpath-link=libpostproc:libswresample:libswscale:libavfilter:libavdevice:libavformat:libavcodec:libavutil:libavresample -lavdevice -lavfilter -lavformat -lavcodec -lswresample -lswscale -lavutil -ldl -lxcb -lxcb-shm -lxcb -lxcb-xfixes -lxcb -lxcb-shape -lxcb -lX11 -lasound -lm -lbz2 -lz -pthread + clang -fsanitize=address -fsanitize-coverage=trace-pc-guard,trace-cmp tools/target_dec_fuzzer.c -o target_dec_fuzzer -I. -DFFMPEG_CODEC=AV_CODEC_ID_MPEG1VIDEO -DFUZZ_FFMPEG_VIDEO ../../libfuzzer/libFuzzer.a -Llibavcodec -Llibavdevice -Llibavfilter -Llibavformat -Llibavresample -Llibavutil -Llibpostproc -Llibswscale -Llibswresample -Wl,--as-needed -Wl,-z,noexecstack -Wl,--warn-common -Wl,-rpath-link=:libpostproc:libswresample:libswscale:libavfilter:libavdevice:libavformat:libavcodec:libavutil:libavresample -lavdevice -lavfilter -lavformat -lavcodec -lswresample -lswscale -lavutil -ldl -lxcb -lxcb-shm -lxcb -lxcb-xfixes -lxcb -lxcb-shape -lxcb -lX11 -lasound -lm -lbz2 -lz -pthread * create a corpus directory and put some samples there (empty dir is ok too): mkdir CORPUS && cp some-files CORPUS @@ -56,6 +56,8 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size); +extern AVCodec * codec_list[]; + static void error(const char *err) { fprintf(stderr, "%s", err); @@ -135,15 +137,19 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { const uint8_t *last = data; const uint8_t *end = data + size; uint32_t it = 0; + uint64_t ec_pixels = 0; int (*decode_handler)(AVCodecContext *avctx, AVFrame *picture, int *got_picture_ptr, const AVPacket *avpkt) = NULL; + AVCodecParserContext *parser = NULL; + if (!c) { #ifdef FFMPEG_DECODER #define DECODER_SYMBOL0(CODEC) ff_##CODEC##_decoder #define DECODER_SYMBOL(CODEC) DECODER_SYMBOL0(CODEC) extern AVCodec DECODER_SYMBOL(FFMPEG_DECODER); + codec_list[0] = &DECODER_SYMBOL(FFMPEG_DECODER); avcodec_register(&DECODER_SYMBOL(FFMPEG_DECODER)); c = &DECODER_SYMBOL(FFMPEG_DECODER); @@ -161,28 +167,46 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { } AVCodecContext* ctx = avcodec_alloc_context3(NULL); - if (!ctx) + AVCodecContext* parser_avctx = avcodec_alloc_context3(NULL); + if (!ctx || !parser_avctx) error("Failed memory allocation"); ctx->max_pixels = 4096 * 4096; //To reduce false positive OOM and hangs if (size > 1024) { GetByteContext gbc; - bytestream2_init(&gbc, data + size - 1024, 1024); + int extradata_size; + size -= 1024; + bytestream2_init(&gbc, data + size, 1024); ctx->width = bytestream2_get_le32(&gbc); ctx->height = bytestream2_get_le32(&gbc); ctx->bit_rate = bytestream2_get_le64(&gbc); ctx->bits_per_coded_sample = bytestream2_get_le32(&gbc); + // Try to initialize a parser for this codec, note, this may fail which just means we test without one + if (bytestream2_get_byte(&gbc) & 1) + parser = av_parser_init(c->id); + + extradata_size = bytestream2_get_le32(&gbc); + if (extradata_size < size) { + ctx->extradata = av_mallocz(extradata_size + AV_INPUT_BUFFER_PADDING_SIZE); + if (ctx->extradata) { + ctx->extradata_size = extradata_size; + size -= ctx->extradata_size; + memcpy(ctx->extradata, data + size, ctx->extradata_size); + } + } if (av_image_check_size(ctx->width, ctx->height, 0, ctx)) ctx->width = ctx->height = 0; - size -= 1024; } int res = avcodec_open2(ctx, c, NULL); if (res < 0) { av_free(ctx); + av_free(parser_avctx); + av_parser_close(parser); return 0; // Failure of avcodec_open2() does not imply that a issue was found } + parser_avctx->codec_id = ctx->codec_id; FDBCreate(&buffer); int got_frame; @@ -191,7 +215,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { error("Failed memory allocation"); // Read very simple container - AVPacket avpkt; + AVPacket avpkt, parsepkt; while (data < end && it < maxiteration) { // Search for the TAG while (data + sizeof(fuzz_tag) < end) { @@ -202,16 +226,39 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { if (data + sizeof(fuzz_tag) > end) data = end; - FDBPrepare(&buffer, &avpkt, last, data - last); + FDBPrepare(&buffer, &parsepkt, last, data - last); data += sizeof(fuzz_tag); last = data; - // Iterate through all data - while (avpkt.size > 0 && it++ < maxiteration) { + while (parsepkt.size > 0) { + + if (parser) { + av_init_packet(&avpkt); + int ret = av_parser_parse2(parser, parser_avctx, &avpkt.data, &avpkt.size, + parsepkt.data, parsepkt.size, + parsepkt.pts, parsepkt.dts, parsepkt.pos); + parsepkt.data += ret; + parsepkt.size -= ret; + parsepkt.pos += ret; + avpkt.pts = parser->pts; + avpkt.dts = parser->dts; + avpkt.pos = parser->pos; + if ( parser->key_frame == 1 || + (parser->key_frame == -1 && parser->pict_type == AV_PICTURE_TYPE_I)) + avpkt.flags |= AV_PKT_FLAG_KEY; + avpkt.flags |= parsepkt.flags & AV_PKT_FLAG_DISCARD; + } else { + avpkt = parsepkt; + parsepkt.size = 0; + } + + // Iterate through all data + while (avpkt.size > 0 && it++ < maxiteration) { av_frame_unref(frame); int ret = decode_handler(ctx, frame, &got_frame, &avpkt); - if (it > 20) + ec_pixels += ctx->width * ctx->height; + if (it > 20 || ec_pixels > 4 * ctx->max_pixels) ctx->error_concealment = 0; if (ret <= 0 || ret > avpkt.size) @@ -220,6 +267,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { ret = avpkt.size; avpkt.data += ret; avpkt.size -= ret; + } } } @@ -234,7 +282,8 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { av_frame_free(&frame); avcodec_free_context(&ctx); - av_freep(&ctx); + avcodec_free_context(&parser_avctx); + av_parser_close(parser); FDBDesroy(&buffer); return 0; } diff --git a/tools/target_dem_fuzzer.c b/tools/target_dem_fuzzer.c new file mode 100644 index 000000000..409599636 --- /dev/null +++ b/tools/target_dem_fuzzer.c @@ -0,0 +1,161 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" +#include "libavutil/avassert.h" + +#include "libavcodec/avcodec.h" +#include "libavcodec/bytestream.h" +#include "libavformat/avformat.h" + + +typedef struct IOContext { + int64_t pos; + int64_t filesize; + uint8_t *fuzz; + int fuzz_size; +} IOContext; + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size); + +static void error(const char *err) +{ + fprintf(stderr, "%s", err); + exit(1); +} + +static int io_read(void *opaque, uint8_t *buf, int buf_size) +{ + IOContext *c = opaque; + int size = FFMIN(buf_size, c->fuzz_size); + + if (!c->fuzz_size) { + c->filesize = FFMIN(c->pos, c->filesize); + return AVERROR_EOF; + } + + memcpy(buf, c->fuzz, size); + c->fuzz += size; + c->fuzz_size -= size; + c->pos += size; + c->filesize = FFMAX(c->filesize, c->pos); + + return size; +} + +static int64_t io_seek(void *opaque, int64_t offset, int whence) +{ + IOContext *c = opaque; + + if (whence == SEEK_CUR) { + if (offset > INT64_MAX - c->pos) + return -1; + offset += c->pos; + } else if (whence == SEEK_END) { + if (offset > INT64_MAX - c->filesize) + return -1; + offset += c->filesize; + } + if (offset < 0 || offset > c->filesize) + return -1; + c->pos = offset; + return 0; +} + +// Ensure we don't loop forever +const uint32_t maxiteration = 8096; + +static const uint64_t FUZZ_TAG = 0x4741542D5A5A5546ULL; + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + const uint64_t fuzz_tag = FUZZ_TAG; + uint32_t it = 0; + AVFormatContext *avfmt = avformat_alloc_context(); + AVPacket pkt; + char filename[1025] = {0}; + AVIOContext *fuzzed_pb = NULL; + uint8_t *io_buffer; + int io_buffer_size = 32768; + int64_t filesize = size; + IOContext opaque; + static int c; + int seekable = 0; + int ret; + + if (!c) { + av_register_all(); + avcodec_register_all(); + av_log_set_level(AV_LOG_PANIC); + c=1; + } + + if (!avfmt) + error("Failed avformat_alloc_context()"); + + if (size > 2048) { + GetByteContext gbc; + memcpy (filename, data + size - 1024, 1024); + bytestream2_init(&gbc, data + size - 2048, 1024); + size -= 2048; + + io_buffer_size = bytestream2_get_le32(&gbc) & 0xFFFFFFF; + seekable = bytestream2_get_byte(&gbc) & 1; + filesize = bytestream2_get_le64(&gbc) & 0x7FFFFFFFFFFFFFFF; + } + io_buffer = av_malloc(io_buffer_size); + if (!io_buffer) + error("Failed to allocate io_buffer"); + + opaque.filesize = filesize; + opaque.pos = 0; + opaque.fuzz = data; + opaque.fuzz_size= size; + fuzzed_pb = avio_alloc_context(io_buffer, io_buffer_size, 0, &opaque, + io_read, NULL, seekable ? io_seek : NULL); + if (!fuzzed_pb) + error("avio_alloc_context failed"); + + avfmt->pb = fuzzed_pb; + + ret = avformat_open_input(&avfmt, filename, NULL, NULL); + if (ret < 0) { + av_freep(&fuzzed_pb->buffer); + av_freep(&fuzzed_pb); + avformat_free_context(avfmt); + return 0; + } + + ret = avformat_find_stream_info(avfmt, NULL); + + av_init_packet(&pkt); + + //TODO, test seeking + + for(it = 0; it < maxiteration; it++) { + ret = av_read_frame(avfmt, &pkt); + if (ret < 0) + break; + av_packet_unref(&pkt); + } +end: + av_freep(&fuzzed_pb->buffer); + av_freep(&fuzzed_pb); + avformat_close_input(&avfmt); + + return 0; +}